From 878ddf1fc3540a715f63594ed22b6929e881afb4 Mon Sep 17 00:00:00 2001 From: bbahnsen Date: Fri, 21 Apr 2006 22:54:32 +0000 Subject: [PATCH] Initial import. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3 6f19259b-4bc3-4df7-8a09-765794883524 --- DeveloperManual.doc | Bin 0 -> 650240 bytes EdkFatBinPkg/EdkFatBinPkg.spd | 40 + EdkFatBinPkg/Fat.mbd | 34 + EdkFatBinPkg/Fat.msa | 53 + EdkFatBinPkg/Fat_build.xml | 36 + EdkFatBinPkg/Ia32/Fat.FFS | Bin 0 -> 24227 bytes EdkFatBinPkg/Ipf/Fat.FFS | Bin 0 -> 38320 bytes EdkFatBinPkg/X64/Fat.FFS | Bin 0 -> 17793 bytes EdkFatBinPkg/build.xml | 47 + EdkFatBinPkg/genbuildfile.xml | 18 + .../Application/HelloWorld/HelloWorld.c | 47 + .../Application/HelloWorld/HelloWorld.mbd | 43 + .../Application/HelloWorld/HelloWorld.msa | 51 + EdkModulePkg/Application/HelloWorld/build.xml | 47 + .../Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.c | 2226 +++++++ .../Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.h | 916 +++ .../Pci/AtapiPassThru/Dxe/AtapiPassThru.mbd | 42 + .../Pci/AtapiPassThru/Dxe/AtapiPassThru.msa | 65 + .../Bus/Pci/AtapiPassThru/Dxe/ComponentName.c | 154 + .../Bus/Pci/AtapiPassThru/Dxe/build.xml | 47 + .../Bus/Pci/CirrusLogic/Dxe/CirrusLogic5430.c | 346 + .../Bus/Pci/CirrusLogic/Dxe/CirrusLogic5430.h | 254 + .../Pci/CirrusLogic/Dxe/CirrusLogic5430.mbd | 42 + .../Pci/CirrusLogic/Dxe/CirrusLogic5430.msa | 66 + .../CirrusLogic/Dxe/CirrusLogic5430UgaDraw.c | 1036 +++ .../Bus/Pci/CirrusLogic/Dxe/ComponentName.c | 222 + .../Bus/Pci/CirrusLogic/Dxe/build.xml | 47 + .../Bus/Pci/IdeBus/Dxe/ComponentName.c | 224 + .../Bus/Pci/IdeBus/Dxe/ComponentName.h | 118 + .../Bus/Pci/IdeBus/Dxe/DriverConfiguration.c | 378 ++ .../Bus/Pci/IdeBus/Dxe/DriverDiagnostics.c | 225 + EdkModulePkg/Bus/Pci/IdeBus/Dxe/ata.c | 3690 +++++++++++ EdkModulePkg/Bus/Pci/IdeBus/Dxe/atapi.c | 2591 ++++++++ EdkModulePkg/Bus/Pci/IdeBus/Dxe/build.xml | 74 + EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.c | 1964 ++++++ EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.h | 1806 ++++++ EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.c | 1400 ++++ EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.h | 439 ++ EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.mbd | 45 + EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.msa | 90 + .../Bus/Pci/IdeBus/Dxe/idebusLite.mbd | 44 + .../Bus/Pci/IdeBus/Dxe/idebusLite.msa | 86 + EdkModulePkg/Bus/Pci/IdeBus/Dxe/idedata.h | 879 +++ .../Bus/Pci/PciBus/Dxe/ComponentName.c | 133 + .../Bus/Pci/PciBus/Dxe/ComponentName.h | 91 + .../Bus/Pci/PciBus/Dxe/LightPciBus.mbd | 43 + .../Bus/Pci/PciBus/Dxe/LightPciBus.msa | 112 + EdkModulePkg/Bus/Pci/PciBus/Dxe/LightPciLib.c | 881 +++ EdkModulePkg/Bus/Pci/PciBus/Dxe/PciBus.mbd | 43 + EdkModulePkg/Bus/Pci/PciBus/Dxe/PciBus.msa | 121 + .../Bus/Pci/PciBus/Dxe/PciBusLite.mbd | 43 + .../Bus/Pci/PciBus/Dxe/PciBusLite.msa | 111 + EdkModulePkg/Bus/Pci/PciBus/Dxe/PciCommand.c | 207 + EdkModulePkg/Bus/Pci/PciBus/Dxe/PciCommand.h | 134 + .../Bus/Pci/PciBus/Dxe/PciDeviceSupport.c | 1345 ++++ .../Bus/Pci/PciBus/Dxe/PciDeviceSupport.h | 477 ++ .../Bus/Pci/PciBus/Dxe/PciDriverOverride.c | 290 + .../Bus/Pci/PciBus/Dxe/PciDriverOverride.h | 108 + .../Bus/Pci/PciBus/Dxe/PciEnumerator.c | 2164 +++++++ .../Bus/Pci/PciBus/Dxe/PciEnumerator.h | 628 ++ .../Bus/Pci/PciBus/Dxe/PciEnumeratorSupport.c | 2261 +++++++ .../Bus/Pci/PciBus/Dxe/PciEnumeratorSupport.h | 598 ++ .../Bus/Pci/PciBus/Dxe/PciHotPlugSupport.c | 462 ++ .../Bus/Pci/PciBus/Dxe/PciHotPlugSupport.h | 269 + EdkModulePkg/Bus/Pci/PciBus/Dxe/PciIo.c | 1964 ++++++ EdkModulePkg/Bus/Pci/PciBus/Dxe/PciIo.h | 773 +++ EdkModulePkg/Bus/Pci/PciBus/Dxe/PciLib.c | 1398 ++++ EdkModulePkg/Bus/Pci/PciBus/Dxe/PciLib.h | 247 + .../Bus/Pci/PciBus/Dxe/PciOptionRomSupport.c | 543 ++ .../Bus/Pci/PciBus/Dxe/PciOptionRomSupport.h | 119 + .../Bus/Pci/PciBus/Dxe/PciPowerManagement.c | 83 + .../Bus/Pci/PciBus/Dxe/PciPowerManagement.h | 48 + .../Bus/Pci/PciBus/Dxe/PciResourceSupport.c | 2276 +++++++ .../Bus/Pci/PciBus/Dxe/PciResourceSupport.h | 740 +++ EdkModulePkg/Bus/Pci/PciBus/Dxe/PciRomTable.c | 457 ++ EdkModulePkg/Bus/Pci/PciBus/Dxe/PciRomTable.h | 107 + EdkModulePkg/Bus/Pci/PciBus/Dxe/build.xml | 101 + EdkModulePkg/Bus/Pci/PciBus/Dxe/pcibus.c | 375 ++ EdkModulePkg/Bus/Pci/PciBus/Dxe/pcibus.h | 243 + EdkModulePkg/Bus/Pci/Uhci/Dxe/ComponentName.c | 189 + EdkModulePkg/Bus/Pci/Uhci/Dxe/Uhci.mbd | 42 + EdkModulePkg/Bus/Pci/Uhci/Dxe/Uhci.msa | 66 + EdkModulePkg/Bus/Pci/Uhci/Dxe/build.xml | 47 + EdkModulePkg/Bus/Pci/Uhci/Dxe/uhchlp.c | 4237 ++++++++++++ EdkModulePkg/Bus/Pci/Uhci/Dxe/uhci.c | 3498 ++++++++++ EdkModulePkg/Bus/Pci/Uhci/Dxe/uhci.h | 1187 ++++ EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/Decode.c | 1661 +++++ EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/E100b.c | 3772 +++++++++++ EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/E100b.h | 668 ++ EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/Init.c | 1162 ++++ EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/Undi.mbd | 47 + EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/Undi.msa | 92 + EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/Undi32.h | 208 + .../Bus/Pci/Undi/RuntimeDxe/build.xml | 47 + .../Bus/Scsi/ScsiBus/Dxe/ComponentName.c | 155 + EdkModulePkg/Bus/Scsi/ScsiBus/Dxe/ScsiBus.c | 751 +++ EdkModulePkg/Bus/Scsi/ScsiBus/Dxe/ScsiBus.h | 266 + EdkModulePkg/Bus/Scsi/ScsiBus/Dxe/ScsiBus.mbd | 44 + EdkModulePkg/Bus/Scsi/ScsiBus/Dxe/ScsiBus.msa | 68 + EdkModulePkg/Bus/Scsi/ScsiBus/Dxe/build.xml | 47 + .../Bus/Scsi/ScsiDisk/Dxe/ComponentName.c | 190 + EdkModulePkg/Bus/Scsi/ScsiDisk/Dxe/ScsiDisk.c | 2414 +++++++ EdkModulePkg/Bus/Scsi/ScsiDisk/Dxe/ScsiDisk.h | 728 +++ .../Bus/Scsi/ScsiDisk/Dxe/ScsiDisk.mbd | 43 + .../Bus/Scsi/ScsiDisk/Dxe/ScsiDisk.msa | 67 + EdkModulePkg/Bus/Scsi/ScsiDisk/Dxe/build.xml | 47 + .../Bus/Usb/UsbBot/Dxe/ComponentName.c | 190 + EdkModulePkg/Bus/Usb/UsbBot/Dxe/UsbBot.mbd | 43 + EdkModulePkg/Bus/Usb/UsbBot/Dxe/UsbBot.msa | 69 + EdkModulePkg/Bus/Usb/UsbBot/Dxe/bot.c | 1088 ++++ EdkModulePkg/Bus/Usb/UsbBot/Dxe/bot.h | 78 + EdkModulePkg/Bus/Usb/UsbBot/Dxe/build.xml | 47 + .../Bus/Usb/UsbBus/Dxe/ComponentName.c | 154 + EdkModulePkg/Bus/Usb/UsbBus/Dxe/UsbBus.mbd | 44 + EdkModulePkg/Bus/Usb/UsbBus/Dxe/UsbBus.msa | 76 + EdkModulePkg/Bus/Usb/UsbBus/Dxe/build.xml | 47 + EdkModulePkg/Bus/Usb/UsbBus/Dxe/hub.c | 507 ++ EdkModulePkg/Bus/Usb/UsbBus/Dxe/hub.h | 138 + EdkModulePkg/Bus/Usb/UsbBus/Dxe/usb.c | 825 +++ EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbbus.c | 2305 +++++++ EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbbus.h | 261 + EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbio.c | 1176 ++++ EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbutil.c | 556 ++ EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbutil.h | 94 + EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/Cbi0.c | 1042 +++ .../Bus/Usb/UsbCbi/Dxe/Cbi0/ComponentName.c | 192 + .../Bus/Usb/UsbCbi/Dxe/Cbi0/UsbCbi0.mbd | 43 + .../Bus/Usb/UsbCbi/Dxe/Cbi0/UsbCbi0.msa | 68 + .../Bus/Usb/UsbCbi/Dxe/Cbi0/build.xml | 47 + .../Bus/Usb/UsbCbi/Dxe/Cbi1/UsbCbi1.mbd | 43 + .../Bus/Usb/UsbCbi/Dxe/Cbi1/UsbCbi1.msa | 66 + .../Bus/Usb/UsbCbi/Dxe/Cbi1/build.xml | 47 + EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/cbi1.c | 854 +++ EdkModulePkg/Bus/Usb/UsbCbi/Dxe/cbi.h | 70 + .../Bus/Usb/UsbKb/Dxe/ComponentName.c | 215 + EdkModulePkg/Bus/Usb/UsbKb/Dxe/UsbKb.mbd | 44 + EdkModulePkg/Bus/Usb/UsbKb/Dxe/UsbKb.msa | 77 + EdkModulePkg/Bus/Usb/UsbKb/Dxe/build.xml | 47 + EdkModulePkg/Bus/Usb/UsbKb/Dxe/efikey.c | 772 +++ EdkModulePkg/Bus/Usb/UsbKb/Dxe/efikey.h | 118 + EdkModulePkg/Bus/Usb/UsbKb/Dxe/keyboard.c | 1150 ++++ EdkModulePkg/Bus/Usb/UsbKb/Dxe/keyboard.h | 106 + .../Usb/UsbMassStorage/Dxe/ComponentName.c | 154 + .../Usb/UsbMassStorage/Dxe/UsbMassStorage.c | 727 +++ .../Usb/UsbMassStorage/Dxe/UsbMassStorage.h | 59 + .../Usb/UsbMassStorage/Dxe/UsbMassStorage.mbd | 43 + .../Usb/UsbMassStorage/Dxe/UsbMassStorage.msa | 70 + .../UsbMassStorage/Dxe/UsbMassStorageData.h | 394 ++ .../UsbMassStorage/Dxe/UsbMassStorageHelper.c | 1653 +++++ .../UsbMassStorage/Dxe/UsbMassStorageHelper.h | 111 + .../Bus/Usb/UsbMassStorage/Dxe/build.xml | 47 + .../Bus/Usb/UsbMouse/Dxe/ComponentName.c | 216 + .../Bus/Usb/UsbMouse/Dxe/UsbMouse.mbd | 43 + .../Bus/Usb/UsbMouse/Dxe/UsbMouse.msa | 71 + EdkModulePkg/Bus/Usb/UsbMouse/Dxe/build.xml | 47 + EdkModulePkg/Bus/Usb/UsbMouse/Dxe/mousehid.c | 395 ++ EdkModulePkg/Bus/Usb/UsbMouse/Dxe/mousehid.h | 84 + EdkModulePkg/Bus/Usb/UsbMouse/Dxe/usbmouse.c | 1028 +++ EdkModulePkg/Bus/Usb/UsbMouse/Dxe/usbmouse.h | 85 + EdkModulePkg/Core/Dxe/DebugImageInfo.h | 126 + EdkModulePkg/Core/Dxe/Dispatcher/Dispatcher.c | 1159 ++++ EdkModulePkg/Core/Dxe/Dispatcher/dependency.c | 450 ++ EdkModulePkg/Core/Dxe/DxeMain.h | 2539 ++++++++ EdkModulePkg/Core/Dxe/DxeMain.mbd | 42 + EdkModulePkg/Core/Dxe/DxeMain.msa | 164 + EdkModulePkg/Core/Dxe/DxeMain/DxeMain.c | 1083 ++++ .../Core/Dxe/DxeMain/DxeProtocolNotify.c | 266 + EdkModulePkg/Core/Dxe/Event/event.c | 862 +++ EdkModulePkg/Core/Dxe/Event/execdata.c | 55 + EdkModulePkg/Core/Dxe/Event/timer.c | 386 ++ EdkModulePkg/Core/Dxe/Event/tpl.c | 198 + EdkModulePkg/Core/Dxe/FwVol/Ffs.c | 266 + EdkModulePkg/Core/Dxe/FwVol/FwVol.c | 553 ++ EdkModulePkg/Core/Dxe/FwVol/FwVolAttrib.c | 99 + EdkModulePkg/Core/Dxe/FwVol/FwVolRead.c | 516 ++ EdkModulePkg/Core/Dxe/FwVol/FwVolWrite.c | 60 + EdkModulePkg/Core/Dxe/FwVolBlock.h | 324 + EdkModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.c | 598 ++ EdkModulePkg/Core/Dxe/FwVolDriver.h | 466 ++ EdkModulePkg/Core/Dxe/Gcd/gcd.c | 2481 +++++++ EdkModulePkg/Core/Dxe/Hand/DriverSupport.c | 848 +++ EdkModulePkg/Core/Dxe/Hand/Notify.c | 333 + EdkModulePkg/Core/Dxe/Hand/handle.c | 1699 +++++ EdkModulePkg/Core/Dxe/Hand/locate.c | 737 +++ EdkModulePkg/Core/Dxe/Image.h | 380 ++ EdkModulePkg/Core/Dxe/Image/Image.c | 1377 ++++ EdkModulePkg/Core/Dxe/Image/ImageFile.c | 569 ++ EdkModulePkg/Core/Dxe/Library.h | 407 ++ EdkModulePkg/Core/Dxe/Library/Library.c | 613 ++ EdkModulePkg/Core/Dxe/Mem/Page.c | 1589 +++++ EdkModulePkg/Core/Dxe/Mem/memdata.c | 41 + EdkModulePkg/Core/Dxe/Mem/pool.c | 613 ++ EdkModulePkg/Core/Dxe/Misc/DebugImageInfo.c | 260 + .../Core/Dxe/Misc/InstallConfigurationTable.c | 214 + EdkModulePkg/Core/Dxe/Misc/SetWatchdogTimer.c | 83 + EdkModulePkg/Core/Dxe/Misc/Stall.c | 82 + .../SectionExtraction/CoreSectionExtraction.c | 1339 ++++ EdkModulePkg/Core/Dxe/build.xml | 47 + EdkModulePkg/Core/Dxe/exec.h | 209 + EdkModulePkg/Core/Dxe/gcd.h | 51 + EdkModulePkg/Core/Dxe/hand.h | 337 + EdkModulePkg/Core/Dxe/imem.h | 227 + EdkModulePkg/Core/DxeIplPeim/DxeIpl.dxs | 29 + EdkModulePkg/Core/DxeIplPeim/DxeIpl.h | 146 + EdkModulePkg/Core/DxeIplPeim/DxeIpl.mbd | 63 + EdkModulePkg/Core/DxeIplPeim/DxeIpl.msa | 129 + EdkModulePkg/Core/DxeIplPeim/DxeIplX64.mbd | 49 + EdkModulePkg/Core/DxeIplPeim/DxeIplX64.msa | 85 + EdkModulePkg/Core/DxeIplPeim/DxeLoad.c | 1010 +++ EdkModulePkg/Core/DxeIplPeim/DxeLoadX64.c | 1018 +++ .../Core/DxeIplPeim/Ipf/DxeLoadFunc.c | 70 + EdkModulePkg/Core/DxeIplPeim/Ipf/ImageRead.c | 72 + EdkModulePkg/Core/DxeIplPeim/build.xml | 47 + EdkModulePkg/Core/DxeIplPeim/build_X64.xml | 46 + .../Core/DxeIplPeim/ia32/DxeLoadFunc.c | 51 + EdkModulePkg/Core/DxeIplPeim/ia32/ImageRead.c | 112 + .../Core/DxeIplPeim/x64/DxeLoadFunc.c | 53 + EdkModulePkg/Core/DxeIplPeim/x64/ImageRead.c | 106 + EdkModulePkg/Core/DxeIplPeim/x64/LongMode.asm | 1357 ++++ .../Core/DxeIplPeim/x64/VirtualMemory.c | 434 ++ .../Core/DxeIplPeim/x64/VirtualMemory.h | 239 + EdkModulePkg/Core/Pei/BootMode/BootMode.c | 106 + EdkModulePkg/Core/Pei/Dependency/dependency.c | 264 + EdkModulePkg/Core/Pei/Dependency/dependency.h | 38 + EdkModulePkg/Core/Pei/Dispatcher/Dispatcher.c | 535 ++ EdkModulePkg/Core/Pei/FwVol/FwVol.c | 474 ++ EdkModulePkg/Core/Pei/Hob/Hob.c | 189 + EdkModulePkg/Core/Pei/Image/Image.c | 237 + EdkModulePkg/Core/Pei/Ipf/IpfCpuCore.i | 93 + EdkModulePkg/Core/Pei/Ipf/IpfCpuCore.s | 192 + EdkModulePkg/Core/Pei/Ipf/SwitchToCacheMode.c | 76 + EdkModulePkg/Core/Pei/Memory/MemoryServices.c | 314 + EdkModulePkg/Core/Pei/PeiMain.h | 1141 ++++ EdkModulePkg/Core/Pei/PeiMain.mbd | 53 + EdkModulePkg/Core/Pei/PeiMain.msa | 91 + EdkModulePkg/Core/Pei/PeiMain/PeiMain.c | 243 + EdkModulePkg/Core/Pei/Ppi/Ppi.c | 658 ++ EdkModulePkg/Core/Pei/Reset/Reset.c | 68 + EdkModulePkg/Core/Pei/Security/Security.c | 192 + EdkModulePkg/Core/Pei/StatusCode/StatusCode.c | 95 + EdkModulePkg/Core/Pei/build.xml | 47 + EdkModulePkg/EdkModulePkg.fpd | 453 ++ EdkModulePkg/EdkModulePkg.spd | 655 ++ EdkModulePkg/Include/Common/CapsuleName.h | 28 + .../Include/Common/DecompressLibraryHob.h | 47 + EdkModulePkg/Include/Common/FlashMap.h | 110 + EdkModulePkg/Include/Common/Variable.h | 78 + .../Include/Common/WorkingBlockHeader.h | 47 + EdkModulePkg/Include/EdkDxe.h | 95 + EdkModulePkg/Include/EdkDxeCore.h | 53 + EdkModulePkg/Include/EdkDxeDepex.h | 62 + EdkModulePkg/Include/EdkPeiCore.h | 42 + EdkModulePkg/Include/EdkPeim.h | 58 + EdkModulePkg/Include/EdkPeimDepex.h | 56 + EdkModulePkg/Include/Guid/AlternateFvBlock.h | 32 + EdkModulePkg/Include/Guid/Bmp.h | 62 + EdkModulePkg/Include/Guid/BootState.h | 36 + EdkModulePkg/Include/Guid/CapsuleVendor.h | 35 + .../Include/Guid/CompatibleMemoryTested.h | 32 + EdkModulePkg/Include/Guid/ConsoleInDevice.h | 29 + EdkModulePkg/Include/Guid/ConsoleOutDevice.h | 29 + EdkModulePkg/Include/Guid/ExtendedSalGuid.h | 279 + EdkModulePkg/Include/Guid/FlashMapHob.h | 33 + EdkModulePkg/Include/Guid/HotPlugDevice.h | 28 + .../Include/Guid/MemoryTypeInformation.h | 35 + EdkModulePkg/Include/Guid/MiniShellFile.h | 30 + EdkModulePkg/Include/Guid/PciHotplugDevice.h | 30 + EdkModulePkg/Include/Guid/PciOptionRomTable.h | 46 + EdkModulePkg/Include/Guid/PeiPeCoffLoader.h | 67 + EdkModulePkg/Include/Guid/PeiPerformanceHob.h | 60 + .../Include/Guid/PrimaryConsoleInDevice.h | 29 + .../Include/Guid/PrimaryConsoleOutDevice.h | 28 + .../Include/Guid/PrimaryStandardErrorDevice.h | 28 + EdkModulePkg/Include/Guid/ShellFile.h | 31 + .../Include/Guid/StandardErrorDevice.h | 29 + EdkModulePkg/Include/Guid/StatusCode.h | 33 + .../Include/Guid/StatusCodeCallerId.h | 30 + EdkModulePkg/Include/Guid/SystemNvDataGuid.h | 45 + .../Include/Library/CustomDecompressLib.h | 42 + .../Library/EdkBsDataHubStatusCodeLib.h | 47 + EdkModulePkg/Include/Library/EdkDxeSalLib.h | 141 + .../Include/Library/EdkFvbServiceLib.h | 250 + EdkModulePkg/Include/Library/EdkGraphicsLib.h | 185 + .../Include/Library/EdkIfrSupportLib.h | 1270 ++++ .../Include/Library/EdkMemoryStatusCodeLib.h | 48 + .../Include/Library/EdkPeCoffLoaderLib.h | 32 + .../Include/Library/EdkPeCoffLoaderX64Lib.h | 33 + .../Library/EdkRtMemoryStatusCodeLib.h | 66 + .../Library/EdkRtPlatformStatusCodeLib.h | 49 + EdkModulePkg/Include/Library/EdkScsiLib.h | 299 + EdkModulePkg/Include/Library/EdkUsbLib.h | 373 ++ .../Include/Library/TianoDecompressLib.h | 42 + EdkModulePkg/Include/Ppi/BaseMemoryTest.h | 56 + EdkModulePkg/Include/Ppi/FlashMap.h | 52 + EdkModulePkg/Include/Ppi/PeiInMemory.h | 29 + EdkModulePkg/Include/Ppi/StatusCodeMemory.h | 53 + EdkModulePkg/Include/Protocol/AcpiS3Save.h | 61 + .../Include/Protocol/ConsoleControl.h | 121 + .../Include/Protocol/CustomizedDecompress.h | 137 + EdkModulePkg/Include/Protocol/DebugAssert.h | 89 + EdkModulePkg/Include/Protocol/DebugLevel.h | 40 + EdkModulePkg/Include/Protocol/DiskInfo.h | 179 + EdkModulePkg/Include/Protocol/EdkDecompress.h | 137 + .../Include/Protocol/ExtendedSalBootService.h | 113 + .../Include/Protocol/FaultTolerantWriteLite.h | 88 + EdkModulePkg/Include/Protocol/FvbExtension.h | 53 + .../Include/Protocol/GenericMemoryTest.h | 156 + EdkModulePkg/Include/Protocol/IsaAcpi.h | 177 + EdkModulePkg/Include/Protocol/IsaIo.h | 174 + EdkModulePkg/Include/Protocol/LoadPe32Image.h | 68 + EdkModulePkg/Include/Protocol/OEMBadging.h | 79 + .../Include/Protocol/PciHotPlugRequest.h | 54 + EdkModulePkg/Include/Protocol/Performance.h | 166 + EdkModulePkg/Include/Protocol/Print.h | 50 + EdkModulePkg/Include/Protocol/PxeDhcp4.h | 350 + .../Include/Protocol/PxeDhcp4CallBack.h | 85 + EdkModulePkg/Include/Protocol/ScsiIo.h | 241 + .../Include/Protocol/SecurityPolicy.h | 33 + EdkModulePkg/Include/Protocol/UgaIo.h | 236 + EdkModulePkg/Include/Protocol/UgaSplash.h | 42 + EdkModulePkg/Include/Protocol/usbatapi.h | 83 + .../BaseCustomDecompressLibNull.c | 80 + .../BaseCustomDecompressLibNull.mbd | 30 + .../BaseCustomDecompressLibNull.msa | 45 + .../BaseCustomDecompressLibNull/build.xml | 47 + .../BaseUefiTianoDecompressLib.c | 887 +++ .../BaseUefiTianoDecompressLib.mbd | 30 + .../BaseUefiTianoDecompressLib.msa | 47 + .../BaseUefiTianoDecompressLib/build.xml | 47 + .../DxeCoreCustomDecompressLibFromHob.c | 105 + .../DxeCoreCustomDecompressLibFromHob.mbd | 30 + .../DxeCoreCustomDecompressLibFromHob.msa | 55 + .../build.xml | 47 + .../DxeCorePerformanceLib.c | 623 ++ .../DxeCorePerformanceLib.mbd | 29 + .../DxeCorePerformanceLib.msa | 70 + .../Library/DxeCorePerformanceLib/build.xml | 47 + .../DxeCoreTianoDecompressLibFromHob.c | 106 + .../DxeCoreTianoDecompressLibFromHob.mbd | 30 + .../DxeCoreTianoDecompressLibFromHob.msa | 55 + .../build.xml | 47 + .../DxeCoreUefiDecompressLibFromHob.c | 105 + .../DxeCoreUefiDecompressLibFromHob.mbd | 30 + .../DxeCoreUefiDecompressLibFromHob.msa | 55 + .../DxeCoreUefiDecompressLibFromHob/build.xml | 47 + .../EdkDxeDebugLibReportStatusCode/DebugLib.c | 314 + .../EdkDxeDebugLibReportStatusCode.mbd | 30 + .../EdkDxeDebugLibReportStatusCode.msa | 69 + .../EdkDxeDebugLibReportStatusCode/build.xml | 47 + .../EdkDxePeCoffLoaderFromHobLib.mbd | 30 + .../EdkDxePeCoffLoaderFromHobLib.msa | 50 + .../EdkDxePeCoffLoaderFromHobLib/PeCoff.c | 38 + .../EdkDxePeCoffLoaderFromHobLib/build.xml | 47 + .../EdkDxePerformanceLib/DxePerformanceLib.c | 213 + .../EdkDxePerformanceLib.mbd | 29 + .../EdkDxePerformanceLib.msa | 62 + .../Library/EdkDxePerformanceLib/build.xml | 47 + .../Library/EdkDxePrintLib/EdkDxePrintLib.mbd | 30 + .../Library/EdkDxePrintLib/EdkDxePrintLib.msa | 49 + .../Library/EdkDxePrintLib/PrintLib.c | 145 + EdkModulePkg/Library/EdkDxePrintLib/build.xml | 47 + .../Common/RuntimeLib.c | 258 + .../Common/RuntimeService.c | 480 ++ .../EdkDxeRuntimeDriverLib.mbd | 30 + .../EdkDxeRuntimeDriverLib.msa | 69 + .../EdkDxeRuntimeDriverLib/Ipf/RuntimeLib.c | 284 + .../Ipf/RuntimeService.c | 516 ++ .../RuntimeLibInternal.h | 30 + .../Library/EdkDxeRuntimeDriverLib/build.xml | 47 + .../Library/EdkDxeSalLib/EdkDxeSalLib.mbd | 30 + .../Library/EdkDxeSalLib/EdkDxeSalLib.msa | 58 + .../EdkDxeSalLib/Ipf/AsmEsalServiceLib.s | 149 + .../Library/EdkDxeSalLib/Ipf/AsmIpfCpuCache.s | 88 + .../Library/EdkDxeSalLib/Ipf/EsalServiceLib.c | 199 + EdkModulePkg/Library/EdkDxeSalLib/build.xml | 47 + .../EdkFvbServiceLib/EdkFvbServiceLib.mbd | 30 + .../EdkFvbServiceLib/EdkFvbServiceLib.msa | 74 + EdkModulePkg/Library/EdkFvbServiceLib/Fvb.h | 31 + .../Library/EdkFvbServiceLib/Ia32/Fvb.c | 534 ++ .../Library/EdkFvbServiceLib/Ipf/Fvb.c | 324 + .../Library/EdkFvbServiceLib/build.xml | 47 + .../Library/EdkFvbServiceLib/x64/Fvb.c | 536 ++ .../Library/EdkGraphicsLib/EdkGraphicsLib.mbd | 30 + .../Library/EdkGraphicsLib/EdkGraphicsLib.msa | 61 + .../Library/EdkGraphicsLib/Graphics.c | 780 +++ EdkModulePkg/Library/EdkGraphicsLib/build.xml | 47 + .../EdkIfrSupportLib/EdkIfrSupportLib.mbd | 30 + .../EdkIfrSupportLib/EdkIfrSupportLib.msa | 75 + .../Library/EdkIfrSupportLib/IfrCommon.c | 995 +++ .../Library/EdkIfrSupportLib/IfrOnTheFly.c | 972 +++ .../EdkIfrSupportLib/IfrOpCodeCreation.c | 613 ++ .../Library/EdkIfrSupportLib/IfrVariable.c | 484 ++ .../Library/EdkIfrSupportLib/build.xml | 47 + .../EdkMemoryStatusCodeLib.mbd | 30 + .../EdkMemoryStatusCodeLib.msa | 63 + .../EdkMemoryStatusCodeLib/MemoryStatusCode.c | 498 ++ .../EdkMemoryStatusCodeLib/MemoryStatusCode.h | 94 + .../Library/EdkMemoryStatusCodeLib/build.xml | 47 + .../CustomizedDecompress.c | 109 + .../CustomizedDecompress.h | 95 + .../EdkNullCustomizedDecompressLib.mbd | 30 + .../EdkNullCustomizedDecompressLib.msa | 44 + .../EdkNullCustomizedDecompressLib/build.xml | 47 + .../EdkPeCoffLoaderLib/EdkPeCoffLoader.c | 112 + .../EdkPeCoffLoaderLib/EdkPeCoffLoaderLib.mbd | 30 + .../EdkPeCoffLoaderLib/EdkPeCoffLoaderLib.msa | 45 + .../Library/EdkPeCoffLoaderLib/build.xml | 47 + .../EdkPeCoffLoaderX64.c | 940 +++ .../EdkPeCoffLoaderX64Lib.mbd | 30 + .../EdkPeCoffLoaderX64Lib.msa | 46 + .../Library/EdkPeCoffLoaderX64Lib/build.xml | 46 + .../EdkPeiPerformanceLib.mbd | 29 + .../EdkPeiPerformanceLib.msa | 61 + .../EdkPeiPerformanceLib/PeiPerformanceLib.c | 315 + .../Library/EdkPeiPerformanceLib/build.xml | 47 + .../BsDataHubStatusCode/BsDataHubStatusCode.c | 397 ++ .../BsDataHubStatusCode/BsDataHubStatusCode.h | 130 + .../BsDataHubStatusCode.mbd | 30 + .../BsDataHubStatusCode.msa | 72 + .../BsDataHubStatusCode/build.xml | 47 + .../RtMemoryStatusCode/RtMemoryStatusCode.c | 188 + .../RtMemoryStatusCode/RtMemoryStatusCode.mbd | 30 + .../RtMemoryStatusCode/RtMemoryStatusCode.msa | 52 + .../RtMemoryStatusCode/build.xml | 47 + .../RtPlatformStatusCode.c | 130 + .../RtPlatformStatusCode.mbd | 30 + .../RtPlatformStatusCode.msa | 54 + .../RtPlatformStatusCode/build.xml | 47 + .../Library/EdkScsiLib/EdkScsiLib.mbd | 30 + .../Library/EdkScsiLib/EdkScsiLib.msa | 45 + EdkModulePkg/Library/EdkScsiLib/ScsiLib.c | 651 ++ EdkModulePkg/Library/EdkScsiLib/build.xml | 47 + .../Library/EdkUefiDebugLibConOut/DebugLib.c | 255 + .../EdkUefiDebugLibConOut.mbd | 30 + .../EdkUefiDebugLibConOut.msa | 69 + .../Library/EdkUefiDebugLibConOut/build.xml | 47 + .../Library/EdkUefiDebugLibStdErr/DebugLib.c | 255 + .../EdkUefiDebugLibStdErr.mbd | 30 + .../EdkUefiDebugLibStdErr.msa | 69 + .../Library/EdkUefiDebugLibStdErr/build.xml | 47 + EdkModulePkg/Library/EdkUsbLib/EdkUsbLib.mbd | 30 + EdkModulePkg/Library/EdkUsbLib/EdkUsbLib.msa | 46 + EdkModulePkg/Library/EdkUsbLib/UsbDxeLib.c | 699 ++ EdkModulePkg/Library/EdkUsbLib/build.xml | 47 + EdkModulePkg/Library/EdkUsbLib/hid.c | 459 ++ .../Console/ConSplitter/Dxe/ComponentName.c | 531 ++ .../Console/ConSplitter/Dxe/ConSplitter.c | 3193 +++++++++ .../Console/ConSplitter/Dxe/ConSplitter.h | 623 ++ .../Console/ConSplitter/Dxe/ConSplitter.mbd | 41 + .../Console/ConSplitter/Dxe/ConSplitter.msa | 102 + .../ConSplitter/Dxe/ConSplitterGraphics.c | 1076 ++++ .../Console/ConSplitter/Dxe/build.xml | 74 + .../GraphicsConsole/Dxe/ComponentName.c | 139 + .../GraphicsConsole/Dxe/ComponentName.h | 51 + .../GraphicsConsole/Dxe/GraphicsConsole.c | 1566 +++++ .../GraphicsConsole/Dxe/GraphicsConsole.h | 160 + .../GraphicsConsole/Dxe/GraphicsConsole.mbd | 42 + .../GraphicsConsole/Dxe/GraphicsConsole.msa | 69 + .../Console/GraphicsConsole/Dxe/LaffStd.c | 290 + .../Console/GraphicsConsole/Dxe/build.xml | 47 + .../Console/Terminal/Dxe/ComponentName.c | 194 + .../Universal/Console/Terminal/Dxe/Terminal.c | 1214 ++++ .../Universal/Console/Terminal/Dxe/Terminal.h | 506 ++ .../Console/Terminal/Dxe/Terminal.mbd | 44 + .../Console/Terminal/Dxe/Terminal.msa | 108 + .../Console/Terminal/Dxe/TerminalConIn.c | 1185 ++++ .../Console/Terminal/Dxe/TerminalConOut.c | 997 +++ .../Universal/Console/Terminal/Dxe/ansi.c | 68 + .../Universal/Console/Terminal/Dxe/build.xml | 47 + .../Universal/Console/Terminal/Dxe/vtutf8.c | 270 + .../Universal/DataHub/DataHub/Dxe/DataHub.c | 655 ++ .../Universal/DataHub/DataHub/Dxe/DataHub.dxs | 26 + .../Universal/DataHub/DataHub/Dxe/DataHub.h | 122 + .../Universal/DataHub/DataHub/Dxe/DataHub.mbd | 44 + .../Universal/DataHub/DataHub/Dxe/DataHub.msa | 61 + .../Universal/DataHub/DataHub/Dxe/build.xml | 47 + .../DataHub/DataHubStdErr/Dxe/DataHubStdErr.c | 163 + .../DataHubStdErr/Dxe/DataHubStdErr.dxs | 27 + .../DataHubStdErr/Dxe/DataHubStdErr.mbd | 41 + .../DataHubStdErr/Dxe/DataHubStdErr.msa | 64 + .../DataHub/DataHubStdErr/Dxe/build.xml | 47 + .../Universal/DebugSupport/Dxe/DebugSupport.c | 151 + .../DebugSupport/Dxe/DebugSupport.dxs | 26 + .../DebugSupport/Dxe/DebugSupport.mbd | 42 + .../DebugSupport/Dxe/DebugSupport.msa | 68 + .../Universal/DebugSupport/Dxe/build.xml | 47 + .../DebugSupport/Dxe/ia32/AsmFuncs.asm | 547 ++ .../DebugSupport/Dxe/ia32/plDebugSupport.c | 440 ++ .../DebugSupport/Dxe/ia32/plDebugSupport.h | 312 + .../Universal/DebugSupport/Dxe/ipf/AsmFuncs.s | 1389 ++++ .../DebugSupport/Dxe/ipf/Ds64Macros.i | 85 + .../Universal/DebugSupport/Dxe/ipf/common.i | 34 + .../DebugSupport/Dxe/ipf/plDebugSupport.c | 625 ++ .../Debugger/Debugport/Dxe/ComponentName.c | 108 + .../Debugger/Debugport/Dxe/DebugPort.c | 833 +++ .../Debugger/Debugport/Dxe/DebugPort.dxs | 26 + .../Debugger/Debugport/Dxe/DebugPort.h | 172 + .../Debugger/Debugport/Dxe/DebugPort.mbd | 46 + .../Debugger/Debugport/Dxe/DebugPort.msa | 77 + .../Debugger/Debugport/Dxe/build.xml | 47 + .../Universal/Disk/DiskIo/Dxe/ComponentName.c | 160 + .../Universal/Disk/DiskIo/Dxe/DiskIo.mbd | 41 + .../Universal/Disk/DiskIo/Dxe/DiskIo.msa | 65 + .../Universal/Disk/DiskIo/Dxe/build.xml | 47 + .../Universal/Disk/DiskIo/Dxe/diskio.c | 876 +++ .../Universal/Disk/DiskIo/Dxe/diskio.h | 44 + .../DiskIoPartition/dxe/DiskIoPartition.mbd | 42 + .../DiskIoPartition/dxe/DiskIoPartition.msa | 88 + .../Disk/DiskIoPartition/dxe/build.xml | 47 + .../Disk/Partition/Dxe/ComponentName.c | 160 + .../Universal/Disk/Partition/Dxe/ElTorito.c | 277 + .../Universal/Disk/Partition/Dxe/ElTorito.h | 130 + .../Universal/Disk/Partition/Dxe/Gpt.c | 768 +++ .../Universal/Disk/Partition/Dxe/Gpt.h | 76 + .../Universal/Disk/Partition/Dxe/Mbr.c | 317 + .../Universal/Disk/Partition/Dxe/Mbr.h | 68 + .../Universal/Disk/Partition/Dxe/Partition.c | 735 +++ .../Universal/Disk/Partition/Dxe/Partition.h | 123 + .../Disk/Partition/Dxe/Partition.mbd | 42 + .../Disk/Partition/Dxe/Partition.msa | 81 + .../Universal/Disk/Partition/Dxe/build.xml | 47 + .../UnicodeCollation/English/Dxe/English.mbd | 38 + .../UnicodeCollation/English/Dxe/English.msa | 53 + .../English/Dxe/UnicodeCollationEng.c | 478 ++ .../English/Dxe/UnicodeCollationEng.h | 102 + .../UnicodeCollation/English/Dxe/build.xml | 47 + EdkModulePkg/Universal/Ebc/Dxe/Ebc.dxs | 26 + EdkModulePkg/Universal/Ebc/Dxe/Ebc.mbd | 43 + EdkModulePkg/Universal/Ebc/Dxe/Ebc.msa | 80 + EdkModulePkg/Universal/Ebc/Dxe/EbcExecute.c | 4603 +++++++++++++ EdkModulePkg/Universal/Ebc/Dxe/EbcExecute.h | 383 ++ EdkModulePkg/Universal/Ebc/Dxe/EbcInt.c | 932 +++ EdkModulePkg/Universal/Ebc/Dxe/EbcInt.h | 231 + .../Universal/Ebc/Dxe/Ia32/EbcLowLevel.asm | 148 + .../Universal/Ebc/Dxe/Ia32/EbcSupport.c | 482 ++ .../Universal/Ebc/Dxe/Ia32/Ia32Math.asm | 622 ++ .../Universal/Ebc/Dxe/Ipf/EbcLowLevel.s | 167 + .../Universal/Ebc/Dxe/Ipf/EbcSupport.c | 906 +++ EdkModulePkg/Universal/Ebc/Dxe/Ipf/IpfMath.c | 375 ++ EdkModulePkg/Universal/Ebc/Dxe/Ipf/IpfMul.s | 144 + EdkModulePkg/Universal/Ebc/Dxe/build.xml | 47 + .../Universal/Ebc/Dxe/x64/EbcLowLevel.asm | 145 + .../Universal/Ebc/Dxe/x64/EbcSupport.c | 579 ++ EdkModulePkg/Universal/Ebc/Dxe/x64/x64Math.c | 451 ++ .../EmuVariable/RuntimeDxe/EmuVariable.c | 754 +++ .../EmuVariable/RuntimeDxe/EmuVariable.dxs | 25 + .../EmuVariable/RuntimeDxe/EmuVariable.mbd | 45 + .../EmuVariable/RuntimeDxe/EmuVariable.msa | 76 + .../EmuVariable/RuntimeDxe/InitVariable.c | 185 + .../EmuVariable/RuntimeDxe/Ipf/InitVariable.c | 167 + .../EmuVariable/RuntimeDxe/Variable.h | 143 + .../EmuVariable/RuntimeDxe/build.xml | 47 + .../FaultTolerantWriteLite/Dxe/FtwLite.c | 951 +++ .../FaultTolerantWriteLite/Dxe/FtwLite.dxs | 28 + .../FaultTolerantWriteLite/Dxe/FtwLite.h | 675 ++ .../FaultTolerantWriteLite/Dxe/FtwLite.mbd | 44 + .../FaultTolerantWriteLite/Dxe/FtwLite.msa | 90 + .../FaultTolerantWriteLite/Dxe/FtwMisc.c | 530 ++ .../FaultTolerantWriteLite/Dxe/FtwWorkSpace.c | 567 ++ .../Dxe/Ia32/Ia32FtwMisc.c | 399 ++ .../Dxe/Ipf/IpfFtwMisc.c | 143 + .../FaultTolerantWriteLite/Dxe/build.xml | 47 + .../Dxe/x64/x64FtwMisc.c | 140 + .../Dxe/Crc32SectionExtract.c | 234 + .../Dxe/Crc32SectionExtract.dxs | 28 + .../Dxe/Crc32SectionExtract.h | 65 + .../Dxe/Crc32SectionExtract.mbd | 40 + .../Dxe/Crc32SectionExtract.msa | 61 + .../Crc32SectionExtract/Dxe/GuidedSection.c | 75 + .../Crc32SectionExtract/Dxe/GuidedSection.h | 53 + .../Crc32SectionExtract/Dxe/build.xml | 47 + .../Universal/GenericMemoryTest/Dxe/Common.h | 59 + .../GenericMemoryTest/Dxe/NullMemoryTest.c | 214 + .../GenericMemoryTest/Dxe/NullMemoryTest.dxs | 26 + .../GenericMemoryTest/Dxe/NullMemoryTest.h | 65 + .../GenericMemoryTest/Dxe/NullMemoryTest.mbd | 44 + .../GenericMemoryTest/Dxe/NullMemoryTest.msa | 60 + .../Universal/GenericMemoryTest/Dxe/build.xml | 47 + .../GenericMemoryTest/Pei/BaseMemoryTest.c | 154 + .../GenericMemoryTest/Pei/BaseMemoryTest.h | 89 + .../GenericMemoryTest/Pei/BaseMemoryTest.mbd | 39 + .../GenericMemoryTest/Pei/BaseMemoryTest.msa | 54 + .../Universal/GenericMemoryTest/Pei/build.xml | 47 + .../RuntimeDxe/MonotonicCounter.c | 266 + .../RuntimeDxe/MonotonicCounter.dxs | 27 + .../RuntimeDxe/MonotonicCounter.h | 36 + .../RuntimeDxe/MonotonicCounter.mbd | 47 + .../RuntimeDxe/MonotonicCounter.msa | 70 + .../MonotonicCounter/RuntimeDxe/build.xml | 47 + .../Universal/Network/PxeBc/Dxe/BC.mbd | 42 + .../Universal/Network/PxeBc/Dxe/BC.msa | 94 + .../Network/PxeBc/Dxe/ComponentName.c | 160 + .../Universal/Network/PxeBc/Dxe/Print.c | 81 + EdkModulePkg/Universal/Network/PxeBc/Dxe/bc.c | 2510 ++++++++ EdkModulePkg/Universal/Network/PxeBc/Dxe/bc.h | 499 ++ .../Universal/Network/PxeBc/Dxe/build.xml | 47 + .../Universal/Network/PxeBc/Dxe/dhcp.h | 627 ++ .../Universal/Network/PxeBc/Dxe/hton.h | 42 + EdkModulePkg/Universal/Network/PxeBc/Dxe/ip.h | 741 +++ .../Universal/Network/PxeBc/Dxe/pxe_bc_arp.c | 617 ++ .../Universal/Network/PxeBc/Dxe/pxe_bc_dhcp.c | 3332 ++++++++++ .../Universal/Network/PxeBc/Dxe/pxe_bc_igmp.c | 476 ++ .../Universal/Network/PxeBc/Dxe/pxe_bc_ip.c | 861 +++ .../Network/PxeBc/Dxe/pxe_bc_mtftp.c | 2391 +++++++ .../Universal/Network/PxeBc/Dxe/pxe_bc_udp.c | 577 ++ .../Network/PxeBc/Dxe/pxe_loadfile.c | 1697 +++++ .../Universal/Network/PxeBc/Dxe/tftp.h | 153 + .../Network/PxeDhcp4/Dxe/ComponentName.c | 169 + .../Universal/Network/PxeDhcp4/Dxe/Dhcp4.mbd | 41 + .../Universal/Network/PxeDhcp4/Dxe/Dhcp4.msa | 74 + .../Universal/Network/PxeDhcp4/Dxe/PxeDhcp4.c | 342 + .../Universal/Network/PxeDhcp4/Dxe/PxeDhcp4.h | 307 + .../Network/PxeDhcp4/Dxe/PxeDhcp4InitSelect.c | 786 +++ .../Network/PxeDhcp4/Dxe/PxeDhcp4Release.c | 246 + .../PxeDhcp4/Dxe/PxeDhcp4RenewRebind.c | 408 ++ .../Network/PxeDhcp4/Dxe/PxeDhcp4Run.c | 196 + .../Network/PxeDhcp4/Dxe/PxeDhcp4Setup.c | 268 + .../Universal/Network/PxeDhcp4/Dxe/build.xml | 47 + .../Universal/Network/PxeDhcp4/Dxe/support.c | 1126 ++++ .../Network/Snp32_64/Dxe/ComponentName.c | 160 + .../Universal/Network/Snp32_64/Dxe/SNP.mbd | 41 + .../Universal/Network/Snp32_64/Dxe/SNP.msa | 85 + .../Network/Snp32_64/Dxe/WaitForPacket.c | 100 + .../Universal/Network/Snp32_64/Dxe/build.xml | 47 + .../Universal/Network/Snp32_64/Dxe/callback.c | 613 ++ .../Network/Snp32_64/Dxe/get_status.c | 193 + .../Network/Snp32_64/Dxe/initialize.c | 244 + .../Network/Snp32_64/Dxe/mcast_ip_to_mac.c | 167 + .../Universal/Network/Snp32_64/Dxe/nvdata.c | 183 + .../Universal/Network/Snp32_64/Dxe/receive.c | 255 + .../Network/Snp32_64/Dxe/receive_filters.c | 411 ++ .../Universal/Network/Snp32_64/Dxe/reset.c | 129 + .../Universal/Network/Snp32_64/Dxe/shutdown.c | 152 + .../Universal/Network/Snp32_64/Dxe/snp.c | 1315 ++++ .../Universal/Network/Snp32_64/Dxe/snp.h | 410 ++ .../Universal/Network/Snp32_64/Dxe/start.c | 191 + .../Network/Snp32_64/Dxe/station_address.c | 248 + .../Network/Snp32_64/Dxe/statistics.c | 193 + .../Universal/Network/Snp32_64/Dxe/stop.c | 120 + .../Universal/Network/Snp32_64/Dxe/transmit.c | 396 ++ EdkModulePkg/Universal/PCD/Common/PcdCommon.c | 592 ++ EdkModulePkg/Universal/PCD/Common/PcdCommon.h | 386 ++ EdkModulePkg/Universal/PCD/Dxe/Pcd.c | 472 ++ EdkModulePkg/Universal/PCD/Dxe/Service.c | 491 ++ EdkModulePkg/Universal/PCD/Dxe/Service.h | 399 ++ EdkModulePkg/Universal/PCD/Pei/Pcd.c | 486 ++ EdkModulePkg/Universal/PCD/Pei/Service.c | 812 +++ EdkModulePkg/Universal/PCD/Pei/Service.h | 371 ++ EdkModulePkg/Universal/PCD/Test/PcdTest.c | 110 + EdkModulePkg/Universal/PCD/Test/PcdTest.dxs | 28 + .../Universal/Runtime/RuntimeDxe/Crc32.c | 124 + .../Runtime/RuntimeDxe/Ia32/PeHotRelocateEx.c | 88 + .../Runtime/RuntimeDxe/Ipf/PeHotRelocateEx.c | 242 + .../Runtime/RuntimeDxe/Ipf/PeHotRelocateEx.h | 76 + .../Runtime/RuntimeDxe/PeHotRelocate.c | 216 + .../Universal/Runtime/RuntimeDxe/Runtime.c | 574 ++ .../Universal/Runtime/RuntimeDxe/Runtime.dxs | 26 + .../Universal/Runtime/RuntimeDxe/Runtime.h | 129 + .../Universal/Runtime/RuntimeDxe/Runtime.mbd | 46 + .../Universal/Runtime/RuntimeDxe/Runtime.msa | 80 + .../Universal/Runtime/RuntimeDxe/build.xml | 47 + .../Runtime/RuntimeDxe/x64/PeHotRelocateEx.c | 88 + .../Security/SecurityStub/Dxe/SecurityStub.c | 156 + .../SecurityStub/Dxe/SecurityStub.dxs | 27 + .../Security/SecurityStub/Dxe/SecurityStub.h | 47 + .../SecurityStub/Dxe/SecurityStub.mbd | 40 + .../SecurityStub/Dxe/SecurityStub.msa | 55 + .../Security/SecurityStub/Dxe/build.xml | 47 + .../StatusCode/RuntimeDxe/DebugAssert.c | 231 + .../RuntimeDxe/Ia32/Ia32StatusCode.c | 75 + .../RuntimeDxe/Ia32/Ia32StatusCode.dxs | 26 + .../StatusCode/RuntimeDxe/Ipf/IpfStatusCode.c | 126 + .../RuntimeDxe/Ipf/IpfStatusCode.dxs | 27 + .../StatusCode/RuntimeDxe/StatusCode.c | 172 + .../StatusCode/RuntimeDxe/StatusCode.h | 64 + .../StatusCode/RuntimeDxe/StatusCode.mbd | 55 + .../StatusCode/RuntimeDxe/StatusCode.msa | 77 + .../Universal/StatusCode/RuntimeDxe/build.xml | 47 + .../StatusCode/RuntimeDxe/x64/x64StatusCode.c | 75 + .../RuntimeDxe/x64/x64StatusCode.dxs | 27 + .../UserInterface/HiiDataBase/Dxe/Fonts.c | 263 + .../UserInterface/HiiDataBase/Dxe/Forms.c | 1564 +++++ .../HiiDataBase/Dxe/HiiDatabase.c | 413 ++ .../HiiDataBase/Dxe/HiiDatabase.dxs | 26 + .../HiiDataBase/Dxe/HiiDatabase.h | 302 + .../HiiDataBase/Dxe/HiiDatabase.mbd | 44 + .../HiiDataBase/Dxe/HiiDatabase.msa | 80 + .../UserInterface/HiiDataBase/Dxe/Keyboard.c | 43 + .../UserInterface/HiiDataBase/Dxe/Package.c | 677 ++ .../UserInterface/HiiDataBase/Dxe/Strings.c | 1276 ++++ .../UserInterface/HiiDataBase/Dxe/build.xml | 47 + .../UserInterface/SetupBrowser/Dxe/Boolean.c | 1360 ++++ .../UserInterface/SetupBrowser/Dxe/Colors.h | 54 + .../Dxe/DriverSample/DriverSample.c | 631 ++ .../Dxe/DriverSample/DriverSample.h | 60 + .../Dxe/DriverSample/DriverSample.mbd | 45 + .../Dxe/DriverSample/DriverSample.msa | 84 + .../Dxe/DriverSample/NVDataStruc.h | 62 + .../SetupBrowser/Dxe/DriverSample/Vfr.vfr | 622 ++ .../Dxe/DriverSample/VfrStrings.uni | Bin 0 -> 35590 bytes .../SetupBrowser/Dxe/DriverSample/build.xml | 47 + .../Dxe/DriverSample/inventory.vfr | 123 + .../Dxe/DriverSample/inventorystrings.uni | Bin 0 -> 8302 bytes .../SetupBrowser/Dxe/InputHandler.c | 1580 +++++ .../SetupBrowser/Dxe/Presentation.c | 1481 +++++ .../UserInterface/SetupBrowser/Dxe/Print.c | 338 + .../UserInterface/SetupBrowser/Dxe/Print.h | 37 + .../SetupBrowser/Dxe/ProcessOptions.c | 1677 +++++ .../UserInterface/SetupBrowser/Dxe/Setup.c | 2217 +++++++ .../UserInterface/SetupBrowser/Dxe/Setup.h | 504 ++ .../SetupBrowser/Dxe/SetupBrowser.mbd | 43 + .../SetupBrowser/Dxe/SetupBrowser.msa | 82 + .../SetupBrowser/Dxe/SetupBrowserStr.uni | Bin 0 -> 11028 bytes .../UserInterface/SetupBrowser/Dxe/Ui.c | 3143 +++++++++ .../UserInterface/SetupBrowser/Dxe/Ui.h | 435 ++ .../UserInterface/SetupBrowser/Dxe/build.xml | 47 + .../Universal/Variable/Pei/Ia32/VarMachine.h | 27 + .../Universal/Variable/Pei/Ipf/VarMachine.h | 27 + .../Universal/Variable/Pei/Variable.c | 563 ++ .../Universal/Variable/Pei/Variable.dxs | 28 + .../Universal/Variable/Pei/Variable.h | 154 + .../Universal/Variable/Pei/Variable.mbd | 43 + .../Universal/Variable/Pei/Variable.msa | 57 + EdkModulePkg/Universal/Variable/Pei/build.xml | 47 + .../Universal/Variable/Pei/x64/VarMachine.h | 27 + .../Variable/RuntimeDxe/Emu/EmuVariable.c | 754 +++ .../Variable/RuntimeDxe/Emu/EmuVariable.dxs | 25 + .../Variable/RuntimeDxe/Emu/EmuVariable.mbd | 45 + .../Variable/RuntimeDxe/Emu/EmuVariable.msa | 73 + .../Variable/RuntimeDxe/Emu/build.xml | 47 + .../Variable/RuntimeDxe/Ia32Variable.dxs | 28 + .../Variable/RuntimeDxe/InitVariable.c | 185 + .../Variable/RuntimeDxe/Ipf/InitVariable.c | 167 + .../Variable/RuntimeDxe/IpfVariable.dxs | 28 + .../Universal/Variable/RuntimeDxe/Variable.c | 1311 ++++ .../Universal/Variable/RuntimeDxe/Variable.h | 143 + .../Variable/RuntimeDxe/Variable.mbd | 51 + .../Variable/RuntimeDxe/Variable.msa | 109 + .../Universal/Variable/RuntimeDxe/build.xml | 47 + .../Universal/Variable/RuntimeDxe/reclaim.c | 240 + .../Universal/Variable/RuntimeDxe/reclaim.h | 45 + .../Variable/RuntimeDxe/x64Variable.dxs | 26 + .../WatchdogTimer/Dxe/WatchDogTimer.c | 310 + .../WatchdogTimer/Dxe/WatchDogTimer.dxs | 27 + .../WatchdogTimer/Dxe/WatchDogTimer.h | 62 + .../WatchdogTimer/Dxe/WatchDogTimer.mbd | 44 + .../WatchdogTimer/Dxe/WatchDogTimer.msa | 61 + .../Universal/WatchdogTimer/Dxe/build.xml | 47 + EdkModulePkg/build.xml | 74 + EdkModulePkg/genbuildfile.xml | 19 + EdkNt32Pkg/Build/AprioriList.mbd | 32 + EdkNt32Pkg/Build/AprioriList.msa | 44 + EdkNt32Pkg/Build/Nt32Common.xml | 183 + EdkNt32Pkg/Build/component.def | 12 + EdkNt32Pkg/Dxe/ConPlatform/ComponentName.c | 141 + EdkNt32Pkg/Dxe/ConPlatform/ComponentName.h | 44 + EdkNt32Pkg/Dxe/ConPlatform/ConPlatform.c | 811 +++ EdkNt32Pkg/Dxe/ConPlatform/ConPlatform.h | 126 + EdkNt32Pkg/Dxe/ConPlatform/ConPlatform.mbd | 44 + EdkNt32Pkg/Dxe/ConPlatform/ConPlatform.msa | 116 + EdkNt32Pkg/Dxe/ConPlatform/build.xml | 47 + .../MiscBaseBoardManufacturer.uni | Bin 0 -> 2896 bytes .../MiscBaseBoardManufacturerData.c | 57 + .../MiscSubclass/MiscBiosLanguageData.c | 45 + .../MiscSubclass/MiscBiosVendor.uni | Bin 0 -> 2260 bytes .../MiscSubclass/MiscBiosVendorData.c | 88 + .../MiscSubclass/MiscBootInformationData.c | 33 + .../MiscSubclass/MiscChassisManufacturer.uni | Bin 0 -> 2460 bytes .../MiscChassisManufacturerData.c | 45 + .../MiscSubclass/MiscDevicePath.h | 175 + .../MiscNumberOfInstallableLanguagesData.c | 37 + .../MiscSubclass/MiscOemString.uni | Bin 0 -> 1996 bytes .../MiscSubclass/MiscOemStringData.c | 32 + .../MiscSubclass/MiscOnboardDevice.uni | Bin 0 -> 2042 bytes .../MiscSubclass/MiscOnboardDeviceData.c | 36 + .../MiscSubclass/MiscOnboardDeviceFunction.c | 164 + .../MiscPortInternalConnectorDesignator.uni | Bin 0 -> 9426 bytes .../MiscPortInternalConnectorDesignatorData.c | 99 + ...cPortInternalConnectorDesignatorFunction.c | 266 + .../MiscSubclass/MiscResetCapabilitiesData.c | 42 + .../MiscSubclass/MiscSubclassDriver.dxs | 27 + .../MiscSubclass/MiscSubclassDriver.h | 104 + .../MiscSubclass/MiscSubclassDriver.mbd | 45 + .../MiscSubclass/MiscSubclassDriver.msa | 114 + .../MiscSubclass/MiscSubclassDriver.uni | Bin 0 -> 2846 bytes .../MiscSubclassDriverDataTable.c | 103 + .../MiscSubclassDriverEntryPoint.c | 518 ++ .../MiscSubclass/MiscSystemLanguageString.uni | Bin 0 -> 2014 bytes .../MiscSystemLanguageStringData.c | 33 + .../MiscSubclass/MiscSystemManufacturer.uni | Bin 0 -> 2456 bytes .../MiscSubclass/MiscSystemManufacturerData.c | 55 + .../MiscSystemManufacturerFunction.c | 122 + .../MiscSubclass/MiscSystemOptionString.uni | Bin 0 -> 2004 bytes .../MiscSubclass/MiscSystemOptionStringData.c | 32 + .../MiscSystemSlotDesignation.uni | Bin 0 -> 2030 bytes .../MiscSystemSlotDesignationData.c | 52 + .../Dxe/Nt32Platform/MiscSubclass/build.xml | 47 + EdkNt32Pkg/Dxe/PcdEmulator/PcdEmulator.c | 557 ++ EdkNt32Pkg/Dxe/PcdEmulator/PcdEmulator.dxs | 27 + EdkNt32Pkg/Dxe/PcdEmulator/PcdEmulator.h | 43 + EdkNt32Pkg/Dxe/PcdEmulator/PcdEmulator.mbd | 46 + EdkNt32Pkg/Dxe/PcdEmulator/PcdEmulator.msa | 75 + EdkNt32Pkg/Dxe/PcdEmulator/build.xml | 47 + EdkNt32Pkg/Dxe/PlatformBds/BdsPlatform.c | 517 ++ EdkNt32Pkg/Dxe/PlatformBds/BdsPlatform.h | 140 + EdkNt32Pkg/Dxe/PlatformBds/Generic/Bds.dxs | 27 + EdkNt32Pkg/Dxe/PlatformBds/Generic/Bds.h | 83 + EdkNt32Pkg/Dxe/PlatformBds/Generic/BdsEntry.c | 356 + .../Generic/BootMaint/BBSsupport.c | 1515 +++++ .../Generic/BootMaint/BBSsupport.h | 83 + .../Dxe/PlatformBds/Generic/BootMaint/BmLib.c | 626 ++ .../PlatformBds/Generic/BootMaint/BootMaint.c | 1305 ++++ .../PlatformBds/Generic/BootMaint/BootMaint.h | 1161 ++++ .../Generic/BootMaint/BootOption.c | 1657 +++++ .../Generic/BootMaint/ConsoleOption.c | 840 +++ .../Dxe/PlatformBds/Generic/BootMaint/Data.c | 324 + .../Dxe/PlatformBds/Generic/BootMaint/FE.vfr | 138 + .../Generic/BootMaint/FileExplorer.c | 335 + .../PlatformBds/Generic/BootMaint/FormGuid.h | 32 + .../Generic/BootMaint/UpdatePage.c | 1275 ++++ .../PlatformBds/Generic/BootMaint/Variable.c | 1279 ++++ .../Dxe/PlatformBds/Generic/BootMaint/bm.vfr | 495 ++ .../Generic/BootMaint/bmstring.uni | Bin 0 -> 36240 bytes .../Generic/BootMngr/BootManager.c | 333 + .../Generic/BootMngr/BootManager.h | 50 + .../Generic/BootMngr/BootManagerStrings.uni | Bin 0 -> 3942 bytes .../Generic/BootMngr/BootManagerVfr.Vfr | 55 + EdkNt32Pkg/Dxe/PlatformBds/Generic/Capsules.c | 213 + .../Generic/DeviceMngr/DeviceManager.c | 482 ++ .../Generic/DeviceMngr/DeviceManager.h | 59 + .../DeviceMngr/DeviceManagerStrings.uni | Bin 0 -> 4232 bytes .../Generic/DeviceMngr/DeviceManagerVfr.Vfr | 75 + .../Dxe/PlatformBds/Generic/FrontPage.c | 888 +++ .../Dxe/PlatformBds/Generic/FrontPage.h | 100 + .../PlatformBds/Generic/FrontPageStrings.uni | Bin 0 -> 9938 bytes .../Dxe/PlatformBds/Generic/FrontPageVfr.Vfr | 159 + EdkNt32Pkg/Dxe/PlatformBds/Generic/Language.c | 431 ++ EdkNt32Pkg/Dxe/PlatformBds/Generic/Language.h | 36 + .../Dxe/PlatformBds/Generic/MemoryTest.c | 386 ++ EdkNt32Pkg/Dxe/PlatformBds/Generic/String.c | 133 + EdkNt32Pkg/Dxe/PlatformBds/Generic/String.h | 59 + .../Dxe/PlatformBds/Generic/Strings.uni | Bin 0 -> 7870 bytes EdkNt32Pkg/Dxe/PlatformBds/PlatformBds.mbd | 54 + EdkNt32Pkg/Dxe/PlatformBds/PlatformBds.msa | 151 + EdkNt32Pkg/Dxe/PlatformBds/PlatformData.c | 182 + EdkNt32Pkg/Dxe/PlatformBds/build.xml | 47 + .../WinNtThunk/Bus/BlockIo/ComponentName.c | 187 + .../Bus/BlockIo/DriverConfiguration.c | 338 + .../Bus/BlockIo/DriverDiagnostics.c | 186 + .../Dxe/WinNtThunk/Bus/BlockIo/WinNtBlockIo.c | 1085 ++++ .../Dxe/WinNtThunk/Bus/BlockIo/WinNtBlockIo.h | 471 ++ .../WinNtThunk/Bus/BlockIo/WinNtBlockIo.mbd | 41 + .../WinNtThunk/Bus/BlockIo/WinNtBlockIo.msa | 78 + .../Dxe/WinNtThunk/Bus/BlockIo/build.xml | 47 + .../WinNtThunk/Bus/Console/ComponentName.c | 187 + .../Dxe/WinNtThunk/Bus/Console/Console.c | 307 + .../Dxe/WinNtThunk/Bus/Console/Console.h | 512 ++ .../Dxe/WinNtThunk/Bus/Console/ConsoleIn.c | 361 ++ .../Dxe/WinNtThunk/Bus/Console/ConsoleOut.c | 638 ++ .../WinNtThunk/Bus/Console/WinNtConsole.mbd | 41 + .../WinNtThunk/Bus/Console/WinNtConsole.msa | 75 + .../Dxe/WinNtThunk/Bus/Console/build.xml | 47 + .../WinNtThunk/Bus/SerialIo/ComponentName.c | 187 + .../WinNtThunk/Bus/SerialIo/WinNtSerialIo.c | 1410 ++++ .../WinNtThunk/Bus/SerialIo/WinNtSerialIo.h | 513 ++ .../WinNtThunk/Bus/SerialIo/WinNtSerialIo.mbd | 42 + .../WinNtThunk/Bus/SerialIo/WinNtSerialIo.msa | 74 + .../Dxe/WinNtThunk/Bus/SerialIo/build.xml | 47 + .../Bus/SimpleFileSystem/ComponentName.c | 193 + .../SimpleFileSystem/WinNtSimpleFileSystem.c | 2615 ++++++++ .../SimpleFileSystem/WinNtSimpleFileSystem.h | 587 ++ .../WinNtSimpleFileSystem.mbd | 41 + .../WinNtSimpleFileSystem.msa | 81 + .../WinNtThunk/Bus/SimpleFileSystem/build.xml | 47 + .../Dxe/WinNtThunk/Bus/Uga/ComponentName.c | 187 + EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/WinNtUga.h | 363 ++ .../Dxe/WinNtThunk/Bus/Uga/WinNtUga.mbd | 41 + .../Dxe/WinNtThunk/Bus/Uga/WinNtUga.msa | 83 + .../Dxe/WinNtThunk/Bus/Uga/WinNtUgaDriver.c | 343 + .../Dxe/WinNtThunk/Bus/Uga/WinNtUgaInput.c | 411 ++ .../Dxe/WinNtThunk/Bus/Uga/WinNtUgaScreen.c | 992 +++ EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/build.xml | 47 + .../Bus/WinNtBusDriver/ComponentName.c | 187 + .../Bus/WinNtBusDriver/WinNtBusDriver.c | 744 +++ .../Bus/WinNtBusDriver/WinNtBusDriver.h | 297 + .../Bus/WinNtBusDriver/WinNtBusDriver.mbd | 43 + .../Bus/WinNtBusDriver/WinNtBusDriver.msa | 167 + .../WinNtThunk/Bus/WinNtBusDriver/build.xml | 47 + .../WinNtThunk/Chipset/Metronome/Metronome.c | 129 + .../Chipset/Metronome/Metronome.dxs | 27 + .../WinNtThunk/Chipset/Metronome/Metronome.h | 84 + .../Chipset/Metronome/Metronome.mbd | 45 + .../Chipset/Metronome/Metronome.msa | 61 + .../WinNtThunk/Chipset/Metronome/build.xml | 47 + .../Chipset/RealTimeClock/RealTimeClock.c | 391 ++ .../Chipset/RealTimeClock/RealTimeClock.dxs | 27 + .../Chipset/RealTimeClock/RealTimeClock.mbd | 45 + .../Chipset/RealTimeClock/RealTimeClock.msa | 60 + .../Chipset/RealTimeClock/build.xml | 47 + .../Dxe/WinNtThunk/Chipset/Reset/Reset.dxs | 27 + .../Dxe/WinNtThunk/Chipset/Reset/Reset.mbd | 45 + .../Dxe/WinNtThunk/Chipset/Reset/Reset.msa | 60 + .../Dxe/WinNtThunk/Chipset/Reset/build.xml | 47 + .../Dxe/WinNtThunk/Chipset/Reset/reset.c | 121 + .../Dxe/WinNtThunk/Chipset/Timer/Timer.c | 597 ++ .../Dxe/WinNtThunk/Chipset/Timer/Timer.dxs | 28 + .../Dxe/WinNtThunk/Chipset/Timer/Timer.h | 162 + .../Dxe/WinNtThunk/Chipset/Timer/Timer.mbd | 46 + .../Dxe/WinNtThunk/Chipset/Timer/Timer.msa | 62 + .../Dxe/WinNtThunk/Chipset/Timer/build.xml | 47 + EdkNt32Pkg/Dxe/WinNtThunk/Cpu/Cpu.c | 736 +++ EdkNt32Pkg/Dxe/WinNtThunk/Cpu/Cpu.dxs | 28 + EdkNt32Pkg/Dxe/WinNtThunk/Cpu/Cpu.mbd | 46 + EdkNt32Pkg/Dxe/WinNtThunk/Cpu/Cpu.msa | 86 + EdkNt32Pkg/Dxe/WinNtThunk/Cpu/CpuDriver.h | 97 + EdkNt32Pkg/Dxe/WinNtThunk/Cpu/CpuIo.c | 335 + EdkNt32Pkg/Dxe/WinNtThunk/Cpu/Strings.uni | Bin 0 -> 2036 bytes EdkNt32Pkg/Dxe/WinNtThunk/Cpu/build.xml | 47 + .../Dxe/WinNtThunk/WinNtThunk/WinNtThunk.c | 87 + .../Dxe/WinNtThunk/WinNtThunk/WinNtThunk.dxs | 27 + .../Dxe/WinNtThunk/WinNtThunk/WinNtThunk.h | 30 + .../Dxe/WinNtThunk/WinNtThunk/WinNtThunk.mbd | 45 + .../Dxe/WinNtThunk/WinNtThunk/WinNtThunk.msa | 61 + .../Dxe/WinNtThunk/WinNtThunk/build.xml | 47 + EdkNt32Pkg/EdkNt32Pkg.spd | 383 ++ EdkNt32Pkg/Include/Common/WinNTInclude.h | 71 + EdkNt32Pkg/Include/FlashLayout.h | 64 + EdkNt32Pkg/Include/Ppi/NtAutoscan.h | 66 + EdkNt32Pkg/Include/Ppi/NtFwh.h | 62 + EdkNt32Pkg/Include/Ppi/NtPeiLoadFile.h | 65 + EdkNt32Pkg/Include/Ppi/NtThunk.h | 56 + EdkNt32Pkg/Include/Protocol/WinNtIo.h | 141 + EdkNt32Pkg/Include/Protocol/WinNtThunk.h | 1264 ++++ EdkNt32Pkg/Include/WinNtDxe.h | 38 + EdkNt32Pkg/Include/WinNtPeim.h | 36 + EdkNt32Pkg/Include/library/EdkGenericBdsLib.h | 332 + EdkNt32Pkg/Include/library/WinNtLib.h | 27 + .../Library/DxeWinNtLib/DxeWinNtLib.mbd | 30 + .../Library/DxeWinNtLib/DxeWinNtLib.msa | 55 + EdkNt32Pkg/Library/DxeWinNtLib/WinNtLib.c | 48 + EdkNt32Pkg/Library/DxeWinNtLib/build.xml | 47 + EdkNt32Pkg/Library/EdkGenericBdsLib/BdsBoot.c | 795 +++ .../Library/EdkGenericBdsLib/BdsConnect.c | 357 + .../Library/EdkGenericBdsLib/BdsConsole.c | 370 ++ EdkNt32Pkg/Library/EdkGenericBdsLib/BdsMisc.c | 764 +++ .../Library/EdkGenericBdsLib/DevicePath.c | 988 +++ .../EdkGenericBdsLib/EdkGenericBdsLib.mbd | 30 + .../EdkGenericBdsLib/EdkGenericBdsLib.msa | 78 + .../Library/EdkGenericBdsLib/Ipf/ShadowRom.c | 53 + .../Library/EdkGenericBdsLib/Performance.c | 426 ++ .../Library/EdkGenericBdsLib/Performance.h | 55 + EdkNt32Pkg/Library/EdkGenericBdsLib/build.xml | 47 + .../EdkNt32PeiPeCoffGetEntryPointLib.mbd | 30 + .../EdkNt32PeiPeCoffGetEntryPointLib.msa | 48 + .../PeCoffGetEntryPoint.c | 75 + .../build.xml | 47 + .../Nt32PeCoffLoaderLib/Nt32PeCoffLoader.c | 51 + .../Nt32PeCoffLoaderLib.mbd | 30 + .../Nt32PeCoffLoaderLib.msa | 53 + .../Library/Nt32PeCoffLoaderLib/build.xml | 47 + EdkNt32Pkg/Logo/Logo.mbd | 30 + EdkNt32Pkg/Logo/Logo.msa | 48 + EdkNt32Pkg/Logo/Logo_build.xml | 75 + EdkNt32Pkg/Logo/build.xml | 47 + EdkNt32Pkg/Logo/logo.bmp | Bin 0 -> 33126 bytes EdkNt32Pkg/Nt32.fpd | 683 ++ EdkNt32Pkg/Pei/Autoscan/WinNtAutoScan.mbd | 43 + EdkNt32Pkg/Pei/Autoscan/WinNtAutoScan.msa | 68 + EdkNt32Pkg/Pei/Autoscan/WinNtAutoscan.dxs | 29 + EdkNt32Pkg/Pei/Autoscan/WinntAutoscan.c | 132 + EdkNt32Pkg/Pei/Autoscan/build.xml | 47 + EdkNt32Pkg/Pei/BootMode/BootMode.c | 85 + EdkNt32Pkg/Pei/BootMode/BootMode.dxs | 29 + EdkNt32Pkg/Pei/BootMode/BootMode.mbd | 42 + EdkNt32Pkg/Pei/BootMode/BootMode.msa | 59 + EdkNt32Pkg/Pei/BootMode/build.xml | 47 + EdkNt32Pkg/Pei/FirmwareVolume/WinNtFwh.dxs | 29 + EdkNt32Pkg/Pei/FirmwareVolume/WinNtFwh.mbd | 43 + EdkNt32Pkg/Pei/FirmwareVolume/WinNtFwh.msa | 69 + EdkNt32Pkg/Pei/FirmwareVolume/WinntFwh.c | 123 + EdkNt32Pkg/Pei/FirmwareVolume/build.xml | 47 + EdkNt32Pkg/Pei/FlashMap/FlashMap.c | 273 + EdkNt32Pkg/Pei/FlashMap/FlashMap.dxs | 28 + EdkNt32Pkg/Pei/FlashMap/FlashMap.mbd | 43 + EdkNt32Pkg/Pei/FlashMap/FlashMap.msa | 101 + EdkNt32Pkg/Pei/FlashMap/build.xml | 47 + .../Pei/MonoStatusCode/MonoStatusCode.c | 150 + .../Pei/MonoStatusCode/MonoStatusCode.dxs | 28 + .../Pei/MonoStatusCode/MonoStatusCode.h | 111 + .../MonoStatusCode/Nt32/MonoStatusCode.mbd | 44 + .../MonoStatusCode/Nt32/MonoStatusCode.msa | 70 + .../MonoStatusCode/Nt32/PlatformStatusCode.c | 162 + EdkNt32Pkg/Pei/MonoStatusCode/Nt32/build.xml | 47 + EdkNt32Pkg/Pei/PcdEmulator/PcdEmulator.c | 657 ++ EdkNt32Pkg/Pei/PcdEmulator/PcdEmulator.dxs | 25 + EdkNt32Pkg/Pei/PcdEmulator/PcdEmulator.h | 53 + EdkNt32Pkg/Pei/PcdEmulator/PcdEmulator.mbd | 41 + EdkNt32Pkg/Pei/PcdEmulator/PcdEmulator.msa | 72 + EdkNt32Pkg/Pei/PcdEmulator/build.xml | 47 + EdkNt32Pkg/Pei/WinNtStuff/WinNtStuff.dxs | 29 + EdkNt32Pkg/Pei/WinNtStuff/WinNtStuff.mbd | 43 + EdkNt32Pkg/Pei/WinNtStuff/WinNtStuff.msa | 68 + EdkNt32Pkg/Pei/WinNtStuff/build.xml | 47 + EdkNt32Pkg/Pei/WinNtStuff/winntstuff.c | 73 + .../FvbServices/Common/FWBlockService.c | 1939 ++++++ .../FvbServices/Common/FwBlockService.h | 324 + .../FvbServices/Common/ia32/Ia32Fwh.c | 42 + EdkNt32Pkg/RuntimeDxe/FvbServices/Nt32Fwh.dxs | 27 + EdkNt32Pkg/RuntimeDxe/FvbServices/Nt32Fwh.mbd | 47 + EdkNt32Pkg/RuntimeDxe/FvbServices/Nt32Fwh.msa | 89 + EdkNt32Pkg/RuntimeDxe/FvbServices/build.xml | 47 + .../FvbServices/nt32/FWBlockService.c | 1493 +++++ .../RuntimeDxe/FvbServices/nt32/FvbInfo.c | 125 + .../FvbServices/nt32/FwBlockService.h | 238 + EdkNt32Pkg/Sec/FwVol.c | 314 + EdkNt32Pkg/Sec/SecMain.c | 1163 ++++ EdkNt32Pkg/Sec/SecMain.h | 570 ++ EdkNt32Pkg/Sec/SecMain.mbd | 38 + EdkNt32Pkg/Sec/SecMain.msa | 96 + EdkNt32Pkg/Sec/SecMain_build.xml | 154 + EdkNt32Pkg/Sec/WinNtThunk.c | 178 + EdkNt32Pkg/Sec/build.xml | 47 + EdkNt32Pkg/build.xml | 105 + EdkNt32Pkg/genbuildfile.xml | 19 + EdkNt32Pkg/run.cmd | 18 + EdkShellBinPkg/EdkShellBinPkg.spd | 40 + EdkShellBinPkg/bin/Shell.mbd | 33 + EdkShellBinPkg/bin/Shell.msa | 47 + EdkShellBinPkg/bin/build.xml | 47 + EdkShellBinPkg/bin/ia32/Apps/Attrib.efi | Bin 0 -> 45056 bytes EdkShellBinPkg/bin/ia32/Apps/Cls.efi | Bin 0 -> 36864 bytes EdkShellBinPkg/bin/ia32/Apps/Cp.efi | Bin 0 -> 69632 bytes EdkShellBinPkg/bin/ia32/Apps/Date.efi | Bin 0 -> 36864 bytes EdkShellBinPkg/bin/ia32/Apps/Dblk.efi | Bin 0 -> 65536 bytes EdkShellBinPkg/bin/ia32/Apps/Devices.efi | Bin 0 -> 40960 bytes EdkShellBinPkg/bin/ia32/Apps/Devtree.efi | Bin 0 -> 40960 bytes EdkShellBinPkg/bin/ia32/Apps/Drivers.efi | Bin 0 -> 49152 bytes EdkShellBinPkg/bin/ia32/Apps/Drvcfg.efi | Bin 0 -> 65536 bytes EdkShellBinPkg/bin/ia32/Apps/Drvdiag.efi | Bin 0 -> 53248 bytes EdkShellBinPkg/bin/ia32/Apps/Guid.efi | Bin 0 -> 36864 bytes EdkShellBinPkg/bin/ia32/Apps/IpConfig.efi | Bin 0 -> 34592 bytes EdkShellBinPkg/bin/ia32/Apps/Load.efi | Bin 0 -> 40960 bytes EdkShellBinPkg/bin/ia32/Apps/LoadPciRom.efi | Bin 0 -> 36864 bytes EdkShellBinPkg/bin/ia32/Apps/Ls.efi | Bin 0 -> 45056 bytes EdkShellBinPkg/bin/ia32/Apps/Mkdir.efi | Bin 0 -> 36864 bytes EdkShellBinPkg/bin/ia32/Apps/Mount.efi | Bin 0 -> 40960 bytes EdkShellBinPkg/bin/ia32/Apps/Mv.efi | Bin 0 -> 45056 bytes EdkShellBinPkg/bin/ia32/Apps/NShell.efi | Bin 0 -> 45056 bytes EdkShellBinPkg/bin/ia32/Apps/Openinfo.efi | Bin 0 -> 40960 bytes EdkShellBinPkg/bin/ia32/Apps/Resets.efi | Bin 0 -> 32768 bytes EdkShellBinPkg/bin/ia32/Apps/Rm.efi | Bin 0 -> 40960 bytes EdkShellBinPkg/bin/ia32/Apps/SmbiosView.efi | Bin 0 -> 158208 bytes EdkShellBinPkg/bin/ia32/Apps/TelnetMgmt.efi | Bin 0 -> 25216 bytes EdkShellBinPkg/bin/ia32/Apps/Time.efi | Bin 0 -> 32768 bytes EdkShellBinPkg/bin/ia32/Apps/Touch.efi | Bin 0 -> 40960 bytes EdkShellBinPkg/bin/ia32/Apps/Type.efi | Bin 0 -> 40960 bytes EdkShellBinPkg/bin/ia32/Apps/Unload.efi | Bin 0 -> 49152 bytes EdkShellBinPkg/bin/ia32/Apps/Ver.efi | Bin 0 -> 36864 bytes EdkShellBinPkg/bin/ia32/Apps/Vol.efi | Bin 0 -> 40960 bytes EdkShellBinPkg/bin/ia32/Apps/comp.efi | Bin 0 -> 45056 bytes EdkShellBinPkg/bin/ia32/Apps/dmem.efi | Bin 0 -> 65536 bytes EdkShellBinPkg/bin/ia32/Apps/dmpstore.efi | Bin 0 -> 40960 bytes EdkShellBinPkg/bin/ia32/Apps/edit.efi | Bin 0 -> 69632 bytes EdkShellBinPkg/bin/ia32/Apps/eficompress.efi | Bin 0 -> 47808 bytes .../bin/ia32/Apps/efidecompress.efi | Bin 0 -> 29536 bytes EdkShellBinPkg/bin/ia32/Apps/err.efi | Bin 0 -> 53248 bytes EdkShellBinPkg/bin/ia32/Apps/hexedit.efi | Bin 0 -> 73344 bytes EdkShellBinPkg/bin/ia32/Apps/legacyboot.efi | Bin 0 -> 25056 bytes EdkShellBinPkg/bin/ia32/Apps/loadfv.efi | Bin 0 -> 24928 bytes EdkShellBinPkg/bin/ia32/Apps/mem.efi | Bin 0 -> 65536 bytes EdkShellBinPkg/bin/ia32/Apps/memmap.efi | Bin 0 -> 36864 bytes EdkShellBinPkg/bin/ia32/Apps/mm.efi | Bin 0 -> 61440 bytes EdkShellBinPkg/bin/ia32/Apps/mode.efi | Bin 0 -> 32768 bytes EdkShellBinPkg/bin/ia32/Apps/pci.efi | Bin 0 -> 81920 bytes EdkShellBinPkg/bin/ia32/Apps/sermode.efi | Bin 0 -> 30912 bytes EdkShellBinPkg/bin/ia32/Apps/stall.efi | Bin 0 -> 32768 bytes EdkShellBinPkg/bin/ia32/Apps/timezone.efi | Bin 0 -> 33568 bytes EdkShellBinPkg/bin/ia32/Shell.efi | Bin 0 -> 557056 bytes EdkShellBinPkg/bin/ia32/Shell_Full.efi | Bin 0 -> 1118208 bytes EdkShellBinPkg/bin/ipf/Apps/Attrib.efi | Bin 0 -> 102528 bytes EdkShellBinPkg/bin/ipf/Apps/Cls.efi | Bin 0 -> 92736 bytes EdkShellBinPkg/bin/ipf/Apps/Cp.efi | Bin 0 -> 174272 bytes EdkShellBinPkg/bin/ipf/Apps/Date.efi | Bin 0 -> 95584 bytes EdkShellBinPkg/bin/ipf/Apps/Dblk.efi | Bin 0 -> 137024 bytes EdkShellBinPkg/bin/ipf/Apps/Devices.efi | Bin 0 -> 113664 bytes EdkShellBinPkg/bin/ipf/Apps/Devtree.efi | Bin 0 -> 117920 bytes EdkShellBinPkg/bin/ipf/Apps/Drivers.efi | Bin 0 -> 122848 bytes EdkShellBinPkg/bin/ipf/Apps/Drvcfg.efi | Bin 0 -> 157280 bytes EdkShellBinPkg/bin/ipf/Apps/Drvdiag.efi | Bin 0 -> 129568 bytes EdkShellBinPkg/bin/ipf/Apps/Guid.efi | Bin 0 -> 93280 bytes EdkShellBinPkg/bin/ipf/Apps/IpConfig.efi | Bin 0 -> 113760 bytes EdkShellBinPkg/bin/ipf/Apps/Load.efi | Bin 0 -> 112736 bytes EdkShellBinPkg/bin/ipf/Apps/LoadPciRom.efi | Bin 0 -> 111904 bytes EdkShellBinPkg/bin/ipf/Apps/Ls.efi | Bin 0 -> 114848 bytes EdkShellBinPkg/bin/ipf/Apps/Mkdir.efi | Bin 0 -> 91776 bytes EdkShellBinPkg/bin/ipf/Apps/Mount.efi | Bin 0 -> 96800 bytes EdkShellBinPkg/bin/ipf/Apps/Mv.efi | Bin 0 -> 119200 bytes EdkShellBinPkg/bin/ipf/Apps/NShell.efi | Bin 0 -> 142752 bytes EdkShellBinPkg/bin/ipf/Apps/Openinfo.efi | Bin 0 -> 104032 bytes EdkShellBinPkg/bin/ipf/Apps/Resets.efi | Bin 0 -> 88160 bytes EdkShellBinPkg/bin/ipf/Apps/Rm.efi | Bin 0 -> 114848 bytes EdkShellBinPkg/bin/ipf/Apps/SmbiosView.efi | Bin 0 -> 386752 bytes EdkShellBinPkg/bin/ipf/Apps/TelnetMgmt.efi | Bin 0 -> 93632 bytes EdkShellBinPkg/bin/ipf/Apps/Time.efi | Bin 0 -> 91744 bytes EdkShellBinPkg/bin/ipf/Apps/Touch.efi | Bin 0 -> 99520 bytes EdkShellBinPkg/bin/ipf/Apps/Type.efi | Bin 0 -> 98272 bytes EdkShellBinPkg/bin/ipf/Apps/Unload.efi | Bin 0 -> 143648 bytes EdkShellBinPkg/bin/ipf/Apps/Ver.efi | Bin 0 -> 95520 bytes EdkShellBinPkg/bin/ipf/Apps/Vol.efi | Bin 0 -> 103680 bytes EdkShellBinPkg/bin/ipf/Apps/comp.efi | Bin 0 -> 107456 bytes EdkShellBinPkg/bin/ipf/Apps/dmem.efi | Bin 0 -> 143808 bytes EdkShellBinPkg/bin/ipf/Apps/dmpstore.efi | Bin 0 -> 99776 bytes EdkShellBinPkg/bin/ipf/Apps/edit.efi | Bin 0 -> 221728 bytes EdkShellBinPkg/bin/ipf/Apps/eficompress.efi | Bin 0 -> 146944 bytes EdkShellBinPkg/bin/ipf/Apps/efidecompress.efi | Bin 0 -> 103168 bytes EdkShellBinPkg/bin/ipf/Apps/err.efi | Bin 0 -> 128704 bytes EdkShellBinPkg/bin/ipf/Apps/hexedit.efi | Bin 0 -> 264768 bytes EdkShellBinPkg/bin/ipf/Apps/mem.efi | Bin 0 -> 138880 bytes EdkShellBinPkg/bin/ipf/Apps/memmap.efi | Bin 0 -> 92544 bytes EdkShellBinPkg/bin/ipf/Apps/mm.efi | Bin 0 -> 135968 bytes EdkShellBinPkg/bin/ipf/Apps/mode.efi | Bin 0 -> 92256 bytes EdkShellBinPkg/bin/ipf/Apps/pci.efi | Bin 0 -> 169952 bytes EdkShellBinPkg/bin/ipf/Apps/sermode.efi | Bin 0 -> 107008 bytes EdkShellBinPkg/bin/ipf/Apps/stall.efi | Bin 0 -> 93184 bytes EdkShellBinPkg/bin/ipf/Apps/timezone.efi | Bin 0 -> 106688 bytes EdkShellBinPkg/bin/ipf/Shell.efi | Bin 0 -> 1118208 bytes EdkShellBinPkg/bin/ipf/Shell_Full.efi | Bin 0 -> 2393408 bytes EdkShellBinPkg/genbuildfile.xml | 18 + MdePkg/Include/Base.h | 28 + MdePkg/Include/Common/BaseTypes.h | 206 + MdePkg/Include/Common/BootMode.h | 37 + MdePkg/Include/Common/BootScript.h | 198 + MdePkg/Include/Common/Capsule.h | 67 + MdePkg/Include/Common/DataHubRecords.h | 1847 ++++++ MdePkg/Include/Common/Dependency.h | 50 + MdePkg/Include/Common/EfiImage.h | 698 ++ MdePkg/Include/Common/FirmwareFileSystem.h | 98 + MdePkg/Include/Common/FirmwareVolumeHeader.h | 109 + .../Common/FirmwareVolumeImageFormat.h | 277 + MdePkg/Include/Common/Hob.h | 235 + .../Common/InternalFormRepresentation.h | 422 ++ MdePkg/Include/Common/Legacy16.h | 310 + MdePkg/Include/Common/MultiPhase.h | 84 + MdePkg/Include/Common/Pcd.h | 33 + MdePkg/Include/Common/PcdTemp.h | 91 + MdePkg/Include/Common/StatusCode.h | 912 +++ MdePkg/Include/Common/StatusCodeDataTypeId.h | 336 + MdePkg/Include/Common/UefiBaseTypes.h | 85 + MdePkg/Include/Dxe.h | 51 + MdePkg/Include/Dxe/ArchProtocol/Bds.h | 87 + MdePkg/Include/Dxe/ArchProtocol/Cpu.h | 326 + MdePkg/Include/Dxe/ArchProtocol/Metronome.h | 100 + .../Dxe/ArchProtocol/MonotonicCounter.h | 33 + .../Include/Dxe/ArchProtocol/RealTimeClock.h | 41 + MdePkg/Include/Dxe/ArchProtocol/Reset.h | 38 + MdePkg/Include/Dxe/ArchProtocol/Runtime.h | 162 + MdePkg/Include/Dxe/ArchProtocol/Security.h | 136 + .../Include/Dxe/ArchProtocol/SecurityPolicy.h | 31 + MdePkg/Include/Dxe/ArchProtocol/StatusCode.h | 82 + MdePkg/Include/Dxe/ArchProtocol/Timer.h | 222 + MdePkg/Include/Dxe/ArchProtocol/Variable.h | 39 + .../Include/Dxe/ArchProtocol/VariableWrite.h | 38 + .../Include/Dxe/ArchProtocol/WatchdogTimer.h | 172 + MdePkg/Include/Dxe/DxeCis.h | 589 ++ MdePkg/Include/Dxe/SmmCis.h | 526 ++ MdePkg/Include/DxeCore.h | 50 + MdePkg/Include/DxeDepex.h | 58 + MdePkg/Include/Ebc/ProcessorBind.h | 81 + MdePkg/Include/Guid/Acpi.h | 48 + MdePkg/Include/Guid/AcpiTableStorage.h | 30 + MdePkg/Include/Guid/Apriori.h | 32 + MdePkg/Include/Guid/Capsule.h | 43 + MdePkg/Include/Guid/DataHubRecords.h | 66 + MdePkg/Include/Guid/DebugImageInfoTable.h | 58 + MdePkg/Include/Guid/DxeServices.h | 30 + MdePkg/Include/Guid/EventGroup.h | 45 + MdePkg/Include/Guid/EventLegacyBios.h | 28 + MdePkg/Include/Guid/FirmwareFileSystem.h | 40 + MdePkg/Include/Guid/FrameworkDevicePath.h | 29 + MdePkg/Include/Guid/GlobalVariable.h | 31 + MdePkg/Include/Guid/Gpt.h | 45 + MdePkg/Include/Guid/HobList.h | 32 + MdePkg/Include/Guid/MemoryAllocationHob.h | 36 + MdePkg/Include/Guid/Mps.h | 37 + MdePkg/Include/Guid/PcAnsi.h | 48 + MdePkg/Include/Guid/SalSystemTable.h | 38 + MdePkg/Include/Guid/SmBios.h | 68 + MdePkg/Include/Guid/SmmCommunicate.h | 39 + MdePkg/Include/Guid/SmramMemoryReserve.h | 67 + MdePkg/Include/Guid/StatusCodeDataTypeId.h | 82 + MdePkg/Include/Ia32/ProcessorBind.h | 167 + MdePkg/Include/IndustryStandard/Acpi.h | 91 + MdePkg/Include/IndustryStandard/Usb.h | 282 + MdePkg/Include/IndustryStandard/pci22.h | 481 ++ MdePkg/Include/IndustryStandard/scsi.h | 282 + MdePkg/Include/Ipf/IpfDefines.h | 553 ++ MdePkg/Include/Ipf/IpfMacro.i | 64 + MdePkg/Include/Ipf/ProcessorBind.h | 202 + MdePkg/Include/Ipf/SalApi.h | 691 ++ MdePkg/Include/Library/BaseLib.h | 4861 ++++++++++++++ MdePkg/Include/Library/BaseMemoryLib.h | 395 ++ MdePkg/Include/Library/CacheMaintenanceLib.h | 72 + MdePkg/Include/Library/CpuLib.h | 20 + MdePkg/Include/Library/DebugLib.h | 439 ++ MdePkg/Include/Library/DevicePathLib.h | 197 + MdePkg/Include/Library/DxeCoreEntryPoint.h | 77 + MdePkg/Include/Library/DxeRuntimeDriverLib.h | 332 + MdePkg/Include/Library/DxeServicesTableLib.h | 26 + .../Include/Library/DxeSmmDriverEntryPoint.h | 140 + MdePkg/Include/Library/HiiLib.h | 44 + MdePkg/Include/Library/HobLib.h | 275 + MdePkg/Include/Library/IoLib.h | 2311 +++++++ MdePkg/Include/Library/MemoryAllocationLib.h | 547 ++ MdePkg/Include/Library/PcdLib.h | 690 ++ MdePkg/Include/Library/PciCf8Lib.h | 1052 +++ MdePkg/Include/Library/PciExpressLib.h | 1020 +++ MdePkg/Include/Library/PciLib.h | 1015 +++ MdePkg/Include/Library/PciSegmentLib.h | 924 +++ .../Include/Library/PeCoffGetEntryPointLib.h | 39 + MdePkg/Include/Library/PeCoffLib.h | 131 + MdePkg/Include/Library/PeiCoreEntryPoint.h | 50 + MdePkg/Include/Library/PeiCoreLib.h | 306 + .../Library/PeiServicesTablePointerLib.h | 26 + MdePkg/Include/Library/PeimEntryPoint.h | 103 + MdePkg/Include/Library/PerformanceLib.h | 201 + MdePkg/Include/Library/PrintLib.h | 116 + MdePkg/Include/Library/ReportStatusCodeLib.h | 763 +++ .../Include/Library/ResourcePublicationLib.h | 44 + MdePkg/Include/Library/SmbusLib.h | 474 ++ MdePkg/Include/Library/TimerLib.h | 100 + .../Library/UefiBootServicesTableLib.h | 27 + MdePkg/Include/Library/UefiDecompressLib.h | 37 + MdePkg/Include/Library/UefiDriverEntryPoint.h | 154 + MdePkg/Include/Library/UefiDriverModelLib.h | 48 + MdePkg/Include/Library/UefiLib.h | 486 ++ .../Library/UefiRuntimeServicesTableLib.h | 25 + MdePkg/Include/PeiCore.h | 48 + MdePkg/Include/Peim.h | 53 + MdePkg/Include/Peim/PeiCis.h | 670 ++ MdePkg/Include/PeimDepex.h | 54 + MdePkg/Include/PiwgDxe.h | 26 + MdePkg/Include/PiwgPeim.h | 25 + MdePkg/Include/Ppi/BlockIo.h | 161 + MdePkg/Include/Ppi/BootInRecoveryMode.h | 33 + MdePkg/Include/Ppi/BootScriptExecuter.h | 78 + MdePkg/Include/Ppi/CpuIo.h | 520 ++ MdePkg/Include/Ppi/DeviceRecoveryModule.h | 143 + MdePkg/Include/Ppi/DxeIpl.h | 70 + MdePkg/Include/Ppi/EndOfPeiPhase.h | 31 + MdePkg/Include/Ppi/FindFv.h | 76 + MdePkg/Include/Ppi/LoadFile.h | 78 + MdePkg/Include/Ppi/MasterBootMode.h | 34 + MdePkg/Include/Ppi/MemoryDiscovered.h | 34 + MdePkg/Include/Ppi/Pcd.h | 294 + MdePkg/Include/Ppi/PciCfg.h | 133 + MdePkg/Include/Ppi/ReadOnlyVariable.h | 136 + MdePkg/Include/Ppi/RecoveryModule.h | 67 + MdePkg/Include/Ppi/Reset.h | 35 + MdePkg/Include/Ppi/S3Resume.h | 65 + MdePkg/Include/Ppi/SecPlatformInformation.h | 86 + MdePkg/Include/Ppi/SectionExtraction.h | 118 + MdePkg/Include/Ppi/Security.h | 77 + MdePkg/Include/Ppi/Smbus.h | 258 + MdePkg/Include/Ppi/Stall.h | 73 + MdePkg/Include/Ppi/StatusCode.h | 42 + MdePkg/Include/Protocol/AcpiSupport.h | 173 + MdePkg/Include/Protocol/Arp.h | 259 + MdePkg/Include/Protocol/AuthenticationInfo.h | 125 + MdePkg/Include/Protocol/Bis.h | 418 ++ MdePkg/Include/Protocol/BlockIo.h | 173 + MdePkg/Include/Protocol/BootScriptSave.h | 110 + .../Protocol/BusSpecificDriverOverride.h | 66 + MdePkg/Include/Protocol/ComponentName.h | 123 + MdePkg/Include/Protocol/CpuIo.h | 131 + MdePkg/Include/Protocol/DataHub.h | 233 + MdePkg/Include/Protocol/DebugPort.h | 141 + MdePkg/Include/Protocol/DebugSupport.h | 517 ++ MdePkg/Include/Protocol/Decompress.h | 121 + MdePkg/Include/Protocol/DeviceIo.h | 222 + MdePkg/Include/Protocol/DevicePath.h | 94 + MdePkg/Include/Protocol/DevicePathFromText.h | 73 + MdePkg/Include/Protocol/DevicePathToText.h | 86 + MdePkg/Include/Protocol/DevicePathUtilities.h | 194 + MdePkg/Include/Protocol/Dhcp4.h | 442 ++ MdePkg/Include/Protocol/DiskIo.h | 98 + MdePkg/Include/Protocol/DriverBinding.h | 111 + MdePkg/Include/Protocol/DriverConfiguration.h | 203 + MdePkg/Include/Protocol/DriverDiagnostics.h | 134 + MdePkg/Include/Protocol/Ebc.h | 148 + MdePkg/Include/Protocol/EdidActive.h | 34 + MdePkg/Include/Protocol/EdidDiscovered.h | 35 + MdePkg/Include/Protocol/EdidOverride.h | 66 + .../Protocol/EfiNetworkInterfaceIdentifier.h | 92 + MdePkg/Include/Protocol/FileInfo.h | 53 + MdePkg/Include/Protocol/FileSystemInfo.h | 45 + .../Protocol/FileSystemVolumeLabelInfo.h | 42 + MdePkg/Include/Protocol/FirmwareVolume.h | 321 + MdePkg/Include/Protocol/FirmwareVolumeBlock.h | 251 + .../Include/Protocol/FirmwareVolumeDispatch.h | 33 + MdePkg/Include/Protocol/FormBrowser.h | 180 + MdePkg/Include/Protocol/FormCallback.h | 227 + MdePkg/Include/Protocol/GraphicsOutput.h | 194 + .../Protocol/GuidedSectionExtraction.h | 102 + MdePkg/Include/Protocol/Hash.h | 149 + MdePkg/Include/Protocol/Hii.h | 1024 +++ MdePkg/Include/Protocol/IP4.h | 411 ++ MdePkg/Include/Protocol/IP4Config.h | 121 + MdePkg/Include/Protocol/IScsiInitatorName.h | 92 + MdePkg/Include/Protocol/IdeControllerInit.h | 485 ++ .../Protocol/IncompatiblePciDeviceSupport.h | 84 + MdePkg/Include/Protocol/Legacy8259.h | 307 + MdePkg/Include/Protocol/LegacyBios.h | 701 ++ MdePkg/Include/Protocol/LegacyBiosPlatform.h | 307 + MdePkg/Include/Protocol/LegacyInterrupt.h | 131 + MdePkg/Include/Protocol/LegacyRegion.h | 152 + MdePkg/Include/Protocol/LoadFile.h | 83 + MdePkg/Include/Protocol/LoadedImage.h | 69 + MdePkg/Include/Protocol/ManagedNetwork.h | 314 + MdePkg/Include/Protocol/Mtftp4.h | 508 ++ MdePkg/Include/Protocol/Pcd.h | 293 + .../PciHostBridgeResourceAllocation.h | 363 ++ MdePkg/Include/Protocol/PciHotPlugInit.h | 185 + MdePkg/Include/Protocol/PciIo.h | 503 ++ MdePkg/Include/Protocol/PciPlatform.h | 207 + MdePkg/Include/Protocol/PciRootBridgeIo.h | 384 ++ .../Include/Protocol/PlatformDriverOverride.h | 135 + MdePkg/Include/Protocol/PxeBaseCode.h | 622 ++ MdePkg/Include/Protocol/PxeBaseCodeCallBack.h | 94 + MdePkg/Include/Protocol/ScsiIo.h | 233 + MdePkg/Include/Protocol/ScsiPassThru.h | 312 + MdePkg/Include/Protocol/ScsiPassThruExt.h | 332 + MdePkg/Include/Protocol/SectionExtraction.h | 162 + MdePkg/Include/Protocol/SerialIo.h | 266 + MdePkg/Include/Protocol/ServiceBinding.h | 74 + MdePkg/Include/Protocol/SimpleFileSystem.h | 328 + MdePkg/Include/Protocol/SimpleNetwork.h | 580 ++ MdePkg/Include/Protocol/SimplePointer.h | 97 + MdePkg/Include/Protocol/SimpleTextIn.h | 126 + MdePkg/Include/Protocol/SimpleTextOut.h | 390 ++ MdePkg/Include/Protocol/Smbus.h | 237 + MdePkg/Include/Protocol/SmmAccess.h | 172 + MdePkg/Include/Protocol/SmmBase.h | 310 + MdePkg/Include/Protocol/SmmControl.h | 139 + MdePkg/Include/Protocol/SmmGpiDispatch.h | 150 + MdePkg/Include/Protocol/SmmIchnDispatch.h | 193 + .../Protocol/SmmPeriodicTimerDispatch.h | 194 + .../Include/Protocol/SmmPowerButtonDispatch.h | 147 + .../Protocol/SmmStandbyButtonDispatch.h | 147 + MdePkg/Include/Protocol/SmmStatusCode.h | 86 + MdePkg/Include/Protocol/SmmSwDispatch.h | 149 + MdePkg/Include/Protocol/SmmSxDispatch.h | 160 + MdePkg/Include/Protocol/SmmUsbDispatch.h | 141 + MdePkg/Include/Protocol/TapeIo.h | 236 + MdePkg/Include/Protocol/Tcp4.h | 507 ++ MdePkg/Include/Protocol/Udp4.h | 363 ++ MdePkg/Include/Protocol/UgaDraw.h | 168 + MdePkg/Include/Protocol/UnicodeCollation.h | 183 + MdePkg/Include/Protocol/Usb2HostController.h | 497 ++ MdePkg/Include/Protocol/UsbHostController.h | 446 ++ MdePkg/Include/Protocol/UsbIo.h | 418 ++ MdePkg/Include/ToBeRemoved/Variable.h | 78 + .../Include/ToBeRemoved/WorkingBlockHeader.h | 47 + MdePkg/Include/Uefi.h | 66 + MdePkg/Include/Uefi/EfiPxe.h | 1780 +++++ MdePkg/Include/Uefi/Errors.h | 24 + MdePkg/Include/Uefi/UefiSpec.h | 2460 +++++++ MdePkg/Include/x64/ProcessorBind.h | 193 + .../BaseCacheMaintenanceLib.mbd | 30 + .../BaseCacheMaintenanceLib.msa | 57 + .../BaseCacheMaintenanceLib/EbcCache.c | 85 + .../BaseCacheMaintenanceLib/Ipf/CallPalProc.s | 38 + .../Library/BaseCacheMaintenanceLib/Ipf/Cpu.s | 106 + .../BaseCacheMaintenanceLib/IpfCache.c | 95 + .../Library/BaseCacheMaintenanceLib/build.xml | 47 + .../BaseCacheMaintenanceLib/x86Cache.c | 95 + .../BaseDebugLibNull/BaseDebugLibNull.mbd | 30 + .../BaseDebugLibNull/BaseDebugLibNull.msa | 64 + MdePkg/Library/BaseDebugLibNull/DebugLib.c | 225 + MdePkg/Library/BaseDebugLibNull/build.xml | 47 + .../BaseDebugLibReportStatusCode.mbd | 30 + .../BaseDebugLibReportStatusCode.msa | 64 + .../BaseDebugLibReportStatusCode/DebugLib.c | 283 + .../BaseDebugLibReportStatusCode/build.xml | 47 + .../BaseIoLibIntrinsic/BaseIoLibIntrinsic.mbd | 33 + .../BaseIoLibIntrinsic/BaseIoLibIntrinsic.msa | 56 + .../Library/BaseIoLibIntrinsic/IoHighLevel.c | 2272 +++++++ MdePkg/Library/BaseIoLibIntrinsic/IoLib.c | 255 + MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c | 194 + MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c | 193 + MdePkg/Library/BaseIoLibIntrinsic/build.xml | 47 + MdePkg/Library/BaseLib/ARShiftU64.c | 41 + MdePkg/Library/BaseLib/BaseLib.mbd | 30 + MdePkg/Library/BaseLib/BaseLib.msa | 309 + MdePkg/Library/BaseLib/BaseLibInternals.h | 195 + MdePkg/Library/BaseLib/BitField.c | 812 +++ MdePkg/Library/BaseLib/Cpu.c | 67 + MdePkg/Library/BaseLib/CpuDeadLoop.c | 33 + MdePkg/Library/BaseLib/DivS64x64Remainder.c | 46 + MdePkg/Library/BaseLib/DivU64x32.c | 42 + MdePkg/Library/BaseLib/DivU64x32Remainder.c | 46 + MdePkg/Library/BaseLib/DivU64x64Remainder.c | 46 + MdePkg/Library/BaseLib/Ebc/CpuBreakpoint.c | 100 + MdePkg/Library/BaseLib/GetPowerOfTwo32.c | 39 + MdePkg/Library/BaseLib/GetPowerOfTwo64.c | 39 + MdePkg/Library/BaseLib/HighBitSet32.c | 41 + MdePkg/Library/BaseLib/HighBitSet64.c | 43 + MdePkg/Library/BaseLib/Ipf/CpuBreakpoint.c | 101 + .../Ipf/InterlockedCompareExchange32.s | 29 + .../Ipf/InterlockedCompareExchange64.s | 28 + MdePkg/Library/BaseLib/Ipf/SwitchStack.s | 122 + MdePkg/Library/BaseLib/Ipf/Synchronization.c | 59 + MdePkg/Library/BaseLib/Ipf/Unaligned.c | 220 + MdePkg/Library/BaseLib/Ipf/asm.h | 27 + MdePkg/Library/BaseLib/Ipf/ia_64gen.h | 205 + MdePkg/Library/BaseLib/Ipf/setjmp.s | 317 + MdePkg/Library/BaseLib/LRotU32.c | 42 + MdePkg/Library/BaseLib/LRotU64.c | 42 + MdePkg/Library/BaseLib/LShiftU64.c | 41 + MdePkg/Library/BaseLib/LinkedList.c | 433 ++ MdePkg/Library/BaseLib/LowBitSet32.c | 44 + MdePkg/Library/BaseLib/LowBitSet64.c | 46 + MdePkg/Library/BaseLib/Math64.c | 174 + MdePkg/Library/BaseLib/ModU64x32.c | 42 + MdePkg/Library/BaseLib/MultS64x64.c | 41 + MdePkg/Library/BaseLib/MultU64x32.c | 45 + MdePkg/Library/BaseLib/MultU64x64.c | 45 + MdePkg/Library/BaseLib/RRotU32.c | 42 + MdePkg/Library/BaseLib/RRotU64.c | 42 + MdePkg/Library/BaseLib/RShiftU64.c | 41 + MdePkg/Library/BaseLib/SetJumpLongJump.c | 40 + MdePkg/Library/BaseLib/String.c | 798 +++ MdePkg/Library/BaseLib/SwapBytes16.c | 36 + MdePkg/Library/BaseLib/SwapBytes32.c | 39 + MdePkg/Library/BaseLib/SwapBytes64.c | 36 + MdePkg/Library/BaseLib/SwitchStack.c | 52 + MdePkg/Library/BaseLib/Synchronization.c | 353 + MdePkg/Library/BaseLib/Unaligned.c | 203 + MdePkg/Library/BaseLib/build.xml | 47 + MdePkg/Library/BaseLib/ia32/ARShiftU64.asm | 38 + MdePkg/Library/BaseLib/ia32/ARShiftU64.s | 41 + MdePkg/Library/BaseLib/ia32/CpuBreakpoint.asm | 40 + MdePkg/Library/BaseLib/ia32/CpuBreakpoint.s | 41 + MdePkg/Library/BaseLib/ia32/CpuFlushTlb.asm | 40 + MdePkg/Library/BaseLib/ia32/CpuFlushTlb.s | 41 + MdePkg/Library/BaseLib/ia32/CpuId.asm | 66 + MdePkg/Library/BaseLib/ia32/CpuId.s | 63 + MdePkg/Library/BaseLib/ia32/CpuPause.asm | 40 + MdePkg/Library/BaseLib/ia32/CpuPause.s | 41 + MdePkg/Library/BaseLib/ia32/CpuSleep.asm | 39 + MdePkg/Library/BaseLib/ia32/CpuSleep.s | 40 + .../BaseLib/ia32/DisableInterrupts.asm | 40 + .../Library/BaseLib/ia32/DisableInterrupts.s | 41 + .../Library/BaseLib/ia32/DisablePaging32.asm | 57 + MdePkg/Library/BaseLib/ia32/DisablePaging32.s | 58 + .../Library/BaseLib/ia32/DivS64x64Remainder.c | 38 + MdePkg/Library/BaseLib/ia32/DivU64x32.asm | 38 + MdePkg/Library/BaseLib/ia32/DivU64x32.s | 39 + .../BaseLib/ia32/DivU64x32Remainder.asm | 42 + .../Library/BaseLib/ia32/DivU64x32Remainder.s | 43 + .../BaseLib/ia32/DivU64x64Remainder.asm | 83 + .../Library/BaseLib/ia32/DivU64x64Remainder.s | 89 + .../BaseLib/ia32/EnableDisableInterrupts.asm | 41 + .../BaseLib/ia32/EnableDisableInterrupts.s | 42 + .../Library/BaseLib/ia32/EnableInterrupts.asm | 40 + .../Library/BaseLib/ia32/EnableInterrupts.s | 41 + .../Library/BaseLib/ia32/EnablePaging32.asm | 57 + MdePkg/Library/BaseLib/ia32/EnablePaging32.s | 58 + .../Library/BaseLib/ia32/EnablePaging64.asm | 57 + MdePkg/Library/BaseLib/ia32/EnablePaging64.s | 66 + .../Library/BaseLib/ia32/FlushCacheLine.asm | 42 + MdePkg/Library/BaseLib/ia32/FlushCacheLine.s | 43 + MdePkg/Library/BaseLib/ia32/FxRestore.asm | 42 + MdePkg/Library/BaseLib/ia32/FxRestore.s | 43 + MdePkg/Library/BaseLib/ia32/FxSave.asm | 42 + MdePkg/Library/BaseLib/ia32/FxSave.s | 43 + .../ia32/InterlockedCompareExchange32.asm | 45 + .../ia32/InterlockedCompareExchange32.s | 64 + .../ia32/InterlockedCompareExchange64.asm | 47 + .../ia32/InterlockedCompareExchange64.s | 52 + .../BaseLib/ia32/InterlockedDecrement.asm | 42 + .../BaseLib/ia32/InterlockedDecrement.s | 44 + .../BaseLib/ia32/InterlockedIncrement.asm | 42 + .../BaseLib/ia32/InterlockedIncrement.s | 44 + MdePkg/Library/BaseLib/ia32/Invd.asm | 40 + MdePkg/Library/BaseLib/ia32/Invd.s | 41 + MdePkg/Library/BaseLib/ia32/LRotU64.asm | 41 + MdePkg/Library/BaseLib/ia32/LRotU64.s | 43 + MdePkg/Library/BaseLib/ia32/LShiftU64.asm | 38 + MdePkg/Library/BaseLib/ia32/LShiftU64.s | 39 + MdePkg/Library/BaseLib/ia32/LongJump.asm | 38 + MdePkg/Library/BaseLib/ia32/LongJump.s | 39 + MdePkg/Library/BaseLib/ia32/ModU64x32.asm | 37 + MdePkg/Library/BaseLib/ia32/ModU64x32.s | 38 + MdePkg/Library/BaseLib/ia32/Monitor.asm | 45 + MdePkg/Library/BaseLib/ia32/Monitor.s | 46 + MdePkg/Library/BaseLib/ia32/MultU64x32.asm | 35 + MdePkg/Library/BaseLib/ia32/MultU64x32.s | 36 + MdePkg/Library/BaseLib/ia32/MultU64x64.asm | 39 + MdePkg/Library/BaseLib/ia32/MultU64x64.s | 49 + MdePkg/Library/BaseLib/ia32/Mwait.asm | 43 + MdePkg/Library/BaseLib/ia32/Mwait.s | 44 + MdePkg/Library/BaseLib/ia32/Non-existing.c | 30 + MdePkg/Library/BaseLib/ia32/RRotU64.asm | 41 + MdePkg/Library/BaseLib/ia32/RRotU64.s | 43 + MdePkg/Library/BaseLib/ia32/RShiftU64.asm | 38 + MdePkg/Library/BaseLib/ia32/RShiftU64.s | 39 + MdePkg/Library/BaseLib/ia32/ReadCr0.asm | 40 + MdePkg/Library/BaseLib/ia32/ReadCr0.s | 41 + MdePkg/Library/BaseLib/ia32/ReadCr2.asm | 40 + MdePkg/Library/BaseLib/ia32/ReadCr2.s | 41 + MdePkg/Library/BaseLib/ia32/ReadCr3.asm | 40 + MdePkg/Library/BaseLib/ia32/ReadCr3.s | 41 + MdePkg/Library/BaseLib/ia32/ReadCr4.asm | 40 + MdePkg/Library/BaseLib/ia32/ReadCr4.s | 41 + MdePkg/Library/BaseLib/ia32/ReadCs.asm | 40 + MdePkg/Library/BaseLib/ia32/ReadCs.s | 41 + MdePkg/Library/BaseLib/ia32/ReadDr0.asm | 40 + MdePkg/Library/BaseLib/ia32/ReadDr0.s | 40 + MdePkg/Library/BaseLib/ia32/ReadDr1.asm | 40 + MdePkg/Library/BaseLib/ia32/ReadDr1.s | 41 + MdePkg/Library/BaseLib/ia32/ReadDr2.asm | 40 + MdePkg/Library/BaseLib/ia32/ReadDr2.s | 41 + MdePkg/Library/BaseLib/ia32/ReadDr3.asm | 40 + MdePkg/Library/BaseLib/ia32/ReadDr3.s | 41 + MdePkg/Library/BaseLib/ia32/ReadDr4.asm | 40 + MdePkg/Library/BaseLib/ia32/ReadDr5.asm | 40 + MdePkg/Library/BaseLib/ia32/ReadDr6.asm | 40 + MdePkg/Library/BaseLib/ia32/ReadDr6.s | 41 + MdePkg/Library/BaseLib/ia32/ReadDr7.asm | 40 + MdePkg/Library/BaseLib/ia32/ReadDr7.s | 41 + MdePkg/Library/BaseLib/ia32/ReadDs.asm | 40 + MdePkg/Library/BaseLib/ia32/ReadDs.s | 41 + MdePkg/Library/BaseLib/ia32/ReadEflags.asm | 41 + MdePkg/Library/BaseLib/ia32/ReadEflags.s | 42 + MdePkg/Library/BaseLib/ia32/ReadEs.asm | 40 + MdePkg/Library/BaseLib/ia32/ReadEs.s | 41 + MdePkg/Library/BaseLib/ia32/ReadFs.asm | 40 + MdePkg/Library/BaseLib/ia32/ReadFs.s | 41 + MdePkg/Library/BaseLib/ia32/ReadGdtr.asm | 41 + MdePkg/Library/BaseLib/ia32/ReadGdtr.s | 42 + MdePkg/Library/BaseLib/ia32/ReadGs.asm | 40 + MdePkg/Library/BaseLib/ia32/ReadGs.s | 41 + MdePkg/Library/BaseLib/ia32/ReadIdtr.asm | 34 + MdePkg/Library/BaseLib/ia32/ReadIdtr.s | 42 + MdePkg/Library/BaseLib/ia32/ReadLdtr.asm | 40 + MdePkg/Library/BaseLib/ia32/ReadLdtr.s | 41 + MdePkg/Library/BaseLib/ia32/ReadMm0.asm | 45 + MdePkg/Library/BaseLib/ia32/ReadMm0.s | 46 + MdePkg/Library/BaseLib/ia32/ReadMm1.asm | 45 + MdePkg/Library/BaseLib/ia32/ReadMm1.s | 46 + MdePkg/Library/BaseLib/ia32/ReadMm2.asm | 45 + MdePkg/Library/BaseLib/ia32/ReadMm2.s | 46 + MdePkg/Library/BaseLib/ia32/ReadMm3.asm | 45 + MdePkg/Library/BaseLib/ia32/ReadMm3.s | 46 + MdePkg/Library/BaseLib/ia32/ReadMm4.asm | 45 + MdePkg/Library/BaseLib/ia32/ReadMm4.s | 46 + MdePkg/Library/BaseLib/ia32/ReadMm5.asm | 45 + MdePkg/Library/BaseLib/ia32/ReadMm5.s | 46 + MdePkg/Library/BaseLib/ia32/ReadMm6.asm | 45 + MdePkg/Library/BaseLib/ia32/ReadMm6.s | 46 + MdePkg/Library/BaseLib/ia32/ReadMm7.asm | 45 + MdePkg/Library/BaseLib/ia32/ReadMm7.s | 46 + MdePkg/Library/BaseLib/ia32/ReadMsr64.asm | 55 + MdePkg/Library/BaseLib/ia32/ReadMsr64.s | 57 + MdePkg/Library/BaseLib/ia32/ReadPmc.asm | 41 + MdePkg/Library/BaseLib/ia32/ReadPmc.s | 42 + MdePkg/Library/BaseLib/ia32/ReadSs.asm | 40 + MdePkg/Library/BaseLib/ia32/ReadSs.s | 41 + MdePkg/Library/BaseLib/ia32/ReadTr.asm | 40 + MdePkg/Library/BaseLib/ia32/ReadTr.s | 41 + MdePkg/Library/BaseLib/ia32/ReadTsc.asm | 40 + MdePkg/Library/BaseLib/ia32/ReadTsc.s | 41 + MdePkg/Library/BaseLib/ia32/SetJump.asm | 39 + MdePkg/Library/BaseLib/ia32/SetJump.s | 40 + MdePkg/Library/BaseLib/ia32/SwapBytes64.asm | 36 + MdePkg/Library/BaseLib/ia32/SwitchStack.c | 57 + MdePkg/Library/BaseLib/ia32/Thunk16.asm | 163 + MdePkg/Library/BaseLib/ia32/Thunk16.s | 191 + MdePkg/Library/BaseLib/ia32/Wbinvd.asm | 40 + MdePkg/Library/BaseLib/ia32/Wbinvd.s | 41 + MdePkg/Library/BaseLib/ia32/WriteCr0.asm | 41 + MdePkg/Library/BaseLib/ia32/WriteCr0.s | 42 + MdePkg/Library/BaseLib/ia32/WriteCr2.asm | 41 + MdePkg/Library/BaseLib/ia32/WriteCr2.s | 42 + MdePkg/Library/BaseLib/ia32/WriteCr3.asm | 41 + MdePkg/Library/BaseLib/ia32/WriteCr3.s | 42 + MdePkg/Library/BaseLib/ia32/WriteCr4.asm | 41 + MdePkg/Library/BaseLib/ia32/WriteCr4.s | 42 + MdePkg/Library/BaseLib/ia32/WriteDr0.asm | 41 + MdePkg/Library/BaseLib/ia32/WriteDr0.s | 42 + MdePkg/Library/BaseLib/ia32/WriteDr1.asm | 41 + MdePkg/Library/BaseLib/ia32/WriteDr1.s | 42 + MdePkg/Library/BaseLib/ia32/WriteDr2.asm | 41 + MdePkg/Library/BaseLib/ia32/WriteDr2.s | 42 + MdePkg/Library/BaseLib/ia32/WriteDr3.asm | 41 + MdePkg/Library/BaseLib/ia32/WriteDr3.s | 42 + MdePkg/Library/BaseLib/ia32/WriteDr4.asm | 41 + MdePkg/Library/BaseLib/ia32/WriteDr5.asm | 41 + MdePkg/Library/BaseLib/ia32/WriteDr6.asm | 41 + MdePkg/Library/BaseLib/ia32/WriteDr6.s | 42 + MdePkg/Library/BaseLib/ia32/WriteDr7.asm | 41 + MdePkg/Library/BaseLib/ia32/WriteDr7.s | 42 + MdePkg/Library/BaseLib/ia32/WriteGdtr.asm | 34 + MdePkg/Library/BaseLib/ia32/WriteGdtr.s | 42 + MdePkg/Library/BaseLib/ia32/WriteIdtr.asm | 34 + MdePkg/Library/BaseLib/ia32/WriteIdtr.s | 42 + MdePkg/Library/BaseLib/ia32/WriteLdtr.asm | 41 + MdePkg/Library/BaseLib/ia32/WriteLdtr.s | 42 + MdePkg/Library/BaseLib/ia32/WriteMm0.asm | 41 + MdePkg/Library/BaseLib/ia32/WriteMm0.s | 42 + MdePkg/Library/BaseLib/ia32/WriteMm1.asm | 41 + MdePkg/Library/BaseLib/ia32/WriteMm1.s | 42 + MdePkg/Library/BaseLib/ia32/WriteMm2.asm | 41 + MdePkg/Library/BaseLib/ia32/WriteMm2.s | 42 + MdePkg/Library/BaseLib/ia32/WriteMm3.asm | 41 + MdePkg/Library/BaseLib/ia32/WriteMm3.s | 42 + MdePkg/Library/BaseLib/ia32/WriteMm4.asm | 41 + MdePkg/Library/BaseLib/ia32/WriteMm4.s | 42 + MdePkg/Library/BaseLib/ia32/WriteMm5.asm | 41 + MdePkg/Library/BaseLib/ia32/WriteMm5.s | 42 + MdePkg/Library/BaseLib/ia32/WriteMm6.asm | 41 + MdePkg/Library/BaseLib/ia32/WriteMm6.s | 42 + MdePkg/Library/BaseLib/ia32/WriteMm7.asm | 41 + MdePkg/Library/BaseLib/ia32/WriteMm7.s | 42 + MdePkg/Library/BaseLib/ia32/WriteMsr32.asm | 44 + MdePkg/Library/BaseLib/ia32/WriteMsr32.s | 45 + MdePkg/Library/BaseLib/ia32/WriteMsr64.asm | 44 + MdePkg/Library/BaseLib/ia32/WriteMsr64.s | 45 + MdePkg/Library/BaseLib/x64/CpuBreakpoint.asm | 37 + MdePkg/Library/BaseLib/x64/CpuFlushTlb.asm | 38 + MdePkg/Library/BaseLib/x64/CpuId.asm | 62 + MdePkg/Library/BaseLib/x64/CpuPause.asm | 37 + MdePkg/Library/BaseLib/x64/CpuSleep.asm | 37 + .../Library/BaseLib/x64/DisableInterrupts.asm | 38 + .../Library/BaseLib/x64/DisablePaging64.asm | 54 + .../BaseLib/x64/EnableDisableInterrupts.asm | 39 + .../Library/BaseLib/x64/EnableInterrupts.asm | 38 + MdePkg/Library/BaseLib/x64/FlushCacheLine.asm | 38 + MdePkg/Library/BaseLib/x64/FxRestore.asm | 31 + MdePkg/Library/BaseLib/x64/FxSave.asm | 31 + .../x64/InterlockedCompareExchange32.asm | 41 + .../x64/InterlockedCompareExchange64.asm | 41 + .../BaseLib/x64/InterlockedDecrement.asm | 39 + .../BaseLib/x64/InterlockedIncrement.asm | 39 + MdePkg/Library/BaseLib/x64/Invd.asm | 38 + MdePkg/Library/BaseLib/x64/LongJump.asm | 38 + MdePkg/Library/BaseLib/x64/Monitor.asm | 43 + MdePkg/Library/BaseLib/x64/Mwait.asm | 41 + MdePkg/Library/BaseLib/x64/Non-existing.c | 54 + MdePkg/Library/BaseLib/x64/ReadCr0.asm | 38 + MdePkg/Library/BaseLib/x64/ReadCr2.asm | 38 + MdePkg/Library/BaseLib/x64/ReadCr3.asm | 38 + MdePkg/Library/BaseLib/x64/ReadCr4.asm | 38 + MdePkg/Library/BaseLib/x64/ReadCs.asm | 38 + MdePkg/Library/BaseLib/x64/ReadDr0.asm | 38 + MdePkg/Library/BaseLib/x64/ReadDr1.asm | 38 + MdePkg/Library/BaseLib/x64/ReadDr2.asm | 38 + MdePkg/Library/BaseLib/x64/ReadDr3.asm | 38 + MdePkg/Library/BaseLib/x64/ReadDr4.asm | 38 + MdePkg/Library/BaseLib/x64/ReadDr5.asm | 38 + MdePkg/Library/BaseLib/x64/ReadDr6.asm | 38 + MdePkg/Library/BaseLib/x64/ReadDr7.asm | 38 + MdePkg/Library/BaseLib/x64/ReadDs.asm | 39 + MdePkg/Library/BaseLib/x64/ReadEflags.asm | 39 + MdePkg/Library/BaseLib/x64/ReadEs.asm | 38 + MdePkg/Library/BaseLib/x64/ReadFs.asm | 38 + MdePkg/Library/BaseLib/x64/ReadGdtr.asm | 31 + MdePkg/Library/BaseLib/x64/ReadGs.asm | 38 + MdePkg/Library/BaseLib/x64/ReadIdtr.asm | 31 + MdePkg/Library/BaseLib/x64/ReadLdtr.asm | 38 + MdePkg/Library/BaseLib/x64/ReadMm0.asm | 38 + MdePkg/Library/BaseLib/x64/ReadMm1.asm | 38 + MdePkg/Library/BaseLib/x64/ReadMm2.asm | 38 + MdePkg/Library/BaseLib/x64/ReadMm3.asm | 38 + MdePkg/Library/BaseLib/x64/ReadMm4.asm | 38 + MdePkg/Library/BaseLib/x64/ReadMm5.asm | 38 + MdePkg/Library/BaseLib/x64/ReadMm6.asm | 38 + MdePkg/Library/BaseLib/x64/ReadMm7.asm | 38 + MdePkg/Library/BaseLib/x64/ReadMsr32.asm | 38 + MdePkg/Library/BaseLib/x64/ReadMsr64.asm | 40 + MdePkg/Library/BaseLib/x64/ReadPmc.asm | 43 + MdePkg/Library/BaseLib/x64/ReadSs.asm | 38 + MdePkg/Library/BaseLib/x64/ReadTr.asm | 38 + MdePkg/Library/BaseLib/x64/ReadTsc.asm | 40 + MdePkg/Library/BaseLib/x64/SetJump.asm | 40 + MdePkg/Library/BaseLib/x64/SwitchStack.asm | 47 + MdePkg/Library/BaseLib/x64/Thunk16.asm | 189 + MdePkg/Library/BaseLib/x64/Wbinvd.asm | 38 + MdePkg/Library/BaseLib/x64/WriteCr0.asm | 38 + MdePkg/Library/BaseLib/x64/WriteCr2.asm | 38 + MdePkg/Library/BaseLib/x64/WriteCr3.asm | 38 + MdePkg/Library/BaseLib/x64/WriteCr4.asm | 38 + MdePkg/Library/BaseLib/x64/WriteDr0.asm | 38 + MdePkg/Library/BaseLib/x64/WriteDr1.asm | 38 + MdePkg/Library/BaseLib/x64/WriteDr2.asm | 38 + MdePkg/Library/BaseLib/x64/WriteDr3.asm | 38 + MdePkg/Library/BaseLib/x64/WriteDr4.asm | 38 + MdePkg/Library/BaseLib/x64/WriteDr5.asm | 38 + MdePkg/Library/BaseLib/x64/WriteDr6.asm | 38 + MdePkg/Library/BaseLib/x64/WriteDr7.asm | 38 + MdePkg/Library/BaseLib/x64/WriteGdtr.asm | 31 + MdePkg/Library/BaseLib/x64/WriteIdtr.asm | 31 + MdePkg/Library/BaseLib/x64/WriteLdtr.asm | 38 + MdePkg/Library/BaseLib/x64/WriteMm0.asm | 38 + MdePkg/Library/BaseLib/x64/WriteMm1.asm | 38 + MdePkg/Library/BaseLib/x64/WriteMm2.asm | 38 + MdePkg/Library/BaseLib/x64/WriteMm3.asm | 38 + MdePkg/Library/BaseLib/x64/WriteMm4.asm | 38 + MdePkg/Library/BaseLib/x64/WriteMm5.asm | 38 + MdePkg/Library/BaseLib/x64/WriteMm6.asm | 38 + MdePkg/Library/BaseLib/x64/WriteMm7.asm | 38 + MdePkg/Library/BaseLib/x64/WriteMsr32.asm | 41 + MdePkg/Library/BaseLib/x64/WriteMsr64.asm | 43 + MdePkg/Library/BaseLib/x86LowLevel.c | 979 +++ MdePkg/Library/BaseLib/x86Thunk.c | 127 + .../Library/BaseMemoryLib/BaseMemoryLib.mbd | 29 + .../Library/BaseMemoryLib/BaseMemoryLib.msa | 48 + MdePkg/Library/BaseMemoryLib/CopyMem.c | 60 + MdePkg/Library/BaseMemoryLib/MemLibGeneric.c | 282 + MdePkg/Library/BaseMemoryLib/MemLibGuid.c | 131 + MdePkg/Library/BaseMemoryLib/MemLibWrapper.c | 620 ++ MdePkg/Library/BaseMemoryLib/SetMem.c | 51 + MdePkg/Library/BaseMemoryLib/build.xml | 47 + .../BaseMemoryLibMmx/BaseMemoryLibMmx.mbd | 29 + .../BaseMemoryLibMmx/BaseMemoryLibMmx.msa | 58 + MdePkg/Library/BaseMemoryLibMmx/MemLibGuid.c | 131 + .../Library/BaseMemoryLibMmx/MemLibWrapper.c | 620 ++ MdePkg/Library/BaseMemoryLibMmx/build.xml | 47 + .../BaseMemoryLibMmx/ia32/CompareMem.asm | 46 + .../Library/BaseMemoryLibMmx/ia32/CopyMem.asm | 86 + .../BaseMemoryLibMmx/ia32/ScanMem16.asm | 44 + .../BaseMemoryLibMmx/ia32/ScanMem32.asm | 44 + .../BaseMemoryLibMmx/ia32/ScanMem64.asm | 53 + .../BaseMemoryLibMmx/ia32/ScanMem8.asm | 44 + .../Library/BaseMemoryLibMmx/ia32/SetMem.asm | 66 + .../BaseMemoryLibMmx/ia32/SetMem16.asm | 59 + .../BaseMemoryLibMmx/ia32/SetMem32.asm | 59 + .../BaseMemoryLibMmx/ia32/SetMem64.asm | 50 + .../Library/BaseMemoryLibMmx/ia32/ZeroMem.asm | 57 + .../BaseMemoryLibRepStr.mbd | 29 + .../BaseMemoryLibRepStr.msa | 73 + .../BaseMemoryLibRepStr/Ia32/CompareMem.asm | 45 + .../BaseMemoryLibRepStr/Ia32/CopyMem.asm | 55 + .../BaseMemoryLibRepStr/Ia32/ScanMem16.asm | 44 + .../BaseMemoryLibRepStr/Ia32/ScanMem32.asm | 44 + .../BaseMemoryLibRepStr/Ia32/ScanMem64.asm | 53 + .../BaseMemoryLibRepStr/Ia32/ScanMem8.asm | 44 + .../BaseMemoryLibRepStr/Ia32/SetMem.asm | 37 + .../BaseMemoryLibRepStr/Ia32/SetMem16.asm | 37 + .../BaseMemoryLibRepStr/Ia32/SetMem32.asm | 37 + .../BaseMemoryLibRepStr/Ia32/SetMem64.asm | 41 + .../BaseMemoryLibRepStr/Ia32/ZeroMem.asm | 43 + .../Library/BaseMemoryLibRepStr/MemLibGuid.c | 131 + .../BaseMemoryLibRepStr/MemLibWrapper.c | 620 ++ MdePkg/Library/BaseMemoryLibRepStr/build.xml | 47 + .../BaseMemoryLibRepStr/x64/CompareMem.asm | 43 + .../BaseMemoryLibRepStr/x64/CopyMem.asm | 52 + .../BaseMemoryLibRepStr/x64/ScanMem16.asm | 42 + .../BaseMemoryLibRepStr/x64/ScanMem32.asm | 42 + .../BaseMemoryLibRepStr/x64/ScanMem64.asm | 42 + .../BaseMemoryLibRepStr/x64/ScanMem8.asm | 42 + .../BaseMemoryLibRepStr/x64/SetMem.asm | 35 + .../BaseMemoryLibRepStr/x64/SetMem16.asm | 35 + .../BaseMemoryLibRepStr/x64/SetMem32.asm | 35 + .../BaseMemoryLibRepStr/x64/SetMem64.asm | 35 + .../BaseMemoryLibRepStr/x64/ZeroMem.asm | 40 + .../BaseMemoryLibSse2/BaseMemoryLibSse2.mbd | 29 + .../BaseMemoryLibSse2/BaseMemoryLibSse2.msa | 73 + MdePkg/Library/BaseMemoryLibSse2/MemLibGuid.c | 131 + .../Library/BaseMemoryLibSse2/MemLibWrapper.c | 620 ++ MdePkg/Library/BaseMemoryLibSse2/build.xml | 47 + .../BaseMemoryLibSse2/ia32/CompareMem.asm | 46 + .../BaseMemoryLibSse2/ia32/CopyMem.asm | 84 + .../BaseMemoryLibSse2/ia32/ScanMem16.asm | 44 + .../BaseMemoryLibSse2/ia32/ScanMem32.asm | 44 + .../BaseMemoryLibSse2/ia32/ScanMem64.asm | 53 + .../BaseMemoryLibSse2/ia32/ScanMem8.asm | 44 + .../Library/BaseMemoryLibSse2/ia32/SetMem.asm | 74 + .../BaseMemoryLibSse2/ia32/SetMem16.asm | 70 + .../BaseMemoryLibSse2/ia32/SetMem32.asm | 69 + .../BaseMemoryLibSse2/ia32/SetMem64.asm | 63 + .../BaseMemoryLibSse2/ia32/ZeroMem.asm | 66 + .../BaseMemoryLibSse2/x64/CompareMem.asm | 43 + .../Library/BaseMemoryLibSse2/x64/CopyMem.asm | 78 + .../BaseMemoryLibSse2/x64/ScanMem16.asm | 42 + .../BaseMemoryLibSse2/x64/ScanMem32.asm | 42 + .../BaseMemoryLibSse2/x64/ScanMem64.asm | 42 + .../BaseMemoryLibSse2/x64/ScanMem8.asm | 42 + .../Library/BaseMemoryLibSse2/x64/SetMem.asm | 69 + .../BaseMemoryLibSse2/x64/SetMem16.asm | 67 + .../BaseMemoryLibSse2/x64/SetMem32.asm | 66 + .../BaseMemoryLibSse2/x64/SetMem64.asm | 61 + .../Library/BaseMemoryLibSse2/x64/ZeroMem.asm | 63 + .../Library/BasePcdLibNull/BasePcdLibNull.mbd | 29 + .../Library/BasePcdLibNull/BasePcdLibNull.msa | 43 + MdePkg/Library/BasePcdLibNull/PcdLib.c | 734 +++ MdePkg/Library/BasePcdLibNull/build.xml | 47 + .../Library/BasePciCf8Lib/BasePciCf8Lib.mbd | 30 + .../Library/BasePciCf8Lib/BasePciCf8Lib.msa | 45 + MdePkg/Library/BasePciCf8Lib/PciLib.c | 1431 ++++ MdePkg/Library/BasePciCf8Lib/build.xml | 47 + .../BasePciExpressLib/BasePciExpressLib.mbd | 30 + .../BasePciExpressLib/BasePciExpressLib.msa | 45 + MdePkg/Library/BasePciExpressLib/PciLib.c | 1328 ++++ MdePkg/Library/BasePciExpressLib/build.xml | 47 + .../Library/BasePciLibCf8/BasePciLibCf8.mbd | 30 + .../Library/BasePciLibCf8/BasePciLibCf8.msa | 45 + MdePkg/Library/BasePciLibCf8/PciLib.c | 1070 +++ MdePkg/Library/BasePciLibCf8/build.xml | 47 + .../BasePciLibPciExpress.mbd | 30 + .../BasePciLibPciExpress.msa | 45 + MdePkg/Library/BasePciLibPciExpress/PciLib.c | 1070 +++ MdePkg/Library/BasePciLibPciExpress/build.xml | 47 + .../BasePeCoffGetEntryPointLib.mbd | 30 + .../BasePeCoffGetEntryPointLib.msa | 43 + .../PeCoffGetEntryPoint.c | 54 + .../BasePeCoffGetEntryPointLib/build.xml | 47 + MdePkg/Library/BasePeCoffLib/BasePeCoff.c | 1019 +++ .../Library/BasePeCoffLib/BasePeCoffLib.mbd | 30 + .../Library/BasePeCoffLib/BasePeCoffLib.msa | 56 + .../BasePeCoffLib/Ebc/PeCoffLoaderEx.c | 43 + .../BasePeCoffLib/Ia32/PeCoffLoaderEx.c | 44 + .../BasePeCoffLib/Ipf/PeCoffLoaderEx.c | 230 + MdePkg/Library/BasePeCoffLib/build.xml | 47 + .../BasePeCoffLib/x64/PeCoffLoaderEx.c | 56 + .../BasePerformanceLibNull.mbd | 30 + .../BasePerformanceLibNull.msa | 52 + .../BasePerformanceLibNull/PerformanceLib.c | 148 + .../Library/BasePerformanceLibNull/build.xml | 47 + MdePkg/Library/BasePrintLib/BasePrintLib.mbd | 30 + MdePkg/Library/BasePrintLib/BasePrintLib.msa | 46 + MdePkg/Library/BasePrintLib/PrintLib.c | 639 ++ .../Library/BasePrintLib/PrintLibInternal.c | 153 + .../Library/BasePrintLib/PrintLibInternal.h | 87 + MdePkg/Library/BasePrintLib/build.xml | 47 + .../BaseReportStatusCodeLibNull.mbd | 30 + .../BaseReportStatusCodeLibNull.msa | 61 + .../BaseReportStatusCodeLibNull/PostCode.c | 125 + .../ReportStatusCodeLib.c | 439 ++ .../BaseReportStatusCodeLibNull/build.xml | 47 + MdePkg/Library/BaseSmbusLib/BaseSmbusLib.mbd | 33 + MdePkg/Library/BaseSmbusLib/BaseSmbusLib.msa | 47 + MdePkg/Library/BaseSmbusLib/SmbusLib.c | 557 ++ MdePkg/Library/BaseSmbusLib/build.xml | 47 + .../BaseTimerLibLocalApic.mbd | 30 + .../BaseTimerLibLocalApic.msa | 56 + .../BaseTimerLibLocalApic/Ipf/CallPalProc.s | 38 + .../BaseTimerLibLocalApic/Ipf/IpfTimerLib.c | 155 + .../BaseTimerLibLocalApic/Ipf/ReadItc.s | 25 + .../Library/BaseTimerLibLocalApic/build.xml | 47 + .../BaseTimerLibLocalApic/x86TimerLib.c | 168 + .../BaseUefiDecompressLib.c | 712 ++ .../BaseUefiDecompressLib.mbd | 30 + .../BaseUefiDecompressLib.msa | 45 + .../Library/BaseUefiDecompressLib/build.xml | 47 + .../DxeCoreEntryPoint/DxeCoreEntryPoint.c | 63 + .../DxeCoreEntryPoint/DxeCoreEntryPoint.mbd | 30 + .../DxeCoreEntryPoint/DxeCoreEntryPoint.msa | 45 + MdePkg/Library/DxeCoreEntryPoint/build.xml | 47 + .../Library/DxeCoreHobLib/DxeCoreHobLib.mbd | 30 + .../Library/DxeCoreHobLib/DxeCoreHobLib.msa | 46 + MdePkg/Library/DxeCoreHobLib/HobLib.c | 365 ++ MdePkg/Library/DxeCoreHobLib/build.xml | 47 + MdePkg/Library/DxeHobLib/DxeHobLib.mbd | 30 + MdePkg/Library/DxeHobLib/DxeHobLib.msa | 56 + MdePkg/Library/DxeHobLib/HobLib.c | 394 ++ MdePkg/Library/DxeHobLib/build.xml | 47 + .../Library/DxeIoLibCpuIo/DxeIoLibCpuIo.mbd | 29 + .../Library/DxeIoLibCpuIo/DxeIoLibCpuIo.msa | 53 + MdePkg/Library/DxeIoLibCpuIo/IoHighLevel.c | 2272 +++++++ MdePkg/Library/DxeIoLibCpuIo/IoLib.c | 460 ++ MdePkg/Library/DxeIoLibCpuIo/build.xml | 47 + .../DxeMemoryAllocationLib.mbd | 30 + .../DxeMemoryAllocationLib.msa | 46 + .../MemoryAllocationLib.c | 886 +++ .../Library/DxeMemoryAllocationLib/build.xml | 47 + MdePkg/Library/DxePcdLib/DxePcdLib.c | 852 +++ MdePkg/Library/DxePcdLib/DxePcdLib.mbd | 30 + MdePkg/Library/DxePcdLib/DxePcdLib.msa | 50 + MdePkg/Library/DxePcdLib/build.xml | 47 + .../DxeReportStatusCodeLib.mbd | 30 + .../DxeReportStatusCodeLib.msa | 71 + .../Library/DxeReportStatusCodeLib/PostCode.c | 125 + .../ReportStatusCodeLib.c | 585 ++ .../Library/DxeReportStatusCodeLib/build.xml | 47 + .../DxeServicesTableLib/DxeServicesTableLib.c | 36 + .../DxeServicesTableLib.mbd | 30 + .../DxeServicesTableLib.msa | 55 + MdePkg/Library/DxeServicesTableLib/build.xml | 47 + MdePkg/Library/DxeSmbusLib/DxeSmbusLib.c | 168 + MdePkg/Library/DxeSmbusLib/DxeSmbusLib.mbd | 30 + MdePkg/Library/DxeSmbusLib/DxeSmbusLib.msa | 54 + MdePkg/Library/DxeSmbusLib/InternalSmbusLib.h | 112 + MdePkg/Library/DxeSmbusLib/SmbusLib.c | 597 ++ MdePkg/Library/DxeSmbusLib/build.xml | 47 + .../DxeSmmDriverEntryPoint/DriverEntryPoint.c | 274 + .../DxeSmmDriverEntryPoint.mbd | 29 + .../DxeSmmDriverEntryPoint.msa | 50 + .../Library/DxeSmmDriverEntryPoint/build.xml | 47 + MdePkg/Library/HiiLib/HiiLib.c | 62 + MdePkg/Library/HiiLib/HiiLib.mbd | 30 + MdePkg/Library/HiiLib/HiiLib.msa | 45 + MdePkg/Library/HiiLib/build.xml | 47 + .../PeiCoreEntryPoint/PeiCoreEntryPoint.c | 51 + .../PeiCoreEntryPoint/PeiCoreEntryPoint.mbd | 30 + .../PeiCoreEntryPoint/PeiCoreEntryPoint.msa | 43 + MdePkg/Library/PeiCoreEntryPoint/build.xml | 47 + MdePkg/Library/PeiCoreLib/PeiCoreLib.c | 376 ++ MdePkg/Library/PeiCoreLib/PeiCoreLib.mbd | 30 + MdePkg/Library/PeiCoreLib/PeiCoreLib.msa | 44 + MdePkg/Library/PeiCoreLib/build.xml | 47 + MdePkg/Library/PeiHobLib/HobLib.c | 432 ++ MdePkg/Library/PeiHobLib/PeiHobLib.mbd | 30 + MdePkg/Library/PeiHobLib/PeiHobLib.msa | 57 + MdePkg/Library/PeiHobLib/build.xml | 47 + MdePkg/Library/PeiIoLibCpuIo/IoHighLevel.c | 2272 +++++++ MdePkg/Library/PeiIoLibCpuIo/IoLib.c | 530 ++ .../Library/PeiIoLibCpuIo/PeiIoLibCpuIo.mbd | 29 + .../Library/PeiIoLibCpuIo/PeiIoLibCpuIo.msa | 46 + MdePkg/Library/PeiIoLibCpuIo/build.xml | 47 + .../MemoryAllocationLib.c | 879 +++ .../PeiMemoryAllocationLib.mbd | 30 + .../PeiMemoryAllocationLib.msa | 46 + .../Library/PeiMemoryAllocationLib/build.xml | 47 + MdePkg/Library/PeiMemoryLib/MemLib.c | 47 + MdePkg/Library/PeiMemoryLib/MemLibGeneric.c | 282 + MdePkg/Library/PeiMemoryLib/MemLibGuid.c | 131 + MdePkg/Library/PeiMemoryLib/MemLibWrapper.c | 620 ++ MdePkg/Library/PeiMemoryLib/PeiMemoryLib.mbd | 29 + MdePkg/Library/PeiMemoryLib/PeiMemoryLib.msa | 48 + MdePkg/Library/PeiMemoryLib/build.xml | 47 + MdePkg/Library/PeiPcdLib/PeiPcdLib.c | 951 +++ MdePkg/Library/PeiPcdLib/PeiPcdLib.mbd | 30 + MdePkg/Library/PeiPcdLib/PeiPcdLib.msa | 46 + MdePkg/Library/PeiPcdLib/build.xml | 47 + .../PeiReportStatusCodeLib.mbd | 30 + .../PeiReportStatusCodeLib.msa | 68 + .../Library/PeiReportStatusCodeLib/PostCode.c | 125 + .../ReportStatusCodeLib.c | 548 ++ .../Library/PeiReportStatusCodeLib/build.xml | 47 + .../PeiResourcePublicationLib.c | 50 + .../PeiResourcePublicationLib.mbd | 30 + .../PeiResourcePublicationLib.msa | 45 + .../PeiResourcePublicationLib/build.xml | 47 + .../PeiServicesTablePointer.c | 39 + .../PeiServicesTablePointerLib.mbd | 30 + .../PeiServicesTablePointerLib.msa | 48 + .../PeiServicesTablePointerLib/build.xml | 47 + .../PeiServicesTablePointer.c | 37 + .../PeiServicesTablePointerLibMm7.mbd | 30 + .../PeiServicesTablePointerLibMm7.msa | 49 + .../PeiServicesTablePointerLibMm7/build.xml | 47 + MdePkg/Library/PeiSmbusLib/InternalSmbusLib.h | 112 + MdePkg/Library/PeiSmbusLib/PeiSmbusLib.c | 177 + MdePkg/Library/PeiSmbusLib/PeiSmbusLib.mbd | 30 + MdePkg/Library/PeiSmbusLib/PeiSmbusLib.msa | 51 + MdePkg/Library/PeiSmbusLib/SmbusLib.c | 597 ++ MdePkg/Library/PeiSmbusLib/build.xml | 47 + .../Library/PeimEntryPoint/PeimEntryPoint.c | 68 + .../Library/PeimEntryPoint/PeimEntryPoint.mbd | 30 + .../Library/PeimEntryPoint/PeimEntryPoint.msa | 44 + MdePkg/Library/PeimEntryPoint/build.xml | 47 + .../UefiBootServicesTableLib.c | 47 + .../UefiBootServicesTableLib.mbd | 30 + .../UefiBootServicesTableLib.msa | 49 + .../UefiBootServicesTableLib/build.xml | 47 + MdePkg/Library/UefiDebugLibConOut/DebugLib.c | 247 + .../UefiDebugLibConOut/UefiDebugLibConOut.mbd | 30 + .../UefiDebugLibConOut/UefiDebugLibConOut.msa | 65 + MdePkg/Library/UefiDebugLibConOut/build.xml | 47 + MdePkg/Library/UefiDebugLibStdErr/DebugLib.c | 247 + .../UefiDebugLibStdErr/UefiDebugLibStdErr.mbd | 30 + .../UefiDebugLibStdErr/UefiDebugLibStdErr.msa | 65 + MdePkg/Library/UefiDebugLibStdErr/build.xml | 47 + .../UefiDevicePathLib/UefiDevicePathLib.c | 434 ++ .../UefiDevicePathLib/UefiDevicePathLib.mbd | 30 + .../UefiDevicePathLib/UefiDevicePathLib.msa | 51 + MdePkg/Library/UefiDevicePathLib/build.xml | 47 + .../UefiDevicePathLib.c | 274 + .../UefiDevicePathLibDevicePathProtocol.mbd | 29 + .../UefiDevicePathLibDevicePathProtocol.msa | 55 + .../build.xml | 47 + .../UefiDriverEntryPoint/DriverEntryPoint.c | 137 + .../UefiDriverEntryPoint.mbd | 30 + .../UefiDriverEntryPoint.msa | 50 + MdePkg/Library/UefiDriverEntryPoint/build.xml | 47 + .../UefiDriverModelLib/UefiDriverModelLib.c | 405 ++ .../UefiDriverModelLib/UefiDriverModelLib.mbd | 30 + .../UefiDriverModelLib/UefiDriverModelLib.msa | 57 + MdePkg/Library/UefiDriverModelLib/build.xml | 47 + MdePkg/Library/UefiLib/Console.c | 278 + MdePkg/Library/UefiLib/UefiLib.c | 650 ++ MdePkg/Library/UefiLib/UefiLib.mbd | 30 + MdePkg/Library/UefiLib/UefiLib.msa | 61 + MdePkg/Library/UefiLib/UefiNotTiano.c | 285 + MdePkg/Library/UefiLib/build.xml | 47 + MdePkg/Library/UefiMemoryLib/MemLib.c | 39 + MdePkg/Library/UefiMemoryLib/MemLibGeneric.c | 282 + MdePkg/Library/UefiMemoryLib/MemLibGuid.c | 131 + MdePkg/Library/UefiMemoryLib/MemLibWrapper.c | 620 ++ .../Library/UefiMemoryLib/UefiMemoryLib.mbd | 29 + .../Library/UefiMemoryLib/UefiMemoryLib.msa | 48 + MdePkg/Library/UefiMemoryLib/build.xml | 47 + .../UefiRuntimeServicesTableLib.c | 36 + .../UefiRuntimeServicesTableLib.mbd | 30 + .../UefiRuntimeServicesTableLib.msa | 49 + .../UefiRuntimeServicesTableLib/build.xml | 47 + MdePkg/MdePkg.fpd | 482 ++ MdePkg/MdePkg.spd | 1231 ++++ MdePkg/build.xml | 74 + MdePkg/genbuildfile.xml | 19 + Start Create Setup Package.bat | 40 + Tools/Conf/BuildMacro.xml | 1115 ++++ Tools/Conf/Common.xml | 133 + Tools/Conf/FrameworkDatabase.db | 65 + Tools/Conf/debug_efi_flags.txt | 4 + Tools/Conf/efi_flags_table.txt | 26 + Tools/Conf/gcc_tools.txt | 7 + Tools/Conf/gcc_tools_def.txt | 55 + Tools/Conf/global_efi_flags.txt | 35 + Tools/Conf/intel_tools.txt | 19 + Tools/Conf/msft_tools.txt | 8 + Tools/Conf/msft_tools_def.txt | 43 + Tools/Conf/my_efi_flags.txt | 2 + Tools/Conf/release_efi_flags.txt | 4 + Tools/Conf/target.txt | 2 + Tools/Conf/tools_def.txt | 44 + Tools/Conf/winddk_tools.txt | 19 + Tools/JavaResources.msa | 71 + Tools/Source/Cpptasks/build.xml | 55 + Tools/Source/Cpptasks/cpptasks.mf | 7 + Tools/Source/Cpptasks/cpptasks.tasks | 1 + Tools/Source/Cpptasks/cpptasks.types | 9 + Tools/Source/Cpptasks/javadoc.xml | 30 + .../sf/antcontrib/cpptasks/AboutCCTask.java | 49 + .../net/sf/antcontrib/cpptasks/ArchEnum.java | 72 + .../antcontrib/cpptasks/AslcompilerDef.java | 118 + .../antcontrib/cpptasks/AslcompilerEnum.java | 54 + .../sf/antcontrib/cpptasks/AssemblerDef.java | 237 + .../sf/antcontrib/cpptasks/AssemblerEnum.java | 53 + .../net/sf/antcontrib/cpptasks/CCTask.java | 1749 +++++ .../cpptasks/CCTaskProgressMonitor.java | 56 + .../net/sf/antcontrib/cpptasks/CPUEnum.java | 71 + .../net/sf/antcontrib/cpptasks/CUtil.java | 461 ++ .../sf/antcontrib/cpptasks/CompilerDef.java | 556 ++ .../sf/antcontrib/cpptasks/CompilerEnum.java | 221 + .../sf/antcontrib/cpptasks/CompilerParam.java | 33 + .../antcontrib/cpptasks/DependencyInfo.java | 86 + .../antcontrib/cpptasks/DependencyTable.java | 609 ++ .../antcontrib/cpptasks/DistributerDef.java | 243 + .../antcontrib/cpptasks/DistributerMap.java | 218 + .../cpptasks/DistributerProtocolEnum.java | 50 + .../sf/antcontrib/cpptasks/FileVisitor.java | 27 + .../net/sf/antcontrib/cpptasks/LinkerDef.java | 549 ++ .../sf/antcontrib/cpptasks/LinkerEnum.java | 106 + .../sf/antcontrib/cpptasks/LinkerParam.java | 33 + .../sf/antcontrib/cpptasks/OSFamilyEnum.java | 59 + .../cpptasks/ObjectFileCollector.java | 42 + .../antcontrib/cpptasks/OptimizationEnum.java | 82 + .../antcontrib/cpptasks/OutputTypeEnum.java | 48 + .../sf/antcontrib/cpptasks/PrecompileDef.java | 215 + .../cpptasks/PrecompileExceptDef.java | 80 + .../sf/antcontrib/cpptasks/ProcessorDef.java | 714 ++ .../cpptasks/ProcessorEnumValue.java | 47 + .../antcontrib/cpptasks/ProcessorParam.java | 100 + .../sf/antcontrib/cpptasks/RuntimeType.java | 26 + .../sf/antcontrib/cpptasks/SourceHistory.java | 51 + .../sf/antcontrib/cpptasks/SubsystemEnum.java | 34 + .../net/sf/antcontrib/cpptasks/TargetDef.java | 228 + .../sf/antcontrib/cpptasks/TargetHistory.java | 58 + .../cpptasks/TargetHistoryTable.java | 426 ++ .../sf/antcontrib/cpptasks/TargetInfo.java | 127 + .../sf/antcontrib/cpptasks/TargetMatcher.java | 117 + .../sf/antcontrib/cpptasks/VersionInfo.java | 550 ++ .../antcontrib/cpptasks/arm/ADSCCompiler.java | 215 + .../antcontrib/cpptasks/arm/ADSLibrarian.java | 160 + .../sf/antcontrib/cpptasks/arm/ADSLinker.java | 166 + .../cpptasks/borland/BorlandCCompiler.java | 135 + .../cpptasks/borland/BorlandCfgParser.java | 70 + .../cpptasks/borland/BorlandLibrarian.java | 200 + .../cpptasks/borland/BorlandLinker.java | 264 + .../cpptasks/borland/BorlandProcessor.java | 219 + .../borland/BorlandResourceCompiler.java | 130 + .../cpptasks/borland/CfgFilenameState.java | 46 + .../borland/ConsumeToSpaceOrNewLine.java | 30 + .../cpptasks/borland/QuoteBranchState.java | 35 + .../compaq/CompaqVisualFortranCompiler.java | 138 + .../compaq/CompaqVisualFortranLibrarian.java | 82 + .../compaq/CompaqVisualFortranLinker.java | 77 + .../compiler/AbstractAslcompiler.java | 75 + .../cpptasks/compiler/AbstractAssembler.java | 72 + .../cpptasks/compiler/AbstractCompiler.java | 205 + .../cpptasks/compiler/AbstractLinker.java | 85 + .../cpptasks/compiler/AbstractProcessor.java | 129 + .../cpptasks/compiler/Aslcompiler.java | 23 + .../compiler/AslcompilerConfiguration.java | 29 + .../cpptasks/compiler/Assembler.java | 23 + .../compiler/AssemblerConfiguration.java | 29 + .../compiler/CaptureStreamHandler.java | 122 + .../compiler/CommandLineAslcompiler.java | 226 + .../CommandLineAslcompilerConfiguration.java | 93 + .../compiler/CommandLineAssembler.java | 326 + .../CommandLineAssemblerConfiguration.java | 123 + .../compiler/CommandLineCCompiler.java | 42 + .../compiler/CommandLineCompiler.java | 435 ++ .../CommandLineCompilerConfiguration.java | 216 + .../compiler/CommandLineFortranCompiler.java | 42 + .../cpptasks/compiler/CommandLineLinker.java | 404 ++ .../CommandLineLinkerConfiguration.java | 119 + .../cpptasks/compiler/Compiler.java | 24 + .../compiler/CompilerConfiguration.java | 64 + .../cpptasks/compiler/LinkType.java | 134 + .../antcontrib/cpptasks/compiler/Linker.java | 57 + .../compiler/LinkerConfiguration.java | 31 + .../PrecompilingCommandLineCCompiler.java | 43 + .../PrecompilingCommandLineCompiler.java | 104 + .../compiler/PrecompilingCompiler.java | 49 + .../cpptasks/compiler/Processor.java | 73 + .../compiler/ProcessorConfiguration.java | 52 + .../cpptasks/compiler/ProgressMonitor.java | 31 + .../devstudio/DevStudioAslcompiler.java | 70 + .../devstudio/DevStudioAssembler.java | 84 + .../devstudio/DevStudioCCompiler.java | 50 + .../DevStudioCompatibleCCompiler.java | 136 + .../DevStudioCompatibleLibrarian.java | 86 + .../devstudio/DevStudioCompatibleLinker.java | 127 + .../devstudio/DevStudioLibrarian.java | 36 + .../cpptasks/devstudio/DevStudioLinker.java | 44 + .../devstudio/DevStudioMIDLCompiler.java | 113 + .../devstudio/DevStudioProcessor.java | 90 + .../devstudio/DevStudioResourceCompiler.java | 117 + .../cpptasks/gcc/AbstractArLibrarian.java | 106 + .../cpptasks/gcc/AbstractLdLinker.java | 323 + .../antcontrib/cpptasks/gcc/GccAssembler.java | 76 + .../antcontrib/cpptasks/gcc/GccCCompiler.java | 243 + .../cpptasks/gcc/GccCompatibleCCompiler.java | 152 + .../antcontrib/cpptasks/gcc/GccLibrarian.java | 41 + .../sf/antcontrib/cpptasks/gcc/GccLinker.java | 210 + .../antcontrib/cpptasks/gcc/GccProcessor.java | 299 + .../sf/antcontrib/cpptasks/gcc/GppLinker.java | 203 + .../sf/antcontrib/cpptasks/gcc/LdLinker.java | 57 + .../cpptasks/gcc/cross/GccCCompiler.java | 273 + .../cpptasks/gcc/cross/GccLibrarian.java | 69 + .../cpptasks/gcc/cross/GccLinker.java | 234 + .../cpptasks/gcc/cross/GccProcessor.java | 288 + .../cpptasks/gcc/cross/GppLinker.java | 228 + .../cpptasks/gcc/cross/LdLinker.java | 83 + .../sparc_sun_solaris2/GccCCompiler.java | 245 + .../sparc_sun_solaris2/GccLibrarian.java | 43 + .../cross/sparc_sun_solaris2/GccLinker.java | 215 + .../sparc_sun_solaris2/GccProcessor.java | 305 + .../cross/sparc_sun_solaris2/GppLinker.java | 210 + .../cross/sparc_sun_solaris2/LdLinker.java | 60 + .../antcontrib/cpptasks/hp/aCCCompiler.java | 104 + .../sf/antcontrib/cpptasks/hp/aCCLinker.java | 100 + .../cpptasks/ibm/VisualAgeCCompiler.java | 111 + .../cpptasks/ibm/VisualAgeLinker.java | 75 + .../cpptasks/intel/IntelLinux32CCompiler.java | 58 + .../cpptasks/intel/IntelLinux32Linker.java | 55 + .../cpptasks/intel/IntelLinux64CCompiler.java | 58 + .../cpptasks/intel/IntelLinux64Linker.java | 55 + .../cpptasks/intel/IntelProcessor.java | 51 + .../cpptasks/intel/IntelWin32Aslcompiler.java | 66 + .../cpptasks/intel/IntelWin32CCompiler.java | 53 + .../cpptasks/intel/IntelWin32Librarian.java | 38 + .../cpptasks/intel/IntelWin32Linker.java | 46 + .../cpptasks/intel/IntelWin64CCompiler.java | 53 + .../cpptasks/os390/OS390CCompiler.java | 157 + .../cpptasks/os390/OS390Linker.java | 201 + .../cpptasks/os390/OS390Processor.java | 71 + .../cpptasks/os400/IccCompiler.java | 124 + .../antcontrib/cpptasks/os400/IccLinker.java | 202 + .../cpptasks/os400/IccProcessor.java | 71 + .../cpptasks/parser/AbstractParser.java | 67 + .../cpptasks/parser/AbstractParserState.java | 41 + .../cpptasks/parser/BranchState.java | 46 + .../antcontrib/cpptasks/parser/CParser.java | 78 + .../parser/CaseInsensitiveLetterState.java | 87 + .../cpptasks/parser/FilenameState.java | 41 + .../cpptasks/parser/FortranParser.java | 106 + .../cpptasks/parser/LetterState.java | 80 + .../sf/antcontrib/cpptasks/parser/Parser.java | 28 + .../sf/antcontrib/cpptasks/parser/PostE.java | 41 + ...hitespaceOrCaseInsensitiveLetterState.java | 83 + .../parser/WhitespaceOrLetterState.java | 75 + .../antcontrib/cpptasks/sun/C89CCompiler.java | 109 + .../sf/antcontrib/cpptasks/sun/C89Linker.java | 125 + .../antcontrib/cpptasks/sun/C89Processor.java | 116 + .../cpptasks/sun/ForteCCCompiler.java | 119 + .../cpptasks/sun/ForteCCLinker.java | 100 + .../antcontrib/cpptasks/ti/ClxxCCompiler.java | 192 + .../antcontrib/cpptasks/ti/ClxxLibrarian.java | 162 + .../sf/antcontrib/cpptasks/ti/ClxxLinker.java | 181 + .../cpptasks/types/AslcompilerArgument.java | 30 + .../cpptasks/types/AssemblerArgument.java | 30 + .../cpptasks/types/CommandLineArgument.java | 122 + .../cpptasks/types/CompilerArgument.java | 28 + .../cpptasks/types/ConditionalFileSet.java | 84 + .../cpptasks/types/ConditionalPath.java | 92 + .../cpptasks/types/DefineArgument.java | 38 + .../antcontrib/cpptasks/types/DefineSet.java | 199 + .../antcontrib/cpptasks/types/FlexLong.java | 59 + .../cpptasks/types/IncludePath.java | 38 + .../antcontrib/cpptasks/types/LibrarySet.java | 290 + .../cpptasks/types/LibraryTypeEnum.java | 48 + .../cpptasks/types/LinkerArgument.java | 28 + .../cpptasks/types/SystemIncludePath.java | 45 + .../cpptasks/types/SystemLibrarySet.java | 37 + .../cpptasks/types/UndefineArgument.java | 153 + .../userdefine/CommandLineUserDefine.java | 389 ++ .../userdefine/UserDefineArgument.java | 31 + .../userdefine/UserDefineCompiler.java | 219 + .../cpptasks/userdefine/UserDefineDef.java | 497 ++ .../userdefine/UserDefineElement.java | 23 + .../userdefine/UserDefineMapping.java | 186 + Tools/Source/CreateMdkPkg/MANIFEST.MF | 2 + Tools/Source/CreateMdkPkg/build.xml | 64 + .../src/org/tianocore/common/Log.java | 188 + .../src/org/tianocore/common/Tools.java | 120 + .../org/tianocore/packaging/FrameworkPkg.java | 238 + .../src/org/tianocore/packaging/MdkPkg.java | 59 + .../packaging/common/ui/ExitConfirm.java | 264 + .../tianocore/packaging/common/ui/IFrame.java | 203 + .../workspace/command/InstallWorkspace.java | 161 + .../packaging/workspace/ui/Finish.java | 295 + .../workspace/ui/LicenseAgreement.java | 403 ++ .../ui/SelectDestinationDirectory.java | 469 ++ .../packaging/workspace/ui/Welcome.java | 272 + Tools/Source/FrameworkTasks/build.xml | 50 + .../FrameworkTasks/frameworktasks.tasks | 11 + .../tianocore/framework/tasks/Compress.java | 78 + .../framework/tasks/CompressHeader.java | 78 + .../framework/tasks/CompressSection.java | 209 + .../tianocore/framework/tasks/Database.java | 112 + .../tianocore/framework/tasks/EfiDefine.java | 56 + .../tianocore/framework/tasks/FfsHeader.java | 185 + .../tianocore/framework/tasks/FfsTypes.java | 115 + .../tianocore/framework/tasks/FileParser.java | 72 + .../framework/tasks/FwImageTask.java | 199 + .../framework/tasks/GenCRC32SectionTask.java | 183 + .../framework/tasks/GenDepexTask.java | 166 + .../framework/tasks/GenFfsFileTask.java | 878 +++ .../framework/tasks/GenFvImageTask.java | 154 + .../framework/tasks/GenSectionTask.java | 215 + .../framework/tasks/GuidChkTask.java | 367 ++ .../framework/tasks/IncludePath.java | 123 + .../org/tianocore/framework/tasks/Input.java | 44 + .../tianocore/framework/tasks/InputFile.java | 95 + .../tianocore/framework/tasks/MakeDeps.java | 443 ++ .../framework/tasks/NestElement.java | 40 + .../tianocore/framework/tasks/SectFile.java | 108 + .../tianocore/framework/tasks/Section.java | 23 + .../framework/tasks/SetStampTask.java | 136 + .../tianocore/framework/tasks/SkipExt.java | 83 + .../framework/tasks/StrGatherTask.java | 527 ++ .../org/tianocore/framework/tasks/Tool.java | 194 + .../tianocore/framework/tasks/ToolArg.java | 42 + .../framework/tasks/VfrCompilerTask.java | 221 + Tools/Source/GenBuild/GenBuild.tasks | 11 + Tools/Source/GenBuild/build.xml | 51 + .../org/tianocore/build/ExpandTask.java | 52 + .../org/tianocore/build/FfsProcess.java | 390 ++ .../org/tianocore/build/FileProcess.java | 225 + .../org/tianocore/build/GenBuildTask.java | 1170 ++++ .../tianocore/build/OutputDirSetupTask.java | 190 + .../org/tianocore/build/autogen/AutoGen.java | 2006 ++++++ .../build/autogen/AutogenLibOrder.java | 306 + .../build/autogen/CommonDefinition.java | 257 + .../build/fpd/FpdModuleIdentification.java | 131 + .../tianocore/build/fpd/FpdParserTask.java | 808 +++ .../org/tianocore/build/global/DpFile.java | 129 + .../tianocore/build/global/DpFileList.java | 50 + .../tianocore/build/global/GlobalData.java | 637 ++ .../tianocore/build/global/GlobalShare.java | 178 + .../build/global/LibBuildFileGenerator.java | 412 ++ .../build/global/ModuleIdentification.java | 55 + .../tianocore/build/global/OnDependency.java | 121 + .../tianocore/build/global/OutputManager.java | 176 + .../build/global/OverrideProcess.java | 354 + .../org/tianocore/build/global/Spd.java | 414 ++ .../build/global/SurfaceAreaParser.java | 218 + .../build/global/SurfaceAreaQuery.java | 1109 ++++ .../tianocore/build/global/VariableTask.java | 71 + .../build/pcd/action/ActionMessage.java | 129 + .../build/pcd/action/BuildAction.java | 114 + .../build/pcd/action/CollectPCDAction.java | 669 ++ .../build/pcd/action/PCDAutoGenAction.java | 452 ++ .../pcd/action/ShowPCDDatabaseAction.java | 130 + .../tianocore/build/pcd/action/UIAction.java | 83 + .../pcd/entity/MemoryDatabaseManager.java | 306 + .../build/pcd/entity/SkuInstance.java | 40 + .../org/tianocore/build/pcd/entity/Token.java | 641 ++ .../build/pcd/entity/UsageInstance.java | 471 ++ .../pcd/exception/BuildActionException.java | 33 + .../build/pcd/exception/EntityException.java | 31 + .../build/pcd/exception/UIException.java | 31 + .../build/pcd/ui/PCDDatabaseFrame.java | 184 + .../build/toolchain/ConfigReader.java | 218 + .../build/toolchain/ToolChainFactory.java | 529 ++ .../build/toolchain/ToolChainTask.java | 60 + Tools/Source/ModuleEditor/MANIFEST.MF | 3 + Tools/Source/ModuleEditor/build.xml | 44 + .../src/org/tianocore/common/DataType.java | 44 + .../org/tianocore/common/DataValidation.java | 905 +++ .../src/org/tianocore/common/IFileFilter.java | 87 + .../src/org/tianocore/common/Log.java | 211 + .../src/org/tianocore/common/Tools.java | 120 + .../packaging/common/ui/ExitConfirm.java | 265 + .../packaging/common/ui/IComboBox.java | 196 + .../common/ui/IDefaultMutableTreeNode.java | 307 + .../packaging/common/ui/IDesktopManager.java | 76 + .../packaging/common/ui/IDialog.java | 144 + .../tianocore/packaging/common/ui/IFrame.java | 204 + .../packaging/common/ui/IInternalFrame.java | 109 + .../tianocore/packaging/common/ui/ITree.java | 204 + .../packaging/common/ui/StarLabel.java | 64 + .../packaging/module/ui/MbdHeader.java | 602 ++ .../packaging/module/ui/MbdLibHeader.java | 599 ++ .../packaging/module/ui/MbdLibraries.java | 1048 +++ .../packaging/module/ui/ModuleAbout.java | 146 + .../packaging/module/ui/ModuleBootModes.java | 456 ++ .../packaging/module/ui/ModuleDataHubs.java | 457 ++ .../packaging/module/ui/ModuleEvents.java | 626 ++ .../packaging/module/ui/ModuleExterns.java | 1030 +++ .../packaging/module/ui/ModuleFormsets.java | 457 ++ .../packaging/module/ui/ModuleGuids.java | 675 ++ .../packaging/module/ui/ModuleHobs.java | 596 ++ .../packaging/module/ui/ModuleIncludes.java | 867 +++ .../ui/ModuleLibraryClassDefinitions.java | 625 ++ .../packaging/module/ui/ModuleMain.java | 4422 +++++++++++++ .../packaging/module/ui/ModulePCDs.java | 519 ++ .../packaging/module/ui/ModulePpis.java | 711 ++ .../packaging/module/ui/ModuleProtocols.java | 705 ++ .../module/ui/ModuleSourceFiles.java | 1060 +++ .../module/ui/ModuleSystemTables.java | 393 ++ .../packaging/module/ui/ModuleVariables.java | 601 ++ .../packaging/module/ui/MsaHeader.java | 843 +++ .../packaging/module/ui/MsaLibHeader.java | 845 +++ .../packaging/workspace/common/Workspace.java | 147 + Tools/Source/PackageEditor/MANIFEST.MF | 3 + Tools/Source/PackageEditor/build.xml | 44 + .../src/org/tianocore/common/Tools.java | 73 + .../org/tianocore/packaging/CreateFdp.java | 93 + .../tianocore/packaging/DbFileContents.java | 315 + .../tianocore/packaging/ForceInstallPkg.java | 80 + .../org/tianocore/packaging/FrameworkPkg.java | 402 ++ .../tianocore/packaging/GuiPkgInstall.java | 804 +++ .../tianocore/packaging/GuiPkgUninstall.java | 370 ++ .../tianocore/packaging/ManifestContents.java | 74 + .../tianocore/packaging/ModalFrameUtil.java | 107 + .../tianocore/packaging/PackageAction.java | 348 + .../org/tianocore/packaging/PackageGuids.java | 354 + .../packaging/PackageLibraryClass.java | 545 ++ .../tianocore/packaging/PackageMsaFile.java | 352 + .../org/tianocore/packaging/PackageNew.java | 533 ++ .../org/tianocore/packaging/PackagePCD.java | 321 + .../tianocore/packaging/PackagePkgHeader.java | 454 ++ .../org/tianocore/packaging/PackagePpi.java | 41 + .../tianocore/packaging/PackageProtocols.java | 377 ++ .../tianocore/packaging/PackagingMain.java | 309 + .../packaging/PkgInstallTypeChooser.java | 373 ++ .../tianocore/packaging/SpdFileContents.java | 1282 ++++ .../org/tianocore/packaging/UpdateAction.java | 328 + .../org/tianocore/packaging/UpdateGuids.java | 226 + .../packaging/UpdateLibraryClass.java | 221 + .../tianocore/packaging/UpdateMsaFile.java | 217 + .../org/tianocore/packaging/UpdateNew.java | 573 ++ .../org/tianocore/packaging/UpdatePCD.java | 256 + .../tianocore/packaging/UpdatePkgHeader.java | 236 + .../org/tianocore/packaging/UpdatePpi.java | 226 + .../tianocore/packaging/UpdateProtocols.java | 226 + .../packaging/common/ui/StarLabel.java | 41 + Tools/Source/Prototype/Auto.java | 8 + Tools/Source/Prototype/Component.java | 43 + Tools/Source/Prototype/DAG.java | 176 + Tools/Source/Prototype/Database.java | 14 + Tools/Source/Prototype/GuidDecl.java | 16 + Tools/Source/Prototype/LibClass.java | 14 + Tools/Source/Prototype/LibInst.java | 22 + Tools/Source/Prototype/Module.java | 178 + Tools/Source/Prototype/Package.java | 44 + Tools/Source/Prototype/PpiDecl.java | 16 + Tools/Source/Prototype/ProtocolDecl.java | 16 + Tools/Source/Prototype/TSort.java | 24 + Tools/Source/Prototype/build.xml | 27 + Tools/Source/SurfaceArea/build.xml | 203 + Tools/Source/TianoTools/Common/CommonLib.c | 495 ++ Tools/Source/TianoTools/Common/CommonLib.h | 131 + Tools/Source/TianoTools/Common/Crc32.c | 326 + Tools/Source/TianoTools/Common/Crc32.h | 57 + Tools/Source/TianoTools/Common/EfiCompress.c | 1745 +++++ Tools/Source/TianoTools/Common/EfiCompress.h | 68 + .../TianoTools/Common/EfiCustomizedCompress.h | 141 + .../Source/TianoTools/Common/EfiDecompress.c | 790 +++ .../Source/TianoTools/Common/EfiDecompress.h | 105 + .../Source/TianoTools/Common/EfiUtilityMsgs.c | 758 +++ .../Source/TianoTools/Common/EfiUtilityMsgs.h | 138 + Tools/Source/TianoTools/Common/FvLib.c | 788 +++ Tools/Source/TianoTools/Common/FvLib.h | 185 + Tools/Source/TianoTools/Common/MyAlloc.c | 516 ++ Tools/Source/TianoTools/Common/MyAlloc.h | 225 + Tools/Source/TianoTools/Common/ParseInf.c | 630 ++ Tools/Source/TianoTools/Common/ParseInf.h | 235 + Tools/Source/TianoTools/Common/PeiLib/Debug.c | 131 + .../TianoTools/Common/PeiLib/Decompress.c | 1104 ++++ .../Source/TianoTools/Common/PeiLib/Hob/Hob.c | 495 ++ .../Common/PeiLib/Ipf/PeCoffLoaderEx.c | 244 + .../Common/PeiLib/Ipf/PeCoffLoaderEx.h | 67 + .../Common/PeiLib/Ipf/PerformancePrimitives.s | 61 + .../Common/PeiLib/Ipf/SwitchStack.s | 122 + .../Source/TianoTools/Common/PeiLib/Ipf/asm.h | 35 + .../TianoTools/Common/PeiLib/Ipf/efijump.h | 112 + .../TianoTools/Common/PeiLib/Ipf/ia_64gen.h | 214 + .../TianoTools/Common/PeiLib/Ipf/math.c | 139 + .../TianoTools/Common/PeiLib/Ipf/pioflush.s | 106 + .../TianoTools/Common/PeiLib/Ipf/processor.c | 118 + .../TianoTools/Common/PeiLib/Ipf/setjmp.s | 325 + .../TianoTools/Common/PeiLib/PeCoffLoader.c | 1249 ++++ .../Source/TianoTools/Common/PeiLib/PeiLib.c | 169 + .../Source/TianoTools/Common/PeiLib/PeiLib.h | 798 +++ Tools/Source/TianoTools/Common/PeiLib/Perf.c | 233 + .../TianoTools/Common/PeiLib/Print/Print.c | 736 +++ .../TianoTools/Common/PeiLib/Print/Print.h | 37 + .../Common/PeiLib/ia32/PeCoffLoaderEx.c | 56 + .../Common/PeiLib/ia32/PeCoffLoaderEx.h | 65 + .../PeiLib/ia32/PerformancePrimitives.c | 47 + .../TianoTools/Common/PeiLib/ia32/Processor.c | 140 + .../Common/PeiLib/ia32/ProcessorAsms.Asm | 223 + .../TianoTools/Common/PeiLib/ia32/efijump.h | 34 + .../TianoTools/Common/SimpleFileParsing.c | 1460 +++++ .../TianoTools/Common/SimpleFileParsing.h | 121 + Tools/Source/TianoTools/Common/WinNtInclude.h | 73 + Tools/Source/TianoTools/Common/build.gcc | 8 + Tools/Source/TianoTools/Common/build.xml | 120 + .../TianoTools/CompressDll/CompressDll.c | 89 + .../TianoTools/CompressDll/CompressDll.h | 21 + Tools/Source/TianoTools/CompressDll/build.xml | 116 + .../CustomizedCompress/CustomizedCompress.c | 147 + .../TianoTools/CustomizedCompress/build.gcc | 8 + .../TianoTools/CustomizedCompress/build.xml | 121 + Tools/Source/TianoTools/FwImage/build.gcc | 1 + Tools/Source/TianoTools/FwImage/build.xml | 117 + Tools/Source/TianoTools/FwImage/fwimage.c | 332 + .../GenCRC32Section/GenCRC32Section.c | 286 + .../GenCRC32Section/GenCRC32Section.h | 64 + .../TianoTools/GenCRC32Section/build.gcc | 1 + .../TianoTools/GenCRC32Section/build.xml | 127 + .../Source/TianoTools/GenDepex/DepexParser.c | 903 +++ .../Source/TianoTools/GenDepex/DepexParser.h | 26 + Tools/Source/TianoTools/GenDepex/GenDepex.c | 916 +++ Tools/Source/TianoTools/GenDepex/GenDepex.h | 71 + Tools/Source/TianoTools/GenDepex/build.gcc | 1 + Tools/Source/TianoTools/GenDepex/build.xml | 146 + .../Source/TianoTools/GenFfsFile/GenFfsFile.c | 2645 ++++++++ .../Source/TianoTools/GenFfsFile/GenFfsFile.h | 36 + .../TianoTools/GenFfsFile/SimpleFileParsing.c | 969 +++ Tools/Source/TianoTools/GenFfsFile/build.gcc | 1 + Tools/Source/TianoTools/GenFfsFile/build.xml | 119 + .../Source/TianoTools/GenFvImage/BasePeCoff.c | 1062 +++ .../TianoTools/GenFvImage/Common/EfiImage.h | 701 ++ .../GenFvImage/Ebc/PeCoffLoaderEx.c | 57 + .../TianoTools/GenFvImage/GenFvImageExe.c | 299 + .../TianoTools/GenFvImage/GenFvImageExe.h | 98 + .../TianoTools/GenFvImage/GenFvImageLib.c | 2871 +++++++++ .../TianoTools/GenFvImage/GenFvImageLib.h | 140 + .../GenFvImage/GenFvImageLibInternal.h | 170 + .../GenFvImage/Ia32/PeCoffLoaderEx.c | 64 + .../GenFvImage/Ipf/PeCoffLoaderEx.c | 251 + Tools/Source/TianoTools/GenFvImage/build.gcc | 3 + Tools/Source/TianoTools/GenFvImage/build.xml | 246 + .../GenFvImage/x64/PeCoffLoaderEx.c | 76 + .../Source/TianoTools/GenSection/GenSection.c | 939 +++ .../Source/TianoTools/GenSection/GenSection.h | 43 + Tools/Source/TianoTools/GenSection/build.gcc | 1 + Tools/Source/TianoTools/GenSection/build.xml | 119 + Tools/Source/TianoTools/GuidChk/CommonUtils.h | 57 + Tools/Source/TianoTools/GuidChk/FileSearch.c | 285 + Tools/Source/TianoTools/GuidChk/FileSearch.h | 108 + Tools/Source/TianoTools/GuidChk/GuidChk.c | 2348 +++++++ Tools/Source/TianoTools/GuidChk/GuidList.c | 188 + Tools/Source/TianoTools/GuidChk/UtilsMsgs.c | 490 ++ Tools/Source/TianoTools/GuidChk/UtilsMsgs.h | 106 + Tools/Source/TianoTools/GuidChk/build.gcc | 1 + Tools/Source/TianoTools/GuidChk/build.xml | 120 + .../TianoTools/Pccts/CHANGES_FROM_131.txt | 522 ++ .../TianoTools/Pccts/CHANGES_FROM_133.txt | 2448 +++++++ .../Pccts/CHANGES_FROM_133_BEFORE_MR13.txt | 3666 +++++++++++ .../TianoTools/Pccts/CHANGES_SUMMARY.txt | 2049 ++++++ .../TianoTools/Pccts/KNOWN_PROBLEMS.txt | 241 + Tools/Source/TianoTools/Pccts/MPW_Read_Me | 21 + Tools/Source/TianoTools/Pccts/NOTES.bcc | 184 + Tools/Source/TianoTools/Pccts/NOTES.msvc | 189 + Tools/Source/TianoTools/Pccts/README | 159 + Tools/Source/TianoTools/Pccts/RIGHTS | 26 + .../Source/TianoTools/Pccts/antlr/AntlrMS.mak | 233 + .../TianoTools/Pccts/antlr/AntlrPPC.mak | 101 + Tools/Source/TianoTools/Pccts/antlr/README | 19 + Tools/Source/TianoTools/Pccts/antlr/antlr.1 | 209 + Tools/Source/TianoTools/Pccts/antlr/antlr.c | 3564 ++++++++++ Tools/Source/TianoTools/Pccts/antlr/antlr.g | 2586 ++++++++ Tools/Source/TianoTools/Pccts/antlr/antlr.r | 787 +++ .../Source/TianoTools/Pccts/antlr/antlr1.txt | 264 + Tools/Source/TianoTools/Pccts/antlr/bits.c | 1025 +++ Tools/Source/TianoTools/Pccts/antlr/build.c | 813 +++ Tools/Source/TianoTools/Pccts/antlr/build.xml | 144 + .../TianoTools/Pccts/antlr/dumpcycles.c | 67 + .../Source/TianoTools/Pccts/antlr/dumpnode.c | 423 ++ Tools/Source/TianoTools/Pccts/antlr/egman.c | 328 + Tools/Source/TianoTools/Pccts/antlr/err.c | 538 ++ Tools/Source/TianoTools/Pccts/antlr/fcache.c | 123 + Tools/Source/TianoTools/Pccts/antlr/fset.c | 1555 +++++ Tools/Source/TianoTools/Pccts/antlr/fset2.c | 2250 +++++++ Tools/Source/TianoTools/Pccts/antlr/gen.c | 4797 ++++++++++++++ Tools/Source/TianoTools/Pccts/antlr/generic.h | 286 + Tools/Source/TianoTools/Pccts/antlr/globals.c | 484 ++ Tools/Source/TianoTools/Pccts/antlr/hash.c | 221 + Tools/Source/TianoTools/Pccts/antlr/hash.h | 73 + Tools/Source/TianoTools/Pccts/antlr/lex.c | 878 +++ Tools/Source/TianoTools/Pccts/antlr/main.c | 1747 +++++ Tools/Source/TianoTools/Pccts/antlr/makefile | 218 + Tools/Source/TianoTools/Pccts/antlr/makefile1 | 96 + Tools/Source/TianoTools/Pccts/antlr/misc.c | 1864 ++++++ Tools/Source/TianoTools/Pccts/antlr/mode.h | 12 + Tools/Source/TianoTools/Pccts/antlr/mrhoist.c | 3030 +++++++++ .../Source/TianoTools/Pccts/antlr/parser.dlg | 1387 ++++ Tools/Source/TianoTools/Pccts/antlr/pred.c | 821 +++ Tools/Source/TianoTools/Pccts/antlr/proto.h | 852 +++ Tools/Source/TianoTools/Pccts/antlr/scan.c | 5735 +++++++++++++++++ .../Source/TianoTools/Pccts/antlr/stdpccts.h | 31 + Tools/Source/TianoTools/Pccts/antlr/syn.h | 390 ++ Tools/Source/TianoTools/Pccts/antlr/tokens.h | 246 + Tools/Source/TianoTools/Pccts/build.gcc | 2 + Tools/Source/TianoTools/Pccts/build.xml | 89 + Tools/Source/TianoTools/Pccts/dlg/DlgMS.mak | 121 + Tools/Source/TianoTools/Pccts/dlg/DlgPPC.mak | 84 + Tools/Source/TianoTools/Pccts/dlg/automata.c | 353 + Tools/Source/TianoTools/Pccts/dlg/build.xml | 145 + Tools/Source/TianoTools/Pccts/dlg/dlg.1 | 79 + Tools/Source/TianoTools/Pccts/dlg/dlg.h | 250 + Tools/Source/TianoTools/Pccts/dlg/dlg.r | 275 + Tools/Source/TianoTools/Pccts/dlg/dlg1.txt | 132 + Tools/Source/TianoTools/Pccts/dlg/dlg_a.c | 1414 ++++ Tools/Source/TianoTools/Pccts/dlg/dlg_p.c | 959 +++ Tools/Source/TianoTools/Pccts/dlg/dlg_p.g | 614 ++ Tools/Source/TianoTools/Pccts/dlg/err.c | 99 + Tools/Source/TianoTools/Pccts/dlg/main.c | 281 + Tools/Source/TianoTools/Pccts/dlg/makefile | 156 + Tools/Source/TianoTools/Pccts/dlg/makefile1 | 63 + Tools/Source/TianoTools/Pccts/dlg/mode.h | 4 + Tools/Source/TianoTools/Pccts/dlg/output.c | 850 +++ Tools/Source/TianoTools/Pccts/dlg/parser.dlg | 398 ++ Tools/Source/TianoTools/Pccts/dlg/relabel.c | 217 + Tools/Source/TianoTools/Pccts/dlg/stdpccts.h | 26 + Tools/Source/TianoTools/Pccts/dlg/support.c | 240 + Tools/Source/TianoTools/Pccts/dlg/tokens.h | 133 + Tools/Source/TianoTools/Pccts/h/AParser.cpp | 871 +++ Tools/Source/TianoTools/Pccts/h/AParser.h | 376 ++ Tools/Source/TianoTools/Pccts/h/ASTBase.cpp | 256 + Tools/Source/TianoTools/Pccts/h/ASTBase.h | 122 + Tools/Source/TianoTools/Pccts/h/ATokPtr.h | 88 + Tools/Source/TianoTools/Pccts/h/ATokPtrImpl.h | 88 + Tools/Source/TianoTools/Pccts/h/AToken.h | 325 + .../TianoTools/Pccts/h/ATokenBuffer.cpp | 374 ++ .../Source/TianoTools/Pccts/h/ATokenBuffer.h | 109 + .../Source/TianoTools/Pccts/h/ATokenStream.h | 51 + .../TianoTools/Pccts/h/BufFileInput.cpp | 100 + .../Source/TianoTools/Pccts/h/BufFileInput.h | 53 + .../TianoTools/Pccts/h/DLG_stream_input.h | 98 + Tools/Source/TianoTools/Pccts/h/DLexer.h | 191 + .../Source/TianoTools/Pccts/h/DLexerBase.cpp | 302 + Tools/Source/TianoTools/Pccts/h/DLexerBase.h | 198 + Tools/Source/TianoTools/Pccts/h/PBlackBox.h | 134 + Tools/Source/TianoTools/Pccts/h/PCCTSAST.cpp | 684 ++ Tools/Source/TianoTools/Pccts/h/PCCTSAST.h | 143 + Tools/Source/TianoTools/Pccts/h/SList.h | 72 + Tools/Source/TianoTools/Pccts/h/antlr.h | 807 +++ Tools/Source/TianoTools/Pccts/h/ast.c | 345 + Tools/Source/TianoTools/Pccts/h/ast.h | 121 + Tools/Source/TianoTools/Pccts/h/charbuf.h | 46 + Tools/Source/TianoTools/Pccts/h/charptr.c | 58 + Tools/Source/TianoTools/Pccts/h/charptr.h | 48 + Tools/Source/TianoTools/Pccts/h/config.h | 1 + Tools/Source/TianoTools/Pccts/h/dlgauto.h | 504 ++ Tools/Source/TianoTools/Pccts/h/dlgdef.h | 128 + Tools/Source/TianoTools/Pccts/h/err.h | 1170 ++++ Tools/Source/TianoTools/Pccts/h/int.h | 37 + .../Source/TianoTools/Pccts/h/pccts_assert.h | 10 + .../TianoTools/Pccts/h/pccts_iostream.h | 10 + .../Source/TianoTools/Pccts/h/pccts_istream.h | 10 + .../Source/TianoTools/Pccts/h/pccts_setjmp.h | 10 + .../Source/TianoTools/Pccts/h/pccts_stdarg.h | 10 + Tools/Source/TianoTools/Pccts/h/pccts_stdio.h | 10 + .../Source/TianoTools/Pccts/h/pccts_stdlib.h | 10 + .../Source/TianoTools/Pccts/h/pccts_string.h | 10 + Tools/Source/TianoTools/Pccts/h/pcctscfg.h | 359 ++ Tools/Source/TianoTools/Pccts/h/pcnames.bat | 11 + Tools/Source/TianoTools/Pccts/h/slist.cpp | 116 + Tools/Source/TianoTools/Pccts/history.ps | 473 ++ Tools/Source/TianoTools/Pccts/history.txt | 186 + Tools/Source/TianoTools/Pccts/makefile | 66 + .../TianoTools/Pccts/support/genmk/genmk.c | 1063 +++ .../Pccts/support/genmk/genmk_old.c | 762 +++ .../TianoTools/Pccts/support/genmk/makefile | 29 + .../TianoTools/Pccts/support/rexpr/makefile | 19 + .../TianoTools/Pccts/support/rexpr/rexpr.c | 586 ++ .../TianoTools/Pccts/support/rexpr/rexpr.h | 30 + .../TianoTools/Pccts/support/rexpr/test.c | 19 + .../Source/TianoTools/Pccts/support/set/set.c | 816 +++ .../Source/TianoTools/Pccts/support/set/set.h | 121 + .../Source/TianoTools/Pccts/support/sym/sym.c | 402 ++ .../TianoTools/Pccts/support/sym/template.h | 41 + Tools/Source/TianoTools/SetStamp/SetStamp.c | 475 ++ Tools/Source/TianoTools/SetStamp/build.gcc | 2 + Tools/Source/TianoTools/SetStamp/build.xml | 117 + Tools/Source/TianoTools/StrGather/StrGather.c | 2531 ++++++++ Tools/Source/TianoTools/StrGather/StrGather.h | 84 + Tools/Source/TianoTools/StrGather/StringDB.c | 2751 ++++++++ Tools/Source/TianoTools/StrGather/StringDB.h | 136 + Tools/Source/TianoTools/StrGather/build.gcc | 1 + Tools/Source/TianoTools/StrGather/build.xml | 119 + Tools/Source/TianoTools/VfrCompile/EfiVfr.h | 181 + .../Source/TianoTools/VfrCompile/VfrCompile.g | 3527 ++++++++++ .../TianoTools/VfrCompile/VfrServices.cpp | 757 +++ .../TianoTools/VfrCompile/VfrServices.h | 227 + Tools/Source/TianoTools/VfrCompile/build.gcc | 10 + Tools/Source/TianoTools/VfrCompile/build.xml | 142 + Tools/Source/TianoTools/build.xml | 96 + Tools/Source/Tools.msa | 72 + Tools/ToolResources.msa | 58 + Tools/Tools.spd | 38 + Tools/XMLSchema/FDPManifest.xsd | 376 ++ Tools/XMLSchema/FrameworkDataElements.xsd | 1479 +++++ Tools/XMLSchema/FrameworkDataTypes.xsd | 1196 ++++ Tools/XMLSchema/FrameworkHeaders.xsd | 160 + .../FrameworkPlatformDataElements.xsd | 357 + Tools/XMLSchema/NamingConvention.xsd | 307 + Tools/XMLSchema/SurfaceArea.xsd | 167 + Tools/XMLSchema/SurfaceArea.xsdconfig | 16 + Tools/bin/CreateMdkPkg.bat | 42 + Tools/bin/GenBuildFile.bat | 45 + Tools/bin/GenBuildFile.xml | 18 + Tools/bin/MakeDeps.exe | Bin 0 -> 77824 bytes Tools/bin/PackageEditor.bat | 47 + Tools/bin/SABeans.bat | 54 + Tools/bin/SACreate.bat | 51 + Tools/bin/SAPretty.bat | 45 + Tools/bin/SAVerify.bat | 55 + Tools/build.xml | 90 + build.xml | 36 + edksetup.bat | 88 + edksetup.sh | 42 + 2651 files changed, 624620 insertions(+) create mode 100644 DeveloperManual.doc create mode 100644 EdkFatBinPkg/EdkFatBinPkg.spd create mode 100644 EdkFatBinPkg/Fat.mbd create mode 100644 EdkFatBinPkg/Fat.msa create mode 100644 EdkFatBinPkg/Fat_build.xml create mode 100644 EdkFatBinPkg/Ia32/Fat.FFS create mode 100644 EdkFatBinPkg/Ipf/Fat.FFS create mode 100644 EdkFatBinPkg/X64/Fat.FFS create mode 100644 EdkFatBinPkg/build.xml create mode 100644 EdkFatBinPkg/genbuildfile.xml create mode 100644 EdkModulePkg/Application/HelloWorld/HelloWorld.c create mode 100644 EdkModulePkg/Application/HelloWorld/HelloWorld.mbd create mode 100644 EdkModulePkg/Application/HelloWorld/HelloWorld.msa create mode 100644 EdkModulePkg/Application/HelloWorld/build.xml create mode 100644 EdkModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.c create mode 100644 EdkModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.h create mode 100644 EdkModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.mbd create mode 100644 EdkModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.msa create mode 100644 EdkModulePkg/Bus/Pci/AtapiPassThru/Dxe/ComponentName.c create mode 100644 EdkModulePkg/Bus/Pci/AtapiPassThru/Dxe/build.xml create mode 100644 EdkModulePkg/Bus/Pci/CirrusLogic/Dxe/CirrusLogic5430.c create mode 100644 EdkModulePkg/Bus/Pci/CirrusLogic/Dxe/CirrusLogic5430.h create mode 100644 EdkModulePkg/Bus/Pci/CirrusLogic/Dxe/CirrusLogic5430.mbd create mode 100644 EdkModulePkg/Bus/Pci/CirrusLogic/Dxe/CirrusLogic5430.msa create mode 100644 EdkModulePkg/Bus/Pci/CirrusLogic/Dxe/CirrusLogic5430UgaDraw.c create mode 100644 EdkModulePkg/Bus/Pci/CirrusLogic/Dxe/ComponentName.c create mode 100644 EdkModulePkg/Bus/Pci/CirrusLogic/Dxe/build.xml create mode 100644 EdkModulePkg/Bus/Pci/IdeBus/Dxe/ComponentName.c create mode 100644 EdkModulePkg/Bus/Pci/IdeBus/Dxe/ComponentName.h create mode 100644 EdkModulePkg/Bus/Pci/IdeBus/Dxe/DriverConfiguration.c create mode 100644 EdkModulePkg/Bus/Pci/IdeBus/Dxe/DriverDiagnostics.c create mode 100644 EdkModulePkg/Bus/Pci/IdeBus/Dxe/ata.c create mode 100644 EdkModulePkg/Bus/Pci/IdeBus/Dxe/atapi.c create mode 100644 EdkModulePkg/Bus/Pci/IdeBus/Dxe/build.xml create mode 100644 EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.c create mode 100644 EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.h create mode 100644 EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.c create mode 100644 EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.h create mode 100644 EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.mbd create mode 100644 EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.msa create mode 100644 EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebusLite.mbd create mode 100644 EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebusLite.msa create mode 100644 EdkModulePkg/Bus/Pci/IdeBus/Dxe/idedata.h create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/ComponentName.c create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/ComponentName.h create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/LightPciBus.mbd create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/LightPciBus.msa create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/LightPciLib.c create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/PciBus.mbd create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/PciBus.msa create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/PciBusLite.mbd create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/PciBusLite.msa create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/PciCommand.c create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/PciCommand.h create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/PciDeviceSupport.c create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/PciDeviceSupport.h create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/PciDriverOverride.c create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/PciDriverOverride.h create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/PciEnumerator.c create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/PciEnumerator.h create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/PciEnumeratorSupport.c create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/PciEnumeratorSupport.h create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/PciHotPlugSupport.c create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/PciHotPlugSupport.h create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/PciIo.c create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/PciIo.h create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/PciLib.c create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/PciLib.h create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/PciOptionRomSupport.c create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/PciOptionRomSupport.h create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/PciPowerManagement.c create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/PciPowerManagement.h create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/PciResourceSupport.c create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/PciResourceSupport.h create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/PciRomTable.c create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/PciRomTable.h create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/build.xml create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/pcibus.c create mode 100644 EdkModulePkg/Bus/Pci/PciBus/Dxe/pcibus.h create mode 100644 EdkModulePkg/Bus/Pci/Uhci/Dxe/ComponentName.c create mode 100644 EdkModulePkg/Bus/Pci/Uhci/Dxe/Uhci.mbd create mode 100644 EdkModulePkg/Bus/Pci/Uhci/Dxe/Uhci.msa create mode 100644 EdkModulePkg/Bus/Pci/Uhci/Dxe/build.xml create mode 100644 EdkModulePkg/Bus/Pci/Uhci/Dxe/uhchlp.c create mode 100644 EdkModulePkg/Bus/Pci/Uhci/Dxe/uhci.c create mode 100644 EdkModulePkg/Bus/Pci/Uhci/Dxe/uhci.h create mode 100644 EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/Decode.c create mode 100644 EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/E100b.c create mode 100644 EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/E100b.h create mode 100644 EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/Init.c create mode 100644 EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/Undi.mbd create mode 100644 EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/Undi.msa create mode 100644 EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/Undi32.h create mode 100644 EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/build.xml create mode 100644 EdkModulePkg/Bus/Scsi/ScsiBus/Dxe/ComponentName.c create mode 100644 EdkModulePkg/Bus/Scsi/ScsiBus/Dxe/ScsiBus.c create mode 100644 EdkModulePkg/Bus/Scsi/ScsiBus/Dxe/ScsiBus.h create mode 100644 EdkModulePkg/Bus/Scsi/ScsiBus/Dxe/ScsiBus.mbd create mode 100644 EdkModulePkg/Bus/Scsi/ScsiBus/Dxe/ScsiBus.msa create mode 100644 EdkModulePkg/Bus/Scsi/ScsiBus/Dxe/build.xml create mode 100644 EdkModulePkg/Bus/Scsi/ScsiDisk/Dxe/ComponentName.c create mode 100644 EdkModulePkg/Bus/Scsi/ScsiDisk/Dxe/ScsiDisk.c create mode 100644 EdkModulePkg/Bus/Scsi/ScsiDisk/Dxe/ScsiDisk.h create mode 100644 EdkModulePkg/Bus/Scsi/ScsiDisk/Dxe/ScsiDisk.mbd create mode 100644 EdkModulePkg/Bus/Scsi/ScsiDisk/Dxe/ScsiDisk.msa create mode 100644 EdkModulePkg/Bus/Scsi/ScsiDisk/Dxe/build.xml create mode 100644 EdkModulePkg/Bus/Usb/UsbBot/Dxe/ComponentName.c create mode 100644 EdkModulePkg/Bus/Usb/UsbBot/Dxe/UsbBot.mbd create mode 100644 EdkModulePkg/Bus/Usb/UsbBot/Dxe/UsbBot.msa create mode 100644 EdkModulePkg/Bus/Usb/UsbBot/Dxe/bot.c create mode 100644 EdkModulePkg/Bus/Usb/UsbBot/Dxe/bot.h create mode 100644 EdkModulePkg/Bus/Usb/UsbBot/Dxe/build.xml create mode 100644 EdkModulePkg/Bus/Usb/UsbBus/Dxe/ComponentName.c create mode 100644 EdkModulePkg/Bus/Usb/UsbBus/Dxe/UsbBus.mbd create mode 100644 EdkModulePkg/Bus/Usb/UsbBus/Dxe/UsbBus.msa create mode 100644 EdkModulePkg/Bus/Usb/UsbBus/Dxe/build.xml create mode 100644 EdkModulePkg/Bus/Usb/UsbBus/Dxe/hub.c create mode 100644 EdkModulePkg/Bus/Usb/UsbBus/Dxe/hub.h create mode 100644 EdkModulePkg/Bus/Usb/UsbBus/Dxe/usb.c create mode 100644 EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbbus.c create mode 100644 EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbbus.h create mode 100644 EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbio.c create mode 100644 EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbutil.c create mode 100644 EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbutil.h create mode 100644 EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/Cbi0.c create mode 100644 EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/ComponentName.c create mode 100644 EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/UsbCbi0.mbd create mode 100644 EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/UsbCbi0.msa create mode 100644 EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/build.xml create mode 100644 EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/UsbCbi1.mbd create mode 100644 EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/UsbCbi1.msa create mode 100644 EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/build.xml create mode 100644 EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/cbi1.c create mode 100644 EdkModulePkg/Bus/Usb/UsbCbi/Dxe/cbi.h create mode 100644 EdkModulePkg/Bus/Usb/UsbKb/Dxe/ComponentName.c create mode 100644 EdkModulePkg/Bus/Usb/UsbKb/Dxe/UsbKb.mbd create mode 100644 EdkModulePkg/Bus/Usb/UsbKb/Dxe/UsbKb.msa create mode 100644 EdkModulePkg/Bus/Usb/UsbKb/Dxe/build.xml create mode 100644 EdkModulePkg/Bus/Usb/UsbKb/Dxe/efikey.c create mode 100644 EdkModulePkg/Bus/Usb/UsbKb/Dxe/efikey.h create mode 100644 EdkModulePkg/Bus/Usb/UsbKb/Dxe/keyboard.c create mode 100644 EdkModulePkg/Bus/Usb/UsbKb/Dxe/keyboard.h create mode 100644 EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/ComponentName.c create mode 100644 EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.c create mode 100644 EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.h create mode 100644 EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.mbd create mode 100644 EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.msa create mode 100644 EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorageData.h create mode 100644 EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorageHelper.c create mode 100644 EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorageHelper.h create mode 100644 EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/build.xml create mode 100644 EdkModulePkg/Bus/Usb/UsbMouse/Dxe/ComponentName.c create mode 100644 EdkModulePkg/Bus/Usb/UsbMouse/Dxe/UsbMouse.mbd create mode 100644 EdkModulePkg/Bus/Usb/UsbMouse/Dxe/UsbMouse.msa create mode 100644 EdkModulePkg/Bus/Usb/UsbMouse/Dxe/build.xml create mode 100644 EdkModulePkg/Bus/Usb/UsbMouse/Dxe/mousehid.c create mode 100644 EdkModulePkg/Bus/Usb/UsbMouse/Dxe/mousehid.h create mode 100644 EdkModulePkg/Bus/Usb/UsbMouse/Dxe/usbmouse.c create mode 100644 EdkModulePkg/Bus/Usb/UsbMouse/Dxe/usbmouse.h create mode 100644 EdkModulePkg/Core/Dxe/DebugImageInfo.h create mode 100644 EdkModulePkg/Core/Dxe/Dispatcher/Dispatcher.c create mode 100644 EdkModulePkg/Core/Dxe/Dispatcher/dependency.c create mode 100644 EdkModulePkg/Core/Dxe/DxeMain.h create mode 100644 EdkModulePkg/Core/Dxe/DxeMain.mbd create mode 100644 EdkModulePkg/Core/Dxe/DxeMain.msa create mode 100644 EdkModulePkg/Core/Dxe/DxeMain/DxeMain.c create mode 100644 EdkModulePkg/Core/Dxe/DxeMain/DxeProtocolNotify.c create mode 100644 EdkModulePkg/Core/Dxe/Event/event.c create mode 100644 EdkModulePkg/Core/Dxe/Event/execdata.c create mode 100644 EdkModulePkg/Core/Dxe/Event/timer.c create mode 100644 EdkModulePkg/Core/Dxe/Event/tpl.c create mode 100644 EdkModulePkg/Core/Dxe/FwVol/Ffs.c create mode 100644 EdkModulePkg/Core/Dxe/FwVol/FwVol.c create mode 100644 EdkModulePkg/Core/Dxe/FwVol/FwVolAttrib.c create mode 100644 EdkModulePkg/Core/Dxe/FwVol/FwVolRead.c create mode 100644 EdkModulePkg/Core/Dxe/FwVol/FwVolWrite.c create mode 100644 EdkModulePkg/Core/Dxe/FwVolBlock.h create mode 100644 EdkModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.c create mode 100644 EdkModulePkg/Core/Dxe/FwVolDriver.h create mode 100644 EdkModulePkg/Core/Dxe/Gcd/gcd.c create mode 100644 EdkModulePkg/Core/Dxe/Hand/DriverSupport.c create mode 100644 EdkModulePkg/Core/Dxe/Hand/Notify.c create mode 100644 EdkModulePkg/Core/Dxe/Hand/handle.c create mode 100644 EdkModulePkg/Core/Dxe/Hand/locate.c create mode 100644 EdkModulePkg/Core/Dxe/Image.h create mode 100644 EdkModulePkg/Core/Dxe/Image/Image.c create mode 100644 EdkModulePkg/Core/Dxe/Image/ImageFile.c create mode 100644 EdkModulePkg/Core/Dxe/Library.h create mode 100644 EdkModulePkg/Core/Dxe/Library/Library.c create mode 100644 EdkModulePkg/Core/Dxe/Mem/Page.c create mode 100644 EdkModulePkg/Core/Dxe/Mem/memdata.c create mode 100644 EdkModulePkg/Core/Dxe/Mem/pool.c create mode 100644 EdkModulePkg/Core/Dxe/Misc/DebugImageInfo.c create mode 100644 EdkModulePkg/Core/Dxe/Misc/InstallConfigurationTable.c create mode 100644 EdkModulePkg/Core/Dxe/Misc/SetWatchdogTimer.c create mode 100644 EdkModulePkg/Core/Dxe/Misc/Stall.c create mode 100644 EdkModulePkg/Core/Dxe/SectionExtraction/CoreSectionExtraction.c create mode 100644 EdkModulePkg/Core/Dxe/build.xml create mode 100644 EdkModulePkg/Core/Dxe/exec.h create mode 100644 EdkModulePkg/Core/Dxe/gcd.h create mode 100644 EdkModulePkg/Core/Dxe/hand.h create mode 100644 EdkModulePkg/Core/Dxe/imem.h create mode 100644 EdkModulePkg/Core/DxeIplPeim/DxeIpl.dxs create mode 100644 EdkModulePkg/Core/DxeIplPeim/DxeIpl.h create mode 100644 EdkModulePkg/Core/DxeIplPeim/DxeIpl.mbd create mode 100644 EdkModulePkg/Core/DxeIplPeim/DxeIpl.msa create mode 100644 EdkModulePkg/Core/DxeIplPeim/DxeIplX64.mbd create mode 100644 EdkModulePkg/Core/DxeIplPeim/DxeIplX64.msa create mode 100644 EdkModulePkg/Core/DxeIplPeim/DxeLoad.c create mode 100644 EdkModulePkg/Core/DxeIplPeim/DxeLoadX64.c create mode 100644 EdkModulePkg/Core/DxeIplPeim/Ipf/DxeLoadFunc.c create mode 100644 EdkModulePkg/Core/DxeIplPeim/Ipf/ImageRead.c create mode 100644 EdkModulePkg/Core/DxeIplPeim/build.xml create mode 100644 EdkModulePkg/Core/DxeIplPeim/build_X64.xml create mode 100644 EdkModulePkg/Core/DxeIplPeim/ia32/DxeLoadFunc.c create mode 100644 EdkModulePkg/Core/DxeIplPeim/ia32/ImageRead.c create mode 100644 EdkModulePkg/Core/DxeIplPeim/x64/DxeLoadFunc.c create mode 100644 EdkModulePkg/Core/DxeIplPeim/x64/ImageRead.c create mode 100644 EdkModulePkg/Core/DxeIplPeim/x64/LongMode.asm create mode 100644 EdkModulePkg/Core/DxeIplPeim/x64/VirtualMemory.c create mode 100644 EdkModulePkg/Core/DxeIplPeim/x64/VirtualMemory.h create mode 100644 EdkModulePkg/Core/Pei/BootMode/BootMode.c create mode 100644 EdkModulePkg/Core/Pei/Dependency/dependency.c create mode 100644 EdkModulePkg/Core/Pei/Dependency/dependency.h create mode 100644 EdkModulePkg/Core/Pei/Dispatcher/Dispatcher.c create mode 100644 EdkModulePkg/Core/Pei/FwVol/FwVol.c create mode 100644 EdkModulePkg/Core/Pei/Hob/Hob.c create mode 100644 EdkModulePkg/Core/Pei/Image/Image.c create mode 100644 EdkModulePkg/Core/Pei/Ipf/IpfCpuCore.i create mode 100644 EdkModulePkg/Core/Pei/Ipf/IpfCpuCore.s create mode 100644 EdkModulePkg/Core/Pei/Ipf/SwitchToCacheMode.c create mode 100644 EdkModulePkg/Core/Pei/Memory/MemoryServices.c create mode 100644 EdkModulePkg/Core/Pei/PeiMain.h create mode 100644 EdkModulePkg/Core/Pei/PeiMain.mbd create mode 100644 EdkModulePkg/Core/Pei/PeiMain.msa create mode 100644 EdkModulePkg/Core/Pei/PeiMain/PeiMain.c create mode 100644 EdkModulePkg/Core/Pei/Ppi/Ppi.c create mode 100644 EdkModulePkg/Core/Pei/Reset/Reset.c create mode 100644 EdkModulePkg/Core/Pei/Security/Security.c create mode 100644 EdkModulePkg/Core/Pei/StatusCode/StatusCode.c create mode 100644 EdkModulePkg/Core/Pei/build.xml create mode 100644 EdkModulePkg/EdkModulePkg.fpd create mode 100644 EdkModulePkg/EdkModulePkg.spd create mode 100644 EdkModulePkg/Include/Common/CapsuleName.h create mode 100644 EdkModulePkg/Include/Common/DecompressLibraryHob.h create mode 100644 EdkModulePkg/Include/Common/FlashMap.h create mode 100644 EdkModulePkg/Include/Common/Variable.h create mode 100644 EdkModulePkg/Include/Common/WorkingBlockHeader.h create mode 100644 EdkModulePkg/Include/EdkDxe.h create mode 100644 EdkModulePkg/Include/EdkDxeCore.h create mode 100644 EdkModulePkg/Include/EdkDxeDepex.h create mode 100644 EdkModulePkg/Include/EdkPeiCore.h create mode 100644 EdkModulePkg/Include/EdkPeim.h create mode 100644 EdkModulePkg/Include/EdkPeimDepex.h create mode 100644 EdkModulePkg/Include/Guid/AlternateFvBlock.h create mode 100644 EdkModulePkg/Include/Guid/Bmp.h create mode 100644 EdkModulePkg/Include/Guid/BootState.h create mode 100644 EdkModulePkg/Include/Guid/CapsuleVendor.h create mode 100644 EdkModulePkg/Include/Guid/CompatibleMemoryTested.h create mode 100644 EdkModulePkg/Include/Guid/ConsoleInDevice.h create mode 100644 EdkModulePkg/Include/Guid/ConsoleOutDevice.h create mode 100644 EdkModulePkg/Include/Guid/ExtendedSalGuid.h create mode 100644 EdkModulePkg/Include/Guid/FlashMapHob.h create mode 100644 EdkModulePkg/Include/Guid/HotPlugDevice.h create mode 100644 EdkModulePkg/Include/Guid/MemoryTypeInformation.h create mode 100644 EdkModulePkg/Include/Guid/MiniShellFile.h create mode 100644 EdkModulePkg/Include/Guid/PciHotplugDevice.h create mode 100644 EdkModulePkg/Include/Guid/PciOptionRomTable.h create mode 100644 EdkModulePkg/Include/Guid/PeiPeCoffLoader.h create mode 100644 EdkModulePkg/Include/Guid/PeiPerformanceHob.h create mode 100644 EdkModulePkg/Include/Guid/PrimaryConsoleInDevice.h create mode 100644 EdkModulePkg/Include/Guid/PrimaryConsoleOutDevice.h create mode 100644 EdkModulePkg/Include/Guid/PrimaryStandardErrorDevice.h create mode 100644 EdkModulePkg/Include/Guid/ShellFile.h create mode 100644 EdkModulePkg/Include/Guid/StandardErrorDevice.h create mode 100644 EdkModulePkg/Include/Guid/StatusCode.h create mode 100644 EdkModulePkg/Include/Guid/StatusCodeCallerId.h create mode 100644 EdkModulePkg/Include/Guid/SystemNvDataGuid.h create mode 100644 EdkModulePkg/Include/Library/CustomDecompressLib.h create mode 100644 EdkModulePkg/Include/Library/EdkBsDataHubStatusCodeLib.h create mode 100644 EdkModulePkg/Include/Library/EdkDxeSalLib.h create mode 100644 EdkModulePkg/Include/Library/EdkFvbServiceLib.h create mode 100644 EdkModulePkg/Include/Library/EdkGraphicsLib.h create mode 100644 EdkModulePkg/Include/Library/EdkIfrSupportLib.h create mode 100644 EdkModulePkg/Include/Library/EdkMemoryStatusCodeLib.h create mode 100644 EdkModulePkg/Include/Library/EdkPeCoffLoaderLib.h create mode 100644 EdkModulePkg/Include/Library/EdkPeCoffLoaderX64Lib.h create mode 100644 EdkModulePkg/Include/Library/EdkRtMemoryStatusCodeLib.h create mode 100644 EdkModulePkg/Include/Library/EdkRtPlatformStatusCodeLib.h create mode 100644 EdkModulePkg/Include/Library/EdkScsiLib.h create mode 100644 EdkModulePkg/Include/Library/EdkUsbLib.h create mode 100644 EdkModulePkg/Include/Library/TianoDecompressLib.h create mode 100644 EdkModulePkg/Include/Ppi/BaseMemoryTest.h create mode 100644 EdkModulePkg/Include/Ppi/FlashMap.h create mode 100644 EdkModulePkg/Include/Ppi/PeiInMemory.h create mode 100644 EdkModulePkg/Include/Ppi/StatusCodeMemory.h create mode 100644 EdkModulePkg/Include/Protocol/AcpiS3Save.h create mode 100644 EdkModulePkg/Include/Protocol/ConsoleControl.h create mode 100644 EdkModulePkg/Include/Protocol/CustomizedDecompress.h create mode 100644 EdkModulePkg/Include/Protocol/DebugAssert.h create mode 100644 EdkModulePkg/Include/Protocol/DebugLevel.h create mode 100644 EdkModulePkg/Include/Protocol/DiskInfo.h create mode 100644 EdkModulePkg/Include/Protocol/EdkDecompress.h create mode 100644 EdkModulePkg/Include/Protocol/ExtendedSalBootService.h create mode 100644 EdkModulePkg/Include/Protocol/FaultTolerantWriteLite.h create mode 100644 EdkModulePkg/Include/Protocol/FvbExtension.h create mode 100644 EdkModulePkg/Include/Protocol/GenericMemoryTest.h create mode 100644 EdkModulePkg/Include/Protocol/IsaAcpi.h create mode 100644 EdkModulePkg/Include/Protocol/IsaIo.h create mode 100644 EdkModulePkg/Include/Protocol/LoadPe32Image.h create mode 100644 EdkModulePkg/Include/Protocol/OEMBadging.h create mode 100644 EdkModulePkg/Include/Protocol/PciHotPlugRequest.h create mode 100644 EdkModulePkg/Include/Protocol/Performance.h create mode 100644 EdkModulePkg/Include/Protocol/Print.h create mode 100644 EdkModulePkg/Include/Protocol/PxeDhcp4.h create mode 100644 EdkModulePkg/Include/Protocol/PxeDhcp4CallBack.h create mode 100644 EdkModulePkg/Include/Protocol/ScsiIo.h create mode 100644 EdkModulePkg/Include/Protocol/SecurityPolicy.h create mode 100644 EdkModulePkg/Include/Protocol/UgaIo.h create mode 100644 EdkModulePkg/Include/Protocol/UgaSplash.h create mode 100644 EdkModulePkg/Include/Protocol/usbatapi.h create mode 100644 EdkModulePkg/Library/BaseCustomDecompressLibNull/BaseCustomDecompressLibNull.c create mode 100644 EdkModulePkg/Library/BaseCustomDecompressLibNull/BaseCustomDecompressLibNull.mbd create mode 100644 EdkModulePkg/Library/BaseCustomDecompressLibNull/BaseCustomDecompressLibNull.msa create mode 100644 EdkModulePkg/Library/BaseCustomDecompressLibNull/build.xml create mode 100644 EdkModulePkg/Library/BaseUefiTianoDecompressLib/BaseUefiTianoDecompressLib.c create mode 100644 EdkModulePkg/Library/BaseUefiTianoDecompressLib/BaseUefiTianoDecompressLib.mbd create mode 100644 EdkModulePkg/Library/BaseUefiTianoDecompressLib/BaseUefiTianoDecompressLib.msa create mode 100644 EdkModulePkg/Library/BaseUefiTianoDecompressLib/build.xml create mode 100644 EdkModulePkg/Library/DxeCoreCustomDecompressLibFromHob/DxeCoreCustomDecompressLibFromHob.c create mode 100644 EdkModulePkg/Library/DxeCoreCustomDecompressLibFromHob/DxeCoreCustomDecompressLibFromHob.mbd create mode 100644 EdkModulePkg/Library/DxeCoreCustomDecompressLibFromHob/DxeCoreCustomDecompressLibFromHob.msa create mode 100644 EdkModulePkg/Library/DxeCoreCustomDecompressLibFromHob/build.xml create mode 100644 EdkModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c create mode 100644 EdkModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.mbd create mode 100644 EdkModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.msa create mode 100644 EdkModulePkg/Library/DxeCorePerformanceLib/build.xml create mode 100644 EdkModulePkg/Library/DxeCoreTianoDecompressLibFromHob/DxeCoreTianoDecompressLibFromHob.c create mode 100644 EdkModulePkg/Library/DxeCoreTianoDecompressLibFromHob/DxeCoreTianoDecompressLibFromHob.mbd create mode 100644 EdkModulePkg/Library/DxeCoreTianoDecompressLibFromHob/DxeCoreTianoDecompressLibFromHob.msa create mode 100644 EdkModulePkg/Library/DxeCoreTianoDecompressLibFromHob/build.xml create mode 100644 EdkModulePkg/Library/DxeCoreUefiDecompressLibFromHob/DxeCoreUefiDecompressLibFromHob.c create mode 100644 EdkModulePkg/Library/DxeCoreUefiDecompressLibFromHob/DxeCoreUefiDecompressLibFromHob.mbd create mode 100644 EdkModulePkg/Library/DxeCoreUefiDecompressLibFromHob/DxeCoreUefiDecompressLibFromHob.msa create mode 100644 EdkModulePkg/Library/DxeCoreUefiDecompressLibFromHob/build.xml create mode 100644 EdkModulePkg/Library/EdkDxeDebugLibReportStatusCode/DebugLib.c create mode 100644 EdkModulePkg/Library/EdkDxeDebugLibReportStatusCode/EdkDxeDebugLibReportStatusCode.mbd create mode 100644 EdkModulePkg/Library/EdkDxeDebugLibReportStatusCode/EdkDxeDebugLibReportStatusCode.msa create mode 100644 EdkModulePkg/Library/EdkDxeDebugLibReportStatusCode/build.xml create mode 100644 EdkModulePkg/Library/EdkDxePeCoffLoaderFromHobLib/EdkDxePeCoffLoaderFromHobLib.mbd create mode 100644 EdkModulePkg/Library/EdkDxePeCoffLoaderFromHobLib/EdkDxePeCoffLoaderFromHobLib.msa create mode 100644 EdkModulePkg/Library/EdkDxePeCoffLoaderFromHobLib/PeCoff.c create mode 100644 EdkModulePkg/Library/EdkDxePeCoffLoaderFromHobLib/build.xml create mode 100644 EdkModulePkg/Library/EdkDxePerformanceLib/DxePerformanceLib.c create mode 100644 EdkModulePkg/Library/EdkDxePerformanceLib/EdkDxePerformanceLib.mbd create mode 100644 EdkModulePkg/Library/EdkDxePerformanceLib/EdkDxePerformanceLib.msa create mode 100644 EdkModulePkg/Library/EdkDxePerformanceLib/build.xml create mode 100644 EdkModulePkg/Library/EdkDxePrintLib/EdkDxePrintLib.mbd create mode 100644 EdkModulePkg/Library/EdkDxePrintLib/EdkDxePrintLib.msa create mode 100644 EdkModulePkg/Library/EdkDxePrintLib/PrintLib.c create mode 100644 EdkModulePkg/Library/EdkDxePrintLib/build.xml create mode 100644 EdkModulePkg/Library/EdkDxeRuntimeDriverLib/Common/RuntimeLib.c create mode 100644 EdkModulePkg/Library/EdkDxeRuntimeDriverLib/Common/RuntimeService.c create mode 100644 EdkModulePkg/Library/EdkDxeRuntimeDriverLib/EdkDxeRuntimeDriverLib.mbd create mode 100644 EdkModulePkg/Library/EdkDxeRuntimeDriverLib/EdkDxeRuntimeDriverLib.msa create mode 100644 EdkModulePkg/Library/EdkDxeRuntimeDriverLib/Ipf/RuntimeLib.c create mode 100644 EdkModulePkg/Library/EdkDxeRuntimeDriverLib/Ipf/RuntimeService.c create mode 100644 EdkModulePkg/Library/EdkDxeRuntimeDriverLib/RuntimeLibInternal.h create mode 100644 EdkModulePkg/Library/EdkDxeRuntimeDriverLib/build.xml create mode 100644 EdkModulePkg/Library/EdkDxeSalLib/EdkDxeSalLib.mbd create mode 100644 EdkModulePkg/Library/EdkDxeSalLib/EdkDxeSalLib.msa create mode 100644 EdkModulePkg/Library/EdkDxeSalLib/Ipf/AsmEsalServiceLib.s create mode 100644 EdkModulePkg/Library/EdkDxeSalLib/Ipf/AsmIpfCpuCache.s create mode 100644 EdkModulePkg/Library/EdkDxeSalLib/Ipf/EsalServiceLib.c create mode 100644 EdkModulePkg/Library/EdkDxeSalLib/build.xml create mode 100644 EdkModulePkg/Library/EdkFvbServiceLib/EdkFvbServiceLib.mbd create mode 100644 EdkModulePkg/Library/EdkFvbServiceLib/EdkFvbServiceLib.msa create mode 100644 EdkModulePkg/Library/EdkFvbServiceLib/Fvb.h create mode 100644 EdkModulePkg/Library/EdkFvbServiceLib/Ia32/Fvb.c create mode 100644 EdkModulePkg/Library/EdkFvbServiceLib/Ipf/Fvb.c create mode 100644 EdkModulePkg/Library/EdkFvbServiceLib/build.xml create mode 100644 EdkModulePkg/Library/EdkFvbServiceLib/x64/Fvb.c create mode 100644 EdkModulePkg/Library/EdkGraphicsLib/EdkGraphicsLib.mbd create mode 100644 EdkModulePkg/Library/EdkGraphicsLib/EdkGraphicsLib.msa create mode 100644 EdkModulePkg/Library/EdkGraphicsLib/Graphics.c create mode 100644 EdkModulePkg/Library/EdkGraphicsLib/build.xml create mode 100644 EdkModulePkg/Library/EdkIfrSupportLib/EdkIfrSupportLib.mbd create mode 100644 EdkModulePkg/Library/EdkIfrSupportLib/EdkIfrSupportLib.msa create mode 100644 EdkModulePkg/Library/EdkIfrSupportLib/IfrCommon.c create mode 100644 EdkModulePkg/Library/EdkIfrSupportLib/IfrOnTheFly.c create mode 100644 EdkModulePkg/Library/EdkIfrSupportLib/IfrOpCodeCreation.c create mode 100644 EdkModulePkg/Library/EdkIfrSupportLib/IfrVariable.c create mode 100644 EdkModulePkg/Library/EdkIfrSupportLib/build.xml create mode 100644 EdkModulePkg/Library/EdkMemoryStatusCodeLib/EdkMemoryStatusCodeLib.mbd create mode 100644 EdkModulePkg/Library/EdkMemoryStatusCodeLib/EdkMemoryStatusCodeLib.msa create mode 100644 EdkModulePkg/Library/EdkMemoryStatusCodeLib/MemoryStatusCode.c create mode 100644 EdkModulePkg/Library/EdkMemoryStatusCodeLib/MemoryStatusCode.h create mode 100644 EdkModulePkg/Library/EdkMemoryStatusCodeLib/build.xml create mode 100644 EdkModulePkg/Library/EdkNullCustomizedDecompressLib/CustomizedDecompress.c create mode 100644 EdkModulePkg/Library/EdkNullCustomizedDecompressLib/CustomizedDecompress.h create mode 100644 EdkModulePkg/Library/EdkNullCustomizedDecompressLib/EdkNullCustomizedDecompressLib.mbd create mode 100644 EdkModulePkg/Library/EdkNullCustomizedDecompressLib/EdkNullCustomizedDecompressLib.msa create mode 100644 EdkModulePkg/Library/EdkNullCustomizedDecompressLib/build.xml create mode 100644 EdkModulePkg/Library/EdkPeCoffLoaderLib/EdkPeCoffLoader.c create mode 100644 EdkModulePkg/Library/EdkPeCoffLoaderLib/EdkPeCoffLoaderLib.mbd create mode 100644 EdkModulePkg/Library/EdkPeCoffLoaderLib/EdkPeCoffLoaderLib.msa create mode 100644 EdkModulePkg/Library/EdkPeCoffLoaderLib/build.xml create mode 100644 EdkModulePkg/Library/EdkPeCoffLoaderX64Lib/EdkPeCoffLoaderX64.c create mode 100644 EdkModulePkg/Library/EdkPeCoffLoaderX64Lib/EdkPeCoffLoaderX64Lib.mbd create mode 100644 EdkModulePkg/Library/EdkPeCoffLoaderX64Lib/EdkPeCoffLoaderX64Lib.msa create mode 100644 EdkModulePkg/Library/EdkPeCoffLoaderX64Lib/build.xml create mode 100644 EdkModulePkg/Library/EdkPeiPerformanceLib/EdkPeiPerformanceLib.mbd create mode 100644 EdkModulePkg/Library/EdkPeiPerformanceLib/EdkPeiPerformanceLib.msa create mode 100644 EdkModulePkg/Library/EdkPeiPerformanceLib/PeiPerformanceLib.c create mode 100644 EdkModulePkg/Library/EdkPeiPerformanceLib/build.xml create mode 100644 EdkModulePkg/Library/EdkRuntimeStatusCodeLib/BsDataHubStatusCode/BsDataHubStatusCode.c create mode 100644 EdkModulePkg/Library/EdkRuntimeStatusCodeLib/BsDataHubStatusCode/BsDataHubStatusCode.h create mode 100644 EdkModulePkg/Library/EdkRuntimeStatusCodeLib/BsDataHubStatusCode/BsDataHubStatusCode.mbd create mode 100644 EdkModulePkg/Library/EdkRuntimeStatusCodeLib/BsDataHubStatusCode/BsDataHubStatusCode.msa create mode 100644 EdkModulePkg/Library/EdkRuntimeStatusCodeLib/BsDataHubStatusCode/build.xml create mode 100644 EdkModulePkg/Library/EdkRuntimeStatusCodeLib/RtMemoryStatusCode/RtMemoryStatusCode.c create mode 100644 EdkModulePkg/Library/EdkRuntimeStatusCodeLib/RtMemoryStatusCode/RtMemoryStatusCode.mbd create mode 100644 EdkModulePkg/Library/EdkRuntimeStatusCodeLib/RtMemoryStatusCode/RtMemoryStatusCode.msa create mode 100644 EdkModulePkg/Library/EdkRuntimeStatusCodeLib/RtMemoryStatusCode/build.xml create mode 100644 EdkModulePkg/Library/EdkRuntimeStatusCodeLib/RtPlatformStatusCode/RtPlatformStatusCode.c create mode 100644 EdkModulePkg/Library/EdkRuntimeStatusCodeLib/RtPlatformStatusCode/RtPlatformStatusCode.mbd create mode 100644 EdkModulePkg/Library/EdkRuntimeStatusCodeLib/RtPlatformStatusCode/RtPlatformStatusCode.msa create mode 100644 EdkModulePkg/Library/EdkRuntimeStatusCodeLib/RtPlatformStatusCode/build.xml create mode 100644 EdkModulePkg/Library/EdkScsiLib/EdkScsiLib.mbd create mode 100644 EdkModulePkg/Library/EdkScsiLib/EdkScsiLib.msa create mode 100644 EdkModulePkg/Library/EdkScsiLib/ScsiLib.c create mode 100644 EdkModulePkg/Library/EdkScsiLib/build.xml create mode 100644 EdkModulePkg/Library/EdkUefiDebugLibConOut/DebugLib.c create mode 100644 EdkModulePkg/Library/EdkUefiDebugLibConOut/EdkUefiDebugLibConOut.mbd create mode 100644 EdkModulePkg/Library/EdkUefiDebugLibConOut/EdkUefiDebugLibConOut.msa create mode 100644 EdkModulePkg/Library/EdkUefiDebugLibConOut/build.xml create mode 100644 EdkModulePkg/Library/EdkUefiDebugLibStdErr/DebugLib.c create mode 100644 EdkModulePkg/Library/EdkUefiDebugLibStdErr/EdkUefiDebugLibStdErr.mbd create mode 100644 EdkModulePkg/Library/EdkUefiDebugLibStdErr/EdkUefiDebugLibStdErr.msa create mode 100644 EdkModulePkg/Library/EdkUefiDebugLibStdErr/build.xml create mode 100644 EdkModulePkg/Library/EdkUsbLib/EdkUsbLib.mbd create mode 100644 EdkModulePkg/Library/EdkUsbLib/EdkUsbLib.msa create mode 100644 EdkModulePkg/Library/EdkUsbLib/UsbDxeLib.c create mode 100644 EdkModulePkg/Library/EdkUsbLib/build.xml create mode 100644 EdkModulePkg/Library/EdkUsbLib/hid.c create mode 100644 EdkModulePkg/Universal/Console/ConSplitter/Dxe/ComponentName.c create mode 100644 EdkModulePkg/Universal/Console/ConSplitter/Dxe/ConSplitter.c create mode 100644 EdkModulePkg/Universal/Console/ConSplitter/Dxe/ConSplitter.h create mode 100644 EdkModulePkg/Universal/Console/ConSplitter/Dxe/ConSplitter.mbd create mode 100644 EdkModulePkg/Universal/Console/ConSplitter/Dxe/ConSplitter.msa create mode 100644 EdkModulePkg/Universal/Console/ConSplitter/Dxe/ConSplitterGraphics.c create mode 100644 EdkModulePkg/Universal/Console/ConSplitter/Dxe/build.xml create mode 100644 EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/ComponentName.c create mode 100644 EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/ComponentName.h create mode 100644 EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/GraphicsConsole.c create mode 100644 EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/GraphicsConsole.h create mode 100644 EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/GraphicsConsole.mbd create mode 100644 EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/GraphicsConsole.msa create mode 100644 EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/LaffStd.c create mode 100644 EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/build.xml create mode 100644 EdkModulePkg/Universal/Console/Terminal/Dxe/ComponentName.c create mode 100644 EdkModulePkg/Universal/Console/Terminal/Dxe/Terminal.c create mode 100644 EdkModulePkg/Universal/Console/Terminal/Dxe/Terminal.h create mode 100644 EdkModulePkg/Universal/Console/Terminal/Dxe/Terminal.mbd create mode 100644 EdkModulePkg/Universal/Console/Terminal/Dxe/Terminal.msa create mode 100644 EdkModulePkg/Universal/Console/Terminal/Dxe/TerminalConIn.c create mode 100644 EdkModulePkg/Universal/Console/Terminal/Dxe/TerminalConOut.c create mode 100644 EdkModulePkg/Universal/Console/Terminal/Dxe/ansi.c create mode 100644 EdkModulePkg/Universal/Console/Terminal/Dxe/build.xml create mode 100644 EdkModulePkg/Universal/Console/Terminal/Dxe/vtutf8.c create mode 100644 EdkModulePkg/Universal/DataHub/DataHub/Dxe/DataHub.c create mode 100644 EdkModulePkg/Universal/DataHub/DataHub/Dxe/DataHub.dxs create mode 100644 EdkModulePkg/Universal/DataHub/DataHub/Dxe/DataHub.h create mode 100644 EdkModulePkg/Universal/DataHub/DataHub/Dxe/DataHub.mbd create mode 100644 EdkModulePkg/Universal/DataHub/DataHub/Dxe/DataHub.msa create mode 100644 EdkModulePkg/Universal/DataHub/DataHub/Dxe/build.xml create mode 100644 EdkModulePkg/Universal/DataHub/DataHubStdErr/Dxe/DataHubStdErr.c create mode 100644 EdkModulePkg/Universal/DataHub/DataHubStdErr/Dxe/DataHubStdErr.dxs create mode 100644 EdkModulePkg/Universal/DataHub/DataHubStdErr/Dxe/DataHubStdErr.mbd create mode 100644 EdkModulePkg/Universal/DataHub/DataHubStdErr/Dxe/DataHubStdErr.msa create mode 100644 EdkModulePkg/Universal/DataHub/DataHubStdErr/Dxe/build.xml create mode 100644 EdkModulePkg/Universal/DebugSupport/Dxe/DebugSupport.c create mode 100644 EdkModulePkg/Universal/DebugSupport/Dxe/DebugSupport.dxs create mode 100644 EdkModulePkg/Universal/DebugSupport/Dxe/DebugSupport.mbd create mode 100644 EdkModulePkg/Universal/DebugSupport/Dxe/DebugSupport.msa create mode 100644 EdkModulePkg/Universal/DebugSupport/Dxe/build.xml create mode 100644 EdkModulePkg/Universal/DebugSupport/Dxe/ia32/AsmFuncs.asm create mode 100644 EdkModulePkg/Universal/DebugSupport/Dxe/ia32/plDebugSupport.c create mode 100644 EdkModulePkg/Universal/DebugSupport/Dxe/ia32/plDebugSupport.h create mode 100644 EdkModulePkg/Universal/DebugSupport/Dxe/ipf/AsmFuncs.s create mode 100644 EdkModulePkg/Universal/DebugSupport/Dxe/ipf/Ds64Macros.i create mode 100644 EdkModulePkg/Universal/DebugSupport/Dxe/ipf/common.i create mode 100644 EdkModulePkg/Universal/DebugSupport/Dxe/ipf/plDebugSupport.c create mode 100644 EdkModulePkg/Universal/Debugger/Debugport/Dxe/ComponentName.c create mode 100644 EdkModulePkg/Universal/Debugger/Debugport/Dxe/DebugPort.c create mode 100644 EdkModulePkg/Universal/Debugger/Debugport/Dxe/DebugPort.dxs create mode 100644 EdkModulePkg/Universal/Debugger/Debugport/Dxe/DebugPort.h create mode 100644 EdkModulePkg/Universal/Debugger/Debugport/Dxe/DebugPort.mbd create mode 100644 EdkModulePkg/Universal/Debugger/Debugport/Dxe/DebugPort.msa create mode 100644 EdkModulePkg/Universal/Debugger/Debugport/Dxe/build.xml create mode 100644 EdkModulePkg/Universal/Disk/DiskIo/Dxe/ComponentName.c create mode 100644 EdkModulePkg/Universal/Disk/DiskIo/Dxe/DiskIo.mbd create mode 100644 EdkModulePkg/Universal/Disk/DiskIo/Dxe/DiskIo.msa create mode 100644 EdkModulePkg/Universal/Disk/DiskIo/Dxe/build.xml create mode 100644 EdkModulePkg/Universal/Disk/DiskIo/Dxe/diskio.c create mode 100644 EdkModulePkg/Universal/Disk/DiskIo/Dxe/diskio.h create mode 100644 EdkModulePkg/Universal/Disk/DiskIoPartition/dxe/DiskIoPartition.mbd create mode 100644 EdkModulePkg/Universal/Disk/DiskIoPartition/dxe/DiskIoPartition.msa create mode 100644 EdkModulePkg/Universal/Disk/DiskIoPartition/dxe/build.xml create mode 100644 EdkModulePkg/Universal/Disk/Partition/Dxe/ComponentName.c create mode 100644 EdkModulePkg/Universal/Disk/Partition/Dxe/ElTorito.c create mode 100644 EdkModulePkg/Universal/Disk/Partition/Dxe/ElTorito.h create mode 100644 EdkModulePkg/Universal/Disk/Partition/Dxe/Gpt.c create mode 100644 EdkModulePkg/Universal/Disk/Partition/Dxe/Gpt.h create mode 100644 EdkModulePkg/Universal/Disk/Partition/Dxe/Mbr.c create mode 100644 EdkModulePkg/Universal/Disk/Partition/Dxe/Mbr.h create mode 100644 EdkModulePkg/Universal/Disk/Partition/Dxe/Partition.c create mode 100644 EdkModulePkg/Universal/Disk/Partition/Dxe/Partition.h create mode 100644 EdkModulePkg/Universal/Disk/Partition/Dxe/Partition.mbd create mode 100644 EdkModulePkg/Universal/Disk/Partition/Dxe/Partition.msa create mode 100644 EdkModulePkg/Universal/Disk/Partition/Dxe/build.xml create mode 100644 EdkModulePkg/Universal/Disk/UnicodeCollation/English/Dxe/English.mbd create mode 100644 EdkModulePkg/Universal/Disk/UnicodeCollation/English/Dxe/English.msa create mode 100644 EdkModulePkg/Universal/Disk/UnicodeCollation/English/Dxe/UnicodeCollationEng.c create mode 100644 EdkModulePkg/Universal/Disk/UnicodeCollation/English/Dxe/UnicodeCollationEng.h create mode 100644 EdkModulePkg/Universal/Disk/UnicodeCollation/English/Dxe/build.xml create mode 100644 EdkModulePkg/Universal/Ebc/Dxe/Ebc.dxs create mode 100644 EdkModulePkg/Universal/Ebc/Dxe/Ebc.mbd create mode 100644 EdkModulePkg/Universal/Ebc/Dxe/Ebc.msa create mode 100644 EdkModulePkg/Universal/Ebc/Dxe/EbcExecute.c create mode 100644 EdkModulePkg/Universal/Ebc/Dxe/EbcExecute.h create mode 100644 EdkModulePkg/Universal/Ebc/Dxe/EbcInt.c create mode 100644 EdkModulePkg/Universal/Ebc/Dxe/EbcInt.h create mode 100644 EdkModulePkg/Universal/Ebc/Dxe/Ia32/EbcLowLevel.asm create mode 100644 EdkModulePkg/Universal/Ebc/Dxe/Ia32/EbcSupport.c create mode 100644 EdkModulePkg/Universal/Ebc/Dxe/Ia32/Ia32Math.asm create mode 100644 EdkModulePkg/Universal/Ebc/Dxe/Ipf/EbcLowLevel.s create mode 100644 EdkModulePkg/Universal/Ebc/Dxe/Ipf/EbcSupport.c create mode 100644 EdkModulePkg/Universal/Ebc/Dxe/Ipf/IpfMath.c create mode 100644 EdkModulePkg/Universal/Ebc/Dxe/Ipf/IpfMul.s create mode 100644 EdkModulePkg/Universal/Ebc/Dxe/build.xml create mode 100644 EdkModulePkg/Universal/Ebc/Dxe/x64/EbcLowLevel.asm create mode 100644 EdkModulePkg/Universal/Ebc/Dxe/x64/EbcSupport.c create mode 100644 EdkModulePkg/Universal/Ebc/Dxe/x64/x64Math.c create mode 100644 EdkModulePkg/Universal/EmuVariable/RuntimeDxe/EmuVariable.c create mode 100644 EdkModulePkg/Universal/EmuVariable/RuntimeDxe/EmuVariable.dxs create mode 100644 EdkModulePkg/Universal/EmuVariable/RuntimeDxe/EmuVariable.mbd create mode 100644 EdkModulePkg/Universal/EmuVariable/RuntimeDxe/EmuVariable.msa create mode 100644 EdkModulePkg/Universal/EmuVariable/RuntimeDxe/InitVariable.c create mode 100644 EdkModulePkg/Universal/EmuVariable/RuntimeDxe/Ipf/InitVariable.c create mode 100644 EdkModulePkg/Universal/EmuVariable/RuntimeDxe/Variable.h create mode 100644 EdkModulePkg/Universal/EmuVariable/RuntimeDxe/build.xml create mode 100644 EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwLite.c create mode 100644 EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwLite.dxs create mode 100644 EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwLite.h create mode 100644 EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwLite.mbd create mode 100644 EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwLite.msa create mode 100644 EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwMisc.c create mode 100644 EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwWorkSpace.c create mode 100644 EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/Ia32/Ia32FtwMisc.c create mode 100644 EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/Ipf/IpfFtwMisc.c create mode 100644 EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/build.xml create mode 100644 EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/x64/x64FtwMisc.c create mode 100644 EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/Crc32SectionExtract.c create mode 100644 EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/Crc32SectionExtract.dxs create mode 100644 EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/Crc32SectionExtract.h create mode 100644 EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/Crc32SectionExtract.mbd create mode 100644 EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/Crc32SectionExtract.msa create mode 100644 EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/GuidedSection.c create mode 100644 EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/GuidedSection.h create mode 100644 EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/build.xml create mode 100644 EdkModulePkg/Universal/GenericMemoryTest/Dxe/Common.h create mode 100644 EdkModulePkg/Universal/GenericMemoryTest/Dxe/NullMemoryTest.c create mode 100644 EdkModulePkg/Universal/GenericMemoryTest/Dxe/NullMemoryTest.dxs create mode 100644 EdkModulePkg/Universal/GenericMemoryTest/Dxe/NullMemoryTest.h create mode 100644 EdkModulePkg/Universal/GenericMemoryTest/Dxe/NullMemoryTest.mbd create mode 100644 EdkModulePkg/Universal/GenericMemoryTest/Dxe/NullMemoryTest.msa create mode 100644 EdkModulePkg/Universal/GenericMemoryTest/Dxe/build.xml create mode 100644 EdkModulePkg/Universal/GenericMemoryTest/Pei/BaseMemoryTest.c create mode 100644 EdkModulePkg/Universal/GenericMemoryTest/Pei/BaseMemoryTest.h create mode 100644 EdkModulePkg/Universal/GenericMemoryTest/Pei/BaseMemoryTest.mbd create mode 100644 EdkModulePkg/Universal/GenericMemoryTest/Pei/BaseMemoryTest.msa create mode 100644 EdkModulePkg/Universal/GenericMemoryTest/Pei/build.xml create mode 100644 EdkModulePkg/Universal/MonotonicCounter/RuntimeDxe/MonotonicCounter.c create mode 100644 EdkModulePkg/Universal/MonotonicCounter/RuntimeDxe/MonotonicCounter.dxs create mode 100644 EdkModulePkg/Universal/MonotonicCounter/RuntimeDxe/MonotonicCounter.h create mode 100644 EdkModulePkg/Universal/MonotonicCounter/RuntimeDxe/MonotonicCounter.mbd create mode 100644 EdkModulePkg/Universal/MonotonicCounter/RuntimeDxe/MonotonicCounter.msa create mode 100644 EdkModulePkg/Universal/MonotonicCounter/RuntimeDxe/build.xml create mode 100644 EdkModulePkg/Universal/Network/PxeBc/Dxe/BC.mbd create mode 100644 EdkModulePkg/Universal/Network/PxeBc/Dxe/BC.msa create mode 100644 EdkModulePkg/Universal/Network/PxeBc/Dxe/ComponentName.c create mode 100644 EdkModulePkg/Universal/Network/PxeBc/Dxe/Print.c create mode 100644 EdkModulePkg/Universal/Network/PxeBc/Dxe/bc.c create mode 100644 EdkModulePkg/Universal/Network/PxeBc/Dxe/bc.h create mode 100644 EdkModulePkg/Universal/Network/PxeBc/Dxe/build.xml create mode 100644 EdkModulePkg/Universal/Network/PxeBc/Dxe/dhcp.h create mode 100644 EdkModulePkg/Universal/Network/PxeBc/Dxe/hton.h create mode 100644 EdkModulePkg/Universal/Network/PxeBc/Dxe/ip.h create mode 100644 EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_arp.c create mode 100644 EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_dhcp.c create mode 100644 EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_igmp.c create mode 100644 EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_ip.c create mode 100644 EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_mtftp.c create mode 100644 EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_udp.c create mode 100644 EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_loadfile.c create mode 100644 EdkModulePkg/Universal/Network/PxeBc/Dxe/tftp.h create mode 100644 EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/ComponentName.c create mode 100644 EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/Dhcp4.mbd create mode 100644 EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/Dhcp4.msa create mode 100644 EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4.c create mode 100644 EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4.h create mode 100644 EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4InitSelect.c create mode 100644 EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4Release.c create mode 100644 EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4RenewRebind.c create mode 100644 EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4Run.c create mode 100644 EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4Setup.c create mode 100644 EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/build.xml create mode 100644 EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/support.c create mode 100644 EdkModulePkg/Universal/Network/Snp32_64/Dxe/ComponentName.c create mode 100644 EdkModulePkg/Universal/Network/Snp32_64/Dxe/SNP.mbd create mode 100644 EdkModulePkg/Universal/Network/Snp32_64/Dxe/SNP.msa create mode 100644 EdkModulePkg/Universal/Network/Snp32_64/Dxe/WaitForPacket.c create mode 100644 EdkModulePkg/Universal/Network/Snp32_64/Dxe/build.xml create mode 100644 EdkModulePkg/Universal/Network/Snp32_64/Dxe/callback.c create mode 100644 EdkModulePkg/Universal/Network/Snp32_64/Dxe/get_status.c create mode 100644 EdkModulePkg/Universal/Network/Snp32_64/Dxe/initialize.c create mode 100644 EdkModulePkg/Universal/Network/Snp32_64/Dxe/mcast_ip_to_mac.c create mode 100644 EdkModulePkg/Universal/Network/Snp32_64/Dxe/nvdata.c create mode 100644 EdkModulePkg/Universal/Network/Snp32_64/Dxe/receive.c create mode 100644 EdkModulePkg/Universal/Network/Snp32_64/Dxe/receive_filters.c create mode 100644 EdkModulePkg/Universal/Network/Snp32_64/Dxe/reset.c create mode 100644 EdkModulePkg/Universal/Network/Snp32_64/Dxe/shutdown.c create mode 100644 EdkModulePkg/Universal/Network/Snp32_64/Dxe/snp.c create mode 100644 EdkModulePkg/Universal/Network/Snp32_64/Dxe/snp.h create mode 100644 EdkModulePkg/Universal/Network/Snp32_64/Dxe/start.c create mode 100644 EdkModulePkg/Universal/Network/Snp32_64/Dxe/station_address.c create mode 100644 EdkModulePkg/Universal/Network/Snp32_64/Dxe/statistics.c create mode 100644 EdkModulePkg/Universal/Network/Snp32_64/Dxe/stop.c create mode 100644 EdkModulePkg/Universal/Network/Snp32_64/Dxe/transmit.c create mode 100644 EdkModulePkg/Universal/PCD/Common/PcdCommon.c create mode 100644 EdkModulePkg/Universal/PCD/Common/PcdCommon.h create mode 100644 EdkModulePkg/Universal/PCD/Dxe/Pcd.c create mode 100644 EdkModulePkg/Universal/PCD/Dxe/Service.c create mode 100644 EdkModulePkg/Universal/PCD/Dxe/Service.h create mode 100644 EdkModulePkg/Universal/PCD/Pei/Pcd.c create mode 100644 EdkModulePkg/Universal/PCD/Pei/Service.c create mode 100644 EdkModulePkg/Universal/PCD/Pei/Service.h create mode 100644 EdkModulePkg/Universal/PCD/Test/PcdTest.c create mode 100644 EdkModulePkg/Universal/PCD/Test/PcdTest.dxs create mode 100644 EdkModulePkg/Universal/Runtime/RuntimeDxe/Crc32.c create mode 100644 EdkModulePkg/Universal/Runtime/RuntimeDxe/Ia32/PeHotRelocateEx.c create mode 100644 EdkModulePkg/Universal/Runtime/RuntimeDxe/Ipf/PeHotRelocateEx.c create mode 100644 EdkModulePkg/Universal/Runtime/RuntimeDxe/Ipf/PeHotRelocateEx.h create mode 100644 EdkModulePkg/Universal/Runtime/RuntimeDxe/PeHotRelocate.c create mode 100644 EdkModulePkg/Universal/Runtime/RuntimeDxe/Runtime.c create mode 100644 EdkModulePkg/Universal/Runtime/RuntimeDxe/Runtime.dxs create mode 100644 EdkModulePkg/Universal/Runtime/RuntimeDxe/Runtime.h create mode 100644 EdkModulePkg/Universal/Runtime/RuntimeDxe/Runtime.mbd create mode 100644 EdkModulePkg/Universal/Runtime/RuntimeDxe/Runtime.msa create mode 100644 EdkModulePkg/Universal/Runtime/RuntimeDxe/build.xml create mode 100644 EdkModulePkg/Universal/Runtime/RuntimeDxe/x64/PeHotRelocateEx.c create mode 100644 EdkModulePkg/Universal/Security/SecurityStub/Dxe/SecurityStub.c create mode 100644 EdkModulePkg/Universal/Security/SecurityStub/Dxe/SecurityStub.dxs create mode 100644 EdkModulePkg/Universal/Security/SecurityStub/Dxe/SecurityStub.h create mode 100644 EdkModulePkg/Universal/Security/SecurityStub/Dxe/SecurityStub.mbd create mode 100644 EdkModulePkg/Universal/Security/SecurityStub/Dxe/SecurityStub.msa create mode 100644 EdkModulePkg/Universal/Security/SecurityStub/Dxe/build.xml create mode 100644 EdkModulePkg/Universal/StatusCode/RuntimeDxe/DebugAssert.c create mode 100644 EdkModulePkg/Universal/StatusCode/RuntimeDxe/Ia32/Ia32StatusCode.c create mode 100644 EdkModulePkg/Universal/StatusCode/RuntimeDxe/Ia32/Ia32StatusCode.dxs create mode 100644 EdkModulePkg/Universal/StatusCode/RuntimeDxe/Ipf/IpfStatusCode.c create mode 100644 EdkModulePkg/Universal/StatusCode/RuntimeDxe/Ipf/IpfStatusCode.dxs create mode 100644 EdkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCode.c create mode 100644 EdkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCode.h create mode 100644 EdkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCode.mbd create mode 100644 EdkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCode.msa create mode 100644 EdkModulePkg/Universal/StatusCode/RuntimeDxe/build.xml create mode 100644 EdkModulePkg/Universal/StatusCode/RuntimeDxe/x64/x64StatusCode.c create mode 100644 EdkModulePkg/Universal/StatusCode/RuntimeDxe/x64/x64StatusCode.dxs create mode 100644 EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/Fonts.c create mode 100644 EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/Forms.c create mode 100644 EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/HiiDatabase.c create mode 100644 EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/HiiDatabase.dxs create mode 100644 EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/HiiDatabase.h create mode 100644 EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/HiiDatabase.mbd create mode 100644 EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/HiiDatabase.msa create mode 100644 EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/Keyboard.c create mode 100644 EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/Package.c create mode 100644 EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/Strings.c create mode 100644 EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/build.xml create mode 100644 EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Boolean.c create mode 100644 EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Colors.h create mode 100644 EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/DriverSample.c create mode 100644 EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/DriverSample.h create mode 100644 EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/DriverSample.mbd create mode 100644 EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/DriverSample.msa create mode 100644 EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/NVDataStruc.h create mode 100644 EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/Vfr.vfr create mode 100644 EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/VfrStrings.uni create mode 100644 EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/build.xml create mode 100644 EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/inventory.vfr create mode 100644 EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/inventorystrings.uni create mode 100644 EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/InputHandler.c create mode 100644 EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Presentation.c create mode 100644 EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Print.c create mode 100644 EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Print.h create mode 100644 EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/ProcessOptions.c create mode 100644 EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Setup.c create mode 100644 EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Setup.h create mode 100644 EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/SetupBrowser.mbd create mode 100644 EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/SetupBrowser.msa create mode 100644 EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/SetupBrowserStr.uni create mode 100644 EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Ui.c create mode 100644 EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Ui.h create mode 100644 EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/build.xml create mode 100644 EdkModulePkg/Universal/Variable/Pei/Ia32/VarMachine.h create mode 100644 EdkModulePkg/Universal/Variable/Pei/Ipf/VarMachine.h create mode 100644 EdkModulePkg/Universal/Variable/Pei/Variable.c create mode 100644 EdkModulePkg/Universal/Variable/Pei/Variable.dxs create mode 100644 EdkModulePkg/Universal/Variable/Pei/Variable.h create mode 100644 EdkModulePkg/Universal/Variable/Pei/Variable.mbd create mode 100644 EdkModulePkg/Universal/Variable/Pei/Variable.msa create mode 100644 EdkModulePkg/Universal/Variable/Pei/build.xml create mode 100644 EdkModulePkg/Universal/Variable/Pei/x64/VarMachine.h create mode 100644 EdkModulePkg/Universal/Variable/RuntimeDxe/Emu/EmuVariable.c create mode 100644 EdkModulePkg/Universal/Variable/RuntimeDxe/Emu/EmuVariable.dxs create mode 100644 EdkModulePkg/Universal/Variable/RuntimeDxe/Emu/EmuVariable.mbd create mode 100644 EdkModulePkg/Universal/Variable/RuntimeDxe/Emu/EmuVariable.msa create mode 100644 EdkModulePkg/Universal/Variable/RuntimeDxe/Emu/build.xml create mode 100644 EdkModulePkg/Universal/Variable/RuntimeDxe/Ia32Variable.dxs create mode 100644 EdkModulePkg/Universal/Variable/RuntimeDxe/InitVariable.c create mode 100644 EdkModulePkg/Universal/Variable/RuntimeDxe/Ipf/InitVariable.c create mode 100644 EdkModulePkg/Universal/Variable/RuntimeDxe/IpfVariable.dxs create mode 100644 EdkModulePkg/Universal/Variable/RuntimeDxe/Variable.c create mode 100644 EdkModulePkg/Universal/Variable/RuntimeDxe/Variable.h create mode 100644 EdkModulePkg/Universal/Variable/RuntimeDxe/Variable.mbd create mode 100644 EdkModulePkg/Universal/Variable/RuntimeDxe/Variable.msa create mode 100644 EdkModulePkg/Universal/Variable/RuntimeDxe/build.xml create mode 100644 EdkModulePkg/Universal/Variable/RuntimeDxe/reclaim.c create mode 100644 EdkModulePkg/Universal/Variable/RuntimeDxe/reclaim.h create mode 100644 EdkModulePkg/Universal/Variable/RuntimeDxe/x64Variable.dxs create mode 100644 EdkModulePkg/Universal/WatchdogTimer/Dxe/WatchDogTimer.c create mode 100644 EdkModulePkg/Universal/WatchdogTimer/Dxe/WatchDogTimer.dxs create mode 100644 EdkModulePkg/Universal/WatchdogTimer/Dxe/WatchDogTimer.h create mode 100644 EdkModulePkg/Universal/WatchdogTimer/Dxe/WatchDogTimer.mbd create mode 100644 EdkModulePkg/Universal/WatchdogTimer/Dxe/WatchDogTimer.msa create mode 100644 EdkModulePkg/Universal/WatchdogTimer/Dxe/build.xml create mode 100644 EdkModulePkg/build.xml create mode 100644 EdkModulePkg/genbuildfile.xml create mode 100644 EdkNt32Pkg/Build/AprioriList.mbd create mode 100644 EdkNt32Pkg/Build/AprioriList.msa create mode 100644 EdkNt32Pkg/Build/Nt32Common.xml create mode 100644 EdkNt32Pkg/Build/component.def create mode 100644 EdkNt32Pkg/Dxe/ConPlatform/ComponentName.c create mode 100644 EdkNt32Pkg/Dxe/ConPlatform/ComponentName.h create mode 100644 EdkNt32Pkg/Dxe/ConPlatform/ConPlatform.c create mode 100644 EdkNt32Pkg/Dxe/ConPlatform/ConPlatform.h create mode 100644 EdkNt32Pkg/Dxe/ConPlatform/ConPlatform.mbd create mode 100644 EdkNt32Pkg/Dxe/ConPlatform/ConPlatform.msa create mode 100644 EdkNt32Pkg/Dxe/ConPlatform/build.xml create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscBaseBoardManufacturer.uni create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscBaseBoardManufacturerData.c create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscBiosLanguageData.c create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscBiosVendor.uni create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscBiosVendorData.c create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscBootInformationData.c create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscChassisManufacturer.uni create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscChassisManufacturerData.c create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscDevicePath.h create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscNumberOfInstallableLanguagesData.c create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscOemString.uni create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscOemStringData.c create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscOnboardDevice.uni create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscOnboardDeviceData.c create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscOnboardDeviceFunction.c create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscPortInternalConnectorDesignator.uni create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscPortInternalConnectorDesignatorData.c create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscPortInternalConnectorDesignatorFunction.c create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscResetCapabilitiesData.c create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSubclassDriver.dxs create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSubclassDriver.h create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSubclassDriver.mbd create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSubclassDriver.msa create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSubclassDriver.uni create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSubclassDriverDataTable.c create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSubclassDriverEntryPoint.c create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSystemLanguageString.uni create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSystemLanguageStringData.c create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSystemManufacturer.uni create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSystemManufacturerData.c create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSystemManufacturerFunction.c create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSystemOptionString.uni create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSystemOptionStringData.c create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSystemSlotDesignation.uni create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSystemSlotDesignationData.c create mode 100644 EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/build.xml create mode 100644 EdkNt32Pkg/Dxe/PcdEmulator/PcdEmulator.c create mode 100644 EdkNt32Pkg/Dxe/PcdEmulator/PcdEmulator.dxs create mode 100644 EdkNt32Pkg/Dxe/PcdEmulator/PcdEmulator.h create mode 100644 EdkNt32Pkg/Dxe/PcdEmulator/PcdEmulator.mbd create mode 100644 EdkNt32Pkg/Dxe/PcdEmulator/PcdEmulator.msa create mode 100644 EdkNt32Pkg/Dxe/PcdEmulator/build.xml create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/BdsPlatform.c create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/BdsPlatform.h create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/Bds.dxs create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/Bds.h create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/BdsEntry.c create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/BBSsupport.c create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/BBSsupport.h create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/BmLib.c create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/BootMaint.c create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/BootMaint.h create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/BootOption.c create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/ConsoleOption.c create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/Data.c create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/FE.vfr create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/FileExplorer.c create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/FormGuid.h create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/UpdatePage.c create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/Variable.c create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/bm.vfr create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/bmstring.uni create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMngr/BootManager.c create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMngr/BootManager.h create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMngr/BootManagerStrings.uni create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMngr/BootManagerVfr.Vfr create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/Capsules.c create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/DeviceMngr/DeviceManager.c create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/DeviceMngr/DeviceManager.h create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/DeviceMngr/DeviceManagerStrings.uni create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/DeviceMngr/DeviceManagerVfr.Vfr create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/FrontPage.c create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/FrontPage.h create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/FrontPageStrings.uni create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/FrontPageVfr.Vfr create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/Language.c create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/Language.h create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/MemoryTest.c create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/String.c create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/String.h create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/Generic/Strings.uni create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/PlatformBds.mbd create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/PlatformBds.msa create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/PlatformData.c create mode 100644 EdkNt32Pkg/Dxe/PlatformBds/build.xml create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/BlockIo/ComponentName.c create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/BlockIo/DriverConfiguration.c create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/BlockIo/DriverDiagnostics.c create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/BlockIo/WinNtBlockIo.c create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/BlockIo/WinNtBlockIo.h create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/BlockIo/WinNtBlockIo.mbd create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/BlockIo/WinNtBlockIo.msa create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/BlockIo/build.xml create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/Console/ComponentName.c create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/Console/Console.c create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/Console/Console.h create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/Console/ConsoleIn.c create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/Console/ConsoleOut.c create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/Console/WinNtConsole.mbd create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/Console/WinNtConsole.msa create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/Console/build.xml create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/SerialIo/ComponentName.c create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/SerialIo/WinNtSerialIo.c create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/SerialIo/WinNtSerialIo.h create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/SerialIo/WinNtSerialIo.mbd create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/SerialIo/WinNtSerialIo.msa create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/SerialIo/build.xml create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/SimpleFileSystem/ComponentName.c create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/SimpleFileSystem/WinNtSimpleFileSystem.c create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/SimpleFileSystem/WinNtSimpleFileSystem.h create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/SimpleFileSystem/WinNtSimpleFileSystem.mbd create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/SimpleFileSystem/WinNtSimpleFileSystem.msa create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/SimpleFileSystem/build.xml create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/ComponentName.c create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/WinNtUga.h create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/WinNtUga.mbd create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/WinNtUga.msa create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/WinNtUgaDriver.c create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/WinNtUgaInput.c create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/WinNtUgaScreen.c create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/build.xml create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/WinNtBusDriver/ComponentName.c create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/WinNtBusDriver/WinNtBusDriver.c create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/WinNtBusDriver/WinNtBusDriver.h create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/WinNtBusDriver/WinNtBusDriver.mbd create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/WinNtBusDriver/WinNtBusDriver.msa create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Bus/WinNtBusDriver/build.xml create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Metronome/Metronome.c create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Metronome/Metronome.dxs create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Metronome/Metronome.h create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Metronome/Metronome.mbd create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Metronome/Metronome.msa create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Metronome/build.xml create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Chipset/RealTimeClock/RealTimeClock.c create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Chipset/RealTimeClock/RealTimeClock.dxs create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Chipset/RealTimeClock/RealTimeClock.mbd create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Chipset/RealTimeClock/RealTimeClock.msa create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Chipset/RealTimeClock/build.xml create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Reset/Reset.dxs create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Reset/Reset.mbd create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Reset/Reset.msa create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Reset/build.xml create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Reset/reset.c create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Timer/Timer.c create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Timer/Timer.dxs create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Timer/Timer.h create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Timer/Timer.mbd create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Timer/Timer.msa create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Timer/build.xml create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Cpu/Cpu.c create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Cpu/Cpu.dxs create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Cpu/Cpu.mbd create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Cpu/Cpu.msa create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Cpu/CpuDriver.h create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Cpu/CpuIo.c create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Cpu/Strings.uni create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/Cpu/build.xml create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/WinNtThunk/WinNtThunk.c create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/WinNtThunk/WinNtThunk.dxs create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/WinNtThunk/WinNtThunk.h create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/WinNtThunk/WinNtThunk.mbd create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/WinNtThunk/WinNtThunk.msa create mode 100644 EdkNt32Pkg/Dxe/WinNtThunk/WinNtThunk/build.xml create mode 100644 EdkNt32Pkg/EdkNt32Pkg.spd create mode 100644 EdkNt32Pkg/Include/Common/WinNTInclude.h create mode 100644 EdkNt32Pkg/Include/FlashLayout.h create mode 100644 EdkNt32Pkg/Include/Ppi/NtAutoscan.h create mode 100644 EdkNt32Pkg/Include/Ppi/NtFwh.h create mode 100644 EdkNt32Pkg/Include/Ppi/NtPeiLoadFile.h create mode 100644 EdkNt32Pkg/Include/Ppi/NtThunk.h create mode 100644 EdkNt32Pkg/Include/Protocol/WinNtIo.h create mode 100644 EdkNt32Pkg/Include/Protocol/WinNtThunk.h create mode 100644 EdkNt32Pkg/Include/WinNtDxe.h create mode 100644 EdkNt32Pkg/Include/WinNtPeim.h create mode 100644 EdkNt32Pkg/Include/library/EdkGenericBdsLib.h create mode 100644 EdkNt32Pkg/Include/library/WinNtLib.h create mode 100644 EdkNt32Pkg/Library/DxeWinNtLib/DxeWinNtLib.mbd create mode 100644 EdkNt32Pkg/Library/DxeWinNtLib/DxeWinNtLib.msa create mode 100644 EdkNt32Pkg/Library/DxeWinNtLib/WinNtLib.c create mode 100644 EdkNt32Pkg/Library/DxeWinNtLib/build.xml create mode 100644 EdkNt32Pkg/Library/EdkGenericBdsLib/BdsBoot.c create mode 100644 EdkNt32Pkg/Library/EdkGenericBdsLib/BdsConnect.c create mode 100644 EdkNt32Pkg/Library/EdkGenericBdsLib/BdsConsole.c create mode 100644 EdkNt32Pkg/Library/EdkGenericBdsLib/BdsMisc.c create mode 100644 EdkNt32Pkg/Library/EdkGenericBdsLib/DevicePath.c create mode 100644 EdkNt32Pkg/Library/EdkGenericBdsLib/EdkGenericBdsLib.mbd create mode 100644 EdkNt32Pkg/Library/EdkGenericBdsLib/EdkGenericBdsLib.msa create mode 100644 EdkNt32Pkg/Library/EdkGenericBdsLib/Ipf/ShadowRom.c create mode 100644 EdkNt32Pkg/Library/EdkGenericBdsLib/Performance.c create mode 100644 EdkNt32Pkg/Library/EdkGenericBdsLib/Performance.h create mode 100644 EdkNt32Pkg/Library/EdkGenericBdsLib/build.xml create mode 100644 EdkNt32Pkg/Library/EdkNt32PeiPeCoffGetEntryPointLib/EdkNt32PeiPeCoffGetEntryPointLib.mbd create mode 100644 EdkNt32Pkg/Library/EdkNt32PeiPeCoffGetEntryPointLib/EdkNt32PeiPeCoffGetEntryPointLib.msa create mode 100644 EdkNt32Pkg/Library/EdkNt32PeiPeCoffGetEntryPointLib/PeCoffGetEntryPoint.c create mode 100644 EdkNt32Pkg/Library/EdkNt32PeiPeCoffGetEntryPointLib/build.xml create mode 100644 EdkNt32Pkg/Library/Nt32PeCoffLoaderLib/Nt32PeCoffLoader.c create mode 100644 EdkNt32Pkg/Library/Nt32PeCoffLoaderLib/Nt32PeCoffLoaderLib.mbd create mode 100644 EdkNt32Pkg/Library/Nt32PeCoffLoaderLib/Nt32PeCoffLoaderLib.msa create mode 100644 EdkNt32Pkg/Library/Nt32PeCoffLoaderLib/build.xml create mode 100644 EdkNt32Pkg/Logo/Logo.mbd create mode 100644 EdkNt32Pkg/Logo/Logo.msa create mode 100644 EdkNt32Pkg/Logo/Logo_build.xml create mode 100644 EdkNt32Pkg/Logo/build.xml create mode 100644 EdkNt32Pkg/Logo/logo.bmp create mode 100644 EdkNt32Pkg/Nt32.fpd create mode 100644 EdkNt32Pkg/Pei/Autoscan/WinNtAutoScan.mbd create mode 100644 EdkNt32Pkg/Pei/Autoscan/WinNtAutoScan.msa create mode 100644 EdkNt32Pkg/Pei/Autoscan/WinNtAutoscan.dxs create mode 100644 EdkNt32Pkg/Pei/Autoscan/WinntAutoscan.c create mode 100644 EdkNt32Pkg/Pei/Autoscan/build.xml create mode 100644 EdkNt32Pkg/Pei/BootMode/BootMode.c create mode 100644 EdkNt32Pkg/Pei/BootMode/BootMode.dxs create mode 100644 EdkNt32Pkg/Pei/BootMode/BootMode.mbd create mode 100644 EdkNt32Pkg/Pei/BootMode/BootMode.msa create mode 100644 EdkNt32Pkg/Pei/BootMode/build.xml create mode 100644 EdkNt32Pkg/Pei/FirmwareVolume/WinNtFwh.dxs create mode 100644 EdkNt32Pkg/Pei/FirmwareVolume/WinNtFwh.mbd create mode 100644 EdkNt32Pkg/Pei/FirmwareVolume/WinNtFwh.msa create mode 100644 EdkNt32Pkg/Pei/FirmwareVolume/WinntFwh.c create mode 100644 EdkNt32Pkg/Pei/FirmwareVolume/build.xml create mode 100644 EdkNt32Pkg/Pei/FlashMap/FlashMap.c create mode 100644 EdkNt32Pkg/Pei/FlashMap/FlashMap.dxs create mode 100644 EdkNt32Pkg/Pei/FlashMap/FlashMap.mbd create mode 100644 EdkNt32Pkg/Pei/FlashMap/FlashMap.msa create mode 100644 EdkNt32Pkg/Pei/FlashMap/build.xml create mode 100644 EdkNt32Pkg/Pei/MonoStatusCode/MonoStatusCode.c create mode 100644 EdkNt32Pkg/Pei/MonoStatusCode/MonoStatusCode.dxs create mode 100644 EdkNt32Pkg/Pei/MonoStatusCode/MonoStatusCode.h create mode 100644 EdkNt32Pkg/Pei/MonoStatusCode/Nt32/MonoStatusCode.mbd create mode 100644 EdkNt32Pkg/Pei/MonoStatusCode/Nt32/MonoStatusCode.msa create mode 100644 EdkNt32Pkg/Pei/MonoStatusCode/Nt32/PlatformStatusCode.c create mode 100644 EdkNt32Pkg/Pei/MonoStatusCode/Nt32/build.xml create mode 100644 EdkNt32Pkg/Pei/PcdEmulator/PcdEmulator.c create mode 100644 EdkNt32Pkg/Pei/PcdEmulator/PcdEmulator.dxs create mode 100644 EdkNt32Pkg/Pei/PcdEmulator/PcdEmulator.h create mode 100644 EdkNt32Pkg/Pei/PcdEmulator/PcdEmulator.mbd create mode 100644 EdkNt32Pkg/Pei/PcdEmulator/PcdEmulator.msa create mode 100644 EdkNt32Pkg/Pei/PcdEmulator/build.xml create mode 100644 EdkNt32Pkg/Pei/WinNtStuff/WinNtStuff.dxs create mode 100644 EdkNt32Pkg/Pei/WinNtStuff/WinNtStuff.mbd create mode 100644 EdkNt32Pkg/Pei/WinNtStuff/WinNtStuff.msa create mode 100644 EdkNt32Pkg/Pei/WinNtStuff/build.xml create mode 100644 EdkNt32Pkg/Pei/WinNtStuff/winntstuff.c create mode 100644 EdkNt32Pkg/RuntimeDxe/FvbServices/Common/FWBlockService.c create mode 100644 EdkNt32Pkg/RuntimeDxe/FvbServices/Common/FwBlockService.h create mode 100644 EdkNt32Pkg/RuntimeDxe/FvbServices/Common/ia32/Ia32Fwh.c create mode 100644 EdkNt32Pkg/RuntimeDxe/FvbServices/Nt32Fwh.dxs create mode 100644 EdkNt32Pkg/RuntimeDxe/FvbServices/Nt32Fwh.mbd create mode 100644 EdkNt32Pkg/RuntimeDxe/FvbServices/Nt32Fwh.msa create mode 100644 EdkNt32Pkg/RuntimeDxe/FvbServices/build.xml create mode 100644 EdkNt32Pkg/RuntimeDxe/FvbServices/nt32/FWBlockService.c create mode 100644 EdkNt32Pkg/RuntimeDxe/FvbServices/nt32/FvbInfo.c create mode 100644 EdkNt32Pkg/RuntimeDxe/FvbServices/nt32/FwBlockService.h create mode 100644 EdkNt32Pkg/Sec/FwVol.c create mode 100644 EdkNt32Pkg/Sec/SecMain.c create mode 100644 EdkNt32Pkg/Sec/SecMain.h create mode 100644 EdkNt32Pkg/Sec/SecMain.mbd create mode 100644 EdkNt32Pkg/Sec/SecMain.msa create mode 100644 EdkNt32Pkg/Sec/SecMain_build.xml create mode 100644 EdkNt32Pkg/Sec/WinNtThunk.c create mode 100644 EdkNt32Pkg/Sec/build.xml create mode 100644 EdkNt32Pkg/build.xml create mode 100644 EdkNt32Pkg/genbuildfile.xml create mode 100644 EdkNt32Pkg/run.cmd create mode 100644 EdkShellBinPkg/EdkShellBinPkg.spd create mode 100644 EdkShellBinPkg/bin/Shell.mbd create mode 100644 EdkShellBinPkg/bin/Shell.msa create mode 100644 EdkShellBinPkg/bin/build.xml create mode 100644 EdkShellBinPkg/bin/ia32/Apps/Attrib.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/Cls.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/Cp.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/Date.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/Dblk.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/Devices.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/Devtree.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/Drivers.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/Drvcfg.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/Drvdiag.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/Guid.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/IpConfig.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/Load.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/LoadPciRom.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/Ls.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/Mkdir.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/Mount.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/Mv.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/NShell.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/Openinfo.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/Resets.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/Rm.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/SmbiosView.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/TelnetMgmt.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/Time.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/Touch.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/Type.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/Unload.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/Ver.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/Vol.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/comp.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/dmem.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/dmpstore.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/edit.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/eficompress.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/efidecompress.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/err.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/hexedit.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/legacyboot.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/loadfv.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/mem.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/memmap.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/mm.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/mode.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/pci.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/sermode.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/stall.efi create mode 100644 EdkShellBinPkg/bin/ia32/Apps/timezone.efi create mode 100644 EdkShellBinPkg/bin/ia32/Shell.efi create mode 100644 EdkShellBinPkg/bin/ia32/Shell_Full.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/Attrib.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/Cls.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/Cp.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/Date.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/Dblk.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/Devices.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/Devtree.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/Drivers.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/Drvcfg.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/Drvdiag.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/Guid.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/IpConfig.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/Load.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/LoadPciRom.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/Ls.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/Mkdir.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/Mount.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/Mv.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/NShell.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/Openinfo.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/Resets.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/Rm.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/SmbiosView.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/TelnetMgmt.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/Time.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/Touch.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/Type.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/Unload.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/Ver.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/Vol.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/comp.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/dmem.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/dmpstore.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/edit.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/eficompress.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/efidecompress.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/err.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/hexedit.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/mem.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/memmap.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/mm.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/mode.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/pci.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/sermode.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/stall.efi create mode 100644 EdkShellBinPkg/bin/ipf/Apps/timezone.efi create mode 100644 EdkShellBinPkg/bin/ipf/Shell.efi create mode 100644 EdkShellBinPkg/bin/ipf/Shell_Full.efi create mode 100644 EdkShellBinPkg/genbuildfile.xml create mode 100644 MdePkg/Include/Base.h create mode 100644 MdePkg/Include/Common/BaseTypes.h create mode 100644 MdePkg/Include/Common/BootMode.h create mode 100644 MdePkg/Include/Common/BootScript.h create mode 100644 MdePkg/Include/Common/Capsule.h create mode 100644 MdePkg/Include/Common/DataHubRecords.h create mode 100644 MdePkg/Include/Common/Dependency.h create mode 100644 MdePkg/Include/Common/EfiImage.h create mode 100644 MdePkg/Include/Common/FirmwareFileSystem.h create mode 100644 MdePkg/Include/Common/FirmwareVolumeHeader.h create mode 100644 MdePkg/Include/Common/FirmwareVolumeImageFormat.h create mode 100644 MdePkg/Include/Common/Hob.h create mode 100644 MdePkg/Include/Common/InternalFormRepresentation.h create mode 100644 MdePkg/Include/Common/Legacy16.h create mode 100644 MdePkg/Include/Common/MultiPhase.h create mode 100644 MdePkg/Include/Common/Pcd.h create mode 100644 MdePkg/Include/Common/PcdTemp.h create mode 100644 MdePkg/Include/Common/StatusCode.h create mode 100644 MdePkg/Include/Common/StatusCodeDataTypeId.h create mode 100644 MdePkg/Include/Common/UefiBaseTypes.h create mode 100644 MdePkg/Include/Dxe.h create mode 100644 MdePkg/Include/Dxe/ArchProtocol/Bds.h create mode 100644 MdePkg/Include/Dxe/ArchProtocol/Cpu.h create mode 100644 MdePkg/Include/Dxe/ArchProtocol/Metronome.h create mode 100644 MdePkg/Include/Dxe/ArchProtocol/MonotonicCounter.h create mode 100644 MdePkg/Include/Dxe/ArchProtocol/RealTimeClock.h create mode 100644 MdePkg/Include/Dxe/ArchProtocol/Reset.h create mode 100644 MdePkg/Include/Dxe/ArchProtocol/Runtime.h create mode 100644 MdePkg/Include/Dxe/ArchProtocol/Security.h create mode 100644 MdePkg/Include/Dxe/ArchProtocol/SecurityPolicy.h create mode 100644 MdePkg/Include/Dxe/ArchProtocol/StatusCode.h create mode 100644 MdePkg/Include/Dxe/ArchProtocol/Timer.h create mode 100644 MdePkg/Include/Dxe/ArchProtocol/Variable.h create mode 100644 MdePkg/Include/Dxe/ArchProtocol/VariableWrite.h create mode 100644 MdePkg/Include/Dxe/ArchProtocol/WatchdogTimer.h create mode 100644 MdePkg/Include/Dxe/DxeCis.h create mode 100644 MdePkg/Include/Dxe/SmmCis.h create mode 100644 MdePkg/Include/DxeCore.h create mode 100644 MdePkg/Include/DxeDepex.h create mode 100644 MdePkg/Include/Ebc/ProcessorBind.h create mode 100644 MdePkg/Include/Guid/Acpi.h create mode 100644 MdePkg/Include/Guid/AcpiTableStorage.h create mode 100644 MdePkg/Include/Guid/Apriori.h create mode 100644 MdePkg/Include/Guid/Capsule.h create mode 100644 MdePkg/Include/Guid/DataHubRecords.h create mode 100644 MdePkg/Include/Guid/DebugImageInfoTable.h create mode 100644 MdePkg/Include/Guid/DxeServices.h create mode 100644 MdePkg/Include/Guid/EventGroup.h create mode 100644 MdePkg/Include/Guid/EventLegacyBios.h create mode 100644 MdePkg/Include/Guid/FirmwareFileSystem.h create mode 100644 MdePkg/Include/Guid/FrameworkDevicePath.h create mode 100644 MdePkg/Include/Guid/GlobalVariable.h create mode 100644 MdePkg/Include/Guid/Gpt.h create mode 100644 MdePkg/Include/Guid/HobList.h create mode 100644 MdePkg/Include/Guid/MemoryAllocationHob.h create mode 100644 MdePkg/Include/Guid/Mps.h create mode 100644 MdePkg/Include/Guid/PcAnsi.h create mode 100644 MdePkg/Include/Guid/SalSystemTable.h create mode 100644 MdePkg/Include/Guid/SmBios.h create mode 100644 MdePkg/Include/Guid/SmmCommunicate.h create mode 100644 MdePkg/Include/Guid/SmramMemoryReserve.h create mode 100644 MdePkg/Include/Guid/StatusCodeDataTypeId.h create mode 100644 MdePkg/Include/Ia32/ProcessorBind.h create mode 100644 MdePkg/Include/IndustryStandard/Acpi.h create mode 100644 MdePkg/Include/IndustryStandard/Usb.h create mode 100644 MdePkg/Include/IndustryStandard/pci22.h create mode 100644 MdePkg/Include/IndustryStandard/scsi.h create mode 100644 MdePkg/Include/Ipf/IpfDefines.h create mode 100644 MdePkg/Include/Ipf/IpfMacro.i create mode 100644 MdePkg/Include/Ipf/ProcessorBind.h create mode 100644 MdePkg/Include/Ipf/SalApi.h create mode 100644 MdePkg/Include/Library/BaseLib.h create mode 100644 MdePkg/Include/Library/BaseMemoryLib.h create mode 100644 MdePkg/Include/Library/CacheMaintenanceLib.h create mode 100644 MdePkg/Include/Library/CpuLib.h create mode 100644 MdePkg/Include/Library/DebugLib.h create mode 100644 MdePkg/Include/Library/DevicePathLib.h create mode 100644 MdePkg/Include/Library/DxeCoreEntryPoint.h create mode 100644 MdePkg/Include/Library/DxeRuntimeDriverLib.h create mode 100644 MdePkg/Include/Library/DxeServicesTableLib.h create mode 100644 MdePkg/Include/Library/DxeSmmDriverEntryPoint.h create mode 100644 MdePkg/Include/Library/HiiLib.h create mode 100644 MdePkg/Include/Library/HobLib.h create mode 100644 MdePkg/Include/Library/IoLib.h create mode 100644 MdePkg/Include/Library/MemoryAllocationLib.h create mode 100644 MdePkg/Include/Library/PcdLib.h create mode 100644 MdePkg/Include/Library/PciCf8Lib.h create mode 100644 MdePkg/Include/Library/PciExpressLib.h create mode 100644 MdePkg/Include/Library/PciLib.h create mode 100644 MdePkg/Include/Library/PciSegmentLib.h create mode 100644 MdePkg/Include/Library/PeCoffGetEntryPointLib.h create mode 100644 MdePkg/Include/Library/PeCoffLib.h create mode 100644 MdePkg/Include/Library/PeiCoreEntryPoint.h create mode 100644 MdePkg/Include/Library/PeiCoreLib.h create mode 100644 MdePkg/Include/Library/PeiServicesTablePointerLib.h create mode 100644 MdePkg/Include/Library/PeimEntryPoint.h create mode 100644 MdePkg/Include/Library/PerformanceLib.h create mode 100644 MdePkg/Include/Library/PrintLib.h create mode 100644 MdePkg/Include/Library/ReportStatusCodeLib.h create mode 100644 MdePkg/Include/Library/ResourcePublicationLib.h create mode 100644 MdePkg/Include/Library/SmbusLib.h create mode 100644 MdePkg/Include/Library/TimerLib.h create mode 100644 MdePkg/Include/Library/UefiBootServicesTableLib.h create mode 100644 MdePkg/Include/Library/UefiDecompressLib.h create mode 100644 MdePkg/Include/Library/UefiDriverEntryPoint.h create mode 100644 MdePkg/Include/Library/UefiDriverModelLib.h create mode 100644 MdePkg/Include/Library/UefiLib.h create mode 100644 MdePkg/Include/Library/UefiRuntimeServicesTableLib.h create mode 100644 MdePkg/Include/PeiCore.h create mode 100644 MdePkg/Include/Peim.h create mode 100644 MdePkg/Include/Peim/PeiCis.h create mode 100644 MdePkg/Include/PeimDepex.h create mode 100644 MdePkg/Include/PiwgDxe.h create mode 100644 MdePkg/Include/PiwgPeim.h create mode 100644 MdePkg/Include/Ppi/BlockIo.h create mode 100644 MdePkg/Include/Ppi/BootInRecoveryMode.h create mode 100644 MdePkg/Include/Ppi/BootScriptExecuter.h create mode 100644 MdePkg/Include/Ppi/CpuIo.h create mode 100644 MdePkg/Include/Ppi/DeviceRecoveryModule.h create mode 100644 MdePkg/Include/Ppi/DxeIpl.h create mode 100644 MdePkg/Include/Ppi/EndOfPeiPhase.h create mode 100644 MdePkg/Include/Ppi/FindFv.h create mode 100644 MdePkg/Include/Ppi/LoadFile.h create mode 100644 MdePkg/Include/Ppi/MasterBootMode.h create mode 100644 MdePkg/Include/Ppi/MemoryDiscovered.h create mode 100644 MdePkg/Include/Ppi/Pcd.h create mode 100644 MdePkg/Include/Ppi/PciCfg.h create mode 100644 MdePkg/Include/Ppi/ReadOnlyVariable.h create mode 100644 MdePkg/Include/Ppi/RecoveryModule.h create mode 100644 MdePkg/Include/Ppi/Reset.h create mode 100644 MdePkg/Include/Ppi/S3Resume.h create mode 100644 MdePkg/Include/Ppi/SecPlatformInformation.h create mode 100644 MdePkg/Include/Ppi/SectionExtraction.h create mode 100644 MdePkg/Include/Ppi/Security.h create mode 100644 MdePkg/Include/Ppi/Smbus.h create mode 100644 MdePkg/Include/Ppi/Stall.h create mode 100644 MdePkg/Include/Ppi/StatusCode.h create mode 100644 MdePkg/Include/Protocol/AcpiSupport.h create mode 100644 MdePkg/Include/Protocol/Arp.h create mode 100644 MdePkg/Include/Protocol/AuthenticationInfo.h create mode 100644 MdePkg/Include/Protocol/Bis.h create mode 100644 MdePkg/Include/Protocol/BlockIo.h create mode 100644 MdePkg/Include/Protocol/BootScriptSave.h create mode 100644 MdePkg/Include/Protocol/BusSpecificDriverOverride.h create mode 100644 MdePkg/Include/Protocol/ComponentName.h create mode 100644 MdePkg/Include/Protocol/CpuIo.h create mode 100644 MdePkg/Include/Protocol/DataHub.h create mode 100644 MdePkg/Include/Protocol/DebugPort.h create mode 100644 MdePkg/Include/Protocol/DebugSupport.h create mode 100644 MdePkg/Include/Protocol/Decompress.h create mode 100644 MdePkg/Include/Protocol/DeviceIo.h create mode 100644 MdePkg/Include/Protocol/DevicePath.h create mode 100644 MdePkg/Include/Protocol/DevicePathFromText.h create mode 100644 MdePkg/Include/Protocol/DevicePathToText.h create mode 100644 MdePkg/Include/Protocol/DevicePathUtilities.h create mode 100644 MdePkg/Include/Protocol/Dhcp4.h create mode 100644 MdePkg/Include/Protocol/DiskIo.h create mode 100644 MdePkg/Include/Protocol/DriverBinding.h create mode 100644 MdePkg/Include/Protocol/DriverConfiguration.h create mode 100644 MdePkg/Include/Protocol/DriverDiagnostics.h create mode 100644 MdePkg/Include/Protocol/Ebc.h create mode 100644 MdePkg/Include/Protocol/EdidActive.h create mode 100644 MdePkg/Include/Protocol/EdidDiscovered.h create mode 100644 MdePkg/Include/Protocol/EdidOverride.h create mode 100644 MdePkg/Include/Protocol/EfiNetworkInterfaceIdentifier.h create mode 100644 MdePkg/Include/Protocol/FileInfo.h create mode 100644 MdePkg/Include/Protocol/FileSystemInfo.h create mode 100644 MdePkg/Include/Protocol/FileSystemVolumeLabelInfo.h create mode 100644 MdePkg/Include/Protocol/FirmwareVolume.h create mode 100644 MdePkg/Include/Protocol/FirmwareVolumeBlock.h create mode 100644 MdePkg/Include/Protocol/FirmwareVolumeDispatch.h create mode 100644 MdePkg/Include/Protocol/FormBrowser.h create mode 100644 MdePkg/Include/Protocol/FormCallback.h create mode 100644 MdePkg/Include/Protocol/GraphicsOutput.h create mode 100644 MdePkg/Include/Protocol/GuidedSectionExtraction.h create mode 100644 MdePkg/Include/Protocol/Hash.h create mode 100644 MdePkg/Include/Protocol/Hii.h create mode 100644 MdePkg/Include/Protocol/IP4.h create mode 100644 MdePkg/Include/Protocol/IP4Config.h create mode 100644 MdePkg/Include/Protocol/IScsiInitatorName.h create mode 100644 MdePkg/Include/Protocol/IdeControllerInit.h create mode 100644 MdePkg/Include/Protocol/IncompatiblePciDeviceSupport.h create mode 100644 MdePkg/Include/Protocol/Legacy8259.h create mode 100644 MdePkg/Include/Protocol/LegacyBios.h create mode 100644 MdePkg/Include/Protocol/LegacyBiosPlatform.h create mode 100644 MdePkg/Include/Protocol/LegacyInterrupt.h create mode 100644 MdePkg/Include/Protocol/LegacyRegion.h create mode 100644 MdePkg/Include/Protocol/LoadFile.h create mode 100644 MdePkg/Include/Protocol/LoadedImage.h create mode 100644 MdePkg/Include/Protocol/ManagedNetwork.h create mode 100644 MdePkg/Include/Protocol/Mtftp4.h create mode 100644 MdePkg/Include/Protocol/Pcd.h create mode 100644 MdePkg/Include/Protocol/PciHostBridgeResourceAllocation.h create mode 100644 MdePkg/Include/Protocol/PciHotPlugInit.h create mode 100644 MdePkg/Include/Protocol/PciIo.h create mode 100644 MdePkg/Include/Protocol/PciPlatform.h create mode 100644 MdePkg/Include/Protocol/PciRootBridgeIo.h create mode 100644 MdePkg/Include/Protocol/PlatformDriverOverride.h create mode 100644 MdePkg/Include/Protocol/PxeBaseCode.h create mode 100644 MdePkg/Include/Protocol/PxeBaseCodeCallBack.h create mode 100644 MdePkg/Include/Protocol/ScsiIo.h create mode 100644 MdePkg/Include/Protocol/ScsiPassThru.h create mode 100644 MdePkg/Include/Protocol/ScsiPassThruExt.h create mode 100644 MdePkg/Include/Protocol/SectionExtraction.h create mode 100644 MdePkg/Include/Protocol/SerialIo.h create mode 100644 MdePkg/Include/Protocol/ServiceBinding.h create mode 100644 MdePkg/Include/Protocol/SimpleFileSystem.h create mode 100644 MdePkg/Include/Protocol/SimpleNetwork.h create mode 100644 MdePkg/Include/Protocol/SimplePointer.h create mode 100644 MdePkg/Include/Protocol/SimpleTextIn.h create mode 100644 MdePkg/Include/Protocol/SimpleTextOut.h create mode 100644 MdePkg/Include/Protocol/Smbus.h create mode 100644 MdePkg/Include/Protocol/SmmAccess.h create mode 100644 MdePkg/Include/Protocol/SmmBase.h create mode 100644 MdePkg/Include/Protocol/SmmControl.h create mode 100644 MdePkg/Include/Protocol/SmmGpiDispatch.h create mode 100644 MdePkg/Include/Protocol/SmmIchnDispatch.h create mode 100644 MdePkg/Include/Protocol/SmmPeriodicTimerDispatch.h create mode 100644 MdePkg/Include/Protocol/SmmPowerButtonDispatch.h create mode 100644 MdePkg/Include/Protocol/SmmStandbyButtonDispatch.h create mode 100644 MdePkg/Include/Protocol/SmmStatusCode.h create mode 100644 MdePkg/Include/Protocol/SmmSwDispatch.h create mode 100644 MdePkg/Include/Protocol/SmmSxDispatch.h create mode 100644 MdePkg/Include/Protocol/SmmUsbDispatch.h create mode 100644 MdePkg/Include/Protocol/TapeIo.h create mode 100644 MdePkg/Include/Protocol/Tcp4.h create mode 100644 MdePkg/Include/Protocol/Udp4.h create mode 100644 MdePkg/Include/Protocol/UgaDraw.h create mode 100644 MdePkg/Include/Protocol/UnicodeCollation.h create mode 100644 MdePkg/Include/Protocol/Usb2HostController.h create mode 100644 MdePkg/Include/Protocol/UsbHostController.h create mode 100644 MdePkg/Include/Protocol/UsbIo.h create mode 100644 MdePkg/Include/ToBeRemoved/Variable.h create mode 100644 MdePkg/Include/ToBeRemoved/WorkingBlockHeader.h create mode 100644 MdePkg/Include/Uefi.h create mode 100644 MdePkg/Include/Uefi/EfiPxe.h create mode 100644 MdePkg/Include/Uefi/Errors.h create mode 100644 MdePkg/Include/Uefi/UefiSpec.h create mode 100644 MdePkg/Include/x64/ProcessorBind.h create mode 100644 MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.mbd create mode 100644 MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.msa create mode 100644 MdePkg/Library/BaseCacheMaintenanceLib/EbcCache.c create mode 100644 MdePkg/Library/BaseCacheMaintenanceLib/Ipf/CallPalProc.s create mode 100644 MdePkg/Library/BaseCacheMaintenanceLib/Ipf/Cpu.s create mode 100644 MdePkg/Library/BaseCacheMaintenanceLib/IpfCache.c create mode 100644 MdePkg/Library/BaseCacheMaintenanceLib/build.xml create mode 100644 MdePkg/Library/BaseCacheMaintenanceLib/x86Cache.c create mode 100644 MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.mbd create mode 100644 MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.msa create mode 100644 MdePkg/Library/BaseDebugLibNull/DebugLib.c create mode 100644 MdePkg/Library/BaseDebugLibNull/build.xml create mode 100644 MdePkg/Library/BaseDebugLibReportStatusCode/BaseDebugLibReportStatusCode.mbd create mode 100644 MdePkg/Library/BaseDebugLibReportStatusCode/BaseDebugLibReportStatusCode.msa create mode 100644 MdePkg/Library/BaseDebugLibReportStatusCode/DebugLib.c create mode 100644 MdePkg/Library/BaseDebugLibReportStatusCode/build.xml create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.mbd create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.msa create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoHighLevel.c create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLib.c create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/build.xml create mode 100644 MdePkg/Library/BaseLib/ARShiftU64.c create mode 100644 MdePkg/Library/BaseLib/BaseLib.mbd create mode 100644 MdePkg/Library/BaseLib/BaseLib.msa create mode 100644 MdePkg/Library/BaseLib/BaseLibInternals.h create mode 100644 MdePkg/Library/BaseLib/BitField.c create mode 100644 MdePkg/Library/BaseLib/Cpu.c create mode 100644 MdePkg/Library/BaseLib/CpuDeadLoop.c create mode 100644 MdePkg/Library/BaseLib/DivS64x64Remainder.c create mode 100644 MdePkg/Library/BaseLib/DivU64x32.c create mode 100644 MdePkg/Library/BaseLib/DivU64x32Remainder.c create mode 100644 MdePkg/Library/BaseLib/DivU64x64Remainder.c create mode 100644 MdePkg/Library/BaseLib/Ebc/CpuBreakpoint.c create mode 100644 MdePkg/Library/BaseLib/GetPowerOfTwo32.c create mode 100644 MdePkg/Library/BaseLib/GetPowerOfTwo64.c create mode 100644 MdePkg/Library/BaseLib/HighBitSet32.c create mode 100644 MdePkg/Library/BaseLib/HighBitSet64.c create mode 100644 MdePkg/Library/BaseLib/Ipf/CpuBreakpoint.c create mode 100644 MdePkg/Library/BaseLib/Ipf/InterlockedCompareExchange32.s create mode 100644 MdePkg/Library/BaseLib/Ipf/InterlockedCompareExchange64.s create mode 100644 MdePkg/Library/BaseLib/Ipf/SwitchStack.s create mode 100644 MdePkg/Library/BaseLib/Ipf/Synchronization.c create mode 100644 MdePkg/Library/BaseLib/Ipf/Unaligned.c create mode 100644 MdePkg/Library/BaseLib/Ipf/asm.h create mode 100644 MdePkg/Library/BaseLib/Ipf/ia_64gen.h create mode 100644 MdePkg/Library/BaseLib/Ipf/setjmp.s create mode 100644 MdePkg/Library/BaseLib/LRotU32.c create mode 100644 MdePkg/Library/BaseLib/LRotU64.c create mode 100644 MdePkg/Library/BaseLib/LShiftU64.c create mode 100644 MdePkg/Library/BaseLib/LinkedList.c create mode 100644 MdePkg/Library/BaseLib/LowBitSet32.c create mode 100644 MdePkg/Library/BaseLib/LowBitSet64.c create mode 100644 MdePkg/Library/BaseLib/Math64.c create mode 100644 MdePkg/Library/BaseLib/ModU64x32.c create mode 100644 MdePkg/Library/BaseLib/MultS64x64.c create mode 100644 MdePkg/Library/BaseLib/MultU64x32.c create mode 100644 MdePkg/Library/BaseLib/MultU64x64.c create mode 100644 MdePkg/Library/BaseLib/RRotU32.c create mode 100644 MdePkg/Library/BaseLib/RRotU64.c create mode 100644 MdePkg/Library/BaseLib/RShiftU64.c create mode 100644 MdePkg/Library/BaseLib/SetJumpLongJump.c create mode 100644 MdePkg/Library/BaseLib/String.c create mode 100644 MdePkg/Library/BaseLib/SwapBytes16.c create mode 100644 MdePkg/Library/BaseLib/SwapBytes32.c create mode 100644 MdePkg/Library/BaseLib/SwapBytes64.c create mode 100644 MdePkg/Library/BaseLib/SwitchStack.c create mode 100644 MdePkg/Library/BaseLib/Synchronization.c create mode 100644 MdePkg/Library/BaseLib/Unaligned.c create mode 100644 MdePkg/Library/BaseLib/build.xml create mode 100644 MdePkg/Library/BaseLib/ia32/ARShiftU64.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ARShiftU64.s create mode 100644 MdePkg/Library/BaseLib/ia32/CpuBreakpoint.asm create mode 100644 MdePkg/Library/BaseLib/ia32/CpuBreakpoint.s create mode 100644 MdePkg/Library/BaseLib/ia32/CpuFlushTlb.asm create mode 100644 MdePkg/Library/BaseLib/ia32/CpuFlushTlb.s create mode 100644 MdePkg/Library/BaseLib/ia32/CpuId.asm create mode 100644 MdePkg/Library/BaseLib/ia32/CpuId.s create mode 100644 MdePkg/Library/BaseLib/ia32/CpuPause.asm create mode 100644 MdePkg/Library/BaseLib/ia32/CpuPause.s create mode 100644 MdePkg/Library/BaseLib/ia32/CpuSleep.asm create mode 100644 MdePkg/Library/BaseLib/ia32/CpuSleep.s create mode 100644 MdePkg/Library/BaseLib/ia32/DisableInterrupts.asm create mode 100644 MdePkg/Library/BaseLib/ia32/DisableInterrupts.s create mode 100644 MdePkg/Library/BaseLib/ia32/DisablePaging32.asm create mode 100644 MdePkg/Library/BaseLib/ia32/DisablePaging32.s create mode 100644 MdePkg/Library/BaseLib/ia32/DivS64x64Remainder.c create mode 100644 MdePkg/Library/BaseLib/ia32/DivU64x32.asm create mode 100644 MdePkg/Library/BaseLib/ia32/DivU64x32.s create mode 100644 MdePkg/Library/BaseLib/ia32/DivU64x32Remainder.asm create mode 100644 MdePkg/Library/BaseLib/ia32/DivU64x32Remainder.s create mode 100644 MdePkg/Library/BaseLib/ia32/DivU64x64Remainder.asm create mode 100644 MdePkg/Library/BaseLib/ia32/DivU64x64Remainder.s create mode 100644 MdePkg/Library/BaseLib/ia32/EnableDisableInterrupts.asm create mode 100644 MdePkg/Library/BaseLib/ia32/EnableDisableInterrupts.s create mode 100644 MdePkg/Library/BaseLib/ia32/EnableInterrupts.asm create mode 100644 MdePkg/Library/BaseLib/ia32/EnableInterrupts.s create mode 100644 MdePkg/Library/BaseLib/ia32/EnablePaging32.asm create mode 100644 MdePkg/Library/BaseLib/ia32/EnablePaging32.s create mode 100644 MdePkg/Library/BaseLib/ia32/EnablePaging64.asm create mode 100644 MdePkg/Library/BaseLib/ia32/EnablePaging64.s create mode 100644 MdePkg/Library/BaseLib/ia32/FlushCacheLine.asm create mode 100644 MdePkg/Library/BaseLib/ia32/FlushCacheLine.s create mode 100644 MdePkg/Library/BaseLib/ia32/FxRestore.asm create mode 100644 MdePkg/Library/BaseLib/ia32/FxRestore.s create mode 100644 MdePkg/Library/BaseLib/ia32/FxSave.asm create mode 100644 MdePkg/Library/BaseLib/ia32/FxSave.s create mode 100644 MdePkg/Library/BaseLib/ia32/InterlockedCompareExchange32.asm create mode 100644 MdePkg/Library/BaseLib/ia32/InterlockedCompareExchange32.s create mode 100644 MdePkg/Library/BaseLib/ia32/InterlockedCompareExchange64.asm create mode 100644 MdePkg/Library/BaseLib/ia32/InterlockedCompareExchange64.s create mode 100644 MdePkg/Library/BaseLib/ia32/InterlockedDecrement.asm create mode 100644 MdePkg/Library/BaseLib/ia32/InterlockedDecrement.s create mode 100644 MdePkg/Library/BaseLib/ia32/InterlockedIncrement.asm create mode 100644 MdePkg/Library/BaseLib/ia32/InterlockedIncrement.s create mode 100644 MdePkg/Library/BaseLib/ia32/Invd.asm create mode 100644 MdePkg/Library/BaseLib/ia32/Invd.s create mode 100644 MdePkg/Library/BaseLib/ia32/LRotU64.asm create mode 100644 MdePkg/Library/BaseLib/ia32/LRotU64.s create mode 100644 MdePkg/Library/BaseLib/ia32/LShiftU64.asm create mode 100644 MdePkg/Library/BaseLib/ia32/LShiftU64.s create mode 100644 MdePkg/Library/BaseLib/ia32/LongJump.asm create mode 100644 MdePkg/Library/BaseLib/ia32/LongJump.s create mode 100644 MdePkg/Library/BaseLib/ia32/ModU64x32.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ModU64x32.s create mode 100644 MdePkg/Library/BaseLib/ia32/Monitor.asm create mode 100644 MdePkg/Library/BaseLib/ia32/Monitor.s create mode 100644 MdePkg/Library/BaseLib/ia32/MultU64x32.asm create mode 100644 MdePkg/Library/BaseLib/ia32/MultU64x32.s create mode 100644 MdePkg/Library/BaseLib/ia32/MultU64x64.asm create mode 100644 MdePkg/Library/BaseLib/ia32/MultU64x64.s create mode 100644 MdePkg/Library/BaseLib/ia32/Mwait.asm create mode 100644 MdePkg/Library/BaseLib/ia32/Mwait.s create mode 100644 MdePkg/Library/BaseLib/ia32/Non-existing.c create mode 100644 MdePkg/Library/BaseLib/ia32/RRotU64.asm create mode 100644 MdePkg/Library/BaseLib/ia32/RRotU64.s create mode 100644 MdePkg/Library/BaseLib/ia32/RShiftU64.asm create mode 100644 MdePkg/Library/BaseLib/ia32/RShiftU64.s create mode 100644 MdePkg/Library/BaseLib/ia32/ReadCr0.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadCr0.s create mode 100644 MdePkg/Library/BaseLib/ia32/ReadCr2.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadCr2.s create mode 100644 MdePkg/Library/BaseLib/ia32/ReadCr3.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadCr3.s create mode 100644 MdePkg/Library/BaseLib/ia32/ReadCr4.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadCr4.s create mode 100644 MdePkg/Library/BaseLib/ia32/ReadCs.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadCs.s create mode 100644 MdePkg/Library/BaseLib/ia32/ReadDr0.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadDr0.s create mode 100644 MdePkg/Library/BaseLib/ia32/ReadDr1.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadDr1.s create mode 100644 MdePkg/Library/BaseLib/ia32/ReadDr2.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadDr2.s create mode 100644 MdePkg/Library/BaseLib/ia32/ReadDr3.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadDr3.s create mode 100644 MdePkg/Library/BaseLib/ia32/ReadDr4.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadDr5.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadDr6.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadDr6.s create mode 100644 MdePkg/Library/BaseLib/ia32/ReadDr7.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadDr7.s create mode 100644 MdePkg/Library/BaseLib/ia32/ReadDs.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadDs.s create mode 100644 MdePkg/Library/BaseLib/ia32/ReadEflags.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadEflags.s create mode 100644 MdePkg/Library/BaseLib/ia32/ReadEs.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadEs.s create mode 100644 MdePkg/Library/BaseLib/ia32/ReadFs.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadFs.s create mode 100644 MdePkg/Library/BaseLib/ia32/ReadGdtr.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadGdtr.s create mode 100644 MdePkg/Library/BaseLib/ia32/ReadGs.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadGs.s create mode 100644 MdePkg/Library/BaseLib/ia32/ReadIdtr.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadIdtr.s create mode 100644 MdePkg/Library/BaseLib/ia32/ReadLdtr.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadLdtr.s create mode 100644 MdePkg/Library/BaseLib/ia32/ReadMm0.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadMm0.s create mode 100644 MdePkg/Library/BaseLib/ia32/ReadMm1.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadMm1.s create mode 100644 MdePkg/Library/BaseLib/ia32/ReadMm2.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadMm2.s create mode 100644 MdePkg/Library/BaseLib/ia32/ReadMm3.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadMm3.s create mode 100644 MdePkg/Library/BaseLib/ia32/ReadMm4.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadMm4.s create mode 100644 MdePkg/Library/BaseLib/ia32/ReadMm5.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadMm5.s create mode 100644 MdePkg/Library/BaseLib/ia32/ReadMm6.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadMm6.s create mode 100644 MdePkg/Library/BaseLib/ia32/ReadMm7.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadMm7.s create mode 100644 MdePkg/Library/BaseLib/ia32/ReadMsr64.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadMsr64.s create mode 100644 MdePkg/Library/BaseLib/ia32/ReadPmc.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadPmc.s create mode 100644 MdePkg/Library/BaseLib/ia32/ReadSs.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadSs.s create mode 100644 MdePkg/Library/BaseLib/ia32/ReadTr.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadTr.s create mode 100644 MdePkg/Library/BaseLib/ia32/ReadTsc.asm create mode 100644 MdePkg/Library/BaseLib/ia32/ReadTsc.s create mode 100644 MdePkg/Library/BaseLib/ia32/SetJump.asm create mode 100644 MdePkg/Library/BaseLib/ia32/SetJump.s create mode 100644 MdePkg/Library/BaseLib/ia32/SwapBytes64.asm create mode 100644 MdePkg/Library/BaseLib/ia32/SwitchStack.c create mode 100644 MdePkg/Library/BaseLib/ia32/Thunk16.asm create mode 100644 MdePkg/Library/BaseLib/ia32/Thunk16.s create mode 100644 MdePkg/Library/BaseLib/ia32/Wbinvd.asm create mode 100644 MdePkg/Library/BaseLib/ia32/Wbinvd.s create mode 100644 MdePkg/Library/BaseLib/ia32/WriteCr0.asm create mode 100644 MdePkg/Library/BaseLib/ia32/WriteCr0.s create mode 100644 MdePkg/Library/BaseLib/ia32/WriteCr2.asm create mode 100644 MdePkg/Library/BaseLib/ia32/WriteCr2.s create mode 100644 MdePkg/Library/BaseLib/ia32/WriteCr3.asm create mode 100644 MdePkg/Library/BaseLib/ia32/WriteCr3.s create mode 100644 MdePkg/Library/BaseLib/ia32/WriteCr4.asm create mode 100644 MdePkg/Library/BaseLib/ia32/WriteCr4.s create mode 100644 MdePkg/Library/BaseLib/ia32/WriteDr0.asm create mode 100644 MdePkg/Library/BaseLib/ia32/WriteDr0.s create mode 100644 MdePkg/Library/BaseLib/ia32/WriteDr1.asm create mode 100644 MdePkg/Library/BaseLib/ia32/WriteDr1.s create mode 100644 MdePkg/Library/BaseLib/ia32/WriteDr2.asm create mode 100644 MdePkg/Library/BaseLib/ia32/WriteDr2.s create mode 100644 MdePkg/Library/BaseLib/ia32/WriteDr3.asm create mode 100644 MdePkg/Library/BaseLib/ia32/WriteDr3.s create mode 100644 MdePkg/Library/BaseLib/ia32/WriteDr4.asm create mode 100644 MdePkg/Library/BaseLib/ia32/WriteDr5.asm create mode 100644 MdePkg/Library/BaseLib/ia32/WriteDr6.asm create mode 100644 MdePkg/Library/BaseLib/ia32/WriteDr6.s create mode 100644 MdePkg/Library/BaseLib/ia32/WriteDr7.asm create mode 100644 MdePkg/Library/BaseLib/ia32/WriteDr7.s create mode 100644 MdePkg/Library/BaseLib/ia32/WriteGdtr.asm create mode 100644 MdePkg/Library/BaseLib/ia32/WriteGdtr.s create mode 100644 MdePkg/Library/BaseLib/ia32/WriteIdtr.asm create mode 100644 MdePkg/Library/BaseLib/ia32/WriteIdtr.s create mode 100644 MdePkg/Library/BaseLib/ia32/WriteLdtr.asm create mode 100644 MdePkg/Library/BaseLib/ia32/WriteLdtr.s create mode 100644 MdePkg/Library/BaseLib/ia32/WriteMm0.asm create mode 100644 MdePkg/Library/BaseLib/ia32/WriteMm0.s create mode 100644 MdePkg/Library/BaseLib/ia32/WriteMm1.asm create mode 100644 MdePkg/Library/BaseLib/ia32/WriteMm1.s create mode 100644 MdePkg/Library/BaseLib/ia32/WriteMm2.asm create mode 100644 MdePkg/Library/BaseLib/ia32/WriteMm2.s create mode 100644 MdePkg/Library/BaseLib/ia32/WriteMm3.asm create mode 100644 MdePkg/Library/BaseLib/ia32/WriteMm3.s create mode 100644 MdePkg/Library/BaseLib/ia32/WriteMm4.asm create mode 100644 MdePkg/Library/BaseLib/ia32/WriteMm4.s create mode 100644 MdePkg/Library/BaseLib/ia32/WriteMm5.asm create mode 100644 MdePkg/Library/BaseLib/ia32/WriteMm5.s create mode 100644 MdePkg/Library/BaseLib/ia32/WriteMm6.asm create mode 100644 MdePkg/Library/BaseLib/ia32/WriteMm6.s create mode 100644 MdePkg/Library/BaseLib/ia32/WriteMm7.asm create mode 100644 MdePkg/Library/BaseLib/ia32/WriteMm7.s create mode 100644 MdePkg/Library/BaseLib/ia32/WriteMsr32.asm create mode 100644 MdePkg/Library/BaseLib/ia32/WriteMsr32.s create mode 100644 MdePkg/Library/BaseLib/ia32/WriteMsr64.asm create mode 100644 MdePkg/Library/BaseLib/ia32/WriteMsr64.s create mode 100644 MdePkg/Library/BaseLib/x64/CpuBreakpoint.asm create mode 100644 MdePkg/Library/BaseLib/x64/CpuFlushTlb.asm create mode 100644 MdePkg/Library/BaseLib/x64/CpuId.asm create mode 100644 MdePkg/Library/BaseLib/x64/CpuPause.asm create mode 100644 MdePkg/Library/BaseLib/x64/CpuSleep.asm create mode 100644 MdePkg/Library/BaseLib/x64/DisableInterrupts.asm create mode 100644 MdePkg/Library/BaseLib/x64/DisablePaging64.asm create mode 100644 MdePkg/Library/BaseLib/x64/EnableDisableInterrupts.asm create mode 100644 MdePkg/Library/BaseLib/x64/EnableInterrupts.asm create mode 100644 MdePkg/Library/BaseLib/x64/FlushCacheLine.asm create mode 100644 MdePkg/Library/BaseLib/x64/FxRestore.asm create mode 100644 MdePkg/Library/BaseLib/x64/FxSave.asm create mode 100644 MdePkg/Library/BaseLib/x64/InterlockedCompareExchange32.asm create mode 100644 MdePkg/Library/BaseLib/x64/InterlockedCompareExchange64.asm create mode 100644 MdePkg/Library/BaseLib/x64/InterlockedDecrement.asm create mode 100644 MdePkg/Library/BaseLib/x64/InterlockedIncrement.asm create mode 100644 MdePkg/Library/BaseLib/x64/Invd.asm create mode 100644 MdePkg/Library/BaseLib/x64/LongJump.asm create mode 100644 MdePkg/Library/BaseLib/x64/Monitor.asm create mode 100644 MdePkg/Library/BaseLib/x64/Mwait.asm create mode 100644 MdePkg/Library/BaseLib/x64/Non-existing.c create mode 100644 MdePkg/Library/BaseLib/x64/ReadCr0.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadCr2.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadCr3.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadCr4.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadCs.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadDr0.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadDr1.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadDr2.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadDr3.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadDr4.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadDr5.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadDr6.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadDr7.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadDs.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadEflags.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadEs.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadFs.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadGdtr.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadGs.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadIdtr.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadLdtr.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadMm0.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadMm1.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadMm2.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadMm3.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadMm4.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadMm5.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadMm6.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadMm7.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadMsr32.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadMsr64.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadPmc.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadSs.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadTr.asm create mode 100644 MdePkg/Library/BaseLib/x64/ReadTsc.asm create mode 100644 MdePkg/Library/BaseLib/x64/SetJump.asm create mode 100644 MdePkg/Library/BaseLib/x64/SwitchStack.asm create mode 100644 MdePkg/Library/BaseLib/x64/Thunk16.asm create mode 100644 MdePkg/Library/BaseLib/x64/Wbinvd.asm create mode 100644 MdePkg/Library/BaseLib/x64/WriteCr0.asm create mode 100644 MdePkg/Library/BaseLib/x64/WriteCr2.asm create mode 100644 MdePkg/Library/BaseLib/x64/WriteCr3.asm create mode 100644 MdePkg/Library/BaseLib/x64/WriteCr4.asm create mode 100644 MdePkg/Library/BaseLib/x64/WriteDr0.asm create mode 100644 MdePkg/Library/BaseLib/x64/WriteDr1.asm create mode 100644 MdePkg/Library/BaseLib/x64/WriteDr2.asm create mode 100644 MdePkg/Library/BaseLib/x64/WriteDr3.asm create mode 100644 MdePkg/Library/BaseLib/x64/WriteDr4.asm create mode 100644 MdePkg/Library/BaseLib/x64/WriteDr5.asm create mode 100644 MdePkg/Library/BaseLib/x64/WriteDr6.asm create mode 100644 MdePkg/Library/BaseLib/x64/WriteDr7.asm create mode 100644 MdePkg/Library/BaseLib/x64/WriteGdtr.asm create mode 100644 MdePkg/Library/BaseLib/x64/WriteIdtr.asm create mode 100644 MdePkg/Library/BaseLib/x64/WriteLdtr.asm create mode 100644 MdePkg/Library/BaseLib/x64/WriteMm0.asm create mode 100644 MdePkg/Library/BaseLib/x64/WriteMm1.asm create mode 100644 MdePkg/Library/BaseLib/x64/WriteMm2.asm create mode 100644 MdePkg/Library/BaseLib/x64/WriteMm3.asm create mode 100644 MdePkg/Library/BaseLib/x64/WriteMm4.asm create mode 100644 MdePkg/Library/BaseLib/x64/WriteMm5.asm create mode 100644 MdePkg/Library/BaseLib/x64/WriteMm6.asm create mode 100644 MdePkg/Library/BaseLib/x64/WriteMm7.asm create mode 100644 MdePkg/Library/BaseLib/x64/WriteMsr32.asm create mode 100644 MdePkg/Library/BaseLib/x64/WriteMsr64.asm create mode 100644 MdePkg/Library/BaseLib/x86LowLevel.c create mode 100644 MdePkg/Library/BaseLib/x86Thunk.c create mode 100644 MdePkg/Library/BaseMemoryLib/BaseMemoryLib.mbd create mode 100644 MdePkg/Library/BaseMemoryLib/BaseMemoryLib.msa create mode 100644 MdePkg/Library/BaseMemoryLib/CopyMem.c create mode 100644 MdePkg/Library/BaseMemoryLib/MemLibGeneric.c create mode 100644 MdePkg/Library/BaseMemoryLib/MemLibGuid.c create mode 100644 MdePkg/Library/BaseMemoryLib/MemLibWrapper.c create mode 100644 MdePkg/Library/BaseMemoryLib/SetMem.c create mode 100644 MdePkg/Library/BaseMemoryLib/build.xml create mode 100644 MdePkg/Library/BaseMemoryLibMmx/BaseMemoryLibMmx.mbd create mode 100644 MdePkg/Library/BaseMemoryLibMmx/BaseMemoryLibMmx.msa create mode 100644 MdePkg/Library/BaseMemoryLibMmx/MemLibGuid.c create mode 100644 MdePkg/Library/BaseMemoryLibMmx/MemLibWrapper.c create mode 100644 MdePkg/Library/BaseMemoryLibMmx/build.xml create mode 100644 MdePkg/Library/BaseMemoryLibMmx/ia32/CompareMem.asm create mode 100644 MdePkg/Library/BaseMemoryLibMmx/ia32/CopyMem.asm create mode 100644 MdePkg/Library/BaseMemoryLibMmx/ia32/ScanMem16.asm create mode 100644 MdePkg/Library/BaseMemoryLibMmx/ia32/ScanMem32.asm create mode 100644 MdePkg/Library/BaseMemoryLibMmx/ia32/ScanMem64.asm create mode 100644 MdePkg/Library/BaseMemoryLibMmx/ia32/ScanMem8.asm create mode 100644 MdePkg/Library/BaseMemoryLibMmx/ia32/SetMem.asm create mode 100644 MdePkg/Library/BaseMemoryLibMmx/ia32/SetMem16.asm create mode 100644 MdePkg/Library/BaseMemoryLibMmx/ia32/SetMem32.asm create mode 100644 MdePkg/Library/BaseMemoryLibMmx/ia32/SetMem64.asm create mode 100644 MdePkg/Library/BaseMemoryLibMmx/ia32/ZeroMem.asm create mode 100644 MdePkg/Library/BaseMemoryLibRepStr/BaseMemoryLibRepStr.mbd create mode 100644 MdePkg/Library/BaseMemoryLibRepStr/BaseMemoryLibRepStr.msa create mode 100644 MdePkg/Library/BaseMemoryLibRepStr/Ia32/CompareMem.asm create mode 100644 MdePkg/Library/BaseMemoryLibRepStr/Ia32/CopyMem.asm create mode 100644 MdePkg/Library/BaseMemoryLibRepStr/Ia32/ScanMem16.asm create mode 100644 MdePkg/Library/BaseMemoryLibRepStr/Ia32/ScanMem32.asm create mode 100644 MdePkg/Library/BaseMemoryLibRepStr/Ia32/ScanMem64.asm create mode 100644 MdePkg/Library/BaseMemoryLibRepStr/Ia32/ScanMem8.asm create mode 100644 MdePkg/Library/BaseMemoryLibRepStr/Ia32/SetMem.asm create mode 100644 MdePkg/Library/BaseMemoryLibRepStr/Ia32/SetMem16.asm create mode 100644 MdePkg/Library/BaseMemoryLibRepStr/Ia32/SetMem32.asm create mode 100644 MdePkg/Library/BaseMemoryLibRepStr/Ia32/SetMem64.asm create mode 100644 MdePkg/Library/BaseMemoryLibRepStr/Ia32/ZeroMem.asm create mode 100644 MdePkg/Library/BaseMemoryLibRepStr/MemLibGuid.c create mode 100644 MdePkg/Library/BaseMemoryLibRepStr/MemLibWrapper.c create mode 100644 MdePkg/Library/BaseMemoryLibRepStr/build.xml create mode 100644 MdePkg/Library/BaseMemoryLibRepStr/x64/CompareMem.asm create mode 100644 MdePkg/Library/BaseMemoryLibRepStr/x64/CopyMem.asm create mode 100644 MdePkg/Library/BaseMemoryLibRepStr/x64/ScanMem16.asm create mode 100644 MdePkg/Library/BaseMemoryLibRepStr/x64/ScanMem32.asm create mode 100644 MdePkg/Library/BaseMemoryLibRepStr/x64/ScanMem64.asm create mode 100644 MdePkg/Library/BaseMemoryLibRepStr/x64/ScanMem8.asm create mode 100644 MdePkg/Library/BaseMemoryLibRepStr/x64/SetMem.asm create mode 100644 MdePkg/Library/BaseMemoryLibRepStr/x64/SetMem16.asm create mode 100644 MdePkg/Library/BaseMemoryLibRepStr/x64/SetMem32.asm create mode 100644 MdePkg/Library/BaseMemoryLibRepStr/x64/SetMem64.asm create mode 100644 MdePkg/Library/BaseMemoryLibRepStr/x64/ZeroMem.asm create mode 100644 MdePkg/Library/BaseMemoryLibSse2/BaseMemoryLibSse2.mbd create mode 100644 MdePkg/Library/BaseMemoryLibSse2/BaseMemoryLibSse2.msa create mode 100644 MdePkg/Library/BaseMemoryLibSse2/MemLibGuid.c create mode 100644 MdePkg/Library/BaseMemoryLibSse2/MemLibWrapper.c create mode 100644 MdePkg/Library/BaseMemoryLibSse2/build.xml create mode 100644 MdePkg/Library/BaseMemoryLibSse2/ia32/CompareMem.asm create mode 100644 MdePkg/Library/BaseMemoryLibSse2/ia32/CopyMem.asm create mode 100644 MdePkg/Library/BaseMemoryLibSse2/ia32/ScanMem16.asm create mode 100644 MdePkg/Library/BaseMemoryLibSse2/ia32/ScanMem32.asm create mode 100644 MdePkg/Library/BaseMemoryLibSse2/ia32/ScanMem64.asm create mode 100644 MdePkg/Library/BaseMemoryLibSse2/ia32/ScanMem8.asm create mode 100644 MdePkg/Library/BaseMemoryLibSse2/ia32/SetMem.asm create mode 100644 MdePkg/Library/BaseMemoryLibSse2/ia32/SetMem16.asm create mode 100644 MdePkg/Library/BaseMemoryLibSse2/ia32/SetMem32.asm create mode 100644 MdePkg/Library/BaseMemoryLibSse2/ia32/SetMem64.asm create mode 100644 MdePkg/Library/BaseMemoryLibSse2/ia32/ZeroMem.asm create mode 100644 MdePkg/Library/BaseMemoryLibSse2/x64/CompareMem.asm create mode 100644 MdePkg/Library/BaseMemoryLibSse2/x64/CopyMem.asm create mode 100644 MdePkg/Library/BaseMemoryLibSse2/x64/ScanMem16.asm create mode 100644 MdePkg/Library/BaseMemoryLibSse2/x64/ScanMem32.asm create mode 100644 MdePkg/Library/BaseMemoryLibSse2/x64/ScanMem64.asm create mode 100644 MdePkg/Library/BaseMemoryLibSse2/x64/ScanMem8.asm create mode 100644 MdePkg/Library/BaseMemoryLibSse2/x64/SetMem.asm create mode 100644 MdePkg/Library/BaseMemoryLibSse2/x64/SetMem16.asm create mode 100644 MdePkg/Library/BaseMemoryLibSse2/x64/SetMem32.asm create mode 100644 MdePkg/Library/BaseMemoryLibSse2/x64/SetMem64.asm create mode 100644 MdePkg/Library/BaseMemoryLibSse2/x64/ZeroMem.asm create mode 100644 MdePkg/Library/BasePcdLibNull/BasePcdLibNull.mbd create mode 100644 MdePkg/Library/BasePcdLibNull/BasePcdLibNull.msa create mode 100644 MdePkg/Library/BasePcdLibNull/PcdLib.c create mode 100644 MdePkg/Library/BasePcdLibNull/build.xml create mode 100644 MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.mbd create mode 100644 MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.msa create mode 100644 MdePkg/Library/BasePciCf8Lib/PciLib.c create mode 100644 MdePkg/Library/BasePciCf8Lib/build.xml create mode 100644 MdePkg/Library/BasePciExpressLib/BasePciExpressLib.mbd create mode 100644 MdePkg/Library/BasePciExpressLib/BasePciExpressLib.msa create mode 100644 MdePkg/Library/BasePciExpressLib/PciLib.c create mode 100644 MdePkg/Library/BasePciExpressLib/build.xml create mode 100644 MdePkg/Library/BasePciLibCf8/BasePciLibCf8.mbd create mode 100644 MdePkg/Library/BasePciLibCf8/BasePciLibCf8.msa create mode 100644 MdePkg/Library/BasePciLibCf8/PciLib.c create mode 100644 MdePkg/Library/BasePciLibCf8/build.xml create mode 100644 MdePkg/Library/BasePciLibPciExpress/BasePciLibPciExpress.mbd create mode 100644 MdePkg/Library/BasePciLibPciExpress/BasePciLibPciExpress.msa create mode 100644 MdePkg/Library/BasePciLibPciExpress/PciLib.c create mode 100644 MdePkg/Library/BasePciLibPciExpress/build.xml create mode 100644 MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.mbd create mode 100644 MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.msa create mode 100644 MdePkg/Library/BasePeCoffGetEntryPointLib/PeCoffGetEntryPoint.c create mode 100644 MdePkg/Library/BasePeCoffGetEntryPointLib/build.xml create mode 100644 MdePkg/Library/BasePeCoffLib/BasePeCoff.c create mode 100644 MdePkg/Library/BasePeCoffLib/BasePeCoffLib.mbd create mode 100644 MdePkg/Library/BasePeCoffLib/BasePeCoffLib.msa create mode 100644 MdePkg/Library/BasePeCoffLib/Ebc/PeCoffLoaderEx.c create mode 100644 MdePkg/Library/BasePeCoffLib/Ia32/PeCoffLoaderEx.c create mode 100644 MdePkg/Library/BasePeCoffLib/Ipf/PeCoffLoaderEx.c create mode 100644 MdePkg/Library/BasePeCoffLib/build.xml create mode 100644 MdePkg/Library/BasePeCoffLib/x64/PeCoffLoaderEx.c create mode 100644 MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.mbd create mode 100644 MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.msa create mode 100644 MdePkg/Library/BasePerformanceLibNull/PerformanceLib.c create mode 100644 MdePkg/Library/BasePerformanceLibNull/build.xml create mode 100644 MdePkg/Library/BasePrintLib/BasePrintLib.mbd create mode 100644 MdePkg/Library/BasePrintLib/BasePrintLib.msa create mode 100644 MdePkg/Library/BasePrintLib/PrintLib.c create mode 100644 MdePkg/Library/BasePrintLib/PrintLibInternal.c create mode 100644 MdePkg/Library/BasePrintLib/PrintLibInternal.h create mode 100644 MdePkg/Library/BasePrintLib/build.xml create mode 100644 MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.mbd create mode 100644 MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.msa create mode 100644 MdePkg/Library/BaseReportStatusCodeLibNull/PostCode.c create mode 100644 MdePkg/Library/BaseReportStatusCodeLibNull/ReportStatusCodeLib.c create mode 100644 MdePkg/Library/BaseReportStatusCodeLibNull/build.xml create mode 100644 MdePkg/Library/BaseSmbusLib/BaseSmbusLib.mbd create mode 100644 MdePkg/Library/BaseSmbusLib/BaseSmbusLib.msa create mode 100644 MdePkg/Library/BaseSmbusLib/SmbusLib.c create mode 100644 MdePkg/Library/BaseSmbusLib/build.xml create mode 100644 MdePkg/Library/BaseTimerLibLocalApic/BaseTimerLibLocalApic.mbd create mode 100644 MdePkg/Library/BaseTimerLibLocalApic/BaseTimerLibLocalApic.msa create mode 100644 MdePkg/Library/BaseTimerLibLocalApic/Ipf/CallPalProc.s create mode 100644 MdePkg/Library/BaseTimerLibLocalApic/Ipf/IpfTimerLib.c create mode 100644 MdePkg/Library/BaseTimerLibLocalApic/Ipf/ReadItc.s create mode 100644 MdePkg/Library/BaseTimerLibLocalApic/build.xml create mode 100644 MdePkg/Library/BaseTimerLibLocalApic/x86TimerLib.c create mode 100644 MdePkg/Library/BaseUefiDecompressLib/BaseUefiDecompressLib.c create mode 100644 MdePkg/Library/BaseUefiDecompressLib/BaseUefiDecompressLib.mbd create mode 100644 MdePkg/Library/BaseUefiDecompressLib/BaseUefiDecompressLib.msa create mode 100644 MdePkg/Library/BaseUefiDecompressLib/build.xml create mode 100644 MdePkg/Library/DxeCoreEntryPoint/DxeCoreEntryPoint.c create mode 100644 MdePkg/Library/DxeCoreEntryPoint/DxeCoreEntryPoint.mbd create mode 100644 MdePkg/Library/DxeCoreEntryPoint/DxeCoreEntryPoint.msa create mode 100644 MdePkg/Library/DxeCoreEntryPoint/build.xml create mode 100644 MdePkg/Library/DxeCoreHobLib/DxeCoreHobLib.mbd create mode 100644 MdePkg/Library/DxeCoreHobLib/DxeCoreHobLib.msa create mode 100644 MdePkg/Library/DxeCoreHobLib/HobLib.c create mode 100644 MdePkg/Library/DxeCoreHobLib/build.xml create mode 100644 MdePkg/Library/DxeHobLib/DxeHobLib.mbd create mode 100644 MdePkg/Library/DxeHobLib/DxeHobLib.msa create mode 100644 MdePkg/Library/DxeHobLib/HobLib.c create mode 100644 MdePkg/Library/DxeHobLib/build.xml create mode 100644 MdePkg/Library/DxeIoLibCpuIo/DxeIoLibCpuIo.mbd create mode 100644 MdePkg/Library/DxeIoLibCpuIo/DxeIoLibCpuIo.msa create mode 100644 MdePkg/Library/DxeIoLibCpuIo/IoHighLevel.c create mode 100644 MdePkg/Library/DxeIoLibCpuIo/IoLib.c create mode 100644 MdePkg/Library/DxeIoLibCpuIo/build.xml create mode 100644 MdePkg/Library/DxeMemoryAllocationLib/DxeMemoryAllocationLib.mbd create mode 100644 MdePkg/Library/DxeMemoryAllocationLib/DxeMemoryAllocationLib.msa create mode 100644 MdePkg/Library/DxeMemoryAllocationLib/MemoryAllocationLib.c create mode 100644 MdePkg/Library/DxeMemoryAllocationLib/build.xml create mode 100644 MdePkg/Library/DxePcdLib/DxePcdLib.c create mode 100644 MdePkg/Library/DxePcdLib/DxePcdLib.mbd create mode 100644 MdePkg/Library/DxePcdLib/DxePcdLib.msa create mode 100644 MdePkg/Library/DxePcdLib/build.xml create mode 100644 MdePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.mbd create mode 100644 MdePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.msa create mode 100644 MdePkg/Library/DxeReportStatusCodeLib/PostCode.c create mode 100644 MdePkg/Library/DxeReportStatusCodeLib/ReportStatusCodeLib.c create mode 100644 MdePkg/Library/DxeReportStatusCodeLib/build.xml create mode 100644 MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.c create mode 100644 MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.mbd create mode 100644 MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.msa create mode 100644 MdePkg/Library/DxeServicesTableLib/build.xml create mode 100644 MdePkg/Library/DxeSmbusLib/DxeSmbusLib.c create mode 100644 MdePkg/Library/DxeSmbusLib/DxeSmbusLib.mbd create mode 100644 MdePkg/Library/DxeSmbusLib/DxeSmbusLib.msa create mode 100644 MdePkg/Library/DxeSmbusLib/InternalSmbusLib.h create mode 100644 MdePkg/Library/DxeSmbusLib/SmbusLib.c create mode 100644 MdePkg/Library/DxeSmbusLib/build.xml create mode 100644 MdePkg/Library/DxeSmmDriverEntryPoint/DriverEntryPoint.c create mode 100644 MdePkg/Library/DxeSmmDriverEntryPoint/DxeSmmDriverEntryPoint.mbd create mode 100644 MdePkg/Library/DxeSmmDriverEntryPoint/DxeSmmDriverEntryPoint.msa create mode 100644 MdePkg/Library/DxeSmmDriverEntryPoint/build.xml create mode 100644 MdePkg/Library/HiiLib/HiiLib.c create mode 100644 MdePkg/Library/HiiLib/HiiLib.mbd create mode 100644 MdePkg/Library/HiiLib/HiiLib.msa create mode 100644 MdePkg/Library/HiiLib/build.xml create mode 100644 MdePkg/Library/PeiCoreEntryPoint/PeiCoreEntryPoint.c create mode 100644 MdePkg/Library/PeiCoreEntryPoint/PeiCoreEntryPoint.mbd create mode 100644 MdePkg/Library/PeiCoreEntryPoint/PeiCoreEntryPoint.msa create mode 100644 MdePkg/Library/PeiCoreEntryPoint/build.xml create mode 100644 MdePkg/Library/PeiCoreLib/PeiCoreLib.c create mode 100644 MdePkg/Library/PeiCoreLib/PeiCoreLib.mbd create mode 100644 MdePkg/Library/PeiCoreLib/PeiCoreLib.msa create mode 100644 MdePkg/Library/PeiCoreLib/build.xml create mode 100644 MdePkg/Library/PeiHobLib/HobLib.c create mode 100644 MdePkg/Library/PeiHobLib/PeiHobLib.mbd create mode 100644 MdePkg/Library/PeiHobLib/PeiHobLib.msa create mode 100644 MdePkg/Library/PeiHobLib/build.xml create mode 100644 MdePkg/Library/PeiIoLibCpuIo/IoHighLevel.c create mode 100644 MdePkg/Library/PeiIoLibCpuIo/IoLib.c create mode 100644 MdePkg/Library/PeiIoLibCpuIo/PeiIoLibCpuIo.mbd create mode 100644 MdePkg/Library/PeiIoLibCpuIo/PeiIoLibCpuIo.msa create mode 100644 MdePkg/Library/PeiIoLibCpuIo/build.xml create mode 100644 MdePkg/Library/PeiMemoryAllocationLib/MemoryAllocationLib.c create mode 100644 MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.mbd create mode 100644 MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.msa create mode 100644 MdePkg/Library/PeiMemoryAllocationLib/build.xml create mode 100644 MdePkg/Library/PeiMemoryLib/MemLib.c create mode 100644 MdePkg/Library/PeiMemoryLib/MemLibGeneric.c create mode 100644 MdePkg/Library/PeiMemoryLib/MemLibGuid.c create mode 100644 MdePkg/Library/PeiMemoryLib/MemLibWrapper.c create mode 100644 MdePkg/Library/PeiMemoryLib/PeiMemoryLib.mbd create mode 100644 MdePkg/Library/PeiMemoryLib/PeiMemoryLib.msa create mode 100644 MdePkg/Library/PeiMemoryLib/build.xml create mode 100644 MdePkg/Library/PeiPcdLib/PeiPcdLib.c create mode 100644 MdePkg/Library/PeiPcdLib/PeiPcdLib.mbd create mode 100644 MdePkg/Library/PeiPcdLib/PeiPcdLib.msa create mode 100644 MdePkg/Library/PeiPcdLib/build.xml create mode 100644 MdePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.mbd create mode 100644 MdePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.msa create mode 100644 MdePkg/Library/PeiReportStatusCodeLib/PostCode.c create mode 100644 MdePkg/Library/PeiReportStatusCodeLib/ReportStatusCodeLib.c create mode 100644 MdePkg/Library/PeiReportStatusCodeLib/build.xml create mode 100644 MdePkg/Library/PeiResourcePublicationLib/PeiResourcePublicationLib.c create mode 100644 MdePkg/Library/PeiResourcePublicationLib/PeiResourcePublicationLib.mbd create mode 100644 MdePkg/Library/PeiResourcePublicationLib/PeiResourcePublicationLib.msa create mode 100644 MdePkg/Library/PeiResourcePublicationLib/build.xml create mode 100644 MdePkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointer.c create mode 100644 MdePkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.mbd create mode 100644 MdePkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.msa create mode 100644 MdePkg/Library/PeiServicesTablePointerLib/build.xml create mode 100644 MdePkg/Library/PeiServicesTablePointerLibMm7/PeiServicesTablePointer.c create mode 100644 MdePkg/Library/PeiServicesTablePointerLibMm7/PeiServicesTablePointerLibMm7.mbd create mode 100644 MdePkg/Library/PeiServicesTablePointerLibMm7/PeiServicesTablePointerLibMm7.msa create mode 100644 MdePkg/Library/PeiServicesTablePointerLibMm7/build.xml create mode 100644 MdePkg/Library/PeiSmbusLib/InternalSmbusLib.h create mode 100644 MdePkg/Library/PeiSmbusLib/PeiSmbusLib.c create mode 100644 MdePkg/Library/PeiSmbusLib/PeiSmbusLib.mbd create mode 100644 MdePkg/Library/PeiSmbusLib/PeiSmbusLib.msa create mode 100644 MdePkg/Library/PeiSmbusLib/SmbusLib.c create mode 100644 MdePkg/Library/PeiSmbusLib/build.xml create mode 100644 MdePkg/Library/PeimEntryPoint/PeimEntryPoint.c create mode 100644 MdePkg/Library/PeimEntryPoint/PeimEntryPoint.mbd create mode 100644 MdePkg/Library/PeimEntryPoint/PeimEntryPoint.msa create mode 100644 MdePkg/Library/PeimEntryPoint/build.xml create mode 100644 MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.c create mode 100644 MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.mbd create mode 100644 MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.msa create mode 100644 MdePkg/Library/UefiBootServicesTableLib/build.xml create mode 100644 MdePkg/Library/UefiDebugLibConOut/DebugLib.c create mode 100644 MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.mbd create mode 100644 MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.msa create mode 100644 MdePkg/Library/UefiDebugLibConOut/build.xml create mode 100644 MdePkg/Library/UefiDebugLibStdErr/DebugLib.c create mode 100644 MdePkg/Library/UefiDebugLibStdErr/UefiDebugLibStdErr.mbd create mode 100644 MdePkg/Library/UefiDebugLibStdErr/UefiDebugLibStdErr.msa create mode 100644 MdePkg/Library/UefiDebugLibStdErr/build.xml create mode 100644 MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.c create mode 100644 MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.mbd create mode 100644 MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.msa create mode 100644 MdePkg/Library/UefiDevicePathLib/build.xml create mode 100644 MdePkg/Library/UefiDevicePathLibDevicePathProtocol/UefiDevicePathLib.c create mode 100644 MdePkg/Library/UefiDevicePathLibDevicePathProtocol/UefiDevicePathLibDevicePathProtocol.mbd create mode 100644 MdePkg/Library/UefiDevicePathLibDevicePathProtocol/UefiDevicePathLibDevicePathProtocol.msa create mode 100644 MdePkg/Library/UefiDevicePathLibDevicePathProtocol/build.xml create mode 100644 MdePkg/Library/UefiDriverEntryPoint/DriverEntryPoint.c create mode 100644 MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.mbd create mode 100644 MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.msa create mode 100644 MdePkg/Library/UefiDriverEntryPoint/build.xml create mode 100644 MdePkg/Library/UefiDriverModelLib/UefiDriverModelLib.c create mode 100644 MdePkg/Library/UefiDriverModelLib/UefiDriverModelLib.mbd create mode 100644 MdePkg/Library/UefiDriverModelLib/UefiDriverModelLib.msa create mode 100644 MdePkg/Library/UefiDriverModelLib/build.xml create mode 100644 MdePkg/Library/UefiLib/Console.c create mode 100644 MdePkg/Library/UefiLib/UefiLib.c create mode 100644 MdePkg/Library/UefiLib/UefiLib.mbd create mode 100644 MdePkg/Library/UefiLib/UefiLib.msa create mode 100644 MdePkg/Library/UefiLib/UefiNotTiano.c create mode 100644 MdePkg/Library/UefiLib/build.xml create mode 100644 MdePkg/Library/UefiMemoryLib/MemLib.c create mode 100644 MdePkg/Library/UefiMemoryLib/MemLibGeneric.c create mode 100644 MdePkg/Library/UefiMemoryLib/MemLibGuid.c create mode 100644 MdePkg/Library/UefiMemoryLib/MemLibWrapper.c create mode 100644 MdePkg/Library/UefiMemoryLib/UefiMemoryLib.mbd create mode 100644 MdePkg/Library/UefiMemoryLib/UefiMemoryLib.msa create mode 100644 MdePkg/Library/UefiMemoryLib/build.xml create mode 100644 MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.c create mode 100644 MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.mbd create mode 100644 MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.msa create mode 100644 MdePkg/Library/UefiRuntimeServicesTableLib/build.xml create mode 100644 MdePkg/MdePkg.fpd create mode 100644 MdePkg/MdePkg.spd create mode 100644 MdePkg/build.xml create mode 100644 MdePkg/genbuildfile.xml create mode 100644 Start Create Setup Package.bat create mode 100644 Tools/Conf/BuildMacro.xml create mode 100644 Tools/Conf/Common.xml create mode 100644 Tools/Conf/FrameworkDatabase.db create mode 100644 Tools/Conf/debug_efi_flags.txt create mode 100644 Tools/Conf/efi_flags_table.txt create mode 100644 Tools/Conf/gcc_tools.txt create mode 100644 Tools/Conf/gcc_tools_def.txt create mode 100644 Tools/Conf/global_efi_flags.txt create mode 100644 Tools/Conf/intel_tools.txt create mode 100644 Tools/Conf/msft_tools.txt create mode 100644 Tools/Conf/msft_tools_def.txt create mode 100644 Tools/Conf/my_efi_flags.txt create mode 100644 Tools/Conf/release_efi_flags.txt create mode 100644 Tools/Conf/target.txt create mode 100644 Tools/Conf/tools_def.txt create mode 100644 Tools/Conf/winddk_tools.txt create mode 100644 Tools/JavaResources.msa create mode 100644 Tools/Source/Cpptasks/build.xml create mode 100644 Tools/Source/Cpptasks/cpptasks.mf create mode 100644 Tools/Source/Cpptasks/cpptasks.tasks create mode 100644 Tools/Source/Cpptasks/cpptasks.types create mode 100644 Tools/Source/Cpptasks/javadoc.xml create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/AboutCCTask.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/ArchEnum.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/AslcompilerDef.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/AslcompilerEnum.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/AssemblerDef.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/AssemblerEnum.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/CCTask.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/CCTaskProgressMonitor.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/CPUEnum.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/CUtil.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/CompilerDef.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/CompilerEnum.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/CompilerParam.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/DependencyInfo.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/DependencyTable.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/DistributerDef.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/DistributerMap.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/DistributerProtocolEnum.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/FileVisitor.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/LinkerDef.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/LinkerEnum.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/LinkerParam.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/OSFamilyEnum.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/ObjectFileCollector.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/OptimizationEnum.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/OutputTypeEnum.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/PrecompileDef.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/PrecompileExceptDef.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/ProcessorDef.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/ProcessorEnumValue.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/ProcessorParam.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/RuntimeType.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/SourceHistory.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/SubsystemEnum.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/TargetDef.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/TargetHistory.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/TargetHistoryTable.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/TargetInfo.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/TargetMatcher.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/VersionInfo.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/arm/ADSCCompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/arm/ADSLibrarian.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/arm/ADSLinker.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/borland/BorlandCCompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/borland/BorlandCfgParser.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/borland/BorlandLibrarian.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/borland/BorlandLinker.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/borland/BorlandProcessor.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/borland/BorlandResourceCompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/borland/CfgFilenameState.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/borland/ConsumeToSpaceOrNewLine.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/borland/QuoteBranchState.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compaq/CompaqVisualFortranCompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compaq/CompaqVisualFortranLibrarian.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compaq/CompaqVisualFortranLinker.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/AbstractAslcompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/AbstractAssembler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/AbstractCompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/AbstractLinker.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/AbstractProcessor.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/Aslcompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/AslcompilerConfiguration.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/Assembler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/AssemblerConfiguration.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/CaptureStreamHandler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/CommandLineAslcompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/CommandLineAslcompilerConfiguration.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/CommandLineAssembler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/CommandLineAssemblerConfiguration.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/CommandLineCCompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/CommandLineCompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/CommandLineCompilerConfiguration.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/CommandLineFortranCompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/CommandLineLinker.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/CommandLineLinkerConfiguration.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/Compiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/CompilerConfiguration.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/LinkType.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/Linker.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/LinkerConfiguration.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/PrecompilingCommandLineCCompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/PrecompilingCommandLineCompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/PrecompilingCompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/Processor.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/ProcessorConfiguration.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/ProgressMonitor.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/devstudio/DevStudioAslcompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/devstudio/DevStudioAssembler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/devstudio/DevStudioCCompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/devstudio/DevStudioCompatibleCCompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/devstudio/DevStudioCompatibleLibrarian.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/devstudio/DevStudioCompatibleLinker.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/devstudio/DevStudioLibrarian.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/devstudio/DevStudioLinker.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/devstudio/DevStudioMIDLCompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/devstudio/DevStudioProcessor.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/devstudio/DevStudioResourceCompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/gcc/AbstractArLibrarian.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/gcc/AbstractLdLinker.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/gcc/GccAssembler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/gcc/GccCCompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/gcc/GccCompatibleCCompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/gcc/GccLibrarian.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/gcc/GccLinker.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/gcc/GccProcessor.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/gcc/GppLinker.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/gcc/LdLinker.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/gcc/cross/GccCCompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/gcc/cross/GccLibrarian.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/gcc/cross/GccLinker.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/gcc/cross/GccProcessor.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/gcc/cross/GppLinker.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/gcc/cross/LdLinker.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/gcc/cross/sparc_sun_solaris2/GccCCompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/gcc/cross/sparc_sun_solaris2/GccLibrarian.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/gcc/cross/sparc_sun_solaris2/GccLinker.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/gcc/cross/sparc_sun_solaris2/GccProcessor.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/gcc/cross/sparc_sun_solaris2/GppLinker.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/gcc/cross/sparc_sun_solaris2/LdLinker.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/hp/aCCCompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/hp/aCCLinker.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/ibm/VisualAgeCCompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/ibm/VisualAgeLinker.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/intel/IntelLinux32CCompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/intel/IntelLinux32Linker.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/intel/IntelLinux64CCompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/intel/IntelLinux64Linker.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/intel/IntelProcessor.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/intel/IntelWin32Aslcompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/intel/IntelWin32CCompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/intel/IntelWin32Librarian.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/intel/IntelWin32Linker.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/intel/IntelWin64CCompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/os390/OS390CCompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/os390/OS390Linker.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/os390/OS390Processor.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/os400/IccCompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/os400/IccLinker.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/os400/IccProcessor.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/parser/AbstractParser.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/parser/AbstractParserState.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/parser/BranchState.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/parser/CParser.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/parser/CaseInsensitiveLetterState.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/parser/FilenameState.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/parser/FortranParser.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/parser/LetterState.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/parser/Parser.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/parser/PostE.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/parser/WhitespaceOrCaseInsensitiveLetterState.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/parser/WhitespaceOrLetterState.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/sun/C89CCompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/sun/C89Linker.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/sun/C89Processor.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/sun/ForteCCCompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/sun/ForteCCLinker.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/ti/ClxxCCompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/ti/ClxxLibrarian.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/ti/ClxxLinker.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/types/AslcompilerArgument.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/types/AssemblerArgument.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/types/CommandLineArgument.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/types/CompilerArgument.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/types/ConditionalFileSet.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/types/ConditionalPath.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/types/DefineArgument.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/types/DefineSet.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/types/FlexLong.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/types/IncludePath.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/types/LibrarySet.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/types/LibraryTypeEnum.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/types/LinkerArgument.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/types/SystemIncludePath.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/types/SystemLibrarySet.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/types/UndefineArgument.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/userdefine/CommandLineUserDefine.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/userdefine/UserDefineArgument.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/userdefine/UserDefineCompiler.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/userdefine/UserDefineDef.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/userdefine/UserDefineElement.java create mode 100644 Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/userdefine/UserDefineMapping.java create mode 100644 Tools/Source/CreateMdkPkg/MANIFEST.MF create mode 100644 Tools/Source/CreateMdkPkg/build.xml create mode 100644 Tools/Source/CreateMdkPkg/src/org/tianocore/common/Log.java create mode 100644 Tools/Source/CreateMdkPkg/src/org/tianocore/common/Tools.java create mode 100644 Tools/Source/CreateMdkPkg/src/org/tianocore/packaging/FrameworkPkg.java create mode 100644 Tools/Source/CreateMdkPkg/src/org/tianocore/packaging/MdkPkg.java create mode 100644 Tools/Source/CreateMdkPkg/src/org/tianocore/packaging/common/ui/ExitConfirm.java create mode 100644 Tools/Source/CreateMdkPkg/src/org/tianocore/packaging/common/ui/IFrame.java create mode 100644 Tools/Source/CreateMdkPkg/src/org/tianocore/packaging/workspace/command/InstallWorkspace.java create mode 100644 Tools/Source/CreateMdkPkg/src/org/tianocore/packaging/workspace/ui/Finish.java create mode 100644 Tools/Source/CreateMdkPkg/src/org/tianocore/packaging/workspace/ui/LicenseAgreement.java create mode 100644 Tools/Source/CreateMdkPkg/src/org/tianocore/packaging/workspace/ui/SelectDestinationDirectory.java create mode 100644 Tools/Source/CreateMdkPkg/src/org/tianocore/packaging/workspace/ui/Welcome.java create mode 100644 Tools/Source/FrameworkTasks/build.xml create mode 100644 Tools/Source/FrameworkTasks/frameworktasks.tasks create mode 100644 Tools/Source/FrameworkTasks/org/tianocore/framework/tasks/Compress.java create mode 100644 Tools/Source/FrameworkTasks/org/tianocore/framework/tasks/CompressHeader.java create mode 100644 Tools/Source/FrameworkTasks/org/tianocore/framework/tasks/CompressSection.java create mode 100644 Tools/Source/FrameworkTasks/org/tianocore/framework/tasks/Database.java create mode 100644 Tools/Source/FrameworkTasks/org/tianocore/framework/tasks/EfiDefine.java create mode 100644 Tools/Source/FrameworkTasks/org/tianocore/framework/tasks/FfsHeader.java create mode 100644 Tools/Source/FrameworkTasks/org/tianocore/framework/tasks/FfsTypes.java create mode 100644 Tools/Source/FrameworkTasks/org/tianocore/framework/tasks/FileParser.java create mode 100644 Tools/Source/FrameworkTasks/org/tianocore/framework/tasks/FwImageTask.java create mode 100644 Tools/Source/FrameworkTasks/org/tianocore/framework/tasks/GenCRC32SectionTask.java create mode 100644 Tools/Source/FrameworkTasks/org/tianocore/framework/tasks/GenDepexTask.java create mode 100644 Tools/Source/FrameworkTasks/org/tianocore/framework/tasks/GenFfsFileTask.java create mode 100644 Tools/Source/FrameworkTasks/org/tianocore/framework/tasks/GenFvImageTask.java create mode 100644 Tools/Source/FrameworkTasks/org/tianocore/framework/tasks/GenSectionTask.java create mode 100644 Tools/Source/FrameworkTasks/org/tianocore/framework/tasks/GuidChkTask.java create mode 100644 Tools/Source/FrameworkTasks/org/tianocore/framework/tasks/IncludePath.java create mode 100644 Tools/Source/FrameworkTasks/org/tianocore/framework/tasks/Input.java create mode 100644 Tools/Source/FrameworkTasks/org/tianocore/framework/tasks/InputFile.java create mode 100644 Tools/Source/FrameworkTasks/org/tianocore/framework/tasks/MakeDeps.java create mode 100644 Tools/Source/FrameworkTasks/org/tianocore/framework/tasks/NestElement.java create mode 100644 Tools/Source/FrameworkTasks/org/tianocore/framework/tasks/SectFile.java create mode 100644 Tools/Source/FrameworkTasks/org/tianocore/framework/tasks/Section.java create mode 100644 Tools/Source/FrameworkTasks/org/tianocore/framework/tasks/SetStampTask.java create mode 100644 Tools/Source/FrameworkTasks/org/tianocore/framework/tasks/SkipExt.java create mode 100644 Tools/Source/FrameworkTasks/org/tianocore/framework/tasks/StrGatherTask.java create mode 100644 Tools/Source/FrameworkTasks/org/tianocore/framework/tasks/Tool.java create mode 100644 Tools/Source/FrameworkTasks/org/tianocore/framework/tasks/ToolArg.java create mode 100644 Tools/Source/FrameworkTasks/org/tianocore/framework/tasks/VfrCompilerTask.java create mode 100644 Tools/Source/GenBuild/GenBuild.tasks create mode 100644 Tools/Source/GenBuild/build.xml create mode 100644 Tools/Source/GenBuild/org/tianocore/build/ExpandTask.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/FfsProcess.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/FileProcess.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/GenBuildTask.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/OutputDirSetupTask.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/autogen/AutoGen.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/autogen/AutogenLibOrder.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/autogen/CommonDefinition.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/fpd/FpdModuleIdentification.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/fpd/FpdParserTask.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/global/DpFile.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/global/DpFileList.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/global/GlobalData.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/global/GlobalShare.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/global/LibBuildFileGenerator.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/global/ModuleIdentification.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/global/OnDependency.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/global/OutputManager.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/global/OverrideProcess.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/global/Spd.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/global/SurfaceAreaParser.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/global/SurfaceAreaQuery.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/global/VariableTask.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/pcd/action/ActionMessage.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/pcd/action/BuildAction.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/pcd/action/CollectPCDAction.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/pcd/action/PCDAutoGenAction.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/pcd/action/ShowPCDDatabaseAction.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/pcd/action/UIAction.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/pcd/entity/MemoryDatabaseManager.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/pcd/entity/SkuInstance.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/pcd/entity/Token.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/pcd/entity/UsageInstance.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/pcd/exception/BuildActionException.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/pcd/exception/EntityException.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/pcd/exception/UIException.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/pcd/ui/PCDDatabaseFrame.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/toolchain/ConfigReader.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/toolchain/ToolChainFactory.java create mode 100644 Tools/Source/GenBuild/org/tianocore/build/toolchain/ToolChainTask.java create mode 100644 Tools/Source/ModuleEditor/MANIFEST.MF create mode 100644 Tools/Source/ModuleEditor/build.xml create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/common/DataType.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/common/DataValidation.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/common/IFileFilter.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/common/Log.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/common/Tools.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/packaging/common/ui/ExitConfirm.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/packaging/common/ui/IComboBox.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/packaging/common/ui/IDefaultMutableTreeNode.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/packaging/common/ui/IDesktopManager.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/packaging/common/ui/IDialog.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/packaging/common/ui/IFrame.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/packaging/common/ui/IInternalFrame.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/packaging/common/ui/ITree.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/packaging/common/ui/StarLabel.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/packaging/module/ui/MbdHeader.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/packaging/module/ui/MbdLibHeader.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/packaging/module/ui/MbdLibraries.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/packaging/module/ui/ModuleAbout.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/packaging/module/ui/ModuleBootModes.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/packaging/module/ui/ModuleDataHubs.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/packaging/module/ui/ModuleEvents.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/packaging/module/ui/ModuleExterns.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/packaging/module/ui/ModuleFormsets.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/packaging/module/ui/ModuleGuids.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/packaging/module/ui/ModuleHobs.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/packaging/module/ui/ModuleIncludes.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/packaging/module/ui/ModuleLibraryClassDefinitions.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/packaging/module/ui/ModuleMain.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/packaging/module/ui/ModulePCDs.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/packaging/module/ui/ModulePpis.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/packaging/module/ui/ModuleProtocols.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/packaging/module/ui/ModuleSourceFiles.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/packaging/module/ui/ModuleSystemTables.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/packaging/module/ui/ModuleVariables.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/packaging/module/ui/MsaHeader.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/packaging/module/ui/MsaLibHeader.java create mode 100644 Tools/Source/ModuleEditor/src/org/tianocore/packaging/workspace/common/Workspace.java create mode 100644 Tools/Source/PackageEditor/MANIFEST.MF create mode 100644 Tools/Source/PackageEditor/build.xml create mode 100644 Tools/Source/PackageEditor/src/org/tianocore/common/Tools.java create mode 100644 Tools/Source/PackageEditor/src/org/tianocore/packaging/CreateFdp.java create mode 100644 Tools/Source/PackageEditor/src/org/tianocore/packaging/DbFileContents.java create mode 100644 Tools/Source/PackageEditor/src/org/tianocore/packaging/ForceInstallPkg.java create mode 100644 Tools/Source/PackageEditor/src/org/tianocore/packaging/FrameworkPkg.java create mode 100644 Tools/Source/PackageEditor/src/org/tianocore/packaging/GuiPkgInstall.java create mode 100644 Tools/Source/PackageEditor/src/org/tianocore/packaging/GuiPkgUninstall.java create mode 100644 Tools/Source/PackageEditor/src/org/tianocore/packaging/ManifestContents.java create mode 100644 Tools/Source/PackageEditor/src/org/tianocore/packaging/ModalFrameUtil.java create mode 100644 Tools/Source/PackageEditor/src/org/tianocore/packaging/PackageAction.java create mode 100644 Tools/Source/PackageEditor/src/org/tianocore/packaging/PackageGuids.java create mode 100644 Tools/Source/PackageEditor/src/org/tianocore/packaging/PackageLibraryClass.java create mode 100644 Tools/Source/PackageEditor/src/org/tianocore/packaging/PackageMsaFile.java create mode 100644 Tools/Source/PackageEditor/src/org/tianocore/packaging/PackageNew.java create mode 100644 Tools/Source/PackageEditor/src/org/tianocore/packaging/PackagePCD.java create mode 100644 Tools/Source/PackageEditor/src/org/tianocore/packaging/PackagePkgHeader.java create mode 100644 Tools/Source/PackageEditor/src/org/tianocore/packaging/PackagePpi.java create mode 100644 Tools/Source/PackageEditor/src/org/tianocore/packaging/PackageProtocols.java create mode 100644 Tools/Source/PackageEditor/src/org/tianocore/packaging/PackagingMain.java create mode 100644 Tools/Source/PackageEditor/src/org/tianocore/packaging/PkgInstallTypeChooser.java create mode 100644 Tools/Source/PackageEditor/src/org/tianocore/packaging/SpdFileContents.java create mode 100644 Tools/Source/PackageEditor/src/org/tianocore/packaging/UpdateAction.java create mode 100644 Tools/Source/PackageEditor/src/org/tianocore/packaging/UpdateGuids.java create mode 100644 Tools/Source/PackageEditor/src/org/tianocore/packaging/UpdateLibraryClass.java create mode 100644 Tools/Source/PackageEditor/src/org/tianocore/packaging/UpdateMsaFile.java create mode 100644 Tools/Source/PackageEditor/src/org/tianocore/packaging/UpdateNew.java create mode 100644 Tools/Source/PackageEditor/src/org/tianocore/packaging/UpdatePCD.java create mode 100644 Tools/Source/PackageEditor/src/org/tianocore/packaging/UpdatePkgHeader.java create mode 100644 Tools/Source/PackageEditor/src/org/tianocore/packaging/UpdatePpi.java create mode 100644 Tools/Source/PackageEditor/src/org/tianocore/packaging/UpdateProtocols.java create mode 100644 Tools/Source/PackageEditor/src/org/tianocore/packaging/common/ui/StarLabel.java create mode 100644 Tools/Source/Prototype/Auto.java create mode 100644 Tools/Source/Prototype/Component.java create mode 100644 Tools/Source/Prototype/DAG.java create mode 100644 Tools/Source/Prototype/Database.java create mode 100644 Tools/Source/Prototype/GuidDecl.java create mode 100644 Tools/Source/Prototype/LibClass.java create mode 100644 Tools/Source/Prototype/LibInst.java create mode 100644 Tools/Source/Prototype/Module.java create mode 100644 Tools/Source/Prototype/Package.java create mode 100644 Tools/Source/Prototype/PpiDecl.java create mode 100644 Tools/Source/Prototype/ProtocolDecl.java create mode 100644 Tools/Source/Prototype/TSort.java create mode 100644 Tools/Source/Prototype/build.xml create mode 100644 Tools/Source/SurfaceArea/build.xml create mode 100644 Tools/Source/TianoTools/Common/CommonLib.c create mode 100644 Tools/Source/TianoTools/Common/CommonLib.h create mode 100644 Tools/Source/TianoTools/Common/Crc32.c create mode 100644 Tools/Source/TianoTools/Common/Crc32.h create mode 100644 Tools/Source/TianoTools/Common/EfiCompress.c create mode 100644 Tools/Source/TianoTools/Common/EfiCompress.h create mode 100644 Tools/Source/TianoTools/Common/EfiCustomizedCompress.h create mode 100644 Tools/Source/TianoTools/Common/EfiDecompress.c create mode 100644 Tools/Source/TianoTools/Common/EfiDecompress.h create mode 100644 Tools/Source/TianoTools/Common/EfiUtilityMsgs.c create mode 100644 Tools/Source/TianoTools/Common/EfiUtilityMsgs.h create mode 100644 Tools/Source/TianoTools/Common/FvLib.c create mode 100644 Tools/Source/TianoTools/Common/FvLib.h create mode 100644 Tools/Source/TianoTools/Common/MyAlloc.c create mode 100644 Tools/Source/TianoTools/Common/MyAlloc.h create mode 100644 Tools/Source/TianoTools/Common/ParseInf.c create mode 100644 Tools/Source/TianoTools/Common/ParseInf.h create mode 100644 Tools/Source/TianoTools/Common/PeiLib/Debug.c create mode 100644 Tools/Source/TianoTools/Common/PeiLib/Decompress.c create mode 100644 Tools/Source/TianoTools/Common/PeiLib/Hob/Hob.c create mode 100644 Tools/Source/TianoTools/Common/PeiLib/Ipf/PeCoffLoaderEx.c create mode 100644 Tools/Source/TianoTools/Common/PeiLib/Ipf/PeCoffLoaderEx.h create mode 100644 Tools/Source/TianoTools/Common/PeiLib/Ipf/PerformancePrimitives.s create mode 100644 Tools/Source/TianoTools/Common/PeiLib/Ipf/SwitchStack.s create mode 100644 Tools/Source/TianoTools/Common/PeiLib/Ipf/asm.h create mode 100644 Tools/Source/TianoTools/Common/PeiLib/Ipf/efijump.h create mode 100644 Tools/Source/TianoTools/Common/PeiLib/Ipf/ia_64gen.h create mode 100644 Tools/Source/TianoTools/Common/PeiLib/Ipf/math.c create mode 100644 Tools/Source/TianoTools/Common/PeiLib/Ipf/pioflush.s create mode 100644 Tools/Source/TianoTools/Common/PeiLib/Ipf/processor.c create mode 100644 Tools/Source/TianoTools/Common/PeiLib/Ipf/setjmp.s create mode 100644 Tools/Source/TianoTools/Common/PeiLib/PeCoffLoader.c create mode 100644 Tools/Source/TianoTools/Common/PeiLib/PeiLib.c create mode 100644 Tools/Source/TianoTools/Common/PeiLib/PeiLib.h create mode 100644 Tools/Source/TianoTools/Common/PeiLib/Perf.c create mode 100644 Tools/Source/TianoTools/Common/PeiLib/Print/Print.c create mode 100644 Tools/Source/TianoTools/Common/PeiLib/Print/Print.h create mode 100644 Tools/Source/TianoTools/Common/PeiLib/ia32/PeCoffLoaderEx.c create mode 100644 Tools/Source/TianoTools/Common/PeiLib/ia32/PeCoffLoaderEx.h create mode 100644 Tools/Source/TianoTools/Common/PeiLib/ia32/PerformancePrimitives.c create mode 100644 Tools/Source/TianoTools/Common/PeiLib/ia32/Processor.c create mode 100644 Tools/Source/TianoTools/Common/PeiLib/ia32/ProcessorAsms.Asm create mode 100644 Tools/Source/TianoTools/Common/PeiLib/ia32/efijump.h create mode 100644 Tools/Source/TianoTools/Common/SimpleFileParsing.c create mode 100644 Tools/Source/TianoTools/Common/SimpleFileParsing.h create mode 100644 Tools/Source/TianoTools/Common/WinNtInclude.h create mode 100644 Tools/Source/TianoTools/Common/build.gcc create mode 100644 Tools/Source/TianoTools/Common/build.xml create mode 100644 Tools/Source/TianoTools/CompressDll/CompressDll.c create mode 100644 Tools/Source/TianoTools/CompressDll/CompressDll.h create mode 100644 Tools/Source/TianoTools/CompressDll/build.xml create mode 100644 Tools/Source/TianoTools/CustomizedCompress/CustomizedCompress.c create mode 100644 Tools/Source/TianoTools/CustomizedCompress/build.gcc create mode 100644 Tools/Source/TianoTools/CustomizedCompress/build.xml create mode 100644 Tools/Source/TianoTools/FwImage/build.gcc create mode 100644 Tools/Source/TianoTools/FwImage/build.xml create mode 100644 Tools/Source/TianoTools/FwImage/fwimage.c create mode 100644 Tools/Source/TianoTools/GenCRC32Section/GenCRC32Section.c create mode 100644 Tools/Source/TianoTools/GenCRC32Section/GenCRC32Section.h create mode 100644 Tools/Source/TianoTools/GenCRC32Section/build.gcc create mode 100644 Tools/Source/TianoTools/GenCRC32Section/build.xml create mode 100644 Tools/Source/TianoTools/GenDepex/DepexParser.c create mode 100644 Tools/Source/TianoTools/GenDepex/DepexParser.h create mode 100644 Tools/Source/TianoTools/GenDepex/GenDepex.c create mode 100644 Tools/Source/TianoTools/GenDepex/GenDepex.h create mode 100644 Tools/Source/TianoTools/GenDepex/build.gcc create mode 100644 Tools/Source/TianoTools/GenDepex/build.xml create mode 100644 Tools/Source/TianoTools/GenFfsFile/GenFfsFile.c create mode 100644 Tools/Source/TianoTools/GenFfsFile/GenFfsFile.h create mode 100644 Tools/Source/TianoTools/GenFfsFile/SimpleFileParsing.c create mode 100644 Tools/Source/TianoTools/GenFfsFile/build.gcc create mode 100644 Tools/Source/TianoTools/GenFfsFile/build.xml create mode 100644 Tools/Source/TianoTools/GenFvImage/BasePeCoff.c create mode 100644 Tools/Source/TianoTools/GenFvImage/Common/EfiImage.h create mode 100644 Tools/Source/TianoTools/GenFvImage/Ebc/PeCoffLoaderEx.c create mode 100644 Tools/Source/TianoTools/GenFvImage/GenFvImageExe.c create mode 100644 Tools/Source/TianoTools/GenFvImage/GenFvImageExe.h create mode 100644 Tools/Source/TianoTools/GenFvImage/GenFvImageLib.c create mode 100644 Tools/Source/TianoTools/GenFvImage/GenFvImageLib.h create mode 100644 Tools/Source/TianoTools/GenFvImage/GenFvImageLibInternal.h create mode 100644 Tools/Source/TianoTools/GenFvImage/Ia32/PeCoffLoaderEx.c create mode 100644 Tools/Source/TianoTools/GenFvImage/Ipf/PeCoffLoaderEx.c create mode 100644 Tools/Source/TianoTools/GenFvImage/build.gcc create mode 100644 Tools/Source/TianoTools/GenFvImage/build.xml create mode 100644 Tools/Source/TianoTools/GenFvImage/x64/PeCoffLoaderEx.c create mode 100644 Tools/Source/TianoTools/GenSection/GenSection.c create mode 100644 Tools/Source/TianoTools/GenSection/GenSection.h create mode 100644 Tools/Source/TianoTools/GenSection/build.gcc create mode 100644 Tools/Source/TianoTools/GenSection/build.xml create mode 100644 Tools/Source/TianoTools/GuidChk/CommonUtils.h create mode 100644 Tools/Source/TianoTools/GuidChk/FileSearch.c create mode 100644 Tools/Source/TianoTools/GuidChk/FileSearch.h create mode 100644 Tools/Source/TianoTools/GuidChk/GuidChk.c create mode 100644 Tools/Source/TianoTools/GuidChk/GuidList.c create mode 100644 Tools/Source/TianoTools/GuidChk/UtilsMsgs.c create mode 100644 Tools/Source/TianoTools/GuidChk/UtilsMsgs.h create mode 100644 Tools/Source/TianoTools/GuidChk/build.gcc create mode 100644 Tools/Source/TianoTools/GuidChk/build.xml create mode 100644 Tools/Source/TianoTools/Pccts/CHANGES_FROM_131.txt create mode 100644 Tools/Source/TianoTools/Pccts/CHANGES_FROM_133.txt create mode 100644 Tools/Source/TianoTools/Pccts/CHANGES_FROM_133_BEFORE_MR13.txt create mode 100644 Tools/Source/TianoTools/Pccts/CHANGES_SUMMARY.txt create mode 100644 Tools/Source/TianoTools/Pccts/KNOWN_PROBLEMS.txt create mode 100644 Tools/Source/TianoTools/Pccts/MPW_Read_Me create mode 100644 Tools/Source/TianoTools/Pccts/NOTES.bcc create mode 100644 Tools/Source/TianoTools/Pccts/NOTES.msvc create mode 100644 Tools/Source/TianoTools/Pccts/README create mode 100644 Tools/Source/TianoTools/Pccts/RIGHTS create mode 100644 Tools/Source/TianoTools/Pccts/antlr/AntlrMS.mak create mode 100644 Tools/Source/TianoTools/Pccts/antlr/AntlrPPC.mak create mode 100644 Tools/Source/TianoTools/Pccts/antlr/README create mode 100644 Tools/Source/TianoTools/Pccts/antlr/antlr.1 create mode 100644 Tools/Source/TianoTools/Pccts/antlr/antlr.c create mode 100644 Tools/Source/TianoTools/Pccts/antlr/antlr.g create mode 100644 Tools/Source/TianoTools/Pccts/antlr/antlr.r create mode 100644 Tools/Source/TianoTools/Pccts/antlr/antlr1.txt create mode 100644 Tools/Source/TianoTools/Pccts/antlr/bits.c create mode 100644 Tools/Source/TianoTools/Pccts/antlr/build.c create mode 100644 Tools/Source/TianoTools/Pccts/antlr/build.xml create mode 100644 Tools/Source/TianoTools/Pccts/antlr/dumpcycles.c create mode 100644 Tools/Source/TianoTools/Pccts/antlr/dumpnode.c create mode 100644 Tools/Source/TianoTools/Pccts/antlr/egman.c create mode 100644 Tools/Source/TianoTools/Pccts/antlr/err.c create mode 100644 Tools/Source/TianoTools/Pccts/antlr/fcache.c create mode 100644 Tools/Source/TianoTools/Pccts/antlr/fset.c create mode 100644 Tools/Source/TianoTools/Pccts/antlr/fset2.c create mode 100644 Tools/Source/TianoTools/Pccts/antlr/gen.c create mode 100644 Tools/Source/TianoTools/Pccts/antlr/generic.h create mode 100644 Tools/Source/TianoTools/Pccts/antlr/globals.c create mode 100644 Tools/Source/TianoTools/Pccts/antlr/hash.c create mode 100644 Tools/Source/TianoTools/Pccts/antlr/hash.h create mode 100644 Tools/Source/TianoTools/Pccts/antlr/lex.c create mode 100644 Tools/Source/TianoTools/Pccts/antlr/main.c create mode 100644 Tools/Source/TianoTools/Pccts/antlr/makefile create mode 100644 Tools/Source/TianoTools/Pccts/antlr/makefile1 create mode 100644 Tools/Source/TianoTools/Pccts/antlr/misc.c create mode 100644 Tools/Source/TianoTools/Pccts/antlr/mode.h create mode 100644 Tools/Source/TianoTools/Pccts/antlr/mrhoist.c create mode 100644 Tools/Source/TianoTools/Pccts/antlr/parser.dlg create mode 100644 Tools/Source/TianoTools/Pccts/antlr/pred.c create mode 100644 Tools/Source/TianoTools/Pccts/antlr/proto.h create mode 100644 Tools/Source/TianoTools/Pccts/antlr/scan.c create mode 100644 Tools/Source/TianoTools/Pccts/antlr/stdpccts.h create mode 100644 Tools/Source/TianoTools/Pccts/antlr/syn.h create mode 100644 Tools/Source/TianoTools/Pccts/antlr/tokens.h create mode 100644 Tools/Source/TianoTools/Pccts/build.gcc create mode 100644 Tools/Source/TianoTools/Pccts/build.xml create mode 100644 Tools/Source/TianoTools/Pccts/dlg/DlgMS.mak create mode 100644 Tools/Source/TianoTools/Pccts/dlg/DlgPPC.mak create mode 100644 Tools/Source/TianoTools/Pccts/dlg/automata.c create mode 100644 Tools/Source/TianoTools/Pccts/dlg/build.xml create mode 100644 Tools/Source/TianoTools/Pccts/dlg/dlg.1 create mode 100644 Tools/Source/TianoTools/Pccts/dlg/dlg.h create mode 100644 Tools/Source/TianoTools/Pccts/dlg/dlg.r create mode 100644 Tools/Source/TianoTools/Pccts/dlg/dlg1.txt create mode 100644 Tools/Source/TianoTools/Pccts/dlg/dlg_a.c create mode 100644 Tools/Source/TianoTools/Pccts/dlg/dlg_p.c create mode 100644 Tools/Source/TianoTools/Pccts/dlg/dlg_p.g create mode 100644 Tools/Source/TianoTools/Pccts/dlg/err.c create mode 100644 Tools/Source/TianoTools/Pccts/dlg/main.c create mode 100644 Tools/Source/TianoTools/Pccts/dlg/makefile create mode 100644 Tools/Source/TianoTools/Pccts/dlg/makefile1 create mode 100644 Tools/Source/TianoTools/Pccts/dlg/mode.h create mode 100644 Tools/Source/TianoTools/Pccts/dlg/output.c create mode 100644 Tools/Source/TianoTools/Pccts/dlg/parser.dlg create mode 100644 Tools/Source/TianoTools/Pccts/dlg/relabel.c create mode 100644 Tools/Source/TianoTools/Pccts/dlg/stdpccts.h create mode 100644 Tools/Source/TianoTools/Pccts/dlg/support.c create mode 100644 Tools/Source/TianoTools/Pccts/dlg/tokens.h create mode 100644 Tools/Source/TianoTools/Pccts/h/AParser.cpp create mode 100644 Tools/Source/TianoTools/Pccts/h/AParser.h create mode 100644 Tools/Source/TianoTools/Pccts/h/ASTBase.cpp create mode 100644 Tools/Source/TianoTools/Pccts/h/ASTBase.h create mode 100644 Tools/Source/TianoTools/Pccts/h/ATokPtr.h create mode 100644 Tools/Source/TianoTools/Pccts/h/ATokPtrImpl.h create mode 100644 Tools/Source/TianoTools/Pccts/h/AToken.h create mode 100644 Tools/Source/TianoTools/Pccts/h/ATokenBuffer.cpp create mode 100644 Tools/Source/TianoTools/Pccts/h/ATokenBuffer.h create mode 100644 Tools/Source/TianoTools/Pccts/h/ATokenStream.h create mode 100644 Tools/Source/TianoTools/Pccts/h/BufFileInput.cpp create mode 100644 Tools/Source/TianoTools/Pccts/h/BufFileInput.h create mode 100644 Tools/Source/TianoTools/Pccts/h/DLG_stream_input.h create mode 100644 Tools/Source/TianoTools/Pccts/h/DLexer.h create mode 100644 Tools/Source/TianoTools/Pccts/h/DLexerBase.cpp create mode 100644 Tools/Source/TianoTools/Pccts/h/DLexerBase.h create mode 100644 Tools/Source/TianoTools/Pccts/h/PBlackBox.h create mode 100644 Tools/Source/TianoTools/Pccts/h/PCCTSAST.cpp create mode 100644 Tools/Source/TianoTools/Pccts/h/PCCTSAST.h create mode 100644 Tools/Source/TianoTools/Pccts/h/SList.h create mode 100644 Tools/Source/TianoTools/Pccts/h/antlr.h create mode 100644 Tools/Source/TianoTools/Pccts/h/ast.c create mode 100644 Tools/Source/TianoTools/Pccts/h/ast.h create mode 100644 Tools/Source/TianoTools/Pccts/h/charbuf.h create mode 100644 Tools/Source/TianoTools/Pccts/h/charptr.c create mode 100644 Tools/Source/TianoTools/Pccts/h/charptr.h create mode 100644 Tools/Source/TianoTools/Pccts/h/config.h create mode 100644 Tools/Source/TianoTools/Pccts/h/dlgauto.h create mode 100644 Tools/Source/TianoTools/Pccts/h/dlgdef.h create mode 100644 Tools/Source/TianoTools/Pccts/h/err.h create mode 100644 Tools/Source/TianoTools/Pccts/h/int.h create mode 100644 Tools/Source/TianoTools/Pccts/h/pccts_assert.h create mode 100644 Tools/Source/TianoTools/Pccts/h/pccts_iostream.h create mode 100644 Tools/Source/TianoTools/Pccts/h/pccts_istream.h create mode 100644 Tools/Source/TianoTools/Pccts/h/pccts_setjmp.h create mode 100644 Tools/Source/TianoTools/Pccts/h/pccts_stdarg.h create mode 100644 Tools/Source/TianoTools/Pccts/h/pccts_stdio.h create mode 100644 Tools/Source/TianoTools/Pccts/h/pccts_stdlib.h create mode 100644 Tools/Source/TianoTools/Pccts/h/pccts_string.h create mode 100644 Tools/Source/TianoTools/Pccts/h/pcctscfg.h create mode 100644 Tools/Source/TianoTools/Pccts/h/pcnames.bat create mode 100644 Tools/Source/TianoTools/Pccts/h/slist.cpp create mode 100644 Tools/Source/TianoTools/Pccts/history.ps create mode 100644 Tools/Source/TianoTools/Pccts/history.txt create mode 100644 Tools/Source/TianoTools/Pccts/makefile create mode 100644 Tools/Source/TianoTools/Pccts/support/genmk/genmk.c create mode 100644 Tools/Source/TianoTools/Pccts/support/genmk/genmk_old.c create mode 100644 Tools/Source/TianoTools/Pccts/support/genmk/makefile create mode 100644 Tools/Source/TianoTools/Pccts/support/rexpr/makefile create mode 100644 Tools/Source/TianoTools/Pccts/support/rexpr/rexpr.c create mode 100644 Tools/Source/TianoTools/Pccts/support/rexpr/rexpr.h create mode 100644 Tools/Source/TianoTools/Pccts/support/rexpr/test.c create mode 100644 Tools/Source/TianoTools/Pccts/support/set/set.c create mode 100644 Tools/Source/TianoTools/Pccts/support/set/set.h create mode 100644 Tools/Source/TianoTools/Pccts/support/sym/sym.c create mode 100644 Tools/Source/TianoTools/Pccts/support/sym/template.h create mode 100644 Tools/Source/TianoTools/SetStamp/SetStamp.c create mode 100644 Tools/Source/TianoTools/SetStamp/build.gcc create mode 100644 Tools/Source/TianoTools/SetStamp/build.xml create mode 100644 Tools/Source/TianoTools/StrGather/StrGather.c create mode 100644 Tools/Source/TianoTools/StrGather/StrGather.h create mode 100644 Tools/Source/TianoTools/StrGather/StringDB.c create mode 100644 Tools/Source/TianoTools/StrGather/StringDB.h create mode 100644 Tools/Source/TianoTools/StrGather/build.gcc create mode 100644 Tools/Source/TianoTools/StrGather/build.xml create mode 100644 Tools/Source/TianoTools/VfrCompile/EfiVfr.h create mode 100644 Tools/Source/TianoTools/VfrCompile/VfrCompile.g create mode 100644 Tools/Source/TianoTools/VfrCompile/VfrServices.cpp create mode 100644 Tools/Source/TianoTools/VfrCompile/VfrServices.h create mode 100644 Tools/Source/TianoTools/VfrCompile/build.gcc create mode 100644 Tools/Source/TianoTools/VfrCompile/build.xml create mode 100644 Tools/Source/TianoTools/build.xml create mode 100644 Tools/Source/Tools.msa create mode 100644 Tools/ToolResources.msa create mode 100644 Tools/Tools.spd create mode 100644 Tools/XMLSchema/FDPManifest.xsd create mode 100644 Tools/XMLSchema/FrameworkDataElements.xsd create mode 100644 Tools/XMLSchema/FrameworkDataTypes.xsd create mode 100644 Tools/XMLSchema/FrameworkHeaders.xsd create mode 100644 Tools/XMLSchema/FrameworkPlatformDataElements.xsd create mode 100644 Tools/XMLSchema/NamingConvention.xsd create mode 100644 Tools/XMLSchema/SurfaceArea.xsd create mode 100644 Tools/XMLSchema/SurfaceArea.xsdconfig create mode 100644 Tools/bin/CreateMdkPkg.bat create mode 100644 Tools/bin/GenBuildFile.bat create mode 100644 Tools/bin/GenBuildFile.xml create mode 100644 Tools/bin/MakeDeps.exe create mode 100644 Tools/bin/PackageEditor.bat create mode 100644 Tools/bin/SABeans.bat create mode 100644 Tools/bin/SACreate.bat create mode 100644 Tools/bin/SAPretty.bat create mode 100644 Tools/bin/SAVerify.bat create mode 100644 Tools/build.xml create mode 100644 build.xml create mode 100644 edksetup.bat create mode 100644 edksetup.sh diff --git a/DeveloperManual.doc b/DeveloperManual.doc new file mode 100644 index 0000000000000000000000000000000000000000..f8a6b90c1cbdfcd68bc4e65b01c1d07c386e7d10 GIT binary patch literal 650240 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

D#p+ty&FEL5>Z-*x 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 literal 0 HcmV?d00001 diff --git a/EdkFatBinPkg/EdkFatBinPkg.spd b/EdkFatBinPkg/EdkFatBinPkg.spd new file mode 100644 index 0000000000..3a739581a5 --- /dev/null +++ b/EdkFatBinPkg/EdkFatBinPkg.spd @@ -0,0 +1,40 @@ + + + + + EdkFatBinPkg + 0fd7197b-9bde-44fe-a7e4-d2177a9922e5 + 0 + This is the Binary Package for the FAT dirver + This package provides FAT drivers which are not licensed under BSD. + Copyright (c) 2004, Intel Corporation. + + All rights reserved. + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License which accompanies this distribution. + The full text of the license may be found at http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES + OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-05 09:49 + 2006-03-19 16:18 + http://www.TianoCore.org + BINARY + true + false + + + + Fat.msa + + + diff --git a/EdkFatBinPkg/Fat.mbd b/EdkFatBinPkg/Fat.mbd new file mode 100644 index 0000000000..ab6d27094d --- /dev/null +++ b/EdkFatBinPkg/Fat.mbd @@ -0,0 +1,34 @@ + + + + + Fat + 5058F21C-BC34-11d4-BD18-0080C73C8881 + 0 + This is the FAT 32 EFI/Tiano Driver + + Copyright 2004, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-17 20:56 + 2006-03-19 16:17 + + + + + diff --git a/EdkFatBinPkg/Fat.msa b/EdkFatBinPkg/Fat.msa new file mode 100644 index 0000000000..71a0739b16 --- /dev/null +++ b/EdkFatBinPkg/Fat.msa @@ -0,0 +1,53 @@ + + + + + Fat + PEIM + BS_DRIVER + 5058F21C-BC34-11d4-BD18-0080C73C8881 + 0 + Make a FFS section for an FV that contains the FAT driver.*.FFS files are compressed FFS sections. + This is the FAT 32 EFI/Tiano Driver + Copyright 2004, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-17 20:56 + 2006-03-19 16:17 + + + + Fat.FFS + + + Fat.FFS + + + Fat.FFS + + + + + + + + + + + diff --git a/EdkFatBinPkg/Fat_build.xml b/EdkFatBinPkg/Fat_build.xml new file mode 100644 index 0000000000..e99c13ffac --- /dev/null +++ b/EdkFatBinPkg/Fat_build.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/EdkFatBinPkg/Ia32/Fat.FFS b/EdkFatBinPkg/Ia32/Fat.FFS new file mode 100644 index 0000000000000000000000000000000000000000..ccb9b6609b68eb5e057774bb866fb38919bad98b GIT binary patch literal 24227 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 USxt7S1LA1EtOA3q)?LU?CA;w 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 literal 0 HcmV?d00001 diff --git a/EdkFatBinPkg/Ipf/Fat.FFS b/EdkFatBinPkg/Ipf/Fat.FFS new file mode 100644 index 0000000000000000000000000000000000000000..5989987b625a77c8b443e1534072762bd60d1a31 GIT binary patch literal 38320 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 >Qp@e_Ht? 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 Y?kw)C_!f7TYT4e|-`SJM|N82<0J22R1^@s6 literal 0 HcmV?d00001 diff --git a/EdkFatBinPkg/build.xml b/EdkFatBinPkg/build.xml new file mode 100644 index 0000000000..e3d4dc4e95 --- /dev/null +++ b/EdkFatBinPkg/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkFatBinPkg/genbuildfile.xml b/EdkFatBinPkg/genbuildfile.xml new file mode 100644 index 0000000000..4b60c0cbe5 --- /dev/null +++ b/EdkFatBinPkg/genbuildfile.xml @@ -0,0 +1,18 @@ + + + + + + + + + diff --git a/EdkModulePkg/Application/HelloWorld/HelloWorld.c b/EdkModulePkg/Application/HelloWorld/HelloWorld.c new file mode 100644 index 0000000000..f3eda071e4 --- /dev/null +++ b/EdkModulePkg/Application/HelloWorld/HelloWorld.c @@ -0,0 +1,47 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + HelloWorld.c + +Abstract: + + This driver supports platform security service + +--*/ + +VOID +Print ( + IN CONST CHAR16 *Format, + ... + ) +{ + CHAR16 PrintBuffer[0x100]; + VA_LIST Marker; + + VA_START (Marker, Format); + UnicodeVSPrint (PrintBuffer, sizeof (PrintBuffer), Format, Marker); + gST->ConOut->OutputString (gST->ConOut, PrintBuffer); + return; +} + +EFI_STATUS +EFIAPI +UefiMain ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) + +{ + Print ((CHAR16 *)L"UEFI Hello World!\n"); + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Application/HelloWorld/HelloWorld.mbd b/EdkModulePkg/Application/HelloWorld/HelloWorld.mbd new file mode 100644 index 0000000000..6d44bac022 --- /dev/null +++ b/EdkModulePkg/Application/HelloWorld/HelloWorld.mbd @@ -0,0 +1,43 @@ + + + + + HelloWorld + 6987936E-ED34-44db-AE97-1FA5E4ED2116 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-20 20:41 + + + UefiBootServicesTableLib + BaseLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDebugLibStdErr + BasePrintLib + + + _ModuleEntryPoint + + + diff --git a/EdkModulePkg/Application/HelloWorld/HelloWorld.msa b/EdkModulePkg/Application/HelloWorld/HelloWorld.msa new file mode 100644 index 0000000000..92fca0ff91 --- /dev/null +++ b/EdkModulePkg/Application/HelloWorld/HelloWorld.msa @@ -0,0 +1,51 @@ + + + + + HelloWorld + DXE_DRIVER + APPLICATION + 6987936E-ED34-44db-AE97-1FA5E4ED2116 + 0 + Component description file for SecurityStub module + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-20 20:41 + + + PrintLib + DebugLib + UefiBootServicesTableLib + UefiDriverEntryPoint + + + HelloWorld.c + + + MdePkg + + + + UefiMain + + + diff --git a/EdkModulePkg/Application/HelloWorld/build.xml b/EdkModulePkg/Application/HelloWorld/build.xml new file mode 100644 index 0000000000..d8531c33e2 --- /dev/null +++ b/EdkModulePkg/Application/HelloWorld/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.c b/EdkModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.c new file mode 100644 index 0000000000..6fe81d1521 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.c @@ -0,0 +1,2226 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + AtapiPassThru.c + +Abstract: + + +Revision History +--*/ + +#include "AtapiPassThru.h" + +EFI_STATUS +EFIAPI +AtapiScsiPassThruDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +AtapiScsiPassThruDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +AtapiScsiPassThruDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +// +// IDE registers' fixed address +// +static IDE_BASE_REGISTERS gAtapiIoPortRegisters[2] = { + { 0x1f0, { 0x1f1 }, 0x1f2, 0x1f3, 0x1f4, 0x1f5, 0x1f6, { 0x1f7 }, { 0x3f6 }, 0x3f7, 0 }, + { 0x170, { 0x171 }, 0x172, 0x173, 0x174, 0x175, 0x176, { 0x177 }, { 0x376 }, 0x377, 0 } +}; + +static SCSI_COMMAND_SET gEndTable = { 0xff, 0xff }; + +// +// This table contains all the supported ATAPI commands. +// +static SCSI_COMMAND_SET gSupportedATAPICommands[] = { + { OP_INQUIRY, DataIn }, + { OP_LOAD_UNLOAD_CD, NoData }, + { OP_MECHANISM_STATUS, DataIn }, + { OP_MODE_SELECT_10, DataOut }, + { OP_MODE_SENSE_10, DataIn }, + { OP_PAUSE_RESUME, NoData }, + { OP_PLAY_AUDIO_10, DataIn }, + { OP_PLAY_AUDIO_MSF, DataIn }, + { OP_PLAY_CD, DataIn }, + { OP_PLAY_CD_MSF, DataIn }, + { OP_PREVENT_ALLOW_MEDIUM_REMOVAL,NoData }, + { OP_READ_10, DataIn }, + { OP_READ_12, DataIn }, + { OP_READ_CAPACITY, DataIn }, + { OP_READ_CD, DataIn }, + { OP_READ_CD_MSF, DataIn }, + { OP_READ_HEADER, DataIn }, + { OP_READ_SUB_CHANNEL, DataIn }, + { OP_READ_TOC, DataIn }, + { OP_REQUEST_SENSE, DataIn }, + { OP_SCAN, NoData }, + { OP_SEEK_10, NoData }, + { OP_SET_CD_SPEED, DataOut }, + { OP_STOPPLAY_SCAN, NoData }, + { OP_START_STOP_UNIT, NoData }, + { OP_TEST_UNIT_READY, NoData }, + { OP_FORMAT_UNIT, DataOut }, + { OP_READ_FORMAT_CAPACITIES, DataIn }, + { OP_VERIFY, DataOut }, + { OP_WRITE_10, DataOut }, + { OP_WRITE_12, DataOut }, + { OP_WRITE_AND_VERIFY, DataOut }, + { 0xff, 0xff } +}; + +static CHAR16 *gControllerNameString = (CHAR16 *) L"ATAPI Controller"; +static CHAR16 *gAtapiChannelString = (CHAR16 *) L"ATAPI Channel"; + +EFI_DRIVER_BINDING_PROTOCOL gAtapiScsiPassThruDriverBinding = { + AtapiScsiPassThruDriverBindingSupported, + AtapiScsiPassThruDriverBindingStart, + AtapiScsiPassThruDriverBindingStop, + 0x10, + NULL, + NULL +}; + +EFI_STATUS +EFIAPI +AtapiScsiPassThruDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + Supported. + + Arguments: + (Standard DriverBinding Protocol Supported() function) + + Returns: + EFI_STATUS + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Controller - add argument and description to function comment +// TODO: RemainingDevicePath - add argument and description to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + PCI_TYPE00 Pci; + + // + // Open the IO Abstraction(s) needed to perform the supported test + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Use the PCI I/O Protocol to see if Controller is a IDE Controller that + // can be managed by this driver. Read the PCI Configuration Header + // for this device. + // + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint32, + 0, + sizeof (Pci) / sizeof (UINT32), + &Pci + ); + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return EFI_UNSUPPORTED; + } + + if (Pci.Hdr.ClassCode[2] != PCI_CLASS_MASS_STORAGE || Pci.Hdr.ClassCode[1] != PCI_CLASS_IDE) { + + Status = EFI_UNSUPPORTED; + } + + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return Status; +} + +EFI_STATUS +EFIAPI +AtapiScsiPassThruDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + Create handles for IDE channels specified by RemainingDevicePath. + Install SCSI Pass Thru Protocol onto each created handle. + + Arguments: + (Standard DriverBinding Protocol Start() function) + + Returns: + EFI_STATUS + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Controller - add argument and description to function comment +// TODO: RemainingDevicePath - add argument and description to function comment +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + + PciIo = NULL; + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationEnable, + EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO | EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO | EFI_PCI_DEVICE_ENABLE, + NULL + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Create SCSI Pass Thru instance for the IDE channel. + // + Status = RegisterAtapiScsiPassThru (This, Controller, PciIo); + +Done: + if (EFI_ERROR (Status)) { + if (PciIo) { + PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationDisable, + EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO | EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO | EFI_PCI_DEVICE_ENABLE, + NULL + ); + } + + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + } + + return Status; +} + +EFI_STATUS +EFIAPI +AtapiScsiPassThruDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + + Routine Description: + Stop. + + Arguments: + (Standard DriverBinding Protocol Stop() function) + + Returns: + EFI_STATUS + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Controller - add argument and description to function comment +// TODO: NumberOfChildren - add argument and description to function comment +// TODO: ChildHandleBuffer - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru; + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate; + + Status = gBS->OpenProtocol ( + Controller, + &gEfiScsiPassThruProtocolGuid, + (VOID **) &ScsiPassThru, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (ScsiPassThru); + + Status = gBS->UninstallProtocolInterface ( + Controller, + &gEfiScsiPassThruProtocolGuid, + &AtapiScsiPrivate->ScsiPassThru + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Release Pci Io protocol on the controller handle. + // + AtapiScsiPrivate->PciIo->Attributes ( + AtapiScsiPrivate->PciIo, + EfiPciIoAttributeOperationDisable, + EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO | EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO | EFI_PCI_DEVICE_ENABLE, + NULL + ); + + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + gBS->FreePool (AtapiScsiPrivate); + + return EFI_SUCCESS; +} + +EFI_STATUS +RegisterAtapiScsiPassThru ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_PCI_IO_PROTOCOL *PciIo + ) +/*++ + + Routine Description: + Attaches SCSI Pass Thru Protocol for specified IDE channel. + + Arguments: + Controller: Parent device handle to the IDE channel. + PciIo: PCI I/O protocol attached on the "Controller". + + Returns: + Always return EFI_SUCCESS unless installing SCSI Pass Thru Protocol failed. +--*/ +// TODO: This - add argument and description to function comment +// TODO: Controller - add argument and description to function comment +// TODO: PciIo - add argument and description to function comment +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +{ + EFI_STATUS Status; + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate; + UINT64 Attributes; + + AtapiScsiPrivate = AllocateZeroPool (sizeof (ATAPI_SCSI_PASS_THRU_DEV)); + if (AtapiScsiPrivate == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Attributes = EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO | EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO | EFI_PCI_DEVICE_ENABLE; + CopyMem (AtapiScsiPrivate->ChannelName, gAtapiChannelString, sizeof (gAtapiChannelString)); + + // + // Enable channel + // + PciIo->Attributes (PciIo, EfiPciIoAttributeOperationSet, Attributes, NULL); + + AtapiScsiPrivate->Signature = ATAPI_SCSI_PASS_THRU_DEV_SIGNATURE; + AtapiScsiPrivate->Handle = Controller; + + // + // will reset the IoPort inside each API function. + // + AtapiScsiPrivate->IoPort = gAtapiIoPortRegisters; + AtapiScsiPrivate->PciIo = PciIo; + + // + // initialize SCSI Pass Thru Protocol interface + // + AtapiScsiPrivate->ScsiPassThru.Mode = &AtapiScsiPrivate->ScsiPassThruMode; + AtapiScsiPrivate->ScsiPassThru.PassThru = AtapiScsiPassThruFunction; + AtapiScsiPrivate->ScsiPassThru.GetNextDevice = AtapiScsiPassThruGetNextDevice; + AtapiScsiPrivate->ScsiPassThru.BuildDevicePath = AtapiScsiPassThruBuildDevicePath; + AtapiScsiPrivate->ScsiPassThru.GetTargetLun = AtapiScsiPassThruGetTargetLun; + AtapiScsiPrivate->ScsiPassThru.ResetChannel = AtapiScsiPassThruResetChannel; + AtapiScsiPrivate->ScsiPassThru.ResetTarget = AtapiScsiPassThruResetTarget; + + // + // Set Mode + // + CopyMem (AtapiScsiPrivate->ControllerName, gControllerNameString, sizeof (gControllerNameString)); + + AtapiScsiPrivate->ScsiPassThruMode.ControllerName = AtapiScsiPrivate->ControllerName; + AtapiScsiPrivate->ScsiPassThruMode.ChannelName = AtapiScsiPrivate->ChannelName; + AtapiScsiPrivate->ScsiPassThruMode.AdapterId = 4; + // + // non-RAID SCSI controllers should set both physical and logical attributes + // + AtapiScsiPrivate->ScsiPassThruMode.Attributes = EFI_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | + EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL; + AtapiScsiPrivate->ScsiPassThruMode.IoAlign = 0; + + // + // Initialize the LatestTargetId to 0xFFFFFFFF (for the GetNextDevice() call). + // + AtapiScsiPrivate->LatestTargetId = 0xFFFFFFFF; + AtapiScsiPrivate->LatestLun = 0; + + Status = gBS->InstallProtocolInterface ( + &Controller, + &gEfiScsiPassThruProtocolGuid, + EFI_NATIVE_INTERFACE, + &AtapiScsiPrivate->ScsiPassThru + ); + return Status; +} + +EFI_STATUS +EFIAPI +AtapiScsiPassThruFunction ( + IN EFI_SCSI_PASS_THRU_PROTOCOL *This, + IN UINT32 Target, + IN UINT64 Lun, + IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet, + IN EFI_EVENT Event OPTIONAL + ) +/*++ + + Routine Description: + Implements EFI_SCSI_PASS_THRU_PROTOCOL.PassThru() function. + + Arguments: + This: The EFI_SCSI_PASS_THRU_PROTOCOL instance. + Target: The Target ID of the ATAPI device to send the SCSI + Request Packet. To ATAPI devices attached on an IDE + Channel, Target ID 0 indicates Master device;Target + ID 1 indicates Slave device. + Lun: The LUN of the ATAPI device to send the SCSI Request + Packet. To the ATAPI device, Lun is always 0. + Packet: The SCSI Request Packet to send to the ATAPI device + specified by Target and Lun. + 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 SCSI Request Packet completes. + + Returns: + +--*/ +// TODO: This - add argument and description to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate; + EFI_STATUS Status; + + AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This); + + // + // Target is not allowed beyond MAX_TARGET_ID + // + if (Target > MAX_TARGET_ID) { + return EFI_INVALID_PARAMETER; + } + + // + // check the data fields in Packet parameter. + // + Status = CheckSCSIRequestPacket (Packet); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // If Request Packet targets at the IDE channel itself, + // do nothing. + // + if (Target == This->Mode->AdapterId) { + Packet->TransferLength = 0; + return EFI_SUCCESS; + } + + // + // According to Target ID, reset the Atapi I/O Register mapping + // (Target Id in [0,1] area, using gAtapiIoPortRegisters[0], + // Target Id in [2,3] area, using gAtapiIoPortRegisters[1] + // + if ((Target / 2) == 0) { + AtapiScsiPrivate->IoPort = &gAtapiIoPortRegisters[0]; + } else { + AtapiScsiPrivate->IoPort = &gAtapiIoPortRegisters[1]; + } + + // + // the ATAPI SCSI interface does not support non-blocking I/O + // ignore the Event parameter + // + // Performs blocking I/O. + // + Status = SubmitBlockingIoCommand (AtapiScsiPrivate, Target, Packet); + return Status; +} + +EFI_STATUS +EFIAPI +AtapiScsiPassThruGetNextDevice ( + IN EFI_SCSI_PASS_THRU_PROTOCOL *This, + IN OUT UINT32 *Target, + IN OUT UINT64 *Lun + ) +/*++ + + Routine Description: + Used to retrieve the list of legal Target IDs for SCSI devices + on a SCSI channel. + + Arguments: + This - Protocol instance pointer. + Target - On input, a pointer to the Target ID of a SCSI + device present on the SCSI channel. On output, + a pointer to the Target ID of the next SCSI device + present on a SCSI channel. An input value of + 0xFFFFFFFF retrieves the Target ID of the first + SCSI device present on a SCSI channel. + 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. + + Returns: + EFI_SUCCESS - The Target ID and Lun of the next SCSI device + on the SCSI channel was returned in Target and Lun. + EFI_NOT_FOUND - There are no more SCSI devices on this SCSI channel. + EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not + returned on a previous call to GetNextDevice(). +--*/ +{ + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate; + + // + // Retrieve Device Private Data Structure. + // + AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This); + + // + // Check whether Target is valid. + // + if (Target == NULL || Lun == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((*Target != 0xFFFFFFFF) && + ((*Target != AtapiScsiPrivate->LatestTargetId) || + (*Lun != AtapiScsiPrivate->LatestLun))) { + return EFI_INVALID_PARAMETER; + } + + if (*Target == MAX_TARGET_ID) { + return EFI_NOT_FOUND; + } + + if (*Target == 0xFFFFFFFF) { + *Target = 0; + } else { + *Target = AtapiScsiPrivate->LatestTargetId + 1; + } + + *Lun = 0; + + // + // Update the LatestTargetId. + // + AtapiScsiPrivate->LatestTargetId = *Target; + AtapiScsiPrivate->LatestLun = *Lun; + + return EFI_SUCCESS; + +} + +EFI_STATUS +EFIAPI +AtapiScsiPassThruBuildDevicePath ( + IN EFI_SCSI_PASS_THRU_PROTOCOL *This, + IN UINT32 Target, + IN UINT64 Lun, + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath + ) +/*++ + + Routine Description: + Used to allocate and build a device path node for a SCSI device + on a SCSI channel. Would not build device path for a SCSI Host Controller. + + Arguments: + This - Protocol instance pointer. + Target - The Target ID of the SCSI device for which + a device path node is to be allocated and built. + Lun - The LUN of the SCSI device for which a device + path node is to be allocated and built. + 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. + Returns: + EFI_SUCCESS - The device path node that describes the SCSI device + specified by Target and Lun was allocated and + returned in DevicePath. + EFI_NOT_FOUND - The SCSI devices specified by Target and Lun does + not exist on the SCSI channel. + EFI_INVALID_PARAMETER - DevicePath is NULL. + EFI_OUT_OF_RESOURCES - There are not enough resources to allocate + DevicePath. +--*/ +{ + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate; + EFI_DEV_PATH *Node; + + // + // Retrieve Device Private Data Structure. + // + AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This); + + // + // Validate parameters passed in. + // + + if (DevicePath == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // can not build device path for the SCSI Host Controller. + // + if ((Target > (MAX_TARGET_ID - 1)) || (Lun != 0)) { + return EFI_NOT_FOUND; + } + + Node = AllocateZeroPool (sizeof (EFI_DEV_PATH)); + if (Node == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Node->DevPath.Type = MESSAGING_DEVICE_PATH; + Node->DevPath.SubType = MSG_ATAPI_DP; + SetDevicePathNodeLength (&Node->DevPath, sizeof (ATAPI_DEVICE_PATH)); + + Node->Atapi.PrimarySecondary = (UINT8) (Target / 2); + Node->Atapi.SlaveMaster = (UINT8) (Target % 2); + Node->Atapi.Lun = (UINT16) Lun; + + *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Node; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +AtapiScsiPassThruGetTargetLun ( + IN EFI_SCSI_PASS_THRU_PROTOCOL *This, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + OUT UINT32 *Target, + OUT UINT64 *Lun + ) +/*++ + + Routine Description: + Used to translate a device path node to a Target ID and LUN. + + Arguments: + This - Protocol instance pointer. + DevicePath - A pointer to the device path node that + describes a SCSI device on the SCSI channel. + Target - A pointer to the Target ID of a SCSI device + on the SCSI channel. + Lun - A pointer to the LUN of a SCSI device on + the SCSI channel. + Returns: + EFI_SUCCESS - DevicePath was successfully translated to a + Target ID and LUN, and they were returned + in Target and Lun. + EFI_INVALID_PARAMETER - DevicePath is NULL. + EFI_INVALID_PARAMETER - Target is NULL. + EFI_INVALID_PARAMETER - Lun is NULL. + EFI_UNSUPPORTED - This driver does not support the device path + node type in DevicePath. + EFI_NOT_FOUND - A valid translation from DevicePath to a + Target ID and LUN does not exist. +--*/ +{ + EFI_DEV_PATH *Node; + + // + // Validate parameters passed in. + // + if (DevicePath == NULL || Target == NULL || Lun == 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) || + (DevicePathNodeLength(DevicePath) != sizeof(ATAPI_DEVICE_PATH))) { + return EFI_UNSUPPORTED; + } + + Node = (EFI_DEV_PATH *) DevicePath; + + *Target = Node->Atapi.PrimarySecondary * 2 + Node->Atapi.SlaveMaster; + *Lun = Node->Atapi.Lun; + + if (*Target > (MAX_TARGET_ID - 1) || *Lun != 0) { + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +AtapiScsiPassThruResetChannel ( + IN EFI_SCSI_PASS_THRU_PROTOCOL *This + ) +/*++ + + Routine Description: + Resets a SCSI channel.This operation resets all the + SCSI devices connected to the SCSI channel. + + Arguments: + This - Protocol instance pointer. + + Returns: + EFI_SUCCESS - The SCSI channel was reset. + EFI_UNSUPPORTED - The SCSI channel does not support + a channel reset operation. + EFI_DEVICE_ERROR - A device error occurred while + attempting to reset the SCSI channel. + EFI_TIMEOUT - A timeout occurred while attempting + to reset the SCSI channel. +--*/ +{ + UINT8 DeviceControlValue; + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate; + UINT8 Index; + + AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This); + + // + // Reset both Primary channel and Secondary channel. + // so, the IoPort pointer must point to the right I/O Register group + // + for (Index = 0; Index < 2; Index++) { + // + // Reset + // + AtapiScsiPrivate->IoPort = &gAtapiIoPortRegisters[Index]; + + DeviceControlValue = 0; + // + // set SRST bit to initiate soft reset + // + DeviceControlValue |= SRST; + // + // disable Interrupt + // + DeviceControlValue |= bit (1); + WritePortB ( + AtapiScsiPrivate->PciIo, + AtapiScsiPrivate->IoPort->Alt.DeviceControl, + DeviceControlValue + ); + + // + // Wait 10us + // + gBS->Stall (10); + + // + // Clear SRST bit + // 0xfb:1111,1011 + // + DeviceControlValue &= 0xfb; + + WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Alt.DeviceControl, DeviceControlValue); + + // + // slave device needs at most 31s to clear BSY + // + if (StatusWaitForBSYClear (AtapiScsiPrivate, 31000) == EFI_TIMEOUT) { + return EFI_DEVICE_ERROR; + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +AtapiScsiPassThruResetTarget ( + IN EFI_SCSI_PASS_THRU_PROTOCOL *This, + IN UINT32 Target, + IN UINT64 Lun + ) +/*++ + + Routine Description: + Resets a SCSI device that is connected to a SCSI channel. + + Arguments: + This - Protocol instance pointer. + Target - The Target ID of the SCSI device to reset. + Lun - The LUN of the SCSI device to reset. + + Returns: + EFI_SUCCESS - The SCSI device specified by Target and + Lun was reset. + EFI_UNSUPPORTED - The SCSI channel does not support a target + reset operation. + EFI_INVALID_PARAMETER - Target or Lun are invalid. + EFI_DEVICE_ERROR - A device error occurred while attempting + to reset the SCSI device specified by Target + and Lun. + EFI_TIMEOUT - A timeout occurred while attempting to reset + the SCSI device specified by Target and Lun. +--*/ +{ + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate; + UINT8 Command; + UINT8 DeviceSelect; + + AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This); + + if (Target > MAX_TARGET_ID) { + return EFI_INVALID_PARAMETER; + } + // + // Directly return EFI_SUCCESS if want to reset the host controller + // + if (Target == This->Mode->AdapterId) { + return EFI_SUCCESS; + } + + // + // According to Target ID, reset the Atapi I/O Register mapping + // (Target Id in [0,1] area, using gAtapiIoPortRegisters[0], + // Target Id in [2,3] area, using gAtapiIoPortRegisters[1] + // + if ((Target / 2) == 0) { + AtapiScsiPrivate->IoPort = &gAtapiIoPortRegisters[0]; + } else { + AtapiScsiPrivate->IoPort = &gAtapiIoPortRegisters[1]; + } + + // + // 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) (((bit (7) | bit (5)) | (Target << 4))); + WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Head, DeviceSelect); + + Command = ATAPI_SOFT_RESET_CMD; + WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Reg.Command, Command); + + // + // BSY clear is the only status return to the host by the device + // when reset is complete. + // slave device needs at most 31s to clear BSY + // + if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate, 31000))) { + return EFI_DEVICE_ERROR; + } + + // + // stall 5 seconds to make the device status stable + // + gBS->Stall (5000000); + + return EFI_SUCCESS; +} + + +EFI_STATUS +CheckSCSIRequestPacket ( + EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet + ) +/*++ + + Checks the parameters in the SCSI Request Packet to make sure + they are valid for a SCSI Pass Thru request. + +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: function comment is missing 'Returns:' +// TODO: Packet - add argument and description to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + if (Packet == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (!ValidCdbLength (Packet->CdbLength)) { + return EFI_INVALID_PARAMETER; + } + + if (Packet->Cdb == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Checks whether the request command is supported. + // + if (!IsCommandValid (Packet)) { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +BOOLEAN +IsCommandValid ( + EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet + ) +/*++ + + Checks the requested SCSI command: + Is it supported by this driver? + Is the Data transfer direction reasonable? + +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: function comment is missing 'Returns:' +// TODO: Packet - add argument and description to function comment +{ + UINT8 Index; + UINT8 *OpCode; + + OpCode = (UINT8 *) (Packet->Cdb); + + for (Index = 0; CompareMem (&gSupportedATAPICommands[Index], &gEndTable, sizeof (SCSI_COMMAND_SET)); Index++) { + + if (*OpCode == gSupportedATAPICommands[Index].OpCode) { + // + // Check whether the requested Command is supported by this driver + // + if (Packet->DataDirection == DataIn) { + // + // Check whether the requested data direction conforms to + // what it should be. + // + if (gSupportedATAPICommands[Index].Direction == DataOut) { + return FALSE; + } + } + + if (Packet->DataDirection == DataOut) { + // + // Check whether the requested data direction conforms to + // what it should be. + // + if (gSupportedATAPICommands[Index].Direction == DataIn) { + return FALSE; + } + } + + return TRUE; + } + } + + return FALSE; +} + +EFI_STATUS +SubmitBlockingIoCommand ( + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate, + UINT32 Target, + EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet + ) +/*++ + +Routine Description: + Performs blocking I/O request. + + Arguments: + AtapiScsiPrivate: Private data structure for the specified channel. + Target: The Target ID of the ATAPI device to send the SCSI + Request Packet. To ATAPI devices attached on an IDE + Channel, Target ID 0 indicates Master device;Target + ID 1 indicates Slave device. + Packet: The SCSI Request Packet to send to the ATAPI device + specified by Target. + + Returns: + +--*/ +// TODO: AtapiScsiPrivate - add argument and description to function comment +{ + UINT8 PacketCommand[12]; + UINT64 TimeoutInMicroSeconds; + EFI_STATUS PacketCommandStatus; + + // + // Fill ATAPI Command Packet according to CDB + // + ZeroMem (&PacketCommand, 12); + CopyMem (&PacketCommand, Packet->Cdb, Packet->CdbLength); + + // + // Timeout is 100ns unit, convert it to 1000ns (1us) unit. + // + TimeoutInMicroSeconds = DivU64x32 (Packet->Timeout, (UINT32) 10); + + // + // Submit ATAPI Command Packet + // + PacketCommandStatus = AtapiPacketCommand ( + AtapiScsiPrivate, + Target, + PacketCommand, + Packet->DataBuffer, + &(Packet->TransferLength), + Packet->DataDirection, + TimeoutInMicroSeconds + ); + if (!EFI_ERROR (PacketCommandStatus) || (Packet->SenseData == NULL)) { + Packet->SenseDataLength = 0; + return PacketCommandStatus; + } + // + // Return SenseData if PacketCommandStatus matches + // the following return codes. + // + if ((PacketCommandStatus == EFI_WARN_BUFFER_TOO_SMALL) || + (PacketCommandStatus == EFI_DEVICE_ERROR) || + (PacketCommandStatus == EFI_TIMEOUT)) { + + // + // avoid submit request sense command continuously. + // + if (PacketCommand[0] == OP_REQUEST_SENSE) { + Packet->SenseDataLength = 0; + return PacketCommandStatus; + } + + RequestSenseCommand ( + AtapiScsiPrivate, + Target, + Packet->Timeout, + Packet->SenseData, + &Packet->SenseDataLength + ); + } + + return PacketCommandStatus; +} + +EFI_STATUS +RequestSenseCommand ( + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate, + UINT32 Target, + UINT64 Timeout, + VOID *SenseData, + UINT8 *SenseDataLength + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AtapiScsiPrivate - TODO: add argument description + Target - TODO: add argument description + Timeout - TODO: add argument description + SenseData - TODO: add argument description + SenseDataLength - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET Packet; + UINT8 Cdb[12]; + EFI_STATUS Status; + + ZeroMem (&Packet, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET)); + ZeroMem (Cdb, 12); + + Cdb[0] = OP_REQUEST_SENSE; + Cdb[4] = (UINT8) (*SenseDataLength); + + Packet.Timeout = Timeout; + Packet.DataBuffer = SenseData; + Packet.SenseData = NULL; + Packet.Cdb = Cdb; + Packet.TransferLength = *SenseDataLength; + Packet.CdbLength = 12; + Packet.DataDirection = DataIn; + + Status = SubmitBlockingIoCommand (AtapiScsiPrivate, Target, &Packet); + *SenseDataLength = (UINT8) (Packet.TransferLength); + return Status; +} + +EFI_STATUS +AtapiPacketCommand ( + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate, + UINT32 Target, + UINT8 *PacketCommand, + VOID *Buffer, + UINT32 *ByteCount, + DATA_DIRECTION Direction, + UINT64 TimeoutInMicroSeconds + ) +/*++ + + Routine Description: + Submits ATAPI command packet to the specified ATAPI device. + + Arguments: + AtapiScsiPrivate: Private data structure for the specified channel. + Target: The Target ID of the ATAPI device to send the SCSI + Request Packet. To ATAPI devices attached on an IDE + Channel, Target ID 0 indicates Master device;Target + ID 1 indicates Slave device. + PacketCommand: Points to the ATAPI command packet. + Buffer: Points to the transferred data. + ByteCount: When input,indicates the buffer size; when output, + indicates the actually transferred data size. + Direction: Indicates the data transfer direction. + TimeoutInMicroSeconds: + The timeout, in micro second units, to use for the + execution of this ATAPI command. + A TimeoutInMicroSeconds value of 0 means that + this function will wait indefinitely for the ATAPI + command to execute. + If TimeoutInMicroSeconds is greater than zero, then + this function will return EFI_TIMEOUT if the time + required to execute the ATAPI command is greater + than TimeoutInMicroSeconds. + + Returns: + + +--*/ +// TODO: AtapiScsiPrivate - add argument and description to function comment +// TODO: PacketCommand - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +// TODO: ByteCount - add argument and description to function comment +// TODO: Direction - add argument and description to function comment +{ + + UINT16 *CommandIndex; + UINT8 Count; + EFI_STATUS Status; + + // + // Set all the command parameters by fill related registers. + // Before write to all the following registers, BSY and DRQ must be 0. + // + Status = StatusDRQClear (AtapiScsiPrivate, TimeoutInMicroSeconds); + if (EFI_ERROR (Status)) { + if (Status == EFI_ABORTED) { + Status = EFI_DEVICE_ERROR; + } + + *ByteCount = 0; + return Status; + } + // + // Select device via Device/Head Register. + // "Target = 0" indicates device 0; "Target = 1" indicates device 1 + // + WritePortB ( + AtapiScsiPrivate->PciIo, + AtapiScsiPrivate->IoPort->Head, + (UINT8) ((Target << 4) | DEFAULT_CMD) // DEFAULT_CMD: 0xa0 (1010,0000) + ); + + // + // No OVL; No DMA (by setting feature register) + // + WritePortB ( + AtapiScsiPrivate->PciIo, + AtapiScsiPrivate->IoPort->Reg1.Feature, + 0x00 + ); + + // + // set the transfersize to MAX_ATAPI_BYTE_COUNT to let the device + // determine how much data should be transfered. + // + WritePortB ( + AtapiScsiPrivate->PciIo, + AtapiScsiPrivate->IoPort->CylinderLsb, + (UINT8) (MAX_ATAPI_BYTE_COUNT & 0x00ff) + ); + WritePortB ( + AtapiScsiPrivate->PciIo, + AtapiScsiPrivate->IoPort->CylinderMsb, + (UINT8) (MAX_ATAPI_BYTE_COUNT >> 8) + ); + + // + // DEFAULT_CTL:0x0a (0000,1010) + // Disable interrupt + // + WritePortB ( + AtapiScsiPrivate->PciIo, + AtapiScsiPrivate->IoPort->Alt.DeviceControl, + DEFAULT_CTL + ); + + // + // Send Packet command to inform device + // that the following data bytes are command packet. + // + WritePortB ( + AtapiScsiPrivate->PciIo, + AtapiScsiPrivate->IoPort->Reg.Command, + PACKET_CMD + ); + + // + // Before data transfer, BSY should be 0 and DRQ should be 1. + // if they are not in specified time frame, + // retrieve Sense Key from Error Register before return. + // + Status = StatusDRQReady (AtapiScsiPrivate, TimeoutInMicroSeconds); + if (EFI_ERROR (Status)) { + if (Status == EFI_ABORTED) { + Status = EFI_DEVICE_ERROR; + } + + *ByteCount = 0; + return Status; + } + + // + // Send out command packet + // + CommandIndex = (UINT16 *) PacketCommand; + for (Count = 0; Count < 6; Count++, CommandIndex++) { + WritePortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Data, *CommandIndex); + } + + // + // call AtapiPassThruPioReadWriteData() function to get + // requested transfer data form device. + // + return AtapiPassThruPioReadWriteData ( + AtapiScsiPrivate, + Buffer, + ByteCount, + Direction, + TimeoutInMicroSeconds + ); +} + +EFI_STATUS +AtapiPassThruPioReadWriteData ( + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate, + UINT16 *Buffer, + UINT32 *ByteCount, + DATA_DIRECTION Direction, + UINT64 TimeoutInMicroSeconds + ) +/*++ + + Routine Description: + Performs data transfer between ATAPI device and host after the + ATAPI command packet is sent. + + Arguments: + AtapiScsiPrivate: Private data structure for the specified channel. + Buffer: Points to the transferred data. + ByteCount: When input,indicates the buffer size; when output, + indicates the actually transferred data size. + Direction: Indicates the data transfer direction. + TimeoutInMicroSeconds: + The timeout, in micro second units, to use for the + execution of this ATAPI command. + A TimeoutInMicroSeconds value of 0 means that + this function will wait indefinitely for the ATAPI + command to execute. + If TimeoutInMicroSeconds is greater than zero, then + this function will return EFI_TIMEOUT if the time + required to execute the ATAPI command is greater + than TimeoutInMicroSeconds. + + Returns: + + +--*/ +// TODO: AtapiScsiPrivate - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +// TODO: ByteCount - add argument and description to function comment +// TODO: Direction - add argument and description to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_WARN_BUFFER_TOO_SMALL - add return value to function comment +{ + UINT32 Index; + UINT32 RequiredWordCount; + UINT32 ActualWordCount; + + UINT32 WordCount; + EFI_STATUS Status; + UINT16 *ptrBuffer; + + Status = EFI_SUCCESS; + + // + // Non Data transfer request is also supported. + // + if (*ByteCount == 0 || Buffer == NULL) { + *ByteCount = 0; + if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate, TimeoutInMicroSeconds))) { + return EFI_DEVICE_ERROR; + } + } + + ptrBuffer = Buffer; + RequiredWordCount = *ByteCount / 2; + + // + // ActuralWordCount means the word count of data really transfered. + // + ActualWordCount = 0; + + while (ActualWordCount < RequiredWordCount) { + // + // before each data transfer stream, the host should poll DRQ bit ready, + // which indicates device's ready for data transfer . + // + Status = StatusDRQReady (AtapiScsiPrivate, TimeoutInMicroSeconds); + if (EFI_ERROR (Status)) { + *ByteCount = ActualWordCount * 2; + + AtapiPassThruCheckErrorStatus (AtapiScsiPrivate); + + if (ActualWordCount == 0) { + return EFI_DEVICE_ERROR; + } + // + // ActualWordCount > 0 + // + if (ActualWordCount < RequiredWordCount) { + return EFI_WARN_BUFFER_TOO_SMALL; + } + } + // + // get current data transfer size from Cylinder Registers. + // + WordCount = + ( + (ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->CylinderMsb) << 8) | + ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->CylinderLsb) + ) & 0xffff; + WordCount /= 2; + + // + // perform a series data In/Out. + // + for (Index = 0; (Index < WordCount) && (ActualWordCount < RequiredWordCount); Index++, ActualWordCount++) { + + if (Direction == DataIn) { + + *ptrBuffer = ReadPortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Data); + } else { + + WritePortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Data, *ptrBuffer); + } + + ptrBuffer++; + + } + } + // + // After data transfer is completed, normally, DRQ bit should clear. + // + StatusDRQClear (AtapiScsiPrivate, TimeoutInMicroSeconds); + + // + // read status register to check whether error happens. + // + Status = AtapiPassThruCheckErrorStatus (AtapiScsiPrivate); + + *ByteCount = ActualWordCount * 2; + + return Status; +} + + +UINT8 +ReadPortB ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT16 Port + ) +/*++ + Read one byte from a specified I/O port. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: function comment is missing 'Returns:' +// TODO: PciIo - add argument and description to function comment +// TODO: Port - add argument and description to function comment +{ + UINT8 Data; + + Data = 0; + PciIo->Io.Read ( + PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) Port, + 1, + &Data + ); + return Data; +} + + +UINT16 +ReadPortW ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT16 Port + ) +/*++ + Read one word from a specified I/O port. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: function comment is missing 'Returns:' +// TODO: PciIo - add argument and description to function comment +// TODO: Port - add argument and description to function comment +{ + UINT16 Data; + + Data = 0; + PciIo->Io.Read ( + PciIo, + EfiPciIoWidthUint16, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) Port, + 1, + &Data + ); + return Data; +} + + +VOID +WritePortB ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT16 Port, + IN UINT8 Data + ) +/*++ + Write one byte to a specified I/O port. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: function comment is missing 'Returns:' +// TODO: PciIo - add argument and description to function comment +// TODO: Port - add argument and description to function comment +// TODO: Data - add argument and description to function comment +{ + + PciIo->Io.Write ( + PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) Port, + 1, + &Data + ); + +} + + +VOID +WritePortW ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT16 Port, + IN UINT16 Data + ) +/*++ + Write one word to a specified I/O port. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: function comment is missing 'Returns:' +// TODO: PciIo - add argument and description to function comment +// TODO: Port - add argument and description to function comment +// TODO: Data - add argument and description to function comment +{ + + PciIo->Io.Write ( + PciIo, + EfiPciIoWidthUint16, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) Port, + 1, + &Data + ); +} + +EFI_STATUS +StatusDRQClear ( + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate, + UINT64 TimeoutInMicroSeconds + ) +/*++ + Check whether DRQ is clear in the Status Register. (BSY must also be cleared) + If TimeoutInMicroSeconds is zero, this routine should wait infinitely for + DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is + elapsed. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: function comment is missing 'Returns:' +// TODO: AtapiScsiPrivate - add argument and description to function comment +// TODO: TimeoutInMicroSeconds - add argument and description to function comment +// TODO: EFI_ABORTED - add return value to function comment +// TODO: EFI_TIMEOUT - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + UINT64 Delay; + UINT8 StatusRegister; + UINT8 ErrRegister; + + if (TimeoutInMicroSeconds == 0) { + Delay = 2; + } else { + Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1; + } + + do { + + StatusRegister = ReadPortB ( + AtapiScsiPrivate->PciIo, + AtapiScsiPrivate->IoPort->Reg.Status + ); + + // + // wait for BSY == 0 and DRQ == 0 + // + if ((StatusRegister & (DRQ | BSY)) == 0) { + break; + } + // + // check whether the command is aborted by the device + // + if ((StatusRegister & (BSY | ERR)) == ERR) { + + ErrRegister = ReadPortB ( + AtapiScsiPrivate->PciIo, + AtapiScsiPrivate->IoPort->Reg1.Error + ); + if ((ErrRegister & ABRT_ERR) == ABRT_ERR) { + + return EFI_ABORTED; + } + } + // + // Stall for 30 us + // + gBS->Stall (30); + + // + // Loop infinitely if not meeting expected condition + // + if (TimeoutInMicroSeconds == 0) { + Delay = 2; + } + + Delay--; + } while (Delay); + + if (Delay == 0) { + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +AltStatusDRQClear ( + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate, + UINT64 TimeoutInMicroSeconds + ) +/*++ + Check whether DRQ is clear in the Alternate Status Register. + (BSY must also be cleared). + If TimeoutInMicroSeconds is zero, this routine should wait infinitely for + DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is + elapsed. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: function comment is missing 'Returns:' +// TODO: AtapiScsiPrivate - add argument and description to function comment +// TODO: TimeoutInMicroSeconds - add argument and description to function comment +// TODO: EFI_ABORTED - add return value to function comment +// TODO: EFI_TIMEOUT - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + UINT64 Delay; + UINT8 AltStatusRegister; + UINT8 ErrRegister; + + if (TimeoutInMicroSeconds == 0) { + Delay = 2; + } else { + Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1; + } + + do { + + AltStatusRegister = ReadPortB ( + AtapiScsiPrivate->PciIo, + AtapiScsiPrivate->IoPort->Alt.AltStatus + ); + + // + // wait for BSY == 0 and DRQ == 0 + // + if ((AltStatusRegister & (DRQ | BSY)) == 0) { + break; + } + + if ((AltStatusRegister & (BSY | ERR)) == ERR) { + + ErrRegister = ReadPortB ( + AtapiScsiPrivate->PciIo, + AtapiScsiPrivate->IoPort->Reg1.Error + ); + if ((ErrRegister & ABRT_ERR) == ABRT_ERR) { + + return EFI_ABORTED; + } + } + // + // Stall for 30 us + // + gBS->Stall (30); + + // + // Loop infinitely if not meeting expected condition + // + if (TimeoutInMicroSeconds == 0) { + Delay = 2; + } + + Delay--; + } while (Delay); + + if (Delay == 0) { + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +StatusDRQReady ( + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate, + UINT64 TimeoutInMicroSeconds + ) +/*++ + Check whether DRQ is ready in the Status Register. (BSY must also be cleared) + If TimeoutInMicroSeconds is zero, this routine should wait infinitely for + DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is + elapsed. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: function comment is missing 'Returns:' +// TODO: AtapiScsiPrivate - add argument and description to function comment +// TODO: TimeoutInMicroSeconds - add argument and description to function comment +// TODO: EFI_ABORTED - add return value to function comment +// TODO: EFI_TIMEOUT - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + UINT64 Delay; + UINT8 StatusRegister; + UINT8 ErrRegister; + + if (TimeoutInMicroSeconds == 0) { + Delay = 2; + } else { + Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1; + } + + do { + // + // read Status Register will clear interrupt + // + StatusRegister = ReadPortB ( + AtapiScsiPrivate->PciIo, + AtapiScsiPrivate->IoPort->Reg.Status + ); + + // + // BSY==0,DRQ==1 + // + if ((StatusRegister & (BSY | DRQ)) == DRQ) { + break; + } + + if ((StatusRegister & (BSY | ERR)) == ERR) { + + ErrRegister = ReadPortB ( + AtapiScsiPrivate->PciIo, + AtapiScsiPrivate->IoPort->Reg1.Error + ); + if ((ErrRegister & ABRT_ERR) == ABRT_ERR) { + return EFI_ABORTED; + } + } + + // + // Stall for 30 us + // + gBS->Stall (30); + + // + // Loop infinitely if not meeting expected condition + // + if (TimeoutInMicroSeconds == 0) { + Delay = 2; + } + + Delay--; + } while (Delay); + + if (Delay == 0) { + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +AltStatusDRQReady ( + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate, + UINT64 TimeoutInMicroSeconds + ) +/*++ + Check whether DRQ is ready in the Alternate Status Register. + (BSY must also be cleared) + If TimeoutInMicroSeconds is zero, this routine should wait infinitely for + DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is + elapsed. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: function comment is missing 'Returns:' +// TODO: AtapiScsiPrivate - add argument and description to function comment +// TODO: TimeoutInMicroSeconds - add argument and description to function comment +// TODO: EFI_ABORTED - add return value to function comment +// TODO: EFI_TIMEOUT - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + UINT64 Delay; + UINT8 AltStatusRegister; + UINT8 ErrRegister; + + if (TimeoutInMicroSeconds == 0) { + Delay = 2; + } else { + Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1; + } + + do { + // + // read Status Register will clear interrupt + // + AltStatusRegister = ReadPortB ( + AtapiScsiPrivate->PciIo, + AtapiScsiPrivate->IoPort->Alt.AltStatus + ); + // + // BSY==0,DRQ==1 + // + if ((AltStatusRegister & (BSY | DRQ)) == DRQ) { + break; + } + + if ((AltStatusRegister & (BSY | ERR)) == ERR) { + + ErrRegister = ReadPortB ( + AtapiScsiPrivate->PciIo, + AtapiScsiPrivate->IoPort->Reg1.Error + ); + if ((ErrRegister & ABRT_ERR) == ABRT_ERR) { + return EFI_ABORTED; + } + } + + // + // Stall for 30 us + // + gBS->Stall (30); + + // + // Loop infinitely if not meeting expected condition + // + if (TimeoutInMicroSeconds == 0) { + Delay = 2; + } + + Delay--; + } while (Delay); + + if (Delay == 0) { + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +StatusWaitForBSYClear ( + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate, + UINT64 TimeoutInMicroSeconds + ) +/*++ + Check whether BSY is clear in the Status Register. + If TimeoutInMicroSeconds is zero, this routine should wait infinitely for + BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is + elapsed. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: function comment is missing 'Returns:' +// TODO: AtapiScsiPrivate - add argument and description to function comment +// TODO: TimeoutInMicroSeconds - add argument and description to function comment +// TODO: EFI_TIMEOUT - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + UINT64 Delay; + UINT8 StatusRegister; + + if (TimeoutInMicroSeconds == 0) { + Delay = 2; + } else { + Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1; + } + + do { + + StatusRegister = ReadPortB ( + AtapiScsiPrivate->PciIo, + AtapiScsiPrivate->IoPort->Reg.Status + ); + if ((StatusRegister & BSY) == 0x00) { + break; + } + + // + // Stall for 30 us + // + gBS->Stall (30); + + // + // Loop infinitely if not meeting expected condition + // + if (TimeoutInMicroSeconds == 0) { + Delay = 2; + } + + Delay--; + } while (Delay); + + if (Delay == 0) { + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +AltStatusWaitForBSYClear ( + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate, + UINT64 TimeoutInMicroSeconds + ) +/*++ + Check whether BSY is clear in the Alternate Status Register. + If TimeoutInMicroSeconds is zero, this routine should wait infinitely for + BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is + elapsed. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: function comment is missing 'Returns:' +// TODO: AtapiScsiPrivate - add argument and description to function comment +// TODO: TimeoutInMicroSeconds - add argument and description to function comment +// TODO: EFI_TIMEOUT - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + UINT64 Delay; + UINT8 AltStatusRegister; + + if (TimeoutInMicroSeconds == 0) { + Delay = 2; + } else { + Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1; + } + + do { + + AltStatusRegister = ReadPortB ( + AtapiScsiPrivate->PciIo, + AtapiScsiPrivate->IoPort->Alt.AltStatus + ); + if ((AltStatusRegister & BSY) == 0x00) { + break; + } + + // + // Stall for 30 us + // + gBS->Stall (30); + // + // Loop infinitely if not meeting expected condition + // + if (TimeoutInMicroSeconds == 0) { + Delay = 2; + } + + Delay--; + } while (Delay); + + if (Delay == 0) { + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +StatusDRDYReady ( + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate, + UINT64 TimeoutInMicroSeconds + ) +/*++ + Check whether DRDY is ready in the Status Register. + (BSY must also be cleared) + If TimeoutInMicroSeconds is zero, this routine should wait infinitely for + DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is + elapsed. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: function comment is missing 'Returns:' +// TODO: AtapiScsiPrivate - add argument and description to function comment +// TODO: TimeoutInMicroSeconds - add argument and description to function comment +// TODO: EFI_ABORTED - add return value to function comment +// TODO: EFI_TIMEOUT - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + UINT64 Delay; + UINT8 StatusRegister; + UINT8 ErrRegister; + + if (TimeoutInMicroSeconds == 0) { + Delay = 2; + } else { + Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1; + } + + do { + StatusRegister = ReadPortB ( + AtapiScsiPrivate->PciIo, + AtapiScsiPrivate->IoPort->Reg.Status + ); + // + // BSY == 0 , DRDY == 1 + // + if ((StatusRegister & (DRDY | BSY)) == DRDY) { + break; + } + + if ((StatusRegister & (BSY | ERR)) == ERR) { + + ErrRegister = ReadPortB ( + AtapiScsiPrivate->PciIo, + AtapiScsiPrivate->IoPort->Reg1.Error + ); + if ((ErrRegister & ABRT_ERR) == ABRT_ERR) { + return EFI_ABORTED; + } + } + + // + // Stall for 30 us + // + gBS->Stall (30); + // + // Loop infinitely if not meeting expected condition + // + if (TimeoutInMicroSeconds == 0) { + Delay = 2; + } + + Delay--; + } while (Delay); + + if (Delay == 0) { + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +AltStatusDRDYReady ( + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate, + UINT64 TimeoutInMicroSeconds + ) +/*++ + Check whether DRDY is ready in the Alternate Status Register. + (BSY must also be cleared) + If TimeoutInMicroSeconds is zero, this routine should wait infinitely for + DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is + elapsed. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: function comment is missing 'Returns:' +// TODO: AtapiScsiPrivate - add argument and description to function comment +// TODO: TimeoutInMicroSeconds - add argument and description to function comment +// TODO: EFI_ABORTED - add return value to function comment +// TODO: EFI_TIMEOUT - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + UINT64 Delay; + UINT8 AltStatusRegister; + UINT8 ErrRegister; + + if (TimeoutInMicroSeconds == 0) { + Delay = 2; + } else { + Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1; + } + + do { + AltStatusRegister = ReadPortB ( + AtapiScsiPrivate->PciIo, + AtapiScsiPrivate->IoPort->Alt.AltStatus + ); + // + // BSY == 0 , DRDY == 1 + // + if ((AltStatusRegister & (DRDY | BSY)) == DRDY) { + break; + } + + if ((AltStatusRegister & (BSY | ERR)) == ERR) { + + ErrRegister = ReadPortB ( + AtapiScsiPrivate->PciIo, + AtapiScsiPrivate->IoPort->Reg1.Error + ); + if ((ErrRegister & ABRT_ERR) == ABRT_ERR) { + return EFI_ABORTED; + } + } + + // + // Stall for 30 us + // + gBS->Stall (30); + // + // Loop infinitely if not meeting expected condition + // + if (TimeoutInMicroSeconds == 0) { + Delay = 2; + } + + Delay--; + } while (Delay); + + if (Delay == 0) { + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +AtapiPassThruCheckErrorStatus ( + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate + ) +/*++ + Check Error Register for Error Information. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: function comment is missing 'Returns:' +// TODO: AtapiScsiPrivate - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +{ + UINT8 StatusRegister; + +//#ifdef EFI_DEBUG + + UINT8 ErrorRegister; + +//#endif + + StatusRegister = ReadPortB ( + AtapiScsiPrivate->PciIo, + AtapiScsiPrivate->IoPort->Reg.Status + ); + DEBUG_CODE ( + + if (StatusRegister & DWF) { + DEBUG ( + (EFI_D_BLKIO, + "AtapiPassThruCheckErrorStatus()-- %02x : Error : Write Fault\n", + StatusRegister) + ); + } + + if (StatusRegister & CORR) { + DEBUG ( + (EFI_D_BLKIO, + "AtapiPassThruCheckErrorStatus()-- %02x : Error : Corrected Data\n", + StatusRegister) + ); + } + + if (StatusRegister & ERR) { + ErrorRegister = ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Reg1.Error); + + if (ErrorRegister & BBK_ERR) { + DEBUG ( + (EFI_D_BLKIO, + "AtapiPassThruCheckErrorStatus()-- %02x : Error : Bad Block Detected\n", + ErrorRegister) + ); + } + + if (ErrorRegister & UNC_ERR) { + DEBUG ( + (EFI_D_BLKIO, + "AtapiPassThruCheckErrorStatus()-- %02x : Error : Uncorrectable Data\n", + ErrorRegister) + ); + } + + if (ErrorRegister & MC_ERR) { + DEBUG ( + (EFI_D_BLKIO, + "AtapiPassThruCheckErrorStatus()-- %02x : Error : Media Change\n", + ErrorRegister) + ); + } + + if (ErrorRegister & ABRT_ERR) { + DEBUG ( + (EFI_D_BLKIO, + "AtapiPassThruCheckErrorStatus()-- %02x : Error : Abort\n", + ErrorRegister) + ); + } + + if (ErrorRegister & TK0NF_ERR) { + DEBUG ( + (EFI_D_BLKIO, + "AtapiPassThruCheckErrorStatus()-- %02x : Error : Track 0 Not Found\n", + ErrorRegister) + ); + } + + if (ErrorRegister & AMNF_ERR) { + DEBUG ( + (EFI_D_BLKIO, + "AtapiPassThruCheckErrorStatus()-- %02x : Error : Address Mark Not Found\n", + ErrorRegister) + ); + } + + } + ); + + if ((StatusRegister & (ERR | DWF | CORR)) == 0) { + + return EFI_SUCCESS; + } + + return EFI_DEVICE_ERROR; + +} diff --git a/EdkModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.h b/EdkModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.h new file mode 100644 index 0000000000..486fd2dd0e --- /dev/null +++ b/EdkModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.h @@ -0,0 +1,916 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + AtapiPassThru.h + +Abstract: + + +Revision History +--*/ + +#ifndef _APT_H +#define _APT_H + + +#include + +// +// bit definition +// +#define bit(a) 1 << (a) + +#define MAX_TARGET_ID 4 +// +// IDE Registers +// +typedef union { + UINT16 Command; /* when write */ + UINT16 Status; /* when read */ +} IDE_CMD_OR_STATUS; + +typedef union { + UINT16 Error; /* when read */ + UINT16 Feature; /* when write */ +} IDE_ERROR_OR_FEATURE; + +typedef union { + UINT16 AltStatus; /* when read */ + UINT16 DeviceControl; /* when write */ +} IDE_AltStatus_OR_DeviceControl; + +// +// IDE registers set +// +typedef struct { + UINT16 Data; + IDE_ERROR_OR_FEATURE Reg1; + UINT16 SectorCount; + UINT16 SectorNumber; + UINT16 CylinderLsb; + UINT16 CylinderMsb; + UINT16 Head; + IDE_CMD_OR_STATUS Reg; + + IDE_AltStatus_OR_DeviceControl Alt; + UINT16 DriveAddress; + + UINT16 MasterSlave; +} IDE_BASE_REGISTERS; + +#define ATAPI_SCSI_PASS_THRU_DEV_SIGNATURE EFI_SIGNATURE_32 ('a', 's', 'p', 't') + +typedef struct { + UINTN Signature; + + EFI_HANDLE Handle; + EFI_SCSI_PASS_THRU_PROTOCOL ScsiPassThru; + EFI_SCSI_PASS_THRU_MODE ScsiPassThruMode; + EFI_PCI_IO_PROTOCOL *PciIo; + + // + // Local Data goes here + // + IDE_BASE_REGISTERS *IoPort; + + CHAR16 ControllerName[100]; + CHAR16 ChannelName[100]; + + UINT32 LatestTargetId; + UINT64 LatestLun; + +} ATAPI_SCSI_PASS_THRU_DEV; + +#define ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS(a) \ + CR (a, \ + ATAPI_SCSI_PASS_THRU_DEV, \ + ScsiPassThru, \ + ATAPI_SCSI_PASS_THRU_DEV_SIGNATURE \ + ) + +// +// Global Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gAtapiScsiPassThruDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gAtapiScsiPassThruComponentName; + +// +// ATAPI Command op code +// +#define OP_INQUIRY 0x12 +#define OP_LOAD_UNLOAD_CD 0xa6 +#define OP_MECHANISM_STATUS 0xbd +#define OP_MODE_SELECT_10 0x55 +#define OP_MODE_SENSE_10 0x5a +#define OP_PAUSE_RESUME 0x4b +#define OP_PLAY_AUDIO_10 0x45 +#define OP_PLAY_AUDIO_MSF 0x47 +#define OP_PLAY_CD 0xbc +#define OP_PLAY_CD_MSF 0xb4 +#define OP_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e +#define OP_READ_10 0x28 +#define OP_READ_12 0xa8 +#define OP_READ_CAPACITY 0x25 +#define OP_READ_CD 0xbe +#define OP_READ_CD_MSF 0xb9 +#define OP_READ_HEADER 0x44 +#define OP_READ_SUB_CHANNEL 0x42 +#define OP_READ_TOC 0x43 +#define OP_REQUEST_SENSE 0x03 +#define OP_SCAN 0xba +#define OP_SEEK_10 0x2b +#define OP_SET_CD_SPEED 0xbb +#define OP_STOPPLAY_SCAN 0x4e +#define OP_START_STOP_UNIT 0x1b +#define OP_TEST_UNIT_READY 0x00 + +#define OP_FORMAT_UNIT 0x04 +#define OP_READ_FORMAT_CAPACITIES 0x23 +#define OP_VERIFY 0x2f +#define OP_WRITE_10 0x2a +#define OP_WRITE_12 0xaa +#define OP_WRITE_AND_VERIFY 0x2e + +// +// ATA Command +// +#define ATAPI_SOFT_RESET_CMD 0x08 + +typedef enum { + DataIn = 0, + DataOut = 1, + NoData = 2, + End = 0xff +} DATA_DIRECTION; + +typedef struct { + UINT8 OpCode; + DATA_DIRECTION Direction; +} SCSI_COMMAND_SET; + +#define MAX_CHANNEL 2 + +#define ValidCdbLength(Len) ((Len) == 6 || (Len) == 10 || (Len) == 12) ? 1 : 0 + +// +// IDE registers bit definitions +// +// ATA Err Reg bitmap +// +#define BBK_ERR bit (7) /* Bad block detected */ +#define UNC_ERR bit (6) /* Uncorrectable Data */ +#define MC_ERR bit (5) /* Media Change */ +#define IDNF_ERR bit (4) /* ID Not Found */ +#define MCR_ERR bit (3) /* Media Change Requested */ +#define ABRT_ERR bit (2) /* Aborted Command */ +#define TK0NF_ERR bit (1) /* Track 0 Not Found */ +#define AMNF_ERR bit (0) /* Address Mark Not Found */ + +// +// ATAPI Err Reg bitmap +// +#define SENSE_KEY_ERR (bit (7) | bit (6) | bit (5) | bit (4)) +#define EOM_ERR bit (1) /* End of Media Detected */ +#define ILI_ERR bit (0) /* Illegal Length Indication */ + +// +// Device/Head Reg +// +#define LBA_MODE bit (6) +#define DEV bit (4) +#define HS3 bit (3) +#define HS2 bit (2) +#define HS1 bit (1) +#define HS0 bit (0) +#define CHS_MODE (0) +#define DRV0 (0) +#define DRV1 (1) +#define MST_DRV DRV0 +#define SLV_DRV DRV1 + +// +// Status Reg +// +#define BSY bit (7) /* Controller Busy */ +#define DRDY bit (6) /* Drive Ready */ +#define DWF bit (5) /* Drive Write Fault */ +#define DSC bit (4) /* Disk Seek Complete */ +#define DRQ bit (3) /* Data Request */ +#define CORR bit (2) /* Corrected Data */ +#define IDX bit (1) /* Index */ +#define ERR bit (0) /* Error */ +#define CHECK bit (0) /* Check bit for ATAPI Status Reg */ + +// +// Device Control Reg +// +#define SRST bit (2) /* Software Reset */ +#define IEN_L bit (1) /* Interrupt Enable #*/ + +// +// ATAPI Feature Register +// +#define OVERLAP bit (1) +#define DMA bit (0) + +// +// ATAPI Interrupt Reason Reson Reg (ATA Sector Count Register) +// +#define RELEASE bit (2) +#define IO bit (1) +#define CoD bit (0) + +#define PACKET_CMD 0xA0 + +#define DEFAULT_CMD (0xa0) +// +// default content of device control register, disable INT +// +#define DEFAULT_CTL (0x0a) +#define MAX_ATAPI_BYTE_COUNT (0xfffe) + +// +// function prototype +// +EFI_STATUS +EFIAPI +AtapiScsiPassThruDriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) + /*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ImageHandle - TODO: add argument description + SystemTable - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +RegisterAtapiScsiPassThru ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_PCI_IO_PROTOCOL *PciIo + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Controller - TODO: add argument description + PciIo - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +AtapiScsiPassThruFunction ( + IN EFI_SCSI_PASS_THRU_PROTOCOL *This, + IN UINT32 Target, + IN UINT64 Lun, + IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet, + IN EFI_EVENT Event OPTIONAL + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Target - TODO: add argument description + Lun - TODO: add argument description + Packet - TODO: add argument description + Event - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +AtapiScsiPassThruGetNextDevice ( + IN EFI_SCSI_PASS_THRU_PROTOCOL *This, + IN OUT UINT32 *Target, + IN OUT UINT64 *Lun + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Target - TODO: add argument description + Lun - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +AtapiScsiPassThruBuildDevicePath ( + IN EFI_SCSI_PASS_THRU_PROTOCOL *This, + IN UINT32 Target, + IN UINT64 Lun, + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Target - TODO: add argument description + Lun - TODO: add argument description + DevicePath - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +AtapiScsiPassThruGetTargetLun ( + IN EFI_SCSI_PASS_THRU_PROTOCOL *This, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + OUT UINT32 *Target, + OUT UINT64 *Lun + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + DevicePath - TODO: add argument description + Target - TODO: add argument description + Lun - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +AtapiScsiPassThruResetChannel ( + IN EFI_SCSI_PASS_THRU_PROTOCOL *This + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +AtapiScsiPassThruResetTarget ( + IN EFI_SCSI_PASS_THRU_PROTOCOL *This, + IN UINT32 Target, + IN UINT64 Lun + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Target - TODO: add argument description + Lun - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +CheckSCSIRequestPacket ( + EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Packet - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +SubmitBlockingIoCommand ( + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate, + UINT32 Target, + EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AtapiScsiPrivate - TODO: add argument description + Target - TODO: add argument description + Packet - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +IsCommandValid ( + EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet + ) + /*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Packet - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +RequestSenseCommand ( + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate, + UINT32 Target, + UINT64 Timeout, + VOID *SenseData, + UINT8 *SenseDataLength + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AtapiScsiPrivate - TODO: add argument description + Target - TODO: add argument description + Timeout - TODO: add argument description + SenseData - TODO: add argument description + SenseDataLength - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtapiPacketCommand ( + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate, + UINT32 Target, + UINT8 *PacketCommand, + VOID *Buffer, + UINT32 *ByteCount, + DATA_DIRECTION Direction, + UINT64 TimeOutInMicroSeconds + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AtapiScsiPrivate - TODO: add argument description + Target - TODO: add argument description + PacketCommand - TODO: add argument description + Buffer - TODO: add argument description + ByteCount - TODO: add argument description + Direction - TODO: add argument description + TimeOutInMicroSeconds - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + + +UINT8 +ReadPortB ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT16 Port + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIo - TODO: add argument description + Port - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + + +UINT16 +ReadPortW ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT16 Port + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIo - TODO: add argument description + Port - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + + +VOID +WritePortB ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT16 Port, + IN UINT8 Data + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIo - TODO: add argument description + Port - TODO: add argument description + Data - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + + +VOID +WritePortW ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT16 Port, + IN UINT16 Data + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIo - TODO: add argument description + Port - TODO: add argument description + Data - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +StatusDRQClear ( + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate, + UINT64 TimeOutInMicroSeconds + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AtapiScsiPrivate - TODO: add argument description + TimeOutInMicroSeconds - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AltStatusDRQClear ( + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate, + UINT64 TimeOutInMicroSeconds + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AtapiScsiPrivate - TODO: add argument description + TimeOutInMicroSeconds - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +StatusDRQReady ( + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate, + UINT64 TimeOutInMicroSeconds + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AtapiScsiPrivate - TODO: add argument description + TimeOutInMicroSeconds - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AltStatusDRQReady ( + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate, + UINT64 TimeOutInMicroSeconds + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AtapiScsiPrivate - TODO: add argument description + TimeOutInMicroSeconds - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +StatusWaitForBSYClear ( + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate, + UINT64 TimeoutInMicroSeconds + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AtapiScsiPrivate - TODO: add argument description + TimeoutInMicroSeconds - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AltStatusWaitForBSYClear ( + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate, + UINT64 TimeoutInMicroSeconds + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AtapiScsiPrivate - TODO: add argument description + TimeoutInMicroSeconds - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +StatusDRDYReady ( + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate, + UINT64 TimeoutInMicroSeconds + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AtapiScsiPrivate - TODO: add argument description + TimeoutInMicroSeconds - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AltStatusDRDYReady ( + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate, + UINT64 TimeoutInMicroSeconds + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AtapiScsiPrivate - TODO: add argument description + TimeoutInMicroSeconds - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtapiPassThruPioReadWriteData ( + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate, + UINT16 *Buffer, + UINT32 *ByteCount, + DATA_DIRECTION Direction, + UINT64 TimeOutInMicroSeconds + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AtapiScsiPrivate - TODO: add argument description + Buffer - TODO: add argument description + ByteCount - TODO: add argument description + Direction - TODO: add argument description + TimeOutInMicroSeconds - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtapiPassThruCheckErrorStatus ( + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AtapiScsiPrivate - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; +#endif diff --git a/EdkModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.mbd b/EdkModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.mbd new file mode 100644 index 0000000000..903a092439 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.mbd @@ -0,0 +1,42 @@ + + + + + AtapiPassThru + E49061CE-99A7-41d3-AB3A-36E5CFBAD63E + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:18 + + + UefiBootServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + EdkDxePrintLib + BaseLib + DxeMemoryAllocationLib + + diff --git a/EdkModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.msa b/EdkModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.msa new file mode 100644 index 0000000000..1c13016bcf --- /dev/null +++ b/EdkModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.msa @@ -0,0 +1,65 @@ + + + + + AtapiPassThru + UEFI_DRIVER + BS_DRIVER + E49061CE-99A7-41d3-AB3A-36E5CFBAD63E + 0 + Description file for the Atapi Passthru component. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:18 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + BaseLib + UefiLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + + + AtapiPassThru.h + AtapiPassThru.c + ComponentName.c + + + MdePkg + + + PciIo + ScsiPassThru + + + + + + + gAtapiScsiPassThruDriverBinding + gAtapiScsiPassThruComponentName + + + diff --git a/EdkModulePkg/Bus/Pci/AtapiPassThru/Dxe/ComponentName.c b/EdkModulePkg/Bus/Pci/AtapiPassThru/Dxe/ComponentName.c new file mode 100644 index 0000000000..14658b0ace --- /dev/null +++ b/EdkModulePkg/Bus/Pci/AtapiPassThru/Dxe/ComponentName.c @@ -0,0 +1,154 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ComponentName.c + +Abstract: + +--*/ +#include "AtapiPassThru.h" + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +AtapiScsiPassThruComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +EFI_STATUS +EFIAPI +AtapiScsiPassThruComponentNameGetControllerName ( + 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 +// +EFI_COMPONENT_NAME_PROTOCOL gAtapiScsiPassThruComponentName = { + AtapiScsiPassThruComponentNameGetDriverName, + AtapiScsiPassThruComponentNameGetControllerName, + "eng" +}; + +static EFI_UNICODE_STRING_TABLE mAtapiScsiPassThruDriverNameTable[] = { + { "eng", (CHAR16 *) L"ATAPI SCSI Pass Thru Driver" }, + { NULL , NULL } +}; + +EFI_STATUS +EFIAPI +AtapiScsiPassThruComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gAtapiScsiPassThruComponentName.SupportedLanguages, + mAtapiScsiPassThruDriverNameTable, + DriverName + ); +} + +EFI_STATUS +EFIAPI +AtapiScsiPassThruComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + 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. + 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. + + Returns: + 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. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return EFI_UNSUPPORTED; +} diff --git a/EdkModulePkg/Bus/Pci/AtapiPassThru/Dxe/build.xml b/EdkModulePkg/Bus/Pci/AtapiPassThru/Dxe/build.xml new file mode 100644 index 0000000000..d9b2b666b2 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/AtapiPassThru/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Bus/Pci/CirrusLogic/Dxe/CirrusLogic5430.c b/EdkModulePkg/Bus/Pci/CirrusLogic/Dxe/CirrusLogic5430.c new file mode 100644 index 0000000000..91d6accd99 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/CirrusLogic/Dxe/CirrusLogic5430.c @@ -0,0 +1,346 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + CirrusLogic5430.c + +Abstract: + + Cirrus Logic 5430 Controller Driver. + This driver is a sample implementation of the UGA Draw Protocol for the + Cirrus Logic 5430 family of PCI video controllers. This driver is only + usable in the EFI pre-boot environment. This sample is intended to show + how the UGA Draw Protocol is able to function. The UGA I/O Protocol is not + implemented in this sample. A fully compliant EFI UGA driver requires both + the UGA Draw and the UGA I/O Protocol. Please refer to Microsoft's + documentation on UGA for details on how to write a UGA driver that is able + to function both in the EFI pre-boot environment and from the OS runtime. + +Revision History: + +--*/ + +// +// Cirrus Logic 5430 Controller Driver +// + +#include "CirrusLogic5430.h" + +EFI_DRIVER_BINDING_PROTOCOL gCirrusLogic5430DriverBinding = { + CirrusLogic5430ControllerDriverSupported, + CirrusLogic5430ControllerDriverStart, + CirrusLogic5430ControllerDriverStop, + 0x10, + NULL, + NULL +}; + +EFI_STATUS +EFIAPI +CirrusLogic5430ControllerDriverSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Controller - add argument and description to function comment +// TODO: RemainingDevicePath - add argument and description to function comment +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + PCI_TYPE00 Pci; + + // + // Open the PCI I/O Protocol + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Read the PCI Configuration Header from the PCI Device + // + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint32, + 0, + sizeof (Pci) / sizeof (UINT32), + &Pci + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = EFI_UNSUPPORTED; + // + // See if the I/O enable is on. Most systems only allow one VGA device to be turned on + // at a time, so see if this is one that is turned on. + // + // if (((Pci.Hdr.Command & 0x01) == 0x01)) { + // + // See if this is a Cirrus Logic PCI controller + // + if (Pci.Hdr.VendorId == CIRRUS_LOGIC_VENDOR_ID) { + // + // See if this is a 5430 or a 5446 PCI controller + // + if (Pci.Hdr.DeviceId == CIRRUS_LOGIC_5430_DEVICE_ID) { + Status = EFI_SUCCESS; + } + + if (Pci.Hdr.DeviceId == CIRRUS_LOGIC_5430_ALTERNATE_DEVICE_ID) { + Status = EFI_SUCCESS; + } + + if (Pci.Hdr.DeviceId == CIRRUS_LOGIC_5446_DEVICE_ID) { + Status = EFI_SUCCESS; + } + } + +Done: + // + // Close the PCI I/O Protocol + // + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return Status; +} + +EFI_STATUS +EFIAPI +CirrusLogic5430ControllerDriverStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Controller - add argument and description to function comment +// TODO: RemainingDevicePath - add argument and description to function comment +{ + EFI_STATUS Status; + CIRRUS_LOGIC_5430_PRIVATE_DATA *Private; + + // + // Allocate Private context data for UGA Draw inteface. + // + Private = NULL; + Private = AllocateZeroPool (sizeof (CIRRUS_LOGIC_5430_PRIVATE_DATA)); + if (Private == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + + // + // Set up context record + // + Private->Signature = CIRRUS_LOGIC_5430_PRIVATE_DATA_SIGNATURE; + Private->Handle = Controller; + + // + // Open PCI I/O Protocol + // + Status = gBS->OpenProtocol ( + Private->Handle, + &gEfiPciIoProtocolGuid, + (VOID **) &Private->PciIo, + This->DriverBindingHandle, + Private->Handle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + goto Error; + } + + Status = Private->PciIo->Attributes ( + Private->PciIo, + EfiPciIoAttributeOperationEnable, + EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO, + NULL + ); + if (EFI_ERROR (Status)) { + goto Error; + } + + // + // Start the UGA Draw software stack. + // + Status = CirrusLogic5430UgaDrawConstructor (Private); + if (EFI_ERROR (Status)) { + goto Error; + } + + // + // Publish the UGA Draw interface to the world + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &Private->Handle, + &gEfiUgaDrawProtocolGuid, + &Private->UgaDraw, + NULL + ); + +Error: + if (EFI_ERROR (Status)) { + if (Private) { + if (Private->PciIo) { + Private->PciIo->Attributes ( + Private->PciIo, + EfiPciIoAttributeOperationDisable, + EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO, + NULL + ); + } + } + + // + // Close the PCI I/O Protocol + // + gBS->CloseProtocol ( + Private->Handle, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Private->Handle + ); + if (Private) { + gBS->FreePool (Private); + } + } + + return Status; +} + +EFI_STATUS +EFIAPI +CirrusLogic5430ControllerDriverStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Controller - add argument and description to function comment +// TODO: NumberOfChildren - add argument and description to function comment +// TODO: ChildHandleBuffer - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_UGA_DRAW_PROTOCOL *UgaDraw; + EFI_STATUS Status; + CIRRUS_LOGIC_5430_PRIVATE_DATA *Private; + + Status = gBS->OpenProtocol ( + Controller, + &gEfiUgaDrawProtocolGuid, + (VOID **) &UgaDraw, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + // + // If the UGA Draw interface does not exist the driver is not started + // + return Status; + } + + // + // Get our private context information + // + Private = CIRRUS_LOGIC_5430_PRIVATE_DATA_FROM_UGA_DRAW_THIS (UgaDraw); + + // + // Remove the UGA Draw interface from the system + // + Status = gBS->UninstallMultipleProtocolInterfaces ( + Private->Handle, + &gEfiUgaDrawProtocolGuid, + &Private->UgaDraw, + NULL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Shutdown the hardware + // + CirrusLogic5430UgaDrawDestructor (Private); + + Private->PciIo->Attributes ( + Private->PciIo, + EfiPciIoAttributeOperationDisable, + EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO, + NULL + ); + + // + // Close the PCI I/O Protocol + // + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + // + // Free our instance data + // + gBS->FreePool (Private); + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Bus/Pci/CirrusLogic/Dxe/CirrusLogic5430.h b/EdkModulePkg/Bus/Pci/CirrusLogic/Dxe/CirrusLogic5430.h new file mode 100644 index 0000000000..5eba0190f2 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/CirrusLogic/Dxe/CirrusLogic5430.h @@ -0,0 +1,254 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + CirrusLogic5430.h + +Abstract: + + Cirrus Logic 5430 Controller Driver + +Revision History + +--*/ + +// +// Cirrus Logic 5430 Controller Driver +// + +#ifndef _CIRRUS_LOGIC_5430_H_ +#define _CIRRUS_LOGIC_5430_H_ + + +#include +// +// Cirrus Logic 5430 PCI Configuration Header values +// +#define CIRRUS_LOGIC_VENDOR_ID 0x1013 +#define CIRRUS_LOGIC_5430_DEVICE_ID 0x00a8 +#define CIRRUS_LOGIC_5430_ALTERNATE_DEVICE_ID 0x00a0 +#define CIRRUS_LOGIC_5446_DEVICE_ID 0x00b8 + +// +// Cirrus Logic Graphical Mode Data +// +#define CIRRUS_LOGIC_5430_UGA_DRAW_MODE_COUNT 3 + +typedef struct { + UINT32 HorizontalResolution; + UINT32 VerticalResolution; + UINT32 ColorDepth; + UINT32 RefreshRate; +} CIRRUS_LOGIC_5430_UGA_DRAW_MODE_DATA; + +// +// Cirrus Logic 5440 Private Data Structure +// +#define CIRRUS_LOGIC_5430_PRIVATE_DATA_SIGNATURE EFI_SIGNATURE_32 ('C', 'L', '5', '4') + +typedef struct { + UINT64 Signature; + EFI_HANDLE Handle; + EFI_PCI_IO_PROTOCOL *PciIo; + EFI_UGA_DRAW_PROTOCOL UgaDraw; + + // + // UGA Draw Private Data + // + BOOLEAN HardwareNeedsStarting; + UINTN CurrentMode; + UINTN MaxMode; + CIRRUS_LOGIC_5430_UGA_DRAW_MODE_DATA ModeData[CIRRUS_LOGIC_5430_UGA_DRAW_MODE_COUNT]; + UINT8 *LineBuffer; +} CIRRUS_LOGIC_5430_PRIVATE_DATA; + +#define CIRRUS_LOGIC_5430_PRIVATE_DATA_FROM_UGA_DRAW_THIS(a) \ + CR(a, CIRRUS_LOGIC_5430_PRIVATE_DATA, UgaDraw, CIRRUS_LOGIC_5430_PRIVATE_DATA_SIGNATURE) + +// +// Global Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gCirrusLogic5430DriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gCirrusLogic5430ComponentName; + +// +// Io Registers defined by VGA +// +#define CRTC_ADDRESS_REGISTER 0x3d4 +#define CRTC_DATA_REGISTER 0x3d5 +#define SEQ_ADDRESS_REGISTER 0x3c4 +#define SEQ_DATA_REGISTER 0x3c5 +#define GRAPH_ADDRESS_REGISTER 0x3ce +#define GRAPH_DATA_REGISTER 0x3cf +#define ATT_ADDRESS_REGISTER 0x3c0 +#define MISC_OUTPUT_REGISTER 0x3c2 +#define INPUT_STATUS_1_REGISTER 0x3da +#define DAC_PIXEL_MASK_REGISTER 0x3c6 +#define PALETTE_INDEX_REGISTER 0x3c8 +#define PALETTE_DATA_REGISTER 0x3c9 + +// +// UGA Draw Hardware abstraction internal worker functions +// +EFI_STATUS +CirrusLogic5430UgaDrawConstructor ( + CIRRUS_LOGIC_5430_PRIVATE_DATA *Private + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +CirrusLogic5430UgaDrawDestructor ( + CIRRUS_LOGIC_5430_PRIVATE_DATA *Private + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +// +// EFI 1.1 driver model prototypes for Cirrus Logic 5430 UGA Draw +// +EFI_STATUS +EFIAPI +CirrusLogic5430DriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ImageHandle - TODO: add argument description + SystemTable - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +// +// EFI_DRIVER_BINDING_PROTOCOL Protocol Interface +// +EFI_STATUS +EFIAPI +CirrusLogic5430ControllerDriverSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Controller - TODO: add argument description + RemainingDevicePath - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +CirrusLogic5430ControllerDriverStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Controller - TODO: add argument description + RemainingDevicePath - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +CirrusLogic5430ControllerDriverStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Controller - TODO: add argument description + NumberOfChildren - TODO: add argument description + ChildHandleBuffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/EdkModulePkg/Bus/Pci/CirrusLogic/Dxe/CirrusLogic5430.mbd b/EdkModulePkg/Bus/Pci/CirrusLogic/Dxe/CirrusLogic5430.mbd new file mode 100644 index 0000000000..16bc2891b6 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/CirrusLogic/Dxe/CirrusLogic5430.mbd @@ -0,0 +1,42 @@ + + + + + CirrusLogic5430UgaDraw + 555F76EA-785F-40d7-9174-153C43636C68 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:18 + + + UefiBootServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + EdkDxePrintLib + BaseLib + DxeMemoryAllocationLib + + diff --git a/EdkModulePkg/Bus/Pci/CirrusLogic/Dxe/CirrusLogic5430.msa b/EdkModulePkg/Bus/Pci/CirrusLogic/Dxe/CirrusLogic5430.msa new file mode 100644 index 0000000000..bbc9c2ee24 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/CirrusLogic/Dxe/CirrusLogic5430.msa @@ -0,0 +1,66 @@ + + + + + CirrusLogic5430UgaDraw + UEFI_DRIVER + BS_DRIVER + 555F76EA-785F-40d7-9174-153C43636C68 + 0 + Component description file for CirrusLogic5430 module + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:18 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + BaseLib + UefiLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + + + CirrusLogic5430.h + CirrusLogic5430.c + CirrusLogic5430UgaDraw.c + ComponentName.c + + + MdePkg + + + PciIo + UgaDraw + + + + + + + gCirrusLogic5430DriverBinding + gCirrusLogic5430ComponentName + + + diff --git a/EdkModulePkg/Bus/Pci/CirrusLogic/Dxe/CirrusLogic5430UgaDraw.c b/EdkModulePkg/Bus/Pci/CirrusLogic/Dxe/CirrusLogic5430UgaDraw.c new file mode 100644 index 0000000000..c33918b675 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/CirrusLogic/Dxe/CirrusLogic5430UgaDraw.c @@ -0,0 +1,1036 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + CirrusLogic5430UgaDraw.c + +Abstract: + + This file produces the graphics abstration of UGA Draw. It is called by + CirrusLogic5430.c file which deals with the EFI 1.1 driver model. + This file just does graphics. + +--*/ + +#include "CirrusLogic5430.h" + +// +// Video Mode structure +// +typedef struct { + UINT32 Width; + UINT32 Height; + UINT32 ColorDepth; + UINT32 RefreshRate; + UINT8 *CrtcSettings; + UINT16 *SeqSettings; + UINT8 MiscSetting; +} CIRRUS_LOGIC_5430_VIDEO_MODES; + +// +// Generic Attribute Controller Register Settings +// +static UINT8 AttributeController[21] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00 +}; + +// +// Generic Graphics Controller Register Settings +// +static UINT8 GraphicsController[9] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 0xFF +}; + +// +// 640 x 480 x 256 color @ 60 Hertz +// +static UINT8 Crtc_640_480_256_60[28] = { + 0x5d, 0x4f, 0x50, 0x82, 0x53, 0x9f, 0x00, 0x3e, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe1, 0x83, 0xdf, 0x50, 0x00, 0xe7, 0x04, 0xe3, + 0xff, 0x00, 0x00, 0x22 +}; + +static UINT16 Seq_640_480_256_60[15] = { + 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1107, 0x0008, 0x4a0b, + 0x5b0c, 0x450d, 0x7e0e, 0x2b1b, 0x2f1c, 0x301d, 0x331e +}; + +// +// 800 x 600 x 256 color @ 60 Hertz +// +static UINT8 Crtc_800_600_256_60[28] = { + 0x7F, 0x63, 0x64, 0x80, 0x6B, 0x1B, 0x72, 0xF0, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x58, 0x8C, 0x57, 0x64, 0x00, 0x5F, 0x91, 0xE3, + 0xFF, 0x00, 0x00, 0x22 +}; + +static UINT16 Seq_800_600_256_60[15] = { + 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1107, 0x0008, 0x4a0b, + 0x5b0c, 0x450d, 0x510e, 0x2b1b, 0x2f1c, 0x301d, 0x3a1e +}; + +// +// 1024 x 768 x 256 color @ 60 Hertz +// +static UINT8 Crtc_1024_768_256_60[28] = { + 0xA3, 0x7F, 0x80, 0x86, 0x85, 0x96, 0x24, 0xFD, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x88, 0xFF, 0x80, 0x00, 0x00, 0x24, 0xE3, + 0xFF, 0x4A, 0x00, 0x22 +}; + +static UINT16 Seq_1024_768_256_60[15] = { + 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1107, 0x0008, 0x4a0b, + 0x5b0c, 0x450d, 0x760e, 0x2b1b, 0x2f1c, 0x301d, 0x341e +}; + +// +// Table of supported video modes +// +static CIRRUS_LOGIC_5430_VIDEO_MODES CirrusLogic5430VideoModes[] = { + { 640, 480, 8, 60, Crtc_640_480_256_60, Seq_640_480_256_60, 0xe3 }, + { 800, 600, 8, 60, Crtc_800_600_256_60, Seq_800_600_256_60, 0xef }, + { 1024, 768, 8, 60, Crtc_1024_768_256_60, Seq_1024_768_256_60, 0xef } +}; + +// +// Local Function Prototypes +// +VOID +InitializeGraphicsMode ( + CIRRUS_LOGIC_5430_PRIVATE_DATA *Private, + CIRRUS_LOGIC_5430_VIDEO_MODES *ModeData + ); + +VOID +SetPaletteColor ( + CIRRUS_LOGIC_5430_PRIVATE_DATA *Private, + UINTN Index, + UINT8 Red, + UINT8 Green, + UINT8 Blue + ); + +VOID +SetDefaultPalette ( + CIRRUS_LOGIC_5430_PRIVATE_DATA *Private + ); + +STATIC +VOID +ClearScreen ( + CIRRUS_LOGIC_5430_PRIVATE_DATA *Private + ); + +VOID +DrawLogo ( + CIRRUS_LOGIC_5430_PRIVATE_DATA *Private + ); + +VOID +outb ( + CIRRUS_LOGIC_5430_PRIVATE_DATA *Private, + UINTN Address, + UINT8 Data + ); + +VOID +outw ( + CIRRUS_LOGIC_5430_PRIVATE_DATA *Private, + UINTN Address, + UINT16 Data + ); + +UINT8 +inb ( + CIRRUS_LOGIC_5430_PRIVATE_DATA *Private, + UINTN Address + ); + +UINT16 +inw ( + CIRRUS_LOGIC_5430_PRIVATE_DATA *Private, + UINTN Address + ); + +// +// UGA Draw Protocol Member Functions +// +EFI_STATUS +EFIAPI +CirrusLogic5430UgaDrawGetMode ( + IN EFI_UGA_DRAW_PROTOCOL *This, + OUT UINT32 *HorizontalResolution, + OUT UINT32 *VerticalResolution, + OUT UINT32 *ColorDepth, + OUT UINT32 *RefreshRate + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + HorizontalResolution - TODO: add argument description + VerticalResolution - TODO: add argument description + ColorDepth - TODO: add argument description + RefreshRate - TODO: add argument description + +Returns: + + EFI_NOT_STARTED - TODO: Add description for return value + EFI_INVALID_PARAMETER - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + CIRRUS_LOGIC_5430_PRIVATE_DATA *Private; + + Private = CIRRUS_LOGIC_5430_PRIVATE_DATA_FROM_UGA_DRAW_THIS (This); + + if (Private->HardwareNeedsStarting) { + return EFI_NOT_STARTED; + } + + if ((HorizontalResolution == NULL) || + (VerticalResolution == NULL) || + (ColorDepth == NULL) || + (RefreshRate == NULL)) { + return EFI_INVALID_PARAMETER; + } + + *HorizontalResolution = Private->ModeData[Private->CurrentMode].HorizontalResolution; + *VerticalResolution = Private->ModeData[Private->CurrentMode].VerticalResolution; + *ColorDepth = Private->ModeData[Private->CurrentMode].ColorDepth; + *RefreshRate = Private->ModeData[Private->CurrentMode].RefreshRate; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +CirrusLogic5430UgaDrawSetMode ( + IN EFI_UGA_DRAW_PROTOCOL *This, + IN UINT32 HorizontalResolution, + IN UINT32 VerticalResolution, + IN UINT32 ColorDepth, + IN UINT32 RefreshRate + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + HorizontalResolution - TODO: add argument description + VerticalResolution - TODO: add argument description + ColorDepth - TODO: add argument description + RefreshRate - TODO: add argument description + +Returns: + + EFI_OUT_OF_RESOURCES - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + EFI_NOT_FOUND - TODO: Add description for return value + +--*/ +{ + CIRRUS_LOGIC_5430_PRIVATE_DATA *Private; + UINTN Index; + + Private = CIRRUS_LOGIC_5430_PRIVATE_DATA_FROM_UGA_DRAW_THIS (This); + + for (Index = 0; Index < Private->MaxMode; Index++) { + + if (HorizontalResolution != Private->ModeData[Index].HorizontalResolution) { + continue; + } + + if (VerticalResolution != Private->ModeData[Index].VerticalResolution) { + continue; + } + + if (ColorDepth != Private->ModeData[Index].ColorDepth) { + continue; + } + + if (RefreshRate != Private->ModeData[Index].RefreshRate) { + continue; + } + + if (Private->LineBuffer) { + gBS->FreePool (Private->LineBuffer); + } + + Private->LineBuffer = NULL; + Private->LineBuffer = AllocatePool (HorizontalResolution); + if (Private->LineBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + InitializeGraphicsMode (Private, &CirrusLogic5430VideoModes[Index]); + + Private->CurrentMode = Index; + + Private->HardwareNeedsStarting = FALSE; + + return EFI_SUCCESS; + } + + return EFI_NOT_FOUND; +} + +EFI_STATUS +EFIAPI +CirrusLogic5430UgaDrawBlt ( + 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 + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + BltBuffer - TODO: add argument description + BltOperation - TODO: add argument description + SourceX - TODO: add argument description + SourceY - TODO: add argument description + DestinationX - TODO: add argument description + DestinationY - TODO: add argument description + Width - TODO: add argument description + Height - TODO: add argument description + Delta - TODO: add argument description + +Returns: + + EFI_INVALID_PARAMETER - TODO: Add description for return value + EFI_INVALID_PARAMETER - TODO: Add description for return value + EFI_INVALID_PARAMETER - TODO: Add description for return value + EFI_INVALID_PARAMETER - TODO: Add description for return value + EFI_INVALID_PARAMETER - TODO: Add description for return value + EFI_INVALID_PARAMETER - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + CIRRUS_LOGIC_5430_PRIVATE_DATA *Private; + EFI_TPL OriginalTPL; + UINTN DstY; + UINTN SrcY; + EFI_UGA_PIXEL *Blt; + UINTN X; + UINT8 Pixel; + UINT32 WidePixel; + UINTN ScreenWidth; + UINTN Offset; + UINTN SourceOffset; + + Private = CIRRUS_LOGIC_5430_PRIVATE_DATA_FROM_UGA_DRAW_THIS (This); + + if ((BltOperation < 0) || (BltOperation >= EfiUgaBltMax)) { + return EFI_INVALID_PARAMETER; + } + + if (Width == 0 || Height == 0) { + return EFI_INVALID_PARAMETER; + } + + // + // If Delta is zero, then the entire BltBuffer is being used, so Delta + // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size, + // the number of bytes in each row can be computed. + // + if (Delta == 0) { + Delta = Width * sizeof (EFI_UGA_PIXEL); + } + + // + // We need to fill the Virtual Screen buffer with the blt data. + // The virtual screen is upside down, as the first row is the bootom row of + // the image. + // + + // + // Make sure the SourceX, SourceY, DestinationX, DestinationY, Width, and Height parameters + // are valid for the operation and the current screen geometry. + // + if (BltOperation == EfiUgaVideoToBltBuffer) { + // + // Video to BltBuffer: Source is Video, destination is BltBuffer + // + if (SourceY + Height > Private->ModeData[Private->CurrentMode].VerticalResolution) { + return EFI_INVALID_PARAMETER; + } + + if (SourceX + Width > Private->ModeData[Private->CurrentMode].HorizontalResolution) { + return EFI_INVALID_PARAMETER; + } + } else { + // + // BltBuffer to Video: Source is BltBuffer, destination is Video + // + if (DestinationY + Height > Private->ModeData[Private->CurrentMode].VerticalResolution) { + return EFI_INVALID_PARAMETER; + } + + if (DestinationX + Width > Private->ModeData[Private->CurrentMode].HorizontalResolution) { + return EFI_INVALID_PARAMETER; + } + } + // + // We have to raise to TPL Notify, so we make an atomic write the frame buffer. + // We would not want a timer based event (Cursor, ...) to come in while we are + // doing this operation. + // + OriginalTPL = gBS->RaiseTPL (EFI_TPL_NOTIFY); + + switch (BltOperation) { + case EfiUgaVideoToBltBuffer: + // + // Video to BltBuffer: Source is Video, destination is BltBuffer + // + for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY); SrcY++, DstY++) { + + Offset = (SrcY * Private->ModeData[Private->CurrentMode].HorizontalResolution) + SourceX; + if (((Offset & 0x03) == 0) && ((Width & 0x03) == 0)) { + Private->PciIo->Mem.Read ( + Private->PciIo, + EfiPciIoWidthUint32, + 0, + Offset, + Width >> 2, + Private->LineBuffer + ); + } else { + Private->PciIo->Mem.Read ( + Private->PciIo, + EfiPciIoWidthUint8, + 0, + Offset, + Width, + Private->LineBuffer + ); + } + + for (X = 0; X < Width; X++) { + Blt = (EFI_UGA_PIXEL *) ((UINT8 *) BltBuffer + (DstY * Delta) + (DestinationX + X) * sizeof (EFI_UGA_PIXEL)); + + Blt->Red = (UINT8) (Private->LineBuffer[X] & 0xe0); + Blt->Green = (UINT8) ((Private->LineBuffer[X] & 0x1c) << 3); + Blt->Blue = (UINT8) ((Private->LineBuffer[X] & 0x03) << 6); + } + } + break; + + case EfiUgaVideoToVideo: + // + // Perform hardware acceleration for Video to Video operations + // + ScreenWidth = Private->ModeData[Private->CurrentMode].HorizontalResolution; + SourceOffset = (SourceY * Private->ModeData[Private->CurrentMode].HorizontalResolution) + (SourceX); + Offset = (DestinationY * Private->ModeData[Private->CurrentMode].HorizontalResolution) + (DestinationX); + + outw (Private, GRAPH_ADDRESS_REGISTER, 0x0000); + outw (Private, GRAPH_ADDRESS_REGISTER, 0x0010); + outw (Private, GRAPH_ADDRESS_REGISTER, 0x0012); + outw (Private, GRAPH_ADDRESS_REGISTER, 0x0014); + + outw (Private, GRAPH_ADDRESS_REGISTER, 0x0001); + outw (Private, GRAPH_ADDRESS_REGISTER, 0x0011); + outw (Private, GRAPH_ADDRESS_REGISTER, 0x0013); + outw (Private, GRAPH_ADDRESS_REGISTER, 0x0015); + + outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) (((Width << 8) & 0xff00) | 0x20)); + outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((Width & 0xff00) | 0x21)); + outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) (((Height << 8) & 0xff00) | 0x22)); + outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((Height & 0xff00) | 0x23)); + outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) (((ScreenWidth << 8) & 0xff00) | 0x24)); + outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((ScreenWidth & 0xff00) | 0x25)); + outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) (((ScreenWidth << 8) & 0xff00) | 0x26)); + outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((ScreenWidth & 0xff00) | 0x27)); + outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((Offset) << 8) & 0xff00) | 0x28)); + outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((Offset) >> 0) & 0xff00) | 0x29)); + outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((Offset) >> 8) & 0xff00) | 0x2a)); + outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((SourceOffset) << 8) & 0xff00) | 0x2c)); + outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((SourceOffset) >> 0) & 0xff00) | 0x2d)); + outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((SourceOffset) >> 8) & 0xff00) | 0x2e)); + outw (Private, GRAPH_ADDRESS_REGISTER, 0x002f); + outw (Private, GRAPH_ADDRESS_REGISTER, 0x0030); + outw (Private, GRAPH_ADDRESS_REGISTER, 0x0d32); + outw (Private, GRAPH_ADDRESS_REGISTER, 0x0033); + outw (Private, GRAPH_ADDRESS_REGISTER, 0x0034); + outw (Private, GRAPH_ADDRESS_REGISTER, 0x0035); + + outw (Private, GRAPH_ADDRESS_REGISTER, 0x0231); + + outb (Private, GRAPH_ADDRESS_REGISTER, 0x31); + while ((inb (Private, GRAPH_DATA_REGISTER) & 0x01) == 0x01) + ; + break; + + case EfiUgaVideoFill: + Blt = BltBuffer; + Pixel = (UINT8) ((Blt->Red & 0xe0) | ((Blt->Green >> 3) & 0x1c) | ((Blt->Blue >> 6) & 0x03)); + WidePixel = (Pixel << 8) | Pixel; + WidePixel = (WidePixel << 16) | WidePixel; + + if (DestinationX == 0 && Width == Private->ModeData[Private->CurrentMode].HorizontalResolution) { + Offset = DestinationY * Private->ModeData[Private->CurrentMode].HorizontalResolution; + if (((Offset & 0x03) == 0) && (((Width * Height) & 0x03) == 0)) { + Private->PciIo->Mem.Write ( + Private->PciIo, + EfiPciIoWidthFillUint32, + 0, + Offset, + (Width * Height) >> 2, + &WidePixel + ); + } else { + Private->PciIo->Mem.Write ( + Private->PciIo, + EfiPciIoWidthFillUint8, + 0, + Offset, + Width * Height, + &Pixel + ); + } + } else { + for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) { + Offset = (DstY * Private->ModeData[Private->CurrentMode].HorizontalResolution) + DestinationX; + if (((Offset & 0x03) == 0) && ((Width & 0x03) == 0)) { + Private->PciIo->Mem.Write ( + Private->PciIo, + EfiPciIoWidthFillUint32, + 0, + Offset, + Width >> 2, + &WidePixel + ); + } else { + Private->PciIo->Mem.Write ( + Private->PciIo, + EfiPciIoWidthFillUint8, + 0, + Offset, + Width, + &Pixel + ); + } + } + } + break; + + case EfiUgaBltBufferToVideo: + for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) { + + for (X = 0; X < Width; X++) { + Blt = (EFI_UGA_PIXEL *) ((UINT8 *) BltBuffer + (SrcY * Delta) + (SourceX + X) * sizeof (EFI_UGA_PIXEL)); + Private->LineBuffer[X] = (UINT8) ((Blt->Red & 0xe0) | ((Blt->Green >> 3) & 0x1c) | ((Blt->Blue >> 6) & 0x03)); + } + + Offset = (DstY * Private->ModeData[Private->CurrentMode].HorizontalResolution) + DestinationX; + + if (((Offset & 0x03) == 0) && ((Width & 0x03) == 0)) { + Private->PciIo->Mem.Write ( + Private->PciIo, + EfiPciIoWidthUint32, + 0, + Offset, + Width >> 2, + Private->LineBuffer + ); + } else { + Private->PciIo->Mem.Write ( + Private->PciIo, + EfiPciIoWidthUint8, + 0, + Offset, + Width, + Private->LineBuffer + ); + } + } + break; + + default: + break; + } + + gBS->RestoreTPL (OriginalTPL); + + return EFI_SUCCESS; +} + +// +// Construction and Destruction functions +// + +EFI_STATUS +CirrusLogic5430UgaDrawConstructor ( + CIRRUS_LOGIC_5430_PRIVATE_DATA *Private + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: Private - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_UGA_DRAW_PROTOCOL *UgaDraw; + UINTN Index; + + // + // Fill in Private->UgaDraw protocol + // + UgaDraw = &Private->UgaDraw; + + UgaDraw->GetMode = CirrusLogic5430UgaDrawGetMode; + UgaDraw->SetMode = CirrusLogic5430UgaDrawSetMode; + UgaDraw->Blt = CirrusLogic5430UgaDrawBlt; + + // + // Initialize the private data + // + Private->MaxMode = CIRRUS_LOGIC_5430_UGA_DRAW_MODE_COUNT; + Private->CurrentMode = 0; + for (Index = 0; Index < Private->MaxMode; Index++) { + Private->ModeData[Index].HorizontalResolution = CirrusLogic5430VideoModes[Index].Width; + Private->ModeData[Index].VerticalResolution = CirrusLogic5430VideoModes[Index].Height; + Private->ModeData[Index].ColorDepth = 32; + Private->ModeData[Index].RefreshRate = CirrusLogic5430VideoModes[Index].RefreshRate; + } + + Private->HardwareNeedsStarting = TRUE; + Private->LineBuffer = NULL; + + // + // Initialize the hardware + // + UgaDraw->SetMode ( + UgaDraw, + Private->ModeData[Private->CurrentMode].HorizontalResolution, + Private->ModeData[Private->CurrentMode].VerticalResolution, + Private->ModeData[Private->CurrentMode].ColorDepth, + Private->ModeData[Private->CurrentMode].RefreshRate + ); + DrawLogo (Private); + + return EFI_SUCCESS; +} + +EFI_STATUS +CirrusLogic5430UgaDrawDestructor ( + CIRRUS_LOGIC_5430_PRIVATE_DATA *Private + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: Private - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + return EFI_SUCCESS; +} + +VOID +outb ( + CIRRUS_LOGIC_5430_PRIVATE_DATA *Private, + UINTN Address, + UINT8 Data + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + Address - TODO: add argument description + Data - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + Private->PciIo->Io.Write ( + Private->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + Address, + 1, + &Data + ); +} + +VOID +outw ( + CIRRUS_LOGIC_5430_PRIVATE_DATA *Private, + UINTN Address, + UINT16 Data + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + Address - TODO: add argument description + Data - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + Private->PciIo->Io.Write ( + Private->PciIo, + EfiPciIoWidthUint16, + EFI_PCI_IO_PASS_THROUGH_BAR, + Address, + 1, + &Data + ); +} + +UINT8 +inb ( + CIRRUS_LOGIC_5430_PRIVATE_DATA *Private, + UINTN Address + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + Address - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + UINT8 Data; + + Private->PciIo->Io.Read ( + Private->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + Address, + 1, + &Data + ); + return Data; +} + +UINT16 +inw ( + CIRRUS_LOGIC_5430_PRIVATE_DATA *Private, + UINTN Address + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + Address - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + UINT16 Data; + + Private->PciIo->Io.Read ( + Private->PciIo, + EfiPciIoWidthUint16, + EFI_PCI_IO_PASS_THROUGH_BAR, + Address, + 1, + &Data + ); + return Data; +} + +VOID +SetPaletteColor ( + CIRRUS_LOGIC_5430_PRIVATE_DATA *Private, + UINTN Index, + UINT8 Red, + UINT8 Green, + UINT8 Blue + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + Index - TODO: add argument description + Red - TODO: add argument description + Green - TODO: add argument description + Blue - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + outb (Private, PALETTE_INDEX_REGISTER, (UINT8) Index); + outb (Private, PALETTE_DATA_REGISTER, (UINT8) (Red >> 2)); + outb (Private, PALETTE_DATA_REGISTER, (UINT8) (Green >> 2)); + outb (Private, PALETTE_DATA_REGISTER, (UINT8) (Blue >> 2)); +} + +VOID +SetDefaultPalette ( + CIRRUS_LOGIC_5430_PRIVATE_DATA *Private + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + UINTN Index; + UINTN RedIndex; + UINTN GreenIndex; + UINTN BlueIndex; + + Index = 0; + for (RedIndex = 0; RedIndex < 8; RedIndex++) { + for (GreenIndex = 0; GreenIndex < 8; GreenIndex++) { + for (BlueIndex = 0; BlueIndex < 4; BlueIndex++) { + SetPaletteColor (Private, Index, (UINT8) (RedIndex << 5), (UINT8) (GreenIndex << 5), (UINT8) (BlueIndex << 6)); + Index++; + } + } + } +} + +STATIC +VOID +ClearScreen ( + CIRRUS_LOGIC_5430_PRIVATE_DATA *Private + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + UINT32 Color; + + Color = 0; + Private->PciIo->Mem.Write ( + Private->PciIo, + EfiPciIoWidthFillUint32, + 0, + 0, + 0x100000 >> 2, + &Color + ); +} + +VOID +DrawLogo ( + CIRRUS_LOGIC_5430_PRIVATE_DATA *Private + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + UINTN Offset; + UINTN X; + UINTN Y; + UINTN ScreenWidth; + UINTN ScreenHeight; + UINT8 Color; + + ScreenWidth = Private->ModeData[Private->CurrentMode].HorizontalResolution; + ScreenHeight = Private->ModeData[Private->CurrentMode].VerticalResolution; + + Offset = 0; + for (Y = 0; Y < ScreenHeight; Y++) { + for (X = 0; X < ScreenWidth; X++) { + Color = (UINT8) (256 * (X + Y) / (ScreenWidth + ScreenHeight)); + Private->LineBuffer[X] = Color; + } + + Private->PciIo->Mem.Write ( + Private->PciIo, + EfiPciIoWidthUint32, + 0, + Offset + (Y * ScreenWidth), + ScreenWidth >> 2, + Private->LineBuffer + ); + } +} + +VOID +InitializeGraphicsMode ( + CIRRUS_LOGIC_5430_PRIVATE_DATA *Private, + CIRRUS_LOGIC_5430_VIDEO_MODES *ModeData + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + ModeData - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + UINT8 Byte; + UINTN Index; + + outw (Private, SEQ_ADDRESS_REGISTER, 0x1206); + outw (Private, SEQ_ADDRESS_REGISTER, 0x0012); + + for (Index = 0; Index < 15; Index++) { + outw (Private, SEQ_ADDRESS_REGISTER, ModeData->SeqSettings[Index]); + } + + outb (Private, SEQ_ADDRESS_REGISTER, 0x0f); + Byte = (UINT8) ((inb (Private, SEQ_DATA_REGISTER) & 0xc7) ^ 0x30); + outb (Private, SEQ_DATA_REGISTER, Byte); + + outb (Private, MISC_OUTPUT_REGISTER, ModeData->MiscSetting); + outw (Private, GRAPH_ADDRESS_REGISTER, 0x0506); + outw (Private, SEQ_ADDRESS_REGISTER, 0x0300); + outw (Private, CRTC_ADDRESS_REGISTER, 0x2011); + + for (Index = 0; Index < 28; Index++) { + outw (Private, CRTC_ADDRESS_REGISTER, (UINT16) ((ModeData->CrtcSettings[Index] << 8) | Index)); + } + + for (Index = 0; Index < 9; Index++) { + outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((GraphicsController[Index] << 8) | Index)); + } + + inb (Private, INPUT_STATUS_1_REGISTER); + + for (Index = 0; Index < 21; Index++) { + outb (Private, ATT_ADDRESS_REGISTER, (UINT8) Index); + outb (Private, ATT_ADDRESS_REGISTER, AttributeController[Index]); + } + + outb (Private, ATT_ADDRESS_REGISTER, 0x20); + + outw (Private, GRAPH_ADDRESS_REGISTER, 0x0009); + outw (Private, GRAPH_ADDRESS_REGISTER, 0x000a); + outw (Private, GRAPH_ADDRESS_REGISTER, 0x000b); + outb (Private, DAC_PIXEL_MASK_REGISTER, 0xff); + + SetDefaultPalette (Private); + ClearScreen (Private); +} diff --git a/EdkModulePkg/Bus/Pci/CirrusLogic/Dxe/ComponentName.c b/EdkModulePkg/Bus/Pci/CirrusLogic/Dxe/ComponentName.c new file mode 100644 index 0000000000..5c10b6d7b4 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/CirrusLogic/Dxe/ComponentName.c @@ -0,0 +1,222 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ComponentName.c + +Abstract: + +--*/ + +#include "CirrusLogic5430.h" + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +CirrusLogic5430ComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +EFI_STATUS +EFIAPI +CirrusLogic5430ComponentNameGetControllerName ( + 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 +// +EFI_COMPONENT_NAME_PROTOCOL gCirrusLogic5430ComponentName = { + CirrusLogic5430ComponentNameGetDriverName, + CirrusLogic5430ComponentNameGetControllerName, + "eng" +}; + +static EFI_UNICODE_STRING_TABLE mCirrusLogic5430DriverNameTable[] = { + { "eng", (CHAR16 *) L"Cirrus Logic 5430 UGA Driver" }, + { NULL , NULL } +}; + +static EFI_UNICODE_STRING_TABLE mCirrusLogic5430ControllerNameTable[] = { + { "eng", (CHAR16 *) L"Cirrus Logic 5430 PCI Adapter" }, + { NULL , NULL } +}; + +EFI_STATUS +EFIAPI +CirrusLogic5430ComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gCirrusLogic5430ComponentName.SupportedLanguages, + mCirrusLogic5430DriverNameTable, + DriverName + ); +} + +EFI_STATUS +EFIAPI +CirrusLogic5430ComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + 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. + 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. + + Returns: + 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. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + EFI_UGA_DRAW_PROTOCOL *UgaDraw; + EFI_STATUS Status; + CIRRUS_LOGIC_5430_PRIVATE_DATA *Private; + EFI_PCI_IO_PROTOCOL *PciIoProtocol; + + // + // This is a device driver, so ChildHandle must be NULL. + // + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + + // + // Check Controller's handle + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIoProtocol, + gCirrusLogic5430DriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (!EFI_ERROR (Status)) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiPciIoProtocolGuid, + gCirrusLogic5430DriverBinding.DriverBindingHandle, + ControllerHandle + ); + + return EFI_UNSUPPORTED; + } + + if (Status != EFI_ALREADY_STARTED) { + return EFI_UNSUPPORTED; + } + + // + // Get the UGA Draw Protocol on Controller + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUgaDrawProtocolGuid, + (VOID **) &UgaDraw, + gCirrusLogic5430DriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get the Cirrus Logic 5430's Device structure + // + Private = CIRRUS_LOGIC_5430_PRIVATE_DATA_FROM_UGA_DRAW_THIS (UgaDraw); + + return LookupUnicodeString ( + Language, + gCirrusLogic5430ComponentName.SupportedLanguages, + mCirrusLogic5430ControllerNameTable, + ControllerName + ); +} diff --git a/EdkModulePkg/Bus/Pci/CirrusLogic/Dxe/build.xml b/EdkModulePkg/Bus/Pci/CirrusLogic/Dxe/build.xml new file mode 100644 index 0000000000..c8e44b1e6c --- /dev/null +++ b/EdkModulePkg/Bus/Pci/CirrusLogic/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ComponentName.c b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ComponentName.c new file mode 100644 index 0000000000..8008527dd1 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ComponentName.c @@ -0,0 +1,224 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ComponentName.c + +Abstract: + +--*/ + +#include "IDEBus.h" + +// +// EFI Component Name Protocol +// +EFI_COMPONENT_NAME_PROTOCOL gIDEBusComponentName = { + IDEBusComponentNameGetDriverName, + IDEBusComponentNameGetControllerName, + "eng" +}; + +STATIC EFI_UNICODE_STRING_TABLE mIDEBusDriverNameTable[] = { + { "eng", (CHAR16 *) L"PCI IDE/ATAPI Bus Driver" }, + { NULL , NULL } +}; + +STATIC EFI_UNICODE_STRING_TABLE mIDEBusControllerNameTable[] = { + { "eng", (CHAR16 *) L"PCI IDE/ATAPI Controller" }, + { NULL , NULL } +}; + +EFI_STATUS +EFIAPI +IDEBusComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gIDEBusComponentName.SupportedLanguages, + mIDEBusDriverNameTable, + DriverName + ); +} + +EFI_STATUS +EFIAPI +IDEBusComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + 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. + 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. + + Returns: + 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. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + EFI_STATUS Status; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + IDE_BLK_IO_DEV *IdeBlkIoDevice; + + // + // Get the controller context + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiCallerIdGuid, + NULL, + gIDEBusDriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (ChildHandle == NULL) { + return LookupUnicodeString ( + Language, + gIDEBusComponentName.SupportedLanguages, + mIDEBusControllerNameTable, + ControllerName + ); + } + + // + // Get the child context + // + Status = gBS->OpenProtocol ( + ChildHandle, + &gEfiBlockIoProtocolGuid, + (VOID **) &BlockIo, + gIDEBusDriverBinding.DriverBindingHandle, + ChildHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (BlockIo); + + return LookupUnicodeString ( + Language, + gIDEBusComponentName.SupportedLanguages, + IdeBlkIoDevice->ControllerNameTable, + ControllerName + ); +} + +VOID +AddName ( + IN IDE_BLK_IO_DEV *IdeBlkIoDevicePtr + ) +/*++ + + Routine Description: + Add the component name for the IDE/ATAPI device + + Arguments: + IdeBlkIoDevicePtr - A pointer to the IDE_BLK_IO_DEV instance. + + Returns: + +--*/ +{ + UINTN StringIndex; + CHAR16 ModelName[41]; + + // + // Add Component Name for the IDE/ATAPI device that was discovered. + // + IdeBlkIoDevicePtr->ControllerNameTable = NULL; + for (StringIndex = 0; StringIndex < 41; StringIndex++) { + ModelName[StringIndex] = IdeBlkIoDevicePtr->ModelName[StringIndex]; + } + + AddUnicodeString ( + "eng", + gIDEBusComponentName.SupportedLanguages, + &IdeBlkIoDevicePtr->ControllerNameTable, + ModelName + ); +} diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ComponentName.h b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ComponentName.h new file mode 100644 index 0000000000..f6c3feb436 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ComponentName.h @@ -0,0 +1,118 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ComponentName.h + +Abstract: + + +Revision History +--*/ + +#ifndef _IDE_BUS_COMPONENT_NAME_H +#define _IDE_BUS_COMPONENT_NAME_H + + +#ifndef EFI_SIZE_REDUCTION_APPLIED + +#define ADD_NAME(x) AddName ((x)); + +extern EFI_COMPONENT_NAME_PROTOCOL gIDEBusComponentName; + +#else + +#define ADD_NAME(x) + +#endif + + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +IDEBusComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Language - TODO: add argument description + DriverName - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +IDEBusComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + ControllerHandle - TODO: add argument description + ChildHandle - TODO: add argument description + Language - TODO: add argument description + ControllerName - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +VOID +AddName ( + IN IDE_BLK_IO_DEV *IdeBlkIoDevicePtr + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeBlkIoDevicePtr - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/DriverConfiguration.c b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/DriverConfiguration.c new file mode 100644 index 0000000000..b8f71fdc8d --- /dev/null +++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/DriverConfiguration.c @@ -0,0 +1,378 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DriverConfiguration.c + +Abstract: + +--*/ + +#include "IDEBus.h" + +CHAR16 *OptionString[4] = { + L"Enable Primary Master (Y/N)? -->", + L"Enable Primary Slave (Y/N)? -->", + L"Enable Secondary Master (Y/N)? -->", + L"Enable Secondary Slave (Y/N)? -->" +}; +// +// EFI Driver Configuration Functions +// +EFI_STATUS +IDEBusDriverConfigurationSetOptions ( + IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED *ActionRequired + ); + +EFI_STATUS +IDEBusDriverConfigurationOptionsValid ( + IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL + ); + +EFI_STATUS +IDEBusDriverConfigurationForceDefaults ( + IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN UINT32 DefaultType, + OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED *ActionRequired + ); + +// +// EFI Driver Configuration Protocol +// +EFI_DRIVER_CONFIGURATION_PROTOCOL gIDEBusDriverConfiguration = { + IDEBusDriverConfigurationSetOptions, + IDEBusDriverConfigurationOptionsValid, + IDEBusDriverConfigurationForceDefaults, + "eng" +}; + +EFI_STATUS +GetResponse ( + VOID + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + None + +Returns: + + EFI_ABORTED - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + EFI_NOT_FOUND - TODO: Add description for return value + +--*/ +{ + EFI_STATUS Status; + EFI_INPUT_KEY Key; + + while (TRUE) { + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + if (!EFI_ERROR (Status)) { + if (Key.ScanCode == SCAN_ESC) { + return EFI_ABORTED; + } + + switch (Key.UnicodeChar) { + + // + // fall through + // + case L'y': + case L'Y': + gST->ConOut->OutputString (gST->ConOut, L"Y\n"); + return EFI_SUCCESS; + + // + // fall through + // + case L'n': + case L'N': + gST->ConOut->OutputString (gST->ConOut, L"N\n"); + return EFI_NOT_FOUND; + } + + } + } +} + +EFI_STATUS +IDEBusDriverConfigurationSetOptions ( + IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED *ActionRequired + ) +/*++ + + Routine Description: + Allows the user to set controller specific options for a controller that a + driver is currently managing. + + Arguments: + This - A pointer to the EFI_DRIVER_CONFIGURATION_ PROTOCOL + instance. + ControllerHandle - The handle of the controller to set options on. + ChildHandle - The handle of the child controller to set options on. + This is an optional parameter that may be NULL. + It will be NULL for device drivers, and for a bus drivers + that wish to set options for the bus controller. + It will not be NULL for a bus driver that wishes to set + options for one of its child controllers. + Language - A pointer to a three character ISO 639-2 language + identifier. This is the language of the user interface + that should be presented to the user, and it must match + one of the languages specified in SupportedLanguages. + The number of languages supported by a driver is up to + the driver writer. + ActionRequired - A pointer to the action that the calling agent is + required to perform when this function returns. + See "Related Definitions" for a list of the actions that + the calling agent is required to perform prior to + accessing ControllerHandle again. + + Returns: + EFI_SUCCESS - The driver specified by This successfully set the + configuration options for the controller specified + by ControllerHandle.. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a + valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ActionRequired is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support + setting configuration options for the controller + specified by ControllerHandle and ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + EFI_DEVICE_ERROR - A device error occurred while attempt to set the + configuration options for the controller specified + by ControllerHandle and ChildHandle. + EFI_OUT_RESOURCES - There are not enough resources available to set the + configuration options for the controller specified + by ControllerHandle and ChildHandle. + +--*/ +{ + EFI_STATUS Status; + UINT8 Value; + UINT8 NewValue; + UINTN DataSize; + UINTN Index; + UINT32 Attributes; + + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + + *ActionRequired = EfiDriverConfigurationActionNone; + + DataSize = sizeof (Value); + Status = gRT->GetVariable ( + L"Configuration", + &gEfiCallerIdGuid, + &Attributes, + &DataSize, + &Value + ); + + gST->ConOut->OutputString (gST->ConOut, L"IDE Bus Driver Configuration\n"); + gST->ConOut->OutputString (gST->ConOut, L"===============================\n"); + + NewValue = 0; + for (Index = 0; Index < 4; Index++) { + gST->ConOut->OutputString (gST->ConOut, OptionString[Index]); + + Status = GetResponse (); + if (Status == EFI_ABORTED) { + return EFI_SUCCESS; + } + + if (!EFI_ERROR (Status)) { + NewValue |= (UINT8) (1 << Index); + } + } + + if (EFI_ERROR (Status) || (NewValue != Value)) { + gRT->SetVariable ( + L"Configuration", + &gEfiCallerIdGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof (NewValue), + &NewValue + ); + + *ActionRequired = EfiDriverConfigurationActionRestartController; + } else { + *ActionRequired = EfiDriverConfigurationActionNone; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +IDEBusDriverConfigurationOptionsValid ( + IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL + ) +/*++ + + Routine Description: + Tests to see if a controller's current configuration options are valid. + + Arguments: + This - A pointer to the EFI_DRIVER_CONFIGURATION_PROTOCOL + instance. + ControllerHandle - The handle of the controller to test if it's current + configuration options are valid. + ChildHandle - The handle of the child controller to test if it's + current + configuration options are valid. This is an optional + parameter that may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers that + wish to test the configuration options for the bus + controller. It will not be NULL for a bus driver that + wishes to test configuration options for one of + its child controllers. + + Returns: + EFI_SUCCESS - The controller specified by ControllerHandle and + ChildHandle that is being managed by the driver + specified by This has a valid set of configuration + options. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + EFI_UNSUPPORTED - The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + EFI_DEVICE_ERROR - The controller specified by ControllerHandle and + ChildHandle that is being managed by the driver + specified by This has an invalid set of + configuration options. + +--*/ +{ + EFI_STATUS Status; + UINT8 Value; + UINTN DataSize; + UINT32 Attributes; + + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + + DataSize = sizeof (Value); + Status = gRT->GetVariable ( + L"Configuration", + &gEfiCallerIdGuid, + &Attributes, + &DataSize, + &Value + ); + if (EFI_ERROR (Status) || Value > 0x0f) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +IDEBusDriverConfigurationForceDefaults ( + IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN UINT32 DefaultType, + OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED *ActionRequired + ) +/*++ + + Routine Description: + Forces a driver to set the default configuration options for a controller. + + Arguments: + This - A pointer to the EFI_DRIVER_CONFIGURATION_ PROTOCOL + instance. + ControllerHandle - The handle of the controller to force default + configuration options on. + ChildHandle - The handle of the child controller to force default + configuration options on This is an optional parameter + that may be NULL. It will be NULL for device drivers. + It will also be NULL for a bus drivers that wish to + force default configuration options for the bus + controller. It will not be NULL for a bus driver that + wishes to force default configuration options for one + of its child controllers. + DefaultType - The type of default configuration options to force on + the controller specified by ControllerHandle and + ChildHandle. See Table 9-1 for legal values. + A DefaultType of 0x00000000 must be supported + by this protocol. + ActionRequired - A pointer to the action that the calling agent + is required to perform when this function returns. + + + Returns: + EFI_SUCCESS - The driver specified by This successfully forced + the default configuration options on the + controller specified by ControllerHandle and + ChildHandle. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a + valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ActionRequired is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support + forcing the default configuration options on + the controller specified by ControllerHandle + and ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support + the configuration type specified by DefaultType. + EFI_DEVICE_ERROR - A device error occurred while attempt to force + the default configuration options on the controller + specified by ControllerHandle and ChildHandle. + EFI_OUT_RESOURCES - There are not enough resources available to force + the default configuration options on the controller + specified by ControllerHandle and ChildHandle. + +--*/ +{ + UINT8 Value; + + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + + Value = 0x0f; + gRT->SetVariable ( + L"Configuration", + &gEfiCallerIdGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof (Value), + &Value + ); + *ActionRequired = EfiDriverConfigurationActionRestartController; + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/DriverDiagnostics.c b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/DriverDiagnostics.c new file mode 100644 index 0000000000..ce3be14234 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/DriverDiagnostics.c @@ -0,0 +1,225 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DriverDiagnostics.c + +Abstract: + +--*/ + +#include "IDEBus.h" + +#define IDE_BUS_DIAGNOSTIC_ERROR L"PCI IDE/ATAPI Driver Diagnostics Failed" + +// +// EFI Driver Diagnostics Functions +// +EFI_STATUS +IDEBusDriverDiagnosticsRunDiagnostics ( + IN EFI_DRIVER_DIAGNOSTICS_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN EFI_DRIVER_DIAGNOSTIC_TYPE DiagnosticType, + IN CHAR8 *Language, + OUT EFI_GUID **ErrorType, + OUT UINTN *BufferSize, + OUT CHAR16 **Buffer + ); + +// +// EFI Driver Diagnostics Protocol +// +EFI_DRIVER_DIAGNOSTICS_PROTOCOL gIDEBusDriverDiagnostics = { + IDEBusDriverDiagnosticsRunDiagnostics, + "eng" +}; + +EFI_STATUS +IDEBusDriverDiagnosticsRunDiagnostics ( + IN EFI_DRIVER_DIAGNOSTICS_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN EFI_DRIVER_DIAGNOSTIC_TYPE DiagnosticType, + IN CHAR8 *Language, + OUT EFI_GUID **ErrorType, + OUT UINTN *BufferSize, + OUT CHAR16 **Buffer + ) +/*++ + + Routine Description: + Runs diagnostics on a controller. + + Arguments: + This - A pointer to the EFI_DRIVER_DIAGNOSTICS_PROTOCOL + instance. + ControllerHandle - The handle of the controller to run diagnostics on. + ChildHandle - The handle of the child controller to run diagnostics on + This is an optional parameter that may be NULL. It will + be NULL for device drivers. It will also be NULL for a + bus drivers that wish to run diagnostics on the bus + controller. It will not be NULL for a bus driver that + wishes to run diagnostics on one of its child + controllers. + DiagnosticType - Indicates type of diagnostics to perform on the + controller specified by ControllerHandle and ChildHandle. + See "Related Definitions" for the list of supported + types. + Language - A pointer to a three character ISO 639-2 language + identifier. This is the language in which the optional + error message should be returned in Buffer, and it must + match one of the languages specified in + SupportedLanguages. The number of languages supported by + a driver is up to the driver writer. + ErrorType - A GUID that defines the format of the data returned in + Buffer. + BufferSize - The size, in bytes, of the data returned in Buffer. + Buffer - A buffer that contains a Null-terminated Unicode string + plus some additional data whose format is defined by + ErrorType. Buffer is allocated by this function with + AllocatePool(), and it is the caller's responsibility + to free it with a call to FreePool(). + + Returns: + EFI_SUCCESS - The controller specified by ControllerHandle and + ChildHandle passed the diagnostic. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ErrorType is NULL. + EFI_INVALID_PARAMETER - BufferType is NULL. + EFI_INVALID_PARAMETER - Buffer is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support + running diagnostics for the controller specified + by ControllerHandle and ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + type of diagnostic specified by DiagnosticType. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + EFI_OUT_OF_RESOURCES - There are not enough resources available to complete + the diagnostics. + EFI_OUT_OF_RESOURCES - There are not enough resources available to return + the status information in ErrorType, BufferSize, + and Buffer. + EFI_DEVICE_ERROR - The controller specified by ControllerHandle and + ChildHandle did not pass the diagnostic. + +--*/ +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + EFI_BLOCK_IO_PROTOCOL *BlkIo; + IDE_BLK_IO_DEV *IdeBlkIoDevice; + UINT32 VendorDeviceId; + VOID *BlockBuffer; + + *ErrorType = NULL; + *BufferSize = 0; + + if (ChildHandle == NULL) { + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiCallerIdGuid, + NULL, + gIDEBusDriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + gIDEBusDriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Use services of PCI I/O Protocol to test the PCI IDE/ATAPI Controller + // The following test simply reads the Device ID and Vendor ID. + // It should never fail. A real test would perform more advanced + // diagnostics. + // + + Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0, 1, &VendorDeviceId); + if (EFI_ERROR (Status) || VendorDeviceId == 0xffffffff) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; + } + + Status = gBS->OpenProtocol ( + ChildHandle, + &gEfiBlockIoProtocolGuid, + (VOID **) &BlkIo, + gIDEBusDriverBinding.DriverBindingHandle, + ChildHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (BlkIo); + + // + // Use services available from IdeBlkIoDevice to test the IDE/ATAPI device + // + Status = gBS->AllocatePool ( + EfiBootServicesData, + IdeBlkIoDevice->BlkMedia.BlockSize, + (VOID **) &BlockBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = IdeBlkIoDevice->BlkIo.ReadBlocks ( + &IdeBlkIoDevice->BlkIo, + IdeBlkIoDevice->BlkMedia.MediaId, + 0, + IdeBlkIoDevice->BlkMedia.BlockSize, + BlockBuffer + ); + + if (EFI_ERROR (Status)) { + *ErrorType = &gEfiCallerIdGuid; + *BufferSize = sizeof (IDE_BUS_DIAGNOSTIC_ERROR); + + Status = gBS->AllocatePool ( + EfiBootServicesData, + (UINTN) (*BufferSize), + (VOID **) Buffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + EfiCopyMem (*Buffer, IDE_BUS_DIAGNOSTIC_ERROR, *BufferSize); + + Status = EFI_DEVICE_ERROR; + } + + gBS->FreePool (BlockBuffer); + + return Status; +} diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ata.c b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ata.c new file mode 100644 index 0000000000..88e81c0ada --- /dev/null +++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ata.c @@ -0,0 +1,3690 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ata.c + +Abstract: + +Revision History + + 2002-6: Add Atapi6 enhancement, support >120GB hard disk, including + update - ATAIdentity() func + update - AtaBlockIoReadBlocks() func + update - AtaBlockIoWriteBlocks() func + add - AtaAtapi6Identify() func + add - AtaReadSectorsExt() func + add - AtaWriteSectorsExt() func + add - AtaPioDataInExt() func + add - AtaPioDataOutExt() func + +--*/ + +#include "idebus.h" + + +EFI_STATUS +AtaReadSectorsExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN OUT VOID *DataBuffer, + IN EFI_LBA StartLba, + IN UINTN NumberOfBlocks + ); + +EFI_STATUS +AtaWriteSectorsExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *DataBuffer, + IN EFI_LBA StartLba, + IN UINTN NumberOfBlocks + ); + +EFI_STATUS +AtaPioDataInExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN OUT VOID *Buffer, + IN UINT32 ByteCount, + IN UINT8 AtaCommand, + IN EFI_LBA StartLba, + IN UINT16 SectorCount + ); + +EFI_STATUS +AtaPioDataOutExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *Buffer, + IN UINT32 ByteCount, + IN UINT8 AtaCommand, + IN EFI_LBA StartLba, + IN UINT16 SectorCount + ); + +EFI_STATUS +ATAIdentify ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + Name: + ATAIdentify + + + Purpose: + 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. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure,used + to record all the information of the IDE device. + + + Returns: + EFI_SUCCESS + Identify ATA device successfully. + + EFI_DEVICE_ERROR + ATA Identify Device Command failed or device is not + ATA device. + + + Notes: + parameter IdeDev will be updated in this function. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +{ + EFI_STATUS Status; + EFI_IDENTIFY_DATA *AtaIdentifyPointer; + UINT32 Capacity; + UINT8 DeviceSelect; + + // + // AtaIdentifyPointer is used for accommodating returned IDENTIFY data of + // the ATA Identify command + // + AtaIdentifyPointer = (EFI_IDENTIFY_DATA *) AllocateZeroPool (sizeof (EFI_IDENTIFY_DATA)); + + // + // use ATA PIO Data In protocol to send ATA Identify command + // and receive data from device + // + DeviceSelect = 0; + DeviceSelect = (UINT8) ((IdeDev->Device) << 4); + Status = AtaPioDataIn ( + IdeDev, + (VOID *) AtaIdentifyPointer, + sizeof (EFI_IDENTIFY_DATA), + IDENTIFY_DRIVE_CMD, + DeviceSelect, + 0, + 0, + 0, + 0 + ); + // + // If ATA Identify command succeeds, then according to the received + // IDENTIFY data, + // identify the device type ( ATA or not ). + // If ATA device, fill the information in IdeDev. + // If not ATA device, return IDE_DEVICE_ERROR + // + if (!EFI_ERROR (Status)) { + + IdeDev->pIdData = AtaIdentifyPointer; + + // + // Print ATA Module Name + // + PrintAtaModuleName (IdeDev); + + // + // bit 15 of pAtaIdentify->config is used to identify whether device is + // ATA device or ATAPI device. + // if 0, means ATA device; if 1, means ATAPI device. + // + if ((AtaIdentifyPointer->AtaData.config & 0x8000) == 0x00) { + // + // Detect if support S.M.A.R.T. If yes, enable it as default + // + AtaSMARTSupport (IdeDev); + + // + // Check whether this device needs 48-bit addressing (ATAPI-6 ata device) + // + Status = AtaAtapi6Identify (IdeDev); + if (!EFI_ERROR (Status)) { + // + // It's a disk with >120GB capacity, initialized in AtaAtapi6Identify() + // + return EFI_SUCCESS; + } + // + // This is a hard disk <= 120GB capacity, treat it as normal hard disk + // + IdeDev->Type = IdeHardDisk; + + // + // Block Media Information: + // Media->LogicalPartition , Media->WriteCaching will be filled + // in the DiscoverIdeDevcie() function. + // + IdeDev->BlkIo.Media->IoAlign = 4; + IdeDev->BlkIo.Media->MediaId = 1; + IdeDev->BlkIo.Media->RemovableMedia = FALSE; + IdeDev->BlkIo.Media->MediaPresent = TRUE; + IdeDev->BlkIo.Media->ReadOnly = FALSE; + IdeDev->BlkIo.Media->BlockSize = 0x200; + + // + // Calculate device capacity + // + Capacity = ((UINT32)AtaIdentifyPointer->AtaData.user_addressable_sectors_hi << 16) | + AtaIdentifyPointer->AtaData.user_addressable_sectors_lo ; + IdeDev->BlkIo.Media->LastBlock = Capacity - 1; + + return EFI_SUCCESS; + + } + } + + gBS->FreePool (AtaIdentifyPointer); + // + // Make sure the pIdData will not be freed again. + // + IdeDev->pIdData = NULL; + + return EFI_DEVICE_ERROR; +} + + +EFI_STATUS +AtaAtapi6Identify ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + Name: + + AtaAtapi6Identify + + Purpose: + + This function is called by ATAIdentify() to identity whether this disk + supports ATA/ATAPI6 48bit addressing, ie support >120G capacity + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + Returns: + + EFI_SUCCESS - The disk specified by IdeDev is a Atapi6 supported one + and 48-bit addressing must be used + + EFI_UNSUPPORTED - The disk dosn't not support Atapi6 or it supports but + the capacity is below 120G, 48bit addressing is not + needed + + Notes: + + This function must be called after DEVICE_IDENTITY command has been + successfully returned +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +{ + UINT8 Index; + EFI_LBA TmpLba; + EFI_LBA Capacity; + EFI_IDENTIFY_DATA *Atapi6IdentifyStruct; + + if (IdeDev->pIdData == NULL) { + return EFI_UNSUPPORTED; + } + + Atapi6IdentifyStruct = IdeDev->pIdData; + + if ((Atapi6IdentifyStruct->AtapiData.cmd_set_support_83 & bit10) == 0) { + // + // The device dosn't support 48 bit addressing + // + return EFI_UNSUPPORTED; + } + + // + // 48 bit address feature set is supported, get maximum capacity + // + Capacity = Atapi6IdentifyStruct->AtapiData.max_user_lba_for_48bit_addr[0]; + for (Index = 1; Index < 4; Index++) { + // + // Lower byte goes first: word[100] is the lowest word, word[103] is highest + // + TmpLba = Atapi6IdentifyStruct->AtapiData.max_user_lba_for_48bit_addr[Index]; + Capacity |= LShiftU64 (TmpLba, 16 * Index); + } + + if (Capacity > MAX_28BIT_ADDRESSING_CAPACITY) { + // + // Capacity exceeds 120GB. 48-bit addressing is really needed + // + IdeDev->Type = Ide48bitAddressingHardDisk; + + // + // Fill block media information:Media->LogicalPartition , + // Media->WriteCaching will be filledin the DiscoverIdeDevcie() function. + // + IdeDev->BlkIo.Media->IoAlign = 4; + IdeDev->BlkIo.Media->MediaId = 1; + IdeDev->BlkIo.Media->RemovableMedia = FALSE; + IdeDev->BlkIo.Media->MediaPresent = TRUE; + IdeDev->BlkIo.Media->ReadOnly = FALSE; + IdeDev->BlkIo.Media->BlockSize = 0x200; + IdeDev->BlkIo.Media->LastBlock = Capacity - 1; + + return EFI_SUCCESS; + } + + return EFI_UNSUPPORTED; +} + +VOID +PrintAtaModuleName ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + Name: + PrintAtaModuleName + + + Purpose: + This function is called by ATAIdentify() or ATAPIIdentify() + to print device's module name. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + Returns: + no returns. + + Notes: +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +{ + if (IdeDev->pIdData == NULL) { + return ; + } + + SwapStringChars (IdeDev->ModelName, IdeDev->pIdData->AtaData.ModelName, 40); + IdeDev->ModelName[40] = 0x00; +} + +EFI_STATUS +AtaPioDataIn ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *Buffer, + IN UINT32 ByteCount, + IN UINT8 AtaCommand, + IN UINT8 Head, + IN UINT8 SectorCount, + IN UINT8 SectorNumber, + IN UINT8 CylinderLsb, + IN UINT8 CylinderMsb + ) +/*++ + Name: + AtaPioDataIn + + + Purpose: + This function is used to send out ATA commands conforms to the + PIO Data In Protocol. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + VOID IN *Buffer + buffer contained data transferred from device to host. + + UINT32 IN ByteCount + data size in byte unit of the buffer. + + UINT8 IN AtaCommand + value of the Command Register + + UINT8 IN Head + value of the Head/Device Register + + UINT8 IN SectorCount + value of the Sector Count Register + + UINT8 IN SectorNumber + value of the Sector Number Register + + UINT8 IN CylinderLsb + value of the low byte of the Cylinder Register + + UINT8 IN CylinderMsb + value of the high byte of the Cylinder Register + + + Returns: + EFI_SUCCESS + send out the ATA command and device send required + data successfully. + + EFI_DEVICE_ERROR + command sent failed. + Notes: +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +// TODO: ByteCount - add argument and description to function comment +// TODO: AtaCommand - add argument and description to function comment +// TODO: Head - add argument and description to function comment +// TODO: SectorCount - add argument and description to function comment +// TODO: SectorNumber - add argument and description to function comment +// TODO: CylinderLsb - add argument and description to function comment +// TODO: CylinderMsb - add argument and description to function comment +{ + UINTN WordCount; + UINTN Increment; + UINT16 *Buffer16; + EFI_STATUS Status; + + Status = WaitForBSYClear (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // e0:1110,0000-- bit7 and bit5 are reserved bits. + // bit6 set means LBA mode + // + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + (UINT8) ((IdeDev->Device << 4) | 0xe0 | Head) + ); + + // + // All ATAPI device's ATA commands can be issued regardless of the + // state of the DRDY + // + if (IdeDev->Type == IdeHardDisk) { + + Status = DRDYReady (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + } + // + // set all the command parameters + // Before write to all the following registers, BSY and DRQ must be 0. + // + Status = DRQClear2 (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + if (AtaCommand == SET_FEATURES_CMD) { + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03); + } + + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, SectorNumber); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, CylinderLsb); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, CylinderMsb); + + // + // send command via Command Register + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand); + + Buffer16 = (UINT16 *) Buffer; + + // + // According to PIO data in protocol, host can perform a series of reads to + // the data register after each time device set DRQ ready; + // The data size of "a series of read" is command specific. + // For most ATA command, data size received from device will not exceed + // 1 sector, hence the data size for "a series of read" can be the whole data + // size of one command request. + // For ATA command such as Read Sector command, the data size of one ATA + // command request is often larger than 1 sector, according to the + // Read Sector command, the data size of "a series of read" is exactly 1 + // sector. + // Here for simplification reason, we specify the data size for + // "a series of read" to 1 sector (256 words) if data size of one ATA command + // request is larger than 256 words. + // + Increment = 256; + + // + // used to record bytes of currently transfered data + // + WordCount = 0; + + while (WordCount < ByteCount / 2) { + // + // Poll DRQ bit set, data transfer can be performed only when DRQ is ready. + // + Status = DRQReady2 (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + Status = CheckErrorStatus (IdeDev); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Get the byte count for one series of read + // + if ((WordCount + Increment) > ByteCount / 2) { + Increment = ByteCount / 2 - WordCount; + } + + IDEReadPortWMultiple ( + IdeDev->PciIo, + IdeDev->IoPort->Data, + Increment, + Buffer16 + ); + + WordCount += Increment; + Buffer16 += Increment; + + } + + DRQClear (IdeDev, ATATIMEOUT); + + return CheckErrorStatus (IdeDev); +} + +EFI_STATUS +AtaPioDataOut ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *Buffer, + IN UINT32 ByteCount, + IN UINT8 AtaCommand, + IN UINT8 Head, + IN UINT8 SectorCount, + IN UINT8 SectorNumber, + IN UINT8 CylinderLsb, + IN UINT8 CylinderMsb + ) +/*++ + Name: + AtaPioDataOut + + + Purpose: + This function is used to send out ATA commands conforms to the + PIO Data Out Protocol. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + VOID IN *Buffer + buffer contained data transferred from host to device. + + UINT32 IN ByteCount + data size in byte unit of the buffer. + + UINT8 IN AtaCommand + value of the Command Register + + UINT8 IN Head + value of the Head/Device Register + + UINT8 IN SectorCount + value of the Sector Count Register + + UINT8 IN SectorNumber + value of the Sector Number Register + + UINT8 IN CylinderLsb + value of the low byte of the Cylinder Register + + UINT8 IN CylinderMsb + value of the high byte of the Cylinder Register + + + Returns: + EFI_SUCCESS + send out the ATA command and device received required + data successfully. + + EFI_DEVICE_ERROR + command sent failed. + + Notes: +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +// TODO: ByteCount - add argument and description to function comment +// TODO: AtaCommand - add argument and description to function comment +// TODO: Head - add argument and description to function comment +// TODO: SectorCount - add argument and description to function comment +// TODO: SectorNumber - add argument and description to function comment +// TODO: CylinderLsb - add argument and description to function comment +// TODO: CylinderMsb - add argument and description to function comment +{ + UINTN WordCount; + UINTN Increment; + UINT16 *Buffer16; + EFI_STATUS Status; + + Status = WaitForBSYClear (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // select device via Head/Device register. + // Before write Head/Device register, BSY and DRQ must be 0. + // + Status = DRQClear2 (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // e0:1110,0000-- bit7 and bit5 are reserved bits. + // bit6 set means LBA mode + // + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + (UINT8) ((IdeDev->Device << 4) | 0xe0 | Head) + ); + + Status = DRDYReady (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // set all the command parameters + // Before write to all the following registers, BSY and DRQ must be 0. + // + Status = DRQClear2 (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, SectorNumber); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, CylinderLsb); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, CylinderMsb); + + // + // send command via Command Register + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand); + + Buffer16 = (UINT16 *) Buffer; + + // + // According to PIO data out protocol, host can perform a series of + // writes to the data register after each time device set DRQ ready; + // The data size of "a series of read" is command specific. + // For most ATA command, data size written to device will not exceed 1 sector, + // hence the data size for "a series of write" can be the data size of one + // command request. + // For ATA command such as Write Sector command, the data size of one + // ATA command request is often larger than 1 sector, according to the + // Write Sector command, the data size of "a series of read" is exactly + // 1 sector. + // Here for simplification reason, we specify the data size for + // "a series of write" to 1 sector (256 words) if data size of one ATA command + // request is larger than 256 words. + // + Increment = 256; + WordCount = 0; + + while (WordCount < ByteCount / 2) { + + // + // DRQReady2-- read Alternate Status Register to determine the DRQ bit + // data transfer can be performed only when DRQ is ready. + // + Status = DRQReady2 (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + Status = CheckErrorStatus (IdeDev); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Check the remaining byte count is less than 512 bytes + // + if ((WordCount + Increment) > ByteCount / 2) { + Increment = ByteCount / 2 - WordCount; + } + // + // perform a series of write without check DRQ ready + // + + IDEWritePortWMultiple ( + IdeDev->PciIo, + IdeDev->IoPort->Data, + Increment, + Buffer16 + ); + WordCount += Increment; + Buffer16 += Increment; + + } + + DRQClear (IdeDev, ATATIMEOUT); + + return CheckErrorStatus (IdeDev); +} + +EFI_STATUS +CheckErrorStatus ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + Name: + CheckErrorStatus + + + Purpose: + 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. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + Returns: + EFI_SUCCESS + No err information in the Status Register. + + EFI_DEVICE_ERROR + Any err information in the Status Register. + + Notes: +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +{ + UINT8 StatusRegister; + +//#ifdef EFI_DEBUG + + UINT8 ErrorRegister; + +//#endif + + StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status); + + DEBUG_CODE ( + + if (StatusRegister & DWF) { + DEBUG ( + (EFI_D_BLKIO, + "CheckErrorStatus()-- %02x : Error : Write Fault\n", + StatusRegister) + ); + } + + if (StatusRegister & CORR) { + DEBUG ( + (EFI_D_BLKIO, + "CheckErrorStatus()-- %02x : Error : Corrected Data\n", + StatusRegister) + ); + } + + if (StatusRegister & ERR) { + ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error); + + if (ErrorRegister & BBK_ERR) { + DEBUG ( + (EFI_D_BLKIO, + "CheckErrorStatus()-- %02x : Error : Bad Block Detected\n", + ErrorRegister) + ); + } + + if (ErrorRegister & UNC_ERR) { + DEBUG ( + (EFI_D_BLKIO, + "CheckErrorStatus()-- %02x : Error : Uncorrectable Data\n", + ErrorRegister) + ); + } + + if (ErrorRegister & MC_ERR) { + DEBUG ( + (EFI_D_BLKIO, + "CheckErrorStatus()-- %02x : Error : Media Change\n", + ErrorRegister) + ); + } + + if (ErrorRegister & ABRT_ERR) { + DEBUG ( + (EFI_D_BLKIO, + "CheckErrorStatus()-- %02x : Error : Abort\n", + ErrorRegister) + ); + } + + if (ErrorRegister & TK0NF_ERR) { + DEBUG ( + (EFI_D_BLKIO, + "CheckErrorStatus()-- %02x : Error : Track 0 Not Found\n", + ErrorRegister) + ); + } + + if (ErrorRegister & AMNF_ERR) { + DEBUG ( + (EFI_D_BLKIO, + "CheckErrorStatus()-- %02x : Error : Address Mark Not Found\n", + ErrorRegister) + ); + } + + } + ); + + if ((StatusRegister & (ERR | DWF | CORR)) == 0) { + return EFI_SUCCESS; + } + + return EFI_DEVICE_ERROR; + +} + +EFI_STATUS +AtaReadSectors ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *DataBuffer, + IN EFI_LBA Lba, + IN UINTN NumberOfBlocks + ) +/*++ + Name: + AtaReadSectors + + + Purpose: + This function is called by the AtaBlkIoReadBlocks() to perform + reading from media in block unit. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + VOID IN *DataBuffer + A pointer to the destination buffer for the data. + + EFI_LBA IN Lba + The starting logical block address to read from + on the device media. + + UINTN IN NumberOfBlocks + The number of transfer data blocks. + + Returns: + return status is fully dependent on the return status + of AtaPioDataIn() function. + + Notes: +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: DataBuffer - add argument and description to function comment +// TODO: Lba - add argument and description to function comment +// TODO: NumberOfBlocks - add argument and description to function comment +{ + EFI_STATUS Status; + UINTN BlocksRemaining; + UINT32 Lba32; + UINT8 Lba0; + UINT8 Lba1; + UINT8 Lba2; + UINT8 Lba3; + UINT8 AtaCommand; + UINT8 SectorCount8; + UINT16 SectorCount; + UINTN ByteCount; + VOID *Buffer; + + Buffer = DataBuffer; + + // + // Using ATA Read Sector(s) command (opcode=0x20) with PIO DATA IN protocol + // + AtaCommand = READ_SECTORS_CMD; + + + BlocksRemaining = NumberOfBlocks; + + Lba32 = (UINT32) Lba; + + Status = EFI_SUCCESS; + + while (BlocksRemaining > 0) { + + // + // in ATA-3 spec, LBA is in 28 bit width + // + Lba0 = (UINT8) Lba32; + Lba1 = (UINT8) (Lba32 >> 8); + Lba2 = (UINT8) (Lba32 >> 16); + // + // low 4 bit of Lba3 stands for LBA bit24~bit27. + // + Lba3 = (UINT8) ((Lba32 >> 24) & 0x0f); + + if (BlocksRemaining >= 0x100) { + + // + // SectorCount8 is sent to Sector Count register, 0x00 means 256 + // sectors to be read + // + SectorCount8 = 0x00; + // + // SectorCount is used to record the number of sectors to be read + // + SectorCount = 256; + } else { + + SectorCount8 = (UINT8) BlocksRemaining; + SectorCount = (UINT16) BlocksRemaining; + } + + // + // ByteCount is the number of bytes that will be read + // + ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize); + + // + // call AtaPioDataIn() to send Read Sector Command and receive data read + // + Status = AtaPioDataIn ( + IdeDev, + Buffer, + (UINT32) ByteCount, + AtaCommand, + Lba3, + SectorCount8, + Lba0, + Lba1, + Lba2 + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Lba32 += SectorCount; + Buffer = ((UINT8 *) Buffer + ByteCount); + BlocksRemaining -= SectorCount; + } + + return Status; +} + +EFI_STATUS +AtaWriteSectors ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *BufferData, + IN EFI_LBA Lba, + IN UINTN NumberOfBlocks + ) +/*++ + Name: + AtaWriteSectors + + + Purpose: + This function is called by the AtaBlkIoWriteBlocks() to perform + writing onto media in block unit. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure,used + to record all the information of the IDE device. + + VOID IN *BufferData + A pointer to the source buffer for the data. + + EFI_LBA IN Lba + The starting logical block address to write onto + the device media. + + UINTN IN NumberOfBlocks + The number of transfer data blocks. + + + Returns: + return status is fully dependent on the return status + of AtaPioDataOut() function. + + Notes: +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: BufferData - add argument and description to function comment +// TODO: Lba - add argument and description to function comment +// TODO: NumberOfBlocks - add argument and description to function comment +{ + EFI_STATUS Status; + UINTN BlocksRemaining; + UINT32 Lba32; + UINT8 Lba0; + UINT8 Lba1; + UINT8 Lba2; + UINT8 Lba3; + UINT8 AtaCommand; + UINT8 SectorCount8; + UINT16 SectorCount; + UINTN ByteCount; + VOID *Buffer; + + Buffer = BufferData; + + // + // Using Write Sector(s) command (opcode=0x30) with PIO DATA OUT protocol + // + AtaCommand = WRITE_SECTORS_CMD; + + BlocksRemaining = NumberOfBlocks; + + Lba32 = (UINT32) Lba; + + Status = EFI_SUCCESS; + + while (BlocksRemaining > 0) { + + Lba0 = (UINT8) Lba32; + Lba1 = (UINT8) (Lba32 >> 8); + Lba2 = (UINT8) (Lba32 >> 16); + Lba3 = (UINT8) ((Lba32 >> 24) & 0x0f); + + if (BlocksRemaining >= 0x100) { + + // + // SectorCount8 is sent to Sector Count register, 0x00 means 256 sectors + // to be written + // + SectorCount8 = 0x00; + // + // SectorCount is used to record the number of sectors to be written + // + SectorCount = 256; + } else { + + SectorCount8 = (UINT8) BlocksRemaining; + SectorCount = (UINT16) BlocksRemaining; + } + + ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize); + + Status = AtaPioDataOut ( + IdeDev, + Buffer, + (UINT32) ByteCount, + AtaCommand, + Lba3, + SectorCount8, + Lba0, + Lba1, + Lba2 + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Lba32 += SectorCount; + Buffer = ((UINT8 *) Buffer + ByteCount); + BlocksRemaining -= SectorCount; + } + + return Status; +} + +EFI_STATUS +AtaSoftReset ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + Name: + AtaSoftReset + + Purpose: + This function is used to implement the Soft Reset on the specified + device. But, the ATA Soft Reset mechanism is so strong a reset method + that it will force resetting on both devices connected to the + same cable. + It is called by IdeBlkIoReset(), a interface function of Block + I/O protocol. + This function can also be used by the ATAPI device to perform reset when + ATAPI Reset command is failed. + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + Returns: + EFI_SUCCESS + Soft reset completes successfully. + + EFI_DEVICE_ERROR + Any step during the reset process is failed. + Notes: + The registers initial values after ATA soft reset are different + to the ATA device and ATAPI device. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +{ + + UINT8 DeviceControl; + + DeviceControl = 0; + // + // set SRST bit to initiate soft reset + // + DeviceControl |= SRST; + + // + // disable Interrupt + // + DeviceControl |= bit1; + + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl); + + gBS->Stall (10); + + // + // Enable interrupt to support UDMA, and clear SRST bit + // + DeviceControl = 0; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl); + + // + // slave device needs at most 31s to clear BSY + // + if (WaitForBSYClear (IdeDev, 31000) == EFI_TIMEOUT) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +AtaBlkIoReadBlocks ( + IN IDE_BLK_IO_DEV *IdeBlkIoDevice, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +/*++ + Name: + AtaBlkIoReadBlocks + + + Purpose: + This function is the ATA implementation for ReadBlocks in the + Block I/O Protocol interface. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeBlkIoDevice + Indicates the calling context. + + UINT32 IN MediaId + The media id that the read request is for. + + EFI_LBA IN LBA + The starting logical block address to read from + on the device. + + UINTN IN BufferSize + The size of the Buffer in bytes. This must be a + multiple of the intrinsic block size of the device. + + VOID OUT *Buffer + A pointer to the destination buffer for the data. + The caller is responsible for either having implicit + or explicit ownership of the memory that data is read into. + + Returns: + EFI_SUCCESS + Read Blocks successfully. + + EFI_DEVICE_ERROR + Read Blocks failed. + + EFI_NO_MEDIA + There is no media in the device. + + EFI_MEDIA_CHANGE + The MediaId is not for the current media. + + EFI_BAD_BUFFER_SIZE + The BufferSize parameter is not a multiple of the + intrinsic block size of the device. + + EFI_INVALID_PARAMETER + The read request contains LBAs that are not valid, + or the data buffer is not valid. + + Notes: + If Read Block error because of device error, this function will call + AtaSoftReset() function to reset device. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeBlkIoDevice - add argument and description to function comment +// TODO: MediaId - add argument and description to function comment +// TODO: LBA - add argument and description to function comment +// TODO: BufferSize - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +// TODO: EFI_MEDIA_CHANGED - add return value to function comment +{ + EFI_BLOCK_IO_MEDIA *Media; + UINTN BlockSize; + UINTN NumberOfBlocks; + EFI_STATUS Status; + + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (BufferSize == 0) { + return EFI_SUCCESS; + } + + Status = EFI_SUCCESS; + + // + // Get the intrinsic block size + // + Media = IdeBlkIoDevice->BlkIo.Media; + BlockSize = Media->BlockSize; + + NumberOfBlocks = BufferSize / BlockSize; + + if (MediaId != Media->MediaId) { + return EFI_MEDIA_CHANGED; + } + + if (BufferSize % BlockSize != 0) { + return EFI_BAD_BUFFER_SIZE; + } + + if (!(Media->MediaPresent)) { + return EFI_NO_MEDIA; + } + + if (LBA > Media->LastBlock) { + return EFI_INVALID_PARAMETER; + } + + if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) { + return EFI_INVALID_PARAMETER; + } + + if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) { + return EFI_INVALID_PARAMETER; + } + + if (IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) { + // + // For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 read block mechanism + // + Status = AtaUdmaReadExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks); + if (EFI_ERROR (Status)) { + Status = AtaReadSectorsExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks); + } + } else { + // + // For ATA-3 compatible device, use ATA-3 read block mechanism + // Notice DMA operation can only handle 32bit address + // + if ((UINTN) Buffer <= 0xFFFFFFFF) { + Status = AtaUdmaRead (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks); + } + + if (EFI_ERROR (Status) || ((UINTN) Buffer > 0xFFFFFFFF)) { + Status = AtaReadSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks); + } + } + + if (EFI_ERROR (Status)) { + AtaSoftReset (IdeBlkIoDevice); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; + +} + +EFI_STATUS +AtaBlkIoWriteBlocks ( + IN IDE_BLK_IO_DEV *IdeBlkIoDevice, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +/*++ + Name: + AtaBlkIoWriteBlocks + + + Purpose: + This function is the ATA implementation for WriteBlocks in the + Block I/O Protocol interface. + + Parameters: + IDE_BLK_IO_DEV IN *IdeBlkIoDevice + Indicates the calling context. + + UINT32 IN MediaId + The media id that the write request is for. + + EFI_LBA IN LBA + The starting logical block address to write onto + the device. + + UINTN IN BufferSize + The size of the Buffer in bytes. This must be a + multiple of the intrinsic block size of the device. + + VOID OUT *Buffer + A pointer to the source buffer for the data. + The caller is responsible for either having implicit + or explicit ownership of the memory that data is + written from. + + + Returns: + EFI_SUCCESS + Write Blocks successfully. + + EFI_DEVICE_ERROR + Write Blocks failed. + + EFI_NO_MEDIA + There is no media in the device. + + EFI_MEDIA_CHANGE + The MediaId is not for the current media. + + EFI_BAD_BUFFER_SIZE + The BufferSize parameter is not a multiple of the + intrinsic block size of the device. + + EFI_INVALID_PARAMETER + The write request contains LBAs that are not valid, + or the data buffer is not valid. + + Notes: + If Write Block error because of device error, this function will call + AtaSoftReset() function to reset device. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeBlkIoDevice - add argument and description to function comment +// TODO: MediaId - add argument and description to function comment +// TODO: LBA - add argument and description to function comment +// TODO: BufferSize - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +// TODO: EFI_MEDIA_CHANGED - add return value to function comment +{ + + EFI_BLOCK_IO_MEDIA *Media; + UINTN BlockSize; + UINTN NumberOfBlocks; + EFI_STATUS Status; + + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (BufferSize == 0) { + return EFI_SUCCESS; + } + + Status = EFI_SUCCESS; + + // + // Get the intrinsic block size + // + Media = IdeBlkIoDevice->BlkIo.Media; + BlockSize = Media->BlockSize; + NumberOfBlocks = BufferSize / BlockSize; + + if (MediaId != Media->MediaId) { + return EFI_MEDIA_CHANGED; + } + + if (BufferSize % BlockSize != 0) { + return EFI_BAD_BUFFER_SIZE; + } + + if (LBA > Media->LastBlock) { + return EFI_INVALID_PARAMETER; + } + + if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) { + return EFI_INVALID_PARAMETER; + } + + if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) { + return EFI_INVALID_PARAMETER; + } + + if (IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) { + // + // For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 write block mechanism + // + Status = AtaUdmaWriteExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks); + if (EFI_ERROR (Status)) { + Status = AtaWriteSectorsExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks); + } + } else { + // + // For ATA-3 compatible device, use ATA-3 write block mechanism + // + Status = AtaUdmaWrite (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks); + if (EFI_ERROR (Status) || ((UINTN) Buffer > 0xFFFFFFFF)) { + Status = AtaWriteSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks); + } + } + + if (EFI_ERROR (Status)) { + AtaSoftReset (IdeBlkIoDevice); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +AtaReadSectorsExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *DataBuffer, + IN EFI_LBA StartLba, + IN UINTN NumberOfBlocks + ) +/*++ + Name: + + AtaReadSectorsExt + + Purpose: + + This function is called by the AtaBlkIoReadBlocks() to perform + reading from media in block unit. The function has been enhanced to + support >120GB access and transfer at most 65536 blocks per command + + Parameters: + + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + VOID IN *DataBuffer + A pointer to the destination buffer for the data. + + EFI_LBA IN StartLba + The starting logical block address to read from + on the device media. + + UINTN IN NumberOfBlocks + The number of transfer data blocks. + + Returns: + + return status is fully dependent on the return status + of AtaPioDataInExt() function. + + Notes: +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: DataBuffer - add argument and description to function comment +// TODO: StartLba - add argument and description to function comment +// TODO: NumberOfBlocks - add argument and description to function comment +{ + EFI_STATUS Status; + UINTN BlocksRemaining; + EFI_LBA Lba64; + UINT8 AtaCommand; + UINT16 SectorCount; + UINT32 ByteCount; + VOID *Buffer; + + // + // Using ATA "Read Sectors Ext" command(opcode=0x24) with PIO DATA IN protocol + // + AtaCommand = READ_SECTORS_EXT_CMD; + Buffer = DataBuffer; + BlocksRemaining = NumberOfBlocks; + Lba64 = StartLba; + Status = EFI_SUCCESS; + + while (BlocksRemaining > 0) { + + if (BlocksRemaining >= 0x10000) { + // + // SectorCount is used to record the number of sectors to be read + // Max 65536 sectors can be transfered at a time. + // + SectorCount = 0xffff; + } else { + SectorCount = (UINT16) BlocksRemaining; + } + + // + // ByteCount is the number of bytes that will be read + // + ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize); + + // + // call AtaPioDataInExt() to send Read Sector Command and receive data read + // + Status = AtaPioDataInExt ( + IdeDev, + Buffer, + ByteCount, + AtaCommand, + Lba64, + SectorCount + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Lba64 += SectorCount; + Buffer = ((UINT8 *) Buffer + ByteCount); + BlocksRemaining -= SectorCount; + } + + return Status; +} + +EFI_STATUS +AtaWriteSectorsExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *DataBuffer, + IN EFI_LBA StartLba, + IN UINTN NumberOfBlocks + ) +/*++ + Name: + + AtaWriteSectorsExt + + Purpose: + + This function is called by the AtaBlkIoWriteBlocks() to perform + writing onto media in block unit. The function has been enhanced to + support >120GB access and transfer at most 65536 blocks per command + + Parameters: + + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure,used + to record all the information of the IDE device. + + VOID IN *DataBuffer + A pointer to the source buffer for the data. + + EFI_LBA IN Lba + The starting logical block address to write onto + the device media. + + UINTN IN NumberOfBlocks + The number of transfer data blocks. + + Returns: + + return status is fully dependent on the return status + of AtaPioDataOutExt() function. + + Notes: +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: DataBuffer - add argument and description to function comment +// TODO: StartLba - add argument and description to function comment +// TODO: NumberOfBlocks - add argument and description to function comment +{ + EFI_STATUS Status; + EFI_LBA Lba64; + UINTN BlocksRemaining; + UINT8 AtaCommand; + UINT16 SectorCount; + UINT32 ByteCount; + VOID *Buffer; + + // + // Using ATA "Write Sectors Ext" cmd(opcode=0x24) with PIO DATA OUT protocol + // + AtaCommand = WRITE_SECTORS_EXT_CMD; + Lba64 = StartLba; + Buffer = DataBuffer; + BlocksRemaining = NumberOfBlocks; + + Status = EFI_SUCCESS; + + while (BlocksRemaining > 0) { + + if (BlocksRemaining >= 0x10000) { + // + // SectorCount is used to record the number of sectors to be written. + // Max 65536 sectors can be transfered at a time. + // + SectorCount = 0xffff; + } else { + SectorCount = (UINT16) BlocksRemaining; + } + + // + // ByteCount is the number of bytes that will be written + // + ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize); + + // + // Call AtaPioDataOutExt() to send "Write Sectors Ext" Command + // + Status = AtaPioDataOutExt ( + IdeDev, + Buffer, + ByteCount, + AtaCommand, + Lba64, + SectorCount + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Lba64 += SectorCount; + Buffer = ((UINT8 *) Buffer + ByteCount); + BlocksRemaining -= SectorCount; + } + + return Status; +} + +EFI_STATUS +AtaPioDataInExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN OUT VOID *Buffer, + IN UINT32 ByteCount, + IN UINT8 AtaCommand, + IN EFI_LBA StartLba, + IN UINT16 SectorCount + ) +/*++ + Name: + + AtaPioDataInExt + + Purpose: + + This function is used to send out ATA commands conforms to the + PIO Data In Protocol, supporting ATA/ATAPI-6 standard + + Comparing with ATA-3 data in protocol, we have two differents here: + 1. Do NOT wait for DRQ clear before sending command into IDE device.(the + wait will frequently fail... cause writing function return error) + + 2. Do NOT wait for DRQ clear after all data readed.(the wait greatly + slow down writing performance by 100 times!) + + + Parameters: + + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + VOID IN OUT *Buffer + buffer contained data transferred from device to host. + + UINT32 IN ByteCount + data size in byte unit of the buffer. + + UINT8 IN AtaCommand + value of the Command Register + + EFI_LBA IN StartLba + the start LBA of this transaction + + UINT16 IN SectorCount + the count of sectors to be transfered + + Returns: + + EFI_SUCCESS + send out the ATA command and device send required + data successfully. + + EFI_DEVICE_ERROR + command sent failed. + Notes: +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +// TODO: ByteCount - add argument and description to function comment +// TODO: AtaCommand - add argument and description to function comment +// TODO: StartLba - add argument and description to function comment +// TODO: SectorCount - add argument and description to function comment +{ + UINT8 DevSel; + UINT8 SectorCount8; + UINT8 LbaLow; + UINT8 LbaMid; + UINT8 LbaHigh; + UINTN WordCount; + UINTN Increment; + UINT16 *Buffer16; + EFI_STATUS Status; + + Status = WaitForBSYClear (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Select device, set bit6 as 1 to indicate LBA mode is used + // + DevSel = (UINT8) (IdeDev->Device << 4); + DevSel |= 0x40; + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + DevSel + ); + + // + // Wait for DRDY singnal asserting. ATAPI device needn't wait + // + if ( (IdeDev->Type == IdeHardDisk) || + (IdeDev->Type == Ide48bitAddressingHardDisk)) { + + Status = DRDYReady (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + } + + // + // Fill feature register if needed + // + if (AtaCommand == SET_FEATURES_CMD) { + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03); + } + + // + // Fill the sector count register, which is a two-byte FIFO. Need write twice. + // + SectorCount8 = (UINT8) (SectorCount >> 8); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8); + + SectorCount8 = (UINT8) SectorCount; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8); + + // + // Fill the start LBA registers, which are also two-byte FIFO + // + LbaLow = (UINT8) RShiftU64 (StartLba, 24); + LbaMid = (UINT8) RShiftU64 (StartLba, 32); + LbaHigh = (UINT8) RShiftU64 (StartLba, 40); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh); + + LbaLow = (UINT8) StartLba; + LbaMid = (UINT8) RShiftU64 (StartLba, 8); + LbaHigh = (UINT8) RShiftU64 (StartLba, 16); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh); + + // + // Send command via Command Register, invoking the processing of this command + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand); + + Buffer16 = (UINT16 *) Buffer; + + // + // According to PIO data in protocol, host can perform a series of reads to + // the data register after each time device set DRQ ready; + // + + // + // 256 words + // + Increment = 256; + + // + // used to record bytes of currently transfered data + // + WordCount = 0; + + while (WordCount < ByteCount / 2) { + // + // Poll DRQ bit set, data transfer can be performed only when DRQ is ready. + // + Status = DRQReady2 (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + Status = CheckErrorStatus (IdeDev); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Get the byte count for one series of read + // + if ((WordCount + Increment) > ByteCount / 2) { + Increment = ByteCount / 2 - WordCount; + } + + IDEReadPortWMultiple ( + IdeDev->PciIo, + IdeDev->IoPort->Data, + Increment, + Buffer16 + ); + + WordCount += Increment; + Buffer16 += Increment; + + } + + return CheckErrorStatus (IdeDev); +} + +EFI_STATUS +AtaPioDataOutExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *Buffer, + IN UINT32 ByteCount, + IN UINT8 AtaCommand, + IN EFI_LBA StartLba, + IN UINT16 SectorCount + ) +/*++ + Name: + + AtaPioDataOutExt + + Purpose: + + This function is used to send out ATA commands conforms to the + PIO Data Out Protocol, supporting ATA/ATAPI-6 standard + + Comparing with ATA-3 data out protocol, we have two differents here: + 1. Do NOT wait for DRQ clear before sending command into IDE device.(the + wait will frequently fail... cause writing function return error) + + 2. Do NOT wait for DRQ clear after all data readed.(the wait greatly + slow down writing performance by 100 times!) + + Parameters: + + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + VOID IN *Buffer + buffer contained data transferred from host to device. + + UINT32 IN ByteCount + data size in byte unit of the buffer. + + UINT8 IN AtaCommand + value of the Command Register + + EFI_LBA IN StartLba + the start LBA of this transaction + + UINT16 IN SectorCount + the count of sectors to be transfered + + Returns: + + EFI_SUCCESS + send out the ATA command and device receive required + data successfully. + + EFI_DEVICE_ERROR + command sent failed. + Notes: +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +// TODO: ByteCount - add argument and description to function comment +// TODO: AtaCommand - add argument and description to function comment +// TODO: StartLba - add argument and description to function comment +// TODO: SectorCount - add argument and description to function comment +{ + UINT8 DevSel; + UINT8 SectorCount8; + UINT8 LbaLow; + UINT8 LbaMid; + UINT8 LbaHigh; + UINTN WordCount; + UINTN Increment; + UINT16 *Buffer16; + EFI_STATUS Status; + + Status = WaitForBSYClear (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Select device. Set bit6 as 1 to indicate LBA mode is used + // + DevSel = (UINT8) (IdeDev->Device << 4); + DevSel |= 0x40; + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + DevSel + ); + + // + // Wait for DRDY singnal asserting. + // + Status = DRDYReady (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Fill feature register if needed + // + if (AtaCommand == SET_FEATURES_CMD) { + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03); + } + + // + // Fill the sector count register, which is a two-byte FIFO. Need write twice. + // + SectorCount8 = (UINT8) (SectorCount >> 8); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8); + + SectorCount8 = (UINT8) SectorCount; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8); + + // + // Fill the start LBA registers, which are also two-byte FIFO + // + LbaLow = (UINT8) RShiftU64 (StartLba, 24); + LbaMid = (UINT8) RShiftU64 (StartLba, 32); + LbaHigh = (UINT8) RShiftU64 (StartLba, 40); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh); + + LbaLow = (UINT8) StartLba; + LbaMid = (UINT8) RShiftU64 (StartLba, 8); + LbaHigh = (UINT8) RShiftU64 (StartLba, 16); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh); + + // + // Send command via Command Register, invoking the processing of this command + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand); + + Buffer16 = (UINT16 *) Buffer; + + // + // According to PIO Data Out protocol, host can perform a series of writes to + // the data register after each time device set DRQ ready; + // + Increment = 256; + + // + // used to record bytes of currently transfered data + // + WordCount = 0; + + while (WordCount < ByteCount / 2) { + // + // Poll DRQ bit set, data transfer can be performed only when DRQ is ready. + // + Status = DRQReady2 (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + Status = CheckErrorStatus (IdeDev); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Write data into device by one series of writing to data register + // + if ((WordCount + Increment) > ByteCount / 2) { + Increment = ByteCount / 2 - WordCount; + } + + IDEWritePortWMultiple ( + IdeDev->PciIo, + IdeDev->IoPort->Data, + Increment, + Buffer16 + ); + + WordCount += Increment; + Buffer16 += Increment; + + } + // + // while + // + + return CheckErrorStatus (IdeDev); +} + + +VOID +AtaSMARTSupport ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + Name: + AtaSMARTSupport + + Purpose: + + Enable SMART of the disk if supported + + Parameters: + + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure,used + to record all the information of the IDE device. + + Returns: + + NONE +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +{ + EFI_STATUS Status; + BOOLEAN SMARTSupported; + UINT8 Device; + EFI_IDENTIFY_DATA *TmpAtaIdentifyPointer; + UINT8 DeviceSelect; + UINT8 LBAMid; + UINT8 LBAHigh; + + // + // Detect if the device supports S.M.A.R.T. + // + if ((IdeDev->pIdData->AtaData.command_set_supported_83 & 0xc000) != 0x4000) { + // + // Data in word 82 is not valid (bit15 shall be zero and bit14 shall be to one) + // + return ; + } else { + if ((IdeDev->pIdData->AtaData.command_set_supported_82 & 0x0001) != 0x0001) { + // + // S.M.A.R.T is not supported by the device + // + SMARTSupported = FALSE; + } else { + SMARTSupported = TRUE; + } + } + + if (!SMARTSupported) { + // + // Report nonsupport status code + // + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_NOTSUPPORTED) + ); + } else { + // + // Enable this feature + // + REPORT_STATUS_CODE ( + EFI_PROGRESS_CODE, + (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_ENABLE) + ); + + Device = (UINT8) ((IdeDev->Device << 4) | 0xe0); + Status = AtaNonDataCommandIn ( + IdeDev, + ATA_SMART_CMD, + Device, + ATA_SMART_ENABLE_OPERATION, + 0, + 0, + ATA_CONSTANT_4F, + ATA_CONSTANT_C2 + ); + // + // Detect if this feature is enabled + // + TmpAtaIdentifyPointer = (EFI_IDENTIFY_DATA *) AllocateZeroPool (sizeof (EFI_IDENTIFY_DATA)); + + DeviceSelect = (UINT8) ((IdeDev->Device) << 4); + Status = AtaPioDataIn ( + IdeDev, + (VOID *) TmpAtaIdentifyPointer, + sizeof (EFI_IDENTIFY_DATA), + IDENTIFY_DRIVE_CMD, + DeviceSelect, + 0, + 0, + 0, + 0 + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (TmpAtaIdentifyPointer); + return ; + } + + // + // Check if the feature is enabled + // + if ((TmpAtaIdentifyPointer->AtaData.command_set_feature_enb_85 & 0x0001) == 0x0001) { + // + // Read status data + // + AtaNonDataCommandIn ( + IdeDev, + ATA_SMART_CMD, + Device, + ATA_SMART_RETURN_STATUS, + 0, + 0, + ATA_CONSTANT_4F, + ATA_CONSTANT_C2 + ); + LBAMid = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb); + LBAHigh = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb); + + if ((LBAMid == 0x4f) && (LBAHigh == 0xc2)) { + // + // The threshold exceeded condition is not detected by the device + // + REPORT_STATUS_CODE ( + EFI_PROGRESS_CODE, + (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_UNDERTHRESHOLD) + ); + + } else if ((LBAMid == 0xf4) && (LBAHigh == 0x2c)) { + // + // The threshold exceeded condition is detected by the device + // + REPORT_STATUS_CODE ( + EFI_PROGRESS_CODE, + (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_OVERTHRESHOLD) + ); + } + + } else { + // + // Report disabled status code + // + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLED) + ); + } + + gBS->FreePool (TmpAtaIdentifyPointer); + } + + return ; +} + +EFI_STATUS +AtaCommandIssueExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINT8 AtaCommand, + IN UINT8 Device, + IN UINT16 Feature, + IN UINT16 SectorCount, + IN EFI_LBA LbaAddress + ) +/*++ + +Routine Description: + + Send ATA Ext command into device with NON_DATA protocol + +Arguments: + + IdeDev - Standard IDE device private data structure + AtaCommand - The ATA command to be sent + Device - The value in Device register + Feature - The value in Feature register + SectorCount - The value in SectorCount register + LbaAddress - The LBA address in 48-bit mode + +Returns: + + EFI_SUCCESS - Reading succeed + EFI_DEVICE_ERROR - Error executing commands on this device + +--*/ +{ + EFI_STATUS Status; + UINT8 SectorCount8; + UINT8 Feature8; + UINT8 LbaLow; + UINT8 LbaMid; + UINT8 LbaHigh; + + Status = WaitForBSYClear (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility) + // + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + (UINT8) ((IdeDev->Device << 4) | 0xe0) + ); + + // + // ATA commands for ATA device must be issued when DRDY is set + // + Status = DRDYReady (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Pass parameter into device register block + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device); + + // + // Fill the feature register, which is a two-byte FIFO. Need write twice. + // + Feature8 = (UINT8) (Feature >> 8); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8); + + Feature8 = (UINT8) Feature; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8); + + // + // Fill the sector count register, which is a two-byte FIFO. Need write twice. + // + SectorCount8 = (UINT8) (SectorCount >> 8); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8); + + SectorCount8 = (UINT8) SectorCount; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8); + + // + // Fill the start LBA registers, which are also two-byte FIFO + // + LbaLow = (UINT8) RShiftU64 (LbaAddress, 24); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow); + LbaLow = (UINT8) LbaAddress; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow); + + LbaMid = (UINT8) RShiftU64 (LbaAddress, 32); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid); + LbaMid = (UINT8) RShiftU64 (LbaAddress, 8); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid); + + LbaHigh = (UINT8) RShiftU64 (LbaAddress, 40); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh); + LbaHigh = (UINT8) RShiftU64 (LbaAddress, 16); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh); + + // + // Work around for Segate 160G disk writing + // + gBS->Stall (1800); + + // + // Send command via Command Register + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand); + + // + // Stall at least 400ns + // + gBS->Stall (100); + + return EFI_SUCCESS; +} + +EFI_STATUS +AtaCommandIssue ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINT8 AtaCommand, + IN UINT8 Device, + IN UINT16 Feature, + IN UINT16 SectorCount, + IN EFI_LBA LbaAddress + ) +/*++ + +Routine Description: + + Send ATA Ext command into device with NON_DATA protocol + +Arguments: + + IdeDev - Standard IDE device private data structure + AtaCommand - The ATA command to be sent + Device - The value in Device register + Feature - The value in Feature register + SectorCount - The value in SectorCount register + LbaAddress - The LBA address in 48-bit mode + +Returns: + + EFI_SUCCESS - Reading succeed + EFI_DEVICE_ERROR - Error executing commands on this device + +--*/ +{ + EFI_STATUS Status; + UINT8 SectorCount8; + UINT8 Feature8; + UINT8 Lba0; + UINT8 Lba1; + UINT8 Lba2; + UINT8 Lba3; + + Status = WaitForBSYClear (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility) + // + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + (UINT8) ((IdeDev->Device << 4) | 0xe0) + ); + + // + // ATA commands for ATA device must be issued when DRDY is set + // + Status = DRDYReady (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + Lba0 = (UINT8) LbaAddress; + Lba1 = (UINT8) RShiftU64 (LbaAddress, 8); + Lba2 = (UINT8) RShiftU64 (LbaAddress, 16); + Lba3 = (UINT8) RShiftU64 (LbaAddress, 24); + Device |= Lba3; + + // + // Pass parameter into device register block + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device); + + // + // Fill the feature register, which is a two-byte FIFO. Need write twice. + // + Feature8 = (UINT8) Feature; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8); + + // + // Fill the sector count register, which is a two-byte FIFO. Need write twice. + // + SectorCount8 = (UINT8) SectorCount; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8); + + // + // Fill the start LBA registers, which are also two-byte FIFO + // + + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, Lba0); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, Lba1); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, Lba2); + + // + // Send command via Command Register + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand); + + // + // Stall at least 400ns + // + gBS->Stall (100); + + return EFI_SUCCESS; +} + +EFI_STATUS +AtaUdmaReadExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *DataBuffer, + IN EFI_LBA StartLba, + IN UINTN NumberOfBlocks + ) +/*++ + Name: + + AtaUdmaReadExt + + Purpose: + + This function is called by the AtaBlkIoReadBlocks() to perform + reading from media in block unit. The function has been enhanced to + support >120GB access and transfer at most 65536 blocks per command + + Parameters: + + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + VOID IN *DataBuffer + A pointer to the destination buffer for the data. + + EFI_LBA IN StartLba + The starting logical block address to read from + on the device media. + + UINTN IN NumberOfBlocks + The number of transfer data blocks. + + Returns: + + The device status of UDMA operation. If the operation is + successful, return EFI_SUCCESS. + +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: DataBuffer - add argument and description to function comment +// TODO: StartLba - add argument and description to function comment +// TODO: NumberOfBlocks - add argument and description to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +{ + IDE_DMA_PRD *PrdAddr; + IDE_DMA_PRD *UsedPrdAddr; + IDE_DMA_PRD *TempPrdAddr; + UINT8 RegisterValue; + UINT8 Device; + UINT64 IoPortForBmic; + UINT64 IoPortForBmis; + UINT64 IoPortForBmid; + EFI_STATUS Status; + UINTN PrdTableNum; + UINTN ByteCount; + UINTN ByteAvailable; + UINT8 *PrdBuffer; + UINTN RemainBlockNum; + UINT8 DeviceControl; + + // + // Channel and device differential. Select device. + // + Device = (UINT8) ((IdeDev->Device << 4) | 0xe0); + + // + // Enable interrupt to support UDMA and Select device + // + DeviceControl = 0; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl); + + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device); + + if (IdePrimary == IdeDev->Channel) { + IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICP_OFFSET; + IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET; + IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDP_OFFSET; + } else { + if (IdeSecondary == IdeDev->Channel) { + IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICS_OFFSET; + IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET; + IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDS_OFFSET; + } else { + return EFI_UNSUPPORTED; + } + } + + RemainBlockNum = NumberOfBlocks; + while (RemainBlockNum > 0) { + + if (RemainBlockNum >= MAX_DMA_EXT_COMMAND_SECTORS) { + // + // SectorCount is used to record the number of sectors to be read + // Max 65536 sectors can be transfered at a time. + // + NumberOfBlocks = MAX_DMA_EXT_COMMAND_SECTORS; + RemainBlockNum -= MAX_DMA_EXT_COMMAND_SECTORS; + } else { + NumberOfBlocks = (UINT16) RemainBlockNum; + RemainBlockNum = 0; + } + + // + // Calculate the number of PRD table to make sure the memory region + // not cross 64K boundary + // + ByteCount = NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize; + PrdTableNum = ((ByteCount >> 16) + 1) + 1; + + // + // Build PRD table + // + PrdAddr = (IDE_DMA_PRD *) AllocateZeroPool ((2 * PrdTableNum * sizeof (IDE_DMA_PRD))); + + // + // To make sure PRD is allocated in one 64K page + // + if (((UINTN) PrdAddr & 0x0FFFF) > (((UINTN) PrdAddr + PrdTableNum * sizeof (IDE_DMA_PRD) - 1) & 0x0FFFF)) { + UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x10000) & 0xFFFF0000); + } else { + if ((UINTN) PrdAddr & 0x03) { + UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x04) & 0xFFFFFFFC); + } else { + UsedPrdAddr = PrdAddr; + } + } + + // + // Build the PRD table + // + PrdBuffer = DataBuffer; + TempPrdAddr = UsedPrdAddr; + while (TRUE) { + + ByteAvailable = 0x10000 - ((UINTN) PrdBuffer & 0xFFFF); + + if (ByteCount <= ByteAvailable) { + TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer); + TempPrdAddr->ByteCount = (UINT16) ByteCount; + TempPrdAddr->EndOfTable = 0x8000; + break; + } + + TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer); + TempPrdAddr->ByteCount = (UINT16) ByteAvailable; + + ByteCount -= ByteAvailable; + PrdBuffer += ByteAvailable; + TempPrdAddr++; + } + + // + // Set the base address to BMID register + // + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint32, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmid, + 1, + &UsedPrdAddr + ); + + // + // Set BMIC register to identify the operation direction + // + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + RegisterValue |= BMIC_nREAD; + + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + // + // Read BMIS register and clear ERROR and INTR bit + // + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmis, + 1, + &RegisterValue + ); + + RegisterValue |= BMIS_INTERRUPT | BMIS_ERROR; + + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmis, + 1, + &RegisterValue + ); + + // + // Issue READ DMA EXT command + // + Status = AtaCommandIssueExt ( + IdeDev, + READ_DMA_EXT_CMD, + Device, + 0, + (UINT16) NumberOfBlocks, + StartLba + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (PrdAddr); + return EFI_DEVICE_ERROR; + } + + // + // Set START bit of BMIC register + // + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + RegisterValue |= BMIC_START; + + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + // + // Check the INTERRUPT and ERROR bit of BMIS + // + while (TRUE) { + + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmis, + 1, + &RegisterValue + ); + if (RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) { + if (RegisterValue & BMIS_ERROR) { + gBS->FreePool (PrdAddr); + return EFI_DEVICE_ERROR; + } + break; + } + + gBS->Stall (1000); + } + + gBS->FreePool (PrdAddr); + + // + // Set START bit of BMIC register + // + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + RegisterValue &= ~((UINT8) BMIC_START); + + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + if (RegisterValue & BMIS_ERROR) { + return EFI_DEVICE_ERROR; + } + + DataBuffer = (UINT8 *) DataBuffer + NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize; + StartLba += NumberOfBlocks; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +AtaUdmaRead ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *DataBuffer, + IN EFI_LBA StartLba, + IN UINTN NumberOfBlocks + ) +/*++ + Name: + + AtaUdmaRead + + Purpose: + + This function is called by the AtaBlkIoReadBlocks() to perform + reading from media in block unit. The function has been enhanced to + support >120GB access and transfer at most 65536 blocks per command + + Parameters: + + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + VOID IN *DataBuffer + A pointer to the destination buffer for the data. + + EFI_LBA IN StartLba + The starting logical block address to read from + on the device media. + + UINTN IN NumberOfBlocks + The number of transfer data blocks. + + Returns: + + The device status of UDMA operation. If the operation is + successful, return EFI_SUCCESS. + +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: DataBuffer - add argument and description to function comment +// TODO: StartLba - add argument and description to function comment +// TODO: NumberOfBlocks - add argument and description to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +{ + IDE_DMA_PRD *PrdAddr; + IDE_DMA_PRD *UsedPrdAddr; + IDE_DMA_PRD *TempPrdAddr; + UINT8 RegisterValue; + UINT8 Device; + UINT64 IoPortForBmic; + UINT64 IoPortForBmis; + UINT64 IoPortForBmid; + EFI_STATUS Status; + UINTN PrdTableNum; + UINTN ByteCount; + UINTN ByteAvailable; + UINT8 *PrdBuffer; + UINTN RemainBlockNum; + UINT8 DeviceControl; + + // + // Channel and device differential + // + Device = (UINT8) ((IdeDev->Device << 4) | 0xe0); + + // + // Enable interrupt to support UDMA and Select device + // + DeviceControl = 0; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl); + + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device); + + if (IdePrimary == IdeDev->Channel) { + IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICP_OFFSET; + IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET; + IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDP_OFFSET; + } else { + if (IdeSecondary == IdeDev->Channel) { + IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICS_OFFSET; + IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET; + IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDS_OFFSET; + } else { + return EFI_UNSUPPORTED; + } + } + + RemainBlockNum = NumberOfBlocks; + while (RemainBlockNum > 0) { + + if (RemainBlockNum >= MAX_DMA_COMMAND_SECTORS) { + // + // SectorCount is used to record the number of sectors to be read + // Max 256 sectors can be transfered at a time. + // + NumberOfBlocks = MAX_DMA_COMMAND_SECTORS; + RemainBlockNum -= MAX_DMA_COMMAND_SECTORS; + } else { + NumberOfBlocks = (UINT16) RemainBlockNum; + RemainBlockNum = 0; + } + + // + // Calculate the number of PRD table to make sure the memory region + // not cross 64K boundary + // + ByteCount = NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize; + PrdTableNum = ((ByteCount >> 16) + 1) + 1; + + // + // Build PRD table + // + PrdAddr = (IDE_DMA_PRD *) AllocateZeroPool ((2 * PrdTableNum * sizeof (IDE_DMA_PRD))); + // + // To make sure PRD is allocated in one 64K page + // + if (((UINTN) PrdAddr & 0x0FFFF) > (((UINTN) PrdAddr + PrdTableNum * sizeof (IDE_DMA_PRD) - 1) & 0x0FFFF)) { + UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x10000) & 0xFFFF0000); + } else { + if ((UINTN) PrdAddr & 0x03) { + UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x04) & 0xFFFFFFFC); + } else { + UsedPrdAddr = PrdAddr; + } + } + + // + // Build the PRD table + // + PrdBuffer = DataBuffer; + TempPrdAddr = UsedPrdAddr; + while (TRUE) { + + ByteAvailable = 0x10000 - ((UINTN) PrdBuffer & 0xFFFF); + + if (ByteCount <= ByteAvailable) { + TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer); + TempPrdAddr->ByteCount = (UINT16) ByteCount; + TempPrdAddr->EndOfTable = 0x8000; + break; + } + + TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer); + TempPrdAddr->ByteCount = (UINT16) ByteAvailable; + + ByteCount -= ByteAvailable; + PrdBuffer += ByteAvailable; + TempPrdAddr++; + } + + // + // Set the base address to BMID register + // + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint32, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmid, + 1, + &UsedPrdAddr + ); + + // + // Set BMIC register to identify the operation direction + // + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + RegisterValue |= BMIC_nREAD; + + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + // + // Read BMIS register and clear ERROR and INTR bit + // + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmis, + 1, + &RegisterValue + ); + + RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR); + + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmis, + 1, + &RegisterValue + ); + + // + // Issue READ DMA command + // + Status = AtaCommandIssue ( + IdeDev, + READ_DMA_CMD, + Device, + 0, + (UINT16) NumberOfBlocks, + StartLba + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (PrdAddr); + return EFI_DEVICE_ERROR; + } + + // + // Set START bit of BMIC register + // + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + RegisterValue |= BMIC_START; + + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + // + // Check the INTERRUPT and ERROR bit of BMIS + // + while (TRUE) { + + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmis, + 1, + &RegisterValue + ); + if (RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) { + if (RegisterValue & BMIS_ERROR) { + gBS->FreePool (PrdAddr); + return EFI_DEVICE_ERROR; + } + break; + } + + gBS->Stall (1000); + } + + gBS->FreePool (PrdAddr); + + // + // Set START bit of BMIC register + // + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + RegisterValue &= ~((UINT8) BMIC_START); + + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + if (RegisterValue & BMIS_ERROR) { + return EFI_DEVICE_ERROR; + } + + DataBuffer = (UINT8 *) DataBuffer + NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize; + StartLba += NumberOfBlocks; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +AtaUdmaWriteExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *DataBuffer, + IN EFI_LBA StartLba, + IN UINTN NumberOfBlocks + ) +/*++ + Name: + + AtaUdmaWriteExt + + Purpose: + + This function is called by the AtaBlkIoWriteBlocks() to perform + writing to media in block unit. The function has been enhanced to + support >120GB access and transfer at most 65536 blocks per command + + Parameters: + + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + VOID IN *DataBuffer + A pointer to the source buffer for the data. + + EFI_LBA IN StartLba + The starting logical block address to write to + on the device media. + + UINTN IN NumberOfBlocks + The number of transfer data blocks. + + Returns: + + The device status of UDMA operation. If the operation is + successful, return EFI_SUCCESS. + +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: DataBuffer - add argument and description to function comment +// TODO: StartLba - add argument and description to function comment +// TODO: NumberOfBlocks - add argument and description to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +{ + IDE_DMA_PRD *PrdAddr; + IDE_DMA_PRD *UsedPrdAddr; + IDE_DMA_PRD *TempPrdAddr; + UINT8 RegisterValue; + UINT8 Device; + UINT64 IoPortForBmic; + UINT64 IoPortForBmis; + UINT64 IoPortForBmid; + EFI_STATUS Status; + UINTN PrdTableNum; + UINTN ByteCount; + UINTN ByteAvailable; + UINT8 *PrdBuffer; + UINTN RemainBlockNum; + UINT8 DeviceControl; + + // + // Channel and device differential + // + Device = (UINT8) ((IdeDev->Device << 4) | 0xe0); + + // + // Enable interrupt to support UDMA and Select device + // + DeviceControl = 0; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl); + + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device); + + if (IdePrimary == IdeDev->Channel) { + IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICP_OFFSET; + IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET; + IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDP_OFFSET; + } else { + if (IdeSecondary == IdeDev->Channel) { + IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICS_OFFSET; + IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET; + IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDS_OFFSET; + } else { + return EFI_UNSUPPORTED; + } + } + + RemainBlockNum = NumberOfBlocks; + while (RemainBlockNum > 0) { + + if (RemainBlockNum >= MAX_DMA_EXT_COMMAND_SECTORS) { + // + // SectorCount is used to record the number of sectors to be read + // Max 65536 sectors can be transfered at a time. + // + NumberOfBlocks = MAX_DMA_EXT_COMMAND_SECTORS; + RemainBlockNum -= MAX_DMA_EXT_COMMAND_SECTORS; + } else { + NumberOfBlocks = (UINT16) RemainBlockNum; + RemainBlockNum = 0; + } + + // + // Calculate the number of PRD table to make sure the memory region + // not cross 64K boundary + // + ByteCount = NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize; + PrdTableNum = ((ByteCount >> 16) + 1) + 1; + + // + // Build PRD table + // + PrdAddr = (IDE_DMA_PRD *) AllocateZeroPool ((2 * PrdTableNum * sizeof (IDE_DMA_PRD))); + // + // To make sure PRD is allocated in one 64K page + // + if (((UINTN) PrdAddr & 0x0FFFF) > (((UINTN) PrdAddr + PrdTableNum * sizeof (IDE_DMA_PRD) - 1) & 0x0FFFF)) { + UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x10000) & 0xFFFF0000); + } else { + if ((UINTN) PrdAddr & 0x03) { + UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x04) & 0xFFFFFFFC); + } else { + UsedPrdAddr = PrdAddr; + } + } + + // + // Build the PRD table + // + PrdBuffer = DataBuffer; + TempPrdAddr = UsedPrdAddr; + while (TRUE) { + + ByteAvailable = 0x10000 - ((UINTN) PrdBuffer & 0xFFFF); + + if (ByteCount <= ByteAvailable) { + TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer); + TempPrdAddr->ByteCount = (UINT16) ByteCount; + TempPrdAddr->EndOfTable = 0x8000; + break; + } + + TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer); + TempPrdAddr->ByteCount = (UINT16) ByteAvailable; + + ByteCount -= ByteAvailable; + PrdBuffer += ByteAvailable; + TempPrdAddr++; + } + + // + // Set the base address to BMID register + // + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint32, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmid, + 1, + &UsedPrdAddr + ); + + // + // Set BMIC register to identify the operation direction + // + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + // + // 0000 1000 + // + RegisterValue &= ~((UINT8) BMIC_nREAD); + + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + // + // Read BMIS register and clear ERROR and INTR bit + // + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmis, + 1, + &RegisterValue + ); + + RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR); + + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmis, + 1, + &RegisterValue + ); + + // + // Issue WRITE DMA EXT command + // + Status = AtaCommandIssueExt ( + IdeDev, + WRITE_DMA_EXT_CMD, + Device, + 0, + (UINT16) NumberOfBlocks, + StartLba + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (PrdAddr); + return EFI_DEVICE_ERROR; + } + + // + // Set START bit of BMIC register + // + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + RegisterValue |= BMIC_START; + + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + // + // Check the INTERRUPT and ERROR bit of BMIS + // + while (TRUE) { + + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmis, + 1, + &RegisterValue + ); + if (RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) { + if (RegisterValue & BMIS_ERROR) { + gBS->FreePool (PrdAddr); + return EFI_DEVICE_ERROR; + } + break; + } + + gBS->Stall (1000); + } + + gBS->FreePool (PrdAddr); + + // + // Set START bit of BMIC register + // + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + RegisterValue &= ~((UINT8) BMIC_START); + + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + DataBuffer = (UINT8 *) DataBuffer + NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize; + StartLba += NumberOfBlocks; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +AtaUdmaWrite ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *DataBuffer, + IN EFI_LBA StartLba, + IN UINTN NumberOfBlocks + ) +/*++ + Name: + + AtaUdmaWrite + + Purpose: + + This function is called by the AtaBlkIoWriteBlocks() to perform + writing to media in block unit. The function has been enhanced to + support >120GB access and transfer at most 65536 blocks per command + + Parameters: + + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + VOID IN *DataBuffer + A pointer to the source buffer for the data. + + EFI_LBA IN StartLba + The starting logical block address to write to + on the device media. + + UINTN IN NumberOfBlocks + The number of transfer data blocks. + + Returns: + + The device status of UDMA operation. If the operation is + successful, return EFI_SUCCESS. + +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: DataBuffer - add argument and description to function comment +// TODO: StartLba - add argument and description to function comment +// TODO: NumberOfBlocks - add argument and description to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +{ + IDE_DMA_PRD *PrdAddr; + IDE_DMA_PRD *UsedPrdAddr; + IDE_DMA_PRD *TempPrdAddr; + UINT8 RegisterValue; + UINT8 Device; + UINT64 IoPortForBmic; + UINT64 IoPortForBmis; + UINT64 IoPortForBmid; + EFI_STATUS Status; + UINTN PrdTableNum; + UINTN ByteCount; + UINTN ByteAvailable; + UINT8 *PrdBuffer; + UINTN RemainBlockNum; + UINT8 DeviceControl; + + // + // Channel and device differential + // + Device = (UINT8) ((IdeDev->Device << 4) | 0xe0); + + // + // Enable interrupt to support UDMA + // + DeviceControl = 0; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl); + + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device); + + if (IdePrimary == IdeDev->Channel) { + IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICP_OFFSET; + IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET; + IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDP_OFFSET; + } else { + if (IdeSecondary == IdeDev->Channel) { + IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICS_OFFSET; + IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET; + IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDS_OFFSET; + } else { + return EFI_UNSUPPORTED; + } + } + + RemainBlockNum = NumberOfBlocks; + while (RemainBlockNum > 0) { + + if (RemainBlockNum >= MAX_DMA_COMMAND_SECTORS) { + // + // SectorCount is used to record the number of sectors to be read + // Max 256 sectors can be transfered at a time. + // + NumberOfBlocks = MAX_DMA_COMMAND_SECTORS; + RemainBlockNum -= MAX_DMA_COMMAND_SECTORS; + } else { + NumberOfBlocks = (UINT16) RemainBlockNum; + RemainBlockNum = 0; + } + + // + // Calculate the number of PRD table to make sure the memory region + // not cross 64K boundary + // + ByteCount = NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize; + PrdTableNum = ((ByteCount >> 16) + 1) + 1; + + // + // Build PRD table + // + PrdAddr = (IDE_DMA_PRD *) AllocateZeroPool ((2 * PrdTableNum * sizeof (IDE_DMA_PRD))); + + // + // To make sure PRD is allocated in one 64K page + // + if (((UINTN) PrdAddr & 0x0FFFF) > (((UINTN) PrdAddr + PrdTableNum * sizeof (IDE_DMA_PRD) - 1) & 0x0FFFF)) { + UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x10000) & 0xFFFF0000); + } else { + if ((UINTN) PrdAddr & 0x03) { + UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x04) & 0xFFFFFFFC); + } else { + UsedPrdAddr = PrdAddr; + } + } + + // + // Build the PRD table + // + PrdBuffer = DataBuffer; + TempPrdAddr = UsedPrdAddr; + while (TRUE) { + + ByteAvailable = 0x10000 - ((UINTN) PrdBuffer & 0xFFFF); + + if (ByteCount <= ByteAvailable) { + TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer); + TempPrdAddr->ByteCount = (UINT16) ByteCount; + TempPrdAddr->EndOfTable = 0x8000; + break; + } + + TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer); + TempPrdAddr->ByteCount = (UINT16) ByteAvailable; + + ByteCount -= ByteAvailable; + PrdBuffer += ByteAvailable; + TempPrdAddr++; + } + + // + // Set the base address to BMID register + // + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint32, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmid, + 1, + &UsedPrdAddr + ); + + // + // Set BMIC register to identify the operation direction + // + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + // + // 0000 1000 + // + RegisterValue &= ~((UINT8) BMIC_nREAD); + + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + // + // Read BMIS register and clear ERROR and INTR bit + // + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmis, + 1, + &RegisterValue + ); + + RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR); + + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmis, + 1, + &RegisterValue + ); + + // + // Issue WRITE DMA command + // + Status = AtaCommandIssue ( + IdeDev, + WRITE_DMA_CMD, + Device, + 0, + (UINT16) NumberOfBlocks, + StartLba + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (PrdAddr); + return EFI_DEVICE_ERROR; + } + + // + // Set START bit of BMIC register + // + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + RegisterValue |= BMIC_START; + + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + // + // Check the INTERRUPT and ERROR bit of BMIS + // + while (TRUE) { + + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmis, + 1, + &RegisterValue + ); + if (RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) { + if (RegisterValue & BMIS_ERROR) { + gBS->FreePool (PrdAddr); + return EFI_DEVICE_ERROR; + } + break; + } + + gBS->Stall (1000); + } + + gBS->FreePool (PrdAddr); + + // + // Set START bit of BMIC register + // + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + RegisterValue &= ~((UINT8) BMIC_START); + + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + DataBuffer = (UINT8 *) DataBuffer + NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize; + StartLba += NumberOfBlocks; + } + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/atapi.c b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/atapi.c new file mode 100644 index 0000000000..fa004e3d7f --- /dev/null +++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/atapi.c @@ -0,0 +1,2591 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + atapi.c + +Abstract: + + +Revision History +--*/ + +#include "idebus.h" + +STATIC +EFI_STATUS +LS120GetMediaStatus ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + Name: + LS120GetMediaStatus + + Purpose: + This function is used to get the current status of the media residing + in the LS-120 drive or ZIP drive. The media status is returned in the + Error Status. + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + Returns: + EFI_SUCCESS + The media status is achieved successfully and the media + can be read/written. + + EFI_DEVICE_ERROR + Get Media Status Command is failed. + + EFI_NO_MEDIA + There is no media in the drive. + + EFI_WRITE_PROTECTED + The media is writing protected. + + Notes: + This function must be called after the LS120EnableMediaStatus() + with second parameter set to TRUE + (means enable media status notification) is called. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +{ + UINT8 DeviceSelect; + UINT8 StatusValue; + EFI_STATUS EfiStatus; + // + // Poll Alternate Register for BSY clear within timeout. + // + EfiStatus = WaitForBSYClear2 (IdeDev, ATATIMEOUT); + if (EFI_ERROR (EfiStatus)) { + return EFI_DEVICE_ERROR; + } + + // + // Select device via Device/Head Register. + // + DeviceSelect = (UINT8) ((IdeDev->Device) << 4 | 0xe0); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect); + + // + // Poll Alternate Register for DRDY set within timeout. + // After device is selected, DRDY set indicates the device is ready to + // accept command. + // + EfiStatus = DRDYReady2 (IdeDev, ATATIMEOUT); + if (EFI_ERROR (EfiStatus)) { + return EFI_DEVICE_ERROR; + } + + // + // Get Media Status Command is sent + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0xDA); + + // + // BSY bit will clear after command is complete. + // + EfiStatus = WaitForBSYClear2 (IdeDev, ATATIMEOUT); + if (EFI_ERROR (EfiStatus)) { + return EFI_DEVICE_ERROR; + } + + // + // the media status is returned by the command in the ERROR register + // + StatusValue = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error); + + if (StatusValue & bit1) { + return EFI_NO_MEDIA; + } + + if (StatusValue & bit6) { + return EFI_WRITE_PROTECTED; + } else { + return EFI_SUCCESS; + } +} + +STATIC +EFI_STATUS +LS120EnableMediaStatus ( + IN IDE_BLK_IO_DEV *IdeDev, + IN BOOLEAN Enable + ) +/*++ + Name: + LS120EnableMediaStatus + + Purpose: + This function is used to send Enable Media Status Notification Command + or Disable Media Status Notification Command. + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + BOOLEAN IN Enable + a flag that indicates whether enable or disable media + status notification. + + Returns: + EFI_SUCCESS + If command completes successfully. + + EFI_DEVICE_ERROR + If command failed. + + + Notes: +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: Enable - add argument and description to function comment +{ + UINT8 DeviceSelect; + EFI_STATUS Status; + + // + // Poll Alternate Register for BSY clear within timeout. + // + Status = WaitForBSYClear2 (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Select device via Device/Head Register. + // + DeviceSelect = (UINT8) ((IdeDev->Device) << 4 | 0xe0); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect); + + // + // Poll Alternate Register for DRDY set within timeout. + // After device is selected, DRDY set indicates the device is ready to + // accept command. + // + Status = DRDYReady2 (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + if (Enable) { + // + // 0x95: Enable media status notification + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x95); + } else { + // + // 0x31: Disable media status notification + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x31); + } + // + // Set Feature Command is sent + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0xEF); + + // + // BSY bit will clear after command is complete. + // + Status = WaitForBSYClear (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +ATAPIIdentify ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + Name: + ATAPIIdentify + + + Purpose: + 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 + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + Returns: + EFI_SUCCESS + Identify ATAPI device successfully. + + EFI_DEVICE_ERROR + ATAPI Identify Device Command failed or device type + is not supported by this IDE driver. + + Notes: + Parameter "IdeDev" will be updated in this function. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +{ + EFI_IDENTIFY_DATA *AtapiIdentifyPointer; + UINT8 DeviceSelect; + EFI_STATUS Status; + + // + // device select bit + // + DeviceSelect = 0; + DeviceSelect = (UINT8) ((IdeDev->Device) << 4); + + AtapiIdentifyPointer = AllocatePool (sizeof (EFI_IDENTIFY_DATA)); + if (AtapiIdentifyPointer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Send ATAPI Identify Command to get IDENTIFY data. + // + Status = AtaPioDataIn ( + IdeDev, + (VOID *) AtapiIdentifyPointer, + sizeof (EFI_IDENTIFY_DATA), + ATAPI_IDENTIFY_DEVICE_CMD, + DeviceSelect, + 0, + 0, + 0, + 0 + ); + + if (EFI_ERROR (Status)) { + gBS->FreePool (AtapiIdentifyPointer); + return EFI_DEVICE_ERROR; + } + + IdeDev->pIdData = AtapiIdentifyPointer; + PrintAtaModuleName (IdeDev); + + // + // Send ATAPI Inquiry Packet Command to get INQUIRY data. + // + Status = AtapiInquiry (IdeDev); + if (EFI_ERROR (Status)) { + gBS->FreePool (IdeDev->pIdData); + // + // Make sure the pIdData will not be freed again. + // + IdeDev->pIdData = NULL; + return EFI_DEVICE_ERROR; + } + // + // Get media removable info from INQUIRY data. + // + IdeDev->BlkIo.Media->RemovableMedia = (UINT8) ((IdeDev->pInquiryData->RMB & 0x80) == 0x80); + + // + // Identify device type via INQUIRY data. + // + switch (IdeDev->pInquiryData->peripheral_type & 0x1f) { + + // + // Magnetic Disk + // + case 0x00: + + // + // device is LS120 or ZIP drive. + // + IdeDev->Type = IdeMagnetic; + + IdeDev->BlkIo.Media->MediaId = 0; + // + // Give initial value + // + IdeDev->BlkIo.Media->MediaPresent = FALSE; + + IdeDev->BlkIo.Media->LastBlock = 0; + IdeDev->BlkIo.Media->BlockSize = 0x200; + break; + + // + // CD-ROM + // + case 0x05: + + IdeDev->Type = IdeCdRom; + IdeDev->BlkIo.Media->MediaId = 0; + // + // Give initial value + // + IdeDev->BlkIo.Media->MediaPresent = FALSE; + + IdeDev->BlkIo.Media->LastBlock = 0; + IdeDev->BlkIo.Media->BlockSize = 0x800; + IdeDev->BlkIo.Media->ReadOnly = TRUE; + break; + + // + // Tape + // + case 0x01: + + // + // WORM + // + case 0x04: + + // + // Optical + // + case 0x07: + + default: + IdeDev->Type = IdeUnknown; + gBS->FreePool (IdeDev->pIdData); + gBS->FreePool (IdeDev->pInquiryData); + // + // Make sure the pIdData and pInquiryData will not be freed again. + // + IdeDev->pIdData = NULL; + IdeDev->pInquiryData = NULL; + return EFI_DEVICE_ERROR; + } + + // + // original sense data numbers + // + IdeDev->SenseDataNumber = 20; + + IdeDev->SenseData = AllocatePool (IdeDev->SenseDataNumber * sizeof (REQUEST_SENSE_DATA)); + if (IdeDev->SenseData == NULL) { + gBS->FreePool (IdeDev->pIdData); + gBS->FreePool (IdeDev->pInquiryData); + // + // Make sure the pIdData and pInquiryData will not be freed again. + // + IdeDev->pIdData = NULL; + IdeDev->pInquiryData = NULL; + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +AtapiInquiry ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + Name: + AtapiInquiry + + Purpose: + Sends out ATAPI Inquiry Packet Command to the specified device. + This command will return INQUIRY data of the device. + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + Returns: + EFI_SUCCESS + Inquiry command completes successfully. + + EFI_DEVICE_ERROR + Inquiry command failed. + Notes: + Parameter "IdeDev" will be updated in this function. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +{ + ATAPI_PACKET_COMMAND Packet; + EFI_STATUS Status; + INQUIRY_DATA *InquiryData; + + // + // prepare command packet for the ATAPI Inquiry Packet Command. + // + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.Inquiry.opcode = INQUIRY; + Packet.Inquiry.page_code = 0; + Packet.Inquiry.allocation_length = sizeof (INQUIRY_DATA); + + InquiryData = AllocatePool (sizeof (INQUIRY_DATA)); + if (InquiryData == NULL) { + return EFI_DEVICE_ERROR; + } + + // + // Send command packet and get requested Inquiry data. + // + Status = AtapiPacketCommandIn ( + IdeDev, + &Packet, + (UINT16 *) InquiryData, + sizeof (INQUIRY_DATA), + ATAPITIMEOUT + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (InquiryData); + return EFI_DEVICE_ERROR; + } + + IdeDev->pInquiryData = InquiryData; + + return EFI_SUCCESS; +} + +EFI_STATUS +AtapiPacketCommandIn ( + IN IDE_BLK_IO_DEV *IdeDev, + IN ATAPI_PACKET_COMMAND *Packet, + IN UINT16 *Buffer, + IN UINT32 ByteCount, + IN UINTN TimeOut + ) +/*++ + Name: + AtapiPacketCommandIn + + Purpose: + This function is used to send out ATAPI commands conforms to the + Packet Command with PIO Data In Protocol. + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + ATAPI_PACKET_COMMAND IN *Packet + pointer pointing to ATAPI_PACKET_COMMAND data structure + which contains the contents of the command. + + UINT16 IN *Buffer + buffer contained data transferred from device to host. + + UINT32 IN ByteCount + data size in byte unit of the buffer. + + UINTN IN TimeOut + this parameter is used to specify the timeout + value for the PioReadWriteData() function. + + Returns: + EFI_SUCCESS + send out the ATAPI packet command successfully + and device sends data successfully. + + EFI_DEVICE_ERROR + the device failed to send data. + + Notes: +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: Packet - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +// TODO: ByteCount - add argument and description to function comment +// TODO: TimeOut - add argument and description to function comment +{ + UINT16 *CommandIndex; + EFI_STATUS Status; + UINT32 Count; + + // + // Set all the command parameters by fill related registers. + // Before write to all the following registers, BSY and DRQ must be 0. + // + Status = DRQClear2 (IdeDev, ATAPITIMEOUT); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Select device via Device/Head Register. + // + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + (UINT8) ((IdeDev->Device << 4) | DEFAULT_CMD) // DEFAULT_CMD: 0xa0 (1010,0000) + ); + + // + // No OVL; No DMA + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x00); + + // + // set the transfersize to MAX_ATAPI_BYTE_COUNT to let the device + // determine how many data should be transferred. + // + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->CylinderLsb, + (UINT8) (MAX_ATAPI_BYTE_COUNT & 0x00ff) + ); + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->CylinderMsb, + (UINT8) (MAX_ATAPI_BYTE_COUNT >> 8) + ); + + // + // DEFAULT_CTL:0x0a (0000,1010) + // Disable interrupt + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DEFAULT_CTL); + + // + // Send Packet command to inform device + // that the following data bytes are command packet. + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, PACKET_CMD); + + Status = DRQReady (IdeDev, ATAPITIMEOUT); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Send out command packet + // + CommandIndex = Packet->Data16; + for (Count = 0; Count < 6; Count++, CommandIndex++) { + + IDEWritePortW (IdeDev->PciIo, IdeDev->IoPort->Data, *CommandIndex); + gBS->Stall (10); + } + + // + // call PioReadWriteData() function to get + // requested transfer data form device. + // + return PioReadWriteData (IdeDev, Buffer, ByteCount, 1, TimeOut); +} + +EFI_STATUS +AtapiPacketCommandOut ( + IN IDE_BLK_IO_DEV *IdeDev, + IN ATAPI_PACKET_COMMAND *Packet, + IN UINT16 *Buffer, + IN UINT32 ByteCount, + IN UINTN TimeOut + ) +/*++ + Name: + AtapiPacketCommandOut + + Purpose: + This function is used to send out ATAPI commands conforms to the + Packet Command with PIO Data Out Protocol. + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + ATAPI_PACKET_COMMAND IN *Packet + pointer pointing to ATAPI_PACKET_COMMAND data structure + which contains the contents of the command. + + VOID IN *Buffer + buffer contained data transferred from host to device. + + UINT32 IN ByteCount + data size in byte unit of the buffer. + + UINTN IN TimeOut + this parameter is used to specify the timeout + value for the PioReadWriteData() function. + + Returns: + EFI_SUCCESS + send out the ATAPI packet command successfully + and device received data successfully. + + EFI_DEVICE_ERROR + the device failed to send data. + + Notes: + +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: Packet - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +// TODO: ByteCount - add argument and description to function comment +// TODO: TimeOut - add argument and description to function comment +{ + UINT16 *CommandIndex; + EFI_STATUS Status; + UINT32 Count; + + // + // set all the command parameters + // Before write to all the following registers, BSY and DRQ must be 0. + // + Status = DRQClear2 (IdeDev, ATAPITIMEOUT); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Select device via Device/Head Register. + // + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + (UINT8) ((IdeDev->Device << 4) | DEFAULT_CMD) // DEFAULT_CMD: 0xa0 (1010,0000) + ); + + // + // No OVL; No DMA + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x00); + + // + // set the transfersize to MAX_ATAPI_BYTE_COUNT to + // let the device determine how many data should be transferred. + // + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->CylinderLsb, + (UINT8) (MAX_ATAPI_BYTE_COUNT & 0x00ff) + ); + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->CylinderMsb, + (UINT8) (MAX_ATAPI_BYTE_COUNT >> 8) + ); + + // + // DEFAULT_CTL:0x0a (0000,1010) + // Disable interrupt + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DEFAULT_CTL); + + // + // Send Packet command to inform device + // that the following data bytes are command packet. + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, PACKET_CMD); + + Status = DRQReady2 (IdeDev, ATAPITIMEOUT); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Send out command packet + // + CommandIndex = Packet->Data16; + for (Count = 0; Count < 6; Count++, CommandIndex++) { + IDEWritePortW (IdeDev->PciIo, IdeDev->IoPort->Data, *CommandIndex); + gBS->Stall (10); + } + + // + // call PioReadWriteData() function to send requested transfer data to device. + // + return PioReadWriteData (IdeDev, Buffer, ByteCount, 0, TimeOut); +} + +EFI_STATUS +PioReadWriteData ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINT16 *Buffer, + IN UINT32 ByteCount, + IN BOOLEAN Read, + IN UINTN TimeOut + ) +/*++ + Name: + PioReadWriteData + + Purpose: + This function is called by either AtapiPacketCommandIn() or + AtapiPacketCommandOut(). It is used to transfer data between + host and device. The data direction is specified by the fourth + parameter. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + VOID IN *Buffer + buffer contained data transferred between host and device. + + UINT32 IN ByteCount + data size in byte unit of the buffer. + + BOOLEAN 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. + + UINTN IN TimeOut + timeout value for wait DRQ ready before each data + stream's transfer. + + Returns: + EFI_SUCCESS + data is transferred successfully. + + EFI_DEVICE_ERROR + the device failed to transfer data. + + Notes: + +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +// TODO: ByteCount - add argument and description to function comment +// TODO: Read - add argument and description to function comment +// TODO: TimeOut - add argument and description to function comment +{ + // + // required transfer data in word unit. + // + UINT32 RequiredWordCount; + + // + // actual transfer data in word unit. + // + UINT32 ActualWordCount; + UINT32 WordCount; + EFI_STATUS Status; + UINT16 *PtrBuffer; + + // + // containing status byte read from Status Register. + // + UINT8 StatusRegister; + + // + // No data transfer is premitted. + // + if (ByteCount == 0) { + return EFI_SUCCESS; + } + // + // for performance, we assert the ByteCount is an even number + // which is actually a resonable assumption + ASSERT((ByteCount%2) == 0); + + PtrBuffer = Buffer; + RequiredWordCount = ByteCount / 2; + // + // ActuralWordCount means the word count of data really transferred. + // + ActualWordCount = 0; + + while (ActualWordCount < RequiredWordCount) { + + // + // before each data transfer stream, the host should poll DRQ bit ready, + // to see whether indicates device is ready to transfer data. + // + Status = DRQReady2 (IdeDev, TimeOut); + if (EFI_ERROR (Status)) { + return CheckErrorStatus (IdeDev); + } + + // + // read Status Register will clear interrupt + // + StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status); + + // + // get current data transfer size from Cylinder Registers. + // + WordCount = + ( + (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb) << 8) | + IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb) + ) & 0xffff; + WordCount /= 2; + + WordCount = EFI_MIN (WordCount, (RequiredWordCount - ActualWordCount)); + + if (Read) { + IDEReadPortWMultiple ( + IdeDev->PciIo, + IdeDev->IoPort->Data, + WordCount, + PtrBuffer + ); + } else { + IDEWritePortWMultiple ( + IdeDev->PciIo, + IdeDev->IoPort->Data, + WordCount, + PtrBuffer + ); + } + + PtrBuffer += WordCount; + ActualWordCount += WordCount; + } + + // + // After data transfer is completed, normally, DRQ bit should clear. + // + Status = DRQClear2 (IdeDev, ATAPITIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // read status register to check whether error happens. + // + return CheckErrorStatus (IdeDev); +} + +EFI_STATUS +AtapiTestUnitReady ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + Name: + AtapiTestUnitReady + + Purpose: + Sends out ATAPI Test Unit Ready Packet Command to the specified device + to find out whether device is accessible. + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + Returns: + EFI_SUCCESS + device is accessible. + + EFI_DEVICE_ERROR + device is not accessible. + + Notes: + +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +{ + ATAPI_PACKET_COMMAND Packet; + EFI_STATUS Status; + + // + // fill command packet + // + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.TestUnitReady.opcode = TEST_UNIT_READY; + + // + // send command packet + // + Status = AtapiPacketCommandIn (IdeDev, &Packet, NULL, 0, ATAPITIMEOUT); + return Status; +} + +EFI_STATUS +AtapiRequestSense ( + IN IDE_BLK_IO_DEV *IdeDev, + OUT UINTN *SenseCounts + ) +/*++ + Name: + AtapiRequestSense + + Purpose: + Sends out ATAPI Request Sense Packet Command to the specified device. + This command will return all the current Sense data in the device. + This function will pack all the Sense data in one single buffer. + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + UINT16 OUT **SenseBuffers + allocated in this function, and freed by the calling function. + This buffer is used to accommodate all the sense data returned + by the device. + + UINTN OUT *BufUnit + record the unit size of the sense data block in the SenseBuffers, + + UINTN OUT *BufNumbers + record the number of units in the SenseBuffers. + + Returns: + EFI_SUCCESS + Request Sense command completes successfully. + + EFI_DEVICE_ERROR + Request Sense command failed. + + Notes: + +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: SenseCounts - add argument and description to function comment +{ + EFI_STATUS Status; + REQUEST_SENSE_DATA *Sense; + UINT16 *Ptr; + BOOLEAN FetchSenseData; + ATAPI_PACKET_COMMAND Packet; + + *SenseCounts = 0; + + ZeroMem (IdeDev->SenseData, sizeof (REQUEST_SENSE_DATA) * (IdeDev->SenseDataNumber)); + // + // fill command packet for Request Sense Packet Command + // + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.RequestSence.opcode = REQUEST_SENSE; + Packet.RequestSence.allocation_length = sizeof (REQUEST_SENSE_DATA); + + // + // initialize pointer + // + Ptr = (UINT16 *) IdeDev->SenseData; + // + // request sense data from device continuously until no sense data + // exists in the device. + // + for (FetchSenseData = TRUE; FetchSenseData;) { + + Sense = (REQUEST_SENSE_DATA *) Ptr; + + // + // send out Request Sense Packet Command and get one Sense data form device + // + Status = AtapiPacketCommandIn ( + IdeDev, + &Packet, + Ptr, + sizeof (REQUEST_SENSE_DATA), + ATAPITIMEOUT + ); + // + // failed to get Sense data + // + if (EFI_ERROR (Status)) { + if (*SenseCounts == 0) { + return EFI_DEVICE_ERROR; + } else { + return EFI_SUCCESS; + } + } + + (*SenseCounts)++; + // + // We limit MAX sense data count to 20 in order to avoid dead loop. Some + // incompatible ATAPI devices don't retrive NO_SENSE when there is no media. + // In this case, dead loop occurs if we don't have a gatekeeper. 20 is + // supposed to be large enough for any ATAPI device. + // + if ((Sense->sense_key != SK_NO_SENSE) && ((*SenseCounts) < 20)) { + // + // Ptr is word-based pointer + // + Ptr += sizeof (REQUEST_SENSE_DATA) / 2; + + } else { + // + // when no sense key, skip out the loop + // + FetchSenseData = FALSE; + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +AtapiReadCapacity ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + Name: + AtapiReadCapacity + + Purpose: + Sends out ATAPI Read Capacity Packet Command to the specified device. + This command will return the information regarding the capacity of the + media in the device. + + Current device status will impact device's response to the Read Capacity + Command. For example, if the device once reset, the Read Capacity + Command will fail. The Sense data record the current device status, so + if the Read Capacity Command failed, the Sense data must be requested + and be analyzed to determine if the Read Capacity Command should retry. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + Returns: + EFI_SUCCESS + Read Capacity Command finally completes successfully. + + EFI_DEVICE_ERROR + Read Capacity Command failed because of device error. + + Notes: + parameter "IdeDev" will be updated in this function. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: EFI_NOT_READY - add return value to function comment +{ + // + // status returned by Read Capacity Packet Command + // + EFI_STATUS Status; + ATAPI_PACKET_COMMAND Packet; + + // + // used for capacity data returned from ATAPI device + // + READ_CAPACITY_DATA Data; + READ_FORMAT_CAPACITY_DATA FormatData; + + ZeroMem (&Data, sizeof (Data)); + ZeroMem (&FormatData, sizeof (FormatData)); + + if (IdeDev->Type == IdeCdRom) { + + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.Inquiry.opcode = READ_CAPACITY; + Status = AtapiPacketCommandIn ( + IdeDev, + &Packet, + (UINT16 *) &Data, + sizeof (READ_CAPACITY_DATA), + ATAPITIMEOUT + ); + + } else { + // + // Type == IdeMagnetic + // + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.ReadFormatCapacity.opcode = READ_FORMAT_CAPACITY; + Packet.ReadFormatCapacity.allocation_length_lo = 12; + Status = AtapiPacketCommandIn ( + IdeDev, + &Packet, + (UINT16 *) &FormatData, + sizeof (READ_FORMAT_CAPACITY_DATA), + ATAPITIMEOUT + ); + } + + if (!EFI_ERROR (Status)) { + + if (IdeDev->Type == IdeCdRom) { + + IdeDev->BlkIo.Media->LastBlock = (Data.LastLba3 << 24) | + (Data.LastLba2 << 16) | + (Data.LastLba1 << 8) | + Data.LastLba0; + + if (IdeDev->BlkIo.Media->LastBlock != 0) { + + IdeDev->BlkIo.Media->BlockSize = (Data.BlockSize3 << 24) | + (Data.BlockSize2 << 16) | + (Data.BlockSize1 << 8) | + Data.BlockSize0; + + IdeDev->BlkIo.Media->MediaPresent = TRUE; + } else { + IdeDev->BlkIo.Media->MediaPresent = FALSE; + return EFI_DEVICE_ERROR; + } + + IdeDev->BlkIo.Media->ReadOnly = TRUE; + + // + // Because the user data portion in the sector of the Data CD supported + // is always 0x800 + // + IdeDev->BlkIo.Media->BlockSize = 0x800; + } + + if (IdeDev->Type == IdeMagnetic) { + + if (FormatData.DesCode == 3) { + IdeDev->BlkIo.Media->MediaPresent = FALSE; + IdeDev->BlkIo.Media->LastBlock = 0; + } else { + + IdeDev->BlkIo.Media->LastBlock = (FormatData.LastLba3 << 24) | + (FormatData.LastLba2 << 16) | + (FormatData.LastLba1 << 8) | + FormatData.LastLba0; + if (IdeDev->BlkIo.Media->LastBlock != 0) { + IdeDev->BlkIo.Media->LastBlock--; + + IdeDev->BlkIo.Media->BlockSize = (FormatData.BlockSize2 << 16) | + (FormatData.BlockSize1 << 8) | + FormatData.BlockSize0; + + IdeDev->BlkIo.Media->MediaPresent = TRUE; + } else { + IdeDev->BlkIo.Media->MediaPresent = FALSE; + // + // Return EFI_NOT_READY operation succeeds but returned capacity is 0 + // + return EFI_NOT_READY; + } + + IdeDev->BlkIo.Media->BlockSize = 0x200; + + } + } + + return EFI_SUCCESS; + + } else { + + return EFI_DEVICE_ERROR; + } +} + +EFI_STATUS +AtapiDetectMedia ( + IN IDE_BLK_IO_DEV *IdeDev, + OUT BOOLEAN *MediaChange + ) +/*++ + Name: + AtapiDetectMedia + + Purpose: + Used before read/write blocks from/to ATAPI device media. + Since ATAPI device media is removable, it is necessary to detect + whether media is present and get current present media's + information, and if media has been changed, Block I/O Protocol + need to be reinstalled. + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + BOOLEAN OUT *MediaChange + return value that indicates if the media of the device has been + changed. + + Returns: + EFI_SUCCESS + media found successfully. + + EFI_DEVICE_ERROR + any error encounters during media detection. + + EFI_NO_MEDIA + media not found. + + Notes: + parameter IdeDev may be updated in this function. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: MediaChange - add argument and description to function comment +{ + EFI_STATUS Status; + EFI_STATUS ReadCapacityStatus; + EFI_BLOCK_IO_MEDIA OldMediaInfo; + UINTN SenseCounts; + UINTN RetryIndex; + UINTN RetryTimes; + UINTN MaximumRetryTimes; + UINTN ReadyWaitFactor; + BOOLEAN NeedRetry; + // + // a flag used to determine whether need to perform Read Capacity command. + // + BOOLEAN NeedReadCapacity; + BOOLEAN WriteProtected; + + // + // init + // + CopyMem (&OldMediaInfo, IdeDev->BlkIo.Media, sizeof (OldMediaInfo)); + // OldMediaInfo = *(IdeDev->BlkIo.Media); + *MediaChange = FALSE; + ReadCapacityStatus = EFI_DEVICE_ERROR; + + // + // if there is no media, or media is not changed, + // the request sense command will detect faster than read capacity command. + // read capacity command can be bypassed, thus improve performance. + // + + // + // Test Unit Ready command is used to detect whether device is accessible, + // the device will produce corresponding Sense data. + // + for (RetryIndex = 0; RetryIndex < 2; RetryIndex++) { + + Status = AtapiTestUnitReady (IdeDev); + if (!EFI_ERROR (Status)) { + // + // skip the loop if test unit command succeeds. + // + break; + } + + Status = AtapiSoftReset (IdeDev); + + if (EFI_ERROR (Status)) { + AtaSoftReset (IdeDev); + } + } + + SenseCounts = 0; + NeedReadCapacity = TRUE; + + // + // at most retry 5 times + // + MaximumRetryTimes = 5; + RetryTimes = 1; + + for (RetryIndex = 0; + (RetryIndex < RetryTimes) && (RetryIndex < MaximumRetryTimes); + RetryIndex++) { + + Status = AtapiRequestSense (IdeDev, &SenseCounts); + + if (!EFI_ERROR (Status)) { + // + // if first time there is no Sense Key, no need to read capacity any more + // + if (!HaveSenseKey (IdeDev->SenseData, SenseCounts) && + (IdeDev->BlkIo.Media->MediaPresent)) { + + if (RetryIndex == 0) { + NeedReadCapacity = FALSE; + } + + } else { + // + // No Media + // + if (IsNoMedia (IdeDev->SenseData, SenseCounts)) { + NeedReadCapacity = FALSE; + IdeDev->BlkIo.Media->MediaPresent = FALSE; + IdeDev->BlkIo.Media->LastBlock = 0; + } else { + // + // Media Changed + // + if (IsMediaChange (IdeDev->SenseData, SenseCounts)) { + NeedReadCapacity = TRUE; + IdeDev->BlkIo.Media->MediaId++; + } + // + // Media Error + // + if (IsMediaError (IdeDev->SenseData, SenseCounts)) { + return EFI_DEVICE_ERROR; + } + } + } + } else { + // + // retry once more, if request sense command met errors. + // + RetryTimes++; + } + } + + if (NeedReadCapacity) { + // + // at most retry 5 times + // + MaximumRetryTimes = 5; + // + // initial retry twice + // + RetryTimes = 2; + ReadyWaitFactor = 2; + + for (RetryIndex = 0; + (RetryIndex < RetryTimes) && (RetryIndex < MaximumRetryTimes); + RetryIndex++) { + + ReadCapacityStatus = AtapiReadCapacity (IdeDev); + + SenseCounts = 0; + + if (!EFI_ERROR (ReadCapacityStatus)) { + // + // Read Capacity succeeded + // + break; + + } else { + + if (ReadCapacityStatus == EFI_NOT_READY) { + // + // If device not ready, wait here... waiting time increases by retry + // times. + // + gBS->Stall (ReadyWaitFactor * 2000 * STALL_1_MILLI_SECOND); + ReadyWaitFactor++; + // + // retry once more + // + RetryTimes++; + continue; + } + + // + // Other errors returned, requery sense data + // + Status = AtapiRequestSense (IdeDev, &SenseCounts); + + // + // If Request Sense data failed, reset the device and retry. + // + if (EFI_ERROR (Status)) { + + Status = AtapiSoftReset (IdeDev); + + // + // if ATAPI soft reset fail, + // use stronger reset mechanism -- ATA soft reset. + // + if (EFI_ERROR (Status)) { + AtaSoftReset (IdeDev); + } + // + // retry once more + // + RetryTimes++; + continue; + } + + // + // No Media + // + if (IsNoMedia (IdeDev->SenseData, SenseCounts)) { + + IdeDev->BlkIo.Media->MediaPresent = FALSE; + IdeDev->BlkIo.Media->LastBlock = 0; + return EFI_NO_MEDIA; + } + + if (IsMediaError (IdeDev->SenseData, SenseCounts)) { + return EFI_DEVICE_ERROR; + } + + // + // Media Changed + // + if (IsMediaChange (IdeDev->SenseData, SenseCounts)) { + IdeDev->BlkIo.Media->MediaId++; + } + + if (!IsDriveReady (IdeDev->SenseData, SenseCounts, &NeedRetry)) { + + // + // Drive not ready: if NeedRetry, then retry once more; + // else return error + // + if (NeedRetry) { + // + // Stall 1 second to wait for drive becoming ready + // + gBS->Stall (1000 * STALL_1_MILLI_SECOND); + // + // reset retry variable to zero, + // to make it retry for "drive in progress of becoming ready". + // + RetryIndex = 0; + continue; + } else { + AtapiSoftReset (IdeDev); + return EFI_DEVICE_ERROR; + } + } + // + // if read capacity fail not for above reasons, retry once more + // + RetryTimes++; + } + + } + + // + // tell whether the readcapacity process is successful or not in the end + // + if (EFI_ERROR (ReadCapacityStatus)) { + return EFI_DEVICE_ERROR; + } + } + + // + // the following code is to check the write-protected for LS120 media + // + if ((IdeDev->BlkIo.Media->MediaPresent) && (IdeDev->Type == IdeMagnetic)) { + + Status = IsLS120orZipWriteProtected (IdeDev, &WriteProtected); + if (!EFI_ERROR (Status)) { + + if (WriteProtected) { + + IdeDev->BlkIo.Media->ReadOnly = TRUE; + } else { + + IdeDev->BlkIo.Media->ReadOnly = FALSE; + } + + } + } + + if (IdeDev->BlkIo.Media->MediaId != OldMediaInfo.MediaId) { + // + // Media change information got from the device + // + *MediaChange = TRUE; + } + + if (IdeDev->BlkIo.Media->ReadOnly != OldMediaInfo.ReadOnly) { + *MediaChange = TRUE; + IdeDev->BlkIo.Media->MediaId += 1; + } + + if (IdeDev->BlkIo.Media->BlockSize != OldMediaInfo.BlockSize) { + *MediaChange = TRUE; + IdeDev->BlkIo.Media->MediaId += 1; + } + + if (IdeDev->BlkIo.Media->LastBlock != OldMediaInfo.LastBlock) { + *MediaChange = TRUE; + IdeDev->BlkIo.Media->MediaId += 1; + } + + if (IdeDev->BlkIo.Media->MediaPresent != OldMediaInfo.MediaPresent) { + if (IdeDev->BlkIo.Media->MediaPresent) { + // + // when change from no media to media present, reset the MediaId to 1. + // + IdeDev->BlkIo.Media->MediaId = 1; + } else { + // + // when no media, reset the MediaId to zero. + // + IdeDev->BlkIo.Media->MediaId = 0; + } + + *MediaChange = TRUE; + } + + // + // if any change on current existing media, + // the Block I/O protocol need to be reinstalled. + // + if (*MediaChange) { + gBS->ReinstallProtocolInterface ( + IdeDev->Handle, + &gEfiBlockIoProtocolGuid, + &IdeDev->BlkIo, + &IdeDev->BlkIo + ); + } + + return EFI_SUCCESS; + +} + +EFI_STATUS +AtapiReadSectors ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *Buffer, + IN EFI_LBA Lba, + IN UINTN NumberOfBlocks + ) +/*++ + Name: + AtapiReadSectors + + Purpose: + This function is called by the AtapiBlkIoReadBlocks() to perform + read from media in block unit. + + The main command used to access media here is READ(10) Command. + READ(10) Command requests that the ATAPI device media transfer + specified data to the host. Data is transferred in block(sector) + unit. The maximum number of blocks that can be transferred once is + 65536. This is the main difference between READ(10) and READ(12) + Command. The maximum number of blocks in READ(12) is 2 power 32. + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + VOID IN *Buffer + A pointer to the destination buffer for the data. + + EFI_LBA IN Lba + The starting logical block address to read from + on the device media. + + UINTN IN NumberOfBlocks + The number of transfer data blocks. + + Returns: + return status is fully dependent on the return status + of AtapiPacketCommandIn() function. + + Notes: + +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +// TODO: Lba - add argument and description to function comment +// TODO: NumberOfBlocks - add argument and description to function comment +{ + + ATAPI_PACKET_COMMAND Packet; + READ10_CMD *Read10Packet; + EFI_STATUS Status; + UINTN BlocksRemaining; + UINT32 Lba32; + UINT32 BlockSize; + UINT32 ByteCount; + UINT16 SectorCount; + VOID *PtrBuffer; + UINT16 MaxBlock; + UINTN TimeOut; + + // + // fill command packet for Read(10) command + // + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Read10Packet = &Packet.Read10; + Lba32 = (UINT32) Lba; + PtrBuffer = Buffer; + + BlockSize = IdeDev->BlkIo.Media->BlockSize; + + // + // limit the data bytes that can be transferred by one Read(10) Command + // + MaxBlock = (UINT16) (65536 / BlockSize); + + BlocksRemaining = NumberOfBlocks; + + Status = EFI_SUCCESS; + while (BlocksRemaining > 0) { + + if (BlocksRemaining <= MaxBlock) { + + SectorCount = (UINT16) BlocksRemaining; + } else { + + SectorCount = MaxBlock; + } + + // + // fill the Packet data structure + // + + Read10Packet->opcode = READ_10; + + // + // Lba0 ~ Lba3 specify the start logical block address of the data transfer. + // Lba0 is MSB, Lba3 is LSB + // + Read10Packet->Lba3 = (UINT8) (Lba32 & 0xff); + Read10Packet->Lba2 = (UINT8) (Lba32 >> 8); + Read10Packet->Lba1 = (UINT8) (Lba32 >> 16); + Read10Packet->Lba0 = (UINT8) (Lba32 >> 24); + + // + // TranLen0 ~ TranLen1 specify the transfer length in block unit. + // TranLen0 is MSB, TranLen is LSB + // + Read10Packet->TranLen1 = (UINT8) (SectorCount & 0xff); + Read10Packet->TranLen0 = (UINT8) (SectorCount >> 8); + + ByteCount = SectorCount * BlockSize; + + if (IdeDev->Type == IdeCdRom) { + TimeOut = CDROMLONGTIMEOUT; + } else { + TimeOut = ATAPILONGTIMEOUT; + } + + Status = AtapiPacketCommandIn ( + IdeDev, + &Packet, + (UINT16 *) PtrBuffer, + ByteCount, + TimeOut + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Lba32 += SectorCount; + PtrBuffer = (UINT8 *) PtrBuffer + SectorCount * BlockSize; + BlocksRemaining -= SectorCount; + } + + return Status; +} + +EFI_STATUS +AtapiWriteSectors ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *Buffer, + IN EFI_LBA Lba, + IN UINTN NumberOfBlocks + ) +/*++ + Name: + AtapiWriteSectors + + Purpose: + This function is called by the AtapiBlkIoWriteBlocks() to perform + write onto media in block unit. + The main command used to access media here is Write(10) Command. + Write(10) Command requests that the ATAPI device media transfer + specified data to the host. Data is transferred in block (sector) + unit. The maximum number of blocks that can be transferred once is + 65536. + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + VOID IN *Buffer + A pointer to the source buffer for the data. + + EFI_LBA IN Lba + The starting logical block address to write onto + the device media. + + UINTN IN NumberOfBlocks + The number of transfer data blocks. + + Returns: + return status is fully dependent on the return status + of AtapiPacketCommandOut() function. + + Notes: + +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +// TODO: Lba - add argument and description to function comment +// TODO: NumberOfBlocks - add argument and description to function comment +{ + + ATAPI_PACKET_COMMAND Packet; + READ10_CMD *Read10Packet; + + EFI_STATUS Status; + UINTN BlocksRemaining; + UINT32 Lba32; + UINT32 BlockSize; + UINT32 ByteCount; + UINT16 SectorCount; + VOID *PtrBuffer; + UINT16 MaxBlock; + + // + // fill command packet for Write(10) command + // Write(10) command packet has the same data structure as + // Read(10) command packet, + // so here use the Read10Packet data structure + // for the Write(10) command packet. + // + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Read10Packet = &Packet.Read10; + + Lba32 = (UINT32) Lba; + PtrBuffer = Buffer; + + BlockSize = IdeDev->BlkIo.Media->BlockSize; + + // + // limit the data bytes that can be transferred by one Read(10) Command + // + MaxBlock = (UINT16) (65536 / BlockSize); + + BlocksRemaining = NumberOfBlocks; + + Status = EFI_SUCCESS; + while (BlocksRemaining > 0) { + + if (BlocksRemaining >= MaxBlock) { + SectorCount = MaxBlock; + } else { + SectorCount = (UINT16) BlocksRemaining; + } + + // + // Command code is WRITE_10. + // + Read10Packet->opcode = WRITE_10; + + // + // Lba0 ~ Lba3 specify the start logical block address of the data transfer. + // Lba0 is MSB, Lba3 is LSB + // + Read10Packet->Lba3 = (UINT8) (Lba32 & 0xff); + Read10Packet->Lba2 = (UINT8) (Lba32 >> 8); + Read10Packet->Lba1 = (UINT8) (Lba32 >> 16); + Read10Packet->Lba0 = (UINT8) (Lba32 >> 24); + + // + // TranLen0 ~ TranLen1 specify the transfer length in block unit. + // TranLen0 is MSB, TranLen is LSB + // + Read10Packet->TranLen1 = (UINT8) (SectorCount & 0xff); + Read10Packet->TranLen0 = (UINT8) (SectorCount >> 8); + + ByteCount = SectorCount * BlockSize; + + Status = AtapiPacketCommandOut ( + IdeDev, + &Packet, + (UINT16 *) PtrBuffer, + ByteCount, + ATAPILONGTIMEOUT + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Lba32 += SectorCount; + PtrBuffer = ((UINT8 *) PtrBuffer + SectorCount * BlockSize); + BlocksRemaining -= SectorCount; + } + + return Status; +} + +EFI_STATUS +AtapiSoftReset ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + Name: + AtapiSoftReset + + Purpose: + This function is used to implement the Soft Reset on the specified + ATAPI device. Different from the AtaSoftReset(), here reset is a ATA + Soft Reset Command special for ATAPI device, and it only take effects + on the specified ATAPI device, not on the whole IDE bus. + Since the ATAPI soft reset is needed when device is in exceptional + condition (such as BSY bit is always set ), I think the Soft Reset + command should be sent without waiting for the BSY clear and DRDY + set. + This function is called by IdeBlkIoReset(), + a interface function of Block I/O protocol. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + Returns: + EFI_SUCCESS + Soft reset completes successfully. + + EFI_DEVICE_ERROR + Any step during the reset process is failed. + + Notes: + +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +{ + UINT8 Command; + UINT8 DeviceSelect; + EFI_STATUS Status; + + // + // for ATAPI device, no need to wait DRDY ready after device selecting. + // (bit7 and bit5 are both set to 1 for backward compatibility) + // + DeviceSelect = (UINT8) (((bit7 | bit5) | (IdeDev->Device << 4))); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect); + + Command = ATAPI_SOFT_RESET_CMD; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, Command); + + // + // BSY cleared is the only status return to the host by the device + // when reset is completed. + // slave device needs at most 31s to clear BSY + // + Status = WaitForBSYClear (IdeDev, 31000); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // stall 5 seconds to make the device status stable + // + gBS->Stall (5000000); + + return EFI_SUCCESS; +} + +EFI_STATUS +AtapiBlkIoReadBlocks ( + IN IDE_BLK_IO_DEV *IdeBlkIoDevice, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +/*++ + Name: + AtapiBlkIoReadBlocks + + Purpose: + This function is the ATAPI implementation for ReadBlocks in the + Block I/O Protocol interface. + + Parameters: + IDE_BLK_IO_DEV IN *IdeBlkIoDev + Indicates the calling context. + + UINT32 IN MediaId + The media id that the read request is for. + + EFI_LBA IN LBA + The starting logical block address to read from + on the device. + + UINTN IN BufferSize + The size of the Buffer in bytes. This must be a + multiple of the intrinsic block size of the device. + + VOID OUT *Buffer + A pointer to the destination buffer for the data. + The caller is responsible for either having implicit + or explicit ownership of the memory that data is read into. + + Returns: + EFI_SUCCESS + Read Blocks successfully. + + EFI_DEVICE_ERROR + Read Blocks failed. + + EFI_NO_MEDIA + There is no media in the device. + + EFI_MEDIA_CHANGED + The MediaId is not for the current media. + + EFI_BAD_BUFFER_SIZE + The BufferSize parameter is not a multiple of the + intrinsic block size of the device. + + EFI_INVALID_PARAMETER + The read request contains LBAs that are not valid, + or the data buffer is not valid. + + Notes: + +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeBlkIoDevice - add argument and description to function comment +// TODO: MediaId - add argument and description to function comment +// TODO: LBA - add argument and description to function comment +// TODO: BufferSize - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +{ + EFI_BLOCK_IO_MEDIA *Media; + UINTN BlockSize; + UINTN NumberOfBlocks; + EFI_STATUS Status; + + BOOLEAN MediaChange; + + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (BufferSize == 0) { + return EFI_SUCCESS; + } + + // + // ATAPI device media is removable, so it is a must + // to detect media first before read operation + // + MediaChange = FALSE; + Status = AtapiDetectMedia (IdeBlkIoDevice, &MediaChange); + if (EFI_ERROR (Status)) { + + if (IdeBlkIoDevice->Cache != NULL) { + gBS->FreePool (IdeBlkIoDevice->Cache); + IdeBlkIoDevice->Cache = NULL; + } + + return Status; + } + // + // Get the intrinsic block size + // + Media = IdeBlkIoDevice->BlkIo.Media; + BlockSize = Media->BlockSize; + + NumberOfBlocks = BufferSize / BlockSize; + + if (!(Media->MediaPresent)) { + + if (IdeBlkIoDevice->Cache != NULL) { + gBS->FreePool (IdeBlkIoDevice->Cache); + IdeBlkIoDevice->Cache = NULL; + } + return EFI_NO_MEDIA; + + } + + if ((MediaId != Media->MediaId) || MediaChange) { + + if (IdeBlkIoDevice->Cache != NULL) { + gBS->FreePool (IdeBlkIoDevice->Cache); + IdeBlkIoDevice->Cache = NULL; + } + return EFI_MEDIA_CHANGED; + } + + if (BufferSize % BlockSize != 0) { + return EFI_BAD_BUFFER_SIZE; + } + + if (LBA > Media->LastBlock) { + return EFI_INVALID_PARAMETER; + } + + if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) { + return EFI_INVALID_PARAMETER; + } + + if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) { + return EFI_INVALID_PARAMETER; + } + + // + // if all the parameters are valid, then perform read sectors command + // to transfer data from device to host. + // + Status = AtapiReadSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Read blocks succeeded + // + + // + // save the first block to the cache for performance + // + if (LBA == 0 && !IdeBlkIoDevice->Cache) { + IdeBlkIoDevice->Cache = AllocatePool (BlockSize); + if (IdeBlkIoDevice != NULL) { + CopyMem ((UINT8 *) IdeBlkIoDevice->Cache, (UINT8 *) Buffer, BlockSize); + } + } + + return EFI_SUCCESS; + +} + +EFI_STATUS +AtapiBlkIoWriteBlocks ( + IN IDE_BLK_IO_DEV *IdeBlkIoDevice, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +/*++ + Name: + AtapiBlkIoWriteBlocks + + Purpose: + This function is the ATAPI implementation for WriteBlocks in the + Block I/O Protocol interface. + + Parameters: + EFI_BLOCK_IO IN *This + Indicates the calling context. + + UINT32 IN MediaId + The media id that the write request is for. + + EFI_LBA IN LBA + The starting logical block address to write onto + the device. + + UINTN IN BufferSize + The size of the Buffer in bytes. This must be a + multiple of the intrinsic block size of the device. + + VOID OUT *Buffer + A pointer to the source buffer for the data. + The caller is responsible for either having implicit + or explicit ownership of the memory that data is + written from. + + Returns: + EFI_SUCCESS + Write Blocks successfully. + + EFI_DEVICE_ERROR + Write Blocks failed. + + EFI_NO_MEDIA + There is no media in the device. + + EFI_MEDIA_CHANGE + The MediaId is not for the current media. + + EFI_BAD_BUFFER_SIZE + The BufferSize parameter is not a multiple of the + intrinsic block size of the device. + + EFI_INVALID_PARAMETER + The write request contains LBAs that are not valid, + or the data buffer is not valid. + + Notes: + +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeBlkIoDevice - add argument and description to function comment +// TODO: MediaId - add argument and description to function comment +// TODO: LBA - add argument and description to function comment +// TODO: BufferSize - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +// TODO: EFI_MEDIA_CHANGED - add return value to function comment +// TODO: EFI_WRITE_PROTECTED - add return value to function comment +{ + + EFI_BLOCK_IO_MEDIA *Media; + UINTN BlockSize; + UINTN NumberOfBlocks; + EFI_STATUS Status; + BOOLEAN MediaChange; + + if (LBA == 0 && IdeBlkIoDevice->Cache) { + gBS->FreePool (IdeBlkIoDevice->Cache); + IdeBlkIoDevice->Cache = NULL; + } + + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (BufferSize == 0) { + return EFI_SUCCESS; + } + + // + // ATAPI device media is removable, + // so it is a must to detect media first before write operation + // + MediaChange = FALSE; + Status = AtapiDetectMedia (IdeBlkIoDevice, &MediaChange); + if (EFI_ERROR (Status)) { + + if (LBA == 0 && IdeBlkIoDevice->Cache) { + gBS->FreePool (IdeBlkIoDevice->Cache); + IdeBlkIoDevice->Cache = NULL; + } + return Status; + } + + // + // Get the intrinsic block size + // + Media = IdeBlkIoDevice->BlkIo.Media; + BlockSize = Media->BlockSize; + NumberOfBlocks = BufferSize / BlockSize; + + if (!(Media->MediaPresent)) { + + if (LBA == 0 && IdeBlkIoDevice->Cache) { + gBS->FreePool (IdeBlkIoDevice->Cache); + IdeBlkIoDevice->Cache = NULL; + } + return EFI_NO_MEDIA; + } + + if ((MediaId != Media->MediaId) || MediaChange) { + + if (LBA == 0 && IdeBlkIoDevice->Cache) { + gBS->FreePool (IdeBlkIoDevice->Cache); + IdeBlkIoDevice->Cache = NULL; + } + return EFI_MEDIA_CHANGED; + } + + if (Media->ReadOnly) { + return EFI_WRITE_PROTECTED; + } + + if (BufferSize % BlockSize != 0) { + return EFI_BAD_BUFFER_SIZE; + } + + if (LBA > Media->LastBlock) { + return EFI_INVALID_PARAMETER; + } + + if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) { + return EFI_INVALID_PARAMETER; + } + + if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) { + return EFI_INVALID_PARAMETER; + } + + // + // if all the parameters are valid, + // then perform write sectors command to transfer data from host to device. + // + Status = AtapiWriteSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; + +} + +// +// The following functions are a set of helper functions, +// which are used to parse sense key returned by the device. +// + +BOOLEAN +IsNoMedia ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SenseData - TODO: add argument description + SenseCounts - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + REQUEST_SENSE_DATA *SensePointer; + UINTN Index; + BOOLEAN NoMedia; + + NoMedia = FALSE; + SensePointer = SenseData; + + for (Index = 0; Index < SenseCounts; Index++) { + // + // Sense Key is SK_NOT_READY (0x2), + // Additional Sense Code is ASC_NO_MEDIA (0x3A) + // + if ((SensePointer->sense_key == SK_NOT_READY) && + (SensePointer->addnl_sense_code == ASC_NO_MEDIA)) { + + NoMedia = TRUE; + } + + SensePointer++; + } + + return NoMedia; +} + +BOOLEAN +IsMediaError ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +/*++ + Name: + IsMediaError + + Purpose: + Test if the device meets a media error after media changed + + Parameters: + EQUEST_SENSE_DATA IN *SenseData + pointer pointing to ATAPI device sense data list. + UINTN IN SenseCounts + sense data number of the list + + Returns: + TRUE + Device meets a media error + + FALSE + No media error +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: SenseData - add argument and description to function comment +// TODO: SenseCounts - add argument and description to function comment +{ + REQUEST_SENSE_DATA *SensePointer; + UINTN Index; + BOOLEAN IsError; + + IsError = FALSE; + SensePointer = SenseData; + + for (Index = 0; Index < SenseCounts; Index++) { + + switch (SensePointer->sense_key) { + + case SK_MEDIUM_ERROR: + // + // Sense Key is SK_MEDIUM_ERROR (0x3) + // + switch (SensePointer->addnl_sense_code) { + case ASC_MEDIA_ERR1: + case ASC_MEDIA_ERR2: + case ASC_MEDIA_ERR3: + case ASC_MEDIA_ERR4: + IsError = TRUE; + break; + + default: + break; + } + + break; + + case SK_NOT_READY: + // + // Sense Key is SK_NOT_READY (0x2) + // + switch (SensePointer->addnl_sense_code) { + // + // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6) + // + case ASC_MEDIA_UPSIDE_DOWN: + IsError = TRUE; + break; + + default: + break; + } + break; + + default: + break; + } + + SensePointer++; + } + + return IsError; +} + +BOOLEAN +IsMediaChange ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SenseData - TODO: add argument description + SenseCounts - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + REQUEST_SENSE_DATA *SensePointer; + UINTN Index; + BOOLEAN IsMediaChange; + + IsMediaChange = FALSE; + SensePointer = SenseData; + + for (Index = 0; Index < SenseCounts; Index++) { + // + // Sense Key is SK_UNIT_ATTENTION (0x6) + // + if ((SensePointer->sense_key == SK_UNIT_ATTENTION) && + (SensePointer->addnl_sense_code == ASC_MEDIA_CHANGE)) { + + IsMediaChange = TRUE; + } + + SensePointer++; + } + + return IsMediaChange; +} + +BOOLEAN +IsDriveReady ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts, + OUT BOOLEAN *NeedRetry + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SenseData - TODO: add argument description + SenseCounts - TODO: add argument description + NeedRetry - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + REQUEST_SENSE_DATA *SensePointer; + UINTN Index; + BOOLEAN IsReady; + + IsReady = TRUE; + *NeedRetry = FALSE; + SensePointer = SenseData; + + for (Index = 0; Index < SenseCounts; Index++) { + + switch (SensePointer->sense_key) { + + case SK_NOT_READY: + // + // Sense Key is SK_NOT_READY (0x2) + // + switch (SensePointer->addnl_sense_code) { + case ASC_NOT_READY: + // + // Additional Sense Code is ASC_NOT_READY (0x4) + // + switch (SensePointer->addnl_sense_code_qualifier) { + case ASCQ_IN_PROGRESS: + // + // Additional Sense Code Qualifier is ASCQ_IN_PROGRESS (0x1) + // + IsReady = FALSE; + *NeedRetry = TRUE; + break; + + default: + IsReady = FALSE; + *NeedRetry = FALSE; + break; + } + break; + + default: + break; + } + break; + + default: + break; + } + + SensePointer++; + } + + return IsReady; +} + +BOOLEAN +HaveSenseKey ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SenseData - TODO: add argument description + SenseCounts - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + BOOLEAN Have; + + Have = TRUE; + + // + // if first sense key in the Sense Data Array is SK_NO_SENSE, + // it indicates there is no more sense key in the Sense Data Array. + // + if (SenseData->sense_key == SK_NO_SENSE) { + Have = FALSE; + } + + return Have; +} + +EFI_STATUS +IsLS120orZipWriteProtected ( + IN IDE_BLK_IO_DEV *IdeDev, + OUT BOOLEAN *WriteProtected + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + WriteProtected - TODO: add argument description + +Returns: + + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + EFI_STATUS Status; + + *WriteProtected = FALSE; + + Status = LS120EnableMediaStatus (IdeDev, TRUE); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // the Get Media Status Command is only valid + // if a Set Features/Enable Media Status Command has been priviously issued. + // + if (LS120GetMediaStatus (IdeDev) == EFI_WRITE_PROTECTED) { + + *WriteProtected = TRUE; + } else { + + *WriteProtected = FALSE; + } + + // + // After Get Media Status Command completes, + // Set Features/Disable Media Command should be sent. + // + Status = LS120EnableMediaStatus (IdeDev, FALSE); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/build.xml b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/build.xml new file mode 100644 index 0000000000..3a33a2b3a9 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/build.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.c b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.c new file mode 100644 index 0000000000..d318fd23df --- /dev/null +++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.c @@ -0,0 +1,1964 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ide.c + +Abstract: + + +Revision History +--*/ + +#include "idebus.h" + +BOOLEAN SlaveDeviceExist = FALSE; +BOOLEAN MasterDeviceExist = FALSE; + +UINT8 +IDEReadPortB ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT16 Port + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIo - TODO: add argument description + Port - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + UINT8 Data; + + Data = 0; + // + // perform 1-byte data read from register + // + PciIo->Io.Read ( + PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) Port, + 1, + &Data + ); + return Data; +} + +VOID +IDEReadPortWMultiple ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT16 Port, + IN UINTN Count, + IN VOID *Buffer + ) +/*++ + +Routine Description: + 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 + + +Arguments: + PciIo - Pointer to the EFI_PCI_IO instance + Port - IO port to read + Count - No. of UINT16's to read + Buffer - Pointer to the data buffer for read + +++*/ +// TODO: function comment should end with '--*/' +// TODO: function comment is missing 'Returns:' +{ + UINT16 *AlignedBuffer; + UINT16 *WorkingBuffer; + UINTN Size; + + // + // Prepare an 16-bit alligned working buffer. CpuIo will return failure and + // not perform actual I/O operations if buffer pointer passed in is not at + // natural boundary. The "Buffer" argument is passed in by user and may not + // at 16-bit natural boundary. + // + Size = sizeof (UINT16) * Count; + + gBS->AllocatePool ( + EfiBootServicesData, + Size + 1, + (VOID**)&WorkingBuffer + ); + + AlignedBuffer = (UINT16 *) ((UINTN)(((UINTN) WorkingBuffer + 0x1) & (~0x1))); + + // + // Perform UINT16 data read from FIFO + // + PciIo->Io.Read ( + PciIo, + EfiPciIoWidthFifoUint16, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) Port, + Count, + (UINT16*)AlignedBuffer + ); + + // + // Copy data to user buffer + // + CopyMem (Buffer, (UINT16*)AlignedBuffer, Size); + gBS->FreePool (WorkingBuffer); +} + +VOID +IDEWritePortB ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT16 Port, + IN UINT8 Data + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIo - TODO: add argument description + Port - TODO: add argument description + Data - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + // + // perform 1-byte data write to register + // + PciIo->Io.Write ( + PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) Port, + 1, + &Data + ); + +} + +VOID +IDEWritePortW ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT16 Port, + IN UINT16 Data + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIo - TODO: add argument description + Port - TODO: add argument description + Data - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + // + // perform 1-word data write to register + // + PciIo->Io.Write ( + PciIo, + EfiPciIoWidthUint16, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) Port, + 1, + &Data + ); +} + +VOID +IDEWritePortWMultiple ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT16 Port, + IN UINTN Count, + IN VOID *Buffer + ) +/*++ + +Routine Description: + 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 + + +Arguments: + PciIo - Pointer to the EFI_PCI_IO instance + Port - IO port to read + Count - No. of UINT16's to read + Buffer - Pointer to the data buffer for read + +++*/ +// TODO: function comment should end with '--*/' +// TODO: function comment is missing 'Returns:' +{ + UINT16 *AlignedBuffer; + UINT32 *WorkingBuffer; + UINTN Size; + + // + // Prepare an 16-bit alligned working buffer. CpuIo will return failure and + // not perform actual I/O operations if buffer pointer passed in is not at + // natural boundary. The "Buffer" argument is passed in by user and may not + // at 16-bit natural boundary. + // + Size = sizeof (UINT16) * Count; + + gBS->AllocatePool ( + EfiBootServicesData, + Size + 1, + (VOID **) &WorkingBuffer + ); + + AlignedBuffer = (UINT16 *) ((UINTN)(((UINTN) WorkingBuffer + 0x1) & (~0x1))); + + // + // Copy data from user buffer to working buffer + // + CopyMem ((UINT16 *) AlignedBuffer, Buffer, Size); + + // + // perform UINT16 data write to the FIFO + // + PciIo->Io.Write ( + PciIo, + EfiPciIoWidthFifoUint16, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) Port, + Count, + (UINT16 *) AlignedBuffer + ); + + gBS->FreePool (WorkingBuffer); +} + +BOOLEAN +BadIdeDeviceCheck ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + // + // check whether all registers return 0xff, + // if so, deem the channel is disabled. + // +#ifdef EFI_DEBUG + + if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Data) != 0xff) { + return FALSE; + } + + if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature) != 0xff) { + return FALSE; + } + + if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount) != 0xff) { + return FALSE; + } + + if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber) != 0xff) { + return FALSE; + } + + if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb) != 0xff) { + return FALSE; + } + + if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb) != 0xff) { + return FALSE; + } + + if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Head) != 0xff) { + return FALSE; + } + + if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command) != 0xff) { + return FALSE; + } + + if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus) != 0xff) { + return FALSE; + } + + return TRUE; + +#else + + return FALSE; + +#endif +} + +// +// GetIdeRegistersBaseAddr +// +EFI_STATUS +GetIdeRegistersBaseAddr ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + OUT IDE_REGISTERS_BASE_ADDR *IdeRegsBaseAddr + ) +/*++ + +Routine Description: + Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode, + use fixed addresses. In Native-PCI mode, get base addresses from BARs in + the PCI IDE controller's Configuration Space. + + The steps to get IDE IO port registers' base addresses for each channel + as follows: + + 1. Examine the Programming Interface byte of the Class Code fields in PCI IDE + controller's Configuration Space to determine the operating mode. + + 2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below. + ___________________________________________ + | | 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 + Note: Refer to Intel ICH4 datasheet, Control Block Offset: 03F4h for + primary, 0374h for secondary. So 2 bytes extra offset should be + added to the base addresses read from BARs. + + For more details, please refer to PCI IDE Controller Specification and Intel + ICH4 Datasheet. + +Arguments: + PciIo - Pointer to the EFI_PCI_IO_PROTOCOL instance + IdeRegsBaseAddr - Pointer to IDE_REGISTERS_BASE_ADDR to + receive IDE IO port registers' base addresses + +Returns: + +--*/ +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + PCI_TYPE00 PciData; + + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint8, + 0, + sizeof (PciData), + &PciData + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + if ((PciData.Hdr.ClassCode[0] & IDE_PRIMARY_OPERATING_MODE) == 0) { + IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr = 0x1f0; + IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr = 0x3f6; + IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr = + (UINT16)((PciData.Device.Bar[4] & 0x0000fff0)); + } else { + // + // The BARs should be of IO type + // + if ((PciData.Device.Bar[0] & bit0) == 0 || + (PciData.Device.Bar[1] & bit0) == 0) { + return EFI_UNSUPPORTED; + } + + IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr = + (UINT16) (PciData.Device.Bar[0] & 0x0000fff8); + IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr = + (UINT16) ((PciData.Device.Bar[1] & 0x0000fffc) + 2); + IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr = + (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0)); + } + + if ((PciData.Hdr.ClassCode[0] & IDE_SECONDARY_OPERATING_MODE) == 0) { + IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr = 0x170; + IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr = 0x376; + IdeRegsBaseAddr[IdeSecondary].BusMasterBaseAddr = + (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0)); + } else { + // + // The BARs should be of IO type + // + if ((PciData.Device.Bar[2] & bit0) == 0 || + (PciData.Device.Bar[3] & bit0) == 0) { + return EFI_UNSUPPORTED; + } + + IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr = + (UINT16) (PciData.Device.Bar[2] & 0x0000fff8); + IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr = + (UINT16) ((PciData.Device.Bar[3] & 0x0000fffc) + 2); + IdeRegsBaseAddr[IdeSecondary].BusMasterBaseAddr = + (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0)); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +ReassignIdeResources ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + This function is used to requery IDE resources. The IDE controller will + probably switch between native and legacy modes during the EFI->CSM->OS + transfer. We do this everytime before an BlkIo operation to ensure its + succeess. + +Arguments: + IdeDev - The BLK_IO private data which specifies the IDE device + +++*/ +// TODO: function comment should end with '--*/' +// TODO: function comment is missing 'Returns:' +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr[IdeMaxChannel]; + UINT16 CommandBlockBaseAddr; + UINT16 ControlBlockBaseAddr; + + // + // Requery IDE IO port registers' base addresses in case of the switch of + // native and legacy modes + // + Status = GetIdeRegistersBaseAddr (IdeDev->PciIo, IdeRegsBaseAddr); + if (EFI_ERROR (Status)) { + return Status; + } + + ZeroMem (IdeDev->IoPort, sizeof (IDE_BASE_REGISTERS)); + CommandBlockBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].CommandBlockBaseAddr; + ControlBlockBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].ControlBlockBaseAddr; + + IdeDev->IoPort->Data = CommandBlockBaseAddr; + (*(UINT16 *) &IdeDev->IoPort->Reg1) = (UINT16) (CommandBlockBaseAddr + 0x01); + IdeDev->IoPort->SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02); + IdeDev->IoPort->SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03); + IdeDev->IoPort->CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04); + IdeDev->IoPort->CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05); + IdeDev->IoPort->Head = (UINT16) (CommandBlockBaseAddr + 0x06); + + (*(UINT16 *) &IdeDev->IoPort->Reg) = (UINT16) (CommandBlockBaseAddr + 0x07); + (*(UINT16 *) &IdeDev->IoPort->Alt) = ControlBlockBaseAddr; + IdeDev->IoPort->DriveAddress = (UINT16) (ControlBlockBaseAddr + 0x01); + IdeDev->IoPort->MasterSlave = (UINT16) ((IdeDev->Device == IdeMaster) ? 1 : 0); + + IdeDev->IoPort->BusMasterBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].BusMasterBaseAddr; + return EFI_SUCCESS; +} + +EFI_STATUS +CheckPowerMode ( + IDE_BLK_IO_DEV *IdeDev + ) +/*++ + Routine Description: + + Read SATA registers to detect SATA disks + + Arguments: + + IdeDev - The BLK_IO private data which specifies the IDE device + +++*/ +// TODO: function comment should end with '--*/' +// TODO: function comment is missing 'Returns:' +// TODO: EFI_NOT_FOUND - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +{ + UINT8 ErrorRegister; + EFI_STATUS Status; + + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + (UINT8) ((IdeDev->Device << 4) | 0xe0) + ); + + // + // Wait 31 seconds for BSY clear. BSY should be in clear state if there exists + // a device (initial state). Normally, BSY is also in clear state if there is + // no device + // + Status = WaitForBSYClear (IdeDev, 31000); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + // + // select device, read error register + // + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + (UINT8) ((IdeDev->Device << 4) | 0xe0) + ); + Status = DRDYReady (IdeDev, 200); + + ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error); + if ((ErrorRegister == 0x01) || (ErrorRegister == 0x81)) { + return EFI_SUCCESS; + } else { + return EFI_NOT_FOUND; + } +} + +// +// DiscoverIdeDevice +// +EFI_STATUS +DiscoverIdeDevice ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + Routine Description: + + Detect if there is disk connected to this port + + Arguments: + + IdeDev - The BLK_IO private data which specifies the IDE device + +++*/ +// TODO: function comment should end with '--*/' +// TODO: function comment is missing 'Returns:' +// TODO: EFI_NOT_FOUND - add return value to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + BOOLEAN SataFlag; + + SataFlag = FALSE; + // + // This extra detection is for SATA disks + // + Status = CheckPowerMode (IdeDev); + if (Status == EFI_SUCCESS) { + SataFlag = TRUE; + } + + // + // If a channel has not been checked, check it now. Then set it to "checked" state + // After this step, all devices in this channel have been checked. + // + Status = DetectIDEController (IdeDev); + + if ((EFI_ERROR (Status)) && !SataFlag) { + return EFI_NOT_FOUND; + } + + // + // Device exists. test if it is an ATA device + // + Status = ATAIdentify (IdeDev); + if (EFI_ERROR (Status)) { + // + // if not ATA device, test if it is an ATAPI device + // + Status = ATAPIIdentify (IdeDev); + if (EFI_ERROR (Status)) { + // + // if not ATAPI device either, return error. + // + return EFI_NOT_FOUND; + } + } + + // + // Init Block I/O interface + // + IdeDev->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION; + IdeDev->BlkIo.Reset = IDEBlkIoReset; + IdeDev->BlkIo.ReadBlocks = IDEBlkIoReadBlocks; + IdeDev->BlkIo.WriteBlocks = IDEBlkIoWriteBlocks; + IdeDev->BlkIo.FlushBlocks = IDEBlkIoFlushBlocks; + + IdeDev->BlkMedia.LogicalPartition = FALSE; + IdeDev->BlkMedia.WriteCaching = FALSE; + + // + // Init Disk Info interface + // + gBS->CopyMem (&IdeDev->DiskInfo.Interface, &gEfiDiskInfoIdeInterfaceGuid, sizeof (EFI_GUID)); + IdeDev->DiskInfo.Inquiry = IDEDiskInfoInquiry; + IdeDev->DiskInfo.Identify = IDEDiskInfoIdentify; + IdeDev->DiskInfo.SenseData = IDEDiskInfoSenseData; + IdeDev->DiskInfo.WhichIde = IDEDiskInfoWhichIde; + + return EFI_SUCCESS; +} + +EFI_STATUS +DetectIDEController ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + + Name: DetectIDEController + + + Purpose: + This function is called by DiscoverIdeDevice(). It is used for detect + whether the IDE device exists in the specified Channel as the specified + Device Number. + + There is two IDE channels: one is Primary Channel, the other is + Secondary Channel.(Channel is the logical name for the physical "Cable".) + Different channel has different register group. + + On each IDE channel, at most two IDE devices attach, + one is called Device 0 (Master device), the other is called Device 1 + (Slave device). The devices on the same channel co-use the same register + group, so before sending out a command for a specified device via command + register, it is a must to select the current device to accept the command + by set the device number in the Head/Device Register. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + + Returns: + TRUE + successfully detects device. + + FALSE + any failure during detection process will return this + value. + + + Notes: +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +{ + EFI_STATUS Status; + UINT8 ErrorReg; + UINT8 StatusReg; + UINT8 InitStatusReg; + EFI_STATUS DeviceStatus; + + // + // Slave device has been detected with master device. + // + if ((IdeDev->Device) == 1) { + if (SlaveDeviceExist) { + // + // If master not exists but slave exists, slave have to wait a while + // + if (!MasterDeviceExist) { + // + // if single slave can't be detected, add delay 4s here. + // + gBS->Stall (4000000); + } + + return EFI_SUCCESS; + } else { + return EFI_NOT_FOUND; + } + } + + // + // Select slave device + // + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + (UINT8) ((1 << 4) | 0xe0) + ); + gBS->Stall (100); + + // + // Save the init slave status register + // + InitStatusReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status); + + // + // Select master back + // + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + (UINT8) ((0 << 4) | 0xe0) + ); + gBS->Stall (100); + // + // Send ATA Device Execut Diagnostic command. + // This command should work no matter DRDY is ready or not + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0x90); + + Status = WaitForBSYClear (IdeDev, 3500); + + ErrorReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error); + + // + // Master Error register is 0x01. D0 passed, D1 passed or not present. + // Master Error register is 0x81. D0 passed, D1 failed. Return. + // Master Error register is other value. D0 failed, D1 passed or not present.. + // + if (ErrorReg == 0x01) { + MasterDeviceExist = TRUE; + DeviceStatus = EFI_SUCCESS; + } else if (ErrorReg == 0x81) { + + MasterDeviceExist = TRUE; + DeviceStatus = EFI_SUCCESS; + SlaveDeviceExist = FALSE; + + return DeviceStatus; + } else { + MasterDeviceExist = FALSE; + DeviceStatus = EFI_NOT_FOUND; + } + + // + // Master Error register is not 0x81, Go on check Slave + // + + // + // select slave + // + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + (UINT8) ((1 << 4) | 0xe0) + ); + + gBS->Stall (300); + ErrorReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error); + + // + // Slave Error register is not 0x01, D1 failed. Return. + // + if (ErrorReg != 0x01) { + SlaveDeviceExist = FALSE; + return DeviceStatus; + } + + StatusReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status); + + // + // Most ATAPI devices don't set DRDY bit, so test with a slow but accurate + // "ATAPI TEST UNIT READY" command + // + if (((StatusReg & DRDY) == 0) && ((InitStatusReg & DRDY) == 0)) { + Status = AtapiTestUnitReady (IdeDev); + + // + // Still fail, Slave doesn't exist. + // + if (EFI_ERROR (Status)) { + SlaveDeviceExist = FALSE; + return DeviceStatus; + } + } + + // + // Error reg is 0x01 and DRDY is ready, + // or ATAPI test unit ready success, + // or init Slave status DRDY is ready + // Slave exists. + // + SlaveDeviceExist = TRUE; + + return DeviceStatus; + +} + +EFI_STATUS +DRQClear ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN TimeoutInMilliSeconds + ) +/*++ + Name: DRQClear + + + Purpose: + 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. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + UINTN IN TimeoutInMilliSeconds + used to designate the timeout for the DRQ clear. + + Returns: + EFI_SUCCESS + DRQ bit clear within the time out. + + EFI_TIMEOUT + DRQ bit not clear within the time out. + + + Notes: + Read Status Register will clear interrupt status. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: TimeoutInMilliSeconds - add argument and description to function comment +// TODO: EFI_ABORTED - add return value to function comment +{ + UINT32 Delay; + UINT8 StatusRegister; + UINT8 ErrorRegister; + + Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1); + do { + + StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status); + + // + // wait for BSY == 0 and DRQ == 0 + // + if ((StatusRegister & (DRQ | BSY)) == 0) { + break; + } + + if ((StatusRegister & (BSY | ERR)) == ERR) { + + ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error); + if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) { + return EFI_ABORTED; + } + } + + // + // Stall for 30 us + // + gBS->Stall (30); + + Delay--; + + } while (Delay); + + if (Delay == 0) { + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +DRQClear2 ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN TimeoutInMilliSeconds + ) +/*++ + Name: DRQClear2 + + + Purpose: + 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. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + UINTN IN TimeoutInMilliSeconds + used to designate the timeout for the DRQ clear. + + Returns: + EFI_SUCCESS + DRQ bit clear within the time out. + + EFI_TIMEOUT + DRQ bit not clear within the time out. + + + Notes: + Read Alternate Status Register will not clear interrupt status. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: TimeoutInMilliSeconds - add argument and description to function comment +// TODO: EFI_ABORTED - add return value to function comment +{ + UINT32 Delay; + UINT8 AltRegister; + UINT8 ErrorRegister; + + Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1); + do { + + AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus); + + // + // wait for BSY == 0 and DRQ == 0 + // + if ((AltRegister & (DRQ | BSY)) == 0) { + break; + } + + if ((AltRegister & (BSY | ERR)) == ERR) { + + ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error); + if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) { + return EFI_ABORTED; + } + } + + // + // Stall for 30 us + // + gBS->Stall (30); + + Delay--; + + } while (Delay); + + if (Delay == 0) { + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +DRQReady ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN TimeoutInMilliSeconds + ) +/*++ + Name: DRQReady + + + Purpose: + 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. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure,used + to record all the information of the IDE device. + + UINTN IN TimeoutInMilliSeconds + used to designate the timeout for the DRQ ready. + + + Returns: + EFI_SUCCESS + DRQ bit set within the time out. + + EFI_TIMEOUT + DRQ bit not set within the time out. + + EFI_ABORTED + DRQ bit not set caused by the command abort. + + Notes: + Read Status Register will clear interrupt status. + +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: TimeoutInMilliSeconds - add argument and description to function comment +{ + UINT32 Delay; + UINT8 StatusRegister; + UINT8 ErrorRegister; + + Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1); + do { + // + // read Status Register will clear interrupt + // + StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status); + + // + // BSY==0,DRQ==1 + // + if ((StatusRegister & (BSY | DRQ)) == DRQ) { + break; + } + + if ((StatusRegister & (BSY | ERR)) == ERR) { + + ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error); + if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) { + return EFI_ABORTED; + } + } + + // + // Stall for 30 us + // + gBS->Stall (30); + + Delay--; + } while (Delay); + + if (Delay == 0) { + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +DRQReady2 ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN TimeoutInMilliSeconds + ) +/*++ + Name: DRQReady2 + + + Purpose: + 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. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + UINTN IN TimeoutInMilliSeconds + used to designate the timeout for the DRQ ready. + + Returns: + EFI_SUCCESS + DRQ bit set within the time out. + + EFI_TIMEOUT + DRQ bit not set within the time out. + + EFI_ABORTED + DRQ bit not set caused by the command abort. + + Notes: + Read Alternate Status Register will not clear interrupt status. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: TimeoutInMilliSeconds - add argument and description to function comment +{ + UINT32 Delay; + UINT8 AltRegister; + UINT8 ErrorRegister; + + Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1); + + do { + // + // Read Alternate Status Register will not clear interrupt status + // + AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus); + // + // BSY == 0 , DRQ == 1 + // + if ((AltRegister & (BSY | DRQ)) == DRQ) { + break; + } + + if ((AltRegister & (BSY | ERR)) == ERR) { + + ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error); + if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) { + return EFI_ABORTED; + } + } + + // + // Stall for 30 us + // + gBS->Stall (30); + + Delay--; + } while (Delay); + + if (Delay == 0) { + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +WaitForBSYClear ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN TimeoutInMilliSeconds + ) +/*++ + Name: + WaitForBSYClear + + + Purpose: + 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. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + UINTN IN TimeoutInMilliSeconds + used to designate the timeout for the DRQ ready. + + Returns: + EFI_SUCCESS + BSY bit clear within the time out. + + EFI_TIMEOUT + BSY bit not clear within the time out. + + + Notes: + Read Status Register will clear interrupt status. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: TimeoutInMilliSeconds - add argument and description to function comment +{ + UINT32 Delay; + UINT8 StatusRegister; + + Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1); + do { + + StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status); + if ((StatusRegister & BSY) == 0x00) { + break; + } + + // + // Stall for 30 us + // + gBS->Stall (30); + + Delay--; + + } while (Delay); + + if (Delay == 0) { + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} +// +// WaitForBSYClear2 +// +EFI_STATUS +WaitForBSYClear2 ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN TimeoutInMilliSeconds + ) +/*++ + Name: + WaitForBSYClear2 + + + Purpose: + This function is used to poll for the BSY bit clear in the + Alternate Status Register. BSY is clear when the device is not busy. + Every command must be sent after device is not busy. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + UINTN IN TimeoutInMilliSeconds + used to designate the timeout for the DRQ ready. + + Returns: + EFI_SUCCESS + BSY bit clear within the time out. + + EFI_TIMEOUT + BSY bit not clear within the time out. + + + Notes: + Read Alternate Status Register will not clear interrupt status. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: TimeoutInMilliSeconds - add argument and description to function comment +{ + UINT32 Delay; + UINT8 AltRegister; + + Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1); + do { + AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus); + if ((AltRegister & BSY) == 0x00) { + break; + } + + gBS->Stall (30); + + Delay--; + + } while (Delay); + + if (Delay == 0) { + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +// +// DRDYReady +// +EFI_STATUS +DRDYReady ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN DelayInMilliSeconds + ) +/*++ + Name: + DRDYReady + + + Purpose: + This function is used to poll for the DRDY bit set in the + Status Register. DRDY bit is set when the device is ready + to accept command. Most ATA commands must be sent after + DRDY set except the ATAPI Packet Command. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + UINTN IN TimeoutInMilliSeconds + used to designate the timeout for the DRQ ready. + + Returns: + EFI_SUCCESS + DRDY bit set within the time out. + + EFI_TIMEOUT + DRDY bit not set within the time out. + + + Notes: + Read Status Register will clear interrupt status. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: DelayInMilliSeconds - add argument and description to function comment +// TODO: EFI_ABORTED - add return value to function comment +{ + UINT32 Delay; + UINT8 StatusRegister; + UINT8 ErrorRegister; + + Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1); + do { + StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status); + // + // BSY == 0 , DRDY == 1 + // + if ((StatusRegister & (DRDY | BSY)) == DRDY) { + break; + } + + if ((StatusRegister & (BSY | ERR)) == ERR) { + + ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error); + if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) { + return EFI_ABORTED; + } + } + + gBS->Stall (15); + + Delay--; + } while (Delay); + + if (Delay == 0) { + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +// +// DRDYReady2 +// +EFI_STATUS +DRDYReady2 ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN DelayInMilliSeconds + ) +/*++ + Name: + DRDYReady2 + + + Purpose: + This function is used to poll for the DRDY bit set in the + Alternate Status Register. DRDY bit is set when the device is ready + to accept command. Most ATA commands must be sent after + DRDY set except the ATAPI Packet Command. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + UINTN IN TimeoutInMilliSeconds + used to designate the timeout for the DRQ ready. + + Returns: + EFI_SUCCESS + DRDY bit set within the time out. + + EFI_TIMEOUT + DRDY bit not set within the time out. + + + Notes: + Read Alternate Status Register will clear interrupt status. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: DelayInMilliSeconds - add argument and description to function comment +// TODO: EFI_ABORTED - add return value to function comment +{ + UINT32 Delay; + UINT8 AltRegister; + UINT8 ErrorRegister; + + Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1); + do { + AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus); + // + // BSY == 0 , DRDY == 1 + // + if ((AltRegister & (DRDY | BSY)) == DRDY) { + break; + } + + if ((AltRegister & (BSY | ERR)) == ERR) { + + ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error); + if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) { + return EFI_ABORTED; + } + } + + gBS->Stall (30); + + Delay--; + } while (Delay); + + if (Delay == 0) { + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +// +// SwapStringChars +// +VOID +SwapStringChars ( + IN CHAR8 *Destination, + IN CHAR8 *Source, + IN UINT32 Size + ) +/*++ + Name: + SwapStringChars + + + Purpose: + This function is a helper function used to change the char order in a + string. It is designed specially for the PrintAtaModuleName() function. + After the IDE device is detected, the IDE driver gets the device module + name by sending ATA command called ATA Identify Command or ATAPI + Identify Command to the specified IDE device. The module name returned + is a string of ASCII characters: the first character is bit8--bit15 + of the first word, the second character is bit0--bit7 of the first word + and so on. Thus the string can not be print directly before it is + preprocessed by this func to change the order of characters in + each word in the string. + + + Parameters: + CHAR8 IN *Destination + Indicates the destination string. + + CHAR8 IN *Source + Indicates the source string. + + UINT8 IN Size + the length of the string + + + Returns: + none + + Notes: + +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: Destination - add argument and description to function comment +// TODO: Source - add argument and description to function comment +// TODO: Size - add argument and description to function comment +{ + UINT32 Index; + CHAR8 Temp; + + for (Index = 0; Index < Size; Index += 2) { + + Temp = Source[Index + 1]; + Destination[Index + 1] = Source[Index]; + Destination[Index] = Temp; + } +} + +// +// ReleaseIdeResources +// +VOID +ReleaseIdeResources ( + IN IDE_BLK_IO_DEV *IdeBlkIoDevice + ) +/*++ +Routing Description: + + Release resources of an IDE device before stopping it. + +Arguments: + + IdeBlkIoDevice -- Standard IDE device private data structure + + +Returns: + + NONE + +---*/ +// TODO: function comment is missing 'Routine Description:' +{ + if (IdeBlkIoDevice == NULL) { + return ; + } + + // + // Release all the resourses occupied by the IDE_BLK_IO_DEV + // + + if (IdeBlkIoDevice->SenseData != NULL) { + gBS->FreePool (IdeBlkIoDevice->SenseData); + IdeBlkIoDevice->SenseData = NULL; + } + + if (IdeBlkIoDevice->Cache != NULL) { + gBS->FreePool (IdeBlkIoDevice->Cache); + IdeBlkIoDevice->Cache = NULL; + } + + if (IdeBlkIoDevice->pIdData != NULL) { + gBS->FreePool (IdeBlkIoDevice->pIdData); + IdeBlkIoDevice->pIdData = NULL; + } + + if (IdeBlkIoDevice->pInquiryData != NULL) { + gBS->FreePool (IdeBlkIoDevice->pInquiryData); + IdeBlkIoDevice->pInquiryData = NULL; + } + + if (IdeBlkIoDevice->ControllerNameTable != NULL) { + FreeUnicodeStringTable (IdeBlkIoDevice->ControllerNameTable); + IdeBlkIoDevice->ControllerNameTable = NULL; + } + + if (IdeBlkIoDevice->IoPort != NULL) { + gBS->FreePool (IdeBlkIoDevice->IoPort); + } + + if (IdeBlkIoDevice->DevicePath != NULL) { + gBS->FreePool (IdeBlkIoDevice->DevicePath); + } + + gBS->FreePool (IdeBlkIoDevice); + IdeBlkIoDevice = NULL; + + return ; +} + +// +// SetDeviceTransferMode +// +EFI_STATUS +SetDeviceTransferMode ( + IN IDE_BLK_IO_DEV *IdeDev, + IN ATA_TRANSFER_MODE *TransferMode + ) +/*++ +Routing Description: + + Set the calculated Best transfer mode to a detected device + +Arguments: + + IdeDev -- Standard IDE device private data structure + TransferMode -- The device transfer mode to be set + +Returns: + + Set transfer mode Command execute status + +---*/ +// TODO: function comment is missing 'Routine Description:' +{ + EFI_STATUS Status; + UINT8 DeviceSelect; + UINT8 SectorCount; + + DeviceSelect = 0; + DeviceSelect = (UINT8) ((IdeDev->Device) << 4); + SectorCount = *((UINT8 *) TransferMode); + + // + // Send SET FEATURE command (sub command 0x03) to set pio mode. + // + Status = AtaNonDataCommandIn ( + IdeDev, + SET_FEATURES_CMD, + DeviceSelect, + 0x03, + SectorCount, + 0, + 0, + 0 + ); + + return Status; +} + +EFI_STATUS +AtaNonDataCommandIn ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINT8 AtaCommand, + IN UINT8 Device, + IN UINT8 Feature, + IN UINT8 SectorCount, + IN UINT8 LbaLow, + IN UINT8 LbaMiddle, + IN UINT8 LbaHigh + ) +/*++ + +Routine Description: + + Send ATA command into device with NON_DATA protocol + +Arguments: + + IdeDev - Standard IDE device private data structure + AtaCommand - The ATA command to be sent + Device - The value in Device register + Feature - The value in Feature register + SectorCount - The value in SectorCount register + LbaLow - The value in LBA_LOW register + LbaMiddle - The value in LBA_MIDDLE register + LbaHigh - The value in LBA_HIGH register + +Returns: + + EFI_SUCCESS - Reading succeed + EFI_ABORTED - Command failed + EFI_DEVICE_ERROR - Device status error + +--*/ +{ + EFI_STATUS Status; + UINT8 StatusRegister; + + Status = WaitForBSYClear (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility) + // + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + (UINT8) ((IdeDev->Device << 4) | 0xe0) + ); + + // + // ATA commands for ATA device must be issued when DRDY is set + // + Status = DRDYReady (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Pass parameter into device register block + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMiddle); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh); + + // + // Send command via Command Register + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand); + + // + // Wait for command completion + // + Status = WaitForBSYClear (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status); + if ((StatusRegister & ERR) == ERR) { + // + // Failed to execute command, abort operation + // + return EFI_ABORTED; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +AtaNonDataCommandInExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINT8 AtaCommand, + IN UINT8 Device, + IN UINT16 Feature, + IN UINT16 SectorCount, + IN EFI_LBA LbaAddress + ) +/*++ + +Routine Description: + + Send ATA Ext command into device with NON_DATA protocol + +Arguments: + + IdeDev - Standard IDE device private data structure + AtaCommand - The ATA command to be sent + Device - The value in Device register + Feature - The value in Feature register + SectorCount - The value in SectorCount register + LbaAddress - The LBA address in 48-bit mode + +Returns: + + EFI_SUCCESS - Reading succeed + EFI_ABORTED - Command failed + EFI_DEVICE_ERROR - Device status error + +--*/ +{ + EFI_STATUS Status; + UINT8 StatusRegister; + UINT8 SectorCount8; + UINT8 Feature8; + UINT8 LbaLow; + UINT8 LbaMid; + UINT8 LbaHigh; + + Status = WaitForBSYClear (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility) + // + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + (UINT8) ((IdeDev->Device << 4) | 0xe0) + ); + + // + // ATA commands for ATA device must be issued when DRDY is set + // + Status = DRDYReady (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Pass parameter into device register block + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device); + + // + // Fill the feature register, which is a two-byte FIFO. Need write twice. + // + Feature8 = (UINT8) (Feature >> 8); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8); + + Feature8 = (UINT8) Feature; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8); + + // + // Fill the sector count register, which is a two-byte FIFO. Need write twice. + // + SectorCount8 = (UINT8) (SectorCount >> 8); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8); + + SectorCount8 = (UINT8) SectorCount; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8); + + // + // Fill the start LBA registers, which are also two-byte FIFO + // + LbaLow = (UINT8) RShiftU64 (LbaAddress, 24); + LbaMid = (UINT8) RShiftU64 (LbaAddress, 32); + LbaHigh = (UINT8) RShiftU64 (LbaAddress, 40); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh); + + LbaLow = (UINT8) LbaAddress; + LbaMid = (UINT8) RShiftU64 (LbaAddress, 8); + LbaHigh = (UINT8) RShiftU64 (LbaAddress, 16); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh); + + // + // Send command via Command Register + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand); + + // + // Wait for command completion + // + Status = WaitForBSYClear (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status); + if ((StatusRegister & ERR) == ERR) { + // + // Failed to execute command, abort operation + // + return EFI_ABORTED; + } + + return EFI_SUCCESS; +} + +// +// SetDriveParameters +// +EFI_STATUS +SetDriveParameters ( + IN IDE_BLK_IO_DEV *IdeDev, + IN ATA_DRIVE_PARMS *DriveParameters + ) +/*++ +Routine Description: + + Set drive parameters for devices not support PACKETS command + +Arguments: + + IdeDev -- Standard IDE device private data structure + DriveParameters -- The device parameters to be set into the disk + +Returns: + + SetParameters Command execute status + +--*/ +{ + EFI_STATUS Status; + UINT8 DeviceSelect; + + DeviceSelect = 0; + DeviceSelect = (UINT8) ((IdeDev->Device) << 4); + + // + // Send Init drive parameters + // + Status = AtaPioDataIn ( + IdeDev, + NULL, + 0, + INIT_DRIVE_PARAM_CMD, + (UINT8) (DeviceSelect + DriveParameters->Heads), + DriveParameters->Sector, + 0, + 0, + 0 + ); + + // + // Send Set Multiple parameters + // + Status = AtaPioDataIn ( + IdeDev, + NULL, + 0, + SET_MULTIPLE_MODE_CMD, + DeviceSelect, + DriveParameters->MultipleSector, + 0, + 0, + 0 + ); + + return Status; +} + +EFI_STATUS +EnableInterrupt ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + UINT8 DeviceControl; + + // + // Enable interrupt for DMA operation + // + DeviceControl = 0; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl); + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.h b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.h new file mode 100644 index 0000000000..4c43ab94cd --- /dev/null +++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.h @@ -0,0 +1,1806 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ide.h + +Abstract: + + Header file for IDE Bus Driver, containing the helper functions' + entire prototype. + +Revision History + + 2002-6: Add Atapi6 enhancement, support >120GB hard disk, including + Add - IDEBlkIoReadBlocksExt() func definition + Add - IDEBlkIoWriteBlocksExt() func definition + +++*/ + +// TODO: fix comment to end with --*/ +#ifndef _IDE_H +#define _IDE_H + +// +// Helper functions Prototype +// +EFI_STATUS +DeRegisterIdeDevice ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_HANDLE Handle + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Controller - TODO: add argument description + Handle - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EnableIdeDevice ( + IN EFI_HANDLE Controller, + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Controller - TODO: add argument description + PciIo - TODO: add argument description + ParentDevicePath - TODO: add argument description + RemainingDevicePath - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +UINT8 +IDEReadPortB ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT16 Port + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIo - TODO: add argument description + Port - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +VOID +IDEReadPortWMultiple ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT16 Port, + IN UINTN Count, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIo - TODO: add argument description + Port - TODO: add argument description + Count - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +VOID +IDEWritePortB ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT16 Port, + IN UINT8 Data + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIo - TODO: add argument description + Port - TODO: add argument description + Data - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +VOID +IDEWritePortW ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT16 Port, + IN UINT16 Data + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIo - TODO: add argument description + Port - TODO: add argument description + Data - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +VOID +IDEWritePortWMultiple ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT16 Port, + IN UINTN Count, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIo - TODO: add argument description + Port - TODO: add argument description + Count - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +GetIdeRegistersBaseAddr ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + OUT IDE_REGISTERS_BASE_ADDR *IdeRegsBaseAddr + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIo - TODO: add argument description + IdeRegsBaseAddr - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +ReassignIdeResources ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +DiscoverIdeDevice ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +DetectIDEController ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +DRQClear ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN TimeoutInMilliSeconds + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + TimeoutInMilliSeconds - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +DRQClear2 ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN TimeoutInMilliSeconds + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + TimeoutInMilliSeconds - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +DRQReady ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN TimeoutInMilliSeconds + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + TimeoutInMilliSeconds - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +DRQReady2 ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN TimeoutInMilliSeconds + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + TimeoutInMilliSeconds - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +WaitForBSYClear ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN TimeoutInMilliSeconds + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + TimeoutInMilliSeconds - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +WaitForBSYClear2 ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN TimeoutInMilliSeconds + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + TimeoutInMilliSeconds - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +DRDYReady ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN DelayInMilliSeconds + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + DelayInMilliSeconds - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +DRDYReady2 ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN DelayInMilliSeconds + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + DelayInMilliSeconds - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +VOID +SwapStringChars ( + IN CHAR8 *Destination, + IN CHAR8 *Source, + IN UINT32 Size + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Destination - TODO: add argument description + Source - TODO: add argument description + Size - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +// +// ATA device functions' prototype +// +EFI_STATUS +ATAIdentify ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +VOID +PrintAtaModuleName ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaPioDataIn ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *Buffer, + IN UINT32 ByteCount, + IN UINT8 AtaCommand, + IN UINT8 Head, + IN UINT8 SectorCount, + IN UINT8 SectorNumber, + IN UINT8 CylinderLsb, + IN UINT8 CylinderMsb + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + Buffer - TODO: add argument description + ByteCount - TODO: add argument description + AtaCommand - TODO: add argument description + Head - TODO: add argument description + SectorCount - TODO: add argument description + SectorNumber - TODO: add argument description + CylinderLsb - TODO: add argument description + CylinderMsb - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaPioDataOut ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *Buffer, + IN UINT32 ByteCount, + IN UINT8 AtaCommand, + IN UINT8 Head, + IN UINT8 SectorCount, + IN UINT8 SectorNumber, + IN UINT8 CylinderLsb, + IN UINT8 CylinderMsb + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + Buffer - TODO: add argument description + ByteCount - TODO: add argument description + AtaCommand - TODO: add argument description + Head - TODO: add argument description + SectorCount - TODO: add argument description + SectorNumber - TODO: add argument description + CylinderLsb - TODO: add argument description + CylinderMsb - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +CheckErrorStatus ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaReadSectors ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *DataBuffer, + IN EFI_LBA Lba, + IN UINTN NumberOfBlocks + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + DataBuffer - TODO: add argument description + Lba - TODO: add argument description + NumberOfBlocks - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaWriteSectors ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *BufferData, + IN EFI_LBA Lba, + IN UINTN NumberOfBlocks + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + BufferData - TODO: add argument description + Lba - TODO: add argument description + NumberOfBlocks - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaSoftReset ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaBlkIoReadBlocks ( + IN IDE_BLK_IO_DEV *IdeBlkIoDevice, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeBlkIoDevice - TODO: add argument description + MediaId - TODO: add argument description + LBA - TODO: add argument description + BufferSize - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaBlkIoWriteBlocks ( + IN IDE_BLK_IO_DEV *IdeBlkIoDevice, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeBlkIoDevice - TODO: add argument description + MediaId - TODO: add argument description + LBA - TODO: add argument description + BufferSize - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +// +// ATAPI device functions' prototype +// +EFI_STATUS +ATAPIIdentify ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtapiInquiry ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtapiPacketCommandIn ( + IN IDE_BLK_IO_DEV *IdeDev, + IN ATAPI_PACKET_COMMAND *Packet, + IN UINT16 *Buffer, + IN UINT32 ByteCount, + IN UINTN TimeOut + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + Packet - TODO: add argument description + Buffer - TODO: add argument description + ByteCount - TODO: add argument description + TimeOut - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtapiPacketCommandOut ( + IN IDE_BLK_IO_DEV *IdeDev, + IN ATAPI_PACKET_COMMAND *Packet, + IN UINT16 *Buffer, + IN UINT32 ByteCount, + IN UINTN TimeOut + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + Packet - TODO: add argument description + Buffer - TODO: add argument description + ByteCount - TODO: add argument description + TimeOut - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +PioReadWriteData ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINT16 *Buffer, + IN UINT32 ByteCount, + IN BOOLEAN Read, + IN UINTN TimeOut + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + Buffer - TODO: add argument description + ByteCount - TODO: add argument description + Read - TODO: add argument description + TimeOut - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtapiTestUnitReady ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtapiRequestSense ( + IN IDE_BLK_IO_DEV *IdeDev, + OUT UINTN *SenseCounts + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + SenseCounts - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtapiReadCapacity ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtapiDetectMedia ( + IN IDE_BLK_IO_DEV *IdeDev, + OUT BOOLEAN *MediaChange + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + MediaChange - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtapiReadSectors ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *Buffer, + IN EFI_LBA Lba, + IN UINTN NumberOfBlocks + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + Buffer - TODO: add argument description + Lba - TODO: add argument description + NumberOfBlocks - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtapiWriteSectors ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *Buffer, + IN EFI_LBA Lba, + IN UINTN NumberOfBlocks + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + Buffer - TODO: add argument description + Lba - TODO: add argument description + NumberOfBlocks - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtapiSoftReset ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtapiBlkIoReadBlocks ( + IN IDE_BLK_IO_DEV *IdeBlkIoDevice, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeBlkIoDevice - TODO: add argument description + MediaId - TODO: add argument description + LBA - TODO: add argument description + BufferSize - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtapiBlkIoWriteBlocks ( + IN IDE_BLK_IO_DEV *IdeBlkIoDevice, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeBlkIoDevice - TODO: add argument description + MediaId - TODO: add argument description + LBA - TODO: add argument description + BufferSize - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +IsNoMedia ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SenseData - TODO: add argument description + SenseCounts - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +IsMediaError ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SenseData - TODO: add argument description + SenseCounts - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +IsMediaChange ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SenseData - TODO: add argument description + SenseCounts - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +IsDriveReady ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts, + OUT BOOLEAN *NeedRetry + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SenseData - TODO: add argument description + SenseCounts - TODO: add argument description + NeedRetry - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +HaveSenseKey ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SenseData - TODO: add argument description + SenseCounts - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +IsLS120orZipWriteProtected ( + IN IDE_BLK_IO_DEV *IdeDev, + OUT BOOLEAN *WriteProtected + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + WriteProtected - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +VOID +ReleaseIdeResources ( + IN IDE_BLK_IO_DEV *IdeBlkIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeBlkIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +SetDeviceTransferMode ( + IN IDE_BLK_IO_DEV *IdeDev, + IN ATA_TRANSFER_MODE *TransferMode + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + TransferMode - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +ReadNativeMaxAddress ( + IN IDE_BLK_IO_DEV *IdeDev, + OUT EFI_LBA *NativeMaxAddress + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + NativeMaxAddress - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +SetMaxAddress ( + IN IDE_BLK_IO_DEV *IdeDev, + IN EFI_LBA MaxAddress, + IN BOOLEAN bVolatile + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + MaxAddress - TODO: add argument description + bVolatile - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaNonDataCommandIn ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINT8 AtaCommand, + IN UINT8 Device, + IN UINT8 Feature, + IN UINT8 SectorCount, + IN UINT8 LbaLow, + IN UINT8 LbaMiddle, + IN UINT8 LbaHigh + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + AtaCommand - TODO: add argument description + Device - TODO: add argument description + Feature - TODO: add argument description + SectorCount - TODO: add argument description + LbaLow - TODO: add argument description + LbaMiddle - TODO: add argument description + LbaHigh - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaNonDataCommandInExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINT8 AtaCommand, + IN UINT8 Device, + IN UINT16 Feature, + IN UINT16 SectorCount, + IN EFI_LBA LbaAddress + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + AtaCommand - TODO: add argument description + Device - TODO: add argument description + Feature - TODO: add argument description + SectorCount - TODO: add argument description + LbaAddress - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaReadSectorsExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *DataBuffer, + IN EFI_LBA StartLba, + IN UINTN NumberOfBlocks + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + DataBuffer - TODO: add argument description + StartLba - TODO: add argument description + NumberOfBlocks - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaWriteSectorsExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *DataBuffer, + IN EFI_LBA StartLba, + IN UINTN NumberOfBlocks + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + DataBuffer - TODO: add argument description + StartLba - TODO: add argument description + NumberOfBlocks - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaUdmaReadExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *DataBuffer, + IN EFI_LBA StartLba, + IN UINTN NumberOfBlocks + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + DataBuffer - TODO: add argument description + StartLba - TODO: add argument description + NumberOfBlocks - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaUdmaRead ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *DataBuffer, + IN EFI_LBA StartLba, + IN UINTN NumberOfBlocks + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + DataBuffer - TODO: add argument description + StartLba - TODO: add argument description + NumberOfBlocks - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaUdmaWriteExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *DataBuffer, + IN EFI_LBA StartLba, + IN UINTN NumberOfBlocks + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + DataBuffer - TODO: add argument description + StartLba - TODO: add argument description + NumberOfBlocks - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaUdmaWrite ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *DataBuffer, + IN EFI_LBA StartLba, + IN UINTN NumberOfBlocks + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + DataBuffer - TODO: add argument description + StartLba - TODO: add argument description + NumberOfBlocks - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaCommandIssueExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINT8 AtaCommand, + IN UINT8 Device, + IN UINT16 Feature, + IN UINT16 SectorCount, + IN EFI_LBA LbaAddress + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + AtaCommand - TODO: add argument description + Device - TODO: add argument description + Feature - TODO: add argument description + SectorCount - TODO: add argument description + LbaAddress - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaCommandIssue ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINT8 AtaCommand, + IN UINT8 Device, + IN UINT16 Feature, + IN UINT16 SectorCount, + IN EFI_LBA LbaAddress + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + AtaCommand - TODO: add argument description + Device - TODO: add argument description + Feature - TODO: add argument description + SectorCount - TODO: add argument description + LbaAddress - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaAtapi6Identify ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + + +VOID +AtaSMARTSupport ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaPioDataInExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN OUT VOID *Buffer, + IN UINT32 ByteCount, + IN UINT8 AtaCommand, + IN EFI_LBA StartLba, + IN UINT16 SectorCount + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + Buffer - TODO: add argument description + ByteCount - TODO: add argument description + AtaCommand - TODO: add argument description + StartLba - TODO: add argument description + SectorCount - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaPioDataOutExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *Buffer, + IN UINT32 ByteCount, + IN UINT8 AtaCommand, + IN EFI_LBA StartLba, + IN UINT16 SectorCount + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + Buffer - TODO: add argument description + ByteCount - TODO: add argument description + AtaCommand - TODO: add argument description + StartLba - TODO: add argument description + SectorCount - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +SetDriveParameters ( + IN IDE_BLK_IO_DEV *IdeDev, + IN ATA_DRIVE_PARMS *DriveParameters + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + DriveParameters - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EnableInterrupt ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.c b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.c new file mode 100644 index 0000000000..2b8f52aa54 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.c @@ -0,0 +1,1400 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + idebus.c + +Abstract: + + +Revision History + This module is modified from DXE\IDE module for Ide Contriller Init support + +--*/ + +#include "idebus.h" + +#define PCI_CLASS_MASS_STORAGE 0x01 +#define PCI_SUB_CLASS_IDE 0x01 + + +// +// IDE Bus Driver Binding Protocol Instance +// +EFI_DRIVER_BINDING_PROTOCOL gIDEBusDriverBinding = { + IDEBusDriverBindingSupported, + IDEBusDriverBindingStart, + IDEBusDriverBindingStop, + 0x10, + NULL, + NULL +}; + +// +// *********************************************************************************** +// IDEBusDriverBindingSupported +// *********************************************************************************** +// +EFI_STATUS +EFIAPI +IDEBusDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + Register Driver Binding protocol for this driver. + +Arguments: + This -- A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + ControllerHandle -- The handle of the controller to test. + RemainingDevicePath -- A pointer to the remaining portion of a device path. + +Returns: + EFI_SUCCESS - Driver loaded. + other - Driver not loaded. +--*/ +// TODO: Controller - add argument and description to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_DEV_PATH *Node; + EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeInit; + + if (RemainingDevicePath != NULL) { + Node = (EFI_DEV_PATH *) RemainingDevicePath; + if (Node->DevPath.Type != MESSAGING_DEVICE_PATH || + Node->DevPath.SubType != MSG_ATAPI_DP || + DevicePathNodeLength(&Node->DevPath) != sizeof(ATAPI_DEVICE_PATH)) { + return EFI_UNSUPPORTED; + } + } + + // + // Open the IO Abstraction(s) 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; + } + + // + // Clsoe protocol, don't use device path protocol in the .Support() function + // + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + // + // Verify the Ide Controller Init Protocol, which installed by the + // IdeController module. + // Note 1: PciIo protocol has been opened BY_DRIVER by ide_init, so We can't + // open BY_DRIVER here) That's why we don't check pciio protocol + // Note 2: ide_init driver check ide controller's pci config space, so we dont + // check here any more to save code size + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiIdeControllerInitProtocolGuid, + (VOID **) &IdeInit, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (Status == EFI_ALREADY_STARTED) { + return EFI_SUCCESS; + } + + // + // If protocols were opened normally, closed it + // + gBS->CloseProtocol ( + Controller, + &gEfiIdeControllerInitProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return Status; +} + +// +// *********************************************************************************** +// IDEBusDriverBindingStart +// *********************************************************************************** +// +EFI_STATUS +EFIAPI +IDEBusDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + Start this driver on Controller by detecting all disks and installing + BlockIo protocol on them. + + Arguments: + This - Protocol instance pointer. + Controller - Handle of device to bind driver to. + RemainingDevicePath - Not used, always produce all possible children. + + Returns: + EFI_SUCCESS - This driver is added to ControllerHandle. + EFI_ALREADY_STARTED - This driver is already running on ControllerHandle. + other - This driver does not support this device. + +--*/ +{ + EFI_STATUS Status; + EFI_STATUS SavedStatus; + EFI_PCI_IO_PROTOCOL *PciIo; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_DEV_PATH *Node; + UINT8 IdeChannel; + UINT8 BeginningIdeChannel; + UINT8 EndIdeChannel; + UINT8 IdeDevice; + UINT8 BeginningIdeDevice; + UINT8 EndIdeDevice; + IDE_BLK_IO_DEV *IdeBlkIoDevice[IdeMaxChannel][IdeMaxDevice]; + IDE_BLK_IO_DEV *IdeBlkIoDevicePtr; + IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr[IdeMaxChannel]; + ATA_TRANSFER_MODE TransferMode; + ATA_DRIVE_PARMS DriveParameters; + EFI_DEV_PATH NewNode; + UINT8 ConfigurationOptions; + UINT16 CommandBlockBaseAddr; + UINT16 ControlBlockBaseAddr; + UINTN DataSize; + UINT32 Attributes; + IDE_BUS_DRIVER_PRIVATE_DATA *IdeBusDriverPrivateData; + + // + // Local variables declaration for IdeControllerInit support + // + EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeInit; + BOOLEAN EnumAll; + BOOLEAN ChannelEnabled; + UINT8 ChannelCount; + UINT8 MaxDevices; + EFI_IDENTIFY_DATA IdentifyData; + EFI_ATA_COLLECTIVE_MODE *SupportedModes; + + IdeBusDriverPrivateData = NULL; + SupportedModes = NULL; + + // + // Perform IdeBus initialization + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &ParentDevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) { + return Status; + } + + // + // Now open the IDE_CONTROLLER_INIT protocol. Step7.1 + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiIdeControllerInitProtocolGuid, + (VOID **) &IdeInit, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + // + // The following OpenProtocol function with _GET_PROTOCOL attribute and + // will not return EFI_ALREADY_STARTED, so save it for now + // + SavedStatus = Status; + + if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) { + DEBUG ((EFI_D_ERROR, "Open Init, Status=%x", Status)); + // + // open protocol is not SUCCESS or not ALREADY_STARTED, error exit + // + goto ErrorExit; + } + + // + // Save Enumall and ChannelCount. Step7.2 + // + EnumAll = IdeInit->EnumAll; + ChannelCount = IdeInit->ChannelCount; + + // + // Consume PCI I/O protocol. Note that the OpenProtocol with _GET_PROTOCOL + // attribute will not return EFI_ALREADY_STARTED + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Open PciIo, Status=%x", Status)); + goto ErrorExit; + } + + // + // We must check EFI_ALREADY_STARTED because many ATAPI devices are removable + // + if (SavedStatus != EFI_ALREADY_STARTED) { + IdeBusDriverPrivateData = AllocatePool (sizeof (IDE_BUS_DRIVER_PRIVATE_DATA)); + if (IdeBusDriverPrivateData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + + ZeroMem (IdeBusDriverPrivateData, sizeof (IDE_BUS_DRIVER_PRIVATE_DATA)); + Status = gBS->InstallMultipleProtocolInterfaces ( + &Controller, + &gEfiCallerIdGuid, + IdeBusDriverPrivateData, + NULL + ); + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + } else { + Status = gBS->OpenProtocol ( + Controller, + &gEfiCallerIdGuid, + (VOID **) &IdeBusDriverPrivateData, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + IdeBusDriverPrivateData = NULL; + goto ErrorExit; + } + } + + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationEnable, + EFI_PCI_DEVICE_ENABLE, + NULL + ); + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + // + // Read the environment variable that contains the IDEBus Driver's + // Config options that were set by the Driver Configuration Protocol + // + DataSize = sizeof (ConfigurationOptions); + Status = gRT->GetVariable ( + (CHAR16 *) L"Configuration", + &gEfiCallerIdGuid, + &Attributes, + &DataSize, + &ConfigurationOptions + ); + if (EFI_ERROR (Status)) { + ConfigurationOptions = 0x0f; + } + + if (EnumAll) { + // + // If IdeInit->EnumAll is TRUE, must enumerate all IDE device anyway + // + BeginningIdeChannel = IdePrimary; + EndIdeChannel = IdeSecondary; + BeginningIdeDevice = IdeMaster; + EndIdeDevice = IdeSlave; + } else if (RemainingDevicePath == NULL) { + // + // RemainingDevicePath is NULL, scan IDE bus for each device; + // + BeginningIdeChannel = IdePrimary; + EndIdeChannel = IdeSecondary; + BeginningIdeDevice = IdeMaster; + // + // default, may be redefined by IdeInit + // + EndIdeDevice = IdeSlave; + } else { + // + // RemainingDevicePath is not NULL, only scan the specified device. + // + Node = (EFI_DEV_PATH *) RemainingDevicePath; + BeginningIdeChannel = Node->Atapi.PrimarySecondary; + EndIdeChannel = BeginningIdeChannel; + BeginningIdeDevice = Node->Atapi.SlaveMaster; + EndIdeDevice = BeginningIdeDevice; + } + + // + // Obtain IDE IO port registers' base addresses + // + Status = GetIdeRegistersBaseAddr (PciIo, IdeRegsBaseAddr); + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + // + // Report status code: begin IdeBus initialization + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_PC_RESET), + ParentDevicePath + ); + + // + // Strictly follow the enumeration based on IDE_CONTROLLER_INIT protocol + // + for (IdeChannel = BeginningIdeChannel; IdeChannel <= EndIdeChannel; IdeChannel++) { + + IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelEnumeration, IdeChannel); + + // + // now obtain channel information fron IdeControllerInit protocol. Step9 + // + Status = IdeInit->GetChannelInfo ( + IdeInit, + IdeChannel, + &ChannelEnabled, + &MaxDevices + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "[GetChannel, Status=%x]", Status)); + continue; + } + + if (!ChannelEnabled) { + continue; + } + + EndIdeDevice = (UINT8) EFI_MIN ((MaxDevices - 1), EndIdeDevice); + + // + // Now inform the IDE Controller Init Module. Sept10 + // + IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelReset, IdeChannel); + + // + // No reset channel function implemented. Sept11 + // + IdeInit->NotifyPhase (IdeInit, EfiIdeAfterChannelReset, IdeChannel); + + // + // Step13 + // + IdeInit->NotifyPhase ( + IdeInit, + EfiIdeBusBeforeDevicePresenceDetection, + IdeChannel + ); + // + // -- 1st inner loop --- Master/Slave ------------ Step14 + // + for (IdeDevice = BeginningIdeDevice; IdeDevice <= EndIdeDevice; IdeDevice++) { + // + // Check whether the configuration options allow this device + // + if (!(ConfigurationOptions & (1 << (IdeChannel * 2 + IdeDevice)))) { + continue; + } + + // + // The device has been scanned in another Start(), No need to scan it again + // for perf optimization. + // + if (IdeBusDriverPrivateData->HaveScannedDevice[IdeChannel * 2 + IdeDevice]) { + continue; + } + + // + // create child handle for the detected device. + // + IdeBlkIoDevice[IdeChannel][IdeDevice] = AllocatePool (sizeof (IDE_BLK_IO_DEV)); + if (IdeBlkIoDevice[IdeChannel][IdeDevice] == NULL) { + continue; + } + + IdeBlkIoDevicePtr = IdeBlkIoDevice[IdeChannel][IdeDevice]; + + ZeroMem (IdeBlkIoDevicePtr, sizeof (IDE_BLK_IO_DEV)); + + IdeBlkIoDevicePtr->Signature = IDE_BLK_IO_DEV_SIGNATURE; + IdeBlkIoDevicePtr->Channel = IdeChannel; + IdeBlkIoDevicePtr->Device = IdeDevice; + + // + // initialize Block IO interface's Media pointer + // + IdeBlkIoDevicePtr->BlkIo.Media = &IdeBlkIoDevicePtr->BlkMedia; + + // + // Initialize IDE IO port addresses, including Command Block registers + // and Control Block registers + // + IdeBlkIoDevicePtr->IoPort = AllocatePool (sizeof (IDE_BASE_REGISTERS)); + if (IdeBlkIoDevicePtr->IoPort == NULL) { + continue; + } + + ZeroMem (IdeBlkIoDevicePtr->IoPort, sizeof (IDE_BASE_REGISTERS)); + CommandBlockBaseAddr = IdeRegsBaseAddr[IdeChannel].CommandBlockBaseAddr; + ControlBlockBaseAddr = IdeRegsBaseAddr[IdeChannel].ControlBlockBaseAddr; + + IdeBlkIoDevicePtr->IoPort->Data = CommandBlockBaseAddr; + (*(UINT16 *) &IdeBlkIoDevicePtr->IoPort->Reg1) = (UINT16) (CommandBlockBaseAddr + 0x01); + IdeBlkIoDevicePtr->IoPort->SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02); + IdeBlkIoDevicePtr->IoPort->SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03); + IdeBlkIoDevicePtr->IoPort->CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04); + IdeBlkIoDevicePtr->IoPort->CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05); + IdeBlkIoDevicePtr->IoPort->Head = (UINT16) (CommandBlockBaseAddr + 0x06); + (*(UINT16 *) &IdeBlkIoDevicePtr->IoPort->Reg) = (UINT16) (CommandBlockBaseAddr + 0x07); + + (*(UINT16 *) &IdeBlkIoDevicePtr->IoPort->Alt) = ControlBlockBaseAddr; + IdeBlkIoDevicePtr->IoPort->DriveAddress = (UINT16) (ControlBlockBaseAddr + 0x01); + + IdeBlkIoDevicePtr->IoPort->MasterSlave = (UINT16) ((IdeDevice == IdeMaster) ? 1 : 0); + + IdeBlkIoDevicePtr->PciIo = PciIo; + IdeBlkIoDevicePtr->IdeBusDriverPrivateData = IdeBusDriverPrivateData; + IdeBlkIoDevicePtr->IoPort->BusMasterBaseAddr = IdeRegsBaseAddr[IdeChannel].BusMasterBaseAddr; + + // + // Report Status code: is about to detect IDE drive + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + (EFI_IO_BUS_ATA_ATAPI | EFI_P_PC_PRESENCE_DETECT), + IdeBlkIoDevicePtr->DevicePath + ); + + // + // Discover device, now! + // + PERF_START (0, "DiscoverIdeDevice", "IDE", 0); + Status = DiscoverIdeDevice (IdeBlkIoDevicePtr); + PERF_END (0, "DiscoverIdeDevice", "IDE", 0); + + IdeBusDriverPrivateData->HaveScannedDevice[IdeChannel * 2 + IdeDevice] = TRUE; + IdeBusDriverPrivateData->DeviceProcessed[IdeChannel * 2 + IdeDevice] = FALSE; + + if (!EFI_ERROR (Status)) { + // + // Set Device Path + // + ZeroMem (&NewNode, sizeof (NewNode)); + NewNode.DevPath.Type = MESSAGING_DEVICE_PATH; + NewNode.DevPath.SubType = MSG_ATAPI_DP; + SetDevicePathNodeLength (&NewNode.DevPath, sizeof (ATAPI_DEVICE_PATH)); + + NewNode.Atapi.PrimarySecondary = (UINT8) IdeBlkIoDevicePtr->Channel; + NewNode.Atapi.SlaveMaster = (UINT8) IdeBlkIoDevicePtr->Device; + NewNode.Atapi.Lun = IdeBlkIoDevicePtr->Lun; + IdeBlkIoDevicePtr->DevicePath = AppendDevicePathNode ( + ParentDevicePath, + &NewNode.DevPath + ); + if (IdeBlkIoDevicePtr->DevicePath == NULL) { + ReleaseIdeResources (IdeBlkIoDevicePtr); + continue; + } + + // + // Submit identify data to IDE controller init driver + // + CopyMem (&IdentifyData, IdeBlkIoDevicePtr->pIdData, sizeof (IdentifyData)); + // IdentifyData = *IdeBlkIoDevicePtr->pIdData; + IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice] = TRUE; + IdeInit->SubmitData (IdeInit, IdeChannel, IdeDevice, &IdentifyData); + } else { + // + // Device detection failed + // + IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice] = FALSE; + IdeInit->SubmitData (IdeInit, IdeChannel, IdeDevice, NULL); + ReleaseIdeResources (IdeBlkIoDevicePtr); + IdeBlkIoDevicePtr = NULL; + } + // + // end of 1st inner loop --- + // + } + // + // end of 1st outer loop ========= + // + } + + // + // = 2nd outer loop == Primary/Secondary ================= + // + for (IdeChannel = BeginningIdeChannel; IdeChannel <= EndIdeChannel; IdeChannel++) { + + // + // -- 2nd inner loop --- Master/Slave -------- + // + for (IdeDevice = BeginningIdeDevice; IdeDevice <= EndIdeDevice; IdeDevice++) { + + if (IdeBusDriverPrivateData->DeviceProcessed[IdeChannel * 2 + IdeDevice]) { + continue; + } + + if (!IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice]) { + continue; + } + + Status = IdeInit->CalculateMode ( + IdeInit, + IdeChannel, + IdeDevice, + &SupportedModes + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "[bStStp20S=%x]", Status)); + continue; + } + + IdeBlkIoDevicePtr = IdeBlkIoDevice[IdeChannel][IdeDevice]; + + // + // Set best supported PIO mode on this IDE device + // + if (SupportedModes->PioMode.Mode <= ATA_PIO_MODE_2) { + TransferMode.ModeCategory = ATA_MODE_CATEGORY_DEFAULT_PIO; + } else { + TransferMode.ModeCategory = ATA_MODE_CATEGORY_FLOW_PIO; + } + + TransferMode.ModeNumber = (UINT8) (SupportedModes->PioMode.Mode); + + if (SupportedModes->ExtModeCount == 0){ + Status = SetDeviceTransferMode (IdeBlkIoDevicePtr, &TransferMode); + + if (EFI_ERROR (Status)) { + IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice] = FALSE; + ReleaseIdeResources (IdeBlkIoDevicePtr); + IdeBlkIoDevicePtr = NULL; + continue; + } + } + + // + // Set supported DMA mode on this IDE device. Note that UDMA & MDMA cann't + // be set together. Only one DMA mode can be set to a device. If setting + // DMA mode operation fails, we can continue moving on because we only use + // PIO mode at boot time. DMA modes are used by certain kind of OS booting + // + if (SupportedModes->UdmaMode.Valid) { + + TransferMode.ModeCategory = ATA_MODE_CATEGORY_UDMA; + TransferMode.ModeNumber = (UINT8) (SupportedModes->UdmaMode.Mode); + Status = SetDeviceTransferMode (IdeBlkIoDevicePtr, &TransferMode); + + if (EFI_ERROR (Status)) { + IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice] = FALSE; + ReleaseIdeResources (IdeBlkIoDevicePtr); + IdeBlkIoDevicePtr = NULL; + continue; + } + + EnableInterrupt (IdeBlkIoDevicePtr); + } else if (SupportedModes->MultiWordDmaMode.Valid) { + + TransferMode.ModeCategory = ATA_MODE_CATEGORY_MDMA; + TransferMode.ModeNumber = (UINT8) SupportedModes->MultiWordDmaMode.Mode; + Status = SetDeviceTransferMode (IdeBlkIoDevicePtr, &TransferMode); + + if (EFI_ERROR (Status)) { + IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice] = FALSE; + ReleaseIdeResources (IdeBlkIoDevicePtr); + IdeBlkIoDevicePtr = NULL; + continue; + } + + EnableInterrupt (IdeBlkIoDevicePtr); + } + // + // Init driver parameters + // + DriveParameters.Sector = (UINT8) IdeBlkIoDevicePtr->pIdData->AtaData.sectors_per_track; + DriveParameters.Heads = (UINT8) (IdeBlkIoDevicePtr->pIdData->AtaData.heads - 1); + DriveParameters.MultipleSector = (UINT8) IdeBlkIoDevicePtr->pIdData->AtaData.multi_sector_cmd_max_sct_cnt; + // + // Set Parameters for the device: + // 1) Init + // 2) Establish the block count for READ/WRITE MULTIPLE (EXT) command + // + if ((IdeBlkIoDevicePtr->Type == IdeHardDisk) || (IdeBlkIoDevicePtr->Type == Ide48bitAddressingHardDisk)) { + Status = SetDriveParameters (IdeBlkIoDevicePtr, &DriveParameters); + } + + // + // Record PIO mode used in private data + // + IdeBlkIoDevicePtr->PioMode = SupportedModes->PioMode.Mode; + + // + // Set IDE controller Timing Blocks in the PCI Configuration Space + // + IdeInit->SetTiming (IdeInit, IdeChannel, IdeDevice, SupportedModes); + + // + // Add Component Name for the IDE/ATAPI device that was discovered. + // + IdeBlkIoDevicePtr->ControllerNameTable = NULL; + ADD_NAME (IdeBlkIoDevicePtr); + + Status = gBS->InstallMultipleProtocolInterfaces ( + &IdeBlkIoDevicePtr->Handle, + &gEfiDevicePathProtocolGuid, + IdeBlkIoDevicePtr->DevicePath, + &gEfiBlockIoProtocolGuid, + &IdeBlkIoDevicePtr->BlkIo, + &gEfiDiskInfoProtocolGuid, + &IdeBlkIoDevicePtr->DiskInfo, + NULL + ); + + if (EFI_ERROR (Status)) { + ReleaseIdeResources (IdeBlkIoDevicePtr); + } + + gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + IdeBlkIoDevicePtr->Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + + IdeBusDriverPrivateData->DeviceProcessed[IdeChannel * 2 + IdeDevice] = TRUE; + + // + // Report status code: device eanbled! + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + (EFI_IO_BUS_ATA_ATAPI | EFI_P_PC_ENABLE), + IdeBlkIoDevicePtr->DevicePath + ); + // + // end of 2nd inner loop ---- + // + } + // + // end of 2nd outer loop ========== + // + } + + // + // All configurations done! Notify IdeController to do post initialization + // work such as saving IDE controller PCI settings for S3 resume + // + IdeInit->NotifyPhase (IdeInit, EfiIdeBusPhaseMaximum, 0); + + if (SupportedModes != NULL) { + gBS->FreePool (SupportedModes); + } + + PERF_START (0, "Finish IDE detection", "IDE", 1); + PERF_END (0, "Finish IDE detection", "IDE", 0); + + return EFI_SUCCESS; + +ErrorExit: + + // + // Report error code: controller error + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_EC_CONTROLLER_ERROR), + ParentDevicePath + ); + + gBS->CloseProtocol ( + Controller, + &gEfiIdeControllerInitProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + gBS->UninstallMultipleProtocolInterfaces ( + Controller, + &gEfiCallerIdGuid, + IdeBusDriverPrivateData, + NULL + ); + + if (IdeBusDriverPrivateData != NULL) { + gBS->FreePool (IdeBusDriverPrivateData); + } + + if (SupportedModes != NULL) { + gBS->FreePool (SupportedModes); + } + + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return Status; + +} + +// +// *********************************************************************************** +// IDEBusDriverBindingStop +// *********************************************************************************** +// +EFI_STATUS +EFIAPI +IDEBusDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + + Routine Description: + Stop this driver on Controller Handle. + + Arguments: + This - Protocol instance pointer. + DeviceHandle - Handle of device to stop driver on + NumberOfChildren - Not used + ChildHandleBuffer - Not used + + Returns: + EFI_SUCCESS - This driver is removed DeviceHandle + other - This driver was not removed from this device + +--*/ +// TODO: Controller - add argument and description to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + BOOLEAN AllChildrenStopped; + UINTN Index; + IDE_BUS_DRIVER_PRIVATE_DATA *IdeBusDriverPrivateData; + + IdeBusDriverPrivateData = NULL; + + if (NumberOfChildren == 0) { + + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationDisable, + EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO | EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO | EFI_PCI_DEVICE_ENABLE, + NULL + ); + } + + gBS->OpenProtocol ( + Controller, + &gEfiCallerIdGuid, + (VOID **) &IdeBusDriverPrivateData, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + gBS->UninstallMultipleProtocolInterfaces ( + Controller, + &gEfiCallerIdGuid, + IdeBusDriverPrivateData, + NULL + ); + + if (IdeBusDriverPrivateData != NULL) { + gBS->FreePool (IdeBusDriverPrivateData); + } + // + // Close the bus driver + // + gBS->CloseProtocol ( + Controller, + &gEfiIdeControllerInitProtocolGuid, + This->DriverBindingHandle, + Controller + ); + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return EFI_SUCCESS; + } + + AllChildrenStopped = TRUE; + + for (Index = 0; Index < NumberOfChildren; Index++) { + + Status = DeRegisterIdeDevice (This, Controller, ChildHandleBuffer[Index]); + + if (EFI_ERROR (Status)) { + AllChildrenStopped = FALSE; + } + } + + if (!AllChildrenStopped) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +// +// *********************************************************************************** +// DeRegisterIdeDevice +// *********************************************************************************** +// +EFI_STATUS +DeRegisterIdeDevice ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_HANDLE Handle + ) +/*++ + +Routine Description: + + Deregister an IDE device and free resources + +Arguments: + + This - Protocol instance pointer. + Controller - Ide device handle + Handle - Handle of device to deregister driver on + +Returns: + + EFI_STATUS + +--*/ +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + EFI_BLOCK_IO_PROTOCOL *BlkIo; + IDE_BLK_IO_DEV *IdeBlkIoDevice; + EFI_PCI_IO_PROTOCOL *PciIo; + UINTN Index; + + Status = gBS->OpenProtocol ( + Handle, + &gEfiBlockIoProtocolGuid, + (VOID **) &BlkIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (BlkIo); + + // + // Report Status code: Device disabled + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + (EFI_IO_BUS_ATA_ATAPI | EFI_P_PC_DISABLE), + IdeBlkIoDevice->DevicePath + ); + + // + // Close the child handle + // + Status = gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Handle + ); + + Status = gBS->UninstallMultipleProtocolInterfaces ( + Handle, + &gEfiDevicePathProtocolGuid, + IdeBlkIoDevice->DevicePath, + &gEfiBlockIoProtocolGuid, + &IdeBlkIoDevice->BlkIo, + &gEfiDiskInfoProtocolGuid, + &IdeBlkIoDevice->DiskInfo, + NULL + ); + + if (EFI_ERROR (Status)) { + gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + return Status; + } + + // + // Release allocated resources + // + Index = IdeBlkIoDevice->Channel * 2 + IdeBlkIoDevice->Device; + IdeBlkIoDevice->IdeBusDriverPrivateData->HaveScannedDevice[Index] = FALSE; + + ReleaseIdeResources (IdeBlkIoDevice); + + return EFI_SUCCESS; +} + +// +// *********************************************************************************** +// IDEBlkIoReset +// *********************************************************************************** +// +EFI_STATUS +EFIAPI +IDEBlkIoReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: ExtendedVerification - add argument and description to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +{ + IDE_BLK_IO_DEV *IdeBlkIoDevice; + EFI_STATUS Status; + + IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (This); + // + // Requery IDE IO resources in case of the switch of native and legacy modes + // + ReassignIdeResources (IdeBlkIoDevice); + + // + // for ATA device, using ATA reset method + // + if (IdeBlkIoDevice->Type == IdeHardDisk) { + return AtaSoftReset (IdeBlkIoDevice); + } + + if (IdeBlkIoDevice->Type == IdeUnknown) { + return EFI_DEVICE_ERROR; + } + + // + // for ATAPI device, using ATAPI reset method + // + Status = AtapiSoftReset (IdeBlkIoDevice); + if (ExtendedVerification) { + Status = AtaSoftReset (IdeBlkIoDevice); + } + + return Status; +} + +EFI_STATUS +EFIAPI +IDEBlkIoReadBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Read data from block io device + +Arguments: + + This - Protocol instance pointer. + MediaId - The media ID of the device + LBA - Starting LBA address to read data + BufferSize - The size of data to be read + Buffer - Caller supplied buffer to save data + +Returns: + + read data status + +--*/ +// TODO: EFI_DEVICE_ERROR - add return value to function comment +{ + IDE_BLK_IO_DEV *IdeBlkIoDevice; + + IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (This); + + // + // Requery IDE IO resources in case of the switch of native and legacy modes + // + ReassignIdeResources (IdeBlkIoDevice); + + // + // For ATA compatible device, use ATA read block's mechanism + // + if (IdeBlkIoDevice->Type == IdeHardDisk || + IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) { + return AtaBlkIoReadBlocks ( + IdeBlkIoDevice, + MediaId, + LBA, + BufferSize, + Buffer + ); + } + + if (IdeBlkIoDevice->Type == IdeUnknown) { + return EFI_DEVICE_ERROR; + } + + // + // for ATAPI device, using ATAPI read block's mechanism + // + return AtapiBlkIoReadBlocks ( + IdeBlkIoDevice, + MediaId, + LBA, + BufferSize, + Buffer + ); + +} + +EFI_STATUS +EFIAPI +IDEBlkIoWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Write data to block io device + +Arguments: + + This - Protocol instance pointer. + MediaId - The media ID of the device + LBA - Starting LBA address to write data + BufferSize - The size of data to be written + Buffer - Caller supplied buffer to save data + +Returns: + + write data status + +--*/ +// TODO: EFI_DEVICE_ERROR - add return value to function comment +{ + IDE_BLK_IO_DEV *IdeBlkIoDevice; + + IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (This); + // + // Requery IDE IO resources in case of the switch of native and legacy modes + // + ReassignIdeResources (IdeBlkIoDevice); + + // + // for ATA device, using ATA write block's mechanism + // + if (IdeBlkIoDevice->Type == IdeHardDisk || + IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) { + + return AtaBlkIoWriteBlocks ( + IdeBlkIoDevice, + MediaId, + LBA, + BufferSize, + Buffer + ); + } + + if (IdeBlkIoDevice->Type == IdeUnknown) { + return EFI_DEVICE_ERROR; + } + + // + // for ATAPI device, using ATAPI write block's mechanism + // + return AtapiBlkIoWriteBlocks ( + IdeBlkIoDevice, + MediaId, + LBA, + BufferSize, + Buffer + ); +} + +// +// *********************************************************************************** +// IDEBlkIoFlushBlocks +// *********************************************************************************** +// +EFI_STATUS +EFIAPI +IDEBlkIoFlushBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + // + // return directly + // + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +IDEDiskInfoInquiry ( + IN EFI_DISK_INFO_PROTOCOL *This, + IN OUT VOID *InquiryData, + IN OUT UINT32 *InquiryDataSize + ) +/*++ + + Routine Description: + Return the results of the Inquiry command to a drive in InquiryData. + Data format of Inquiry data is defined by the Interface GUID. + + Arguments: + This - Protocol instance pointer. + InquiryData - Results of Inquiry command to device + InquiryDataSize - Size of InquiryData in bytes. + + Returns: + EFI_SUCCESS - InquiryData valid + EFI_NOT_FOUND - Device does not support this data class + EFI_DEVICE_ERROR - Error reading InquiryData from device + EFI_BUFFER_TOO_SMALL - IntquiryDataSize not big enough + +--*/ +{ + IDE_BLK_IO_DEV *IdeBlkIoDevice; + + IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_DISK_INFO_THIS (This); + + if (*InquiryDataSize < sizeof (INQUIRY_DATA)) { + *InquiryDataSize = sizeof (INQUIRY_DATA); + return EFI_BUFFER_TOO_SMALL; + } + + if (IdeBlkIoDevice->pInquiryData == NULL) { + return EFI_NOT_FOUND; + } + + gBS->CopyMem (InquiryData, IdeBlkIoDevice->pInquiryData, sizeof (INQUIRY_DATA)); + *InquiryDataSize = sizeof (INQUIRY_DATA); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +IDEDiskInfoIdentify ( + IN EFI_DISK_INFO_PROTOCOL *This, + IN OUT VOID *IdentifyData, + IN OUT UINT32 *IdentifyDataSize + ) +/*++ + + Routine Description: + Return the results of the Identify command to a drive in IdentifyData. + Data format of Identify data is defined by the Interface GUID. + + Arguments: + This - Protocol instance pointer. + IdentifyData - Results of Identify command to device + IdentifyDataSize - Size of IdentifyData in bytes. + + Returns: + EFI_SUCCESS - IdentifyData valid + EFI_NOT_FOUND - Device does not support this data class + EFI_DEVICE_ERROR - Error reading IdentifyData from device + EFI_BUFFER_TOO_SMALL - IdentifyDataSize not big enough + +--*/ +{ + IDE_BLK_IO_DEV *IdeBlkIoDevice; + + IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_DISK_INFO_THIS (This); + + if (*IdentifyDataSize < sizeof (EFI_IDENTIFY_DATA)) { + *IdentifyDataSize = sizeof (EFI_IDENTIFY_DATA); + return EFI_BUFFER_TOO_SMALL; + } + + if (IdeBlkIoDevice->pIdData == NULL) { + return EFI_NOT_FOUND; + } + + gBS->CopyMem (IdentifyData, IdeBlkIoDevice->pIdData, sizeof (EFI_IDENTIFY_DATA)); + *IdentifyDataSize = sizeof (EFI_IDENTIFY_DATA); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +IDEDiskInfoSenseData ( + IN EFI_DISK_INFO_PROTOCOL *This, + IN OUT VOID *SenseData, + IN OUT UINT32 *SenseDataSize, + OUT UINT8 *SenseDataNumber + ) +/*++ + + Routine Description: + Return the results of the Request Sense command to a drive in SenseData. + Data format of Sense data is defined by the Interface GUID. + + Arguments: + This - Protocol instance pointer. + SenseData - Results of Request Sense command to device + SenseDataSize - Size of SenseData in bytes. + SenseDataNumber - Type of SenseData + + Returns: + EFI_SUCCESS - InquiryData valid + EFI_NOT_FOUND - Device does not support this data class + EFI_DEVICE_ERROR - Error reading InquiryData from device + EFI_BUFFER_TOO_SMALL - SenseDataSize not big enough + +--*/ +{ + return EFI_NOT_FOUND; +} + +EFI_STATUS +EFIAPI +IDEDiskInfoWhichIde ( + IN EFI_DISK_INFO_PROTOCOL *This, + OUT UINT32 *IdeChannel, + OUT UINT32 *IdeDevice + ) +/*++ + + Routine Description: + Return the results of the Request Sense command to a drive in SenseData. + Data format of Sense data is defined by the Interface GUID. + + Arguments: + This - Protocol instance pointer. + IdeChannel - Primary or Secondary + IdeDevice - Master or Slave + + Returns: + EFI_SUCCESS - IdeChannel and IdeDevice are valid + EFI_UNSUPPORTED - This is not an IDE device + +--*/ +{ + IDE_BLK_IO_DEV *IdeBlkIoDevice; + + IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_DISK_INFO_THIS (This); + *IdeChannel = IdeBlkIoDevice->Channel; + *IdeDevice = IdeBlkIoDevice->Device; + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.h b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.h new file mode 100644 index 0000000000..2e3caaf1b7 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.h @@ -0,0 +1,439 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + idebus.h + +Abstract: + + Header file for IDE Bus Driver. + +Revision History +++*/ + +// TODO: fix comment to end with --*/ +#ifndef _IDE_BUS_H +#define _IDE_BUS_H + + +#include +#include "idedata.h" + +// +// Extra Definition to porting +// +#define EFI_MIN(a, b) (((a) < (b)) ? (a) : (b)) + +#define MAX_IDE_DEVICE 4 +#define MAX_IDE_CHANNELS 2 +#define MAX_IDE_DRIVES 2 + +typedef struct { + BOOLEAN HaveScannedDevice[MAX_IDE_DEVICE]; + BOOLEAN DeviceFound[MAX_IDE_DEVICE]; + BOOLEAN DeviceProcessed[MAX_IDE_DEVICE]; +} IDE_BUS_DRIVER_PRIVATE_DATA; + +#define IDE_BLK_IO_DEV_SIGNATURE EFI_SIGNATURE_32 ('i', 'b', 'i', 'd') + +typedef struct { + UINT32 Signature; + + EFI_HANDLE Handle; + EFI_BLOCK_IO_PROTOCOL BlkIo; + EFI_BLOCK_IO_MEDIA BlkMedia; + EFI_DISK_INFO_PROTOCOL DiskInfo; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_PCI_IO_PROTOCOL *PciIo; + IDE_BUS_DRIVER_PRIVATE_DATA *IdeBusDriverPrivateData; + + // + // Local Data for IDE interface goes here + // + EFI_IDE_CHANNEL Channel; + EFI_IDE_DEVICE Device; + UINT16 Lun; + IDE_DEVICE_TYPE Type; + + IDE_BASE_REGISTERS *IoPort; + UINT16 AtapiError; + + INQUIRY_DATA *pInquiryData; + EFI_IDENTIFY_DATA *pIdData; + ATA_PIO_MODE PioMode; + ATA_UDMA_MODE UDma_Mode; + CHAR8 ModelName[41]; + REQUEST_SENSE_DATA *SenseData; + UINT8 SenseDataNumber; + UINT8 *Cache; + + EFI_UNICODE_STRING_TABLE *ControllerNameTable; +} IDE_BLK_IO_DEV; + +#include "ComponentName.h" + +#define IDE_BLOCK_IO_DEV_FROM_THIS(a) CR (a, IDE_BLK_IO_DEV, BlkIo, IDE_BLK_IO_DEV_SIGNATURE) +#define IDE_BLOCK_IO_DEV_FROM_DISK_INFO_THIS(a) CR (a, IDE_BLK_IO_DEV, DiskInfo, IDE_BLK_IO_DEV_SIGNATURE) + +// +// Global Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gIDEBusDriverBinding; + +#include "ide.h" + +// +// Prototypes +// Driver model protocol interface +// +EFI_STATUS +EFIAPI +IDEBusControllerDriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ImageHandle - TODO: add argument description + SystemTable - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +IDEBusDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Controller - TODO: add argument description + RemainingDevicePath - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +IDEBusDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Controller - TODO: add argument description + RemainingDevicePath - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +IDEBusDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Controller - TODO: add argument description + NumberOfChildren - TODO: add argument description + ChildHandleBuffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +// +// Block I/O Protocol Interface +// +EFI_STATUS +EFIAPI +IDEBlkIoReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + ExtendedVerification - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +IDEBlkIoReadBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + MediaId - TODO: add argument description + LBA - TODO: add argument description + BufferSize - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +IDEBlkIoWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + MediaId - TODO: add argument description + LBA - TODO: add argument description + BufferSize - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +IDEBlkIoFlushBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +IDERegisterDecodeEnableorDisable ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN BOOLEAN Enable + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIo - TODO: add argument description + Enable - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +IDEDiskInfoInquiry ( + IN EFI_DISK_INFO_PROTOCOL *This, + IN OUT VOID *InquiryData, + IN OUT UINT32 *IntquiryDataSize + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + InquiryData - TODO: add argument description + IntquiryDataSize - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +IDEDiskInfoIdentify ( + IN EFI_DISK_INFO_PROTOCOL *This, + IN OUT VOID *IdentifyData, + IN OUT UINT32 *IdentifyDataSize + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + IdentifyData - TODO: add argument description + IdentifyDataSize - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +IDEDiskInfoSenseData ( + IN EFI_DISK_INFO_PROTOCOL *This, + IN OUT VOID *SenseData, + IN OUT UINT32 *SenseDataSize, + OUT UINT8 *SenseDataNumber + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + SenseData - TODO: add argument description + SenseDataSize - TODO: add argument description + SenseDataNumber - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +IDEDiskInfoWhichIde ( + IN EFI_DISK_INFO_PROTOCOL *This, + OUT UINT32 *IdeChannel, + OUT UINT32 *IdeDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + IdeChannel - TODO: add argument description + IdeDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.mbd b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.mbd new file mode 100644 index 0000000000..f6e3ba1c8a --- /dev/null +++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.mbd @@ -0,0 +1,45 @@ + + + + + IdeBus + 69FD8E47-A161-4550-B01A-5594CEB2B2B2 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-22 16:27 + + + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + EdkDxePrintLib + BaseLib + DxeMemoryAllocationLib + UefiDevicePathLib + BasePerformanceLibNull + + diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.msa b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.msa new file mode 100644 index 0000000000..1b303c6823 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.msa @@ -0,0 +1,90 @@ + + + + + IdeBus + DXE_DRIVER + BS_DRIVER + 69FD8E47-A161-4550-B01A-5594CEB2B2B2 + 0 + Component description file for PS2 keyboard module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-22 16:27 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + BaseLib + UefiLib + BaseMemoryLib + ReportStatusCodeLib + MemoryAllocationLib + PerformanceLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + DevicePathLib + + + idebus.h + ide.h + idedata.h + idebus.c + ide.c + ata.c + atapi.c + ComponentName.c + ComponentName.h + + + MdePkg + EdkModulePkg + + + DevicePath + PciIo + IdeControllerInit + BlockIo + DiskInfo + + + + Configuration + 0x69fd8e47, 0xa161, 0x4550, 0xb0, 0x1a, 0x55, 0x94, 0xce, 0xb2, 0xb2, 0xb2 + + + + + DiskInfoIde + + + + + + + + gIDEBusDriverBinding + gIDEBusComponentName + + + diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebusLite.mbd b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebusLite.mbd new file mode 100644 index 0000000000..fa4bc333d4 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebusLite.mbd @@ -0,0 +1,44 @@ + + + + + IdeBusLite + 69FD8E47-A161-4550-B01A-5594CEB2B2B2 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:18 + + + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibNull + EdkDxePrintLib + BaseLib + UefiDevicePathLib + BasePerformanceLibNull + + diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebusLite.msa b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebusLite.msa new file mode 100644 index 0000000000..71fc18ddce --- /dev/null +++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebusLite.msa @@ -0,0 +1,86 @@ + + + + + IdeBusLite + DXE_DRIVER + BS_DRIVER + 69FD8E47-A161-4550-B01A-5594CEB2B2B2 + 0 + Component description file for PS2 keyboard module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:18 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + BaseLib + UefiLib + BaseMemoryLib + PerformanceLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + DevicePathLib + + + idebus.h + ide.h + idedata.h + idebus.c + ide.c + ata.c + atapi.c + + + MdePkg + EdkModulePkg + + + DevicePath + PciIo + IdeControllerInit + BlockIo + DiskInfo + + + + DiskInfoIde + + + DiskInfoScsi + + + DiskInfoUsb + + + + + + + + gIDEBusDriverBinding + gIDEBusComponentName + + + diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idedata.h b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idedata.h new file mode 100644 index 0000000000..50b1f05a47 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idedata.h @@ -0,0 +1,879 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + idedata.h + +Abstract: + + Header file for IDE Bus Driver's Data Structures + +Revision History +++*/ + +// TODO: fix comment to end with --*/ +#ifndef _IDE_DATA_H +#define _IDE_DATA_H + +// +// bit definition +// +#define bit0 (1 << 0) +#define bit1 (1 << 1) +#define bit2 (1 << 2) +#define bit3 (1 << 3) +#define bit4 (1 << 4) +#define bit5 (1 << 5) +#define bit6 (1 << 6) +#define bit7 (1 << 7) +#define bit8 (1 << 8) +#define bit9 (1 << 9) +#define bit10 (1 << 10) +#define bit11 (1 << 11) +#define bit12 (1 << 12) +#define bit13 (1 << 13) +#define bit14 (1 << 14) +#define bit15 (1 << 15) +#define bit16 (1 << 16) +#define bit17 (1 << 17) +#define bit18 (1 << 18) +#define bit19 (1 << 19) +#define bit20 (1 << 20) +#define bit21 (1 << 21) +#define bit22 (1 << 22) +#define bit23 (1 << 23) +#define bit24 (1 << 24) +#define bit25 (1 << 25) +#define bit26 (1 << 26) +#define bit27 (1 << 27) +#define bit28 (1 << 28) +#define bit29 (1 << 29) +#define bit30 (1 << 30) +#define bit31 (1 << 31) + +// +// common constants +// +#define STALL_1_MILLI_SECOND 1000 // stall 1 ms +#define STALL_1_SECOND 1000000 // stall 1 second +typedef enum { + IdePrimary = 0, + IdeSecondary = 1, + IdeMaxChannel = 2 +} EFI_IDE_CHANNEL; + +typedef enum { + IdeMaster = 0, + IdeSlave = 1, + IdeMaxDevice = 2 +} EFI_IDE_DEVICE; + +typedef enum { + IdeMagnetic, /* ZIP Drive or LS120 Floppy Drive */ + IdeCdRom, /* ATAPI CDROM */ + IdeHardDisk, /* Hard Disk */ + Ide48bitAddressingHardDisk, /* Hard Disk larger than 120GB */ + IdeUnknown +} IDE_DEVICE_TYPE; + +// +// IDE Registers +// +typedef union { + UINT16 Command; /* when write */ + UINT16 Status; /* when read */ +} IDE_CMD_OR_STATUS; + +typedef union { + UINT16 Error; /* when read */ + UINT16 Feature; /* when write */ +} IDE_ERROR_OR_FEATURE; + +typedef union { + UINT16 AltStatus; /* when read */ + UINT16 DeviceControl; /* when write */ +} IDE_AltStatus_OR_DeviceControl; + +// +// IDE registers set +// +typedef struct { + UINT16 Data; + IDE_ERROR_OR_FEATURE Reg1; + UINT16 SectorCount; + UINT16 SectorNumber; + UINT16 CylinderLsb; + UINT16 CylinderMsb; + UINT16 Head; + IDE_CMD_OR_STATUS Reg; + + IDE_AltStatus_OR_DeviceControl Alt; + UINT16 DriveAddress; + + UINT16 MasterSlave; + UINT16 BusMasterBaseAddr; +} IDE_BASE_REGISTERS; + +// +// IDE registers' base addresses +// +typedef struct { + UINT16 CommandBlockBaseAddr; + UINT16 ControlBlockBaseAddr; + UINT16 BusMasterBaseAddr; +} IDE_REGISTERS_BASE_ADDR; + +// +// Bit definitions in Programming Interface byte of the Class Code field +// in PCI IDE controller's Configuration Space +// +#define IDE_PRIMARY_OPERATING_MODE bit0 +#define IDE_PRIMARY_PROGRAMMABLE_INDICATOR bit1 +#define IDE_SECONDARY_OPERATING_MODE bit2 +#define IDE_SECONDARY_PROGRAMMABLE_INDICATOR bit3 + +// +// IDE registers bit definitions +// + +// +// Err Reg +// +#define BBK_ERR bit7 /* Bad block detected */ +#define UNC_ERR bit6 /* Uncorrectable Data */ +#define MC_ERR bit5 /* Media Change */ +#define IDNF_ERR bit4 /* ID Not Found */ +#define MCR_ERR bit3 /* Media Change Requested */ +#define ABRT_ERR bit2 /* Aborted Command */ +#define TK0NF_ERR bit1 /* Track 0 Not Found */ +#define AMNF_ERR bit0 /* Address Mark Not Found */ + +// +// Device/Head Reg +// +#define LBA_MODE bit6 +#define DEV bit4 +#define HS3 bit3 +#define HS2 bit2 +#define HS1 bit1 +#define HS0 bit0 +#define CHS_MODE (0) +#define DRV0 (0) +#define DRV1 (1) +#define MST_DRV DRV0 +#define SLV_DRV DRV1 + +// +// Status Reg +// +#define BSY bit7 /* Controller Busy */ +#define DRDY bit6 /* Drive Ready */ +#define DWF bit5 /* Drive Write Fault */ +#define DSC bit4 /* Disk Seek Complete */ +#define DRQ bit3 /* Data Request */ +#define CORR bit2 /* Corrected Data */ +#define IDX bit1 /* Index */ +#define ERR bit0 /* Error */ + +// +// Device Control Reg +// +#define SRST bit2 /* Software Reset */ +#define IEN_L bit1 /* Interrupt Enable #*/ + +// +// Bus Master Reg +// +#define BMIC_nREAD bit3 +#define BMIC_START bit0 +#define BMIS_INTERRUPT bit2 +#define BMIS_ERROR bit1 + +#define BMICP_OFFSET 0x00 +#define BMISP_OFFSET 0x02 +#define BMIDP_OFFSET 0x04 +#define BMICS_OFFSET 0x08 +#define BMISS_OFFSET 0x0A +#define BMIDS_OFFSET 0x0C + +// +// Time Out Value For IDE Device Polling +// + +// +// ATATIMEOUT is used for waiting time out for ATA device +// + +// +// 1 second +// +#define ATATIMEOUT 1000 + +// +// ATAPITIMEOUT is used for waiting operation +// except read and write time out for ATAPI device +// + +// +// 1 second +// +#define ATAPITIMEOUT 1000 + +// +// ATAPILONGTIMEOUT is used for waiting read and +// write operation timeout for ATAPI device +// + +// +// 2 seconds +// +#define CDROMLONGTIMEOUT 2000 + +// +// 5 seconds +// +#define ATAPILONGTIMEOUT 5000 + +// +// ATA Commands Code +// +#define ATA_INITIALIZE_DEVICE 0x91 + +// +// Class 1 +// +#define IDENTIFY_DRIVE_CMD 0xec +#define READ_BUFFER_CMD 0xe4 +#define READ_SECTORS_CMD 0x20 +#define READ_SECTORS_WITH_RETRY_CMD 0x21 +#define READ_LONG_CMD 0x22 +#define READ_LONG_WITH_RETRY_CMD 0x23 +// +// Class 1 - Atapi6 enhanced commands +// +#define READ_SECTORS_EXT_CMD 0x24 + +// +// Class 2 +// +#define FORMAT_TRACK_CMD 0x50 +#define WRITE_BUFFER_CMD 0xe8 +#define WRITE_SECTORS_CMD 0x30 +#define WRITE_SECTORS_WITH_RETRY_CMD 0x31 +#define WRITE_LONG_CMD 0x32 +#define WRITE_LONG_WITH_RETRY_CMD 0x33 +#define WRITE_VERIFY_CMD 0x3c +// +// Class 2 - Atapi6 enhanced commands +// +#define WRITE_SECTORS_EXT_CMD 0x34 + +// +// Class 3 +// +#define ACK_MEDIA_CHANGE_CMD 0xdb +#define BOOT_POST_BOOT_CMD 0xdc +#define BOOT_PRE_BOOT_CMD 0xdd +#define CHECK_POWER_MODE_CMD 0x98 +#define CHECK_POWER_MODE_CMD_ALIAS 0xe5 +#define DOOR_LOCK_CMD 0xde +#define DOOR_UNLOCK_CMD 0xdf +#define EXEC_DRIVE_DIAG_CMD 0x90 +#define IDLE_CMD_ALIAS 0x97 +#define IDLE_CMD 0xe3 +#define IDLE_IMMEDIATE_CMD 0x95 +#define IDLE_IMMEDIATE_CMD_ALIAS 0xe1 +#define INIT_DRIVE_PARAM_CMD 0x91 +#define RECALIBRATE_CMD 0x10 /* aliased to 1x */ +#define READ_DRIVE_STATE_CMD 0xe9 +#define SET_MULTIPLE_MODE_CMD 0xC6 +#define READ_DRIVE_STATE_CMD 0xe9 +#define READ_VERIFY_CMD 0x40 +#define READ_VERIFY_WITH_RETRY_CMD 0x41 +#define SEEK_CMD 0x70 /* aliased to 7x */ +#define SET_FEATURES_CMD 0xef +#define STANDBY_CMD 0x96 +#define STANDBY_CMD_ALIAS 0xe2 +#define STANDBY_IMMEDIATE_CMD 0x94 +#define STANDBY_IMMEDIATE_CMD_ALIAS 0xe0 + +// +// Class 4 +// +#define READ_DMA_CMD 0xc8 +#define READ_DMA_WITH_RETRY_CMD 0xc9 +#define READ_DMA_EXT_CMD 0x25 +#define WRITE_DMA_CMD 0xca +#define WRITE_DMA_WITH_RETRY_CMD 0xcb +#define WRITE_DMA_EXT_CMD 0x35 + +// +// Class 5 +// +#define READ_MULTIPLE_CMD 0xc4 +#define REST_CMD 0xe7 +#define RESTORE_DRIVE_STATE_CMD 0xea +#define SET_SLEEP_MODE_CMD 0x99 +#define SET_SLEEP_MODE_CMD_ALIAS 0xe6 +#define WRITE_MULTIPLE_CMD 0xc5 +#define WRITE_SAME_CMD 0xe9 + +// +// Class 6 - Host protected area access feature set +// +#define READ_NATIVE_MAX_ADDRESS_CMD 0xf8 +#define SET_MAX_ADDRESS_CMD 0xf9 + +// +// Class 6 - ATA/ATAPI-6 enhanced commands +// +#define READ_NATIVE_MAX_ADDRESS_EXT_CMD 0x27 +#define SET_MAX_ADDRESS_CMD_EXT 0x37 + +// +// Class 6 - SET_MAX related sub command (in feature register) +// +#define PARTIES_SET_MAX_ADDRESS_SUB_CMD 0x00 +#define PARTIES_SET_PASSWORD_SUB_CMD 0x01 +#define PARTIES_LOCK_SUB_CMD 0x02 +#define PARTIES_UNLOCK_SUB_CMD 0x03 +#define PARTIES_FREEZE_SUB_CMD 0x04 + +// +// S.M.A.R.T +// +#define ATA_SMART_CMD 0xb0 +#define ATA_CONSTANT_C2 0xc2 +#define ATA_CONSTANT_4F 0x4f +#define ATA_SMART_ENABLE_OPERATION 0xd8 +#define ATA_SMART_RETURN_STATUS 0xda + +// +// Error codes for Exec Drive Diag +// +#define DRIV_DIAG_NO_ERROR (0x01) +#define DRIV_DIAG_FORMATTER_ERROR (0x02) +#define DRIV_DIAG_DATA_BUFFER_ERROR (0x03) +#define DRIV_DIAG_ECC_CKT_ERRROR (0x04) +#define DRIV_DIAG_UP_ERROR (0x05) +#define DRIV_DIAG_SLAVE_DRV_ERROR (0x80) /* aliased to 0x8x */ + +// +// Codes for Format Track +// +#define FORMAT_GOOD_SECTOR (0x00) +#define FORMAT_SUSPEND_ALLOC (0x01) +#define FORMAT_REALLOC_SECTOR (0x02) +#define FORMAT_MARK_SECTOR_DEFECTIVE (0x03) + +// +// IDE_IDENTIFY bits +// config bits : +// +#define ID_CONFIG_RESERVED0 bit0 +#define ID_CONFIG_HARD_SECTORED_DRIVE bit1 +#define ID_CONFIG_SOFT_SECTORED_DRIVE bit2 +#define ID_CONFIG_NON_MFM bit3 +#define ID_CONFIG_15uS_HEAD_SWITCHING bit4 +#define ID_CONFIG_SPINDLE_MOTOR_CONTROL bit5 +#define ID_CONFIG_HARD_DRIVE bit6 +#define ID_CONFIG_CHANGEABLE_MEDIUM bit7 +#define ID_CONFIG_DATA_RATE_TO_5MHZ bit8 +#define ID_CONFIG_DATA_RATE_5_TO_10MHZ bit9 +#define ID_CONFIG_DATA_RATE_ABOVE_10MHZ bit10 +#define ID_CONFIG_MOTOR_SPEED_TOLERANCE_ABOVE_0_5_PERC bit11 +#define ID_CONFIG_DATA_CLK_OFFSET_AVAIL bit12 +#define ID_CONFIG_TRACK_OFFSET_AVAIL bit13 +#define ID_CONFIG_SPEED_TOLERANCE_GAP_NECESSARY bit14 +#define ID_CONFIG_RESERVED1 bit15 + +#define ID_DOUBLE_WORD_IO_POSSIBLE bit01 +#define ID_LBA_SUPPORTED bit9 +#define ID_DMA_SUPPORTED bit8 + +#define SET_FEATURE_ENABLE_8BIT_TRANSFER (0x01) +#define SET_FEATURE_ENABLE_WRITE_CACHE (0x02) +#define SET_FEATURE_TRANSFER_MODE (0x03) +#define SET_FEATURE_WRITE_SAME_WRITE_SPECIFIC_AREA (0x22) +#define SET_FEATURE_DISABLE_RETRIES (0x33) +// +// for Read & Write Longs +// +#define SET_FEATURE_VENDOR_SPEC_ECC_LENGTH (0x44) +#define SET_FEATURE_PLACE_NO_OF_CACHE_SEGMENTS_IN_SECTOR_NO_REG (0x54) +#define SET_FEATURE_DISABLE_READ_AHEAD (0x55) +#define SET_FEATURE_MAINTAIN_PARAM_AFTER_RESET (0x66) +#define SET_FEATURE_DISABLE_ECC (0x77) +#define SET_FEATURE_DISABLE_8BIT_TRANSFER (0x81) +#define SET_FEATURE_DISABLE_WRITE_CACHE (0x82) +#define SET_FEATURE_ENABLE_ECC (0x88) +#define SET_FEATURE_ENABLE_RETRIES (0x99) +#define SET_FEATURE_ENABLE_READ_AHEAD (0xaa) +#define SET_FEATURE_SET_SECTOR_CNT_REG_AS_NO_OF_READ_AHEAD_SECTORS (0xab) +#define SET_FEATURE_ALLOW_REST_MODE (0xac) +// +// for Read & Write Longs +// +#define SET_FEATURE_4BYTE_ECC (0xbb) +#define SET_FEATURE_DEFALUT_FEATURES_ON_SOFTWARE_RESET (0xcc) +#define SET_FEATURE_WRITE_SAME_TO_WRITE_ENTIRE_MEDIUM (0xdd) + +#define BLOCK_TRANSFER_MODE (0x00) +#define SINGLE_WORD_DMA_TRANSFER_MODE (0x10) +#define MULTI_WORD_DMA_TRANSFER_MODE (0x20) +#define TRANSFER_MODE_MASK (0x07) // 3 LSBs + +// +// Drive 0 - Head 0 +// +#define DEFAULT_DRIVE (0x00) +#define DEFAULT_CMD (0xa0) +// +// default content of device control register, disable INT +// +#define DEFAULT_CTL (0x0a) +#define DEFAULT_IDE_BM_IO_BASE_ADR (0xffa0) + +// +// ATAPI6 related data structure definition +// + +// +// The maximum sectors count in 28 bit addressing mode +// +#define MAX_28BIT_ADDRESSING_CAPACITY 0xfffffff + +// +// Move the IDENTIFY section to DXE\Protocol\IdeControllerInit +// + +// +// ATAPI Command +// +#define ATAPI_SOFT_RESET_CMD 0x08 +#define ATAPI_PACKET_CMD 0xA0 +#define PACKET_CMD 0xA0 +#define ATAPI_IDENTIFY_DEVICE_CMD 0xA1 +#define ATAPI_SERVICE_CMD 0xA2 + +// +// ATAPI Packet Command +// +#pragma pack(1) + +typedef struct { + UINT8 opcode; + UINT8 reserved_1; + UINT8 reserved_2; + UINT8 reserved_3; + UINT8 reserved_4; + UINT8 reserved_5; + UINT8 reserved_6; + UINT8 reserved_7; + UINT8 reserved_8; + UINT8 reserved_9; + UINT8 reserved_10; + UINT8 reserved_11; +} TEST_UNIT_READY_CMD; + +typedef struct { + UINT8 opcode; + UINT8 reserved_1 : 4; + UINT8 lun : 4; + UINT8 page_code; + UINT8 reserved_3; + UINT8 allocation_length; + UINT8 reserved_5; + UINT8 reserved_6; + UINT8 reserved_7; + UINT8 reserved_8; + UINT8 reserved_9; + UINT8 reserved_10; + UINT8 reserved_11; +} INQUIRY_CMD; + +typedef struct { + UINT8 opcode; + UINT8 reserved_1 : 4; + UINT8 lun : 4; + UINT8 reserved_2; + UINT8 reserved_3; + UINT8 allocation_length; + UINT8 reserved_5; + UINT8 reserved_6; + UINT8 reserved_7; + UINT8 reserved_8; + UINT8 reserved_9; + UINT8 reserved_10; + UINT8 reserved_11; +} REQUEST_SENSE_CMD; + +typedef struct { + UINT8 opcode; + UINT8 reserved_1 : 4; + UINT8 lun : 4; + UINT8 page_code : 4; + UINT8 page_control : 4; + UINT8 reserved_3; + UINT8 reserved_4; + UINT8 reserved_5; + UINT8 reserved_6; + UINT8 parameter_list_length_hi; + UINT8 parameter_list_length_lo; + UINT8 reserved_9; + UINT8 reserved_10; + UINT8 reserved_11; +} MODE_SENSE_CMD; + +typedef struct { + UINT8 opcode; + UINT8 reserved_1 : 5; + UINT8 lun : 3; + UINT8 Lba0; + UINT8 Lba1; + UINT8 Lba2; + UINT8 Lba3; + UINT8 reserved_6; + UINT8 TranLen0; + UINT8 TranLen1; + UINT8 reserved_9; + UINT8 reserved_10; + UINT8 reserved_11; +} READ10_CMD; + +typedef struct { + UINT8 opcode; + UINT8 reserved_1; + UINT8 reserved_2; + UINT8 reserved_3; + UINT8 reserved_4; + UINT8 reserved_5; + UINT8 reserved_6; + UINT8 allocation_length_hi; + UINT8 allocation_length_lo; + UINT8 reserved_9; + UINT8 reserved_10; + UINT8 reserved_11; +} READ_FORMAT_CAP_CMD; + +typedef union { + UINT16 Data16[6]; + TEST_UNIT_READY_CMD TestUnitReady; + READ10_CMD Read10; + REQUEST_SENSE_CMD RequestSence; + INQUIRY_CMD Inquiry; + MODE_SENSE_CMD ModeSense; + READ_FORMAT_CAP_CMD ReadFormatCapacity; +} ATAPI_PACKET_COMMAND; + +typedef struct { + UINT32 RegionBaseAddr; + UINT16 ByteCount; + UINT16 EndOfTable; +} IDE_DMA_PRD; + +#define MAX_DMA_EXT_COMMAND_SECTORS 0x10000 +#define MAX_DMA_COMMAND_SECTORS 0x100 + +#pragma pack() + +// +// Packet Command Code +// +#define TEST_UNIT_READY 0x00 +#define REZERO 0x01 +#define REQUEST_SENSE 0x03 +#define FORMAT_UNIT 0x04 +#define REASSIGN_BLOCKS 0x07 +#define INQUIRY 0x12 +#define START_STOP_UNIT 0x1B +#define PREVENT_ALLOW_MEDIA_REMOVAL 0x1E +#define READ_FORMAT_CAPACITY 0x23 +#define OLD_FORMAT_UNIT 0x24 +#define READ_CAPACITY 0x25 +#define READ_10 0x28 +#define WRITE_10 0x2A +#define SEEK 0x2B +#define SEND_DIAGNOSTICS 0x3D +#define WRITE_VERIFY 0x2E +#define VERIFY 0x2F +#define READ_DEFECT_DATA 0x37 +#define WRITE_BUFFER 0x38 +#define READ_BUFFER 0x3C +#define READ_LONG 0x3E +#define WRITE_LONG 0x3F +#define MODE_SELECT 0x55 +#define MODE_SENSE 0x5A +#define READ_12 0xA8 +#define WRITE_12 0xAA +#define MAX_ATAPI_BYTE_COUNT (0xfffe) + +// +// Sense Key +// +#define REQUEST_SENSE_ERROR (0x70) +#define SK_NO_SENSE (0x0) +#define SK_RECOVERY_ERROR (0x1) +#define SK_NOT_READY (0x2) +#define SK_MEDIUM_ERROR (0x3) +#define SK_HARDWARE_ERROR (0x4) +#define SK_ILLEGAL_REQUEST (0x5) +#define SK_UNIT_ATTENTION (0x6) +#define SK_DATA_PROTECT (0x7) +#define SK_BLANK_CHECK (0x8) +#define SK_VENDOR_SPECIFIC (0x9) +#define SK_RESERVED_A (0xA) +#define SK_ABORT (0xB) +#define SK_RESERVED_C (0xC) +#define SK_OVERFLOW (0xD) +#define SK_MISCOMPARE (0xE) +#define SK_RESERVED_F (0xF) + +// +// Additional Sense Codes +// +#define ASC_NOT_READY (0x04) +#define ASC_MEDIA_ERR1 (0x10) +#define ASC_MEDIA_ERR2 (0x11) +#define ASC_MEDIA_ERR3 (0x14) +#define ASC_MEDIA_ERR4 (0x30) +#define ASC_MEDIA_UPSIDE_DOWN (0x06) +#define ASC_INVALID_CMD (0x20) +#define ASC_LBA_OUT_OF_RANGE (0x21) +#define ASC_INVALID_FIELD (0x24) +#define ASC_WRITE_PROTECTED (0x27) +#define ASC_MEDIA_CHANGE (0x28) +#define ASC_RESET (0x29) /* Power On Reset or Bus Reset occurred */ +#define ASC_ILLEGAL_FIELD (0x26) +#define ASC_NO_MEDIA (0x3A) +#define ASC_ILLEGAL_MODE_FOR_THIS_TRACK (0x64) + +// +// Additional Sense Code Qualifier +// +#define ASCQ_IN_PROGRESS (0x01) + +#define SETFEATURE TRUE +#define CLEARFEATURE FALSE + +// +// ATAPI Data structure +// +#pragma pack(1) + +typedef struct { + UINT8 peripheral_type; + UINT8 RMB; + UINT8 version; + UINT8 response_data_format; + UINT8 addnl_length; + UINT8 reserved_5; + UINT8 reserved_6; + UINT8 reserved_7; + UINT8 vendor_info[8]; + UINT8 product_id[12]; + UINT8 eeprom_product_code[4]; + UINT8 firmware_rev_level[4]; + UINT8 firmware_sub_rev_level[1]; + UINT8 reserved_37; + UINT8 reserved_38; + UINT8 reserved_39; + UINT8 max_capacity_hi; + UINT8 max_capacity_mid; + UINT8 max_capacity_lo; + UINT8 reserved_43_95[95 - 43 + 1]; +} INQUIRY_DATA; + +typedef struct { + UINT8 peripheral_type; + UINT8 RMB; + UINT8 version; + UINT8 response_data_format; + UINT8 addnl_length; + UINT8 reserved_5; + UINT8 reserved_6; + UINT8 reserved_7; + UINT8 vendor_info[8]; + UINT8 product_id[16]; + UINT8 product_revision_level[4]; + UINT8 vendor_specific[20]; + UINT8 reserved_56_95[40]; +} CDROM_INQUIRY_DATA; + +typedef struct { + UINT8 error_code : 7; + UINT8 valid : 1; + UINT8 reserved_1; + UINT8 sense_key : 4; + UINT8 reserved_21 : 1; + UINT8 ILI : 1; + UINT8 reserved_22 : 2; + UINT8 vendor_specific_3; + UINT8 vendor_specific_4; + UINT8 vendor_specific_5; + UINT8 vendor_specific_6; + UINT8 addnl_sense_length; // n - 7 + UINT8 vendor_specific_8; + UINT8 vendor_specific_9; + UINT8 vendor_specific_10; + UINT8 vendor_specific_11; + UINT8 addnl_sense_code; // mandatory + UINT8 addnl_sense_code_qualifier; // mandatory + UINT8 field_replaceable_unit_code; // optional + UINT8 reserved_15; + UINT8 reserved_16; + UINT8 reserved_17; + // + // Followed by additional sense bytes : FIXME + // +} REQUEST_SENSE_DATA; + +typedef struct { + UINT8 LastLba3; + UINT8 LastLba2; + UINT8 LastLba1; + UINT8 LastLba0; + UINT8 BlockSize3; + UINT8 BlockSize2; + UINT8 BlockSize1; + UINT8 BlockSize0; +} READ_CAPACITY_DATA; + +typedef struct { + UINT8 reserved_0; + UINT8 reserved_1; + UINT8 reserved_2; + UINT8 Capacity_Length; + UINT8 LastLba3; + UINT8 LastLba2; + UINT8 LastLba1; + UINT8 LastLba0; + UINT8 DesCode : 2; + UINT8 reserved_9 : 6; + UINT8 BlockSize2; + UINT8 BlockSize1; + UINT8 BlockSize0; +} READ_FORMAT_CAPACITY_DATA; + +#pragma pack() + +// +// PIO mode definition +// +typedef enum { + ATA_PIO_MODE_BELOW_2, + ATA_PIO_MODE_2, + ATA_PIO_MODE_3, + ATA_PIO_MODE_4 +} ATA_PIO_MODE; + +// +// Multi word DMA definition +// +typedef enum { + ATA_MDMA_MODE_0, + ATA_MDMA_MODE_1, + ATA_MDMA_MODE_2 +} ATA_MDMA_MODE; + +// +// UDMA mode definition +// +typedef enum { + ATA_UDMA_MODE_0, + ATA_UDMA_MODE_1, + ATA_UDMA_MODE_2, + ATA_UDMA_MODE_3, + ATA_UDMA_MODE_4, + ATA_UDMA_MODE_5 +} ATA_UDMA_MODE; + +#define ATA_MODE_CATEGORY_DEFAULT_PIO 0x00 +#define ATA_MODE_CATEGORY_FLOW_PIO 0x01 +#define ATA_MODE_CATEGORY_MDMA 0x04 +#define ATA_MODE_CATEGORY_UDMA 0x08 + +#pragma pack(1) + +typedef struct { + UINT8 ModeNumber : 3; + UINT8 ModeCategory : 5; +} ATA_TRANSFER_MODE; + +typedef struct { + UINT8 Sector; + UINT8 Heads; + UINT8 MultipleSector; +} ATA_DRIVE_PARMS; + +#pragma pack() +// +// IORDY Sample Point field value +// +#define ISP_5_CLK 0 +#define ISP_4_CLK 1 +#define ISP_3_CLK 2 +#define ISP_2_CLK 3 + +// +// Recovery Time field value +// +#define RECVY_4_CLK 0 +#define RECVY_3_CLK 1 +#define RECVY_2_CLK 2 +#define RECVY_1_CLK 3 + +// +// Slave IDE Timing Register Enable +// +#define SITRE bit14 + +// +// DMA Timing Enable Only Select 1 +// +#define DTE1 bit7 + +// +// Pre-fetch and Posting Enable Select 1 +// +#define PPE1 bit6 + +// +// IORDY Sample Point Enable Select 1 +// +#define IE1 bit5 + +// +// Fast Timing Bank Drive Select 1 +// +#define TIME1 bit4 + +// +// DMA Timing Enable Only Select 0 +// +#define DTE0 bit3 + +// +// Pre-fetch and Posting Enable Select 0 +// +#define PPE0 bit2 + +// +// IOREY Sample Point Enable Select 0 +// +#define IE0 bit1 + +// +// Fast Timing Bank Drive Select 0 +// +#define TIME0 bit0 + +#endif diff --git a/EdkModulePkg/Bus/Pci/PciBus/Dxe/ComponentName.c b/EdkModulePkg/Bus/Pci/PciBus/Dxe/ComponentName.c new file mode 100644 index 0000000000..ba7ec08c4e --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/ComponentName.c @@ -0,0 +1,133 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ComponentName.c + +Abstract: + +--*/ + +#include "PciBus.h" + +// +// EFI Component Name Protocol +// +EFI_COMPONENT_NAME_PROTOCOL gPciBusComponentName = { + PciBusComponentNameGetDriverName, + PciBusComponentNameGetControllerName, + "eng" +}; + +STATIC EFI_UNICODE_STRING_TABLE mPciBusDriverNameTable[] = { + { "eng", (CHAR16 *) L"PCI Bus Driver" }, + { NULL , NULL } +}; + +EFI_STATUS +EFIAPI +PciBusComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gPciBusComponentName.SupportedLanguages, + mPciBusDriverNameTable, + DriverName + ); +} + +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 + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + 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. + 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. + + Returns: + 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. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return EFI_UNSUPPORTED; +} diff --git a/EdkModulePkg/Bus/Pci/PciBus/Dxe/ComponentName.h b/EdkModulePkg/Bus/Pci/PciBus/Dxe/ComponentName.h new file mode 100644 index 0000000000..87d44c8427 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/ComponentName.h @@ -0,0 +1,91 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ComponentName.h + +Abstract: + + +Revision History + +--*/ + +#ifndef _EFI_PCI_BUS_COMPONENT_NAME_H +#define _EFI_PCI_BUS_COMPONENT_NAME_H + +#ifndef EFI_SIZE_REDUCTION_APPLIED + +extern EFI_COMPONENT_NAME_PROTOCOL gPciBusComponentName; + +#endif + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +PciBusComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Language - TODO: add argument description + DriverName - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +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 + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + ControllerHandle - TODO: add argument description + ChildHandle - TODO: add argument description + Language - TODO: add argument description + ControllerName - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/EdkModulePkg/Bus/Pci/PciBus/Dxe/LightPciBus.mbd b/EdkModulePkg/Bus/Pci/PciBus/Dxe/LightPciBus.mbd new file mode 100644 index 0000000000..eea4971cbf --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/LightPciBus.mbd @@ -0,0 +1,43 @@ + + + + + LightPciBusPciBus + C0734D12-7927-432b-986B-A7E3A35BA005 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:18 + + + UefiBootServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + EdkDxePrintLib + BaseLib + UefiDevicePathLib + DxeMemoryAllocationLib + + diff --git a/EdkModulePkg/Bus/Pci/PciBus/Dxe/LightPciBus.msa b/EdkModulePkg/Bus/Pci/PciBus/Dxe/LightPciBus.msa new file mode 100644 index 0000000000..eec5c3c069 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/LightPciBus.msa @@ -0,0 +1,112 @@ + + + + + LightPciBusPciBus + DXE_DRIVER + BS_DRIVER + C0734D12-7927-432b-986B-A7E3A35BA005 + 0 + Component description file for LightPciBus module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:18 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + BaseLib + UefiLib + BaseMemoryLib + ReportStatusCodeLib + UefiBootServicesTableLib + DevicePathLib + MemoryAllocationLib + + + PciBus.h + PciIo.h + PciCommand.h + PciDeviceSupport.h + PciResourceSupport.h + PciEnumerator.h + PciEnumeratorSupport.h + PciOptionRomSupport.h + PciRomTable.h + PciLib.h + PciRomTable.c + PciDriverOverride.h + PciPowerManagement.h + PciPowerManagement.c + PciDriverOverride.c + PciOptionRomSupport.c + PciEnumerator.c + PciEnumeratorSupport.c + PciResourceSupport.c + PciCOmmand.c + ComponentName.c + PciDeviceSupport.c + PciHotPlugSupport.c + PciBus.c + PciIo.c + LightPciLib.c + + + MdePkg + EdkModulePkg + + + DevicePath + PciRootBridgeIo + Decompress + UgaIo + PciPlatform + PciIo + BusSpecificDriverOverride + PciHotPlugRequest + IncompatiblePciDeviceSupport + PciHotPlugInit + PciHostBridgeResourceAllocation + LoadedImage + + + + PciOptionRomTable + + + PciHotplugDevice + + + StatusCodeSpecificData + + + + + PciBusEntryPoint + + + gPciBusDriverBinding + gPciBusComponentName + + + diff --git a/EdkModulePkg/Bus/Pci/PciBus/Dxe/LightPciLib.c b/EdkModulePkg/Bus/Pci/PciBus/Dxe/LightPciLib.c new file mode 100644 index 0000000000..28c8a794d4 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/LightPciLib.c @@ -0,0 +1,881 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + LightPciLib.c + +Abstract: + + Light PCI Bus Driver Lib file + It abstracts some functions that can be different + between light PCI bus driver and full PCI bus driver + +Revision History + +--*/ + +#include "pcibus.h" + +// +// Light PCI bus driver woundn't support hotplug device +// So just return +// +VOID +InstallHotPlugRequestProtocol ( + IN EFI_STATUS *Status + ) +/*++ + +Routine Description: + + +Arguments: + +Returns: + + None + +--*/ +// TODO: Status - add argument and description to function comment +{ + return ; +} + +// +// Light PCI bus driver woundn't support hotplug device +// So just skip install this GUID +// +VOID +InstallPciHotplugGuid ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciIoDevice - add argument and description to function comment +{ + return ; +} + +// +// Light PCI bus driver woundn't support hotplug device +// So just skip uninstall the GUID +// +VOID +UninstallPciHotplugGuid ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciIoDevice - add argument and description to function comment +{ + return ; +} + +// +// Light PCI bus driver woundn't support PCCard +// So it needn't get the bar of CardBus +// +VOID +GetBackPcCardBar ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + return ; +} + +// +// Light PCI bus driver woundn't support resource reallocation +// So just return +// +EFI_STATUS +RemoveRejectedPciDevices ( + EFI_HANDLE RootBridgeHandle, + IN PCI_IO_DEVICE *Bridge + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + RootBridgeHandle - TODO: add argument description + Bridge - TODO: add argument description + +Returns: + + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + return EFI_SUCCESS; +} + +// +// Light PCI bus driver woundn't support resource reallocation +// Simplified the code +// +EFI_STATUS +PciHostBridgeResourceAllocator ( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciResAlloc - add argument and description to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + PCI_IO_DEVICE *RootBridgeDev; + EFI_HANDLE RootBridgeHandle; + VOID *AcpiConfig; + EFI_STATUS Status; + UINT64 IoBase; + UINT64 Mem32Base; + UINT64 PMem32Base; + UINT64 Mem64Base; + UINT64 PMem64Base; + UINT64 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; + REPORT_STATUS_CODE_LIBRARY_DEVICE_HANDLE_EXTENDED_DATA ExtendedData; + + // + // 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 RootBridg Device by handle + // + RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle); + + if (RootBridgeDev == NULL) { + return EFI_NOT_FOUND; + } + + // + // Get host bridge handle for status report + // + ExtendedData.Handle = RootBridgeDev->PciRootBridgeIo->ParentHandle; + + // + // Create the entire system resource map from the information collected by + // enumerator. Several resource tree was created + // + + IoBridge = CreateResourceNode ( + RootBridgeDev, + 0, + 0xFFF, + 0, + PciBarTypeIo16, + PciResUsageTypical + ); + + Mem32Bridge = CreateResourceNode ( + RootBridgeDev, + 0, + 0xFFFFF, + 0, + PciBarTypeMem32, + PciResUsageTypical + ); + + PMem32Bridge = CreateResourceNode ( + RootBridgeDev, + 0, + 0xFFFFF, + 0, + PciBarTypePMem32, + PciResUsageTypical + ); + + Mem64Bridge = CreateResourceNode ( + RootBridgeDev, + 0, + 0xFFFFF, + 0, + PciBarTypeMem64, + PciResUsageTypical + ); + + PMem64Bridge = CreateResourceNode ( + RootBridgeDev, + 0, + 0xFFFFF, + 0, + PciBarTypePMem64, + PciResUsageTypical + ); + + // + // Create resourcemap by going through all the devices subject to this root bridge + // + Status = CreateResourceMap ( + RootBridgeDev, + IoBridge, + Mem32Bridge, + PMem32Bridge, + Mem64Bridge, + PMem64Bridge + ); + + // + // Get the max ROM size that the root bridge can process + // + RootBridgeDev->RomSize = Mem32Bridge->Length; + + // + // Get Max Option Rom size for current root bridge + // + MaxOptionRomSize = GetMaxOptionRomSize (RootBridgeDev); + + // + // Enlarger the mem32 resource to accomdate the option rom + // if the mem32 resource is not enough to hold the rom + // + if (MaxOptionRomSize > Mem32Bridge->Length) { + + Mem32Bridge->Length = MaxOptionRomSize; + RootBridgeDev->RomSize = MaxOptionRomSize; + + // + // Alignment should be adjusted as well + // + if (Mem32Bridge->Alignment < MaxOptionRomSize - 1) { + Mem32Bridge->Alignment = MaxOptionRomSize - 1; + } + } + + // + // Based on the all the resource tree, contruct 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 + ); + } + // + // Free acpi resource node + // + if (AcpiConfig) { + gBS->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 + // + + // + // Notify pci bus driver starts to program the resource + // + Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeAllocateResources); + + if (EFI_ERROR (Status)) { + // + // Allocation failed, then return + // + return EFI_OUT_OF_RESOURCES; + } + // + // 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_PC_RES_ALLOC, + (VOID *) &ExtendedData, + sizeof (ExtendedData) + ); + + // + // Notify pci bus driver starts to program the resource + // + NotifyPhase (PciResAlloc, EfiPciHostBridgeSetResources); + + 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 + ); + + // + // Process option rom for this root bridge + // + Status = ProcessOptionRom (RootBridgeDev, Mem32Base, RootBridgeDev->RomSize); + + // + // Create the entire system resource map from the information collected by + // enumerator. Several resource tree was created + // + Status = GetResourceMap ( + RootBridgeDev, + &IoBridge, + &Mem32Bridge, + &PMem32Bridge, + &Mem64Bridge, + &PMem64Bridge, + &IoPool, + &Mem32Pool, + &PMem32Pool, + &Mem64Pool, + &PMem64Pool + ); + + 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 + ); + + if (AcpiConfig != NULL) { + gBS->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 + // + NotifyPhase (PciResAlloc, EfiPciHostBridgeEndResourceAllocation); + + return EFI_SUCCESS; +} + +EFI_STATUS +PciScanBus ( + IN PCI_IO_DEVICE *Bridge, + IN UINT8 StartBusNumber, + OUT UINT8 *SubBusNumber, + OUT UINT8 *PaddedBusRange + ) +/*++ + +Routine Description: + + This routine is used to assign bus number to the given PCI bus system + +Arguments: + +Returns: + + None + +--*/ +// TODO: Bridge - add argument and description to function comment +// TODO: StartBusNumber - add argument and description to function comment +// TODO: SubBusNumber - add argument and description to function comment +// TODO: PaddedBusRange - add argument and description to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + PCI_TYPE00 Pci; + UINT8 Device; + UINT8 Func; + UINT64 Address; + UINTN SecondBus; + UINT16 Register; + PCI_IO_DEVICE *PciDevice; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; + + PciRootBridgeIo = Bridge->PciRootBridgeIo; + SecondBus = 0; + Register = 0; + + ResetAllPpbBusReg (Bridge, StartBusNumber); + + 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) && + (IS_PCI_BRIDGE (&Pci) || + IS_CARDBUS_BRIDGE (&Pci))) { + + // + // Get the bridge information + // + Status = PciSearchDevice ( + Bridge, + &Pci, + StartBusNumber, + Device, + Func, + &PciDevice + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + (*SubBusNumber)++; + + 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)) { + // + // Temporarily initialize SubBusNumber to maximum bus number to ensure the + // PCI configuration transaction to go through any PPB + // + Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A); + Register = 0xFF; + Status = PciRootBridgeIo->Pci.Write ( + PciRootBridgeIo, + EfiPciWidthUint8, + Address, + 1, + &Register + ); + + PreprocessController ( + PciDevice, + PciDevice->BusNumber, + PciDevice->DeviceNumber, + PciDevice->FunctionNumber, + EfiPciBeforeChildBusEnumeration + ); + + Status = PciScanBus ( + PciDevice, + (UINT8) (SecondBus), + SubBusNumber, + PaddedBusRange + ); + + 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; +} + +// +// Light PCI bus driver woundn't support P2C +// Return instead +// +EFI_STATUS +PciHostBridgeP2CProcess ( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciResAlloc - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + return EFI_SUCCESS; +} + +// +// Light PCI bus driver woundn't support hotplug device +// Simplified the code +// +EFI_STATUS +PciHostBridgeEnumerator ( + EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc + ) +/*++ + +Routine Description: + + This function is used to enumerate the entire host bridge + in a given platform + +Arguments: + + PciResAlloc A pointer to the protocol to allocate resource. + +Returns: + + None + +--*/ +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + 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; + + InitializeHotPlugSupport (); + + // + // Notify the bus allocation phase is about to start + // + NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation); + + 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 (EFI_ERROR (Status)) { + return Status; + } + + DestroyRootBridge (RootBridgeDev); + + // + // Error proccess here + // + } + + // + // Notify the bus allocation phase is to end + // + NotifyPhase (PciResAlloc, EfiPciHostBridgeEndBusAllocation); + + // + // Notify the resource allocation phase is to start + // + NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginResourceAllocation); + + 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/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciBus.mbd b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciBus.mbd new file mode 100644 index 0000000000..41543f7832 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciBus.mbd @@ -0,0 +1,43 @@ + + + + + PciBus + 93B80004-9FB3-11d4-9A3A-0090273FC14D + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:18 + + + UefiBootServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + EdkDxePrintLib + BaseLib + DxeMemoryAllocationLib + UefiDevicePathLib + + diff --git a/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciBus.msa b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciBus.msa new file mode 100644 index 0000000000..bf5c3698ef --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciBus.msa @@ -0,0 +1,121 @@ + + + + + PciBus + DXE_DRIVER + BS_DRIVER + 93B80004-9FB3-11d4-9A3A-0090273FC14D + 0 + Component description file for PciBus module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:18 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + BaseLib + UefiLib + BaseMemoryLib + ReportStatusCodeLib + MemoryAllocationLib + UefiBootServicesTableLib + DevicePathLib + + + PciBus.h + PciIo.h + PciCommand.h + PciDeviceSupport.h + PciResourceSupport.h + PciEnumerator.h + PciEnumeratorSupport.h + PciOptionRomSupport.h + PciRomTable.h + PciHotPlugSupport.h + PciLib.h + PciHotPlugSupport.c + PciRomTable.c + PciDriverOverride.h + PciPowerManagement.h + PciPowerManagement.c + PciDriverOverride.c + PciOptionRomSupport.c + PciEnumerator.c + PciEnumeratorSupport.c + PciResourceSupport.c + PciCOmmand.c + ComponentName.c + PciDeviceSupport.c + PciBus.c + PciIo.c + PciLib.c + + + MdePkg + EdkModulePkg + + + DevicePath + PciRootBridgeIo + PciPlatform + IncompatiblePciDeviceSupport + PciHostBridgeResourceAllocation + PciHotPlugInit + Decompress + LoadedImage + UgaIo + PciIo + BusSpecificDriverOverride + PciHotPlugRequest + + + + gEfiUgaIoProtocolGuid + + + gEfiPciOptionRomTableGuid + + + + + PciOptionRomTable + + + StatusCodeSpecificData + + + PciHotplugDevice + + + + + PciBusEntryPoint + + + gPciBusDriverBinding + gPciBusComponentName + + + diff --git a/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciBusLite.mbd b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciBusLite.mbd new file mode 100644 index 0000000000..c02965265c --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciBusLite.mbd @@ -0,0 +1,43 @@ + + + + + PciBusPciBusLite + C0734D12-7927-432b-986B-A7E3A35BA005 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:18 + + + UefiBootServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + EdkDxePrintLib + BaseLib + UefiDevicePathLib + DxeMemoryAllocationLib + + diff --git a/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciBusLite.msa b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciBusLite.msa new file mode 100644 index 0000000000..1568b31e31 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciBusLite.msa @@ -0,0 +1,111 @@ + + + + + PciBusPciBusLite + DXE_DRIVER + BS_DRIVER + C0734D12-7927-432b-986B-A7E3A35BA005 + 0 + Component description file for LightPciBus module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:18 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + BaseLib + UefiLib + BaseMemoryLib + ReportStatusCodeLib + UefiBootServicesTableLib + DevicePathLib + MemoryAllocationLib + + + PciBus.h + PciIo.h + PciCommand.h + PciDeviceSupport.h + PciResourceSupport.h + PciEnumerator.h + PciEnumeratorSupport.h + PciOptionRomSupport.h + PciRomTable.h + PciLib.h + PciRomTable.c + PciDriverOverride.h + PciPowerManagement.h + PciPowerManagement.c + PciDriverOverride.c + PciOptionRomSupport.c + PciEnumerator.c + PciEnumeratorSupport.c + PciResourceSupport.c + PciCOmmand.c + PciDeviceSupport.c + PciHotPlugSupport.c + PciBus.c + PciIo.c + LightPciLib.c + + + MdePkg + EdkModulePkg + + + DevicePath + PciRootBridgeIo + Decompress + UgaIo + PciPlatform + PciIo + BusSpecificDriverOverride + PciHotPlugRequest + IncompatiblePciDeviceSupport + PciHotPlugInit + PciHostBridgeResourceAllocation + LoadedImage + + + + PciOptionRomTable + + + PciHotplugDevice + + + StatusCodeSpecificData + + + + + PciBusEntryPoint + + + gPciBusDriverBinding + gPciBusComponentName + + + diff --git a/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciCommand.c b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciCommand.c new file mode 100644 index 0000000000..90712338f0 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciCommand.c @@ -0,0 +1,207 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PciCommand.c + +Abstract: + + PCI Bus Driver + +Revision History + +--*/ + +#include "Pcibus.h" + +EFI_STATUS +PciOperateRegister ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINT16 Command, + IN UINT8 Offset, + IN UINT8 Operation, + OUT UINT16 *PtrCommand + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciIoDevice - add argument and description to function comment +// TODO: Command - add argument and description to function comment +// TODO: Offset - add argument and description to function comment +// TODO: Operation - add argument and description to function comment +// TODO: PtrCommand - add argument and description to function comment +{ + 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 |= Command; + } else if (Operation == EFI_DISABLE_REGISTER) { + OldCommand &= ~(Command); + } else { + OldCommand = Command; + } + + return PciIo->Pci.Write ( + PciIo, + EfiPciIoWidthUint16, + Offset, + 1, + &OldCommand + ); +} + +BOOLEAN +PciCapabilitySupport ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciIoDevice - add argument and description to function comment +{ + + if (PciIoDevice->Pci.Hdr.Status & EFI_PCI_STATUS_CAPABILITY) { + return TRUE; + } + + return FALSE; +} + +EFI_STATUS +LocateCapabilityRegBlock ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINT8 CapId, + IN OUT UINT8 *Offset, + OUT UINT8 *NextRegBlock OPTIONAL + ) +/*++ + +Routine Description: + Locate cap reg. + +Arguments: + PciIoDevice - A pointer to the PCI_IO_DEVICE. + CapId - The cap ID. + Offset - A pointer to the offset. + NextRegBlock - A pointer to the next block. + +Returns: + + None + +--*/ +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +{ + UINT8 CapabilityPtr; + UINT16 CapabilityEntry; + UINT8 CapabilityID; + + // + // To check the cpability 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, + EFI_PCI_CAPABILITY_PTR, + 1, + &CapabilityPtr + ); + } + } + + while (CapabilityPtr > 0x3F) { + // + // Mask it to DWORD alignment per PCI spec + // + CapabilityPtr &= 0xFC; + 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; + } + + CapabilityPtr = (UINT8) (CapabilityEntry >> 8); + } + + return EFI_NOT_FOUND; +} diff --git a/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciCommand.h b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciCommand.h new file mode 100644 index 0000000000..56f632e8da --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciCommand.h @@ -0,0 +1,134 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PciCommand.h + +Abstract: + + PCI Bus Driver + +Revision History + +--*/ + +#ifndef _EFI_PCI_COMMAND_H +#define _EFI_PCI_COMMAND_H + +#define EFI_GET_REGISTER 1 +#define EFI_SET_REGISTER 2 +#define EFI_ENABLE_REGISTER 3 +#define EFI_DISABLE_REGISTER 4 + +EFI_STATUS +PciOperateRegister ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINT16 Command, + IN UINT8 Offset, + IN UINT8 Operation, + OUT UINT16 *PtrCommand + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + Command - TODO: add argument description + Offset - TODO: add argument description + Operation - TODO: add argument description + PtrCommand - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +PciCapabilitySupport ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +LocateCapabilityRegBlock ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINT8 CapId, + IN OUT UINT8 *Offset, + OUT UINT8 *NextRegBlock OPTIONAL + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + CapId - TODO: add argument description + Offset - TODO: add argument description + NextRegBlock - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + + +#define PciReadCommandRegister(a,b) \ + PciOperateRegister (a,0, PCI_COMMAND_OFFSET, EFI_GET_REGISTER, b) + +#define PciSetCommandRegister(a,b) \ + PciOperateRegister (a,b, PCI_COMMAND_OFFSET, EFI_SET_REGISTER, NULL) + +#define PciEnableCommandRegister(a,b) \ + PciOperateRegister (a,b, PCI_COMMAND_OFFSET, EFI_ENABLE_REGISTER, NULL) + +#define PciDisableCommandRegister(a,b) \ + PciOperateRegister (a,b, PCI_COMMAND_OFFSET, EFI_DISABLE_REGISTER, NULL) + +#define PciReadBridgeControlRegister(a,b) \ + PciOperateRegister (a,0, PCI_BRIDGE_CONTROL_REGISTER_OFFSET, EFI_GET_REGISTER, b) + +#define PciSetBridgeControlRegister(a,b) \ + PciOperateRegister (a,b, PCI_BRIDGE_CONTROL_REGISTER_OFFSET, EFI_SET_REGISTER, NULL) + +#define PciEnableBridgeControlRegister(a,b) \ + PciOperateRegister (a,b, PCI_BRIDGE_CONTROL_REGISTER_OFFSET, EFI_ENABLE_REGISTER, NULL) + +#define PciDisableBridgeControlRegister(a,b) \ + PciOperateRegister (a,b, PCI_BRIDGE_CONTROL_REGISTER_OFFSET, EFI_DISABLE_REGISTER, NULL) + +#endif diff --git a/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciDeviceSupport.c b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciDeviceSupport.c new file mode 100644 index 0000000000..c24d1b5e59 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciDeviceSupport.c @@ -0,0 +1,1345 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PciDeviceSupport.c + +Abstract: + + This file provides routine to support Pci device node manipulation + +Revision History + +--*/ + +#include "Pcibus.h" +#include "PciDeviceSupport.h" + +// +// This device structure is serviced as a header. +// Its Next field points to the first root bridge device node +// +LIST_ENTRY gPciDevicePool; + +EFI_STATUS +InitializePciDevicePool ( + VOID + ) +/*++ + +Routine Description: + + Initialize the gPciDevicePool + +Arguments: + +Returns: + + None + +--*/ +// TODO: EFI_SUCCESS - add return value to function comment +{ + InitializeListHead (&gPciDevicePool); + + return EFI_SUCCESS; +} + +EFI_STATUS +InsertRootBridge ( + PCI_IO_DEVICE *RootBridge + ) +/*++ + +Routine Description: + + Insert a root bridge into PCI device pool + +Arguments: + + RootBridge - A pointer to the PCI_IO_DEVICE. + +Returns: + + None + +--*/ +// TODO: EFI_SUCCESS - add return value to function comment +{ + + InsertTailList (&gPciDevicePool, &(RootBridge->Link)); + + return EFI_SUCCESS; +} + +EFI_STATUS +InsertPciDevice ( + PCI_IO_DEVICE *Bridge, + PCI_IO_DEVICE *PciDeviceNode + ) +/*++ + +Routine Description: + + This function is used to insert a PCI device node under + a bridge + +Arguments: + Bridge - A pointer to the PCI_IO_DEVICE. + PciDeviceNode - A pointer to the PCI_IO_DEVICE. + +Returns: + + None + +--*/ +// TODO: EFI_SUCCESS - add return value to function comment +{ + + InsertTailList (&Bridge->ChildList, &(PciDeviceNode->Link)); + PciDeviceNode->Parent = Bridge; + + return EFI_SUCCESS; +} + +EFI_STATUS +DestroyRootBridge ( + IN PCI_IO_DEVICE *RootBridge + ) +/*++ + +Routine Description: + + +Arguments: + + RootBridge - A pointer to the PCI_IO_DEVICE. + +Returns: + + None + +--*/ +// TODO: EFI_SUCCESS - add return value to function comment +{ + DestroyPciDeviceTree (RootBridge); + + FreePciDevice (RootBridge); + + return EFI_SUCCESS; +} + +EFI_STATUS +FreePciDevice ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + Destroy a pci device node. + Also all direct or indirect allocated resource for this node will be freed. + +Arguments: + + PciIoDevice - A pointer to the PCI_IO_DEVICE. + +Returns: + + None + +--*/ +// TODO: EFI_SUCCESS - add return value to function comment +{ + + // + // Assume all children have been removed underneath this device + // + if (PciIoDevice->ResourcePaddingDescriptors != NULL) { + gBS->FreePool (PciIoDevice->ResourcePaddingDescriptors); + } + + if (PciIoDevice->DevicePath != NULL) { + gBS->FreePool (PciIoDevice->DevicePath); + } + + gBS->FreePool (PciIoDevice); + + return EFI_SUCCESS; +} + +EFI_STATUS +DestroyPciDeviceTree ( + IN PCI_IO_DEVICE *Bridge + ) +/*++ + +Routine Description: + + Destroy all the pci device node under the bridge. + Bridge itself is not included. + +Arguments: + + Bridge - A pointer to the PCI_IO_DEVICE. + +Returns: + + None + +--*/ +// TODO: EFI_SUCCESS - add return value to function comment +{ + 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); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +DestroyRootBridgeByHandle ( + EFI_HANDLE Controller + ) +/*++ + +Routine Description: + + Destroy all device nodes under the root bridge + specified by Controller. + The root bridge itself is also included. + +Arguments: + + Controller - An efi handle. + +Returns: + + None + +--*/ +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +{ + + LIST_ENTRY *CurrentLink; + PCI_IO_DEVICE *Temp; + + CurrentLink = gPciDevicePool.ForwardLink; + + while (CurrentLink && CurrentLink != &gPciDevicePool) { + 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; +} + +EFI_STATUS +RegisterPciDevice ( + IN EFI_HANDLE Controller, + IN PCI_IO_DEVICE *PciIoDevice, + OUT EFI_HANDLE *Handle OPTIONAL + ) +/*++ + +Routine Description: + + This function is used to register the PCI device to the EFI, + create a handle for this PCI device,then attach apporpriate protocols + onto the handle. + +Arguments: + + Controller - An efi handle. + PciIoDevice - A pointer to the PCI_IO_DEVICE. + Handle - A pointer to a efi handle. + +Returns: + + None + +--*/ +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + VOID *PlatformOpRomBuffer; + UINTN PlatformOpRomSize; + UINT8 PciExpressCapRegOffset; + EFI_PCI_IO_PROTOCOL *PciIo; + + // + // 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; + } + + // + // Detect if PCI Express Device + // + PciExpressCapRegOffset = 0; + Status = LocateCapabilityRegBlock ( + PciIoDevice, + EFI_PCI_CAPABILITY_ID_PCIEXP, + &PciExpressCapRegOffset, + NULL + ); + if (!EFI_ERROR (Status)) { + PciIoDevice->IsPciExp = TRUE; + } + + // + // Force Interrupt line to zero for cards that come up randomly + // + PciIo = &(PciIoDevice->PciIo); + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero); + // + // Process Platform OpRom + // + if (gPciPlatformProtocol != NULL && !PciIoDevice->AllOpRomProcessed) { + PciIoDevice->AllOpRomProcessed = TRUE; + + Status = gPciPlatformProtocol->GetPciRom ( + gPciPlatformProtocol, + PciIoDevice->Handle, + &PlatformOpRomBuffer, + &PlatformOpRomSize + ); + + if (!EFI_ERROR (Status)) { + + // + // Have Platform OpRom + // + PciIoDevice->RomSize = PlatformOpRomSize; + PciIoDevice->PciIo.RomSize = PlatformOpRomSize; + PciIoDevice->PciIo.RomImage = PlatformOpRomBuffer; + + // + // Process Image + // + ProcessOpRomImage (PciIoDevice); + } + } + + if (PciIoDevice->BusOverride) { + // + // Install BusSpecificDriverOverride 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 + ); + + 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; + } + + // + // Install Pccard Hotplug GUID for Pccard device so that + // to notify CardBus driver to stop the device when de-register happens + // + InstallPciHotplugGuid (PciIoDevice); + + if (Handle != NULL) { + *Handle = PciIoDevice->Handle; + } + + // + // Indicate the pci device is registered + // + PciIoDevice->Registered = TRUE; + + return EFI_SUCCESS; +} + +EFI_STATUS +RemoveAllPciDeviceOnBridge ( + EFI_HANDLE RootBridgeHandle, + PCI_IO_DEVICE *Bridge + ) +/*++ + +Routine Description: + + This function is used to remove the whole PCI devices from the bridge. + +Arguments: + + RootBridgeHandle - An efi handle. + Bridge - A pointer to the PCI_IO_DEVICE. + +Returns: + + None + +--*/ +// TODO: EFI_SUCCESS - add return value to function comment +{ + + 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); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +DeRegisterPciDevice ( + IN EFI_HANDLE Controller, + IN EFI_HANDLE Handle + ) +/*++ + +Routine Description: + + This function is used to de-register the PCI device from the EFI, + That includes un-installing PciIo protocol from the specified PCI + device handle. + +Arguments: + + Controller - An efi handle. + Handle - An efi handle. + +Returns: + + None + +--*/ +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + 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 && CurrentLink != &PciIoDevice->ChildList) { + Node = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + Status = DeRegisterPciDevice (Controller, Node->Handle); + + if (EFI_ERROR (Status)) { + return Status; + } + + CurrentLink = CurrentLink->ForwardLink; + } + } + // + // Uninstall Pccard Hotplug GUID for Pccard device + // + UninstallPciHotplugGuid (PciIoDevice); + + // + // Close the child handle + // + Status = gBS->CloseProtocol ( + Controller, + &gEfiPciRootBridgeIoProtocolGuid, + gPciBusDriverBinding.DriverBindingHandle, + Handle + ); + + // + // Un-install the device path protocol and pci io protocol + // + 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)) { + 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; +} + +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 + ) +/*++ + +Routine Description: + + Start to manage the PCI device on specified the root bridge or PCI-PCI Bridge + +Arguments: + + Controller - An efi handle. + RootBridge - A pointer to the PCI_IO_DEVICE. + RemainingDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCOL. + NumberOfChildren - Children number. + ChildHandleBuffer - A pointer to the child handle buffer. + +Returns: + + None + +--*/ +// TODO: EFI_NOT_READY - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +{ + PCI_IO_DEVICE *Temp; + PCI_IO_DEVICE *PciIoDevice; + EFI_DEV_PATH_PTR Node; + EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath; + EFI_STATUS Status; + LIST_ENTRY *CurrentLink; + UINT64 Supports; + + CurrentLink = RootBridge->ChildList.ForwardLink; + + while (CurrentLink && CurrentLink != &RootBridge->ChildList) { + + Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + if (RemainingDevicePath != NULL) { + + Node.DevPath = RemainingDevicePath; + + if (Node.Pci->Device != Temp->DeviceNumber || + Node.Pci->Function != Temp->FunctionNumber) { + CurrentLink = CurrentLink->ForwardLink; + continue; + } + + // + // Check if the device has been assigned with required resource + // + if (!Temp->Allocated) { + return EFI_NOT_READY; + } + + // + // Check if the current node has been registered before + // If it is not, register it + // + if (!Temp->Registered) { + PciIoDevice = Temp; + + Status = RegisterPciDevice ( + Controller, + PciIoDevice, + NULL + ); + + } + + if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && Temp->Registered) { + ChildHandleBuffer[*NumberOfChildren] = Temp->Handle; + (*NumberOfChildren)++; + } + + // + // Get the next device path + // + CurrentDevicePath = EfiNextDevicePathNode (RemainingDevicePath); + if (EfiIsDevicePathEnd (CurrentDevicePath)) { + return EFI_SUCCESS; + } + + // + // If it is a PPB + // + if (!IsListEmpty (&Temp->ChildList)) { + Status = StartPciDevicesOnBridge ( + Controller, + Temp, + CurrentDevicePath, + NumberOfChildren, + ChildHandleBuffer + ); + + Temp->PciIo.Attributes ( + &(Temp->PciIo), + EfiPciIoAttributeOperationSupported, + 0, + &Supports + ); + Supports &= EFI_PCI_DEVICE_ENABLE; + Temp->PciIo.Attributes ( + &(Temp->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 (!Temp->Registered && Temp->Allocated) { + + PciIoDevice = Temp; + + Status = RegisterPciDevice ( + Controller, + PciIoDevice, + NULL + ); + + } + + if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && Temp->Registered) { + ChildHandleBuffer[*NumberOfChildren] = Temp->Handle; + (*NumberOfChildren)++; + } + + if (!IsListEmpty (&Temp->ChildList)) { + Status = StartPciDevicesOnBridge ( + Controller, + Temp, + RemainingDevicePath, + NumberOfChildren, + ChildHandleBuffer + ); + + Temp->PciIo.Attributes ( + &(Temp->PciIo), + EfiPciIoAttributeOperationSupported, + 0, + &Supports + ); + Supports &= EFI_PCI_DEVICE_ENABLE; + Temp->PciIo.Attributes ( + &(Temp->PciIo), + EfiPciIoAttributeOperationEnable, + Supports, + NULL + ); + + } + + CurrentLink = CurrentLink->ForwardLink; + continue; + } + } + + return EFI_NOT_FOUND; +} + +EFI_STATUS +StartPciDevices ( + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + Start to manage the PCI device according to RemainingDevicePath + If RemainingDevicePath == NULL, the PCI bus driver will start + to manage all the PCI devices it found previously + +Arguments: + Controller - An efi handle. + RemainingDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCOL. + +Returns: + + None + +--*/ +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_DEV_PATH_PTR Node; + PCI_IO_DEVICE *RootBridge; + LIST_ENTRY *CurrentLink; + + if (RemainingDevicePath != NULL) { + + // + // Check if the RemainingDevicePath is valid + // + 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; + } + } + + CurrentLink = gPciDevicePool.ForwardLink; + + while (CurrentLink && CurrentLink != &gPciDevicePool) { + + RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + // + // Locate the right root bridge to start + // + if (RootBridge->Handle == Controller) { + StartPciDevicesOnBridge ( + Controller, + RootBridge, + RemainingDevicePath, + NULL, + NULL + ); + } + + CurrentLink = CurrentLink->ForwardLink; + } + + return EFI_SUCCESS; +} + +PCI_IO_DEVICE * +CreateRootBridge ( + IN EFI_HANDLE RootBridgeHandle + ) +/*++ + +Routine Description: + + +Arguments: + RootBridgeHandle - An efi handle. + +Returns: + + None + +--*/ +{ + + EFI_STATUS Status; + PCI_IO_DEVICE *Dev; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; + + Dev = NULL; + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (PCI_IO_DEVICE), + (VOID **) &Dev + ); + + if (EFI_ERROR (Status)) { + return NULL; + } + + ZeroMem (Dev, sizeof (PCI_IO_DEVICE)); + 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)) { + gBS->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 + // + Status = InitializePciIoInstance (Dev); + Status = InitializePciDriverOverrideInstance (Dev); + + // + // Initialize reserved resource list and + // option rom driver list + // + InitializeListHead (&Dev->ReservedResourceList); + InitializeListHead (&Dev->OptionRomDriverList); + + return Dev; +} + +PCI_IO_DEVICE * +GetRootBridgeByHandle ( + EFI_HANDLE RootBridgeHandle + ) +/*++ + +Routine Description: + + +Arguments: + + RootBridgeHandle - An efi handle. + +Returns: + + None + +--*/ +{ + PCI_IO_DEVICE *RootBridgeDev; + LIST_ENTRY *CurrentLink; + + CurrentLink = gPciDevicePool.ForwardLink; + + while (CurrentLink && CurrentLink != &gPciDevicePool) { + + RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + if (RootBridgeDev->Handle == RootBridgeHandle) { + return RootBridgeDev; + } + + CurrentLink = CurrentLink->ForwardLink; + } + + return NULL; +} + +BOOLEAN +RootBridgeExisted ( + IN EFI_HANDLE RootBridgeHandle + ) +/*++ + +Routine Description: + + This function searches if RootBridgeHandle has already existed + in current device pool. + + If so, it means the given root bridge has been already enumerated. + +Arguments: + + RootBridgeHandle - An efi handle. + +Returns: + + None + +--*/ +{ + PCI_IO_DEVICE *Bridge; + + Bridge = GetRootBridgeByHandle (RootBridgeHandle); + + if (Bridge != NULL) { + return TRUE; + } + + return FALSE; +} + +BOOLEAN +PciDeviceExisted ( + IN PCI_IO_DEVICE *Bridge, + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + +Arguments: + + Bridge - A pointer to the PCI_IO_DEVICE. + PciIoDevice - A pointer to the PCI_IO_DEVICE. + +Returns: + + None + +--*/ +{ + + PCI_IO_DEVICE *Temp; + LIST_ENTRY *CurrentLink; + + CurrentLink = Bridge->ChildList.ForwardLink; + + while (CurrentLink && 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; +} + +PCI_IO_DEVICE * +ActiveVGADeviceOnTheSameSegment ( + IN PCI_IO_DEVICE *VgaDevice + ) +/*++ + +Routine Description: + +Arguments: + + VgaDevice - A pointer to the PCI_IO_DEVICE. + +Returns: + + None + +--*/ +{ + LIST_ENTRY *CurrentLink; + PCI_IO_DEVICE *Temp; + + CurrentLink = gPciDevicePool.ForwardLink; + + while (CurrentLink && CurrentLink != &gPciDevicePool) { + + Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + + if (Temp->PciRootBridgeIo->SegmentNumber == VgaDevice->PciRootBridgeIo->SegmentNumber) { + + Temp = ActiveVGADeviceOnTheRootBridge (Temp); + + if (Temp != NULL) { + return Temp; + } + } + + CurrentLink = CurrentLink->ForwardLink; + } + + return NULL; +} + +PCI_IO_DEVICE * +ActiveVGADeviceOnTheRootBridge ( + IN PCI_IO_DEVICE *RootBridge + ) +/*++ + +Routine Description: + +Arguments: + + RootBridge - A pointer to the PCI_IO_DEVICE. + +Returns: + + None + +--*/ +{ + LIST_ENTRY *CurrentLink; + PCI_IO_DEVICE *Temp; + + CurrentLink = RootBridge->ChildList.ForwardLink; + + while (CurrentLink && CurrentLink != &RootBridge->ChildList) { + + Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + + if (IS_PCI_VGA(&Temp->Pci) && + (Temp->Attributes & (EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_IO))) { + return Temp; + } + + if (IS_PCI_BRIDGE (&Temp->Pci)) { + + Temp = ActiveVGADeviceOnTheRootBridge (Temp); + + if (Temp != NULL) { + return Temp; + } + } + + CurrentLink = CurrentLink->ForwardLink; + } + + return NULL; +} + +EFI_STATUS +GetHpcPciAddress ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, + IN EFI_DEVICE_PATH_PROTOCOL *HpcDevicePath, + OUT UINT64 *PciAddress + ) +/*++ + +Routine Description: + +Arguments: + + PciRootBridgeIo - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + HpcDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCL. + PciAddress - A pointer to the pci address. + +Returns: + + None + +--*/ +// TODO: EFI_NOT_FOUND - add return value to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +{ + EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath; + EFI_DEV_PATH_PTR Node; + LIST_ENTRY *CurrentLink; + PCI_IO_DEVICE *RootBridge; + EFI_STATUS Status; + + CurrentDevicePath = HpcDevicePath; + + // + // Get the remaining device path for this PCI device, if it is a PCI device + // + while (!EfiIsDevicePathEnd (CurrentDevicePath)) { + + Node.DevPath = CurrentDevicePath; + + // + // Check if it is PCI device Path? + // + if ((Node.DevPath->Type != HARDWARE_DEVICE_PATH) || + ((Node.DevPath->SubType != HW_PCI_DP) && + (DevicePathNodeLength (Node.DevPath) != sizeof (PCI_DEVICE_PATH)))) { + CurrentDevicePath = EfiNextDevicePathNode (CurrentDevicePath); + continue; + } + + break; + } + + // + // Check if it is not PCI device path + // + if (EfiIsDevicePathEnd (CurrentDevicePath)) { + return EFI_NOT_FOUND; + } + + CurrentLink = gPciDevicePool.ForwardLink; + + while (CurrentLink && CurrentLink != &gPciDevicePool) { + + RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + // + // Locate the right root bridge to start + // + if (RootBridge->PciRootBridgeIo == PciRootBridgeIo) { + Status = GetHpcPciAddressFromRootBridge ( + RootBridge, + CurrentDevicePath, + PciAddress + ); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; + + } + + CurrentLink = CurrentLink->ForwardLink; + } + + return EFI_NOT_FOUND; +} + +EFI_STATUS +GetHpcPciAddressFromRootBridge ( + IN PCI_IO_DEVICE *RootBridge, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath, + OUT UINT64 *PciAddress + ) +/*++ + +Routine Description: + +Arguments: + + PciRootBridgeIo - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + HpcDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCL. + PciAddress - A pointer to the pci address. + +Returns: + + None + +--*/ +// TODO: RootBridge - add argument and description to function comment +// TODO: RemainingDevicePath - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_DEV_PATH_PTR Node; + PCI_IO_DEVICE *Temp; + EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath; + LIST_ENTRY *CurrentLink; + BOOLEAN MisMatch; + + MisMatch = FALSE; + + CurrentDevicePath = RemainingDevicePath; + Node.DevPath = CurrentDevicePath; + Temp = NULL; + + while (!EfiIsDevicePathEnd (CurrentDevicePath)) { + + CurrentLink = RootBridge->ChildList.ForwardLink; + Node.DevPath = CurrentDevicePath; + + while (CurrentLink && CurrentLink != &RootBridge->ChildList) { + Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + + if (Node.Pci->Device == Temp->DeviceNumber && + Node.Pci->Function == Temp->FunctionNumber) { + RootBridge = Temp; + break; + } + + CurrentLink = CurrentLink->ForwardLink; + } + + // + // Check if we find the bridge + // + if (CurrentLink == &RootBridge->ChildList) { + + MisMatch = TRUE; + break; + + } + + CurrentDevicePath = EfiNextDevicePathNode (CurrentDevicePath); + } + + if (MisMatch) { + + CurrentDevicePath = EfiNextDevicePathNode (CurrentDevicePath); + + if (EfiIsDevicePathEnd (CurrentDevicePath)) { + *PciAddress = EFI_PCI_ADDRESS (RootBridge->BusNumber, Node.Pci->Device, Node.Pci->Function, 0); + return EFI_SUCCESS; + } + + return EFI_NOT_FOUND; + } + + *PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0); + + return EFI_SUCCESS; + +} diff --git a/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciDeviceSupport.h b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciDeviceSupport.h new file mode 100644 index 0000000000..374f4dfad3 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciDeviceSupport.h @@ -0,0 +1,477 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PciDeviceSupport.h + +Abstract: + + + +Revision History + +--*/ + +#ifndef _EFI_PCI_DEVICE_SUPPORT_H +#define _EFI_PCI_DEVICE_SUPPORT_H + +EFI_STATUS +InitializePciDevicePool ( + VOID + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + None + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +InsertRootBridge ( + PCI_IO_DEVICE *RootBridge + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + RootBridge - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +InsertPciDevice ( + PCI_IO_DEVICE *Bridge, + PCI_IO_DEVICE *PciDeviceNode + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Bridge - TODO: add argument description + PciDeviceNode - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +DestroyRootBridge ( + IN PCI_IO_DEVICE *RootBridge + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + RootBridge - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +DestroyPciDeviceTree ( + IN PCI_IO_DEVICE *Bridge + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Bridge - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +DestroyRootBridgeByHandle ( + EFI_HANDLE Controller + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Controller - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +RegisterPciDevice ( + IN EFI_HANDLE Controller, + IN PCI_IO_DEVICE *PciIoDevice, + OUT EFI_HANDLE *Handle OPTIONAL + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Controller - TODO: add argument description + PciIoDevice - TODO: add argument description + Handle - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +RemoveAllPciDeviceOnBridge ( + EFI_HANDLE RootBridgeHandle, + PCI_IO_DEVICE *Bridge + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + RootBridgeHandle - TODO: add argument description + Bridge - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +DeRegisterPciDevice ( + IN EFI_HANDLE Controller, + IN EFI_HANDLE Handle + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Controller - TODO: add argument description + Handle - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +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 + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Controller - TODO: add argument description + RootBridge - TODO: add argument description + RemainingDevicePath - TODO: add argument description + NumberOfChildren - TODO: add argument description + ChildHandleBuffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +StartPciDevices ( + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Controller - TODO: add argument description + RemainingDevicePath - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +PCI_IO_DEVICE * +CreateRootBridge ( + IN EFI_HANDLE RootBridgeHandle + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + RootBridgeHandle - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +PCI_IO_DEVICE * +GetRootBridgeByHandle ( + EFI_HANDLE RootBridgeHandle + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + RootBridgeHandle - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +RootBridgeExisted ( + IN EFI_HANDLE RootBridgeHandle + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + RootBridgeHandle - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +PciDeviceExisted ( + IN PCI_IO_DEVICE *Bridge, + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Bridge - TODO: add argument description + PciIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +PCI_IO_DEVICE * +ActiveVGADeviceOnTheSameSegment ( + IN PCI_IO_DEVICE *VgaDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + VgaDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +PCI_IO_DEVICE * +ActiveVGADeviceOnTheRootBridge ( + IN PCI_IO_DEVICE *RootBridge + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + RootBridge - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +GetHpcPciAddress ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, + IN EFI_DEVICE_PATH_PROTOCOL *HpcDevicePath, + OUT UINT64 *PciAddress + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciRootBridgeIo - TODO: add argument description + HpcDevicePath - TODO: add argument description + PciAddress - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +GetHpcPciAddressFromRootBridge ( + IN PCI_IO_DEVICE *RootBridge, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath, + OUT UINT64 *PciAddress + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + RootBridge - TODO: add argument description + RemainingDevicePath - TODO: add argument description + PciAddress - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +FreePciDevice ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciDriverOverride.c b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciDriverOverride.c new file mode 100644 index 0000000000..76c5a20784 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciDriverOverride.c @@ -0,0 +1,290 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PciDriverOverride.c + +Abstract: + + PCI Bus Driver + +Revision History + +--*/ + +#include "pcibus.h" + +EFI_STATUS +InitializePciDriverOverrideInstance ( + PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + Initializes a PCI Driver Override Instance + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciIoDevice - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + PciIoDevice->PciDriverOverride.GetDriver = GetDriver; + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +GetDriver ( + IN EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL *This, + IN OUT EFI_HANDLE *DriverImageHandle + ) +/*++ + +Routine Description: + + Get a overriding driver image + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: DriverImageHandle - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +{ + PCI_IO_DEVICE *PciIoDevice; + LIST_ENTRY *CurrentLink; + PCI_DRIVER_OVERRIDE_LIST *Node; + + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_DRIVER_OVERRIDE_THIS (This); + + CurrentLink = PciIoDevice->OptionRomDriverList.ForwardLink; + + while (CurrentLink && CurrentLink != &PciIoDevice->OptionRomDriverList) { + + Node = DRIVER_OVERRIDE_FROM_LINK (CurrentLink); + + if (*DriverImageHandle == NULL) { + + *DriverImageHandle = Node->DriverImageHandle; + return EFI_SUCCESS; + } + + if (*DriverImageHandle == Node->DriverImageHandle) { + + if (CurrentLink->ForwardLink == &PciIoDevice->OptionRomDriverList || + CurrentLink->ForwardLink == NULL) { + return EFI_NOT_FOUND; + } + + // + // Get next node + // + Node = DRIVER_OVERRIDE_FROM_LINK (CurrentLink->ForwardLink); + *DriverImageHandle = Node->DriverImageHandle; + return EFI_SUCCESS; + } + + CurrentLink = CurrentLink->ForwardLink; + } + + return EFI_INVALID_PARAMETER; +} + +EFI_STATUS +AddDriver ( + IN PCI_IO_DEVICE *PciIoDevice, + IN EFI_HANDLE DriverImageHandle + ) +/*++ + +Routine Description: + + Add a overriding driver image + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciIoDevice - add argument and description to function comment +// TODO: DriverImageHandle - add argument and description to function comment +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + EFI_IMAGE_DOS_HEADER *DosHdr; + EFI_IMAGE_NT_HEADERS *PeHdr; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + PCI_DRIVER_OVERRIDE_LIST *Node; + EFI_DRIVER_OS_HANDOFF_HEADER *DriverOsHandoffHeader; + EFI_DRIVER_OS_HANDOFF_HEADER *NewDriverOsHandoffHeader; + EFI_DRIVER_OS_HANDOFF *DriverOsHandoff; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_HANDLE DeviceHandle; + UINTN NumberOfEntries; + UINTN Size; + UINTN Index; + + Status = gBS->HandleProtocol (DriverImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &LoadedImage); + if (EFI_ERROR (Status)) { + return Status; + } + + Node = AllocatePool (sizeof (PCI_DRIVER_OVERRIDE_LIST)); + if (Node == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Node->Signature = DRIVER_OVERRIDE_SIGNATURE; + Node->DriverImageHandle = DriverImageHandle; + + InsertTailList (&PciIoDevice->OptionRomDriverList, &(Node->Link)); + + PciIoDevice->BusOverride = TRUE; + + DosHdr = (EFI_IMAGE_DOS_HEADER *) LoadedImage->ImageBase; + if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) { + return EFI_SUCCESS; + } + + PeHdr = (EFI_IMAGE_NT_HEADERS *) ((UINTN) LoadedImage->ImageBase + DosHdr->e_lfanew); + + if (PeHdr->FileHeader.Machine != EFI_IMAGE_MACHINE_EBC) { + return EFI_SUCCESS; + } + + DriverOsHandoffHeader = NULL; + Status = EfiGetSystemConfigurationTable (&gEfiUgaIoProtocolGuid, (VOID **) &DriverOsHandoffHeader); + if (!EFI_ERROR (Status) && DriverOsHandoffHeader != NULL) { + for (Index = 0; Index < DriverOsHandoffHeader->NumberOfEntries; Index++) { + DriverOsHandoff = (EFI_DRIVER_OS_HANDOFF *)((UINTN)(DriverOsHandoffHeader) + + DriverOsHandoffHeader->HeaderSize + + Index * DriverOsHandoffHeader->SizeOfEntries); + DevicePath = DriverOsHandoff->DevicePath; + Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &DevicePath, &DeviceHandle); + if (!EFI_ERROR (Status) && DeviceHandle != NULL && IsDevicePathEnd (DevicePath)) { + if (DeviceHandle == PciIoDevice->Handle) { + return EFI_SUCCESS; + } + } + } + + NumberOfEntries = DriverOsHandoffHeader->NumberOfEntries + 1; + } else { + NumberOfEntries = 1; + } + + Status = gBS->AllocatePool ( + EfiRuntimeServicesData, + sizeof (EFI_DRIVER_OS_HANDOFF_HEADER) + NumberOfEntries * sizeof (EFI_DRIVER_OS_HANDOFF), + (VOID **) &NewDriverOsHandoffHeader + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (DriverOsHandoffHeader == NULL) { + NewDriverOsHandoffHeader->Version = 0; + NewDriverOsHandoffHeader->HeaderSize = sizeof (EFI_DRIVER_OS_HANDOFF_HEADER); + NewDriverOsHandoffHeader->SizeOfEntries = sizeof (EFI_DRIVER_OS_HANDOFF); + NewDriverOsHandoffHeader->NumberOfEntries = (UINT32) NumberOfEntries; + } else { + gBS->CopyMem ( + NewDriverOsHandoffHeader, + DriverOsHandoffHeader, + DriverOsHandoffHeader->HeaderSize + (NumberOfEntries - 1) * DriverOsHandoffHeader->SizeOfEntries + ); + NewDriverOsHandoffHeader->NumberOfEntries = (UINT32) NumberOfEntries; + } + + DriverOsHandoff = (EFI_DRIVER_OS_HANDOFF *)((UINTN)NewDriverOsHandoffHeader + + NewDriverOsHandoffHeader->HeaderSize + + (NumberOfEntries - 1) * NewDriverOsHandoffHeader->SizeOfEntries); + + // + // Fill in the EFI_DRIVER_OS_HANDOFF structure + // + DriverOsHandoff->Type = EfiUgaDriverFromPciRom; + + // + // Compute the size of the device path + // + Size = GetDevicePathSize (PciIoDevice->DevicePath); + if (Size == 0) { + DriverOsHandoff->DevicePath = NULL; + } else { + + // + // Allocate space for duplicate device path + // + Status = gBS->AllocatePool ( + EfiRuntimeServicesData, + Size, + (VOID **) &DriverOsHandoff->DevicePath + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (NewDriverOsHandoffHeader); + return Status; + } + + // + // Make copy of device path + // + CopyMem (DriverOsHandoff->DevicePath, PciIoDevice->DevicePath, Size); + } + + DriverOsHandoff->PciRomSize = (UINT64) PciIoDevice->PciIo.RomSize; + Status = gBS->AllocatePool ( + EfiRuntimeServicesData, + (UINTN) DriverOsHandoff->PciRomSize, + (VOID **) &DriverOsHandoff->PciRomImage + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (NewDriverOsHandoffHeader); + return Status; + } + + gBS->CopyMem ( + DriverOsHandoff->PciRomImage, + PciIoDevice->PciIo.RomImage, + (UINTN) DriverOsHandoff->PciRomSize + ); + + Status = gBS->InstallConfigurationTable (&gEfiUgaIoProtocolGuid, NewDriverOsHandoffHeader); + if (EFI_ERROR (Status)) { + return Status; + } + + if (DriverOsHandoffHeader != NULL) { + gBS->FreePool (DriverOsHandoffHeader); + } + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciDriverOverride.h b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciDriverOverride.h new file mode 100644 index 0000000000..5992df9eb7 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciDriverOverride.h @@ -0,0 +1,108 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PciDriverOverride.h + +Abstract: + + + +Revision History + +--*/ + +#ifndef _EFI_PCI_DRIVER_OVERRRIDE_H +#define _EFI_PCI_DRIVER_OVERRRIDE_H + +#define DRIVER_OVERRIDE_SIGNATURE EFI_SIGNATURE_32 ('d', 'r', 'o', 'v') + +typedef struct { + UINT32 Signature; + LIST_ENTRY Link; + EFI_HANDLE DriverImageHandle; +} PCI_DRIVER_OVERRIDE_LIST; + + +#define DRIVER_OVERRIDE_FROM_LINK(a) \ + CR (a, PCI_DRIVER_OVERRIDE_LIST, Link, DRIVER_OVERRIDE_SIGNATURE) + + +EFI_STATUS +InitializePciDriverOverrideInstance ( + PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AddDriver ( + IN PCI_IO_DEVICE *PciIoDevice, + IN EFI_HANDLE DriverImageHandle + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + DriverImageHandle - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +GetDriver ( + IN EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL *This, + IN OUT EFI_HANDLE *DriverImageHandle + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + DriverImageHandle - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciEnumerator.c b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciEnumerator.c new file mode 100644 index 0000000000..d3566a1600 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciEnumerator.c @@ -0,0 +1,2164 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PciEnumerator.c + +Abstract: + + PCI Bus Driver + +Revision History + +--*/ + +#include "Pcibus.h" +#include "PciEnumerator.h" +#include "PciResourceSupport.h" +#include "PciOptionRomSupport.h" + +EFI_STATUS +PciEnumerator ( + IN EFI_HANDLE Controller + ) +/*++ + +Routine Description: + + This routine is used to enumerate entire pci bus system + in a given platform + +Arguments: + +Returns: + + None + +--*/ +// TODO: Controller - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + + EFI_HANDLE HostBridgeHandle; + EFI_STATUS Status; + EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; + + // + // If PCI bus has already done the full enumeration, never do it again + // + if (!gFullEnumeration) { + return PciEnumeratorLight (Controller); + } + + // + // If this host bridge has been already enumerated, then return successfully + // + if (RootBridgeExisted (Controller)) { + return EFI_SUCCESS; + } + + // + // 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)) { + return Status; + } + + // + // Get the host bridge handle + // + HostBridgeHandle = PciRootBridgeIo->ParentHandle; + + // + // 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 + // + NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginEnumeration); + + // + // 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; + } + + // + // 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; + } + + gFullEnumeration = FALSE; + + return EFI_SUCCESS; +} + +EFI_STATUS +PciRootBridgeEnumerator ( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc, + IN PCI_IO_DEVICE *RootBridgeDev + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciResAlloc - add argument and description to function comment +// TODO: RootBridgeDev - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *pConfiguration; + UINT8 SubBusNumber; + UINT8 StartBusNumber; + UINT8 PaddedBusRange; + EFI_HANDLE RootBridgeHandle; + + 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_PC_BUS_ENUM, + RootBridgeDev->DevicePath + ); + + // + // Get the Bus information + // + Status = PciResAlloc->StartBusEnumeration ( + PciResAlloc, + RootBridgeHandle, + (VOID **) &pConfiguration + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get the bus number to start with + // + StartBusNumber = (UINT8) (pConfiguration->AddrRangeMin); + + // + // Initialize the subordinate bus number + // + SubBusNumber = StartBusNumber; + + // + // Assign bus number + // + Status = PciScanBus ( + RootBridgeDev, + (UINT8) (pConfiguration->AddrRangeMin), + &SubBusNumber, + &PaddedBusRange + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + + // + // Assign max bus number scanned + // + pConfiguration->AddrLen = SubBusNumber - StartBusNumber + 1 + PaddedBusRange; + + // + // Set bus number + // + Status = PciResAlloc->SetBusNumbers ( + PciResAlloc, + RootBridgeHandle, + pConfiguration + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +ProcessOptionRom ( + IN PCI_IO_DEVICE *Bridge, + IN UINT64 RomBase, + IN UINT64 MaxLength + ) +/*++ + +Routine Description: + + This routine is used to process option rom on a certain root bridge + +Arguments: + +Returns: + + None + +--*/ +// TODO: Bridge - add argument and description to function comment +// TODO: RomBase - add argument and description to function comment +// TODO: MaxLength - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + LIST_ENTRY *CurrentLink; + PCI_IO_DEVICE *Temp; + EFI_STATUS Status; + + // + // Go through bridges to reach all devices + // + CurrentLink = Bridge->ChildList.ForwardLink; + while (CurrentLink && CurrentLink != &Bridge->ChildList) { + Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + if (!IsListEmpty (&Temp->ChildList)) { + + // + // Go further to process the option rom under this bridge + // + Status = ProcessOptionRom (Temp, RomBase, MaxLength); + } + + if (Temp->RomSize != 0 && Temp->RomSize <= MaxLength) { + + // + // Load and process the option rom + // + Status = LoadOpRomImage (Temp, RomBase); + if (Status == EFI_SUCCESS) { + Status = ProcessOpRomImage (Temp); + } + } + + CurrentLink = CurrentLink->ForwardLink; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +PciAssignBusNumber ( + IN PCI_IO_DEVICE *Bridge, + IN UINT8 StartBusNumber, + OUT UINT8 *SubBusNumber + ) +/*++ + +Routine Description: + + This routine is used to assign bus number to the given PCI bus system + +Arguments: + +Returns: + + None + +--*/ +// TODO: Bridge - add argument and description to function comment +// TODO: StartBusNumber - add argument and description to function comment +// TODO: SubBusNumber - add argument and description to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + 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) && + (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci))) { + + // + // Reserved one bus for cardbus bridge + // + 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; +} + +EFI_STATUS +DetermineRootBridgeAttributes ( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc, + IN PCI_IO_DEVICE *RootBridgeDev + ) +/*++ + +Routine Description: + + This routine is used to determine the root bridge attribute by interfacing + the host bridge resource allocation protocol. + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciResAlloc - add argument and description to function comment +// TODO: RootBridgeDev - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + 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) { + RootBridgeDev->Decodes |= EFI_BRIDGE_PMEM_MEM_COMBINE_SUPPORTED; + } + + if (Attributes & EFI_PCI_HOST_BRIDGE_MEM64_DECODE) { + 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; +} + +UINT64 +GetMaxOptionRomSize ( + IN PCI_IO_DEVICE *Bridge + ) +/*++ + +Routine Description: + + Get Max Option Rom size on this bridge + +Arguments: + +Returns: + + None + +--*/ +// TODO: Bridge - add argument and description to function comment +{ + LIST_ENTRY *CurrentLink; + PCI_IO_DEVICE *Temp; + UINT64 MaxOptionRomSize; + UINT64 TempOptionRomSize; + + MaxOptionRomSize = 0; + + // + // Go through bridges to reach all devices + // + CurrentLink = Bridge->ChildList.ForwardLink; + while (CurrentLink && 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; +} + +EFI_STATUS +PciHostBridgeDeviceAttribute ( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc + ) +/*++ + +Routine Description: + + Process attributes of devices on this host bridge + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciResAlloc - add argument and description to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + 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; +} + +EFI_STATUS +GetResourceAllocationStatus ( + VOID *AcpiConfig, + OUT UINT64 *IoResStatus, + OUT UINT64 *Mem32ResStatus, + OUT UINT64 *PMem32ResStatus, + OUT UINT64 *Mem64ResStatus, + OUT UINT64 *PMem64ResStatus + ) +/*++ + +Routine Description: + + Get resource allocation status from the ACPI pointer + +Arguments: + +Returns: + + None + +--*/ +// TODO: AcpiConfig - add argument and description to function comment +// TODO: IoResStatus - add argument and description to function comment +// TODO: Mem32ResStatus - add argument and description to function comment +// TODO: PMem32ResStatus - add argument and description to function comment +// TODO: Mem64ResStatus - add argument and description to function comment +// TODO: PMem64ResStatus - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + + UINT8 *Temp; + UINT64 ResStatus; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *ptr; + + Temp = (UINT8 *) AcpiConfig; + + while (*Temp == ACPI_ADDRESS_SPACE_DESCRIPTOR) { + + ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp; + ResStatus = ptr->AddrTranslationOffset; + + switch (ptr->ResType) { + case 0: + if (ptr->AddrSpaceGranularity == 32) { + if (ptr->SpecificFlag == 0x06) { + // + // Pmem32 + // + *PMem32ResStatus = ResStatus; + } else { + // + // Mem32 + // + *Mem32ResStatus = ResStatus; + } + } + + if (ptr->AddrSpaceGranularity == 64) { + if (ptr->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); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +RejectPciDevice ( + IN PCI_IO_DEVICE *PciDevice + ) +/*++ + +Routine Description: + + Remove a PCI device from device pool and mark its bar + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciDevice - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_ABORTED - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_ABORTED - add return value to function comment +{ + 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 ) { + gBS->FreePool (PciDevice->ResourcePaddingDescriptors); + PciDevice->ResourcePaddingDescriptors = NULL; + return EFI_SUCCESS; + } + + // + // Skip RB and PPB + // + if (IS_PCI_BRIDGE (&PciDevice->Pci) || (!PciDevice->Parent)) { + return EFI_ABORTED; + } + + if (IS_CARDBUS_BRIDGE (&PciDevice->Pci)) { + // + // Get the root bridge device + // + Bridge = PciDevice; + while (Bridge->Parent) { + Bridge = Bridge->Parent; + } + + RemoveAllPciDeviceOnBridge (Bridge->Handle, PciDevice); + + // + // Mark its bar + // + InitializeP2C (PciDevice); + } + + // + // Remove the device + // + Bridge = PciDevice->Parent; + CurrentLink = Bridge->ChildList.ForwardLink; + while (CurrentLink && CurrentLink != &Bridge->ChildList) { + Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + if (Temp == PciDevice) { + InitializePciDevice (Temp); + RemoveEntryList (CurrentLink); + FreePciDevice (Temp); + return EFI_SUCCESS; + } + + CurrentLink = CurrentLink->ForwardLink; + } + + return EFI_ABORTED; +} + +BOOLEAN +IsRejectiveDevice ( + IN PCI_RESOURCE_NODE *PciResNode + ) +/*++ + +Routine Description: + + Determine whethter a PCI device can be rejected + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciResNode - add argument and description to function comment +{ + PCI_IO_DEVICE *Temp; + + Temp = PciResNode->PciDev; + + // + // Ensure the device is present + // + if (!Temp) { + return FALSE; + } + + // + // PPB and RB should go ahead + // + if (IS_PCI_BRIDGE (&Temp->Pci) || (!Temp->Parent)) { + return TRUE; + } + + // + // Skip device on Bus0 + // + if ((Temp->Parent) && (Temp->BusNumber == 0)) { + return FALSE; + } + + // + // Skip VGA + // + if (IS_PCI_VGA (&Temp->Pci)) { + return FALSE; + } + + return TRUE; +} + +PCI_RESOURCE_NODE * +GetLargerConsumerDevice ( + IN PCI_RESOURCE_NODE *PciResNode1, + IN PCI_RESOURCE_NODE *PciResNode2 + ) +/*++ + +Routine Description: + + Get the larger resource consumer + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciResNode1 - add argument and description to function comment +// TODO: PciResNode2 - add argument and description to function comment +{ + if (!PciResNode2) { + return PciResNode1; + } + + if ((IS_PCI_BRIDGE(&(PciResNode2->PciDev->Pci)) || !(PciResNode2->PciDev->Parent)) \ + && (PciResNode2->ResourceUsage != PciResUsagePadding) ) + { + return PciResNode1; + } + + if (!PciResNode1) { + return PciResNode2; + } + + if ((PciResNode1->Length) > (PciResNode2->Length)) { + return PciResNode1; + } + + return PciResNode2; + +} + +PCI_RESOURCE_NODE * +GetMaxResourceConsumerDevice ( + IN PCI_RESOURCE_NODE *ResPool + ) +/*++ + +Routine Description: + + Get the max resource consumer in the host resource pool + +Arguments: + +Returns: + + None + +--*/ +// TODO: ResPool - add argument and description to function comment +{ + PCI_RESOURCE_NODE *Temp; + LIST_ENTRY *CurrentLink; + PCI_RESOURCE_NODE *PciResNode; + PCI_RESOURCE_NODE *PPBResNode; + + PciResNode = NULL; + + CurrentLink = ResPool->ChildList.ForwardLink; + while (CurrentLink && 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)) \ + && (Temp->ResourceUsage != PciResUsagePadding)) + { + PPBResNode = GetMaxResourceConsumerDevice (Temp); + PciResNode = GetLargerConsumerDevice (PciResNode, PPBResNode); + } else { + PciResNode = GetLargerConsumerDevice (PciResNode, Temp); + } + + CurrentLink = CurrentLink->ForwardLink; + } + + return PciResNode; +} + +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 + ) +/*++ + +Routine Description: + + Adjust host bridge allocation so as to reduce resource requirement + +Arguments: + +Returns: + + None + +--*/ +// TODO: IoPool - add argument and description to function comment +// TODO: Mem32Pool - add argument and description to function comment +// TODO: PMem32Pool - add argument and description to function comment +// TODO: Mem64Pool - add argument and description to function comment +// TODO: PMem64Pool - add argument and description to function comment +// TODO: IoResStatus - add argument and description to function comment +// TODO: Mem32ResStatus - add argument and description to function comment +// TODO: PMem32ResStatus - add argument and description to function comment +// TODO: Mem64ResStatus - add argument and description to function comment +// TODO: PMem64ResStatus - add argument and description to function comment +// TODO: EFI_ABORTED - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_ABORTED - add return value to function comment +{ + 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; + REPORT_STATUS_CODE_LIBRARY_RESOURCE_ALLOC_FAILURE_ERROR_DATA 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_NONEXISTENT) { + // + // Hostbridge hasn't this resource type + // + return EFI_ABORTED; + } + + // + // Hostbridge hasn't enough resource + // + PciResNode = GetMaxResourceConsumerDevice (ResPool[ResType]); + if (!PciResNode) { + continue; + } + + // + // Check if the device has been removed before + // + for (DevIndex = 0; DevIndex < RemovedPciDevNum; DevIndex++) { + if (PciResNode->PciDev == RemovedPciDev[DevIndex]) { + continue; + } + } + + // + // Remove the device if it isn't in the array + // + Status = RejectPciDevice (PciResNode->PciDev); + if (Status == EFI_SUCCESS) { + + // + // Raise the EFI_IOB_EC_RESOURCE_CONFLICT status code + // + // + // Have no way to get ReqRes, AllocRes & Bar here + // + ZeroMem (&AllocFailExtendedData, sizeof (AllocFailExtendedData)); + AllocFailExtendedData.DevicePathSize = 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; + } +} + +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 **pConfig + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: Bridge - add argument and description to function comment +// TODO: IoNode - add argument and description to function comment +// TODO: Mem32Node - add argument and description to function comment +// TODO: PMem32Node - add argument and description to function comment +// TODO: Mem64Node - add argument and description to function comment +// TODO: PMem64Node - add argument and description to function comment +// TODO: pConfig - add argument and description to function comment +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + UINT8 NumConfig; + UINT8 Aperture; + UINT8 *Configuration; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr; + EFI_ACPI_END_TAG_DESCRIPTOR *PtrEnd; + + NumConfig = 0; + Aperture = 0; + + *pConfig = 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 = AllocatePool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) * NumConfig + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)); + if (Configuration == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + ZeroMem ( + Configuration, + sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) * NumConfig + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR) + ); + + Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration; + + // + // Deal with io aperture + // + if (Aperture & 0x01) { + Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; + Ptr->Len = 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 = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) ((UINT8 *) Ptr + sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR)); + } + // + // Deal with mem32 aperture + // + if (Aperture & 0x02) { + Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; + Ptr->Len = 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 = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) ((UINT8 *) Ptr + sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR)); + } + + // + // Deal with Pmem32 aperture + // + if (Aperture & 0x04) { + Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; + Ptr->Len = 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 = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) ((UINT8 *) Ptr + sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR)); + } + // + // Deal with mem64 aperture + // + if (Aperture & 0x08) { + Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; + Ptr->Len = 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 = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) ((UINT8 *) Ptr + sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR)); + } + // + // Deal with Pmem64 aperture + // + if (Aperture & 0x10) { + Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; + Ptr->Len = 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 = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) (Configuration + sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR)); + } + + // + // put the checksum + // + PtrEnd = (EFI_ACPI_END_TAG_DESCRIPTOR *) ((UINT8 *) Ptr); + + PtrEnd->Desc = ACPI_END_TAG_DESCRIPTOR; + PtrEnd->Checksum = 0; + + } else { + + // + // If there is no resource request + // + Configuration = AllocatePool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)); + if (Configuration == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + ZeroMem (Configuration, sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)); + + Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) (Configuration); + Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; + + PtrEnd = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Configuration + sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR)); + PtrEnd->Desc = ACPI_END_TAG_DESCRIPTOR; + PtrEnd->Checksum = 0; + } + + *pConfig = Configuration; + + return EFI_SUCCESS; +} + +EFI_STATUS +GetResourceBase ( + IN VOID *pConfig, + OUT UINT64 *IoBase, + OUT UINT64 *Mem32Base, + OUT UINT64 *PMem32Base, + OUT UINT64 *Mem64Base, + OUT UINT64 *PMem64Base + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: pConfig - add argument and description to function comment +// TODO: IoBase - add argument and description to function comment +// TODO: Mem32Base - add argument and description to function comment +// TODO: PMem32Base - add argument and description to function comment +// TODO: Mem64Base - add argument and description to function comment +// TODO: PMem64Base - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + UINT8 *Temp; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr; + UINT64 ResStatus; + + *IoBase = 0xFFFFFFFFFFFFFFFFULL; + *Mem32Base = 0xFFFFFFFFFFFFFFFFULL; + *PMem32Base = 0xFFFFFFFFFFFFFFFFULL; + *Mem64Base = 0xFFFFFFFFFFFFFFFFULL; + *PMem64Base = 0xFFFFFFFFFFFFFFFFULL; + + Temp = (UINT8 *) pConfig; + + 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) { + *PMem32Base = Ptr->AddrRangeMin; + } else { + *Mem32Base = Ptr->AddrRangeMin; + } + } + + if (Ptr->AddrSpaceGranularity == 64) { + if (Ptr->SpecificFlag & 0x06) { + *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); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +PciBridgeEnumerator ( + IN PCI_IO_DEVICE *BridgeDev + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: BridgeDev - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + 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; + +} + +EFI_STATUS +PciBridgeResourceAllocator ( + IN PCI_IO_DEVICE *Bridge + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: Bridge - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + 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, + 0xFFF, + 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 + // + Status = CreateResourceMap ( + Bridge, + IoBridge, + Mem32Bridge, + PMem32Bridge, + Mem64Bridge, + PMem64Bridge + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + 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; +} + +EFI_STATUS +GetResourceBaseFromBridge ( + IN PCI_IO_DEVICE *Bridge, + OUT UINT64 *IoBase, + OUT UINT64 *Mem32Base, + OUT UINT64 *PMem32Base, + OUT UINT64 *Mem64Base, + OUT UINT64 *PMem64Base + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: Bridge - add argument and description to function comment +// TODO: IoBase - add argument and description to function comment +// TODO: Mem32Base - add argument and description to function comment +// TODO: PMem32Base - add argument and description to function comment +// TODO: Mem64Base - add argument and description to function comment +// TODO: PMem64Base - add argument and description to function comment +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + 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) { + *IoBase = Bridge->PciBar[PPB_IO_RANGE].BaseAddress; + } + + if (Bridge->PciBar[PPB_MEM32_RANGE].Length) { + *Mem32Base = Bridge->PciBar[PPB_MEM32_RANGE].BaseAddress; + } + + if (Bridge->PciBar[PPB_PMEM32_RANGE].Length) { + *PMem32Base = Bridge->PciBar[PPB_PMEM32_RANGE].BaseAddress; + } + + if (Bridge->PciBar[PPB_PMEM64_RANGE].Length) { + *PMem64Base = Bridge->PciBar[PPB_PMEM64_RANGE].BaseAddress; + } else { + *PMem64Base = gAllOne; + } + + } + + if (IS_CARDBUS_BRIDGE (&Bridge->Pci)) { + if (Bridge->PciBar[P2C_IO_1].Length) { + *IoBase = Bridge->PciBar[P2C_IO_1].BaseAddress; + } else { + if (Bridge->PciBar[P2C_IO_2].Length) { + *IoBase = Bridge->PciBar[P2C_IO_2].BaseAddress; + } + } + + if (Bridge->PciBar[P2C_MEM_1].Length) { + 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) { + 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; +} + +EFI_STATUS +NotifyPhase ( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc, + EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciResAlloc - add argument and description to function comment +// TODO: Phase - add argument and description to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + 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::PhaseNotify() if the protocol is present. + // + gPciPlatformProtocol->PhaseNotify ( + gPciPlatformProtocol, + HostBridgeHandle, + Phase, + ChipsetEntry + ); + } + + Status = PciResAlloc->NotifyPhase ( + PciResAlloc, + Phase + ); + + if (gPciPlatformProtocol != NULL) { + // + // Call PlatformPci::PhaseNotify() if the protocol is present. + // + gPciPlatformProtocol->PhaseNotify ( + gPciPlatformProtocol, + HostBridgeHandle, + Phase, + ChipsetExit + ); + + } + + return EFI_SUCCESS; +} + +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 + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: Bridge - add argument and description to function comment +// TODO: Bus - add argument and description to function comment +// TODO: Device - add argument and description to function comment +// TODO: Func - add argument and description to function comment +// TODO: Phase - add argument and description to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + 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) { + 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 + ); + } + + 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 + ); + } + + return EFI_SUCCESS; +} + +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 + ) +/*++ + +Routine Description: + + Hot plug request notify. + +Arguments: + + This - A pointer to the hot plug request protocol. + Operation - The operation. + Controller - A pointer to the controller. + RemainningDevicePath - A pointer to the device path. + NumberOfChildren - A the number of child handle in the ChildHandleBuffer. + ChildHandleBuffer - A pointer to the array contain the child handle. + +Returns: + + Status code. + +--*/ +// TODO: RemainingDevicePath - add argument and description to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + PCI_IO_DEVICE *Bridge; + PCI_IO_DEVICE *Temp; + EFI_PCI_IO_PROTOCOL *PciIo; + UINTN Index; + EFI_HANDLE RootBridgeHandle; + EFI_STATUS Status; + + 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) { + Temp = Temp->Parent; + } + + RootBridgeHandle = Temp->Handle; + + if (Operation == EfiPciHotPlugRequestAdd) { + + 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 EFI_SUCCESS; + } + + if (Operation == EfiPciHotplugRequestRemove) { + + if (*NumberOfChildren == 0) { + // + // Remove all devices on the bridge + // + Status = RemoveAllPciDeviceOnBridge (RootBridgeHandle, Bridge); + return Status; + + } + + 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; +} + +BOOLEAN +SearchHostBridgeHandle ( + IN EFI_HANDLE RootBridgeHandle + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: RootBridgeHandle - add argument and description to function comment +{ + 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; +} + +EFI_STATUS +AddHostBridgeEnumerator ( + IN EFI_HANDLE HostBridgeHandle + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: HostBridgeHandle - add argument and description to function comment +// TODO: EFI_ABORTED - add return value to function comment +// TODO: EFI_ABORTED - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + UINTN Index; + + if (!HostBridgeHandle) { + 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/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciEnumerator.h b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciEnumerator.h new file mode 100644 index 0000000000..e7667d5c49 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciEnumerator.h @@ -0,0 +1,628 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PciEnumerator.h + +Abstract: + + PCI Bus Driver + +Revision History + +--*/ + +#ifndef _EFI_PCI_ENUMERATOR_H +#define _EFI_PCI_ENUMERATOR_H + +#include "PciResourceSupport.h" + +EFI_STATUS +PciEnumerator ( + IN EFI_HANDLE Controller + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Controller - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +PciRootBridgeEnumerator ( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc, + IN PCI_IO_DEVICE *RootBridgeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciResAlloc - TODO: add argument description + RootBridgeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +ProcessOptionRom ( + IN PCI_IO_DEVICE *Bridge, + IN UINT64 RomBase, + IN UINT64 MaxLength + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Bridge - TODO: add argument description + RomBase - TODO: add argument description + MaxLength - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +PciAssignBusNumber ( + IN PCI_IO_DEVICE *Bridge, + IN UINT8 StartBusNumber, + OUT UINT8 *SubBusNumber + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Bridge - TODO: add argument description + StartBusNumber - TODO: add argument description + SubBusNumber - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +DetermineRootBridgeAttributes ( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc, + IN PCI_IO_DEVICE *RootBridgeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciResAlloc - TODO: add argument description + RootBridgeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +UINT64 +GetMaxOptionRomSize ( + IN PCI_IO_DEVICE *Bridge + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Bridge - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +PciHostBridgeDeviceAttribute ( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciResAlloc - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +GetResourceAllocationStatus ( + VOID *AcpiConfig, + OUT UINT64 *IoResStatus, + OUT UINT64 *Mem32ResStatus, + OUT UINT64 *PMem32ResStatus, + OUT UINT64 *Mem64ResStatus, + OUT UINT64 *PMem64ResStatus + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AcpiConfig - TODO: add argument description + IoResStatus - TODO: add argument description + Mem32ResStatus - TODO: add argument description + PMem32ResStatus - TODO: add argument description + Mem64ResStatus - TODO: add argument description + PMem64ResStatus - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +RejectPciDevice ( + IN PCI_IO_DEVICE *PciDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +IsRejectiveDevice ( + IN PCI_RESOURCE_NODE *PciResNode + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciResNode - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +PCI_RESOURCE_NODE * +GetLargerConsumerDevice ( + IN PCI_RESOURCE_NODE *PciResNode1, + IN PCI_RESOURCE_NODE *PciResNode2 + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciResNode1 - TODO: add argument description + PciResNode2 - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +PCI_RESOURCE_NODE * +GetMaxResourceConsumerDevice ( + IN PCI_RESOURCE_NODE *ResPool + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ResPool - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +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 + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IoPool - TODO: add argument description + Mem32Pool - TODO: add argument description + PMem32Pool - TODO: add argument description + Mem64Pool - TODO: add argument description + PMem64Pool - TODO: add argument description + IoResStatus - TODO: add argument description + Mem32ResStatus - TODO: add argument description + PMem32ResStatus - TODO: add argument description + Mem64ResStatus - TODO: add argument description + PMem64ResStatus - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +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 **pConfig + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Bridge - TODO: add argument description + IoNode - TODO: add argument description + Mem32Node - TODO: add argument description + PMem32Node - TODO: add argument description + Mem64Node - TODO: add argument description + PMem64Node - TODO: add argument description + pConfig - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +GetResourceBase ( + IN VOID *pConfig, + OUT UINT64 *IoBase, + OUT UINT64 *Mem32Base, + OUT UINT64 *PMem32Base, + OUT UINT64 *Mem64Base, + OUT UINT64 *PMem64Base + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + pConfig - TODO: add argument description + IoBase - TODO: add argument description + Mem32Base - TODO: add argument description + PMem32Base - TODO: add argument description + Mem64Base - TODO: add argument description + PMem64Base - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +PciBridgeEnumerator ( + IN PCI_IO_DEVICE *BridgeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + BridgeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +PciBridgeResourceAllocator ( + IN PCI_IO_DEVICE *Bridge + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Bridge - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +GetResourceBaseFromBridge ( + IN PCI_IO_DEVICE *Bridge, + OUT UINT64 *IoBase, + OUT UINT64 *Mem32Base, + OUT UINT64 *PMem32Base, + OUT UINT64 *Mem64Base, + OUT UINT64 *PMem64Base + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Bridge - TODO: add argument description + IoBase - TODO: add argument description + Mem32Base - TODO: add argument description + PMem32Base - TODO: add argument description + Mem64Base - TODO: add argument description + PMem64Base - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +PciHostBridgeP2CProcess ( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciResAlloc - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +NotifyPhase ( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc, + EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciResAlloc - TODO: add argument description + Phase - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +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 + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Bridge - TODO: add argument description + Bus - TODO: add argument description + Device - TODO: add argument description + Func - TODO: add argument description + Phase - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +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 + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Operation - TODO: add argument description + Controller - TODO: add argument description + RemainingDevicePath - TODO: add argument description + NumberOfChildren - TODO: add argument description + ChildHandleBuffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +SearchHostBridgeHandle ( + IN EFI_HANDLE RootBridgeHandle + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + RootBridgeHandle - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AddHostBridgeEnumerator ( + IN EFI_HANDLE HostBridgeHandle + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + HostBridgeHandle - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciEnumeratorSupport.c b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciEnumeratorSupport.c new file mode 100644 index 0000000000..2c54897953 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciEnumeratorSupport.c @@ -0,0 +1,2261 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PciEnumeratorSupport.c + +Abstract: + + PCI Bus Driver + +Revision History + +--*/ + +#include "Pcibus.h" +#include "PciEnumeratorSupport.h" +#include "PciCommand.h" +#include "PciIo.h" + +EFI_STATUS +PciDevicePresent ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, + PCI_TYPE00 *Pci, + UINT8 Bus, + UINT8 Device, + UINT8 Func + ) +/*++ + +Routine Description: + + This routine is used to check whether the pci device is present + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciRootBridgeIo - add argument and description to function comment +// TODO: Pci - add argument and description to function comment +// TODO: Bus - add argument and description to function comment +// TODO: Device - add argument and description to function comment +// TODO: Func - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +{ + 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; +} + +EFI_STATUS +PciPciDeviceInfoCollector ( + IN PCI_IO_DEVICE *Bridge, + UINT8 StartBusNumber + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: Bridge - add argument and description to function comment +// TODO: StartBusNumber - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + 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)) { + + // + // 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, 0x19, 1, &SecBus); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // 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; +} + +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 + ) +/*++ + +Routine Description: + + Search required device. + +Arguments: + + Bridge - A pointer to the PCI_IO_DEVICE. + Pci - A pointer to the PCI_TYPE00. + Bus - Bus number. + Device - Device number. + Func - Function number. + PciDevice - The Required pci device. + +Returns: + + Status code. + +--*/ +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + PCI_IO_DEVICE *PciIoDevice; + + PciIoDevice = NULL; + + if (!IS_PCI_BRIDGE (Pci)) { + + if (IS_CARDBUS_BRIDGE (Pci)) { + PciIoDevice = GatherP2CInfo ( + Bridge, + Pci, + Bus, + Device, + Func + ); + if (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 (gFullEnumeration) { + InitializePpb (PciIoDevice); + } + } + + if (!PciIoDevice) { + 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; +} + +PCI_IO_DEVICE * +GatherDeviceInfo ( + IN PCI_IO_DEVICE *Bridge, + IN PCI_TYPE00 *Pci, + UINT8 Bus, + UINT8 Device, + UINT8 Func + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: Bridge - add argument and description to function comment +// TODO: Pci - add argument and description to function comment +// TODO: Bus - add argument and description to function comment +// TODO: Device - add argument and description to function comment +// TODO: Func - add argument and description to function comment +{ + UINTN Offset; + UINTN BarIndex; + PCI_IO_DEVICE *PciIoDevice; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; + + PciRootBridgeIo = Bridge->PciRootBridgeIo; + PciIoDevice = CreatePciIoDevice ( + PciRootBridgeIo, + Pci, + Bus, + Device, + Func + ); + + if (!PciIoDevice) { + return NULL; + } + + // + // Create a device path for this PCI device and store it into its private data + // + CreatePciDevicePath ( + Bridge->DevicePath, + PciIoDevice + ); + + // + // If it is a full enumeration, disconnect the device in advance + // + if (gFullEnumeration) { + + PciSetCommandRegister (PciIoDevice, 0); + + } + + // + // Start to parse the bars + // + for (Offset = 0x10, BarIndex = 0; Offset <= 0x24; BarIndex++) { + Offset = PciParseBar (PciIoDevice, Offset, BarIndex); + } + + return PciIoDevice; +} + +PCI_IO_DEVICE * +GatherPpbInfo ( + IN PCI_IO_DEVICE *Bridge, + IN PCI_TYPE00 *Pci, + UINT8 Bus, + UINT8 Device, + UINT8 Func + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: Bridge - add argument and description to function comment +// TODO: Pci - add argument and description to function comment +// TODO: Bus - add argument and description to function comment +// TODO: Device - add argument and description to function comment +// TODO: Func - add argument and description to function comment +{ + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; + PCI_IO_DEVICE *PciIoDevice; + EFI_STATUS Status; + UINT32 Value; + EFI_PCI_IO_PROTOCOL *PciIo; + UINT8 Temp; + + PciRootBridgeIo = Bridge->PciRootBridgeIo; + PciIoDevice = CreatePciIoDevice ( + PciRootBridgeIo, + Pci, + Bus, + Device, + Func + ); + + if (!PciIoDevice) { + return NULL; + } + + // + // Create a device path for this PCI device and store it into its private data + // + CreatePciDevicePath ( + Bridge->DevicePath, + PciIoDevice + ); + + if (gFullEnumeration) { + PciSetCommandRegister (PciIoDevice, 0); + + // + // Initalize the bridge control register + // + PciSetBridgeControlRegister (PciIoDevice, 0); + + } + + // + // 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) { + if (Value & 0x01) { + PciIoDevice->Decodes |= EFI_BRIDGE_IO32_DECODE_SUPPORTED; + } else { + PciIoDevice->Decodes |= EFI_BRIDGE_IO16_DECODE_SUPPORTED; + } + } + + Status = BarExisted ( + PciIoDevice, + 0x24, + NULL, + NULL + ); + + // + // test if it supports 64 memory or not + // + if (!EFI_ERROR (Status)) { + + 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); + + return PciIoDevice; +} + +PCI_IO_DEVICE * +GatherP2CInfo ( + IN PCI_IO_DEVICE *Bridge, + IN PCI_TYPE00 *Pci, + UINT8 Bus, + UINT8 Device, + UINT8 Func + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: Bridge - add argument and description to function comment +// TODO: Pci - add argument and description to function comment +// TODO: Bus - add argument and description to function comment +// TODO: Device - add argument and description to function comment +// TODO: Func - add argument and description to function comment +{ + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; + PCI_IO_DEVICE *PciIoDevice; + + PciRootBridgeIo = Bridge->PciRootBridgeIo; + PciIoDevice = CreatePciIoDevice ( + PciRootBridgeIo, + Pci, + Bus, + Device, + Func + ); + + if (!PciIoDevice) { + return NULL; + } + + // + // Create a device path for this PCI device and store it into its private data + // + CreatePciDevicePath ( + Bridge->DevicePath, + PciIoDevice + ); + + if (gFullEnumeration) { + PciSetCommandRegister (PciIoDevice, 0); + + // + // Initalize the bridge control register + // + PciSetBridgeControlRegister (PciIoDevice, 0); + + } + // + // 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; + + return PciIoDevice; +} + +EFI_DEVICE_PATH_PROTOCOL * +CreatePciDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath, + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: ParentDevicePath - add argument and description to function comment +// TODO: PciIoDevice - add argument and description to function comment +{ + + 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; +} + +EFI_STATUS +BarExisted ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINTN Offset, + OUT UINT32 *BarLengthValue, + OUT UINT32 *OriginalBarValue + ) +/*++ + +Routine Description: + + Check the bar is existed or not. + +Arguments: + + PciIoDevice - A pointer to the PCI_IO_DEVICE. + Offset - The offset. + BarLengthValue - The bar length value. + OriginalBarValue - The original bar value. + +Returns: + + EFI_NOT_FOUND - The bar don't exist. + EFI_SUCCESS - The bar exist. + +--*/ +{ + 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 (EFI_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; + } +} + +EFI_STATUS +PciTestSupportedAttribute ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINT16 *Command, + IN UINT16 *BridgeControl, + IN UINT16 *OldCommand, + IN UINT16 *OldBridgeControl + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciIoDevice - add argument and description to function comment +// TODO: Command - add argument and description to function comment +// TODO: BridgeControl - add argument and description to function comment +// TODO: OldCommand - add argument and description to function comment +// TODO: OldBridgeControl - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_TPL OldTpl; + + // + // Preserve the original value + // + PciReadCommandRegister (PciIoDevice, OldCommand); + + // + // Raise TPL to high level to disable timer interrupt while the BAR is probed + // + OldTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL); + + PciSetCommandRegister (PciIoDevice, *Command); + PciReadCommandRegister (PciIoDevice, Command); + + // + // Write back the original value + // + PciSetCommandRegister (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 + // + PciReadBridgeControlRegister (PciIoDevice, OldBridgeControl); + + // + // Raise TPL to high level to disable timer interrupt while the BAR is probed + // + OldTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL); + + PciSetBridgeControlRegister (PciIoDevice, *BridgeControl); + PciReadBridgeControlRegister (PciIoDevice, BridgeControl); + + // + // Write back the original value + // + PciSetBridgeControlRegister (PciIoDevice, *OldBridgeControl); + + // + // Restore TPL to its original level + // + gBS->RestoreTPL (OldTpl); + + } else { + *OldBridgeControl = 0; + *BridgeControl = 0; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +PciSetDeviceAttribute ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINT16 Command, + IN UINT16 BridgeControl, + IN UINTN Option + ) +/*++ + + Routine Description: + Set the supported or current attributes of a PCI device + + Arguments: + PciIoDevice - Structure pointer for PCI device. + Command - Command register value. + BridgeControl - Bridge control value for PPB or P2C. + Option - Make a choice of EFI_SET_SUPPORTS or EFI_SET_ATTRIBUTES. + + Returns: + +--*/ + +/*++ + +Routine Description: + + + +Arguments: + + +Returns: + + EFI_SUCCESS Always success + + +--*/ +{ + UINT64 Attributes; + + Attributes = 0; + + if (Command & EFI_PCI_COMMAND_IO_SPACE) { + Attributes |= EFI_PCI_IO_ATTRIBUTE_IO; + } + + if (Command & EFI_PCI_COMMAND_MEMORY_SPACE) { + Attributes |= EFI_PCI_IO_ATTRIBUTE_MEMORY; + } + + if (Command & EFI_PCI_COMMAND_BUS_MASTER) { + Attributes |= EFI_PCI_IO_ATTRIBUTE_BUS_MASTER; + } + + if (Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) { + Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO; + } + + if (BridgeControl & EFI_PCI_BRIDGE_CONTROL_ISA) { + Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_IO; + } + + if (BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA) { + Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO; + Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY; + Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO; + } + + if (Option == EFI_SET_SUPPORTS) { + + Attributes |= 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 (Attributes & EFI_PCI_IO_ATTRIBUTE_IO) { + Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO; + Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_IO; + } + + 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; + } 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 |= EFI_PCI_IO_ATTRIBUTE_VGA_IO; + } + } + + 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 { + PciIoDevice->Attributes = Attributes; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +GetFastBackToBackSupport ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINT8 StatusIndex + ) +/*++ + +Routine Description: + + Determine if the device can support Fast Back to Back attribute + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciIoDevice - add argument and description to function comment +// TODO: StatusIndex - add argument and description to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +{ + 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) { + return EFI_SUCCESS; + } else { + return EFI_UNSUPPORTED; + } + +} + +EFI_STATUS +ProcessOptionRomLight ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + 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. + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciIoDevice - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + PCI_IO_DEVICE *Temp; + LIST_ENTRY *CurrentLink; + + // + // For RootBridge, PPB , P2C, go recursively to traverse all its children + // + CurrentLink = PciIoDevice->ChildList.ForwardLink; + while (CurrentLink && CurrentLink != &PciIoDevice->ChildList) { + + Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + + if (!IsListEmpty (&Temp->ChildList)) { + ProcessOptionRomLight (Temp); + } + + PciRomGetImageMapping (Temp); + CurrentLink = CurrentLink->ForwardLink; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +DetermineDeviceAttribute ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + Determine the related attributes of all devices under a Root Bridge + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciIoDevice - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + UINT16 Command; + UINT16 BridgeControl; + UINT16 OldCommand; + UINT16 OldBridgeControl; + BOOLEAN FastB2BSupport; + + /* + UINT8 IdePI; + EFI_PCI_IO_PROTOCOL *PciIo; + */ + PCI_IO_DEVICE *Temp; + LIST_ENTRY *CurrentLink; + EFI_STATUS Status; + + // + // For Root Bridge, just copy it by RootBridgeIo proctocol + // so as to keep consistent with the actual attribute + // + if (!PciIoDevice->Parent) { + Status = PciIoDevice->PciRootBridgeIo->GetAttributes ( + PciIoDevice->PciRootBridgeIo, + &PciIoDevice->Supports, + &PciIoDevice->Attributes + ); + if (EFI_ERROR (Status)) { + return Status; + } + } 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; + + // + // 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 supported attributes but not defined in PCI_IO_PROTOCOL + // + PciEnableCommandRegister (PciIoDevice, EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE); + + // + // Enable IDE native mode + // + /* + if (IS_PCI_IDE(&PciIoDevice->Pci)) { + + PciIo = &PciIoDevice->PciIo; + + PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint8, + 0x09, + 1, + &IdePI + ); + + // + // Set native mode if it can be supported + // + IdePI |= (((IdePI & 0x0F) >> 1) & 0x05); + + PciIo->Pci.Write ( + PciIo, + EfiPciIoWidthUint8, + 0x09, + 1, + &IdePI + ); + + } + */ + } + + 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 && CurrentLink != &PciIoDevice->ChildList) { + + Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + Status = DetermineDeviceAttribute (Temp); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Detect Fast Bact to Bact 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; + PciDisableBridgeControlRegister (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK); + } else { + PciEnableBridgeControlRegister (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK); + } + } + + CurrentLink = PciIoDevice->ChildList.ForwardLink; + while (CurrentLink && CurrentLink != &PciIoDevice->ChildList) { + Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + if (FastB2BSupport) { + PciEnableCommandRegister (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK); + } else { + PciDisableCommandRegister (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK); + } + + CurrentLink = CurrentLink->ForwardLink; + } + } + // + // End for IsListEmpty + // + return EFI_SUCCESS; +} + +EFI_STATUS +UpdatePciInfo ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + This routine is used to update the bar information for those incompatible PCI device + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciIoDevice - add argument and description to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +{ + EFI_STATUS Status; + UINTN BarIndex; + UINTN BarEndIndex; + BOOLEAN SetFlag; + VOID *Configuration; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr; + + Configuration = NULL; + + // + // It can only be supported after the Incompatible PCI Device + // Support Protocol has been installed + // + if (gEfiIncompatiblePciDeviceSupport == NULL) { + + Status = gBS->LocateProtocol ( + &gEfiIncompatiblePciDeviceSupportProtocolGuid, + NULL, + (VOID **) &gEfiIncompatiblePciDeviceSupport + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + } + + // + // Check whether the device belongs to incompatible devices or not + // If it is , then get its special requirement in the ACPI table + // + Status = gEfiIncompatiblePciDeviceSupport->CheckDevice ( + gEfiIncompatiblePciDeviceSupport, + 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)) { + return Status; + } + + // + // 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; + } + + BarIndex = (UINTN) Ptr->AddrTranslationOffset; + BarEndIndex = BarIndex; + + // + // Update all the bars in the device + // + if (BarIndex == PCI_BAR_ALL) { + BarIndex = 0; + BarEndIndex = PCI_MAX_BAR - 1; + } + + if (BarIndex >= PCI_MAX_BAR) { + Ptr++; + continue; + } + + for (; BarIndex <= BarEndIndex; BarIndex++) { + 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; + } + 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 != PCI_BAR_NOCHANGE) { + PciIoDevice->PciBar[BarIndex].Length = Ptr->AddrLen; + } + } + } + + Ptr++; + } + + gBS->FreePool (Configuration); + return Status; + +} + +VOID +SetNewAlign ( + IN UINT64 *Alignment, + IN UINT64 NewAlignment + ) +/*++ + +Routine Description: + + This routine will update the alignment with the new alignment + +Arguments: + +Returns: + + None + +--*/ +// TODO: Alignment - add argument and description to function comment +// TODO: NewAlignment - add argument and description to function comment +{ + UINT64 OldAlignment; + UINTN ShiftBit; + + // + // The new alignment is the same as the original, + // so skip it + // + if (NewAlignment == PCI_BAR_OLD_ALIGN) { + return ; + } + // + // Check the validity of the parameter + // + if (NewAlignment != PCI_BAR_EVEN_ALIGN && + NewAlignment != PCI_BAR_SQUAD_ALIGN && + NewAlignment != PCI_BAR_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 == PCI_BAR_EVEN_ALIGN) { + if (OldAlignment & 0x01) { + OldAlignment = OldAlignment + 2 - (OldAlignment & 0x01); + } + } else if (NewAlignment == PCI_BAR_SQUAD_ALIGN) { + if (OldAlignment & 0x03) { + OldAlignment = OldAlignment + 4 - (OldAlignment & 0x03); + } + } else if (NewAlignment == PCI_BAR_DQUAD_ALIGN) { + if (OldAlignment & 0x07) { + OldAlignment = OldAlignment + 8 - (OldAlignment & 0x07); + } + } + + // + // Update the old value + // + NewAlignment = LShiftU64 (OldAlignment, ShiftBit) - 1; + *Alignment = NewAlignment; + + return ; +} + +UINTN +PciParseBar ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINTN Offset, + IN UINTN BarIndex + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciIoDevice - add argument and description to function comment +// TODO: Offset - add argument and description to function comment +// TODO: BarIndex - add argument and description to function comment +{ + UINT32 Value; + UINT64 BarValue64; + UINT32 OriginalValue; + UINT32 Mask; + UINT32 Data; + UINT8 Index; + EFI_STATUS Status; + + OriginalValue = 0; + Value = 0; + BarValue64 = 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].Offset = (UINT8) Offset; + if (Value & 0x01) { + // + // Device I/Os + // + Mask = 0xfffffffc; + + if (Value & 0xFFFF0000) { + // + // 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 inplement IO bar with 0 length + // Need to treat it as no-bar + // + if (PciIoDevice->PciBar[BarIndex].Length == 0) { + PciIoDevice->PciBar[BarIndex].BarType = 0; + } + + PciIoDevice->PciBar[BarIndex].Prefetchable = FALSE; + 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) { + PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32; + } else { + PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32; + } + + PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1; + PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1; + + break; + + // + // memory space; anywhere in 64 bit address space + // + case 0x04: + if (Value & 0x08) { + 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)) { + return Offset + 4; + } + + // + // Fix the length to support some spefic 64 bit BAR + // + Data = Value; + Index = 0; + for (Data = Value; Data != 0; Data >>= 1) { + Index ++; + } + Value |= ((UINT32)(-1) << Index); + + // + // 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; + PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1; + + break; + + // + // reserved + // + default: + PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown; + PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1; + 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; +} + +EFI_STATUS +InitializePciDevice ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + This routine is used to initialize the bar of a PCI device + It can be called typically when a device is going to be rejected + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciIoDevice - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + 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 alloacted + // + for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) { + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllOne); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +InitializePpb ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciIoDevice - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + 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); + + return EFI_SUCCESS; +} + +EFI_STATUS +InitializeP2C ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciIoDevice - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + 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); + return EFI_SUCCESS; +} + +PCI_IO_DEVICE * +CreatePciIoDevice ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, + IN PCI_TYPE00 *Pci, + UINT8 Bus, + UINT8 Device, + UINT8 Func + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciRootBridgeIo - add argument and description to function comment +// TODO: Pci - add argument and description to function comment +// TODO: Bus - add argument and description to function comment +// TODO: Device - add argument and description to function comment +// TODO: Func - add argument and description to function comment +{ + + EFI_STATUS Status; + PCI_IO_DEVICE *PciIoDevice; + + PciIoDevice = NULL; + + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (PCI_IO_DEVICE), + (VOID **) &PciIoDevice + ); + + if (EFI_ERROR (Status)) { + return NULL; + } + + ZeroMem (PciIoDevice, sizeof (PCI_IO_DEVICE)); + + PciIoDevice->Signature = PCI_IO_DEVICE_SIGNATURE; + PciIoDevice->Handle = NULL; + PciIoDevice->PciRootBridgeIo = 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 + // + + Status = InitializePciIoInstance (PciIoDevice); + Status = InitializePciDriverOverrideInstance (PciIoDevice); + + if (EFI_ERROR (Status)) { + gBS->FreePool (PciIoDevice); + return NULL; + } + + // + // Initialize the reserved resource list + // + InitializeListHead (&PciIoDevice->ReservedResourceList); + + // + // Initialize the driver list + // + InitializeListHead (&PciIoDevice->OptionRomDriverList); + + // + // Initialize the child list + // + InitializeListHead (&PciIoDevice->ChildList); + + return PciIoDevice; +} + +EFI_STATUS +PciEnumeratorLight ( + IN EFI_HANDLE Controller + ) +/*++ + +Routine Description: + + This routine is used to enumerate entire pci bus system + in a given platform + +Arguments: + +Returns: + + None + +--*/ +// TODO: Controller - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + + 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 host bridge has been already enumerated, then return successfully + // + if (RootBridgeExisted (Controller)) { + 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) { + 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 unsuccessly, destroy the entire node + // + DestroyRootBridge (RootBridgeDev); + } + + Descriptors++; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +PciGetBusRange ( + IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors, + OUT UINT16 *MinBus, + OUT UINT16 *MaxBus, + OUT UINT16 *BusRange + ) +/*++ + +Routine Description: + + Get the bus range. + +Arguments: + + Descriptors - A pointer to the address space descriptor. + MinBus - The min bus. + MaxBus - The max bus. + BusRange - The bus range. + +Returns: + + Status Code. + +--*/ +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +{ + + 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; +} + +EFI_STATUS +StartManagingRootBridge ( + IN PCI_IO_DEVICE *RootBridgeDev + ) +/*++ + +Routine Description: + + +Arguments: + +Returns: + + None + +--*/ +// TODO: RootBridgeDev - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + 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; + +} + +BOOLEAN +IsPciDeviceRejected ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + This routine can be used to check whether a PCI device should be rejected when light enumeration + +Arguments: + +Returns: + + TRUE This device should be rejected + FALSE This device shouldn't be rejected + +--*/ +// TODO: PciIoDevice - add argument and description to function comment +{ + 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) { + + // + // 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; +} + +EFI_STATUS +ResetAllPpbBusReg ( + IN PCI_IO_DEVICE *Bridge, + IN UINT8 StartBusNumber + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Bridge - TODO: add argument description + StartBusNumber - TODO: add argument description + +Returns: + + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + EFI_STATUS Status; + PCI_TYPE00 Pci; + UINT8 Device; + UINT32 Register; + UINT8 Func; + UINT64 Address; + 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) && (IS_PCI_BRIDGE (&Pci))) { + Register = 0; + Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18); + Status = PciRootBridgeIo->Pci.Read ( + PciRootBridgeIo, + EfiPciWidthUint32, + Address, + 1, + &Register + ); + // + // 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; + } + } + } + + return EFI_SUCCESS; +} + diff --git a/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciEnumeratorSupport.h b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciEnumeratorSupport.h new file mode 100644 index 0000000000..41d6efb102 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciEnumeratorSupport.h @@ -0,0 +1,598 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PciEnumeratorSupport.h + +Abstract: + + PCI Bus Driver + +Revision History + +--*/ + +#ifndef _EFI_PCI_ENUMERATOR_SUPPORT_H +#define _EFI_PCI_ENUMERATOR_SUPPORT_H + +EFI_STATUS +PciDevicePresent ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, + PCI_TYPE00 *Pci, + UINT8 Bus, + UINT8 Device, + UINT8 Func + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciRootBridgeIo - TODO: add argument description + Pci - TODO: add argument description + Bus - TODO: add argument description + Device - TODO: add argument description + Func - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +PciPciDeviceInfoCollector ( + IN PCI_IO_DEVICE *Bridge, + UINT8 StartBusNumber + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Bridge - TODO: add argument description + StartBusNumber - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +PciSearchDevice ( + IN PCI_IO_DEVICE *Bridge, + PCI_TYPE00 *Pci, + UINT8 Bus, + UINT8 Device, + UINT8 Func, + PCI_IO_DEVICE **PciDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Bridge - TODO: add argument description + Pci - TODO: add argument description + Bus - TODO: add argument description + Device - TODO: add argument description + Func - TODO: add argument description + PciDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +PCI_IO_DEVICE * +GatherDeviceInfo ( + IN PCI_IO_DEVICE *Bridge, + IN PCI_TYPE00 *Pci, + UINT8 Bus, + UINT8 Device, + UINT8 Func + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Bridge - TODO: add argument description + Pci - TODO: add argument description + Bus - TODO: add argument description + Device - TODO: add argument description + Func - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +PCI_IO_DEVICE * +GatherPpbInfo ( + IN PCI_IO_DEVICE *Bridge, + IN PCI_TYPE00 *Pci, + UINT8 Bus, + UINT8 Device, + UINT8 Func + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Bridge - TODO: add argument description + Pci - TODO: add argument description + Bus - TODO: add argument description + Device - TODO: add argument description + Func - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +PCI_IO_DEVICE * +GatherP2CInfo ( + IN PCI_IO_DEVICE *Bridge, + IN PCI_TYPE00 *Pci, + UINT8 Bus, + UINT8 Device, + UINT8 Func + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Bridge - TODO: add argument description + Pci - TODO: add argument description + Bus - TODO: add argument description + Device - TODO: add argument description + Func - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_DEVICE_PATH_PROTOCOL * +CreatePciDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath, + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ParentDevicePath - TODO: add argument description + PciIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +BarExisted ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINTN Offset, + OUT UINT32 *BarLengthValue, + OUT UINT32 *OriginalBarValue + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + Offset - TODO: add argument description + BarLengthValue - TODO: add argument description + OriginalBarValue - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +PciTestSupportedAttribute ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINT16 *Command, + IN UINT16 *BridgeControl, + IN UINT16 *OldCommand, + IN UINT16 *OldBridgeControl + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + Command - TODO: add argument description + BridgeControl - TODO: add argument description + OldCommand - TODO: add argument description + OldBridgeControl - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +PciSetDeviceAttribute ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINT16 Command, + IN UINT16 BridgeControl, + IN UINTN Option + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + Command - TODO: add argument description + BridgeControl - TODO: add argument description + Option - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +GetFastBackToBackSupport ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINT8 StatusIndex + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + StatusIndex - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +DetermineDeviceAttribute ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +UpdatePciInfo ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +VOID +SetNewAlign ( + IN UINT64 *Alignment, + IN UINT64 NewAlignment + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Alignment - TODO: add argument description + NewAlignment - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +UINTN +PciParseBar ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINTN Offset, + IN UINTN BarIndex + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + Offset - TODO: add argument description + BarIndex - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +InitializePciDevice ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +InitializePpb ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +InitializeP2C ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +PCI_IO_DEVICE * +CreatePciIoDevice ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, + IN PCI_TYPE00 *Pci, + UINT8 Bus, + UINT8 Device, + UINT8 Func + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciRootBridgeIo - TODO: add argument description + Pci - TODO: add argument description + Bus - TODO: add argument description + Device - TODO: add argument description + Func - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +PciEnumeratorLight ( + IN EFI_HANDLE Controller + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Controller - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +PciGetBusRange ( + IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors, + OUT UINT16 *MinBus, + OUT UINT16 *MaxBus, + OUT UINT16 *BusRange + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Descriptors - TODO: add argument description + MinBus - TODO: add argument description + MaxBus - TODO: add argument description + BusRange - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +StartManagingRootBridge ( + IN PCI_IO_DEVICE *RootBridgeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + RootBridgeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +IsPciDeviceRejected ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciHotPlugSupport.c b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciHotPlugSupport.c new file mode 100644 index 0000000000..4ebf9a7afc --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciHotPlugSupport.c @@ -0,0 +1,462 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PciHotPlugSupport.c + +Abstract: + + + +Revision History + +--*/ + +#include "Pcibus.h" +#include "PciHotPlugSupport.h" + +EFI_PCI_HOT_PLUG_INIT_PROTOCOL *gPciHotPlugInit; +EFI_HPC_LOCATION *gPciRootHpcPool; +UINTN gPciRootHpcCount; +ROOT_HPC_DATA *gPciRootHpcData; + +VOID +EFIAPI +PciHPCInitialized ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: Event - add argument and description to function comment +// TODO: Context - add argument and description to function comment +{ + ROOT_HPC_DATA *HpcData; + + HpcData = (ROOT_HPC_DATA *) Context; + HpcData->Initialized = TRUE; + +} + +BOOLEAN +EfiCompareDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath1, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath2 + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: DevicePath1 - add argument and description to function comment +// TODO: DevicePath2 - add argument and description to function comment +{ + UINTN Size1; + UINTN Size2; + + Size1 = GetDevicePathSize (DevicePath1); + Size2 = GetDevicePathSize (DevicePath2); + + if (Size1 != Size2) { + return FALSE; + } + + if (CompareMem (DevicePath1, DevicePath2, Size1)) { + return FALSE; + } + + return TRUE; +} + +EFI_STATUS +InitializeHotPlugSupport ( + VOID + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + 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 + // + gPciHotPlugInit = NULL; + gPciRootHpcPool = NULL; + gPciRootHpcCount = 0; + gPciRootHpcData = NULL; + + 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; +} + +BOOLEAN +IsRootPciHotPlugBus ( + IN EFI_DEVICE_PATH_PROTOCOL *HpbDevicePath, + OUT UINTN *HpIndex + ) +/*++ + +Routine Description: + +Arguments: + + HpcDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCOL. + HpIndex - A pointer to the Index. + +Returns: + + None + +--*/ +// TODO: HpbDevicePath - add argument and description to function comment +{ + UINTN Index; + + for (Index = 0; Index < gPciRootHpcCount; Index++) { + + if (EfiCompareDevicePath (gPciRootHpcPool[Index].HpbDevicePath, HpbDevicePath)) { + + if (HpIndex != NULL) { + *HpIndex = Index; + } + + return TRUE; + } + } + + return FALSE; +} + +BOOLEAN +IsRootPciHotPlugController ( + IN EFI_DEVICE_PATH_PROTOCOL *HpcDevicePath, + OUT UINTN *HpIndex + ) +/*++ + +Routine Description: + +Arguments: + + HpcDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCOL. + HpIndex - A pointer to the Index. + +Returns: + + None + +--*/ +{ + UINTN Index; + + for (Index = 0; Index < gPciRootHpcCount; Index++) { + + if (EfiCompareDevicePath (gPciRootHpcPool[Index].HpcDevicePath, HpcDevicePath)) { + + if (HpIndex != NULL) { + *HpIndex = Index; + } + + return TRUE; + } + } + + return FALSE; +} + +EFI_STATUS +CreateEventForHpc ( + IN UINTN HpIndex, + OUT EFI_EVENT *Event + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: HpIndex - add argument and description to function comment +// TODO: Event - add argument and description to function comment +{ + EFI_STATUS Status; + + Status = gBS->CreateEvent ( + EFI_EVENT_NOTIFY_SIGNAL, + EFI_TPL_CALLBACK, + PciHPCInitialized, + gPciRootHpcData + HpIndex, + &((gPciRootHpcData + HpIndex)->Event) + ); + + if (!EFI_ERROR (Status)) { + *Event = (gPciRootHpcData + HpIndex)->Event; + } + + return Status; +} + +EFI_STATUS +AllRootHPCInitialized ( + IN UINTN TimeoutInMilliSeconds + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: TimeoutInMilliSeconds - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_TIMEOUT - add return value to function comment +{ + UINT32 Delay; + UINTN Index; + + Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1); + do { + + for (Index = 0; Index < gPciRootHpcCount; Index++) { + + if (!gPciRootHpcData[Index].Initialized) { + break; + } + } + + if (Index == gPciRootHpcCount) { + return EFI_SUCCESS; + } + + // + // Stall for 30 us + // + gBS->Stall (30); + + Delay--; + + } while (Delay); + + return EFI_TIMEOUT; +} + +EFI_STATUS +IsSHPC ( + PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciIoDevice - add argument and description to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +{ + + EFI_STATUS Status; + UINT8 Offset; + + if (!PciIoDevice) { + return EFI_NOT_FOUND; + } + + Offset = 0; + Status = LocateCapabilityRegBlock ( + PciIoDevice, + EFI_PCI_CAPABILITY_ID_HOTPLUG, + &Offset, + NULL + ); + + // + // If the PPB has the hot plug controller build-in, + // then return TRUE; + // + if (!EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + + return EFI_NOT_FOUND; +} + +EFI_STATUS +GetResourcePaddingForHpb ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciIoDevice - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +{ + EFI_STATUS Status; + EFI_HPC_STATE State; + UINT64 PciAddress; + EFI_HPC_PADDING_ATTRIBUTES Attributes; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors; + + Status = IsPciHotPlugBus (PciIoDevice); + + if (!EFI_ERROR (Status)) { + 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 Status; + } + + if ((State & EFI_HPC_STATE_ENABLED) && (State & EFI_HPC_STATE_INITIALIZED)) { + PciIoDevice->ResourcePaddingDescriptors = Descriptors; + PciIoDevice->PaddingAttributes = Attributes; + } + + return EFI_SUCCESS; + } + + return EFI_NOT_FOUND; +} + +EFI_STATUS +IsPciHotPlugBus ( + PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciIoDevice - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +{ + BOOLEAN Result; + EFI_STATUS Status; + + Status = IsSHPC (PciIoDevice); + + // + // If the PPB has the hot plug controller build-in, + // then return TRUE; + // + if (!EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + + // + // Otherwise, see if it is a Root HPC + // + Result = IsRootPciHotPlugBus (PciIoDevice->DevicePath, NULL); + + if (Result) { + return EFI_SUCCESS; + } + + return EFI_NOT_FOUND; +} diff --git a/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciHotPlugSupport.h b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciHotPlugSupport.h new file mode 100644 index 0000000000..df49ebaf56 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciHotPlugSupport.h @@ -0,0 +1,269 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PciHotPlugSupport.h + +Abstract: + + + +Revision History + +--*/ + +#ifndef _EFI_PCI_HOT_PLUG_SUPPORT_H +#define _EFI_PCI_HOT_PLUG_SUPPORT_H + +// +// stall 1 ms +// +#define STALL_1_MILLI_SECOND 1000 + +// +// stall 1 second +// +#define STALL_1_SECOND 1000000 + +typedef struct { + EFI_EVENT Event; + BOOLEAN Initialized; + VOID *Padding; +} ROOT_HPC_DATA; + +extern EFI_PCI_HOT_PLUG_INIT_PROTOCOL *gPciHotPlugInit; +extern EFI_HPC_LOCATION *gPciRootHpcPool; +extern UINTN gPciRootHpcCount; +extern ROOT_HPC_DATA *gPciRootHpcData; + +VOID +EFIAPI +PciHPCInitialized ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Event - TODO: add argument description + Context - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +EfiCompareDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath1, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath2 + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + DevicePath1 - TODO: add argument description + DevicePath2 - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +InitializeHotPlugSupport ( + VOID + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + None + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +IsPciHotPlugBus ( + PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +IsRootPciHotPlugBus ( + IN EFI_DEVICE_PATH_PROTOCOL *HpbDevicePath, + OUT UINTN *HpIndex + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + HpbDevicePath - TODO: add argument description + HpIndex - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +IsRootPciHotPlugController ( + IN EFI_DEVICE_PATH_PROTOCOL *HpcDevicePath, + OUT UINTN *HpIndex + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + HpcDevicePath - TODO: add argument description + HpIndex - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +CreateEventForHpc ( + IN UINTN HpIndex, + OUT EFI_EVENT *Event + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + HpIndex - TODO: add argument description + Event - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AllRootHPCInitialized ( + IN UINTN TimeoutInMilliSeconds + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + TimeoutInMilliSeconds - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +IsSHPC ( + PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +GetResourcePaddingForHpb ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciIo.c b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciIo.c new file mode 100644 index 0000000000..4f1737f5af --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciIo.c @@ -0,0 +1,1964 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PciIo.c + +Abstract: + + PCI I/O Abstraction Driver + +Revision History + +--*/ + +#include "Pcibus.h" + +// +// Internal use only +// +STATIC +EFI_STATUS +ReportErrorStatusCode ( + IN PCI_IO_DEVICE *PciIoDevice, + IN EFI_STATUS_CODE_VALUE Code + ); + +// +// PCI I/O Support Function Prototypes +// +// +// +// Pci Io Protocol Interface +// +static EFI_PCI_IO_PROTOCOL PciIoInterface = { + PciIoPollMem, + PciIoPollIo, + { + PciIoMemRead, + PciIoMemWrite + }, + { + PciIoIoRead, + PciIoIoWrite + }, + { + PciIoConfigRead, + PciIoConfigWrite + }, + PciIoCopyMem, + PciIoMap, + PciIoUnmap, + PciIoAllocateBuffer, + PciIoFreeBuffer, + PciIoFlush, + PciIoGetLocation, + PciIoAttributes, + PciIoGetBarAttributes, + PciIoSetBarAttributes, + 0, + NULL +}; + +STATIC +EFI_STATUS +ReportErrorStatusCode ( + IN PCI_IO_DEVICE *PciIoDevice, + IN EFI_STATUS_CODE_VALUE Code + ) +/*++ + +Routine Description: + + report a error Status code of PCI bus driver controller + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciIoDevice - add argument and description to function comment +// TODO: Code - add argument and description to function comment +{ + return REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + Code, + PciIoDevice->DevicePath + ); +} + +EFI_STATUS +InitializePciIoInstance ( + PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + Initializes a PCI I/O Instance + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciIoDevice - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + CopyMem (&PciIoDevice->PciIo, &PciIoInterface, sizeof (EFI_PCI_IO_PROTOCOL)); + return EFI_SUCCESS; +} + +EFI_STATUS +PciIoVerifyBarAccess ( + PCI_IO_DEVICE *PciIoDevice, + UINT8 BarIndex, + PCI_BAR_TYPE Type, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINTN Count, + UINT64 *Offset + ) +/*++ + +Routine Description: + + Verifies access to a PCI Base Address Register (BAR) + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciIoDevice - add argument and description to function comment +// TODO: BarIndex - add argument and description to function comment +// TODO: Type - add argument and description to function comment +// TODO: Width - add argument and description to function comment +// TODO: Count - add argument and description to function comment +// TODO: Offset - add argument and description to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + if (Width < 0 || 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 >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) { + Count = 1; + } + + 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; +} + +EFI_STATUS +PciIoVerifyConfigAccess ( + PCI_IO_DEVICE *PciIoDevice, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINTN Count, + IN UINT64 *Offset + ) +/*++ + +Routine Description: + + Verifies access to a PCI Config Header + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciIoDevice - add argument and description to function comment +// TODO: Width - add argument and description to function comment +// TODO: Count - add argument and description to function comment +// TODO: Offset - add argument and description to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + UINT64 ExtendOffset; + + if (Width < 0 || Width >= EfiPciIoWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + // + // If Width is EfiPciIoWidthFillUintX then convert to EfiPciIoWidthUintX + // + 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; +} + +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 + ) +/*++ + +Routine Description: + + Poll PCI Memmory + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Width - add argument and description to function comment +// TODO: BarIndex - add argument and description to function comment +// TODO: Offset - add argument and description to function comment +// TODO: Mask - add argument and description to function comment +// TODO: Value - add argument and description to function comment +// TODO: Delay - add argument and description to function comment +// TODO: Result - add argument and description to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +{ + EFI_STATUS Status; + PCI_IO_DEVICE *PciIoDevice; + + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This); + + if (Width < 0 || 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; + } + + Status = PciIoDevice->PciRootBridgeIo->PollMem ( + PciIoDevice->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Offset, + Mask, + Value, + Delay, + Result + ); + + if (EFI_ERROR (Status)) { + ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR); + } + + return Status; +} + +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 + ) +/*++ + +Routine Description: + + Poll PCI IO + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Width - add argument and description to function comment +// TODO: BarIndex - add argument and description to function comment +// TODO: Offset - add argument and description to function comment +// TODO: Mask - add argument and description to function comment +// TODO: Value - add argument and description to function comment +// TODO: Delay - add argument and description to function comment +// TODO: Result - add argument and description to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +{ + EFI_STATUS Status; + PCI_IO_DEVICE *PciIoDevice; + + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This); + + if (Width < 0 || Width >= EfiPciIoWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width, 1, &Offset); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + if (Width > EfiPciIoWidthUint64) { + return EFI_INVALID_PARAMETER; + } + + Status = PciIoDevice->PciRootBridgeIo->PollIo ( + PciIoDevice->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Offset, + Mask, + Value, + Delay, + Result + ); + + if (EFI_ERROR (Status)) { + ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR); + } + + return Status; +} + +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 + ) +/*++ + +Routine Description: + + Performs a PCI Memory Read Cycle + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Width - add argument and description to function comment +// TODO: BarIndex - add argument and description to function comment +// TODO: Offset - add argument and description to function comment +// TODO: Count - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +{ + EFI_STATUS Status; + PCI_IO_DEVICE *PciIoDevice; + + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This); + + if (Width < 0 || Width >= EfiPciIoWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeMem, Width, Count, &Offset); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Status = PciIoDevice->PciRootBridgeIo->Mem.Read ( + PciIoDevice->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Offset, + Count, + Buffer + ); + + if (EFI_ERROR (Status)) { + ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_READ_ERROR); + } + + return Status; +} + +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 + ) +/*++ + +Routine Description: + + Performs a PCI Memory Write Cycle + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Width - add argument and description to function comment +// TODO: BarIndex - add argument and description to function comment +// TODO: Offset - add argument and description to function comment +// TODO: Count - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +{ + EFI_STATUS Status; + PCI_IO_DEVICE *PciIoDevice; + + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This); + + if (Width < 0 || Width >= EfiPciIoWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeMem, Width, Count, &Offset); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Status = PciIoDevice->PciRootBridgeIo->Mem.Write ( + PciIoDevice->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Offset, + Count, + Buffer + ); + + if (EFI_ERROR (Status)) { + ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_WRITE_ERROR); + } + + return Status; +} + +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 + ) +/*++ + +Routine Description: + + Performs a PCI I/O Read Cycle + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Width - add argument and description to function comment +// TODO: BarIndex - add argument and description to function comment +// TODO: Offset - add argument and description to function comment +// TODO: Count - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +{ + EFI_STATUS Status; + PCI_IO_DEVICE *PciIoDevice; + + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This); + + if (Width < 0 || Width >= EfiPciIoWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width, Count, &Offset); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Status = PciIoDevice->PciRootBridgeIo->Io.Read ( + PciIoDevice->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Offset, + Count, + Buffer + ); + + if (EFI_ERROR (Status)) { + ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_READ_ERROR); + } + + return Status; +} + +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 + ) +/*++ + +Routine Description: + + Performs a PCI I/O Write Cycle + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Width - add argument and description to function comment +// TODO: BarIndex - add argument and description to function comment +// TODO: Offset - add argument and description to function comment +// TODO: Count - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +{ + EFI_STATUS Status; + PCI_IO_DEVICE *PciIoDevice; + + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This); + + if (Width < 0 || Width >= EfiPciIoWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width, Count, &Offset); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Status = PciIoDevice->PciRootBridgeIo->Io.Write ( + PciIoDevice->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Offset, + Count, + Buffer + ); + + if (EFI_ERROR (Status)) { + ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_WRITE_ERROR); + } + + return Status; +} + +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 + ) +/*++ + +Routine Description: + + Performs a PCI Configuration Read Cycle + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Width - add argument and description to function comment +// TODO: Offset - add argument and description to function comment +// TODO: Count - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +{ + 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; + } + + Status = PciIoDevice->PciRootBridgeIo->Pci.Read ( + PciIoDevice->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Address, + Count, + Buffer + ); + + if (EFI_ERROR (Status)) { + ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_READ_ERROR); + } + + return Status; +} + +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 + ) +/*++ + +Routine Description: + + Performs a PCI Configuration Write Cycle + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Width - add argument and description to function comment +// TODO: Offset - add argument and description to function comment +// TODO: Count - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +{ + 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; + } + + Status = PciIoDevice->PciRootBridgeIo->Pci.Write ( + PciIoDevice->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Address, + Count, + Buffer + ); + + if (EFI_ERROR (Status)) { + ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_WRITE_ERROR); + } + + return Status; +} + +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 + ) +/*++ + +Routine Description: + + Copy PCI Memory + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Width - add argument and description to function comment +// TODO: DestBarIndex - add argument and description to function comment +// TODO: DestOffset - add argument and description to function comment +// TODO: SrcBarIndex - add argument and description to function comment +// TODO: SrcOffset - add argument and description to function comment +// TODO: Count - add argument and description to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +{ + EFI_STATUS Status; + PCI_IO_DEVICE *PciIoDevice; + + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This); + + if (Width < 0 || 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; + } + + Status = PciIoDevice->PciRootBridgeIo->CopyMem ( + PciIoDevice->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + DestOffset, + SrcOffset, + Count + ); + + if (EFI_ERROR (Status)) { + ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR); + } + + return Status; +} + +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 + ) +/*++ + +Routine Description: + + Maps a memory region for DMA + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Operation - add argument and description to function comment +// TODO: HostAddress - add argument and description to function comment +// TODO: NumberOfBytes - add argument and description to function comment +// TODO: DeviceAddress - add argument and description to function comment +// TODO: Mapping - add argument and description to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +{ + EFI_STATUS Status; + PCI_IO_DEVICE *PciIoDevice; + + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This); + + if (Operation < 0 || Operation >= EfiPciIoOperationMaximum) { + return EFI_INVALID_PARAMETER; + } + + if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL || Mapping == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) { + Operation = Operation + EfiPciOperationBusMasterRead64; + } + + Status = PciIoDevice->PciRootBridgeIo->Map ( + PciIoDevice->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION) Operation, + HostAddress, + NumberOfBytes, + DeviceAddress, + Mapping + ); + + if (EFI_ERROR (Status)) { + ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR); + } + + return Status; +} + +EFI_STATUS +EFIAPI +PciIoUnmap ( + IN EFI_PCI_IO_PROTOCOL *This, + IN VOID *Mapping + ) +/*++ + +Routine Description: + + Unmaps a memory region for DMA + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Mapping - add argument and description to function comment +{ + EFI_STATUS Status; + PCI_IO_DEVICE *PciIoDevice; + + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This); + + Status = PciIoDevice->PciRootBridgeIo->Unmap ( + PciIoDevice->PciRootBridgeIo, + Mapping + ); + + if (EFI_ERROR (Status)) { + ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR); + } + + return Status; +} + +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 + ) +/*++ + +Routine Description: + + Allocates a common buffer for DMA + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Type - add argument and description to function comment +// TODO: MemoryType - add argument and description to function comment +// TODO: Pages - add argument and description to function comment +// TODO: HostAddress - add argument and description to function comment +// TODO: Attributes - add argument and description to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +{ + EFI_STATUS Status; + PCI_IO_DEVICE *PciIoDevice; + + if (Attributes & + (~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_PCI_ATTRIBUTE_MEMORY_CACHED))) { + return EFI_UNSUPPORTED; + } + + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This); + + if (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) { + Attributes |= EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE; + } + + Status = PciIoDevice->PciRootBridgeIo->AllocateBuffer ( + PciIoDevice->PciRootBridgeIo, + Type, + MemoryType, + Pages, + HostAddress, + Attributes + ); + + if (EFI_ERROR (Status)) { + ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR); + } + + return Status; +} + +EFI_STATUS +EFIAPI +PciIoFreeBuffer ( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINTN Pages, + IN VOID *HostAddress + ) +/*++ + +Routine Description: + + Frees a common buffer + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Pages - add argument and description to function comment +// TODO: HostAddress - add argument and description to function comment +{ + 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)) { + ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR); + } + + return Status; +} + +EFI_STATUS +EFIAPI +PciIoFlush ( + IN EFI_PCI_IO_PROTOCOL *This + ) +/*++ + +Routine Description: + + Flushes a DMA buffer + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +{ + 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)) { + ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR); + } + + return Status; +} + +EFI_STATUS +EFIAPI +PciIoGetLocation ( + IN EFI_PCI_IO_PROTOCOL *This, + OUT UINTN *Segment, + OUT UINTN *Bus, + OUT UINTN *Device, + OUT UINTN *Function + ) +/*++ + +Routine Description: + + Gets a PCI device's current bus number, device number, and function number. + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Segment - add argument and description to function comment +// TODO: Bus - add argument and description to function comment +// TODO: Device - add argument and description to function comment +// TODO: Function - add argument and description to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + 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; +} + +BOOLEAN +CheckBarType ( + IN PCI_IO_DEVICE *PciIoDevice, + UINT8 BarIndex, + PCI_BAR_TYPE BarType + ) +/*++ + +Routine Description: + + Sets a PCI controllers attributes on a resource range + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciIoDevice - add argument and description to function comment +// TODO: BarIndex - add argument and description to function comment +// TODO: BarType - add argument and description to function comment +{ + 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; +} + +EFI_STATUS +ModifyRootBridgeAttributes ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINT64 Attributes, + IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation + ) +/*++ + +Routine Description: + + Set new attributes to a Root Bridge + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciIoDevice - add argument and description to function comment +// TODO: Attributes - add argument and description to function comment +// TODO: Operation - add argument and description to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + 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; + } + + // + // 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) { + + 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; + +} + +EFI_STATUS +SupportPaletteSnoopAttributes ( + IN PCI_IO_DEVICE *PciIoDevice, + IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation + ) +/*++ + +Routine Description: + + Check whether this device can be enable/disable to snoop + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciIoDevice - add argument and description to function comment +// TODO: Operation - add argument and description to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + 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 segement + // + Temp = ActiveVGADeviceOnTheSameSegment (PciIoDevice); + + if (!Temp) { + // + // If there is no VGA device on the segement, 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) { + + PciReadCommandRegister (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) { + // + // 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) { + PciEnableCommandRegister (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) { + PciDisableCommandRegister (Temp, EFI_PCI_COMMAND_VGA_PALETTE_SNOOP); + Temp->Attributes &= (~EFI_PCI_COMMAND_VGA_PALETTE_SNOOP); + } else { + return EFI_UNSUPPORTED; + } + + } + + return EFI_SUCCESS; +} + +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 + ) +/*++ + +Routine Description: + + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Operation - add argument and description to function comment +// TODO: Attributes - add argument and description to function comment +// TODO: Result - add argument and description to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +{ + 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 + // + 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 + ); + } + + // + // 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) { + 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) { + BridgeControl |= EFI_PCI_BRIDGE_CONTROL_VGA; + } + + if (Attributes & EFI_PCI_IO_ATTRIBUTE_ISA_IO) { + BridgeControl |= EFI_PCI_BRIDGE_CONTROL_ISA; + } + + if (Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO) { + Command |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO; + } + + } else { + // + // Do with the attributes on VGA + // + if ((Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_IO) || + (IS_PCI_VGA(&PciIoDevice->Pci) && + ((Attributes & EFI_PCI_IO_ATTRIBUTE_IO) || + (Attributes & EFI_PCI_IO_ATTRIBUTE_MEMORY)))) { + // + // 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 segment + // + Temp = ActiveVGADeviceOnTheSameSegment (PciIoDevice); + if (Temp && 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) { + + 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) { + Command |= EFI_PCI_COMMAND_IO_SPACE; + } + + if (Attributes & EFI_PCI_IO_ATTRIBUTE_MEMORY) { + Command |= EFI_PCI_COMMAND_MEMORY_SPACE; + } + + if (Attributes & EFI_PCI_IO_ATTRIBUTE_BUS_MASTER) { + Command |= EFI_PCI_COMMAND_BUS_MASTER; + } + // + // The upstream bridge should be also set to revelant 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 = PciEnableCommandRegister (PciIoDevice, Command); + if (BridgeControl) { + Status = PciEnableBridgeControlRegister (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 = PciDisableCommandRegister (PciIoDevice, Command); + if (BridgeControl) { + Status = PciDisableBridgeControlRegister (PciIoDevice, BridgeControl); + } + + PciIoDevice->Attributes &= (~Attributes); + Status = EFI_SUCCESS; + + } + + if (EFI_ERROR (Status)) { + ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR); + } + + return Status; +} + +EFI_STATUS +EFIAPI +PciIoGetBarAttributes ( + IN EFI_PCI_IO_PROTOCOL * This, + IN UINT8 BarIndex, + OUT UINT64 *Supports, OPTIONAL + OUT VOID **Resources OPTIONAL + ) +/*++ + +Routine Description: + + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: BarIndex - add argument and description to function comment +// TODO: Supports - add argument and description to function comment +// TODO: Resources - add argument and description to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + + UINT8 *Configuration; + UINT8 NumConfig; + PCI_IO_DEVICE *PciIoDevice; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr; + EFI_ACPI_END_TAG_DESCRIPTOR *PtrEnd; + + NumConfig = 0; + + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This); + + if (Supports == NULL && Resources == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (BarIndex >= PCI_MAX_BAR) { + 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) { + + if (PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeUnknown) { + NumConfig = 1; + } + + Configuration = AllocatePool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) * NumConfig + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)); + if (Configuration == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + ZeroMem ( + Configuration, + sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) * NumConfig + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR) + ); + + Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration; + + if (NumConfig == 1) { + Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; + Ptr->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3; + + Ptr->AddrRangeMin = PciIoDevice->PciBar[BarIndex].BaseAddress; + Ptr->AddrLen = PciIoDevice->PciBar[BarIndex].Length; + Ptr->AddrRangeMax = PciIoDevice->PciBar[BarIndex].Alignment; + + switch (PciIoDevice->PciBar[BarIndex].BarType) { + case PciBarTypeIo16: + case PciBarTypeIo32: + // + // Io + // + Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_IO; + break; + + case PciBarTypeMem32: + // + // Mem + // + Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; + // + // 32 bit + // + Ptr->AddrSpaceGranularity = 32; + break; + + case PciBarTypePMem32: + // + // Mem + // + Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; + // + // prefechable + // + Ptr->SpecificFlag = 0x6; + // + // 32 bit + // + Ptr->AddrSpaceGranularity = 32; + break; + + case PciBarTypeMem64: + // + // Mem + // + Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; + // + // 64 bit + // + Ptr->AddrSpaceGranularity = 64; + break; + + case PciBarTypePMem64: + // + // Mem + // + Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; + // + // prefechable + // + Ptr->SpecificFlag = 0x6; + // + // 64 bit + // + Ptr->AddrSpaceGranularity = 64; + break; + + default: + break; + } + + Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) ((UINT8 *) Ptr + sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR)); + } + + // + // put the checksum + // + PtrEnd = (EFI_ACPI_END_TAG_DESCRIPTOR *) ((UINT8 *) Ptr); + PtrEnd->Desc = ACPI_END_TAG_DESCRIPTOR; + PtrEnd->Checksum = 0; + + *Resources = Configuration; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PciIoSetBarAttributes ( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINT64 Attributes, + IN UINT8 BarIndex, + IN OUT UINT64 *Offset, + IN OUT UINT64 *Length + ) +/*++ + +Routine Description: + + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Attributes - add argument and description to function comment +// TODO: BarIndex - add argument and description to function comment +// TODO: Offset - add argument and description to function comment +// TODO: Length - add argument and description to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + 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 describd 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; +} + +EFI_STATUS +UpStreamBridgesAttributes ( + IN PCI_IO_DEVICE *PciIoDevice, + IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation, + IN UINT64 Attributes + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciIoDevice - add argument and description to function comment +// TODO: Operation - add argument and description to function comment +// TODO: Attributes - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + PCI_IO_DEVICE *Parent; + EFI_PCI_IO_PROTOCOL *PciIo; + + Parent = PciIoDevice->Parent; + + while (Parent && IS_PCI_BRIDGE (&Parent->Pci)) { + + // + // Get the PciIo Protocol + // + PciIo = &Parent->PciIo; + + PciIo->Attributes (PciIo, Operation, Attributes, NULL); + + Parent = Parent->Parent; + } + + return EFI_SUCCESS; +} + +BOOLEAN +PciDevicesOnTheSamePath ( + IN PCI_IO_DEVICE *PciDevice1, + IN PCI_IO_DEVICE *PciDevice2 + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciDevice1 - add argument and description to function comment +// TODO: PciDevice2 - add argument and description to function comment +{ + + if (PciDevice1->Parent == PciDevice2->Parent) { + return TRUE; + } + + if (PciDevice1->BusNumber > PciDevice2->BusNumber) { + return PciDeviceExisted (PciDevice1->Parent, PciDevice2); + } + + return PciDeviceExisted (PciDevice2->Parent, PciDevice1); +} diff --git a/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciIo.h b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciIo.h new file mode 100644 index 0000000000..5733f592e3 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciIo.h @@ -0,0 +1,773 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PciIo.h + +Abstract: + + PCI Bus Driver + +Revision History + +--*/ + +#ifndef _EFI_PCI_IO_PROTOCOL_H +#define _EFI_PCI_IO_PROTOCOL_H + +EFI_STATUS +InitializePciIoInstance ( + PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +PciIoVerifyBarAccess ( + PCI_IO_DEVICE *PciIoDevice, + UINT8 BarIndex, + PCI_BAR_TYPE Type, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINTN Count, + UINT64 *Offset + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + BarIndex - TODO: add argument description + Type - TODO: add argument description + Width - TODO: add argument description + Count - TODO: add argument description + Offset - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +PciIoVerifyConfigAccess ( + PCI_IO_DEVICE *PciIoDevice, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINTN Count, + IN UINT64 *Offset + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + Width - TODO: add argument description + Count - TODO: add argument description + Offset - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +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 + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Width - TODO: add argument description + BarIndex - TODO: add argument description + Offset - TODO: add argument description + Mask - TODO: add argument description + Value - TODO: add argument description + Delay - TODO: add argument description + Result - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +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 + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Width - TODO: add argument description + BarIndex - TODO: add argument description + Offset - TODO: add argument description + Mask - TODO: add argument description + Value - TODO: add argument description + Delay - TODO: add argument description + Result - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +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 + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Width - TODO: add argument description + BarIndex - TODO: add argument description + Offset - TODO: add argument description + Count - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +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 + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Width - TODO: add argument description + BarIndex - TODO: add argument description + Offset - TODO: add argument description + Count - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +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 + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Width - TODO: add argument description + BarIndex - TODO: add argument description + Offset - TODO: add argument description + Count - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +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 + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Width - TODO: add argument description + BarIndex - TODO: add argument description + Offset - TODO: add argument description + Count - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +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 + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Width - TODO: add argument description + Offset - TODO: add argument description + Count - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +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 + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Width - TODO: add argument description + Offset - TODO: add argument description + Count - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +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 + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Width - TODO: add argument description + DestBarIndex - TODO: add argument description + DestOffset - TODO: add argument description + SrcBarIndex - TODO: add argument description + SrcOffset - TODO: add argument description + Count - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +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 + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Operation - TODO: add argument description + HostAddress - TODO: add argument description + NumberOfBytes - TODO: add argument description + DeviceAddress - TODO: add argument description + Mapping - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +PciIoUnmap ( + IN EFI_PCI_IO_PROTOCOL *This, + IN VOID *Mapping + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Mapping - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +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 + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Type - TODO: add argument description + MemoryType - TODO: add argument description + Pages - TODO: add argument description + HostAddress - TODO: add argument description + Attributes - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +PciIoFreeBuffer ( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINTN Pages, + IN VOID *HostAddress + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Pages - TODO: add argument description + HostAddress - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +PciIoFlush ( + IN EFI_PCI_IO_PROTOCOL *This + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +PciIoGetLocation ( + IN EFI_PCI_IO_PROTOCOL *This, + OUT UINTN *Segment, + OUT UINTN *Bus, + OUT UINTN *Device, + OUT UINTN *Function + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Segment - TODO: add argument description + Bus - TODO: add argument description + Device - TODO: add argument description + Function - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +CheckBarType ( + IN PCI_IO_DEVICE *PciIoDevice, + UINT8 BarIndex, + PCI_BAR_TYPE BarType + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + BarIndex - TODO: add argument description + BarType - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +ModifyRootBridgeAttributes ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINT64 Attributes, + IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + Attributes - TODO: add argument description + Operation - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +SupportPaletteSnoopAttributes ( + IN PCI_IO_DEVICE *PciIoDevice, + IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + Operation - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +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 + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Operation - TODO: add argument description + Attributes - TODO: add argument description + Result - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +PciIoGetBarAttributes ( + IN EFI_PCI_IO_PROTOCOL * This, + IN UINT8 BarIndex, + OUT UINT64 *Supports, OPTIONAL + OUT VOID **Resources OPTIONAL + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + BarIndex - TODO: add argument description + Supports - TODO: add argument description + Resources - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +PciIoSetBarAttributes ( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINT64 Attributes, + IN UINT8 BarIndex, + IN OUT UINT64 *Offset, + IN OUT UINT64 *Length + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Attributes - TODO: add argument description + BarIndex - TODO: add argument description + Offset - TODO: add argument description + Length - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +UpStreamBridgesAttributes ( + IN PCI_IO_DEVICE *PciIoDevice, + IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation, + IN UINT64 Attributes + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + Operation - TODO: add argument description + Attributes - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +PciDevicesOnTheSamePath ( + IN PCI_IO_DEVICE *PciDevice1, + IN PCI_IO_DEVICE *PciDevice2 + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciDevice1 - TODO: add argument description + PciDevice2 - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciLib.c b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciLib.c new file mode 100644 index 0000000000..11a0c29210 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciLib.c @@ -0,0 +1,1398 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PciLib.c + +Abstract: + + PCI Bus Driver Lib file + It abstracts some functions that can be different + between light PCI bus driver and full PCI bus driver + +Revision History + +--*/ + +#include "pcibus.h" + +EFI_PCI_HOTPLUG_REQUEST_PROTOCOL gPciHotPlugRequest = { + PciHotPlugRequestNotify +}; + + +VOID +InstallHotPlugRequestProtocol ( + IN EFI_STATUS *Status + ) +/*++ + +Routine Description: + +Arguments: + Status - A pointer to the status. + +Returns: + + None + +--*/ +{ + EFI_HANDLE Handle; + + Handle = NULL; + *Status = gBS->InstallProtocolInterface ( + &Handle, + &gEfiPciHotPlugRequestProtocolGuid, + EFI_NATIVE_INTERFACE, + &gPciHotPlugRequest + ); +} + +VOID +InstallPciHotplugGuid ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + +Arguments: + + PciIoDevice - A pointer to the PCI_IO_DEVICE. + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + + if (IS_CARDBUS_BRIDGE (&PciIoDevice->Parent->Pci)) { + + Status = gBS->InstallProtocolInterface ( + &PciIoDevice->Handle, + &gEfiPciHotplugDeviceGuid, + EFI_NATIVE_INTERFACE, + NULL + ); + } +} + +VOID +UninstallPciHotplugGuid ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + +Arguments: + + PciIoDevice - A pointer to the PCI_IO_DEVICE. + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + + Status = gBS->OpenProtocol ( + PciIoDevice->Handle, + &gEfiPciHotplugDeviceGuid, + NULL, + NULL, + NULL, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + + if (Status == EFI_SUCCESS) { + // + // This may triger CardBus driver to stop for + // Pccard devices opened the GUID via BY_DRIVER + // + Status = gBS->UninstallProtocolInterface ( + PciIoDevice->Handle, + &gEfiPciHotplugDeviceGuid, + NULL + ); + } +} + +VOID +GetBackPcCardBar ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + +Arguments: + + PciIoDevice - A pointer to the PCI_IO_DEVICE. + +Returns: + + None + +--*/ +{ + UINT32 Address; + + // + // Read PciBar information from the bar register + // + if (!gFullEnumeration) { + + Address = 0; + PciIoDevice->PciIo.Pci.Read ( + &(PciIoDevice->PciIo), + EfiPciIoWidthUint32, + 0x1c, + 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, + 0x20, + 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, + 0x2c, + 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, + 0x34, + 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) { + GetResourcePaddingForHpb (PciIoDevice); + } +} + +EFI_STATUS +RemoveRejectedPciDevices ( + EFI_HANDLE RootBridgeHandle, + IN PCI_IO_DEVICE *Bridge + ) +/*++ + +Routine Description: + + +Arguments: + + RootBridgeHandle - An efi handle. + Bridge - An pointer to the PCI_IO_DEVICE. + +Returns: + + None + +--*/ +// TODO: EFI_SUCCESS - add return value to function comment +{ + PCI_IO_DEVICE *Temp; + LIST_ENTRY *CurrentLink; + LIST_ENTRY *LastLink; + + CurrentLink = Bridge->ChildList.ForwardLink; + + while (CurrentLink && 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; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +PciHostBridgeResourceAllocator ( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc + ) +/*++ + +Routine Description: + + Host brige resource allocator. + +Arguments: + + PciResAlloc - A pointer to the EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL. + +Returns: + + EFI Status. + +--*/ +// TODO: EFI_NOT_FOUND - add return value to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + 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; + UINT64 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; + BOOLEAN ReAllocate; + REPORT_STATUS_CODE_LIBRARY_DEVICE_HANDLE_EXTENDED_DATA HandleExtendedData; + REPORT_STATUS_CODE_LIBRARY_RESOURCE_ALLOC_FAILURE_ERROR_DATA AllocFailExtendedData; + + // + // Reallocate flag + // + ReAllocate = FALSE; + + // + // It will 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 RootBridg 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 + // + + IoBridge = CreateResourceNode ( + RootBridgeDev, + 0, + 0xFFF, + 0, + PciBarTypeIo16, + PciResUsageTypical + ); + + Mem32Bridge = CreateResourceNode ( + RootBridgeDev, + 0, + 0xFFFFF, + 0, + PciBarTypeMem32, + PciResUsageTypical + ); + + PMem32Bridge = CreateResourceNode ( + RootBridgeDev, + 0, + 0xFFFFF, + 0, + PciBarTypePMem32, + PciResUsageTypical + ); + + Mem64Bridge = CreateResourceNode ( + RootBridgeDev, + 0, + 0xFFFFF, + 0, + PciBarTypeMem64, + PciResUsageTypical + ); + + PMem64Bridge = CreateResourceNode ( + RootBridgeDev, + 0, + 0xFFFFF, + 0, + PciBarTypePMem64, + PciResUsageTypical + ); + + // + // Create resourcemap by going through all the devices subject to this root bridge + // + Status = CreateResourceMap ( + RootBridgeDev, + IoBridge, + Mem32Bridge, + PMem32Bridge, + Mem64Bridge, + PMem64Bridge + ); + + // + // Get the max ROM size that the root bridge can process + // + RootBridgeDev->RomSize = Mem32Bridge->Length; + + // + // Skip to enlarge the resource request during realloction + // + if (!ReAllocate) { + // + // Get Max Option Rom size for current root bridge + // + MaxOptionRomSize = GetMaxOptionRomSize (RootBridgeDev); + + // + // Enlarger the mem32 resource to accomdate the option rom + // if the mem32 resource is not enough to hold the rom + // + if (MaxOptionRomSize > Mem32Bridge->Length) { + + Mem32Bridge->Length = MaxOptionRomSize; + RootBridgeDev->RomSize = MaxOptionRomSize; + + // + // Alignment should be adjusted as well + // + if (Mem32Bridge->Alignment < MaxOptionRomSize - 1) { + Mem32Bridge->Alignment = MaxOptionRomSize - 1; + } + } + } + + // + // Based on the all the resource tree, contruct 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 + ); + } + + // + // Free acpi resource node + // + if (AcpiConfig != NULL) { + gBS->FreePool (AcpiConfig); + } + + if (EFI_ERROR (Status)) { + // + // Destroy all the resource tree + // + DestroyResourceTree (&IoPool); + DestroyResourceTree (&Mem32Pool); + DestroyResourceTree (&PMem32Pool); + DestroyResourceTree (&Mem64Pool); + DestroyResourceTree (&PMem64Pool); + return Status; + } + } + + // + // Notify pci bus driver starts to program the resource + // + + Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeAllocateResources); + + 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 + ); + gBS->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; + } + + ReAllocate = TRUE; + + } + // + // 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_PC_RES_ALLOC, + (VOID *) &HandleExtendedData, + sizeof (HandleExtendedData) + ); + + // + // Notify pci bus driver starts to program the resource + // + NotifyPhase (PciResAlloc, EfiPciHostBridgeSetResources); + + 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 + ); + + // + // Process option rom for this root bridge + // + Status = ProcessOptionRom (RootBridgeDev, Mem32Base, RootBridgeDev->RomSize); + + // + // Create the entire system resource map from the information collected by + // enumerator. Several resource tree was created + // + Status = GetResourceMap ( + RootBridgeDev, + &IoBridge, + &Mem32Bridge, + &PMem32Bridge, + &Mem64Bridge, + &PMem64Bridge, + &IoPool, + &Mem32Pool, + &PMem32Pool, + &Mem64Pool, + &PMem64Pool + ); + + 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 + ); + + if (AcpiConfig != NULL) { + gBS->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 + // + NotifyPhase (PciResAlloc, EfiPciHostBridgeEndResourceAllocation); + + return EFI_SUCCESS; +} + +EFI_STATUS +PciScanBus ( + IN PCI_IO_DEVICE *Bridge, + IN UINT8 StartBusNumber, + OUT UINT8 *SubBusNumber, + OUT UINT8 *PaddedBusRange + ) +/*++ + +Routine Description: + + This routine is used to assign bus number to the given PCI bus system + +Arguments: + + Bridge - A pointer to the PCI_IO_DEVICE structure. + StartBusNumber - The start bus number. + SubBusNumber - A pointer to the sub bus number. + PaddedBusRange - A pointer to the padded bus range. + +Returns: + + None + +--*/ +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + PCI_TYPE00 Pci; + UINT8 Device; + UINT8 Func; + UINT64 Address; + UINTN SecondBus; + 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; + UINT16 BusRange; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; + BOOLEAN BusPadding; + + PciRootBridgeIo = Bridge->PciRootBridgeIo; + SecondBus = 0; + Register = 0; + State = 0; + Attributes = 0; + BusRange = 0; + + ResetAllPpbBusReg (Bridge, StartBusNumber); + + 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)) { + if (Func == 0) { + // + // Skip sub functions, this is not a multi function device + // + Func = PCI_MAX_FUNC; + } + + continue; + } + + // + // Get the PCI device information + // + Status = PciSearchDevice ( + Bridge, + &Pci, + StartBusNumber, + Device, + Func, + &PciDevice + ); + + ASSERT (!EFI_ERROR (Status)); + + 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 + ); + } + + // + // For Pci Hotplug controller devcie only + // + if (gPciHotPlugInit != NULL) { + // + // Check if it is a Hotplug PCI controller + // + if (IsRootPciHotPlugController (PciDevice->DevicePath, &HpIndex)) { + + 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 + ); + continue; + } + } + } + + if (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci)) { + // + // For PPB + // Get the bridge information + // + BusPadding = FALSE; + if (gPciHotPlugInit != NULL) { + + if (IsRootPciHotPlugBus (PciDevice->DevicePath, &HpIndex)) { + + // + // If it is initialized, get the padded bus range + // + Status = gPciHotPlugInit->GetResourcePadding ( + gPciHotPlugInit, + gPciRootHpcPool[HpIndex].HpbDevicePath, + PciAddress, + &State, + (VOID **) &Descriptors, + &Attributes + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + BusRange = 0; + Status = PciGetBusRange ( + &Descriptors, + NULL, + NULL, + &BusRange + ); + + gBS->FreePool (Descriptors); + + if (EFI_ERROR (Status)) { + return Status; + } + + BusPadding = TRUE; + } + } + + (*SubBusNumber)++; + 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 + ); + + + // + // If it is PPB, resursively search down this bridge + // + if (IS_PCI_BRIDGE (&Pci)) { + + // + // Initialize SubBusNumber to Maximum bus number + // + Register = 0xFF; + Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A); + 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, + (UINT8) (SecondBus), + SubBusNumber, + PaddedBusRange + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + } + + if (BusPadding) { + // + // Ensure the device is enabled and initialized + // + if ((Attributes == EfiPaddingPciRootBridge) && + (State & EFI_HPC_STATE_ENABLED) && + (State & EFI_HPC_STATE_INITIALIZED) ) { + *PaddedBusRange = (UINT8) ((UINT8) (BusRange) +*PaddedBusRange); + } else { + *SubBusNumber = (UINT8) ((UINT8) (BusRange) +*SubBusNumber); + } + } + + // + // 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; +} + +EFI_STATUS +PciRootBridgeP2CProcess ( + IN PCI_IO_DEVICE *Bridge + ) +/*++ + +Routine Description: + + Process Option Rom on this host bridge + +Arguments: + +Returns: + + None + +--*/ +// TODO: Bridge - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + LIST_ENTRY *CurrentLink; + PCI_IO_DEVICE *Temp; + EFI_HPC_STATE State; + UINT64 PciAddress; + EFI_STATUS Status; + + CurrentLink = Bridge->ChildList.ForwardLink; + + while (CurrentLink && CurrentLink != &Bridge->ChildList) { + + Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + + if (IS_CARDBUS_BRIDGE (&Temp->Pci)) { + + if (gPciHotPlugInit && Temp->Allocated) { + + // + // 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_PC_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; +} + +EFI_STATUS +PciHostBridgeP2CProcess ( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciResAlloc - add argument and description to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + 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; + } + + Status = PciRootBridgeP2CProcess (RootBridgeDev); + + if (EFI_ERROR (Status)) { + return Status; + } + + } + + return EFI_SUCCESS; +} + +EFI_STATUS +PciHostBridgeEnumerator ( + EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc + ) +/*++ + +Routine Description: + + This function is used to enumerate the entire host bridge + in a given platform + +Arguments: + + PciResAlloc - A pointer to the resource allocate protocol. + +Returns: + + None + +--*/ +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + 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; + + InitializeHotPlugSupport (); + + // + // Notify the bus allocation phase is about to start + // + NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation); + + 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 (EFI_ERROR (Status)) { + return Status; + } + + DestroyRootBridge (RootBridgeDev); + + // + // Error proccess here + // + } + + // + // Notify the bus allocation phase is finished for the first time + // + NotifyPhase (PciResAlloc, EfiPciHostBridgeEndBusAllocation); + + + if (gPciHotPlugInit != NULL) { + // + // Wait for all HPC initialized + // + Status = AllRootHPCInitialized (STALL_1_SECOND * 15); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Notify the bus allocation phase is about to start for the 2nd time + // + NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation); + + 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 + // + NotifyPhase (PciResAlloc, EfiPciHostBridgeEndBusAllocation); + } + + // + // Notify the resource allocation phase is to start + // + NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginResourceAllocation); + + 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/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciLib.h b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciLib.h new file mode 100644 index 0000000000..1e89445df6 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciLib.h @@ -0,0 +1,247 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PciLib.h + +Abstract: + + PCI Bus Driver Lib header file + It abstracts some functions that can be different + between light PCI bus driver and full PCI bus driver + +Revision History + +--*/ + +#ifndef _EFI_PCI_LIB_H +#define _EFI_PCI_LIB_H + +VOID +InstallHotPlugRequestProtocol ( + IN EFI_STATUS *Status + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Status - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +VOID +InstallPciHotplugGuid ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +VOID +UninstallPciHotplugGuid ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +VOID +GetBackPcCardBar ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +RemoveRejectedPciDevices ( + EFI_HANDLE RootBridgeHandle, + IN PCI_IO_DEVICE *Bridge + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + RootBridgeHandle - TODO: add argument description + Bridge - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +PciHostBridgeResourceAllocator ( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciResAlloc - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +PciScanBus ( + IN PCI_IO_DEVICE *Bridge, + IN UINT8 StartBusNumber, + OUT UINT8 *SubBusNumber, + OUT UINT8 *PaddedBusRange + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Bridge - TODO: add argument description + StartBusNumber - TODO: add argument description + SubBusNumber - TODO: add argument description + PaddedBusRange - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +PciRootBridgeP2CProcess ( + IN PCI_IO_DEVICE *Bridge + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Bridge - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +PciHostBridgeP2CProcess ( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciResAlloc - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +PciHostBridgeEnumerator ( + EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciResAlloc - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciOptionRomSupport.c b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciOptionRomSupport.c new file mode 100644 index 0000000000..324ad62827 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciOptionRomSupport.c @@ -0,0 +1,543 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PciOptionRomSupport.c + +Abstract: + + PCI Bus Driver + +Revision History + +--*/ + +#include "PciBus.h" +#include "PciResourceSupport.h" + +EFI_STATUS +GetOpRomInfo ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +// TODO: PciIoDevice - add argument and description to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + 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 48 if is not ppb + // + + // + // 0x30 + // + RomBarIndex = PCI_DEVICE_ROMBAR; + + 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 Status; + } + + // + // read back + // + Status = PciRootBridgeIo->Pci.Read ( + PciRootBridgeIo, + EfiPciWidthUint32, + Address, + 1, + &AllOnes + ); + if (EFI_ERROR (Status)) { + return Status; + } + + AllOnes &= 0xFFFFFFFC; + if ((AllOnes == 0) || (AllOnes == 0xFFFFFFFC)) { + return EFI_NOT_FOUND; + } + + PciIoDevice->RomSize = (UINT64) ((~AllOnes) + 1); + return EFI_SUCCESS; + +} + +EFI_STATUS +LoadOpRomImage ( + IN PCI_IO_DEVICE *PciDevice, + IN UINT64 RomBase + ) +/*++ + +Routine Description: + + Load option rom image for specified PCI device + +Arguments: + +Returns: + +--*/ +// TODO: PciDevice - add argument and description to function comment +// TODO: RomBase - add argument and description to function comment +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +{ + UINT8 RomBarIndex; + UINT8 Indicator; + UINT16 OffsetPcir; + UINT32 RomBarOffset; + UINT32 RomBar; + UINT64 Temp; + EFI_STATUS retStatus; + BOOLEAN FirstCheck; + UINT8 *Image; + PCI_EXPANSION_ROM_HEADER *RomHeader; + PCI_DATA_STRUCTURE *RomPcir; + UINT64 RomSize; + UINT64 RomImageSize; + UINT8 *RomInMemory; + + RomSize = PciDevice->RomSize; + + Indicator = 0; + RomImageSize = 0; + RomInMemory = NULL; + Temp = 0; + + // + // Get the RomBarIndex + // + + // + // 0x30 + // + RomBarIndex = PCI_DEVICE_ROMBAR; + 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) { + gBS->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; + + 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; + PciDevice->PciRootBridgeIo->Mem.Read ( + PciDevice->PciRootBridgeIo, + EfiPciWidthUint8, + RomBarOffset + OffsetPcir, + sizeof (PCI_DATA_STRUCTURE), + (UINT8 *) RomPcir + ); + Indicator = RomPcir->Indicator; + RomImageSize = RomImageSize + RomPcir->ImageLength * 512; + RomBarOffset = RomBarOffset + RomPcir->ImageLength * 512; + } while (((Indicator & 0x80) == 0x00) && ((RomBarOffset - RomBar) < RomSize)); + + if (RomImageSize > 0) { + retStatus = EFI_SUCCESS; + Image = AllocatePool ((UINT32) RomImageSize); + if (Image == NULL) { + RomDecode (PciDevice, RomBarIndex, RomBar, FALSE); + gBS->FreePool (RomHeader); + gBS->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->PciIo.RomSize = RomImageSize; + PciDevice->PciIo.RomImage = RomInMemory; + + PciRomAddImageMapping ( + NULL, + PciDevice->PciRootBridgeIo->SegmentNumber, + PciDevice->BusNumber, + PciDevice->DeviceNumber, + PciDevice->FunctionNumber, + (UINT64) (UINTN) PciDevice->PciIo.RomImage, + PciDevice->PciIo.RomSize + ); + + // + // Free allocated memory + // + gBS->FreePool (RomHeader); + gBS->FreePool (RomPcir); + + return retStatus; +} + +EFI_STATUS +RomDecode ( + IN PCI_IO_DEVICE *PciDevice, + IN UINT8 RomBarIndex, + IN UINT32 RomBar, + IN BOOLEAN Enable + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +// TODO: PciDevice - add argument and description to function comment +// TODO: RomBarIndex - add argument and description to function comment +// TODO: RomBar - add argument and description to function comment +// TODO: Enable - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + UINT32 Value32; + UINT32 Offset; + EFI_PCI_IO_PROTOCOL *PciIo; + + PciIo = &PciDevice->PciIo; + if (Enable) { + // + // Clear all bars + // + for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) { + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllZero); + } + + // + // 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 + // + ProgrameUpstreamBridgeForRom(PciDevice, RomBar, TRUE); + + // + // Setting the memory space bit in the function's command register + // + PciEnableCommandRegister(PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE); + + } else { + + // + // disable command register decode to memory + // + PciDisableCommandRegister(PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE); + + // + // Destroy the programmed bar in all the upstream bridge. + // + ProgrameUpstreamBridgeForRom(PciDevice, RomBar, FALSE); + + // + // disable rom decode + // + Value32 = 0xFFFFFFFE; + PciIo->Pci.Write ( + PciIo, + (EFI_PCI_IO_PROTOCOL_WIDTH) EfiPciWidthUint32, + RomBarIndex, + 1, + &Value32 + ); + + } + + return EFI_SUCCESS; + +} + +EFI_STATUS +ProcessOpRomImage ( + PCI_IO_DEVICE *PciDevice + ) +/*++ + +Routine Description: + + Process the oprom image. + +Arguments: + PciDevice A pointer to a pci device. + +Returns: + + EFI Status. + +--*/ +{ + UINT8 Indicator; + UINT32 ImageSize; + UINT16 ImageOffset; + VOID *RomBar; + UINT8 *RomBarOffset; + EFI_HANDLE ImageHandle; + EFI_STATUS Status; + EFI_STATUS retStatus; + BOOLEAN FirstCheck; + BOOLEAN SkipImage; + UINT32 DestinationSize; + UINT32 ScratchSize; + UINT8 *Scratch; + VOID *ImageBuffer; + VOID *DecompressedImageBuffer; + UINT32 ImageLength; + EFI_DECOMPRESS_PROTOCOL *Decompress; + EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader; + PCI_DATA_STRUCTURE *Pcir; + + Indicator = 0; + + // + // Get the Address of the Rom image + // + RomBar = PciDevice->PciIo.RomImage; + RomBarOffset = (UINT8 *) RomBar; + retStatus = EFI_NOT_FOUND; + FirstCheck = TRUE; + + do { + EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset; + if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) { + RomBarOffset = RomBarOffset + 512; + if (FirstCheck) { + break; + } else { + continue; + } + } + + FirstCheck = FALSE; + Pcir = (PCI_DATA_STRUCTURE *) (RomBarOffset + EfiRomHeader->PcirOffset); + ImageSize = (UINT32) (Pcir->ImageLength * 512); + Indicator = Pcir->Indicator; + + if ((Pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) && + (EfiRomHeader->EfiSignature == EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE)) { + + if ((EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) || + (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)) { + + ImageOffset = EfiRomHeader->EfiImageHeaderOffset; + ImageSize = (UINT32) (EfiRomHeader->InitializationSize * 512); + + ImageBuffer = (VOID *) (RomBarOffset + ImageOffset); + ImageLength = ImageSize - (UINT32)ImageOffset; + DecompressedImageBuffer = NULL; + + // + // decompress here if needed + // + SkipImage = FALSE; + if (EfiRomHeader->CompressionType > EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) { + SkipImage = TRUE; + } + + if (EfiRomHeader->CompressionType == EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) { + Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **) &Decompress); + if (EFI_ERROR (Status)) { + SkipImage = TRUE; + } else { + SkipImage = TRUE; + Status = Decompress->GetInfo ( + Decompress, + ImageBuffer, + ImageLength, + &DestinationSize, + &ScratchSize + ); + if (!EFI_ERROR (Status)) { + DecompressedImageBuffer = NULL; + DecompressedImageBuffer = AllocatePool (DestinationSize); + if (DecompressedImageBuffer != NULL) { + Scratch = AllocatePool (ScratchSize); + if (Scratch != NULL) { + Status = Decompress->Decompress ( + Decompress, + ImageBuffer, + ImageLength, + DecompressedImageBuffer, + DestinationSize, + Scratch, + ScratchSize + ); + if (!EFI_ERROR (Status)) { + ImageBuffer = DecompressedImageBuffer; + ImageLength = DestinationSize; + SkipImage = FALSE; + } + + gBS->FreePool (Scratch); + } + } + } + } + } + + if (!SkipImage) { + // + // load image and start image + // + Status = gBS->LoadImage ( + FALSE, + gPciBusDriverBinding.DriverBindingHandle, + PciDevice->Handle, + ImageBuffer, + ImageLength, + &ImageHandle + ); + if (!EFI_ERROR (Status)) { + Status = gBS->StartImage (ImageHandle, NULL, NULL); + if (!EFI_ERROR (Status)) { + AddDriver (PciDevice, ImageHandle); + PciRomAddImageMapping ( + ImageHandle, + PciDevice->PciRootBridgeIo->SegmentNumber, + PciDevice->BusNumber, + PciDevice->DeviceNumber, + PciDevice->FunctionNumber, + (UINT64) (UINTN) PciDevice->PciIo.RomImage, + PciDevice->PciIo.RomSize + ); + retStatus = EFI_SUCCESS; + } + } + } + + RomBarOffset = RomBarOffset + ImageSize; + } else { + RomBarOffset = RomBarOffset + ImageSize; + } + } else { + RomBarOffset = RomBarOffset + ImageSize; + } + + } while (((Indicator & 0x80) == 0x00) && ((UINTN) (RomBarOffset - (UINT8 *) RomBar) < PciDevice->RomSize)); + + return retStatus; + +} diff --git a/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciOptionRomSupport.h b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciOptionRomSupport.h new file mode 100644 index 0000000000..2bb11bf3d3 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciOptionRomSupport.h @@ -0,0 +1,119 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PciOptionRomSupport.h + +Abstract: + + PCI Bus Driver + +Revision History + +--*/ + +#ifndef _EFI_PCI_OP_ROM_SUPPORT_H +#define _EFI_PCI_OP_ROM_SUPPORT_H + +EFI_STATUS +GetOpRomInfo ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +LoadOpRomImage ( + IN PCI_IO_DEVICE *PciDevice, + IN UINT64 RomBase + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciDevice - TODO: add argument description + RomBase - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +RomDecode ( + IN PCI_IO_DEVICE *PciDevice, + IN UINT8 RomBarIndex, + IN UINT32 RomBar, + IN BOOLEAN Enable + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciDevice - TODO: add argument description + RomBarIndex - TODO: add argument description + RomBar - TODO: add argument description + Enable - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +ProcessOpRomImage ( + PCI_IO_DEVICE *PciDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciPowerManagement.c b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciPowerManagement.c new file mode 100644 index 0000000000..1760c3946b --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciPowerManagement.c @@ -0,0 +1,83 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PciPowerManagement.c + +Abstract: + + PCI Bus Driver + +Revision History + +--*/ + +#include "Pcibus.h" + +EFI_STATUS +ResetPowerManagementFeature ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + This function is intended to turn off PWE assertion and + put the device to D0 state if the device supports + PCI Power Management. + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciIoDevice - add argument and description to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + UINT8 PowerManagementRegBlock; + UINT16 PMCSR; + + 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 + // + PMCSR = 0x8000; + + // + // Write PMCSR + // + PciIoDevice->PciIo.Pci.Write ( + &PciIoDevice->PciIo, + EfiPciIoWidthUint16, + PowerManagementRegBlock + 4, + 1, + &PMCSR + ); + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciPowerManagement.h b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciPowerManagement.h new file mode 100644 index 0000000000..f33f7ab0de --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciPowerManagement.h @@ -0,0 +1,48 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PciPowerManagement.h + +Abstract: + + PCI Bus Driver + +Revision History + +--*/ + +#ifndef _EFI_PCI_POWER_MANAGEMENT_H +#define _EFI_PCI_POWER_MANAGEMENT_H + +EFI_STATUS +ResetPowerManagementFeature ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciResourceSupport.c b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciResourceSupport.c new file mode 100644 index 0000000000..8f89e8983a --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciResourceSupport.c @@ -0,0 +1,2276 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PciResourceSupport.c + +Abstract: + + PCI Bus Driver + +Revision History + +--*/ + +#include "PciBus.h" +#include "PciResourceSupport.h" +#include "PciCommand.h" + +EFI_STATUS +SkipVGAAperture ( + OUT UINT64 *Start, + IN UINT64 Length + ) +/*++ + +Routine Description: + + The function is used to skip VGA range + +Arguments: + +Returns: + + None + +--*/ +// TODO: Start - add argument and description to function comment +// TODO: Length - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + UINT64 Original; + UINT64 Mask; + UINT64 StartOffset; + UINT64 LimitOffset; + + // + // 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; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +SkipIsaAliasAperture ( + OUT UINT64 *Start, + IN UINT64 Length + ) +/*++ + +Routine Description: + + This function is used to skip ISA aliasing aperture + +Arguments: + +Returns: + + None + +--*/ +// TODO: Start - add argument and description to function comment +// TODO: Length - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + + UINT64 Original; + UINT64 Mask; + UINT64 StartOffset; + UINT64 LimitOffset; + + // + // 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; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +InsertResourceNode ( + PCI_RESOURCE_NODE *Bridge, + PCI_RESOURCE_NODE *ResNode + ) +/*++ + +Routine Description: + + This function inserts a resource node into the resource list. + The resource list is sorted in descend order. + +Arguments: + +Returns: + + None + +--*/ +// TODO: Bridge - add argument and description to function comment +// TODO: ResNode - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + LIST_ENTRY *CurrentLink; + PCI_RESOURCE_NODE *Temp; + UINT64 ResNodeAlignRest; + UINT64 TempAlignRest; + + 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; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +MergeResourceTree ( + PCI_RESOURCE_NODE *Dst, + PCI_RESOURCE_NODE *Res, + BOOLEAN TypeMerge + ) +/*++ + +Routine Description: + + This routine is used to merge two different resource tree in need of + resoure degradation. For example, if a upstream PPB doesn't support, + prefetchable memory decoding, the PCI bus driver will choose to call this function + to merge prefectchable memory resource list into normal memory list. + + If the TypeMerge is TRUE, Res resource type is changed to the type of destination resource + type. + +Arguments: + +Returns: + + None + +--*/ +// TODO: Dst - add argument and description to function comment +// TODO: Res - add argument and description to function comment +// TODO: TypeMerge - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + + LIST_ENTRY *CurrentLink; + PCI_RESOURCE_NODE *Temp; + + 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); + + } + + return EFI_SUCCESS; +} + +EFI_STATUS +CalculateApertureIo16 ( + IN PCI_RESOURCE_NODE *Bridge + ) +/*++ + +Routine Description: + + This function is used to calculate the IO16 aperture + for a bridge. + +Arguments: + +Returns: + + None + +--*/ +// TODO: Bridge - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + + UINT64 Aperture; + LIST_ENTRY *CurrentLink; + PCI_RESOURCE_NODE *Node; + UINT64 offset; + + // + // Always assume there is ISA device and VGA device on the platform + // will be customized later + // + Aperture = 0; + + if (!Bridge) { + return EFI_SUCCESS; + } + + CurrentLink = Bridge->ChildList.ForwardLink; + + // + // Assume the bridge is aligned + // + while (CurrentLink != &Bridge->ChildList) { + + Node = RESOURCE_NODE_FROM_LINK (CurrentLink); + + // + // Consider the aperture alignment + // + offset = Aperture & (Node->Alignment); + + if (offset) { + + 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. + // + + Node->Offset = Aperture; + + // + // Increment aperture by the length of node + // + Aperture += Node->Length; + + CurrentLink = CurrentLink->ForwardLink; + } + + // + // At last, adjust the aperture with the bridge's + // alignment + // + offset = Aperture & (Bridge->Alignment); + + if (offset) { + 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; + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +CalculateResourceAperture ( + IN PCI_RESOURCE_NODE *Bridge + ) +/*++ + +Routine Description: + + This function is used to calculate the resource aperture + for a given bridge device + +Arguments: + +Returns: + + None + +--*/ +// TODO: Bridge - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + UINT64 Aperture; + LIST_ENTRY *CurrentLink; + PCI_RESOURCE_NODE *Node; + + UINT64 offset; + + Aperture = 0; + + if (!Bridge) { + return EFI_SUCCESS; + } + + if (Bridge->ResType == PciBarTypeIo16) { + return CalculateApertureIo16 (Bridge); + } + + CurrentLink = Bridge->ChildList.ForwardLink; + + // + // Assume the bridge is aligned + // + while (CurrentLink != &Bridge->ChildList) { + + Node = RESOURCE_NODE_FROM_LINK (CurrentLink); + + // + // Apply padding resource if available + // + + offset = Aperture & (Node->Alignment); + + if (offset) { + + Aperture = Aperture + (Node->Alignment + 1) - offset; + + } + + // + // Recode current aperture as a offset + // this offset will be used in future real allocation + // + Node->Offset = Aperture; + + // + // Increment aperture by the length of node + // + Aperture += Node->Length; + + // + // Consider the aperture alignment + // + + CurrentLink = CurrentLink->ForwardLink; + } + + // + // At last, adjust the aperture with the bridge's + // alignment + // + offset = Aperture & (Bridge->Alignment); + if (offset) { + Aperture = Aperture + (Bridge->Alignment + 1) - offset; + } + + // + // If the bridge has already padded the resource and the + // amount of padded resource is larger, then keep the + // padded resource + // + if (Bridge->Length < Aperture) { + 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; + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +GetResourceFromDevice ( + PCI_IO_DEVICE *PciDev, + PCI_RESOURCE_NODE *IoNode, + PCI_RESOURCE_NODE *Mem32Node, + PCI_RESOURCE_NODE *PMem32Node, + PCI_RESOURCE_NODE *Mem64Node, + PCI_RESOURCE_NODE *PMem64Node + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciDev - add argument and description to function comment +// TODO: IoNode - add argument and description to function comment +// TODO: Mem32Node - add argument and description to function comment +// TODO: PMem32Node - add argument and description to function comment +// TODO: Mem64Node - add argument and description to function comment +// TODO: PMem64Node - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + + 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: + + Node = CreateResourceNode ( + PciDev, + (PciDev->PciBar)[Index].Length, + (PciDev->PciBar)[Index].Alignment, + Index, + PciBarTypeMem32, + 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; + } + } + + // + // If there is no resource requested from this device, + // then we indicate this device has been allocated naturally. + // + if (!ResourceRequested) { + PciDev->Allocated = TRUE; + } + + return EFI_SUCCESS; +} + +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 + ) +/*++ + +Routine Description: + + This function is used to create a resource node + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciDev - add argument and description to function comment +// TODO: Length - add argument and description to function comment +// TODO: Alignment - add argument and description to function comment +// TODO: Bar - add argument and description to function comment +// TODO: ResType - add argument and description to function comment +// TODO: ResUsage - add argument and description to function comment +{ + EFI_STATUS Status; + PCI_RESOURCE_NODE *Node; + + Status = 0; + Node = NULL; + + Node = AllocatePool (sizeof (PCI_RESOURCE_NODE)); + if (Node == NULL) { + return NULL; + } + + ZeroMem (Node, sizeof (PCI_RESOURCE_NODE)); + + 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; +} + +EFI_STATUS +CreateResourceMap ( + 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 + ) +/*++ + +Routine Description: + + This routine is used to extract resource request from + device node list. + +Arguments: + +Returns: + + None + +--*/ +// TODO: Bridge - add argument and description to function comment +// TODO: IoNode - add argument and description to function comment +// TODO: Mem32Node - add argument and description to function comment +// TODO: PMem32Node - add argument and description to function comment +// TODO: Mem64Node - add argument and description to function comment +// TODO: PMem64Node - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + PCI_IO_DEVICE *Temp; + EFI_STATUS Status; + 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 && 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 + // This device is typically a bridge device like PPB and P2C + // + IoBridge = CreateResourceNode ( + Temp, + 0, + 0xFFF, + PPB_IO_RANGE, + PciBarTypeIo16, + PciResUsageTypical + ); //0x1000 aligned + + 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 resouce map on this bridge + // + Status = CreateResourceMap ( + Temp, + IoBridge, + Mem32Bridge, + PMem32Bridge, + Mem64Bridge, + PMem64Bridge + ); + + if (ResourceRequestExisted (IoBridge)) { + InsertResourceNode ( + IoNode, + IoBridge + ); + } else { + gBS->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 { + gBS->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 { + gBS->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 { + gBS->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 { + gBS->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 ... + // + Status = 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); + + return EFI_SUCCESS; + +} + +EFI_STATUS +ResourcePaddingPolicy ( + PCI_IO_DEVICE *PciDev, + PCI_RESOURCE_NODE *IoNode, + PCI_RESOURCE_NODE *Mem32Node, + PCI_RESOURCE_NODE *PMem32Node, + PCI_RESOURCE_NODE *Mem64Node, + PCI_RESOURCE_NODE *PMem64Node + ) +/*++ + +Routine Description: + + This function is used to do the resource padding for a specific platform + +Arguments: + + PciDev - A pointer to the PCI_IO_DEVICE structrue. + IoNode - A pointer to the PCI_RESOURCE_NODE structrue. + Mem32Node - A pointer to the PCI_RESOURCE_NODE structrue. + PMem32Node - A pointer to the PCI_RESOURCE_NODE structrue. + Mem64Node - A pointer to the PCI_RESOURCE_NODE structrue. + PMem64Node - A pointer to the PCI_RESOURCE_NODE structrue. + +Returns: + Status code + + None + +--*/ +// TODO: EFI_SUCCESS - add return value to function comment +{ + // + // Create padding resource node + // + if (PciDev->ResourcePaddingDescriptors != NULL) { + ApplyResourcePadding ( + PciDev, + IoNode, + Mem32Node, + PMem32Node, + Mem64Node, + PMem64Node + ); + } + + return EFI_SUCCESS; + +} + +EFI_STATUS +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 + ) +/*++ + +Routine Description: + + 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 + +Arguments: + +Returns: + + None + +--*/ +// TODO: Bridge - add argument and description to function comment +// TODO: Mem32Node - add argument and description to function comment +// TODO: PMem32Node - add argument and description to function comment +// TODO: Mem64Node - add argument and description to function comment +// TODO: PMem64Node - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + + // + // If bridge doesn't support Prefetchable + // memory64, degrade it to Mem64 + // + if (!BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_PMEM64_DECODE_SUPPORTED)) { + MergeResourceTree ( + PMem32Node, + PMem64Node, + TRUE + ); + } else { + // + // if no PMem32 request, still keep PMem64. Otherwise degrade to PMem32 + // + if (PMem32Node != NULL) { + MergeResourceTree ( + PMem32Node, + PMem64Node, + TRUE + ); + } + } + + + // + // If bridge doesn't support Mem64 + // degrade it to mem32 + // + if (!BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_MEM64_DECODE_SUPPORTED)) { + MergeResourceTree ( + Mem32Node, + Mem64Node, + TRUE + ); + } + + // + // If bridge doesn't support Pmem32 + // degrade it to mem32 + // + if (!BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_PMEM32_DECODE_SUPPORTED)) { + MergeResourceTree ( + Mem32Node, + PMem32Node, + TRUE + ); + } + + // + // if 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 + ); + + MergeResourceTree ( + Mem64Node, + PMem64Node, + FALSE + ); + } + + return EFI_SUCCESS; +} + +BOOLEAN +BridgeSupportResourceDecode ( + IN PCI_IO_DEVICE *Bridge, + IN UINT32 Decode + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Bridge - TODO: add argument description + Decode - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + /*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ + if ((Bridge->Decodes) & Decode) { + return TRUE; + } + + return FALSE; +} + +EFI_STATUS +ProgramResource ( + IN UINT64 Base, + IN PCI_RESOURCE_NODE *Bridge + ) +/*++ + +Routine Description: + + This function is used to program the resource allocated + for each resource node + +Arguments: + +Returns: + + None + +--*/ +// TODO: Base - add argument and description to function comment +// TODO: Bridge - add argument and description to function comment +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + 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))) { + ProgramP2C (Base, Node); + } else { + ProgramBar (Base, Node); + } + } else { + Status = ProgramResource (Base + Node->Offset, Node); + + if (EFI_ERROR (Status)) { + return Status; + } + + ProgramPpbApperture (Base, Node); + } + + CurrentLink = CurrentLink->ForwardLink; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +ProgramBar ( + IN UINT64 Base, + IN PCI_RESOURCE_NODE *Node + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: Base - add argument and description to function comment +// TODO: Node - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_PCI_IO_PROTOCOL *PciIo; + UINT64 Address; + UINT32 Address32; + + 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 + ); + + 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; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +ProgramPpbApperture ( + IN UINT64 Base, + IN PCI_RESOURCE_NODE *Node + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: Base - add argument and description to function comment +// TODO: Node - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_PCI_IO_PROTOCOL *PciIo; + UINT64 Address; + UINT32 Address32; + + Address = 0; + // + // if no device south of this PPB, return anyway + // Apperture is set default in the initialization code + // + if (Node->Length == 0 || Node->ResourceUsage == PciResUsagePadding) { + // + // For padding resource node, just ignore when programming + // + return EFI_SUCCESS; + } + + 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: + 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 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; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +ProgrameUpstreamBridgeForRom ( + IN PCI_IO_DEVICE *PciDevice, + IN UINT32 OptionRomBase, + IN BOOLEAN Enable + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +// TODO: PciDevice - add argument and description to function comment +// TODO: OptionRomBase - add argument and description to function comment +// TODO: Enable - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + PCI_IO_DEVICE *Parent; + PCI_RESOURCE_NODE Node; + // + // For root bridge, just return. + // + Parent = PciDevice->Parent; + ZeroMem (&Node, sizeof (Node)); + while (Parent) { + if (!IS_PCI_BRIDGE (&Parent->Pci)) { + break; + } + + Node.PciDev = Parent; + Node.Length = PciDevice->RomSize; + Node.Alignment = 0; + Node.Bar = PPB_MEM32_RANGE; + Node.ResType = PciBarTypeMem32; + Node.Offset = 0; + + // + // Program PPB to only open a single <= 16Parent; + } + + return EFI_SUCCESS; +} + +BOOLEAN +ResourceRequestExisted ( + IN PCI_RESOURCE_NODE *Bridge + ) +/*++ + +Routine Description: + +Arguments: + + Bridge - A pointer to the PCI_RESOURCE_NODE. + +Returns: + + None + +--*/ +{ + if (Bridge != NULL) { + if (!IsListEmpty (&Bridge->ChildList) || Bridge->Length != 0) { + return TRUE; + } + } + + return FALSE; +} + +EFI_STATUS +InitializeResourcePool ( + PCI_RESOURCE_NODE *ResourcePool, + PCI_BAR_TYPE ResourceType + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: ResourcePool - add argument and description to function comment +// TODO: ResourceType - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + + ZeroMem (ResourcePool, sizeof (PCI_RESOURCE_NODE)); + ResourcePool->ResType = ResourceType; + ResourcePool->Signature = PCI_RESOURCE_SIGNATURE; + InitializeListHead (&ResourcePool->ChildList); + + return EFI_SUCCESS; +} + +EFI_STATUS +GetResourceMap ( + PCI_IO_DEVICE *PciDev, + 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 + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciDev - add argument and description to function comment +// TODO: IoBridge - add argument and description to function comment +// TODO: Mem32Bridge - add argument and description to function comment +// TODO: PMem32Bridge - add argument and description to function comment +// TODO: Mem64Bridge - add argument and description to function comment +// TODO: PMem64Bridge - add argument and description to function comment +// TODO: IoPool - add argument and description to function comment +// TODO: Mem32Pool - add argument and description to function comment +// TODO: PMem32Pool - add argument and description to function comment +// TODO: Mem64Pool - add argument and description to function comment +// TODO: PMem64Pool - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + + PCI_RESOURCE_NODE *Temp; + LIST_ENTRY *CurrentLink; + + CurrentLink = IoPool->ChildList.ForwardLink; + + // + // Get Io resource map + // + while (CurrentLink != &IoPool->ChildList) { + + Temp = RESOURCE_NODE_FROM_LINK (CurrentLink); + + if (Temp->PciDev == PciDev) { + *IoBridge = Temp; + } + + CurrentLink = CurrentLink->ForwardLink; + } + + // + // Get Mem32 resource map + // + CurrentLink = Mem32Pool->ChildList.ForwardLink; + + while (CurrentLink != &Mem32Pool->ChildList) { + + Temp = RESOURCE_NODE_FROM_LINK (CurrentLink); + + if (Temp->PciDev == PciDev) { + *Mem32Bridge = Temp; + } + + CurrentLink = CurrentLink->ForwardLink; + } + + // + // Get Pmem32 resource map + // + CurrentLink = PMem32Pool->ChildList.ForwardLink; + + while (CurrentLink != &PMem32Pool->ChildList) { + + Temp = RESOURCE_NODE_FROM_LINK (CurrentLink); + + if (Temp->PciDev == PciDev) { + *PMem32Bridge = Temp; + } + + CurrentLink = CurrentLink->ForwardLink; + } + + // + // Get Mem64 resource map + // + CurrentLink = Mem64Pool->ChildList.ForwardLink; + + while (CurrentLink != &Mem64Pool->ChildList) { + + Temp = RESOURCE_NODE_FROM_LINK (CurrentLink); + + if (Temp->PciDev == PciDev) { + *Mem64Bridge = Temp; + } + + CurrentLink = CurrentLink->ForwardLink; + } + + // + // Get Pmem64 resource map + // + CurrentLink = PMem64Pool->ChildList.ForwardLink; + + while (CurrentLink != &PMem64Pool->ChildList) { + + Temp = RESOURCE_NODE_FROM_LINK (CurrentLink); + + if (Temp->PciDev == PciDev) { + *PMem64Bridge = Temp; + } + + CurrentLink = CurrentLink->ForwardLink; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +DestroyResourceTree ( + IN PCI_RESOURCE_NODE *Bridge + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: Bridge - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + PCI_RESOURCE_NODE *Temp; + LIST_ENTRY *CurrentLink; + + while (!IsListEmpty (&Bridge->ChildList)) { + + CurrentLink = Bridge->ChildList.ForwardLink; + + Temp = RESOURCE_NODE_FROM_LINK (CurrentLink); + + RemoveEntryList (CurrentLink); + + if (IS_PCI_BRIDGE (&(Temp->PciDev->Pci))) { + DestroyResourceTree (Temp); + } + + gBS->FreePool (Temp); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +RecordReservedResource ( + IN UINT64 Base, + IN UINT64 Length, + IN PCI_BAR_TYPE ResType, + IN PCI_IO_DEVICE *Bridge + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: Base - add argument and description to function comment +// TODO: Length - add argument and description to function comment +// TODO: ResType - add argument and description to function comment +// TODO: Bridge - add argument and description to function comment +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + PCI_RESERVED_RESOURCE_LIST *ReservedNode; + + ReservedNode = AllocatePool (sizeof (PCI_RESERVED_RESOURCE_LIST)); + if (ReservedNode == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + ReservedNode->Signature = RESERVED_RESOURCE_SIGNATURE; + ReservedNode->Node.Base = Base; + ReservedNode->Node.Length = Length; + ReservedNode->Node.ResType = ResType; + + InsertTailList (&Bridge->ReservedResourceList, &(ReservedNode->Link)); + + return EFI_SUCCESS; +} + +EFI_STATUS +ResourcePaddingForCardBusBridge ( + PCI_IO_DEVICE *PciDev, + PCI_RESOURCE_NODE *IoNode, + PCI_RESOURCE_NODE *Mem32Node, + PCI_RESOURCE_NODE *PMem32Node, + PCI_RESOURCE_NODE *Mem64Node, + PCI_RESOURCE_NODE *PMem64Node + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciDev - add argument and description to function comment +// TODO: IoNode - add argument and description to function comment +// TODO: Mem32Node - add argument and description to function comment +// TODO: PMem32Node - add argument and description to function comment +// TODO: Mem64Node - add argument and description to function comment +// TODO: PMem64Node - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + PCI_RESOURCE_NODE *Node; + + Node = NULL; + + // + // Memory Base/Limit Register 0 + // Bar 1 denodes memory range 0 + // + Node = CreateResourceNode ( + PciDev, + 0x2000000, + 0x1ffffff, + 1, + PciBarTypeMem32, + PciResUsagePadding + ); + + InsertResourceNode ( + Mem32Node, + Node + ); + + // + // Memory Base/Limit Register 1 + // Bar 2 denodes memory range1 + // + Node = CreateResourceNode ( + PciDev, + 0x2000000, + 0x1ffffff, + 2, + PciBarTypePMem32, + PciResUsagePadding + ); + + InsertResourceNode ( + PMem32Node, + Node + ); + + // + // Io Base/Limit + // Bar 3 denodes io range 0 + // + Node = CreateResourceNode ( + PciDev, + 0x100, + 0xff, + 3, + PciBarTypeIo16, + PciResUsagePadding + ); + + InsertResourceNode ( + IoNode, + Node + ); + + // + // Io Base/Limit + // Bar 4 denodes io range 0 + // + Node = CreateResourceNode ( + PciDev, + 0x100, + 0xff, + 4, + PciBarTypeIo16, + PciResUsagePadding + ); + + InsertResourceNode ( + IoNode, + Node + ); + + return EFI_SUCCESS; +} + +EFI_STATUS +ProgramP2C ( + IN UINT64 Base, + IN PCI_RESOURCE_NODE *Node + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: Base - add argument and description to function comment +// TODO: Node - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + 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, + 0x1c, + 1, + &Address + ); + + TempAddress = Address + Node->Length - 1; + PciIo->Pci.Write ( + PciIo, + EfiPciIoWidthUint32, + 0x20, + 1, + &TempAddress + ); + + if (Node->ResType == PciBarTypeMem32) { + + // + // Set non-prefetchable bit + // + PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint16, + 0x3e, + 1, + &BridgeControl + ); + + BridgeControl &= 0xfeff; + PciIo->Pci.Write ( + PciIo, + EfiPciIoWidthUint16, + 0x3e, + 1, + &BridgeControl + ); + + } else { + + // + // Set pre-fetchable bit + // + PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint16, + 0x3e, + 1, + &BridgeControl + ); + + BridgeControl |= 0x0100; + PciIo->Pci.Write ( + PciIo, + EfiPciIoWidthUint16, + 0x3e, + 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, + 0x24, + 1, + &Address + ); + + TempAddress = Address + Node->Length - 1; + + PciIo->Pci.Write ( + PciIo, + EfiPciIoWidthUint32, + 0x28, + 1, + &TempAddress + ); + + if (Node->ResType == PciBarTypeMem32) { + + // + // Set non-prefetchable bit + // + PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint16, + 0x3e, + 1, + &BridgeControl + ); + + BridgeControl &= 0xfdff; + PciIo->Pci.Write ( + PciIo, + EfiPciIoWidthUint16, + 0x3e, + 1, + &BridgeControl + ); + } else { + + // + // Set pre-fetchable bit + // + PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint16, + 0x3e, + 1, + &BridgeControl + ); + + BridgeControl |= 0x0200; + PciIo->Pci.Write ( + PciIo, + EfiPciIoWidthUint16, + 0x3e, + 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, + 0x2c, + 1, + &Address + ); + TempAddress = Address + Node->Length - 1; + PciIo->Pci.Write ( + PciIo, + EfiPciIoWidthUint32, + 0x30, + 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, + 0x34, + 1, + &Address + ); + + TempAddress = Address + Node->Length - 1; + PciIo->Pci.Write ( + PciIo, + EfiPciIoWidthUint32, + 0x38, + 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; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +ApplyResourcePadding ( + PCI_IO_DEVICE *PciDev, + PCI_RESOURCE_NODE *IoNode, + PCI_RESOURCE_NODE *Mem32Node, + PCI_RESOURCE_NODE *PMem32Node, + PCI_RESOURCE_NODE *Mem64Node, + PCI_RESOURCE_NODE *PMem64Node + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciDev - add argument and description to function comment +// TODO: IoNode - add argument and description to function comment +// TODO: Mem32Node - add argument and description to function comment +// TODO: PMem32Node - add argument and description to function comment +// TODO: Mem64Node - add argument and description to function comment +// TODO: PMem64Node - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + 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) { + + // + // prefechable + // + if (Ptr->SpecificFlag == 0x6) { + if (Ptr->AddrLen) { + Node = CreateResourceNode ( + PciDev, + Ptr->AddrLen, + Ptr->AddrRangeMax, + DummyBarIndex, + PciBarTypePMem32, + PciResUsagePadding + ); + InsertResourceNode ( + PMem32Node, + Node + ); + } + + Ptr++; + continue; + } + + // + // Non-prefechable + // + if (Ptr->SpecificFlag == 0) { + if (Ptr->AddrLen) { + Node = CreateResourceNode ( + PciDev, + Ptr->AddrLen, + Ptr->AddrRangeMax, + DummyBarIndex, + PciBarTypeMem32, + PciResUsagePadding + ); + InsertResourceNode ( + Mem32Node, + Node + ); + } + + Ptr++; + continue; + } + } + + if (Ptr->AddrSpaceGranularity == 64) { + + // + // prefechable + // + if (Ptr->SpecificFlag == 0x6) { + if (Ptr->AddrLen) { + Node = CreateResourceNode ( + PciDev, + Ptr->AddrLen, + Ptr->AddrRangeMax, + DummyBarIndex, + PciBarTypePMem64, + PciResUsagePadding + ); + InsertResourceNode ( + PMem64Node, + Node + ); + } + + Ptr++; + continue; + } + + // + // Non-prefechable + // + if (Ptr->SpecificFlag == 0) { + if (Ptr->AddrLen) { + Node = CreateResourceNode ( + PciDev, + Ptr->AddrLen, + Ptr->AddrRangeMax, + DummyBarIndex, + PciBarTypeMem64, + PciResUsagePadding + ); + InsertResourceNode ( + Mem64Node, + Node + ); + } + + Ptr++; + continue; + } + } + } + + Ptr++; + } + + return EFI_SUCCESS; +} + +// +// Light PCI bus driver woundn't support hotplug root device +// So no need to pad resource for them +// +VOID +GetResourcePaddingPpb ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + Get resource. + +Arguments: + + PciIoDevice A pointer to a pci device. + +Returns: + + None + +--*/ +{ + if (gPciHotPlugInit) { + if (PciIoDevice->ResourcePaddingDescriptors == NULL) { + GetResourcePaddingForHpb (PciIoDevice); + } + } +} diff --git a/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciResourceSupport.h b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciResourceSupport.h new file mode 100644 index 0000000000..61ec29f7ec --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciResourceSupport.h @@ -0,0 +1,740 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PciResourceSupport.h + +Abstract: + + + +Revision History + +--*/ + +#ifndef _EFI_PCI_RESOURCE_SUPPORT_H +#define _EFI_PCI_RESOURCE_SUPPORT_H + +#define RESERVED_RESOURCE_SIGNATURE EFI_SIGNATURE_32 ('r', 's', 'v', 'd') + +typedef struct { + UINT64 Base; + UINT64 Length; + PCI_BAR_TYPE ResType; +} PCI_RESERVED_RESOURCE_NODE; + +typedef struct { + UINT32 Signature; + LIST_ENTRY Link; + PCI_RESERVED_RESOURCE_NODE Node; +} PCI_RESERVED_RESOURCE_LIST; + +#define RESOURCED_LIST_FROM_NODE(a) \ + CR (a, PCI_RESERVED_RESOURCE_LIST, Node, RESERVED_RESOURCE_SIGNATURE) + +#define RESOURCED_LIST_FROM_LINK(a) \ + CR (a, PCI_RESERVED_RESOURCE_LIST, Link, RESERVED_RESOURCE_SIGNATURE) + +typedef enum { + PciResUsageTypical = 0, + PciResUsagePadding, + PciResUsageOptionRomProcessing +} PCI_RESOURCE_USAGE; + +#define PCI_RESOURCE_SIGNATURE EFI_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; +} PCI_RESOURCE_NODE; + +#define RESOURCE_NODE_FROM_LINK(a) \ + CR (a, PCI_RESOURCE_NODE, Link, PCI_RESOURCE_SIGNATURE) + +EFI_STATUS +SkipVGAAperture ( + OUT UINT64 *Start, + IN UINT64 Length + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Start - TODO: add argument description + Length - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +SkipIsaAliasAperture ( + OUT UINT64 *Start, + IN UINT64 Length + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Start - TODO: add argument description + Length - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +InsertResourceNode ( + PCI_RESOURCE_NODE *Bridge, + PCI_RESOURCE_NODE *ResNode + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Bridge - TODO: add argument description + ResNode - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +MergeResourceTree ( + PCI_RESOURCE_NODE *Dst, + PCI_RESOURCE_NODE *Res, + BOOLEAN TypeMerge + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Dst - TODO: add argument description + Res - TODO: add argument description + TypeMerge - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +CalculateApertureIo16 ( + IN PCI_RESOURCE_NODE *Bridge + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Bridge - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +CalculateResourceAperture ( + IN PCI_RESOURCE_NODE *Bridge + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Bridge - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +GetResourceFromDevice ( + PCI_IO_DEVICE *PciDev, + PCI_RESOURCE_NODE *IoNode, + PCI_RESOURCE_NODE *Mem32Node, + PCI_RESOURCE_NODE *PMem32Node, + PCI_RESOURCE_NODE *Mem64Node, + PCI_RESOURCE_NODE *PMem64Node + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciDev - TODO: add argument description + IoNode - TODO: add argument description + Mem32Node - TODO: add argument description + PMem32Node - TODO: add argument description + Mem64Node - TODO: add argument description + PMem64Node - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +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 + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciDev - TODO: add argument description + Length - TODO: add argument description + Alignment - TODO: add argument description + Bar - TODO: add argument description + ResType - TODO: add argument description + ResUsage - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +CreateResourceMap ( + 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 + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Bridge - TODO: add argument description + IoNode - TODO: add argument description + Mem32Node - TODO: add argument description + PMem32Node - TODO: add argument description + Mem64Node - TODO: add argument description + PMem64Node - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +ResourcePaddingPolicy ( + PCI_IO_DEVICE *PciDev, + PCI_RESOURCE_NODE *IoNode, + PCI_RESOURCE_NODE *Mem32Node, + PCI_RESOURCE_NODE *PMem32Node, + PCI_RESOURCE_NODE *Mem64Node, + PCI_RESOURCE_NODE *PMem64Node + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciDev - TODO: add argument description + IoNode - TODO: add argument description + Mem32Node - TODO: add argument description + PMem32Node - TODO: add argument description + Mem64Node - TODO: add argument description + PMem64Node - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +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 + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Bridge - TODO: add argument description + Mem32Node - TODO: add argument description + PMem32Node - TODO: add argument description + Mem64Node - TODO: add argument description + PMem64Node - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +BridgeSupportResourceDecode ( + IN PCI_IO_DEVICE *Bridge, + IN UINT32 Decode + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Bridge - TODO: add argument description + Decode - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +ProgramResource ( + IN UINT64 Base, + IN PCI_RESOURCE_NODE *Bridge + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Base - TODO: add argument description + Bridge - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +ProgramBar ( + IN UINT64 Base, + IN PCI_RESOURCE_NODE *Node + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Base - TODO: add argument description + Node - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +ProgramPpbApperture ( + IN UINT64 Base, + IN PCI_RESOURCE_NODE *Node + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Base - TODO: add argument description + Node - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +ProgrameUpstreamBridgeForRom ( + IN PCI_IO_DEVICE *PciDevice, + IN UINT32 OptionRomBase, + IN BOOLEAN Enable + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciDevice - TODO: add argument description + OptionRomBase - TODO: add argument description + Enable - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +ResourceRequestExisted ( + IN PCI_RESOURCE_NODE *Bridge + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Bridge - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +InitializeResourcePool ( + PCI_RESOURCE_NODE *ResourcePool, + PCI_BAR_TYPE ResourceType + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ResourcePool - TODO: add argument description + ResourceType - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +GetResourceMap ( + PCI_IO_DEVICE *PciDev, + 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 + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciDev - TODO: add argument description + IoBridge - TODO: add argument description + Mem32Bridge - TODO: add argument description + PMem32Bridge - TODO: add argument description + Mem64Bridge - TODO: add argument description + PMem64Bridge - TODO: add argument description + IoPool - TODO: add argument description + Mem32Pool - TODO: add argument description + PMem32Pool - TODO: add argument description + Mem64Pool - TODO: add argument description + PMem64Pool - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +DestroyResourceTree ( + IN PCI_RESOURCE_NODE *Bridge + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Bridge - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +RecordReservedResource ( + IN UINT64 Base, + IN UINT64 Length, + IN PCI_BAR_TYPE ResType, + IN PCI_IO_DEVICE *Bridge + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Base - TODO: add argument description + Length - TODO: add argument description + ResType - TODO: add argument description + Bridge - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +ResourcePaddingForCardBusBridge ( + PCI_IO_DEVICE *PciDev, + PCI_RESOURCE_NODE *IoNode, + PCI_RESOURCE_NODE *Mem32Node, + PCI_RESOURCE_NODE *PMem32Node, + PCI_RESOURCE_NODE *Mem64Node, + PCI_RESOURCE_NODE *PMem64Node + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciDev - TODO: add argument description + IoNode - TODO: add argument description + Mem32Node - TODO: add argument description + PMem32Node - TODO: add argument description + Mem64Node - TODO: add argument description + PMem64Node - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +ProgramP2C ( + IN UINT64 Base, + IN PCI_RESOURCE_NODE *Node + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Base - TODO: add argument description + Node - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +ApplyResourcePadding ( + PCI_IO_DEVICE *PciDev, + PCI_RESOURCE_NODE *IoNode, + PCI_RESOURCE_NODE *Mem32Node, + PCI_RESOURCE_NODE *PMem32Node, + PCI_RESOURCE_NODE *Mem64Node, + PCI_RESOURCE_NODE *PMem64Node + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciDev - TODO: add argument description + IoNode - TODO: add argument description + Mem32Node - TODO: add argument description + PMem32Node - TODO: add argument description + Mem64Node - TODO: add argument description + PMem64Node - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +VOID +GetResourcePaddingPpb ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +ResetAllPpbBusReg ( + IN PCI_IO_DEVICE *Bridge, + IN UINT8 StartBusNumber + ) +/*++ + +Routine Description: + + Reset bus register + +Arguments: + + Bridge - a pointer to the PCI_IO_DEVICE + StartBusNumber - the number of bus + +Returns: + + None + +--*/ +; + +#endif diff --git a/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciRomTable.c b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciRomTable.c new file mode 100644 index 0000000000..a1e16a0eea --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciRomTable.c @@ -0,0 +1,457 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PciRomTable.c + +Abstract: + + Option Rom Support for PCI Bus Driver + +Revision History + +--*/ + +#include "pcibus.h" +#include "PciRomTable.h" + +typedef struct { + EFI_HANDLE ImageHandle; + UINTN Seg; + UINT8 Bus; + UINT8 Dev; + UINT8 Func; + UINT64 RomAddress; + UINT64 RomLength; +} EFI_PCI_ROM_IMAGE_MAPPING; + +static UINTN mNumberOfPciRomImages = 0; +static UINTN mMaxNumberOfPciRomImages = 0; +static EFI_PCI_ROM_IMAGE_MAPPING *mRomImageTable = NULL; + +VOID +PciRomAddImageMapping ( + IN EFI_HANDLE ImageHandle, + IN UINTN Seg, + IN UINT8 Bus, + IN UINT8 Dev, + IN UINT8 Func, + IN UINT64 RomAddress, + IN UINT64 RomLength + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ImageHandle - TODO: add argument description + Seg - TODO: add argument description + Bus - TODO: add argument description + Dev - TODO: add argument description + Func - TODO: add argument description + RomAddress - TODO: add argument description + RomLength - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + EFI_PCI_ROM_IMAGE_MAPPING *TempMapping; + + if (mNumberOfPciRomImages >= mMaxNumberOfPciRomImages) { + + mMaxNumberOfPciRomImages += 0x20; + + TempMapping = NULL; + TempMapping = AllocatePool (mMaxNumberOfPciRomImages * sizeof (EFI_PCI_ROM_IMAGE_MAPPING)); + if (TempMapping == NULL) { + return ; + } + + CopyMem (TempMapping, mRomImageTable, mNumberOfPciRomImages * sizeof (EFI_PCI_ROM_IMAGE_MAPPING)); + + if (mRomImageTable != NULL) { + gBS->FreePool (mRomImageTable); + } + + mRomImageTable = TempMapping; + } + + mRomImageTable[mNumberOfPciRomImages].ImageHandle = ImageHandle; + mRomImageTable[mNumberOfPciRomImages].Seg = Seg; + mRomImageTable[mNumberOfPciRomImages].Bus = Bus; + mRomImageTable[mNumberOfPciRomImages].Dev = Dev; + mRomImageTable[mNumberOfPciRomImages].Func = Func; + mRomImageTable[mNumberOfPciRomImages].RomAddress = RomAddress; + mRomImageTable[mNumberOfPciRomImages].RomLength = RomLength; + mNumberOfPciRomImages++; +} + +VOID +HexToString ( + CHAR16 *String, + UINTN Value, + UINTN Digits + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + String - TODO: add argument description + Value - TODO: add argument description + Digits - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + for (; Digits > 0; Digits--, String++) { + *String = (CHAR16) ((Value >> (4 * (Digits - 1))) & 0x0f); + if (*String > 9) { + (*String) += ('A' - 10); + } else { + (*String) += '0'; + } + } +} +EFI_STATUS +PciRomLoadEfiDriversFromRomImage ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_PCI_OPTION_ROM_DESCRIPTOR *PciOptionRomDescriptor + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +// TODO: This - add argument and description to function comment +// TODO: PciOptionRomDescriptor - add argument and description to function comment +{ + VOID *RomBar; + UINTN RomSize; + CHAR16 *FileName; + EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader; + PCI_DATA_STRUCTURE *Pcir; + UINTN ImageIndex; + UINTN RomBarOffset; + UINT32 ImageSize; + UINT16 ImageOffset; + EFI_HANDLE ImageHandle; + EFI_STATUS Status; + EFI_STATUS retStatus; + EFI_DEVICE_PATH_PROTOCOL *FilePath; + BOOLEAN SkipImage; + UINT32 DestinationSize; + UINT32 ScratchSize; + UINT8 *Scratch; + VOID *ImageBuffer; + VOID *DecompressedImageBuffer; + UINT32 ImageLength; + EFI_DECOMPRESS_PROTOCOL *Decompress; + + RomBar = (VOID *) (UINTN) PciOptionRomDescriptor->RomAddress; + RomSize = (UINTN) PciOptionRomDescriptor->RomLength; + FileName = L"PciRom Seg=00000000 Bus=00 Dev=00 Func=00 Image=0000"; + + HexToString (&FileName[11], PciOptionRomDescriptor->Seg, 8); + HexToString (&FileName[24], PciOptionRomDescriptor->Bus, 2); + HexToString (&FileName[31], PciOptionRomDescriptor->Dev, 2); + HexToString (&FileName[39], PciOptionRomDescriptor->Func, 2); + + ImageIndex = 0; + retStatus = EFI_NOT_FOUND; + RomBarOffset = (UINTN) RomBar; + + do { + + EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) (UINTN) RomBarOffset; + + if (EfiRomHeader->Signature != 0xaa55) { + return retStatus; + } + + Pcir = (PCI_DATA_STRUCTURE *) (UINTN) (RomBarOffset + EfiRomHeader->PcirOffset); + ImageSize = Pcir->ImageLength * 512; + + if ((Pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) && + (EfiRomHeader->EfiSignature == EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE) ) { + + if ((EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) || + (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) ) { + + ImageOffset = EfiRomHeader->EfiImageHeaderOffset; + ImageSize = EfiRomHeader->InitializationSize * 512; + + ImageBuffer = (VOID *) (UINTN) (RomBarOffset + ImageOffset); + ImageLength = ImageSize - ImageOffset; + DecompressedImageBuffer = NULL; + + // + // decompress here if needed + // + SkipImage = FALSE; + if (EfiRomHeader->CompressionType > EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) { + SkipImage = TRUE; + } + + if (EfiRomHeader->CompressionType == EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) { + Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **) &Decompress); + if (EFI_ERROR (Status)) { + SkipImage = TRUE; + } else { + SkipImage = TRUE; + Status = Decompress->GetInfo ( + Decompress, + ImageBuffer, + ImageLength, + &DestinationSize, + &ScratchSize + ); + if (!EFI_ERROR (Status)) { + DecompressedImageBuffer = NULL; + DecompressedImageBuffer = AllocatePool (DestinationSize); + if (DecompressedImageBuffer != NULL) { + Scratch = AllocatePool (ScratchSize); + if (Scratch != NULL) { + Status = Decompress->Decompress ( + Decompress, + ImageBuffer, + ImageLength, + DecompressedImageBuffer, + DestinationSize, + Scratch, + ScratchSize + ); + if (!EFI_ERROR (Status)) { + ImageBuffer = DecompressedImageBuffer; + ImageLength = DestinationSize; + SkipImage = FALSE; + } + + gBS->FreePool (Scratch); + } + } + } + } + } + + if (!SkipImage) { + + // + // load image and start image + // + + HexToString (&FileName[48], ImageIndex, 4); + FilePath = FileDevicePath (NULL, FileName); + + Status = gBS->LoadImage ( + FALSE, + This->ImageHandle, + FilePath, + ImageBuffer, + ImageLength, + &ImageHandle + ); + if (!EFI_ERROR (Status)) { + Status = gBS->StartImage (ImageHandle, NULL, NULL); + if (!EFI_ERROR (Status)) { + PciRomAddImageMapping ( + ImageHandle, + PciOptionRomDescriptor->Seg, + PciOptionRomDescriptor->Bus, + PciOptionRomDescriptor->Dev, + PciOptionRomDescriptor->Func, + PciOptionRomDescriptor->RomAddress, + PciOptionRomDescriptor->RomLength + ); + retStatus = Status; + } + } + } + + if (DecompressedImageBuffer != NULL) { + gBS->FreePool (DecompressedImageBuffer); + } + + } + } + + RomBarOffset = RomBarOffset + ImageSize; + ImageIndex++; + } while (((Pcir->Indicator & 0x80) == 0x00) && ((RomBarOffset - (UINTN) RomBar) < RomSize)); + + return retStatus; +} + +EFI_STATUS +PciRomLoadEfiDriversFromOptionRomTable ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +// TODO: This - add argument and description to function comment +// TODO: PciRootBridgeIo - add argument and description to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +{ + EFI_STATUS Status; + EFI_PCI_OPTION_ROM_TABLE *PciOptionRomTable; + EFI_PCI_OPTION_ROM_DESCRIPTOR *PciOptionRomDescriptor; + UINTN Index; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors; + UINT16 MinBus; + UINT16 MaxBus; + + Status = EfiGetSystemConfigurationTable (&gEfiPciOptionRomTableGuid, (VOID **) &PciOptionRomTable); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + Status = EFI_NOT_FOUND; + + for (Index = 0; Index < PciOptionRomTable->PciOptionRomCount; Index++) { + PciOptionRomDescriptor = &PciOptionRomTable->PciOptionRomDescriptors[Index]; + if (!PciOptionRomDescriptor->DontLoadEfiRom) { + if (PciOptionRomDescriptor->Seg == PciRootBridgeIo->SegmentNumber) { + Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors); + if (EFI_ERROR (Status)) { + return Status; + } + + PciGetBusRange (&Descriptors, &MinBus, &MaxBus, NULL); + if ((MinBus <= PciOptionRomDescriptor->Bus) && (PciOptionRomDescriptor->Bus <= MaxBus)) { + Status = PciRomLoadEfiDriversFromRomImage (This, PciOptionRomDescriptor); + PciOptionRomDescriptor->DontLoadEfiRom |= 2; + } + } + } + } + + return Status; +} + +EFI_STATUS +PciRomGetRomResourceFromPciOptionRomTable ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, + PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +// TODO: This - add argument and description to function comment +// TODO: PciRootBridgeIo - add argument and description to function comment +// TODO: PciIoDevice - add argument and description to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + EFI_PCI_OPTION_ROM_TABLE *PciOptionRomTable; + EFI_PCI_OPTION_ROM_DESCRIPTOR *PciOptionRomDescriptor; + UINTN Index; + + Status = EfiGetSystemConfigurationTable (&gEfiPciOptionRomTableGuid, (VOID **) &PciOptionRomTable); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + for (Index = 0; Index < PciOptionRomTable->PciOptionRomCount; Index++) { + PciOptionRomDescriptor = &PciOptionRomTable->PciOptionRomDescriptors[Index]; + if (PciOptionRomDescriptor->Seg == PciRootBridgeIo->SegmentNumber && + PciOptionRomDescriptor->Bus == PciIoDevice->BusNumber && + PciOptionRomDescriptor->Dev == PciIoDevice->DeviceNumber && + PciOptionRomDescriptor->Func == PciIoDevice->FunctionNumber ) { + + PciIoDevice->PciIo.RomImage = (VOID *) (UINTN) PciOptionRomDescriptor->RomAddress; + PciIoDevice->PciIo.RomSize = (UINTN) PciOptionRomDescriptor->RomLength; + } + } + + 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 ) { + + AddDriver (PciIoDevice, mRomImageTable[Index].ImageHandle); + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +PciRomGetImageMapping ( + PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +// TODO: PciIoDevice - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + 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); + } else { + PciIoDevice->PciIo.RomImage = (VOID *) (UINTN) mRomImageTable[Index].RomAddress; + PciIoDevice->PciIo.RomSize = (UINTN) mRomImageTable[Index].RomLength; + } + } + } + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciRomTable.h b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciRomTable.h new file mode 100644 index 0000000000..bb20c70156 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/PciRomTable.h @@ -0,0 +1,107 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PciRomTable.h + +Abstract: + + Option Rom Support for PCI Bus Driver + +Revision History + +--*/ + +#ifndef _EFI_PCI_ROM_TABLE_H +#define _EFI_PCI_ROM_TABLE_H + +VOID +PciRomAddImageMapping ( + IN EFI_HANDLE ImageHandle, + IN UINTN Seg, + IN UINT8 Bus, + IN UINT8 Dev, + IN UINT8 Func, + IN UINT64 RomAddress, + IN UINT64 RomLength + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ImageHandle - TODO: add argument description + Seg - TODO: add argument description + Bus - TODO: add argument description + Dev - TODO: add argument description + Func - TODO: add argument description + RomAddress - TODO: add argument description + RomLength - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + + +EFI_STATUS +PciRomGetRomResourceFromPciOptionRomTable ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, + PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + PciRootBridgeIo - TODO: add argument description + PciIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +PciRomGetImageMapping ( + PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/EdkModulePkg/Bus/Pci/PciBus/Dxe/build.xml b/EdkModulePkg/Bus/Pci/PciBus/Dxe/build.xml new file mode 100644 index 0000000000..ee051c7231 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/build.xml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Bus/Pci/PciBus/Dxe/pcibus.c b/EdkModulePkg/Bus/Pci/PciBus/Dxe/pcibus.c new file mode 100644 index 0000000000..16a33010e4 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/pcibus.c @@ -0,0 +1,375 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PciBus.c + +Abstract: + + PCI Bus Driver + +Revision History + +--*/ + +#include "PciBus.h" + +// +// PCI Bus Support Function Prototypes +// + +EFI_STATUS +EFIAPI +PciBusEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +EFI_STATUS +EFIAPI +PciBusDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +PciBusDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +PciBusDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +// +// PCI Bus Driver Global Variables +// + +EFI_DRIVER_BINDING_PROTOCOL gPciBusDriverBinding = { + PciBusDriverBindingSupported, + PciBusDriverBindingStart, + PciBusDriverBindingStop, + 0x10, + NULL, + NULL +}; + +EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL *gEfiIncompatiblePciDeviceSupport = NULL; +EFI_HANDLE gPciHostBrigeHandles[PCI_MAX_HOST_BRIDGE_NUM]; +UINTN gPciHostBridgeNumber; +BOOLEAN gFullEnumeration; +UINT64 gAllOne = 0xFFFFFFFFFFFFFFFFULL; +UINT64 gAllZero = 0; + +EFI_PCI_PLATFORM_PROTOCOL *gPciPlatformProtocol; + +// +// PCI Bus Driver Support Functions +// +EFI_STATUS +EFIAPI +PciBusEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Initialize the global variables + publish the driver binding protocol + +Arguments: + + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + +Returns: + + EFI_SUCCESS + EFI_DEVICE_ERROR + +--*/ +// TODO: ImageHandle - add argument and description to function comment +// TODO: SystemTable - add argument and description to function comment +{ + EFI_STATUS Status; + + InitializePciDevicePool (); + + gFullEnumeration = TRUE; + + gPciHostBridgeNumber = 0; + + InstallHotPlugRequestProtocol (&Status); + return Status; +} + +EFI_STATUS +EFIAPI +PciBusDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + Check to see if pci bus driver supports the given controller + +Arguments: + + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + +Returns: + + EFI_SUCCESS + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Controller - add argument and description to function comment +// TODO: RemainingDevicePath - add argument and description to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; + EFI_DEV_PATH_PTR Node; + + if (RemainingDevicePath != NULL) { + 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; + } + } + // + // Open the IO Abstraction(s) 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; + } + + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + 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; + } + + gBS->CloseProtocol ( + Controller, + &gEfiPciRootBridgeIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PciBusDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + Start to management the controller passed in + +Arguments: + + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + +Returns: + + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Controller - add argument and description to function comment +// TODO: RemainingDevicePath - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + + Status = gBS->LocateProtocol ( + &gEfiIncompatiblePciDeviceSupportProtocolGuid, + NULL, + (VOID **) &gEfiIncompatiblePciDeviceSupport + ); + + // + // 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 + ); + + gFullEnumeration = (BOOLEAN) ((SearchHostBridgeHandle (Controller) ? FALSE : TRUE)); + + // + // Enumerate the entire host bridge + // After enumeration, a database that records all the device information will be created + // + // + Status = PciEnumerator (Controller); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Enable PCI device specified by remaining device path. BDS or other driver can call the + // start more than once. + // + + StartPciDevices (Controller, RemainingDevicePath); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PciBusDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + +Routine Description: + + Stop one or more children created at start of pci bus driver + if all the the children get closed, close the protocol + +Arguments: + + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + +Returns: + + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Controller - add argument and description to function comment +// TODO: NumberOfChildren - add argument and description to function comment +// TODO: ChildHandleBuffer - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + 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/EdkModulePkg/Bus/Pci/PciBus/Dxe/pcibus.h b/EdkModulePkg/Bus/Pci/PciBus/Dxe/pcibus.h new file mode 100644 index 0000000000..170a4e278a --- /dev/null +++ b/EdkModulePkg/Bus/Pci/PciBus/Dxe/pcibus.h @@ -0,0 +1,243 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PciBus.h + +Abstract: + + PCI Bus Driver + +Revision History + +--*/ + +#ifndef _EFI_PCI_BUS_H +#define _EFI_PCI_BUS_H + + +#include +#include +#include "ComponentName.h" + +// +// Driver Produced Protocol Prototypes +// + +#define VGABASE1 0x3B0 +#define VGALIMIT1 0x3BB + +#define VGABASE2 0x3C0 +#define VGALIMIT2 0x3DF + +#define ISABASE 0x100 +#define ISALIMIT 0x3FF + +typedef enum { + PciBarTypeUnknown = 0, + PciBarTypeIo16, + PciBarTypeIo32, + PciBarTypeMem32, + PciBarTypePMem32, + PciBarTypeMem64, + PciBarTypePMem64, + PciBarTypeIo, + PciBarTypeMem, + PciBarTypeMaxType +} PCI_BAR_TYPE; + +typedef struct { + UINT64 BaseAddress; + UINT64 Length; + UINT64 Alignment; + PCI_BAR_TYPE BarType; + BOOLEAN Prefetchable; + UINT8 MemType; + UINT8 Offset; +} PCI_BAR; + +#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 PCI_IO_DEVICE_SIGNATURE EFI_SIGNATURE_32 ('p', 'c', 'i', 'o') + +#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 resource status constant +// +#define EFI_RESOURCE_NONEXISTENT 0xFFFFFFFFFFFFFFFFULL +#define EFI_RESOURCE_LESS 0xFFFFFFFFFFFFFFFEULL +#define EFI_RESOURCE_SATISFIED 0x0000000000000000ULL + +// +// Define option for attribute +// +#define EFI_SET_SUPPORTS 0 +#define EFI_SET_ATTRIBUTES 1 + +typedef 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; + + // + // 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 + // + struct _PCI_IO_DEVICE *Parent; + + // + // A linked list for children Pci Device if it is bridge device + // + LIST_ENTRY ChildList; + + // + // TURE 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; + + // + // The OptionRom Size + // + UINT64 RomSize; + + // + // The OptionRom Size + // + UINT64 RomBase; + + // + // 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; + + BOOLEAN IsPciExp; + +} PCI_IO_DEVICE; + + +#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) + +// +// Global Variables +// +extern EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL *gEfiIncompatiblePciDeviceSupport; +extern EFI_DRIVER_BINDING_PROTOCOL gPciBusDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gPciBusComponentName; +extern LIST_ENTRY gPciDevicePool; +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; + +#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" + +#endif diff --git a/EdkModulePkg/Bus/Pci/Uhci/Dxe/ComponentName.c b/EdkModulePkg/Bus/Pci/Uhci/Dxe/ComponentName.c new file mode 100644 index 0000000000..71d9339a8f --- /dev/null +++ b/EdkModulePkg/Bus/Pci/Uhci/Dxe/ComponentName.c @@ -0,0 +1,189 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ComponentName.c + +Abstract: + +--*/ + +#include "uhci.h" + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +UhciComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +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 Component Name Protocol +// +EFI_COMPONENT_NAME_PROTOCOL gUhciComponentName = { + UhciComponentNameGetDriverName, + UhciComponentNameGetControllerName, + "eng" +}; + +static EFI_UNICODE_STRING_TABLE mUhciDriverNameTable[] = { + { "eng", (CHAR16 *) L"Usb Uhci Driver" }, + { NULL , NULL } +}; + +EFI_STATUS +EFIAPI +UhciComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gUhciComponentName.SupportedLanguages, + mUhciDriverNameTable, + DriverName + ); +} + +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 + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + 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. + 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. + + Returns: + 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. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + EFI_STATUS Status; + USB_HC_DEV *UhciDev; + EFI_USB_HC_PROTOCOL *UsbHc; + + // + // This is a device driver, so ChildHandle must be NULL. + // + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + // + // Get the device context + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsbHcProtocolGuid, + (VOID **) &UsbHc, + gUhciDriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + UhciDev = USB_HC_DEV_FROM_THIS (UsbHc); + + return LookupUnicodeString ( + Language, + gUhciComponentName.SupportedLanguages, + UhciDev->ControllerNameTable, + ControllerName + ); + +} diff --git a/EdkModulePkg/Bus/Pci/Uhci/Dxe/Uhci.mbd b/EdkModulePkg/Bus/Pci/Uhci/Dxe/Uhci.mbd new file mode 100644 index 0000000000..76d35e7455 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/Uhci/Dxe/Uhci.mbd @@ -0,0 +1,42 @@ + + + + + Uhci + 2FB92EFA-2EE0-4bae-9EB6-7464125E1EF7 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:18 + + + UefiBootServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + EdkDxePrintLib + BaseLib + DxeMemoryAllocationLib + + diff --git a/EdkModulePkg/Bus/Pci/Uhci/Dxe/Uhci.msa b/EdkModulePkg/Bus/Pci/Uhci/Dxe/Uhci.msa new file mode 100644 index 0000000000..9e91154fc0 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/Uhci/Dxe/Uhci.msa @@ -0,0 +1,66 @@ + + + + + Uhci + UEFI_DRIVER + BS_DRIVER + 2FB92EFA-2EE0-4bae-9EB6-7464125E1EF7 + 0 + Component description file for Uhci module + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:18 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + BaseLib + UefiLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + + + uhci.c + uhchlp.c + ComponentName.c + uhci.h + + + MdePkg + + + PciIo + UsbHc + + + + + + + gUhciDriverBinding + gUhciComponentName + + + diff --git a/EdkModulePkg/Bus/Pci/Uhci/Dxe/build.xml b/EdkModulePkg/Bus/Pci/Uhci/Dxe/build.xml new file mode 100644 index 0000000000..37bb3c32e6 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/Uhci/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Bus/Pci/Uhci/Dxe/uhchlp.c b/EdkModulePkg/Bus/Pci/Uhci/Dxe/uhchlp.c new file mode 100644 index 0000000000..62d58eed78 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/Uhci/Dxe/uhchlp.c @@ -0,0 +1,4237 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + UhcHlp.c + +Abstract: + + +Revision History +--*/ + +#include "uhci.h" + +EFI_STATUS +USBReadPortW ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 PortOffset, + IN OUT UINT16 *Data + ) +/*++ + +Routine Description: + + USBReadPort Word + +Arguments: + + PciIo - EFI_PCI_IO_PROTOCOL + PortOffset - Port offset + Data - Data to reutrn + +Returns: + + EFI_SUCCESS + +--*/ +{ + // + // Perform 16bit Read in PCI IO Space + // + return PciIo->Io.Read ( + PciIo, + EfiPciIoWidthUint16, + USB_BAR_INDEX, + (UINT64) PortOffset, + 1, + Data + ); +} + +EFI_STATUS +USBReadPortDW ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 PortOffset, + IN OUT UINT32 *Data + ) +/*++ + +Routine Description: + + USBReadPort DWord + +Arguments: + + PciIo - EFI_PCI_IO_PROTOCOL + PortOffset - Port offset + Data - Data to reutrn + +Returns: + + EFI_SUCCESS + +--*/ +{ + // + // Perform 32bit Read in PCI IO Space + // + return PciIo->Io.Read ( + PciIo, + EfiPciIoWidthUint32, + USB_BAR_INDEX, + (UINT64) PortOffset, + 1, + Data + ); +} + +EFI_STATUS +USBWritePortW ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 PortOffset, + IN UINT16 Data + ) +/*++ + +Routine Description: + + USB Write Port Word + +Arguments: + + PciIo - EFI_PCI_IO_PROTOCOL + PortOffset - Port offset + Data - Data to write + +Returns: + + EFI_SUCCESS + +--*/ +{ + // + // Perform 16bit Write in PCI IO Space + // + return PciIo->Io.Write ( + PciIo, + EfiPciIoWidthUint16, + USB_BAR_INDEX, + (UINT64) PortOffset, + 1, + &Data + ); +} + +EFI_STATUS +USBWritePortDW ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 PortOffset, + IN UINT32 Data + ) +/*++ + +Routine Description: + + USB Write Port DWord + +Arguments: + + PciIo - EFI_PCI_IO_PROTOCOL + PortOffset - Port offset + Data - Data to write + +Returns: + + EFI_SUCCESS + +--*/ +{ + // + // Perform 32bit Write in PCI IO Space + // + return PciIo->Io.Write ( + PciIo, + EfiPciIoWidthUint32, + USB_BAR_INDEX, + (UINT64) PortOffset, + 1, + &Data + ); +} +// +// USB register-base helper functions +// +EFI_STATUS +WriteUHCCommandReg ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 CmdAddrOffset, + IN UINT16 UsbCmd + ) +/*++ + +Routine Description: + + Write UHCI Command Register + +Arguments: + + PciIo - EFI_PCI_IO_PROTOCOL + CmdAddrOffset - Command address offset + UsbCmd - Data to write + +Returns: + + EFI_SUCCESS + +--*/ +{ + // + // Write to UHC's Command Register + // + return USBWritePortW (PciIo, CmdAddrOffset, UsbCmd); +} + +EFI_STATUS +ReadUHCCommandReg ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 CmdAddrOffset, + IN OUT UINT16 *Data + ) +/*++ + +Routine Description: + + Read UHCI Command Register + +Arguments: + + PciIo - EFI_PCI_IO_PROTOCOL + CmdAddrOffset - Command address offset + Data - Data to return + +Returns: + + EFI_SUCCESS + +--*/ +{ + // + // Read from UHC's Command Register + // + return USBReadPortW (PciIo, CmdAddrOffset, Data); +} + +EFI_STATUS +WriteUHCStatusReg ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 StatusAddrOffset, + IN UINT16 UsbSts + ) +/*++ + +Routine Description: + + Write UHCI Staus Register + +Arguments: + + PciIo - EFI_PCI_IO_PROTOCOL + StatusAddrOffset - Status address offset + UsbSts - Data to write + +Returns: + + EFI_SUCCESS + +--*/ +{ + // + // Write to UHC's Status Register + // + return USBWritePortW (PciIo, StatusAddrOffset, UsbSts); +} + +EFI_STATUS +ReadUHCStatusReg ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 StatusAddrOffset, + IN OUT UINT16 *Data + ) +/*++ + +Routine Description: + + Read UHCI Staus Register + +Arguments: + + PciIo - EFI_PCI_IO_PROTOCOL + StatusAddrOffset - Status address offset + UsbSts - Data to return + +Returns: + + EFI_SUCCESS + +--*/ +{ + // + // Read from UHC's Status Register + // + return USBReadPortW (PciIo, StatusAddrOffset, Data); +} + + +EFI_STATUS +ClearStatusReg ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 StatusAddrOffset + ) +/*++ + +Routine Description: + + Clear the content of UHC's Status Register + +Arguments: + + PciIo - EFI_PCI_IO_PROTOCOL + StatusAddrOffset - Status address offset + +Returns: + + EFI_SUCCESS + +--*/ +{ + + return WriteUHCStatusReg (PciIo, StatusAddrOffset, 0x003F); +} + +EFI_STATUS +ReadUHCFrameNumberReg ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 FrameNumAddrOffset, + IN OUT UINT16 *Data + ) +/*++ + +Routine Description: + + Read from UHC's Frame Number Register + +Arguments: + + PciIo - EFI_PCI_IO_PROTOCOL + FrameNumAddrOffset - Frame number register offset + Data - Data to return +Returns: + + EFI_SUCCESS + +--*/ +{ + + return USBReadPortW (PciIo, FrameNumAddrOffset, Data); +} + +EFI_STATUS +WriteUHCFrameListBaseReg ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 FlBaseAddrOffset, + IN UINT32 UsbFrameListBaseAddr + ) +/*++ + +Routine Description: + + Write to UHC's Frame List Base Register + +Arguments: + + PciIo - EFI_PCI_IO_PROTOCOL + FlBaseAddrOffset - Frame Base address register + UsbFrameListBaseAddr - Address to write + +Returns: + + EFI_SUCCESS + +--*/ +{ + + return USBWritePortDW (PciIo, FlBaseAddrOffset, UsbFrameListBaseAddr); +} + +EFI_STATUS +ReadRootPortReg ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 PortAddrOffset, + IN OUT UINT16 *Data + ) +/*++ + +Routine Description: + + Read from UHC's Root Port Register + +Arguments: + + PciIo - EFI_PCI_IO_PROTOCOL + PortAddrOffset - Port Addrress Offset, + Data - Data to return +Returns: + + EFI_SUCCESS + +--*/ +{ + + return USBReadPortW (PciIo, PortAddrOffset, Data); +} + +EFI_STATUS +WriteRootPortReg ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 PortAddrOffset, + IN UINT16 ControlBits + ) +/*++ + +Routine Description: + + Write to UHC's Root Port Register + +Arguments: + + PciIo - EFI_PCI_IO_PROTOCOL + PortAddrOffset - Port Addrress Offset, + ControlBits - Data to write +Returns: + + EFI_SUCCESS + +--*/ +{ + + return USBWritePortW (PciIo, PortAddrOffset, ControlBits); +} + + + +EFI_STATUS +WaitForUHCHalt ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 StatusRegAddr, + IN UINTN Timeout + ) +/*++ + +Routine Description: + + Wait until UHCI halt or timeout + +Arguments: + + PciIo - EFI_PCI_IO_PROTOCOL + StatusRegAddr - Status Register Address + Timeout - Time out value in us + +Returns: + + EFI_DEVICE_ERROR - Unable to read the status register + EFI_TIMEOUT - Time out + EFI_SUCCESS - Success + +--*/ +{ + UINTN Delay; + EFI_STATUS Status; + UINT16 HcStatus; + + // + // Timeout is in us unit + // + Delay = (Timeout / 50) + 1; + do { + Status = ReadUHCStatusReg (PciIo, StatusRegAddr, &HcStatus); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + if ((HcStatus & USBSTS_HCH) == USBSTS_HCH) { + break; + } + // + // Stall for 50 us + // + gBS->Stall (50); + + } while (Delay--); + + if (Delay == 0) { + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +BOOLEAN +IsStatusOK ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 StatusRegAddr + ) +/*++ + +Routine Description: + + Judge whether the host controller operates well + +Arguments: + + PciIo - EFI_PCI_IO_PROTOCOL + StatusRegAddr - Status register address + +Returns: + + TRUE - Status is good + FALSE - Status is bad + +--*/ +{ + EFI_STATUS Status; + UINT16 HcStatus; + // + // Detect whether the interrupt is caused by fatal error. + // see "UHCI Design Guid". + // + Status = ReadUHCStatusReg (PciIo, StatusRegAddr, &HcStatus); + if (EFI_ERROR (Status)) { + return FALSE; + } + + if (HcStatus & (USBSTS_HCPE | USBSTS_HSE | USBSTS_HCH)) { + return FALSE; + } else { + return TRUE; + } + +} + + +BOOLEAN +IsHostSysOrProcessErr ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 StatusRegAddr + ) +/*++ + +Routine Description: + + Judge the status is HostSys,ProcessErr error or good + +Arguments: + + PciIo - EFI_PCI_IO_PROTOCOL + StatusRegAddr - Status register address + +Returns: + + TRUE - Status is good + FALSE - Status is bad + +--*/ +{ + EFI_STATUS Status; + UINT16 HcStatus; + // + // Detect whether the interrupt is caused by serious error. + // see "UHCI Design Guid". + // + Status = ReadUHCStatusReg (PciIo, StatusRegAddr, &HcStatus); + if (EFI_ERROR (Status)) { + return FALSE; + } + + if (HcStatus & (USBSTS_HSE | USBSTS_HCPE)) { + return TRUE; + } else { + return FALSE; + } +} + + +UINT16 +GetCurrentFrameNumber ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 FrameNumAddrOffset + ) +/*++ + +Routine Description: + + Get Current Frame Number + +Arguments: + + PciIo - EFI_PCI_IO_PROTOCOL + FrameNumAddrOffset - FrameNum register AddrOffset + +Returns: + + Frame number + +--*/ +{ + // + // Gets value in the USB frame number register. + // + UINT16 FrameNumber; + + ReadUHCFrameNumberReg (PciIo, FrameNumAddrOffset, &FrameNumber); + + return (UINT16) (FrameNumber & 0x03FF); +} + +EFI_STATUS +SetFrameListBaseAddress ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 FlBaseAddrReg, + IN UINT32 Addr + ) +/*++ + +Routine Description: + + Set FrameListBase Address + +Arguments: + + PciIo - EFI_PCI_IO_PROTOCOL + FlBaseAddrReg - FrameListBase register + Addr - Address to set + +Returns: + + EFI_SUCCESS + +--*/ +{ + // + // Sets value in the USB Frame List Base Address register. + // + return WriteUHCFrameListBaseReg (PciIo, FlBaseAddrReg, (UINT32) (Addr & 0xFFFFF000)); +} + +VOID +EnableMaxPacketSize ( + IN USB_HC_DEV *HcDev + ) +/*++ + +Routine Description: + + Enable Max Packet Size + +Arguments: + + HcDev - USB_HC_DEV + +Returns: + + VOID + +--*/ +{ + UINT16 CommandContent; + EFI_STATUS Status; + + Status = ReadUHCCommandReg ( + HcDev->PciIo, + (UINT32) (USBCMD), + &CommandContent + ); + + if ((CommandContent & USBCMD_MAXP) != USBCMD_MAXP) { + CommandContent |= USBCMD_MAXP; + WriteUHCCommandReg ( + HcDev->PciIo, + (UINT32) (USBCMD), + CommandContent + ); + } + + return ; +} + +EFI_STATUS +CreateFrameList ( + IN USB_HC_DEV *HcDev, + IN UINT32 FlBaseAddrReg + ) +/*++ + +Routine Description: + + CreateFrameList + +Arguments: + + HcDev - USB_HC_DEV + FlBaseAddrReg - Frame List register + +Returns: + + EFI_OUT_OF_RESOURCES - Can't allocate memory resources + EFI_UNSUPPORTED - Map memory fail + EFI_SUCCESS - Success + +--*/ +{ + EFI_STATUS Status; + VOID *CommonBuffer; + EFI_PHYSICAL_ADDRESS MappedAddress; + VOID *Mapping; + UINTN BufferSizeInPages; + UINTN BufferSizeInBytes; + + // + // 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. + // + BufferSizeInBytes = 4096; + BufferSizeInPages = EFI_SIZE_TO_PAGES (BufferSizeInBytes); + Status = HcDev->PciIo->AllocateBuffer ( + HcDev->PciIo, + AllocateAnyPages, + EfiBootServicesData, + BufferSizeInPages, + &CommonBuffer, + 0 + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + Status = HcDev->PciIo->Map ( + HcDev->PciIo, + EfiPciIoOperationBusMasterCommonBuffer, + CommonBuffer, + &BufferSizeInBytes, + &MappedAddress, + &Mapping + ); + if (EFI_ERROR (Status) || (BufferSizeInBytes != 4096)) { + HcDev->PciIo->FreeBuffer (HcDev->PciIo, BufferSizeInPages, CommonBuffer); + return EFI_UNSUPPORTED; + } + + HcDev->FrameListEntry = (FRAMELIST_ENTRY *) ((UINTN) MappedAddress); + + HcDev->FrameListMapping = Mapping; + + InitFrameList (HcDev); + + // + // Tell the Host Controller where the Frame List lies, + // by set the Frame List Base Address Register. + // + SetFrameListBaseAddress ( + HcDev->PciIo, + FlBaseAddrReg, + (UINT32) ((UINTN) HcDev->FrameListEntry) + ); + + return EFI_SUCCESS; +} + +EFI_STATUS +FreeFrameListEntry ( + IN USB_HC_DEV *HcDev + ) +/*++ + +Routine Description: + + Free FrameList buffer + +Arguments: + + HcDev - USB_HC_DEV + +Returns: + + EFI_SUCCESS - success + +--*/ +{ + // + // Unmap the common buffer for framelist entry, + // and free the common buffer. + // Uhci's frame list occupy 4k memory. + // + HcDev->PciIo->Unmap (HcDev->PciIo, HcDev->FrameListMapping); + HcDev->PciIo->FreeBuffer ( + HcDev->PciIo, + EFI_SIZE_TO_PAGES (4096), + (VOID *) (HcDev->FrameListEntry) + ); + return EFI_SUCCESS; +} + +VOID +InitFrameList ( + IN USB_HC_DEV *HcDev + ) +/*++ + +Routine Description: + + Initialize FrameList + +Arguments: + + HcDev - USB_HC_DEV + +Returns: + VOID + +--*/ +{ + FRAMELIST_ENTRY *FrameListPtr; + UINTN Index; + + // + // Validate each Frame List Entry + // + FrameListPtr = HcDev->FrameListEntry; + for (Index = 0; Index < 1024; Index++) { + FrameListPtr->FrameListPtrTerminate = 1; + FrameListPtr->FrameListPtr = 0; + FrameListPtr->FrameListPtrQSelect = 0; + FrameListPtr->FrameListRsvd = 0; + FrameListPtr++; + } +} +// +// ////////////////////////////////////////////////////////////// +// +// QH TD related Helper Functions +// +//////////////////////////////////////////////////////////////// +// +// functions for QH +// +EFI_STATUS +AllocateQHStruct ( + IN USB_HC_DEV *HcDev, + OUT QH_STRUCT **ppQHStruct + ) +/*++ + +Routine Description: + + Allocate QH Struct + +Arguments: + + HcDev - USB_HC_DEV + ppQHStruct - QH_STRUCT content to return +Returns: + + EFI_SUCCESS + +--*/ +{ + *ppQHStruct = NULL; + + // + // QH must align on 16 bytes alignment, + // since the memory allocated by UhciAllocatePool () + // is aligned on 32 bytes, it is no need to adjust + // the allocated memory returned. + // + return UhciAllocatePool (HcDev, (UINT8 **) ppQHStruct, sizeof (QH_STRUCT)); +} + + +EFI_STATUS +CreateQH ( + IN USB_HC_DEV *HcDev, + OUT QH_STRUCT **pptrQH + ) +/*++ + +Routine Description: + + CreateQH + +Arguments: + + HcDev - USB_HC_DEV + ppQHStruct - QH_STRUCT content to return +Returns: + + EFI_SUCCESS - Success + EFI_OUT_OF_RESOURCES - Can't allocate memory +--*/ +{ + EFI_STATUS Status; + + // + // allocate align memory for QH_STRUCT + // + Status = AllocateQHStruct (HcDev, pptrQH); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + // + // init each field of the QH_STRUCT + // + // + // Make QH ready + // + SetQHHorizontalValidorInvalid (*pptrQH, FALSE); + SetQHVerticalValidorInvalid (*pptrQH, FALSE); + + return EFI_SUCCESS; +} + +VOID +SetQHHorizontalLinkPtr ( + IN QH_STRUCT *PtrQH, + IN VOID *ptrNext + ) +/*++ + +Routine Description: + + Set QH Horizontal Link Pointer + +Arguments: + + PtrQH - QH_STRUCT + ptrNext - Data to write + +Returns: + + VOID + +--*/ +{ + // + // 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->QH.QHHorizontalPtr = (UINT32) ((UINTN) ptrNext >> 4); +} + +VOID * +GetQHHorizontalLinkPtr ( + IN QH_STRUCT *PtrQH + ) +/*++ + +Routine Description: + + Get QH Horizontal Link Pointer + +Arguments: + + PtrQH - QH_STRUCT + + +Returns: + + Data to return + +--*/ +{ + // + // Restore the 28bit address to 32bit address + // (take 32bit address as an example) + // + return (VOID *) ((UINTN) (PtrQH->QH.QHHorizontalPtr << 4)); +} + +VOID +SetQHHorizontalQHorTDSelect ( + IN QH_STRUCT *PtrQH, + IN BOOLEAN bQH + ) +/*++ + +Routine Description: + + Set QH Horizontal QH or TD + +Arguments: + + PtrQH - QH_STRUCT + bQH - TRUE is QH FALSE is TD + +Returns: + VOID + +--*/ +{ + // + // if QH is connected, the specified bit is set, + // if TD is connected, the specified bit is cleared. + // + PtrQH->QH.QHHorizontalQSelect = bQH ? 1 : 0; +} + + +VOID +SetQHHorizontalValidorInvalid ( + IN QH_STRUCT *PtrQH, + IN BOOLEAN bValid + ) +/*++ + +Routine Description: + + Set QH Horizontal Valid or Invalid + +Arguments: + + PtrQH - QH_STRUCT + bValid - TRUE is Valid FALSE is Invalid + +Returns: + VOID + +--*/ +{ + // + // Valid means the horizontal link pointer is valid, + // else, it's invalid. + // + PtrQH->QH.QHHorizontalTerminate = bValid ? 0 : 1; +} + +VOID +SetQHVerticalLinkPtr ( + IN QH_STRUCT *PtrQH, + IN VOID *ptrNext + ) +/*++ + +Routine Description: + + Set QH Vertical Link Pointer + +Arguments: + + PtrQH - QH_STRUCT + ptrNext - Data to write +Returns: + + VOID + +--*/ +{ + // + // 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->QH.QHVerticalPtr = (UINT32) ((UINTN) ptrNext >> 4); +} + +VOID * +GetQHVerticalLinkPtr ( + IN QH_STRUCT *PtrQH + ) +/*++ + +Routine Description: + + Get QH Vertical Link Pointer + +Arguments: + + PtrQH - QH_STRUCT + +Returns: + + Data to return + +--*/ +{ + // + // Restore the 28bit address to 32bit address + // (take 32bit address as an example) + // + return (VOID *) ((UINTN) (PtrQH->QH.QHVerticalPtr << 4)); +} + +VOID +SetQHVerticalQHorTDSelect ( + IN QH_STRUCT *PtrQH, + IN BOOLEAN bQH + ) +/*++ + +Routine Description: + + Set QH Vertical QH or TD + +Arguments: + + PtrQH - QH_STRUCT + bQH - TRUE is QH FALSE is TD + +Returns: + + VOID + +--*/ +{ + // + // 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->QH.QHVerticalQSelect = bQH ? 1 : 0; +} + +BOOLEAN +IsQHHorizontalQHSelect ( + IN QH_STRUCT *PtrQH + ) +/*++ + +Routine Description: + + Is QH Horizontal QH Select + +Arguments: + + PtrQH - QH_STRUCT + +Returns: + + TRUE - QH + FALSE - TD + +--*/ +{ + // + // Retrieve the information about whether the Horizontal Link Pointer + // pointing to a QH or TD. + // + return (BOOLEAN) (PtrQH->QH.QHHorizontalQSelect ? TRUE : FALSE); +} + +VOID +SetQHVerticalValidorInvalid ( + IN QH_STRUCT *PtrQH, + IN BOOLEAN IsValid + ) +/*++ + +Routine Description: + + Set QH Vertical Valid or Invalid + +Arguments: + + PtrQH - QH_STRUCT + IsValid - TRUE is valid FALSE is invalid + +Returns: + + VOID + +--*/ +{ + // + // If TRUE, indicates the Vertical Link Pointer field is valid, + // else, the field is invalid. + // + PtrQH->QH.QHVerticalTerminate = IsValid ? 0 : 1; +} + + +BOOLEAN +GetQHVerticalValidorInvalid ( + IN QH_STRUCT *PtrQH + ) +/*++ + +Routine Description: + + Get QH Vertical Valid or Invalid + +Arguments: + + PtrQH - QH_STRUCT + +Returns: + + TRUE - Valid + FALSE - Invalid + +--*/ +{ + // + // If TRUE, indicates the Vertical Link Pointer field is valid, + // else, the field is invalid. + // + return (BOOLEAN) (!(PtrQH->QH.QHVerticalTerminate)); +} + +BOOLEAN +GetQHHorizontalValidorInvalid ( + IN QH_STRUCT *PtrQH + ) +/*++ + +Routine Description: + + Get QH Horizontal Valid or Invalid + +Arguments: + + PtrQH - QH_STRUCT + +Returns: + + TRUE - Valid + FALSE - Invalid + +--*/ +{ + // + // If TRUE, meaning the Horizontal Link Pointer field is valid, + // else, the field is invalid. + // + return (BOOLEAN) (!(PtrQH->QH.QHHorizontalTerminate)); +} +// +// functions for TD +// +EFI_STATUS +AllocateTDStruct ( + IN USB_HC_DEV *HcDev, + OUT TD_STRUCT **ppTDStruct + ) +/*++ + +Routine Description: + + Allocate TD Struct + +Arguments: + + HcDev - USB_HC_DEV + ppTDStruct - place to store TD_STRUCT pointer +Returns: + + EFI_SUCCESS + +--*/ +{ + *ppTDStruct = NULL; + + // + // TD must align on 16 bytes alignment, + // since the memory allocated by UhciAllocatePool () + // is aligned on 32 bytes, it is no need to adjust + // the allocated memory returned. + // + return UhciAllocatePool ( + HcDev, + (UINT8 **) ppTDStruct, + sizeof (TD_STRUCT) + ); +} + +EFI_STATUS +CreateTD ( + IN USB_HC_DEV *HcDev, + OUT TD_STRUCT **pptrTD + ) +/*++ + +Routine Description: + + Create TD + +Arguments: + + HcDev - USB_HC_DEV + pptrTD - TD_STRUCT pointer to store + +Returns: + + EFI_OUT_OF_RESOURCES - Can't allocate resources + EFI_SUCCESS - Success + +--*/ +{ + EFI_STATUS Status; + // + // create memory for TD_STRUCT, and align the memory. + // + Status = AllocateTDStruct (HcDev, pptrTD); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Make TD ready. + // + SetTDLinkPtrValidorInvalid (*pptrTD, FALSE); + + + return EFI_SUCCESS; +} + +EFI_STATUS +GenSetupStageTD ( + IN USB_HC_DEV *HcDev, + IN UINT8 DevAddr, + IN UINT8 Endpoint, + IN BOOLEAN bSlow, + IN UINT8 *pDevReq, + IN UINT8 RequestLen, + OUT TD_STRUCT **ppTD + ) +/*++ + +Routine Description: + + Generate Setup Stage TD + +Arguments: + + HcDev - USB_HC_DEV + DevAddr - Device address + Endpoint - Endpoint number + bSlow - Full speed or low speed + pDevReq - Device request + RequestLen - Request length + ppTD - TD_STRUCT to return +Returns: + + EFI_OUT_OF_RESOURCES - Can't allocate memory + EFI_SUCCESS - Success + +--*/ +{ + EFI_STATUS Status; + TD_STRUCT *pTDStruct; + + Status = CreateTD (HcDev, &pTDStruct); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + SetTDLinkPtr (pTDStruct, NULL); + + // + // Depth first fashion + // + SetTDLinkPtrDepthorBreadth (pTDStruct, TRUE); + + // + // initialize as the last TD in the QH context, + // this field will be updated in the TD linkage process. + // + SetTDLinkPtrValidorInvalid (pTDStruct, FALSE); + + // + // Disable Short Packet Detection by default + // + EnableorDisableTDShortPacket (pTDStruct, FALSE); + + // + // Max error counter is 3, retry 3 times when error encountered. + // + SetTDControlErrorCounter (pTDStruct, 3); + + // + // set device speed attribute + // (TRUE - Slow Device; FALSE - Full Speed Device) + // + SetTDLoworFullSpeedDevice (pTDStruct, bSlow); + + // + // Non isochronous transfer TD + // + SetTDControlIsochronousorNot (pTDStruct, FALSE); + + // + // Interrupt On Complete bit be set to zero, + // Disable IOC interrupt. + // + SetorClearTDControlIOC (pTDStruct, FALSE); + + // + // Set TD Active bit + // + SetTDStatusActiveorInactive (pTDStruct, TRUE); + + SetTDTokenMaxLength (pTDStruct, RequestLen); + + SetTDTokenDataToggle0 (pTDStruct); + + SetTDTokenEndPoint (pTDStruct, Endpoint); + + SetTDTokenDeviceAddress (pTDStruct, DevAddr); + + SetTDTokenPacketID (pTDStruct, SETUP_PACKET_ID); + + pTDStruct->pTDBuffer = (UINT8 *) pDevReq; + pTDStruct->TDBufferLength = RequestLen; + SetTDDataBuffer (pTDStruct); + + *ppTD = pTDStruct; + + return EFI_SUCCESS; +} + +EFI_STATUS +GenDataTD ( + IN USB_HC_DEV *HcDev, + IN UINT8 DevAddr, + IN UINT8 Endpoint, + IN UINT8 *pData, + IN UINT8 Len, + IN UINT8 PktID, + IN UINT8 Toggle, + IN BOOLEAN bSlow, + OUT TD_STRUCT **ppTD + ) +/*++ + +Routine Description: + + Generate Data Stage TD + +Arguments: + + HcDev - USB_HC_DEV + DevAddr - Device address + Endpoint - Endpoint number + pData - Data buffer + Len - Data length + PktID - Packet ID + Toggle - Data toggle value + bSlow - Full speed or low speed + ppTD - TD_STRUCT to return +Returns: + + EFI_OUT_OF_RESOURCES - Can't allocate memory + EFI_SUCCESS - Success + +--*/ +{ + TD_STRUCT *pTDStruct; + EFI_STATUS Status; + + Status = CreateTD (HcDev, &pTDStruct); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + SetTDLinkPtr (pTDStruct, NULL); + + // + // Depth first fashion + // + SetTDLinkPtrDepthorBreadth (pTDStruct, TRUE); + + // + // Link pointer pointing to TD struct + // + SetTDLinkPtrQHorTDSelect (pTDStruct, FALSE); + + // + // initialize as the last TD in the QH context, + // this field will be updated in the TD linkage process. + // + SetTDLinkPtrValidorInvalid (pTDStruct, FALSE); + + // + // Disable short packet detect + // + EnableorDisableTDShortPacket (pTDStruct, FALSE); + // + // Max error counter is 3 + // + SetTDControlErrorCounter (pTDStruct, 3); + + // + // set device speed attribute + // (TRUE - Slow Device; FALSE - Full Speed Device) + // + SetTDLoworFullSpeedDevice (pTDStruct, bSlow); + + // + // Non isochronous transfer TD + // + SetTDControlIsochronousorNot (pTDStruct, FALSE); + + // + // Disable Interrupt On Complete + // Disable IOC interrupt. + // + SetorClearTDControlIOC (pTDStruct, FALSE); + + // + // Set Active bit + // + SetTDStatusActiveorInactive (pTDStruct, TRUE); + + SetTDTokenMaxLength (pTDStruct, Len); + + if (Toggle) { + SetTDTokenDataToggle1 (pTDStruct); + } else { + SetTDTokenDataToggle0 (pTDStruct); + } + + SetTDTokenEndPoint (pTDStruct, Endpoint); + + SetTDTokenDeviceAddress (pTDStruct, DevAddr); + + SetTDTokenPacketID (pTDStruct, PktID); + + pTDStruct->pTDBuffer = (UINT8 *) pData; + pTDStruct->TDBufferLength = Len; + SetTDDataBuffer (pTDStruct); + *ppTD = pTDStruct; + + return EFI_SUCCESS; +} + + +EFI_STATUS +CreateStatusTD ( + IN USB_HC_DEV *HcDev, + IN UINT8 DevAddr, + IN UINT8 Endpoint, + IN UINT8 PktID, + IN BOOLEAN bSlow, + OUT TD_STRUCT **ppTD + ) +/*++ + +Routine Description: + + Generate Status Stage TD + +Arguments: + + HcDev - USB_HC_DEV + DevAddr - Device address + Endpoint - Endpoint number + PktID - Packet ID + bSlow - Full speed or low speed + ppTD - TD_STRUCT to return +Returns: + + EFI_OUT_OF_RESOURCES - Can't allocate memory + EFI_SUCCESS - Success + +--*/ +{ + TD_STRUCT *ptrTDStruct; + EFI_STATUS Status; + + Status = CreateTD (HcDev, &ptrTDStruct); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + 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) + // + SetTDLoworFullSpeedDevice (ptrTDStruct, bSlow); + + // + // 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->pTDBuffer = NULL; + ptrTDStruct->TDBufferLength = 0; + SetTDDataBuffer (ptrTDStruct); + + *ppTD = ptrTDStruct; + + return EFI_SUCCESS; +} + + +VOID +SetTDLinkPtrValidorInvalid ( + IN TD_STRUCT *ptrTDStruct, + IN BOOLEAN bValid + ) +/*++ + +Routine Description: + + Set TD Link Pointer Valid or Invalid + +Arguments: + + ptrTDStruct - TD_STRUCT + bValid - TRUE is valid FALSE is invalid + +Returns: + + VOID + +--*/ +{ + // + // Valid means the link pointer is valid, + // else, it's invalid. + // + ptrTDStruct->TDData.TDLinkPtrTerminate = (bValid ? 0 : 1); +} + +VOID +SetTDLinkPtrQHorTDSelect ( + IN TD_STRUCT *ptrTDStruct, + IN BOOLEAN bQH + ) +/*++ + +Routine Description: + + Set TD Link Pointer QH or TD Select + +Arguments: + + ptrTDStruct - TD_STRUCT + bQH - TRUE is QH FALSE is TD + +Returns: + + VOID + +--*/ +{ + // + // Indicate whether the Link Pointer pointing to a QH or TD + // + ptrTDStruct->TDData.TDLinkPtrQSelect = (bQH ? 1 : 0); +} + +VOID +SetTDLinkPtrDepthorBreadth ( + IN TD_STRUCT *ptrTDStruct, + IN BOOLEAN bDepth + ) +/*++ + +Routine Description: + + Set TD Link Pointer depth or bread priority + +Arguments: + + ptrTDStruct - TD_STRUCT + bDepth - TRUE is Depth FALSE is Breadth + +Returns: + + VOID + +--*/ +{ + // + // 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 = (bDepth ? 1 : 0); +} + +VOID +SetTDLinkPtr ( + IN TD_STRUCT *ptrTDStruct, + IN VOID *ptrNext + ) +/*++ + +Routine Description: + + Set TD Link Pointer + +Arguments: + + ptrTDStruct - TD_STRUCT + ptrNext - Pointer to set + +Returns: + + VOID + +--*/ +{ + // + // 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); +} + +VOID * +GetTDLinkPtr ( + IN TD_STRUCT *ptrTDStruct + ) +/*++ + +Routine Description: + + Get TD Link Pointer + +Arguments: + + ptrTDStruct - TD_STRUCT + +Returns: + + Pointer to get + +--*/ +{ + // + // Get TD Link Pointer. Restore it back to 32bit + // (if take 32bit address as an example) + // + return (VOID *) ((UINTN) (ptrTDStruct->TDData.TDLinkPtr << 4)); +} + +BOOLEAN +IsTDLinkPtrQHOrTD ( + IN TD_STRUCT *ptrTDStruct + ) +/*++ + +Routine Description: + + Is TD Link Pointer is QH Or TD + +Arguments: + + ptrTDStruct - TODO: add argument description + +Returns: + + TRUE - QH + FALSE - TD + +--*/ +{ + // + // Get the information about whether the Link Pointer field pointing to + // a QH or a TD. + // + return (BOOLEAN) (ptrTDStruct->TDData.TDLinkPtrQSelect); +} + +VOID +EnableorDisableTDShortPacket ( + IN TD_STRUCT *ptrTDStruct, + IN BOOLEAN bEnable + ) +/*++ + +Routine Description: + + Enable or Disable TD ShortPacket + +Arguments: + + ptrTDStruct - TD_STRUCT + bEnable - TRUE is Enanble FALSE is Disable + +Returns: + + VOID + +--*/ +{ + // + // TRUE means enable short packet detection mechanism. + // + ptrTDStruct->TDData.TDStatusSPD = (bEnable ? 1 : 0); +} + +VOID +SetTDControlErrorCounter ( + IN TD_STRUCT *ptrTDStruct, + IN UINT8 nMaxErrors + ) +/*++ + +Routine Description: + + Set TD Control ErrorCounter + +Arguments: + + ptrTDStruct - TD_STRUCT + nMaxErrors - Error counter number + +Returns: + + VOID + +--*/ +{ + // + // valid value of nMaxErrors is 0,1,2,3 + // + if (nMaxErrors > 3) { + nMaxErrors = 3; + } + + ptrTDStruct->TDData.TDStatusErr = nMaxErrors; +} + + +VOID +SetTDLoworFullSpeedDevice ( + IN TD_STRUCT *ptrTDStruct, + IN BOOLEAN bLowSpeedDevice + ) +{ + // + // TRUE means the TD is targeting at a Low-speed device + // + ptrTDStruct->TDData.TDStatusLS = (bLowSpeedDevice ? 1 : 0); +} + +VOID +SetTDControlIsochronousorNot ( + IN TD_STRUCT *ptrTDStruct, + IN BOOLEAN IsIsochronous + ) +{ + // + // TRUE means the TD belongs to Isochronous transfer type. + // + ptrTDStruct->TDData.TDStatusIOS = (IsIsochronous ? 1 : 0); +} + +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; +} + +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; + } +} + +UINT16 +SetTDTokenMaxLength ( + IN TD_STRUCT *ptrTDStruct, + IN UINT16 MaximumLength + ) +{ + // + // Specifies the maximum number of data bytes allowed for the transfer. + // the legal value extent is 0 ~ 0x500. + // + if (MaximumLength > 0x500) { + MaximumLength = 0x500; + } + ptrTDStruct->TDData.TDTokenMaxLen = MaximumLength - 1; + + return MaximumLength; +} + +VOID +SetTDTokenDataToggle1 ( + IN TD_STRUCT *ptrTDStruct + ) +{ + // + // Set the data toggle bit to DATA1 + // + ptrTDStruct->TDData.TDTokenDataToggle = 1; +} + +VOID +SetTDTokenDataToggle0 ( + IN TD_STRUCT *ptrTDStruct + ) +{ + // + // Set the data toggle bit to DATA0 + // + ptrTDStruct->TDData.TDTokenDataToggle = 0; +} + +UINT8 +GetTDTokenDataToggle ( + IN TD_STRUCT *ptrTDStruct + ) +{ + // + // Get the data toggle value. + // + return (UINT8) (ptrTDStruct->TDData.TDTokenDataToggle); +} + +VOID +SetTDTokenEndPoint ( + IN TD_STRUCT *ptrTDStruct, + IN UINTN EndPoint + ) +{ + // + // Set EndPoint Number the TD is targeting at. + // + ptrTDStruct->TDData.TDTokenEndPt = (UINT8) EndPoint; +} + +VOID +SetTDTokenDeviceAddress ( + IN TD_STRUCT *ptrTDStruct, + IN UINTN DeviceAddress + ) +{ + // + // Set Device Address the TD is targeting at. + // + ptrTDStruct->TDData.TDTokenDevAddr = (UINT8) DeviceAddress; +} + +VOID +SetTDTokenPacketID ( + IN TD_STRUCT *ptrTDStruct, + IN UINT8 PID + ) +{ + // + // Set the Packet Identification to be used for this transaction. + // + ptrTDStruct->TDData.TDTokenPID = PID; +} + +VOID +SetTDDataBuffer ( + IN TD_STRUCT *ptrTDStruct + ) +{ + // + // Set the beginning address of the data buffer that will be used + // during the transaction. + // + ptrTDStruct->TDData.TDBufferPtr = (UINT32) ((UINTN) (ptrTDStruct->pTDBuffer)); +} + +BOOLEAN +IsTDStatusActive ( + IN TD_STRUCT *ptrTDStruct + ) +{ + UINT8 TDStatus; + + // + // Detect whether the TD is active. + // + TDStatus = (UINT8) (ptrTDStruct->TDData.TDStatus); + return (BOOLEAN) (TDStatus & 0x80); +} + +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); +} + +BOOLEAN +IsTDStatusBufferError ( + IN TD_STRUCT *ptrTDStruct + ) +{ + UINT8 TDStatus; + // + // Detect whether Data Buffer Error is happened. + // + TDStatus = (UINT8) (ptrTDStruct->TDData.TDStatus); + return (BOOLEAN) (TDStatus & 0x20); +} + +BOOLEAN +IsTDStatusBabbleError ( + IN TD_STRUCT *ptrTDStruct + ) +{ + UINT8 TDStatus; + + // + // Detect whether Babble Error is happened. + // + TDStatus = (UINT8) (ptrTDStruct->TDData.TDStatus); + return (BOOLEAN) (TDStatus & 0x10); +} + +BOOLEAN +IsTDStatusNAKReceived ( + IN TD_STRUCT *ptrTDStruct + ) +{ + UINT8 TDStatus; + + // + // Detect whether NAK is received. + // + TDStatus = (UINT8) (ptrTDStruct->TDData.TDStatus); + return (BOOLEAN) (TDStatus & 0x08); +} + +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); +} + +BOOLEAN +IsTDStatusBitStuffError ( + IN TD_STRUCT *ptrTDStruct + ) +{ + UINT8 TDStatus; + + // + // Detect whether Bitstuff Error is received. + // + TDStatus = (UINT8) (ptrTDStruct->TDData.TDStatus); + return (BOOLEAN) (TDStatus & 0x02); +} + +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); +} + +UINT16 +GetTDTokenMaxLength ( + IN TD_STRUCT *ptrTDStruct + ) +{ + // + // Retrieve the maximum number of data bytes allowed for the trnasfer. + // + return (UINT16) ((ptrTDStruct->TDData.TDTokenMaxLen) + 1); +} + +UINT8 +GetTDTokenEndPoint ( + IN TD_STRUCT *ptrTDStruct + ) +{ + // + // Retrieve the endpoint number the transaction is targeting at. + // + return (UINT8) (ptrTDStruct->TDData.TDTokenEndPt); +} + +UINT8 +GetTDTokenDeviceAddress ( + IN TD_STRUCT *ptrTDStruct + ) +{ + // + // Retrieve the device address the transaction is targeting at. + // + return (UINT8) (ptrTDStruct->TDData.TDTokenDevAddr); +} + +UINT8 +GetTDTokenPacketID ( + IN TD_STRUCT *ptrTDStruct + ) +{ + // + // Retrieve the Packet Identification information. + // + return (UINT8) (ptrTDStruct->TDData.TDTokenPID); +} + +UINT8 * +GetTDDataBuffer ( + IN TD_STRUCT *ptrTDStruct + ) +{ + // + // Retrieve the beginning address of the data buffer + // that involved in this transaction. + // + return ptrTDStruct->pTDBuffer; +} + +BOOLEAN +GetTDLinkPtrValidorInvalid ( + IN TD_STRUCT *ptrTDStruct + ) +{ + // + // Retrieve the information of whether the Link Pointer field + // is valid or not. + // + if (ptrTDStruct->TDData.TDLinkPtrTerminate) { + return FALSE; + } else { + return TRUE; + } + +} + +UINTN +CountTDsNumber ( + IN TD_STRUCT *PtrFirstTD + ) +{ + UINTN Number; + TD_STRUCT *ptr; + // + // Count the queued TDs number. + // + Number = 0; + ptr = PtrFirstTD; + while (ptr) { + ptr = (TD_STRUCT *) ptr->ptrNextTD; + Number++; + } + + return Number; +} + + + +VOID +LinkTDToQH ( + IN QH_STRUCT *PtrQH, + IN TD_STRUCT *PtrTD + ) +/*++ + +Routine Description: + + Link TD To QH + +Arguments: + + PtrQH - QH_STRUCT + PtrTD - TD_STRUCT +Returns: + + VOID + +--*/ +{ + 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; +} + +VOID +LinkTDToTD ( + IN TD_STRUCT *ptrPreTD, + IN TD_STRUCT *PtrTD + ) +/*++ + +Routine Description: + + Link TD To TD + +Arguments: + + ptrPreTD - Previous TD_STRUCT to be linked + PtrTD - TD_STRUCT to link +Returns: + + VOID + +--*/ +{ + 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; +} +// +// Transfer Schedule related Helper Functions +// +VOID +SetorClearCurFrameListTerminate ( + IN FRAMELIST_ENTRY *pCurEntry, + IN BOOLEAN IsSet + ) +{ + // + // If TRUE, empty the frame. If FALSE, indicate the Pointer field is valid. + // + pCurEntry->FrameListPtrTerminate = (IsSet ? 1 : 0); +} + +VOID +SetCurFrameListQHorTD ( + IN FRAMELIST_ENTRY *pCurEntry, + IN BOOLEAN IsQH + ) +{ + // + // This bit indicates to the hardware whether the item referenced by the + // link pointer is a TD or a QH. + // + pCurEntry->FrameListPtrQSelect = (IsQH ? 1 : 0); +} + +BOOLEAN +IsCurFrameListQHorTD ( + IN FRAMELIST_ENTRY *pCurEntry + ) +{ + // + // TRUE is QH + // FALSE is TD + // + return (BOOLEAN) (pCurEntry->FrameListPtrQSelect); +} + +BOOLEAN +GetCurFrameListTerminate ( + IN FRAMELIST_ENTRY *pCurEntry + ) +{ + // + // TRUE means the frame is empty, + // FALSE means the link pointer field is valid. + // + return (BOOLEAN) (pCurEntry->FrameListPtrTerminate); +} + +VOID +SetCurFrameListPointer ( + IN FRAMELIST_ENTRY *pCurEntry, + IN UINT8 *ptr + ) +{ + // + // Set the pointer field of the frame. + // + pCurEntry->FrameListPtr = (UINT32) ((UINTN) ptr >> 4); +} + +VOID * +GetCurFrameListPointer ( + IN FRAMELIST_ENTRY *pCurEntry + ) +{ + // + // Get the link pointer of the frame. + // + return (VOID *) ((UINTN) (pCurEntry->FrameListPtr << 4)); + +} + +VOID +LinkQHToFrameList ( + IN FRAMELIST_ENTRY *pEntry, + IN UINT16 FrameListIndex, + IN QH_STRUCT *PtrQH + ) +/*++ + +Routine Description: + + Link QH To Frame List + +Arguments: + + pEntry - FRAMELIST_ENTRY + FrameListIndex - Frame List Index + PtrQH - QH to link +Returns: + + VOID + +--*/ +{ + FRAMELIST_ENTRY *pCurFrame; + QH_STRUCT *TempQH; + QH_STRUCT *NextTempQH; + TD_STRUCT *TempTD; + BOOLEAN LINK; + + // + // Get frame list entry that the link process will begin from. + // + pCurFrame = pEntry + FrameListIndex; + + // + // if current frame is empty + // then link the specified QH directly to the Frame List. + // + if (GetCurFrameListTerminate (pCurFrame)) { + + // + // Link new QH to the frame list entry. + // + SetCurFrameListQHorTD (pCurFrame, TRUE); + + SetCurFrameListPointer (pCurFrame, (UINT8 *) PtrQH); + + // + // clear T bit in the Frame List, indicating that the frame list entry + // is no longer empty. + // + SetorClearCurFrameListTerminate (pCurFrame, FALSE); + + return ; + + } else { + // + // current frame list has link pointer + // + if (!IsCurFrameListQHorTD (pCurFrame)) { + // + // a TD is linked to the framelist entry + // + TempTD = (TD_STRUCT *) GetCurFrameListPointer (pCurFrame); + + while (GetTDLinkPtrValidorInvalid (TempTD)) { + + if (IsTDLinkPtrQHOrTD (TempTD)) { + // + // QH linked next to the TD + // + break; + } + + TempTD = (TD_STRUCT *) GetTDLinkPtr (TempTD); + } + + // + // either no ptr linked next to the TD or QH is linked next to the TD + // + if (!GetTDLinkPtrValidorInvalid (TempTD)) { + + // + // no ptr linked next to the TD + // + TempTD->ptrNextQH = PtrQH; + SetTDLinkPtrQHorTDSelect (TempTD, TRUE); + SetTDLinkPtr (TempTD, PtrQH); + SetTDLinkPtrValidorInvalid (TempTD, TRUE); + return ; + + } else { + // + // QH is linked next to the TD + // + TempQH = (QH_STRUCT *) GetTDLinkPtr (TempTD); + } + } else { + // + // a QH is linked to the framelist entry + // + TempQH = (QH_STRUCT *) GetCurFrameListPointer (pCurFrame); + } + + // + // Set up Flag + // + LINK = TRUE; + + // + // Avoid the same qh repeated linking in one frame entry + // + if (TempQH == PtrQH) { + LINK = FALSE; + return ; + } + // + // if current QH has next QH connected + // + while (GetQHHorizontalValidorInvalid (TempQH)) { + // + // Get next QH pointer + // + NextTempQH = (QH_STRUCT *) GetQHHorizontalLinkPtr (TempQH); + + // + // Bulk transfer qh may be self-linked, + // so, the code below is to aVOID dead-loop when meeting self-linked qh + // + if (NextTempQH == TempQH) { + LINK = FALSE; + break; + } + + TempQH = NextTempQH; + + // + // Avoid the same qh repeated linking in one frame entry + // + if (TempQH == PtrQH) { + LINK = FALSE; + } + } + + if (LINK) { + TempQH->ptrNext = PtrQH; + SetQHHorizontalQHorTDSelect (TempQH, TRUE); + SetQHHorizontalLinkPtr (TempQH, PtrQH); + SetQHHorizontalValidorInvalid (TempQH, TRUE); + } + + return ; + } +} + +EFI_STATUS +ExecuteControlTransfer ( + IN USB_HC_DEV *HcDev, + IN TD_STRUCT *PtrTD, + IN UINT32 wIndex, + OUT UINTN *ActualLen, + IN UINTN TimeOut, + OUT UINT32 *TransferResult + ) +/*++ + +Routine Description: + + Execute Control Transfer + +Arguments: + + HcDev - USB_HC_DEV + PtrTD - TD_STRUCT + wIndex - No use + ActualLen - Actual transfered Len + TimeOut - TimeOut value in milliseconds + TransferResult - Transfer result +Returns: + + EFI_SUCCESS - Sucess + EFI_DEVICE_ERROR - Error + + +--*/ +{ + UINTN ErrTDPos; + UINTN Delay; + UINTN RequiredLen; + BOOLEAN TransferFinished; + + ErrTDPos = 0; + *TransferResult = EFI_USB_NOERROR; + RequiredLen = *ActualLen; + *ActualLen = 0; + + Delay = (TimeOut * STALL_1_MILLI_SECOND / 50) + 1; + + do { + TransferFinished = CheckTDsResults ( + PtrTD, + RequiredLen, + TransferResult, + &ErrTDPos, + ActualLen + ); + + if (TransferFinished) { + break; + } + + // + // TD is inactive, which means the control transfer is end. + // + if ((*TransferResult & EFI_USB_ERR_NOTEXECUTE) != EFI_USB_ERR_NOTEXECUTE) { + break; + } + + gBS->Stall (50); + + } while (Delay--); + + if (*TransferResult != EFI_USB_NOERROR) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +ExecBulkorSyncInterruptTransfer ( + IN USB_HC_DEV *HcDev, + IN TD_STRUCT *PtrTD, + IN UINT32 wIndex, + OUT UINTN *ActualLen, + OUT UINT8 *DataToggle, + IN UINTN TimeOut, + OUT UINT32 *TransferResult + ) +/*++ + +Routine Description: + + Execute Bulk or SyncInterrupt Transfer + +Arguments: + + HcDev - USB_HC_DEV + PtrTD - TD_STRUCT + wIndex - No use + ActualLen - Actual transfered Len + DataToggle - Data Toggle + TimeOut - TimeOut value in milliseconds + TransferResult - Transfer result +Returns: + + EFI_SUCCESS - Sucess + EFI_DEVICE_ERROR - Error +--*/ +{ + UINTN ErrTDPos; + UINTN ScrollNum; + UINTN Delay; + UINTN RequiredLen; + BOOLEAN TransferFinished; + + ErrTDPos = 0; + *TransferResult = EFI_USB_NOERROR; + RequiredLen = *ActualLen; + *ActualLen = 0; + + Delay = (TimeOut * STALL_1_MILLI_SECOND / 50) + 1; + + do { + + TransferFinished = CheckTDsResults ( + PtrTD, + RequiredLen, + TransferResult, + &ErrTDPos, + ActualLen + ); + + if (TransferFinished) { + break; + } + + // + // TD is inactive, which means bulk or interrupt transfer's end. + // + if ((*TransferResult & EFI_USB_ERR_NOTEXECUTE) != EFI_USB_ERR_NOTEXECUTE) { + break; + } + + gBS->Stall (50); + + } while (Delay--); + + // + // has error + // + if (*TransferResult != EFI_USB_NOERROR) { + + // + // scroll the Data Toggle back to the last success TD + // + ScrollNum = CountTDsNumber (PtrTD) - ErrTDPos; + if (ScrollNum & 0x1) { + *DataToggle ^= 1; + } + + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +VOID +DelLinkSingleQH ( + IN USB_HC_DEV *HcDev, + IN QH_STRUCT *PtrQH, + IN UINT16 FrameListIndex, + IN BOOLEAN SearchOther, + IN BOOLEAN Delete + ) +/*++ + +Routine Description: + + Unlink from frame list and delete single QH +Arguments: + + HcDev - USB_HC_DEV + PtrQH - QH_STRUCT + FrameListIndex - Frame List Index + SearchOther - Search Other QH + Delete - TRUE is to delete the QH +Returns: + VOID +--*/ +{ + FRAMELIST_ENTRY *pCurFrame; + UINTN Index; + UINTN BeginFrame; + UINTN EndFrame; + QH_STRUCT *CurrentQH; + QH_STRUCT *NextQH; + TD_STRUCT *CurrentTD; + VOID *PtrPreQH; + BOOLEAN Found; + + NextQH = NULL; + PtrPreQH = NULL; + Found = FALSE; + + if (PtrQH == NULL) { + return ; + } + + if (SearchOther) { + BeginFrame = 0; + EndFrame = 1024; + } else { + BeginFrame = FrameListIndex; + EndFrame = FrameListIndex + 1; + } + + for (Index = BeginFrame; Index < EndFrame; Index++) { + + pCurFrame = HcDev->FrameListEntry + (Index & 0x3FF); + + if (GetCurFrameListTerminate (pCurFrame)) { + // + // current frame list is empty,search next frame list entry + // + continue; + } + + if (!IsCurFrameListQHorTD (pCurFrame)) { + // + // TD linked to current framelist + // + CurrentTD = (TD_STRUCT *) GetCurFrameListPointer (pCurFrame); + + while (GetTDLinkPtrValidorInvalid (CurrentTD)) { + + if (IsTDLinkPtrQHOrTD (CurrentTD)) { + // + // QH linked next to the TD,break while () + // + break; + } + + CurrentTD = (TD_STRUCT *) GetTDLinkPtr (CurrentTD); + } + + if (!GetTDLinkPtrValidorInvalid (CurrentTD)) { + // + // no QH linked next to the last TD, + // search next frame list + // + continue; + } + + // + // a QH linked next to the last TD + // + CurrentQH = (QH_STRUCT *) GetTDLinkPtr (CurrentTD); + + PtrPreQH = CurrentTD; + + } else { + // + // a QH linked to current framelist + // + CurrentQH = (QH_STRUCT *) GetCurFrameListPointer (pCurFrame); + + PtrPreQH = NULL; + } + + if (CurrentQH == PtrQH) { + + if (GetQHHorizontalValidorInvalid (PtrQH)) { + // + // there is QH connected after the QH found + // + // + // retrieve nex qh pointer of the qh found. + // + NextQH = GetQHHorizontalLinkPtr (PtrQH); + } else { + NextQH = NULL; + } + + if (PtrPreQH) { + // + // QH linked to a TD struct + // + CurrentTD = (TD_STRUCT *) PtrPreQH; + + SetTDLinkPtrValidorInvalid (CurrentTD, (BOOLEAN) ((NextQH == NULL) ? FALSE : TRUE)); + SetTDLinkPtr (CurrentTD, NextQH); + CurrentTD->ptrNextQH = NextQH; + + } else { + // + // QH linked directly to current framelist entry + // + SetorClearCurFrameListTerminate (pCurFrame, (BOOLEAN) ((NextQH == NULL) ? TRUE : FALSE)); + SetCurFrameListPointer (pCurFrame, (UINT8 *) NextQH); + } + + Found = TRUE; + // + // search next framelist entry + // + continue; + } + + while (GetQHHorizontalValidorInvalid (CurrentQH)) { + + PtrPreQH = CurrentQH; + // + // Get next horizontal linked QH + // + CurrentQH = (QH_STRUCT *) GetQHHorizontalLinkPtr (CurrentQH); + // + // the qh is found + // + if (CurrentQH == PtrQH) { + break; + } + } + + // + // search next frame list entry + // + if (CurrentQH != PtrQH) { + // + // Not find the QH + // + continue; + } + // + // find the specified qh, then delink it from + // the horizontal QH list in the frame entry. + // + + if (GetQHHorizontalValidorInvalid (PtrQH)) { + // + // there is QH connected after the QH found + // + // + // retrieve nex qh pointer of the qh found. + // + NextQH = GetQHHorizontalLinkPtr (PtrQH); + + } else { + // + // NO QH connected after the QH found + // + NextQH = NULL; + // + // NULL the previous QH's link ptr and set Terminate field. + // + SetQHHorizontalValidorInvalid ((QH_STRUCT *) PtrPreQH, FALSE); + } + + SetQHHorizontalLinkPtr ((QH_STRUCT *) PtrPreQH, NextQH); + ((QH_STRUCT *) PtrPreQH)->ptrNext = NextQH; + + Found = TRUE; + } + + if (Found && Delete) { + // + // free memory once used by the specific QH + // + UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT)); + } + + return ; +} + + +VOID +DeleteQueuedTDs ( + IN USB_HC_DEV *HcDev, + IN TD_STRUCT *PtrFirstTD + ) +/*++ +Routine Description: + + Delete Queued TDs +Arguments: + + HcDev - USB_HC_DEV + PtrFirstTD - TD link list head + +Returns: + VOID + +--*/ +{ + TD_STRUCT *Tptr1; + TD_STRUCT *Tptr2; + + Tptr1 = PtrFirstTD; + // + // Delete all the TDs in a queue. + // + while (Tptr1) { + + Tptr2 = Tptr1; + + if (!GetTDLinkPtrValidorInvalid (Tptr2)) { + Tptr1 = NULL; + } else { + + Tptr1 = GetTDLinkPtr (Tptr2); + + // + // TD link to itself + // + if (Tptr1 == Tptr2) { + Tptr1 = NULL; + } + } + + UhciFreePool (HcDev, (UINT8 *) Tptr2, sizeof (TD_STRUCT)); + } + + return ; +} + +VOID +InsertQHTDToINTList ( + IN USB_HC_DEV *HcDev, + IN QH_STRUCT *PtrQH, + IN TD_STRUCT *PtrFirstTD, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 DataToggle, + IN UINTN DataLength, + IN UINTN PollingInterval, + IN VOID *Mapping, + IN UINT8 *DataBuffer, + IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction, + IN VOID *Context + ) +/*++ +Routine Description: + Insert QH and TD To Interrupt List +Arguments: + + HcDev - USB_HC_DEV + PtrQH - QH_STRUCT + PtrFirstTD - First TD_STRUCT + DeviceAddress - Device Address + EndPointAddress - EndPoint Address + DataToggle - Data Toggle + DataLength - Data length + PollingInterval - Polling Interval when inserted to frame list + Mapping - Mapping alue + DataBuffer - Data buffer + CallBackFunction- CallBackFunction after interrupt transfeer + Context - CallBackFunction Context passed as function parameter +Returns: + EFI_SUCCESS - Sucess + EFI_INVALID_PARAMETER - Paremeter is error + +--*/ +{ + INTERRUPT_LIST *Node; + + Node = AllocatePool (sizeof (INTERRUPT_LIST)); + if (Node == NULL) { + return ; + } + + // + // Fill Node field + // + Node->Signature = INTERRUPT_LIST_SIGNATURE; + Node->DevAddr = DeviceAddress; + Node->EndPoint = EndPointAddress; + Node->PtrQH = PtrQH; + Node->PtrFirstTD = PtrFirstTD; + Node->DataToggle = DataToggle; + Node->DataLen = DataLength; + Node->PollInterval = PollingInterval; + Node->Mapping = Mapping; + // + // DataBuffer is allocated host memory, not mapped memory + // + Node->DataBuffer = DataBuffer; + Node->InterruptCallBack = CallBackFunction; + Node->InterruptContext = Context; + + // + // 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 + // for the sake of error recovery. + // + InsertHeadList (&(HcDev->InterruptListHead), &(Node->Link)); + + return ; +} + + +EFI_STATUS +DeleteAsyncINTQHTDs ( + IN USB_HC_DEV *HcDev, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + OUT UINT8 *DataToggle + ) +/*++ +Routine Description: + + Delete Async INT QH and TDs +Arguments: + + HcDev - USB_HC_DEV + DeviceAddress - Device Address + EndPointAddress - EndPoint Address + DataToggle - Data Toggle + +Returns: + EFI_SUCCESS - Sucess + EFI_INVALID_PARAMETER - Paremeter is error + +--*/ +{ + QH_STRUCT *MatchQH; + QH_STRUCT *ptrNextQH; + TD_STRUCT *MatchTD; + LIST_ENTRY *Link; + INTERRUPT_LIST *MatchList; + INTERRUPT_LIST *PtrList; + BOOLEAN Found; + + UINT32 Result; + UINTN ErrTDPos; + UINTN ActualLen; + + MatchQH = NULL; + MatchTD = NULL; + MatchList = NULL; + + // + // no interrupt transaction exists + // + if (IsListEmpty (&(HcDev->InterruptListHead))) { + return EFI_INVALID_PARAMETER; + } + // + // find the correct QH-TD that need to delete + // (by matching Device address and EndPoint number to match QH-TD ) + // + Found = FALSE; + Link = &(HcDev->InterruptListHead); + do { + + Link = Link->ForwardLink; + PtrList = INTERRUPT_LIST_FROM_LINK (Link); + + if ((PtrList->DevAddr == DeviceAddress) && ((PtrList->EndPoint & 0x0f) == (EndPointAddress & 0x0f))) { + MatchList = PtrList; + + Found = TRUE; + break; + } + + } while (Link->ForwardLink != &(HcDev->InterruptListHead)); + + if (!Found) { + return EFI_INVALID_PARAMETER; + } + // + // get current endpoint's data toggle bit and save. + // + ExecuteAsyncINTTDs (HcDev, MatchList, &Result, &ErrTDPos, &ActualLen); + UpdateAsyncINTQHTDs (MatchList, Result, (UINT32) ErrTDPos); + *DataToggle = MatchList->DataToggle; + + MatchTD = MatchList->PtrFirstTD; + MatchQH = MatchList->PtrQH; + // + // find the first matching QH position in the FrameList + // + while (MatchQH) { + + ptrNextQH = MatchQH->ptrNextIntQH; + + // + // Search all the entries + // + DelLinkSingleQH (HcDev, MatchQH, 0, TRUE, TRUE); + + MatchQH = ptrNextQH; + } + + // + // Call PciIo->Unmap() to unmap the busmaster read/write + // + HcDev->PciIo->Unmap (HcDev->PciIo, MatchList->Mapping); + + // + // free host data buffer allocated, + // mapped data buffer is freed by Unmap + // + if (MatchList->DataBuffer != NULL) { + gBS->FreePool (MatchList->DataBuffer); + } + + // + // at last delete the TDs, to aVOID problems + // + DeleteQueuedTDs (HcDev, MatchTD); + + // + // remove Match node from interrupt list + // + RemoveEntryList (&(MatchList->Link)); + gBS->FreePool (MatchList); + return EFI_SUCCESS; +} + +BOOLEAN +CheckTDsResults ( + IN TD_STRUCT *PtrTD, + IN UINTN RequiredLen, + OUT UINT32 *Result, + OUT UINTN *ErrTDPos, + OUT UINTN *ActualTransferSize + ) +/*++ + +Routine Description: + + Check TDs Results + +Arguments: + + PtrTD - TD_STRUCT to check + RequiredLen - Required Len + Result - Transfer result + ErrTDPos - Error TD Position + ActualTransferSize - Actual Transfer Size + +Returns: + + TRUE - Sucess + FALSE - Fail + +--*/ +{ + UINTN Len; + + *Result = EFI_USB_NOERROR; + *ErrTDPos = 0; + + // + // Init to zero. + // + *ActualTransferSize = 0; + + while (PtrTD) { + + 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; + } + + // + // if any error encountered, stop processing the left TDs. + // + if (*Result) { + return FALSE; + } + + Len = GetTDStatusActualLength (PtrTD) & 0x7FF; + *ActualTransferSize += Len; + + if (*ActualTransferSize <= RequiredLen && Len < PtrTD->TDData.TDTokenMaxLen) { + // + // transter finished and actural length less than required length + // + goto Done; + } + // + // Accumulate actual transferred data length in each TD. + // + PtrTD = (TD_STRUCT *) (PtrTD->ptrNextTD); + // + // Record the first Error TD's position in the queue, + // this value is zero-based. + // + (*ErrTDPos)++; + } + +Done: + return TRUE; +} + + +VOID +ExecuteAsyncINTTDs ( + IN USB_HC_DEV *HcDev, + IN INTERRUPT_LIST *PtrList, + OUT UINT32 *Result, + OUT UINTN *ErrTDPos, + OUT UINTN *ActualLen + ) +/*++ + +Routine Description: + + Execute Async Interrupt TDs + +Arguments: + + HcDev - USB_HC_DEV + PtrList - INTERRUPT_LIST + Result - Transfer result + ErrTDPos - Error TD Position + ActualTransferSize - Actual Transfer Size + +Returns: + + VOID + +--*/ +{ + // + // *ErrTDPos is zero-based value, indicating the first error TD's position + // in the TDs' sequence. + // *ErrTDPos value is only valid when *Result is not equal NOERROR. + // + UINTN RequiredLen; + + RequiredLen = *ActualLen; + CheckTDsResults (PtrList->PtrFirstTD, RequiredLen, Result, ErrTDPos, ActualLen); + + return ; +} + + +VOID +UpdateAsyncINTQHTDs ( + IN INTERRUPT_LIST *PtrList, + IN UINT32 Result, + IN UINT32 ErrTDPos + ) +/*++ + +Routine Description: + + Update Async Interrupt QH and TDs + +Arguments: + + PtrList - INTERRUPT_LIST + Result - Transfer reslut + ErrTDPos - Error TD Position + +Returns: + + VOID + +--*/ +{ + QH_STRUCT *PtrFirstQH; + QH_STRUCT *PtrQH; + TD_STRUCT *PtrFirstTD; + TD_STRUCT *PtrTD; + UINT8 DataToggle; + UINT32 Index; + + PtrFirstQH = PtrList->PtrQH; + PtrFirstTD = PtrList->PtrFirstTD; + + DataToggle = 0; + + if (Result == EFI_USB_NOERROR) { + + PtrTD = PtrFirstTD; + while (PtrTD) { + DataToggle = GetTDTokenDataToggle (PtrTD); + PtrTD = PtrTD->ptrNextTD; + } + + // + // save current DataToggle value to interrupt list. + // this value is used for tracing the interrupt endpoint DataToggle. + // when this interrupt transfer is deleted, the last DataToggle is saved + // + PtrList->DataToggle = DataToggle; + + PtrTD = PtrFirstTD; + + // + // Since DataToggle bit should toggle after each success transaction, + // the First TD's DataToggle bit will be updated to XOR of Last TD's + // DataToggle bit. If the First TD's DataToggle bit is not equal Last + // TD's DataToggle bit, that means it already be the XOR of Last TD's, + // so no update is needed. + // + if (DataToggle == GetTDTokenDataToggle (PtrFirstTD)) { + PtrTD = PtrFirstTD; + while (PtrTD) { + + DataToggle ^= 1; + if (DataToggle) { + SetTDTokenDataToggle1 (PtrTD); + } else { + SetTDTokenDataToggle0 (PtrTD); + } + + PtrTD = PtrTD->ptrNextTD; + } + } + // + // restore Link Pointer of QH to First TD + // (because QH's Link Pointer will change during TD execution) + // + PtrQH = PtrFirstQH; + while (PtrQH) { + + LinkTDToQH (PtrQH, PtrFirstTD); + PtrQH = PtrQH->ptrNextIntQH; + } + + // + // set all the TDs active + // + PtrTD = PtrFirstTD; + while (PtrTD) { + SetTDStatusActiveorInactive (PtrTD, TRUE); + PtrTD = PtrTD->ptrNextTD; + } + + } else if (((Result & EFI_USB_ERR_NOTEXECUTE) == EFI_USB_ERR_NOTEXECUTE) || + ((Result & EFI_USB_ERR_NAK) == EFI_USB_ERR_NAK) + ) { + // + // no update + // + } else { + // + // Have Errors + // + PtrTD = PtrFirstTD; + // + // not first TD error + // + if (ErrTDPos != 0) { + // + // get the last success TD + // + for (Index = 1; Index < ErrTDPos; Index++) { + PtrTD = PtrTD->ptrNextTD; + } + // + // update Data Toggle in the interrupt list node + // + PtrList->DataToggle = GetTDTokenDataToggle (PtrTD); + + // + // get the error TD + // + PtrTD = PtrTD->ptrNextTD; + + } else { + PtrList->DataToggle = GetTDTokenDataToggle (PtrTD); + } + // + // do not restore the QH's vertical link pointer, + // let the callback function do the rest of error handling. + // + } + + return ; +} + +VOID +ReleaseInterruptList ( + IN USB_HC_DEV *HcDev, + IN LIST_ENTRY *ListHead + ) +/*++ + +Routine Description: + + Release Interrupt List +Arguments: + + HcDev - USB_HC_DEV + ListHead - List head + +Returns: + + VOID + +--*/ +{ + LIST_ENTRY *Link; + LIST_ENTRY *SavedLink; + INTERRUPT_LIST *pNode; + TD_STRUCT *PtrTD; + TD_STRUCT *ptrNextTD; + QH_STRUCT *PtrQH; + QH_STRUCT *SavedQH; + + if (ListHead == NULL) { + return ; + } + + Link = ListHead; + + // + // Free all the resources in the interrupt list + // + SavedLink = Link->ForwardLink; + while (!IsListEmpty (ListHead)) { + + Link = SavedLink; + + SavedLink = Link->ForwardLink; + + pNode = INTERRUPT_LIST_FROM_LINK (Link); + + RemoveEntryList (&pNode->Link); + + SavedQH = pNode->PtrQH; + for (PtrQH = SavedQH; PtrQH != NULL; PtrQH = SavedQH) { + SavedQH = PtrQH->ptrNextIntQH; + UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT)); + } + + PtrTD = pNode->PtrFirstTD; + while (PtrTD != NULL) { + + ptrNextTD = PtrTD->ptrNextTD; + UhciFreePool (HcDev, (UINT8 *) PtrTD, sizeof (TD_STRUCT)); + PtrTD = ptrNextTD; + } + + gBS->FreePool (pNode); + } +} + + +EFI_STATUS +InitializeMemoryManagement ( + IN USB_HC_DEV *HcDev + ) +/*++ + +Routine Description: + + Initialize Memory Management + +Arguments: + + HcDev - USB_HC_DEV + +Returns: + + EFI_SUCCESS - Success +--*/ +{ + MEMORY_MANAGE_HEADER *MemoryHeader; + EFI_STATUS Status; + UINTN MemPages; + + MemPages = NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES; + Status = CreateMemoryBlock (HcDev, &MemoryHeader, MemPages); + if (EFI_ERROR (Status)) { + return Status; + } + + HcDev->MemoryHeader = MemoryHeader; + + return EFI_SUCCESS; +} + +EFI_STATUS +CreateMemoryBlock ( + IN USB_HC_DEV *HcDev, + OUT MEMORY_MANAGE_HEADER **MemoryHeader, + IN UINTN MemoryBlockSizeInPages + ) +/*++ + +Routine Description: + + Use PciIo->AllocateBuffer to allocate common buffer for the memory block, + and use PciIo->Map to map the common buffer for Bus Master Read/Write. + + +Arguments: + + HcDev - USB_HC_DEV + MemoryHeader - MEMORY_MANAGE_HEADER to output + MemoryBlockSizeInPages - MemoryBlockSizeInPages +Returns: + + EFI_SUCCESS - Success +--*/ +{ + EFI_STATUS Status; + VOID *CommonBuffer; + EFI_PHYSICAL_ADDRESS MappedAddress; + UINTN MemoryBlockSizeInBytes; + VOID *Mapping; + + // + // Allocate memory for MemoryHeader + // + *MemoryHeader = AllocateZeroPool (sizeof (MEMORY_MANAGE_HEADER)); + if (*MemoryHeader == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + (*MemoryHeader)->Next = NULL; + + // + // set Memory block size + // + (*MemoryHeader)->MemoryBlockSizeInBytes = EFI_PAGES_TO_SIZE (MemoryBlockSizeInPages); + + // + // each bit in Bit Array will manage 32 bytes memory in memory block + // + (*MemoryHeader)->BitArraySizeInBytes = ((*MemoryHeader)->MemoryBlockSizeInBytes / 32) / 8; + + // + // Allocate memory for BitArray + // + (*MemoryHeader)->BitArrayPtr = AllocateZeroPool ((*MemoryHeader)->BitArraySizeInBytes); + if ((*MemoryHeader)->BitArrayPtr == NULL) { + gBS->FreePool (*MemoryHeader); + return EFI_OUT_OF_RESOURCES; + } + + // + // Memory Block uses MemoryBlockSizeInPages pages, + // and it is allocated as common buffer use. + // + Status = HcDev->PciIo->AllocateBuffer ( + HcDev->PciIo, + AllocateAnyPages, + EfiBootServicesData, + MemoryBlockSizeInPages, + &CommonBuffer, + 0 + ); + if (EFI_ERROR (Status)) { + gBS->FreePool ((*MemoryHeader)->BitArrayPtr); + gBS->FreePool (*MemoryHeader); + return Status; + } + + MemoryBlockSizeInBytes = EFI_PAGES_TO_SIZE (MemoryBlockSizeInPages); + Status = HcDev->PciIo->Map ( + HcDev->PciIo, + EfiPciIoOperationBusMasterCommonBuffer, + CommonBuffer, + &MemoryBlockSizeInBytes, + &MappedAddress, + &Mapping + ); + // + // if returned Mapped size is less than the size we request,do not support. + // + if (EFI_ERROR (Status) || (MemoryBlockSizeInBytes != EFI_PAGES_TO_SIZE (MemoryBlockSizeInPages))) { + HcDev->PciIo->FreeBuffer (HcDev->PciIo, MemoryBlockSizeInPages, CommonBuffer); + gBS->FreePool ((*MemoryHeader)->BitArrayPtr); + gBS->FreePool (*MemoryHeader); + return EFI_UNSUPPORTED; + } + // + // Set Memory block initial address + // + (*MemoryHeader)->MemoryBlockPtr = (UINT8 *) ((UINTN) MappedAddress); + (*MemoryHeader)->Mapping = Mapping; + + ZeroMem ( + (*MemoryHeader)->MemoryBlockPtr, + EFI_PAGES_TO_SIZE (MemoryBlockSizeInPages) + ); + + return EFI_SUCCESS; +} + +EFI_STATUS +FreeMemoryHeader ( + IN USB_HC_DEV *HcDev, + IN MEMORY_MANAGE_HEADER *MemoryHeader + ) +/*++ + +Routine Description: + + Free Memory Header + +Arguments: + + HcDev - USB_HC_DEV + MemoryHeader - MemoryHeader to be freed + +Returns: + + EFI_INVALID_PARAMETER - Parameter is error + EFI_SUCCESS - Success + +--*/ +{ + if ((MemoryHeader == NULL) || (HcDev == NULL)) { + return EFI_INVALID_PARAMETER; + } + // + // unmap the common buffer used by the memory block + // + HcDev->PciIo->Unmap (HcDev->PciIo, MemoryHeader->Mapping); + + // + // free common buffer + // + HcDev->PciIo->FreeBuffer ( + HcDev->PciIo, + EFI_SIZE_TO_PAGES (MemoryHeader->MemoryBlockSizeInBytes), + MemoryHeader->MemoryBlockPtr + ); + // + // free bit array + // + gBS->FreePool (MemoryHeader->BitArrayPtr); + // + // free memory header + // + gBS->FreePool (MemoryHeader); + + return EFI_SUCCESS; +} + +EFI_STATUS +UhciAllocatePool ( + IN USB_HC_DEV *HcDev, + OUT UINT8 **Pool, + IN UINTN AllocSize + ) +/*++ + +Routine Description: + + Uhci Allocate Pool + +Arguments: + + HcDev - USB_HC_DEV + Pool - Place to store pointer to the memory buffer + AllocSize - Alloc Size + +Returns: + + EFI_SUCCESS - Success + +--*/ +{ + MEMORY_MANAGE_HEADER *MemoryHeader; + MEMORY_MANAGE_HEADER *TempHeaderPtr; + MEMORY_MANAGE_HEADER *NewMemoryHeader; + UINTN RealAllocSize; + UINTN MemoryBlockSizeInPages; + EFI_STATUS Status; + + *Pool = NULL; + + MemoryHeader = HcDev->MemoryHeader; + ASSERT (MemoryHeader != NULL); + + // + // allocate unit is 32 bytes (align on 32 byte) + // + if (AllocSize & 0x1F) { + RealAllocSize = (AllocSize / 32 + 1) * 32; + } else { + RealAllocSize = AllocSize; + } + + // + // There may be linked MemoryHeaders. + // To allocate a free pool in Memory blocks, + // must search in the MemoryHeader link list + // until enough free pool is found. + // + Status = EFI_NOT_FOUND; + for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL; + TempHeaderPtr = TempHeaderPtr->Next) { + + Status = AllocMemInMemoryBlock ( + TempHeaderPtr, + (VOID **) Pool, + RealAllocSize / 32 + ); + if (!EFI_ERROR (Status)) { + ZeroMem (*Pool, AllocSize); + 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 > EFI_PAGES_TO_SIZE (NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES)) { + MemoryBlockSizeInPages = EFI_SIZE_TO_PAGES (RealAllocSize) + 1; + } else { + MemoryBlockSizeInPages = NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES; + } + + Status = CreateMemoryBlock (HcDev, &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 + ); + + if (!EFI_ERROR (Status)) { + ZeroMem (*Pool, AllocSize); + } + + return Status; +} + +VOID +UhciFreePool ( + IN USB_HC_DEV *HcDev, + IN UINT8 *Pool, + IN UINTN AllocSize + ) +/*++ + +Routine Description: + + Uhci Free Pool + +Arguments: + + HcDev - USB_HC_DEV + Pool - Pool to free + AllocSize - Pool size + +Returns: + + VOID + +--*/ +{ + MEMORY_MANAGE_HEADER *MemoryHeader; + MEMORY_MANAGE_HEADER *TempHeaderPtr; + UINTN StartBytePos; + UINTN Index; + UINT8 StartBitPos; + UINT8 Index2; + UINTN Count; + UINTN RealAllocSize; + + MemoryHeader = HcDev->MemoryHeader; + + // + // allocate unit is 32 byte (align on 32 byte) + // + if (AllocSize & 0x1F) { + RealAllocSize = (AllocSize / 32 + 1) * 32; + } else { + RealAllocSize = AllocSize; + } + // + // scan the memory header linked list for + // the asigned memory to free. + // + 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) & 0x7); + + // + // reset associated bits in bit arry + // + for (Index = StartBytePos, Index2 = StartBitPos, Count = 0; Count < (RealAllocSize / 32); Count++) { + + TempHeaderPtr->BitArrayPtr[Index] ^= (UINT8) (bit (Index2)); + Index2++; + if (Index2 == 8) { + Index += 1; + Index2 = 0; + } + } + // + // break the loop + // + break; + } + } + + // + // Release emptied memory blocks (only if the memory block is not + // the first one in the memory header list + // + for (TempHeaderPtr = MemoryHeader->Next; TempHeaderPtr != NULL;) { + // + // Debug + // + ASSERT (MemoryHeader->Next != NULL); + + if (IsMemoryBlockEmptied (TempHeaderPtr)) { + + DelinkMemoryBlock (MemoryHeader, TempHeaderPtr); + // + // when the TempHeaderPtr is freed in FreeMemoryHeader(), + // the TempHeaderPtr is pointing to nonsense content. + // + FreeMemoryHeader (HcDev, TempHeaderPtr); + // + // reset the TempHeaderPtr, continue search for + // another empty memory block. + // + TempHeaderPtr = MemoryHeader->Next; + continue; + } + + TempHeaderPtr = TempHeaderPtr->Next; + } +} + +VOID +InsertMemoryHeaderToList ( + IN MEMORY_MANAGE_HEADER *MemoryHeader, + IN MEMORY_MANAGE_HEADER *NewMemoryHeader + ) +/*++ + +Routine Description: + + Insert Memory Header To List + +Arguments: + + MemoryHeader - MEMORY_MANAGE_HEADER + NewMemoryHeader - MEMORY_MANAGE_HEADER + +Returns: + + VOID + +--*/ +{ + MEMORY_MANAGE_HEADER *TempHeaderPtr; + + for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL; + TempHeaderPtr = TempHeaderPtr->Next) { + if (TempHeaderPtr->Next == NULL) { + TempHeaderPtr->Next = NewMemoryHeader; + break; + } + } +} + +EFI_STATUS +AllocMemInMemoryBlock ( + IN MEMORY_MANAGE_HEADER *MemoryHeader, + OUT VOID **Pool, + IN UINTN NumberOfMemoryUnit + ) +/*++ + +Routine Description: + + Alloc Memory In MemoryBlock + +Arguments: + + MemoryHeader - MEMORY_MANAGE_HEADER + Pool - Place to store pointer to memory + NumberOfMemoryUnit - Number Of Memory Unit + +Returns: + + EFI_NOT_FOUND - Can't find the free memory + EFI_SUCCESS - Success + +--*/ +{ + 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); + // + // right shift the byte + // + ByteValue /= 2; + + 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; + } + } + // + // 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] & bit (0)) != 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] |= bit (Index); + Index++; + if (Index == 8) { + TempBytePos += 1; + Index = 0; + } + } + + *Pool = MemoryHeader->MemoryBlockPtr + (FoundBytePos * 8 + FoundBitPos) * 32; + + return EFI_SUCCESS; +} + +BOOLEAN +IsMemoryBlockEmptied ( + IN MEMORY_MANAGE_HEADER *MemoryHeaderPtr + ) +/*++ + +Routine Description: + + Is Memory Block Emptied + +Arguments: + + MemoryHeaderPtr - MEMORY_MANAGE_HEADER + +Returns: + + TRUE - Empty + FALSE - Not Empty + +--*/ +{ + UINTN Index; + + for (Index = 0; Index < MemoryHeaderPtr->BitArraySizeInBytes; Index++) { + if (MemoryHeaderPtr->BitArrayPtr[Index] != 0) { + return FALSE; + } + } + + return TRUE; +} + +VOID +DelinkMemoryBlock ( + IN MEMORY_MANAGE_HEADER *FirstMemoryHeader, + IN MEMORY_MANAGE_HEADER *NeedFreeMemoryHeader + ) +/*++ + +Routine Description: + + Delink Memory Block + +Arguments: + + FirstMemoryHeader - MEMORY_MANAGE_HEADER + NeedFreeMemoryHeader - MEMORY_MANAGE_HEADER + +Returns: + + VOID + +--*/ +{ + MEMORY_MANAGE_HEADER *TempHeaderPtr; + + if ((FirstMemoryHeader == NULL) || (NeedFreeMemoryHeader == NULL)) { + return ; + } + for (TempHeaderPtr = FirstMemoryHeader; TempHeaderPtr != NULL; + TempHeaderPtr = TempHeaderPtr->Next) { + + if (TempHeaderPtr->Next == NeedFreeMemoryHeader) { + // + // Link the before and after + // + TempHeaderPtr->Next = NeedFreeMemoryHeader->Next; + break; + } + } +} + +EFI_STATUS +DelMemoryManagement ( + IN USB_HC_DEV *HcDev + ) +/*++ + +Routine Description: + + Delete Memory Management + +Arguments: + + HcDev - USB_HC_DEV + +Returns: + + EFI_SUCCESS - Success + +--*/ +{ + MEMORY_MANAGE_HEADER *TempHeaderPtr; + + for (TempHeaderPtr = HcDev->MemoryHeader->Next; TempHeaderPtr != NULL;) { + + DelinkMemoryBlock (HcDev->MemoryHeader, TempHeaderPtr); + // + // when the TempHeaderPtr is freed in FreeMemoryHeader(), + // the TempHeaderPtr is pointing to nonsense content. + // + FreeMemoryHeader (HcDev, TempHeaderPtr); + // + // reset the TempHeaderPtr,continue free another memory block. + // + TempHeaderPtr = HcDev->MemoryHeader->Next; + } + + FreeMemoryHeader (HcDev, HcDev->MemoryHeader); + + return EFI_SUCCESS; +} + + +VOID +CleanUsbTransactions ( + IN USB_HC_DEV *HcDev + ) +{ + // + // only asynchronous interrupt transfers are always alive on the bus + // + ReleaseInterruptList (HcDev, &(HcDev->InterruptListHead)); +} + +VOID +TurnOffUSBEmulation ( + IN EFI_PCI_IO_PROTOCOL *PciIo + ) +/*++ + + Routine Description: + Disable USB Emulation + Arguments: + PciIo - EFI_PCI_IO_PROTOCOL + Returns: + VOID +--*/ +{ + UINT16 Command; + + // + // Disable USB Emulation + // + Command = 0; + PciIo->Pci.Write ( + PciIo, + EfiPciIoWidthUint16, + USB_EMULATION, + 1, + &Command + ); + + return ; +} diff --git a/EdkModulePkg/Bus/Pci/Uhci/Dxe/uhci.c b/EdkModulePkg/Bus/Pci/Uhci/Dxe/uhci.c new file mode 100644 index 0000000000..1eba8bed5b --- /dev/null +++ b/EdkModulePkg/Bus/Pci/Uhci/Dxe/uhci.c @@ -0,0 +1,3498 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Uhci.c + +Abstract: + + +Revision History +--*/ + +#include "uhci.h" + +// +// Prototypes +// Driver model protocol interface +// + +EFI_STATUS +EFIAPI +UHCIDriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +EFI_STATUS +EFIAPI +UHCIDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +UHCIDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +UHCIDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +// +// UHCI interface functions +// + +EFI_STATUS +EFIAPI +UHCIReset ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT16 Attributes + ); + +EFI_STATUS +EFIAPI +UHCIGetState ( + IN EFI_USB_HC_PROTOCOL *This, + OUT EFI_USB_HC_STATE *State + ); + +EFI_STATUS +EFIAPI +UHCISetState ( + IN EFI_USB_HC_PROTOCOL *This, + IN EFI_USB_HC_STATE State + ); + +EFI_STATUS +EFIAPI +UHCIControlTransfer ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN BOOLEAN IsSlowDevice, + 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 + ); + +EFI_STATUS +EFIAPI +UHCIBulkTransfer ( + IN EFI_USB_HC_PROTOCOL *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 + ); + +EFI_STATUS +EFIAPI +UHCIAsyncInterruptTransfer ( + IN EFI_USB_HC_PROTOCOL * This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN BOOLEAN IsSlowDevice, + IN UINT8 MaxiumPacketLength, + IN BOOLEAN IsNewTransfer, + IN OUT UINT8 *DataToggle, + IN UINTN PollingInterval, OPTIONAL + IN UINTN DataLength, OPTIONAL + IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction, OPTIONAL + IN VOID *Context OPTIONAL + ); + +EFI_STATUS +EFIAPI +UHCISyncInterruptTransfer ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN BOOLEAN IsSlowDevice, + IN UINT8 MaximumPacketLength, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN OUT UINT8 *DataToggle, + IN UINTN TimeOut, + OUT UINT32 *TransferResult + ); + +EFI_STATUS +EFIAPI +UHCIIsochronousTransfer ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 MaximumPacketLength, + IN OUT VOID *Data, + IN UINTN DataLength, + OUT UINT32 *TransferResult + ); + +EFI_STATUS +EFIAPI +UHCIAsyncIsochronousTransfer ( + IN EFI_USB_HC_PROTOCOL * This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 MaximumPacketLength, + IN OUT VOID *Data, + IN UINTN DataLength, + IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack, + IN VOID *Context OPTIONAL + ); + +EFI_STATUS +EFIAPI +UHCIGetRootHubPortNumber ( + IN EFI_USB_HC_PROTOCOL *This, + OUT UINT8 *PortNumber + ); + +EFI_STATUS +EFIAPI +UHCIGetRootHubPortStatus ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 PortNumber, + OUT EFI_USB_PORT_STATUS *PortStatus + ); + +EFI_STATUS +EFIAPI +UHCISetRootHubPortFeature ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 PortNumber, + IN EFI_USB_PORT_FEATURE PortFeature + ); + +EFI_STATUS +EFIAPI +UHCIClearRootHubPortFeature ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 PortNumber, + IN EFI_USB_PORT_FEATURE PortFeature + ); + +// +// Asynchronous interrupt transfer monitor function +// +VOID +EFIAPI +MonitorInterruptTrans ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +// +// UHCI Driver Global Variables +// +EFI_DRIVER_BINDING_PROTOCOL gUhciDriverBinding = { + UHCIDriverBindingSupported, + UHCIDriverBindingStart, + UHCIDriverBindingStop, + 0x10, + NULL, + NULL +}; + +EFI_STATUS +EFIAPI +UHCIDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + Test to see if this driver supports ControllerHandle. Any ControllerHandle + that has UsbHcProtocol installed will be supported. + + Arguments: + This - Protocol instance pointer. + Controller, - Handle of device to test + RemainingDevicePath - Not used + + Returns: + EFI_SUCCESS - This driver supports this device. + EFI_UNSUPPORTED - This driver does not support this device. + +--*/ +{ + 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, + CLASSC, + sizeof (USB_CLASSC) / sizeof (UINT8), + &UsbClassCReg + ); + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return EFI_UNSUPPORTED; + } + // + // Test whether the controller belongs to UHCI type + // + if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) || + (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) || + (UsbClassCReg.PI != PCI_CLASSC_PI_UHCI)) { + + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return EFI_UNSUPPORTED; + } + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return EFI_SUCCESS; + +} + +EFI_STATUS +EFIAPI +UHCIDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + Starting the Usb UHCI Driver + + Arguments: + This - Protocol instance pointer. + Controller - Handle of device to test + RemainingDevicePath - Not used + + Returns: + EFI_SUCCESS - This driver supports this device. + EFI_UNSUPPORTED - This driver does not support this device. + EFI_DEVICE_ERROR - This driver cannot be started due to device + Error + EFI_OUT_OF_RESOURCES + +--*/ +{ + EFI_STATUS Status; + UINTN FlBaseAddrReg; + EFI_PCI_IO_PROTOCOL *PciIo; + USB_HC_DEV *HcDev; + + HcDev = NULL; + + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Turn off USB emulation + // + TurnOffUSBEmulation (PciIo); + + // + // Enable the USB Host Controller + // + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationEnable, + EFI_PCI_DEVICE_ENABLE, + NULL + ); + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return EFI_UNSUPPORTED; + } + + // + // allocate memory for UHC private data structure + // + HcDev = AllocateZeroPool (sizeof (USB_HC_DEV)); + if (HcDev == NULL) { + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return EFI_OUT_OF_RESOURCES; + } + + // + // init EFI_USB_HC_PROTOCOL protocol interface and install the protocol + // + HcDev->UsbHc.Reset = UHCIReset; + HcDev->UsbHc.GetState = UHCIGetState; + HcDev->UsbHc.SetState = UHCISetState; + HcDev->UsbHc.ControlTransfer = UHCIControlTransfer; + HcDev->UsbHc.BulkTransfer = UHCIBulkTransfer; + HcDev->UsbHc.AsyncInterruptTransfer = UHCIAsyncInterruptTransfer; + HcDev->UsbHc.SyncInterruptTransfer = UHCISyncInterruptTransfer; + HcDev->UsbHc.IsochronousTransfer = UHCIIsochronousTransfer; + HcDev->UsbHc.AsyncIsochronousTransfer = UHCIAsyncIsochronousTransfer; + HcDev->UsbHc.GetRootHubPortNumber = UHCIGetRootHubPortNumber; + HcDev->UsbHc.GetRootHubPortStatus = UHCIGetRootHubPortStatus; + HcDev->UsbHc.SetRootHubPortFeature = UHCISetRootHubPortFeature; + HcDev->UsbHc.ClearRootHubPortFeature = UHCIClearRootHubPortFeature; + + HcDev->UsbHc.MajorRevision = 0x1; + HcDev->UsbHc.MinorRevision = 0x1; + + // + // Init UHCI private data structures + // + HcDev->Signature = USB_HC_DEV_SIGNATURE; + HcDev->PciIo = PciIo; + + FlBaseAddrReg = USBFLBASEADD; + + // + // Allocate and Init Host Controller's Frame List Entry + // + Status = CreateFrameList (HcDev, (UINT32) FlBaseAddrReg); + if (EFI_ERROR (Status)) { + + if (HcDev != NULL) { + gBS->FreePool (HcDev); + } + + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return EFI_OUT_OF_RESOURCES; + } + + // + // Init interrupt list head in the HcDev structure. + // + InitializeListHead (&(HcDev->InterruptListHead)); + + // + // Create timer for interrupt transfer result polling + // + Status = gBS->CreateEvent ( + EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL, + EFI_TPL_NOTIFY, + MonitorInterruptTrans, + HcDev, + &HcDev->InterruptTransTimer + ); + if (EFI_ERROR (Status)) { + + FreeFrameListEntry (HcDev); + + if (HcDev != NULL) { + gBS->FreePool (HcDev); + } + + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return EFI_UNSUPPORTED; + } + + // + // Here set interrupt transfer polling timer in 50ms unit. + // + Status = gBS->SetTimer ( + HcDev->InterruptTransTimer, + TimerPeriodic, + INTERRUPT_POLLING_TIME + ); + if (EFI_ERROR (Status)) { + gBS->CloseEvent (HcDev->InterruptTransTimer); + + FreeFrameListEntry (HcDev); + + if (HcDev != NULL) { + gBS->FreePool (HcDev); + } + + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return EFI_UNSUPPORTED; + } + + // + // QH,TD structures must in common buffer that will be + // accessed by both cpu and usb bus master at the same time. + // so, there must has memory management for QH,TD structures. + // + Status = InitializeMemoryManagement (HcDev); + if (EFI_ERROR (Status)) { + + gBS->CloseEvent (HcDev->InterruptTransTimer); + + FreeFrameListEntry (HcDev); + + if (HcDev != NULL) { + gBS->FreePool (HcDev); + } + + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return Status; + } + + // + // Install Host Controller Protocol + // + Status = gBS->InstallProtocolInterface ( + &Controller, + &gEfiUsbHcProtocolGuid, + EFI_NATIVE_INTERFACE, + &HcDev->UsbHc + ); + if (EFI_ERROR (Status)) { + gBS->CloseEvent (HcDev->InterruptTransTimer); + FreeFrameListEntry (HcDev); + DelMemoryManagement (HcDev); + + if (HcDev != NULL) { + gBS->FreePool (HcDev); + } + + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return Status; + } + + // + // component name protocol. + // + HcDev->ControllerNameTable = NULL; + AddUnicodeString ( + "eng", + gUhciComponentName.SupportedLanguages, + &HcDev->ControllerNameTable, + (CHAR16 *) L"Usb Universal Host Controller" + ); + + return EFI_SUCCESS; +} + + +EFI_STATUS +UnInstallUHCInterface ( + IN EFI_HANDLE Controller, + IN EFI_USB_HC_PROTOCOL *This + ) +/*++ + Routine Description: + UnInstall UHCInterface + Arguments: + Controller - Controller handle + This - Protocol instance pointer. + Returns: + EFI_SUCCESS + others +--*/ +{ + USB_HC_DEV *HcDev; + + HcDev = USB_HC_DEV_FROM_THIS (This); + + gBS->UninstallProtocolInterface ( + Controller, + &gEfiUsbHcProtocolGuid, + &HcDev->UsbHc + ); + + // + // first stop USB Host Controller + // + This->SetState (This, EfiUsbHcStateHalt); + + // + // Delete interrupt transfer polling timer + // + gBS->CloseEvent (HcDev->InterruptTransTimer); + + // + // Delete all the asynchronous interrupt transfers in the interrupt list + // and free associated memory + // + ReleaseInterruptList (HcDev, &(HcDev->InterruptListHead)); + + // + // free Frame List Entry. + // + FreeFrameListEntry (HcDev); + + // + // Free common buffer allocated for QH,TD structures + // + DelMemoryManagement (HcDev); + + if (HcDev->ControllerNameTable) { + FreeUnicodeStringTable (HcDev->ControllerNameTable); + } + // + // Disable the USB Host Controller + // + HcDev->PciIo->Attributes ( + HcDev->PciIo, + EfiPciIoAttributeOperationDisable, + EFI_PCI_DEVICE_ENABLE, + NULL + ); + + gBS->FreePool (HcDev); + + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +UHCIDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + + Routine Description: + Stop this driver on ControllerHandle. Support stoping any child handles + created by this driver. + + Arguments: + This - Protocol instance pointer. + Controller - Handle of device to stop driver on + NumberOfChildren - Number of Children in the ChildHandleBuffer + ChildHandleBuffer - List of handles for the children we need to stop. + + Returns: + EFI_SUCCESS + others + +--*/ +{ + EFI_USB_HC_PROTOCOL *UsbHc; + EFI_STATUS OpenStatus; + + OpenStatus = gBS->OpenProtocol ( + Controller, + &gEfiUsbHcProtocolGuid, + (VOID **) &UsbHc, + 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 (OpenStatus)) { + return OpenStatus; + } + // + // free all the controller related memory and uninstall UHCI Protocol. + // + UnInstallUHCInterface (Controller, UsbHc); + + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return EFI_SUCCESS; + +} + + +EFI_STATUS +EFIAPI +UHCIReset ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT16 Attributes + ) +/*++ + + Routine Description: + Provides software reset for the USB host controller. + + Arguments: + + This A pointer to the EFI_USB_HC_PROTOCOL instance. + + Attributes A bit mask of the reset operation to perform. + See below for a list of the supported bit mask values. + + #define EFI_USB_HC_RESET_GLOBAL 0x0001 + #define EFI_USB_HC_RESET_HOST_CONTROLLER 0x0002 + + EFI_USB_HC_RESET_GLOBAL + If this bit is set, a global reset signal will be sent to the USB bus. + This resets all of the USB bus logic, including the USB host + controller hardware and all the devices attached on the USB bus. + EFI_USB_HC_RESET_HOST_CONTROLLER + If this bit is set, the USB host controller hardware will be reset. + No reset signal will be sent to the USB bus. + + Returns: + EFI_SUCCESS + The reset operation succeeded. + EFI_INVALID_PARAMETER + Attributes is not valid. + EFI_DEVICE_ERROR + An error was encountered while attempting to perform + the reset operation. +--*/ +{ + BOOLEAN Match; + USB_HC_DEV *HcDev; + UINT32 CommandRegAddr; + UINT32 FlBaseAddrReg; + UINT16 Command; + EFI_STATUS Status; + + Match = FALSE; + HcDev = USB_HC_DEV_FROM_THIS (This); + + CommandRegAddr = (UINT32) (USBCMD); + FlBaseAddrReg = (UINT32) (USBFLBASEADD); + + if ((Attributes & EFI_USB_HC_RESET_GLOBAL) != 0) { + Match = TRUE; + // + // set the Global Reset bit in the command register + // + Status = ReadUHCCommandReg ( + HcDev->PciIo, + CommandRegAddr, + &Command + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + Command |= USBCMD_GRESET; + Status = WriteUHCCommandReg ( + HcDev->PciIo, + CommandRegAddr, + Command + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Wait 50ms for root port to let reset complete + // See UHCI spec page122 Reset signaling + // + gBS->Stall (ROOT_PORT_REST_TIME); + + // + // Clear the Global Reset bit to zero. + // + Command &= ~USBCMD_GRESET; + Status = WriteUHCCommandReg ( + HcDev->PciIo, + CommandRegAddr, + Command + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + // + // UHCI spec page120 reset recovery time + // + gBS->Stall (PORT_RESET_RECOVERY_TIME); + } + + if ((Attributes & EFI_USB_HC_RESET_HOST_CONTROLLER) != 0) { + Match = TRUE; + // + // set Host Controller Reset bit to 1 + // + Status = ReadUHCCommandReg ( + HcDev->PciIo, + CommandRegAddr, + &Command + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + Command |= USBCMD_HCRESET; + Status = WriteUHCCommandReg ( + HcDev->PciIo, + CommandRegAddr, + Command + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + // + // this bit will be reset by Host Controller when reset is completed. + // wait 10ms to let reset complete + // + gBS->Stall (PORT_RESET_RECOVERY_TIME); + } + + if (!Match) { + return EFI_INVALID_PARAMETER; + } + + // + // Delete all old transactions on the USB bus + // + CleanUsbTransactions (HcDev); + + // + // Initialize Universal Host Controller's Frame List Data Structure + // + InitFrameList (HcDev); + + // + // Reset may cause Frame List Base Address Register reset to zero, + // so set the original value back again. + // + SetFrameListBaseAddress ( + HcDev->PciIo, + FlBaseAddrReg, + (UINT32) ((UINTN) HcDev->FrameListEntry) + ); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +UHCIGetState ( + IN EFI_USB_HC_PROTOCOL *This, + OUT EFI_USB_HC_STATE *State + ) +/*++ + + Routine Description: + Retrieves current state of the USB host controller. + + Arguments: + + This A pointer to the EFI_USB_HC_PROTOCOL instance. + + State A pointer to the EFI_USB_HC_STATE data structure that + indicates current state of the USB host controller. + Type EFI_USB_HC_STATE is defined below. + + typedef enum { + EfiUsbHcStateHalt, + EfiUsbHcStateOperational, + EfiUsbHcStateSuspend, + EfiUsbHcStateMaximum + } EFI_USB_HC_STATE; + + Returns: + EFI_SUCCESS + The state information of the host controller was returned in State. + EFI_INVALID_PARAMETER + State is NULL. + EFI_DEVICE_ERROR + An error was encountered while attempting to retrieve the + host controller's current state. +--*/ +{ + USB_HC_DEV *HcDev; + UINT32 CommandRegAddr; + UINT32 StatusRegAddr; + UINT16 UhcCommand; + UINT16 UhcStatus; + EFI_STATUS Status; + + if (State == NULL) { + return EFI_INVALID_PARAMETER; + } + + HcDev = USB_HC_DEV_FROM_THIS (This); + + CommandRegAddr = (UINT32) (USBCMD); + StatusRegAddr = (UINT32) (USBSTS); + + Status = ReadUHCCommandReg ( + HcDev->PciIo, + CommandRegAddr, + &UhcCommand + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + Status = ReadUHCCommandReg ( + HcDev->PciIo, + StatusRegAddr, + &UhcStatus + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + if (UhcCommand & USBCMD_EGSM) { + *State = EfiUsbHcStateSuspend; + return EFI_SUCCESS; + } + + if ((UhcStatus & USBSTS_HCH) == 0) { + *State = EfiUsbHcStateOperational; + } else { + *State = EfiUsbHcStateHalt; + } + + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +UHCISetState ( + IN EFI_USB_HC_PROTOCOL *This, + IN EFI_USB_HC_STATE State + ) +/*++ + + Routine Description: + Sets the USB host controller to a specific state. + + Arguments: + + This A pointer to the EFI_USB_HC_PROTOCOL instance. + + State Indicates the state of the host controller that will be set. + + Returns: + EFI_SUCCESS + The USB host controller was successfully placed in the state + specified by State. + EFI_INVALID_PARAMETER + State is invalid. + EFI_DEVICE_ERROR + Failed to set the state specified by State due to device error. +--*/ +{ + USB_HC_DEV *HcDev; + UINT32 CommandRegAddr; + UINT32 StatusRegAddr; + UINT16 Command; + EFI_USB_HC_STATE CurrentState; + EFI_STATUS Status; + + HcDev = USB_HC_DEV_FROM_THIS (This); + + CommandRegAddr = (UINT32) (USBCMD); + StatusRegAddr = (UINT32) (USBSTS); + + Status = UHCIGetState (This, &CurrentState); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + switch (State) { + + case EfiUsbHcStateHalt: + if (CurrentState == EfiUsbHcStateHalt) { + return EFI_SUCCESS; + } + + Status = ReadUHCCommandReg ( + HcDev->PciIo, + CommandRegAddr, + &Command + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + Command &= ~USBCMD_RS; + + Status = WriteUHCCommandReg ( + HcDev->PciIo, + CommandRegAddr, + Command + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + StatusRegAddr = (UINT32) (USBSTS); + // + // ensure the HC is in halt status after send the stop command + // + if (WaitForUHCHalt (HcDev->PciIo, StatusRegAddr, STALL_1_SECOND) == EFI_TIMEOUT) { + return EFI_DEVICE_ERROR; + } + break; + + case EfiUsbHcStateOperational: + if (IsHostSysOrProcessErr (HcDev->PciIo, StatusRegAddr)) { + return EFI_DEVICE_ERROR; + } + + switch (CurrentState) { + + case EfiUsbHcStateOperational: + return EFI_SUCCESS; + + case EfiUsbHcStateHalt: + // + // Set Run/Stop bit to 1. + // + Status = ReadUHCCommandReg ( + HcDev->PciIo, + CommandRegAddr, + &Command + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + Command |= USBCMD_RS | USBCMD_MAXP; + Status = WriteUHCCommandReg ( + HcDev->PciIo, + CommandRegAddr, + Command + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + break; + + case EfiUsbHcStateSuspend: + Status = ReadUHCCommandReg ( + HcDev->PciIo, + CommandRegAddr, + &Command + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // FGR(Force Global Resume) bit is 0 + // + if ((Command | (~USBCMD_FGR)) != 0xFF) { + // + // Write FGR bit to 1 + // + Command |= USBCMD_FGR; + WriteUHCCommandReg ( + HcDev->PciIo, + CommandRegAddr, + Command + ); + } + + // + // wait 20ms to let resume complete + // (20ms is specified by UHCI spec) + // + gBS->Stall (FORCE_GLOBAL_RESUME_TIME); + + // + // Write FGR bit to 0 and EGSM(Enter Global Suspend Mode) bit to 0 + // + Command &= ~USBCMD_FGR; + Command &= ~USBCMD_EGSM; + Command |= USBCMD_RS; + WriteUHCCommandReg ( + HcDev->PciIo, + CommandRegAddr, + Command + ); + break; + + default: + break; + } + break; + + case EfiUsbHcStateSuspend: + if (CurrentState == EfiUsbHcStateSuspend) { + return EFI_SUCCESS; + } + + Status = UHCISetState (This, EfiUsbHcStateHalt); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + // + // Set Enter Global Suspend Mode bit to 1. + // + Status = ReadUHCCommandReg ( + HcDev->PciIo, + CommandRegAddr, + &Command + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + Command |= USBCMD_EGSM; + Status = WriteUHCCommandReg ( + HcDev->PciIo, + CommandRegAddr, + Command + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + break; + + default: + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +UHCIGetRootHubPortNumber ( + IN EFI_USB_HC_PROTOCOL *This, + OUT UINT8 *PortNumber + ) +/*++ + + Routine Description: + Retrieves the number of root hub ports. + + Arguments: + + This A pointer to the EFI_USB_HC_PROTOCOL instance. + + PortNumber A pointer to the number of the root hub ports. + + Returns: + EFI_SUCCESS + The port number was retrieved successfully. + EFI_INVALID_PARAMETER + PortNumber is NULL. + EFI_DEVICE_ERROR + An error was encountered while attempting to + retrieve the port number. +--*/ +{ + USB_HC_DEV *HcDev; + UINT32 PSAddr; + UINT16 RHPortControl; + UINT32 Index; + EFI_STATUS Status; + + HcDev = USB_HC_DEV_FROM_THIS (This); + + if (PortNumber == NULL) { + return EFI_INVALID_PARAMETER; + } + + *PortNumber = 0; + + for (Index = 0; Index < 2; Index++) { + PSAddr = (UINT32) (USBPORTSC1 + Index * 2); + Status = ReadRootPortReg ( + HcDev->PciIo, + PSAddr, + &RHPortControl + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + // + // Port Register content is valid + // + if (RHPortControl != 0xff) { + (*PortNumber)++; + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +UHCIGetRootHubPortStatus ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 PortNumber, + OUT EFI_USB_PORT_STATUS *PortStatus + ) +/*++ + + Routine Description: + Retrieves the current status of a USB root hub port. + + Arguments: + + This A pointer to the EFI_USB_HC_PROTOCOL. + + PortNumber Specifies the root hub port from which the status + is to be retrieved. This value is zero-based. For example, + if a root hub has two ports, then the first port is numbered 0, + and the second port is numbered 1. + + PortStatus A pointer to the current port status bits and + port status change bits. + + Returns: + EFI_SUCCESS + The status of the USB root hub port specified by PortNumber + was returned in PortStatus. + EFI_INVALID_PARAMETER + PortNumber is invalid. + EFI_DEVICE_ERROR - Can't read register +--*/ +{ + USB_HC_DEV *HcDev; + UINT32 PSAddr; + UINT16 RHPortStatus; + UINT8 TotalPortNumber; + EFI_STATUS Status; + + if (PortStatus == NULL) { + return EFI_INVALID_PARAMETER; + } + + UHCIGetRootHubPortNumber (This, &TotalPortNumber); + if (PortNumber >= TotalPortNumber) { + return EFI_INVALID_PARAMETER; + } + + HcDev = USB_HC_DEV_FROM_THIS (This); + PSAddr = (UINT32) (USBPORTSC1 + PortNumber * 2); + + // + // Clear port status + // + PortStatus->PortStatus = 0; + PortStatus->PortChangeStatus = 0; + + Status = ReadRootPortReg ( + HcDev->PciIo, + PSAddr, + &RHPortStatus + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + // + // Fill Port Status bits + // + + // + // Current Connect Status + // + if (RHPortStatus & USBPORTSC_CCS) { + PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION; + } + // + // Port Enabled/Disabled + // + if (RHPortStatus & USBPORTSC_PED) { + PortStatus->PortStatus |= USB_PORT_STAT_ENABLE; + } + + // + // Port Suspend + // + if (RHPortStatus & USBPORTSC_SUSP) { + PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND; + } + + // + // Port Reset + // + if (RHPortStatus & USBPORTSC_PR) { + PortStatus->PortStatus |= USB_PORT_STAT_RESET; + } + + // + // Low Speed Device Attached + // + if (RHPortStatus & USBPORTSC_LSDA) { + PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED; + } + // + // Fill Port Status Change bits + // + + // + // Connect Status Change + // + if (RHPortStatus & USBPORTSC_CSC) { + PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION; + } + + // + // Port Enabled/Disabled Change + // + if (RHPortStatus & USBPORTSC_PEDC) { + PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +UHCISetRootHubPortFeature ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 PortNumber, + IN EFI_USB_PORT_FEATURE PortFeature + ) +/*++ + + Routine Description: + Sets a feature for the specified root hub port. + + Arguments: + + This A pointer to the EFI_USB_HC_PROTOCOL. + + PortNumber Specifies the root hub port whose feature + is requested to be set. + + PortFeature Indicates the feature selector associated + with the feature set request. + + Returns: + EFI_SUCCESS + The feature specified by PortFeature was set for the + USB root hub port specified by PortNumber. + EFI_INVALID_PARAMETER + PortNumber is invalid or PortFeature is invalid. + EFI_DEVICE_ERROR + Can't read register +--*/ +{ + USB_HC_DEV *HcDev; + UINT32 PSAddr; + UINT32 CommandRegAddr; + // + // root hub port status + // + UINT16 RHPortControl; + UINT16 Command; + UINT8 TotalPortNumber; + EFI_STATUS Status; + + UHCIGetRootHubPortNumber (This, &TotalPortNumber); + if (PortNumber >= TotalPortNumber) { + return EFI_INVALID_PARAMETER; + } + + HcDev = USB_HC_DEV_FROM_THIS (This); + + PSAddr = (UINT32) (USBPORTSC1 + PortNumber * 2); + CommandRegAddr = (UINT32) (USBCMD); + + Status = ReadRootPortReg ( + HcDev->PciIo, + PSAddr, + &RHPortControl + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + switch (PortFeature) { + + case EfiUsbPortSuspend: + Status = ReadUHCCommandReg ( + HcDev->PciIo, + CommandRegAddr, + &Command + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + if (!(Command & USBCMD_EGSM)) { + // + // if global suspend is not active, can set port suspend + // + RHPortControl &= 0xfff5; + RHPortControl |= USBPORTSC_SUSP; + } + break; + + case EfiUsbPortReset: + RHPortControl &= 0xfff5; + // + // Set the reset bit + // + RHPortControl |= USBPORTSC_PR; + break; + + case EfiUsbPortPower: + break; + + case EfiUsbPortEnable: + RHPortControl &= 0xfff5; + RHPortControl |= USBPORTSC_PED; + break; + + default: + return EFI_INVALID_PARAMETER; + } + + WriteRootPortReg ( + HcDev->PciIo, + PSAddr, + RHPortControl + ); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +UHCIClearRootHubPortFeature ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 PortNumber, + IN EFI_USB_PORT_FEATURE PortFeature + ) +/*++ + + Routine Description: + Clears a feature for the specified root hub port. + + Arguments: + + This A pointer to the EFI_USB_HC_PROTOCOL instance. + + PortNumber Specifies the root hub port whose feature + is requested to be cleared. + + PortFeature Indicates the feature selector associated with the + feature clear request. + + Returns: + EFI_SUCCESS + The feature specified by PortFeature was cleared for the + USB root hub port specified by PortNumber. + EFI_INVALID_PARAMETER + PortNumber is invalid or PortFeature is invalid. + EFI_DEVICE_ERROR + Can't read register +--*/ +{ + USB_HC_DEV *HcDev; + UINT32 PSAddr; + UINT16 RHPortControl; + UINT8 TotalPortNumber; + EFI_STATUS Status; + + UHCIGetRootHubPortNumber (This, &TotalPortNumber); + + if (PortNumber >= TotalPortNumber) { + return EFI_INVALID_PARAMETER; + } + + HcDev = USB_HC_DEV_FROM_THIS (This); + PSAddr = (UINT32) (USBPORTSC1 + PortNumber * 2); + + Status = ReadRootPortReg ( + HcDev->PciIo, + PSAddr, + &RHPortControl + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + 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; + } + + WriteRootPortReg ( + HcDev->PciIo, + PSAddr, + RHPortControl + ); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +UHCIControlTransfer ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN BOOLEAN IsSlowDevice, + 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 + ) +/*++ + + Routine Description: + Submits control transfer to a target USB device. + + Arguments: + + This A pointer to the EFI_USB_HC_PROTOCOL instance. + + DeviceAddress Represents the address of the target device on the USB, + which is assigned during USB enumeration. + + IsSlowDevice Indicates whether the target device is slow device + or full-speed device. + + MaximumPacketLength Indicates the maximum packet size that the + default control transfer endpoint is capable of + sending or receiving. + + Request A pointer to the USB device request that will be sent + to the USB device. + + TransferDirection Specifies the data direction for the transfer. + There are three values available, DataIn, DataOut + and NoData. + + Data A pointer to the buffer of data that will be transmitted + to USB device or received from USB device. + + DataLength Indicates the size, in bytes, of the data buffer + specified by Data. + + TimeOut Indicates the maximum time, in microseconds, + which the transfer is allowed to complete. + + TransferResult A pointer to the detailed result information generated + by this control transfer. + + Returns: + EFI_SUCCESS + The control transfer was completed successfully. + EFI_OUT_OF_RESOURCES + The control transfer could not be completed due to a lack of resources. + EFI_INVALID_PARAMETER + Some parameters are invalid. + EFI_TIMEOUT + The control transfer failed due to timeout. + EFI_DEVICE_ERROR + The control transfer failed due to host controller or device error. + Caller should check TranferResult for detailed error information. + +--*/ +{ + USB_HC_DEV *HcDev; + UINT32 StatusReg; + UINT32 FrameNumReg; + UINT8 PktID; + QH_STRUCT *PtrQH; + TD_STRUCT *PtrTD; + TD_STRUCT *PtrPreTD; + TD_STRUCT *PtrSetupTD; + TD_STRUCT *PtrStatusTD; + EFI_STATUS Status; + UINTN Index; + UINTN DataLen; + UINT8 *PtrDataSource; + UINT8 *Ptr; + UINT8 DataToggle; + UINT16 LoadFrameListIndex; + UINT8 PktSize; + + UINT8 *RequestMappedAddress; + VOID *RequestMapping; + UINTN RequestLen; + + EFI_PHYSICAL_ADDRESS TempPtr; + VOID *Mapping; + + TD_STRUCT *PtrFirstDataTD; + TD_STRUCT *ptrLastDataTD; + BOOLEAN FirstTD; + + FirstTD = FALSE; + RequestMappedAddress = NULL; + RequestMapping = NULL; + Mapping = NULL; + PtrFirstDataTD = NULL; + ptrLastDataTD = NULL; + PktID = INPUT_PACKET_ID; + Mapping = NULL; + HcDev = USB_HC_DEV_FROM_THIS (This); + StatusReg = (UINT32) (USBSTS); + FrameNumReg = (UINT32) (USBFRNUM); + PtrPreTD = NULL; + PtrTD = NULL; + + // + // Parameters Checking + // + if (Request == NULL || TransferResult == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // if errors exist that cause host controller halt, + // then return EFI_DEVICE_ERROR. + // + if (!IsStatusOK (HcDev->PciIo, StatusReg)) { + + ClearStatusReg (HcDev->PciIo, StatusReg); + *TransferResult = EFI_USB_ERR_SYSTEM; + return EFI_DEVICE_ERROR; + } + + // + // low speed usb devices are limited to only an eight-byte + // maximum data payload size + // + if (IsSlowDevice && (MaximumPacketLength != 8)) { + return EFI_INVALID_PARAMETER; + } + + if (MaximumPacketLength != 8 && + MaximumPacketLength != 16 && + MaximumPacketLength != 32 && + MaximumPacketLength != 64) { + return EFI_INVALID_PARAMETER; + } + + if ((TransferDirection != EfiUsbNoData) && (DataLength == NULL)) { + return EFI_INVALID_PARAMETER; + } + + switch (TransferDirection) { + + case EfiUsbDataIn: + PktID = INPUT_PACKET_ID; + PtrDataSource = Data; + DataLen = *DataLength; + + // + // map the source data buffer for bus master access. + // BusMasterWrite means cpu read + // + Status = HcDev->PciIo->Map ( + HcDev->PciIo, + EfiPciIoOperationBusMasterWrite, + PtrDataSource, + &DataLen, + &TempPtr, + &Mapping + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Ptr = (UINT8 *) ((UINTN) TempPtr); + break; + + case EfiUsbDataOut: + PktID = OUTPUT_PACKET_ID; + PtrDataSource = Data; + DataLen = *DataLength; + + // + // map the source data buffer for bus master access. + // BusMasterRead means cpu write + // + Status = HcDev->PciIo->Map ( + HcDev->PciIo, + EfiPciIoOperationBusMasterRead, + PtrDataSource, + &DataLen, + &TempPtr, + &Mapping + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Ptr = (UINT8 *) ((UINTN) TempPtr); + break; + + // + // no data stage + // + case EfiUsbNoData: + if ((DataLength != NULL) && (*DataLength != 0)) { + return EFI_INVALID_PARAMETER; + } + + PktID = OUTPUT_PACKET_ID; + PtrDataSource = NULL; + DataLen = 0; + Ptr = NULL; + break; + + default: + return EFI_INVALID_PARAMETER; + } + + Status = ClearStatusReg (HcDev->PciIo, StatusReg); + if (EFI_ERROR (Status)) { + HcDev->PciIo->Unmap (HcDev->PciIo, Mapping); + return EFI_DEVICE_ERROR; + } + // + // create QH structure and init + // + Status = CreateQH (HcDev, &PtrQH); + if (EFI_ERROR (Status)) { + HcDev->PciIo->Unmap (HcDev->PciIo, Mapping); + return Status; + } + + // + // map the Request for bus master access. + // BusMasterRead means cpu write + // + RequestLen = sizeof (EFI_USB_DEVICE_REQUEST); + Status = HcDev->PciIo->Map ( + HcDev->PciIo, + EfiPciIoOperationBusMasterRead, + (UINT8 *) Request, + &RequestLen, + &TempPtr, + &RequestMapping + ); + + if (EFI_ERROR (Status)) { + HcDev->PciIo->Unmap (HcDev->PciIo, Mapping); + UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT)); + return Status; + } + + RequestMappedAddress = (UINT8 *) ((UINTN) TempPtr); + + // + // generate Setup Stage TD + // + Status = GenSetupStageTD ( + HcDev, + DeviceAddress, + 0, + IsSlowDevice, + (UINT8 *) RequestMappedAddress, + sizeof (EFI_USB_DEVICE_REQUEST), + &PtrSetupTD + ); + + if (EFI_ERROR (Status)) { + HcDev->PciIo->Unmap (HcDev->PciIo, Mapping); + UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT)); + HcDev->PciIo->Unmap (HcDev->PciIo, RequestMapping); + return Status; + } + + // + // Data Stage of Control Transfer + // + DataToggle = 1; + FirstTD = TRUE; + while (DataLen > 0) { + // + // create TD structures and link together + // + + // + // PktSize is the data load size that each TD carries. + // + PktSize = (UINT8) DataLen; + if (DataLen > MaximumPacketLength) { + PktSize = MaximumPacketLength; + } + + Status = GenDataTD ( + HcDev, + DeviceAddress, + 0, + Ptr, + PktSize, + PktID, + DataToggle, + IsSlowDevice, + &PtrTD + ); + + if (EFI_ERROR (Status)) { + // + // free all resources occupied + // + HcDev->PciIo->Unmap (HcDev->PciIo, Mapping); + UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT)); + HcDev->PciIo->Unmap (HcDev->PciIo, RequestMapping); + DeleteQueuedTDs (HcDev, PtrSetupTD); + DeleteQueuedTDs (HcDev, PtrFirstDataTD); + return Status; + } + + // + // Link two TDs in vertical depth + // + if (FirstTD) { + PtrFirstDataTD = PtrTD; + PtrFirstDataTD->ptrNextTD = NULL; + FirstTD = FALSE; + } else { + LinkTDToTD (PtrPreTD, PtrTD); + } + + PtrPreTD = PtrTD; + + DataToggle ^= 1; + Ptr += PktSize; + DataLen -= PktSize; + } + + ptrLastDataTD = 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 + // + Status = CreateStatusTD ( + HcDev, + DeviceAddress, + 0, + PktID, + IsSlowDevice, + &PtrStatusTD + ); + + if (EFI_ERROR (Status)) { + HcDev->PciIo->Unmap (HcDev->PciIo, Mapping); + UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT)); + HcDev->PciIo->Unmap (HcDev->PciIo, RequestMapping); + DeleteQueuedTDs (HcDev, PtrSetupTD); + DeleteQueuedTDs (HcDev, PtrFirstDataTD); + return Status; + } + + if (IsSlowDevice) { + // + // link setup TD structures to QH structure + // + LinkTDToQH (PtrQH, PtrSetupTD); + + LoadFrameListIndex = (UINT16) ((GetCurrentFrameNumber (HcDev->PciIo, FrameNumReg)) & 0x3FF); + + // + // link QH-TDs to total 100 frame list entry to speed up the execution. + // + for (Index = 0; Index < 100; Index++) { + LinkQHToFrameList ( + HcDev->FrameListEntry, + (UINT16) ((LoadFrameListIndex + Index) & 0x3FF), + PtrQH + ); + } + // + // Poll QH-TDs execution and get result. + // detail status is returned + // + Status = ExecuteControlTransfer ( + HcDev, + PtrSetupTD, + LoadFrameListIndex, + DataLength, + TimeOut, + TransferResult + ); + // + // Remove Control Transfer QH-TDs structure from the frame list + // and update the pointers in the Frame List + // and other pointers in other related QH structures. + // + for (Index = 0; Index < 100; Index++) { + DelLinkSingleQH ( + HcDev, + PtrQH, + (UINT16) ((LoadFrameListIndex + Index) & 0x3FF), + FALSE, + FALSE + ); + } + // + // delete setup stage TD; the QH is reserved for the next stages. + // + DeleteQueuedTDs (HcDev, PtrSetupTD); + + // + // if setup stage error, return error + // + if (EFI_ERROR (Status)) { + goto Done; + } + // + // some control transfers do not have Data Stage + // + if (PtrFirstDataTD != NULL) { + + LinkTDToQH (PtrQH, PtrFirstDataTD); + LoadFrameListIndex = (UINT16) ((GetCurrentFrameNumber (HcDev->PciIo, FrameNumReg)) & 0x3FF); + + for (Index = 0; Index < 500; Index++) { + LinkQHToFrameList ( + HcDev->FrameListEntry, + (UINT16) ((LoadFrameListIndex + Index) & 0x3FF), + PtrQH + ); + } + + Status = ExecuteControlTransfer ( + HcDev, + PtrFirstDataTD, + LoadFrameListIndex, + DataLength, + TimeOut, + TransferResult + ); + + for (Index = 0; Index < 500; Index++) { + DelLinkSingleQH ( + HcDev, + PtrQH, + (UINT16) ((LoadFrameListIndex + Index) & 0x3FF), + FALSE, + FALSE + ); + } + // + // delete data stage TD; the QH is reserved for the next stage. + // + DeleteQueuedTDs (HcDev, PtrFirstDataTD); + } + // + // if data stage error, goto done and return error + // + if (EFI_ERROR (Status)) { + goto Done; + } + + LinkTDToQH (PtrQH, PtrStatusTD); + // + // get the frame list index that the QH-TDs will be linked to. + // + LoadFrameListIndex = (UINT16) ((GetCurrentFrameNumber (HcDev->PciIo, FrameNumReg)) & 0x3FF); + + for (Index = 0; Index < 100; Index++) { + // + // put the QH-TDs directly or indirectly into the proper place + // in the Frame List + // + LinkQHToFrameList ( + HcDev->FrameListEntry, + (UINT16) ((LoadFrameListIndex + Index) & 0x3FF), + PtrQH + ); + } + // + // Poll QH-TDs execution and get result. + // detail status is returned + // + Status = ExecuteControlTransfer ( + HcDev, + PtrStatusTD, + LoadFrameListIndex, + DataLength, + TimeOut, + TransferResult + ); + + // + // Delete Control Transfer QH-TDs structure + // and update the pointers in the Frame List + // and other pointers in other related QH structures. + // + // TRUE means must search other framelistindex + // + for (Index = 0; Index < 100; Index++) { + DelLinkSingleQH ( + HcDev, + PtrQH, + (UINT16) ((LoadFrameListIndex + Index) & 0x3FF), + FALSE, + FALSE + ); + } + + DeleteQueuedTDs (HcDev, PtrStatusTD); + + } else { + // + // link setup stage TD with data stage TD + // + PtrPreTD = PtrSetupTD; + if (PtrFirstDataTD != NULL) { + LinkTDToTD (PtrSetupTD, PtrFirstDataTD); + PtrPreTD = ptrLastDataTD; + } + // + // link status TD with previous TD + // + LinkTDToTD (PtrPreTD, PtrStatusTD); + + // + // link QH with TD + // + LinkTDToQH (PtrQH, PtrSetupTD); + + LoadFrameListIndex = (UINT16) ((GetCurrentFrameNumber (HcDev->PciIo, FrameNumReg)) & 0x3FF); + for (Index = 0; Index < 500; Index++) { + // + // put the QH-TDs directly or indirectly into the proper place + // in the Frame List + // + LinkQHToFrameList ( + HcDev->FrameListEntry, + (UINT16) ((LoadFrameListIndex + Index) & 0x3FF), + PtrQH + ); + } + // + // Poll QH-TDs execution and get result. + // detail status is returned + // + Status = ExecuteControlTransfer ( + HcDev, + PtrSetupTD, + LoadFrameListIndex, + DataLength, + TimeOut, + TransferResult + ); + // + // Remove Control Transfer QH-TDs structure from the frame list + // and update the pointers in the Frame List + // and other pointers in other related QH structures. + // + for (Index = 0; Index < 500; Index++) { + DelLinkSingleQH ( + HcDev, + PtrQH, + (UINT16) ((LoadFrameListIndex + Index) & 0x3FF), + FALSE, + FALSE + ); + } + + DeleteQueuedTDs (HcDev, PtrSetupTD); + } + +Done: + + UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT)); + + if (Mapping != NULL) { + HcDev->PciIo->Unmap (HcDev->PciIo, Mapping); + } + + if (RequestMapping != NULL) { + HcDev->PciIo->Unmap (HcDev->PciIo, RequestMapping); + } + // + // if has errors that cause host controller halt, + // then return EFI_DEVICE_ERROR directly. + // + if (!IsStatusOK (HcDev->PciIo, StatusReg)) { + + ClearStatusReg (HcDev->PciIo, StatusReg); + *TransferResult |= EFI_USB_ERR_SYSTEM; + return EFI_DEVICE_ERROR; + } + + ClearStatusReg (HcDev->PciIo, StatusReg); + HcDev->PciIo->Flush (HcDev->PciIo); + return Status; +} + +EFI_STATUS +EFIAPI +UHCIBulkTransfer ( + IN EFI_USB_HC_PROTOCOL *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 + ) +/*++ + + Routine Description: + Submits bulk transfer to a bulk endpoint of a USB device. + + Arguments: + + This A pointer to the EFI_USB_HC_PROTOCOL instance. + + DeviceAddress Represents the address of the target device on the USB, + which is assigned during USB enumeration. + EndPointAddress The combination of an endpoint number and an + endpoint direction of the target USB device. + Each endpoint address supports data transfer in + one direction except the control endpoint + (whose default endpoint address is 0). + It is the caller's responsibility to make sure that + the EndPointAddress represents a bulk endpoint. + + MaximumPacketLength Indicates the maximum packet size the target endpoint + is capable of sending or receiving. + + Data A pointer to the buffer of data that will be transmitted + to USB device or received from USB device. + DataLength When input, indicates the size, in bytes, of the data buffer + specified by Data. When output, indicates the actually + transferred data size. + + DataToggle A pointer to the data toggle value. On input, it indicates + the initial data toggle value the bulk transfer should adopt; + on output, it is updated to indicate the data toggle value + of the subsequent bulk transfer. + + TimeOut Indicates the maximum time, in microseconds, which the + transfer is allowed to complete. + + TransferResult A pointer to the detailed result information of the + bulk transfer. + + Returns: + EFI_SUCCESS + The bulk transfer was completed successfully. + EFI_OUT_OF_RESOURCES + The bulk transfer could not be submitted due to lack of resource. + EFI_INVALID_PARAMETER + Some parameters are invalid. + EFI_TIMEOUT + The bulk transfer failed due to timeout. + EFI_DEVICE_ERROR + The bulk transfer failed due to host controller or device error. + Caller should check TranferResult for detailed error information. + +--*/ +{ + USB_HC_DEV *HcDev; + UINT32 StatusReg; + UINT32 FrameNumReg; + UINTN DataLen; + QH_STRUCT *PtrQH; + TD_STRUCT *PtrFirstTD; + TD_STRUCT *PtrTD; + TD_STRUCT *PtrPreTD; + UINT16 LoadFrameListIndex; + UINT16 SavedFrameListIndex; + UINT8 PktID; + UINT8 *PtrDataSource; + UINT8 *Ptr; + BOOLEAN IsFirstTD; + EFI_STATUS Status; + UINT32 Index; + UINT8 PktSize; + + EFI_USB_DATA_DIRECTION TransferDirection; + // + // Used to calculate how many entries are linked to the + // specified bulk transfer QH-TDs + // + UINT32 LinkTimes; + + BOOLEAN ShortPacketEnable; + EFI_PHYSICAL_ADDRESS TempPtr; + VOID *Mapping; + + HcDev = USB_HC_DEV_FROM_THIS (This); + StatusReg = (UINT32) (USBSTS); + FrameNumReg = (UINT32) (USBFRNUM); + PktID = INPUT_PACKET_ID; + PtrTD = NULL; + PtrFirstTD = NULL; + PtrPreTD = NULL; + LinkTimes = 1; + DataLen = 0; + Ptr = NULL; + ShortPacketEnable = FALSE; + Mapping = NULL; + + // + // Parameters Checking + // + + if ((DataLength == NULL) || + (Data == NULL) || + (TransferResult == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // if has errors that cause host controller halt, + // then return EFI_DEVICE_ERROR directly. + // + if (!IsStatusOK (HcDev->PciIo, StatusReg)) { + + ClearStatusReg (HcDev->PciIo, StatusReg); + *TransferResult = EFI_USB_ERR_SYSTEM; + return EFI_DEVICE_ERROR; + } + + if (*DataLength == 0) { + 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; + } + + // + // Enable the maximum packet size (64bytes) + // that can be used for full speed bandwidth reclamation + // at the end of a frame. + // + EnableMaxPacketSize (HcDev); + + Status = ClearStatusReg (HcDev->PciIo, StatusReg); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // construct QH and TD data structures, + // and link them together + // + if (EndPointAddress & 0x80) { + TransferDirection = EfiUsbDataIn; + } else { + TransferDirection = EfiUsbDataOut; + } + + switch (TransferDirection) { + + case EfiUsbDataIn: + ShortPacketEnable = TRUE; + PktID = INPUT_PACKET_ID; + PtrDataSource = Data; + DataLen = *DataLength; + + // + // BusMasterWrite means cpu read + // + Status = HcDev->PciIo->Map ( + HcDev->PciIo, + EfiPciIoOperationBusMasterWrite, + PtrDataSource, + &DataLen, + &TempPtr, + &Mapping + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Ptr = (UINT8 *) ((UINTN) TempPtr); + break; + + case EfiUsbDataOut: + PktID = OUTPUT_PACKET_ID; + PtrDataSource = Data; + DataLen = *DataLength; + + // + // BusMasterRead means cpu write + // + Status = HcDev->PciIo->Map ( + HcDev->PciIo, + EfiPciIoOperationBusMasterRead, + PtrDataSource, + &DataLen, + &TempPtr, + &Mapping + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Ptr = (UINT8 *) ((UINTN) TempPtr); + break; + + default: + return EFI_INVALID_PARAMETER; + } + + // + // create QH structure and init + // + Status = CreateQH (HcDev, &PtrQH); + if (EFI_ERROR (Status)) { + HcDev->PciIo->Unmap (HcDev->PciIo, Mapping); + return Status; + } + + // + // i is used to calculate the total number of TDs. + // + Index = 0; + + IsFirstTD = TRUE; + while (DataLen > 0) { + + // + // create TD structures and link together + // + + PktSize = (UINT8) DataLen; + if (DataLen > MaximumPacketLength) { + PktSize = MaximumPacketLength; + } + + Status = GenDataTD ( + HcDev, + DeviceAddress, + EndPointAddress, + Ptr, + PktSize, + PktID, + *DataToggle, + FALSE, + &PtrTD + ); + + if (EFI_ERROR (Status)) { + HcDev->PciIo->Unmap (HcDev->PciIo, Mapping); + UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT)); + DeleteQueuedTDs (HcDev, PtrFirstTD); + return Status; + } + + // + // 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); + } + + Index++; + + PtrPreTD = PtrTD; + + *DataToggle ^= 1; + Ptr += PktSize; + DataLen -= PktSize; + } + + // + // link TD structures to QH structure + // + LinkTDToQH (PtrQH, PtrFirstTD); + + // + // calculate how many entries are linked to the specified bulk transfer QH-TDs + // the below values are referred to the USB spec revision1.1. + // + switch (MaximumPacketLength) { + case 8: + LinkTimes = Index / 71 + 1; + break; + + case 16: + LinkTimes = Index / 51 + 1; + break; + + case 32: + LinkTimes = Index / 33 + 1; + break; + + case 64: + LinkTimes = Index / 19 + 1; + break; + } + + LinkTimes += 500; + + // + // put QH-TDs into Frame list + // + LoadFrameListIndex = (UINT16) ((GetCurrentFrameNumber (HcDev->PciIo, FrameNumReg)) & 0x3FF); + SavedFrameListIndex = LoadFrameListIndex; + + for (Index = 0; Index <= LinkTimes; Index++) { + + // + // put the QH-TD directly or indirectly into the proper place + // in the Frame List + // + LinkQHToFrameList (HcDev->FrameListEntry, LoadFrameListIndex, PtrQH); + + LoadFrameListIndex += 1; + LoadFrameListIndex &= 0x3FF; + } + + LoadFrameListIndex = SavedFrameListIndex; + + // + // 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 = ExecBulkorSyncInterruptTransfer ( + HcDev, + PtrFirstTD, + LoadFrameListIndex, + DataLength, + DataToggle, + TimeOut, + TransferResult + ); + + // + // Delete Bulk transfer QH-TD structure + // and maitain the pointers in the Frame List + // and other pointers in related QH structure + // + // TRUE means must search other framelistindex + // + for (Index = 0; Index <= LinkTimes; Index++) { + DelLinkSingleQH ( + HcDev, + PtrQH, + LoadFrameListIndex, + FALSE, + FALSE + ); + LoadFrameListIndex += 1; + LoadFrameListIndex &= 0x3FF; + } + + UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT)); + + DeleteQueuedTDs (HcDev, PtrFirstTD); + + if (Mapping != NULL) { + HcDev->PciIo->Unmap (HcDev->PciIo, Mapping); + } + + // + // if has errors that cause host controller halt, + // then return EFI_DEVICE_ERROR directly. + // + if (!IsStatusOK (HcDev->PciIo, StatusReg)) { + + ClearStatusReg (HcDev->PciIo, StatusReg); + *TransferResult |= EFI_USB_ERR_SYSTEM; + return EFI_DEVICE_ERROR; + } + + ClearStatusReg (HcDev->PciIo, StatusReg); + + HcDev->PciIo->Flush (HcDev->PciIo); + + return Status; +} + +EFI_STATUS +EFIAPI +UHCIAsyncInterruptTransfer ( + IN EFI_USB_HC_PROTOCOL * This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN BOOLEAN IsSlowDevice, + IN UINT8 MaxiumPacketLength, + IN BOOLEAN IsNewTransfer, + IN OUT UINT8 *DataToggle, + IN UINTN PollingInterval, OPTIONAL + IN UINTN DataLength, OPTIONAL + IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction, OPTIONAL + IN VOID *Context OPTIONAL + ) +/*++ + + Routine Description: + Submits an asynchronous interrupt transfer to an + interrupt endpoint of a USB device. + + Arguments: + + This A pointer to the EFI_USB_HC_PROTOCOL instance. + + DeviceAddress Represents the address of the target device on the USB, + which is assigned during USB enumeration. + + EndPointAddress The combination of an endpoint number and an endpoint + direction of the target USB device. Each endpoint address + supports data transfer in one direction except the + control endpoint (whose default endpoint address is 0). + It is the caller's responsibility to make sure that + the EndPointAddress represents an interrupt endpoint. + + IsSlowDevice Indicates whether the target device is slow device + or full-speed device. + + MaxiumPacketLength Indicates the maximum packet size the target endpoint + is capable of sending or receiving. + + IsNewTransfer If TRUE, an asynchronous interrupt pipe is built between + the host and the target interrupt endpoint. + If FALSE, the specified asynchronous interrupt pipe + is canceled. + + DataToggle A pointer to the data toggle value. On input, it is valid + when IsNewTransfer is TRUE, and it indicates the initial + data toggle value the asynchronous interrupt transfer + should adopt. + On output, it is valid when IsNewTransfer is FALSE, + and it is updated to indicate the data toggle value of + the subsequent asynchronous interrupt transfer. + + PollingInterval Indicates the interval, in milliseconds, that the + asynchronous interrupt transfer is polled. + This parameter is required when IsNewTransfer is TRUE. + + DataLength Indicates the length of data to be received at the + rate specified by PollingInterval from the target + asynchronous interrupt endpoint. This parameter + is only required when IsNewTransfer is TRUE. + + CallBackFunction The Callback function.This function is called at the + rate specified by PollingInterval.This parameter is + only required when IsNewTransfer is TRUE. + + Context The context that is passed to the CallBackFunction. + This is an optional parameter and may be NULL. + + Returns: + EFI_SUCCESS + The asynchronous interrupt transfer request has been successfully + submitted or canceled. + EFI_INVALID_PARAMETER + Some parameters are invalid. + EFI_OUT_OF_RESOURCES + The request could not be completed due to a lack of resources. + EFI_DEVICE_ERROR + Can't read register +--*/ +{ + USB_HC_DEV *HcDev; + UINT32 StatusReg; + UINT32 FrameNumReg; + UINTN DataLen; + QH_STRUCT *ptrFirstQH; + QH_STRUCT *PtrQH; + QH_STRUCT *ptrPreQH; + TD_STRUCT *PtrFirstTD; + TD_STRUCT *PtrTD; + TD_STRUCT *PtrPreTD; + UINT16 LoadFrameListIndex; + UINT16 Index; + UINT8 PktID; + UINT8 *Ptr; + UINT8 *MappedPtr; + BOOLEAN IsFirstTD; + BOOLEAN IsFirstQH; + EFI_STATUS Status; + BOOLEAN ShortPacketEnable; + UINT8 CurrentDataToggle; + EFI_PHYSICAL_ADDRESS TempPtr; + VOID *Mapping; + UINT8 PktSize; + QH_STRUCT *TempQH; + EFI_TPL OldTpl; + + HcDev = USB_HC_DEV_FROM_THIS (This); + StatusReg = (UINT32) (USBSTS); + FrameNumReg = (UINT32) (USBFRNUM); + Mapping = NULL; + ShortPacketEnable = FALSE; + + PktID = INPUT_PACKET_ID; + PtrTD = NULL; + PtrFirstTD = NULL; + PtrPreTD = NULL; + Ptr = NULL; + PtrQH = NULL; + ptrPreQH = NULL; + ptrFirstQH = NULL; + + if ((EndPointAddress & 0x80) == 0) { + return EFI_INVALID_PARAMETER; + } + + // + // delete Async interrupt transfer request + // + if (!IsNewTransfer) { + + OldTpl = gBS->RaiseTPL (EFI_TPL_NOTIFY); + + Status = DeleteAsyncINTQHTDs ( + HcDev, + DeviceAddress, + EndPointAddress, + DataToggle + ); + + gBS->RestoreTPL (OldTpl); + + return Status; + } + // + // if has errors that cause host controller halt, + // then return EFI_DEVICE_ERROR directly. + // + if (!IsStatusOK (HcDev->PciIo, StatusReg)) { + + ClearStatusReg (HcDev->PciIo, StatusReg); + return EFI_DEVICE_ERROR; + } + + ClearStatusReg (HcDev->PciIo, StatusReg); + + // + // submit Async interrupt transfer request + // + 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; + } + + ShortPacketEnable = TRUE; + PktID = INPUT_PACKET_ID; + DataLen = DataLength; + Ptr = AllocatePool (DataLen); + if (Ptr == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // BusMasterWrite means cpu read + // + Status = HcDev->PciIo->Map ( + HcDev->PciIo, + EfiPciIoOperationBusMasterWrite, + Ptr, + &DataLen, + &TempPtr, + &Mapping + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (Ptr); + return Status; + } + + MappedPtr = (UINT8 *) ((UINTN) TempPtr); + + CurrentDataToggle = *DataToggle; + + IsFirstTD = TRUE; + + while (DataLen > 0) { + // + // create TD structures and link together + // + + PktSize = (UINT8) DataLen; + if (DataLen > MaxiumPacketLength) { + PktSize = MaxiumPacketLength; + } + + Status = GenDataTD ( + HcDev, + DeviceAddress, + EndPointAddress, + MappedPtr, + PktSize, + PktID, + CurrentDataToggle, + IsSlowDevice, + &PtrTD + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (Ptr); + HcDev->PciIo->Unmap (HcDev->PciIo, Mapping); + DeleteQueuedTDs (HcDev, PtrFirstTD); + return Status; + } + // + // Enable 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; + + CurrentDataToggle ^= 1; + MappedPtr += PktSize; + DataLen -= PktSize; + } + + // + // roll one value back + // + CurrentDataToggle ^= 1; + + // + // create a list of QH structures and init, + // link TDs to all the QHs, and link all the QHs together using internal + // defined pointer of the QH_STRUCT. + // + IsFirstQH = TRUE; + ptrPreQH = NULL; + for (Index = 0; Index < 1024;) { + + Status = CreateQH (HcDev, &PtrQH); + if (EFI_ERROR (Status)) { + gBS->FreePool (Ptr); + HcDev->PciIo->Unmap (HcDev->PciIo, Mapping); + DeleteQueuedTDs (HcDev, PtrFirstTD); + PtrQH = ptrFirstQH; + while (PtrQH) { + TempQH = PtrQH; + PtrQH = TempQH->ptrNextIntQH; + UhciFreePool (HcDev, (UINT8 *) TempQH, sizeof (QH_STRUCT)); + } + + return Status; + } + + // + // link TD structures to QH structure + // + LinkTDToQH (PtrQH, PtrFirstTD); + + if (IsFirstQH) { + ptrFirstQH = PtrQH; + ptrFirstQH->ptrNextIntQH = NULL; + IsFirstQH = FALSE; + } else { + // + // link neighbor QH structures together + // + ptrPreQH->ptrNextIntQH = PtrQH; + } + + ptrPreQH = PtrQH; + + Index = (UINT16) (PollingInterval + Index); + } + // + // last QH in QH list should set its next QH pointer to NULL. + // + PtrQH->ptrNextIntQH = NULL; + + // + // Save QH-TD structures in Interrupt transfer list, + // for monitor interrupt transfer execution routine use. + // + InsertQHTDToINTList ( + HcDev, + ptrFirstQH, + PtrFirstTD, + DeviceAddress, + EndPointAddress, + CurrentDataToggle, + DataLength, + PollingInterval, + Mapping, + Ptr, + CallBackFunction, + Context + ); + + // + // put QHs-TDs into Frame list + // + LoadFrameListIndex = (UINT16) ((GetCurrentFrameNumber (HcDev->PciIo, FrameNumReg)) & 0x3FF); + + PtrQH = ptrFirstQH; + + for (Index = LoadFrameListIndex; Index < (1024 + LoadFrameListIndex);) { + + // + // put the QH-TD directly or indirectly into the proper place + // in the Frame List + // + LinkQHToFrameList (HcDev->FrameListEntry, (UINT16) (Index & 0x3FF), PtrQH); + + Index = (UINT16) (PollingInterval + Index); + + PtrQH = PtrQH->ptrNextIntQH; + } + + HcDev->PciIo->Flush (HcDev->PciIo); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +UHCISyncInterruptTransfer ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN BOOLEAN IsSlowDevice, + IN UINT8 MaximumPacketLength, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN OUT UINT8 *DataToggle, + IN UINTN TimeOut, + OUT UINT32 *TransferResult + ) +/*++ + + Routine Description: + Submits synchronous interrupt transfer to an interrupt endpoint + of a USB device. + + Arguments: + + This A pointer to the EFI_USB_HC_PROTOCOL instance. + + DeviceAddress Represents the address of the target device on the USB, + which is assigned during USB enumeration. + + EndPointAddress The combination of an endpoint number and an endpoint + direction of the target USB device. Each endpoint + address supports data transfer in one direction + except the control endpoint (whose default + endpoint address is 0). It is the caller's responsibility + to make sure that the EndPointAddress represents + an interrupt endpoint. + + IsSlowDevice Indicates whether the target device is slow device + or full-speed device. + + MaximumPacketLength Indicates the maximum packet size the target endpoint + is capable of sending or receiving. + + Data A pointer to the buffer of data that will be transmitted + to USB device or received from USB device. + + DataLength On input, the size, in bytes, of the data buffer specified + by Data. On output, the number of bytes transferred. + + DataToggle A pointer to the data toggle value. On input, it indicates + the initial data toggle value the synchronous interrupt + transfer should adopt; + on output, it is updated to indicate the data toggle value + of the subsequent synchronous interrupt transfer. + + TimeOut Indicates the maximum time, in microseconds, which the + transfer is allowed to complete. + + TransferResult A pointer to the detailed result information from + the synchronous interrupt transfer. + + Returns: + EFI_SUCCESS + The synchronous interrupt transfer was completed successfully. + EFI_OUT_OF_RESOURCES + The synchronous interrupt transfer could not be submitted due + to lack of resource. + EFI_INVALID_PARAMETER + Some parameters are invalid. + EFI_TIMEOUT + The synchronous interrupt transfer failed due to timeout. + EFI_DEVICE_ERROR + The synchronous interrupt transfer failed due to host controller + or device error. Caller should check TranferResult for detailed + error information. +--*/ +{ + USB_HC_DEV *HcDev; + UINT32 StatusReg; + UINT32 FrameNumReg; + UINTN DataLen; + QH_STRUCT *PtrQH; + TD_STRUCT *PtrFirstTD; + TD_STRUCT *PtrTD; + TD_STRUCT *PtrPreTD; + UINT16 LoadFrameListIndex; + UINT16 SavedFrameListIndex; + UINT32 Index; + UINT32 LinkTimes; + UINT8 PktID; + UINT8 *PtrDataSource; + UINT8 *Ptr; + BOOLEAN IsFirstTD; + EFI_STATUS Status; + BOOLEAN ShortPacketEnable; + EFI_PHYSICAL_ADDRESS TempPtr; + VOID *Mapping; + UINT8 PktSize; + + HcDev = USB_HC_DEV_FROM_THIS (This); + StatusReg = (UINT32) (USBSTS); + FrameNumReg = (UINT32) (USBFRNUM); + ShortPacketEnable = FALSE; + Mapping = NULL; + PktID = INPUT_PACKET_ID; + PtrTD = NULL; + PtrFirstTD = NULL; + PtrPreTD = NULL; + DataLen = 0; + Ptr = NULL; + Index = 0; + LinkTimes = 0; + + // + // Parameters Checking + // + + if ((DataLength == NULL) || + (Data == NULL) || + (TransferResult == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // if has errors that cause host controller halt, + // then return EFI_DEVICE_ERROR directly. + // + if (!IsStatusOK (HcDev->PciIo, StatusReg)) { + + ClearStatusReg (HcDev->PciIo, StatusReg); + *TransferResult = EFI_USB_ERR_SYSTEM; + return EFI_DEVICE_ERROR; + } + + if ((EndPointAddress & 0x80) == 0) { + return EFI_INVALID_PARAMETER; + } + + if (*DataLength == 0) { + return EFI_INVALID_PARAMETER; + } + + if ((*DataToggle != 1) && (*DataToggle != 0)) { + return EFI_INVALID_PARAMETER; + } + + if (MaximumPacketLength > 64) { + return EFI_INVALID_PARAMETER; + } + + if (IsSlowDevice && (MaximumPacketLength > 8)) { + return EFI_INVALID_PARAMETER; + } + + ClearStatusReg (HcDev->PciIo, StatusReg); + + // + // submit Sync interrupt transfer request + // + ShortPacketEnable = TRUE; + PktID = INPUT_PACKET_ID; + DataLen = *DataLength; + PtrDataSource = Data; + + // + // create QH structure and init + // + Status = CreateQH (HcDev, &PtrQH); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // BusMasterWrite means cpu read + // + Status = HcDev->PciIo->Map ( + HcDev->PciIo, + EfiPciIoOperationBusMasterWrite, + PtrDataSource, + &DataLen, + &TempPtr, + &Mapping + ); + if (EFI_ERROR (Status)) { + UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT)); + return Status; + } + + Ptr = (UINT8 *) ((UINTN) TempPtr); + + IsFirstTD = TRUE; + while (DataLen > 0) { + // + // create TD structures and link together + // + PktSize = (UINT8) DataLen; + if (DataLen > MaximumPacketLength) { + PktSize = MaximumPacketLength; + } + + Status = GenDataTD ( + HcDev, + DeviceAddress, + EndPointAddress, + Ptr, + PktSize, + PktID, + *DataToggle, + IsSlowDevice, + &PtrTD + ); + if (EFI_ERROR (Status)) { + UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT)); + HcDev->PciIo->Unmap (HcDev->PciIo, Mapping); + DeleteQueuedTDs (HcDev, PtrFirstTD); + return Status; + } + // + // Enable 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); + } + + Index++; + + PtrPreTD = PtrTD; + + *DataToggle ^= 1; + Ptr += PktSize; + DataLen -= PktSize; + } + + // + // link TD structures to QH structure + // + LinkTDToQH (PtrQH, PtrFirstTD); + + switch (MaximumPacketLength) { + case 8: + LinkTimes = Index / 71 + 1; + break; + + case 16: + LinkTimes = Index / 51 + 1; + break; + + case 32: + LinkTimes = Index / 33 + 1; + break; + + case 64: + LinkTimes = Index / 19 + 1; + break; + } + + LinkTimes += 100; + + LoadFrameListIndex = (UINT16) ((GetCurrentFrameNumber (HcDev->PciIo, FrameNumReg)) & 0x3FF); + SavedFrameListIndex = LoadFrameListIndex; + + for (Index = 0; Index < LinkTimes; Index++) { + + // + // put the QH-TD directly or indirectly into the proper place + // in the Frame List + // + LinkQHToFrameList (HcDev->FrameListEntry, LoadFrameListIndex, PtrQH); + + LoadFrameListIndex += 1; + LoadFrameListIndex &= 0x3FF; + } + + LoadFrameListIndex = SavedFrameListIndex; + // + // 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 = ExecBulkorSyncInterruptTransfer ( + HcDev, + PtrFirstTD, + LoadFrameListIndex, + DataLength, + DataToggle, + TimeOut, + TransferResult + ); + // + // Delete Sync Interrupt transfer QH-TD structure + // and maintain the pointers in the Frame List + // and other pointers in related QH structure + // + // TRUE means must search other framelistindex + // + for (Index = 0; Index <= LinkTimes; Index++) { + DelLinkSingleQH ( + HcDev, + PtrQH, + LoadFrameListIndex, + FALSE, + FALSE + ); + LoadFrameListIndex += 1; + LoadFrameListIndex &= 0x3FF; + } + + UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT)); + + DeleteQueuedTDs (HcDev, PtrFirstTD); + + HcDev->PciIo->Unmap (HcDev->PciIo, Mapping); + + // + // if has errors that cause host controller halt, + // then return EFI_DEVICE_ERROR directly. + // + if (!IsStatusOK (HcDev->PciIo, StatusReg)) { + + ClearStatusReg (HcDev->PciIo, StatusReg); + *TransferResult |= EFI_USB_ERR_SYSTEM; + return EFI_DEVICE_ERROR; + } + + ClearStatusReg (HcDev->PciIo, StatusReg); + + HcDev->PciIo->Flush (HcDev->PciIo); + + return Status; +} + +EFI_STATUS +EFIAPI +UHCIIsochronousTransfer ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 MaximumPacketLength, + IN OUT VOID *Data, + IN UINTN DataLength, + OUT UINT32 *TransferResult + ) +/*++ + + Routine Description: + Submits isochronous transfer to a target USB device. + + Arguments: + + This - A pointer to the EFI_USB_HC_PROTOCOL instance. + DeviceAddress - Represents the address of the target device on the USB, + which is assigned during USB enumeration. + EndPointAddress - End point address + MaximumPacketLength - Indicates the maximum packet size that the + default control transfer endpoint is capable of + sending or receiving. + Data - A pointer to the buffer of data that will be transmitted + to USB device or received from USB device. + DataLength - Indicates the size, in bytes, of the data buffer + specified by Data. + TransferResult - A pointer to the detailed result information generated + by this control transfer. + Returns: + EFI_UNSUPPORTED + +--*/ +{ + return EFI_UNSUPPORTED; +} + + +EFI_STATUS +EFIAPI +UHCIAsyncIsochronousTransfer ( + IN EFI_USB_HC_PROTOCOL * This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 MaximumPacketLength, + IN OUT VOID *Data, + IN UINTN DataLength, + IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack, + IN VOID *Context OPTIONAL + ) +/*++ + + Routine Description: + Submits Async isochronous transfer to a target USB device. + + Arguments: + + This - A pointer to the EFI_USB_HC_PROTOCOL instance. + + DeviceAddress - Represents the address of the target device on the USB, + which is assigned during USB enumeration. + + EndPointAddress - End point address + + MaximumPacketLength - Indicates the maximum packet size that the + default control transfer endpoint is capable of + sending or receiving. + + Data - A pointer to the buffer of data that will be transmitted + to USB device or received from USB device. + + IsochronousCallBack - When the transfer complete, the call back function will be called + + Context - Pass to the call back function as parameter + + Returns: + EFI_UNSUPPORTED + +--*/ +{ + return EFI_UNSUPPORTED; +} + +VOID +EFIAPI +MonitorInterruptTrans ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + Routine Description: + Interrupt transfer periodic check handler + Arguments: + Event - Interrupt event + Contex - Pointer to USB_HC_DEV + Returns: + None +--*/ +{ + + USB_HC_DEV *HcDev; + INTERRUPT_LIST *PtrList; + LIST_ENTRY *Link; + UINT32 Result; + VOID *DataBuffer; + UINTN DataLen; + UINTN ActualLen; + UINTN ErrTDPos; + UINT32 StatusAddr; + LIST_ENTRY *NextLink; + + HcDev = (USB_HC_DEV *) Context; + StatusAddr = (UINT32) (USBSTS); + + // + // interrupt transfer list is empty, means that no interrupt transfer + // is submitted by far. + // + if (IsListEmpty (&(HcDev->InterruptListHead))) { + return ; + } + + NextLink = HcDev->InterruptListHead.ForwardLink; + do { + + Link = NextLink; + NextLink = Link->ForwardLink; + + PtrList = INTERRUPT_LIST_FROM_LINK (Link); + + // + // get TD execution results. + // ErrTDPos is zero-based value indicating the first error TD's position + // in the TDs' list. + // This value is only valid when Result not equal NOERROR. + // + ExecuteAsyncINTTDs ( + HcDev, + PtrList, + &Result, + &ErrTDPos, + &ActualLen + ); + + // + // interrupt transfer has not been executed yet. + // + if (((Result & EFI_USB_ERR_NAK) == EFI_USB_ERR_NAK) || + ((Result & EFI_USB_ERR_NOTEXECUTE) == EFI_USB_ERR_NOTEXECUTE)) { + continue; + } + // + // get actual data length transferred data and its data length. + // + DataLen = ActualLen; + DataBuffer = AllocatePool (DataLen); + if (DataBuffer == NULL) { + return ; + } + + CopyMem ( + DataBuffer, + PtrList->PtrFirstTD->pTDBuffer, + DataLen + ); + + // + // only if interrupt endpoint responds + // and the interrupt transfer stops because of completion + // or error, then we will call callback function. + // + if (Result == EFI_USB_NOERROR) { + // + // add for real platform debug + // + if (PtrList->InterruptCallBack != NULL) { + (PtrList->InterruptCallBack) ( + DataBuffer, + DataLen, + PtrList->InterruptContext, + Result + ); + } + + if (DataBuffer) { + gBS->FreePool (DataBuffer); + } + + // + // update should done after data buffer got. + // + UpdateAsyncINTQHTDs (PtrList, Result, (UINT32) ErrTDPos); + + } else { + + DEBUG ((EFI_D_ERROR, "interrupt transfer error code is %x\n", Result)); + + if (DataBuffer) { + gBS->FreePool (DataBuffer); + } + // + // 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. + // + if (PtrList->InterruptCallBack != NULL) { + (PtrList->InterruptCallBack) ( + NULL, + 0, + PtrList->InterruptContext, + Result + ); + } + } + } while (NextLink != &(HcDev->InterruptListHead)); + +} diff --git a/EdkModulePkg/Bus/Pci/Uhci/Dxe/uhci.h b/EdkModulePkg/Bus/Pci/Uhci/Dxe/uhci.h new file mode 100644 index 0000000000..93da46c9ca --- /dev/null +++ b/EdkModulePkg/Bus/Pci/Uhci/Dxe/uhci.h @@ -0,0 +1,1187 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Uhci.h + +Abstract: + + +Revision History +--*/ + +#ifndef _UHCI_H +#define _UHCI_H + +/* + * Universal Host Controller Interface data structures and defines + */ + +#include + +#define EFI_D_UHCI EFI_D_INFO + +// +// stall time +// +#define STALL_1_MILLI_SECOND 1000 +#define STALL_1_SECOND 1000 * STALL_1_MILLI_SECOND + +#define FORCE_GLOBAL_RESUME_TIME 20 * STALL_1_MILLI_SECOND + +#define ROOT_PORT_REST_TIME 50 * STALL_1_MILLI_SECOND + +#define PORT_RESET_RECOVERY_TIME 10 * STALL_1_MILLI_SECOND + +// +// 50 ms +// +#define INTERRUPT_POLLING_TIME 50 * 1000 * 10 + +// +// UHCI IO Space Address Register Register locates at +// offset 20 ~ 23h of PCI Configuration Space (UHCI spec, Revision 1.1), +// so, its BAR Index is 4. +// +#define USB_BAR_INDEX 4 + +// +// One memory block uses 1 page (common buffer for QH,TD use.) +// +#define NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES 1 + + +#define bit(a) 1 << (a) + +// +// //////////////////////////////////////////////////////////////////////// +// +// Universal Host Controller Registers Definitions +// +////////////////////////////////////////////////////////////////////////// +extern UINT16 USBBaseAddr; + +/* Command register */ +#define USBCMD 0 /* Command Register Offset 00-01h */ +#define USBCMD_RS bit (0) /* Run/Stop */ +#define USBCMD_HCRESET bit (1) /* Host reset */ +#define USBCMD_GRESET bit (2) /* Global reset */ +#define USBCMD_EGSM bit (3) /* Global Suspend Mode */ +#define USBCMD_FGR bit (4) /* Force Global Resume */ +#define USBCMD_SWDBG bit (5) /* SW Debug mode */ +#define USBCMD_CF bit (6) /* Config Flag (sw only) */ +#define USBCMD_MAXP bit (7) /* Max Packet (0 = 32, 1 = 64) */ + +/* Status register */ +#define USBSTS 2 /* Status Register Offset 02-03h */ +#define USBSTS_USBINT bit (0) /* Interrupt due to IOC */ +#define USBSTS_ERROR bit (1) /* Interrupt due to error */ +#define USBSTS_RD bit (2) /* Resume Detect */ +#define USBSTS_HSE bit (3) /* Host System Error*/ +#define USBSTS_HCPE bit (4) /* Host Controller Process Error*/ +#define USBSTS_HCH bit (5) /* HC Halted */ + +/* Interrupt enable register */ +#define USBINTR 4 /* Interrupt Enable Register 04-05h */ +#define USBINTR_TIMEOUT bit (0) /* Timeout/CRC error enable */ +#define USBINTR_RESUME bit (1) /* Resume interrupt enable */ +#define USBINTR_IOC bit (2) /* Interrupt On Complete enable */ +#define USBINTR_SP bit (3) /* 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 bit (0) /* Current Connect Status*/ +#define USBPORTSC_CSC bit (1) /* Connect Status Change */ +#define USBPORTSC_PED bit (2) /* Port Enable / Disable */ +#define USBPORTSC_PEDC bit (3) /* Port Enable / Disable Change */ +#define USBPORTSC_LSL bit (4) /* Line Status Low bit*/ +#define USBPORTSC_LSH bit (5) /* Line Status High bit*/ +#define USBPORTSC_RD bit (6) /* Resume Detect */ +#define USBPORTSC_LSDA bit (8) /* Low Speed Device Attached */ +#define USBPORTSC_PR bit (9) /* Port Reset */ +#define USBPORTSC_SUSP bit (12) /* Suspend */ + +/* PCI Configuration Registers for USB */ + +// +// Class Code Register offset +// +#define CLASSC 0x09 +// +// USB IO Space Base Address Register offset +// +#define USBBASE 0x20 + +// +// USB legacy Support +// +#define USB_EMULATION 0xc0 + +// +// USB Base Class Code,Sub-Class Code and Programming Interface. +// +#define PCI_CLASSC_PI_UHCI 0x00 + +#define SETUP_PACKET_ID 0x2D +#define INPUT_PACKET_ID 0x69 +#define OUTPUT_PACKET_ID 0xE1 +#define ERROR_PACKET_ID 0x55 + +// +// //////////////////////////////////////////////////////////////////////// +// +// USB Transfer Mechanism Data Structures +// +////////////////////////////////////////////////////////////////////////// +#pragma pack(1) +// +// USB Class Code structure +// +typedef struct { + UINT8 PI; + UINT8 SubClassCode; + UINT8 BaseCode; +} USB_CLASSC; + +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 { + 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; + +#pragma pack() + +typedef struct { + QUEUE_HEAD QH; + VOID *ptrNext; + VOID *ptrDown; + VOID *ptrNextIntQH; // for interrupt transfer's special use + VOID *LoopPtr; +} QH_STRUCT; + +typedef struct { + TD TDData; + UINT8 *pTDBuffer; + VOID *ptrNextTD; + VOID *ptrNextQH; + UINT16 TDBufferLength; + UINT16 reserved; +} TD_STRUCT; + +// +// //////////////////////////////////////////////////////////////////////// +// +// Universal Host Controller Device Data Structure +// +////////////////////////////////////////////////////////////////////////// +#define USB_HC_DEV_FROM_THIS(a) CR (a, USB_HC_DEV, UsbHc, USB_HC_DEV_SIGNATURE) + +#define USB_HC_DEV_SIGNATURE EFI_SIGNATURE_32 ('u', 'h', 'c', 'i') +#define INTERRUPT_LIST_SIGNATURE EFI_SIGNATURE_32 ('i', 'n', 't', 's') +typedef struct { + UINTN Signature; + + LIST_ENTRY Link; + UINT8 DevAddr; + UINT8 EndPoint; + UINT8 DataToggle; + UINT8 Reserved[5]; + TD_STRUCT *PtrFirstTD; + QH_STRUCT *PtrQH; + UINTN DataLen; + UINTN PollInterval; + VOID *Mapping; + UINT8 *DataBuffer; // allocated host memory, not mapped memory + EFI_ASYNC_USB_TRANSFER_CALLBACK InterruptCallBack; + VOID *InterruptContext; +} INTERRUPT_LIST; + +#define INTERRUPT_LIST_FROM_LINK(a) CR (a, INTERRUPT_LIST, Link, INTERRUPT_LIST_SIGNATURE) + +typedef struct { + UINT32 FrameListPtrTerminate : 1; + UINT32 FrameListPtrQSelect : 1; + UINT32 FrameListRsvd : 2; + UINT32 FrameListPtr : 28; + +} FRAMELIST_ENTRY; + +typedef struct _MEMORY_MANAGE_HEADER { + UINT8 *BitArrayPtr; + UINTN BitArraySizeInBytes; + UINT8 *MemoryBlockPtr; + UINTN MemoryBlockSizeInBytes; + VOID *Mapping; + struct _MEMORY_MANAGE_HEADER *Next; +} MEMORY_MANAGE_HEADER; + +typedef struct { + UINTN Signature; + EFI_USB_HC_PROTOCOL UsbHc; + EFI_PCI_IO_PROTOCOL *PciIo; + + // + // local data + // + LIST_ENTRY InterruptListHead; + FRAMELIST_ENTRY *FrameListEntry; + VOID *FrameListMapping; + MEMORY_MANAGE_HEADER *MemoryHeader; + EFI_EVENT InterruptTransTimer; + EFI_UNICODE_STRING_TABLE *ControllerNameTable; + +} USB_HC_DEV; + +extern EFI_DRIVER_BINDING_PROTOCOL gUhciDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gUhciComponentName; + +EFI_STATUS +WriteUHCCommandReg ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 CmdAddrOffset, + IN UINT16 UsbCmd + ); + +EFI_STATUS +ReadUHCCommandReg ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 CmdAddrOffset, + IN OUT UINT16 *Data + ); + +EFI_STATUS +WriteUHCStatusReg ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 StatusAddrOffset, + IN UINT16 UsbSts + ); + +EFI_STATUS +ReadUHCStatusReg ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 StatusAddrOffset, + IN OUT UINT16 *Data + ); + +EFI_STATUS +ClearStatusReg ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 StatusAddrOffset + ); + +EFI_STATUS +ReadUHCFrameNumberReg ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 FrameNumAddrOffset, + IN OUT UINT16 *Data + ); + +EFI_STATUS +WriteUHCFrameListBaseReg ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 FlBaseAddrOffset, + IN UINT32 UsbFrameListBaseAddr + ); + +EFI_STATUS +ReadRootPortReg ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 PortAddrOffset, + IN OUT UINT16 *Data + ); + +EFI_STATUS +WriteRootPortReg ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 PortAddrOffset, + IN UINT16 ControlBits + ); + +EFI_STATUS +WaitForUHCHalt ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 StatusRegAddr, + IN UINTN Timeout + ); + +BOOLEAN +IsStatusOK ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 StatusRegAddr + ); + +BOOLEAN +IsHostSysOrProcessErr ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 StatusRegAddr + ); + +// +// This routine programs the USB frame number register. We assume that the +// HC schedule execution is stopped. +// +EFI_STATUS +SetFrameNumberReg ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 FRNUMAddr, + IN UINT16 Index + ); + +UINT16 +GetCurrentFrameNumber ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 FRNUMAddr + ); + +EFI_STATUS +SetFrameListBaseAddress ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 FLBASEADDRReg, + IN UINT32 Addr + ); + +UINT32 +GetFrameListBaseAddress ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 FLBAddr + ); + +EFI_STATUS +CreateFrameList ( + IN USB_HC_DEV *HcDev, + IN UINT32 FLBASEADDRReg + ); + +EFI_STATUS +FreeFrameListEntry ( + IN USB_HC_DEV *UhcDev + ); + +VOID +InitFrameList ( + IN USB_HC_DEV *HcDev + ); + + +EFI_STATUS +CreateQH ( + IN USB_HC_DEV *HcDev, + OUT QH_STRUCT **pptrQH + ); + +VOID +SetQHHorizontalLinkPtr ( + IN QH_STRUCT *ptrQH, + IN VOID *ptrNext + ); + +VOID * +GetQHHorizontalLinkPtr ( + IN QH_STRUCT *ptrQH + ); + +VOID +SetQHHorizontalQHorTDSelect ( + IN QH_STRUCT *ptrQH, + IN BOOLEAN bQH + ); + +VOID +SetQHHorizontalValidorInvalid ( + IN QH_STRUCT *ptrQH, + IN BOOLEAN bValid + ); + +VOID +SetQHVerticalLinkPtr ( + IN QH_STRUCT *ptrQH, + IN VOID *ptrNext + ); + +VOID * +GetQHVerticalLinkPtr ( + IN QH_STRUCT *ptrQH + ); + +VOID +SetQHVerticalQHorTDSelect ( + IN QH_STRUCT *ptrQH, + IN BOOLEAN bQH + ); + +BOOLEAN +IsQHHorizontalQHSelect ( + IN QH_STRUCT *ptrQH + ); + +VOID +SetQHVerticalValidorInvalid ( + IN QH_STRUCT *ptrQH, + IN BOOLEAN bValid + ); + +BOOLEAN +GetQHVerticalValidorInvalid ( + IN QH_STRUCT *ptrQH + ); + +EFI_STATUS +AllocateTDStruct ( + IN USB_HC_DEV *HcDev, + OUT TD_STRUCT **ppTDStruct + ); +/*++ + +Routine Description: + + Allocate TD Struct + +Arguments: + + HcDev - USB_HC_DEV + ppTDStruct - place to store TD_STRUCT pointer +Returns: + + EFI_SUCCESS + +--*/ + +EFI_STATUS +CreateTD ( + IN USB_HC_DEV *HcDev, + OUT TD_STRUCT **pptrTD + ); +/*++ + +Routine Description: + + Create TD + +Arguments: + + HcDev - USB_HC_DEV + pptrTD - TD_STRUCT pointer to store + +Returns: + + EFI_OUT_OF_RESOURCES - Can't allocate resources + EFI_SUCCESS - Success + +--*/ + + +EFI_STATUS +GenSetupStageTD ( + IN USB_HC_DEV *HcDev, + IN UINT8 DevAddr, + IN UINT8 Endpoint, + IN BOOLEAN bSlow, + IN UINT8 *pDevReq, + IN UINT8 RequestLen, + OUT TD_STRUCT **ppTD + ); +/*++ + +Routine Description: + + Generate Setup Stage TD + +Arguments: + + HcDev - USB_HC_DEV + DevAddr - Device address + Endpoint - Endpoint number + bSlow - Full speed or low speed + pDevReq - Device request + RequestLen - Request length + ppTD - TD_STRUCT to return +Returns: + + EFI_OUT_OF_RESOURCES - Can't allocate memory + EFI_SUCCESS - Success + +--*/ + +EFI_STATUS +GenDataTD ( + IN USB_HC_DEV *HcDev, + IN UINT8 DevAddr, + IN UINT8 Endpoint, + IN UINT8 *pData, + IN UINT8 Len, + IN UINT8 PktID, + IN UINT8 Toggle, + IN BOOLEAN bSlow, + OUT TD_STRUCT **ppTD + ); +/*++ + +Routine Description: + + Generate Data Stage TD + +Arguments: + + HcDev - USB_HC_DEV + DevAddr - Device address + Endpoint - Endpoint number + pData - Data buffer + Len - Data length + PktID - Packet ID + Toggle - Data toggle value + bSlow - Full speed or low speed + ppTD - TD_STRUCT to return +Returns: + + EFI_OUT_OF_RESOURCES - Can't allocate memory + EFI_SUCCESS - Success + +--*/ + +EFI_STATUS +CreateStatusTD ( + IN USB_HC_DEV *HcDev, + IN UINT8 DevAddr, + IN UINT8 Endpoint, + IN UINT8 PktID, + IN BOOLEAN bSlow, + OUT TD_STRUCT **ppTD + ); +/*++ + +Routine Description: + + Generate Setup Stage TD + +Arguments: + + HcDev - USB_HC_DEV + DevAddr - Device address + Endpoint - Endpoint number + bSlow - Full speed or low speed + pDevReq - Device request + RequestLen - Request length + ppTD - TD_STRUCT to return +Returns: + + EFI_OUT_OF_RESOURCES - Can't allocate memory + EFI_SUCCESS - Success + +--*/ + +VOID +SetTDLinkPtrValidorInvalid ( + IN TD_STRUCT *ptrTDStruct, + IN BOOLEAN bValid + ); + +VOID +SetTDLinkPtrQHorTDSelect ( + IN TD_STRUCT *ptrTDStruct, + IN BOOLEAN bQH + ); + +VOID +SetTDLinkPtrDepthorBreadth ( + IN TD_STRUCT *ptrTDStruct, + IN BOOLEAN bDepth + ); + +VOID +SetTDLinkPtr ( + IN TD_STRUCT *ptrTDStruct, + IN VOID *ptrNext + ); + +VOID * +GetTDLinkPtr ( + IN TD_STRUCT *ptrTDStruct + ); + +VOID +EnableorDisableTDShortPacket ( + IN TD_STRUCT *ptrTDStruct, + IN BOOLEAN bEnable + ); + +VOID +SetTDControlErrorCounter ( + IN TD_STRUCT *ptrTDStruct, + IN UINT8 nMaxErrors + ); + +VOID +SetTDLoworFullSpeedDevice ( + IN TD_STRUCT *ptrTDStruct, + IN BOOLEAN bLowSpeedDevice + ); + +VOID +SetTDControlIsochronousorNot ( + IN TD_STRUCT *ptrTDStruct, + IN BOOLEAN bIsochronous + ); + +VOID +SetorClearTDControlIOC ( + IN TD_STRUCT *ptrTDStruct, + IN BOOLEAN bSet + ); + +VOID +SetTDStatusActiveorInactive ( + IN TD_STRUCT *ptrTDStruct, + IN BOOLEAN bActive + ); + +UINT16 +SetTDTokenMaxLength ( + IN TD_STRUCT *ptrTDStruct, + IN UINT16 nMaxLen + ); + +VOID +SetTDTokenDataToggle1 ( + IN TD_STRUCT *ptrTDStruct + ); + +VOID +SetTDTokenDataToggle0 ( + IN TD_STRUCT *ptrTDStruct + ); + +UINT8 +GetTDTokenDataToggle ( + IN TD_STRUCT *ptrTDStruct + ); + +VOID +SetTDTokenEndPoint ( + IN TD_STRUCT *ptrTDStruct, + IN UINTN nEndPoint + ); + +VOID +SetTDTokenDeviceAddress ( + IN TD_STRUCT *ptrTDStruct, + IN UINTN nDevAddr + ); + +VOID +SetTDTokenPacketID ( + IN TD_STRUCT *ptrTDStruct, + IN UINT8 nPID + ); + +VOID +SetTDDataBuffer ( + IN TD_STRUCT *ptrTDStruct + ); + +BOOLEAN +IsTDStatusActive ( + IN TD_STRUCT *ptrTDStruct + ); + +BOOLEAN +IsTDStatusStalled ( + IN TD_STRUCT *ptrTDStruct + ); + +BOOLEAN +IsTDStatusBufferError ( + IN TD_STRUCT *ptrTDStruct + ); + +BOOLEAN +IsTDStatusBabbleError ( + IN TD_STRUCT *ptrTDStruct + ); + +BOOLEAN +IsTDStatusNAKReceived ( + IN TD_STRUCT *ptrTDStruct + ); + +BOOLEAN +IsTDStatusCRCTimeOutError ( + IN TD_STRUCT *ptrTDStruct + ); + +BOOLEAN +IsTDStatusBitStuffError ( + IN TD_STRUCT *ptrTDStruct + ); + +UINT16 +GetTDStatusActualLength ( + IN TD_STRUCT *ptrTDStruct + ); + +UINT16 +GetTDTokenMaxLength ( + IN TD_STRUCT *ptrTDStruct + ); + +UINT8 +GetTDTokenEndPoint ( + IN TD_STRUCT *ptrTDStruct + ); + +UINT8 +GetTDTokenDeviceAddress ( + IN TD_STRUCT *ptrTDStruct + ); + +UINT8 +GetTDTokenPacketID ( + IN TD_STRUCT *ptrTDStruct + ); + +UINT8 * +GetTDDataBuffer ( + IN TD_STRUCT *ptrTDStruct + ); + +BOOLEAN +GetTDLinkPtrValidorInvalid ( + IN TD_STRUCT *ptrTDStruct + ); + +UINTN +CountTDsNumber ( + IN TD_STRUCT *ptrFirstTD + ); + +VOID +LinkTDToQH ( + IN QH_STRUCT *ptrQH, + IN TD_STRUCT *ptrTD + ); + +VOID +LinkTDToTD ( + IN TD_STRUCT *ptrPreTD, + IN TD_STRUCT *ptrTD + ); + +VOID +SetorClearCurFrameListTerminate ( + IN FRAMELIST_ENTRY *pCurEntry, + IN BOOLEAN bSet + ); + +VOID +SetCurFrameListQHorTD ( + IN FRAMELIST_ENTRY *pCurEntry, + IN BOOLEAN bQH + ); + +BOOLEAN +GetCurFrameListTerminate ( + IN FRAMELIST_ENTRY *pCurEntry + ); + +VOID +SetCurFrameListPointer ( + IN FRAMELIST_ENTRY *pCurEntry, + IN UINT8 *ptr + ); + +VOID * +GetCurFrameListPointer ( + IN FRAMELIST_ENTRY *pCurEntry + ); + +VOID +LinkQHToFrameList ( + IN FRAMELIST_ENTRY *pEntry, + IN UINT16 FrameListIndex, + IN QH_STRUCT *ptrQH + ); +/*++ + +Routine Description: + + Link QH To Frame List + +Arguments: + + pEntry - FRAMELIST_ENTRY + FrameListIndex - Frame List Index + PtrQH - QH to link +Returns: + + VOID + +--*/ +VOID +DeleteQHTDs ( + IN FRAMELIST_ENTRY *pEntry, + IN QH_STRUCT *ptrQH, + IN TD_STRUCT *ptrFirstTD, + IN UINT16 FrameListIndex, + IN BOOLEAN SearchOther + ); + +VOID +DelLinkSingleQH ( + IN USB_HC_DEV *HcDev, + IN QH_STRUCT *ptrQH, + IN UINT16 FrameListIndex, + IN BOOLEAN SearchOther, + IN BOOLEAN Delete + ); + +VOID +DeleteQueuedTDs ( + IN USB_HC_DEV *HcDev, + IN TD_STRUCT *ptrFirstTD + ); + +VOID +InsertQHTDToINTList ( + IN USB_HC_DEV *HcDev, + IN QH_STRUCT *ptrQH, + IN TD_STRUCT *ptrFirstTD, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 DataToggle, + IN UINTN DataLength, + IN UINTN PollingInterval, + IN VOID *Mapping, + IN UINT8 *DataBuffer, + IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction, + IN VOID *Context + ); +/*++ +Routine Description: + Insert QH and TD To Interrupt List +Arguments: + + HcDev - USB_HC_DEV + PtrQH - QH_STRUCT + PtrFirstTD - First TD_STRUCT + DeviceAddress - Device Address + EndPointAddress - EndPoint Address + DataToggle - Data Toggle + DataLength - Data length + PollingInterval - Polling Interval when inserted to frame list + Mapping - Mapping alue + DataBuffer - Data buffer + CallBackFunction- CallBackFunction after interrupt transfeer + Context - CallBackFunction Context passed as function parameter +Returns: + EFI_SUCCESS - Sucess + EFI_INVALID_PARAMETER - Paremeter is error + +--*/ + +EFI_STATUS +DeleteAsyncINTQHTDs ( + IN USB_HC_DEV *HcDev, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + OUT UINT8 *DataToggle + ); +/*++ +Routine Description: + + Delete Async INT QH and TDs +Arguments: + + HcDev - USB_HC_DEV + DeviceAddress - Device Address + EndPointAddress - EndPoint Address + DataToggle - Data Toggle + +Returns: + EFI_SUCCESS - Sucess + EFI_INVALID_PARAMETER - Paremeter is error + +--*/ +BOOLEAN +CheckTDsResults ( + IN TD_STRUCT *ptrTD, + IN UINTN RequiredLen, + OUT UINT32 *Result, + OUT UINTN *ErrTDPos, + OUT UINTN *ActualTransferSize + ); +/*++ + +Routine Description: + + Check TDs Results + +Arguments: + + PtrTD - TD_STRUCT to check + RequiredLen - Required Len + Result - Transfer result + ErrTDPos - Error TD Position + ActualTransferSize - Actual Transfer Size + +Returns: + + TRUE - Sucess + FALSE - Fail + +--*/ +VOID +ExecuteAsyncINTTDs ( + IN USB_HC_DEV *HcDev, + IN INTERRUPT_LIST *ptrList, + OUT UINT32 *Result, + OUT UINTN *ErrTDPos, + OUT UINTN *ActualLen + ) ; +/*++ + +Routine Description: + + Execute Async Interrupt TDs + +Arguments: + + HcDev - USB_HC_DEV + PtrList - INTERRUPT_LIST + Result - Transfer result + ErrTDPos - Error TD Position + ActualTransferSize - Actual Transfer Size + +Returns: + + VOID + +--*/ +VOID +UpdateAsyncINTQHTDs ( + IN INTERRUPT_LIST *ptrList, + IN UINT32 Result, + IN UINT32 ErrTDPos + ); +/*++ + +Routine Description: + + Update Async Interrupt QH and TDs + +Arguments: + + PtrList - INTERRUPT_LIST + Result - Transfer reslut + ErrTDPos - Error TD Position + +Returns: + + VOID + +--*/ +VOID +ReleaseInterruptList ( + IN USB_HC_DEV *HcDev, + IN LIST_ENTRY *ListHead + ); +/*++ + +Routine Description: + + Release Interrupt List +Arguments: + + HcDev - USB_HC_DEV + ListHead - List head + +Returns: + + VOID + +--*/ +EFI_STATUS +ExecuteControlTransfer ( + IN USB_HC_DEV *HcDev, + IN TD_STRUCT *ptrTD, + IN UINT32 wIndex, + OUT UINTN *ActualLen, + IN UINTN TimeOut, + OUT UINT32 *TransferResult + ); +/*++ + +Routine Description: + + Execute Control Transfer + +Arguments: + + HcDev - USB_HC_DEV + PtrTD - TD_STRUCT + wIndex - No use + ActualLen - Actual transfered Len + TimeOut - TimeOut value in milliseconds + TransferResult - Transfer result +Returns: + + EFI_SUCCESS - Sucess + EFI_DEVICE_ERROR - Error + + +--*/ +EFI_STATUS +ExecBulkorSyncInterruptTransfer ( + IN USB_HC_DEV *HcDev, + IN TD_STRUCT *ptrTD, + IN UINT32 wIndex, + OUT UINTN *ActualLen, + OUT UINT8 *DataToggle, + IN UINTN TimeOut, + OUT UINT32 *TransferResult + ); +/*++ + +Routine Description: + + Execute Bulk or SyncInterrupt Transfer + +Arguments: + + HcDev - USB_HC_DEV + PtrTD - TD_STRUCT + wIndex - No use + ActualLen - Actual transfered Len + DataToggle - Data Toggle + TimeOut - TimeOut value in milliseconds + TransferResult - Transfer result +Returns: + + EFI_SUCCESS - Sucess + EFI_DEVICE_ERROR - Error +--*/ + +EFI_STATUS +InitializeMemoryManagement ( + IN USB_HC_DEV *HcDev + ); + +EFI_STATUS +CreateMemoryBlock ( + IN USB_HC_DEV *HcDev, + IN MEMORY_MANAGE_HEADER **MemoryHeader, + IN UINTN MemoryBlockSizeInPages + ); + +EFI_STATUS +FreeMemoryHeader ( + IN USB_HC_DEV *HcDev, + IN MEMORY_MANAGE_HEADER *MemoryHeader + ); + +EFI_STATUS +UhciAllocatePool ( + IN USB_HC_DEV *UhcDev, + IN UINT8 **Pool, + IN UINTN AllocSize + ); + +VOID +UhciFreePool ( + IN USB_HC_DEV *HcDev, + IN UINT8 *Pool, + IN UINTN AllocSize + ); + +VOID +InsertMemoryHeaderToList ( + IN MEMORY_MANAGE_HEADER *MemoryHeader, + IN MEMORY_MANAGE_HEADER *NewMemoryHeader + ); + +EFI_STATUS +AllocMemInMemoryBlock ( + IN MEMORY_MANAGE_HEADER *MemoryHeader, + IN VOID **Pool, + IN UINTN NumberOfMemoryUnit + ); + +BOOLEAN +IsMemoryBlockEmptied ( + IN MEMORY_MANAGE_HEADER *MemoryHeaderPtr + ); + +VOID +DelinkMemoryBlock ( + IN MEMORY_MANAGE_HEADER *FirstMemoryHeader, + IN MEMORY_MANAGE_HEADER *FreeMemoryHeader + ); + +EFI_STATUS +DelMemoryManagement ( + IN USB_HC_DEV *HcDev + ); + +VOID +EnableMaxPacketSize ( + IN USB_HC_DEV *HcDev + ); + +VOID +CleanUsbTransactions ( + IN USB_HC_DEV *HcDev + ); + +VOID +TurnOffUSBEmulation ( + IN EFI_PCI_IO_PROTOCOL *PciIo + ); + +#endif diff --git a/EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/Decode.c b/EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/Decode.c new file mode 100644 index 0000000000..f851b9b961 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/Decode.c @@ -0,0 +1,1661 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module name: + decode.c + +Abstract: + +Revision history: + +--*/ + +// TODO: fix comment to add: Module Name: DECODE.C +#include "undi32.h" + + +#pragma data_seg("rtdata") + +// +// Global variables defined outside this file +// +extern PXE_SW_UNDI *pxe; // !pxe structure +extern PXE_SW_UNDI *pxe_31; // !pxe structure for 3.1 drivers +extern UNDI32_DEV *UNDI32DeviceList[MAX_NIC_INTERFACES]; + +// +// Global variables defined in this file +// +UNDI_CALL_TABLE api_table[PXE_OPCODE_LAST_VALID+1] = { \ + {PXE_CPBSIZE_NOT_USED,PXE_DBSIZE_NOT_USED,0, (UINT16)(ANY_STATE),UNDI_GetState },\ + {(UINT16)(DONT_CHECK),PXE_DBSIZE_NOT_USED,0,(UINT16)(ANY_STATE),UNDI_Start },\ + {PXE_CPBSIZE_NOT_USED,PXE_DBSIZE_NOT_USED,0,MUST_BE_STARTED,UNDI_Stop },\ + {PXE_CPBSIZE_NOT_USED,sizeof(PXE_DB_GET_INIT_INFO),0,MUST_BE_STARTED, UNDI_GetInitInfo },\ + {PXE_CPBSIZE_NOT_USED,sizeof(PXE_DB_GET_CONFIG_INFO),0,MUST_BE_STARTED, UNDI_GetConfigInfo },\ + {sizeof(PXE_CPB_INITIALIZE),(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK),MUST_BE_STARTED,UNDI_Initialize },\ + {PXE_CPBSIZE_NOT_USED,PXE_DBSIZE_NOT_USED,(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED,UNDI_Reset },\ + {PXE_CPBSIZE_NOT_USED,PXE_DBSIZE_NOT_USED,0, MUST_BE_INITIALIZED,UNDI_Shutdown },\ + {PXE_CPBSIZE_NOT_USED,PXE_DBSIZE_NOT_USED,(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED,UNDI_Interrupt },\ + {(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_RecFilter },\ + {(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_StnAddr },\ + {PXE_CPBSIZE_NOT_USED, (UINT16)(DONT_CHECK), (UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_Statistics },\ + {sizeof(PXE_CPB_MCAST_IP_TO_MAC),sizeof(PXE_DB_MCAST_IP_TO_MAC), (UINT16)(DONT_CHECK),MUST_BE_INITIALIZED, UNDI_ip2mac },\ + {(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_NVData },\ + {PXE_CPBSIZE_NOT_USED,(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_Status },\ + {(UINT16)(DONT_CHECK),PXE_DBSIZE_NOT_USED,(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_FillHeader },\ + {(UINT16)(DONT_CHECK),PXE_DBSIZE_NOT_USED,(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_Transmit },\ + {sizeof(PXE_CPB_RECEIVE),sizeof(PXE_DB_RECEIVE),0,MUST_BE_INITIALIZED, UNDI_Receive } \ +}; + +// +// end of global variables +// + +VOID +UNDI_GetState ( + IN PXE_CDB *CdbPtr, + IN NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + This routine determines the operational state of the UNDI. It updates the state flags in the + Command Descriptor Block based on information derived from the AdapterInfo instance data. + + To ensure the command has completed successfully, CdbPtr->StatCode will contain the result of + the command execution. + + The CdbPtr->StatFlags will contain a STOPPED, STARTED, or INITIALIZED state once the command + has successfully completed. + + Keep in mind the AdapterInfo->State is the active state of the adapter (based on software + interrogation), and the CdbPtr->StateFlags is the passed back information that is reflected + to the caller of the UNDI API. + +Arguments: + CdbPtr - Pointer to the command descriptor block. + AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on.. + +Returns: + None + +--*/ +{ + CdbPtr->StatFlags |= AdapterInfo->State; + return ; +} + +VOID +UNDI_Start ( + IN PXE_CDB *CdbPtr, + IN NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + This routine is used to change the operational state of the UNDI from stopped to started. + It will do this as long as the adapter's state is PXE_STATFLAGS_GET_STATE_STOPPED, otherwise + the CdbPtr->StatFlags will reflect a command failure, and the CdbPtr->StatCode will reflect the + UNDI as having already been started. + + This routine is modified to reflect the undi 1.1 specification changes. The + changes in the spec are mainly in the callback routines, the new spec adds + 3 more callbacks and a unique id. + Since this UNDI supports both old and new undi specifications, + The NIC's data structure is filled in with the callback routines (depending + on the version) pointed to in the caller's CpbPtr. This seeds the Delay, + Virt2Phys, Block, and Mem_IO for old and new versions and Map_Mem, UnMap_Mem + and Sync_Mem routines and a unique id variable for the new version. + This is the function which an external entity (SNP, O/S, etc) would call + to provide it's I/O abstraction to the UNDI. + + It's final action is to change the AdapterInfo->State to PXE_STATFLAGS_GET_STATE_STARTED. + +Arguments: + CdbPtr - Pointer to the command descriptor block. + AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on.. + +Returns: + None + +--*/ +{ + PXE_CPB_START_30 *CpbPtr; + PXE_CPB_START_31 *CpbPtr_31; + + // + // check if it is already started. + // + if (AdapterInfo->State != PXE_STATFLAGS_GET_STATE_STOPPED) { + CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; + CdbPtr->StatCode = PXE_STATCODE_ALREADY_STARTED; + return ; + } + + if (CdbPtr->CPBsize != sizeof(PXE_CPB_START_30) && + CdbPtr->CPBsize != sizeof(PXE_CPB_START_31)) { + + CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; + CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB; + return ; + } + + CpbPtr = (PXE_CPB_START_30 *) (UINTN) (CdbPtr->CPBaddr); + CpbPtr_31 = (PXE_CPB_START_31 *) (UINTN) (CdbPtr->CPBaddr); + + if (AdapterInfo->VersionFlag == 0x30) { + AdapterInfo->Delay_30 = (bsptr_30) (UINTN) CpbPtr->Delay; + AdapterInfo->Virt2Phys_30 = (virtphys_30) (UINTN) CpbPtr->Virt2Phys; + AdapterInfo->Block_30 = (block_30) (UINTN) CpbPtr->Block; + // + // patch for old buggy 3.0 code: + // In EFI1.0 undi used to provide the full (absolute) I/O address to the + // i/o calls and SNP used to provide a callback that used GlobalIoFncs and + // everything worked fine! In EFI 1.1, UNDI is not using the full + // i/o or memory address to access the device, The base values for the i/o + // and memory address is abstracted by the device specific PciIoFncs and + // UNDI only uses the offset values. Since UNDI3.0 cannot provide any + // identification to SNP, SNP cannot use nic specific PciIoFncs callback! + // + // To fix this and make undi3.0 work with SNP in EFI1.1 we + // use a TmpMemIo function that is defined in init.c + // This breaks the runtime driver feature of undi, but what to do + // if we have to provide the 3.0 compatibility (including the 3.0 bugs) + // + // This TmpMemIo function also takes a UniqueId parameter + // (as in undi3.1 design) and so initialize the UniqueId as well here + // Note: AdapterInfo->Mem_Io_30 is just filled for consistency with other + // parameters but never used, we only use Mem_Io field in the In/Out routines + // inside e100b.c. + // + AdapterInfo->Mem_Io_30 = (mem_io_30) (UINTN) CpbPtr->Mem_IO; + AdapterInfo->Mem_Io = (mem_io) (UINTN) TmpMemIo; + AdapterInfo->Unique_ID = (UINT64) (UINTN) AdapterInfo; + + } else { + AdapterInfo->Delay = (bsptr) (UINTN) CpbPtr_31->Delay; + AdapterInfo->Virt2Phys = (virtphys) (UINTN) CpbPtr_31->Virt2Phys; + AdapterInfo->Block = (block) (UINTN) CpbPtr_31->Block; + AdapterInfo->Mem_Io = (mem_io) (UINTN) CpbPtr_31->Mem_IO; + + AdapterInfo->Map_Mem = (map_mem) (UINTN) CpbPtr_31->Map_Mem; + AdapterInfo->UnMap_Mem = (unmap_mem) (UINTN) CpbPtr_31->UnMap_Mem; + AdapterInfo->Sync_Mem = (sync_mem) (UINTN) CpbPtr_31->Sync_Mem; + AdapterInfo->Unique_ID = CpbPtr_31->Unique_ID; + } + + AdapterInfo->State = PXE_STATFLAGS_GET_STATE_STARTED; + + return ; +} + +VOID +UNDI_Stop ( + IN PXE_CDB *CdbPtr, + IN NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + This routine is used to change the operational state of the UNDI from started to stopped. + It will not do this if the adapter's state is PXE_STATFLAGS_GET_STATE_INITIALIZED, otherwise + the CdbPtr->StatFlags will reflect a command failure, and the CdbPtr->StatCode will reflect the + UNDI as having already not been shut down. + + The NIC's data structure will have the Delay, Virt2Phys, and Block, pointers zero'd out.. + + It's final action is to change the AdapterInfo->State to PXE_STATFLAGS_GET_STATE_STOPPED. + +Arguments: + CdbPtr - Pointer to the command descriptor block. + AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on.. + +Returns: + None + +--*/ +{ + if (AdapterInfo->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) { + CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; + CdbPtr->StatCode = PXE_STATCODE_NOT_SHUTDOWN; + return ; + } + + AdapterInfo->Delay_30 = 0; + AdapterInfo->Virt2Phys_30 = 0; + AdapterInfo->Block_30 = 0; + + AdapterInfo->Delay = 0; + AdapterInfo->Virt2Phys = 0; + AdapterInfo->Block = 0; + + AdapterInfo->Map_Mem = 0; + AdapterInfo->UnMap_Mem = 0; + AdapterInfo->Sync_Mem = 0; + + AdapterInfo->State = PXE_STATFLAGS_GET_STATE_STOPPED; + + return ; +} + +VOID +UNDI_GetInitInfo ( + IN PXE_CDB *CdbPtr, + IN NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + This routine is used to retrieve the initialization information that is needed by drivers and + applications to initialize the UNDI. This will fill in data in the Data Block structure that is + pointed to by the caller's CdbPtr->DBaddr. The fields filled in are as follows: + + MemoryRequired, FrameDataLen, LinkSpeeds[0-3], NvCount, NvWidth, MediaHeaderLen, HWaddrLen, + MCastFilterCnt, TxBufCnt, TxBufSize, RxBufCnt, RxBufSize, IFtype, Duplex, and LoopBack. + + In addition, the CdbPtr->StatFlags ORs in that this NIC supports cable detection. (APRIORI knowledge) + +Arguments: + CdbPtr - Pointer to the command descriptor block. + AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on.. + +Returns: + None + +--*/ +{ + PXE_DB_GET_INIT_INFO *DbPtr; + + DbPtr = (PXE_DB_GET_INIT_INFO *) (UINTN) (CdbPtr->DBaddr); + + DbPtr->MemoryRequired = MEMORY_NEEDED; + DbPtr->FrameDataLen = PXE_MAX_TXRX_UNIT_ETHER; + DbPtr->LinkSpeeds[0] = 10; + DbPtr->LinkSpeeds[1] = 100; + DbPtr->LinkSpeeds[2] = DbPtr->LinkSpeeds[3] = 0; + DbPtr->NvCount = MAX_EEPROM_LEN; + DbPtr->NvWidth = 4; + DbPtr->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER; + DbPtr->HWaddrLen = PXE_HWADDR_LEN_ETHER; + DbPtr->MCastFilterCnt = MAX_MCAST_ADDRESS_CNT; + + DbPtr->TxBufCnt = TX_BUFFER_COUNT; + DbPtr->TxBufSize = sizeof (TxCB); + DbPtr->RxBufCnt = RX_BUFFER_COUNT; + DbPtr->RxBufSize = sizeof (RxFD); + + DbPtr->IFtype = PXE_IFTYPE_ETHERNET; + DbPtr->SupportedDuplexModes = PXE_DUPLEX_ENABLE_FULL_SUPPORTED | + PXE_DUPLEX_FORCE_FULL_SUPPORTED; + DbPtr->SupportedLoopBackModes = PXE_LOOPBACK_INTERNAL_SUPPORTED | + PXE_LOOPBACK_EXTERNAL_SUPPORTED; + + CdbPtr->StatFlags |= PXE_STATFLAGS_CABLE_DETECT_SUPPORTED; + return ; +} + +VOID +UNDI_GetConfigInfo ( + IN PXE_CDB *CdbPtr, + IN NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + This routine is used to retrieve the configuration information about the NIC being controlled by + this driver. This will fill in data in the Data Block structure that is pointed to by the caller's CdbPtr->DBaddr. + The fields filled in are as follows: + + DbPtr->pci.BusType, DbPtr->pci.Bus, DbPtr->pci.Device, and DbPtr->pci. + + In addition, the DbPtr->pci.Config.Dword[0-63] grabs a copy of this NIC's PCI configuration space. + +Arguments: + CdbPtr - Pointer to the command descriptor block. + AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on.. + +Returns: + None + +--*/ +{ + UINT16 Index; + PXE_DB_GET_CONFIG_INFO *DbPtr; + + DbPtr = (PXE_DB_GET_CONFIG_INFO *) (UINTN) (CdbPtr->DBaddr); + + DbPtr->pci.BusType = PXE_BUSTYPE_PCI; + DbPtr->pci.Bus = AdapterInfo->Bus; + DbPtr->pci.Device = AdapterInfo->Device; + DbPtr->pci.Function = AdapterInfo->Function; + + for (Index = 0; Index < MAX_PCI_CONFIG_LEN; Index++) { + DbPtr->pci.Config.Dword[Index] = AdapterInfo->Config[Index]; + } + + return ; +} + +VOID +UNDI_Initialize ( + IN PXE_CDB *CdbPtr, + NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + This routine resets the network adapter and initializes the UNDI using the parameters supplied in + the CPB. This command must be issued before the network adapter can be setup to transmit and + receive packets. + + Once the memory requirements of the UNDI are obtained by using the GetInitInfo command, a block + of non-swappable memory may need to be allocated. The address of this memory must be passed to + UNDI during the Initialize in the CPB. This memory is used primarily for transmit and receive buffers. + + The fields CableDetect, LinkSpeed, Duplex, LoopBack, MemoryPtr, and MemoryLength are set with information + that was passed in the CPB and the NIC is initialized. + + If the NIC initialization fails, the CdbPtr->StatFlags are updated with PXE_STATFLAGS_COMMAND_FAILED + Otherwise, AdapterInfo->State is updated with PXE_STATFLAGS_GET_STATE_INITIALIZED showing the state of + the UNDI is now initialized. + +Arguments: + CdbPtr - Pointer to the command descriptor block. + AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on.. + +Returns: + None + +--*/ +{ + PXE_CPB_INITIALIZE *CpbPtr; + PXE_DB_INITIALIZE *DbPtr; + + if ((CdbPtr->OpFlags != PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) && + (CdbPtr->OpFlags != PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE)) { + CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; + CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB; + return ; + } + + // + // check if it is already initialized + // + if (AdapterInfo->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) { + CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; + CdbPtr->StatCode = PXE_STATCODE_ALREADY_INITIALIZED; + return ; + } + + CpbPtr = (PXE_CPB_INITIALIZE *) (UINTN) CdbPtr->CPBaddr; + DbPtr = (PXE_DB_INITIALIZE *) (UINTN) CdbPtr->DBaddr; + + if (CpbPtr->MemoryLength < (UINT32) MEMORY_NEEDED) { + CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; + CdbPtr->StatCode = PXE_STATCODE_INVALID_CPB; + return ; + } + + // + // default behaviour is to detect the cable, if the 3rd param is 1, + // do not do that + // + AdapterInfo->CableDetect = (UINT8) ((CdbPtr->OpFlags == (UINT16) PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE) ? (UINT8) 0 : (UINT8) 1); + AdapterInfo->LinkSpeedReq = (UINT16) CpbPtr->LinkSpeed; + AdapterInfo->DuplexReq = CpbPtr->DuplexMode; + AdapterInfo->LoopBack = CpbPtr->LoopBackMode; + AdapterInfo->MemoryPtr = CpbPtr->MemoryAddr; + AdapterInfo->MemoryLength = CpbPtr->MemoryLength; + + CdbPtr->StatCode = (PXE_STATCODE) E100bInit (AdapterInfo); + + if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) { + CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; + } else { + AdapterInfo->State = PXE_STATFLAGS_GET_STATE_INITIALIZED; + } + + return ; +} + +VOID +UNDI_Reset ( + IN PXE_CDB *CdbPtr, + IN NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + This routine resets the network adapter and initializes the UNDI using the parameters supplied in + the CPB. The transmit and receive queues are emptied and any pending interrupts are cleared. + + If the NIC reset fails, the CdbPtr->StatFlags are updated with PXE_STATFLAGS_COMMAND_FAILED + +Arguments: + CdbPtr - Pointer to the command descriptor block. + AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on.. + +Returns: + None + +--*/ +{ + if (CdbPtr->OpFlags != PXE_OPFLAGS_NOT_USED && + CdbPtr->OpFlags != PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS && + CdbPtr->OpFlags != PXE_OPFLAGS_RESET_DISABLE_FILTERS ) { + + CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; + CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB; + return ; + } + + CdbPtr->StatCode = (UINT16) E100bReset (AdapterInfo, CdbPtr->OpFlags); + + if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) { + CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; + } +} + +VOID +UNDI_Shutdown ( + IN PXE_CDB *CdbPtr, + IN NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + This routine resets the network adapter and leaves it in a safe state for another driver to + initialize. Any pending transmits or receives are lost. Receive filters and external + interrupt enables are disabled. Once the UNDI has been shutdown, it can then be stopped + or initialized again. + + If the NIC reset fails, the CdbPtr->StatFlags are updated with PXE_STATFLAGS_COMMAND_FAILED + + Otherwise, AdapterInfo->State is updated with PXE_STATFLAGS_GET_STATE_STARTED showing the state of + the NIC as being started. + +Arguments: + CdbPtr - Pointer to the command descriptor block. + AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on.. + +Returns: + None + +--*/ +{ + // + // do the shutdown stuff here + // + CdbPtr->StatCode = (UINT16) E100bShutdown (AdapterInfo); + + if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) { + CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; + } else { + AdapterInfo->State = PXE_STATFLAGS_GET_STATE_STARTED; + } + + return ; +} + +VOID +UNDI_Interrupt ( + IN PXE_CDB *CdbPtr, + IN NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + This routine can be used to read and/or change the current external interrupt enable + settings. Disabling an external interrupt enable prevents and external (hardware) + interrupt from being signaled by the network device. Internally the interrupt events + can still be polled by using the UNDI_GetState command. + + The resulting information on the interrupt state will be passed back in the CdbPtr->StatFlags. + +Arguments: + CdbPtr - Pointer to the command descriptor block. + AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on.. + +Returns: + None + +--*/ +{ + UINT8 IntMask; + + IntMask = (UINT8)(UINTN)(CdbPtr->OpFlags & (PXE_OPFLAGS_INTERRUPT_RECEIVE | + PXE_OPFLAGS_INTERRUPT_TRANSMIT | + PXE_OPFLAGS_INTERRUPT_COMMAND | + PXE_OPFLAGS_INTERRUPT_SOFTWARE)); + + switch (CdbPtr->OpFlags & PXE_OPFLAGS_INTERRUPT_OPMASK) { + case PXE_OPFLAGS_INTERRUPT_READ: + break; + + case PXE_OPFLAGS_INTERRUPT_ENABLE: + if (IntMask == 0) { + CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; + CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB; + return ; + } + + AdapterInfo->int_mask = IntMask; + E100bSetInterruptState (AdapterInfo); + break; + + case PXE_OPFLAGS_INTERRUPT_DISABLE: + if (IntMask != 0) { + AdapterInfo->int_mask &= ~(IntMask); + E100bSetInterruptState (AdapterInfo); + break; + } + + // + // else fall thru. + // + default: + CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; + CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB; + return ; + } + + if ((AdapterInfo->int_mask & PXE_OPFLAGS_INTERRUPT_RECEIVE) != 0) { + CdbPtr->StatFlags |= PXE_STATFLAGS_INTERRUPT_RECEIVE; + + } + + if ((AdapterInfo->int_mask & PXE_OPFLAGS_INTERRUPT_TRANSMIT) != 0) { + CdbPtr->StatFlags |= PXE_STATFLAGS_INTERRUPT_TRANSMIT; + + } + + if ((AdapterInfo->int_mask & PXE_OPFLAGS_INTERRUPT_COMMAND) != 0) { + CdbPtr->StatFlags |= PXE_STATFLAGS_INTERRUPT_COMMAND; + + } + + return ; +} + +VOID +UNDI_RecFilter ( + IN PXE_CDB *CdbPtr, + IN NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + This routine is used to read and change receive filters and, if supported, read + and change multicast MAC address filter list. + +Arguments: + CdbPtr - Pointer to the command descriptor block. + AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on.. + +Returns: + None + +--*/ +{ + UINT16 NewFilter; + UINT16 OpFlags; + PXE_DB_RECEIVE_FILTERS *DbPtr; + UINT8 *MacAddr; + UINTN MacCount; + UINT16 Index; + UINT16 copy_len; + UINT8 *ptr1; + UINT8 *ptr2; + OpFlags = CdbPtr->OpFlags; + NewFilter = (UINT16) (OpFlags & 0x1F); + + switch (OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_OPMASK) { + case PXE_OPFLAGS_RECEIVE_FILTER_READ: + + // + // not expecting a cpb, not expecting any filter bits + // + if ((NewFilter != 0) || (CdbPtr->CPBsize != 0)) { + goto BadCdb; + + } + + if ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) == 0) { + goto JustRead; + + } + + NewFilter |= AdapterInfo->Rx_Filter; + // + // all other flags are ignored except mcast_reset + // + break; + + case PXE_OPFLAGS_RECEIVE_FILTER_ENABLE: + // + // there should be atleast one other filter bit set. + // + if (NewFilter == 0) { + // + // nothing to enable + // + goto BadCdb; + } + + if (CdbPtr->CPBsize != 0) { + // + // this must be a multicast address list! + // don't accept the list unless selective_mcast is set + // don't accept confusing mcast settings with this + // + if (((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) == 0) || + ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) || + ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) || + ((CdbPtr->CPBsize % sizeof (PXE_MAC_ADDR)) != 0) ) { + goto BadCdb; + } + + MacAddr = (UINT8 *) ((UINTN) (CdbPtr->CPBaddr)); + MacCount = CdbPtr->CPBsize / sizeof (PXE_MAC_ADDR); + + for (; MacCount-- != 0; MacAddr += sizeof (PXE_MAC_ADDR)) { + if (MacAddr[0] != 0x01 || MacAddr[1] != 0x00 || MacAddr[2] != 0x5E || (MacAddr[3] & 0x80) != 0) { + CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; + CdbPtr->StatCode = PXE_STATCODE_INVALID_CPB; + return ; + } + } + } + + // + // check selective mcast case enable case + // + if ((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) { + if (((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) || + ((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) ) { + goto BadCdb; + + } + // + // if no cpb, make sure we have an old list + // + if ((CdbPtr->CPBsize == 0) && (AdapterInfo->mcast_list.list_len == 0)) { + goto BadCdb; + } + } + // + // if you want to enable anything, you got to have unicast + // and you have what you already enabled! + // + NewFilter |= (PXE_OPFLAGS_RECEIVE_FILTER_UNICAST | AdapterInfo->Rx_Filter); + + break; + + case PXE_OPFLAGS_RECEIVE_FILTER_DISABLE: + + // + // mcast list not expected, i.e. no cpb here! + // + if (CdbPtr->CPBsize != PXE_CPBSIZE_NOT_USED) { + goto BadCdb; + } + + NewFilter = (UINT16) ((~(CdbPtr->OpFlags & 0x1F)) & AdapterInfo->Rx_Filter); + + break; + + default: + goto BadCdb; + } + + if ((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) { + AdapterInfo->mcast_list.list_len = 0; + NewFilter &= (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST); + } + + E100bSetfilter (AdapterInfo, NewFilter, CdbPtr->CPBaddr, CdbPtr->CPBsize); + +JustRead: + // + // give the current mcast list + // + if ((CdbPtr->DBsize != 0) && (AdapterInfo->mcast_list.list_len != 0)) { + // + // copy the mc list to db + // + + DbPtr = (PXE_DB_RECEIVE_FILTERS *) (UINTN) CdbPtr->DBaddr; + ptr1 = (UINT8 *) (&DbPtr->MCastList[0]); + + // + // DbPtr->mc_count = AdapterInfo->mcast_list.list_len; + // + copy_len = (UINT16) (AdapterInfo->mcast_list.list_len * PXE_MAC_LENGTH); + + if (copy_len > CdbPtr->DBsize) { + copy_len = CdbPtr->DBsize; + + } + + ptr2 = (UINT8 *) (&AdapterInfo->mcast_list.mc_list[0]); + for (Index = 0; Index < copy_len; Index++) { + ptr1[Index] = ptr2[Index]; + } + } + // + // give the stat flags here + // + if (AdapterInfo->Receive_Started) { + CdbPtr->StatFlags |= AdapterInfo->Rx_Filter; + + } + + return ; + +BadCdb: + CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; + CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB; +} + +VOID +UNDI_StnAddr ( + IN PXE_CDB *CdbPtr, + IN NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + This routine is used to get the current station and broadcast MAC addresses, and to change the + current station MAC address. + +Arguments: + CdbPtr - Pointer to the command descriptor block. + AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on.. + +Returns: + None + +--*/ +{ + PXE_CPB_STATION_ADDRESS *CpbPtr; + PXE_DB_STATION_ADDRESS *DbPtr; + UINT16 Index; + + if (CdbPtr->OpFlags == PXE_OPFLAGS_STATION_ADDRESS_RESET) { + // + // configure the permanent address. + // change the AdapterInfo->CurrentNodeAddress field. + // + if (CompareMem ( + &AdapterInfo->CurrentNodeAddress[0], + &AdapterInfo->PermNodeAddress[0], + PXE_MAC_LENGTH + ) != 0) { + for (Index = 0; Index < PXE_MAC_LENGTH; Index++) { + AdapterInfo->CurrentNodeAddress[Index] = AdapterInfo->PermNodeAddress[Index]; + } + + E100bSetupIAAddr (AdapterInfo); + } + } + + if (CdbPtr->CPBaddr != (UINT64) 0) { + CpbPtr = (PXE_CPB_STATION_ADDRESS *) (UINTN) (CdbPtr->CPBaddr); + // + // configure the new address + // + for (Index = 0; Index < PXE_MAC_LENGTH; Index++) { + AdapterInfo->CurrentNodeAddress[Index] = CpbPtr->StationAddr[Index]; + } + + E100bSetupIAAddr (AdapterInfo); + } + + if (CdbPtr->DBaddr != (UINT64) 0) { + DbPtr = (PXE_DB_STATION_ADDRESS *) (UINTN) (CdbPtr->DBaddr); + // + // fill it with the new values + // + for (Index = 0; Index < PXE_MAC_LENGTH; Index++) { + DbPtr->StationAddr[Index] = AdapterInfo->CurrentNodeAddress[Index]; + DbPtr->BroadcastAddr[Index] = AdapterInfo->BroadcastNodeAddress[Index]; + DbPtr->PermanentAddr[Index] = AdapterInfo->PermNodeAddress[Index]; + } + } + + return ; +} + +VOID +UNDI_Statistics ( + IN PXE_CDB *CdbPtr, + IN NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + This routine is used to read and clear the NIC traffic statistics. This command is supported only + if the !PXE structure's Implementation flags say so. + + Results will be parsed out in the following manner: + CdbPtr->DBaddr.Data[0] R Total Frames (Including frames with errors and dropped frames) + CdbPtr->DBaddr.Data[1] R Good Frames (All frames copied into receive buffer) + CdbPtr->DBaddr.Data[2] R Undersize Frames (Frames below minimum length for media <64 for ethernet) + CdbPtr->DBaddr.Data[4] R Dropped Frames (Frames that were dropped because receive buffers were full) + CdbPtr->DBaddr.Data[8] R CRC Error Frames (Frames with alignment or CRC errors) + CdbPtr->DBaddr.Data[A] T Total Frames (Including frames with errors and dropped frames) + CdbPtr->DBaddr.Data[B] T Good Frames (All frames copied into transmit buffer) + CdbPtr->DBaddr.Data[C] T Undersize Frames (Frames below minimum length for media <64 for ethernet) + CdbPtr->DBaddr.Data[E] T Dropped Frames (Frames that were dropped because of collisions) + CdbPtr->DBaddr.Data[14] T Total Collision Frames (Total collisions on this subnet) + +Arguments: + CdbPtr - Pointer to the command descriptor block. + AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on.. + +Returns: + None + +--*/ +{ + if ((CdbPtr->OpFlags &~(PXE_OPFLAGS_STATISTICS_RESET)) != 0) { + CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; + CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB; + return ; + } + + if ((CdbPtr->OpFlags & PXE_OPFLAGS_STATISTICS_RESET) != 0) { + // + // Reset the statistics + // + CdbPtr->StatCode = (UINT16) E100bStatistics (AdapterInfo, 0, 0); + } else { + CdbPtr->StatCode = (UINT16) E100bStatistics (AdapterInfo, CdbPtr->DBaddr, CdbPtr->DBsize); + } + + return ; +} + +VOID +UNDI_ip2mac ( + IN PXE_CDB *CdbPtr, + IN NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + This routine is used to translate a multicast IP address to a multicast MAC address. + + This results in a MAC address composed of 25 bits of fixed data with the upper 23 bits of the IP + address being appended to it. Results passed back in the equivalent of CdbPtr->DBaddr->MAC[0-5]. + +Arguments: + CdbPtr - Pointer to the command descriptor block. + AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on.. + +Returns: + None + +--*/ +{ + PXE_CPB_MCAST_IP_TO_MAC *CpbPtr; + PXE_DB_MCAST_IP_TO_MAC *DbPtr; + UINT8 *TmpPtr; + + CpbPtr = (PXE_CPB_MCAST_IP_TO_MAC *) (UINTN) CdbPtr->CPBaddr; + DbPtr = (PXE_DB_MCAST_IP_TO_MAC *) (UINTN) CdbPtr->DBaddr; + + if ((CdbPtr->OpFlags & PXE_OPFLAGS_MCAST_IPV6_TO_MAC) != 0) { + // + // for now this is not supported + // + CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; + CdbPtr->StatCode = PXE_STATCODE_UNSUPPORTED; + return ; + } + + TmpPtr = (UINT8 *) (&CpbPtr->IP.IPv4); + // + // check if the ip given is a mcast IP + // + if ((TmpPtr[0] & 0xF0) != 0xE0) { + CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; + CdbPtr->StatCode = PXE_STATCODE_INVALID_CPB; + } + // + // take the last 23 bits in IP. + // be very careful. accessing word on a non-word boundary will hang motherboard codenamed Big Sur + // casting the mac array (in the middle) to a UINT32 pointer and accessing + // the UINT32 content hung the system... + // + DbPtr->MAC[0] = 0x01; + DbPtr->MAC[1] = 0x00; + DbPtr->MAC[2] = 0x5e; + DbPtr->MAC[3] = (UINT8) (TmpPtr[1] & 0x7f); + DbPtr->MAC[4] = (UINT8) TmpPtr[2]; + DbPtr->MAC[5] = (UINT8) TmpPtr[3]; + + return ; +} + +VOID +UNDI_NVData ( + IN PXE_CDB *CdbPtr, + IN NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + This routine is used to read and write non-volatile storage on the NIC (if supported). The NVRAM + could be EEPROM, FLASH, or battery backed RAM. + + This is an optional function according to the UNDI specification (or will be......) + +Arguments: + CdbPtr - Pointer to the command descriptor block. + AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on.. + +Returns: + None + +--*/ +{ + PXE_DB_NVDATA *DbPtr; + UINT16 Index; + + if ((CdbPtr->OpFlags == PXE_OPFLAGS_NVDATA_READ) != 0) { + + if ((CdbPtr->DBsize == PXE_DBSIZE_NOT_USED) != 0) { + CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; + CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB; + return ; + } + + DbPtr = (PXE_DB_NVDATA *) (UINTN) CdbPtr->DBaddr; + + for (Index = 0; Index < MAX_PCI_CONFIG_LEN; Index++) { + DbPtr->Data.Dword[Index] = AdapterInfo->NVData[Index]; + + } + + } else { + // + // no write for now + // + CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; + CdbPtr->StatCode = PXE_STATCODE_UNSUPPORTED; + } + + return ; +} + +VOID +UNDI_Status ( + IN PXE_CDB *CdbPtr, + IN NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + This routine returns the current interrupt status and/or the transmitted buffer addresses. + If the current interrupt status is returned, pending interrupts will be acknowledged by this + command. Transmitted buffer addresses that are written to the DB are removed from the transmit + buffer queue. + + Normally, this command would be polled with interrupts disabled. + + The transmit buffers are returned in CdbPtr->DBaddr->TxBufer[0 - NumEntries]. + The interrupt status is returned in CdbPtr->StatFlags. + +Arguments: + CdbPtr - Pointer to the command descriptor block. + AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on.. + +Returns: + None + +--*/ +{ + PXE_DB_GET_STATUS *DbPtr; + PXE_DB_GET_STATUS TmpGetStatus; + UINT16 Index; + UINT16 Status; + UINT16 NumEntries; + RxFD *RxPtr; + + // + // Fill in temporary GetStatus storage. + // + RxPtr = &AdapterInfo->rx_ring[AdapterInfo->cur_rx_ind]; + + if ((RxPtr->cb_header.status & RX_COMPLETE) != 0) { + TmpGetStatus.RxFrameLen = RxPtr->ActualCount & 0x3fff; + } else { + TmpGetStatus.RxFrameLen = 0; + } + + TmpGetStatus.reserved = 0; + + // + // Fill in size of next available receive packet and + // reserved field in caller's DB storage. + // + DbPtr = (PXE_DB_GET_STATUS *) (UINTN) CdbPtr->DBaddr; + + if (CdbPtr->DBsize > 0 && CdbPtr->DBsize < sizeof (UINT32) * 2) { + CopyMem (DbPtr, &TmpGetStatus, CdbPtr->DBsize); + } else { + CopyMem (DbPtr, &TmpGetStatus, sizeof (UINT32) * 2); + } + + // + // + // + if ((CdbPtr->OpFlags & PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS) != 0) { + // + // DBsize of zero is invalid if Tx buffers are requested. + // + if (CdbPtr->DBsize == 0) { + CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; + CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB; + return ; + } + + // + // remember this b4 we overwrite + // + NumEntries = (UINT16) (CdbPtr->DBsize - sizeof (UINT64)); + + // + // We already filled in 2 UINT32s. + // + CdbPtr->DBsize = sizeof (UINT32) * 2; + + // + // will claim any hanging free CBs + // + CheckCBList (AdapterInfo); + + if (AdapterInfo->xmit_done_head == AdapterInfo->xmit_done_tail) { + CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_TXBUF_QUEUE_EMPTY; + } else { + for (Index = 0; NumEntries >= sizeof (UINT64); Index++, NumEntries -= sizeof (UINT64)) { + if (AdapterInfo->xmit_done_head != AdapterInfo->xmit_done_tail) { + DbPtr->TxBuffer[Index] = AdapterInfo->xmit_done[AdapterInfo->xmit_done_head]; + AdapterInfo->xmit_done_head = next (AdapterInfo->xmit_done_head); + CdbPtr->DBsize += sizeof (UINT64); + } else { + break; + } + } + } + + if (AdapterInfo->xmit_done_head != AdapterInfo->xmit_done_tail) { + CdbPtr->StatFlags |= PXE_STATFLAGS_DB_WRITE_TRUNCATED; + + } + // + // check for a receive buffer and give it's size in db + // + } + // + // + // + if ((CdbPtr->OpFlags & PXE_OPFLAGS_GET_INTERRUPT_STATUS) != 0) { + + Status = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBStatus); + AdapterInfo->Int_Status |= Status; + + // + // acknoledge the interrupts + // + OutWord (AdapterInfo, (UINT16) (Status & 0xfc00), (UINT32) (AdapterInfo->ioaddr + SCBStatus)); + + // + // report all the outstanding interrupts + // + Status = AdapterInfo->Int_Status; + if ((Status & SCB_STATUS_FR) != 0) { + CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_RECEIVE; + } + + if ((Status & SCB_STATUS_SWI) != 0) { + CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_SOFTWARE; + } + } + + return ; +} + +VOID +UNDI_FillHeader ( + IN PXE_CDB *CdbPtr, + IN NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + This routine is used to fill media header(s) in transmit packet(s). + Copies the MAC address into the media header whether it is dealing + with fragmented or non-fragmented packets. + +Arguments: + CdbPtr - Pointer to the command descriptor block. + AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on.. + +Returns: + None + +--*/ +{ + PXE_CPB_FILL_HEADER *Cpb; + PXE_CPB_FILL_HEADER_FRAGMENTED *Cpbf; + EtherHeader *MacHeader; + UINTN Index; + + if (CdbPtr->CPBsize == PXE_CPBSIZE_NOT_USED) { + CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; + CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB; + return ; + } + + if ((CdbPtr->OpFlags & PXE_OPFLAGS_FILL_HEADER_FRAGMENTED) != 0) { + Cpbf = (PXE_CPB_FILL_HEADER_FRAGMENTED *) (UINTN) CdbPtr->CPBaddr; + + // + // assume 1st fragment is big enough for the mac header + // + if ((Cpbf->FragCnt == 0) || (Cpbf->FragDesc[0].FragLen < PXE_MAC_HEADER_LEN_ETHER)) { + // + // no buffers given + // + CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; + CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB; + return ; + } + + MacHeader = (EtherHeader *) (UINTN) Cpbf->FragDesc[0].FragAddr; + // + // we don't swap the protocol bytes + // + MacHeader->type = Cpbf->Protocol; + + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) { + MacHeader->dest_addr[Index] = Cpbf->DestAddr[Index]; + MacHeader->src_addr[Index] = Cpbf->SrcAddr[Index]; + } + } else { + Cpb = (PXE_CPB_FILL_HEADER *) (UINTN) CdbPtr->CPBaddr; + + MacHeader = (EtherHeader *) (UINTN) Cpb->MediaHeader; + // + // we don't swap the protocol bytes + // + MacHeader->type = Cpb->Protocol; + + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) { + MacHeader->dest_addr[Index] = Cpb->DestAddr[Index]; + MacHeader->src_addr[Index] = Cpb->SrcAddr[Index]; + } + } + + return ; +} + +VOID +UNDI_Transmit ( + IN PXE_CDB *CdbPtr, + IN NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + This routine is used to place a packet into the transmit queue. The data buffers given to + this command are to be considered locked and the application or network driver loses + ownership of these buffers and must not free or relocate them until the ownership returns. + + When the packets are transmitted, a transmit complete interrupt is generated (if interrupts + are disabled, the transmit interrupt status is still set and can be checked using the UNDI_Status + command. + + Some implementations and adapters support transmitting multiple packets with one transmit + command. If this feature is supported, the transmit CPBs can be linked in one transmit + command. + + All UNDIs support fragmented frames, now all network devices or protocols do. If a fragmented + frame CPB is given to UNDI and the network device does not support fragmented frames + (see !PXE.Implementation flag), the UNDI will have to copy the fragments into a local buffer + before transmitting. + + +Arguments: + CdbPtr - Pointer to the command descriptor block. + AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on.. + +Returns: + None + +--*/ +{ + + if (CdbPtr->CPBsize == PXE_CPBSIZE_NOT_USED) { + CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; + CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB; + return ; + } + + CdbPtr->StatCode = (PXE_STATCODE) E100bTransmit (AdapterInfo, CdbPtr->CPBaddr, CdbPtr->OpFlags); + + if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) { + CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; + } + + return ; +} + +VOID +UNDI_Receive ( + IN PXE_CDB *CdbPtr, + IN NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + When the network adapter has received a frame, this command is used to copy the frame + into the driver/application storage location. Once a frame has been copied, it is + removed from the receive queue. + +Arguments: + CdbPtr - Pointer to the command descriptor block. + AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on.. + +Returns: + None + +--*/ +{ + PXE_CPB_RECEIVE *cpbptr; + + // + // check if RU has started... + // + if (!AdapterInfo->Receive_Started) { + CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; + CdbPtr->StatCode = PXE_STATCODE_NOT_INITIALIZED; + return ; + } + + cpbptr = (PXE_CPB_RECEIVE *) (UINTN) CdbPtr->CPBaddr; + + CdbPtr->StatCode = (UINT16) E100bReceive (AdapterInfo, CdbPtr->CPBaddr, CdbPtr->DBaddr); + if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) { + CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; + + } + + return ; +} + +VOID +UNDI_APIEntry_old ( + IN UINT64 cdb + ) +/*++ + +Routine Description: + This is the main SW UNDI API entry using the older nii protocol. + The parameter passed in is a 64 bit flat model virtual + address of the cdb. We then jump into the common routine for both old and + new nii protocol entries. + +Arguments: + CdbPtr - Pointer to the command descriptor block. + AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on.. + +Returns: + None + +--*/ +// TODO: cdb - add argument and description to function comment +{ + PXE_CDB *CdbPtr; + NIC_DATA_INSTANCE *AdapterInfo; + + if (cdb == (UINT64) 0) { + return ; + + } + + CdbPtr = (PXE_CDB *) (UINTN) cdb; + + if (CdbPtr->IFnum >= pxe->IFcnt) { + CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; + CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB; + return ; + } + + AdapterInfo = &(UNDI32DeviceList[CdbPtr->IFnum]->NicInfo); + + // + // entering from older entry point + // + AdapterInfo->VersionFlag = 0x30; + UNDI_APIEntry_Common (cdb); +} + +VOID +UNDI_APIEntry_new ( + IN UINT64 cdb + ) +/*++ + +Routine Description: + This is the main SW UNDI API entry using the newer nii protocol. + The parameter passed in is a 64 bit flat model virtual + address of the cdb. We then jump into the common routine for both old and + new nii protocol entries. + +Arguments: + CdbPtr - Pointer to the command descriptor block. + AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on.. + +Returns: + None + +--*/ +// TODO: cdb - add argument and description to function comment +{ + PXE_CDB *CdbPtr; + NIC_DATA_INSTANCE *AdapterInfo; + + if (cdb == (UINT64) 0) { + return ; + + } + + CdbPtr = (PXE_CDB *) (UINTN) cdb; + + if (CdbPtr->IFnum >= pxe_31->IFcnt) { + CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; + CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB; + return ; + } + + AdapterInfo = &(UNDI32DeviceList[CdbPtr->IFnum]->NicInfo); + // + // entering from older entry point + // + AdapterInfo->VersionFlag = 0x31; + UNDI_APIEntry_Common (cdb); +} + +VOID +UNDI_APIEntry_Common ( + IN UINT64 cdb + ) +/*++ + +Routine Description: + This is the common routine for both old and new entry point procedures. + The parameter passed in is a 64 bit flat model virtual + address of the cdb. We then jump into the service routine pointed to by the + Api_Table[OpCode]. + +Arguments: + CdbPtr - Pointer to the command descriptor block. + AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on.. + +Returns: + None + +--*/ +// TODO: cdb - add argument and description to function comment +{ + PXE_CDB *CdbPtr; + NIC_DATA_INSTANCE *AdapterInfo; + UNDI_CALL_TABLE *tab_ptr; + + CdbPtr = (PXE_CDB *) (UINTN) cdb; + + // + // check the OPCODE range + // + if ((CdbPtr->OpCode > PXE_OPCODE_LAST_VALID) || + (CdbPtr->StatCode != PXE_STATCODE_INITIALIZE) || + (CdbPtr->StatFlags != PXE_STATFLAGS_INITIALIZE) || + (CdbPtr->IFnum >= pxe_31->IFcnt) ) { + goto badcdb; + + } + + if (CdbPtr->CPBsize == PXE_CPBSIZE_NOT_USED) { + if (CdbPtr->CPBaddr != PXE_CPBADDR_NOT_USED) { + goto badcdb; + } + } else if (CdbPtr->CPBaddr == PXE_CPBADDR_NOT_USED) { + goto badcdb; + } + + if (CdbPtr->DBsize == PXE_DBSIZE_NOT_USED) { + if (CdbPtr->DBaddr != PXE_DBADDR_NOT_USED) { + goto badcdb; + } + } else if (CdbPtr->DBaddr == PXE_DBADDR_NOT_USED) { + goto badcdb; + } + + // + // check if cpbsize and dbsize are as needed + // check if opflags are as expected + // + tab_ptr = &api_table[CdbPtr->OpCode]; + + if (tab_ptr->cpbsize != (UINT16) (DONT_CHECK) && tab_ptr->cpbsize != CdbPtr->CPBsize) { + goto badcdb; + } + + if (tab_ptr->dbsize != (UINT16) (DONT_CHECK) && tab_ptr->dbsize != CdbPtr->DBsize) { + goto badcdb; + } + + if (tab_ptr->opflags != (UINT16) (DONT_CHECK) && tab_ptr->opflags != CdbPtr->OpFlags) { + goto badcdb; + + } + + AdapterInfo = &(UNDI32DeviceList[CdbPtr->IFnum]->NicInfo); + + // + // check if UNDI_State is valid for this call + // + if (tab_ptr->state != (UINT16) (-1)) { + // + // should atleast be started + // + if (AdapterInfo->State == PXE_STATFLAGS_GET_STATE_STOPPED) { + CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; + CdbPtr->StatCode = PXE_STATCODE_NOT_STARTED; + return ; + } + // + // check if it should be initialized + // + if (tab_ptr->state == 2) { + if (AdapterInfo->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) { + CdbPtr->StatCode = PXE_STATCODE_NOT_INITIALIZED; + CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; + return ; + } + } + } + // + // set the return variable for success case here + // + CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE; + CdbPtr->StatCode = PXE_STATCODE_SUCCESS; + + tab_ptr->api_ptr (CdbPtr, AdapterInfo); + return ; + // + // %% AVL - check for command linking + // +badcdb: + CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; + CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB; + return ; +} + +UINT8 +ChkSum ( + IN VOID *Buffer, + IN UINT16 Len + ) +/*++ + +Routine Description: + This does an 8 bit check sum of the passed in buffer for Len bytes. + This is primarily used to update the check sum in the SW UNDI header. + +Arguments: + Buffer - Pointer to the passed in buffer to check sum + Len - Length of buffer to be check summed in bytes. + +Returns: + None + +--*/ +{ + UINT8 Chksum; + INT8 *Bp; + + Chksum = 0; + if ((Bp = Buffer) != NULL) { + while (Len--) { + Chksum = (UINT8) (Chksum +*Bp++); + + } + + } + + return Chksum; +} + +VOID +PxeUpdate ( + IN NIC_DATA_INSTANCE *NicPtr, + IN PXE_SW_UNDI *PxePtr + ) +/*++ + +Routine Description: + When called with a null NicPtr, this routine decrements the number of NICs + this UNDI is supporting and removes the NIC_DATA_POINTER from the array. + Otherwise, it increments the number of NICs this UNDI is supported and + updates the pxe.Fudge to ensure a proper check sum results. + +Arguments: + NicPtr - Pointer to the NIC data structure. + +Returns: + None + +--*/ +// TODO: PxePtr - add argument and description to function comment +{ + if (NicPtr == NULL) { + if (PxePtr->IFcnt > 0) { + // + // number of NICs this undi supports + // + PxePtr->IFcnt--; + } + + PxePtr->Fudge = (UINT8) (PxePtr->Fudge - ChkSum ((VOID *) PxePtr, PxePtr->Len)); + return ; + } + + // + // number of NICs this undi supports + // + PxePtr->IFcnt++; + PxePtr->Fudge = (UINT8) (PxePtr->Fudge - ChkSum ((VOID *) PxePtr, PxePtr->Len)); + + return ; +} + +VOID +PxeStructInit ( + IN PXE_SW_UNDI *PxePtr, + IN UINTN VersionFlag + ) +/*++ + +Routine Description: + Initialize the !PXE structure + +Arguments: + RemainingDevicePath - Not used, always produce all possible children. + +Returns: + EFI_SUCCESS - This driver is added to Controller. + other - This driver does not support this device. + +--*/ +// TODO: PxePtr - add argument and description to function comment +// TODO: VersionFlag - add argument and description to function comment +{ + // + // Initialize the !PXE structure + // + PxePtr->Signature = PXE_ROMID_SIGNATURE; + PxePtr->Len = sizeof (PXE_SW_UNDI); + // + // cksum + // + PxePtr->Fudge = 0; + // + // number of NICs this undi supports + // + PxePtr->IFcnt = 0; + PxePtr->Rev = PXE_ROMID_REV; + PxePtr->MajorVer = PXE_ROMID_MAJORVER; + PxePtr->MinorVer = PXE_ROMID_MINORVER; + PxePtr->reserved1 = 0; + + PxePtr->Implementation = PXE_ROMID_IMP_SW_VIRT_ADDR | + PXE_ROMID_IMP_FRAG_SUPPORTED | + PXE_ROMID_IMP_CMD_LINK_SUPPORTED | + PXE_ROMID_IMP_NVDATA_READ_ONLY | + PXE_ROMID_IMP_STATION_ADDR_SETTABLE | + PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED | + PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED | + PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED | + PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED | + PXE_ROMID_IMP_SOFTWARE_INT_SUPPORTED | + PXE_ROMID_IMP_PACKET_RX_INT_SUPPORTED; + + if (VersionFlag == 0x30) { + PxePtr->EntryPoint = (UINT64) UNDI_APIEntry_old; + } else { + PxePtr->EntryPoint = (UINT64) UNDI_APIEntry_new; + PxePtr->MinorVer = PXE_ROMID_MINORVER_31; + } + + PxePtr->reserved2[0] = 0; + PxePtr->reserved2[1] = 0; + PxePtr->reserved2[2] = 0; + PxePtr->BusCnt = 1; + PxePtr->BusType[0] = PXE_BUSTYPE_PCI; + + PxePtr->Fudge = (UINT8) (PxePtr->Fudge - ChkSum ((VOID *) PxePtr, PxePtr->Len)); +} + +#pragma data_seg() diff --git a/EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/E100b.c b/EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/E100b.c new file mode 100644 index 0000000000..5b69a46ac4 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/E100b.c @@ -0,0 +1,3772 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + + E100B.C + +Abstract: + + +Revision History + +--*/ + +#include "undi32.h" + +static UINT8 basic_config_cmd[22] = { + 22, 0x08, + 0, 0, + 0, (UINT8)0x80, + 0x32, 0x03, + 1, 0, + 0x2E, 0, + 0x60, 0, + (UINT8)0xf2, 0x48, + 0, 0x40, + (UINT8)0xf2, (UINT8)0x80, // 0x40=Force full-duplex + 0x3f, 0x05, +}; + +// +// How to wait for the command unit to accept a command. +// Typically this takes 0 ticks. +// +#define wait_for_cmd_done(cmd_ioaddr) \ +{ \ + INT16 wait = 2000; \ + while ((InByte (AdapterInfo, cmd_ioaddr) != 0) && --wait >= 0) \ + DelayIt (AdapterInfo, 10); \ + if (wait == 0) \ + DelayIt (AdapterInfo, 50); \ +} + +UINT8 +InByte ( + IN NIC_DATA_INSTANCE *AdapterInfo, + IN UINT32 Port + ) +/*++ + +Routine Description: + This function calls the MemIo callback to read a byte from the device's + address space + Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine) + which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have + to make undi3.0 a special case + +Arguments: + Port - Which port to read from. + +Returns: + Results - The data read from the port. + +--*/ +// TODO: AdapterInfo - add argument and description to function comment +{ + UINT8 Results; + + (*AdapterInfo->Mem_Io) ( + AdapterInfo->Unique_ID, + PXE_MEM_READ, + 1, + (UINT64)Port, + (UINT64) (UINTN) &Results + ); + return Results; +} + +UINT16 +InWord ( + IN NIC_DATA_INSTANCE *AdapterInfo, + IN UINT32 Port + ) +/*++ + +Routine Description: + This function calls the MemIo callback to read a word from the device's + address space + Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine) + which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have + to make undi3.0 a special case + +Arguments: + Port - Which port to read from. + +Returns: + Results - The data read from the port. + +--*/ +// TODO: AdapterInfo - add argument and description to function comment +{ + UINT16 Results; + + (*AdapterInfo->Mem_Io) ( + AdapterInfo->Unique_ID, + PXE_MEM_READ, + 2, + (UINT64)Port, + (UINT64)(UINTN)&Results + ); + return Results; +} + +UINT32 +InLong ( + IN NIC_DATA_INSTANCE *AdapterInfo, + IN UINT32 Port + ) +/*++ + +Routine Description: + This function calls the MemIo callback to read a dword from the device's + address space + Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine) + which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have + to make undi3.0 a special case + +Arguments: + Port - Which port to read from. + +Returns: + Results - The data read from the port. + +--*/ +// TODO: AdapterInfo - add argument and description to function comment +{ + UINT32 Results; + + (*AdapterInfo->Mem_Io) ( + AdapterInfo->Unique_ID, + PXE_MEM_READ, + 4, + (UINT64)Port, + (UINT64)(UINTN)&Results + ); + return Results; +} + +VOID +OutByte ( + IN NIC_DATA_INSTANCE *AdapterInfo, + IN UINT8 Data, + IN UINT32 Port + ) +/*++ + +Routine Description: + This function calls the MemIo callback to write a byte from the device's + address space + Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine) + which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have + to make undi3.0 a special case + +Arguments: + Data - Data to write to Port. + Port - Which port to write to. + +Returns: + none + +--*/ +// TODO: AdapterInfo - add argument and description to function comment +{ + UINT8 Val; + + Val = Data; + (*AdapterInfo->Mem_Io) ( + AdapterInfo->Unique_ID, + PXE_MEM_WRITE, + 1, + (UINT64)Port, + (UINT64)(UINTN)(UINTN)&Val + ); + return ; +} + +VOID +OutWord ( + IN NIC_DATA_INSTANCE *AdapterInfo, + IN UINT16 Data, + IN UINT32 Port + ) +/*++ + +Routine Description: + This function calls the MemIo callback to write a word from the device's + address space + Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine) + which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have + to make undi3.0 a special case + +Arguments: + Data - Data to write to Port. + Port - Which port to write to. + +Returns: + none + +--*/ +// TODO: AdapterInfo - add argument and description to function comment +{ + UINT16 Val; + + Val = Data; + (*AdapterInfo->Mem_Io) ( + AdapterInfo->Unique_ID, + PXE_MEM_WRITE, + 2, + (UINT64)Port, + (UINT64)(UINTN)&Val + ); + return ; +} + +VOID +OutLong ( + IN NIC_DATA_INSTANCE *AdapterInfo, + IN UINT32 Data, + IN UINT32 Port + ) +/*++ + +Routine Description: + This function calls the MemIo callback to write a dword from the device's + address space + Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine) + which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have + to make undi3.0 a special case + +Arguments: + Data - Data to write to Port. + Port - Which port to write to. + +Returns: + none + +--*/ +// TODO: AdapterInfo - add argument and description to function comment +{ + UINT32 Val; + + Val = Data; + (*AdapterInfo->Mem_Io) ( + AdapterInfo->Unique_ID, + PXE_MEM_WRITE, + 4, + (UINT64)Port, + (UINT64)(UINTN)&Val + ); + return ; +} + +UINTN +MapIt ( + IN NIC_DATA_INSTANCE *AdapterInfo, + IN UINT64 MemAddr, + IN UINT32 Size, + IN UINT32 Direction, + OUT UINT64 MappedAddr + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AdapterInfo - TODO: add argument description + MemAddr - TODO: add argument description + Size - TODO: add argument description + Direction - TODO: add argument description + MappedAddr - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + UINT64 *PhyAddr; + + PhyAddr = (UINT64 *) (UINTN) MappedAddr; + // + // mapping is different for theold and new NII protocols + // + if (AdapterInfo->VersionFlag == 0x30) { + if (AdapterInfo->Virt2Phys_30 == (VOID *) NULL) { + *PhyAddr = (UINT64) AdapterInfo->MemoryPtr; + } else { + (*AdapterInfo->Virt2Phys_30) (MemAddr, (UINT64) (UINTN) PhyAddr); + } + + if (*PhyAddr > FOUR_GIGABYTE) { + return PXE_STATCODE_INVALID_PARAMETER; + } + } else { + if (AdapterInfo->Map_Mem == (VOID *) NULL) { + // + // this UNDI cannot handle addresses beyond 4 GB without a map routine + // + if (MemAddr > FOUR_GIGABYTE) { + return PXE_STATCODE_INVALID_PARAMETER; + } else { + *PhyAddr = MemAddr; + } + } else { + (*AdapterInfo->Map_Mem) ( + AdapterInfo->Unique_ID, + MemAddr, + Size, + Direction, + MappedAddr + ); + } + } + + return PXE_STATCODE_SUCCESS; +} + +VOID +UnMapIt ( + IN NIC_DATA_INSTANCE *AdapterInfo, + IN UINT64 MemAddr, + IN UINT32 Size, + IN UINT32 Direction, + IN UINT64 MappedAddr + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AdapterInfo - TODO: add argument description + MemAddr - TODO: add argument description + Size - TODO: add argument description + Direction - TODO: add argument description + MappedAddr - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + if (AdapterInfo->VersionFlag > 0x30) { + // + // no mapping service + // + if (AdapterInfo->UnMap_Mem != (VOID *) NULL) { + (*AdapterInfo->UnMap_Mem) ( + AdapterInfo->Unique_ID, + MemAddr, + Size, + Direction, + MappedAddr + ); + + } + } + + return ; +} + +VOID +DelayIt ( + IN NIC_DATA_INSTANCE *AdapterInfo, + UINT16 MicroSeconds + ) +/*++ + +Routine Description: + +Arguments: + AdapterInfo - Pointer to the NIC data structure information + which the UNDI driver is layering on.. + +Returns: + +--*/ +// TODO: MicroSeconds - add argument and description to function comment +{ + if (AdapterInfo->VersionFlag == 0x30) { + (*AdapterInfo->Delay_30) (MicroSeconds); + } else { + (*AdapterInfo->Delay) (AdapterInfo->Unique_ID, MicroSeconds); + } +} + +VOID +BlockIt ( + IN NIC_DATA_INSTANCE *AdapterInfo, + UINT32 flag + ) +/*++ + +Routine Description: + +Arguments: + AdapterInfo - Pointer to the NIC data structure information + which the UNDI driver is layering on.. + +Returns: + +--*/ +// TODO: flag - add argument and description to function comment +{ + if (AdapterInfo->VersionFlag == 0x30) { + (*AdapterInfo->Block_30) (flag); + } else { + (*AdapterInfo->Block) (AdapterInfo->Unique_ID, flag); + } +} + +UINT8 +Load_Base_Regs ( + NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AdapterInfo - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + // + // we will use the linear (flat) memory model and fill our base registers + // with 0's so that the entire physical address is our offset + // + // + // we reset the statistics totals here because this is where we are loading stats addr + // + AdapterInfo->RxTotals = 0; + AdapterInfo->TxTotals = 0; + + // + // Load the statistics block address. + // + wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd); + OutLong (AdapterInfo, (UINT32) AdapterInfo->stat_phy_addr, AdapterInfo->ioaddr + SCBPointer); + OutByte (AdapterInfo, CU_STATSADDR, AdapterInfo->ioaddr + SCBCmd); + AdapterInfo->statistics->done_marker = 0; + + wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd); + OutLong (AdapterInfo, 0, AdapterInfo->ioaddr + SCBPointer); + OutByte (AdapterInfo, RX_ADDR_LOAD, AdapterInfo->ioaddr + SCBCmd); + + wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd); + OutLong (AdapterInfo, 0, AdapterInfo->ioaddr + SCBPointer); + OutByte (AdapterInfo, CU_CMD_BASE, AdapterInfo->ioaddr + SCBCmd); + + return 0; +} + +UINT8 +IssueCB ( + NIC_DATA_INSTANCE *AdapterInfo, + TxCB *cmd_ptr + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AdapterInfo - TODO: add argument description + cmd_ptr - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + UINT16 status; + + wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd); + + // + // read the CU status, if it is idle, write the address of cb_ptr + // in the scbpointer and issue a cu_start, + // if it is suspended, remove the suspend bit in the previous command + // block and issue a resume + // + // Ensure that the CU Active Status bit is not on from previous CBs. + // + status = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBStatus); + + // + // Skip acknowledging the interrupt if it is not already set + // + + // + // ack only the cna the integer + // + if ((status & SCB_STATUS_CNA) != 0) { + OutWord (AdapterInfo, SCB_STATUS_CNA, AdapterInfo->ioaddr + SCBStatus); + + } + + if ((status & SCB_STATUS_CU_MASK) == SCB_STATUS_CU_IDLE) { + // + // give a cu_start + // + OutLong (AdapterInfo, cmd_ptr->PhysTCBAddress, AdapterInfo->ioaddr + SCBPointer); + OutByte (AdapterInfo, CU_START, AdapterInfo->ioaddr + SCBCmd); + } else { + // + // either active or suspended, give a resume + // + + cmd_ptr->PrevTCBVirtualLinkPtr->cb_header.command &= ~(CmdSuspend | CmdIntr); + OutByte (AdapterInfo, CU_RESUME, AdapterInfo->ioaddr + SCBCmd); + } + + return 0; +} + +UINT8 +Configure ( + NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AdapterInfo - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + // + // all command blocks are of TxCB format + // + TxCB *cmd_ptr; + UINT8 *data_ptr; + INT16 Index; + UINT8 my_filter; + + cmd_ptr = GetFreeCB (AdapterInfo); + data_ptr = (UINT8 *) (&cmd_ptr->PhysTBDArrayAddres); + + // + // start the config data right after the command header + // + for (Index = 0; Index < sizeof (basic_config_cmd); Index++) { + data_ptr[Index] = basic_config_cmd[Index]; + } + + my_filter = (UINT8) ((AdapterInfo->Rx_Filter & PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS) ? 1 : 0); + my_filter |= (AdapterInfo->Rx_Filter & PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST) ? 0 : 2; + + data_ptr[15] |= my_filter; + data_ptr[19] = (UINT8) (AdapterInfo->Duplex ? 0xC0 : 0x80); + data_ptr[21] = (UINT8) ((AdapterInfo->Rx_Filter & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) ? 0x0D : 0x05); + + // + // check if we have to use the AUI port instead + // + if ((AdapterInfo->PhyRecord[0] & 0x8000) != 0) { + data_ptr[15] |= 0x80; + data_ptr[8] = 0; + } + + BlockIt (AdapterInfo, TRUE); + cmd_ptr->cb_header.command = CmdSuspend | CmdConfigure; + + IssueCB (AdapterInfo, cmd_ptr); + wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd); + + BlockIt (AdapterInfo, FALSE); + + CommandWaitForCompletion (cmd_ptr, AdapterInfo); + + // + // restore the cb values for tx + // + cmd_ptr->PhysTBDArrayAddres = cmd_ptr->PhysArrayAddr; + cmd_ptr->ByteCount = cmd_ptr->Threshold = cmd_ptr->TBDCount = 0; + // + // fields beyond the immediatedata are assumed to be safe + // add the CB to the free list again + // + SetFreeCB (AdapterInfo, cmd_ptr); + return 0; +} + +UINT8 +E100bSetupIAAddr ( + NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AdapterInfo - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + // + // all command blocks are of TxCB format + // + TxCB *cmd_ptr; + UINT16 *data_ptr; + UINT16 *eaddrs; + + eaddrs = (UINT16 *) AdapterInfo->CurrentNodeAddress; + + cmd_ptr = GetFreeCB (AdapterInfo); + data_ptr = (UINT16 *) (&cmd_ptr->PhysTBDArrayAddres); + + // + // AVOID a bug (?!) here by marking the command already completed. + // + cmd_ptr->cb_header.command = (CmdSuspend | CmdIASetup); + cmd_ptr->cb_header.status = 0; + data_ptr[0] = eaddrs[0]; + data_ptr[1] = eaddrs[1]; + data_ptr[2] = eaddrs[2]; + + BlockIt (AdapterInfo, TRUE); + IssueCB (AdapterInfo, cmd_ptr); + wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd); + BlockIt (AdapterInfo, FALSE); + + CommandWaitForCompletion (cmd_ptr, AdapterInfo); + + // + // restore the cb values for tx + // + cmd_ptr->PhysTBDArrayAddres = cmd_ptr->PhysArrayAddr; + cmd_ptr->ByteCount = cmd_ptr->Threshold = cmd_ptr->TBDCount = 0; + // + // fields beyond the immediatedata are assumed to be safe + // add the CB to the free list again + // + SetFreeCB (AdapterInfo, cmd_ptr); + return 0; +} + +VOID +StopRU ( + IN NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + Instructs the NIC to stop receiving packets. + +Arguments: + AdapterInfo - Pointer to the NIC data structure information + which the UNDI driver is layering on.. +Returns: + +--*/ +{ + if (AdapterInfo->Receive_Started) { + + // + // Todo: verify that we must wait for previous command completion. + // + wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd); + + // + // Disable interrupts, and stop the chip's Rx process. + // + OutWord (AdapterInfo, INT_MASK, AdapterInfo->ioaddr + SCBCmd); + OutWord (AdapterInfo, INT_MASK | RX_ABORT, AdapterInfo->ioaddr + SCBCmd); + + AdapterInfo->Receive_Started = FALSE; + } + + return ; +} + +INT8 +StartRU ( + NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + Instructs the NIC to start receiving packets. + +Arguments: + AdapterInfo - Pointer to the NIC data structure information + which the UNDI driver is layering on.. +Returns: + 0 - Successful + -1 - Already Started +--*/ +{ + + if (AdapterInfo->Receive_Started) { + // + // already started + // + return -1; + } + + AdapterInfo->cur_rx_ind = 0; + AdapterInfo->Int_Status = 0; + + wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd); + + OutLong (AdapterInfo, (UINT32) AdapterInfo->rx_phy_addr, AdapterInfo->ioaddr + SCBPointer); + OutByte (AdapterInfo, RX_START, AdapterInfo->ioaddr + SCBCmd); + + wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd); + + AdapterInfo->Receive_Started = TRUE; + return 0; +} + +UINTN +E100bInit ( + IN NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + Configures the chip. This routine expects the NIC_DATA_INSTANCE structure to be filled in. + +Arguments: + AdapterInfo - Pointer to the NIC data structure information + which the UNDI driver is layering on.. + +Returns: + 0 - Successful + PXE_STATCODE_NOT_ENOUGH_MEMORY - Insufficient length of locked memory + other - Failure initializing chip +--*/ +{ + PCI_CONFIG_HEADER *CfgHdr; + UINTN stat; + UINTN rx_size; + UINTN tx_size; + + if (AdapterInfo->MemoryLength < MEMORY_NEEDED) { + return PXE_STATCODE_NOT_ENOUGH_MEMORY; + } + + stat = MapIt ( + AdapterInfo, + AdapterInfo->MemoryPtr, + AdapterInfo->MemoryLength, + TO_AND_FROM_DEVICE, + (UINT64)(UINTN) &AdapterInfo->Mapped_MemoryPtr + ); + + if (stat != 0) { + return stat; + } + + CfgHdr = (PCI_CONFIG_HEADER *) &(AdapterInfo->Config[0]); + + // + // fill in the ioaddr, int... from the config space + // + AdapterInfo->int_num = CfgHdr->int_line; + + // + // we don't need to validate integer number, what if they don't want to assign one? + // if (AdapterInfo->int_num == 0 || AdapterInfo->int_num == 0xff) + // return PXE_STATCODE_DEVICE_FAILURE; + // + AdapterInfo->ioaddr = 0; + AdapterInfo->VendorID = CfgHdr->VendorID; + AdapterInfo->DeviceID = CfgHdr->DeviceID; + AdapterInfo->RevID = CfgHdr->RevID; + AdapterInfo->SubVendorID = CfgHdr->SubVendorID; + AdapterInfo->SubSystemID = CfgHdr->SubSystemID; + AdapterInfo->flash_addr = 0; + + // + // Read the station address EEPROM before doing the reset. + // Perhaps this should even be done before accepting the device, + // then we wouldn't have a device name with which to report the error. + // + if (E100bReadEepromAndStationAddress (AdapterInfo) != 0) { + return PXE_STATCODE_DEVICE_FAILURE; + + } + // + // ## calculate the buffer #s depending on memory given + // ## calculate the rx and tx ring pointers + // + + AdapterInfo->TxBufCnt = TX_BUFFER_COUNT; + AdapterInfo->RxBufCnt = RX_BUFFER_COUNT; + rx_size = (AdapterInfo->RxBufCnt * sizeof (RxFD)); + tx_size = (AdapterInfo->TxBufCnt * sizeof (TxCB)); + AdapterInfo->rx_ring = (RxFD *) (UINTN) (AdapterInfo->MemoryPtr); + AdapterInfo->tx_ring = (TxCB *) (UINTN) (AdapterInfo->MemoryPtr + rx_size); + AdapterInfo->statistics = (struct speedo_stats *) (UINTN) (AdapterInfo->MemoryPtr + rx_size + tx_size); + + AdapterInfo->rx_phy_addr = AdapterInfo->Mapped_MemoryPtr; + AdapterInfo->tx_phy_addr = AdapterInfo->Mapped_MemoryPtr + rx_size; + AdapterInfo->stat_phy_addr = AdapterInfo->tx_phy_addr + tx_size; + + // + // auto detect. + // + AdapterInfo->PhyAddress = 0xFF; + AdapterInfo->Rx_Filter = PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST; + AdapterInfo->Receive_Started = FALSE; + AdapterInfo->mcast_list.list_len = 0; + return InitializeChip (AdapterInfo); +} + +UINT8 +E100bSetInterruptState ( + IN NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + Sets the interrupt state for the NIC. + +Arguments: + AdapterInfo - Pointer to the NIC data structure information + which the UNDI driver is layering on.. +Returns: + 0 - Successful +--*/ +{ + // + // don't set receive interrupt if receiver is disabled... + // + UINT16 cmd_word; + + if ((AdapterInfo->int_mask & PXE_OPFLAGS_INTERRUPT_RECEIVE) != 0) { + cmd_word = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBCmd); + cmd_word &= ~INT_MASK; + OutWord (AdapterInfo, cmd_word, AdapterInfo->ioaddr + SCBCmd); + } else { + // + // disable ints, should not be given for SW Int. + // + OutWord (AdapterInfo, INT_MASK, AdapterInfo->ioaddr + SCBCmd); + } + + if ((AdapterInfo->int_mask & PXE_OPFLAGS_INTERRUPT_SOFTWARE) != 0) { + // + // reset the bit in our mask, it is only one time!! + // + AdapterInfo->int_mask &= ~(PXE_OPFLAGS_INTERRUPT_SOFTWARE); + cmd_word = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBCmd); + cmd_word |= DRVR_INT; + OutWord (AdapterInfo, cmd_word, AdapterInfo->ioaddr + SCBCmd); + } + + return 0; +} +// +// we are not going to disable broadcast for the WOL's sake! +// +UINTN +E100bSetfilter ( + NIC_DATA_INSTANCE *AdapterInfo, + UINT16 new_filter, + UINT64 cpb, + UINT32 cpbsize + ) +/*++ + +Routine Description: + Instructs the NIC to start receiving packets. + +Arguments: + AdapterInfo - Pointer to the NIC data structure information + which the UNDI driver is layering on.. + new_filter - + cpb - + cpbsize - + +Returns: + 0 - Successful + -1 - Already Started +--*/ +{ + PXE_CPB_RECEIVE_FILTERS *mc_list = (PXE_CPB_RECEIVE_FILTERS *) (UINTN)cpb; + UINT16 cfg_flt; + UINT16 old_filter; + UINT16 Index; + UINT16 Index2; + UINT16 mc_count; + TxCB *cmd_ptr; + struct MC_CB_STRUCT *data_ptr; + UINT16 mc_byte_cnt; + + old_filter = AdapterInfo->Rx_Filter; + + // + // only these bits need a change in the configuration + // actually change in bcast requires configure but we ignore that change + // + cfg_flt = PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS | + PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST; + + if ((old_filter & cfg_flt) != (new_filter & cfg_flt)) { + XmitWaitForCompletion (AdapterInfo); + + if (AdapterInfo->Receive_Started) { + StopRU (AdapterInfo); + } + + AdapterInfo->Rx_Filter = (UINT8) (new_filter | PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST); + Configure (AdapterInfo); + } + + // + // check if mcast setting changed + // + if ( ((new_filter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != + (old_filter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) ) || + (mc_list != NULL) ) { + + + if (mc_list != NULL) { + mc_count = AdapterInfo->mcast_list.list_len = (UINT16) (cpbsize / PXE_MAC_LENGTH); + + for (Index = 0; (Index < mc_count && Index < MAX_MCAST_ADDRESS_CNT); Index++) { + for (Index2 = 0; Index2 < PXE_MAC_LENGTH; Index2++) { + AdapterInfo->mcast_list.mc_list[Index][Index2] = mc_list->MCastList[Index][Index2]; + } + } + } + + // + // are we setting the list or resetting?? + // + if ((new_filter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) { + // + // we are setting a new list! + // + mc_count = AdapterInfo->mcast_list.list_len; + // + // count should be the actual # of bytes in the list + // so multiply this with 6 + // + mc_byte_cnt = (UINT16) ((mc_count << 2) + (mc_count << 1)); + AdapterInfo->Rx_Filter |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST; + } else { + // + // disabling the list in the NIC. + // + mc_byte_cnt = mc_count = 0; + AdapterInfo->Rx_Filter &= (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST); + } + + // + // before issuing any new command! + // + XmitWaitForCompletion (AdapterInfo); + + if (AdapterInfo->Receive_Started) { + StopRU (AdapterInfo); + + } + + cmd_ptr = GetFreeCB (AdapterInfo); + if (cmd_ptr == NULL) { + return PXE_STATCODE_QUEUE_FULL; + } + // + // fill the command structure and issue + // + data_ptr = (struct MC_CB_STRUCT *) (&cmd_ptr->PhysTBDArrayAddres); + // + // first 2 bytes are the count; + // + data_ptr->count = mc_byte_cnt; + for (Index = 0; Index < mc_count; Index++) { + for (Index2 = 0; Index2 < PXE_HWADDR_LEN_ETHER; Index2++) { + data_ptr->m_list[Index][Index2] = AdapterInfo->mcast_list.mc_list[Index][Index2]; + } + } + + cmd_ptr->cb_header.command = CmdSuspend | CmdMulticastList; + cmd_ptr->cb_header.status = 0; + + BlockIt (AdapterInfo, TRUE); + IssueCB (AdapterInfo, cmd_ptr); + wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd); + + BlockIt (AdapterInfo, FALSE); + + CommandWaitForCompletion (cmd_ptr, AdapterInfo); + + cmd_ptr->PhysTBDArrayAddres = cmd_ptr->PhysArrayAddr; + cmd_ptr->ByteCount = cmd_ptr->Threshold = cmd_ptr->TBDCount = 0; + // + // fields beyond the immediatedata are assumed to be safe + // add the CB to the free list again + // + SetFreeCB (AdapterInfo, cmd_ptr); + } + + if (new_filter != 0) { + // + // enable unicast and start the RU + // + AdapterInfo->Rx_Filter |= (new_filter | PXE_OPFLAGS_RECEIVE_FILTER_UNICAST); + StartRU (AdapterInfo); + } else { + // + // may be disabling everything! + // + if (AdapterInfo->Receive_Started) { + StopRU (AdapterInfo); + } + + AdapterInfo->Rx_Filter |= (~PXE_OPFLAGS_RECEIVE_FILTER_UNICAST); + } + + return 0; +} + +UINTN +E100bTransmit ( + NIC_DATA_INSTANCE *AdapterInfo, + UINT64 cpb, + UINT16 opflags + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AdapterInfo - TODO: add argument description + cpb - TODO: add argument description + opflags - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + PXE_CPB_TRANSMIT_FRAGMENTS *tx_ptr_f; + PXE_CPB_TRANSMIT *tx_ptr_1; + TxCB *tcb_ptr; + UINT64 Tmp_ptr; + UINTN stat; + INT32 Index; + UINT16 wait_sec; + + tx_ptr_1 = (PXE_CPB_TRANSMIT *) (UINTN) cpb; + tx_ptr_f = (PXE_CPB_TRANSMIT_FRAGMENTS *) (UINTN) cpb; + + // + // stop reentrancy here + // + if (AdapterInfo->in_transmit) { + return PXE_STATCODE_BUSY; + + } + + AdapterInfo->in_transmit = TRUE; + + // + // Prevent interrupts from changing the Tx ring from underneath us. + // + // Calculate the Tx descriptor entry. + // + if ((tcb_ptr = GetFreeCB (AdapterInfo)) == NULL) { + AdapterInfo->in_transmit = FALSE; + return PXE_STATCODE_QUEUE_FULL; + } + + AdapterInfo->TxTotals++; + + tcb_ptr->cb_header.command = (CmdSuspend | CmdTx | CmdTxFlex); + tcb_ptr->cb_header.status = 0; + + // + // no immediate data, set EOF in the ByteCount + // + tcb_ptr->ByteCount = 0x8000; + + // + // The data region is always in one buffer descriptor, Tx FIFO + // threshold of 256. + // 82557 multiplies the threashold value by 8, so give 256/8 + // + tcb_ptr->Threshold = 32; + if ((opflags & PXE_OPFLAGS_TRANSMIT_FRAGMENTED) != 0) { + + if (tx_ptr_f->FragCnt > MAX_XMIT_FRAGMENTS) { + SetFreeCB (AdapterInfo, tcb_ptr); + AdapterInfo->in_transmit = FALSE; + return PXE_STATCODE_INVALID_PARAMETER; + } + + tcb_ptr->TBDCount = (UINT8) tx_ptr_f->FragCnt; + + for (Index = 0; Index < tx_ptr_f->FragCnt; Index++) { + stat = MapIt ( + AdapterInfo, + tx_ptr_f->FragDesc[Index].FragAddr, + tx_ptr_f->FragDesc[Index].FragLen, + TO_DEVICE, + (UINT64)(UINTN) &Tmp_ptr + ); + if (stat != 0) { + SetFreeCB (AdapterInfo, tcb_ptr); + AdapterInfo->in_transmit = FALSE; + return PXE_STATCODE_INVALID_PARAMETER; + } + + tcb_ptr->TBDArray[Index].phys_buf_addr = (UINT32) Tmp_ptr; + tcb_ptr->TBDArray[Index].buf_len = tx_ptr_f->FragDesc[Index].FragLen; + } + + tcb_ptr->free_data_ptr = tx_ptr_f->FragDesc[0].FragAddr; + + } else { + // + // non fragmented case + // + tcb_ptr->TBDCount = 1; + stat = MapIt ( + AdapterInfo, + tx_ptr_1->FrameAddr, + tx_ptr_1->DataLen + tx_ptr_1->MediaheaderLen, + TO_DEVICE, + (UINT64)(UINTN) &Tmp_ptr + ); + if (stat != 0) { + SetFreeCB (AdapterInfo, tcb_ptr); + AdapterInfo->in_transmit = FALSE; + return PXE_STATCODE_INVALID_PARAMETER; + } + + tcb_ptr->TBDArray[0].phys_buf_addr = (UINT32) (Tmp_ptr); + tcb_ptr->TBDArray[0].buf_len = tx_ptr_1->DataLen + tx_ptr_1->MediaheaderLen; + tcb_ptr->free_data_ptr = tx_ptr_1->FrameAddr; + } + + // + // must wait for previous command completion only if it was a non-transmit + // + BlockIt (AdapterInfo, TRUE); + IssueCB (AdapterInfo, tcb_ptr); + BlockIt (AdapterInfo, FALSE); + + // + // see if we need to wait for completion here + // + if ((opflags & PXE_OPFLAGS_TRANSMIT_BLOCK) != 0) { + // + // don't wait for more than 1 second!!! + // + wait_sec = 1000; + while (tcb_ptr->cb_header.status == 0) { + DelayIt (AdapterInfo, 10); + wait_sec--; + if (wait_sec == 0) { + break; + } + } + // + // we need to un-map any mapped buffers here + // + if ((opflags & PXE_OPFLAGS_TRANSMIT_FRAGMENTED) != 0) { + + for (Index = 0; Index < tx_ptr_f->FragCnt; Index++) { + Tmp_ptr = tcb_ptr->TBDArray[Index].phys_buf_addr; + UnMapIt ( + AdapterInfo, + tx_ptr_f->FragDesc[Index].FragAddr, + tx_ptr_f->FragDesc[Index].FragLen, + TO_DEVICE, + (UINT64) Tmp_ptr + ); + } + } else { + Tmp_ptr = tcb_ptr->TBDArray[0].phys_buf_addr; + UnMapIt ( + AdapterInfo, + tx_ptr_1->FrameAddr, + tx_ptr_1->DataLen + tx_ptr_1->MediaheaderLen, + TO_DEVICE, + (UINT64) Tmp_ptr + ); + } + + if (tcb_ptr->cb_header.status == 0) { + SetFreeCB (AdapterInfo, tcb_ptr); + AdapterInfo->in_transmit = FALSE; + return PXE_STATCODE_DEVICE_FAILURE; + } + + SetFreeCB (AdapterInfo, tcb_ptr); + } + // + // CB will be set free later in get_status (or when we run out of xmit buffers + // + AdapterInfo->in_transmit = FALSE; + + return 0; +} + +UINTN +E100bReceive ( + NIC_DATA_INSTANCE *AdapterInfo, + UINT64 cpb, + UINT64 db + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AdapterInfo - TODO: add argument description + cpb - TODO: add argument description + db - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + PXE_CPB_RECEIVE *rx_cpbptr; + PXE_DB_RECEIVE *rx_dbptr; + RxFD *rx_ptr; + INT32 status; + INT32 Index; + UINT16 pkt_len; + UINT16 ret_code; + PXE_FRAME_TYPE pkt_type; + UINT16 Tmp_len; + EtherHeader *hdr_ptr; + ret_code = PXE_STATCODE_NO_DATA; + pkt_type = PXE_FRAME_TYPE_NONE; + status = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBStatus); + AdapterInfo->Int_Status |= status; + // + // acknoledge the interrupts + // + OutWord (AdapterInfo, (UINT16) (status & 0xfc00), (UINT32) (AdapterInfo->ioaddr + SCBStatus)); + + // + // include the prev ints as well + // + status = AdapterInfo->Int_Status; + rx_cpbptr = (PXE_CPB_RECEIVE *) (UINTN) cpb; + rx_dbptr = (PXE_DB_RECEIVE *) (UINTN) db; + + rx_ptr = &AdapterInfo->rx_ring[AdapterInfo->cur_rx_ind]; + + // + // be in a loop just in case (we may drop a pkt) + // + while ((status = rx_ptr->cb_header.status) & RX_COMPLETE) { + + AdapterInfo->RxTotals++; + // + // If we own the next entry, it's a new packet. Send it up. + // + if (rx_ptr->forwarded) { + goto FreeRFD; + + } + + // + // discard bad frames + // + + // + // crc, align, dma overrun, too short, receive error (v22 no coll) + // + if ((status & 0x0D90) != 0) { + goto FreeRFD; + + } + + // + // make sure the status is OK + // + if ((status & 0x02000) == 0) { + goto FreeRFD; + } + + pkt_len = (UINT16) (rx_ptr->ActualCount & 0x3fff); + + if (pkt_len != 0) { + + Tmp_len = pkt_len; + if (pkt_len > rx_cpbptr->BufferLen) { + Tmp_len = (UINT16) rx_cpbptr->BufferLen; + } + + CopyMem ((INT8 *) (UINTN) rx_cpbptr->BufferAddr, (INT8 *) &rx_ptr->RFDBuffer, Tmp_len); + + hdr_ptr = (EtherHeader *) &rx_ptr->RFDBuffer; + // + // fill the CDB and break the loop + // + + // + // includes header + // + rx_dbptr->FrameLen = pkt_len; + rx_dbptr->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER; + + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) { + if (hdr_ptr->dest_addr[Index] != AdapterInfo->CurrentNodeAddress[Index]) { + break; + } + } + + if (Index >= PXE_HWADDR_LEN_ETHER) { + pkt_type = PXE_FRAME_TYPE_UNICAST; + } else { + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) { + if (hdr_ptr->dest_addr[Index] != AdapterInfo->BroadcastNodeAddress[Index]) { + break; + } + } + + if (Index >= PXE_HWADDR_LEN_ETHER) { + pkt_type = PXE_FRAME_TYPE_BROADCAST; + } else { + if ((hdr_ptr->dest_addr[0] & 1) == 1) { + // + // mcast + // + + pkt_type = PXE_FRAME_TYPE_MULTICAST; + } else { + pkt_type = PXE_FRAME_TYPE_PROMISCUOUS; + } + } + } + + rx_dbptr->Type = pkt_type; + rx_dbptr->Protocol = hdr_ptr->type; + + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) { + rx_dbptr->SrcAddr[Index] = hdr_ptr->src_addr[Index]; + rx_dbptr->DestAddr[Index] = hdr_ptr->dest_addr[Index]; + } + + rx_ptr->forwarded = TRUE; + // + // success + // + ret_code = 0; + Recycle_RFD (AdapterInfo, AdapterInfo->cur_rx_ind); + AdapterInfo->cur_rx_ind++; + if (AdapterInfo->cur_rx_ind == AdapterInfo->RxBufCnt) { + AdapterInfo->cur_rx_ind = 0; + } + break; + } + +FreeRFD: + Recycle_RFD (AdapterInfo, AdapterInfo->cur_rx_ind); + AdapterInfo->cur_rx_ind++; + if (AdapterInfo->cur_rx_ind == AdapterInfo->RxBufCnt) { + AdapterInfo->cur_rx_ind = 0; + } + + rx_ptr = &AdapterInfo->rx_ring[AdapterInfo->cur_rx_ind]; + } + + if (pkt_type == PXE_FRAME_TYPE_NONE) { + AdapterInfo->Int_Status &= (~SCB_STATUS_FR); + } + + status = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBStatus); + if ((status & SCB_RUS_NO_RESOURCES) != 0) { + // + // start the receive unit here! + // leave all the filled frames, + // + SetupReceiveQueues (AdapterInfo); + OutLong (AdapterInfo, (UINT32) AdapterInfo->rx_phy_addr, AdapterInfo->ioaddr + SCBPointer); + OutWord (AdapterInfo, RX_START, AdapterInfo->ioaddr + SCBCmd); + AdapterInfo->cur_rx_ind = 0; + } + + return ret_code; +} + +INT16 +E100bReadEepromAndStationAddress ( + NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AdapterInfo - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + INT32 Index; + INT32 Index2; + UINT16 sum; + UINT16 eeprom_len; + UINT8 addr_len; + UINT16 *eedata; + + eedata = (UINT16 *) (&AdapterInfo->NVData[0]); + + sum = 0; + addr_len = E100bGetEepromAddrLen (AdapterInfo); + + // + // in words + // + AdapterInfo->NVData_Len = eeprom_len = (UINT16) (1 << addr_len); + for (Index2 = 0, Index = 0; Index < eeprom_len; Index++) { + UINT16 value; + value = E100bReadEeprom (AdapterInfo, Index, addr_len); + eedata[Index] = value; + sum = (UINT16) (sum + value); + if (Index < 3) { + AdapterInfo->PermNodeAddress[Index2++] = (UINT8) value; + AdapterInfo->PermNodeAddress[Index2++] = (UINT8) (value >> 8); + } + } + + if (sum != 0xBABA) { + return -1; + } + + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) { + AdapterInfo->CurrentNodeAddress[Index] = AdapterInfo->PermNodeAddress[Index]; + } + + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) { + AdapterInfo->BroadcastNodeAddress[Index] = 0xff; + } + + for (Index = PXE_HWADDR_LEN_ETHER; Index < PXE_MAC_LENGTH; Index++) { + AdapterInfo->CurrentNodeAddress[Index] = 0; + AdapterInfo->PermNodeAddress[Index] = 0; + AdapterInfo->BroadcastNodeAddress[Index] = 0; + } + + return 0; +} + +// +// CBList is a circular linked list +// 1) When all are free, Tail->next == Head and FreeCount == # allocated +// 2) When none are free, Tail == Head and FreeCount == 0 +// 3) when one is free, Tail == Head and Freecount == 1 +// 4) First non-Free frame is always at Tail->next +// +UINT8 +SetupCBlink ( + NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AdapterInfo - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + TxCB *head_ptr; + TxCB *tail_ptr; + TxCB *cur_ptr; + INT32 Index; + UINTN array_off; + + cur_ptr = &(AdapterInfo->tx_ring[0]); + array_off = (UINTN) (&cur_ptr->TBDArray) - (UINTN) cur_ptr; + for (Index = 0; Index < AdapterInfo->TxBufCnt; Index++) { + cur_ptr[Index].cb_header.status = 0; + cur_ptr[Index].cb_header.command = 0; + + cur_ptr[Index].PhysTCBAddress = + (UINT32) AdapterInfo->tx_phy_addr + (Index * sizeof (TxCB)); + + cur_ptr[Index].PhysArrayAddr = (UINT32)(cur_ptr[Index].PhysTCBAddress + array_off); + cur_ptr[Index].PhysTBDArrayAddres = (UINT32)(cur_ptr[Index].PhysTCBAddress + array_off); + + cur_ptr->free_data_ptr = (UINT64) 0; + + if (Index < AdapterInfo->TxBufCnt - 1) { + cur_ptr[Index].cb_header.link = cur_ptr[Index].PhysTCBAddress + sizeof (TxCB); + cur_ptr[Index].NextTCBVirtualLinkPtr = &cur_ptr[Index + 1]; + cur_ptr[Index + 1].PrevTCBVirtualLinkPtr = &cur_ptr[Index]; + } + } + + head_ptr = &cur_ptr[0]; + tail_ptr = &cur_ptr[AdapterInfo->TxBufCnt - 1]; + tail_ptr->cb_header.link = head_ptr->PhysTCBAddress; + tail_ptr->NextTCBVirtualLinkPtr = head_ptr; + head_ptr->PrevTCBVirtualLinkPtr = tail_ptr; + + AdapterInfo->FreeCBCount = AdapterInfo->TxBufCnt; + AdapterInfo->FreeTxHeadPtr = head_ptr; + // + // set tail of the free list, next to this would be either in use + // or the head itself + // + AdapterInfo->FreeTxTailPtr = tail_ptr; + + AdapterInfo->xmit_done_head = AdapterInfo->xmit_done_tail = 0; + + return 0; +} + +TxCB * +GetFreeCB ( + NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AdapterInfo - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + TxCB *free_cb_ptr; + + // + // claim any hanging free CBs + // + if (AdapterInfo->FreeCBCount <= 1) { + CheckCBList (AdapterInfo); + } + + // + // don't use up the last CB problem if the previous CB that the CU used + // becomes the last CB we submit because of the SUSPEND bit we set. + // the CU thinks it was never cleared. + // + + if (AdapterInfo->FreeCBCount <= 1) { + return NULL; + } + + BlockIt (AdapterInfo, TRUE); + free_cb_ptr = AdapterInfo->FreeTxHeadPtr; + AdapterInfo->FreeTxHeadPtr = free_cb_ptr->NextTCBVirtualLinkPtr; + --AdapterInfo->FreeCBCount; + BlockIt (AdapterInfo, FALSE); + return free_cb_ptr; +} + +VOID +SetFreeCB ( + IN NIC_DATA_INSTANCE *AdapterInfo, + IN TxCB *cb_ptr + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AdapterInfo - TODO: add argument description + cb_ptr - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + // + // here we assume cb are returned in the order they are taken out + // and we link the newly freed cb at the tail of free cb list + // + cb_ptr->cb_header.status = 0; + cb_ptr->free_data_ptr = (UINT64) 0; + + AdapterInfo->FreeTxTailPtr = cb_ptr; + ++AdapterInfo->FreeCBCount; + return ; +} + +UINT16 +next ( + IN UINT16 ind + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ind - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + UINT16 Tmp; + + Tmp = (UINT16) (ind + 1); + if (Tmp >= (TX_BUFFER_COUNT << 1)) { + Tmp = 0; + } + + return Tmp; +} + +UINT16 +CheckCBList ( + IN NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AdapterInfo - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + TxCB *Tmp_ptr; + UINT16 cnt; + + cnt = 0; + while (1) { + Tmp_ptr = AdapterInfo->FreeTxTailPtr->NextTCBVirtualLinkPtr; + if ((Tmp_ptr->cb_header.status & CMD_STATUS_MASK) != 0) { + // + // check if Q is full + // + if (next (AdapterInfo->xmit_done_tail) != AdapterInfo->xmit_done_head) { + AdapterInfo->xmit_done[AdapterInfo->xmit_done_tail] = Tmp_ptr->free_data_ptr; + + UnMapIt ( + AdapterInfo, + Tmp_ptr->free_data_ptr, + Tmp_ptr->TBDArray[0].buf_len, + TO_DEVICE, + (UINT64) Tmp_ptr->TBDArray[0].phys_buf_addr + ); + + AdapterInfo->xmit_done_tail = next (AdapterInfo->xmit_done_tail); + } + + SetFreeCB (AdapterInfo, Tmp_ptr); + } else { + break; + } + } + + return cnt; +} +// +// Description : Initialize the RFD list list by linking each element together +// in a circular list. The simplified memory model is used. +// All data is in the RFD. The RFDs are linked together and the +// last one points back to the first one. When the current RFD +// is processed (frame received), its EL bit is set and the EL +// bit in the previous RXFD is cleared. +// Allocation done during INIT, this is making linked list. +// +UINT8 +SetupReceiveQueues ( + IN NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AdapterInfo - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + RxFD *rx_ptr; + RxFD *head_ptr; + RxFD *tail_ptr; + UINT16 Index; + + AdapterInfo->cur_rx_ind = 0; + rx_ptr = (&AdapterInfo->rx_ring[0]); + + for (Index = 0; Index < AdapterInfo->RxBufCnt; Index++) { + rx_ptr[Index].cb_header.status = 0; + rx_ptr[Index].cb_header.command = 0; + rx_ptr[Index].RFDSize = RX_BUFFER_SIZE; + rx_ptr[Index].ActualCount = 0; + // + // RBDs not used, simple memory model + // + rx_ptr[Index].rx_buf_addr = (UINT32) (-1); + + // + // RBDs not used, simple memory model + // + rx_ptr[Index].forwarded = FALSE; + + // + // don't use Tmp_ptr if it is beyond the last one + // + if (Index < AdapterInfo->RxBufCnt - 1) { + rx_ptr[Index].cb_header.link = (UINT32) AdapterInfo->rx_phy_addr + ((Index + 1) * sizeof (RxFD)); + } + } + + head_ptr = (&AdapterInfo->rx_ring[0]); + tail_ptr = (&AdapterInfo->rx_ring[AdapterInfo->RxBufCnt - 1]); + tail_ptr->cb_header.link = (UINT32) AdapterInfo->rx_phy_addr; + + // + // set the EL bit + // + tail_ptr->cb_header.command = 0xC000; + AdapterInfo->RFDTailPtr = tail_ptr; + return 0; +} + +VOID +Recycle_RFD ( + IN NIC_DATA_INSTANCE *AdapterInfo, + IN UINT16 rx_index + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AdapterInfo - TODO: add argument description + rx_index - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + RxFD *rx_ptr; + RxFD *tail_ptr; + // + // change the EL bit and change the AdapterInfo->RxTailPtr + // rx_ptr is assumed to be the head of the Q + // AdapterInfo->rx_forwarded[rx_index] = FALSE; + // + rx_ptr = &AdapterInfo->rx_ring[rx_index]; + tail_ptr = AdapterInfo->RFDTailPtr; + // + // set el_bit and suspend bit + // + rx_ptr->cb_header.command = 0xc000; + rx_ptr->cb_header.status = 0; + rx_ptr->ActualCount = 0; + rx_ptr->forwarded = FALSE; + AdapterInfo->RFDTailPtr = rx_ptr; + // + // resetting the el_bit. + // + tail_ptr->cb_header.command = 0; + // + // check the receive unit, fix if there is any problem + // + return ; +} +// +// Serial EEPROM section. +// +// EEPROM_Ctrl bits. +// +#define EE_SHIFT_CLK 0x01 /* EEPROM shift clock. */ +#define EE_CS 0x02 /* EEPROM chip select. */ +#define EE_DI 0x04 /* EEPROM chip data in. */ +#define EE_WRITE_0 0x01 +#define EE_WRITE_1 0x05 +#define EE_DO 0x08 /* EEPROM chip data out. */ +#define EE_ENB (0x4800 | EE_CS) + +// +// Delay between EEPROM clock transitions. +// This will actually work with no delay on 33Mhz PCI. +// +#define eeprom_delay(nanosec) DelayIt (AdapterInfo, nanosec); + +// +// The EEPROM commands include the alway-set leading bit. +// +#define EE_WRITE_CMD 5 // 101b +#define EE_READ_CMD 6 // 110b +#define EE_ERASE_CMD (7 << 6) + +VOID +shift_bits_out ( + IN NIC_DATA_INSTANCE *AdapterInfo, + IN UINT16 val, + IN UINT8 num_bits + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AdapterInfo - TODO: add argument description + val - TODO: add argument description + num_bits - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + INT32 Index; + UINT8 Tmp; + UINT32 EEAddr; + + EEAddr = AdapterInfo->ioaddr + SCBeeprom; + + for (Index = num_bits; Index >= 0; Index--) { + INT16 dataval; + + // + // will be 0 or 4 + // + dataval = (INT16) ((val & (1 << Index)) ? EE_DI : 0); + + // + // mask off the data_in bit + // + Tmp = (UINT8) (InByte (AdapterInfo, EEAddr) &~EE_DI); + Tmp |= dataval; + OutByte (AdapterInfo, Tmp, EEAddr); + eeprom_delay (100); + // + // raise the eeprom clock + // + OutByte (AdapterInfo, (UINT8) (Tmp | EE_SHIFT_CLK), EEAddr); + eeprom_delay (150); + // + // lower the eeprom clock + // + OutByte (AdapterInfo, (UINT8) (Tmp &~EE_SHIFT_CLK), EEAddr); + eeprom_delay (150); + } +} + +UINT16 +shift_bits_in ( + IN NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AdapterInfo - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + UINT8 Tmp; + INT32 Index; + UINT16 retval; + UINT32 EEAddr; + + EEAddr = AdapterInfo->ioaddr + SCBeeprom; + + retval = 0; + for (Index = 15; Index >= 0; Index--) { + // + // raise the clock + // + + // + // mask off the data_in bit + // + Tmp = InByte (AdapterInfo, EEAddr); + OutByte (AdapterInfo, (UINT8) (Tmp | EE_SHIFT_CLK), EEAddr); + eeprom_delay (100); + Tmp = InByte (AdapterInfo, EEAddr); + retval = (UINT16) ((retval << 1) | ((Tmp & EE_DO) ? 1 : 0)); + // + // lower the clock + // + OutByte (AdapterInfo, (UINT8) (Tmp &~EE_SHIFT_CLK), EEAddr); + eeprom_delay (100); + } + + return retval; +} + +BOOLEAN +E100bSetEepromLockOut ( + IN NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + This routine sets the EEPROM lockout bit to gain exclusive access to the + eeprom. the access bit is the most significant bit in the General Control + Register 2 in the SCB space. + +Arguments: + AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on.. + +Returns: + TRUE - if it got the access + FALSE - if it fails to get the exclusive access + +--*/ +{ + UINTN wait; + UINT8 tmp; + + if ((AdapterInfo->DeviceID == D102_DEVICE_ID) || + (AdapterInfo->RevID >= D102_REVID)) { + + wait = 500; + + while (wait--) { + + tmp = InByte (AdapterInfo, AdapterInfo->ioaddr + SCBGenCtrl2); + tmp |= GCR2_EEPROM_ACCESS_SEMAPHORE; + OutByte (AdapterInfo, tmp, AdapterInfo->ioaddr + SCBGenCtrl2); + + DelayIt (AdapterInfo, 50); + tmp = InByte (AdapterInfo, AdapterInfo->ioaddr + SCBGenCtrl2); + + if (tmp & GCR2_EEPROM_ACCESS_SEMAPHORE) { + return TRUE; + } + } + + return FALSE; + } + + return TRUE; +} + +VOID +E100bReSetEepromLockOut ( + IN NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + This routine Resets the EEPROM lockout bit to giveup access to the + eeprom. the access bit is the most significant bit in the General Control + Register 2 in the SCB space. + +Arguments: + AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on.. + +Returns: + None + +--*/ +{ + UINT8 tmp; + + if ((AdapterInfo->DeviceID == D102_DEVICE_ID) || + (AdapterInfo->RevID >= D102_REVID)) { + + tmp = InByte (AdapterInfo, AdapterInfo->ioaddr + SCBGenCtrl2); + tmp &= ~(GCR2_EEPROM_ACCESS_SEMAPHORE); + OutByte (AdapterInfo, tmp, AdapterInfo->ioaddr + SCBGenCtrl2); + + DelayIt (AdapterInfo, 50); + } +} + +UINT16 +E100bReadEeprom ( + IN NIC_DATA_INSTANCE *AdapterInfo, + IN INT32 Location, + IN UINT8 AddrLen + ) +/*++ + +Routine Description: + Using the NIC data structure information, read the EEPROM to get a Word of data for the MAC address. + +Arguments: + AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on.. + Location - Word offset into the MAC address to read. + AddrLen - Number of bits of address length. + +Returns: + RetVal - The word read from the EEPROM. + +--*/ +{ + UINT16 RetVal; + UINT8 Tmp; + + UINT32 EEAddr; + UINT16 ReadCmd; + + EEAddr = AdapterInfo->ioaddr + SCBeeprom; + ReadCmd = (UINT16) (Location | (EE_READ_CMD << AddrLen)); + + RetVal = 0; + + // + // get exclusive access to the eeprom first! + // + E100bSetEepromLockOut (AdapterInfo); + + // + // eeprom control reg bits: x,x,x,x,DO,DI,CS,SK + // to write the opcode+data value out one bit at a time in DI starting at msb + // and then out a 1 to sk, wait, out 0 to SK and wait + // repeat this for all the bits to be written + // + + // + // 11110010b + // + Tmp = (UINT8) (InByte (AdapterInfo, EEAddr) & 0xF2); + OutByte (AdapterInfo, (UINT8) (Tmp | EE_CS), EEAddr); + + // + // 3 for the read opcode 110b + // + shift_bits_out (AdapterInfo, ReadCmd, (UINT8) (3 + AddrLen)); + + // + // read the eeprom word one bit at a time + // + RetVal = shift_bits_in (AdapterInfo); + + // + // Terminate the EEPROM access and leave eeprom in a clean state. + // + Tmp = InByte (AdapterInfo, EEAddr); + Tmp &= ~(EE_CS | EE_DI); + OutByte (AdapterInfo, Tmp, EEAddr); + + // + // raise the clock and lower the eeprom shift clock + // + OutByte (AdapterInfo, (UINT8) (Tmp | EE_SHIFT_CLK), EEAddr); + eeprom_delay (100); + + OutByte (AdapterInfo, (UINT8) (Tmp &~EE_SHIFT_CLK), EEAddr); + eeprom_delay (100); + + // + // giveup access to the eeprom + // + E100bReSetEepromLockOut (AdapterInfo); + + return RetVal; +} + +UINT8 +E100bGetEepromAddrLen ( + IN NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + Using the NIC data structure information, read the EEPROM to determine how many bits of address length + this EEPROM is in Words. + +Arguments: + AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on.. + +Returns: + RetVal - The word read from the EEPROM. + +--*/ +{ + UINT8 Tmp; + UINT8 AddrLen; + UINT32 EEAddr; + // + // assume 64word eeprom (so,6 bits of address_length) + // + UINT16 ReadCmd; + + EEAddr = AdapterInfo->ioaddr + SCBeeprom; + ReadCmd = (EE_READ_CMD << 6); + + // + // get exclusive access to the eeprom first! + // + E100bSetEepromLockOut (AdapterInfo); + + // + // address we are trying to read is 0 + // eeprom control reg bits: x,x,x,x,DO,,DI,,CS,SK + // to write the opcode+data value out one bit at a time in DI starting at msb + // and then out a 1 to sk, wait, out 0 to SK and wait + // repeat this for all the bits to be written + // + Tmp = (UINT8) (InByte (AdapterInfo, EEAddr) & 0xF2); + + // + // enable eeprom access + // + OutByte (AdapterInfo, (UINT8) (Tmp | EE_CS), EEAddr); + + // + // 3 for opcode, 6 for the default address len + // + shift_bits_out (AdapterInfo, ReadCmd, (UINT8) (3 + 6)); + + // + // (in case of a 64 word eeprom). + // read the "dummy zero" from EE_DO to say that the address we wrote + // (six 0s) is accepted, write more zeros (until 8) to get a "dummy zero" + // + + // + // assume the smallest + // + AddrLen = 6; + Tmp = InByte (AdapterInfo, EEAddr); + while ((AddrLen < 8) && ((Tmp & EE_DO) != 0)) { + OutByte (AdapterInfo, (UINT8) (Tmp &~EE_DI), EEAddr); + eeprom_delay (100); + + // + // raise the eeprom clock + // + OutByte (AdapterInfo, (UINT8) (Tmp | EE_SHIFT_CLK), EEAddr); + eeprom_delay (150); + + // + // lower the eeprom clock + // + OutByte (AdapterInfo, (UINT8) (Tmp &~EE_SHIFT_CLK), EEAddr); + eeprom_delay (150); + Tmp = InByte (AdapterInfo, EEAddr); + AddrLen++; + } + + // + // read the eeprom word, even though we don't need this + // + shift_bits_in (AdapterInfo); + + // + // Terminate the EEPROM access. + // + Tmp = InByte (AdapterInfo, EEAddr); + Tmp &= ~(EE_CS | EE_DI); + OutByte (AdapterInfo, Tmp, EEAddr); + + // + // raise the clock and lower the eeprom shift clock + // + OutByte (AdapterInfo, (UINT8) (Tmp | EE_SHIFT_CLK), EEAddr); + eeprom_delay (100); + + OutByte (AdapterInfo, (UINT8) (Tmp &~EE_SHIFT_CLK), EEAddr); + eeprom_delay (100); + + // + // giveup access to the eeprom! + // + E100bReSetEepromLockOut (AdapterInfo); + + return AddrLen; +} + +UINTN +E100bStatistics ( + NIC_DATA_INSTANCE *AdapterInfo, + UINT64 DBaddr, + UINT16 DBsize + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AdapterInfo - TODO: add argument description + DBaddr - TODO: add argument description + DBsize - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + PXE_DB_STATISTICS db; + // + // wait upto one second (each wait is 100 micro s) + // + UINT32 Wait; + Wait = 10000; + wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd); + + // + // Clear statistics done marker. + // + AdapterInfo->statistics->done_marker = 0; + + // + // Issue statistics dump (or dump w/ reset) command. + // + OutByte ( + AdapterInfo, + (UINT8) (DBsize ? CU_SHOWSTATS : CU_DUMPSTATS), + (UINT32) (AdapterInfo->ioaddr + SCBCmd) + ); + + // + // Wait for command to complete. + // + // zero the db here just to chew up a little more time. + // + + ZeroMem ((VOID *) &db, sizeof db); + + while (Wait != 0) { + // + // Wait a bit before checking. + // + + DelayIt (AdapterInfo, 100); + + // + // Look for done marker at end of statistics. + // + + switch (AdapterInfo->statistics->done_marker) { + case 0xA005: + case 0xA007: + break; + + default: + Wait--; + continue; + } + + // + // if we did not "continue" from the above switch, we are done, + // + break; + } + + // + // If this is a reset, we are out of here! + // + if (DBsize == 0) { + return PXE_STATCODE_SUCCESS; + } + + // + // Convert NIC statistics counter format to EFI/UNDI + // specification statistics counter format. + // + + // + // 54 3210 fedc ba98 7654 3210 + // db.Supported = 01 0000 0100 1101 0001 0111; + // + db.Supported = 0x104D17; + + // + // Statistics from the NIC + // + + db.Data[0x01] = AdapterInfo->statistics->rx_good_frames; + + db.Data[0x02] = AdapterInfo->statistics->rx_runt_errs; + + db.Data[0x08] = AdapterInfo->statistics->rx_crc_errs + + AdapterInfo->statistics->rx_align_errs; + + db.Data[0x04] = db.Data[0x02] + + db.Data[0x08] + + AdapterInfo->statistics->rx_resource_errs + + AdapterInfo->statistics->rx_overrun_errs; + + db.Data[0x00] = db.Data[0x01] + db.Data[0x04]; + + db.Data[0x0B] = AdapterInfo->statistics->tx_good_frames; + + db.Data[0x0E] = AdapterInfo->statistics->tx_coll16_errs + + AdapterInfo->statistics->tx_late_colls + + AdapterInfo->statistics->tx_underruns + + AdapterInfo->statistics->tx_one_colls + + AdapterInfo->statistics->tx_multi_colls; + + db.Data[0x14] = AdapterInfo->statistics->tx_total_colls; + + db.Data[0x0A] = db.Data[0x0B] + + db.Data[0x0E] + + AdapterInfo->statistics->tx_lost_carrier; + + if (DBsize > sizeof db) { + DBsize = sizeof db; + } + + CopyMem ((VOID *) (UINTN) DBaddr, (VOID *) &db, (UINTN) DBsize); + + return PXE_STATCODE_SUCCESS; +} + +UINTN +E100bReset ( + IN NIC_DATA_INSTANCE *AdapterInfo, + IN INT32 OpFlags + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AdapterInfo - TODO: add argument description + OpFlags - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + + UINT16 save_filter; + // + // disable the interrupts + // + OutWord (AdapterInfo, INT_MASK, AdapterInfo->ioaddr + SCBCmd); + + // + // wait for the tx queue to complete + // + CheckCBList (AdapterInfo); + + XmitWaitForCompletion (AdapterInfo); + + if (AdapterInfo->Receive_Started) { + StopRU (AdapterInfo); + } + + InitializeChip (AdapterInfo); + + // + // check the opflags and restart receive filters + // + if ((OpFlags & PXE_OPFLAGS_RESET_DISABLE_FILTERS) == 0) { + + save_filter = AdapterInfo->Rx_Filter; + // + // if we give the filter same as Rx_Filter, + // this routine will not set mcast list (it thinks there is no change) + // to force it, we will reset that flag in the Rx_Filter + // + AdapterInfo->Rx_Filter &= (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST); + E100bSetfilter (AdapterInfo, save_filter, (UINT64) 0, (UINT32) 0); + } + + if ((OpFlags & PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS) != 0) { + // + // disable the interrupts + // + AdapterInfo->int_mask = 0; + } + // + // else leave the interrupt in the pre-set state!!! + // + E100bSetInterruptState (AdapterInfo); + + return 0; +} + +UINTN +E100bShutdown ( + IN NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AdapterInfo - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + // + // disable the interrupts + // + OutWord (AdapterInfo, INT_MASK, AdapterInfo->ioaddr + SCBCmd); + + // + // stop the receive unit + // + if (AdapterInfo->Receive_Started) { + StopRU (AdapterInfo); + } + + // + // wait for the tx queue to complete + // + CheckCBList (AdapterInfo); + if (AdapterInfo->FreeCBCount != AdapterInfo->TxBufCnt) { + wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd); + } + + // + // we do not want to reset the phy, it takes a long time to renegotiate the + // link after that (3-4 seconds) + // + InitializeChip (AdapterInfo); + SelectiveReset (AdapterInfo); + return 0; +} + +VOID +MdiWrite ( + IN NIC_DATA_INSTANCE *AdapterInfo, + IN UINT8 RegAddress, + IN UINT8 PhyAddress, + IN UINT16 DataValue + ) +/*++ + +Routine Description: + This routine will write a value to the specified MII register + of an external MDI compliant device (e.g. PHY 100). The command will + execute in polled mode. + +Arguments: + AdapterInfo - pointer to the structure that contains the NIC's context. + RegAddress - The MII register that we are writing to + PhyAddress - The MDI address of the Phy component. + DataValue - The value that we are writing to the MII register. + +Returns: + nothing +--*/ +{ + UINT32 WriteCommand; + + WriteCommand = ((UINT32) DataValue) | + ((UINT32)(RegAddress << 16)) | + ((UINT32)(PhyAddress << 21)) | + ((UINT32)(MDI_WRITE << 26)); + + // + // Issue the write command to the MDI control register. + // + OutLong (AdapterInfo, WriteCommand, AdapterInfo->ioaddr + SCBCtrlMDI); + + // + // wait 20usec before checking status + // + DelayIt (AdapterInfo, 20); + + // + // poll for the mdi write to complete + while ((InLong (AdapterInfo, AdapterInfo->ioaddr + SCBCtrlMDI) & + MDI_PHY_READY) == 0){ + DelayIt (AdapterInfo, 20); + } +} + +VOID +MdiRead ( + IN NIC_DATA_INSTANCE *AdapterInfo, + IN UINT8 RegAddress, + IN UINT8 PhyAddress, + IN OUT UINT16 *DataValue + ) +/*++ + +Routine Description: + This routine will read a value from the specified MII register + of an external MDI compliant device (e.g. PHY 100), and return + it to the calling routine. The command will execute in polled mode. + +Arguments: + AdapterInfo - pointer to the structure that contains the NIC's context. + RegAddress - The MII register that we are reading from + PhyAddress - The MDI address of the Phy component. + DataValue - pointer to the value that we read from the MII register. + +Returns: + +--*/ +{ + UINT32 ReadCommand; + + ReadCommand = ((UINT32) (RegAddress << 16)) | + ((UINT32) (PhyAddress << 21)) | + ((UINT32) (MDI_READ << 26)); + + // + // Issue the read command to the MDI control register. + // + OutLong (AdapterInfo, ReadCommand, AdapterInfo->ioaddr + SCBCtrlMDI); + + // + // wait 20usec before checking status + // + DelayIt (AdapterInfo, 20); + + // + // poll for the mdi read to complete + // + while ((InLong (AdapterInfo, AdapterInfo->ioaddr + SCBCtrlMDI) & + MDI_PHY_READY) == 0) { + DelayIt (AdapterInfo, 20); + + } + + *DataValue = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBCtrlMDI); +} + +VOID +PhyReset ( + NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + This routine will reset the PHY that the adapter is currently + configured to use. + +Arguments: + AdapterInfo - pointer to the structure that contains the NIC's context. + +Returns: + +--*/ +{ + UINT16 MdiControlReg; + + MdiControlReg = (MDI_CR_AUTO_SELECT | + MDI_CR_RESTART_AUTO_NEG | + MDI_CR_RESET); + + // + // Write the MDI control register with our new Phy configuration + // + MdiWrite ( + AdapterInfo, + MDI_CONTROL_REG, + AdapterInfo->PhyAddress, + MdiControlReg + ); + + return ; +} + +BOOLEAN +PhyDetect ( + NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + This routine will detect what phy we are using, set the line + speed, FDX or HDX, and configure the phy if necessary. + + The following combinations are supported: + - TX or T4 PHY alone at PHY address 1 + - T4 or TX PHY at address 1 and MII PHY at address 0 + - 82503 alone (10Base-T mode, no full duplex support) + - 82503 and MII PHY (TX or T4) at address 0 + + The sequence / priority of detection is as follows: + - PHY 1 with cable termination + - PHY 0 with cable termination + - PHY 1 (if found) without cable termination + - 503 interface + + Additionally auto-negotiation capable (NWAY) and parallel + detection PHYs are supported. The flow-chart is described in + the 82557 software writer's manual. + + NOTE: 1. All PHY MDI registers are read in polled mode. + 2. The routines assume that the 82557 has been RESET and we have + obtained the virtual memory address of the CSR. + 3. PhyDetect will not RESET the PHY. + 4. If FORCEFDX is set, SPEED should also be set. The driver will + check the values for inconsistency with the detected PHY + technology. + 5. PHY 1 (the PHY on the adapter) may have an address in the range + 1 through 31 inclusive. The driver will accept addresses in + this range. + 6. Driver ignores FORCEFDX and SPEED overrides if a 503 interface + is detected. + +Arguments: + AdapterInfo - pointer to the structure that contains the NIC's context. + +Returns: + TRUE - If a Phy was detected, and configured correctly. + FALSE - If a valid phy could not be detected and configured. + +--*/ +{ + UINT16 *eedata; + UINT16 MdiControlReg; + UINT16 MdiStatusReg; + BOOLEAN FoundPhy1; + UINT8 ReNegotiateTime; + + eedata = (UINT16 *) (&AdapterInfo->NVData[0]); + + FoundPhy1 = FALSE; + ReNegotiateTime = 35; + // + // EEPROM word [6] contains the Primary PHY record in which the least 3 bits + // indicate the PHY address + // and word [7] contains the secondary PHY record + // + AdapterInfo->PhyRecord[0] = eedata[6]; + AdapterInfo->PhyRecord[1] = eedata[7]; + AdapterInfo->PhyAddress = (UINT8) (AdapterInfo->PhyRecord[0] & 7); + + // + // Check for a phy address over-ride of 32 which indicates force use of 82503 + // not detecting the link in this case + // + if (AdapterInfo->PhyAddress == 32) { + // + // 503 interface over-ride + // Record the current speed and duplex. We will be in half duplex + // mode unless the user used the force full duplex over-ride. + // + AdapterInfo->LinkSpeed = 10; + return (TRUE); + } + + // + // If the Phy Address is between 1-31 then we must first look for phy 1, + // at that address. + // + if ((AdapterInfo->PhyAddress > 0) && (AdapterInfo->PhyAddress < 32)) { + + // + // Read the MDI control and status registers at phy 1 + // and check if we found a valid phy + // + MdiRead ( + AdapterInfo, + MDI_CONTROL_REG, + AdapterInfo->PhyAddress, + &MdiControlReg + ); + + MdiRead ( + AdapterInfo, + MDI_STATUS_REG, + AdapterInfo->PhyAddress, + &MdiStatusReg + ); + + if (!((MdiControlReg == 0xffff) || + ((MdiStatusReg == 0) && (MdiControlReg == 0)))) { + + // + // we have a valid phy1 + // Read the status register again because of sticky bits + // + FoundPhy1 = TRUE; + MdiRead ( + AdapterInfo, + MDI_STATUS_REG, + AdapterInfo->PhyAddress, + &MdiStatusReg + ); + + // + // If there is a valid link then use this Phy. + // + if (MdiStatusReg & MDI_SR_LINK_STATUS) { + return (SetupPhy(AdapterInfo)); + } + } + } + + // + // Next try to detect a PHY at address 0x00 because there was no Phy 1, + // or Phy 1 didn't have link, or we had a phy 0 over-ride + // + + // + // Read the MDI control and status registers at phy 0 + // + MdiRead (AdapterInfo, MDI_CONTROL_REG, 0, &MdiControlReg); + MdiRead (AdapterInfo, MDI_STATUS_REG, 0, &MdiStatusReg); + + // + // check if we found a valid phy 0 + // + if (((MdiControlReg == 0xffff) || + ((MdiStatusReg == 0) && (MdiControlReg == 0)))) { + + // + // we don't have a valid phy at address 0 + // if phy address was forced to 0, then error out because we + // didn't find a phy at that address + // + if (AdapterInfo->PhyAddress == 0x0000) { + return (FALSE); + } else { + // + // at this point phy1 does not have link and there is no phy 0 at all + // if we are forced to detect the cable, error out here! + // + if (AdapterInfo->CableDetect != 0) { + return FALSE; + + } + + if (FoundPhy1) { + // + // no phy 0, but there is a phy 1 (no link I guess), so use phy 1 + // + return SetupPhy (AdapterInfo); + } else { + // + // didn't find phy 0 or phy 1, so assume a 503 interface + // + AdapterInfo->PhyAddress = 32; + + // + // Record the current speed and duplex. We'll be in half duplex + // mode unless the user used the force full duplex over-ride. + // + AdapterInfo->LinkSpeed = 10; + return (TRUE); + } + } + } else { + // + // We have a valid phy at address 0. If phy 0 has a link then we use + // phy 0. If Phy 0 doesn't have a link then we use Phy 1 (no link) + // if phy 1 is present, or phy 0 if phy 1 is not present + // If phy 1 was present, then we must isolate phy 1 before we enable + // phy 0 to see if Phy 0 has a link. + // + if (FoundPhy1) { + // + // isolate phy 1 + // + MdiWrite ( + AdapterInfo, + MDI_CONTROL_REG, + AdapterInfo->PhyAddress, + MDI_CR_ISOLATE + ); + + // + // wait 100 microseconds for the phy to isolate. + // + DelayIt (AdapterInfo, 100); + } + + // + // Since this Phy is at address 0, we must enable it. So clear + // the isolate bit, and set the auto-speed select bit + // + MdiWrite ( + AdapterInfo, + MDI_CONTROL_REG, + 0, + MDI_CR_AUTO_SELECT + ); + + // + // wait 100 microseconds for the phy to be enabled. + // + DelayIt (AdapterInfo, 100); + + // + // restart the auto-negotion process + // + MdiWrite ( + AdapterInfo, + MDI_CONTROL_REG, + 0, + MDI_CR_RESTART_AUTO_NEG | MDI_CR_AUTO_SELECT + ); + + // + // wait no more than 3.5 seconds for auto-negotiation to complete + // + while (ReNegotiateTime) { + // + // Read the status register twice because of sticky bits + // + MdiRead (AdapterInfo, MDI_STATUS_REG, 0, &MdiStatusReg); + MdiRead (AdapterInfo, MDI_STATUS_REG, 0, &MdiStatusReg); + + if (MdiStatusReg & MDI_SR_AUTO_NEG_COMPLETE) { + break; + } + + DelayIt (AdapterInfo, 100); + ReNegotiateTime--; + } + + // + // Read the status register again because of sticky bits + // + MdiRead (AdapterInfo, MDI_STATUS_REG, 0, &MdiStatusReg); + + // + // If the link was not set + // + if ((MdiStatusReg & MDI_SR_LINK_STATUS) == 0) { + // + // PHY1 does not have a link and phy 0 does not have a link + // do not proceed if we need to detect the link! + // + if (AdapterInfo->CableDetect != 0) { + return FALSE; + } + + // + // the link wasn't set, so use phy 1 if phy 1 was present + // + if (FoundPhy1) { + // + // isolate phy 0 + // + MdiWrite (AdapterInfo, MDI_CONTROL_REG, 0, MDI_CR_ISOLATE); + + // + // wait 100 microseconds for the phy to isolate. + // + DelayIt (AdapterInfo, 100); + + // + // Now re-enable PHY 1 + // + MdiWrite ( + AdapterInfo, + MDI_CONTROL_REG, + AdapterInfo->PhyAddress, + MDI_CR_AUTO_SELECT + ); + + // + // wait 100 microseconds for the phy to be enabled + // + DelayIt (AdapterInfo, 100); + + // + // restart the auto-negotion process + // + MdiWrite ( + AdapterInfo, + MDI_CONTROL_REG, + AdapterInfo->PhyAddress, + MDI_CR_RESTART_AUTO_NEG | MDI_CR_AUTO_SELECT + ); + + // + // Don't wait for it to complete (we didn't have link earlier) + // + return (SetupPhy (AdapterInfo)); + } + } + + // + // Definitely using Phy 0 + // + AdapterInfo->PhyAddress = 0; + return (SetupPhy(AdapterInfo)); + } +} + +BOOLEAN +SetupPhy ( + IN NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + This routine will setup phy 1 or phy 0 so that it is configured + to match a speed and duplex over-ride option. If speed or + duplex mode is not explicitly specified in the registry, the + driver will skip the speed and duplex over-ride code, and + assume the adapter is automatically setting the line speed, and + the duplex mode. At the end of this routine, any truly Phy + specific code will be executed (each Phy has its own quirks, + and some require that certain special bits are set). + + NOTE: The driver assumes that SPEED and FORCEFDX are specified at the + same time. If FORCEDPX is set without speed being set, the driver + will encouter a fatal error and log a message into the event viewer. + +Arguments: + AdapterInfo - pointer to the structure that contains the NIC's context. + +Returns: + TRUE - If the phy could be configured correctly + FALSE - If the phy couldn't be configured correctly, because an + unsupported over-ride option was used + +--*/ +{ + UINT16 MdiControlReg; + UINT16 MdiStatusReg; + UINT16 MdiIdLowReg; + UINT16 MdiIdHighReg; + UINT16 MdiMiscReg; + UINT32 PhyId; + BOOLEAN ForcePhySetting; + + ForcePhySetting = FALSE; + + // + // If we are NOT forcing a setting for line speed or full duplex, then + // we won't force a link setting, and we'll jump down to the phy + // specific code. + // + if (((AdapterInfo->LinkSpeedReq) || (AdapterInfo->DuplexReq))) { + // + // Find out what kind of technology this Phy is capable of. + // + MdiRead ( + AdapterInfo, + MDI_STATUS_REG, + AdapterInfo->PhyAddress, + &MdiStatusReg + ); + + // + // Read the MDI control register at our phy + // + MdiRead ( + AdapterInfo, + MDI_CONTROL_REG, + AdapterInfo->PhyAddress, + &MdiControlReg + ); + + // + // Now check the validity of our forced option. If the force option is + // valid, then force the setting. If the force option is not valid, + // we'll set a flag indicating that we should error out. + // + + // + // If speed is forced to 10mb + // + if (AdapterInfo->LinkSpeedReq == 10) { + // + // If half duplex is forced + // + if ((AdapterInfo->DuplexReq & PXE_FORCE_HALF_DUPLEX) != 0) { + if (MdiStatusReg & MDI_SR_10T_HALF_DPX) { + + MdiControlReg &= ~(MDI_CR_10_100 | MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF); + ForcePhySetting = TRUE; + } + } else if ((AdapterInfo->DuplexReq & PXE_FORCE_FULL_DUPLEX) != 0) { + + // + // If full duplex is forced + // + if (MdiStatusReg & MDI_SR_10T_FULL_DPX) { + + MdiControlReg &= ~(MDI_CR_10_100 | MDI_CR_AUTO_SELECT); + MdiControlReg |= MDI_CR_FULL_HALF; + ForcePhySetting = TRUE; + } + } else { + // + // If auto duplex (we actually set phy to 1/2) + // + if (MdiStatusReg & (MDI_SR_10T_FULL_DPX | MDI_SR_10T_HALF_DPX)) { + + MdiControlReg &= ~(MDI_CR_10_100 | MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF); + ForcePhySetting = TRUE; + } + } + } + + // + // If speed is forced to 100mb + // + else if (AdapterInfo->LinkSpeedReq == 100) { + // + // If half duplex is forced + // + if ((AdapterInfo->DuplexReq & PXE_FORCE_HALF_DUPLEX) != 0) { + if (MdiStatusReg & (MDI_SR_TX_HALF_DPX | MDI_SR_T4_CAPABLE)) { + + MdiControlReg &= ~(MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF); + MdiControlReg |= MDI_CR_10_100; + ForcePhySetting = TRUE; + } + } else if ((AdapterInfo->DuplexReq & PXE_FORCE_FULL_DUPLEX) != 0) { + // + // If full duplex is forced + // + if (MdiStatusReg & MDI_SR_TX_FULL_DPX) { + MdiControlReg &= ~MDI_CR_AUTO_SELECT; + MdiControlReg |= (MDI_CR_10_100 | MDI_CR_FULL_HALF); + ForcePhySetting = TRUE; + } + } else { + // + // If auto duplex (we set phy to 1/2) + // + if (MdiStatusReg & (MDI_SR_TX_HALF_DPX | MDI_SR_T4_CAPABLE)) { + + MdiControlReg &= ~(MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF); + MdiControlReg |= MDI_CR_10_100; + ForcePhySetting = TRUE; + } + } + } + + if (!ForcePhySetting) { + return (FALSE); + } + + // + // Write the MDI control register with our new Phy configuration + // + MdiWrite ( + AdapterInfo, + MDI_CONTROL_REG, + AdapterInfo->PhyAddress, + MdiControlReg + ); + + // + // wait 100 milliseconds for auto-negotiation to complete + // + DelayIt (AdapterInfo, 100); + } + + // + // Find out specifically what Phy this is. We do this because for certain + // phys there are specific bits that must be set so that the phy and the + // 82557 work together properly. + // + + MdiRead ( + AdapterInfo, + PHY_ID_REG_1, + AdapterInfo->PhyAddress, + &MdiIdLowReg + ); + MdiRead ( + AdapterInfo, + PHY_ID_REG_2, + AdapterInfo->PhyAddress, + &MdiIdHighReg + ); + + PhyId = ((UINT32) MdiIdLowReg | ((UINT32) MdiIdHighReg << 16)); + + // + // And out the revsion field of the Phy ID so that we'll be able to detect + // future revs of the same Phy. + // + PhyId &= PHY_MODEL_REV_ID_MASK; + + // + // Handle the National TX + // + if (PhyId == PHY_NSC_TX) { + + MdiRead ( + AdapterInfo, + NSC_CONG_CONTROL_REG, + AdapterInfo->PhyAddress, + &MdiMiscReg + ); + + MdiMiscReg |= (NSC_TX_CONG_TXREADY | NSC_TX_CONG_F_CONNECT); + +#if CONGESTION_CONTROL + // + // If we are configured to do congestion control, then enable the + // congestion control bit in the National Phy + // + if (AdapterInfo->Congest) { + MdiMiscReg |= NSC_TX_CONG_ENABLE; + } else { + MdiMiscReg &= ~NSC_TX_CONG_ENABLE; + } +#endif + MdiWrite ( + AdapterInfo, + NSC_CONG_CONTROL_REG, + AdapterInfo->PhyAddress, + MdiMiscReg + ); + } + + FindPhySpeedAndDpx (AdapterInfo, PhyId); + + // + // We put a hardware fix on to our adapters to work-around the PHY_100 errata + // described below. The following code is only compiled in, if we wanted + // to attempt a software workaround to the PHY_100 A/B step problem. + // + +#if DO_PHY_100B_SOFTWARE_FIX + // + // Handle the Intel PHY_100 (A and B steps) + // + if ((PhyId == PHY_100_A) && (AdapterInfo->LinkSpeed == 100)) { + // + // The PHY_100 is very sensitive to collisions at 100mb, so increase + // the Adaptive IFS value with the intention of reducing the number of + // collisions that the adapter generates. + // + AdapterInfo->CurrentIFSValue = 0x18; + AdapterInfo->AdaptiveIFS = 0; + } +#endif + + return (TRUE); +} + +VOID +FindPhySpeedAndDpx ( + IN NIC_DATA_INSTANCE *AdapterInfo, + IN UINT32 PhyId + ) +/*++ + +Routine Description: + This routine will figure out what line speed and duplex mode + the PHY is currently using. + +Arguments: + AdapterInfo - pointer to the structure that contains the NIC's context. + PhyId - The ID of the PHY in question. + +Returns: + NOTHING +--*/ +{ + UINT16 MdiStatusReg; + UINT16 MdiMiscReg; + UINT16 MdiOwnAdReg; + UINT16 MdiLinkPartnerAdReg; + + // + // If there was a speed and/or duplex override, then set our current + // value accordingly + // + AdapterInfo->LinkSpeed = AdapterInfo->LinkSpeedReq; + AdapterInfo->Duplex = (UINT8) ((AdapterInfo->DuplexReq & PXE_FORCE_FULL_DUPLEX) ? + FULL_DUPLEX : HALF_DUPLEX); + + // + // If speed and duplex were forced, then we know our current settings, so + // we'll just return. Otherwise, we'll need to figure out what NWAY set + // us to. + // + if (AdapterInfo->LinkSpeed && AdapterInfo->Duplex) { + return ; + + } + // + // If we didn't have a valid link, then we'll assume that our current + // speed is 10mb half-duplex. + // + + // + // Read the status register twice because of sticky bits + // + MdiRead ( + AdapterInfo, + MDI_STATUS_REG, + AdapterInfo->PhyAddress, + &MdiStatusReg + ); + MdiRead ( + AdapterInfo, + MDI_STATUS_REG, + AdapterInfo->PhyAddress, + &MdiStatusReg + ); + + // + // If there wasn't a valid link then use default speed & duplex + // + if (!(MdiStatusReg & MDI_SR_LINK_STATUS)) { + + AdapterInfo->LinkSpeed = 10; + AdapterInfo->Duplex = HALF_DUPLEX; + return ; + } + + // + // If this is an Intel PHY (a T4 PHY_100 or a TX PHY_TX), then read bits + // 1 and 0 of extended register 0, to get the current speed and duplex + // settings. + // + if ((PhyId == PHY_100_A) || (PhyId == PHY_100_C) || (PhyId == PHY_TX_ID)) { + // + // Read extended register 0 + // + MdiRead ( + AdapterInfo, + EXTENDED_REG_0, + AdapterInfo->PhyAddress, + &MdiMiscReg + ); + + // + // Get current speed setting + // + if (MdiMiscReg & PHY_100_ER0_SPEED_INDIC) { + AdapterInfo->LinkSpeed = 100; + } else { + AdapterInfo->LinkSpeed = 10; + } + + // + // Get current duplex setting -- if bit is set then FDX is enabled + // + if (MdiMiscReg & PHY_100_ER0_FDX_INDIC) { + AdapterInfo->Duplex = FULL_DUPLEX; + } else { + AdapterInfo->Duplex = HALF_DUPLEX; + } + + return ; + } + // + // Read our link partner's advertisement register + // + MdiRead ( + AdapterInfo, + AUTO_NEG_LINK_PARTNER_REG, + AdapterInfo->PhyAddress, + &MdiLinkPartnerAdReg + ); + + // + // See if Auto-Negotiation was complete (bit 5, reg 1) + // + MdiRead ( + AdapterInfo, + MDI_STATUS_REG, + AdapterInfo->PhyAddress, + &MdiStatusReg + ); + + // + // If a True NWAY connection was made, then we can detect speed/duplex by + // ANDing our adapter's advertised abilities with our link partner's + // advertised ablilities, and then assuming that the highest common + // denominator was chosed by NWAY. + // + if ((MdiLinkPartnerAdReg & NWAY_LP_ABILITY) && + (MdiStatusReg & MDI_SR_AUTO_NEG_COMPLETE)) { + + // + // Read our advertisement register + // + MdiRead ( + AdapterInfo, + AUTO_NEG_ADVERTISE_REG, + AdapterInfo->PhyAddress, + &MdiOwnAdReg + ); + + // + // AND the two advertisement registers together, and get rid of any + // extraneous bits. + // + MdiOwnAdReg &= (MdiLinkPartnerAdReg & NWAY_LP_ABILITY); + + // + // Get speed setting + // + if (MdiOwnAdReg & (NWAY_AD_TX_HALF_DPX | NWAY_AD_TX_FULL_DPX | NWAY_AD_T4_CAPABLE)) { + AdapterInfo->LinkSpeed = 100; + } else { + AdapterInfo->LinkSpeed = 10; + } + + // + // Get duplex setting -- use priority resolution algorithm + // + if (MdiOwnAdReg & (NWAY_AD_T4_CAPABLE)) { + AdapterInfo->Duplex = HALF_DUPLEX; + return ; + } else if (MdiOwnAdReg & (NWAY_AD_TX_FULL_DPX)) { + AdapterInfo->Duplex = FULL_DUPLEX; + return ; + } else if (MdiOwnAdReg & (NWAY_AD_TX_HALF_DPX)) { + AdapterInfo->Duplex = HALF_DUPLEX; + return ; + } else if (MdiOwnAdReg & (NWAY_AD_10T_FULL_DPX)) { + AdapterInfo->Duplex = FULL_DUPLEX; + return ; + } else { + AdapterInfo->Duplex = HALF_DUPLEX; + return ; + } + } + + // + // If we are connected to a dumb (non-NWAY) repeater or hub, and the line + // speed was determined automatically by parallel detection, then we have + // no way of knowing exactly what speed the PHY is set to unless that PHY + // has a propietary register which indicates speed in this situation. The + // NSC TX PHY does have such a register. Also, since NWAY didn't establish + // the connection, the duplex setting should HALF duplex. + // + AdapterInfo->Duplex = HALF_DUPLEX; + + if (PhyId == PHY_NSC_TX) { + // + // Read register 25 to get the SPEED_10 bit + // + MdiRead ( + AdapterInfo, + NSC_SPEED_IND_REG, + AdapterInfo->PhyAddress, + &MdiMiscReg + ); + + // + // If bit 6 was set then we're at 10mb + // + if (MdiMiscReg & NSC_TX_SPD_INDC_SPEED) { + AdapterInfo->LinkSpeed = 10; + } else { + AdapterInfo->LinkSpeed = 100; + } + } + + // + // If we don't know what line speed we are set at, then we'll default to + // 10mbs + // + else { + AdapterInfo->LinkSpeed = 10; + } +} + +VOID +XmitWaitForCompletion ( + NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AdapterInfo - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + TxCB *TxPtr; + + if (AdapterInfo->FreeCBCount == AdapterInfo->TxBufCnt) { + return ; + } + + // + // used xmit cb list starts right after the free tail (ends before the + // free head ptr) + // + TxPtr = AdapterInfo->FreeTxTailPtr->NextTCBVirtualLinkPtr; + while (TxPtr != AdapterInfo->FreeTxHeadPtr) { + CommandWaitForCompletion (TxPtr, AdapterInfo); + SetFreeCB (AdapterInfo, TxPtr); + TxPtr = TxPtr->NextTCBVirtualLinkPtr; + } +} + +INT8 +CommandWaitForCompletion ( + TxCB *cmd_ptr, + NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + cmd_ptr - TODO: add argument description + AdapterInfo - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + INT16 wait; + wait = 5000; + while ((cmd_ptr->cb_header.status == 0) && (--wait > 0)) { + DelayIt (AdapterInfo, 10); + } + + if (cmd_ptr->cb_header.status == 0) { + return -1; + } + + return 0; +} + +INT8 +SoftwareReset ( + NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AdapterInfo - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + UINT8 tco_stat; + UINT16 wait; + + tco_stat = 0; + + // + // Reset the chip: stop Tx and Rx processes and clear counters. + // This takes less than 10usec and will easily finish before the next + // action. + // + + OutLong (AdapterInfo, PORT_RESET, AdapterInfo->ioaddr + SCBPort); + // + // wait for 5 milli seconds here! + // + DelayIt (AdapterInfo, 5000); + // + // TCO Errata work around for 559s only + // ----------------------------------------------------------------------------------- + // TCO Workaround Code + // haifa workaround + // ----------------------------------------------------------------------------------- + // 1. Issue SW-RST ^^^ (already done above) + // 2. Issue a redundant Set CU Base CMD immediately + // Do not set the General Pointer before the Set CU Base cycle + // Do not check the SCB CMD before the Set CU Base cycle + // 3. Wait for the SCB-CMD to be cleared + // this indicates the transition to post-driver + // 4. Poll the TCO-Req bit in the PMDR to be cleared + // this indicates the tco activity has stopped for real + // 5. Proceed with the nominal Driver Init: + // Actual Set CU & RU Base ... + // + // Check for ICH2 device ID. If this is an ICH2, + // do the TCO workaround code. + // + if (AdapterInfo->VendorID == D102_DEVICE_ID || + AdapterInfo->VendorID == ICH3_DEVICE_ID_1 || + AdapterInfo->VendorID == ICH3_DEVICE_ID_2 || + AdapterInfo->VendorID == ICH3_DEVICE_ID_3 || + AdapterInfo->VendorID == ICH3_DEVICE_ID_4 || + AdapterInfo->VendorID == ICH3_DEVICE_ID_5 || + AdapterInfo->VendorID == ICH3_DEVICE_ID_6 || + AdapterInfo->VendorID == ICH3_DEVICE_ID_7 || + AdapterInfo->VendorID == ICH3_DEVICE_ID_8 || + AdapterInfo->RevID >= 8) { // do the TCO fix + // + // donot load the scb pointer but just give load_cu cmd. + // + OutByte (AdapterInfo, CU_CMD_BASE, AdapterInfo->ioaddr + SCBCmd); + // + // wait for command to be accepted. + // + wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd); + // + // read PMDR register and check bit 1 in it to see if TCO is active + // + + // + // wait for 5 milli seconds + // + wait = 5000; + while (wait) { + tco_stat = InByte (AdapterInfo, AdapterInfo->ioaddr + 0x1b); + if ((tco_stat & 2) == 0) { + // + // is the activity bit clear?? + // + break; + } + + wait--; + DelayIt (AdapterInfo, 1); + } + + if ((tco_stat & 2) != 0) { + // + // not zero?? + // + return -1; + } + } + + return 0; +} + +UINT8 +SelectiveReset ( + IN NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AdapterInfo - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + UINT16 wait; + UINT32 stat; + + wait = 10; + stat = 0; + OutLong (AdapterInfo, POR_SELECTIVE_RESET, AdapterInfo->ioaddr + SCBPort); + // + // wait for this to complete + // + + // + // wait for 2 milli seconds here! + // + DelayIt (AdapterInfo, 2000); + while (wait > 0) { + wait--; + stat = InLong (AdapterInfo, AdapterInfo->ioaddr + SCBPort); + if (stat == 0) { + break; + } + + // + // wait for 1 milli second + // + DelayIt (AdapterInfo, 1000); + } + + if (stat != 0) { + return PXE_STATCODE_DEVICE_FAILURE; + } + + return 0; +} + +UINT16 +InitializeChip ( + IN NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + AdapterInfo - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + UINT16 ret_val; + if (SoftwareReset (AdapterInfo) != 0) { + return PXE_STATCODE_DEVICE_FAILURE; + } + + // + // disable interrupts + // + OutWord (AdapterInfo, INT_MASK, AdapterInfo->ioaddr + SCBCmd); + + // + // Load the base registers with 0s (we will give the complete address as + // offset later when we issue any command + // + if ((ret_val = Load_Base_Regs (AdapterInfo)) != 0) { + return ret_val; + } + + if ((ret_val = SetupCBlink (AdapterInfo)) != 0) { + return ret_val; + } + + if ((ret_val = SetupReceiveQueues (AdapterInfo)) != 0) { + return ret_val; + } + + // + // detect the PHY only if we need to detect the cable as requested by the + // initialize parameters + // + AdapterInfo->PhyAddress = 0xFF; + + if (AdapterInfo->CableDetect != 0) { + if (!PhyDetect (AdapterInfo)) { + return PXE_STATCODE_DEVICE_FAILURE; + } + } + + if ((ret_val = E100bSetupIAAddr (AdapterInfo)) != 0) { + return ret_val; + } + + if ((ret_val = Configure (AdapterInfo)) != 0) { + return ret_val; + } + + return 0; +} + +#pragma data_seg() diff --git a/EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/E100b.h b/EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/E100b.h new file mode 100644 index 0000000000..3a4127c4e5 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/E100b.h @@ -0,0 +1,668 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + E100B.H + +Abstract: + + +Revision History + +--*/ +// pci config offsets: + +#define RX_BUFFER_COUNT 32 +#define TX_BUFFER_COUNT 32 + +#define PCI_VENDOR_ID_INTEL 0x8086 +#define PCI_DEVICE_ID_INTEL_82557 0x1229 +#define D100_VENDOR_ID 0x8086 +#define D100_DEVICE_ID 0x1229 +#define D102_DEVICE_ID 0x2449 + +#define ICH3_DEVICE_ID_1 0x1031 +#define ICH3_DEVICE_ID_2 0x1032 +#define ICH3_DEVICE_ID_3 0x1033 +#define ICH3_DEVICE_ID_4 0x1034 +#define ICH3_DEVICE_ID_5 0x1035 +#define ICH3_DEVICE_ID_6 0x1036 +#define ICH3_DEVICE_ID_7 0x1037 +#define ICH3_DEVICE_ID_8 0x1038 + +#define SPEEDO_DEVICE_ID 0x1227 +#define SPLASH1_DEVICE_ID 0x1226 + + +// bit fields for the command +#define PCI_COMMAND_MASTER 0x04 // bit 2 +#define PCI_COMMAND_IO 0x01 // bit 0 +#define PCI_COMMAND 0x04 +#define PCI_LATENCY_TIMER 0x0D + +#define ETHER_MAC_ADDR_LEN 6 +#ifdef AVL_XXX +#define ETHER_HEADER_LEN 14 +// media interface type +// #define INTERFACE_TYPE " + +// Hardware type values +#define HW_ETHER_TYPE 1 +#define HW_EXPERIMENTAL_ETHER_TYPE 2 +#define HW_IEEE_TYPE 6 +#define HW_ARCNET_TYPE 7 + +#endif // AVL_XXX + +#define MAX_ETHERNET_PKT_SIZE 1514 // including eth header +#define RX_BUFFER_SIZE 1536 // including crc and padding +#define TX_BUFFER_SIZE 64 +#define ETH_MTU 1500 // does not include ethernet header length + +#define SPEEDO3_TOTAL_SIZE 0x20 + +#pragma pack(1) + +typedef struct eth { + UINT8 dest_addr[PXE_HWADDR_LEN_ETHER]; + UINT8 src_addr[PXE_HWADDR_LEN_ETHER]; + UINT16 type; +} EtherHeader; + +#pragma pack(1) +typedef struct CONFIG_HEADER { + UINT16 VendorID; + UINT16 DeviceID; + UINT16 Command; + UINT16 Status; + UINT16 RevID; + UINT16 ClassID; + UINT8 CacheLineSize; + UINT8 LatencyTimer; + UINT8 HeaderType; // must be zero to impose this structure... + UINT8 BIST; // built-in self test + UINT32 BaseAddressReg_0; // memory mapped address + UINT32 BaseAddressReg_1; //io mapped address, Base IO address + UINT32 BaseAddressReg_2; // option rom address + UINT32 BaseAddressReg_3; + UINT32 BaseAddressReg_4; + UINT32 BaseAddressReg_5; + UINT32 CardBusCISPtr; + UINT16 SubVendorID; + UINT16 SubSystemID; + UINT32 ExpansionROMBaseAddr; + UINT8 CapabilitiesPtr; + UINT8 reserved1; + UINT16 Reserved2; + UINT32 Reserved3; + UINT8 int_line; + UINT8 int_pin; + UINT8 Min_gnt; + UINT8 Max_lat; +} PCI_CONFIG_HEADER; +#pragma pack() + +//------------------------------------------------------------------------- +// Offsets to the various registers. +// All accesses need not be longword aligned. +//------------------------------------------------------------------------- +enum speedo_offsets { + SCBStatus = 0, SCBCmd = 2, // Rx/Command Unit command and status. + SCBPointer = 4, // General purpose pointer. + SCBPort = 8, // Misc. commands and operands. + SCBflash = 12, SCBeeprom = 14, // EEPROM and flash memory control. + SCBCtrlMDI = 16, // MDI interface control. + SCBEarlyRx = 20, // Early receive byte count. + SCBEarlyRxInt = 24, SCBFlowCtrlReg = 25, SCBPmdr = 27, + // offsets for general control registers (GCRs) + SCBGenCtrl = 28, SCBGenStatus = 29, SCBGenCtrl2 = 30, SCBRsvd = 31, +}; + +#define GCR2_EEPROM_ACCESS_SEMAPHORE 0x80 // bit offset into the gcr2 + +//------------------------------------------------------------------------- +// Action commands - Commands that can be put in a command list entry. +//------------------------------------------------------------------------- +enum commands { + CmdNOp = 0, CmdIASetup = 1, CmdConfigure = 2, CmdMulticastList = 3, + CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7, + CmdSuspend = 0x4000, /* Suspend after completion. */ + CmdIntr = 0x2000, /* Interrupt after completion. */ + CmdTxFlex = 0x0008, /* Use "Flexible mode" for CmdTx command. */ +}; + +//------------------------------------------------------------------------- +// port commands +//------------------------------------------------------------------------- +#define PORT_RESET 0 +#define PORT_SELF_TEST 1 +#define POR_SELECTIVE_RESET 2 +#define PORT_DUMP_POINTER 2 + +//------------------------------------------------------------------------- +// SCB Command Word bit definitions +//------------------------------------------------------------------------- +//- CUC fields +#define CU_START 0x0010 +#define CU_RESUME 0x0020 +#define CU_STATSADDR 0x0040 +#define CU_SHOWSTATS 0x0050 /* Dump statistics counters. */ +#define CU_CMD_BASE 0x0060 /* Base address to add to add CU commands. */ +#define CU_DUMPSTATS 0x0070 /* Dump then reset stats counters. */ + +//- RUC fields +#define RX_START 0x0001 +#define RX_RESUME 0x0002 +#define RX_ABORT 0x0004 +#define RX_ADDR_LOAD 0x0006 /* load ru_base_reg */ +#define RX_RESUMENR 0x0007 + +// Interrupt fields (assuming byte addressing) +#define INT_MASK 0x0100 +#define DRVR_INT 0x0200 /* Driver generated interrupt. */ + +//- CB Status Word +#define CMD_STATUS_COMPLETE 0x8000 +#define RX_STATUS_COMPLETE 0x8000 +#define CMD_STATUS_MASK 0xF000 + +//------------------------------------------------------------------------- +//- SCB Status bits: +// Interrupts are ACKed by writing to the upper 6 interrupt bits +//------------------------------------------------------------------------- +#define SCB_STATUS_MASK 0xFC00 // bits 2-7 - STATUS/ACK Mask +#define SCB_STATUS_CX_TNO 0x8000 // BIT_15 - CX or TNO Interrupt +#define SCB_STATUS_FR 0x4000 // BIT_14 - FR Interrupt +#define SCB_STATUS_CNA 0x2000 // BIT_13 - CNA Interrupt +#define SCB_STATUS_RNR 0x1000 // BIT_12 - RNR Interrupt +#define SCB_STATUS_MDI 0x0800 // BIT_11 - MDI R/W Done Interrupt +#define SCB_STATUS_SWI 0x0400 // BIT_10 - SWI Interrupt + +// CU STATUS: bits 6 & 7 +#define SCB_STATUS_CU_MASK 0x00C0 // bits 6 & 7 +#define SCB_STATUS_CU_IDLE 0x0000 // 00 +#define SCB_STATUS_CU_SUSPEND 0x0040 // 01 +#define SCB_STATUS_CU_ACTIVE 0x0080 // 10 + +// RU STATUS: bits 2-5 +#define SCB_RUS_IDLE 0x0000 +#define SCB_RUS_SUSPENDED 0x0004 // bit 2 +#define SCB_RUS_NO_RESOURCES 0x0008 // bit 3 +#define SCB_RUS_READY 0x0010 // bit 4 + +//------------------------------------------------------------------------- +// Bit Mask definitions +//------------------------------------------------------------------------- +#define BIT_0 0x0001 +#define BIT_1 0x0002 +#define BIT_2 0x0004 +#define BIT_3 0x0008 +#define BIT_4 0x0010 +#define BIT_5 0x0020 +#define BIT_6 0x0040 +#define BIT_7 0x0080 +#define BIT_8 0x0100 +#define BIT_9 0x0200 +#define BIT_10 0x0400 +#define BIT_11 0x0800 +#define BIT_12 0x1000 +#define BIT_13 0x2000 +#define BIT_14 0x4000 +#define BIT_15 0x8000 +#define BIT_24 0x01000000 +#define BIT_28 0x10000000 + + +//------------------------------------------------------------------------- +// MDI Control register bit definitions +//------------------------------------------------------------------------- +#define MDI_DATA_MASK BIT_0_15 // MDI Data port +#define MDI_REG_ADDR BIT_16_20 // which MDI register to read/write +#define MDI_PHY_ADDR BIT_21_25 // which PHY to read/write +#define MDI_PHY_OPCODE BIT_26_27 // which PHY to read/write +#define MDI_PHY_READY BIT_28 // PHY is ready for another MDI cycle +#define MDI_PHY_INT_ENABLE BIT_29 // Assert INT at MDI cycle completion + +#define BIT_0_2 0x0007 +#define BIT_0_3 0x000F +#define BIT_0_4 0x001F +#define BIT_0_5 0x003F +#define BIT_0_6 0x007F +#define BIT_0_7 0x00FF +#define BIT_0_8 0x01FF +#define BIT_0_13 0x3FFF +#define BIT_0_15 0xFFFF +#define BIT_1_2 0x0006 +#define BIT_1_3 0x000E +#define BIT_2_5 0x003C +#define BIT_3_4 0x0018 +#define BIT_4_5 0x0030 +#define BIT_4_6 0x0070 +#define BIT_4_7 0x00F0 +#define BIT_5_7 0x00E0 +#define BIT_5_9 0x03E0 +#define BIT_5_12 0x1FE0 +#define BIT_5_15 0xFFE0 +#define BIT_6_7 0x00c0 +#define BIT_7_11 0x0F80 +#define BIT_8_10 0x0700 +#define BIT_9_13 0x3E00 +#define BIT_12_15 0xF000 + +#define BIT_16_20 0x001F0000 +#define BIT_21_25 0x03E00000 +#define BIT_26_27 0x0C000000 + +//------------------------------------------------------------------------- +// MDI Control register opcode definitions +//------------------------------------------------------------------------- +#define MDI_WRITE 1 // Phy Write +#define MDI_READ 2 // Phy read + +//------------------------------------------------------------------------- +// PHY 100 MDI Register/Bit Definitions +//------------------------------------------------------------------------- +// MDI register set +#define MDI_CONTROL_REG 0x00 // MDI control register +#define MDI_STATUS_REG 0x01 // MDI Status regiser +#define PHY_ID_REG_1 0x02 // Phy indentification reg (word 1) +#define PHY_ID_REG_2 0x03 // Phy indentification reg (word 2) +#define AUTO_NEG_ADVERTISE_REG 0x04 // Auto-negotiation advertisement +#define AUTO_NEG_LINK_PARTNER_REG 0x05 // Auto-negotiation link partner ability +#define AUTO_NEG_EXPANSION_REG 0x06 // Auto-negotiation expansion +#define AUTO_NEG_NEXT_PAGE_REG 0x07 // Auto-negotiation next page transmit +#define EXTENDED_REG_0 0x10 // Extended reg 0 (Phy 100 modes) +#define EXTENDED_REG_1 0x14 // Extended reg 1 (Phy 100 error indications) +#define NSC_CONG_CONTROL_REG 0x17 // National (TX) congestion control +#define NSC_SPEED_IND_REG 0x19 // National (TX) speed indication + +// MDI Control register bit definitions +#define MDI_CR_COLL_TEST_ENABLE BIT_7 // Collision test enable +#define MDI_CR_FULL_HALF BIT_8 // FDX =1, half duplex =0 +#define MDI_CR_RESTART_AUTO_NEG BIT_9 // Restart auto negotiation +#define MDI_CR_ISOLATE BIT_10 // Isolate PHY from MII +#define MDI_CR_POWER_DOWN BIT_11 // Power down +#define MDI_CR_AUTO_SELECT BIT_12 // Auto speed select enable +#define MDI_CR_10_100 BIT_13 // 0 = 10Mbs, 1 = 100Mbs +#define MDI_CR_LOOPBACK BIT_14 // 0 = normal, 1 = loopback +#define MDI_CR_RESET BIT_15 // 0 = normal, 1 = PHY reset + +// MDI Status register bit definitions +#define MDI_SR_EXT_REG_CAPABLE BIT_0 // Extended register capabilities +#define MDI_SR_JABBER_DETECT BIT_1 // Jabber detected +#define MDI_SR_LINK_STATUS BIT_2 // Link Status -- 1 = link +#define MDI_SR_AUTO_SELECT_CAPABLE BIT_3 // Auto speed select capable +#define MDI_SR_REMOTE_FAULT_DETECT BIT_4 // Remote fault detect +#define MDI_SR_AUTO_NEG_COMPLETE BIT_5 // Auto negotiation complete +#define MDI_SR_10T_HALF_DPX BIT_11 // 10BaseT Half Duplex capable +#define MDI_SR_10T_FULL_DPX BIT_12 // 10BaseT full duplex capable +#define MDI_SR_TX_HALF_DPX BIT_13 // TX Half Duplex capable +#define MDI_SR_TX_FULL_DPX BIT_14 // TX full duplex capable +#define MDI_SR_T4_CAPABLE BIT_15 // T4 capable + +// Auto-Negotiation advertisement register bit definitions +#define NWAY_AD_SELCTOR_FIELD BIT_0_4 // identifies supported protocol +#define NWAY_AD_ABILITY BIT_5_12 // technologies that are supported +#define NWAY_AD_10T_HALF_DPX BIT_5 // 10BaseT Half Duplex capable +#define NWAY_AD_10T_FULL_DPX BIT_6 // 10BaseT full duplex capable +#define NWAY_AD_TX_HALF_DPX BIT_7 // TX Half Duplex capable +#define NWAY_AD_TX_FULL_DPX BIT_8 // TX full duplex capable +#define NWAY_AD_T4_CAPABLE BIT_9 // T4 capable +#define NWAY_AD_REMOTE_FAULT BIT_13 // indicates local remote fault +#define NWAY_AD_RESERVED BIT_14 // reserved +#define NWAY_AD_NEXT_PAGE BIT_15 // Next page (not supported) + +// Auto-Negotiation link partner ability register bit definitions +#define NWAY_LP_SELCTOR_FIELD BIT_0_4 // identifies supported protocol +#define NWAY_LP_ABILITY BIT_5_9 // technologies that are supported +#define NWAY_LP_REMOTE_FAULT BIT_13 // indicates partner remote fault +#define NWAY_LP_ACKNOWLEDGE BIT_14 // acknowledge +#define NWAY_LP_NEXT_PAGE BIT_15 // Next page (not supported) + +// Auto-Negotiation expansion register bit definitions +#define NWAY_EX_LP_NWAY BIT_0 // link partner is NWAY +#define NWAY_EX_PAGE_RECEIVED BIT_1 // link code word received +#define NWAY_EX_NEXT_PAGE_ABLE BIT_2 // local is next page able +#define NWAY_EX_LP_NEXT_PAGE_ABLE BIT_3 // partner is next page able +#define NWAY_EX_PARALLEL_DET_FLT BIT_4 // parallel detection fault +#define NWAY_EX_RESERVED BIT_5_15 // reserved + + +// PHY 100 Extended Register 0 bit definitions +#define PHY_100_ER0_FDX_INDIC BIT_0 // 1 = FDX, 0 = half duplex +#define PHY_100_ER0_SPEED_INDIC BIT_1 // 1 = 100mbs, 0= 10mbs +#define PHY_100_ER0_WAKE_UP BIT_2 // Wake up DAC +#define PHY_100_ER0_RESERVED BIT_3_4 // Reserved +#define PHY_100_ER0_REV_CNTRL BIT_5_7 // Revsion control (A step = 000) +#define PHY_100_ER0_FORCE_FAIL BIT_8 // Force Fail is enabled +#define PHY_100_ER0_TEST BIT_9_13 // Revsion control (A step = 000) +#define PHY_100_ER0_LINKDIS BIT_14 // Link integrity test is disabled +#define PHY_100_ER0_JABDIS BIT_15 // Jabber function is disabled + + +// PHY 100 Extended Register 1 bit definitions +#define PHY_100_ER1_RESERVED BIT_0_8 // Reserved +#define PHY_100_ER1_CH2_DET_ERR BIT_9 // Channel 2 EOF detection error +#define PHY_100_ER1_MANCH_CODE_ERR BIT_10 // Manchester code error +#define PHY_100_ER1_EOP_ERR BIT_11 // EOP error +#define PHY_100_ER1_BAD_CODE_ERR BIT_12 // bad code error +#define PHY_100_ER1_INV_CODE_ERR BIT_13 // invalid code error +#define PHY_100_ER1_DC_BAL_ERR BIT_14 // DC balance error +#define PHY_100_ER1_PAIR_SKEW_ERR BIT_15 // Pair skew error + +// National Semiconductor TX phy congestion control register bit definitions +#define NSC_TX_CONG_TXREADY BIT_10 // Makes TxReady an input +#define NSC_TX_CONG_ENABLE BIT_8 // Enables congestion control +#define NSC_TX_CONG_F_CONNECT BIT_5 // Enables congestion control + +// National Semiconductor TX phy speed indication register bit definitions +#define NSC_TX_SPD_INDC_SPEED BIT_6 // 0 = 100mb, 1=10mb + +//------------------------------------------------------------------------- +// Phy related constants +//------------------------------------------------------------------------- +#define PHY_503 0 +#define PHY_100_A 0x000003E0 +#define PHY_100_C 0x035002A8 +#define PHY_TX_ID 0x015002A8 +#define PHY_NSC_TX 0x5c002000 +#define PHY_OTHER 0xFFFF + +#define PHY_MODEL_REV_ID_MASK 0xFFF0FFFF +#define PARALLEL_DETECT 0 +#define N_WAY 1 + +#define RENEGOTIATE_TIME 35 // (3.5 Seconds) + +#define CONNECTOR_AUTO 0 +#define CONNECTOR_TPE 1 +#define CONNECTOR_MII 2 + +//------------------------------------------------------------------------- + +/* The Speedo3 Rx and Tx frame/buffer descriptors. */ +#pragma pack(1) +struct CB_Header { /* A generic descriptor. */ + UINT16 status; /* Offset 0. */ + UINT16 command; /* Offset 2. */ + UINT32 link; /* struct descriptor * */ +}; + +/* transmit command block structure */ +#pragma pack(1) +typedef struct s_TxCB { + struct CB_Header cb_header; + UINT32 PhysTBDArrayAddres; /* address of an array that contains + physical TBD pointers */ + UINT16 ByteCount; /* immediate data count = 0 always */ + UINT8 Threshold; + UINT8 TBDCount; + UINT8 ImmediateData[TX_BUFFER_SIZE]; + /* following fields are not seen by the 82557 */ + struct TBD { + UINT32 phys_buf_addr; + UINT32 buf_len; + } TBDArray[MAX_XMIT_FRAGMENTS]; + UINT32 PhysArrayAddr; /* in case the one in the header is lost */ + UINT32 PhysTCBAddress; /* for this TCB */ + struct s_TxCB *NextTCBVirtualLinkPtr; + struct s_TxCB *PrevTCBVirtualLinkPtr; + UINT64 free_data_ptr; // to be given to the upper layer when this xmit completes1 +}TxCB; + +/* The Speedo3 Rx and Tx buffer descriptors. */ +#pragma pack(1) +typedef struct s_RxFD { /* Receive frame descriptor. */ + struct CB_Header cb_header; + UINT32 rx_buf_addr; /* VOID * */ + UINT16 ActualCount; + UINT16 RFDSize; + UINT8 RFDBuffer[RX_BUFFER_SIZE]; + UINT8 forwarded; + UINT8 junk[3]; +}RxFD; + +/* Elements of the RxFD.status word. */ +#define RX_COMPLETE 0x8000 +#define RX_FRAME_OK 0x2000 + +/* Elements of the dump_statistics block. This block must be lword aligned. */ +#pragma pack(1) +struct speedo_stats { + UINT32 tx_good_frames; + UINT32 tx_coll16_errs; + UINT32 tx_late_colls; + UINT32 tx_underruns; + UINT32 tx_lost_carrier; + UINT32 tx_deferred; + UINT32 tx_one_colls; + UINT32 tx_multi_colls; + UINT32 tx_total_colls; + UINT32 rx_good_frames; + UINT32 rx_crc_errs; + UINT32 rx_align_errs; + UINT32 rx_resource_errs; + UINT32 rx_overrun_errs; + UINT32 rx_colls_errs; + UINT32 rx_runt_errs; + UINT32 done_marker; +}; +#pragma pack() + + +struct Krn_Mem{ + RxFD rx_ring[RX_BUFFER_COUNT]; + TxCB tx_ring[TX_BUFFER_COUNT]; + struct speedo_stats statistics; +}; +#define MEMORY_NEEDED sizeof(struct Krn_Mem) + +/* The parameters for a CmdConfigure operation. + There are so many options that it would be difficult to document each bit. + We mostly use the default or recommended settings. +*/ + +/* + *-------------------------------------------------------------------------- + * Configuration CB Parameter Bit Definitions + *-------------------------------------------------------------------------- + */ +// - Byte 0 (Default Value = 16h) +#define CFIG_BYTE_COUNT 0x16 // 22 Configuration Bytes + +//- Byte 1 (Default Value = 88h) +#define CFIG_TXRX_FIFO_LIMIT 0x88 + +//- Byte 2 (Default Value = 0) +#define CFIG_ADAPTIVE_IFS 0 + +//- Byte 3 (Default Value = 0, ALWAYS. This byte is RESERVED) +#define CFIG_RESERVED 0 + +//- Byte 4 (Default Value = 0. Default implies that Rx DMA cannot be +//- preempted). +#define CFIG_RXDMA_BYTE_COUNT 0 + +//- Byte 5 (Default Value = 80h. Default implies that Tx DMA cannot be +//- preempted. However, setting these counters is enabled.) +#define CFIG_DMBC_ENABLE 0x80 + +//- Byte 6 (Default Value = 33h. Late SCB enabled, No TNO interrupts, +//- CNA interrupts and do not save bad frames.) +#define CFIG_LATE_SCB 1 // BIT 0 +#define CFIG_TNO_INTERRUPT 0x4 // BIT 2 +#define CFIG_CI_INTERRUPT 0x8 // BIT 3 +#define CFIG_SAVE_BAD_FRAMES 0x80 // BIT_7 + +//- Byte 7 (Default Value = 7h. Discard short frames automatically and +//- attempt upto 3 retries on transmit.) +#define CFIG_DISCARD_SHORTRX 0x00001 +#define CFIG_URUN_RETRY BIT_1 OR BIT_2 + +//- Byte 8 (Default Value = 1. Enable MII mode.) +#define CFIG_503_MII BIT_0 + +//- Byte 9 (Default Value = 0, ALWAYS) + +//- Byte 10 (Default Value = 2Eh) +#define CFIG_NSAI BIT_3 +#define CFIG_PREAMBLE_LENGTH BIT_5 ;- Bit 5-4 = 1-0 +#define CFIG_NO_LOOPBACK 0 +#define CFIG_INTERNAL_LOOPBACK BIT_6 +#define CFIG_EXT_LOOPBACK BIT_7 +#define CFIG_EXT_PIN_LOOPBACK BIT_6 OR BIT_7 + +//- Byte 11 (Default Value = 0) +#define CFIG_LINEAR_PRIORITY 0 + +//- Byte 12 (Default Value = 60h) +#define CFIG_LPRIORITY_MODE 0 +#define CFIG_IFS 6 ;- 6 * 16 = 96 + +//- Byte 13 (Default Value = 0, ALWAYS) + +//- Byte 14 (Default Value = 0F2h, ALWAYS) + +//- Byte 15 (Default Value = E8h) +#define CFIG_PROMISCUOUS_MODE BIT_0 +#define CFIG_BROADCAST_DISABLE BIT_1 +#define CFIG_CRS_CDT BIT_7 + +//- Byte 16 (Default Value = 0, ALWAYS) + +//- Byte 17 (Default Value = 40h, ALWAYS) + +//- Byte 18 (Default Value = F2h) +#define CFIG_STRIPPING BIT_0 +#define CFIG_PADDING BIT_1 +#define CFIG_RX_CRC_TRANSFER BIT_2 + +//- Byte 19 (Default Value = 80h) +#define CFIG_FORCE_FDX BIT_6 +#define CFIG_FDX_PIN_ENABLE BIT_7 + +//- Byte 20 (Default Value = 3Fh) +#define CFIG_MULTI_IA BIT_6 + +//- Byte 21 (Default Value = 05) +#define CFIG_MC_ALL BIT_3 + +/*-----------------------------------------------------------------------*/ +#define D102_REVID 0x0b + +#define HALF_DUPLEX 1 +#define FULL_DUPLEX 2 + +typedef struct s_data_instance { + + UINT16 State; // stopped, started or initialized + UINT16 Bus; + UINT8 Device; + UINT8 Function; + UINT16 VendorID; + UINT16 DeviceID; + UINT16 RevID; + UINT16 SubVendorID; + UINT16 SubSystemID; + + UINT8 PermNodeAddress[PXE_MAC_LENGTH]; + UINT8 CurrentNodeAddress[PXE_MAC_LENGTH]; + UINT8 BroadcastNodeAddress[PXE_MAC_LENGTH]; + UINT32 Config[MAX_PCI_CONFIG_LEN]; + UINT32 NVData[MAX_EEPROM_LEN]; + + UINT32 ioaddr; + UINT32 flash_addr; + + UINT16 LinkSpeed; // actual link speed setting + UINT16 LinkSpeedReq; // requested (forced) link speed + UINT8 DuplexReq; // requested duplex + UINT8 Duplex; // Duplex set + UINT8 CableDetect; // 1 to detect and 0 not to detect the cable + UINT8 LoopBack; + + UINT16 TxBufCnt; + UINT16 TxBufSize; + UINT16 RxBufCnt; + UINT16 RxBufSize; + UINT32 RxTotals; + UINT32 TxTotals; + + UINT16 int_mask; + UINT16 Int_Status; + UINT16 PhyRecord[2]; // primary and secondary PHY record registers from eeprom + UINT8 PhyAddress; + UINT8 int_num; + UINT16 NVData_Len; + UINT32 MemoryLength; + + RxFD *rx_ring; // array of rx buffers + TxCB *tx_ring; // array of tx buffers + struct speedo_stats *statistics; + TxCB *FreeTxHeadPtr; + TxCB *FreeTxTailPtr; + RxFD *RFDTailPtr; + + UINT64 rx_phy_addr; // physical addresses + UINT64 tx_phy_addr; + UINT64 stat_phy_addr; + UINT64 MemoryPtr; + UINT64 Mapped_MemoryPtr; + + UINT64 xmit_done[TX_BUFFER_COUNT << 1]; // circular buffer + UINT16 xmit_done_head; // index into the xmit_done array + UINT16 xmit_done_tail; // where are we filling now (index into xmit_done) + UINT16 cur_rx_ind; // current RX Q head index + UINT16 FreeCBCount; + + BOOLEAN in_interrupt; + BOOLEAN in_transmit; + BOOLEAN Receive_Started; + UINT8 Rx_Filter; + UINT8 VersionFlag; // UNDI30 or UNDI31?? + UINT8 rsvd[3]; + + struct mc{ + UINT16 reserved [3]; // padding for this structure to make it 8 byte aligned + UINT16 list_len; + UINT8 mc_list[MAX_MCAST_ADDRESS_CNT][PXE_MAC_LENGTH]; // 8*32 is the size + } mcast_list; + + UINT64 Unique_ID; + + EFI_PCI_IO_PROTOCOL *Io_Function; + + VOID (*Delay_30)(UINTN); // call back routine + VOID (*Virt2Phys_30)(UINT64 virtual_addr, UINT64 physical_ptr); // call back routine + VOID (*Block_30)(UINT32 enable); // call back routine + VOID (*Mem_Io_30)(UINT8 read_write, UINT8 len, UINT64 port, UINT64 buf_addr); + VOID (*Delay)(UINT64, UINTN); // call back routine + VOID (*Virt2Phys)(UINT64 unq_id, UINT64 virtual_addr, UINT64 physical_ptr); // call back routine + VOID (*Block)(UINT64 unq_id, UINT32 enable); // call back routine + VOID (*Mem_Io)(UINT64 unq_id, UINT8 read_write, UINT8 len, UINT64 port, + UINT64 buf_addr); + VOID (*Map_Mem)(UINT64 unq_id, UINT64 virtual_addr, UINT32 size, + UINT32 Direction, UINT64 mapped_addr); + VOID (*UnMap_Mem)(UINT64 unq_id, UINT64 virtual_addr, UINT32 size, + UINT32 Direction, UINT64 mapped_addr); + VOID (*Sync_Mem)(UINT64 unq_id, UINT64 virtual_addr, + UINT32 size, UINT32 Direction, UINT64 mapped_addr); +} NIC_DATA_INSTANCE; + +#pragma pack(1) +struct MC_CB_STRUCT{ + UINT16 count; + UINT8 m_list[MAX_MCAST_ADDRESS_CNT][ETHER_MAC_ADDR_LEN]; +}; +#pragma pack() + +#define FOUR_GIGABYTE (UINT64)0x100000000ULL diff --git a/EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/Init.c b/EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/Init.c new file mode 100644 index 0000000000..70982cba45 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/Init.c @@ -0,0 +1,1162 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + init.c + +Abstract: + + Initialization functions for EFI UNDI32 driver + +Revision History + +--*/ + +#include "undi32.h" + +// +// Global Variables +// +PXE_SW_UNDI *pxe = 0; // 3.0 entry point +PXE_SW_UNDI *pxe_31 = 0; // 3.1 entry +UNDI32_DEV *UNDI32DeviceList[MAX_NIC_INTERFACES]; + +NII_TABLE *UnidiDataPointer=NULL; +// +// external Global Variables +// +extern UNDI_CALL_TABLE api_table[]; + +// +// function prototypes +// +EFI_STATUS +InstallConfigTable ( + IN VOID + ); + +EFI_STATUS +EFIAPI +InitializeUNDIDriver ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +VOID +UNDI_notify_virtual ( + EFI_EVENT event, + VOID *context + ); + +VOID +EFIAPI +UndiNotifyExitBs ( + EFI_EVENT Event, + VOID *Context + ); + +EFI_STATUS +EFIAPI +UndiDriverSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +UndiDriverStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +UndiDriverStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +EFI_STATUS +AppendMac2DevPath ( + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevPtr, + IN EFI_DEVICE_PATH_PROTOCOL *BaseDevPtr, + IN NIC_DATA_INSTANCE *AdapterInfo + ); +// +// end function prototypes +// +VOID +EFIAPI +UndiNotifyVirtual ( + EFI_EVENT Event, + VOID *Context + ) +/*++ + +Routine Description: + + When address mapping changes to virtual this should make the appropriate + address conversions. + +Arguments: + + (Standard Event handler) + +Returns: + + None + +--*/ +// TODO: Context - add argument and description to function comment +{ + UINT16 Index; + VOID *Pxe31Pointer; + + if (pxe_31 != NULL) { + Pxe31Pointer = (VOID *) pxe_31; + + EfiConvertPointer ( + EFI_OPTIONAL_POINTER, + (void **) &Pxe31Pointer + ); + + // + // UNDI32DeviceList is an array of pointers + // + for (Index = 0; Index < pxe_31->IFcnt; Index++) { + UNDI32DeviceList[Index]->NIIProtocol_31.ID = (UINT64) (UINTN) Pxe31Pointer; + EfiConvertPointer ( + EFI_OPTIONAL_POINTER, + (void **) &(UNDI32DeviceList[Index]) + ); + } + + EfiConvertPointer ( + EFI_OPTIONAL_POINTER, + (void **) &(pxe_31->EntryPoint) + ); + pxe_31 = Pxe31Pointer; + } + + for (Index = 0; Index <= PXE_OPCODE_LAST_VALID; Index++) { + EfiConvertPointer ( + EFI_OPTIONAL_POINTER, + (void **) &api_table[Index].api_ptr + ); + } +} + +VOID +EFIAPI +UndiNotifyExitBs ( + EFI_EVENT Event, + VOID *Context + ) +/*++ + +Routine Description: + + When EFI is shuting down the boot services, we need to install a + configuration table for UNDI to work at runtime! + +Arguments: + + (Standard Event handler) + +Returns: + + None + +--*/ +// TODO: Context - add argument and description to function comment +{ + InstallConfigTable (); +} +// +// UNDI Class Driver Global Variables +// +EFI_DRIVER_BINDING_PROTOCOL gUndiDriverBinding = { + UndiDriverSupported, + UndiDriverStart, + UndiDriverStop, + 0x10, + NULL, + NULL +}; + +EFI_STATUS +EFIAPI +InitializeUNDIDriver ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Register Driver Binding protocol for this driver. + +Arguments: + + ImageHandle - Image Handle + + SystemTable - Pointer to system table + +Returns: + + EFI_SUCCESS - Driver loaded. + + other - Driver not loaded. + +--*/ +{ + EFI_STATUS Status; + EFI_EVENT Event; + + Status = gBS->CreateEvent ( + EFI_EVENT_SIGNAL_EXIT_BOOT_SERVICES, + EFI_TPL_NOTIFY, + UndiNotifyExitBs, + NULL, + &Event + ); + + return Status; +} + +EFI_STATUS +EFIAPI +UndiDriverSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + Test to see if this driver supports ControllerHandle. Any ControllerHandle + than contains a DevicePath, PciIo protocol, Class code of 2, Vendor ID of 0x8086, + and DeviceId of (D100_DEVICE_ID || D102_DEVICE_ID || ICH3_DEVICE_ID_1 || + ICH3_DEVICE_ID_2 || ICH3_DEVICE_ID_3 || ICH3_DEVICE_ID_4 || ICH3_DEVICE_ID_5 || + ICH3_DEVICE_ID_6 || ICH3_DEVICE_ID_7 || ICH3_DEVICE_ID_8) can be supported. + +Arguments: + + This - Protocol instance pointer. + + Controller - Handle of device to test. + + RemainingDevicePath - Not used. + +Returns: + + EFI_SUCCESS - This driver supports this device. + + other - This driver does not support this device. + +--*/ +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + PCI_TYPE00 Pci; + + Status = gBS->OpenProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + NULL, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint8, + 0, + sizeof (PCI_CONFIG_HEADER), + &Pci + ); + + if (!EFI_ERROR (Status)) { + Status = EFI_UNSUPPORTED; + + if (Pci.Hdr.ClassCode[2] == 0x02 && Pci.Hdr.VendorId == PCI_VENDOR_ID_INTEL) { + switch (Pci.Hdr.DeviceId) { + case D100_DEVICE_ID: + case D102_DEVICE_ID: + case ICH3_DEVICE_ID_1: + case ICH3_DEVICE_ID_2: + case ICH3_DEVICE_ID_3: + case ICH3_DEVICE_ID_4: + case ICH3_DEVICE_ID_5: + case ICH3_DEVICE_ID_6: + case ICH3_DEVICE_ID_7: + case ICH3_DEVICE_ID_8: + case 0x1039: + case 0x103A: + case 0x103B: + case 0x103C: + case 0x103D: + case 0x103E: + case 0x1050: + case 0x1051: + case 0x1052: + case 0x1053: + case 0x1054: + case 0x1055: + case 0x1056: + case 0x1057: + case 0x1059: + case 0x1064: + Status = EFI_SUCCESS; + } + } + } + + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return Status; +} + +EFI_STATUS +EFIAPI +UndiDriverStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + Start this driver on Controller by opening PciIo and DevicePath protocol. + Initialize PXE structures, create a copy of the Controller Device Path with the + NIC's MAC address appended to it, install the NetworkInterfaceIdentifier protocol + on the newly created Device Path. + +Arguments: + + This - Protocol instance pointer. + + Controller - Handle of device to work with. + + RemainingDevicePath - Not used, always produce all possible children. + +Returns: + + EFI_SUCCESS - This driver is added to Controller. + + other - This driver does not support this device. + +--*/ +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *UndiDevicePath; + PCI_CONFIG_HEADER *CfgHdr; + UNDI32_DEV *UNDI32Device; + UINT16 NewCommand; + UINT8 *TmpPxePointer; + EFI_PCI_IO_PROTOCOL *PciIoFncs; + UINTN Len; + + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIoFncs, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->OpenProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &UndiDevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return Status; + } + + Status = gBS->AllocatePool ( + EfiRuntimeServicesData, + sizeof (UNDI32_DEV), + (VOID **) &UNDI32Device + ); + + if (EFI_ERROR (Status)) { + goto UndiError; + } + + ZeroMem ((CHAR8 *) UNDI32Device, sizeof (UNDI32_DEV)); + + // + // allocate and initialize both (old and new) the !pxe structures here, + // there should only be one copy of each of these structure for any number + // of NICs this undi supports. Also, these structures need to be on a + // paragraph boundary as per the spec. so, while allocating space for these, + // make sure that there is space for 2 !pxe structures (old and new) and a + // 32 bytes padding for alignment adjustment (in case) + // + TmpPxePointer = NULL; + if (pxe_31 == NULL) { + Status = gBS->AllocatePool ( + EfiRuntimeServicesData, + (sizeof (PXE_SW_UNDI) + sizeof (PXE_SW_UNDI) + 32), + (VOID **) &TmpPxePointer + ); + + if (EFI_ERROR (Status)) { + goto UndiErrorDeleteDevice; + } + + ZeroMem ( + TmpPxePointer, + sizeof (PXE_SW_UNDI) + sizeof (PXE_SW_UNDI) + 32 + ); + // + // check for paragraph alignment here, assuming that the pointer is + // already 8 byte aligned. + // + if (((UINTN) TmpPxePointer & 0x0F) != 0) { + pxe_31 = (PXE_SW_UNDI *) ((UINTN) (TmpPxePointer + 8)); + } else { + pxe_31 = (PXE_SW_UNDI *) TmpPxePointer; + } + // + // assuming that the sizeof pxe_31 is a 16 byte multiple + // + pxe = (PXE_SW_UNDI *) ((CHAR8 *) (pxe_31) + sizeof (PXE_SW_UNDI)); + + PxeStructInit (pxe, 0x30); + PxeStructInit (pxe_31, 0x31); + } + + UNDI32Device->NIIProtocol.ID = (UINT64) (UINTN) (pxe); + UNDI32Device->NIIProtocol_31.ID = (UINT64) (UINTN) (pxe_31); + + Status = PciIoFncs->Attributes ( + PciIoFncs, + EfiPciIoAttributeOperationEnable, + EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER, + NULL + ); + // + // Read all the registers from device's PCI Configuration space + // + Status = PciIoFncs->Pci.Read ( + PciIoFncs, + EfiPciIoWidthUint32, + 0, + MAX_PCI_CONFIG_LEN, + &UNDI32Device->NicInfo.Config + ); + + CfgHdr = (PCI_CONFIG_HEADER *) &(UNDI32Device->NicInfo.Config[0]); + + // + // make sure that this device is a PCI bus master + // + + NewCommand = (UINT16) (CfgHdr->Command | PCI_COMMAND_MASTER | PCI_COMMAND_IO); + if (CfgHdr->Command != NewCommand) { + PciIoFncs->Pci.Write ( + PciIoFncs, + EfiPciIoWidthUint16, + PCI_COMMAND, + 1, + &NewCommand + ); + CfgHdr->Command = NewCommand; + } + + // + // make sure that the latency timer is at least 32 + // + if (CfgHdr->LatencyTimer < 32) { + CfgHdr->LatencyTimer = 32; + PciIoFncs->Pci.Write ( + PciIoFncs, + EfiPciIoWidthUint8, + PCI_LATENCY_TIMER, + 1, + &CfgHdr->LatencyTimer + ); + } + // + // the IfNum index for the current interface will be the total number + // of interfaces initialized so far + // + UNDI32Device->NIIProtocol.IfNum = pxe->IFcnt; + UNDI32Device->NIIProtocol_31.IfNum = pxe_31->IFcnt; + + PxeUpdate (&UNDI32Device->NicInfo, pxe); + PxeUpdate (&UNDI32Device->NicInfo, pxe_31); + + UNDI32Device->NicInfo.Io_Function = PciIoFncs; + UNDI32DeviceList[UNDI32Device->NIIProtocol.IfNum] = UNDI32Device; + UNDI32Device->Undi32BaseDevPath = UndiDevicePath; + + Status = AppendMac2DevPath ( + &UNDI32Device->Undi32DevPath, + UNDI32Device->Undi32BaseDevPath, + &UNDI32Device->NicInfo + ); + + if (Status != 0) { + goto UndiErrorDeletePxe; + } + + UNDI32Device->Signature = UNDI_DEV_SIGNATURE; + + UNDI32Device->NIIProtocol.Revision = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION; + UNDI32Device->NIIProtocol.Type = EfiNetworkInterfaceUndi; + UNDI32Device->NIIProtocol.MajorVer = PXE_ROMID_MAJORVER; + UNDI32Device->NIIProtocol.MinorVer = PXE_ROMID_MINORVER; + UNDI32Device->NIIProtocol.ImageSize = 0; + UNDI32Device->NIIProtocol.ImageAddr = 0; + UNDI32Device->NIIProtocol.Ipv6Supported = FALSE; + + UNDI32Device->NIIProtocol.StringId[0] = 'U'; + UNDI32Device->NIIProtocol.StringId[1] = 'N'; + UNDI32Device->NIIProtocol.StringId[2] = 'D'; + UNDI32Device->NIIProtocol.StringId[3] = 'I'; + + UNDI32Device->NIIProtocol_31.Revision = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION_31; + UNDI32Device->NIIProtocol_31.Type = EfiNetworkInterfaceUndi; + UNDI32Device->NIIProtocol_31.MajorVer = PXE_ROMID_MAJORVER; + UNDI32Device->NIIProtocol_31.MinorVer = PXE_ROMID_MINORVER_31; + UNDI32Device->NIIProtocol_31.ImageSize = 0; + UNDI32Device->NIIProtocol_31.ImageAddr = 0; + UNDI32Device->NIIProtocol_31.Ipv6Supported = FALSE; + + UNDI32Device->NIIProtocol_31.StringId[0] = 'U'; + UNDI32Device->NIIProtocol_31.StringId[1] = 'N'; + UNDI32Device->NIIProtocol_31.StringId[2] = 'D'; + UNDI32Device->NIIProtocol_31.StringId[3] = 'I'; + + UNDI32Device->DeviceHandle = NULL; + + // + // install both the 3.0 and 3.1 NII protocols. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &UNDI32Device->DeviceHandle, + &gEfiNetworkInterfaceIdentifierProtocolGuid_31, + &UNDI32Device->NIIProtocol_31, + &gEfiNetworkInterfaceIdentifierProtocolGuid, + &UNDI32Device->NIIProtocol, + &gEfiDevicePathProtocolGuid, + UNDI32Device->Undi32DevPath, + NULL + ); + + if (EFI_ERROR (Status)) { + goto UndiErrorDeleteDevicePath; + } + + // + // if the table exists, free it and alloc again, or alloc it directly + // + if (UnidiDataPointer != NULL) { + Status = gBS->FreePool(UnidiDataPointer); + } + if (EFI_ERROR (Status)) { + goto UndiErrorDeleteDevicePath; + } + + Len = (pxe_31->IFcnt * sizeof (NII_ENTRY)) + sizeof (UnidiDataPointer); + Status = gBS->AllocatePool (EfiRuntimeServicesData, Len, (VOID **) &UnidiDataPointer); + + if (EFI_ERROR (Status)) { + goto UndiErrorAllocDataPointer; + } + + // + // Open For Child Device + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIoFncs, + This->DriverBindingHandle, + UNDI32Device->DeviceHandle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + + return EFI_SUCCESS; +UndiErrorAllocDataPointer: + gBS->UninstallMultipleProtocolInterfaces ( + &UNDI32Device->DeviceHandle, + &gEfiNetworkInterfaceIdentifierProtocolGuid_31, + &UNDI32Device->NIIProtocol_31, + &gEfiNetworkInterfaceIdentifierProtocolGuid, + &UNDI32Device->NIIProtocol, + &gEfiDevicePathProtocolGuid, + UNDI32Device->Undi32DevPath, + NULL + ); + +UndiErrorDeleteDevicePath: + UNDI32DeviceList[UNDI32Device->NIIProtocol.IfNum] = NULL; + gBS->FreePool (UNDI32Device->Undi32DevPath); + +UndiErrorDeletePxe: + PxeUpdate (NULL, pxe); + PxeUpdate (NULL, pxe_31); + if (TmpPxePointer != NULL) { + gBS->FreePool (TmpPxePointer); + + } + +UndiErrorDeleteDevice: + gBS->FreePool (UNDI32Device); + +UndiError: + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return Status; +} + +EFI_STATUS +EFIAPI +UndiDriverStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + +Routine Description: + Stop this driver on Controller by removing NetworkInterfaceIdentifier protocol and + closing the DevicePath and PciIo protocols on Controller. + +Arguments: + This - Protocol instance pointer. + Controller - Handle of device to stop driver on. + NumberOfChildren - How many children need to be stopped. + ChildHandleBuffer - Not used. + +Returns: + EFI_SUCCESS - This driver is removed Controller. + other - This driver was not removed from this device. + +--*/ +// TODO: EFI_DEVICE_ERROR - add return value to function comment +{ + EFI_STATUS Status; + BOOLEAN AllChildrenStopped; + UINTN Index; + UNDI32_DEV *UNDI32Device; + EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NIIProtocol; + EFI_PCI_IO_PROTOCOL *PciIo; + + // + // Complete all outstanding transactions to Controller. + // Don't allow any new transaction to Controller to be started. + // + if (NumberOfChildren == 0) { + + // + // Close the bus driver + // + Status = gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + Status = gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return Status; + } + + AllChildrenStopped = TRUE; + + for (Index = 0; Index < NumberOfChildren; Index++) { + + Status = gBS->OpenProtocol ( + ChildHandleBuffer[Index], + &gEfiNetworkInterfaceIdentifierProtocolGuid, + (VOID **) &NIIProtocol, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + + UNDI32Device = UNDI_DEV_FROM_THIS (NIIProtocol); + + Status = gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + ChildHandleBuffer[Index] + ); + + Status = gBS->UninstallMultipleProtocolInterfaces ( + ChildHandleBuffer[Index], + &gEfiDevicePathProtocolGuid, + UNDI32Device->Undi32DevPath, + &gEfiNetworkInterfaceIdentifierProtocolGuid_31, + &UNDI32Device->NIIProtocol_31, + &gEfiNetworkInterfaceIdentifierProtocolGuid, + &UNDI32Device->NIIProtocol, + NULL + ); + + if (EFI_ERROR (Status)) { + gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + ChildHandleBuffer[Index], + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + } else { + gBS->FreePool (UNDI32Device->Undi32DevPath); + gBS->FreePool (UNDI32Device); + } + } + + if (EFI_ERROR (Status)) { + AllChildrenStopped = FALSE; + } + } + + if (!AllChildrenStopped) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; + +} + +VOID +TmpDelay ( + IN UINT64 UnqId, + IN UINTN MicroSeconds + ) +/*++ + +Routine Description: + + Use the EFI boot services to produce a pause. This is also the routine which + gets replaced during RunTime by the O/S in the NIC_DATA_INSTANCE so it can + do it's own pause. + +Arguments: + + UnqId - Runtime O/S routine might use this, this temp routine does not use it + + MicroSeconds - Determines the length of pause. + +Returns: + + none + +--*/ +{ + gBS->Stall ((UINT32) MicroSeconds); +} + +VOID +TmpMemIo ( + IN UINT64 UnqId, + IN UINT8 ReadWrite, + IN UINT8 Len, + IN UINT64 Port, + IN UINT64 BuffAddr + ) +/*++ + +Routine Description: + + Use the PCI IO abstraction to issue memory or I/O reads and writes. This is also the routine which + gets replaced during RunTime by the O/S in the NIC_DATA_INSTANCE so it can do it's own I/O abstractions. + +Arguments: + + UnqId - Runtime O/S routine may use this field, this temp routine does not. + + ReadWrite - Determine if it is an I/O or Memory Read/Write Operation. + + Len - Determines the width of the data operation. + + Port - What port to Read/Write from. + + BuffAddr - Address to read to or write from. + +Returns: + + none + +--*/ +{ + EFI_PCI_IO_PROTOCOL_WIDTH Width; + NIC_DATA_INSTANCE *AdapterInfo; + + Width = 0; + AdapterInfo = (NIC_DATA_INSTANCE *) (UINTN) UnqId; + switch (Len) { + case 2: + Width = 1; + break; + + case 4: + Width = 2; + break; + + case 8: + Width = 3; + break; + } + + switch (ReadWrite) { + case PXE_IO_READ: + AdapterInfo->Io_Function->Io.Read ( + AdapterInfo->Io_Function, + Width, + 1, + Port, + 1, + (VOID *) (UINTN) (BuffAddr) + ); + break; + + case PXE_IO_WRITE: + AdapterInfo->Io_Function->Io.Write ( + AdapterInfo->Io_Function, + Width, + 1, + Port, + 1, + (VOID *) (UINTN) (BuffAddr) + ); + break; + + case PXE_MEM_READ: + AdapterInfo->Io_Function->Mem.Read ( + AdapterInfo->Io_Function, + Width, + 0, + Port, + 1, + (VOID *) (UINTN) (BuffAddr) + ); + break; + + case PXE_MEM_WRITE: + AdapterInfo->Io_Function->Mem.Write ( + AdapterInfo->Io_Function, + Width, + 0, + Port, + 1, + (VOID *) (UINTN) (BuffAddr) + ); + break; + } + + return ; +} + +EFI_STATUS +AppendMac2DevPath ( + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevPtr, + IN EFI_DEVICE_PATH_PROTOCOL *BaseDevPtr, + IN NIC_DATA_INSTANCE *AdapterInfo + ) +/*++ + +Routine Description: + + Using the NIC data structure information, read the EEPROM to get the MAC address and then allocate space + for a new devicepath (**DevPtr) which will contain the original device path the NIC was found on (*BaseDevPtr) + and an added MAC node. + +Arguments: + + DevPtr - Pointer which will point to the newly created device path with the MAC node attached. + + BaseDevPtr - Pointer to the device path which the UNDI device driver is latching on to. + + AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on.. + +Returns: + + EFI_SUCCESS - A MAC address was successfully appended to the Base Device Path. + + other - Not enough resources available to create new Device Path node. + +--*/ +{ + EFI_MAC_ADDRESS MACAddress; + PCI_CONFIG_HEADER *CfgHdr; + INT32 Val; + INT32 Index; + INT32 Index2; + UINT8 AddrLen; + MAC_ADDR_DEVICE_PATH MacAddrNode; + EFI_DEVICE_PATH_PROTOCOL *EndNode; + UINT8 *DevicePtr; + UINT16 TotalPathLen; + UINT16 BasePathLen; + EFI_STATUS Status; + + // + // set the environment ready (similar to UNDI_Start call) so that we can + // execute the other UNDI_ calls to get the mac address + // we are using undi 3.1 style + // + AdapterInfo->Delay = TmpDelay; + AdapterInfo->Virt2Phys = (VOID *) 0; + AdapterInfo->Block = (VOID *) 0; + AdapterInfo->Map_Mem = (VOID *) 0; + AdapterInfo->UnMap_Mem = (VOID *) 0; + AdapterInfo->Sync_Mem = (VOID *) 0; + AdapterInfo->Mem_Io = TmpMemIo; + // + // these tmp call-backs follow 3.1 undi style + // i.e. they have the unique_id parameter. + // + AdapterInfo->VersionFlag = 0x31; + AdapterInfo->Unique_ID = (UINT64) (UINTN) AdapterInfo; + + // + // undi init portion + // + CfgHdr = (PCI_CONFIG_HEADER *) &(AdapterInfo->Config[0]); + AdapterInfo->ioaddr = 0; + AdapterInfo->RevID = CfgHdr->RevID; + + AddrLen = E100bGetEepromAddrLen (AdapterInfo); + + for (Index = 0, Index2 = 0; Index < 3; Index++) { + Val = E100bReadEeprom (AdapterInfo, Index, AddrLen); + MACAddress.Addr[Index2++] = (UINT8) Val; + MACAddress.Addr[Index2++] = (UINT8) (Val >> 8); + } + + SetMem (MACAddress.Addr + Index2, sizeof (EFI_MAC_ADDRESS) - Index2, 0); + //for (; Index2 < sizeof (EFI_MAC_ADDRESS); Index2++) { + // MACAddress.Addr[Index2] = 0; + //} + // + // stop undi + // + AdapterInfo->Delay = (VOID *) 0; + AdapterInfo->Mem_Io = (VOID *) 0; + + // + // fill the mac address node first + // + ZeroMem ((CHAR8 *) &MacAddrNode, sizeof MacAddrNode); + CopyMem ( + (CHAR8 *) &MacAddrNode.MacAddress, + (CHAR8 *) &MACAddress, + sizeof (EFI_MAC_ADDRESS) + ); + + MacAddrNode.Header.Type = MESSAGING_DEVICE_PATH; + MacAddrNode.Header.SubType = MSG_MAC_ADDR_DP; + MacAddrNode.Header.Length[0] = sizeof (MacAddrNode); + MacAddrNode.Header.Length[1] = 0; + + // + // find the size of the base dev path. + // + EndNode = BaseDevPtr; + + while (!IsDevicePathEnd (EndNode)) { + EndNode = NextDevicePathNode (EndNode); + } + + BasePathLen = (UINT16) ((UINTN) (EndNode) - (UINTN) (BaseDevPtr)); + + // + // create space for full dev path + // + TotalPathLen = (UINT16) (BasePathLen + sizeof (MacAddrNode) + sizeof (EFI_DEVICE_PATH_PROTOCOL)); + + Status = gBS->AllocatePool ( + EfiRuntimeServicesData, + TotalPathLen, + (VOID **) &DevicePtr + ); + + if (Status != EFI_SUCCESS) { + return Status; + } + // + // copy the base path, mac addr and end_dev_path nodes + // + *DevPtr = (EFI_DEVICE_PATH_PROTOCOL *) DevicePtr; + CopyMem (DevicePtr, (CHAR8 *) BaseDevPtr, BasePathLen); + DevicePtr += BasePathLen; + CopyMem (DevicePtr, (CHAR8 *) &MacAddrNode, sizeof (MacAddrNode)); + DevicePtr += sizeof (MacAddrNode); + CopyMem (DevicePtr, (CHAR8 *) EndNode, sizeof (EFI_DEVICE_PATH_PROTOCOL)); + + return EFI_SUCCESS; +} + +EFI_STATUS +InstallConfigTable ( + IN VOID + ) +/*++ + +Routine Description: + + Install a GUID/Pointer pair into the system's configuration table. + +Arguments: + + none + +Returns: + + EFI_SUCCESS - Install a GUID/Pointer pair into the system's configuration table. + + other - Did not successfully install the GUID/Pointer pair into the configuration table. + +--*/ +// TODO: VOID - add argument and description to function comment +{ + EFI_STATUS Status; + EFI_CONFIGURATION_TABLE *CfgPtr; + NII_TABLE *TmpData; + UINT16 Index; + NII_TABLE *UndiData; + + if (pxe_31 == NULL) { + return EFI_SUCCESS; + } + + if(UnidiDataPointer == NULL) { + return EFI_SUCCESS; + } + + UndiData = (NII_TABLE *)UnidiDataPointer; + + UndiData->NumEntries = pxe_31->IFcnt; + UndiData->NextLink = NULL; + + for (Index = 0; Index < pxe_31->IFcnt; Index++) { + UndiData->NiiEntry[Index].InterfacePointer = &UNDI32DeviceList[Index]->NIIProtocol_31; + UndiData->NiiEntry[Index].DevicePathPointer = UNDI32DeviceList[Index]->Undi32DevPath; + } + + // + // see if there is an entry in the config table already + // + CfgPtr = gST->ConfigurationTable; + + for (Index = 0; Index < gST->NumberOfTableEntries; Index++) { + Status = CompareGuid ( + &CfgPtr->VendorGuid, + &gEfiNetworkInterfaceIdentifierProtocolGuid_31 + ); + if (Status != EFI_SUCCESS) { + break; + } + + CfgPtr++; + } + + if (Index < gST->NumberOfTableEntries) { + TmpData = (NII_TABLE *) CfgPtr->VendorTable; + + // + // go to the last link + // + while (TmpData->NextLink != NULL) { + TmpData = TmpData->NextLink; + } + + TmpData->NextLink = UndiData; + + // + // 1st one in chain + // + UndiData = (NII_TABLE *) CfgPtr->VendorTable; + } + + // + // create an entry in the configuration table for our GUID + // + Status = gBS->InstallConfigurationTable ( + &gEfiNetworkInterfaceIdentifierProtocolGuid_31, + UndiData + ); + return Status; +} diff --git a/EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/Undi.mbd b/EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/Undi.mbd new file mode 100644 index 0000000000..d486d63165 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/Undi.mbd @@ -0,0 +1,47 @@ + + + + + Undi + A1f436EA-A127-4EF8-957C-8048606FF670 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:18 + + + UefiBootServicesTableLib + BaseLib + BaseMemoryLib + UefiLib + UefiDriverEntryPoint + DxeReportStatusCodeLib + BaseDebugLibNull + BasePrintLib + EdkDxeRuntimeDriverLib + UefiDriverModelLib + DxeHobLib + DxeMemoryAllocationLib + + EdkDxeSalLib + + + diff --git a/EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/Undi.msa b/EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/Undi.msa new file mode 100644 index 0000000000..dcf0238680 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/Undi.msa @@ -0,0 +1,92 @@ + + + + + Undi + DXE_RUNTIME_DRIVER + RT_DRIVER + A1f436EA-A127-4EF8-957C-8048606FF670 + 0 + Component description file for DiskIo module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:18 + + + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + BaseLib + DxeRuntimeDriverLib + DebugLib + HobLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + + + Init.c + Decode.c + E100b.c + E100b.h + Undi32.h + + + MdePkg + EdkModulePkg + + + DevicePath + PciIo + NetworkInterfaceIdentifier + NetworkInterfaceIdentifier31 + + + + + gEfiEventVirtualAddressChangeGuid + 0x13fa7698, 0xc831, 0x49c7, 0x87, 0xea, 0x8f, 0x43, 0xfc, 0xc2, 0x51, 0x96 + + + gEfiEventExitBootServicesGuid + 0x27abf055, 0xb1b8, 0x4c26, 0x80, 0x48, 0x74, 0x8f, 0x37, 0xba, 0xa2, 0xdf + + + + + + gEfiNetworkInterfaceIdentifierProtocolGuid_31 + + + + + InitializeUNDIDriver + + + gUndiDriverBinding + + + UndiNotifyVirtual + + + + diff --git a/EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/Undi32.h b/EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/Undi32.h new file mode 100644 index 0000000000..5e0044398f --- /dev/null +++ b/EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/Undi32.h @@ -0,0 +1,208 @@ + +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + undi32.h + +Abstract: + + EFI internal structures for the EFI UNDI driver + + + +Revision History + +--*/ + +#ifndef _UNDI_32_H_ +#define _UNDI_32_H_ + + +#include "E100b.h" +#include + +#define MAX_NIC_INTERFACES 16 + +#define EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION_31 0x00010001 +#define PXE_ROMID_MINORVER_31 0x10 +#define PXE_STATFLAGS_DB_WRITE_TRUNCATED 0x2000 + +// +// UNDI_CALL_TABLE.state can have the following values +// +#define DONT_CHECK -1 +#define ANY_STATE -1 +#define MUST_BE_STARTED 1 +#define MUST_BE_INITIALIZED 2 + +#define UNDI_DEV_SIGNATURE EFI_SIGNATURE_32('u','n','d','i') +#define UNDI_DEV_FROM_THIS(a) CR(a, UNDI32_DEV, NIIProtocol, UNDI_DEV_SIGNATURE) +#define UNDI_DEV_FROM_NIC(a) CR(a, UNDI32_DEV, NicInfo, UNDI_DEV_SIGNATURE) + +typedef struct { + UINTN Signature; + EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL NIIProtocol; + EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL NIIProtocol_31; + EFI_HANDLE DeviceHandle; + EFI_DEVICE_PATH_PROTOCOL *Undi32BaseDevPath; + EFI_DEVICE_PATH_PROTOCOL *Undi32DevPath; + NIC_DATA_INSTANCE NicInfo; +} UNDI32_DEV; + +typedef struct { + UINT16 cpbsize; + UINT16 dbsize; + UINT16 opflags; + UINT16 state; + VOID (*api_ptr)(); +} UNDI_CALL_TABLE; + +typedef struct { + EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *InterfacePointer; + EFI_DEVICE_PATH_PROTOCOL *DevicePathPointer; +} NII_ENTRY; + +typedef struct NII_CONFIG_ENTRY { + UINT32 NumEntries; + UINT32 Reserved; // padding for alignment + struct NII_CONFIG_ENTRY *NextLink; + NII_ENTRY NiiEntry[1]; +} NII_TABLE; + +typedef VOID (*ptr)(VOID); +typedef VOID (*bsptr_30)(UINTN); +typedef VOID (*virtphys_30)(UINT64, UINT64); +typedef VOID (*block_30)(UINT32); +typedef VOID (*mem_io_30)(UINT8, UINT8, UINT64, UINT64); + +typedef VOID (*bsptr)(UINT64, UINTN); +typedef VOID (*virtphys)(UINT64, UINT64, UINT64); +typedef VOID (*block)(UINT64, UINT32); +typedef VOID (*mem_io)(UINT64, UINT8, UINT8, UINT64, UINT64); + +typedef VOID (*map_mem)(UINT64, UINT64, UINT32, UINT32, UINT64); +typedef VOID (*unmap_mem)(UINT64, UINT64, UINT32, UINT32, UINT64); +typedef VOID (*sync_mem)(UINT64, UINT64, UINT32, UINT32, UINT64); + +// +// functions defined in e100b.c +// +UINT8 InByte (NIC_DATA_INSTANCE *AdapterInfo, UINT32 Port); +UINT16 InWord (NIC_DATA_INSTANCE *AdapterInfo, UINT32 Port); +UINT32 InLong (NIC_DATA_INSTANCE *AdapterInfo, UINT32 Port); +VOID OutByte (NIC_DATA_INSTANCE *AdapterInfo, UINT8 Data, UINT32 Port); +VOID OutWord (NIC_DATA_INSTANCE *AdapterInfo, UINT16 Data, UINT32 Port); +VOID OutLong (NIC_DATA_INSTANCE *AdapterInfo, UINT32 Data, UINT32 Port); + +UINTN E100bInit (NIC_DATA_INSTANCE *AdapterInfo); +UINTN E100bReset (NIC_DATA_INSTANCE *AdapterInfo, INT32 OpFlags); +UINTN E100bShutdown (NIC_DATA_INSTANCE *AdapterInfo); +UINTN E100bTransmit (NIC_DATA_INSTANCE *AdapterInfo, UINT64 cpb, UINT16 opflags); +UINTN E100bReceive (NIC_DATA_INSTANCE *AdapterInfo, UINT64 cpb, UINT64 db); +UINTN E100bSetfilter (NIC_DATA_INSTANCE *AdapterInfo, UINT16 New_filter, + UINT64 cpb, UINT32 cpbsize); +UINTN E100bStatistics(NIC_DATA_INSTANCE *AdapterInfo, UINT64 db, UINT16 dbsize); +UINT8 E100bSetupIAAddr (NIC_DATA_INSTANCE *AdapterInfo); +UINT8 E100bSetInterruptState (NIC_DATA_INSTANCE *AdapterInfo); + +UINT8 E100bGetEepromAddrLen (NIC_DATA_INSTANCE *AdapterInfo); +UINT16 E100bReadEeprom (NIC_DATA_INSTANCE *AdapterInfo, INT32 Location, UINT8 address_len); +INT16 E100bReadEepromAndStationAddress (NIC_DATA_INSTANCE *AdapterInfo); + +UINT16 next(UINT16); +UINT8 SetupCBlink (NIC_DATA_INSTANCE *AdapterInfo); +VOID SetFreeCB (NIC_DATA_INSTANCE *AdapterInfo,TxCB *); +TxCB *GetFreeCB (NIC_DATA_INSTANCE *AdapterInfo); +UINT16 CheckCBList (NIC_DATA_INSTANCE *AdapterInfo); + +UINT8 SelectiveReset (NIC_DATA_INSTANCE *AdapterInfo); +UINT16 InitializeChip (NIC_DATA_INSTANCE *AdapterInfo); +UINT8 SetupReceiveQueues (NIC_DATA_INSTANCE *AdapterInfo); +VOID Recycle_RFD (NIC_DATA_INSTANCE *AdapterInfo, UINT16); +VOID XmitWaitForCompletion (NIC_DATA_INSTANCE *AdapterInfo); +INT8 CommandWaitForCompletion (TxCB *cmd_ptr, NIC_DATA_INSTANCE *AdapterInfo); + +BOOLEAN PhyDetect (NIC_DATA_INSTANCE *AdapterInfo); +VOID PhyReset (NIC_DATA_INSTANCE *AdapterInfo); +VOID +MdiWrite ( + IN NIC_DATA_INSTANCE *AdapterInfo, + IN UINT8 RegAddress, + IN UINT8 PhyAddress, + IN UINT16 DataValue + ); + +VOID +MdiRead( + IN NIC_DATA_INSTANCE *AdapterInfo, + IN UINT8 RegAddress, + IN UINT8 PhyAddress, + IN OUT UINT16 *DataValue + ); + +BOOLEAN SetupPhy (NIC_DATA_INSTANCE *AdapterInfo); +VOID FindPhySpeedAndDpx (NIC_DATA_INSTANCE *AdapterInfo, UINT32 PhyId); + + + +// +// functions defined in init.c +// +VOID +TmpDelay ( + IN UINT64 UnqId, + IN UINTN MicroSeconds + ); + +VOID +TmpMemIo ( + IN UINT64 UnqId, + IN UINT8 ReadWrite, + IN UINT8 Len, + IN UINT64 Port, + IN UINT64 BufAddr + ); + +// +// functions defined in decode.c +// +VOID UNDI_GetState(); +VOID UNDI_Start(); +VOID UNDI_Stop(); +VOID UNDI_GetInitInfo(); +VOID UNDI_GetConfigInfo(); +VOID UNDI_Initialize(); +VOID UNDI_Reset(); +VOID UNDI_Shutdown(); +VOID UNDI_Interrupt(); +VOID UNDI_RecFilter(); +VOID UNDI_StnAddr(); +VOID UNDI_Statistics(); +VOID UNDI_ip2mac(); +VOID UNDI_NVData(); +VOID UNDI_Status(); +VOID UNDI_FillHeader(); +VOID UNDI_Transmit(); +VOID UNDI_Receive(); + +VOID UNDI_APIEntry_new(UINT64); +VOID UNDI_APIEntry_old(UINT64); +VOID UNDI_APIEntry_Common(UINT64); + +PXE_IPV4 convert_mcip(PXE_MAC_ADDR *); +INT32 validate_mcip (PXE_MAC_ADDR *MCastAddr); + +VOID PxeStructInit (PXE_SW_UNDI *PxePtr, UINTN VersionFlag); +VOID PxeUpdate (NIC_DATA_INSTANCE *NicPtr, PXE_SW_UNDI *PxePtr); + +#endif diff --git a/EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/build.xml b/EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/build.xml new file mode 100644 index 0000000000..2375cd7820 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/Undi/RuntimeDxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Bus/Scsi/ScsiBus/Dxe/ComponentName.c b/EdkModulePkg/Bus/Scsi/ScsiBus/Dxe/ComponentName.c new file mode 100644 index 0000000000..3f61c46d54 --- /dev/null +++ b/EdkModulePkg/Bus/Scsi/ScsiBus/Dxe/ComponentName.c @@ -0,0 +1,155 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ComponentName.c + +Abstract: + +--*/ + +#include "ScsiBus.h" + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +ScsiBusComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +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 + ); + +// +// EFI Component Name Protocol +// +EFI_COMPONENT_NAME_PROTOCOL gScsiBusComponentName = { + ScsiBusComponentNameGetDriverName, + ScsiBusComponentNameGetControllerName, + "eng" +}; + +static EFI_UNICODE_STRING_TABLE mScsiBusDriverNameTable[] = { + { "eng", (CHAR16 *) L"SCSI Bus Driver" }, + { NULL , NULL } +}; + +EFI_STATUS +EFIAPI +ScsiBusComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gScsiBusComponentName.SupportedLanguages, + mScsiBusDriverNameTable, + DriverName + ); +} + +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 + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + 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. + 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. + + Returns: + 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. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return EFI_UNSUPPORTED; +} diff --git a/EdkModulePkg/Bus/Scsi/ScsiBus/Dxe/ScsiBus.c b/EdkModulePkg/Bus/Scsi/ScsiBus/Dxe/ScsiBus.c new file mode 100644 index 0000000000..3aa31a812f --- /dev/null +++ b/EdkModulePkg/Bus/Scsi/ScsiBus/Dxe/ScsiBus.c @@ -0,0 +1,751 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + scsibus.c + +Abstract: + + +Revision History +--*/ + +#include "scsibus.h" + +EFI_STATUS +EFIAPI +SCSIBusDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +SCSIBusDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +SCSIBusDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +EFI_DRIVER_BINDING_PROTOCOL gSCSIBusDriverBinding = { + SCSIBusDriverBindingSupported, + SCSIBusDriverBindingStart, + SCSIBusDriverBindingStop, + 0x10, + NULL, + NULL +}; + +EFI_STATUS +EFIAPI +SCSIBusDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + + Arguments: + + Returns: + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Controller - add argument and description to function comment +// TODO: RemainingDevicePath - add argument and description to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + + // + // If RemainingDevicePath is not NULL, it should verify that the first device + // path node in RemainingDevicePath is an ATAPI Device path node. + // + if (RemainingDevicePath != NULL) { + if ((RemainingDevicePath->Type != MESSAGING_DEVICE_PATH) || + (RemainingDevicePath->SubType != MSG_ATAPI_DP) || + (DevicePathNodeLength (RemainingDevicePath) != sizeof(ATAPI_DEVICE_PATH))) { + return EFI_UNSUPPORTED; + } + } + // + // check for the existence of SCSI Pass Thru Protocol + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiScsiPassThruProtocolGuid, + NULL, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +SCSIBusDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + + Arguments: + + Returns: + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Controller - add argument and description to function comment +// TODO: RemainingDevicePath - add argument and description to function comment +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru; + UINT32 StartPun; + UINT64 StartLun; + UINT32 Pun; + UINT64 Lun; + BOOLEAN ScanOtherPuns; + + StartPun = 0; + StartLun = 0; + 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; + } + + // + // Consume SCSI Pass Thru protocol. + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiScsiPassThruProtocolGuid, + (VOID **) &ScsiPassThru, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return Status; + } + + if (RemainingDevicePath == NULL) { + StartPun = 0xFFFFFFFF; + StartLun = 0; + } else { + ScsiPassThru->GetTargetLun (ScsiPassThru, RemainingDevicePath, &StartPun, &StartLun); + } + + for (Pun = StartPun, ScanOtherPuns = TRUE; ScanOtherPuns;) { + + if (StartPun == 0xFFFFFFFF) { + // + // Remaining Device Path is NULL, scan all the possible Puns in the + // SCSI Channel. + // + Status = ScsiPassThru->GetNextDevice (ScsiPassThru, &Pun, &Lun); + if (EFI_ERROR (Status)) { + // + // no legal Pun and Lun found any more + // + break; + } + } else { + // + // Remaining Device Path is not NULL, only scan the specified Pun. + // + Pun = StartPun; + Lun = StartLun; + ScanOtherPuns = FALSE; + } + + // + // Avoid creating handle for the host adapter. + // + if (Pun == ScsiPassThru->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, Pun, Lun, ScsiPassThru, ParentDevicePath); + } + + return Status; +} + +EFI_STATUS +EFIAPI +SCSIBusDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + + Routine Description: + + Arguments: + + Returns: + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Controller - add argument and description to function comment +// TODO: NumberOfChildren - add argument and description to function comment +// TODO: ChildHandleBuffer - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + BOOLEAN AllChildrenStopped; + UINTN Index; + EFI_SCSI_IO_PROTOCOL *ScsiIo; + SCSI_IO_DEV *ScsiIoDevice; + EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru; + + if (NumberOfChildren == 0) { + // + // Close the bus driver + // + gBS->CloseProtocol ( + Controller, + &gEfiScsiPassThruProtocolGuid, + 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], + &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 + // + 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; + gBS->OpenProtocol ( + Controller, + &gEfiScsiPassThruProtocolGuid, + (VOID **) &ScsiPassThru, + This->DriverBindingHandle, + ChildHandleBuffer[Index], + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + } else { + gBS->FreePool (ScsiIoDevice); + } + } + + if (!AllChildrenStopped) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +ScsiGetDeviceType ( + IN EFI_SCSI_IO_PROTOCOL *This, + OUT UINT8 *DeviceType + ) +/*++ + + Routine Description: + Retrieves the device type information of the SCSI Controller. + + Arguments: + This - Protocol instance pointer. + DeviceType - A pointer to the device type information + retrieved from the SCSI Controller. + + Returns: + EFI_SUCCESS - Retrieves the device type information successfully. + EFI_INVALID_PARAMETER - The DeviceType is NULL. +--*/ +{ + SCSI_IO_DEV *ScsiIoDevice; + + if (DeviceType == NULL) { + return EFI_INVALID_PARAMETER; + } + + ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This); + *DeviceType = ScsiIoDevice->ScsiDeviceType; + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +ScsiGetDeviceLocation ( + IN EFI_SCSI_IO_PROTOCOL *This, + OUT UINT8 **Target, + OUT UINT64 *Lun + ) +/*++ + Routine Description: + Retrieves the device location in the SCSI channel. + + Arguments: + This - Protocol instance pointer. + Target - A pointer to the Target ID of a SCSI device + on the SCSI channel. + Lun - A pointer to the LUN of the SCSI device on + the SCSI channel. + + Returns: + EFI_SUCCESS - Retrieves the device location successfully. + EFI_INVALID_PARAMETER - The Target or Lun is NULL. +--*/ +{ + SCSI_IO_DEV *ScsiIoDevice; + + if (Target == NULL || Lun == NULL) { + return EFI_INVALID_PARAMETER; + } + + ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This); + + *Target = (UINT8 *) (UINTN) ScsiIoDevice->Pun; + *Lun = ScsiIoDevice->Lun; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +ScsiResetBus ( + IN EFI_SCSI_IO_PROTOCOL *This + ) +/*++ + + Routine Description: + Resets the SCSI Bus that the SCSI Controller is attached to. + + Arguments: + This - Protocol instance pointer. + + Returns: + EFI_SUCCESS - The SCSI bus is reset successfully. + EFI_DEVICE_ERROR - Errors encountered when resetting the SCSI bus. + EFI_UNSUPPORTED - The bus reset operation is not supported by the + SCSI Host Controller. + EFI_TIMEOUT - A timeout occurred while attempting to reset + the SCSI bus. +--*/ +{ + SCSI_IO_DEV *ScsiIoDevice; + + ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This); + + return ScsiIoDevice->ScsiPassThru->ResetChannel (ScsiIoDevice->ScsiPassThru); + +} + +EFI_STATUS +EFIAPI +ScsiResetDevice ( + IN EFI_SCSI_IO_PROTOCOL *This + ) +/*++ + + Routine Description: + Resets the SCSI Controller that the device handle specifies. + + Arguments: + This - Protocol instance pointer. + + + Returns: + EFI_SUCCESS - Reset the SCSI controller successfully. + EFI_DEVICE_ERROR - Errors are encountered when resetting the + SCSI Controller. + EFI_UNSUPPORTED - The SCSI bus does not support a device + reset operation. + EFI_TIMEOUT - A timeout occurred while attempting to + reset the SCSI Controller. +--*/ +{ + SCSI_IO_DEV *ScsiIoDevice; + + ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This); + + return ScsiIoDevice->ScsiPassThru->ResetTarget ( + ScsiIoDevice->ScsiPassThru, + ScsiIoDevice->Pun, + ScsiIoDevice->Lun + ); +} + +EFI_STATUS +EFIAPI +ScsiExecuteSCSICommand ( + IN EFI_SCSI_IO_PROTOCOL *This, + IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet, + IN EFI_EVENT Event OPTIONAL + ) +/*++ + + Routine Description: + Sends a SCSI Request Packet to the SCSI Controller for execution. + + Arguments: + This - Protocol instance pointer. + Packet - The SCSI request packet to send to the SCSI + Controller specified by the device handle. + 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. + Returns: + 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. + EFI_WARN_BUFFER_TOO_SMALL - 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. + 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. + 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. + EFI_INVALID_PARAMETER - The contents of CommandPacket are invalid. + The SCSI Request Packet was not sent, so no + additional status information is available. + 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. + 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. +--*/ +{ + SCSI_IO_DEV *ScsiIoDevice; + EFI_STATUS Status; + + EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *RequestPacket; + + if (Packet == NULL) { + return EFI_INVALID_PARAMETER; + } + + ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This); + + RequestPacket = (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *) Packet; + + Status = ScsiIoDevice->ScsiPassThru->PassThru ( + ScsiIoDevice->ScsiPassThru, + ScsiIoDevice->Pun, + ScsiIoDevice->Lun, + RequestPacket, + Event + ); + return Status; +} + +EFI_STATUS +ScsiScanCreateDevice ( + EFI_DRIVER_BINDING_PROTOCOL *This, + EFI_HANDLE Controller, + UINT32 Pun, + UINT64 Lun, + EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru, + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Controller - TODO: add argument description + Pun - TODO: add argument description + Lun - TODO: add argument description + ScsiPassThru - TODO: add argument description + ParentDevicePath - TODO: add argument description + +Returns: + + EFI_SUCCESS - TODO: Add description for return value + EFI_OUT_OF_RESOURCES - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + EFI_STATUS Status; + SCSI_IO_DEV *ScsiIoDevice; + EFI_DEVICE_PATH_PROTOCOL *ScsiDevicePath; + + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (SCSI_IO_DEV), + (VOID **) &ScsiIoDevice + ); + if (EFI_ERROR (Status)) { + return Status; + } + + ZeroMem (ScsiIoDevice, sizeof (SCSI_IO_DEV)); + + ScsiIoDevice->Signature = SCSI_IO_DEV_SIGNATURE; + ScsiIoDevice->ScsiPassThru = ScsiPassThru; + ScsiIoDevice->Pun = Pun; + ScsiIoDevice->Lun = Lun; + + ScsiIoDevice->ScsiIo.GetDeviceType = ScsiGetDeviceType; + ScsiIoDevice->ScsiIo.GetDeviceLocation = ScsiGetDeviceLocation; + ScsiIoDevice->ScsiIo.ResetBus = ScsiResetBus; + ScsiIoDevice->ScsiIo.ResetDevice = ScsiResetDevice; + ScsiIoDevice->ScsiIo.ExecuteSCSICommand = ScsiExecuteSCSICommand; + + if (!DiscoverScsiDevice (ScsiIoDevice)) { + gBS->FreePool (ScsiIoDevice); + return EFI_SUCCESS; + } + + // + // Set Device Path + // + Status = ScsiIoDevice->ScsiPassThru->BuildDevicePath ( + ScsiIoDevice->ScsiPassThru, + ScsiIoDevice->Pun, + ScsiIoDevice->Lun, + &ScsiDevicePath + ); + if (Status == EFI_OUT_OF_RESOURCES) { + gBS->FreePool (ScsiIoDevice); + return Status; + } + + ScsiIoDevice->DevicePath = AppendDevicePathNode ( + ParentDevicePath, + ScsiDevicePath + ); + // + // The memory space for ScsiDevicePath is allocated in + // ScsiPassThru->BuildDevicePath() function; It is no longer used + // after EfiAppendDevicePathNode,so free the memory it occupies. + // + gBS->FreePool (ScsiDevicePath); + + if (ScsiIoDevice->DevicePath == NULL) { + gBS->FreePool (ScsiIoDevice); + return EFI_OUT_OF_RESOURCES; + } + + Status = gBS->InstallMultipleProtocolInterfaces ( + &ScsiIoDevice->Handle, + &gEfiDevicePathProtocolGuid, + ScsiIoDevice->DevicePath, + &gEfiScsiIoProtocolGuid, + &ScsiIoDevice->ScsiIo, + NULL + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (ScsiIoDevice); + } else { + gBS->OpenProtocol ( + Controller, + &gEfiScsiPassThruProtocolGuid, + (VOID **) &ScsiPassThru, + This->DriverBindingHandle, + ScsiIoDevice->Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + } + + return EFI_SUCCESS; +} + +BOOLEAN +DiscoverScsiDevice ( + SCSI_IO_DEV *ScsiIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + EFI_STATUS Status; + EFI_SCSI_INQUIRY_DATA InquiryData; + UINT32 InquiryDataLength; + EFI_SCSI_SENSE_DATA SenseData; + UINT8 SenseDataLength; + UINT8 HostAdapterStatus; + UINT8 TargetStatus; + + HostAdapterStatus = 0; + TargetStatus = 0; + // + // Using Inquiry command to scan for the device + // + InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA); + SenseDataLength = sizeof (EFI_SCSI_SENSE_DATA); + + Status = SubmitInquiryCommand ( + &ScsiIoDevice->ScsiIo, + EfiScsiStallSeconds (1), + (VOID *) &SenseData, + &SenseDataLength, + &HostAdapterStatus, + &TargetStatus, + (VOID *) &InquiryData, + &InquiryDataLength, + FALSE + ); + if (EFI_ERROR (Status)) { + // + // ParseSenseData (&SenseData,SenseDataLength); + // + return FALSE; + } + // + // Retrieved inquiry data successfully + // + if ((InquiryData.Peripheral_Qualifier != 0) && + (InquiryData.Peripheral_Qualifier != 3)) { + return FALSE; + } + + if (InquiryData.Peripheral_Qualifier == 3) { + if (InquiryData.Peripheral_Type != 0x1f) { + return FALSE; + } + } + + if ((0x1e >= InquiryData.Peripheral_Type) && (InquiryData.Peripheral_Type >= 0xa)) { + return FALSE; + } + + // + // 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 & 0x03); + } + + return TRUE; +} diff --git a/EdkModulePkg/Bus/Scsi/ScsiBus/Dxe/ScsiBus.h b/EdkModulePkg/Bus/Scsi/ScsiBus/Dxe/ScsiBus.h new file mode 100644 index 0000000000..da1fa23bfa --- /dev/null +++ b/EdkModulePkg/Bus/Scsi/ScsiBus/Dxe/ScsiBus.h @@ -0,0 +1,266 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + scsibus.h + +Abstract: + + Header file for SCSI Bus Driver. + +Revision History +++*/ + +// TODO: fix comment to end with --*/ +#ifndef _SCSI_BUS_H +#define _SCSI_BUS_H + + +#include +// +// 1000 * 1000 * 10 +// +#define ONE_SECOND_TIMER 10000000 + +#define SCSI_IO_DEV_SIGNATURE EFI_SIGNATURE_32 ('s', 'c', 'i', 'o') + +typedef struct { + UINT32 Signature; + + EFI_HANDLE Handle; + EFI_SCSI_IO_PROTOCOL ScsiIo; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru; + + UINT32 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; + +EFI_STATUS +EFIAPI +ScsiGetDeviceType ( + IN EFI_SCSI_IO_PROTOCOL *This, + OUT UINT8 *DeviceType + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + DeviceType - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +ScsiResetBus ( + IN EFI_SCSI_IO_PROTOCOL *This + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +ScsiResetDevice ( + IN EFI_SCSI_IO_PROTOCOL *This + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +ScsiExecuteSCSICommand ( + IN EFI_SCSI_IO_PROTOCOL *This, + IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *CommandPacket, + IN EFI_EVENT Event + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + CommandPacket - TODO: add argument description + Event - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +ScsiScanCreateDevice ( + EFI_DRIVER_BINDING_PROTOCOL *This, + EFI_HANDLE Controller, + UINT32 Pun, + UINT64 Lun, + EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru, + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Controller - TODO: add argument description + Pun - TODO: add argument description + Lun - TODO: add argument description + ScsiPassThru - TODO: add argument description + ParentDevicePath - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +DiscoverScsiDevice ( + SCSI_IO_DEV *ScsiIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +GetLunList ( + EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru, + UINT32 Target, + UINT64 **LunArray, + UINTN *NumberOfLuns + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiPassThru - TODO: add argument description + Target - TODO: add argument description + LunArray - TODO: add argument description + NumberOfLuns - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +ScsiBusSubmitReportLunCommand ( + EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru, + UINT32 Target, + UINTN AllocationLength, + VOID *Buffer, + EFI_SCSI_SENSE_DATA *SenseData, + UINT8 *SenseDataLength, + UINT8 *HostAdapterStatus, + UINT8 *TargetStatus + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiPassThru - TODO: add argument description + Target - TODO: add argument description + AllocationLength - TODO: add argument description + Buffer - TODO: add argument description + SenseData - TODO: add argument description + SenseDataLength - TODO: add argument description + HostAdapterStatus - TODO: add argument description + TargetStatus - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; +#endif diff --git a/EdkModulePkg/Bus/Scsi/ScsiBus/Dxe/ScsiBus.mbd b/EdkModulePkg/Bus/Scsi/ScsiBus/Dxe/ScsiBus.mbd new file mode 100644 index 0000000000..0254903cd1 --- /dev/null +++ b/EdkModulePkg/Bus/Scsi/ScsiBus/Dxe/ScsiBus.mbd @@ -0,0 +1,44 @@ + + + + + ScsiBus + 0167CCC4-D0F7-4f21-A3EF-9E64B7CDCE8B + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:18 + + + UefiBootServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + EdkDxePrintLib + BaseLib + EdkScsiLib + DxeMemoryAllocationLib + UefiDevicePathLib + + diff --git a/EdkModulePkg/Bus/Scsi/ScsiBus/Dxe/ScsiBus.msa b/EdkModulePkg/Bus/Scsi/ScsiBus/Dxe/ScsiBus.msa new file mode 100644 index 0000000000..c4c0b4566b --- /dev/null +++ b/EdkModulePkg/Bus/Scsi/ScsiBus/Dxe/ScsiBus.msa @@ -0,0 +1,68 @@ + + + + + ScsiBus + DXE_DRIVER + BS_DRIVER + 0167CCC4-D0F7-4f21-A3EF-9E64B7CDCE8B + 0 + Component description file for Scsi Bus module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:18 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + UefiLib + BaseMemoryLib + EdkScsiLib + MemoryAllocationLib + UefiBootServicesTableLib + DevicePathLib + + + ScsiBus.h + ScsiBus.c + ComponentName.c + + + MdePkg + EdkModulePkg + + + ScsiPassThru + DevicePath + ScsiIo + + + + + + + gSCSIBusDriverBinding + gScsiBusComponentName + + + diff --git a/EdkModulePkg/Bus/Scsi/ScsiBus/Dxe/build.xml b/EdkModulePkg/Bus/Scsi/ScsiBus/Dxe/build.xml new file mode 100644 index 0000000000..9942471bb9 --- /dev/null +++ b/EdkModulePkg/Bus/Scsi/ScsiBus/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Bus/Scsi/ScsiDisk/Dxe/ComponentName.c b/EdkModulePkg/Bus/Scsi/ScsiDisk/Dxe/ComponentName.c new file mode 100644 index 0000000000..15f02d6c41 --- /dev/null +++ b/EdkModulePkg/Bus/Scsi/ScsiDisk/Dxe/ComponentName.c @@ -0,0 +1,190 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ComponentName.c + +Abstract: + +--*/ + +#include "ScsiDisk.h" + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +ScsiDiskComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +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 Component Name Protocol +// +EFI_COMPONENT_NAME_PROTOCOL gScsiDiskComponentName = { + ScsiDiskComponentNameGetDriverName, + ScsiDiskComponentNameGetControllerName, + "eng" +}; + +static EFI_UNICODE_STRING_TABLE mScsiDiskDriverNameTable[] = { + { "eng", (CHAR16 *) L"Scsi Disk Driver" }, + { NULL , NULL } +}; + +EFI_STATUS +EFIAPI +ScsiDiskComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gScsiDiskComponentName.SupportedLanguages, + mScsiDiskDriverNameTable, + DriverName + ); +} + +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 + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + 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. + 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. + + Returns: + 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. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + 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; + } + + // + // 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_THIS (BlockIo); + + return LookupUnicodeString ( + Language, + gScsiDiskComponentName.SupportedLanguages, + ScsiDiskDevice->ControllerNameTable, + ControllerName + ); + +} diff --git a/EdkModulePkg/Bus/Scsi/ScsiDisk/Dxe/ScsiDisk.c b/EdkModulePkg/Bus/Scsi/ScsiDisk/Dxe/ScsiDisk.c new file mode 100644 index 0000000000..2c6fd29d37 --- /dev/null +++ b/EdkModulePkg/Bus/Scsi/ScsiDisk/Dxe/ScsiDisk.c @@ -0,0 +1,2414 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ScsiDisk.c + +Abstract: + +--*/ + +#include "scsidisk.h" + +EFI_STATUS +EFIAPI +ScsiDiskDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +ScsiDiskDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +ScsiDiskDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +EFI_DRIVER_BINDING_PROTOCOL gScsiDiskDriverBinding = { + ScsiDiskDriverBindingSupported, + ScsiDiskDriverBindingStart, + ScsiDiskDriverBindingStop, + 0x10, + NULL, + NULL +}; + +EFI_STATUS +EFIAPI +ScsiDiskDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + + Arguments: + + Returns: + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Controller - add argument and description to function comment +// TODO: RemainingDevicePath - add argument and description to function comment +{ + 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)) { + Status = EFI_SUCCESS; + } else { + Status = EFI_UNSUPPORTED; + } + } + + gBS->CloseProtocol ( + Controller, + &gEfiScsiIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return Status; +} + +EFI_STATUS +EFIAPI +ScsiDiskDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + + Arguments: + + Returns: + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Controller - add argument and description to function comment +// TODO: RemainingDevicePath - add argument and description to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + EFI_SCSI_IO_PROTOCOL *ScsiIo; + SCSI_DISK_DEV *ScsiDiskDevice; + BOOLEAN Temp; + UINT8 Index; + UINT8 MaxRetry; + BOOLEAN NeedRetry; + + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (SCSI_DISK_DEV), + (VOID **) &ScsiDiskDevice + ); + if (EFI_ERROR (Status)) { + return Status; + } + + ZeroMem (ScsiDiskDevice, sizeof (SCSI_DISK_DEV)); + + Status = gBS->OpenProtocol ( + Controller, + &gEfiScsiIoProtocolGuid, + (VOID **) &ScsiIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (ScsiDiskDevice); + return Status; + } + + ScsiDiskDevice->Signature = SCSI_DISK_DEV_SIGNATURE; + ScsiDiskDevice->ScsiIo = ScsiIo; + ScsiDiskDevice->BlkIo.Media = &ScsiDiskDevice->BlkIoMedia; + ScsiDiskDevice->BlkIo.Reset = ScsiDiskReset; + ScsiDiskDevice->BlkIo.ReadBlocks = ScsiDiskReadBlocks; + ScsiDiskDevice->BlkIo.WriteBlocks = ScsiDiskWriteBlocks; + ScsiDiskDevice->BlkIo.FlushBlocks = ScsiDiskFlushBlocks; + ScsiDiskDevice->Handle = Controller; + + ScsiIo->GetDeviceType (ScsiIo, &(ScsiDiskDevice->DeviceType)); + switch (ScsiDiskDevice->DeviceType) { + case EFI_SCSI_TYPE_DISK: + ScsiDiskDevice->BlkIo.Media->BlockSize = 0x200; + break; + + case EFI_SCSI_TYPE_CDROM: + ScsiDiskDevice->BlkIo.Media->BlockSize = 0x800; + break; + } + // + // The Sense Data Array's initial size is 6 + // + ScsiDiskDevice->SenseDataNumber = 6; + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (EFI_SCSI_SENSE_DATA) * ScsiDiskDevice->SenseDataNumber, + (VOID **) &(ScsiDiskDevice->SenseData) + ); + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + Controller, + &gEfiScsiIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + gBS->FreePool (ScsiDiskDevice); + return Status; + } + + ZeroMem ( + ScsiDiskDevice->SenseData, + sizeof (EFI_SCSI_SENSE_DATA) * ScsiDiskDevice->SenseDataNumber + ); + + // + // Retrive device information + // + MaxRetry = 2; + for (Index = 0; Index < MaxRetry; Index++) { + Status = ScsiDiskInquiryDevice (ScsiDiskDevice, &NeedRetry); + if (!EFI_ERROR (Status)) { + break; + } + + if (!NeedRetry) { + gBS->FreePool (ScsiDiskDevice->SenseData); + gBS->CloseProtocol ( + Controller, + &gEfiScsiIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + gBS->FreePool (ScsiDiskDevice); + return EFI_DEVICE_ERROR; + } + } + // + // The second parameter "TRUE" means must + // retrieve media capacity + // + Status = ScsiDiskDetectMedia (ScsiDiskDevice, TRUE, &Temp); + if (!EFI_ERROR (Status)) { + Status = gBS->InstallMultipleProtocolInterfaces ( + &Controller, + &gEfiBlockIoProtocolGuid, + &ScsiDiskDevice->BlkIo, + NULL + ); + } + + if (EFI_ERROR (Status)) { + gBS->FreePool (ScsiDiskDevice->SenseData); + gBS->CloseProtocol ( + Controller, + &gEfiScsiIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + gBS->FreePool (ScsiDiskDevice); + return Status; + } + + ScsiDiskDevice->ControllerNameTable = NULL; + AddUnicodeString ( + "eng", + gScsiDiskComponentName.SupportedLanguages, + &ScsiDiskDevice->ControllerNameTable, + (CHAR16 *) L"SCSI Disk Device" + ); + + return EFI_SUCCESS; + +} + +EFI_STATUS +EFIAPI +ScsiDiskDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + + Routine Description: + + Arguments: + + Returns: + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Controller - add argument and description to function comment +// TODO: NumberOfChildren - add argument and description to function comment +// TODO: ChildHandleBuffer - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_BLOCK_IO_PROTOCOL *BlkIo; + 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_THIS (BlkIo); + Status = gBS->UninstallProtocolInterface ( + Controller, + &gEfiBlockIoProtocolGuid, + &ScsiDiskDevice->BlkIo + ); + if (!EFI_ERROR (Status)) { + gBS->CloseProtocol ( + Controller, + &gEfiScsiIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + ReleaseScsiDiskDeviceResources (ScsiDiskDevice); + + return EFI_SUCCESS; + } + // + // errors met + // + return Status; +} + +// +// Block I/O Protocol Interface +// + +EFI_STATUS +EFIAPI +ScsiDiskReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + ExtendedVerification - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + SCSI_DISK_DEV *ScsiDiskDevice; + EFI_STATUS Status; + + ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (This); + + Status = ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo); + + if (!ExtendedVerification) { + return Status; + } + + Status = ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo); + + return Status; +} + +EFI_STATUS +EFIAPI +ScsiDiskReadBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + MediaId - TODO: add argument description + LBA - TODO: add argument description + BufferSize - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + EFI_INVALID_PARAMETER - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_NO_MEDIA - TODO: Add description for return value + EFI_MEDIA_CHANGED - TODO: Add description for return value + EFI_BAD_BUFFER_SIZE - TODO: Add description for return value + EFI_INVALID_PARAMETER - TODO: Add description for return value + EFI_INVALID_PARAMETER - TODO: Add description for return value + EFI_INVALID_PARAMETER - TODO: Add description for return value + +--*/ +{ + SCSI_DISK_DEV *ScsiDiskDevice; + EFI_BLOCK_IO_MEDIA *Media; + EFI_STATUS Status; + UINTN BlockSize; + UINTN NumberOfBlocks; + BOOLEAN MediaChange; + + MediaChange = FALSE; + if (!Buffer) { + return EFI_INVALID_PARAMETER; + } + + if (BufferSize == 0) { + return EFI_SUCCESS; + } + + ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (This); + + if (!IsDeviceFixed (ScsiDiskDevice)) { + + Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + if (MediaChange) { + gBS->ReinstallProtocolInterface ( + ScsiDiskDevice->Handle, + &gEfiBlockIoProtocolGuid, + &ScsiDiskDevice->BlkIo, + &ScsiDiskDevice->BlkIo + ); + } + } + // + // Get the intrinsic block size + // + Media = ScsiDiskDevice->BlkIo.Media; + BlockSize = Media->BlockSize; + + NumberOfBlocks = BufferSize / BlockSize; + + if (!(Media->MediaPresent)) { + return EFI_NO_MEDIA; + } + + if (MediaId != Media->MediaId) { + return EFI_MEDIA_CHANGED; + } + + if (BufferSize % BlockSize != 0) { + return EFI_BAD_BUFFER_SIZE; + } + + if (LBA > Media->LastBlock) { + return EFI_INVALID_PARAMETER; + } + + if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) { + return EFI_INVALID_PARAMETER; + } + + if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) { + return EFI_INVALID_PARAMETER; + } + + // + // if all the parameters are valid, then perform read sectors command + // to transfer data from device to host. + // + Status = ScsiDiskReadSectors (ScsiDiskDevice, Buffer, LBA, NumberOfBlocks); + + return Status; +} + +EFI_STATUS +EFIAPI +ScsiDiskWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + MediaId - TODO: add argument description + LBA - TODO: add argument description + BufferSize - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + EFI_INVALID_PARAMETER - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_NO_MEDIA - TODO: Add description for return value + EFI_MEDIA_CHANGED - TODO: Add description for return value + EFI_BAD_BUFFER_SIZE - TODO: Add description for return value + EFI_INVALID_PARAMETER - TODO: Add description for return value + EFI_INVALID_PARAMETER - TODO: Add description for return value + EFI_INVALID_PARAMETER - TODO: Add description for return value + +--*/ +{ + SCSI_DISK_DEV *ScsiDiskDevice; + EFI_BLOCK_IO_MEDIA *Media; + EFI_STATUS Status; + UINTN BlockSize; + UINTN NumberOfBlocks; + BOOLEAN MediaChange; + + MediaChange = FALSE; + if (!Buffer) { + return EFI_INVALID_PARAMETER; + } + + if (BufferSize == 0) { + return EFI_SUCCESS; + } + + ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (This); + + if (!IsDeviceFixed (ScsiDiskDevice)) { + + Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + if (MediaChange) { + gBS->ReinstallProtocolInterface ( + ScsiDiskDevice->Handle, + &gEfiBlockIoProtocolGuid, + &ScsiDiskDevice->BlkIo, + &ScsiDiskDevice->BlkIo + ); + } + } + // + // Get the intrinsic block size + // + Media = ScsiDiskDevice->BlkIo.Media; + BlockSize = Media->BlockSize; + + NumberOfBlocks = BufferSize / BlockSize; + + if (!(Media->MediaPresent)) { + return EFI_NO_MEDIA; + } + + if (MediaId != Media->MediaId) { + return EFI_MEDIA_CHANGED; + } + + if (BufferSize % BlockSize != 0) { + return EFI_BAD_BUFFER_SIZE; + } + + if (LBA > Media->LastBlock) { + return EFI_INVALID_PARAMETER; + } + + if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) { + return EFI_INVALID_PARAMETER; + } + + if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) { + return EFI_INVALID_PARAMETER; + } + // + // if all the parameters are valid, then perform read sectors command + // to transfer data from device to host. + // + Status = ScsiDiskWriteSectors (ScsiDiskDevice, Buffer, LBA, NumberOfBlocks); + + return Status; +} + +EFI_STATUS +EFIAPI +ScsiDiskFlushBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + +Returns: + + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + // + // return directly + // + return EFI_SUCCESS; +} + +EFI_STATUS +ScsiDiskDetectMedia ( + SCSI_DISK_DEV *ScsiDiskDevice, + BOOLEAN MustReadCapacity, + BOOLEAN *MediaChange + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiDiskDevice - TODO: add argument description + MustReadCapacity - TODO: add argument description + MediaChange - TODO: add argument description + +Returns: + + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + EFI_STATUS Status; + EFI_STATUS ReadCapacityStatus; + EFI_SCSI_SENSE_DATA *SenseData; + UINTN NumberOfSenseKeys; + BOOLEAN NeedRetry; + BOOLEAN NeedReadCapacity; + UINT8 Index; + UINT8 MaxRetry; + EFI_BLOCK_IO_MEDIA OldMedia; + UINTN Action; + + Status = EFI_SUCCESS; + ReadCapacityStatus = EFI_SUCCESS; + SenseData = NULL; + NumberOfSenseKeys = 0; + NeedReadCapacity = FALSE; + CopyMem (&OldMedia, ScsiDiskDevice->BlkIo.Media, sizeof (OldMedia)); + // OldMedia = *(ScsiDiskDevice->BlkIo.Media); + + *MediaChange = FALSE; + + MaxRetry = 3; + for (Index = 0; Index < MaxRetry; Index++) { + Status = ScsiDiskTestUnitReady ( + ScsiDiskDevice, + &NeedRetry, + &SenseData, + &NumberOfSenseKeys + ); + if (!EFI_ERROR (Status)) { + break; + } + + if (!NeedRetry) { + return Status; + } + } + + if ((Index == MaxRetry) && EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + Status = DetectMediaParsingSenseKeys ( + ScsiDiskDevice, + SenseData, + NumberOfSenseKeys, + &Action + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // ACTION_NO_ACTION: need not read capacity + // other action code: need read capacity + // + if (Action == ACTION_NO_ACTION) { + NeedReadCapacity = FALSE; + } else { + NeedReadCapacity = TRUE; + } + + // + // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE, + // retrieve capacity via Read Capacity command + // + if (NeedReadCapacity || MustReadCapacity) { + + // + // retrieve media information + // + MaxRetry = 3; + for (Index = 0; Index < MaxRetry; Index++) { + + ReadCapacityStatus = ScsiDiskReadCapacity ( + ScsiDiskDevice, + &NeedRetry, + &SenseData, + &NumberOfSenseKeys + ); + if (EFI_ERROR (ReadCapacityStatus) && !NeedRetry) { + return EFI_DEVICE_ERROR; + } + // + // analyze sense key to action + // + Status = DetectMediaParsingSenseKeys ( + ScsiDiskDevice, + SenseData, + NumberOfSenseKeys, + &Action + ); + // + // if Status is error, it may indicate crisis error, + // so return without retry. + // + if (EFI_ERROR (Status)) { + return Status; + } + + switch (Action) { + case ACTION_NO_ACTION: + // + // no retry + // + Index = MaxRetry; + break; + + case ACTION_RETRY_COMMAND_LATER: + // + // retry the ReadCapacity later and continuously, until the condition + // no longer emerges. + // stall time is 100000us, or say 0.1 second. + // + gBS->Stall (100000); + Index = 0; + break; + + default: + // + // other cases, just retry the command + // + break; + } + } + + if ((Index == MaxRetry) && EFI_ERROR (ReadCapacityStatus)) { + return EFI_DEVICE_ERROR; + } + } + + 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; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +ScsiDiskInquiryDevice ( + SCSI_DISK_DEV *ScsiDiskDevice, + BOOLEAN *NeedRetry + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiDiskDevice - TODO: add argument description + NeedRetry - TODO: add argument description + +Returns: + + EFI_SUCCESS - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + +--*/ +{ + UINT32 InquiryDataLength; + UINT8 SenseDataLength; + UINT8 HostAdapterStatus; + UINT8 TargetStatus; + EFI_SCSI_SENSE_DATA *SenseDataArray; + UINTN NumberOfSenseKeys; + EFI_STATUS Status; + UINT8 MaxRetry; + UINT8 Index; + + InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA); + SenseDataLength = 0; + + Status = SubmitInquiryCommand ( + ScsiDiskDevice->ScsiIo, + EfiScsiStallSeconds (1), + NULL, + &SenseDataLength, + &HostAdapterStatus, + &TargetStatus, + (VOID *) &(ScsiDiskDevice->InquiryData), + &InquiryDataLength, + FALSE + ); + switch (Status) { + // + // no need to check HostAdapterStatus and TargetStatus + // + case EFI_SUCCESS: + case EFI_WARN_BUFFER_TOO_SMALL: + ParseInquiryData (ScsiDiskDevice); + return EFI_SUCCESS; + + case EFI_NOT_READY: + *NeedRetry = TRUE; + return EFI_DEVICE_ERROR; + + case EFI_INVALID_PARAMETER: + case EFI_UNSUPPORTED: + *NeedRetry = FALSE; + return EFI_DEVICE_ERROR; + + // + // go ahead to check HostAdapterStatus and TargetStatus + // (EFI_TIMEOUT, EFI_DEVICE_ERROR) + // + default: + break; + } + + Status = CheckHostAdapterStatus (HostAdapterStatus); + switch (Status) { + case EFI_SUCCESS: + break; + + case EFI_TIMEOUT: + case EFI_NOT_READY: + *NeedRetry = TRUE; + return EFI_DEVICE_ERROR; + + case EFI_DEVICE_ERROR: + // + // reset the scsi channel + // + ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo); + *NeedRetry = FALSE; + return EFI_DEVICE_ERROR; + } + + Status = CheckTargetStatus (TargetStatus); + switch (Status) { + case EFI_SUCCESS: + break; + + case EFI_NOT_READY: + // + // reset the scsi device + // + ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo); + *NeedRetry = TRUE; + return EFI_DEVICE_ERROR; + + case EFI_DEVICE_ERROR: + *NeedRetry = FALSE; + return EFI_DEVICE_ERROR; + } + + // + // if goes here, meant SubmitInquiryCommand() failed. + // if ScsiDiskRequestSenseKeys() succeeds at last, + // better retry SubmitInquiryCommand(). (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; +} + +EFI_STATUS +ScsiDiskTestUnitReady ( + SCSI_DISK_DEV *ScsiDiskDevice, + BOOLEAN *NeedRetry, + EFI_SCSI_SENSE_DATA **SenseDataArray, + UINTN *NumberOfSenseKeys + ) +// TODO: function comment should start with '/*++' +/* + 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. +*/ +// TODO: function comment should end with '--*/' +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: function comment is missing 'Returns:' +// TODO: ScsiDiskDevice - add argument and description to function comment +// TODO: NeedRetry - add argument and description to function comment +// TODO: SenseDataArray - add argument and description to function comment +// TODO: NumberOfSenseKeys - add argument and description to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +{ + EFI_STATUS Status; + UINT8 SenseDataLength; + UINT8 HostAdapterStatus; + UINT8 TargetStatus; + UINT8 Index; + UINT8 MaxRetry; + + SenseDataLength = 0; + *NumberOfSenseKeys = 0; + + // + // Parameter 3 and 4: do not require sense data, retrieve it when needed. + // + Status = SubmitTestUnitReadyCommand ( + ScsiDiskDevice->ScsiIo, + EfiScsiStallSeconds (1), + NULL, + &SenseDataLength, + &HostAdapterStatus, + &TargetStatus + ); + switch (Status) { + // + // no need to check HostAdapterStatus and TargetStatus + // + case EFI_NOT_READY: + *NeedRetry = TRUE; + return EFI_DEVICE_ERROR; + + case EFI_INVALID_PARAMETER: + case EFI_UNSUPPORTED: + *NeedRetry = FALSE; + return EFI_DEVICE_ERROR; + + // + // go ahead to check HostAdapterStatus and TargetStatus + // + default: + break; + } + + Status = CheckHostAdapterStatus (HostAdapterStatus); + switch (Status) { + case EFI_SUCCESS: + break; + + case EFI_TIMEOUT: + case EFI_NOT_READY: + *NeedRetry = TRUE; + return EFI_DEVICE_ERROR; + + case EFI_DEVICE_ERROR: + // + // reset the scsi channel + // + ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo); + *NeedRetry = FALSE; + return EFI_DEVICE_ERROR; + } + + Status = CheckTargetStatus (TargetStatus); + switch (Status) { + case EFI_SUCCESS: + break; + + case EFI_NOT_READY: + // + // reset the scsi device + // + ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo); + *NeedRetry = TRUE; + return EFI_DEVICE_ERROR; + + case EFI_DEVICE_ERROR: + *NeedRetry = FALSE; + return EFI_DEVICE_ERROR; + } + + 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; +} + +EFI_STATUS +DetectMediaParsingSenseKeys ( + SCSI_DISK_DEV *ScsiDiskDevice, + EFI_SCSI_SENSE_DATA *SenseData, + UINTN NumberOfSenseKeys, + UINTN *Action + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiDiskDevice - TODO: add argument description + SenseData - TODO: add argument description + NumberOfSenseKeys - TODO: add argument description + Action - TODO: add argument description + +Returns: + + EFI_SUCCESS - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + BOOLEAN RetryLater; + + // + // Default is to read capacity, unless.. + // + *Action = ACTION_READ_CAPACITY; + + if (NumberOfSenseKeys == 0) { + *Action = ACTION_NO_ACTION; + return EFI_SUCCESS; + } + + if (!ScsiDiskHaveSenseKey (SenseData, NumberOfSenseKeys)) { + // + // No Sense Key returned from last submitted command + // + *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; + return EFI_SUCCESS; + } + + if (ScsiDiskIsMediaChange (SenseData, NumberOfSenseKeys)) { + ScsiDiskDevice->BlkIo.Media->MediaId++; + return EFI_SUCCESS; + } + + if (ScsiDiskIsMediaError (SenseData, NumberOfSenseKeys)) { + ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE; + ScsiDiskDevice->BlkIo.Media->LastBlock = 0; + return EFI_DEVICE_ERROR; + } + + if (ScsiDiskIsHardwareError (SenseData, NumberOfSenseKeys)) { + return EFI_DEVICE_ERROR; + } + + if (!ScsiDiskIsDriveReady (SenseData, NumberOfSenseKeys, &RetryLater)) { + if (RetryLater) { + *Action = ACTION_RETRY_COMMAND_LATER; + return EFI_SUCCESS; + } + + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +ScsiDiskReadCapacity ( + SCSI_DISK_DEV *ScsiDiskDevice, + BOOLEAN *NeedRetry, + EFI_SCSI_SENSE_DATA **SenseDataArray, + UINTN *NumberOfSenseKeys + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiDiskDevice - TODO: add argument description + NeedRetry - TODO: add argument description + SenseDataArray - TODO: add argument description + NumberOfSenseKeys - TODO: add argument description + +Returns: + + EFI_SUCCESS - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + +--*/ +{ + EFI_SCSI_DISK_CAPACITY_DATA CapacityData; + UINT32 DataLength; + UINT8 HostAdapterStatus; + UINT8 TargetStatus; + EFI_STATUS CommandStatus; + EFI_STATUS Status; + UINT8 Index; + UINT8 MaxRetry; + UINT8 SenseDataLength; + + SenseDataLength = 0; + ZeroMem (&CapacityData, sizeof (EFI_SCSI_DISK_CAPACITY_DATA)); + DataLength = sizeof (EFI_SCSI_DISK_CAPACITY_DATA); + + *NumberOfSenseKeys = 0; + *NeedRetry = FALSE; + // + // submit Read Capacity Command. in this call,not request sense data + // + CommandStatus = SubmitReadCapacityCommand ( + ScsiDiskDevice->ScsiIo, + EfiScsiStallSeconds (1), + NULL, + &SenseDataLength, + &HostAdapterStatus, + &TargetStatus, + (VOID *) &CapacityData, + &DataLength, + FALSE + ); + switch (CommandStatus) { + // + // no need to check HostAdapterStatus and TargetStatus + // + case EFI_SUCCESS: + GetMediaInfo (ScsiDiskDevice, &CapacityData); + return EFI_SUCCESS; + + case EFI_NOT_READY: + *NeedRetry = TRUE; + return EFI_DEVICE_ERROR; + + case EFI_INVALID_PARAMETER: + case 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) + // + default: + break; + } + + Status = CheckHostAdapterStatus (HostAdapterStatus); + switch (Status) { + case EFI_SUCCESS: + break; + + case EFI_TIMEOUT: + case EFI_NOT_READY: + *NeedRetry = TRUE; + return EFI_DEVICE_ERROR; + + case EFI_DEVICE_ERROR: + // + // reset the scsi channel + // + ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo); + *NeedRetry = FALSE; + return EFI_DEVICE_ERROR; + } + + Status = CheckTargetStatus (TargetStatus); + switch (Status) { + case EFI_SUCCESS: + break; + + case EFI_NOT_READY: + // + // reset the scsi device + // + ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo); + *NeedRetry = TRUE; + return EFI_DEVICE_ERROR; + + case EFI_DEVICE_ERROR: + *NeedRetry = FALSE; + return EFI_DEVICE_ERROR; + } + + // + // if goes here, meant SubmitReadCapacityCommand() failed. + // if ScsiDiskRequestSenseKeys() succeeds at last, + // better retry SubmitReadCapacityCommand(). (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; +} + +EFI_STATUS +CheckHostAdapterStatus ( + UINT8 HostAdapterStatus + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + HostAdapterStatus - TODO: add argument description + +Returns: + + EFI_SUCCESS - TODO: Add description for return value + EFI_TIMEOUT - TODO: Add description for return value + EFI_NOT_READY - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + switch (HostAdapterStatus) { + case EFI_SCSI_IO_STATUS_HOST_ADAPTER_OK: + return EFI_SUCCESS; + + case EFI_SCSI_IO_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT: + case EFI_SCSI_IO_STATUS_HOST_ADAPTER_TIMEOUT: + case EFI_SCSI_IO_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND: + return EFI_TIMEOUT; + + case EFI_SCSI_IO_STATUS_HOST_ADAPTER_MESSAGE_REJECT: + case EFI_SCSI_IO_STATUS_HOST_ADAPTER_PARITY_ERROR: + case EFI_SCSI_IO_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED: + case EFI_SCSI_IO_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN: + case EFI_SCSI_IO_STATUS_HOST_ADAPTER_BUS_RESET: + return EFI_NOT_READY; + + case EFI_SCSI_IO_STATUS_HOST_ADAPTER_BUS_FREE: + case EFI_SCSI_IO_STATUS_HOST_ADAPTER_PHASE_ERROR: + return EFI_DEVICE_ERROR; + + default: + return EFI_SUCCESS; + } +} + +EFI_STATUS +CheckTargetStatus ( + UINT8 TargetStatus + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + TargetStatus - TODO: add argument description + +Returns: + + EFI_SUCCESS - TODO: Add description for return value + EFI_NOT_READY - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + switch (TargetStatus) { + case EFI_SCSI_IO_STATUS_TARGET_GOOD: + case EFI_SCSI_IO_STATUS_TARGET_CHECK_CONDITION: + case EFI_SCSI_IO_STATUS_TARGET_CONDITION_MET: + return EFI_SUCCESS; + + case EFI_SCSI_IO_STATUS_TARGET_INTERMEDIATE: + case EFI_SCSI_IO_STATUS_TARGET_INTERMEDIATE_CONDITION_MET: + case EFI_SCSI_IO_STATUS_TARGET_BUSY: + case EFI_SCSI_IO_STATUS_TARGET_COMMOND_TERMINATED: + case EFI_SCSI_IO_STATUS_TARGET_QUEUE_FULL: + return EFI_NOT_READY; + + case EFI_SCSI_IO_STATUS_TARGET_RESERVATION_CONFLICT: + return EFI_DEVICE_ERROR; + break; + + default: + return EFI_SUCCESS; + } +} + +EFI_STATUS +ScsiDiskRequestSenseKeys ( + SCSI_DISK_DEV *ScsiDiskDevice, + BOOLEAN *NeedRetry, + EFI_SCSI_SENSE_DATA **SenseDataArray, + UINTN *NumberOfSenseKeys, + BOOLEAN AskResetIfError + ) +// TODO: function comment should start with '/*++' +/* + Retrieve all sense keys from the device. + When encountering error during the process, + if retrieve sense keys before error encounterred, + return the sense keys with return status set to EFI_SUCCESS, + and NeedRetry set to FALSE; otherwize, return the proper return + status. +*/ +// TODO: function comment should end with '--*/' +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: function comment is missing 'Returns:' +// TODO: ScsiDiskDevice - add argument and description to function comment +// TODO: NeedRetry - add argument and description to function comment +// TODO: SenseDataArray - add argument and description to function comment +// TODO: NumberOfSenseKeys - add argument and description to function comment +// TODO: AskResetIfError - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_SCSI_SENSE_DATA *PtrSenseData; + UINT8 SenseDataLength; + BOOLEAN SenseReq; + EFI_STATUS Status; + EFI_STATUS FallStatus; + UINT8 HostAdapterStatus; + UINT8 TargetStatus; + + FallStatus = EFI_SUCCESS; + SenseDataLength = sizeof (EFI_SCSI_SENSE_DATA); + + ZeroMem ( + ScsiDiskDevice->SenseData, + sizeof (EFI_SCSI_SENSE_DATA) * (ScsiDiskDevice->SenseDataNumber) + ); + + *NumberOfSenseKeys = 0; + *SenseDataArray = ScsiDiskDevice->SenseData; + PtrSenseData = ScsiDiskDevice->SenseData; + + for (SenseReq = TRUE; SenseReq;) { + + Status = SubmitRequestSenseCommand ( + ScsiDiskDevice->ScsiIo, + EfiScsiStallSeconds (2), + PtrSenseData, + &SenseDataLength, + &HostAdapterStatus, + &TargetStatus + ); + switch (Status) { + + case EFI_SUCCESS: + + // + // fall through + // + case EFI_WARN_BUFFER_TOO_SMALL: + FallStatus = EFI_SUCCESS; + break; + + case EFI_TIMEOUT: + + // + // fall through + // + case EFI_NOT_READY: + *NeedRetry = TRUE; + FallStatus = EFI_DEVICE_ERROR; + break; + + case EFI_INVALID_PARAMETER: + case EFI_UNSUPPORTED: + *NeedRetry = FALSE; + FallStatus = EFI_DEVICE_ERROR; + break; + + case EFI_DEVICE_ERROR: + if (AskResetIfError) { + ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo); + } + + FallStatus = EFI_DEVICE_ERROR; + break; + } + + if (EFI_ERROR (FallStatus)) { + if (*NumberOfSenseKeys != 0) { + *NeedRetry = FALSE; + return EFI_SUCCESS; + } else { + return EFI_DEVICE_ERROR; + } + } + + (*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; + } + + PtrSenseData += 1; + + } + + return EFI_SUCCESS; +} + +VOID +GetMediaInfo ( + SCSI_DISK_DEV *ScsiDiskDevice, + EFI_SCSI_DISK_CAPACITY_DATA *Capacity + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiDiskDevice - TODO: add argument description + Capacity - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + ScsiDiskDevice->BlkIo.Media->LastBlock = (Capacity->LastLba3 << 24) | + (Capacity->LastLba2 << 16) | + (Capacity->LastLba1 << 8) | + Capacity->LastLba0; + + ScsiDiskDevice->BlkIo.Media->MediaPresent = TRUE; + ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity->BlockSize3 << 24) | + (Capacity->BlockSize2 << 16) | + (Capacity->BlockSize1 << 8) | + Capacity->BlockSize0; + if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_DISK) { + ScsiDiskDevice->BlkIo.Media->BlockSize = 0x200; + } + + if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_CDROM) { + ScsiDiskDevice->BlkIo.Media->BlockSize = 0x800; + } +} + +VOID +ParseInquiryData ( + SCSI_DISK_DEV *ScsiDiskDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiDiskDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + ScsiDiskDevice->FixedDevice = (BOOLEAN) (ScsiDiskDevice->InquiryData.RMB ? 0 : 1); + ScsiDiskDevice->BlkIoMedia.RemovableMedia = (BOOLEAN) (!ScsiDiskDevice->FixedDevice); +} + +EFI_STATUS +ScsiDiskReadSectors ( + SCSI_DISK_DEV *ScsiDiskDevice, + VOID *Buffer, + EFI_LBA Lba, + UINTN NumberOfBlocks + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiDiskDevice - TODO: add argument description + Buffer - TODO: add argument description + Lba - TODO: add argument description + NumberOfBlocks - TODO: add argument description + +Returns: + + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + UINTN BlocksRemaining; + UINT32 Lba32; + UINT8 *PtrBuffer; + UINT32 BlockSize; + UINT32 ByteCount; + UINT32 MaxBlock; + UINT32 SectorCount; + UINT64 Timeout; + EFI_STATUS Status; + UINT8 Index; + UINT8 MaxRetry; + BOOLEAN NeedRetry; + EFI_SCSI_SENSE_DATA *SenseData; + UINT8 SenseDataLength; + UINTN NumberOfSenseKeys; + + SenseData = NULL; + SenseDataLength = 0; + NumberOfSenseKeys = 0; + + Status = EFI_SUCCESS; + + BlocksRemaining = NumberOfBlocks; + BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize; + // + // limit the data bytes that can be transferred by one Read(10) Command + // + MaxBlock = 65536; + + PtrBuffer = Buffer; + Lba32 = (UINT32) Lba; + + while (BlocksRemaining > 0) { + + if (BlocksRemaining <= MaxBlock) { + + SectorCount = (UINT16) BlocksRemaining; + } else { + + SectorCount = MaxBlock; + } + + ByteCount = SectorCount * BlockSize; + Timeout = EfiScsiStallSeconds (2); + + MaxRetry = 2; + for (Index = 0; Index < MaxRetry; Index++) { + + Status = ScsiDiskRead10 ( + ScsiDiskDevice, + &NeedRetry, + &SenseData, + &NumberOfSenseKeys, + Timeout, + PtrBuffer, + &ByteCount, + Lba32, + SectorCount + ); + if (!EFI_ERROR (Status)) { + break; + } + + if (!NeedRetry) { + return EFI_DEVICE_ERROR; + } + + } + + if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) { + return EFI_DEVICE_ERROR; + } + + // + // actual transferred sectors + // + SectorCount = ByteCount / BlockSize; + + Lba32 += SectorCount; + PtrBuffer = PtrBuffer + SectorCount * BlockSize; + BlocksRemaining -= SectorCount; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +ScsiDiskWriteSectors ( + SCSI_DISK_DEV *ScsiDiskDevice, + VOID *Buffer, + EFI_LBA Lba, + UINTN NumberOfBlocks + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiDiskDevice - TODO: add argument description + Buffer - TODO: add argument description + Lba - TODO: add argument description + NumberOfBlocks - TODO: add argument description + +Returns: + + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + UINTN BlocksRemaining; + UINT32 Lba32; + UINT8 *PtrBuffer; + UINT32 BlockSize; + UINT32 ByteCount; + UINT32 MaxBlock; + UINT32 SectorCount; + UINT64 Timeout; + EFI_STATUS Status; + UINT8 Index; + UINT8 MaxRetry; + BOOLEAN NeedRetry; + EFI_SCSI_SENSE_DATA *SenseData; + UINT8 SenseDataLength; + UINTN NumberOfSenseKeys; + + SenseData = NULL; + SenseDataLength = 0; + NumberOfSenseKeys = 0; + + Status = EFI_SUCCESS; + + BlocksRemaining = NumberOfBlocks; + BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize; + // + // limit the data bytes that can be transferred by one Write(10) Command + // + MaxBlock = 65536; + + PtrBuffer = Buffer; + Lba32 = (UINT32) Lba; + + while (BlocksRemaining > 0) { + + if (BlocksRemaining <= MaxBlock) { + + SectorCount = (UINT16) BlocksRemaining; + } else { + + SectorCount = MaxBlock; + } + + ByteCount = SectorCount * BlockSize; + Timeout = EfiScsiStallSeconds (2); + MaxRetry = 2; + for (Index = 0; Index < MaxRetry; Index++) { + Status = ScsiDiskWrite10 ( + ScsiDiskDevice, + &NeedRetry, + &SenseData, + &NumberOfSenseKeys, + Timeout, + PtrBuffer, + &ByteCount, + Lba32, + SectorCount + ); + if (!EFI_ERROR (Status)) { + break; + } + + if (!NeedRetry) { + return EFI_DEVICE_ERROR; + } + } + + if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) { + return EFI_DEVICE_ERROR; + } + // + // actual transferred sectors + // + SectorCount = ByteCount / BlockSize; + + Lba32 += SectorCount; + PtrBuffer = PtrBuffer + SectorCount * BlockSize; + BlocksRemaining -= SectorCount; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +ScsiDiskRead10 ( + SCSI_DISK_DEV *ScsiDiskDevice, + BOOLEAN *NeedRetry, + EFI_SCSI_SENSE_DATA **SenseDataArray, + UINTN *NumberOfSenseKeys, + UINT64 Timeout, + UINT8 *DataBuffer, + UINT32 *DataLength, + UINT32 StartLba, + UINT32 SectorSize + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiDiskDevice - TODO: add argument description + NeedRetry - TODO: add argument description + SenseDataArray - TODO: add argument description + NumberOfSenseKeys - TODO: add argument description + Timeout - TODO: add argument description + DataBuffer - TODO: add argument description + DataLength - TODO: add argument description + StartLba - TODO: add argument description + SectorSize - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + UINT8 SenseDataLength; + EFI_STATUS Status; + UINT8 HostAdapterStatus; + UINT8 TargetStatus; + + *NeedRetry = FALSE; + *NumberOfSenseKeys = 0; + SenseDataLength = 0; + Status = SubmitRead10Command ( + ScsiDiskDevice->ScsiIo, + Timeout, + NULL, + &SenseDataLength, + &HostAdapterStatus, + &TargetStatus, + DataBuffer, + DataLength, + StartLba, + SectorSize + ); + return Status; +} + +EFI_STATUS +ScsiDiskWrite10 ( + SCSI_DISK_DEV *ScsiDiskDevice, + BOOLEAN *NeedRetry, + EFI_SCSI_SENSE_DATA **SenseDataArray, + UINTN *NumberOfSenseKeys, + UINT64 Timeout, + UINT8 *DataBuffer, + UINT32 *DataLength, + UINT32 StartLba, + UINT32 SectorSize + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiDiskDevice - TODO: add argument description + NeedRetry - TODO: add argument description + SenseDataArray - TODO: add argument description + NumberOfSenseKeys - TODO: add argument description + Timeout - TODO: add argument description + DataBuffer - TODO: add argument description + DataLength - TODO: add argument description + StartLba - TODO: add argument description + SectorSize - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + EFI_STATUS Status; + UINT8 SenseDataLength; + UINT8 HostAdapterStatus; + UINT8 TargetStatus; + + *NeedRetry = FALSE; + *NumberOfSenseKeys = 0; + SenseDataLength = 0; + Status = SubmitWrite10Command ( + ScsiDiskDevice->ScsiIo, + Timeout, + NULL, + &SenseDataLength, + &HostAdapterStatus, + &TargetStatus, + DataBuffer, + DataLength, + StartLba, + SectorSize + ); + return Status; +} + +BOOLEAN +ScsiDiskIsNoMedia ( + IN EFI_SCSI_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SenseData - TODO: add argument description + SenseCounts - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + 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; +} + +BOOLEAN +ScsiDiskIsMediaError ( + IN EFI_SCSI_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SenseData - TODO: add argument description + SenseCounts - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + 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; +} + +BOOLEAN +ScsiDiskIsHardwareError ( + IN EFI_SCSI_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SenseData - TODO: add argument description + SenseCounts - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + 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; +} + +BOOLEAN +ScsiDiskIsMediaChange ( + IN EFI_SCSI_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SenseData - TODO: add argument description + SenseCounts - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + 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; +} + +BOOLEAN +ScsiDiskIsResetBefore ( + IN EFI_SCSI_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SenseData - TODO: add argument description + SenseCounts - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + 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; +} + +BOOLEAN +ScsiDiskIsDriveReady ( + IN EFI_SCSI_SENSE_DATA *SenseData, + IN UINTN SenseCounts, + OUT BOOLEAN *RetryLater + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SenseData - TODO: add argument description + SenseCounts - TODO: add argument description + RetryLater - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + 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; +} + +BOOLEAN +ScsiDiskHaveSenseKey ( + IN EFI_SCSI_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SenseData - TODO: add argument description + SenseCounts - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + 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; +} + +VOID +ReleaseScsiDiskDeviceResources ( + IN SCSI_DISK_DEV *ScsiDiskDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiDiskDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + if (ScsiDiskDevice == NULL) { + return ; + } + + if (ScsiDiskDevice->SenseData != NULL) { + gBS->FreePool (ScsiDiskDevice->SenseData); + ScsiDiskDevice->SenseData = NULL; + } + + if (ScsiDiskDevice->ControllerNameTable != NULL) { + FreeUnicodeStringTable (ScsiDiskDevice->ControllerNameTable); + ScsiDiskDevice->ControllerNameTable = NULL; + } + + gBS->FreePool (ScsiDiskDevice); + + ScsiDiskDevice = NULL; +} diff --git a/EdkModulePkg/Bus/Scsi/ScsiDisk/Dxe/ScsiDisk.h b/EdkModulePkg/Bus/Scsi/ScsiDisk/Dxe/ScsiDisk.h new file mode 100644 index 0000000000..96d1da4f90 --- /dev/null +++ b/EdkModulePkg/Bus/Scsi/ScsiDisk/Dxe/ScsiDisk.h @@ -0,0 +1,728 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ScsiDisk.h + +Abstract: + + Header file for SCSI Disk Driver. + +--*/ + +#ifndef _SCSI_DISK_H +#define _SCSI_DISK_H + + +#include + +#define IsDeviceFixed(a) (a)->FixedDevice ? 1 : 0 + +#define SCSI_DISK_DEV_SIGNATURE EFI_SIGNATURE_32 ('s', 'c', 'd', 'k') + +typedef struct { + UINT32 Signature; + + EFI_HANDLE Handle; + + EFI_BLOCK_IO_PROTOCOL BlkIo; + EFI_BLOCK_IO_MEDIA BlkIoMedia; + 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; + +} SCSI_DISK_DEV; + +#define SCSI_DISK_DEV_FROM_THIS(a) CR (a, SCSI_DISK_DEV, BlkIo, SCSI_DISK_DEV_SIGNATURE) + +// +// Global Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gScsiDiskDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gScsiDiskComponentName; +// +// action code used in detect media process +// +#define ACTION_NO_ACTION 0x00 +#define ACTION_READ_CAPACITY 0x01 +#define ACTION_RETRY_COMMAND_LATER 0x02 + +EFI_STATUS +EFIAPI +ScsiDiskReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + ExtendedVerification - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +ScsiDiskReadBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + MediaId - TODO: add argument description + LBA - TODO: add argument description + BufferSize - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +ScsiDiskWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + MediaId - TODO: add argument description + LBA - TODO: add argument description + BufferSize - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +ScsiDiskFlushBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +ScsiDiskDetectMedia ( + SCSI_DISK_DEV *ScsiDiskDevice, + BOOLEAN MustReadCap, + BOOLEAN *MediaChange + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiDiskDevice - TODO: add argument description + MustReadCap - TODO: add argument description + MediaChange - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +ScsiDiskTestUnitReady ( + SCSI_DISK_DEV *ScsiDiskDevice, + BOOLEAN *NeedRetry, + EFI_SCSI_SENSE_DATA **SenseDataArray, + UINTN *NumberOfSenseKeys + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiDiskDevice - TODO: add argument description + NeedRetry - TODO: add argument description + SenseDataArray - TODO: add argument description + NumberOfSenseKeys - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +DetectMediaParsingSenseKeys ( + SCSI_DISK_DEV *ScsiDiskDevice, + EFI_SCSI_SENSE_DATA *SenseData, + UINTN NumberOfSenseKeys, + UINTN *Action + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiDiskDevice - TODO: add argument description + SenseData - TODO: add argument description + NumberOfSenseKeys - TODO: add argument description + Action - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +ScsiDiskReadCapacity ( + SCSI_DISK_DEV *ScsiDiskDevice, + BOOLEAN *NeedRetry, + EFI_SCSI_SENSE_DATA **SenseDataArray, + UINTN *NumberOfSenseKeys + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiDiskDevice - TODO: add argument description + NeedRetry - TODO: add argument description + SenseDataArray - TODO: add argument description + NumberOfSenseKeys - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +CheckHostAdapterStatus ( + UINT8 HostAdapterStatus + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + HostAdapterStatus - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +CheckTargetStatus ( + UINT8 TargetStatus + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + TargetStatus - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +ScsiDiskRequestSenseKeys ( + SCSI_DISK_DEV *ScsiDiskDevice, + BOOLEAN *NeedRetry, + EFI_SCSI_SENSE_DATA **SenseDataArray, + UINTN *NumberOfSenseKeys, + BOOLEAN AskResetIfError + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiDiskDevice - TODO: add argument description + NeedRetry - TODO: add argument description + SenseDataArray - TODO: add argument description + NumberOfSenseKeys - TODO: add argument description + AskResetIfError - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +ScsiDiskInquiryDevice ( + SCSI_DISK_DEV *ScsiDiskDevice, + BOOLEAN *NeedRetry + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiDiskDevice - TODO: add argument description + NeedRetry - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +VOID +ParseInquiryData ( + SCSI_DISK_DEV *ScsiDiskDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiDiskDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +ScsiDiskReadSectors ( + SCSI_DISK_DEV *ScsiDiskDevice, + VOID *Buffer, + EFI_LBA Lba, + UINTN NumberOfBlocks + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiDiskDevice - TODO: add argument description + Buffer - TODO: add argument description + Lba - TODO: add argument description + NumberOfBlocks - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +ScsiDiskWriteSectors ( + SCSI_DISK_DEV *ScsiDiskDevice, + VOID *Buffer, + EFI_LBA Lba, + UINTN NumberOfBlocks + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiDiskDevice - TODO: add argument description + Buffer - TODO: add argument description + Lba - TODO: add argument description + NumberOfBlocks - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +ScsiDiskRead10 ( + SCSI_DISK_DEV *ScsiDiskDevice, + BOOLEAN *NeedRetry, + EFI_SCSI_SENSE_DATA **SenseDataArray, + UINTN *NumberOfSenseKeys, + UINT64 Timeout, + UINT8 *DataBuffer, + UINT32 *DataLength, + UINT32 StartLba, + UINT32 SectorSize + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiDiskDevice - TODO: add argument description + NeedRetry - TODO: add argument description + SenseDataArray - TODO: add argument description + NumberOfSenseKeys - TODO: add argument description + Timeout - TODO: add argument description + DataBuffer - TODO: add argument description + DataLength - TODO: add argument description + StartLba - TODO: add argument description + SectorSize - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +ScsiDiskWrite10 ( + SCSI_DISK_DEV *ScsiDiskDevice, + BOOLEAN *NeedRetry, + EFI_SCSI_SENSE_DATA **SenseDataArray, + UINTN *NumberOfSenseKeys, + UINT64 Timeout, + UINT8 *DataBuffer, + UINT32 *DataLength, + UINT32 StartLba, + UINT32 SectorSize + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiDiskDevice - TODO: add argument description + NeedRetry - TODO: add argument description + SenseDataArray - TODO: add argument description + NumberOfSenseKeys - TODO: add argument description + Timeout - TODO: add argument description + DataBuffer - TODO: add argument description + DataLength - TODO: add argument description + StartLba - TODO: add argument description + SectorSize - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +VOID +GetMediaInfo ( + SCSI_DISK_DEV *ScsiDiskDevice, + EFI_SCSI_DISK_CAPACITY_DATA *Capacity + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiDiskDevice - TODO: add argument description + Capacity - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +ScsiDiskIsNoMedia ( + IN EFI_SCSI_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SenseData - TODO: add argument description + SenseCounts - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +ScsiDiskIsMediaError ( + IN EFI_SCSI_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SenseData - TODO: add argument description + SenseCounts - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +ScsiDiskIsHardwareError ( + IN EFI_SCSI_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SenseData - TODO: add argument description + SenseCounts - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +ScsiDiskIsMediaChange ( + IN EFI_SCSI_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SenseData - TODO: add argument description + SenseCounts - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +ScsiDiskIsResetBefore ( + IN EFI_SCSI_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SenseData - TODO: add argument description + SenseCounts - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +ScsiDiskIsDriveReady ( + IN EFI_SCSI_SENSE_DATA *SenseData, + IN UINTN SenseCounts, + OUT BOOLEAN *NeedRetry + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SenseData - TODO: add argument description + SenseCounts - TODO: add argument description + NeedRetry - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +ScsiDiskHaveSenseKey ( + IN EFI_SCSI_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SenseData - TODO: add argument description + SenseCounts - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +VOID +ReleaseScsiDiskDeviceResources ( + IN SCSI_DISK_DEV *ScsiDiskDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiDiskDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/EdkModulePkg/Bus/Scsi/ScsiDisk/Dxe/ScsiDisk.mbd b/EdkModulePkg/Bus/Scsi/ScsiDisk/Dxe/ScsiDisk.mbd new file mode 100644 index 0000000000..ec19f96872 --- /dev/null +++ b/EdkModulePkg/Bus/Scsi/ScsiDisk/Dxe/ScsiDisk.mbd @@ -0,0 +1,43 @@ + + + + + ScsiDisk + 0A66E322-3740-4cce-AD62-BD172CECCA35 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:18 + + + UefiBootServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + EdkDxePrintLib + BaseLib + EdkScsiLib + DxeMemoryAllocationLib + + diff --git a/EdkModulePkg/Bus/Scsi/ScsiDisk/Dxe/ScsiDisk.msa b/EdkModulePkg/Bus/Scsi/ScsiDisk/Dxe/ScsiDisk.msa new file mode 100644 index 0000000000..d81af71b53 --- /dev/null +++ b/EdkModulePkg/Bus/Scsi/ScsiDisk/Dxe/ScsiDisk.msa @@ -0,0 +1,67 @@ + + + + + ScsiDisk + DXE_DRIVER + BS_DRIVER + 0A66E322-3740-4cce-AD62-BD172CECCA35 + 0 + Component description file for Scsi Disk module.Revision History + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:18 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + BaseLib + UefiLib + BaseMemoryLib + EdkScsiLib + MemoryAllocationLib + UefiBootServicesTableLib + + + ScsiDisk.h + ScsiDisk.c + ComponentName.c + + + MdePkg + EdkModulePkg + + + ScsiIo + BlockIo + + + + + + + gScsiDiskDriverBinding + gScsiDiskComponentName + + + diff --git a/EdkModulePkg/Bus/Scsi/ScsiDisk/Dxe/build.xml b/EdkModulePkg/Bus/Scsi/ScsiDisk/Dxe/build.xml new file mode 100644 index 0000000000..5d5f4d83b7 --- /dev/null +++ b/EdkModulePkg/Bus/Scsi/ScsiDisk/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Bus/Usb/UsbBot/Dxe/ComponentName.c b/EdkModulePkg/Bus/Usb/UsbBot/Dxe/ComponentName.c new file mode 100644 index 0000000000..6a9cf13456 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBot/Dxe/ComponentName.c @@ -0,0 +1,190 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ComponentName.c + +Abstract: + +--*/ + +#include "bot.h" + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +UsbBotComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +EFI_STATUS +EFIAPI +UsbBotComponentNameGetControllerName ( + 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 +// +EFI_COMPONENT_NAME_PROTOCOL gUsbBotComponentName = { + UsbBotComponentNameGetDriverName, + UsbBotComponentNameGetControllerName, + "eng" +}; + +STATIC EFI_UNICODE_STRING_TABLE mUsbBotDriverNameTable[] = { + { "eng", (CHAR16 *) L"Usb Bot Mass Storage Driver" }, + { NULL , NULL } +}; + + +EFI_STATUS +EFIAPI +UsbBotComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gUsbBotComponentName.SupportedLanguages, + mUsbBotDriverNameTable, + DriverName + ); +} + +EFI_STATUS +EFIAPI +UsbBotComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + 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. + 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. + + Returns: + 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. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + EFI_STATUS Status; + USB_BOT_DEVICE *UsbBotDev; + EFI_USB_ATAPI_PROTOCOL *UsbAtapi; + + // + // This is a device driver, so ChildHandle must be NULL. + // + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + + // + // Get the device context + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsbAtapiProtocolGuid, + (VOID **) &UsbAtapi, + gUsbBotDriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + UsbBotDev = USB_BOT_DEVICE_FROM_THIS (UsbAtapi); + + return LookupUnicodeString ( + Language, + gUsbBotComponentName.SupportedLanguages, + UsbBotDev->ControllerNameTable, + ControllerName + ); + +} diff --git a/EdkModulePkg/Bus/Usb/UsbBot/Dxe/UsbBot.mbd b/EdkModulePkg/Bus/Usb/UsbBot/Dxe/UsbBot.mbd new file mode 100644 index 0000000000..1d18c75266 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBot/Dxe/UsbBot.mbd @@ -0,0 +1,43 @@ + + + + + UsbBot + B40612B9-A063-11d4-9A3A-0090273FC14D + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:18 + + + UefiBootServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + EdkDxePrintLib + BaseLib + EdkUsbLib + DxeMemoryAllocationLib + + diff --git a/EdkModulePkg/Bus/Usb/UsbBot/Dxe/UsbBot.msa b/EdkModulePkg/Bus/Usb/UsbBot/Dxe/UsbBot.msa new file mode 100644 index 0000000000..c00bebdce5 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBot/Dxe/UsbBot.msa @@ -0,0 +1,69 @@ + + + + + UsbBot + DXE_DRIVER + BS_DRIVER + B40612B9-A063-11d4-9A3A-0090273FC14D + 0 + Component description file for UsbBot module + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:18 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + BaseLib + UefiLib + BaseMemoryLib + EdkUsbLib + ReportStatusCodeLib + MemoryAllocationLib + UefiBootServicesTableLib + + + bot.h + bot.c + ComponentName.c + + + MdePkg + EdkModulePkg + + + DevicePath + UsbIo + UsbAtapi + + + + + + + gUsbBotDriverBinding + gUsbBotComponentName + + + diff --git a/EdkModulePkg/Bus/Usb/UsbBot/Dxe/bot.c b/EdkModulePkg/Bus/Usb/UsbBot/Dxe/bot.c new file mode 100644 index 0000000000..0aa0507c2a --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBot/Dxe/bot.c @@ -0,0 +1,1088 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + BOT.c + +Abstract: + +--*/ + +#include "bot.h" + +// +// Function prototypes +// +EFI_STATUS +EFIAPI +UsbBotDriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +// +// Bot Driver Binding Protocol +// +EFI_STATUS +EFIAPI +BotDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +BotDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +BotDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + + +EFI_DRIVER_BINDING_PROTOCOL gUsbBotDriverBinding = { + BotDriverBindingSupported, + BotDriverBindingStart, + BotDriverBindingStop, + 0x10, + NULL, + NULL +}; + +// +// Bot Protocol +// +STATIC +EFI_STATUS +BotCommandPhase ( + IN USB_BOT_DEVICE *UsbBotDev, + IN VOID *Command, + IN UINT8 CommandSize, + IN UINT32 DataTransferLength, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT16 Timeout + ); + +STATIC +EFI_STATUS +BotDataPhase ( + IN USB_BOT_DEVICE *UsbBotDev, + IN UINT32 *DataSize, + IN OUT VOID *DataBuffer, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT16 Timeout + ); + +STATIC +EFI_STATUS +BotStatusPhase ( + IN USB_BOT_DEVICE *UsbBotDev, + OUT UINT8 *TransferStatus, + IN UINT16 Timeout + ); + +// +// USB Atapi protocol prototype +// +STATIC +EFI_STATUS +EFIAPI +BotAtapiCommand ( + IN EFI_USB_ATAPI_PROTOCOL *This, + IN VOID *Command, + IN UINT8 CommandSize, + IN VOID *DataBuffer, + IN UINT32 BufferLength, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT16 TimeOutInMilliSeconds + ); + +STATIC +EFI_STATUS +EFIAPI +BotMassStorageReset ( + IN EFI_USB_ATAPI_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +VOID +BotReportStatusCode ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN EFI_STATUS_CODE_TYPE CodeType, + IN EFI_STATUS_CODE_VALUE Value + ); + +STATIC EFI_USB_ATAPI_PROTOCOL BotAtapiProtocol = { + BotAtapiCommand, + BotMassStorageReset, + 0 +}; + +EFI_STATUS +EFIAPI +BotDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + Test to see if this driver supports ControllerHandle. Any ControllerHandle + than contains a BlockIo and DiskIo protocol can be supported. + + Arguments: + This - Protocol instance pointer. + ControllerHandle - Handle of device to test + RemainingDevicePath - Not used + + Returns: + EFI_SUCCESS - This driver supports this device + EFI_ALREADY_STARTED - This driver is already running on this device + other - This driver does not support this device + +--*/ +{ + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + + // + // Check if the Controller supports USB IO protocol + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + (VOID **) &UsbIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Get the Default interface descriptor, now we only + // suppose interface 1 + // + Status = UsbIo->UsbGetInterfaceDescriptor ( + UsbIo, + &InterfaceDescriptor + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + // + // Check if it is a BOT type Mass Storage Device + // + if ((InterfaceDescriptor.InterfaceClass != 0x08) || + (InterfaceDescriptor.InterfaceProtocol != BOT)) { + Status = EFI_UNSUPPORTED; + goto Exit; + } + +Exit: + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + return Status; +} + +EFI_STATUS +EFIAPI +BotDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + 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. + + Arguments: + This - Protocol instance pointer. + ControllerHandle - Handle of device to bind driver to + RemainingDevicePath - Not used + + Returns: + EFI_SUCCESS - This driver is added to DeviceHandle + EFI_ALREADY_STARTED - This driver is already running on DeviceHandle + EFI_OUT_OF_RESOURCES- Can't allocate the memory resource + other - This driver does not support this device + +--*/ +{ + USB_BOT_DEVICE *UsbBotDev; + UINT8 Index; + EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDescriptor; + EFI_USB_INTERFACE_DESCRIPTOR *InterfaceDescriptor; + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIo; + + // + // Check if the Controller supports USB IO protocol + // + UsbBotDev = NULL; + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + (VOID **) &UsbIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + InterfaceDescriptor = AllocateZeroPool (sizeof (EFI_USB_INTERFACE_DESCRIPTOR)); + if (InterfaceDescriptor == NULL) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + return EFI_OUT_OF_RESOURCES; + } + // + // Get the controller interface descriptor, + // + Status = UsbIo->UsbGetInterfaceDescriptor ( + UsbIo, + InterfaceDescriptor + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (InterfaceDescriptor); + goto ErrorExit; + } + + BotAtapiProtocol.CommandProtocol = InterfaceDescriptor->InterfaceSubClass; + + UsbBotDev = AllocateZeroPool (sizeof (USB_BOT_DEVICE)); + if (UsbBotDev == NULL) { + Status = EFI_OUT_OF_RESOURCES; + gBS->FreePool (InterfaceDescriptor); + goto ErrorExit; + } + + UsbBotDev->Signature = USB_BOT_DEVICE_SIGNATURE; + UsbBotDev->UsbIo = UsbIo; + UsbBotDev->InterfaceDescriptor = InterfaceDescriptor; + CopyMem (&UsbBotDev->UsbAtapiProtocol, &BotAtapiProtocol, sizeof (BotAtapiProtocol)); + + // + // Get the Device Path Protocol on Controller's handle + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + (VOID **) &UsbBotDev->DevicePath, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + for (Index = 0; Index < InterfaceDescriptor->NumEndpoints; Index++) { + EndpointDescriptor = AllocatePool (sizeof (EFI_USB_INTERFACE_DESCRIPTOR)); + if (EndpointDescriptor == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + + UsbIo->UsbGetEndpointDescriptor ( + UsbIo, + Index, + EndpointDescriptor + ); + + // + // We parse bulk endpoint + // + if ((EndpointDescriptor->Attributes & 0x03) == 0x02) { + if ((EndpointDescriptor->EndpointAddress & 0x80) != 0) { + UsbBotDev->BulkInEndpointDescriptor = EndpointDescriptor; + } else { + UsbBotDev->BulkOutEndpointDescriptor = EndpointDescriptor; + } + + continue; + } + + gBS->FreePool (EndpointDescriptor); + } + // + // Double check we have these endpoint descriptors + // + if (!(UsbBotDev->BulkInEndpointDescriptor && + UsbBotDev->BulkOutEndpointDescriptor)) { + Status = EFI_DEVICE_ERROR; + goto ErrorExit; + } + // + // After installing Usb-Atapi protocol onto this handle + // it will be called by upper layer drivers such as Fat + // + BotReportStatusCode ( + UsbBotDev->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_ENABLE) + ); + + // + // Install Usb-Atapi Protocol onto the handle + // + Status = gBS->InstallProtocolInterface ( + &ControllerHandle, + &gEfiUsbAtapiProtocolGuid, + EFI_NATIVE_INTERFACE, + &UsbBotDev->UsbAtapiProtocol + ); + + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + UsbBotDev->ControllerNameTable = NULL; + AddUnicodeString ( + "eng", + gUsbBotComponentName.SupportedLanguages, + &UsbBotDev->ControllerNameTable, + (CHAR16 *) L"Usb Bot Mass Storage" + ); + + return EFI_SUCCESS; + +ErrorExit: + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + + if (UsbBotDev != NULL) { + if (UsbBotDev->InterfaceDescriptor != NULL) { + gBS->FreePool (UsbBotDev->InterfaceDescriptor); + } + + if (UsbBotDev->BulkInEndpointDescriptor != NULL) { + gBS->FreePool (UsbBotDev->BulkInEndpointDescriptor); + } + + if (UsbBotDev->BulkOutEndpointDescriptor != NULL) { + gBS->FreePool (UsbBotDev->BulkOutEndpointDescriptor); + } + + gBS->FreePool (UsbBotDev); + } + + return Status; +} + +EFI_STATUS +EFIAPI +BotDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + + Routine Description: + Stop this driver on ControllerHandle. Support stoping any child handles + created by this driver. + + Arguments: + This - Protocol instance pointer. + ControllerHandle - Handle of device to stop driver on + NumberOfChildren - Number of Children in the ChildHandleBuffer + ChildHandleBuffer - List of handles for the children we need to stop. + + Returns: + EFI_SUCCESS - This driver is removed DeviceHandle + EFI_UNSUPPORTED - Can't open the gEfiUsbAtapiProtocolGuid protocl + other - This driver was not removed from this device + +--*/ +{ + EFI_STATUS Status; + EFI_USB_ATAPI_PROTOCOL *BotAtapiProtocol; + USB_BOT_DEVICE *UsbBotDev; + + EFI_USB_IO_PROTOCOL *UsbIo; + + // + // Get our context back. + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsbAtapiProtocolGuid, + (VOID **) &BotAtapiProtocol, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + UsbBotDev = USB_BOT_DEVICE_FROM_THIS (BotAtapiProtocol); + + // + // After installing Usb-Atapi protocol onto this handle + // it will be called by upper layer drivers such as Fat + // + UsbIo = UsbBotDev->UsbIo; + + BotReportStatusCode ( + UsbBotDev->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_DISABLE) + ); + + // + // Uninstall protocol + // + Status = gBS->UninstallProtocolInterface ( + ControllerHandle, + &gEfiUsbAtapiProtocolGuid, + &UsbBotDev->UsbAtapiProtocol + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + // + // Free all allocated resources + // + if (UsbBotDev->InterfaceDescriptor != NULL) { + gBS->FreePool (UsbBotDev->InterfaceDescriptor); + } + + if (UsbBotDev->BulkInEndpointDescriptor != NULL) { + gBS->FreePool (UsbBotDev->BulkInEndpointDescriptor); + } + + if (UsbBotDev->BulkOutEndpointDescriptor != NULL) { + gBS->FreePool (UsbBotDev->BulkOutEndpointDescriptor); + } + + if (UsbBotDev->ControllerNameTable) { + FreeUnicodeStringTable (UsbBotDev->ControllerNameTable); + } + + gBS->FreePool (UsbBotDev); + + return Status; +} + +STATIC +EFI_STATUS +BotRecoveryReset ( + IN USB_BOT_DEVICE *UsbBotDev + ) +/*++ + +Routine Description: + + Bot reset routine + +Arguments: + + UsbBotDev - USB_BOT_DEVICE pointer + +Returns: + EFI_SUCCESS - Success the operation + +--*/ +{ + EFI_STATUS Status; + UINT32 Result; + EFI_USB_DEVICE_REQUEST Request; + EFI_USB_IO_PROTOCOL *UsbIo; + UINT8 EndpointAddr; + + UsbIo = UsbBotDev->UsbIo; + + BotReportStatusCode ( + UsbBotDev->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_RESET) + ); + + ZeroMem (&Request, sizeof (EFI_USB_DEVICE_REQUEST)); + + // + // See BOT specification + // + Request.RequestType = 0x21; + Request.Request = 0xFF; + + Status = UsbIo->UsbControlTransfer ( + UsbIo, + &Request, + EfiUsbNoData, + TIMEOUT_VALUE, + NULL, + 0, + &Result + ); + + gBS->Stall (100 * 1000); + + if (!EFI_ERROR (Status)) { + // + // clear bulk in endpoint stall feature + // + EndpointAddr = UsbBotDev->BulkInEndpointDescriptor->EndpointAddress; + + Status = UsbClearEndpointHalt ( + UsbIo, + EndpointAddr, + &Result + ); + + // + // clear bulk out endpoint stall feature + // + EndpointAddr = UsbBotDev->BulkOutEndpointDescriptor->EndpointAddress; + Status = UsbClearEndpointHalt ( + UsbIo, + EndpointAddr, + &Result + ); + } + + return Status; +} +// +// Bot Protocol Implementation +// +STATIC +EFI_STATUS +BotCommandPhase ( + IN USB_BOT_DEVICE *UsbBotDev, + IN VOID *Command, + IN UINT8 CommandSize, + IN UINT32 DataTransferLength, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT16 Timeout + ) +/*++ + + Routine Description: + Send ATAPI command through BOT interface. + + Parameters: + UsbBotDev - USB_BOT_DEVICE + Command - command packet + CommandSize - Command size + DataTransferLength - Data Transfer Length + Direction - Data IN/OUT/NODATA + Timeout - Time out value in milliseconds + Return Values: + EFI_SUCCESS + Others + +--*/ +{ + CBW cbw; + EFI_STATUS Status; + UINT32 Result; + EFI_USB_IO_PROTOCOL *UsbIo; + UINTN DataSize; + + UsbIo = UsbBotDev->UsbIo; + + ZeroMem (&cbw, sizeof (CBW)); + + // + // Fill the command block, detailed see BOT spec + // + cbw.dCBWSignature = CBWSIG; + cbw.dCBWTag = 0x01; + cbw.dCBWDataTransferLength = DataTransferLength; + cbw.bmCBWFlags = (UINT8) (Direction << 7); + cbw.bCBWCBLength = CommandSize; + + CopyMem (cbw.CBWCB, Command, CommandSize); + + DataSize = sizeof (CBW); + + Status = UsbIo->UsbBulkTransfer ( + UsbIo, + (UsbBotDev->BulkOutEndpointDescriptor)->EndpointAddress, + &cbw, + &DataSize, + Timeout, + &Result + ); + if (EFI_ERROR (Status)) { + // + // Command phase fail, we need to recovery reset this device + // + BotRecoveryReset (UsbBotDev); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +BotDataPhase ( + IN USB_BOT_DEVICE *UsbBotDev, + IN UINT32 *DataSize, + IN OUT VOID *DataBuffer, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT16 Timeout + ) +/*++ + + Routine Description: + Get/Send Data through BOT interface + + Parameters: + UsbBotDev - USB_BOT_DEVICE pointer + DataSize - Data size + DataBuffer - Data buffer pointer + Direction - IN/OUT/NODATA + Timeout - Time out value in milliseconds + Return Value: + EFI_SUCCESS + Others + +--*/ +{ + EFI_STATUS Status; + UINT32 Result; + EFI_USB_IO_PROTOCOL *UsbIo; + UINT8 EndpointAddr; + UINTN Remain; + UINTN Increment; + UINT32 MaxPacketLen; + UINT8 *BufferPtr; + UINTN TransferredSize; + UINTN RetryTimes; + UINTN MaxRetry; + UINTN BlockSize; + UINTN PackageNum; + + UsbIo = UsbBotDev->UsbIo; + Remain = *DataSize; + BufferPtr = (UINT8 *) DataBuffer; + TransferredSize = 0; + MaxRetry = 10; + PackageNum = 15; + + // + // retrieve the the max packet length of the given endpoint + // + if (Direction == EfiUsbDataIn) { + MaxPacketLen = (UsbBotDev->BulkInEndpointDescriptor)->MaxPacketSize; + EndpointAddr = (UsbBotDev->BulkInEndpointDescriptor)->EndpointAddress; + } else { + MaxPacketLen = (UsbBotDev->BulkOutEndpointDescriptor)->MaxPacketSize; + EndpointAddr = (UsbBotDev->BulkOutEndpointDescriptor)->EndpointAddress; + } + + RetryTimes = MaxRetry; + BlockSize = PackageNum * MaxPacketLen; + while (Remain > 0) { + // + // Using 15 packets to aVOID Bitstuff error + // + if (Remain > PackageNum * MaxPacketLen) { + Increment = BlockSize; + } else { + Increment = Remain; + } + + Status = UsbIo->UsbBulkTransfer ( + UsbIo, + EndpointAddr, + BufferPtr, + &Increment, + Timeout, + &Result + ); + + TransferredSize += Increment; + + if (EFI_ERROR (Status)) { + RetryTimes--; + if ((RetryTimes == 0) || ((Result & EFI_USB_ERR_TIMEOUT) == 0)) { + goto ErrorExit; + } + + TransferredSize -= Increment; + continue; + } else { + // + // we try MaxTetry times for every bulk transfer + // + RetryTimes = MaxRetry; + } + + BufferPtr += Increment; + Remain -= Increment; + if (Increment < BlockSize && TransferredSize <= *DataSize) { + // + // we get to the end of transter and transter size is + // less than requriedsize + // + break; + } + } + + *DataSize = (UINT32) TransferredSize; + + return EFI_SUCCESS; + +ErrorExit: + if (Direction == EfiUsbDataIn) { + BotReportStatusCode ( + UsbBotDev->DevicePath, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_EC_INPUT_ERROR) + ); + } else { + BotReportStatusCode ( + UsbBotDev->DevicePath, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_EC_OUTPUT_ERROR) + ); + } + + if ((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) { + // + // just endpoint stall happens + // + UsbClearEndpointHalt ( + UsbIo, + EndpointAddr, + &Result + ); + } + + *DataSize = (UINT32) TransferredSize; + + return Status; + +} + +STATIC +EFI_STATUS +BotStatusPhase ( + IN USB_BOT_DEVICE *UsbBotDev, + OUT UINT8 *TransferStatus, + IN UINT16 Timeout + ) +/*++ + + Routine Description: + Get transfer status through BOT interface + + Parameters: + UsbBotDev - USB_BOT_DEVICE pointer + TransferStatus - TransferStatus + Timeout - Time out value in milliseconds + Return Value: + EFI_SUCCESS + Others + +--*/ +{ + CSW csw; + EFI_STATUS Status; + UINT32 Result; + EFI_USB_IO_PROTOCOL *UsbIo; + UINT8 EndpointAddr; + UINTN DataSize; + + UsbIo = UsbBotDev->UsbIo; + + ZeroMem (&csw, sizeof (CSW)); + + EndpointAddr = (UsbBotDev->BulkInEndpointDescriptor)->EndpointAddress; + + DataSize = sizeof (CSW); + + // + // Get the status field from bulk transfer + // + Status = UsbIo->UsbBulkTransfer ( + UsbIo, + EndpointAddr, + &csw, + &DataSize, + Timeout, + &Result + ); + if (EFI_ERROR (Status)) { + if ((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) { + // + // just endpoint stall happens + // + UsbClearEndpointHalt ( + UsbIo, + EndpointAddr, + &Result + ); + } + + ZeroMem (&csw, sizeof (CSW)); + + EndpointAddr = (UsbBotDev->BulkInEndpointDescriptor)->EndpointAddress; + + DataSize = sizeof (CSW); + Status = UsbIo->UsbBulkTransfer ( + UsbIo, + EndpointAddr, + &csw, + &DataSize, + Timeout, + &Result + ); + if (EFI_ERROR (Status)) { + if ((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) { + UsbClearEndpointHalt ( + UsbIo, + EndpointAddr, + &Result + ); + } + + return Status; + } + } + + if (csw.dCSWSignature == CSWSIG) { + *TransferStatus = csw.bCSWStatus; + } else { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} +// +// Usb Atapi Protocol implementation +// +EFI_STATUS +EFIAPI +BotAtapiCommand ( + IN EFI_USB_ATAPI_PROTOCOL *This, + IN VOID *Command, + IN UINT8 CommandSize, + IN VOID *DataBuffer, + IN UINT32 BufferLength, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT16 TimeOutInMilliSeconds + ) +/*++ + + Routine Description: + Send ATAPI command using BOT protocol. + + Arguments: + This - Protocol instance pointer. + Command - Command buffer + CommandSize - Size of Command Buffer + DataBuffer - Data buffer + BufferLength - Length of Data buffer + Direction - Data direction of this command + TimeoutInMilliSeconds - Timeout value in ms + + Returns: + EFI_SUCCESS - Command succeeded. + EFI_DEVICE_ERROR - Command failed. + +--*/ +{ + EFI_STATUS Status; + EFI_STATUS BotDataStatus; + UINT8 TransferStatus; + USB_BOT_DEVICE *UsbBotDev; + UINT32 BufferSize; + + BotDataStatus = EFI_SUCCESS; + TransferStatus = 0; + + // + // Get the context + // + UsbBotDev = USB_BOT_DEVICE_FROM_THIS (This); + + // + // First send ATAPI command through Bot + // + Status = BotCommandPhase ( + UsbBotDev, + 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 ( + UsbBotDev, + &BufferSize, + DataBuffer, + Direction, + (UINT16) (TimeOutInMilliSeconds) + ); + + break; + + case EfiUsbNoData: + break; + } + + // + // Status Phase + // + Status = BotStatusPhase ( + UsbBotDev, + &TransferStatus, + TimeOutInMilliSeconds + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + if (TransferStatus == 0x02) { + // + // Phase error + // + BotRecoveryReset (UsbBotDev); + return EFI_DEVICE_ERROR; + } + + if (TransferStatus == 0x01) { + return EFI_DEVICE_ERROR; + } + + return BotDataStatus; +} + +EFI_STATUS +EFIAPI +BotMassStorageReset ( + IN EFI_USB_ATAPI_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + + Routine Description: + Reset Bot Devices + + Arguments: + This - Protocol instance pointer. + ExtendedVerification - TRUE if we need to do strictly reset. + + Returns: + EFI_SUCCESS - Command succeeded. + EFI_DEVICE_ERROR - Command failed. + +--*/ +{ + EFI_STATUS Status; + USB_BOT_DEVICE *UsbBotDev; + EFI_USB_IO_PROTOCOL *UsbIo; + + UsbBotDev = USB_BOT_DEVICE_FROM_THIS (This); + UsbIo = UsbBotDev->UsbIo; + + if (ExtendedVerification) { + // + // If we need to do strictly reset, reset its parent hub port + // + Status = UsbIo->UsbPortReset (UsbIo); + if (EFI_ERROR (Status)) { + return Status; + } + } + + Status = BotRecoveryReset (UsbBotDev); + + return Status; +} + +VOID +BotReportStatusCode ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN EFI_STATUS_CODE_TYPE CodeType, + IN EFI_STATUS_CODE_VALUE Value + ) +/*++ + + Routine Description: + Report Status Code in Usb Bot Driver + + Arguments: + DevicePath - Use this to get Device Path + CodeType - Status Code Type + CodeValue - Status Code Value + + Returns: + None + +--*/ +{ + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + CodeType, + Value, + DevicePath + ); +} diff --git a/EdkModulePkg/Bus/Usb/UsbBot/Dxe/bot.h b/EdkModulePkg/Bus/Usb/UsbBot/Dxe/bot.h new file mode 100644 index 0000000000..575dfbea05 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBot/Dxe/bot.h @@ -0,0 +1,78 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + BOT.h + +Abstract: + +--*/ + +#ifndef _BOT_H +#define _BOT_H + + +#include + +#pragma pack(1) +// +// Bulk Only device protocol +// +typedef struct { + UINT32 dCBWSignature; + UINT32 dCBWTag; + UINT32 dCBWDataTransferLength; + UINT8 bmCBWFlags; + UINT8 bCBWLUN; + UINT8 bCBWCBLength; + UINT8 CBWCB[16]; +} CBW; + +typedef struct { + UINT32 dCSWSignature; + UINT32 dCSWTag; + UINT32 dCSWDataResidue; + UINT8 bCSWStatus; +} CSW; + +#pragma pack() + +#define USB_BOT_DEVICE_SIGNATURE EFI_SIGNATURE_32 ('u', 'b', 'o', 't') + +typedef struct { + UINTN Signature; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_USB_ATAPI_PROTOCOL UsbAtapiProtocol; + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_USB_INTERFACE_DESCRIPTOR *InterfaceDescriptor; + EFI_USB_ENDPOINT_DESCRIPTOR *BulkInEndpointDescriptor; + EFI_USB_ENDPOINT_DESCRIPTOR *BulkOutEndpointDescriptor; + EFI_UNICODE_STRING_TABLE *ControllerNameTable; +} USB_BOT_DEVICE; + +#define USB_BOT_DEVICE_FROM_THIS(a) \ + CR(a, USB_BOT_DEVICE, UsbAtapiProtocol, USB_BOT_DEVICE_SIGNATURE) + +// +// Status code, see Usb Bot device spec +// +#define CSWSIG 0x53425355 +#define CBWSIG 0x43425355 + +// +// Global Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gUsbBotDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gUsbBotComponentName; +extern EFI_GUID gUsbBotDriverGuid; + +#endif diff --git a/EdkModulePkg/Bus/Usb/UsbBot/Dxe/build.xml b/EdkModulePkg/Bus/Usb/UsbBot/Dxe/build.xml new file mode 100644 index 0000000000..aab054b222 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBot/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Bus/Usb/UsbBus/Dxe/ComponentName.c b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/ComponentName.c new file mode 100644 index 0000000000..347a0003f4 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/ComponentName.c @@ -0,0 +1,154 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ComponentName.c + +Abstract: + +--*/ + +#include "UsbBus.h" + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +UsbBusComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +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 +// +EFI_COMPONENT_NAME_PROTOCOL gUsbBusComponentName = { + UsbBusComponentNameGetDriverName, + UsbBusComponentNameGetControllerName, + "eng" +}; + +STATIC EFI_UNICODE_STRING_TABLE mUsbBusDriverNameTable[] = { + { "eng", (CHAR16 *) L"USB Bus Driver" }, + { NULL , NULL } +}; + +EFI_STATUS +EFIAPI +UsbBusComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gUsbBusComponentName.SupportedLanguages, + mUsbBusDriverNameTable, + DriverName + ); +} + +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 + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + 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. + 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. + + Returns: + 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. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return EFI_UNSUPPORTED; +} diff --git a/EdkModulePkg/Bus/Usb/UsbBus/Dxe/UsbBus.mbd b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/UsbBus.mbd new file mode 100644 index 0000000000..4e46c13f97 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/UsbBus.mbd @@ -0,0 +1,44 @@ + + + + + UsbBus + 240612B7-A063-11d4-9A3A-0090273FC14D + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:18 + + + UefiBootServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + EdkDxePrintLib + BaseLib + EdkUsbLib + DxeMemoryAllocationLib + UefiDevicePathLib + + diff --git a/EdkModulePkg/Bus/Usb/UsbBus/Dxe/UsbBus.msa b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/UsbBus.msa new file mode 100644 index 0000000000..f035473c61 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/UsbBus.msa @@ -0,0 +1,76 @@ + + + + + UsbBus + DXE_DRIVER + BS_DRIVER + 240612B7-A063-11d4-9A3A-0090273FC14D + 0 + Component description file for UsbBus module + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:18 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + BaseLib + UefiLib + BaseMemoryLib + EdkUsbLib + ReportStatusCodeLib + MemoryAllocationLib + UefiBootServicesTableLib + DevicePathLib + + + UsbBus.h + usbutil.h + hub.h + UsbBus.c + UsbIo.c + usb.c + usbutil.c + Hub.c + ComponentName.c + + + MdePkg + EdkModulePkg + + + UsbIo + UsbHc + DevicePath + + + + + + + gUsbBusDriverBinding + gUsbBusComponentName + + + diff --git a/EdkModulePkg/Bus/Usb/UsbBus/Dxe/build.xml b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/build.xml new file mode 100644 index 0000000000..508c7582b3 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Bus/Usb/UsbBus/Dxe/hub.c b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/hub.c new file mode 100644 index 0000000000..fd9e673b6c --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/hub.c @@ -0,0 +1,507 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + Module Name: + + Hub.c + + Abstract: + + Usb Hub Request + + Revision History + +--*/ + +#include "usbbus.h" + +EFI_STATUS +HubGetPortStatus ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 Port, + OUT UINT32 *PortStatus + ) +/*++ + + Routine Description: + Get a given hub port status + + Arguments: + UsbIo - EFI_USB_IO_PROTOCOL instance + Port - Usb hub port number (starting from 1). + PortStatus - Current Hub port status and change status. + + Returns: + EFI_SUCCESS + EFI_DEVICE + EFI_TIME_OUT + EFI_INVALID_PARAMETER + +--*/ +{ + EFI_USB_DEVICE_REQUEST DevReq; + EFI_STATUS EfiStatus; + UINT32 UsbStatus; + UINT32 Timeout; + + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); + + // + // Fill Device request packet + // + DevReq.RequestType = HUB_GET_PORT_STATUS_REQ_TYPE; + DevReq.Request = HUB_GET_PORT_STATUS; + DevReq.Value = 0; + DevReq.Index = Port; + DevReq.Length = sizeof (UINT32); + + Timeout = 3000; + + EfiStatus = UsbIo->UsbControlTransfer ( + UsbIo, + &DevReq, + EfiUsbDataIn, + Timeout, + PortStatus, + sizeof (UINT32), + &UsbStatus + ); + + return EfiStatus; +} + +EFI_STATUS +HubSetPortFeature ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 Port, + IN UINT8 Value + ) +/*++ + + Routine Description: + Set specified feature to a give hub port + + Arguments: + UsbIo - EFI_USB_IO_PROTOCOL instance + Port - Usb hub port number (starting from 1). + Value - New feature value. + + Returns: + EFI_SUCCESS + EFI_DEVICE + EFI_TIME_OUT + EFI_INVALID_PARAMETER + +--*/ +{ + EFI_USB_DEVICE_REQUEST DevReq; + EFI_STATUS EfiStatus; + UINT32 UsbStatus; + UINT32 Timeout; + + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); + + // + // Fill Device request packet + // + DevReq.RequestType = HUB_SET_PORT_FEATURE_REQ_TYPE; + DevReq.Request = HUB_SET_PORT_FEATURE; + DevReq.Value = Value; + DevReq.Index = Port; + DevReq.Length = 0; + + Timeout = 3000; + EfiStatus = UsbIo->UsbControlTransfer ( + UsbIo, + &DevReq, + EfiUsbNoData, + Timeout, + NULL, + 0, + &UsbStatus + ); + + return EfiStatus; +} + +EFI_STATUS +HubClearPortFeature ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 Port, + IN UINT8 Value + ) +/*++ + + Routine Description: + Clear a specified feature of a given hub port + + Arguments: + UsbIo - EFI_USB_IO_PROTOCOL instance + Port - Usb hub port number (starting from 1). + Value - Feature value that will be cleared from + that hub port. + + Returns: + EFI_SUCCESS + EFI_DEVICE + EFI_TIME_OUT + EFI_INVALID_PARAMETER + +--*/ +{ + EFI_USB_DEVICE_REQUEST DevReq; + EFI_STATUS EfiStatus; + UINT32 UsbStatus; + UINT32 Timeout; + + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); + + // + // Fill Device request packet + // + DevReq.RequestType = HUB_CLEAR_FEATURE_PORT_REQ_TYPE; + DevReq.Request = HUB_CLEAR_FEATURE_PORT; + DevReq.Value = Value; + DevReq.Index = Port; + DevReq.Length = 0; + + Timeout = 3000; + EfiStatus = UsbIo->UsbControlTransfer ( + UsbIo, + &DevReq, + EfiUsbNoData, + Timeout, + NULL, + 0, + &UsbStatus + ); + + return EfiStatus; +} + +EFI_STATUS +HubGetHubStatus ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + OUT UINT32 *HubStatus + ) +/*++ + + Routine Description: + Get Hub Status + + Arguments: + UsbIo - EFI_USB_IO_PROTOCOL instance + HubStatus - Current Hub status and change status. + + Returns: + EFI_SUCCESS + EFI_DEVICE + EFI_TIME_OUT + +--*/ +{ + EFI_USB_DEVICE_REQUEST DevReq; + EFI_STATUS EfiStatus; + UINT32 UsbStatus; + UINT32 Timeout; + + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); + + // + // Fill Device request packet + // + DevReq.RequestType = HUB_GET_HUB_STATUS_REQ_TYPE; + DevReq.Request = HUB_GET_HUB_STATUS; + DevReq.Value = 0; + DevReq.Index = 0; + DevReq.Length = sizeof (UINT32); + + Timeout = 3000; + EfiStatus = UsbIo->UsbControlTransfer ( + UsbIo, + &DevReq, + EfiUsbDataIn, + Timeout, + HubStatus, + sizeof (UINT32), + &UsbStatus + ); + + return EfiStatus; +} + +EFI_STATUS +HubSetHubFeature ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 Value + ) +/*++ + + Routine Description: + Set a specified feature to the hub + + Arguments: + UsbIo - EFI_USB_IO_PROTOCOL instance + Value - Feature value that will be set to the hub. + + Returns: + EFI_SUCCESS + EFI_DEVICE + EFI_TIME_OUT + +--*/ +{ + EFI_USB_DEVICE_REQUEST DevReq; + EFI_STATUS EfiStatus; + UINT32 UsbStatus; + UINT32 Timeout; + + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); + + // + // Fill Device request packet + // + DevReq.RequestType = HUB_SET_HUB_FEATURE_REQ_TYPE; + DevReq.Request = HUB_SET_HUB_FEATURE; + DevReq.Value = Value; + DevReq.Index = 0; + DevReq.Length = 0; + + Timeout = 3000; + EfiStatus = UsbIo->UsbControlTransfer ( + UsbIo, + &DevReq, + EfiUsbNoData, + Timeout, + NULL, + 0, + &UsbStatus + ); + + return EfiStatus; +} + +EFI_STATUS +HubClearHubFeature ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 Value + ) +/*++ + + Routine Description: + Set a specified feature to the hub + + Arguments: + UsbIo - EFI_USB_IO_PROTOCOL instance + Value - Feature value that will be cleared from the hub. + + Returns: + EFI_SUCCESS + EFI_DEVICE + EFI_TIME_OUT + +--*/ +{ + EFI_USB_DEVICE_REQUEST DevReq; + EFI_STATUS EfiStatus; + UINT32 UsbStatus; + UINT32 Timeout; + + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); + + // + // Fill Device request packet + // + DevReq.RequestType = HUB_CLEAR_FEATURE_REQ_TYPE; + DevReq.Request = HUB_CLEAR_FEATURE; + DevReq.Value = Value; + DevReq.Index = 0; + DevReq.Length = 0; + + Timeout = 3000; + EfiStatus = UsbIo->UsbControlTransfer ( + UsbIo, + &DevReq, + EfiUsbNoData, + Timeout, + NULL, + 0, + &UsbStatus + ); + + return EfiStatus; + +} + +EFI_STATUS +GetHubDescriptor ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINTN DescriptorSize, + OUT EFI_USB_HUB_DESCRIPTOR *HubDescriptor + ) +/*++ + + Routine Description: + Get the hub descriptor + + Arguments: + UsbIo - EFI_USB_IO_PROTOCOL instance + DescriptorSize - The length of Hub Descriptor buffer. + HubDescriptor - Caller allocated buffer to store the hub descriptor + if successfully returned. + + Returns: + EFI_SUCCESS + EFI_DEVICE + EFI_TIME_OUT + +--*/ +{ + EFI_USB_DEVICE_REQUEST DevReq; + EFI_STATUS EfiStatus; + UINT32 UsbStatus; + UINT32 Timeout; + + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); + + // + // Fill Device request packet + // + DevReq.RequestType = USB_RT_HUB | 0x80; + DevReq.Request = HUB_GET_DESCRIPTOR; + DevReq.Value = USB_DT_HUB << 8; + DevReq.Index = 0; + DevReq.Length = (UINT16) DescriptorSize; + + Timeout = 3000; + EfiStatus = UsbIo->UsbControlTransfer ( + UsbIo, + &DevReq, + EfiUsbDataIn, + Timeout, + HubDescriptor, + (UINT16) DescriptorSize, + &UsbStatus + ); + + return EfiStatus; + +} + +EFI_STATUS +DoHubConfig ( + IN USB_IO_CONTROLLER_DEVICE *HubController + ) +/*++ + + Routine Description: + Configure the hub + + Arguments: + HubController - Indicating the hub controller device that + will be configured + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + +--*/ +{ + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_USB_HUB_DESCRIPTOR HubDescriptor; + EFI_STATUS Status; + EFI_USB_HUB_STATUS HubStatus; + UINTN Index; + UINT32 PortStatus; + + UsbIo = &HubController->UsbIo; + + ZeroMem (&HubDescriptor, sizeof (HubDescriptor)); + + // + // First get the hub descriptor length + // + Status = GetHubDescriptor (UsbIo, 2, &HubDescriptor); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // First get the whole descriptor, then + // get the number of hub ports + // + Status = GetHubDescriptor ( + UsbIo, + HubDescriptor.Length, + &HubDescriptor + ); + if (EFI_ERROR (Status)) { + DEBUG ((gUSBErrorLevel, "Get hub descriptor fail\n")); + return EFI_DEVICE_ERROR; + } + + HubController->DownstreamPorts = HubDescriptor.NbrPorts; + + Status = HubGetHubStatus (UsbIo, (UINT32 *) &HubStatus); + if (EFI_ERROR (Status)) { + DEBUG ((gUSBErrorLevel, "Get hub status fail when configure\n")); + return EFI_DEVICE_ERROR; + } + + // + // Get all hub ports status + // + for (Index = 0; Index < HubController->DownstreamPorts; Index++) { + + Status = HubGetPortStatus (UsbIo, (UINT8) (Index + 1), &PortStatus); + if (EFI_ERROR (Status)) { + continue; + } + } + // + // Power all the hub ports + // + for (Index = 0; Index < HubController->DownstreamPorts; Index++) { + Status = HubSetPortFeature ( + UsbIo, + (UINT8) (Index + 1), + EfiUsbPortPower + ); + if (EFI_ERROR (Status)) { + continue; + } + } + + // + // Clear Hub Status Change + // + Status = HubGetHubStatus (UsbIo, (UINT32 *) &HubStatus); + if (EFI_ERROR (Status)) { + DEBUG ((gUSBErrorLevel, "Get hub status fail\n")); + return EFI_DEVICE_ERROR; + } else { + // + // Hub power supply change happens + // + if (HubStatus.HubChange & HUB_CHANGE_LOCAL_POWER) { + HubClearHubFeature (UsbIo, C_HUB_LOCAL_POWER); + } + // + // Hub change overcurrent happens + // + if (HubStatus.HubChange & HUB_CHANGE_OVERCURRENT) { + HubClearHubFeature (UsbIo, C_HUB_OVER_CURRENT); + } + } + + return EFI_SUCCESS; + +} diff --git a/EdkModulePkg/Bus/Usb/UsbBus/Dxe/hub.h b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/hub.h new file mode 100644 index 0000000000..4545d71c6a --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/hub.h @@ -0,0 +1,138 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + Module Name: + + Hub.h + + Abstract: + + Constants definitions for Usb Hub + + Revision History + +--*/ + +#ifndef _HUB_H +#define _HUB_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 + +// +// Hub specific request +// +#define HUB_CLEAR_FEATURE 0x01 +#define HUB_CLEAR_FEATURE_REQ_TYPE 0x20 + +#define HUB_CLEAR_FEATURE_PORT 0x01 +#define HUB_CLEAR_FEATURE_PORT_REQ_TYPE 0x23 + +#define HUB_GET_BUS_STATE 0x02 +#define HUB_GET_BUS_STATE_REQ_TYPE 0xA3 + +#define HUB_GET_DESCRIPTOR 0x06 +#define HUB_GET_DESCRIPTOR_REQ_TYPE 0xA0 + +#define HUB_GET_HUB_STATUS 0x00 +#define HUB_GET_HUB_STATUS_REQ_TYPE 0xA0 + +#define HUB_GET_PORT_STATUS 0x00 +#define HUB_GET_PORT_STATUS_REQ_TYPE 0xA3 + +#define HUB_SET_DESCRIPTOR 0x07 +#define HUB_SET_DESCRIPTOR_REQ_TYPE 0x20 + +#define HUB_SET_HUB_FEATURE 0x03 +#define HUB_SET_HUB_FEATURE_REQ_TYPE 0x20 + +#define HUB_SET_PORT_FEATURE 0x03 +#define HUB_SET_PORT_FEATURE_REQ_TYPE 0x23 + +#pragma pack(1) +typedef struct usb_hub_status { + UINT16 HubStatus; + UINT16 HubChange; +} EFI_USB_HUB_STATUS; +#pragma pack() + +EFI_STATUS +HubGetPortStatus ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 Port, + OUT UINT32 *PortStatus + ); + +EFI_STATUS +HubSetPortFeature ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 Port, + IN UINT8 Value + ); + +EFI_STATUS +HubSetHubFeature ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 Value + ); + +EFI_STATUS +HubGetHubStatus ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + OUT UINT32 *HubStatus + ); + +EFI_STATUS +HubClearPortFeature ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 Port, + IN UINT8 Value + ); + +EFI_STATUS +HubClearHubFeature ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 Value + ); + +EFI_STATUS +GetHubDescriptor ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINTN DescriptorSize, + OUT EFI_USB_HUB_DESCRIPTOR *HubDescriptor + ); + +#endif diff --git a/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usb.c b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usb.c new file mode 100644 index 0000000000..474e38829e --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usb.c @@ -0,0 +1,825 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + Module Name: + + Usb.c + + Abstract: + + Parse usb device configurations. + + Revision History + +--*/ + +#include "usbbus.h" + +// +// Here are some internal helper functions +// +STATIC +EFI_STATUS +GetExpectedDescriptor ( + IN UINT8 *Buffer, + IN UINTN Length, + IN UINT8 DescType, + IN UINT8 DescLength, + OUT UINTN *ParsedBytes + ); + +STATIC +EFI_STATUS +ParseThisEndpoint ( + IN ENDPOINT_DESC_LIST_ENTRY *EndpointEntry, + IN UINT8 *Buffer, + IN UINTN BufferLength, + OUT UINTN *ParsedBytes + ); + +STATIC +EFI_STATUS +ParseThisInterface ( + IN INTERFACE_DESC_LIST_ENTRY *InterfaceEntry, + IN UINT8 *Buffer, + IN UINTN *BufferLen, + OUT UINTN *ParsedBytes + ); + +STATIC +EFI_STATUS +ParseThisConfig ( + IN CONFIG_DESC_LIST_ENTRY *ConfigDescEntry, + IN UINT8 *Buffer, + IN UINTN Length + ); + +// +// Implementations +// +BOOLEAN +IsHub ( + IN USB_IO_CONTROLLER_DEVICE *Dev + ) +/*++ + + Routine Description: + Tell if a usb controller is a hub controller. + + Arguments: + Dev - UsbIoController device structure. + + Returns: + TRUE/FALSE +--*/ +{ + EFI_USB_INTERFACE_DESCRIPTOR Interface; + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_USB_ENDPOINT_DESCRIPTOR EndpointDescriptor; + UINT8 Index; + + if (Dev == NULL) { + return FALSE; + } + + UsbIo = &Dev->UsbIo; + + UsbIo->UsbGetInterfaceDescriptor ( + UsbIo, + &Interface + ); + + // + // Check classcode + // + if (Interface.InterfaceClass != 0x09) { + return FALSE; + } + + // + // Check protocol + // + if (Interface.InterfaceProtocol != 0x0) { + return FALSE; + } + + for (Index = 0; Index < Interface.NumEndpoints; Index++) { + UsbIo->UsbGetEndpointDescriptor ( + UsbIo, + Index, + &EndpointDescriptor + ); + + if ((EndpointDescriptor.EndpointAddress & 0x80) == 0) { + continue; + } + + if (EndpointDescriptor.Attributes != 0x03) { + continue; + } + + Dev->HubEndpointAddress = EndpointDescriptor.EndpointAddress; + return TRUE; + } + + return FALSE; +} + +EFI_STATUS +UsbGetStringtable ( + IN USB_IO_DEVICE *Dev + ) +/*++ + + Routine Description: + Get the string table stored in a usb device. + + Arguments: + Dev - UsbIoController device structure. + + Returns: + EFI_SUCCESS + EFI_UNSUPPORTED + EFI_OUT_OF_RESOURCES + +--*/ +{ + EFI_STATUS Result; + UINT32 Status; + EFI_USB_SUPPORTED_LANGUAGES *LanguageTable; + UINT8 *Buffer; + UINT8 *ptr; + UINTN Index; + UINTN LangTableSize; + EFI_USB_IO_PROTOCOL *UsbIo; + UINT16 TempBuffer; + + UsbIo = &(Dev->UsbController[0]->UsbIo); + + // + // We get first 2 byte of langID table, + // so we can have the whole table length + // + Result = UsbGetString ( + UsbIo, + 0, + 0, + &TempBuffer, + 2, + &Status + ); + if (EFI_ERROR (Result)) { + return EFI_UNSUPPORTED; + } + + LanguageTable = (EFI_USB_SUPPORTED_LANGUAGES *) &TempBuffer; + + if (LanguageTable->Length == 0) { + return EFI_UNSUPPORTED; + } + // + // If length is 2, then there is no string table + // + if (LanguageTable->Length == 2) { + return EFI_UNSUPPORTED; + } + + Buffer = AllocateZeroPool (LanguageTable->Length); + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Now we get the whole LangID table + // + Result = UsbGetString ( + UsbIo, + 0, + 0, + Buffer, + LanguageTable->Length, + &Status + ); + if (EFI_ERROR (Result)) { + gBS->FreePool (Buffer); + return EFI_UNSUPPORTED; + } + + LanguageTable = (EFI_USB_SUPPORTED_LANGUAGES *) Buffer; + + // + // ptr point to the LangID table + // + ptr = Buffer + 2; + LangTableSize = (LanguageTable->Length - 2) / 2; + + for (Index = 0; Index < LangTableSize && Index < USB_MAXLANID; Index++) { + Dev->LangID[Index] = *((UINT16 *) ptr); + ptr += 2; + } + + gBS->FreePool (Buffer); + LanguageTable = NULL; + + return EFI_SUCCESS; +} + + +EFI_STATUS +UsbGetAllConfigurations ( + IN USB_IO_DEVICE *UsbIoDevice + ) +/*++ + + Routine Description: + This function is to parse all the configuration descriptor. + + Arguments: + UsbIoDevice - USB_IO_DEVICE device structure. + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + EFI_OUT_OF_RESOURCES + +--*/ +{ + EFI_STATUS Result; + UINT32 Status; + UINTN Index; + UINTN TotalLength; + UINT8 *Buffer; + CONFIG_DESC_LIST_ENTRY *ConfigDescEntry; + EFI_USB_IO_PROTOCOL *UsbIo; + + InitializeListHead (&UsbIoDevice->ConfigDescListHead); + UsbIo = &(UsbIoDevice->UsbController[0]->UsbIo); + + for (Index = 0; Index < UsbIoDevice->DeviceDescriptor.NumConfigurations; Index++) { + ConfigDescEntry = NULL; + + ConfigDescEntry = AllocateZeroPool (sizeof (CONFIG_DESC_LIST_ENTRY)); + if (ConfigDescEntry == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // 1st only get 1st 4 bytes config descriptor, + // so we can know the whole length + // + Result = UsbGetDescriptor ( + UsbIo, + (UINT16) ((USB_DT_CONFIG << 8) | Index), + 0, + 4, + &ConfigDescEntry->CongfigDescriptor, + &Status + ); + if (EFI_ERROR (Result)) { + DEBUG ((gUSBErrorLevel, "First get config descriptor error\n")); + gBS->FreePool (ConfigDescEntry); + return EFI_DEVICE_ERROR; + } + + TotalLength = ConfigDescEntry->CongfigDescriptor.TotalLength; + + Buffer = AllocateZeroPool (TotalLength); + if (Buffer == NULL) { + gBS->FreePool (ConfigDescEntry); + return EFI_OUT_OF_RESOURCES; + } + // + // Then we get the total descriptors for this configuration + // + Result = UsbGetDescriptor ( + UsbIo, + (UINT16) ((USB_DT_CONFIG << 8) | Index), + 0, + (UINT16) TotalLength, + Buffer, + &Status + ); + if (EFI_ERROR (Result)) { + DEBUG ((gUSBErrorLevel, "Get whole config descriptor error\n")); + gBS->FreePool (ConfigDescEntry); + gBS->FreePool (Buffer); + return EFI_DEVICE_ERROR; + } + + InitializeListHead (&ConfigDescEntry->InterfaceDescListHead); + + // + // Parse this whole configuration + // + Result = ParseThisConfig (ConfigDescEntry, Buffer, TotalLength); + + if (EFI_ERROR (Result)) { + // + // Ignore this configuration, parse next one + // + gBS->FreePool (ConfigDescEntry); + gBS->FreePool (Buffer); + continue; + } + + InsertTailList (&UsbIoDevice->ConfigDescListHead, &ConfigDescEntry->Link); + + gBS->FreePool (Buffer); + + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +GetExpectedDescriptor ( + IN UINT8 *Buffer, + IN UINTN Length, + IN UINT8 DescType, + IN UINT8 DescLength, + OUT UINTN *ParsedBytes + ) +/*++ + + Routine Description: + Get the start position of next wanted descriptor. + + Arguments: + Buffer - Buffer to parse + Length - Buffer length + DescType - Descriptor type + DescLength - Descriptor length + ParsedBytes - Parsed Bytes to return + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + +--*/ +{ + UINT16 DescriptorHeader; + UINT8 Len; + UINT8 *ptr; + UINTN Parsed; + + Parsed = 0; + ptr = Buffer; + + while (TRUE) { + // + // Buffer length should not less than Desc length + // + if (Length < DescLength) { + return EFI_DEVICE_ERROR; + } + // + // DescriptorHeader = *((UINT16 *)ptr), compatible with IPF + // + DescriptorHeader = (UINT16) ((*(ptr + 1) << 8) | *ptr); + + Len = ptr[0]; + + // + // Check to see if it is a start of expected descriptor + // + if (DescriptorHeader == ((DescType << 8) | DescLength)) { + break; + } + + if ((UINT8) (DescriptorHeader >> 8) == DescType) { + if (Len > DescLength) { + return EFI_DEVICE_ERROR; + } + } + // + // Descriptor length should be at least 2 + // and should not exceed the buffer length + // + if (Len < 2) { + return EFI_DEVICE_ERROR; + } + + if (Len > Length) { + return EFI_DEVICE_ERROR; + } + // + // Skip this mismatch descriptor + // + Length -= Len; + ptr += Len; + Parsed += Len; + } + + *ParsedBytes = Parsed; + + return EFI_SUCCESS; +} + + +STATIC +EFI_STATUS +ParseThisEndpoint ( + IN ENDPOINT_DESC_LIST_ENTRY *EndpointEntry, + IN UINT8 *Buffer, + IN UINTN BufferLength, + OUT UINTN *ParsedBytes + ) +/*++ + + Routine Description: + Get the start position of next wanted endpoint descriptor. + + Arguments: + EndpointEntry - ENDPOINT_DESC_LIST_ENTRY + Buffer - Buffer to parse + BufferLength - Buffer Length + ParsedBytes - Parsed Bytes to return + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + +--*/ +{ + UINT8 *ptr; + EFI_STATUS Status; + UINTN SkipBytes; + + // + // Skip some data for this interface + // + Status = GetExpectedDescriptor ( + Buffer, + BufferLength, + USB_DT_ENDPOINT, + sizeof (EFI_USB_ENDPOINT_DESCRIPTOR), + &SkipBytes + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + ptr = Buffer + SkipBytes; + *ParsedBytes = SkipBytes; + + CopyMem ( + &EndpointEntry->EndpointDescriptor, + ptr, + sizeof (EFI_USB_ENDPOINT_DESCRIPTOR) + ); + + *ParsedBytes += sizeof (EFI_USB_ENDPOINT_DESCRIPTOR); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +ParseThisInterface ( + IN INTERFACE_DESC_LIST_ENTRY *InterfaceEntry, + IN UINT8 *Buffer, + IN UINTN *BufferLen, + OUT UINTN *ParsedBytes + ) +/*++ + + Routine Description: + Get the start position of next wanted interface descriptor. + + Arguments: + InterfaceEntry - INTERFACE_DESC_LIST_ENTRY + Buffer - Buffer to parse + BufferLength - Buffer Length + ParsedBytes - Parsed Bytes to return + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + +--*/ +{ + UINT8 *ptr; + UINTN SkipBytes; + UINTN Index; + UINTN Length; + UINTN Parsed; + ENDPOINT_DESC_LIST_ENTRY *EndpointEntry; + EFI_STATUS Status; + + Parsed = 0; + + // + // Skip some data for this interface + // + Status = GetExpectedDescriptor ( + Buffer, + *BufferLen, + USB_DT_INTERFACE, + sizeof (EFI_USB_INTERFACE_DESCRIPTOR), + &SkipBytes + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + ptr = Buffer + SkipBytes; + *ParsedBytes = SkipBytes; + + // + // Copy the interface descriptor + // + CopyMem ( + &InterfaceEntry->InterfaceDescriptor, + ptr, + sizeof (EFI_USB_INTERFACE_DESCRIPTOR) + ); + + ptr = Buffer + sizeof (EFI_USB_INTERFACE_DESCRIPTOR); + *ParsedBytes += sizeof (EFI_USB_INTERFACE_DESCRIPTOR); + + InitializeListHead (&InterfaceEntry->EndpointDescListHead); + + Length = *BufferLen - SkipBytes - sizeof (EFI_USB_INTERFACE_DESCRIPTOR); + + for (Index = 0; Index < InterfaceEntry->InterfaceDescriptor.NumEndpoints; Index++) { + EndpointEntry = AllocateZeroPool (sizeof (ENDPOINT_DESC_LIST_ENTRY)); + if (EndpointEntry == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Parses all the endpoint descriptors within this interface. + // + Status = ParseThisEndpoint (EndpointEntry, ptr, Length, &Parsed); + + if (EFI_ERROR (Status)) { + gBS->FreePool (EndpointEntry); + return Status; + } + + InsertTailList ( + &InterfaceEntry->EndpointDescListHead, + &EndpointEntry->Link + ); + + Length -= Parsed; + ptr += Parsed; + *ParsedBytes += Parsed; + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +ParseThisConfig ( + IN CONFIG_DESC_LIST_ENTRY *ConfigDescEntry, + IN UINT8 *Buffer, + IN UINTN Length + ) +/*++ + + Routine Description: + Parse the current configuration descriptior. + + Arguments: + ConfigDescEntry - CONFIG_DESC_LIST_ENTRY + Buffer - Buffer to parse + Length - Buffer Length + + Returns + EFI_SUCCESS + EFI_DEVICE_ERROR + +--*/ +{ + UINT8 *ptr; + UINT8 NumInterface; + UINTN Index; + INTERFACE_DESC_LIST_ENTRY *InterfaceEntry; + UINTN SkipBytes; + UINTN Parsed; + EFI_STATUS Status; + UINTN LengthLeft; + + Parsed = 0; + + // + // First skip the current config descriptor; + // + Status = GetExpectedDescriptor ( + Buffer, + Length, + USB_DT_CONFIG, + sizeof (EFI_USB_CONFIG_DESCRIPTOR), + &SkipBytes + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + ptr = Buffer + SkipBytes; + + CopyMem ( + &ConfigDescEntry->CongfigDescriptor, + ptr, + sizeof (EFI_USB_CONFIG_DESCRIPTOR) + ); + + NumInterface = ConfigDescEntry->CongfigDescriptor.NumInterfaces; + + // + // Skip size of Configuration Descriptor + // + ptr += sizeof (EFI_USB_CONFIG_DESCRIPTOR); + + LengthLeft = Length - SkipBytes - sizeof (EFI_USB_CONFIG_DESCRIPTOR); + + for (Index = 0; Index < NumInterface; Index++) { + // + // Parse all Interface + // + InterfaceEntry = AllocateZeroPool (sizeof (INTERFACE_DESC_LIST_ENTRY)); + if (InterfaceEntry == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = ParseThisInterface (InterfaceEntry, ptr, &LengthLeft, &Parsed); + if (EFI_ERROR (Status)) { + gBS->FreePool (InterfaceEntry); + return Status; + } + + InsertTailList ( + &ConfigDescEntry->InterfaceDescListHead, + &InterfaceEntry->Link + ); + + // + // Parsed for next interface + // + LengthLeft -= Parsed; + ptr += Parsed; + } + // + // Parse for additional alt setting; + // + return EFI_SUCCESS; +} + +EFI_STATUS +UsbSetConfiguration ( + IN USB_IO_DEVICE *UsbIoDev, + IN UINTN ConfigurationValue + ) +/*++ + + Routine Description: + Set the device to a configuration value. + + Arguments: + UsbIoDev - USB_IO_DEVICE to be set configuration + ConfigrationValue - The configuration value to be set to that device + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + +--*/ +{ + LIST_ENTRY *NextEntry; + CONFIG_DESC_LIST_ENTRY *ConfigEntry; + UINT32 Status; + EFI_STATUS Result; + EFI_USB_IO_PROTOCOL *UsbIo; + + UsbIo = &(UsbIoDev->UsbController[0]->UsbIo); + NextEntry = UsbIoDev->ConfigDescListHead.ForwardLink; + + while (NextEntry != &UsbIoDev->ConfigDescListHead) { + // + // Get one entry + // + ConfigEntry = (CONFIG_DESC_LIST_ENTRY *) NextEntry; + if (ConfigEntry->CongfigDescriptor.ConfigurationValue == ConfigurationValue) { + // + // Find one, set to the active configuration + // + UsbIoDev->ActiveConfig = ConfigEntry; + break; + } + + NextEntry = NextEntry->ForwardLink; + } + // + // Next Entry should not be null + // + Result = UsbSetDeviceConfiguration ( + UsbIo, + (UINT16) ConfigurationValue, + &Status + ); + + return Result; +} + +EFI_STATUS +UsbSetDefaultConfiguration ( + IN USB_IO_DEVICE *UsbIoDev + ) +/*++ + + Routine Description: + Set the device to a default configuration value. + + Arguments: + UsbIoDev - USB_IO_DEVICE to be set configuration + + Returns + EFI_SUCCESS + EFI_DEVICE_ERROR + +--*/ +{ + CONFIG_DESC_LIST_ENTRY *ConfigEntry; + UINT16 ConfigValue; + LIST_ENTRY *NextEntry; + + if (IsListEmpty (&UsbIoDev->ConfigDescListHead)) { + return EFI_DEVICE_ERROR; + } + + NextEntry = UsbIoDev->ConfigDescListHead.ForwardLink; + + ConfigEntry = (CONFIG_DESC_LIST_ENTRY *) NextEntry; + ConfigValue = ConfigEntry->CongfigDescriptor.ConfigurationValue; + + return UsbSetConfiguration (UsbIoDev, ConfigValue); +} + +VOID +UsbDestroyAllConfiguration ( + IN USB_IO_DEVICE *UsbIoDevice + ) +/*++ + + Routine Description: + Delete all configuration data when device is not used. + + Arguments: + UsbIoDevice - USB_IO_DEVICE to be set configuration + + Returns: + N/A + +--*/ +{ + CONFIG_DESC_LIST_ENTRY *ConfigEntry; + INTERFACE_DESC_LIST_ENTRY *InterfaceEntry; + ENDPOINT_DESC_LIST_ENTRY *EndpointEntry; + LIST_ENTRY *NextEntry; + + // + // Delete all configuration descriptor data + // + ConfigEntry = (CONFIG_DESC_LIST_ENTRY *) UsbIoDevice->ConfigDescListHead.ForwardLink; + + while (ConfigEntry != (CONFIG_DESC_LIST_ENTRY *) &UsbIoDevice->ConfigDescListHead) { + // + // Delete all its interface descriptors + // + InterfaceEntry = (INTERFACE_DESC_LIST_ENTRY *) ConfigEntry->InterfaceDescListHead.ForwardLink; + + while (InterfaceEntry != (INTERFACE_DESC_LIST_ENTRY *) &ConfigEntry->InterfaceDescListHead) { + // + // Delete all its endpoint descriptors + // + EndpointEntry = (ENDPOINT_DESC_LIST_ENTRY *) InterfaceEntry->EndpointDescListHead.ForwardLink; + while (EndpointEntry != (ENDPOINT_DESC_LIST_ENTRY *) &InterfaceEntry->EndpointDescListHead) { + NextEntry = ((LIST_ENTRY *) EndpointEntry)->ForwardLink; + RemoveEntryList ((LIST_ENTRY *) EndpointEntry); + gBS->FreePool (EndpointEntry); + EndpointEntry = (ENDPOINT_DESC_LIST_ENTRY *) NextEntry; + } + + NextEntry = ((LIST_ENTRY *) InterfaceEntry)->ForwardLink; + RemoveEntryList ((LIST_ENTRY *) InterfaceEntry); + gBS->FreePool (InterfaceEntry); + InterfaceEntry = (INTERFACE_DESC_LIST_ENTRY *) NextEntry; + } + + NextEntry = ((LIST_ENTRY *) ConfigEntry)->ForwardLink; + RemoveEntryList ((LIST_ENTRY *) ConfigEntry); + gBS->FreePool (ConfigEntry); + ConfigEntry = (CONFIG_DESC_LIST_ENTRY *) NextEntry; + } +} diff --git a/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbbus.c b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbbus.c new file mode 100644 index 0000000000..f4ac69e13f --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbbus.c @@ -0,0 +1,2305 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + Module Name: + + UsbBus.c + + Abstract: + + USB Bus Driver + + Revision History + +--*/ + +#include "usbbus.h" + +//#ifdef EFI_DEBUG +UINTN gUSBDebugLevel = EFI_D_ERROR; +UINTN gUSBErrorLevel = EFI_D_ERROR; +//#endif +// +// The UsbBusProtocol is just used to locate USB_BUS_CONTROLLER +// structure in the UsbBusDriverControllerDriverStop(). Then we can +// Close all opened protocols and release this structure. +// +STATIC EFI_GUID mUsbBusProtocolGuid = EFI_USB_BUS_PROTOCOL_GUID; + + + +// +// EFI_DRIVER_BINDING_PROTOCOL Protocol Interface +// +EFI_STATUS +EFIAPI +UsbBusControllerDriverSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +UsbBusControllerDriverStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +UsbBusControllerDriverStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +EFI_DRIVER_BINDING_PROTOCOL gUsbBusDriverBinding = { + UsbBusControllerDriverSupported, + UsbBusControllerDriverStart, + UsbBusControllerDriverStop, + 0x10, + NULL, + NULL +}; + +// +// Internal use only +// +STATIC +EFI_STATUS +ReportUsbStatusCode ( + IN USB_BUS_CONTROLLER_DEVICE *UsbBusController, + IN EFI_STATUS_CODE_TYPE Type, + IN EFI_STATUS_CODE_VALUE Code + ); + +// +// Supported function +// +VOID +InitializeUsbIoInstance ( + IN USB_IO_CONTROLLER_DEVICE *UsbIoController + ); + +STATIC +USB_IO_CONTROLLER_DEVICE * +CreateUsbIoControllerDevice ( + VOID + ); + +STATIC +EFI_STATUS +InitUsbIoController ( + IN USB_IO_CONTROLLER_DEVICE *UsbIoController + ); + +// +// USB Device Configuration / Deconfiguration +// +STATIC +EFI_STATUS +UsbDeviceConfiguration ( + IN USB_IO_CONTROLLER_DEVICE *ParentHubController, + IN EFI_HANDLE HostController, + IN UINT8 ParentPort, + IN USB_IO_DEVICE *UsbIoDevice + ); + +// +// Usb Bus enumeration function +// +STATIC +VOID +EFIAPI +UsbEnumeration ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +EFI_STATUS +ResetRootPort ( + IN EFI_USB_HC_PROTOCOL *UsbHCInterface, + IN UINT8 PortNum, + IN UINT8 RetryTimes + ); + +EFI_STATUS +ResetHubPort ( + IN USB_IO_CONTROLLER_DEVICE *UsbIoController, + IN UINT8 PortIndex + ); + +EFI_STATUS +ClearRootPortConnectionChangeStatus ( + IN UINT8 PortNum, + IN EFI_USB_HC_PROTOCOL *UsbHCInterface + ); + +STATIC +EFI_STATUS +ParentPortReset ( + IN USB_IO_CONTROLLER_DEVICE *UsbIoController, + IN BOOLEAN ReConfigure, + IN UINT8 RetryTimes + ); + +// +// Following are address allocate and free functions +// +STATIC +UINT8 +UsbAllocateAddress ( + IN UINT8 *AddressPool + ) +{ + UINT8 ByteIndex; + UINT8 BitIndex; + + for (ByteIndex = 0; ByteIndex < 16; ByteIndex++) { + for (BitIndex = 0; BitIndex < 8; BitIndex++) { + if ((AddressPool[ByteIndex] & (1 << BitIndex)) == 0) { + // + // Found one, covert to address, and mark it use + // + AddressPool[ByteIndex] |= (1 << BitIndex); + return (UINT8) (ByteIndex * 8 + BitIndex); + } + } + } + + return 0; + +} + +STATIC +VOID +UsbFreeAddress ( + IN UINT8 DevAddress, + IN UINT8 *AddressPool + ) +{ + UINT8 WhichByte; + UINT8 WhichBit; + // + // Locate the position + // + WhichByte = (UINT8) (DevAddress / 8); + WhichBit = (UINT8) (DevAddress & 0x7); + + AddressPool[WhichByte] &= (~(1 << WhichBit)); +} + +EFI_STATUS +EFIAPI +UsbBusControllerDriverSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + Test to see if this driver supports ControllerHandle. Any ControllerHandle + that has UsbHcProtocol installed will be supported. + + Arguments: + This - Protocol instance pointer. + Controller - Handle of device to test + RemainingDevicePath - Not used + + Returns: + EFI_SUCCESS - This driver supports this device. + EFI_UNSUPPORTED - This driver does not support this device. + +--*/ +{ + EFI_STATUS OpenStatus; + + // + // Check whether USB Host Controller Protocol is already + // installed on this handle. If it is installed, we can start + // USB Bus Driver now. + // + OpenStatus = gBS->OpenProtocol ( + Controller, + &gEfiUsbHcProtocolGuid, + NULL, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + + if (EFI_ERROR (OpenStatus) && (OpenStatus != EFI_ALREADY_STARTED)) { + return EFI_UNSUPPORTED; + } + + return OpenStatus; +} + + +EFI_STATUS +EFIAPI +UsbBusControllerDriverStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + + Starting the Usb Bus Driver + + Arguments: + + This - Protocol instance pointer. + Controller - Handle of device to test + RemainingDevicePath - Not used + + Returns: + + EFI_SUCCESS - This driver supports this device. + EFI_UNSUPPORTED - This driver does not support this device. + EFI_DEVICE_ERROR - This driver cannot be started due to device + Error + EFI_OUT_OF_RESOURCES- Can't allocate memory resources + EFI_ALREADY_STARTED - This driver has been started + +--*/ +{ + EFI_STATUS Status; + EFI_STATUS OpenStatus; + USB_BUS_CONTROLLER_DEVICE *UsbBusDev; + USB_IO_DEVICE *RootHub; + USB_IO_CONTROLLER_DEVICE *RootHubController; + EFI_USB_HC_PROTOCOL *UsbHCInterface; + + // + // Allocate USB_BUS_CONTROLLER_DEVICE structure + // + UsbBusDev = NULL; + UsbBusDev = AllocateZeroPool (sizeof (USB_BUS_CONTROLLER_DEVICE)); + if (UsbBusDev == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + UsbBusDev->Signature = USB_BUS_DEVICE_SIGNATURE; + UsbBusDev->AddressPool[0] = 1; + + // + // Get the Device Path Protocol on Controller's handle + // + OpenStatus = gBS->OpenProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &UsbBusDev->DevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (OpenStatus)) { + gBS->FreePool (UsbBusDev); + return EFI_UNSUPPORTED; + } + // + // Locate the Host Controller Interface + // + OpenStatus = gBS->OpenProtocol ( + Controller, + &gEfiUsbHcProtocolGuid, + (VOID **) &UsbHCInterface, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (OpenStatus) && (OpenStatus != EFI_ALREADY_STARTED)) { + + // + // Report Status Code here since we will reset the host controller + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_IO_BUS_USB | EFI_IOB_EC_CONTROLLER_ERROR, + UsbBusDev->DevicePath + ); + + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + gBS->FreePool (UsbBusDev); + return EFI_UNSUPPORTED; + } + + if (OpenStatus == EFI_ALREADY_STARTED) { + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + gBS->FreePool (UsbBusDev); + return EFI_ALREADY_STARTED; + } + + UsbBusDev->UsbHCInterface = UsbHCInterface; + + // + // Attach EFI_USB_BUS_PROTOCOL to controller handle, + // for locate UsbBusDev later + // + Status = gBS->InstallProtocolInterface ( + &Controller, + &mUsbBusProtocolGuid, + EFI_NATIVE_INTERFACE, + &UsbBusDev->BusIdentify + ); + + if (EFI_ERROR (Status)) { + + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + gBS->CloseProtocol ( + Controller, + &gEfiUsbHcProtocolGuid, + This->DriverBindingHandle, + Controller + ); + gBS->FreePool (UsbBusDev); + return Status; + } + // + // Add root hub to the tree + // + RootHub = NULL; + RootHub = AllocateZeroPool (sizeof (USB_IO_DEVICE)); + if (RootHub == NULL) { + gBS->UninstallProtocolInterface ( + Controller, + &mUsbBusProtocolGuid, + &UsbBusDev->BusIdentify + ); + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + gBS->CloseProtocol ( + Controller, + &gEfiUsbHcProtocolGuid, + This->DriverBindingHandle, + Controller + ); + gBS->FreePool (UsbBusDev); + return EFI_OUT_OF_RESOURCES; + } + + RootHub->BusController = UsbBusDev; + RootHub->DeviceAddress = UsbAllocateAddress (UsbBusDev->AddressPool); + + UsbBusDev->Root = RootHub; + + // + // Allocate Root Hub Controller + // + RootHubController = CreateUsbIoControllerDevice (); + if (RootHubController == NULL) { + gBS->UninstallProtocolInterface ( + Controller, + &mUsbBusProtocolGuid, + &UsbBusDev->BusIdentify + ); + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + gBS->CloseProtocol ( + Controller, + &gEfiUsbHcProtocolGuid, + This->DriverBindingHandle, + Controller + ); + gBS->FreePool (UsbBusDev); + gBS->FreePool (RootHub); + return EFI_OUT_OF_RESOURCES; + } + + UsbHCInterface->GetRootHubPortNumber ( + UsbHCInterface, + &RootHubController->DownstreamPorts + ); + RootHubController->UsbDevice = RootHub; + RootHubController->IsUsbHub = TRUE; + RootHubController->DevicePath = UsbBusDev->DevicePath; + RootHubController->HostController = Controller; + + RootHub->NumOfControllers = 1; + RootHub->UsbController[0] = RootHubController; + + // + // Report Status Code here since we will reset the host controller + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + EFI_IO_BUS_USB | EFI_IOB_PC_RESET, + UsbBusDev->DevicePath + ); + + // + // Reset USB Host Controller + // + UsbHCInterface->Reset ( + UsbHCInterface, + EFI_USB_HC_RESET_GLOBAL + ); + + // + // Report Status Code while we are going to bring up the Host Controller + // and start bus enumeration + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + EFI_IO_BUS_USB | EFI_IOB_PC_ENABLE, + UsbBusDev->DevicePath + ); + + // + // Start USB Host Controller + // + UsbHCInterface->SetState ( + UsbHCInterface, + EfiUsbHcStateOperational + ); + + // + // Create a timer to query root ports periodically + // + Status = gBS->CreateEvent ( + EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL, + EFI_TPL_CALLBACK, + UsbEnumeration, + RootHubController, + &RootHubController->HubNotify + ); + if (EFI_ERROR (Status)) { + gBS->UninstallProtocolInterface ( + Controller, + &mUsbBusProtocolGuid, + &UsbBusDev->BusIdentify + ); + + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + gBS->CloseProtocol ( + Controller, + &gEfiUsbHcProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + gBS->FreePool (RootHubController); + gBS->FreePool (RootHub); + gBS->FreePool (UsbBusDev); + return EFI_UNSUPPORTED; + } + + // + // Before depending on the timer to check root ports periodically, + // here we should check them immediately for the first time, or + // there will be an interval between bus start and devices start. + // + gBS->SignalEvent (RootHubController->HubNotify); + + Status = gBS->SetTimer ( + RootHubController->HubNotify, + TimerPeriodic, + BUSPOLLING_PERIOD + ); + if (EFI_ERROR (Status)) { + gBS->UninstallProtocolInterface ( + Controller, + &mUsbBusProtocolGuid, + &UsbBusDev->BusIdentify + ); + + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + gBS->CloseProtocol ( + Controller, + &gEfiUsbHcProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + gBS->CloseEvent (RootHubController->HubNotify); + gBS->FreePool (RootHubController); + gBS->FreePool (RootHub); + gBS->FreePool (UsbBusDev); + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} +// +// Stop the bus controller +// +EFI_STATUS +EFIAPI +UsbBusControllerDriverStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + + Routine Description: + Stop this driver on ControllerHandle. Support stoping any child handles + created by this driver. + + Arguments: + This - Protocol instance pointer. + Controller - Handle of device to stop driver on + NumberOfChildren - Number of Children in the ChildHandleBuffer + ChildHandleBuffer - List of handles for the children we need to stop. + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + others + +--*/ +{ + EFI_STATUS Status; + USB_IO_DEVICE *Root; + USB_IO_CONTROLLER_DEVICE *RootHubController; + USB_BUS_CONTROLLER_DEVICE *UsbBusController; + EFI_USB_BUS_PROTOCOL *UsbIdentifier; + UINT8 Index2; + EFI_USB_HC_PROTOCOL *UsbHCInterface; + USB_IO_CONTROLLER_DEVICE *UsbController; + USB_IO_DEVICE *UsbIoDevice; + USB_IO_CONTROLLER_DEVICE *HubController; + UINTN Index; + EFI_USB_IO_PROTOCOL *UsbIo; + + if (NumberOfChildren > 0) { + + 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)) { + // + // We are here since the handle passed in does not support + // UsbIo protocol. There are several reasons that will cause + // this. + // For combo device such as keyboard, it may have 2 devices + // in one, namely, keyboard and mouse. If we deconfigure one + // of them, the other will be freed at the same time. This will + // cause the status error. But this is the correct behavior. + // For hub device, if we deconfigure hub first, the other chile + // device will be disconnected also, this will also provide us + // a status error. Now we will only report EFI_SUCCESS since Uhc + // driver will be disconnected at the second time.(pls see + // CoreDisconnectController for details) + // + continue; + } + + UsbController = USB_IO_CONTROLLER_DEVICE_FROM_USB_IO_THIS (UsbIo); + UsbIoDevice = UsbController->UsbDevice; + HubController = UsbController->Parent; + UsbDeviceDeConfiguration (UsbIoDevice); + for (Index2 = 0; Index2 < HubController->DownstreamPorts; Index2++) { + if (HubController->Children[Index2] == UsbIoDevice) { + HubController->Children[Index2] = NULL; + } + } + } + + return EFI_SUCCESS; + } + // + // Get the USB_BUS_CONTROLLER_DEVICE + // + Status = gBS->OpenProtocol ( + Controller, + &mUsbBusProtocolGuid, + (VOID **) &UsbIdentifier, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + UsbBusController = USB_BUS_CONTROLLER_DEVICE_FROM_THIS (UsbIdentifier); + + // + // Stop USB Host Controller + // + UsbHCInterface = UsbBusController->UsbHCInterface; + + // + // Report Status Code here since we will reset the host controller + // + ReportUsbStatusCode ( + UsbBusController, + EFI_PROGRESS_CODE, + EFI_IO_BUS_USB | EFI_IOB_PC_RESET + ); + + UsbHCInterface->SetState ( + UsbHCInterface, + EfiUsbHcStateHalt + ); + + // + // Deconfiguration all its devices + // + Root = UsbBusController->Root; + RootHubController = Root->UsbController[0]; + + gBS->CloseEvent (RootHubController->HubNotify); + + for (Index2 = 0; Index2 < RootHubController->DownstreamPorts; Index2++) { + if (RootHubController->Children[Index2]) { + UsbDeviceDeConfiguration (RootHubController->Children[Index2]); + RootHubController->Children[Index2] = NULL; + } + } + + gBS->FreePool (RootHubController); + gBS->FreePool (Root); + + // + // Uninstall USB Bus Protocol + // + gBS->UninstallProtocolInterface ( + Controller, + &mUsbBusProtocolGuid, + &UsbBusController->BusIdentify + ); + + // + // Close USB_HC_PROTOCOL & DEVICE_PATH_PROTOCOL + // Opened by this Controller + // + gBS->CloseProtocol ( + Controller, + &gEfiUsbHcProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + gBS->FreePool (UsbBusController); + + return EFI_SUCCESS; +} +// +// USB Device Configuration +// +STATIC +EFI_STATUS +UsbDeviceConfiguration ( + IN USB_IO_CONTROLLER_DEVICE *ParentHubController, + IN EFI_HANDLE HostController, + IN UINT8 ParentPort, + IN USB_IO_DEVICE *UsbIoDevice + ) +/*++ + + Routine Description: + Configurate a new device attached to the usb bus + + Arguments: + ParentHubController - Parent Hub which this device is connected. + HostController - Host Controller handle + ParentPort - Parent Hub port which this device is connected. + UsbIoDevice - The device to be configured. + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + EFI_OUT_OF_RESOURCES + +--*/ +{ + UINT8 DevAddress; + UINT8 Index; + EFI_STATUS Result; + UINT32 Status; + CHAR16 *StrManufacturer; + CHAR16 *StrProduct; + CHAR16 *StrSerialNumber; + EFI_USB_IO_PROTOCOL *UsbIo; + UINT8 NumOfInterface; + USB_IO_CONTROLLER_DEVICE *FirstController; + USB_BUS_CONTROLLER_DEVICE *UsbBusDev; + USB_IO_CONTROLLER_DEVICE *UsbIoController; + + UsbBusDev = UsbIoDevice->BusController; + // + // Since a USB device must have at least on interface, + // so create this instance first + // + FirstController = CreateUsbIoControllerDevice (); + FirstController->UsbDevice = UsbIoDevice; + UsbIoDevice->UsbController[0] = FirstController; + FirstController->InterfaceNumber = 0; + FirstController->ParentPort = ParentPort; + FirstController->Parent = ParentHubController; + FirstController->HostController = HostController; + + InitializeUsbIoInstance (FirstController); + + DEBUG ((gUSBDebugLevel, "Configuration Usb Device at 0x%x...\n", ParentPort)); + + // + // Ensure we used the correctly USB I/O instance + // + UsbIo = &FirstController->UsbIo; + + // + // First retrieve the 1st 8 bytes of + // in order to get the MaxPacketSize for Endpoint 0 + // + for (Index = 0; Index < 3; Index++) { + + UsbIoDevice->DeviceDescriptor.MaxPacketSize0 = 8; + + ParentPortReset (FirstController, FALSE, Index); + + Result = UsbGetDescriptor ( + UsbIo, + (USB_DT_DEVICE << 8), + 0, + 8, + &UsbIoDevice->DeviceDescriptor, + &Status + ); + if (!EFI_ERROR (Result)) { + DEBUG ((gUSBDebugLevel, + "Get Device Descriptor Success, MaxPacketSize0 = 0x%x\n", + UsbIoDevice->DeviceDescriptor.MaxPacketSize0) + ); + break; + } + + } + + if (Index == 3) { + ReportUsbStatusCode ( + UsbBusDev, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_IO_BUS_USB | EFI_IOB_EC_READ_ERROR + ); + DEBUG ((gUSBErrorLevel, "Get Device Descriptor Fail when configing\n")); + gBS->FreePool (FirstController); + return EFI_DEVICE_ERROR; + } + + DevAddress = UsbAllocateAddress (UsbIoDevice->BusController->AddressPool); + if (DevAddress == 0) { + DEBUG ((gUSBErrorLevel, "Cannot allocate address\n")); + gBS->FreePool (FirstController); + return EFI_OUT_OF_RESOURCES; + } + + Result = UsbSetDeviceAddress (UsbIo, DevAddress, &Status); + + if (EFI_ERROR (Result)) { + DEBUG ((gUSBErrorLevel, "Set address error\n")); + ReportUsbStatusCode ( + UsbBusDev, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_IO_BUS_USB | EFI_IOB_EC_WRITE_ERROR + ); + + UsbFreeAddress ( + DevAddress, + UsbIoDevice->BusController->AddressPool + ); + + gBS->FreePool (FirstController); + return EFI_DEVICE_ERROR; + } + + UsbIoDevice->DeviceAddress = DevAddress; + + // + // Get the whole device descriptor + // + Result = UsbGetDescriptor ( + UsbIo, + (USB_DT_DEVICE << 8), + 0, + sizeof (EFI_USB_DEVICE_DESCRIPTOR), + &UsbIoDevice->DeviceDescriptor, + &Status + ); + + if (EFI_ERROR (Result)) { + DEBUG ((gUSBErrorLevel, "Get whole Device Descriptor error\n")); + ReportUsbStatusCode ( + UsbBusDev, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_IO_BUS_USB | EFI_IOB_EC_READ_ERROR + ); + UsbFreeAddress ( + DevAddress, + UsbIoDevice->BusController->AddressPool + ); + + gBS->FreePool (FirstController); + return EFI_DEVICE_ERROR; + } + // + // Get & parse all configurations for this device, including + // all configuration descriptors, all interface descriptors, all + // endpoint descriptors + // + Result = UsbGetAllConfigurations (UsbIoDevice); + + if (EFI_ERROR (Result)) { + DEBUG ((gUSBErrorLevel, "Failed to get device configuration\n")); + ReportUsbStatusCode ( + UsbBusDev, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_IO_BUS_USB | EFI_IOB_EC_READ_ERROR + ); + UsbFreeAddress ( + DevAddress, + UsbIoDevice->BusController->AddressPool + ); + + gBS->FreePool (FirstController); + return EFI_DEVICE_ERROR; + } + // + // Set the 1st configuration value + // + Result = UsbSetDefaultConfiguration (UsbIoDevice); + if (EFI_ERROR (Result)) { + DEBUG ((gUSBErrorLevel, "Failed to set device configuration\n")); + ReportUsbStatusCode ( + UsbBusDev, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_IO_BUS_USB | EFI_IOB_EC_WRITE_ERROR + ); + UsbFreeAddress ( + DevAddress, + UsbIoDevice->BusController->AddressPool + ); + + gBS->FreePool (FirstController); + return EFI_DEVICE_ERROR; + } + + UsbIoDevice->IsConfigured = TRUE; + + // + // Get all string table if applicable + // + Result = UsbGetStringtable (UsbIoDevice); + if (EFI_ERROR (Result)) { + DEBUG ((gUSBDebugLevel, "Device doesn't support string table\n")); + } else { + + StrManufacturer = NULL; + UsbIo->UsbGetStringDescriptor ( + UsbIo, + UsbIoDevice->LangID[0], + (UsbIoDevice->DeviceDescriptor).StrManufacturer, + &StrManufacturer + ); + + StrProduct = NULL; + UsbIo->UsbGetStringDescriptor ( + UsbIo, + UsbIoDevice->LangID[0], + (UsbIoDevice->DeviceDescriptor).StrProduct, + &StrProduct + ); + + StrSerialNumber = NULL; + UsbIo->UsbGetStringDescriptor ( + UsbIo, + UsbIoDevice->LangID[0], + (UsbIoDevice->DeviceDescriptor).StrSerialNumber, + &StrSerialNumber + ); + + if (StrManufacturer) { + gBS->FreePool (StrManufacturer); + } + + if (StrProduct) { + gBS->FreePool (StrProduct); + } + + if (StrSerialNumber) { + gBS->FreePool (StrSerialNumber); + } + } + // + // Create USB_IO_CONTROLLER_DEVICE for + // each detected interface + // + FirstController->CurrentConfigValue = + UsbIoDevice->ActiveConfig->CongfigDescriptor.ConfigurationValue; + + NumOfInterface = + UsbIoDevice->ActiveConfig->CongfigDescriptor.NumInterfaces; + UsbIoDevice->NumOfControllers = NumOfInterface; + + Result = InitUsbIoController (FirstController); + if (EFI_ERROR (Result)) { + ReportUsbStatusCode ( + UsbBusDev, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_IO_BUS_USB | EFI_IOB_EC_INTERFACE_ERROR + ); + gBS->FreePool (FirstController); + UsbIoDevice->UsbController[0] = NULL; + return EFI_DEVICE_ERROR; + } + + for (Index = 1; Index < NumOfInterface; Index++) { + UsbIoController = CreateUsbIoControllerDevice (); + UsbIoController->UsbDevice = UsbIoDevice; + UsbIoController->CurrentConfigValue = + UsbIoDevice->ActiveConfig->CongfigDescriptor.ConfigurationValue; + UsbIoController->InterfaceNumber = Index; + UsbIoDevice->UsbController[Index] = UsbIoController; + UsbIoController->ParentPort = ParentPort; + UsbIoController->Parent = ParentHubController; + UsbIoController->HostController = HostController; + + // + // First copy the USB_IO Protocol instance + // + CopyMem ( + &UsbIoController->UsbIo, + UsbIo, + sizeof (EFI_USB_IO_PROTOCOL) + ); + + Result = InitUsbIoController (UsbIoController); + if (EFI_ERROR (Result)) { + ReportUsbStatusCode ( + UsbBusDev, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_IO_BUS_USB | EFI_IOB_EC_INTERFACE_ERROR + ); + gBS->FreePool (UsbIoController); + UsbIoDevice->UsbController[Index] = NULL; + } + } + + return EFI_SUCCESS; +} +// +// USB Device DeConfiguration +// + +EFI_STATUS +UsbDeviceDeConfiguration ( + IN USB_IO_DEVICE *UsbIoDevice + ) +/*++ + + Routine Description: + Remove Device, Device Handles, Uninstall Protocols. + + Arguments: + UsbIoDevice - The device to be deconfigured. + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + +--*/ +{ + USB_IO_CONTROLLER_DEVICE *UsbController; + UINT8 index; + USB_IO_DEVICE *ChildDevice; + UINT8 Index; + EFI_USB_IO_PROTOCOL *UsbIo; + + DEBUG ((gUSBDebugLevel, "Enter Usb Device Deconfiguration\n")); + + // + // Double check UsbIoDevice exists + // + if (UsbIoDevice == NULL) { + return EFI_SUCCESS; + } + + for (index = 0; index < UsbIoDevice->NumOfControllers; index++) { + // + // Check if it is a hub, if so, de configuration all its + // downstream ports + // + UsbController = UsbIoDevice->UsbController[index]; + + // + // Check the controller pointer + // + if (UsbController == NULL) { + continue; + } + + if (UsbController->IsUsbHub) { + + DEBUG ((gUSBDebugLevel, "Hub Deconfig, First Deconfig its downstream ports\n")); + + // + // First Remove interrupt transfer request for the status + // change port + // + UsbIo = &UsbController->UsbIo; + UsbIo->UsbAsyncInterruptTransfer ( + UsbIo, + UsbController->HubEndpointAddress, + FALSE, + 0, + 0, + NULL, + NULL + ); + + if (NULL != UsbController->HubNotify) { + gBS->CloseEvent (UsbController->HubNotify); + } + + for (Index = 0; Index < UsbController->DownstreamPorts; Index++) { + if (UsbController->Children[Index]) { + ChildDevice = UsbController->Children[Index]; + UsbDeviceDeConfiguration (ChildDevice); + UsbController->Children[Index] = NULL; + } + } + } + // + // If the controller is managed by a device driver, we need to + // disconnect them + // + if (UsbController->IsManagedByDriver) { + gBS->DisconnectController ( + UsbController->Handle, + NULL, + NULL + ); + } + + // + // remove child handle reference to the USB_HC_PROTOCOL + // + gBS->CloseProtocol ( + UsbController->HostController, + &gEfiUsbHcProtocolGuid, + gUsbBusDriverBinding.DriverBindingHandle, + UsbController->Handle + ); + + // + // Uninstall EFI_USB_IO_PROTOCOL & DEVICE_PATH_PROTOCOL + // installed on this handle + // + gBS->UninstallMultipleProtocolInterfaces ( + UsbController->Handle, + &gEfiDevicePathProtocolGuid, + UsbController->DevicePath, + &gEfiUsbIoProtocolGuid, + &UsbController->UsbIo, + NULL + ); + + if (UsbController->DevicePath != NULL) { + gBS->FreePool (UsbController->DevicePath); + } + + gBS->FreePool (UsbController); + UsbIoDevice->UsbController[index] = NULL; + } + // + // Free address for later use + // + UsbFreeAddress ( + UsbIoDevice->DeviceAddress, + UsbIoDevice->BusController->AddressPool + ); + + // + // Free all resouces allocated for all its configurations + // + UsbDestroyAllConfiguration (UsbIoDevice); + + if (UsbIoDevice) { + gBS->FreePool (UsbIoDevice); + UsbIoDevice = NULL; + } + + return EFI_SUCCESS; +} +// +// After interrupt complete, this function will be called, +// This function need to be well-defined later +// +STATIC +EFI_STATUS +EFIAPI +OnHubInterruptComplete ( + IN VOID *Data, + IN UINTN DataLength, + IN VOID *Context, + IN UINT32 Result + ) +/*++ + + Routine Description: + Whenever hub interrupt occurs, this routine will be called to check + which event happens. + + Arguments: + Data - Hub interrupt transfer data. + DataLength - The length of the Data. + Context - Hub Controller Device. + Result - Hub interrupt transfer status. + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + +--*/ +{ + USB_IO_CONTROLLER_DEVICE *HubController; + UINT8 Index; + UINT8 *ptr; + EFI_USB_IO_PROTOCOL *UsbIo; + UINT32 UsbResult; + BOOLEAN Disconnected; + EFI_STATUS Status; + + HubController = (USB_IO_CONTROLLER_DEVICE *) Context; + UsbIo = &HubController->UsbIo; + + // + // If something error in this interrupt transfer, + // + if (Result != EFI_USB_NOERROR) { + if ((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) { + UsbClearEndpointHalt ( + UsbIo, + HubController->HubEndpointAddress, + &UsbResult + ); + } + + // + // Delete & Submit this interrupt again + // + UsbIo->UsbAsyncInterruptTransfer ( + UsbIo, + HubController->HubEndpointAddress, + FALSE, + 0, + 0, + NULL, + NULL + ); + + // + // try to detect if the hub itself was disconnected or not + // + Status = IsDeviceDisconnected ( + HubController, + &Disconnected + ); + + if (!EFI_ERROR (Status) && Disconnected == TRUE) { + DEBUG ((gUSBErrorLevel, "Hub is disconnected\n")); + return EFI_DEVICE_ERROR; + } + // + // Hub ports < 7 + // + UsbIo->UsbAsyncInterruptTransfer ( + UsbIo, + HubController->HubEndpointAddress, + TRUE, + 100, + 1, + OnHubInterruptComplete, + HubController + ); + + return EFI_DEVICE_ERROR; + } + + if (DataLength == 0 || Data == NULL) { + return EFI_SUCCESS; + } + + // + // Scan which port has status change + // Bit 0 stands for hub itself, other bit stands for + // the corresponding port + // + for (Index = 0; Index < DataLength * 8; Index++) { + ptr = (UINT8 *) Data + Index / 8; + if ((*ptr) & (1 << (Index & 0x7))) { + HubController->StatusChangePort = Index; + break; + } + } + // + // Signal hub notify event + // + gBS->SignalEvent (HubController->HubNotify); + + return EFI_SUCCESS; +} +// +// USB Root Hub Enumerator +// +STATIC +VOID +EFIAPI +UsbEnumeration ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + + Routine Description: + This is USB enumerator + + Arguments: + Event - Indicating which event is signaled + Context - actually it is a USB_IO_DEVICE + + Returns: + EFI_SUCCESS + Others + +--*/ +{ + USB_IO_CONTROLLER_DEVICE *HubController; + EFI_USB_PORT_STATUS HubPortStatus; + EFI_STATUS Status; + UINT8 Index; + EFI_USB_HC_PROTOCOL *UsbHCInterface; + USB_IO_DEVICE *UsbIoDev; + USB_BUS_CONTROLLER_DEVICE *UsbBusDev; + EFI_HANDLE HostController; + USB_IO_DEVICE *OldUsbIoDevice; + USB_IO_DEVICE *NewDevice; + USB_IO_CONTROLLER_DEVICE *NewController; + UINT8 Index2; + EFI_USB_IO_PROTOCOL *UsbIo; + UINT8 StatusChangePort; + + HubController = (USB_IO_CONTROLLER_DEVICE *) Context; + HostController = HubController->HostController; + UsbBusDev = HubController->UsbDevice->BusController; + + if (HubController->UsbDevice->DeviceAddress == 1) { + // + // Root hub has the address 1 + // + UsbIoDev = HubController->UsbDevice; + UsbHCInterface = UsbIoDev->BusController->UsbHCInterface; + + for (Index = 0; Index < HubController->DownstreamPorts; Index++) { + UsbHCInterface->GetRootHubPortStatus ( + UsbHCInterface, + Index, + (EFI_USB_PORT_STATUS *) &HubPortStatus + ); + + if (!IsPortConnectChange (HubPortStatus.PortChangeStatus)) { + continue; + } + // + // Clear root hub status change status + // + ClearRootPortConnectionChangeStatus ( + Index, + UsbHCInterface + ); + + gBS->Stall (100 * 1000); + + UsbHCInterface->GetRootHubPortStatus ( + UsbHCInterface, + Index, + (EFI_USB_PORT_STATUS *) &HubPortStatus + ); + + if (IsPortConnect (HubPortStatus.PortStatus)) { + + // + // There is something connected to this port + // + DEBUG ((gUSBDebugLevel, "Something attached from Root Hub in 0x%x\n", Index)); + + ReportUsbStatusCode ( + UsbBusDev, + EFI_PROGRESS_CODE, + EFI_IO_BUS_USB | EFI_IOB_PC_HOTPLUG + ); + // + // if there is something physically detached, but still logically + // attached... + // + OldUsbIoDevice = HubController->Children[Index]; + + if (NULL != OldUsbIoDevice) { + UsbDeviceDeConfiguration (OldUsbIoDevice); + HubController->Children[Index] = NULL; + } + + NewDevice = AllocateZeroPool (sizeof (USB_IO_DEVICE)); + if (NewDevice == NULL) { + return ; + } + // + // Initialize some fields by copying data from + // its parents + // + NewDevice->IsSlowDevice = IsPortLowSpeedDeviceAttached (HubPortStatus.PortStatus); + + DEBUG ((gUSBDebugLevel, "DeviceSpeed 0x%x\n", NewDevice->IsSlowDevice)); + + NewDevice->BusController = UsbIoDev->BusController; + + // + // Configure that device + // + Status = UsbDeviceConfiguration ( + HubController, + HostController, + Index, + NewDevice + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (NewDevice); + return ; + } + // + // Add this device to the usb bus tree + // + HubController->Children[Index] = NewDevice; + + for (Index2 = 0; Index2 < NewDevice->NumOfControllers; Index2++) { + // + // If this device is hub, add to the hub index + // + NewController = NewDevice->UsbController[Index2]; + + Status = gBS->ConnectController ( + NewController->Handle, + NULL, + NULL, + TRUE + ); + // + // If connect success, we need to disconnect when + // stop the controller, otherwise we need not call + // gBS->DisconnectController () + // This is used by those usb devices we don't plan + // to support. We can allocate + // controller handles for them, but we don't have + // device drivers to manage them. + // + NewController->IsManagedByDriver = (BOOLEAN) (!EFI_ERROR (Status)); + + if (IsHub (NewController)) { + + NewController->IsUsbHub = TRUE; + + // + // Configure Hub Controller + // + Status = DoHubConfig (NewController); + if (EFI_ERROR (Status)) { + continue; + } + // + // Create an event to do hub enumeration + // + gBS->CreateEvent ( + EFI_EVENT_NOTIFY_SIGNAL, + EFI_TPL_CALLBACK, + UsbEnumeration, + NewController, + &NewController->HubNotify + ); + + // + // Add request to do query hub status + // change endpoint + // Hub ports < 7 + // + UsbIo = &NewController->UsbIo; + UsbIo->UsbAsyncInterruptTransfer ( + UsbIo, + NewController->HubEndpointAddress, + TRUE, + 100, + 1, + OnHubInterruptComplete, + NewController + ); + + } + } + } else { + // + // Something disconnected from USB root hub + // + DEBUG ((gUSBDebugLevel, "Something deteached from Root Hub\n")); + + OldUsbIoDevice = HubController->Children[Index]; + + UsbDeviceDeConfiguration (OldUsbIoDevice); + + HubController->Children[Index] = NULL; + + UsbHCInterface->ClearRootHubPortFeature ( + UsbHCInterface, + Index, + EfiUsbPortEnableChange + ); + + UsbHCInterface->GetRootHubPortStatus ( + UsbHCInterface, + Index, + (EFI_USB_PORT_STATUS *) &HubPortStatus + ); + + } + } + + return ; + } else { + // + // Event from Hub, Get the hub controller handle + // + // + // Get the status change endpoint + // + StatusChangePort = HubController->StatusChangePort; + + // + // Clear HubController Status Change Bit + // + HubController->StatusChangePort = 0; + + if (StatusChangePort == 0) { + // + // Hub changes, we don't handle here + // + return ; + } + // + // Check which event took place at that port + // + UsbIo = &HubController->UsbIo; + Status = HubGetPortStatus ( + UsbIo, + StatusChangePort, + (UINT32 *) &HubPortStatus + ); + + if (EFI_ERROR (Status)) { + return ; + } + // + // Clear some change status + // + if (HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_ENABLE) { + // + // Clear Hub port enable change + // + DEBUG ((gUSBDebugLevel, "Port Enable Change\n")); + HubClearPortFeature ( + UsbIo, + StatusChangePort, + EfiUsbPortEnableChange + ); + + HubGetPortStatus ( + UsbIo, + StatusChangePort, + (UINT32 *) &HubPortStatus + ); + } + + if (HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) { + // + // Clear Hub reset change + // + DEBUG ((gUSBDebugLevel, "Port Reset Change\n")); + HubClearPortFeature ( + UsbIo, + StatusChangePort, + EfiUsbPortResetChange + ); + + HubGetPortStatus ( + UsbIo, + StatusChangePort, + (UINT32 *) &HubPortStatus + ); + } + + if (HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_OVERCURRENT) { + // + // Clear Hub overcurrent change + // + DEBUG ((gUSBDebugLevel, "Port Overcurrent Change\n")); + HubClearPortFeature ( + UsbIo, + StatusChangePort, + EfiUsbPortOverCurrentChange + ); + + HubGetPortStatus ( + UsbIo, + StatusChangePort, + (UINT32 *) &HubPortStatus + ); + } + + if (IsPortConnectChange (HubPortStatus.PortChangeStatus)) { + // + // First clear port connection change + // + DEBUG ((gUSBDebugLevel, "Port Connection Change\n")); + HubClearPortFeature ( + UsbIo, + StatusChangePort, + EfiUsbPortConnectChange + ); + + HubGetPortStatus ( + UsbIo, + StatusChangePort, + (UINT32 *) &HubPortStatus + ); + + if (IsPortConnect (HubPortStatus.PortStatus)) { + + DEBUG ((gUSBDebugLevel, "New Device Connect on Hub port \n")); + + ReportUsbStatusCode ( + UsbBusDev, + EFI_PROGRESS_CODE, + EFI_IO_BUS_USB | EFI_IOB_PC_HOTPLUG + ); + + // + // if there is something physically detached, but still logically + // attached... + // + OldUsbIoDevice = HubController->Children[StatusChangePort - 1]; + + if (NULL != OldUsbIoDevice) { + UsbDeviceDeConfiguration (OldUsbIoDevice); + HubController->Children[StatusChangePort - 1] = NULL; + } + + NewDevice = AllocateZeroPool (sizeof (USB_IO_DEVICE)); + if (NewDevice == NULL) { + return ; + } + + ResetHubPort (HubController, StatusChangePort); + + HubGetPortStatus ( + UsbIo, + StatusChangePort, + (UINT32 *) &HubPortStatus + ); + + // + // Initialize some fields + // + NewDevice->IsSlowDevice = IsPortLowSpeedDeviceAttached (HubPortStatus.PortStatus); + + NewDevice->BusController = HubController->UsbDevice->BusController; + + // + // Configure that device + // + Status = UsbDeviceConfiguration ( + HubController, + HostController, + (UINT8) (StatusChangePort - 1), + NewDevice + ); + + if (EFI_ERROR (Status)) { + gBS->FreePool (NewDevice); + return ; + } + // + // Add this device to the usb bus tree + // StatusChangePort is begin from 1, + // + HubController->Children[StatusChangePort - 1] = NewDevice; + + for (Index2 = 0; Index2 < NewDevice->NumOfControllers; Index2++) { + // + // If this device is hub, add to the hub index + // + NewController = NewDevice->UsbController[Index2]; + + // + // Connect the controller to the driver image + // + Status = gBS->ConnectController ( + NewController->Handle, + NULL, + NULL, + TRUE + ); + // + // If connect success, we need to disconnect when + // stop the controller, otherwise we need not call + // gBS->DisconnectController () + // This is used by those usb devices we don't plan + // to support. We can allocate + // controller handles for them, but we don't have + // device drivers to manage them. + // + NewController->IsManagedByDriver = (BOOLEAN) (!EFI_ERROR (Status)); + + // + // If this device is hub, add to the hub index + // + if (IsHub (NewController)) { + + NewController->IsUsbHub = TRUE; + + // + // Configure Hub + // + Status = DoHubConfig (NewController); + + if (EFI_ERROR (Status)) { + continue; + } + // + // Create an event to do hub enumeration + // + gBS->CreateEvent ( + EFI_EVENT_NOTIFY_SIGNAL, + EFI_TPL_CALLBACK, + UsbEnumeration, + NewController, + &NewController->HubNotify + ); + + // + // Add request to do query hub status + // change endpoint + // + UsbIo = &NewController->UsbIo; + UsbIo->UsbAsyncInterruptTransfer ( + UsbIo, + NewController->HubEndpointAddress, // Hub endpoint address + TRUE, + 100, + 1, // Hub ports < 7 + OnHubInterruptComplete, + NewController + ); + } + } + } else { + // + // Something disconnected from USB hub + // + DEBUG ((gUSBDebugLevel, "Something Device Detached on Hub port\n")); + + OldUsbIoDevice = HubController->Children[StatusChangePort - 1]; + + UsbDeviceDeConfiguration (OldUsbIoDevice); + + HubController->Children[StatusChangePort - 1] = NULL; + + } + + return ; + } + + return ; + } +} +// +// Clear port connection change status over a given root hub port +// +EFI_STATUS +ClearRootPortConnectionChangeStatus ( + UINT8 PortNum, + EFI_USB_HC_PROTOCOL *UsbHCInterface + ) +/*++ + + Routine Description: + Clear port connection change status over a given root hub port + + Arguments: + PortNum - The given port. + UsbHCInterface - The EFI_USB_HC_PROTOCOL instance. + + Returns: + EFI_SUCCESS + +--*/ +{ + EFI_STATUS Status; + Status = UsbHCInterface->ClearRootHubPortFeature ( + UsbHCInterface, + PortNum, + EfiUsbPortConnectChange + ); + return Status; +} + +STATIC +USB_IO_CONTROLLER_DEVICE * +CreateUsbIoControllerDevice ( + VOID + ) +/*++ + + Routine Description: + Allocate a structure for USB_IO_CONTROLLER_DEVICE + + Arguments: + N/A + + Returns: + A pointer to a USB_IO_CONTROLLER_DEVICE structure, + Or NULL. + +--*/ +{ + USB_IO_CONTROLLER_DEVICE *UsbIoControllerDev; + + // + // Allocate USB_IO_CONTROLLER_DEVICE structure + // + UsbIoControllerDev = NULL; + UsbIoControllerDev = AllocateZeroPool (sizeof (USB_IO_CONTROLLER_DEVICE)); + + if (UsbIoControllerDev == NULL) { + return NULL; + } + + UsbIoControllerDev->Signature = USB_IO_CONTROLLER_SIGNATURE; + + return UsbIoControllerDev; +} + +STATIC +EFI_STATUS +InitUsbIoController ( + IN USB_IO_CONTROLLER_DEVICE *UsbIoController + ) +/*++ + + Routine Description: + Init and install EFI_USB_IO_PROTOCOL onto that controller. + + Arguments: + UsbIoController - The Controller to be operated. + + Returns: + EFI_SUCCESS + Others + +--*/ +{ + USB_DEVICE_PATH UsbNode; + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_USB_HC_PROTOCOL *UsbHcProtocol; + + // + // Build the child device path for each new USB_IO device + // + ZeroMem (&UsbNode, sizeof (UsbNode)); + UsbNode.Header.Type = MESSAGING_DEVICE_PATH; + UsbNode.Header.SubType = MSG_USB_DP; + SetDevicePathNodeLength (&UsbNode.Header, sizeof (UsbNode)); + UsbNode.InterfaceNumber = UsbIoController->InterfaceNumber; + UsbNode.ParentPortNumber = UsbIoController->ParentPort; + ParentDevicePath = UsbIoController->Parent->DevicePath; + + UsbIoController->DevicePath = + AppendDevicePathNode (ParentDevicePath, &UsbNode.Header); + if (UsbIoController->DevicePath == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = gBS->InstallMultipleProtocolInterfaces ( + &UsbIoController->Handle, + &gEfiDevicePathProtocolGuid, + UsbIoController->DevicePath, + &gEfiUsbIoProtocolGuid, + &UsbIoController->UsbIo, + NULL + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->OpenProtocol ( + UsbIoController->HostController, + &gEfiUsbHcProtocolGuid, + (VOID **) &UsbHcProtocol, + gUsbBusDriverBinding.DriverBindingHandle, + UsbIoController->Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + + return Status; +} + +STATIC +EFI_STATUS +ParentPortReset ( + IN USB_IO_CONTROLLER_DEVICE *UsbIoController, + IN BOOLEAN ReConfigure, + IN UINT8 RetryTimes + ) +/*++ + + Routine Description: + Reset parent hub port to which this device is connected. + + Arguments: + UsbIoController - Indicating the Usb Controller Device. + Reconfigure - Do we need to reconfigure it. + RetryTimes - Retry Times when failed + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + +--*/ +{ + USB_IO_DEVICE *ParentIoDev; + USB_IO_DEVICE *UsbIoDev; + USB_IO_CONTROLLER_DEVICE *ParentController; + UINT8 HubPort; + UINT32 Status; + EFI_STATUS Result; + EFI_USB_IO_PROTOCOL *UsbIo; + UINT8 Address; + + ParentController = UsbIoController->Parent; + ParentIoDev = ParentController->UsbDevice; + UsbIoDev = UsbIoController->UsbDevice; + HubPort = UsbIoController->ParentPort; + + gBS->Stall (100 * 1000); + + if (ParentIoDev->DeviceAddress == 1) { + DEBUG ((gUSBDebugLevel, "Reset from Root Hub 0x%x\n", HubPort)); + ResetRootPort (ParentIoDev->BusController->UsbHCInterface, HubPort, RetryTimes); + } else { + DEBUG ((gUSBDebugLevel, "Reset from Hub, Addr 0x%x\n", ParentIoDev->DeviceAddress)); + ResetHubPort (ParentController, HubPort + 1); + } + // + // If we only need port reset, just return + // + if (!ReConfigure) { + return EFI_SUCCESS; + } + // + // Re-config that USB device + // + UsbIo = &UsbIoController->UsbIo; + + // + // Assign a unique address to this device + // + Address = UsbIoDev->DeviceAddress; + UsbIoDev->DeviceAddress = 0; + + Result = UsbSetDeviceAddress (UsbIo, Address, &Status); + UsbIoDev->DeviceAddress = Address; + + if (EFI_ERROR (Result)) { + return EFI_DEVICE_ERROR; + } + // + // Set the device to the default configuration + // + Result = UsbSetDefaultConfiguration (UsbIoDev); + if (EFI_ERROR (Result)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +UsbPortReset ( + IN EFI_USB_IO_PROTOCOL *This + ) +/*++ + + Routine Description: + Resets and reconfigures the USB controller. This function will + work for all USB devices except USB Hub Controllers. + + Arguments: + This - Indicates the calling context. + + Returns: + EFI_SUCCESS + EFI_INVALID_PARAMETER + EFI_DEVICE_ERROR + +--*/ +{ + USB_IO_CONTROLLER_DEVICE *UsbIoController; + EFI_STATUS Status; + + UsbIoController = USB_IO_CONTROLLER_DEVICE_FROM_USB_IO_THIS (This); + + // + // Since at this time, this device has already been configured, + // it needs to be re-configured. + // + Status = ParentPortReset (UsbIoController, TRUE, 0); + + return Status; +} + +EFI_STATUS +ResetRootPort ( + IN EFI_USB_HC_PROTOCOL *UsbHCInterface, + IN UINT8 PortNum, + IN UINT8 RetryTimes + ) +/*++ + + Routine Description: + Reset Root Hub port. + + Arguments: + UsbHCInterface - The EFI_USB_HC_PROTOCOL instance. + PortNum - The given port to be reset. + RetryTimes - RetryTimes when failed + Returns: + N/A + +--*/ +{ + EFI_STATUS Status; + + // + // reset root port + // + Status = UsbHCInterface->SetRootHubPortFeature ( + UsbHCInterface, + PortNum, + EfiUsbPortReset + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + gBS->Stall (50 * 1000); + + // + // clear reset root port + // + Status = UsbHCInterface->ClearRootHubPortFeature ( + UsbHCInterface, + PortNum, + EfiUsbPortReset + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + gBS->Stall (1000); + + Status = ClearRootPortConnectionChangeStatus (PortNum, UsbHCInterface); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + // + // Set port enable + // + Status = UsbHCInterface->SetRootHubPortFeature ( + UsbHCInterface, + PortNum, + EfiUsbPortEnable + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + Status = UsbHCInterface->ClearRootHubPortFeature ( + UsbHCInterface, + PortNum, + EfiUsbPortEnableChange + ); + gBS->Stall ((1 + RetryTimes) * 50 * 1000); + + return EFI_SUCCESS; +} + + +EFI_STATUS +ResetHubPort ( + IN USB_IO_CONTROLLER_DEVICE *UsbIoController, + IN UINT8 PortIndex + ) +/*++ + + Routine Description: + Reset Hub port. + + Arguments: + UsbIoController - The USB_IO_CONTROLLER_DEVICE instance. + PortIndex - The given port to be reset. + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + +--*/ +{ + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_USB_PORT_STATUS HubPortStatus; + UINT8 Number; + + ASSERT (UsbIoController->IsUsbHub == TRUE); + + UsbIo = &UsbIoController->UsbIo; + + HubSetPortFeature ( + UsbIo, + PortIndex, + EfiUsbPortReset + ); + + gBS->Stall (10 * 1000); + + // + // Wait for port reset complete + // + Number = 10; + do { + HubGetPortStatus ( + UsbIo, + PortIndex, + (UINT32 *) &HubPortStatus + ); + gBS->Stall (10 * 100); + Number -= 1; + } while ((HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0 && Number > 0); + + if (Number == 0) { + // + // Cannot reset port, return error + // + return EFI_DEVICE_ERROR; + } + + gBS->Stall (1000); + + HubGetPortStatus ( + UsbIo, + PortIndex, + (UINT32 *) &HubPortStatus + ); + // + // reset port will cause some bits change, clear them + // + if (HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_ENABLE) { + DEBUG ((gUSBDebugLevel, "Port Enable Change\n")); + HubClearPortFeature ( + UsbIo, + PortIndex, + EfiUsbPortEnableChange + ); + } + + if (HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) { + DEBUG ((gUSBDebugLevel, "Port Reset Change\n")); + HubClearPortFeature ( + UsbIo, + PortIndex, + EfiUsbPortResetChange + ); + } + + return EFI_SUCCESS; +} + + + + + +STATIC +EFI_STATUS +ReportUsbStatusCode ( + IN USB_BUS_CONTROLLER_DEVICE *UsbBusController, + IN EFI_STATUS_CODE_TYPE Type, + IN EFI_STATUS_CODE_VALUE Code + ) +/*++ + +Routine Description: + + report a error Status code of USB bus driver controller + + Arguments: + UsbBusController - USB_BUS_CONTROLLER_DEVICE + Type - EFI_STATUS_CODE_TYPE + Code - EFI_STATUS_CODE_VALUE + Returns: + + None + +--*/ +{ + return REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + Type, + Code, + UsbBusController->DevicePath + ); +} + + +EFI_STATUS +IsDeviceDisconnected ( + IN USB_IO_CONTROLLER_DEVICE *UsbIoController, + IN OUT BOOLEAN *Disconnected + ) +/*++ + + Routine Description: + Reset if the device is disconencted or not + + Arguments: + UsbIoController - Indicating the Usb Controller Device. + Disconnected - Indicate whether the device is disconencted or not + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + +--*/ +{ + USB_IO_DEVICE *ParentIoDev; + USB_IO_DEVICE *UsbIoDev; + USB_IO_CONTROLLER_DEVICE *ParentController; + UINT8 HubPort; + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_USB_PORT_STATUS PortStatus; + EFI_USB_HC_PROTOCOL *UsbHCInterface; + + ParentController = UsbIoController->Parent; + ParentIoDev = ParentController->UsbDevice; + UsbIoDev = UsbIoController->UsbDevice; + HubPort = UsbIoController->ParentPort; + + if (ParentIoDev->DeviceAddress == 1) { + // + // Connected to the root hub + // + UsbHCInterface = ParentIoDev->BusController->UsbHCInterface; + Status = UsbHCInterface->GetRootHubPortStatus ( + UsbHCInterface, + HubPort, + &PortStatus + ); + + } else { + UsbIo = &UsbIoController->UsbIo; + Status = HubGetPortStatus ( + &ParentController->UsbIo, + HubPort + 1, + (UINT32 *) &PortStatus + ); + + if (EFI_ERROR (Status)) { + return IsDeviceDisconnected (ParentController, Disconnected); + } + } + + *Disconnected = FALSE; + + if (!IsPortConnect (PortStatus.PortStatus)) { + *Disconnected = TRUE; + } + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbbus.h b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbbus.h new file mode 100644 index 0000000000..b32620342c --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbbus.h @@ -0,0 +1,261 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + Module Name: + + usbbus.h + + Abstract: + + Header file for USB bus driver Interface + + Revision History + + + +--*/ + +#ifndef _EFI_USB_BUS_H +#define _EFI_USB_BUS_H + + +#include +#include "Hub.h" +#include "Usbutil.h" + +//#ifdef EFI_DEBUG +extern UINTN gUSBDebugLevel; +extern UINTN gUSBErrorLevel; +//#endif + +#define MICROSECOND 10000 +#define ONESECOND (1000 * MICROSECOND) +#define BUSPOLLING_PERIOD ONESECOND +// +// We define some maximun value here +// +#define USB_MAXCONFIG 8 +#define USB_MAXALTSETTING 4 +#define USB_MAXINTERFACES 32 +#define USB_MAXENDPOINTS 16 +#define USB_MAXSTRINGS 16 +#define USB_MAXLANID 16 +#define USB_MAXCHILDREN 8 +#define USB_MAXCONTROLLERS 4 + +#define USB_IO_CONTROLLER_SIGNATURE EFI_SIGNATURE_32 ('u', 's', 'b', 'd') + +typedef struct { + LIST_ENTRY Link; + UINT16 StringIndex; + CHAR16 *String; +} STR_LIST_ENTRY; + +typedef struct { + LIST_ENTRY Link; + UINT16 Toggle; + EFI_USB_ENDPOINT_DESCRIPTOR EndpointDescriptor; +} ENDPOINT_DESC_LIST_ENTRY; + +typedef struct { + LIST_ENTRY Link; + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + LIST_ENTRY EndpointDescListHead; +} INTERFACE_DESC_LIST_ENTRY; + +typedef struct { + LIST_ENTRY Link; + EFI_USB_CONFIG_DESCRIPTOR CongfigDescriptor; + LIST_ENTRY InterfaceDescListHead; + UINTN ActiveInterface; +} CONFIG_DESC_LIST_ENTRY; + +// +// Forward declaring +// +struct usb_io_device; + +// +// This is used to form the USB Controller Handle +// +typedef struct usb_io_controller_device { + UINTN Signature; + EFI_HANDLE Handle; + EFI_USB_IO_PROTOCOL UsbIo; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_HANDLE HostController; + UINT8 CurrentConfigValue; + UINT8 InterfaceNumber; + struct usb_io_device *UsbDevice; + + BOOLEAN IsUsbHub; + BOOLEAN IsManagedByDriver; + + // + // Fields specified for USB Hub + // + EFI_EVENT HubNotify; + UINT8 HubEndpointAddress; + UINT8 StatusChangePort; + UINT8 DownstreamPorts; + + UINT8 ParentPort; + struct usb_io_controller_device *Parent; + struct usb_io_device *Children[USB_MAXCHILDREN]; +} USB_IO_CONTROLLER_DEVICE; + +#define USB_IO_CONTROLLER_DEVICE_FROM_USB_IO_THIS(a) \ + CR(a, USB_IO_CONTROLLER_DEVICE, UsbIo, USB_IO_CONTROLLER_SIGNATURE) + +// +// This is used to keep the topology of USB bus +// +struct _usb_bus_controller_device; + +typedef struct usb_io_device { + UINT8 DeviceAddress; + BOOLEAN IsConfigured; + BOOLEAN IsSlowDevice; + EFI_USB_DEVICE_DESCRIPTOR DeviceDescriptor; + LIST_ENTRY ConfigDescListHead; + CONFIG_DESC_LIST_ENTRY *ActiveConfig; + UINT16 LangID[USB_MAXLANID]; + + struct _usb_bus_controller_device *BusController; + + // + // Track the controller handle + // + UINT8 NumOfControllers; + USB_IO_CONTROLLER_DEVICE *UsbController[USB_MAXCONTROLLERS]; + +} USB_IO_DEVICE; + +// +// Usb Bus Controller device strcuture +// +#define EFI_USB_BUS_PROTOCOL_GUID \ + { 0x2B2F68CC, 0x0CD2, 0x44cf, { 0x8E, 0x8B, 0xBB, 0xA2, 0x0B, 0x1B, 0x5B, 0x75 } } + +typedef struct _EFI_USB_BUS_PROTOCOL { + UINT64 Reserved; +} EFI_USB_BUS_PROTOCOL; + +#define USB_BUS_DEVICE_SIGNATURE EFI_SIGNATURE_32 ('u', 'b', 'u', 's') + +typedef struct _usb_bus_controller_device { + UINTN Signature; + + EFI_USB_BUS_PROTOCOL BusIdentify; + EFI_USB_HC_PROTOCOL *UsbHCInterface; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + UINT8 AddressPool[16]; + USB_IO_DEVICE *Root; +} USB_BUS_CONTROLLER_DEVICE; + +#define USB_BUS_CONTROLLER_DEVICE_FROM_THIS(a) \ + CR(a, USB_BUS_CONTROLLER_DEVICE, BusIdentify, USB_BUS_DEVICE_SIGNATURE) + + +// +// Global Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gUsbBusDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gUsbBusComponentName; +extern EFI_GUID gUSBBusDriverGuid; + +// +// Usb Device Configuration functions +// +BOOLEAN +IsHub ( + IN USB_IO_CONTROLLER_DEVICE *Dev + ); + +EFI_STATUS +UsbGetStringtable ( + IN USB_IO_DEVICE *UsbIoDevice + ); + +EFI_STATUS +UsbGetAllConfigurations ( + IN USB_IO_DEVICE *UsbIoDevice + ); + +EFI_STATUS +UsbSetConfiguration ( + IN USB_IO_DEVICE *Dev, + IN UINTN ConfigurationValue + ); + +EFI_STATUS +UsbSetDefaultConfiguration ( + IN USB_IO_DEVICE *Dev + ); + +// +// Device Deconfiguration functions +// +VOID +UsbDestroyAllConfiguration ( + IN USB_IO_DEVICE *UsbIoDevice + ); + +EFI_STATUS +DoHubConfig ( + IN USB_IO_CONTROLLER_DEVICE *HubIoDevice + ); + +VOID +GetDeviceEndPointMaxPacketLength ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 EndpointAddr, + OUT UINT8 *MaxPacketLength + ); + +VOID +GetDataToggleBit ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 EndpointAddr, + OUT UINT8 *DataToggle + ); + +VOID +SetDataToggleBit ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 EndpointAddr, + IN UINT8 DataToggle + ); + +INTERFACE_DESC_LIST_ENTRY * +FindInterfaceListEntry ( + IN EFI_USB_IO_PROTOCOL *This + ); + +ENDPOINT_DESC_LIST_ENTRY * +FindEndPointListEntry ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT8 EndPointAddress + ); + + +EFI_STATUS +IsDeviceDisconnected ( + IN USB_IO_CONTROLLER_DEVICE *UsbIoController, + IN OUT BOOLEAN *Disconnected + ); + +EFI_STATUS +UsbDeviceDeConfiguration ( + IN USB_IO_DEVICE *UsbIoDevice + ); + + +#endif diff --git a/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbio.c b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbio.c new file mode 100644 index 0000000000..bd87c5ca2e --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbio.c @@ -0,0 +1,1176 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + Module Name: + + UsbIo.c + + Abstract: + + USB I/O Abstraction Driver + + Revision History + +--*/ + +#include "usbbus.h" + +// +// USB I/O Support Function Prototypes +// +STATIC +EFI_STATUS +EFIAPI +UsbControlTransfer ( + 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 *Status + ); + +STATIC +EFI_STATUS +EFIAPI +UsbBulkTransfer ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT8 DeviceEndpoint, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN UINTN Timeout, + OUT UINT32 *Status + ); + +STATIC +EFI_STATUS +EFIAPI +UsbAsyncInterruptTransfer ( + IN EFI_USB_IO_PROTOCOL * This, + IN UINT8 DeviceEndpoint, + IN BOOLEAN IsNewTransfer, + IN UINTN PollingInterval, OPTIONAL + IN UINTN DataLength, OPTIONAL + IN EFI_ASYNC_USB_TRANSFER_CALLBACK InterruptCallBack, OPTIONAL + IN VOID *Context OPTIONAL + ); + +STATIC +EFI_STATUS +EFIAPI +UsbSyncInterruptTransfer ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT8 DeviceEndpoint, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN UINTN Timeout, + OUT UINT32 *Status + ); + +STATIC +EFI_STATUS +EFIAPI +UsbIsochronousTransfer ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT8 DeviceEndpoint, + IN OUT VOID *Data, + IN UINTN DataLength, + OUT UINT32 *Status + ); + +STATIC +EFI_STATUS +EFIAPI +UsbAsyncIsochronousTransfer ( + 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 + ); + +extern +EFI_STATUS +EFIAPI +UsbPortReset ( + IN EFI_USB_IO_PROTOCOL *This + ); + +STATIC +EFI_STATUS +EFIAPI +UsbGetDeviceDescriptor ( + IN EFI_USB_IO_PROTOCOL *This, + OUT EFI_USB_DEVICE_DESCRIPTOR *DeviceDescriptor + ); + +STATIC +EFI_STATUS +EFIAPI +UsbGetActiveConfigDescriptor ( + IN EFI_USB_IO_PROTOCOL *This, + OUT EFI_USB_CONFIG_DESCRIPTOR *ConfigurationDescriptor + ); + +STATIC +EFI_STATUS +EFIAPI +UsbGetInterfaceDescriptor ( + IN EFI_USB_IO_PROTOCOL *This, + OUT EFI_USB_INTERFACE_DESCRIPTOR *InterfaceDescriptor + ); + +STATIC +EFI_STATUS +EFIAPI +UsbGetEndpointDescriptor ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT8 EndpointIndex, + OUT EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDescriptor + ); + +STATIC +EFI_STATUS +EFIAPI +UsbGetStringDescriptor ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT16 LangID, + IN UINT8 StringIndex, + OUT CHAR16 **String + ); + +STATIC +EFI_STATUS +EFIAPI +UsbGetSupportedLanguages ( + IN EFI_USB_IO_PROTOCOL *This, + OUT UINT16 **LangIDTable, + OUT UINT16 *TableSize + ); + +// +// USB I/O Interface structure +// +STATIC EFI_USB_IO_PROTOCOL UsbIoInterface = { + UsbControlTransfer, + UsbBulkTransfer, + UsbAsyncInterruptTransfer, + UsbSyncInterruptTransfer, + UsbIsochronousTransfer, + UsbAsyncIsochronousTransfer, + UsbGetDeviceDescriptor, + UsbGetActiveConfigDescriptor, + UsbGetInterfaceDescriptor, + UsbGetEndpointDescriptor, + UsbGetStringDescriptor, + UsbGetSupportedLanguages, + UsbPortReset +}; + +VOID +InitializeUsbIoInstance ( + IN USB_IO_CONTROLLER_DEVICE *UsbIoController + ) +{ + // + // Copy EFI_USB_IO protocol instance + // + CopyMem ( + &UsbIoController->UsbIo, + &UsbIoInterface, + sizeof (EFI_USB_IO_PROTOCOL) + ); +} +// +// Implementation +// +STATIC +EFI_STATUS +EFIAPI +UsbControlTransfer ( + 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 *Status + ) +/*++ + + Routine Description: + This function is used to manage a USB device with a control transfer pipe. + + Arguments: + This - Indicates calling context. + Request - A pointer to the USB device request that will be sent to + the USB device. + Direction - Indicates the data direction. + Data - A pointer to the buffer of data that will be transmitted + to USB device or received from USB device. + Timeout - Indicates the transfer should be completed within this time + frame. + DataLength - The size, in bytes, of the data buffer specified by Data. + Status - A pointer to the result of the USB transfer. + + Returns: + EFI_SUCCESS + EFI_INVALID_PARAMETER + EFI_OUT_OF_RESOURCES + EFI_TIMEOUT + EFI_DEVICE_ERROR + +--*/ +{ + USB_IO_CONTROLLER_DEVICE *UsbIoController; + EFI_USB_HC_PROTOCOL *UsbHCInterface; + EFI_STATUS RetStatus; + USB_IO_DEVICE *UsbIoDevice; + UINT8 MaxPacketLength; + UINT32 TransferResult; + BOOLEAN Disconnected; + // + // Parameters Checking + // + if (Status == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // leave the HostController's ControlTransfer + // to perform other parameters checking + // + UsbIoController = USB_IO_CONTROLLER_DEVICE_FROM_USB_IO_THIS (This); + UsbIoDevice = UsbIoController->UsbDevice; + UsbHCInterface = UsbIoDevice->BusController->UsbHCInterface; + MaxPacketLength = UsbIoDevice->DeviceDescriptor.MaxPacketSize0; + + + if (Request->Request == USB_DEV_CLEAR_FEATURE && + Request->RequestType == 0x02 && + Request->Value == EfiUsbEndpointHalt) { + // + //Reduce the remove delay time for system response + // + IsDeviceDisconnected (UsbIoController, &Disconnected); + if (!EFI_ERROR (Status) && Disconnected == TRUE) { + DEBUG ((gUSBErrorLevel, "Device is disconnected when trying reset\n")); + return EFI_DEVICE_ERROR; + } + } + + + + // + // using HostController's ControlTransfer to complete the request + // + RetStatus = UsbHCInterface->ControlTransfer ( + UsbHCInterface, + UsbIoDevice->DeviceAddress, + UsbIoDevice->IsSlowDevice, + MaxPacketLength, + Request, + Direction, + Data, + &DataLength, + (UINTN) Timeout, + &TransferResult + ); + *Status = TransferResult; + + if (Request->Request == USB_DEV_CLEAR_FEATURE && + Request->RequestType == 0x02 && + Request->Value == EfiUsbEndpointHalt) { + // + // This is a UsbClearEndpointHalt request + // Need to clear data toggle + // Request.Index == EndpointAddress + // + if (!EFI_ERROR (RetStatus) && TransferResult == EFI_USB_NOERROR) { + SetDataToggleBit ( + This, + (UINT8) Request->Index, + 0 + ); + } + } + return RetStatus; +} + +STATIC +EFI_STATUS +EFIAPI +UsbBulkTransfer ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT8 DeviceEndpoint, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN UINTN Timeout, + OUT UINT32 *Status + ) +/*++ + + Routine Description: + This function is used to manage a USB device with the bulk transfer pipe. + + Arguments: + This - Indicates calling context. + DeviceEndpoint - The destination USB device endpoint to which the device + request is being sent. + Data - A pointer to the buffer of data that will be transmitted + to USB device or received from USB device. + DataLength - On input, the size, in bytes, of the data buffer + specified by Data. On output, the number of bytes that + were actually transferred. + Timeout - Indicates the transfer should be completed within this + time frame. + Status - This parameter indicates the USB transfer status. + + Returns: + EFI_SUCCESS + EFI_INVALID_PARAMETER + EFI_OUT_OF_RESOURCES + EFI_TIMEOUT + EFI_DEVICE_ERROR + +--*/ +{ + USB_IO_DEVICE *UsbIoDev; + UINT8 MaxPacketLength; + UINT8 DataToggle; + UINT8 OldToggle; + EFI_STATUS RetStatus; + EFI_USB_HC_PROTOCOL *UsbHCInterface; + USB_IO_CONTROLLER_DEVICE *UsbIoController; + ENDPOINT_DESC_LIST_ENTRY *EndPointListEntry; + UINT32 TransferResult; + + UsbIoController = USB_IO_CONTROLLER_DEVICE_FROM_USB_IO_THIS (This); + UsbIoDev = UsbIoController->UsbDevice; + UsbHCInterface = UsbIoDev->BusController->UsbHCInterface; + + // + // Parameters Checking + // + if ((DeviceEndpoint & 0x7F) == 0) { + return EFI_INVALID_PARAMETER; + } + + if ((DeviceEndpoint & 0x7F) > 15) { + return EFI_INVALID_PARAMETER; + } + + if (Status == NULL) { + return EFI_INVALID_PARAMETER; + } + + EndPointListEntry = FindEndPointListEntry ( + This, + DeviceEndpoint + ); + + if (EndPointListEntry == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((EndPointListEntry->EndpointDescriptor.Attributes & 0x03) != 0x02) { + return EFI_INVALID_PARAMETER; + } + + // + // leave the HostController's BulkTransfer + // to perform other parameters checking + // + GetDeviceEndPointMaxPacketLength ( + This, + DeviceEndpoint, + &MaxPacketLength + ); + + GetDataToggleBit ( + This, + DeviceEndpoint, + &DataToggle + ); + + OldToggle = DataToggle; + + // + // using HostController's BulkTransfer to complete the request + // + RetStatus = UsbHCInterface->BulkTransfer ( + UsbHCInterface, + UsbIoDev->DeviceAddress, + DeviceEndpoint, + MaxPacketLength, + Data, + DataLength, + &DataToggle, + Timeout, + &TransferResult + ); + + if (OldToggle != DataToggle) { + // + // Write the toggle back + // + SetDataToggleBit ( + This, + DeviceEndpoint, + DataToggle + ); + } + + *Status = TransferResult; + + return RetStatus; +} + +STATIC +EFI_STATUS +EFIAPI +UsbSyncInterruptTransfer ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT8 DeviceEndpoint, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN UINTN Timeout, + OUT UINT32 *Status + ) +/*++ + + Routine Description: + Usb Sync Interrupt Transfer + + Arguments: + This - Indicates calling context. + DeviceEndpoint - The destination USB device endpoint to which the device + request is being sent. + Data - A pointer to the buffer of data that will be transmitted + to USB device or received from USB device. + DataLength - On input, the size, in bytes, of the data buffer + specified by Data. On output, the number of bytes that + were actually transferred. + Timeout - Indicates the transfer should be completed within this + time frame. + Status - This parameter indicates the USB transfer status. + + Returns: + EFI_SUCCESS + EFI_INVALID_PARAMETER + EFI_OUT_OF_RESOURCES + EFI_TIMEOUT + EFI_DEVICE_ERROR + +--*/ +{ + USB_IO_DEVICE *UsbIoDev; + UINT8 MaxPacketLength; + UINT8 DataToggle; + UINT8 OldToggle; + EFI_STATUS RetStatus; + EFI_USB_HC_PROTOCOL *UsbHCInterface; + USB_IO_CONTROLLER_DEVICE *UsbIoController; + ENDPOINT_DESC_LIST_ENTRY *EndPointListEntry; + + // + // Parameters Checking + // + if ((DeviceEndpoint & 0x7F) == 0) { + return EFI_INVALID_PARAMETER; + } + + if ((DeviceEndpoint & 0x7F) > 15) { + return EFI_INVALID_PARAMETER; + } + + if (Status == NULL) { + return EFI_INVALID_PARAMETER; + } + + EndPointListEntry = FindEndPointListEntry ( + This, + DeviceEndpoint + ); + + if (EndPointListEntry == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((EndPointListEntry->EndpointDescriptor.Attributes & 0x03) != 0x03) { + return EFI_INVALID_PARAMETER; + } + + // + // leave the HostController's SyncInterruptTransfer + // to perform other parameters checking + // + UsbIoController = USB_IO_CONTROLLER_DEVICE_FROM_USB_IO_THIS (This); + UsbIoDev = UsbIoController->UsbDevice; + UsbHCInterface = UsbIoDev->BusController->UsbHCInterface; + + GetDeviceEndPointMaxPacketLength ( + This, + DeviceEndpoint, + &MaxPacketLength + ); + + GetDataToggleBit ( + This, + DeviceEndpoint, + &DataToggle + ); + + OldToggle = DataToggle; + // + // using HostController's SyncInterruptTransfer to complete the request + // + RetStatus = UsbHCInterface->SyncInterruptTransfer ( + UsbHCInterface, + UsbIoDev->DeviceAddress, + DeviceEndpoint, + UsbIoDev->IsSlowDevice, + MaxPacketLength, + Data, + DataLength, + &DataToggle, + Timeout, + Status + ); + + if (OldToggle != DataToggle) { + // + // Write the toggle back + // + SetDataToggleBit ( + This, + DeviceEndpoint, + DataToggle + ); + } + + return RetStatus; +} + +STATIC +EFI_STATUS +EFIAPI +UsbAsyncInterruptTransfer ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT8 DeviceEndpoint, + IN BOOLEAN IsNewTransfer, + IN UINTN PollingInterval, OPTIONAL + IN UINTN DataLength, OPTIONAL + IN EFI_ASYNC_USB_TRANSFER_CALLBACK InterruptCallBack, OPTIONAL + IN VOID *Context OPTIONAL + ) +/*++ + + Routine Description: + Usb Async Interrput Transfer + + Arguments: + This - Indicates calling context. + DeviceEndpoint - The destination USB device endpoint to which the + device request is being sent. + IsNewTransfer - If TRUE, a new transfer will be submitted to USB + controller. If FALSE, the interrupt transfer is + deleted from the device's interrupt transfer queue. + PollingInterval - Indicates the periodic rate, in milliseconds, that + the transfer is to be executed. + DataLength - Specifies the length, in bytes, of the data to be + received from the USB device. + InterruptCallback - The Callback function. This function is called if + the asynchronous interrupt transfer is completed. + Context - Passed to InterruptCallback + Returns: + EFI_SUCCESS + EFI_INVALID_PARAMETER + EFI_OUT_OF_RESOURCES + +--*/ +{ + USB_IO_DEVICE *UsbIoDev; + UINT8 MaxPacketLength; + UINT8 DataToggle; + EFI_USB_HC_PROTOCOL *UsbHCInterface; + EFI_STATUS RetStatus; + USB_IO_CONTROLLER_DEVICE *UsbIoController; + ENDPOINT_DESC_LIST_ENTRY *EndpointListEntry; + + // + // Check endpoint + // + if ((DeviceEndpoint & 0x7F) == 0) { + return EFI_INVALID_PARAMETER; + } + + if ((DeviceEndpoint & 0x7F) > 15) { + return EFI_INVALID_PARAMETER; + } + + EndpointListEntry = FindEndPointListEntry ( + This, + DeviceEndpoint + ); + + if (EndpointListEntry == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((EndpointListEntry->EndpointDescriptor.Attributes & 0x03) != 0x03) { + return EFI_INVALID_PARAMETER; + } + + UsbIoController = USB_IO_CONTROLLER_DEVICE_FROM_USB_IO_THIS (This); + UsbIoDev = UsbIoController->UsbDevice; + UsbHCInterface = UsbIoDev->BusController->UsbHCInterface; + + if (!IsNewTransfer) { + // + // Delete this transfer + // + UsbHCInterface->AsyncInterruptTransfer ( + UsbHCInterface, + UsbIoDev->DeviceAddress, + DeviceEndpoint, + UsbIoDev->IsSlowDevice, + 0, + FALSE, + &DataToggle, + PollingInterval, + DataLength, + NULL, + NULL + ); + + // + // We need to store the toggle value + // + SetDataToggleBit ( + This, + DeviceEndpoint, + DataToggle + ); + + return EFI_SUCCESS; + } + + GetDeviceEndPointMaxPacketLength ( + This, + DeviceEndpoint, + &MaxPacketLength + ); + + GetDataToggleBit ( + This, + DeviceEndpoint, + &DataToggle + ); + + RetStatus = UsbHCInterface->AsyncInterruptTransfer ( + UsbHCInterface, + UsbIoDev->DeviceAddress, + DeviceEndpoint, + UsbIoDev->IsSlowDevice, + MaxPacketLength, + TRUE, + &DataToggle, + PollingInterval, + DataLength, + InterruptCallBack, + Context + ); + + return RetStatus; +} + +STATIC +EFI_STATUS +EFIAPI +UsbIsochronousTransfer ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT8 DeviceEndpoint, + IN OUT VOID *Data, + IN UINTN DataLength, + OUT UINT32 *Status + ) +/*++ + + Routine Description: + Usb Isochronous Transfer + + Arguments: + This - Indicates calling context. + DeviceEndpoint - The destination USB device endpoint to which the + device request is being sent. + Data - A pointer to the buffer of data that will be + transmitted to USB device or received from USB device. + DataLength - The size, in bytes, of the data buffer specified by + Data. + Status - This parameter indicates the USB transfer status. + + Returns: + EFI_SUCCESS + EFI_INVALID_PARAMETER + EFI_OUT_OF_RESOURCES + EFI_TIMEOUT + EFI_DEVICE_ERROR + EFI_UNSUPPORTED +--*/ +{ + // + // Currently we don't support this transfer + // + return EFI_UNSUPPORTED; +} + +STATIC +EFI_STATUS +EFIAPI +UsbAsyncIsochronousTransfer ( + 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 + ) +/*++ + +Routine Description: + + Usb Async Isochronous Transfer + +Arguments: + + This - EFI_USB_IO_PROTOCOL + DeviceEndpoint - DeviceEndpoint number + Data - Data to transfer + DataLength - DataLength + IsochronousCallBack - Isochronous CallBack function + Context - Passed to IsochronousCallBack function +Returns: + + EFI_UNSUPPORTED - Unsupported now + +--*/ +{ + // + // Currently we don't support this transfer + // + return EFI_UNSUPPORTED; +} +// +// Here is new definitions +// +STATIC +EFI_STATUS +EFIAPI +UsbGetDeviceDescriptor ( + IN EFI_USB_IO_PROTOCOL *This, + OUT EFI_USB_DEVICE_DESCRIPTOR *DeviceDescriptor + ) +/*++ + + Routine Description: + Retrieves the USB Device Descriptor. + + Arguments: + This - Indicates the calling context. + DeviceDescriptor - A pointer to the caller allocated USB Device + Descriptor. + + Returns: + EFI_SUCCESS + EFI_INVALID_PARAMETER + EFI_NOT_FOUND + +--*/ +{ + USB_IO_CONTROLLER_DEVICE *UsbIoController; + USB_IO_DEVICE *UsbIoDev; + + // + // This function just wrapps UsbGetDeviceDescriptor. + // + + if (DeviceDescriptor == NULL) { + return EFI_INVALID_PARAMETER; + } + + UsbIoController = USB_IO_CONTROLLER_DEVICE_FROM_USB_IO_THIS (This); + UsbIoDev = UsbIoController->UsbDevice; + + if (!UsbIoDev->IsConfigured) { + return EFI_NOT_FOUND; + } + + CopyMem ( + DeviceDescriptor, + &UsbIoDev->DeviceDescriptor, + sizeof (EFI_USB_DEVICE_DESCRIPTOR) + ); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +UsbGetActiveConfigDescriptor ( + IN EFI_USB_IO_PROTOCOL *This, + OUT EFI_USB_CONFIG_DESCRIPTOR *ConfigurationDescriptor + ) +/*++ + + Routine Description: + Retrieves the current USB configuration Descriptor. + + Arguments: + This - Indicates the calling context. + ConfigurationDescriptor - A pointer to the caller allocated USB active + Configuration Descriptor. + + Returns: + EFI_SUCCESS + EFI_INVALID_PARAMETER + EFI_NOT_FOUND + +--*/ +{ + USB_IO_DEVICE *UsbIoDev; + USB_IO_CONTROLLER_DEVICE *UsbIoController; + + // + // This function just wrapps UsbGetActiveConfigDescriptor. + // + if (ConfigurationDescriptor == NULL) { + return EFI_INVALID_PARAMETER; + } + + UsbIoController = USB_IO_CONTROLLER_DEVICE_FROM_USB_IO_THIS (This); + UsbIoDev = UsbIoController->UsbDevice; + + if (!UsbIoDev->IsConfigured) { + return EFI_NOT_FOUND; + } + + CopyMem ( + ConfigurationDescriptor, + &(UsbIoDev->ActiveConfig->CongfigDescriptor), + sizeof (EFI_USB_CONFIG_DESCRIPTOR) + ); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +UsbGetInterfaceDescriptor ( + IN EFI_USB_IO_PROTOCOL *This, + OUT EFI_USB_INTERFACE_DESCRIPTOR *InterfaceDescriptor + ) +/*++ + + Routine Description: + Retrieves the interface Descriptor for that controller. + + Arguments: + This - Indicates the calling context. + InterfaceDescriptor - A pointer to the caller allocated USB interface + Descriptor. + + Returns: + EFI_SUCCESS + EFI_INVALID_PARAMETER + EFI_NOT_FOUND + +--*/ +{ + INTERFACE_DESC_LIST_ENTRY *InterfaceListEntry; + + if (InterfaceDescriptor == NULL) { + return EFI_INVALID_PARAMETER; + } + + InterfaceListEntry = FindInterfaceListEntry (This); + + if (InterfaceListEntry == NULL) { + return EFI_NOT_FOUND; + } + + CopyMem ( + InterfaceDescriptor, + &(InterfaceListEntry->InterfaceDescriptor), + sizeof (EFI_USB_INTERFACE_DESCRIPTOR) + ); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +UsbGetEndpointDescriptor ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT8 EndpointIndex, + OUT EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDescriptor + ) +/*++ + + Routine Description: + Retrieves the endpoint Descriptor for a given endpoint. + + Arguments: + This - Indicates the calling context. + EndpointIndex - Indicates which endpoint descriptor to retrieve. + The valid range is 0..15. + EndpointDescriptor - A pointer to the caller allocated USB Endpoint + Descriptor of a USB controller. + + Returns: + EFI_SUCCESS - The endpoint descriptor was retrieved successfully. + EFI_INVALID_PARAMETER - EndpointIndex is not valid. + - EndpointDescriptor is NULL. + EFI_NOT_FOUND - The endpoint descriptor cannot be found. + The device may not be correctly configured. + +--*/ +{ + INTERFACE_DESC_LIST_ENTRY *InterfaceListEntry; + LIST_ENTRY *EndpointListHead; + ENDPOINT_DESC_LIST_ENTRY *EndpointListEntry; + + if (EndpointDescriptor == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (EndpointIndex > 15) { + return EFI_INVALID_PARAMETER; + } + + InterfaceListEntry = FindInterfaceListEntry (This); + + if (InterfaceListEntry == NULL) { + return EFI_NOT_FOUND; + } + + EndpointListHead = (LIST_ENTRY *) (&InterfaceListEntry->EndpointDescListHead); + EndpointListEntry = (ENDPOINT_DESC_LIST_ENTRY *) (EndpointListHead->ForwardLink); + + if (EndpointIndex >= InterfaceListEntry->InterfaceDescriptor.NumEndpoints) { + return EFI_NOT_FOUND; + } + // + // Loop all endpoint descriptor to get match one. + // + while (EndpointIndex != 0) { + EndpointListEntry = (ENDPOINT_DESC_LIST_ENTRY *) (EndpointListEntry->Link.ForwardLink); + EndpointIndex--; + } + + CopyMem ( + EndpointDescriptor, + &EndpointListEntry->EndpointDescriptor, + sizeof (EFI_USB_ENDPOINT_DESCRIPTOR) + ); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +UsbGetSupportedLanguages ( + IN EFI_USB_IO_PROTOCOL *This, + OUT UINT16 **LangIDTable, + OUT UINT16 *TableSize + ) +/*++ + + Routine Description: + Get all the languages that the USB device supports + + Arguments: + This - Indicates the calling context. + LangIDTable - Language ID for the string the caller wants to get. + TableSize - The size, in bytes, of the table LangIDTable. + + Returns: + EFI_SUCCESS + EFI_NOT_FOUND + +--*/ +{ + USB_IO_DEVICE *UsbIoDev; + USB_IO_CONTROLLER_DEVICE *UsbIoController; + UINTN Index; + BOOLEAN Found; + + UsbIoController = USB_IO_CONTROLLER_DEVICE_FROM_USB_IO_THIS (This); + UsbIoDev = UsbIoController->UsbDevice; + + Found = FALSE; + Index = 0; + // + // Loop language table + // + while (UsbIoDev->LangID[Index]) { + Found = TRUE; + Index++; + } + + if (!Found) { + return EFI_NOT_FOUND; + } + + *LangIDTable = UsbIoDev->LangID; + *TableSize = (UINT16) Index; + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +UsbGetStringDescriptor ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT16 LangID, + IN UINT8 StringIndex, + OUT CHAR16 **String + ) +/*++ + + Routine Description: + Get a given string descriptor + + Arguments: + This - Indicates the calling context. + LangID - The Language ID for the string being retrieved. + StringIndex - The ID of the string being retrieved. + String - A pointer to a buffer allocated by this function + with AllocatePool() to store the string. If this + function returns EFI_SUCCESS, it stores the string + the caller wants to get. The caller should release + the string buffer with FreePool() after the string + is not used any more. + Returns: + EFI_SUCCESS + EFI_NOT_FOUND + EFI_OUT_OF_RESOURCES + +--*/ +{ + UINT32 Status; + EFI_STATUS Result; + EFI_USB_STRING_DESCRIPTOR *StrDescriptor; + UINT8 *Buffer; + CHAR16 *UsbString; + UINT16 TempBuffer; + USB_IO_DEVICE *UsbIoDev; + UINT8 Index; + BOOLEAN Found; + USB_IO_CONTROLLER_DEVICE *UsbIoController; + + if (StringIndex == 0) { + return EFI_NOT_FOUND; + } + // + // Search LanguageID, check if it is supported by this device + // + if (LangID == 0) { + return EFI_NOT_FOUND; + } + + UsbIoController = USB_IO_CONTROLLER_DEVICE_FROM_USB_IO_THIS (This); + UsbIoDev = UsbIoController->UsbDevice; + + Found = FALSE; + Index = 0; + while (UsbIoDev->LangID[Index]) { + if (UsbIoDev->LangID[Index] == LangID) { + Found = TRUE; + break; + } + + Index++; + } + + if (!Found) { + return EFI_NOT_FOUND; + } + // + // Get String Length + // + Result = UsbGetString ( + This, + LangID, + StringIndex, + &TempBuffer, + 2, + &Status + ); + if (EFI_ERROR (Result)) { + return EFI_NOT_FOUND; + } + + StrDescriptor = (EFI_USB_STRING_DESCRIPTOR *) &TempBuffer; + + if (StrDescriptor->Length == 0) { + return EFI_UNSUPPORTED; + } + + Buffer = AllocateZeroPool (StrDescriptor->Length); + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Result = UsbGetString ( + This, + LangID, + StringIndex, + Buffer, + StrDescriptor->Length, + &Status + ); + + if (EFI_ERROR (Result)) { + gBS->FreePool (Buffer); + return EFI_NOT_FOUND; + } + + StrDescriptor = (EFI_USB_STRING_DESCRIPTOR *) Buffer; + + // + // UsbString is a UNICODE string + // + UsbString = AllocateZeroPool (StrDescriptor->Length); + if (UsbString == NULL) { + gBS->FreePool (Buffer); + return EFI_OUT_OF_RESOURCES; + } + + CopyMem ( + (VOID *) UsbString, + Buffer + 2, + StrDescriptor->Length - 2 + ); + + *String = UsbString; + + gBS->FreePool (Buffer); + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbutil.c b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbutil.c new file mode 100644 index 0000000000..07eb5805e9 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbutil.c @@ -0,0 +1,556 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + Module Name: + usbutil.c + + Abstract: + + Helper functions for USB + + Revision History + +--*/ + +#include "usbbus.h" + +// +// Following APIs are used to query Port Status +// +BOOLEAN +IsPortConnect ( + IN UINT16 PortStatus + ) +/*++ + + Routine Description: + Tell if there is a device connected to that port according to + the Port Status. + + Parameters: + PortStatus - The status value of that port. + + Return Value: + TRUE + FALSE + +--*/ +{ + // + // return the bit 0 value of PortStatus + // + if ((PortStatus & USB_PORT_STAT_CONNECTION) != 0) { + return TRUE; + } else { + return FALSE; + } +} + +BOOLEAN +IsPortEnable ( + IN UINT16 PortStatus + ) +/*++ + + Routine Description: + Tell if Port is enabled. + + Arguments: + PortStatus - The status value of that port. + + Returns: + TRUE - Port is enable + FALSE - Port is disable + +--*/ +{ + // + // return the bit 1 value of PortStatus + // + if ((PortStatus & USB_PORT_STAT_ENABLE) != 0) { + return TRUE; + } else { + return FALSE; + } +} + +BOOLEAN +IsPortInReset ( + IN UINT16 PortStatus + ) +/*++ + + Routine Description: + Tell if the port is being reset. + + Arguments: + PortStatus - The status value of that port. + + Returns: + TRUE + FALSE + +--*/ +{ + // + // return the bit 4 value of PortStatus + // + if ((PortStatus & USB_PORT_STAT_RESET) != 0) { + return TRUE; + } else { + return FALSE; + } +} + +BOOLEAN +IsPortPowerApplied ( + IN UINT16 PortStatus + ) +/*++ + + Routine Description: + Tell if there is power applied to that port. + + Arguments: + PortStatus - The status value of that port. + + Returns: + TRUE + FALSE + +--*/ +{ + // + // return the bit 8 value of PortStatus + // + if ((PortStatus & USB_PORT_STAT_POWER) != 0) { + return TRUE; + } else { + return FALSE; + } +} + +BOOLEAN +IsPortLowSpeedDeviceAttached ( + IN UINT16 PortStatus + ) +/*++ + + Routine Description: + Tell if the connected device is a low device. + + Arguments: + PortStatus - The status value of that port. + + Returns: + TRUE + FALSE + +--*/ +{ + // + // return the bit 9 value of PortStatus + // + if ((PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) { + return TRUE; + } else { + return FALSE; + } +} + +BOOLEAN +IsPortSuspend ( + IN UINT16 PortStatus + ) +/*++ + + Routine Description: + Tell if the port is suspend. + + Arguments: + PortStatus - The status value of that port. + + Returns: + TRUE + FALSE + +--*/ +{ + // + // return the bit 2 value of PortStatus + // + if ((PortStatus & USB_PORT_STAT_SUSPEND) != 0) { + return TRUE; + } else { + return FALSE; + } +} +// +// Following APIs are used to query Port Change Status +// +BOOLEAN +IsPortConnectChange ( + IN UINT16 PortChangeStatus + ) +/*++ + + Routine Description: + Tell if there is a Connect Change status in that port. + + Arguments: + PortChangeStatus - The status value of that port. + + Returns: + TRUE + FALSE + +--*/ +{ + // + // return the bit 0 value of PortChangeStatus + // + if ((PortChangeStatus & USB_PORT_STAT_C_CONNECTION) != 0) { + return TRUE; + } else { + return FALSE; + } +} + +BOOLEAN +IsPortEnableDisableChange ( + IN UINT16 PortChangeStatus + ) +/*++ + + Routine Description: + Tell if there is a Enable/Disable change in that port. + + Arguments: + PortChangeStatus - The status value of that port. + + Returns: + TRUE + FALSE + +--*/ +{ + // + // return the bit 1 value of PortChangeStatus + // + if ((PortChangeStatus & USB_PORT_STAT_C_ENABLE) != 0) { + return TRUE; + } else { + return FALSE; + } +} + +BOOLEAN +IsPortResetChange ( + IN UINT16 PortChangeStatus + ) +/*++ + + Routine Description: + Tell if there is a Port Reset Change status in that port. + + Arguments: + PortChangeStatus - The status value of that port. + + Returns: + TRUE + FALSE + +--*/ +{ + // + // return the bit 4 value of PortChangeStatus + // + if ((PortChangeStatus & USB_PORT_STAT_C_RESET) != 0) { + return TRUE; + } else { + return FALSE; + } +} + + +BOOLEAN +IsPortSuspendChange ( + IN UINT16 PortChangeStatus + ) +/*++ + + Routine Description: + Tell if there is a Suspend Change Status in that port. + + Arguments: + PortChangeStatus - The status value of that port. + + Returns: + TRUE + FALSE + +--*/ +{ + // + // return the bit 2 value of PortChangeStatus + // + if ((PortChangeStatus & USB_PORT_STAT_C_SUSPEND) != 0) { + return TRUE; + } else { + return FALSE; + } +} + + +INTERFACE_DESC_LIST_ENTRY* +FindInterfaceListEntry ( + IN EFI_USB_IO_PROTOCOL *This + ) +/*++ + + Routine Description: + Find Interface ListEntry. + + Arguments: + This - EFI_USB_IO_PROTOCOL + + Returns: + INTERFACE_DESC_LIST_ENTRY pointer + +--*/ +{ + USB_IO_CONTROLLER_DEVICE *UsbIoController; + USB_IO_DEVICE *UsbIoDev; + LIST_ENTRY *InterfaceListHead; + INTERFACE_DESC_LIST_ENTRY *InterfaceListEntry; + + UsbIoController = USB_IO_CONTROLLER_DEVICE_FROM_USB_IO_THIS (This); + UsbIoDev = UsbIoController->UsbDevice; + + if (!UsbIoDev->IsConfigured) { + return NULL; + } + + InterfaceListHead = &UsbIoDev->ActiveConfig->InterfaceDescListHead; + InterfaceListEntry = (INTERFACE_DESC_LIST_ENTRY *) (InterfaceListHead->ForwardLink); + + // + // Loop all interface descriptor to get match one. + // + while (InterfaceListEntry != (INTERFACE_DESC_LIST_ENTRY *) InterfaceListHead) { + if (InterfaceListEntry->InterfaceDescriptor.InterfaceNumber == UsbIoController->InterfaceNumber) { + return InterfaceListEntry; + } + + InterfaceListEntry = (INTERFACE_DESC_LIST_ENTRY *) InterfaceListEntry->Link.ForwardLink; + } + + return NULL; +} + +ENDPOINT_DESC_LIST_ENTRY* +FindEndPointListEntry ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT8 EndPointAddress + ) +/*++ + + Routine Description: + Find EndPoint ListEntry. + + Arguments: + This - EFI_USB_IO_PROTOCOL + EndpointAddr - Endpoint address. + + Returns: + ENDPOINT_DESC_LIST_ENTRY pointer + +--*/ +{ + INTERFACE_DESC_LIST_ENTRY *InterfaceListEntry; + LIST_ENTRY *EndpointDescListHead; + ENDPOINT_DESC_LIST_ENTRY *EndPointListEntry; + + InterfaceListEntry = FindInterfaceListEntry (This); + if (InterfaceListEntry != NULL) { + EndpointDescListHead = &InterfaceListEntry->EndpointDescListHead; + EndPointListEntry = (ENDPOINT_DESC_LIST_ENTRY *) (EndpointDescListHead->ForwardLink); + + // + // Loop all interface descriptor to get match one. + // + while (EndPointListEntry != (ENDPOINT_DESC_LIST_ENTRY *) EndpointDescListHead) { + if (EndPointListEntry->EndpointDescriptor.EndpointAddress == EndPointAddress) { + return EndPointListEntry; + } + + EndPointListEntry = (ENDPOINT_DESC_LIST_ENTRY *) EndPointListEntry->Link.ForwardLink; + } + } + + return NULL; +} + +VOID +GetDataToggleBit ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 EndpointAddr, + OUT UINT8 *DataToggle + ) +/*++ + + Routine Description: + Get the datatoggle of a specified endpoint. + + Arguments: + UsbIo - Given Usb Controller device. + EndpointAddr - Given Endpoint address. + DataToggle - The current data toggle of that endpoint + + Returns: + N/A + +--*/ +{ + + ENDPOINT_DESC_LIST_ENTRY *EndpointListEntry; + + *DataToggle = 0; + + EndpointListEntry = FindEndPointListEntry (UsbIo, EndpointAddr); + if (EndpointListEntry == NULL) { + return ; + } + + *DataToggle = (UINT8) (EndpointListEntry->Toggle); + return ; +} + +VOID +SetDataToggleBit ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 EndpointAddr, + IN UINT8 DataToggle + ) +/*++ + + Routine Description: + Set the datatoggle of a specified endpoint + + Arguments: + UsbIo - Given Usb Controller device. + EndpointAddr - Given Endpoint address. + DataToggle - The current data toggle of that endpoint to be set + + Returns: + N/A + +--*/ +{ + + ENDPOINT_DESC_LIST_ENTRY *EndpointListEntry; + + EndpointListEntry = FindEndPointListEntry (UsbIo, EndpointAddr); + if (EndpointListEntry == NULL) { + return ; + } + + EndpointListEntry->Toggle = DataToggle; + return ; +} + +VOID +GetDeviceEndPointMaxPacketLength ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 EndpointAddr, + OUT UINT8 *MaxPacketLength + ) +/*++ + + Routine Description: + Get the Max Packet Length of the speified Endpoint. + + Arguments: + UsbIo - Given Usb Controller device. + EndpointAddr - Given Endpoint address. + MaxPacketLength - The max packet length of that endpoint + + Returns: + N/A + +--*/ +{ + + ENDPOINT_DESC_LIST_ENTRY *EndpointListEntry; + + *MaxPacketLength = 0; + + EndpointListEntry = FindEndPointListEntry (UsbIo, EndpointAddr); + if (EndpointListEntry == NULL) { + return ; + } + + *MaxPacketLength = (UINT8) (EndpointListEntry->EndpointDescriptor.MaxPacketSize); + + return ; +} + + +EFI_STATUS +UsbSetDeviceAddress ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT16 AddressValue, + OUT UINT32 *Status + ) +/*++ + +Routine Description: + + Usb Set Device Address + +Arguments: + + UsbIo - EFI_USB_IO_PROTOCOL + AddressValue - Device address + Status - Transfer status + +Returns: + + EFI_INVALID_PARAMETER - Parameter is error + EFI_SUCCESS - Success + EFI_TIMEOUT - Device has no response + + +--*/ +{ + EFI_USB_DEVICE_REQUEST DevReq; + + if (UsbIo == NULL) { + return EFI_INVALID_PARAMETER; + } + + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); + + DevReq.RequestType = USB_DEV_SET_ADDRESS_REQ_TYPE; + DevReq.Request = USB_DEV_SET_ADDRESS; + DevReq.Value = AddressValue; + + return UsbIo->UsbControlTransfer ( + UsbIo, + &DevReq, + EfiUsbNoData, + TIMEOUT_VALUE, + NULL, + 0, + Status + ); +} + diff --git a/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbutil.h b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbutil.h new file mode 100644 index 0000000000..259276cbaf --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbutil.h @@ -0,0 +1,94 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + Module Name: + usbutil.h + + Abstract: + + Helper functions for USB + + Revision History + + +--*/ + +#ifndef _USB_UTIL_H +#define _USB_UTIL_H + +// +// Following APIs are used to query Port Status +// +BOOLEAN +IsPortConnect ( + IN UINT16 PortStatus + ); + +BOOLEAN +IsPortEnable ( + IN UINT16 PortStatus + ); + +BOOLEAN +IsPortInReset ( + IN UINT16 PortStatus + ); + +BOOLEAN +IsPortPowerApplied ( + IN UINT16 PortStatus + ); + +BOOLEAN +IsPortLowSpeedDeviceAttached ( + IN UINT16 PortStatus + ); + +BOOLEAN +IsPortSuspend ( + IN UINT16 PortStatus + ); + +// +// Following APIs are used to query Port Change Status +// +BOOLEAN +IsPortConnectChange ( + IN UINT16 PortChangeStatus + ); + +BOOLEAN +IsPortEnableDisableChange ( + IN UINT16 PortChangeStatus + ); + +BOOLEAN +IsPortResetChange ( + IN UINT16 PortChangeStatus + ); + +BOOLEAN +IsPortSuspendChange ( + IN UINT16 PortChangeStatus + ); + +// +// Set device address; +// +EFI_STATUS +UsbSetDeviceAddress ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT16 AddressValue, + OUT UINT32 *Status + ); + + +#endif diff --git a/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/Cbi0.c b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/Cbi0.c new file mode 100644 index 0000000000..5bd8728fcf --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/Cbi0.c @@ -0,0 +1,1042 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Cbi0.c + +Abstract: + +--*/ + +#include "../cbi.h" + +extern EFI_COMPONENT_NAME_PROTOCOL gUsbCbi0ComponentName; +// +// Function prototypes +// +EFI_STATUS +EFIAPI +UsbCbi0DriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +// +// Bot Driver Binding Protocol +// +STATIC +EFI_STATUS +EFIAPI +Cbi0DriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +STATIC +EFI_STATUS +EFIAPI +Cbi0DriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +STATIC +EFI_STATUS +EFIAPI +Cbi0DriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +VOID +Cbi0ReportStatusCode ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN EFI_STATUS_CODE_TYPE CodeType, + IN EFI_STATUS_CODE_VALUE Value + ); + + +EFI_DRIVER_BINDING_PROTOCOL gUsbCbi0DriverBinding = { + Cbi0DriverBindingSupported, + Cbi0DriverBindingStart, + Cbi0DriverBindingStop, + 0x10, + NULL, + NULL +}; + +STATIC +EFI_STATUS +Cbi0RecoveryReset ( + IN USB_CBI_DEVICE *UsbCbiDev + ); + +STATIC +EFI_STATUS +Cbi0CommandPhase ( + IN USB_CBI_DEVICE *UsbCbiDev, + IN VOID *Command, + IN UINT8 CommandSize, + IN UINT16 Timeout + ); + +STATIC +EFI_STATUS +Cbi0DataPhase ( + IN USB_CBI_DEVICE *UsbCbiDev, + IN UINT32 *DataSize, + IN OUT VOID *DataBuffer, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT16 Timeout + ); + +STATIC +EFI_STATUS +Cbi0StatusPhase ( + IN USB_CBI_DEVICE *UsbCbiDev, + OUT INTERRUPT_DATA_BLOCK *InterruptDataBlock, + IN UINT16 Timeout + ); + +// +// USB Atapi protocol prototype +// +STATIC +EFI_STATUS +EFIAPI +Cbi0AtapiCommand ( + IN EFI_USB_ATAPI_PROTOCOL *This, + IN VOID *Command, + IN UINT8 CommandSize, + IN VOID *DataBuffer, + IN UINT32 BufferLength, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT16 TimeOutInMilliSeconds + ); + +STATIC +EFI_STATUS +EFIAPI +Cbi0MassStorageReset ( + IN EFI_USB_ATAPI_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +STATIC EFI_USB_ATAPI_PROTOCOL Cbi0AtapiProtocol = { + Cbi0AtapiCommand, + Cbi0MassStorageReset, + 0 +}; + +STATIC +EFI_STATUS +EFIAPI +Cbi0DriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + Test to see if this driver supports ControllerHandle. Any ControllerHandle + than contains a BlockIo and DiskIo protocol can be supported. + + Arguments: + This - Protocol instance pointer. + ControllerHandle - Handle of device to test + RemainingDevicePath - Not used + + Returns: + EFI_SUCCESS - This driver supports this device + EFI_ALREADY_STARTED - This driver is already running on this device + other - This driver does not support this device + +--*/ +{ + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + + // + // Check if the Controller supports USB IO protocol + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + (VOID **) &UsbIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Get the Default interface descriptor, now we only + // suppose interface 1 + // + Status = UsbIo->UsbGetInterfaceDescriptor ( + UsbIo, + &InterfaceDescriptor + ); + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + return Status; + } + // + // Check if it is a Cbi0 Type Mass Storage Device + // + if((InterfaceDescriptor.InterfaceClass != MASS_STORAGE_CLASS) || + (InterfaceDescriptor.InterfaceProtocol != CBI0_INTERFACE_PROTOCOL)) { + Status = EFI_UNSUPPORTED; + } else { + Status = EFI_SUCCESS; + } + + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + + return Status; +} + +STATIC +EFI_STATUS +EFIAPI +Cbi0DriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + 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. + + Arguments: + This - Protocol instance pointer. + ControllerHandle - Handle of device to bind driver to + RemainingDevicePath - Not used + + Returns: + EFI_SUCCESS - This driver is added to DeviceHandle + EFI_ALREADY_STARTED - This driver is already running on DeviceHandle + other - This driver does not support this device + EFI_OUT_OF_RESOURCES- Can't allocate memory + EFI_UNSUPPORTED - Endpoint is not as expected +--*/ +{ + USB_CBI_DEVICE *UsbCbiDev; + UINT8 Index; + EFI_USB_ENDPOINT_DESCRIPTOR EndpointDescriptor; + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIo; + UINT8 EndpointExistMask; + + // + // Check if the Controller supports USB IO protocol + // + UsbCbiDev = NULL; + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + (VOID **) &UsbIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Get the controller interface descriptor + // + Status = UsbIo->UsbGetInterfaceDescriptor ( + UsbIo, + &InterfaceDescriptor + ); + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + return Status; + } + + Cbi0AtapiProtocol.CommandProtocol = InterfaceDescriptor.InterfaceSubClass; + + UsbCbiDev = AllocateZeroPool (sizeof (USB_CBI_DEVICE)); + if (UsbCbiDev == NULL) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + return EFI_OUT_OF_RESOURCES; + } + + UsbCbiDev->Signature = USB_CBI_DEVICE_SIGNATURE; + UsbCbiDev->UsbIo = UsbIo; + CopyMem (&UsbCbiDev->InterfaceDescriptor, &InterfaceDescriptor, sizeof (InterfaceDescriptor)); + CopyMem (&UsbCbiDev->UsbAtapiProtocol, &Cbi0AtapiProtocol, sizeof (Cbi0AtapiProtocol)); + + // + // Get the Device Path Protocol on Controller's handle + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + (VOID **) &UsbCbiDev->DevicePath, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + if (UsbCbiDev != NULL) { + gBS->FreePool (UsbCbiDev); + } + + return Status; + } + // + // Mask used to see whether all three kinds of endpoints exist, + // Mask value: + // bit0: bulk in endpoint; + // bit1: bulk out endpoint; + // bit2: interrupt in endpoint; + // + EndpointExistMask = 0; + for (Index = 0; Index < InterfaceDescriptor.NumEndpoints; Index++) { + UsbIo->UsbGetEndpointDescriptor ( + UsbIo, + Index, + &EndpointDescriptor + ); + + // + // We parse bulk endpoint + // + if (EndpointDescriptor.Attributes == 0x02) { + if (EndpointDescriptor.EndpointAddress & 0x80) { + CopyMem (&UsbCbiDev->BulkInEndpointDescriptor, &EndpointDescriptor, sizeof(EndpointDescriptor)); + // UsbCbiDev->BulkInEndpointDescriptor = EndpointDescriptor; + EndpointExistMask |= bit (0); + } else { + CopyMem (&UsbCbiDev->BulkOutEndpointDescriptor, &EndpointDescriptor, sizeof(EndpointDescriptor)); + // UsbCbiDev->BulkOutEndpointDescriptor = EndpointDescriptor; + EndpointExistMask |= bit (1); + } + } + // + // We parse interrupt endpoint + // + if (EndpointDescriptor.Attributes == 0x03) { + CopyMem (&UsbCbiDev->InterruptEndpointDescriptor, &EndpointDescriptor, sizeof(EndpointDescriptor)); + // UsbCbiDev->InterruptEndpointDescriptor = EndpointDescriptor; + EndpointExistMask |= bit (2); + } + + } + // + // Double check we have all endpoints needed + // + if (EndpointExistMask != (bit (0) | bit (1) | bit (2))) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + if (UsbCbiDev != NULL) { + gBS->FreePool (UsbCbiDev); + } + + return EFI_UNSUPPORTED; + } + // + // After installing Usb-Atapi protocol onto this handle + // it will be called by upper layer drivers such as Fat + // + Cbi0ReportStatusCode ( + UsbCbiDev->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_ENABLE) + ); + + Status = gBS->InstallProtocolInterface ( + &ControllerHandle, + &gEfiUsbAtapiProtocolGuid, + EFI_NATIVE_INTERFACE, + &UsbCbiDev->UsbAtapiProtocol + ); + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + if (UsbCbiDev != NULL) { + gBS->FreePool (UsbCbiDev); + } + + return Status; + } + + UsbCbiDev->ControllerNameTable = NULL; + AddUnicodeString ( + "eng", + gUsbCbi0ComponentName.SupportedLanguages, + &UsbCbiDev->ControllerNameTable, + (CHAR16 *) L"Usb Cbi0 Mass Storage" + ); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +Cbi0DriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + + Routine Description: + Stop this driver on ControllerHandle. Support stoping any child handles + created by this driver. + + Arguments: + This - Protocol instance pointer. + ControllerHandle - Handle of device to stop driver on + NumberOfChildren - Number of Children in the ChildHandleBuffer + ChildHandleBuffer - List of handles for the children we need to stop. + + Returns: + EFI_SUCCESS - This driver is removed DeviceHandle + EFI_UNSUPPORTED - This driver was not removed from this device + +--*/ +{ + EFI_STATUS Status; + EFI_USB_ATAPI_PROTOCOL *Cbi0AtapiProtocol; + USB_CBI_DEVICE *UsbCbiDev; + EFI_USB_IO_PROTOCOL *UsbIo; + + // + // Get our context back. + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsbAtapiProtocolGuid, + (VOID **) &Cbi0AtapiProtocol, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + UsbCbiDev = USB_CBI_DEVICE_FROM_THIS (Cbi0AtapiProtocol); + + UsbIo = UsbCbiDev->UsbIo; + + Cbi0ReportStatusCode ( + UsbCbiDev->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_DISABLE) + ); + + // + // Uninstall protocol + // + Status = gBS->UninstallProtocolInterface ( + ControllerHandle, + &gEfiUsbAtapiProtocolGuid, + &UsbCbiDev->UsbAtapiProtocol + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + // + // Free all allocated resources + // + if (UsbCbiDev->ControllerNameTable) { + FreeUnicodeStringTable (UsbCbiDev->ControllerNameTable); + } + + gBS->FreePool (UsbCbiDev); + + return Status; +} + + +STATIC +EFI_STATUS +Cbi0RecoveryReset ( + IN USB_CBI_DEVICE *UsbCbiDev + ) +/*++ + +Routine Description: + + Cbi0 Recovery Reset routine + +Arguments: + + UsbCbiDev - Cbi0RecoveryReset + +Returns: + + EFI_SUCCESS - Success + +--*/ +{ + UINT8 ResetCommand[12]; + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIo; + UINT8 EndpointAddress; + UINT32 Result; + UINT16 Timeout; + + UsbIo = UsbCbiDev->UsbIo; + + Cbi0ReportStatusCode ( + UsbCbiDev->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_RESET) + ); + // + // CBI reset command protocol + // + SetMem (ResetCommand, sizeof (ResetCommand), 0xff); + ResetCommand[0] = 0x1d; + ResetCommand[1] = 0x04; + + // + // (in millisecond unit) + // + Timeout = STALL_1_SECOND; + + Status = Cbi0AtapiCommand ( + &UsbCbiDev->UsbAtapiProtocol, + ResetCommand, + 12, + NULL, + 0, + EfiUsbNoData, + Timeout + ); + if (EFI_ERROR (Status)) { + return Status; + } + + gBS->Stall (100 * 1000); + // + // clear bulk in endpoint stall feature + // + EndpointAddress = UsbCbiDev->BulkInEndpointDescriptor.EndpointAddress; + Status = UsbClearEndpointHalt ( + UsbIo, + EndpointAddress, + &Result + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // clear bulk out endpoint stall feature + // + EndpointAddress = UsbCbiDev->BulkOutEndpointDescriptor.EndpointAddress; + Status = UsbClearEndpointHalt ( + UsbIo, + EndpointAddress, + &Result + ); + // + // according to CBI spec, no need to clear interrupt endpoint feature. + // + return Status; +} + +STATIC +EFI_STATUS +Cbi0CommandPhase ( + IN USB_CBI_DEVICE *UsbCbiDev, + IN VOID *Command, + IN UINT8 CommandSize, + IN UINT16 Timeout + ) +/*++ + + Routine Description: + Send ATAPI command through CBI0 interface. + + Arguments: + UsbCbiDev - USB_CBI_DEVICE + Command - Command to send + CommandSize - Command size + Timeout - Time out value in milliseconds + Returns: + EFI_SUCCESS - Success + EFI_DEVICE_ERROR - Fail + Others + +--*/ +{ + EFI_STATUS Status; + UINT32 Result; + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_USB_DEVICE_REQUEST Request; + + UsbIo = UsbCbiDev->UsbIo; + + ZeroMem (&Request, sizeof (EFI_USB_DEVICE_REQUEST)); + + // + // Device request see CBI specification + // + Request.RequestType = 0x21; + Request.Request = 0x00; + Request.Value = 0; + Request.Index = 0; + Request.Length = CommandSize; + + Status = UsbIo->UsbControlTransfer ( + UsbIo, + &Request, + EfiUsbDataOut, + Timeout, + Command, + CommandSize, + &Result + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +Cbi0DataPhase ( + IN USB_CBI_DEVICE *UsbCbiDev, + IN UINT32 *DataSize, + IN OUT VOID *DataBuffer, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT16 Timeout + ) +/*++ + + Routine Description: + Get/Send Data through CBI0 interface + + Arguments: + UsbCbiDev - USB_CBI_DEVICE + DataSize - Data size + DataBuffer - Data buffer + Direction - IN/OUT/NODATA + Timeout - Time out value in milliseconds + Returns: + EFI_SUCCESS + Others + +--*/ +{ + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIo; + UINT8 EndpointAddress; + UINTN Remain; + UINTN Increment; + UINT32 MaxPacketLength; + UINT8 *BufferPtr; + UINT32 Result; + UINTN TransferredSize; + + UsbIo = UsbCbiDev->UsbIo; + + Remain = *DataSize; + BufferPtr = (UINT8 *) DataBuffer; + TransferredSize = 0; + // + // retrieve the the max packet length of the given endpoint + // + if (Direction == EfiUsbDataIn) { + MaxPacketLength = UsbCbiDev->BulkInEndpointDescriptor.MaxPacketSize; + EndpointAddress = UsbCbiDev->BulkInEndpointDescriptor.EndpointAddress; + } else { + MaxPacketLength = UsbCbiDev->BulkOutEndpointDescriptor.MaxPacketSize; + EndpointAddress = UsbCbiDev->BulkOutEndpointDescriptor.EndpointAddress; + } + + while (Remain > 0) { + + if (Remain > 16 * MaxPacketLength) { + Increment = 16 * MaxPacketLength; + } else { + Increment = Remain; + } + + Status = UsbIo->UsbBulkTransfer ( + UsbIo, + EndpointAddress, + BufferPtr, + &Increment, + Timeout, + &Result + ); + TransferredSize += Increment; + + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + BufferPtr += Increment; + Remain -= Increment; + } + + return EFI_SUCCESS; + +ErrorExit: + + if (Direction == EfiUsbDataIn) { + Cbi0ReportStatusCode ( + UsbCbiDev->DevicePath, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_EC_INPUT_ERROR) + ); + } else { + Cbi0ReportStatusCode ( + UsbCbiDev->DevicePath, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_EC_OUTPUT_ERROR) + ); + } + + if ((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) { + Status = Cbi0RecoveryReset (UsbCbiDev); + } + + *DataSize = (UINT32) TransferredSize; + return Status; +} + +STATIC +EFI_STATUS +Cbi0StatusPhase ( + IN USB_CBI_DEVICE *UsbCbiDev, + OUT INTERRUPT_DATA_BLOCK *InterruptDataBlock, + IN UINT16 Timeout + ) +/*++ + + Routine Description: + Get transfer status through BOT interface + + Arguments: + UsbCbiDev - USB_CBI_DEVICE + InterruptDataBlock - Interrupt Data Block for interrupt transfer + Timeout - Time out value in milliseconds + Returns: + EFI_SUCCESS + Others + +--*/ +{ + UINT8 EndpointAddress; + UINTN InterruptDataBlockLength; + UINT32 Result; + EFI_STATUS Status; + + ZeroMem (InterruptDataBlock, sizeof (INTERRUPT_DATA_BLOCK)); + + EndpointAddress = UsbCbiDev->InterruptEndpointDescriptor.EndpointAddress; + InterruptDataBlockLength = sizeof (INTERRUPT_DATA_BLOCK); + + Status = UsbCbiDev->UsbIo->UsbSyncInterruptTransfer ( + UsbCbiDev->UsbIo, + EndpointAddress, + InterruptDataBlock, + &InterruptDataBlockLength, + Timeout, + &Result + ); + if (EFI_ERROR (Status)) { + if ((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) { + // + // just endpoint stall happens + // + UsbClearEndpointHalt ( + UsbCbiDev->UsbIo, + EndpointAddress, + &Result + ); + gBS->Stall (100 * 1000); + } + + return Status; + } + + return EFI_SUCCESS; +} +// +// Cbi0 Atapi Protocol Implementation +// +STATIC +EFI_STATUS +EFIAPI +Cbi0MassStorageReset ( + IN EFI_USB_ATAPI_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + + Routine Description: + Reset CBI Devices + + Arguments: + This - Protocol instance pointer. + ExtendedVerification - TRUE if we need to do strictly reset. + + Returns: + EFI_SUCCESS - Command succeeded. + EFI_DEVICE_ERROR - Command failed. + +--*/ +{ + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIo; + USB_CBI_DEVICE *UsbCbiDev; + + UsbCbiDev = USB_CBI_DEVICE_FROM_THIS (This); + UsbIo = UsbCbiDev->UsbIo; + + if (ExtendedVerification) { + // + // UsbIo->UsbPortReset (UsbIo); + // + } + + Status = Cbi0RecoveryReset (UsbCbiDev); + return Status; +} + +STATIC +EFI_STATUS +EFIAPI +Cbi0AtapiCommand ( + IN EFI_USB_ATAPI_PROTOCOL *This, + IN VOID *Command, + IN UINT8 CommandSize, + IN VOID *DataBuffer, + IN UINT32 BufferLength, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT16 TimeOutInMilliSeconds + ) +/*++ + + Routine Description: + Send ATAPI command using BOT protocol. + + Arguments: + This - Protocol instance pointer. + Command - Command buffer + CommandSize - Size of Command Buffer + DataBuffer - Data buffer + BufferLength - Length of Data buffer + Direction - Data direction of this command + TimeOutInMilliSeconds - Timeout value in ms + + Returns: + EFI_SUCCESS - Command succeeded. + EFI_DEVICE_ERROR - Command failed. + EFI_INVALID_PARAMETER - Invalidate parameter +--*/ +{ + EFI_STATUS Status; + USB_CBI_DEVICE *UsbCbiDev; + UINT32 BufferSize; + INTERRUPT_DATA_BLOCK InterruptDataBlock; + EFI_STATUS DataPhaseStatus; + + if (Direction != EfiUsbNoData) { + if (DataBuffer == NULL || BufferLength == 0) { + return EFI_INVALID_PARAMETER; + } + } + + DataPhaseStatus = EFI_SUCCESS; + // + // Get the context + // + UsbCbiDev = USB_CBI_DEVICE_FROM_THIS (This); + + // + // First send ATAPI command through Cbi + // + Status = Cbi0CommandPhase ( + UsbCbiDev, + Command, + CommandSize, + 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; + + DataPhaseStatus = Cbi0DataPhase ( + UsbCbiDev, + &BufferSize, + DataBuffer, + Direction, + TimeOutInMilliSeconds + ); + break; + + case EfiUsbNoData: + break; + } + + if (EFI_ERROR (DataPhaseStatus)) { + return EFI_DEVICE_ERROR; + } + + // + // Status Phase + // + Status = Cbi0StatusPhase ( + UsbCbiDev, + &InterruptDataBlock, + TimeOutInMilliSeconds + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + if (This->CommandProtocol != EFI_USB_SUBCLASS_UFI) { + + if (InterruptDataBlock.bType == 0) { + // + // indicates command completion + // + switch (InterruptDataBlock.bValue & 0x03) { + + case 0: + Status = EFI_SUCCESS; + break; + + case 1: + Status = EFI_DEVICE_ERROR; + break; + + case 2: + Status = Cbi0RecoveryReset (UsbCbiDev); + if (EFI_ERROR (Status)) { + UsbCbiDev->UsbIo->UsbPortReset (UsbCbiDev->UsbIo); + } + + Status = EFI_DEVICE_ERROR; + break; + + case 3: + Status = EFI_DEVICE_ERROR; + } + } else { + Status = DataPhaseStatus; + } + + } else { + // + // UFI device, InterruptDataBlock.bType: ASC (Additional Sense Code) + // InterruptDataBlock.bValue: ASCQ (Additional Snese Code Qualifier) + // + Status = DataPhaseStatus; + } + + return Status; +} + +VOID +Cbi0ReportStatusCode ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN EFI_STATUS_CODE_TYPE CodeType, + IN EFI_STATUS_CODE_VALUE Value + ) +/*++ + + Routine Description: + Report Status Code in Usb Cbi0 Driver + + Arguments: + DevicePath - Use this to get Device Path + CodeType - Status Code Type + CodeValue - Status Code Value + + Returns: + None + +--*/ +{ + + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + CodeType, + Value, + DevicePath + ); +} diff --git a/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/ComponentName.c b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/ComponentName.c new file mode 100644 index 0000000000..0692c7fee5 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/ComponentName.c @@ -0,0 +1,192 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ComponentName.c + +Abstract: + +--*/ + +#include "../cbi.h" + +extern EFI_DRIVER_BINDING_PROTOCOL gUsbCbi0DriverBinding; + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +UsbCbi0ComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +EFI_STATUS +EFIAPI +UsbCbi0ComponentNameGetControllerName ( + 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 +// +EFI_COMPONENT_NAME_PROTOCOL gUsbCbi0ComponentName = { + UsbCbi0ComponentNameGetDriverName, + UsbCbi0ComponentNameGetControllerName, + "eng" +}; + +STATIC EFI_UNICODE_STRING_TABLE mUsbCbi0DriverNameTable[] = { + { "eng", (CHAR16 *) L"Usb Cbi0 Mass Storage Driver" }, + { NULL , NULL } +}; + + +EFI_STATUS +EFIAPI +UsbCbi0ComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gUsbCbi0ComponentName.SupportedLanguages, + mUsbCbi0DriverNameTable, + DriverName + ); +} + +EFI_STATUS +EFIAPI +UsbCbi0ComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + 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. + 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. + + Returns: + 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. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + EFI_STATUS Status; + USB_CBI_DEVICE *UsbCbiDev; + EFI_USB_ATAPI_PROTOCOL *UsbAtapi; + + // + // This is a device driver, so ChildHandle must be NULL. + // + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + + // + // Get the device context + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsbAtapiProtocolGuid, + (VOID **) &UsbAtapi, + gUsbCbi0DriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + UsbCbiDev = USB_CBI_DEVICE_FROM_THIS (UsbAtapi); + + return LookupUnicodeString ( + Language, + gUsbCbi0ComponentName.SupportedLanguages, + UsbCbiDev->ControllerNameTable, + ControllerName + ); + +} diff --git a/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/UsbCbi0.mbd b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/UsbCbi0.mbd new file mode 100644 index 0000000000..17a63f9b21 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/UsbCbi0.mbd @@ -0,0 +1,43 @@ + + + + + UsbCbi0 + A3527D16-E6CC-42f5-BADB-BF3DE177742B + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:18 + + + UefiBootServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + EdkDxePrintLib + BaseLib + EdkUsbLib + DxeMemoryAllocationLib + + diff --git a/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/UsbCbi0.msa b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/UsbCbi0.msa new file mode 100644 index 0000000000..a128159e12 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/UsbCbi0.msa @@ -0,0 +1,68 @@ + + + + + UsbCbi0 + DXE_DRIVER + BS_DRIVER + A3527D16-E6CC-42f5-BADB-BF3DE177742B + 0 + Component description file for UsbCbi1 module + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:18 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + BaseLib + UefiLib + BaseMemoryLib + EdkUsbLib + ReportStatusCodeLib + MemoryAllocationLib + UefiBootServicesTableLib + + + cbi0.c + componentname.c + + + MdePkg + EdkModulePkg + + + DevicePath + UsbIo + UsbAtapi + + + + + + + gUsbCbi0DriverBinding + gUsbCbi0ComponentName + + + diff --git a/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/build.xml b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/build.xml new file mode 100644 index 0000000000..e406abee8b --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/UsbCbi1.mbd b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/UsbCbi1.mbd new file mode 100644 index 0000000000..e48251eb07 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/UsbCbi1.mbd @@ -0,0 +1,43 @@ + + + + + UsbCbi1 + B40612B2-A063-11d4-9A3A-0090273FC14D + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:18 + + + UefiBootServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + EdkDxePrintLib + BaseLib + EdkUsbLib + DxeMemoryAllocationLib + + diff --git a/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/UsbCbi1.msa b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/UsbCbi1.msa new file mode 100644 index 0000000000..057585689e --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/UsbCbi1.msa @@ -0,0 +1,66 @@ + + + + + UsbCbi1 + DXE_DRIVER + BS_DRIVER + B40612B2-A063-11d4-9A3A-0090273FC14D + 0 + Component description file for UsbCbi1 module + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:18 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + BaseLib + UefiLib + BaseMemoryLib + EdkUsbLib + ReportStatusCodeLib + MemoryAllocationLib + UefiBootServicesTableLib + + + cbi1.c + + + MdePkg + EdkModulePkg + + + DevicePath + UsbIo + UsbAtapi + + + + + + + gCBI1DriverBinding + + + diff --git a/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/build.xml b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/build.xml new file mode 100644 index 0000000000..132e52237c --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/cbi1.c b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/cbi1.c new file mode 100644 index 0000000000..71644acef8 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/cbi1.c @@ -0,0 +1,854 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + cbi1.c + +Abstract: + cbi1 transportation protocol implementation files + +--*/ + +#include "../cbi.h" + +EFI_STATUS +EFIAPI +UsbCBI1DriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +// +// CBI Function prototypes +// +STATIC +EFI_STATUS +CBI1CommandPhase ( + IN USB_CBI_DEVICE *UsbCbiDev, + IN VOID *Command, + IN UINT8 CommandSize, + OUT UINT32 *Result + ); + +STATIC +EFI_STATUS +CBI1DataPhase ( + IN USB_CBI_DEVICE *UsbCbiDev, + IN UINT32 DataSize, + IN OUT VOID *DataBuffer, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT16 Timeout, + OUT UINT32 *Result + ); + +// +// USB Atapi implementation +// +STATIC +EFI_STATUS +EFIAPI +CBI1AtapiCommand ( + IN EFI_USB_ATAPI_PROTOCOL *This, + IN VOID *Command, + IN UINT8 CommandSize, + IN VOID *DataBuffer, + IN UINT32 BufferLength, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT16 TimeOutInMilliSeconds + ); + +STATIC +EFI_STATUS +EFIAPI +CBI1MassStorageReset ( + IN EFI_USB_ATAPI_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +// +// CBI1 Driver Binding Protocol +// +STATIC +EFI_STATUS +EFIAPI +CBI1DriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +STATIC +EFI_STATUS +EFIAPI +CBI1DriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +STATIC +EFI_STATUS +EFIAPI +CBI1DriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +VOID +Cbi1ReportStatusCode ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN EFI_STATUS_CODE_TYPE CodeType, + IN EFI_STATUS_CODE_VALUE Value + ); + + +EFI_DRIVER_BINDING_PROTOCOL gCBI1DriverBinding = { + CBI1DriverBindingSupported, + CBI1DriverBindingStart, + CBI1DriverBindingStop, + 0x10, + NULL, + NULL +}; + +STATIC EFI_USB_ATAPI_PROTOCOL CBI1AtapiProtocol = { + CBI1AtapiCommand, + CBI1MassStorageReset, + 0 +}; + +// +// CBI1 Driver Binding implementation +// +STATIC +EFI_STATUS +EFIAPI +CBI1DriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + Test to see if this driver supports ControllerHandle. Any ControllerHandle + than contains a BlockIo and DiskIo protocol can be supported. + + Arguments: + This - Protocol instance pointer. + ControllerHandle - Handle of device to test + RemainingDevicePath - Not used + + Returns: + EFI_SUCCESS - This driver supports this device + EFI_ALREADY_STARTED - This driver is already running on this device + other - This driver does not support this device + +--*/ +{ + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + + // + // Check if the Controller supports USB IO protocol + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + (VOID **) &UsbIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Get the Controller interface descriptor + // + Status = UsbIo->UsbGetInterfaceDescriptor ( + UsbIo, + &InterfaceDescriptor + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + // + // Bug here: just let Vendor specific CBI protocol get supported + // + if (!((InterfaceDescriptor.InterfaceClass == 0xFF) && + (InterfaceDescriptor.InterfaceProtocol == 0))) { + Status = EFI_UNSUPPORTED; + goto Exit; + } + +Exit: + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + return Status; + +} + +STATIC +EFI_STATUS +EFIAPI +CBI1DriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + 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. + + Arguments: + This - Protocol instance pointer. + ControllerHandle - Handle of device to bind driver to + RemainingDevicePath - Not used + + Returns: + EFI_SUCCESS - This driver is added to DeviceHandle + EFI_ALREADY_STARTED - This driver is already running on DeviceHandle + other - This driver does not support this device + +--*/ +{ + USB_CBI_DEVICE *UsbCbiDev; + UINT8 Index; + EFI_USB_ENDPOINT_DESCRIPTOR EndpointDescriptor; + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIo; + BOOLEAN Found; + + Found = FALSE; + // + // Check if the Controller supports USB IO protocol + // + UsbCbiDev = NULL; + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + (VOID **) &UsbIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Get the controller interface descriptor + // + Status = UsbIo->UsbGetInterfaceDescriptor ( + UsbIo, + &InterfaceDescriptor + ); + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + CBI1AtapiProtocol.CommandProtocol = InterfaceDescriptor.InterfaceSubClass; + + UsbCbiDev = AllocateZeroPool (sizeof (USB_CBI_DEVICE)); + if (UsbCbiDev == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + + UsbCbiDev->Signature = USB_CBI_DEVICE_SIGNATURE; + UsbCbiDev->UsbIo = UsbIo; + CopyMem (&UsbCbiDev->InterfaceDescriptor, &InterfaceDescriptor, sizeof (InterfaceDescriptor)); + CopyMem (&UsbCbiDev->UsbAtapiProtocol , &CBI1AtapiProtocol, sizeof (CBI1AtapiProtocol)); + + // + // Get the Device Path Protocol on Controller's handle + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + (VOID **) &UsbCbiDev->DevicePath, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + for (Index = 0; Index < InterfaceDescriptor.NumEndpoints; Index++) { + UsbIo->UsbGetEndpointDescriptor ( + UsbIo, + Index, + &EndpointDescriptor + ); + + // + // We parse bulk endpoint + // + if (EndpointDescriptor.Attributes == 0x02) { + if (EndpointDescriptor.EndpointAddress & 0x80) { + CopyMem (&UsbCbiDev->BulkInEndpointDescriptor, &EndpointDescriptor, sizeof(EndpointDescriptor)); + //UsbCbiDev->BulkInEndpointDescriptor = EndpointDescriptor; + } else { + CopyMem (&UsbCbiDev->BulkOutEndpointDescriptor, &EndpointDescriptor, sizeof(EndpointDescriptor)); + //UsbCbiDev->BulkOutEndpointDescriptor = EndpointDescriptor; + } + + Found = TRUE; + } + // + // We parse interrupt endpoint + // + if (EndpointDescriptor.Attributes == 0x03) { + CopyMem (&UsbCbiDev->InterruptEndpointDescriptor, &EndpointDescriptor, sizeof(EndpointDescriptor)); + //UsbCbiDev->InterruptEndpointDescriptor = EndpointDescriptor; + Found = TRUE; + } + + } + // + // Double check we have these + // + if (!Found) { + goto ErrorExit; + } + // + // After installing Usb-Atapi protocol onto this handle + // it will be called by upper layer drivers such as Fat + // + Cbi1ReportStatusCode ( + UsbCbiDev->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_ENABLE) + ); + + Status = gBS->InstallProtocolInterface ( + &ControllerHandle, + &gEfiUsbAtapiProtocolGuid, + EFI_NATIVE_INTERFACE, + &UsbCbiDev->UsbAtapiProtocol + ); + + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + return EFI_SUCCESS; + +ErrorExit: + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + if (UsbCbiDev != NULL) { + gBS->FreePool (UsbCbiDev); + } + + return Status; + +} + +STATIC +EFI_STATUS +EFIAPI +CBI1DriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + + Routine Description: + Stop this driver on ControllerHandle. Support stoping any child handles + created by this driver. + + Arguments: + This - Protocol instance pointer. + ControllerHandle - Handle of device to stop driver on + NumberOfChildren - Number of Children in the ChildHandleBuffer + ChildHandleBuffer - List of handles for the children we need to stop. + + Returns: + EFI_SUCCESS - This driver is removed DeviceHandle + EFI_UNSUPPORTED - Can't open the gEfiUsbAtapiProtocolGuid protocol + other - This driver was not removed from this device + +--*/ +{ + EFI_STATUS Status; + EFI_USB_ATAPI_PROTOCOL *CBI1AtapiProtocol; + USB_CBI_DEVICE *UsbCbiDev; + EFI_USB_IO_PROTOCOL *UsbIo; + + // + // Get our context back. + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsbAtapiProtocolGuid, + (VOID **) &CBI1AtapiProtocol, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + UsbCbiDev = USB_CBI_DEVICE_FROM_THIS (CBI1AtapiProtocol); + + UsbIo = UsbCbiDev->UsbIo; + + Cbi1ReportStatusCode ( + UsbCbiDev->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_DISABLE) + ); + + Status = gBS->UninstallProtocolInterface ( + ControllerHandle, + &gEfiUsbAtapiProtocolGuid, + &UsbCbiDev->UsbAtapiProtocol + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + gBS->FreePool (UsbCbiDev); + + return Status; + +} +// +// CBI1 command +// +STATIC +EFI_STATUS +CBI1CommandPhase ( + IN USB_CBI_DEVICE *UsbCbiDev, + IN VOID *Command, + IN UINT8 CommandSize, + OUT UINT32 *Result + ) +/*++ + + Routine Description: + In order to make consistence, CBI transportation protocol does only use + the first 3 parameters. Other parameters are not used here. + + Arguments: + UsbCbiDev - USB_CBI_DEVICE + Command - Command to send + CommandSize - Command Size + Result - Result to return + + Returns: + EFI_SUCCESS - This driver is removed DeviceHandle + other - This driver was not removed from this device +--*/ +{ + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_USB_DEVICE_REQUEST Request; + UINT32 TimeOutInMilliSeconds; + + UsbIo = UsbCbiDev->UsbIo; + + ZeroMem (&Request, sizeof (EFI_USB_DEVICE_REQUEST)); + + // + // Device request see CBI specification + // + Request.RequestType = 0x21; + Request.Length = CommandSize; + + TimeOutInMilliSeconds = 1000; + + Status = UsbIo->UsbControlTransfer ( + UsbIo, + &Request, + EfiUsbDataOut, + TimeOutInMilliSeconds, + Command, + CommandSize, + Result + ); + + return Status; +} + +STATIC +EFI_STATUS +CBI1DataPhase ( + IN USB_CBI_DEVICE *UsbCbiDev, + IN UINT32 DataSize, + IN OUT VOID *DataBuffer, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT16 Timeout, + OUT UINT32 *Result + ) +/*++ + +Routine Description: + + CBI1 Data Phase + +Arguments: + + UsbCbiDev - USB_CBI_DEVICE + DataSize - Data Size + DataBuffer - Data Buffer + Direction - IN/OUT/NODATA + Timeout - Time out value in milliseconds + Result - Transfer result + +Returns: + + EFI_SUCCESS - Success + +--*/ +{ + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIo; + UINT8 EndpointAddr; + UINTN Remain; + UINTN Increment; + UINT32 MaxPacketLen; + UINT8 *BufferPtr; + + UsbIo = UsbCbiDev->UsbIo; + + Remain = DataSize; + BufferPtr = (UINT8 *) DataBuffer; + + // + // retrieve the the max packet length of the given endpoint + // + if (Direction == EfiUsbDataIn) { + MaxPacketLen = (UsbCbiDev->BulkInEndpointDescriptor).MaxPacketSize; + EndpointAddr = (UsbCbiDev->BulkInEndpointDescriptor).EndpointAddress; + } else { + MaxPacketLen = (UsbCbiDev->BulkOutEndpointDescriptor).MaxPacketSize; + EndpointAddr = (UsbCbiDev->BulkOutEndpointDescriptor).EndpointAddress; + } + + while (Remain > 0) { + // + // Using 15 packets to aVOID Bitstuff error + // + if (Remain > 15 * MaxPacketLen) { + Increment = 15 * MaxPacketLen; + } else { + Increment = Remain; + } + + Status = UsbIo->UsbBulkTransfer ( + UsbIo, + EndpointAddr, + BufferPtr, + &Increment, + Timeout, + Result + ); + + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + BufferPtr += Increment; + Remain -= Increment; + } + + return EFI_SUCCESS; + +ErrorExit: + + if (Direction == EfiUsbDataIn) { + Cbi1ReportStatusCode ( + UsbCbiDev->DevicePath, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_EC_INPUT_ERROR) + ); + } else { + Cbi1ReportStatusCode ( + UsbCbiDev->DevicePath, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_EC_OUTPUT_ERROR) + ); + } + + if (((*Result) & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) { + // + // just endpoint stall happens + // + UsbClearEndpointHalt ( + UsbIo, + EndpointAddr, + Result + ); + } + + return Status; +} +// +// CBI1 USB ATAPI Protocol +// +STATIC +EFI_STATUS +EFIAPI +CBI1MassStorageReset ( + IN EFI_USB_ATAPI_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + + Routine Description: + Reset CBI Devices + + Arguments: + This - Protocol instance pointer. + ExtendedVerification - TRUE if we need to do strictly reset. + + Returns: + EFI_SUCCESS - Command succeeded. + EFI_DEVICE_ERROR - Command failed. + +--*/ +{ + UINT8 ResetCommand[12]; + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIo; + USB_CBI_DEVICE *UsbCbiDev; + UINT8 EndpointAddr; + UINT32 Result; + + UsbCbiDev = USB_CBI_DEVICE_FROM_THIS (This); + UsbIo = UsbCbiDev->UsbIo; + + Cbi1ReportStatusCode ( + UsbCbiDev->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_RESET) + ); + + if (ExtendedVerification) { + UsbIo->UsbPortReset (UsbIo); + } + // + // CBI reset command protocol + // + SetMem (ResetCommand, sizeof (ResetCommand), 0xff); + ResetCommand[0] = 0x1d; + ResetCommand[1] = 0x04; + + Status = CBI1CommandPhase ( + UsbCbiDev, + ResetCommand, + 12, + &Result + ); + + // + // clear bulk in endpoint stall feature + // + EndpointAddr = UsbCbiDev->BulkInEndpointDescriptor.EndpointAddress; + UsbClearEndpointHalt ( + UsbIo, + EndpointAddr, + &Result + ); + + // + // clear bulk out endpoint stall feature + // + EndpointAddr = UsbCbiDev->BulkOutEndpointDescriptor.EndpointAddress; + UsbClearEndpointHalt ( + UsbIo, + EndpointAddr, + &Result + ); + + return EFI_SUCCESS; + +} + +STATIC +EFI_STATUS +EFIAPI +CBI1AtapiCommand ( + IN EFI_USB_ATAPI_PROTOCOL *This, + IN VOID *Command, + IN UINT8 CommandSize, + IN VOID *DataBuffer, + IN UINT32 BufferLength, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT16 TimeOutInMilliSeconds + ) +/*++ + + Routine Description: + Send ATAPI command using CBI1 protocol. + + Arguments: + This - Protocol instance pointer. + Command - Command buffer + CommandSize - Size of Command Buffer + DataBuffer - Data buffer + BufferLength - Length of Data buffer + Direction - Data direction of this command + TimeOutInMilliSeconds - Timeout value in ms + + Returns: + EFI_SUCCESS - Command succeeded. + EFI_DEVICE_ERROR - Command failed. + +--*/ +{ + EFI_STATUS Status; + USB_CBI_DEVICE *UsbCbiDev; + UINT32 Result; + UINT8 Index; + UINT8 MaxRetryNum; + + UsbCbiDev = USB_CBI_DEVICE_FROM_THIS (This); + + MaxRetryNum = 3; + + for (Index = 0; Index < MaxRetryNum; Index++) { + + // + // First send ATAPI command through CBI1 + // + Status = CBI1CommandPhase ( + UsbCbiDev, + Command, + CommandSize, + &Result + ); + if (EFI_ERROR (Status)) { + + switch (Result) { + + case EFI_USB_NOERROR: + case EFI_USB_ERR_STALL: + case EFI_USB_ERR_SYSTEM: + return EFI_DEVICE_ERROR; + + default: + continue; + break; + } + } else { + break; + } + } + + if (Index == MaxRetryNum) { + return EFI_DEVICE_ERROR; + } + + for (Index = 0; Index < MaxRetryNum; Index++) { + // + // Send/Get Data if there is a Data Stage + // + switch (Direction) { + + case EfiUsbDataIn: + case EfiUsbDataOut: + Status = CBI1DataPhase ( + UsbCbiDev, + BufferLength, + DataBuffer, + Direction, + TimeOutInMilliSeconds, + &Result + ); + + if (EFI_ERROR (Status)) { + switch (Result) { + + case EFI_USB_NOERROR: + case EFI_USB_ERR_STALL: + case EFI_USB_ERR_SYSTEM: + return EFI_DEVICE_ERROR; + + default: + continue; + break; + } + + } else { + + return EFI_SUCCESS; + } + break; + + case EfiUsbNoData: + return EFI_SUCCESS; + } + } + // + // If goes here, means met error. + // + return EFI_DEVICE_ERROR; +} + +VOID +Cbi1ReportStatusCode ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN EFI_STATUS_CODE_TYPE CodeType, + IN EFI_STATUS_CODE_VALUE Value + ) +/*++ + + Routine Description: + Report Status Code in Usb Cbi1 Driver + + Arguments: + DevicePath - Use this to get Device Path + CodeType - Status Code Type + CodeValue - Status Code Value + + Returns: + None + +--*/ +{ + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + CodeType, + Value, + DevicePath + ); + +} diff --git a/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/cbi.h b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/cbi.h new file mode 100644 index 0000000000..dfbe4d9886 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/cbi.h @@ -0,0 +1,70 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + cbi.h + +Abstract: + + USB CBI transportation protocol definitions. +--*/ + +#ifndef _CBI_H +#define _CBI_H + + +#include + +#define bit(a) (1 << (a)) + +#define MASS_STORAGE_CLASS 0x08 +#define CBI0_INTERFACE_PROTOCOL 0x00 +#define CBI1_INTERFACE_PROTOCOL 0x01 + +// +// in millisecond unit +// +#define STALL_1_SECOND 1000 + +#pragma pack(1) +// +// Data block definition for transportation through interrupt endpoint +// +typedef struct { + UINT8 bType; + UINT8 bValue; +} INTERRUPT_DATA_BLOCK; + +#pragma pack() + +#define USB_CBI_DEVICE_SIGNATURE EFI_SIGNATURE_32 ('u', 'c', 'b', 'i') + +// +// Device structure for CBI, interrupt endpoint may be not used in +// CBI1 Protocol +// +typedef struct { + UINT32 Signature; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_USB_ATAPI_PROTOCOL UsbAtapiProtocol; + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + EFI_USB_ENDPOINT_DESCRIPTOR BulkInEndpointDescriptor; + EFI_USB_ENDPOINT_DESCRIPTOR BulkOutEndpointDescriptor; + EFI_USB_ENDPOINT_DESCRIPTOR InterruptEndpointDescriptor; + EFI_UNICODE_STRING_TABLE *ControllerNameTable; +} USB_CBI_DEVICE; + +#define USB_CBI_DEVICE_FROM_THIS(a) \ + CR(a, USB_CBI_DEVICE, UsbAtapiProtocol, USB_CBI_DEVICE_SIGNATURE) + +#endif diff --git a/EdkModulePkg/Bus/Usb/UsbKb/Dxe/ComponentName.c b/EdkModulePkg/Bus/Usb/UsbKb/Dxe/ComponentName.c new file mode 100644 index 0000000000..3e139f9d9a --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbKb/Dxe/ComponentName.c @@ -0,0 +1,215 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ComponentName.c + +Abstract: + +--*/ + +#include "keyboard.h" + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +UsbKeyboardComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +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 Component Name Protocol +// +EFI_COMPONENT_NAME_PROTOCOL gUsbKeyboardComponentName = { + UsbKeyboardComponentNameGetDriverName, + UsbKeyboardComponentNameGetControllerName, + "eng" +}; + +STATIC EFI_UNICODE_STRING_TABLE mUsbKeyboardDriverNameTable[] = { + { "eng", (CHAR16 *) L"Usb Keyboard Driver" }, + { NULL , NULL } +}; + + +EFI_STATUS +EFIAPI +UsbKeyboardComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gUsbKeyboardComponentName.SupportedLanguages, + mUsbKeyboardDriverNameTable, + DriverName + ); +} + +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 + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + 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. + 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. + + Returns: + 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. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + EFI_STATUS Status; + USB_KB_DEV *UsbKbDev; + EFI_SIMPLE_TEXT_IN_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 LookupUnicodeString ( + Language, + gUsbKeyboardComponentName.SupportedLanguages, + UsbKbDev->ControllerNameTable, + ControllerName + ); + +} diff --git a/EdkModulePkg/Bus/Usb/UsbKb/Dxe/UsbKb.mbd b/EdkModulePkg/Bus/Usb/UsbKb/Dxe/UsbKb.mbd new file mode 100644 index 0000000000..ecb6af6c96 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbKb/Dxe/UsbKb.mbd @@ -0,0 +1,44 @@ + + + + + UsbKb + 2D2E62CF-9ECF-43b7-8219-94E7FC713DFE + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:18 + + + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + EdkDxePrintLib + BaseLib + EdkUsbLib + DxeMemoryAllocationLib + + diff --git a/EdkModulePkg/Bus/Usb/UsbKb/Dxe/UsbKb.msa b/EdkModulePkg/Bus/Usb/UsbKb/Dxe/UsbKb.msa new file mode 100644 index 0000000000..0ff6464825 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbKb/Dxe/UsbKb.msa @@ -0,0 +1,77 @@ + + + + + UsbKb + DXE_DRIVER + BS_DRIVER + 2D2E62CF-9ECF-43b7-8219-94E7FC713DFE + 0 + Component description file for UsbKb module + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:18 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + BaseLib + UefiLib + BaseMemoryLib + EdkUsbLib + ReportStatusCodeLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + + + efikey.h + keyboard.h + efikey.c + keyboard.c + ComponentName.c + + + MdePkg + EdkModulePkg + + + DevicePath + UsbIo + SimpleTextIn + + + + HotPlugDevice + + + + + + + + gUsbKeyboardDriverBinding + gUsbKeyboardComponentName + + + diff --git a/EdkModulePkg/Bus/Usb/UsbKb/Dxe/build.xml b/EdkModulePkg/Bus/Usb/UsbKb/Dxe/build.xml new file mode 100644 index 0000000000..2608381d96 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbKb/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Bus/Usb/UsbKb/Dxe/efikey.c b/EdkModulePkg/Bus/Usb/UsbKb/Dxe/efikey.c new file mode 100644 index 0000000000..a9cdbc8760 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbKb/Dxe/efikey.c @@ -0,0 +1,772 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + EfiKey.c + +Abstract: + + USB Keyboard Driver + +Revision History + +--*/ + +#include "efikey.h" +#include "keyboard.h" + +// +// Prototypes +// Driver model protocol interface +// +EFI_STATUS +EFIAPI +USBKeyboardDriverBindingEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +EFI_STATUS +EFIAPI +USBKeyboardDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +USBKeyboardDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +USBKeyboardDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +// +// Simple Text In Protocol Interface +// +STATIC +EFI_STATUS +EFIAPI +USBKeyboardReset ( + IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +STATIC +EFI_STATUS +EFIAPI +USBKeyboardReadKeyStroke ( + IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This, + OUT EFI_INPUT_KEY *Key + ); + +STATIC +VOID +EFIAPI +USBKeyboardWaitForKey ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +// +// Helper functions +// +STATIC +EFI_STATUS +USBKeyboardCheckForKey ( + IN USB_KB_DEV *UsbKeyboardDevice + ); + +// +// USB Keyboard Driver Global Variables +// +EFI_DRIVER_BINDING_PROTOCOL gUsbKeyboardDriverBinding = { + USBKeyboardDriverBindingSupported, + USBKeyboardDriverBindingStart, + USBKeyboardDriverBindingStop, + 0x10, + NULL, + NULL +}; + +EFI_STATUS +EFIAPI +USBKeyboardDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + Supported. + + Arguments: + This - EFI_DRIVER_BINDING_PROTOCOL + Controller - Controller handle + RemainingDevicePath - EFI_DEVICE_PATH_PROTOCOL + Returns: + EFI_STATUS + +--*/ +{ + EFI_STATUS OpenStatus; + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_STATUS Status; + + // + // Check if USB_IO protocol is attached on the controller handle. + // + OpenStatus = gBS->OpenProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + (VOID **) &UsbIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (OpenStatus)) { + return OpenStatus; + } + + // + // Use the USB I/O protocol interface to check whether the Controller is + // the Keyboard controller 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; +} + +EFI_STATUS +EFIAPI +USBKeyboardDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + Start. + + Arguments: + This - EFI_DRIVER_BINDING_PROTOCOL + Controller - Controller handle + RemainingDevicePath - EFI_DEVICE_PATH_PROTOCOL + Returns: + EFI_SUCCESS - Success + EFI_OUT_OF_RESOURCES - Can't allocate memory + EFI_UNSUPPORTED - The Start routine fail +--*/ +{ + 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; + + UsbKeyboardDevice = NULL; + Found = FALSE; + + // + // Open USB_IO Protocol + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + (VOID **) &UsbIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + UsbKeyboardDevice = AllocateZeroPool (sizeof (USB_KB_DEV)); + if (UsbKeyboardDevice == NULL) { + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return EFI_OUT_OF_RESOURCES; + } + // + // 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)) { + gBS->FreePool (UsbKeyboardDevice); + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return Status; + } + // + // Report that the usb keyboard is being enabled + // + KbdReportStatusCode ( + UsbKeyboardDevice->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE) + ); + + // + // This is pretty close to keyboard detection, so log progress + // + KbdReportStatusCode ( + UsbKeyboardDevice->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_PRESENCE_DETECT) + ); + + // + // Initialize UsbKeyboardDevice + // + UsbKeyboardDevice->UsbIo = UsbIo; + + // + // Get interface & endpoint descriptor + // + UsbIo->UsbGetInterfaceDescriptor ( + UsbIo, + &UsbKeyboardDevice->InterfaceDescriptor + ); + + EndpointNumber = UsbKeyboardDevice->InterfaceDescriptor.NumEndpoints; + + for (Index = 0; Index < EndpointNumber; Index++) { + + UsbIo->UsbGetEndpointDescriptor ( + UsbIo, + Index, + &EndpointDescriptor + ); + + if ((EndpointDescriptor.Attributes & 0x03) == 0x03) { + // + // We only care interrupt endpoint here + // + CopyMem (&UsbKeyboardDevice->IntEndpointDescriptor, &EndpointDescriptor, sizeof (EndpointDescriptor)); + //UsbKeyboardDevice->IntEndpointDescriptor = EndpointDescriptor; + Found = TRUE; + } + } + + if (!Found) { + // + // No interrupt endpoint found, then return unsupported. + // + gBS->FreePool (UsbKeyboardDevice); + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return EFI_UNSUPPORTED; + } + + UsbKeyboardDevice->Signature = USB_KB_DEV_SIGNATURE; + UsbKeyboardDevice->SimpleInput.Reset = USBKeyboardReset; + UsbKeyboardDevice->SimpleInput.ReadKeyStroke = USBKeyboardReadKeyStroke; + Status = gBS->CreateEvent ( + EFI_EVENT_NOTIFY_WAIT, + EFI_TPL_NOTIFY, + USBKeyboardWaitForKey, + UsbKeyboardDevice, + &(UsbKeyboardDevice->SimpleInput.WaitForKey) + ); + + if (EFI_ERROR (Status)) { + gBS->FreePool (UsbKeyboardDevice); + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return Status; + } + + // + // Install simple txt in protocol interface + // for the usb keyboard device. + // Usb keyboard is a hot plug device, and expected to work immediately + // when plugging into system, so a HotPlugDeviceGuid is installed onto + // the usb keyboard device handle, to distinguish it from other conventional + // console devices. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &Controller, + &gEfiSimpleTextInProtocolGuid, + &UsbKeyboardDevice->SimpleInput, + &gEfiHotPlugDeviceGuid, + NULL, + NULL + ); + if (EFI_ERROR (Status)) { + gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey); + gBS->FreePool (UsbKeyboardDevice); + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return Status; + } + + // + // Reset USB Keyboard Device + // + Status = UsbKeyboardDevice->SimpleInput.Reset ( + &UsbKeyboardDevice->SimpleInput, + TRUE + ); + if (EFI_ERROR (Status)) { + gBS->UninstallMultipleProtocolInterfaces ( + Controller, + &gEfiSimpleTextInProtocolGuid, + &UsbKeyboardDevice->SimpleInput, + &gEfiHotPlugDeviceGuid, + NULL, + NULL + ); + gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey); + gBS->FreePool (UsbKeyboardDevice); + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return Status; + } + // + // submit async interrupt transfer + // + 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, + &gEfiHotPlugDeviceGuid, + NULL, + NULL + ); + gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey); + gBS->FreePool (UsbKeyboardDevice); + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return Status; + } + + UsbKeyboardDevice->ControllerNameTable = NULL; + AddUnicodeString ( + "eng", + gUsbKeyboardComponentName.SupportedLanguages, + &UsbKeyboardDevice->ControllerNameTable, + (CHAR16 *) L"Generic Usb Keyboard" + ); + + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +USBKeyboardDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + + Routine Description: + Stop. + + Arguments: + This - EFI_DRIVER_BINDING_PROTOCOL + Controller - Controller handle + NumberOfChildren - Child handle number + ChildHandleBuffer - Child handle buffer + Returns: + EFI_SUCCESS - Success + EFI_UNSUPPORTED - Can't support +--*/ +{ + EFI_STATUS Status; + EFI_SIMPLE_TEXT_IN_PROTOCOL *SimpleInput; + USB_KB_DEV *UsbKeyboardDevice; + EFI_USB_IO_PROTOCOL *UsbIo; + + Status = gBS->OpenProtocol ( + Controller, + &gEfiSimpleTextInProtocolGuid, + (VOID **) &SimpleInput, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + // + // Get USB_KB_DEV instance. + // + UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (SimpleInput); + + gBS->CloseProtocol ( + Controller, + &gEfiSimpleTextInProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + UsbIo = UsbKeyboardDevice->UsbIo; + // + // Uninstall the Asyn Interrupt Transfer from this device + // will disable the key data input from this device + // + KbdReportStatusCode ( + UsbKeyboardDevice->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_DISABLE) + ); + + // + // Destroy asynchronous interrupt transfer + // + 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, + &gEfiHotPlugDeviceGuid, + NULL, + NULL + ); + // + // free all the resources. + // + gBS->CloseEvent (UsbKeyboardDevice->RepeatTimer); + gBS->CloseEvent (UsbKeyboardDevice->DelayedRecoveryEvent); + gBS->CloseEvent ((UsbKeyboardDevice->SimpleInput).WaitForKey); + + if (UsbKeyboardDevice->ControllerNameTable != NULL) { + FreeUnicodeStringTable (UsbKeyboardDevice->ControllerNameTable); + } + + gBS->FreePool (UsbKeyboardDevice); + + return Status; + +} + + +EFI_STATUS +EFIAPI +USBKeyboardReset ( + IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + + Routine Description: + Implements EFI_SIMPLE_TEXT_IN_PROTOCOL.Reset() function. + + Arguments: + This The EFI_SIMPLE_TEXT_IN_PROTOCOL instance. + ExtendedVerification + Indicates that the driver may perform a more exhaustive + verification operation of the device during reset. + + Returns: + EFI_SUCCESS - Success + EFI_DEVICE_ERROR - Hardware Error +--*/ +{ + EFI_STATUS Status; + USB_KB_DEV *UsbKeyboardDevice; + EFI_USB_IO_PROTOCOL *UsbIo; + + UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This); + + UsbIo = UsbKeyboardDevice->UsbIo; + + KbdReportStatusCode ( + UsbKeyboardDevice->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_RESET) + ); + + // + // Non Exhaustive reset: + // only reset private data structures. + // + if (!ExtendedVerification) { + // + // Clear the key buffer of this Usb keyboard + // + KbdReportStatusCode ( + UsbKeyboardDevice->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_CLEAR_BUFFER) + ); + + InitUSBKeyBuffer (&(UsbKeyboardDevice->KeyboardBuffer)); + UsbKeyboardDevice->CurKeyChar = 0; + return EFI_SUCCESS; + } + + // + // Exhaustive reset + // + Status = InitUSBKeyboard (UsbKeyboardDevice); + UsbKeyboardDevice->CurKeyChar = 0; + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +USBKeyboardReadKeyStroke ( + IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This, + OUT EFI_INPUT_KEY *Key + ) +/*++ + + Routine Description: + Implements EFI_SIMPLE_TEXT_IN_PROTOCOL.ReadKeyStroke() function. + + Arguments: + This The EFI_SIMPLE_TEXT_IN_PROTOCOL instance. + Key A pointer to a buffer that is filled in with the keystroke + information for the key that was pressed. + + Returns: + EFI_SUCCESS - Success +--*/ +{ + USB_KB_DEV *UsbKeyboardDevice; + EFI_STATUS Status; + UINT8 KeyChar; + + UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This); + + // + // if there is no saved ASCII byte, fetch it + // by calling USBKeyboardCheckForKey(). + // + if (UsbKeyboardDevice->CurKeyChar == 0) { + Status = USBKeyboardCheckForKey (UsbKeyboardDevice); + if (EFI_ERROR (Status)) { + return Status; + } + } + + Key->UnicodeChar = 0; + Key->ScanCode = SCAN_NULL; + + KeyChar = UsbKeyboardDevice->CurKeyChar; + + UsbKeyboardDevice->CurKeyChar = 0; + + // + // Translate saved ASCII byte into EFI_INPUT_KEY + // + Status = USBKeyCodeToEFIScanCode (UsbKeyboardDevice, KeyChar, Key); + + return Status; + +} + +STATIC +VOID +EFIAPI +USBKeyboardWaitForKey ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + + Routine Description: + Handler function for WaitForKey event. + + Arguments: + Event Event to be signaled when a key is pressed. + Context Points to USB_KB_DEV instance. + + Returns: + VOID +--*/ +{ + USB_KB_DEV *UsbKeyboardDevice; + + UsbKeyboardDevice = (USB_KB_DEV *) Context; + + if (UsbKeyboardDevice->CurKeyChar == 0) { + + if (EFI_ERROR (USBKeyboardCheckForKey (UsbKeyboardDevice))) { + return ; + } + } + // + // If has key pending, signal the event. + // + gBS->SignalEvent (Event); +} + + +STATIC +EFI_STATUS +USBKeyboardCheckForKey ( + IN USB_KB_DEV *UsbKeyboardDevice + ) +/*++ + + Routine Description: + Check whether there is key pending. + + Arguments: + UsbKeyboardDevice The USB_KB_DEV instance. + + Returns: + EFI_SUCCESS - Success +--*/ +{ + EFI_STATUS Status; + UINT8 KeyChar; + + // + // Fetch raw data from the USB keyboard input, + // and translate it into ASCII data. + // + Status = USBParseKey (UsbKeyboardDevice, &KeyChar); + if (EFI_ERROR (Status)) { + return Status; + } + + UsbKeyboardDevice->CurKeyChar = KeyChar; + return EFI_SUCCESS; +} + +VOID +KbdReportStatusCode ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN EFI_STATUS_CODE_TYPE CodeType, + IN EFI_STATUS_CODE_VALUE Value + ) +/*++ + + Routine Description: + Report Status Code in Usb Bot Driver + + Arguments: + DevicePath - Use this to get Device Path + CodeType - Status Code Type + CodeValue - Status Code Value + + Returns: + None + +--*/ +{ + + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + CodeType, + Value, + DevicePath + ); +} diff --git a/EdkModulePkg/Bus/Usb/UsbKb/Dxe/efikey.h b/EdkModulePkg/Bus/Usb/UsbKb/Dxe/efikey.h new file mode 100644 index 0000000000..bf9f47732d --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbKb/Dxe/efikey.h @@ -0,0 +1,118 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + EfiKey.h + +Abstract: + + Header file for USB Keyboard Driver's Data Structures + +Revision History +--*/ +#ifndef _USB_KB_H +#define _USB_KB_H + + +#include + +#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 { + UINT8 Down; + UINT8 KeyCode; +} USB_KEY; + +typedef struct { + USB_KEY buffer[MAX_KEY_ALLOWED + 1]; + UINT8 bHead; + UINT8 bTail; +} USB_KB_BUFFER; + +#define USB_KB_DEV_SIGNATURE EFI_SIGNATURE_32 ('u', 'k', 'b', 'd') +typedef struct { + UINTN Signature; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_EVENT DelayedRecoveryEvent; + EFI_SIMPLE_TEXT_IN_PROTOCOL SimpleInput; + EFI_USB_IO_PROTOCOL *UsbIo; + + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + EFI_USB_ENDPOINT_DESCRIPTOR IntEndpointDescriptor; + + USB_KB_BUFFER KeyboardBuffer; + UINT8 CtrlOn; + UINT8 AltOn; + UINT8 ShiftOn; + UINT8 NumLockOn; + UINT8 CapsOn; + UINT8 LastKeyCodeArray[8]; + UINT8 CurKeyChar; + + UINT8 RepeatKey; + EFI_EVENT RepeatTimer; + + EFI_UNICODE_STRING_TABLE *ControllerNameTable; + +} USB_KB_DEV; + +// +// Global Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gUsbKeyboardDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gUsbKeyboardComponentName; +extern EFI_GUID gEfiUsbKeyboardDriverGuid; + +VOID +KbdReportStatusCode ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN EFI_STATUS_CODE_TYPE CodeType, + IN EFI_STATUS_CODE_VALUE Value + ); + +#define USB_KB_DEV_FROM_THIS(a) \ + CR(a, USB_KB_DEV, SimpleInput, USB_KB_DEV_SIGNATURE) + +#define MOD_CONTROL_L 0x01 +#define MOD_CONTROL_R 0x10 +#define MOD_SHIFT_L 0x02 +#define MOD_SHIFT_R 0x20 +#define MOD_ALT_L 0x04 +#define MOD_ALT_R 0x40 +#define MOD_WIN_L 0x08 +#define MOD_WIN_R 0x80 + +typedef struct { + UINT8 Mask; + UINT8 Key; +} KB_MODIFIER; + +#define USB_KEYCODE_MAX_MAKE 0x64 + +#define USBKBD_VALID_KEYCODE(key) ((UINT8) (key) > 3) + +typedef struct { + UINT8 NumLock : 1; + UINT8 CapsLock : 1; + UINT8 Resrvd : 6; +} LED_MAP; +#endif diff --git a/EdkModulePkg/Bus/Usb/UsbKb/Dxe/keyboard.c b/EdkModulePkg/Bus/Usb/UsbKb/Dxe/keyboard.c new file mode 100644 index 0000000000..1328e6a098 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbKb/Dxe/keyboard.c @@ -0,0 +1,1150 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Keyboard.c + +Abstract: + + Helper functions for USB Keyboard Driver + +Revision History + +--*/ + +#include "keyboard.h" + +// +// USB Key Code to Efi key mapping table +// Format:, , +// +STATIC +UINT8 KeyConvertionTable[USB_KEYCODE_MAX_MAKE][3] = { + { SCAN_NULL, 'a', 'A' }, // 0x04 + { SCAN_NULL, 'b', 'B' }, // 0x05 + { SCAN_NULL, 'c', 'C' }, // 0x06 + { SCAN_NULL, 'd', 'D' }, // 0x07 + { SCAN_NULL, 'e', 'E' }, // 0x08 + { SCAN_NULL, 'f', 'F' }, // 0x09 + { SCAN_NULL, 'g', 'G' }, // 0x0A + { SCAN_NULL, 'h', 'H' }, // 0x0B + { SCAN_NULL, 'i', 'I' }, // 0x0C + { SCAN_NULL, 'j', 'J' }, // 0x0D + { SCAN_NULL, 'k', 'K' }, // 0x0E + { SCAN_NULL, 'l', 'L' }, // 0x0F + { SCAN_NULL, 'm', 'M' }, // 0x10 + { SCAN_NULL, 'n', 'N' }, // 0x11 + { SCAN_NULL, 'o', 'O' }, // 0x12 + { SCAN_NULL, 'p', 'P' }, // 0x13 + { SCAN_NULL, 'q', 'Q' }, // 0x14 + { SCAN_NULL, 'r', 'R' }, // 0x15 + { SCAN_NULL, 's', 'S' }, // 0x16 + { SCAN_NULL, 't', 'T' }, // 0x17 + { SCAN_NULL, 'u', 'U' }, // 0x18 + { SCAN_NULL, 'v', 'V' }, // 0x19 + { SCAN_NULL, 'w', 'W' }, // 0x1A + { SCAN_NULL, 'x', 'X' }, // 0x1B + { SCAN_NULL, 'y', 'Y' }, // 0x1C + { SCAN_NULL, 'z', 'Z' }, // 0x1D + { SCAN_NULL, '1', '!' }, // 0x1E + { SCAN_NULL, '2', '@' }, // 0x1F + { SCAN_NULL, '3', '#' }, // 0x20 + { SCAN_NULL, '4', '$' }, // 0x21 + { SCAN_NULL, '5', '%' }, // 0x22 + { SCAN_NULL, '6', '^' }, // 0x23 + { SCAN_NULL, '7', '&' }, // 0x24 + { SCAN_NULL, '8', '*' }, // 0x25 + { SCAN_NULL, '9', '(' }, // 0x26 + { SCAN_NULL, '0', ')' }, // 0x27 + { SCAN_NULL, 0x0d, 0x0d }, // 0x28 Enter + { SCAN_ESC, 0x00, 0x00 }, // 0x29 Esc + { SCAN_NULL, 0x08, 0x08 }, // 0x2A Backspace + { SCAN_NULL, 0x09, 0x09 }, // 0x2B Tab + { SCAN_NULL, ' ', ' ' }, // 0x2C Spacebar + { SCAN_NULL, '-', '_' }, // 0x2D + { SCAN_NULL, '=', '+' }, // 0x2E + { SCAN_NULL, '[', '{' }, // 0x2F + { SCAN_NULL, ']', '}' }, // 0x30 + { SCAN_NULL, '\\', '|' }, // 0x31 + { SCAN_NULL, '\\', '|' }, // 0x32 Keyboard US \ and | + { SCAN_NULL, ';', ':' }, // 0x33 + { SCAN_NULL, '\'', '"' }, // 0x34 + { SCAN_NULL, '`', '~' }, // 0x35 Keyboard Grave Accent and Tlide + { SCAN_NULL, ',', '<' }, // 0x36 + { SCAN_NULL, '.', '>' }, // 0x37 + { SCAN_NULL, '/', '?' }, // 0x38 + { SCAN_NULL, 0x00, 0x00 }, // 0x39 CapsLock + { SCAN_F1, 0x00, 0x00 }, // 0x3A + { SCAN_F2, 0x00, 0x00 }, // 0x3B + { SCAN_F3, 0x00, 0x00 }, // 0x3C + { SCAN_F4, 0x00, 0x00 }, // 0x3D + { SCAN_F5, 0x00, 0x00 }, // 0x3E + { SCAN_F6, 0x00, 0x00 }, // 0x3F + { SCAN_F7, 0x00, 0x00 }, // 0x40 + { SCAN_F8, 0x00, 0x00 }, // 0x41 + { SCAN_F9, 0x00, 0x00 }, // 0x42 + { SCAN_F10, 0x00, 0x00 }, // 0x43 + { SCAN_NULL, 0x00, 0x00 }, // 0x44 F11 + { SCAN_NULL, 0x00, 0x00 }, // 0x45 F12 + { SCAN_NULL, 0x00, 0x00 }, // 0x46 PrintScreen + { SCAN_NULL, 0x00, 0x00 }, // 0x47 Scroll Lock + { SCAN_NULL, 0x00, 0x00 }, // 0x48 Pause + { SCAN_INSERT, 0x00, 0x00 }, // 0x49 + { SCAN_HOME, 0x00, 0x00 }, // 0x4A + { SCAN_PAGE_UP, 0x00, 0x00 }, // 0x4B + { SCAN_DELETE, 0x00, 0x00 }, // 0x4C + { SCAN_END, 0x00, 0x00 }, // 0x4D + { SCAN_PAGE_DOWN, 0x00, 0x00 }, // 0x4E + { SCAN_RIGHT, 0x00, 0x00 }, // 0x4F + { SCAN_LEFT, 0x00, 0x00 }, // 0x50 + { SCAN_DOWN, 0x00, 0x00 }, // 0x51 + { SCAN_UP, 0x00, 0x00 }, // 0x52 + { SCAN_NULL, 0x00, 0x00 }, // 0x53 NumLock + { SCAN_NULL, '/', '/' }, // 0x54 + { SCAN_NULL, '*', '*' }, // 0x55 + { SCAN_NULL, '-', '-' }, // 0x56 + { SCAN_NULL, '+', '+' }, // 0x57 + { SCAN_NULL, 0x0d, 0x0d }, // 0x58 + { SCAN_END, '1', '1' }, // 0x59 + { SCAN_DOWN, '2', '2' }, // 0x5A + { SCAN_PAGE_DOWN, '3', '3' }, // 0x5B + { SCAN_LEFT, '4', '4' }, // 0x5C + { SCAN_NULL, '5', '5' }, // 0x5D + { SCAN_RIGHT, '6', '6' }, // 0x5E + { SCAN_HOME, '7', '7' }, // 0x5F + { SCAN_UP, '8', '8' }, // 0x60 + { SCAN_PAGE_UP, '9', '9' }, // 0x61 + { SCAN_INSERT, '0', '0' }, // 0x62 + { SCAN_DELETE, '.', '.' }, // 0x63 + { SCAN_NULL, '\\', '|' }, // 0x64 Keyboard Non-US \ and | + { SCAN_NULL, 0x00, 0x00 }, // 0x65 Keyboard Application + { SCAN_NULL, 0x00, 0x00 }, // 0x66 Keyboard Power + { SCAN_NULL, '=' , '=' } // 0x67 Keypad = +}; + +STATIC KB_MODIFIER KB_Mod[8] = { + { MOD_CONTROL_L, 0xe0 }, // 11100000 + { MOD_CONTROL_R, 0xe4 }, // 11100100 + { MOD_SHIFT_L, 0xe1 }, // 11100001 + { MOD_SHIFT_R, 0xe5 }, // 11100101 + { MOD_ALT_L, 0xe2 }, // 11100010 + { MOD_ALT_R, 0xe6 }, // 11100110 + { MOD_WIN_L, 0xe3 }, // 11100011 + { MOD_WIN_R, 0xe7 } // 11100111 +}; + + +BOOLEAN +IsUSBKeyboard ( + IN EFI_USB_IO_PROTOCOL *UsbIo + ) +/*++ + + Routine Description: + Uses USB I/O to check whether the device is a USB Keyboard device. + + Arguments: + UsbIo: Points to a USB I/O protocol instance. + + Returns: + +--*/ +{ + EFI_STATUS Status; + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + + // + // Get the Default interface descriptor, currently we + // assume it is interface 1 + // + 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; +} + + +EFI_STATUS +InitUSBKeyboard ( + IN USB_KB_DEV *UsbKeyboardDevice + ) +/*++ + + Routine Description: + Initialize USB Keyboard device and all private data structures. + + Arguments: + UsbKeyboardDevice The USB_KB_DEV instance. + + Returns: + EFI_SUCCESS - Success + EFI_DEVICE_ERROR - Hardware Error +--*/ +{ + UINT8 ConfigValue; + UINT8 Protocol; + UINT8 ReportId; + UINT8 Duration; + EFI_STATUS Status; + UINT32 TransferResult; + EFI_USB_IO_PROTOCOL *UsbIo; + + UsbIo = UsbKeyboardDevice->UsbIo; + + KbdReportStatusCode ( + UsbKeyboardDevice->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_SELF_TEST) + ); + + InitUSBKeyBuffer (&(UsbKeyboardDevice->KeyboardBuffer)); + + // + // default configurations + // + ConfigValue = 0x01; + + // + // Uses default configuration to configure the USB Keyboard device. + // + Status = UsbSetDeviceConfiguration ( + UsbKeyboardDevice->UsbIo, + (UINT16) 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 + // + KbdReportStatusCode ( + UsbKeyboardDevice->DevicePath, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_INTERFACE_ERROR) + ); + + return EFI_DEVICE_ERROR; + } + + UsbGetProtocolRequest ( + UsbKeyboardDevice->UsbIo, + UsbKeyboardDevice->InterfaceDescriptor.InterfaceNumber, + &Protocol + ); + // + // Sets boot protocol for the USB Keyboard. + // This driver only supports boot protocol. + // !!BugBug: How about the device that does not support boot protocol? + // + if (Protocol != BOOT_PROTOCOL) { + UsbSetProtocolRequest ( + UsbKeyboardDevice->UsbIo, + UsbKeyboardDevice->InterfaceDescriptor.InterfaceNumber, + BOOT_PROTOCOL + ); + } + // + // the duration is indefinite, so the endpoint will inhibit reporting forever, + // and only reporting when a change is detected in the report data. + // + + // + // idle value for all report ID + // + ReportId = 0; + // + // idle forever until there is a key pressed and released. + // + Duration = 0; + UsbSetIdleRequest ( + UsbKeyboardDevice->UsbIo, + UsbKeyboardDevice->InterfaceDescriptor.InterfaceNumber, + ReportId, + Duration + ); + + UsbKeyboardDevice->CtrlOn = 0; + UsbKeyboardDevice->AltOn = 0; + UsbKeyboardDevice->ShiftOn = 0; + UsbKeyboardDevice->NumLockOn = 0; + UsbKeyboardDevice->CapsOn = 0; + ZeroMem (UsbKeyboardDevice->LastKeyCodeArray, sizeof (UINT8) * 8); + + // + // Set a timer for repeat keys' generation. + // + if (UsbKeyboardDevice->RepeatTimer) { + gBS->CloseEvent (UsbKeyboardDevice->RepeatTimer); + UsbKeyboardDevice->RepeatTimer = 0; + } + + Status = gBS->CreateEvent ( + EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL, + EFI_TPL_NOTIFY, + USBKeyboardRepeatHandler, + UsbKeyboardDevice, + &UsbKeyboardDevice->RepeatTimer + ); + + if (UsbKeyboardDevice->DelayedRecoveryEvent) { + gBS->CloseEvent (UsbKeyboardDevice->DelayedRecoveryEvent); + UsbKeyboardDevice->DelayedRecoveryEvent = 0; + } + + Status = gBS->CreateEvent ( + EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL, + EFI_TPL_NOTIFY, + USBKeyboardRecoveryHandler, + UsbKeyboardDevice, + &UsbKeyboardDevice->DelayedRecoveryEvent + ); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +KeyboardHandler ( + IN VOID *Data, + IN UINTN DataLength, + IN VOID *Context, + IN UINT32 Result + ) +/*++ + + Routine Description: + Handler function for USB Keyboard's asynchronous interrupt transfer. + + Arguments: + Data A pointer to a buffer that is filled with key data which is + retrieved via asynchronous interrupt transfer. + DataLength Indicates the size of the data buffer. + Context Pointing to USB_KB_DEV instance. + Result Indicates the result of the asynchronous interrupt transfer. + + Returns: + EFI_SUCCESS - Success + EFI_DEVICE_ERROR - Hardware Error +--*/ +{ + USB_KB_DEV *UsbKeyboardDevice; + EFI_USB_IO_PROTOCOL *UsbIo; + UINT8 *CurKeyCodeBuffer; + UINT8 *OldKeyCodeBuffer; + UINT8 CurModifierMap; + UINT8 OldModifierMap; + UINT8 Index; + UINT8 Index2; + BOOLEAN Down; + EFI_STATUS Status; + BOOLEAN KeyRelease; + BOOLEAN KeyPress; + UINT8 SavedTail; + USB_KEY UsbKey; + UINT8 NewRepeatKey; + UINT32 UsbStatus; + UINT8 *DataPtr; + + ASSERT (Context); + + NewRepeatKey = 0; + DataPtr = (UINT8 *) Data; + UsbKeyboardDevice = (USB_KB_DEV *) Context; + UsbIo = UsbKeyboardDevice->UsbIo; + + // + // Analyzes the Result and performs corresponding action. + // + if (Result != EFI_USB_NOERROR) { + // + // Some errors happen during the process + // + KbdReportStatusCode ( + UsbKeyboardDevice->DevicePath, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_INPUT_ERROR) + ); + + // + // 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 + // + + Status = UsbIo->UsbAsyncInterruptTransfer ( + UsbIo, + UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress, + FALSE, + 0, + 0, + NULL, + NULL + ); + + gBS->SetTimer ( + UsbKeyboardDevice->DelayedRecoveryEvent, + TimerRelative, + EFI_USB_INTERRUPT_DELAY + ); + + return EFI_DEVICE_ERROR; + } + + if (DataLength == 0 || Data == NULL) { + return EFI_SUCCESS; + } + + CurKeyCodeBuffer = (UINT8 *) Data; + OldKeyCodeBuffer = UsbKeyboardDevice->LastKeyCodeArray; + + // + // checks for new key stroke. + // if no new key got, return immediately. + // + for (Index = 0; Index < 8; Index++) { + if (OldKeyCodeBuffer[Index] != CurKeyCodeBuffer[Index]) { + break; + } + } + + if (Index == 8) { + return EFI_SUCCESS; + } + + // + // Parse the modifier key + // + CurModifierMap = CurKeyCodeBuffer[0]; + OldModifierMap = OldKeyCodeBuffer[0]; + + // + // handle modifier key's pressing or releasing situation. + // + for (Index = 0; Index < 8; Index++) { + + if ((CurModifierMap & KB_Mod[Index].Mask) != (OldModifierMap & KB_Mod[Index].Mask)) { + // + // if current modifier key is up, then + // CurModifierMap & KB_Mod[Index].Mask = 0; + // otherwize it is a non-zero value. + // Inserts the pressed modifier key into key buffer. + // + Down = (UINT8) (CurModifierMap & KB_Mod[Index].Mask); + InsertKeyCode (&(UsbKeyboardDevice->KeyboardBuffer), KB_Mod[Index].Key, Down); + } + } + + // + // handle normal key's releasing situation + // + KeyRelease = FALSE; + for (Index = 2; Index < 8; Index++) { + + if (!USBKBD_VALID_KEYCODE (OldKeyCodeBuffer[Index])) { + continue; + } + + 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) { + InsertKeyCode ( + &(UsbKeyboardDevice->KeyboardBuffer), + OldKeyCodeBuffer[Index], + 0 + ); + // + // the original reapeat key is released. + // + if (OldKeyCodeBuffer[Index] == UsbKeyboardDevice->RepeatKey) { + UsbKeyboardDevice->RepeatKey = 0; + } + } + } + + // + // 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; + } + + 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) { + InsertKeyCode (&(UsbKeyboardDevice->KeyboardBuffer), CurKeyCodeBuffer[Index], 1); + // + // NumLock pressed or CapsLock pressed + // + if (CurKeyCodeBuffer[Index] == 0x53 || CurKeyCodeBuffer[Index] == 0x39) { + UsbKeyboardDevice->RepeatKey = 0; + } else { + NewRepeatKey = CurKeyCodeBuffer[Index]; + // + // do not repeat the original repeated key + // + UsbKeyboardDevice->RepeatKey = 0; + } + } + } + + // + // Update LastKeycodeArray[] buffer in the + // Usb Keyboard Device data structure. + // + for (Index = 0; Index < 8; Index++) { + UsbKeyboardDevice->LastKeyCodeArray[Index] = CurKeyCodeBuffer[Index]; + } + + // + // pre-process KeyboardBuffer, pop out the ctrl,alt,del key in sequence + // and judge whether it will invoke reset event. + // + SavedTail = UsbKeyboardDevice->KeyboardBuffer.bTail; + Index = UsbKeyboardDevice->KeyboardBuffer.bHead; + while (Index != SavedTail) { + RemoveKeyCode (&(UsbKeyboardDevice->KeyboardBuffer), &UsbKey); + + switch (UsbKey.KeyCode) { + + case 0xe0: + case 0xe4: + if (UsbKey.Down) { + UsbKeyboardDevice->CtrlOn = 1; + } else { + UsbKeyboardDevice->CtrlOn = 0; + } + break; + + case 0xe2: + case 0xe6: + if (UsbKey.Down) { + UsbKeyboardDevice->AltOn = 1; + } else { + UsbKeyboardDevice->AltOn = 0; + } + break; + + // + // Del Key Code + // + case 0x4c: + case 0x63: + if (UsbKey.Down) { + if (UsbKeyboardDevice->CtrlOn && UsbKeyboardDevice->AltOn) { + gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL); + } + } + break; + + default: + break; + } + + // + // insert the key back to the buffer. + // so the key sequence will not be destroyed. + // + InsertKeyCode ( + &(UsbKeyboardDevice->KeyboardBuffer), + UsbKey.KeyCode, + UsbKey.Down + ); + Index = UsbKeyboardDevice->KeyboardBuffer.bHead; + + } + // + // If have 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; +} + +EFI_STATUS +USBParseKey ( + IN OUT USB_KB_DEV *UsbKeyboardDevice, + OUT UINT8 *KeyChar + ) +/*++ + + Routine Description: + Retrieves a key character after parsing the raw data in keyboard buffer. + + Arguments: + UsbKeyboardDevice The USB_KB_DEV instance. + KeyChar Points to the Key character after key parsing. + + Returns: + EFI_SUCCESS - Success + EFI_NOT_READY - Device is not ready +--*/ +{ + USB_KEY UsbKey; + + *KeyChar = 0; + + while (!IsUSBKeyboardBufferEmpty (&UsbKeyboardDevice->KeyboardBuffer)) { + // + // pops one raw data off. + // + RemoveKeyCode (&(UsbKeyboardDevice->KeyboardBuffer), &UsbKey); + + if (!UsbKey.Down) { + switch (UsbKey.KeyCode) { + + case 0xe0: + case 0xe4: + UsbKeyboardDevice->CtrlOn = 0; + break; + + case 0xe1: + case 0xe5: + UsbKeyboardDevice->ShiftOn = 0; + break; + + case 0xe2: + case 0xe6: + UsbKeyboardDevice->AltOn = 0; + break; + + default: + break; + } + + continue; + } + + // + // Analyzes key pressing situation + // + switch (UsbKey.KeyCode) { + + case 0xe0: + case 0xe4: + UsbKeyboardDevice->CtrlOn = 1; + continue; + break; + + case 0xe1: + case 0xe5: + UsbKeyboardDevice->ShiftOn = 1; + continue; + break; + + case 0xe2: + case 0xe6: + UsbKeyboardDevice->AltOn = 1; + continue; + break; + + case 0xe3: + case 0xe7: + continue; + break; + + case 0x53: + UsbKeyboardDevice->NumLockOn ^= 1; + SetKeyLED (UsbKeyboardDevice); + continue; + break; + + case 0x39: + UsbKeyboardDevice->CapsOn ^= 1; + SetKeyLED (UsbKeyboardDevice); + continue; + break; + + // + // F11,F12,PrintScreen,ScrollLock,Pause,Application,Power + // keys are not valid EFI key + // + case 0x44: + // + // fall through + // + case 0x45: + // + // fall through + // + case 0x46: + // + // fall through + // + case 0x47: + // + // fall through + // + case 0x48: + // + // fall through + // + case 0x65: + case 0x66: + continue; + break; + + default: + break; + } + + // + // When encountered Del Key... + // + if (UsbKey.KeyCode == 0x4c || UsbKey.KeyCode == 0x63) { + if (UsbKeyboardDevice->CtrlOn && UsbKeyboardDevice->AltOn) { + gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL); + } + } + + *KeyChar = UsbKey.KeyCode; + return EFI_SUCCESS; + } + + return EFI_NOT_READY; + +} + + +EFI_STATUS +USBKeyCodeToEFIScanCode ( + IN USB_KB_DEV *UsbKeyboardDevice, + IN UINT8 KeyChar, + OUT EFI_INPUT_KEY *Key + ) +/*++ + + Routine Description: + Converts USB Keyboard code to EFI Scan Code. + + Arguments: + UsbKeyboardDevice The USB_KB_DEV instance. + KeyChar Indicates the key code that will be interpreted. + Key A pointer to a buffer that is filled in with + the keystroke information for the key that + was pressed. + Returns: + EFI_NOT_READY - Device is not ready + EFI_SUCCESS - Success +--*/ +{ + UINT8 Index; + + if (!USBKBD_VALID_KEYCODE (KeyChar)) { + return EFI_NOT_READY; + } + + // + // valid USB Key Code starts from 4 + // + Index = (UINT8) (KeyChar - 4); + + if (Index >= USB_KEYCODE_MAX_MAKE) { + return EFI_NOT_READY; + } + + Key->ScanCode = KeyConvertionTable[Index][0]; + + if (UsbKeyboardDevice->ShiftOn) { + + Key->UnicodeChar = KeyConvertionTable[Index][2]; + + } else { + + Key->UnicodeChar = KeyConvertionTable[Index][1]; + } + + if (UsbKeyboardDevice->CapsOn) { + + if (Key->UnicodeChar >= 'a' && Key->UnicodeChar <= 'z') { + + Key->UnicodeChar = KeyConvertionTable[Index][2]; + + } else if (Key->UnicodeChar >= 'A' && Key->UnicodeChar <= 'Z') { + + Key->UnicodeChar = KeyConvertionTable[Index][1]; + + } + } + + if (KeyChar >= 0x59 && KeyChar <= 0x63) { + + if (UsbKeyboardDevice->NumLockOn && !UsbKeyboardDevice->ShiftOn) { + + Key->ScanCode = SCAN_NULL; + + } else { + + Key->UnicodeChar = 0x00; + } + } + + if (Key->UnicodeChar == 0 && Key->ScanCode == SCAN_NULL) { + return EFI_NOT_READY; + } + + return EFI_SUCCESS; + +} + + +EFI_STATUS +InitUSBKeyBuffer ( + IN OUT USB_KB_BUFFER *KeyboardBuffer + ) +/*++ + + Routine Description: + Resets USB Keyboard Buffer. + + Arguments: + KeyboardBuffer - Points to the USB Keyboard Buffer. + + Returns: + EFI_SUCCESS - Success +--*/ +{ + ZeroMem (KeyboardBuffer, sizeof (USB_KB_BUFFER)); + + KeyboardBuffer->bHead = KeyboardBuffer->bTail; + + return EFI_SUCCESS; +} + +BOOLEAN +IsUSBKeyboardBufferEmpty ( + IN USB_KB_BUFFER *KeyboardBuffer + ) +/*++ + + Routine Description: + Check whether USB Keyboard buffer is empty. + + Arguments: + KeyboardBuffer - USB Keyboard Buffer. + + Returns: + +--*/ +{ + // + // meet FIFO empty condition + // + return (BOOLEAN) (KeyboardBuffer->bHead == KeyboardBuffer->bTail); +} + + +BOOLEAN +IsUSBKeyboardBufferFull ( + IN USB_KB_BUFFER *KeyboardBuffer + ) +/*++ + + Routine Description: + Check whether USB Keyboard buffer is full. + + Arguments: + KeyboardBuffer - USB Keyboard Buffer. + + Returns: + +--*/ +{ + return (BOOLEAN)(((KeyboardBuffer->bTail + 1) % (MAX_KEY_ALLOWED + 1)) == + KeyboardBuffer->bHead); +} + + +EFI_STATUS +InsertKeyCode ( + IN OUT USB_KB_BUFFER *KeyboardBuffer, + IN UINT8 Key, + IN UINT8 Down + ) +/*++ + + Routine Description: + Inserts a key code into keyboard buffer. + + Arguments: + KeyboardBuffer - Points to the USB Keyboard Buffer. + Key - Key code + Down - Special key + Returns: + EFI_SUCCESS - Success +--*/ +{ + USB_KEY UsbKey; + + // + // if keyboard buffer is full, throw the + // first key out of the keyboard buffer. + // + if (IsUSBKeyboardBufferFull (KeyboardBuffer)) { + RemoveKeyCode (KeyboardBuffer, &UsbKey); + } + + KeyboardBuffer->buffer[KeyboardBuffer->bTail].KeyCode = Key; + KeyboardBuffer->buffer[KeyboardBuffer->bTail].Down = Down; + + // + // adjust the tail pointer of the FIFO keyboard buffer. + // + KeyboardBuffer->bTail = (UINT8) ((KeyboardBuffer->bTail + 1) % (MAX_KEY_ALLOWED + 1)); + + return EFI_SUCCESS; +} + +EFI_STATUS +RemoveKeyCode ( + IN OUT USB_KB_BUFFER *KeyboardBuffer, + OUT USB_KEY *UsbKey + ) +/*++ + + Routine Description: + Pops a key code off from keyboard buffer. + + Arguments: + KeyboardBuffer - Points to the USB Keyboard Buffer. + UsbKey - Points to the buffer that contains a usb key code. + + Returns: + EFI_SUCCESS - Success + EFI_DEVICE_ERROR - Hardware Error +--*/ +{ + if (IsUSBKeyboardBufferEmpty (KeyboardBuffer)) { + return EFI_DEVICE_ERROR; + } + + UsbKey->KeyCode = KeyboardBuffer->buffer[KeyboardBuffer->bHead].KeyCode; + UsbKey->Down = KeyboardBuffer->buffer[KeyboardBuffer->bHead].Down; + + // + // adjust the head pointer of the FIFO keyboard buffer. + // + KeyboardBuffer->bHead = (UINT8) ((KeyboardBuffer->bHead + 1) % (MAX_KEY_ALLOWED + 1)); + + return EFI_SUCCESS; +} + +EFI_STATUS +SetKeyLED ( + IN USB_KB_DEV *UsbKeyboardDevice + ) +/*++ + + Routine Description: + Sets USB Keyboard LED state. + + Arguments: + UsbKeyboardDevice - The USB_KB_DEV instance. + + Returns: + EFI_SUCCESS - Success +--*/ +{ + LED_MAP Led; + UINT8 ReportId; + + // + // Set each field in Led map. + // + Led.NumLock = (UINT8) UsbKeyboardDevice->NumLockOn; + Led.CapsLock = (UINT8) UsbKeyboardDevice->CapsOn; + 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 + ); + + return EFI_SUCCESS; +} + +VOID +EFIAPI +USBKeyboardRepeatHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + + Routine Description: + Timer handler for Repeat Key timer. + + Arguments: + Event - The Repeat Key event. + Context - Points to the USB_KB_DEV instance. + + Returns: + +--*/ +{ + USB_KB_DEV *UsbKeyboardDevice; + + UsbKeyboardDevice = (USB_KB_DEV *) Context; + + // + // Do nothing when there is no repeat key. + // + if (UsbKeyboardDevice->RepeatKey != 0) { + // + // Inserts one Repeat key into keyboard buffer, + // + InsertKeyCode ( + &(UsbKeyboardDevice->KeyboardBuffer), + UsbKeyboardDevice->RepeatKey, + 1 + ); + + // + // set repeate rate for repeat key generation. + // + gBS->SetTimer ( + UsbKeyboardDevice->RepeatTimer, + TimerRelative, + USBKBD_REPEAT_RATE + ); + + } +} + +VOID +EFIAPI +USBKeyboardRecoveryHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + + Routine Description: + Timer handler for Delayed Recovery timer. + + Arguments: + Event - The Delayed Recovery event. + Context - Points to the USB_KB_DEV instance. + + Returns: + +--*/ +{ + + USB_KB_DEV *UsbKeyboardDevice; + EFI_USB_IO_PROTOCOL *UsbIo; + UINT8 PacketSize; + + UsbKeyboardDevice = (USB_KB_DEV *) Context; + + UsbIo = UsbKeyboardDevice->UsbIo; + + PacketSize = (UINT8) (UsbKeyboardDevice->IntEndpointDescriptor.MaxPacketSize); + + UsbIo->UsbAsyncInterruptTransfer ( + UsbIo, + UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress, + TRUE, + UsbKeyboardDevice->IntEndpointDescriptor.Interval, + PacketSize, + KeyboardHandler, + UsbKeyboardDevice + ); +} diff --git a/EdkModulePkg/Bus/Usb/UsbKb/Dxe/keyboard.h b/EdkModulePkg/Bus/Usb/UsbKb/Dxe/keyboard.h new file mode 100644 index 0000000000..a01fda3ca4 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbKb/Dxe/keyboard.h @@ -0,0 +1,106 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Keyboard.h + +Abstract: + + Function prototype for USB Keyboard Driver + +Revision History +--*/ + +#ifndef _KEYBOARD_H +#define _KEYBOARD_H + +#include "efikey.h" + +BOOLEAN +IsUSBKeyboard ( + IN EFI_USB_IO_PROTOCOL *UsbIo + ); + +EFI_STATUS +InitUSBKeyboard ( + IN USB_KB_DEV *UsbKeyboardDevice + ); + +EFI_STATUS +EFIAPI +KeyboardHandler ( + IN VOID *Data, + IN UINTN DataLength, + IN VOID *Context, + IN UINT32 Result + ); + +VOID +EFIAPI +USBKeyboardRecoveryHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +EFI_STATUS +USBParseKey ( + IN OUT USB_KB_DEV *UsbKeyboardDevice, + OUT UINT8 *KeyChar + ); + +EFI_STATUS +USBKeyCodeToEFIScanCode ( + IN USB_KB_DEV *UsbKeyboardDevice, + IN UINT8 KeyChar, + OUT EFI_INPUT_KEY *Key + ); + +EFI_STATUS +InitUSBKeyBuffer ( + IN OUT USB_KB_BUFFER *KeyboardBuffer + ); + +BOOLEAN +IsUSBKeyboardBufferEmpty ( + IN USB_KB_BUFFER *KeyboardBuffer + ); + +BOOLEAN +IsUSBKeyboardBufferFull ( + IN USB_KB_BUFFER *KeyboardBuffer + ); + +EFI_STATUS +InsertKeyCode ( + IN OUT USB_KB_BUFFER *KeyboardBuffer, + IN UINT8 Key, + IN UINT8 Down + ); + +EFI_STATUS +RemoveKeyCode ( + IN OUT USB_KB_BUFFER *KeyboardBuffer, + OUT USB_KEY *UsbKey + ); + +VOID +EFIAPI +USBKeyboardRepeatHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +EFI_STATUS +SetKeyLED ( + IN USB_KB_DEV *UsbKeyboardDevice + ); + +#endif diff --git a/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/ComponentName.c b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/ComponentName.c new file mode 100644 index 0000000000..a021d95389 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/ComponentName.c @@ -0,0 +1,154 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ComponentName.c + +Abstract: + +--*/ + +#include "UsbMassStorage.h" + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +UsbMassStorageComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +EFI_STATUS +EFIAPI +UsbMassStorageComponentNameGetControllerName ( + 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 +// +EFI_COMPONENT_NAME_PROTOCOL gUsbMassStorageComponentName = { + UsbMassStorageComponentNameGetDriverName, + UsbMassStorageComponentNameGetControllerName, + "eng" +}; + +STATIC EFI_UNICODE_STRING_TABLE mUsbMassStorageDriverNameTable[] = { + { "eng", (CHAR16 *) L"Generic USB Mass Storage Driver" }, + { NULL , NULL } +}; + +EFI_STATUS +EFIAPI +UsbMassStorageComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gUsbMassStorageComponentName.SupportedLanguages, + mUsbMassStorageDriverNameTable, + DriverName + ); +} + +EFI_STATUS +EFIAPI +UsbMassStorageComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + 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. + 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. + + Returns: + 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. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return EFI_UNSUPPORTED; +} diff --git a/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.c b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.c new file mode 100644 index 0000000000..932b8c5ed9 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.c @@ -0,0 +1,727 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + UsbMassStorage.c + +Abstract: + + USB Mass Storage Driver + +Revision History + +--*/ + +#include "UsbMassStorage.h" +#include "UsbMassStorageHelper.h" + +extern EFI_COMPONENT_NAME_PROTOCOL gUsbMassStorageComponentName; + +// +// Prototypes +// Driver model protocol interface +// +EFI_STATUS +EFIAPI +USBMassStorageDriverBindingEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +EFI_STATUS +EFIAPI +USBFloppyDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +USBFloppyDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +USBFloppyDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +// +// Block I/O Protocol Interface +// +STATIC +EFI_STATUS +EFIAPI +USBFloppyReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +STATIC +EFI_STATUS +EFIAPI +USBFloppyReadBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ); + +STATIC +EFI_STATUS +EFIAPI +USBFloppyWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + IN VOID *Buffer + ); + +STATIC +EFI_STATUS +EFIAPI +USBFloppyFlushBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This + ); + +// +// USB Floppy Driver Global Variables +// +EFI_DRIVER_BINDING_PROTOCOL gUSBFloppyDriverBinding = { + USBFloppyDriverBindingSupported, + USBFloppyDriverBindingStart, + USBFloppyDriverBindingStop, + 0x10, + NULL, + NULL +}; + +EFI_STATUS +EFIAPI +USBFloppyDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + Test to see if this driver supports ControllerHandle. Any ControllerHandle + that has UsbHcProtocol installed will be supported. + + Arguments: + This - Protocol instance pointer. + Controller - Handle of device to test + RemainingDevicePath - Not used + + Returns: + EFI_SUCCESS - This driver supports this device. + EFI_UNSUPPORTED - This driver does not support this device. + +--*/ +{ + EFI_STATUS OpenStatus; + EFI_USB_ATAPI_PROTOCOL *AtapiProtocol; + + // + // check whether EFI_USB_ATAPI_PROTOCOL exists, if it does, + // then the controller must be a USB Mass Storage Controller + // + OpenStatus = gBS->OpenProtocol ( + Controller, + &gEfiUsbAtapiProtocolGuid, + (VOID **) &AtapiProtocol, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (OpenStatus)) { + return OpenStatus; + } + + gBS->CloseProtocol ( + Controller, + &gEfiUsbAtapiProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +USBFloppyDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + Starting the Usb Bus Driver + + Arguments: + This - Protocol instance pointer. + Controller - Handle of device to test + RemainingDevicePath - Not used + + Returns: + EFI_SUCCESS - This driver supports this device. + EFI_UNSUPPORTED - This driver does not support this device. + EFI_DEVICE_ERROR - This driver cannot be started due to device + Error + EFI_OUT_OF_RESOURCES- Can't allocate memory resources + EFI_ALREADY_STARTED - Thios driver has been started +--*/ +{ + EFI_STATUS Status; + EFI_USB_ATAPI_PROTOCOL *AtapiProtocol; + USB_FLOPPY_DEV *UsbFloppyDevice; + + UsbFloppyDevice = NULL; + // + // Check whether Usb Atapi Protocol attached on the controller handle. + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiUsbAtapiProtocolGuid, + (VOID **) &AtapiProtocol, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (USB_FLOPPY_DEV), + (VOID **) &UsbFloppyDevice + ); + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + Controller, + &gEfiUsbAtapiProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return Status; + } + + ZeroMem (UsbFloppyDevice, sizeof (USB_FLOPPY_DEV)); + + UsbFloppyDevice->Handle = Controller; + UsbFloppyDevice->BlkIo.Media = &UsbFloppyDevice->BlkMedia; + UsbFloppyDevice->Signature = USB_FLOPPY_DEV_SIGNATURE; + UsbFloppyDevice->BlkIo.Reset = USBFloppyReset; + UsbFloppyDevice->BlkIo.ReadBlocks = USBFloppyReadBlocks; + UsbFloppyDevice->BlkIo.WriteBlocks = USBFloppyWriteBlocks; + UsbFloppyDevice->BlkIo.FlushBlocks = USBFloppyFlushBlocks; + UsbFloppyDevice->AtapiProtocol = AtapiProtocol; + + // + // Identify drive type and retrieve media information. + // + Status = USBFloppyIdentify (UsbFloppyDevice); + if (EFI_ERROR (Status)) { + if (UsbFloppyDevice->SenseData != NULL) { + gBS->FreePool (UsbFloppyDevice->SenseData); + } + + gBS->FreePool (UsbFloppyDevice); + gBS->CloseProtocol ( + Controller, + &gEfiUsbAtapiProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return Status; + } + // + // Install Block I/O protocol for the usb floppy device. + // + Status = gBS->InstallProtocolInterface ( + &Controller, + &gEfiBlockIoProtocolGuid, + EFI_NATIVE_INTERFACE, + &UsbFloppyDevice->BlkIo + ); + if (EFI_ERROR (Status)) { + if (UsbFloppyDevice->SenseData != NULL) { + gBS->FreePool (UsbFloppyDevice->SenseData); + } + + gBS->FreePool (UsbFloppyDevice); + gBS->CloseProtocol ( + Controller, + &gEfiUsbAtapiProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return Status; + } + + return EFI_SUCCESS; + +} + + +EFI_STATUS +EFIAPI +USBFloppyDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + + Routine Description: + Stop this driver on ControllerHandle. Support stoping any child handles + created by this driver. + + Arguments: + This - Protocol instance pointer. + Controller - Handle of device to stop driver on + NumberOfChildren - Number of Children in the ChildHandleBuffer + ChildHandleBuffer - List of handles for the children we need to stop. + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + others + +--*/ +{ + EFI_STATUS Status; + USB_FLOPPY_DEV *UsbFloppyDevice; + EFI_BLOCK_IO_PROTOCOL *BlkIo; + + // + // First find USB_FLOPPY_DEV + // + gBS->OpenProtocol ( + Controller, + &gEfiBlockIoProtocolGuid, + (VOID **) &BlkIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + UsbFloppyDevice = USB_FLOPPY_DEV_FROM_THIS (BlkIo); + + // + // Uninstall Block I/O protocol from the device handle + // + Status = gBS->UninstallProtocolInterface ( + Controller, + &gEfiBlockIoProtocolGuid, + &UsbFloppyDevice->BlkIo + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Stop using EFI_USB_ATAPI_PROTOCOL + // + gBS->CloseProtocol ( + Controller, + &gEfiUsbAtapiProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + if (UsbFloppyDevice->SenseData != NULL) { + gBS->FreePool (UsbFloppyDevice->SenseData); + } + + gBS->FreePool (UsbFloppyDevice); + + return EFI_SUCCESS; +} + + +STATIC +EFI_STATUS +EFIAPI +USBFloppyReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + + Routine Description: + Implements EFI_BLOCK_IO_PROTOCOL.Reset() function. + + Arguments: + This The EFI_BLOCK_IO_PROTOCOL instance. + ExtendedVerification + Indicates that the driver may perform a more exhaustive + verification operation of the device during reset. + (This parameter is ingored in this driver.) + + Returns: + EFI_SUCCESS - Success +--*/ +{ + USB_FLOPPY_DEV *UsbFloppyDevice; + EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; + EFI_STATUS Status; + + UsbFloppyDevice = USB_FLOPPY_DEV_FROM_THIS (This); + + UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; + + // + // directly calling EFI_USB_ATAPI_PROTOCOL.Reset() to implement reset. + // + Status = UsbAtapiInterface->UsbAtapiReset (UsbAtapiInterface, TRUE); + + return Status; +} + +STATIC +EFI_STATUS +EFIAPI +USBFloppyReadBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +/*++ + + Routine Description: + Implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks() function. + + Arguments: + This The EFI_BLOCK_IO_PROTOCOL instance. + MediaId The media id that the read request is for. + LBA The starting logical block address to read from on the device. + BufferSize + The size of the Buffer in bytes. This must be a multiple of + the intrinsic block size of the device. + Buffer A pointer to the destination buffer for the data. The caller + is responsible for either having implicit or explicit ownership + of the buffer. + + Returns: + EFI_INVALID_PARAMETER - Parameter is error + EFI_SUCCESS - Success + EFI_DEVICE_ERROR - Hardware Error + EFI_NO_MEDIA - No media + EFI_MEDIA_CHANGED - Media Change + EFI_BAD_BUFFER_SIZE - Buffer size is bad + --*/ +{ + USB_FLOPPY_DEV *UsbFloppyDevice; + EFI_STATUS Status; + EFI_BLOCK_IO_MEDIA *Media; + UINTN BlockSize; + UINTN NumberOfBlocks; + BOOLEAN MediaChange; + EFI_TPL OldTpl; + UINT32 Retry; + + OldTpl = gBS->RaiseTPL (EFI_TPL_NOTIFY); + Status = EFI_SUCCESS; + MediaChange = FALSE; + Retry = 0; + + UsbFloppyDevice = USB_FLOPPY_DEV_FROM_THIS (This); + + // + // Check parameters + // + if (!Buffer) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + if (BufferSize == 0) { + Status = EFI_SUCCESS; + goto Done; + } + + UsbFloppyTestUnitReady (UsbFloppyDevice); + + Status = UsbFloppyDetectMedia (UsbFloppyDevice, &MediaChange); + if (EFI_ERROR (Status)) { + + Status = EFI_DEVICE_ERROR; + goto Done; + } + + if (MediaChange) { + gBS->RestoreTPL (OldTpl); + gBS->ReinstallProtocolInterface ( + UsbFloppyDevice->Handle, + &gEfiBlockIoProtocolGuid, + &UsbFloppyDevice->BlkIo, + &UsbFloppyDevice->BlkIo + ); + gBS->RaiseTPL (EFI_TPL_NOTIFY); + } + + Media = UsbFloppyDevice->BlkIo.Media; + BlockSize = Media->BlockSize; + NumberOfBlocks = BufferSize / BlockSize; + + if (!(Media->MediaPresent)) { + Status = EFI_NO_MEDIA; + goto Done; + } + + if (MediaId != Media->MediaId) { + Status = EFI_MEDIA_CHANGED; + 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 (!EFI_ERROR (Status)) { + + Status = USBFloppyRead10 (UsbFloppyDevice, Buffer, LBA, 1); + if (EFI_ERROR (Status)) { + This->Reset (This, TRUE); + Status = EFI_DEVICE_ERROR; + goto Done; + } + + LBA += 1; + NumberOfBlocks -= 1; + Buffer = (UINT8 *) Buffer + This->Media->BlockSize; + + if (NumberOfBlocks == 0) { + Status = EFI_SUCCESS; + goto Done; + } + + Status = USBFloppyRead10 (UsbFloppyDevice, Buffer, LBA, NumberOfBlocks); + if (EFI_ERROR (Status)) { + This->Reset (This, TRUE); + Status = EFI_DEVICE_ERROR; + } + } + +Done: + gBS->RestoreTPL (OldTpl); + return Status; +} + +STATIC +EFI_STATUS +EFIAPI +USBFloppyWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + IN VOID *Buffer + ) +/*++ + + Routine Description: + Implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks() function. + + Arguments: + This The EFI_BLOCK_IO_PROTOCOL instance. + MediaId The media id that the write request is for. + LBA The starting logical block address to be written. + The caller is responsible for writing to only + legitimate locations. + BufferSize + The size of the Buffer in bytes. This must be a multiple of + the intrinsic block size of the device. + Buffer A pointer to the source buffer for the data. The caller + is responsible for either having implicit or explicit ownership + of the buffer. + + Returns: + EFI_INVALID_PARAMETER - Parameter is error + EFI_SUCCESS - Success + EFI_DEVICE_ERROR - Hardware Error + EFI_NO_MEDIA - No media + EFI_MEDIA_CHANGED - Media Change + EFI_BAD_BUFFER_SIZE - Buffer size is bad + +--*/ +{ + USB_FLOPPY_DEV *UsbFloppyDevice; + EFI_STATUS Status; + EFI_BLOCK_IO_MEDIA *Media; + UINTN BlockSize; + UINTN NumberOfBlocks; + BOOLEAN MediaChange; + EFI_TPL OldTpl; + UINT32 Retry; + + OldTpl = gBS->RaiseTPL (EFI_TPL_NOTIFY); + Status = EFI_SUCCESS; + MediaChange = FALSE; + Retry = 0; + + UsbFloppyDevice = USB_FLOPPY_DEV_FROM_THIS (This); + + // + // Check parameters + // + if (!Buffer) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + if (BufferSize == 0) { + Status = EFI_SUCCESS; + goto Done; + } + + UsbFloppyTestUnitReady (UsbFloppyDevice); + + Status = UsbFloppyDetectMedia (UsbFloppyDevice, &MediaChange); + if (EFI_ERROR (Status)) { + + Status = EFI_DEVICE_ERROR; + goto Done; + } + + if (MediaChange) { + gBS->RestoreTPL (OldTpl); + gBS->ReinstallProtocolInterface ( + UsbFloppyDevice->Handle, + &gEfiBlockIoProtocolGuid, + &UsbFloppyDevice->BlkIo, + &UsbFloppyDevice->BlkIo + ); + gBS->RaiseTPL (EFI_TPL_NOTIFY); + } + + Media = UsbFloppyDevice->BlkIo.Media; + BlockSize = Media->BlockSize; + NumberOfBlocks = BufferSize / BlockSize; + + if (!(Media->MediaPresent)) { + Status = EFI_NO_MEDIA; + goto Done; + } + + if (MediaId != Media->MediaId) { + Status = EFI_MEDIA_CHANGED; + 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 (UsbFloppyDevice->BlkMedia.ReadOnly) { + Status = EFI_WRITE_PROTECTED; + goto Done; + } + + if (!EFI_ERROR (Status)) { + Status = USBFloppyWrite10 (UsbFloppyDevice, Buffer, LBA, 1); + if (EFI_ERROR (Status)) { + This->Reset (This, TRUE); + Status = EFI_DEVICE_ERROR; + goto Done; + } + + LBA += 1; + NumberOfBlocks -= 1; + Buffer = (UINT8 *) Buffer + This->Media->BlockSize; + + if (NumberOfBlocks == 0) { + Status = EFI_SUCCESS; + goto Done; + } + + Status = USBFloppyWrite10 (UsbFloppyDevice, Buffer, LBA, NumberOfBlocks); + if (EFI_ERROR (Status)) { + This->Reset (This, TRUE); + Status = EFI_DEVICE_ERROR; + } + } + +Done: + gBS->RestoreTPL (OldTpl); + return Status; +} + +STATIC +EFI_STATUS +EFIAPI +USBFloppyFlushBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This + ) +/*++ + + Routine Description: + Implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks() function. + (In this driver, this function just returns EFI_SUCCESS.) + + Arguments: + This The EFI_BLOCK_IO_PROTOCOL instance. + + Returns: + EFI_SUCCESS - Success +--*/ +{ + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.h b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.h new file mode 100644 index 0000000000..4874bb08cc --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.h @@ -0,0 +1,59 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + UsbMassStorage.h + +Abstract: + + Header file for USB Mass Storage Driver's Data Structures + +Revision History +--*/ + +#ifndef _USB_FLP_H +#define _USB_FLP_H + + +#include +#include "UsbMassStorageData.h" + +#define CLASS_MASSTORAGE 8 +#define SUBCLASS_UFI 4 +#define SUBCLASS_8070 5 +#define PROTOCOL_BOT 0x50 +#define PROTOCOL_CBI0 0 +#define PROTOCOL_CBI1 1 + +#define USBFLOPPY 1 +#define USBFLOPPY2 2 // for those that use ReadCapacity(0x25) command to retrieve media capacity +#define USBCDROM 3 + +#define USB_FLOPPY_DEV_SIGNATURE EFI_SIGNATURE_32 ('u', 'f', 'l', 'p') + +typedef struct { + UINTN Signature; + + EFI_HANDLE Handle; + EFI_BLOCK_IO_PROTOCOL BlkIo; + EFI_BLOCK_IO_MEDIA BlkMedia; + EFI_USB_ATAPI_PROTOCOL *AtapiProtocol; + + REQUEST_SENSE_DATA *SenseData; + UINT8 SenseDataNumber; + UINT8 DeviceType; + +} USB_FLOPPY_DEV; + +#define USB_FLOPPY_DEV_FROM_THIS(a) \ + CR(a, USB_FLOPPY_DEV, BlkIo, USB_FLOPPY_DEV_SIGNATURE) + +#endif diff --git a/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.mbd b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.mbd new file mode 100644 index 0000000000..c9c9b5c73b --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.mbd @@ -0,0 +1,43 @@ + + + + + UsbMassStorage + A5C6D68B-E78A-4426-9278-A8F0D9EB4D8F + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:18 + + + UefiBootServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + EdkDxePrintLib + BaseLib + EdkUsbLib + DxeMemoryAllocationLib + + diff --git a/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.msa b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.msa new file mode 100644 index 0000000000..d071c9f656 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.msa @@ -0,0 +1,70 @@ + + + + + UsbMassStorage + DXE_DRIVER + BS_DRIVER + A5C6D68B-E78A-4426-9278-A8F0D9EB4D8F + 0 + Component description file for UsbMassStorage module + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:18 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + BaseLib + UefiLib + BaseMemoryLib + EdkUsbLib + MemoryAllocationLib + UefiBootServicesTableLib + + + UsbMassStorage.h + UsbMassStorageData.h + UsbMassStorageHelper.h + UsbMassStorage.c + UsbMassStorageHelper.c + ComponentName.c + + + MdePkg + EdkModulePkg + + + UsbAtapi + BlockIo + + + + + + + gUSBFloppyDriverBinding + gUsbMassStorageComponentName + + + diff --git a/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorageData.h b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorageData.h new file mode 100644 index 0000000000..598c82e220 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorageData.h @@ -0,0 +1,394 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + UsbMassStorageData.h + +Abstract: + + Header file for USB Mass Storage Device related Data Structures + +Revision History +--*/ + +#ifndef _USB_FLP_DATA_H +#define _USB_FLP_DATA_H + +// +// bit definition +// +#define bit(a) 1 << (a) + +// +// timeout unit is in millisecond. +// +#define USBFLPTIMEOUT 2000 +#define STALL_1_MILLI_SECOND 1000 + +// +// ATAPI Packet Command +// +#pragma pack(1) + +typedef struct { + UINT8 opcode; + UINT8 reserved_1; + UINT8 reserved_2; + UINT8 reserved_3; + UINT8 reserved_4; + UINT8 reserved_5; + UINT8 reserved_6; + UINT8 reserved_7; + UINT8 reserved_8; + UINT8 reserved_9; + UINT8 reserved_10; + UINT8 reserved_11; +} TEST_UNIT_READY_CMD; + +typedef struct { + UINT8 opcode; + UINT8 reserved_1 : 4; + UINT8 lun : 4; + UINT8 page_code; + UINT8 reserved_3; + UINT8 allocation_length; + UINT8 reserved_5; + UINT8 reserved_6; + UINT8 reserved_7; + UINT8 reserved_8; + UINT8 reserved_9; + UINT8 reserved_10; + UINT8 reserved_11; +} INQUIRY_CMD; + +typedef struct { + UINT8 opcode; + UINT8 reserved_1 : 4; + UINT8 lun : 4; + UINT8 reserved_2; + UINT8 reserved_3; + UINT8 allocation_length; + UINT8 reserved_5; + UINT8 reserved_6; + UINT8 reserved_7; + UINT8 reserved_8; + UINT8 reserved_9; + UINT8 reserved_10; + UINT8 reserved_11; +} REQUEST_SENSE_CMD; + +typedef struct { + UINT8 opcode; + UINT8 reserved_1 : 4; + UINT8 lun : 4; + UINT8 page_code : 6; + UINT8 page_control : 2; + UINT8 reserved_3; + UINT8 reserved_4; + UINT8 reserved_5; + UINT8 reserved_6; + UINT8 parameter_list_length_hi; + UINT8 parameter_list_length_lo; + UINT8 reserved_9; + UINT8 reserved_10; + UINT8 reserved_11; +} MODE_SENSE_CMD_UFI; + +typedef struct { + UINT8 opcode; + UINT8 reserved_1 : 3; + UINT8 dbd : 1; + UINT8 reserved_2 : 1; + UINT8 lun : 3; + UINT8 page_code : 6; + UINT8 page_control : 2; + UINT8 reserved_3; + UINT8 allocation_length; + UINT8 control; +} MODE_SENSE_CMD_SCSI; + +typedef struct { + UINT8 opcode; + UINT8 reserved_1 : 5; + UINT8 lun : 3; + UINT8 Lba0; + UINT8 Lba1; + UINT8 Lba2; + UINT8 Lba3; + UINT8 reserved_6; + UINT8 TranLen0; + UINT8 TranLen1; + UINT8 reserved_9; + UINT8 reserved_10; + UINT8 reserved_11; +} READ10_CMD; + +typedef struct { + UINT8 opcode; + UINT8 reserved_1; + UINT8 reserved_2; + UINT8 reserved_3; + UINT8 reserved_4; + UINT8 reserved_5; + UINT8 reserved_6; + UINT8 allocation_length_hi; + UINT8 allocation_length_lo; + UINT8 reserved_9; + UINT8 reserved_10; + UINT8 reserved_11; +} READ_FORMAT_CAP_CMD; + +typedef union { + UINT16 Data16[6]; + TEST_UNIT_READY_CMD TestUnitReady; + READ10_CMD Read10; + REQUEST_SENSE_CMD RequestSense; + INQUIRY_CMD Inquiry; + MODE_SENSE_CMD_UFI ModeSenseUFI; + READ_FORMAT_CAP_CMD ReadFormatCapacity; + MODE_SENSE_CMD_SCSI ModeSenseSCSI; +} ATAPI_PACKET_COMMAND; + +#pragma pack() +// +// Packet Command Code +// +#define TEST_UNIT_READY 0x00 +#define REZERO 0x01 +#define REQUEST_SENSE 0x03 +#define FORMAT_UNIT 0x04 +#define REASSIGN_BLOCKS 0x07 +#define INQUIRY 0x12 +#define START_STOP_UNIT 0x1B +#define PREVENT_ALLOW_MEDIA_REMOVAL 0x1E +#define READ_FORMAT_CAPACITY 0x23 +#define OLD_FORMAT_UNIT 0x24 +#define READ_CAPACITY 0x25 +#define READ_10 0x28 +#define WRITE_10 0x2A +#define SEEK 0x2B +#define SEND_DIAGNOSTICS 0x3D +#define WRITE_VERIFY 0x2E +#define VERIFY 0x2F +#define READ_DEFECT_DATA 0x37 +#define WRITE_BUFFER 0x38 +#define READ_BUFFER 0x3C +#define READ_LONG 0x3E +#define WRITE_LONG 0x3F +#define MODE_SELECT 0x55 +#define UFI_MODE_SENSE5A 0x5A +#define SCSI_MODE_SENSE1A 0x1A +#define READ_12 0xA8 +#define WRITE_12 0xAA +#define MAX_ATAPI_BYTE_COUNT (0xfffe) + +// +// Sense Key +// +#define REQUEST_SENSE_ERROR (0x70) +#define SK_NO_SENSE (0x0) +#define SK_RECOVERY_ERROR (0x1) +#define SK_NOT_READY (0x2) +#define SK_MEDIUM_ERROR (0x3) +#define SK_HARDWARE_ERROR (0x4) +#define SK_ILLEGAL_REQUEST (0x5) +#define SK_UNIT_ATTENTION (0x6) +#define SK_DATA_PROTECT (0x7) +#define SK_BLANK_CHECK (0x8) +#define SK_VENDOR_SPECIFIC (0x9) +#define SK_RESERVED_A (0xA) +#define SK_ABORT (0xB) +#define SK_RESERVED_C (0xC) +#define SK_OVERFLOW (0xD) +#define SK_MISCOMPARE (0xE) +#define SK_RESERVED_F (0xF) + +// +// Additional Sense Codes +// +#define ASC_NOT_READY (0x04) +#define ASC_MEDIA_ERR1 (0x10) +#define ASC_MEDIA_ERR2 (0x11) +#define ASC_MEDIA_ERR3 (0x14) +#define ASC_MEDIA_ERR4 (0x30) +#define ASC_MEDIA_UPSIDE_DOWN (0x06) +#define ASC_INVALID_CMD (0x20) +#define ASC_LBA_OUT_OF_RANGE (0x21) +#define ASC_INVALID_FIELD (0x24) +#define ASC_WRITE_PROTECTED (0x27) +#define ASC_MEDIA_CHANGE (0x28) +#define ASC_RESET (0x29) /* Power On Reset or Bus Reset occurred */ +#define ASC_ILLEGAL_FIELD (0x26) +#define ASC_NO_MEDIA (0x3A) +#define ASC_ILLEGAL_MODE_FOR_THIS_TRACK (0x64) +#define ASC_LOGICAL_UNIT_STATUS (0x08) + +// +// Additional Sense Code Qualifier +// +#define ASCQ_IN_PROGRESS (0x01) +#define ASCQ_DEVICE_BUSY (0xff) +#define ASCQ_LOGICAL_UNIT_FAILURE (0x00) +#define ASCQ_LOGICAL_UNIT_TIMEOUT (0x01) +#define ASCQ_LOGICAL_UNIT_OVERRUN (0x80) + +#define SETFEATURE TRUE +#define CLEARFEATURE FALSE + +// +// ATAPI Data structure +// +#pragma pack(1) + +typedef struct { + UINT8 peripheral_type; + UINT8 RMB; + UINT8 version; + UINT8 response_data_format; + UINT8 addnl_length; + UINT8 reserved_5; + UINT8 reserved_6; + UINT8 reserved_7; + UINT8 vendor_info[8]; + UINT8 product_id[12]; + UINT8 eeprom_product_code[4]; + UINT8 firmware_rev_level[4]; +} USB_INQUIRY_DATA; + +typedef struct { + UINT8 error_code : 7; + UINT8 valid : 1; + UINT8 reserved_1; + UINT8 sense_key : 4; + UINT8 reserved_21 : 1; + UINT8 ILI : 1; + UINT8 reserved_22 : 2; + UINT8 vendor_specific_3; + UINT8 vendor_specific_4; + UINT8 vendor_specific_5; + UINT8 vendor_specific_6; + UINT8 addnl_sense_length; // n - 7 + UINT8 vendor_specific_8; + UINT8 vendor_specific_9; + UINT8 vendor_specific_10; + UINT8 vendor_specific_11; + UINT8 addnl_sense_code; // mandatory + UINT8 addnl_sense_code_qualifier; // mandatory + UINT8 field_replaceable_unit_code; // optional + UINT8 reserved_15; + UINT8 reserved_16; + UINT8 reserved_17; + // + // Followed by additional sense bytes : FIXME + // +} REQUEST_SENSE_DATA; + +typedef struct { + UINT8 LastLba3; + UINT8 LastLba2; + UINT8 LastLba1; + UINT8 LastLba0; + UINT8 BlockSize3; + UINT8 BlockSize2; + UINT8 BlockSize1; + UINT8 BlockSize0; +} READ_CAPACITY_DATA; + +typedef struct { + UINT8 reserved_0; + UINT8 reserved_1; + UINT8 reserved_2; + UINT8 Capacity_Length; + UINT8 LastLba3; + UINT8 LastLba2; + UINT8 LastLba1; + UINT8 LastLba0; + UINT8 DesCode : 2; + UINT8 reserved_9 : 6; + UINT8 BlockSize2; + UINT8 BlockSize1; + UINT8 BlockSize0; +} READ_FORMAT_CAPACITY_DATA; + +typedef struct { + UINT8 mode_data_len_hi; + UINT8 mode_data_len_lo; + UINT8 media_type_code; + UINT8 reserved_3_0 : 4; + UINT8 dpofua : 1; + UINT8 reserved_3_1 : 2; + UINT8 write_protected : 1; + UINT8 reserved_4; + UINT8 reserved_5; + UINT8 reserved_6; + UINT8 reserved_7; +} UFI_MODE_PARAMETER_HEADER; + +typedef struct { + UINT8 mode_data_len; + UINT8 media_type_code; + UINT8 speed : 4; + UINT8 buffered_mode : 3; + UINT8 write_protected : 1; + UINT8 block_descritptor_length; +} SCSI_MODE_PARAMETER_HEADER6; + +typedef struct { + UINT8 page_code : 6; + UINT8 reserved_0 : 1; + UINT8 parameter_savable : 1; + UINT8 page_length; + UINT8 transfer_rate_msb; + UINT8 transfer_rate_lsb; + UINT8 number_of_heads; + UINT8 sectors_per_track; + UINT8 databytes_per_sector_msb; + UINT8 databytes_per_sector_lsb; + UINT8 number_of_cylinders_msb; + UINT8 number_of_cylinders_lsb; + UINT8 reserved_10_18[9]; + UINT8 motor_on_delay; + UINT8 motor_off_delay; + UINT8 reserved_21_27[7]; + UINT8 medium_rotation_rate_msb; + UINT8 medium_rotation_rate_lsb; + UINT8 reserved_30_31[2]; +} FLEXIBLE_DISK_PAGE; + +typedef struct { + UFI_MODE_PARAMETER_HEADER mode_param_header; + FLEXIBLE_DISK_PAGE flex_disk_page; +} UFI_MODE_PARAMETER_PAGE_5; + +typedef struct { + UINT8 page_code : 6; + UINT8 reserved_0 : 1; + UINT8 parameter_savable : 1; + UINT8 page_length; + UINT8 reserved_2; + UINT8 inactive_time_multplier : 4; + UINT8 reserved_3 : 4; + UINT8 software_write_protect : 1; + UINT8 disable_media_access : 1; + UINT8 reserved_4 : 6; + UINT8 reserved_5; + UINT8 reserved_6; + UINT8 reserved_7; +} TIMER_AND_PROTECT_PAGE; + +typedef struct { + UFI_MODE_PARAMETER_HEADER mode_param_header; + TIMER_AND_PROTECT_PAGE time_and_protect_page; +} UFI_MODE_PARAMETER_PAGE_1C; + +#pragma pack() + +#endif diff --git a/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorageHelper.c b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorageHelper.c new file mode 100644 index 0000000000..b8ed813ea2 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorageHelper.c @@ -0,0 +1,1653 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + UsbMassStorageHelper.c + +Abstract: + + Helper functions for USB Mass Storage Driver + +Revision History + +--*/ + +#include "UsbMassStorageHelper.h" + +STATIC +BOOLEAN +IsNoMedia ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ); + +STATIC +BOOLEAN +IsMediaError ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ); + +STATIC +BOOLEAN +IsMediaChange ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ); + +STATIC +BOOLEAN +IsDriveReady ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts, + OUT BOOLEAN *NeedRetry + ); + +STATIC +BOOLEAN +IsMediaWriteProtected ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ); + +STATIC +BOOLEAN +IsLogicalUnitCommunicationOverRun ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ); + +EFI_STATUS +USBFloppyPacketCommand ( + USB_FLOPPY_DEV *UsbFloppyDevice, + VOID *Command, + UINT8 CommandSize, + VOID *DataBuffer, + UINT32 BufferLength, + EFI_USB_DATA_DIRECTION Direction, + UINT16 TimeOutInMilliSeconds + ) +/*++ + + Routine Description: + Sends Packet Command to USB Floppy Drive. + + Arguments: + UsbFloppyDevice - The USB_FLOPPY_DEV instance. + Command - A pointer to the command packet. + CommandSize - Indicates the size of the command packet. + DataBuffer - A pointer to the buffer for the data transfer + after the command packet. + BufferLength - Indicates the size of the Data Buffer. + Direction - Transfer Direction + TimeOutInMilliSeconds - Timeout Value + Returns: + EFI_SUCCESS - Success +--*/ +{ + EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; + EFI_STATUS Status; + + UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; + // + // Directly calling EFI_USB_ATAPI_PROTOCOL.UsbAtapiPacketCmd() + // to perform the command request. + // + Status = UsbAtapiInterface->UsbAtapiPacketCmd ( + UsbAtapiInterface, + Command, + CommandSize, + DataBuffer, + BufferLength, + Direction, + TimeOutInMilliSeconds + ); + + return Status; +} + +EFI_STATUS +USBFloppyIdentify ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ) +/*++ + + Routine Description: + Retrieves device information to tell the device type. + + Arguments: + UsbFloppyDevice The USB_FLOPPY_DEV instance. + + Returns: + EFI_DEVICE_ERROR - Hardware error + EFI_SUCCESS - Success +--*/ +{ + + EFI_STATUS Status; + USB_INQUIRY_DATA *Idata; + BOOLEAN MediaChange; + + // + // Send Inquiry Packet Command to get INQUIRY data. + // + Status = USBFloppyInquiry (UsbFloppyDevice, &Idata); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Get media removable info from INQUIRY data. + // + UsbFloppyDevice->BlkIo.Media->RemovableMedia = (UINT8) ((Idata->RMB & 0x80) == 0x80); + + // + // Identify device type via INQUIRY data. + // + switch ((Idata->peripheral_type) & 0x1f) { + // + // Floppy + // + case 0x00: + UsbFloppyDevice->DeviceType = USBFLOPPY; + UsbFloppyDevice->BlkIo.Media->MediaId = 0; + UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE; + UsbFloppyDevice->BlkIo.Media->LastBlock = 0; + UsbFloppyDevice->BlkIo.Media->BlockSize = 0x200; + break; + + // + // CD-ROM + // + case 0x05: + UsbFloppyDevice->DeviceType = USBCDROM; + UsbFloppyDevice->BlkIo.Media->MediaId = 0; + UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE; + UsbFloppyDevice->BlkIo.Media->LastBlock = 0; + UsbFloppyDevice->BlkIo.Media->BlockSize = 0x800; + UsbFloppyDevice->BlkIo.Media->ReadOnly = TRUE; + break; + + default: + gBS->FreePool (Idata); + return EFI_DEVICE_ERROR; + }; + + // + // Initialize some device specific data. + // + // + // original sense data numbers + // + UsbFloppyDevice->SenseDataNumber = 6; + + if (UsbFloppyDevice->SenseData != NULL) { + gBS->FreePool (UsbFloppyDevice->SenseData); + UsbFloppyDevice->SenseData = NULL; + } + + UsbFloppyDevice->SenseData = AllocatePool (UsbFloppyDevice->SenseDataNumber * sizeof (REQUEST_SENSE_DATA)); + + if (UsbFloppyDevice->SenseData == NULL) { + gBS->FreePool (Idata); + return EFI_DEVICE_ERROR; + } + + // + // Get media information. + // + UsbFloppyDetectMedia (UsbFloppyDevice, &MediaChange); + + gBS->FreePool (Idata); + + return EFI_SUCCESS; +} + +EFI_STATUS +USBFloppyInquiry ( + IN USB_FLOPPY_DEV *UsbFloppyDevice, + OUT USB_INQUIRY_DATA **Idata + ) +/*++ + + Routine Description: + Send Inquiry Packet Command to device and retrieve Inquiry Data. + + Arguments: + UsbFloppyDevice The USB_FLOPPY_DEV instance. + Idata A pointer pointing to the address of + Inquiry Data. + + Returns: + EFI_DEVICE_ERROR - Hardware error + EFI_SUCCESS - Success +--*/ +{ + ATAPI_PACKET_COMMAND Packet; + EFI_STATUS Status; + EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; + + UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; + + // + // prepare command packet for the Inquiry Packet Command. + // + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.Inquiry.opcode = INQUIRY; + Packet.Inquiry.page_code = 0; + Packet.Inquiry.allocation_length = sizeof (USB_INQUIRY_DATA); + + *Idata = AllocateZeroPool (sizeof (USB_INQUIRY_DATA)); + if (*Idata == NULL) { + return EFI_DEVICE_ERROR; + } + // + // Send command packet and retrieve requested Inquiry Data. + // + Status = USBFloppyPacketCommand ( + UsbFloppyDevice, + &Packet, + sizeof (ATAPI_PACKET_COMMAND), + (VOID *) (*Idata), + sizeof (USB_INQUIRY_DATA), + EfiUsbDataIn, + USBFLPTIMEOUT * 3 + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (*Idata); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +USBFloppyRead10 ( + IN USB_FLOPPY_DEV *UsbFloppyDevice, + IN VOID *Buffer, + IN EFI_LBA Lba, + IN UINTN NumberOfBlocks + ) +/*++ + + Routine Description: + Sends Read10 Packet Command to device to perform data transfer + from device to host. + + Arguments: + UsbFloppyDevice - The USB_FLOPPY_DEV instance. + Buffer - A pointer to the destination buffer for the data. + The caller is responsible for either having implicit + or explicit ownership of the buffer. + Lba - The starting logical block address to read from + on the device. + NumberOfBlocks - Indicates the number of blocks that the read + operation requests. + + Returns: + EFI_DEVICE_ERROR - Hardware error + EFI_SUCCESS - Success +--*/ +{ + ATAPI_PACKET_COMMAND Packet; + READ10_CMD *Read10Packet; + UINT16 MaxBlock; + UINT16 BlocksRemaining; + UINT16 SectorCount; + UINT32 Lba32; + UINT32 BlockSize; + UINT32 ByteCount; + VOID *ptrBuffer; + EFI_STATUS Status; + UINT16 TimeOut; + EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; + UINTN SenseCounts; + + UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; + + // + // prepare command packet for the Inquiry Packet Command. + // + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Read10Packet = &Packet.Read10; + Lba32 = (UINT32) Lba; + ptrBuffer = Buffer; + BlockSize = UsbFloppyDevice->BlkIo.Media->BlockSize; + + MaxBlock = (UINT16) (65536 / 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 = 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 * USBFLPTIMEOUT); + + Status = USBFloppyPacketCommand ( + UsbFloppyDevice, + &Packet, + sizeof (ATAPI_PACKET_COMMAND), + (VOID *) ptrBuffer, + ByteCount, + EfiUsbDataIn, + TimeOut + ); + if (EFI_ERROR (Status)) { + + Status = UsbFloppyRequestSense (UsbFloppyDevice, &SenseCounts); + if (!EFI_ERROR (Status)) { + if (IsLogicalUnitCommunicationOverRun ( + UsbFloppyDevice->SenseData, + SenseCounts + )) { + Lba32 = (UINT32) Lba; + ptrBuffer = Buffer; + BlocksRemaining = (UINT16) NumberOfBlocks; + MaxBlock = (UINT16) (MaxBlock / 4); + if (MaxBlock < 1) { + MaxBlock = 1; + } + + continue; + } + } else { + return EFI_DEVICE_ERROR; + } + // + // retry read10 command + // + Status = USBFloppyPacketCommand ( + UsbFloppyDevice, + &Packet, + sizeof (ATAPI_PACKET_COMMAND), + (VOID *) ptrBuffer, + ByteCount, + EfiUsbDataIn, + TimeOut + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + } + + Lba32 += SectorCount; + ptrBuffer = (UINT8 *) ptrBuffer + SectorCount * BlockSize; + BlocksRemaining = (UINT16) (BlocksRemaining - SectorCount); + } + + return Status; +} + +EFI_STATUS +USBFloppyReadCapacity ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ) +/*++ + + Routine Description: + Retrieves media capacity information via + sending Read Capacity Packet Command. + + Arguments: + UsbFloppyDevice - The USB_FLOPPY_DEV instance. + + Returns: + EFI_DEVICE_ERROR - Hardware error + EFI_SUCCESS - Success +--*/ +{ + // + // status returned by Read Capacity Packet Command + // + EFI_STATUS Status; + ATAPI_PACKET_COMMAND Packet; + EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; + + // + // used for capacity data returned from Usb Floppy + // + READ_CAPACITY_DATA Data; + + ZeroMem (&Data, sizeof (Data)); + + UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; + + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.Inquiry.opcode = READ_CAPACITY; + Status = USBFloppyPacketCommand ( + UsbFloppyDevice, + &Packet, + sizeof (ATAPI_PACKET_COMMAND), + (VOID *) &Data, + sizeof (READ_CAPACITY_DATA), + EfiUsbDataIn, + USBFLPTIMEOUT + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + UsbFloppyDevice->BlkIo.Media->LastBlock = (Data.LastLba3 << 24) | + (Data.LastLba2 << 16) | + (Data.LastLba1 << 8) | + Data.LastLba0; + + UsbFloppyDevice->BlkIo.Media->MediaPresent = TRUE; + + UsbFloppyDevice->BlkIo.Media->BlockSize = 0x800; + + return EFI_SUCCESS; + +} + +EFI_STATUS +USBFloppyReadFormatCapacity ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ) +/*++ + + Routine Description: + Retrieves media capacity information via sending Read Format + Capacity Packet Command. + + Arguments: + UsbFloppyDevice - The USB_FLOPPY_DEV instance. + + Returns: + EFI_DEVICE_ERROR - Hardware error + EFI_SUCCESS - Success +--*/ +{ + // + // status returned by Read Capacity Packet Command + // + EFI_STATUS Status; + ATAPI_PACKET_COMMAND Packet; + EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; + + // + // used for capacity data returned from Usb Floppy + // + READ_FORMAT_CAPACITY_DATA FormatData; + + ZeroMem (&FormatData, sizeof (FormatData)); + + UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; + + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.ReadFormatCapacity.opcode = READ_FORMAT_CAPACITY; + Packet.ReadFormatCapacity.allocation_length_lo = 12; + Status = USBFloppyPacketCommand ( + UsbFloppyDevice, + &Packet, + sizeof (ATAPI_PACKET_COMMAND), + (VOID *) &FormatData, + sizeof (READ_FORMAT_CAPACITY_DATA), + EfiUsbDataIn, + USBFLPTIMEOUT + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + if (FormatData.DesCode == 3) { + // + // Media is not present + // + UsbFloppyDevice->BlkIo.Media->MediaId = 0; + UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE; + UsbFloppyDevice->BlkIo.Media->LastBlock = 0; + } else { + + UsbFloppyDevice->BlkIo.Media->LastBlock = (FormatData.LastLba3 << 24) | + (FormatData.LastLba2 << 16) | + (FormatData.LastLba1 << 8) | + FormatData.LastLba0; + + UsbFloppyDevice->BlkIo.Media->LastBlock--; + + UsbFloppyDevice->BlkIo.Media->BlockSize = (FormatData.BlockSize2 << 16) | + (FormatData.BlockSize1 << 8) | + FormatData.BlockSize0; + + UsbFloppyDevice->BlkIo.Media->MediaPresent = TRUE; + + UsbFloppyDevice->BlkIo.Media->BlockSize = 0x200; + + } + + return EFI_SUCCESS; + +} + +EFI_STATUS +UsbFloppyRequestSense ( + IN USB_FLOPPY_DEV *UsbFloppyDevice, + OUT UINTN *SenseCounts + ) +/*++ + + Routine Description: + Retrieves Sense Data from device via + sending Request Sense Packet Command. + + Arguments: + UsbFloppyDevice - The USB_FLOPPY_DEV instance. + SenseCounts - A pointer to the number of Sense Data returned. + + Returns: + EFI_DEVICE_ERROR - Hardware error + EFI_SUCCESS - Success +--*/ +{ + EFI_STATUS Status; + REQUEST_SENSE_DATA *Sense; + UINT8 *Ptr; + BOOLEAN SenseReq; + ATAPI_PACKET_COMMAND Packet; + EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; + + UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; + + *SenseCounts = 0; + + ZeroMem ( + UsbFloppyDevice->SenseData, + sizeof (REQUEST_SENSE_DATA) * (UsbFloppyDevice->SenseDataNumber) + ); + // + // fill command packet for Request Sense Packet Command + // + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.RequestSense.opcode = REQUEST_SENSE; + Packet.RequestSense.allocation_length = sizeof (REQUEST_SENSE_DATA); + + // + // initialize pointer + // + Ptr = (UINT8 *) (UsbFloppyDevice->SenseData); + + // + // request sense data from device continuously + // until no sense data exists in the device. + // + for (SenseReq = TRUE; SenseReq;) { + + Sense = (REQUEST_SENSE_DATA *) Ptr; + + // + // send out Request Sense Packet Command and get one Sense + // data from device. + // + Status = USBFloppyPacketCommand ( + UsbFloppyDevice, + &Packet, + sizeof (ATAPI_PACKET_COMMAND), + (VOID *) Ptr, + sizeof (REQUEST_SENSE_DATA), + EfiUsbDataIn, + USBFLPTIMEOUT + ); + // + // failed to get Sense data + // + if (EFI_ERROR (Status)) { + // + // Recovery the device back to normal state. + // + UsbFloppyDevice->AtapiProtocol->UsbAtapiReset ( + UsbFloppyDevice->AtapiProtocol, + TRUE + ); + + if (*SenseCounts == 0) { + // + // never retrieved any sense data from device, + // just return error. + // + return EFI_DEVICE_ERROR; + } else { + // + // has retrieved some sense data from device, + // so return success. + // + return EFI_SUCCESS; + } + } + + if (Sense->sense_key != SK_NO_SENSE) { + // + // Ptr is byte based pointer + // + Ptr += sizeof (REQUEST_SENSE_DATA); + + (*SenseCounts)++; + + } else { + // + // when no sense key, skip out the loop + // + SenseReq = FALSE; + } + + // + // If the sense key numbers exceed Sense Data Buffer size, + // just skip the loop and do not fetch the sense key in this function. + // + if (*SenseCounts == UsbFloppyDevice->SenseDataNumber) { + SenseReq = FALSE; + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +UsbFloppyTestUnitReady ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ) +/*++ + + Routine Description: + Sends Test Unit ReadyPacket Command to the device. + + Arguments: + UsbFloppyDevice - The USB_FLOPPY_DEV instance. + + Returns: + EFI_DEVICE_ERROR - Hardware error + EFI_SUCCESS - Success +--*/ +{ + ATAPI_PACKET_COMMAND Packet; + EFI_STATUS Status; + EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; + UINT32 RetryIndex; + UINT32 MaximumRetryTimes; + + UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; + MaximumRetryTimes = 2; + // + // fill command packet + // + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.TestUnitReady.opcode = TEST_UNIT_READY; + + // + // send command packet + // + Status = EFI_DEVICE_ERROR; + + for (RetryIndex = 0; RetryIndex < MaximumRetryTimes && EFI_ERROR (Status); RetryIndex++) { + + Status = USBFloppyPacketCommand ( + UsbFloppyDevice, + &Packet, + sizeof (ATAPI_PACKET_COMMAND), + NULL, + 0, + EfiUsbNoData, + USBFLPTIMEOUT + ); + + if (EFI_ERROR (Status)) { + gBS->Stall (100 * STALL_1_MILLI_SECOND); + } + } + + return Status; +} + +EFI_STATUS +USBFloppyWrite10 ( + IN USB_FLOPPY_DEV *UsbFloppyDevice, + IN VOID *Buffer, + IN EFI_LBA Lba, + IN UINTN NumberOfBlocks + ) +/*++ + + Routine Description: + Sends Write10 Packet Command to device to perform data transfer + from host to device. + + Arguments: + UsbFloppyDevice - The USB_FLOPPY_DEV instance. + Buffer - A pointer to the source buffer for the data. + The caller is responsible for either having implicit + or explicit ownership of the buffer. + Lba - The starting logical block address to written to + the device. + NumberOfBlocks - Indicates the number of blocks that the write + operation requests. + + Returns: + EFI_DEVICE_ERROR - Hardware error + EFI_SUCCESS - Success +--*/ +{ + ATAPI_PACKET_COMMAND Packet; + READ10_CMD *Write10Packet; + UINT16 MaxBlock; + UINT16 BlocksRemaining; + UINT16 SectorCount; + UINT32 Lba32; + UINT32 BlockSize; + UINT32 ByteCount; + VOID *ptrBuffer; + EFI_STATUS Status; + UINT16 TimeOut; + EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; + UINTN SenseCounts; + + UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; + + // + // prepare command packet for the Write10 Packet Command. + // + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Write10Packet = &Packet.Read10; + Lba32 = (UINT32) Lba; + ptrBuffer = Buffer; + BlockSize = UsbFloppyDevice->BlkIo.Media->BlockSize; + + MaxBlock = (UINT16) (65536 / BlockSize); + BlocksRemaining = (UINT16) NumberOfBlocks; + + Status = EFI_SUCCESS; + while (BlocksRemaining > 0) { + + if (BlocksRemaining <= MaxBlock) { + + SectorCount = BlocksRemaining; + } else { + + SectorCount = MaxBlock; + } + // + // fill the Packet data structure + // + Write10Packet->opcode = WRITE_10; + + // + // Lba0 ~ Lba3 specify the start logical block address + // of the data transfer. + // Lba0 is MSB, Lba3 is LSB + // + Write10Packet->Lba3 = (UINT8) (Lba32 & 0xff); + Write10Packet->Lba2 = (UINT8) (Lba32 >> 8); + Write10Packet->Lba1 = (UINT8) (Lba32 >> 16); + Write10Packet->Lba0 = (UINT8) (Lba32 >> 24); + + // + // TranLen0 ~ TranLen1 specify the transfer length in block unit. + // TranLen0 is MSB, TranLen is LSB + // + Write10Packet->TranLen1 = (UINT8) (SectorCount & 0xff); + Write10Packet->TranLen0 = (UINT8) (SectorCount >> 8); + + ByteCount = SectorCount * BlockSize; + + TimeOut = (UINT16) (SectorCount * USBFLPTIMEOUT); + + Status = USBFloppyPacketCommand ( + UsbFloppyDevice, + &Packet, + sizeof (ATAPI_PACKET_COMMAND), + (VOID *) ptrBuffer, + ByteCount, + EfiUsbDataOut, + TimeOut + ); + if (EFI_ERROR (Status)) { + Status = UsbFloppyRequestSense (UsbFloppyDevice, &SenseCounts); + if (!EFI_ERROR (Status)) { + if (IsLogicalUnitCommunicationOverRun ( + UsbFloppyDevice->SenseData, + SenseCounts + )) { + Lba32 = (UINT32) Lba; + ptrBuffer = Buffer; + BlocksRemaining = (UINT16) NumberOfBlocks; + MaxBlock = (UINT16) (MaxBlock / 4); + if (MaxBlock < 1) { + MaxBlock = 1; + } + + continue; + } + } + // + // retry write10 command + // + Status = USBFloppyPacketCommand ( + UsbFloppyDevice, + &Packet, + sizeof (ATAPI_PACKET_COMMAND), + (VOID *) ptrBuffer, + ByteCount, + EfiUsbDataOut, + TimeOut + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + } + + Lba32 += SectorCount; + ptrBuffer = (UINT8 *) ptrBuffer + SectorCount * BlockSize; + BlocksRemaining = (UINT16) (BlocksRemaining - SectorCount); + } + + return Status; +} + +EFI_STATUS +UsbFloppyDetectMedia ( + IN USB_FLOPPY_DEV *UsbFloppyDevice, + OUT BOOLEAN *MediaChange + ) +/*++ + + Routine Description: + Retrieves media information. + + Arguments: + UsbFloppyDevice - The USB_FLOPPY_DEV instance. + MediaChange - Indicates whether media was changed. + + Returns: + EFI_DEVICE_ERROR - Hardware error + EFI_SUCCESS - Success + EFI_INVALID_PARAMETER - Parameter is error +--*/ +{ + EFI_STATUS Status; + EFI_STATUS FloppyStatus; + // + // the following variables are used to record previous media information + // + EFI_BLOCK_IO_MEDIA OldMediaInfo; + UINTN SenseCounts; + UINTN RetryIndex; + UINTN RetryTimes; + UINTN MaximumRetryTimes; + BOOLEAN NeedRetry; + + // + // a flag used to determine whether need to perform Read Capacity command. + // + BOOLEAN NeedReadCapacity; + + REQUEST_SENSE_DATA *SensePtr; + + // + // init + // + Status = EFI_SUCCESS; + FloppyStatus = EFI_SUCCESS; + CopyMem (&OldMediaInfo, UsbFloppyDevice->BlkIo.Media, sizeof (OldMediaInfo)); + //OldMediaInfo = *UsbFloppyDevice->BlkIo.Media; + *MediaChange = FALSE; + NeedReadCapacity = TRUE; + + // + // 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; + Status = UsbFloppyRequestSense (UsbFloppyDevice, &SenseCounts); + + if (!EFI_ERROR (Status)) { + + SensePtr = UsbFloppyDevice->SenseData; + + // + // No Media + // + if (IsNoMedia (UsbFloppyDevice->SenseData, SenseCounts)) { + + NeedReadCapacity = FALSE; + UsbFloppyDevice->BlkIo.Media->MediaId = 0; + UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE; + UsbFloppyDevice->BlkIo.Media->LastBlock = 0; + } else { + // + // Media Changed + // + if (IsMediaChange (UsbFloppyDevice->SenseData, SenseCounts)) { + UsbFloppyDevice->BlkIo.Media->MediaId++; + } + + // + // Media Write-protected + // + if (IsMediaWriteProtected (UsbFloppyDevice->SenseData, SenseCounts)) { + UsbFloppyDevice->BlkIo.Media->ReadOnly = TRUE; + } + + // + // Media Error + // + if (IsMediaError (UsbFloppyDevice->SenseData, SenseCounts)) { + // + // if media error encountered, make it look like no media present. + // + UsbFloppyDevice->BlkIo.Media->MediaId = 0; + UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE; + UsbFloppyDevice->BlkIo.Media->LastBlock = 0; + } + + } + + } + + if (NeedReadCapacity) { + // + // at most retry 5 times + // + MaximumRetryTimes = 5; + // + // initial retry twice + // + RetryTimes = 2; + + for (RetryIndex = 0; (RetryIndex < RetryTimes) && (RetryIndex < MaximumRetryTimes); RetryIndex++) { + // + // Using different command to retrieve media capacity. + // + switch (UsbFloppyDevice->DeviceType) { + + case USBCDROM: + Status = USBFloppyReadCapacity (UsbFloppyDevice); + break; + + case USBFLOPPY: + UsbMassStorageModeSense (UsbFloppyDevice); + Status = USBFloppyReadFormatCapacity (UsbFloppyDevice); + if (EFI_ERROR (Status) || !UsbFloppyDevice->BlkMedia.MediaPresent) { + // + // retry the ReadCapacity command + // + UsbFloppyDevice->DeviceType = USBFLOPPY2; + Status = EFI_DEVICE_ERROR; + } + break; + + case USBFLOPPY2: + UsbMassStorageModeSense (UsbFloppyDevice); + Status = USBFloppyReadCapacity (UsbFloppyDevice); + if (EFI_ERROR (Status)) { + // + // retry the ReadFormatCapacity command + // + UsbFloppyDevice->DeviceType = USBFLOPPY; + } + // + // force the BlockSize to be 0x200. + // + UsbFloppyDevice->BlkIo.Media->BlockSize = 0x200; + break; + + default: + return EFI_INVALID_PARAMETER; + } + + if (!EFI_ERROR (Status)) { + // + // skip the loop when read capacity succeeds. + // + break; + } + + SenseCounts = 0; + + FloppyStatus = UsbFloppyRequestSense (UsbFloppyDevice, &SenseCounts); + + // + // If Request Sense data failed,retry. + // + if (EFI_ERROR (FloppyStatus)) { + // + // retry once more + // + RetryTimes++; + continue; + } + // + // No Media + // + if (IsNoMedia (UsbFloppyDevice->SenseData, SenseCounts)) { + + UsbFloppyDevice->BlkIo.Media->MediaId = 0; + UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE; + UsbFloppyDevice->BlkIo.Media->LastBlock = 0; + break; + } + + if (IsMediaError (UsbFloppyDevice->SenseData, SenseCounts)) { + // + // if media error encountered, make it look like no media present. + // + UsbFloppyDevice->BlkIo.Media->MediaId = 0; + UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE; + UsbFloppyDevice->BlkIo.Media->LastBlock = 0; + break; + } + + if (IsMediaWriteProtected (UsbFloppyDevice->SenseData, SenseCounts)) { + UsbFloppyDevice->BlkIo.Media->ReadOnly = TRUE; + continue; + } + + if (!IsDriveReady (UsbFloppyDevice->SenseData, SenseCounts, &NeedRetry)) { + + // + // Drive not ready: if NeedRetry, then retry once more; + // else return error + // + if (NeedRetry) { + // + // Stall 0.1 second to wait for drive becoming ready + // + gBS->Stall (100 * STALL_1_MILLI_SECOND); + // + // reset retry variable to zero, + // to make it retry for "drive in progress of becoming ready". + // + RetryIndex = 0; + continue; + } else { + return EFI_DEVICE_ERROR; + } + } + // + // if read capacity fail not for above reasons, retry once more + // + RetryTimes++; + + } + // + // ENDFOR + // + + // + // tell whether the readcapacity process is successful or not + // ("Status" variable record the latest status returned + // by ReadCapacity AND "FloppyStatus" record the latest status + // returned by RequestSense) + // + if (EFI_ERROR (Status) && EFI_ERROR (FloppyStatus)) { + return EFI_DEVICE_ERROR; + } + + } + + if (UsbFloppyDevice->BlkIo.Media->MediaPresent != OldMediaInfo.MediaPresent) { + + if (UsbFloppyDevice->BlkIo.Media->MediaPresent) { + UsbFloppyDevice->BlkIo.Media->MediaId = 1; + } + + *MediaChange = TRUE; + } + + if (UsbFloppyDevice->BlkIo.Media->ReadOnly != OldMediaInfo.ReadOnly) { + *MediaChange = TRUE; + UsbFloppyDevice->BlkIo.Media->MediaId += 1; + } + + if (UsbFloppyDevice->BlkIo.Media->BlockSize != OldMediaInfo.BlockSize) { + *MediaChange = TRUE; + UsbFloppyDevice->BlkIo.Media->MediaId += 1; + } + + if (UsbFloppyDevice->BlkIo.Media->LastBlock != OldMediaInfo.LastBlock) { + *MediaChange = TRUE; + UsbFloppyDevice->BlkIo.Media->MediaId += 1; + } + + if (UsbFloppyDevice->BlkIo.Media->MediaId != OldMediaInfo.MediaId) { + *MediaChange = TRUE; + } + + return EFI_SUCCESS; +} + + + +EFI_STATUS +UsbFloppyModeSense5APage5 ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ) +/*++ + + Routine Description: + Retrieves media capacity information via sending Read Format + Capacity Packet Command. + + Arguments: + UsbFloppyDevice - The USB_FLOPPY_DEV instance. + + Returns: + EFI_DEVICE_ERROR - Hardware error + EFI_SUCCESS - Success + +--*/ +{ + // + // status returned by Read Capacity Packet Command + // + EFI_STATUS Status; + ATAPI_PACKET_COMMAND Packet; + EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; + UFI_MODE_PARAMETER_PAGE_5 ModePage5; + EFI_LBA LastBlock; + UINT32 SectorsPerTrack; + UINT32 NumberOfCylinders; + UINT32 NumberOfHeads; + UINT32 DataBytesPerSector; + + UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; + + ZeroMem (&ModePage5, sizeof (UFI_MODE_PARAMETER_PAGE_5)); + + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.ModeSenseUFI.opcode = UFI_MODE_SENSE5A; + // + // Flexible Disk Page + // + Packet.ModeSenseUFI.page_code = 5; + // + // current values + // + Packet.ModeSenseUFI.page_control = 0; + Packet.ModeSenseUFI.parameter_list_length_hi = 0; + Packet.ModeSenseUFI.parameter_list_length_lo = sizeof (UFI_MODE_PARAMETER_PAGE_5); + Status = USBFloppyPacketCommand ( + UsbFloppyDevice, + &Packet, + sizeof (ATAPI_PACKET_COMMAND), + (VOID *) &ModePage5, + sizeof (UFI_MODE_PARAMETER_PAGE_5), + EfiUsbDataIn, + USBFLPTIMEOUT + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + NumberOfHeads = ModePage5.flex_disk_page.number_of_heads; + SectorsPerTrack = ModePage5.flex_disk_page.sectors_per_track; + NumberOfCylinders = ModePage5.flex_disk_page.number_of_cylinders_msb << 8 | + ModePage5.flex_disk_page.number_of_cylinders_lsb; + + LastBlock = SectorsPerTrack * NumberOfHeads * NumberOfCylinders; + DataBytesPerSector = ModePage5.flex_disk_page.databytes_per_sector_msb << 8 | + ModePage5.flex_disk_page.databytes_per_sector_lsb; + + UsbFloppyDevice->BlkIo.Media->LastBlock = LastBlock; + + UsbFloppyDevice->BlkIo.Media->LastBlock--; + + UsbFloppyDevice->BlkIo.Media->BlockSize = DataBytesPerSector; + + UsbFloppyDevice->BlkIo.Media->MediaPresent = TRUE; + + UsbFloppyDevice->BlkIo.Media->ReadOnly = + ModePage5.mode_param_header.write_protected; + + return EFI_SUCCESS; + +} + +EFI_STATUS +UsbFloppyModeSense5APage1C ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ) +/*++ + + Routine Description: + Retrieves media capacity information via sending Read Format + Capacity Packet Command. + + Arguments: + UsbFloppyDevice - The USB_FLOPPY_DEV instance. + + Returns: + EFI_DEVICE_ERROR - Hardware error + EFI_SUCCESS - Success + +--*/ +{ + // + // status returned by Read Capacity Packet Command + // + EFI_STATUS Status; + ATAPI_PACKET_COMMAND Packet; + EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; + UFI_MODE_PARAMETER_PAGE_1C ModePage1C; + + UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; + + ZeroMem (&ModePage1C, sizeof (UFI_MODE_PARAMETER_PAGE_1C)); + + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.ModeSenseUFI.opcode = UFI_MODE_SENSE5A; + // + // Flexible Disk Page + // + Packet.ModeSenseUFI.page_code = 0x1C; + // + // current values + // + Packet.ModeSenseUFI.page_control = 0; + Packet.ModeSenseUFI.parameter_list_length_hi = 0; + Packet.ModeSenseUFI.parameter_list_length_lo = sizeof (UFI_MODE_PARAMETER_PAGE_1C); + Status = USBFloppyPacketCommand ( + UsbFloppyDevice, + &Packet, + sizeof (ATAPI_PACKET_COMMAND), + (VOID *) &ModePage1C, + sizeof (UFI_MODE_PARAMETER_PAGE_1C), + EfiUsbDataIn, + USBFLPTIMEOUT + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + UsbFloppyDevice->BlkIo.Media->ReadOnly = ModePage1C.mode_param_header.write_protected; + + return EFI_SUCCESS; + +} + +EFI_STATUS +UsbMassStorageModeSense ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ) +{ + if (UsbFloppyDevice->AtapiProtocol->CommandProtocol == EFI_USB_SUBCLASS_SCSI) { + return UsbSCSIModeSense1APage3F (UsbFloppyDevice); + } else { + return UsbFloppyModeSense5APage3F (UsbFloppyDevice); + } +} + +EFI_STATUS +UsbFloppyModeSense5APage3F ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ) +/*++ + + Routine Description: + Retrieves mode sense information via sending Mode Sense + Packet Command. + + Arguments: + UsbFloppyDevice - The USB_FLOPPY_DEV instance. + + Returns: + EFI_DEVICE_ERROR - Hardware error + EFI_SUCCESS - Success + +--*/ +{ + // + // status returned by Read Capacity Packet Command + // + EFI_STATUS Status; + ATAPI_PACKET_COMMAND Packet; + EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; + UFI_MODE_PARAMETER_HEADER Header; + UINT32 Size; + + UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; + + Size = sizeof (UFI_MODE_PARAMETER_HEADER); + + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.ModeSenseUFI.opcode = UFI_MODE_SENSE5A; + Packet.ModeSenseUFI.page_code = 0x3F; + Packet.ModeSenseUFI.page_control = 0; + Packet.ModeSenseUFI.parameter_list_length_hi = 0; + Packet.ModeSenseUFI.parameter_list_length_lo = (UINT8) Size; + Status = USBFloppyPacketCommand ( + UsbFloppyDevice, + &Packet, + sizeof (ATAPI_PACKET_COMMAND), + &Header, + Size, + EfiUsbDataIn, + USBFLPTIMEOUT + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + UsbFloppyDevice->BlkIo.Media->ReadOnly = Header.write_protected; + + return EFI_SUCCESS; + +} + +EFI_STATUS +UsbSCSIModeSense1APage3F ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ) +/*++ + + Routine Description: + Retrieves mode sense information via sending Mode Sense + Packet Command. + + Arguments: + UsbFloppyDevice - The USB_FLOPPY_DEV instance. + + Returns: + EFI_DEVICE_ERROR - Hardware error + EFI_SUCCESS - Success + +--*/ +{ + // + // status returned by Read Capacity Packet Command + // + EFI_STATUS Status; + ATAPI_PACKET_COMMAND Packet; + EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; + SCSI_MODE_PARAMETER_HEADER6 Header; + UINT32 Size; + + UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; + + Size = sizeof (SCSI_MODE_PARAMETER_HEADER6); + + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.ModeSenseSCSI.opcode = SCSI_MODE_SENSE1A; + Packet.ModeSenseSCSI.page_code = 0x3F; + Packet.ModeSenseSCSI.page_control = 0; + Packet.ModeSenseSCSI.allocation_length = (UINT8) Size; + Status = USBFloppyPacketCommand ( + UsbFloppyDevice, + &Packet, + sizeof (MODE_SENSE_CMD_SCSI), + &Header, + Size, + EfiUsbDataIn, + USBFLPTIMEOUT + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + UsbFloppyDevice->BlkIo.Media->ReadOnly = Header.write_protected; + return EFI_SUCCESS; + +} + +/*++ + + The following functions are a set of helper functions, + which are used to parse sense key returned by the device. + +--*/ +BOOLEAN +IsNoMedia ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +{ + REQUEST_SENSE_DATA *SensePtr; + UINTN Index; + BOOLEAN NoMedia; + + NoMedia = FALSE; + + SensePtr = SenseData; + + for (Index = 0; Index < SenseCounts; Index++) { + + if ((SensePtr->sense_key == SK_NOT_READY) && + (SensePtr->addnl_sense_code == ASC_NO_MEDIA)) { + + NoMedia = TRUE; + } + + SensePtr++; + } + + return NoMedia; +} + + +BOOLEAN +IsMediaError ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +{ + REQUEST_SENSE_DATA *SensePtr; + UINTN Index; + BOOLEAN IsError; + + IsError = FALSE; + SensePtr = SenseData; + + for (Index = 0; Index < SenseCounts; Index++) { + + switch (SensePtr->sense_key) { + + // + // Medium error case + // + case SK_MEDIUM_ERROR: + switch (SensePtr->addnl_sense_code) { + + case ASC_MEDIA_ERR1: + case ASC_MEDIA_ERR2: + case ASC_MEDIA_ERR3: + case ASC_MEDIA_ERR4: + IsError = TRUE; + break; + + default: + break; + } + + break; + + // + // Medium upside-down case + // + case SK_NOT_READY: + switch (SensePtr->addnl_sense_code) { + case ASC_MEDIA_UPSIDE_DOWN: + IsError = TRUE; + break; + + default: + break; + } + break; + + default: + break; + } + + SensePtr++; + } + + return IsError; +} + +BOOLEAN +IsMediaChange ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +{ + REQUEST_SENSE_DATA *SensePtr; + UINTN Index; + BOOLEAN MediaChanged; + + MediaChanged = FALSE; + SensePtr = SenseData; + + for (Index = 0; Index < SenseCounts; Index++) { + + if ((SensePtr->sense_key == SK_UNIT_ATTENTION) && + (SensePtr->addnl_sense_code == ASC_MEDIA_CHANGE)) { + + MediaChanged = TRUE; + } + + SensePtr++; + } + + return MediaChanged; +} + +BOOLEAN +IsDriveReady ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts, + OUT BOOLEAN *NeedRetry + ) +{ + REQUEST_SENSE_DATA *SensePtr; + UINTN Index; + BOOLEAN IsReady; + + IsReady = TRUE; + *NeedRetry = FALSE; + SensePtr = SenseData; + + for (Index = 0; Index < SenseCounts; Index++) { + + if ((SensePtr->sense_key == SK_NOT_READY) && + (SensePtr->addnl_sense_code == ASC_NOT_READY)) { + + switch (SensePtr->addnl_sense_code_qualifier) { + + case ASCQ_IN_PROGRESS: + case ASCQ_DEVICE_BUSY: + IsReady = FALSE; + *NeedRetry = TRUE; + break; + + default: + // + // Drive is in error condition, + // no need to retry. + // + IsReady = FALSE; + *NeedRetry = FALSE; + break; + } + } + + SensePtr++; + } + + return IsReady; +} + +BOOLEAN +IsMediaWriteProtected ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +{ + REQUEST_SENSE_DATA *SensePtr; + UINTN Index; + BOOLEAN IsWriteProtected; + + IsWriteProtected = FALSE; + SensePtr = SenseData; + + for (Index = 0; Index < SenseCounts; Index++) { + // + // catch media write-protected condition. + // + if ((SensePtr->sense_key == SK_DATA_PROTECT) && + (SensePtr->addnl_sense_code == ASC_WRITE_PROTECTED)) { + + IsWriteProtected = TRUE; + } + + SensePtr++; + } + + return IsWriteProtected; +} + +BOOLEAN +IsLogicalUnitCommunicationOverRun ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +{ + REQUEST_SENSE_DATA *SensePtr; + UINTN Index; + BOOLEAN IsOverRun; + + IsOverRun = FALSE; + SensePtr = SenseData; + + for (Index = 0; Index < SenseCounts; Index++) { + + if ((SensePtr->sense_key == SK_NOT_READY) && + (SensePtr->addnl_sense_code == ASC_LOGICAL_UNIT_STATUS) && + (SensePtr->addnl_sense_code_qualifier == ASCQ_LOGICAL_UNIT_OVERRUN)) { + IsOverRun = TRUE; + } + + SensePtr++; + } + + return IsOverRun; +} diff --git a/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorageHelper.h b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorageHelper.h new file mode 100644 index 0000000000..f41241adc4 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorageHelper.h @@ -0,0 +1,111 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + UsbMassStorageHelper.h + +Abstract: + + Function prototype for USB Mass Storage Driver + +Revision History +--*/ +#ifndef _USB_FLPHLP_H +#define _USB_FLPHLP_H + +#include "UsbMassStorage.h" + +EFI_STATUS +USBFloppyIdentify ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ); + +EFI_STATUS +USBFloppyPacketCommand ( + USB_FLOPPY_DEV *UsbFloppyDevice, + VOID *Command, + UINT8 CommandSize, + VOID *DataBuffer, + UINT32 BufferLength, + EFI_USB_DATA_DIRECTION Direction, + UINT16 TimeOutInMilliSeconds + ); + +EFI_STATUS +USBFloppyInquiry ( + IN USB_FLOPPY_DEV *UsbFloppyDevice, + OUT USB_INQUIRY_DATA **Idata + ); + +EFI_STATUS +USBFloppyRead10 ( + IN USB_FLOPPY_DEV *UsbFloppyDevice, + IN VOID *Buffer, + IN EFI_LBA Lba, + IN UINTN NumberOfBlocks + ); + +EFI_STATUS +USBFloppyReadFormatCapacity ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ); + +EFI_STATUS +UsbFloppyRequestSense ( + IN USB_FLOPPY_DEV *UsbFloppyDevice, + OUT UINTN *SenseCounts + ); + +EFI_STATUS +UsbFloppyTestUnitReady ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ); + +EFI_STATUS +USBFloppyWrite10 ( + IN USB_FLOPPY_DEV *UsbFloppyDevice, + IN VOID *Buffer, + IN EFI_LBA Lba, + IN UINTN NumberOfBlocks + ); + +EFI_STATUS +UsbFloppyDetectMedia ( + IN USB_FLOPPY_DEV *UsbFloppyDevice, + OUT BOOLEAN *MediaChange + ); + +EFI_STATUS +UsbFloppyModeSense5APage5 ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ); + +EFI_STATUS +UsbFloppyModeSense5APage1C ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ); + +EFI_STATUS +UsbFloppyModeSense5APage3F ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ); + +EFI_STATUS +UsbSCSIModeSense1APage3F ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ); + +EFI_STATUS +UsbMassStorageModeSense ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ); + +#endif diff --git a/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/build.xml b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/build.xml new file mode 100644 index 0000000000..d2e48d3027 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/ComponentName.c b/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/ComponentName.c new file mode 100644 index 0000000000..5b01cea9d4 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/ComponentName.c @@ -0,0 +1,216 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ComponentName.c + +Abstract: + +--*/ + +#include "usbmouse.h" + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +UsbMouseComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +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 Component Name Protocol +// +EFI_COMPONENT_NAME_PROTOCOL gUsbMouseComponentName = { + UsbMouseComponentNameGetDriverName, + UsbMouseComponentNameGetControllerName, + "eng" +}; + +STATIC EFI_UNICODE_STRING_TABLE mUsbMouseDriverNameTable[] = { + { "eng", (CHAR16 *) L"Usb Mouse Driver" }, + { NULL , NULL } +}; + + +EFI_STATUS +EFIAPI +UsbMouseComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gUsbMouseComponentName.SupportedLanguages, + mUsbMouseDriverNameTable, + DriverName + ); +} + +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 + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + 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. + 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. + + Returns: + 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. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + 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 LookupUnicodeString ( + Language, + gUsbMouseComponentName.SupportedLanguages, + UsbMouseDev->ControllerNameTable, + ControllerName + ); + +} diff --git a/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/UsbMouse.mbd b/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/UsbMouse.mbd new file mode 100644 index 0000000000..88b3e47a97 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/UsbMouse.mbd @@ -0,0 +1,43 @@ + + + + + UsbMouse + 2D2E62AA-9ECF-43b7-8219-94E7FC713DFE + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:18 + + + UefiBootServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + EdkDxePrintLib + BaseLib + EdkUsbLib + DxeMemoryAllocationLib + + diff --git a/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/UsbMouse.msa b/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/UsbMouse.msa new file mode 100644 index 0000000000..8d2e1a2999 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/UsbMouse.msa @@ -0,0 +1,71 @@ + + + + + UsbMouse + DXE_DRIVER + BS_DRIVER + 2D2E62AA-9ECF-43b7-8219-94E7FC713DFE + 0 + Component description file for UsbMouse module + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:18 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + BaseLib + UefiLib + BaseMemoryLib + EdkUsbLib + ReportStatusCodeLib + MemoryAllocationLib + UefiBootServicesTableLib + + + usbmouse.h + usbmouse.c + mousehid.h + mousehid.c + ComponentName.c + + + MdePkg + EdkModulePkg + + + DevicePath + UsbIo + SimplePointer + + + + + + + gUsbMouseDriverBinding + gUsbMouseComponentName + + + diff --git a/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/build.xml b/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/build.xml new file mode 100644 index 0000000000..081a9e0582 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/mousehid.c b/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/mousehid.c new file mode 100644 index 0000000000..cbe0970484 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/mousehid.c @@ -0,0 +1,395 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Mousehid.c + +Abstract: + Parse mouse hid descriptor + +--*/ + +#include "usbmouse.h" +#include "mousehid.h" + +// +// Get an item from report descriptor +// +STATIC +UINT8 * +GetNextItem ( + IN UINT8 *StartPos, + IN UINT8 *EndPos, + OUT HID_ITEM *HidItem + ) +/*++ + +Routine Description: + + Get Next Item + +Arguments: + + StartPos - Start Position + EndPos - End Position + HidItem - HidItem to return + +Returns: + Position + +--*/ +{ + UINT8 Temp; + + if ((EndPos - StartPos) <= 0) { + return NULL; + } + + Temp = *StartPos; + StartPos++; + // + // bit 2,3 + // + HidItem->Type = (UINT8) ((Temp >> 2) & 0x03); + // + // bit 4-7 + // + HidItem->Tag = (UINT8) ((Temp >> 4) & 0x0F); + + if (HidItem->Tag == HID_ITEM_TAG_LONG) { + // + // Long Items are not supported by HID rev1.0, + // 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; + // + // bit 0, 1 + // + HidItem->Size = (UINT8) (Temp & 0x03); + switch (HidItem->Size) { + + case 0: + // + // No data + // + return StartPos; + + case 1: + // + // One byte data + // + if ((EndPos - StartPos) >= 1) { + HidItem->Data.U8 = *StartPos++; + return StartPos; + } + + case 2: + // + // Two byte data + // + if ((EndPos - StartPos) >= 2) { + CopyMem (&HidItem->Data.U16, StartPos, sizeof (UINT16)); + StartPos += 2; + return StartPos; + } + + case 3: + // + // 4 byte data, adjust size + // + HidItem->Size++; + if ((EndPos - StartPos) >= 4) { + CopyMem (&HidItem->Data.U32, StartPos, sizeof (UINT32)); + StartPos += 4; + return StartPos; + } + } + } + + return NULL; +} + +STATIC +UINT32 +GetItemData ( + IN HID_ITEM *HidItem + ) +/*++ + +Routine Description: + + Get Item Data + +Arguments: + + HidItem - HID_ITEM + +Returns: + HidItem Data + + +--*/ +{ + // + // Get Data from HID_ITEM structure + // + switch (HidItem->Size) { + + case 1: + return HidItem->Data.U8; + + case 2: + return HidItem->Data.U16; + + case 4: + return HidItem->Data.U32; + } + + return 0; +} + +STATIC +VOID +ParseLocalItem ( + IN USB_MOUSE_DEV *UsbMouse, + IN HID_ITEM *LocalItem + ) +/*++ + +Routine Description: + + Parse Local Item + +Arguments: + + UsbMouse - USB_MOUSE_DEV + LocalItem - Local Item + +Returns: + +--*/ +{ + UINT32 Data; + + if (LocalItem->Size == 0) { + // + // No expected data for local item + // + return ; + } + + Data = GetItemData (LocalItem); + + switch (LocalItem->Tag) { + + case HID_LOCAL_ITEM_TAG_DELIMITER: + // + // we don't support delimiter here + // + return ; + + case HID_LOCAL_ITEM_TAG_USAGE: + return ; + + case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM: + if (UsbMouse->PrivateData.ButtonDetected) { + UsbMouse->PrivateData.ButtonMinIndex = (UINT8) Data; + } + + return ; + + case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM: + { + if (UsbMouse->PrivateData.ButtonDetected) { + UsbMouse->PrivateData.ButtonMaxIndex = (UINT8) Data; + } + + return ; + } + } +} + +STATIC +VOID +ParseGlobalItem ( + IN USB_MOUSE_DEV *UsbMouse, + IN HID_ITEM *GlobalItem + ) +{ + UINT8 UsagePage; + + switch (GlobalItem->Tag) { + case HID_GLOBAL_ITEM_TAG_USAGE_PAGE: + { + UsagePage = (UINT8) GetItemData (GlobalItem); + + // + // We only care Button Page here + // + if (UsagePage == 0x09) { + // + // Button Page + // + UsbMouse->PrivateData.ButtonDetected = TRUE; + return ; + } + break; + } + + } +} + + +STATIC +VOID +ParseMainItem ( + IN USB_MOUSE_DEV *UsbMouse, + IN HID_ITEM *MainItem + ) +/*++ + +Routine Description: + + Parse Main Item + +Arguments: + + UsbMouse - TODO: add argument description + MainItem - HID_ITEM to parse + +Returns: + + VOID + +--*/ +{ + // + // we don't care any main items, just skip + // + return ; +} + +STATIC +VOID +ParseHidItem ( + IN USB_MOUSE_DEV *UsbMouse, + IN HID_ITEM *HidItem + ) +/*++ + +Routine Description: + + Parse Hid Item + +Arguments: + + UsbMouse - USB_MOUSE_DEV + HidItem - HidItem to parse + +Returns: + + VOID + +--*/ +{ + switch (HidItem->Type) { + + case HID_ITEM_TYPE_MAIN: + // + // For Main Item, parse main item + // + ParseMainItem (UsbMouse, HidItem); + break; + + case HID_ITEM_TYPE_GLOBAL: + // + // For global Item, parse global item + // + ParseGlobalItem (UsbMouse, HidItem); + break; + + case HID_ITEM_TYPE_LOCAL: + // + // For Local Item, parse local item + // + ParseLocalItem (UsbMouse, HidItem); + break; + } +} +// +// A simple parse just read some field we are interested in +// +EFI_STATUS +ParseMouseReportDescriptor ( + IN USB_MOUSE_DEV *UsbMouse, + IN UINT8 *ReportDescriptor, + IN UINTN ReportSize + ) +/*++ + +Routine Description: + + Parse Mouse Report Descriptor + +Arguments: + + UsbMouse - USB_MOUSE_DEV + ReportDescriptor - Report descriptor to parse + ReportSize - Report descriptor size + +Returns: + + EFI_DEVICE_ERROR - Report descriptor error + EFI_SUCCESS - Success + +--*/ +{ + UINT8 *DescriptorEnd; + UINT8 *ptr; + HID_ITEM HidItem; + + DescriptorEnd = ReportDescriptor + ReportSize; + + ptr = GetNextItem (ReportDescriptor, DescriptorEnd, &HidItem); + + while (ptr != NULL) { + if (HidItem.Format != HID_ITEM_FORMAT_SHORT) { + // + // Long Format Item is not supported at current HID revision + // + return EFI_DEVICE_ERROR; + } + + ParseHidItem (UsbMouse, &HidItem); + + ptr = GetNextItem (ptr, DescriptorEnd, &HidItem); + } + + UsbMouse->NumberOfButtons = (UINT8) (UsbMouse->PrivateData.ButtonMaxIndex - UsbMouse->PrivateData.ButtonMinIndex + 1); + UsbMouse->XLogicMax = UsbMouse->YLogicMax = 127; + UsbMouse->XLogicMin = UsbMouse->YLogicMin = -127; + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/mousehid.h b/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/mousehid.h new file mode 100644 index 0000000000..ccce8354ea --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/mousehid.h @@ -0,0 +1,84 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + MouseHid.h + +Abstract: + +--*/ + +#ifndef __MOUSE_HID_H +#define __MOUSE_HID_H + +#include "usbmouse.h" + +// +// HID Item general structure +// +typedef struct _hid_item { + UINT16 Format; + UINT8 Size; + UINT8 Type; + UINT8 Tag; + union { + UINT8 U8; + UINT16 U16; + UINT32 U32; + INT8 I8; + INT16 I16; + INT32 I32; + UINT8 *LongData; + } Data; +} HID_ITEM; + +typedef struct { + UINT16 UsagePage; + INT32 LogicMin; + INT32 LogicMax; + INT32 PhysicalMin; + INT32 PhysicalMax; + UINT16 UnitExp; + UINT16 UINT; + UINT16 ReportId; + UINT16 ReportSize; + UINT16 ReportCount; +} HID_GLOBAL; + +typedef struct { + UINT16 Usage[16]; /* usage array */ + UINT16 UsageIndex; + UINT16 UsageMin; +} HID_LOCAL; + +typedef struct { + UINT16 Type; + UINT16 Usage; +} HID_COLLECTION; + +typedef struct { + HID_GLOBAL Global; + HID_GLOBAL GlobalStack[8]; + UINT32 GlobalStackPtr; + HID_LOCAL Local; + HID_COLLECTION CollectionStack[8]; + UINT32 CollectionStackPtr; +} HID_PARSER; + +EFI_STATUS +ParseMouseReportDescriptor ( + IN USB_MOUSE_DEV *UsbMouse, + IN UINT8 *ReportDescriptor, + IN UINTN ReportSize + ); + +#endif diff --git a/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/usbmouse.c b/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/usbmouse.c new file mode 100644 index 0000000000..81da0205a4 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/usbmouse.c @@ -0,0 +1,1028 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + Module Name: + + UsbMouse.c + + Abstract: + +--*/ + +#include "usbmouse.h" +#include "mousehid.h" + +// +// Prototypes +// Driver model protocol interface +// +EFI_STATUS +EFIAPI +USBMouseDriverBindingEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +EFI_STATUS +EFIAPI +USBMouseDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +USBMouseDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +USBMouseDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + + +EFI_DRIVER_BINDING_PROTOCOL gUsbMouseDriverBinding = { + USBMouseDriverBindingSupported, + USBMouseDriverBindingStart, + USBMouseDriverBindingStop, + 0x10, + NULL, + NULL +}; + +// +// helper functions +// +STATIC +BOOLEAN +IsUsbMouse ( + IN EFI_USB_IO_PROTOCOL *UsbIo + ); + +STATIC +EFI_STATUS +InitializeUsbMouseDevice ( + IN USB_MOUSE_DEV *UsbMouseDev + ); + +STATIC +VOID +EFIAPI +UsbMouseWaitForInput ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +// +// Mouse interrupt handler +// +STATIC +EFI_STATUS +EFIAPI +OnMouseInterruptComplete ( + IN VOID *Data, + IN UINTN DataLength, + IN VOID *Context, + IN UINT32 Result + ); + +// +// Mouse Protocol +// +STATIC +EFI_STATUS +EFIAPI +GetMouseState ( + IN EFI_SIMPLE_POINTER_PROTOCOL *This, + OUT EFI_SIMPLE_POINTER_STATE *MouseState + ); + +STATIC +EFI_STATUS +EFIAPI +UsbMouseReset ( + IN EFI_SIMPLE_POINTER_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +EFI_STATUS +EFIAPI +USBMouseDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + Test to see if this driver supports ControllerHandle. Any ControllerHandle + that has UsbHcProtocol installed will be supported. + + Arguments: + This - Protocol instance pointer. + Controller - Handle of device to test + RemainingDevicePath - Not used + + Returns: + EFI_SUCCESS - This driver supports this device. + EFI_UNSUPPORTED - This driver does not support this device. + +--*/ +{ + EFI_STATUS OpenStatus; + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_STATUS Status; + + OpenStatus = gBS->OpenProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + (VOID **) &UsbIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (OpenStatus) && (OpenStatus != EFI_ALREADY_STARTED)) { + return EFI_UNSUPPORTED; + } + + if (OpenStatus == EFI_ALREADY_STARTED) { + return EFI_ALREADY_STARTED; + } + + // + // Use the USB I/O protocol interface to see the Controller is + // the Mouse controller 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; +} + +EFI_STATUS +EFIAPI +USBMouseDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + Starting the Usb Bus Driver + + Arguments: + This - Protocol instance pointer. + Controller - Handle of device to test + RemainingDevicePath - Not used + + Returns: + EFI_SUCCESS - This driver supports this device. + EFI_UNSUPPORTED - This driver does not support this device. + EFI_DEVICE_ERROR - This driver cannot be started due to device + Error + EFI_OUT_OF_RESOURCES- Can't allocate memory resources + EFI_ALREADY_STARTED - Thios driver has been started +--*/ +{ + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDesc; + USB_MOUSE_DEV *UsbMouseDevice; + UINT8 EndpointNumber; + UINT8 Index; + UINT8 EndpointAddr; + UINT8 PollingInterval; + UINT8 PacketSize; + + UsbMouseDevice = NULL; + Status = EFI_SUCCESS; + + Status = gBS->OpenProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + (VOID **) &UsbIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + UsbMouseDevice = AllocateZeroPool (sizeof (USB_MOUSE_DEV)); + if (UsbMouseDevice == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + + UsbMouseDevice->UsbIo = UsbIo; + + UsbMouseDevice->Signature = USB_MOUSE_DEV_SIGNATURE; + + UsbMouseDevice->InterfaceDescriptor = AllocatePool (sizeof (EFI_USB_INTERFACE_DESCRIPTOR)); + if (UsbMouseDevice->InterfaceDescriptor == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + + EndpointDesc = AllocatePool (sizeof (EFI_USB_ENDPOINT_DESCRIPTOR)); + if (EndpointDesc == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + // + // 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; + } + // + // Get interface & endpoint descriptor + // + UsbIo->UsbGetInterfaceDescriptor ( + UsbIo, + UsbMouseDevice->InterfaceDescriptor + ); + + EndpointNumber = UsbMouseDevice->InterfaceDescriptor->NumEndpoints; + + for (Index = 0; Index < EndpointNumber; Index++) { + UsbIo->UsbGetEndpointDescriptor ( + UsbIo, + Index, + EndpointDesc + ); + + if ((EndpointDesc->Attributes & 0x03) == 0x03) { + + // + // We only care interrupt endpoint here + // + UsbMouseDevice->IntEndpointDescriptor = EndpointDesc; + } + } + + if (UsbMouseDevice->IntEndpointDescriptor == NULL) { + // + // No interrupt endpoint, then error + // + Status = EFI_UNSUPPORTED; + goto ErrorExit; + } + + Status = InitializeUsbMouseDevice (UsbMouseDevice); + if (EFI_ERROR (Status)) { + MouseReportStatusCode ( + UsbMouseDevice->DevicePath, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (EFI_PERIPHERAL_MOUSE | EFI_P_EC_INTERFACE_ERROR) + ); + + goto ErrorExit; + } + + UsbMouseDevice->SimplePointerProtocol.GetState = GetMouseState; + UsbMouseDevice->SimplePointerProtocol.Reset = UsbMouseReset; + UsbMouseDevice->SimplePointerProtocol.Mode = &UsbMouseDevice->Mode; + + Status = gBS->CreateEvent ( + EFI_EVENT_NOTIFY_WAIT, + EFI_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)) { + Status = EFI_DEVICE_ERROR; + goto ErrorExit; + } + + // + // After Enabling Async Interrupt Transfer on this mouse Device + // we will be able to get key data from it. Thus this is deemed as + // the enable action of the mouse + // + + MouseReportStatusCode ( + UsbMouseDevice->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_MOUSE | EFI_P_PC_ENABLE) + ); + + // + // submit async interrupt transfer + // + 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)) { + + UsbMouseDevice->ControllerNameTable = NULL; + AddUnicodeString ( + "eng", + gUsbMouseComponentName.SupportedLanguages, + &UsbMouseDevice->ControllerNameTable, + (CHAR16 *) L"Generic Usb Mouse" + ); + + return EFI_SUCCESS; + } + + // + // If submit error, uninstall that interface + // + Status = EFI_DEVICE_ERROR; + gBS->UninstallProtocolInterface ( + Controller, + &gEfiSimplePointerProtocolGuid, + &UsbMouseDevice->SimplePointerProtocol + ); + +ErrorExit: + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + if (UsbMouseDevice != NULL) { + if (UsbMouseDevice->InterfaceDescriptor != NULL) { + gBS->FreePool (UsbMouseDevice->InterfaceDescriptor); + } + + if (UsbMouseDevice->IntEndpointDescriptor != NULL) { + gBS->FreePool (UsbMouseDevice->IntEndpointDescriptor); + } + + if ((UsbMouseDevice->SimplePointerProtocol).WaitForInput != NULL) { + gBS->CloseEvent ((UsbMouseDevice->SimplePointerProtocol).WaitForInput); + } + + gBS->FreePool (UsbMouseDevice); + UsbMouseDevice = NULL; + } + } + + return Status; +} + +EFI_STATUS +EFIAPI +USBMouseDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + + Routine Description: + Stop this driver on ControllerHandle. Support stoping any child handles + created by this driver. + + Arguments: + This - Protocol instance pointer. + Controller - Handle of device to stop driver on + NumberOfChildren - Number of Children in the ChildHandleBuffer + ChildHandleBuffer - List of handles for the children we need to stop. + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + others + +--*/ +{ + EFI_STATUS Status; + USB_MOUSE_DEV *UsbMouseDevice; + EFI_SIMPLE_POINTER_PROTOCOL *SimplePointerProtocol; + EFI_USB_IO_PROTOCOL *UsbIo; + + // + // Get our context back. + // + 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); + + gBS->CloseProtocol ( + Controller, + &gEfiSimplePointerProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + UsbIo = UsbMouseDevice->UsbIo; + + // + // Uninstall the Asyn Interrupt Transfer from this device + // will disable the mouse data input from this device + // + MouseReportStatusCode ( + UsbMouseDevice->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_MOUSE | EFI_P_PC_DISABLE) + ); + + // + // Delete Mouse Async Interrupt Transfer + // + UsbIo->UsbAsyncInterruptTransfer ( + UsbIo, + UsbMouseDevice->IntEndpointDescriptor->EndpointAddress, + FALSE, + UsbMouseDevice->IntEndpointDescriptor->Interval, + 0, + NULL, + NULL + ); + + gBS->CloseEvent (UsbMouseDevice->SimplePointerProtocol.WaitForInput); + + if (UsbMouseDevice->DelayedRecoveryEvent) { + gBS->CloseEvent (UsbMouseDevice->DelayedRecoveryEvent); + UsbMouseDevice->DelayedRecoveryEvent = 0; + } + + Status = gBS->UninstallProtocolInterface ( + Controller, + &gEfiSimplePointerProtocolGuid, + &UsbMouseDevice->SimplePointerProtocol + ); + if (EFI_ERROR (Status)) { + return Status; + } + + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + gBS->FreePool (UsbMouseDevice->InterfaceDescriptor); + gBS->FreePool (UsbMouseDevice->IntEndpointDescriptor); + + if (UsbMouseDevice->ControllerNameTable) { + FreeUnicodeStringTable (UsbMouseDevice->ControllerNameTable); + } + + gBS->FreePool (UsbMouseDevice); + + return EFI_SUCCESS; + +} + +BOOLEAN +IsUsbMouse ( + IN EFI_USB_IO_PROTOCOL *UsbIo + ) +/*++ + + Routine Description: + Tell if a Usb Controller is a mouse + + Arguments: + UsbIo - Protocol instance pointer. + + Returns: + TRUE - It is a mouse + FALSE - It is not a mouse +--*/ +{ + EFI_STATUS Status; + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + + // + // Get the Default interface descriptor, now we only + // suppose it is interface 1 + // + 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; +} + +STATIC +EFI_STATUS +InitializeUsbMouseDevice ( + IN USB_MOUSE_DEV *UsbMouseDev + ) +/*++ + + Routine Description: + Initialize the Usb Mouse Device. + + Arguments: + UsbMouseDev - Device instance to be initialized + + Returns: + EFI_SUCCESS - Success + EFI_DEVICE_ERROR - Init error. + EFI_OUT_OF_RESOURCES- Can't allocate memory +--*/ +{ + EFI_USB_IO_PROTOCOL *UsbIo; + UINT8 Protocol; + EFI_STATUS Status; + EFI_USB_HID_DESCRIPTOR MouseHidDesc; + UINT8 *ReportDesc; + + UsbIo = UsbMouseDev->UsbIo; + + // + // Get HID descriptor + // + Status = UsbGetHidDescriptor ( + UsbIo, + UsbMouseDev->InterfaceDescriptor->InterfaceNumber, + &MouseHidDesc + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get Report descriptor + // + if (MouseHidDesc.HidClassDesc[0].DescriptorType != 0x22) { + return EFI_UNSUPPORTED; + } + + ReportDesc = AllocateZeroPool (MouseHidDesc.HidClassDesc[0].DescriptorLength); + if (ReportDesc == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = UsbGetReportDescriptor ( + UsbIo, + UsbMouseDev->InterfaceDescriptor->InterfaceNumber, + MouseHidDesc.HidClassDesc[0].DescriptorLength, + ReportDesc + ); + + if (EFI_ERROR (Status)) { + gBS->FreePool (ReportDesc); + return Status; + } + + // + // Parse report descriptor + // + Status = ParseMouseReportDescriptor ( + UsbMouseDev, + ReportDesc, + MouseHidDesc.HidClassDesc[0].DescriptorLength + ); + + if (EFI_ERROR (Status)) { + gBS->FreePool (ReportDesc); + return Status; + } + + 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; + // + // Here we just assume interface 0 is the mouse interface + // + UsbGetProtocolRequest ( + UsbIo, + 0, + &Protocol + ); + + if (Protocol != BOOT_PROTOCOL) { + Status = UsbSetProtocolRequest ( + UsbIo, + 0, + BOOT_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + gBS->FreePool (ReportDesc); + return EFI_DEVICE_ERROR; + } + } + + // + // Set indefinite Idle rate for USB Mouse + // + UsbSetIdleRequest ( + UsbIo, + 0, + 0, + 0 + ); + + gBS->FreePool (ReportDesc); + + if (UsbMouseDev->DelayedRecoveryEvent) { + gBS->CloseEvent (UsbMouseDev->DelayedRecoveryEvent); + UsbMouseDev->DelayedRecoveryEvent = 0; + } + + Status = gBS->CreateEvent ( + EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL, + EFI_TPL_NOTIFY, + USBMouseRecoveryHandler, + UsbMouseDev, + &UsbMouseDev->DelayedRecoveryEvent + ); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +OnMouseInterruptComplete ( + IN VOID *Data, + IN UINTN DataLength, + IN VOID *Context, + IN UINT32 Result + ) +/*++ + + Routine Description: + It is called whenever there is data received from async interrupt + transfer. + + Arguments: + Data - Data received. + DataLength - Length of Data + Context - Passed in context + Result - Async Interrupt Transfer result + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + +--*/ +{ + 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 + // + MouseReportStatusCode ( + UsbMouseDevice->DevicePath, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (EFI_PERIPHERAL_MOUSE | EFI_P_EC_INPUT_ERROR) + ); + + if ((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) { + EndpointAddr = UsbMouseDevice->IntEndpointDescriptor->EndpointAddress; + + UsbClearEndpointHalt ( + UsbIo, + EndpointAddr, + &UsbResult + ); + } + + UsbIo->UsbAsyncInterruptTransfer ( + UsbIo, + UsbMouseDevice->IntEndpointDescriptor->EndpointAddress, + FALSE, + 0, + 0, + NULL, + NULL + ); + + gBS->SetTimer ( + UsbMouseDevice->DelayedRecoveryEvent, + TimerRelative, + EFI_USB_INTERRUPT_DELAY + ); + return EFI_DEVICE_ERROR; + } + + if (DataLength == 0 || Data == NULL) { + return EFI_SUCCESS; + } + + UsbMouseDevice->StateChanged = TRUE; + + // + // Check mouse Data + // + UsbMouseDevice->State.LeftButton = (BOOLEAN) (*(UINT8 *) Data & 0x01); + UsbMouseDevice->State.RightButton = (BOOLEAN) (*(UINT8 *) Data & 0x02); + UsbMouseDevice->State.RelativeMovementX += *((INT8 *) Data + 1); + UsbMouseDevice->State.RelativeMovementY += *((INT8 *) Data + 2); + + if (DataLength > 3) { + UsbMouseDevice->State.RelativeMovementZ += *((INT8 *) Data + 3); + } + + return EFI_SUCCESS; +} + +/* +STATIC VOID +PrintMouseState( + IN EFI_MOUSE_STATE *MouseState + ) +{ + Aprint("(%x: %x, %x)\n", + MouseState->ButtonStates, + MouseState->dx, + MouseState->dy + ); +} +*/ +STATIC +EFI_STATUS +EFIAPI +GetMouseState ( + IN EFI_SIMPLE_POINTER_PROTOCOL *This, + OUT EFI_SIMPLE_POINTER_STATE *MouseState + ) +/*++ + + Routine Description: + Get the mouse state, see SIMPLE POINTER PROTOCOL. + + Arguments: + This - Protocol instance pointer. + MouseState - Current mouse state + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + EFI_NOT_READY + +--*/ +{ + USB_MOUSE_DEV *MouseDev; + + if (MouseState == NULL) { + return EFI_DEVICE_ERROR; + } + + MouseDev = USB_MOUSE_DEV_FROM_MOUSE_PROTOCOL (This); + + if (!MouseDev->StateChanged) { + return EFI_NOT_READY; + } + + 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; +} + +STATIC +EFI_STATUS +EFIAPI +UsbMouseReset ( + IN EFI_SIMPLE_POINTER_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + + Routine Description: + Reset the mouse device, see SIMPLE POINTER PROTOCOL. + + Arguments: + This - Protocol instance pointer. + ExtendedVerification - Ignored here/ + + Returns: + EFI_SUCCESS + +--*/ +{ + USB_MOUSE_DEV *UsbMouseDevice; + EFI_USB_IO_PROTOCOL *UsbIo; + + UsbMouseDevice = USB_MOUSE_DEV_FROM_MOUSE_PROTOCOL (This); + + UsbIo = UsbMouseDevice->UsbIo; + + MouseReportStatusCode ( + UsbMouseDevice->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_MOUSE | EFI_P_PC_RESET) + ); + + ZeroMem ( + &UsbMouseDevice->State, + sizeof (EFI_SIMPLE_POINTER_STATE) + ); + UsbMouseDevice->StateChanged = FALSE; + + return EFI_SUCCESS; +} + +STATIC +VOID +EFIAPI +UsbMouseWaitForInput ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + + Event notification function for SIMPLE_POINTER.WaitForInput event + Signal the event if there is input from mouse + +Arguments: + Event - Wait Event + Context - Passed parameter to event handler +Returns: + VOID +--*/ +{ + USB_MOUSE_DEV *UsbMouseDev; + + UsbMouseDev = (USB_MOUSE_DEV *) Context; + + // + // Someone is waiting on the mouse event, if there's + // input from mouse, signal the event + // + if (UsbMouseDev->StateChanged) { + gBS->SignalEvent (Event); + } +} + +VOID +EFIAPI +USBMouseRecoveryHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + + Routine Description: + Timer handler for Delayed Recovery timer. + + Arguments: + Event - The Delayed Recovery event. + Context - Points to the USB_KB_DEV instance. + + Returns: + +--*/ +{ + USB_MOUSE_DEV *UsbMouseDev; + EFI_USB_IO_PROTOCOL *UsbIo; + + UsbMouseDev = (USB_MOUSE_DEV *) Context; + + UsbIo = UsbMouseDev->UsbIo; + + UsbIo->UsbAsyncInterruptTransfer ( + UsbIo, + UsbMouseDev->IntEndpointDescriptor->EndpointAddress, + TRUE, + UsbMouseDev->IntEndpointDescriptor->Interval, + UsbMouseDev->IntEndpointDescriptor->MaxPacketSize, + OnMouseInterruptComplete, + UsbMouseDev + ); +} + +VOID +MouseReportStatusCode ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN EFI_STATUS_CODE_TYPE CodeType, + IN EFI_STATUS_CODE_VALUE Value + ) +/*++ + + Routine Description: + Report Status Code in Usb Bot Driver + + Arguments: + DevicePath - Use this to get Device Path + CodeType - Status Code Type + CodeValue - Status Code Value + + Returns: + None + +--*/ +{ + + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + CodeType, + Value, + DevicePath + ); +} diff --git a/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/usbmouse.h b/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/usbmouse.h new file mode 100644 index 0000000000..8a7dd753b1 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/usbmouse.h @@ -0,0 +1,85 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + Module Name: + + UsbMouse.h + + Abstract: + +--*/ + +#ifndef _USB_MOUSE_H +#define _USB_MOUSE_H + +#include + +#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 EFI_SIGNATURE_32 ('u', 'm', 'o', 'u') + +typedef struct { + BOOLEAN ButtonDetected; + UINT8 ButtonMinIndex; + UINT8 ButtonMaxIndex; + UINT8 Reserved; +} PRIVATE_DATA; + +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; + PRIVATE_DATA PrivateData; + EFI_UNICODE_STRING_TABLE *ControllerNameTable; +} USB_MOUSE_DEV; + +#define USB_MOUSE_DEV_FROM_MOUSE_PROTOCOL(a) \ + CR(a, USB_MOUSE_DEV, SimplePointerProtocol, USB_MOUSE_DEV_SIGNATURE) + +VOID +EFIAPI +USBMouseRecoveryHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +// +// Global Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gUsbMouseDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gUsbMouseComponentName; +extern EFI_GUID gEfiUsbMouseDriverGuid; + +VOID +MouseReportStatusCode ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN EFI_STATUS_CODE_TYPE CodeType, + IN EFI_STATUS_CODE_VALUE Value + ); + +#endif diff --git a/EdkModulePkg/Core/Dxe/DebugImageInfo.h b/EdkModulePkg/Core/Dxe/DebugImageInfo.h new file mode 100644 index 0000000000..be1d1f1908 --- /dev/null +++ b/EdkModulePkg/Core/Dxe/DebugImageInfo.h @@ -0,0 +1,126 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DebugImageInfo.h + +Abstract: + + Support functions for managing debug image info table when loading and unloading + images. + +--*/ + +#ifndef __DEBUG_IMAGE_INFO_H__ +#define __DEBUG_IMAGE_INFO_H__ + +#define FOUR_MEG_PAGES 0x400 +#define FOUR_MEG_MASK ((FOUR_MEG_PAGES * EFI_PAGE_SIZE) - 1) + +#define EFI_DEBUG_TABLE_ENTRY_SIZE (sizeof (VOID *)) + +VOID +CoreInitializeDebugImageInfoTable ( + VOID + ) +/*++ + +Routine Description: + + Creates and initializes the DebugImageInfo Table. Also creates the configuration + table and registers it into the system table. + +Arguments: + None + +Returns: + NA + +Notes: + 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 +CoreUpdateDebugTableCrc32 ( + VOID + ) +/*++ + +Routine Description: + + 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. + +Arguments: + None + +Returns: + NA + +--*/ +; + +VOID +CoreNewDebugImageInfoEntry ( + UINTN ImageInfoType, + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage, + EFI_HANDLE ImageHandle + ) +/*++ + +Routine Description: + + Adds a new DebugImageInfo structure to the DebugImageInfo Table. Re-Allocates + the table if it's not large enough to accomidate another entry. + +Arguments: + + ImageInfoType - type of debug image information + LoadedImage - pointer to the loaded image protocol for the image being loaded + ImageHandle - image handle for the image being loaded + +Returns: + NA + +--*/ +; + +VOID +CoreRemoveDebugImageInfoEntry ( + EFI_HANDLE ImageHandle + ) +/*++ + +Routine Description: + + Removes and frees an entry from the DebugImageInfo Table. + +Arguments: + + ImageHandle - image handle for the image being unloaded + +Returns: + + NA + +--*/ +; + +#endif diff --git a/EdkModulePkg/Core/Dxe/Dispatcher/Dispatcher.c b/EdkModulePkg/Core/Dxe/Dispatcher/Dispatcher.c new file mode 100644 index 0000000000..32ba23a957 --- /dev/null +++ b/EdkModulePkg/Core/Dxe/Dispatcher/Dispatcher.c @@ -0,0 +1,1159 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Dispatcher.c + +Abstract: + + Tiano 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. + +--*/ + +#include + +// +// 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 (EFI_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 +// +static EFI_FV_FILETYPE mDxeFileTypes[] = { + EFI_FV_FILETYPE_DRIVER, + 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 +// +VOID +CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter ( + IN EFI_CORE_DRIVER_ENTRY *InsertedDriverEntry + ); + +VOID +EFIAPI +CoreFwVolEventProtocolNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +EFI_DEVICE_PATH_PROTOCOL * +CoreFvToDevicePath ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *Fv, + IN EFI_HANDLE FvHandle, + IN EFI_GUID *DriverName + ); + +STATIC +EFI_STATUS +CoreAddToDriverList ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *Fv, + IN EFI_HANDLE FvHandle, + IN EFI_GUID *DriverName + ); + +STATIC +EFI_STATUS +CoreProcessFvImageFile ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *Fv, + IN EFI_HANDLE FvHandle, + IN EFI_GUID *DriverName + ); + + +VOID +CoreAcquireDispatcherLock ( + VOID + ) +/*++ + +Routine Description: + + Enter critical section by gaining lock on mDispatcherLock + +Arguments: + + None + +Returns: + + None + +--*/ + +{ + CoreAcquireLock (&mDispatcherLock); +} + +VOID +CoreReleaseDispatcherLock ( + VOID + ) +/*++ + +Routine Description: + + Exit critical section by releasing lock on mDispatcherLock + +Arguments: + + None + +Returns: + + None + +--*/ +{ + CoreReleaseLock (&mDispatcherLock); +} + + +EFI_STATUS +CoreGetDepexSectionAndPreProccess ( + IN EFI_CORE_DRIVER_ENTRY *DriverEntry + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + DriverEntry - Driver to work on. + +Returns: + + EFI_SUCCESS - Depex read and preprossesed + + EFI_PROTOCOL_ERROR - The section extraction protocol returned an error and + Depex reading needs to be retried. + + Other Error - DEPEX not found. + +--*/ +{ + EFI_STATUS Status; + EFI_SECTION_TYPE SectionType; + UINT32 AuthenticationStatus; + EFI_FIRMWARE_VOLUME_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 EFI 1.1 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; +} + +EFI_DXESERVICE +EFI_STATUS +EFIAPI +CoreSchedule ( + IN EFI_HANDLE FirmwareVolumeHandle, + IN EFI_GUID *DriverName + ) +/*++ + +Routine Description: + + Check every driver and locate a matching one. If the driver is found, the Unrequested + state flag is cleared. + +Arguments: + + FirmwareVolumeHandle - The handle of the Firmware Volume that contains the firmware + file specified by DriverName. + + DriverName - The Driver name to put in the Dependent state. + +Returns: + + EFI_SUCCESS - The DriverName was found and it's SOR bit was cleared + + EFI_NOT_FOUND - The DriverName does not exist or it's SOR bit was not set. + +--*/ +{ + 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 (); + + return EFI_SUCCESS; + } + } + return EFI_NOT_FOUND; +} + + +EFI_DXESERVICE +EFI_STATUS +EFIAPI +CoreTrust ( + IN EFI_HANDLE FirmwareVolumeHandle, + IN EFI_GUID *DriverName + ) +/*++ + +Routine Description: + + Convert a driver from the Untrused back to the Scheduled state + +Arguments: + + FirmwareVolumeHandle - The handle of the Firmware Volume that contains the firmware + file specified by DriverName. + + DriverName - The Driver name to put in the Scheduled state + +Returns: + + EFI_SUCCESS - The file was found in the untrusted state, and it was promoted + to the trusted state. + + EFI_NOT_FOUND - The file was not found in the untrusted state. + +--*/ +{ + 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; +} + + +EFI_DXESERVICE +EFI_STATUS +EFIAPI +CoreDispatcher ( + VOID + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + NONE + +Returns: + + EFI_ALREADY_STARTED - The DXE Dispatcher is already running + + EFI_NOT_FOUND - No DXE Drivers were dispatched + + EFI_SUCCESS - One or more DXE Drivers were dispatched + +--*/ +{ + EFI_STATUS Status; + EFI_STATUS ReturnStatus; + LIST_ENTRY *Link; + EFI_CORE_DRIVER_ENTRY *DriverEntry; + BOOLEAN ReadyToRun; + + if (gDispatcherRunning) { + // + // If the dispatcher is running don't let it be restarted. + // + return EFI_ALREADY_STARTED; + } + + gDispatcherRunning = TRUE; + + + 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) { + Status = CoreLoadImage ( + TRUE, + 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 (); + + + CoreReportProgressCodeSpecific (EFI_SOFTWARE_DXE_CORE | EFI_SW_PC_INIT_BEGIN, DriverEntry->ImageHandle); + Status = CoreStartImage (DriverEntry->ImageHandle, NULL, NULL); + CoreReportProgressCodeSpecific (EFI_SOFTWARE_DXE_CORE | EFI_SW_PC_INIT_END, DriverEntry->ImageHandle); + + ReturnStatus = EFI_SUCCESS; + } + + // + // 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; + } + } + } + } while (ReadyToRun); + + gDispatcherRunning = FALSE; + + return ReturnStatus; +} + + +VOID +CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter ( + IN EFI_CORE_DRIVER_ENTRY *InsertedDriverEntry + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + InsertedDriverEntry - The driver to insert on the ScheduledLink Queue + +Returns: + + NONE + +--*/ +{ + 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) { + if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) { + // + // Recursively process BEFORE + // + CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry); + } + } + } + + // + // 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) { + if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) { + // + // Recursively process AFTER + // + CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry); + } + } + } +} + + +BOOLEAN +FvHasBeenProcessed ( + IN EFI_HANDLE FvHandle + ) +/*++ + +Routine Description: + + Return TRUE if the Fv has been processed, FALSE if not. + +Arguments: + + FvHandle - The handle of a FV that's being tested + +Returns: + + TRUE - Fv protocol on FvHandle has been processed + + FALSE - Fv protocol on FvHandle has not yet been processed + +--*/ +{ + 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; +} + + +VOID +FvIsBeingProcesssed ( + IN EFI_HANDLE FvHandle + ) +/*++ + +Routine Description: + + Remember that Fv protocol on FvHandle has had it's drivers placed on the + mDiscoveredList. This fucntion adds entries on the mFvHandleList. Items are + never removed/freed from the mFvHandleList. + +Arguments: + + FvHandle - The handle of a FV that has been processed + +Returns: + + None + +--*/ +{ + KNOWN_HANDLE *KnownHandle; + + KnownHandle = CoreAllocateBootServicesPool (sizeof (KNOWN_HANDLE)); + ASSERT (KnownHandle != NULL); + + KnownHandle->Signature = KNOWN_HANDLE_SIGNATURE; + KnownHandle->Handle = FvHandle; + InsertTailList (&mFvHandleList, &KnownHandle->Link); +} + + + + +EFI_DEVICE_PATH_PROTOCOL * +CoreFvToDevicePath ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *Fv, + IN EFI_HANDLE FvHandle, + IN EFI_GUID *DriverName + ) +/*++ + +Routine Description: + + Convert FvHandle and DriverName into an EFI device path + +Arguments: + + Fv - Fv protocol, needed to read Depex info out of FLASH. + + 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. + + DriverName - Name of driver to add to mDiscoveredList. + +Returns: + + Pointer to device path constructed from FvHandle and 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); + mFvDevicePath.End.Type = EFI_END_ENTIRE_DEVICE_PATH; + mFvDevicePath.End.SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; + SetDevicePathNodeLength (&mFvDevicePath.End, sizeof (EFI_DEVICE_PATH_PROTOCOL)); + + FileNameDevicePath = CoreAppendDevicePath ( + FvDevicePath, + (EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath + ); + } + + return FileNameDevicePath; +} + + + +EFI_STATUS +CoreAddToDriverList ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *Fv, + IN EFI_HANDLE FvHandle, + IN EFI_GUID *DriverName + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + Fv - Fv protocol, needed to read Depex info out of FLASH. + + 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. + + DriverName - Name of driver to add to mDiscoveredList. + +Returns: + + EFI_SUCCESS - If driver was added to the mDiscoveredList. + + EFI_ALREADY_STARTED - The driver has already been started. Only one DriverName + may be active in the system at any one time. + +--*/ +{ + EFI_CORE_DRIVER_ENTRY *DriverEntry; + + + // + // Create the Driver Entry for the list. ZeroPool initializes lots of variables to + // NULL or FALSE. + // + DriverEntry = CoreAllocateZeroBootServicesPool (sizeof (EFI_CORE_DRIVER_ENTRY)); + ASSERT (DriverEntry != NULL); + + DriverEntry->Signature = EFI_CORE_DRIVER_ENTRY_SIGNATURE; + CopyMem (&DriverEntry->FileName, DriverName, sizeof (EFI_GUID)); + DriverEntry->FvHandle = FvHandle; + DriverEntry->Fv = Fv; + DriverEntry->FvFileDevicePath = CoreFvToDevicePath (Fv, FvHandle, DriverName); + + CoreGetDepexSectionAndPreProccess (DriverEntry); + + CoreAcquireDispatcherLock (); + + InsertTailList (&mDiscoveredList, &DriverEntry->Link); + + CoreReleaseDispatcherLock (); + + return EFI_SUCCESS; +} + + + +EFI_STATUS +CoreProcessFvImageFile ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *Fv, + IN EFI_HANDLE FvHandle, + IN EFI_GUID *DriverName + ) +/*++ + +Routine Description: + + Get the driver from the FV through driver name, and produce a FVB protocol on FvHandle. + +Arguments: + + Fv - The FIRMWARE_VOLUME protocol installed on the FV. + FvHandle - The handle which FVB protocol installed on. + DriverName - The driver guid specified. + +Returns: + + EFI_OUT_OF_RESOURCES - No enough memory or other resource. + + EFI_VOLUME_CORRUPTED - Corrupted volume. + + EFI_SUCCESS - Function successfully returned. + + +--*/ +{ + EFI_STATUS Status; + EFI_SECTION_TYPE SectionType; + UINT32 AuthenticationStatus; + VOID *Buffer; + UINTN BufferSize; + + // + // Read the first (and only the first) firmware volume section + // + SectionType = EFI_SECTION_FIRMWARE_VOLUME_IMAGE; + Buffer = NULL; + BufferSize = 0; + Status = Fv->ReadSection ( + Fv, + DriverName, + SectionType, + 0, + &Buffer, + &BufferSize, + &AuthenticationStatus + ); + if (!EFI_ERROR (Status)) { + // + // Produce a FVB protocol for the file + // + Status = ProduceFVBProtocolOnBuffer ( + (EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, + (UINT64)BufferSize, + FvHandle, + NULL + ); + } + + if (EFI_ERROR (Status) && (Buffer != NULL)) { + // + // ReadSection or Produce FVB failed, Free data buffer + // + CoreFreePool (Buffer); + + } + + return Status; +} + + +VOID +EFIAPI +CoreFwVolEventProtocolNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + Event - The Event that is being processed, not used. + + Context - Event Context, not used. + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + EFI_STATUS GetNextFileStatus; + EFI_STATUS SecurityStatus; + EFI_FIRMWARE_VOLUME_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; + + + 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; + } + + Status = CoreHandleProtocol (FvHandle, &gEfiFirmwareVolumeDispatchProtocolGuid, (VOID **)&Fv); + if (EFI_ERROR (Status)) { + // + // If no dispatch protocol then skip, but do not marked as being processed as it + // may show up later. + // + continue; + } + + // + // Since we are about to process this Fv mark it as processed. + // + FvIsBeingProcesssed (FvHandle); + + + Status = CoreHandleProtocol (FvHandle, &gEfiFirmwareVolumeProtocolGuid, (VOID **)&Fv); + if (EFI_ERROR (Status)) { + // + // The Handle has a FirmwareVolumeDispatch protocol and should also contiain + // a FirmwareVolume 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; + } + + // + // Evaluate the authentication status of the Firmware Volume through + // Security Architectural Protocol + // + if (gSecurity != NULL) { + SecurityStatus = gSecurity->FileAuthenticationState ( + gSecurity, + 0, + FvDevicePath + ); + if (SecurityStatus != EFI_SUCCESS) { + // + // Security check failed. The firmware volume should not be used for any purpose. + // + 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)) { + CopyGuid (&mFvDevicePath.File.NameGuid, &NameGuid); + + gDxeCoreLoadedImage->FilePath = CoreDuplicateDevicePath ( + (EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath + ); + gDxeCoreLoadedImage->DeviceHandle = FvHandle; + } + } + } else if (Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) { + // + // Found a firmware volume image. Produce a firmware volume block + // protocol for it so it gets dispatched from. This is usually a + // capsule. + // + CoreProcessFvImageFile (Fv, FvHandle, &NameGuid); + } else { + // + // Transition driver from Undiscovered to Discovered state + // + CoreAddToDriverList (Fv, FvHandle, &NameGuid); + } + } + } 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. + // + CoreAcquireDispatcherLock (); + + 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)) { + DriverEntry->Dependent = FALSE; + DriverEntry->Scheduled = TRUE; + InsertTailList (&mScheduledQueue, &DriverEntry->ScheduledLink); + break; + } + } + } + + CoreReleaseDispatcherLock (); + + // + // Free data allocated by Fv->ReadSection () + // + CoreFreePool (AprioriFile); + } +} + + +VOID +CoreInitializeDispatcher ( + VOID + ) +/*++ + +Routine Description: + + Initialize the dispatcher. Initialize the notification function that runs when + a FV protocol is added to the system. + +Arguments: + + NONE + +Returns: + + NONE + +--*/ +{ + mFwVolEvent = CoreCreateProtocolNotifyEvent ( + &gEfiFirmwareVolumeProtocolGuid, + EFI_TPL_CALLBACK, + CoreFwVolEventProtocolNotify, + NULL, + &mFwVolEventRegistration, + TRUE + ); +} + +// +// Function only used in debug buils +// +VOID +CoreDisplayDiscoveredNotDispatched ( + VOID + ) +/*++ + +Routine Description: + + Traverse the discovered list for any drivers that were discovered but not loaded + because the dependency experessions evaluated to false + +Arguments: + + NONE + +Returns: + + NONE + +--*/ +{ + 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 ((EFI_D_LOAD, "Driver %g was discovered but not loaded!!\n", &DriverEntry->FileName)); + } + } +} diff --git a/EdkModulePkg/Core/Dxe/Dispatcher/dependency.c b/EdkModulePkg/Core/Dxe/Dispatcher/dependency.c new file mode 100644 index 0000000000..e6dc3282e6 --- /dev/null +++ b/EdkModulePkg/Core/Dxe/Dispatcher/dependency.c @@ -0,0 +1,450 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + dependency.c + +Abstract: + + 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. + +--*/ + +#include + +// +// Global stack used to evaluate dependency expressions +// +BOOLEAN *mDepexEvaluationStack = NULL; +BOOLEAN *mDepexEvaluationStackEnd = NULL; +BOOLEAN *mDepexEvaluationStackPointer = NULL; + +// +// Worker functions +// + +STATIC +EFI_STATUS +GrowDepexStack ( + VOID + ) +/*++ + +Routine Description: + + Grow size of the Depex stack + +Arguments: + + Stack - Old stack on the way in and new stack on the way out + + StackSize - New size of the stack + +Returns: + + EFI_SUCCESS - Stack successfully growed. + + EFI_OUT_OF_RESOURCES - There is not enough system memory to grow the stack. + + + +--*/ +{ + BOOLEAN *NewStack; + UINTN Size; + + Size = DEPEX_STACK_SIZE_INCREMENT; + if (mDepexEvaluationStack != NULL) { + Size = Size + (mDepexEvaluationStackEnd - mDepexEvaluationStack); + } + + NewStack = CoreAllocateBootServicesPool (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 + // + CoreFreePool (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; +} + + +STATIC +EFI_STATUS +PushBool ( + IN BOOLEAN Value + ) +/*++ + +Routine Description: + + Push an element onto the Boolean Stack + +Arguments: + + Value - BOOLEAN to push. + +Returns: + + EFI_SUCCESS - The value was pushed onto the stack. + + EFI_OUT_OF_RESOURCES - There is not enough system memory to grow the stack. + +--*/ +{ + 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; +} + + +STATIC +EFI_STATUS +PopBool ( + OUT BOOLEAN *Value + ) +/*++ + +Routine Description: + + Pop an element from the Boolean stack. + +Arguments: + + Value - BOOLEAN to pop. + +Returns: + + EFI_SUCCESS - The value was popped onto the stack. + + EFI_ACCESS_DENIED - The pop operation underflowed the stack + +--*/ +{ + // + // 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; +} + + +EFI_STATUS +CorePreProcessDepex ( + IN EFI_CORE_DRIVER_ENTRY *DriverEntry + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + DriverEntry - DriverEntry element to update + +Returns: + + EFI_SUCCESS - It always works. + +--*/ +{ + 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; +} + + +BOOLEAN +CoreIsSchedulable ( + IN EFI_CORE_DRIVER_ENTRY *DriverEntry + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + DriverEntry - DriverEntry element to update + +Returns: + + TRUE - If driver is ready to run. + + FALSE - If driver is not ready to run or some fatal error was found. + +--*/ +{ + EFI_STATUS Status; + UINT8 *Iterator; + BOOLEAN Operator; + BOOLEAN Operator2; + EFI_GUID DriverGuid; + VOID *Interface; + + if (DriverEntry->After || DriverEntry->Before) { + // + // If Before or After Depex skip as CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter () + // processes them. + // + return FALSE; + } + + if (DriverEntry->Depex == NULL) { + // + // A NULL Depex means treat the driver like an EFI 1.0 thing. + // + Status = CoreAllEfiServicesAvailable (); + if (EFI_ERROR (Status)) { + return FALSE; + } + 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) { + 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. + // + 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) { + return FALSE; + } + // + // 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)) { + Status = PushBool (FALSE); + } else { + *Iterator = EFI_DEP_REPLACE_TRUE; + Status = PushBool (TRUE); + } + if (EFI_ERROR (Status)) { + return FALSE; + } + + Iterator += sizeof (EFI_GUID); + break; + + case EFI_DEP_AND: + Status = PopBool (&Operator); + if (EFI_ERROR (Status)) { + return FALSE; + } + + Status = PopBool (&Operator2); + if (EFI_ERROR (Status)) { + return FALSE; + } + + Status = PushBool ((BOOLEAN)(Operator && Operator2)); + if (EFI_ERROR (Status)) { + return FALSE; + } + break; + + case EFI_DEP_OR: + Status = PopBool (&Operator); + if (EFI_ERROR (Status)) { + return FALSE; + } + + Status = PopBool (&Operator2); + if (EFI_ERROR (Status)) { + return FALSE; + } + + Status = PushBool ((BOOLEAN)(Operator || Operator2)); + if (EFI_ERROR (Status)) { + return FALSE; + } + break; + + case EFI_DEP_NOT: + Status = PopBool (&Operator); + if (EFI_ERROR (Status)) { + return FALSE; + } + + Status = PushBool ((BOOLEAN)(!Operator)); + if (EFI_ERROR (Status)) { + return FALSE; + } + break; + + case EFI_DEP_TRUE: + Status = PushBool (TRUE); + if (EFI_ERROR (Status)) { + return FALSE; + } + break; + + case EFI_DEP_FALSE: + Status = PushBool (FALSE); + if (EFI_ERROR (Status)) { + return FALSE; + } + break; + + case EFI_DEP_END: + Status = PopBool (&Operator); + if (EFI_ERROR (Status)) { + return FALSE; + } + return Operator; + + case EFI_DEP_REPLACE_TRUE: + Status = PushBool (TRUE); + if (EFI_ERROR (Status)) { + return FALSE; + } + + Iterator += sizeof (EFI_GUID); + break; + + default: + return FALSE; + } + + // + // 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++; + } + return FALSE; +} + diff --git a/EdkModulePkg/Core/Dxe/DxeMain.h b/EdkModulePkg/Core/Dxe/DxeMain.h new file mode 100644 index 0000000000..9a9ba683e7 --- /dev/null +++ b/EdkModulePkg/Core/Dxe/DxeMain.h @@ -0,0 +1,2539 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DxeMain.h + +Abstract: + +Revision History + +--*/ + +#ifndef _DXE_MAIN_H_ +#define _DXE_MAIN_H_ + + +#include "DebugImageInfo.h" +#include "Library.h" +#include "FwVolBlock.h" +#include "FwVolDriver.h" +#include "gcd.h" +#include "imem.h" +#include "Image.h" +#include "Exec.h" +#include "hand.h" + +typedef struct { + EFI_GUID *ProtocolGuid; + VOID **Protocol; + EFI_EVENT Event; + VOID *Registration; + BOOLEAN Present; +} ARCHITECTURAL_PROTOCOL_ENTRY; + + +// +// DXE Dispatcher Data structures +// + +#define KNOWN_HANDLE_SIGNATURE EFI_SIGNATURE_32('k','n','o','w') +typedef struct { + UINTN Signature; + LIST_ENTRY Link; // mFvHandleList + EFI_HANDLE Handle; +} KNOWN_HANDLE; + + +#define EFI_CORE_DRIVER_ENTRY_SIGNATURE EFI_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_VOLUME_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; + +} EFI_CORE_DRIVER_ENTRY; + +// +//The data structure of GCD memory map entry +// +#define EFI_GCD_MAP_SIGNATURE EFI_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; + +// +// DXE Core Global Variables +// +extern EFI_SYSTEM_TABLE *gST; +extern EFI_BOOT_SERVICES *gBS; +extern EFI_RUNTIME_SERVICES *gRT; +extern EFI_DXE_SERVICES *gDS; +extern EFI_HANDLE gDxeCoreImageHandle; + +extern EFI_DECOMPRESS_PROTOCOL gEfiDecompress; +extern EFI_PEI_PE_COFF_LOADER_PROTOCOL *gEfiPeiPeCoffLoader; + +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_BDS_ARCH_PROTOCOL *gBds; +extern EFI_STATUS_CODE_PROTOCOL *gStatusCode; + +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; + +// +// Service Initialization Functions +// + + +VOID +CoreInitializePool ( + VOID + ) +/*++ + +Routine Description: + + Called to initialize the pool. + +Arguments: + + None + +Returns: + + None + +--*/ +; + +VOID +CoreAddMemoryDescriptor ( + IN EFI_MEMORY_TYPE Type, + IN EFI_PHYSICAL_ADDRESS Start, + IN UINT64 NumberOfPages, + IN UINT64 Attribute + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + Type - The type of memory to add + + Start - The starting address in the memory range + Must be page aligned + + NumberOfPages - The number of pages in the range + + Attribute - Attributes of the memory to add + +Returns: + + None. The range is added to the memory map + +--*/ +; + +VOID +CoreReleaseGcdMemoryLock ( + VOID + ) +/*++ + +Routine Description: + Release memory lock on mGcdMemorySpaceLock + +Arguments: + None + +Returns: + None + +--*/ +; + +VOID +CoreAcquireGcdMemoryLock ( + VOID + ) +/*++ + +Routine Description: + Acquire memory lock on mGcdMemorySpaceLock + +Arguments: + None + +Returns: + None + +--*/ +; + +EFI_STATUS +CoreInitializeMemoryServices ( + IN VOID **HobStart, + IN EFI_PHYSICAL_ADDRESS *MemoryBaseAddress, + IN UINT64 *MemoryLength + ) +/*++ + +Routine Description: + + 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 first + part of this function can not depend on any memory services until at least one + memory descriptor is provided to the memory services. Then the memory services + can be used to intialize the GCD map. + +Arguments: + + HobStart - The start address of the HOB. + + MemoryBaseAddress - Start address of memory region found to init DXE core. + + MemoryLength - Length of memory region found to init DXE core. + +Returns: + + EFI_SUCCESS - Memory services successfully initialized. + +--*/ +; + + +EFI_STATUS +CoreInitializeGcdServices ( + IN VOID **HobStart, + IN EFI_PHYSICAL_ADDRESS MemoryBaseAddress, + IN UINT64 MemoryLength + ) +/*++ + +Routine Description: + + 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 first + part of this function can not depend on any memory services until at least one + memory descriptor is provided to the memory services. Then the memory services + can be used to intialize the GCD map. + +Arguments: + + HobStart - The start address of the HOB + + MemoryBaseAddress - Start address of memory region found to init DXE core. + + MemoryLength - Length of memory region found to init DXE core. + + +Returns: + + EFI_SUCCESS - GCD services successfully initialized. + +--*/ +; + +EFI_STATUS +CoreInitializeEventServices ( + VOID + ) +/*++ + +Routine Description: + + Initializes "event" support and populates parts of the System and Runtime Table. + +Arguments: + + None + +Returns: + + EFI_SUCCESS - Always return success + +--*/ +; + +EFI_STATUS +CoreShutdownEventServices ( + VOID + ) +/*++ + +Routine Description: + + Register all runtime events to make sure they are still available after ExitBootService. + +Arguments: + + None + +Returns: + + EFI_SUCCESS - Always return success + +--*/ +; + +EFI_STATUS +CoreInitializeImageServices ( + IN VOID *HobStart + ) +/*++ + +Routine Description: + + Add the Image Services to EFI Boot Services Table and install the protocol + interfaces for this image. + +Arguments: + + HobStart - The HOB to initialize + +Returns: + + Status code. + +--*/ +; + +EFI_STATUS +CoreShutdownImageServices ( + VOID + ) +/*++ + +Routine Description: + + Transfer control of runtime images to runtime service + +Arguments: + + None + +Returns: + + EFI_SUCCESS - Function successfully returned + +--*/ +; + +VOID +CoreNotifyOnArchProtocolInstallation ( + VOID + ) +/*++ + +Routine Description: + Creates an event that is fired everytime a Protocol of a specific type is installed + +Arguments: + NONE + +Returns: + NONE + +--*/ +; + +EFI_STATUS +CoreAllEfiServicesAvailable ( + VOID + ) +/*++ + +Routine Description: + Return TRUE if all AP services are availible. + +Arguments: + NONE + +Returns: + EFI_SUCCESS - All AP services are available + EFI_NOT_FOUND - At least one AP service is not available + +--*/ +; + +VOID +CalculateEfiHdrCrc ( + IN OUT EFI_TABLE_HEADER *Hdr + ) +/*++ + +Routine Description: + + Calcualte the 32-bit CRC in a EFI table using the service provided by the + gRuntime service. + +Arguments: + + Hdr - Pointer to an EFI standard header + +Returns: + + None + +--*/ +; + +VOID +EFIAPI +CoreTimerTick ( + IN UINT64 Duration + ) +/*++ + +Routine Description: + + Called by the platform code to process a tick. + +Arguments: + + Duration - The number of 100ns elasped since the last call to TimerTick + +Returns: + + None + +--*/ +; + +VOID +CoreInitializeDispatcher ( + VOID + ) +/*++ + +Routine Description: + + Initialize the dispatcher. Initialize the notification function that runs when + a FV protocol is added to the system. + +Arguments: + + NONE + +Returns: + + NONE + +--*/ +; + +BOOLEAN +CoreIsSchedulable ( + IN EFI_CORE_DRIVER_ENTRY *DriverEntry + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + DriverEntry - DriverEntry element to update + +Returns: + + TRUE - If driver is ready to run. + + FALSE - If driver is not ready to run or some fatal error was found. + +--*/ +; + +EFI_STATUS +CorePreProcessDepex ( + IN EFI_CORE_DRIVER_ENTRY *DriverEntry + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + DriverEntry - DriverEntry element to update + +Returns: + + EFI_SUCCESS - It always works. + +--*/ +; + + +EFI_STATUS +EFIAPI +CoreExitBootServices ( + IN EFI_HANDLE ImageHandle, + IN UINTN MapKey + ) +/*++ + +Routine Description: + + EFI 1.0 API to terminate Boot Services + +Arguments: + + ImageHandle - Handle that represents the identity of the calling image + + MapKey -Key to the latest memory map. + +Returns: + + EFI_SUCCESS - Boot Services terminated + EFI_INVALID_PARAMETER - MapKey is incorrect. + +--*/ +; + +EFI_STATUS +CoreTerminateMemoryMap ( + IN UINTN MapKey + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + MapKey - Memory map key + +Returns: + + EFI_INVALID_PARAMETER - Memory map not consistent with construction rules. + + EFI_SUCCESS - Valid memory map. + +--*/ +; + +VOID +CoreNotifySignalList ( + IN EFI_GUID *EventGroup + ) +/*++ + +Routine Description: + + Signals all events on the requested list + +Arguments: + + SignalType - The list to signal + +Returns: + + None + +--*/ +; + + +EFI_STATUS +EFIAPI +CoreInstallConfigurationTable ( + IN EFI_GUID *Guid, + IN VOID *Table + ) +/*++ + +Routine Description: + + Boot Service called to add, modify, or remove a system configuration table from + the EFI System Table. + +Arguments: + + Guid: Pointer to the GUID for the entry to add, update, or remove + Table: Pointer to the configuration table for the entry to add, update, or + remove, may be NULL. + +Returns: + + EFI_SUCCESS Guid, Table pair added, updated, or removed. + EFI_INVALID_PARAMETER Input GUID not valid. + EFI_NOT_FOUND Attempted to delete non-existant entry + EFI_OUT_OF_RESOURCES Not enough memory available + +--*/ +; + + +EFI_TPL +EFIAPI +CoreRaiseTpl ( + IN EFI_TPL NewTpl + ) +/*++ + +Routine Description: + + Raise the task priority level to the new level. + High level is implemented by disabling processor interrupts. + +Arguments: + + NewTpl - New task priority level + +Returns: + + The previous task priority level + +--*/ +; + + +VOID +EFIAPI +CoreRestoreTpl ( + IN EFI_TPL NewTpl + ) +/*++ + +Routine Description: + + Lowers the task priority to the previous value. If the new + priority unmasks events at a higher priority, they are dispatched. + +Arguments: + + NewTpl - New, lower, task priority + +Returns: + + None + +--*/ +; + + +EFI_STATUS +EFIAPI +CoreStall ( + IN UINTN Microseconds + ) +/*++ + +Routine Description: + + Introduces a fine-grained stall. + +Arguments: + + Microseconds The number of microseconds to stall execution + +Returns: + + EFI_SUCCESS - Execution was stalled for at least the requested amount + of microseconds. + + EFI_NOT_AVAILABLE_YET - gMetronome is not available yet + +--*/ +; + + +EFI_STATUS +EFIAPI +CoreSetWatchdogTimer ( + IN UINTN Timeout, + IN UINT64 WatchdogCode, + IN UINTN DataSize, + IN CHAR16 *WatchdogData OPTIONAL + ) +/*++ + +Routine Description: + + Sets the system's watchdog timer. + +Arguments: + + Timeout The number of seconds. Zero disables the timer. + + ///////following three parameters are left for platform specific using + + WatchdogCode The numberic code to log. 0x0 to 0xffff are firmware + DataSize Size of the optional data + WatchdogData Optional Null terminated unicode string followed by binary + data. + +Returns: + + EFI_SUCCESS Timeout has been set + EFI_NOT_AVAILABLE_YET WatchdogTimer is not available yet + EFI_UNSUPPORTED System does not have a timer (currently not used) + EFI_DEVICE_ERROR Could not complete due to hardware error + +--*/ +; + + +EFI_STATUS +EFIAPI +CoreInstallProtocolInterface ( + IN OUT EFI_HANDLE *UserHandle, + IN EFI_GUID *Protocol, + IN EFI_INTERFACE_TYPE InterfaceType, + IN VOID *Interface + ) +/*++ + +Routine Description: + + Wrapper function to CoreInstallProtocolInterfaceNotify. This is the public API which + Calls the private one which contains a BOOLEAN parameter for notifications + +Arguments: + + UserHandle - The handle to install the protocol handler on, + or NULL if a new handle is to be allocated + + Protocol - The protocol to add to the handle + + InterfaceType - Indicates whether Interface is supplied in native form. + + Interface - The interface for the protocol being added + +Returns: + + Status code + +--*/ +; + +EFI_STATUS +CoreInstallProtocolInterfaceNotify ( + IN OUT EFI_HANDLE *UserHandle, + IN EFI_GUID *Protocol, + IN EFI_INTERFACE_TYPE InterfaceType, + IN VOID *Interface, + IN BOOLEAN Notify + ) +/*++ + +Routine Description: + + Installs a protocol interface into the boot services environment. + +Arguments: + + UserHandle - The handle to install the protocol handler on, + or NULL if a new handle is to be allocated + + Protocol - The protocol to add to the handle + + InterfaceType - Indicates whether Interface is supplied in native form. + + Interface - The interface for the protocol being added + + Notify - Whether to notify the notification list for this protocol + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_OUT_OF_RESOURCES - No enough buffer to allocate + + EFI_SUCCESS - Protocol interface successfully installed + +--*/ +; + + +EFI_STATUS +EFIAPI +CoreInstallMultipleProtocolInterfaces ( + IN OUT EFI_HANDLE *Handle, + ... + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + Handle - The handle to install the protocol handlers on, + or NULL if a new handle is to be allocated + ... - 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. + +Returns: + + EFI_INVALID_PARAMETER - Handle is NULL. + + EFI_SUCCESS - Protocol interfaces successfully installed. + +--*/ +; + + +EFI_STATUS +EFIAPI +CoreUninstallMultipleProtocolInterfaces ( + IN EFI_HANDLE Handle, + ... + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + Handle - The handle to uninstall the protocol + + ... - 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. + +Returns: + + Status code + +--*/ +; + + +EFI_STATUS +EFIAPI +CoreReinstallProtocolInterface ( + IN EFI_HANDLE UserHandle, + IN EFI_GUID *Protocol, + IN VOID *OldInterface, + IN VOID *NewInterface + ) +/*++ + +Routine Description: + + Reinstall a protocol interface on a device handle. The OldInterface for Protocol is replaced by the NewInterface. + +Arguments: + + UserHandle - Handle on which the interface is to be reinstalled + Protocol - The numeric ID of the interface + OldInterface - A pointer to the old interface + NewInterface - A pointer to the new interface + + +Returns: + + Status code. + + On EFI_SUCCESS The protocol interface was installed + On EFI_NOT_FOUND The OldInterface on the handle was not found + On EFI_INVALID_PARAMETER One of the parameters has an invalid value + +--*/ +; + + +EFI_STATUS +EFIAPI +CoreUninstallProtocolInterface ( + IN EFI_HANDLE UserHandle, + IN EFI_GUID *Protocol, + IN VOID *Interface + ) +/*++ + +Routine Description: + + Uninstalls all instances of a protocol:interfacer from a handle. + If the last protocol interface is remove from the handle, the + handle is freed. + +Arguments: + + UserHandle - The handle to remove the protocol handler from + + Protocol - The protocol, of protocol:interface, to remove + + Interface - The interface, of protocol:interface, to remove + +Returns: + + EFI_INVALID_PARAMETER - Protocol is NULL. + + EFI_SUCCESS - Protocol interface successfully uninstalled. + +--*/ +; + + +EFI_STATUS +EFIAPI +CoreHandleProtocol ( + IN EFI_HANDLE UserHandle, + IN EFI_GUID *Protocol, + OUT VOID **Interface + ) +/*++ + +Routine Description: + + Queries a handle to determine if it supports a specified protocol. + +Arguments: + + UserHandle - The handle being queried. + + Protocol - The published unique identifier of the protocol. + + Interface - Supplies the address where a pointer to the corresponding Protocol + Interface is returned. + +Returns: + + The requested protocol interface for the handle + +--*/ +; + + +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 + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + UserHandle - The handle to obtain the protocol interface on + + Protocol - The ID of the protocol + + Interface - The location to return the protocol interface + + ImageHandle - The handle of the Image that is opening the protocol interface + specified by Protocol and Interface. + + ControllerHandle - The controller handle that is requiring this interface. + + Attributes - The open mode of the protocol interface specified by Handle + and Protocol. + +Returns: + + EFI_INVALID_PARAMETER - Protocol is NULL. + + EFI_SUCCESS - Get the protocol interface. + +--*/ +; + + +EFI_STATUS +EFIAPI +CoreOpenProtocolInformation ( + IN EFI_HANDLE UserHandle, + IN EFI_GUID *Protocol, + OUT EFI_OPEN_PROTOCOL_INFORMATION_ENTRY **EntryBuffer, + OUT UINTN *EntryCount + ) +/*++ + +Routine Description: + + Return information about Opened protocols in the system + +Arguments: + + UserHandle - The handle to close the protocol interface on + + Protocol - The ID of the protocol + + EntryBuffer - A pointer to a buffer of open protocol information in the form of + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY structures. + + EntryCount - Number of EntryBuffer entries + +Returns: + + +--*/ +; + + +EFI_STATUS +EFIAPI +CoreCloseProtocol ( + IN EFI_HANDLE UserHandle, + IN EFI_GUID *Protocol, + IN EFI_HANDLE ImageHandle, + IN EFI_HANDLE ControllerHandle + ) +/*++ + +Routine Description: + + Close Protocol + +Arguments: + + UserHandle - The handle to close the protocol interface on + + Protocol - The ID of the protocol + + ImageHandle - The user of the protocol to close + + ControllerHandle - The user of the protocol to close + +Returns: + + EFI_INVALID_PARAMETER - Protocol is NULL. + +--*/ +; + + +EFI_STATUS +EFIAPI +CoreProtocolsPerHandle ( + IN EFI_HANDLE UserHandle, + OUT EFI_GUID ***ProtocolBuffer, + OUT UINTN *ProtocolBufferCount + ) +/*++ + +Routine Description: + + Retrieves the list of protocol interface GUIDs that are installed on a handle in a buffer allocated + from pool. + +Arguments: + + UserHandle - The handle from which to retrieve the list of protocol interface + GUIDs. + + ProtocolBuffer - A pointer to the list of protocol interface GUID pointers that are + installed on Handle. + + ProtocolBufferCount - A pointer to the number of GUID pointers present in + ProtocolBuffer. + +Returns: + 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. + EFI_INVALID_PARAMETER - Handle is NULL. + EFI_INVALID_PARAMETER - Handle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ProtocolBuffer is NULL. + EFI_INVALID_PARAMETER - ProtocolBufferCount is NULL. + EFI_OUT_OF_RESOURCES - There is not enough pool memory to store the results. + +--*/ +; + + +EFI_STATUS +EFIAPI +CoreRegisterProtocolNotify ( + IN EFI_GUID *Protocol, + IN EFI_EVENT Event, + OUT VOID **Registration + ) +/*++ + +Routine Description: + + Add a new protocol notification record for the request protocol. + +Arguments: + + Protocol - The requested protocol to add the notify registration + + Event - The event to signal + + Registration - Returns the registration record + + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_SUCCESS - Successfully returned the registration record that has been added + +--*/ +; + + +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 + ) +/*++ + +Routine Description: + + Locates the requested handle(s) and returns them in Buffer. + +Arguments: + + SearchType - The type of search to perform to locate the handles + + Protocol - The protocol to search for + + SearchKey - Dependant on SearchType + + BufferSize - On input the size of Buffer. On output the + size of data returned. + + Buffer - The buffer to return the results in + + +Returns: + + EFI_BUFFER_TOO_SMALL - Buffer too small, required buffer size is returned in BufferSize. + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_SUCCESS - Successfully found the requested handle(s) and returns them in Buffer. + +--*/ +; + + +EFI_STATUS +EFIAPI +CoreLocateDevicePath ( + IN EFI_GUID *Protocol, + IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath, + OUT EFI_HANDLE *Device + ) +/*++ + +Routine Description: + + Locates the handle to a device on the device path that supports the specified protocol. + +Arguments: + + Protocol - The protocol to search for. + FilePath - 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. + Device - A pointer to the returned device handle. + +Returns: + + EFI_SUCCESS - The resulting handle was returned. + EFI_NOT_FOUND - No handles matched the search. + EFI_INVALID_PARAMETER - One of the parameters has an invalid value. + +--*/ +; + + +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 + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + SearchType - Specifies which handle(s) are to be returned. + Protocol - Provides the protocol to search by. + This parameter is only valid for SearchType ByProtocol. + SearchKey - Supplies the search key depending on the SearchType. + NumberHandles - The number of handles returned in Buffer. + Buffer - A pointer to the buffer to return the requested array of + handles that support Protocol. + +Returns: + + EFI_SUCCESS - The result array of handles was returned. + EFI_NOT_FOUND - No handles match the search. + EFI_OUT_OF_RESOURCES - There is not enough pool memory to store the matching results. + EFI_INVALID_PARAMETER - Invalid parameter + +--*/ +; + + +EFI_STATUS +EFIAPI +CoreLocateProtocol ( + IN EFI_GUID *Protocol, + IN VOID *Registration OPTIONAL, + OUT VOID **Interface + ) +/*++ + +Routine Description: + + 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 Retistration is NULL return the first Protocol Interface + you find. + +Arguments: + + Protocol - The protocol to search for + + Registration - Optional Registration Key returned from RegisterProtocolNotify() + + Interface - Return the Protocol interface (instance). + +Returns: + + EFI_SUCCESS - If a valid Interface is returned + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_NOT_FOUND - Protocol interface not found + +--*/ +; + +UINT64 +CoreGetHandleDatabaseKey ( + VOID + ) +/*++ + +Routine Description: + + return handle database key. + +Arguments: + + None + +Returns: + + Handle database key. + +--*/ +; + +VOID +CoreConnectHandlesByKey ( + UINT64 Key + ) +/*++ + +Routine Description: + + Go connect any handles that were created or modified while a image executed. + +Arguments: + + Key - The Key to show that the handle has been created/modified + +Returns: + + None +--*/ +; + + +EFI_STATUS +EFIAPI +CoreConnectController ( + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE *DriverImageHandle OPTIONAL, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL, + IN BOOLEAN Recursive + ) +/*++ + +Routine Description: + + Connects one or more drivers to a controller. + +Arguments: + + ControllerHandle - Handle of the controller to be connected. + + DriverImageHandle - DriverImageHandle A pointer to an ordered list of driver image handles. + + RemainingDevicePath - RemainingDevicePath A pointer to the device path that specifies a child of the + controller specified by ControllerHandle. + + Recursive - - Whether the function would be called recursively or not. + +Returns: + + Status code. + +--*/ +; + + +EFI_STATUS +EFIAPI +CoreDisconnectController ( + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE DriverImageHandle OPTIONAL, + IN EFI_HANDLE ChildHandle OPTIONAL + ) +/*++ + +Routine Description: + + Disonnects a controller from a driver + +Arguments: + + ControllerHandle - ControllerHandle The handle of the controller from which driver(s) + are to be disconnected. + DriverImageHandle - DriverImageHandle The driver to disconnect from ControllerHandle. + ChildHandle - ChildHandle The handle of the child to destroy. + +Returns: + + EFI_SUCCESS - One or more drivers were disconnected from the controller. + EFI_SUCCESS - On entry, no drivers are managing ControllerHandle. + EFI_SUCCESS - DriverImageHandle is not NULL, and on entry DriverImageHandle is not managing ControllerHandle. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - DriverImageHandle is not NULL, and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL, and it is not a valid EFI_HANDLE. + EFI_OUT_OF_RESOURCES - There are not enough resources available to disconnect any drivers from ControllerHandle. + EFI_DEVICE_ERROR - The controller could not be disconnected because of a device error. + +--*/ +; + + +EFI_STATUS +EFIAPI +CoreAllocatePages ( + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN NumberOfPages, + IN OUT EFI_PHYSICAL_ADDRESS *Memory + ) +/*++ + +Routine Description: + + Allocates pages from the memory map. + +Arguments: + + Type - The type of allocation to perform + + MemoryType - The type of memory to turn the allocated pages into + + NumberOfPages - The number of pages to allocate + + Memory - A pointer to receive the base allocated memory address + +Returns: + + Status. On success, Memory is filled in with the base address allocated + + EFI_INVALID_PARAMETER - Parameters violate checking rules defined in spec. + + EFI_NOT_FOUND - Could not allocate pages match the requirement. + + EFI_OUT_OF_RESOURCES - No enough pages to allocate. + + EFI_SUCCESS - Pages successfully allocated. + +--*/ +; + + +EFI_STATUS +EFIAPI +CoreFreePages ( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN NumberOfPages + ) +/*++ + +Routine Description: + + Frees previous allocated pages. + +Arguments: + + Memory - Base address of memory being freed + + NumberOfPages - The number of pages to free + +Returns: + + EFI_NOT_FOUND - Could not find the entry that covers the range + + EFI_INVALID_PARAMETER - Address not aligned + + EFI_SUCCESS -Pages successfully freed. + +--*/ +; + + +EFI_STATUS +EFIAPI +CoreGetMemoryMap ( + IN OUT UINTN *MemoryMapSize, + IN OUT EFI_MEMORY_DESCRIPTOR *Desc, + OUT UINTN *MapKey, + OUT UINTN *DescriptorSize, + OUT UINT32 *DescriptorVersion + ) +/*++ + +Routine Description: + + Returns the current memory map. + +Arguments: + + MemoryMapSize - On input the buffer size of MemoryMap allocated by caller + On output the required buffer size to contain the memory map + + Desc - The buffer to return the current memory map + + MapKey - The address to return the current map key + + DescriptorSize - The size in bytes for an individual EFI_MEMORY_DESCRIPTOR + + DescriptorVersion - The version number associated with the EFI_MEMORY_DESCRIPTOR + +Returns: + + EFI_SUCCESS The current memory map was returned successfully + + EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small + + EFI_INVALID_PARAMETER One of the parameters has an invalid value + +--*/ +; + + +EFI_STATUS +EFIAPI +CoreAllocatePool ( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN Size, + OUT VOID **Buffer + ) +/*++ + +Routine Description: + + Allocate pool of a particular type. + +Arguments: + + PoolType - Type of pool to allocate + + Size - The amount of pool to allocate + + Buffer - The address to return a pointer to the allocated pool + +Returns: + + EFI_INVALID_PARAMETER - PoolType not valid + + EFI_OUT_OF_RESOURCES - Size exceeds max pool size or allocation failed. + + EFI_SUCCESS - Pool successfully allocated. + +--*/ +; + + +EFI_STATUS +EFIAPI +CoreFreePool ( + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Frees pool. + +Arguments: + + Buffer - The allocated pool entry to free + +Returns: + + EFI_INVALID_PARAMETER - Buffer is not a valid value. + + EFI_SUCCESS - Pool successfully freed. + +--*/ +; + + +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 + ) +/*++ + +Routine Description: + + Loads an EFI image into memory and returns a handle to the image. + +Arguments: + + 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. + ParentImageHandle - The caller's image handle. + FilePath - The specific file path from which the image is loaded. + SourceBuffer - If not NULL, a pointer to the memory location containing a copy of + the image to be loaded. + SourceSize - The size in bytes of SourceBuffer. + ImageHandle - Pointer to the returned image handle that is created when the image + is successfully loaded. + +Returns: + + EFI_SUCCESS - The image was loaded into memory. + EFI_NOT_FOUND - The FilePath was not found. + EFI_INVALID_PARAMETER - One of the parameters has an invalid value. + EFI_UNSUPPORTED - The image type is not supported, or the device path cannot be + parsed to locate the proper protocol for loading the file. + EFI_OUT_OF_RESOURCES - Image was not loaded due to insufficient resources. +--*/ +; + + +EFI_STATUS +EFIAPI +CoreUnloadImage ( + IN EFI_HANDLE ImageHandle + ) +/*++ + +Routine Description: + + Unload the specified image. + +Arguments: + + ImageHandle - The specified image handle. + +Returns: + + EFI_INVALID_PARAMETER - Image handle is NULL. + + EFI_UNSUPPORTED - Attempt to unload an unsupported image. + + EFI_SUCCESS - Image successfully unloaded. + +--*/ +; + + +EFI_STATUS +EFIAPI +CoreStartImage ( + IN EFI_HANDLE ImageHandle, + OUT UINTN *ExitDataSize, + OUT CHAR16 **ExitData OPTIONAL + ) +/*++ + +Routine Description: + + Transfer control to a loaded image's entry point. + +Arguments: + + ImageHandle - Handle of image to be started. + + ExitDataSize - Pointer of the size to ExitData + + ExitData - Pointer to a 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. + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_OUT_OF_RESOURCES - No enough buffer to allocate + + EFI_SUCCESS - Successfully transfer control to the image's entry point. + +--*/ +; + + +EFI_STATUS +EFIAPI +CoreExit ( + IN EFI_HANDLE ImageHandle, + IN EFI_STATUS Status, + IN UINTN ExitDataSize, + IN CHAR16 *ExitData OPTIONAL + ) +/*++ + +Routine Description: + + Terminates the currently loaded EFI image and returns control to boot services. + +Arguments: + + ImageHandle - Handle that identifies the image. This parameter is passed to the image + on entry. + Status - The image¡¯s exit code. + ExitDataSize - The size, in bytes, of ExitData. Ignored if ExitStatus is + EFI_SUCCESS. + 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. + +Returns: + + EFI_INVALID_PARAMETER - Image handle is NULL or it is not current image. + + EFI_SUCCESS - Successfully terminates the currently loaded EFI image. + + EFI_ACCESS_DENIED - Should never reach there. + +--*/ +; + + +EFI_STATUS +EFIAPI +CoreCreateEvent ( + IN UINT32 Type, + IN EFI_TPL NotifyTpl, + IN EFI_EVENT_NOTIFY NotifyFunction, + IN VOID *NotifyContext, + OUT EFI_EVENT *pEvent + ) +/*++ + +Routine Description: + + Creates a general-purpose event structure + +Arguments: + + Type - The type of event to create and its mode and attributes + NotifyTpl - The task priority level of event notifications + NotifyFunction - Pointer to the event’s notification function + NotifyContext - Pointer to the notification function’s context; corresponds to + parameter "Context" in the notification function + pEvent - Pointer to the newly created event if the call succeeds; undefined otherwise + +Returns: + + EFI_SUCCESS - The event structure was created + EFI_INVALID_PARAMETER - One of the parameters has an invalid value + 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 + ) +/*++ + +Routine Description: + Creates a general-purpose event structure + +Arguments: + Type - The type of event to create and its mode and attributes + NotifyTpl - The task priority level of event notifications + NotifyFunction - Pointer to the events notification function + NotifyContext - Pointer to the notification functions context; corresponds to + parameter "Context" in the notification function + EventGrout - GUID for EventGroup if NULL act the same as gBS->CreateEvent(). + Event - Pointer to the newly created event if the call succeeds; undefined otherwise + +Returns: + EFI_SUCCESS - The event structure was created + EFI_INVALID_PARAMETER - One of the parameters has an invalid value + EFI_OUT_OF_RESOURCES - The event could not be allocated + +--*/ +; + + +EFI_STATUS +EFIAPI +CoreSetTimer ( + IN EFI_EVENT Event, + IN EFI_TIMER_DELAY Type, + IN UINT64 TriggerTime + ) +/*++ + +Routine Description: + + Sets the type of timer and the trigger time for a timer event. + +Arguments: + + UserEvent - The timer event that is to be signaled at the specified time + Type - The type of time that is specified in TriggerTime + TriggerTime - The number of 100ns units until the timer expires + +Returns: + + EFI_SUCCESS - The event has been set to be signaled at the requested time + EFI_INVALID_PARAMETER - Event or Type is not valid + +--*/ +; + + +EFI_STATUS +EFIAPI +CoreSignalEvent ( + IN EFI_EVENT Event + ) +/*++ + +Routine Description: + + Signals the event. Queues the event to be notified if needed + +Arguments: + + Event - The event to signal + +Returns: + + EFI_INVALID_PARAMETER - Parameters are not valid. + + EFI_SUCCESS - The event was signaled. + +--*/ +; + + +EFI_STATUS +EFIAPI +CoreWaitForEvent ( + IN UINTN NumberOfEvents, + IN EFI_EVENT *UserEvents, + OUT UINTN *UserIndex + ) +/*++ + +Routine Description: + + Stops execution until an event is signaled. + +Arguments: + + NumberOfEvents - The number of events in the UserEvents array + UserEvents - An array of EFI_EVENT + UserIndex - Pointer to the index of the event which satisfied the wait condition + +Returns: + + EFI_SUCCESS - The event indicated by Index was signaled. + EFI_INVALID_PARAMETER - The event indicated by Index has a notification function or + Event was not a valid type + EFI_UNSUPPORTED - The current TPL is not TPL_APPLICATION + +--*/ +; + + +EFI_STATUS +EFIAPI +CoreCloseEvent ( + IN EFI_EVENT Event + ) +/*++ + +Routine Description: + + Closes an event and frees the event structure. + +Arguments: + + UserEvent - Event to close + +Returns: + + EFI_INVALID_PARAMETER - Parameters are not valid. + + EFI_SUCCESS - The event has been closed + +--*/ +; + + +EFI_STATUS +EFIAPI +CoreCheckEvent ( + IN EFI_EVENT Event + ) +/*++ + +Routine Description: + + Check the status of an event + +Arguments: + + UserEvent - The event to check + +Returns: + + EFI_SUCCESS - The event is in the signaled state + EFI_NOT_READY - The event is not in the signaled state + EFI_INVALID_PARAMETER - Event is of type EVT_NOTIFY_SIGNAL + +--*/ +; + +EFI_STATUS +CoreAddMemorySpace ( + IN EFI_GCD_MEMORY_TYPE GcdMemoryType, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Capabilities + ) +/*++ + +Routine Description: + + Add a segment of memory space to GCD map and add all available pages in this segment + as memory descriptors. + +Arguments: + + GcdMemoryType - Memory type of the segment. + + BaseAddress - Base address of the segment. + + Length - Length of the segment. + + Capabilities - alterable attributes of the segment. + +Returns: + + EFI_SUCCESS - Merged this segment into GCD map. + +--*/ +; + +EFI_STATUS +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 + ) +/*++ + +Routine Description: + + Allocate memory space on GCD map. + +Arguments: + + GcdAllocateType - The type of allocate operation + + GcdMemoryType - The desired memory type + + Alignment - Align with 2^Alignment + + Length - Length to allocate + + BaseAddress - Base address to allocate + + ImageHandle - The image handle consume the allocated space. + + DeviceHandle - The device handle consume the allocated space. + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter. + + EFI_NOT_FOUND - No descriptor contains the desired space. + + EFI_SUCCESS - Memory space successfully allocated. + +--*/ +; + +EFI_STATUS +CoreFreeMemorySpace ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +/*++ + +Routine Description:Routine Description: + + Free a segment of memory space in GCD map. + +Arguments: + + BaseAddress - Base address of the segment. + + Length - Length of the segment. + +Returns: + + EFI_SUCCESS - Space successfully freed. + +--*/ +; + +EFI_STATUS +CoreRemoveMemorySpace ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +/*++ + +Routine Description:Routine Description: + + Remove a segment of memory space in GCD map. + +Arguments: + + BaseAddress - Base address of the segment. + + Length - Length of the segment. + +Returns: + + EFI_SUCCESS - Successfully a segment of memory space. + +--*/ +; + +EFI_STATUS +CoreGetMemorySpaceDescriptor ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor + ) +/*++ + +Routine Description: + + Search all entries in GCD map which contains specified segment and build it to a descriptor. + +Arguments: + + BaseAddress - Specified start address + + Descriptor - Specified length + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_SUCCESS - Successfully get memory space descriptor. + +--*/ +; + +EFI_STATUS +CoreSetMemorySpaceAttributes ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Attributes + ) +/*++ + +Routine Description: + + Set memory space with specified attributes. + +Arguments: + + BaseAddress - Specified start address + + Length - Specified length + + Attributes - Specified attributes + +Returns: + + EFI_SUCCESS - Successfully set attribute of a segment of memory space. + +--*/ +; + +EFI_STATUS +CoreGetMemorySpaceMap ( + OUT UINTN *NumberOfDescriptors, + OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR **MemorySpaceMap + ) +/*++ + +Routine Description: + + Transer all entries of GCD memory map into memory descriptors and pass to caller. + +Arguments: + + NumberOfDescriptors - Number of descriptors. + + MemorySpaceMap - Descriptor array + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_OUT_OF_RESOURCES - No enough buffer to allocate + + EFI_SUCCESS - Successfully get memory space map. + +--*/ +; + +EFI_STATUS +CoreAddIoSpace ( + IN EFI_GCD_IO_TYPE GcdIoType, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +/*++ + +Routine Description: + + Add a segment of IO space to GCD map. + +Arguments: + + GcdIoType - IO type of the segment. + + BaseAddress - Base address of the segment. + + Length - Length of the segment. + +Returns: + + EFI_SUCCESS - Merged this segment into GCD map. + +--*/ +; + +EFI_STATUS +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 + ) +/*++ + +Routine Description: + + Allocate IO space on GCD map. + +Arguments: + + GcdAllocateType - The type of allocate operation + + GcdIoType - The desired IO type + + Alignment - Align with 2^Alignment + + Length - Length to allocate + + BaseAddress - Base address to allocate + + ImageHandle - The image handle consume the allocated space. + + DeviceHandle - The device handle consume the allocated space. + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter. + + EFI_NOT_FOUND - No descriptor contains the desired space. + + EFI_SUCCESS - IO space successfully allocated. + +--*/ +; + +EFI_STATUS +CoreFreeIoSpace ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +/*++ + +Routine Description:Routine Description: + + Free a segment of IO space in GCD map. + +Arguments: + + BaseAddress - Base address of the segment. + + Length - Length of the segment. + +Returns: + + EFI_SUCCESS - Space successfully freed. + +--*/ +; + +EFI_STATUS +CoreRemoveIoSpace ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +/*++ + +Routine Description:Routine Description: + + Remove a segment of IO space in GCD map. + +Arguments: + + BaseAddress - Base address of the segment. + + Length - Length of the segment. + +Returns: + + EFI_SUCCESS - Successfully removed a segment of IO space. + +--*/ +; + +EFI_STATUS +CoreGetIoSpaceDescriptor ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + OUT EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor + ) +/*++ + +Routine Description: + + Search all entries in GCD map which contains specified segment and build it to a descriptor. + +Arguments: + + BaseAddress - Specified start address + + Descriptor - Specified length + +Returns: + + EFI_INVALID_PARAMETER - Descriptor is NULL. + + EFI_SUCCESS - Successfully get the IO space descriptor. + +--*/ +; + +EFI_STATUS +CoreGetIoSpaceMap ( + OUT UINTN *NumberOfDescriptors, + OUT EFI_GCD_IO_SPACE_DESCRIPTOR **IoSpaceMap + ) +/*++ + +Routine Description: + + Transer all entries of GCD IO map into IO descriptors and pass to caller. + +Arguments: + + NumberOfDescriptors - Number of descriptors. + + IoSpaceMap - Descriptor array + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_OUT_OF_RESOURCES - No enough buffer to allocate + + EFI_SUCCESS - Successfully get IO space map. + +--*/ +; + +EFI_DXESERVICE +EFI_STATUS +EFIAPI +CoreDispatcher ( + VOID + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + NONE + +Returns: + + EFI_ALREADY_STARTED - The DXE Dispatcher is already running + + EFI_NOT_FOUND - No DXE Drivers were dispatched + + EFI_SUCCESS - One or more DXE Drivers were dispatched + +--*/ +; +EFI_DXESERVICE +EFI_STATUS +EFIAPI +CoreSchedule ( + IN EFI_HANDLE FirmwareVolumeHandle, + IN EFI_GUID *DriverName + ) +/*++ + +Routine Description: + + Check every driver and locate a matching one. If the driver is found, the Unrequested + state flag is cleared. + +Arguments: + + FirmwareVolumeHandle - The handle of the Firmware Volume that contains the firmware + file specified by DriverName. + + DriverName - The Driver name to put in the Dependent state. + +Returns: + + EFI_SUCCESS - The DriverName was found and it's SOR bit was cleared + + EFI_NOT_FOUND - The DriverName does not exist or it's SOR bit was not set. + +--*/ +; + +EFI_DXESERVICE +EFI_STATUS +EFIAPI +CoreTrust ( + IN EFI_HANDLE FirmwareVolumeHandle, + IN EFI_GUID *DriverName + ) +/*++ + +Routine Description: + + Convert a driver from the Untrused back to the Scheduled state + +Arguments: + + FirmwareVolumeHandle - The handle of the Firmware Volume that contains the firmware + file specified by DriverName. + + DriverName - The Driver name to put in the Scheduled state + +Returns: + + EFI_SUCCESS - The file was found in the untrusted state, and it was promoted + to the trusted state. + + EFI_NOT_FOUND - The file was not found in the untrusted state. + +--*/ +; + +BOOLEAN +CoreGrowBuffer ( + IN OUT EFI_STATUS *Status, + IN OUT VOID **Buffer, + IN UINTN BufferSize + ) +/*++ + +Routine Description: + + Helper function called as part of the code needed + to allocate the proper sized buffer for various + EFI interfaces. + +Arguments: + + Status - Current status + + Buffer - Current allocated buffer, or NULL + + BufferSize - Current buffer size needed + +Returns: + + TRUE - if the buffer was reallocated and the caller + should try the API again. + + FALSE - buffer could not be allocated and the caller + should not try the API again. + +--*/ +; + +EFI_STATUS +EFIAPI +FwVolDriverInit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + 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. + +Arguments: + ImageHandle - The image handle. + SystemTable - The system table. + +Returns: + EFI_SUCCESS - Function successfully returned. + +--*/ +; + +EFI_STATUS +EFIAPI +InitializeSectionExtraction ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + Entry point of the section extraction code. Initializes an instance of the + section extraction interface and installs it on a new handle. + +Arguments: + ImageHandle EFI_HANDLE: A handle for the image that is initializing this driver + SystemTable EFI_SYSTEM_TABLE: A pointer to the EFI system table + +Returns: + EFI_SUCCESS: Driver initialized successfully + EFI_OUT_OF_RESOURCES: Could not allocate needed resources + +--*/ +; + +EFI_STATUS +CoreProcessFirmwareVolume ( + IN VOID *FvHeader, + IN UINTN Size, + OUT EFI_HANDLE *FVProtocolHandle + ) +/*++ + +Routine Description: + 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. + +Arguments: + FvHeader - pointer to a firmware volume header + Size - the size of the buffer pointed to by FvHeader + FVProtocolHandle - the handle on which a firmware volume protocol + was produced for the firmware volume passed in. + +Returns: + EFI_OUT_OF_RESOURCES - if an FVB could not be produced due to lack of + system resources + EFI_VOLUME_CORRUPTED - if the volume was corrupted + EFI_SUCCESS - a firmware volume protocol was produced for the + firmware volume + +--*/ +; + +// +//Functions used during debug buils +// +VOID +CoreDisplayMissingArchProtocols ( + VOID + ) +/*++ + + Routine Description: + Displays Architectural protocols that were not loaded and are required for DXE core to function + Only used in Debug Builds + + Arguments: + NONE + + Returns: + NONE + +--*/; + +VOID +CoreDisplayDiscoveredNotDispatched ( + VOID + ) +/*++ + + Routine Description: + + Traverse the discovered list for any drivers that were discovered but not loaded + because the dependency experessions evaluated to false + + Arguments: + + NONE + + Returns: + + NONE + +--*/; +#endif diff --git a/EdkModulePkg/Core/Dxe/DxeMain.mbd b/EdkModulePkg/Core/Dxe/DxeMain.mbd new file mode 100644 index 0000000000..ec084b5c56 --- /dev/null +++ b/EdkModulePkg/Core/Dxe/DxeMain.mbd @@ -0,0 +1,42 @@ + + + + + DxeMain + D6A2CB7F-6A18-4e2f-B43B-9920A733700A + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + All rights reserved. This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + 2006-03-12 17:09 + 2006-03-19 15:18 + + + BaseLib + BaseCacheMaintenanceLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + DxeCoreUefiDecompressLibFromHob + DxeCoreTianoDecompressLibFromHob + DxeCoreCustomDecompressLibFromHob + EdkDxePeCoffLoaderFromHobLib + DxeCoreHobLib + DxeCoreEntryPoint + BaseMemoryLib + UefiLib + BasePerformanceLibNull + + + _ModuleEntryPoint + + + diff --git a/EdkModulePkg/Core/Dxe/DxeMain.msa b/EdkModulePkg/Core/Dxe/DxeMain.msa new file mode 100644 index 0000000000..42531812df --- /dev/null +++ b/EdkModulePkg/Core/Dxe/DxeMain.msa @@ -0,0 +1,164 @@ + + + + + DxeMain + DXE_CORE + BS_DRIVER + D6A2CB7F-6A18-4e2f-B43B-9920A733700A + 0 + Component description file for DxeMain. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + All rights reserved. This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + 0 + 2006-03-12 17:09 + 2006-03-19 15:18 + + + DxeCoreEntryPoint + DebugLib + UefiLib + BaseLib + HobLib + PerformanceLib + UefiDecompressLib + TianoDecompressLib + CustomDecompressLib + EdkPeCoffLoaderLib + CacheMaintenanceLib + BaseMemoryLib + + + DxeMain\DxeMain.c + DxeMain\DxeProtocolNotify.c + Dispatcher\Dispatcher.c + Dispatcher\Dependency.c + Event\ExecData.c + Event\Event.c + Event\Timer.c + Event\Tpl.c + FwVol\FwVol.c + FwVol\Ffs.c + FwVol\FwVolAttrib.c + FwVol\FwVolRead.c + FwVol\FwVolWrite.c + FwVolBlock\FwVolBlock.c + Mem\MemData.c + Mem\Page.c + Mem\Pool.c + Gcd\Gcd.c + Hand\Handle.c + Hand\Locate.c + Hand\Notify.c + Hand\DriverSupport.c + Library\Library.c + Misc\InstallConfigurationTable.c + Misc\SetWatchdogTimer.c + Misc\Stall.c + Misc\DebugImageInfo.c + Image\Image.c + Image\ImageFile.c + SectionExtraction\CoreSectionExtraction.c + DebugImageInfo.h + DebugMask.h + DxeMain.h + Exec.h + FwVolBlock.h + FwVolDriver.h + Gcd.h + Hand.h + Image.h + Imem.h + Library.h + + + MdePkg + EdkModulePkg + + + Ebc + LoadedImage + DevicePath + Cpu + FirmwareVolume + FirmwareVolumeDispatch + FirmwareVolumeBlock + SectionExtraction + DriverBinding + PlatformDriverOverride + BusSpecificDriverOverride + Timer + Metronome + MonotonicCounter + VariableWrite + Bds + Variable + Security + WatchdogTimer + Runtime + RealTimeClock + Reset + LoadFile + SimpleFileSystem + LoadPeImage + + + + MemoryTypeInformation + + + DxeServicesTable + + + HobList + + + DebugImageInfoTable + + + Apriori + + + FirmwareFileSystem + + + FileInfo + + + HobMemoryAllocModule + + + PeiPeCoffLoader + + + LoadPeImage + + + EventExitBootServices + + + EventVirtualAddressChange + + + EventMemoryMapChange + + + + + DxeMain + + + + + + diff --git a/EdkModulePkg/Core/Dxe/DxeMain/DxeMain.c b/EdkModulePkg/Core/Dxe/DxeMain/DxeMain.c new file mode 100644 index 0000000000..f98f0541ff --- /dev/null +++ b/EdkModulePkg/Core/Dxe/DxeMain/DxeMain.c @@ -0,0 +1,1083 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DxeMain.c + +Abstract: + + DXE Core Main Entry Point + +--*/ + +#include + +VOID +EFIAPI +DxeMain ( + IN VOID *HobStart + ); + +EFI_STATUS +EFIAPI +CoreEfiNotAvailableYetArg0 ( + VOID + ); + +EFI_STATUS +EFIAPI +CoreEfiNotAvailableYetArg1 ( + UINTN Arg1 + ); + +EFI_STATUS +EFIAPI +CoreEfiNotAvailableYetArg2 ( + UINTN Arg1, + UINTN Arg2 + ); + +EFI_STATUS +EFIAPI +CoreEfiNotAvailableYetArg3 ( + UINTN Arg1, + UINTN Arg2, + UINTN Arg3 + ); + +EFI_STATUS +EFIAPI +CoreEfiNotAvailableYetArg4 ( + UINTN Arg1, + UINTN Arg2, + UINTN Arg3, + UINTN Arg4 + ); + +EFI_STATUS +EFIAPI +CoreEfiNotAvailableYetArg5 ( + UINTN Arg1, + UINTN Arg2, + UINTN Arg3, + UINTN Arg4, + UINTN Arg5 + ); + +EFI_STATUS +CoreGetPeiProtocol ( + IN EFI_GUID *ProtocolGuid, + IN VOID **Interface + ); + +EFI_STATUS +DxeMainUefiDecompressGetInfo ( + IN EFI_DECOMPRESS_PROTOCOL *This, + IN VOID *Source, + IN UINT32 SourceSize, + OUT UINT32 *DestinationSize, + OUT UINT32 *ScratchSize + ); + +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 +DxeMainTianoDecompressGetInfo ( + IN EFI_TIANO_DECOMPRESS_PROTOCOL *This, + IN VOID *Source, + IN UINT32 SourceSize, + OUT UINT32 *DestinationSize, + OUT UINT32 *ScratchSize + ); + +EFI_STATUS +EFIAPI +DxeMainTianoDecompress ( + IN EFI_TIANO_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 +DxeMainCustomDecompressGetInfo ( + IN EFI_CUSTOMIZED_DECOMPRESS_PROTOCOL *This, + IN VOID *Source, + IN UINT32 SourceSize, + OUT UINT32 *DestinationSize, + OUT UINT32 *ScratchSize + ); + +EFI_STATUS +EFIAPI +DxeMainCustomDecompress ( + IN EFI_CUSTOMIZED_DECOMPRESS_PROTOCOL *This, + IN VOID *Source, + IN UINT32 SourceSize, + IN OUT VOID *Destination, + IN UINT32 DestinationSize, + IN OUT VOID *Scratch, + IN UINT32 ScratchSize + ); + +// +// DXE Core Global Variables for Protocols from PEI +// +EFI_HANDLE mDecompressHandle = NULL; +EFI_PEI_PE_COFF_LOADER_PROTOCOL *gEfiPeiPeCoffLoader = NULL; + +// +// DXE Core globals for Architecture Protocols +// +EFI_SECURITY_ARCH_PROTOCOL *gSecurity = 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; +EFI_RUNTIME_ARCH_PROTOCOL *gRuntime = NULL; + +// +// BugBug: I'n not runtime, but is the PPI? +// +EFI_STATUS_CODE_PROTOCOL gStatusCodeInstance = { + NULL +}; + +EFI_STATUS_CODE_PROTOCOL *gStatusCode = &gStatusCodeInstance; + + +// +// 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 +#if (EFI_SPECIFICATION_VERSION >= 0x00020000) + , + (EFI_CREATE_EVENT_EX) CoreCreateEventEx // CreateEventEx +#endif +}; + +EFI_DXE_SERVICES mDxeServices = { + { + EFI_DXE_SERVICES_SIGNATURE, // Signature + EFI_DXE_SERVICES_REVISION, // Revision + sizeof (EFI_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_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 +#if ((EDK_RELEASE_VERSION != 0) && (EFI_SPECIFICATION_VERSION < 0x00020000)) + , + (TIANO_REPORT_STATUS_CODE) CoreEfiNotAvailableYetArg5 // ReportStatusCode +#elif (EFI_SPECIFICATION_VERSION >= 0x00020000) + , + (EFI_UPDATE_CAPSULE) CoreEfiNotAvailableYetArg3, // UpdateCapsule + (EFI_QUERY_CAPSULE_CAPABILITIES) CoreEfiNotAvailableYetArg4, // QueryCapsuleCapabilities + (EFI_QUERY_VARIABLE_INFO) CoreEfiNotAvailableYetArg4 // QueryVariableInfo +#endif +}; + +// +// DXE Core Global Variables for the EFI System Table, Boot Services Table, +// DXE Services Table, and Runtime Services Table +// +EFI_BOOT_SERVICES *gBS = &mBootServices; +EFI_DXE_SERVICES *gDS = &mDxeServices; +EFI_SYSTEM_TABLE *gST = NULL; + +// +// For debug initialize gRT to template. gRT must be allocated from RT memory +// but gRT 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 *gRT = &mEfiRuntimeServicesTableTemplate; +EFI_HANDLE gDxeCoreImageHandle = NULL; + +VOID *mHobStart; + +// +// EFI Decompress Protocol +// +EFI_DECOMPRESS_PROTOCOL gEfiDecompress = { + DxeMainUefiDecompressGetInfo, + DxeMainUefiDecompress +}; + +// +// Tiano Decompress Protocol +// +EFI_TIANO_DECOMPRESS_PROTOCOL gEfiTianoDecompress = { + DxeMainTianoDecompressGetInfo, + DxeMainTianoDecompress +}; + +// +// Customized Decompress Protocol +// +EFI_CUSTOMIZED_DECOMPRESS_PROTOCOL gEfiCustomizedDecompress = { + DxeMainCustomDecompressGetInfo, + DxeMainCustomDecompress +}; + +// +// Main entry point to the DXE Core +// +VOID +EFIAPI +DxeMain ( + IN VOID *HobStart + ) +/*++ + +Routine Description: + + Main entry point to DXE Core. + +Arguments: + + HobStart - Pointer to the beginning of the HOB List from PEI + +Returns: + + This function should never return + +--*/ +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS MemoryBaseAddress; + UINT64 MemoryLength; + +#ifdef EFI_DXE_PERFORMANCE + UINT64 Tick; + + GetTimerValue (&Tick); +#endif + + mHobStart = HobStart; + + // + // Initialize Memory Services + // + CoreInitializeMemoryServices (&HobStart, &MemoryBaseAddress, &MemoryLength); + + // + // 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 + // + gST = CoreAllocateRuntimeCopyPool (sizeof (EFI_SYSTEM_TABLE), &mEfiSystemTableTemplate); + ASSERT (gST != NULL); + + gRT = CoreAllocateRuntimeCopyPool (sizeof (EFI_RUNTIME_SERVICES), &mEfiRuntimeServicesTableTemplate); + ASSERT (gRT != NULL); + + gST->RuntimeServices = gRT; + + // + // Start the Image Services. + // + Status = CoreInitializeImageServices (HobStart); + ASSERT_EFI_ERROR (Status); + + // + // Call constructor for all libraries + // + ProcessLibraryConstructorList (gDxeCoreImageHandle, gST); + + // + // Initialize the Global Coherency Domain Services + // + Status = CoreInitializeGcdServices (&HobStart, MemoryBaseAddress, MemoryLength); + ASSERT_EFI_ERROR (Status); + + // + // Install the DXE Services Table into the EFI System Tables's Configuration Table + // + Status = CoreInstallConfigurationTable (&gEfiDxeServicesTableGuid, gDS); + 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); + + // + // Initialize the ReportStatusCode with PEI version, if availible + // + CoreGetPeiProtocol (&gEfiStatusCodeRuntimeProtocolGuid, (VOID **)&gStatusCode->ReportStatusCode); +#if ((EDK_RELEASE_VERSION != 0) && (EFI_SPECIFICATION_VERSION < 0x00020000)) + gRT->ReportStatusCode = gStatusCode->ReportStatusCode; +#endif + + // + // Report Status Code here for DXE_ENTRY_POINT once it is available + // + CoreReportProgressCode ((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 ((EFI_D_INFO | EFI_D_LOAD, "HOBLIST address in DXE = 0x%08x\n", HobStart)); + + // + // Initialize the Event Services + // + Status = CoreInitializeEventServices (); + 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, + &gEfiTianoDecompressProtocolGuid, &gEfiTianoDecompress, + &gEfiCustomizedDecompressProtocolGuid, &gEfiCustomizedDecompress, + NULL + ); + ASSERT_EFI_ERROR (Status); + + gEfiPeiPeCoffLoader = GetPeCoffLoaderProtocol (); + ASSERT (gEfiPeiPeCoffLoader != NULL); + + // + // 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. + // + CoreNotifyOnArchProtocolInstallation (); + + // + // Produce Firmware Volume Protocols, one for each FV in the HOB list. + // + Status = FwVolBlockDriverInit (gDxeCoreImageHandle, gST); + ASSERT_EFI_ERROR (Status); + + Status = FwVolDriverInit (gDxeCoreImageHandle, gST); + ASSERT_EFI_ERROR (Status); + + // + // Produce the Section Extraction Protocol + // + Status = InitializeSectionExtraction (gDxeCoreImageHandle, gST); + ASSERT_EFI_ERROR (Status); + + // + // Initialize the DXE Dispatcher + // + PERF_START (0,"CoreInitializeDispatcher", "DxeMain", 0) ; + CoreInitializeDispatcher (); + PERF_END (0,"CoreInitializeDispatcher", "DxeMain", 0) ; + + // + // Invoke the DXE Dispatcher + // + PERF_START (0, "CoreDispatcher", "DxeMain", 0); + CoreDispatcher (); + PERF_END (0, "CoreDispatcher", "DxeMain", 0); + + // + // Display Architectural protocols that were not loaded if this is DEBUG build + // + DEBUG_CODE ( + CoreDisplayMissingArchProtocols (); + ); + + // + // Assert if the Architectural Protocols are not present. + // + ASSERT_EFI_ERROR (CoreAllEfiServicesAvailable ()); + + // + // Report Status code before transfer control to BDS + // + CoreReportProgressCode ((EFI_SOFTWARE_DXE_CORE | EFI_SW_DXE_CORE_PC_HANDOFF_TO_NEXT)); + // + // Display any drivers that were not dispatched because dependency expression + // evaluated to false if this is a debug build + // + DEBUG_CODE ( + CoreDisplayDiscoveredNotDispatched (); + ); + + // + // Transfer control to the BDS Architectural Protocol + // + gBds->Entry (gBds); + + // + // BDS should never return + // + ASSERT (FALSE); + CpuDeadLoop (); +} + + +EFI_STATUS +EFIAPI +CoreEfiNotAvailableYetArg0 ( + VOID + ) +/*++ + +Routine Description: + + Place holder function until all the Boot Services and Runtime Services are available + +Arguments: + + None + +Returns: + + EFI_NOT_AVAILABLE_YET + +--*/ +{ + // + // 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; +} + +EFI_STATUS +EFIAPI +CoreEfiNotAvailableYetArg1 ( + UINTN Arg1 + ) +/*++ + +Routine Description: + + Place holder function until all the Boot Services and Runtime Services are available + +Arguments: + + Arg1 - Undefined + +Returns: + + EFI_NOT_AVAILABLE_YET + +--*/ +{ + // + // 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; +} + +EFI_STATUS +EFIAPI +CoreEfiNotAvailableYetArg2 ( + UINTN Arg1, + UINTN Arg2 + ) +/*++ + +Routine Description: + + Place holder function until all the Boot Services and Runtime Services are available + +Arguments: + + Arg1 - Undefined + + Arg2 - Undefined + +Returns: + + EFI_NOT_AVAILABLE_YET + +--*/ +{ + // + // 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; +} + +EFI_STATUS +EFIAPI +CoreEfiNotAvailableYetArg3 ( + UINTN Arg1, + UINTN Arg2, + UINTN Arg3 + ) +/*++ + +Routine Description: + + Place holder function until all the Boot Services and Runtime Services are available + +Arguments: + + Arg1 - Undefined + + Arg2 - Undefined + + Arg3 - Undefined + +Returns: + + EFI_NOT_AVAILABLE_YET + +--*/ +{ + // + // 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; +} + +EFI_STATUS +EFIAPI +CoreEfiNotAvailableYetArg4 ( + UINTN Arg1, + UINTN Arg2, + UINTN Arg3, + UINTN Arg4 + ) +/*++ + +Routine Description: + + Place holder function until all the Boot Services and Runtime Services are available + +Arguments: + + Arg1 - Undefined + + Arg2 - Undefined + + Arg3 - Undefined + + Arg4 - Undefined + +Returns: + + EFI_NOT_AVAILABLE_YET + +--*/ +{ + // + // 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; +} + +EFI_STATUS +EFIAPI +CoreEfiNotAvailableYetArg5 ( + UINTN Arg1, + UINTN Arg2, + UINTN Arg3, + UINTN Arg4, + UINTN Arg5 + ) +/*++ + +Routine Description: + + Place holder function until all the Boot Services and Runtime Services are available + +Arguments: + + Arg1 - Undefined + + Arg2 - Undefined + + Arg3 - Undefined + + Arg4 - Undefined + + Arg5 - Undefined + +Returns: + + EFI_NOT_AVAILABLE_YET + +--*/ +{ + // + // 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; +} + + +EFI_STATUS +CoreGetPeiProtocol ( + IN EFI_GUID *ProtocolGuid, + IN VOID **Interface + ) +/*++ + +Routine Description: + + Searches for a Protocol Interface passed from PEI through a HOB + +Arguments: + + ProtocolGuid - The Protocol GUID to search for in the HOB List + + Interface - A pointer to the interface for the Protocol GUID + +Returns: + + EFI_SUCCESS - The Protocol GUID was found and its interface is returned in Interface + + EFI_NOT_FOUND - The Protocol GUID was not found in the HOB List + +--*/ +{ + EFI_HOB_GUID_TYPE *GuidHob; + VOID *Buffer; + + GuidHob = GetNextGuidHob (ProtocolGuid, mHobStart); + if (GuidHob == NULL) { + return EFI_NOT_FOUND; + } + + Buffer = GET_GUID_HOB_DATA (GuidHob); + ASSERT (Buffer != NULL); + + *Interface = (VOID *)(*(UINTN *)(Buffer)); + + return EFI_SUCCESS; +} + + +VOID +CalculateEfiHdrCrc ( + IN OUT EFI_TABLE_HEADER *Hdr + ) +/*++ + +Routine Description: + + Calcualte the 32-bit CRC in a EFI table using the service provided by the + gRuntime service. + +Arguments: + + Hdr - Pointer to an EFI standard header + +Returns: + + None + +--*/ +{ + 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; +} + + + +EFI_STATUS +EFIAPI +CoreExitBootServices ( + IN EFI_HANDLE ImageHandle, + IN UINTN MapKey + ) +/*++ + +Routine Description: + + EFI 1.0 API to terminate Boot Services + +Arguments: + + ImageHandle - Handle that represents the identity of the calling image + + MapKey -Key to the latest memory map. + +Returns: + + EFI_SUCCESS - Boot Services terminated + EFI_INVALID_PARAMETER - MapKey is incorrect. + +--*/ +{ + EFI_STATUS Status; + + // + // Terminate memory services if the MapKey matches + // + Status = CoreTerminateMemoryMap (MapKey); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Notify other drivers that we are exiting boot services. + // + CoreNotifySignalList (&gEfiEventExitBootServicesGuid); + + // + // Disable Timer + // + gTimer->SetTimerPeriod (gTimer, 0); + + // + // Disable CPU Interrupts + // + gCpu->DisableInterrupt (gCpu); + + // + // Register Runtime events with the Runtime Architectural Protocol + // + CoreShutdownEventServices (); + + // + // Register Runtime images with the Runtime Architectural Protocol + // + CoreShutdownImageServices (); + + // + // Report that ExitBootServices() has been called + // + // We are using gEfiDxeServicesTableGuid as the caller ID for Dxe Core + // + CoreReportProgressCode ((EFI_SOFTWARE_EFI_BOOT_SERVICE | EFI_SW_BS_PC_EXIT_BOOT_SERVICES)); + + // + // Clear the non-runtime values of the EFI System Table + // + gST->BootServices = NULL; + gST->ConIn = NULL; + gST->ConsoleInHandle = NULL; + gST->ConOut = NULL; + gST->ConsoleOutHandle = NULL; + gST->StdErr = NULL; + gST->StandardErrorHandle = NULL; + + // + // Recompute the 32-bit CRC of the EFI System Table + // + CalculateEfiHdrCrc (&gST->Hdr); + + // + // Zero out the Boot Service Table + // + SetMem (gBS, sizeof (EFI_BOOT_SERVICES), 0); + gBS = NULL; + + return Status; +} + +EFI_STATUS +DxeMainUefiDecompressGetInfo ( + IN EFI_DECOMPRESS_PROTOCOL *This, + IN VOID *Source, + IN UINT32 SourceSize, + OUT UINT32 *DestinationSize, + OUT UINT32 *ScratchSize + ) +{ + return UefiDecompressGetInfo (Source, SourceSize, DestinationSize, ScratchSize); +} + +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; + + 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); +} + +EFI_STATUS +DxeMainTianoDecompressGetInfo ( + IN EFI_TIANO_DECOMPRESS_PROTOCOL *This, + IN VOID *Source, + IN UINT32 SourceSize, + OUT UINT32 *DestinationSize, + OUT UINT32 *ScratchSize + ) +{ + return TianoDecompressGetInfo (Source, SourceSize, DestinationSize, ScratchSize); +} + +EFI_STATUS +EFIAPI +DxeMainTianoDecompress ( + IN EFI_TIANO_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; + + Status = TianoDecompressGetInfo (Source, SourceSize, &TestDestinationSize, &TestScratchSize); + if (EFI_ERROR (Status)) { + return Status; + } + + if (ScratchSize < TestScratchSize || DestinationSize < TestDestinationSize) { + return RETURN_INVALID_PARAMETER; + } + + return TianoDecompress (Source, Destination, Scratch); +} + +EFI_STATUS +DxeMainCustomDecompressGetInfo ( + IN EFI_CUSTOMIZED_DECOMPRESS_PROTOCOL *This, + IN VOID *Source, + IN UINT32 SourceSize, + OUT UINT32 *DestinationSize, + OUT UINT32 *ScratchSize + ) +{ + return CustomDecompressGetInfo (Source, SourceSize, DestinationSize, ScratchSize); +} + +EFI_STATUS +EFIAPI +DxeMainCustomDecompress ( + IN EFI_CUSTOMIZED_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; + + Status = CustomDecompressGetInfo (Source, SourceSize, &TestDestinationSize, &TestScratchSize); + if (EFI_ERROR (Status)) { + return Status; + } + + if (ScratchSize < TestScratchSize || DestinationSize < TestDestinationSize) { + return RETURN_INVALID_PARAMETER; + } + + return CustomDecompress (Source, Destination, Scratch); +} + diff --git a/EdkModulePkg/Core/Dxe/DxeMain/DxeProtocolNotify.c b/EdkModulePkg/Core/Dxe/DxeMain/DxeProtocolNotify.c new file mode 100644 index 0000000000..7e49423fb4 --- /dev/null +++ b/EdkModulePkg/Core/Dxe/DxeMain/DxeProtocolNotify.c @@ -0,0 +1,266 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DxeProtocolNotify.c + +Abstract: + + 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. + +--*/ + +#include + + +// +// 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. +// + +ARCHITECTURAL_PROTOCOL_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 }, + { &gEfiMonotonicCounterArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE }, + { &gEfiResetArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE }, +// { &gEfiStatusCodeRuntimeProtocolGuid, (VOID **)&gStatusCode, NULL, NULL, FALSE }, + { &gEfiRealTimeClockArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE }, + { NULL, (VOID **)NULL, NULL, NULL, FALSE } +}; + + +EFI_STATUS +CoreAllEfiServicesAvailable ( + VOID + ) +/*++ + +Routine Description: + Return TRUE if all AP services are availible. + +Arguments: + NONE + +Returns: + EFI_SUCCESS - All AP services are available + EFI_NOT_FOUND - At least one AP service is not available + +--*/ +{ + ARCHITECTURAL_PROTOCOL_ENTRY *Entry; + + for (Entry = mArchProtocols; Entry->ProtocolGuid != NULL; Entry++) { + if (!Entry->Present) { + return EFI_NOT_FOUND; + } + } + + return EFI_SUCCESS; +} + + +VOID +EFIAPI +GenericArchProtocolNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + 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. + +Arguments: + + Event - The Event that is being processed, not used. + + Context - Event Context, not used. + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + ARCHITECTURAL_PROTOCOL_ENTRY *Entry; + VOID *Protocol; + BOOLEAN Found; + + Found = FALSE; + for (Entry = mArchProtocols; Entry->ProtocolGuid != NULL; Entry++) { + + Status = CoreLocateProtocol (Entry->ProtocolGuid, Entry->Registration, &Protocol); + if (EFI_ERROR (Status)) { + continue; + } + + Found = TRUE; + 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; + } + + 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 (); + } + } + + // + // It's over kill to do them all every time, but it saves a lot of code. + // + if (Found) { + CalculateEfiHdrCrc (&gRT->Hdr); + CalculateEfiHdrCrc (&gBS->Hdr); + CalculateEfiHdrCrc (&gST->Hdr); + CalculateEfiHdrCrc (&gDS->Hdr); + } +} + + + +VOID +CoreNotifyOnArchProtocolInstallation ( + VOID + ) +/*++ + +Routine Description: + Creates an event that is fired everytime a Protocol of a specific type is installed + +Arguments: + NONE + +Returns: + NONE + +--*/ +{ + EFI_STATUS Status; + ARCHITECTURAL_PROTOCOL_ENTRY *Entry; + + for (Entry = mArchProtocols; Entry->ProtocolGuid != NULL; Entry++) { + + // + // Create the event + // + Status = CoreCreateEvent ( + EFI_EVENT_NOTIFY_SIGNAL, + EFI_TPL_CALLBACK, + GenericArchProtocolNotify, + NULL, + &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); + + } +} + +// +// Following is needed to display missing architectural protocols in debug builds +// +typedef struct { + EFI_GUID *ProtocolGuid; + CHAR16 *GuidString; +} GUID_TO_STRING_PROTOCOL_ENTRY; + +static const GUID_TO_STRING_PROTOCOL_ENTRY MissingProtocols[] = { + { &gEfiSecurityArchProtocolGuid, (CHAR16 *)L"Security" }, + { &gEfiCpuArchProtocolGuid, (CHAR16 *)L"CPU" }, + { &gEfiMetronomeArchProtocolGuid, (CHAR16 *)L"Metronome" }, + { &gEfiTimerArchProtocolGuid, (CHAR16 *)L"Timer" }, + { &gEfiBdsArchProtocolGuid, (CHAR16 *)L"Bds" }, + { &gEfiWatchdogTimerArchProtocolGuid, (CHAR16 *)L"Watchdog Timer" }, + { &gEfiRuntimeArchProtocolGuid, (CHAR16 *)L"Runtime" }, + { &gEfiVariableArchProtocolGuid, (CHAR16 *)L"Variable" }, + { &gEfiVariableWriteArchProtocolGuid, (CHAR16 *)L"Variable Write" }, + { &gEfiMonotonicCounterArchProtocolGuid, (CHAR16 *)L"Monotonic Counter" }, + { &gEfiResetArchProtocolGuid, (CHAR16 *)L"Reset" }, +// { &gEfiStatusCodeRuntimeProtocolGuid, (CHAR16 *)L"Status Code" }, + { &gEfiRealTimeClockArchProtocolGuid, (CHAR16 *)L"Real Time Clock" } +}; + +VOID +CoreDisplayMissingArchProtocols ( + VOID + ) +/*++ + +Routine Description: + Displays Architectural protocols that were not loaded and are required for DXE core to function + Only used in Debug Builds + +Arguments: + NONE + +Returns: + NONE + +--*/ +{ + const GUID_TO_STRING_PROTOCOL_ENTRY *MissingEntry; + ARCHITECTURAL_PROTOCOL_ENTRY *Entry; + + for (Entry = mArchProtocols; Entry->ProtocolGuid != NULL; Entry++) { + if (!Entry->Present) { + MissingEntry = MissingProtocols; + for (MissingEntry = MissingProtocols; TRUE ; MissingEntry++) { + if (CompareGuid (Entry->ProtocolGuid, MissingEntry->ProtocolGuid)) { + DEBUG ((EFI_D_ERROR, "\n%s Arch Protocol not present!!\n", MissingEntry->GuidString)); + break; + } + } + } + } +} diff --git a/EdkModulePkg/Core/Dxe/Event/event.c b/EdkModulePkg/Core/Dxe/Event/event.c new file mode 100644 index 0000000000..e8391419ab --- /dev/null +++ b/EdkModulePkg/Core/Dxe/Event/event.c @@ -0,0 +1,862 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + event.c + +Abstract: + + EFI Event support + +--*/ + + +#include + +// +// Enumerate the valid types +// +UINT32 mEventTable[] = { + // + // 0x80000200 Timer event with a notification function that is + // queue when the event is signaled with SignalEvent() + // + EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL, + // + // 0x80000000 Timer event without a notification function. It can be + // signaled with SignalEvent() and checked with CheckEvent() or WaitForEvent(). + // + EFI_EVENT_TIMER, + // + // 0x00000100 Generic event with a notification function that + // can be waited on with CheckEvent() or WaitForEvent() + // + EFI_EVENT_NOTIFY_WAIT, + // + // 0x00000200 Generic event with a notification function that + // is queue when the event is signaled with SignalEvent() + // + EFI_EVENT_NOTIFY_SIGNAL, + // + // 0x00000201 ExitBootServicesEvent. + // + EFI_EVENT_SIGNAL_EXIT_BOOT_SERVICES, + // + // 0x60000202 SetVirtualAddressMapEvent. + // + EFI_EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE, + +#if (EFI_SPECIFICATION_VERSION < 0x00020000) + // + // 0x00000203 ReadyToBootEvent. + // + EFI_EVENT_SIGNAL_READY_TO_BOOT, + // + // 0x00000204 LegacyBootEvent. + // + EFI_EVENT_SIGNAL_LEGACY_BOOT, + // + // 0x00000603 Signal all ReadyToBootEvents. + // + EFI_EVENT_NOTIFY_SIGNAL_ALL | EFI_EVENT_SIGNAL_READY_TO_BOOT, + // + // 0x00000604 Signal all LegacyBootEvents. + // + EFI_EVENT_NOTIFY_SIGNAL_ALL | EFI_EVENT_SIGNAL_LEGACY_BOOT, +#endif + + // + // 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() + // + EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_WAIT, +}; + + +VOID +CoreAcquireEventLock ( + VOID + ) +/*++ + +Routine Description: + + Enter critical section by acquiring the lock on gEventQueueLock. + +Arguments: + + None + +Returns: + + None + +--*/ +{ + CoreAcquireLock (&gEventQueueLock); +} + + +VOID +CoreReleaseEventLock ( + VOID + ) +/*++ + +Routine Description: + + Exit critical section by releasing the lock on gEventQueueLock. + +Arguments: + + None + +Returns: + + None + +--*/ +{ + CoreReleaseLock (&gEventQueueLock); +} + + +EFI_STATUS +CoreInitializeEventServices ( + VOID + ) +/*++ + +Routine Description: + + Initializes "event" support and populates parts of the System and Runtime Table. + +Arguments: + + None + +Returns: + + EFI_SUCCESS - Always return success + +--*/ +{ + UINTN Index; + + for (Index=0; Index <= EFI_TPL_HIGH_LEVEL; Index++) { + InitializeListHead (&gEventQueue[Index]); + } + + CoreInitializeTimer (); + + return EFI_SUCCESS; +} + + +EFI_STATUS +CoreShutdownEventServices ( + VOID + ) +/*++ + +Routine Description: + + Register all runtime events to make sure they are still available after ExitBootService. + +Arguments: + + None + +Returns: + + EFI_SUCCESS - Always return success. + +--*/ +{ + LIST_ENTRY *Link; + IEVENT *Event; + + // + // The Runtime AP is required for the core to function! + // + ASSERT (gRuntime != NULL); + + for (Link = mRuntimeEventList.ForwardLink; Link != &mRuntimeEventList; Link = Link->ForwardLink) { + Event = CR (Link, IEVENT, RuntimeLink, EVENT_SIGNATURE); + gRuntime->RegisterEvent ( + gRuntime, + Event->Type, + Event->NotifyTpl, + Event->NotifyFunction, + Event->NotifyContext, + (VOID **)Event + ); + } + + return EFI_SUCCESS; +} + + +VOID +CoreDispatchEventNotifies ( + IN EFI_TPL Priority + ) +/*++ + +Routine Description: + + Dispatches all pending events. + +Arguments: + + Priority - The task priority level of event notifications to dispatch + +Returns: + + None + +--*/ +{ + 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 & EFI_EVENT_NOTIFY_SIGNAL) { + Event->SignalCount = 0; + } + + CoreReleaseEventLock (); + + // + // Notify this event + // + ASSERT (Event->NotifyFunction != NULL); + Event->NotifyFunction (Event, Event->NotifyContext); + + // + // Check for next pending event + // + CoreAcquireEventLock (); + } + + gEventPending &= ~(1 << Priority); + CoreReleaseEventLock (); +} + + +VOID +STATIC +CoreNotifyEvent ( + IN IEVENT *Event + ) +/*++ + +Routine Description: + + Queues the event's notification function to fire + +Arguments: + + Event - The Event to notify + +Returns: + + None + +--*/ +{ + + // + // 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); +} + + + +VOID +CoreNotifySignalList ( + IN EFI_GUID *EventGroup + ) +/*++ + +Routine Description: + Signals all events in the EventGroup + +Arguments: + EventGroup - The list to signal + +Returns: + + None + +--*/ +{ + 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 (); +} + + +#if (EFI_SPECIFICATION_VERSION < 0x00020000) + +static +VOID +EFIAPI +EventNofitySignalAllNullEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + // + // This null event is a size efficent way to enusre that + // EFI_EVENT_NOTIFY_SIGNAL_ALL is error checked correctly. + // EFI_EVENT_NOTIFY_SIGNAL_ALL is now mapped into + // CreateEventEx() and this function is used to make the + // old error checking in CreateEvent() for Tiano extensions + // function. + // + return; +} + +#endif + + + + +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 + ) +/*++ + +Routine Description: + Creates a general-purpose event structure + +Arguments: + Type - The type of event to create and its mode and attributes + NotifyTpl - The task priority level of event notifications + NotifyFunction - Pointer to the events notification function + NotifyContext - Pointer to the notification functions context; corresponds to + parameter "Context" in the notification function + Event - Pointer to the newly created event if the call succeeds; undefined otherwise + +Returns: + EFI_SUCCESS - The event structure was created + EFI_INVALID_PARAMETER - One of the parameters has an invalid value + EFI_OUT_OF_RESOURCES - The event could not be allocated + +--*/ +{ + EFI_GUID *GuidPtr; + EFI_EVENT_NOTIFY Function; + + GuidPtr = NULL; + Function = NotifyFunction; + +#if (EFI_SPECIFICATION_VERSION < 0x00020000) + // + // Clear EFI_EVENT_NOFITY_SIGNAL_ALL (Tiano extension) as all events in the + // EventGroup now have this property. So we need to filter it out. + // + if (Type & EFI_EVENT_NOTIFY_SIGNAL_ALL) { + Type &= ~EFI_EVENT_NOTIFY_SIGNAL_ALL; + Function = EventNofitySignalAllNullEvent; + } + + // + // Map the Tiano extensions Events to CreateEventEx form + // + if (Type == EFI_EVENT_SIGNAL_READY_TO_BOOT) { + GuidPtr = &gEfiEventReadToBootGuid; + } else if (Type == EFI_EVENT_SIGNAL_LEGACY_BOOT) { + GuidPtr = &gEfiEventLegacyBootGuid + } +#endif + + // + // Convert EFI 1.10 Events to thier UEFI 2.0 CreateEventEx mapping + // + if (Type == EVENT_SIGNAL_EXIT_BOOT_SERVICES) { + GuidPtr = &gEfiEventExitBootServicesGuid; + } else if (Type == EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) { + GuidPtr = &gEfiEventVirtualAddressChangeGuid; + } + + return CoreCreateEventEx (Type, NotifyTpl, Function, NotifyContext, GuidPtr, Event); +} + + +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 + ) +/*++ + +Routine Description: + Creates a general-purpose event structure + +Arguments: + Type - The type of event to create and its mode and attributes + NotifyTpl - The task priority level of event notifications + NotifyFunction - Pointer to the events notification function + NotifyContext - Pointer to the notification functions context; corresponds to + parameter "Context" in the notification function + EventGrout - GUID for EventGroup if NULL act the same as gBS->CreateEvent(). + Event - Pointer to the newly created event if the call succeeds; undefined otherwise + +Returns: + EFI_SUCCESS - The event structure was created + EFI_INVALID_PARAMETER - One of the parameters has an invalid value + EFI_OUT_OF_RESOURCES - The event could not be allocated + +--*/ +{ + EFI_STATUS Status; + IEVENT *IEvent; + INTN Index; + + + if ((Event == NULL) || (NotifyTpl == EFI_TPL_APPLICATION)) { + 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; + } + + // + // If it's a notify type of event, check its parameters + // + if ((Type & (EFI_EVENT_NOTIFY_WAIT | EFI_EVENT_NOTIFY_SIGNAL))) { + // + // Check for an invalid NotifyFunction or NotifyTpl + // + if ((NotifyFunction == NULL) || + (NotifyTpl < EFI_TPL_APPLICATION) || + (NotifyTpl >= EFI_TPL_HIGH_LEVEL)) { + return EFI_INVALID_PARAMETER; + } + + } else { + // + // No notification needed, zero ignored values + // + NotifyTpl = 0; + NotifyFunction = NULL; + NotifyContext = NULL; + } + + // + // Allcoate and initialize a new event structure. + // + Status = CoreAllocatePool ( + (Type & EFI_EVENT_RUNTIME) ? EfiRuntimeServicesData: EfiBootServicesData, + sizeof (IEVENT), + (VOID **)&IEvent + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + SetMem (IEvent, sizeof (IEVENT), 0); + + 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 = TRUE; + } + + *Event = IEvent; + + if (Type & EFI_EVENT_RUNTIME) { + // + // Keep a list of all RT events so we can tell the RT AP. + // + InsertTailList (&mRuntimeEventList, &IEvent->RuntimeLink); + } + + CoreAcquireEventLock (); + + if ((Type & EFI_EVENT_NOTIFY_SIGNAL) != 0x00000000) { + // + // The Event's NotifyFunction must be queued whenever the event is signaled + // + InsertHeadList (&gEventSignalQueue, &IEvent->SignalLink); + } + + CoreReleaseEventLock (); + + // + // Done + // + return EFI_SUCCESS; +} + + + +EFI_STATUS +EFIAPI +CoreSignalEvent ( + IN EFI_EVENT UserEvent + ) +/*++ + +Routine Description: + + Signals the event. Queues the event to be notified if needed + +Arguments: + + UserEvent - The event to signal + +Returns: + + EFI_INVALID_PARAMETER - Parameters are not valid. + + EFI_SUCCESS - The event was signaled. + +--*/ +{ + 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 & EFI_EVENT_NOTIFY_SIGNAL) { + if (Event->ExFlag) { + // + // 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; +} + + +EFI_STATUS +EFIAPI +CoreCheckEvent ( + IN EFI_EVENT UserEvent + ) +/*++ + +Routine Description: + + Check the status of an event + +Arguments: + + UserEvent - The event to check + +Returns: + + EFI_SUCCESS - The event is in the signaled state + EFI_NOT_READY - The event is not in the signaled state + EFI_INVALID_PARAMETER - Event is of type EVT_NOTIFY_SIGNAL + +--*/ + +{ + 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 & EFI_EVENT_NOTIFY_SIGNAL) { + return EFI_INVALID_PARAMETER; + } + + Status = EFI_NOT_READY; + + if (!Event->SignalCount && (Event->Type & EFI_EVENT_NOTIFY_WAIT)) { + + // + // Queue the wait notify function + // + + CoreAcquireEventLock (); + if (!Event->SignalCount) { + CoreNotifyEvent (Event); + } + CoreReleaseEventLock (); + } + + // + // If the even looks signalled, get the lock and clear it + // + + if (Event->SignalCount) { + CoreAcquireEventLock (); + + if (Event->SignalCount) { + Event->SignalCount = 0; + Status = EFI_SUCCESS; + } + + CoreReleaseEventLock (); + } + + return Status; +} + + + +EFI_STATUS +EFIAPI +CoreWaitForEvent ( + IN UINTN NumberOfEvents, + IN EFI_EVENT *UserEvents, + OUT UINTN *UserIndex + ) +/*++ + +Routine Description: + + Stops execution until an event is signaled. + +Arguments: + + NumberOfEvents - The number of events in the UserEvents array + UserEvents - An array of EFI_EVENT + UserIndex - Pointer to the index of the event which satisfied the wait condition + +Returns: + + EFI_SUCCESS - The event indicated by Index was signaled. + EFI_INVALID_PARAMETER - The event indicated by Index has a notification function or + Event was not a valid type + EFI_UNSUPPORTED - The current TPL is not TPL_APPLICATION + +--*/ + +{ + EFI_STATUS Status; + UINTN Index; + + // + // Can only WaitForEvent at TPL_APPLICATION + // + if (gEfiCurrentTpl != EFI_TPL_APPLICATION) { + return EFI_UNSUPPORTED; + } + + for(;;) { + + for(Index = 0; Index < NumberOfEvents; Index++) { + + Status = CoreCheckEvent (UserEvents[Index]); + + // + // provide index of event that caused problem + // + if (Status != EFI_NOT_READY) { + *UserIndex = Index; + return Status; + } + } + + // + // This was the location of the Idle loop callback in EFI 1.x reference + // code. We don't have that concept in this base at this point. + // + } +} + + +EFI_STATUS +EFIAPI +CoreCloseEvent ( + IN EFI_EVENT UserEvent + ) +/*++ + +Routine Description: + + Closes an event and frees the event structure. + +Arguments: + + UserEvent - Event to close + +Returns: + + EFI_INVALID_PARAMETER - Parameters are not valid. + + EFI_SUCCESS - The event has been closed + +--*/ + +{ + 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 & EFI_EVENT_TIMER) { + CoreSetTimer (Event, TimerCancel, 0); + } + + CoreAcquireEventLock (); + + // + // If the event is queued somewhere, remove it + // + + if (Event->RuntimeLink.ForwardLink != NULL) { + RemoveEntryList (&Event->RuntimeLink); + } + + 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 + // + CoreUnregisterProtocolNotify (Event); + + Status = CoreFreePool (Event); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/EdkModulePkg/Core/Dxe/Event/execdata.c b/EdkModulePkg/Core/Dxe/Event/execdata.c new file mode 100644 index 0000000000..e7a11c2400 --- /dev/null +++ b/EdkModulePkg/Core/Dxe/Event/execdata.c @@ -0,0 +1,55 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + execdata.c + +Abstract: + + + + +Revision History + +--*/ + +#include + + +// +// gTpl - Task priority level +// +EFI_TPL gEfiCurrentTpl = EFI_TPL_APPLICATION; + + +// +// gEventQueueLock - Protects the event queus +// +EFI_LOCK gEventQueueLock = EFI_INITIALIZE_LOCK_VARIABLE (EFI_TPL_HIGH_LEVEL); + +// +// gEventQueue - A list of event's to notify for each priority level +// gEventPending - A bitmask of the EventQueues that are pending +// +LIST_ENTRY gEventQueue[EFI_TPL_HIGH_LEVEL + 1]; +UINTN gEventPending = 0; + + +// +// gEventSignalQueue - A list of events to signal based on EventGroup type +// +LIST_ENTRY gEventSignalQueue = INITIALIZE_LIST_HEAD_VARIABLE (gEventSignalQueue); + +// +// LIST of runtime events that need to be fired by RT AP. +// +LIST_ENTRY mRuntimeEventList = INITIALIZE_LIST_HEAD_VARIABLE (mRuntimeEventList); diff --git a/EdkModulePkg/Core/Dxe/Event/timer.c b/EdkModulePkg/Core/Dxe/Event/timer.c new file mode 100644 index 0000000000..8d7932f837 --- /dev/null +++ b/EdkModulePkg/Core/Dxe/Event/timer.c @@ -0,0 +1,386 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + timer.c + +Abstract: + + EFI Event support + +Revision History + +--*/ + + +#include + +// +// Internal prototypes +// +STATIC +UINT64 +CoreCurrentSystemTime ( + VOID + ); + +VOID +EFIAPI +CoreCheckTimers ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +STATIC +VOID +CoreInsertEventTimer ( + IN IEVENT *Event + ); + +// +// Internal data +// + +static LIST_ENTRY mEfiTimerList = INITIALIZE_LIST_HEAD_VARIABLE (mEfiTimerList); +static EFI_LOCK mEfiTimerLock = EFI_INITIALIZE_LOCK_VARIABLE (EFI_TPL_HIGH_LEVEL - 1); +static EFI_EVENT mEfiCheckTimerEvent; + +static EFI_LOCK mEfiSystemTimeLock = EFI_INITIALIZE_LOCK_VARIABLE (EFI_TPL_HIGH_LEVEL); +static UINT64 mEfiSystemTime = 0; + +// +// Timer functions +// + +VOID +CoreInitializeTimer ( + VOID + ) +/*++ + +Routine Description: + + Initializes timer support + +Arguments: + + None + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + + Status = CoreCreateEvent ( + EFI_EVENT_NOTIFY_SIGNAL, + EFI_TPL_HIGH_LEVEL - 1, + CoreCheckTimers, + NULL, + &mEfiCheckTimerEvent + ); + ASSERT_EFI_ERROR (Status); +} + +STATIC +UINT64 +CoreCurrentSystemTime ( + VOID + ) +/*++ + +Routine Description: + + Returns the current system time + +Arguments: + + None + +Returns: + + Returns the current system time + +--*/ +{ + UINT64 SystemTime; + + CoreAcquireLock (&mEfiSystemTimeLock); + SystemTime = mEfiSystemTime; + CoreReleaseLock (&mEfiSystemTimeLock); + return SystemTime; +} + +VOID +EFIAPI +CoreTimerTick ( + IN UINT64 Duration + ) +/*++ + +Routine Description: + + Called by the platform code to process a tick. + +Arguments: + + Duration - The number of 100ns elasped since the last call to TimerTick + +Returns: + + None + +--*/ +{ + 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, u.Timer.Link, EVENT_SIGNATURE); + + if (Event->u.Timer.TriggerTime <= mEfiSystemTime) { + CoreSignalEvent (mEfiCheckTimerEvent); + } + } + + CoreReleaseLock (&mEfiSystemTimeLock); +} + +VOID +EFIAPI +CoreCheckTimers ( + IN EFI_EVENT CheckEvent, + IN VOID *Context + ) +/*++ + +Routine Description: + + Checks the sorted timer list against the current system time. + Signals any expired event timer. + +Arguments: + + CheckEvent - Not used + + Context - Not used + +Returns: + + None + +--*/ +{ + UINT64 SystemTime; + IEVENT *Event; + + // + // Check the timer database for expired timers + // + + CoreAcquireLock (&mEfiTimerLock); + SystemTime = CoreCurrentSystemTime (); + + while (!IsListEmpty (&mEfiTimerList)) { + Event = CR (mEfiTimerList.ForwardLink, IEVENT, u.Timer.Link, EVENT_SIGNATURE); + + // + // If this timer is not expired, then we're done + // + + if (Event->u.Timer.TriggerTime > SystemTime) { + break; + } + + // + // Remove this timer from the timer queue + // + + RemoveEntryList (&Event->u.Timer.Link); + Event->u.Timer.Link.ForwardLink = NULL; + + // + // Signal it + // + CoreSignalEvent (Event); + + // + // If this is a periodic timer, set it + // + if (Event->u.Timer.Period) { + + // + // Compute the timers new trigger time + // + + Event->u.Timer.TriggerTime = Event->u.Timer.TriggerTime + Event->u.Timer.Period; + + // + // If that's before now, then reset the timer to start from now + // + if (Event->u.Timer.TriggerTime <= SystemTime) { + Event->u.Timer.TriggerTime = SystemTime; + CoreSignalEvent (mEfiCheckTimerEvent); + } + + // + // Add the timer + // + + CoreInsertEventTimer (Event); + } + } + + CoreReleaseLock (&mEfiTimerLock); +} + +STATIC +VOID +CoreInsertEventTimer ( + IN IEVENT *Event + ) +/*++ + +Routine Description: + + Inserts the timer event + +Arguments: + + Event - Points to the internal structure of timer event to be installed + +Returns: + + None + +--*/ +{ + UINT64 TriggerTime; + LIST_ENTRY *Link; + IEVENT *Event2; + + ASSERT_LOCKED (&mEfiTimerLock); + + // + // Get the timer's trigger time + // + + TriggerTime = Event->u.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, u.Timer.Link, EVENT_SIGNATURE); + + if (Event2->u.Timer.TriggerTime > TriggerTime) { + break; + } + } + + InsertTailList (Link, &Event->u.Timer.Link); +} + + + +EFI_STATUS +EFIAPI +CoreSetTimer ( + IN EFI_EVENT UserEvent, + IN EFI_TIMER_DELAY Type, + IN UINT64 TriggerTime + ) +/*++ + +Routine Description: + + Sets the type of timer and the trigger time for a timer event. + +Arguments: + + UserEvent - The timer event that is to be signaled at the specified time + Type - The type of time that is specified in TriggerTime + TriggerTime - The number of 100ns units until the timer expires + +Returns: + + EFI_SUCCESS - The event has been set to be signaled at the requested time + EFI_INVALID_PARAMETER - Event or Type is not valid + +--*/ +{ + IEVENT *Event; + + Event = UserEvent; + + if (Event == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Event->Signature != EVENT_SIGNATURE) { + return EFI_INVALID_PARAMETER; + } + + if (Type < 0 || Type > TimerRelative || !(Event->Type & EFI_EVENT_TIMER)) { + return EFI_INVALID_PARAMETER; + } + + CoreAcquireLock (&mEfiTimerLock); + + // + // If the timer is queued to the timer database, remove it + // + + if (Event->u.Timer.Link.ForwardLink != NULL) { + RemoveEntryList (&Event->u.Timer.Link); + Event->u.Timer.Link.ForwardLink = NULL; + } + + Event->u.Timer.TriggerTime = 0; + Event->u.Timer.Period = 0; + + if (Type != TimerCancel) { + + if (Type == TimerPeriodic) { + Event->u.Timer.Period = TriggerTime; + } + + Event->u.Timer.TriggerTime = CoreCurrentSystemTime () + TriggerTime; + CoreInsertEventTimer (Event); + + if (TriggerTime == 0) { + CoreSignalEvent (mEfiCheckTimerEvent); + } + } + + CoreReleaseLock (&mEfiTimerLock); + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Core/Dxe/Event/tpl.c b/EdkModulePkg/Core/Dxe/Event/tpl.c new file mode 100644 index 0000000000..ae851638af --- /dev/null +++ b/EdkModulePkg/Core/Dxe/Event/tpl.c @@ -0,0 +1,198 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + tpl.c + +Abstract: + + Task priority function + +--*/ + +#include + +STATIC +VOID +CoreSetInterruptState ( + IN BOOLEAN Enable + ) +/*++ + +Routine Description: + + Set Interrupt State + +Arguments: + + Enable - The state of enable or disable interrupt + +Returns: + + None + +--*/ + +{ + if (gCpu != NULL) { + if (Enable) { + gCpu->EnableInterrupt(gCpu); + } else { + gCpu->DisableInterrupt(gCpu); + } + } +} + +// +// Return the highest set bit +// +UINTN +CoreHighestSetBit ( + IN UINTN Number + ) +/*++ + +Routine Description: + + Return the highest set bit + +Arguments: + + Number - The value to check + +Returns: + + Bit position of the highest set bit + +--*/ +{ + UINTN msb; + + msb = 31; + while ((msb > 0) && ((Number & (UINTN)(1 << msb)) == 0)) { + msb--; + } + + return msb; +} + + + +EFI_TPL +EFIAPI +CoreRaiseTpl ( + IN EFI_TPL NewTpl + ) +/*++ + +Routine Description: + + Raise the task priority level to the new level. + High level is implemented by disabling processor interrupts. + +Arguments: + + NewTpl - New task priority level + +Returns: + + The previous task priority level + +--*/ +{ + EFI_TPL OldTpl; + + OldTpl = gEfiCurrentTpl; + ASSERT (OldTpl <= NewTpl); + ASSERT (VALID_TPL (NewTpl)); + + // + // If raising to high level, disable interrupts + // + if (NewTpl >= EFI_TPL_HIGH_LEVEL && OldTpl < EFI_TPL_HIGH_LEVEL) { + CoreSetInterruptState (FALSE); + } + + // + // Set the new value + // + gEfiCurrentTpl = NewTpl; + + return OldTpl; +} + + + +VOID +EFIAPI +CoreRestoreTpl ( + IN EFI_TPL NewTpl + ) +/*++ + +Routine Description: + + Lowers the task priority to the previous value. If the new + priority unmasks events at a higher priority, they are dispatched. + +Arguments: + + NewTpl - New, lower, task priority + +Returns: + + None + +--*/ +{ + EFI_TPL OldTpl; + + OldTpl = gEfiCurrentTpl; + ASSERT (NewTpl <= OldTpl); + ASSERT (VALID_TPL (NewTpl)); + + // + // If lowering below HIGH_LEVEL, make sure + // interrupts are enabled + // + + if (OldTpl >= EFI_TPL_HIGH_LEVEL && NewTpl < EFI_TPL_HIGH_LEVEL) { + gEfiCurrentTpl = EFI_TPL_HIGH_LEVEL; + } + + // + // Dispatch any pending events + // + + while ((-2 << NewTpl) & gEventPending) { + gEfiCurrentTpl = CoreHighestSetBit (gEventPending); + if (gEfiCurrentTpl < EFI_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 < EFI_TPL_HIGH_LEVEL) { + CoreSetInterruptState (TRUE); + } + +} diff --git a/EdkModulePkg/Core/Dxe/FwVol/Ffs.c b/EdkModulePkg/Core/Dxe/FwVol/Ffs.c new file mode 100644 index 0000000000..6f7d353e05 --- /dev/null +++ b/EdkModulePkg/Core/Dxe/FwVol/Ffs.c @@ -0,0 +1,266 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Ffs.c + +Abstract: + + FFS file access utilities. + +--*/ + + +#include + +#define PHYSICAL_ADDRESS_TO_POINTER(Address) ((VOID *)((UINTN)(Address))) + + +EFI_FFS_FILE_STATE +GetFileState ( + IN UINT8 ErasePolarity, + IN EFI_FFS_FILE_HEADER *FfsHeader + ) +/*++ + +Routine Description: + Get the FFS file state by checking the highest bit set in the header's state field + +Arguments: + ErasePolarity - Erase polarity attribute of the firmware volume + FfsHeader - Points to the FFS file header + +Returns: + FFS File state + +--*/ +{ + 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; +} + + +BOOLEAN +IsBufferErased ( + IN UINT8 ErasePolarity, + IN VOID *InBuffer, + IN UINTN BufferSize + ) +/*++ + +Routine Description: + Check if a block of buffer is erased + +Arguments: + ErasePolarity - Erase polarity attribute of the firmware volume + InBuffer - The buffer to be checked + BufferSize - Size of the buffer in bytes + +Returns: + TRUE - The block of buffer is erased + FALSE - The block of buffer is not erased + +--*/ +{ + 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; +} + + +BOOLEAN +VerifyFvHeaderChecksum ( + IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader + ) +/*++ + +Routine Description: + Verify checksum of the firmware volume header + +Arguments: + FvHeader - Points to the firmware volume header to be checked + +Returns: + TRUE - Checksum verification passed + FALSE - Checksum verification failed + +--*/ +{ + UINT32 Index; + UINT32 HeaderLength; + UINT16 Checksum; + UINT16 *ptr; + + HeaderLength = FvHeader->HeaderLength; + ptr = (UINT16 *)FvHeader; + Checksum = 0; + + for (Index = 0; Index < HeaderLength / sizeof (UINT16); Index++) { + Checksum = (UINT16)(Checksum + ptr[Index]); + } + + if (Checksum == 0) { + return TRUE; + } else { + return FALSE; + } +} + + +BOOLEAN +VerifyHeaderChecksum ( + IN EFI_FFS_FILE_HEADER *FfsHeader + ) +/*++ + +Routine Description: + Verify checksum of the FFS file header + +Arguments: + FfsHeader - Points to the FFS file header to be checked + +Returns: + TRUE - Checksum verification passed + FALSE - Checksum verification failed + +--*/ +{ + UINT32 Index; + UINT8 *ptr; + UINT8 HeaderChecksum; + + ptr = (UINT8 *)FfsHeader; + HeaderChecksum = 0; + for (Index = 0; Index < sizeof(EFI_FFS_FILE_HEADER); Index++) { + HeaderChecksum = (UINT8)(HeaderChecksum + ptr[Index]); + } + + HeaderChecksum = HeaderChecksum - FfsHeader->State - FfsHeader->IntegrityCheck.Checksum.File; + + if (HeaderChecksum == 0) { + return TRUE; + } else { + return FALSE; + } +} + + +BOOLEAN +IsValidFfsHeader ( + IN UINT8 ErasePolarity, + IN EFI_FFS_FILE_HEADER *FfsHeader, + OUT EFI_FFS_FILE_STATE *FileState + ) +/*++ + +Routine Description: + Check if it's a valid FFS file header + +Arguments: + ErasePolarity - Erase polarity attribute of the firmware volume + FfsHeader - Points to the FFS file header to be checked + FileState - FFS file state to be returned + +Returns: + TRUE - Valid FFS file header + FALSE - Invalid FFS file header + +--*/ +{ + *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; + } +} + + +BOOLEAN +IsValidFfsFile ( + IN UINT8 ErasePolarity, + IN EFI_FFS_FILE_HEADER *FfsHeader + ) +/*++ + +Routine Description: + 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. + +Arguments: + ErasePolarity - Erase polarity attribute of the firmware volume + FfsHeader - Points to the FFS file to be checked + +Returns: + TRUE - Valid FFS file + FALSE - Invalid FFS file + +--*/ +{ + EFI_FFS_FILE_STATE FileState; + + FileState = GetFileState (ErasePolarity, FfsHeader); + switch (FileState) { + + case EFI_FILE_DELETED: + case EFI_FILE_DATA_VALID: + case EFI_FILE_MARKED_FOR_UPDATE: + // + // Some other vliadation like file content checksum might be done here. + // For performance issue, Tiano only do FileState check. + // + return TRUE; + + default: + return FALSE; + } +} + diff --git a/EdkModulePkg/Core/Dxe/FwVol/FwVol.c b/EdkModulePkg/Core/Dxe/FwVol/FwVol.c new file mode 100644 index 0000000000..d8137d79c6 --- /dev/null +++ b/EdkModulePkg/Core/Dxe/FwVol/FwVol.c @@ -0,0 +1,553 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FwVol.c + +Abstract: + + 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. + +--*/ + +#include + +#define KEYSIZE sizeof (UINTN) + +// +// Protocol notify related globals +// +VOID *gEfiFwVolBlockNotifyReg; +EFI_EVENT gEfiFwVolBlockEvent; + +FV_DEVICE mFvDevice = { + FV_DEVICE_SIGNATURE, + NULL, + NULL, + { + FvGetVolumeAttributes, + FvSetVolumeAttributes, + FvReadFile, + FvReadFileSection, + FvWriteFile, + FvGetNextFile, + KEYSIZE + }, + NULL, + NULL, + NULL, + NULL, + { NULL, NULL }, + 0 +}; + + +// +// FFS helper functions +// + +EFI_STATUS +GetFwVolHeader ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb, + OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader + ) +/*++ + +Routine Description: + given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and + copy the volume header into it. + +Arguments: + Fvb - The FW_VOL_BLOCK_PROTOCOL instance from which to read the volume + header + FwVolHeader - Pointer to pointer to allocated buffer in which the volume + header is returned. + +Returns: + EFI_OUT_OF_RESOURCES - No enough buffer could be allocated. + EFI_SUCCESS - Successfully read volume header to the allocated buffer. + +--*/ + +{ + EFI_STATUS Status; + EFI_FIRMWARE_VOLUME_HEADER TempFvh; + UINTN FvhLength; + UINT8 *Buffer; + + + // + //Determine the real length of FV header + // + FvhLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER); + Status = Fvb->Read (Fvb, 0, 0, &FvhLength, (UINT8 *)&TempFvh); + + // + // Allocate a buffer for the caller + // + *FwVolHeader = CoreAllocateBootServicesPool (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 = Fvb->Read (Fvb, 0, sizeof (EFI_FIRMWARE_VOLUME_HEADER), &FvhLength, Buffer); + if (EFI_ERROR (Status)) { + // + // Read failed so free buffer + // + CoreFreePool (*FwVolHeader); + } + + return Status; +} + + +STATIC +VOID +FreeFvDeviceResource ( + IN FV_DEVICE *FvDevice + ) +/*++ + +Routine Description: + Free FvDevice resource when error happens + +Arguments: + FvDevice - pointer to the FvDevice to be freed. + +Returns: + None. + +--*/ +{ + 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 + // + FfsFileEntry->Sep->CloseSectionStream (FfsFileEntry->Sep, FfsFileEntry->StreamHandle); + } + + CoreFreePool (FfsFileEntry); + + FfsFileEntry = (FFS_FILE_LIST_ENTRY *)NextEntry; + } + + + // + // Free the cache + // + CoreFreePool (FvDevice->CachedFv); + + // + // Free Volume Header + // + CoreFreePool (FvDevice->FwVolHeader); + + return; +} + + +EFI_STATUS +FvCheck ( + IN OUT FV_DEVICE *FvDevice + ) +/*++ + +Routine Description: + Check if a FV is consistent and allocate cache + +Arguments: + FvDevice - pointer to the FvDevice to be checked. + +Returns: + EFI_OUT_OF_RESOURCES - No enough buffer could be allocated. + EFI_SUCCESS - FV is consistent and cache is allocated. + EFI_VOLUME_CORRUPTED - File system is corrupted. + +--*/ +{ + EFI_STATUS Status; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_FVB_ATTRIBUTES FvbAttributes; + EFI_FV_BLOCK_MAP_ENTRY *BlockMap; + FFS_FILE_LIST_ENTRY *FfsFileEntry; + EFI_FFS_FILE_HEADER *FfsHeader; + UINT8 *CacheLocation; + UINTN LbaOffset; + UINTN Index; + EFI_LBA LbaIndex; + UINTN Size; + UINTN FileLength; + EFI_FFS_FILE_STATE FileState; + UINT8 *TopFvAddress; + UINTN TestLength; + + + Fvb = FvDevice->Fvb; + FwVolHeader = FvDevice->FwVolHeader; + + Status = Fvb->GetVolumeAttributes (Fvb, &FvbAttributes); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Size is the size of the FV minus the head. We have already allocated + // the header to check to make sure the volume is valid + // + Size = (UINTN)(FwVolHeader->FvLength - FwVolHeader->HeaderLength); + FvDevice->CachedFv = CoreAllocateZeroBootServicesPool (Size); + if (FvDevice->CachedFv == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Remember a pointer to the end fo the CachedFv + // + FvDevice->EndOfCachedFv = FvDevice->CachedFv + Size; + + // + // Copy FV minus header into memory using the block map we have all ready + // read into memory. + // + BlockMap = FwVolHeader->FvBlockMap; + CacheLocation = FvDevice->CachedFv; + LbaIndex = 0; + LbaOffset = FwVolHeader->HeaderLength; + while ((BlockMap->NumBlocks != 0) || (BlockMap->BlockLength != 0)) { + + for (Index = 0; Index < BlockMap->NumBlocks; Index ++) { + + Size = BlockMap->BlockLength; + if (Index == 0) { + // + // Cache does not include FV Header + // + Size -= LbaOffset; + } + Status = Fvb->Read (Fvb, + LbaIndex, + LbaOffset, + &Size, + CacheLocation + ); + // + // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->BlockLength + // + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // After we skip Fv Header always read from start of block + // + LbaOffset = 0; + + LbaIndex++; + CacheLocation += Size; + } + BlockMap++; + } + + // + // Scan to check the free space & File list + // + if (FvbAttributes & EFI_FVB_ERASE_POLARITY) { + FvDevice->ErasePolarity = 1; + } else { + FvDevice->ErasePolarity = 0; + } + + + // + // go through the whole FV cache, check the consistence of the FV. + // Make a linked list off all the Ffs file headers + // + Status = EFI_SUCCESS; + InitializeListHead (&FvDevice->FfsFileListHeader); + + // + // Build FFS list + // + FfsHeader = (EFI_FFS_FILE_HEADER *)FvDevice->CachedFv; + TopFvAddress = FvDevice->EndOfCachedFv; + while ((UINT8 *)FfsHeader < TopFvAddress) { + + 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)) { + FfsHeader++; + + continue; + + } else { + // + // File system is corrputed + // + Status = EFI_VOLUME_CORRUPTED; + goto Done; + } + } + + if (!IsValidFfsFile (FvDevice->ErasePolarity, FfsHeader)) { + // + // File system is corrupted + // + Status = EFI_VOLUME_CORRUPTED; + goto Done; + } + + // + // Size[3] is a three byte array, read 4 bytes and throw one away + // + FileLength = *(UINT32 *)&FfsHeader->Size[0] & 0x00FFFFFF; + + FileState = GetFileState (FvDevice->ErasePolarity, FfsHeader); + + // + // check for non-deleted file + // + if (FileState != EFI_FILE_DELETED) { + // + // Create a FFS list entry for each non-deleted file + // + FfsFileEntry = CoreAllocateZeroBootServicesPool (sizeof (FFS_FILE_LIST_ENTRY)); + if (FfsFileEntry == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + FfsFileEntry->FfsHeader = FfsHeader; + InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link); + } + + FfsHeader = (EFI_FFS_FILE_HEADER *)(((UINT8 *)FfsHeader) + FileLength); + + // + // Adjust pointer to the next 8-byte aligned boundry. + // + FfsHeader = (EFI_FFS_FILE_HEADER *)(((UINTN)FfsHeader + 7) & ~0x07); + + } + +Done: + if (EFI_ERROR (Status)) { + FreeFvDeviceResource (FvDevice); + } + + return Status; +} + + +STATIC +VOID +EFIAPI +NotifyFwVolBlock ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + This notification function is invoked when an instance of the + EFI_FW_VOLUME_BLOCK_PROTOCOL is produced. It layers an instance of the + EFI_FIRMWARE_VOLUME_PROTOCOL on the same handle. This is the function where + the actual initialization of the EFI_FIRMWARE_VOLUME_PROTOCOL is done. + +Arguments: + Event - The event that occured + Context - For EFI compatiblity. Not used. + +Returns: + + None. + +--*/ +{ + EFI_HANDLE Handle; + EFI_STATUS Status; + UINTN BufferSize; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; + EFI_FIRMWARE_VOLUME_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); + + + // + // Make sure the Fv Header is O.K. + // + Status = GetFwVolHeader (Fvb, &FwVolHeader); + if (EFI_ERROR (Status)) { + return; + } + + if (!VerifyFvHeaderChecksum (FwVolHeader)) { + CoreFreePool (FwVolHeader); + continue; + } + + + // + // Check to see that the file system is indeed formatted in a way we can + // understand it... + // + if (!CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystemGuid)) { + continue; + } + + // + // Check if there is an FV protocol already installed in that handle + // + Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolumeProtocolGuid, (VOID **)&Fv); + if (!EFI_ERROR (Status)) { + // + // Update Fv to use a new Fvb + // + FvDevice = _CR (Fv, FV_DEVICE, Fv); + if (FvDevice->Signature == FV_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 = CoreAllocateCopyPool (sizeof (FV_DEVICE), &mFvDevice); + if (FvDevice == NULL) { + return; + } + + FvDevice->Fvb = Fvb; + FvDevice->Handle = Handle; + FvDevice->FwVolHeader = FwVolHeader; + FvDevice->Fv.ParentHandle = Fvb->ParentHandle; + + // + // Install an New FV protocol on the existing handle + // + Status = CoreInstallProtocolInterface ( + &Handle, + &gEfiFirmwareVolumeProtocolGuid, + EFI_NATIVE_INTERFACE, + &FvDevice->Fv + ); + ASSERT_EFI_ERROR (Status); + } + } + + return; +} + + +EFI_STATUS +EFIAPI +FwVolDriverInit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + 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. + +Arguments: + ImageHandle - The image handle. + SystemTable - The system table. + +Returns: + EFI_SUCCESS - Function successfully returned. + +--*/ +{ + gEfiFwVolBlockEvent = CoreCreateProtocolNotifyEvent ( + &gEfiFirmwareVolumeBlockProtocolGuid, + EFI_TPL_CALLBACK, + NotifyFwVolBlock, + NULL, + &gEfiFwVolBlockNotifyReg, + TRUE + ); + return EFI_SUCCESS; +} + diff --git a/EdkModulePkg/Core/Dxe/FwVol/FwVolAttrib.c b/EdkModulePkg/Core/Dxe/FwVol/FwVolAttrib.c new file mode 100644 index 0000000000..8a44653282 --- /dev/null +++ b/EdkModulePkg/Core/Dxe/FwVol/FwVolAttrib.c @@ -0,0 +1,99 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FwVolAttrib.c + +Abstract: + + Implements get/set firmware volume attributes + +--*/ + +#include + +EFI_STATUS +EFIAPI +FvGetVolumeAttributes ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, + OUT EFI_FV_ATTRIBUTES *Attributes + ) +/*++ + +Routine Description: + Retrieves attributes, insures positive polarity of attribute bits, returns + resulting attributes in output parameter + +Arguments: + This - Calling context + Attributes - output buffer which contains attributes + +Returns: + EFI_SUCCESS - Successfully got volume attributes + +--*/ +{ + EFI_STATUS Status; + FV_DEVICE *FvDevice; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; + EFI_FVB_ATTRIBUTES FvbAttributes; + + FvDevice = FV_DEVICE_FROM_THIS (This); + Fvb = FvDevice->Fvb; + + if (FvDevice->CachedFv == NULL) { + Status = FvCheck (FvDevice); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // First get the Firmware Volume Block Attributes + // + Status = Fvb->GetVolumeAttributes (Fvb, &FvbAttributes); + + // + // Mask out Fvb bits that are not defined in FV + // + FvbAttributes &= 0xfffff0ff; + + *Attributes = (EFI_FV_ATTRIBUTES)FvbAttributes; + + return Status; +} + + +EFI_STATUS +EFIAPI +FvSetVolumeAttributes ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, + IN OUT EFI_FV_ATTRIBUTES *Attributes + ) +/*++ + +Routine Description: + Sets current attributes for volume + +Arguments: + This - Calling context + Attributes - At input, contains attributes to be set. At output contains + new value of FV + +Returns: + EFI_UNSUPPORTED - Could not be set. + +--*/ +{ + return EFI_UNSUPPORTED; +} + diff --git a/EdkModulePkg/Core/Dxe/FwVol/FwVolRead.c b/EdkModulePkg/Core/Dxe/FwVol/FwVolRead.c new file mode 100644 index 0000000000..ff2fcb8023 --- /dev/null +++ b/EdkModulePkg/Core/Dxe/FwVol/FwVolRead.c @@ -0,0 +1,516 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FwVolRead.c + +Abstract: + + Implements read firmware file + +--*/ + +#include + +/*++ + +Required Alignment Alignment Value in FFS Alignment Value in +(bytes) Attributes Field Firmware Volume Interfaces +1 0 0 +2 0 1 +4 0 2 +8 0 3 +16 1 4 +128 2 7 +512 3 9 +1 KB 4 10 +4 KB 5 12 +32 KB 6 15 +64 KB 7 16 + +--*/ + +UINT8 mFvAttributes[] = {0, 4, 7, 9, 10, 12, 15, 16}; + + +STATIC +EFI_FV_FILE_ATTRIBUTES +FfsAttributes2FvFileAttributes ( + IN EFI_FFS_FILE_ATTRIBUTES FfsAttributes + ) +/*++ + + Routine Description: + Convert the FFS File Attributes to FV File Attributes + + Arguments: + FfsAttributes - The attributes of UINT8 type. + + Returns: + The attributes of EFI_FV_FILE_ATTRIBUTES + +--*/ +{ + FfsAttributes = (EFI_FFS_FILE_ATTRIBUTES)((FfsAttributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3); + ASSERT (FfsAttributes < 8); + + return (EFI_FV_FILE_ATTRIBUTES) mFvAttributes[FfsAttributes]; +} + + +EFI_STATUS +EFIAPI +FvGetNextFile ( + IN EFI_FIRMWARE_VOLUME_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 + ) +/*++ + +Routine Description: + Given the input key, search for the next matching file in the volume. + +Arguments: + This - Indicates the calling context. + 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. + 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(). + 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. + 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. + 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. + +Returns: + EFI_SUCCESS - Successfully find the file. + EFI_DEVICE_ERROR - Device error. + EFI_ACCESS_DENIED - Fv could not read. + EFI_NOT_FOUND - No matching file found. + EFI_INVALID_PARAMETER - Invalid parameter + +--*/ +{ + 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; + UINTN FileLength; + + 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_FV_READ_STATUS) == 0) { + return EFI_ACCESS_DENIED; + } + + if (*FileType > EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) { + // + // File type needs to be in 0 - 0x0B + // + return EFI_INVALID_PARAMETER; + } + + 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 == 0) { + // + // 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; + CopyMem (NameGuid, &FfsFileHeader->Name, sizeof (EFI_GUID)); + *Attributes = FfsAttributes2FvFileAttributes (FfsFileHeader->Attributes); + + // + // Read four bytes out of the 3 byte array and throw out extra data + // + FileLength = *(UINT32 *)&FfsFileHeader->Size[0] & 0x00FFFFFF; + + // + // we need to substract the header size + // + *Size = FileLength - sizeof(EFI_FFS_FILE_HEADER); + + if (FfsFileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT) { + // + // If tail is present substract it's size; + // + *Size -= sizeof(EFI_FFS_FILE_TAIL); + } + + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +FvReadFile ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, + IN 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 + ) +/*++ + +Routine Description: + Locates a file in the firmware volume and + copies it to the supplied buffer. + +Arguments: + This - Indicates the calling context. + NameGuid - Pointer to an EFI_GUID, which is the filename. + Buffer - Buffer is a pointer to pointer to a buffer in + which the file or section contents or are returned. + 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. + 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. + 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. + AuthenticationStatus - AuthenticationStatus is a pointer to a caller + allocated UINTN in which the authentication status + is returned. +Returns: + EFI_SUCCESS - Successfully read to memory buffer. + EFI_WARN_BUFFER_TOO_SMALL - Buffer too small. + EFI_NOT_FOUND - Not found. + EFI_DEVICE_ERROR - Device error. + EFI_ACCESS_DENIED - Could not read. + EFI_INVALID_PARAMETER - Invalid parameter. + EFI_OUT_OF_RESOURCES - Not enough buffer to be allocated. + +--*/ +{ + 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; + + if (NULL == NameGuid) { + return EFI_INVALID_PARAMETER; + } + + FvDevice = FV_DEVICE_FROM_THIS (This); + + + // + // Keep looking until we find the matching NameGuid. + // The Key is really an 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; + + // + // Remember callers buffer size + // + InputBufferSize = *BufferSize; + + // + // Calculate return values + // + *FoundType = FfsHeader->Type; + *FileAttributes = FfsAttributes2FvFileAttributes (FfsHeader->Attributes); + *AuthenticationStatus = 0; + *BufferSize = FileSize; + + if (Buffer == NULL) { + // + // If Buffer is NULL, we only want to get the information colected so far + // + return EFI_SUCCESS; + } + + // + // Skip over file header + // + 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 = CoreAllocateBootServicesPool (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; +} + + +EFI_STATUS +EFIAPI +FvReadFileSection ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, + IN EFI_GUID *NameGuid, + IN EFI_SECTION_TYPE SectionType, + IN UINTN SectionInstance, + IN OUT VOID **Buffer, + IN OUT UINTN *BufferSize, + OUT UINT32 *AuthenticationStatus + ) +/*++ + + Routine Description: + Locates a section in a given FFS File and + copies it to the supplied buffer (not including section header). + + Arguments: + This - Indicates the calling context. + NameGuid - Pointer to an EFI_GUID, which is the filename. + SectionType - Indicates the section type to return. + SectionInstance - Indicates which instance of sections with a type of + SectionType to return. + Buffer - Buffer is a pointer to pointer to a buffer in which + the file or section contents or are returned. + BufferSize - BufferSize is a pointer to caller allocated UINTN. + AuthenticationStatus -AuthenticationStatus is a pointer to a caller + allocated UINT32 in which the authentication status + is returned. + + Returns: + EFI_SUCCESS - Successfully read the file section into buffer. + EFI_WARN_BUFFER_TOO_SMALL - Buffer too small. + EFI_NOT_FOUND - Section not found. + EFI_DEVICE_ERROR - Device error. + EFI_ACCESS_DENIED - Could not read. + EFI_INVALID_PARAMETER - Invalid parameter. + +--*/ +{ + EFI_STATUS Status; + FV_DEVICE *FvDevice; + EFI_FV_FILETYPE FileType; + EFI_FV_FILE_ATTRIBUTES FileAttributes; + UINTN FileSize; + UINT8 *FileBuffer; + EFI_SECTION_EXTRACTION_PROTOCOL *Sep; + FFS_FILE_LIST_ENTRY *FfsEntry; + + if (NULL == NameGuid || Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + FvDevice = FV_DEVICE_FROM_THIS (This); + + // + // Read the whole file into buffer + // + FileBuffer = NULL; + Status = FvReadFile ( + This, + NameGuid, + (VOID **)&FileBuffer, + &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; + } + + // + // 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 Inforomation + // + if (FfsEntry->StreamHandle == 0) { + // + // Located the protocol + // + Status = CoreLocateProtocol (&gEfiSectionExtractionProtocolGuid, NULL, (VOID **)&Sep); + // + // Section Extraction Protocol is part of Dxe Core so this should never fail + // + ASSERT_EFI_ERROR (Status); + + Status = Sep->OpenSectionStream ( + Sep, + FileSize, + FileBuffer, + &FfsEntry->StreamHandle + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + FfsEntry->Sep = Sep; + } else { + // + // Get cached copy of Sep + // + Sep = FfsEntry->Sep; + } + + // + // If SectionType == 0 We need the whole section stream + // + Status = Sep->GetSection ( + Sep, + FfsEntry->StreamHandle, + (SectionType == 0) ? NULL : &SectionType, + NULL, + (SectionType == 0) ? 0 : SectionInstance, + Buffer, + BufferSize, + AuthenticationStatus + ); + + // + // Close of stream defered to close of FfsHeader list to allow SEP to cache data + // + +Done: + CoreFreePool (FileBuffer); + + return Status; +} + diff --git a/EdkModulePkg/Core/Dxe/FwVol/FwVolWrite.c b/EdkModulePkg/Core/Dxe/FwVol/FwVolWrite.c new file mode 100644 index 0000000000..4368fe534e --- /dev/null +++ b/EdkModulePkg/Core/Dxe/FwVol/FwVolWrite.c @@ -0,0 +1,60 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FwVolWrite.c + +Abstract: + + Implements write firmware file + +--*/ + +#include + + +EFI_STATUS +EFIAPI +FvWriteFile ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, + IN UINT32 NumberOfFiles, + IN EFI_FV_WRITE_POLICY WritePolicy, + IN EFI_FV_WRITE_FILE_DATA *FileData + ) +/*++ + + Routine Description: + Writes one or more files to the firmware volume. + + Arguments: + This - Indicates the calling context. + NumberOfFiles - Number of files. + 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. + FileData - FileData is an pointer to an array of EFI_FV_WRITE_DATA. + Each element of FileData[] represents a file to be written. + + Returns: + EFI_SUCCESS - Files successfully written to firmware volume + EFI_OUT_OF_RESOURCES - Not enough buffer to be allocated. + EFI_DEVICE_ERROR - Device error. + EFI_WRITE_PROTECTED - Write protected. + EFI_NOT_FOUND - Not found. + EFI_INVALID_PARAMETER - Invalid parameter. + EFI_UNSUPPORTED - This function not supported. + +--*/ +{ + return EFI_UNSUPPORTED; +} + diff --git a/EdkModulePkg/Core/Dxe/FwVolBlock.h b/EdkModulePkg/Core/Dxe/FwVolBlock.h new file mode 100644 index 0000000000..2e76242184 --- /dev/null +++ b/EdkModulePkg/Core/Dxe/FwVolBlock.h @@ -0,0 +1,324 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FwVolBlock.h + +Abstract: + + Firmware Volume Block protocol.. Consumes FV hobs and creates + appropriate block protocols. + + Also consumes NT_NON_MM_FV envinronment variable and produces appropriate + block protocols fro them also... (this is TBD) + +--*/ + +#ifndef _FWVOL_BLOCK_H_ +#define _FWVOL_BLOCK_H_ + + +#define FVB_DEVICE_SIGNATURE EFI_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_DEVICE_PATH; + + +typedef struct { + UINTN Signature; + EFI_HANDLE Handle; + FV_DEVICE_PATH DevicePath; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL FwVolBlockInstance; + UINTN NumBlocks; + LBA_CACHE *LbaCache; + UINT32 FvbAttributes; + EFI_PHYSICAL_ADDRESS BaseAddress; +} EFI_FW_VOL_BLOCK_DEVICE; + +#define FVB_DEVICE_FROM_THIS(a) \ + CR(a, EFI_FW_VOL_BLOCK_DEVICE, FwVolBlockInstance, FVB_DEVICE_SIGNATURE) + + + +EFI_STATUS +EFIAPI +FwVolBlockDriverInit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + This routine is the driver initialization entry point. It initializes the + libraries, consumes FV hobs and NT_NON_MM_FV environment variable and + produces instances of FW_VOL_BLOCK_PROTOCOL as appropriate. +Arguments: + ImageHandle - The image handle. + SystemTable - The system table. +Returns: + EFI_SUCCESS - Successfully initialized firmware volume block driver. +--*/ +; + + +EFI_STATUS +EFIAPI +FwVolBlockGetAttributes ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_FVB_ATTRIBUTES *Attributes + ) +/*++ + +Routine Description: + Retrieves Volume attributes. No polarity translations are done. + +Arguments: + This - Calling context + Attributes - output buffer which contains attributes + +Returns: + EFI_SUCCESS - The firmware volume attributes were returned. + +--*/ +; + + +EFI_STATUS +EFIAPI +FwVolBlockSetAttributes ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_FVB_ATTRIBUTES *Attributes + ) +/*++ + +Routine Description: + Modifies the current settings of the firmware volume according to the input parameter. + +Arguments: + This - Calling context + Attributes - input buffer which contains attributes + +Returns: + EFI_SUCCESS - The firmware volume attributes were returned. + EFI_INVALID_PARAMETER - The attributes requested are in conflict with the capabilities as + declared in the firmware volume header. + EFI_UNSUPPORTED - Not supported. +--*/ +; + + +EFI_STATUS +EFIAPI +FwVolBlockEraseBlock ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + ... + ) +/*++ + +Routine Description: + 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. + +Arguments: + This - Calling context + ... - Starting LBA followed by Number of Lba to erase. a -1 to terminate + the list. + +Returns: + EFI_SUCCESS - The erase request was successfully completed. + EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state. + EFI_DEVICE_ERROR - The block device is not functioning correctly and could not be + written. The firmware device may have been partially erased. + EFI_INVALID_PARAMETER - One or more of the LBAs listed in the variable argument list do + EFI_UNSUPPORTED - Not supported. + +--*/ +; + + +EFI_STATUS +EFIAPI +FwVolBlockReadBlock ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +/*++ + +Routine Description: + Read the specified number of bytes from the block to the input buffer. + +Arguments: + This - Indicates the calling context. + Lba - The starting logical block index to read. + Offset - Offset into the block at which to begin reading. + 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. + Buffer - Pinter to a caller-allocated buffer that contains the destine + for the read. + +Returns: + EFI_SUCCESS - The firmware volume was read successfully. + EFI_BAD_BUFFER_SIZE - The read was attempted across an LBA boundary. + EFI_ACCESS_DENIED - Access denied. + EFI_DEVICE_ERROR - The block device is malfunctioning and could not be read. +--*/ +; + + +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 + ) +/*++ + +Routine Description: + Writes the specified number of bytes from the input buffer to the block. + +Arguments: + This - Indicates the calling context. + Lba - The starting logical block index to write to. + Offset - Offset into the block at which to begin writing. + 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. + Buffer - Pinter to a caller-allocated buffer that contains the source + for the write. + +Returns: + EFI_SUCCESS - The firmware volume was written successfully. + EFI_BAD_BUFFER_SIZE - The write was attempted across an LBA boundary. On output, + NumBytes contains the total number of bytes actually written. + EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state. + EFI_DEVICE_ERROR - The block device is malfunctioning and could not be written. + EFI_UNSUPPORTED - Not supported. +--*/ +; + + +EFI_STATUS +EFIAPI +FwVolBlockGetPhysicalAddress ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_PHYSICAL_ADDRESS *Address + ) +/*++ + +Routine Description: + Get Fvb's base address. + +Arguments: + This - Indicates the calling context. + Address - Fvb device base address. + +Returns: + EFI_SUCCESS - Successfully got Fvb's base address. + EFI_UNSUPPORTED - Not supported. +--*/ +; + + +EFI_STATUS +EFIAPI +FwVolBlockGetBlockSize ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + OUT UINTN *BlockSize, + OUT UINTN *NumberOfBlocks + ) +/*++ + +Routine Description: + Retrieves the size in bytes of a specific block within a firmware volume. + +Arguments: + This - Indicates the calling context. + Lba - Indicates the block for which to return the size. + BlockSize - Pointer to a caller-allocated UINTN in which the size of the + block is returned. + 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. +Returns: + EFI_SUCCESS - The firmware volume base address is returned. + EFI_INVALID_PARAMETER - The requested LBA is out of range. +--*/ +; +EFI_STATUS +FwVolBlockDriverInit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + This routine is the driver initialization entry point. It initializes the + libraries, consumes FV hobs and NT_NON_MM_FV environment variable and + produces instances of FW_VOL_BLOCK_PROTOCOL as appropriate. +Arguments: + ImageHandle - The image handle. + SystemTable - The system table. +Returns: + Status code + +--*/ +; + +EFI_STATUS +ProduceFVBProtocolOnBuffer ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN EFI_HANDLE ParentHandle, + OUT EFI_HANDLE *FvProtocolHandle OPTIONAL + ) +/*++ + +Routine Description: + This routine produces a firmware volume block protocol on a given + buffer. + +Arguments: + BaseAddress - base address of the firmware volume image + Length - length of the firmware volume image + ParentHandle - handle of parent firmware volume, if this + image came from an FV image file in another + firmware volume (ala capsules) + FvProtocolHandle - Firmware volume block protocol produced. + +Returns: + EFI_VOLUME_CORRUPTED - Volume corrupted. + EFI_OUT_OF_RESOURCES - No enough buffer to be allocated. + EFI_SUCCESS - Successfully produced a FVB protocol on given buffer. + +--*/ +; + +#endif diff --git a/EdkModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.c b/EdkModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.c new file mode 100644 index 0000000000..49f197f811 --- /dev/null +++ b/EdkModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.c @@ -0,0 +1,598 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FwVolBlock.c + +Abstract: + + Firmware Volume Block protocol.. Consumes FV hobs and creates + appropriate block protocols. + + Also consumes NT_NON_MM_FV envinronment variable and produces appropriate + block protocols fro them also... (this is TBD) + +--*/ + +#include + + +EFI_FW_VOL_BLOCK_DEVICE mFwVolBlock = { + FVB_DEVICE_SIGNATURE, + NULL, + { + { + { + 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 } + }, + }, + { + FwVolBlockGetAttributes, + (EFI_FVB_SET_ATTRIBUTES)FwVolBlockSetAttributes, + FwVolBlockGetPhysicalAddress, + FwVolBlockGetBlockSize, + FwVolBlockReadBlock, + (EFI_FVB_WRITE)FwVolBlockWriteBlock, + (EFI_FVB_ERASE_BLOCKS)FwVolBlockEraseBlock, + NULL + }, + 0, + NULL, + 0, + 0 +}; + + + + +EFI_STATUS +EFIAPI +FwVolBlockGetAttributes ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_FVB_ATTRIBUTES *Attributes + ) +/*++ + +Routine Description: + Retrieves Volume attributes. No polarity translations are done. + +Arguments: + This - Calling context + Attributes - output buffer which contains attributes + +Returns: + EFI_SUCCESS - The firmware volume attributes were returned. + +--*/ +{ + 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; + + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +FwVolBlockSetAttributes ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_FVB_ATTRIBUTES *Attributes + ) +/*++ + +Routine Description: + Modifies the current settings of the firmware volume according to the input parameter. + +Arguments: + This - Calling context + Attributes - input buffer which contains attributes + +Returns: + EFI_SUCCESS - The firmware volume attributes were returned. + EFI_INVALID_PARAMETER - The attributes requested are in conflict with the capabilities as + declared in the firmware volume header. + EFI_UNSUPPORTED - Not supported. +--*/ +{ + return EFI_UNSUPPORTED; +} + + +EFI_STATUS +EFIAPI +FwVolBlockEraseBlock ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + ... + ) +/*++ + +Routine Description: + 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. + +Arguments: + This - Calling context + ... - Starting LBA followed by Number of Lba to erase. a -1 to terminate + the list. + +Returns: + EFI_SUCCESS - The erase request was successfully completed. + EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state. + EFI_DEVICE_ERROR - The block device is not functioning correctly and could not be + written. The firmware device may have been partially erased. + EFI_INVALID_PARAMETER - One or more of the LBAs listed in the variable argument list do + EFI_UNSUPPORTED - Not supported. + +--*/ +{ + return EFI_UNSUPPORTED; +} + + +EFI_STATUS +EFIAPI +FwVolBlockReadBlock ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +/*++ + +Routine Description: + Read the specified number of bytes from the block to the input buffer. + +Arguments: + This - Indicates the calling context. + Lba - The starting logical block index to read. + Offset - Offset into the block at which to begin reading. + 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. + Buffer - Pinter to a caller-allocated buffer that contains the destine + for the read. + +Returns: + EFI_SUCCESS - The firmware volume was read successfully. + EFI_BAD_BUFFER_SIZE - The read was attempted across an LBA boundary. + EFI_ACCESS_DENIED - Access denied. + EFI_DEVICE_ERROR - The block device is malfunctioning and could not be read. +--*/ +{ + 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_FVB_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 boundry, read nothing. + // + *NumBytes = 0; + return EFI_BAD_BUFFER_SIZE; + } + + NumOfBytesRead = *NumBytes; + if (Offset + NumOfBytesRead > FvbDevice->LbaCache[LbaIndex].Length) { + // + // partial exceed boundry, 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; +} + + +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 + ) +/*++ + +Routine Description: + Writes the specified number of bytes from the input buffer to the block. + +Arguments: + This - Indicates the calling context. + Lba - The starting logical block index to write to. + Offset - Offset into the block at which to begin writing. + 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. + Buffer - Pinter to a caller-allocated buffer that contains the source + for the write. + +Returns: + EFI_SUCCESS - The firmware volume was written successfully. + EFI_BAD_BUFFER_SIZE - The write was attempted across an LBA boundary. On output, + NumBytes contains the total number of bytes actually written. + EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state. + EFI_DEVICE_ERROR - The block device is malfunctioning and could not be written. + EFI_UNSUPPORTED - Not supported. +--*/ +{ + return EFI_UNSUPPORTED; +} + + +EFI_STATUS +EFIAPI +FwVolBlockGetPhysicalAddress ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_PHYSICAL_ADDRESS *Address + ) +/*++ + +Routine Description: + Get Fvb's base address. + +Arguments: + This - Indicates the calling context. + Address - Fvb device base address. + +Returns: + EFI_SUCCESS - Successfully got Fvb's base address. + EFI_UNSUPPORTED - Not supported. +--*/ +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + + if (FvbDevice->FvbAttributes & EFI_FVB_MEMORY_MAPPED) { + *Address = FvbDevice->BaseAddress; + return EFI_SUCCESS; + } + + return EFI_UNSUPPORTED; +} + + +EFI_STATUS +EFIAPI +FwVolBlockGetBlockSize ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + OUT UINTN *BlockSize, + OUT UINTN *NumberOfBlocks + ) +/*++ + +Routine Description: + Retrieves the size in bytes of a specific block within a firmware volume. + +Arguments: + This - Indicates the calling context. + Lba - Indicates the block for which to return the size. + BlockSize - Pointer to a caller-allocated UINTN in which the size of the + block is returned. + 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. +Returns: + EFI_SUCCESS - The firmware volume base address is returned. + EFI_INVALID_PARAMETER - The requested LBA is out of range. +--*/ +{ + 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->FvBlockMap; + + // + // Search the block map for the given block + // + TotalBlocks = 0; + while ((PtrBlockMapEntry->NumBlocks != 0) || (PtrBlockMapEntry->BlockLength !=0 )) { + TotalBlocks += PtrBlockMapEntry->NumBlocks; + if (Lba < TotalBlocks) { + // + // We find the range + // + break; + } + + PtrBlockMapEntry++; + } + + *BlockSize = PtrBlockMapEntry->BlockLength; + *NumberOfBlocks = TotalBlocks - (UINTN)Lba; + + return EFI_SUCCESS; +} + + +EFI_STATUS +ProduceFVBProtocolOnBuffer ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN EFI_HANDLE ParentHandle, + OUT EFI_HANDLE *FvProtocol OPTIONAL + ) +/*++ + +Routine Description: + This routine produces a firmware volume block protocol on a given + buffer. + +Arguments: + BaseAddress - base address of the firmware volume image + Length - length of the firmware volume image + ParentHandle - handle of parent firmware volume, if this + image came from an FV image file in another + firmware volume (ala capsules) + FvProtocol - Firmware volume block protocol produced. + +Returns: + EFI_VOLUME_CORRUPTED - Volume corrupted. + EFI_OUT_OF_RESOURCES - No enough buffer to be allocated. + EFI_SUCCESS - Successfully produced a FVB protocol on given buffer. + +--*/ +{ + EFI_STATUS Status; + EFI_FW_VOL_BLOCK_DEVICE *FvbDev; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + UINTN BlockIndex; + UINTN BlockIndex2; + UINTN LinearOffset; + EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry; + + 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; + } + // + // Allocate EFI_FW_VOL_BLOCK_DEVICE + // + FvbDev = CoreAllocateCopyPool (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; + + // + // Init the block caching fields of the device + // First, count the number of blocks + // + FvbDev->NumBlocks = 0; + for (PtrBlockMapEntry = FwVolHeader->FvBlockMap; + PtrBlockMapEntry->NumBlocks != 0; + PtrBlockMapEntry++) { + FvbDev->NumBlocks += PtrBlockMapEntry->NumBlocks; + } + // + // Second, allocate the cache + // + FvbDev->LbaCache = CoreAllocateBootServicesPool (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->FvBlockMap; + PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) { + for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) { + FvbDev->LbaCache[BlockIndex].Base = LinearOffset; + FvbDev->LbaCache[BlockIndex].Length = PtrBlockMapEntry->BlockLength; + LinearOffset += PtrBlockMapEntry->BlockLength; + BlockIndex++; + } + } + + // + // Set up the devicepath + // + FvbDev->DevicePath.MemMapDevPath.StartingAddress = BaseAddress; + FvbDev->DevicePath.MemMapDevPath.EndingAddress = BaseAddress + FwVolHeader->FvLength - 1; + + // + // + // Attach FvVolBlock Protocol to new handle + // + Status = CoreInstallMultipleProtocolInterfaces ( + &FvbDev->Handle, + &gEfiFirmwareVolumeBlockProtocolGuid, &FvbDev->FwVolBlockInstance, + &gEfiDevicePathProtocolGuid, &FvbDev->DevicePath, + &gEfiFirmwareVolumeDispatchProtocolGuid, NULL, + NULL + ); + + // + // If they want the handle back, set it. + // + if (FvProtocol != NULL) { + *FvProtocol = FvbDev->Handle; + } + + return Status; +} + + +EFI_STATUS +EFIAPI +FwVolBlockDriverInit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + This routine is the driver initialization entry point. It initializes the + libraries, consumes FV hobs and NT_NON_MM_FV environment variable and + produces instances of FW_VOL_BLOCK_PROTOCOL as appropriate. +Arguments: + ImageHandle - The image handle. + SystemTable - The system table. +Returns: + EFI_SUCCESS - Successfully initialized firmware volume block driver. +--*/ +{ + EFI_PEI_HOB_POINTERS FvHob; + // + // Core Needs Firmware Volumes to function + // + FvHob.Raw = GetHobList (); + while ((FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw)) != NULL) { + // + // Produce an FVB protocol for it + // + ProduceFVBProtocolOnBuffer (FvHob.FirmwareVolume->BaseAddress, FvHob.FirmwareVolume->Length, NULL, NULL); + FvHob.Raw = GET_NEXT_HOB (FvHob); + } + return EFI_SUCCESS; +} + + +EFI_STATUS +CoreProcessFirmwareVolume ( + IN VOID *FvHeader, + IN UINTN Size, + OUT EFI_HANDLE *FVProtocolHandle + ) +/*++ + +Routine Description: + 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. + +Arguments: + FvHeader - pointer to a firmware volume header + Size - the size of the buffer pointed to by FvHeader + FVProtocolHandle - the handle on which a firmware volume protocol + was produced for the firmware volume passed in. + +Returns: + EFI_OUT_OF_RESOURCES - if an FVB could not be produced due to lack of + system resources + EFI_VOLUME_CORRUPTED - if the volume was corrupted + EFI_SUCCESS - a firmware volume protocol was produced for the + firmware volume + +--*/ +{ + VOID *Ptr; + EFI_STATUS Status; + + *FVProtocolHandle = NULL; + Status = ProduceFVBProtocolOnBuffer ( + (EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader, + (UINT64)Size, + NULL, + 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)) { + Ptr = NULL; + Status = CoreHandleProtocol (*FVProtocolHandle, &gEfiFirmwareVolumeProtocolGuid, (VOID **)&Ptr); + if (EFI_ERROR(Status) || (Ptr == NULL)) { + return EFI_VOLUME_CORRUPTED; + } + return EFI_SUCCESS; + } + return Status; +} + + diff --git a/EdkModulePkg/Core/Dxe/FwVolDriver.h b/EdkModulePkg/Core/Dxe/FwVolDriver.h new file mode 100644 index 0000000000..fb4e0d5bb2 --- /dev/null +++ b/EdkModulePkg/Core/Dxe/FwVolDriver.h @@ -0,0 +1,466 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FwVolDriver.h + +Abstract: + + Firmware File System protocol. Layers on top of Firmware + Block protocol to produce a file abstraction of FV based files. + +--*/ + +#ifndef __FWVOL_H +#define __FWVOL_H + + +// +// Used to track all non-deleted files +// +typedef struct { + LIST_ENTRY Link; + EFI_FFS_FILE_HEADER *FfsHeader; + UINTN StreamHandle; + EFI_SECTION_EXTRACTION_PROTOCOL *Sep; +} FFS_FILE_LIST_ENTRY; + +typedef struct { + UINTN Signature; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; + EFI_HANDLE Handle; + EFI_FIRMWARE_VOLUME_PROTOCOL Fv; + + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + UINT8 *CachedFv; + UINT8 *EndOfCachedFv; + + FFS_FILE_LIST_ENTRY *LastKey; + + LIST_ENTRY FfsFileListHeader; + + UINT8 ErasePolarity; +} FV_DEVICE; + +#define FV_DEVICE_FROM_THIS(a) CR(a, FV_DEVICE, Fv, FV_DEVICE_SIGNATURE) + + +EFI_STATUS +EFIAPI +FvGetVolumeAttributes ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, + OUT EFI_FV_ATTRIBUTES *Attributes + ) +/*++ + +Routine Description: + Retrieves attributes, insures positive polarity of attribute bits, returns + resulting attributes in output parameter + +Arguments: + This - Calling context + Attributes - output buffer which contains attributes + +Returns: + EFI_SUCCESS - Successfully got volume attributes + +--*/ +; + +EFI_STATUS +EFIAPI +FvSetVolumeAttributes ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, + IN OUT EFI_FV_ATTRIBUTES *Attributes + ) +/*++ + +Routine Description: + Sets current attributes for volume + +Arguments: + This - Calling context + Attributes - At input, contains attributes to be set. At output contains + new value of FV + +Returns: + EFI_UNSUPPORTED - Could not be set. +--*/ +; + +EFI_STATUS +EFIAPI +FvGetNextFile ( + IN EFI_FIRMWARE_VOLUME_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 + ) +/*++ + +Routine Description: + Given the input key, search for the next matching file in the volume. + +Arguments: + This - Indicates the calling context. + 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. + 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(). + 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. + 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. + 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. + +Returns: + EFI_SUCCESS - Successfully find the file. + EFI_DEVICE_ERROR - Device error. + EFI_ACCESS_DENIED - Fv could not read. + EFI_NOT_FOUND - No matching file found. + EFI_INVALID_PARAMETER - Invalid parameter + +--*/ +; + + +EFI_STATUS +EFIAPI +FvReadFile ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, + IN 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 + ) +/*++ + +Routine Description: + Locates a file in the firmware volume and + copies it to the supplied buffer. + +Arguments: + This - Indicates the calling context. + NameGuid - Pointer to an EFI_GUID, which is the filename. + Buffer - Buffer is a pointer to pointer to a buffer in + which the file or section contents or are returned. + 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. + 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. + 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. + AuthenticationStatus - AuthenticationStatus is a pointer to a caller + allocated UINTN in which the authentication status + is returned. +Returns: + EFI_SUCCESS - Successfully read to memory buffer. + EFI_WARN_BUFFER_TOO_SMALL - Buffer too small. + EFI_NOT_FOUND - Not found. + EFI_DEVICE_ERROR - Device error. + EFI_ACCESS_DENIED - Could not read. + EFI_INVALID_PARAMETER - Invalid parameter. + EFI_OUT_OF_RESOURCES - Not enough buffer to be allocated. + +--*/ +; + +EFI_STATUS +EFIAPI +FvReadFileSection ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, + IN EFI_GUID *NameGuid, + IN EFI_SECTION_TYPE SectionType, + IN UINTN SectionInstance, + IN OUT VOID **Buffer, + IN OUT UINTN *BufferSize, + OUT UINT32 *AuthenticationStatus + ) +/*++ + + Routine Description: + Locates a section in a given FFS File and + copies it to the supplied buffer (not including section header). + + Arguments: + This - Indicates the calling context. + NameGuid - Pointer to an EFI_GUID, which is the filename. + SectionType - Indicates the section type to return. + SectionInstance - Indicates which instance of sections with a type of + SectionType to return. + Buffer - Buffer is a pointer to pointer to a buffer in which + the file or section contents or are returned. + BufferSize - BufferSize is a pointer to caller allocated UINTN. + AuthenticationStatus -AuthenticationStatus is a pointer to a caller + allocated UINT32 in which the authentication status + is returned. + + Returns: + EFI_SUCCESS - Successfully read the file section into buffer. + EFI_WARN_BUFFER_TOO_SMALL - Buffer too small. + EFI_NOT_FOUND - Section not found. + EFI_DEVICE_ERROR - Device error. + EFI_ACCESS_DENIED - Could not read. + EFI_INVALID_PARAMETER - Invalid parameter. + +--*/ +; + +EFI_STATUS +EFIAPI +FvWriteFile ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, + IN UINT32 NumberOfFiles, + IN EFI_FV_WRITE_POLICY WritePolicy, + IN EFI_FV_WRITE_FILE_DATA *FileData + ) +/*++ + + Routine Description: + Writes one or more files to the firmware volume. + + Arguments: + This - Indicates the calling context. + 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. + FileData - FileData is an pointer to an array of EFI_FV_WRITE_DATA. + Each element of FileData[] represents a file to be written. + + Returns: + EFI_SUCCESS - Files successfully written to firmware volume + EFI_OUT_OF_RESOURCES - Not enough buffer to be allocated. + EFI_DEVICE_ERROR - Device error. + EFI_WRITE_PROTECTED - Write protected. + EFI_NOT_FOUND - Not found. + EFI_INVALID_PARAMETER - Invalid parameter. + EFI_UNSUPPORTED - This function not supported. + +--*/ +; + + + +// +//Internal functions +// +typedef enum { + EfiCheckSumUint8 = 0, + EfiCheckSumUint16 = 1, + EfiCheckSumUint32 = 2, + EfiCheckSumUint64 = 3, + EfiCheckSumMaximum = 4 +} EFI_CHECKSUM_TYPE; + + +BOOLEAN +IsBufferErased ( + IN UINT8 ErasePolarity, + IN VOID *Buffer, + IN UINTN BufferSize + ) +/*++ + +Routine Description: + Check if a block of buffer is erased + +Arguments: + ErasePolarity - Erase polarity attribute of the firmware volume + Buffer - The buffer to be checked + BufferSize - Size of the buffer in bytes + +Returns: + TRUE - The block of buffer is erased + FALSE - The block of buffer is not erased + +--*/ +; + +EFI_FFS_FILE_STATE +GetFileState ( + IN UINT8 ErasePolarity, + IN EFI_FFS_FILE_HEADER *FfsHeader + ) +/*++ + +Routine Description: + Get the FFS file state by checking the highest bit set in the header's state field + +Arguments: + ErasePolarity - Erase polarity attribute of the firmware volume + FfsHeader - Points to the FFS file header + +Returns: + FFS File state + +--*/ +; + +VOID +SetFileState ( + IN UINT8 State, + IN EFI_FFS_FILE_HEADER *FfsHeader + ) +/*++ + +Routine Description: + Set the FFS file state. + +Arguments: + State - The state to be set. + FfsHeader - Points to the FFS file header + +Returns: + None. + +--*/ +; + +BOOLEAN +VerifyFvHeaderChecksum ( + IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader + ) +/*++ + +Routine Description: + Verify checksum of the firmware volume header + +Arguments: + FvHeader - Points to the firmware volume header to be checked + +Returns: + TRUE - Checksum verification passed + FALSE - Checksum verification failed + +--*/ +; + +BOOLEAN +IsValidFfsHeader ( + IN UINT8 ErasePolarity, + IN EFI_FFS_FILE_HEADER *FfsHeader, + OUT EFI_FFS_FILE_STATE *FileState + ) +/*++ + +Routine Description: + Check if it's a valid FFS file header + +Arguments: + ErasePolarity - Erase polarity attribute of the firmware volume + FfsHeader - Points to the FFS file header to be checked + FileState - FFS file state to be returned + +Returns: + TRUE - Valid FFS file header + FALSE - Invalid FFS file header + +--*/ +; + +BOOLEAN +IsValidFfsFile ( + IN UINT8 ErasePolarity, + IN EFI_FFS_FILE_HEADER *FfsHeader + ) +/*++ + +Routine Description: + 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. + +Arguments: + ErasePolarity - Erase polarity attribute of the firmware volume + FfsHeader - Points to the FFS file to be checked + +Returns: + TRUE - Valid FFS file + FALSE - Invalid FFS file + +--*/ +; + +EFI_STATUS +GetFwVolHeader ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb, + OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader + ) +/*++ + +Routine Description: + given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and + copy the volume header into it. + +Arguments: + Fvb - The FW_VOL_BLOCK_PROTOCOL instance from which to read the volume + header + FwVolHeader - Pointer to pointer to allocated buffer in which the volume + header is returned. + +Returns: + Status code. + +--*/ +; + + +EFI_STATUS +FvCheck ( + IN OUT FV_DEVICE *FvDevice + ) +/*++ + +Routine Description: + Check if a FV is consistent and allocate cache + +Arguments: + FvDevice - pointer to the FvDevice to be checked. + +Returns: + EFI_OUT_OF_RESOURCES - Not enough buffer to be allocated. + EFI_SUCCESS - FV is consistent and cache is allocated. + EFI_VOLUME_CORRUPTED - File system is corrupted. + +--*/ +; + +#endif diff --git a/EdkModulePkg/Core/Dxe/Gcd/gcd.c b/EdkModulePkg/Core/Dxe/Gcd/gcd.c new file mode 100644 index 0000000000..73037edb24 --- /dev/null +++ b/EdkModulePkg/Core/Dxe/Gcd/gcd.c @@ -0,0 +1,2481 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + gcd.c + +Abstract: + 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. + +--*/ + +#include + +#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_16_BIT_IO | \ + EFI_RESOURCE_ATTRIBUTE_32_BIT_IO | \ + EFI_RESOURCE_ATTRIBUTE_64_BIT_IO ) + +#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) + +#define INVALID_CPU_ARCH_ATTRIBUTES 0xffffffff + +// +// Module Variables +// +EFI_LOCK mGcdMemorySpaceLock = EFI_INITIALIZE_LOCK_VARIABLE (EFI_TPL_NOTIFY); +EFI_LOCK mGcdIoSpaceLock = EFI_INITIALIZE_LOCK_VARIABLE (EFI_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, + 0, + NULL, + NULL +}; + +EFI_GCD_MAP_ENTRY mGcdIoSpaceMapEntryTemplate = { + EFI_GCD_MAP_SIGNATURE, + { NULL, NULL }, + 0, + 0, + 0, + 0, + 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_PROTECTED, EFI_MEMORY_RP, TRUE }, + { EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED, EFI_MEMORY_WP, TRUE }, + { EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED, EFI_MEMORY_XP, 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 }, + { 0, 0, FALSE } +}; + +VOID +CoreAcquireGcdMemoryLock ( + VOID + ) +/*++ + +Routine Description: + Acquire memory lock on mGcdMemorySpaceLock + +Arguments: + None + +Returns: + None + +--*/ +{ + CoreAcquireLock (&mGcdMemorySpaceLock); +} + + +VOID +CoreReleaseGcdMemoryLock ( + VOID + ) +/*++ + +Routine Description: + Release memory lock on mGcdMemorySpaceLock + +Arguments: + None + +Returns: + None + +--*/ +{ + CoreReleaseLock (&mGcdMemorySpaceLock); +} + + + +VOID +CoreAcquireGcdIoLock ( + VOID + ) +/*++ + +Routine Description: + Acquire memory lock on mGcdIoSpaceLock + +Arguments: + None + +Returns: + None + +--*/ +{ + CoreAcquireLock (&mGcdIoSpaceLock); +} + + +VOID +CoreReleaseGcdIoLock ( + VOID + ) +/*++ + +Routine Description: + Release memory lock on mGcdIoSpaceLock + +Arguments: + None + +Returns: + None + +--*/ +{ + CoreReleaseLock (&mGcdIoSpaceLock); +} + + + +// +// GCD Initialization Worker Functions +// +UINT64 +AlignValue ( + IN UINT64 Value, + IN UINTN Alignment, + IN BOOLEAN RoundUp + ) +/*++ + +Routine Description: + + Aligns a value to the specified boundary. + +Arguments: + + Value - 64 bit value to align + Alignment - Log base 2 of the boundary to align Value to + 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. + +Returns: + + A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment. + +--*/ +{ + UINT64 AlignmentMask; + + AlignmentMask = LShiftU64 (1, Alignment) - 1; + if (RoundUp) { + Value += AlignmentMask; + } + return Value & (~AlignmentMask); +} + +UINT64 +PageAlignAddress ( + IN UINT64 Value + ) +/*++ + +Routine Description: + + Aligns address to the page boundary. + +Arguments: + + Value - 64 bit address to align + +Returns: + + A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment. + +--*/ +{ + return AlignValue (Value, EFI_PAGE_SHIFT, TRUE); +} + +UINT64 +PageAlignLength ( + IN UINT64 Value + ) +/*++ + +Routine Description: + + Aligns length to the page boundary. + +Arguments: + + Value - 64 bit length to align + +Returns: + + A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment. + +--*/ +{ + return AlignValue (Value, EFI_PAGE_SHIFT, FALSE); +} + +// +// GCD Memory Space Worker Functions +// +EFI_STATUS +CoreAllocateGcdMapEntry ( + IN OUT EFI_GCD_MAP_ENTRY **TopEntry, + IN OUT EFI_GCD_MAP_ENTRY **BottomEntry + ) +/*++ + +Routine Description: + + Allocate pool for two entries. + +Arguments: + + TopEntry - An entry of GCD map + BottomEntry - An entry of GCD map + +Returns: + + EFI_OUT_OF_RESOURCES - No enough buffer to be allocated. + EFI_SUCCESS - Both entries successfully allocated. + +--*/ +{ + *TopEntry = CoreAllocateZeroBootServicesPool (sizeof (EFI_GCD_MAP_ENTRY)); + if (*TopEntry == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + *BottomEntry = CoreAllocateZeroBootServicesPool (sizeof (EFI_GCD_MAP_ENTRY)); + if (*BottomEntry == NULL) { + CoreFreePool (*TopEntry); + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} + +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 + ) +/*++ + +Routine Description: + + Internal function. Inserts a new descriptor into a sorted list + +Arguments: + + Link - The linked list to insert the range BaseAddress and Length into + + Entry - A pointer to the entry that is inserted + + BaseAddress - The base address of the new range + + Length - The length of the new range in bytes + + TopEntry - Top pad entry to insert if needed. + + BottomEntry - Bottom pad entry to insert if needed. + +Returns: + + EFI_SUCCESS - The new range was inserted into the linked list + +--*/ +{ + ASSERT (Length != 0); + ASSERT (TopEntry->Signature == 0); + ASSERT (BottomEntry->Signature == 0); + + if (BaseAddress > Entry->BaseAddress) { + 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) { + CopyMem (TopEntry, Entry, sizeof (EFI_GCD_MAP_ENTRY)); + TopEntry->BaseAddress = BaseAddress + Length; + Entry->EndAddress = BaseAddress + Length - 1; + InsertHeadList (Link, &TopEntry->Link); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +CoreMergeGcdMapEntry ( + IN LIST_ENTRY *Link, + IN BOOLEAN Forward, + IN LIST_ENTRY *Map + ) +/*++ + +Routine Description: + + Merge the Gcd region specified by Link and its adjacent entry + +Arguments: + + Link - Specify the entry to be merged (with its adjacent entry). + + Forward - Direction (forward or backward). + + Map - Boundary. + +Returns: + + EFI_SUCCESS - Successfully returned. + + EFI_UNSUPPORTED - These adjacent regions could not merge. + +--*/ +{ + 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; +} + +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 + ) +/*++ + +Routine Description: + + Merge adjacent entries on total chain. + +Arguments: + + TopEntry - Top entry of GCD map. + + BottomEntry - Bottom entry of GCD map. + + StartLink - Start link of the list for this loop. + + EndLink - End link of the list for this loop. + + Map - Boundary. + +Returns: + + EFI_SUCCESS - GCD map successfully cleaned up. + +--*/ +{ + 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; +} + +EFI_STATUS +CoreSearchGcdMapEntry ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + OUT LIST_ENTRY **StartLink, + OUT LIST_ENTRY **EndLink, + IN LIST_ENTRY *Map + ) +/*++ + +Routine Description: + + Search a segment of memory space in GCD map. The result is a range of GCD entry list. + +Arguments: + + BaseAddress - The start address of the segment. + + Length - The length of the segment. + + StartLink - The first GCD entry involves this segment of memory space. + + EndLink - The first GCD entry involves this segment of memory space. + + Map - Points to the start entry to search. + +Returns: + + EFI_SUCCESS - Successfully found the entry. + + EFI_NOT_FOUND - Not found. + +--*/ +{ + 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; +} + +UINTN +CoreCountGcdMapEntry ( + IN LIST_ENTRY *Map + ) +/*++ + +Routine Description: + + Count the amount of GCD map entries. + +Arguments: + + Map - Points to the start entry to do the count loop. + +Returns: + + The count. + +--*/ +{ + UINTN Count; + LIST_ENTRY *Link; + + Count = 0; + Link = Map->ForwardLink; + while (Link != Map) { + Count++; + Link = Link->ForwardLink; + } + return Count; +} + + + +UINT64 +ConverToCpuArchAttributes ( + UINT64 Attributes + ) +/*++ + +Routine Description: + + Return the memory attribute specified by Attributes + +Arguments: + + Attributes - A num with some attribute bits on. + +Returns: + + The enum value of memory attribute. + +--*/ +{ + if ( (Attributes & EFI_MEMORY_UC) == EFI_MEMORY_UC) { + return EFI_MEMORY_UC; + } + + if ( (Attributes & EFI_MEMORY_WC ) == EFI_MEMORY_WC) { + return EFI_MEMORY_WC; + } + + if ( (Attributes & EFI_MEMORY_WT ) == EFI_MEMORY_WT) { + return EFI_MEMORY_WT; + } + + if ( (Attributes & EFI_MEMORY_WB) == EFI_MEMORY_WB) { + return EFI_MEMORY_WB; + } + + if ( (Attributes & EFI_MEMORY_WP) == EFI_MEMORY_WP) { + return EFI_MEMORY_WP; + } + + return INVALID_CPU_ARCH_ATTRIBUTES; + +} + + +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 + ) +/*++ + +Routine Description: + + Do operation on a segment of memory space specified (add, free, remove, change attribute ...). + +Arguments: + + Operation - The type of the operation + + GcdMemoryType - Additional information for the operation + + GcdIoType - Additional information for the operation + + BaseAddress - Start address of the segment + + Length - length of the segment + + Capabilities - The alterable attributes of a newly added entry + + Attributes - The attributes needs to be set + +Returns: + + EFI_INVALID_PARAMETER - Length is 0 or address (length) not aligned when setting attribute. + + EFI_SUCCESS - Action successfully done. + + EFI_UNSUPPORTED - Could not find the proper descriptor on this segment or + set an upsupported attribute. + + EFI_ACCESS_DENIED - Operate on an space non-exist or is used for an image. + + EFI_NOT_FOUND - Free a non-using space or remove a non-exist space, and so on. + + EFI_OUT_OF_RESOURCES - No buffer could be allocated. + +Returns: + +--*/ +{ + 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; + + EFI_CPU_ARCH_PROTOCOL *CpuArch; + UINT64 CpuArchAttributes; + + if (Length == 0) { + return EFI_INVALID_PARAMETER; + } + + Map = NULL; + if (Operation & GCD_MEMORY_SPACE_OPERATION) { + CoreAcquireGcdMemoryLock (); + Map = &mGcdMemorySpaceMap; + } + if (Operation & GCD_IO_SPACE_OPERATION) { + CoreAcquireGcdIoLock (); + Map = &mGcdIoSpaceMap; + } + + // + // 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; + } + + // + // 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 attribute operations + // + case GCD_SET_ATTRIBUTES_MEMORY_OPERATION: + if (Attributes & EFI_MEMORY_RUNTIME) { + 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; + } + 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; + } + + // + // + // + if (Operation == GCD_SET_ATTRIBUTES_MEMORY_OPERATION) { + // + // Call CPU Arch Protocol to attempt to set attributes on the range + // + CpuArchAttributes = ConverToCpuArchAttributes (Attributes); + if ( CpuArchAttributes != INVALID_CPU_ARCH_ATTRIBUTES ) { + Status = CoreLocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&CpuArch); + if (EFI_ERROR (Status)) { + Status = EFI_ACCESS_DENIED; + goto Done; + } + + Status = CpuArch->SetMemoryAttributes ( + CpuArch, + BaseAddress, + Length, + CpuArchAttributes + ); + if (EFI_ERROR (Status)) { + 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 attribute operations + // + case GCD_SET_ATTRIBUTES_MEMORY_OPERATION: + Entry->Attributes = Attributes; + break; + } + Link = Link->ForwardLink; + } + + // + // Cleanup + // + Status = CoreCleanupGcdMapEntry (TopEntry, BottomEntry, StartLink, EndLink, Map); + +Done: + if (Operation & GCD_MEMORY_SPACE_OPERATION) { + CoreReleaseGcdMemoryLock (); + } + if (Operation & GCD_IO_SPACE_OPERATION) { + CoreReleaseGcdIoLock (); + } + + return Status; +} + +EFI_STATUS +CoreAllocateSpaceCheckEntry ( + IN UINTN Operation, + IN EFI_GCD_MAP_ENTRY *Entry, + IN EFI_GCD_MEMORY_TYPE GcdMemoryType, + IN EFI_GCD_IO_TYPE GcdIoType + ) +/*++ + +Routine Description: + + Check whether an entry could be used to allocate space. + +Arguments: + + Operation - Allocate memory or IO + + Entry - The entry to be tested + + GcdMemoryType - The desired memory type + + GcdIoType - The desired IO type + +Returns: + + EFI_NOT_FOUND - The memory type does not match or there's an image handle on the entry. + + EFI_UNSUPPORTED - The operation unsupported. + + EFI_SUCCESS - It's ok for this entry to be used to allocate space. + +--*/ +{ + 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; +} + +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 + ) +/*++ + +Routine Description: + + Allocate space on specified address and length. + +Arguments: + + Operation - The type of operation (memory or IO) + + GcdAllocateType - The type of allocate operation + + GcdMemoryType - The desired memory type + + GcdIoType - The desired IO type + + Alignment - Align with 2^Alignment + + Length - Length to allocate + + BaseAddress - Base address to allocate + + ImageHandle - The image handle consume the allocated space. + + DeviceHandle - The device handle consume the allocated space. + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter. + + EFI_NOT_FOUND - No descriptor for the desired space exists. + + EFI_SUCCESS - Space successfully allocated. + +--*/ +{ + 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 (GcdAllocateType < 0 || GcdAllocateType >= EfiGcdMaxAllocateType) { + return EFI_INVALID_PARAMETER; + } + if (GcdMemoryType < 0 || GcdMemoryType >= EfiGcdMemoryTypeMaximum) { + return EFI_INVALID_PARAMETER; + } + if (GcdIoType < 0 || GcdIoType >= EfiGcdIoTypeMaximum) { + return EFI_INVALID_PARAMETER; + } + if (BaseAddress == NULL) { + return EFI_INVALID_PARAMETER; + } + if (ImageHandle == NULL) { + return EFI_INVALID_PARAMETER; + } + if (Alignment >= 64) { + return EFI_NOT_FOUND; + } + if (Length == 0) { + return EFI_INVALID_PARAMETER; + } + + Map = NULL; + if (Operation & GCD_MEMORY_SPACE_OPERATION) { + CoreAcquireGcdMemoryLock (); + Map = &mGcdMemorySpaceMap; + } + if (Operation & GCD_IO_SPACE_OPERATION) { + CoreAcquireGcdIoLock (); + Map = &mGcdIoSpaceMap; + } + + 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; + } + + // + // 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 - 1; + } 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; + } + + 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; + } + + // + // 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: + if (Operation & GCD_MEMORY_SPACE_OPERATION) { + CoreReleaseGcdMemoryLock (); + } + if (Operation & GCD_IO_SPACE_OPERATION) { + CoreReleaseGcdIoLock (); + } + + return Status; +} + + +EFI_STATUS +CoreInternalAddMemorySpace ( + IN EFI_GCD_MEMORY_TYPE GcdMemoryType, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Capabilities + ) +/*++ + +Routine Description: + + Add a segment of memory to GCD map. + +Arguments: + + GcdMemoryType - Memory type of the segment. + + BaseAddress - Base address of the segment. + + Length - Length of the segment. + + Capabilities - alterable attributes of the segment. + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameters. + + EFI_SUCCESS - Successfully add a segment of memory space. + +--*/ +{ + // + // Make sure parameters are valid + // + if (GcdMemoryType <= EfiGcdMemoryTypeNonExistent || GcdMemoryType >= EfiGcdMemoryTypeMaximum) { + return EFI_INVALID_PARAMETER; + } + + return CoreConvertSpace (GCD_ADD_MEMORY_OPERATION, GcdMemoryType, 0, BaseAddress, Length, Capabilities, 0); +} + +// +// GCD Core Services +// +EFI_STATUS +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 + ) +/*++ + +Routine Description: + + Allocates nonexistent memory, reserved memory, system memory, or memorymapped +I/O resources from the global coherency domain of the processor. + +Arguments: + + GcdAllocateType - The type of allocate operation + + GcdMemoryType - The desired memory type + + Alignment - Align with 2^Alignment + + Length - Length to allocate + + BaseAddress - Base address to allocate + + ImageHandle - The image handle consume the allocated space. + + DeviceHandle - The device handle consume the allocated space. + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter. + + EFI_NOT_FOUND - No descriptor contains the desired space. + + EFI_SUCCESS - Memory space successfully allocated. + +--*/ +{ + return CoreAllocateSpace ( + GCD_ALLOCATE_MEMORY_OPERATION, + GcdAllocateType, + GcdMemoryType, + 0, + Alignment, + Length, + BaseAddress, + ImageHandle, + DeviceHandle + ); +} + +EFI_STATUS +CoreAddMemorySpace ( + IN EFI_GCD_MEMORY_TYPE GcdMemoryType, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Capabilities + ) +/*++ + +Routine Description: + + Adds reserved memory, system memory, or memory-mapped I/O resources to the +global coherency domain of the processor. + +Arguments: + + GcdMemoryType - Memory type of the memory space. + + BaseAddress - Base address of the memory space. + + Length - Length of the memory space. + + Capabilities - alterable attributes of the memory space. + +Returns: + + EFI_SUCCESS - Merged this memory space into GCD map. + +--*/ +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS PageBaseAddress; + UINT64 PageLength; + + Status = CoreInternalAddMemorySpace (GcdMemoryType, BaseAddress, Length, Capabilities); + + if (!EFI_ERROR (Status) && GcdMemoryType == EfiGcdMemoryTypeSystemMemory) { + + PageBaseAddress = PageAlignLength (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; +} + +EFI_STATUS +CoreFreeMemorySpace ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +/*++ + +Routine Description: + + Frees nonexistent memory, reserved memory, system memory, or memory-mapped +I/O resources from the global coherency domain of the processor. + +Arguments: + + BaseAddress - Base address of the memory space. + + Length - Length of the memory space. + +Returns: + + EFI_SUCCESS - Space successfully freed. + +--*/ +{ + return CoreConvertSpace (GCD_FREE_MEMORY_OPERATION, 0, 0, BaseAddress, Length, 0, 0); +} + +EFI_STATUS +CoreRemoveMemorySpace ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +/*++ + +Routine Description: + + Removes reserved memory, system memory, or memory-mapped I/O resources from +the global coherency domain of the processor. + +Arguments: + + BaseAddress - Base address of the memory space. + + Length - Length of the memory space. + +Returns: + + EFI_SUCCESS - Successfully remove a segment of memory space. + +--*/ +{ + return CoreConvertSpace (GCD_REMOVE_MEMORY_OPERATION, 0, 0, BaseAddress, Length, 0, 0); +} + +VOID +BuildMemoryDescriptor ( + IN OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor, + IN EFI_GCD_MAP_ENTRY *Entry + ) +/*++ + +Routine Description: + + Build a memory descriptor according to an entry. + +Arguments: + + Descriptor - The descriptor to be built + + Entry - According to this entry + +Returns: + + None + +--*/ +{ + 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; +} + +EFI_STATUS +CoreGetMemorySpaceDescriptor ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor + ) +/*++ + +Routine Description: + + Retrieves the descriptor for a memory region containing a specified address. + +Arguments: + + BaseAddress - Specified start address + + Descriptor - Specified length + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_SUCCESS - Successfully get memory space 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 { + // + // 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; +} + +EFI_STATUS +CoreSetMemorySpaceAttributes ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Attributes + ) +/*++ + +Routine Description: + + Modifies the attributes for a memory region in the global coherency domain of the +processor. + +Arguments: + + BaseAddress - Specified start address + + Length - Specified length + + Attributes - Specified attributes + +Returns: + + EFI_SUCCESS - Successfully set attribute of a segment of memory space. + +--*/ +{ + return CoreConvertSpace (GCD_SET_ATTRIBUTES_MEMORY_OPERATION, 0, 0, BaseAddress, Length, 0, Attributes); +} + +EFI_STATUS +CoreGetMemorySpaceMap ( + OUT UINTN *NumberOfDescriptors, + OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR **MemorySpaceMap + ) +/*++ + +Routine Description: + + Returns a map of the memory resources in the global coherency domain of the +processor. + +Arguments: + + NumberOfDescriptors - Number of descriptors. + + MemorySpaceMap - Descriptor array + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_OUT_OF_RESOURCES - No enough buffer to allocate + + EFI_SUCCESS - Successfully get memory space map. + +--*/ +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + EFI_GCD_MAP_ENTRY *Entry; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor; + + // + // Make sure parameters are valid + // + if (NumberOfDescriptors == NULL) { + return EFI_INVALID_PARAMETER; + } + if (MemorySpaceMap == NULL) { + return EFI_INVALID_PARAMETER; + } + + CoreAcquireGcdMemoryLock (); + + // + // Count the number of descriptors + // + *NumberOfDescriptors = CoreCountGcdMapEntry (&mGcdMemorySpaceMap); + + // + // Allocate the MemorySpaceMap + // + *MemorySpaceMap = CoreAllocateBootServicesPool (*NumberOfDescriptors * sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR)); + if (*MemorySpaceMap == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + // + // Fill in the MemorySpaceMap + // + 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; + } + Status = EFI_SUCCESS; + +Done: + CoreReleaseGcdMemoryLock (); + return Status; +} + +EFI_STATUS +CoreAddIoSpace ( + IN EFI_GCD_IO_TYPE GcdIoType, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +/*++ + +Routine Description: + + Adds reserved I/O or I/O resources to the global coherency domain of the processor. + +Arguments: + + GcdIoType - IO type of the segment. + + BaseAddress - Base address of the segment. + + Length - Length of the segment. + +Returns: + + EFI_SUCCESS - Merged this segment into GCD map. + EFI_INVALID_PARAMETER - Parameter not valid + +--*/ +{ + // + // Make sure parameters are valid + // + if (GcdIoType <= EfiGcdIoTypeNonExistent || GcdIoType >= EfiGcdIoTypeMaximum) { + return EFI_INVALID_PARAMETER; + } + return CoreConvertSpace (GCD_ADD_IO_OPERATION, 0, GcdIoType, BaseAddress, Length, 0, 0); +} + +EFI_STATUS +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 + ) +/*++ + +Routine Description: + + Allocates nonexistent I/O, reserved I/O, or I/O resources from the global coherency +domain of the processor. + +Arguments: + + GcdAllocateType - The type of allocate operation + + GcdIoType - The desired IO type + + Alignment - Align with 2^Alignment + + Length - Length to allocate + + BaseAddress - Base address to allocate + + ImageHandle - The image handle consume the allocated space. + + DeviceHandle - The device handle consume the allocated space. + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter. + + EFI_NOT_FOUND - No descriptor contains the desired space. + + EFI_SUCCESS - IO space successfully allocated. + +--*/ +{ + return CoreAllocateSpace ( + GCD_ALLOCATE_IO_OPERATION, + GcdAllocateType, + 0, + GcdIoType, + Alignment, + Length, + BaseAddress, + ImageHandle, + DeviceHandle + ); +} + +EFI_STATUS +CoreFreeIoSpace ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +/*++ + +Routine Description: + + Frees nonexistent I/O, reserved I/O, or I/O resources from the global coherency +domain of the processor. + +Arguments: + + BaseAddress - Base address of the segment. + + Length - Length of the segment. + +Returns: + + EFI_SUCCESS - Space successfully freed. + +--*/ +{ + return CoreConvertSpace (GCD_FREE_IO_OPERATION, 0, 0, BaseAddress, Length, 0, 0); +} + +EFI_STATUS +CoreRemoveIoSpace ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +/*++ + +Routine Description: + + Removes reserved I/O or I/O resources from the global coherency domain of the +processor. + +Arguments: + + BaseAddress - Base address of the segment. + + Length - Length of the segment. + +Returns: + + EFI_SUCCESS - Successfully removed a segment of IO space. + +--*/ +{ + return CoreConvertSpace (GCD_REMOVE_IO_OPERATION, 0, 0, BaseAddress, Length, 0, 0); +} + +VOID +BuildIoDescriptor ( + IN EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor, + IN EFI_GCD_MAP_ENTRY *Entry + ) +/*++ + +Routine Description: + + Build a IO descriptor according to an entry. + +Arguments: + + Descriptor - The descriptor to be built + + Entry - According to this entry + +Returns: + + None + +--*/ +{ + Descriptor->BaseAddress = Entry->BaseAddress; + Descriptor->Length = Entry->EndAddress - Entry->BaseAddress + 1; + Descriptor->GcdIoType = Entry->GcdIoType; + Descriptor->ImageHandle = Entry->ImageHandle; + Descriptor->DeviceHandle = Entry->DeviceHandle; +} + +EFI_STATUS +CoreGetIoSpaceDescriptor ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + OUT EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor + ) +/*++ + +Routine Description: + + Retrieves the descriptor for an I/O region containing a specified address. + +Arguments: + + BaseAddress - Specified start address + + Descriptor - Specified length + +Returns: + + EFI_INVALID_PARAMETER - Descriptor is NULL. + + EFI_SUCCESS - Successfully get the IO space 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 { + // + // 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; +} + +EFI_STATUS +CoreGetIoSpaceMap ( + OUT UINTN *NumberOfDescriptors, + OUT EFI_GCD_IO_SPACE_DESCRIPTOR **IoSpaceMap + ) +/*++ + +Routine Description: + + Returns a map of the I/O resources in the global coherency domain of the processor. + +Arguments: + + NumberOfDescriptors - Number of descriptors. + + IoSpaceMap - Descriptor array + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_OUT_OF_RESOURCES - No enough buffer to allocate + + EFI_SUCCESS - Successfully get IO space map. + +--*/ +{ + 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 = CoreAllocateBootServicesPool (*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; +} + +UINT64 +CoreConvertResourceDescriptorHobAttributesToCapabilities ( + EFI_GCD_MEMORY_TYPE GcdMemoryType, + UINT64 Attributes + ) +/*++ + +Routine Description: + + Converts a Resource Descriptor HOB attributes mask to an EFI Memory Descriptor + capabilities mask + +Arguments: + + GcdMemoryType - Type of resource in the GCD memory map. + Attributes - The attribute mask in the Resource Descriptor HOB. + +Returns: + + The capabilities mask for an EFI Memory Descriptor. + +--*/ +{ + 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)) { + if (Attributes & Conversion->Attribute) { + Capabilities |= Conversion->Capability; + } + } + } + + return Capabilities; +} + +EFI_STATUS +CoreInitializeMemoryServices ( + IN VOID **HobStart, + OUT EFI_PHYSICAL_ADDRESS *MemoryBaseAddress, + OUT UINT64 *MemoryLength + ) +/*++ + +Routine Description: + + 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 first + part of this function can not depend on any memory services until at least one + memory descriptor is provided to the memory services. Then the memory services + can be used to intialize the GCD map. + +Arguments: + + HobStart - The start address of the HOB. + MemoryBaseAddress - Start address of memory region found to init DXE core. + MemoryLength - Length of memory region found to init DXE core. + +Returns: + + EFI_SUCCESS - Memory services successfully initialized. + +--*/ +{ + 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 MaxMemoryBaseAddress; + UINT64 MaxMemoryLength; + UINT64 MaxMemoryAttributes; + EFI_PHYSICAL_ADDRESS MaxAddress; + EFI_PHYSICAL_ADDRESS HighAddress; + EFI_HOB_RESOURCE_DESCRIPTOR *MaxResourceHob; + EFI_HOB_GUID_TYPE *GuidHob; + + // + // 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; + MaxResourceHob = NULL; + ResourceHob = NULL; + BaseAddress = 0; + Length = 0; + Attributes = 0; + MaxMemoryBaseAddress = 0; + MaxMemoryLength = 0; + MaxMemoryAttributes = 0; + + // + // Cache the PHIT HOB for later use + // + PhitHob = Hob.HandoffInformationTable; + + // + // 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 * sizeof (EFI_MEMORY_TYPE_INFORMATION)) { + CopyMem (&gMemoryTypeInformation, EfiMemoryTypeInformation, DataSize); + } + } + + // + // Find the Resource Descriptor HOB that contains range FreeMemoryBaseAddress..FreeMemoryLength + // + Length = 0; + Found = FALSE; + for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) { + + if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { + + ResourceHob = Hob.ResourceDescriptor; + + if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY && + (ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == TESTED_MEMORY_ATTRIBUTES ) { + + if (PhitHob->EfiFreeMemoryBottom >= ResourceHob->PhysicalStart && + PhitHob->EfiFreeMemoryTop <= (ResourceHob->PhysicalStart + ResourceHob->ResourceLength) ) { + + // + // Cache the resource descriptor HOB for the memory region described by the PHIT HOB + // + PhitResourceHob = ResourceHob; + Found = TRUE; + + Attributes = PhitResourceHob->ResourceAttribute; + BaseAddress = PageAlignAddress (PhitHob->EfiMemoryTop); + Length = PageAlignLength (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - BaseAddress); + if (Length < MINIMUM_INITIAL_MEMORY_SIZE) { + BaseAddress = PageAlignAddress (PhitHob->EfiFreeMemoryBottom); + Length = PageAlignLength (PhitHob->EfiFreeMemoryTop - BaseAddress); + if (Length < MINIMUM_INITIAL_MEMORY_SIZE) { + 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); + + // + // 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. + // + MaxMemoryLength = 0; + MaxAddress = EFI_MAX_ADDRESS; + do { + HighAddress = 0; + Found = FALSE; + // + // Search for a tested memory region that is below MaxAddress + // + for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) { + + // + // See if this is a resource descriptor HOB that does not contain the PHIT. + // + if (Hob.ResourceDescriptor != PhitResourceHob && GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { + + ResourceHob = Hob.ResourceDescriptor; + // + // See if this resource descrior HOB describes tested system memory below MaxAddress + // + if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY && + (ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == TESTED_MEMORY_ATTRIBUTES && + ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MaxAddress ) { + + // + // See if this is the highest tested system memory region below MaxAddress + // + if (ResourceHob->PhysicalStart > HighAddress) { + + MaxResourceHob = ResourceHob; + HighAddress = MaxResourceHob->PhysicalStart; + Found = TRUE; + } + } + } + } + if (Found) { + // + // Compute the size of the tested memory region below MaxAddrees + // + MaxMemoryBaseAddress = PageAlignAddress (MaxResourceHob->PhysicalStart); + MaxMemoryLength = PageAlignLength (MaxResourceHob->PhysicalStart + MaxResourceHob->ResourceLength - MaxMemoryBaseAddress); + MaxMemoryAttributes = MaxResourceHob->ResourceAttribute; + } + MaxAddress = ResourceHob->PhysicalStart; + } while (Found && MaxMemoryLength < MINIMUM_INITIAL_MEMORY_SIZE); + + // + // + // + if ((Length < MINIMUM_INITIAL_MEMORY_SIZE) || + (MaxMemoryBaseAddress > BaseAddress && MaxMemoryLength >= MINIMUM_INITIAL_MEMORY_SIZE) ) { + BaseAddress = MaxMemoryBaseAddress; + Length = MaxMemoryLength; + Attributes = MaxMemoryAttributes; + } + + // + // If no memory regions are found that are big enough to initialize the DXE core, then ASSERT(). + // + ASSERT (Length >= MINIMUM_INITIAL_MEMORY_SIZE); + + // + // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask + // + 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; +} + +EFI_STATUS +CoreInitializeGcdServices ( + IN VOID **HobStart, + IN EFI_PHYSICAL_ADDRESS MemoryBaseAddress, + IN UINT64 MemoryLength + ) +/*++ + +Routine Description: + + 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 first + part of this function can not depend on any memory services until at least one + memory descriptor is provided to the memory services. Then the memory services + can be used to intialize the GCD map. + +Arguments: + + HobStart - The start address of the HOB + + MemoryBaseAddress - Start address of memory region found to init DXE core. + + MemoryLength - Length of memory region found to init DXE core. + + +Returns: + + EFI_SUCCESS - GCD services successfully initialized. + +--*/ +{ + 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; + // + // 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 = CoreAllocateCopyPool (sizeof (EFI_GCD_MAP_ENTRY), &mGcdMemorySpaceMapEntryTemplate); + ASSERT (Entry != NULL); + + Entry->EndAddress = LShiftU64 (1, SizeOfMemorySpace) - 1; + + InsertHeadList (&mGcdMemorySpaceMap, &Entry->Link); + + // + // Initialize the GCD I/O Space Map + // + Entry = CoreAllocateCopyPool (sizeof (EFI_GCD_MAP_ENTRY), &mGcdIoSpaceMapEntryTemplate); + ASSERT (Entry != NULL); + + Entry->EndAddress = LShiftU64 (1, SizeOfIoSpace) - 1; + + InsertHeadList (&mGcdIoSpaceMap, &Entry->Link); + + // + // 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) { + GcdMemoryType = EfiGcdMemoryTypeSystemMemory; + } + if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == INITIALIZED_MEMORY_ATTRIBUTES) { + GcdMemoryType = EfiGcdMemoryTypeReserved; + } + if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == PRESENT_MEMORY_ATTRIBUTES) { + GcdMemoryType = EfiGcdMemoryTypeReserved; + } + 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) { + + // + // 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 = CoreAllocateMemorySpace ( + EfiGcdAllocateAddress, + EfiGcdMemoryTypeSystemMemory, + 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 = CoreAllocateMemorySpace ( + EfiGcdAllocateAddress, + EfiGcdMemoryTypeSystemMemory, + 0, + MemoryHob->AllocDescriptor.MemoryLength, + &BaseAddress, + gDxeCoreImageHandle, + NULL + ); + if (!EFI_ERROR (Status)) { + Status = CoreGetMemorySpaceDescriptor (MemoryHob->AllocDescriptor.MemoryBaseAddress, &Descriptor); + if (!EFI_ERROR (Status)) { + 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 + ); + } + } + + // + // Relocate HOB List to an allocated pool buffer. + // + NewHobList = CoreAllocateCopyPool ( + (UINTN)PhitHob->EfiFreeMemoryBottom - (UINTN)(*HobStart), + *HobStart + ); + ASSERT (NewHobList != NULL); + + *HobStart = NewHobList; + + // + // Add and allocate the remaining unallocated system memory to the memory services. + // + Status = CoreGetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap); + for (Index = 0; Index < NumberOfDescriptors; Index++) { + if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeSystemMemory) { + if (MemorySpaceMap[Index].ImageHandle == NULL) { + BaseAddress = PageAlignAddress (MemorySpaceMap[Index].BaseAddress); + Length = PageAlignLength (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - BaseAddress); + CoreAddMemoryDescriptor ( + EfiConventionalMemory, + BaseAddress, + RShiftU64 (Length, EFI_PAGE_SHIFT), + MemorySpaceMap[Index].Capabilities & (~EFI_MEMORY_RUNTIME) + ); + Status = CoreAllocateMemorySpace ( + EfiGcdAllocateAddress, + EfiGcdMemoryTypeSystemMemory, + 0, + Length, + &BaseAddress, + gDxeCoreImageHandle, + NULL + ); + } + } + } + CoreFreePool (MemorySpaceMap); + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Core/Dxe/Hand/DriverSupport.c b/EdkModulePkg/Core/Dxe/Hand/DriverSupport.c new file mode 100644 index 0000000000..aa601fba08 --- /dev/null +++ b/EdkModulePkg/Core/Dxe/Hand/DriverSupport.c @@ -0,0 +1,848 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DriverSupport.c + +Abstract: + + EFI Driver Support Protocol + +Revision History + +--*/ + +#include + + + +STATIC +EFI_STATUS +GetHandleFromDriverBinding ( + IN EFI_DRIVER_BINDING_PROTOCOL *DriverBindingNeed, + OUT EFI_HANDLE *Handle + ); + + +// +// Driver Support Function Prototypes +// +STATIC +EFI_STATUS +CoreConnectSingleController ( + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE *DriverImageHandle OPTIONAL, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +// +// Driver Support Functions +// + + +EFI_STATUS +EFIAPI +CoreConnectController ( + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE *DriverImageHandle OPTIONAL, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL, + IN BOOLEAN Recursive + ) +/*++ + +Routine Description: + + Connects one or more drivers to a controller. + +Arguments: + + ControllerHandle - Handle of the controller to be connected. + + DriverImageHandle - DriverImageHandle A pointer to an ordered list of driver image handles. + + RemainingDevicePath - RemainingDevicePath A pointer to the device path that specifies a child of the + controller specified by ControllerHandle. + + Recursive - Whether the function would be called recursively or not. + +Returns: + + Status code. + +--*/ +{ + 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; + + // + // Make sure ControllerHandle is valid + // + Status = CoreValidateHandle (ControllerHandle); + if (EFI_ERROR (Status)) { + return Status; + } + + Handle = ControllerHandle; + + // + // Connect all drivers to ControllerHandle + // + AlignedRemainingDevicePath = NULL; + if (RemainingDevicePath != NULL) { + AlignedRemainingDevicePath = CoreDuplicateDevicePath (RemainingDevicePath); + } + ReturnStatus = CoreConnectSingleController ( + ControllerHandle, + DriverImageHandle, + AlignedRemainingDevicePath + ); + if (AlignedRemainingDevicePath != NULL) { + CoreFreePool (AlignedRemainingDevicePath); + } + + // + // If not recursive, then just return after connecting drivers to ControllerHandle + // + if (!Recursive) { + return ReturnStatus; + } + + // + // If recursive, then connect all drivers to all of ControllerHandle's children + // + 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_CHILD_CONTROLLER) != 0) { + CoreReleaseProtocolLock (); + Status = CoreConnectController ( + OpenData->ControllerHandle, + NULL, + NULL, + TRUE + ); + CoreAcquireProtocolLock (); + } + } + } + CoreReleaseProtocolLock (); + + return ReturnStatus; +} + +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 + ) +/*++ + +Routine Description: + + Add Driver Binding Protocols from Context Driver Image Handles to sorted + Driver Binding Protocol list. + +Arguments: + + DriverBindingHandle - Handle of the driver binding protocol. + + NumberOfSortedDriverBindingProtocols - Number Of sorted driver binding protocols + + SortedDriverBindingProtocols - The sorted protocol list. + + DriverBindingHandleCount - Driver Binding Handle Count. + + DriverBindingHandleBuffer - The buffer of driver binding protocol to be modified. + +Returns: + + None. + +--*/ +{ + EFI_STATUS Status; + EFI_DRIVER_BINDING_PROTOCOL *DriverBinding; + UINTN Index; + + // + // Make sure the DriverBindingHandle is valid + // + Status = CoreValidateHandle (DriverBindingHandle); + if (EFI_ERROR (Status)) { + 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++) { + if (DriverBinding == SortedDriverBindingProtocols[Index]) { + return; + } + } + + // + // Add DriverBinding to the end of the list + // + 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; + } + } +} + +STATIC +EFI_STATUS +CoreConnectSingleController ( + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE *ContextDriverImageHandles OPTIONAL, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +/*++ + +Routine Description: + + Connects a controller to a driver. + +Arguments: + + ControllerHandle - Handle of the controller to be connected. + ContextDriverImageHandles - DriverImageHandle A pointer to an ordered list of driver image handles. + RemainingDevicePath - RemainingDevicePath A pointer to the device path that specifies a child + of the controller specified by ControllerHandle. + +Returns: + + EFI_SUCCESS - One or more drivers were connected to ControllerHandle. + EFI_OUT_OF_RESOURCES - No enough system resources to complete the request. + EFI_NOT_FOUND - No drivers were connected to ControllerHandle. + +--*/ +{ + EFI_STATUS Status; + UINTN Index; + EFI_HANDLE DriverImageHandle; + UINTN PlatformDriverOverrideHandleCount; + EFI_HANDLE *PlatformDriverOverrideHandleBuffer; + EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL *PlatformDriverOverride; + EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL *BusSpecificDriverOverride; + UINTN DriverBindingHandleCount; + EFI_HANDLE *DriverBindingHandleBuffer; + EFI_DRIVER_BINDING_PROTOCOL *DriverBinding; + UINTN NumberOfSortedDriverBindingProtocols; + EFI_DRIVER_BINDING_PROTOCOL **SortedDriverBindingProtocols; + UINT32 HighestVersion; + UINTN HighestIndex; + UINTN SortIndex; + BOOLEAN OneStarted; + BOOLEAN DriverFound; + EFI_HANDLE DriverBindingHandle; + + // + // DriverBindingHandle is used for performance measurement, initialize it here just in case. + // + DriverBindingHandle = NULL; + // + // Initialize local variables + // + DriverBindingHandleCount = 0; + DriverBindingHandleBuffer = NULL; + PlatformDriverOverrideHandleCount = 0; + PlatformDriverOverrideHandleBuffer = NULL; + NumberOfSortedDriverBindingProtocols = 0; + SortedDriverBindingProtocols = 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 = CoreAllocateBootServicesPool (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 + ); + } + } + + // + // 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 + ); + } + } while (!EFI_ERROR (Status)); + } + + // + // 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 + ); + } + } 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 + ); + } + + // + // Free the Driver Binding Handle Buffer + // + CoreFreePool (DriverBindingHandleBuffer); + + // + // Sort the remaining DriverBinding Protocol based on their Version field from + // highest to lowest. + // + for ( ; SortIndex < DriverBindingHandleCount; SortIndex++) { + HighestVersion = SortedDriverBindingProtocols[SortIndex]->Version; + HighestIndex = SortIndex; + for (Index = SortIndex + 1; Index < DriverBindingHandleCount; 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]; + Status = DriverBinding->Supported( + DriverBinding, + ControllerHandle, + RemainingDevicePath + ); + 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_CODE_BEGIN (); + GetHandleFromDriverBinding (DriverBinding, &DriverBindingHandle); + PERF_CODE_END (); + + PERF_START (DriverBindingHandle, DRIVERBINDING_START_TOK, NULL, 0); + Status = DriverBinding->Start ( + DriverBinding, + ControllerHandle, + RemainingDevicePath + ); + PERF_END (DriverBindingHandle, DRIVERBINDING_START_TOK, NULL, 0); + + 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; +} + + +EFI_STATUS +EFIAPI +CoreDisconnectController ( + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE DriverImageHandle OPTIONAL, + IN EFI_HANDLE ChildHandle OPTIONAL + ) +/*++ + +Routine Description: + + Disonnects a controller from a driver + +Arguments: + + ControllerHandle - ControllerHandle The handle of the controller from which driver(s) + are to be disconnected. + DriverImageHandle - DriverImageHandle The driver to disconnect from ControllerHandle. + ChildHandle - ChildHandle The handle of the child to destroy. + +Returns: + + EFI_SUCCESS - One or more drivers were disconnected from the controller. + EFI_SUCCESS - On entry, no drivers are managing ControllerHandle. + EFI_SUCCESS - DriverImageHandle is not NULL, and on entry DriverImageHandle is not managing ControllerHandle. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - DriverImageHandle is not NULL, and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL, and it is not a valid EFI_HANDLE. + EFI_OUT_OF_RESOURCES - There are not enough resources available to disconnect any drivers from ControllerHandle. + EFI_DEVICE_ERROR - The controller could not be disconnected because of a device error. + +--*/ +{ + 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 = CoreAllocateBootServicesPool (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)) { + 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 = CoreAllocateBootServicesPool (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; +} + + + +STATIC +EFI_STATUS +GetHandleFromDriverBinding ( + IN EFI_DRIVER_BINDING_PROTOCOL *DriverBindingNeed, + OUT EFI_HANDLE *Handle + ) +/*++ + +Routine Description: + + Locate the driver binding handle which a specified driver binding protocol installed on. + +Arguments: + + DriverBindingNeed - The specified driver binding protocol. + + Handle - The driver binding handle which the protocol installed on. + + +Returns: + + EFI_NOT_FOUND - Could not find the handle. + + EFI_SUCCESS - Successfully find the associated driver binding handle. + +--*/ + { + EFI_STATUS Status ; + EFI_DRIVER_BINDING_PROTOCOL *DriverBinding; + UINTN DriverBindingHandleCount; + EFI_HANDLE *DriverBindingHandleBuffer; + UINTN Index; + + DriverBindingHandleCount = 0; + DriverBindingHandleBuffer = NULL; + *Handle = NULL_HANDLE; + Status = CoreLocateHandleBuffer ( + ByProtocol, + &gEfiDriverBindingProtocolGuid, + NULL, + &DriverBindingHandleCount, + &DriverBindingHandleBuffer + ); + if (EFI_ERROR (Status) || DriverBindingHandleCount == 0) { + return EFI_NOT_FOUND; + } + + for (Index = 0 ; Index < DriverBindingHandleCount; Index++ ) { + Status = CoreOpenProtocol( + DriverBindingHandleBuffer[Index], + &gEfiDriverBindingProtocolGuid, + (VOID **)&DriverBinding, + gDxeCoreImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (!EFI_ERROR (Status) && DriverBinding != NULL) { + + if ( DriverBinding == DriverBindingNeed ) { + *Handle = DriverBindingHandleBuffer[Index]; + CoreFreePool (DriverBindingHandleBuffer); + return EFI_SUCCESS ; + } + } + } + + CoreFreePool (DriverBindingHandleBuffer); + return EFI_NOT_FOUND ; +} + diff --git a/EdkModulePkg/Core/Dxe/Hand/Notify.c b/EdkModulePkg/Core/Dxe/Hand/Notify.c new file mode 100644 index 0000000000..f48fee76cb --- /dev/null +++ b/EdkModulePkg/Core/Dxe/Hand/Notify.c @@ -0,0 +1,333 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + notify.c + +Abstract: + + EFI notify infrastructure + + + +Revision History + +--*/ + +#include + +VOID +CoreNotifyProtocolEntry ( + IN PROTOCOL_ENTRY *ProtEntry + ) +/*++ + +Routine Description: + + Signal event for every protocol in protocol entry. + +Arguments: + + ProtEntry - Protocol entry + +Returns: + +--*/ +{ + 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); + } +} + + +PROTOCOL_INTERFACE * +CoreRemoveInterfaceFromProtocol ( + IN IHANDLE *Handle, + IN EFI_GUID *Protocol, + IN VOID *Interface + ) +/*++ + +Routine Description: + + Removes Protocol from the protocol list (but not the handle list). + +Arguments: + + Handle - The handle to remove protocol on. + + Protocol - GUID of the protocol to be moved + + Interface - The interface of the protocol + +Returns: + + Protocol Entry + +--*/ +{ + 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; +} + + + +EFI_STATUS +EFIAPI +CoreRegisterProtocolNotify ( + IN EFI_GUID *Protocol, + IN EFI_EVENT Event, + OUT VOID **Registration + ) +/*++ + +Routine Description: + + Add a new protocol notification record for the request protocol. + +Arguments: + + Protocol - The requested protocol to add the notify registration + + Event - The event to signal + + Registration - Returns the registration record + + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_SUCCESS - Successfully returned the registration record that has been added + +--*/ +{ + 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 = CoreAllocateBootServicesPool (sizeof(PROTOCOL_NOTIFY)); + + if (ProtNotify != NULL) { + + 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; +} + + + +EFI_STATUS +EFIAPI +CoreReinstallProtocolInterface ( + IN EFI_HANDLE UserHandle, + IN EFI_GUID *Protocol, + IN VOID *OldInterface, + IN VOID *NewInterface + ) +/*++ + +Routine Description: + + Reinstall a protocol interface on a device handle. The OldInterface for Protocol is replaced by the NewInterface. + +Arguments: + + UserHandle - Handle on which the interface is to be reinstalled + Protocol - The numeric ID of the interface + OldInterface - A pointer to the old interface + NewInterface - A pointer to the new interface + + +Returns: + + Status code. + + On EFI_SUCCESS The protocol interface was installed + On EFI_NOT_FOUND The OldInterface on the handle was not found + On EFI_INVALID_PARAMETER One of the parameters has an invalid value + +--*/ +{ + 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) { + CoreReleaseProtocolLock (); + return EFI_NOT_FOUND; + } + + // + // 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 + // + CoreReleaseProtocolLock (); + return Status; + } + + // + // Remove the protocol interface from the protocol + // + Prot = CoreRemoveInterfaceFromProtocol (Handle, Protocol, OldInterface); + + if (Prot == NULL) { + CoreReleaseProtocolLock (); + return EFI_NOT_FOUND; + } + + 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 (); + Status = CoreConnectController ( + UserHandle, + NULL, + NULL, + TRUE + ); + CoreAcquireProtocolLock (); + + // + // Notify the notification list for this protocol + // + CoreNotifyProtocolEntry (ProtEntry); + + CoreReleaseProtocolLock (); + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Core/Dxe/Hand/handle.c b/EdkModulePkg/Core/Dxe/Hand/handle.c new file mode 100644 index 0000000000..2edfdeb78b --- /dev/null +++ b/EdkModulePkg/Core/Dxe/Hand/handle.c @@ -0,0 +1,1699 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + handle.c + +Abstract: + + EFI handle & protocol handling + + + +Revision History + +--*/ + +#include + + +// +// 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 +// +static LIST_ENTRY mProtocolDatabase = INITIALIZE_LIST_HEAD_VARIABLE (mProtocolDatabase); +LIST_ENTRY gHandleList = INITIALIZE_LIST_HEAD_VARIABLE (gHandleList); +EFI_LOCK gProtocolDatabaseLock = EFI_INITIALIZE_LOCK_VARIABLE (EFI_TPL_NOTIFY); +UINT64 gHandleDatabaseKey = 0; + + +VOID +CoreAcquireProtocolLock ( + VOID + ) +/*++ + +Routine Description: + + Acquire lock on gProtocolDatabaseLock. + +Arguments: + + None + +Returns: + + None + +--*/ +{ + CoreAcquireLock (&gProtocolDatabaseLock); +} + + +VOID +CoreReleaseProtocolLock ( + VOID + ) +/*++ + +Routine Description: + + Release lock on gProtocolDatabaseLock. + +Arguments: + + None + +Returns: + + None + +--*/ +{ + CoreReleaseLock (&gProtocolDatabaseLock); +} + + +EFI_STATUS +CoreValidateHandle ( + IN EFI_HANDLE UserHandle + ) +/*++ + +Routine Description: + + Check whether a handle is a valid EFI_HANDLE + +Arguments: + + UserHandle - The handle to check + +Returns: + + EFI_INVALID_PARAMETER - The handle is NULL or not a valid EFI_HANDLE. + + EFI_SUCCESS - The handle is valid EFI_HANDLE. + +--*/ +{ + 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; +} + + +PROTOCOL_ENTRY * +CoreFindProtocolEntry ( + IN EFI_GUID *Protocol, + IN BOOLEAN Create + ) +/*++ + +Routine Description: + + Finds the protocol entry for the requested protocol. + + The gProtocolDatabaseLock must be owned + +Arguments: + + Protocol - The ID of the protocol + + Create - Create a new entry if not found + +Returns: + + Protocol entry + +--*/ +{ + 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 = CoreAllocateBootServicesPool (sizeof(PROTOCOL_ENTRY)); + + if (ProtEntry != NULL) { + // + // Initialize new protocol entry structure + // + ProtEntry->Signature = PROTOCOL_ENTRY_SIGNATURE; + CopyMem ((VOID *)&ProtEntry->ProtocolID, Protocol, sizeof (EFI_GUID)); + InitializeListHead (&ProtEntry->Protocols); + InitializeListHead (&ProtEntry->Notify); + + // + // Add it to protocol database + // + InsertTailList (&mProtocolDatabase, &ProtEntry->AllEntries); + } + } + + return ProtEntry; +} + + +PROTOCOL_INTERFACE * +CoreFindProtocolInterface ( + IN IHANDLE *Handle, + IN EFI_GUID *Protocol, + IN VOID *Interface + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + Handle - The handle to search the protocol on + + Protocol - GUID of the protocol + + Interface - The interface for the protocol being searched + +Returns: + + Protocol instance (NULL: Not found) + +--*/ +{ + 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; +} + +STATIC +EFI_STATUS +CoreUnregisterProtocolNotifyEvent ( + IN EFI_EVENT Event + ) +/*++ + +Routine Description: + + Removes an event from a register protocol notify list on a protocol. + +Arguments: + + Event - The event to search for in the protocol database. + +Returns: + + EFI_SUCCESS if the event was found and removed. + EFI_NOT_FOUND if the event was not found in the protocl database. + +--*/ +{ + 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; +} + + +EFI_STATUS +CoreUnregisterProtocolNotify ( + IN EFI_EVENT Event + ) +/*++ + +Routine Description: + + Removes all the events in the protocol database that match Event. + +Arguments: + + Event - The event to search for in the protocol database. + +Returns: + + EFI_SUCCESS when done searching the entire database. + +--*/ +{ + EFI_STATUS Status; + + do { + Status = CoreUnregisterProtocolNotifyEvent (Event); + } while (!EFI_ERROR (Status)); + + return EFI_SUCCESS; +} + + + +EFI_STATUS +EFIAPI +CoreInstallProtocolInterface ( + IN OUT EFI_HANDLE *UserHandle, + IN EFI_GUID *Protocol, + IN EFI_INTERFACE_TYPE InterfaceType, + IN VOID *Interface + ) +/*++ + +Routine Description: + + Wrapper function to CoreInstallProtocolInterfaceNotify. This is the public API which + Calls the private one which contains a BOOLEAN parameter for notifications + +Arguments: + + UserHandle - The handle to install the protocol handler on, + or NULL if a new handle is to be allocated + + Protocol - The protocol to add to the handle + + InterfaceType - Indicates whether Interface is supplied in native form. + + Interface - The interface for the protocol being added + +Returns: + + Status code + +--*/ +{ + return CoreInstallProtocolInterfaceNotify ( + UserHandle, + Protocol, + InterfaceType, + Interface, + TRUE + ); +} + +EFI_STATUS +CoreInstallProtocolInterfaceNotify ( + IN OUT EFI_HANDLE *UserHandle, + IN EFI_GUID *Protocol, + IN EFI_INTERFACE_TYPE InterfaceType, + IN VOID *Interface, + IN BOOLEAN Notify + ) +/*++ + +Routine Description: + + Installs a protocol interface into the boot services environment. + +Arguments: + + UserHandle - The handle to install the protocol handler on, + or NULL if a new handle is to be allocated + + Protocol - The protocol to add to the handle + + InterfaceType - Indicates whether Interface is supplied in native form. + + Interface - The interface for the protocol being added + + Notify - indicates whether notify the notification list + for this protocol + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_OUT_OF_RESOURCES - No enough buffer to allocate + + EFI_SUCCESS - Protocol interface successfully installed + +--*/ +{ + 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((EFI_D_ERROR | EFI_D_INFO, "InstallProtocolInterface: %g %x\n", Protocol, Interface)); + + Status = EFI_OUT_OF_RESOURCES; + Prot = NULL; + Handle = NULL; + + ASSERT (NULL != gBS); + + if (*UserHandle != NULL_HANDLE) { + 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 = CoreAllocateZeroBootServicesPool (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 = CoreAllocateZeroBootServicesPool (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); + } + + Status = CoreValidateHandle (Handle); + if (EFI_ERROR (Status)) { + 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); + } + } + + return Status; +} + + + +EFI_STATUS +EFIAPI +CoreInstallMultipleProtocolInterfaces ( + IN OUT EFI_HANDLE *Handle, + ... + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + Handle - The handle to install the protocol handlers on, + or NULL if a new handle is to be allocated + ... - 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. + +Returns: + + EFI_INVALID_PARAMETER - Handle is NULL. + + EFI_SUCCESS - Protocol interfaces successfully installed. + +--*/ +{ + 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 (EFI_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_HANDLE) && IsDevicePathEnd(DevicePath)) { + Status = EFI_ALREADY_STARTED; + continue; + } + } + + // + // Install it + // + Status = CoreInstallProtocolInterface (Handle, Protocol, EFI_NATIVE_INTERFACE, Interface); + } + + // + // 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); + } + *Handle = OldHandle; + } + + // + // Done + // + CoreRestoreTpl (OldTpl); + return Status; +} + +EFI_STATUS +CoreDisconnectControllersUsingProtocolInterface ( + IN EFI_HANDLE UserHandle, + IN PROTOCOL_INTERFACE *Prot + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + UserHandle - The handle on which the protocol is installed + Prot - The protocol to disconnect drivers from + +Returns: + + EFI_SUCCESS - Drivers using the protocol interface are all disconnected + EFI_ACCESS_DENIED - Failed to disconnect one or all of the drivers + +--*/ +{ + 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) && !ItemFound; + Link = Link->ForwardLink ) { + OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE); + if (OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) { + ItemFound = TRUE; + CoreReleaseProtocolLock (); + Status = CoreDisconnectController (UserHandle, OpenData->AgentHandle, NULL); + CoreAcquireProtocolLock (); + if (EFI_ERROR (Status)) { + ItemFound = FALSE; + break; + } + } + } + } while (ItemFound); + + if (!EFI_ERROR (Status)) { + // + // Attempt to remove BY_HANDLE_PROTOOCL and GET_PROTOCOL and TEST_PROTOCOL Open List items + // + do { + ItemFound = FALSE; + for ( Link = Prot->OpenList.ForwardLink; + (Link != &Prot->OpenList) && !ItemFound; + Link = Link->ForwardLink ) { + 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)) { + ItemFound = TRUE; + RemoveEntryList (&OpenData->Link); + Prot->OpenListCount--; + CoreFreePool (OpenData); + } + } + } while (ItemFound); + } + + // + // 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; +} + + +EFI_STATUS +EFIAPI +CoreUninstallProtocolInterface ( + IN EFI_HANDLE UserHandle, + IN EFI_GUID *Protocol, + IN VOID *Interface + ) +/*++ + +Routine Description: + + Uninstalls all instances of a protocol:interfacer from a handle. + If the last protocol interface is remove from the handle, the + handle is freed. + +Arguments: + + UserHandle - The handle to remove the protocol handler from + + Protocol - The protocol, of protocol:interface, to remove + + Interface - The interface, of protocol:interface, to remove + +Returns: + + EFI_INVALID_PARAMETER - Protocol is NULL. + + EFI_SUCCESS - Protocol interface successfully uninstalled. + +--*/ +{ + 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; +} + + + +EFI_STATUS +EFIAPI +CoreUninstallMultipleProtocolInterfaces ( + IN EFI_HANDLE Handle, + ... + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + Handle - The handle to uninstall the protocol + + ... - 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. + +Returns: + + Status code + +--*/ +{ + 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); + } + + // + // 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); + } + } + + return Status; +} + +PROTOCOL_INTERFACE * +CoreGetProtocolInterface ( + IN EFI_HANDLE UserHandle, + IN EFI_GUID *Protocol + ) +/*++ + +Routine Description: + + Locate a certain GUID protocol interface in a Handle's protocols. + +Arguments: + + UserHandle - The handle to obtain the protocol interface on + + Protocol - The GUID of the protocol + +Returns: + + The requested protocol interface for the handle + +--*/ +{ + 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; +} + + +EFI_STATUS +EFIAPI +CoreHandleProtocol ( + IN EFI_HANDLE UserHandle, + IN EFI_GUID *Protocol, + OUT VOID **Interface + ) +/*++ + +Routine Description: + + Queries a handle to determine if it supports a specified protocol. + +Arguments: + + UserHandle - The handle being queried. + + Protocol - The published unique identifier of the protocol. + + Interface - Supplies the address where a pointer to the corresponding Protocol + Interface is returned. + +Returns: + + The requested protocol interface for the handle + +--*/ +{ + return CoreOpenProtocol ( + UserHandle, + Protocol, + Interface, + gDxeCoreImageHandle, + NULL, + EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL + ); +} + + +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 + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + UserHandle - The handle to obtain the protocol interface on + + Protocol - The ID of the protocol + + Interface - The location to return the protocol interface + + ImageHandle - The handle of the Image that is opening the protocol interface + specified by Protocol and Interface. + + ControllerHandle - The controller handle that is requiring this interface. + + Attributes - The open mode of the protocol interface specified by Handle + and Protocol. + +Returns: + + EFI_INVALID_PARAMETER - Protocol is NULL. + + EFI_SUCCESS - Get the protocol interface. + +--*/ +{ + 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) { + if (Interface == NULL) { + return EFI_INVALID_PARAMETER; + } else { + *Interface = NULL; + } + } + + // + // 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; + } + + // + // This is the protocol interface entry for this protocol + // + if (Attributes != EFI_OPEN_PROTOCOL_TEST_PROTOCOL) { + *Interface = Prot->Interface; + } + 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) { + ByDriver = TRUE; + if (ExactMatch) { + Status = EFI_ALREADY_STARTED; + goto Done; + } + } + if (OpenData->Attributes & EFI_OPEN_PROTOCOL_EXCLUSIVE) { + 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) && (!Disconnect); Link = Link->ForwardLink) { + OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE); + if (OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) { + Disconnect = TRUE; + CoreReleaseProtocolLock (); + Status = CoreDisconnectController (UserHandle, OpenData->AgentHandle, NULL); + CoreAcquireProtocolLock (); + if (EFI_ERROR (Status)) { + Status = EFI_ACCESS_DENIED; + goto Done; + } + } + } + } 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 = CoreAllocateBootServicesPool (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: + // + // Done. Release the database lock are return + // + CoreReleaseProtocolLock (); + return Status; +} + + +EFI_STATUS +EFIAPI +CoreCloseProtocol ( + IN EFI_HANDLE UserHandle, + IN EFI_GUID *Protocol, + IN EFI_HANDLE AgentHandle, + IN EFI_HANDLE ControllerHandle + ) +/*++ + +Routine Description: + + Closes a protocol on a handle that was opened using OpenProtocol(). + +Arguments: + + UserHandle - The handle for the protocol interface that was previously opened + with OpenProtocol(), and is now being closed. + Protocol - The published unique identifier of the protocol. It is the caller¡¯s + responsibility to pass in a valid GUID. + AgentHandle - The handle of the agent that is closing the protocol interface. + 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. + +Returns: + + EFI_SUCCESS - The protocol instance was closed. + EFI_INVALID_PARAMETER - Handle, AgentHandle or ControllerHandle is not a valid EFI_HANDLE. + EFI_NOT_FOUND - Can not find the specified protocol or AgentHandle. + +--*/ +{ + 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_HANDLE) { + 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; +} + + + +EFI_STATUS +EFIAPI +CoreOpenProtocolInformation ( + IN EFI_HANDLE UserHandle, + IN EFI_GUID *Protocol, + OUT EFI_OPEN_PROTOCOL_INFORMATION_ENTRY **EntryBuffer, + OUT UINTN *EntryCount + ) +/*++ + +Routine Description: + + Return information about Opened protocols in the system + +Arguments: + + UserHandle - The handle to close the protocol interface on + + Protocol - The ID of the protocol + + EntryBuffer - A pointer to a buffer of open protocol information in the form of + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY structures. + + EntryCount - Number of EntryBuffer entries + +Returns: + + +--*/ +{ + 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 = CoreAllocateBootServicesPool (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 are return + // + CoreReleaseProtocolLock (); + return Status; +} + + + +EFI_STATUS +EFIAPI +CoreProtocolsPerHandle ( + IN EFI_HANDLE UserHandle, + OUT EFI_GUID ***ProtocolBuffer, + OUT UINTN *ProtocolBufferCount + ) +/*++ + +Routine Description: + + Retrieves the list of protocol interface GUIDs that are installed on a handle in a buffer allocated + from pool. + +Arguments: + + UserHandle - The handle from which to retrieve the list of protocol interface + GUIDs. + + ProtocolBuffer - A pointer to the list of protocol interface GUID pointers that are + installed on Handle. + + ProtocolBufferCount - A pointer to the number of GUID pointers present in + ProtocolBuffer. + +Returns: + 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. + EFI_INVALID_PARAMETER - Handle is NULL. + EFI_INVALID_PARAMETER - Handle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ProtocolBuffer is NULL. + EFI_INVALID_PARAMETER - ProtocolBufferCount is NULL. + EFI_OUT_OF_RESOURCES - There is not enough pool memory to store the results. + +--*/ +{ + 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 = CoreAllocateBootServicesPool (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; +} + + +UINT64 +CoreGetHandleDatabaseKey ( + VOID + ) +/*++ + +Routine Description: + + return handle database key. + +Arguments: + + None + +Returns: + + Handle database key. + +--*/ +{ + return gHandleDatabaseKey; +} + + +VOID +CoreConnectHandlesByKey ( + UINT64 Key + ) +/*++ + +Routine Description: + + Go connect any handles that were created or modified while a image executed. + +Arguments: + + Key - The Key to show that the handle has been created/modified + +Returns: + + None +--*/ +{ + 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 = CoreAllocateBootServicesPool (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/EdkModulePkg/Core/Dxe/Hand/locate.c b/EdkModulePkg/Core/Dxe/Hand/locate.c new file mode 100644 index 0000000000..faa4255c7e --- /dev/null +++ b/EdkModulePkg/Core/Dxe/Hand/locate.c @@ -0,0 +1,737 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + locate.c + +Abstract: + + Locate handle functions + +Revision History + +--*/ + +#include + +// +// 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 + ); + +STATIC +IHANDLE * +CoreGetNextLocateAllHandles ( + IN OUT LOCATE_POSITION *Position, + OUT VOID **Interface + ); + +STATIC +IHANDLE * +CoreGetNextLocateByRegisterNotify ( + IN OUT LOCATE_POSITION *Position, + OUT VOID **Interface + ); + +STATIC +IHANDLE * +CoreGetNextLocateByProtocol ( + IN OUT LOCATE_POSITION *Position, + OUT VOID **Interface + ); + +// +// +// + + + + +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 + ) +/*++ + +Routine Description: + + Locates the requested handle(s) and returns them in Buffer. + +Arguments: + + SearchType - The type of search to perform to locate the handles + + Protocol - The protocol to search for + + SearchKey - Dependant on SearchType + + BufferSize - On input the size of Buffer. On output the + size of data returned. + + Buffer - The buffer to return the results in + + +Returns: + + EFI_BUFFER_TOO_SMALL - Buffer too small, required buffer size is returned in BufferSize. + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_SUCCESS - Successfully found the requested handle(s) and returns them in 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) { + Status = 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; + } + + // + // 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 + // + ProtNotify = SearchKey; + ProtNotify->Position = ProtNotify->Position->ForwardLink; + } + } + + CoreReleaseProtocolLock (); + return Status; +} + + +STATIC +IHANDLE * +CoreGetNextLocateAllHandles ( + IN OUT LOCATE_POSITION *Position, + OUT VOID **Interface + ) +/*++ + +Routine Description: + + Routine to get the next Handle, when you are searching for all handles. + +Arguments: + + Position - Information about which Handle to seach for. + + Interface - Return the interface structure for the matching protocol. + +Returns: + IHANDLE - An IHANDLE is returned if the next Position is not the end of the + list. A NULL_HANDLE is returned if it's the end of the list. + +--*/ +{ + IHANDLE *Handle; + + // + // Next handle + // + Position->Position = Position->Position->ForwardLink; + + // + // If not at the end of the list, get the handle + // + Handle = NULL_HANDLE; + *Interface = NULL; + if (Position->Position != &gHandleList) { + Handle = CR (Position->Position, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE); + } + + return Handle; +} + + +STATIC +IHANDLE * +CoreGetNextLocateByRegisterNotify ( + IN OUT LOCATE_POSITION *Position, + OUT VOID **Interface + ) +/*++ + +Routine Description: + + Routine to get the next Handle, when you are searching for register protocol + notifies. + +Arguments: + + Position - Information about which Handle to seach for. + + Interface - Return the interface structure for the matching protocol. + +Returns: + IHANDLE - An IHANDLE is returned if the next Position is not the end of the + list. A NULL_HANDLE is returned if it's the end of the list. + +--*/ +{ + IHANDLE *Handle; + PROTOCOL_NOTIFY *ProtNotify; + PROTOCOL_INTERFACE *Prot; + LIST_ENTRY *Link; + + Handle = NULL_HANDLE; + *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 = (IHANDLE *) Prot->Handle; + *Interface = Prot->Interface; + } + } + + return Handle; +} + + +STATIC +IHANDLE * +CoreGetNextLocateByProtocol ( + IN OUT LOCATE_POSITION *Position, + OUT VOID **Interface + ) +/*++ + +Routine Description: + + Routine to get the next Handle, when you are searching for a given protocol. + +Arguments: + + Position - Information about which Handle to seach for. + + Interface - Return the interface structure for the matching protocol. + +Returns: + IHANDLE - An IHANDLE is returned if the next Position is not the end of the + list. A NULL_HANDLE is returned if it's the end of the list. + +--*/ +{ + IHANDLE *Handle; + LIST_ENTRY *Link; + PROTOCOL_INTERFACE *Prot; + + Handle = NULL_HANDLE; + *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_HANDLE; + break; + } + + // + // Get the handle + // + Prot = CR(Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE); + Handle = (IHANDLE *) 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; +} + + + +EFI_STATUS +EFIAPI +CoreLocateDevicePath ( + IN EFI_GUID *Protocol, + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath, + OUT EFI_HANDLE *Device + ) +/*++ + +Routine Description: + + Locates the handle to a device on the device path that best matches the specified protocol. + +Arguments: + + Protocol - The protocol to search for. + 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. + Device - A pointer to the returned device handle. + +Returns: + + EFI_SUCCESS - The resulting handle was returned. + EFI_NOT_FOUND - No handles matched the search. + EFI_INVALID_PARAMETER - One of the parameters has an invalid value. + +--*/ +{ + INTN SourceSize; + INTN Size; + INTN BestMatch; + UINTN HandleCount; + UINTN Index; + EFI_STATUS Status; + EFI_HANDLE *Handles; + EFI_HANDLE Handle; + 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; + } + + if (Device == NULL) { + return EFI_INVALID_PARAMETER; + } + + *Device = NULL_HANDLE; + SourcePath = *DevicePath; + SourceSize = CoreDevicePathSize (SourcePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL); + + // + // The source path can only have 1 instance + // + if (CoreIsDevicePathMultiInstance (SourcePath)) { + DEBUG((EFI_D_ERROR, "LocateDevicePath: Device path has too many instances\n")); + return EFI_INVALID_PARAMETER; + } + + // + // 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 = CoreDevicePathSize (TmpDevicePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL); + if ((Size <= SourceSize) && CompareMem (SourcePath, TmpDevicePath, Size) == 0) { + // + // If the size is equal to the best match, then we + // have a duplice 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; + *Device = 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; + } + + // + // Return the remaining part of the device path + // + *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) (((UINT8 *) SourcePath) + BestMatch); + return EFI_SUCCESS; +} + + + +EFI_STATUS +EFIAPI +CoreLocateProtocol ( + IN EFI_GUID *Protocol, + IN VOID *Registration OPTIONAL, + OUT VOID **Interface + ) +/*++ + +Routine Description: + + 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 Retistration is NULL return the first Protocol Interface + you find. + +Arguments: + + Protocol - The protocol to search for + + Registration - Optional Registration Key returned from RegisterProtocolNotify() + + Interface - Return the Protocol interface (instance). + +Returns: + + EFI_SUCCESS - If a valid Interface is returned + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_NOT_FOUND - Protocol interface not found + +--*/ +{ + EFI_STATUS Status; + LOCATE_POSITION Position; + PROTOCOL_NOTIFY *ProtNotify; + IHANDLE *Handle; + + if (Interface == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Protocol == NULL) { + return EFI_NOT_FOUND; + } + + *Interface = NULL; + Status = EFI_SUCCESS; + + // + // Set initial position + // + Position.Protocol = Protocol; + Position.SearchKey = Registration; + Position.Position = &gHandleList; + + // + // Lock the protocol database + // + CoreAcquireProtocolLock (); + + mEfiLocateHandleRequest += 1; + + if (NULL == Registration) { + // + // 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 (NULL == Handle) { + Status = EFI_NOT_FOUND; + } else if (NULL != Registration) { + // + // 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; +} + + + +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 + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + SearchType - Specifies which handle(s) are to be returned. + Protocol - Provides the protocol to search by. + This parameter is only valid for SearchType ByProtocol. + SearchKey - Supplies the search key depending on the SearchType. + NumberHandles - The number of handles returned in Buffer. + Buffer - A pointer to the buffer to return the requested array of + handles that support Protocol. + +Returns: + + EFI_SUCCESS - The result array of handles was returned. + EFI_NOT_FOUND - No handles match the search. + EFI_OUT_OF_RESOURCES - There is not enough pool memory to store the matching results. + EFI_INVALID_PARAMETER - Invalid parameter + +--*/ +{ + 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)) { + switch (Status) { + case EFI_BUFFER_TOO_SMALL: + break; + case EFI_INVALID_PARAMETER: + return Status; + default: + return EFI_NOT_FOUND; + } + } + + *Buffer = CoreAllocateBootServicesPool (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/EdkModulePkg/Core/Dxe/Image.h b/EdkModulePkg/Core/Dxe/Image.h new file mode 100644 index 0000000000..067d42d4b5 --- /dev/null +++ b/EdkModulePkg/Core/Dxe/Image.h @@ -0,0 +1,380 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Image.h + +Abstract: + +Revision History + +--*/ + + +#ifndef _IMAGE_H_ +#define _IMAGE_H_ + + + +#define LOADED_IMAGE_PRIVATE_DATA_SIGNATURE EFI_SIGNATURE_32('l','d','r','i') + +typedef struct { + UINTN Signature; + EFI_HANDLE Handle; // Image handle + UINTN Type; // Image type + + BOOLEAN Started; // If entrypoint has been called + + EFI_IMAGE_ENTRY_POINT EntryPoint; // The image's entry point + EFI_LOADED_IMAGE_PROTOCOL Info; // loaded image protocol + + EFI_PHYSICAL_ADDRESS ImageBasePage; // Location in memory + UINTN NumberOfPages; // Number of pages + + CHAR8 *FixupData; // Original fixup data + + EFI_TPL Tpl; // Tpl of started image + EFI_STATUS Status; // Status returned by started image + + UINTN ExitDataSize; // Size of ExitData from started image + VOID *ExitData; // Pointer to exit data from started image + BASE_LIBRARY_JUMP_BUFFER *JumpContext; // Pointer to buffer for context save/retore + UINT16 Machine; // Machine type from PE image + + EFI_EBC_PROTOCOL *Ebc; // EBC Protocol pointer + + BOOLEAN RuntimeFixupValid; // True if RT image needs fixup + VOID *RuntimeFixup; // Copy of fixup data; + LIST_ENTRY Link; // List of RT LOADED_IMAGE_PRIVATE_DATA + + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; // PeCoffLoader ImageContext + +} 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 LOAD_PE32_IMAGE_PRIVATE_DATA_SIGNATURE EFI_SIGNATURE_32('l','p','e','i') + +typedef struct { + UINTN Signature; + EFI_HANDLE Handle; // Image handle + EFI_PE32_IMAGE_PROTOCOL Pe32Image; +} LOAD_PE32_IMAGE_PRIVATE_DATA; + +#define LOAD_PE32_IMAGE_PRIVATE_DATA_FROM_THIS(a) \ + CR(a, LOAD_PE32_IMAGE_PRIVATE_DATA, Pe32Image, LOAD_PE32_IMAGE_PRIVATE_DATA_SIGNATURE) + + + +// +// Private Data Types +// +#define IMAGE_FILE_HANDLE_SIGNATURE EFI_SIGNATURE_32('i','m','g','f') +typedef struct { + UINTN Signature; + BOOLEAN FreeBuffer; + VOID *Source; + UINTN SourceSize; +} IMAGE_FILE_HANDLE; + + +// +// Abstractions for reading image contents +// + +EFI_STATUS +CoreOpenImageFile ( + IN BOOLEAN BootPolicy, + IN VOID *SourceBuffer OPTIONAL, + IN UINTN SourceSize, + IN OUT EFI_DEVICE_PATH_PROTOCOL *FilePath, + OUT EFI_HANDLE *DeviceHandle, + IN IMAGE_FILE_HANDLE *ImageFileHandle, + OUT UINT32 *AuthenticationStatus + ) +/*++ + +Routine Description: + + Opens a file for (simple) reading. The simple read abstraction + will access the file either from a memory copy, from a file + system interface, or from the load file interface. + +Arguments: + + BootPolicy - Policy for Open Image File. + SourceBuffer - Pointer to the memory location containing copy + of the image to be loaded. + SourceSize - The size in bytes of SourceBuffer. + FilePath - The specific file path from which the image is loaded + DeviceHandle - Pointer to the return device handle. + ImageFileHandle - Pointer to the image file handle. + AuthenticationStatus - Pointer to a caller-allocated UINT32 in which the authentication status is returned. + +Returns: + + A handle to access the file + +--*/ +; + + +EFI_STATUS +EFIAPI +CoreReadImageFile ( + IN VOID *UserHandle, + IN UINTN Offset, + IN OUT UINTN *ReadSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Read image file (specified by UserHandle) into user specified buffer with specified offset + and length. + +Arguments: + + UserHandle - Image file handle + + Offset - Offset to the source file + + ReadSize - For input, pointer of size to read; + For output, pointer of size actually read. + + Buffer - Buffer to write into + +Returns: + + EFI_SUCCESS - Successfully read the specified part of file into buffer. + +--*/ +; + +VOID +EFIAPI +CoreCloseImageFile ( + IN IMAGE_FILE_HANDLE *ImageFileHandle + ) +/*++ + +Routine Description: + + A function out of date, should be removed. + +Arguments: + + ImageFileHandle - Handle of the file to close + +Returns: + + None + +--*/ +; + +// +// Image processing worker functions +// +EFI_STATUS +CoreDevicePathToInterface ( + IN EFI_GUID *Protocol, + IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath, + OUT VOID **Interface, + OUT EFI_HANDLE *Handle + ) +/*++ + +Routine Description: + + Search a handle to a device on a specified device path that supports a specified protocol, + interface of that protocol on that handle is another output. + +Arguments: + + Protocol - The protocol to search for + + FilePath - The specified device path + + Interface - Interface of the protocol on the handle + + Handle - The handle to the device on the specified device path that supports the protocol. + +Returns: + + Status code. + +--*/ +; + +EFI_STATUS +CoreLoadPeImage ( + IN VOID *Pe32Handle, + IN LOADED_IMAGE_PRIVATE_DATA *Image, + IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL, + OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL, + IN UINT32 Attribute + ) +/*++ + +Routine Description: + + Loads, relocates, and invokes a PE/COFF image + +Arguments: + + Pe32Handle - The handle of PE32 image + Image - PE image to be loaded + DstBuffer - The buffer to store the image + EntryPoint - A pointer to the entry point + Attribute - The bit mask of attributes to set for the load PE image + +Returns: + + EFI_SUCCESS - The file was loaded, relocated, and invoked + + EFI_OUT_OF_RESOURCES - There was not enough memory to load and relocate the PE/COFF file + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_BUFFER_TOO_SMALL - Buffer for image is too small + +--*/ +; + +LOADED_IMAGE_PRIVATE_DATA * +CoreLoadedImageInfo ( + IN EFI_HANDLE ImageHandle + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ImageHandle - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +VOID +CoreUnloadAndCloseImage ( + IN LOADED_IMAGE_PRIVATE_DATA *Image, + IN BOOLEAN FreePage + ) +/*++ + +Routine Description: + + Unloads EFI image from memory. + +Arguments: + + Image - EFI image + FreePage - Free allocated pages + +Returns: + + None + +--*/ +; + + +// +// Exported Image functions +// + +EFI_STATUS +EFIAPI +CoreLoadImageEx ( + 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, + OUT UINTN *NumberOfPages OPTIONAL, + OUT EFI_HANDLE *ImageHandle, + OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL, + IN UINT32 Attribute + ) +/*++ + +Routine Description: + + Loads an EFI image into memory and returns a handle to the image with extended parameters. + +Arguments: + + ParentImageHandle - The caller's image handle. + FilePath - The specific file path from which the image is loaded. + SourceBuffer - If not NULL, a pointer to the memory location containing a copy of + the image to be loaded. + SourceSize - The size in bytes of SourceBuffer. + DstBuffer - The buffer to store the image. + NumberOfPages - For input, specifies the space size of the image by caller if not NULL. + For output, specifies the actual space size needed. + ImageHandle - Image handle for output. + EntryPoint - Image entry point for output. + Attribute - The bit mask of attributes to set for the load PE image. + +Returns: + + EFI_SUCCESS - The image was loaded into memory. + EFI_NOT_FOUND - The FilePath was not found. + EFI_INVALID_PARAMETER - One of the parameters has an invalid value. + EFI_UNSUPPORTED - The image type is not supported, or the device path cannot be + parsed to locate the proper protocol for loading the file. + EFI_OUT_OF_RESOURCES - Image was not loaded due to insufficient resources. +--*/ +; + +EFI_STATUS +EFIAPI +CoreUnloadImageEx ( + IN EFI_PE32_IMAGE_PROTOCOL *This, + IN EFI_HANDLE ImageHandle + ) +/*++ + +Routine Description: + + Unload the specified image. + +Arguments: + + This - Indicates the calling context. + + ImageHandle - The specified image handle. + +Returns: + + EFI_INVALID_PARAMETER - Image handle is NULL. + + EFI_UNSUPPORTED - Attempt to unload an unsupported image. + + EFI_SUCCESS - Image successfully unloaded. + +--*/ +; +#endif diff --git a/EdkModulePkg/Core/Dxe/Image/Image.c b/EdkModulePkg/Core/Dxe/Image/Image.c new file mode 100644 index 0000000000..c818cc2131 --- /dev/null +++ b/EdkModulePkg/Core/Dxe/Image/Image.c @@ -0,0 +1,1377 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Image.c + +Abstract: + + Core image handling services + +--*/ + +#include +// +// Module Globals +// + +// +// LIST of runtime images that need to be relocated. +// +LIST_ENTRY mRuntimeImageList = INITIALIZE_LIST_HEAD_VARIABLE (mRuntimeImageList); + +LOADED_IMAGE_PRIVATE_DATA *mCurrentImage = NULL; + +LOAD_PE32_IMAGE_PRIVATE_DATA mLoadPe32PrivateData = { + LOAD_PE32_IMAGE_PRIVATE_DATA_SIGNATURE, + NULL, + { + CoreLoadImageEx, + CoreUnloadImageEx + } +}; + + +// +// 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, // JumpContext + 0, // Machine + NULL, // Ebc + FALSE, // RuntimeFixupValid + NULL, // RuntimeFixup + { NULL, NULL }, // Link +}; + + +EFI_STATUS +CoreInitializeImageServices ( + IN VOID *HobStart + ) +/*++ + +Routine Description: + + Add the Image Services to EFI Boot Services Table and install the protocol + interfaces for this image. + +Arguments: + + HobStart - The HOB to initialize + +Returns: + + Status code. + +--*/ +{ + 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 = gST; + 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 + // + gDxeCoreImageHandle = Image->Handle; + gDxeCoreLoadedImage = &Image->Info; + + // + // Export DXE Core PE Loader functionality + // + return CoreInstallProtocolInterface ( + &mLoadPe32PrivateData.Handle, + &gEfiLoadPeImageProtocolGuid, + EFI_NATIVE_INTERFACE, + &mLoadPe32PrivateData.Pe32Image + ); +} + + +EFI_STATUS +CoreShutdownImageServices ( + VOID + ) +/*++ + +Routine Description: + + Transfer control of runtime images to runtime service + +Arguments: + + None + +Returns: + + EFI_SUCCESS - Function successfully returned + +--*/ +{ + LIST_ENTRY *Link; + LOADED_IMAGE_PRIVATE_DATA *Image; + + // + // The Runtime AP is required for the core to function! + // + ASSERT (gRuntime != NULL); + + for (Link = mRuntimeImageList.ForwardLink; Link != &mRuntimeImageList; Link = Link->ForwardLink) { + Image = CR (Link, LOADED_IMAGE_PRIVATE_DATA, Link, LOADED_IMAGE_PRIVATE_DATA_SIGNATURE); + if (Image->RuntimeFixupValid) { + gRuntime->RegisterImage ( + gRuntime, + (UINT64)(UINTN)(Image->Info.ImageBase), + (EFI_SIZE_TO_PAGES ((UINTN)Image->Info.ImageSize)), + Image->RuntimeFixup + ); + } + } + + return EFI_SUCCESS; +} + + + +EFI_STATUS +CoreLoadPeImage ( + IN VOID *Pe32Handle, + IN LOADED_IMAGE_PRIVATE_DATA *Image, + IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL, + OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL, + IN UINT32 Attribute + ) +/*++ + +Routine Description: + + Loads, relocates, and invokes a PE/COFF image + +Arguments: + + Pe32Handle - The handle of PE32 image + Image - PE image to be loaded + DstBuffer - The buffer to store the image + EntryPoint - A pointer to the entry point + Attribute - The bit mask of attributes to set for the load PE image + +Returns: + + EFI_SUCCESS - The file was loaded, relocated, and invoked + + EFI_OUT_OF_RESOURCES - There was not enough memory to load and relocate the PE/COFF file + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_BUFFER_TOO_SMALL - Buffer for image is too small + +--*/ +{ + EFI_STATUS Status; + 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 = gEfiPeiPeCoffLoader->GetImageInfo (gEfiPeiPeCoffLoader, &Image->ImageContext); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Allocate memory of the correct memory type aligned on the required image boundry + // + + 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. + // + Status = CoreAllocatePages ( + (Image->ImageContext.RelocationsStripped) ? AllocateAddress : AllocateAnyPages, + Image->ImageContext.ImageCodeMemoryType, + Image->NumberOfPages, + &Image->ImageContext.ImageAddress + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Image->ImageBasePage = Image->ImageContext.ImageAddress; + + } 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; + } + + 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 = gEfiPeiPeCoffLoader->LoadImage (gEfiPeiPeCoffLoader, &Image->ImageContext); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // 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) { + if (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) { + Image->ImageContext.FixupData = CoreAllocateRuntimePool ((UINTN)(Image->ImageContext.FixupDataSize)); + if (Image->ImageContext.FixupData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + // + // Make a list off all the RT images so we can let the RT AP know about them + // + Image->RuntimeFixupValid = TRUE; + Image->RuntimeFixup = Image->ImageContext.FixupData; + InsertTailList (&mRuntimeImageList, &Image->Link); + } + } + + // + // Relocate the image in memory + // + Status = gEfiPeiPeCoffLoader->RelocateImage (gEfiPeiPeCoffLoader, &Image->ImageContext); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // 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. This + // is needed during image unload to know if we should call an EBC protocol + // to unload the image. + // + Image->Machine = Image->ImageContext.Machine; + + // + // Get the image entry point. If it's an EBC image, then call into the + // interpreter to create a thunk for the entry point and use the returned + // value for the entry point. + // + Image->EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)Image->ImageContext.EntryPoint; + if (Image->ImageContext.Machine == EFI_IMAGE_MACHINE_EBC) { + // + // Locate the EBC interpreter protocol + // + Status = CoreLocateProtocol (&gEfiEbcProtocolGuid, NULL, (VOID **)&Image->Ebc); + if (EFI_ERROR(Status)) { + goto Done; + } + + // + // Register a callback for flushing the instruction cache so that created + // thunks can be flushed. + // + Status = Image->Ebc->RegisterICacheFlush (Image->Ebc, (EBC_ICACHE_FLUSH)InvalidateInstructionCacheRange); + if (EFI_ERROR(Status)) { + goto Done; + } + + // + // Create a thunk for the image's entry point. This will be the new + // entry point for the image. + // + Status = Image->Ebc->CreateThunk ( + Image->Ebc, + Image->Handle, + (VOID *)(UINTN)Image->ImageContext.EntryPoint, + (VOID **)&Image->EntryPoint + ); + if (EFI_ERROR(Status)) { + goto Done; + } + } + + // + // 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 = Image->ImageContext.ImageCodeMemoryType; + Image->Info.ImageDataType = Image->ImageContext.ImageDataMemoryType; + + // + // 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 ( + { + UINTN Index; + UINTN StartIndex; + CHAR8 EfiFileName[256]; + + DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading driver at 0x%08x EntryPoint=0x%08x ", (UINTN)Image->ImageContext.ImageAddress, (UINTN)Image->ImageContext.EntryPoint)); + if (Image->ImageContext.PdbPointer != NULL) { + StartIndex = 0; + for (Index = 0; Image->ImageContext.PdbPointer[Index] != 0; Index++) { + if (Image->ImageContext.PdbPointer[Index] == '\\') { + StartIndex = Index + 1; + } + } + // + // Copy the PDB file name to our temporary string, and replace .pdb with .efi + // + for (Index = 0; Index < sizeof (EfiFileName); 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; + } + } + DEBUG ((EFI_D_INFO | EFI_D_LOAD, "%a", EfiFileName)); // &Image->ImageContext.PdbPointer[StartIndex])); + } + DEBUG ((EFI_D_INFO | EFI_D_LOAD, "\n")); + } + ); + + return EFI_SUCCESS; + +Done: + // + // Free memory + // + CoreFreePages (Image->ImageContext.ImageAddress, Image->NumberOfPages); + return Status; +} + + +LOADED_IMAGE_PRIVATE_DATA * +CoreLoadedImageInfo ( + IN EFI_HANDLE ImageHandle + ) +/*++ + +Routine Description: + + Get the image's private data from its handle. + +Arguments: + + ImageHandle - The image handle + +Returns: + + Return the image private data associated with 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 ((EFI_D_LOAD, "CoreLoadedImageInfo: Not an ImageHandle %x\n", ImageHandle)); + Image = NULL; + } + + return Image; +} + + +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 + ) +/*++ + +Routine Description: + + Loads an EFI image into memory and returns a handle to the image. + +Arguments: + + 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. + ParentImageHandle - The caller's image handle. + FilePath - The specific file path from which the image is loaded. + SourceBuffer - If not NULL, a pointer to the memory location containing a copy of + the image to be loaded. + SourceSize - The size in bytes of SourceBuffer. + DstBuffer - The buffer to store the image + NumberOfPages - If not NULL, a pointer to the image's page number, if this number + is not enough, return EFI_BUFFER_TOO_SMALL and this parameter contain + the required number. + ImageHandle - Pointer to the returned image handle that is created when the image + is successfully loaded. + EntryPoint - A pointer to the entry point + Attribute - The bit mask of attributes to set for the load PE image + +Returns: + + EFI_SUCCESS - The image was loaded into memory. + EFI_NOT_FOUND - The FilePath was not found. + EFI_INVALID_PARAMETER - One of the parameters has an invalid value. + EFI_BUFFER_TOO_SMALL - The buffer is too small + EFI_UNSUPPORTED - The image type is not supported, or the device path cannot be + parsed to locate the proper protocol for loading the file. + EFI_OUT_OF_RESOURCES - Image was not loaded due to insufficient resources. +--*/ +{ + 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; + UINTN FilePathSize; + + + ASSERT (gEfiCurrentTpl < EFI_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((EFI_D_LOAD|EFI_D_ERROR, "LoadImageEx: Parent handle not an image handle\n")); + return EFI_INVALID_PARAMETER; + } + + // + // Get simple read access to the source file + // + OriginalFilePath = FilePath; + Status = CoreOpenImageFile ( + BootPolicy, + SourceBuffer, + SourceSize, + FilePath, + &DeviceHandle, + &FHand, + &AuthenticationStatus + ); + if (Status == EFI_ALREADY_STARTED) { + Image = NULL; + goto Done; + } else if (EFI_ERROR (Status)) { + return Status; + } + + // + // Verify the Authentication Status through the Security Architectural Protocol + // + if ((gSecurity != NULL) && (OriginalFilePath != NULL)) { + SecurityStatus = gSecurity->FileAuthenticationState ( + gSecurity, + AuthenticationStatus, + OriginalFilePath + ); + if (EFI_ERROR (SecurityStatus) && SecurityStatus != EFI_SECURITY_VIOLATION) { + Status = SecurityStatus; + Image = NULL; + goto Done; + } + } + + + // + // Allocate a new image structure + // + Image = CoreAllocateZeroBootServicesPool (sizeof(LOADED_IMAGE_PRIVATE_DATA)); + if (Image == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Pull out just the file portion of the DevicePath for the LoadedImage FilePath + // + Status = CoreHandleProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&HandleFilePath); + if (!EFI_ERROR (Status)) { + FilePathSize = CoreDevicePathSize (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 = gST; + Image->Info.DeviceHandle = DeviceHandle; + Image->Info.Revision = EFI_LOADED_IMAGE_INFORMATION_REVISION; + Image->Info.FilePath = CoreDuplicateDevicePath (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 (&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; + } + + // + // 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) { + 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; + } + + + // + // 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); + } + + // + // There was an error. If there's an Image structure, free it + // + if (EFI_ERROR (Status)) { + if (Image != NULL) { + CoreUnloadAndCloseImage (Image, (BOOLEAN)(DstBuffer == 0)); + *ImageHandle = NULL; + } + } + + return Status; +} + + + +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 + ) +/*++ + +Routine Description: + + Loads an EFI image into memory and returns a handle to the image. + +Arguments: + + 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. + ParentImageHandle - The caller's image handle. + FilePath - The specific file path from which the image is loaded. + SourceBuffer - If not NULL, a pointer to the memory location containing a copy of + the image to be loaded. + SourceSize - The size in bytes of SourceBuffer. + ImageHandle - Pointer to the returned image handle that is created when the image + is successfully loaded. + +Returns: + + EFI_SUCCESS - The image was loaded into memory. + EFI_NOT_FOUND - The FilePath was not found. + EFI_INVALID_PARAMETER - One of the parameters has an invalid value. + EFI_UNSUPPORTED - The image type is not supported, or the device path cannot be + parsed to locate the proper protocol for loading the file. + EFI_OUT_OF_RESOURCES - Image was not loaded due to insufficient resources. +--*/ +{ + EFI_STATUS Status; + + PERF_START (NULL, "LoadImage", NULL, 0); + + Status = CoreLoadImageCommon ( + BootPolicy, + ParentImageHandle, + FilePath, + SourceBuffer, + SourceSize, + (EFI_PHYSICAL_ADDRESS)NULL, + NULL, + ImageHandle, + NULL, + EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION | EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION + ); + + PERF_END (NULL, "LoadImage", NULL, 0); + + return Status; +} + + +EFI_STATUS +EFIAPI +CoreLoadImageEx ( + 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, + OUT UINTN *NumberOfPages OPTIONAL, + OUT EFI_HANDLE *ImageHandle, + OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL, + IN UINT32 Attribute + ) +/*++ + +Routine Description: + + Loads an EFI image into memory and returns a handle to the image with extended parameters. + +Arguments: + + This - Calling context + ParentImageHandle - The caller's image handle. + FilePath - The specific file path from which the image is loaded. + SourceBuffer - If not NULL, a pointer to the memory location containing a copy of + the image to be loaded. + SourceSize - The size in bytes of SourceBuffer. + DstBuffer - The buffer to store the image. + NumberOfPages - For input, specifies the space size of the image by caller if not NULL. + For output, specifies the actual space size needed. + ImageHandle - Image handle for output. + EntryPoint - Image entry point for output. + Attribute - The bit mask of attributes to set for the load PE image. + +Returns: + + EFI_SUCCESS - The image was loaded into memory. + EFI_NOT_FOUND - The FilePath was not found. + EFI_INVALID_PARAMETER - One of the parameters has an invalid value. + EFI_UNSUPPORTED - The image type is not supported, or the device path cannot be + parsed to locate the proper protocol for loading the file. + EFI_OUT_OF_RESOURCES - Image was not loaded due to insufficient resources. +--*/ +{ + return CoreLoadImageCommon ( + TRUE, + ParentImageHandle, + FilePath, + SourceBuffer, + SourceSize, + DstBuffer, + NumberOfPages, + ImageHandle, + EntryPoint, + Attribute + ); +} + + + + +EFI_STATUS +EFIAPI +CoreStartImage ( + IN EFI_HANDLE ImageHandle, + OUT UINTN *ExitDataSize, + OUT CHAR16 **ExitData OPTIONAL + ) +/*++ + +Routine Description: + + Transfer control to a loaded image's entry point. + +Arguments: + + ImageHandle - Handle of image to be started. + + ExitDataSize - Pointer of the size to ExitData + + ExitData - Pointer to a 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. + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_OUT_OF_RESOURCES - No enough buffer to allocate + + EFI_SUCCESS - Successfully transfer control to the image's entry point. + +--*/ +{ + EFI_STATUS Status; + LOADED_IMAGE_PRIVATE_DATA *Image; + LOADED_IMAGE_PRIVATE_DATA *LastImage; + UINT64 HandleDatabaseKey; + UINTN SetJumpFlag; + + Image = CoreLoadedImageInfo (ImageHandle); + if (Image == NULL_HANDLE || Image->Started) { + return EFI_INVALID_PARAMETER; + } + + // + // Don't profile Objects or invalid start requests + // + PERF_START (ImageHandle, START_IMAGE_TOK, NULL, 0); + + if (sizeof (UINTN) == 4 && Image->Machine == EFI_IMAGE_MACHINE_X64) { + return EFI_UNSUPPORTED; + } else if (sizeof (UINTN) == 8 && Image->Machine == EFI_IMAGE_MACHINE_IA32) { + return EFI_UNSUPPORTED; + } else { + // + // For orther possible cases + // + } + + // + // 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 + // + Image->JumpContext = CoreAllocateBootServicesPool (sizeof (*Image->JumpContext)); + if (Image->JumpContext == NULL) { + PERF_END (ImageHandle, START_IMAGE_TOK, NULL, 0); + return EFI_OUT_OF_RESOURCES; + } + + 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) { + // + // 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 ( + if (EFI_ERROR (Image->Status)) { + DEBUG ((EFI_D_ERROR, "Error: Image at %08X start failed: %x\n", Image->Info.ImageBase, Image->Status)); + } + ); + + // + // 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->JumpContext); + + // + // Pop the current start image context + // + mCurrentImage = LastImage; + + // + // Go connect any handles that were created or modified while the image executed. + // + CoreConnectHandlesByKey (HandleDatabaseKey); + + // + // Handle the image's returned ExitData + // + DEBUG_CODE ( + if (Image->ExitDataSize != 0 || Image->ExitData != NULL) { + + DEBUG ( + (EFI_D_LOAD, + "StartImage: ExitDataSize %d, ExitData %x", + Image->ExitDataSize, + Image->ExitData) + ); + if (Image->ExitData != NULL) { + DEBUG ((EFI_D_LOAD, " (%hs)", Image->ExitData)); + } + DEBUG ((EFI_D_LOAD, "\n")); + } + ); + + // + // 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); + } + + // + // Done + // + PERF_END (ImageHandle, START_IMAGE_TOK, NULL, 0); + return Status; +} + + +VOID +CoreUnloadAndCloseImage ( + IN LOADED_IMAGE_PRIVATE_DATA *Image, + IN BOOLEAN FreePage + ) +/*++ + +Routine Description: + + Unloads EFI image from memory. + +Arguments: + + Image - EFI image + FreePage - Free allocated pages + +Returns: + + None + +--*/ +{ + 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; + + if (Image->Ebc != NULL) { + // + // If EBC protocol exists we must perform cleanups for this image. + // + Image->Ebc->UnloadImage (Image->Ebc, Image->Handle); + } + + // + // Unload image, free Image->ImageContext->ModHandle + // + gEfiPeiPeCoffLoader->UnloadImage (gEfiPeiPeCoffLoader, &Image->ImageContext); + + // + // Free our references to the image handle + // + if (Image->Handle != NULL_HANDLE) { + + 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, + &gEfiLoadedImageProtocolGuid, + &Image->Info + ); + } + + if (Image->RuntimeFixupValid) { + // + // Remove the Image from the Runtime Image list as we are about to Free it! + // + RemoveEntryList (&Image->Link); + } + + // + // 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->FixupData != NULL) { + CoreFreePool (Image->FixupData); + } + + CoreFreePool (Image); +} + + + +EFI_STATUS +EFIAPI +CoreExit ( + IN EFI_HANDLE ImageHandle, + IN EFI_STATUS Status, + IN UINTN ExitDataSize, + IN CHAR16 *ExitData OPTIONAL + ) +/*++ + +Routine Description: + + Terminates the currently loaded EFI image and returns control to boot services. + +Arguments: + + ImageHandle - Handle that identifies the image. This parameter is passed to the image + on entry. + Status - The image¡¯s exit code. + ExitDataSize - The size, in bytes, of ExitData. Ignored if ExitStatus is + EFI_SUCCESS. + 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. + +Returns: + + EFI_INVALID_PARAMETER - Image handle is NULL or it is not current image. + + EFI_SUCCESS - Successfully terminates the currently loaded EFI image. + + EFI_ACCESS_DENIED - Should never reach there. + + EFI_OUT_OF_RESOURCES - Could not allocate pool + +--*/ +{ + LOADED_IMAGE_PRIVATE_DATA *Image; + + Image = CoreLoadedImageInfo (ImageHandle); + if (Image == NULL_HANDLE) { + return EFI_INVALID_PARAMETER; + } + + if (!Image->Started) { + // + // The image has not been started so just free its resources + // + CoreUnloadAndCloseImage (Image, TRUE); + return EFI_SUCCESS; + } + + // + // Image has been started, verify this image can exit + // + if (Image != mCurrentImage) { + DEBUG ((EFI_D_LOAD|EFI_D_ERROR, "Exit: Image is not exitable image\n")); + return EFI_INVALID_PARAMETER; + } + + // + // Set status + // + Image->Status = Status; + + // + // If there's ExitData info, move it + // + if (ExitData != NULL) { + Image->ExitDataSize = ExitDataSize; + Image->ExitData = CoreAllocateBootServicesPool (Image->ExitDataSize); + if (Image->ExitData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + CopyMem (Image->ExitData, ExitData, Image->ExitDataSize); + } + + // + // return to StartImage + // + LongJump (Image->JumpContext, (UINTN)-1); + + // + // If we return from LongJump, then it is an error + // + ASSERT (FALSE); + return EFI_ACCESS_DENIED; +} + + + +EFI_STATUS +EFIAPI +CoreUnloadImage ( + IN EFI_HANDLE ImageHandle + ) +/*++ + +Routine Description: + + Unloads an image. + +Arguments: + + ImageHandle - Handle that identifies the image to be unloaded. + +Returns: + + EFI_SUCCESS - The image has been unloaded. + EFI_UNSUPPORTED - The image has been sarted, and does not support unload. + EFI_INVALID_PARAMPETER - ImageHandle is not a valid image handle. + +--*/ +{ + EFI_STATUS Status; + LOADED_IMAGE_PRIVATE_DATA *Image; + + Image = CoreLoadedImageInfo (ImageHandle); + if (Image == NULL ) { + // + // The image handle is not valid + // + return EFI_INVALID_PARAMETER; + } + + 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); + } + + return Status; +} + + +EFI_STATUS +EFIAPI +CoreUnloadImageEx ( + IN EFI_PE32_IMAGE_PROTOCOL *This, + IN EFI_HANDLE ImageHandle + ) +/*++ + +Routine Description: + + Unload the specified image. + +Arguments: + + This - Indicates the calling context. + + ImageHandle - The specified image handle. + +Returns: + + EFI_INVALID_PARAMETER - Image handle is NULL. + + EFI_UNSUPPORTED - Attempt to unload an unsupported image. + + EFI_SUCCESS - Image successfully unloaded. + +--*/ +{ + return CoreUnloadImage (ImageHandle); +} diff --git a/EdkModulePkg/Core/Dxe/Image/ImageFile.c b/EdkModulePkg/Core/Dxe/Image/ImageFile.c new file mode 100644 index 0000000000..999cd694ad --- /dev/null +++ b/EdkModulePkg/Core/Dxe/Image/ImageFile.c @@ -0,0 +1,569 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ImageFile.c + + +Abstract: + + + + +Revision History + +--*/ + +#include + + +VOID +CoreDevicePathToFileName ( + IN FILEPATH_DEVICE_PATH *FilePath, + OUT CHAR16 **String + ); + + + +EFI_STATUS +CoreOpenImageFile ( + IN BOOLEAN BootPolicy, + IN VOID *SourceBuffer OPTIONAL, + IN UINTN SourceSize, + IN OUT EFI_DEVICE_PATH_PROTOCOL *FilePath, + OUT EFI_HANDLE *DeviceHandle, + IN IMAGE_FILE_HANDLE *ImageFileHandle, + OUT UINT32 *AuthenticationStatus + ) +/*++ + +Routine Description: + + Opens a file for (simple) reading. The simple read abstraction + will access the file either from a memory copy, from a file + system interface, or from the load file interface. + +Arguments: + + BootPolicy - Policy for Open Image File. + SourceBuffer - Pointer to the memory location containing copy + of the image to be loaded. + SourceSize - The size in bytes of SourceBuffer. + FilePath - The specific file path from which the image is loaded + DeviceHandle - Pointer to the return device handle. + ImageFileHandle - Pointer to the image file handle. + AuthenticationStatus - Pointer to a caller-allocated UINT32 in which the authentication status is returned. + +Returns: + + EFI_SUCCESS - Image file successfully opened. + + EFI_LOAD_ERROR - If the caller passed a copy of the file, and SourceSize is 0. + + EFI_INVALID_PARAMETER - File path is not valid. + + EFI_NOT_FOUND - File not found. + +--*/ +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *TempFilePath; + FILEPATH_DEVICE_PATH *FilePathNode; + MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FwVolFilePathNode; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume; + EFI_FILE_HANDLE FileHandle; + EFI_FILE_HANDLE LastHandle; + EFI_LOAD_FILE_PROTOCOL *LoadFile; + EFI_FIRMWARE_VOLUME_PROTOCOL *FwVol; + EFI_SECTION_TYPE SectionType; + UINT8 *Pe32Buffer; + UINTN Pe32BufferSize; + EFI_FV_FILETYPE Type; + EFI_FV_FILE_ATTRIBUTES Attrib; + EFI_FILE_INFO *FileInfo; + UINTN FileInfoSize; + EFI_GUID *NameGuid; + + *AuthenticationStatus = 0; + ZeroMem (ImageFileHandle, sizeof (IMAGE_FILE_HANDLE)); + ImageFileHandle->Signature = IMAGE_FILE_HANDLE_SIGNATURE; + + // + // If the caller passed a copy of the file, then just use it + // + if (SourceBuffer != NULL) { + ImageFileHandle->Source = SourceBuffer; + ImageFileHandle->SourceSize = SourceSize; + *DeviceHandle = NULL; + if (SourceSize > 0) { + Status = EFI_SUCCESS; + } else { + Status = EFI_LOAD_ERROR; + } + goto Done; + } + + // + // Make sure FilePath is valid + // + if (FilePath == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Check to see if it's in a Firmware Volume + // + FwVolFilePathNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)FilePath; + Status = CoreDevicePathToInterface ( + &gEfiFirmwareVolumeProtocolGuid, + (EFI_DEVICE_PATH_PROTOCOL **)&FwVolFilePathNode, + (VOID*)&FwVol, + DeviceHandle + ); + if (!EFI_ERROR (Status)) { + // + // For FwVol File system there is only a single file name that is a GUID. + // + NameGuid = EfiGetNameGuidFromFwVolDevicePathNode (FwVolFilePathNode); + if (NameGuid != NULL) { + + SectionType = EFI_SECTION_PE32; + Pe32Buffer = NULL; + Status = FwVol->ReadSection ( + FwVol, + NameGuid, + SectionType, + 0, + (VOID **)&Pe32Buffer, + &Pe32BufferSize, + AuthenticationStatus + ); + if (EFI_ERROR (Status)) { + // + // Try a raw file, since a PE32 SECTION does not exist + // + if (Pe32Buffer != NULL) { + CoreFreePool (Pe32Buffer); + *AuthenticationStatus = 0; + } + Pe32Buffer = NULL; + Status = FwVol->ReadFile ( + FwVol, + NameGuid, + (VOID **)&Pe32Buffer, + &Pe32BufferSize, + &Type, + &Attrib, + AuthenticationStatus + ); + } + + if (!EFI_ERROR (Status)) { + // + // One of the reads passed so we are done + // + ImageFileHandle->Source = Pe32Buffer; + ImageFileHandle->SourceSize = Pe32BufferSize; + ImageFileHandle->FreeBuffer = TRUE; + goto Done; + } + } + } + + // + // Attempt to access the file via a file system interface + // + FilePathNode = (FILEPATH_DEVICE_PATH *) FilePath; + Status = CoreDevicePathToInterface ( + &gEfiSimpleFileSystemProtocolGuid, + (EFI_DEVICE_PATH_PROTOCOL **)&FilePathNode, + (VOID*)&Volume, + DeviceHandle + ); + if (!EFI_ERROR (Status)) { + // + // Open the Volume to get the File System handle + // + Status = Volume->OpenVolume (Volume, &FileHandle); + if (!EFI_ERROR (Status)) { + + // + // 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 + // + while (!IsDevicePathEnd (&FilePathNode->Header)) { + if (DevicePathType (&FilePathNode->Header) != MEDIA_DEVICE_PATH || + DevicePathSubType (&FilePathNode->Header) != MEDIA_FILEPATH_DP) { + Status = EFI_UNSUPPORTED; + } + + if (EFI_ERROR (Status)) { + // + // Exit loop on Error + // + break; + } + + LastHandle = FileHandle; + FileHandle = NULL; + Status = LastHandle->Open ( + LastHandle, + &FileHandle, + FilePathNode->PathName, + EFI_FILE_MODE_READ, + 0 + ); + + // + // Close the previous node + // + LastHandle->Close (LastHandle); + + FilePathNode = (FILEPATH_DEVICE_PATH *) NextDevicePathNode (&FilePathNode->Header); + } + + if (!EFI_ERROR (Status)) { + // + // We have found the file. Now we need to read it. Before we can read the file we need to + // figure out how big the file is. + // + FileInfo = NULL; + FileInfoSize = sizeof (EFI_FILE_INFO); + while (CoreGrowBuffer (&Status, (VOID **)&FileInfo, FileInfoSize)) { + // + // Automatically allocate buffer of the correct size and make the call + // + Status = FileHandle->GetInfo ( + FileHandle, + &gEfiFileInfoGuid, + &FileInfoSize, + FileInfo + ); + } + if (!EFI_ERROR (Status)) { + // + // Allocate space for the file + // + ImageFileHandle->Source = CoreAllocateBootServicesPool ((UINTN)FileInfo->FileSize); + if (ImageFileHandle->Source != NULL) { + // + // Read the file into the buffer we allocated + // + ImageFileHandle->SourceSize = (UINTN)FileInfo->FileSize; + ImageFileHandle->FreeBuffer = TRUE; + Status = FileHandle->Read (FileHandle, &ImageFileHandle->SourceSize, ImageFileHandle->Source); + + // + // Close the file since we are done + // + FileHandle->Close (FileHandle); + } else { + Status = EFI_OUT_OF_RESOURCES; + } + + goto Done; + } + } + } + } + + + // + // Try LoadFile style + // + + TempFilePath = FilePath; + Status = CoreDevicePathToInterface ( + &gEfiLoadFileProtocolGuid, + &TempFilePath, + (VOID*)&LoadFile, + DeviceHandle + ); + if (!EFI_ERROR (Status)) { + // + // Call LoadFile with the correct buffer size + // + while (CoreGrowBuffer (&Status, (VOID **)&ImageFileHandle->Source, ImageFileHandle->SourceSize)) { + Status = LoadFile->LoadFile ( + LoadFile, + TempFilePath, + BootPolicy, + &ImageFileHandle->SourceSize, + ImageFileHandle->Source + ); + // + // If success or other error happens, stop loop + // + if (Status != EFI_BUFFER_TOO_SMALL) { + break; + } + } + + if (!EFI_ERROR (Status) || Status == EFI_ALREADY_STARTED) { + ImageFileHandle->FreeBuffer = TRUE; + goto Done; + } + } + + // + // Nothing else to try + // + DEBUG ((EFI_D_LOAD|EFI_D_WARN, "CoreOpenImageFile: Device did not support a known load protocol\n")); + Status = EFI_NOT_FOUND; + +Done: + + // + // If the file was not accessed, clean up + // + if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) { + if (ImageFileHandle->FreeBuffer) { + // + // Free the source buffer if we allocated it + // + CoreFreePool (ImageFileHandle->Source); + } + } + + return Status; +} + + + +EFI_STATUS +EFIAPI +CoreReadImageFile ( + IN VOID *UserHandle, + IN UINTN Offset, + IN OUT UINTN *ReadSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Read image file (specified by UserHandle) into user specified buffer with specified offset + and length. + +Arguments: + + UserHandle - Image file handle + + Offset - Offset to the source file + + ReadSize - For input, pointer of size to read; + For output, pointer of size actually read. + + Buffer - Buffer to write into + +Returns: + + EFI_SUCCESS - Successfully read the specified part of file into buffer. + +--*/ +{ + UINTN EndPosition; + IMAGE_FILE_HANDLE *FHand; + + 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; +} + +EFI_STATUS +CoreDevicePathToInterface ( + IN EFI_GUID *Protocol, + IN EFI_DEVICE_PATH_PROTOCOL **FilePath, + OUT VOID **Interface, + OUT EFI_HANDLE *Handle + ) +/*++ + +Routine Description: + + Search a handle to a device on a specified device path that supports a specified protocol, + interface of that protocol on that handle is another output. + +Arguments: + + Protocol - The protocol to search for + + FilePath - The specified device path + + Interface - Interface of the protocol on the handle + + Handle - The handle to the device on the specified device path that supports the protocol. + +Returns: + + Status code. + +--*/ +{ + EFI_STATUS Status; + + Status = CoreLocateDevicePath (Protocol, FilePath, Handle); + if (!EFI_ERROR (Status)) { + Status = CoreHandleProtocol (*Handle, Protocol, Interface); + } + return Status; +} + + +VOID +CoreDevicePathToFileName ( + IN FILEPATH_DEVICE_PATH *FilePath, + OUT CHAR16 **String + ) +/*++ + +Routine Description: + + Transfer a device's full path a string. + +Arguments: + + FilePath - Device path + + String - The string represent the device's full path + +Returns: + + None + +--*/ +{ + UINTN StringSize; + FILEPATH_DEVICE_PATH *FilePathNode; + CHAR16 *Str; + + *String = NULL; + StringSize = 0; + FilePathNode = FilePath; + while (!IsDevicePathEnd (&FilePathNode->Header)) { + + // + // For filesystem access each node should be a filepath component + // + if (DevicePathType (&FilePathNode->Header) != MEDIA_DEVICE_PATH || + DevicePathSubType (&FilePathNode->Header) != MEDIA_FILEPATH_DP) { + + return; + } + + StringSize += StrLen (FilePathNode->PathName); + + FilePathNode = (FILEPATH_DEVICE_PATH *) NextDevicePathNode (&FilePathNode->Header); + } + + *String = CoreAllocateBootServicesPool (StringSize); + if (*String == NULL) { + return; + } + + FilePathNode = FilePath; + Str = *String; + while (!IsDevicePathEnd (&FilePathNode->Header)) { + StrCat (Str, FilePathNode->PathName); + FilePathNode = (FILEPATH_DEVICE_PATH *) NextDevicePathNode (&FilePathNode->Header); + } +} + + +BOOLEAN +CoreGrowBuffer ( + IN OUT EFI_STATUS *Status, + IN OUT VOID **Buffer, + IN UINTN BufferSize + ) +/*++ + +Routine Description: + + Helper function called as part of the code needed + to allocate the proper sized buffer for various + EFI interfaces. + +Arguments: + + Status - Current status + + Buffer - Current allocated buffer, or NULL + + BufferSize - Current buffer size needed + +Returns: + + TRUE - if the buffer was reallocated and the caller + should try the API again. + + FALSE - buffer could not be allocated and the caller + should not try the API again. + +--*/ +{ + BOOLEAN TryAgain; + + TryAgain = FALSE; + // + // If this is an initial request, buffer will be null with a new buffer size + // + if (*Buffer == NULL) { + *Status = EFI_BUFFER_TOO_SMALL; + } + + if (BufferSize == 0) { + return TRUE; + } + + // + // If the status code is "buffer too small", resize the buffer + // + + if (*Status == EFI_BUFFER_TOO_SMALL) { + if (*Buffer != NULL) { + CoreFreePool (*Buffer); + } + + *Buffer = CoreAllocateBootServicesPool (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)) { + CoreFreePool (*Buffer); + *Buffer = NULL; + } + + return TryAgain; +} + diff --git a/EdkModulePkg/Core/Dxe/Library.h b/EdkModulePkg/Core/Dxe/Library.h new file mode 100644 index 0000000000..5e33da5285 --- /dev/null +++ b/EdkModulePkg/Core/Dxe/Library.h @@ -0,0 +1,407 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Library.h + +Abstract: + +Revision History + +--*/ + +#ifndef _DXE_LIBRARY_H_ +#define _DXE_LIBRARY_H_ + + +VOID +CoreReportProgressCode ( + IN EFI_STATUS_CODE_VALUE Value + ) +/*++ + +Routine Description: + + Report status code of type EFI_PROGRESS_CODE by caller ID gEfiDxeServicesTableGuid. + +Arguments: + + Value - Describes the class/subclass/operation of the hardware or software entity + that the Status Code relates to. + +Returns: + + None + +--*/ +; + +VOID +CoreReportProgressCodeSpecific ( + IN EFI_STATUS_CODE_VALUE Value, + IN EFI_HANDLE Handle + ) +/*++ + +Routine Description: + + Report status code of type EFI_PROGRESS_CODE by caller ID gEfiDxeServicesTableGuid, + with a handle as additional information. + +Arguments: + + Value - Describes the class/subclass/operation of the hardware or software entity + that the Status Code relates to. + + Handle - Additional information. + +Returns: + + None + +--*/ +; + +VOID +CoreAcquireLock ( + IN EFI_LOCK *Lock + ) +/*++ + +Routine Description: + + Raising to the task priority level of the mutual exclusion + lock, and then acquires ownership of the lock. + +Arguments: + + Lock - The lock to acquire + +Returns: + + Lock owned + +--*/ +; + +EFI_STATUS +CoreAcquireLockOrFail ( + IN EFI_LOCK *Lock + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + Lock - The EFI_LOCK structure to initialize + +Returns: + + EFI_SUCCESS - Lock Owned. + EFI_ACCESS_DENIED - Reentrant Lock Acquisition, Lock not Owned. + +--*/ +; + +VOID +CoreReleaseLock ( + IN EFI_LOCK *Lock + ) +/*++ + +Routine Description: + + Releases ownership of the mutual exclusion lock, and + restores the previous task priority level. + +Arguments: + + Lock - The lock to release + +Returns: + + Lock unowned + +--*/ +; + +// +// Device Path functions +// + +UINTN +CoreDevicePathSize ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +/*++ + +Routine Description: + + Calculate the size of a whole device path. + +Arguments: + + DevicePath - The pointer to the device path data. + +Returns: + + Size of device path data structure.. + +--*/ +; + +BOOLEAN +CoreIsDevicePathMultiInstance ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +/*++ + +Routine Description: + Return TRUE is this is a multi instance device path. + +Arguments: + DevicePath - A pointer to a device path data structure. + + +Returns: + TRUE - If DevicePath is multi instance. FALSE - If DevicePath is not multi + instance. + +--*/ +; + + +EFI_DEVICE_PATH_PROTOCOL * +CoreDuplicateDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +/*++ + +Routine Description: + Duplicate a new device path data structure from the old one. + +Arguments: + DevicePath - A pointer to a device path data structure. + +Returns: + A pointer to the new allocated device path data. + Caller must free the memory used by DevicePath if it is no longer needed. + +--*/ +; + +EFI_DEVICE_PATH_PROTOCOL * +CoreAppendDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *Src1, + IN EFI_DEVICE_PATH_PROTOCOL *Node + ) +/*++ + +Routine Description: + Function is used to append a Src1 and Src2 together. + +Arguments: + Src1 - A pointer to a device path data structure. + + Node - A pointer to a device path data structure. + +Returns: + + A pointer to the new device path is returned. + NULL is returned if space for the new device path could not be allocated from pool. + It is up to the caller to free the memory used by Src1 and Src2 if they are no longer needed. + +--*/ +; + +VOID * +CoreAllocateBootServicesPool ( + IN UINTN AllocationSize + ) +/*++ + +Routine Description: + + Allocate pool of type EfiBootServicesData, the size is specified with AllocationSize. + +Arguments: + + AllocationSize - Size to allocate. + +Returns: + + Pointer of the allocated pool. + +--*/ +; + +VOID * +CoreAllocateZeroBootServicesPool ( + IN UINTN AllocationSize + ) +/*++ + +Routine Description: + + Allocate pool of type EfiBootServicesData and zero it, the size is specified with AllocationSize. + +Arguments: + + AllocationSize - Size to allocate. + +Returns: + + Pointer of the allocated pool. + +--*/ +; + +EFI_STATUS +CoreGetConfigTable ( + IN EFI_GUID *Guid, + IN OUT VOID **Table + ) +/*++ + +Routine Description: + + Find a config table by name in system table's ConfigurationTable. + +Arguments: + + Guid - The table name to look for + + Table - Pointer of the config table + +Returns: + + EFI_NOT_FOUND - Could not find the table in system table's ConfigurationTable. + + EFI_SUCCESS - Table successfully found. + +--*/ +; + +VOID * +CoreAllocateRuntimeCopyPool ( + IN UINTN AllocationSize, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Allocate pool of specified size with EfiRuntimeServicesData type, and copy specified buffer to this pool. + +Arguments: + + AllocationSize - Size to allocate. + + Buffer - Specified buffer that will be copy to the allocated pool + +Returns: + + Pointer of the allocated pool. + +--*/ +; + +VOID * +CoreAllocateRuntimePool ( + IN UINTN AllocationSize + ) +/*++ + +Routine Description: + + Allocate pool of type EfiRuntimeServicesData, the size is specified with AllocationSize. + +Arguments: + + AllocationSize - Size to allocate. + +Returns: + + Pointer of the allocated pool. + +--*/ +; + +VOID * +CoreAllocateCopyPool ( + IN UINTN AllocationSize, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Allocate pool of specified size with EfiBootServicesData type, and copy specified buffer to this pool. + +Arguments: + + AllocationSize - Size to allocate. + + Buffer - Specified buffer that will be copy to the allocated pool + +Returns: + + Pointer of the allocated pool. + +--*/ +; + +EFI_EVENT +CoreCreateProtocolNotifyEvent ( + IN EFI_GUID *ProtocolGuid, + IN EFI_TPL NotifyTpl, + IN EFI_EVENT_NOTIFY NotifyFunction, + IN VOID *NotifyContext, + OUT VOID **Registration, + IN BOOLEAN SignalFlag + ) +/*++ + +Routine Description: + + Create a protocol notification event and return it. + +Arguments: + + ProtocolGuid - Protocol to register notification event on. + + NotifyTpl - Maximum TPL to signal the NotifyFunction. + + NotifyFuncition - EFI notification routine. + + NotifyContext - Context passed into Event when it is created. + + Registration - Registration key returned from RegisterProtocolNotify(). + + SignalFlag - Boolean value to decide whether kick the event after register or not. + +Returns: + + The EFI_EVENT that has been registered to be signaled when a ProtocolGuid + is added to the system. + +--*/ +; + +#endif diff --git a/EdkModulePkg/Core/Dxe/Library/Library.c b/EdkModulePkg/Core/Dxe/Library/Library.c new file mode 100644 index 0000000000..74d873e3f8 --- /dev/null +++ b/EdkModulePkg/Core/Dxe/Library/Library.c @@ -0,0 +1,613 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Library.c + +Abstract: + + DXE Core library services. + +--*/ + +#include + +UINTN mErrorLevel = EFI_D_ERROR | EFI_D_LOAD; + +EFI_DEVICE_HANDLE_EXTENDED_DATA mStatusCodeData = { + { + sizeof (EFI_STATUS_CODE_DATA), + 0, + EFI_STATUS_CODE_SPECIFIC_DATA_GUID + }, + NULL +}; + +VOID +CoreReportProgressCodeSpecific ( + IN EFI_STATUS_CODE_VALUE Value, + IN EFI_HANDLE Handle + ) +/*++ + +Routine Description: + + Report status code of type EFI_PROGRESS_CODE by caller ID gEfiDxeServicesTableGuid, + with a handle as additional information. + +Arguments: + + Value - Describes the class/subclass/operation of the hardware or software entity + that the Status Code relates to. + + Handle - Additional information. + +Returns: + + None + +--*/ +{ + mStatusCodeData.DataHeader.Size = sizeof (EFI_DEVICE_HANDLE_EXTENDED_DATA) - sizeof (EFI_STATUS_CODE_DATA); + mStatusCodeData.Handle = Handle; + + if ((gStatusCode != NULL) && (gStatusCode->ReportStatusCode != NULL) ) { + gStatusCode->ReportStatusCode ( + EFI_PROGRESS_CODE, + Value, + 0, + &gEfiDxeServicesTableGuid, + (EFI_STATUS_CODE_DATA *) &mStatusCodeData + ); + } +} + +VOID +CoreReportProgressCode ( + IN EFI_STATUS_CODE_VALUE Value + ) +/*++ + +Routine Description: + + Report status code of type EFI_PROGRESS_CODE by caller ID gEfiDxeServicesTableGuid. + +Arguments: + + Value - Describes the class/subclass/operation of the hardware or software entity + that the Status Code relates to. + +Returns: + + None + +--*/ +{ + if ((gStatusCode != NULL) && (gStatusCode->ReportStatusCode != NULL) ) { + gStatusCode->ReportStatusCode ( + EFI_PROGRESS_CODE, + Value, + 0, + &gEfiDxeServicesTableGuid, + NULL + ); + } +} + + +VOID * +CoreAllocateBootServicesPool ( + IN UINTN AllocationSize + ) +/*++ + +Routine Description: + + Allocate pool of type EfiBootServicesData, the size is specified with AllocationSize. + +Arguments: + + AllocationSize - Size to allocate. + +Returns: + + Pointer of the allocated pool. + +--*/ +{ + VOID *Memory; + + CoreAllocatePool (EfiBootServicesData, AllocationSize, &Memory); + return Memory; +} + + +VOID * +CoreAllocateZeroBootServicesPool ( + IN UINTN AllocationSize + ) +/*++ + +Routine Description: + + Allocate pool of type EfiBootServicesData and zero it, the size is specified with AllocationSize. + +Arguments: + + AllocationSize - Size to allocate. + +Returns: + + Pointer of the allocated pool. + +--*/ +{ + VOID *Memory; + + Memory = CoreAllocateBootServicesPool (AllocationSize); + SetMem (Memory, (Memory == NULL) ? 0 : AllocationSize, 0); + return Memory; +} + + +VOID * +CoreAllocateCopyPool ( + IN UINTN AllocationSize, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Allocate pool of specified size with EfiBootServicesData type, and copy specified buffer to this pool. + +Arguments: + + AllocationSize - Size to allocate. + + Buffer - Specified buffer that will be copy to the allocated pool + +Returns: + + Pointer of the allocated pool. + +--*/ +{ + VOID *Memory; + + Memory = CoreAllocateBootServicesPool (AllocationSize); + CopyMem (Memory, Buffer, (Memory == NULL) ? 0 : AllocationSize); + + return Memory; +} + + + +VOID * +CoreAllocateRuntimePool ( + IN UINTN AllocationSize + ) +/*++ + +Routine Description: + + Allocate pool of type EfiRuntimeServicesData, the size is specified with AllocationSize. + +Arguments: + + AllocationSize - Size to allocate. + +Returns: + + Pointer of the allocated pool. + +--*/ +{ + VOID *Memory; + + CoreAllocatePool (EfiRuntimeServicesData, AllocationSize, &Memory); + return Memory; +} + +VOID * +CoreAllocateRuntimeCopyPool ( + IN UINTN AllocationSize, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Allocate pool of specified size with EfiRuntimeServicesData type, and copy specified buffer to this pool. + +Arguments: + + AllocationSize - Size to allocate. + + Buffer - Specified buffer that will be copy to the allocated pool + +Returns: + + Pointer of the allocated pool. + +--*/ + +{ + VOID *Memory; + + Memory = CoreAllocateRuntimePool (AllocationSize); + CopyMem (Memory, Buffer, (Memory == NULL) ? 0 : AllocationSize); + + return Memory; +} + + + +// +// Lock Stuff +// + + + +EFI_STATUS +CoreAcquireLockOrFail ( + IN EFI_LOCK *Lock + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + Lock - The EFI_LOCK structure to initialize + +Returns: + + EFI_SUCCESS - Lock Owned. + EFI_ACCESS_DENIED - Reentrant Lock Acquisition, Lock not Owned. + +--*/ +{ + 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; +} + + +VOID +CoreAcquireLock ( + IN EFI_LOCK *Lock + ) +/*++ + +Routine Description: + + Raising to the task priority level of the mutual exclusion + lock, and then acquires ownership of the lock. + +Arguments: + + Lock - The lock to acquire + +Returns: + + Lock owned + +--*/ +{ + ASSERT (Lock != NULL); + ASSERT (Lock->Lock == EfiLockReleased); + + Lock->OwnerTpl = CoreRaiseTpl (Lock->Tpl); + Lock->Lock = EfiLockAcquired; +} + + +VOID +CoreReleaseLock ( + IN EFI_LOCK *Lock + ) +/*++ + +Routine Description: + + Releases ownership of the mutual exclusion lock, and + restores the previous task priority level. + +Arguments: + + Lock - The lock to release + +Returns: + + Lock unowned + +--*/ +{ + EFI_TPL Tpl; + + ASSERT (Lock != NULL); + ASSERT (Lock->Lock == EfiLockAcquired); + + Tpl = Lock->OwnerTpl; + + Lock->Lock = EfiLockReleased; + + CoreRestoreTpl (Tpl); +} + + +UINTN +CoreDevicePathSize ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +/*++ + +Routine Description: + + Calculate the size of a whole device path. + +Arguments: + + DevicePath - The pointer to the device path data. + +Returns: + + Size of device path data structure.. + +--*/ +{ + EFI_DEVICE_PATH_PROTOCOL *Start; + + if (DevicePath == NULL) { + return 0; + } + + // + // Search for the end of the device path structure + // + Start = DevicePath; + while (!EfiIsDevicePathEnd (DevicePath)) { + DevicePath = EfiNextDevicePathNode (DevicePath); + } + + // + // Compute the size and add back in the size of the end device path structure + // + return ((UINTN)DevicePath - (UINTN)Start) + sizeof(EFI_DEVICE_PATH_PROTOCOL); +} + + +BOOLEAN +CoreIsDevicePathMultiInstance ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +/*++ + +Routine Description: + Return TRUE is this is a multi instance device path. + +Arguments: + DevicePath - A pointer to a device path data structure. + + +Returns: + TRUE - If DevicePath is multi instance. FALSE - If DevicePath is not multi + instance. + +--*/ +{ + EFI_DEVICE_PATH_PROTOCOL *Node; + + if (DevicePath == NULL) { + return FALSE; + } + + Node = DevicePath; + while (!EfiIsDevicePathEnd (Node)) { + if (EfiIsDevicePathEndInstance (Node)) { + return TRUE; + } + Node = EfiNextDevicePathNode (Node); + } + return FALSE; +} + + + +EFI_DEVICE_PATH_PROTOCOL * +CoreDuplicateDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +/*++ + +Routine Description: + Duplicate a new device path data structure from the old one. + +Arguments: + DevicePath - A pointer to a device path data structure. + +Returns: + A pointer to the new allocated device path data. + Caller must free the memory used by DevicePath if it is no longer needed. + +--*/ +{ + EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; + UINTN Size; + + if (DevicePath == NULL) { + return NULL; + } + + // + // Compute the size + // + Size = CoreDevicePathSize (DevicePath); + + // + // Allocate space for duplicate device path + // + NewDevicePath = CoreAllocateCopyPool (Size, DevicePath); + + return NewDevicePath; +} + + + +EFI_DEVICE_PATH_PROTOCOL * +CoreAppendDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *Src1, + IN EFI_DEVICE_PATH_PROTOCOL *Src2 + ) +/*++ + +Routine Description: + Function is used to append a Src1 and Src2 together. + +Arguments: + Src1 - A pointer to a device path data structure. + + Src2 - A pointer to a device path data structure. + +Returns: + + A pointer to the new device path is returned. + NULL is returned if space for the new device path could not be allocated from pool. + It is up to the caller to free the memory used by Src1 and Src2 if they are no longer needed. + +--*/ +{ + UINTN Size; + UINTN Size1; + UINTN Size2; + EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; + EFI_DEVICE_PATH_PROTOCOL *SecondDevicePath; + + if (Src1 == NULL && Src2 == NULL) { + return NULL; + } + + // + // Allocate space for the combined device path. It only has one end node of + // length EFI_DEVICE_PATH_PROTOCOL + // + Size1 = CoreDevicePathSize (Src1); + Size2 = CoreDevicePathSize (Src2); + Size = Size1 + Size2 - sizeof(EFI_DEVICE_PATH_PROTOCOL); + + NewDevicePath = CoreAllocateCopyPool (Size, Src1); + if (NewDevicePath != NULL) { + + // + // Over write Src1 EndNode and do the copy + // + SecondDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)((CHAR8 *)NewDevicePath + (Size1 - sizeof(EFI_DEVICE_PATH_PROTOCOL))); + CopyMem (SecondDevicePath, Src2, Size2); + } + + return NewDevicePath; +} + + + +EFI_EVENT +CoreCreateProtocolNotifyEvent ( + IN EFI_GUID *ProtocolGuid, + IN EFI_TPL NotifyTpl, + IN EFI_EVENT_NOTIFY NotifyFunction, + IN VOID *NotifyContext, + OUT VOID **Registration, + IN BOOLEAN SignalFlag + ) +/*++ + +Routine Description: + + Create a protocol notification event and return it. + +Arguments: + + ProtocolGuid - Protocol to register notification event on. + + NotifyTpl - Maximum TPL to signal the NotifyFunction. + + NotifyFuncition - EFI notification routine. + + NotifyContext - Context passed into Event when it is created. + + Registration - Registration key returned from RegisterProtocolNotify(). + + SignalFlag - Boolean value to decide whether kick the event after register or not. + +Returns: + + The EFI_EVENT that has been registered to be signaled when a ProtocolGuid + is added to the system. + +--*/ +{ + EFI_STATUS Status; + EFI_EVENT Event; + + // + // Create the event + // + + Status = CoreCreateEvent ( + EFI_EVENT_NOTIFY_SIGNAL, + NotifyTpl, + NotifyFunction, + NotifyContext, + &Event + ); + ASSERT_EFI_ERROR (Status); + + // + // Register for protocol notifactions on this event + // + + Status = CoreRegisterProtocolNotify ( + ProtocolGuid, + Event, + Registration + ); + ASSERT_EFI_ERROR (Status); + + if (SignalFlag) { + // + // Kick the event so we will perform an initial pass of + // current installed drivers + // + CoreSignalEvent (Event); + } + + return Event; +} + diff --git a/EdkModulePkg/Core/Dxe/Mem/Page.c b/EdkModulePkg/Core/Dxe/Mem/Page.c new file mode 100644 index 0000000000..e65b0283c6 --- /dev/null +++ b/EdkModulePkg/Core/Dxe/Mem/Page.c @@ -0,0 +1,1589 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + page.c + +Abstract: + + EFI Memory page management + + +Revision History + +--*/ + +#include + +#define EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT (EFI_PAGE_SIZE) + +// +// Entry for tracking the memory regions for each memory type to help cooalese like memory types +// +typedef struct { + EFI_PHYSICAL_ADDRESS BaseAddress; + EFI_PHYSICAL_ADDRESS MaximumAddress; + UINT64 CurrentNumberOfPages; + UINTN InformationIndex; +} EFI_MEMORY_TYPE_STAISTICS; + +// +// MemoryMap - The current memory map +// +UINTN mMemoryMapKey = 0; + +// +// mMapStack - space to use as temp storage to build new map descriptors +// mMapDepth - depth of new descriptor stack +// + +#define MAX_MAP_DEPTH 6 +UINTN mMapDepth = 0; +MEMORY_MAP mMapStack[MAX_MAP_DEPTH]; +UINTN mFreeMapStack = 0; + +BOOLEAN mMemoryTypeInformationInitialized = FALSE; + +EFI_MEMORY_TYPE_STAISTICS mMemoryTypeStatistics[EfiMaxMemoryType + 1] = { + { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiReservedMemoryType + { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiLoaderCode + { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiLoaderData + { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiBootServicesCode + { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiBootServicesData + { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiRuntimeServicesCode + { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiRuntimeServicesData + { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiConventionalMemory + { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiUnusableMemory + { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiACPIReclaimMemory + { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiACPIMemoryNVS + { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiMemoryMappedIO + { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiMemoryMappedIOPortSpace + { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiPalCode + { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType } // EfiMaxMemoryType +}; + +EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress = EFI_MAX_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 }, + { EfiMaxMemoryType, 0 } +}; + +// +// Internal prototypes +// +VOID +PromoteMemoryResource ( + VOID +); + +STATIC +VOID +CoreAddRange ( + IN EFI_MEMORY_TYPE Type, + IN EFI_PHYSICAL_ADDRESS Start, + IN EFI_PHYSICAL_ADDRESS End, + IN UINT64 Attribute + ); + +STATIC +VOID +CoreFreeMemoryMapStack ( + VOID + ); + +STATIC +EFI_STATUS +CoreConvertPages ( + IN UINT64 Start, + IN UINT64 NumberOfPages, + IN EFI_MEMORY_TYPE NewType + ); + +STATIC +VOID +RemoveMemoryMapEntry ( + MEMORY_MAP *Entry + ); + +VOID +CoreAcquireMemoryLock ( + VOID + ) +/*++ + +Routine Description: + + Enter critical section by gaining lock on gMemoryLock + +Arguments: + + None + +Returns: + + None + +--*/ +{ + CoreAcquireLock (&gMemoryLock); +} + + +VOID +CoreReleaseMemoryLock ( + VOID + ) +/*++ + +Routine Description: + + Exit critical section by releasing lock on gMemoryLock + +Arguments: + + None + +Returns: + + None + +--*/ +{ + CoreReleaseLock (&gMemoryLock); +} + +VOID +PromoteMemoryResource ( + VOID + ) +/*++ + +Routine Description: + + Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable. + +Arguments: + + None + +Returns: + + None + +--*/ +{ + LIST_ENTRY *Link; + EFI_GCD_MAP_ENTRY *Entry; + + DEBUG ((EFI_D_ERROR | EFI_D_PAGE, "Promote the memory resource\n")); + + 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 < EFI_MAX_ADDRESS && + (Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) == + (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)) { + // + // Update the GCD map + // + 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 (); + + } + + Link = Link->ForwardLink; + } + + CoreReleaseGcdMemoryLock (); + + return; +} + +VOID +CoreAddMemoryDescriptor ( + IN EFI_MEMORY_TYPE Type, + IN EFI_PHYSICAL_ADDRESS Start, + IN UINT64 NumberOfPages, + IN UINT64 Attribute + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + Type - The type of memory to add + + Start - The starting address in the memory range + Must be page aligned + + NumberOfPages - The number of pages in the range + + Attribute - Attributes of the memory to add + +Returns: + + None. The range is added to the memory map + +--*/ +{ + EFI_PHYSICAL_ADDRESS End; + EFI_STATUS Status; + UINTN Index; + UINTN FreeIndex; + + if ((Start & EFI_PAGE_MASK) != 0) { + return; + } + + if (Type >= EfiMaxMemoryType && Type <= 0x7fffffff) { + return; + } + + CoreAcquireMemoryLock (); + End = Start + LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT) - 1; + CoreAddRange (Type, Start, End, Attribute); + CoreFreeMemoryMapStack (); + CoreReleaseMemoryLock (); + + // + // 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 = gMemoryTypeInformation[Index].Type; + if (Type < 0 || 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 = gMemoryTypeInformation[FreeIndex].Type; + if (Type < 0 || Type > EfiMaxMemoryType) { + continue; + } + + if (gMemoryTypeInformation[FreeIndex].NumberOfPages != 0) { + CoreFreePages ( + mMemoryTypeStatistics[Type].BaseAddress, + gMemoryTypeInformation[FreeIndex].NumberOfPages + ); + mMemoryTypeStatistics[Type].BaseAddress = 0; + mMemoryTypeStatistics[Type].MaximumAddress = EFI_MAX_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 = gMemoryTypeInformation[Index].Type; + if (Type < 0 || Type > EfiMaxMemoryType) { + continue; + } + + if (gMemoryTypeInformation[Index].NumberOfPages != 0) { + CoreFreePages ( + mMemoryTypeStatistics[Type].BaseAddress, + 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 = 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 == EFI_MAX_ADDRESS) { + mMemoryTypeStatistics[Type].MaximumAddress = mDefaultMaximumAddress; + } + } + + mMemoryTypeInformationInitialized = TRUE; +} + + +STATIC +VOID +CoreAddRange ( + IN EFI_MEMORY_TYPE Type, + IN EFI_PHYSICAL_ADDRESS Start, + IN EFI_PHYSICAL_ADDRESS End, + IN UINT64 Attribute + ) +/*++ + +Routine Description: + + Internal function. Adds a ranges to the memory map. + The range must not already exist in the map. + +Arguments: + + Type - The type of memory range to add + + Start - The starting address in the memory range + Must be paged aligned + + End - The last address in the range + Must be the last byte of a page + + Attribute - The attributes of the memory range to add + +Returns: + + None. The range is added to the memory map + +--*/ +{ + LIST_ENTRY *Link; + MEMORY_MAP *Entry; + + ASSERT ((Start & EFI_PAGE_MASK) == 0); + ASSERT (End > Start) ; + + ASSERT_LOCKED (&gMemoryLock); + + DEBUG ((EFI_D_PAGE, "AddRange: %lx-%lx to %d\n", Start, End, Type)); + + // + // 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 funciton + // 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].FromPool = 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 ; +} + +STATIC +VOID +CoreFreeMemoryMapStack ( + VOID + ) +/*++ + +Routine Description: + + Internal function. Moves any memory descriptors that are on the + temporary descriptor stack to heap. + +Arguments: + + None + +Returns: + + None + +--*/ +{ + MEMORY_MAP *Entry; + MEMORY_MAP *Entry2; + LIST_ENTRY *Link2; + + ASSERT_LOCKED (&gMemoryLock); + + // + // If already freeing the map stack, then return + // + if (mFreeMapStack) { + return ; + } + + // + // Move the temporary memory descriptor stack into pool + // + mFreeMapStack += 1; + + while (mMapDepth) { + + // + // Allocate memory for a entry + // + Entry = CoreAllocatePoolI (EfiRuntimeServicesData, sizeof(MEMORY_MAP)); + + ASSERT (Entry); + + // + // Update to proper entry + // + mMapDepth -= 1; + + if (mMapStack[mMapDepth].Link.ForwardLink != NULL) { + + // + // Move this entry to general pool + // + RemoveEntryList (&mMapStack[mMapDepth].Link); + mMapStack[mMapDepth].Link.ForwardLink = NULL; + + CopyMem (Entry , &mMapStack[mMapDepth], sizeof (MEMORY_MAP)); + Entry->FromPool = TRUE; + + // + // Find insertion location + // + for (Link2 = gMemoryMap.ForwardLink; Link2 != &gMemoryMap; Link2 = Link2->ForwardLink) { + Entry2 = CR (Link2, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE); + if (Entry2->FromPool && Entry2->Start > Entry->Start) { + break; + } + } + + InsertTailList (Link2, &Entry->Link); + + } else { + + // + // It was removed, don't move it + // + CoreFreePoolI (Entry); + + } + } + + mFreeMapStack -= 1; +} + +STATIC +VOID +RemoveMemoryMapEntry ( + MEMORY_MAP *Entry + ) +/*++ + +Routine Description: + + Internal function. Removes a descriptor entry. + +Arguments: + + Entry - The entry to remove + +Returns: + + None + +--*/ +{ + RemoveEntryList (&Entry->Link); + Entry->Link.ForwardLink = NULL; + + if (Entry->FromPool) { + CoreFreePoolI (Entry); + } +} + + +STATIC +EFI_STATUS +CoreConvertPages ( + IN UINT64 Start, + IN UINT64 NumberOfPages, + IN EFI_MEMORY_TYPE NewType + ) +/*++ + +Routine Description: + + Internal function. Converts a memory range to the specified type. + The range must exist in the memory map. + +Arguments: + + Start - The first address of the range + Must be page aligned + + NumberOfPages - The number of pages to convert + + NewType - The new type for the memory range + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_NOT_FOUND - Could not find a descriptor cover the specified range + or convertion not allowed. + + EFI_SUCCESS - Successfully converts the memory range to the specified type. + +--*/ +{ + + UINT64 NumberOfBytes; + UINT64 End; + UINT64 RangeEnd; + UINT64 Attribute; + 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); + + if (NumberOfPages == 0 || (Start & EFI_PAGE_MASK ) || (Start > (Start + NumberOfBytes))) { + 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 ((EFI_D_ERROR | EFI_D_PAGE, "ConvertPages: failed to find range %lx - %lx\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; + if (Entry->End < End) { + RangeEnd = Entry->End; + } + + DEBUG ((EFI_D_PAGE, "ConvertRange: %lx-%lx to %d\n", Start, RangeEnd, NewType)); + + // + // Debug code - verify conversion is allowed + // + if (!(NewType == EfiConventionalMemory ? 1 : 0) ^ (Entry->Type == EfiConventionalMemory ? 1 : 0)) { + DEBUG ((EFI_D_ERROR , "ConvertPages: Incompatible memory types\n")); + return EFI_NOT_FOUND; + } + + // + // Update counters for the number of pages allocated to each memory type + // + if (Entry->Type >= 0 && Entry->Type < EfiMaxMemoryType) { + if (Start >= mMemoryTypeStatistics[Entry->Type].BaseAddress && + Start <= mMemoryTypeStatistics[Entry->Type].MaximumAddress) { + if (NumberOfPages > mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages) { + mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages = 0; + } else { + mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages -= NumberOfPages; + } + } + } + + if (NewType >= 0 && NewType < EfiMaxMemoryType) { + if (Start >= mMemoryTypeStatistics[NewType].BaseAddress && Start <= mMemoryTypeStatistics[NewType].MaximumAddress) { + 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].FromPool = 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 + // + Attribute = Entry->Attribute; + + // + // 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 + // + CoreAddRange (NewType, Start, RangeEnd, Attribute); + + // + // 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; +} + + +STATIC +UINT64 +CoreFindFreePagesI ( + IN UINT64 MaxAddress, + IN UINT64 NumberOfPages, + IN EFI_MEMORY_TYPE NewType, + IN UINTN Alignment + ) +/*++ + +Routine Description: + + Internal function. Finds a consecutive free page range below + the requested address. + +Arguments: + + MaxAddress - The address that the range must be below + + NumberOfPages - Number of pages needed + + NewType - The type of memory the range is going to be turned into + + Alignment - Bits to align with + +Returns: + + The base address of the range, or 0 if the range was not found + +--*/ +{ + 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 &= ~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, skip it + // + if (DescStart >= MaxAddress) { + continue; + } + + // + // If desc ends past max allowed address, clip the end + // + if (DescEnd >= MaxAddress) { + DescEnd = MaxAddress; + } + + DescEnd = ((DescEnd + 1) & (~(Alignment - 1))) - 1; + + // + // 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 this is the best match so far remember it + // + if (DescEnd > Target) { + 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; +} + +STATIC +UINT64 +FindFreePages ( + IN UINT64 MaxAddress, + IN UINT64 NoPages, + IN EFI_MEMORY_TYPE NewType, + IN UINTN Alignment + ) +/*++ + +Routine Description: + + Internal function. Finds a consecutive free page range below + the requested address + +Arguments: + + MaxAddress - The address that the range must be below + + NoPages - Number of pages needed + + NewType - The type of memory the range is going to be turned into + + Alignment - Bits to align with + +Returns: + + The base address of the range, or 0 if the range was not found. + +--*/ +{ + UINT64 NewMaxAddress; + UINT64 Start; + + NewMaxAddress = MaxAddress; + + if (NewType >= 0 && NewType < EfiMaxMemoryType && NewMaxAddress >= mMemoryTypeStatistics[NewType].MaximumAddress) { + NewMaxAddress = mMemoryTypeStatistics[NewType].MaximumAddress; + } else { + if (NewMaxAddress > mDefaultMaximumAddress) { + NewMaxAddress = mDefaultMaximumAddress; + } + } + + Start = CoreFindFreePagesI (NewMaxAddress, NoPages, NewType, Alignment); + if (!Start) { + Start = CoreFindFreePagesI (MaxAddress, NoPages, NewType, Alignment); + if (!Start) { + // + // Here means there may be no enough memory to use, so try to go through + // all the memory descript to promote the untested memory directly + // + PromoteMemoryResource (); + + // + // Allocate memory again after the memory resource re-arranged + // + Start = CoreFindFreePagesI (MaxAddress, NoPages, NewType, Alignment); + } + } + + return Start; +} + + +EFI_STATUS +EFIAPI +CoreAllocatePages ( + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN NumberOfPages, + IN OUT EFI_PHYSICAL_ADDRESS *Memory + ) +/*++ + +Routine Description: + + Allocates pages from the memory map. + +Arguments: + + Type - The type of allocation to perform + + MemoryType - The type of memory to turn the allocated pages into + + NumberOfPages - The number of pages to allocate + + Memory - A pointer to receive the base allocated memory address + +Returns: + + Status. On success, Memory is filled in with the base address allocated + + EFI_INVALID_PARAMETER - Parameters violate checking rules defined in spec. + + EFI_NOT_FOUND - Could not allocate pages match the requirement. + + EFI_OUT_OF_RESOURCES - No enough pages to allocate. + + EFI_SUCCESS - Pages successfully allocated. + +--*/ +{ + EFI_STATUS Status; + UINT64 Start; + UINT64 MaxAddress; + UINTN Alignment; + + if (Type < AllocateAnyPages || Type >= (UINTN) MaxAllocateType) { + return EFI_INVALID_PARAMETER; + } + + if ((MemoryType >= EfiMaxMemoryType && MemoryType <= 0x7fffffff) || + MemoryType == EfiConventionalMemory) { + return EFI_INVALID_PARAMETER; + } + + Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT; + + if (MemoryType == EfiACPIReclaimMemory || + MemoryType == EfiACPIMemoryNVS || + MemoryType == EfiRuntimeServicesCode || + MemoryType == EfiRuntimeServicesData) { + + Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT; + } + + 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 = EFI_MAX_ADDRESS; + + 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); + if (Start == 0) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + } + + // + // Convert pages from FreeMemory to the requested type + // + Status = CoreConvertPages (Start, NumberOfPages, MemoryType); + +Done: + CoreReleaseMemoryLock (); + + if (!EFI_ERROR (Status)) { + *Memory = Start; + } + + return Status; +} + + + + +EFI_STATUS +EFIAPI +CoreFreePages ( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN NumberOfPages + ) +/*++ + +Routine Description: + + Frees previous allocated pages. + +Arguments: + + Memory - Base address of memory being freed + + NumberOfPages - The number of pages to free + +Returns: + + EFI_NOT_FOUND - Could not find the entry that covers the range + + EFI_INVALID_PARAMETER - Address not aligned + + EFI_SUCCESS -Pages successfully freed. + +--*/ +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + MEMORY_MAP *Entry; + UINTN Alignment; + + // + // Free the range + // + CoreAcquireMemoryLock (); + + // + // Find the entry that the covers the range + // + 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) { + CoreReleaseMemoryLock (); + return EFI_NOT_FOUND; + } + + Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT; + + if (Entry->Type == EfiACPIReclaimMemory || + Entry->Type == EfiACPIMemoryNVS || + Entry->Type == EfiRuntimeServicesCode || + Entry->Type == EfiRuntimeServicesData) { + + Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT; + + } + + if ((Memory & (Alignment - 1)) != 0) { + CoreReleaseMemoryLock (); + return EFI_INVALID_PARAMETER; + } + + NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1; + NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1); + + Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory); + + CoreReleaseMemoryLock (); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Destroy the contents + // + if (Memory < EFI_MAX_ADDRESS) { + DEBUG_CLEAR_MEMORY ((VOID *)(UINTN)Memory, NumberOfPages << EFI_PAGE_SHIFT); + } + + return Status; +} + + + +EFI_STATUS +EFIAPI +CoreGetMemoryMap ( + IN OUT UINTN *MemoryMapSize, + IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, + OUT UINTN *MapKey, + OUT UINTN *DescriptorSize, + OUT UINT32 *DescriptorVersion + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + 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. + MemoryMap - A pointer to the buffer in which firmware places the current memory map. + MapKey - A pointer to the location in which firmware returns the key for the + current memory map. + DescriptorSize - A pointer to the location in which firmware returns the size, in + bytes, of an individual EFI_MEMORY_DESCRIPTOR. + DescriptorVersion - A pointer to the location in which firmware returns the version + number associated with the EFI_MEMORY_DESCRIPTOR. + +Returns: + + EFI_SUCCESS - The memory map was returned in the MemoryMap buffer. + EFI_BUFFER_TOO_SMALL - The MemoryMap buffer was too small. The current buffer size + needed to hold the memory map is returned in MemoryMapSize. + EFI_INVALID_PARAMETER - One of the parameters has an invalid value. + +--*/ +{ + EFI_STATUS Status; + UINTN Size; + UINTN BufferSize; + UINTN NumberOfRuntimeEntries; + LIST_ENTRY *Link; + MEMORY_MAP *Entry; + EFI_GCD_MAP_ENTRY *GcdMapEntry; + + // + // Make sure the parameters are valid + // + if (MemoryMapSize == NULL) { + return EFI_INVALID_PARAMETER; + } + + CoreAcquireGcdMemoryLock (); + + // + // Count the number of Reserved and MMIO entries that are marked for runtime use + // + NumberOfRuntimeEntries = 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 == EfiGcdMemoryTypeReserved) || + (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo)) { + if ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) { + NumberOfRuntimeEntries++; + } + } + } + + 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 * NumberOfRuntimeEntries; + 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, Size); + for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) { + Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE); + ASSERT (Entry->VirtualStart == 0); + + MemoryMap->Type = Entry->Type; + MemoryMap->PhysicalStart = Entry->Start; + MemoryMap->VirtualStart = Entry->VirtualStart; + MemoryMap->NumberOfPages = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT); + + switch (Entry->Type) { + case EfiRuntimeServicesCode: + case EfiRuntimeServicesData: + case EfiPalCode: + MemoryMap->Attribute = Entry->Attribute | EFI_MEMORY_RUNTIME; + break; + + default: + MemoryMap->Attribute = Entry->Attribute; + break; + } + + MemoryMap = NextMemoryDescriptor (MemoryMap, Size); + } + + for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) { + GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE); + if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) || + (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo)) { + if ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) { + + MemoryMap->PhysicalStart = GcdMapEntry->BaseAddress; + MemoryMap->VirtualStart = 0; + MemoryMap->NumberOfPages = MemoryMap->NumberOfPages = RShiftU64 ((GcdMapEntry->EndAddress - GcdMapEntry->BaseAddress + 1), EFI_PAGE_SHIFT); + MemoryMap->Attribute = GcdMapEntry->Attributes & ~EFI_MEMORY_PORT_IO; + + if (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) { + MemoryMap->Type = EfiReservedMemoryType; + } else if (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) { + if ((GcdMapEntry->Attributes & EFI_MEMORY_PORT_IO) == EFI_MEMORY_PORT_IO) { + MemoryMap->Type = EfiMemoryMappedIOPortSpace; + } else { + MemoryMap->Type = EfiMemoryMappedIO; + } + } + + MemoryMap = NextMemoryDescriptor (MemoryMap, Size); + } + } + } + + Status = EFI_SUCCESS; + +Done: + + CoreReleaseMemoryLock (); + + CoreReleaseGcdMemoryLock (); + + // + // Update the map key finally + // + if (MapKey != NULL) { + *MapKey = mMemoryMapKey; + } + + *MemoryMapSize = BufferSize; + + return Status; +} + +VOID * +CoreAllocatePoolPages ( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN NumberOfPages, + IN UINTN Alignment + ) +/*++ + +Routine Description: + + Internal function. Used by the pool functions to allocate pages + to back pool allocation requests. + +Arguments: + + PoolType - The type of memory for the new pool pages + + NumberOfPages - No of pages to allocate + + Alignment - Bits to align. + +Returns: + + The allocated memory, or NULL + +--*/ +{ + EFI_STATUS Status; + UINT64 Start; + + // + // Find the pages to convert + // + Start = FindFreePages (EFI_MAX_ADDRESS, NumberOfPages, PoolType, Alignment); + + // + // Convert it to boot services data + // + if (Start == 0) { + DEBUG ((EFI_D_ERROR | EFI_D_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", NumberOfPages)); + } else { + Status = CoreConvertPages (Start, NumberOfPages, PoolType); + } + + return (VOID *)(UINTN)Start; +} + +VOID +CoreFreePoolPages ( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN NumberOfPages + ) +/*++ + +Routine Description: + + Internal function. Frees pool pages allocated via AllocatePoolPages () + +Arguments: + + Memory - The base address to free + + NumberOfPages - The number of pages to free + +Returns: + + None + +--*/ +{ + CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory); +} + + +EFI_STATUS +CoreTerminateMemoryMap ( + IN UINTN MapKey + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + MapKey - Memory map key + +Returns: + + EFI_INVALID_PARAMETER - Memory map not consistent with construction rules. + + EFI_SUCCESS - Valid memory map. + +--*/ +{ + 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->Attribute & EFI_MEMORY_RUNTIME) { + if (Entry->Type == EfiACPIReclaimMemory || Entry->Type == EfiACPIMemoryNVS) { + DEBUG((EFI_D_ERROR, "ExitBootServices: ACPI memory entry has RUNTIME attribute set.\n")); + CoreReleaseMemoryLock (); + return EFI_INVALID_PARAMETER; + } + if (Entry->Start & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) { + DEBUG((EFI_D_ERROR, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n")); + CoreReleaseMemoryLock (); + return EFI_INVALID_PARAMETER; + } + if ((Entry->End + 1) & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) { + DEBUG((EFI_D_ERROR, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n")); + CoreReleaseMemoryLock (); + return EFI_INVALID_PARAMETER; + } + } + } + + // + // 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; + } + + CoreReleaseMemoryLock (); + + return Status; +} + + + + + + + + diff --git a/EdkModulePkg/Core/Dxe/Mem/memdata.c b/EdkModulePkg/Core/Dxe/Mem/memdata.c new file mode 100644 index 0000000000..2fa4843102 --- /dev/null +++ b/EdkModulePkg/Core/Dxe/Mem/memdata.c @@ -0,0 +1,41 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + memdata.c + +Abstract: + + Global data used in memory service + + +Revision History + +--*/ + +#include + + +// +// MemoryLock - synchronizes access to the memory map and pool lists +// +EFI_LOCK gMemoryLock = EFI_INITIALIZE_LOCK_VARIABLE (EFI_TPL_NOTIFY); + +// +// MemoryMap - the current memory map +// +LIST_ENTRY gMemoryMap = INITIALIZE_LIST_HEAD_VARIABLE (gMemoryMap); + +// +// MemoryLastConvert - the last memory descriptor used for a conversion request +// +MEMORY_MAP *gMemoryLastConvert; diff --git a/EdkModulePkg/Core/Dxe/Mem/pool.c b/EdkModulePkg/Core/Dxe/Mem/pool.c new file mode 100644 index 0000000000..2f4669e6c1 --- /dev/null +++ b/EdkModulePkg/Core/Dxe/Mem/pool.c @@ -0,0 +1,613 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + pool.c + +Abstract: + + EFI Memory pool management + +Revision History + +--*/ + +#include + +#define POOL_FREE_SIGNATURE EFI_SIGNATURE_32('p','f','r','0') +typedef struct { + UINT32 Signature; + UINT32 Index; + LIST_ENTRY Link; +} POOL_FREE; + + +#define POOL_HEAD_SIGNATURE EFI_SIGNATURE_32('p','h','d','0') +typedef struct { + UINT32 Signature; + UINT32 Size; + EFI_MEMORY_TYPE Type; + UINTN Reserved; + CHAR8 Data[1]; +} POOL_HEAD; + +#define SIZE_OF_POOL_HEAD EFI_FIELD_OFFSET(POOL_HEAD,Data) + +#define POOL_TAIL_SIGNATURE EFI_SIGNATURE_32('p','t','a','l') +typedef struct { + UINT32 Signature; + UINT32 Size; +} POOL_TAIL; + + +#define POOL_SHIFT 7 + +#define POOL_OVERHEAD (SIZE_OF_POOL_HEAD + sizeof(POOL_TAIL)) + +#define HEAD_TO_TAIL(a) \ + ((POOL_TAIL *) (((CHAR8 *) (a)) + (a)->Size - sizeof(POOL_TAIL))); + + +#define SIZE_TO_LIST(a) ((a) >> POOL_SHIFT) +#define LIST_TO_SIZE(a) ((a+1) << POOL_SHIFT) + +#define MAX_POOL_LIST SIZE_TO_LIST(DEFAULT_PAGE_ALLOCATION) + +#define MAX_POOL_SIZE 0xffffff00 + +// +// Globals +// + +#define POOL_SIGNATURE EFI_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 PoolHead[EfiMaxMemoryType]; +LIST_ENTRY PoolHeadList; + +// +// +// + +VOID +CoreInitializePool ( + VOID + ) +/*++ + +Routine Description: + + Called to initialize the pool. + +Arguments: + + None + +Returns: + + None + +--*/ +{ + UINTN Type; + UINTN Index; + + for (Type=0; Type < EfiMaxMemoryType; Type++) { + PoolHead[Type].Signature = 0; + PoolHead[Type].Used = 0; + PoolHead[Type].MemoryType = Type; + for (Index=0; Index < MAX_POOL_LIST; Index++) { + InitializeListHead (&PoolHead[Type].FreeList[Index]); + } + } + InitializeListHead (&PoolHeadList); +} + + +POOL * +LookupPoolHead ( + IN EFI_MEMORY_TYPE MemoryType + ) +/*++ + +Routine Description: + + Look up pool head for specified memory type. + +Arguments: + + MemoryType - Memory type of which pool head is looked for + +Returns: + + Pointer of Corresponding pool head. + +--*/ +{ + LIST_ENTRY *Link; + POOL *Pool; + UINTN Index; + + if (MemoryType >= 0 && MemoryType < EfiMaxMemoryType) { + return &PoolHead[MemoryType]; + } + + if (MemoryType < 0) { + + for (Link = PoolHeadList.ForwardLink; Link != &PoolHeadList; Link = Link->ForwardLink) { + Pool = CR(Link, POOL, Link, POOL_SIGNATURE); + if (Pool->MemoryType == MemoryType) { + return Pool; + } + } + + Pool = CoreAllocatePoolI (EfiBootServicesData, sizeof (POOL)); + 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 (&PoolHeadList, &Pool->Link); + + return Pool; + } + + return NULL; +} + + + +EFI_STATUS +EFIAPI +CoreAllocatePool ( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN Size, + OUT VOID **Buffer + ) +/*++ + +Routine Description: + + Allocate pool of a particular type. + +Arguments: + + PoolType - Type of pool to allocate + + Size - The amount of pool to allocate + + Buffer - The address to return a pointer to the allocated pool + +Returns: + + EFI_INVALID_PARAMETER - PoolType not valid + + EFI_OUT_OF_RESOURCES - Size exceeds max pool size or allocation failed. + + EFI_SUCCESS - Pool successfully allocated. + +--*/ +{ + EFI_STATUS Status; + + // + // If it's not a valid type, fail it + // + if ((PoolType >= EfiMaxMemoryType && PoolType <= 0x7fffffff) || + PoolType == EfiConventionalMemory) { + 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; + } + + // + // Acquire the memory lock and make the allocation + // + Status = CoreAcquireLockOrFail (&gMemoryLock); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + *Buffer = CoreAllocatePoolI (PoolType, Size); + CoreReleaseMemoryLock (); + return (*Buffer != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES; +} + + +VOID * +CoreAllocatePoolI ( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN Size + ) +/*++ + +Routine Description: + + Internal function to allocate pool of a particular type. + + Caller must have the memory lock held + + +Arguments: + + PoolType - Type of pool to allocate + + Size - The amount of pool to allocate + +Returns: + + The allocate pool, or NULL + +--*/ +{ + POOL *Pool; + POOL_FREE *Free; + POOL_HEAD *Head; + POOL_TAIL *Tail; + CHAR8 *NewPage; + VOID *Buffer; + UINTN Index; + UINTN FSize; + UINTN offset; + UINTN Adjustment; + UINTN NoPages; + + ASSERT_LOCKED (&gMemoryLock); + + // + // Adjust the size by the pool header & tail overhead + // + + // + // 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 + // + ALIGN_VARIABLE (Size, Adjustment); + + 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 >= MAX_POOL_LIST) { + NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1; + NoPages &= ~(EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1); + Head = CoreAllocatePoolPages (PoolType, NoPages, DEFAULT_PAGE_ALLOCATION); + goto Done; + } + + // + // If there's no free pool in the proper list size, go get some more pages + // + if (IsListEmpty (&Pool->FreeList[Index])) { + + // + // Get another page + // + NewPage = CoreAllocatePoolPages(PoolType, EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION), DEFAULT_PAGE_ALLOCATION); + if (NewPage == NULL) { + goto Done; + } + + // + // Carve up new page into free pool blocks + // + offset = 0; + while (offset < DEFAULT_PAGE_ALLOCATION) { + ASSERT (Index < MAX_POOL_LIST); + FSize = LIST_TO_SIZE(Index); + + while (offset + FSize <= DEFAULT_PAGE_ALLOCATION) { + 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 == DEFAULT_PAGE_ALLOCATION); + Index = SIZE_TO_LIST(Size); + } + + // + // 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) { + + // + // If we have a pool buffer, fill in the header & tail info + // + Head->Signature = POOL_HEAD_SIGNATURE; + Head->Size = (UINT32) Size; + Head->Type = (EFI_MEMORY_TYPE) PoolType; + Tail = HEAD_TO_TAIL (Head); + Tail->Signature = POOL_TAIL_SIGNATURE; + Tail->Size = (UINT32) Size; + Buffer = Head->Data; + DEBUG_CLEAR_MEMORY (Buffer, Size - POOL_OVERHEAD); + + DEBUG ( + (EFI_D_POOL, + "AllcocatePoolI: Type %x, Addr %x (len %x) %,d\n", + PoolType, + Buffer, + Size - POOL_OVERHEAD, + Pool->Used) + ); + + // + // Account the allocation + // + Pool->Used += Size; + + } else { + DEBUG ((EFI_D_ERROR | EFI_D_POOL, "AllocatePool: failed to allocate %d bytes\n", Size)); + } + + return Buffer; +} + + + +EFI_STATUS +EFIAPI +CoreFreePool ( + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Frees pool. + +Arguments: + + Buffer - The allocated pool entry to free + +Returns: + + EFI_INVALID_PARAMETER - Buffer is not a valid value. + + EFI_SUCCESS - Pool successfully freed. + +--*/ +{ + EFI_STATUS Status; + + if (NULL == Buffer) { + return EFI_INVALID_PARAMETER; + } + + CoreAcquireMemoryLock (); + Status = CoreFreePoolI (Buffer); + CoreReleaseMemoryLock (); + return Status; +} + + +EFI_STATUS +CoreFreePoolI ( + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Internal function to free a pool entry. + + Caller must have the memory lock held + + +Arguments: + + Buffer - The allocated pool entry to free + +Returns: + + EFI_INVALID_PARAMETER - Buffer not valid + + EFI_SUCCESS - Buffer successfully freed. + +--*/ +{ + POOL *Pool; + POOL_HEAD *Head; + POOL_TAIL *Tail; + POOL_FREE *Free; + UINTN Index; + UINTN NoPages; + UINTN Size; + CHAR8 *NewPage; + UINTN FSize; + UINTN offset; + BOOLEAN AllFree; + + ASSERT(NULL != Buffer); + // + // Get the head & tail of the pool entry + // + Head = CR (Buffer, POOL_HEAD, Data, POOL_HEAD_SIGNATURE); + ASSERT(NULL != Head); + + if (Head->Signature != POOL_HEAD_SIGNATURE) { + return EFI_INVALID_PARAMETER; + } + + Tail = HEAD_TO_TAIL (Head); + ASSERT(NULL != Tail); + + // + // Debug + // + ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE); + ASSERT (Head->Size == Tail->Size); + ASSERT_LOCKED (&gMemoryLock); + + if (Tail->Signature != POOL_TAIL_SIGNATURE) { + return EFI_INVALID_PARAMETER; + } + + if (Head->Size != Tail->Size) { + return EFI_INVALID_PARAMETER; + } + + // + // 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 ((EFI_D_POOL, "FreePool: %x (len %x) %,d\n", Head->Data, Head->Size - POOL_OVERHEAD, Pool->Used)); + + // + // 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 >= MAX_POOL_LIST) { + + // + // Return the memory pages back to free memory + // + NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1; + NoPages &= ~(EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1); + CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN) Head, NoPages); + + } else { + + // + // Put the pool entry onto the free pool list + // + Free = (POOL_FREE *) Head; + ASSERT(NULL != Free); + 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 & ~((DEFAULT_PAGE_ALLOCATION) -1)); + Free = (POOL_FREE *) &NewPage[0]; + ASSERT(NULL != Free); + + if (Free->Signature == POOL_FREE_SIGNATURE) { + + Index = Free->Index; + + AllFree = TRUE; + offset = 0; + + while ((offset < DEFAULT_PAGE_ALLOCATION) && (AllFree)) { + FSize = LIST_TO_SIZE(Index); + while (offset + FSize <= DEFAULT_PAGE_ALLOCATION) { + Free = (POOL_FREE *) &NewPage[offset]; + ASSERT(NULL != Free); + if (Free->Signature != POOL_FREE_SIGNATURE) { + AllFree = FALSE; + } + offset += FSize; + } + Index -= 1; + } + + 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(NULL != Free); + Index = Free->Index; + offset = 0; + + while (offset < DEFAULT_PAGE_ALLOCATION) { + FSize = LIST_TO_SIZE(Index); + while (offset + FSize <= DEFAULT_PAGE_ALLOCATION) { + Free = (POOL_FREE *) &NewPage[offset]; + ASSERT(NULL != Free); + RemoveEntryList (&Free->Link); + offset += FSize; + } + Index -= 1; + } + + // + // Free the page + // + CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN)NewPage, EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION)); + } + } + } + + // + // If this is an OS 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 (Pool->MemoryType < 0 && Pool->Used == 0) { + RemoveEntryList (&Pool->Link); + CoreFreePoolI (Pool); + } + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Core/Dxe/Misc/DebugImageInfo.c b/EdkModulePkg/Core/Dxe/Misc/DebugImageInfo.c new file mode 100644 index 0000000000..e7f90de025 --- /dev/null +++ b/EdkModulePkg/Core/Dxe/Misc/DebugImageInfo.c @@ -0,0 +1,260 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DebugImageInfo.c + +Abstract: + + Support functions for managing debug image info table when loading and unloading + images. + +--*/ + +#include + + +static EFI_DEBUG_IMAGE_INFO_TABLE_HEADER mDebugInfoTableHeader = { + 0, // volatile UINT32 UpdateStatus; + 0, // UINT32 TableSize; + NULL // EFI_DEBUG_IMAGE_INFO *EfiDebugImageInfoTable; +}; + +static EFI_SYSTEM_TABLE_POINTER *mDebugTable = NULL; + + +VOID +CoreInitializeDebugImageInfoTable ( + VOID + ) +/*++ + +Routine Description: + + Creates and initializes the DebugImageInfo Table. Also creates the configuration + table and registers it into the system table. + +Arguments: + None + +Returns: + NA + +Notes: + 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. + +--*/ +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS Mem; + UINTN NumberOfPages; + + // + // Allocate boot services memory for the structure. It's required to be aligned on + // a 4M boundary, so allocate a 4M block (plus what we require), free it up, calculate + // a 4M aligned address within the memory we just freed, and then allocate memory at that + // address for our initial structure. + // + NumberOfPages = FOUR_MEG_PAGES + EFI_SIZE_TO_PAGES(sizeof (EFI_SYSTEM_TABLE_POINTER)); + + Status = CoreAllocatePages (AllocateAnyPages, EfiBootServicesData, NumberOfPages , &Mem); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR(Status)) { + return; + } + Status = CoreFreePages (Mem, NumberOfPages); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR(Status)) { + return; + } + // + // Now get a 4M aligned address within the memory range we were given. + // Then allocate memory at that address + // + Mem = (Mem + FOUR_MEG_MASK) & (~FOUR_MEG_MASK); + + Status = CoreAllocatePages (AllocateAddress, EfiBootServicesData, NumberOfPages - FOUR_MEG_PAGES, &Mem); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR(Status)) { + return; + } + // + // We now have a 4M aligned page allocated, so fill in the data structure. + // 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. + // + mDebugTable = (EFI_SYSTEM_TABLE_POINTER *)(UINTN)Mem; + mDebugTable->Signature = EFI_SYSTEM_TABLE_SIGNATURE; + mDebugTable->EfiSystemTableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) gST; + mDebugTable->Crc32 = 0; + Status = CoreInstallConfigurationTable (&gEfiDebugImageInfoTableGuid, &mDebugInfoTableHeader); + ASSERT_EFI_ERROR (Status); +} + +VOID +CoreUpdateDebugTableCrc32 ( + VOID + ) +/*++ + +Routine Description: + + 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. + +Arguments: + None + +Returns: + NA + +--*/ +{ + ASSERT(mDebugTable != NULL); + mDebugTable->Crc32 = 0; + gBS->CalculateCrc32 ((VOID *)mDebugTable, sizeof (EFI_SYSTEM_TABLE_POINTER), &mDebugTable->Crc32); +} + +VOID +CoreNewDebugImageInfoEntry ( + IN UINTN ImageInfoType, + IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage, + IN EFI_HANDLE ImageHandle + ) +/*++ + +Routine Description: + + Adds a new DebugImageInfo structure to the DebugImageInfo Table. Re-Allocates + the table if it's not large enough to accomidate another entry. + +Arguments: + + ImageInfoType - type of debug image information + LoadedImage - pointer to the loaded image protocol for the image being loaded + ImageHandle - image handle for the image being loaded + +Returns: + NA + +--*/ +{ + EFI_DEBUG_IMAGE_INFO *Table; + EFI_DEBUG_IMAGE_INFO *NewTable; + UINTN Index; + UINTN MaxTableIndex; + 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; + MaxTableIndex = mDebugInfoTableHeader.TableSize; + + for (Index = 0; Index < MaxTableIndex; Index++) { + if (Table[Index].NormalImage == NULL) { + // + // We have found a free entry so exit the loop + // + break; + } + } + if (Index == MaxTableIndex) { + // + // Table is full, so re-allocate another page for a larger table... + // + TableSize = MaxTableIndex * EFI_DEBUG_TABLE_ENTRY_SIZE; + NewTable = CoreAllocateZeroBootServicesPool (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; + mDebugInfoTableHeader.TableSize += EFI_PAGE_SIZE / EFI_DEBUG_TABLE_ENTRY_SIZE; + } + // + // Allocate data for new entry + // + Table[Index].NormalImage = CoreAllocateZeroBootServicesPool (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; + } + mDebugInfoTableHeader.UpdateStatus &= ~EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS; +} + + +VOID +CoreRemoveDebugImageInfoEntry ( + EFI_HANDLE ImageHandle + ) +/*++ + +Routine Description: + + Removes and frees an entry from the DebugImageInfo Table. + +Arguments: + + ImageHandle - image handle for the image being unloaded + +Returns: + + NA + +--*/ +{ + EFI_DEBUG_IMAGE_INFO *Table; + UINTN Index; + + mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS; + + Table = mDebugInfoTableHeader.EfiDebugImageInfoTable; + + for (Index = 0; Index < mDebugInfoTableHeader.TableSize; 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; + break; + } + } + mDebugInfoTableHeader.UpdateStatus &= ~EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS; +} + diff --git a/EdkModulePkg/Core/Dxe/Misc/InstallConfigurationTable.c b/EdkModulePkg/Core/Dxe/Misc/InstallConfigurationTable.c new file mode 100644 index 0000000000..e81fcad35a --- /dev/null +++ b/EdkModulePkg/Core/Dxe/Misc/InstallConfigurationTable.c @@ -0,0 +1,214 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + InstallConfigurationTable.c + + +Abstract: + + Tiano Miscellaneous Services InstallConfigurationTable service + +--*/ + +#include + +#define CONFIG_TABLE_SIZE_INCREASED 0x10 + +UINTN mSystemTableAllocateSize = 0; + + +EFI_STATUS +CoreGetConfigTable ( + IN EFI_GUID *Guid, + OUT VOID **Table + ) +/*++ + +Routine Description: + + Find a config table by name in system table's ConfigurationTable. + +Arguments: + + Guid - The table name to look for + + Table - Pointer of the config table + +Returns: + + EFI_NOT_FOUND - Could not find the table in system table's ConfigurationTable. + + EFI_SUCCESS - Table successfully found. + +--*/ +{ + UINTN Index; + + for (Index = 0; Index < gST->NumberOfTableEntries; Index++) { + if (CompareGuid (Guid, &(gST->ConfigurationTable[Index].VendorGuid))) { + *Table = gST->ConfigurationTable[Index].VendorTable; + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + + + +EFI_STATUS +EFIAPI +CoreInstallConfigurationTable ( + IN EFI_GUID *Guid, + IN VOID *Table + ) +/*++ + +Routine Description: + + Boot Service called to add, modify, or remove a system configuration table from + the EFI System Table. + +Arguments: + + Guid - Pointer to the GUID for the entry to add, update, or remove + Table - Pointer to the configuration table for the entry to add, update, or + remove, may be NULL. + +Returns: + + EFI_SUCCESS Guid, Table pair added, updated, or removed. + EFI_INVALID_PARAMETER Input GUID not valid. + EFI_NOT_FOUND Attempted to delete non-existant entry + EFI_OUT_OF_RESOURCES Not enough memory available + +--*/ +{ + UINTN Index; + EFI_CONFIGURATION_TABLE *EfiConfigurationTable; + + // + // If Guid is NULL, then this operation cannot be performed + // + if (Guid == NULL) { + return EFI_INVALID_PARAMETER; + } + + EfiConfigurationTable = gST->ConfigurationTable; + + // + // Search all the table for an entry that matches Guid + // + for (Index = 0; Index < gST->NumberOfTableEntries; Index++) { + if (CompareGuid (Guid, &(gST->ConfigurationTable[Index].VendorGuid))) { + break; + } + } + + if (Index < gST->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 enty and return. + // + gST->ConfigurationTable[Index].VendorTable = Table; + return EFI_SUCCESS; + } + + // + // A match was found and Table is NULL, so this is a delete operation. + // + gST->NumberOfTableEntries--; + + // + // Copy over deleted entry + // + CopyMem ( + &(EfiConfigurationTable[Index]), + &(gST->ConfigurationTable[Index + 1]), + (gST->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 == gST->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 = CoreAllocateRuntimePool (mSystemTableAllocateSize); + if (EfiConfigurationTable == NULL) { + // + // If a new table could not be allocated, then return an error. + // + return EFI_OUT_OF_RESOURCES; + } + + if (gST->ConfigurationTable != NULL) { + // + // Copy the old table to the new table. + // + CopyMem ( + EfiConfigurationTable, + gST->ConfigurationTable, + Index * sizeof (EFI_CONFIGURATION_TABLE) + ); + + // + // Free Old Table + // + CoreFreePool (gST->ConfigurationTable); + } + + // + // Update System Table + // + gST->ConfigurationTable = EfiConfigurationTable; + } + + // + // Fill in the new entry + // + CopyMem ((VOID *)&EfiConfigurationTable[Index].VendorGuid, Guid, sizeof (EFI_GUID)); + EfiConfigurationTable[Index].VendorTable = Table; + + // + // This is an add operation, so increment the number of table entries + // + gST->NumberOfTableEntries++; + } + + // + // Fix up the CRC-32 in the EFI System Table + // + CalculateEfiHdrCrc (&gST->Hdr); + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Core/Dxe/Misc/SetWatchdogTimer.c b/EdkModulePkg/Core/Dxe/Misc/SetWatchdogTimer.c new file mode 100644 index 0000000000..c11c926e06 --- /dev/null +++ b/EdkModulePkg/Core/Dxe/Misc/SetWatchdogTimer.c @@ -0,0 +1,83 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + SetWatchdogTimer.c + +Abstract: + + Tiano Miscellaneous Services SetWatchdogTimer service implementation + +--*/ + +#include + +#define WATCHDOG_TIMER_CALIBRATE_PER_SECOND 10000000 + + +EFI_STATUS +EFIAPI +CoreSetWatchdogTimer ( + IN UINTN Timeout, + IN UINT64 WatchdogCode, + IN UINTN DataSize, + IN CHAR16 *WatchdogData OPTIONAL + ) +/*++ + +Routine Description: + + Sets the system's watchdog timer. + +Arguments: + + Timeout The number of seconds. Zero disables the timer. + + ///////following three parameters are left for platform specific using + + WatchdogCode The numberic code to log. 0x0 to 0xffff are firmware + DataSize Size of the optional data + WatchdogData Optional Null terminated unicode string followed by binary + data. + +Returns: + + EFI_SUCCESS Timeout has been set + EFI_NOT_AVAILABLE_YET WatchdogTimer is not available yet + EFI_UNSUPPORTED System does not have a timer (currently not used) + EFI_DEVICE_ERROR Could not complete due to hardware error + +--*/ +{ + 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/EdkModulePkg/Core/Dxe/Misc/Stall.c b/EdkModulePkg/Core/Dxe/Misc/Stall.c new file mode 100644 index 0000000000..c251f31dc9 --- /dev/null +++ b/EdkModulePkg/Core/Dxe/Misc/Stall.c @@ -0,0 +1,82 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Stall.c + +Abstract: + + Tiano Miscellaneous Services Stall service implementation + +--*/ + +// +// Include statements +// + +#include + + +EFI_STATUS +EFIAPI +CoreStall ( + IN UINTN Microseconds + ) +/*++ + +Routine Description: + + Introduces a fine-grained stall. + +Arguments: + + Microseconds The number of microseconds to stall execution + +Returns: + + EFI_SUCCESS - Execution was stalled for at least the requested amount + of microseconds. + + EFI_NOT_AVAILABLE_YET - gMetronome is not available yet + +--*/ +{ + UINT32 Counter; + UINT32 Remainder; + + if (gMetronome == NULL) { + return EFI_NOT_AVAILABLE_YET; + } + + // + // Calculate the number of ticks by dividing the number of microseconds by + // the TickPeriod. + // Calcullation is based on 100ns unit. + // + Counter = (UINT32) DivU64x32Remainder ( + Microseconds * 10, + gMetronome->TickPeriod, + &Remainder + ); + + // + // Call WaitForTick for Counter + 1 ticks to try to guarantee Counter tick + // periods, thus attempting to ensure Microseconds of stall time. + // + if (Remainder != 0) { + Counter++; + } + + gMetronome->WaitForTick (gMetronome, Counter); + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Core/Dxe/SectionExtraction/CoreSectionExtraction.c b/EdkModulePkg/Core/Dxe/SectionExtraction/CoreSectionExtraction.c new file mode 100644 index 0000000000..e98b80cddf --- /dev/null +++ b/EdkModulePkg/Core/Dxe/SectionExtraction/CoreSectionExtraction.c @@ -0,0 +1,1339 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + CoreSectionExtraction.c + +Abstract: + + 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. + +--*/ + +#include + +// +// Local defines and typedefs +// +#define CORE_SECTION_CHILD_SIGNATURE EFI_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; +} CORE_SECTION_CHILD_NODE; + +#define CORE_SECTION_STREAM_SIGNATURE EFI_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; + EFI_EVENT Event; +} RPN_EVENT_CONTEXT; + + + +// +// Local prototypes +// + +STATIC +BOOLEAN +ChildIsType ( + IN CORE_SECTION_STREAM_NODE *Stream, + IN CORE_SECTION_CHILD_NODE *Child, + IN EFI_SECTION_TYPE SearchType, + IN EFI_GUID *SectionDefinitionGuid + ); + +STATIC +VOID +EFIAPI +NotifyGuidedExtraction ( + IN EFI_EVENT Event, + IN VOID *RpnContext + ); + +STATIC +VOID +CreateGuidedExtractionRpnEvent ( + IN CORE_SECTION_STREAM_NODE *ParentStream, + IN CORE_SECTION_CHILD_NODE *ChildNode + ); + +EFI_STATUS +EFIAPI +OpenSectionStream ( + IN EFI_SECTION_EXTRACTION_PROTOCOL *This, + IN UINTN SectionStreamLength, + IN VOID *SectionStream, + OUT UINTN *SectionStreamHandle + ); + +EFI_STATUS +EFIAPI +GetSection ( + IN EFI_SECTION_EXTRACTION_PROTOCOL *This, + IN UINTN SectionStreamHandle, + IN EFI_SECTION_TYPE *SectionType, + IN EFI_GUID *SectionDefinitionGuid, + IN UINTN SectionInstance, + IN VOID **Buffer, + IN OUT UINTN *BufferSize, + OUT UINT32 *AuthenticationStatus + ); + +EFI_STATUS +EFIAPI +CloseSectionStream ( + IN EFI_SECTION_EXTRACTION_PROTOCOL *This, + IN UINTN StreamHandleToClose + ); + +STATIC +EFI_STATUS +FindStreamNode ( + IN UINTN SearchHandle, + OUT CORE_SECTION_STREAM_NODE **FoundStream + ); + +STATIC +EFI_STATUS +FindChildNode ( + IN CORE_SECTION_STREAM_NODE *SourceStream, + IN EFI_SECTION_TYPE SearchType, + IN UINTN *SectionInstance, + IN EFI_GUID *SectionDefinitionGuid, + OUT CORE_SECTION_CHILD_NODE **FoundChild, + OUT CORE_SECTION_STREAM_NODE **FoundStream, + OUT UINT32 *AuthenticationStatus + ); + +STATIC +EFI_STATUS +CreateChildNode ( + IN CORE_SECTION_STREAM_NODE *Stream, + IN UINT32 ChildOffset, + OUT CORE_SECTION_CHILD_NODE **ChildNode + ); + +STATIC +VOID +FreeChildNode ( + IN CORE_SECTION_CHILD_NODE *ChildNode + ); + +STATIC +EFI_STATUS +OpenSectionStreamEx ( + IN UINTN SectionStreamLength, + IN VOID *SectionStream, + IN BOOLEAN AllocateBuffer, + IN UINT32 AuthenticationStatus, + OUT UINTN *SectionStreamHandle + ); + +STATIC +BOOLEAN +IsValidSectionStream ( + IN VOID *SectionStream, + IN UINTN SectionStreamLength + ); + +// +// Module globals +// +LIST_ENTRY mStreamRoot = INITIALIZE_LIST_HEAD_VARIABLE (mStreamRoot); + +EFI_HANDLE mSectionExtractionHandle = NULL; + +EFI_SECTION_EXTRACTION_PROTOCOL mSectionExtraction = { + OpenSectionStream, + GetSection, + CloseSectionStream +}; + + +EFI_STATUS +EFIAPI +InitializeSectionExtraction ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + Entry point of the section extraction code. Initializes an instance of the + section extraction interface and installs it on a new handle. + +Arguments: + ImageHandle EFI_HANDLE: A handle for the image that is initializing this driver + SystemTable EFI_SYSTEM_TABLE: A pointer to the EFI system table + +Returns: + EFI_SUCCESS: Driver initialized successfully + EFI_OUT_OF_RESOURCES: Could not allocate needed resources + +--*/ +{ + EFI_STATUS Status; + + // + // Install SEP to a new handle + // + Status = CoreInstallProtocolInterface ( + &mSectionExtractionHandle, + &gEfiSectionExtractionProtocolGuid, + EFI_NATIVE_INTERFACE, + &mSectionExtraction + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + + +EFI_STATUS +EFIAPI +OpenSectionStream ( + IN EFI_SECTION_EXTRACTION_PROTOCOL *This, + IN UINTN SectionStreamLength, + IN VOID *SectionStream, + OUT UINTN *SectionStreamHandle + ) +/*++ + +Routine Description: + SEP member function. This function creates and returns a new section stream + handle to represent the new section stream. + +Arguments: + This - Indicates the calling context. + SectionStreamLength - Size in bytes of the section stream. + SectionStream - Buffer containing the new section stream. + SectionStreamHandle - A pointer to a caller allocated UINTN that on output + contains the new section stream handle. + +Returns: + EFI_SUCCESS + EFI_OUT_OF_RESOURCES - memory allocation failed. + EFI_INVALID_PARAMETER - section stream does not end concident with end of + last section. + +--*/ +{ + // + // Check to see section stream looks good... + // + if (!IsValidSectionStream (SectionStream, SectionStreamLength)) { + return EFI_INVALID_PARAMETER; + } + + return OpenSectionStreamEx ( + SectionStreamLength, + SectionStream, + TRUE, + 0, + SectionStreamHandle + ); +} + + +EFI_STATUS +EFIAPI +GetSection ( + IN EFI_SECTION_EXTRACTION_PROTOCOL *This, + IN UINTN SectionStreamHandle, + IN EFI_SECTION_TYPE *SectionType, + IN EFI_GUID *SectionDefinitionGuid, + IN UINTN SectionInstance, + IN VOID **Buffer, + IN OUT UINTN *BufferSize, + OUT UINT32 *AuthenticationStatus + ) +/*++ + +Routine Description: + SEP member function. Retrieves requested section from section stream. + +Arguments: + This: Pointer to SEP instance. + SectionStreamHandle: The section stream from which to extract the requested + section. + SectionType: A pointer to the type of section to search for. + SectionDefinitionGuid: If the section type is EFI_SECTION_GUID_DEFINED, then + SectionDefinitionGuid indicates which of these types + of sections to search for. + SectionInstance: Indicates which instance of the requested section to + return. + Buffer: Double indirection to buffer. If *Buffer is non-null on + input, then the buffer is caller allocated. If + *Buffer is NULL, then the buffer is callee allocated. + In either case, the requried buffer size is returned + in *BufferSize. + 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. + AuthenticationStatus: Indicates the authentication status of the retrieved + section. + +Returns: + EFI_SUCCESS: Section was retrieved successfully + 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. + EFI_NOT_FOUND: An error was encountered when parsing the SectionStream. + This indicates the SectionStream is not correctly + formatted. + EFI_NOT_FOUND: The requested section does not exist. + EFI_OUT_OF_RESOURCES: The system has insufficient resources to process the + request. + EFI_INVALID_PARAMETER: The SectionStreamHandle does not exist. + EFI_WARN_TOO_SMALL: The size of the caller allocated input buffer is + insufficient to contain the requested section. The + input buffer is filled and contents are section contents + are truncated. + +--*/ +{ + 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; + + + OldTpl = CoreRaiseTpl (EFI_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; + } + CopySize = ChildNode->Size - sizeof (EFI_COMMON_SECTION_HEADER); + CopyBuffer = ChildStreamNode->StreamBuffer + ChildNode->OffsetInStream + 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 = CoreAllocateBootServicesPool (CopySize); + if (*Buffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto GetSection_Done; + } + } + CopyMem (*Buffer, CopyBuffer, CopySize); + *BufferSize = SectionSize; + +GetSection_Done: + CoreRestoreTpl (OldTpl); + return Status; +} + + + +EFI_STATUS +EFIAPI +CloseSectionStream ( + IN EFI_SECTION_EXTRACTION_PROTOCOL *This, + IN UINTN StreamHandleToClose + ) +/*++ + +Routine Description: + SEP member function. Deletes an existing section stream + +Arguments: + This - Indicates the calling context. + StreamHandleToClose - Indicates the stream to close + +Returns: + EFI_SUCCESS + EFI_OUT_OF_RESOURCES - memory allocation failed. + EFI_INVALID_PARAMETER - section stream does not end concident with end of + last section. + +--*/ +{ + CORE_SECTION_STREAM_NODE *StreamNode; + EFI_TPL OldTpl; + EFI_STATUS Status; + LIST_ENTRY *Link; + CORE_SECTION_CHILD_NODE *ChildNode; + + OldTpl = CoreRaiseTpl (EFI_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); + } + CoreFreePool (StreamNode->StreamBuffer); + CoreFreePool (StreamNode); + Status = EFI_SUCCESS; + } else { + Status = EFI_INVALID_PARAMETER; + } + + CoreRestoreTpl (OldTpl); + return Status; +} + + +STATIC +BOOLEAN +ChildIsType ( + IN CORE_SECTION_STREAM_NODE *Stream, + IN CORE_SECTION_CHILD_NODE *Child, + IN EFI_SECTION_TYPE SearchType, + IN EFI_GUID *SectionDefinitionGuid + ) +/*++ + +Routine Description: + Worker function. Determine if the input stream:child matches the input type. + +Arguments: + Stream - Indicates the section stream associated with the child + Child - Indicates the child to check + SearchType - Indicates the type of section to check against for + SectionDefinitionGuid - Indicates the GUID to check against if the type is + EFI_SECTION_GUID_DEFINED +Returns: + TRUE - The child matches + FALSE - The child doesn't match + +--*/ +{ + EFI_GUID_DEFINED_SECTION *GuidedSection; + + if (SearchType == EFI_SECTION_ALL) { + return TRUE; + } + if (Child->Type != SearchType) { + return FALSE; + } + if (SearchType != EFI_SECTION_GUID_DEFINED) { + return TRUE; + } + GuidedSection = (EFI_GUID_DEFINED_SECTION * )(Stream->StreamBuffer + Child->OffsetInStream); + return CompareGuid (&GuidedSection->SectionDefinitionGuid, SectionDefinitionGuid); +} + + +STATIC +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 + ) +/*++ + +Routine Description: + Worker function Recursively searches / builds section stream database + looking for requested section. + +Arguments: + SourceStream - Indicates the section stream in which to do the search. + SearchType - Indicates the type of section to search for. + SectionInstance - Indicates which instance of section to find. This is + an in/out parameter to deal with recursions. + SectionDefinitionGuid - Guid of section definition + FoundChild - Output indicating the child node that is found. + 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. + AuthenticationStatus- Indicates the authentication status of the found section. + +Returns: + EFI_SUCCESS - Child node was found and returned. + EFI_OUT_OF_RESOURCES- Memory allocation failed. + EFI_NOT_FOUND - Requested child node does not exist. + EFI_PROTOCOL_ERROR - a required GUIDED section extraction protocol does not + exist + +--*/ +{ + 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. + // + 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 (;;) { + 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; + } + } + + 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; + } + } + } +} + + +STATIC +EFI_STATUS +CreateChildNode ( + IN CORE_SECTION_STREAM_NODE *Stream, + IN UINT32 ChildOffset, + OUT CORE_SECTION_CHILD_NODE **ChildNode + ) +/*++ + +Routine Description: + Worker function. Constructor for new child nodes. + +Arguments: + Stream - Indicates the section stream in which to add the child. + ChildOffset - Indicates the offset in Stream that is the beginning + of the child section. + ChildNode - Indicates the Callee allocated and initialized child. + +Returns: + EFI_SUCCESS - Child node was found and returned. + EFI_OUT_OF_RESOURCES- Memory allocation failed. + 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 Status; + EFI_COMMON_SECTION_HEADER *SectionHeader; + EFI_COMPRESSION_SECTION *CompressionHeader; + EFI_GUID_DEFINED_SECTION *GuidedHeader; + EFI_TIANO_DECOMPRESS_PROTOCOL *Decompress; + EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *GuidedExtraction; + VOID *NewStreamBuffer; + VOID *ScratchBuffer; + UINT32 ScratchSize; + UINTN NewStreamBufferSize; + UINT32 AuthenticationStatus; + UINT32 SectionLength; + + CORE_SECTION_CHILD_NODE *Node; + + SectionHeader = (EFI_COMMON_SECTION_HEADER *) (Stream->StreamBuffer + ChildOffset); + + // + // Allocate a new node + // + *ChildNode = CoreAllocateBootServicesPool (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; + 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 + // + ASSERT (Node->Size >= sizeof (EFI_COMPRESSION_SECTION)); + + CompressionHeader = (EFI_COMPRESSION_SECTION *) SectionHeader; + + // + // Allocate space for the new stream + // + if (CompressionHeader->UncompressedLength > 0) { + NewStreamBufferSize = CompressionHeader->UncompressedLength; + NewStreamBuffer = CoreAllocateBootServicesPool (NewStreamBufferSize); + if (NewStreamBuffer == NULL) { + CoreFreePool (Node); + return EFI_OUT_OF_RESOURCES; + } + + if (CompressionHeader->CompressionType == EFI_NOT_COMPRESSED) { + // + // stream is not actually compressed, just encapsulated. So just copy it. + // + CopyMem (NewStreamBuffer, CompressionHeader + 1, NewStreamBufferSize); + } else if (CompressionHeader->CompressionType == EFI_STANDARD_COMPRESSION || + CompressionHeader->CompressionType == EFI_CUSTOMIZED_COMPRESSION) { + // + // Decompress the stream + // + if (CompressionHeader->CompressionType == EFI_STANDARD_COMPRESSION) { + Status = CoreLocateProtocol (&gEfiTianoDecompressProtocolGuid, NULL, (VOID **)&Decompress); + } else { + Status = CoreLocateProtocol (&gEfiCustomizedDecompressProtocolGuid, NULL, (VOID **)&Decompress); + } + + ASSERT_EFI_ERROR (Status); + + Status = Decompress->GetInfo ( + Decompress, + CompressionHeader + 1, + Node->Size - sizeof (EFI_COMPRESSION_SECTION), + (UINT32 *)&NewStreamBufferSize, + &ScratchSize + ); + ASSERT_EFI_ERROR (Status); + ASSERT (NewStreamBufferSize == CompressionHeader->UncompressedLength); + + ScratchBuffer = CoreAllocateBootServicesPool (ScratchSize); + if (ScratchBuffer == NULL) { + CoreFreePool (Node); + CoreFreePool (NewStreamBuffer); + return EFI_OUT_OF_RESOURCES; + } + + Status = Decompress->Decompress ( + Decompress, + CompressionHeader + 1, + Node->Size - sizeof (EFI_COMPRESSION_SECTION), + NewStreamBuffer, + (UINT32)NewStreamBufferSize, + ScratchBuffer, + ScratchSize + ); + ASSERT_EFI_ERROR (Status); + CoreFreePool (ScratchBuffer); + } + } 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; + Node->EncapsulationGuid = &GuidedHeader->SectionDefinitionGuid; + Status = CoreLocateProtocol (Node->EncapsulationGuid, NULL, (VOID **)&GuidedExtraction); + if (!EFI_ERROR (Status)) { + // + // 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 (GuidedHeader->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) { + // + // OR in the parent stream's aggregate status. + // + AuthenticationStatus |= Stream->AuthenticationStatus & EFI_AGGREGATE_AUTH_STATUS_ALL; + } else { + // + // since there's no authentication data contributed by the section, + // just inherit the full value from our immediate parent. + // + AuthenticationStatus = Stream->AuthenticationStatus; + } + + Status = OpenSectionStreamEx ( + NewStreamBufferSize, + NewStreamBuffer, + FALSE, + AuthenticationStatus, + &Node->EncapsulatedStreamHandle + ); + if (EFI_ERROR (Status)) { + CoreFreePool (*ChildNode); + CoreFreePool (NewStreamBuffer); + return Status; + } + } else { + // + // There's no GUIDed section extraction protocol available. + // + if (GuidedHeader->Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) { + // + // If the section REQUIRES an extraction protocol, then we're toast + // + CoreFreePool (*ChildNode); + return EFI_PROTOCOL_ERROR; + } + + // + // Figure out the proper authentication status + // + AuthenticationStatus = Stream->AuthenticationStatus; + if (GuidedHeader->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) { + // + // The local status of the new stream is contained in + // AuthenticaionStatus. This value needs to be ORed into the + // Aggregate bits also... + // + + // + // Clear out and initialize the local status + // + AuthenticationStatus &= ~EFI_LOCAL_AUTH_STATUS_ALL; + AuthenticationStatus |= EFI_LOCAL_AUTH_STATUS_IMAGE_SIGNED | EFI_LOCAL_AUTH_STATUS_NOT_TESTED; + // + // OR local status into aggregate status + // + AuthenticationStatus |= AuthenticationStatus >> 16; + } + + SectionLength = SECTION_SIZE (GuidedHeader); + Status = OpenSectionStreamEx ( + SectionLength - GuidedHeader->DataOffset, + (UINT8 *) GuidedHeader + GuidedHeader->DataOffset, + TRUE, + AuthenticationStatus, + &Node->EncapsulatedStreamHandle + ); + if (EFI_ERROR (Status)) { + CoreFreePool (Node); + return Status; + } + } + + if ((AuthenticationStatus & EFI_LOCAL_AUTH_STATUS_ALL) == + (EFI_LOCAL_AUTH_STATUS_IMAGE_SIGNED | EFI_LOCAL_AUTH_STATUS_NOT_TESTED)) { + // + // Need to register for RPN for when the required GUIDed extraction + // protocol becomes available. This will enable us to refresh the + // AuthenticationStatus cached in the Stream if it's ever requested + // again. + // + CreateGuidedExtractionRpnEvent (Stream, Node); + } + + break; + + default: + + // + // Nothing to do if it's a leaf + // + break; + } + + // + // Last, add the new child node to the stream + // + InsertTailList (&Stream->Children, &Node->Link); + + return EFI_SUCCESS; +} + + +STATIC +VOID +CreateGuidedExtractionRpnEvent ( + IN CORE_SECTION_STREAM_NODE *ParentStream, + IN CORE_SECTION_CHILD_NODE *ChildNode + ) +/*++ + +Routine Description: + Worker function. Constructor for RPN event if needed to keep AuthenticationStatus + cache correct when a missing GUIDED_SECTION_EXTRACTION_PROTOCOL appears... + +Arguments: + ParentStream - Indicates the parent of the ecnapsulation section (child) + ChildNode - Indicates the child node that is the encapsulation section. + +Returns: + None + +--*/ +{ + RPN_EVENT_CONTEXT *Context; + + // + // Allocate new event structure and context + // + Context = CoreAllocateBootServicesPool (sizeof (RPN_EVENT_CONTEXT)); + ASSERT (Context != NULL); + + Context->ChildNode = ChildNode; + Context->ParentStream = ParentStream; + + Context->Event = CoreCreateProtocolNotifyEvent ( + Context->ChildNode->EncapsulationGuid, + EFI_TPL_NOTIFY, + NotifyGuidedExtraction, + Context, + &Context->Registration, + FALSE + ); +} + + +STATIC +VOID +EFIAPI +NotifyGuidedExtraction ( + IN EFI_EVENT Event, + IN VOID *RpnContext + ) +/*++ + +Routine Description: + RPN callback function. Removes a stale section stream and re-initializes it + with an updated AuthenticationStatus. + +Arguments: + Event - The event that fired + RpnContext - A pointer to the context that allows us to identify + the relevent encapsulation... + +Returns: + None + +--*/ +{ + EFI_STATUS Status; + EFI_GUID_DEFINED_SECTION *GuidedHeader; + EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *GuidedExtraction; + VOID *NewStreamBuffer; + UINTN NewStreamBufferSize; + UINT32 AuthenticationStatus; + RPN_EVENT_CONTEXT *Context; + + Context = RpnContext; + + Status = CloseSectionStream (&mSectionExtraction, Context->ChildNode->EncapsulatedStreamHandle); + if (!EFI_ERROR (Status)) { + // + // The stream closed successfully, so re-open the stream with correct AuthenticationStatus + // + + GuidedHeader = (EFI_GUID_DEFINED_SECTION *) + (Context->ParentStream->StreamBuffer + Context->ChildNode->OffsetInStream); + ASSERT (GuidedHeader->CommonHeader.Type == EFI_SECTION_GUID_DEFINED); + + Status = CoreLocateProtocol (Context->ChildNode->EncapsulationGuid, NULL, (VOID **)&GuidedExtraction); + ASSERT_EFI_ERROR (Status); + + + Status = GuidedExtraction->ExtractSection ( + GuidedExtraction, + GuidedHeader, + &NewStreamBuffer, + &NewStreamBufferSize, + &AuthenticationStatus + ); + ASSERT_EFI_ERROR (Status); + // + // OR in the parent stream's aggregagate status. + // + AuthenticationStatus |= Context->ParentStream->AuthenticationStatus & EFI_AGGREGATE_AUTH_STATUS_ALL; + Status = OpenSectionStreamEx ( + NewStreamBufferSize, + NewStreamBuffer, + FALSE, + AuthenticationStatus, + &Context->ChildNode->EncapsulatedStreamHandle + ); + ASSERT_EFI_ERROR (Status); + } + + // + // If above, the stream did not close successfully, it indicates it's + // alread been closed by someone, so just destroy the event and be done with + // it. + // + + CoreCloseEvent (Event); + CoreFreePool (Context); +} + + +STATIC +VOID +FreeChildNode ( + IN CORE_SECTION_CHILD_NODE *ChildNode + ) +/*++ + +Routine Description: + Worker function. Destructor for child nodes. + +Arguments: + ChildNode - Indicates the node to destroy + +Returns: + none + +--*/ +{ + 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 (&mSectionExtraction, ChildNode->EncapsulatedStreamHandle); + } + // + // Last, free the child node itself + // + CoreFreePool (ChildNode); +} + + +STATIC +EFI_STATUS +OpenSectionStreamEx ( + IN UINTN SectionStreamLength, + IN VOID *SectionStream, + IN BOOLEAN AllocateBuffer, + IN UINT32 AuthenticationStatus, + OUT UINTN *SectionStreamHandle + ) +/*++ + + Routine Description: + Worker function. Constructor for section streams. + + Arguments: + SectionStreamLength - Size in bytes of the section stream. + SectionStream - Buffer containing the new section stream. + 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. + SectionStreamHandle - A pointer to a caller allocated section stream handle. + + Returns: + EFI_SUCCESS - Stream was added to stream database. + EFI_OUT_OF_RESOURCES - memory allocation failed. + +--*/ +{ + CORE_SECTION_STREAM_NODE *NewStream; + EFI_TPL OldTpl; + + // + // Allocate a new stream + // + NewStream = CoreAllocateBootServicesPool (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 = CoreAllocateBootServicesPool (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 (EFI_TPL_NOTIFY); + InsertTailList (&mStreamRoot, &NewStream->Link); + CoreRestoreTpl (OldTpl); + + *SectionStreamHandle = NewStream->StreamHandle; + + return EFI_SUCCESS; +} + + +STATIC +EFI_STATUS +FindStreamNode ( + IN UINTN SearchHandle, + OUT CORE_SECTION_STREAM_NODE **FoundStream + ) +/*++ + + Routine Description: + Worker function. Search stream database for requested stream handle. + + Arguments: + SearchHandle - Indicates which stream to look for. + FoundStream - Output pointer to the found stream. + + Returns: + EFI_SUCCESS - StreamHandle was found and *FoundStream contains + the stream node. + EFI_NOT_FOUND - SearchHandle was not found in the stream database. + +--*/ +{ + 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; +} + + +STATIC +BOOLEAN +IsValidSectionStream ( + IN VOID *SectionStream, + IN UINTN SectionStreamLength + ) +/*++ + +Routine Description: + Check if a stream is valid. + +Arguments: + SectionStream - The section stream to be checked + SectionStreamLength - The length of section stream + +Returns: + TRUE + FALSE + +--*/ +{ + 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) { + 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 = (EFI_COMMON_SECTION_HEADER *) ((UINTN) SectionHeader + 3); + NextSectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINTN) NextSectionHeader & ~(UINTN)3); + TotalLength += (UINTN) NextSectionHeader - (UINTN) SectionHeader; + SectionHeader = NextSectionHeader; + } + + ASSERT (FALSE); + return FALSE; +} diff --git a/EdkModulePkg/Core/Dxe/build.xml b/EdkModulePkg/Core/Dxe/build.xml new file mode 100644 index 0000000000..1041d64072 --- /dev/null +++ b/EdkModulePkg/Core/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Core/Dxe/exec.h b/EdkModulePkg/Core/Dxe/exec.h new file mode 100644 index 0000000000..e7b0f7b660 --- /dev/null +++ b/EdkModulePkg/Core/Dxe/exec.h @@ -0,0 +1,209 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + exec.h + +Abstract: + + EFI Event support + +--*/ + +#ifndef _EXEC_H_ +#define _EXEC_H_ + +#define VALID_TPL(a) ((a) <= EFI_TPL_HIGH_LEVEL) + +// +// EFI_EVENT +// + + + +#define EVENT_SIGNATURE EFI_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; + BOOLEAN ExFlag; + + // + // A list of all runtime events + // + LIST_ENTRY RuntimeLink; + + // + // Information by event type + // + + union { + // + // For timer events + // + struct { + LIST_ENTRY Link; + UINT64 TriggerTime; + UINT64 Period; + } Timer; + } u; + +} IEVENT; + +// +// Internal prototypes +// + +VOID +CoreDispatchEventNotifies ( + IN EFI_TPL Priority + ) +/*++ + +Routine Description: + + Dispatches all pending events. + +Arguments: + + Priority - The task priority level of event notifications to dispatch + +Returns: + + None + +--*/ +; + + +UINTN +CoreHighestSetBit ( + IN UINTN Number + ) +/*++ + +Routine Description: + + Return the highest set bit + +Arguments: + + Number - The value to check + +Returns: + + Bit position of the highest set bit + +--*/ +; + + +BOOLEAN +GetInterruptState ( + VOID + ) +/*++ + +Routine Description: + + Disables CPU interrupts. + +Arguments: + + This - Protocol instance structure + + State - Pointer to the CPU's current interrupt state + +Returns: + + EFI_SUCCESS - If interrupts were disabled in the CPU. + + EFI_INVALID_PARAMETER - State is NULL. + +--*/ +; + +// +// Exported functions +// + +VOID +CoreEventVirtualAddressFixup ( + VOID + ) +/*++ + +Routine Description: + + A function out of date, should be removed. + +Arguments: + + None + +Returns: + + None + +--*/ +; + + +VOID +CoreInitializeTimer ( + VOID + ) +/*++ + +Routine Description: + + Initializes timer support + +Arguments: + + None + +Returns: + + None + +--*/ +; + +// +// extern data declarations +// + +extern EFI_LOCK gEventQueueLock; +extern UINTN gEventPending; +extern LIST_ENTRY gEventQueue[]; +extern LIST_ENTRY gEventSignalQueue; +extern UINT8 gHSB[]; +extern LIST_ENTRY mRuntimeEventList; + +#endif diff --git a/EdkModulePkg/Core/Dxe/gcd.h b/EdkModulePkg/Core/Dxe/gcd.h new file mode 100644 index 0000000000..445821e913 --- /dev/null +++ b/EdkModulePkg/Core/Dxe/gcd.h @@ -0,0 +1,51 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + gcd.h + +Abstract: + +Revision History + +--*/ + +#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_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/EdkModulePkg/Core/Dxe/hand.h b/EdkModulePkg/Core/Dxe/hand.h new file mode 100644 index 0000000000..c61af16234 --- /dev/null +++ b/EdkModulePkg/Core/Dxe/hand.h @@ -0,0 +1,337 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + hand.h + +Abstract: + + EFI internal protocol definitions + + + +Revision History + +--*/ + +#ifndef _HAND_H_ +#define _HAND_H_ + + +// +// IHANDLE - contains a list of protocol handles +// + +#define EFI_HANDLE_SIGNATURE EFI_SIGNATURE_32('h','n','d','l') +typedef struct { + UINTN Signature; + LIST_ENTRY AllHandles; // All handles list of IHANDLE + LIST_ENTRY Protocols; // List of PROTOCOL_INTERFACE's for this handle + UINTN LocateRequest; // + UINT64 Key; // The Handle Database Key value when this handle was last created or modified +} IHANDLE; + +#define ASSERT_IS_HANDLE(a) ASSERT((a)->Signature == EFI_HANDLE_SIGNATURE) + + +// +// 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. +// + +#define PROTOCOL_ENTRY_SIGNATURE EFI_SIGNATURE_32('p','r','t','e') +typedef struct { + UINTN Signature; + LIST_ENTRY AllEntries; // All entries + EFI_GUID ProtocolID; // ID of the protocol + LIST_ENTRY Protocols; // All protocol interfaces + LIST_ENTRY Notify; // Registerd notification handlers +} PROTOCOL_ENTRY; + +// +// PROTOCOL_INTERFACE - each protocol installed on a handle is tracked +// with a protocol interface structure +// + +#define PROTOCOL_INTERFACE_SIGNATURE EFI_SIGNATURE_32('p','i','f','c') +typedef struct { + UINTN Signature; + EFI_HANDLE Handle; // Back pointer + LIST_ENTRY Link; // Link on IHANDLE.Protocols + LIST_ENTRY ByProtocol; // Link on PROTOCOL_ENTRY.Protocols + PROTOCOL_ENTRY *Protocol; // The protocol ID + VOID *Interface; // The interface value + + LIST_ENTRY OpenList; // OPEN_PROTOCOL_DATA list. + UINTN OpenListCount; + + EFI_HANDLE ControllerHandle; + +} PROTOCOL_INTERFACE; + +#define OPEN_PROTOCOL_DATA_SIGNATURE EFI_SIGNATURE_32('p','o','d','l') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + EFI_HANDLE AgentHandle; + EFI_HANDLE ControllerHandle; + UINT32 Attributes; + UINT32 OpenCount; +} OPEN_PROTOCOL_DATA; + + +// +// PROTOCOL_NOTIFY - used for each register notification for a protocol +// + +#define PROTOCOL_NOTIFY_SIGNATURE EFI_SIGNATURE_32('p','r','t','n') +typedef struct { + UINTN Signature; + PROTOCOL_ENTRY *Protocol; + LIST_ENTRY Link; // All notifications for this protocol + EFI_EVENT Event; // Event to notify + LIST_ENTRY *Position; // Last position notified +} PROTOCOL_NOTIFY; + +// +// Internal prototypes +// + + +PROTOCOL_ENTRY * +CoreFindProtocolEntry ( + IN EFI_GUID *Protocol, + IN BOOLEAN Create + ) +/*++ + +Routine Description: + + Finds the protocol entry for the requested protocol. + + The gProtocolDatabaseLock must be owned + +Arguments: + + Protocol - The ID of the protocol + + Create - Create a new entry if not found + +Returns: + + Protocol entry + +--*/ +; + +VOID +CoreNotifyProtocolEntry ( + IN PROTOCOL_ENTRY *ProtEntry + ) +/*++ + +Routine Description: + + Signal event for every protocol in protocol entry. + +Arguments: + + ProtEntry - Protocol entry + +Returns: + +--*/ +; + +PROTOCOL_INTERFACE * +CoreFindProtocolInterface ( + IN IHANDLE *Handle, + IN EFI_GUID *Protocol, + IN VOID *Interface + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + Handle - The handle to search the protocol on + + Protocol - GUID of the protocol + + Interface - The interface for the protocol being searched + +Returns: + + Protocol instance (NULL: Not found) + +--*/ +; + +PROTOCOL_INTERFACE * +CoreRemoveInterfaceFromProtocol ( + IN IHANDLE *Handle, + IN EFI_GUID *Protocol, + IN VOID *Interface + ) +/*++ + +Routine Description: + + Removes Protocol from the protocol list (but not the handle list). + +Arguments: + + Handle - The handle to remove protocol on. + + Protocol - GUID of the protocol to be moved + + Interface - The interface of the protocol + +Returns: + + Protocol Entry + +--*/ +; + +EFI_STATUS +CoreUnregisterProtocolNotify ( + IN EFI_EVENT Event + ) +/*++ + +Routine Description: + + Removes all the events in the protocol database that match Event. + +Arguments: + + Event - The event to search for in the protocol database. + +Returns: + + EFI_SUCCESS when done searching the entire database. + +--*/ +; + +EFI_STATUS +CoreDisconnectControllersUsingProtocolInterface ( + IN EFI_HANDLE UserHandle, + IN PROTOCOL_INTERFACE *Prot + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + UserHandle - The handle on which the protocol is installed + Prot - The protocol to disconnect drivers from + +Returns: + + EFI_SUCCESS - Drivers using the protocol interface are all disconnected + EFI_ACCESS_DENIED - Failed to disconnect one or all of the drivers + +--*/ +; + +VOID +CoreAcquireProtocolLock ( + VOID + ) +/*++ + +Routine Description: + + Acquire lock on gProtocolDatabaseLock. + +Arguments: + + None + +Returns: + + None + +--*/ +; + +VOID +CoreReleaseProtocolLock ( + VOID + ) +/*++ + +Routine Description: + + Release lock on gProtocolDatabaseLock. + +Arguments: + + None + +Returns: + + None + +--*/ +; + +EFI_STATUS +CoreValidateHandle ( + IN EFI_HANDLE UserHandle + ) +/*++ + +Routine Description: + + Check whether a handle is a valid EFI_HANDLE + +Arguments: + + UserHandle - The handle to check + +Returns: + + EFI_INVALID_PARAMETER - The handle is NULL or not a valid EFI_HANDLE. + + EFI_SUCCESS - The handle is valid EFI_HANDLE. + +--*/ +; + +// +// Externs +// + +extern EFI_LOCK gProtocolDatabaseLock; +extern LIST_ENTRY gHandleList; +extern UINT64 gHandleDatabaseKey; + +#endif diff --git a/EdkModulePkg/Core/Dxe/imem.h b/EdkModulePkg/Core/Dxe/imem.h new file mode 100644 index 0000000000..e1f8215eb7 --- /dev/null +++ b/EdkModulePkg/Core/Dxe/imem.h @@ -0,0 +1,227 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + imem.h + +Abstract: + + Head file to imem.h + + +Revision History + +--*/ + +#ifndef _IMEM_H_ +#define _IMEM_H_ + +#if defined (MDE_CPU_IPF) +// +// For Itanium machines make the default allocations 8K aligned +// +#define EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT (EFI_PAGE_SIZE * 2) +#define DEFAULT_PAGE_ALLOCATION (EFI_PAGE_SIZE * 2) + +#else +// +// For genric EFI machines make the default allocations 4K aligned +// +#define EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT (EFI_PAGE_SIZE) +#define DEFAULT_PAGE_ALLOCATION (EFI_PAGE_SIZE) + +#endif + + +// +// MEMORY_MAP_ENTRY +// + +#define MEMORY_MAP_SIGNATURE EFI_SIGNATURE_32('m','m','a','p') +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + BOOLEAN FromPool; + + EFI_MEMORY_TYPE Type; + UINT64 Start; + UINT64 End; + + UINT64 VirtualStart; + UINT64 Attribute; +} MEMORY_MAP; + +// +// Internal prototypes +// + +VOID * +CoreAllocatePoolPages ( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN NumberOfPages, + IN UINTN Alignment + ) +/*++ + +Routine Description: + + Internal function. Used by the pool functions to allocate pages + to back pool allocation requests. + +Arguments: + + PoolType - The type of memory for the new pool pages + + NumberOfPages - No of pages to allocate + + Alignment - Bits to align. + +Returns: + + The allocated memory, or NULL + +--*/ +; + + +VOID +CoreFreePoolPages ( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN NumberOfPages + ) +/*++ + +Routine Description: + + Internal function. Frees pool pages allocated via AllocatePoolPages () + +Arguments: + + Memory - The base address to free + + NumberOfPages - The number of pages to free + +Returns: + + None + +--*/ +; + + +VOID * +CoreAllocatePoolI ( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN Size + ) +/*++ + +Routine Description: + + Internal function to allocate pool of a particular type. + + Caller must have the memory lock held + + +Arguments: + + PoolType - Type of pool to allocate + + Size - The amount of pool to allocate + +Returns: + + The allocate pool, or NULL + +--*/ +; + + +EFI_STATUS +CoreFreePoolI ( + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Internal function to free a pool entry. + + Caller must have the memory lock held + + +Arguments: + + Buffer - The allocated pool entry to free + +Returns: + + EFI_INVALID_PARAMETER - Buffer not valid + + EFI_SUCCESS - Buffer successfully freed. + +--*/ +; + + +VOID +CoreAcquireMemoryLock ( + VOID + ) +/*++ + +Routine Description: + + Enter critical section by gaining lock on gMemoryLock + +Arguments: + + None + +Returns: + + None + +--*/ +; + +VOID +CoreReleaseMemoryLock ( + VOID + ) +/*++ + +Routine Description: + + Exit critical section by releasing lock on gMemoryLock + +Arguments: + + None + +Returns: + + None + +--*/ +; + + +// +// Internal Global data +// + +extern EFI_LOCK gMemoryLock; +extern LIST_ENTRY gMemoryMap; +extern MEMORY_MAP *gMemoryLastConvert; +extern LIST_ENTRY mGcdMemorySpaceMap; +#endif diff --git a/EdkModulePkg/Core/DxeIplPeim/DxeIpl.dxs b/EdkModulePkg/Core/DxeIplPeim/DxeIpl.dxs new file mode 100644 index 0000000000..6370d86cbf --- /dev/null +++ b/EdkModulePkg/Core/DxeIplPeim/DxeIpl.dxs @@ -0,0 +1,29 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DxeIpl.dxs + +Abstract: + + Dependency expression file for DXE Initial Program Loader PEIM. + +--*/ + +#include +#include + +DEPENDENCY_START + EFI_PEI_PERMANENT_MEMORY_INSTALLED_PPI_GUID +DEPENDENCY_END + + diff --git a/EdkModulePkg/Core/DxeIplPeim/DxeIpl.h b/EdkModulePkg/Core/DxeIplPeim/DxeIpl.h new file mode 100644 index 0000000000..bc50666df6 --- /dev/null +++ b/EdkModulePkg/Core/DxeIplPeim/DxeIpl.h @@ -0,0 +1,146 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DxeIpl.h + +Abstract: + +--*/ + +#ifndef __PEI_DXEIPL_H__ +#define __PEI_DXEIPL_H__ + +#define STACK_SIZE 0x20000 +#define BSP_STORE_SIZE 0x4000 + +extern BOOLEAN gInMemory; + +VOID +SwitchIplStacks ( + VOID *EntryPoint, + UINTN Parameter1, + UINTN Parameter2, + VOID *NewStack, + VOID *NewBsp + ) +; + +EFI_STATUS +PeiFindFile ( + IN UINT8 Type, + IN UINT16 SectionType, + OUT EFI_GUID *FileName, + OUT VOID **Pe32Data + ) +; + +EFI_STATUS +PeiLoadFile ( + IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader, + IN VOID *Pe32Data, + OUT EFI_PHYSICAL_ADDRESS *ImageAddress, + OUT UINT64 *ImageSize, + OUT EFI_PHYSICAL_ADDRESS *EntryPoint + ) +; + + +EFI_STATUS +CreateArchSpecificHobs ( + OUT EFI_PHYSICAL_ADDRESS *BspStore + ) +; + +EFI_STATUS +GetImageReadFunction ( + IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +; + +EFI_STATUS +PeiImageRead ( + IN VOID *FileHandle, + IN UINTN FileOffset, + IN OUT UINTN *ReadSize, + OUT VOID *Buffer + ) +; + +EFI_STATUS +EFIAPI +DxeIplLoadFile ( + IN EFI_PEI_FV_FILE_LOADER_PPI *This, + IN EFI_FFS_FILE_HEADER *FfsHeader, + OUT EFI_PHYSICAL_ADDRESS *ImageAddress, + OUT UINT64 *ImageSize, + OUT EFI_PHYSICAL_ADDRESS *EntryPoint + ); + +EFI_STATUS +ShadowDxeIpl ( + IN EFI_FFS_FILE_HEADER *DxeIpl, + IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader + ); + +EFI_STATUS +EFIAPI +DxeLoadCore ( + IN EFI_DXE_IPL_PPI *This, + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_HOB_POINTERS HobList + ); + +EFI_STATUS +PeiProcessFile ( + IN UINT16 SectionType, + IN EFI_FFS_FILE_HEADER *FfsFileHeader, + OUT VOID **Pe32Data + ); + +EFI_STATUS +EFIAPI +PeimInitializeDxeIpl ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices + ); + +EFI_STATUS +PeiLoadx64File ( + IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader, + IN VOID *Pe32Data, + IN EFI_MEMORY_TYPE MemoryType, + OUT EFI_PHYSICAL_ADDRESS *ImageAddress, + OUT UINT64 *ImageSize, + OUT EFI_PHYSICAL_ADDRESS *EntryPoint + ) +; + +EFI_PHYSICAL_ADDRESS +CreateIdentityMappingPageTables ( + IN UINT32 NumberOfProcessorPhysicalAddressBits + ) +; + +VOID +ActivateLongMode ( + IN EFI_PHYSICAL_ADDRESS PageTables, + IN EFI_PHYSICAL_ADDRESS HobStart, + IN EFI_PHYSICAL_ADDRESS Stack, + IN EFI_PHYSICAL_ADDRESS CodeEntryPoint1, + IN EFI_PHYSICAL_ADDRESS CodeEntryPoint2 + ); + +VOID +LoadGo64Gdt(); + +#endif diff --git a/EdkModulePkg/Core/DxeIplPeim/DxeIpl.mbd b/EdkModulePkg/Core/DxeIplPeim/DxeIpl.mbd new file mode 100644 index 0000000000..a604fccf08 --- /dev/null +++ b/EdkModulePkg/Core/DxeIplPeim/DxeIpl.mbd @@ -0,0 +1,63 @@ + + + + + DxeIpl + 86D70125-BAA3-4296-A62F-602BEBBB9081 + EDK_RELEASE_VERSION 0x00020000 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-22 18:54 + + + PeimEntryPoint + PeiMemoryLib + PeiCoreLib + PeiServicesTablePointerLib + PeiHobLib + BaseCacheMaintenanceLib + BaseUefiTianoDecompressLib + BaseCustomDecompressLibNull + PeiReportStatusCodeLib + BaseDebugLibReportStatusCode + BaseLib + PeiMemoryAllocationLib + + EdkPeCoffLoaderLib + BasePeCoffLib + + + EdkPeCoffLoaderLib + BasePeCoffLib + + + EdkPeCoffLoaderLib + BasePeCoffLib + + + EdkPeCoffLoaderLib + BasePeCoffLib + + + + _ModuleEntryPoint + + diff --git a/EdkModulePkg/Core/DxeIplPeim/DxeIpl.msa b/EdkModulePkg/Core/DxeIplPeim/DxeIpl.msa new file mode 100644 index 0000000000..7d7d531cca --- /dev/null +++ b/EdkModulePkg/Core/DxeIplPeim/DxeIpl.msa @@ -0,0 +1,129 @@ + + + + + DxeIpl + PEIM + PE32_PEIM + 86D70125-BAA3-4296-A62F-602BEBBB9081 + EDK_RELEASE_VERSION 0x00020000 + Component description file for DxeIpl module + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + EFI_SPECIFICATION_VERSION 0x00000000 + 2006-03-12 17:09 + 2006-03-22 18:54 + + + DebugLib + PeimEntryPoint + BaseLib + HobLib + PerformanceLib + PeiCoreLib + ReportStatusCodeLib + CacheMaintenanceLib + EdkPeCoffLoaderLib + UefiDecompressLib + TianoDecompressLib + CustomDecompressLib + PeiServicesTablePointerLib + BaseMemoryLib + MemoryAllocationLib + + + DxeLoad.c + DxeIpl.dxs + + ia32\ImageRead.c + ia32\DxeLoadFunc.c + + + ia32\ImageRead.c + ia32\DxeLoadFunc.c + + + ipf\ImageRead.c + ipf\DxeLoadFunc.c + + + ia32\ImageRead.c + ia32\DxeLoadFunc.c + + + + MdePkg + EdkModulePkg + + + Decompress + TianoDecompress + CustomizedDecompress + + + + gEfiHobMemoryAllocBspStoreGuid + 0x564b33cd, 0xc92a, 0x4593, 0x90, 0xbf, 0x24, 0x73, 0xe4, 0x3c, 0x63, 0x22 + + + gEfiDecompressProtocolGuid + 0xd8117cfe, 0x94a6, 0x11d4, 0x9a, 0x3a, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d + + + gEfiTianoDecompressProtocolGuid + 0xe84cf29c, 0x191f, 0x4eae, 0x96, 0xe1, 0xf4, 0x6a, 0xec, 0xea, 0xea, 0x0b + + + gEfiCustomizedDecompressProtocolGuid + 0x9a44198e, 0xa4a2, 0x44e6, 0x8a, 0x1f, 0x39, 0xbe, 0xfd, 0xac, 0x89, 0x6f + + + gEfiPeiPeCoffLoaderGuid + 0xd8117cff, 0x94a6, 0x11d4, 0x9a, 0x3a, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d + + + gEfiHobMemoryAllocModuleGuid + 0xf8e21975, 0x0899, 0x4f58, 0xa4, 0xbe, 0x55, 0x25, 0xa9, 0xc6, 0xd7, 0x7a + + + DecompressedFvmain.fv + + + + DxeIpl + FvFileLoader + EndOfPeiSignal + RecoveryModule + S3Resume + SectionExtraction + Security + PeiInMemory + + + + PeiPeCoffLoader + + + + + PeimInitializeDxeIpl + + + diff --git a/EdkModulePkg/Core/DxeIplPeim/DxeIplX64.mbd b/EdkModulePkg/Core/DxeIplPeim/DxeIplX64.mbd new file mode 100644 index 0000000000..2df91ecde8 --- /dev/null +++ b/EdkModulePkg/Core/DxeIplPeim/DxeIplX64.mbd @@ -0,0 +1,49 @@ + + + + + DxeIpl + 86D70125-BAA3-4296-A62F-602BEBBB9081 + EDK_RELEASE_VERSION 0x00020000 + FIX ME! + Copyright 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-04-03 23:58 + + + PeimEntryPoint + PeiMemoryLib + PeiCoreLib + PeiServicesTablePointerLib + PeiHobLib + BaseCacheMaintenanceLib + BaseUefiTianoDecompressLib + BaseCustomDecompressLibNull + PeiReportStatusCodeLib + BaseDebugLibReportStatusCode + BaseLib + PeiMemoryAllocationLib + PeiReportStatusCodeLib + + EdkPeCoffLoaderX64Lib + EdkPeCoffLoaderLib + BasePeCoffLib + + + diff --git a/EdkModulePkg/Core/DxeIplPeim/DxeIplX64.msa b/EdkModulePkg/Core/DxeIplPeim/DxeIplX64.msa new file mode 100644 index 0000000000..df4efbc285 --- /dev/null +++ b/EdkModulePkg/Core/DxeIplPeim/DxeIplX64.msa @@ -0,0 +1,85 @@ + + + + + DxeIpl + PEIM + PE32_PEIM + 86D70125-BAA3-4296-A62F-602BEBBB9081 + EDK_RELEASE_VERSION 0x00020000 + Component description file for DxeIpl module + FIX ME! + Copyright 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + EFI_SPECIFICATION_VERSION 0x00000000 + 2006-04-03 23:58 + + + DebugLib + PeimEntryPoint + BaseLib + HobLib + PerformanceLib + PeiCoreLib + ReportStatusCodeLib + CacheMaintenanceLib + EdkPeCoffLoaderLib + UefiDecompressLib + TianoDecompressLib + CustomDecompressLib + PeiServicesTablePointerLib + BaseMemoryLib + MemoryAllocationLib + EdkPeCoffLoaderX64Lib + + + DxeIpl.dxs + DxeLoadX64.c + + x64\ImageRead.c + x64\LongMode.asm + x64\DxeLoadFunc.c + x64\VirtualMemory.c + + + + MdePkg + EdkModulePkg + + + Decompress + TianoDecompress + CustomizedDecompress + + + PeiInMemory + RecoveryModule + SectionExtraction + Security + DxeIpl + S3Resume + EndOfPeiSignal + FvFileLoader + + + + PeiPeCoffLoader + + + diff --git a/EdkModulePkg/Core/DxeIplPeim/DxeLoad.c b/EdkModulePkg/Core/DxeIplPeim/DxeLoad.c new file mode 100644 index 0000000000..a181095813 --- /dev/null +++ b/EdkModulePkg/Core/DxeIplPeim/DxeLoad.c @@ -0,0 +1,1010 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DxeLoad.c + +Abstract: + + Last PEIM. + Responsibility of this module is to load the DXE Core from a Firmware Volume. + +--*/ + +#include + +BOOLEAN gInMemory = FALSE; + +// +// Module Globals used in the DXE to PEI handoff +// These must be module globals, so the stack can be switched +// +static EFI_DXE_IPL_PPI mDxeIplPpi = { + DxeLoadCore +}; + +static EFI_PEI_FV_FILE_LOADER_PPI mLoadFilePpi = { + DxeIplLoadFile +}; + +static EFI_PEI_PPI_DESCRIPTOR mPpiLoadFile = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiPeiFvFileLoaderPpiGuid, + &mLoadFilePpi +}; + +static EFI_PEI_PPI_DESCRIPTOR mPpiList = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiDxeIplPpiGuid, + &mDxeIplPpi +}; + +static EFI_PEI_PPI_DESCRIPTOR mPpiPeiInMemory = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gPeiInMemoryGuid, + NULL +}; + +static EFI_PEI_PPI_DESCRIPTOR mPpiSignal = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiEndOfPeiSignalPpiGuid, + NULL +}; + +DECOMPRESS_LIBRARY gEfiDecompress = { + UefiDecompressGetInfo, + UefiDecompress +}; + +DECOMPRESS_LIBRARY gTianoDecompress = { + TianoDecompressGetInfo, + TianoDecompress +}; + +DECOMPRESS_LIBRARY gCustomDecompress = { + CustomDecompressGetInfo, + CustomDecompress +}; + +STATIC +UINTN +GetOccupiedSize ( + IN UINTN ActualSize, + IN UINTN Alignment + ) +{ + UINTN OccupiedSize; + + OccupiedSize = ActualSize; + while ((OccupiedSize & (Alignment - 1)) != 0) { + OccupiedSize++; + } + + return OccupiedSize; +} + +EFI_STATUS +EFIAPI +PeimInitializeDxeIpl ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices + ) +/*++ + +Routine Description: + + Initializes the Dxe Ipl PPI + +Arguments: + + FfsHeader - Pointer to FFS file header + PeiServices - General purpose services available to every PEIM. + +Returns: + + EFI_SUCCESS + +--*/ +{ + EFI_STATUS Status; + EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader; + EFI_BOOT_MODE BootMode; + + Status = PeiCoreGetBootMode (&BootMode); + + ASSERT_EFI_ERROR (Status); + + Status = PeiCoreLocatePpi ( + &gPeiInMemoryGuid, + 0, + NULL, + NULL + ); + + if (EFI_ERROR (Status) && (BootMode != BOOT_ON_S3_RESUME)) { + // + // The DxeIpl has not yet been shadowed + // + PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)GetPeCoffLoaderProtocol (); + + // + // Shadow DxeIpl and then re-run its entry point + // + Status = ShadowDxeIpl (FfsHeader, PeiEfiPeiPeCoffLoader); + if (EFI_ERROR (Status)) { + return Status; + } + + } else { + if (BootMode != BOOT_ON_S3_RESUME) { + // + // The DxeIpl has been shadowed + // + gInMemory = TRUE; + + // + // Install LoadFile PPI + // + Status = PeiCoreInstallPpi (&mPpiLoadFile); + + if (EFI_ERROR (Status)) { + return Status; + } + } + // + // Install DxeIpl PPI + // + PeiCoreInstallPpi (&mPpiList); + + if (EFI_ERROR (Status)) { + return Status; + } + + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +DxeLoadCore ( + IN EFI_DXE_IPL_PPI *This, + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_HOB_POINTERS HobList + ) +/*++ + +Routine Description: + + Main entry point to last PEIM + +Arguments: + This - Entry point for DXE IPL PPI + PeiServices - General purpose services available to every PEIM. + HobList - Address to the Pei HOB list + +Returns: + + EFI_SUCCESS - DEX core was successfully loaded. + EFI_OUT_OF_RESOURCES - There are not enough resources to load DXE core. + +--*/ +{ + EFI_STATUS Status; + VOID *TopOfStack; + VOID *BaseOfStack; + EFI_PHYSICAL_ADDRESS BspStore; + EFI_GUID DxeCoreFileName; + EFI_GUID FirmwareFileName; + VOID *Pe32Data; + EFI_PHYSICAL_ADDRESS DxeCoreAddress; + UINT64 DxeCoreSize; + EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint; + EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader; + EFI_BOOT_MODE BootMode; + EFI_PEI_RECOVERY_MODULE_PPI *PeiRecovery; + EFI_PEI_S3_RESUME_PPI *S3Resume; + +// PERF_START (PeiServices, L"DxeIpl", NULL, 0); + TopOfStack = NULL; + BaseOfStack = NULL; + BspStore = 0; + Status = EFI_SUCCESS; + + // + // if in S3 Resume, restore configure + // + Status = PeiCoreGetBootMode (&BootMode); + + if (!EFI_ERROR (Status) && (BootMode == BOOT_ON_S3_RESUME)) { + Status = PeiCoreLocatePpi ( + &gEfiPeiS3ResumePpiGuid, + 0, + NULL, + (VOID **)&S3Resume + ); + + ASSERT_EFI_ERROR (Status); + + Status = S3Resume->S3RestoreConfig (PeiServices); + + ASSERT_EFI_ERROR (Status); + } + + Status = EFI_SUCCESS; + + // + // Install the PEI Protocols that are shared between PEI and DXE + // + PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)GetPeCoffLoaderProtocol (); + ASSERT (PeiEfiPeiPeCoffLoader != NULL); + + + // + // 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 - sizeof (UINTN)); + + // + // Add architecture-specifc HOBs (including the BspStore HOB) + // + Status = CreateArchSpecificHobs (&BspStore); + + ASSERT_EFI_ERROR (Status); + + // + // Add HOB for the EFI Decompress Protocol + // + BuildGuidDataHob ( + &gEfiDecompressProtocolGuid, + (VOID *)&gEfiDecompress, + sizeof (gEfiDecompress) + ); + + // + // Add HOB for the Tiano Decompress Protocol + // + BuildGuidDataHob ( + &gEfiTianoDecompressProtocolGuid, + (VOID *)&gTianoDecompress, + sizeof (gTianoDecompress) + ); + + // + // Add HOB for the user customized Decompress Protocol + // + BuildGuidDataHob ( + &gEfiCustomizedDecompressProtocolGuid, + (VOID *)&gCustomDecompress, + sizeof (gCustomDecompress) + ); + + // + // Add HOB for the PE/COFF Loader Protocol + // + BuildGuidDataHob ( + &gEfiPeiPeCoffLoaderGuid, + (VOID *)&PeiEfiPeiPeCoffLoader, + sizeof (VOID *) + ); + + // + // See if we are in crisis recovery + // + Status = PeiCoreGetBootMode (&BootMode); + + if (!EFI_ERROR (Status) && (BootMode == BOOT_IN_RECOVERY_MODE)) { + + Status = PeiCoreLocatePpi ( + &gEfiPeiRecoveryModulePpiGuid, + 0, + NULL, + (VOID **)&PeiRecovery + ); + + ASSERT_EFI_ERROR (Status); + Status = PeiRecovery->LoadRecoveryCapsule (PeiServices, PeiRecovery); + ASSERT_EFI_ERROR (Status); + + // + // Now should have a HOB with the DXE core w/ the old HOB destroyed + // + } + + // + // Find the EFI_FV_FILETYPE_RAW type compressed Firmware Volume file in FTW spare block + // The file found will be processed by PeiProcessFile: It will first be decompressed to + // a normal FV, then a corresponding FV type hob will be built which is provided for DXE + // core to find and dispatch drivers in this FV. Because PeiProcessFile typically checks + // for EFI_FV_FILETYPE_DXE_CORE type file, in this condition we need not check returned + // status + // + Status = PeiFindFile ( + EFI_FV_FILETYPE_RAW, + EFI_SECTION_PE32, + &FirmwareFileName, + &Pe32Data + ); + + // + // Find the DXE Core in a Firmware Volume + // + Status = PeiFindFile ( + EFI_FV_FILETYPE_DXE_CORE, + EFI_SECTION_PE32, + &DxeCoreFileName, + &Pe32Data + ); + + ASSERT_EFI_ERROR (Status); + + // + // Load the DXE Core from a Firmware Volume + // + Status = PeiLoadFile ( + PeiEfiPeiPeCoffLoader, + Pe32Data, + &DxeCoreAddress, + &DxeCoreSize, + &DxeCoreEntryPoint + ); + + ASSERT_EFI_ERROR (Status); + + // + // Transfer control to the DXE Core + // The handoff state is simply a pointer to the HOB list + // +// PERF_END (PeiServices, L"DxeIpl", NULL, 0); + + Status = PeiCoreInstallPpi (&mPpiSignal); + + ASSERT_EFI_ERROR (Status); + + // + // Add HOB for the DXE Core + // + BuildModuleHob ( + &DxeCoreFileName, + DxeCoreAddress, + DxeCoreSize, + DxeCoreEntryPoint + ); + + // + // Report Status Code EFI_SW_PEI_PC_HANDOFF_TO_NEXT + // + REPORT_STATUS_CODE ( + EFI_PROGRESS_CODE, + EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_CORE_PC_HANDOFF_TO_NEXT + ); + + DEBUG ((EFI_D_INFO, "DXE Core Entry\n")); + SwitchStack ( + (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint, + HobList.Raw, + (VOID *) (UINTN) BspStore, + TopOfStack + ); + + // + // If we get here, then the DXE Core returned. This is an error + // + ASSERT_EFI_ERROR (Status); + + return EFI_OUT_OF_RESOURCES; +} + +EFI_STATUS +PeiFindFile ( + IN UINT8 Type, + IN UINT16 SectionType, + OUT EFI_GUID *FileName, + OUT VOID **Pe32Data + ) +/*++ + +Routine Description: + + Finds a PE/COFF of a specific Type and SectionType in the Firmware Volumes + described in the HOB list. Able to search in a compression set in a FFS file. + But only one level of compression is supported, that is, not able to search + in a compression set that is within another compression set. + +Arguments: + + Type - The Type of file to retrieve + + SectionType - The type of section to retrieve from a file + + FileName - The name of the file found in the Firmware Volume + + Pe32Data - Pointer to the beginning of the PE/COFF file found in the Firmware Volume + +Returns: + + EFI_SUCCESS - The file was found, and the name is returned in FileName, and a pointer to + the PE/COFF image is returned in Pe32Data + + EFI_NOT_FOUND - The file was not found in the Firmware Volumes present in the HOB List + +--*/ +{ + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_FFS_FILE_HEADER *FfsFileHeader; + VOID *SectionData; + EFI_STATUS Status; + EFI_PEI_HOB_POINTERS Hob; + + + FwVolHeader = NULL; + FfsFileHeader = NULL; + SectionData = NULL; + + // + // Foreach Firmware Volume, look for a specified type + // of file and break out when one is found + // + Hob.Raw = GetHobList (); + while ((Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw)) != NULL) { + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (Hob.FirmwareVolume->BaseAddress); + Status = PeiCoreFfsFindNextFile ( + Type, + FwVolHeader, + &FfsFileHeader + ); + if (!EFI_ERROR (Status)) { + CopyMem (FileName, &FfsFileHeader->Name, sizeof (EFI_GUID)); + Status = PeiProcessFile ( + SectionType, + FfsFileHeader, + Pe32Data + ); + return Status; + } + Hob.Raw = GET_NEXT_HOB (Hob); + } + return EFI_NOT_FOUND; +} + +EFI_STATUS +PeiLoadFile ( + IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader, + IN VOID *Pe32Data, + OUT EFI_PHYSICAL_ADDRESS *ImageAddress, + OUT UINT64 *ImageSize, + OUT EFI_PHYSICAL_ADDRESS *EntryPoint + ) +/*++ + +Routine Description: + + Loads and relocates a PE/COFF image into memory. + +Arguments: + + PeiEfiPeiPeCoffLoader - Pointer to a PE COFF loader protocol + + Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated + + ImageAddress - The base address of the relocated PE/COFF image + + ImageSize - The size of the relocated PE/COFF image + + EntryPoint - The entry point of the relocated PE/COFF image + +Returns: + + EFI_SUCCESS - The file was loaded and relocated + + EFI_OUT_OF_RESOURCES - There was not enough memory to load and relocate the PE/COFF file + +--*/ +{ + EFI_STATUS Status; + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + + ZeroMem (&ImageContext, sizeof (ImageContext)); + ImageContext.Handle = Pe32Data; + Status = GetImageReadFunction (&ImageContext); + + ASSERT_EFI_ERROR (Status); + + Status = PeiEfiPeiPeCoffLoader->GetImageInfo (PeiEfiPeiPeCoffLoader, &ImageContext); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Allocate Memory for the image + // + ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize)); + ASSERT (ImageContext.ImageAddress != 0); + + // + // Load the image to our new buffer + // + Status = PeiEfiPeiPeCoffLoader->LoadImage (PeiEfiPeiPeCoffLoader, &ImageContext); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Relocate the image in our new buffer + // + Status = PeiEfiPeiPeCoffLoader->RelocateImage (PeiEfiPeiPeCoffLoader, &ImageContext); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Flush the instruction cache so the image data is written before we execute it + // + InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); + + *ImageAddress = ImageContext.ImageAddress; + *ImageSize = ImageContext.ImageSize; + *EntryPoint = ImageContext.EntryPoint; + + return EFI_SUCCESS; +} + +EFI_STATUS +ShadowDxeIpl ( + IN EFI_FFS_FILE_HEADER *DxeIplFileHeader, + IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader + ) +/*++ + +Routine Description: + + Shadow the DXE IPL to a different memory location. This occurs after permanent + memory has been discovered. + +Arguments: + + DxeIplFileHeader - Pointer to the FFS file header of the DXE IPL driver + + PeiEfiPeiPeCoffLoader - Pointer to a PE COFF loader protocol + +Returns: + + EFI_SUCCESS - DXE IPL was successfully shadowed to a different memory location. + + EFI_ ERROR - The shadow was unsuccessful. + + +--*/ +{ + UINTN SectionLength; + UINTN OccupiedSectionLength; + EFI_PHYSICAL_ADDRESS DxeIplAddress; + UINT64 DxeIplSize; + EFI_PHYSICAL_ADDRESS DxeIplEntryPoint; + EFI_STATUS Status; + EFI_COMMON_SECTION_HEADER *Section; + + Section = (EFI_COMMON_SECTION_HEADER *) (DxeIplFileHeader + 1); + + while ((Section->Type != EFI_SECTION_PE32) && (Section->Type != EFI_SECTION_TE)) { + SectionLength = *(UINT32 *) (Section->Size) & 0x00ffffff; + OccupiedSectionLength = GetOccupiedSize (SectionLength, 4); + Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + OccupiedSectionLength); + } + // + // Relocate DxeIpl into memory by using loadfile service + // + Status = PeiLoadFile ( + PeiEfiPeiPeCoffLoader, + (VOID *) (Section + 1), + &DxeIplAddress, + &DxeIplSize, + &DxeIplEntryPoint + ); + + if (Status == EFI_SUCCESS) { + // + // Install PeiInMemory to indicate the Dxeipl is shadowed + // + Status = PeiCoreInstallPpi (&mPpiPeiInMemory); + + if (EFI_ERROR (Status)) { + return Status; + } + + Status = ((EFI_PEIM_ENTRY_POINT) (UINTN) DxeIplEntryPoint) (DxeIplFileHeader, GetPeiServicesTablePointer()); + } + + return Status; +} + +EFI_STATUS +EFIAPI +DxeIplLoadFile ( + IN EFI_PEI_FV_FILE_LOADER_PPI *This, + IN EFI_FFS_FILE_HEADER *FfsHeader, + OUT EFI_PHYSICAL_ADDRESS *ImageAddress, + OUT UINT64 *ImageSize, + OUT EFI_PHYSICAL_ADDRESS *EntryPoint + ) +/*++ + +Routine Description: + + Given a pointer to an FFS file containing a PE32 image, get the + information on the PE32 image, and then "load" it so that it + can be executed. + +Arguments: + + This - pointer to our file loader protocol + + FfsHeader - pointer to the FFS file header of the FFS file that + contains the PE32 image we want to load + + ImageAddress - returned address where the PE32 image is loaded + + ImageSize - returned size of the loaded PE32 image + + EntryPoint - entry point to the loaded PE32 image + +Returns: + + EFI_SUCCESS - The FFS file was successfully loaded. + + EFI_ERROR - Unable to load the FFS file. + +--*/ +{ + EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader; + EFI_STATUS Status; + VOID *Pe32Data; + + Pe32Data = NULL; + PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)GetPeCoffLoaderProtocol (); + + // + // Preprocess the FFS file to get a pointer to the PE32 information + // in the enclosed PE32 image. + // + Status = PeiProcessFile ( + EFI_SECTION_PE32, + FfsHeader, + &Pe32Data + ); + + if (EFI_ERROR (Status)) { + return Status; + } + // + // Load the PE image from the FFS file + // + Status = PeiLoadFile ( + PeiEfiPeiPeCoffLoader, + Pe32Data, + ImageAddress, + ImageSize, + EntryPoint + ); + + return Status; +} + +EFI_STATUS +PeiProcessFile ( + IN UINT16 SectionType, + IN EFI_FFS_FILE_HEADER *FfsFileHeader, + OUT VOID **Pe32Data + ) +/*++ + +Routine Description: + +Arguments: + + SectionType - The type of section in the FFS file to process. + + FfsFileHeader - Pointer to the FFS file to process, looking for the + specified SectionType + + Pe32Data - returned pointer to the start of the PE32 image found + in the FFS file. + +Returns: + + EFI_SUCCESS - found the PE32 section in the FFS file + +--*/ +{ + EFI_STATUS Status; + VOID *SectionData; + DECOMPRESS_LIBRARY *DecompressLibrary; + UINT8 *DstBuffer; + UINT8 *ScratchBuffer; + UINT32 DstBufferSize; + UINT32 ScratchBufferSize; + EFI_COMMON_SECTION_HEADER *CmpSection; + UINTN CmpSectionLength; + UINTN OccupiedCmpSectionLength; + VOID *CmpFileData; + UINTN CmpFileSize; + EFI_COMMON_SECTION_HEADER *Section; + UINTN SectionLength; + UINTN OccupiedSectionLength; + UINT64 FileSize; + EFI_GUID_DEFINED_SECTION *GuidedSectionHeader; + UINT32 AuthenticationStatus; + EFI_PEI_SECTION_EXTRACTION_PPI *SectionExtract; + UINT32 BufferSize; + UINT8 *Buffer; + EFI_PEI_SECURITY_PPI *Security; + BOOLEAN StartCrisisRecovery; + EFI_GUID TempGuid; + EFI_FIRMWARE_VOLUME_HEADER *FvHeader; + EFI_COMPRESSION_SECTION *CompressionSection; + + Status = PeiCoreFfsFindSectionData ( + EFI_SECTION_COMPRESSION, + FfsFileHeader, + &SectionData + ); + + // + // Upon finding a DXE Core file, see if there is first a compression section + // + if (!EFI_ERROR (Status)) { + // + // Yes, there is a compression section, so extract the contents + // Decompress the image here + // + Section = (EFI_COMMON_SECTION_HEADER *) (UINTN) (VOID *) ((UINT8 *) (FfsFileHeader) + (UINTN) sizeof (EFI_FFS_FILE_HEADER)); + + do { + SectionLength = *(UINT32 *) (Section->Size) & 0x00ffffff; + OccupiedSectionLength = GetOccupiedSize (SectionLength, 4); + + // + // Was the DXE Core file encapsulated in a GUID'd section? + // + if (Section->Type == EFI_SECTION_GUID_DEFINED) { + // + // Locate the GUID'd Section Extractor + // + GuidedSectionHeader = (VOID *) (Section + 1); + + // + // This following code constitutes the addition of the security model + // to the DXE IPL. + // + // + // Set a default authenticatino state + // + AuthenticationStatus = 0; + + Status = PeiCoreLocatePpi ( + &gEfiPeiSectionExtractionPpiGuid, + 0, + NULL, + (VOID **)&SectionExtract + ); + + if (EFI_ERROR (Status)) { + return Status; + } + // + // Verify Authentication State + // + CopyMem (&TempGuid, Section + 1, sizeof (EFI_GUID)); + + Status = SectionExtract->PeiGetSection ( + GetPeiServicesTablePointer(), + SectionExtract, + (EFI_SECTION_TYPE *) &SectionType, + &TempGuid, + 0, + (VOID **) &Buffer, + &BufferSize, + &AuthenticationStatus + ); + + if (EFI_ERROR (Status)) { + return Status; + } + // + // If not ask the Security PPI, if exists, for disposition + // + // + Status = PeiCoreLocatePpi ( + &gEfiPeiSecurityPpiGuid, + 0, + NULL, + (VOID **)&Security + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = Security->AuthenticationState ( + GetPeiServicesTablePointer(), + (struct _EFI_PEI_SECURITY_PPI *) Security, + AuthenticationStatus, + FfsFileHeader, + &StartCrisisRecovery + ); + + if (EFI_ERROR (Status)) { + return Status; + } + // + // If there is a security violation, report to caller and have + // the upper-level logic possible engender a crisis recovery + // + if (StartCrisisRecovery) { + return EFI_SECURITY_VIOLATION; + } + } + + if (Section->Type == EFI_SECTION_PE32) { + // + // This is what we want + // + *Pe32Data = (VOID *) (Section + 1); + return EFI_SUCCESS; + } else if (Section->Type == EFI_SECTION_COMPRESSION) { + // + // This is a compression set, expand it + // + CompressionSection = (EFI_COMPRESSION_SECTION *) Section; + + switch (CompressionSection->CompressionType) { + case EFI_STANDARD_COMPRESSION: + DecompressLibrary = &gTianoDecompress; + break; + + case EFI_CUSTOMIZED_COMPRESSION: + // + // Load user customized compression protocol. + // + DecompressLibrary = &gCustomDecompress; + break; + + case EFI_NOT_COMPRESSED: + default: + // + // Need to support not compressed file + // + ASSERT_EFI_ERROR (Status); + return EFI_NOT_FOUND; + } + + Status = DecompressLibrary->GetInfo ( + (UINT8 *) ((EFI_COMPRESSION_SECTION *) Section + 1), + (UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION), + &DstBufferSize, + &ScratchBufferSize + ); + if (EFI_ERROR (Status)) { + // + // GetInfo failed + // + 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 = DecompressLibrary->Decompress ( + (CHAR8 *) ((EFI_COMPRESSION_SECTION *) Section + 1), + DstBuffer, + ScratchBuffer + ); + + CmpSection = (EFI_COMMON_SECTION_HEADER *) DstBuffer; + if (CmpSection->Type == EFI_SECTION_RAW) { + // + // Skip the section header and + // adjust the pointer alignment to 16 + // + FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (DstBuffer + 16); + + if (FvHeader->Signature == EFI_FVH_SIGNATURE) { + FfsFileHeader = NULL; + BuildFvHob ((EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader, FvHeader->FvLength); + Status = PeiCoreFfsFindNextFile ( + EFI_FV_FILETYPE_DXE_CORE, + FvHeader, + &FfsFileHeader + ); + + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + return PeiProcessFile (SectionType, FfsFileHeader, Pe32Data); + } + } + // + // Decompress successfully. + // Loop the decompressed data searching for expected section. + // + CmpFileData = (VOID *) DstBuffer; + CmpFileSize = DstBufferSize; + do { + CmpSectionLength = *(UINT32 *) (CmpSection->Size) & 0x00ffffff; + if (CmpSection->Type == EFI_SECTION_PE32) { + // + // This is what we want + // + *Pe32Data = (VOID *) (CmpSection + 1); + return EFI_SUCCESS; + } + + OccupiedCmpSectionLength = GetOccupiedSize (CmpSectionLength, 4); + CmpSection = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) CmpSection + OccupiedCmpSectionLength); + } while (CmpSection->Type != 0 && (UINTN) ((UINT8 *) CmpSection - (UINT8 *) CmpFileData) < CmpFileSize); + } + + Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + OccupiedSectionLength); + FileSize = FfsFileHeader->Size[0] & 0xFF; + FileSize += (FfsFileHeader->Size[1] << 8) & 0xFF00; + FileSize += (FfsFileHeader->Size[2] << 16) & 0xFF0000; + FileSize &= 0x00FFFFFF; + } while (Section->Type != 0 && (UINTN) ((UINT8 *) Section - (UINT8 *) FfsFileHeader) < FileSize); + + // + // End of the decompression activity + // + } else { + + Status = PeiCoreFfsFindSectionData ( + EFI_SECTION_PE32, + FfsFileHeader, + &SectionData + ); + + if (EFI_ERROR (Status)) { + Status = PeiCoreFfsFindSectionData ( + EFI_SECTION_TE, + FfsFileHeader, + &SectionData + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + } + + *Pe32Data = SectionData; + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Core/DxeIplPeim/DxeLoadX64.c b/EdkModulePkg/Core/DxeIplPeim/DxeLoadX64.c new file mode 100644 index 0000000000..6727bf4ca7 --- /dev/null +++ b/EdkModulePkg/Core/DxeIplPeim/DxeLoadX64.c @@ -0,0 +1,1018 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DxeLoad.c + +Abstract: + + Last PEIM. + Responsibility of this module is to load the DXE Core from a Firmware Volume. + +--*/ + +#include + +#pragma warning( disable : 4305 ) + +BOOLEAN gInMemory = FALSE; + +// +// GUID for EM64T +// +#define EFI_PPI_NEEDED_BY_DXE \ + { \ + 0x4d37da42, 0x3a0c, 0x4eda, 0xb9, 0xeb, 0xbc, 0x0e, 0x1d, 0xb4, 0x71, 0x3b \ + } +EFI_GUID mPpiNeededByDxeGuid = EFI_PPI_NEEDED_BY_DXE; + +// +// Module Globals used in the DXE to PEI handoff +// These must be module globals, so the stack can be switched +// +static EFI_DXE_IPL_PPI mDxeIplPpi = { + DxeLoadCore +}; + +static EFI_PEI_FV_FILE_LOADER_PPI mLoadFilePpi = { + DxeIplLoadFile +}; + +static EFI_PEI_PPI_DESCRIPTOR mPpiLoadFile = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiPeiFvFileLoaderPpiGuid, + &mLoadFilePpi +}; + +static EFI_PEI_PPI_DESCRIPTOR mPpiList = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiDxeIplPpiGuid, + &mDxeIplPpi +}; + +static EFI_PEI_PPI_DESCRIPTOR mPpiPeiInMemory = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gPeiInMemoryGuid, + NULL +}; + +static EFI_PEI_PPI_DESCRIPTOR mPpiSignal = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiEndOfPeiSignalPpiGuid, + NULL +}; + +DECOMPRESS_LIBRARY gEfiDecompress = { + UefiDecompressGetInfo, + UefiDecompress +}; + +DECOMPRESS_LIBRARY gTianoDecompress = { + TianoDecompressGetInfo, + TianoDecompress +}; + +DECOMPRESS_LIBRARY gCustomDecompress = { + CustomDecompressGetInfo, + CustomDecompress +}; + +STATIC +UINTN +GetOccupiedSize ( + IN UINTN ActualSize, + IN UINTN Alignment + ) +{ + UINTN OccupiedSize; + + OccupiedSize = ActualSize; + while ((OccupiedSize & (Alignment - 1)) != 0) { + OccupiedSize++; + } + + return OccupiedSize; +} + +EFI_STATUS +EFIAPI +PeimInitializeDxeIpl ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices + ) +/*++ + +Routine Description: + + Initializes the Dxe Ipl PPI + +Arguments: + + FfsHeader - Pointer to FFS file header + PeiServices - General purpose services available to every PEIM. + +Returns: + + EFI_SUCCESS + +--*/ +{ + EFI_STATUS Status; + EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader; + EFI_BOOT_MODE BootMode; + + Status = PeiCoreGetBootMode (&BootMode); + + ASSERT_EFI_ERROR (Status); + + Status = PeiCoreLocatePpi ( + &gPeiInMemoryGuid, + 0, + NULL, + NULL + ); + + if (EFI_ERROR (Status) && (BootMode != BOOT_ON_S3_RESUME)) { + // + // The DxeIpl has not yet been shadowed + // + PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)GetPeCoffLoaderProtocol (); + + // + // Shadow DxeIpl and then re-run its entry point + // + Status = ShadowDxeIpl (FfsHeader, PeiEfiPeiPeCoffLoader); + if (EFI_ERROR (Status)) { + return Status; + } + + } else { + if (BootMode != BOOT_ON_S3_RESUME) { + // + // The DxeIpl has been shadowed + // + gInMemory = TRUE; + + // + // Install LoadFile PPI + // + Status = PeiCoreInstallPpi (&mPpiLoadFile); + + if (EFI_ERROR (Status)) { + return Status; + } + } + // + // Install DxeIpl PPI + // + PeiCoreInstallPpi (&mPpiList); + + if (EFI_ERROR (Status)) { + return Status; + } + + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +DxeLoadCore ( + IN EFI_DXE_IPL_PPI *This, + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_HOB_POINTERS HobList + ) +/*++ + +Routine Description: + + Main entry point to last PEIM + +Arguments: + + This - Entry point for DXE IPL PPI + PeiServices - General purpose services available to every PEIM. + HobList - Address to the Pei HOB list + +Returns: + + EFI_SUCCESS - DEX core was successfully loaded. + EFI_OUT_OF_RESOURCES - There are not enough resources to load DXE core. + +--*/ +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS TopOfStack; + EFI_PHYSICAL_ADDRESS BaseOfStack; + EFI_PHYSICAL_ADDRESS BspStore; + EFI_GUID DxeCoreFileName; + VOID *DxeCorePe32Data; + EFI_PHYSICAL_ADDRESS DxeCoreAddress; + UINT64 DxeCoreSize; + EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint; + VOID *PpisNeededByDxePe32Data; + EFI_PHYSICAL_ADDRESS PpisNeededByDxeAddress; + UINT64 PpisNeededByDxeSize; + EFI_PHYSICAL_ADDRESS PpisNeededByDxeEntryPoint; + EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader; + EFI_BOOT_MODE BootMode; + EFI_PEI_RECOVERY_MODULE_PPI *PeiRecovery; + EFI_PEI_S3_RESUME_PPI *S3Resume; + EFI_PHYSICAL_ADDRESS PageTables; + + TopOfStack = 0; + BaseOfStack = 0; + BspStore = 0; + Status = EFI_SUCCESS; + + // + // if in S3 Resume, restore configure + // + Status = PeiCoreGetBootMode (&BootMode); + + if (!EFI_ERROR (Status) && (BootMode == BOOT_ON_S3_RESUME)) { + Status = PeiCoreLocatePpi ( + &gEfiPeiS3ResumePpiGuid, + 0, + NULL, + (VOID **)&S3Resume + ); + + ASSERT_EFI_ERROR (Status); + + Status = S3Resume->S3RestoreConfig (PeiServices); + + ASSERT_EFI_ERROR (Status); + } + + Status = EFI_SUCCESS; + + // + // Install the PEI Protocols that are shared between PEI and DXE + // +#ifdef EFI_NT_EMULATOR + PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)GetPeCoffLoaderProtocol (); + ASSERT (PeiEfiPeiPeCoffLoader != NULL); +#else + PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)GetPeCoffLoaderX64Protocol (); +#endif + +#if 0 + Status = InstallEfiPeiPeCoffLoader64 (PeiServices, &PeiEfiPeiPeCoffLoader, NULL); + ASSERT_EFI_ERROR (Status); +#endif + // + // Allocate 128KB for the Stack + // + PeiCoreAllocatePages (EfiBootServicesData, EFI_SIZE_TO_PAGES (STACK_SIZE), &BaseOfStack); + ASSERT (BaseOfStack != 0); + + // + // Compute the top of the stack we were allocated. Pre-allocate a 32 bytes + // for safety (PpisNeededByDxe and DxeCore). + // + TopOfStack = BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - 32; + + // + // Add architecture-specifc HOBs (including the BspStore HOB) + // + Status = CreateArchSpecificHobs (&BspStore); + ASSERT_EFI_ERROR (Status); + + // + // See if we are in crisis recovery + // + Status = PeiCoreGetBootMode (&BootMode); + if (!EFI_ERROR (Status) && (BootMode == BOOT_IN_RECOVERY_MODE)) { + Status = PeiCoreLocatePpi ( + &gEfiPeiRecoveryModulePpiGuid, + 0, + NULL, + (VOID **)&PeiRecovery + ); + + ASSERT_EFI_ERROR (Status); + Status = PeiRecovery->LoadRecoveryCapsule (PeiServices, PeiRecovery); + ASSERT_EFI_ERROR (Status); + } + + // + // Find the DXE Core in a Firmware Volume + // + Status = PeiFindFile ( + EFI_FV_FILETYPE_DXE_CORE, + EFI_SECTION_PE32, + &DxeCoreFileName, + &DxeCorePe32Data + ); + ASSERT_EFI_ERROR (Status); + + // + // Find the PpisNeededByDxe in a Firmware Volume + // + Status = PeiFindFile ( + EFI_FV_FILETYPE_ALL, + EFI_SECTION_PE32, + &mPpiNeededByDxeGuid, + &PpisNeededByDxePe32Data + ); + ASSERT_EFI_ERROR (Status); + + // + // Transfer control to the DXE Core + // The handoff state is simply a pointer to the HOB list + // + // PEI_PERF_END (PeiServices, L"DxeIpl", NULL, 0); + + Status = PeiCoreInstallPpi (&mPpiSignal); + ASSERT_EFI_ERROR (Status); + + // + // 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 + LoadGo64Gdt(); + + // + // Limit to 36 bits of addressing for debug. Should get it from CPU + // + PageTables = CreateIdentityMappingPageTables (36); + + // + // Load the PpiNeededByDxe from a Firmware Volume + // + Status = PeiLoadx64File ( + PeiEfiPeiPeCoffLoader, + PpisNeededByDxePe32Data, + EfiBootServicesData, + &PpisNeededByDxeAddress, + &PpisNeededByDxeSize, + &PpisNeededByDxeEntryPoint + ); + ASSERT_EFI_ERROR (Status); + + + // + // Load the DXE Core from a Firmware Volume + // + Status = PeiLoadx64File ( + PeiEfiPeiPeCoffLoader, + DxeCorePe32Data, + EfiBootServicesData, + &DxeCoreAddress, + &DxeCoreSize, + &DxeCoreEntryPoint + ); + ASSERT_EFI_ERROR (Status); + + // + // + // Add HOB for the DXE Core + // + BuildModuleHob ( + &DxeCoreFileName, + DxeCoreAddress, + DxeCoreSize, + DxeCoreEntryPoint + ); + + // + // Report Status Code EFI_SW_PEI_PC_HANDOFF_TO_NEXT + // + REPORT_STATUS_CODE ( + EFI_PROGRESS_CODE, + EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_CORE_PC_HANDOFF_TO_NEXT + ); + + DEBUG ((EFI_D_INFO, "DXE Core Entry\n")); + // + // Go to Long Mode. Interrupts will not get turned on until the CPU AP is loaded. + // Call x64 drivers passing in single argument, a pointer to the HOBs. + // + ActivateLongMode ( + PageTables, + (EFI_PHYSICAL_ADDRESS)(UINTN)(HobList.Raw), + TopOfStack, + PpisNeededByDxeEntryPoint, + DxeCoreEntryPoint + ); + + // + // If we get here, then the DXE Core returned. This is an error + // + ASSERT_EFI_ERROR (Status); + + return EFI_OUT_OF_RESOURCES; +} + +EFI_STATUS +PeiFindFile ( + IN UINT8 Type, + IN UINT16 SectionType, + OUT EFI_GUID *FileName, + OUT VOID **Pe32Data + ) +/*++ + +Routine Description: + + Finds a PE/COFF of a specific Type and SectionType in the Firmware Volumes + described in the HOB list. Able to search in a compression set in a FFS file. + But only one level of compression is supported, that is, not able to search + in a compression set that is within another compression set. + +Arguments: + + Type - The Type of file to retrieve + + SectionType - The type of section to retrieve from a file + + FileName - The name of the file found in the Firmware Volume + + Pe32Data - Pointer to the beginning of the PE/COFF file found in the Firmware Volume + +Returns: + + EFI_SUCCESS - The file was found, and the name is returned in FileName, and a pointer to + the PE/COFF image is returned in Pe32Data + + EFI_NOT_FOUND - The file was not found in the Firmware Volumes present in the HOB List + +--*/ +{ + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_FFS_FILE_HEADER *FfsFileHeader; + VOID *SectionData; + EFI_STATUS Status; + EFI_PEI_HOB_POINTERS Hob; + + + FwVolHeader = NULL; + FfsFileHeader = NULL; + SectionData = NULL; + + // + // Foreach Firmware Volume, look for a specified type + // of file and break out when one is found + // + Hob.Raw = GetHobList (); + while ((Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw)) != NULL) { + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (Hob.FirmwareVolume->BaseAddress); + Status = PeiCoreFfsFindNextFile ( + Type, + FwVolHeader, + &FfsFileHeader + ); + if (!EFI_ERROR (Status)) { + CopyMem (FileName, &FfsFileHeader->Name, sizeof (EFI_GUID)); + Status = PeiProcessFile ( + SectionType, + FfsFileHeader, + Pe32Data + ); + return Status; + } + Hob.Raw = GET_NEXT_HOB (Hob); + } + return EFI_NOT_FOUND; +} + +EFI_STATUS +PeiLoadx64File ( + IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader, + IN VOID *Pe32Data, + IN EFI_MEMORY_TYPE MemoryType, + OUT EFI_PHYSICAL_ADDRESS *ImageAddress, + OUT UINT64 *ImageSize, + OUT EFI_PHYSICAL_ADDRESS *EntryPoint + ) +/*++ + +Routine Description: + + Loads and relocates a PE/COFF image into memory. + +Arguments: + + PeiEfiPeiPeCoffLoader - Pointer to a PE COFF loader protocol + + Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated + + ImageAddress - The base address of the relocated PE/COFF image + + ImageSize - The size of the relocated PE/COFF image + + EntryPoint - The entry point of the relocated PE/COFF image + +Returns: + + EFI_SUCCESS - The file was loaded and relocated + EFI_OUT_OF_RESOURCES - There was not enough memory to load and relocate the PE/COFF file + +--*/ +{ + EFI_STATUS Status; + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + EFI_PHYSICAL_ADDRESS MemoryBuffer; + + ZeroMem (&ImageContext, sizeof (ImageContext)); + ImageContext.Handle = Pe32Data; + Status = GetImageReadFunction (&ImageContext); + + ASSERT_EFI_ERROR (Status); + + Status = PeiEfiPeiPeCoffLoader->GetImageInfo (PeiEfiPeiPeCoffLoader, &ImageContext); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Allocate Memory for the image + // + // + // Allocate Memory for the image + // + PeiCoreAllocatePages (MemoryType, EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize), &MemoryBuffer); + ImageContext.ImageAddress = MemoryBuffer; + ASSERT (ImageContext.ImageAddress != 0); + + // + // Load the image to our new buffer + // + + Status = PeiEfiPeiPeCoffLoader->LoadImage (PeiEfiPeiPeCoffLoader, &ImageContext); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Relocate the image in our new buffer + // + Status = PeiEfiPeiPeCoffLoader->RelocateImage (PeiEfiPeiPeCoffLoader, &ImageContext); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Flush the instruction cache so the image data is written before we execute it + // + InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); + + *ImageAddress = ImageContext.ImageAddress; + *ImageSize = ImageContext.ImageSize; + *EntryPoint = ImageContext.EntryPoint; + + return EFI_SUCCESS; +} + +EFI_STATUS +ShadowDxeIpl ( + IN EFI_FFS_FILE_HEADER *DxeIplFileHeader, + IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader + ) +/*++ + +Routine Description: + + Shadow the DXE IPL to a different memory location. This occurs after permanent + memory has been discovered. + +Arguments: + + DxeIplFileHeader - Pointer to the FFS file header of the DXE IPL driver + + PeiEfiPeiPeCoffLoader - Pointer to a PE COFF loader protocol + +Returns: + + EFI_SUCCESS - DXE IPL was successfully shadowed to a different memory location. + + EFI_ ERROR - The shadow was unsuccessful. + + +--*/ +{ + UINTN SectionLength; + UINTN OccupiedSectionLength; + EFI_PHYSICAL_ADDRESS DxeIplAddress; + UINT64 DxeIplSize; + EFI_PHYSICAL_ADDRESS DxeIplEntryPoint; + EFI_STATUS Status; + EFI_COMMON_SECTION_HEADER *Section; + + Section = (EFI_COMMON_SECTION_HEADER *) (DxeIplFileHeader + 1); + + while ((Section->Type != EFI_SECTION_PE32) && (Section->Type != EFI_SECTION_TE)) { + SectionLength = *(UINT32 *) (Section->Size) & 0x00ffffff; + OccupiedSectionLength = GetOccupiedSize (SectionLength, 4); + Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + OccupiedSectionLength); + } + + // + // Relocate DxeIpl into memory by using loadfile service + // + Status = PeiLoadx64File ( + PeiEfiPeiPeCoffLoader, + (VOID *) (Section + 1), + EfiBootServicesData, + &DxeIplAddress, + &DxeIplSize, + &DxeIplEntryPoint + ); + + if (Status == EFI_SUCCESS) { + // + // Install PeiInMemory to indicate the Dxeipl is shadowed + // + Status = PeiCoreInstallPpi (&mPpiPeiInMemory); + + if (EFI_ERROR (Status)) { + return Status; + } + + Status = ((EFI_PEIM_ENTRY_POINT) (UINTN) DxeIplEntryPoint) (DxeIplFileHeader, GetPeiServicesTablePointer()); + } + + return Status; +} + +EFI_STATUS +EFIAPI +DxeIplLoadFile ( + IN EFI_PEI_FV_FILE_LOADER_PPI *This, + IN EFI_FFS_FILE_HEADER *FfsHeader, + OUT EFI_PHYSICAL_ADDRESS *ImageAddress, + OUT UINT64 *ImageSize, + OUT EFI_PHYSICAL_ADDRESS *EntryPoint + ) +/*++ + +Routine Description: + + Given a pointer to an FFS file containing a PE32 image, get the + information on the PE32 image, and then "load" it so that it + can be executed. + +Arguments: + + This - pointer to our file loader protocol + FfsHeader - pointer to the FFS file header of the FFS file that + contains the PE32 image we want to load + ImageAddress - returned address where the PE32 image is loaded + ImageSize - returned size of the loaded PE32 image + EntryPoint - entry point to the loaded PE32 image + +Returns: + + EFI_SUCCESS - The FFS file was successfully loaded. + EFI_ERROR - Unable to load the FFS file. + +--*/ +{ + EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader; + EFI_STATUS Status; + VOID *Pe32Data; + + Pe32Data = NULL; + PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)GetPeCoffLoaderProtocol (); + + // + // Preprocess the FFS file to get a pointer to the PE32 information + // in the enclosed PE32 image. + // + Status = PeiProcessFile ( + EFI_SECTION_PE32, + FfsHeader, + &Pe32Data + ); + + if (EFI_ERROR (Status)) { + return Status; + } + // + // Load the PE image from the FFS file + // + Status = PeiLoadx64File ( + PeiEfiPeiPeCoffLoader, + Pe32Data, + EfiBootServicesData, + ImageAddress, + ImageSize, + EntryPoint + ); + + return Status; +} + +EFI_STATUS +PeiProcessFile ( + IN UINT16 SectionType, + IN EFI_FFS_FILE_HEADER *FfsFileHeader, + OUT VOID **Pe32Data + ) +/*++ + +Routine Description: + +Arguments: + + SectionType - The type of section in the FFS file to process. + + FfsFileHeader - Pointer to the FFS file to process, looking for the + specified SectionType + + Pe32Data - returned pointer to the start of the PE32 image found + in the FFS file. + +Returns: + + EFI_SUCCESS - found the PE32 section in the FFS file + +--*/ +{ + EFI_STATUS Status; + VOID *SectionData; + DECOMPRESS_LIBRARY *DecompressLibrary; + UINT8 *DstBuffer; + UINT8 *ScratchBuffer; + UINT32 DstBufferSize; + UINT32 ScratchBufferSize; + EFI_COMMON_SECTION_HEADER *CmpSection; + UINTN CmpSectionLength; + UINTN OccupiedCmpSectionLength; + VOID *CmpFileData; + UINTN CmpFileSize; + EFI_COMMON_SECTION_HEADER *Section; + UINTN SectionLength; + UINTN OccupiedSectionLength; + UINT64 FileSize; + EFI_GUID_DEFINED_SECTION *GuidedSectionHeader; + UINT32 AuthenticationStatus; + EFI_PEI_SECTION_EXTRACTION_PPI *SectionExtract; + UINT32 BufferSize; + UINT8 *Buffer; + EFI_PEI_SECURITY_PPI *Security; + BOOLEAN StartCrisisRecovery; + EFI_GUID TempGuid; + EFI_FIRMWARE_VOLUME_HEADER *FvHeader; + EFI_COMPRESSION_SECTION *CompressionSection; + + Status = PeiCoreFfsFindSectionData ( + EFI_SECTION_COMPRESSION, + FfsFileHeader, + &SectionData + ); + + // + // Upon finding a DXE Core file, see if there is first a compression section + // + if (!EFI_ERROR (Status)) { + // + // Yes, there is a compression section, so extract the contents + // Decompress the image here + // + Section = (EFI_COMMON_SECTION_HEADER *) (UINTN) (VOID *) ((UINT8 *) (FfsFileHeader) + (UINTN) sizeof (EFI_FFS_FILE_HEADER)); + + do { + SectionLength = *(UINT32 *) (Section->Size) & 0x00ffffff; + OccupiedSectionLength = GetOccupiedSize (SectionLength, 4); + + // + // Was the DXE Core file encapsulated in a GUID'd section? + // + if (Section->Type == EFI_SECTION_GUID_DEFINED) { + // + // Locate the GUID'd Section Extractor + // + GuidedSectionHeader = (VOID *) (Section + 1); + + // + // This following code constitutes the addition of the security model + // to the DXE IPL. + // + // + // Set a default authenticatino state + // + AuthenticationStatus = 0; + + Status = PeiCoreLocatePpi ( + &gEfiPeiSectionExtractionPpiGuid, + 0, + NULL, + (VOID **)&SectionExtract + ); + + if (EFI_ERROR (Status)) { + return Status; + } + // + // Verify Authentication State + // + CopyMem (&TempGuid, Section + 1, sizeof (EFI_GUID)); + + Status = SectionExtract->PeiGetSection ( + GetPeiServicesTablePointer(), + SectionExtract, + (EFI_SECTION_TYPE *) &SectionType, + &TempGuid, + 0, + (VOID **) &Buffer, + &BufferSize, + &AuthenticationStatus + ); + + if (EFI_ERROR (Status)) { + return Status; + } + // + // If not ask the Security PPI, if exists, for disposition + // + // + Status = PeiCoreLocatePpi ( + &gEfiPeiSecurityPpiGuid, + 0, + NULL, + (VOID **)&Security + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = Security->AuthenticationState ( + GetPeiServicesTablePointer(), + (struct _EFI_PEI_SECURITY_PPI *) Security, + AuthenticationStatus, + FfsFileHeader, + &StartCrisisRecovery + ); + + if (EFI_ERROR (Status)) { + return Status; + } + // + // If there is a security violation, report to caller and have + // the upper-level logic possible engender a crisis recovery + // + if (StartCrisisRecovery) { + return EFI_SECURITY_VIOLATION; + } + } + + if (Section->Type == EFI_SECTION_PE32) { + // + // This is what we want + // + *Pe32Data = (VOID *) (Section + 1); + return EFI_SUCCESS; + } else if (Section->Type == EFI_SECTION_COMPRESSION) { + // + // This is a compression set, expand it + // + CompressionSection = (EFI_COMPRESSION_SECTION *) Section; + + switch (CompressionSection->CompressionType) { + case EFI_STANDARD_COMPRESSION: + DecompressLibrary = &gTianoDecompress; + break; + + case EFI_CUSTOMIZED_COMPRESSION: + // + // Load user customized compression protocol. + // + DecompressLibrary = &gCustomDecompress; + break; + + case EFI_NOT_COMPRESSED: + default: + // + // Need to support not compressed file + // + ASSERT_EFI_ERROR (Status); + return EFI_NOT_FOUND; + } + + Status = DecompressLibrary->GetInfo ( + (UINT8 *) ((EFI_COMPRESSION_SECTION *) Section + 1), + (UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION), + &DstBufferSize, + &ScratchBufferSize + ); + if (EFI_ERROR (Status)) { + // + // GetInfo failed + // + 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 = DecompressLibrary->Decompress ( + (CHAR8 *) ((EFI_COMPRESSION_SECTION *) Section + 1), + DstBuffer, + ScratchBuffer + ); + + CmpSection = (EFI_COMMON_SECTION_HEADER *) DstBuffer; + if (CmpSection->Type == EFI_SECTION_RAW) { + // + // Skip the section header and + // adjust the pointer alignment to 16 + // + FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (DstBuffer + 16); + + if (FvHeader->Signature == EFI_FVH_SIGNATURE) { + FfsFileHeader = NULL; + BuildFvHob ((EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader, FvHeader->FvLength); + Status = PeiCoreFfsFindNextFile ( + EFI_FV_FILETYPE_DXE_CORE, + FvHeader, + &FfsFileHeader + ); + + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + return PeiProcessFile (SectionType, FfsFileHeader, Pe32Data); + } + } + // + // Decompress successfully. + // Loop the decompressed data searching for expected section. + // + CmpFileData = (VOID *) DstBuffer; + CmpFileSize = DstBufferSize; + do { + CmpSectionLength = *(UINT32 *) (CmpSection->Size) & 0x00ffffff; + if (CmpSection->Type == EFI_SECTION_PE32) { + // + // This is what we want + // + *Pe32Data = (VOID *) (CmpSection + 1); + return EFI_SUCCESS; + } + + OccupiedCmpSectionLength = GetOccupiedSize (CmpSectionLength, 4); + CmpSection = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) CmpSection + OccupiedCmpSectionLength); + } while (CmpSection->Type != 0 && (UINTN) ((UINT8 *) CmpSection - (UINT8 *) CmpFileData) < CmpFileSize); + } + + Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + OccupiedSectionLength); + FileSize = FfsFileHeader->Size[0] & 0xFF; + FileSize += (FfsFileHeader->Size[1] << 8) & 0xFF00; + FileSize += (FfsFileHeader->Size[2] << 16) & 0xFF0000; + FileSize &= 0x00FFFFFF; + } while (Section->Type != 0 && (UINTN) ((UINT8 *) Section - (UINT8 *) FfsFileHeader) < FileSize); + + // + // End of the decompression activity + // + } else { + + Status = PeiCoreFfsFindSectionData ( + EFI_SECTION_PE32, + FfsFileHeader, + &SectionData + ); + + if (EFI_ERROR (Status)) { + Status = PeiCoreFfsFindSectionData ( + EFI_SECTION_TE, + FfsFileHeader, + &SectionData + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + } + + *Pe32Data = SectionData; + + return EFI_SUCCESS; +} \ No newline at end of file diff --git a/EdkModulePkg/Core/DxeIplPeim/Ipf/DxeLoadFunc.c b/EdkModulePkg/Core/DxeIplPeim/Ipf/DxeLoadFunc.c new file mode 100644 index 0000000000..95fb0937c5 --- /dev/null +++ b/EdkModulePkg/Core/DxeIplPeim/Ipf/DxeLoadFunc.c @@ -0,0 +1,70 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + IpfDxeLoad.c + +Abstract: + + Ipf-specifc functionality for DxeLoad. + +--*/ + +#include + +EFI_STATUS +CreateArchSpecificHobs ( + OUT EFI_PHYSICAL_ADDRESS *BspStore + ) +/*++ + +Routine Description: + + Creates architecture-specific HOBs. + + Note: New parameters should NOT be added for any HOBs that are added to this + function. BspStore is a special case because it is required for the + call to SwitchStacks() in DxeLoad(). + +Arguments: + + BspStore - The address of the BSP Store for those architectures that need + it. Otherwise 0. + +Returns: + + EFI_SUCCESS - The HOBs were created successfully. + +--*/ +{ + EFI_STATUS Status; + + Status = EFI_SUCCESS; + + ASSERT (NULL != BspStore); + + // + // Allocate 16KB for the BspStore + // + Status = PeiCoreAllocatePages (EfiBootServicesData, EFI_SIZE_TO_PAGES (BSP_STORE_SIZE), BspStore); + if (EFI_ERROR (Status)) { + return Status; + } + + BuildBspStoreHob ( + *BspStore, + BSP_STORE_SIZE, + EfiBootServicesData + ); + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Core/DxeIplPeim/Ipf/ImageRead.c b/EdkModulePkg/Core/DxeIplPeim/Ipf/ImageRead.c new file mode 100644 index 0000000000..16b44b24d8 --- /dev/null +++ b/EdkModulePkg/Core/DxeIplPeim/Ipf/ImageRead.c @@ -0,0 +1,72 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ImageRead.c + +Abstract: + +--*/ + +#include + +EFI_STATUS +PeiImageRead ( + IN VOID *FileHandle, + IN UINTN FileOffset, + IN OUT UINTN *ReadSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file + +Arguments: + + FileHandle - The handle to the PE/COFF file + + FileOffset - The offset, in bytes, into the file to read + + ReadSize - The number of bytes to read from the file starting at FileOffset + + Buffer - A pointer to the buffer to read the data into. + +Returns: + + EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset + +--*/ +{ + CHAR8 *Destination8; + CHAR8 *Source8; + UINTN Length; + + Destination8 = Buffer; + Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset); + Length = *ReadSize; + while (Length--) { + *(Destination8++) = *(Source8++); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +GetImageReadFunction ( + IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + ImageContext->ImageRead = PeiImageRead; + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Core/DxeIplPeim/build.xml b/EdkModulePkg/Core/DxeIplPeim/build.xml new file mode 100644 index 0000000000..5f83fe7365 --- /dev/null +++ b/EdkModulePkg/Core/DxeIplPeim/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Core/DxeIplPeim/build_X64.xml b/EdkModulePkg/Core/DxeIplPeim/build_X64.xml new file mode 100644 index 0000000000..aef68ec4dc --- /dev/null +++ b/EdkModulePkg/Core/DxeIplPeim/build_X64.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Core/DxeIplPeim/ia32/DxeLoadFunc.c b/EdkModulePkg/Core/DxeIplPeim/ia32/DxeLoadFunc.c new file mode 100644 index 0000000000..4d1015bbd8 --- /dev/null +++ b/EdkModulePkg/Core/DxeIplPeim/ia32/DxeLoadFunc.c @@ -0,0 +1,51 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DxeLoadFunc.c + +Abstract: + + Ia32-specifc functionality for DxeLoad. + +--*/ + +#include + +EFI_STATUS +CreateArchSpecificHobs ( + OUT EFI_PHYSICAL_ADDRESS *BspStore + ) +/*++ + +Routine Description: + + Creates architecture-specific HOBs. + + Note: New parameters should NOT be added for any HOBs that are added to this + function. BspStore is a special case because it is required for the + call to SwitchStacks() in DxeLoad(). + +Arguments: + + BspStore - The address of the BSP Store for those architectures that need + it. Otherwise 0. + +Returns: + + EFI_SUCCESS - The HOBs were created successfully. + +--*/ +{ + *BspStore = 0; + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Core/DxeIplPeim/ia32/ImageRead.c b/EdkModulePkg/Core/DxeIplPeim/ia32/ImageRead.c new file mode 100644 index 0000000000..fe07608290 --- /dev/null +++ b/EdkModulePkg/Core/DxeIplPeim/ia32/ImageRead.c @@ -0,0 +1,112 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ImageRead.c + +Abstract: + +--*/ + +#include + +EFI_STATUS +EFIAPI +PeiImageRead ( + IN VOID *FileHandle, + IN UINTN FileOffset, + IN OUT UINTN *ReadSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file + +Arguments: + + FileHandle - The handle to the PE/COFF file + + FileOffset - The offset, in bytes, into the file to read + + ReadSize - The number of bytes to read from the file starting at FileOffset + + Buffer - A pointer to the buffer to read the data into. + +Returns: + + EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset + +--*/ +{ + UINT8 *Destination32; + UINT8 *Source32; + UINTN Length; + + + Destination32 = Buffer; + Source32 = (UINT8 *) ((UINTN) FileHandle + FileOffset); + + // + // This function assumes 32-bit alignment to increase performance + // +// ASSERT (ALIGN_POINTER (Destination32, sizeof (UINT32)) == Destination32); +// ASSERT (ALIGN_POINTER (Source32, sizeof (UINT32)) == Source32); + + Length = *ReadSize; + while (Length--) { + *(Destination32++) = *(Source32++); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +GetImageReadFunction ( + IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +/*++ + +Routine Description: + Support routine to return the PE32 Image Reader. + If the PeiImageRead() function is less than a page + in legnth. If the function is more than a page the DXE IPL will crash!!!! + +Arguments: + ImageContext - The context of the image being loaded + +Returns: + EFI_SUCCESS - If Image function location is found + +--*/ +{ + VOID *MemoryBuffer; + + if (gInMemory) { + ImageContext->ImageRead = PeiImageRead; + return EFI_SUCCESS; + } + + // + // BugBug; This code assumes PeiImageRead() is less than a page in size! + // Allocate a page so we can shaddow the read function from FLASH into + // memory to increase performance. + // + + MemoryBuffer = AllocateCopyPool (0x400, (VOID *)(UINTN) PeiImageRead); + ASSERT (MemoryBuffer != NULL); + + ImageContext->ImageRead = (PE_COFF_LOADER_READ_FILE) (UINTN) MemoryBuffer; + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Core/DxeIplPeim/x64/DxeLoadFunc.c b/EdkModulePkg/Core/DxeIplPeim/x64/DxeLoadFunc.c new file mode 100644 index 0000000000..c93c7e1747 --- /dev/null +++ b/EdkModulePkg/Core/DxeIplPeim/x64/DxeLoadFunc.c @@ -0,0 +1,53 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DxeLoadFunc.c + +Abstract: + + Ia32-specifc functionality for DxeLoad X64 Lakeport. + +--*/ + +#include + +EFI_STATUS +CreateArchSpecificHobs ( + OUT EFI_PHYSICAL_ADDRESS *BspStore + ) +/*++ + +Routine Description: + + Creates architecture-specific HOBs. + + Note: New parameters should NOT be added for any HOBs that are added to this + function. BspStore is a special case because it is required for the + call to SwitchStacks() in DxeLoad(). + +Arguments: + + PeiServices - General purpose services available to every PEIM. + BspStore - The address of the BSP Store for those architectures that need + it. Otherwise 0. + +Returns: + + EFI_SUCCESS - The HOBs were created successfully. + +--*/ +{ + *BspStore = 0; + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Core/DxeIplPeim/x64/ImageRead.c b/EdkModulePkg/Core/DxeIplPeim/x64/ImageRead.c new file mode 100644 index 0000000000..dd977f2d2e --- /dev/null +++ b/EdkModulePkg/Core/DxeIplPeim/x64/ImageRead.c @@ -0,0 +1,106 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ImageRead.c + +Abstract: + +--*/ + +#include + +EFI_STATUS +EFIAPI +PeiImageRead ( + IN VOID *FileHandle, + IN UINTN FileOffset, + IN OUT UINTN *ReadSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file + +Arguments: + + FileHandle - The handle to the PE/COFF file + + FileOffset - The offset, in bytes, into the file to read + + ReadSize - The number of bytes to read from the file starting at FileOffset + + Buffer - A pointer to the buffer to read the data into. + +Returns: + + EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset + +--*/ +{ + CHAR8 *Destination8; + CHAR8 *Source8; + UINTN Length; + + Destination8 = Buffer; + Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset); + Length = *ReadSize; + while (Length--) { + *(Destination8++) = *(Source8++); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +GetImageReadFunction ( + IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +/*++ + +Routine Description: + + Support routine to return the PE32 Image Reader. + If the PeiImageRead() function is less than a page + in legnth. If the function is more than a page the DXE IPL will crash!!!! + +Arguments: + ImageContext - The context of the image being loaded + +Returns: + + EFI_SUCCESS - If Image function location is found + +--*/ +{ + VOID *MemoryBuffer; + + if (gInMemory) { + ImageContext->ImageRead = PeiImageRead; + return EFI_SUCCESS; + } + + // + // BugBug; This code assumes PeiImageRead() is less than a page in size! + // Allocate a page so we can shaddow the read function from FLASH into + // memory to increase performance. + // + + MemoryBuffer = AllocateCopyPool (0x400, (VOID *)(UINTN) PeiImageRead); + ASSERT (MemoryBuffer != NULL); + + ImageContext->ImageRead = (PE_COFF_LOADER_READ_FILE) (UINTN) MemoryBuffer; + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Core/DxeIplPeim/x64/LongMode.asm b/EdkModulePkg/Core/DxeIplPeim/x64/LongMode.asm new file mode 100644 index 0000000000..a9c4e774cf --- /dev/null +++ b/EdkModulePkg/Core/DxeIplPeim/x64/LongMode.asm @@ -0,0 +1,1357 @@ + TITLE LongMode.asm: Assembly code for the entering long mode + +;------------------------------------------------------------------------------ +;* +;* Copyright (c) 2006, Intel Corporation +;* All rights reserved. This program and the accompanying materials +;* are licensed and made available under the terms and conditions of the BSD License +;* which accompanies this distribution. The full text of the license may be found at +;* http://opensource.org/licenses/bsd-license.php +;* +;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +;* +;* LongMode.asm +;* +;* Abstract: +;* +;* Transition from 32-bit protected mode EFI environment into x64 +;* 64-bit bit long mode. +;* +;------------------------------------------------------------------------------ + +.686p +.model flat + +; +; Create the exception handler code in IA32 C code +; + +.code +.stack +.MMX +.XMM + +_LoadGo64Gdt PROC Near Public + push ebp ; C prolog + push edi + mov ebp, esp + ; + ; Disable interrupts + ; + cli + ; + ; Reload the selectors + ; Note: + ; Make the Selectors 64-bit ready + ; + mov edi, OFFSET gdtr ; Load GDT register + mov ax,cs ; Get the selector data from our code image + mov es,ax + lgdt FWORD PTR es:[edi] ; and update the GDTR + + db 067h + db 0eah ; Far Jump Offset:Selector to reload CS + dd OFFSET DataSelectorRld; Offset is ensuing instruction boundary + dw LINEAR_CODE_SEL ; Selector is our code selector, 10h +DataSelectorRld:: + mov ax, SYS_DATA_SEL ; Update the Base for the new selectors, too + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + + pop edi + pop ebp + ret +_LoadGo64Gdt endp + + +; VOID +; ActivateLongMode ( +; IN EFI_PHYSICAL_ADDRESS PageTables, +; IN EFI_PHYSICAL_ADDRESS HobStart, +; IN EFI_PHYSICAL_ADDRESS Stack, +; IN EFI_PHYSICAL_ADDRESS PpisNeededByDxeIplEntryPoint, +; IN EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint +; ) +; +; Input: [ebp][0h] = Original ebp +; [ebp][4h] = Return address +; [ebp][8h] = PageTables +; [ebp][10h] = HobStart +; [ebp][18h] = Stack +; [ebp][20h] = CodeEntryPoint1 <--- Call this first (for each call, pass HOB pointer) +; [ebp][28h] = CodeEntryPoint2 <--- Call this second +; +; +_ActivateLongMode PROC Near Public + push ebp ; C prolog + mov ebp, esp + + ; + ; Use CPUID to determine if the processor supports long mode. + ; + mov eax, 80000000h ; Extended-function code 8000000h. + cpuid ; Is largest extended function + cmp eax, 80000000h ; any function > 80000000h? + jbe no_long_mode ; If not, no long mode. + mov eax, 80000001h ; Extended-function code 8000001h. + cpuid ; Now EDX = extended-features flags. + bt edx, 29 ; Test if long mode is supported. + jnc no_long_mode ; Exit if not supported. + + ; + ; Enable the 64-bit page-translation-table entries by + ; setting CR4.PAE=1 (this is _required_ before activating + ; long mode). Paging is not enabled until after long mode + ; is enabled. + ; + mov eax, cr4 + bts eax, 5 + mov cr4, eax + + ; + ; Get the long-mode page tables, and initialize the + ; 64-bit CR3 (page-table base address) to point to the base + ; of the PML4 page table. The PML4 page table must be located + ; below 4 Gbytes because only 32 bits of CR3 are loaded when + ; the processor is not in 64-bit mode. + ; + mov eax, [ebp+8h] ; Get Page Tables + mov cr3, eax ; Initialize CR3 with PML4 base. + + ; + ; Enable long mode (set EFER.LME=1). + ; + mov ecx, 0c0000080h ; EFER MSR number. + rdmsr ; Read EFER. + bts eax, 8 ; Set LME=1. + wrmsr ; Write EFER. + + ; + ; Enable paging to activate long mode (set CR0.PG=1) + ; + + + mov eax, cr0 ; Read CR0. + bts eax, 31 ; Set PG=1. + mov cr0, eax ; Write CR0. + jmp go_to_long_mode +go_to_long_mode: + + ; + ; This is the next instruction after enabling paging. Jump to long mode + ; + db 067h + db 0eah ; Far Jump Offset:Selector to reload CS + dd OFFSET in_long_mode; Offset is ensuing instruction boundary + dw SYS_CODE64_SEL ; Selector is our code selector, 10h +in_long_mode:: + mov ax, SYS_DATA64_SEL + mov es, ax + mov ss, ax + mov ds, ax +;; jmp $ + + + ; + ; We're in long mode, so marshall the arguments to call the + ; passed in function pointers + ; Recall + ; [ebp][10h] = HobStart + ; [ebp][18h] = Stack + ; [ebp][20h] = PpisNeededByDxeIplEntryPoint <--- Call this first (for each call, pass HOB pointer) + ; [ebp][28h] = DxeCoreEntryPoint <--- Call this second + ; + db 48h + mov ebx, [ebp+18h] ; Setup the stack + db 48h + mov esp, ebx ; On a new stack now + + db 48h + mov ecx, [ebp+10h] ; Pass Hob Start in RCX + db 48h + mov eax, [ebp+20h] ; Get the function pointer for + ; PpisNeededByDxeIplEntryPoint into EAX + +;; 00000905 FF D0 call rax + db 0ffh + db 0d0h + + db 48h + mov ecx, [ebp+10h] ; Pass Hob Start in RCX + db 48h + mov eax, [ebp+28h] ; Get the function pointer for + ; DxeCoreEntryPoint into EAX + +;; 00000905 FF D0 call rax + db 0ffh + db 0d0h + + ; + ; WE SHOULD NEVER GET HERE!!!!!!!!!!!!! + ; +no_long_mode: + jmp no_long_mode +_ActivateLongMode endp + + align 16 + +gdtr dw GDT_END - GDT_BASE - 1 ; GDT limit + dd OFFSET GDT_BASE ; (GDT base gets set above) + +;-----------------------------------------------------------------------------; +; global descriptor table (GDT) +;-----------------------------------------------------------------------------; + + align 16 + +public GDT_BASE +GDT_BASE: +; null descriptor +NULL_SEL equ $-GDT_BASE ; Selector [0] + dw 0 ; limit 15:0 + dw 0 ; base 15:0 + db 0 ; base 23:16 + db 0 ; type + db 0 ; limit 19:16, flags + db 0 ; base 31:24 + +; linear data segment descriptor +LINEAR_SEL equ $-GDT_BASE ; Selector [0x8] + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 092h ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; linear code segment descriptor +LINEAR_CODE_SEL equ $-GDT_BASE ; Selector [0x10] + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 09Fh ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; system data segment descriptor +SYS_DATA_SEL equ $-GDT_BASE ; Selector [0x18] + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 093h ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; system code segment descriptor +SYS_CODE_SEL equ $-GDT_BASE ; Selector [0x20] + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 09Ah ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; spare segment descriptor +SPARE3_SEL equ $-GDT_BASE ; Selector [0x28] + dw 0 ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 0 ; present, ring 0, data, expand-up, writable + db 0 ; page-granular, 32-bit + db 0 + +; +; system data segment descriptor +; +SYS_DATA64_SEL equ $-GDT_BASE ; Selector [0x30] + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 092h ; P | DPL [1..2] | 1 | 1 | C | R | A + db 0CFh ; G | D | L | AVL | Segment [19..16] + db 0 + +; +; system code segment descriptor +; +SYS_CODE64_SEL equ $-GDT_BASE ; Selector [0x38] + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 09Ah ; P | DPL [1..2] | 1 | 1 | C | R | A + db 0AFh ; G | D | L | AVL | Segment [19..16] + db 0 + +; spare segment descriptor +SPARE4_SEL equ $-GDT_BASE ; Selector [0x40] + dw 0 ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 0 ; present, ring 0, data, expand-up, writable + db 0 ; page-granular, 32-bit + db 0 + +GDT_END: + +; +; +;------------------------------------------------------------------------------ +; Generic IDT Vector Handlers for the Host. They are all the same so they +; will compress really well. +; +; By knowing the return address for Vector 00 you can can calculate the +; vector number by looking at the call CommonInterruptEntry return address. +; (return address - AsmIdtVector00Base)/8 == IDT index +; +;------------------------------------------------------------------------------ + +_AsmIdtVector00 PROC NEAR PUBLIC + call CommonInterruptEntry +_AsmIdtVector00 ENDP +AsmIdtVector00Base PROC NEAR PUBLIC + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop + call CommonInterruptEntry + nop + nop + nop +AsmIdtVector00Base ENDP + + +;---------------------------------------; +; CommonInterruptEntry ; +;---------------------------------------; +; The follow algorithm is used for the common interrupt routine. +; TBD: Save EFI_SYSTEM_CONTEXT_x64 on the stack per AP definition +; +; +CommonInterruptEntry PROC NEAR PUBLIC + cli + jmp $ + iret + +CommonInterruptEntry ENDP + +END + diff --git a/EdkModulePkg/Core/DxeIplPeim/x64/VirtualMemory.c b/EdkModulePkg/Core/DxeIplPeim/x64/VirtualMemory.c new file mode 100644 index 0000000000..40eaed2ce6 --- /dev/null +++ b/EdkModulePkg/Core/DxeIplPeim/x64/VirtualMemory.c @@ -0,0 +1,434 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + VirtualMemory.c + +Abstract: + + 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 attirbutes + 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) Atchitecture Software Developer's Manual Volume 1:Basic Architecture, Intel + 2) IA-32 Intel(R) Atchitecture Software Developer's Manual Volume 2:Instruction Set Reference, Intel + 3) IA-32 Intel(R) Atchitecture Software Developer's Manual Volume 3:System Programmer's Guide, Intel + +--*/ + +#include "VirtualMemory.h" + +x64_MTRR_VARIABLE_RANGE *mMTRRVariableRange; +x64_MTRR_FIXED_RANGE mMTRRFixedRange; + + +// +// Physial memory limit values for each of the 11 fixed MTRRs +// +UINTN mFixedRangeLimit[] = { + 0x7FFFF, // Fixed MTRR #0 describes 0x00000..0x7FFFF + 0x9FFFF, // Fixed MTRR #1 describes 0x80000..0x9FFFF + 0xBFFFF, // Fixed MTRR #2 describes 0xA0000..0xBFFFF + 0xC7FFF, // Fixed MTRR #3 describes 0xC0000..0xC7FFF + 0xCFFFF, // Fixed MTRR #4 describes 0xC8000..0xCFFFF + 0xD7FFF, // Fixed MTRR #5 describes 0xD0000..0xD7FFF + 0xDFFFF, // Fixed MTRR #6 describes 0xD8000..0xDFFFF + 0xE7FFF, // Fixed MTRR #7 describes 0xE0000..0xE7FFF + 0xEFFFF, // Fixed MTRR #8 describes 0xE8000..0xEFFFF + 0xF7FFF, // Fixed MTRR #9 describes 0xF0000..0xF7FFF + 0xFFFFF // Fixed MTRR #10 describes 0xF8000..0xFFFFF +}; + +// +// The size, in bits, of each of the 11 fixed MTRR. +// +UINTN mFixedRangeShift[] = { + 16, // Fixed MTRR #0 describes 8, 64 KB ranges + 14, // Fixed MTRR #1 describes 8, 16 KB ranges + 14, // Fixed MTRR #2 describes 8, 16 KB ranges + 12, // Fixed MTRR #3 describes 8, 4 KB ranges + 12, // Fixed MTRR #4 describes 8, 4 KB ranges + 12, // Fixed MTRR #5 describes 8, 4 KB ranges + 12, // Fixed MTRR #6 describes 8, 4 KB ranges + 12, // Fixed MTRR #7 describes 8, 4 KB ranges + 12, // Fixed MTRR #8 describes 8, 4 KB ranges + 12, // Fixed MTRR #9 describes 8, 4 KB ranges + 12 // Fixed MTRR #10 describes 8, 4 KB ranges +}; + + +UINTN mPowerOf2[] = { + 1, + 2, + 4, + 8, + 16, + 32, + 64, + 128, + 256, + 512 +}; + +x64_MTRR_MEMORY_TYPE +EfiGetMTRRMemoryType ( + IN EFI_PHYSICAL_ADDRESS Address + ) +/*++ + +Routine Description: + + Retrieves the memory type from the MTRR that describes a physical address. + +Arguments: + + VariableRange - Set of Variable MTRRs + + FixedRange - Set of Fixed MTRRs + + Address - The physical address for which the MTRR memory type is being retrieved + +Returns: + + The MTRR Memory Type for the physical memory specified by Address. + +--*/ +{ + UINTN Index; + UINTN TypeIndex; + BOOLEAN Found; + x64_MTRR_MEMORY_TYPE VariableType; + EFI_PHYSICAL_ADDRESS MaskBase; + EFI_PHYSICAL_ADDRESS PhysMask; + + // + // If the MTRRs are disabled, then return the Uncached Memory Type + // + if (mMTRRFixedRange.DefaultType.Bits.E == 0) { + return Uncached; + } + + // + // If the CPU supports Fixed MTRRs and the Fixed MTRRs are enabled, then + // see if Address falls into one of the Fixed MTRRs + // + if (mMTRRFixedRange.Capabilities.Bits.FIX && mMTRRFixedRange.DefaultType.Bits.FE) { + // + // Loop though 11 fixed MTRRs + // + for (Index = 0; Index < 11; Index++) { + // + // Check for a matching range + // + if (Address <= mFixedRangeLimit[Index]) { + // + // Compute the offset address into the MTRR bu subtrating the base address of the MTRR + // + if (Index > 0) { + Address = Address - (mFixedRangeLimit[Index-1] + 1); + } + // + // Retrieve the index into the MTRR to extract the memory type. The range is 0..7 + // + TypeIndex = (UINTN)RShiftU64 (Address, mFixedRangeShift[Index]); + + // + // Retrieve and return the memory type for the matching range + // + return mMTRRFixedRange.Fixed[Index].Type[TypeIndex]; + } + } + } + + // + // If Address was not found in a Fixed MTRR, then search the Variable MTRRs + // + for (Index = 0, Found = FALSE, VariableType = WriteBack; Index < mMTRRFixedRange.Capabilities.Bits.VCNT; Index++) { + // + // BugBug: __aullshr complier error + // + if ((mMTRRVariableRange[Index].PhysMask.Uint64 & 0x800) == 0x800) { + //if (mMTRRVariableRange[Index].PhysMask.Bits.Valid == 1) { + PhysMask = mMTRRVariableRange[Index].PhysMask.Uint64 & ~0xfff; + MaskBase = PhysMask & (mMTRRVariableRange[Index].PhysBase.Uint64 & ~0xfff); + if (MaskBase == (PhysMask & Address)) { + // + // Check to see how many matches we find + // + Found = TRUE; + if ((mMTRRVariableRange[Index].PhysBase.Bits.Type == Uncached) || (VariableType == Uncached)) { + // + // If any matching region uses UC, the memory region is UC + // + VariableType = Uncached; + } else if ((mMTRRVariableRange[Index].PhysBase.Bits.Type == WriteThrough) || (VariableType == WriteThrough)){ + // + // If it's WT and WB then set it to WT. If it's WT and other type it's undefined + // + VariableType = WriteThrough; + } else { + VariableType = mMTRRVariableRange[Index].PhysBase.Bits.Type; + } + } + } + } + + if (Found) { + return VariableType; + } + + // + // Address was not found in the Fixed or Variable MTRRs, so return the default memory type + // + return mMTRRFixedRange.DefaultType.Bits.Type; +} + + +BOOLEAN +CanNotUse2MBPage ( + IN EFI_PHYSICAL_ADDRESS BaseAddress + ) +/*++ + +Routine Description: + Test to see if a 2MB aligned page has all the same attributes. If a 2MB page + has more than one attibute type it needs to be split into multiple 4K pages. + +Arguments: + BaseAddress - 2MB aligned address to check out + +Returns: + TRUE - This 2MB address range (BaseAddress) can NOT be mapped by a 2MB page + FALSE - This 2MB address range can be mapped by a 2MB page + +--*/ +{ + UINTN Index; + x64_MTRR_MEMORY_TYPE MemoryType; + x64_MTRR_MEMORY_TYPE PreviousMemoryType; + + // + // Address needs to be 2MB aligned + // + ASSERT ((BaseAddress & 0x1fffff) == 0); + + PreviousMemoryType = -1; + for (Index = 0; Index < 512; Index++, BaseAddress += 0x1000) { + MemoryType = EfiGetMTRRMemoryType (BaseAddress); + if ((Index != 0) && (MemoryType != PreviousMemoryType)) { + return TRUE; + } + + PreviousMemoryType = MemoryType; + } + + // + // All the pages had the same type + // + return FALSE; +} + + + + +VOID +Convert2MBPageTo4KPages ( + IN x64_PAGE_TABLE_ENTRY_2M *PageDirectoryEntry2MB, + IN EFI_PHYSICAL_ADDRESS PageAddress + ) +/*++ + +Routine Description: + Convert a single 2MB page entry to 512 4K page entries. The attributes for + the 4K pages are read from the MTRR registers. + +Arguments: + PageDirectoryEntry2MB - Page directory entry for PageAddress + PageAddress - 2MB algined address of region to convert + +Returns: + None + +--*/ +{ + EFI_PHYSICAL_ADDRESS Address; + x64_PAGE_DIRECTORY_ENTRY_4K *PageDirectoryEntry4k; + x64_PAGE_TABLE_ENTRY_4K *PageTableEntry; + UINTN Index1; + + // + // Allocate the page table entry for the 4K pages + // + PageTableEntry = (x64_PAGE_TABLE_ENTRY_4K *) AllocatePages (1); + + ASSERT (PageTableEntry != NULL); + + // + // Convert PageDirectoryEntry2MB into a 4K Page Directory + // + PageDirectoryEntry4k = (x64_PAGE_DIRECTORY_ENTRY_4K *)PageDirectoryEntry2MB; + PageDirectoryEntry2MB->Uint64 = (UINT64)PageTableEntry; + PageDirectoryEntry2MB->Bits.ReadWrite = 1; + PageDirectoryEntry2MB->Bits.Present = 1; + + // + // Fill in the 4K page entries with the attributes from the MTRRs + // + for (Index1 = 0, Address = PageAddress; Index1 < 512; Index1++, PageTableEntry++, Address += 0x1000) { + PageTableEntry->Uint64 = (UINT64)Address; + PageTableEntry->Bits.ReadWrite = 1; + PageTableEntry->Bits.Present = 1; + } +} + + +EFI_PHYSICAL_ADDRESS +CreateIdentityMappingPageTables ( + IN UINT32 NumberOfProcessorPhysicalAddressBits + ) +/*++ + +Routine Description: + + Allocates and fills in the Page Directory and Page Table Entries to + establish a 1:1 Virtual to Physical mapping for physical memory from + 0 to 4GB. Memory above 4GB is not mapped. The MTRRs are used to + determine the cachability of the physical memory regions + +Arguments: + + NumberOfProcessorPhysicalAddressBits - Number of processor address bits to use. + Limits the number of page table entries + to the physical address space. + +Returns: + EFI_OUT_OF_RESOURCES There are not enough resources to allocate the Page Tables + + EFI_SUCCESS The 1:1 Virtual to Physical identity mapping was created + +--*/ +{ + EFI_PHYSICAL_ADDRESS PageAddress; + UINTN Index; + UINTN MaxBitsSupported; + UINTN Index1; + UINTN Index2; + x64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *PageMapLevel4Entry; + x64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *PageMap; + x64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *PageDirectoryPointerEntry; + x64_PAGE_TABLE_ENTRY_2M *PageDirectoryEntry2MB; + + + // + // Page Table structure 4 level 4K, 3 level 2MB. + // + // PageMapLevel4Entry : bits 47-39 + // PageDirectoryPointerEntry : bits 38-30 + // Page Table 2MB : PageDirectoryEntry2M : bits 29-21 + // Page Table 4K : PageDirectoryEntry4K : bits 29 - 21 + // PageTableEntry : bits 20 - 12 + // + // Strategy is to map every thing in the processor address space using + // 2MB pages. If more granularity is required the 2MB page will get + // converted to set of 4K pages. + // + + // + // By architecture only one PageMapLevel4 exists - so lets allocate storgage for it. + // + PageMap = PageMapLevel4Entry = (x64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *) AllocatePages (1); + ASSERT (PageMap != NULL); + PageAddress = 0; + + // + // The number of page-map Level-4 Offset entries is based on the number of + // physical address bits. Less than equal to 38 bits only takes one entry. + // 512 entries represents 48 address bits. + // + if (NumberOfProcessorPhysicalAddressBits <= 38) { + MaxBitsSupported = 1; + } else { + MaxBitsSupported = mPowerOf2[NumberOfProcessorPhysicalAddressBits - 39]; + } + + for (Index = 0; Index < MaxBitsSupported; Index++, 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 Index1 loop. + // + PageDirectoryPointerEntry = (x64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *) AllocatePages (1); + ASSERT (PageDirectoryPointerEntry != NULL); + + // + // Make a PML4 Entry + // + PageMapLevel4Entry->Uint64 = (UINT64)(UINTN)PageDirectoryPointerEntry; + PageMapLevel4Entry->Bits.ReadWrite = 1; + PageMapLevel4Entry->Bits.Present = 1; + + for (Index1 = 0; Index1 < 512; Index1++, PageDirectoryPointerEntry++) { + // + // Each Directory Pointer entries points to a page of Page Directory entires. + // So lets allocate space for them and fill them in in the Index2 loop. + // + PageDirectoryEntry2MB = (x64_PAGE_TABLE_ENTRY_2M *) AllocatePages (1); + ASSERT (PageDirectoryEntry2MB != NULL); + + // + // Fill in a Page Directory Pointer Entries + // + PageDirectoryPointerEntry->Uint64 = (UINT64)(UINTN)PageDirectoryEntry2MB; + PageDirectoryPointerEntry->Bits.ReadWrite = 1; + PageDirectoryPointerEntry->Bits.Present = 1; + + for (Index2 = 0; Index2 < 512; Index2++, PageDirectoryEntry2MB++, PageAddress += 0x200000) { + // + // Fill in the Page Directory entries + // + PageDirectoryEntry2MB->Uint64 = (UINT64)PageAddress; + PageDirectoryEntry2MB->Bits.ReadWrite = 1; + PageDirectoryEntry2MB->Bits.Present = 1; + PageDirectoryEntry2MB->Bits.MustBe1 = 1; + + if (CanNotUse2MBPage (PageAddress)) { + // + // Check to see if all 2MB has the same mapping. If not convert + // to 4K pages by adding the 4th level of page table entries + // + Convert2MBPageTo4KPages (PageDirectoryEntry2MB, PageAddress); + } + } + } + } + + // + // For the PML4 entries we are not using fill in a null entry. + // for now we just copy the first entry. + // + for (; Index < 512; Index++, PageMapLevel4Entry++) { + // EfiCopyMem (PageMapLevel4Entry, PageMap, sizeof (x64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K)); + CopyMem (PageMapLevel4Entry, + PageMap, + sizeof (x64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K) + ); + } + + return (EFI_PHYSICAL_ADDRESS)PageMap; +} + diff --git a/EdkModulePkg/Core/DxeIplPeim/x64/VirtualMemory.h b/EdkModulePkg/Core/DxeIplPeim/x64/VirtualMemory.h new file mode 100644 index 0000000000..8133ad447f --- /dev/null +++ b/EdkModulePkg/Core/DxeIplPeim/x64/VirtualMemory.h @@ -0,0 +1,239 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + VirtualMemory.h + +Abstract: + + x64 Long Mode Virtual Memory Management Definitions + + References: + 1) IA-32 Intel(R) Atchitecture Software Developer's Manual Volume 1:Basic Architecture, Intel + 2) IA-32 Intel(R) Atchitecture Software Developer's Manual Volume 2:Instruction Set Reference, Intel + 3) IA-32 Intel(R) Atchitecture Software Developer's Manual Volume 3:System Programmer's Guide, Intel + 4) AMD64 Architecture Programmer's Manual Volume 2: System Programming +--*/ +#ifndef _VIRTUAL_MEMORY_H_ +#define _VIRTUAL_MEMORY_H_ + + +#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; +} x64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K; + +// +// Page-Directory Offset 4K +// +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:1; // Must Be Zero + UINT64 Reserved2:1; // Reserved + 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; +} x64_PAGE_DIRECTORY_ENTRY_4K; + +// +// Page Table Entry 4K +// +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; // 0 = Ignore Page Attribute Table + 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; +} x64_PAGE_TABLE_ENTRY_4K; + + +// +// 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; +} x64_PAGE_TABLE_ENTRY_2M; + +typedef union { + 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 Reserved:57; +} x64_PAGE_TABLE_ENTRY_COMMON; + +typedef union { + x64_PAGE_TABLE_ENTRY_4K Page4k; + x64_PAGE_TABLE_ENTRY_2M Page2Mb; + x64_PAGE_TABLE_ENTRY_COMMON Common; +} x64_PAGE_TABLE_ENTRY; + +// +// MTRR Definitions +// +typedef enum { + Uncached = 0, + WriteCombining = 1, + WriteThrough = 4, + WriteProtected = 5, + WriteBack = 6 +} x64_MTRR_MEMORY_TYPE; + +typedef union { + struct { + UINT32 VCNT:8; // The number of Variable Range MTRRs + UINT32 FIX:1; // 1=Fixed Range MTRRs supported. 0=Fixed Range MTRRs not supported + UINT32 Reserved_0; // Reserved + UINT32 WC:1; // Write combining memory type supported + UINT32 Reserved_1:21; // Reserved + UINT32 Reserved_2:32; // Reserved + } Bits; + UINT64 Uint64; +} x64_MTRRCAP_MSR; + +typedef union { + struct { + UINT32 Type:8; // Default Memory Type + UINT32 Reserved_0:2; // Reserved + UINT32 FE:1; // 1=Fixed Range MTRRs enabled. 0=Fixed Range MTRRs disabled + UINT32 E:1; // 1=MTRRs enabled, 0=MTRRs disabled + UINT32 Reserved_1:20; // Reserved + UINT32 Reserved_2:32; // Reserved + } Bits; + UINT64 Uint64; +} x64_MTRR_DEF_TYPE_MSR; + +typedef union { + UINT8 Type[8]; // The 8 Memory Type values in the 64-bit MTRR + UINT64 Uint64; // The full 64-bit MSR +} x64_MTRR_FIXED_RANGE_MSR; + +typedef struct { + x64_MTRRCAP_MSR Capabilities; // MTRR Capabilities MSR value + x64_MTRR_DEF_TYPE_MSR DefaultType; // Default Memory Type MSR Value + x64_MTRR_FIXED_RANGE_MSR Fixed[11]; // The 11 Fixed MTRR MSR Values +} x64_MTRR_FIXED_RANGE; + + +typedef union { + struct { + UINT64 Type:8; // Memory Type + UINT64 Reserved0:4; // Reserved + UINT64 PhysBase:40; // The physical base address(bits 35..12) of the MTRR + UINT64 Reserved1:12 ; // Reserved + } Bits; + UINT64 Uint64; +} x64_MTRR_PHYSBASE_MSR; + +typedef union { + struct { + UINT64 Reserved0:11; // Reserved + UINT64 Valid:1; // 1=MTRR is valid, 0=MTRR is not valid + UINT64 PhysMask:40; // The physical address mask (bits 35..12) of the MTRR + UINT64 Reserved1:12; // Reserved + } Bits; + UINT64 Uint64; +} x64_MTRR_PHYSMASK_MSR; + +typedef struct { + x64_MTRR_PHYSBASE_MSR PhysBase; // Variable MTRR Physical Base MSR + x64_MTRR_PHYSMASK_MSR PhysMask; // Variable MTRR Physical Mask MSR +} x64_MTRR_VARIABLE_RANGE; + +#pragma pack() + +x64_MTRR_MEMORY_TYPE +EfiGetMTRRMemoryType ( + IN EFI_PHYSICAL_ADDRESS Address + ) +; + +BOOLEAN +CanNotUse2MBPage ( + IN EFI_PHYSICAL_ADDRESS BaseAddress + ) +; + +VOID +Convert2MBPageTo4KPages ( + IN x64_PAGE_TABLE_ENTRY_2M *PageDirectoryEntry2MB, + IN EFI_PHYSICAL_ADDRESS PageAddress + ) +; + +EFI_PHYSICAL_ADDRESS +CreateIdentityMappingPageTables ( + IN UINT32 NumberOfProcessorPhysicalAddressBits + ) +; + +#endif diff --git a/EdkModulePkg/Core/Pei/BootMode/BootMode.c b/EdkModulePkg/Core/Pei/BootMode/BootMode.c new file mode 100644 index 0000000000..049cfd1a8f --- /dev/null +++ b/EdkModulePkg/Core/Pei/BootMode/BootMode.c @@ -0,0 +1,106 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + BootMode.c + +Abstract: + + EFI PEI Core Boot Mode services + + + +Revision History + +--*/ + +#include + +EFI_STATUS +EFIAPI +PeiGetBootMode ( + IN EFI_PEI_SERVICES **PeiServices, + OUT EFI_BOOT_MODE *BootMode + ) +/*++ + +Routine Description: + + This service enables PEIMs to ascertain the present value of the boot mode. + +Arguments: + + PeiServices - The PEI core services table. + BootMode - A pointer to contain the value of the boot mode. + +Returns: + + EFI_SUCCESS - The boot mode was returned successfully. + EFI_INVALID_PARAMETER - BootMode is NULL. + +--*/ +{ + 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; +}; + + +EFI_STATUS +EFIAPI +PeiSetBootMode ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_BOOT_MODE BootMode + ) +/*++ + +Routine Description: + + This service enables PEIMs to update the boot mode variable. + +Arguments: + + PeiServices - The PEI core services table. + BootMode - The value of the boot mode to set. + +Returns: + + EFI_SUCCESS - The value was successfully updated + +--*/ +{ + 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/EdkModulePkg/Core/Pei/Dependency/dependency.c b/EdkModulePkg/Core/Pei/Dependency/dependency.c new file mode 100644 index 0000000000..5c82eefa1b --- /dev/null +++ b/EdkModulePkg/Core/Pei/Dependency/dependency.c @@ -0,0 +1,264 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + dependency.c + +Abstract: + + PEI 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. + +--*/ + +#include +#include "Dependency.h" + +STATIC +BOOLEAN +IsPpiInstalled ( + IN EFI_PEI_SERVICES **PeiServices, + IN EVAL_STACK_ENTRY *Stack + ) +/*++ + +Routine Description: + + 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. + +Arguments: + PeiServices - The PEI core services table. + Stack - Reference to EVAL_STACK_ENTRY that contains PPI GUID to check + +Returns: + + True if the PPI is already installed. + False if the PPI has yet to be installed. + +--*/ +{ + 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 locale 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 = PeiCoreLocatePpi( + &PpiGuid, // GUID + 0, // INSTANCE + NULL, // EFI_PEI_PPI_DESCRIPTOR + &PeiInstance // PPI + ); + + if (EFI_ERROR(Status)) { + return FALSE; + } + + return TRUE; +} + + +EFI_STATUS +PeimDispatchReadiness ( + IN EFI_PEI_SERVICES **PeiServices, + IN VOID *DependencyExpression, + OUT BOOLEAN *Runnable + ) +/*++ + +Routine Description: + + 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 poped 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). + +Arguments: + + PeiServices - Calling context. + + DependencyExpression - Pointer to a dependency expression. The Grammar adheres to + the BNF described above and is stored in postfix notation. + Runnable - is True if the driver can be scheduled and False if the driver + cannot be scheduled. This is the value that the schedulers + should use for deciding the state of the driver. + +Returns: + + Status = EFI_SUCCESS if it is a well-formed Grammar + EFI_INVALID_PARAMETER if the dependency expression overflows + the evaluation stack + EFI_INVALID_PARAMETER if the dependency expression underflows + the evaluation stack + EFI_INVALID_PARAMETER if the dependency expression is not a + well-formed Grammar. +--*/ +{ + EFI_STATUS Status; + DEPENDENCY_EXPRESSION_OPERAND *Iterator; + EVAL_STACK_ENTRY *StackPtr; + EVAL_STACK_ENTRY EvalStack[MAX_GRAMMAR_SIZE]; + + Status = EFI_SUCCESS; + Iterator = DependencyExpression; + *Runnable = FALSE; + + StackPtr = &EvalStack[0]; + + 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]) { + return EFI_INVALID_PARAMETER; + } + + // + // Push the pointer to the PUSH opcode operator (pointer to PPI GUID) + // We will evaluate if the PPI is insalled on the POP operation. + // + StackPtr->Operator = (VOID *) Iterator; + Iterator = Iterator + sizeof (EFI_GUID); + StackPtr++; + break; + + case (EFI_DEP_AND): + case (EFI_DEP_OR): + // + // 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]) { + return EFI_INVALID_PARAMETER; + } + + // + // 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): + 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]) { + return EFI_INVALID_PARAMETER; + } + *Runnable = IsPpiInstalled (PeiServices, StackPtr); + return EFI_SUCCESS; + break; + + case (EFI_DEP_NOT): + // + // 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]) { + return EFI_INVALID_PARAMETER; + } + (StackPtr-1)->Result = (BOOLEAN) !IsPpiInstalled (PeiServices, (StackPtr-1)); + (StackPtr-1)->Operator = NULL; + break; + + case (EFI_DEP_TRUE): + case (EFI_DEP_FALSE): + // + // Check to make sure the dependency grammar doesn't overflow the + // EvalStack on the push + // + if (StackPtr > &EvalStack[MAX_GRAMMAR_SIZE-1]) { + return EFI_INVALID_PARAMETER; + } + // + // 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: + // + // The grammar should never arrive here + // + return EFI_INVALID_PARAMETER; + break; + } + } +} diff --git a/EdkModulePkg/Core/Pei/Dependency/dependency.h b/EdkModulePkg/Core/Pei/Dependency/dependency.h new file mode 100644 index 0000000000..a1a54ed0cd --- /dev/null +++ b/EdkModulePkg/Core/Pei/Dependency/dependency.h @@ -0,0 +1,38 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + dependency.h + +Abstract: + + This module contains data specific to dependency expressions + and local function prototypes. + +--*/ + +#ifndef _PEI_DEPENDENCY_H_ +#define _PEI_DEPENDENCY_H_ + +#define MAX_GRAMMAR_SIZE 256 + +// +// type definitions +// +typedef UINT8 DEPENDENCY_EXPRESSION_OPERAND; + +typedef struct { + BOOLEAN Result; + VOID *Operator; +} EVAL_STACK_ENTRY; + +#endif diff --git a/EdkModulePkg/Core/Pei/Dispatcher/Dispatcher.c b/EdkModulePkg/Core/Pei/Dispatcher/Dispatcher.c new file mode 100644 index 0000000000..b4e09e3fca --- /dev/null +++ b/EdkModulePkg/Core/Pei/Dispatcher/Dispatcher.c @@ -0,0 +1,535 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Dispatcher.c + +Abstract: + + EFI PEI Core dispatch services + +Revision History + +--*/ + +#include + +VOID * +TransferOldDataToNewDataRange ( + IN PEI_CORE_INSTANCE *PrivateData + ); + +EFI_GUID gEfiPeiCorePrivateGuid = EFI_PEI_CORE_PRIVATE_GUID; + + +EFI_STATUS +PeiDispatcher ( + IN EFI_PEI_STARTUP_DESCRIPTOR *PeiStartupDescriptor, + IN PEI_CORE_INSTANCE *PrivateData, + IN PEI_CORE_DISPATCH_DATA *DispatchData + ) + +/*++ + +Routine Description: + + Conduct PEIM dispatch. + +Arguments: + + PeiStartupDescriptor - Pointer to IN EFI_PEI_STARTUP_DESCRIPTOR + PrivateData - Pointer to the private data passed in from caller + DispatchData - Pointer to PEI_CORE_DISPATCH_DATA data. + +Returns: + + EFI_SUCCESS - Successfully dispatched PEIM. + EFI_NOT_FOUND - The dispatch failed. + +--*/ +{ + EFI_STATUS Status; + PEI_CORE_TEMP_POINTERS TempPtr; + UINTN PrivateDataInMem; + BOOLEAN NextFvFound; + EFI_FIRMWARE_VOLUME_HEADER *NextFvAddress; + EFI_FIRMWARE_VOLUME_HEADER *DefaultFvAddress; + // + // Debug data for uninstalled Peim list + // + EFI_GUID DebugFoundPeimList[32]; + REPORT_STATUS_CODE_LIBRARY_DEVICE_HANDLE_EXTENDED_DATA ExtendedData; + + // + // save the Current FV Address so that we will not process it again if FindFv returns it later + // + DefaultFvAddress = DispatchData->BootFvAddress; + + // + // 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 dipatcher should run only once. + // + for (;;) { + // + // This is the PEIM search loop. It will scan through all PEIMs it can find + // looking for PEIMs to dispatch, and will dipatch them if they have not + // already been dispatched and all of their dependencies are met. + // If no more PEIMs can be found in this pass through all known FVs, + // then it will break out of this loop. + // + for (;;) { + + Status = FindNextPeim ( + &PrivateData->PS, + DispatchData->CurrentFvAddress, + &DispatchData->CurrentPeimAddress + ); + + // + // If we found a PEIM, check if it is dispatched. If so, go to the + // next PEIM. If not, dispatch it if its dependencies are satisfied. + // If its dependencies are not satisfied, go to the next PEIM. + // + if (Status == EFI_SUCCESS) { + + DEBUG_CODE ( + + // + // Fill list of found Peims for later list of those not installed + // + CopyMem ( + &DebugFoundPeimList[DispatchData->CurrentPeim], + &DispatchData->CurrentPeimAddress->Name, + sizeof (EFI_GUID) + ); + + ); + + if (!Dispatched ( + DispatchData->CurrentPeim, + DispatchData->DispatchedPeimBitMap + )) { + if (DepexSatisfied (&PrivateData->PS, DispatchData->CurrentPeimAddress)) { + Status = PeiLoadImage ( + &PrivateData->PS, + DispatchData->CurrentPeimAddress, + &TempPtr.Raw + ); + if (Status == EFI_SUCCESS) { + + // + // The PEIM has its dependencies satisfied, and its entry point + // has been found, so invoke it. + // + PERF_START ( + (VOID *) (UINTN) (DispatchData->CurrentPeimAddress), + "PEIM", + NULL, + 0 + ); + + // + // BUGBUG: Used to be EFI_PEI_REPORT_STATUS_CODE_CODE + // + ExtendedData.Handle = (EFI_HANDLE)DispatchData->CurrentPeimAddress; + + REPORT_STATUS_CODE_WITH_EXTENDED_DATA ( + EFI_PROGRESS_CODE, + EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_BEGIN, + (VOID *)(&ExtendedData), + sizeof (ExtendedData) + ); + + // + // Is this a authentic image + // + Status = VerifyPeim ( + &PrivateData->PS, + DispatchData->CurrentPeimAddress + ); + + if (Status != EFI_SECURITY_VIOLATION) { + + Status = TempPtr.PeimEntry ( + DispatchData->CurrentPeimAddress, + &PrivateData->PS + ); + } + + REPORT_STATUS_CODE_WITH_EXTENDED_DATA ( + EFI_PROGRESS_CODE, + EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_END, + (VOID *)(&ExtendedData), + sizeof (ExtendedData) + ); + + PERF_END ((VOID *) (UINTN) (DispatchData->CurrentPeimAddress), "PEIM", NULL, 0); + + // + // Mark the PEIM as dispatched so we don't attempt to run it again + // + SetDispatched ( + &PrivateData->PS, + DispatchData->CurrentPeim, + &DispatchData->DispatchedPeimBitMap + ); + + // + // Process the Notify list and dispatch any notifies for + // newly installed PPIs. + // + ProcessNotifyList (&PrivateData->PS); + + // + // If real system memory was discovered and installed by this + // PEIM, switch the stacks to the new memory. Since we are + // at dispatch level, only the Core's private data is preserved, + // nobody else should have any data on the stack. + // + if (PrivateData->SwitchStackSignal) { + TempPtr.PeiCore = (PEI_CORE_ENTRY_POINT)PeiCore; + PrivateDataInMem = (UINTN) TransferOldDataToNewDataRange (PrivateData); + ASSERT (PrivateDataInMem != 0); + // + //Subtract 0x10 from the 4th parameter indicating the new stack base, + //in order to provide buffer protection against possible illegal stack + //access that might corrupt the stack. + // + SwitchStack ( + (SWITCH_STACK_ENTRY_POINT)(UINTN)TempPtr.Raw, + PeiStartupDescriptor, + (VOID*)PrivateDataInMem, + (VOID*)((UINTN)PrivateData->StackBase + (UINTN)PrivateData->StackSize) + ); + } + } + } + } + DispatchData->CurrentPeim++; + continue; + + } else { + + // + // If we could not find another PEIM in the current FV, go try + // the FindFv PPI to look in other FVs for more PEIMs. If we can + // not locate the FindFv PPI, or if the FindFv PPI can not find + // anymore FVs, then exit the PEIM search loop. + // + if (DispatchData->FindFv == NULL) { + Status = PeiCoreLocatePpi ( + &gEfiFindFvPpiGuid, + 0, + NULL, + (VOID **)&DispatchData->FindFv + ); + if (Status != EFI_SUCCESS) { + break; + } + } + NextFvFound = FALSE; + while (!NextFvFound) { + Status = DispatchData->FindFv->FindFv ( + DispatchData->FindFv, + &PrivateData->PS, + &DispatchData->CurrentFv, + &NextFvAddress + ); + // + // if there is no next fv, get out of this loop of finding FVs + // + if (Status != EFI_SUCCESS) { + break; + } + // + // don't process the default Fv again. (we don't know the order in which the hobs were created) + // + if ((NextFvAddress != DefaultFvAddress) && + (NextFvAddress != DispatchData->CurrentFvAddress)) { + + // + // VerifyFv() is currently returns SUCCESS all the time, add code to it to + // actually verify the given FV + // + Status = VerifyFv (NextFvAddress); + if (Status == EFI_SUCCESS) { + NextFvFound = TRUE; + DispatchData->CurrentFvAddress = NextFvAddress; + DispatchData->CurrentPeimAddress = NULL; + // + // current PRIM number (CurrentPeim) must continue as is, don't reset it here + // + } + } + } + // + // if there is no next fv, get out of this loop of dispatching PEIMs + // + if (!NextFvFound) { + break; + } + // + // continue in the inner for(;;) loop with a new FV; + // + } + } + + // + // If all the PEIMs that we have found have been dispatched, then + // there is nothing left to dispatch and we don't need to go search + // through all PEIMs again. + // + if ((~(DispatchData->DispatchedPeimBitMap) & + ((1 << DispatchData->CurrentPeim)-1)) == 0) { + break; + } + + // + // Check if no more PEIMs that depex was satisfied + // + if (DispatchData->DispatchedPeimBitMap == DispatchData->PreviousPeimBitMap) { + break; + } + + // + // Case when Depex is not satisfied and has to traverse the list again + // + DispatchData->CurrentPeim = 0; + DispatchData->CurrentPeimAddress = 0; + DispatchData->PreviousPeimBitMap = DispatchData->DispatchedPeimBitMap; + + // + // don't go back to the loop without making sure that the CurrentFvAddress is the + // same as the 1st (or default) FV we started with. otherwise we will interpret the bimap wrongly and + // mess it up, always start processing the PEIMs from the default FV just like in the first time around. + // + DispatchData->CurrentFv = 0; + DispatchData->CurrentFvAddress = DefaultFvAddress; + } + + DEBUG_CODE ( + // + // Debug data for uninstalled Peim list + // + UINT32 DebugNotDispatchedBitmap; + UINT8 DebugFoundPeimPoint; + + DebugFoundPeimPoint = 0; + // + // Get bitmap of Peims that were not dispatched, + // + + DebugNotDispatchedBitmap = ((DispatchData->DispatchedPeimBitMap) ^ ((1 << DispatchData->CurrentPeim)-1)); + // + // Scan bitmap of Peims not installed and print GUIDS + // + while (DebugNotDispatchedBitmap != 0) { + if ((DebugNotDispatchedBitmap & 1) != 0) { + DEBUG ((EFI_D_INFO, "WARNING -> InstallPpi: Not Installed: %g\n", + &DebugFoundPeimList[DebugFoundPeimPoint] + )); + } + DebugFoundPeimPoint++; + DebugNotDispatchedBitmap >>= 1; + } + + ); + + return EFI_NOT_FOUND; +} + +VOID +InitializeDispatcherData ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_CORE_INSTANCE *OldCoreData, + IN EFI_PEI_STARTUP_DESCRIPTOR *PeiStartupDescriptor + ) +/*++ + +Routine Description: + + Initialize the Dispatcher's data members + +Arguments: + + PeiServices - The PEI core services table. + OldCoreData - Pointer to old core data (before switching stack). + NULL if being run in non-permament memory mode. + PeiStartupDescriptor - Information and services provided by SEC phase. + +Returns: + + None. + +--*/ +{ + PEI_CORE_INSTANCE *PrivateData; + + PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices); + + if (OldCoreData == NULL) { + PrivateData->DispatchData.CurrentFvAddress = (EFI_FIRMWARE_VOLUME_HEADER *) PeiStartupDescriptor->BootFirmwareVolume; + PrivateData->DispatchData.BootFvAddress = (EFI_FIRMWARE_VOLUME_HEADER *) PeiStartupDescriptor->BootFirmwareVolume; + } else { + + // + // Current peim has been dispatched, but not count + // + PrivateData->DispatchData.CurrentPeim = (UINT8)(OldCoreData->DispatchData.CurrentPeim + 1); + } + + return; +} + + +BOOLEAN +Dispatched ( + IN UINT8 CurrentPeim, + IN UINT32 DispatchedPeimBitMap + ) +/*++ + +Routine Description: + + This routine checks to see if a particular PEIM has been dispatched during + the PEI core dispatch. + +Arguments: + CurrentPeim - The PEIM/FV in the bit array to check. + DispatchedPeimBitMap - Bit array, each bit corresponds to a PEIM/FV. + +Returns: + TRUE - PEIM already dispatched + FALSE - Otherwise + +--*/ +{ + return (BOOLEAN)((DispatchedPeimBitMap & (1 << CurrentPeim)) != 0); +} + +VOID +SetDispatched ( + IN EFI_PEI_SERVICES **PeiServices, + IN UINT8 CurrentPeim, + OUT UINT32 *DispatchedPeimBitMap + ) +/*++ + +Routine Description: + + This routine sets a PEIM as having been dispatched once its entry + point has been invoked. + +Arguments: + + PeiServices - The PEI core services table. + CurrentPeim - The PEIM/FV in the bit array to check. + DispatchedPeimBitMap - Bit array, each bit corresponds to a PEIM/FV. + +Returns: + None + +--*/ +{ + // + // Check if the total number of PEIMs exceed the bitmap. + // CurrentPeim is 0-based + // + DEBUG_CODE ( + if (CurrentPeim > (sizeof (*DispatchedPeimBitMap) * 8 - 1)) { + ASSERT_EFI_ERROR (EFI_OUT_OF_RESOURCES); + } + ); + + *DispatchedPeimBitMap |= (1 << CurrentPeim); + return; +} + +BOOLEAN +DepexSatisfied ( + IN EFI_PEI_SERVICES **PeiServices, + IN VOID *CurrentPeimAddress + ) +/*++ + +Routine Description: + + This routine parses the Dependency Expression, if available, and + decides if the module can be executed. + +Arguments: + PeiServices - The PEI Service Table + CurrentPeimAddress - Address of the PEIM Firmware File under investigation + +Returns: + TRUE - Can be dispatched + FALSE - Cannot be dispatched + +--*/ +{ + EFI_STATUS Status; + INT8 *DepexData; + BOOLEAN Runnable; + + Status = PeiCoreFfsFindSectionData ( + EFI_SECTION_PEI_DEPEX, + CurrentPeimAddress, + (VOID **)&DepexData + ); + // + // If there is no DEPEX, assume the module can be executed + // + if (EFI_ERROR (Status)) { + return TRUE; + } + + // + // Evaluate a given DEPEX + // + Status = PeimDispatchReadiness ( + PeiServices, + DepexData, + &Runnable + ); + + return Runnable; +} + + +VOID * +TransferOldDataToNewDataRange ( + IN PEI_CORE_INSTANCE *PrivateData + ) +/*++ + +Routine Description: + + This routine transfers the contents of the pre-permanent memory + PEI Core private data to a post-permanent memory data location. + +Arguments: + + PrivateData - Pointer to the current PEI Core private data pre-permanent memory + +Returns: + + Pointer to the PrivateData once the private data has been transferred to permanent memory + +--*/ +{ + return BuildGuidDataHob (&gEfiPeiCorePrivateGuid, PrivateData, sizeof (PEI_CORE_INSTANCE)); +} + diff --git a/EdkModulePkg/Core/Pei/FwVol/FwVol.c b/EdkModulePkg/Core/Pei/FwVol/FwVol.c new file mode 100644 index 0000000000..d034513bb0 --- /dev/null +++ b/EdkModulePkg/Core/Pei/FwVol/FwVol.c @@ -0,0 +1,474 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FwVol.c + +Abstract: + + Pei Core Firmware File System service routines. + +--*/ + +#include + +#define GETOCCUPIEDSIZE(ActualSize, Alignment) \ + (ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1)) + +STATIC +EFI_FFS_FILE_STATE +GetFileState( + IN UINT8 ErasePolarity, + IN EFI_FFS_FILE_HEADER *FfsHeader + ) +/*++ + +Routine Description: + + Returns the highest bit set of the State field + +Arguments: + + ErasePolarity - Erase Polarity as defined by EFI_FVB_ERASE_POLARITY + in the Attributes field. + FfsHeader - Pointer to FFS File Header. + +Returns: + Returns the highest bit in the State field + +--*/ +{ + EFI_FFS_FILE_STATE FileState; + EFI_FFS_FILE_STATE HighestBit; + + FileState = FfsHeader->State; + + if (ErasePolarity != 0) { + FileState = (EFI_FFS_FILE_STATE)~FileState; + } + + HighestBit = 0x80; + while (HighestBit != 0 && (HighestBit & FileState) == 0) { + HighestBit >>= 1; + } + + return HighestBit; +} + +STATIC +UINT8 +CalculateHeaderChecksum ( + IN EFI_FFS_FILE_HEADER *FileHeader + ) +/*++ + +Routine Description: + + Calculates the checksum of the header of a file. + +Arguments: + + FileHeader - Pointer to FFS File Header. + +Returns: + Checksum of the header. + + The header is zero byte checksum. + - Zero means the header is good. + - Non-zero means the header is bad. + + +Bugbug: For PEI performance reason, we comments this code at this time. +--*/ +{ + UINT8 *ptr; + UINTN Index; + UINT8 Sum; + + Sum = 0; + ptr = (UINT8 *)FileHeader; + + for (Index = 0; Index < sizeof(EFI_FFS_FILE_HEADER) - 3; Index += 4) { + Sum = (UINT8)(Sum + ptr[Index]); + Sum = (UINT8)(Sum + ptr[Index+1]); + Sum = (UINT8)(Sum + ptr[Index+2]); + Sum = (UINT8)(Sum + ptr[Index+3]); + } + + for (; Index < sizeof(EFI_FFS_FILE_HEADER); Index++) { + Sum = (UINT8)(Sum + ptr[Index]); + } + + // + // State field (since this indicates the different state of file). + // + Sum = (UINT8)(Sum - FileHeader->State); + // + // Checksum field of the file is not part of the header checksum. + // + Sum = (UINT8)(Sum - FileHeader->IntegrityCheck.Checksum.File); + + return Sum; +} + +STATIC +EFI_STATUS +PeiFfsFindNextFileEx ( + IN EFI_FV_FILETYPE SearchType, + IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader, + IN OUT EFI_FFS_FILE_HEADER **FileHeader, + IN BOOLEAN Flag + ) +/*++ + +Routine Description: + 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. + +Arguments: + PeiServices - Pointer to the PEI Core Services Table. + SearchType - Filter to find only files of this type. + Type EFI_FV_FILETYPE_ALL causes no filtering to be done. + FwVolHeader - Pointer to the FV header of the volume to search. + This parameter must point to a valid FFS volume. + FileHeader - Pointer to the current file from which to begin searching. + This pointer will be updated upon return to reflect the file found. + Flag - Indicator for if this is for PEI Dispath search +Returns: + EFI_NOT_FOUND - No files matching the search criteria were found + EFI_SUCCESS + +--*/ +{ + EFI_FFS_FILE_HEADER *FfsFileHeader; + UINT32 FileLength; + UINT32 FileOccupiedSize; + UINT32 FileOffset; + UINT64 FvLength; + UINT8 ErasePolarity; + UINT8 FileState; + + + FvLength = FwVolHeader->FvLength; + if (FwVolHeader->Attributes & EFI_FVB_ERASE_POLARITY) { + ErasePolarity = 1; + } else { + ErasePolarity = 0; + } + + // + // If FileHeader is not specified (NULL) start with the first file in the + // firmware volume. Otherwise, start from the FileHeader. + // + if (*FileHeader == NULL) { + FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FwVolHeader + FwVolHeader->HeaderLength); + } else { + // + // Length is 24 bits wide so mask upper 8 bits + // FileLength is adjusted to FileOccupiedSize as it is 8 byte aligned. + // + FileLength = *(UINT32 *)(*FileHeader)->Size & 0x00FFFFFF; + FileOccupiedSize = GETOCCUPIEDSIZE(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_INVALID: + 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) { + FileLength = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF; + FileOccupiedSize = GETOCCUPIEDSIZE(FileLength, 8); + if (Flag) { + if ((FfsFileHeader->Type == EFI_FV_FILETYPE_PEIM) || + (FfsFileHeader->Type == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER)) { + + *FileHeader = FfsFileHeader; + + + return EFI_SUCCESS; + } + } else { + if ((SearchType == FfsFileHeader->Type) || + (SearchType == EFI_FV_FILETYPE_ALL)) { + + *FileHeader = FfsFileHeader; + + + return EFI_SUCCESS; + } + } + + FileOffset += FileOccupiedSize; + FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize); + } else { + ASSERT (FALSE); + return EFI_NOT_FOUND; + } + break; + + case EFI_FILE_DELETED: + FileLength = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF; + FileOccupiedSize = GETOCCUPIEDSIZE(FileLength, 8); + FileOffset += FileOccupiedSize; + FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize); + break; + + default: + return EFI_NOT_FOUND; + + } + } + + return EFI_NOT_FOUND; +} + + +EFI_STATUS +EFIAPI +PeiFfsFindSectionData ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_SECTION_TYPE SectionType, + IN EFI_FFS_FILE_HEADER *FfsFileHeader, + IN OUT VOID **SectionData + ) +/*++ + +Routine Description: + Given the input file pointer, search for the next matching section in the + FFS volume. + +Arguments: + PeiServices - Pointer to the PEI Core Services Table. + SearchType - Filter to find only sections of this type. + FfsFileHeader - Pointer to the current file to search. + SectionData - Pointer to the Section matching SectionType in FfsFileHeader. + - NULL if section not found + +Returns: + EFI_NOT_FOUND - No files matching the search criteria were found + EFI_SUCCESS + +--*/ +{ + UINT32 FileSize; + EFI_COMMON_SECTION_HEADER *Section; + UINT32 SectionLength; + UINT32 ParsedLength; + + + // + // Size is 24 bits wide so mask upper 8 bits. + // Does not include FfsFileHeader header size + // FileSize is adjusted to FileOccupiedSize as it is 8 byte aligned. + // + Section = (EFI_COMMON_SECTION_HEADER *)(FfsFileHeader + 1); + FileSize = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF; + FileSize -= sizeof(EFI_FFS_FILE_HEADER); + + *SectionData = NULL; + ParsedLength = 0; + while (ParsedLength < FileSize) { + if (Section->Type == SectionType) { + *SectionData = (VOID *)(Section + 1); + + + return EFI_SUCCESS; + } + // + // Size is 24 bits wide so mask upper 8 bits. + // SectionLength is adjusted it is 4 byte aligned. + // Go to the next section + // + SectionLength = *(UINT32 *)Section->Size & 0x00FFFFFF; + SectionLength = GETOCCUPIEDSIZE (SectionLength, 4); + ASSERT (SectionLength != 0); + ParsedLength += SectionLength; + Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength); + } + + return EFI_NOT_FOUND; + +} + + +EFI_STATUS +FindNextPeim ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader, + IN OUT EFI_FFS_FILE_HEADER **PeimFileHeader + ) +/*++ + +Routine Description: + Given the input file pointer, search for the next matching file in the + FFS volume. The search starts from FileHeader inside + the Firmware Volume defined by FwVolHeader. + +Arguments: + PeiServices - Pointer to the PEI Core Services Table. + + FwVolHeader - Pointer to the FV header of the volume to search. + This parameter must point to a valid FFS volume. + + PeimFileHeader - Pointer to the current file from which to begin searching. + This pointer will be updated upon return to reflect the file found. + +Returns: + EFI_NOT_FOUND - No files matching the search criteria were found + EFI_SUCCESS + +--*/ +{ + return PeiFfsFindNextFileEx ( + 0, + FwVolHeader, + PeimFileHeader, + TRUE + ); +} + +EFI_STATUS +EFIAPI +PeiFfsFindNextFile ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_FV_FILETYPE SearchType, + IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader, + IN OUT EFI_FFS_FILE_HEADER **FileHeader + ) +/*++ + +Routine Description: + 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. + +Arguments: + PeiServices - Pointer to the PEI Core Services Table. + + SearchType - Filter to find only files of this type. + Type EFI_FV_FILETYPE_ALL causes no filtering to be done. + + FwVolHeader - Pointer to the FV header of the volume to search. + This parameter must point to a valid FFS volume. + + FileHeader - Pointer to the current file from which to begin searching. + This pointer will be updated upon return to reflect the file found. + +Returns: + EFI_NOT_FOUND - No files matching the search criteria were found + EFI_SUCCESS + +--*/ +{ + return PeiFfsFindNextFileEx ( + SearchType, + FwVolHeader, + FileHeader, + FALSE + ); +} + +EFI_STATUS +EFIAPI +PeiFvFindNextVolume ( + IN EFI_PEI_SERVICES **PeiServices, + IN UINTN Instance, + IN OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader + ) +/*++ + +Routine Description: + + Return the BFV location + + BugBug -- Move this to the location of this code to where the + other FV and FFS support code lives. + Also, update to use FindFV for instances #'s >= 1. + +Arguments: + + PeiServices - The PEI core services table. + Instance - Instance of FV to find + FwVolHeader - Pointer to contain the data to return + +Returns: + Pointer to the Firmware Volume instance requested + + EFI_INVALID_PARAMETER - FwVolHeader is NULL + + EFI_SUCCESS - Firmware volume instance successfully found. + +--*/ +{ + PEI_CORE_INSTANCE *PrivateData; + EFI_STATUS Status; + EFI_PEI_FIND_FV_PPI *FindFvPpi; + UINT8 LocalInstance; + + + LocalInstance = (UINT8) Instance; + + Status = EFI_SUCCESS; + PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices); + + if (FwVolHeader == NULL) { + + return EFI_INVALID_PARAMETER; + } + + if (Instance == 0) { + *FwVolHeader = PrivateData->DispatchData.BootFvAddress; + + + return Status; + } else { + // + // Locate all instances of FindFV + // Alternately, could use FV HOBs, but the PPI is cleaner + // + Status = PeiCoreLocatePpi ( + &gEfiFindFvPpiGuid, + 0, + NULL, + (VOID **)&FindFvPpi + ); + + if (Status != EFI_SUCCESS) { + Status = EFI_NOT_FOUND; + } else { + Status = FindFvPpi->FindFv ( + FindFvPpi, + PeiServices, + &LocalInstance, + FwVolHeader + ); + + } + } + return Status; +} diff --git a/EdkModulePkg/Core/Pei/Hob/Hob.c b/EdkModulePkg/Core/Pei/Hob/Hob.c new file mode 100644 index 0000000000..6117827522 --- /dev/null +++ b/EdkModulePkg/Core/Pei/Hob/Hob.c @@ -0,0 +1,189 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Hob.c + +Abstract: + + EFI PEI Core HOB services + +--*/ + +#include + +EFI_STATUS +EFIAPI +PeiGetHobList ( + IN EFI_PEI_SERVICES **PeiServices, + IN OUT VOID **HobList + ) +/*++ + +Routine Description: + + Gets the pointer to the HOB List. + +Arguments: + + PeiServices - The PEI core services table. + HobList - Pointer to the HOB List. + +Returns: + + EFI_SUCCESS - Get the pointer of HOB List + EFI_NOT_AVAILABLE_YET - the HOB List is not yet published + EFI_INVALID_PARAMETER - HobList is NULL (in debug mode) + +--*/ +{ + PEI_CORE_INSTANCE *PrivateData; + + + // + // Only check this parameter in debug mode + // + + DEBUG_CODE ( + if (HobList == NULL) { + return EFI_INVALID_PARAMETER; + } + ); + + PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices); + + *HobList = PrivateData->HobList.Raw; + + + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +PeiCreateHob ( + IN EFI_PEI_SERVICES **PeiServices, + IN UINT16 Type, + IN UINT16 Length, + IN OUT VOID **Hob + ) +/*++ + +Routine Description: + + Add a new HOB to the HOB List. + +Arguments: + + PeiServices - The PEI core services table. + Type - Type of the new HOB. + Length - Length of the new HOB to allocate. + Hob - Pointer to the new HOB. + +Returns: + + Status - EFI_SUCCESS + - EFI_INVALID_PARAMETER if Hob is NULL + - EFI_NOT_AVAILABLE_YET if HobList is still not available. + - EFI_OUT_OF_RESOURCES if there is no more memory to grow the Hoblist. + +--*/ +{ + 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; + + Length = (UINT16)((Length + 0x7) & (~0x7)); + + FreeMemory = HandOffHob->EfiFreeMemoryTop - + HandOffHob->EfiFreeMemoryBottom; + + if (FreeMemory < Length) { + 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 = sizeof(EFI_HOB_GENERIC_HEADER); + HobEnd->Reserved = 0; + HobEnd++; + HandOffHob->EfiFreeMemoryBottom = (EFI_PHYSICAL_ADDRESS) (UINTN) HobEnd; + + + return EFI_SUCCESS; +} + + +EFI_STATUS +PeiCoreBuildHobHandoffInfoTable ( + IN EFI_BOOT_MODE BootMode, + IN EFI_PHYSICAL_ADDRESS MemoryBegin, + IN UINT64 MemoryLength + ) +/*++ + +Routine Description: + + Builds a Handoff Information Table HOB + +Arguments: + + BootMode - Current Bootmode + MemoryBegin - Start Memory Address. + MemoryLength - Length of Memory. + +Returns: + + EFI_SUCCESS + +--*/ +{ + 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 = sizeof(EFI_HOB_HANDOFF_INFO_TABLE); + Hob->Header.Reserved = 0; + + HobEnd->HobType = EFI_HOB_TYPE_END_OF_HOB_LIST; + HobEnd->HobLength = 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/EdkModulePkg/Core/Pei/Image/Image.c b/EdkModulePkg/Core/Pei/Image/Image.c new file mode 100644 index 0000000000..74286cff31 --- /dev/null +++ b/EdkModulePkg/Core/Pei/Image/Image.c @@ -0,0 +1,237 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Image.c + +Abstract: + + Pei Core Load Image Support + +--*/ + +#include + +EFI_STATUS +PeiLoadImage ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_FFS_FILE_HEADER *PeimFileHeader, + OUT VOID **EntryPoint + ) +/*++ + +Routine Description: + + Routine for loading file image. + +Arguments: + + PeiServices - The PEI core services table. + PeimFileHeader - Pointer to the FFS file header of the image. + EntryPoint - Pointer to entry point of specified image file for output. + +Returns: + + Status - EFI_SUCCESS - Image is successfully loaded. + EFI_NOT_FOUND - Fail to locate necessary PPI + Others - Fail to load file. + +--*/ +{ + EFI_STATUS Status; + VOID *Pe32Data; + EFI_PEI_FV_FILE_LOADER_PPI *FvLoadFilePpi; +//#ifdef EFI_NT_EMULATOR +// EFI_PEI_PPI_DESCRIPTOR *PpiDescriptor; +// NT_PEI_LOAD_FILE_PPI *PeiNtService; +//#endif + EFI_PHYSICAL_ADDRESS ImageAddress; + UINT64 ImageSize; + EFI_PHYSICAL_ADDRESS ImageEntryPoint; + EFI_TE_IMAGE_HEADER *TEImageHeader; + + *EntryPoint = NULL; + TEImageHeader = NULL; + + // + // Try to find a PE32 section. + // + Status = PeiCoreFfsFindSectionData ( + EFI_SECTION_PE32, + PeimFileHeader, + &Pe32Data + ); + // + // If we didn't find a PE32 section, try to find a TE section. + // + if (EFI_ERROR (Status)) { + Status = PeiCoreFfsFindSectionData ( + EFI_SECTION_TE, + PeimFileHeader, + (VOID **) &TEImageHeader + ); + if (EFI_ERROR (Status) || TEImageHeader == NULL) { + // + // There was not a PE32 or a TE section, so assume that it's a Compressed section + // and use the LoadFile + // + Status = PeiCoreLocatePpi ( + &gEfiPeiFvFileLoaderPpiGuid, + 0, + NULL, + (VOID **)&FvLoadFilePpi + ); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + Status = FvLoadFilePpi->FvLoadFile ( + FvLoadFilePpi, + PeimFileHeader, + &ImageAddress, + &ImageSize, + &ImageEntryPoint + ); + + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + // + // Retrieve the entry point from the PE/COFF image header + // + Status = PeCoffLoaderGetEntryPoint ((VOID *)(UINTN)ImageAddress, EntryPoint); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + } else { + // + // Retrieve the entry point from the TE image header + // + ImageAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) TEImageHeader; + *EntryPoint = (VOID *)((UINTN) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) + + TEImageHeader->AddressOfEntryPoint - TEImageHeader->StrippedSize); + } + } else { + // + // Retrieve the entry point from the PE/COFF image header + // + ImageAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) Pe32Data; + Status = PeCoffLoaderGetEntryPoint (Pe32Data, EntryPoint); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + } + + // + // Print debug message: Loading PEIM at 0x12345678 EntryPoint=0x12345688 Driver.efi + // + DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%08x EntryPoint=0x%08x ", Pe32Data, *EntryPoint)); + DEBUG_CODE ( + EFI_IMAGE_DATA_DIRECTORY * DirectoryEntry; + EFI_IMAGE_DEBUG_DIRECTORY_ENTRY * DebugEntry; + UINTN DirCount; + UINTN Index; + UINTN Index1; + BOOLEAN FileNameFound; + CHAR8 *AsciiString; + CHAR8 AsciiBuffer[512]; + VOID *CodeViewEntryPointer; + INTN TEImageAdjust; + EFI_IMAGE_DOS_HEADER *DosHeader; + EFI_IMAGE_NT_HEADERS *PeHeader; + + DosHeader = (EFI_IMAGE_DOS_HEADER *)Pe32Data; + if (DosHeader->e_magic == EFI_IMAGE_DOS_SIGNATURE) { + // + // DOS image header is present, so read the PE header after the DOS image header + // + PeHeader = (EFI_IMAGE_NT_HEADERS *) ((UINTN) Pe32Data + (UINTN) ((DosHeader->e_lfanew) & 0x0ffff)); + } else { + // + // DOS image header is not present, so PE header is at the image base + // + PeHeader = (EFI_IMAGE_NT_HEADERS *) Pe32Data; + } + + // + // Find the codeview info in the image and display the file name + // being loaded. + // + // Per the PE/COFF spec, you can't assume that a given data directory + // is present in the image. You have to check the NumberOfRvaAndSizes in + // the optional header to verify a desired directory entry is there. + // + DebugEntry = NULL; + DirectoryEntry = NULL; + TEImageAdjust = 0; + if (TEImageHeader == NULL) { + if (PeHeader->OptionalHeader.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) { + DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(PeHeader->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]); + DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) ((UINTN) ImageAddress + DirectoryEntry->VirtualAddress); + } + } else { + if (TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress != 0) { + DirectoryEntry = &TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG]; + TEImageAdjust = sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize; + DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)((UINTN) TEImageHeader + + TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress + + TEImageAdjust); + } + } + + if (DebugEntry != NULL && DirectoryEntry != NULL) { + for (DirCount = 0; DirCount < DirectoryEntry->Size; DirCount++, DebugEntry++) { + if (DebugEntry->Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) { + if (DebugEntry->SizeOfData > 0) { + CodeViewEntryPointer = (VOID *) ((UINTN) DebugEntry->RVA + (UINTN) ImageAddress + (UINTN)TEImageAdjust); + switch (* (UINT32 *) CodeViewEntryPointer) { + case CODEVIEW_SIGNATURE_NB10: + AsciiString = (CHAR8 *) CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY); + break; + + case CODEVIEW_SIGNATURE_RSDS: + AsciiString = (CHAR8 *) CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY); + break; + + default: + AsciiString = NULL; + break; + } + if (AsciiString != NULL) { + FileNameFound = FALSE; + for (Index = 0, Index1 = 0; AsciiString[Index] != 0; Index++) { + if (AsciiString[Index] == '\\') { + Index1 = Index; + FileNameFound = TRUE; + } + } + + if (FileNameFound) { + for (Index = Index1 + 1; AsciiString[Index] != '.'; Index++) { + AsciiBuffer[Index - (Index1 + 1)] = AsciiString[Index]; + } + AsciiBuffer[Index - (Index1 + 1)] = 0; + DEBUG ((EFI_D_INFO | EFI_D_LOAD, "%a.efi", AsciiBuffer)); + break; + } + } + } + } + } + } + ); + + DEBUG ((EFI_D_INFO | EFI_D_LOAD, "\n")); + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Core/Pei/Ipf/IpfCpuCore.i b/EdkModulePkg/Core/Pei/Ipf/IpfCpuCore.i new file mode 100644 index 0000000000..c8a209debc --- /dev/null +++ b/EdkModulePkg/Core/Pei/Ipf/IpfCpuCore.i @@ -0,0 +1,93 @@ +//++ +// Copyright (c) 2006, Intel Corporation +// All rights reserved. This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// Module Name: +// +// IpfCpuCore.i +// +// Abstract: +// IPF CPU definitions +// +//-- + +#ifndef _IPF_CPU_CORE_ +#define _IPF_CPU_CORE_ + +#define PEI_BSP_STORE_SIZE 0x4000 +#define ResetFn 0x00 +#define MachineCheckFn 0x01 +#define InitFn 0x02 +#define RecoveryFn 0x03 +#define GuardBand 0x10 + +// +// Define hardware RSE Configuration Register +// + +// +// RS Configuration (RSC) bit field positions +// +#define RSC_MODE 0 +#define RSC_PL 2 +#define RSC_BE 4 +// +// RSC bits 5-15 reserved +// +#define RSC_MBZ0 5 +#define RSC_MBZ0_V 0x3ff +#define RSC_LOADRS 16 +#define RSC_LOADRS_LEN 14 +// +// RSC bits 30-63 reserved +// +#define RSC_MBZ1 30 +#define RSC_MBZ1_V 0x3ffffffffULL + +// +// RSC modes +// + +// +// Lazy +// +#define RSC_MODE_LY (0x0) +// +// Store intensive +// +#define RSC_MODE_SI (0x1) +// +// Load intensive +// +#define RSC_MODE_LI (0x2) +// +// Eager +// +#define RSC_MODE_EA (0x3) + +// +// RSC Endian bit values +// +#define RSC_BE_LITTLE 0 +#define RSC_BE_BIG 1 + +// +// RSC while in kernel: enabled, little endian, pl = 0, eager mode +// +#define RSC_KERNEL ((RSC_MODE_EA< +#include "IpfCpuCore.i" + +extern +SAL_RETURN_REGS +GetHandOffStatus ( + VOID + ); + +VOID +SwitchToCacheMode ( + IN PEI_CORE_INSTANCE *CoreData + ) +/*++ + +Routine Description: + + Switch the PHIT pointers to cache mode after InstallPeiMemory in CAR. + +Arguments: + + CoreData - The PEI core Private Data + +Returns: + +--*/ +{ + EFI_HOB_HANDOFF_INFO_TABLE *Phit; + + if (CoreData == NULL) { + // + // the first call with CoreData as NULL. + // + return; + } + + if ((GetHandOffStatus().r10 & 0xFF) == RecoveryFn) { + CoreData->StackBase = CoreData->StackBase & CACHE_MODE_ADDRESS_MASK; + CoreData->HobList.Raw = (UINT8 *)((UINTN)CoreData->HobList.Raw & CACHE_MODE_ADDRESS_MASK); + + // + // Change the PHIT pointer value to cache mode + // + Phit = CoreData->HobList.HandoffInformationTable; + + Phit->EfiMemoryTop = Phit->EfiMemoryTop & CACHE_MODE_ADDRESS_MASK; + Phit->EfiFreeMemoryTop = Phit->EfiFreeMemoryTop & CACHE_MODE_ADDRESS_MASK; + Phit->EfiMemoryBottom = Phit->EfiMemoryBottom & CACHE_MODE_ADDRESS_MASK; + Phit->EfiFreeMemoryBottom = Phit->EfiFreeMemoryBottom & CACHE_MODE_ADDRESS_MASK; + Phit->EfiEndOfHobList = Phit->EfiEndOfHobList & CACHE_MODE_ADDRESS_MASK; + } + + return; +} \ No newline at end of file diff --git a/EdkModulePkg/Core/Pei/Memory/MemoryServices.c b/EdkModulePkg/Core/Pei/Memory/MemoryServices.c new file mode 100644 index 0000000000..48b2b3818c --- /dev/null +++ b/EdkModulePkg/Core/Pei/Memory/MemoryServices.c @@ -0,0 +1,314 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + MemoryServices.c + +Abstract: + + EFI PEI Core memory services + +--*/ + +#include + +VOID +InitializeMemoryServices ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_STARTUP_DESCRIPTOR *PeiStartupDescriptor, + IN PEI_CORE_INSTANCE *OldCoreData + ) +/*++ + +Routine Description: + + Initialize the memory services. + +Arguments: + + PeiServices - The PEI core services table. + PeiStartupDescriptor - Information and services provided by SEC phase. + OldCoreData - Pointer to the PEI Core data. + NULL if being run in non-permament memory mode. + +Returns: + + None + +--*/ +{ + PEI_CORE_INSTANCE *PrivateData; + UINT64 SizeOfCarHeap; + + PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices); + PrivateData->SwitchStackSignal = FALSE; + + if (OldCoreData == NULL) { + + PrivateData->PeiMemoryInstalled = FALSE; + + PrivateData->BottomOfCarHeap = (VOID *) (((UINTN)(VOID *)(&PrivateData)) + & (~((PeiStartupDescriptor->SizeOfCacheAsRam) - 1))); + PrivateData->TopOfCarHeap = (VOID *)((UINTN)(PrivateData->BottomOfCarHeap) + PeiStartupDescriptor->SizeOfCacheAsRam); + // + // SizeOfCarHeap is 1/2 (arbitrary) of CacheAsRam Size. + // + SizeOfCarHeap = (UINT64) PeiStartupDescriptor->SizeOfCacheAsRam; + SizeOfCarHeap = RShiftU64 (SizeOfCarHeap, 1); + + DEBUG_CODE ( + PrivateData->SizeOfCacheAsRam = PeiStartupDescriptor->SizeOfCacheAsRam; + PrivateData->MaxTopOfCarHeap = (VOID *) ((UINTN) PrivateData->BottomOfCarHeap + (UINTN) SizeOfCarHeap); + ); + + PrivateData->HobList.Raw = PrivateData->BottomOfCarHeap; + + PeiCoreBuildHobHandoffInfoTable ( + BOOT_WITH_FULL_CONFIGURATION, + (EFI_PHYSICAL_ADDRESS) (UINTN) PrivateData->BottomOfCarHeap, + (UINTN) SizeOfCarHeap + ); + // + // Copy PeiServices from ROM to Cache in PrivateData + // + CopyMem (&(PrivateData->ServiceTableShadow), *PeiServices, sizeof (EFI_PEI_SERVICES)); + + // + // Set PS to point to ServiceTableShadow in Cache + // + PrivateData->PS = &(PrivateData->ServiceTableShadow); + } else { + // + // Set PS to point to ServiceTableShadow in Cache one time after the + // stack switched to main memory + // + PrivateData->PS = &(PrivateData->ServiceTableShadow); +} + + return; +} + +EFI_STATUS +EFIAPI +PeiInstallPeiMemory ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PHYSICAL_ADDRESS MemoryBegin, + IN UINT64 MemoryLength + ) +/*++ + +Routine Description: + + Install the permanent memory is now available. + Creates HOB (PHIT and Stack). + +Arguments: + + PeiServices - The PEI core services table. + MemoryBegin - Start of memory address. + MemoryLength - Length of memory. + +Returns: + + Status - EFI_SUCCESS + +--*/ +{ + PEI_CORE_INSTANCE *PrivateData; + EFI_HOB_HANDOFF_INFO_TABLE *OldHandOffHob; + EFI_HOB_HANDOFF_INFO_TABLE *NewHandOffHob; + UINT64 PeiStackSize; + UINT64 EfiFreeMemorySize; + EFI_PHYSICAL_ADDRESS PhysicalAddressOfOldHob; + + PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices); + + PrivateData->SwitchStackSignal = TRUE; + PrivateData->PeiMemoryInstalled = TRUE; + + PrivateData->StackBase = MemoryBegin; + + PeiStackSize = RShiftU64 (MemoryLength, 1); + if (PEI_STACK_SIZE > PeiStackSize) { + PrivateData->StackSize = PeiStackSize; + } else { + PrivateData->StackSize = PEI_STACK_SIZE; + } + + OldHandOffHob = PrivateData->HobList.HandoffInformationTable; + + PrivateData->HobList.Raw = (VOID *)((UINTN)(MemoryBegin + PrivateData->StackSize)); + NewHandOffHob = PrivateData->HobList.HandoffInformationTable; + PhysicalAddressOfOldHob = (EFI_PHYSICAL_ADDRESS) (UINTN) OldHandOffHob; + + EfiFreeMemorySize = OldHandOffHob->EfiFreeMemoryBottom - PhysicalAddressOfOldHob; + + DEBUG ((EFI_D_INFO, "HOBLIST address before memory init = 0x%08x\n", OldHandOffHob)); + DEBUG ((EFI_D_INFO, "HOBLIST address after memory init = 0x%08x\n", NewHandOffHob)); + + CopyMem ( + NewHandOffHob, + OldHandOffHob, + (UINTN)EfiFreeMemorySize + ); + + NewHandOffHob->EfiMemoryTop = MemoryBegin + MemoryLength; + NewHandOffHob->EfiFreeMemoryTop = NewHandOffHob->EfiMemoryTop; + NewHandOffHob->EfiMemoryBottom = MemoryBegin; + + NewHandOffHob->EfiFreeMemoryBottom = (UINTN)NewHandOffHob + EfiFreeMemorySize; + + NewHandOffHob->EfiEndOfHobList = (UINTN)NewHandOffHob + + (OldHandOffHob->EfiEndOfHobList - + PhysicalAddressOfOldHob); + + ConvertPpiPointers (PeiServices, OldHandOffHob, NewHandOffHob); + + BuildStackHob (PrivateData->StackBase, PrivateData->StackSize); + + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PeiAllocatePages ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT EFI_PHYSICAL_ADDRESS *Memory + ) +/*++ + +Routine Description: + + Memory allocation service on permanent memory, + not usable prior to the memory installation. + +Arguments: + + PeiServices - The PEI core services table. + MemoryType - Type of memory to allocate. + Pages - Number of pages to allocate. + Memory - Pointer of memory allocated. + +Returns: + + Status - EFI_SUCCESS The allocation was successful + EFI_INVALID_PARAMETER Only AllocateAnyAddress is supported. + EFI_NOT_AVAILABLE_YET Called with permanent memory not available + EFI_OUT_OF_RESOURCES There is not enough HOB heap to satisfy the requirement + to allocate the number of pages. + +--*/ +{ + PEI_CORE_INSTANCE *PrivateData; + EFI_PEI_HOB_POINTERS Hob; + EFI_PHYSICAL_ADDRESS Offset; + + PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices); + + // + // Check if Hob already available + // + if (!PrivateData->PeiMemoryInstalled) { + return EFI_NOT_AVAILABLE_YET; + } + + Hob.Raw = PrivateData->HobList.Raw; + + // + // Check to see if on 4k boundary + // + Offset = Hob.HandoffInformationTable->EfiFreeMemoryTop & 0xFFF; + + // + // If not aligned, make the allocation aligned. + // + if (Offset != 0) { + Hob.HandoffInformationTable->EfiFreeMemoryTop -= Offset; + } + + // + // Verify that there is sufficient memory to satisfy the allocation + // + if (Hob.HandoffInformationTable->EfiFreeMemoryTop - ((Pages * EFI_PAGE_SIZE) + sizeof (EFI_HOB_MEMORY_ALLOCATION)) < + Hob.HandoffInformationTable->EfiFreeMemoryBottom) { + return EFI_OUT_OF_RESOURCES; + } else { + // + // Update the PHIT to reflect the memory usage + // + Hob.HandoffInformationTable->EfiFreeMemoryTop -= Pages * EFI_PAGE_SIZE; + + // + // Update the value for the caller + // + *Memory = Hob.HandoffInformationTable->EfiFreeMemoryTop; + + // + // Create a memory allocation HOB. + // + BuildMemoryAllocationHob ( + Hob.HandoffInformationTable->EfiFreeMemoryTop, + Pages * EFI_PAGE_SIZE + Offset, + MemoryType + ); + + return EFI_SUCCESS; + } +} + + +EFI_STATUS +EFIAPI +PeiAllocatePool ( + IN EFI_PEI_SERVICES **PeiServices, + IN UINTN Size, + OUT VOID **Buffer + ) +/*++ + +Routine Description: + + Memory allocation service on the CAR. + +Arguments: + + PeiServices - The PEI core services table. + + Size - Amount of memory required + + Buffer - Address of pointer to the buffer + +Returns: + + Status - EFI_SUCCESS The allocation was successful + EFI_OUT_OF_RESOURCES There is not enough heap to satisfy the requirement + to allocate the requested size. + +--*/ +{ + EFI_STATUS Status; + EFI_HOB_MEMORY_POOL *Hob; + + + Status = PeiCoreCreateHob ( + EFI_HOB_TYPE_PEI_MEMORY_POOL, + (UINT16)(sizeof (EFI_HOB_MEMORY_POOL) + Size), + (VOID **)&Hob + ); + *Buffer = Hob+1; + + + return Status; +} diff --git a/EdkModulePkg/Core/Pei/PeiMain.h b/EdkModulePkg/Core/Pei/PeiMain.h new file mode 100644 index 0000000000..783fcd5867 --- /dev/null +++ b/EdkModulePkg/Core/Pei/PeiMain.h @@ -0,0 +1,1141 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PeiMain.h + +Abstract: + + Definition of Pei Core Structures and Services + +Revision History + +--*/ + +#ifndef _PEI_MAIN_H_ +#define _PEI_MAIN_H_ + +#ifdef EFI64 +#include "SalApi.h" +#endif + +// +//Build private HOB to PEI core to transfer old NEM-range data to new NEM-range +// +#define EFI_PEI_CORE_PRIVATE_GUID \ + {0xd641a0f5, 0xcb7c, 0x4846, { 0xa3, 0x80, 0x1d, 0x01, 0xb4, 0xd9, 0xe3, 0xb9 } } + +// +// Pei Core private data structures +// +typedef union { + EFI_PEI_PPI_DESCRIPTOR *Ppi; + EFI_PEI_NOTIFY_DESCRIPTOR *Notify; + VOID *Raw; +} PEI_PPI_LIST_POINTERS; + +#define PEI_STACK_SIZE 0x20000 + +#define MAX_PPI_DESCRIPTORS 64 + +typedef struct { + INTN PpiListEnd; + INTN NotifyListEnd; + INTN DispatchListEnd; + INTN LastDispatchedInstall; + INTN LastDispatchedNotify; + PEI_PPI_LIST_POINTERS PpiListPtrs[MAX_PPI_DESCRIPTORS]; +} PEI_PPI_DATABASE; + +typedef struct { + UINT8 CurrentPeim; + UINT8 CurrentFv; + UINT32 DispatchedPeimBitMap; + UINT32 PreviousPeimBitMap; + EFI_FFS_FILE_HEADER *CurrentPeimAddress; + EFI_FIRMWARE_VOLUME_HEADER *CurrentFvAddress; + EFI_FIRMWARE_VOLUME_HEADER *BootFvAddress; + EFI_PEI_FIND_FV_PPI *FindFv; +} PEI_CORE_DISPATCH_DATA; + + +// +// Pei Core private data structure instance +// + +#define PEI_CORE_HANDLE_SIGNATURE EFI_SIGNATURE_32('P','e','i','C') + +typedef struct{ + UINTN Signature; + EFI_PEI_SERVICES *PS; // Point to ServiceTableShadow + PEI_PPI_DATABASE PpiData; + PEI_CORE_DISPATCH_DATA DispatchData; + EFI_PEI_HOB_POINTERS HobList; + BOOLEAN SwitchStackSignal; + BOOLEAN PeiMemoryInstalled; + EFI_PHYSICAL_ADDRESS StackBase; + UINT64 StackSize; + VOID *BottomOfCarHeap; + VOID *TopOfCarHeap; + VOID *CpuIo; + EFI_PEI_SECURITY_PPI *PrivateSecurityPpi; + EFI_PEI_SERVICES ServiceTableShadow; + UINTN SizeOfCacheAsRam; + VOID *MaxTopOfCarHeap; +} PEI_CORE_INSTANCE; + +// +// Pei Core Instance Data Macros +// + +#define PEI_CORE_INSTANCE_FROM_PS_THIS(a) \ + CR(a, PEI_CORE_INSTANCE, PS, PEI_CORE_HANDLE_SIGNATURE) + +// +// BUGBUG: Where does this go really? +// +typedef +EFI_STATUS +(EFIAPI *PEI_CORE_ENTRY_POINT)( + IN EFI_PEI_STARTUP_DESCRIPTOR *PeiStartupDescriptor, + IN PEI_CORE_INSTANCE *OldCoreData + ); + +// +// Union of temporarily used function pointers (to save stack space) +// +typedef union { + PEI_CORE_ENTRY_POINT PeiCore; + EFI_PEIM_ENTRY_POINT 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; + + +// +// Main PEI entry +// +EFI_STATUS +EFIAPI +PeiMain ( + IN EFI_PEI_STARTUP_DESCRIPTOR *PeiStartupDescriptor + ) +/*++ + +Routine Description: + + Main entry point to Pei Core. + +Arguments: + + PeiStartupDescriptor - Information and services provided by SEC phase. + +Returns: + + This function never returns + +--*/ +; + + +EFI_STATUS +EFIAPI +PeiCore ( + IN EFI_PEI_STARTUP_DESCRIPTOR *PeiStartupDescriptor, + IN PEI_CORE_INSTANCE *OldCoreData + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + PeiStartupDescriptor - Information and services provided by SEC phase. + OldCoreData - Pointer to old core data that is used to initialize the + core's data areas. + +Returns: + + This function never returns + +--*/ +; + + +// +// Dispatcher support functions +// + +EFI_STATUS +PeimDispatchReadiness ( + IN EFI_PEI_SERVICES **PeiServices, + IN VOID *DependencyExpression, + IN OUT BOOLEAN *Runnable + ) +/*++ + +Routine Description: + + 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 poped 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). + +Arguments: + + PeiServices - Calling context. + + DependencyExpression - Pointer to a dependency expression. The Grammar adheres to + the BNF described above and is stored in postfix notation. + Runnable - is True if the driver can be scheduled and False if the driver + cannot be scheduled. This is the value that the schedulers + should use for deciding the state of the driver. + +Returns: + + Status = EFI_SUCCESS if it is a well-formed Grammar + EFI_INVALID_PARAMETER if the dependency expression overflows + the evaluation stack + EFI_INVALID_PARAMETER if the dependency expression underflows + the evaluation stack + EFI_INVALID_PARAMETER if the dependency expression is not a + well-formed Grammar. +--*/ +; + + +EFI_STATUS +PeiDispatcher ( + IN EFI_PEI_STARTUP_DESCRIPTOR *PeiStartupDescriptor, + IN PEI_CORE_INSTANCE *PrivateData, + IN PEI_CORE_DISPATCH_DATA *DispatchData + ) + +/*++ + +Routine Description: + + Conduct PEIM dispatch. + +Arguments: + + PeiStartupDescriptor - Pointer to IN EFI_PEI_STARTUP_DESCRIPTOR + PrivateData - Pointer to the private data passed in from caller + DispatchData - Pointer to PEI_CORE_DISPATCH_DATA data. + +Returns: + + EFI_SUCCESS - Successfully dispatched PEIM. + EFI_NOT_FOUND - The dispatch failed. + +--*/ +; + + +VOID +InitializeDispatcherData ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_CORE_INSTANCE *OldCoreData, + IN EFI_PEI_STARTUP_DESCRIPTOR *PeiStartupDescriptor + ) +/*++ + +Routine Description: + + Initialize the Dispatcher's data members + +Arguments: + + PeiServices - The PEI core services table. + OldCoreData - Pointer to old core data (before switching stack). + NULL if being run in non-permament memory mode. + PeiStartupDescriptor - Information and services provided by SEC phase. + + +Returns: + + None + +--*/ +; + + +EFI_STATUS +FindNextPeim ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader, + IN OUT EFI_FFS_FILE_HEADER **PeimFileHeader + ) +/*++ + +Routine Description: + Given the input file pointer, search for the next matching file in the + FFS volume. The search starts from FileHeader inside + the Firmware Volume defined by FwVolHeader. + +Arguments: + PeiServices - Pointer to the PEI Core Services Table. + + FwVolHeader - Pointer to the FV header of the volume to search. + This parameter must point to a valid FFS volume. + + PeimFileHeader - Pointer to the current file from which to begin searching. + This pointer will be updated upon return to reflect the file found. + +Returns: + EFI_NOT_FOUND - No files matching the search criteria were found + EFI_SUCCESS + +--*/ +; + +BOOLEAN +Dispatched ( + IN UINT8 CurrentPeim, + IN UINT32 DispatchedPeimBitMap + ) +/*++ + +Routine Description: + + This routine checks to see if a particular PEIM has been dispatched during + the PEI core dispatch. + +Arguments: + CurrentPeim - The PEIM/FV in the bit array to check. + DispatchedPeimBitMap - Bit array, each bit corresponds to a PEIM/FV. + +Returns: + TRUE if PEIM already dispatched + FALSE if not + +--*/ +; + +VOID +SetDispatched ( + IN EFI_PEI_SERVICES **PeiServices, + IN UINT8 CurrentPeim, + OUT UINT32 *DispatchedPeimBitMap + ) +/*++ + +Routine Description: + + This routine sets a PEIM as having been dispatched once its entry + point has been invoked. + +Arguments: + + PeiServices - The PEI core services table. + CurrentPeim - The PEIM/FV in the bit array to check. + DispatchedPeimBitMap - Bit array, each bit corresponds to a PEIM/FV. + +Returns: + None + +--*/ +; + +BOOLEAN +DepexSatisfied ( + IN EFI_PEI_SERVICES **PeiServices, + IN VOID *CurrentPeimAddress + ) +/*++ + +Routine Description: + + This routine parses the Dependency Expression, if available, and + decides if the module can be executed. + +Arguments: + PeiServices - The PEI Service Table + CurrentPeimAddress - Address of the PEIM Firmware File under investigation + +Returns: + TRUE - Can be dispatched + FALSE - Cannot be dispatched + +--*/ +; + +#ifdef EFI64 + // + // In Ipf we should make special changes for the PHIT pointers to support + // recovery boot in cache mode. + // +#define SWITCH_TO_CACHE_MODE(CoreData) SwitchToCacheMode(CoreData) +#define CACHE_MODE_ADDRESS_MASK 0x7FFFFFFFFFFFFFFFULL +VOID +SwitchToCacheMode ( + IN PEI_CORE_INSTANCE *CoreData +) +/*++ + +Routine Description: + + Switch the PHIT pointers to cache mode after InstallPeiMemory in CAR. + +Arguments: + + CoreData - The PEI core Private Data + +Returns: + +--*/ +; + +#else + +#define SWITCH_TO_CACHE_MODE(CoreData) + +#endif + +// +// PPI support functions +// +VOID +InitializePpiServices ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_CORE_INSTANCE *OldCoreData + ) +/*++ + +Routine Description: + + Initialize PPI services. + +Arguments: + + PeiServices - The PEI core services table. + OldCoreData - Pointer to the PEI Core data. + NULL if being run in non-permament memory mode. + +Returns: + Nothing + +--*/ +; + +VOID +ConvertPpiPointers ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_HOB_HANDOFF_INFO_TABLE *OldHandOffHob, + IN EFI_HOB_HANDOFF_INFO_TABLE *NewHandOffHob + ) +/*++ + +Routine Description: + + Migrate the Hob list from the CAR stack to PEI installed memory. + +Arguments: + + PeiServices - The PEI core services table. + OldHandOffHob - The old handoff HOB list. + NewHandOffHob - The new handoff HOB list. + +Returns: + +--*/ +; + +EFI_STATUS +EFIAPI +PeiInstallPpi ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_PPI_DESCRIPTOR *PpiList + ) +/*++ + +Routine Description: + + Install PPI services. + +Arguments: + + PeiServices - Pointer to the PEI Service Table + PpiList - Pointer to a list of PEI PPI Descriptors. + +Returns: + + EFI_SUCCESS - if all PPIs in PpiList are successfully installed. + EFI_INVALID_PARAMETER - if PpiList is NULL pointer + EFI_INVALID_PARAMETER - if any PPI in PpiList is not valid + EFI_OUT_OF_RESOURCES - if there is no more memory resource to install PPI + +--*/ +; + +EFI_STATUS +EFIAPI +PeiReInstallPpi ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_PPI_DESCRIPTOR *OldPpi, + IN EFI_PEI_PPI_DESCRIPTOR *NewPpi + ) +/*++ + +Routine Description: + + Re-Install PPI services. + +Arguments: + + PeiServices - Pointer to the PEI Service Table + OldPpi - Pointer to the old PEI PPI Descriptors. + NewPpi - Pointer to the new PEI PPI Descriptors. + +Returns: + + EFI_SUCCESS - if the operation was successful + EFI_INVALID_PARAMETER - if OldPpi or NewPpi is NULL + EFI_INVALID_PARAMETER - if NewPpi is not valid + EFI_NOT_FOUND - if the PPI was not in the database + +--*/ +; + +EFI_STATUS +EFIAPI +PeiLocatePpi ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_GUID *Guid, + IN UINTN Instance, + IN OUT EFI_PEI_PPI_DESCRIPTOR **PpiDescriptor, + IN OUT VOID **Ppi + ) +/*++ + +Routine Description: + + Locate a given named PPI. + +Arguments: + + PeiServices - Pointer to the PEI Service Table + Guid - Pointer to GUID of the PPI. + Instance - Instance Number to discover. + PpiDescriptor - Pointer to reference the found descriptor. If not NULL, + returns a pointer to the descriptor (includes flags, etc) + Ppi - Pointer to reference the found PPI + +Returns: + + Status - EFI_SUCCESS if the PPI is in the database + EFI_NOT_FOUND if the PPI is not in the database +--*/ +; + +EFI_STATUS +EFIAPI +PeiNotifyPpi ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyList + ) +/*++ + +Routine Description: + + Install a notification for a given PPI. + +Arguments: + + PeiServices - Pointer to the PEI Service Table + NotifyList - Pointer to list of Descriptors to notify upon. + +Returns: + + Status - EFI_SUCCESS if successful + EFI_OUT_OF_RESOURCES if no space in the database + EFI_INVALID_PARAMETER if not a good decriptor + +--*/ +; + +VOID +ProcessNotifyList ( + IN EFI_PEI_SERVICES **PeiServices + ) +/*++ + +Routine Description: + + Process the Notify List at dispatch level. + +Arguments: + + PeiServices - Pointer to the PEI Service Table + +Returns: + +--*/ +; + +VOID +DispatchNotify ( + IN EFI_PEI_SERVICES **PeiServices, + IN UINTN NotifyType, + IN INTN InstallStartIndex, + IN INTN InstallStopIndex, + IN INTN NotifyStartIndex, + IN INTN NotifyStopIndex + ) +/*++ + +Routine Description: + + Dispatch notifications. + +Arguments: + + PeiServices - Pointer to the PEI Service Table + NotifyType - Type of notify to fire. + InstallStartIndex - Install Beginning index. + InstallStopIndex - Install Ending index. + NotifyStartIndex - Notify Beginning index. + NotifyStopIndex - Notify Ending index. + +Returns: None + +--*/ +; + +// +// Boot mode support functions +// +EFI_STATUS +EFIAPI +PeiGetBootMode ( + IN EFI_PEI_SERVICES **PeiServices, + IN OUT EFI_BOOT_MODE *BootMode + ) +/*++ + +Routine Description: + + This service enables PEIMs to ascertain the present value of the boot mode. + +Arguments: + + PeiServices - The PEI core services table. + BootMode - A pointer to contain the value of the boot mode. + +Returns: + + EFI_SUCCESS - The boot mode was returned successfully. + EFI_INVALID_PARAMETER - BootMode is NULL. + +--*/ +; + +EFI_STATUS +EFIAPI +PeiSetBootMode ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_BOOT_MODE BootMode + ) +/*++ + +Routine Description: + + This service enables PEIMs to update the boot mode variable. + +Arguments: + + PeiServices - The PEI core services table. + BootMode - The value of the boot mode to set. + +Returns: + + EFI_SUCCESS - The value was successfully updated + +--*/ +; + +// +// Security support functions +// +VOID +InitializeSecurityServices ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_CORE_INSTANCE *OldCoreData + ) +/*++ + +Routine Description: + + Initialize the security services. + +Arguments: + + PeiServices - The PEI core services table. + OldCoreData - Pointer to the old core data. + NULL if being run in non-permament memory mode. +Returns: + + None + +--*/ +; + +EFI_STATUS +VerifyFv ( + IN EFI_FIRMWARE_VOLUME_HEADER *CurrentFvAddress + ) +/*++ + +Routine Description: + + Provide a callout to the OEM FV verification service. + +Arguments: + + CurrentFvAddress - Pointer to the FV under investigation. + +Returns: + + Status - EFI_SUCCESS + +--*/ +; + + +EFI_STATUS +VerifyPeim ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_FFS_FILE_HEADER *CurrentPeimAddress + ) +/*++ + +Routine Description: + + Provide a callout to the security verification service. + +Arguments: + + PeiServices - The PEI core services table. + CurrentPeimAddress - Pointer to the Firmware File under investigation. + +Returns: + + EFI_SUCCESS - Image is OK + EFI_SECURITY_VIOLATION - Image is illegal + +--*/ +; + + +EFI_STATUS +EFIAPI +PeiGetHobList ( + IN EFI_PEI_SERVICES **PeiServices, + IN OUT VOID **HobList + ) +/*++ + +Routine Description: + + Gets the pointer to the HOB List. + +Arguments: + + PeiServices - The PEI core services table. + HobList - Pointer to the HOB List. + +Returns: + + EFI_SUCCESS - Get the pointer of HOB List + EFI_NOT_AVAILABLE_YET - the HOB List is not yet published + EFI_INVALID_PARAMETER - HobList is NULL (in debug mode) + +--*/ +; + +EFI_STATUS +EFIAPI +PeiCreateHob ( + IN EFI_PEI_SERVICES **PeiServices, + IN UINT16 Type, + IN UINT16 Length, + IN OUT VOID **Hob + ) +/*++ + +Routine Description: + + Add a new HOB to the HOB List. + +Arguments: + + PeiServices - The PEI core services table. + Type - Type of the new HOB. + Length - Length of the new HOB to allocate. + Hob - Pointer to the new HOB. + +Returns: + + Status - EFI_SUCCESS + - EFI_INVALID_PARAMETER if Hob is NULL + - EFI_NOT_AVAILABLE_YET if HobList is still not available. + - EFI_OUT_OF_RESOURCES if there is no more memory to grow the Hoblist. + +--*/ +; + +EFI_STATUS +PeiCoreBuildHobHandoffInfoTable ( + IN EFI_BOOT_MODE BootMode, + IN EFI_PHYSICAL_ADDRESS MemoryBegin, + IN UINT64 MemoryLength + ) +/*++ + +Routine Description: + + Builds a Handoff Information Table HOB + +Arguments: + + BootMode - Current Bootmode + MemoryBegin - Start Memory Address. + MemoryLength - Length of Memory. + +Returns: + + EFI_SUCCESS + +--*/ +; + + +// +// FFS Fw Volume support functions +// +EFI_STATUS +EFIAPI +PeiFfsFindNextFile ( + IN EFI_PEI_SERVICES **PeiServices, + IN UINT8 SearchType, + IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader, + IN OUT EFI_FFS_FILE_HEADER **FileHeader + ) +/*++ + +Routine Description: + 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. + +Arguments: + PeiServices - Pointer to the PEI Core Services Table. + + SearchType - Filter to find only files of this type. + Type EFI_FV_FILETYPE_ALL causes no filtering to be done. + + FwVolHeader - Pointer to the FV header of the volume to search. + This parameter must point to a valid FFS volume. + + FileHeader - Pointer to the current file from which to begin searching. + This pointer will be updated upon return to reflect the file found. + +Returns: + EFI_NOT_FOUND - No files matching the search criteria were found + EFI_SUCCESS + +--*/ +; + +EFI_STATUS +EFIAPI +PeiFfsFindSectionData ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_SECTION_TYPE SectionType, + IN EFI_FFS_FILE_HEADER *FfsFileHeader, + IN OUT VOID **SectionData + ) +/*++ + +Routine Description: + Given the input file pointer, search for the next matching section in the + FFS volume. + +Arguments: + PeiServices - Pointer to the PEI Core Services Table. + SearchType - Filter to find only sections of this type. + FfsFileHeader - Pointer to the current file to search. + SectionData - Pointer to the Section matching SectionType in FfsFileHeader. + - NULL if section not found + +Returns: + EFI_NOT_FOUND - No files matching the search criteria were found + EFI_SUCCESS + +--*/ +; + +EFI_STATUS +EFIAPI +PeiFvFindNextVolume ( + IN EFI_PEI_SERVICES **PeiServices, + IN UINTN Instance, + IN OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader + ) +/*++ + +Routine Description: + + Return the BFV location + + BugBug -- Move this to the location of this code to where the + other FV and FFS support code lives. + Also, update to use FindFV for instances #'s >= 1. + +Arguments: + + PeiServices - The PEI core services table. + Instance - Instance of FV to find + FwVolHeader - Pointer to contain the data to return + +Returns: + Pointer to the Firmware Volume instance requested + + EFI_INVALID_PARAMETER - FwVolHeader is NULL + + EFI_SUCCESS - Firmware volume instance successfully found. + +--*/ +; + +// +// Memory support functions +// +VOID +InitializeMemoryServices ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_STARTUP_DESCRIPTOR *PeiStartupDescriptor, + IN PEI_CORE_INSTANCE *OldCoreData + ) +/*++ + +Routine Description: + + Initialize the memory services. + +Arguments: + + PeiServices - The PEI core services table. + PeiStartupDescriptor - Information and services provided by SEC phase. + OldCoreData - Pointer to the PEI Core data. + NULL if being run in non-permament memory mode. + +Returns: + + None + +--*/ +; + +EFI_STATUS +EFIAPI +PeiInstallPeiMemory ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PHYSICAL_ADDRESS MemoryBegin, + IN UINT64 MemoryLength + ) +/*++ + +Routine Description: + + Install the permanent memory is now available. + Creates HOB (PHIT and Stack). + +Arguments: + + PeiServices - The PEI core services table. + MemoryBegin - Start of memory address. + MemoryLength - Length of memory. + +Returns: + + Status - EFI_SUCCESS + +--*/ +; + +EFI_STATUS +EFIAPI +PeiAllocatePages ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT EFI_PHYSICAL_ADDRESS *Memory + ) +/*++ + +Routine Description: + + Memory allocation service on permanent memory, + not usable prior to the memory installation. + +Arguments: + + PeiServices - The PEI core services table. + Type - Type of allocation. + MemoryType - Type of memory to allocate. + Pages - Number of pages to allocate. + Memory - Pointer of memory allocated. + +Returns: + + Status - EFI_SUCCESS The allocation was successful + EFI_INVALID_PARAMETER Only AllocateAnyAddress is supported. + EFI_NOT_AVAILABLE_YET Called with permanent memory not available + EFI_OUT_OF_RESOURCES There is not enough HOB heap to satisfy the requirement + to allocate the number of pages. + +--*/ +; + +EFI_STATUS +EFIAPI +PeiAllocatePool ( + IN EFI_PEI_SERVICES **PeiServices, + IN UINTN Size, + OUT VOID **Buffer + ) +/*++ + +Routine Description: + + Memory allocation service on the CAR. + +Arguments: + + PeiServices - The PEI core services table. + + Size - Amount of memory required + + Buffer - Address of pointer to the buffer + +Returns: + + Status - EFI_SUCCESS The allocation was successful + EFI_OUT_OF_RESOURCES There is not enough heap to satisfy the requirement + to allocate the requested size. + +--*/ +; + +EFI_STATUS +PeiLoadImage ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_FFS_FILE_HEADER *PeimFileHeader, + OUT VOID **EntryPoint + ) +/*++ + +Routine Description: + + Get entry point of a Peim file. + +Arguments: + + PeiServices - Calling context. + + PeimFileHeader - Peim file's header. + + EntryPoint - Entry point of that Peim file. + +Returns: + + Status code. + +--*/ +; + + +EFI_STATUS +EFIAPI +PeiReportStatusCode ( + IN EFI_PEI_SERVICES **PeiServices, + 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 + ) +/*++ + +Routine Description: + + Core version of the Status Code reporter + +Arguments: + + PeiServices - The PEI core services table. + + CodeType - Type of Status Code. + + Value - Value to output for Status Code. + + Instance - Instance Number of this status code. + + CallerId - ID of the caller of this status code. + + Data - Optional data associated with this status code. + +Returns: + + Status - EFI_SUCCESS if status code is successfully reported + - EFI_NOT_AVAILABLE_YET if StatusCodePpi has not been installed + +--*/ +; + + +EFI_STATUS +EFIAPI +PeiResetSystem ( + IN EFI_PEI_SERVICES **PeiServices + ) +/*++ + +Routine Description: + + Core version of the Reset System + +Arguments: + + PeiServices - The PEI core services table. + +Returns: + + Status - EFI_NOT_AVAILABLE_YET. PPI not available yet. + - EFI_DEVICE_ERROR. Did not reset system. + + Otherwise, resets the system. + +--*/ +; + +#endif diff --git a/EdkModulePkg/Core/Pei/PeiMain.mbd b/EdkModulePkg/Core/Pei/PeiMain.mbd new file mode 100644 index 0000000000..c9d64e336a --- /dev/null +++ b/EdkModulePkg/Core/Pei/PeiMain.mbd @@ -0,0 +1,53 @@ + + + + + PeiMain + 52C05B14-0B98-496c-BC3B-04B50211D680 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:18 + + + PeiCoreEntryPoint + BaseLib + BaseMemoryLib + PeiServicesTablePointerLib + PeiCoreLib + PeiHobLib + PeiReportStatusCodeLib + BaseDebugLibReportStatusCode + BasePerformanceLibNull + + BasePeCoffGetEntryPointLib + + + BasePeCoffGetEntryPointLib + + + BasePeCoffGetEntryPointLib + + + BasePeCoffGetEntryPointLib + + + diff --git a/EdkModulePkg/Core/Pei/PeiMain.msa b/EdkModulePkg/Core/Pei/PeiMain.msa new file mode 100644 index 0000000000..b18b178caa --- /dev/null +++ b/EdkModulePkg/Core/Pei/PeiMain.msa @@ -0,0 +1,91 @@ + + + + + PeiMain + PEI_CORE + PEI_CORE + 52C05B14-0B98-496c-BC3B-04B50211D680 + 0 + Component description file for PeiMain module + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:18 + + + DebugLib + PeiCoreEntryPoint + BaseLib + HobLib + PerformanceLib + PeiCoreLib + ReportStatusCodeLib + PeCoffGetEntryPointLib + BaseMemoryLib + TimerLib + + + PeiMain.h + BootMode\BootMode.c + Dependency\Dependency.c + Dispatcher\Dispatcher.c + FwVol\FwVol.c + Hob\Hob.c + Image\Image.c + Memory\MemoryServices.c + PeiMain\PeiMain.c + Ppi\Ppi.c + Reset\Reset.c + Security\Security.c + StatusCode\StatusCode.c + + ipf\SwitchToCacheMode.c + ipf\IpfCpuCore.i + ipf\IpfCpuCore.s + + + + MdePkg + EdkModulePkg + + + + + gPeiPerformanceHobGuid + 0xec4df5af, 0x4395, 0x4cc9, 0x94, 0xde, 0x77, 0x50, 0x6d, 0x12, 0xc7, 0xb8 + + + + MemoryDiscovered + FindFv + FvFileLoader + DxeIpl + Reset + StatusCode + Security + + + + PeiCore + + + diff --git a/EdkModulePkg/Core/Pei/PeiMain/PeiMain.c b/EdkModulePkg/Core/Pei/PeiMain/PeiMain.c new file mode 100644 index 0000000000..014c571c05 --- /dev/null +++ b/EdkModulePkg/Core/Pei/PeiMain/PeiMain.c @@ -0,0 +1,243 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PeiMain.c + +Abstract: + + Pei Core Main Entry Point + +Revision History + +--*/ + +#include + +// +//CAR is filled with this initial value during SEC phase +// +#define INIT_CAR_VALUE 0x5AA55AA5 + +static EFI_PEI_PPI_DESCRIPTOR mMemoryDiscoveredPpi = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiPeiMemoryDiscoveredPpiGuid, + NULL +}; + +// +// Pei Core Module Variables +// +// +static EFI_PEI_SERVICES mPS = { + { + PEI_SERVICES_SIGNATURE, + PEI_SERVICES_REVISION, + sizeof (EFI_PEI_SERVICES), + 0, + 0 + }, + PeiInstallPpi, + PeiReInstallPpi, + PeiLocatePpi, + PeiNotifyPpi, + + PeiGetBootMode, + PeiSetBootMode, + + PeiGetHobList, + PeiCreateHob, + + PeiFvFindNextVolume, + PeiFfsFindNextFile, + PeiFfsFindSectionData, + + PeiInstallPeiMemory, + PeiAllocatePages, + PeiAllocatePool, + (EFI_PEI_COPY_MEM)CopyMem, + (EFI_PEI_SET_MEM)SetMem, + + PeiReportStatusCode, + + PeiResetSystem +}; + +EFI_STATUS +EFIAPI +PeiCore ( + IN EFI_PEI_STARTUP_DESCRIPTOR *PeiStartupDescriptor, + IN PEI_CORE_INSTANCE *OldCoreData + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + PeiStartupDescriptor - Information and services provided by SEC phase. + OldCoreData - Pointer to old core data that is used to initialize the + core's data areas. + +Returns: + + This function never returns + EFI_NOT_FOUND - Never reach + +--*/ +{ + PEI_CORE_INSTANCE PrivateData; + EFI_STATUS Status; + PEI_CORE_TEMP_POINTERS TempPtr; + PEI_CORE_DISPATCH_DATA *DispatchData; + UINT64 mTick; + + mTick = 0; + +#ifdef EFI_PEI_PERFORMANCE + if (OldCoreData == NULL) { + mTick = GetPerformanceCounter (); + } +#endif + + + // + // For IPF in CAR mode the real memory access is uncached,in InstallPeiMemory() + // the 63-bit of address is set to 1. + // + SWITCH_TO_CACHE_MODE (OldCoreData); + + if (OldCoreData != NULL) { + CopyMem (&PrivateData, OldCoreData, sizeof (PEI_CORE_INSTANCE)); + } else { + ZeroMem (&PrivateData, sizeof (PEI_CORE_INSTANCE)); + } + + PrivateData.Signature = PEI_CORE_HANDLE_SIGNATURE; + PrivateData.PS = &mPS; + + // + // Initialize libraries that the PeiCore is linked against + // BUGBUG: The FfsHeader is passed in as NULL. Do we look it up or remove it from the lib init? + // + ProcessLibraryConstructorList (NULL, &PrivateData.PS); + + InitializeMemoryServices (&PrivateData.PS, PeiStartupDescriptor, OldCoreData); + + InitializePpiServices (&PrivateData.PS, OldCoreData); + + InitializeSecurityServices (&PrivateData.PS, OldCoreData); + + InitializeDispatcherData (&PrivateData.PS, OldCoreData, PeiStartupDescriptor); + + if (OldCoreData != NULL) { + + PERF_END (NULL,"PreMem", NULL, 0); + PERF_START (NULL,"PostMem", NULL, 0); + + // + // The following code dumps out interesting cache as RAM usage information + // so we can keep tabs on how the cache as RAM is being utilized. The + // DEBUG_CODE macro is used to prevent this code from being compiled + // on a debug build. + // + DEBUG_CODE ( + UINTN *StackPointer; + UINTN StackValue; + + StackValue = INIT_CAR_VALUE; + for (StackPointer = (UINTN *) OldCoreData->MaxTopOfCarHeap; + ((UINTN) StackPointer < ((UINTN) OldCoreData->BottomOfCarHeap + OldCoreData->SizeOfCacheAsRam)) + && StackValue == INIT_CAR_VALUE; + StackPointer++) { + StackValue = *StackPointer; + } + + DEBUG ((EFI_D_INFO, "Total Cache as RAM: %d bytes.\n", OldCoreData->SizeOfCacheAsRam)); + DEBUG ((EFI_D_INFO, " CAR stack ever used: %d bytes.\n", + ((UINTN) OldCoreData->TopOfCarHeap - (UINTN) StackPointer) + )); + DEBUG ((EFI_D_INFO, " CAR heap used: %d bytes.\n", + ((UINTN) OldCoreData->HobList.HandoffInformationTable->EfiFreeMemoryBottom - + (UINTN) OldCoreData->HobList.Raw) + )); + ); + + // + // Alert any listeners that there is permanent memory available + // + PERF_START (NULL,"DisMem", NULL, 0); + Status = PeiCoreInstallPpi (&mMemoryDiscoveredPpi); + PERF_END (NULL,"DisMem", NULL, 0); + + } else { + + // + // Report Status Code EFI_SW_PC_INIT + // + REPORT_STATUS_CODE ( + EFI_PROGRESS_CODE, + EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT + ); + + // + // If first pass, start performance measurement. + // + PERF_START (NULL,"PreMem", NULL, mTick); + + // + // If SEC provided any PPI services to PEI, install them. + // + if (PeiStartupDescriptor->DispatchTable != NULL) { + Status = PeiCoreInstallPpi (PeiStartupDescriptor->DispatchTable); + ASSERT_EFI_ERROR (Status); + } + } + + DispatchData = &PrivateData.DispatchData; + + // + // Call PEIM dispatcher + // + PeiDispatcher (PeiStartupDescriptor, &PrivateData, DispatchData); + + // + // Check if InstallPeiMemory service was called. + // + ASSERT(PrivateData.PeiMemoryInstalled == TRUE); + + PERF_END (NULL, "PostMem", NULL, 0); + + Status = PeiCoreLocatePpi ( + &gEfiDxeIplPpiGuid, + 0, + NULL, + (VOID **)&TempPtr.DxeIpl + ); + ASSERT_EFI_ERROR (Status); + + DEBUG ((EFI_D_INFO, "DXE IPL Entry\n")); + Status = TempPtr.DxeIpl->Entry ( + TempPtr.DxeIpl, + &PrivateData.PS, + PrivateData.HobList + ); + + ASSERT_EFI_ERROR (Status); + + return EFI_NOT_FOUND; +} + diff --git a/EdkModulePkg/Core/Pei/Ppi/Ppi.c b/EdkModulePkg/Core/Pei/Ppi/Ppi.c new file mode 100644 index 0000000000..7fdb08c66f --- /dev/null +++ b/EdkModulePkg/Core/Pei/Ppi/Ppi.c @@ -0,0 +1,658 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Ppi.c + +Abstract: + + EFI PEI Core PPI services + +Revision History + +--*/ + +#include + +VOID +InitializePpiServices ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_CORE_INSTANCE *OldCoreData + ) +/*++ + +Routine Description: + + Initialize PPI services. + +Arguments: + + PeiServices - The PEI core services table. + OldCoreData - Pointer to the PEI Core data. + NULL if being run in non-permament memory mode. + +Returns: + Nothing + +--*/ +{ + PEI_CORE_INSTANCE *PrivateData; + + if (OldCoreData == NULL) { + PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices); + + PrivateData->PpiData.NotifyListEnd = MAX_PPI_DESCRIPTORS-1; + PrivateData->PpiData.DispatchListEnd = MAX_PPI_DESCRIPTORS-1; + PrivateData->PpiData.LastDispatchedNotify = MAX_PPI_DESCRIPTORS-1; + } + + return; +} + +VOID +ConvertPpiPointers ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_HOB_HANDOFF_INFO_TABLE *OldHandOffHob, + IN EFI_HOB_HANDOFF_INFO_TABLE *NewHandOffHob + ) +/*++ + +Routine Description: + + Migrate the Hob list from the CAR stack to PEI installed memory. + +Arguments: + + PeiServices - The PEI core services table. + OldHandOffHob - The old handoff HOB list. + NewHandOffHob - The new handoff HOB list. + +Returns: + +--*/ +{ + PEI_CORE_INSTANCE *PrivateData; + UINT8 Index; + PEI_PPI_LIST_POINTERS *PpiPointer; + UINTN Fixup; + + PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices); + + Fixup = (UINTN)NewHandOffHob - (UINTN)OldHandOffHob; + + for (Index = 0; Index < MAX_PPI_DESCRIPTORS; Index++) { + if (Index < PrivateData->PpiData.PpiListEnd || + Index > PrivateData->PpiData.NotifyListEnd) { + PpiPointer = &PrivateData->PpiData.PpiListPtrs[Index]; + + if (((UINTN)PpiPointer->Raw < (UINTN)OldHandOffHob->EfiFreeMemoryBottom) && + ((UINTN)PpiPointer->Raw >= (UINTN)OldHandOffHob)) { + // + // Convert the pointer to the PEIM descriptor from the old HOB heap + // to the relocated HOB heap. + // + PpiPointer->Raw = (VOID *) ((UINTN)PpiPointer->Raw + Fixup); + + // + // Only when the PEIM descriptor is in the old HOB should it be necessary + // to try to convert the pointers in the PEIM descriptor + // + + if (((UINTN)PpiPointer->Ppi->Guid < (UINTN)OldHandOffHob->EfiFreeMemoryBottom) && + ((UINTN)PpiPointer->Ppi->Guid >= (UINTN)OldHandOffHob)) { + // + // Convert the pointer to the GUID in the PPI or NOTIFY descriptor + // from the old HOB heap to the relocated HOB heap. + // + PpiPointer->Ppi->Guid = (VOID *) ((UINTN)PpiPointer->Ppi->Guid + Fixup); + } + + // + // Assume that no code is located in the temporary memory, so the pointer to + // the notification function in the NOTIFY descriptor needs not be converted. + // + if (Index < PrivateData->PpiData.PpiListEnd && + (UINTN)PpiPointer->Ppi->Ppi < (UINTN)OldHandOffHob->EfiFreeMemoryBottom && + (UINTN)PpiPointer->Ppi->Ppi >= (UINTN)OldHandOffHob) { + // + // Convert the pointer to the PPI interface structure in the PPI descriptor + // from the old HOB heap to the relocated HOB heap. + // + PpiPointer->Ppi->Ppi = (VOID *) ((UINTN)PpiPointer->Ppi->Ppi+ Fixup); + } + } + } + } +} + + + +EFI_STATUS +EFIAPI +PeiInstallPpi ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_PPI_DESCRIPTOR *PpiList + ) +/*++ + +Routine Description: + + Install PPI services. + +Arguments: + + PeiServices - Pointer to the PEI Service Table + PpiList - Pointer to a list of PEI PPI Descriptors. + +Returns: + + EFI_SUCCESS - if all PPIs in PpiList are successfully installed. + EFI_INVALID_PARAMETER - if PpiList is NULL pointer + EFI_INVALID_PARAMETER - if any PPI in PpiList is not valid + EFI_OUT_OF_RESOURCES - if there is no more memory resource to install PPI + +--*/ +{ + PEI_CORE_INSTANCE *PrivateData; + INTN Index; + INTN LastCallbackInstall; + + + if (PpiList == NULL) { + return EFI_INVALID_PARAMETER; + } + + PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices); + + Index = PrivateData->PpiData.PpiListEnd; + LastCallbackInstall = 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 (;;) { + // + // Since PpiData is used for NotifyList and InstallList, max resource + // is reached if the Install reaches the NotifyList + // + if (Index == PrivateData->PpiData.NotifyListEnd + 1) { + return EFI_OUT_OF_RESOURCES; + } + // + // 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) { + PrivateData->PpiData.PpiListEnd = LastCallbackInstall; + DEBUG((EFI_D_INFO, "ERROR -> InstallPpi: %g %x\n", PpiList->Guid, PpiList->Ppi)); + return EFI_INVALID_PARAMETER; + } + + DEBUG((EFI_D_INFO, "Install PPI: %g\n", PpiList->Guid)); + PrivateData->PpiData.PpiListPtrs[Index].Ppi = PpiList; + PrivateData->PpiData.PpiListEnd++; + + // + // Continue until the end of the PPI List. + // + if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) == + EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) { + break; + } + PpiList++; + Index++; + } + + // + // Dispatch any callback level notifies for newly installed PPIs. + // + DispatchNotify ( + PeiServices, + EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK, + LastCallbackInstall, + PrivateData->PpiData.PpiListEnd, + PrivateData->PpiData.DispatchListEnd, + PrivateData->PpiData.NotifyListEnd + ); + + + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +PeiReInstallPpi ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_PPI_DESCRIPTOR *OldPpi, + IN EFI_PEI_PPI_DESCRIPTOR *NewPpi + ) +/*++ + +Routine Description: + + Re-Install PPI services. + +Arguments: + + PeiServices - Pointer to the PEI Service Table + OldPpi - Pointer to the old PEI PPI Descriptors. + NewPpi - Pointer to the new PEI PPI Descriptors. + +Returns: + + EFI_SUCCESS - if the operation was successful + EFI_INVALID_PARAMETER - if OldPpi or NewPpi is NULL + EFI_INVALID_PARAMETER - if NewPpi is not valid + EFI_NOT_FOUND - if the PPI was not in the database + +--*/ +{ + PEI_CORE_INSTANCE *PrivateData; + INTN 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.PpiListEnd; Index++) { + if (OldPpi == PrivateData->PpiData.PpiListPtrs[Index].Ppi) { + break; + } + } + if (Index == PrivateData->PpiData.PpiListEnd) { + return EFI_NOT_FOUND; + } + + // + // Remove the old PPI from the database, add the new one. + // + DEBUG((EFI_D_INFO, "Reinstall PPI: %g\n", NewPpi->Guid)); + PrivateData->PpiData.PpiListPtrs[Index].Ppi = NewPpi; + + // + // Dispatch any callback level notifies for the newly installed PPI. + // + DispatchNotify ( + PeiServices, + EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK, + Index, + Index+1, + PrivateData->PpiData.DispatchListEnd, + PrivateData->PpiData.NotifyListEnd + ); + + + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +PeiLocatePpi ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_GUID *Guid, + IN UINTN Instance, + IN OUT EFI_PEI_PPI_DESCRIPTOR **PpiDescriptor, + IN OUT VOID **Ppi + ) +/*++ + +Routine Description: + + Locate a given named PPI. + +Arguments: + + PeiServices - Pointer to the PEI Service Table + Guid - Pointer to GUID of the PPI. + Instance - Instance Number to discover. + PpiDescriptor - Pointer to reference the found descriptor. If not NULL, + returns a pointer to the descriptor (includes flags, etc) + Ppi - Pointer to reference the found PPI + +Returns: + + Status - EFI_SUCCESS if the PPI is in the database + EFI_NOT_FOUND if the PPI is not in the database +--*/ +{ + PEI_CORE_INSTANCE *PrivateData; + INTN 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.PpiListEnd; Index++) { + TempPtr = PrivateData->PpiData.PpiListPtrs[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; +} + + +EFI_STATUS +EFIAPI +PeiNotifyPpi ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyList + ) +/*++ + +Routine Description: + + Install a notification for a given PPI. + +Arguments: + + PeiServices - Pointer to the PEI Service Table + NotifyList - Pointer to list of Descriptors to notify upon. + +Returns: + + Status - EFI_SUCCESS if successful + EFI_OUT_OF_RESOURCES if no space in the database + EFI_INVALID_PARAMETER if not a good decriptor + +--*/ +{ + PEI_CORE_INSTANCE *PrivateData; + INTN Index; + INTN NotifyIndex; + INTN LastCallbackNotify; + EFI_PEI_NOTIFY_DESCRIPTOR *NotifyPtr; + UINTN NotifyDispatchCount; + + + NotifyDispatchCount = 0; + + if (NotifyList == NULL) { + return EFI_INVALID_PARAMETER; + } + + PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices); + + Index = PrivateData->PpiData.NotifyListEnd; + LastCallbackNotify = Index; + + // + // 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 (;;) { + // + // Since PpiData is used for NotifyList and InstallList, max resource + // is reached if the Install reaches the PpiList + // + if (Index == PrivateData->PpiData.PpiListEnd - 1) { + return EFI_OUT_OF_RESOURCES; + } + + // + // If some of the PPI data is invalid restore original Notify PPI database value + // + if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_TYPES) == 0) { + PrivateData->PpiData.NotifyListEnd = LastCallbackNotify; + DEBUG((EFI_D_INFO, "ERROR -> InstallNotify: %g %x\n", NotifyList->Guid, NotifyList->Notify)); + return EFI_INVALID_PARAMETER; + } + + if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH) != 0) { + NotifyDispatchCount ++; + } + + PrivateData->PpiData.PpiListPtrs[Index].Notify = NotifyList; + + PrivateData->PpiData.NotifyListEnd--; + DEBUG((EFI_D_INFO, "Register PPI Notify: %g\n", NotifyList->Guid)); + if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) == + EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) { + break; + } + // + // Go the next descriptor. Remember the NotifyList moves down. + // + NotifyList++; + Index--; + } + + // + // If there is Dispatch Notify PPI installed put them on the bottom + // + if (NotifyDispatchCount > 0) { + for (NotifyIndex = LastCallbackNotify; NotifyIndex > PrivateData->PpiData.NotifyListEnd; NotifyIndex--) { + if ((PrivateData->PpiData.PpiListPtrs[NotifyIndex].Notify->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH) != 0) { + NotifyPtr = PrivateData->PpiData.PpiListPtrs[NotifyIndex].Notify; + + for (Index = NotifyIndex; Index < PrivateData->PpiData.DispatchListEnd; Index++){ + PrivateData->PpiData.PpiListPtrs[Index].Notify = PrivateData->PpiData.PpiListPtrs[Index + 1].Notify; + } + PrivateData->PpiData.PpiListPtrs[Index].Notify = NotifyPtr; + PrivateData->PpiData.DispatchListEnd--; + } + } + + LastCallbackNotify -= NotifyDispatchCount; + } + + // + // Dispatch any callback level notifies for all previously installed PPIs. + // + DispatchNotify ( + PeiServices, + EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK, + 0, + PrivateData->PpiData.PpiListEnd, + LastCallbackNotify, + PrivateData->PpiData.NotifyListEnd + ); + + + return EFI_SUCCESS; +} + + +VOID +ProcessNotifyList ( + IN EFI_PEI_SERVICES **PeiServices + ) +/*++ + +Routine Description: + + Process the Notify List at dispatch level. + +Arguments: + + PeiServices - Pointer to the PEI Service Table + +Returns: + +--*/ + +{ + PEI_CORE_INSTANCE *PrivateData; + INTN TempValue; + + PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices); + + + 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 previouly installed PPIs. + // Use "while" instead of "if" since DispatchNotify can modify + // DispatchListEnd (with NotifyPpi) so we have to iterate until the same. + // + while (PrivateData->PpiData.LastDispatchedNotify != PrivateData->PpiData.DispatchListEnd) { + TempValue = PrivateData->PpiData.DispatchListEnd; + DispatchNotify ( + PeiServices, + EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH, + 0, + PrivateData->PpiData.LastDispatchedInstall, + PrivateData->PpiData.LastDispatchedNotify, + PrivateData->PpiData.DispatchListEnd + ); + PrivateData->PpiData.LastDispatchedNotify = 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 DispatchNotify can modify + // PpiListEnd (with InstallPpi) so we have to iterate until the same. + // + while (PrivateData->PpiData.LastDispatchedInstall != PrivateData->PpiData.PpiListEnd) { + TempValue = PrivateData->PpiData.PpiListEnd; + DispatchNotify ( + PeiServices, + EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH, + PrivateData->PpiData.LastDispatchedInstall, + PrivateData->PpiData.PpiListEnd, + MAX_PPI_DESCRIPTORS-1, + PrivateData->PpiData.DispatchListEnd + ); + PrivateData->PpiData.LastDispatchedInstall = TempValue; + } + + if (PrivateData->PpiData.LastDispatchedNotify == PrivateData->PpiData.DispatchListEnd) { + break; + } + } + return; +} + +VOID +DispatchNotify ( + IN EFI_PEI_SERVICES **PeiServices, + IN UINTN NotifyType, + IN INTN InstallStartIndex, + IN INTN InstallStopIndex, + IN INTN NotifyStartIndex, + IN INTN NotifyStopIndex + ) +/*++ + +Routine Description: + + Dispatch notifications. + +Arguments: + + PeiServices - Pointer to the PEI Service Table + NotifyType - Type of notify to fire. + InstallStartIndex - Install Beginning index. + InstallStopIndex - Install Ending index. + NotifyStartIndex - Notify Beginning index. + NotifyStopIndex - Notify Ending index. + +Returns: None + +--*/ + +{ + PEI_CORE_INSTANCE *PrivateData; + INTN Index1; + INTN Index2; + EFI_GUID *SearchGuid; + EFI_GUID *CheckGuid; + EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor; + + PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices); + + // + // Remember that Installs moves up and Notifies moves down. + // + for (Index1 = NotifyStartIndex; Index1 > NotifyStopIndex; Index1--) { + NotifyDescriptor = PrivateData->PpiData.PpiListPtrs[Index1].Notify; + + CheckGuid = NotifyDescriptor->Guid; + + for (Index2 = InstallStartIndex; Index2 < InstallStopIndex; Index2++) { + SearchGuid = PrivateData->PpiData.PpiListPtrs[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: %x\n", + SearchGuid, + NotifyDescriptor->Notify + )); + NotifyDescriptor->Notify ( + PeiServices, + NotifyDescriptor, + (PrivateData->PpiData.PpiListPtrs[Index2].Ppi)->Ppi + ); + } + } + } + + return; +} + diff --git a/EdkModulePkg/Core/Pei/Reset/Reset.c b/EdkModulePkg/Core/Pei/Reset/Reset.c new file mode 100644 index 0000000000..6bcb4ce31b --- /dev/null +++ b/EdkModulePkg/Core/Pei/Reset/Reset.c @@ -0,0 +1,68 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Reset.c + +Abstract: + + Pei Core Reset System Support + +Revision History + +--*/ + +#include + +EFI_STATUS +EFIAPI +PeiResetSystem ( + IN EFI_PEI_SERVICES **PeiServices + ) +/*++ + +Routine Description: + + Core version of the Reset System + +Arguments: + + PeiServices - The PEI core services table. + +Returns: + + Status - EFI_NOT_AVAILABLE_YET. PPI not available yet. + - EFI_DEVICE_ERROR. Did not reset system. + + Otherwise, resets the system. + +--*/ +{ + EFI_STATUS Status; + EFI_PEI_RESET_PPI *ResetPpi; + + Status = PeiCoreLocatePpi ( + &gEfiPeiResetPpiGuid, + 0, + NULL, + (VOID **)&ResetPpi + ); + + // + // LocatePpi returns EFI_NOT_FOUND on error + // + if (!EFI_ERROR (Status)) { + return ResetPpi->ResetSystem (PeiServices); + } + return EFI_NOT_AVAILABLE_YET; +} + diff --git a/EdkModulePkg/Core/Pei/Security/Security.c b/EdkModulePkg/Core/Pei/Security/Security.c new file mode 100644 index 0000000000..5908928c7b --- /dev/null +++ b/EdkModulePkg/Core/Pei/Security/Security.c @@ -0,0 +1,192 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Security.c + +Abstract: + + EFI PEI Core Security services + +--*/ + +#include + +EFI_STATUS +EFIAPI +SecurityPpiNotifyCallback ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ); + +static EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList = { + EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, + &gEfiPeiSecurityPpiGuid, + SecurityPpiNotifyCallback +}; + +VOID +InitializeSecurityServices ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_CORE_INSTANCE *OldCoreData + ) +/*++ + +Routine Description: + + Initialize the security services. + +Arguments: + + PeiServices - The PEI core services table. + OldCoreData - Pointer to the old core data. + NULL if being run in non-permament memory mode. +Returns: + + None + +--*/ +{ + if (OldCoreData == NULL) { + PeiCoreNotifyPpi (&mNotifyList); + } + return; +} + +EFI_STATUS +EFIAPI +SecurityPpiNotifyCallback ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ) +/*++ + +Routine Description: + + Provide a callback for when the security PPI is installed. + +Arguments: + + PeiServices - The PEI core services table. + NotifyDescriptor - The descriptor for the notification event. + Ppi - Pointer to the PPI in question. + +Returns: + + EFI_SUCCESS - The function is successfully processed. + +--*/ +{ + 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_SECURITY_PPI *)Ppi; + } + return EFI_SUCCESS; +} + +EFI_STATUS +VerifyPeim ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_FFS_FILE_HEADER *CurrentPeimAddress + ) +/*++ + +Routine Description: + + Provide a callout to the security verification service. + +Arguments: + + PeiServices - The PEI core services table. + CurrentPeimAddress - Pointer to the Firmware File under investigation. + +Returns: + + EFI_SUCCESS - Image is OK + EFI_SECURITY_VIOLATION - Image is illegal + +--*/ +{ + PEI_CORE_INSTANCE *PrivateData; + EFI_STATUS Status; + UINT32 AuthenticationStatus; + BOOLEAN StartCrisisRecovery; + + // + // Set a default authentication state + // + AuthenticationStatus = 0; + + // + // get security PPI instance from PEI private data + // + PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices); + + if (PrivateData->PrivateSecurityPpi == NULL) { + Status = EFI_NOT_FOUND; + } else { + // + // Check to see if the image is OK + // + Status = PrivateData->PrivateSecurityPpi->AuthenticationState ( + PeiServices, + PrivateData->PrivateSecurityPpi, + AuthenticationStatus, + CurrentPeimAddress, + &StartCrisisRecovery + ); + if (StartCrisisRecovery) { + Status = EFI_SECURITY_VIOLATION; + } + } + return Status; +} + + +EFI_STATUS +VerifyFv ( + IN EFI_FIRMWARE_VOLUME_HEADER *CurrentFvAddress + ) +/*++ + +Routine Description: + + Verify a Firmware volume + +Arguments: + + CurrentFvAddress - Pointer to the current Firmware Volume under consideration + +Returns: + + EFI_SUCCESS - Firmware Volume is legal + EFI_SECURITY_VIOLATION - Firmware Volume fails integrity test + +--*/ +{ + // + // 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/EdkModulePkg/Core/Pei/StatusCode/StatusCode.c b/EdkModulePkg/Core/Pei/StatusCode/StatusCode.c new file mode 100644 index 0000000000..496effa5e5 --- /dev/null +++ b/EdkModulePkg/Core/Pei/StatusCode/StatusCode.c @@ -0,0 +1,95 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + StatusCode.c + +Abstract: + + Pei Core Status Code Support + +Revision History + +--*/ + +#include + +EFI_STATUS +EFIAPI +PeiReportStatusCode ( + IN EFI_PEI_SERVICES **PeiServices, + 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 + ) +/*++ + +Routine Description: + + Core version of the Status Code reporter + +Arguments: + + PeiServices - The PEI core services table. + + CodeType - Type of Status Code. + + Value - Value to output for Status Code. + + Instance - Instance Number of this status code. + + CallerId - ID of the caller of this status code. + + Data - Optional data associated with this status code. + +Returns: + + Status - EFI_SUCCESS if status code is successfully reported + - EFI_NOT_AVAILABLE_YET if StatusCodePpi has not been installed + +--*/ +{ + EFI_STATUS Status; + EFI_PEI_PROGRESS_CODE_PPI *StatusCodePpi; + + + // + //Locate StatusCode Ppi. + // + Status = PeiCoreLocatePpi ( + &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/EdkModulePkg/Core/Pei/build.xml b/EdkModulePkg/Core/Pei/build.xml new file mode 100644 index 0000000000..94a26db352 --- /dev/null +++ b/EdkModulePkg/Core/Pei/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/EdkModulePkg.fpd b/EdkModulePkg/EdkModulePkg.fpd new file mode 100644 index 0000000000..c820656838 --- /dev/null +++ b/EdkModulePkg/EdkModulePkg.fpd @@ -0,0 +1,453 @@ + + + + + MdePkg + EFI/Tiano MdePkg Package + This FPD file is used for Package Level build. + 2006-04-03 13:40 + lhauch + + + dummy.fdf + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PcdMaximumUnicodeStringLength + 0x00000001 + UINT32 + false + false + false + false + false + 0x00 + 0x00 + 4 + 0 + L"" + 0 + 0 + 1000000 + + + PcdMaximumAsciiStringLength + 0x00000002 + UINT32 + false + false + false + false + false + 0x00 + 0x00 + 4 + 0 + L"" + 0 + 0 + 1000000 + + + PcdMaximumLinkedListLength + 0x00000003 + UINT32 + false + false + false + false + false + 0x00 + 0x00 + 4 + 0 + L"" + 0 + 0 + 1000000 + + + PcdSpinLockTimeout + 0x00000004 + UINT32 + false + false + false + false + false + 0x00 + 0x00 + 4 + 0 + L"" + 0 + 0 + 10000000 + + + PcdDebugPropertyMask + 0x00000005 + UINT8 + false + false + false + false + false + 0x00 + 0x00 + 4 + 0 + L"" + 0 + 0 + 0x0f + + + PcdDebugPrintErrorLevel + 0x00000006 + UINT32 + false + false + false + false + false + 0x00 + 0x00 + 4 + 0 + L"" + 0 + 0 + 0x80000000 + + + PcdReportStatusCodePropertyMask + 0x00000007 + UINT8 + false + false + false + false + false + 0x00 + 0x00 + 1 + 0 + L"" + 0 + 0 + 0x07 + + + PcdDebugClearMemoryValue + 0x00000008 + UINT8 + false + false + false + false + false + 0 + 0 + 1 + 0 + L"" + 0 + 0 + 0xAF + + + PcdPerformanceLibraryPropertyMask + 0x00000009 + UINT8 + false + false + false + false + false + 0x00 + 0x00 + 1 + 0 + L"" + 0 + 0 + 0 + + + + + + diff --git a/EdkModulePkg/EdkModulePkg.spd b/EdkModulePkg/EdkModulePkg.spd new file mode 100644 index 0000000000..f2bdfa0401 --- /dev/null +++ b/EdkModulePkg/EdkModulePkg.spd @@ -0,0 +1,655 @@ + + + + + EdkModulePkg + 0xb6ec423c, 0x21d2, 0x490d, 0x85, 0xc6, 0xdd, 0x58, 0x64, 0xea, 0xa6, 0x74 + 0 + Edk Module Package Reference Implementations + This Module provides standard reference information for EFI/Tiano implementations. + Copyright (c) 2006, Intel Corporation. + + All rights reserved. + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License which accompanies this distribution. + The full text of the license may be found at http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES + OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-02-21 17:43 + 2006-03-19 16:26 + http://www.TianoCore.org + SOURCE + true + false + + + + CustomDecompressLib + Include/Library/CustomDecompressLib.h + + + EdkBsDataHubStatusCodeLib + Include/Library/EdkBsDataHubStatusCodeLib.h + + + EdkDxeSalLib + Include/Library/EdkDxeSalLib.h + + + EdkFvbServiceLib + Include/Library/EdkFvbServiceLib.h + + + EdkGraphicsLib + Include/Library/EdkGraphicsLib.h + + + EdkIfrSupportLib + Include/Library/EdkIfrSupportLib.h + + + EdkMemoryStatusCodeLib + Include/Library/EdkMemoryStatusCodeLib.h + + + EdkPeCoffLoaderLib + Include/Library/EdkPeCoffLoaderLib.h + + + EdkPeCoffLoaderX64Lib + Include/Library/EdkPeCoffLoaderX64Lib.h + + + EdkRtMemoryStatusCodeLib + Include/Library/EdkRtMemoryStatusCodeLib.h + + + EdkRtPlatformStatusCodeLib + Include/Library/EdkRtPlatformStatusCodeLib.h + + + EdkScsiLib + Include/Library/EdkScsiLib.h + + + EdkUsbLib + Include/Library/EdkUsbLib.h + + + TianoDecompressLib + Include/Library/TianoDecompressLib.h + + + + + Application/HelloWorld/HelloWorld.msa + + + Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.msa + + + Bus/Pci/CirrusLogic/Dxe/CirrusLogic5430.msa + + + Bus/Pci/IdeBus/Dxe/idebus.msa + + + Bus/Pci/IdeBus/Dxe/idebusLite.msa + + + Bus/Pci/PciBus/Dxe/LightPciBus.msa + + + Bus/Pci/PciBus/Dxe/PciBus.msa + + + Bus/Pci/PciBus/Dxe/PciBusLite.msa + + + Bus/Pci/Uhci/Dxe/Uhci.msa + + + Bus/Pci/Undi/RuntimeDxe/Undi.msa + + + Bus/Scsi/ScsiBus/Dxe/ScsiBus.msa + + + Bus/Scsi/ScsiDisk/Dxe/ScsiDisk.msa + + + Bus/Usb/UsbBot/Dxe/UsbBot.msa + + + Bus/Usb/UsbBus/Dxe/UsbBus.msa + + + Bus/Usb/UsbCbi/Dxe/Cbi0/UsbCbi0.msa + + + Bus/Usb/UsbCbi/Dxe/Cbi1/UsbCbi1.msa + + + Bus/Usb/UsbKb/Dxe/UsbKb.msa + + + Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.msa + + + Bus/Usb/UsbMouse/Dxe/UsbMouse.msa + + + Core/Dxe/DxeMain.msa + + + Core/DxeIplPeim/DxeIpl.msa + + + Core/Pei/PeiMain.msa + + + Library/BaseCustomDecompressLibNull/BaseCustomDecompressLibNull.msa + + + Library/BaseUefiTianoDecompressLib/BaseUefiTianoDecompressLib.msa + + + Library/DxeCoreCustomDecompressLibFromHob/DxeCoreCustomDecompressLibFromHob.msa + + + Library/DxeCorePerformanceLib/DxeCorePerformanceLib.msa + + + Library/DxeCoreTianoDecompressLibFromHob/DxeCoreTianoDecompressLibFromHob.msa + + + Library/DxeCoreUefiDecompressLibFromHob/DxeCoreUefiDecompressLibFromHob.msa + + + Library/EdkDxeDebugLibReportStatusCode/EdkDxeDebugLibReportStatusCode.msa + + + Library/EdkDxePeCoffLoaderFromHobLib/EdkDxePeCoffLoaderFromHobLib.msa + + + Library/EdkDxePerformanceLib/EdkDxePerformanceLib.msa + + + Library/EdkDxePrintLib/EdkDxePrintLib.msa + + + Library/EdkDxeRuntimeDriverLib/EdkDxeRuntimeDriverLib.msa + + + Library/EdkDxeSalLib/EdkDxeSalLib.msa + + + Library/EdkFvbServiceLib/EdkFvbServiceLib.msa + + + Library/EdkGraphicsLib/EdkGraphicsLib.msa + + + Library/EdkIfrSupportLib/EdkIfrSupportLib.msa + + + Library/EdkMemoryStatusCodeLib/EdkMemoryStatusCodeLib.msa + + + Library/EdkNullCustomizedDecompressLib/EdkNullCustomizedDecompressLib.msa + + + Library/EdkPeCoffLoaderLib/EdkPeCoffLoaderLib.msa + + + Library/EdkPeCoffLoaderX64Lib/EdkPeCoffLoaderX64Lib.msa + + + Library/EdkPeiPerformanceLib/EdkPeiPerformanceLib.msa + + + Library/EdkRuntimeStatusCodeLib/BsDataHubStatusCode/BsDataHubStatusCode.msa + + + Library/EdkRuntimeStatusCodeLib/RtMemoryStatusCode/RtMemoryStatusCode.msa + + + Library/EdkRuntimeStatusCodeLib/RtPlatformStatusCode/RtPlatformStatusCode.msa + + + Library/EdkScsiLib/EdkScsiLib.msa + + + Library/EdkUefiDebugLibConOut/EdkUefiDebugLibConOut.msa + + + Library/EdkUefiDebugLibStdErr/EdkUefiDebugLibStdErr.msa + + + Library/EdkUsbLib/EdkUsbLib.msa + + + Universal/Console/ConSplitter/Dxe/ConSplitter.msa + + + Universal/Console/GraphicsConsole/Dxe/GraphicsConsole.msa + + + Universal/Console/Terminal/Dxe/Terminal.msa + + + Universal/DataHub/DataHub/Dxe/DataHub.msa + + + Universal/DataHub/DataHubStdErr/Dxe/DataHubStdErr.msa + + + Universal/Debugger/Debugport/Dxe/DebugPort.msa + + + Universal/DebugSupport/Dxe/DebugSupport.msa + + + Universal/Disk/DiskIo/Dxe/DiskIo.msa + + + Universal/Disk/DiskIoPartition/dxe/DiskIoPartition.msa + + + Universal/Disk/Partition/Dxe/Partition.msa + + + Universal/Disk/UnicodeCollation/English/Dxe/English.msa + + + Universal/Ebc/Dxe/Ebc.msa + + + Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwLite.msa + + + Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/Crc32SectionExtract.msa + + + Universal/GenericMemoryTest/Dxe/NullMemoryTest.msa + + + Universal/GenericMemoryTest/Pei/BaseMemoryTest.msa + + + Universal/MonotonicCounter/RuntimeDxe/MonotonicCounter.msa + + + Universal/Network/PxeBc/Dxe/BC.msa + + + Universal/Network/PxeDhcp4/Dxe/Dhcp4.msa + + + Universal/Network/Snp32_64/Dxe/SNP.msa + + + Universal/Runtime/RuntimeDxe/Runtime.msa + + + Universal/Security/SecurityStub/Dxe/SecurityStub.msa + + + Universal/StatusCode/RuntimeDxe/StatusCode.msa + + + Universal/UserInterface/HiiDataBase/Dxe/HiiDatabase.msa + + + Universal/UserInterface/SetupBrowser/Dxe/DriverSample/DriverSample.msa + + + Universal/UserInterface/SetupBrowser/Dxe/SetupBrowser.msa + + + Universal/Variable/Pei/Variable.msa + + + Universal/EmuVariable/RuntimeDxe/EmuVariable.msa + + + Universal/Variable/RuntimeDxe/Variable.msa + + + Universal/WatchdogTimer/Dxe/WatchDogTimer.msa + + + + Include/EdkPeim.h + Include/EdkPeiCore.h + Include/EdkPeim.h + Include/EdkDxeCore.h + Include/EdkDxe.h + Include/EdkDxe.h + Include/EdkDxe.h + Include/EdkDxe.h + Include/EdkDxe.h + + + + gEfiPeiPeCoffLoaderGuid + 0xd8117cff, 0x94a6, 0x11d4, 0x9a, 0x3a, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d + + + gEfiFlashMapHobGuid + 0xb091e7d2, 0x5a0, 0x4198, 0x94, 0xf0, 0x74, 0xb7, 0xb8, 0xc5, 0x54, 0x59 + + + gEfiStatusCodeDataTypeStringGuid + 0x92D11080, 0x496F, 0x4D95, 0xBE, 0x7E, 0x03, 0x74, 0x88, 0x38, 0x2B, 0x0A + + + gEfiStatusCodeDataTypeDebugGuid + 0x9A4E9246, 0xD553, 0x11D5, 0x87, 0xE2, 0x00, 0x06, 0x29, 0x45, 0xC3, 0xb9 + + + gEfiStatusCodeDataTypeAssertGuid + 0xDA571595, 0x4D99, 0x487C, 0x82, 0x7C, 0x26, 0x22, 0x67, 0x7D, 0x33, 0x07 + + + gEfiStatusCodeDataTypeExceptionHandlerGuid + 0x3BC2BD12, 0xAD2E, 0x11D5, 0x87, 0xDD, 0x00, 0x06, 0x29, 0x45, 0xC3, 0xB9 + + + gEfiStatusCodeDataTypeErrorGuid + 0xAB359CE3, 0x99B3, 0xAE18, 0xC8, 0x9D, 0x95, 0xD3, 0xB0, 0x72, 0xE1, 0x9B + + + gEfiStatusCodeDataTypeProgressCodeGuid + 0xA356AB39, 0x35C4, 0x35DA, 0xB3, 0x7A, 0xF8, 0xEA, 0x9E, 0x8B, 0x36, 0xA3 + + + gEfiStatusCodeSpecificDataGuid + 0x335984bd, 0xe805, 0x409a, 0xb8, 0xf8, 0xd2, 0x7e, 0xce, 0x5f, 0xf7, 0xa6 + + + gEfiSystemNvDataHobGuid + 0xd6e5092d, 0xc7b2, 0x4872, 0xaf, 0x66, 0xfd, 0xc0, 0xe6, 0xf9, 0x5e, 0x78 + + + gEfiSystemNvDataFvGuid + 0xfff12b8d, 0x7696, 0x4c8b, 0xa9, 0x85, 0x27, 0x47, 0x07, 0x5b, 0x4f, 0x50 + + + gEfiDiskInfoIdeInterfaceGuid + 0x5e948fe3, 0x26d3, 0x42b5, 0xaf, 0x17, 0x61, 0x02, 0x87, 0x18, 0x8d, 0xec + + + gEfiDiskInfoScsiInterfaceGuid + 0x8f74baa, 0xea36, 0x41d9, 0x95, 0x21, 0x21, 0xa7, 0x0f, 0x87, 0x80, 0xbc + + + gEfiDiskInfoUsbInterfaceGuid + 0xcb871572, 0xc11a, 0x47b5, 0xb4, 0x92, 0x67, 0x5e, 0xaf, 0xa7, 0x77, 0x27 + + + gEfiAlternateFvBlockGuid + 0xf496922d, 0x172f, 0x4bbc, 0xa1, 0xeb, 0x0e, 0xeb, 0x94, 0x9c, 0x34, 0x86 + + + gEfiConsoleInDeviceGuid + 0xd3b36f2b, 0xd551, 0x11d4, 0x9a, 0x46, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d + + + gEfiConsoleOutDeviceGuid + 0xd3b36f2c, 0xd551, 0x11d4, 0x9a, 0x46, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d + + + gEfiStandardErrorDeviceGuid + 0xd3b36f2d, 0xd551, 0x11d4, 0x9a, 0x46, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d + + + gEfiHotPlugDeviceGuid + 0x220ac432, 0x1d43, 0x49e5, 0xa7, 0x4f, 0x4c, 0x9d, 0xa6, 0x7a, 0xd2, 0x3b + + + gEfiPrimaryStandardErrorDeviceGuid + 0x5a68191b, 0x9b97, 0x4752, 0x99, 0x46, 0xe3, 0x6a, 0x5d, 0xa9, 0x42, 0xb1 + + + gEfiPrimaryConsoleInDeviceGuid + 0xe451dcbe, 0x96a1, 0x4729, 0xa5, 0xcf, 0x6b, 0x9c, 0x2c, 0xff, 0x47, 0xfd + + + gEfiPrimaryConsoleOutDeviceGuid + 0x62bdf38a, 0xe3d5, 0x492c, 0x95, 0x0c, 0x23, 0xa7, 0xf6, 0x6e, 0x67, 0x2e + + + gEfiDefaultBmpLogoGuid + 0x7BB28B99, 0x61BB, 0x11d5, 0x9A, 0x5D, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D + + + gEfiBootStateGuid + 0x60b5e939, 0xfcf, 0x4227, 0xba, 0x83, 0x6b, 0xbe, 0xd4, 0x5b, 0xc0, 0xe3 + + + gEfiShellFileGuid + 0xc57ad6b7, 0x0515, 0x40a8, 0x9d, 0x21, 0x55, 0x16, 0x52, 0x85, 0x4e, 0x37 + + + gEfiMiniShellFileGuid + 0x86ad232b, 0xd33a, 0x465c, 0xbf, 0x5f, 0x41, 0x37, 0x0b, 0xa9, 0x2f, 0xe2 + + + gEfiStatusCodeGuid + 0xd083e94c, 0x6560, 0x42e4, 0xb6, 0xd4, 0x2d, 0xf7, 0x5a, 0xdf, 0x6a, 0x2a + + + gEfiPciOptionRomTableGuid + 0x7462660f, 0x1cbd, 0x48da, 0xad, 0x11, 0x91, 0x71, 0x79, 0x13, 0x83, 0x1c + + + gEfiPciHotplugDeviceGuid + 0x0b280816, 0x52e7, 0x4e51, 0xaa, 0x57, 0x11, 0xbd, 0x41, 0xcb, 0xef, 0xc3 + + + gEfiMemoryTypeInformationGuid + 0x4c19049f, 0x4137, 0x4dd3, 0x9c, 0x10, 0x8b, 0x97, 0xa8, 0x3f, 0xfd, 0xfa + + + gEfiCapsuleVendorGuid + 0x711C703F, 0xC285, 0x4B10, 0xA3, 0xB0, 0x36, 0xEC, 0xBD, 0x3C, 0x8B, 0xE2 + + + gEfiCompatibleMemoryTestedGuid + 0x64c475ef, 0x344b, 0x492c, 0x93, 0xad, 0xab, 0x9e, 0xb4, 0x39, 0x50, 0x4 + + + + + gEfiCustomizedDecompressProtocolGuid + 0x9a44198e, 0xa4a2, 0x44e6, 0x8a, 0x1f, 0x39, 0xbe, 0xfd, 0xac, 0x89, 0x6f + + + gEfiDebugLevelProtocolGuid + 0x8d4c62e6, 0xcd98, 0x4e1d, 0xad, 0x6e, 0x48, 0xbb, 0x50, 0xd2, 0x9f, 0xf7 + + + gEfiTianoDecompressProtocolGuid + 0xe84cf29c, 0x191f, 0x4eae, 0x96, 0xe1, 0xf4, 0x6a, 0xec, 0xea, 0xea, 0x0b + + + gEfiLoadPeImageProtocolGuid + 0x5cb5c776, 0x60d5, 0x45ee, 0x88, 0x3c, 0x45, 0x27, 0x08, 0xcd, 0x74, 0x3f + + + gEfiPrintProtocolGuid + 0xdf2d868e, 0x32fc, 0x4cf0, 0x8e, 0x6b, 0xff, 0xd9, 0x5d, 0x13, 0x43, 0xd0 + + + gEfiGenericMemTestProtocolGuid + 0x309de7f1, 0x7f5e, 0x4ace, 0xb4, 0x9c, 0x53, 0x1b, 0xe5, 0xaa, 0x95, 0xef + + + gEfiDiskInfoProtocolGuid + 0xd432a67f, 0x14dc, 0x484b, 0xb3, 0xbb, 0x3f, 0x02, 0x91, 0x84, 0x93, 0x27 + + + gEfiFvbExtensionProtocolGuid + 0x53a4c71b, 0xb581, 0x4170, 0x91, 0xb3, 0x8d, 0xb8, 0x7a, 0x4b, 0x5c, 0x46 + + + gEfiFaultTolerantWriteLiteProtocolGuid + 0x3f557189, 0x8dae, 0x45ae, 0xa0, 0xb3, 0x2b, 0x99, 0xca, 0x7a, 0xa7, 0xa0 + + + gEfiConsoleControlProtocolGuid + 0xf42f7782, 0x12e, 0x4c12, 0x99, 0x56, 0x49, 0xf9, 0x43, 0x04, 0xf7, 0x21 + + + gEfiOEMBadgingProtocolGuid + 0x170e13c0, 0xbf1b, 0x4218, 0x87, 0x1d, 0x2a, 0xbd, 0xc6, 0xf8, 0x87, 0xbc + + + gEfiUgaSplashProtocolGuid + 0xa45b3a0d, 0x2e55, 0x4c03, 0xad, 0x9c, 0x27, 0xd4, 0x82, 0x0b, 0x50, 0x7e + + + gEfiAcpiS3SaveProtocolGuid + 0x125f2de1, 0xfb85, 0x440c, 0xa5, 0x4c, 0x4d, 0x99, 0x35, 0x8a, 0x8d, 0x38 + + + gEfiPerformanceProtocolGuid + 0xFFECFFFF, 0x923C, 0x14d2, 0x9E, 0x3F, 0x22, 0xA0, 0xC9, 0x69, 0x56, 0x3B + + + gEfiPxeDhcp4ProtocolGuid + 0x03c4e624, 0xac28, 0x11d3, 0x9a, 0x2d, 0x00, 0x90, 0x29, 0x3f, 0xc1, 0x4d + + + gEfiPxeDhcp4CallbackProtocolGuid + 0xc1544c01, 0x92a4, 0x4198, 0x8a, 0x84, 0x77, 0x85, 0x83, 0xc2, 0x36, 0x21 + + + gEfiUgaIoProtocolGuid + 0x61a4d49e, 0x6f68, 0x4f1b, 0xb9, 0x22, 0xa8, 0x6e, 0xed, 0x0b, 0x07, 0xa2 + + + gEfiDebugAssertProtocolGuid + 0xbe499c92, 0x7d4b, 0x11d4, 0xbc, 0xee, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81 + + + gEfiUsbAtapiProtocolGuid + 0x2B2F68DA, 0x0CD2, 0x44cf, 0x8E, 0x8B, 0xBB, 0xA2, 0x0B, 0x1B, 0x5B, 0x75 + + + gEfiPciHotPlugRequestProtocolGuid + 0x19cb87ab, 0x2cb9, 0x4665, 0x83, 0x60, 0xdd, 0xcf, 0x60, 0x54, 0xf7, 0x9d + + + gEfiExtendedSalBootServiceProtocolGuid + 0xde0ee9a4, 0x3c7a, 0x44f2, 0xb7, 0x8b, 0xe3, 0xcc, 0xd6, 0x9c, 0x3a, 0xf7 + + + gEfiExtendedSalVariableServicesProtocolGuid + 0x4ecb6c53, 0xc641, 0x4370, 0x8c, 0xb2, 0x3b, 0x0e, 0x49, 0x6e, 0x83, 0x78 + + + gEfiExtendedSalStatusCodeServicesProtocolGuid + 0x00dbd91d, 0x55e9, 0x420f, 0x96, 0x39, 0x5e, 0x9f, 0x84, 0x37, 0xb4, 0x4f + + + gEfiIsaIoProtocolGuid + 0x7ee2bd44, 0x3da0, 0x11d4, 0x9a, 0x38, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d + + + gEfiIsaAcpiProtocolGuid + 0x64a892dc, 0x5561, 0x4536, 0x92, 0xc7, 0x79, 0x9b, 0xfc, 0x18, 0x33, 0x55 + + + + + gPeiInMemoryGuid + 0x643b8786, 0xb417, 0x48d2, 0x8f, 0x5e, 0x78, 0x19, 0x93, 0x1c, 0xae, 0xd8 + + + gPeiFlashMapPpiGuid + 0xf34c2fa0, 0xde88, 0x4270, 0x84, 0x14, 0x96, 0x12, 0x22, 0xf4, 0x52, 0x1c + + + gPeiBaseMemoryTestPpiGuid + 0xb6ec423c, 0x21d2, 0x490d, 0x85, 0xc6, 0xdd, 0x58, 0x64, 0xea, 0xa6, 0x74 + + + gPeiStatusCodeMemoryPpiGuid + 0x26f8ab01, 0xd3cd, 0x489c, 0x98, 0x4f, 0xdf, 0xde, 0xf7, 0x68, 0x39, 0x5b + + + + + PcdMaximumUnicodeStringLength + 0x00000001 + UINT32 + 1000000 + + + PcdMaximumAsciiStringLength + 0x00000002 + UINT32 + 1000000 + + + PcdMaximumLinkedListLength + 0x00000003 + UINT32 + 1000000 + + + PcdSpinLockTimeout + 0x00000004 + UINT32 + 10000000 + + + PcdDebugPropertyMask + 0x00000005 + UINT8 + 0x0f + + + PcdDebugPrintErrorLevel + 0x00000006 + UINT32 + 0x80000000 + + + PcdReportStatusCodePropertyMask + 0x00000007 + UINT8 + 0x07 + + + PcdDebugClearMemoryValue + 0x00000008 + UINT8 + 0xAF + + + PcdDebugClearMemoryValue + 0x00000008 + UINT8 + 0xAF + + + PcdPerformanceLibraryPropertyMask + 0x00000009 + UINT8 + 0 + + + diff --git a/EdkModulePkg/Include/Common/CapsuleName.h b/EdkModulePkg/Include/Common/CapsuleName.h new file mode 100644 index 0000000000..651fbe3889 --- /dev/null +++ b/EdkModulePkg/Include/Common/CapsuleName.h @@ -0,0 +1,28 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + CapsuleName.h + +Abstract: + +--*/ + +#ifndef _CAPSULE_NAME_H +#define _CAPSULE_NAME_H + +// +// If capsule data is passed via a variable, then this name should be used. +// +#define EFI_CAPSULE_VARIABLE_NAME L"CapsuleUpdateData" + +#endif diff --git a/EdkModulePkg/Include/Common/DecompressLibraryHob.h b/EdkModulePkg/Include/Common/DecompressLibraryHob.h new file mode 100644 index 0000000000..ee7b8a2ea1 --- /dev/null +++ b/EdkModulePkg/Include/Common/DecompressLibraryHob.h @@ -0,0 +1,47 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DecompressLibraryHob.h + +Abstract: + + Declaration of HOB that is used to pass decompressor library functions from PEI to DXE + +--*/ + +#ifndef __DECOMPRESS_LIBRARY_HOB_H__ +#define __DECOMPRESS_LIBRARY_HOB_H__ + +typedef +RETURN_STATUS +(EFIAPI *DECOMPRESS_LIBRARY_GET_INFO) ( + IN CONST VOID *Source, + IN UINT32 SourceSize, + OUT UINT32 *DestinationSize, + OUT UINT32 *ScratchSize + ); + +typedef +RETURN_STATUS +(EFIAPI *DECOMPRESS_LIBRARY_DECOMPRESS) ( + IN CONST VOID *Source, + IN OUT VOID *Destination, + IN OUT VOID *Scratch + ); + +typedef struct { + DECOMPRESS_LIBRARY_GET_INFO GetInfo; + DECOMPRESS_LIBRARY_DECOMPRESS Decompress; +} DECOMPRESS_LIBRARY; + +#endif diff --git a/EdkModulePkg/Include/Common/FlashMap.h b/EdkModulePkg/Include/Common/FlashMap.h new file mode 100644 index 0000000000..829fa2ddd6 --- /dev/null +++ b/EdkModulePkg/Include/Common/FlashMap.h @@ -0,0 +1,110 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FlashMap.h + +Abstract: + + FlashMap PPI defined in Tiano + + This code abstracts FlashMap access + +--*/ + +#ifndef __COMMON_FLASHMAP_H__ +#define __COMMON_FLASHMAP_H__ + +#include +// +// Definition for flash map GUIDed HOBs +// +typedef UINT32 EFI_FLASH_AREA_ATTRIBUTES; + +#define EFI_FLASH_AREA_FV 0x0001 +#define EFI_FLASH_AREA_SUBFV 0x0002 +#define EFI_FLASH_AREA_MEMMAPPED_FV 0x0004 +#define EFI_FLASH_AREA_REQUIRED 0x0008 +#define EFI_FLASH_AREA_CORRUPT 0x0010 + +typedef UINT8 EFI_FLASH_AREA_TYPE; + +#define EFI_FLASH_AREA_RECOVERY_BIOS 0x0 // Recovery code +#define EFI_FLASH_AREA_MAIN_BIOS 0x1 // Regular BIOS code +#define EFI_FLASH_AREA_PAL_B 0x2 // PAL-B +#define EFI_FLASH_AREA_RESERVED_03 0x3 // Reserved for backwards compatibility +#define EFI_FLASH_AREA_RESERVED_04 0x4 // Reserved for backwards compatibility +#define EFI_FLASH_AREA_DMI_FRU 0x5 // DMI FRU information +#define EFI_FLASH_AREA_OEM_BINARY 0x6 // OEM Binary Code/data +#define EFI_FLASH_AREA_RESERVED_07 0x7 // Reserved for backwards compatibility +#define EFI_FLASH_AREA_RESERVED_08 0x8 // Reserved for backwards compatibility +#define EFI_FLASH_AREA_RESERVED_09 0x9 // Reserved for backwards compatibility +#define EFI_FLASH_AREA_RESERVED_0A 0x0a // Reserved for backwards compatibility +#define EFI_FLASH_AREA_EFI_VARIABLES 0x0b // EFI variables +#define EFI_FLASH_AREA_MCA_LOG 0x0c // MCA error log +#define EFI_FLASH_AREA_SMBIOS_LOG 0x0d // SMBIOS error log +#define EFI_FLASH_AREA_FTW_BACKUP 0x0e // A backup block during FTW operations +#define EFI_FLASH_AREA_FTW_STATE 0x0f // State information during FTW operations +#define EFI_FLASH_AREA_UNUSED 0x0fd // Not used +#define EFI_FLASH_AREA_GUID_DEFINED 0x0fe // Usage defined by a GUID +#pragma pack(1) +// +// An individual sub-area Entry. +// A single flash area may consist of more than one sub-area. +// +typedef struct { + EFI_FLASH_AREA_ATTRIBUTES Attributes; + UINT32 Reserved; + EFI_PHYSICAL_ADDRESS Base; + EFI_PHYSICAL_ADDRESS Length; + EFI_GUID FileSystem; +} EFI_FLASH_SUBAREA_ENTRY; + +typedef struct { + UINT8 Reserved[3]; + EFI_FLASH_AREA_TYPE AreaType; + EFI_GUID AreaTypeGuid; + UINT32 NumEntries; + EFI_FLASH_SUBAREA_ENTRY Entries[1]; +} EFI_FLASH_MAP_ENTRY_DATA; + +typedef struct { + EFI_HOB_GENERIC_HEADER Header; + EFI_GUID Name; + UINT8 Reserved[3]; + EFI_FLASH_AREA_TYPE AreaType; + EFI_GUID AreaTypeGuid; + UINT32 NumEntries; + EFI_FLASH_SUBAREA_ENTRY Entries[1]; +} EFI_HOB_FLASH_MAP_ENTRY_TYPE; + +// +// Internal definitions +// +typedef struct { + UINT8 Reserved[3]; + EFI_FLASH_AREA_TYPE AreaType; + EFI_GUID AreaTypeGuid; + UINT32 NumberOfEntries; + EFI_FLASH_SUBAREA_ENTRY SubAreaData; +} EFI_FLASH_AREA_HOB_DATA; + +typedef struct { + UINTN Base; + UINTN Length; + EFI_FLASH_AREA_ATTRIBUTES Attributes; + EFI_FLASH_AREA_TYPE AreaType; +} EFI_FLASH_AREA_DATA; + +#pragma pack() + +#endif diff --git a/EdkModulePkg/Include/Common/Variable.h b/EdkModulePkg/Include/Common/Variable.h new file mode 100644 index 0000000000..e75adafc12 --- /dev/null +++ b/EdkModulePkg/Include/Common/Variable.h @@ -0,0 +1,78 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + EfiVariable.h + +Abstract: + + Header file for EFI Variable Services + +--*/ + +#ifndef _EFI_VARIABLE_H_ +#define _EFI_VARIABLE_H_ + +#define VARIABLE_STORE_SIGNATURE EFI_SIGNATURE_32 ('$', 'V', 'S', 'S') + +#define MAX_VARIABLE_SIZE 1024 + +#define VARIABLE_DATA 0x55AA + +// +// Variable Store Header flags +// +#define VARIABLE_STORE_FORMATTED 0x5a +#define VARIABLE_STORE_HEALTHY 0xfe + +// +// Variable Store Status +// +typedef enum { + EfiRaw, + EfiValid, + EfiInvalid, + EfiUnknown +} VARIABLE_STORE_STATUS; + +// +// Variable State flags +// +#define VAR_IN_DELETED_TRANSITION 0xfe // Variable is in obsolete transistion +#define VAR_DELETED 0xfd // Variable is obsolete +#define VAR_ADDED 0x7f // Variable has been completely added +#define IS_VARIABLE_STATE(_c, _Mask) (BOOLEAN) (((~_c) & (~_Mask)) != 0) + +#pragma pack(1) + +typedef struct { + UINT32 Signature; + UINT32 Size; + UINT8 Format; + UINT8 State; + UINT16 Reserved; + UINT32 Reserved1; +} VARIABLE_STORE_HEADER; + +typedef struct { + UINT16 StartId; + UINT8 State; + UINT8 Reserved; + UINT32 Attributes; + UINT32 NameSize; + UINT32 DataSize; + EFI_GUID VendorGuid; +} VARIABLE_HEADER; + +#pragma pack() + +#endif // _EFI_VARIABLE_H_ diff --git a/EdkModulePkg/Include/Common/WorkingBlockHeader.h b/EdkModulePkg/Include/Common/WorkingBlockHeader.h new file mode 100644 index 0000000000..235b740e83 --- /dev/null +++ b/EdkModulePkg/Include/Common/WorkingBlockHeader.h @@ -0,0 +1,47 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + EfiWorkingBlockHeader.h + +Abstract: + + Defines data structure that is the headers found at the runtime + updatable firmware volumes, such as the FileSystemGuid of the + working block, the header structure of the variable block, FTW + working block, or event log block. + +--*/ + +#ifndef _EFI_WORKING_BLOCK_HEADER_H_ +#define _EFI_WORKING_BLOCK_HEADER_H_ + +// +// EFI Fault tolerant working block header +// The header is immediately followed by the write queue. +// +typedef struct { + EFI_GUID Signature; + UINT32 Crc; + UINT32 WorkingBlockValid : 1; + UINT32 WorkingBlockInvalid : 1; +#define WORKING_BLOCK_VALID 0x1 +#define WORKING_BLOCK_INVALID 0x2 + UINT32 Reserved : 6; + UINT8 Reserved3[3]; + UINTN WriteQueueSize; + // + // UINT8 WriteQueue[WriteQueueSize]; + // +} EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER; + +#endif diff --git a/EdkModulePkg/Include/EdkDxe.h b/EdkModulePkg/Include/EdkDxe.h new file mode 100644 index 0000000000..775c52e84c --- /dev/null +++ b/EdkModulePkg/Include/EdkDxe.h @@ -0,0 +1,95 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + EdkDxe.h + +Abstract: + This file defines the base package surface area for writting a PEIM + + Things defined in the Tiano specification go in DxeCis.h. + + Dxe.h contains build environment and library information needed to build + a basic Dxe driver. This file must match the "base package" definition of + how to write a Dxe driver. + +--*/ + +#ifndef __EDK_DXE_H__ +#define __EDK_DXE_H__ + +// +#include +// BUGBUG: We must include this lib here due to ordering issues +// +#include +#include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if ((EDK_RELEASE_VERSION != 0) && (EFI_SPECIFICATION_VERSION < 0x00020000)) +// +// Tiano8.5 Module use ScsiPassThru protocol together with the original ScsiIo protocol +// In UEFI2.0, Module use ScsiPassThruExt Protocol with new UEFI2.0 ScsiIo protocol +// +#include +#endif + +#endif diff --git a/EdkModulePkg/Include/EdkDxeCore.h b/EdkModulePkg/Include/EdkDxeCore.h new file mode 100644 index 0000000000..d1b4ca77e3 --- /dev/null +++ b/EdkModulePkg/Include/EdkDxeCore.h @@ -0,0 +1,53 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + EdkDxe.h + +Abstract: + This file defines the base package surface area for writting a PEIM + + Things defined in the Tiano specification go in DxeCis.h. + + Dxe.h contains build environment and library information needed to build + a basic Dxe driver. This file must match the "base package" definition of + how to write a Dxe driver. + +--*/ + +#ifndef __EDK_DXE_CORE_H__ +#define __EDK_DXE_CORE_H__ + +// +// BUGBUG: We must include this lib here due to ordering issues +// +#include +#include + +// +// BUGBUG: Performance related protocol and Guid. +// They are Tiano-private, but are required for DxeCore +// +#include +#include +// +// BUGBUG: Do these really belomg here? +// +#include +#include + +#include +#include +#include +#include +#include + +#endif diff --git a/EdkModulePkg/Include/EdkDxeDepex.h b/EdkModulePkg/Include/EdkDxeDepex.h new file mode 100644 index 0000000000..1ce8be1832 --- /dev/null +++ b/EdkModulePkg/Include/EdkDxeDepex.h @@ -0,0 +1,62 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + EdkDxeDepex.h + +Abstract: + This include file is only used in *.DXS files. Do not use this + include file in normal DXE code. + + Depex - Dependency Expresion + + The BNF grammar is thus: + ::= before GUID + | after GUID + | SOR + | + ::= and + | or + | + ::= not + | + ::= + | + | + | + ::= true + | false + ::= push GUID + ::= end + +--*/ + +#ifndef __EDK_DXE_DEPEX_H__ +#define __EDK_DXE_DEPEX_H__ + +#include + +// +// The Depex grammer needs the following strings so we must undo +// any pre-processor redefinitions +// +#undef DEPENDENCY_START +#undef BEFORE +#undef AFTER +#undef SOR +#undef AND +#undef OR +#undef NOT +#undef TRUE +#undef FALSE +#undef DEPENDENCY_END + +#endif diff --git a/EdkModulePkg/Include/EdkPeiCore.h b/EdkModulePkg/Include/EdkPeiCore.h new file mode 100644 index 0000000000..4e07efb01b --- /dev/null +++ b/EdkModulePkg/Include/EdkPeiCore.h @@ -0,0 +1,42 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + EdkDxe.h + +Abstract: + This file defines the base package surface area for writting a PEIM + + Things defined in the Tiano specification go in DxeCis.h. + + Dxe.h contains build environment and library information needed to build + a basic Dxe driver. This file must match the "base package" definition of + how to write a Dxe driver. + +--*/ + +#ifndef __EDK_PEI_CORE_H__ +#define __EDK_PEI_CORE_H__ + +// +// BUGBUG: We must include this lib here due to ordering issues +// +#include + +#include + +// +// BUGBUG: Performance related Guid. +// It is Tiano-private, but is required for PeiCore +// +#include + +#endif diff --git a/EdkModulePkg/Include/EdkPeim.h b/EdkModulePkg/Include/EdkPeim.h new file mode 100644 index 0000000000..5da04e555e --- /dev/null +++ b/EdkModulePkg/Include/EdkPeim.h @@ -0,0 +1,58 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + EdkPeim.h + +Abstract: + This file defines the base package surface area for writting a PEIM + + Things defined in the PEI CIS specification go in PeiCis.h. + + EdkPeim.h contains build environment and library information needed to build + a basic PEIM that needs Tiano specific definitiosn. T + + Currently we just add in some extra PPI and GUID definitions + +--*/ + +#ifndef __EDK_PEIM_H__ +#define __EDK_PEIM_H__ + +// +#include +#include +// BUGBUG: We must include this lib here due to ordering issues +// +#include + +// +// BUGBUG: Performance related Guid. +// It is Tiano-private, but is required for PeiCore +// +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#endif diff --git a/EdkModulePkg/Include/EdkPeimDepex.h b/EdkModulePkg/Include/EdkPeimDepex.h new file mode 100644 index 0000000000..0b5059906e --- /dev/null +++ b/EdkModulePkg/Include/EdkPeimDepex.h @@ -0,0 +1,56 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + EdkPeimDepex.h + +Abstract: + This include file is only used in *.DXS files. Do not use this + include file in normal Peim code. + + Depex - Dependency Expresion + + The BNF grammar is thus: + ::= + ::= and + | or + | + ::= not + | + ::= + | + | + | + ::= true + | false + ::= push GUID + ::= end + +--*/ + +#ifndef __EDK_PEIM_DEPEX_H__ +#define __EDK_PEIM_DEPEX_H__ + +#include + +// +// The Depex grammer needs the following strings so we must undo +// any pre-processor redefinitions +// +#undef DEPENDENCY_START +#undef AND +#undef OR +#undef NOT +#undef TRUE +#undef FALSE +#undef DEPENDENCY_END + +#endif diff --git a/EdkModulePkg/Include/Guid/AlternateFvBlock.h b/EdkModulePkg/Include/Guid/AlternateFvBlock.h new file mode 100644 index 0000000000..e3a789a4d2 --- /dev/null +++ b/EdkModulePkg/Include/Guid/AlternateFvBlock.h @@ -0,0 +1,32 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + AlternateFvBlock.h + +Abstract: + + Tiano Guid used to define the Alternate Firmware Volume Block Guid. + +--*/ + +#ifndef _ALT_FVB_GUID_H +#define _ALT_FVB_GUID_H + +#define EFI_ALTERNATE_FV_BLOCK_GUID \ + { \ + 0xf496922d, 0x172f, 0x4bbc, {0xa1, 0xeb, 0xe, 0xeb, 0x94, 0x9c, 0x34, 0x86 } \ + } + +extern EFI_GUID gEfiAlternateFvBlockGuid; + +#endif diff --git a/EdkModulePkg/Include/Guid/Bmp.h b/EdkModulePkg/Include/Guid/Bmp.h new file mode 100644 index 0000000000..7a5f5a8d8e --- /dev/null +++ b/EdkModulePkg/Include/Guid/Bmp.h @@ -0,0 +1,62 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Bmp.h + +Abstract: + +--*/ + +#ifndef _BMP_GUID_H_ +#define _BMP_GUID_H_ + + +// +// Definitions for BMP files +// +#pragma pack(1) + +typedef struct { + UINT8 Blue; + UINT8 Green; + UINT8 Red; + UINT8 Reserved; +} BMP_COLOR_MAP; + +typedef struct { + CHAR8 CharB; + CHAR8 CharM; + UINT32 Size; + UINT16 Reserved[2]; + UINT32 ImageOffset; + UINT32 HeaderSize; + UINT32 PixelWidth; + UINT32 PixelHeight; + UINT16 Planes; // Must be 1 + UINT16 BitPerPixel; // 1, 4, 8, or 24 + UINT32 CompressionType; + UINT32 ImageSize; // Compressed image size in bytes + UINT32 XPixelsPerMeter; + UINT32 YPixelsPerMeter; + UINT32 NumberOfColors; + UINT32 ImportantColors; +} BMP_IMAGE_HEADER; + +#pragma pack() + +#define EFI_DEFAULT_BMP_LOGO_GUID \ + {0x7BB28B99,0x61BB,0x11d5,{0x9A,0x5D,0x00,0x90,0x27,0x3F,0xC1,0x4D}} + +extern EFI_GUID gEfiDefaultBmpLogoGuid; + +#endif diff --git a/EdkModulePkg/Include/Guid/BootState.h b/EdkModulePkg/Include/Guid/BootState.h new file mode 100644 index 0000000000..2d9a0d1faf --- /dev/null +++ b/EdkModulePkg/Include/Guid/BootState.h @@ -0,0 +1,36 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + BootState.h + +Abstract: + + Constants and declarations that are common accross PEI and DXE. +--*/ + +#ifndef _BOOT_STATE_H_ +#define _BOOT_STATE_H_ + +// +// BOOT STATE +// + +typedef UINT32 EFI_BOOT_STATE; + +#define BOOT_STATE_VARIABLE_NAME L"BootState" + +#define EFI_BOOT_STATE_VARIABLE_GUID \ + {0x60b5e939, 0xfcf, 0x4227, {0xba, 0x83, 0x6b, 0xbe, 0xd4, 0x5b, 0xc0, 0xe3} } + +extern EFI_GUID gEfiBootStateGuid; +#endif diff --git a/EdkModulePkg/Include/Guid/CapsuleVendor.h b/EdkModulePkg/Include/Guid/CapsuleVendor.h new file mode 100644 index 0000000000..4f5762883a --- /dev/null +++ b/EdkModulePkg/Include/Guid/CapsuleVendor.h @@ -0,0 +1,35 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + CapsuleVendor.h + +Abstract: + + Capsule update Guid definitions + +--*/ + +#ifndef _EFI_CAPSULE_VENDOR_GUID_H_ +#define _EFI_CAPSULE_VENDOR_GUID_H_ + +// +// Note -- This guid is used as a vendor GUID (depending on implementation) +// for the capsule variable if the capsule pointer is passes through reset +// via a variable. +// +#define EFI_CAPSULE_VENDOR_GUID \ + { 0x711C703F, 0xC285, 0x4B10, { 0xA3, 0xB0, 0x36, 0xEC, 0xBD, 0x3C, 0x8B, 0xE2 } } + +extern EFI_GUID gEfiCapsuleVendorGuid; + +#endif // #ifndef _EFI_CAPSULE_VENDOR_GUID_H_ diff --git a/EdkModulePkg/Include/Guid/CompatibleMemoryTested.h b/EdkModulePkg/Include/Guid/CompatibleMemoryTested.h new file mode 100644 index 0000000000..645cacf93e --- /dev/null +++ b/EdkModulePkg/Include/Guid/CompatibleMemoryTested.h @@ -0,0 +1,32 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + CompatibleMemoryTested.h + +Abstract: + + Tiano Guid used for all Compatible Memory Range Tested GUID. + +--*/ + +#ifndef _COMPATIBLE_MEMORY_TESTED_GUID_H_ +#define _COMPATIBLE_MEMORY_TESTED_GUID_H_ + +#define EFI_COMPATIBLE_MEMORY_TESTED_PROTOCOL_GUID \ + { \ + 0x64c475ef, 0x344b, 0x492c, 0x93, 0xad, 0xab, 0x9e, 0xb4, 0x39, 0x50, 0x4 \ + } + +extern EFI_GUID gEfiCompatibleMemoryTestedGuid; + +#endif diff --git a/EdkModulePkg/Include/Guid/ConsoleInDevice.h b/EdkModulePkg/Include/Guid/ConsoleInDevice.h new file mode 100644 index 0000000000..6e53028307 --- /dev/null +++ b/EdkModulePkg/Include/Guid/ConsoleInDevice.h @@ -0,0 +1,29 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ConsoleInDevice.h + +Abstract: + + +--*/ + +#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/EdkModulePkg/Include/Guid/ConsoleOutDevice.h b/EdkModulePkg/Include/Guid/ConsoleOutDevice.h new file mode 100644 index 0000000000..691aa4167d --- /dev/null +++ b/EdkModulePkg/Include/Guid/ConsoleOutDevice.h @@ -0,0 +1,29 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ConsoleOutDevice.h + +Abstract: + + +--*/ + +#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/EdkModulePkg/Include/Guid/ExtendedSalGuid.h b/EdkModulePkg/Include/Guid/ExtendedSalGuid.h new file mode 100644 index 0000000000..4a4dbee9c0 --- /dev/null +++ b/EdkModulePkg/Include/Guid/ExtendedSalGuid.h @@ -0,0 +1,279 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ExtendedSalGuid.h + +Abstract: + + +--*/ + +#ifndef _EXTENDED_SAL_GUID_H_ +#define _EXTENDED_SAL_GUID_H_ + +// +// Extended SAL Services protocol GUIDs +// + +#define EFI_EXTENDED_SAL_BASE_IO_SERVICES_PROTOCOL_GUID \ + { 0x5aea42b5, 0x31e1, 0x4515, {0xbc, 0x31, 0xb8, 0xd5, 0x25, 0x75, 0x65, 0xa6 } } + +#define EFI_EXTENDED_SAL_STALL_SERVICES_PROTOCOL_GUID \ + { 0x53a58d06, 0xac27, 0x4d8c, {0xb5, 0xe9, 0xf0, 0x8a, 0x80, 0x65, 0x41, 0x70 } } + +#define EFI_EXTENDED_SAL_LOCK_SERVICES_PROTOCOL_GUID \ + { 0x76b75c23, 0xfe4f, 0x4e17, {0xa2, 0xad, 0x1a, 0x65, 0x3d, 0xbb, 0x49, 0x4a } } + +#define EFI_EXTENDED_SAL_VIRTUAL_SERVICES_PROTOCOL_GUID \ + { 0xc1a74056, 0x260e, 0x4871, {0xa0, 0x31, 0xe6, 0x45, 0xa6, 0x5b, 0x6e, 0x11 } } + +#define EFI_EXTENDED_SAL_RTC_SERVICES_PROTOCOL_GUID \ + { 0x7e97a470, 0xefdb, 0x4d02, {0x8f, 0xce, 0x61, 0x90, 0xd2, 0x7b, 0xa2, 0x96 } } + +#define EFI_EXTENDED_SAL_VARIABLE_SERVICES_PROTOCOL_GUID \ + { 0x4ecb6c53, 0xc641, 0x4370, {0x8c, 0xb2, 0x3b, 0x0e, 0x49, 0x6e, 0x83, 0x78 } } + +#define EFI_EXTENDED_SAL_MTC_SERVICES_PROTOCOL_GUID \ + { 0x899afd18, 0x75e8, 0x408b, {0xa4, 0x1a, 0x6e, 0x2e, 0x7e, 0xcd, 0xf4, 0x54 } } + +#define EFI_EXTENDED_SAL_RESET_SERVICES_PROTOCOL_GUID \ + { 0x7d019990, 0x8ce1, 0x46f5, {0xa7, 0x76, 0x3c, 0x51, 0x98, 0x67, 0x6a, 0xa0 } } + +#define EFI_EXTENDED_SAL_STATUS_CODE_SERVICES_PROTOCOL_GUID \ + { 0xdbd91d, 0x55e9, 0x420f, {0x96, 0x39, 0x5e, 0x9f, 0x84, 0x37, 0xb4, 0x4f } } + +#define EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID \ + { 0xa2271df1, 0xbcbb, 0x4f1d, {0x98, 0xa9, 0x06, 0xbc, 0x17, 0x2f, 0x07, 0x1a } } + +#define EFI_EXTENDED_SAL_MP_SERVICES_PROTOCOL_GUID \ + { 0x697d81a2, 0xcf18, 0x4dc0, {0x9e, 0x0d, 0x06, 0x11, 0x3b, 0x61, 0x8a, 0x3f } } + +#define EFI_EXTENDED_SAL_PAL_SERVICES_PROTOCOL_GUID \ + { 0xe1cd9d21, 0x0fc2, 0x438d, {0x97, 0x03, 0x04, 0xe6, 0x6d, 0x96, 0x1e, 0x57 } } + +#define EFI_EXTENDED_SAL_BASE_SERVICES_PROTOCOL_GUID \ + { 0xd9e9fa06, 0x0fe0, 0x41c3, {0x96, 0xfb, 0x83, 0x42, 0x5a, 0x33, 0x94, 0xf8 } } + +#define EFI_EXTENDED_SAL_MCA_SERVICES_PROTOCOL_GUID \ + { 0x2a591128, 0x6cc7, 0x42b1, {0x8a, 0xf0, 0x58, 0x93, 0x3b, 0x68, 0x2d, 0xbb } } + +#define EFI_EXTENDED_SAL_PCI_SERVICES_PROTOCOL_GUID \ + { 0xa46b1a31, 0xad66, 0x4905, {0x92, 0xf6, 0x2b, 0x46, 0x59, 0xdc, 0x30, 0x63 } } + +#define EFI_EXTENDED_SAL_CACHE_SERVICES_PROTOCOL_GUID \ + { 0xedc9494, 0x2743, 0x4ba5, { 0x88, 0x18, 0x0a, 0xef, 0x52, 0x13, 0xf1, 0x88 } } + +#define EFI_EXTENDED_SAL_MCA_LOG_SERVICES_PROTOCOL_GUID \ + { 0xcb3fd86e, 0x38a3, 0x4c03, {0x9a, 0x5c, 0x90, 0xcf, 0xa3, 0xa2, 0xab, 0x7a } } + +#define EFI_EXTENDED_SAL_ELOG_SERVICES_PROTOCOL_GUID \ + { 0xd5e4ee5f, 0x3e0a, 0x453c, {0xa7, 0x25, 0xb6, 0x92, 0xbb, 0x6, 0x36, 0x5a } } + +#define EFI_EXTENDED_SAL_SENSOR_SERVICES_PROTOCOL_GUID \ + { 0x4a153b6e, 0x85a1, 0x4982, {0x98, 0xf4, 0x6a, 0x8c, 0xfc, 0xa4, 0xab, 0xa1 } } + +#define EFI_EXTENDED_SAL_SM_COM_LAYER_SERVICES_PROTOCOL_GUID \ + { 0x4356799, 0x81b7, 0x4e08, { 0xa3, 0x8d, 0xd9, 0x78, 0xfa, 0x47, 0xba, 0x42 } } + +#define EFI_EXTENDED_SAL_SST_GUID \ + { 0x38802700, 0x868a, 0x4b4e, {0x81, 0xd4, 0x4f, 0x1b, 0xdc, 0xcf, 0xb4, 0x6f } } + +// +// Extended Sal Proc Function IDs. +// + +// +// BugBug: These enums are name colisions waiting to happen. They should all be +// prefixed with Esal! It might be better to just make them #define, so +// they would be all caps. +// + +typedef enum { + IoRead, + IoWrite, + MemRead, + MemWrite +} EFI_EXTENDED_SAL_BASE_IO_SERVICES_FUNC_ID; + +typedef enum { + Stall +} EFI_EXTENDED_SAL_STALL_FUNC_ID; + + +typedef enum { + InitializeLockService, + AcquireLockService, + ReleaseLockService, + MaxLockServiceFunctionId +} EFI_EXTENDED_SAL_LOCK_SERVICES_FUNC_ID; + +// +// BugBug : Covert the first 3 functions into a lib functions +// and move SalRegisterPhysicalAddress to SAL BASE Class +// +typedef enum { + SetVirtualAddress, + IsVirtual, + IsEfiRuntime, + SalRegisterPhysicalAddress +} EFI_EXTENDED_SAL_VIRTUAL_SERVICES_FUNC_ID; + +typedef enum { + GetTime, + SetTime, + GetWakeupTime, + SetWakeupTime, + GetRtcFreq, + InitializeThreshold, + BumpThresholdCount, + GetThresholdCount +} EFI_EXTENDED_SAL_RTC_SERVICES_FUNC_ID; + +typedef enum { + EsalGetVariable, + EsalGetNextVariableName, + EsalSetVariable +} EFI_EXTENDED_SAL_VARIABLE_SERVICES_FUNC_ID; + +typedef enum { + GetNextHighMonotonicCount +} EFI_EXTENDED_SAL_MTC_SERVICES_FUNC_ID; + +typedef enum { + ResetSystem +} EFI_EXTENDED_SAL_RESET_SERVICES_FUNC_ID; + +typedef enum { + StatusCode +} EFI_EXTENDED_SAL_STATUS_CODE_FUNC_ID; + +typedef enum { + ReportStatusCodeService +} EFI_EXTENDED_SAL_STATUS_CODE_SERVICES_FUNC_ID; + +typedef enum { + Read, + Write, + EraseBlock, + GetVolumeAttributes, + SetVolumeAttributes, + GetPhysicalAddress, + GetBlockSize, + EraseCustomBlockRange, +} EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_FUNC_ID; + +typedef enum { + AddCpuData, + RemoveCpuData, + ModifyCpuData, + GetCpuDataByID, + GetCpuDataByIndex, + SendIpi, + CurrentProcInfo, + NumProcessors, + SetMinState, + GetMinState +} EFI_EXTENDED_SAL_MP_SERVICES_FUNC_ID; + +typedef enum { + PalProc, + SetNewPalEntry, + GetNewPalEntry +} EFI_EXTENDED_SAL_PAL_SERVICES_FUNC_ID; + +typedef enum { + SalSetVectors, + SalMcRendez, + SalMcSetParams, + EsalGetVectors, + EsalMcGetParams, + EsalMcGetMcParams, + EsalGetMcCheckinFlags, + EsalGetPlatformBaseFreq +} EFI_EXTENDED_SAL_BASE_SERVICES_FUNC_ID; + +typedef enum { + McaGetStateInfo, + McaRegisterCpu +} EFI_EXTENDED_SAL_MCA_SERVICES_FUNC_ID; + +typedef enum { + SalPciConfigRead, + SalPciConfigWrite +} EFI_EXTENDED_SAL_PCI_SERVICES_FUNC_ID; + +typedef enum { + SalCacheInit, + SalCacheFlush +} EFI_EXTENDED_SAL_CACHE_SERVICES_FUNC_ID; + +typedef enum { + SalGetStateInfo, + SalGetStateInfoSize, + SalClearStateInfo, + EsalGetStateBuffer, + EsalSaveStateBuffer +} EFI_EXTENDED_SAL_MCA_LOG_SERVICES_FUNC_ID; + +typedef enum { + SalSetEventLogData, + SalGetEventLogData, + SalEraseEventLogData, + SalActivateEventLogData +} EFI_EXTENDED_SAL_ELOG_SERVICES_FUNC_ID; + +typedef enum { + EsalGetComControllerInfo, + EsalSendComData, + EsalReceiveComData +} EFI_EXTENDED_SAL_SM_COM_LAYER_SERVICES_FUNC_ID; + +typedef enum { + SalUpdatePal +} EFI_EXTENDED_SAL_UPDATE_PAL_SERVICES_FUNC_ID; + +typedef enum { + EsalReadSensorInfo, + EsalReadSensorStatus, + EsalRearmSensor, + EsalReadSensorData +} EFI_EXTENDED_SAL_SENSOR_SERVICES_FUNC_ID; + +typedef struct { + UINT64 ProtoData; +} ESAL_GUID_DUMMY_PROTOCOL; + +extern EFI_GUID gEfiExtendedSalBaseIoServicesProtocolGuid; +extern EFI_GUID gEfiExtendedSalStallServicesProtocolGuid; +extern EFI_GUID gEfiExtendedSalLockServicesProtocolGuid; +extern EFI_GUID gEfiExtendedSalVirtualServicesProtocolGuid; +extern EFI_GUID gEfiExtendedSalRtcServicesProtocolGuid; +extern EFI_GUID gEfiExtendedSalVariableServicesProtocolGuid; +extern EFI_GUID gEfiExtendedSalMtcServicesProtocolGuid; +extern EFI_GUID gEfiExtendedSalResetServicesProtocolGuid; +extern EFI_GUID gEfiExtendedSalStatusCodeServicesProtocolGuid; +extern EFI_GUID gEfiExtendedSalFvBlockServicesProtocolGuid; +extern EFI_GUID gEfiExtendedSalMpServicesProtocolGuid; +extern EFI_GUID gEfiExtendedSalPalServicesProtocolGuid; +extern EFI_GUID gEfiExtendedSalBaseServicesProtocolGuid; +extern EFI_GUID gEfiExtendedSalMcaServicesProtocolGuid; +extern EFI_GUID gEfiExtendedSalPciServicesProtocolGuid; +extern EFI_GUID gEfiExtendedSalCacheServicesProtocolGuid; +extern EFI_GUID gEfiExtendedSalMcaLogServicesProtocolGuid; +extern EFI_GUID gEfiExtendedSalElogServicesProtocolGuid; +extern EFI_GUID gEfiExtendedSalSensorServicesProtocolGuid; +extern EFI_GUID gEfiExtendedSalSmComLayerServicesProtocolGuid; +extern EFI_GUID gEfiExtendedSalSstGuid; + + +#endif diff --git a/EdkModulePkg/Include/Guid/FlashMapHob.h b/EdkModulePkg/Include/Guid/FlashMapHob.h new file mode 100644 index 0000000000..a9e9b6736f --- /dev/null +++ b/EdkModulePkg/Include/Guid/FlashMapHob.h @@ -0,0 +1,33 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FlashMapHob.h + +Abstract: + + GUID used for Flash Map HOB entries in the HOB list. + +--*/ + +#ifndef _FLASH_MAP_HOB_GUID_H_ +#define _FLASH_MAP_HOB_GUID_H_ + +// +// Definitions for Flash Map +// +#define EFI_FLASH_MAP_HOB_GUID \ + { 0xb091e7d2, 0x5a0, 0x4198, {0x94, 0xf0, 0x74, 0xb7, 0xb8, 0xc5, 0x54, 0x59 } } + +extern EFI_GUID gEfiFlashMapHobGuid; + +#endif // _FLASH_MAP_HOB_GUID_H_ diff --git a/EdkModulePkg/Include/Guid/HotPlugDevice.h b/EdkModulePkg/Include/Guid/HotPlugDevice.h new file mode 100644 index 0000000000..42fb6da8f3 --- /dev/null +++ b/EdkModulePkg/Include/Guid/HotPlugDevice.h @@ -0,0 +1,28 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + HotPlugDevice.h + +Abstract: + + +--*/ + +#ifndef _HOT_PLUG_DEVICE_H_ +#define _HOT_PLUG_DEVICE_H_ + +#define HOT_PLUG_DEVICE_GUID \ + { 0x220ac432, 0x1d43, 0x49e5, {0xa7, 0x4f, 0x4c, 0x9d, 0xa6, 0x7a, 0xd2, 0x3b } } + +extern EFI_GUID gEfiHotPlugDeviceGuid; +#endif diff --git a/EdkModulePkg/Include/Guid/MemoryTypeInformation.h b/EdkModulePkg/Include/Guid/MemoryTypeInformation.h new file mode 100644 index 0000000000..ed9270b09d --- /dev/null +++ b/EdkModulePkg/Include/Guid/MemoryTypeInformation.h @@ -0,0 +1,35 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + MemoryTypeInformation.h + +Abstract: + GUID used for Memory Type Information entries in the HOB list. + +--*/ + +#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; + UINT32 NumberOfPages; +} EFI_MEMORY_TYPE_INFORMATION; + +#endif diff --git a/EdkModulePkg/Include/Guid/MiniShellFile.h b/EdkModulePkg/Include/Guid/MiniShellFile.h new file mode 100644 index 0000000000..fa42d4d6b1 --- /dev/null +++ b/EdkModulePkg/Include/Guid/MiniShellFile.h @@ -0,0 +1,30 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + EfiShell.h + +Abstract: + + FFS Filename for EFI Shell + +--*/ + +#ifndef _MINISHELLFILE_H_ +#define _MINISHELLFILE_H_ + +#define EFI_MINI_SHELL_FILE_GUID \ + { 0x86ad232b, 0xd33a, 0x465c, {0xbf, 0x5f, 0x41, 0x37, 0xb, 0xa9, 0x2f, 0xe2 } } + +extern EFI_GUID gEfiMiniShellFileGuid; + +#endif diff --git a/EdkModulePkg/Include/Guid/PciHotplugDevice.h b/EdkModulePkg/Include/Guid/PciHotplugDevice.h new file mode 100644 index 0000000000..3b488ced2f --- /dev/null +++ b/EdkModulePkg/Include/Guid/PciHotplugDevice.h @@ -0,0 +1,30 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PciHotplugDevice.h + +Abstract: + + GUIDs used to indicate the device is Pccard hotplug device + +--*/ + +#ifndef _PCI_HOTPLUG_DEVICE_GUID_H_ +#define _PCI_HOTPLUG_DEVICE_GUID_H_ + +#define EFI_PCI_HOTPLUG_DEVICE_GUID \ + { 0x0b280816, 0x52e7, 0x4e51, {0xaa, 0x57, 0x11, 0xbd, 0x41, 0xcb, 0xef, 0xc3 } } + +extern EFI_GUID gEfiPciHotplugDeviceGuid; + +#endif diff --git a/EdkModulePkg/Include/Guid/PciOptionRomTable.h b/EdkModulePkg/Include/Guid/PciOptionRomTable.h new file mode 100644 index 0000000000..5ad956e1c3 --- /dev/null +++ b/EdkModulePkg/Include/Guid/PciOptionRomTable.h @@ -0,0 +1,46 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PciOptionRomTable.h + +Abstract: + + GUID and data structure used to describe the list of PCI Option ROMs present in a system. + +--*/ + +#ifndef _PCI_OPTION_ROM_TABLE_GUID_H_ + +#define EFI_PCI_OPTION_ROM_TABLE_GUID \ + { 0x7462660f, 0x1cbd, 0x48da, {0xad, 0x11, 0x91, 0x71, 0x79, 0x13, 0x83, 0x1c } } + +extern EFI_GUID gEfiPciOptionRomTableGuid; + +typedef struct { + EFI_PHYSICAL_ADDRESS RomAddress; + EFI_MEMORY_TYPE MemoryType; + UINT32 RomLength; + UINT32 Seg; + UINT8 Bus; + UINT8 Dev; + UINT8 Func; + BOOLEAN ExecutedLegacyBiosImage; + BOOLEAN DontLoadEfiRom; +} EFI_PCI_OPTION_ROM_DESCRIPTOR; + +typedef struct { + UINT64 PciOptionRomCount; + EFI_PCI_OPTION_ROM_DESCRIPTOR *PciOptionRomDescriptors; +} EFI_PCI_OPTION_ROM_TABLE; + +#endif diff --git a/EdkModulePkg/Include/Guid/PeiPeCoffLoader.h b/EdkModulePkg/Include/Guid/PeiPeCoffLoader.h new file mode 100644 index 0000000000..abafb71afd --- /dev/null +++ b/EdkModulePkg/Include/Guid/PeiPeCoffLoader.h @@ -0,0 +1,67 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + PeiPeCoffLoader.h + +Abstract: + GUID for the PE/COFF Loader APIs shared between PEI and DXE + +--*/ + +#ifndef __PEI_PE_COFF_LOADER_H__ +#define __PEI_PE_COFF_LOADER_H__ + + +#define EFI_PEI_PE_COFF_LOADER_GUID \ + { 0xd8117cff, 0x94a6, 0x11d4, {0x9a, 0x3a, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } } + +typedef struct _EFI_PEI_PE_COFF_LOADER_PROTOCOL EFI_PEI_PE_COFF_LOADER_PROTOCOL; + + +typedef +EFI_STATUS +(EFIAPI *EFI_PEI_PE_COFF_LOADER_GET_IMAGE_INFO) ( + IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This, + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_PEI_PE_COFF_LOADER_LOAD_IMAGE) ( + IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This, + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_PEI_PE_COFF_LOADER_RELOCATE_IMAGE) ( + IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This, + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_PEI_PE_COFF_LOADER_UNLOAD_IMAGE) ( + IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This, + IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ); + +struct _EFI_PEI_PE_COFF_LOADER_PROTOCOL { + EFI_PEI_PE_COFF_LOADER_GET_IMAGE_INFO GetImageInfo; + EFI_PEI_PE_COFF_LOADER_LOAD_IMAGE LoadImage; + EFI_PEI_PE_COFF_LOADER_RELOCATE_IMAGE RelocateImage; + EFI_PEI_PE_COFF_LOADER_UNLOAD_IMAGE UnloadImage; +}; + +extern EFI_GUID gEfiPeiPeCoffLoaderGuid; + +#endif diff --git a/EdkModulePkg/Include/Guid/PeiPerformanceHob.h b/EdkModulePkg/Include/Guid/PeiPerformanceHob.h new file mode 100644 index 0000000000..33a2dc9089 --- /dev/null +++ b/EdkModulePkg/Include/Guid/PeiPerformanceHob.h @@ -0,0 +1,60 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PeiPerformanceHob.h + +Abstract: + + GUIDs used for PEI Performance HOB data structures + +--*/ + +#ifndef __PEI_PERFORMANCE_HOB_H__ +#define __PEI_PERFORMANCE_HOB_H__ + +// +// This is the GUID of PEI performance HOB +// +#define PEI_PERFORMANCE_HOB_GUID \ + { 0xec4df5af, 0x4395, 0x4cc9, { 0x94, 0xde, 0x77, 0x50, 0x6d, 0x12, 0xc7, 0xb8 } } + +// +// 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) +// +// Bugbug: This macro will be replaced by a binary patchable PCD entry in EdkModulePkg +// +#define MAX_PEI_PERFORMANCE_LOG_ENTRIES 28 + +typedef struct { + EFI_PHYSICAL_ADDRESS Handle; + CHAR8 Token[PEI_PERFORMANCE_STRING_SIZE]; + CHAR8 Module[PEI_PERFORMANCE_STRING_SIZE]; + UINT64 StartTimeStamp; + UINT64 EndTimeStamp; +} PEI_PERFORMANCE_LOG_ENTRY; + +// +// The header must be aligned at 8 bytes. +// +typedef struct { + UINT32 NumberOfEntries; + UINT32 Reserved; +} PEI_PERFORMANCE_LOG_HEADER; + + +extern EFI_GUID gPeiPerformanceHobGuid; + +#endif diff --git a/EdkModulePkg/Include/Guid/PrimaryConsoleInDevice.h b/EdkModulePkg/Include/Guid/PrimaryConsoleInDevice.h new file mode 100644 index 0000000000..e5aa49cf44 --- /dev/null +++ b/EdkModulePkg/Include/Guid/PrimaryConsoleInDevice.h @@ -0,0 +1,29 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PrimaryConsoleInDevice.h + +Abstract: + + +--*/ + +#ifndef _PRIMARY_CONSOLE_IN_DEVICE_H_ +#define _PRIMARY_CONSOLE_IN_DEVICE_H_ + +#define EFI_PRIMARY_CONSOLE_IN_DEVICE_GUID \ + { 0xe451dcbe, 0x96a1, 0x4729, {0xa5, 0xcf, 0x6b, 0x9c, 0x2c, 0xff, 0x47, 0xfd } } + +extern EFI_GUID gEfiPrimaryConsoleInDeviceGuid; + +#endif diff --git a/EdkModulePkg/Include/Guid/PrimaryConsoleOutDevice.h b/EdkModulePkg/Include/Guid/PrimaryConsoleOutDevice.h new file mode 100644 index 0000000000..f73d727e88 --- /dev/null +++ b/EdkModulePkg/Include/Guid/PrimaryConsoleOutDevice.h @@ -0,0 +1,28 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PrimaryConsoleOutDevice.h + +Abstract: + +--*/ + +#ifndef _PRIMARY_CONSOLE_OUT_DEVICE_H_ +#define _PRIMARY_CONSOLE_OUT_DEVICE_H_ + +#define EFI_PRIMARY_CONSOLE_OUT_DEVICE_GUID \ + { 0x62bdf38a, 0xe3d5, 0x492c, {0x95, 0xc, 0x23, 0xa7, 0xf6, 0x6e, 0x67, 0x2e } } + +extern EFI_GUID gEfiPrimaryConsoleOutDeviceGuid; + +#endif diff --git a/EdkModulePkg/Include/Guid/PrimaryStandardErrorDevice.h b/EdkModulePkg/Include/Guid/PrimaryStandardErrorDevice.h new file mode 100644 index 0000000000..97905ea6aa --- /dev/null +++ b/EdkModulePkg/Include/Guid/PrimaryStandardErrorDevice.h @@ -0,0 +1,28 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PrimaryStandardErrorDevice.h + +Abstract: + +--*/ + +#ifndef _PRIMARY_STANDARD_ERROR_DEVICE_H_ +#define _PRIMARY_STANDARD_ERROR_DEVICE_H_ + +#define EFI_PRIMARY_STANDARD_ERROR_DEVICE_GUID \ + { 0x5a68191b, 0x9b97, 0x4752, {0x99, 0x46, 0xe3, 0x6a, 0x5d, 0xa9, 0x42, 0xb1 } } + +extern EFI_GUID gEfiPrimaryStandardErrorDeviceGuid; + +#endif diff --git a/EdkModulePkg/Include/Guid/ShellFile.h b/EdkModulePkg/Include/Guid/ShellFile.h new file mode 100644 index 0000000000..1f3d3b3d00 --- /dev/null +++ b/EdkModulePkg/Include/Guid/ShellFile.h @@ -0,0 +1,31 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + EfiShell.h + +Abstract: + + FFS Filename for EFI Shell + +--*/ + +#ifndef _SHELLFILE_H_ +#define _SHELLFILE_H_ + +#define EFI_SHELL_FILE_GUID \ + { 0xc57ad6b7, 0x0515, 0x40a8, {0x9d, 0x21, 0x55, 0x16, 0x52, 0x85, 0x4e, 0x37 } } + + +extern EFI_GUID gEfiShellFileGuid; + +#endif diff --git a/EdkModulePkg/Include/Guid/StandardErrorDevice.h b/EdkModulePkg/Include/Guid/StandardErrorDevice.h new file mode 100644 index 0000000000..32b5af44c8 --- /dev/null +++ b/EdkModulePkg/Include/Guid/StandardErrorDevice.h @@ -0,0 +1,29 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + StandardErrorDevice.h + +Abstract: + + +--*/ + +#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/EdkModulePkg/Include/Guid/StatusCode.h b/EdkModulePkg/Include/Guid/StatusCode.h new file mode 100644 index 0000000000..8242290b22 --- /dev/null +++ b/EdkModulePkg/Include/Guid/StatusCode.h @@ -0,0 +1,33 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + StatusCode.h + +Abstract: + + GUID used to identify Data Hub records that originate from the Tiano + ReportStatusCode API. + +--*/ + +#ifndef _STATUS_CODE_H__ +#define _STATUS_CODE_H__ + +#define EFI_STATUS_CODE_GUID \ + { \ + 0xd083e94c, 0x6560, 0x42e4, {0xb6, 0xd4, 0x2d, 0xf7, 0x5a, 0xdf, 0x6a, 0x2a } \ + } + +extern EFI_GUID gEfiStatusCodeGuid; + +#endif diff --git a/EdkModulePkg/Include/Guid/StatusCodeCallerId.h b/EdkModulePkg/Include/Guid/StatusCodeCallerId.h new file mode 100644 index 0000000000..8cf9d16928 --- /dev/null +++ b/EdkModulePkg/Include/Guid/StatusCodeCallerId.h @@ -0,0 +1,30 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + StatusCodeCallerId.h + +Abstract: + GUID used to identify id for the caller who is initiating the Status Code. + +--*/ + +#ifndef __STATUS_CODE_CALLER_ID_H__ +#define __STATUS_CODE_CALLER_ID_H__ + + +#define EFI_STANDARD_CALLER_ID_GUID \ + {0xC9DCF469, 0xA7C4, 0x11D5, {0x87, 0xDA, 0x00, 0x06, 0x29, 0x45, 0xC3, 0xB9} } + +extern EFI_GUID gEfiCallerIdGuid; + + +#endif diff --git a/EdkModulePkg/Include/Guid/SystemNvDataGuid.h b/EdkModulePkg/Include/Guid/SystemNvDataGuid.h new file mode 100644 index 0000000000..946d4d8d03 --- /dev/null +++ b/EdkModulePkg/Include/Guid/SystemNvDataGuid.h @@ -0,0 +1,45 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + SystemNvDataGuid.h + +Abstract: + + GUIDs used for System Non Volatile HOB entries in the in the HOB list and FV Guids carrying + the System specific information. + +--*/ + +#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 EFI_SYSTEM_NV_DATA_HOB_GUID \ + {0xd6e5092d, 0xc7b2, 0x4872, {0xaf, 0x66, 0xfd, 0xc0, 0xe6, 0xf9, 0x5e, 0x78} } + +typedef struct { + EFI_GUID SystemNvDataHobGuid; + EFI_GUID SystemNvDataFvGuid; + EFI_LBA StartLba; + UINTN StartLbaOffset; + EFI_LBA EndLba; + UINTN EndLbaOffset; + UINT32 DataTypeSignature; +} NV_SYSTEM_DATA_GUID_TYPE; + +extern EFI_GUID gEfiSystemNvDataHobGuid; +extern EFI_GUID gEfiSystemNvDataFvGuid; + +#endif diff --git a/EdkModulePkg/Include/Library/CustomDecompressLib.h b/EdkModulePkg/Include/Library/CustomDecompressLib.h new file mode 100644 index 0000000000..6edd3ba80f --- /dev/null +++ b/EdkModulePkg/Include/Library/CustomDecompressLib.h @@ -0,0 +1,42 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + CustomDecompressLib.h + +Abstract: + + Custom Decompress Functions + +--*/ + +#ifndef __CUSTOM_DECPOMPRESS_LIB_H__ +#define __CUSTOM_DECPOMPRESS_LIB_H__ + +RETURN_STATUS +EFIAPI +CustomDecompressGetInfo ( + IN CONST VOID *Source, + IN UINT32 SourceSize, + OUT UINT32 *DestinationSize, + OUT UINT32 *ScratchSize + ); + +RETURN_STATUS +EFIAPI +CustomDecompress ( + IN CONST VOID *Source, + IN OUT VOID *Destination, + IN OUT VOID *Scratch + ); + +#endif diff --git a/EdkModulePkg/Include/Library/EdkBsDataHubStatusCodeLib.h b/EdkModulePkg/Include/Library/EdkBsDataHubStatusCodeLib.h new file mode 100644 index 0000000000..a334c92697 --- /dev/null +++ b/EdkModulePkg/Include/Library/EdkBsDataHubStatusCodeLib.h @@ -0,0 +1,47 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + BsDataHubStatusCodeLib.h + +Abstract: + + Lib to provide data hub status code reporting. + +--*/ + +#ifndef _EFI_BS_DATA_HUB_STATUS_CODE_LIB_H_ +#define _EFI_BS_DATA_HUB_STATUS_CODE_LIB_H_ + +// +// Initialization function +// +VOID +BsDataHubStatusCodeInitialize ( + VOID + ) +; + +// +// Status code reporting function +// +EFI_STATUS +BsDataHubReportStatusCode ( + 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/EdkModulePkg/Include/Library/EdkDxeSalLib.h b/EdkModulePkg/Include/Library/EdkDxeSalLib.h new file mode 100644 index 0000000000..9d21846289 --- /dev/null +++ b/EdkModulePkg/Include/Library/EdkDxeSalLib.h @@ -0,0 +1,141 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + EdkDxeSalLib.h + +Abstract: + +--*/ + +#ifndef _ESAL_SERVICE_LIB_H__ +#define _ESAL_SERVICE_LIB_H__ + +//#include + +EFI_STATUS +RegisterEsalFunction ( + IN UINT64 FunctionId, + IN EFI_GUID *ClassGuid, + IN SAL_INTERNAL_EXTENDED_SAL_PROC Function, + IN VOID *ModuleGlobal + ) +/*++ + +Routine Description: + + Register ESAL Class Function and it's asociated global. + This function is boot service only! + +Arguments: + FunctionId - ID of function to register + ClassGuid - GUID of function class + Function - Function to register under ClassGuid/FunctionId pair + ModuleGlobal - Module global for Function. + +Returns: + EFI_SUCCESS - If ClassGuid/FunctionId Function was registered. + +--*/ +; + +EFI_STATUS +RegisterEsalClass ( + IN EFI_GUID *ClassGuid, + IN VOID *ModuleGlobal, + ... + ) +/*++ + +Routine Description: + + Register ESAL Class and it's asociated global. + This function is boot service only! + +Arguments: + ClassGuid - GUID of function class + ModuleGlobal - Module global for Function. + .. - SAL_INTERNAL_EXTENDED_SAL_PROC and FunctionId pairs. NULL + indicates the end of the list. + +Returns: + EFI_SUCCESS - All members of ClassGuid registered + +--*/ +; + +SAL_RETURN_REGS +EfiCallEsalService ( + IN EFI_GUID *ClassGuid, + IN UINT64 FunctionId, + IN UINT64 Arg2, + IN UINT64 Arg3, + IN UINT64 Arg4, + IN UINT64 Arg5, + IN UINT64 Arg6, + IN UINT64 Arg7, + IN UINT64 Arg8 + ) +/*++ + +Routine Description: + + Call module that is not linked direclty to this module. This code is IP + relative and hides the binding issues of virtual or physical calling. The + function that gets dispatched has extra arguments that include the registered + module global and a boolean flag to indicate if the system is in virutal mode. + +Arguments: + ClassGuid - GUID of function + FunctionId - Function in ClassGuid to call + Arg2 - Argument 2 ClassGuid/FunctionId defined + Arg3 - Argument 3 ClassGuid/FunctionId defined + Arg4 - Argument 4 ClassGuid/FunctionId defined + Arg5 - Argument 5 ClassGuid/FunctionId defined + Arg6 - Argument 6 ClassGuid/FunctionId defined + Arg7 - Argument 7 ClassGuid/FunctionId defined + Arg8 - Argument 8 ClassGuid/FunctionId defined + +Returns: + Status of ClassGuid/FuncitonId + +--*/ +; + +SAL_RETURN_REGS +SetEsalVirtualEntryPoint ( + IN UINT64 EntryPoint, + IN UINT64 Gp + ) +; + +SAL_RETURN_REGS +SetEsalPhysicalEntryPoint ( + IN UINT64 EntryPoint, + IN UINT64 Gp + ) +; + +SAL_RETURN_REGS +GetEsalEntryPoint ( + VOID + ) +; + +VOID +SalFlushCache ( + IN EFI_PHYSICAL_ADDRESS Start, + IN UINT64 Length + ) +; + +#endif diff --git a/EdkModulePkg/Include/Library/EdkFvbServiceLib.h b/EdkModulePkg/Include/Library/EdkFvbServiceLib.h new file mode 100644 index 0000000000..16e00d3a8d --- /dev/null +++ b/EdkModulePkg/Include/Library/EdkFvbServiceLib.h @@ -0,0 +1,250 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + EdkFvbServiceLib.h + +Abstract: + +--*/ +#ifndef __EDK_FVB_SERVICE_LIB_H__ +#define __EDK_FVB_SERVICE_LIB_H__ + +EFI_STATUS +EfiFvbReadBlock ( + IN UINTN Instance, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +/*++ + +Routine Description: + Reads specified number of bytes into a buffer from the specified block + +Arguments: + Instance - The FV instance to be read from + Lba - The logical block address to be read from + Offset - Offset into the block at which to begin reading + NumBytes - Pointer that on input contains the total size of + the buffer. On output, it contains the total number + of bytes read + Buffer - Pointer to a caller allocated buffer that will be + used to hold the data read + +Returns: + + Status code + + EFI_INVALID_PARAMETER - invalid parameter + +--*/ +; + +EFI_STATUS +EfiFvbWriteBlock ( + IN UINTN Instance, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +/*++ + +Routine Description: + Writes specified number of bytes from the input buffer to the block + +Arguments: + Instance - The FV instance to be written to + Lba - The starting logical block index to write to + Offset - Offset into the block at which to begin writing + NumBytes - Pointer that on input contains the total size of + the buffer. On output, it contains the total number + of bytes actually written + Buffer - Pointer to a caller allocated buffer that contains + the source for the write + +Returns: + + Status code + + EFI_INVALID_PARAMETER - invalid parameter + +--*/ +; + +EFI_STATUS +EfiFvbEraseBlock ( + IN UINTN Instance, + IN EFI_LBA Lba + ) +/*++ + +Routine Description: + Erases and initializes a firmware volume block + +Arguments: + Instance - The FV instance to be erased + Lba - The logical block index to be erased + +Returns: + + Status code + + EFI_INVALID_PARAMETER - invalid parameter + +--*/ +; + +EFI_STATUS +EfiFvbGetVolumeAttributes ( + IN UINTN Instance, + OUT EFI_FVB_ATTRIBUTES *Attributes + ) +/*++ + +Routine Description: + Retrieves attributes, insures positive polarity of attribute bits, returns + resulting attributes in output parameter + +Arguments: + Instance - The FV instance whose attributes is going to be + returned + Attributes - Output buffer which contains attributes + +Returns: + Status code + + EFI_INVALID_PARAMETER - invalid parameter + +--*/ +; + +EFI_STATUS +EfiFvbSetVolumeAttributes ( + IN UINTN Instance, + IN EFI_FVB_ATTRIBUTES Attributes + ) +/*++ + +Routine Description: + Modifies the current settings of the firmware volume according to the + input parameter, and returns the new setting of the volume + +Arguments: + Instance - The FV instance whose attributes is going to be + modified + Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES + containing the desired firmware volume settings. + On successful return, it contains the new settings + of the firmware volume + +Returns: + Status code + + EFI_INVALID_PARAMETER - invalid parameter + +--*/ +; + +EFI_STATUS +EfiFvbGetPhysicalAddress ( + IN UINTN Instance, + OUT EFI_PHYSICAL_ADDRESS *BaseAddress + ) +/*++ + +Routine Description: + Retrieves the physical address of a memory mapped FV + +Arguments: + Instance - The FV instance whose base address is going to be + returned + BaseAddress - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS + that on successful return, contains the base address + of the firmware volume. + +Returns: + + Status code + + EFI_INVALID_PARAMETER - invalid parameter + +--*/ +; + +EFI_STATUS +EfiFvbGetBlockSize ( + IN UINTN Instance, + IN EFI_LBA Lba, + OUT UINTN *BlockSize, + OUT UINTN *NumOfBlocks + ) +/*++ + +Routine Description: + Retrieve the size of a logical block + +Arguments: + Instance - The FV instance whose block size is going to be + returned + Lba - Indicates which block to return the size for. + BlockSize - A pointer to a caller allocated UINTN in which + the size of the block is returned + NumOfBlocks - a 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 + +Returns: + EFI_SUCCESS - The firmware volume was read successfully and + contents are in Buffer + + EFI_INVALID_PARAMETER - invalid parameter + +--*/ +; + +EFI_STATUS +EfiFvbEraseCustomBlockRange ( + IN UINTN Instance, + IN EFI_LBA StartLba, + IN UINTN OffsetStartLba, + IN EFI_LBA LastLba, + IN UINTN OffsetLastLba + ) +/*++ + +Routine Description: + Erases and initializes a specified range of a firmware volume + +Arguments: + Instance - The FV instance to be erased + StartLba - The starting logical block index to be erased + OffsetStartLba - Offset into the starting block at which to + begin erasing + LastLba - The last logical block index to be erased + OffsetLastLba - Offset into the last block at which to end erasing + +Returns: + + Status code + + EFI_INVALID_PARAMETER - invalid parameter + + EFI_UNSUPPORTED - not support + +--*/ +; + +#endif diff --git a/EdkModulePkg/Include/Library/EdkGraphicsLib.h b/EdkModulePkg/Include/Library/EdkGraphicsLib.h new file mode 100644 index 0000000000..52bedd891a --- /dev/null +++ b/EdkModulePkg/Include/Library/EdkGraphicsLib.h @@ -0,0 +1,185 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + GraphicsLib.h + +Abstract: + + +--*/ + +#ifndef _EFI_GRAPHICS_LIB_H_ +#define _EFI_GRAPHICS_LIB_H_ + +EFI_STATUS +GetGraphicsBitMapFromFV ( + IN EFI_GUID *FileNameGuid, + OUT VOID **Image, + OUT UINTN *ImageSize + ) +/*++ + +Routine Description: + + Return the graphics image file named FileNameGuid into Image and return it's + size in ImageSize. All Firmware Volumes (FV) in the system are searched for the + file name. + +Arguments: + + FileNameGuid - File Name of graphics file in the FV(s). + + Image - Pointer to pointer to return graphics image. If NULL, a + buffer will be allocated. + + ImageSize - Size of the graphics Image in bytes. Zero if no image found. + + +Returns: + + EFI_SUCCESS - Image and ImageSize are valid. + EFI_BUFFER_TOO_SMALL - Image not big enough. ImageSize has required size + EFI_NOT_FOUND - FileNameGuid not found + +--*/ +; + +EFI_STATUS +ConvertBmpToUgaBlt ( + IN VOID *BmpImage, + IN UINTN BmpImageSize, + IN OUT VOID **UgaBlt, + IN OUT UINTN *UgaBltSize, + OUT UINTN *PixelHeight, + OUT UINTN *PixelWidth + ) +/*++ + +Routine Description: + + Convert a *.BMP graphics image to a UGA blt buffer. If a NULL UgaBlt buffer + is passed in a UgaBlt buffer will be allocated by this routine. If a UgaBlt + buffer is passed in it will be used if it is big enough. + +Arguments: + + BmpImage - Pointer to BMP file + + BmpImageSize - Number of bytes in BmpImage + + UgaBlt - Buffer containing UGA version of BmpImage. + + UgaBltSize - Size of UgaBlt in bytes. + + PixelHeight - Height of UgaBlt/BmpImage in pixels + + PixelWidth - Width of UgaBlt/BmpImage in pixels + + +Returns: + + EFI_SUCCESS - UgaBlt and UgaBltSize are returned. + EFI_UNSUPPORTED - BmpImage is not a valid *.BMP image + EFI_BUFFER_TOO_SMALL - The passed in UgaBlt buffer is not big enough. + UgaBltSize will contain the required size. + +--*/ +; + +EFI_STATUS +EnableQuietBoot ( + IN EFI_GUID *LogoFile + ) +/*++ + +Routine Description: + + Use Console Control to turn off UGA based Simple Text Out consoles from going + to the UGA device. Put up LogoFile on every UGA device that is a console + +Arguments: + + LogoFile - File name of logo to display on the center of the screen. + + +Returns: + + EFI_SUCCESS - ConsoleControl has been flipped to graphics and logo + displayed. + EFI_UNSUPPORTED - Logo not found + +--*/ +; + +EFI_STATUS +DisableQuietBoot ( + VOID + ) +/*++ + +Routine Description: + + Use Console Control to turn on UGA based Simple Text Out consoles. The UGA + Simple Text Out screens will now be synced up with all non UGA output devices + +Arguments: + + NONE + +Returns: + + EFI_SUCCESS - UGA devices are back in text mode and synced up. + EFI_UNSUPPORTED - Logo not found + +--*/ +; + +EFI_STATUS +LockKeyboards ( + IN CHAR16 *Password + ) +/*++ + +Routine Description: + Use Console Control Protocol to lock the Console In Spliter virtual handle. + This is the ConInHandle and ConIn handle in the EFI system table. All key + presses will be ignored until the Password is typed in. The only way to + disable the password is to type it in to a ConIn device. + +Arguments: + Password - Password used to lock ConIn device + + +Returns: + + EFI_SUCCESS - ConsoleControl has been flipped to graphics and logo + displayed. + EFI_UNSUPPORTED - Logo not found + +--*/ +; + +UINTN +EFIAPI +PrintXY ( + IN UINTN X, + IN UINTN Y, + IN EFI_UGA_PIXEL *Foreground, OPTIONAL + IN EFI_UGA_PIXEL *Background, OPTIONAL + IN CHAR16 *Fmt, + ... + ) +; + + +#endif diff --git a/EdkModulePkg/Include/Library/EdkIfrSupportLib.h b/EdkModulePkg/Include/Library/EdkIfrSupportLib.h new file mode 100644 index 0000000000..d2a1ff5ee4 --- /dev/null +++ b/EdkModulePkg/Include/Library/EdkIfrSupportLib.h @@ -0,0 +1,1270 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + IfrSupportLib.h + +Abstract: + + The file contain all library function for Ifr Operations. + +--*/ + +#ifndef _IFRSUPPORTLIBRARY_H +#define _IFRSUPPORTLIBRARY_H + +#define DEFAULT_FORM_BUFFER_SIZE 0xFFFF +#define DEFAULT_STRING_BUFFER_SIZE 0xFFFF + +#pragma pack(1) +typedef struct { + CHAR16 *OptionString; // Passed in string to generate a token for in a truly dynamic form creation + STRING_REF StringToken; // This is used when creating a single op-code without generating a StringToken (have one already) + UINT16 Value; + UINT8 Flags; + UINT16 Key; +} IFR_OPTION; +#pragma pack() + +EFI_STATUS +GetCurrentLanguage ( + OUT CHAR16 *Lang + ) +/*++ + +Routine Description: + + Determine what is the current language setting + +Arguments: + + Lang - Pointer of system language + +Returns: + + Status code + +--*/ +; + +EFI_STATUS +AddString ( + IN VOID *StringBuffer, + IN CHAR16 *Language, + IN CHAR16 *String, + IN OUT STRING_REF *StringToken + ) +/*++ + +Routine Description: + + Add a string to the incoming buffer and return the token and offset data + +Arguments: + + StringBuffer - The incoming buffer + + Language - Currrent language + + String - The string to be added + + StringToken - The index where the string placed + +Returns: + + EFI_OUT_OF_RESOURCES - No enough buffer to allocate + + EFI_SUCCESS - String successfully added to the incoming buffer + +--*/ +; + +EFI_STATUS +AddOpCode ( + IN VOID *FormBuffer, + IN OUT VOID *OpCodeData + ) +/*++ + +Routine Description: + + Add op-code data to the FormBuffer + +Arguments: + + FormBuffer - Form buffer to be inserted to + + OpCodeData - Op-code data to be inserted + +Returns: + + EFI_OUT_OF_RESOURCES - No enough buffer to allocate + + EFI_SUCCESS - Op-code data successfully inserted + +--*/ +; + +EFI_STATUS +CreateFormSet ( + IN CHAR16 *FormSetTitle, + IN EFI_GUID *Guid, + IN UINT8 Class, + IN UINT8 SubClass, + IN OUT VOID **FormBuffer, + IN OUT VOID **StringBuffer + ) +/*++ + +Routine Description: + + Create a formset + +Arguments: + + FormSetTitle - Title of formset + + Guid - Guid of formset + + Class - Class of formset + + SubClass - Sub class of formset + + FormBuffer - Pointer of the formset created + + StringBuffer - Pointer of FormSetTitile string created + +Returns: + + EFI_OUT_OF_RESOURCES - No enough buffer to allocate + + EFI_SUCCESS - Formset successfully created + +--*/ +; + +EFI_STATUS +CreateForm ( + IN CHAR16 *FormTitle, + IN UINT16 FormId, + IN OUT VOID *FormBuffer, + IN OUT VOID *StringBuffer + ) +/*++ + +Routine Description: + + Create a form + +Arguments: + + FormTitle - Title of the form + + FormId - Id of the form + + FormBuffer - Pointer of the form created + + StringBuffer - Pointer of FormTitil string created + +Returns: + + EFI_SUCCESS - Form successfully created + +--*/ +; + +EFI_STATUS +CreateSubTitle ( + IN CHAR16 *SubTitle, + IN OUT VOID *FormBuffer, + IN OUT VOID *StringBuffer + ) +/*++ + +Routine Description: + + Create a SubTitle + +Arguments: + + SubTitle - Sub title to be created + + FormBuffer - Where this subtitle to add to + + StringBuffer - String buffer created for subtitle + +Returns: + + EFI_SUCCESS - Subtitle successfully created + +--*/ +; + +EFI_STATUS +CreateText ( + IN CHAR16 *String, + IN CHAR16 *String2, + IN CHAR16 *String3, + IN UINT8 Flags, + IN UINT16 Key, + IN OUT VOID *FormBuffer, + IN OUT VOID *StringBuffer + ) +/*++ + +Routine Description: + + Create a line of text + +Arguments: + + String - First string of the text + + String2 - Second string of the text + + String3 - Help string of the text + + Flags - Flag of the text + + Key - Key of the text + + FormBuffer - The form where this text adds to + + StringBuffer - String buffer created for String, String2 and String3 + +Returns: + + EFI_SUCCESS - Text successfully created + +--*/ +; + +EFI_STATUS +CreateGoto ( + IN UINT16 FormId, + IN CHAR16 *Prompt, + IN OUT VOID *FormBuffer, + IN OUT VOID *StringBuffer + ) +/*++ + +Routine Description: + + Create a hyperlink + +Arguments: + + FormId - Form ID of the hyperlink + + Prompt - Prompt of the hyperlink + + FormBuffer - The form where this hyperlink adds to + + StringBuffer - String buffer created for Prompt + +Returns: + + EFI_SUCCESS - Hyperlink successfully created + +--*/ +; + +EFI_STATUS +CreateOneOf ( + IN UINT16 QuestionId, + IN UINT8 DataWidth, + IN CHAR16 *Prompt, + IN CHAR16 *Help, + IN IFR_OPTION *OptionsList, + IN UINTN OptionCount, + IN OUT VOID *FormBuffer, + IN OUT VOID *StringBuffer + ) +/*++ + +Routine Description: + + Create a one-of question with a set of options to choose from. The + OptionsList is a pointer to a null-terminated list of option descriptions. + +Arguments: + + QuestionId - Question ID of the one-of box + + DataWidth - DataWidth of the one-of box + + Prompt - Prompt of the one-of box + + Help - Help of the one-of box + + OptionsList - Each string in it is an option of the one-of box + + OptionCount - Option string count + + FormBuffer - The form where this one-of box adds to + + StringBuffer - String buffer created for Prompt, Help and Option strings + +Returns: + + EFI_DEVICE_ERROR - DataWidth > 2 + + EFI_SUCCESS - One-Of box successfully created. + +--*/ +; + +EFI_STATUS +CreateOrderedList ( + IN UINT16 QuestionId, + IN UINT8 MaxEntries, + IN CHAR16 *Prompt, + IN CHAR16 *Help, + IN IFR_OPTION *OptionsList, + IN UINTN OptionCount, + IN OUT VOID *FormBuffer, + IN OUT VOID *StringBuffer + ) +/*++ + +Routine Description: + + Create a one-of question with a set of options to choose from. The + OptionsList is a pointer to a null-terminated list of option descriptions. + +Arguments: + + QuestionId - Question ID of the ordered list + + MaxEntries - MaxEntries of the ordered list + + Prompt - Prompt of the ordered list + + Help - Help of the ordered list + + OptionsList - Each string in it is an option of the ordered list + + OptionCount - Option string count + + FormBuffer - The form where this ordered list adds to + + StringBuffer - String buffer created for Prompt, Help and Option strings + +Returns: + + EFI_SUCCESS - Ordered list successfully created. + +--*/ +; + +EFI_STATUS +CreateCheckBox ( + IN UINT16 QuestionId, + IN UINT8 DataWidth, + IN CHAR16 *Prompt, + IN CHAR16 *Help, + IN UINT8 Flags, + IN OUT VOID *FormBuffer, + IN OUT VOID *StringBuffer + ) +/*++ + +Routine Description: + + Create a checkbox + +Arguments: + + QuestionId - Question ID of the check box + + DataWidth - DataWidth of the check box + + Prompt - Prompt of the check box + + Help - Help of the check box + + Flags - Flags of the check box + + FormBuffer - The form where this check box adds to + + StringBuffer - String buffer created for Prompt and Help. + +Returns: + + EFI_DEVICE_ERROR - DataWidth > 1 + + EFI_SUCCESS - Check box successfully created + +--*/ +; + +EFI_STATUS +CreateNumeric ( + IN UINT16 QuestionId, + IN UINT8 DataWidth, + IN CHAR16 *Prompt, + IN CHAR16 *Help, + IN UINT16 Minimum, + IN UINT16 Maximum, + IN UINT16 Step, + IN UINT16 Default, + IN UINT8 Flags, + IN UINT16 Key, + IN OUT VOID *FormBuffer, + IN OUT VOID *StringBuffer + ) +/*++ + +Routine Description: + + Create a numeric + +Arguments: + + QuestionId - Question ID of the numeric + + DataWidth - DataWidth of the numeric + + Prompt - Prompt of the numeric + + Help - Help of the numeric + + Minimum - Minumun boundary of the numeric + + Maximum - Maximum boundary of the numeric + + Step - Step of the numeric + + Default - Default value + + Flags - Flags of the numeric + + Key - Key of the numeric + + FormBuffer - The form where this numeric adds to + + StringBuffer - String buffer created for Prompt and Help. + +Returns: + + EFI_DEVICE_ERROR - DataWidth > 2 + + EFI_SUCCESS - Numeric is successfully created + +--*/ +; + +EFI_STATUS +CreateString ( + IN UINT16 QuestionId, + IN UINT8 DataWidth, + IN CHAR16 *Prompt, + IN CHAR16 *Help, + IN UINT8 MinSize, + IN UINT8 MaxSize, + IN UINT8 Flags, + IN UINT16 Key, + IN OUT VOID *FormBuffer, + IN OUT VOID *StringBuffer + ) +/*++ + +Routine Description: + + Create a string + +Arguments: + + QuestionId - Question ID of the string + + DataWidth - DataWidth of the string + + Prompt - Prompt of the string + + Help - Help of the string + + MinSize - Min size boundary of the string + + MaxSize - Max size boundary of the string + + Flags - Flags of the string + + Key - Key of the string + + FormBuffer - The form where this string adds to + + StringBuffer - String buffer created for Prompt and Help. + +Returns: + + EFI_SUCCESS - String successfully created. + +--*/ +; + +EFI_STATUS +ExtractDataFromHiiHandle ( + IN EFI_HII_HANDLE HiiHandle, + IN OUT UINT16 *ImageLength, + OUT UINT8 *DefaultImage, + OUT EFI_GUID *Guid + ) +/*++ + +Routine Description: + + Extract information pertaining to the HiiHandle + +Arguments: + + HiiHandle - Hii handle + + ImageLength - For input, length of DefaultImage; + For output, length of actually required + + DefaultImage - Image buffer prepared by caller + + Guid - Guid information about the form + +Returns: + + EFI_OUT_OF_RESOURCES - No enough buffer to allocate + + EFI_BUFFER_TOO_SMALL - DefualtImage has no enough ImageLength + + EFI_SUCCESS - Successfully extract data from Hii database. + + +--*/ +; + +EFI_HII_HANDLE +FindHiiHandle ( + IN OUT EFI_HII_PROTOCOL **HiiProtocol, OPTIONAL + IN EFI_GUID *Guid + ) +/*++ + +Routine Description: + Finds HII handle for given pack GUID previously registered with the HII. + +Arguments: + HiiProtocol - pointer to pointer to HII protocol interface. + If NULL, the interface will be found but not returned. + If it points to NULL, the interface will be found and + written back to the pointer that is pointed to. + Guid - The GUID of the pack that registered with the HII. + +Returns: + Handle to the HII pack previously registered by the memory driver. + +--*/ +; + +EFI_STATUS +CreateSubTitleOpCode ( + IN STRING_REF StringToken, + IN OUT VOID *FormBuffer + ) +/*++ + +Routine Description: + + Create a SubTitle opcode independent of string creation + This is used primarily by users who need to create just one particular valid op-code and the string + data will be assumed to exist in the HiiDatabase already. (Useful when exporting op-codes at a label + location to pre-defined forms in HII) + +Arguments: + + StringToken - StringToken of the subtitle + + FormBuffer - Output of subtitle as a form + +Returns: + + EFI_SUCCESS - Subtitle created to be a form + +--*/ +; + +EFI_STATUS +CreateTextOpCode ( + IN STRING_REF StringToken, + IN STRING_REF StringTokenTwo, + IN STRING_REF StringTokenThree, + IN UINT8 Flags, + IN UINT16 Key, + IN OUT VOID *FormBuffer + ) +/*++ + +Routine Description: + + Create a Text opcode independent of string creation + This is used primarily by users who need to create just one particular valid op-code and the string + data will be assumed to exist in the HiiDatabase already. (Useful when exporting op-codes at a label + location to pre-defined forms in HII) + +Arguments: + + StringToken - First string token of the text + + StringTokenTwo - Second string token of the text + + StringTokenThree - Help string token of the text + + Flags - Flag of the text + + Key - Key of the text + + FormBuffer - Output of text as a form + +Returns: + + EFI_SUCCESS - Text created to be a form + +--*/ +; + +EFI_STATUS +CreateGotoOpCode ( + IN UINT16 FormId, + IN STRING_REF StringToken, + IN STRING_REF StringTokenTwo, + IN UINT8 Flags, + IN UINT16 Key, + IN OUT VOID *FormBuffer + ) +/*++ + +Routine Description: + + Create a hyperlink opcode independent of string creation + This is used primarily by users who need to create just one particular valid op-code and the string + data will be assumed to exist in the HiiDatabase already. (Useful when exporting op-codes at a label + location to pre-defined forms in HII) + +Arguments: + + FormId - Form ID of the hyperlink + + StringToken - Prompt string token of the hyperlink + + StringTokenTwo - Help string token of the hyperlink + + Flags - Flags of the hyperlink + + Key - Key of the hyperlink + + FormBuffer - Output of hyperlink as a form + +Returns: + + EFI_SUCCESS - Hyperlink created to be a form + +--*/ +; + +EFI_STATUS +CreateOneOfOpCode ( + IN UINT16 QuestionId, + IN UINT8 DataWidth, + IN STRING_REF PromptToken, + IN STRING_REF HelpToken, + IN IFR_OPTION *OptionsList, + IN UINTN OptionCount, + IN OUT VOID *FormBuffer + ) +/*++ + +Routine Description: + + Create a one-of opcode with a set of option op-codes to choose from independent of string creation. + This is used primarily by users who need to create just one particular valid op-code and the string + data will be assumed to exist in the HiiDatabase already. (Useful when exporting op-codes at a label + location to pre-defined forms in HII) + + OptionsList is a pointer to a null-terminated list of option descriptions. Ensure that OptionsList[x].StringToken + has been filled in since this routine will not generate StringToken values. + +Arguments: + + QuestionId - Question ID of the one-of box + + DataWidth - DataWidth of the one-of box + + PromptToken - Prompt string token of the one-of box + + HelpToken - Help string token of the one-of box + + OptionsList - Each string in it is an option of the one-of box + + OptionCount - Option string count + + FormBuffer - Output of One-Of box as a form + +Returns: + + EFI_SUCCESS - One-Of box created to be a form + + EFI_DEVICE_ERROR - DataWidth > 2 + +--*/ +; + +EFI_STATUS +CreateOrderedListOpCode ( + IN UINT16 QuestionId, + IN UINT8 MaxEntries, + IN STRING_REF PromptToken, + IN STRING_REF HelpToken, + IN IFR_OPTION *OptionsList, + IN UINTN OptionCount, + IN OUT VOID *FormBuffer + ) +/*++ + +Routine Description: + + Create a ordered list opcode with a set of option op-codes to choose from independent of string creation. + This is used primarily by users who need to create just one particular valid op-code and the string + data will be assumed to exist in the HiiDatabase already. (Useful when exporting op-codes at a label + location to pre-defined forms in HII) + + OptionsList is a pointer to a null-terminated list of option descriptions. Ensure that OptionsList[x].StringToken + has been filled in since this routine will not generate StringToken values. + +Arguments: + + QuestionId - Question ID of the ordered list + + MaxEntries - MaxEntries of the ordered list + + PromptToken - Prompt string token of the ordered list + + HelpToken - Help string token of the ordered list + + OptionsList - Each string in it is an option of the ordered list + + OptionCount - Option string count + + FormBuffer - Output of ordered list as a form + +Returns: + + EFI_SUCCESS - Ordered list created to be a form + +--*/ +; + +EFI_STATUS +CreateCheckBoxOpCode ( + IN UINT16 QuestionId, + IN UINT8 DataWidth, + IN STRING_REF PromptToken, + IN STRING_REF HelpToken, + IN UINT8 Flags, + IN UINT16 Key, + IN OUT VOID *FormBuffer + ) +/*++ + +Routine Description: + + Create a checkbox opcode independent of string creation + This is used primarily by users who need to create just one particular valid op-code and the string + data will be assumed to exist in the HiiDatabase already. (Useful when exporting op-codes at a label + location to pre-defined forms in HII) + +Arguments: + + QuestionId - Question ID of the check box + + DataWidth - DataWidth of the check box + + PromptToken - Prompt string token of the check box + + HelpToken - Help string token of the check box + + Flags - Flags of the check box + + Key - Key of the check box + + FormBuffer - Output of the check box as a form + +Returns: + + EFI_SUCCESS - Checkbox created to be a form + + EFI_DEVICE_ERROR - DataWidth > 1 + +--*/ +; + +EFI_STATUS +CreateNumericOpCode ( + IN UINT16 QuestionId, + IN UINT8 DataWidth, + IN STRING_REF PromptToken, + IN STRING_REF HelpToken, + IN UINT16 Minimum, + IN UINT16 Maximum, + IN UINT16 Step, + IN UINT16 Default, + IN UINT8 Flags, + IN UINT16 Key, + IN OUT VOID *FormBuffer + ) +/*++ + +Routine Description: + + Create a numeric opcode independent of string creation + This is used primarily by users who need to create just one particular valid op-code and the string + data will be assumed to exist in the HiiDatabase already. (Useful when exporting op-codes at a label + location to pre-defined forms in HII) + +Arguments: + + QuestionId - Question ID of the numeric + + DataWidth - DataWidth of the numeric + + PromptToken - Prompt string token of the numeric + + HelpToken - Help string token of the numeric + + Minimum - Minumun boundary of the numeric + + Maximum - Maximum boundary of the numeric + + Step - Step of the numeric + + Default - Default value of the numeric + + Flags - Flags of the numeric + + Key - Key of the numeric + + FormBuffer - Output of the numeric as a form + +Returns: + + EFI_SUCCESS - The numeric created to be a form. + + EFI_DEVICE_ERROR - DataWidth > 2 + +--*/ +; + +EFI_STATUS +CreateStringOpCode ( + IN UINT16 QuestionId, + IN UINT8 DataWidth, + IN STRING_REF PromptToken, + IN STRING_REF HelpToken, + IN UINT8 MinSize, + IN UINT8 MaxSize, + IN UINT8 Flags, + IN UINT16 Key, + IN OUT VOID *FormBuffer + ) +/*++ + +Routine Description: + + Create a numeric opcode independent of string creation + This is used primarily by users who need to create just one particular valid op-code and the string + data will be assumed to exist in the HiiDatabase already. (Useful when exporting op-codes at a label + location to pre-defined forms in HII) + +Arguments: + + QuestionId - Question ID of the string + + DataWidth - DataWidth of the string + + PromptToken - Prompt token of the string + + HelpToken - Help token of the string + + MinSize - Min size boundary of the string + + MaxSize - Max size boundary of the string + + Flags - Flags of the string + + Key - Key of the string + + FormBuffer - Output of the string as a form + +Returns: + + EFI_SUCCESS - String created to be a form. + +--*/ +; + +EFI_STATUS +ValidateDataFromHiiHandle ( + IN EFI_HII_HANDLE HiiHandle, + OUT BOOLEAN *Results + ) +/*++ + +Routine Description: + + Validate that the data associated with the HiiHandle in NVRAM is within + the reasonable parameters for that FormSet. Values for strings and passwords + are not verified due to their not having the equivalent of valid range settings. + +Arguments: + + HiiHandle - Handle of the HII database entry to query + + Results - If return Status is EFI_SUCCESS, Results provides valid data + TRUE = NVRAM Data is within parameters + FALSE = NVRAM Data is NOT within parameters + +Returns: + + EFI_OUT_OF_RESOURCES - No enough buffer to allocate + + EFI_SUCCESS - Data successfully validated +--*/ +; + +EFI_STATUS +CreateBannerOpCode ( + IN UINT16 Title, + IN UINT16 LineNumber, + IN UINT8 Alignment, + IN OUT VOID *FormBuffer + ) +/*++ + +Routine Description: + + Create a banner opcode. This is primarily used by the FrontPage implementation from BDS. + +Arguments: + + Title - Title of the banner + + LineNumber - LineNumber of the banner + + Alignment - Alignment of the banner + + FormBuffer - Output of banner as a form + +Returns: + + EFI_SUCCESS - Banner created to be a form. + +--*/ +; + +VOID +EfiLibHiiVariablePackGetMap ( + IN EFI_HII_VARIABLE_PACK *Pack, + OUT CHAR16 **Name, OPTIONAL + OUT EFI_GUID **Guid, OPTIONAL + OUT UINT16 *Id, OPTIONAL + OUT VOID **Var, OPTIONAL + OUT UINTN *Size OPTIONAL + ) +/*++ + +Routine Description: + + Extracts a variable form a Pack. + +Arguments: + + Pack - List of variables + Name - Name of the variable/map + Guid - GUID of the variable/map + Var - Pointer to the variable/map + Size - Size of the variable/map in bytes + +Returns: + + VOID. + +--*/ +; + +UINTN +EfiLibHiiVariablePackListGetMapCnt ( + IN EFI_HII_VARIABLE_PACK_LIST *List + ) +/*++ + +Routine Description: + + Finds a count of the variables/maps in the List. + +Arguments: + + List - List of variables + +Returns: + + Number of Map in the variable pack list. + +--*/ +; + +typedef VOID (EFI_LIB_HII_VARIABLE_PACK_LIST_CALLBACK) ( + IN CHAR16 *Name, + IN EFI_GUID *Guid, + IN UINT16 Id, + IN VOID *Var, + IN UINTN Size + ) +/*++ + +Routine Description: + + type definition for the callback to be + used with EfiLibHiiVariablePackListForEachVar(). + +Arguments: + + Id - Variable/Map ID + Name - Name of the variable/map + Guid - GUID of the variable/map + Var - Pointer to the variable/map + Size - Size of the variable/map in bytes + +Returns: + + VOID + +--*/ +; + +VOID +EfiLibHiiVariablePackListForEachVar ( + IN EFI_HII_VARIABLE_PACK_LIST *List, + IN EFI_LIB_HII_VARIABLE_PACK_LIST_CALLBACK *Callback + ) +/*++ + +Routine Description: + + Will iterate all variable/maps as appearing + in List and for each, it will call the Callback. + +Arguments: + + List - List of variables + Callback - Routine to be called for each iterated variable. + +Returns: + + VOID + +--*/ +; + +EFI_STATUS +EfiLibHiiVariablePackListGetMapByIdx ( + IN UINTN Idx, + IN EFI_HII_VARIABLE_PACK_LIST *List, + OUT CHAR16 **Name, OPTIONAL + OUT EFI_GUID **Guid, OPTIONAL + OUT UINT16 *Id, OPTIONAL + OUT VOID **Var, + OUT UINTN *Size + ) +/*++ + +Routine Description: + + Finds a variable form List given + the order number as appears in the List. + +Arguments: + + Idx - The index of the variable/map to retrieve + List - List of variables + Name - Name of the variable/map + Guid - GUID of the variable/map + Var - Pointer to the variable/map + Size - Size of the variable/map in bytes + +Returns: + + EFI_SUCCESS - Variable is found, OUT parameters are valid + EFI_NOT_FOUND - Variable is not found, OUT parameters are not valid + +--*/ +; + +EFI_STATUS +EfiLibHiiVariablePackListGetMapById ( + IN UINT16 Id, + IN EFI_HII_VARIABLE_PACK_LIST *List, + OUT CHAR16 **Name, OPTIONAL + OUT EFI_GUID **Guid, OPTIONAL + OUT VOID **Var, + OUT UINTN *Size + ) +/*++ + +Routine Description: + + Finds a variable form List given the + order number as appears in the List. + +Arguments: + + Id - The ID of the variable/map to retrieve + List - List of variables + Name - Name of the variable/map + Guid - GUID of the variable/map + Var - Pointer to the variable/map + Size - Size of the variable/map in bytes + +Returns: + + EFI_SUCCESS - Variable is found, OUT parameters are valid + EFI_NOT_FOUND - Variable is not found, OUT parameters are not valid + +--*/ +; + +EFI_STATUS +EfiLibHiiVariablePackListGetMap ( + IN EFI_HII_VARIABLE_PACK_LIST *List, + IN CHAR16 *Name, + IN EFI_GUID *Guid, + OUT UINT16 *Id, + OUT VOID **Var, + OUT UINTN *Size + ) +/*++ + +Routine Description: + + Finds a variable form EFI_HII_VARIABLE_PACK_LIST given name and GUID. + +Arguments: + + List - List of variables + Name - Name of the variable/map to be found + Guid - GUID of the variable/map to be found + Var - Pointer to the variable/map found + Size - Size of the variable/map in bytes found + +Returns: + + EFI_SUCCESS - variable is found, OUT parameters are valid + EFI_NOT_FOUND - variable is not found, OUT parameters are not valid + +--*/ +; + +EFI_STATUS +EfiLibHiiVariableRetrieveFromNv ( + IN CHAR16 *Name, + IN EFI_GUID *Guid, + IN UINTN Size, + OUT VOID **Var + ) +/*++ + +Routine Description: + Finds out if a variable of specific Name/Guid/Size exists in NV. + If it does, it will retrieve it into the Var. + +Arguments: + Name, Guid, Size - Parameters of the variable to retrieve. Must match exactly. + Var - Variable will be retrieved into buffer pointed by this pointer. + If pointing to NULL, the buffer will be allocated. Caller is responsible for releasing the buffer. +Returns: + EFI_SUCCESS - The variable of exact Name/Guid/Size parameters was retrieved and written to Var. + EFI_NOT_FOUND - The variable of this Name/Guid was not found in the NV. + EFI_LOAD_ERROR - The variable in the NV was of different size, or NV API returned error. + +--*/ +; + +//// +//// Variable override support. +//// + +EFI_STATUS +EfiLibHiiVariableOverrideIfSuffix ( + IN CHAR16 *Suffix, + IN CHAR16 *Name, + IN EFI_GUID *Guid, + IN UINTN Size, + OUT VOID *Var + ) +/*++ + +Routine Description: + Overrrides the variable with NV data if found. + But it only does it if the Name ends with specified Suffix. + For example, if Suffix="MyOverride" and the Name="XyzSetupMyOverride", + the Suffix matches the end of Name, so the variable will be loaded from NV + provided the variable exists and the GUID and Size matches. + +Arguments: + Suffix - Suffix the Name should end with. + Name, Guid, Size - Parameters of the variable to retrieve. Must match exactly. + Var - Variable will be retrieved into this buffer. + Caller is responsible for providing storage of exactly Size size in bytes. +Returns: + EFI_SUCCESS - The variable was overriden with NV variable of same Name/Guid/Size. + EFI_INVALID_PARAMETER - The name of the variable does not end with . + EFI_NOT_FOUND - The variable of this Name/Guid was not found in the NV. + EFI_LOAD_ERROR - The variable in the NV was of different size, or NV API returned error. + +--*/ +; + +EFI_STATUS +EfiLibHiiVariableOverrideBySuffix ( + IN CHAR16 *Suffix, + IN CHAR16 *Name, + IN EFI_GUID *Guid, + IN UINTN Size, + OUT VOID *Var + ) +/*++ + +Routine Description: + Overrrides the variable with NV data if found. + But it only does it if the NV contains the same variable with Name is appended with Suffix. + For example, if Suffix="MyOverride" and the Name="XyzSetup", + the Suffix will be appended to the end of Name, and the variable with Name="XyzSetupMyOverride" + will be loaded from NV provided the variable exists and the GUID and Size matches. + +Arguments: + Suffix - Suffix the variable will be appended with. + Name, Guid, Size - Parameters of the variable to retrieve. Must match exactly. + Var - Variable will be retrieved into this buffer. + Caller is responsible for providing storage of exactly Size size in bytes. + +Returns: + EFI_SUCCESS - The variable was overriden with NV variable of same Name/Guid/Size. + EFI_NOT_FOUND - The variable of this Name/Guid was not found in the NV. + EFI_LOAD_ERROR - The variable in the NV was of different size, or NV API returned error. + +--*/ +; + +#endif diff --git a/EdkModulePkg/Include/Library/EdkMemoryStatusCodeLib.h b/EdkModulePkg/Include/Library/EdkMemoryStatusCodeLib.h new file mode 100644 index 0000000000..08aaf69c47 --- /dev/null +++ b/EdkModulePkg/Include/Library/EdkMemoryStatusCodeLib.h @@ -0,0 +1,48 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + MemoryStatusCodeLib.h + +Abstract: + + Lib to provide memory status code reporting. + +--*/ + +#ifndef _PEI_MEMORY_STATUS_CODE_LIB_H_ +#define _PEI_MEMORY_STATUS_CODE_LIB_H_ + +// +// Initialization function +// +EFI_STATUS +MemoryStatusCodeInitialize ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices + ) +; + +// +// Status code reporting function +// +EFI_STATUS +MemoryReportStatusCode ( + 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/EdkModulePkg/Include/Library/EdkPeCoffLoaderLib.h b/EdkModulePkg/Include/Library/EdkPeCoffLoaderLib.h new file mode 100644 index 0000000000..ccacf7ee5e --- /dev/null +++ b/EdkModulePkg/Include/Library/EdkPeCoffLoaderLib.h @@ -0,0 +1,32 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + EdkPeCoffLoaderLib.h + +Abstract: + Wrap the Base PE/COFF loader with the PE COFF Protocol + + + +--*/ + +#ifndef __EDK_PE_COFF_LOADER_LIB__ +#define __EDK_PE_COFF_LOADER_LIB__ + +EFI_PEI_PE_COFF_LOADER_PROTOCOL * +EFIAPI +GetPeCoffLoaderProtocol ( + VOID + ); + +#endif diff --git a/EdkModulePkg/Include/Library/EdkPeCoffLoaderX64Lib.h b/EdkModulePkg/Include/Library/EdkPeCoffLoaderX64Lib.h new file mode 100644 index 0000000000..47756d3cf5 --- /dev/null +++ b/EdkModulePkg/Include/Library/EdkPeCoffLoaderX64Lib.h @@ -0,0 +1,33 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + EdkPeCoffLoaderX64Lib.h + +Abstract: + Wrap the Base PE/COFF loader with the PE COFF Protocol + + + +--*/ + +#ifndef __EDK_PE_COFF_LOADER_X64_LIB__ +#define __EDK_PE_COFF_LOADER_X64_LIB__ + +EFI_PEI_PE_COFF_LOADER_PROTOCOL * +EFIAPI +GetPeCoffLoaderX64Protocol ( + VOID + ); + +#endif + diff --git a/EdkModulePkg/Include/Library/EdkRtMemoryStatusCodeLib.h b/EdkModulePkg/Include/Library/EdkRtMemoryStatusCodeLib.h new file mode 100644 index 0000000000..02ae5a874e --- /dev/null +++ b/EdkModulePkg/Include/Library/EdkRtMemoryStatusCodeLib.h @@ -0,0 +1,66 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + RtMemoryStatusCodeLib.h + +Abstract: + + Lib to provide memory status code reporting. + +--*/ + +#ifndef _EFI_RT_MEMORY_STATUS_CODE_LIB_H_ +#define _EFI_RT_MEMORY_STATUS_CODE_LIB_H_ + +// +// Initialization function +// +VOID +RtMemoryStatusCodeInitialize ( + VOID + ) +; + +// +// Status code reporting function +// +EFI_STATUS +RtMemoryReportStatusCode ( + 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 + ) +; + +// +// Playback all prior status codes to a listener +// +typedef +EFI_STATUS +(*PLATFORM_REPORT_STATUS_CODE) ( + 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 + ); + +VOID +PlaybackStatusCodes ( + IN PLATFORM_REPORT_STATUS_CODE ReportStatusCode + ) +; + +#endif diff --git a/EdkModulePkg/Include/Library/EdkRtPlatformStatusCodeLib.h b/EdkModulePkg/Include/Library/EdkRtPlatformStatusCodeLib.h new file mode 100644 index 0000000000..c0a690756e --- /dev/null +++ b/EdkModulePkg/Include/Library/EdkRtPlatformStatusCodeLib.h @@ -0,0 +1,49 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + RtPlatformStatusCodeLib.h + +Abstract: + + Lib to provide platform implementations necessary for the Monolithic status + code to work. + +--*/ + +#ifndef _EFI_PLATFORM_STATUS_CODE_LIB_H_ +#define _EFI_PLATFORM_STATUS_CODE_LIB_H_ + + +// +// Initialization function +// +VOID +RtPlatformStatusCodeInitialize ( + VOID + ) +; + +// +// Status code reporting function +// +EFI_STATUS +RtPlatformReportStatusCode ( + 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/EdkModulePkg/Include/Library/EdkScsiLib.h b/EdkModulePkg/Include/Library/EdkScsiLib.h new file mode 100644 index 0000000000..bb1a1adbb3 --- /dev/null +++ b/EdkModulePkg/Include/Library/EdkScsiLib.h @@ -0,0 +1,299 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ScsiLib.h + + Abstract: + + Common Libarary for SCSI + + Revision History + +--*/ + +#ifndef _SCSI_LIB_H +#define _SCSI_LIB_H + +// +// the time unit is 100ns, since the SCSI I/O defines timeout in 100ns unit. +// +#define EFI_SCSI_STALL_1_MICROSECOND 10 +#define EFI_SCSI_STALL_1_MILLISECOND 10000 +#define EFI_SCSI_STALL_1_SECOND 10000000 + +// +// this macro cannot be directly used by the gBS->Stall(), +// since the value output by this macro is in 100ns unit, +// not 1us unit (1us = 1000ns) +// +#define EfiScsiStallSeconds(a) (a) * EFI_SCSI_STALL_1_SECOND + +EFI_STATUS +SubmitTestUnitReadyCommand ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + OUT VOID *SenseData, + OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiIo - TODO: add argument description + Timeout - TODO: add argument description + SenseData - TODO: add argument description + SenseDataLength - TODO: add argument description + HostAdapterStatus - TODO: add argument description + TargetStatus - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +SubmitInquiryCommand ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN VOID *SenseData, + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus, + IN OUT VOID *InquiryDataBuffer, + IN OUT UINT32 *InquiryDataLength, + IN BOOLEAN EnableVitalProductData + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiIo - TODO: add argument description + Timeout - TODO: add argument description + SenseData - TODO: add argument description + SenseDataLength - TODO: add argument description + HostAdapterStatus - TODO: add argument description + TargetStatus - TODO: add argument description + InquiryDataBuffer - TODO: add argument description + InquiryDataLength - TODO: add argument description + EnableVitalProductData - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +SubmitModeSense10Command ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN VOID *SenseData, + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus, + IN VOID *DataBuffer, + IN OUT UINT32 *DataLength, + IN UINT8 DBDField, OPTIONAL + IN UINT8 PageControl, + IN UINT8 PageCode + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiIo - TODO: add argument description + Timeout - TODO: add argument description + SenseData - TODO: add argument description + SenseDataLength - TODO: add argument description + HostAdapterStatus - TODO: add argument description + TargetStatus - TODO: add argument description + DataBuffer - TODO: add argument description + DataLength - TODO: add argument description + DBDField - TODO: add argument description + PageControl - TODO: add argument description + PageCode - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +SubmitRequestSenseCommand ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN VOID *SenseData, + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiIo - TODO: add argument description + Timeout - TODO: add argument description + SenseData - TODO: add argument description + SenseDataLength - TODO: add argument description + HostAdapterStatus - TODO: add argument description + TargetStatus - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +// +// Commands for direct access command +// +EFI_STATUS +SubmitReadCapacityCommand ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN VOID *SenseData, + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus, + OUT VOID *DataBuffer, + IN OUT UINT32 *DataLength, + IN BOOLEAN PMI + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiIo - TODO: add argument description + Timeout - TODO: add argument description + SenseData - TODO: add argument description + SenseDataLength - TODO: add argument description + HostAdapterStatus - TODO: add argument description + TargetStatus - TODO: add argument description + DataBuffer - TODO: add argument description + DataLength - TODO: add argument description + PMI - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +SubmitRead10Command ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN VOID *SenseData, + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus, + OUT VOID *DataBuffer, + IN OUT UINT32 *DataLength, + IN UINT32 StartLba, + IN UINT32 SectorSize + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiIo - TODO: add argument description + Timeout - TODO: add argument description + SenseData - TODO: add argument description + SenseDataLength - TODO: add argument description + HostAdapterStatus - TODO: add argument description + TargetStatus - TODO: add argument description + DataBuffer - TODO: add argument description + DataLength - TODO: add argument description + StartLba - TODO: add argument description + SectorSize - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +SubmitWrite10Command ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN VOID *SenseData, + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus, + OUT VOID *DataBuffer, + IN OUT UINT32 *DataLength, + IN UINT32 StartLba, + IN UINT32 SectorSize + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ScsiIo - TODO: add argument description + Timeout - TODO: add argument description + SenseData - TODO: add argument description + SenseDataLength - TODO: add argument description + HostAdapterStatus - TODO: add argument description + TargetStatus - TODO: add argument description + DataBuffer - TODO: add argument description + DataLength - TODO: add argument description + StartLba - TODO: add argument description + SectorSize - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/EdkModulePkg/Include/Library/EdkUsbLib.h b/EdkModulePkg/Include/Library/EdkUsbLib.h new file mode 100644 index 0000000000..005e045aac --- /dev/null +++ b/EdkModulePkg/Include/Library/EdkUsbLib.h @@ -0,0 +1,373 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + Module Name: + + UsbDxeLib.h + + Abstract: + + Common Dxe Libarary for USB + Add Constants & structure definitions for Usb HID + + Revision History + +--*/ + +#ifndef _USB_DXE_LIB_H +#define _USB_DXE_LIB_H + +// +// define the timeout time as 3ms +// +#define TIMEOUT_VALUE 3 * 1000 + +// +// HID constants definition, see HID rev1.0 +// +// +// HID report item format +// +#define HID_ITEM_FORMAT_SHORT 0 +#define HID_ITEM_FORMAT_LONG 1 + +// +// Special tag indicating long items +// +#define HID_ITEM_TAG_LONG 15 + +// +// HID report descriptor item type (prefix bit 2,3) +// +#define HID_ITEM_TYPE_MAIN 0 +#define HID_ITEM_TYPE_GLOBAL 1 +#define HID_ITEM_TYPE_LOCAL 2 +#define HID_ITEM_TYPE_RESERVED 3 + +// +// HID report descriptor main item tags +// +#define HID_MAIN_ITEM_TAG_INPUT 8 +#define HID_MAIN_ITEM_TAG_OUTPUT 9 +#define HID_MAIN_ITEM_TAG_FEATURE 11 +#define HID_MAIN_ITEM_TAG_BEGIN_COLLECTION 10 +#define HID_MAIN_ITEM_TAG_END_COLLECTION 12 + +// +// HID report descriptor main item contents +// +#define HID_MAIN_ITEM_CONSTANT 0x001 +#define HID_MAIN_ITEM_VARIABLE 0x002 +#define HID_MAIN_ITEM_RELATIVE 0x004 +#define HID_MAIN_ITEM_WRAP 0x008 +#define HID_MAIN_ITEM_NONLINEAR 0x010 +#define HID_MAIN_ITEM_NO_PREFERRED 0x020 +#define HID_MAIN_ITEM_NULL_STATE 0x040 +#define HID_MAIN_ITEM_VOLATILE 0x080 +#define HID_MAIN_ITEM_BUFFERED_BYTE 0x100 + +// +// HID report descriptor collection item types +// +#define HID_COLLECTION_PHYSICAL 0 +#define HID_COLLECTION_APPLICATION 1 +#define HID_COLLECTION_LOGICAL 2 + +// +// HID report descriptor global item tags +// +#define HID_GLOBAL_ITEM_TAG_USAGE_PAGE 0 +#define HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM 1 +#define HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM 2 +#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM 3 +#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM 4 +#define HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT 5 +#define HID_GLOBAL_ITEM_TAG_UNIT 6 +#define HID_GLOBAL_ITEM_TAG_REPORT_SIZE 7 +#define HID_GLOBAL_ITEM_TAG_REPORT_ID 8 +#define HID_GLOBAL_ITEM_TAG_REPORT_COUNT 9 +#define HID_GLOBAL_ITEM_TAG_PUSH 10 +#define HID_GLOBAL_ITEM_TAG_POP 11 + +// +// HID report descriptor local item tags +// +#define HID_LOCAL_ITEM_TAG_USAGE 0 +#define HID_LOCAL_ITEM_TAG_USAGE_MINIMUM 1 +#define HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM 2 +#define HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX 3 +#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM 4 +#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM 5 +#define HID_LOCAL_ITEM_TAG_STRING_INDEX 7 +#define HID_LOCAL_ITEM_TAG_STRING_MINIMUM 8 +#define HID_LOCAL_ITEM_TAG_STRING_MAXIMUM 9 +#define HID_LOCAL_ITEM_TAG_DELIMITER 10 + +// +// HID usage tables +// +#define HID_USAGE_PAGE 0xffff0000 + +#define HID_UP_GENDESK 0x00010000 +#define HID_UP_KEYBOARD 0x00070000 +#define HID_UP_LED 0x00080000 +#define HID_UP_BUTTON 0x00090000 +#define HID_UP_CONSUMER 0x000c0000 +#define HID_UP_DIGITIZER 0x000d0000 +#define HID_UP_PID 0x000f0000 + +#define HID_USAGE 0x0000ffff + +#define HID_GD_POINTER 0x00010001 +#define HID_GD_MOUSE 0x00010002 +#define HID_GD_JOYSTICK 0x00010004 +#define HID_GD_GAMEPAD 0x00010005 +#define HID_GD_HATSWITCH 0x00010039 + +// +// HID report types +// +#define HID_INPUT_REPORT 1 +#define HID_OUTPUT_REPORT 2 +#define HID_FEATURE_REPORT 3 + +// +// HID device quirks. +// +#define HID_QUIRK_INVERT 0x01 +#define HID_QUIRK_NOTOUCH 0x02 + +// +// HID class protocol request +// +#define EFI_USB_GET_REPORT_REQUEST 0x01 +#define EFI_USB_GET_IDLE_REQUEST 0x02 +#define EFI_USB_GET_PROTOCOL_REQUEST 0x03 +#define EFI_USB_SET_REPORT_REQUEST 0x09 +#define EFI_USB_SET_IDLE_REQUEST 0x0a +#define EFI_USB_SET_PROTOCOL_REQUEST 0x0b + +#pragma pack(1) +// +// Descriptor header for Report/Physical Descriptors +// +typedef struct hid_class_descriptor { + UINT8 DescriptorType; + UINT16 DescriptorLength; +} EFI_USB_HID_CLASS_DESCRIPTOR; + +typedef struct hid_descriptor { + UINT8 Length; + UINT8 DescriptorType; + UINT16 BcdHID; + UINT8 CountryCode; + UINT8 NumDescriptors; + EFI_USB_HID_CLASS_DESCRIPTOR HidClassDesc[1]; +} EFI_USB_HID_DESCRIPTOR; + +#pragma pack() + +EFI_STATUS +UsbGetHidDescriptor ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 InterfaceNum, + OUT EFI_USB_HID_DESCRIPTOR *HidDescriptor + ); + +EFI_STATUS +UsbGetReportDescriptor ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 InterfaceNum, + IN UINT16 DescriptorSize, + OUT UINT8 *DescriptorBuffer + ); + +EFI_STATUS +UsbGetProtocolRequest ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 Interface, + IN UINT8 *Protocol + ); + +EFI_STATUS +UsbSetProtocolRequest ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 Interface, + IN UINT8 Protocol + ); + +EFI_STATUS +UsbSetIdleRequest ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 Interface, + IN UINT8 ReportId, + IN UINT8 Duration + ); + +EFI_STATUS +UsbGetIdleRequest ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 Interface, + IN UINT8 ReportId, + OUT UINT8 *Duration + ); + +EFI_STATUS +UsbSetReportRequest ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 Interface, + IN UINT8 ReportId, + IN UINT8 ReportType, + IN UINT16 ReportLen, + IN UINT8 *Report + ); + +EFI_STATUS +UsbGetReportRequest ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 Interface, + IN UINT8 ReportId, + IN UINT8 ReportType, + IN UINT16 ReportLen, + IN UINT8 *Report + ); + +// +// Get Device Descriptor +// +EFI_STATUS +UsbGetDescriptor ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT16 Value, + IN UINT16 Index, + IN UINT16 DescriptorLength, + OUT VOID *Descriptor, + OUT UINT32 *Status + ); + +// +// Set Device Descriptor +// +EFI_STATUS +UsbSetDescriptor ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT16 Value, + IN UINT16 Index, + IN UINT16 DescriptorLength, + IN VOID *Descriptor, + OUT UINT32 *Status + ); + +// +// Get device Interface +// +EFI_STATUS +UsbGetDeviceInterface ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT16 Index, + OUT UINT8 *AltSetting, + OUT UINT32 *Status + ); + +// +// Set device interface +// +EFI_STATUS +UsbSetDeviceInterface ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT16 InterfaceNo, + IN UINT16 AltSetting, + OUT UINT32 *Status + ); + +// +// Get device configuration +// +EFI_STATUS +UsbGetDeviceConfiguration ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + OUT UINT8 *ConfigValue, + OUT UINT32 *Status + ); + +// +// Set device configuration +// +EFI_STATUS +UsbSetDeviceConfiguration ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT16 Value, + OUT UINT32 *Status + ); + +// +// Set Device Feature +// +EFI_STATUS +UsbSetDeviceFeature ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN EFI_USB_RECIPIENT Recipient, + IN UINT16 Value, + IN UINT16 Target, + OUT UINT32 *Status + ); + +// +// Clear Device Feature +// +EFI_STATUS +UsbClearDeviceFeature ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN EFI_USB_RECIPIENT Recipient, + IN UINT16 Value, + IN UINT16 Target, + OUT UINT32 *Status + ); + +// +// Get Device Status +// +EFI_STATUS +UsbGetDeviceStatus ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN EFI_USB_RECIPIENT Recipient, + IN UINT16 Target, + OUT UINT16 *DevStatus, + OUT UINT32 *Status + ); + +// +// The following APIs are not basic library, but they are common used. +// +// +// Usb Get String +// +EFI_STATUS +UsbGetString ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT16 LangID, + IN UINT8 Index, + IN VOID *Buf, + IN UINTN BufSize, + OUT UINT32 *Status + ); + +// +// Clear endpoint stall +// +EFI_STATUS +UsbClearEndpointHalt ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 EndpointNo, + OUT UINT32 *Status + ); + +#endif diff --git a/EdkModulePkg/Include/Library/TianoDecompressLib.h b/EdkModulePkg/Include/Library/TianoDecompressLib.h new file mode 100644 index 0000000000..58e9426a31 --- /dev/null +++ b/EdkModulePkg/Include/Library/TianoDecompressLib.h @@ -0,0 +1,42 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + TianoDecompressLib.h + +Abstract: + + Tiano Decompress functions + +--*/ + +#ifndef __TIANO_DECPOMPRESS_LIB_H__ +#define __TIANO_DECPOMPRESS_LIB_H__ + +RETURN_STATUS +EFIAPI +TianoDecompressGetInfo ( + IN CONST VOID *Source, + IN UINT32 SourceSize, + OUT UINT32 *DestinationSize, + OUT UINT32 *ScratchSize + ); + +RETURN_STATUS +EFIAPI +TianoDecompress ( + IN CONST VOID *Source, + IN OUT VOID *Destination, + IN OUT VOID *Scratch + ); + +#endif diff --git a/EdkModulePkg/Include/Ppi/BaseMemoryTest.h b/EdkModulePkg/Include/Ppi/BaseMemoryTest.h new file mode 100644 index 0000000000..8b0be6e130 --- /dev/null +++ b/EdkModulePkg/Include/Ppi/BaseMemoryTest.h @@ -0,0 +1,56 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + BaseMemoryTest.h + +Abstract: + + Pei memory test PPI as defined in Tiano + + Used to Pei memory test in PEI + +--*/ + +#ifndef _BASE_MEMORY_TEST_H_ +#define _BASE_MEMORY_TEST_H_ + +#define PEI_BASE_MEMORY_TEST_GUID \ + { 0xb6ec423c, 0x21d2, 0x490d, {0x85, 0xc6, 0xdd, 0x58, 0x64, 0xea, 0xa6, 0x74 } } + +typedef struct _PEI_BASE_MEMORY_TEST_PPI PEI_BASE_MEMORY_TEST_PPI; + +typedef enum { + Ignore, + Quick, + Sparse, + Extensive +} PEI_MEMORY_TEST_OP; + +typedef +EFI_STATUS +(EFIAPI *PEI_BASE_MEMORY_TEST) ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_BASE_MEMORY_TEST_PPI * This, + IN EFI_PHYSICAL_ADDRESS BeginAddress, + IN UINT64 MemoryLength, + IN PEI_MEMORY_TEST_OP Operation, + OUT EFI_PHYSICAL_ADDRESS * ErrorAddress + ); + +struct _PEI_BASE_MEMORY_TEST_PPI { + PEI_BASE_MEMORY_TEST BaseMemoryTest; +}; + +extern EFI_GUID gPeiBaseMemoryTestPpiGuid; + +#endif diff --git a/EdkModulePkg/Include/Ppi/FlashMap.h b/EdkModulePkg/Include/Ppi/FlashMap.h new file mode 100644 index 0000000000..312f38b416 --- /dev/null +++ b/EdkModulePkg/Include/Ppi/FlashMap.h @@ -0,0 +1,52 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FlashMap.h + +Abstract: + + FlashMap PPI defined in Tiano + + This code abstracts FlashMap access + +--*/ + +#ifndef _PEI_FLASH_MAP_PPI_H_ +#define _PEI_FLASH_MAP_PPI_H_ + +#define PEI_FLASH_MAP_PPI_GUID \ + { 0xf34c2fa0, 0xde88, 0x4270, {0x84, 0x14, 0x96, 0x12, 0x22, 0xf4, 0x52, 0x1c } } + +typedef struct _PEI_FLASH_MAP_PPI PEI_FLASH_MAP_PPI; +// +// Functions +// +typedef +EFI_STATUS +(EFIAPI *PEI_GET_FLASH_AREA_INFO) ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_FLASH_MAP_PPI *This, + IN EFI_FLASH_AREA_TYPE AreaType, + IN EFI_GUID *AreaTypeGuid, + OUT UINT32 *NumEntries, + OUT EFI_FLASH_SUBAREA_ENTRY **Entries + ); + + +struct _PEI_FLASH_MAP_PPI { + PEI_GET_FLASH_AREA_INFO GetAreaInfo; +}; + +extern EFI_GUID gPeiFlashMapPpiGuid; + +#endif diff --git a/EdkModulePkg/Include/Ppi/PeiInMemory.h b/EdkModulePkg/Include/Ppi/PeiInMemory.h new file mode 100644 index 0000000000..74d0905766 --- /dev/null +++ b/EdkModulePkg/Include/Ppi/PeiInMemory.h @@ -0,0 +1,29 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PeiInMemory.h + +Abstract: + + +--*/ + +#ifndef __PEI_IN_MEMORY_H__ +#define __PEI_IN_MEMORY_H__ + +#define PEI_IN_MEMORY_GUID \ + {0x643b8786, 0xb417, 0x48d2, {0x8f, 0x5e, 0x78, 0x19, 0x93, 0x1c, 0xae, 0xd8} } + +extern EFI_GUID gPeiInMemoryGuid; + +#endif diff --git a/EdkModulePkg/Include/Ppi/StatusCodeMemory.h b/EdkModulePkg/Include/Ppi/StatusCodeMemory.h new file mode 100644 index 0000000000..85b2b6de5f --- /dev/null +++ b/EdkModulePkg/Include/Ppi/StatusCodeMemory.h @@ -0,0 +1,53 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + StatusCodeMemory.h + +Abstract: + + Status Code memory descriptor PPI. Contains information about memory that + the Status Code PEIM may use to journal Status Codes. + +--*/ + +#ifndef _PEI_STATUS_CODE_MEMORY_PPI_H_ +#define _PEI_STATUS_CODE_MEMORY_PPI_H_ + +// +// GUID definition +// +#define PEI_STATUS_CODE_MEMORY_PPI_GUID \ + { 0x26f8ab01, 0xd3cd, 0x489c, {0x98, 0x4f, 0xdf, 0xde, 0xf7, 0x68, 0x39, 0x5b } } + +// +// Data types +// +typedef struct { + EFI_STATUS_CODE_TYPE Type; + EFI_STATUS_CODE_VALUE Value; + UINT32 Instance; +} EFI_STATUS_CODE_ENTRY; + +// +// PPI definition +// +typedef struct { + UINTN FirstEntry; + UINTN LastEntry; + EFI_PHYSICAL_ADDRESS Address; + UINTN Length; +} PEI_STATUS_CODE_MEMORY_PPI; + +extern EFI_GUID gPeiStatusCodeMemoryPpiGuid; + +#endif diff --git a/EdkModulePkg/Include/Protocol/AcpiS3Save.h b/EdkModulePkg/Include/Protocol/AcpiS3Save.h new file mode 100644 index 0000000000..1571e3dcd2 --- /dev/null +++ b/EdkModulePkg/Include/Protocol/AcpiS3Save.h @@ -0,0 +1,61 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + AcpiS3Save.h + +Abstract: + + +--*/ + +#ifndef _ACPI_S3_SAVE_PROTOCOL_H +#define _ACPI_S3_SAVE_PROTOCOL_H + +// +// Forward reference for pure ANSI compatability +// +typedef struct _EFI_ACPI_S3_SAVE_PROTOCOL EFI_ACPI_S3_SAVE_PROTOCOL; + +// +// S3 Save Protocol GUID +// +#define EFI_ACPI_S3_SAVE_GUID \ + { \ + 0x125f2de1, 0xfb85, 0x440c, {0xa5, 0x4c, 0x4d, 0x99, 0x35, 0x8a, 0x8d, 0x38 } \ + } + +// +// Protocol Data Structures +// +typedef +EFI_STATUS +(EFIAPI *EFI_ACPI_S3_SAVE) ( + IN EFI_ACPI_S3_SAVE_PROTOCOL * This, + IN VOID * LegacyMemoryAddress + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_ACPI_GET_LEGACY_MEMORY_SIZE) ( + IN EFI_ACPI_S3_SAVE_PROTOCOL * This, + OUT UINTN * Size +); + +struct _EFI_ACPI_S3_SAVE_PROTOCOL { + EFI_ACPI_GET_LEGACY_MEMORY_SIZE GetLegacyMemorySize; + EFI_ACPI_S3_SAVE S3Save; +}; + +extern EFI_GUID gEfiAcpiS3SaveProtocolGuid; + +#endif diff --git a/EdkModulePkg/Include/Protocol/ConsoleControl.h b/EdkModulePkg/Include/Protocol/ConsoleControl.h new file mode 100644 index 0000000000..c894302c66 --- /dev/null +++ b/EdkModulePkg/Include/Protocol/ConsoleControl.h @@ -0,0 +1,121 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ConsoleControl.h + +Abstract: + + Abstraction of a Text mode or UGA screen + +--*/ + +#ifndef __CONSOLE_CONTROL_H__ +#define __CONSOLE_CONTROL_H__ + +#define EFI_CONSOLE_CONTROL_PROTOCOL_GUID \ + { 0xf42f7782, 0x12e, 0x4c12, {0x99, 0x56, 0x49, 0xf9, 0x43, 0x4, 0xf7, 0x21 } } + +typedef struct _EFI_CONSOLE_CONTROL_PROTOCOL EFI_CONSOLE_CONTROL_PROTOCOL; + + +typedef enum { + EfiConsoleControlScreenText, + EfiConsoleControlScreenGraphics, + EfiConsoleControlScreenMaxValue +} EFI_CONSOLE_CONTROL_SCREEN_MODE; + + +typedef +EFI_STATUS +(EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_GET_MODE) ( + IN EFI_CONSOLE_CONTROL_PROTOCOL *This, + OUT EFI_CONSOLE_CONTROL_SCREEN_MODE *Mode, + OUT BOOLEAN *UgaExists, OPTIONAL + OUT BOOLEAN *StdInLocked OPTIONAL + ) +/*++ + + Routine Description: + Return the current video mode information. Also returns info about existence + of UGA Draw devices in system, and if the Std In device is locked. All the + arguments are optional and only returned if a non NULL pointer is passed in. + + Arguments: + This - Protocol instance pointer. + Mode - Are we in text of grahics mode. + UgaExists - TRUE if UGA Spliter has found a UGA device + StdInLocked - TRUE if StdIn device is keyboard locked + + Returns: + EFI_SUCCESS - Mode information returned. + +--*/ +; + + +typedef +EFI_STATUS +(EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE) ( + IN EFI_CONSOLE_CONTROL_PROTOCOL *This, + OUT EFI_CONSOLE_CONTROL_SCREEN_MODE Mode + ) +/*++ + + Routine Description: + Set the current mode to either text or graphics. Graphics is + for Quiet Boot. + + Arguments: + This - Protocol instance pointer. + Mode - Mode to set the + + Returns: + EFI_SUCCESS - Mode information returned. + +--*/ +; + + +typedef +EFI_STATUS +(EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN) ( + IN EFI_CONSOLE_CONTROL_PROTOCOL *This, + IN CHAR16 *Password + ) +/*++ + + Routine Description: + Lock Std In devices until Password is typed. + + Arguments: + This - Protocol instance pointer. + Password - Password needed to unlock screen. NULL means unlock keyboard + + Returns: + EFI_SUCCESS - Mode information returned. + EFI_DEVICE_ERROR - Std In not locked + +--*/ +; + + + +struct _EFI_CONSOLE_CONTROL_PROTOCOL { + EFI_CONSOLE_CONTROL_PROTOCOL_GET_MODE GetMode; + EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE SetMode; + EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN LockStdIn; +}; + +extern EFI_GUID gEfiConsoleControlProtocolGuid; + +#endif diff --git a/EdkModulePkg/Include/Protocol/CustomizedDecompress.h b/EdkModulePkg/Include/Protocol/CustomizedDecompress.h new file mode 100644 index 0000000000..bff8d46e88 --- /dev/null +++ b/EdkModulePkg/Include/Protocol/CustomizedDecompress.h @@ -0,0 +1,137 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + CustomizedDecompress.h + +Abstract: + The user Customized Decompress Protocol Interface + +--*/ + +#ifndef __CUSTOMIZED_DECOMPRESS_H__ +#define __CUSTOMIZED_DECOMPRESS_H__ + +#define EFI_CUSTOMIZED_DECOMPRESS_PROTOCOL_GUID \ + { 0x9a44198e, 0xa4a2, 0x44e6, {0x8a, 0x1f, 0x39, 0xbe, 0xfd, 0xac, 0x89, 0x6f } } + +typedef struct _EFI_CUSTOMIZED_DECOMPRESS_PROTOCOL EFI_CUSTOMIZED_DECOMPRESS_PROTOCOL; + +typedef +EFI_STATUS +(EFIAPI *EFI_CUSTOMIZED_DECOMPRESS_GET_INFO) ( + IN EFI_CUSTOMIZED_DECOMPRESS_PROTOCOL *This, + IN VOID *Source, + IN UINT32 SourceSize, + OUT UINT32 *DestinationSize, + OUT UINT32 *ScratchSize + ); +/*++ + +Routine Description: + + 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. + +Arguments: + + This - The protocol instance pointer + Source - The source buffer containing the compressed data. + SourceSize - The size, in bytes, of source buffer. + 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. + 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. + +Returns: + EFI_SUCCESS - The size of the uncompressed data was returned in DestinationSize + and the size of the scratch buffer was returned in ScratchSize. + 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 SourceData. + +--*/ + + +typedef +EFI_STATUS +(EFIAPI *EFI_CUSTOMIZED_DECOMPRESS_DECOMPRESS) ( + IN EFI_CUSTOMIZED_DECOMPRESS_PROTOCOL *This, + IN VOID* Source, + IN UINT32 SourceSize, + IN OUT VOID* Destination, + IN UINT32 DestinationSize, + IN OUT VOID* Scratch, + IN UINT32 ScratchSize + ); +/*++ + +Routine Description: + + 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. + +Arguments: + + This - The protocol instance pointer + Source - The source buffer containing the compressed data. + SourceSize - The size of source data. + Destination - On output, the destination buffer that contains + the uncompressed data. + DestinationSize - The size of destination buffer. The size of destination + buffer needed is obtained from GetInfo(). + Scratch - A temporary scratch buffer that is used to perform the + decompression. + ScratchSize - The size of scratch buffer. The size of scratch buffer needed + is obtained from GetInfo(). + +Returns: + + EFI_SUCCESS - Decompression completed successfully, and the uncompressed + buffer is returned in Destination. + EFI_INVALID_PARAMETER + - The source buffer specified by Source and SourceSize is + corrupted (not in a valid compressed format). + +--*/ + +struct _EFI_CUSTOMIZED_DECOMPRESS_PROTOCOL { + EFI_CUSTOMIZED_DECOMPRESS_GET_INFO GetInfo; + EFI_CUSTOMIZED_DECOMPRESS_DECOMPRESS Decompress; +}; + +extern EFI_GUID gEfiCustomizedDecompressProtocolGuid; + +#endif diff --git a/EdkModulePkg/Include/Protocol/DebugAssert.h b/EdkModulePkg/Include/Protocol/DebugAssert.h new file mode 100644 index 0000000000..9d26d83277 --- /dev/null +++ b/EdkModulePkg/Include/Protocol/DebugAssert.h @@ -0,0 +1,89 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DebugAssert.h + +Abstract: + + This protocol allows provides debug services to a driver. This is not + debugger support, but things like ASSERT() and DEBUG() macros + +--*/ + +#ifndef _DEBUG_ASSERT_H_ +#define _DEBUG_ASSERT_H_ + + +#define EFI_DEBUG_ASSERT_PROTOCOL_GUID \ + { 0xbe499c92, 0x7d4b, 0x11d4, {0xbc, 0xee, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } } + +// +// Forward reference for pure ANSI compatability +// +typedef struct _EFI_DEBUG_ASSERT_PROTOCOL EFI_DEBUG_ASSERT_PROTOCOL; + + +typedef +EFI_STATUS +(EFIAPI *EFI_DEBUG_ASSERT) ( + IN EFI_DEBUG_ASSERT_PROTOCOL *This, + IN CHAR8 *FileName, + IN INTN LineNumber, + IN CHAR8 *Description + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_DEBUG_PRINT) ( + IN EFI_DEBUG_ASSERT_PROTOCOL *This, + IN UINTN ErrorLevel, + IN CHAR8 *Format, + IN VA_LIST Marker + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_POST_CODE) ( + IN EFI_DEBUG_ASSERT_PROTOCOL *This, + IN UINT16 PostCode, + IN CHAR8 *PostCodeString OPTIONAL + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_GET_ERROR_LEVEL) ( + IN EFI_DEBUG_ASSERT_PROTOCOL *This, + IN UINTN *ErrorLevel + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_SET_ERROR_LEVEL) ( + IN EFI_DEBUG_ASSERT_PROTOCOL *This, + IN UINTN ErrorLevel + ); + +struct _EFI_DEBUG_ASSERT_PROTOCOL { + + EFI_DEBUG_ASSERT Assert; + EFI_DEBUG_PRINT Print; + EFI_POST_CODE PostCode; + + EFI_GET_ERROR_LEVEL GetErrorLevel; + EFI_SET_ERROR_LEVEL SetErrorLevel; + +}; + +extern EFI_GUID gEfiDebugAssertProtocolGuid; + +#endif diff --git a/EdkModulePkg/Include/Protocol/DebugLevel.h b/EdkModulePkg/Include/Protocol/DebugLevel.h new file mode 100644 index 0000000000..9c5f06a21f --- /dev/null +++ b/EdkModulePkg/Include/Protocol/DebugLevel.h @@ -0,0 +1,40 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DebugLevel.h + +Abstract: + This protocol is used to abstract the Debug Mask serivces for + the specific driver or application image. + +--*/ + +#ifndef __DEBUG_LEVEL_H__ +#define __DEBUG_LEVEL_H__ + +// +// 8D4C62E6-CD98-4e1d-AD6E-48BB50D29FF7 +// +#define EFI_DEBUG_LEVEL_PROTOCOL_GUID \ + { 0x8d4c62e6, 0xcd98, 0x4e1d, {0xad, 0x6e, 0x48, 0xbb, 0x50, 0xd2, 0x9f, 0xf7 } } + +// +// DebugLevel protocol definition +// +typedef struct _EFI_DEBUG_LEVEL_PROTOCOL { + UINTN DebugLevel; +} EFI_DEBUG_LEVEL_PROTOCOL; + +extern EFI_GUID gEfiDebugLevelProtocolGuid; + +#endif diff --git a/EdkModulePkg/Include/Protocol/DiskInfo.h b/EdkModulePkg/Include/Protocol/DiskInfo.h new file mode 100644 index 0000000000..6952163c22 --- /dev/null +++ b/EdkModulePkg/Include/Protocol/DiskInfo.h @@ -0,0 +1,179 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DiskInfo.h + +Abstract: + + Disk Info protocol is used to export Inquiry Data for a drive. + Its needed to support low level formating of drives in a mannor + thats DOS compatible. + +--*/ + +#ifndef __DISK_INFO_H__ +#define __DISK_INFO_H__ + +#define EFI_DISK_INFO_PROTOCOL_GUID \ + { \ + 0xd432a67f, 0x14dc, 0x484b, {0xb3, 0xbb, 0x3f, 0x2, 0x91, 0x84, 0x93, 0x27 } \ + } + +// +// Forward reference for pure ANSI compatability +// +typedef struct _EFI_DISK_INFO_PROTOCOL EFI_DISK_INFO_PROTOCOL; + +typedef +EFI_STATUS +(EFIAPI *EFI_DISK_INFO_INQUIRY) ( + IN EFI_DISK_INFO_PROTOCOL * This, + IN OUT VOID *InquiryData, + IN OUT UINT32 *IntquiryDataSize + ) +/*++ + + Routine Description: + Return the results of the Inquiry command to a drive in InquiryData. + Data format of Inquiry data is defined by the Interface GUID. + + Arguments: + This - Protocol instance pointer. + InquiryData - Results of Inquiry command to device + InquiryDataSize - Size of InquiryData in bytes. + + Returns: + EFI_SUCCESS - InquiryData valid + EFI_NOT_FOUND - Device does not support this data class + EFI_DEVICE_ERROR - Error reading InquiryData from device + EFI_BUFFER_TOO_SMALL - IntquiryDataSize not big enough + +--*/ +; + +typedef +EFI_STATUS +(EFIAPI *EFI_DISK_INFO_IDENTIFY) ( + IN EFI_DISK_INFO_PROTOCOL * This, + IN OUT VOID *IdentifyData, + IN OUT UINT32 *IdentifyDataSize + ) +/*++ + + Routine Description: + Return the results of the Identify command to a drive in IdentifyData. + Data format of Identify data is defined by the Interface GUID. + + Arguments: + This - Protocol instance pointer. + IdentifyData - Results of Identify command to device + IdentifyDataSize - Size of IdentifyData in bytes. + + Returns: + EFI_SUCCESS - IdentifyData valid + EFI_NOT_FOUND - Device does not support this data class + EFI_DEVICE_ERROR - Error reading IdentifyData from device + EFI_BUFFER_TOO_SMALL - IdentifyDataSize not big enough + +--*/ +; + +typedef +EFI_STATUS +(EFIAPI *EFI_DISK_INFO_SENSE_DATA) ( + IN EFI_DISK_INFO_PROTOCOL * This, + IN OUT VOID *SenseData, + IN OUT UINT32 *SenseDataSize, + OUT UINT8 *SenseDataNumber + ) +/*++ + + Routine Description: + Return the results of the Request Sense command to a drive in SenseData. + Data format of Sense data is defined by the Interface GUID. + + Arguments: + This - Protocol instance pointer. + SenseData - Results of Request Sense command to device + SenseDataSize - Size of SenseData in bytes. + SenseDataNumber - Type of SenseData + + Returns: + EFI_SUCCESS - InquiryData valid + EFI_NOT_FOUND - Device does not support this data class + EFI_DEVICE_ERROR - Error reading InquiryData from device + EFI_BUFFER_TOO_SMALL - SenseDataSize not big enough + +--*/ +; + +typedef +EFI_STATUS +(EFIAPI *EFI_DISK_INFO_WHICH_IDE) ( + IN EFI_DISK_INFO_PROTOCOL * This, + OUT UINT32 *IdeChannel, + OUT UINT32 *IdeDevice + ) +/*++ + + Routine Description: + Return the results of the Request Sense command to a drive in SenseData. + Data format of Sense data is defined by the Interface GUID. + + Arguments: + This - Protocol instance pointer. + IdeChannel - Primary or Secondary + IdeDevice - Master or Slave + + Returns: + EFI_SUCCESS - IdeChannel and IdeDevice are valid + EFI_UNSUPPORTED - This is not an IDE device + +--*/ +; + +// +// GUIDs for EFI_DISK_INFO_PROTOCOL.Interface. Defines the format of the +// buffers returned by member functions +// +#define EFI_DISK_INFO_IDE_INTERFACE_GUID \ + { \ + 0x5e948fe3, 0x26d3, 0x42b5, {0xaf, 0x17, 0x61, 0x2, 0x87, 0x18, 0x8d, 0xec } \ + } +extern EFI_GUID gEfiDiskInfoIdeInterfaceGuid; + +#define EFI_DISK_INFO_SCSI_INTERFACE_GUID \ + { \ + 0x8f74baa, 0xea36, 0x41d9, {0x95, 0x21, 0x21, 0xa7, 0xf, 0x87, 0x80, 0xbc } \ + } +extern EFI_GUID gEfiDiskInfoScsiInterfaceGuid; + +#define EFI_DISK_INFO_USB_INTERFACE_GUID \ + { \ + 0xcb871572, 0xc11a, 0x47b5, {0xb4, 0x92, 0x67, 0x5e, 0xaf, 0xa7, 0x77, 0x27 } \ + } +extern EFI_GUID gEfiDiskInfoUsbInterfaceGuid; + +struct _EFI_DISK_INFO_PROTOCOL { + EFI_GUID Interface; + EFI_DISK_INFO_INQUIRY Inquiry; + EFI_DISK_INFO_IDENTIFY Identify; + EFI_DISK_INFO_SENSE_DATA SenseData; + EFI_DISK_INFO_WHICH_IDE WhichIde; +}; + +extern EFI_GUID gEfiDiskInfoProtocolGuid; + +#endif + + diff --git a/EdkModulePkg/Include/Protocol/EdkDecompress.h b/EdkModulePkg/Include/Protocol/EdkDecompress.h new file mode 100644 index 0000000000..ab9b840cf2 --- /dev/null +++ b/EdkModulePkg/Include/Protocol/EdkDecompress.h @@ -0,0 +1,137 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + EdkDecompress.h + +Abstract: + The Tiano Decompress Protocol Interface + +--*/ + +#ifndef __EDK_DECOMPRESS_H__ +#define __EDK_DECOMPRESS_H__ + +#define EFI_TIANO_DECOMPRESS_PROTOCOL_GUID \ + { 0xe84cf29c, 0x191f, 0x4eae, {0x96, 0xe1, 0xf4, 0x6a, 0xec, 0xea, 0xea, 0x0b } } + +typedef struct _EFI_TIANO_DECOMPRESS_PROTOCOL EFI_TIANO_DECOMPRESS_PROTOCOL; + +typedef +EFI_STATUS +(EFIAPI *EFI_TIANO_DECOMPRESS_GET_INFO) ( + IN EFI_TIANO_DECOMPRESS_PROTOCOL *This, + IN VOID *Source, + IN UINT32 SourceSize, + OUT UINT32 *DestinationSize, + OUT UINT32 *ScratchSize + ); +/*++ + +Routine Description: + + 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. + +Arguments: + + This - The protocol instance pointer + Source - The source buffer containing the compressed data. + SourceSize - The size, in bytes, of source buffer. + 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. + 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. + +Returns: + EFI_SUCCESS - The size of the uncompressed data was returned in DestinationSize + and the size of the scratch buffer was returned in ScratchSize. + 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 SourceData. + +--*/ + + +typedef +EFI_STATUS +(EFIAPI *EFI_TIANO_DECOMPRESS_DECOMPRESS) ( + IN EFI_TIANO_DECOMPRESS_PROTOCOL *This, + IN VOID* Source, + IN UINT32 SourceSize, + IN OUT VOID* Destination, + IN UINT32 DestinationSize, + IN OUT VOID* Scratch, + IN UINT32 ScratchSize + ); +/*++ + +Routine Description: + + 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. + +Arguments: + + This - The protocol instance pointer + Source - The source buffer containing the compressed data. + SourceSize - The size of source data. + Destination - On output, the destination buffer that contains + the uncompressed data. + DestinationSize - The size of destination buffer. The size of destination + buffer needed is obtained from GetInfo(). + Scratch - A temporary scratch buffer that is used to perform the + decompression. + ScratchSize - The size of scratch buffer. The size of scratch buffer needed + is obtained from GetInfo(). + +Returns: + + EFI_SUCCESS - Decompression completed successfully, and the uncompressed + buffer is returned in Destination. + EFI_INVALID_PARAMETER + - The source buffer specified by Source and SourceSize is + corrupted (not in a valid compressed format). + +--*/ + +struct _EFI_TIANO_DECOMPRESS_PROTOCOL { + EFI_TIANO_DECOMPRESS_GET_INFO GetInfo; + EFI_TIANO_DECOMPRESS_DECOMPRESS Decompress; +}; + +extern EFI_GUID gEfiTianoDecompressProtocolGuid; + +#endif diff --git a/EdkModulePkg/Include/Protocol/ExtendedSalBootService.h b/EdkModulePkg/Include/Protocol/ExtendedSalBootService.h new file mode 100644 index 0000000000..28aceb3758 --- /dev/null +++ b/EdkModulePkg/Include/Protocol/ExtendedSalBootService.h @@ -0,0 +1,113 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ExtendedSalBootService.h + +Abstract: + +--*/ + +#ifndef _EXTENDED_SAL_PROTOCOL_H_ +#define _EXTENDED_SAL_PROTOCOL_H_ + +#define EXTENDED_SAL_BOOT_SERVICE_PROTOCOL_GUID \ + {0xde0ee9a4,0x3c7a,0x44f2, {0xb7,0x8b,0xe3,0xcc,0xd6,0x9c,0x3a,0xf7}} + +#define EXTENDED_SAL_SIGNATURE EFI_SIGNATURE_32('e', 's', 'a', 'l') + +#define SAL_MIN_STATE_SIZE 0x400 * 1 +#define PAL_SCARTCH_SIZE 0x400 * 3 +#define ALIGN_MINSTATE_SIZE 512 +#define MAX_SAL_RECORD_SIZE 8*1024 + +#define SAL_RUNTIMESERVICE + +typedef UINT16 EFI_SAL_PROCESSOR_ID; + +typedef struct _EXTENDED_SAL_BOOT_SERVICE_PROTOCOL EXTENDED_SAL_BOOT_SERVICE_PROTOCOL; + +typedef +SAL_RUNTIMESERVICE +SAL_RETURN_REGS +(EFIAPI *SAL_EXTENDED_SAL_PROC) ( + IN EFI_GUID *ClassGuid, + IN UINT64 FunctionId, + IN UINT64 Arg2, + IN UINT64 Arg3, + IN UINT64 Arg4, + IN UINT64 Arg5, + IN UINT64 Arg6, + IN UINT64 Arg7, + IN UINT64 Arg8 + ); + +typedef +SAL_RUNTIMESERVICE +SAL_RETURN_REGS +(EFIAPI *SAL_INTERNAL_EXTENDED_SAL_PROC) ( + IN UINT64 FunctionId, + IN UINT64 Arg2, + IN UINT64 Arg3, + IN UINT64 Arg4, + IN UINT64 Arg5, + IN UINT64 Arg6, + IN UINT64 Arg7, + IN UINT64 Arg8, + IN SAL_EXTENDED_SAL_PROC ExtendedSalProc, + IN BOOLEAN VirtualMode, + IN VOID *ModuleGlobal + ); + +typedef +EFI_STATUS +(EFIAPI *EXTENDED_SAL_ADD_SST_INFO) ( + IN EXTENDED_SAL_BOOT_SERVICE_PROTOCOL *This, + IN UINT16 SalAVersion, + IN UINT16 SalBVersion, + IN CHAR8 *OemId, + IN CHAR8 *ProductId + ); + +typedef +EFI_STATUS +(EFIAPI *EXTENDED_SAL_ADD_SST_ENTRY) ( + IN EXTENDED_SAL_BOOT_SERVICE_PROTOCOL *This, + IN UINT8 EntryType, + IN UINT8 *TableEntry, + IN UINTN EntrySize + ); + +typedef +EFI_STATUS +(EFIAPI *EXTENDED_SAL_REGISTER_INTERNAL_PROC) ( + IN EXTENDED_SAL_BOOT_SERVICE_PROTOCOL *This, + IN EFI_GUID *ClassGuid, + IN UINT64 FunctionId, + IN SAL_INTERNAL_EXTENDED_SAL_PROC InternalSalProc, + IN VOID *PhysicalModuleGlobal + ); + +// +// Extended Sal Boot Service Protocol Interface +// +struct _EXTENDED_SAL_BOOT_SERVICE_PROTOCOL{ + EXTENDED_SAL_ADD_SST_INFO AddSalSystemTableInfo; + EXTENDED_SAL_ADD_SST_ENTRY AddSalSystemTableEntry; + EXTENDED_SAL_REGISTER_INTERNAL_PROC AddExtendedSalProc; + SAL_EXTENDED_SAL_PROC ExtendedSalProc; + SAL_PROC SalProc; +}; + +extern EFI_GUID gEfiExtendedSalBootServiceProtocolGuid; + +#endif diff --git a/EdkModulePkg/Include/Protocol/FaultTolerantWriteLite.h b/EdkModulePkg/Include/Protocol/FaultTolerantWriteLite.h new file mode 100644 index 0000000000..c3ec825461 --- /dev/null +++ b/EdkModulePkg/Include/Protocol/FaultTolerantWriteLite.h @@ -0,0 +1,88 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FaultTolerantWriteLite.h + +Abstract: + + This is a simple fault tolerant write driver, based on PlatformFd library. + And it only supports write BufferSize <= SpareAreaLength. + +--*/ + +#ifndef _FW_FAULT_TOLERANT_WRITE_LITE_PROTOCOL_H_ +#define _FW_FAULT_TOLERANT_WRITE_LITE_PROTOCOL_H_ + +#define EFI_FTW_LITE_PROTOCOL_GUID \ +{ 0x3f557189, 0x8dae, 0x45ae, {0xa0, 0xb3, 0x2b, 0x99, 0xca, 0x7a, 0xa7, 0xa0 } } + +// +// Forward reference for pure ANSI compatability +// +typedef struct _EFI_FTW_LITE_PROTOCOL EFI_FTW_LITE_PROTOCOL; + +// +// Protocol API definitions +// + +typedef +EFI_STATUS +(EFIAPI * EFI_FTW_LITE_WRITE) ( + IN EFI_FTW_LITE_PROTOCOL *This, + IN EFI_HANDLE FvbHandle, + IN EFI_LBA Lba, + IN UINTN Offset, + IN UINTN *NumBytes, + IN VOID *Buffer + ); +/*++ + +Routine Description: + + 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. + +Arguments: + + This - Calling context + FvBlockHandle - The handle of FVB protocol that provides services for + reading, writing, and erasing the target block. + Lba - The logical block address of the target block. + Offset - The offset within the target block to place the data. + Length - The number of bytes to write to the target block. + Buffer - The data to write. + +Returns: + + EFI_SUCCESS - The function completed successfully + EFI_ABORTED - The function could not complete successfully. + EFI_BAD_BUFFER_SIZE - The write would span a block boundary, + which is not a valid action. + EFI_ACCESS_DENIED - No writes have been allocated. + EFI_NOT_READY - The last write has not been completed. + Restart () must be called to complete it. + +--*/ + +// +// Protocol declaration +// +struct _EFI_FTW_LITE_PROTOCOL { + EFI_FTW_LITE_WRITE Write; +}; + +extern EFI_GUID gEfiFaultTolerantWriteLiteProtocolGuid; + +#endif diff --git a/EdkModulePkg/Include/Protocol/FvbExtension.h b/EdkModulePkg/Include/Protocol/FvbExtension.h new file mode 100644 index 0000000000..c2be78b8e4 --- /dev/null +++ b/EdkModulePkg/Include/Protocol/FvbExtension.h @@ -0,0 +1,53 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FvbExtension.h + +Abstract: + + FVB Extension protocol that extends the FVB Class in a component fashion. + +--*/ + +#ifndef _FVB_EXTENSION_H_ +#define _FVB_EXTENSION_H_ + +#define EFI_FVB_EXTENSION_PROTOCOL_GUID \ + {0x53a4c71b, 0xb581, 0x4170, {0x91, 0xb3, 0x8d, 0xb8, 0x7a, 0x4b, 0x5c, 0x46 } } + +typedef struct _EFI_FVB_EXTENSION_PROTOCOL EFI_FVB_EXTENSION_PROTOCOL; + +// +// FVB Extension Function Prototypes +// +typedef +EFI_STATUS +(EFIAPI * EFI_FV_ERASE_CUSTOM_BLOCK) ( + IN EFI_FVB_EXTENSION_PROTOCOL *This, + IN EFI_LBA StartLba, + IN UINTN OffsetStartLba, + IN EFI_LBA LastLba, + IN UINTN OffsetLastLba +); + +// +// IPMI TRANSPORT PROTOCOL +// +struct _EFI_FVB_EXTENSION_PROTOCOL { + EFI_FV_ERASE_CUSTOM_BLOCK EraseFvbCustomBlock; +}; + +extern EFI_GUID gEfiFvbExtensionProtocolGuid; + +#endif + diff --git a/EdkModulePkg/Include/Protocol/GenericMemoryTest.h b/EdkModulePkg/Include/Protocol/GenericMemoryTest.h new file mode 100644 index 0000000000..8f566d3763 --- /dev/null +++ b/EdkModulePkg/Include/Protocol/GenericMemoryTest.h @@ -0,0 +1,156 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + GenericMemoryTest.h + +Abstract: + + The EFI generic memory test protocol + For more information please look at EfiMemoryTest.doc + +--*/ + +#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; + +typedef enum { + IGNORE, + QUICK, + SPARSE, + EXTENSIVE, + MAXLEVEL +} EXTENDMEM_COVERAGE_LEVEL; + +typedef +EFI_STATUS +(EFIAPI *EFI_MEMORY_TEST_INIT) ( + IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This, + IN EXTENDMEM_COVERAGE_LEVEL Level, + OUT BOOLEAN *RequireSoftECCInit + ) +/*++ + + Routine Description: + Initialize the generic memory test. + + Arguments: + This - Protocol instance pointer. + Level - The coverage level of the memory test. + RequireSoftECCInit - Indicate if the memory need software ECC init. + + Returns: + EFI_SUCCESS - The generic memory test initialized correctly. + 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. + +--*/ +; + +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 + ) +/*++ + + Routine Description: + Perform the memory test. + + Arguments: + This - Protocol instance pointer. + TestedMemorySize - Return the tested extended memory size. + TotalMemorySize - Return the whole system physical memory size, this + value may be changed if in some case some error + DIMMs be disabled. + ErrorOut - Any time the memory error occurs, this will be TRUE. + IfTestAbort - Indicate if the user press "ESC" to skip the memory + test. + + Returns: + EFI_SUCCESS - One block of memory test ok, the block size is hide + internally. + EFI_NOT_FOUND - Indicate all the non-tested memory blocks have + already go through. + +--*/ +; + +typedef +EFI_STATUS +(EFIAPI *EFI_MEMORY_TEST_FINISHED) ( + IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This + ) +/*++ + + Routine Description: + The memory test finished. + + Arguments: + This - Protocol instance pointer. + + Returns: + EFI_SUCCESS - Successful free all the generic memory test driver + allocated resource and notify to platform memory + test driver that memory test finished. + +--*/ +; + +typedef +EFI_STATUS +(EFIAPI *EFI_MEMORY_TEST_COMPATIBLE_RANGE) ( + IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS StartAddress, + IN UINT64 Length + ) +/*++ + + Routine Description: + Provide capability to test compatible range which used by some sepcial + driver required using memory range before BDS perform memory test. + + Arguments: + This - Protocol instance pointer. + StartAddress - The start address of the memory range. + Length - The memory range's length. + + Return: + EFI_SUCCESS - The compatible memory range pass the memory test. + EFI_DEVICE_ERROR - The compatible memory range test find memory error + and also return return the error address. + +--*/ +; + +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/EdkModulePkg/Include/Protocol/IsaAcpi.h b/EdkModulePkg/Include/Protocol/IsaAcpi.h new file mode 100644 index 0000000000..c3d92f609d --- /dev/null +++ b/EdkModulePkg/Include/Protocol/IsaAcpi.h @@ -0,0 +1,177 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + IsaAcpi.h + +Abstract: + + EFI ISA Acpi Protocol + +Revision History + +--*/ + +#ifndef _ISA_ACPI_H_ +#define _ISA_ACPI_H_ + +#define EFI_ISA_ACPI_PROTOCOL_GUID \ + { 0x64a892dc, 0x5561, 0x4536, { 0x92, 0xc7, 0x79, 0x9b, 0xfc, 0x18, 0x33, 0x55 } } + +typedef struct _EFI_ISA_ACPI_PROTOCOL EFI_ISA_ACPI_PROTOCOL; + +// +// Resource Attribute definition +// +#define EFI_ISA_ACPI_IRQ_TYPE_HIGH_TRUE_EDGE_SENSITIVE 0x01 +#define EFI_ISA_ACPI_IRQ_TYPE_LOW_TRUE_EDGE_SENSITIVE 0x02 +#define EFI_ISA_ACPI_IRQ_TYPE_HIGH_TRUE_LEVEL_SENSITIVE 0x04 +#define EFI_ISA_ACPI_IRQ_TYPE_LOW_TRUE_LEVEL_SENSITIVE 0x08 + +#define EFI_ISA_ACPI_DMA_SPEED_TYPE_MASK 0x03 + +#define EFI_ISA_ACPI_DMA_SPEED_TYPE_COMPATIBILITY 0x00 +#define EFI_ISA_ACPI_DMA_SPEED_TYPE_A 0x01 +#define EFI_ISA_ACPI_DMA_SPEED_TYPE_B 0x02 +#define EFI_ISA_ACPI_DMA_SPEED_TYPE_F 0x03 +#define EFI_ISA_ACPI_DMA_COUNT_BY_BYTE 0x04 +#define EFI_ISA_ACPI_DMA_COUNT_BY_WORD 0x08 +#define EFI_ISA_ACPI_DMA_BUS_MASTER 0x10 +#define EFI_ISA_ACPI_DMA_TRANSFER_TYPE_8_BIT 0x20 +#define EFI_ISA_ACPI_DMA_TRANSFER_TYPE_8_BIT_AND_16_BIT 0x40 +#define EFI_ISA_ACPI_DMA_TRANSFER_TYPE_16_BIT 0x80 + +#define EFI_ISA_ACPI_MEMORY_WIDTH_MASK 0x03 + +#define EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT 0x00 +#define EFI_ISA_ACPI_MEMORY_WIDTH_16_BIT 0x01 +#define EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT_AND_16_BIT 0x02 +#define EFI_ISA_ACPI_MEMORY_WRITEABLE 0x04 +#define EFI_ISA_ACPI_MEMORY_CACHEABLE 0x08 +#define EFI_ISA_ACPI_MEMORY_SHADOWABLE 0x10 +#define EFI_ISA_ACPI_MEMORY_EXPANSION_ROM 0x20 + +#define EFI_ISA_ACPI_IO_DECODE_10_BITS 0x01 +#define EFI_ISA_ACPI_IO_DECODE_16_BITS 0x02 + +// +// Resource List definition: +// at first, the resource was defined as below +// but in the future, it will be defined again that follow ACPI spec: ACPI resource type +// so that, in this driver, we can interpret the ACPI table and get the ISA device information. +// + +typedef enum { + EfiIsaAcpiResourceEndOfList, + EfiIsaAcpiResourceIo, + EfiIsaAcpiResourceMemory, + EfiIsaAcpiResourceDma, + EfiIsaAcpiResourceInterrupt +} EFI_ISA_ACPI_RESOURCE_TYPE; + +typedef struct { + EFI_ISA_ACPI_RESOURCE_TYPE Type; + UINT32 Attribute; + UINT32 StartRange; + UINT32 EndRange; +} EFI_ISA_ACPI_RESOURCE; + +typedef struct { + UINT32 HID; + UINT32 UID; +} EFI_ISA_ACPI_DEVICE_ID; + +typedef struct { + EFI_ISA_ACPI_DEVICE_ID Device; + EFI_ISA_ACPI_RESOURCE *ResourceItem; +} EFI_ISA_ACPI_RESOURCE_LIST; + +// +// Prototypes for the ISA ACPI Protocol +// +typedef +EFI_STATUS +(EFIAPI *EFI_ISA_ACPI_DEVICE_ENUMERATE) ( + IN EFI_ISA_ACPI_PROTOCOL *This, + OUT EFI_ISA_ACPI_DEVICE_ID **Device + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_ISA_ACPI_SET_DEVICE_POWER) ( + IN EFI_ISA_ACPI_PROTOCOL *This, + IN EFI_ISA_ACPI_DEVICE_ID *Device, + IN BOOLEAN OnOff + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_ISA_ACPI_GET_CUR_RESOURCE) ( + IN EFI_ISA_ACPI_PROTOCOL *This, + IN EFI_ISA_ACPI_DEVICE_ID *Device, + OUT EFI_ISA_ACPI_RESOURCE_LIST **ResourceList + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_ISA_ACPI_GET_POS_RESOURCE) ( + IN EFI_ISA_ACPI_PROTOCOL *This, + IN EFI_ISA_ACPI_DEVICE_ID *Device, + OUT EFI_ISA_ACPI_RESOURCE_LIST **ResourceList + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_ISA_ACPI_SET_RESOURCE) ( + IN EFI_ISA_ACPI_PROTOCOL *This, + IN EFI_ISA_ACPI_DEVICE_ID *Device, + IN EFI_ISA_ACPI_RESOURCE_LIST *ResourceList + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_ISA_ACPI_ENABLE_DEVICE) ( + IN EFI_ISA_ACPI_PROTOCOL *This, + IN EFI_ISA_ACPI_DEVICE_ID *Device, + IN BOOLEAN Enable + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_ISA_ACPI_INIT_DEVICE) ( + IN EFI_ISA_ACPI_PROTOCOL *This, + IN EFI_ISA_ACPI_DEVICE_ID *Device + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_ISA_ACPI_INTERFACE_INIT) ( + IN EFI_ISA_ACPI_PROTOCOL *This + ); + +// +// Interface structure for the ISA ACPI Protocol +// +struct _EFI_ISA_ACPI_PROTOCOL { + EFI_ISA_ACPI_DEVICE_ENUMERATE DeviceEnumerate; + EFI_ISA_ACPI_SET_DEVICE_POWER SetPower; + EFI_ISA_ACPI_GET_CUR_RESOURCE GetCurResource; + EFI_ISA_ACPI_GET_POS_RESOURCE GetPosResource; + EFI_ISA_ACPI_SET_RESOURCE SetResource; + EFI_ISA_ACPI_ENABLE_DEVICE EnableDevice; + EFI_ISA_ACPI_INIT_DEVICE InitDevice; + EFI_ISA_ACPI_INTERFACE_INIT InterfaceInit; +}; + +extern EFI_GUID gEfiIsaAcpiProtocolGuid; + +#endif diff --git a/EdkModulePkg/Include/Protocol/IsaIo.h b/EdkModulePkg/Include/Protocol/IsaIo.h new file mode 100644 index 0000000000..8419dd4792 --- /dev/null +++ b/EdkModulePkg/Include/Protocol/IsaIo.h @@ -0,0 +1,174 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + IsaIo.h + +Abstract: + + EFI ISA I/O Protocol + +Revision History + +--*/ + +#ifndef _EFI_ISA_IO_H +#define _EFI_ISA_IO_H + +// +// Global ID for the ISA I/O Protocol +// + +#define EFI_ISA_IO_PROTOCOL_GUID \ + { 0x7ee2bd44, 0x3da0, 0x11d4, { 0x9a, 0x38, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } } + +typedef struct _EFI_ISA_IO_PROTOCOL EFI_ISA_IO_PROTOCOL; + +// +// Prototypes for the ISA I/O Protocol +// + +typedef enum { + EfiIsaIoWidthUint8, + EfiIsaIoWidthUint16, + EfiIsaIoWidthUint32, + EfiIsaIoWidthReserved, + EfiIsaIoWidthFifoUint8, + EfiIsaIoWidthFifoUint16, + EfiIsaIoWidthFifoUint32, + EfiIsaIoWidthFifoReserved, + EfiIsaIoWidthFillUint8, + EfiIsaIoWidthFillUint16, + EfiIsaIoWidthFillUint32, + EfiIsaIoWidthFillReserved, + EfiIsaIoWidthMaximum +} EFI_ISA_IO_PROTOCOL_WIDTH; + +// +// Attributes for common buffer allocations +// +#define EFI_ISA_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE 0x080 // Map a memory range so write are combined +#define EFI_ISA_IO_ATTRIBUTE_MEMORY_CACHED 0x800 // Map a memory range so all r/w accesses are cached +#define EFI_ISA_IO_ATTRIBUTE_MEMORY_DISABLE 0x1000 // Disable a memory range + +// +// Channel attribute for DMA operations +// +#define EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_COMPATIBLE 0x001 +#define EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_A 0x002 +#define EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_B 0x004 +#define EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_C 0x008 +#define EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8 0x010 +#define EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16 0x020 +#define EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE 0x040 +#define EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE 0x080 +#define EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_AUTO_INITIALIZE 0x100 + +typedef enum { + EfiIsaIoOperationBusMasterRead, + EfiIsaIoOperationBusMasterWrite, + EfiIsaIoOperationBusMasterCommonBuffer, + EfiIsaIoOperationSlaveRead, + EfiIsaIoOperationSlaveWrite, + EfiIsaIoOperationMaximum +} EFI_ISA_IO_PROTOCOL_OPERATION; + +typedef +EFI_STATUS +(EFIAPI *EFI_ISA_IO_PROTOCOL_IO_MEM) ( + IN EFI_ISA_IO_PROTOCOL *This, + IN EFI_ISA_IO_PROTOCOL_WIDTH Width, + IN UINT32 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +typedef struct { + EFI_ISA_IO_PROTOCOL_IO_MEM Read; + EFI_ISA_IO_PROTOCOL_IO_MEM Write; +} EFI_ISA_IO_PROTOCOL_ACCESS; + +typedef +EFI_STATUS +(EFIAPI *EFI_ISA_IO_PROTOCOL_COPY_MEM) ( + IN EFI_ISA_IO_PROTOCOL *This, + IN EFI_ISA_IO_PROTOCOL_WIDTH Width, + IN UINT32 DestOffset, + IN UINT32 SrcOffset, + IN UINTN Count + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_ISA_IO_PROTOCOL_MAP) ( + IN EFI_ISA_IO_PROTOCOL *This, + IN EFI_ISA_IO_PROTOCOL_OPERATION Operation, + IN UINT8 ChannelNumber OPTIONAL, + IN UINT32 ChannelAttributes, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_ISA_IO_PROTOCOL_UNMAP) ( + IN EFI_ISA_IO_PROTOCOL *This, + IN VOID *Mapping + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_ISA_IO_PROTOCOL_ALLOCATE_BUFFER) ( + IN EFI_ISA_IO_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT VOID **HostAddress, + IN UINT64 Attributes + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_ISA_IO_PROTOCOL_FREE_BUFFER) ( + IN EFI_ISA_IO_PROTOCOL *This, + IN UINTN Pages, + IN VOID *HostAddress + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_ISA_IO_PROTOCOL_FLUSH) ( + IN EFI_ISA_IO_PROTOCOL *This + ); + +// +// Interface structure for the ISA I/O Protocol +// +struct _EFI_ISA_IO_PROTOCOL { + EFI_ISA_IO_PROTOCOL_ACCESS Mem; + EFI_ISA_IO_PROTOCOL_ACCESS Io; + EFI_ISA_IO_PROTOCOL_COPY_MEM CopyMem; + EFI_ISA_IO_PROTOCOL_MAP Map; + EFI_ISA_IO_PROTOCOL_UNMAP Unmap; + EFI_ISA_IO_PROTOCOL_ALLOCATE_BUFFER AllocateBuffer; + EFI_ISA_IO_PROTOCOL_FREE_BUFFER FreeBuffer; + EFI_ISA_IO_PROTOCOL_FLUSH Flush; + EFI_ISA_ACPI_RESOURCE_LIST *ResourceList; + UINT32 RomSize; + VOID *RomImage; +}; + +extern EFI_GUID gEfiIsaIoProtocolGuid; + +#endif diff --git a/EdkModulePkg/Include/Protocol/LoadPe32Image.h b/EdkModulePkg/Include/Protocol/LoadPe32Image.h new file mode 100644 index 0000000000..d6f54aa527 --- /dev/null +++ b/EdkModulePkg/Include/Protocol/LoadPe32Image.h @@ -0,0 +1,68 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + LoadPe32Image.h + +Abstract: + Load File protocol as defined in the EFI 1.0 specification. + + Load file protocol exists to supports the addition of new boot devices, + and to support booting from devices that do not map well to file system. + Network boot is done via a LoadFile protocol. + + EFI 1.0 can boot from any device that produces a LoadFile protocol. + +--*/ + +#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; + +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, + OUT UINTN *NumberOfPages OPTIONAL, + OUT EFI_HANDLE *ImageHandle, + OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL, + IN UINT32 Attribute + ); + +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/EdkModulePkg/Include/Protocol/OEMBadging.h b/EdkModulePkg/Include/Protocol/OEMBadging.h new file mode 100644 index 0000000000..6b4602e2ee --- /dev/null +++ b/EdkModulePkg/Include/Protocol/OEMBadging.h @@ -0,0 +1,79 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + EfiOEMBadging.h + +Abstract: + + EFI OEM Badging Protocol definition header file + +Revision History + +--*/ + +#ifndef _EFI_OEM_BADGING_H_ +#define _EFI_OEM_BADGING_H_ + +// +// GUID for EFI OEM Badging Protocol +// +#define EFI_OEM_BADGING_PROTOCOL_GUID \ + { 0x170e13c0, 0xbf1b, 0x4218, {0x87, 0x1d, 0x2a, 0xbd, 0xc6, 0xf8, 0x87, 0xbc } } + + +typedef struct _EFI_OEM_BADGING_PROTOCOL EFI_OEM_BADGING_PROTOCOL; + +typedef enum { + EfiBadgingFormatBMP, + EfiBadgingFormatJPEG, + EfiBadgingFormatTIFF, + EfiBadgingFormatGIF, + EfiBadgingFormatUnknown +} EFI_BADGING_FORMAT; + +typedef enum { + EfiBadgingDisplayAttributeLeftTop, + EfiBadgingDisplayAttributeCenterTop, + EfiBadgingDisplayAttributeRightTop, + EfiBadgingDisplayAttributeCenterRight, + EfiBadgingDisplayAttributeRightBottom, + EfiBadgingDisplayAttributeCenterBottom, + EfiBadgingDisplayAttributeLeftBottom, + EfiBadgingDisplayAttributeCenterLeft, + EfiBadgingDisplayAttributeCenter, + EfiBadgingDisplayAttributeCustomized +} EFI_BADGING_DISPLAY_ATTRIBUTE; + + +typedef +EFI_STATUS +(EFIAPI *EFI_BADGING_GET_IMAGE) ( + IN EFI_OEM_BADGING_PROTOCOL *This, + IN OUT UINT32 *Instance, + OUT EFI_BADGING_FORMAT *Format, + OUT UINT8 **ImageData, + OUT UINTN *ImageSize, + OUT EFI_BADGING_DISPLAY_ATTRIBUTE *Attribute, + OUT UINTN *CoordinateX, + OUT UINTN *CoordinateY +); + + +struct _EFI_OEM_BADGING_PROTOCOL { + EFI_BADGING_GET_IMAGE GetImage; +}; + + +extern EFI_GUID gEfiOEMBadgingProtocolGuid; + +#endif diff --git a/EdkModulePkg/Include/Protocol/PciHotPlugRequest.h b/EdkModulePkg/Include/Protocol/PciHotPlugRequest.h new file mode 100644 index 0000000000..6d194ae3f0 --- /dev/null +++ b/EdkModulePkg/Include/Protocol/PciHotPlugRequest.h @@ -0,0 +1,54 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PciHotPlugRequest.h + +Abstract: + + + +--*/ + +#ifndef _PCI_HOTPLUG_REQUEST_H_ +#define _PCI_HOTPLUG_REQUEST_H_ + +#define EFI_PCI_HOTPLUG_REQUEST_PROTOCOL_GUID \ +{0x19cb87ab,0x2cb9,{0x4665,0x83,0x60,0xdd,0xcf,0x60,0x54,0xf7,0x9d}} + +typedef enum { + EfiPciHotPlugRequestAdd, + EfiPciHotplugRequestRemove +} EFI_PCI_HOTPLUG_OPERATION; + +typedef struct _EFI_PCI_HOTPLUG_REQUEST_PROTOCOL EFI_PCI_HOTPLUG_REQUEST_PROTOCOL; + +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_HOTPLUG_REQUEST_NOTIFY) ( + 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 +); + + + +struct _EFI_PCI_HOTPLUG_REQUEST_PROTOCOL { + EFI_PCI_HOTPLUG_REQUEST_NOTIFY Notify; +}; + +extern EFI_GUID gEfiPciHotPlugRequestProtocolGuid; + +#endif diff --git a/EdkModulePkg/Include/Protocol/Performance.h b/EdkModulePkg/Include/Protocol/Performance.h new file mode 100644 index 0000000000..c16ed8cced --- /dev/null +++ b/EdkModulePkg/Include/Protocol/Performance.h @@ -0,0 +1,166 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Performance.h + +Abstract: + + +--*/ + +#ifndef __PERFORMANCE_H_ +#define __PERFORMANCE_H_ + +#define PERFORMANCE_PROTOCOL_GUID \ + { 0x76b6bdfa, 0x2acd, 0x4462, {0x9E, 0x3F, 0xcb, 0x58, 0xC9, 0x69, 0xd9, 0x37 } } + +// +// Forward reference for pure ANSI compatability +// +typedef struct _PERFORMANCE_PROTOCOL PERFORMANCE_PROTOCOL; + +#define DXE_TOK "DXE" +#define SHELL_TOK "SHELL" +#define PEI_TOK "PEI" +#define BDS_TOK "BDS" +#define DRIVERBINDING_START_TOK "DriverBinding:Start" +#define DRIVERBINDING_SUPPORT_TOK "DriverBinding:Support" +#define START_IMAGE_TOK "StartImage" +#define LOAD_IMAGE_TOK "LoadImage" + +// +// 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]; + CHAR8 Module[DXE_PERFORMANCE_STRING_SIZE]; + UINT64 StartTimeStamp; + UINT64 EndTimeStamp; +} GAUGE_DATA_ENTRY; + +// +// The header must be aligned at 8 bytes +// +typedef struct { + UINT32 NumberOfEntries; + UINT32 Reserved; +} GAUGE_DATA_HEADER; + +/** + 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 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 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 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. + + 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 The indirect pointer to the gauge data entry specified by LogEntryKey + if the retrieval is successful. + + @retval EFI_SUCCESS The GuageDataEntry is successfuly found based on LogEntryKey. + @retval EFI_NOT_FOUND The LogEntryKey is the last entry (equals to the total entry number). + @retval EFI_INVALIDE_PARAMETER The LogEntryKey is not a valid entry (greater than the total entry number). + @retval EFI_INVALIDE_PARAMETER GaugeDataEntry is NULL. + +**/ +typedef +EFI_STATUS +(EFIAPI * PERFORMANCE_GET_GAUGE) ( + IN UINTN LogEntryKey, + OUT GAUGE_DATA_ENTRY **GaugeDataEntry + ); + +struct _PERFORMANCE_PROTOCOL { + PERFORMANCE_START_GAUGE StartGauge; + PERFORMANCE_END_GAUGE EndGauge; + PERFORMANCE_GET_GAUGE GetGauge; +}; + +extern EFI_GUID gPerformanceProtocolGuid; + +#endif diff --git a/EdkModulePkg/Include/Protocol/Print.h b/EdkModulePkg/Include/Protocol/Print.h new file mode 100644 index 0000000000..eee7a0db47 --- /dev/null +++ b/EdkModulePkg/Include/Protocol/Print.h @@ -0,0 +1,50 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Print.h + +Abstract: + + This file defines the Print protocol + +--*/ + +#ifndef _PPRINT_H_ +#define _PPRINT_H_ + +#define EFI_PRINT_PROTOCOL_GUID \ + { 0xdf2d868e, 0x32fc, 0x4cf0, {0x8e, 0x6b, 0xff, 0xd9, 0x5d, 0x13, 0x43, 0xd0 } } + +// +// Forward reference for pure ANSI compatability +// +typedef struct _EFI_PRINT_PROTOCOL EFI_PRINT_PROTOCOL; + + +typedef +UINTN +(EFIAPI *EFI_VSPRINT) ( + OUT CHAR16 *StartOfBuffer, + IN UINTN BufferSize, + IN CONST CHAR16 *FormatString, + IN VA_LIST Marker + ); + +struct _EFI_PRINT_PROTOCOL { + EFI_VSPRINT VSPrint; +}; + + +extern EFI_GUID gEfiPrintProtocolGuid; + +#endif diff --git a/EdkModulePkg/Include/Protocol/PxeDhcp4.h b/EdkModulePkg/Include/Protocol/PxeDhcp4.h new file mode 100644 index 0000000000..cd4602c06c --- /dev/null +++ b/EdkModulePkg/Include/Protocol/PxeDhcp4.h @@ -0,0 +1,350 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + PxeDhcp4.h + +Abstract: + EFI PXE DHCPv4 protocol definition + +--*/ + +#ifndef _PXEDHCP4_H_ +#define _PXEDHCP4_H_ + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +// +// PXE DHCPv4 GUID definition +// + +#define EFI_PXE_DHCP4_PROTOCOL_GUID \ + { 0x03c4e624, 0xac28, 0x11d3, {0x9a, 0x2d, 0x00, 0x90, 0x29, 0x3f, 0xc1, 0x4d } } + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +// +// Interface definition +// + +typedef struct _EFI_PXE_DHCP4_PROTOCOL EFI_PXE_DHCP4_PROTOCOL; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +// +// Descriptions of the DHCP version 4 header and options can be found +// in RFC-2131 and RFC-2132 at www.ietf.org +// + +#pragma pack(1) +typedef struct { + + UINT8 op; +#define BOOTP_REQUEST 1 +#define BOOTP_REPLY 2 + + UINT8 htype; + + UINT8 hlen; + + UINT8 hops; + + UINT32 xid; + + UINT16 secs; +#define DHCP4_INITIAL_SECONDS 4 + + UINT16 flags; +#define DHCP4_BROADCAST_FLAG 0x8000 + + UINT32 ciaddr; + + UINT32 yiaddr; + + UINT32 siaddr; + + UINT32 giaddr; + + UINT8 chaddr[16]; + + UINT8 sname[64]; + + UINT8 fname[128]; + +// +// This is the minimum option length as specified in RFC-2131. +// The packet must be padded out this far with DHCP4_PAD. +// DHCPv4 packets are usually 576 bytes in length. This length +// includes the IPv4 and UDPv4 headers but not the media header. +// Note: Not all DHCP relay agents will forward DHCPv4 packets +// if they are less than 384 bytes or exceed 576 bytes. Even if +// the underlying hardware can handle smaller and larger packets, +// many older relay agents will not accept them. +// + UINT32 magik; +#define DHCP4_MAGIK_NUMBER 0x63825363 + + UINT8 options[308]; + +} DHCP4_HEADER; +#pragma pack() + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +// +// DHCPv4 packet definition. Room for 576 bytes including IP and +// UDP header. +// + +#define DHCP4_MAX_PACKET_SIZE 576 +#define DHCP4_UDP_HEADER_SIZE 8 +#define DHCP4_IP_HEADER_SIZE 20 + +#pragma pack(1) +typedef union _DHCP4_PACKET { + UINT32 _force_data_alignment; + + UINT8 raw[1500]; + + DHCP4_HEADER dhcp4; +} DHCP4_PACKET; +#pragma pack() + +#define DHCP4_SERVER_PORT 67 +#define DHCP4_CLIENT_PORT 68 + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +// +// DHCPv4 and PXE option numbers. +// + +#define DHCP4_PAD 0 +#define DHCP4_END 255 +#define DHCP4_SUBNET_MASK 1 +#define DHCP4_TIME_OFFSET 2 +#define DHCP4_ROUTER_LIST 3 +#define DHCP4_TIME_SERVERS 4 +#define DHCP4_NAME_SERVERS 5 +#define DHCP4_DNS_SERVERS 6 +#define DHCP4_LOG_SERVERS 7 +#define DHCP4_COOKIE_SERVERS 8 +#define DHCP4_LPR_SREVERS 9 +#define DHCP4_IMPRESS_SERVERS 10 +#define DHCP4_RESOURCE_LOCATION_SERVERS 11 +#define DHCP4_HOST_NAME 12 +#define DHCP4_BOOT_FILE_SIZE 13 +#define DHCP4_DUMP_FILE 14 +#define DHCP4_DOMAIN_NAME 15 +#define DHCP4_SWAP_SERVER 16 +#define DHCP4_ROOT_PATH 17 +#define DHCP4_EXTENSION_PATH 18 +#define DHCP4_IP_FORWARDING 19 +#define DHCP4_NON_LOCAL_SOURCE_ROUTE 20 +#define DHCP4_POLICY_FILTER 21 +#define DHCP4_MAX_DATAGRAM_SIZE 22 +#define DHCP4_DEFAULT_TTL 23 +#define DHCP4_MTU_AGING_TIMEOUT 24 +#define DHCP4_MTU_SIZES 25 +#define DHCP4_MTU_TO_USE 26 +#define DHCP4_ALL_SUBNETS_LOCAL 27 +#define DHCP4_BROADCAST_ADDRESS 28 +#define DHCP4_PERFORM_MASK_DISCOVERY 29 +#define DHCP4_RESPOND_TO_MASK_REQ 30 +#define DHCP4_PERFORM_ROUTER_DISCOVERY 31 +#define DHCP4_ROUTER_SOLICIT_ADDRESS 32 +#define DHCP4_STATIC_ROUTER_LIST 33 +#define DHCP4_USE_ARP_TRAILERS 34 +#define DHCP4_ARP_CACHE_TIMEOUT 35 +#define DHCP4_ETHERNET_ENCAPSULATION 36 +#define DHCP4_TCP_DEFAULT_TTL 37 +#define DHCP4_TCP_KEEP_ALIVE_INT 38 +#define DHCP4_KEEP_ALIVE_GARBAGE 39 +#define DHCP4_NIS_DOMAIN_NAME 40 +#define DHCP4_NIS_SERVERS 41 +#define DHCP4_NTP_SERVERS 42 +#define DHCP4_VENDOR_SPECIFIC 43 +# define PXE_MTFTP_IP 1 +# define PXE_MTFTP_CPORT 2 +# define PXE_MTFTP_SPORT 3 +# define PXE_MTFTP_TMOUT 4 +# define PXE_MTFTP_DELAY 5 +# define PXE_DISCOVERY_CONTROL 6 +# define PXE_DISABLE_BROADCAST_DISCOVERY 0x01 +# define PXE_DISABLE_MULTICAST_DISCOVERY 0x02 +# define PXE_ACCEPT_ONLY_PXE_BOOT_SERVERS 0x04 +# define PXE_DO_NOT_PROMPT 0x08 +# define PXE_DISCOVERY_MCAST_ADDR 7 +# define PXE_BOOT_SERVERS 8 +# define PXE_BOOT_MENU 9 +# define PXE_BOOT_PROMPT 10 +# define PXE_MCAST_ADDRS_ALLOC 11 +# define PXE_CREDENTIAL_TYPES 12 +# define PXE_BOOT_ITEM 71 +#define DHCP4_NBNS_SERVERS 44 +#define DHCP4_NBDD_SERVERS 45 +#define DHCP4_NETBIOS_NODE_TYPE 46 +#define DHCP4_NETBIOS_SCOPE 47 +#define DHCP4_XWINDOW_SYSTEM_FONT_SERVERS 48 +#define DHCP4_XWINDOW_SYSTEM_DISPLAY_MANAGERS 49 +#define DHCP4_REQUESTED_IP_ADDRESS 50 +#define DHCP4_LEASE_TIME 51 +#define DHCP4_OPTION_OVERLOAD 52 +# define DHCP4_OVERLOAD_FNAME 1 +# define DHCP4_OVERLOAD_SNAME 2 +# define DHCP4_OVERLOAD_FNAME_AND_SNAME 3 +#define DHCP4_MESSAGE_TYPE 53 +# define DHCP4_MESSAGE_TYPE_DISCOVER 1 +# define DHCP4_MESSAGE_TYPE_OFFER 2 +# define DHCP4_MESSAGE_TYPE_REQUEST 3 +# define DHCP4_MESSAGE_TYPE_DECLINE 4 +# define DHCP4_MESSAGE_TYPE_ACK 5 +# define DHCP4_MESSAGE_TYPE_NAK 6 +# define DHCP4_MESSAGE_TYPE_RELEASE 7 +# define DHCP4_MESSAGE_TYPE_INFORM 8 +#define DHCP4_SERVER_IDENTIFIER 54 +#define DHCP4_PARAMETER_REQUEST_LIST 55 +#define DHCP4_ERROR_MESSAGE 56 +#define DHCP4_MAX_MESSAGE_SIZE 57 +# define DHCP4_DEFAULT_MAX_MESSAGE_SIZE 576 +#define DHCP4_RENEWAL_TIME 58 +#define DHCP4_REBINDING_TIME 59 +#define DHCP4_CLASS_IDENTIFIER 60 +#define DHCP4_CLIENT_IDENTIFIER 61 +#define DHCP4_NISPLUS_DOMAIN_NAME 64 +#define DHCP4_NISPLUS_SERVERS 65 +#define DHCP4_TFTP_SERVER_NAME 66 +#define DHCP4_BOOTFILE 67 +#define DHCP4_MOBILE_IP_HOME_AGENTS 68 +#define DHCP4_SMPT_SERVERS 69 +#define DHCP4_POP3_SERVERS 70 +#define DHCP4_NNTP_SERVERS 71 +#define DHCP4_WWW_SERVERS 72 +#define DHCP4_FINGER_SERVERS 73 +#define DHCP4_IRC_SERVERS 74 +#define DHCP4_STREET_TALK_SERVERS 75 +#define DHCP4_STREET_TALK_DIR_ASSIST_SERVERS 76 +#define DHCP4_NDS_SERVERS 85 +#define DHCP4_NDS_TREE_NAME 86 +#define DHCP4_NDS_CONTEXT 87 +#define DHCP4_SYSTEM_ARCHITECTURE 93 +#define DHCP4_NETWORK_ARCHITECTURE 94 +#define DHCP4_PLATFORM_ID 97 + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +// +// DHCP4 option format. +// + +#pragma pack(1) +typedef struct { + UINT8 op; + UINT8 len; + UINT8 data[1]; +} DHCP4_OP; +#pragma pack() + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +typedef struct { + DHCP4_PACKET Discover; + DHCP4_PACKET Offer; + DHCP4_PACKET Request; + DHCP4_PACKET AckNak; + BOOLEAN SetupCompleted; + BOOLEAN InitCompleted; + BOOLEAN SelectCompleted; + BOOLEAN IsBootp; + BOOLEAN IsAck; +} EFI_PXE_DHCP4_DATA; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_DHCP4_RUN) ( + IN EFI_PXE_DHCP4_PROTOCOL *This, + IN OPTIONAL UINTN OpLen, + IN OPTIONAL VOID *OpList + ); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_DHCP4_SETUP) ( + IN EFI_PXE_DHCP4_PROTOCOL *This, + IN OPTIONAL EFI_PXE_DHCP4_DATA * NewData + ); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_DHCP4_INIT) ( + IN EFI_PXE_DHCP4_PROTOCOL *This, + IN UINTN SecondsTimeout, + OUT UINTN *Offers, + OUT DHCP4_PACKET **OfferList + ); + +#define DHCP4_MIN_SECONDS 1 +#define DHCP4_MAX_SECONDS 60 + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_DHCP4_SELECT) ( + IN EFI_PXE_DHCP4_PROTOCOL *This, + IN UINTN SecondsTimeout, + IN DHCP4_PACKET * offer + ); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_DHCP4_RENEW) ( + IN EFI_PXE_DHCP4_PROTOCOL *This, + UINTN seconds_timeout + ); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_DHCP4_REBIND) ( + IN EFI_PXE_DHCP4_PROTOCOL *This, + UINTN seconds_timeout + ); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_DHCP4_RELEASE) ( + IN EFI_PXE_DHCP4_PROTOCOL * This + ); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +#define EFI_PXE_DHCP4_PROTOCOL_REVISION 0x00010000 + +struct _EFI_PXE_DHCP4_PROTOCOL { + UINT64 Revision; + EFI_PXE_DHCP4_RUN Run; + EFI_PXE_DHCP4_SETUP Setup; + EFI_PXE_DHCP4_INIT Init; + EFI_PXE_DHCP4_SELECT Select; + EFI_PXE_DHCP4_RENEW Renew; + EFI_PXE_DHCP4_REBIND Rebind; + EFI_PXE_DHCP4_RELEASE Release; + EFI_PXE_DHCP4_DATA *Data; +}; + +// +// +// + +extern EFI_GUID gEfiPxeDhcp4ProtocolGuid; + +#endif /* _PXEDHCP4_H_ */ +/* EOF - PxeDhcp4.h */ diff --git a/EdkModulePkg/Include/Protocol/PxeDhcp4CallBack.h b/EdkModulePkg/Include/Protocol/PxeDhcp4CallBack.h new file mode 100644 index 0000000000..aa2b89a884 --- /dev/null +++ b/EdkModulePkg/Include/Protocol/PxeDhcp4CallBack.h @@ -0,0 +1,85 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + PxeDhcp4Callback.h + +Abstract: + EFI PXE DHCP4 Callback protocol definition. + +--*/ + +#ifndef _PXE_DHCP4CALLBACK_H +#define _PXE_DHCP4CALLBACK_H + +#include +// +// GUID definition +// + +#define EFI_PXE_DHCP4_CALLBACK_PROTOCOL_GUID \ +{ 0xc1544c01, 0x92a4, 0x4198, {0x8a, 0x84, 0x77, 0x85, 0x83, 0xc2, 0x36, 0x21 } } + + +// +// Revision number +// + +#define EFI_PXE_DHCP4_CALLBACK_INTERFACE_REVISION 0x00010000 + +// +// Interface definition +// + +typedef struct _EFI_PXE_DHCP4_CALLBACK_PROTOCOL EFI_PXE_DHCP4_CALLBACK_PROTOCOL; + +typedef enum { + EFI_PXE_DHCP4_FUNCTION_FIRST, + EFI_PXE_DHCP4_FUNCTION_INIT, + EFI_PXE_DHCP4_FUNCTION_SELECT, + EFI_PXE_DHCP4_FUNCTION_RENEW, + EFI_PXE_DHCP4_FUNCTION_REBIND, + EFI_PXE_DHCP4_FUNCTION_LAST +} EFI_PXE_DHCP4_FUNCTION; + +typedef enum { + EFI_PXE_DHCP4_CALLBACK_STATUS_FIRST, + EFI_PXE_DHCP4_CALLBACK_STATUS_ABORT, + EFI_PXE_DHCP4_CALLBACK_STATUS_IGNORE_ABORT, + EFI_PXE_DHCP4_CALLBACK_STATUS_KEEP_ABORT, + EFI_PXE_DHCP4_CALLBACK_STATUS_CONTINUE, + EFI_PXE_DHCP4_CALLBACK_STATUS_IGNORE_CONTINUE, + EFI_PXE_DHCP4_CALLBACK_STATUS_KEEP_CONTINUE, + EFI_PXE_DHCP4_CALLBACK_STATUS_LAST +} EFI_PXE_DHCP4_CALLBACK_STATUS; + +typedef +EFI_PXE_DHCP4_CALLBACK_STATUS +(EFIAPI *EFI_PXE_DHCP4_CALLBACK) ( + IN EFI_PXE_DHCP4_PROTOCOL *This, + IN EFI_PXE_DHCP4_FUNCTION Function, + IN UINT32 PacketLen, + IN DHCP4_PACKET *Packet OPTIONAL + ); + +struct _EFI_PXE_DHCP4_CALLBACK_PROTOCOL { + UINT64 Revision; + EFI_PXE_DHCP4_CALLBACK Callback; +}; + +// +// GUID declaration +// + +extern EFI_GUID gEfiPxeDhcp4CallbackProtocolGuid; + +#endif /* _PXE_DHCP4CALLBACK_H */ +/* EOF - PxeDhcp4Callback.h */ diff --git a/EdkModulePkg/Include/Protocol/ScsiIo.h b/EdkModulePkg/Include/Protocol/ScsiIo.h new file mode 100644 index 0000000000..1b0bbbf862 --- /dev/null +++ b/EdkModulePkg/Include/Protocol/ScsiIo.h @@ -0,0 +1,241 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ScsiIo.h + +Abstract: + + SCSI I/O protocol. + +--*/ + +#ifndef __SCSI_IO_H__ +#define __SCSI_IO_H__ + +#define EFI_SCSI_IO_PROTOCOL_GUID \ + { 0x403cd195, 0xf233, 0x48ec, {0x84, 0x55, 0xb2, 0xe5, 0x2f, 0x1d, 0x9e, 0x2 } } + +// +// Forward reference for pure ANSI compatability +// +typedef struct _EFI_SCSI_IO_PROTOCOL EFI_SCSI_IO_PROTOCOL; + +// +// SCSI Host Adapter Status definition +// +#define EFI_SCSI_IO_STATUS_HOST_ADAPTER_OK 0x00 +#define EFI_SCSI_IO_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND 0x09 // timeout when processing the command +#define EFI_SCSI_IO_STATUS_HOST_ADAPTER_TIMEOUT 0x0b // timeout when waiting for the command processing +#define EFI_SCSI_IO_STATUS_HOST_ADAPTER_MESSAGE_REJECT 0x0d // a message reject was received when processing command +#define EFI_SCSI_IO_STATUS_HOST_ADAPTER_BUS_RESET 0x0e // a bus reset was detected +#define EFI_SCSI_IO_STATUS_HOST_ADAPTER_PARITY_ERROR 0x0f +#define EFI_SCSI_IO_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED 0x10 // the adapter failed in issuing request sense command +#define EFI_SCSI_IO_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT 0x11 // selection timeout +#define EFI_SCSI_IO_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN 0x12 // data overrun or data underrun +#define EFI_SCSI_IO_STATUS_HOST_ADAPTER_BUS_FREE 0x13 // Unexepected bus free +#define EFI_SCSI_IO_STATUS_HOST_ADAPTER_PHASE_ERROR 0x14 // Target bus phase sequence failure +#define EFI_SCSI_IO_STATUS_HOST_ADAPTER_OTHER 0x7f + + +// +// SCSI Target Status definition +// +#define EFI_SCSI_IO_STATUS_TARGET_GOOD 0x00 +#define EFI_SCSI_IO_STATUS_TARGET_CHECK_CONDITION 0x02 // check condition +#define EFI_SCSI_IO_STATUS_TARGET_CONDITION_MET 0x04 // condition met +#define EFI_SCSI_IO_STATUS_TARGET_BUSY 0x08 // busy +#define EFI_SCSI_IO_STATUS_TARGET_INTERMEDIATE 0x10 // intermediate +#define EFI_SCSI_IO_STATUS_TARGET_INTERMEDIATE_CONDITION_MET 0x14 // intermediate-condition met +#define EFI_SCSI_IO_STATUS_TARGET_RESERVATION_CONFLICT 0x18 // reservation conflict +#define EFI_SCSI_IO_STATUS_TARGET_COMMOND_TERMINATED 0x22 // command terminated +#define EFI_SCSI_IO_STATUS_TARGET_QUEUE_FULL 0x28 // queue full + +typedef struct { + UINT64 Timeout; + VOID *DataBuffer; + VOID *SenseData; + VOID *Cdb; + UINT32 TransferLength; + UINT8 CdbLength; + UINT8 DataDirection; + UINT8 HostAdapterStatus; + UINT8 TargetStatus; + UINT8 SenseDataLength; +}EFI_SCSI_IO_SCSI_REQUEST_PACKET; + +typedef +EFI_STATUS +(EFIAPI *EFI_SCSI_IO_PROTOCOL_GET_DEVICE_TYPE) ( + IN EFI_SCSI_IO_PROTOCOL *This, + OUT UINT8 *DeviceType + ) +/*++ + + Routine Description: + Retrieves the device type information of the SCSI Controller. + + Arguments: + This - Protocol instance pointer. + DeviceType - A pointer to the device type information + retrieved from the SCSI Controller. + + Returns: + EFI_SUCCESS - Retrieves the device type information successfully. + EFI_INVALID_PARAMETER - The DeviceType is NULL. +--*/ +; + +typedef +EFI_STATUS +(EFIAPI *EFI_SCSI_IO_PROTOCOL_GET_DEVICE_LOCATION) ( + IN EFI_SCSI_IO_PROTOCOL *This, + OUT UINT32 *Target, + OUT UINT64 *Lun + ) +/*++ + Routine Description: + Retrieves the device location in the SCSI channel. + + Arguments: + This - Protocol instance pointer. + Target - A pointer to the Target ID of a SCSI device + on the SCSI channel. + Lun - A pointer to the LUN of the SCSI device on + the SCSI channel. + + Returns: + EFI_SUCCESS - Retrieves the device location successfully. + EFI_INVALID_PARAMETER - The Target or Lun is NULL. +--*/ +; + +typedef +EFI_STATUS +(EFIAPI *EFI_SCSI_IO_PROTOCOL_RESET_BUS) ( + IN EFI_SCSI_IO_PROTOCOL *This + ) +/*++ + + Routine Description: + Resets the SCSI Bus that the SCSI Controller is attached to. + + Arguments: + This - Protocol instance pointer. + + Returns: + EFI_SUCCESS - The SCSI bus is reset successfully. + EFI_DEVICE_ERROR - Errors encountered when resetting the SCSI bus. + EFI_UNSUPPORTED - The bus reset operation is not supported by the + SCSI Host Controller. + EFI_TIMEOUT - A timeout occurred while attempting to reset + the SCSI bus. +--*/ +; + +typedef +EFI_STATUS +(EFIAPI *EFI_SCSI_IO_PROTOCOL_RESET_DEVICE) ( + IN EFI_SCSI_IO_PROTOCOL *This + ) +/*++ + + Routine Description: + Resets the SCSI Controller that the device handle specifies. + + Arguments: + This - Protocol instance pointer. + + + Returns: + EFI_SUCCESS - Reset the SCSI controller successfully. + EFI_DEVICE_ERROR - Errors are encountered when resetting the + SCSI Controller. + EFI_UNSUPPORTED - The SCSI bus does not support a device + reset operation. + EFI_TIMEOUT - A timeout occurred while attempting to + reset the SCSI Controller. +--*/ +; + + +typedef +EFI_STATUS +(EFIAPI *EFI_SCSI_IO_PROTOCOL_EXEC_SCSI_CMD) ( + IN EFI_SCSI_IO_PROTOCOL *This, + IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet, + IN EFI_EVENT Event OPTIONAL + ) +/*++ + + Routine Description: + Sends a SCSI Request Packet to the SCSI Controller for execution. + + Arguments: + This - Protocol instance pointer. + Packet - The SCSI request packet to send to the SCSI + Controller specified by the device handle. + 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. + Returns: + 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. + EFI_WARN_BUFFER_TOO_SMALL - 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. + 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. + 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. + EFI_INVALID_PARAMETER - The contents of CommandPacket are invalid. + The SCSI Request Packet was not sent, so no + additional status information is available. + 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. + 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. +--*/ +; + +struct _EFI_SCSI_IO_PROTOCOL { + EFI_SCSI_IO_PROTOCOL_GET_DEVICE_TYPE GetDeviceType; + EFI_SCSI_IO_PROTOCOL_GET_DEVICE_LOCATION GetDeviceLocation; + EFI_SCSI_IO_PROTOCOL_RESET_BUS ResetBus; + EFI_SCSI_IO_PROTOCOL_RESET_DEVICE ResetDevice; + EFI_SCSI_IO_PROTOCOL_EXEC_SCSI_CMD ExecuteSCSICommand; +}; + +extern EFI_GUID gEfiScsiIoProtocolGuid; + +#endif + diff --git a/EdkModulePkg/Include/Protocol/SecurityPolicy.h b/EdkModulePkg/Include/Protocol/SecurityPolicy.h new file mode 100644 index 0000000000..f587b441e5 --- /dev/null +++ b/EdkModulePkg/Include/Protocol/SecurityPolicy.h @@ -0,0 +1,33 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + SecurityPolicy.h + +Abstract: + + Security Policy protocol as defined in the DXE CIS + +--*/ + +#ifndef _SECURITY_POLICY_H_ +#define _SECURITY_POLICY_H_ + +// +// Security policy protocol GUID definition +// +#define EFI_SECURITY_POLICY_PROTOCOL_GUID \ + {0x78E4D245, 0xCD4D, 0x4a05, {0xA2, 0xBA, 0x47, 0x43, 0xE8, 0x6C, 0xFC, 0xAB} } + +extern EFI_GUID gEfiSecurityPolicyProtocolGuid; + +#endif diff --git a/EdkModulePkg/Include/Protocol/UgaIo.h b/EdkModulePkg/Include/Protocol/UgaIo.h new file mode 100644 index 0000000000..91ff8df35a --- /dev/null +++ b/EdkModulePkg/Include/Protocol/UgaIo.h @@ -0,0 +1,236 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + UgaIo.h + +Abstract: + + UGA IO protocol from the EFI 1.1 specification. + + Abstraction of a very simple graphics device. + +--*/ + +#ifndef __UGA_IO_H__ +#define __UGA_IO_H__ + +#define EFI_UGA_IO_PROTOCOL_GUID \ + { \ + 0x61a4d49e, 0x6f68, 0x4f1b, { 0xb9, 0x22, 0xa8, 0x6e, 0xed, 0xb, 0x7, 0xa2 } \ + } + +typedef struct _EFI_UGA_IO_PROTOCOL EFI_UGA_IO_PROTOCOL; + +typedef UINT32 UGA_STATUS; + +typedef enum { + UgaDtParentBus = 1, + UgaDtGraphicsController, + UgaDtOutputController, + UgaDtOutputPort, + UgaDtOther +} +UGA_DEVICE_TYPE, *PUGA_DEVICE_TYPE; + +typedef UINT32 UGA_DEVICE_ID, *PUGA_DEVICE_ID; + +typedef struct { + UGA_DEVICE_TYPE deviceType; + UGA_DEVICE_ID deviceId; + UINT32 ui32DeviceContextSize; + UINT32 ui32SharedContextSize; +} +UGA_DEVICE_DATA, *PUGA_DEVICE_DATA; + +typedef struct _UGA_DEVICE { + VOID *pvDeviceContext; + VOID *pvSharedContext; + VOID *pvRunTimeContext; + struct _UGA_DEVICE *pParentDevice; + VOID *pvBusIoServices; + VOID *pvStdIoServices; + UGA_DEVICE_DATA deviceData; +} +UGA_DEVICE, *PUGA_DEVICE; + +#ifndef UGA_IO_REQUEST_CODE +// +// Prevent conflicts with UGA typedefs. +// +typedef enum { + UgaIoGetVersion = 1, + UgaIoGetChildDevice, + UgaIoStartDevice, + UgaIoStopDevice, + UgaIoFlushDevice, + UgaIoResetDevice, + UgaIoGetDeviceState, + UgaIoSetDeviceState, + UgaIoSetPowerState, + UgaIoGetMemoryConfiguration, + UgaIoSetVideoMode, + UgaIoCopyRectangle, + UgaIoGetEdidSegment, + UgaIoDeviceChannelOpen, + UgaIoDeviceChannelClose, + UgaIoDeviceChannelRead, + UgaIoDeviceChannelWrite, + UgaIoGetPersistentDataSize, + UgaIoGetPersistentData, + UgaIoSetPersistentData, + UgaIoGetDevicePropertySize, + UgaIoGetDeviceProperty, + UgaIoBtPrivateInterface +} +UGA_IO_REQUEST_CODE, *PUGA_IO_REQUEST_CODE; + +#endif + +typedef struct { + IN UGA_IO_REQUEST_CODE ioRequestCode; + IN VOID *pvInBuffer; + IN UINT64 ui64InBufferSize; + OUT VOID *pvOutBuffer; + IN UINT64 ui64OutBufferSize; + OUT UINT64 ui64BytesReturned; +} +UGA_IO_REQUEST, *PUGA_IO_REQUEST; + +typedef +EFI_STATUS +(EFIAPI *EFI_UGA_IO_PROTOCOL_CREATE_DEVICE) ( + IN EFI_UGA_IO_PROTOCOL * This, + IN UGA_DEVICE * ParentDevice, + IN UGA_DEVICE_DATA * DeviceData, + IN VOID *RunTimeContext, + OUT UGA_DEVICE **Device + ); + +/*++ + + Routine Description: + + Dynamically allocate storage for a child UGA_DEVICE . + + Arguments: + + This - The EFI_UGA_IO_PROTOCOL instance. Type EFI_UGA_IO_PROTOCOL is + defined in Section 10.7. + + ParentDevice - ParentDevice specifies a pointer to the parent device of Device. + + DeviceData - A pointer to UGA_DEVICE_DATA returned from a call to DispatchService() + with a UGA_DEVICE of Parent and an IoRequest of type UgaIoGetChildDevice. + + RuntimeContext - Context to associate with Device. + + Device - The Device returns a dynamically allocated child UGA_DEVICE object + for ParentDevice. The caller is responsible for deleting Device. + + Returns: + + EFI_SUCCESS - Device was returned. + + EFI_INVALID_PARAMETER - One of the arguments was not valid. + + EFI_DEVICE_ERROR - The device had an error and could not complete the request. + +--*/ +typedef +EFI_STATUS +(EFIAPI *EFI_UGA_IO_PROTOCOL_DELETE_DEVICE) ( + IN EFI_UGA_IO_PROTOCOL * This, + IN UGA_DEVICE * Device + ); + +/*++ + + Routine Description: + + Delete a dynamically allocated child UGA_DEVICE object that was allocated via + CreateDevice() . + + Arguments: + + This - The EFI_UGA_IO_PROTOCOL instance. Type EFI_UGA_IO_PROTOCOL is defined + in Section 10.7. + + Device - The Device points to a UGA_DEVICE object that was dynamically + allocated via a CreateDevice() call. + + Returns: + + EFI_SUCCESS - Device was deleted. + + EFI_INVALID_PARAMETER - The Device was not allocated via CreateDevice() + +--*/ +typedef UGA_STATUS (EFIAPI *PUGA_FW_SERVICE_DISPATCH) (IN PUGA_DEVICE pDevice, IN OUT PUGA_IO_REQUEST pIoRequest); + +/*++ + + Routine Description: + + This is the main UGA service dispatch routine for all UGA_IO_REQUEST s. + + Arguments: + + pDevice - pDevice specifies a pointer to a device object associated with a + device enumerated by a pIoRequest->ioRequestCode of type + UgaIoGetChildDevice. The root device for the EFI_UGA_IO_PROTOCOL + is represented by pDevice being set to NULL. + + pIoRequest - pIoRequest points to a caller allocated buffer that contains data + defined by pIoRequest->ioRequestCode. See Related Definitions for + a definition of UGA_IO_REQUEST_CODE s and their associated data + structures. + + Returns: + + Varies depending on pIoRequest. + +--*/ +struct _EFI_UGA_IO_PROTOCOL { + EFI_UGA_IO_PROTOCOL_CREATE_DEVICE CreateDevice; + EFI_UGA_IO_PROTOCOL_DELETE_DEVICE DeleteDevice; + PUGA_FW_SERVICE_DISPATCH DispatchService; +}; + +extern EFI_GUID gEfiUgaIoProtocolGuid; + +// +// Data structure that is stored in the EFI Configuration Table with the +// EFI_UGA_IO_PROTOCOL_GUID. The option ROMs listed in this table may have +// EBC UGA drivers. +// +typedef struct { + UINT32 Version; + UINT32 HeaderSize; + UINT32 SizeOfEntries; + UINT32 NumberOfEntries; +} EFI_DRIVER_OS_HANDOFF_HEADER; + +typedef enum { + EfiUgaDriverFromPciRom, + EfiUgaDriverFromSystem, + EfiDriverHandoffMax +} EFI_DRIVER_HANOFF_ENUM; + +typedef struct { + EFI_DRIVER_HANOFF_ENUM Type; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + VOID *PciRomImage; + UINT64 PciRomSize; +} EFI_DRIVER_OS_HANDOFF; + +#endif diff --git a/EdkModulePkg/Include/Protocol/UgaSplash.h b/EdkModulePkg/Include/Protocol/UgaSplash.h new file mode 100644 index 0000000000..51dcf523d3 --- /dev/null +++ b/EdkModulePkg/Include/Protocol/UgaSplash.h @@ -0,0 +1,42 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + UgaSplash.h + +Abstract: + + UGA Splash screen protocol. + + Abstraction of a very simple graphics device. + +--*/ + +#ifndef __UGA_SPLASH_H__ +#define __UGA_SPLASH_H__ + + +#define EFI_UGA_SPLASH_PROTOCOL_GUID \ + { 0xa45b3a0d, 0x2e55, 0x4c03, {0xad, 0x9c, 0x27, 0xd4, 0x82, 0xb, 0x50, 0x7e } } + +typedef struct _EFI_UGA_SPLASH_PROTOCOL EFI_UGA_SPLASH_PROTOCOL; + + +struct _EFI_UGA_SPLASH_PROTOCOL { + UINT32 PixelWidth; + UINT32 PixelHeight; + EFI_UGA_PIXEL *Image; +}; + +extern EFI_GUID gEfiUgaSplashProtocolGuid; + +#endif diff --git a/EdkModulePkg/Include/Protocol/usbatapi.h b/EdkModulePkg/Include/Protocol/usbatapi.h new file mode 100644 index 0000000000..8801a7ae6c --- /dev/null +++ b/EdkModulePkg/Include/Protocol/usbatapi.h @@ -0,0 +1,83 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + UsbAtapi.h + +Abstract: + + EFI Atapi Protocol definition. + +Revision History + +--*/ + +#ifndef _EFI_USB_ATAPI_H +#define _EFI_USB_ATAPI_H + +// +// Transfer protocol types +// +#define BOT 0x50 +#define CBI0 0x00 +#define CBI1 0x01 + +// +// SubClass Code (defines command set) +// +#define EFI_USB_SUBCLASS_RBC 0x01 +#define EFI_USB_SUBCLASS_ATAPI 0x02 +#define EFI_USB_SUBCLASS_QIC_157 0x03 +#define EFI_USB_SUBCLASS_UFI 0x04 +#define EFI_USB_SUBCLASS_SFF_8070i 0x05 +#define EFI_USB_SUBCLASS_SCSI 0x06 +#define EFI_USB_SUBCLASS_RESERVED_LOW 0x07 +#define EFI_USB_SUBCLASS_RESERVED_HIGH 0xff +// +// Global GUID for transfer protocol interface +// +#define EFI_USB_ATAPI_PROTOCOL_GUID \ + { 0x2B2F68DA, 0x0CD2, 0x44cf, {0x8E, 0x8B, 0xBB, 0xA2, 0x0B, 0x1B, 0x5B, 0x75 } } + +typedef struct _EFI_USB_ATAPI_PROTOCOL EFI_USB_ATAPI_PROTOCOL; + +typedef +EFI_STATUS +(EFIAPI *EFI_USB_ATAPI_PACKET_CMD) ( + IN EFI_USB_ATAPI_PROTOCOL *This, + IN VOID *Command, + IN UINT8 CommandSize, + IN VOID *DataBuffer, + IN UINT32 BufferLength, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT16 TimeOutInMilliSeconds +); + +typedef +EFI_STATUS +(EFIAPI *EFI_USB_MASS_STORAGE_RESET) ( + IN EFI_USB_ATAPI_PROTOCOL *This, + IN BOOLEAN ExtendedVerification +); + +// +// Protocol Interface Structure +// +struct _EFI_USB_ATAPI_PROTOCOL { + EFI_USB_ATAPI_PACKET_CMD UsbAtapiPacketCmd; + EFI_USB_MASS_STORAGE_RESET UsbAtapiReset; + UINT32 CommandProtocol; +}; + +extern EFI_GUID gEfiUsbAtapiProtocolGuid; + +#endif diff --git a/EdkModulePkg/Library/BaseCustomDecompressLibNull/BaseCustomDecompressLibNull.c b/EdkModulePkg/Library/BaseCustomDecompressLibNull/BaseCustomDecompressLibNull.c new file mode 100644 index 0000000000..b165f474e3 --- /dev/null +++ b/EdkModulePkg/Library/BaseCustomDecompressLibNull/BaseCustomDecompressLibNull.c @@ -0,0 +1,80 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + BaseCustomDecompressLibNull.c + +Abstract: + + NULL Custom Decompress Library + +--*/ + +RETURN_STATUS +EFIAPI +CustomDecompressGetInfo ( + IN CONST VOID *Source, + IN UINT32 SourceSize, + OUT UINT32 *DestinationSize, + OUT UINT32 *ScratchSize + ) +/*++ + +Routine Description: + + The internal implementation of *_DECOMPRESS_PROTOCOL.GetInfo(). + +Arguments: + + Source - The source buffer containing the compressed data. + SourceSize - The size of source buffer + DestinationSize - The size of destination buffer. + ScratchSize - The size of scratch buffer. + +Returns: + + RETURN_SUCCESS - The size of destination buffer and the size of scratch buffer are successull retrieved. + RETURN_INVALID_PARAMETER - The source data is corrupted + +--*/ +{ + return RETURN_UNSUPPORTED; +} + +RETURN_STATUS +EFIAPI +CustomDecompress ( + IN CONST VOID *Source, + IN OUT VOID *Destination, + IN OUT VOID *Scratch + ) +/*++ + +Routine Description: + + The internal implementation of *_DECOMPRESS_PROTOCOL.Decompress(). + +Arguments: + + Source - The source buffer containing the compressed data. + Destination - The destination buffer to store the decompressed data + Scratch - The buffer used internally by the decompress routine. This buffer is needed to store intermediate data. + +Returns: + + RETURN_SUCCESS - Decompression is successfull + RETURN_INVALID_PARAMETER - The source data is corrupted + +--*/ +{ + return RETURN_UNSUPPORTED; +} diff --git a/EdkModulePkg/Library/BaseCustomDecompressLibNull/BaseCustomDecompressLibNull.mbd b/EdkModulePkg/Library/BaseCustomDecompressLibNull/BaseCustomDecompressLibNull.mbd new file mode 100644 index 0000000000..0cbb341dd7 --- /dev/null +++ b/EdkModulePkg/Library/BaseCustomDecompressLibNull/BaseCustomDecompressLibNull.mbd @@ -0,0 +1,30 @@ + + + + + BaseCustomDecompressLibNull + e5566134-c75e-4ace-bad1-e23a3b335e30 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:18 + + diff --git a/EdkModulePkg/Library/BaseCustomDecompressLibNull/BaseCustomDecompressLibNull.msa b/EdkModulePkg/Library/BaseCustomDecompressLibNull/BaseCustomDecompressLibNull.msa new file mode 100644 index 0000000000..4dbc8a6f63 --- /dev/null +++ b/EdkModulePkg/Library/BaseCustomDecompressLibNull/BaseCustomDecompressLibNull.msa @@ -0,0 +1,45 @@ + + + + + BaseCustomDecompressLibNull + BASE + LIBRARY + e5566134-c75e-4ace-bad1-e23a3b335e30 + 0 + Component description file for the entry point to a EFIDXE Drivers + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:18 + + + CustomDecompressLib + DebugLib + + + BaseCustomDecompressLibNull.c + + + MdePkg + EdkModulePkg + + diff --git a/EdkModulePkg/Library/BaseCustomDecompressLibNull/build.xml b/EdkModulePkg/Library/BaseCustomDecompressLibNull/build.xml new file mode 100644 index 0000000000..d2f8ab44df --- /dev/null +++ b/EdkModulePkg/Library/BaseCustomDecompressLibNull/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Library/BaseUefiTianoDecompressLib/BaseUefiTianoDecompressLib.c b/EdkModulePkg/Library/BaseUefiTianoDecompressLib/BaseUefiTianoDecompressLib.c new file mode 100644 index 0000000000..bbf88f93e7 --- /dev/null +++ b/EdkModulePkg/Library/BaseUefiTianoDecompressLib/BaseUefiTianoDecompressLib.c @@ -0,0 +1,887 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + BaseUefiTianoDecompressLib.c + +Abstract: + + UEFI and Tiano Decompress Library + +--*/ + +// +// Decompression algorithm begins here +// +#define BITBUFSIZ 32 +#define MAXMATCH 256 +#define THRESHOLD 3 +#define CODE_BIT 16 +#define BAD_TABLE - 1 + +// +// C: Char&Len Set; P: Position Set; T: exTra Set +// +#define NC (0xff + MAXMATCH + 2 - THRESHOLD) +#define CBIT 9 +#define MAXPBIT 5 +#define TBIT 5 +#define MAXNP ((1U << MAXPBIT) - 1) +#define NT (CODE_BIT + 3) +#if NT > MAXNP +#define NPT NT +#else +#define NPT MAXNP +#endif + +typedef struct { + UINT8 *mSrcBase; // Starting address of compressed data + UINT8 *mDstBase; // Starting address of decompressed data + UINT32 mOutBuf; + UINT32 mInBuf; + + UINT16 mBitCount; + UINT32 mBitBuf; + UINT32 mSubBitBuf; + UINT16 mBlockSize; + UINT32 mCompSize; + UINT32 mOrigSize; + + UINT16 mBadTableFlag; + + UINT16 mLeft[2 * NC - 1]; + UINT16 mRight[2 * NC - 1]; + UINT8 mCLen[NC]; + UINT8 mPTLen[NPT]; + UINT16 mCTable[4096]; + UINT16 mPTTable[256]; + + // + // The length of the field 'Position Set Code Length Array Size' in Block Header. + // For EFI 1.1 de/compression algorithm, mPBit = 4 + // For Tiano de/compression algorithm, mPBit = 5 + // + UINT8 mPBit; +} SCRATCH_DATA; + +VOID +FillBuf ( + IN SCRATCH_DATA *Sd, + IN UINT16 NumOfBits + ) +/*++ + +Routine Description: + + Shift mBitBuf NumOfBits left. Read in NumOfBits of bits from source. + +Arguments: + + Sd - The global scratch data + NumOfBits - The number of bits to shift and read. + +Returns: (VOID) + +--*/ +{ + Sd->mBitBuf = (UINT32) (Sd->mBitBuf << NumOfBits); + + while (NumOfBits > Sd->mBitCount) { + + Sd->mBitBuf |= (UINT32) (Sd->mSubBitBuf << (NumOfBits = (UINT16) (NumOfBits - Sd->mBitCount))); + + if (Sd->mCompSize > 0) { + // + // Get 1 byte into SubBitBuf + // + Sd->mCompSize--; + Sd->mSubBitBuf = 0; + Sd->mSubBitBuf = Sd->mSrcBase[Sd->mInBuf++]; + Sd->mBitCount = 8; + + } else { + // + // No more bits from the source, just pad zero bit. + // + Sd->mSubBitBuf = 0; + Sd->mBitCount = 8; + + } + } + + Sd->mBitCount = (UINT16) (Sd->mBitCount - NumOfBits); + Sd->mBitBuf |= Sd->mSubBitBuf >> Sd->mBitCount; +} + +UINT32 +GetBits ( + IN SCRATCH_DATA *Sd, + IN UINT16 NumOfBits + ) +/*++ + +Routine Description: + + Get NumOfBits of bits out from mBitBuf. Fill mBitBuf with subsequent + NumOfBits of bits from source. Returns NumOfBits of bits that are + popped out. + +Arguments: + + Sd - The global scratch data. + NumOfBits - The number of bits to pop and read. + +Returns: + + The bits that are popped out. + +--*/ +{ + UINT32 OutBits; + + OutBits = (UINT32) (Sd->mBitBuf >> (BITBUFSIZ - NumOfBits)); + + FillBuf (Sd, NumOfBits); + + return OutBits; +} + +UINT16 +MakeTable ( + IN SCRATCH_DATA *Sd, + IN UINT16 NumOfChar, + IN UINT8 *BitLen, + IN UINT16 TableBits, + OUT UINT16 *Table + ) +/*++ + +Routine Description: + + Creates Huffman Code mapping table according to code length array. + +Arguments: + + Sd - The global scratch data + NumOfChar - Number of symbols in the symbol set + BitLen - Code length array + TableBits - The width of the mapping table + Table - The table + +Returns: + + 0 - OK. + BAD_TABLE - The table is corrupted. + +--*/ +{ + UINT16 Count[17]; + UINT16 Weight[17]; + UINT16 Start[18]; + UINT16 *Pointer; + UINT16 Index3; + volatile UINT16 Index; + UINT16 Len; + UINT16 Char; + UINT16 JuBits; + UINT16 Avail; + UINT16 NextCode; + UINT16 Mask; + + for (Index = 1; Index <= 16; Index++) { + Count[Index] = 0; + } + + for (Index = 0; Index < NumOfChar; Index++) { + Count[BitLen[Index]]++; + } + + Start[1] = 0; + + for (Index = 1; Index <= 16; Index++) { + Start[Index + 1] = (UINT16) (Start[Index] + (Count[Index] << (16 - Index))); + } + + if (Start[17] != 0) { + /*(1U << 16)*/ + return (UINT16) BAD_TABLE; + } + + JuBits = (UINT16) (16 - TableBits); + + for (Index = 1; Index <= TableBits; Index++) { + Start[Index] >>= JuBits; + Weight[Index] = (UINT16) (1U << (TableBits - Index)); + } + + while (Index <= 16) { + Weight[Index] = (UINT16) (1U << (16 - Index)); + Index++; + } + + Index = (UINT16) (Start[TableBits + 1] >> JuBits); + + if (Index != 0) { + Index3 = (UINT16) (1U << TableBits); + while (Index != Index3) { + Table[Index++] = 0; + } + } + + Avail = NumOfChar; + Mask = (UINT16) (1U << (15 - TableBits)); + + for (Char = 0; Char < NumOfChar; Char++) { + + Len = BitLen[Char]; + if (Len == 0) { + continue; + } + + NextCode = (UINT16) (Start[Len] + Weight[Len]); + + if (Len <= TableBits) { + + for (Index = Start[Len]; Index < NextCode; Index++) { + Table[Index] = Char; + } + + } else { + + Index3 = Start[Len]; + Pointer = &Table[Index3 >> JuBits]; + Index = (UINT16) (Len - TableBits); + + while (Index != 0) { + if (*Pointer == 0) { + Sd->mRight[Avail] = Sd->mLeft[Avail] = 0; + *Pointer = Avail++; + } + + if (Index3 & Mask) { + Pointer = &Sd->mRight[*Pointer]; + } else { + Pointer = &Sd->mLeft[*Pointer]; + } + + Index3 <<= 1; + Index--; + } + + *Pointer = Char; + + } + + Start[Len] = NextCode; + } + // + // Succeeds + // + return 0; +} + +UINT32 +DecodeP ( + IN SCRATCH_DATA *Sd + ) +/*++ + +Routine Description: + + Decodes a position value. + +Arguments: + + Sd - the global scratch data + +Returns: + + The position value decoded. + +--*/ +{ + UINT16 Val; + UINT32 Mask; + UINT32 Pos; + + Val = Sd->mPTTable[Sd->mBitBuf >> (BITBUFSIZ - 8)]; + + if (Val >= MAXNP) { + Mask = 1U << (BITBUFSIZ - 1 - 8); + + do { + + if (Sd->mBitBuf & Mask) { + Val = Sd->mRight[Val]; + } else { + Val = Sd->mLeft[Val]; + } + + Mask >>= 1; + } while (Val >= MAXNP); + } + // + // Advance what we have read + // + FillBuf (Sd, Sd->mPTLen[Val]); + + Pos = Val; + if (Val > 1) { + Pos = (UINT32) ((1U << (Val - 1)) + GetBits (Sd, (UINT16) (Val - 1))); + } + + return Pos; +} + +UINT16 +ReadPTLen ( + IN SCRATCH_DATA *Sd, + IN UINT16 nn, + IN UINT16 nbit, + IN UINT16 Special + ) +/*++ + +Routine Description: + + Reads code lengths for the Extra Set or the Position Set + +Arguments: + + Sd - The global scratch data + nn - Number of symbols + nbit - Number of bits needed to represent nn + Special - The special symbol that needs to be taken care of + +Returns: + + 0 - OK. + BAD_TABLE - Table is corrupted. + +--*/ +{ + UINT16 Number; + UINT16 CharC; + volatile UINT16 Index; + UINT32 Mask; + + Number = (UINT16) GetBits (Sd, nbit); + + if (Number == 0) { + CharC = (UINT16) GetBits (Sd, nbit); + + for (Index = 0; Index < 256; Index++) { + Sd->mPTTable[Index] = CharC; + } + + for (Index = 0; Index < nn; Index++) { + Sd->mPTLen[Index] = 0; + } + + return 0; + } + + Index = 0; + + while (Index < Number) { + + CharC = (UINT16) (Sd->mBitBuf >> (BITBUFSIZ - 3)); + + if (CharC == 7) { + Mask = 1U << (BITBUFSIZ - 1 - 3); + while (Mask & Sd->mBitBuf) { + Mask >>= 1; + CharC += 1; + } + } + + FillBuf (Sd, (UINT16) ((CharC < 7) ? 3 : CharC - 3)); + + Sd->mPTLen[Index++] = (UINT8) CharC; + + if (Index == Special) { + CharC = (UINT16) GetBits (Sd, 2); + while ((INT16) (--CharC) >= 0) { + Sd->mPTLen[Index++] = 0; + } + } + } + + while (Index < nn) { + Sd->mPTLen[Index++] = 0; + } + + return MakeTable (Sd, nn, Sd->mPTLen, 8, Sd->mPTTable); +} + +VOID +ReadCLen ( + SCRATCH_DATA *Sd + ) +/*++ + +Routine Description: + + Reads code lengths for Char&Len Set. + +Arguments: + + Sd - the global scratch data + +Returns: (VOID) + +--*/ +{ + UINT16 Number; + UINT16 CharC; + volatile UINT16 Index; + UINT32 Mask; + + Number = (UINT16) GetBits (Sd, CBIT); + + if (Number == 0) { + CharC = (UINT16) GetBits (Sd, CBIT); + + for (Index = 0; Index < NC; Index++) { + Sd->mCLen[Index] = 0; + } + + for (Index = 0; Index < 4096; Index++) { + Sd->mCTable[Index] = CharC; + } + + return ; + } + + Index = 0; + while (Index < Number) { + + CharC = Sd->mPTTable[Sd->mBitBuf >> (BITBUFSIZ - 8)]; + if (CharC >= NT) { + Mask = 1U << (BITBUFSIZ - 1 - 8); + + do { + + if (Mask & Sd->mBitBuf) { + CharC = Sd->mRight[CharC]; + } else { + CharC = Sd->mLeft[CharC]; + } + + Mask >>= 1; + + } while (CharC >= NT); + } + // + // Advance what we have read + // + FillBuf (Sd, Sd->mPTLen[CharC]); + + if (CharC <= 2) { + + if (CharC == 0) { + CharC = 1; + } else if (CharC == 1) { + CharC = (UINT16) (GetBits (Sd, 4) + 3); + } else if (CharC == 2) { + CharC = (UINT16) (GetBits (Sd, CBIT) + 20); + } + + while ((INT16) (--CharC) >= 0) { + Sd->mCLen[Index++] = 0; + } + + } else { + + Sd->mCLen[Index++] = (UINT8) (CharC - 2); + + } + } + + while (Index < NC) { + Sd->mCLen[Index++] = 0; + } + + MakeTable (Sd, NC, Sd->mCLen, 12, Sd->mCTable); + + return ; +} + +UINT16 +DecodeC ( + SCRATCH_DATA *Sd + ) +/*++ + +Routine Description: + + Decode a character/length value. + +Arguments: + + Sd - The global scratch data. + +Returns: + + The value decoded. + +--*/ +{ + UINT16 Index2; + UINT32 Mask; + + if (Sd->mBlockSize == 0) { + // + // Starting a new block + // + Sd->mBlockSize = (UINT16) GetBits (Sd, 16); + Sd->mBadTableFlag = ReadPTLen (Sd, NT, TBIT, 3); + if (Sd->mBadTableFlag != 0) { + return 0; + } + + ReadCLen (Sd); + + Sd->mBadTableFlag = ReadPTLen (Sd, MAXNP, Sd->mPBit, (UINT16) (-1)); + if (Sd->mBadTableFlag != 0) { + return 0; + } + } + + Sd->mBlockSize--; + Index2 = Sd->mCTable[Sd->mBitBuf >> (BITBUFSIZ - 12)]; + + if (Index2 >= NC) { + Mask = 1U << (BITBUFSIZ - 1 - 12); + + do { + if (Sd->mBitBuf & Mask) { + Index2 = Sd->mRight[Index2]; + } else { + Index2 = Sd->mLeft[Index2]; + } + + Mask >>= 1; + } while (Index2 >= NC); + } + // + // Advance what we have read + // + FillBuf (Sd, Sd->mCLen[Index2]); + + return Index2; +} + +VOID +Decode ( + SCRATCH_DATA *Sd + ) +/*++ + +Routine Description: + + Decode the source data and put the resulting data into the destination buffer. + +Arguments: + + Sd - The global scratch data + +Returns: (VOID) + + --*/ +{ + UINT16 BytesRemain; + UINT32 DataIdx; + UINT16 CharC; + + BytesRemain = (UINT16) (-1); + + DataIdx = 0; + + for (;;) { + CharC = DecodeC (Sd); + if (Sd->mBadTableFlag != 0) { + return ; + } + + if (CharC < 256) { + // + // Process an Original character + // + if (Sd->mOutBuf >= Sd->mOrigSize) { + return ; + } else { + Sd->mDstBase[Sd->mOutBuf++] = (UINT8) CharC; + } + + } else { + // + // Process a Pointer + // + CharC = (UINT16) (CharC - (UINT8_MAX + 1 - THRESHOLD)); + + BytesRemain = CharC; + + DataIdx = Sd->mOutBuf - DecodeP (Sd) - 1; + + BytesRemain--; + while ((INT16) (BytesRemain) >= 0) { + Sd->mDstBase[Sd->mOutBuf++] = Sd->mDstBase[DataIdx++]; + if (Sd->mOutBuf >= Sd->mOrigSize) { + return ; + } + + BytesRemain--; + } + } + } + + return ; +} + +RETURN_STATUS +EFIAPI +UefiDecompressGetInfo ( + IN CONST VOID *Source, + IN UINT32 SourceSize, + OUT UINT32 *DestinationSize, + OUT UINT32 *ScratchSize + ) +/*++ + +Routine Description: + + The internal implementation of *_DECOMPRESS_PROTOCOL.GetInfo(). + +Arguments: + + Source - The source buffer containing the compressed data. + SourceSize - The size of source buffer + DestinationSize - The size of destination buffer. + ScratchSize - The size of scratch buffer. + +Returns: + + RETURN_SUCCESS - The size of destination buffer and the size of scratch buffer are successull retrieved. + RETURN_INVALID_PARAMETER - The source data is corrupted + +--*/ +{ + UINT32 CompressedSize; + + ASSERT (Source != NULL); + ASSERT (DestinationSize != NULL); + ASSERT (ScratchSize != NULL); + + *ScratchSize = sizeof (SCRATCH_DATA); + + if (SourceSize < 8) { + return RETURN_INVALID_PARAMETER; + } + + CopyMem (&CompressedSize, Source, sizeof (UINT32)); + CopyMem (DestinationSize, (VOID *)((UINT8 *)Source + 4), sizeof (UINT32)); + + if (SourceSize < (CompressedSize + 8)) { + return RETURN_INVALID_PARAMETER; + } + + return RETURN_SUCCESS; +} + +RETURN_STATUS +EFIAPI +UefiTianoDecompress ( + IN CONST VOID *Source, + IN OUT VOID *Destination, + IN OUT VOID *Scratch, + IN UINT32 Version + ) +/*++ + +Routine Description: + + The internal implementation of *_DECOMPRESS_PROTOCOL.Decompress(). + +Arguments: + + Source - The source buffer containing the compressed data. + Destination - The destination buffer to store the decompressed data + Scratch - The buffer used internally by the decompress routine. This buffer is needed to store intermediate data. + Version - 1 for UEFI Decompress algoruthm, 2 for Tiano Decompess algorithm + +Returns: + + RETURN_SUCCESS - Decompression is successfull + RETURN_INVALID_PARAMETER - The source data is corrupted + +--*/ +{ + volatile UINT32 Index; + UINT32 CompSize; + UINT32 OrigSize; + SCRATCH_DATA *Sd; + CONST UINT8 *Src; + UINT8 *Dst; + + ASSERT (Source != NULL); + ASSERT (Destination != NULL); + ASSERT (Scratch != NULL); + + Src = Source; + Dst = Destination; + + Sd = (SCRATCH_DATA *) Scratch; + + CompSize = Src[0] + (Src[1] << 8) + (Src[2] << 16) + (Src[3] << 24); + OrigSize = Src[4] + (Src[5] << 8) + (Src[6] << 16) + (Src[7] << 24); + + // + // If compressed file size is 0, return + // + if (OrigSize == 0) { + return RETURN_SUCCESS; + } + + Src = Src + 8; + + for (Index = 0; Index < sizeof (SCRATCH_DATA); Index++) { + ((UINT8 *) Sd)[Index] = 0; + } + // + // The length of the field 'Position Set Code Length Array Size' in Block Header. + // For EFI 1.1 de/compression algorithm(Version 1), mPBit = 4 + // For Tiano de/compression algorithm(Version 2), mPBit = 5 + // + switch (Version) { + case 1 : + Sd->mPBit = 4; + break; + case 2 : + Sd->mPBit = 5; + break; + default: + ASSERT (FALSE); + } + Sd->mSrcBase = (UINT8 *)Src; + Sd->mDstBase = Dst; + Sd->mCompSize = CompSize; + Sd->mOrigSize = OrigSize; + + // + // Fill the first BITBUFSIZ bits + // + FillBuf (Sd, BITBUFSIZ); + + // + // Decompress it + // + Decode (Sd); + + if (Sd->mBadTableFlag != 0) { + // + // Something wrong with the source + // + return RETURN_INVALID_PARAMETER; + } + + return RETURN_SUCCESS; +} + +RETURN_STATUS +EFIAPI +UefiDecompress ( + IN CONST VOID *Source, + IN OUT VOID *Destination, + IN OUT VOID *Scratch + ) +/*++ + +Routine Description: + + The internal implementation of *_DECOMPRESS_PROTOCOL.Decompress(). + +Arguments: + + Source - The source buffer containing the compressed data. + Destination - The destination buffer to store the decompressed data + Scratch - The buffer used internally by the decompress routine. This buffer is needed to store intermediate data. + +Returns: + + RETURN_SUCCESS - Decompression is successfull + RETURN_INVALID_PARAMETER - The source data is corrupted + +--*/ +{ + return UefiTianoDecompress (Source, Destination, Scratch, 1); +} + +RETURN_STATUS +EFIAPI +TianoDecompressGetInfo ( + IN CONST VOID *Source, + IN UINT32 SourceSize, + OUT UINT32 *DestinationSize, + OUT UINT32 *ScratchSize + ) +/*++ + +Routine Description: + + The internal implementation of *_DECOMPRESS_PROTOCOL.GetInfo(). + +Arguments: + + Source - The source buffer containing the compressed data. + SourceSize - The size of source buffer + DestinationSize - The size of destination buffer. + ScratchSize - The size of scratch buffer. + +Returns: + + RETURN_SUCCESS - The size of destination buffer and the size of scratch buffer are successull retrieved. + RETURN_INVALID_PARAMETER - The source data is corrupted + +--*/ +{ + return UefiDecompressGetInfo (Source, SourceSize, DestinationSize, ScratchSize); +} + +RETURN_STATUS +EFIAPI +TianoDecompress ( + IN CONST VOID *Source, + IN OUT VOID *Destination, + IN OUT VOID *Scratch + ) +/*++ + +Routine Description: + + The internal implementation of *_DECOMPRESS_PROTOCOL.Decompress(). + +Arguments: + + Source - The source buffer containing the compressed data. + Destination - The destination buffer to store the decompressed data + Scratch - The buffer used internally by the decompress routine. This buffer is needed to store intermediate data. + +Returns: + + RETURN_SUCCESS - Decompression is successfull + RETURN_INVALID_PARAMETER - The source data is corrupted + +--*/ +{ + return UefiTianoDecompress (Source, Destination, Scratch, 2); +} diff --git a/EdkModulePkg/Library/BaseUefiTianoDecompressLib/BaseUefiTianoDecompressLib.mbd b/EdkModulePkg/Library/BaseUefiTianoDecompressLib/BaseUefiTianoDecompressLib.mbd new file mode 100644 index 0000000000..684d8e635d --- /dev/null +++ b/EdkModulePkg/Library/BaseUefiTianoDecompressLib/BaseUefiTianoDecompressLib.mbd @@ -0,0 +1,30 @@ + + + + + BaseUefiTianoDecompressLib + d774c4d9-c121-4da3-a5e2-0f317e3c630c + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:18 + + diff --git a/EdkModulePkg/Library/BaseUefiTianoDecompressLib/BaseUefiTianoDecompressLib.msa b/EdkModulePkg/Library/BaseUefiTianoDecompressLib/BaseUefiTianoDecompressLib.msa new file mode 100644 index 0000000000..89d574e180 --- /dev/null +++ b/EdkModulePkg/Library/BaseUefiTianoDecompressLib/BaseUefiTianoDecompressLib.msa @@ -0,0 +1,47 @@ + + + + + BaseUefiTianoDecompressLib + BASE + LIBRARY + d774c4d9-c121-4da3-a5e2-0f317e3c630c + 0 + Component description file for the entry point to a EFIDXE Drivers + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:18 + + + UefiDecompressLib + TianoDecompressLib + DebugLib + BaseMemoryLib + + + BaseUefiTianoDecompressLib.c + + + MdePkg + EdkModulePkg + + diff --git a/EdkModulePkg/Library/BaseUefiTianoDecompressLib/build.xml b/EdkModulePkg/Library/BaseUefiTianoDecompressLib/build.xml new file mode 100644 index 0000000000..9b8695b963 --- /dev/null +++ b/EdkModulePkg/Library/BaseUefiTianoDecompressLib/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Library/DxeCoreCustomDecompressLibFromHob/DxeCoreCustomDecompressLibFromHob.c b/EdkModulePkg/Library/DxeCoreCustomDecompressLibFromHob/DxeCoreCustomDecompressLibFromHob.c new file mode 100644 index 0000000000..300cc91fed --- /dev/null +++ b/EdkModulePkg/Library/DxeCoreCustomDecompressLibFromHob/DxeCoreCustomDecompressLibFromHob.c @@ -0,0 +1,105 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DxeCoreCustomDecompressLibFromHob.c + +Abstract: + + Custom Decompress Library from HOBs + +--*/ + +static DECOMPRESS_LIBRARY mCustomDecompress; + +EFI_STATUS +DxeCoreCustomDecompressLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + EFI_HOB_GUID_TYPE *GuidHob; + + GuidHob = GetFirstGuidHob (&gEfiCustomizedDecompressProtocolGuid); + ASSERT (GuidHob != NULL); + CopyMem (&mCustomDecompress, GET_GUID_HOB_DATA (GuidHob), sizeof (mCustomDecompress)); + return EFI_SUCCESS; +} + +RETURN_STATUS +EFIAPI +CustomDecompressGetInfo ( + IN CONST VOID *Source, + IN UINT32 SourceSize, + OUT UINT32 *DestinationSize, + OUT UINT32 *ScratchSize + ) +/*++ + +Routine Description: + + The internal implementation of *_DECOMPRESS_PROTOCOL.GetInfo(). + +Arguments: + + Source - The source buffer containing the compressed data. + SourceSize - The size of source buffer + DestinationSize - The size of destination buffer. + ScratchSize - The size of scratch buffer. + +Returns: + + RETURN_SUCCESS - The size of destination buffer and the size of scratch buffer are successull retrieved. + RETURN_INVALID_PARAMETER - The source data is corrupted + +--*/ +{ + return mCustomDecompress.GetInfo (Source, SourceSize, DestinationSize, ScratchSize); +} + +RETURN_STATUS +EFIAPI +CustomDecompress ( + IN CONST VOID *Source, + IN OUT VOID *Destination, + IN OUT VOID *Scratch + ) +/*++ + +Routine Description: + + The internal implementation of *_DECOMPRESS_PROTOCOL.Decompress(). + +Arguments: + + Source - The source buffer containing the compressed data. + Destination - The destination buffer to store the decompressed data + Scratch - The buffer used internally by the decompress routine. This buffer is needed to store intermediate data. + +Returns: + + RETURN_SUCCESS - Decompression is successfull + RETURN_INVALID_PARAMETER - The source data is corrupted + +--*/ +{ + return mCustomDecompress.Decompress (Source, Destination, Scratch); +} diff --git a/EdkModulePkg/Library/DxeCoreCustomDecompressLibFromHob/DxeCoreCustomDecompressLibFromHob.mbd b/EdkModulePkg/Library/DxeCoreCustomDecompressLibFromHob/DxeCoreCustomDecompressLibFromHob.mbd new file mode 100644 index 0000000000..f183e5aa15 --- /dev/null +++ b/EdkModulePkg/Library/DxeCoreCustomDecompressLibFromHob/DxeCoreCustomDecompressLibFromHob.mbd @@ -0,0 +1,30 @@ + + + + + DxeCoreCustomDecompressLibFromHob + 942e0182-3e1d-47f9-92dc-4939d1a0ba00 + EDK_RELEASE_VERSION 0x00020000 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-31 13:07 + + diff --git a/EdkModulePkg/Library/DxeCoreCustomDecompressLibFromHob/DxeCoreCustomDecompressLibFromHob.msa b/EdkModulePkg/Library/DxeCoreCustomDecompressLibFromHob/DxeCoreCustomDecompressLibFromHob.msa new file mode 100644 index 0000000000..e135047315 --- /dev/null +++ b/EdkModulePkg/Library/DxeCoreCustomDecompressLibFromHob/DxeCoreCustomDecompressLibFromHob.msa @@ -0,0 +1,55 @@ + + + + + DxeCoreCustomDecompressLibFromHob + DXE_CORE + LIBRARY + 942e0182-3e1d-47f9-92dc-4939d1a0ba00 + EDK_RELEASE_VERSION 0x00020000 + Component description file for the entry point to a EFIDXE Drivers + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + EFI_SPECIFICATION_VERSION 0x00000000 + 2006-03-12 17:09 + 2006-03-31 13:07 + + + CustomDecompressLib + DebugLib + HobLib + BaseMemoryLib + + + DxeCoreCustomDecompressLibFromHob.c + + + MdePkg + EdkModulePkg + + + CustomizedDecompress + + + + DxeCoreCustomDecompressLibConstructor + + + diff --git a/EdkModulePkg/Library/DxeCoreCustomDecompressLibFromHob/build.xml b/EdkModulePkg/Library/DxeCoreCustomDecompressLibFromHob/build.xml new file mode 100644 index 0000000000..c8fb0f7cd6 --- /dev/null +++ b/EdkModulePkg/Library/DxeCoreCustomDecompressLibFromHob/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c b/EdkModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c new file mode 100644 index 0000000000..c75ab851f7 --- /dev/null +++ b/EdkModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c @@ -0,0 +1,623 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DxeCorePerformance.c + +Abstract: + + Support for measurement of DXE performance + +--*/ + +// +// Interface declarations for Performance Protocol. +// +/** + 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 EFI_SUCCESS The data was read correctly from the device. + @retval EFI_OUT_OF_RESOURCES There are not enough resources to record the measurement. + +**/ +EFI_STATUS +EFIAPI +StartGauge ( + 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 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 EFI_SUCCESS The end of the measurement was recorded. + @retval EFI_NOT_FOUND The specified measurement record could not be found. + +**/ +EFI_STATUS +EFIAPI +EndGauge ( + IN CONST VOID *Handle, OPTIONAL + IN CONST CHAR8 *Token, OPTIONAL + IN CONST CHAR8 *Module, OPTIONAL + IN UINT64 TimeStamp + ); + +/** + Retrieves a previously logged performance measurement. + + 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 The indirect pointer to the gauge data entry specified by LogEntryKey + if the retrieval is successful. + + @retval EFI_SUCCESS The GuageDataEntry is successfuly found based on LogEntryKey. + @retval EFI_NOT_FOUND The LogEntryKey is the last entry (equals to the total entry number). + @retval EFI_INVALIDE_PARAMETER The LogEntryKey is not a valid entry (greater than the total entry number). + @retval EFI_INVALIDE_PARAMETER GaugeDataEntry is NULL. + +**/ +EFI_STATUS +EFIAPI +GetGauge ( + IN UINTN LogEntryKey, + OUT GAUGE_DATA_ENTRY **GaugeDataEntry + ); + +// +// Definition for global variables. +// +STATIC GAUGE_DATA_HEADER *mGaugeData; +STATIC UINT32 mMaxGaugeRecords; + +PERFORMANCE_PROTOCOL PerformanceInterface = { + StartGauge, + EndGauge, + GetGauge + }; + + +/** + Searches in the gauge array with keyword Handle, Token and Module. + + This internal function searches for the gauge entry in the gauge array. + If there is an entry that exactly matches the given key word triple + and its end time stamp is zero, then the index of that gauge entry is returned; + otherwise, the the number of gauge entries in the array is returned. + + @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. + + @retval The index of gauge entry in the array. + +**/ +UINT32 +InternalSearchForGaugeEntry ( + IN CONST VOID *Handle, OPTIONAL + IN CONST CHAR8 *Token, OPTIONAL + IN CONST CHAR8 *Module OPTIONAL + ) +{ + UINT32 Index; + UINT32 NumberOfEntries; + GAUGE_DATA_ENTRY *GaugeEntryArray; + + if (Token == NULL) { + Token = ""; + } + if (Module == NULL) { + Module = ""; + } + + NumberOfEntries = mGaugeData->NumberOfEntries; + GaugeEntryArray = (GAUGE_DATA_ENTRY *) (mGaugeData + 1); + + for (Index = 0; Index < NumberOfEntries; Index++) { + if ((GaugeEntryArray[Index].Handle == (EFI_PHYSICAL_ADDRESS) (UINTN) Handle) && + AsciiStrnCmp (GaugeEntryArray[Index].Token, Token, PEI_PERFORMANCE_STRING_LENGTH) == 0 && + AsciiStrnCmp (GaugeEntryArray[Index].Module, Module, PEI_PERFORMANCE_STRING_LENGTH) == 0 && + GaugeEntryArray[Index].EndTimeStamp == 0 + ) { + break; + } + } + + return Index; +} + +/** + 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 EFI_SUCCESS The data was read correctly from the device. + @retval EFI_OUT_OF_RESOURCES There are not enough resources to record the measurement. + +**/ +EFI_STATUS +EFIAPI +StartGauge ( + IN CONST VOID *Handle, OPTIONAL + IN CONST CHAR8 *Token, OPTIONAL + IN CONST CHAR8 *Module, OPTIONAL + IN UINT64 TimeStamp + ) +{ + GAUGE_DATA_ENTRY *GaugeEntryArray; + UINTN GaugeDataSize; + UINTN OldGaugeDataSize; + GAUGE_DATA_HEADER *OldGaugeData; + EFI_STATUS Status; + UINT32 Index; + + Index = mGaugeData->NumberOfEntries; + if (Index >= mMaxGaugeRecords) { + // + // Try to enlarge the scale of gauge arrary. + // + OldGaugeData = mGaugeData; + OldGaugeDataSize = sizeof (GAUGE_DATA_HEADER) + sizeof (GAUGE_DATA_ENTRY) * mMaxGaugeRecords; + mMaxGaugeRecords *= 2; + GaugeDataSize = sizeof (GAUGE_DATA_HEADER) + sizeof (GAUGE_DATA_ENTRY) * mMaxGaugeRecords; + Status = gBS->AllocatePool ( + EfiBootServicesData, + GaugeDataSize, + (VOID **) &mGaugeData + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Initialize new data arry and migrate old data one. + // + mGaugeData = ZeroMem (mGaugeData, GaugeDataSize); + mGaugeData = CopyMem (mGaugeData, OldGaugeData, OldGaugeDataSize); + + gBS->FreePool (OldGaugeData); + } + + GaugeEntryArray = (GAUGE_DATA_ENTRY *) (mGaugeData + 1); + GaugeEntryArray[Index].Handle = (EFI_PHYSICAL_ADDRESS) (UINTN) Handle; + + if (Token != NULL) { + AsciiStrnCpy (GaugeEntryArray[Index].Token, Token, DXE_PERFORMANCE_STRING_LENGTH); + } + if (Module != NULL) { + AsciiStrnCpy (GaugeEntryArray[Index].Module, Module, DXE_PERFORMANCE_STRING_LENGTH); + } + + if (TimeStamp == 0) { + TimeStamp = GetPerformanceCounter (); + } + GaugeEntryArray[Index].StartTimeStamp = TimeStamp; + + mGaugeData->NumberOfEntries++; + + return EFI_SUCCESS; +} + +/** + 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 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 EFI_SUCCESS The end of the measurement was recorded. + @retval EFI_NOT_FOUND The specified measurement record could not be found. + +**/ +EFI_STATUS +EFIAPI +EndGauge ( + IN CONST VOID *Handle, OPTIONAL + IN CONST CHAR8 *Token, OPTIONAL + IN CONST CHAR8 *Module, OPTIONAL + IN UINT64 TimeStamp + ) +{ + GAUGE_DATA_ENTRY *GaugeEntryArray; + UINT32 Index; + + if (TimeStamp == 0) { + TimeStamp = GetPerformanceCounter (); + } + + Index = InternalSearchForGaugeEntry (Handle, Token, Module); + if (Index >= mGaugeData->NumberOfEntries) { + return EFI_NOT_FOUND; + } + GaugeEntryArray = (GAUGE_DATA_ENTRY *) (mGaugeData + 1); + GaugeEntryArray[Index].EndTimeStamp = TimeStamp; + + return EFI_SUCCESS; +} + +/** + Retrieves a previously logged performance measurement. + + 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 The indirect pointer to the gauge data entry specified by LogEntryKey + if the retrieval is successful. + + @retval EFI_SUCCESS The GuageDataEntry is successfuly found based on LogEntryKey. + @retval EFI_NOT_FOUND The LogEntryKey is the last entry (equals to the total entry number). + @retval EFI_INVALIDE_PARAMETER The LogEntryKey is not a valid entry (greater than the total entry number). + @retval EFI_INVALIDE_PARAMETER GaugeDataEntry is NULL. + +**/ +EFI_STATUS +EFIAPI +GetGauge ( + IN UINTN LogEntryKey, + OUT GAUGE_DATA_ENTRY **GaugeDataEntry + ) +{ + UINTN NumberOfEntries; + GAUGE_DATA_ENTRY *LogEntryArray; + + NumberOfEntries = (UINTN) (mGaugeData->NumberOfEntries); + if (LogEntryKey > NumberOfEntries) { + return EFI_INVALID_PARAMETER; + } + if (LogEntryKey == NumberOfEntries) { + return EFI_NOT_FOUND; + } + + LogEntryArray = (GAUGE_DATA_ENTRY *) (mGaugeData + 1); + + if (GaugeDataEntry == NULL) { + return EFI_INVALID_PARAMETER; + } + *GaugeDataEntry = &LogEntryArray[LogEntryKey]; + + return EFI_SUCCESS; +} + +/** + Dumps all the PEI performance log to DXE performance gauge array. + + 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 + ) +{ + EFI_HOB_GUID_TYPE *GuidHob; + PEI_PERFORMANCE_LOG_HEADER *LogHob; + PEI_PERFORMANCE_LOG_ENTRY *LogEntryArray; + GAUGE_DATA_ENTRY *GaugeEntryArray; + UINT32 Index; + UINT32 NumberOfEntries; + + NumberOfEntries = 0; + GaugeEntryArray = (GAUGE_DATA_ENTRY *) (mGaugeData + 1); + + // + // Dump PEI Log Entries to DXE Guage Data structure. + // + GuidHob = GetFirstGuidHob (&gPeiPerformanceHobGuid); + if (GuidHob != NULL) { + LogHob = GET_GUID_HOB_DATA (GuidHob); + LogEntryArray = (PEI_PERFORMANCE_LOG_ENTRY *) (LogHob + 1); + GaugeEntryArray = (GAUGE_DATA_ENTRY *) (mGaugeData + 1); + + NumberOfEntries = LogHob->NumberOfEntries; + for (Index = 0; Index < NumberOfEntries; Index++) { + GaugeEntryArray[Index].Handle = LogEntryArray[Index].Handle; + AsciiStrnCpy (GaugeEntryArray[Index].Token, LogEntryArray[Index].Token, DXE_PERFORMANCE_STRING_LENGTH); + AsciiStrnCpy (GaugeEntryArray[Index].Module, LogEntryArray[Index].Module, DXE_PERFORMANCE_STRING_LENGTH); + GaugeEntryArray[Index].StartTimeStamp = LogEntryArray[Index].StartTimeStamp; + GaugeEntryArray[Index].EndTimeStamp = LogEntryArray[Index].EndTimeStamp; + } + } + mGaugeData->NumberOfEntries = NumberOfEntries; +} + +/** + The constructor function initializes Performance infrastructure for DXE phase. + + The constructor function publishes Performance 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; + UINTN GaugeDataSize; + + // + // Install the protocol interfaces. + // + Handle = NULL; + Status = gBS->InstallProtocolInterface ( + &Handle, + &gPerformanceProtocolGuid, + EFI_NATIVE_INTERFACE, + &PerformanceInterface + ); + ASSERT_EFI_ERROR (Status); + + mMaxGaugeRecords = INIT_DXE_GAUGE_DATA_ENTRIES + MAX_PEI_PERFORMANCE_LOG_ENTRIES; + GaugeDataSize = sizeof (GAUGE_DATA_HEADER) + sizeof (GAUGE_DATA_ENTRY) * mMaxGaugeRecords; + Status = gBS->AllocatePool ( + EfiBootServicesData, + GaugeDataSize, + (VOID **) &mGaugeData + ); + ASSERT_EFI_ERROR (Status); + + ZeroMem (mGaugeData, GaugeDataSize); + + InternalGetPeiPerformance (); + + 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, 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 + ) +{ + EFI_STATUS Status; + + Status = StartGauge (Handle, Token, Module, TimeStamp); + return (RETURN_STATUS) Status; +} + +/** + 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 + ) +{ + EFI_STATUS Status; + + Status = EndGauge (Handle, Token, Module, TimeStamp); + return (RETURN_STATUS) Status; +} + +/** + Retrieves a previously logged performance measurement. + + Retrieves the performance log entry from the performance log + that immediately follows the log entry specified by LogEntryKey. + If LogEntryKey is zero, then the first entry from the performance log is returned. + If the log entry specified by LogEntryKey is the last entry in the performance log, + then 0 is returned. Otherwise, the performance log entry is returned in Handle, + Token, Module, StartTimeStamp, and EndTimeStamp. + The key for the current performance log entry is returned. + + @param LogEntryKey The key for the previous performance measurement log entry. + If 0, then the first performance measurement log entry is retrieved. + @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 The 64-bit time stamp that was recorded when the measurement was started. + @param EndTimeStamp The 64-bit time stamp that was recorded when the measurement was ended. + + @return The key for the current performance log entry. + +**/ +UINTN +EFIAPI +GetPerformanceMeasurement ( + UINTN LogEntryKey, + OUT CONST VOID **Handle, + OUT CONST CHAR8 **Token, + OUT CONST CHAR8 **Module, + OUT UINT64 *StartTimeStamp, + OUT UINT64 *EndTimeStamp + ) +{ + EFI_STATUS Status; + GAUGE_DATA_ENTRY *GaugeData; + + ASSERT (Handle != NULL); + ASSERT (Token != NULL); + ASSERT (Module != NULL); + ASSERT (StartTimeStamp != NULL); + ASSERT (EndTimeStamp != NULL); + + Status = GetGauge (LogEntryKey++, &GaugeData); + + // + // Make sure that LogEntryKey is a valid log entry key, + // + ASSERT (Status != EFI_INVALID_PARAMETER); + + if (EFI_ERROR (Status)) { + // + // The LogEntryKey is the last entry (equals to the total entry number). + // + return 0; + } + + ASSERT (GaugeData != NULL); + + *Handle = (VOID *) (UINTN) GaugeData->Handle; + *Token = GaugeData->Token; + *Module = GaugeData->Module; + *StartTimeStamp = GaugeData->StartTimeStamp; + *EndTimeStamp = GaugeData->EndTimeStamp; + + return LogEntryKey; +} + +/** + 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 ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0); +} diff --git a/EdkModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.mbd b/EdkModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.mbd new file mode 100644 index 0000000000..a8f235f65b --- /dev/null +++ b/EdkModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.mbd @@ -0,0 +1,29 @@ + + + + + DxeCorePerformanceLib + D0F78BBF-0A30-4c63-8A48-0F618A4AFACD + EDK_RELEASE_VERSION 0x00020000 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-04-04 11:10 + + diff --git a/EdkModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.msa b/EdkModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.msa new file mode 100644 index 0000000000..40ce308449 --- /dev/null +++ b/EdkModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.msa @@ -0,0 +1,70 @@ + + + + + DxeCorePerformanceLib + DXE_CORE + LIBRARY + D0F78BBF-0A30-4c63-8A48-0F618A4AFACD + EDK_RELEASE_VERSION 0x00020000 + Component description file for the Tiano Decompress Library + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + EFI_SPECIFICATION_VERSION 0x00000000 + 2006-04-04 11:10 + + + PerformanceLib + DebugLib + HobLib + BaseLib + BaseMemoryLib + TimerLib + PcdLib + UefiBootServicesTableLib + + + DxeCorePerformanceLib.c + + + MdePkg + EdkModulePkg + + + Performance + + + + PeiPerformanceHob + + + + + DxeCorePerformanceLibConstructor + + + + + PcdPerformanceLibraryPropertyMask + 0x00000001 + UINT8 + + + diff --git a/EdkModulePkg/Library/DxeCorePerformanceLib/build.xml b/EdkModulePkg/Library/DxeCorePerformanceLib/build.xml new file mode 100644 index 0000000000..b9d04eed7b --- /dev/null +++ b/EdkModulePkg/Library/DxeCorePerformanceLib/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Library/DxeCoreTianoDecompressLibFromHob/DxeCoreTianoDecompressLibFromHob.c b/EdkModulePkg/Library/DxeCoreTianoDecompressLibFromHob/DxeCoreTianoDecompressLibFromHob.c new file mode 100644 index 0000000000..1bb832be02 --- /dev/null +++ b/EdkModulePkg/Library/DxeCoreTianoDecompressLibFromHob/DxeCoreTianoDecompressLibFromHob.c @@ -0,0 +1,106 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DxeCoreTianoDecompressLibFromHob.c + +Abstract: + + Tiano Decompress Library from HOBs + +--*/ + +static DECOMPRESS_LIBRARY mTianoDecompress; + +EFI_STATUS +DxeCoreTianoDecompressLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + EFI_HOB_GUID_TYPE *GuidHob; + + GuidHob = GetFirstGuidHob (&gEfiTianoDecompressProtocolGuid); + ASSERT (GuidHob != NULL); + CopyMem (&mTianoDecompress, GET_GUID_HOB_DATA (GuidHob), sizeof (mTianoDecompress)); + return EFI_SUCCESS; +} + +RETURN_STATUS +EFIAPI +TianoDecompressGetInfo ( + IN CONST VOID *Source, + IN UINT32 SourceSize, + OUT UINT32 *DestinationSize, + OUT UINT32 *ScratchSize + ) +/*++ + +Routine Description: + + The internal implementation of *_DECOMPRESS_PROTOCOL.GetInfo(). + +Arguments: + + Source - The source buffer containing the compressed data. + SourceSize - The size of source buffer + DestinationSize - The size of destination buffer. + ScratchSize - The size of scratch buffer. + +Returns: + + RETURN_SUCCESS - The size of destination buffer and the size of scratch buffer are successull retrieved. + RETURN_INVALID_PARAMETER - The source data is corrupted + +--*/ +{ + return mTianoDecompress.GetInfo (Source, SourceSize, DestinationSize, ScratchSize); +} + +RETURN_STATUS +EFIAPI +TianoDecompress ( + IN CONST VOID *Source, + IN OUT VOID *Destination, + IN OUT VOID *Scratch + ) +/*++ + +Routine Description: + + The internal implementation of *_DECOMPRESS_PROTOCOL.Decompress(). + +Arguments: + + Source - The source buffer containing the compressed data. + Destination - The destination buffer to store the decompressed data + Scratch - The buffer used internally by the decompress routine. This buffer is needed to store intermediate data. + +Returns: + + RETURN_SUCCESS - Decompression is successfull + RETURN_INVALID_PARAMETER - The source data is corrupted + +--*/ +{ + return mTianoDecompress.Decompress (Source, Destination, Scratch); +} + diff --git a/EdkModulePkg/Library/DxeCoreTianoDecompressLibFromHob/DxeCoreTianoDecompressLibFromHob.mbd b/EdkModulePkg/Library/DxeCoreTianoDecompressLibFromHob/DxeCoreTianoDecompressLibFromHob.mbd new file mode 100644 index 0000000000..f3ca9a4321 --- /dev/null +++ b/EdkModulePkg/Library/DxeCoreTianoDecompressLibFromHob/DxeCoreTianoDecompressLibFromHob.mbd @@ -0,0 +1,30 @@ + + + + + DxeCoreTianoDecompressLibFromHob + cef487a1-751d-4fe0-a39b-e6892b4610c8 + EDK_RELEASE_VERSION 0x00020000 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-31 13:10 + + diff --git a/EdkModulePkg/Library/DxeCoreTianoDecompressLibFromHob/DxeCoreTianoDecompressLibFromHob.msa b/EdkModulePkg/Library/DxeCoreTianoDecompressLibFromHob/DxeCoreTianoDecompressLibFromHob.msa new file mode 100644 index 0000000000..bf49ef5644 --- /dev/null +++ b/EdkModulePkg/Library/DxeCoreTianoDecompressLibFromHob/DxeCoreTianoDecompressLibFromHob.msa @@ -0,0 +1,55 @@ + + + + + DxeCoreTianoDecompressLibFromHob + DXE_CORE + LIBRARY + cef487a1-751d-4fe0-a39b-e6892b4610c8 + EDK_RELEASE_VERSION 0x00020000 + Component description file for the entry point to a EFIDXE Drivers + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + EFI_SPECIFICATION_VERSION 0x00000000 + 2006-03-12 17:09 + 2006-03-31 13:10 + + + TianoDecompressLib + DebugLib + HobLib + BaseMemoryLib + + + DxeCoreTianoDecompressLibFromHob.c + + + MdePkg + EdkModulePkg + + + TianoDecompress + + + + DxeCoreTianoDecompressLibConstructor + + + diff --git a/EdkModulePkg/Library/DxeCoreTianoDecompressLibFromHob/build.xml b/EdkModulePkg/Library/DxeCoreTianoDecompressLibFromHob/build.xml new file mode 100644 index 0000000000..095b92e284 --- /dev/null +++ b/EdkModulePkg/Library/DxeCoreTianoDecompressLibFromHob/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Library/DxeCoreUefiDecompressLibFromHob/DxeCoreUefiDecompressLibFromHob.c b/EdkModulePkg/Library/DxeCoreUefiDecompressLibFromHob/DxeCoreUefiDecompressLibFromHob.c new file mode 100644 index 0000000000..b4bd539975 --- /dev/null +++ b/EdkModulePkg/Library/DxeCoreUefiDecompressLibFromHob/DxeCoreUefiDecompressLibFromHob.c @@ -0,0 +1,105 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DxeCoreUefiDecompressLibFromHob.c + +Abstract: + + UEFI Decompress Library from HOBs + +--*/ + +static DECOMPRESS_LIBRARY mEfiDecompress; + +EFI_STATUS +DxeCoreUefiDecompressLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + EFI_HOB_GUID_TYPE *GuidHob; + + GuidHob = GetFirstGuidHob (&gEfiDecompressProtocolGuid); + ASSERT (GuidHob != NULL); + CopyMem (&mEfiDecompress, GET_GUID_HOB_DATA (GuidHob), sizeof (mEfiDecompress)); + return EFI_SUCCESS; +} + +RETURN_STATUS +EFIAPI +UefiDecompressGetInfo ( + IN CONST VOID *Source, + IN UINT32 SourceSize, + OUT UINT32 *DestinationSize, + OUT UINT32 *ScratchSize + ) +/*++ + +Routine Description: + + The internal implementation of *_DECOMPRESS_PROTOCOL.GetInfo(). + +Arguments: + + Source - The source buffer containing the compressed data. + SourceSize - The size of source buffer + DestinationSize - The size of destination buffer. + ScratchSize - The size of scratch buffer. + +Returns: + + RETURN_SUCCESS - The size of destination buffer and the size of scratch buffer are successull retrieved. + RETURN_INVALID_PARAMETER - The source data is corrupted + +--*/ +{ + return mEfiDecompress.GetInfo (Source, SourceSize, DestinationSize, ScratchSize); +} + +RETURN_STATUS +EFIAPI +UefiDecompress ( + IN CONST VOID *Source, + IN OUT VOID *Destination, + IN OUT VOID *Scratch + ) +/*++ + +Routine Description: + + The internal implementation of *_DECOMPRESS_PROTOCOL.Decompress(). + +Arguments: + + Source - The source buffer containing the compressed data. + Destination - The destination buffer to store the decompressed data + Scratch - The buffer used internally by the decompress routine. This buffer is needed to store intermediate data. + +Returns: + + RETURN_SUCCESS - Decompression is successfull + RETURN_INVALID_PARAMETER - The source data is corrupted + +--*/ +{ + return mEfiDecompress.Decompress (Source, Destination, Scratch); +} diff --git a/EdkModulePkg/Library/DxeCoreUefiDecompressLibFromHob/DxeCoreUefiDecompressLibFromHob.mbd b/EdkModulePkg/Library/DxeCoreUefiDecompressLibFromHob/DxeCoreUefiDecompressLibFromHob.mbd new file mode 100644 index 0000000000..5bb0b9344d --- /dev/null +++ b/EdkModulePkg/Library/DxeCoreUefiDecompressLibFromHob/DxeCoreUefiDecompressLibFromHob.mbd @@ -0,0 +1,30 @@ + + + + + DxeCoreUefiDecompressLibFromHob + 5c12c06f-5cf8-48a6-9860-6c5b2c036bbf + EDK_RELEASE_VERSION 0x00020000 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-31 13:10 + + diff --git a/EdkModulePkg/Library/DxeCoreUefiDecompressLibFromHob/DxeCoreUefiDecompressLibFromHob.msa b/EdkModulePkg/Library/DxeCoreUefiDecompressLibFromHob/DxeCoreUefiDecompressLibFromHob.msa new file mode 100644 index 0000000000..895b86c4ba --- /dev/null +++ b/EdkModulePkg/Library/DxeCoreUefiDecompressLibFromHob/DxeCoreUefiDecompressLibFromHob.msa @@ -0,0 +1,55 @@ + + + + + DxeCoreUefiDecompressLibFromHob + DXE_CORE + LIBRARY + 5c12c06f-5cf8-48a6-9860-6c5b2c036bbf + EDK_RELEASE_VERSION 0x00020000 + Component description file for the entry point to a EFIDXE Drivers + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + EFI_SPECIFICATION_VERSION 0x00000000 + 2006-03-12 17:09 + 2006-03-31 13:10 + + + UefiDecompressLib + DebugLib + HobLib + BaseMemoryLib + + + DxeCoreUefiDecompressLibFromHob.c + + + MdePkg + EdkModulePkg + + + Decompress + + + + DxeCoreUefiDecompressLibConstructor + + + diff --git a/EdkModulePkg/Library/DxeCoreUefiDecompressLibFromHob/build.xml b/EdkModulePkg/Library/DxeCoreUefiDecompressLibFromHob/build.xml new file mode 100644 index 0000000000..b46ad569f0 --- /dev/null +++ b/EdkModulePkg/Library/DxeCoreUefiDecompressLibFromHob/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Library/EdkDxeDebugLibReportStatusCode/DebugLib.c b/EdkModulePkg/Library/EdkDxeDebugLibReportStatusCode/DebugLib.c new file mode 100644 index 0000000000..5a7300faba --- /dev/null +++ b/EdkModulePkg/Library/EdkDxeDebugLibReportStatusCode/DebugLib.c @@ -0,0 +1,314 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DebugLib.c + +Abstract: + + EFI Debug Library + +--*/ + +static BOOLEAN mDebugLevelInstalled = FALSE; +static EFI_DEBUG_LEVEL_PROTOCOL mDebugLevel = { 0 }; + +EFI_STATUS +DebugLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + EFI_STATUS Status; + + // + // Initialize Debug Level Protocol + // + mDebugLevel.DebugLevel = PcdGet32(PcdDebugPrintErrorLevel); + + // + // Install Debug Level Protocol + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gEfiDebugLevelProtocolGuid, &mDebugLevel, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // + // Set flag to show that the Debug Level Protocol has been installed + // + mDebugLevelInstalled = TRUE; + + return EFI_SUCCESS; +} + +VOID +EFIAPI +DebugAssert ( + IN CHAR8 *FileName, + IN INTN LineNumber, + IN CHAR8 *Description + ) +/*++ + +Routine Description: + + Worker function for ASSERT(). If Error Logging hub is loaded log ASSERT + information. If Error Logging hub is not loaded CpuBreakpoint (). + + We use UINT64 buffers due to IPF alignment concerns. + +Arguments: + + FileName - File name of failing routine. + + LineNumber - Line number of failing ASSERT(). + + Description - Descritption, usally the assertion, + +Returns: + + None + +--*/ +{ + UINT64 Buffer[EFI_STATUS_CODE_DATA_MAX_SIZE / sizeof(UINT64)]; + EFI_DEBUG_ASSERT_DATA *AssertData; + UINTN TotalSize; + CHAR8 *Temp; + + if ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED) == 0) { + return; + } + + // + // Make sure it will all fit in the passed in buffer + // + TotalSize = sizeof (EFI_DEBUG_ASSERT_DATA) + AsciiStrLen (FileName) + 1 + AsciiStrLen (Description) + 1; + if (TotalSize <= EFI_STATUS_CODE_DATA_MAX_SIZE) { + // + // Fill in EFI_DEBUG_ASSERT_DATA + // + AssertData = (EFI_DEBUG_ASSERT_DATA *)Buffer; + AssertData->LineNumber = (UINT32)LineNumber; + + // + // Copy Ascii FileName including NULL. + // + Temp = AsciiStrCpy ((CHAR8 *)(AssertData + 1), FileName); + + // + // Copy Ascii Description + // + AsciiStrCpy (Temp + AsciiStrLen(FileName) + 1, Description); + + REPORT_STATUS_CODE_WITH_EXTENDED_DATA ( + (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED), + (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_ILLEGAL_SOFTWARE_STATE), + AssertData, + TotalSize + ); + } + + // + // Put break point in module that contained the error. + // + CpuBreakpoint (); +} + +VOID +DebugVPrint ( + IN UINTN ErrorLevel, + IN CHAR8 *Format, + IN VA_LIST Marker + ) +/*++ + +Routine Description: + + Worker function for DEBUG(). If Error Logging hub is loaded log ASSERT + information. If Error Logging hub is not loaded do nothing. + + We use UINT64 buffers due to IPF alignment concerns. + +Arguments: + + ErrorLevel - If error level is set do the debug print. + + Format - String to use for the print, followed by Print arguments. + + Marker - VarArgs + +Returns: + + None + +--*/ +{ + UINT64 Buffer[EFI_STATUS_CODE_DATA_MAX_SIZE / sizeof (UINT64)]; + EFI_DEBUG_INFO *DebugInfo; + UINTN TotalSize; + UINTN Index; + UINT64 *ArgumentPointer; + + // + // Check driver Debug Level value and global debug level + // + if (mDebugLevelInstalled) { + if ((ErrorLevel & mDebugLevel.DebugLevel) == 0) { + return; + } + } else { + if ((ErrorLevel & PcdGet32(PcdDebugPrintErrorLevel)) == 0) { + return; + } + } + + TotalSize = sizeof (EFI_DEBUG_INFO) + 12 * sizeof (UINT64 *) + AsciiStrLen (Format) + 1; + if (TotalSize > EFI_STATUS_CODE_DATA_MAX_SIZE) { + return; + } + + // + // Then EFI_DEBUG_INFO + // + DebugInfo = (EFI_DEBUG_INFO *)Buffer; + DebugInfo->ErrorLevel = (UINT32)ErrorLevel; + + // + // 256 byte mini Var Arg stack. That is followed by the format string. + // + for (Index = 0, ArgumentPointer = (UINT64 *)(DebugInfo + 1); Index < 12; Index++, ArgumentPointer++) { + *ArgumentPointer = VA_ARG (Marker, UINT64); + } + AsciiStrCpy ((CHAR8 *)ArgumentPointer, Format); + + // + // + // + REPORT_STATUS_CODE_WITH_EXTENDED_DATA ( + EFI_DEBUG_CODE, + (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_DC_UNSPECIFIED), + DebugInfo, + TotalSize + ); +} + +VOID +EFIAPI +DebugPrint ( + IN UINTN ErrorLevel, + IN CHAR8 *Format, + ... + ) +/*++ + +Routine Description: + + Wrapper for DebugVPrint () + +Arguments: + + ErrorLevel - If error level is set do the debug print. + + Format - String to use for the print, followed by Print arguments. + + ... - Print arguments. + +Returns: + + None + +--*/ +{ + VA_LIST Marker; + + VA_START (Marker, Format); + DebugVPrint (ErrorLevel, Format, Marker); + VA_END (Marker); +} + +/** + 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 fill with PcdDebugClearMemoryValue. + @param Length Number of bytes in Buffer to fill with zeros PcdDebugClearMemoryValue. + + @return Buffer + +**/ +VOID * +EFIAPI +DebugClearMemory ( + OUT VOID *Buffer, + IN UINTN Length + ) +{ +// SetMem (Buffer, Length, PcdGet8(PcdDebugClearMemoryValue)); + SetMem (Buffer, Length, 0xAF); + return Buffer; +} + +BOOLEAN +EFIAPI +DebugAssertEnabled ( + VOID + ) +{ + return ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED) != 0); +} + +BOOLEAN +EFIAPI +DebugPrintEnabled ( + VOID + ) +{ + return ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_PRINT_ENABLED) != 0); +} + +BOOLEAN +EFIAPI +DebugCodeEnabled ( + VOID + ) +{ + return ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_CODE_ENABLED) != 0); +} + +BOOLEAN +EFIAPI +DebugClearMemoryEnabled ( + VOID + ) +{ + return ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED) != 0); +} + diff --git a/EdkModulePkg/Library/EdkDxeDebugLibReportStatusCode/EdkDxeDebugLibReportStatusCode.mbd b/EdkModulePkg/Library/EdkDxeDebugLibReportStatusCode/EdkDxeDebugLibReportStatusCode.mbd new file mode 100644 index 0000000000..9825a208c4 --- /dev/null +++ b/EdkModulePkg/Library/EdkDxeDebugLibReportStatusCode/EdkDxeDebugLibReportStatusCode.mbd @@ -0,0 +1,30 @@ + + + + + EdkDxeDebugLibReportStatusCode + 76a2a4d8-f605-407a-8057-4a17dcdc4c6d + EDK_RELEASE_VERSION 0x00020000 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-31 13:12 + + diff --git a/EdkModulePkg/Library/EdkDxeDebugLibReportStatusCode/EdkDxeDebugLibReportStatusCode.msa b/EdkModulePkg/Library/EdkDxeDebugLibReportStatusCode/EdkDxeDebugLibReportStatusCode.msa new file mode 100644 index 0000000000..e80bee2a87 --- /dev/null +++ b/EdkModulePkg/Library/EdkDxeDebugLibReportStatusCode/EdkDxeDebugLibReportStatusCode.msa @@ -0,0 +1,69 @@ + + + + + EdkDxeDebugLibReportStatusCode + DXE_DRIVER + LIBRARY + 76a2a4d8-f605-407a-8057-4a17dcdc4c6d + EDK_RELEASE_VERSION 0x00020000 + Debug Library for DXE drivers + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + EFI_SPECIFICATION_VERSION 0x00000000 + 2006-03-12 17:09 + 2006-03-31 13:12 + + + DebugLib + ReportStatusCodeLib + BaseMemoryLib + BaseLib + PcdLib + UefiBootServicesTableLib + + + DebugLib.c + + + MdePkg + EdkModulePkg + + + DebugLevel + + + + DebugLibConstructor + + + + + PcdDebugPropertyMask + 0x00000005 + UINT8 + + + PcdDebugPrintErrorLevel + 0x00000006 + UINT32 + + + diff --git a/EdkModulePkg/Library/EdkDxeDebugLibReportStatusCode/build.xml b/EdkModulePkg/Library/EdkDxeDebugLibReportStatusCode/build.xml new file mode 100644 index 0000000000..fb105466c7 --- /dev/null +++ b/EdkModulePkg/Library/EdkDxeDebugLibReportStatusCode/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Library/EdkDxePeCoffLoaderFromHobLib/EdkDxePeCoffLoaderFromHobLib.mbd b/EdkModulePkg/Library/EdkDxePeCoffLoaderFromHobLib/EdkDxePeCoffLoaderFromHobLib.mbd new file mode 100644 index 0000000000..bc500a04a7 --- /dev/null +++ b/EdkModulePkg/Library/EdkDxePeCoffLoaderFromHobLib/EdkDxePeCoffLoaderFromHobLib.mbd @@ -0,0 +1,30 @@ + + + + + EdkDxePeCoffLoaderFromHobLib + ed3de5c8-c389-44f2-a35e-2ebdc9802a49 + 0 + FIX ME! + Copyright (c) 2004 - 2005, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-22 15:50 + + diff --git a/EdkModulePkg/Library/EdkDxePeCoffLoaderFromHobLib/EdkDxePeCoffLoaderFromHobLib.msa b/EdkModulePkg/Library/EdkDxePeCoffLoaderFromHobLib/EdkDxePeCoffLoaderFromHobLib.msa new file mode 100644 index 0000000000..892ae8a34a --- /dev/null +++ b/EdkModulePkg/Library/EdkDxePeCoffLoaderFromHobLib/EdkDxePeCoffLoaderFromHobLib.msa @@ -0,0 +1,50 @@ + + + + + EdkDxePeCoffLoaderFromHobLib + DXE_DRIVER + LIBRARY + ed3de5c8-c389-44f2-a35e-2ebdc9802a49 + 0 + Component description file for the PEI library. + FIX ME! + Copyright (c) 2004 - 2005, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-22 15:50 + + + EdkPeCoffLoaderLib + HobLib + + + PeCoff.c + + + MdePkg + EdkModulePkg + + + + PeiPeCoffLoader + + + diff --git a/EdkModulePkg/Library/EdkDxePeCoffLoaderFromHobLib/PeCoff.c b/EdkModulePkg/Library/EdkDxePeCoffLoaderFromHobLib/PeCoff.c new file mode 100644 index 0000000000..7afe9c2446 --- /dev/null +++ b/EdkModulePkg/Library/EdkDxePeCoffLoaderFromHobLib/PeCoff.c @@ -0,0 +1,38 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Decompress.c + +Abstract: + +--*/ + + + + + +EFI_PEI_PE_COFF_LOADER_PROTOCOL * +EFIAPI +GetPeCoffLoaderProtocol ( + ) +{ + EFI_HOB_GUID_TYPE *GuidHob; + + GuidHob = GetFirstGuidHob (&gEfiPeiPeCoffLoaderGuid); + if (GuidHob == NULL) { + return NULL; + } else { + return (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)(*(UINTN *)(GET_GUID_HOB_DATA (GuidHob))); + } +} + diff --git a/EdkModulePkg/Library/EdkDxePeCoffLoaderFromHobLib/build.xml b/EdkModulePkg/Library/EdkDxePeCoffLoaderFromHobLib/build.xml new file mode 100644 index 0000000000..ba50f03c3d --- /dev/null +++ b/EdkModulePkg/Library/EdkDxePeCoffLoaderFromHobLib/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Library/EdkDxePerformanceLib/DxePerformanceLib.c b/EdkModulePkg/Library/EdkDxePerformanceLib/DxePerformanceLib.c new file mode 100644 index 0000000000..5e448c6974 --- /dev/null +++ b/EdkModulePkg/Library/EdkDxePerformanceLib/DxePerformanceLib.c @@ -0,0 +1,213 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DxePerformanceLib.c + +Abstract: + + Performance Library + +--*/ + +STATIC PERFORMANCE_PROTOCOL *mPerformance = NULL; + +/** + The constructor function caches the pointer to Performance protocol. + + The constructor function locates Performance 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 +PerformanceLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status = gBS->LocateProtocol (&gPerformanceProtocolGuid, NULL, (VOID **) &mPerformance); + ASSERT_EFI_ERROR (Status); + ASSERT (mPerformance != NULL); + + return Status; +} + +/** + 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 + ) +{ + EFI_STATUS Status; + + Status = mPerformance->StartGauge (Handle, Token, Module, TimeStamp); + + 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. + If this function is called multiple times for the same record, then the end time is overwritten. + + @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 + ) +{ + EFI_STATUS Status; + + Status = mPerformance->EndGauge (Handle, Token, Module, TimeStamp); + + return (RETURN_STATUS) Status; +} + +/** + Retrieves a previously logged 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 then the start of the measurement is returned in StartTimeStamp, + and the end of the measurement is returned in EndTimeStamp. + + @param LogEntryKey The key for the previous performance measurement log entry. + If 0, then the first performance measurement log entry is retrieved. + @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 The 64-bit time stamp that was recorded when the measurement was started. + @param EndTimeStamp The 64-bit time stamp that was recorded when the measurement was ended. + + @return The key for the current performance log entry. + +**/ +UINTN +EFIAPI +GetPerformanceMeasurement ( + UINTN LogEntryKey, + OUT CONST VOID **Handle, + OUT CONST CHAR8 **Token, + OUT CONST CHAR8 **Module, + OUT UINT64 *StartTimeStamp, + OUT UINT64 *EndTimeStamp + ) +{ + EFI_STATUS Status; + GAUGE_DATA_ENTRY *GaugeData; + + ASSERT (Handle != NULL); + ASSERT (Token != NULL); + ASSERT (Module != NULL); + ASSERT (StartTimeStamp != NULL); + ASSERT (EndTimeStamp != NULL); + + Status = mPerformance->GetGauge (LogEntryKey++, &GaugeData); + + // + // Make sure that LogEntryKey is a valid log entry key, + // + ASSERT (Status != EFI_INVALID_PARAMETER); + + if (EFI_ERROR (Status)) { + // + // The LogEntryKey is the last entry (equals to the total entry number). + // + return 0; + } + + ASSERT (GaugeData != NULL); + + *Handle = (VOID *) (UINTN) GaugeData->Handle; + *Token = GaugeData->Token; + *Module = GaugeData->Module; + *StartTimeStamp = GaugeData->StartTimeStamp; + *EndTimeStamp = GaugeData->EndTimeStamp; + + return LogEntryKey; +} + +/** + 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 ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0); +} diff --git a/EdkModulePkg/Library/EdkDxePerformanceLib/EdkDxePerformanceLib.mbd b/EdkModulePkg/Library/EdkDxePerformanceLib/EdkDxePerformanceLib.mbd new file mode 100644 index 0000000000..7bd0e106f0 --- /dev/null +++ b/EdkModulePkg/Library/EdkDxePerformanceLib/EdkDxePerformanceLib.mbd @@ -0,0 +1,29 @@ + + + + + EdkDxePerformanceLib + 8B8B4CCC-65FC-41a5-8067-308B8E42CCF2 + EDK_RELEASE_VERSION 0x00020000 + FIX ME! + Copyright (c) 2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-04-04 11:11 + + diff --git a/EdkModulePkg/Library/EdkDxePerformanceLib/EdkDxePerformanceLib.msa b/EdkModulePkg/Library/EdkDxePerformanceLib/EdkDxePerformanceLib.msa new file mode 100644 index 0000000000..8cddf79be5 --- /dev/null +++ b/EdkModulePkg/Library/EdkDxePerformanceLib/EdkDxePerformanceLib.msa @@ -0,0 +1,62 @@ + + + + + EdkDxePerformanceLib + DXE_DRIVER + LIBRARY + 8B8B4CCC-65FC-41a5-8067-308B8E42CCF2 + EDK_RELEASE_VERSION 0x00020000 + Memory-only library functions with no library constructor/destructor + FIX ME! + Copyright (c) 2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + EFI_SPECIFICATION_VERSION 0x00000000 + 2006-04-04 11:11 + + + PerformanceLib + DebugLib + UefiBootServicesTableLib + TimerLib + PcdLib + + + DxePerformanceLib.c + + + MdePkg + EdkModulePkg + + + Performance + + + + PerformanceLibConstructor + + + + + PcdPerformanceLibraryPropertyMask + 0x00000001 + UINT8 + + + diff --git a/EdkModulePkg/Library/EdkDxePerformanceLib/build.xml b/EdkModulePkg/Library/EdkDxePerformanceLib/build.xml new file mode 100644 index 0000000000..5a1dca4e89 --- /dev/null +++ b/EdkModulePkg/Library/EdkDxePerformanceLib/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Library/EdkDxePrintLib/EdkDxePrintLib.mbd b/EdkModulePkg/Library/EdkDxePrintLib/EdkDxePrintLib.mbd new file mode 100644 index 0000000000..ca9912b2c1 --- /dev/null +++ b/EdkModulePkg/Library/EdkDxePrintLib/EdkDxePrintLib.mbd @@ -0,0 +1,30 @@ + + + + + EdkDxePrintLib + 50bcb105-6634-441d-b403-659110a03ad2 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + diff --git a/EdkModulePkg/Library/EdkDxePrintLib/EdkDxePrintLib.msa b/EdkModulePkg/Library/EdkDxePrintLib/EdkDxePrintLib.msa new file mode 100644 index 0000000000..bd58f916db --- /dev/null +++ b/EdkModulePkg/Library/EdkDxePrintLib/EdkDxePrintLib.msa @@ -0,0 +1,49 @@ + + + + + EdkDxePrintLib + DXE_DRIVER + LIBRARY + 50bcb105-6634-441d-b403-659110a03ad2 + 0 + Component description file for the entry point to a EFIDXE Drivers + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + PrintLib + MemoryAllocationLib + UefiBootServicesTableLib + + + PrintLib.c + + + MdePkg + EdkModulePkg + + + Print + + diff --git a/EdkModulePkg/Library/EdkDxePrintLib/PrintLib.c b/EdkModulePkg/Library/EdkDxePrintLib/PrintLib.c new file mode 100644 index 0000000000..30c0354021 --- /dev/null +++ b/EdkModulePkg/Library/EdkDxePrintLib/PrintLib.c @@ -0,0 +1,145 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PrintLib.c + +Abstract: + + Print Library + +--*/ + + + +static EFI_PRINT_PROTOCOL *gPrintProtocol = NULL; + +UINTN +UnicodeVSPrint ( + OUT CHAR16 *StartOfBuffer, + IN UINTN BufferSize, + IN const CHAR16 *FormatString, + IN VA_LIST Marker + ) +/*++ + +Routine Description: + + VSPrint function to process format and place the results in Buffer. Since a + VA_LIST is used this rountine allows the nesting of Vararg routines. Thus + this is the main print working routine + +Arguments: + + StartOfBuffer - Unicode buffer to print the results of the parsing of Format into. + + BufferSize - Maximum number of characters to put into buffer. Zero means + no limit. + + FormatString - Unicode format string see file header for more details. + + Marker - Vararg list consumed by processing Format. + +Returns: + + Number of characters printed. + +--*/ +{ + EFI_STATUS Status; + + if (gPrintProtocol == NULL) { + Status = gBS->LocateProtocol ( + &gEfiPrintProtocolGuid, + NULL, + (VOID **)&gPrintProtocol + ); + if (EFI_ERROR (Status)) { + gPrintProtocol = NULL; + } + if (gPrintProtocol == NULL) { + return 0; + } + } + return gPrintProtocol->VSPrint (StartOfBuffer, BufferSize, FormatString, Marker); +} + +UINTN +UnicodeSPrint ( + OUT CHAR16 *StartOfBuffer, + IN UINTN BufferSize, + IN const CHAR16 *FormatString, + ... + ) + +{ + UINTN Return; + VA_LIST Marker; + + VA_START (Marker, FormatString); + Return = UnicodeVSPrint (StartOfBuffer, BufferSize, FormatString, Marker); + VA_END (Marker); + return Return; +} + +UINTN +AsciiVSPrint ( + OUT CHAR8 *StartOfBuffer, + IN UINTN BufferSize, + IN const CHAR8 *FormatString, + IN VA_LIST Marker + ) +/*++ + +Routine Description: + + VSPrint function to process format and place the results in Buffer. Since a + VA_LIST is used this rountine allows the nesting of Vararg routines. Thus + this is the main print working routine + +Arguments: + + StartOfBuffer - Unicode buffer to print the results of the parsing of Format into. + + BufferSize - Maximum number of characters to put into buffer. Zero means + no limit. + + FormatString - Unicode format string see file header for more details. + + Marker - Vararg list consumed by processing Format. + +Returns: + + Number of characters printed. + +--*/ +{ + return 0; +} + +UINTN +AsciiSPrint ( + OUT CHAR8 *StartOfBuffer, + IN UINTN BufferSize, + IN const CHAR8 *FormatString, + ... + ) + +{ + UINTN Return; + VA_LIST Marker; + + VA_START (Marker, FormatString); + Return = AsciiVSPrint (StartOfBuffer, BufferSize, FormatString, Marker); + VA_END (Marker); + return Return; +} diff --git a/EdkModulePkg/Library/EdkDxePrintLib/build.xml b/EdkModulePkg/Library/EdkDxePrintLib/build.xml new file mode 100644 index 0000000000..2ad6bed86c --- /dev/null +++ b/EdkModulePkg/Library/EdkDxePrintLib/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Library/EdkDxeRuntimeDriverLib/Common/RuntimeLib.c b/EdkModulePkg/Library/EdkDxeRuntimeDriverLib/Common/RuntimeLib.c new file mode 100644 index 0000000000..adddf933e2 --- /dev/null +++ b/EdkModulePkg/Library/EdkDxeRuntimeDriverLib/Common/RuntimeLib.c @@ -0,0 +1,258 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + RuntimeLib.c + +Abstract: + + Light weight lib to support Tiano drivers. + +--*/ + +#include + +// +// Driver Lib Module Globals +// +STATIC EFI_EVENT mRuntimeNotifyEvent; +STATIC EFI_EVENT mEfiVirtualNotifyEvent; +STATIC BOOLEAN mEfiGoneVirtual = FALSE; +STATIC BOOLEAN mEfiAtRuntime = FALSE; + +EFI_RUNTIME_SERVICES *mRT = NULL; + +VOID +EFIAPI +RuntimeDriverExitBootServices ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + + Set AtRuntime flag as TRUE after ExitBootServices + +Arguments: + + Event - The Event that is being processed + + Context - Event Context + +Returns: + + None + +--*/ +{ + EFI_EVENT_NOTIFY ChildNotifyEventHandler; + UINTN Index; + + for (Index = 0; + _gDriverExitBootServicesEvent[Index] != NULL; + Index++) { + ChildNotifyEventHandler = _gDriverExitBootServicesEvent[Index]; + ChildNotifyEventHandler (Event, NULL); + } + + mEfiAtRuntime = TRUE; +} + +STATIC +VOID +EFIAPI +RuntimeLibVirtualNotifyEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + + Fixup internal data so that EFI can be call in virtual mode. + Call the passed in Child Notify event and convert any pointers in + lib to virtual mode. + +Arguments: + + Event - The Event that is being processed + + Context - Event Context + +Returns: + + None + +--*/ +{ + UINTN Index; + EFI_EVENT_NOTIFY ChildNotifyEventHandler; + + for (Index = 0; + _gDriverSetVirtualAddressMapEvent[Index] != NULL; + Index++) { + ChildNotifyEventHandler = _gDriverSetVirtualAddressMapEvent[Index]; + ChildNotifyEventHandler (Event, NULL); + } + + // + // Update global for Runtime Services Table and IO + // + EfiConvertInternalPointer ((VOID **) &mRT); + + // + // Clear out BootService globals + // + gBS = NULL; + gST = NULL; + mEfiGoneVirtual = TRUE; +} + +EFI_STATUS +RuntimeDriverLibConstruct ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Intialize runtime Driver Lib if it has not yet been initialized. + +Arguments: + + ImageHandle - The firmware allocated handle for the EFI image. + + SystemTable - A pointer to the EFI System Table. + + GoVirtualChildEvent - Caller can register a virtual notification event. + +Returns: + + EFI_STATUS always returns EFI_SUCCESS except EFI_ALREADY_STARTED if already started. + +--*/ +{ + EFI_STATUS Status; + + mRT = SystemTable->RuntimeServices; + + // + // Register our ExitBootServices () notify function + // + Status = gBS->CreateEvent ( + EFI_EVENT_SIGNAL_EXIT_BOOT_SERVICES, + EFI_TPL_NOTIFY, + RuntimeDriverExitBootServices, + NULL, + &mRuntimeNotifyEvent + ); + + ASSERT_EFI_ERROR (Status); + + // + // Register SetVirtualAddressMap () notify function + // + Status = gBS->CreateEvent ( + EFI_EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE, + EFI_TPL_NOTIFY, + RuntimeLibVirtualNotifyEvent, + NULL, + &mEfiVirtualNotifyEvent + ); + + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + +EFI_STATUS +RuntimeDriverLibDeconstruct ( + VOID + ) +/*++ + +Routine Description: + + This routine will free some resources which have been allocated in + EfiInitializeRuntimeDriverLib(). If a runtime driver exits with an error, + it must call this routine to free the allocated resource before the exiting. + +Arguments: + + None + +Returns: + + EFI_SUCCESS - Shotdown the Runtime Driver Lib successfully + EFI_UNSUPPORTED - Runtime Driver lib was not initialized at all + +--*/ +{ + EFI_STATUS Status; + + // + // Close our ExitBootServices () notify function + // + Status = gBS->CloseEvent (mRuntimeNotifyEvent); + ASSERT_EFI_ERROR (Status); + + // + // Close SetVirtualAddressMap () notify function + // + Status = gBS->CloseEvent (mEfiVirtualNotifyEvent); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + +BOOLEAN +EfiAtRuntime ( + VOID + ) +/*++ + +Routine Description: + Return TRUE if ExitBootServices () has been called + +Arguments: + NONE + +Returns: + TRUE - If ExitBootServices () has been called + +--*/ +{ + return mEfiAtRuntime; +} + +BOOLEAN +EfiGoneVirtual ( + VOID + ) +/*++ + +Routine Description: + Return TRUE if SetVirtualAddressMap () has been called + +Arguments: + NONE + +Returns: + TRUE - If SetVirtualAddressMap () has been called + +--*/ +{ + return mEfiGoneVirtual; +} + diff --git a/EdkModulePkg/Library/EdkDxeRuntimeDriverLib/Common/RuntimeService.c b/EdkModulePkg/Library/EdkDxeRuntimeDriverLib/Common/RuntimeService.c new file mode 100644 index 0000000000..971dcdbf89 --- /dev/null +++ b/EdkModulePkg/Library/EdkDxeRuntimeDriverLib/Common/RuntimeService.c @@ -0,0 +1,480 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + RuntimeService.c + +Abstract: + + Light weight lib to support Tiano drivers. + +--*/ + +#include + +VOID +EfiResetSystem ( + IN EFI_RESET_TYPE ResetType, + IN EFI_STATUS ResetStatus, + IN UINTN DataSize, + IN CHAR16 *ResetData + ) +/*++ + +Routine Description: + + Resets the entire platform. + +Arguments: + + ResetType - The type of reset to perform. + ResetStatus - The status code for the reset. + DataSize - The size, in bytes, of ResetData. + ResetData - A data buffer that includes a Null-terminated Unicode string, optionally + followed by additional binary data. + +Returns: + + None + +--*/ +{ + mRT->ResetSystem (ResetType, ResetStatus, DataSize, ResetData); +} + +// +// The following functions hide the mRT local global from the call to +// runtime service in the EFI system table. +// +EFI_STATUS +EfiGetTime ( + OUT EFI_TIME *Time, + OUT EFI_TIME_CAPABILITIES *Capabilities + ) +/*++ + +Routine Description: + + Returns the current time and date information, and the time-keeping + capabilities of the hardware platform. + +Arguments: + + Time - A pointer to storage to receive a snapshot of the current time. + Capabilities - An optional pointer to a buffer to receive the real time clock device¡¯s + capabilities. + +Returns: + + Status code + +--*/ +{ + return mRT->GetTime (Time, Capabilities); +} + +EFI_STATUS +EfiSetTime ( + IN EFI_TIME *Time + ) +/*++ + +Routine Description: + + Sets the current local time and date information. + +Arguments: + + Time - A pointer to the current time. + +Returns: + + Status code + +--*/ +{ + return mRT->SetTime (Time); +} + +EFI_STATUS +EfiGetWakeupTime ( + OUT BOOLEAN *Enabled, + OUT BOOLEAN *Pending, + OUT EFI_TIME *Time + ) +/*++ + +Routine Description: + + Returns the current wakeup alarm clock setting. + +Arguments: + + Enabled - Indicates if the alarm is currently enabled or disabled. + Pending - Indicates if the alarm signal is pending and requires acknowledgement. + Time - The current alarm setting. + +Returns: + + Status code + +--*/ +{ + return mRT->GetWakeupTime (Enabled, Pending, Time); +} + +EFI_STATUS +EfiSetWakeupTime ( + IN BOOLEAN Enable, + IN EFI_TIME *Time + ) +/*++ + +Routine Description: + + Sets the system wakeup alarm clock time. + +Arguments: + + Enable - Enable or disable the wakeup alarm. + Time - If Enable is TRUE, the time to set the wakeup alarm for. + If Enable is FALSE, then this parameter is optional, and may be NULL. + +Returns: + + Status code + +--*/ +{ + return mRT->SetWakeupTime (Enable, Time); +} + + + + +EFI_STATUS +EfiGetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID * VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, + OUT VOID *Data + ) +/*++ + +Routine Description: + + Returns the value of a variable. + +Arguments: + + VariableName - A Null-terminated Unicode string that is the name of the + vendor¡¯s variable. + VendorGuid - A unique identifier for the vendor. + Attributes - If not NULL, a pointer to the memory location to return the + attributes bitmask for the variable. + DataSize - On input, the size in bytes of the return Data buffer. + On output the size of data returned in Data. + Data - The buffer to return the contents of the variable. + +Returns: + + Status code + +--*/ +{ + return mRT->GetVariable (VariableName, VendorGuid, Attributes, DataSize, Data); +} + +EFI_STATUS +EfiGetNextVariableName ( + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VendorGuid + ) +/*++ + +Routine Description: + + Enumerates the current variable names. + +Arguments: + + VariableNameSize - The size of the VariableName buffer. + VariableName - On input, supplies the last VariableName that was returned + by GetNextVariableName(). + On output, returns the Nullterminated Unicode string of the + current variable. + VendorGuid - On input, supplies the last VendorGuid that was returned by + GetNextVariableName(). + On output, returns the VendorGuid of the current variable. + +Returns: + + Status code + +--*/ +{ + return mRT->GetNextVariableName (VariableNameSize, VariableName, VendorGuid); +} + +EFI_STATUS +EfiSetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data + ) +/*++ + +Routine Description: + + Sets the value of a variable. + +Arguments: + + VariableName - A Null-terminated Unicode string that is the name of the + vendor¡¯s variable. + VendorGuid - A unique identifier for the vendor. + Attributes - Attributes bitmask to set for the variable. + DataSize - The size in bytes of the Data buffer. + Data - The contents for the variable. + +Returns: + + Status code + +--*/ +{ + return mRT->SetVariable (VariableName, VendorGuid, Attributes, DataSize, Data); +} + +EFI_STATUS +EfiGetNextHighMonotonicCount ( + OUT UINT32 *HighCount + ) +/*++ + +Routine Description: + + Returns the next high 32 bits of the platform¡¯s monotonic counter. + +Arguments: + + HighCount - Pointer to returned value. + +Returns: + + Status code + +--*/ +{ + return mRT->GetNextHighMonotonicCount (HighCount); +} + +EFI_STATUS +EfiConvertPointer ( + IN UINTN DebugDisposition, + IN OUT VOID *Address + ) +/*++ + +Routine Description: + + Determines the new virtual address that is to be used on subsequent memory accesses. + +Arguments: + + DebugDisposition - Supplies type information for the pointer being converted. + Address - A pointer to a pointer that is to be fixed to be the value needed + for the new virtual address mappings being applied. + +Returns: + + Status code + +--*/ +{ + return mRT->ConvertPointer (DebugDisposition, Address); +} + +EFI_STATUS +EfiConvertInternalPointer ( + IN OUT VOID *Address + ) +/*++ + +Routine Description: + + Call EfiConvertPointer() to convert internal pointer. + +Arguments: + + Address - A pointer to a pointer that is to be fixed to be the value needed + for the new virtual address mappings being applied. + +Returns: + + Status code + +--*/ +{ + return EfiConvertPointer (0x0, Address); +} + +EFI_STATUS +EfiConvertList ( + IN UINTN DebugDisposition, + IN OUT LIST_ENTRY *ListHead + ) +/*++ + +Routine Description: + + Conver the standard Lib double linked list to a virtual mapping. + +Arguments: + + DebugDisposition - Argument to EfiConvertPointer (EFI 1.0 API) + + ListHead - Head of linked list to convert + +Returns: + + EFI_SUCCESS + +--*/ +{ + LIST_ENTRY *Link; + LIST_ENTRY *NextLink; + + // + // Convert all the ForwardLink & BackLink pointers in the list + // + Link = ListHead; + do { + NextLink = Link->ForwardLink; + + EfiConvertPointer ( + Link->ForwardLink == ListHead ? DebugDisposition : 0, + (VOID **) &Link->ForwardLink + ); + + EfiConvertPointer ( + Link->BackLink == ListHead ? DebugDisposition : 0, + (VOID **) &Link->BackLink + ); + + Link = NextLink; + } while (Link != ListHead); + return EFI_SUCCESS; +} + + +/** + Change 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. Type + EFI_MEMORY_DESCRIPTOR is defined in the + GetMemoryMap() function description. + + @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 +EfiSetVirtualAddressMap ( + IN UINTN MemoryMapSize, + IN UINTN DescriptorSize, + IN UINT32 DescriptorVersion, + IN CONST EFI_MEMORY_DESCRIPTOR *VirtualMap + ) +{ + return mRT->SetVirtualAddressMap ( + MemoryMapSize, + DescriptorSize, + DescriptorVersion, + (EFI_MEMORY_DESCRIPTOR *) VirtualMap + ); +} + + +EFI_STATUS +EfiUpdateCapsule ( + IN UEFI_CAPSULE_HEADER **CapsuleHeaderArray, + IN UINTN CapsuleCount, + IN EFI_PHYSICAL_ADDRESS ScatterGatherList OPTIONAL + ) +{ +#if (EFI_SPECIFICATION_VERSION >= 0x00020000) + return mRT->UpdateCapsule ( + CapsuleHeaderArray, + CapsuleCount, + ScatterGatherList + ); +#else + return EFI_UNSUPPORTED; +#endif +} + +EFI_STATUS +EfiQueryCapsuleCapabilities ( + IN UEFI_CAPSULE_HEADER **CapsuleHeaderArray, + IN UINTN CapsuleCount, + OUT UINT64 *MaximumCapsuleSize, + OUT EFI_RESET_TYPE *ResetType + ) +{ +#if (EFI_SPECIFICATION_VERSION >= 0x00020000) + return mRT->QueryCapsuleCapabilities ( + CapsuleHeaderArray, + CapsuleCount, + MaximumCapsuleSize, + ResetType + ); +#else + return EFI_UNSUPPORTED; +#endif +} + + +EFI_STATUS +EfiQueryVariableInfo ( + IN UINT32 Attributes, + OUT UINT64 *MaximumVariableStorageSize, + OUT UINT64 *RemainingVariableStorageSize, + OUT UINT64 *MaximumVariableSize + ) +{ +#if (EFI_SPECIFICATION_VERSION >= 0x00020000) + return mRT->QueryVariableInfo ( + Attributes, + MaximumVariableStorageSize, + RemainingVariableStorageSize, + MaximumVariableSize + ); +#else + return EFI_UNSUPPORTED; +#endif +} diff --git a/EdkModulePkg/Library/EdkDxeRuntimeDriverLib/EdkDxeRuntimeDriverLib.mbd b/EdkModulePkg/Library/EdkDxeRuntimeDriverLib/EdkDxeRuntimeDriverLib.mbd new file mode 100644 index 0000000000..72edffb8ba --- /dev/null +++ b/EdkModulePkg/Library/EdkDxeRuntimeDriverLib/EdkDxeRuntimeDriverLib.mbd @@ -0,0 +1,30 @@ + + + + + EdkDxeRuntimeDriverLib + b1ee6c28-54aa-4d17-b705-3e28ccb27b2e + EDK_RELEASE_VERSION 0x00020000 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-31 13:13 + + diff --git a/EdkModulePkg/Library/EdkDxeRuntimeDriverLib/EdkDxeRuntimeDriverLib.msa b/EdkModulePkg/Library/EdkDxeRuntimeDriverLib/EdkDxeRuntimeDriverLib.msa new file mode 100644 index 0000000000..4d9183e32e --- /dev/null +++ b/EdkModulePkg/Library/EdkDxeRuntimeDriverLib/EdkDxeRuntimeDriverLib.msa @@ -0,0 +1,69 @@ + + + + + EdkDxeRuntimeDriverLib + DXE_DRIVER + LIBRARY + b1ee6c28-54aa-4d17-b705-3e28ccb27b2e + EDK_RELEASE_VERSION 0x00020000 + Component description file for the entry point to a EFIDXE Drivers + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + EFI_SPECIFICATION_VERSION 0x00000000 + 2006-03-12 17:09 + 2006-03-31 13:13 + + + DxeRuntimeDriverLib + UefiLib + BaseLib + DebugLib + UefiBootServicesTableLib + EdkDxeSalLib + + + + Common\RuntimeLib.c + Common\RuntimeService.c + + + Common\RuntimeLib.c + Common\RuntimeService.c + + + Ipf\RuntimeLib.c + Ipf\RuntimeService.c + + + + MdePkg + EdkModulePkg + + + ExtendedSalBootService + + + + RuntimeDriverLibConstruct + RuntimeDriverLibDeconstruct + + + diff --git a/EdkModulePkg/Library/EdkDxeRuntimeDriverLib/Ipf/RuntimeLib.c b/EdkModulePkg/Library/EdkDxeRuntimeDriverLib/Ipf/RuntimeLib.c new file mode 100644 index 0000000000..a4eeb33838 --- /dev/null +++ b/EdkModulePkg/Library/EdkDxeRuntimeDriverLib/Ipf/RuntimeLib.c @@ -0,0 +1,284 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + RuntimeLib.c + +Abstract: + + Light weight lib to support Tiano drivers. + +--*/ + +#include +#include + +// +// Driver Lib Module Globals +// + +STATIC EFI_EVENT mRuntimeNotifyEvent; +STATIC EFI_EVENT mEfiVirtualNotifyEvent; + +STATIC EFI_PLABEL mPlabel; +STATIC EXTENDED_SAL_BOOT_SERVICE_PROTOCOL *mEsalBootService; + +EFI_RUNTIME_SERVICES *mRT = NULL; + +STATIC +VOID +EFIAPI +RuntimeDriverExitBootServices ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + + Set AtRuntime flag as TRUE after ExitBootServices + +Arguments: + + Event - The Event that is being processed + + Context - Event Context + +Returns: + + None + +--*/ +{ + EFI_EVENT_NOTIFY ChildNotifyEventHandler; + UINTN Index; + + for (Index = 0; _gDriverExitBootServicesEvent[Index] != NULL; Index++) { + ChildNotifyEventHandler = _gDriverExitBootServicesEvent[Index]; + ChildNotifyEventHandler (Event, NULL); + } +} + +STATIC +VOID +EFIAPI +RuntimeLibVirtualNotifyEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + + Fixup internal data so that EFI can be call in virtual mode. + Call the passed in Child Notify event and convert any pointers in + lib to virtual mode. + +Arguments: + + Event - The Event that is being processed + + Context - Event Context + +Returns: + + None + +--*/ +{ + UINTN Index; + EFI_EVENT_NOTIFY ChildNotifyEventHandler; + + for (Index = 0; _gDriverSetVirtualAddressMapEvent[Index] != NULL; Index++) { + ChildNotifyEventHandler = _gDriverSetVirtualAddressMapEvent[Index]; + ChildNotifyEventHandler (Event, NULL); + } + + mRT->ConvertPointer (0x0, (VOID **) &mPlabel.EntryPoint); + mRT->ConvertPointer (EFI_IPF_GP_POINTER, (VOID **) &mPlabel.GP); + + SetEsalVirtualEntryPoint (mPlabel.EntryPoint, mPlabel.GP); + + // + // Clear out BootService globals + // + gBS = NULL; + gST = NULL; + mRT = NULL; +} + +EFI_STATUS +RuntimeDriverLibConstruct ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Intialize runtime Driver Lib if it has not yet been initialized. + +Arguments: + + ImageHandle - The firmware allocated handle for the EFI image. + + SystemTable - A pointer to the EFI System Table. + + GoVirtualChildEvent - Caller can register a virtual notification event. + +Returns: + + EFI_STATUS always returns EFI_SUCCESS except EFI_ALREADY_STARTED if already started. + +--*/ +{ + EFI_PLABEL *Plabel; + EFI_STATUS Status; + + mRT = SystemTable->RuntimeServices; + + // + // The protocol contains a function pointer, which is an indirect procedure call. + // An indirect procedure call goes through a plabel, and pointer to a function is + // a pointer to a plabel. To implement indirect procedure calls that can work in + // both physical and virtual mode, two plabels are required (one physical and one + // virtual). So lets grap the physical PLABEL for the EsalEntryPoint and store it + // away. We cache it in a module global, so we can register the vitrual version. + // + Status = gBS->LocateProtocol (&gEfiExtendedSalBootServiceProtocolGuid, NULL, &mEsalBootService); + ASSERT_EFI_ERROR (Status); + + Plabel = (EFI_PLABEL *) (UINTN) mEsalBootService->ExtendedSalProc; + + mPlabel.EntryPoint = Plabel->EntryPoint; + mPlabel.GP = Plabel->GP; + + SetEsalPhysicalEntryPoint (mPlabel.EntryPoint, mPlabel.GP); + + // + // Register our ExitBootServices () notify function + // + + Status = gBS->CreateEvent ( + EFI_EVENT_SIGNAL_EXIT_BOOT_SERVICES, + EFI_TPL_NOTIFY, + RuntimeDriverExitBootServices, + NULL, + &mRuntimeNotifyEvent + ); + ASSERT_EFI_ERROR (Status); + + // + // Register SetVirtualAddressMap () notify function + // + + Status = gBS->CreateEvent ( + EFI_EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE, + EFI_TPL_NOTIFY, + RuntimeLibVirtualNotifyEvent, + NULL, + mEfiVirtualNotifyEvent + ); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + +EFI_STATUS +RuntimeDriverLibDeconstruct ( + VOID + ) +/*++ + +Routine Description: + + This routine will free some resources which have been allocated in + EfiInitializeRuntimeDriverLib(). If a runtime driver exits with an error, + it must call this routine to free the allocated resource before the exiting. + +Arguments: + + None + +Returns: + + EFI_SUCCESS - Shotdown the Runtime Driver Lib successfully + EFI_UNSUPPORTED - Runtime Driver lib was not initialized at all + +--*/ +{ + EFI_STATUS Status; + + // + // Close our ExitBootServices () notify function + // + Status = gBS->CloseEvent (mRuntimeNotifyEvent); + ASSERT_EFI_ERROR (Status); + + // + // Close SetVirtualAddressMap () notify function + // + Status = gBS->CloseEvent (mEfiVirtualNotifyEvent); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + +BOOLEAN +EfiAtRuntime ( + VOID + ) +/*++ + +Routine Description: + Return TRUE if ExitBootService () has been called + +Arguments: + NONE + +Returns: + TRUE - If ExitBootService () has been called + +--*/ +{ + EFI_GUID Guid = EFI_EXTENDED_SAL_VIRTUAL_SERVICES_PROTOCOL_GUID; + SAL_RETURN_REGS ReturnReg; + + ReturnReg = EfiCallEsalService (&Guid, IsEfiRuntime, 0, 0, 0, 0, 0, 0, 0); + + return (BOOLEAN) (ReturnReg.r9 == 1); +} + +BOOLEAN +EfiGoneVirtual ( + VOID + ) +/*++ + +Routine Description: + Return TRUE if SetVirtualAddressMap () has been called + +Arguments: + NONE + +Returns: + TRUE - If SetVirtualAddressMap () has been called + +--*/ +{ + EFI_GUID Guid = EFI_EXTENDED_SAL_VIRTUAL_SERVICES_PROTOCOL_GUID; + SAL_RETURN_REGS ReturnReg; + + ReturnReg = EfiCallEsalService (&Guid, IsVirtual, 0, 0, 0, 0, 0, 0, 0); + + return (BOOLEAN) (ReturnReg.r9 == 1); +} diff --git a/EdkModulePkg/Library/EdkDxeRuntimeDriverLib/Ipf/RuntimeService.c b/EdkModulePkg/Library/EdkDxeRuntimeDriverLib/Ipf/RuntimeService.c new file mode 100644 index 0000000000..bc7a31841b --- /dev/null +++ b/EdkModulePkg/Library/EdkDxeRuntimeDriverLib/Ipf/RuntimeService.c @@ -0,0 +1,516 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + RuntimeService.c + +Abstract: + + Light weight lib to support Tiano drivers. + +--*/ + +#include + +VOID +EfiResetSystem ( + IN EFI_RESET_TYPE ResetType, + IN EFI_STATUS ResetStatus, + IN UINTN DataSize, + IN CHAR16 *ResetData + ) +/*++ + +Routine Description: + + Resets the entire platform. + +Arguments: + + ResetType - The type of reset to perform. + ResetStatus - The status code for the reset. + DataSize - The size, in bytes, of ResetData. + ResetData - A data buffer that includes a Null-terminated Unicode string, optionally + followed by additional binary data. + +Returns: + + None + +--*/ +{ + EFI_GUID Guid = EFI_EXTENDED_SAL_RESET_SERVICES_PROTOCOL_GUID; + + EfiCallEsalService ( + &Guid, + ResetSystem, + (UINT64) ResetType, + (UINT64) ResetStatus, + (UINT64) DataSize, + (UINT64) ResetData, + 0, + 0, + 0 + ); +} + + +// +// The following functions hide the mRT local global from the call to +// runtime service in the EFI system table. +// +EFI_STATUS +EfiGetTime ( + OUT EFI_TIME *Time, + OUT EFI_TIME_CAPABILITIES *Capabilities + ) +/*++ + +Routine Description: + + Returns the current time and date information, and the time-keeping + capabilities of the hardware platform. + +Arguments: + + Time - A pointer to storage to receive a snapshot of the current time. + Capabilities - An optional pointer to a buffer to receive the real time clock device¡¯s + capabilities. + +Returns: + + Status code + +--*/ +{ + SAL_RETURN_REGS ReturnReg; + EFI_GUID Guid = EFI_EXTENDED_SAL_RTC_SERVICES_PROTOCOL_GUID; + + ReturnReg = EfiCallEsalService (&Guid, GetTime, (UINT64) Time, (UINT64) Capabilities, 0, 0, 0, 0, 0); + return ReturnReg.Status; +} + +EFI_STATUS +EfiSetTime ( + IN EFI_TIME *Time + ) +/*++ + +Routine Description: + + Sets the current local time and date information. + +Arguments: + + Time - A pointer to the current time. + +Returns: + + Status code + +--*/ +{ + SAL_RETURN_REGS ReturnReg; + + EFI_GUID Guid = EFI_EXTENDED_SAL_RTC_SERVICES_PROTOCOL_GUID; + + ReturnReg = EfiCallEsalService (&Guid, SetTime, (UINT64) Time, 0, 0, 0, 0, 0, 0); + return ReturnReg.Status; +} + +EFI_STATUS +EfiGetWakeupTime ( + OUT BOOLEAN *Enabled, + OUT BOOLEAN *Pending, + OUT EFI_TIME *Time + ) +/*++ + +Routine Description: + + Returns the current wakeup alarm clock setting. + +Arguments: + + Enabled - Indicates if the alarm is currently enabled or disabled. + Pending - Indicates if the alarm signal is pending and requires acknowledgement. + Time - The current alarm setting. + +Returns: + + Status code + +--*/ +{ + SAL_RETURN_REGS ReturnReg; + + EFI_GUID Guid = EFI_EXTENDED_SAL_RTC_SERVICES_PROTOCOL_GUID; + + ReturnReg = EfiCallEsalService (&Guid, GetWakeupTime, (UINT64) Enabled, (UINT64) Pending, (UINT64) Time, 0, 0, 0, 0); + return ReturnReg.Status; +} + +EFI_STATUS +EfiSetWakeupTime ( + IN BOOLEAN Enable, + IN EFI_TIME *Time + ) +/*++ + +Routine Description: + + Sets the system wakeup alarm clock time. + +Arguments: + + Enable - Enable or disable the wakeup alarm. + Time - If Enable is TRUE, the time to set the wakeup alarm for. + If Enable is FALSE, then this parameter is optional, and may be NULL. + +Returns: + + Status code + +--*/ +{ + SAL_RETURN_REGS ReturnReg; + + EFI_GUID Guid = EFI_EXTENDED_SAL_RTC_SERVICES_PROTOCOL_GUID; + + ReturnReg = EfiCallEsalService (&Guid, SetWakeupTime, (UINT64) Enable, (UINT64) Time, 0, 0, 0, 0, 0); + return ReturnReg.Status; +} + +EFI_STATUS +EfiGetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID * VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, + OUT VOID *Data + ) +/*++ + +Routine Description: + + Returns the value of a variable. + +Arguments: + + VariableName - A Null-terminated Unicode string that is the name of the + vendor¡¯s variable. + VendorGuid - A unique identifier for the vendor. + Attributes - If not NULL, a pointer to the memory location to return the + attributes bitmask for the variable. + DataSize - On input, the size in bytes of the return Data buffer. + On output the size of data returned in Data. + Data - The buffer to return the contents of the variable. + +Returns: + + Status code + +--*/ +{ + SAL_RETURN_REGS ReturnReg; + EFI_GUID Guid = EFI_EXTENDED_SAL_VARIABLE_SERVICES_PROTOCOL_GUID; + + ReturnReg = EfiCallEsalService ( + &Guid, + EsalGetVariable, + (UINT64) VariableName, + (UINT64) VendorGuid, + (UINT64) Attributes, + (UINT64) DataSize, + (UINT64) Data, + 0, + 0 + ); + return (EFI_STATUS) ReturnReg.Status; +} + +EFI_STATUS +EfiGetNextVariableName ( + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VendorGuid + ) +/*++ + +Routine Description: + + Enumerates the current variable names. + +Arguments: + + VariableNameSize - The size of the VariableName buffer. + VariableName - On input, supplies the last VariableName that was returned + by GetNextVariableName(). + On output, returns the Nullterminated Unicode string of the + current variable. + VendorGuid - On input, supplies the last VendorGuid that was returned by + GetNextVariableName(). + On output, returns the VendorGuid of the current variable. + +Returns: + + Status code + +--*/ +{ + SAL_RETURN_REGS ReturnReg; + EFI_GUID Guid = EFI_EXTENDED_SAL_VARIABLE_SERVICES_PROTOCOL_GUID; + + ReturnReg = EfiCallEsalService ( + &Guid, + EsalGetNextVariableName, + (UINT64) VariableNameSize, + (UINT64) VariableName, + (UINT64) VendorGuid, + 0, + 0, + 0, + 0 + ); + return (EFI_STATUS) ReturnReg.Status; +} + +EFI_STATUS +EfiSetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data + ) +/*++ + +Routine Description: + + Sets the value of a variable. + +Arguments: + + VariableName - A Null-terminated Unicode string that is the name of the + vendor¡¯s variable. + VendorGuid - A unique identifier for the vendor. + Attributes - Attributes bitmask to set for the variable. + DataSize - The size in bytes of the Data buffer. + Data - The contents for the variable. + +Returns: + + Status code + +--*/ +{ + SAL_RETURN_REGS ReturnReg; + EFI_GUID Guid = EFI_EXTENDED_SAL_VARIABLE_SERVICES_PROTOCOL_GUID; + + ReturnReg = EfiCallEsalService ( + &Guid, + EsalSetVariable, + (UINT64) VariableName, + (UINT64) VendorGuid, + (UINT64) Attributes, + (UINT64) DataSize, + (UINT64) Data, + 0, + 0 + ); + return (EFI_STATUS) ReturnReg.Status; +} + +EFI_STATUS +EfiGetNextHighMonotonicCount ( + OUT UINT32 *HighCount + ) +/*++ + +Routine Description: + + Returns the next high 32 bits of the platform¡¯s monotonic counter. + +Arguments: + + HighCount - Pointer to returned value. + +Returns: + + Status code + +--*/ +{ + SAL_RETURN_REGS ReturnReg; + + EFI_GUID Guid = EFI_EXTENDED_SAL_MTC_SERVICES_PROTOCOL_GUID; + + ReturnReg = EfiCallEsalService (&Guid, GetNextHighMonotonicCount, (UINT64) HighCount, 0, 0, 0, 0, 0, 0); + return (EFI_STATUS) ReturnReg.Status; +} + +EFI_STATUS +EfiConvertPointer ( + IN UINTN DebugDisposition, + IN OUT VOID *Address + ) +/*++ + +Routine Description: + + Determines the new virtual address that is to be used on subsequent memory accesses. + +Arguments: + + DebugDisposition - Supplies type information for the pointer being converted. + Address - A pointer to a pointer that is to be fixed to be the value needed + for the new virtual address mappings being applied. + +Returns: + + Status code + +--*/ +{ + return mRT->ConvertPointer (DebugDisposition, Address); +} + +EFI_STATUS +EfiConvertList ( + IN UINTN DebugDisposition, + IN OUT LIST_ENTRY *ListHead + ) +/*++ + +Routine Description: + + Conver the standard Lib double linked list to a virtual mapping. + +Arguments: + + DebugDisposition - Argument to EfiConvertPointer (EFI 1.0 API) + + ListHead - Head of linked list to convert + +Returns: + + EFI_SUCCESS + +--*/ +{ + LIST_ENTRY *Link; + LIST_ENTRY *NextLink; + + // + // Convert all the ForwardLink & BackLink pointers in the list + // + Link = ListHead; + do { + NextLink = Link->ForwardLink; + + EfiConvertPointer ( + Link->ForwardLink == ListHead ? DebugDisposition : 0, + (VOID **) &Link->ForwardLink + ); + + EfiConvertPointer ( + Link->BackLink == ListHead ? DebugDisposition : 0, + (VOID **) &Link->BackLink + ); + + Link = NextLink; + } while (Link != ListHead); + return EFI_SUCCESS; +} + + +/** + Change 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. Type + EFI_MEMORY_DESCRIPTOR is defined in the + GetMemoryMap() function description. + + @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 +EfiSetVirtualAddressMap ( + IN UINTN MemoryMapSize, + IN UINTN DescriptorSize, + IN UINT32 DescriptorVersion, + IN CONST EFI_MEMORY_DESCRIPTOR *VirtualMap + ) +{ + SAL_RETURN_REGS ReturnReg; + EFI_GUID Guid = EFI_EXTENDED_SAL_VIRTUAL_SERVICES_PROTOCOL_GUID; + + ReturnReg = EfiCallEsalService ( + &Guid, + SetVirtualAddress, + (UINT64) MemoryMapSize, + (UINT64) DescriptorSize, + (UINT64) DescriptorVersion, + (UINT64) VirtualMap, + 0, + 0, + 0 + ); + + return ReturnReg.Status; +} + + +EFI_STATUS +EfiUpdateCapsule ( + IN UEFI_CAPSULE_HEADER **CapsuleHeaderArray, + IN UINTN CapsuleCount, + IN EFI_PHYSICAL_ADDRESS ScatterGatherList OPTIONAL + ) +{ + return EFI_UNSUPPORTED; +} + +EFI_STATUS +EfiQueryCapsuleCapabilities ( + IN UEFI_CAPSULE_HEADER **CapsuleHeaderArray, + IN UINTN CapsuleCount, + OUT UINT64 *MaximumCapsuleSize, + OUT EFI_RESET_TYPE *ResetType + ) +{ + return EFI_UNSUPPORTED; +} + + +EFI_STATUS +EfiQueryVariableInfo ( + IN UINT32 Attributes, + OUT UINT64 *MaximumVariableStorageSize, + OUT UINT64 *RemainingVariableStorageSize, + OUT UINT64 *MaximumVariableSize + ) +{ + return EFI_UNSUPPORTED; +} diff --git a/EdkModulePkg/Library/EdkDxeRuntimeDriverLib/RuntimeLibInternal.h b/EdkModulePkg/Library/EdkDxeRuntimeDriverLib/RuntimeLibInternal.h new file mode 100644 index 0000000000..82494fd7a0 --- /dev/null +++ b/EdkModulePkg/Library/EdkDxeRuntimeDriverLib/RuntimeLibInternal.h @@ -0,0 +1,30 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + RuntimeLibInternal.h + +Abstract: + +--*/ + +#ifndef __RUNTIMELIBINTERNAL_H__ +#define __RUNTIMELIBINTERNAL_H__ + +EFI_STATUS +EfiConvertInternalPointer ( + IN OUT VOID *Address + ); + +extern EFI_RUNTIME_SERVICES *mRT; + +#endif //__RUNTIMELIBINTERNAL_H__ diff --git a/EdkModulePkg/Library/EdkDxeRuntimeDriverLib/build.xml b/EdkModulePkg/Library/EdkDxeRuntimeDriverLib/build.xml new file mode 100644 index 0000000000..e43f7080a9 --- /dev/null +++ b/EdkModulePkg/Library/EdkDxeRuntimeDriverLib/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Library/EdkDxeSalLib/EdkDxeSalLib.mbd b/EdkModulePkg/Library/EdkDxeSalLib/EdkDxeSalLib.mbd new file mode 100644 index 0000000000..dababd27ad --- /dev/null +++ b/EdkModulePkg/Library/EdkDxeSalLib/EdkDxeSalLib.mbd @@ -0,0 +1,30 @@ + + + + + EdkDxeSalLib + 61999c3c-72a5-4506-a4ff-4271d18a1d14 + EDK_RELEASE_VERSION 0x00020000 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-31 13:13 + + diff --git a/EdkModulePkg/Library/EdkDxeSalLib/EdkDxeSalLib.msa b/EdkModulePkg/Library/EdkDxeSalLib/EdkDxeSalLib.msa new file mode 100644 index 0000000000..d9fc5830ed --- /dev/null +++ b/EdkModulePkg/Library/EdkDxeSalLib/EdkDxeSalLib.msa @@ -0,0 +1,58 @@ + + + + + EdkDxeSalLib + DXE_DRIVER + LIBRARY + 61999c3c-72a5-4506-a4ff-4271d18a1d14 + EDK_RELEASE_VERSION 0x00020000 + Component description file for the entry point to a EFIDXE Drivers + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + EFI_SPECIFICATION_VERSION 0x00000000 + 2006-03-12 17:09 + 2006-03-31 13:13 + + + EdkDxeSalLib + DebugLib + UefiBootServicesTableLib + + + + Ipf/EsalServiceLib.c + Ipf/AsmEsalServiceLib.s + Ipf/AsmIpfCpuCache.s + + + + MdePkg + EdkModulePkg + + + ExtendedSalBootService + + + + DxeSalLibConstruct + + + diff --git a/EdkModulePkg/Library/EdkDxeSalLib/Ipf/AsmEsalServiceLib.s b/EdkModulePkg/Library/EdkDxeSalLib/Ipf/AsmEsalServiceLib.s new file mode 100644 index 0000000000..2b040b710b --- /dev/null +++ b/EdkModulePkg/Library/EdkDxeSalLib/Ipf/AsmEsalServiceLib.s @@ -0,0 +1,149 @@ +//++ +// Copyright (c) 2006, Intel Corporation +// All rights reserved. This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// Module Name: +// +// EsalLib.s +// +// Abstract: +// +// +// Revision History: +// +//-- + +.file "EsalLib.s" + +#include "IpfMacro.i" + +// +// Exports +// +.global GetEsalEntryPoint + + +//----------------------------------------------------------------------------- +//++ +// GetEsalEntryPoint +// +// Return Esal global and PSR register. +// +// On Entry : +// +// +// Return Value: +// r8 = EFI_SAL_SUCCESS +// r9 = Physical Plabel +// r10 = Virtual Plabel +// r11 = psr +// +// As per static calling conventions. +// +//-- +//--------------------------------------------------------------------------- +PROCEDURE_ENTRY (GetEsalEntryPoint) + + NESTED_SETUP (0,8,0,0) + +EsalCalcStart: + mov r8 = ip;; + add r8 = (EsalEntryPoint - EsalCalcStart), r8;; + mov r9 = r8;; + add r10 = 0x10, r8;; + mov r11 = psr;; + mov r8 = r0;; + + NESTED_RETURN + +PROCEDURE_EXIT (GetEsalEntryPoint) + + + + + +//----------------------------------------------------------------------------- +//++ +// SetEsalPhysicalEntryPoint +// +// Set the dispatcher entry point +// +// On Entry: +// in0 = Physical address of Esal Dispatcher +// in1 = Physical GP +// +// Return Value: +// r8 = EFI_SAL_SUCCESS +// +// As per static calling conventions. +// +//-- +//--------------------------------------------------------------------------- +PROCEDURE_ENTRY (SetEsalPhysicalEntryPoint) + + NESTED_SETUP (2,8,0,0) + +EsalCalcStart1: + mov r8 = ip;; + add r8 = (EsalEntryPoint - EsalCalcStart1), r8;; + st8 [r8] = in0;; + add r8 = 0x08, r8;; + st8 [r8] = in1;; + mov r8 = r0;; + + NESTED_RETURN + +PROCEDURE_EXIT (SetEsalPhysicalEntryPoint) + + +//----------------------------------------------------------------------------- +//++ +// SetEsalVirtualEntryPoint +// +// Register physical address of Esal globals. +// +// On Entry : +// in0 = Virtual address of Esal Dispatcher +// in1 = Virtual GP +// +// Return Value: +// r8 = EFI_SAL_ERROR +// +// As per static calling conventions. +// +//-- +//--------------------------------------------------------------------------- +PROCEDURE_ENTRY (SetEsalVirtualEntryPoint) + + NESTED_SETUP (2,8,0,0) + +EsalCalcStart2: + mov r8 = ip;; + add r8 = (EsalEntryPoint - EsalCalcStart2), r8;; + add r8 = 0x10, r8;; + st8 [r8] = in0;; + add r8 = 0x08, r8;; + st8 [r8] = in1;; + mov r8 = r0;; + + NESTED_RETURN + +PROCEDURE_EXIT (SetEsalVirtualEntryPoint) + + + + +.align 32 +EsalEntryPoint: + data8 0 // Physical Entry + data8 0 // GP + data8 0 // Virtual Entry + data8 0 // GP + + diff --git a/EdkModulePkg/Library/EdkDxeSalLib/Ipf/AsmIpfCpuCache.s b/EdkModulePkg/Library/EdkDxeSalLib/Ipf/AsmIpfCpuCache.s new file mode 100644 index 0000000000..c4505051fa --- /dev/null +++ b/EdkModulePkg/Library/EdkDxeSalLib/Ipf/AsmIpfCpuCache.s @@ -0,0 +1,88 @@ +//++ +// Copyright (c) 2006, Intel Corporation +// All rights reserved. This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// Module Name: +// +// IpfCpuCache.s +// +// Abstract: +// +// Contains Misc assembly procedures to support IPF CPU AP. +// +// Revision History: +// +//-- + +.file "IpfCpuCache.s" + +#include "IpfMacro.i" +#include "IpfDefines.h" + +//----------------------------------------------------------------------------- +//++ +// Flush Cache +// +// Arguments : + +// Input = in0 = Starting Address to Flush. +// Input = in1 = Length in bytes. +// Input = b0 = return branch register. +// On Entry : +// +// Return Value: +// +// VOID +// SalFlushCache ( +// IN UINT64 BaseToFlush, +// IN UINT64 LengthToFlush +// ); +// +//-- +//--------------------------------------------------------------------------- +PROCEDURE_ENTRY (SalFlushCache) + + NESTED_SETUP (5,8,0,0) + + mov loc2 = ar.lc + + mov loc3 = in0 // Start address. + mov loc4 = in1;; // Length in bytes. + + cmp.eq p6,p7 = loc4, r0;; // If Length is zero then don't flush any cache + (p6) br.spnt.many DoneFlushingC;; + + add loc4 = loc4,loc3 + mov loc5 = 1;; + sub loc4 = loc4, loc5 ;; // the End address to flush + + dep loc3 = r0,loc3,0,5 + dep loc4 = r0,loc4,0,5;; + shr loc3 = loc3,5 + shr loc4 = loc4,5;; // 32 byte cache line + + sub loc4 = loc4,loc3;; // total flush count, It should be add 1 but + // the br.cloop will first execute one time + mov loc3 = in0 + mov loc5 = 32 + mov ar.lc = loc4;; + +StillFlushingC: + fc loc3;; + sync.i;; + srlz.i;; + add loc3 = loc5,loc3;; + br.cloop.sptk.few StillFlushingC;; + +DoneFlushingC: + mov ar.lc = loc2 + NESTED_RETURN + +PROCEDURE_EXIT (SalFlushCache) + diff --git a/EdkModulePkg/Library/EdkDxeSalLib/Ipf/EsalServiceLib.c b/EdkModulePkg/Library/EdkDxeSalLib/Ipf/EsalServiceLib.c new file mode 100644 index 0000000000..d258b98cab --- /dev/null +++ b/EdkModulePkg/Library/EdkDxeSalLib/Ipf/EsalServiceLib.c @@ -0,0 +1,199 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + EsalServiceLib.c + +Abstract: + +--*/ + +#include + + +STATIC EXTENDED_SAL_BOOT_SERVICE_PROTOCOL *mEsalBootService; + +EFI_STATUS +EFIAPI +DxeSalLibConstruct ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status = gBS->LocateProtocol (&gEfiExtendedSalBootServiceProtocolGuid, NULL, &mEsalBootService); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +EFI_STATUS +RegisterEsalFunction ( + IN UINT64 FunctionId, + IN EFI_GUID *ClassGuid, + IN SAL_INTERNAL_EXTENDED_SAL_PROC Function, + IN VOID *ModuleGlobal + ) +/*++ + +Routine Description: + + Register ESAL Class Function and it's asociated global. + This function is boot service only! + +Arguments: + FunctionId - ID of function to register + ClassGuid - GUID of function class + Function - Function to register under ClassGuid/FunctionId pair + ModuleGlobal - Module global for Function. + +Returns: + EFI_SUCCESS - If ClassGuid/FunctionId Function was registered. + +--*/ +{ + return mEsalBootService->AddExtendedSalProc ( + mEsalBootService, + ClassGuid, + FunctionId, + Function, + ModuleGlobal + ); +} + +EFI_STATUS +RegisterEsalClass ( + IN EFI_GUID *ClassGuid, + IN VOID *ModuleGlobal, + ... + ) +/*++ + +Routine Description: + + Register ESAL Class and it's asociated global. + This function is boot service only! + +Arguments: + ClassGuid - GUID of function class + ModuleGlobal - Module global for Function. + ... - SAL_INTERNAL_EXTENDED_SAL_PROC and FunctionId pairs. NULL + indicates the end of the list. + +Returns: + EFI_SUCCESS - All members of ClassGuid registered + +--*/ +{ + VA_LIST Args; + EFI_STATUS Status; + SAL_INTERNAL_EXTENDED_SAL_PROC Function; + UINT64 FunctionId; + EFI_HANDLE NewHandle; + + VA_START (Args, ModuleGlobal); + + Status = EFI_SUCCESS; + while (!EFI_ERROR (Status)) { + Function = (SAL_INTERNAL_EXTENDED_SAL_PROC) VA_ARG (Args, SAL_INTERNAL_EXTENDED_SAL_PROC); + if (Function == NULL) { + break; + } + + FunctionId = VA_ARG (Args, UINT64); + + Status = RegisterEsalFunction (FunctionId, ClassGuid, Function, ModuleGlobal); + } + + if (EFI_ERROR (Status)) { + return Status; + } + + NewHandle = NULL; + return gBS->InstallProtocolInterface ( + &NewHandle, + ClassGuid, + EFI_NATIVE_INTERFACE, + NULL + ); +} + +SAL_RETURN_REGS +EfiCallEsalService ( + IN EFI_GUID *ClassGuid, + IN UINT64 FunctionId, + IN UINT64 Arg2, + IN UINT64 Arg3, + IN UINT64 Arg4, + IN UINT64 Arg5, + IN UINT64 Arg6, + IN UINT64 Arg7, + IN UINT64 Arg8 + ) +/*++ + +Routine Description: + + Call module that is not linked direclty to this module. This code is IP + relative and hides the binding issues of virtual or physical calling. The + function that gets dispatched has extra arguments that include the registered + module global and a boolean flag to indicate if the system is in virutal mode. + +Arguments: + ClassGuid - GUID of function + FunctionId - Function in ClassGuid to call + Arg2 - Argument 2 ClassGuid/FunctionId defined + Arg3 - Argument 3 ClassGuid/FunctionId defined + Arg4 - Argument 4 ClassGuid/FunctionId defined + Arg5 - Argument 5 ClassGuid/FunctionId defined + Arg6 - Argument 6 ClassGuid/FunctionId defined + Arg7 - Argument 7 ClassGuid/FunctionId defined + Arg8 - Argument 8 ClassGuid/FunctionId defined + +Returns: + Status of ClassGuid/FuncitonId + +--*/ +{ + SAL_RETURN_REGS ReturnReg; + SAL_EXTENDED_SAL_PROC EsalProc; + + ReturnReg = GetEsalEntryPoint (); + if (ReturnReg.Status != EFI_SAL_SUCCESS) { + return ReturnReg; + } + + if (ReturnReg.r11 & PSR_IT_MASK) { + // + // Virtual mode plabel to entry point + // + EsalProc = (SAL_EXTENDED_SAL_PROC) ReturnReg.r10; + } else { + // + // Physical mode plabel to entry point + // + EsalProc = (SAL_EXTENDED_SAL_PROC) ReturnReg.r9; + } + + return EsalProc ( + ClassGuid, + FunctionId, + Arg2, + Arg3, + Arg4, + Arg5, + Arg6, + Arg7, + Arg8 + ); +} diff --git a/EdkModulePkg/Library/EdkDxeSalLib/build.xml b/EdkModulePkg/Library/EdkDxeSalLib/build.xml new file mode 100644 index 0000000000..e4f1e3ea02 --- /dev/null +++ b/EdkModulePkg/Library/EdkDxeSalLib/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Library/EdkFvbServiceLib/EdkFvbServiceLib.mbd b/EdkModulePkg/Library/EdkFvbServiceLib/EdkFvbServiceLib.mbd new file mode 100644 index 0000000000..a5ee7cb19d --- /dev/null +++ b/EdkModulePkg/Library/EdkFvbServiceLib/EdkFvbServiceLib.mbd @@ -0,0 +1,30 @@ + + + + + EdkFvbServiceLib + bd4d540e-04b0-4b10-8fd5-4a7bb533cf67 + EDK_RELEASE_VERSION 0x00020000 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-31 13:13 + + diff --git a/EdkModulePkg/Library/EdkFvbServiceLib/EdkFvbServiceLib.msa b/EdkModulePkg/Library/EdkFvbServiceLib/EdkFvbServiceLib.msa new file mode 100644 index 0000000000..c20d5ee16d --- /dev/null +++ b/EdkModulePkg/Library/EdkFvbServiceLib/EdkFvbServiceLib.msa @@ -0,0 +1,74 @@ + + + + + EdkFvbServiceLib + DXE_DRIVER + LIBRARY + bd4d540e-04b0-4b10-8fd5-4a7bb533cf67 + EDK_RELEASE_VERSION 0x00020000 + FvbService Library for UEFI drivers + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + EFI_SPECIFICATION_VERSION 0x00000000 + 2006-03-12 17:09 + 2006-03-31 13:13 + + + EdkFvbServiceLib + UefiLib + PrintLib + BaseLib + MemoryAllocationLib + DebugLib + BaseMemoryLib + DxeRuntimeDriverLib + UefiBootServicesTableLib + EdkDxeSalLib + + + + Ia32/Fvb.c + + + x64/Fvb.c + + + Ipf/Fvb.c + + + + MdePkg + EdkModulePkg + + + FirmwareVolumeBlock + FvbExtension + FirmwareVolumeBlock + + + + FvbLibInitialize + + + FvbVirtualAddressChangeNotifyEvent + + + diff --git a/EdkModulePkg/Library/EdkFvbServiceLib/Fvb.h b/EdkModulePkg/Library/EdkFvbServiceLib/Fvb.h new file mode 100644 index 0000000000..c6d1eb7193 --- /dev/null +++ b/EdkModulePkg/Library/EdkFvbServiceLib/Fvb.h @@ -0,0 +1,31 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Fvb.h + +Abstract: + +--*/ + +#ifndef __FVB_H__ +#define __FVB_H__ + +#define MAX_FVB_COUNT 16 + +typedef struct { + EFI_HANDLE Handle; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; + EFI_FVB_EXTENSION_PROTOCOL *FvbExtension; +} FVB_ENTRY; + +#endif diff --git a/EdkModulePkg/Library/EdkFvbServiceLib/Ia32/Fvb.c b/EdkModulePkg/Library/EdkFvbServiceLib/Ia32/Fvb.c new file mode 100644 index 0000000000..222fb9bd4d --- /dev/null +++ b/EdkModulePkg/Library/EdkFvbServiceLib/Ia32/Fvb.c @@ -0,0 +1,534 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Fvb.c + +Abstract: + + Firmware Volume Block Protocol Runtime Abstraction + + mFvbEntry is an array of Handle Fvb pairs. The Fvb Lib Instance matches the + index in the mFvbEntry array. This should be the same sequence as the FVB's + were described in the HOB. We have to remember the handle so we can tell if + the protocol has been reinstalled and it needs updateing. + + If you are using any of these lib functions.you must first call FvbInitialize (). + +Key: + FVB - Firmware Volume Block + +--*/ + +#include "Fvb.h" + +// +// Lib will ASSERT if more FVB devices than this are added to the system. +// +STATIC FVB_ENTRY *mFvbEntry; +STATIC EFI_EVENT mFvbRegistration; +STATIC BOOLEAN mEfiFvbInitialized = FALSE; +STATIC UINTN mFvbCount; + +STATIC +VOID +EFIAPI +FvbNotificationEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + Update mFvbEntry. Add new entry, or update existing entry if Fvb protocol is + reinstalled. + +Arguments: + + Event - The Event that is being processed + + Context - Event Context + +Returns: + None + +--*/ +{ + EFI_STATUS Status; + UINTN BufferSize; + EFI_HANDLE Handle; + UINTN Index; + UINTN UpdateIndex; + + while (TRUE) { + BufferSize = sizeof (Handle); + Status = gBS->LocateHandle ( + ByRegisterNotify, + &gEfiFirmwareVolumeBlockProtocolGuid, + mFvbRegistration, + &BufferSize, + &Handle + ); + if (EFI_ERROR (Status)) { + // + // Exit Path of While Loop.... + // + break; + } + + UpdateIndex = MAX_FVB_COUNT; + for (Index = 0; Index < mFvbCount; Index++) { + if (mFvbEntry[Index].Handle == Handle) { + // + // If the handle is already in the table just update the protocol + // + UpdateIndex = Index; + break; + } + } + + if (UpdateIndex == MAX_FVB_COUNT) { + // + // Use the next free slot for a new entry + // + UpdateIndex = mFvbCount++;; + mFvbEntry[UpdateIndex].Handle = Handle; + } + // + // The array does not have enough entries + // + ASSERT (UpdateIndex < MAX_FVB_COUNT); + + // + // Get the interface pointer and if it's ours, skip it + // + Status = gBS->HandleProtocol (Handle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **) &mFvbEntry[UpdateIndex].Fvb); + ASSERT_EFI_ERROR (Status); + + Status = gBS->HandleProtocol (Handle, &gEfiFvbExtensionProtocolGuid, (VOID **) &mFvbEntry[UpdateIndex].FvbExtension); + if (Status != EFI_SUCCESS) { + mFvbEntry[UpdateIndex].FvbExtension = NULL; + } + } +} + +VOID +EFIAPI +FvbVirtualAddressChangeNotifyEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + + Convert all pointers in mFvbEntry after ExitBootServices. + +Arguments: + + Event - The Event that is being processed + + Context - Event Context + +Returns: + + None + +--*/ +{ + UINTN Index; + if (mFvbEntry != NULL) { + for (Index = 0; Index < MAX_FVB_COUNT; Index++) { + if (NULL != mFvbEntry[Index].Fvb) { + EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->GetBlockSize); + EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->GetPhysicalAddress); + EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->GetVolumeAttributes); + EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->SetVolumeAttributes); + EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->Read); + EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->Write); + EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->EraseBlocks); + EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb); + } + + if (NULL != mFvbEntry[Index].FvbExtension) { + EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].FvbExtension->EraseFvbCustomBlock); + EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].FvbExtension); + } + } + + EfiConvertPointer (0x0, (VOID **) &mFvbEntry); + } +} + +EFI_STATUS +EFIAPI +FvbLibInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + Initialize globals and register Fvb Protocol notification function. + +Arguments: + None + +Returns: + EFI_SUCCESS + +--*/ +{ + UINTN Status; + mFvbCount = 0; + + Status = gBS->AllocatePool ( + EfiRuntimeServicesData, + (UINTN) sizeof (FVB_ENTRY) * MAX_FVB_COUNT, + (VOID *) &mFvbEntry + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + ZeroMem (mFvbEntry, sizeof (FVB_ENTRY) * MAX_FVB_COUNT); + + EfiCreateProtocolNotifyEvent ( + &gEfiFirmwareVolumeBlockProtocolGuid, + EFI_TPL_CALLBACK, + FvbNotificationEvent, + NULL, + &mFvbRegistration + ); + + // + // Register SetVirtualAddressMap () notify function + // + // Status = gBS->CreateEvent ( + // EFI_EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE, + // EFI_TPL_NOTIFY, + // EfiRuntimeLibFvbVirtualNotifyEvent, + // NULL, + // &mEfiFvbVirtualNotifyEvent + // ); + // ASSERT_EFI_ERROR (Status); + // + + // + // Register SetVirtualAddressMap () notify function + // + + ASSERT_EFI_ERROR (Status); + + mEfiFvbInitialized = TRUE; + + return EFI_SUCCESS; +} +// +// The following functions wrap Fvb protocol in the Runtime Lib functions. +// The Instance translates into Fvb instance. The Fvb order defined by HOBs and +// thus the sequence of FVB protocol addition define Instance. +// +// EfiFvbInitialize () must be called before any of the following functions +// must be called. +// + +EFI_STATUS +EfiFvbReadBlock ( + IN UINTN Instance, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +/*++ + +Routine Description: + Reads specified number of bytes into a buffer from the specified block + +Arguments: + Instance - The FV instance to be read from + Lba - The logical block address to be read from + Offset - Offset into the block at which to begin reading + NumBytes - Pointer that on input contains the total size of + the buffer. On output, it contains the total number + of bytes read + Buffer - Pointer to a caller allocated buffer that will be + used to hold the data read + +Returns: + + Status code + + EFI_INVALID_PARAMETER - invalid parameter + +--*/ +{ + if (Instance >= mFvbCount) { + return EFI_INVALID_PARAMETER; + } + + return mFvbEntry[Instance].Fvb->Read (mFvbEntry[Instance].Fvb, Lba, Offset, NumBytes, Buffer); +} + +EFI_STATUS +EfiFvbWriteBlock ( + IN UINTN Instance, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +/*++ + +Routine Description: + Writes specified number of bytes from the input buffer to the block + +Arguments: + Instance - The FV instance to be written to + Lba - The starting logical block index to write to + Offset - Offset into the block at which to begin writing + NumBytes - Pointer that on input contains the total size of + the buffer. On output, it contains the total number + of bytes actually written + Buffer - Pointer to a caller allocated buffer that contains + the source for the write + +Returns: + + Status code + + EFI_INVALID_PARAMETER - invalid parameter + +--*/ +{ + if (Instance >= mFvbCount) { + return EFI_INVALID_PARAMETER; + } + + return mFvbEntry[Instance].Fvb->Write (mFvbEntry[Instance].Fvb, Lba, Offset, NumBytes, Buffer); +} + +EFI_STATUS +EfiFvbEraseBlock ( + IN UINTN Instance, + IN EFI_LBA Lba + ) +/*++ + +Routine Description: + Erases and initializes a firmware volume block + +Arguments: + Instance - The FV instance to be erased + Lba - The logical block index to be erased + +Returns: + + Status code + + EFI_INVALID_PARAMETER - invalid parameter + +--*/ +{ + if (Instance >= mFvbCount) { + return EFI_INVALID_PARAMETER; + } + + return mFvbEntry[Instance].Fvb->EraseBlocks (mFvbEntry[Instance].Fvb, Lba, -1); +} + +EFI_STATUS +EfiFvbGetVolumeAttributes ( + IN UINTN Instance, + OUT EFI_FVB_ATTRIBUTES *Attributes + ) +/*++ + +Routine Description: + Retrieves attributes, insures positive polarity of attribute bits, returns + resulting attributes in output parameter + +Arguments: + Instance - The FV instance whose attributes is going to be + returned + Attributes - Output buffer which contains attributes + +Returns: + Status code + + EFI_INVALID_PARAMETER - invalid parameter + +--*/ +{ + if (Instance >= mFvbCount) { + return EFI_INVALID_PARAMETER; + } + + return mFvbEntry[Instance].Fvb->GetVolumeAttributes (mFvbEntry[Instance].Fvb, Attributes); +} + +EFI_STATUS +EfiFvbSetVolumeAttributes ( + IN UINTN Instance, + IN EFI_FVB_ATTRIBUTES Attributes + ) +/*++ + +Routine Description: + Modifies the current settings of the firmware volume according to the + input parameter, and returns the new setting of the volume + +Arguments: + Instance - The FV instance whose attributes is going to be + modified + Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES + containing the desired firmware volume settings. + On successful return, it contains the new settings + of the firmware volume + +Returns: + Status code + + EFI_INVALID_PARAMETER - invalid parameter + +--*/ +{ + if (Instance >= mFvbCount) { + return EFI_INVALID_PARAMETER; + } + + return mFvbEntry[Instance].Fvb->SetVolumeAttributes (mFvbEntry[Instance].Fvb, &Attributes); +} + +EFI_STATUS +EfiFvbGetPhysicalAddress ( + IN UINTN Instance, + OUT EFI_PHYSICAL_ADDRESS *BaseAddress + ) +/*++ + +Routine Description: + Retrieves the physical address of a memory mapped FV + +Arguments: + Instance - The FV instance whose base address is going to be + returned + BaseAddress - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS + that on successful return, contains the base address + of the firmware volume. + +Returns: + + Status code + + EFI_INVALID_PARAMETER - invalid parameter + +--*/ +{ + if (Instance >= mFvbCount) { + return EFI_INVALID_PARAMETER; + } + + return mFvbEntry[Instance].Fvb->GetPhysicalAddress (mFvbEntry[Instance].Fvb, BaseAddress); +} + +EFI_STATUS +EfiFvbGetBlockSize ( + IN UINTN Instance, + IN EFI_LBA Lba, + OUT UINTN *BlockSize, + OUT UINTN *NumOfBlocks + ) +/*++ + +Routine Description: + Retrieve the size of a logical block + +Arguments: + Instance - The FV instance whose block size is going to be + returned + Lba - Indicates which block to return the size for. + BlockSize - A pointer to a caller allocated UINTN in which + the size of the block is returned + NumOfBlocks - a 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 + +Returns: + EFI_SUCCESS - The firmware volume was read successfully and + contents are in Buffer + + EFI_INVALID_PARAMETER - invalid parameter + +--*/ +{ + if (Instance >= mFvbCount) { + return EFI_INVALID_PARAMETER; + } + + return mFvbEntry[Instance].Fvb->GetBlockSize (mFvbEntry[Instance].Fvb, Lba, BlockSize, NumOfBlocks); +} + +EFI_STATUS +EfiFvbEraseCustomBlockRange ( + IN UINTN Instance, + IN EFI_LBA StartLba, + IN UINTN OffsetStartLba, + IN EFI_LBA LastLba, + IN UINTN OffsetLastLba + ) +/*++ + +Routine Description: + Erases and initializes a specified range of a firmware volume + +Arguments: + Instance - The FV instance to be erased + StartLba - The starting logical block index to be erased + OffsetStartLba - Offset into the starting block at which to + begin erasing + LastLba - The last logical block index to be erased + OffsetLastLba - Offset into the last block at which to end erasing + +Returns: + + Status code + + EFI_INVALID_PARAMETER - invalid parameter + + EFI_UNSUPPORTED - not support + +--*/ +{ + if (Instance >= mFvbCount) { + return EFI_INVALID_PARAMETER; + } + + if (!(mFvbEntry[Instance].FvbExtension)) { + return EFI_UNSUPPORTED; + } + + if (!(mFvbEntry[Instance].FvbExtension->EraseFvbCustomBlock)) { + return EFI_UNSUPPORTED; + } + + return mFvbEntry[Instance].FvbExtension->EraseFvbCustomBlock ( + mFvbEntry[Instance].FvbExtension, + StartLba, + OffsetStartLba, + LastLba, + OffsetLastLba + ); +} diff --git a/EdkModulePkg/Library/EdkFvbServiceLib/Ipf/Fvb.c b/EdkModulePkg/Library/EdkFvbServiceLib/Ipf/Fvb.c new file mode 100644 index 0000000000..58ad6f538c --- /dev/null +++ b/EdkModulePkg/Library/EdkFvbServiceLib/Ipf/Fvb.c @@ -0,0 +1,324 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Fvb.c + +Abstract: + + Light weight lib to support Tiano Firmware Volume Block + protocol abstraction at runtime. + + All these functions convert EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID + class function to the Runtime Lib function. There is a 1 to 1 mapping. + + If you are using any of these lib functions.you must first call FvbInitialize (). + +--*/ + +EFI_STATUS +FvbLibInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + Initialize globals and register Fvb Protocol notification function. + +Arguments: + None + +Returns: + EFI_SUCCESS + +--*/ +{ + return EFI_SUCCESS; +} +// +// The following functions wrap Fvb protocol in the Runtime Lib functions. +// The Instance translates into Fvb instance. The Fvb order defined by HOBs and +// thus the sequence of FVB protocol addition define Instance. +// +// EfiFvbInitialize () must be called before any of the following functions +// must be called. +// +EFI_STATUS +EfiFvbReadBlock ( + IN UINTN Instance, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +/*++ + +Routine Description: + Reads specified number of bytes into a buffer from the specified block + +Arguments: + Instance - The FV instance to be read from + Lba - The logical block address to be read from + Offset - Offset into the block at which to begin reading + NumBytes - Pointer that on input contains the total size of + the buffer. On output, it contains the total number + of bytes read + Buffer - Pointer to a caller allocated buffer that will be + used to hold the data read + +Returns: + Status code + +--*/ +{ + EFI_GUID Guid = EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID; + + return EfiCallEsalService (&Guid, Read, Instance, Lba, Offset, (UINT64) NumBytes, (UINT64) Buffer, 0, 0).Status; +} + +EFI_STATUS +EfiFvbWriteBlock ( + IN UINTN Instance, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +/*++ + +Routine Description: + Writes specified number of bytes from the input buffer to the block + +Arguments: + Instance - The FV instance to be written to + Lba - The starting logical block index to write to + Offset - Offset into the block at which to begin writing + NumBytes - Pointer that on input contains the total size of + the buffer. On output, it contains the total number + of bytes actually written + Buffer - Pointer to a caller allocated buffer that contains + the source for the write + +Returns: + Status code + +--*/ +{ + EFI_GUID Guid = EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID; + + return EfiCallEsalService (&Guid, Write, Instance, Lba, Offset, (UINT64) NumBytes, (UINT64) Buffer, 0, 0).Status; +} + +EFI_STATUS +EfiFvbEraseBlock ( + IN UINTN Instance, + IN UINTN Lba + ) +/*++ + +Routine Description: + Erases and initializes a firmware volume block + +Arguments: + Instance - The FV instance to be erased + Lba - The logical block index to be erased + +Returns: + Status code + +--*/ +{ + EFI_GUID Guid = EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID; + + return EfiCallEsalService (&Guid, EraseBlock, Instance, Lba, 0, 0, 0, 0, 0).Status; +} + +EFI_STATUS +EfiFvbGetVolumeAttributes ( + IN UINTN Instance, + OUT EFI_FVB_ATTRIBUTES *Attributes + ) +/*++ + +Routine Description: + Retrieves attributes, insures positive polarity of attribute bits, returns + resulting attributes in output parameter + +Arguments: + Instance - The FV instance whose attributes is going to be + returned + Attributes - Output buffer which contains attributes + +Returns: + Status code + +--*/ +{ + EFI_GUID Guid = EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID; + + return EfiCallEsalService (&Guid, SetVolumeAttributes, Instance, (UINT64) Attributes, 0, 0, 0, 0, 0).Status; +} + +EFI_STATUS +EfiFvbSetVolumeAttributes ( + IN UINTN Instance, + IN EFI_FVB_ATTRIBUTES Attributes + ) +/*++ + +Routine Description: + Modifies the current settings of the firmware volume according to the + input parameter, and returns the new setting of the volume + +Arguments: + Instance - The FV instance whose attributes is going to be + modified + Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES + containing the desired firmware volume settings. + On successful return, it contains the new settings + of the firmware volume + +Returns: + Status code + +--*/ +{ + EFI_GUID Guid = EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID; + + return EfiCallEsalService (&Guid, SetVolumeAttributes, Instance, (UINT64) Attributes, 0, 0, 0, 0, 0).Status; +} + +EFI_STATUS +EfiFvbGetPhysicalAddress ( + IN UINTN Instance, + OUT EFI_PHYSICAL_ADDRESS *BaseAddress + ) +/*++ + +Routine Description: + Retrieves the physical address of a memory mapped FV + +Arguments: + Instance - The FV instance whose base address is going to be + returned + BaseAddress - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS + that on successful return, contains the base address + of the firmware volume. + +Returns: + Status code + +--*/ +{ + EFI_GUID Guid = EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID; + + return EfiCallEsalService (&Guid, GetPhysicalAddress, Instance, (UINT64) BaseAddress, 0, 0, 0, 0, 0).Status; +} + +EFI_STATUS +EfiFvbGetBlockSize ( + IN UINTN Instance, + IN EFI_LBA Lba, + OUT UINTN *BlockSize, + OUT UINTN *NumOfBlocks + ) +/*++ + +Routine Description: + Retrieve the size of a logical block + +Arguments: + Instance - The FV instance whose block size is going to be + returned + Lba - Indicates which block to return the size for. + BlockSize - A pointer to a caller allocated UINTN in which + the size of the block is returned + NumOfBlocks - a 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 + +Returns: + EFI_SUCCESS - The firmware volume was read successfully and + contents are in Buffer + +--*/ +{ + EFI_GUID Guid = EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID; + + return EfiCallEsalService ( + &Guid, + GetBlockSize, + Instance, + Lba, + (UINT64) BlockSize, + (UINT64) NumOfBlocks, + 0, + 0, + 0 + ).Status; +} + +EFI_STATUS +EfiFvbEraseCustomBlockRange ( + IN UINTN Instance, + IN EFI_LBA StartLba, + IN UINTN OffsetStartLba, + IN EFI_LBA LastLba, + IN UINTN OffsetLastLba + ) +/*++ + +Routine Description: + Erases and initializes a specified range of a firmware volume + +Arguments: + Instance - The FV instance to be erased + StartLba - The starting logical block index to be erased + OffsetStartLba - Offset into the starting block at which to + begin erasing + LastLba - The last logical block index to be erased + OffsetLastLba - Offset into the last block at which to end erasing + +Returns: + Status code + +--*/ +{ + EFI_GUID Guid = EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID; + + return EfiCallEsalService ( + &Guid, + EraseCustomBlockRange, + Instance, + StartLba, + OffsetStartLba, + LastLba, + OffsetLastLba, + 0, + 0 + ).Status; +} + + +/** + BugBug: Can't turn this off in the current MSA so we need a stub +**/ +VOID +EFIAPI +FvbVirtualAddressChangeNotifyEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ +} diff --git a/EdkModulePkg/Library/EdkFvbServiceLib/build.xml b/EdkModulePkg/Library/EdkFvbServiceLib/build.xml new file mode 100644 index 0000000000..ebbb303b70 --- /dev/null +++ b/EdkModulePkg/Library/EdkFvbServiceLib/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Library/EdkFvbServiceLib/x64/Fvb.c b/EdkModulePkg/Library/EdkFvbServiceLib/x64/Fvb.c new file mode 100644 index 0000000000..76ddfa80d4 --- /dev/null +++ b/EdkModulePkg/Library/EdkFvbServiceLib/x64/Fvb.c @@ -0,0 +1,536 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Fvb.c + +Abstract: + + Firmware Volume Block Protocol Runtime Abstraction + + mFvbEntry is an array of Handle Fvb pairs. The Fvb Lib Instance matches the + index in the mFvbEntry array. This should be the same sequence as the FVB's + were described in the HOB. We have to remember the handle so we can tell if + the protocol has been reinstalled and it needs updateing. + + If you are using any of these lib functions.you must first call FvbInitialize (). + +Key: + FVB - Firmware Volume Block + +--*/ + +#include "Fvb.h" + +// +// Lib will ASSERT if more FVB devices than this are added to the system. +// +STATIC FVB_ENTRY *mFvbEntry; +STATIC EFI_EVENT mFvbVirtualNotifyEvent; +STATIC EFI_EVENT mFvbRegistration; +STATIC EFI_EVENT mEfiFvbVirtualNotifyEvent; +STATIC BOOLEAN mEfiFvbInitialized = FALSE; +STATIC UINTN mFvbCount; + +STATIC +VOID +EFIAPI +FvbNotificationEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + Update mFvbEntry. Add new entry, or update existing entry if Fvb protocol is + reinstalled. + +Arguments: + + Event - The Event that is being processed + + Context - Event Context + +Returns: + None + +--*/ +{ + EFI_STATUS Status; + UINTN BufferSize; + EFI_HANDLE Handle; + UINTN Index; + UINTN UpdateIndex; + + while (TRUE) { + BufferSize = sizeof (Handle); + Status = gBS->LocateHandle ( + ByRegisterNotify, + &gEfiFirmwareVolumeBlockProtocolGuid, + mFvbRegistration, + &BufferSize, + &Handle + ); + if (EFI_ERROR (Status)) { + // + // Exit Path of While Loop.... + // + break; + } + + UpdateIndex = MAX_FVB_COUNT; + for (Index = 0; Index < mFvbCount; Index++) { + if (mFvbEntry[Index].Handle == Handle) { + // + // If the handle is already in the table just update the protocol + // + UpdateIndex = Index; + break; + } + } + + if (UpdateIndex == MAX_FVB_COUNT) { + // + // Use the next free slot for a new entry + // + UpdateIndex = mFvbCount++;; + mFvbEntry[UpdateIndex].Handle = Handle; + } + // + // The array does not have enough entries + // + ASSERT (UpdateIndex < MAX_FVB_COUNT); + + // + // Get the interface pointer and if it's ours, skip it + // + Status = gBS->HandleProtocol (Handle, &gEfiFirmwareVolumeBlockProtocolGuid, &mFvbEntry[UpdateIndex].Fvb); + ASSERT_EFI_ERROR (Status); + + Status = gBS->HandleProtocol (Handle, &gEfiFvbExtensionProtocolGuid, &mFvbEntry[UpdateIndex].FvbExtension); + if (Status != EFI_SUCCESS) { + mFvbEntry[UpdateIndex].FvbExtension = NULL; + } + } +} + +VOID +EFIAPI +FvbVirtualAddressChangeNotifyEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + + Convert all pointers in mFvbEntry after ExitBootServices. + +Arguments: + + Event - The Event that is being processed + + Context - Event Context + +Returns: + + None + +--*/ +{ + UINTN Index; + if (mFvbEntry != NULL) { + for (Index = 0; Index < MAX_FVB_COUNT; Index++) { + if (NULL != mFvbEntry[Index].Fvb) { + EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->GetBlockSize); + EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->GetPhysicalAddress); + EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->GetVolumeAttributes); + EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->SetVolumeAttributes); + EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->Read); + EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->Write); + EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->EraseBlocks); + EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb); + } + + if (NULL != mFvbEntry[Index].FvbExtension) { + EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].FvbExtension->EraseFvbCustomBlock); + EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].FvbExtension); + } + } + + EfiConvertPointer (0x0, (VOID **) &mFvbEntry); + } +} + +EFI_STATUS +EFIAPI +FvbLibInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + Initialize globals and register Fvb Protocol notification function. + +Arguments: + None + +Returns: + EFI_SUCCESS + +--*/ +{ + UINTN Status; + mFvbCount = 0; + + Status = gBS->AllocatePool ( + EfiRuntimeServicesData, + (UINTN) sizeof (FVB_ENTRY) * MAX_FVB_COUNT, + (VOID *) &mFvbEntry + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + ZeroMem (mFvbEntry, sizeof (FVB_ENTRY) * MAX_FVB_COUNT); + + EfiCreateProtocolNotifyEvent ( + &gEfiFirmwareVolumeBlockProtocolGuid, + EFI_TPL_CALLBACK, + FvbNotificationEvent, + NULL, + &mFvbRegistration + ); + + // + // Register SetVirtualAddressMap () notify function + // + // Status = gBS->CreateEvent ( + // EFI_EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE, + // EFI_TPL_NOTIFY, + // EfiRuntimeLibFvbVirtualNotifyEvent, + // NULL, + // &mEfiFvbVirtualNotifyEvent + // ); + // ASSERT_EFI_ERROR (Status); + // + + // + // Register SetVirtualAddressMap () notify function + // + + ASSERT_EFI_ERROR (Status); + + mEfiFvbInitialized = TRUE; + + return EFI_SUCCESS; +} +// +// The following functions wrap Fvb protocol in the Runtime Lib functions. +// The Instance translates into Fvb instance. The Fvb order defined by HOBs and +// thus the sequence of FVB protocol addition define Instance. +// +// EfiFvbInitialize () must be called before any of the following functions +// must be called. +// + +EFI_STATUS +EfiFvbReadBlock ( + IN UINTN Instance, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +/*++ + +Routine Description: + Reads specified number of bytes into a buffer from the specified block + +Arguments: + Instance - The FV instance to be read from + Lba - The logical block address to be read from + Offset - Offset into the block at which to begin reading + NumBytes - Pointer that on input contains the total size of + the buffer. On output, it contains the total number + of bytes read + Buffer - Pointer to a caller allocated buffer that will be + used to hold the data read + +Returns: + + Status code + + EFI_INVALID_PARAMETER - invalid parameter + +--*/ +{ + if (Instance >= mFvbCount) { + return EFI_INVALID_PARAMETER; + } + + return mFvbEntry[Instance].Fvb->Read (mFvbEntry[Instance].Fvb, Lba, Offset, NumBytes, Buffer); +} + +EFI_STATUS +EfiFvbWriteBlock ( + IN UINTN Instance, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +/*++ + +Routine Description: + Writes specified number of bytes from the input buffer to the block + +Arguments: + Instance - The FV instance to be written to + Lba - The starting logical block index to write to + Offset - Offset into the block at which to begin writing + NumBytes - Pointer that on input contains the total size of + the buffer. On output, it contains the total number + of bytes actually written + Buffer - Pointer to a caller allocated buffer that contains + the source for the write + +Returns: + + Status code + + EFI_INVALID_PARAMETER - invalid parameter + +--*/ +{ + if (Instance >= mFvbCount) { + return EFI_INVALID_PARAMETER; + } + + return mFvbEntry[Instance].Fvb->Write (mFvbEntry[Instance].Fvb, Lba, Offset, NumBytes, Buffer); +} + +EFI_STATUS +EfiFvbEraseBlock ( + IN UINTN Instance, + IN EFI_LBA Lba + ) +/*++ + +Routine Description: + Erases and initializes a firmware volume block + +Arguments: + Instance - The FV instance to be erased + Lba - The logical block index to be erased + +Returns: + + Status code + + EFI_INVALID_PARAMETER - invalid parameter + +--*/ +{ + if (Instance >= mFvbCount) { + return EFI_INVALID_PARAMETER; + } + + return mFvbEntry[Instance].Fvb->EraseBlocks (mFvbEntry[Instance].Fvb, Lba, -1); +} + +EFI_STATUS +EfiFvbGetVolumeAttributes ( + IN UINTN Instance, + OUT EFI_FVB_ATTRIBUTES *Attributes + ) +/*++ + +Routine Description: + Retrieves attributes, insures positive polarity of attribute bits, returns + resulting attributes in output parameter + +Arguments: + Instance - The FV instance whose attributes is going to be + returned + Attributes - Output buffer which contains attributes + +Returns: + Status code + + EFI_INVALID_PARAMETER - invalid parameter + +--*/ +{ + if (Instance >= mFvbCount) { + return EFI_INVALID_PARAMETER; + } + + return mFvbEntry[Instance].Fvb->GetVolumeAttributes (mFvbEntry[Instance].Fvb, Attributes); +} + +EFI_STATUS +EfiFvbSetVolumeAttributes ( + IN UINTN Instance, + IN EFI_FVB_ATTRIBUTES Attributes + ) +/*++ + +Routine Description: + Modifies the current settings of the firmware volume according to the + input parameter, and returns the new setting of the volume + +Arguments: + Instance - The FV instance whose attributes is going to be + modified + Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES + containing the desired firmware volume settings. + On successful return, it contains the new settings + of the firmware volume + +Returns: + Status code + + EFI_INVALID_PARAMETER - invalid parameter + +--*/ +{ + if (Instance >= mFvbCount) { + return EFI_INVALID_PARAMETER; + } + + return mFvbEntry[Instance].Fvb->SetVolumeAttributes (mFvbEntry[Instance].Fvb, &Attributes); +} + +EFI_STATUS +EfiFvbGetPhysicalAddress ( + IN UINTN Instance, + OUT EFI_PHYSICAL_ADDRESS *BaseAddress + ) +/*++ + +Routine Description: + Retrieves the physical address of a memory mapped FV + +Arguments: + Instance - The FV instance whose base address is going to be + returned + BaseAddress - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS + that on successful return, contains the base address + of the firmware volume. + +Returns: + + Status code + + EFI_INVALID_PARAMETER - invalid parameter + +--*/ +{ + if (Instance >= mFvbCount) { + return EFI_INVALID_PARAMETER; + } + + return mFvbEntry[Instance].Fvb->GetPhysicalAddress (mFvbEntry[Instance].Fvb, BaseAddress); +} + +EFI_STATUS +EfiFvbGetBlockSize ( + IN UINTN Instance, + IN EFI_LBA Lba, + OUT UINTN *BlockSize, + OUT UINTN *NumOfBlocks + ) +/*++ + +Routine Description: + Retrieve the size of a logical block + +Arguments: + Instance - The FV instance whose block size is going to be + returned + Lba - Indicates which block to return the size for. + BlockSize - A pointer to a caller allocated UINTN in which + the size of the block is returned + NumOfBlocks - a 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 + +Returns: + EFI_SUCCESS - The firmware volume was read successfully and + contents are in Buffer + + EFI_INVALID_PARAMETER - invalid parameter + +--*/ +{ + if (Instance >= mFvbCount) { + return EFI_INVALID_PARAMETER; + } + + return mFvbEntry[Instance].Fvb->GetBlockSize (mFvbEntry[Instance].Fvb, Lba, BlockSize, NumOfBlocks); +} + +EFI_STATUS +EfiFvbEraseCustomBlockRange ( + IN UINTN Instance, + IN EFI_LBA StartLba, + IN UINTN OffsetStartLba, + IN EFI_LBA LastLba, + IN UINTN OffsetLastLba + ) +/*++ + +Routine Description: + Erases and initializes a specified range of a firmware volume + +Arguments: + Instance - The FV instance to be erased + StartLba - The starting logical block index to be erased + OffsetStartLba - Offset into the starting block at which to + begin erasing + LastLba - The last logical block index to be erased + OffsetLastLba - Offset into the last block at which to end erasing + +Returns: + + Status code + + EFI_INVALID_PARAMETER - invalid parameter + + EFI_UNSUPPORTED - not support + +--*/ +{ + if (Instance >= mFvbCount) { + return EFI_INVALID_PARAMETER; + } + + if (!(mFvbEntry[Instance].FvbExtension)) { + return EFI_UNSUPPORTED; + } + + if (!(mFvbEntry[Instance].FvbExtension->EraseFvbCustomBlock)) { + return EFI_UNSUPPORTED; + } + + return mFvbEntry[Instance].FvbExtension->EraseFvbCustomBlock ( + mFvbEntry[Instance].FvbExtension, + StartLba, + OffsetStartLba, + LastLba, + OffsetLastLba + ); +} diff --git a/EdkModulePkg/Library/EdkGraphicsLib/EdkGraphicsLib.mbd b/EdkModulePkg/Library/EdkGraphicsLib/EdkGraphicsLib.mbd new file mode 100644 index 0000000000..4758d6b192 --- /dev/null +++ b/EdkModulePkg/Library/EdkGraphicsLib/EdkGraphicsLib.mbd @@ -0,0 +1,30 @@ + + + + + EdkGraphicsLib + 08c1a0e4-1208-47f8-a2c5-f42eabee653a + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + diff --git a/EdkModulePkg/Library/EdkGraphicsLib/EdkGraphicsLib.msa b/EdkModulePkg/Library/EdkGraphicsLib/EdkGraphicsLib.msa new file mode 100644 index 0000000000..03b4f51026 --- /dev/null +++ b/EdkModulePkg/Library/EdkGraphicsLib/EdkGraphicsLib.msa @@ -0,0 +1,61 @@ + + + + + EdkGraphicsLib + DXE_DRIVER + LIBRARY + 08c1a0e4-1208-47f8-a2c5-f42eabee653a + 0 + Graphics Library for UEFI drivers + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + EdkGraphicsLib + UefiLib + PrintLib + BaseLib + MemoryAllocationLib + UefiBootServicesTableLib + + + Graphics.c + + + MdePkg + EdkModulePkg + + + OEMBadging + FirmwareVolume + ConsoleControl + UgaDraw + SimpleTextOut + + + + Bmp + + + diff --git a/EdkModulePkg/Library/EdkGraphicsLib/Graphics.c b/EdkModulePkg/Library/EdkGraphicsLib/Graphics.c new file mode 100644 index 0000000000..01c612abd3 --- /dev/null +++ b/EdkModulePkg/Library/EdkGraphicsLib/Graphics.c @@ -0,0 +1,780 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Graphics.c + +Abstract: + + Support for Basic Graphics operations. + + BugBug: Currently *.BMP files are supported. This will be replaced + when Tiano graphics format is supported. + +--*/ + +EFI_STATUS +GetGraphicsBitMapFromFV ( + IN EFI_GUID *FileNameGuid, + OUT VOID **Image, + OUT UINTN *ImageSize + ) +/*++ + +Routine Description: + + Return the graphics image file named FileNameGuid into Image and return it's + size in ImageSize. All Firmware Volumes (FV) in the system are searched for the + file name. + +Arguments: + + FileNameGuid - File Name of graphics file in the FV(s). + + Image - Pointer to pointer to return graphics image. If NULL, a + buffer will be allocated. + + ImageSize - Size of the graphics Image in bytes. Zero if no image found. + + +Returns: + + EFI_SUCCESS - Image and ImageSize are valid. + EFI_BUFFER_TOO_SMALL - Image not big enough. ImageSize has required size + EFI_NOT_FOUND - FileNameGuid not found + +--*/ +{ + EFI_STATUS Status; + UINTN FvProtocolCount; + EFI_HANDLE *FvHandles; + EFI_FIRMWARE_VOLUME_PROTOCOL *Fv; + UINTN Index; + UINT32 AuthenticationStatus; + + + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiFirmwareVolumeProtocolGuid, + NULL, + &FvProtocolCount, + &FvHandles + ); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + for (Index = 0; Index < FvProtocolCount; Index++) { + Status = gBS->HandleProtocol ( + FvHandles[Index], + &gEfiFirmwareVolumeProtocolGuid, + (VOID **) &Fv + ); + + // + // Assuming Image and ImageSize are correct on input. + // + Status = Fv->ReadSection ( + Fv, + &gEfiDefaultBmpLogoGuid, + EFI_SECTION_RAW, + 0, + Image, + ImageSize, + &AuthenticationStatus + ); + if (!EFI_ERROR (Status)) { + return EFI_SUCCESS; + } else if (Status == EFI_BUFFER_TOO_SMALL) { + // + // ImageSize updated to needed size so return + // + return EFI_BUFFER_TOO_SMALL; + } + } + + return EFI_NOT_FOUND; +} + + +EFI_STATUS +ConvertBmpToUgaBlt ( + IN VOID *BmpImage, + IN UINTN BmpImageSize, + IN OUT VOID **UgaBlt, + IN OUT UINTN *UgaBltSize, + OUT UINTN *PixelHeight, + OUT UINTN *PixelWidth + ) +/*++ + +Routine Description: + + Convert a *.BMP graphics image to a UGA blt buffer. If a NULL UgaBlt buffer + is passed in a UgaBlt buffer will be allocated by this routine. If a UgaBlt + buffer is passed in it will be used if it is big enough. + +Arguments: + + BmpImage - Pointer to BMP file + + BmpImageSize - Number of bytes in BmpImage + + UgaBlt - Buffer containing UGA version of BmpImage. + + UgaBltSize - Size of UgaBlt in bytes. + + PixelHeight - Height of UgaBlt/BmpImage in pixels + + PixelWidth - Width of UgaBlt/BmpImage in pixels + + +Returns: + + EFI_SUCCESS - UgaBlt and UgaBltSize are returned. + EFI_UNSUPPORTED - BmpImage is not a valid *.BMP image + EFI_BUFFER_TOO_SMALL - The passed in UgaBlt buffer is not big enough. + UgaBltSize will contain the required size. + EFI_OUT_OF_RESOURCES - No enough buffer to allocate + +--*/ +{ + UINT8 *Image; + UINT8 *ImageHeader; + BMP_IMAGE_HEADER *BmpHeader; + BMP_COLOR_MAP *BmpColorMap; + EFI_UGA_PIXEL *BltBuffer; + EFI_UGA_PIXEL *Blt; + UINTN BltBufferSize; + UINTN Index; + UINTN Height; + UINTN Width; + UINTN ImageIndex; + + BmpHeader = (BMP_IMAGE_HEADER *) BmpImage; + if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M') { + return EFI_UNSUPPORTED; + } + + if (BmpHeader->CompressionType != 0) { + return EFI_UNSUPPORTED; + } + + // + // Calculate Color Map offset in the image. + // + Image = BmpImage; + BmpColorMap = (BMP_COLOR_MAP *) (Image + sizeof (BMP_IMAGE_HEADER)); + + // + // Calculate graphics image data address in the image + // + Image = ((UINT8 *) BmpImage) + BmpHeader->ImageOffset; + ImageHeader = Image; + + BltBufferSize = BmpHeader->PixelWidth * BmpHeader->PixelHeight * sizeof (EFI_UGA_PIXEL); + if (*UgaBlt == NULL) { + *UgaBltSize = BltBufferSize; + *UgaBlt = AllocatePool (*UgaBltSize); + if (*UgaBlt == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } else { + if (*UgaBltSize < BltBufferSize) { + *UgaBltSize = BltBufferSize; + return EFI_BUFFER_TOO_SMALL; + } + } + + *PixelWidth = BmpHeader->PixelWidth; + *PixelHeight = BmpHeader->PixelHeight; + + // + // Convert image from BMP to Blt buffer format + // + BltBuffer = *UgaBlt; + for (Height = 0; Height < BmpHeader->PixelHeight; Height++) { + Blt = &BltBuffer[(BmpHeader->PixelHeight - Height - 1) * BmpHeader->PixelWidth]; + for (Width = 0; Width < BmpHeader->PixelWidth; Width++, Image++, Blt++) { + switch (BmpHeader->BitPerPixel) { + case 1: + // + // Convert 1bit BMP to 24-bit color + // + for (Index = 0; Index < 8 && Width < BmpHeader->PixelWidth; Index++) { + Blt->Red = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Red; + Blt->Green = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Green; + Blt->Blue = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Blue; + Blt++; + Width++; + } + + Blt --; + Width --; + break; + + case 4: + // + // Convert BMP Palette to 24-bit color + // + Index = (*Image) >> 4; + Blt->Red = BmpColorMap[Index].Red; + Blt->Green = BmpColorMap[Index].Green; + Blt->Blue = BmpColorMap[Index].Blue; + if (Width < (BmpHeader->PixelWidth - 1)) { + Blt++; + Width++; + Index = (*Image) & 0x0f; + Blt->Red = BmpColorMap[Index].Red; + Blt->Green = BmpColorMap[Index].Green; + Blt->Blue = BmpColorMap[Index].Blue; + } + break; + + case 8: + // + // Convert BMP Palette to 24-bit color + // + Blt->Red = BmpColorMap[*Image].Red; + Blt->Green = BmpColorMap[*Image].Green; + Blt->Blue = BmpColorMap[*Image].Blue; + break; + + case 24: + Blt->Blue = *Image++; + Blt->Green = *Image++; + Blt->Red = *Image; + break; + + default: + return EFI_UNSUPPORTED; + break; + }; + + } + + ImageIndex = (UINTN) (Image - ImageHeader); + if ((ImageIndex % 4) != 0) { + // + // Bmp Image starts each row on a 32-bit boundary! + // + Image = Image + (4 - (ImageIndex % 4)); + } + } + + return EFI_SUCCESS; +} + + +EFI_STATUS +LockKeyboards ( + IN CHAR16 *Password + ) +/*++ + +Routine Description: + Use Console Control Protocol to lock the Console In Spliter virtual handle. + This is the ConInHandle and ConIn handle in the EFI system table. All key + presses will be ignored until the Password is typed in. The only way to + disable the password is to type it in to a ConIn device. + +Arguments: + Password - Password used to lock ConIn device + + +Returns: + + EFI_SUCCESS - ConsoleControl has been flipped to graphics and logo + displayed. + EFI_UNSUPPORTED - Logo not found + +--*/ +{ + EFI_STATUS Status; + EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl; + + Status = gBS->LocateProtocol (&gEfiConsoleControlProtocolGuid, NULL, (VOID **) &ConsoleControl); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Status = ConsoleControl->LockStdIn (ConsoleControl, Password); + return Status; +} + + +EFI_STATUS +EnableQuietBoot ( + IN EFI_GUID *LogoFile + ) +/*++ + +Routine Description: + + Use Console Control to turn off UGA based Simple Text Out consoles from going + to the UGA device. Put up LogoFile on every UGA device that is a console + +Arguments: + + LogoFile - File name of logo to display on the center of the screen. + + +Returns: + + EFI_SUCCESS - ConsoleControl has been flipped to graphics and logo + displayed. + EFI_UNSUPPORTED - Logo not found + +--*/ +{ + EFI_STATUS Status; + EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl; + EFI_UGA_DRAW_PROTOCOL *UgaDraw; + EFI_OEM_BADGING_PROTOCOL *Badging; + UINT32 SizeOfX; + UINT32 SizeOfY; + UINT32 ColorDepth; + UINT32 RefreshRate; + INTN DestX; + INTN DestY; + + UINT8 *ImageData; + UINTN ImageSize; + EFI_UGA_PIXEL *UgaBlt; + UINTN UgaBltSize; + + UINT32 Instance; + EFI_BADGING_FORMAT Format; + EFI_BADGING_DISPLAY_ATTRIBUTE Attribute; + UINTN CoordinateX; + UINTN CoordinateY; + UINTN Height; + UINTN Width; + + Status = gBS->LocateProtocol (&gEfiConsoleControlProtocolGuid, NULL, (VOID **) &ConsoleControl); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiUgaDrawProtocolGuid, (VOID **) &UgaDraw); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Badging = NULL; + Status = gBS->LocateProtocol (&gEfiOEMBadgingProtocolGuid, NULL, (VOID **) &Badging); + + ConsoleControl->SetMode (ConsoleControl, EfiConsoleControlScreenGraphics); + + Status = UgaDraw->GetMode (UgaDraw, &SizeOfX, &SizeOfY, &ColorDepth, &RefreshRate); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Instance = 0; + while (1) { + ImageData = NULL; + ImageSize = 0; + + if (Badging != NULL) { + Status = Badging->GetImage ( + Badging, + &Instance, + &Format, + &ImageData, + &ImageSize, + &Attribute, + &CoordinateX, + &CoordinateY + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Currently only support BMP format + // + if (Format != EfiBadgingFormatBMP) { + gBS->FreePool (ImageData); + continue; + } + } else { + Status = GetGraphicsBitMapFromFV (LogoFile, (VOID **) &ImageData, &ImageSize); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + CoordinateX = 0; + CoordinateY = 0; + Attribute = EfiBadgingDisplayAttributeCenter; + } + + UgaBlt = NULL; + Status = ConvertBmpToUgaBlt ( + ImageData, + ImageSize, + (VOID **) &UgaBlt, + &UgaBltSize, + &Height, + &Width + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (ImageData); + continue; + } + + switch (Attribute) { + case EfiBadgingDisplayAttributeLeftTop: + DestX = CoordinateX; + DestY = CoordinateY; + break; + + case EfiBadgingDisplayAttributeCenterTop: + DestX = (SizeOfX - Width) / 2; + DestY = CoordinateY; + break; + + case EfiBadgingDisplayAttributeRightTop: + DestX = (SizeOfX - Width - CoordinateX); + DestY = CoordinateY;; + break; + + case EfiBadgingDisplayAttributeCenterRight: + DestX = (SizeOfX - Width - CoordinateX); + DestY = (SizeOfY - Height) / 2; + break; + + case EfiBadgingDisplayAttributeRightBottom: + DestX = (SizeOfX - Width - CoordinateX); + DestY = (SizeOfY - Height - CoordinateY); + break; + + case EfiBadgingDisplayAttributeCenterBottom: + DestX = (SizeOfX - Width) / 2; + DestY = (SizeOfY - Height - CoordinateY); + break; + + case EfiBadgingDisplayAttributeLeftBottom: + DestX = CoordinateX; + DestY = (SizeOfY - Height - CoordinateY); + break; + + case EfiBadgingDisplayAttributeCenterLeft: + DestX = CoordinateX; + DestY = (SizeOfY - Height) / 2; + break; + + case EfiBadgingDisplayAttributeCenter: + DestX = (SizeOfX - Width) / 2; + DestY = (SizeOfY - Height) / 2; + break; + + default: + DestX = CoordinateX; + DestY = CoordinateY; + break; + } + + if ((DestX >= 0) && (DestY >= 0)) { + Status = UgaDraw->Blt ( + UgaDraw, + UgaBlt, + EfiUgaBltBufferToVideo, + 0, + 0, + (UINTN) DestX, + (UINTN) DestY, + Width, + Height, + Width * sizeof (EFI_UGA_PIXEL) + ); + } + + gBS->FreePool (ImageData); + gBS->FreePool (UgaBlt); + + if (Badging == NULL) { + break; + } + } + + return Status; +} + + +EFI_STATUS +DisableQuietBoot ( + VOID + ) +/*++ + +Routine Description: + + Use Console Control to turn on UGA based Simple Text Out consoles. The UGA + Simple Text Out screens will now be synced up with all non UGA output devices + +Arguments: + + NONE + +Returns: + + EFI_SUCCESS - UGA devices are back in text mode and synced up. + EFI_UNSUPPORTED - Logo not found + +--*/ +{ + EFI_STATUS Status; + EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl; + + Status = gBS->LocateProtocol (&gEfiConsoleControlProtocolGuid, NULL, (VOID **) &ConsoleControl); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + return ConsoleControl->SetMode (ConsoleControl, EfiConsoleControlScreenText); +} + +static EFI_UGA_PIXEL mEfiColors[16] = { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x98, 0x00, 0x00, 0x00 }, + { 0x00, 0x98, 0x00, 0x00 }, + { 0x98, 0x98, 0x00, 0x00 }, + { 0x00, 0x00, 0x98, 0x00 }, + { 0x98, 0x00, 0x98, 0x00 }, + { 0x00, 0x98, 0x98, 0x00 }, + { 0x98, 0x98, 0x98, 0x00 }, + { 0x10, 0x10, 0x10, 0x00 }, + { 0xff, 0x10, 0x10, 0x00 }, + { 0x10, 0xff, 0x10, 0x00 }, + { 0xff, 0xff, 0x10, 0x00 }, + { 0x10, 0x10, 0xff, 0x00 }, + { 0xf0, 0x10, 0xff, 0x00 }, + { 0x10, 0xff, 0xff, 0x00 }, + { 0xff, 0xff, 0xff, 0x00 } +}; + +STATIC +UINTN +_IPrint ( + IN EFI_UGA_DRAW_PROTOCOL *UgaDraw, + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *Sto, + IN UINTN X, + IN UINTN Y, + IN EFI_UGA_PIXEL *Foreground, + IN EFI_UGA_PIXEL *Background, + IN CHAR16 *fmt, + IN VA_LIST args + ) +/*++ + +Routine Description: + + Display string worker for: Print, PrintAt, IPrint, IPrintAt + +Arguments: + + UgaDraw - UGA draw protocol interface + + Sto - Simple text out protocol interface + + X - X coordinate to start printing + + Y - Y coordinate to start printing + + Foreground - Foreground color + + Background - Background color + + fmt - Format string + + args - Print arguments + +Returns: + + EFI_SUCCESS - success + EFI_OUT_OF_RESOURCES - out of resources + +--*/ +{ + VOID *Buffer; + EFI_STATUS Status; + UINT16 GlyphWidth; + UINT32 GlyphStatus; + UINT16 StringIndex; + UINTN Index; + CHAR16 *UnicodeWeight; + EFI_NARROW_GLYPH *Glyph; + EFI_HII_PROTOCOL *Hii; + EFI_UGA_PIXEL *LineBuffer; + UINT32 HorizontalResolution; + UINT32 VerticalResolution; + UINT32 ColorDepth; + UINT32 RefreshRate; + + GlyphStatus = 0; + + // + // For now, allocate an arbitrarily long buffer + // + Buffer = AllocateZeroPool (0x10000); + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + UgaDraw->GetMode (UgaDraw, &HorizontalResolution, &VerticalResolution, &ColorDepth, &RefreshRate); + + LineBuffer = AllocatePool (sizeof (EFI_UGA_PIXEL) * HorizontalResolution * GLYPH_WIDTH * GLYPH_HEIGHT); + if (LineBuffer == NULL) { + gBS->FreePool (Buffer); + return EFI_OUT_OF_RESOURCES; + } + + Status = gBS->LocateProtocol (&gEfiHiiProtocolGuid, NULL, (VOID **) &Hii); + if (EFI_ERROR (Status)) { + goto Error; + } + + UnicodeVSPrint (Buffer, 0x10000, fmt, args); + + UnicodeWeight = (CHAR16 *) Buffer; + + for (Index = 0; UnicodeWeight[Index] != 0; Index++) { + if (UnicodeWeight[Index] == CHAR_BACKSPACE || + UnicodeWeight[Index] == CHAR_LINEFEED || + UnicodeWeight[Index] == CHAR_CARRIAGE_RETURN) { + UnicodeWeight[Index] = 0; + } + } + + for (Index = 0; Index < StrLen (Buffer); Index++) { + StringIndex = (UINT16) Index; + Status = Hii->GetGlyph (Hii, UnicodeWeight, &StringIndex, (UINT8 **) &Glyph, &GlyphWidth, &GlyphStatus); + if (EFI_ERROR (Status)) { + goto Error; + } + + if (Foreground == NULL || Background == NULL) { + Status = Hii->GlyphToBlt ( + Hii, + (UINT8 *) Glyph, + mEfiColors[Sto->Mode->Attribute & 0x0f], + mEfiColors[Sto->Mode->Attribute >> 4], + StrLen (Buffer), + GlyphWidth, + GLYPH_HEIGHT, + &LineBuffer[Index * GLYPH_WIDTH] + ); + } else { + Status = Hii->GlyphToBlt ( + Hii, + (UINT8 *) Glyph, + *Foreground, + *Background, + StrLen (Buffer), + GlyphWidth, + GLYPH_HEIGHT, + &LineBuffer[Index * GLYPH_WIDTH] + ); + } + } + + // + // Blt a character to the screen + // + Status = UgaDraw->Blt ( + UgaDraw, + LineBuffer, + EfiUgaBltBufferToVideo, + 0, + 0, + X, + Y, + GLYPH_WIDTH * StrLen (Buffer), + GLYPH_HEIGHT, + GLYPH_WIDTH * StrLen (Buffer) * sizeof (EFI_UGA_PIXEL) + ); + +Error: + gBS->FreePool (LineBuffer); + gBS->FreePool (Buffer); + return Status; +} + + +UINTN +PrintXY ( + IN UINTN X, + IN UINTN Y, + IN EFI_UGA_PIXEL *ForeGround, OPTIONAL + IN EFI_UGA_PIXEL *BackGround, OPTIONAL + IN CHAR16 *Fmt, + ... + ) +/*++ + +Routine Description: + + Prints a formatted unicode string to the default console + +Arguments: + + X - X coordinate to start printing + + Y - Y coordinate to start printing + + ForeGround - Foreground color + + BackGround - Background color + + Fmt - Format string + + ... - Print arguments + +Returns: + + Length of string printed to the console + +--*/ +{ + EFI_HANDLE Handle; + EFI_UGA_DRAW_PROTOCOL *UgaDraw; + EFI_SIMPLE_TEXT_OUT_PROTOCOL *Sto; + EFI_STATUS Status; + VA_LIST Args; + + VA_START (Args, Fmt); + + Handle = gST->ConsoleOutHandle; + + Status = gBS->HandleProtocol ( + Handle, + &gEfiUgaDrawProtocolGuid, + (VOID **) &UgaDraw + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->HandleProtocol ( + Handle, + &gEfiSimpleTextOutProtocolGuid, + (VOID **) &Sto + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + return _IPrint (UgaDraw, Sto, X, Y, ForeGround, BackGround, Fmt, Args); +} diff --git a/EdkModulePkg/Library/EdkGraphicsLib/build.xml b/EdkModulePkg/Library/EdkGraphicsLib/build.xml new file mode 100644 index 0000000000..cccef0efe3 --- /dev/null +++ b/EdkModulePkg/Library/EdkGraphicsLib/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Library/EdkIfrSupportLib/EdkIfrSupportLib.mbd b/EdkModulePkg/Library/EdkIfrSupportLib/EdkIfrSupportLib.mbd new file mode 100644 index 0000000000..3864ea2a5c --- /dev/null +++ b/EdkModulePkg/Library/EdkIfrSupportLib/EdkIfrSupportLib.mbd @@ -0,0 +1,30 @@ + + + + + EdkIfrSupportLib + ea55bada-d488-427b-9d2d-227e0aaa3707 + EDK_RELEASE_VERSION 0x00020000 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-31 13:14 + + diff --git a/EdkModulePkg/Library/EdkIfrSupportLib/EdkIfrSupportLib.msa b/EdkModulePkg/Library/EdkIfrSupportLib/EdkIfrSupportLib.msa new file mode 100644 index 0000000000..fcf02afb02 --- /dev/null +++ b/EdkModulePkg/Library/EdkIfrSupportLib/EdkIfrSupportLib.msa @@ -0,0 +1,75 @@ + + + + + EdkIfrSupportLib + DXE_DRIVER + LIBRARY + ea55bada-d488-427b-9d2d-227e0aaa3707 + EDK_RELEASE_VERSION 0x00020000 + Graphics Library for UEFI drivers + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + EFI_SPECIFICATION_VERSION 0x00000000 + 2006-03-12 17:09 + 2006-03-31 13:14 + + + EdkIfrSupportLib + UefiLib + DebugLib + PrintLib + BaseLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + + + IfrCommon.c + IfrOnTheFly.c + IfrOpCodeCreation.c + IfrLibrary.h + IfrVariable.c + + + MdePkg + EdkModulePkg + + + Hii + + + + L"Lang" + 0x8BE4DF61, 0x93CA, 0x11d2, {0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C} + + + + + GlobalVariable + + + + + IfrLibConstruct + + + diff --git a/EdkModulePkg/Library/EdkIfrSupportLib/IfrCommon.c b/EdkModulePkg/Library/EdkIfrSupportLib/IfrCommon.c new file mode 100644 index 0000000000..6d0a84de5e --- /dev/null +++ b/EdkModulePkg/Library/EdkIfrSupportLib/IfrCommon.c @@ -0,0 +1,995 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + IfrCommon.c + +Abstract: + + Common Library Routines to assist in IFR creation on-the-fly + +Revision History: + +--*/ + +EFI_STATUS +IfrLibConstruct ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return EFI_SUCCESS; +} + +EFI_STATUS +GetCurrentLanguage ( + OUT CHAR16 *Lang + ) +/*++ + +Routine Description: + + Determine what is the current language setting + +Arguments: + + Lang - Pointer of system language + +Returns: + + Status code + +--*/ +{ + EFI_STATUS Status; + UINTN Size; + UINTN Index; + CHAR8 Language[4]; + + // + // Getting the system language and placing it into our Global Data + // + Size = sizeof (Language); + + Status = gRT->GetVariable ( + (CHAR16 *) L"Lang", + &gEfiGlobalVariableGuid, + NULL, + &Size, + Language + ); + + if (EFI_ERROR (Status)) { + AsciiStrCpy (Language, "eng"); + } + + for (Index = 0; Language[Index] != 0; Index++) { + // + // Bitwise AND ascii value with 0xDF yields an uppercase value. + // Sign extend into a unicode value + // + Lang[Index] = (CHAR16) (Language[Index] & 0xDF); + } + + // + // Null-terminate the value + // + Lang[3] = (CHAR16) 0; + + return Status; +} + + +EFI_STATUS +AddString ( + IN VOID *StringBuffer, + IN CHAR16 *Language, + IN CHAR16 *String, + IN OUT STRING_REF *StringToken + ) +/*++ + +Routine Description: + + Add a string to the incoming buffer and return the token and offset data + +Arguments: + + StringBuffer - The incoming buffer + + Language - Currrent language + + String - The string to be added + + StringToken - The index where the string placed + +Returns: + + EFI_OUT_OF_RESOURCES - No enough buffer to allocate + + EFI_SUCCESS - String successfully added to the incoming buffer + +--*/ +{ + EFI_HII_STRING_PACK *StringPack; + EFI_HII_STRING_PACK *StringPackBuffer; + VOID *NewBuffer; + RELOFST *PackSource; + RELOFST *PackDestination; + UINT8 *Source; + UINT8 *Destination; + UINTN Index; + BOOLEAN Finished; + + StringPack = (EFI_HII_STRING_PACK *) StringBuffer; + Finished = FALSE; + + // + // Pre-allocate a buffer sufficient for us to work on. + // We will use it as a destination scratch pad to build data on + // and when complete shift the data back to the original buffer + // + NewBuffer = AllocateZeroPool (DEFAULT_STRING_BUFFER_SIZE); + if (NewBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + StringPackBuffer = (EFI_HII_STRING_PACK *) NewBuffer; + + // + // StringPack is terminated with a length 0 entry + // + for (; StringPack->Header.Length != 0;) { + // + // If this stringpack's language is same as CurrentLanguage, use it + // + if (CompareMem ((VOID *) ((CHAR8 *) (StringPack) + StringPack->LanguageNameString), Language, 3) == 0) { + // + // We have some data in this string pack, copy the string package up to the string data + // + CopyMem (&StringPackBuffer->Header, &StringPack->Header, sizeof (StringPack)); + + // + // These are references in the structure to tokens, need to increase them by the space occupied by an additional StringPointer + // + StringPackBuffer->LanguageNameString = (UINT16) (StringPackBuffer->LanguageNameString + (UINT16) sizeof (RELOFST)); + StringPackBuffer->PrintableLanguageName = (UINT16) (StringPackBuffer->PrintableLanguageName + (UINT16) sizeof (RELOFST)); + + PackSource = (RELOFST *) (StringPack + 1); + PackDestination = (RELOFST *) (StringPackBuffer + 1); + for (Index = 0; PackSource[Index] != 0x0000; Index++) { + // + // Copy the stringpointers from old to new buffer + // remember that we are adding a string, so the string offsets will all go up by sizeof (RELOFST) + // + PackDestination[Index] = (UINT16) (PackDestination[Index] + sizeof (RELOFST)); + } + + // + // Add a new stringpointer in the new buffer since we are adding a string. Null terminate it + // + PackDestination[Index] = (UINT16)(PackDestination[Index-1] + + StrSize((CHAR16 *)((CHAR8 *)(StringPack) + PackSource[Index-1]))); + PackDestination[Index + 1] = (UINT16) 0; + + // + // Index is the token value for the new string + // + *StringToken = (UINT16) Index; + + // + // Source now points to the beginning of the old buffer strings + // Destination now points to the beginning of the new buffer strings + // + Source = (UINT8 *) &PackSource[Index + 1]; + Destination = (UINT8 *) &PackDestination[Index + 2]; + + // + // This should copy all the strings from the old buffer to the new buffer + // + for (; Index != 0; Index--) { + // + // Copy Source string to destination buffer + // + StrCpy ((CHAR16 *) Destination, (CHAR16 *) Source); + + // + // Adjust the source/destination to the next string location + // + Destination = Destination + StrSize ((CHAR16 *) Source); + Source = Source + StrSize ((CHAR16 *) Source); + } + + // + // This copies the new string to the destination buffer + // + StrCpy ((CHAR16 *) Destination, (CHAR16 *) String); + + // + // Adjust the size of the changed string pack by adding the size of the new string + // along with the size of the additional offset entry for the new string + // + StringPackBuffer->Header.Length = (UINT32) ((UINTN) StringPackBuffer->Header.Length + StrSize (String) + sizeof (RELOFST)); + + // + // Advance the buffers to point to the next spots. + // + StringPackBuffer = (EFI_HII_STRING_PACK *) ((CHAR8 *) (StringPackBuffer) + StringPackBuffer->Header.Length); + StringPack = (EFI_HII_STRING_PACK *) ((CHAR8 *) (StringPack) + StringPack->Header.Length); + Finished = TRUE; + continue; + } + // + // This isn't the language of the stringpack we were asked to add a string to + // so we need to copy it to the new buffer. + // + CopyMem (&StringPackBuffer->Header, &StringPack->Header, StringPack->Header.Length); + + // + // Advance the buffers to point to the next spots. + // + StringPackBuffer = (EFI_HII_STRING_PACK *) ((CHAR8 *) (StringPackBuffer) + StringPack->Header.Length); + StringPack = (EFI_HII_STRING_PACK *) ((CHAR8 *) (StringPack) + StringPack->Header.Length); + } + + // + // If we didn't copy the new data to a stringpack yet + // + if (!Finished) { + PackDestination = (RELOFST *) (StringPackBuffer + 1); + // + // Pointing to a new string pack location + // + StringPackBuffer->Header.Length = (UINT32) + ( + sizeof (EFI_HII_STRING_PACK) - + sizeof (EFI_STRING) + + sizeof (RELOFST) + + sizeof (RELOFST) + + StrSize (Language) + + StrSize (String) + ); + StringPackBuffer->Header.Type = EFI_HII_STRING; + StringPackBuffer->LanguageNameString = (UINT16) ((UINTN) &PackDestination[3] - (UINTN) StringPackBuffer); + StringPackBuffer->PrintableLanguageName = (UINT16) ((UINTN) &PackDestination[3] - (UINTN) StringPackBuffer); + StringPackBuffer->Attributes = 0; + PackDestination[0] = (UINT16) ((UINTN) &PackDestination[3] - (UINTN) StringPackBuffer); + PackDestination[1] = (UINT16) (PackDestination[0] + StrSize (Language)); + PackDestination[2] = (UINT16) 0; + + // + // The first string location will be set to destination. The minimum number of strings + // associated with a stringpack will always be token 0 stored as the languagename (e.g. ENG, SPA, etc) + // and token 1 as the new string being added and and null entry for the stringpointers + // + Destination = (UINT8 *) &PackDestination[3]; + + // + // Copy the language name string to the new buffer + // + StrCpy ((CHAR16 *) Destination, Language); + + // + // Advance the destination to the new empty spot + // + Destination = Destination + StrSize (Language); + + // + // Copy the string to the new buffer + // + StrCpy ((CHAR16 *) Destination, String); + + // + // Since we are starting with a new string pack - we know the new string is token 1 + // + *StringToken = (UINT16) 1; + } + + // + // Zero out the original buffer and copy the updated data in the new buffer to the old buffer + // + ZeroMem (StringBuffer, DEFAULT_STRING_BUFFER_SIZE); + CopyMem (StringBuffer, NewBuffer, DEFAULT_STRING_BUFFER_SIZE); + + // + // Free the newly created buffer since we don't need it anymore + // + gBS->FreePool (NewBuffer); + return EFI_SUCCESS; +} + + +EFI_STATUS +AddOpCode ( + IN VOID *FormBuffer, + IN OUT VOID *OpCodeData + ) +/*++ + +Routine Description: + + Add op-code data to the FormBuffer + +Arguments: + + FormBuffer - Form buffer to be inserted to + + OpCodeData - Op-code data to be inserted + +Returns: + + EFI_OUT_OF_RESOURCES - No enough buffer to allocate + + EFI_SUCCESS - Op-code data successfully inserted + +--*/ +{ + EFI_HII_PACK_HEADER *NewBuffer; + UINT8 *Source; + UINT8 *Destination; + + // + // Pre-allocate a buffer sufficient for us to work on. + // We will use it as a destination scratch pad to build data on + // and when complete shift the data back to the original buffer + // + NewBuffer = AllocateZeroPool (DEFAULT_FORM_BUFFER_SIZE); + if (NewBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Source = (UINT8 *) FormBuffer; + Destination = (UINT8 *) NewBuffer; + + // + // Copy the IFR Package header to the new buffer + // + CopyMem (Destination, Source, sizeof (EFI_HII_PACK_HEADER)); + + // + // Advance Source and Destination to next op-code + // + Source = Source + sizeof (EFI_HII_PACK_HEADER); + Destination = Destination + sizeof (EFI_HII_PACK_HEADER); + + // + // Copy data to the new buffer until we run into the end_form + // + for (; ((EFI_IFR_OP_HEADER *) Source)->OpCode != EFI_IFR_END_FORM_OP;) { + // + // If the this opcode is an end_form_set we better be creating and endform + // Nonetheless, we will add data before the end_form_set. This also provides + // for interesting behavior in the code we will run, but has no bad side-effects + // since we will possibly do a 0 byte copy in this particular end-case. + // + if (((EFI_IFR_OP_HEADER *) Source)->OpCode == EFI_IFR_END_FORM_SET_OP) { + break; + } + + // + // Copy data to new buffer + // + CopyMem (Destination, Source, ((EFI_IFR_OP_HEADER *) Source)->Length); + + // + // Adjust Source/Destination to next op-code location + // + Destination = Destination + (UINTN) ((EFI_IFR_OP_HEADER *) Source)->Length; + Source = Source + (UINTN) ((EFI_IFR_OP_HEADER *) Source)->Length; + } + + // + // Prior to the end_form is where we insert the new op-code data + // + CopyMem (Destination, OpCodeData, ((EFI_IFR_OP_HEADER *) OpCodeData)->Length); + Destination = Destination + (UINTN) ((EFI_IFR_OP_HEADER *) OpCodeData)->Length; + + NewBuffer->Length = (UINT32) (NewBuffer->Length + (UINT32) (((EFI_IFR_OP_HEADER *) OpCodeData)->Length)); + + // + // Copy end-form data to new buffer + // + CopyMem (Destination, Source, ((EFI_IFR_OP_HEADER *) Source)->Length); + + // + // Adjust Source/Destination to next op-code location + // + Destination = Destination + (UINTN) ((EFI_IFR_OP_HEADER *) Source)->Length; + Source = Source + (UINTN) ((EFI_IFR_OP_HEADER *) Source)->Length; + + // + // Copy end-formset data to new buffer + // + CopyMem (Destination, Source, ((EFI_IFR_OP_HEADER *) Source)->Length); + + // + // Zero out the original buffer and copy the updated data in the new buffer to the old buffer + // + ZeroMem (FormBuffer, DEFAULT_FORM_BUFFER_SIZE); + CopyMem (FormBuffer, NewBuffer, DEFAULT_FORM_BUFFER_SIZE); + + // + // Free the newly created buffer since we don't need it anymore + // + gBS->FreePool (NewBuffer); + return EFI_SUCCESS; +} + + +EFI_STATUS +GetHiiInterface ( + OUT EFI_HII_PROTOCOL **Hii + ) +/*++ + +Routine Description: + + Get the HII protocol interface + +Arguments: + + Hii - HII protocol interface + +Returns: + + Status code + +--*/ +{ + EFI_STATUS Status; + + // + // There should only be one HII protocol + // + Status = gBS->LocateProtocol ( + &gEfiHiiProtocolGuid, + NULL, + (VOID **) Hii + ); + + return Status;; +} + + +EFI_STATUS +ExtractDataFromHiiHandle ( + IN EFI_HII_HANDLE HiiHandle, + IN OUT UINT16 *ImageLength, + OUT UINT8 *DefaultImage, + OUT EFI_GUID *Guid + ) +/*++ + +Routine Description: + + Extract information pertaining to the HiiHandle + +Arguments: + + HiiHandle - Hii handle + + ImageLength - For input, length of DefaultImage; + For output, length of actually required + + DefaultImage - Image buffer prepared by caller + + Guid - Guid information about the form + +Returns: + + EFI_OUT_OF_RESOURCES - No enough buffer to allocate + + EFI_BUFFER_TOO_SMALL - DefualtImage has no enough ImageLength + + EFI_SUCCESS - Successfully extract data from Hii database. + + +--*/ +{ + EFI_STATUS Status; + EFI_HII_PROTOCOL *Hii; + UINTN DataLength; + UINT8 *RawData; + UINT8 *OldData; + UINTN Index; + UINTN Temp; + UINTN SizeOfNvStore; + UINTN CachedStart; + + DataLength = DEFAULT_FORM_BUFFER_SIZE; + SizeOfNvStore = 0; + CachedStart = 0; + + Status = GetHiiInterface (&Hii); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Allocate space for retrieval of IFR data + // + RawData = AllocateZeroPool (DataLength); + if (RawData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Get all the forms associated with this HiiHandle + // + Status = Hii->GetForms (Hii, HiiHandle, 0, &DataLength, RawData); + + if (EFI_ERROR (Status)) { + gBS->FreePool (RawData); + + // + // Allocate space for retrieval of IFR data + // + RawData = AllocateZeroPool (DataLength); + if (RawData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Get all the forms associated with this HiiHandle + // + Status = Hii->GetForms (Hii, HiiHandle, 0, &DataLength, RawData); + } + + OldData = RawData; + + // + // Point RawData to the beginning of the form data + // + RawData = (UINT8 *) ((UINTN) RawData + sizeof (EFI_HII_PACK_HEADER)); + + for (Index = 0; RawData[Index] != EFI_IFR_END_FORM_SET_OP;) { + switch (RawData[Index]) { + case EFI_IFR_FORM_SET_OP: + // + // Copy the GUID information from this handle + // + CopyMem (Guid, &((EFI_IFR_FORM_SET *) &RawData[Index])->Guid, sizeof (EFI_GUID)); + break; + + case EFI_IFR_ONE_OF_OP: + case EFI_IFR_CHECKBOX_OP: + case EFI_IFR_NUMERIC_OP: + case EFI_IFR_DATE_OP: + case EFI_IFR_TIME_OP: + case EFI_IFR_PASSWORD_OP: + case EFI_IFR_STRING_OP: + // + // Remember, multiple op-codes may reference the same item, so let's keep a running + // marker of what the highest QuestionId that wasn't zero length. This will accurately + // maintain the Size of the NvStore + // + if (((EFI_IFR_ONE_OF *) &RawData[Index])->Width != 0) { + Temp = ((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId + ((EFI_IFR_ONE_OF *) &RawData[Index])->Width; + if (SizeOfNvStore < Temp) { + SizeOfNvStore = ((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId + ((EFI_IFR_ONE_OF *) &RawData[Index])->Width; + } + } + } + + Index = RawData[Index + 1] + Index; + } + + // + // Return an error if buffer is too small + // + if (SizeOfNvStore > *ImageLength) { + gBS->FreePool (OldData); + *ImageLength = (UINT16) SizeOfNvStore; + return EFI_BUFFER_TOO_SMALL; + } + + if (DefaultImage != NULL) { + ZeroMem (DefaultImage, SizeOfNvStore); + } + + // + // Copy the default image information to the user's buffer + // + for (Index = 0; RawData[Index] != EFI_IFR_END_FORM_SET_OP;) { + switch (RawData[Index]) { + case EFI_IFR_ONE_OF_OP: + CachedStart = ((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId; + break; + + case EFI_IFR_ONE_OF_OPTION_OP: + if (((EFI_IFR_ONE_OF_OPTION *) &RawData[Index])->Flags & EFI_IFR_FLAG_DEFAULT) { + CopyMem (&DefaultImage[CachedStart], &((EFI_IFR_ONE_OF_OPTION *) &RawData[Index])->Value, 2); + } + break; + + case EFI_IFR_CHECKBOX_OP: + DefaultImage[((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId] = ((EFI_IFR_CHECKBOX *) &RawData[Index])->Flags; + break; + + case EFI_IFR_NUMERIC_OP: + CopyMem ( + &DefaultImage[((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId], + &((EFI_IFR_NUMERIC *) &RawData[Index])->Default, + 2 + ); + break; + + } + + Index = RawData[Index + 1] + Index; + } + + *ImageLength = (UINT16) SizeOfNvStore; + + // + // Free our temporary repository of form data + // + gBS->FreePool (OldData); + + return EFI_SUCCESS; +} + + +EFI_HII_HANDLE +FindHiiHandle ( + IN OUT EFI_HII_PROTOCOL **HiiProtocol, OPTIONAL + IN EFI_GUID *Guid + ) +/*++ + +Routine Description: + Finds HII handle for given pack GUID previously registered with the HII. + +Arguments: + HiiProtocol - pointer to pointer to HII protocol interface. + If NULL, the interface will be found but not returned. + If it points to NULL, the interface will be found and + written back to the pointer that is pointed to. + Guid - The GUID of the pack that registered with the HII. + +Returns: + Handle to the HII pack previously registered by the memory driver. + +--*/ +{ + EFI_STATUS Status; + + EFI_HII_HANDLE *HiiHandleBuffer; + EFI_HII_HANDLE HiiHandle; + UINT16 HiiHandleBufferLength; + UINT32 NumberOfHiiHandles; + EFI_GUID HiiGuid; + EFI_HII_PROTOCOL *HiiProt; + UINT32 Index; + UINT16 Length; + + HiiHandle = 0; + if ((HiiProtocol != NULL) && (*HiiProtocol != NULL)) { + // + // The protocol has been passed in + // + HiiProt = *HiiProtocol; + } else { + gBS->LocateProtocol ( + &gEfiHiiProtocolGuid, + NULL, + (VOID **) &HiiProt + ); + if (HiiProt == NULL) { + return HiiHandle; + } + + if (HiiProtocol != NULL) { + // + // Return back the HII protocol for the caller as promissed + // + *HiiProtocol = HiiProt; + } + } + // + // Allocate buffer + // + HiiHandleBufferLength = 10; + HiiHandleBuffer = AllocatePool (HiiHandleBufferLength); + ASSERT (HiiHandleBuffer != NULL); + + // + // Get the Handles of the packages that were registered with Hii + // + Status = HiiProt->FindHandles ( + HiiProt, + &HiiHandleBufferLength, + HiiHandleBuffer + ); + + // + // Get a bigger bugffer if this one is to small, and try again + // + if (Status == EFI_BUFFER_TOO_SMALL) { + + gBS->FreePool (HiiHandleBuffer); + + HiiHandleBuffer = AllocatePool (HiiHandleBufferLength); + ASSERT (HiiHandleBuffer != NULL); + + Status = HiiProt->FindHandles ( + HiiProt, + &HiiHandleBufferLength, + HiiHandleBuffer + ); + } + + if (EFI_ERROR (Status)) { + goto lbl_exit; + } + + NumberOfHiiHandles = HiiHandleBufferLength / sizeof (EFI_HII_HANDLE); + + // + // Iterate Hii handles and look for the one that matches our Guid + // + for (Index = 0; Index < NumberOfHiiHandles; Index++) { + + Length = 0; + ExtractDataFromHiiHandle (HiiHandleBuffer[Index], &Length, NULL, &HiiGuid); + + if (CompareGuid (&HiiGuid, Guid)) { + + HiiHandle = HiiHandleBuffer[Index]; + break; + } + } + +lbl_exit: + gBS->FreePool (HiiHandleBuffer); + return HiiHandle; +} + + +EFI_STATUS +ValidateDataFromHiiHandle ( + IN EFI_HII_HANDLE HiiHandle, + OUT BOOLEAN *Results + ) +/*++ + +Routine Description: + + Validate that the data associated with the HiiHandle in NVRAM is within + the reasonable parameters for that FormSet. Values for strings and passwords + are not verified due to their not having the equivalent of valid range settings. + +Arguments: + + HiiHandle - Handle of the HII database entry to query + + Results - If return Status is EFI_SUCCESS, Results provides valid data + TRUE = NVRAM Data is within parameters + FALSE = NVRAM Data is NOT within parameters + +Returns: + + EFI_OUT_OF_RESOURCES - No enough buffer to allocate + + EFI_SUCCESS - Data successfully validated +--*/ +{ + EFI_STATUS Status; + EFI_HII_PROTOCOL *Hii; + EFI_GUID Guid; + UINT8 *RawData; + UINT8 *OldData; + UINTN RawDataLength; + UINT8 *VariableData; + UINTN Index; + UINTN Temp; + UINTN SizeOfNvStore; + UINTN CachedStart; + BOOLEAN GotMatch; + + RawDataLength = DEFAULT_FORM_BUFFER_SIZE; + SizeOfNvStore = 0; + CachedStart = 0; + GotMatch = FALSE; + *Results = TRUE; + + Status = GetHiiInterface (&Hii); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Allocate space for retrieval of IFR data + // + RawData = AllocateZeroPool (RawDataLength); + if (RawData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Get all the forms associated with this HiiHandle + // + Status = Hii->GetForms (Hii, HiiHandle, 0, &RawDataLength, RawData); + + if (EFI_ERROR (Status)) { + gBS->FreePool (RawData); + + // + // Allocate space for retrieval of IFR data + // + RawData = AllocateZeroPool (RawDataLength); + if (RawData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Get all the forms associated with this HiiHandle + // + Status = Hii->GetForms (Hii, HiiHandle, 0, &RawDataLength, RawData); + } + + OldData = RawData; + + // + // Point RawData to the beginning of the form data + // + RawData = (UINT8 *) ((UINTN) RawData + sizeof (EFI_HII_PACK_HEADER)); + + for (Index = 0; RawData[Index] != EFI_IFR_END_FORM_SET_OP;) { + if (RawData[Index] == EFI_IFR_FORM_SET_OP) { + CopyMem (&Guid, &((EFI_IFR_FORM_SET *) &RawData[Index])->Guid, sizeof (EFI_GUID)); + break; + } + + Index = RawData[Index + 1] + Index; + } + + for (Index = 0; RawData[Index] != EFI_IFR_END_FORM_SET_OP;) { + switch (RawData[Index]) { + case EFI_IFR_FORM_SET_OP: + break; + + case EFI_IFR_ONE_OF_OP: + case EFI_IFR_CHECKBOX_OP: + case EFI_IFR_NUMERIC_OP: + case EFI_IFR_DATE_OP: + case EFI_IFR_TIME_OP: + case EFI_IFR_PASSWORD_OP: + case EFI_IFR_STRING_OP: + // + // Remember, multiple op-codes may reference the same item, so let's keep a running + // marker of what the highest QuestionId that wasn't zero length. This will accurately + // maintain the Size of the NvStore + // + if (((EFI_IFR_ONE_OF *) &RawData[Index])->Width != 0) { + Temp = ((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId + ((EFI_IFR_ONE_OF *) &RawData[Index])->Width; + if (SizeOfNvStore < Temp) { + SizeOfNvStore = ((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId + ((EFI_IFR_ONE_OF *) &RawData[Index])->Width; + } + } + } + + Index = RawData[Index + 1] + Index; + } + + // + // Allocate memory for our File Form Tags + // + VariableData = AllocateZeroPool (SizeOfNvStore); + if (VariableData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = gRT->GetVariable ( + (CHAR16 *) L"Setup", + &Guid, + NULL, + &SizeOfNvStore, + (VOID *) VariableData + ); + + if (EFI_ERROR (Status)) { + + // + // If there is a variable that exists already and it is larger than what we calculated the + // storage needs to be, we must assume the variable size from GetVariable is correct and not + // allow the truncation of the variable. It is very possible that the user who created the IFR + // we are cracking is not referring to a variable that was in a previous map, however we cannot + // allow it's truncation. + // + if (Status == EFI_BUFFER_TOO_SMALL) { + // + // Free the buffer that was allocated that was too small + // + gBS->FreePool (VariableData); + + VariableData = AllocatePool (SizeOfNvStore); + if (VariableData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = gRT->GetVariable ( + (CHAR16 *) L"Setup", + &Guid, + NULL, + &SizeOfNvStore, + (VOID *) VariableData + ); + } + } + + // + // Walk through the form and see that the variable data it refers to is ok. + // This allows for the possibility of stale (obsoleted) data in the variable + // can be overlooked without causing an error + // + for (Index = 0; RawData[Index] != EFI_IFR_END_FORM_SET_OP;) { + switch (RawData[Index]) { + case EFI_IFR_ONE_OF_OP: + // + // A one_of has no data, its the option that does - cache the storage Id + // + CachedStart = ((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId; + break; + + case EFI_IFR_ONE_OF_OPTION_OP: + // + // A one_of_option can be any value + // + if (VariableData[CachedStart] == ((EFI_IFR_ONE_OF_OPTION *) &RawData[Index])->Value) { + GotMatch = TRUE; + } + break; + + case EFI_IFR_END_ONE_OF_OP: + // + // At this point lets make sure that the data value in the NVRAM matches one of the options + // + if (!GotMatch) { + *Results = FALSE; + return EFI_SUCCESS; + } + break; + + case EFI_IFR_CHECKBOX_OP: + // + // A checkbox is a boolean, so 0 and 1 are valid + // Remember, QuestionId corresponds to the offset location of the data in the variable + // + if (VariableData[((EFI_IFR_CHECKBOX *) &RawData[Index])->QuestionId] > 1) { + *Results = FALSE; + return EFI_SUCCESS; + } + break; + + case EFI_IFR_NUMERIC_OP: + if ((VariableData[((EFI_IFR_NUMERIC *)&RawData[Index])->QuestionId] < ((EFI_IFR_NUMERIC *)&RawData[Index])->Minimum) || + (VariableData[((EFI_IFR_NUMERIC *)&RawData[Index])->QuestionId] > ((EFI_IFR_NUMERIC *)&RawData[Index])->Maximum)) { + *Results = FALSE; + return EFI_SUCCESS; + } + break; + + } + + Index = RawData[Index + 1] + Index; + } + + // + // Free our temporary repository of form data + // + gBS->FreePool (OldData); + gBS->FreePool (VariableData); + + return EFI_SUCCESS; +} + diff --git a/EdkModulePkg/Library/EdkIfrSupportLib/IfrOnTheFly.c b/EdkModulePkg/Library/EdkIfrSupportLib/IfrOnTheFly.c new file mode 100644 index 0000000000..e3d1040896 --- /dev/null +++ b/EdkModulePkg/Library/EdkIfrSupportLib/IfrOnTheFly.c @@ -0,0 +1,972 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + IfrOnTheFly.c + +Abstract: + + Library Routines to create IFR on-the-fly + +Revision History: + +--*/ + +EFI_STATUS +CreateFormSet ( + IN CHAR16 *FormSetTitle, + IN EFI_GUID *Guid, + IN UINT8 Class, + IN UINT8 SubClass, + IN OUT VOID **FormBuffer, + IN OUT VOID **StringBuffer + ) +/*++ + +Routine Description: + + Create a formset + +Arguments: + + FormSetTitle - Title of formset + + Guid - Guid of formset + + Class - Class of formset + + SubClass - Sub class of formset + + FormBuffer - Pointer of the formset created + + StringBuffer - Pointer of FormSetTitile string created + +Returns: + + EFI_OUT_OF_RESOURCES - No enough buffer to allocate + + EFI_SUCCESS - Formset successfully created + +--*/ +{ + EFI_STATUS Status; + EFI_HII_IFR_PACK IfrPack; + EFI_IFR_FORM_SET FormSet; + EFI_IFR_END_FORM_SET EndFormSet; + UINT8 *Destination; + CHAR16 CurrentLanguage[4]; + STRING_REF StringToken; + + // + // Pre-allocate a buffer sufficient for us to work from. + // + FormBuffer = AllocateZeroPool (DEFAULT_FORM_BUFFER_SIZE); + if (FormBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Pre-allocate a buffer sufficient for us to work from. + // + StringBuffer = AllocateZeroPool (DEFAULT_STRING_BUFFER_SIZE); + if (StringBuffer == NULL) { + gBS->FreePool (FormBuffer); + return EFI_OUT_OF_RESOURCES; + } + + // + // Obtain current language value + // + GetCurrentLanguage (CurrentLanguage); + + // + // Add the FormSetTitle to the string buffer and get the StringToken + // + Status = AddString (*StringBuffer, CurrentLanguage, FormSetTitle, &StringToken); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Initialize the Ifr Package header data + // + IfrPack.Header.Length = sizeof (EFI_HII_PACK_HEADER) + sizeof (EFI_IFR_FORM_SET) + sizeof (EFI_IFR_END_FORM_SET); + IfrPack.Header.Type = EFI_HII_IFR; + + // + // Initialize FormSet with the appropriate information + // + FormSet.Header.OpCode = EFI_IFR_FORM_SET_OP; + FormSet.Header.Length = sizeof (EFI_IFR_FORM_SET); + FormSet.FormSetTitle = StringToken; + FormSet.Class = Class; + FormSet.SubClass = SubClass; + CopyMem (&FormSet.Guid, Guid, sizeof (EFI_GUID)); + + // + // Initialize the end formset data + // + EndFormSet.Header.Length = sizeof (EFI_IFR_END_FORM_SET); + EndFormSet.Header.OpCode = EFI_IFR_END_FORM_SET_OP; + + Destination = (UINT8 *) *FormBuffer; + + // + // Copy the formset/endformset data to the form buffer + // + CopyMem (Destination, &IfrPack, sizeof (EFI_HII_PACK_HEADER)); + + Destination = Destination + sizeof (EFI_HII_PACK_HEADER); + + CopyMem (Destination, &FormSet, sizeof (EFI_IFR_FORM_SET)); + + Destination = Destination + sizeof (EFI_IFR_FORM_SET); + + CopyMem (Destination, &EndFormSet, sizeof (EFI_IFR_END_FORM_SET)); + return EFI_SUCCESS; +} + + +EFI_STATUS +CreateForm ( + IN CHAR16 *FormTitle, + IN UINT16 FormId, + IN OUT VOID *FormBuffer, + IN OUT VOID *StringBuffer + ) +/*++ + +Routine Description: + + Create a form + +Arguments: + + FormTitle - Title of the form + + FormId - Id of the form + + FormBuffer - Pointer of the form created + + StringBuffer - Pointer of FormTitil string created + +Returns: + + EFI_SUCCESS - Form successfully created + +--*/ +{ + EFI_STATUS Status; + EFI_IFR_FORM Form; + EFI_IFR_END_FORM EndForm; + CHAR16 CurrentLanguage[4]; + STRING_REF StringToken; + + // + // Obtain current language value + // + GetCurrentLanguage (CurrentLanguage); + + Status = AddString (StringBuffer, CurrentLanguage, FormTitle, &StringToken); + + if (EFI_ERROR (Status)) { + return Status; + } + + Form.Header.OpCode = EFI_IFR_FORM_OP; + Form.Header.Length = sizeof (EFI_IFR_FORM); + Form.FormId = FormId; + Form.FormTitle = StringToken; + + Status = AddOpCode (FormBuffer, &Form); + + if (EFI_ERROR (Status)) { + return Status; + } + + EndForm.Header.OpCode = EFI_IFR_END_FORM_OP; + EndForm.Header.Length = sizeof (EFI_IFR_END_FORM); + + Status = AddOpCode (FormBuffer, &EndForm); + + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} + + +EFI_STATUS +CreateSubTitle ( + IN CHAR16 *SubTitle, + IN OUT VOID *FormBuffer, + IN OUT VOID *StringBuffer + ) +/*++ + +Routine Description: + + Create a SubTitle + +Arguments: + + SubTitle - Sub title to be created + + FormBuffer - Where this subtitle to add to + + StringBuffer - String buffer created for subtitle + +Returns: + + EFI_SUCCESS - Subtitle successfully created + +--*/ +{ + EFI_STATUS Status; + EFI_IFR_SUBTITLE Subtitle; + CHAR16 CurrentLanguage[4]; + STRING_REF StringToken; + + // + // Obtain current language value + // + GetCurrentLanguage (CurrentLanguage); + + Status = AddString (StringBuffer, CurrentLanguage, SubTitle, &StringToken); + + if (EFI_ERROR (Status)) { + return Status; + } + + Subtitle.Header.OpCode = EFI_IFR_SUBTITLE_OP; + Subtitle.Header.Length = sizeof (EFI_IFR_SUBTITLE); + Subtitle.SubTitle = StringToken; + + Status = AddOpCode (FormBuffer, &Subtitle); + + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} + + +EFI_STATUS +CreateText ( + IN CHAR16 *String, + IN CHAR16 *String2, + IN CHAR16 *String3, + IN UINT8 Flags, + IN UINT16 Key, + IN OUT VOID *FormBuffer, + IN OUT VOID *StringBuffer + ) +/*++ + +Routine Description: + + Create a line of text + +Arguments: + + String - First string of the text + + String2 - Second string of the text + + String3 - Help string of the text + + Flags - Flag of the text + + Key - Key of the text + + FormBuffer - The form where this text adds to + + StringBuffer - String buffer created for String, String2 and String3 + +Returns: + + EFI_SUCCESS - Text successfully created + +--*/ +{ + EFI_STATUS Status; + EFI_IFR_TEXT Text; + CHAR16 CurrentLanguage[4]; + STRING_REF StringToken; + + // + // Obtain current language value + // + GetCurrentLanguage (CurrentLanguage); + + // + // Add first string, get first string's token + // + Status = AddString (StringBuffer, CurrentLanguage, String, &StringToken); + + if (EFI_ERROR (Status)) { + return Status; + } + + Text.Header.OpCode = EFI_IFR_TEXT_OP; + Text.Header.Length = sizeof (EFI_IFR_TEXT); + Text.Text = StringToken; + + // + // Add second string, get first string's token + // + Status = AddString (StringBuffer, CurrentLanguage, String2, &StringToken); + + if (EFI_ERROR (Status)) { + return Status; + } + + Text.TextTwo = StringToken; + + Text.Flags = (UINT8) (Flags | EFI_IFR_FLAG_CREATED); + Text.Key = Key; + + // + // Add second string, get first string's token + // + Status = AddString (StringBuffer, CurrentLanguage, String3, &StringToken); + + if (EFI_ERROR (Status)) { + return Status; + } + + Text.Help = StringToken; + + Status = AddOpCode (FormBuffer, &Text); + + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} + + +EFI_STATUS +CreateGoto ( + IN UINT16 FormId, + IN CHAR16 *Prompt, + IN OUT VOID *FormBuffer, + IN OUT VOID *StringBuffer + ) +/*++ + +Routine Description: + + Create a hyperlink + +Arguments: + + FormId - Form ID of the hyperlink + + Prompt - Prompt of the hyperlink + + FormBuffer - The form where this hyperlink adds to + + StringBuffer - String buffer created for Prompt + +Returns: + + EFI_SUCCESS - Hyperlink successfully created + +--*/ +{ + EFI_STATUS Status; + EFI_IFR_REF Hyperlink; + CHAR16 CurrentLanguage[4]; + STRING_REF StringToken; + + // + // Obtain current language value + // + GetCurrentLanguage (CurrentLanguage); + + Status = AddString (StringBuffer, CurrentLanguage, Prompt, &StringToken); + + if (EFI_ERROR (Status)) { + return Status; + } + + Hyperlink.Header.OpCode = EFI_IFR_REF_OP; + Hyperlink.Header.Length = sizeof (EFI_IFR_REF); + Hyperlink.FormId = FormId; + Hyperlink.Prompt = StringToken; + + Status = AddOpCode (FormBuffer, &Hyperlink); + + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} + + +EFI_STATUS +CreateOneOf ( + IN UINT16 QuestionId, + IN UINT8 DataWidth, + IN CHAR16 *Prompt, + IN CHAR16 *Help, + IN IFR_OPTION *OptionsList, + IN UINTN OptionCount, + IN OUT VOID *FormBuffer, + IN OUT VOID *StringBuffer + ) +/*++ + +Routine Description: + + Create a one-of question with a set of options to choose from. The + OptionsList is a pointer to a null-terminated list of option descriptions. + +Arguments: + + QuestionId - Question ID of the one-of box + + DataWidth - DataWidth of the one-of box + + Prompt - Prompt of the one-of box + + Help - Help of the one-of box + + OptionsList - Each string in it is an option of the one-of box + + OptionCount - Option string count + + FormBuffer - The form where this one-of box adds to + + StringBuffer - String buffer created for Prompt, Help and Option strings + +Returns: + + EFI_DEVICE_ERROR - DataWidth > 2 + + EFI_SUCCESS - One-Of box successfully created. + +--*/ +{ + EFI_STATUS Status; + UINTN Index; + EFI_IFR_ONE_OF OneOf; + EFI_IFR_ONE_OF_OPTION OneOfOption; + EFI_IFR_END_ONE_OF EndOneOf; + CHAR16 CurrentLanguage[4]; + STRING_REF StringToken; + + // + // We do not create op-code storage widths for one-of in excess of 16 bits for now + // + if (DataWidth > 2) { + return EFI_DEVICE_ERROR; + } + + // + // Obtain current language value + // + GetCurrentLanguage (CurrentLanguage); + + // + // Add first string, get first string's token + // + Status = AddString (StringBuffer, CurrentLanguage, Prompt, &StringToken); + + if (EFI_ERROR (Status)) { + return Status; + } + + OneOf.Header.OpCode = EFI_IFR_ONE_OF_OP; + OneOf.Header.Length = sizeof (EFI_IFR_ONE_OF); + OneOf.QuestionId = QuestionId; + OneOf.Width = DataWidth; + OneOf.Prompt = StringToken; + + // + // Add second string, get first string's token + // + Status = AddString (StringBuffer, CurrentLanguage, Help, &StringToken); + + if (EFI_ERROR (Status)) { + return Status; + } + + OneOf.Help = StringToken; + + Status = AddOpCode (FormBuffer, &OneOf); + + if (EFI_ERROR (Status)) { + return Status; + } + + for (Index = 0; Index < OptionCount; Index++) { + OneOfOption.Header.OpCode = EFI_IFR_ONE_OF_OPTION_OP; + OneOfOption.Header.Length = sizeof (EFI_IFR_ONE_OF_OPTION); + + // + // Add string and get token back + // + Status = AddString (StringBuffer, CurrentLanguage, OptionsList[Index].OptionString, &StringToken); + + OneOfOption.Option = StringToken; + OneOfOption.Value = OptionsList[Index].Value; + OneOfOption.Flags = (UINT8) (OptionsList[Index].Flags | EFI_IFR_FLAG_CREATED); + OneOfOption.Key = OptionsList[Index].Key; + + Status = AddOpCode (FormBuffer, &OneOfOption); + + if (EFI_ERROR (Status)) { + return Status; + } + } + + EndOneOf.Header.Length = sizeof (EFI_IFR_END_ONE_OF); + EndOneOf.Header.OpCode = EFI_IFR_END_ONE_OF_OP; + + Status = AddOpCode (FormBuffer, &EndOneOf); + + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +CreateOrderedList ( + IN UINT16 QuestionId, + IN UINT8 MaxEntries, + IN CHAR16 *Prompt, + IN CHAR16 *Help, + IN IFR_OPTION *OptionsList, + IN UINTN OptionCount, + IN OUT VOID *FormBuffer, + IN OUT VOID *StringBuffer + ) +/*++ + +Routine Description: + + Create a one-of question with a set of options to choose from. The + OptionsList is a pointer to a null-terminated list of option descriptions. + +Arguments: + + QuestionId - Question ID of the ordered list + + MaxEntries - MaxEntries of the ordered list + + Prompt - Prompt of the ordered list + + Help - Help of the ordered list + + OptionsList - Each string in it is an option of the ordered list + + OptionCount - Option string count + + FormBuffer - The form where this ordered list adds to + + StringBuffer - String buffer created for Prompt, Help and Option strings + +Returns: + + EFI_SUCCESS - Ordered list successfully created. + +--*/ +{ + EFI_STATUS Status; + UINTN Index; + EFI_IFR_ORDERED_LIST OrderedList; + EFI_IFR_ONE_OF_OPTION OrderedListOption; + EFI_IFR_END_ONE_OF EndOrderedList; + CHAR16 CurrentLanguage[4]; + STRING_REF StringToken; + + // + // Obtain current language value + // + GetCurrentLanguage (CurrentLanguage); + + // + // Add first string, get first string's token + // + Status = AddString (StringBuffer, CurrentLanguage, Prompt, &StringToken); + + if (EFI_ERROR (Status)) { + return Status; + } + + OrderedList.Header.OpCode = EFI_IFR_ORDERED_LIST_OP; + OrderedList.Header.Length = sizeof (EFI_IFR_ORDERED_LIST); + OrderedList.QuestionId = QuestionId; + OrderedList.MaxEntries = MaxEntries; + OrderedList.Prompt = StringToken; + + // + // Add second string, get first string's token + // + Status = AddString (StringBuffer, CurrentLanguage, Help, &StringToken); + + if (EFI_ERROR (Status)) { + return Status; + } + + OrderedList.Help = StringToken; + + Status = AddOpCode (FormBuffer, &OrderedList); + + if (EFI_ERROR (Status)) { + return Status; + } + + for (Index = 0; Index < OptionCount; Index++) { + OrderedListOption.Header.OpCode = EFI_IFR_ONE_OF_OPTION_OP; + OrderedListOption.Header.Length = sizeof (EFI_IFR_ONE_OF_OPTION); + + // + // Add string and get token back + // + Status = AddString (StringBuffer, CurrentLanguage, OptionsList[Index].OptionString, &StringToken); + + OrderedListOption.Option = StringToken; + OrderedListOption.Value = OptionsList[Index].Value; + OrderedListOption.Flags = (UINT8) (OptionsList[Index].Flags | EFI_IFR_FLAG_CREATED); + OrderedListOption.Key = OptionsList[Index].Key; + + Status = AddOpCode (FormBuffer, &OrderedListOption); + + if (EFI_ERROR (Status)) { + return Status; + } + } + + EndOrderedList.Header.Length = sizeof (EFI_IFR_END_ONE_OF); + EndOrderedList.Header.OpCode = EFI_IFR_END_ONE_OF_OP; + + Status = AddOpCode (FormBuffer, &EndOrderedList); + + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} + + +EFI_STATUS +CreateCheckBox ( + IN UINT16 QuestionId, + IN UINT8 DataWidth, + IN CHAR16 *Prompt, + IN CHAR16 *Help, + IN UINT8 Flags, + IN OUT VOID *FormBuffer, + IN OUT VOID *StringBuffer + ) +/*++ + +Routine Description: + + Create a checkbox + +Arguments: + + QuestionId - Question ID of the check box + + DataWidth - DataWidth of the check box + + Prompt - Prompt of the check box + + Help - Help of the check box + + Flags - Flags of the check box + + FormBuffer - The form where this check box adds to + + StringBuffer - String buffer created for Prompt and Help. + +Returns: + + EFI_DEVICE_ERROR - DataWidth > 1 + + EFI_SUCCESS - Check box successfully created + +--*/ +{ + EFI_STATUS Status; + EFI_IFR_CHECKBOX CheckBox; + CHAR16 CurrentLanguage[4]; + STRING_REF StringToken; + + // + // We do not create op-code storage widths for checkbox in excess of 8 bits for now + // + if (DataWidth > 1) { + return EFI_DEVICE_ERROR; + } + + // + // Obtain current language value + // + GetCurrentLanguage (CurrentLanguage); + + // + // Add first string, get first string's token + // + Status = AddString (StringBuffer, CurrentLanguage, Prompt, &StringToken); + + if (EFI_ERROR (Status)) { + return Status; + } + + CheckBox.Header.OpCode = EFI_IFR_CHECKBOX_OP; + CheckBox.Header.Length = sizeof (EFI_IFR_CHECKBOX); + CheckBox.QuestionId = QuestionId; + CheckBox.Width = DataWidth; + CheckBox.Prompt = StringToken; + + // + // Add second string, get first string's token + // + Status = AddString (StringBuffer, CurrentLanguage, Help, &StringToken); + + if (EFI_ERROR (Status)) { + return Status; + } + + CheckBox.Help = StringToken; + CheckBox.Flags = (UINT8) (Flags | EFI_IFR_FLAG_CREATED); + + Status = AddOpCode (FormBuffer, &CheckBox); + + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} + + +EFI_STATUS +CreateNumeric ( + IN UINT16 QuestionId, + IN UINT8 DataWidth, + IN CHAR16 *Prompt, + IN CHAR16 *Help, + IN UINT16 Minimum, + IN UINT16 Maximum, + IN UINT16 Step, + IN UINT16 Default, + IN UINT8 Flags, + IN UINT16 Key, + IN OUT VOID *FormBuffer, + IN OUT VOID *StringBuffer + ) +/*++ + +Routine Description: + + Create a numeric + +Arguments: + + QuestionId - Question ID of the numeric + + DataWidth - DataWidth of the numeric + + Prompt - Prompt of the numeric + + Help - Help of the numeric + + Minimum - Minumun boundary of the numeric + + Maximum - Maximum boundary of the numeric + + Step - Step of the numeric + + Default - Default value + + Flags - Flags of the numeric + + Key - Key of the numeric + + FormBuffer - The form where this numeric adds to + + StringBuffer - String buffer created for Prompt and Help. + +Returns: + + EFI_DEVICE_ERROR - DataWidth > 2 + + EFI_SUCCESS - Numeric is successfully created + +--*/ +{ + EFI_STATUS Status; + EFI_IFR_NUMERIC Numeric; + CHAR16 CurrentLanguage[4]; + STRING_REF StringToken; + + // + // We do not create op-code storage widths for numerics in excess of 16 bits for now + // + if (DataWidth > 2) { + return EFI_DEVICE_ERROR; + } + + // + // Obtain current language value + // + GetCurrentLanguage (CurrentLanguage); + + // + // Add first string, get first string's token + // + Status = AddString (StringBuffer, CurrentLanguage, Prompt, &StringToken); + + if (EFI_ERROR (Status)) { + return Status; + } + + Numeric.Header.OpCode = EFI_IFR_NUMERIC_OP; + Numeric.Header.Length = sizeof (EFI_IFR_NUMERIC); + Numeric.QuestionId = QuestionId; + Numeric.Width = DataWidth; + Numeric.Prompt = StringToken; + + // + // Add second string, get first string's token + // + Status = AddString (StringBuffer, CurrentLanguage, Help, &StringToken); + + if (EFI_ERROR (Status)) { + return Status; + } + + Numeric.Help = StringToken; + Numeric.Minimum = Minimum; + Numeric.Maximum = Maximum; + Numeric.Step = Step; + Numeric.Default = Default; + Numeric.Flags = (UINT8) (Flags | EFI_IFR_FLAG_CREATED); + Numeric.Key = Key; + + Status = AddOpCode (FormBuffer, &Numeric); + + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} + + +EFI_STATUS +CreateString ( + IN UINT16 QuestionId, + IN UINT8 DataWidth, + IN CHAR16 *Prompt, + IN CHAR16 *Help, + IN UINT8 MinSize, + IN UINT8 MaxSize, + IN UINT8 Flags, + IN UINT16 Key, + IN OUT VOID *FormBuffer, + IN OUT VOID *StringBuffer + ) +/*++ + +Routine Description: + + Create a string + +Arguments: + + QuestionId - Question ID of the string + + DataWidth - DataWidth of the string + + Prompt - Prompt of the string + + Help - Help of the string + + MinSize - Min size boundary of the string + + MaxSize - Max size boundary of the string + + Flags - Flags of the string + + Key - Key of the string + + FormBuffer - The form where this string adds to + + StringBuffer - String buffer created for Prompt and Help. + +Returns: + + EFI_SUCCESS - String successfully created. + +--*/ +{ + EFI_STATUS Status; + EFI_IFR_STRING String; + CHAR16 CurrentLanguage[4]; + STRING_REF StringToken; + + // + // Obtain current language value + // + GetCurrentLanguage (CurrentLanguage); + + // + // Add first string, get first string's token + // + Status = AddString (StringBuffer, CurrentLanguage, Prompt, &StringToken); + + if (EFI_ERROR (Status)) { + return Status; + } + + String.Header.OpCode = EFI_IFR_STRING_OP; + String.Header.Length = sizeof (EFI_IFR_STRING); + String.QuestionId = QuestionId; + String.Width = DataWidth; + String.Prompt = StringToken; + + // + // Add second string, get first string's token + // + Status = AddString (StringBuffer, CurrentLanguage, Help, &StringToken); + + if (EFI_ERROR (Status)) { + return Status; + } + + String.Help = StringToken; + String.MinSize = MinSize; + String.MaxSize = MaxSize; + String.Flags = (UINT8) (Flags | EFI_IFR_FLAG_CREATED); + String.Key = Key; + + Status = AddOpCode (FormBuffer, &String); + + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Library/EdkIfrSupportLib/IfrOpCodeCreation.c b/EdkModulePkg/Library/EdkIfrSupportLib/IfrOpCodeCreation.c new file mode 100644 index 0000000000..6fb2be791e --- /dev/null +++ b/EdkModulePkg/Library/EdkIfrSupportLib/IfrOpCodeCreation.c @@ -0,0 +1,613 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + IfrOpCodeCreation.c + +Abstract: + + Library Routines to create IFR independent of string data - assume tokens already exist + Primarily to be used for exporting op-codes at a label in pre-defined forms. + +Revision History: + +--*/ + +EFI_STATUS +CreateSubTitleOpCode ( + IN STRING_REF StringToken, + IN OUT VOID *FormBuffer + ) +/*++ + +Routine Description: + + Create a SubTitle opcode independent of string creation + This is used primarily by users who need to create just one particular valid op-code and the string + data will be assumed to exist in the HiiDatabase already. (Useful when exporting op-codes at a label + location to pre-defined forms in HII) + +Arguments: + + StringToken - StringToken of the subtitle + + FormBuffer - Output of subtitle as a form + +Returns: + + EFI_SUCCESS - Subtitle created to be a form + +--*/ +{ + EFI_IFR_SUBTITLE Subtitle; + + Subtitle.Header.OpCode = EFI_IFR_SUBTITLE_OP; + Subtitle.Header.Length = sizeof (EFI_IFR_SUBTITLE); + Subtitle.SubTitle = StringToken; + + CopyMem (FormBuffer, &Subtitle, sizeof (EFI_IFR_SUBTITLE)); + return EFI_SUCCESS; +} + + +EFI_STATUS +CreateTextOpCode ( + IN STRING_REF StringToken, + IN STRING_REF StringTokenTwo, + IN STRING_REF StringTokenThree, + IN UINT8 Flags, + IN UINT16 Key, + IN OUT VOID *FormBuffer + ) +/*++ + +Routine Description: + + Create a Text opcode independent of string creation + This is used primarily by users who need to create just one particular valid op-code and the string + data will be assumed to exist in the HiiDatabase already. (Useful when exporting op-codes at a label + location to pre-defined forms in HII) + +Arguments: + + StringToken - First string token of the text + + StringTokenTwo - Second string token of the text + + StringTokenThree - Help string token of the text + + Flags - Flag of the text + + Key - Key of the text + + FormBuffer - Output of text as a form + +Returns: + + EFI_SUCCESS - Text created to be a form + +--*/ +{ + EFI_IFR_TEXT Text; + + Text.Header.OpCode = EFI_IFR_TEXT_OP; + Text.Header.Length = sizeof (EFI_IFR_TEXT); + Text.Text = StringToken; + + Text.TextTwo = StringTokenTwo; + Text.Help = StringTokenThree; + Text.Flags = Flags; + Text.Key = Key; + + CopyMem (FormBuffer, &Text, sizeof (EFI_IFR_TEXT)); + + return EFI_SUCCESS; +} + + +EFI_STATUS +CreateGotoOpCode ( + IN UINT16 FormId, + IN STRING_REF StringToken, + IN STRING_REF StringTokenTwo, + IN UINT8 Flags, + IN UINT16 Key, + IN OUT VOID *FormBuffer + ) +/*++ + +Routine Description: + + Create a hyperlink opcode independent of string creation + This is used primarily by users who need to create just one particular valid op-code and the string + data will be assumed to exist in the HiiDatabase already. (Useful when exporting op-codes at a label + location to pre-defined forms in HII) + +Arguments: + + FormId - Form ID of the hyperlink + + StringToken - Prompt string token of the hyperlink + + StringTokenTwo - Help string token of the hyperlink + + Flags - Flags of the hyperlink + + Key - Key of the hyperlink + + FormBuffer - Output of hyperlink as a form + +Returns: + + EFI_SUCCESS - Hyperlink created to be a form + +--*/ +{ + EFI_IFR_REF Hyperlink; + + Hyperlink.Header.OpCode = EFI_IFR_REF_OP; + Hyperlink.Header.Length = sizeof (EFI_IFR_REF); + Hyperlink.FormId = FormId; + Hyperlink.Prompt = StringToken; + Hyperlink.Help = StringTokenTwo; + Hyperlink.Key = Key; + Hyperlink.Flags = Flags; + + CopyMem (FormBuffer, &Hyperlink, sizeof (EFI_IFR_REF)); + + return EFI_SUCCESS; +} + + +EFI_STATUS +CreateOneOfOpCode ( + IN UINT16 QuestionId, + IN UINT8 DataWidth, + IN STRING_REF PromptToken, + IN STRING_REF HelpToken, + IN IFR_OPTION *OptionsList, + IN UINTN OptionCount, + IN OUT VOID *FormBuffer + ) +/*++ + +Routine Description: + + Create a one-of opcode with a set of option op-codes to choose from independent of string creation. + This is used primarily by users who need to create just one particular valid op-code and the string + data will be assumed to exist in the HiiDatabase already. (Useful when exporting op-codes at a label + location to pre-defined forms in HII) + + OptionsList is a pointer to a null-terminated list of option descriptions. Ensure that OptionsList[x].StringToken + has been filled in since this routine will not generate StringToken values. + +Arguments: + + QuestionId - Question ID of the one-of box + + DataWidth - DataWidth of the one-of box + + PromptToken - Prompt string token of the one-of box + + HelpToken - Help string token of the one-of box + + OptionsList - Each string in it is an option of the one-of box + + OptionCount - Option string count + + FormBuffer - Output of One-Of box as a form + +Returns: + + EFI_SUCCESS - One-Of box created to be a form + + EFI_DEVICE_ERROR - DataWidth > 2 + +--*/ +{ + UINTN Index; + EFI_IFR_ONE_OF OneOf; + EFI_IFR_ONE_OF_OPTION OneOfOption; + EFI_IFR_END_ONE_OF EndOneOf; + UINT8 *LocalBuffer; + + // + // We do not create op-code storage widths for one-of in excess of 16 bits for now + // + if (DataWidth > 2) { + return EFI_DEVICE_ERROR; + } + + OneOf.Header.OpCode = EFI_IFR_ONE_OF_OP; + OneOf.Header.Length = sizeof (EFI_IFR_ONE_OF); + OneOf.QuestionId = QuestionId; + OneOf.Width = DataWidth; + OneOf.Prompt = PromptToken; + + OneOf.Help = HelpToken; + + LocalBuffer = (UINT8 *) FormBuffer; + + CopyMem (LocalBuffer, &OneOf, sizeof (EFI_IFR_ONE_OF)); + + LocalBuffer = (UINT8 *) (LocalBuffer + sizeof (EFI_IFR_ONE_OF)); + + for (Index = 0; Index < OptionCount; Index++) { + OneOfOption.Header.OpCode = EFI_IFR_ONE_OF_OPTION_OP; + OneOfOption.Header.Length = sizeof (EFI_IFR_ONE_OF_OPTION); + + OneOfOption.Option = OptionsList[Index].StringToken; + OneOfOption.Value = OptionsList[Index].Value; + OneOfOption.Flags = OptionsList[Index].Flags; + OneOfOption.Key = OptionsList[Index].Key; + + CopyMem (LocalBuffer, &OneOfOption, sizeof (EFI_IFR_ONE_OF_OPTION)); + + LocalBuffer = (UINT8 *) (LocalBuffer + sizeof (EFI_IFR_ONE_OF_OPTION)); + } + + EndOneOf.Header.Length = sizeof (EFI_IFR_END_ONE_OF); + EndOneOf.Header.OpCode = EFI_IFR_END_ONE_OF_OP; + + CopyMem (LocalBuffer, &EndOneOf, sizeof (EFI_IFR_END_ONE_OF)); + + LocalBuffer = (UINT8 *) (LocalBuffer + sizeof (EFI_IFR_END_ONE_OF)); + + return EFI_SUCCESS; +} + +EFI_STATUS +CreateOrderedListOpCode ( + IN UINT16 QuestionId, + IN UINT8 MaxEntries, + IN STRING_REF PromptToken, + IN STRING_REF HelpToken, + IN IFR_OPTION *OptionsList, + IN UINTN OptionCount, + IN OUT VOID *FormBuffer + ) +/*++ + +Routine Description: + + Create a ordered list opcode with a set of option op-codes to choose from independent of string creation. + This is used primarily by users who need to create just one particular valid op-code and the string + data will be assumed to exist in the HiiDatabase already. (Useful when exporting op-codes at a label + location to pre-defined forms in HII) + + OptionsList is a pointer to a null-terminated list of option descriptions. Ensure that OptionsList[x].StringToken + has been filled in since this routine will not generate StringToken values. + +Arguments: + + QuestionId - Question ID of the ordered list + + MaxEntries - MaxEntries of the ordered list + + PromptToken - Prompt string token of the ordered list + + HelpToken - Help string token of the ordered list + + OptionsList - Each string in it is an option of the ordered list + + OptionCount - Option string count + + FormBuffer - Output of ordered list as a form + +Returns: + + EFI_SUCCESS - Ordered list created to be a form + +--*/ +{ + UINTN Index; + EFI_IFR_ORDERED_LIST OrderedList; + EFI_IFR_ONE_OF_OPTION OrderedListOption; + EFI_IFR_END_ONE_OF EndOrderedList; + UINT8 *LocalBuffer; + + OrderedList.Header.OpCode = EFI_IFR_ORDERED_LIST_OP; + OrderedList.Header.Length = sizeof (EFI_IFR_ORDERED_LIST); + OrderedList.QuestionId = QuestionId; + OrderedList.MaxEntries = MaxEntries; + OrderedList.Prompt = PromptToken; + + OrderedList.Help = HelpToken; + + LocalBuffer = (UINT8 *) FormBuffer; + + CopyMem (LocalBuffer, &OrderedList, sizeof (EFI_IFR_ORDERED_LIST)); + + LocalBuffer = (UINT8 *) (LocalBuffer + sizeof (EFI_IFR_ORDERED_LIST)); + + for (Index = 0; Index < OptionCount; Index++) { + OrderedListOption.Header.OpCode = EFI_IFR_ONE_OF_OPTION_OP; + OrderedListOption.Header.Length = sizeof (EFI_IFR_ONE_OF_OPTION); + + OrderedListOption.Option = OptionsList[Index].StringToken; + OrderedListOption.Value = OptionsList[Index].Value; + OrderedListOption.Flags = OptionsList[Index].Flags; + OrderedListOption.Key = OptionsList[Index].Key; + + CopyMem (LocalBuffer, &OrderedListOption, sizeof (EFI_IFR_ONE_OF_OPTION)); + + LocalBuffer = (UINT8 *) (LocalBuffer + sizeof (EFI_IFR_ONE_OF_OPTION)); + } + + EndOrderedList.Header.Length = sizeof (EFI_IFR_END_ONE_OF); + EndOrderedList.Header.OpCode = EFI_IFR_END_ONE_OF_OP; + + CopyMem (LocalBuffer, &EndOrderedList, sizeof (EFI_IFR_END_ONE_OF)); + + LocalBuffer = (UINT8 *) (LocalBuffer + sizeof (EFI_IFR_END_ONE_OF)); + + return EFI_SUCCESS; +} + +EFI_STATUS +CreateCheckBoxOpCode ( + IN UINT16 QuestionId, + IN UINT8 DataWidth, + IN STRING_REF PromptToken, + IN STRING_REF HelpToken, + IN UINT8 Flags, + IN UINT16 Key, + IN OUT VOID *FormBuffer + ) +/*++ + +Routine Description: + + Create a checkbox opcode independent of string creation + This is used primarily by users who need to create just one particular valid op-code and the string + data will be assumed to exist in the HiiDatabase already. (Useful when exporting op-codes at a label + location to pre-defined forms in HII) + +Arguments: + + QuestionId - Question ID of the check box + + DataWidth - DataWidth of the check box + + PromptToken - Prompt string token of the check box + + HelpToken - Help string token of the check box + + Flags - Flags of the check box + + Key - Key of the check box + + FormBuffer - Output of the check box as a form + +Returns: + + EFI_SUCCESS - Checkbox created to be a form + + EFI_DEVICE_ERROR - DataWidth > 1 + +--*/ +{ + EFI_IFR_CHECKBOX CheckBox; + + // + // We do not create op-code storage widths for checkbox in excess of 8 bits for now + // + if (DataWidth > 1) { + return EFI_DEVICE_ERROR; + } + + CheckBox.Header.OpCode = EFI_IFR_CHECKBOX_OP; + CheckBox.Header.Length = sizeof (EFI_IFR_CHECKBOX); + CheckBox.QuestionId = QuestionId; + CheckBox.Width = DataWidth; + CheckBox.Prompt = PromptToken; + + CheckBox.Help = HelpToken; + CheckBox.Flags = Flags; + CheckBox.Key = Key; + + CopyMem (FormBuffer, &CheckBox, sizeof (EFI_IFR_CHECKBOX)); + + return EFI_SUCCESS; +} + + +EFI_STATUS +CreateNumericOpCode ( + IN UINT16 QuestionId, + IN UINT8 DataWidth, + IN STRING_REF PromptToken, + IN STRING_REF HelpToken, + IN UINT16 Minimum, + IN UINT16 Maximum, + IN UINT16 Step, + IN UINT16 Default, + IN UINT8 Flags, + IN UINT16 Key, + IN OUT VOID *FormBuffer + ) +/*++ + +Routine Description: + + Create a numeric opcode independent of string creation + This is used primarily by users who need to create just one particular valid op-code and the string + data will be assumed to exist in the HiiDatabase already. (Useful when exporting op-codes at a label + location to pre-defined forms in HII) + +Arguments: + + QuestionId - Question ID of the numeric + + DataWidth - DataWidth of the numeric + + PromptToken - Prompt string token of the numeric + + HelpToken - Help string token of the numeric + + Minimum - Minumun boundary of the numeric + + Maximum - Maximum boundary of the numeric + + Step - Step of the numeric + + Default - Default value of the numeric + + Flags - Flags of the numeric + + Key - Key of the numeric + + FormBuffer - Output of the numeric as a form + +Returns: + + EFI_SUCCESS - The numeric created to be a form. + + EFI_DEVICE_ERROR - DataWidth > 2 + +--*/ +{ + EFI_IFR_NUMERIC Numeric; + + // + // We do not create op-code storage widths for numerics in excess of 16 bits for now + // + if (DataWidth > 2) { + return EFI_DEVICE_ERROR; + } + + Numeric.Header.OpCode = EFI_IFR_NUMERIC_OP; + Numeric.Header.Length = sizeof (EFI_IFR_NUMERIC); + Numeric.QuestionId = QuestionId; + Numeric.Width = DataWidth; + Numeric.Prompt = PromptToken; + + Numeric.Help = HelpToken; + Numeric.Minimum = Minimum; + Numeric.Maximum = Maximum; + Numeric.Step = Step; + Numeric.Default = Default; + Numeric.Flags = Flags; + Numeric.Key = Key; + + CopyMem (FormBuffer, &Numeric, sizeof (EFI_IFR_NUMERIC)); + + return EFI_SUCCESS; +} + + +EFI_STATUS +CreateStringOpCode ( + IN UINT16 QuestionId, + IN UINT8 DataWidth, + IN STRING_REF PromptToken, + IN STRING_REF HelpToken, + IN UINT8 MinSize, + IN UINT8 MaxSize, + IN UINT8 Flags, + IN UINT16 Key, + IN OUT VOID *FormBuffer + ) +/*++ + +Routine Description: + + Create a numeric opcode independent of string creation + This is used primarily by users who need to create just one particular valid op-code and the string + data will be assumed to exist in the HiiDatabase already. (Useful when exporting op-codes at a label + location to pre-defined forms in HII) + +Arguments: + + QuestionId - Question ID of the string + + DataWidth - DataWidth of the string + + PromptToken - Prompt token of the string + + HelpToken - Help token of the string + + MinSize - Min size boundary of the string + + MaxSize - Max size boundary of the string + + Flags - Flags of the string + + Key - Key of the string + + FormBuffer - Output of the string as a form + +Returns: + + EFI_SUCCESS - String created to be a form. + +--*/ +{ + EFI_IFR_STRING String; + + String.Header.OpCode = EFI_IFR_STRING_OP; + String.Header.Length = sizeof (EFI_IFR_STRING); + String.QuestionId = QuestionId; + String.Width = DataWidth; + String.Prompt = PromptToken; + + String.Help = HelpToken; + String.MinSize = MinSize; + String.MaxSize = MaxSize; + String.Flags = Flags; + String.Key = Key; + + CopyMem (FormBuffer, &String, sizeof (EFI_IFR_STRING)); + + return EFI_SUCCESS; +} + + +EFI_STATUS +CreateBannerOpCode ( + IN UINT16 Title, + IN UINT16 LineNumber, + IN UINT8 Alignment, + IN OUT VOID *FormBuffer + ) +/*++ + +Routine Description: + + Create a banner opcode. This is primarily used by the FrontPage implementation from BDS. + +Arguments: + + Title - Title of the banner + + LineNumber - LineNumber of the banner + + Alignment - Alignment of the banner + + FormBuffer - Output of banner as a form + +Returns: + + EFI_SUCCESS - Banner created to be a form. + +--*/ +{ + EFI_IFR_BANNER Banner; + + Banner.Header.OpCode = EFI_IFR_BANNER_OP; + Banner.Header.Length = sizeof (EFI_IFR_BANNER); + CopyMem (&Banner.Title, &Title, sizeof (UINT16)); + CopyMem (&Banner.LineNumber, &LineNumber, sizeof (UINT16)); + Banner.Alignment = Alignment; + + CopyMem (FormBuffer, &Banner, sizeof (EFI_IFR_BANNER)); + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Library/EdkIfrSupportLib/IfrVariable.c b/EdkModulePkg/Library/EdkIfrSupportLib/IfrVariable.c new file mode 100644 index 0000000000..3e37553668 --- /dev/null +++ b/EdkModulePkg/Library/EdkIfrSupportLib/IfrVariable.c @@ -0,0 +1,484 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + IfrVariable.c + +Abstract: + Variable/Map manipulations routines + +--*/ + +VOID +EfiLibHiiVariablePackGetMap ( + IN EFI_HII_VARIABLE_PACK *Pack, + OUT CHAR16 **Name, OPTIONAL + OUT EFI_GUID **Guid, OPTIONAL + OUT UINT16 *Id, OPTIONAL + OUT VOID **Var, OPTIONAL + OUT UINTN *Size OPTIONAL + ) +/*++ + +Routine Description: + + Extracts a variable form a Pack. + +Arguments: + + Pack - List of variables + Name - Name of the variable/map + Guid - GUID of the variable/map + Var - Pointer to the variable/map + Size - Size of the variable/map in bytes + +Returns: + + VOID + +--*/ +{ + if (NULL != Name) { + *Name = (VOID *) (Pack + 1); + } + + if (NULL != Guid) { + *Guid = (EFI_GUID *)(UINTN)&Pack->VariableGuid; + } + + + if (NULL != Id) { + *Id = Pack->VariableId; + } + + if (NULL != Var) { + *Var = (VOID *) ((CHAR8 *) (Pack + 1) + Pack->VariableNameLength); + } + + if (NULL != Size) { + *Size = Pack->Header.Length - sizeof (*Pack) - Pack->VariableNameLength; + } +} + + +UINTN +EfiLibHiiVariablePackListGetMapCnt ( + IN EFI_HII_VARIABLE_PACK_LIST *List + ) + +/*++ + +Routine Description: + + Finds a count of the variables/maps in the List. + +Arguments: + + List - List of variables + +Returns: + + UINTN - The number of map count. + +--*/ + +{ + UINTN Cnt = 0; + while (NULL != List) { + Cnt++; + List = List->NextVariablePack; + } + return Cnt; +} + + +VOID +EfiLibHiiVariablePackListForEachVar ( + IN EFI_HII_VARIABLE_PACK_LIST *List, + IN EFI_LIB_HII_VARIABLE_PACK_LIST_CALLBACK *Callback + ) +/*++ + +Routine Description: + + Will iterate all variable/maps as appearing + in List and for each, it will call the Callback. + +Arguments: + + List - List of variables + Callback - Routine to be called for each iterated variable. + +Returns: + + VOID + +--*/ + +{ + CHAR16 *MapName; + EFI_GUID *MapGuid; + UINT16 MapId; + VOID *Map; + UINTN MapSize; + + while (NULL != List) { + EfiLibHiiVariablePackGetMap (List->VariablePack, &MapName, &MapGuid, &MapId, &Map, &MapSize); + // + // call the callback + // + Callback (MapName, MapGuid, MapId, Map, MapSize); + List = List->NextVariablePack; + } +} + + +EFI_STATUS +EfiLibHiiVariablePackListGetMapByIdx ( + IN UINTN Idx, + IN EFI_HII_VARIABLE_PACK_LIST *List, + OUT CHAR16 **Name, OPTIONAL + OUT EFI_GUID **Guid, OPTIONAL + OUT UINT16 *Id, OPTIONAL + OUT VOID **Var, + OUT UINTN *Size + ) + +/*++ + +Routine Description: + + Finds a variable form List given + the order number as appears in the List. + +Arguments: + + Idx - The index of the variable/map to retrieve + List - List of variables + Name - Name of the variable/map + Guid - GUID of the variable/map + Var - Pointer to the variable/map + Size - Size of the variable/map in bytes + +Returns: + + EFI_SUCCESS - Variable is found, OUT parameters are valid + EFI_NOT_FOUND - Variable is not found, OUT parameters are not valid + +--*/ +{ + CHAR16 *MapName; + EFI_GUID *MapGuid; + UINT16 MapId; + VOID *Map; + UINTN MapSize; + + while (NULL != List) { + EfiLibHiiVariablePackGetMap (List->VariablePack, &MapName, &MapGuid, &MapId, &Map, &MapSize); + if (0 == Idx--) { + *Var = Map; + *Size = MapSize; + + if (NULL != Name) { + *Name = MapName; + } + + if (NULL != Guid) { + *Guid = MapGuid; + } + + if (NULL != Id) { + *Id = MapId; + } + + return EFI_SUCCESS; // Map found + } + List = List->NextVariablePack; + } + // + // If here, the map is not found + // + return EFI_NOT_FOUND; +} + + +EFI_STATUS +EfiLibHiiVariablePackListGetMapById ( + IN UINT16 Id, + IN EFI_HII_VARIABLE_PACK_LIST *List, + OUT CHAR16 **Name, OPTIONAL + OUT EFI_GUID **Guid, OPTIONAL + OUT VOID **Var, + OUT UINTN *Size + ) + +/*++ + +Routine Description: + + Finds a variable form List given the + order number as appears in the List. + +Arguments: + + Id - The ID of the variable/map to retrieve + List - List of variables + Name - Name of the variable/map + Guid - GUID of the variable/map + Var - Pointer to the variable/map + Size - Size of the variable/map in bytes + +Returns: + + EFI_SUCCESS - Variable is found, OUT parameters are valid + EFI_NOT_FOUND - Variable is not found, OUT parameters are not valid + +--*/ + +{ + CHAR16 *MapName; + EFI_GUID *MapGuid; + UINT16 MapId; + VOID *Map; + UINTN MapSize; + + while (NULL != List) { + EfiLibHiiVariablePackGetMap (List->VariablePack, &MapName, &MapGuid, &MapId, &Map, &MapSize); + if (MapId == Id) { + *Var = Map; + *Size = MapSize; + if (NULL != Name) { + *Name = MapName; + } + if (NULL != Guid) { + *Guid = MapGuid; + } + // + // Map found + // + return EFI_SUCCESS; + } + List = List->NextVariablePack; + } + // + // If here, the map is not found + // + return EFI_NOT_FOUND; +} + + +EFI_STATUS +EfiLibHiiVariablePackListGetMap ( + IN EFI_HII_VARIABLE_PACK_LIST *List, + IN CHAR16 *Name, + IN EFI_GUID *Guid, + OUT UINT16 *Id, + OUT VOID **Var, + OUT UINTN *Size + ) + +/*++ + +Routine Description: + + Finds a variable form EFI_HII_VARIABLE_PACK_LIST given name and GUID. + +Arguments: + + List - List of variables + Name - Name of the variable/map to be found + Guid - GUID of the variable/map to be found + Var - Pointer to the variable/map found + Size - Size of the variable/map in bytes found + +Returns: + + EFI_SUCCESS - variable is found, OUT parameters are valid + EFI_NOT_FOUND - variable is not found, OUT parameters are not valid + +--*/ + +{ + VOID *Map; + UINTN MapSize; + UINT16 MapId; + CHAR16 *MapName; + EFI_GUID *MapGuid; + + while (NULL != List) { + EfiLibHiiVariablePackGetMap (List->VariablePack, &MapName, &MapGuid, &MapId, &Map, &MapSize); + if ((0 == StrCmp (Name, MapName)) && CompareGuid (Guid, MapGuid)) { + *Id = MapId; + *Var = Map; + *Size = MapSize; + return EFI_SUCCESS; + } + List = List->NextVariablePack; + } + // + // If here, the map is not found + // + return EFI_NOT_FOUND; +} + +EFI_STATUS +EfiLibHiiVariableRetrieveFromNv ( + IN CHAR16 *Name, + IN EFI_GUID *Guid, + IN UINTN Size, + OUT VOID **Var + ) +/*++ + +Routine Description: + Finds out if a variable of specific Name/Guid/Size exists in NV. + If it does, it will retrieve it into the Var. + +Arguments: + Name, Guid, Size - Parameters of the variable to retrieve. Must match exactly. + Var - Variable will be retrieved into buffer pointed by this pointer. + If pointing to NULL, the buffer will be allocated. Caller is responsible for releasing the buffer. +Returns: + EFI_SUCCESS - The variable of exact Name/Guid/Size parameters was retrieved and written to Var. + EFI_NOT_FOUND - The variable of this Name/Guid was not found in the NV. + EFI_LOAD_ERROR - The variable in the NV was of different size, or NV API returned error. + +--*/ +{ + EFI_STATUS Status; + UINTN SizeNv; + + // + // Test for existence of the variable. + // + SizeNv = 0; + Status = gRT->GetVariable (Name, Guid, NULL, &SizeNv, NULL); + if (EFI_BUFFER_TOO_SMALL != Status) { + ASSERT (EFI_SUCCESS != Status); + return EFI_NOT_FOUND; + } + if (SizeNv != Size) { + // + // The variable is considered corrupt, as it has different size from expected. + // + return EFI_LOAD_ERROR; + } + + if (NULL == *Var) { + *Var = AllocatePool (Size); + ASSERT (NULL != *Var); + } + SizeNv = Size; + // + // Final read into the Var + // + Status = gRT->GetVariable (Name, Guid, NULL, &SizeNv, *Var); + // + // No tolerance for random failures. Such behavior is undetermined and not validated. + // + ASSERT_EFI_ERROR (Status); + ASSERT (SizeNv == Size); + return EFI_SUCCESS; +} + + + +EFI_STATUS +EfiLibHiiVariableOverrideIfSuffix ( + IN CHAR16 *Suffix, + IN CHAR16 *Name, + IN EFI_GUID *Guid, + IN UINTN Size, + OUT VOID *Var + ) +/*++ + +Routine Description: + Overrrides the variable with NV data if found. + But it only does it if the Name ends with specified Suffix. + For example, if Suffix="MyOverride" and the Name="XyzSetupMyOverride", + the Suffix matches the end of Name, so the variable will be loaded from NV + provided the variable exists and the GUID and Size matches. + +Arguments: + Suffix - Suffix the Name should end with. + Name, Guid, Size - Parameters of the variable to retrieve. Must match exactly. + Var - Variable will be retrieved into this buffer. + Caller is responsible for providing storage of exactly Size size in bytes. +Returns: + EFI_SUCCESS - The variable was overriden with NV variable of same Name/Guid/Size. + EFI_INVALID_PARAMETER - The name of the variable does not end with . + EFI_NOT_FOUND - The variable of this Name/Guid was not found in the NV. + EFI_LOAD_ERROR - The variable in the NV was of different size, or NV API returned error. + +--*/ +{ + UINTN StrLength; + UINTN StrLenSuffix; + + StrLength = StrLen (Name); + StrLenSuffix = StrLen (Suffix); + if ((StrLength <= StrLenSuffix) || (0 != StrCmp (Suffix, &Name[StrLength - StrLenSuffix]))) { + // + // Not ending with . + // + return EFI_INVALID_PARAMETER; + } + return EfiLibHiiVariableRetrieveFromNv (Name, Guid, Size, &Var); +} + +EFI_STATUS +EfiLibHiiVariableOverrideBySuffix ( + IN CHAR16 *Suffix, + IN CHAR16 *Name, + IN EFI_GUID *Guid, + IN UINTN Size, + OUT VOID *Var + ) +/*++ + +Routine Description: + Overrrides the variable with NV data if found. + But it only does it if the NV contains the same variable with Name is appended with Suffix. + For example, if Suffix="MyOverride" and the Name="XyzSetup", + the Suffix will be appended to the end of Name, and the variable with Name="XyzSetupMyOverride" + will be loaded from NV provided the variable exists and the GUID and Size matches. + +Arguments: + Suffix - Suffix the variable will be appended with. + Name, Guid, Size - Parameters of the variable to retrieve. Must match exactly. + Var - Variable will be retrieved into this buffer. + Caller is responsible for providing storage of exactly Size size in bytes. + +Returns: + EFI_SUCCESS - The variable was overriden with NV variable of same Name/Guid/Size. + EFI_NOT_FOUND - The variable of this Name/Guid was not found in the NV. + EFI_LOAD_ERROR - The variable in the NV was of different size, or NV API returned error. + +--*/ +{ + EFI_STATUS Status; + CHAR16 *NameSuffixed; + + // + // enough to concatenate both strings. + // + NameSuffixed = AllocateZeroPool ((StrLen (Name) + StrLen (Suffix) + 1) * sizeof (CHAR16)); + + StrCpy (NameSuffixed, Name); + StrCat (NameSuffixed, Suffix); + + Status = EfiLibHiiVariableRetrieveFromNv (NameSuffixed, Guid, Size, &Var); + gBS->FreePool (NameSuffixed); + + return Status; +} + diff --git a/EdkModulePkg/Library/EdkIfrSupportLib/build.xml b/EdkModulePkg/Library/EdkIfrSupportLib/build.xml new file mode 100644 index 0000000000..54b607a71f --- /dev/null +++ b/EdkModulePkg/Library/EdkIfrSupportLib/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Library/EdkMemoryStatusCodeLib/EdkMemoryStatusCodeLib.mbd b/EdkModulePkg/Library/EdkMemoryStatusCodeLib/EdkMemoryStatusCodeLib.mbd new file mode 100644 index 0000000000..01e0cb2e4a --- /dev/null +++ b/EdkModulePkg/Library/EdkMemoryStatusCodeLib/EdkMemoryStatusCodeLib.mbd @@ -0,0 +1,30 @@ + + + + + EdkMemoryStatusCodeLib + e2368d1d-4c94-4e62-be2f-7817bbd78293 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + diff --git a/EdkModulePkg/Library/EdkMemoryStatusCodeLib/EdkMemoryStatusCodeLib.msa b/EdkModulePkg/Library/EdkMemoryStatusCodeLib/EdkMemoryStatusCodeLib.msa new file mode 100644 index 0000000000..6ad58a20e4 --- /dev/null +++ b/EdkModulePkg/Library/EdkMemoryStatusCodeLib/EdkMemoryStatusCodeLib.msa @@ -0,0 +1,63 @@ + + + + + EdkMemoryStatusCodeLib + PEIM + LIBRARY + e2368d1d-4c94-4e62-be2f-7817bbd78293 + 0 + Memory Status Code Library for UEFI drivers + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + EdkMemoryStatusCodeLib + DebugLib + HobLib + BaseLib + PeiCoreLib + PeiServicesTablePointerLib + BaseMemoryLib + + + MemoryStatusCode.c + MemoryStatusCode.h + + + MdePkg + EdkModulePkg + + + + StatusCodeMemoryPpi + gPeiStatusCodeMemoryPpiGuid + 0x26f8ab01, 0xd3cd, 0x489c, 0x98, 0x4f, 0xdf, 0xde, 0xf7, 0x68, 0x39, 0x5b + + + + StatusCodeMemory + StatusCode + FvFileLoader + + diff --git a/EdkModulePkg/Library/EdkMemoryStatusCodeLib/MemoryStatusCode.c b/EdkModulePkg/Library/EdkMemoryStatusCodeLib/MemoryStatusCode.c new file mode 100644 index 0000000000..1661d7753c --- /dev/null +++ b/EdkModulePkg/Library/EdkMemoryStatusCodeLib/MemoryStatusCode.c @@ -0,0 +1,498 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + MemoryStatusCode.c + +Abstract: + + Lib to provide memory journal status code reporting Routines. + +--*/ +#include "MemoryStatusCode.h" + +// +// Global variable. Not accessible while running from flash. +// After we relocate ourselves into memory, we update this +// and use it to determine if we are running from flash or memory. +// + +// +// Global variable used to replace the PPI once we start running from memory. +// +PEI_STATUS_CODE_MEMORY_PPI mStatusCodeMemoryPpi = { 0, 0, 0, 0 }; + +// +// PPI descriptor for the MonoStatusCode PEIM, see MonoStatusCode.c +// +extern EFI_PEI_PPI_DESCRIPTOR mPpiListStatusCode; + +EFI_STATUS +EFIAPI +MemoryStatusCodeInitialize ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices + ) +/*++ + +Routine Description: + + Initialization routine. + Allocates heap space for storing Status Codes. + Installs a PPI to point to that heap space. + Installs a callback to switch to memory. + Installs a callback to + +Arguments: + + FfsHeader - FV this PEIM was loaded from. + PeiServices - General purpose services available to every PEIM. + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + MEMORY_STATUS_CODE_INSTANCE *PrivateData; + PEI_STATUS_CODE_MEMORY_PPI *StatusCodeMemoryPpi; + EFI_PEI_PROGRESS_CODE_PPI *ReportStatusCodePpi; + EFI_PHYSICAL_ADDRESS Buffer; + VOID *StartPointer; + UINTN Length; + UINTN LastEntry; + EFI_PEI_PPI_DESCRIPTOR *ReportStatusCodeDescriptor; + EFI_PEI_PPI_DESCRIPTOR *StatusCodeMemoryDescriptor; + + // + // Determine if we are being called after relocation into memory. + // + if (!gRunningFromMemory) { + // + // If we are not running from memory, we need to allocate some heap and + // install the PPI + // + // + // Allocate heap storage for the journal + // + Status = (*PeiServices)->AllocatePool ( + PeiServices, + PEI_STATUS_CODE_HEAP_LENGTH, + &StartPointer + ); + + // + // This is not a required feature to boot. + // + if (EFI_ERROR (Status)) { + return Status; + } + // + // Allocate heap storage for private data + // The private data contains the FFS header for this PEIM, + // a PPI containing information about the status code journal, and + // a notification for the LoadFile service, to relocate the PEIM into + // memory. + // + Status = (*PeiServices)->AllocatePool ( + PeiServices, + sizeof (MEMORY_STATUS_CODE_INSTANCE), + (VOID **) &PrivateData + ); + + // + // This is not a required feature to boot. + // + if (EFI_ERROR (Status)) { + return Status; + } + // + // Update the contents of the private data. + // + PrivateData->Signature = MEMORY_STATUS_CODE_SIGNATURE; + PrivateData->This = PrivateData; + PrivateData->FfsHeader = FfsHeader; + PrivateData->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST); + PrivateData->PpiDescriptor.Guid = &gPeiStatusCodeMemoryPpiGuid; + PrivateData->PpiDescriptor.Ppi = &PrivateData->StatusCodeMemoryPpi; + PrivateData->StatusCodeMemoryPpi.FirstEntry = 0; + PrivateData->StatusCodeMemoryPpi.LastEntry = 0; + PrivateData->StatusCodeMemoryPpi.Address = (EFI_PHYSICAL_ADDRESS) (UINTN) StartPointer; + PrivateData->StatusCodeMemoryPpi.Length = PEI_STATUS_CODE_HEAP_LENGTH; + PrivateData->NotifyDescriptor.Flags = + ( + EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | + EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST + ); + PrivateData->NotifyDescriptor.Guid = &gEfiPeiFvFileLoaderPpiGuid; + PrivateData->NotifyDescriptor.Notify = LoadImageCallback; + + // + // Publish the PPI + // + Status = (*PeiServices)->InstallPpi (PeiServices, &PrivateData->PpiDescriptor); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Post a callback to relocate to memory + // + Status = (**PeiServices).NotifyPpi (PeiServices, &PrivateData->NotifyDescriptor); + if (EFI_ERROR (Status)) { + return Status; + } + } else { + // + // If we are running from memory, we need to copy from the heap to a RT + // memory buffer. + // + // + // Locate Journal + // + Status = (*PeiServices)->LocatePpi ( + PeiServices, + &gPeiStatusCodeMemoryPpiGuid, + 0, + &StatusCodeMemoryDescriptor, + (VOID **) &StatusCodeMemoryPpi + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Get private data + // + PrivateData = _CR (StatusCodeMemoryDescriptor, MEMORY_STATUS_CODE_INSTANCE, PpiDescriptor); + // + // At this point, we need to fix up any addresses that we have as the heap + // has moved. + // + PrivateData->PpiDescriptor.Ppi = &PrivateData->StatusCodeMemoryPpi; + PrivateData->PpiDescriptor.Guid = &gPeiStatusCodeMemoryPpiGuid; + PrivateData->StatusCodeMemoryPpi.Address = PrivateData->StatusCodeMemoryPpi.Address + + (UINTN) PrivateData - (UINTN) PrivateData->This; + PrivateData->NotifyDescriptor.Guid = &gEfiPeiFvFileLoaderPpiGuid; + PrivateData->NotifyDescriptor.Notify = LoadImageCallback; + PrivateData->This = PrivateData; + + // + // Allocate RT memory. + // + Status = (*PeiServices)->AllocatePages ( + PeiServices, + EfiRuntimeServicesData, + PEI_STATUS_CODE_RT_PAGES, + &Buffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + DEBUG_CODE ( + ZeroMem ((VOID *) (UINTN) Buffer, PEI_STATUS_CODE_RT_LENGTH); + ); + + // + // Copy the heap to the allocated memory. + // Unwind the rolling queue to start at 0 in the new space. We need to do + // this because the new queue is much bigger than the heap allocation. + // + if (PEI_STATUS_CODE_RT_LENGTH <= PEI_STATUS_CODE_HEAP_LENGTH) { + return Status; + } + + if (StatusCodeMemoryPpi->LastEntry >= StatusCodeMemoryPpi->FirstEntry) { + LastEntry = StatusCodeMemoryPpi->LastEntry - StatusCodeMemoryPpi->FirstEntry; + StartPointer = (VOID *) ((UINTN) StatusCodeMemoryPpi->Address + (StatusCodeMemoryPpi->FirstEntry * sizeof (EFI_STATUS_CODE_ENTRY))); + Length = (StatusCodeMemoryPpi->LastEntry - StatusCodeMemoryPpi->FirstEntry) * sizeof (EFI_STATUS_CODE_ENTRY); + (*PeiServices)->CopyMem ((VOID *) (UINTN) Buffer, StartPointer, Length); + } else { + // + // The last entry will be the new last entry after moving heap to buffer + // + LastEntry = (PEI_STATUS_CODE_MAX_HEAP_ENTRY - StatusCodeMemoryPpi->FirstEntry) + StatusCodeMemoryPpi->LastEntry; + // + // Copy from the first entry to the end of the heap + // + StartPointer = (VOID *) ((UINTN) StatusCodeMemoryPpi->Address + (StatusCodeMemoryPpi->FirstEntry * sizeof (EFI_STATUS_CODE_ENTRY))); + Length = PEI_STATUS_CODE_HEAP_LENGTH - (StatusCodeMemoryPpi->FirstEntry * sizeof (EFI_STATUS_CODE_ENTRY)); + (*PeiServices)->CopyMem ((VOID *) (UINTN) Buffer, StartPointer, Length); + // + // Copy from the start to the heap to the last entry + // + StartPointer = (VOID *) (UINTN) StatusCodeMemoryPpi->Address; + (*PeiServices)->CopyMem ( + (VOID *) (UINTN) (Buffer + Length), + StartPointer, + (StatusCodeMemoryPpi->LastEntry * sizeof (EFI_STATUS_CODE_ENTRY)) + ); + }; + + // + // Update the PPI to NULL, so it will not be used. + // + StatusCodeMemoryPpi->FirstEntry = 0; + StatusCodeMemoryPpi->LastEntry = 0; + StatusCodeMemoryPpi->Address = 0; + StatusCodeMemoryPpi->Length = 0; + + // + // Update in memory version of PPI that will be used. + // + mStatusCodeMemoryPpi.FirstEntry = 0; + mStatusCodeMemoryPpi.LastEntry = LastEntry; + mStatusCodeMemoryPpi.Address = (EFI_PHYSICAL_ADDRESS) (UINTN) Buffer; + mStatusCodeMemoryPpi.Length = PEI_STATUS_CODE_RT_LENGTH; + + // + // Reinstall the report status code function + // + // + // Locate status code PPI + // + Status = (*PeiServices)->LocatePpi ( + PeiServices, + &gEfiPeiStatusCodePpiGuid, + 0, + &ReportStatusCodeDescriptor, + (VOID **) &ReportStatusCodePpi + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Reinstall the ReportStatusCode interface using the memory-based + // descriptor + // + Status = (*PeiServices)->ReInstallPpi ( + PeiServices, + ReportStatusCodeDescriptor, + &mPpiListStatusCode + ); + if (EFI_ERROR (Status)) { + CpuBreakpoint (); + return Status; + } + // + // Publish a GUIDed HOB that contains a pointer to the status code PPI + // structure. This is a bit of a short cut as I just used the PPI GUID to + // identify the HOB. This HOB is caught by the DXE status code memory + // listener and used to find the journal. + // + StatusCodeMemoryPpi = &mStatusCodeMemoryPpi; + + BuildGuidDataHob ( + &gPeiStatusCodeMemoryPpiGuid, + &StatusCodeMemoryPpi, + sizeof (VOID *) + ); + } + return EFI_SUCCESS; +} + +EFI_STATUS +MemoryReportStatusCode ( + 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 + ) +/*++ + +Routine Description: + + Provide a memory status code + +Arguments: + + Same as ReportStatusCode PPI + +Returns: + + EFI_SUCCESS This function always returns success + +--*/ +{ + EFI_STATUS Status; + PEI_STATUS_CODE_MEMORY_PPI *StatusCodeMemoryPpi; + EFI_STATUS_CODE_ENTRY *CurrentEntry; + UINTN LastEntry; + MEMORY_STATUS_CODE_INSTANCE *PrivateData; + EFI_PEI_PPI_DESCRIPTOR *StatusCodeMemoryDescriptor; + EFI_PEI_SERVICES **PeiServices; + + PeiServices = GetPeiServicesTablePointer (); + // + // We don't care to log debug codes. + // + if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE) { + return EFI_SUCCESS; + } + + if (!gRunningFromMemory) { + // + // If we are called from DXE and have not been reinstalled into memory, we + // can no longer locate the journal, so we can no longer log status codes. + // + if (!PeiServices) { + return EFI_SUCCESS; + } + // + // Locate Journal + // + Status = (*PeiServices)->LocatePpi ( + PeiServices, + &gPeiStatusCodeMemoryPpiGuid, + 0, + &StatusCodeMemoryDescriptor, + (VOID **) &StatusCodeMemoryPpi + ); + if (EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + // + // Determine the last entry in the journal. + // This is needed to properly implement the rolling queue. + // + LastEntry = PEI_STATUS_CODE_MAX_HEAP_ENTRY; + + // + // Get private data + // + PrivateData = _CR (StatusCodeMemoryDescriptor, MEMORY_STATUS_CODE_INSTANCE, PpiDescriptor); + + // + // Once memory gets installed, heap gets moved to real memory. + // We need to fix up the pointers to match the move. + // + PrivateData->PpiDescriptor.Ppi = &PrivateData->StatusCodeMemoryPpi; + PrivateData->PpiDescriptor.Guid = &gPeiStatusCodeMemoryPpiGuid; + PrivateData->StatusCodeMemoryPpi.Address = PrivateData->StatusCodeMemoryPpi.Address + + (UINTN) PrivateData - (UINTN) PrivateData->This; + PrivateData->NotifyDescriptor.Guid = &gEfiPeiFvFileLoaderPpiGuid; + PrivateData->NotifyDescriptor.Notify = LoadImageCallback; + PrivateData->This = PrivateData; + + StatusCodeMemoryPpi = PrivateData->PpiDescriptor.Ppi; + } else { + // + // Use global/memory copy of the PPI + // + StatusCodeMemoryPpi = &mStatusCodeMemoryPpi; + + // + // Determine the last entry in the journal. + // This is needed to properly implement the rolling queue. + // + LastEntry = PEI_STATUS_CODE_MAX_RT_ENTRY; + } + // + // Return if we are using a cleared PPI somehow + // + if (!StatusCodeMemoryPpi->Address || !StatusCodeMemoryPpi->Length) { + return EFI_SUCCESS; + } + // + // Update the latest entry in the journal (may actually be first due to rolling + // queue). + // + CurrentEntry = (EFI_STATUS_CODE_ENTRY *) (UINTN) (StatusCodeMemoryPpi->Address + (StatusCodeMemoryPpi->LastEntry * sizeof (EFI_STATUS_CODE_ENTRY))); + + StatusCodeMemoryPpi->LastEntry = (StatusCodeMemoryPpi->LastEntry + 1) % LastEntry; + if (StatusCodeMemoryPpi->LastEntry == StatusCodeMemoryPpi->FirstEntry) { + StatusCodeMemoryPpi->FirstEntry = (StatusCodeMemoryPpi->FirstEntry + 1) % LastEntry; + } + + CurrentEntry->Type = CodeType; + CurrentEntry->Value = Value; + CurrentEntry->Instance = Instance; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +LoadImageCallback ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ) +/*++ + +Routine Description: + + Relocate the PEIM into memory. + + Once load protocol becomes available, relocate our PEIM into memory. + The primary benefit is to eliminate the blackout window that we would have in + the memory log between the end of PEI and the status code DXE driver taking + control. If we don't do this, we cannot determine where our memory journal + is located and cannot function. + + A second benefit is speed optimization throughout DXE. + +Arguments: + + PeiServices - General purpose services available to every PEIM. + NotifyDescriptor - Information about the notify event. + Ppi - Context + +Returns: + + EFI_SUCCESS This function always returns success. + +--*/ +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS ImageAddress; + EFI_PHYSICAL_ADDRESS EntryPoint; + UINT64 ImageSize; + MEMORY_STATUS_CODE_INSTANCE *PrivateData; + + // + // Relocate to memory + // + if (!gRunningFromMemory) { + // + // Use the callback descriptor to get the FfsHeader + // + PrivateData = _CR (NotifyDescriptor, MEMORY_STATUS_CODE_INSTANCE, NotifyDescriptor); + + Status = ((EFI_PEI_FV_FILE_LOADER_PPI *) Ppi)->FvLoadFile ( + Ppi, + PrivateData->FfsHeader, + &ImageAddress, + &ImageSize, + &EntryPoint + ); + if (EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + // + // Set the flag in the loaded image that indicates the PEIM is executing + // from memory. + // +#ifdef EFI_NT_EMULATOR + gRunningFromMemory = TRUE; +#else + * (BOOLEAN *) ((UINTN) &gRunningFromMemory + (UINTN) EntryPoint - (UINTN) InstallMonoStatusCode) = TRUE; +#endif + Status = ((EFI_PEIM_ENTRY_POINT )(UINTN) EntryPoint) (PrivateData->FfsHeader, PeiServices); + if (EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + } + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Library/EdkMemoryStatusCodeLib/MemoryStatusCode.h b/EdkModulePkg/Library/EdkMemoryStatusCodeLib/MemoryStatusCode.h new file mode 100644 index 0000000000..3580083efa --- /dev/null +++ b/EdkModulePkg/Library/EdkMemoryStatusCodeLib/MemoryStatusCode.h @@ -0,0 +1,94 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + MemoryStatusCode.h + +Abstract: + + Lib to provide status code reporting via memory. + +--*/ + +#ifndef _PEI_MEMORY_STATUS_CODE_H_ +#define _PEI_MEMORY_STATUS_CODE_H_ + +// +// Publicly exported function +// +EFI_STATUS +EFIAPI +InstallMonoStatusCode ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices + ) +; +// +// Publicly exported data +// +extern BOOLEAN gRunningFromMemory; +// +// Private data +// +// +// Define the amount of heap to use before memory is allocated +// +#define PEI_STATUS_CODE_HEAP_LENGTH 512 +#define PEI_STATUS_CODE_MAX_HEAP_ENTRY (PEI_STATUS_CODE_HEAP_LENGTH / sizeof (EFI_STATUS_CODE_ENTRY)) + +// +// Define the number of 4K pages of BS memory to allocate (1MB) +// +#define PEI_STATUS_CODE_RT_PAGES (128) +#define PEI_STATUS_CODE_RT_LENGTH (PEI_STATUS_CODE_RT_PAGES * 1024 * 4) +#define PEI_STATUS_CODE_MAX_RT_ENTRY (PEI_STATUS_CODE_RT_LENGTH / sizeof (EFI_STATUS_CODE_ENTRY)) + +// +// Define a private data structure +// +#define MEMORY_STATUS_CODE_SIGNATURE EFI_SIGNATURE_32 ('M', 'S', 'C', 'S') + +typedef struct _MEMORY_STATUS_CODE_INSTANCE { + UINT32 Signature; + struct _MEMORY_STATUS_CODE_INSTANCE *This; + EFI_FFS_FILE_HEADER *FfsHeader; + EFI_PEI_PPI_DESCRIPTOR PpiDescriptor; + PEI_STATUS_CODE_MEMORY_PPI StatusCodeMemoryPpi; + EFI_PEI_NOTIFY_DESCRIPTOR NotifyDescriptor; +} MEMORY_STATUS_CODE_INSTANCE; + +#define MEMORY_STATUS_CODE_FROM_DESCRIPTOR_THIS(a) \ + PEI_CR (a, \ + MEMORY_STATUS_CODE_INSTANCE, \ + PpiDescriptor, \ + MEMORY_STATUS_CODE_SIGNATURE \ + ) +#define MEMORY_STATUS_CODE_FROM_NOTIFY_THIS(a) \ + PEI_CR (a, \ + MEMORY_STATUS_CODE_INSTANCE, \ + NotifyDescriptor, \ + MEMORY_STATUS_CODE_SIGNATURE \ + ) + +// +// Private function declarations +// +EFI_STATUS +EFIAPI +LoadImageCallback ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ) +; + +#endif diff --git a/EdkModulePkg/Library/EdkMemoryStatusCodeLib/build.xml b/EdkModulePkg/Library/EdkMemoryStatusCodeLib/build.xml new file mode 100644 index 0000000000..40db09a722 --- /dev/null +++ b/EdkModulePkg/Library/EdkMemoryStatusCodeLib/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Library/EdkNullCustomizedDecompressLib/CustomizedDecompress.c b/EdkModulePkg/Library/EdkNullCustomizedDecompressLib/CustomizedDecompress.c new file mode 100644 index 0000000000..55d9bbe216 --- /dev/null +++ b/EdkModulePkg/Library/EdkNullCustomizedDecompressLib/CustomizedDecompress.c @@ -0,0 +1,109 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + CustomizedDecompress.c + +Abstract: + + Implementation file for Customized decompression routine + +--*/ + +#include + +EFI_CUSTOMIZED_DECOMPRESS_PROTOCOL mCustomizedDecompress = { + CustomizedGetInfo, + CustomizedDecompress +}; + +EFI_CUSTOMIZED_DECOMPRESS_PROTOCOL * +EFIAPI +GetCustomizedDecompressProtocol ( + VOID + ) +{ + return &mCustomizedDecompress; +} + + + +EFI_STATUS +EFIAPI +CustomizedGetInfo ( + IN EFI_CUSTOMIZED_DECOMPRESS_PROTOCOL *This, + IN VOID *Source, + IN UINT32 SrcSize, + OUT UINT32 *DstSize, + OUT UINT32 *ScratchSize + ) +/*++ + +Routine Description: + + The implementation of Customized GetInfo(). + +Arguments: + This - The EFI customized decompress protocol + Source - The source buffer containing the compressed data. + SrcSize - The size of source buffer + DstSize - The size of destination buffer. + ScratchSize - The size of scratch buffer. + +Returns: + + EFI_SUCCESS - The size of destination buffer and the size of scratch buffer are successull retrieved. + EFI_INVALID_PARAMETER - The source data is corrupted + EFI_UNSUPPORTED - Not supported + +--*/ +{ + return EFI_UNSUPPORTED; +} + +EFI_STATUS +EFIAPI +CustomizedDecompress ( + IN EFI_CUSTOMIZED_DECOMPRESS_PROTOCOL *This, + IN VOID *Source, + IN UINT32 SrcSize, + IN OUT VOID *Destination, + IN UINT32 DstSize, + IN OUT VOID *Scratch, + IN UINT32 ScratchSize + ) +/*++ + +Routine Description: + + The implementation of Customized Decompress(). + +Arguments: + + This - The protocol instance pointer + Source - The source buffer containing the compressed data. + SrcSize - The size of source buffer + Destination - The destination buffer to store the decompressed data + DstSize - The size of destination buffer. + Scratch - The buffer used internally by the decompress routine. This buffer is needed to store intermediate data. + ScratchSize - The size of scratch buffer. + +Returns: + + EFI_SUCCESS - Decompression is successfull + EFI_INVALID_PARAMETER - The source data is corrupted + EFI_UNSUPPORTED - Not supported + +--*/ +{ + return EFI_UNSUPPORTED; +} diff --git a/EdkModulePkg/Library/EdkNullCustomizedDecompressLib/CustomizedDecompress.h b/EdkModulePkg/Library/EdkNullCustomizedDecompressLib/CustomizedDecompress.h new file mode 100644 index 0000000000..e94be43b48 --- /dev/null +++ b/EdkModulePkg/Library/EdkNullCustomizedDecompressLib/CustomizedDecompress.h @@ -0,0 +1,95 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + CustomizedDecompress.h + +Abstract: + + Header file for Customized decompression routine + +--*/ +#ifndef _CUSTOMIZED_DECOMPRESS_LIB_H_ +#define _CUSTOMIZED_DECOMPRESS_LIB_H_ + + + + +EFI_STATUS +EFIAPI +CustomizedGetInfo ( + IN EFI_CUSTOMIZED_DECOMPRESS_PROTOCOL *This, + IN VOID *Source, + IN UINT32 SrcSize, + OUT UINT32 *DstSize, + OUT UINT32 *ScratchSize + ) +/*++ + +Routine Description: + + The implementation of Customized GetInfo(). + +Arguments: + This - The EFI customized decompress protocol + Source - The source buffer containing the compressed data. + SrcSize - The size of source buffer + DstSize - The size of destination buffer. + ScratchSize - The size of scratch buffer. + +Returns: + + EFI_SUCCESS - The size of destination buffer and the size of scratch buffer are successull retrieved. + EFI_INVALID_PARAMETER - The source data is corrupted + EFI_UNSUPPORTED - Not supported + +--*/ +; + +EFI_STATUS +EFIAPI +CustomizedDecompress ( + IN EFI_CUSTOMIZED_DECOMPRESS_PROTOCOL *This, + IN VOID *Source, + IN UINT32 SrcSize, + IN OUT VOID *Destination, + IN UINT32 DstSize, + IN OUT VOID *Scratch, + IN UINT32 ScratchSize + ) +/*++ + +Routine Description: + + The implementation of Customized Decompress(). + +Arguments: + + This - The protocol instance pointer + Source - The source buffer containing the compressed data. + SrcSize - The size of source buffer + Destination - The destination buffer to store the decompressed data + DstSize - The size of destination buffer. + Scratch - The buffer used internally by the decompress routine. This buffer is needed to store intermediate data. + ScratchSize - The size of scratch buffer. + +Returns: + + EFI_SUCCESS - Decompression is successfull + EFI_INVALID_PARAMETER - The source data is corrupted + EFI_UNSUPPORTED - Not supported + +--*/ +; + + +#endif diff --git a/EdkModulePkg/Library/EdkNullCustomizedDecompressLib/EdkNullCustomizedDecompressLib.mbd b/EdkModulePkg/Library/EdkNullCustomizedDecompressLib/EdkNullCustomizedDecompressLib.mbd new file mode 100644 index 0000000000..a6a6d56a1c --- /dev/null +++ b/EdkModulePkg/Library/EdkNullCustomizedDecompressLib/EdkNullCustomizedDecompressLib.mbd @@ -0,0 +1,30 @@ + + + + + EdkNullCustomizedDecompressLib + 4a024320-0648-49c3-84d4-3d04670a1c77 + 0 + FIX ME! + Copyright (c) 2004 - 2005, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + diff --git a/EdkModulePkg/Library/EdkNullCustomizedDecompressLib/EdkNullCustomizedDecompressLib.msa b/EdkModulePkg/Library/EdkNullCustomizedDecompressLib/EdkNullCustomizedDecompressLib.msa new file mode 100644 index 0000000000..3ca559f642 --- /dev/null +++ b/EdkModulePkg/Library/EdkNullCustomizedDecompressLib/EdkNullCustomizedDecompressLib.msa @@ -0,0 +1,44 @@ + + + + + EdkNullCustomizedDecompressLib + DXE_DRIVER + LIBRARY + 4a024320-0648-49c3-84d4-3d04670a1c77 + 0 + Component description file for the PEI library. + FIX ME! + Copyright (c) 2004 - 2005, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + CustomDecompressLib + + + CustomizedDecompress.c + + + MdePkg + EdkModulePkg + + diff --git a/EdkModulePkg/Library/EdkNullCustomizedDecompressLib/build.xml b/EdkModulePkg/Library/EdkNullCustomizedDecompressLib/build.xml new file mode 100644 index 0000000000..a8ae7fe640 --- /dev/null +++ b/EdkModulePkg/Library/EdkNullCustomizedDecompressLib/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Library/EdkPeCoffLoaderLib/EdkPeCoffLoader.c b/EdkModulePkg/Library/EdkPeCoffLoaderLib/EdkPeCoffLoader.c new file mode 100644 index 0000000000..86421dbff0 --- /dev/null +++ b/EdkModulePkg/Library/EdkPeCoffLoaderLib/EdkPeCoffLoader.c @@ -0,0 +1,112 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + TianoPeCoffLoader.c + +Abstract: + + Wrap the Base PE/COFF loader with the PE COFF Protocol + + +--*/ + + + +EFI_STATUS +EFIAPI +TianoPeCoffLoaderLibGetImageInfo ( + IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This, + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + EFI_STATUS Status; + + Status = PeCoffLoaderGetImageInfo (ImageContext); + if (EFI_ERROR (Status)) { + return Status; + } + + switch (ImageContext->ImageType) { + + case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION: + ImageContext->ImageCodeMemoryType = EfiLoaderCode; + ImageContext->ImageDataMemoryType = EfiLoaderData; + break; + + case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER: + ImageContext->ImageCodeMemoryType = EfiBootServicesCode; + ImageContext->ImageDataMemoryType = EfiBootServicesData; + break; + + case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER: + case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER: + ImageContext->ImageCodeMemoryType = EfiRuntimeServicesCode; + ImageContext->ImageDataMemoryType = EfiRuntimeServicesData; + break; + + default: + ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM; + return RETURN_UNSUPPORTED; + } + + return Status; +} + +EFI_STATUS +EFIAPI +TianoPeCoffLoaderLibLoadImage ( + IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This, + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + return PeCoffLoaderLoadImage (ImageContext); +} + +EFI_STATUS +EFIAPI +TianoPeCoffLoaderLibRelocateImage ( + IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This, + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + return PeCoffLoaderRelocateImage (ImageContext); +} + + +EFI_STATUS +EFIAPI +TianoPeCoffLoaderLibUnloadimage ( + IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This, + IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + return EFI_SUCCESS; +} + + +EFI_PEI_PE_COFF_LOADER_PROTOCOL mPeiEfiPeiPeCoffLoader = { + TianoPeCoffLoaderLibGetImageInfo, + TianoPeCoffLoaderLibLoadImage, + TianoPeCoffLoaderLibRelocateImage, + TianoPeCoffLoaderLibUnloadimage +}; + +EFI_PEI_PE_COFF_LOADER_PROTOCOL * +EFIAPI +GetPeCoffLoaderProtocol ( + ) +{ + return &mPeiEfiPeiPeCoffLoader; +} + + diff --git a/EdkModulePkg/Library/EdkPeCoffLoaderLib/EdkPeCoffLoaderLib.mbd b/EdkModulePkg/Library/EdkPeCoffLoaderLib/EdkPeCoffLoaderLib.mbd new file mode 100644 index 0000000000..4ffdf99f8f --- /dev/null +++ b/EdkModulePkg/Library/EdkPeCoffLoaderLib/EdkPeCoffLoaderLib.mbd @@ -0,0 +1,30 @@ + + + + + EdkPeCoffLoaderLib + 858bbbc9-474f-4556-a361-0ae52a44ffa5 + 0 + FIX ME! + Copyright (c) 2004 - 2005, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + diff --git a/EdkModulePkg/Library/EdkPeCoffLoaderLib/EdkPeCoffLoaderLib.msa b/EdkModulePkg/Library/EdkPeCoffLoaderLib/EdkPeCoffLoaderLib.msa new file mode 100644 index 0000000000..0f855307d5 --- /dev/null +++ b/EdkModulePkg/Library/EdkPeCoffLoaderLib/EdkPeCoffLoaderLib.msa @@ -0,0 +1,45 @@ + + + + + EdkPeCoffLoaderLib + PEIM + LIBRARY + 858bbbc9-474f-4556-a361-0ae52a44ffa5 + 0 + Component description file for the PEI library. + FIX ME! + Copyright (c) 2004 - 2005, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + EdkPeCoffLoaderLib + PeCoffLib + + + EdkPeCoffLoader.c + + + MdePkg + EdkModulePkg + + diff --git a/EdkModulePkg/Library/EdkPeCoffLoaderLib/build.xml b/EdkModulePkg/Library/EdkPeCoffLoaderLib/build.xml new file mode 100644 index 0000000000..6e7a34f37b --- /dev/null +++ b/EdkModulePkg/Library/EdkPeCoffLoaderLib/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Library/EdkPeCoffLoaderX64Lib/EdkPeCoffLoaderX64.c b/EdkModulePkg/Library/EdkPeCoffLoaderX64Lib/EdkPeCoffLoaderX64.c new file mode 100644 index 0000000000..a2862576fa --- /dev/null +++ b/EdkModulePkg/Library/EdkPeCoffLoaderX64Lib/EdkPeCoffLoaderX64.c @@ -0,0 +1,940 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + EdkPeCoffLoaderX64.c + +Abstract: + + Wrap the Base PE/COFF loader with the PE COFF Protocol + + +--*/ + +#define IMAGE_64_MACHINE_TYPE_SUPPORTED(Machine) \ + ((Machine) == EFI_IMAGE_MACHINE_IA32 || \ + (Machine) == EFI_IMAGE_MACHINE_X64 || \ + (Machine) == EFI_IMAGE_MACHINE_EBC) + +STATIC +EFI_STATUS +PeCoffLoader64GetPeHeader ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, + OUT EFI_IMAGE_NT_HEADERS64 *PeHdr + ); + +STATIC +EFI_STATUS +PeCoffLoader64CheckImageType ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, + IN EFI_IMAGE_NT_HEADERS64 *PeHdr + ); + +STATIC +VOID * +PeCoffLoader64ImageAddress ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, + IN UINTN Address + ); + +EFI_STATUS +EFIAPI +PeCoffLoader64GetImageInfo ( + IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This, + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ); + +EFI_STATUS +EFIAPI +PeCoffLoader64RelocateImage ( + IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This, + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ); + +EFI_STATUS +EFIAPI +PeCoffLoader64LoadImage ( + IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This, + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ); + +EFI_STATUS +EFIAPI +PeCoffLoader64UnloadImage ( + IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This, + IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ); + +EFI_STATUS +PeCoffLoader64RelocateImageEx ( + IN UINT16 *Reloc, + IN OUT CHAR8 *Fixup, + IN OUT CHAR8 **FixupData, + IN UINT64 Adjust + ); + +EFI_PEI_PE_COFF_LOADER_PROTOCOL mPeCoffLoaderX64 = { + PeCoffLoader64GetImageInfo, + PeCoffLoader64LoadImage, + PeCoffLoader64RelocateImage, + PeCoffLoader64UnloadImage +}; + +STATIC +EFI_STATUS +PeCoffLoader64GetPeHeader ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, + OUT EFI_IMAGE_NT_HEADERS64 *PeHdr + ) +/*++ + +Routine Description: + Retrieves the PE Header from a PE/COFF image + +Arguments: + ImageContext - The context of the image being loaded + PeHdr - The buffer in which to return the PE header + +Returns: + EFI_SUCCESS if the PE Header is read, + Otherwise, the error status from reading the PE/COFF image using the ImageRead function. + +--*/ +{ + EFI_STATUS Status; + EFI_IMAGE_DOS_HEADER DosHdr; + UINTN Size; + + // + // Read the DOS image headers + // + Size = sizeof (EFI_IMAGE_DOS_HEADER); + Status = ImageContext->ImageRead ( + ImageContext->Handle, + 0, + &Size, + &DosHdr + ); + if (EFI_ERROR (Status)) { + ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ; + return Status; + } + + ImageContext->PeCoffHeaderOffset = 0; + if (DosHdr.e_magic == EFI_IMAGE_DOS_SIGNATURE) { + // + // DOS image header is present, so read the PE header after the DOS image header + // + ImageContext->PeCoffHeaderOffset = DosHdr.e_lfanew; + } + + // + // Read the PE/COFF Header + // + Size = sizeof (EFI_IMAGE_NT_HEADERS64); + Status = ImageContext->ImageRead ( + ImageContext->Handle, + ImageContext->PeCoffHeaderOffset, + &Size, + PeHdr + ); + if (EFI_ERROR (Status)) { + ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ; + return Status; + } + + return EFI_SUCCESS; +} + +static +EFI_STATUS +PeCoffLoader64CheckImageType ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, + IN EFI_IMAGE_NT_HEADERS64 *PeHdr + ) +/*++ + +Routine Description: + Checks the PE header of a PE/COFF image to determine if it supported + +Arguments: + ImageContext - The context of the image being loaded + PeHdr - The buffer in which to return the PE header + +Returns: + EFI_SUCCESS if the PE/COFF image is supported + EFI_UNSUPPORTED of the PE/COFF image is not supported. + +--*/ +{ + // + // Check the PE/COFF Header SIgnature + // + if (PeHdr->Signature != EFI_IMAGE_NT_SIGNATURE) { + ImageContext->ImageError = IMAGE_ERROR_INVALID_PE_HEADER_SIGNATURE; + return EFI_UNSUPPORTED; + } + + // + // See if the machine type is supported. We support a native machine type (IA-32/Itanium-based) + // and the machine type for the Virtual Machine. + // + ImageContext->Machine = PeHdr->FileHeader.Machine; + if (!(IMAGE_64_MACHINE_TYPE_SUPPORTED (ImageContext->Machine))) { + ImageContext->ImageError = IMAGE_ERROR_INVALID_MACHINE_TYPE; + return EFI_UNSUPPORTED; + } + + // + // See if the image type is supported. We support EFI Applications, + // EFI Boot Service Drivers, and EFI Runtime Drivers. + // + ImageContext->ImageType = PeHdr->OptionalHeader.Subsystem; + switch (ImageContext->ImageType) { + + case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION: + ImageContext->ImageCodeMemoryType = EfiLoaderCode; + ImageContext->ImageDataMemoryType = EfiLoaderData; + break; + + case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER: + ImageContext->ImageCodeMemoryType = EfiBootServicesCode; + ImageContext->ImageDataMemoryType = EfiBootServicesData; + break; + + case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER: + case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER: + ImageContext->ImageCodeMemoryType = EfiRuntimeServicesCode; + ImageContext->ImageDataMemoryType = EfiRuntimeServicesData; + break; + + default: + ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM; + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PeCoffLoader64GetImageInfo ( + IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This, + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +/*++ + +Routine Description: + Retrieves information on a PE/COFF image + +Arguments: + ImageContext - The context of the image being loaded + PeHdr - The buffer in which to return the PE header + +Returns: + EFI_SUCCESS if the information on the PE/COFF image was collected. + EFI_UNSUPPORTED of the PE/COFF image is not supported. + Otherwise, the error status from reading the PE/COFF image using the + ImageContext->ImageRead() function + +--*/ +{ + EFI_STATUS Status; + EFI_IMAGE_NT_HEADERS64 PeHdr; + EFI_IMAGE_DATA_DIRECTORY *DebugDirectoryEntry; + UINTN Size; + UINTN Index; + UINTN DebugDirectoryEntryRva; + UINTN DebugDirectoryEntryFileOffset; + UINTN SectionHeaderOffset; + EFI_IMAGE_SECTION_HEADER SectionHeader; + EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry; + + if (NULL == ImageContext) { + return EFI_INVALID_PARAMETER; + } + + // + // Assume success + // + ImageContext->ImageError = IMAGE_ERROR_SUCCESS; + + Status = PeCoffLoader64GetPeHeader (ImageContext, &PeHdr); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Verify machine type + // + Status = PeCoffLoader64CheckImageType (ImageContext, &PeHdr); + if (EFI_ERROR(Status)) { + return Status; + } + + // + // Retrieve the base address of the image + // + ImageContext->ImageAddress = PeHdr.OptionalHeader.ImageBase; + + // + // Initialize the alternate destination address to 0 indicating that it + // should not be used. + // + ImageContext->DestinationAddress = 0; + + // + // Initialize the codeview pointer. + // + ImageContext->CodeView = NULL; + ImageContext->PdbPointer = NULL; + + // + // 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 (PeHdr.FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) { + ImageContext->RelocationsStripped = TRUE; + } else { + ImageContext->RelocationsStripped = FALSE; + } + + ImageContext->ImageSize = (UINT64)PeHdr.OptionalHeader.SizeOfImage; + ImageContext->SectionAlignment = PeHdr.OptionalHeader.SectionAlignment; + ImageContext->SizeOfHeaders = PeHdr.OptionalHeader.SizeOfHeaders; + + // + // Modify ImageSize to contain .PDB file name if required and initialize + // PdbRVA field... + // + + if (PeHdr.OptionalHeader.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) { + DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) + &(PeHdr.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]); + + DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress; + + // + // Determine the file offset of the debug directory... This means we walk + // the sections to find which section contains the RVA of the debug + // directory + // + + DebugDirectoryEntryFileOffset = 0; + + SectionHeaderOffset = (UINTN) ( + ImageContext->PeCoffHeaderOffset + + sizeof (UINT32) + + sizeof (EFI_IMAGE_FILE_HEADER) + + PeHdr.FileHeader.SizeOfOptionalHeader + ); + + for (Index = 0; Index < PeHdr.FileHeader.NumberOfSections; Index += 1) { + // + // Read section header from file + // + Size = sizeof (EFI_IMAGE_SECTION_HEADER); + Status = ImageContext->ImageRead ( + ImageContext->Handle, + SectionHeaderOffset, + &Size, + &SectionHeader + ); + if (EFI_ERROR (Status)) { + ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ; + return Status; + } + + if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress && + DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) { + DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData; + break; + } + + SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER); + } + + if (DebugDirectoryEntryFileOffset != 0) { + for (Index = 0; Index < DebugDirectoryEntry->Size; Index++) { + // + // Read next debug directory entry + // + Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY); + Status = ImageContext->ImageRead ( + ImageContext->Handle, + DebugDirectoryEntryFileOffset, + &Size, + &DebugEntry + ); + if (EFI_ERROR (Status)) { + ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ; + return Status; + } + if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) { + ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index * sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)); + if (DebugEntry.RVA == 0 && DebugEntry.FileOffset != 0) { + ImageContext->ImageSize += DebugEntry.SizeOfData; + } + return EFI_SUCCESS; + } + } + } + } + return EFI_SUCCESS; +} + +static +VOID * +PeCoffLoader64ImageAddress ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, + IN UINTN Address + ) +/*++ + +Routine Description: + Converts an image address to the loaded address + +Arguments: + ImageContext - The context of the image being loaded + Address - The address to be converted to the loaded address + +Returns: + NULL if the address can not be converted, otherwise, the converted address + +--*/ +{ + if (Address >= ImageContext->ImageSize) { + ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS; + return NULL; + } + return (CHAR8 *)((UINTN)ImageContext->ImageAddress + Address); +} + +EFI_STATUS +EFIAPI +PeCoffLoader64RelocateImage ( + IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This, + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +/*++ + +Routine Description: + Relocates a PE/COFF image in memory + +Arguments: + ImageContext - Contains information on the loaded image to relocate + +Returns: + EFI_SUCCESS if the PE/COFF image was relocated + EFI_LOAD_ERROR if the image is not a valid PE/COFF image + +--*/ +{ + EFI_STATUS Status; + EFI_IMAGE_NT_HEADERS64 *PeHdr; + EFI_IMAGE_DATA_DIRECTORY *RelocDir; + IN UINT64 Adjust; + EFI_IMAGE_BASE_RELOCATION *RelocBase; + EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd; + UINT16 *Reloc; + UINT16 *RelocEnd; + CHAR8 *Fixup; + CHAR8 *FixupBase; + UINT16 *F16; + UINT32 *F32; + CHAR8 *FixupData; + EFI_PHYSICAL_ADDRESS BaseAddress; + + + // + // Assume success + // + ImageContext->ImageError = IMAGE_ERROR_SUCCESS; + + // + // If there are no relocation entries, then we are done + // + if (ImageContext->RelocationsStripped) { + return EFI_SUCCESS; + } + + // + // If the destination address is not 0, use that rather than the + // image address as the relocation target. + // + if (ImageContext->DestinationAddress) { + BaseAddress = ImageContext->DestinationAddress; + } else { + BaseAddress = ImageContext->ImageAddress; + } + PeHdr = (EFI_IMAGE_NT_HEADERS64 *)((UINTN)ImageContext->ImageAddress + + ImageContext->PeCoffHeaderOffset); + Adjust = (UINT64) BaseAddress - PeHdr->OptionalHeader.ImageBase; + + PeHdr->OptionalHeader.ImageBase = (UINTN) BaseAddress; + + // + // Find the relocation block + // + // Per the PE/COFF spec, you can't assume that a given data directory + // is present in the image. You have to check the NumberOfRvaAndSizes in + // the optional header to verify a desired directory entry is there. + // + if (PeHdr->OptionalHeader.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) { + RelocDir = &PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]; + RelocBase = PeCoffLoader64ImageAddress (ImageContext, RelocDir->VirtualAddress); + RelocBaseEnd = PeCoffLoader64ImageAddress ( + ImageContext, + RelocDir->VirtualAddress + RelocDir->Size - 1 + ); +} else { + // + // Set base and end to bypass processing below. + // + RelocBase = RelocBaseEnd = 0; + } + // + // Run the relocation information and apply the fixups + // + FixupData = ImageContext->FixupData; + while (RelocBase < RelocBaseEnd) { + + Reloc = (UINT16 *) ((CHAR8 *) RelocBase + sizeof(EFI_IMAGE_BASE_RELOCATION)); + RelocEnd = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock); + FixupBase = PeCoffLoader64ImageAddress (ImageContext, RelocBase->VirtualAddress); + if ((CHAR8 *) RelocEnd < (CHAR8 *)((UINTN)ImageContext->ImageAddress) || + (CHAR8 *) RelocEnd > (CHAR8 *)((UINTN)ImageContext->ImageAddress + + (UINTN)ImageContext->ImageSize)) { + ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION; + return EFI_LOAD_ERROR; + } + + // + // Run this relocation record + // + while (Reloc < RelocEnd) { + + Fixup = FixupBase + (*Reloc & 0xFFF); + switch ((*Reloc) >> 12) { + case EFI_IMAGE_REL_BASED_ABSOLUTE: + break; + case EFI_IMAGE_REL_BASED_HIGH: + F16 = (UINT16 *) Fixup; + *F16 = (UINT16)((*F16 << 16) + (UINT16) Adjust); + if (FixupData != NULL) { + *(UINT16 *) FixupData = *F16; + FixupData = FixupData + sizeof(UINT16); + } + break; + case EFI_IMAGE_REL_BASED_LOW: + F16 = (UINT16 *) Fixup; + *F16 = (UINT16)(*F16 + (UINT16) Adjust); + if (FixupData != NULL) { + *(UINT16 *) FixupData = *F16; + FixupData = FixupData + sizeof(UINT16); + } + break; + case EFI_IMAGE_REL_BASED_HIGHLOW: + F32 = (UINT32 *) Fixup; + *F32 = *F32 + (UINT32) Adjust; + if (FixupData != NULL) { + FixupData = ALIGN_POINTER(FixupData, sizeof(UINT32)); + *(UINT32 *) FixupData = *F32; + FixupData = FixupData + sizeof(UINT32); + } + break; + case EFI_IMAGE_REL_BASED_HIGHADJ: + // Return the same EFI_UNSUPPORTED return code as + // PeCoffLoader64RelocateImageEx() returns if it does not recognize + // the relocation type. + // + ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION; + return EFI_UNSUPPORTED; + default: + Status = PeCoffLoader64RelocateImageEx (Reloc, Fixup, &FixupData, Adjust); + if (EFI_ERROR (Status)) { + ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION; + return Status; + } + } + + // + // Next relocation record + // + Reloc += 1; + } + + // + // Next reloc block + // + RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd; + } + + return EFI_SUCCESS; +} + + +EFI_STATUS +PeCoffLoader64RelocateImageEx ( + IN UINT16 *Reloc, + IN OUT CHAR8 *Fixup, + IN OUT CHAR8 **FixupData, + IN UINT64 Adjust + ) +/*++ + +Routine Description: + Performs an IA-32 specific relocation fixup + +Arguments: + Reloc - Pointer to the relocation record + Fixup - Pointer to the address to fix up + FixupData - Pointer to a buffer to log the fixups + Adjust - The offset to adjust the fixup + +Returns: + None + +--*/ +{ + UINT64 *F64; + + switch ((*Reloc) >> 12) { + + case EFI_IMAGE_REL_BASED_DIR64: + F64 = (UINT64 *) Fixup; + *F64 = *F64 + (UINT64) Adjust; + if (*FixupData != NULL) { + *FixupData = ALIGN_POINTER(*FixupData, sizeof(UINT64)); + *(UINT64 *)(*FixupData) = *F64; + *FixupData = *FixupData + sizeof(UINT64); + } + break; + + default: + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + + + +EFI_STATUS +EFIAPI +PeCoffLoader64LoadImage ( + IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This, + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +/*++ + +Routine Description: + Loads a PE/COFF image into memory + +Arguments: + ImageContext - Contains information on image to load into memory + +Returns: + EFI_SUCCESS if the PE/COFF image was loaded + EFI_BUFFER_TOO_SMALL if the caller did not provide a large enough buffer + EFI_LOAD_ERROR if the image is a runtime driver with no relocations + EFI_INVALID_PARAMETER if the image address is invalid + +--*/ +{ + EFI_STATUS Status; + EFI_IMAGE_NT_HEADERS64 *PeHdr; + PE_COFF_LOADER_IMAGE_CONTEXT CheckContext; + EFI_IMAGE_SECTION_HEADER *FirstSection; + EFI_IMAGE_SECTION_HEADER *Section; + UINTN Index; + CHAR8 *Base; + CHAR8 *End; + CHAR8 *MaxEnd; + EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry; + EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry; + UINTN Size; + UINT32 TempDebugEntryRva; + + // + // Assume success + // + ImageContext->ImageError = IMAGE_ERROR_SUCCESS; + + // + // Copy the provided context info into our local version, get what we + // can from the original image, and then use that to make sure everything + // is legit. + // + CopyMem ( + &CheckContext, + ImageContext, + sizeof (PE_COFF_LOADER_IMAGE_CONTEXT) + ); + + Status = PeCoffLoader64GetImageInfo ( + This, + &CheckContext + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Make sure there is enough allocated space for the image being loaded + // + if (ImageContext->ImageSize < CheckContext.ImageSize) { + ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_SIZE; + return EFI_BUFFER_TOO_SMALL; + } + + // + // If there's no relocations, then make sure it's not a runtime driver, + // and that it's being loaded at the linked address. + // + if (CheckContext.RelocationsStripped == TRUE) { + // + // If the image does not contain relocations and it is a runtime driver + // then return an error. + // + if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) { + ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM; + return EFI_LOAD_ERROR; + } + // + // If the image does not contain relocations, and the requested load address + // is not the linked address, then return an error. + // + if (CheckContext.ImageAddress != ImageContext->ImageAddress) { + ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS; + return EFI_INVALID_PARAMETER; + } + } + + // + // Make sure the allocated space has the proper section alignment + // + if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) { + ImageContext->ImageError = IMAGE_ERROR_INVALID_SECTION_ALIGNMENT; + return EFI_INVALID_PARAMETER; + } + + // + // Read the entire PE/COFF header into memory + // + Status = ImageContext->ImageRead ( + ImageContext->Handle, + 0, + &ImageContext->SizeOfHeaders, + (VOID *)(UINTN)ImageContext->ImageAddress + ); + if (EFI_ERROR(Status)) { + ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ; + return EFI_LOAD_ERROR; + } + + PeHdr = (EFI_IMAGE_NT_HEADERS64 *) + ((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset); + + // + // Load each section of the image + // + FirstSection = (EFI_IMAGE_SECTION_HEADER *) ( + (UINTN)ImageContext->ImageAddress + + ImageContext->PeCoffHeaderOffset + + sizeof(UINT32) + + sizeof(EFI_IMAGE_FILE_HEADER) + + PeHdr->FileHeader.SizeOfOptionalHeader + ); + + Section = FirstSection; + for ( Index=0, MaxEnd = NULL; + Index < PeHdr->FileHeader.NumberOfSections; + Index += 1) { + + // + // Compute sections address + // + Base = PeCoffLoader64ImageAddress (ImageContext, Section->VirtualAddress); + End = PeCoffLoader64ImageAddress ( + ImageContext, + Section->VirtualAddress + Section->Misc.VirtualSize - 1); + if (End > MaxEnd) { + MaxEnd = End; + } + // + // If the base start or end address resolved to 0, then fail. + // + if (!Base || !End) { + ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED; + return EFI_LOAD_ERROR; + } + + // + // Read the section, we can resume the length of PE image can't + // exceed the max 32bit integer + // + Size = (UINTN) Section->Misc.VirtualSize; + if ((Size == 0) || (Size > Section->SizeOfRawData)) { + Size = (UINTN) Section->SizeOfRawData; + } + if (Section->SizeOfRawData) { + Status = ImageContext->ImageRead ( + ImageContext->Handle, + Section->PointerToRawData, + &Size, + Base); + if (EFI_ERROR(Status)) { + ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ; + return Status; + } + } + + // + // If raw size is less then virt size, zero fill the remaining + // + + if (Size < Section->Misc.VirtualSize) { + ZeroMem (Base + Size, Section->Misc.VirtualSize - (UINTN)Size); + } + + // + // Next Section + // + Section += 1; + } + + // + // Get image's entry point + // + ImageContext->EntryPoint = + (EFI_PHYSICAL_ADDRESS) (UINTN) PeCoffLoader64ImageAddress ( + ImageContext, + PeHdr->OptionalHeader.AddressOfEntryPoint + ); + + // + // Determine the size of the fixup data + // + // Per the PE/COFF spec, you can't assume that a given data directory + // is present in the image. You have to check the NumberOfRvaAndSizes in + // the optional header to verify a desired directory entry is there. + // + if (PeHdr->OptionalHeader.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) { + DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) + &PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]; + ImageContext->FixupDataSize = + DirectoryEntry->Size / sizeof(UINT16) * sizeof(UINTN); + } else { + ImageContext->FixupDataSize = 0; + } + // + // Consumer must allocate a buffer for the relocation fixup log. + // Only used for runtime drivers. + // + ImageContext->FixupData = NULL; + + // + // Load the Codeview info if present + // + if (ImageContext->DebugDirectoryEntryRva != 0) { + DebugEntry = PeCoffLoader64ImageAddress ( + ImageContext, + ImageContext->DebugDirectoryEntryRva + ); + if (DebugEntry != NULL) { + TempDebugEntryRva = DebugEntry->RVA; + if (DebugEntry->RVA == 0 && DebugEntry->FileOffset != 0) { + Section--; + if ((UINTN) Section->SizeOfRawData < Section->Misc.VirtualSize) { + TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize; + } else { + TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData; + } + } + if (TempDebugEntryRva != 0) { + ImageContext->CodeView = PeCoffLoader64ImageAddress (ImageContext, TempDebugEntryRva); + if (ImageContext->CodeView == NULL) { + ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ; + return EFI_LOAD_ERROR; + } + + if (DebugEntry->RVA == 0) { + Size = (UINTN) DebugEntry->SizeOfData; + Status = ImageContext->ImageRead ( + ImageContext->Handle, + DebugEntry->FileOffset, + &Size, + ImageContext->CodeView + ); + if (EFI_ERROR(Status)) { + ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ; + return EFI_LOAD_ERROR; + } + DebugEntry->RVA = TempDebugEntryRva; + } + + switch (* (UINT32 *) ImageContext->CodeView) { + case CODEVIEW_SIGNATURE_NB10: + ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY); + break; + case CODEVIEW_SIGNATURE_RSDS: + ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY); + break; + default: + break; + } + } + } + } + + return Status; +} + +EFI_STATUS +EFIAPI +PeCoffLoader64UnloadImage ( + IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This, + IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +/*++ + +Routine Description: + Unload of images is not supported + +Arguments: + ImageContext - The image to unload + +Returns: + EFI_SUCCESS + +--*/ +{ + return EFI_SUCCESS; +} + +EFI_PEI_PE_COFF_LOADER_PROTOCOL * +EFIAPI +GetPeCoffLoaderX64Protocol ( + ) +{ + return &mPeCoffLoaderX64; +} + + diff --git a/EdkModulePkg/Library/EdkPeCoffLoaderX64Lib/EdkPeCoffLoaderX64Lib.mbd b/EdkModulePkg/Library/EdkPeCoffLoaderX64Lib/EdkPeCoffLoaderX64Lib.mbd new file mode 100644 index 0000000000..8b6f365014 --- /dev/null +++ b/EdkModulePkg/Library/EdkPeCoffLoaderX64Lib/EdkPeCoffLoaderX64Lib.mbd @@ -0,0 +1,30 @@ + + + + + EdkPeCoffLoaderX64Lib + 6aac37f2-7b46-4ef3-8645-c24800a3d410 + EDK_RELEASE_VERSION 0x00020000 + FIX ME! + Copyright (c) 2004 - 2005, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-04-03 23:59 + 2006-04-05 21:30 + + diff --git a/EdkModulePkg/Library/EdkPeCoffLoaderX64Lib/EdkPeCoffLoaderX64Lib.msa b/EdkModulePkg/Library/EdkPeCoffLoaderX64Lib/EdkPeCoffLoaderX64Lib.msa new file mode 100644 index 0000000000..964ae551c9 --- /dev/null +++ b/EdkModulePkg/Library/EdkPeCoffLoaderX64Lib/EdkPeCoffLoaderX64Lib.msa @@ -0,0 +1,46 @@ + + + + + EdkPeCoffLoaderX64Lib + PEIM + LIBRARY + 6aac37f2-7b46-4ef3-8645-c24800a3d410 + EDK_RELEASE_VERSION 0x00020000 + Component description file for the PEI library. + FIX ME! + Copyright (c) 2004 - 2005, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + EFI_SPECIFICATION_VERSION 0x00000000 + 2006-04-03 23:59 + 2006-04-05 21:30 + + + EdkPeCoffLoaderX64Lib + BaseMemoryLib + PeCoffLib + + + EdkPeCoffLoaderX64.c + + + MdePkg + EdkModulePkg + + diff --git a/EdkModulePkg/Library/EdkPeCoffLoaderX64Lib/build.xml b/EdkModulePkg/Library/EdkPeCoffLoaderX64Lib/build.xml new file mode 100644 index 0000000000..c72e03e73e --- /dev/null +++ b/EdkModulePkg/Library/EdkPeCoffLoaderX64Lib/build.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Library/EdkPeiPerformanceLib/EdkPeiPerformanceLib.mbd b/EdkModulePkg/Library/EdkPeiPerformanceLib/EdkPeiPerformanceLib.mbd new file mode 100644 index 0000000000..103f7c4466 --- /dev/null +++ b/EdkModulePkg/Library/EdkPeiPerformanceLib/EdkPeiPerformanceLib.mbd @@ -0,0 +1,29 @@ + + + + + EdkPeiPerformanceLib + F72DE735-B24F-4ef6-897F-70A85D01A047 + EDK_RELEASE_VERSION 0x00020000 + FIX ME! + Copyright (c) 2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-04-04 11:12 + + diff --git a/EdkModulePkg/Library/EdkPeiPerformanceLib/EdkPeiPerformanceLib.msa b/EdkModulePkg/Library/EdkPeiPerformanceLib/EdkPeiPerformanceLib.msa new file mode 100644 index 0000000000..9c2eda7216 --- /dev/null +++ b/EdkModulePkg/Library/EdkPeiPerformanceLib/EdkPeiPerformanceLib.msa @@ -0,0 +1,61 @@ + + + + + EdkPeiPerformanceLib + PEIM + LIBRARY + F72DE735-B24F-4ef6-897F-70A85D01A047 + EDK_RELEASE_VERSION 0x00020000 + Memory-only library functions with no library constructor/destructor + FIX ME! + Copyright (c) 2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + EFI_SPECIFICATION_VERSION 0x00000000 + 2006-04-04 11:12 + + + PerformanceLib + DebugLib + HobLib + BaseLib + TimerLib + PcdLib + BaseMemoryLib + + + PeiPerformanceLib.c + + + MdePkg + EdkModulePkg + + + + PeiPerformanceHob + + + + + PcdPerformanceLibraryPropertyMask + 0x00000001 + UINT8 + + + diff --git a/EdkModulePkg/Library/EdkPeiPerformanceLib/PeiPerformanceLib.c b/EdkModulePkg/Library/EdkPeiPerformanceLib/PeiPerformanceLib.c new file mode 100644 index 0000000000..89e2dd3c94 --- /dev/null +++ b/EdkModulePkg/Library/EdkPeiPerformanceLib/PeiPerformanceLib.c @@ -0,0 +1,315 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PeiPerformanceLib.c + +Abstract: + + Performance Library + +--*/ + +/** + Gets PEI the GUID HOB for PEI performance. + + This internal function searches for the GUID HOB for PEI performance. + If that GUID HOB is not found, it will build a new one. + It returns the data area of that GUID HOB to record performance log. + + @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. + + @retval The index of log entry in the array. + +**/ +PEI_PERFORMANCE_LOG_HEADER * +InternalGetPerformanceHobLog ( + VOID + ) +{ + EFI_HOB_GUID_TYPE *GuidHob; + PEI_PERFORMANCE_LOG_HEADER *PeiPerformanceLog; + UINTN PeiPerformanceLogSize; + + GuidHob = GetFirstGuidHob (&gPeiPerformanceHobGuid); + + if (GuidHob != NULL) { + // + // PEI Performance HOB was found, then return the existing one. + // + PeiPerformanceLog = GET_GUID_HOB_DATA (GuidHob); + } else { + // + // PEI Performance HOB was not found, then build one. + // + PeiPerformanceLogSize = sizeof (PEI_PERFORMANCE_LOG_HEADER) + + sizeof (PEI_PERFORMANCE_LOG_ENTRY) * MAX_PEI_PERFORMANCE_LOG_ENTRIES; + PeiPerformanceLog = BuildGuidHob (&gPeiPerformanceHobGuid, PeiPerformanceLogSize); + PeiPerformanceLog = ZeroMem (PeiPerformanceLog, PeiPerformanceLogSize); + } + + return PeiPerformanceLog; +} + +/** + Searches in the log array with keyword Handle, Token and Module. + + This internal function searches for the log entry in the log array. + If there is an entry that exactly matches the given key word triple + and its end time stamp is zero, then the index of that log entry is returned; + otherwise, the the number of log entries in the array is returned. + + @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. + + @retval The index of log entry in the array. + +**/ +UINT32 +InternalSearchForLogEntry ( + IN PEI_PERFORMANCE_LOG_HEADER *PeiPerformanceLog, + IN CONST VOID *Handle, OPTIONAL + IN CONST CHAR8 *Token, OPTIONAL + IN CONST CHAR8 *Module OPTIONAL + ) +{ + UINT32 Index; + UINT32 NumberOfEntries; + PEI_PERFORMANCE_LOG_ENTRY *LogEntryArray; + + + if (Token == NULL) { + Token = ""; + } + if (Module == NULL) { + Module = ""; + } + NumberOfEntries = PeiPerformanceLog->NumberOfEntries; + LogEntryArray = (PEI_PERFORMANCE_LOG_ENTRY *) (PeiPerformanceLog + 1); + + for (Index = 0; Index < NumberOfEntries; Index++) { + if ((LogEntryArray[Index].Handle == (EFI_PHYSICAL_ADDRESS) (UINTN) Handle) && + AsciiStrnCmp (LogEntryArray[Index].Token, Token, PEI_PERFORMANCE_STRING_LENGTH) == 0 && + AsciiStrnCmp (LogEntryArray[Index].Module, Module, PEI_PERFORMANCE_STRING_LENGTH) == 0 && + LogEntryArray[Index].EndTimeStamp == 0 + ) { + break; + } + } + return Index; +} + +/** + 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 + ) +{ + PEI_PERFORMANCE_LOG_HEADER *PeiPerformanceLog; + PEI_PERFORMANCE_LOG_ENTRY *LogEntryArray; + UINT32 Index; + + PeiPerformanceLog = InternalGetPerformanceHobLog (); + + if (PeiPerformanceLog->NumberOfEntries >= MAX_PEI_PERFORMANCE_LOG_ENTRIES) { + return RETURN_OUT_OF_RESOURCES; + } + Index = PeiPerformanceLog->NumberOfEntries++; + LogEntryArray = (PEI_PERFORMANCE_LOG_ENTRY *) (PeiPerformanceLog + 1); + LogEntryArray[Index].Handle = (EFI_PHYSICAL_ADDRESS) (UINTN) Handle; + + if (Token != NULL) { + AsciiStrnCpy (LogEntryArray[Index].Token, Token, PEI_PERFORMANCE_STRING_LENGTH); + } + if (Module != NULL) { + AsciiStrnCpy (LogEntryArray[Index].Module, Module, PEI_PERFORMANCE_STRING_LENGTH); + } + + if (TimeStamp == 0) { + TimeStamp = GetPerformanceCounter (); + } + LogEntryArray[Index].StartTimeStamp = TimeStamp; + + return RETURN_SUCCESS; +} + +/** + 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. + If this function is called multiple times for the same record, then the end time is overwritten. + + @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 + ) +{ + PEI_PERFORMANCE_LOG_HEADER *PeiPerformanceLog; + PEI_PERFORMANCE_LOG_ENTRY *LogEntryArray; + UINT32 Index; + + if (TimeStamp == 0) { + TimeStamp = GetPerformanceCounter (); + } + + PeiPerformanceLog = InternalGetPerformanceHobLog (); + Index = InternalSearchForLogEntry (PeiPerformanceLog, Handle, Token, Module); + if (Index >= PeiPerformanceLog->NumberOfEntries) { + return RETURN_NOT_FOUND; + } + LogEntryArray = (PEI_PERFORMANCE_LOG_ENTRY *) (PeiPerformanceLog + 1); + LogEntryArray[Index].EndTimeStamp = TimeStamp; + + return RETURN_SUCCESS; +} + +/** + Retrieves a previously logged 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 then the start of the measurement is returned in StartTimeStamp, + and the end of the measurement is returned in EndTimeStamp. + + @param LogEntryKey The key for the previous performance measurement log entry. + If 0, then the first performance measurement log entry is retrieved. + @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 The 64-bit time stamp that was recorded when the measurement was started. + @param EndTimeStamp The 64-bit time stamp that was recorded when the measurement was ended. + + @return The key for the current performance log entry. + +**/ +UINTN +EFIAPI +GetPerformanceMeasurement ( + UINTN LogEntryKey, + OUT CONST VOID **Handle, + OUT CONST CHAR8 **Token, + OUT CONST CHAR8 **Module, + OUT UINT64 *StartTimeStamp, + OUT UINT64 *EndTimeStamp + ) +{ + PEI_PERFORMANCE_LOG_HEADER *PeiPerformanceLog; + PEI_PERFORMANCE_LOG_ENTRY *CurrentLogEntry; + PEI_PERFORMANCE_LOG_ENTRY *LogEntryArray; + UINTN NumberOfEntries; + + ASSERT (Handle != NULL); + ASSERT (Token != NULL); + ASSERT (Module != NULL); + ASSERT (StartTimeStamp != NULL); + ASSERT (EndTimeStamp != NULL); + + PeiPerformanceLog = InternalGetPerformanceHobLog (); + + NumberOfEntries = (UINTN) (PeiPerformanceLog->NumberOfEntries); + LogEntryArray = (PEI_PERFORMANCE_LOG_ENTRY *) (PeiPerformanceLog + 1); + // + // Make sure that LogEntryKey is a valid log entry key. + // + ASSERT (LogEntryKey <= NumberOfEntries); + + if (LogEntryKey == NumberOfEntries) { + return 0; + } + + CurrentLogEntry = &(LogEntryArray[LogEntryKey++]); + + *Handle = (VOID *) (UINTN) (CurrentLogEntry->Handle); + *Token = CurrentLogEntry->Token; + *Module = CurrentLogEntry->Module; + *StartTimeStamp = CurrentLogEntry->StartTimeStamp; + *EndTimeStamp = CurrentLogEntry->EndTimeStamp; + + return LogEntryKey; +} + +/** + 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 ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0); +} diff --git a/EdkModulePkg/Library/EdkPeiPerformanceLib/build.xml b/EdkModulePkg/Library/EdkPeiPerformanceLib/build.xml new file mode 100644 index 0000000000..8b476daa7e --- /dev/null +++ b/EdkModulePkg/Library/EdkPeiPerformanceLib/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/BsDataHubStatusCode/BsDataHubStatusCode.c b/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/BsDataHubStatusCode/BsDataHubStatusCode.c new file mode 100644 index 0000000000..d72aae11a3 --- /dev/null +++ b/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/BsDataHubStatusCode/BsDataHubStatusCode.c @@ -0,0 +1,397 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + BsDataHubStatusCode.c + +Abstract: + + This implements a status code listener that logs status codes into the data + hub. This is only active during non-runtime DXE. + +--*/ +#include "BsDataHubStatusCode.h" + +// +// Globals only work at BootService Time. NOT at Runtime! +// +static EFI_DATA_HUB_PROTOCOL *mDataHub; +static LIST_ENTRY mRecordBuffer; +static INTN mRecordNum; +static EFI_EVENT mLogDataHubEvent; +static EFI_LOCK mStatusCodeReportLock; +static BOOLEAN mEventHandlerActive = FALSE; + +STATUS_CODE_RECORD_LIST * +GetRecordBuffer ( + VOID + ) +/*++ + +Routine Description: + + Returned buffer of length BYTES_PER_RECORD + +Arguments: + + None + +Returns: + + Entry in mRecordBuffer or NULL if non available + +--*/ +{ + STATUS_CODE_RECORD_LIST *Buffer; + + gBS->AllocatePool (EfiBootServicesData, sizeof (STATUS_CODE_RECORD_LIST), (VOID **) &Buffer); + if (Buffer == NULL) { + return NULL; + } + + ZeroMem (Buffer, sizeof (STATUS_CODE_RECORD_LIST)); + Buffer->Signature = BS_DATA_HUB_STATUS_CODE_SIGNATURE; + + return Buffer; +} + +DATA_HUB_STATUS_CODE_DATA_RECORD * +AquireEmptyRecordBuffer ( + VOID + ) +/*++ + +Routine Description: + + Allocate a mRecordBuffer entry in the form of a pointer. + +Arguments: + + None + +Returns: + + Pointer to new buffer. NULL if none exist. + +--*/ +{ + STATUS_CODE_RECORD_LIST *DataBuffer; + + if (mRecordNum < MAX_RECORD_NUM) { + DataBuffer = GetRecordBuffer (); + if (DataBuffer != NULL) { + EfiAcquireLock (&mStatusCodeReportLock); + InsertTailList (&mRecordBuffer, &DataBuffer->Link); + mRecordNum++; + EfiReleaseLock (&mStatusCodeReportLock); + return (DATA_HUB_STATUS_CODE_DATA_RECORD *) DataBuffer->RecordBuffer; + } + } + + return NULL; +} + +EFI_STATUS +ReleaseRecordBuffer ( + IN STATUS_CODE_RECORD_LIST *RecordBuffer + ) +/*++ + +Routine Description: + + Release a mRecordBuffer entry allocated by AquireEmptyRecordBuffer (). + +Arguments: + + RecordBuffer - Data to free + +Returns: + + EFI_SUCCESS - If DataRecord is valid + EFI_UNSUPPORTED - The record list has empty + +--*/ +{ + ASSERT (RecordBuffer != NULL); + if (mRecordNum <= 0) { + return EFI_UNSUPPORTED; + } + + EfiAcquireLock (&mStatusCodeReportLock); + RemoveEntryList (&RecordBuffer->Link); + mRecordNum--; + EfiReleaseLock (&mStatusCodeReportLock); + gBS->FreePool (RecordBuffer); + return EFI_SUCCESS; +} + +EFI_STATUS +BsDataHubReportStatusCode ( + 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 + ) +/*++ + +Routine Description: + + Boot service report status code listener. This function logs the status code + into the data hub. + +Arguments: + + Same as ReportStatusCode (See Tiano Runtime Specification) + +Returns: + + None + +--*/ +{ + DATA_HUB_STATUS_CODE_DATA_RECORD *DataHub; + UINT32 ErrorLevel; + VA_LIST Marker; + CHAR8 *Format; + UINTN Index; + CHAR16 FormatBuffer[BYTES_PER_RECORD]; + + if (EfiAtRuntime ()) { + // + // For now all we do is post code at runtime + // + return EFI_SUCCESS; + } + // + // If we had an error while in our event handler, then do nothing so + // that we don't get in an endless loop. + // + if (mEventHandlerActive) { + return EFI_SUCCESS; + } + + DataHub = (DATA_HUB_STATUS_CODE_DATA_RECORD *) AquireEmptyRecordBuffer (); + if (DataHub == NULL) { + // + // There are no empty record buffer in private buffers + // + return EFI_OUT_OF_RESOURCES; + } + // + // Construct Data Hub Extended Data + // + DataHub->CodeType = CodeType; + DataHub->Value = Value; + DataHub->Instance = Instance; + + if (CallerId != NULL) { + CopyMem (&DataHub->CallerId, CallerId, sizeof (EFI_GUID)); + } else { + ZeroMem (&DataHub->CallerId, sizeof (EFI_GUID)); + } + + if (Data == NULL) { + ZeroMem (&DataHub->Data, sizeof (EFI_STATUS_CODE_DATA)); + } else { + // + // Copy generic Header + // + CopyMem (&DataHub->Data, Data, sizeof (EFI_STATUS_CODE_DATA)); + + if (ReportStatusCodeExtractDebugInfo (Data, &ErrorLevel, &Marker, &Format)) { + // + // Convert Ascii Format string to Unicode. + // + for (Index = 0; Format[Index] != '\0' && Index < (BYTES_PER_RECORD - 1); Index += 1) { + FormatBuffer[Index] = (CHAR16) Format[Index]; + } + + FormatBuffer[Index] = L'\0'; + + // + // Put processed string into the buffer + // + Index = UnicodeVSPrint ( + (CHAR16 *) (DataHub + 1), + BYTES_PER_RECORD - (sizeof (DATA_HUB_STATUS_CODE_DATA_RECORD)), + FormatBuffer, + Marker + ); + + // + // DATA_HUB_STATUS_CODE_DATA_RECORD followed by VSPrint String Buffer + // + DataHub->Data.Size = (UINT16) (Index * sizeof (CHAR16)); + + } else { + // + // Default behavior is to copy optional data + // + if (Data->Size > (BYTES_PER_RECORD - sizeof (DATA_HUB_STATUS_CODE_DATA_RECORD))) { + DataHub->Data.Size = (UINT16) (BYTES_PER_RECORD - sizeof (DATA_HUB_STATUS_CODE_DATA_RECORD)); + } + + CopyMem (DataHub + 1, Data + 1, DataHub->Data.Size); + } + } + + gBS->SignalEvent (mLogDataHubEvent); + + return EFI_SUCCESS; +} + +VOID +EFIAPI +LogDataHubEventHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + + The Event handler which will be notified to log data in Data Hub. + +Arguments: + + Event - Instance of the EFI_EVENT to signal whenever data is + available to be logged in the system. + Context - Context of the event. + +Returns: + + None. + +--*/ +{ + EFI_STATUS Status; + DATA_HUB_STATUS_CODE_DATA_RECORD *DataRecord; + UINTN Size; + UINT64 DataRecordClass; + LIST_ENTRY *Link; + STATUS_CODE_RECORD_LIST *BufferEntry; + + // + // Set our global flag so we don't recurse if we get an error here. + // + mEventHandlerActive = TRUE; + + // + // Log DataRecord in Data Hub. + // If there are multiple DataRecords, Log all of them. + // + for (Link = mRecordBuffer.ForwardLink; Link != &mRecordBuffer;) { + BufferEntry = CR (Link, STATUS_CODE_RECORD_LIST, Link, BS_DATA_HUB_STATUS_CODE_SIGNATURE); + DataRecord = (DATA_HUB_STATUS_CODE_DATA_RECORD *) (BufferEntry->RecordBuffer); + Link = Link->ForwardLink; + + // + // Add in the size of the header we added. + // + Size = sizeof (DATA_HUB_STATUS_CODE_DATA_RECORD) + DataRecord->Data.Size; + + if ((DataRecord->CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) { + DataRecordClass = EFI_DATA_RECORD_CLASS_PROGRESS_CODE; + } else if ((DataRecord->CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) { + DataRecordClass = EFI_DATA_RECORD_CLASS_ERROR; + } else if ((DataRecord->CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE) { + DataRecordClass = EFI_DATA_RECORD_CLASS_DEBUG; + } else { + // + // Should never get here. + // + DataRecordClass = EFI_DATA_RECORD_CLASS_DEBUG | + EFI_DATA_RECORD_CLASS_ERROR | + EFI_DATA_RECORD_CLASS_DATA | + EFI_DATA_RECORD_CLASS_PROGRESS_CODE; + } + + if (((DataRecord->Instance & EFI_D_ERROR) != 0) && + (((DataRecord->Instance & EFI_D_POOL) != 0) || ((DataRecord->Instance & EFI_D_PAGE) != 0)) + ) { + // + // If memory error, do not call LogData (). + // + DebugPrint ((UINTN)-1, "Memory Error\n"); + Status = EFI_OUT_OF_RESOURCES; + } else { + // + // Log DataRecord in Data Hub + // + Status = mDataHub->LogData ( + mDataHub, + &gEfiStatusCodeGuid, + &gEfiStatusCodeRuntimeProtocolGuid, + DataRecordClass, + DataRecord, + (UINT32) Size + ); + } + + ReleaseRecordBuffer (BufferEntry); + } + + mEventHandlerActive = FALSE; + + return ; +} + +VOID +BsDataHubStatusCodeInitialize ( + VOID + ) +/*++ + +Routine Description: + + Install a data hub listener. + +Arguments: + + (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT) + +Returns: + + EFI_SUCCESS - Logging Hub protocol installed + Other - No protocol installed, unload driver. + +--*/ +{ + EFI_STATUS Status; + + Status = gBS->LocateProtocol (&gEfiDataHubProtocolGuid, NULL, (VOID **) &mDataHub); + // + // Should never fail due to dependency grammer + // + ASSERT_EFI_ERROR (Status); + + // + // Initialize FIFO + // + InitializeListHead (&mRecordBuffer); + mRecordNum = 0; + + EfiInitializeLock (&mStatusCodeReportLock, EFI_TPL_HIGH_LEVEL); + + // + // Create a Notify Event to log data in Data Hub + // + Status = gBS->CreateEvent ( + EFI_EVENT_NOTIFY_SIGNAL, + EFI_TPL_CALLBACK, + LogDataHubEventHandler, + NULL, + &mLogDataHubEvent + ); + +} diff --git a/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/BsDataHubStatusCode/BsDataHubStatusCode.h b/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/BsDataHubStatusCode/BsDataHubStatusCode.h new file mode 100644 index 0000000000..f15a90e5e2 --- /dev/null +++ b/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/BsDataHubStatusCode/BsDataHubStatusCode.h @@ -0,0 +1,130 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + BsDataHubStatusCode.h + +Abstract: + + Header for the status code data hub logging component + +--*/ + +#ifndef _EFI_BS_DATA_HUB_STATUS_CODE_H_ +#define _EFI_BS_DATA_HUB_STATUS_CODE_H_ + +// +// Private data declarations +// +#define MAX_RECORD_NUM 1000 +#define BYTES_PER_RECORD EFI_STATUS_CODE_DATA_MAX_SIZE +#define EMPTY_RECORD_TAG 0xFF + +#define BS_DATA_HUB_STATUS_CODE_SIGNATURE EFI_SIGNATURE_32 ('B', 'D', 'H', 'S') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + UINT8 RecordBuffer[BYTES_PER_RECORD]; +} STATUS_CODE_RECORD_LIST; + +// +// Function prototypes +// +STATUS_CODE_RECORD_LIST * +GetRecordBuffer ( + VOID + ) +; + +/*++ + +Routine Description: + + Returned buffer of length BYTES_PER_RECORD + +Arguments: + + None + +Returns: + + Entry in mRecordBuffer or NULL if non available + +--*/ +DATA_HUB_STATUS_CODE_DATA_RECORD * +AquireEmptyRecordBuffer ( + VOID + ) +; + +/*++ + +Routine Description: + + Allocate a mRecordBuffer entry in the form of a pointer. + +Arguments: + + None + +Returns: + + Pointer to new buffer. NULL if none exist. + +--*/ +EFI_STATUS +ReleaseRecordBuffer ( + IN STATUS_CODE_RECORD_LIST *RecordBuffer + ) +; + +/*++ + +Routine Description: + + Release a mRecordBuffer entry allocated by AquireEmptyRecordBuffer (). + +Arguments: + + RecordBuffer - Data to free + +Returns: + + EFI_SUCCESS - If RecordBuffer is valid + EFI_UNSUPPORTED - The record list has empty + +--*/ +VOID +EFIAPI +LogDataHubEventHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ) +; + +/*++ + +Routine Description: + + Event Handler that log in Status code in Data Hub. + +Arguments: + + (Standard EFI Event Handler - EFI_EVENT_NOTIFY) + +Returns: + + NONE + +--*/ +#endif diff --git a/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/BsDataHubStatusCode/BsDataHubStatusCode.mbd b/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/BsDataHubStatusCode/BsDataHubStatusCode.mbd new file mode 100644 index 0000000000..ce1bd63b0d --- /dev/null +++ b/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/BsDataHubStatusCode/BsDataHubStatusCode.mbd @@ -0,0 +1,30 @@ + + + + + EdkBsDataHubStatusCodeLib + 041bf780-dc3e-49ab-8d67-4b86075440ea + 0 + FIX ME! + Copyright (c) 2004 - 2005, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + diff --git a/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/BsDataHubStatusCode/BsDataHubStatusCode.msa b/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/BsDataHubStatusCode/BsDataHubStatusCode.msa new file mode 100644 index 0000000000..7eff726640 --- /dev/null +++ b/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/BsDataHubStatusCode/BsDataHubStatusCode.msa @@ -0,0 +1,72 @@ + + + + + EdkBsDataHubStatusCodeLib + DXE_DRIVER + LIBRARY + 041bf780-dc3e-49ab-8d67-4b86075440ea + 0 + Component description file for the PEI library. + FIX ME! + Copyright (c) 2004 - 2005, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + EdkBsDataHubStatusCodeLib + UefiLib + DebugLib + BaseLib + BaseMemoryLib + DxeRuntimeDriverLib + ReportStatusCodeLib + PrintLib + UefiBootServicesTableLib + + + BsDataHubStatusCode.c + BsDataHubStatusCode.h + + + MdePkg + EdkModulePkg + + + StatusCode + DataHub + + + + + EFI_EVENT_NOTIFY_SIGNAL + + + + + gEfiStatusCodeGuid + + + + StatusCode + + + diff --git a/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/BsDataHubStatusCode/build.xml b/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/BsDataHubStatusCode/build.xml new file mode 100644 index 0000000000..308ca95b11 --- /dev/null +++ b/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/BsDataHubStatusCode/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/RtMemoryStatusCode/RtMemoryStatusCode.c b/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/RtMemoryStatusCode/RtMemoryStatusCode.c new file mode 100644 index 0000000000..375a338a85 --- /dev/null +++ b/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/RtMemoryStatusCode/RtMemoryStatusCode.c @@ -0,0 +1,188 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + RtMemoryStatusCode.c + +Abstract: + + EFI lib to provide memory journal status code reporting routines. + +--*/ + +#include + +// +// Global variables +// +PEI_STATUS_CODE_MEMORY_PPI mStatusCodeMemoryPpi = { 0, 0, 0, 0 }; + +// +// Function implementations +// +EFI_STATUS +RtMemoryReportStatusCode ( + 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 + ) +/*++ + +Routine Description: + + Log a status code to a memory journal. If no memory journal exists, + we will just return. + +Arguments: + + Same as ReportStatusCode AP + +Returns: + + EFI_SUCCESS This function always returns success + +--*/ +{ + EFI_STATUS_CODE_ENTRY *CurrentEntry; + UINTN MaxEntry; + + // + // We don't care to log debug codes. + // + if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE) { + return EFI_SUCCESS; + } + // + // Update the latest entry in the journal. + // + MaxEntry = mStatusCodeMemoryPpi.Length / sizeof (EFI_STATUS_CODE_ENTRY); + if (!MaxEntry) { + // + // If we don't have any entries, then we can return. + // This effectively means that no memory buffer was passed forward from PEI. + // + return EFI_SUCCESS; + } + + CurrentEntry = (EFI_STATUS_CODE_ENTRY *) (UINTN) (mStatusCodeMemoryPpi.Address + (mStatusCodeMemoryPpi.LastEntry * sizeof (EFI_STATUS_CODE_ENTRY))); + + mStatusCodeMemoryPpi.LastEntry = (mStatusCodeMemoryPpi.LastEntry + 1) % MaxEntry; + if (mStatusCodeMemoryPpi.LastEntry == mStatusCodeMemoryPpi.FirstEntry) { + mStatusCodeMemoryPpi.FirstEntry = (mStatusCodeMemoryPpi.FirstEntry + 1) % MaxEntry; + } + + CurrentEntry->Type = CodeType; + CurrentEntry->Value = Value; + CurrentEntry->Instance = Instance; + + return EFI_SUCCESS; +} + +VOID +RtMemoryStatusCodeInitialize ( + VOID + ) +/*++ + +Routine Description: + + Initialization routine. + Allocates heap space for storing Status Codes. + Installs a PPI to point to that heap space. + Installs a callback to switch to memory. + Installs a callback to + +Arguments: + + (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT) + +Returns: + + None + +--*/ +{ + EFI_HOB_GUID_TYPE *GuidHob; + PEI_STATUS_CODE_MEMORY_PPI **StatusCodeMemoryPpi; + + GuidHob = GetFirstGuidHob (&gPeiStatusCodeMemoryPpiGuid); + if (GuidHob == NULL) { + return; + } + + StatusCodeMemoryPpi = GET_GUID_HOB_DATA (GuidHob); + + // + // Copy data to our structure since the HOB will go away at runtime + // + // BUGBUG: Virtualize for RT + // + mStatusCodeMemoryPpi.FirstEntry = (*StatusCodeMemoryPpi)->FirstEntry; + mStatusCodeMemoryPpi.LastEntry = (*StatusCodeMemoryPpi)->LastEntry; + mStatusCodeMemoryPpi.Address = (*StatusCodeMemoryPpi)->Address; + mStatusCodeMemoryPpi.Length = (*StatusCodeMemoryPpi)->Length; +} + +VOID +PlaybackStatusCodes ( + IN EFI_REPORT_STATUS_CODE ReportStatusCodeFunc + ) +/*++ + +Routine Description: + + Call the input ReportStatusCode function with every status code recorded in + the journal. + +Arguments: + + ReportStatusCode ReportStatusCode function to call. + +Returns: + + None + +--*/ +{ + UINTN MaxEntry; + EFI_STATUS_CODE_ENTRY *CurrentEntry; + UINTN Counter; + + if (ReportStatusCodeFunc == RtMemoryReportStatusCode) { + return ; + } + // + // Playback prior status codes to current listeners + // + MaxEntry = mStatusCodeMemoryPpi.Length / sizeof (EFI_STATUS_CODE_ENTRY); + for (Counter = mStatusCodeMemoryPpi.FirstEntry; Counter != mStatusCodeMemoryPpi.LastEntry; Counter++) { + // + // Check if we have to roll back to beginning of queue buffer + // + if (Counter == MaxEntry) { + Counter = 0; + } + // + // Play current entry + // + CurrentEntry = (EFI_STATUS_CODE_ENTRY *) (UINTN) (mStatusCodeMemoryPpi.Address + (Counter * sizeof (EFI_STATUS_CODE_ENTRY))); + ReportStatusCodeFunc ( + CurrentEntry->Type, + CurrentEntry->Value, + CurrentEntry->Instance, + NULL, + NULL + ); + } +} diff --git a/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/RtMemoryStatusCode/RtMemoryStatusCode.mbd b/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/RtMemoryStatusCode/RtMemoryStatusCode.mbd new file mode 100644 index 0000000000..1795204d66 --- /dev/null +++ b/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/RtMemoryStatusCode/RtMemoryStatusCode.mbd @@ -0,0 +1,30 @@ + + + + + EdkRtMemoryStatusCodeLib + 1517564b-ab66-42b7-8903-731a95f314f9 + 0 + FIX ME! + Copyright (c) 2004 - 2005, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + diff --git a/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/RtMemoryStatusCode/RtMemoryStatusCode.msa b/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/RtMemoryStatusCode/RtMemoryStatusCode.msa new file mode 100644 index 0000000000..84d38e3293 --- /dev/null +++ b/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/RtMemoryStatusCode/RtMemoryStatusCode.msa @@ -0,0 +1,52 @@ + + + + + EdkRtMemoryStatusCodeLib + DXE_DRIVER + LIBRARY + 1517564b-ab66-42b7-8903-731a95f314f9 + 0 + Component description file for the PEI library. + FIX ME! + Copyright (c) 2004 - 2005, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + EdkRtMemoryStatusCodeLib + UefiLib + DebugLib + BaseLib + DxeRuntimeDriverLib + ReportStatusCodeLib + PrintLib + HobLib + UefiBootServicesTableLib + + + RtMemoryStatusCode.c + + + MdePkg + EdkModulePkg + + diff --git a/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/RtMemoryStatusCode/build.xml b/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/RtMemoryStatusCode/build.xml new file mode 100644 index 0000000000..0f02e4e8f7 --- /dev/null +++ b/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/RtMemoryStatusCode/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/RtPlatformStatusCode/RtPlatformStatusCode.c b/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/RtPlatformStatusCode/RtPlatformStatusCode.c new file mode 100644 index 0000000000..47f7f96511 --- /dev/null +++ b/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/RtPlatformStatusCode/RtPlatformStatusCode.c @@ -0,0 +1,130 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + RtPlatformStatusCode.c + +Abstract: + + Contains NT32 specific implementations required to use status codes. + +--*/ + +// +// Globals only work at BootService Time. NOT at Runtime! +// +// + +typedef +EFI_STATUS +(EFIAPI *REPORT_STATUS_CODE_FUNCTION) ( + 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 + ); + +REPORT_STATUS_CODE_FUNCTION mPeiReportStatusCode; + +// +// Function implementations +// +EFI_STATUS +RtPlatformReportStatusCode ( + 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 + ) +/*++ + +Routine Description: + + Call all status code listeners in the MonoStatusCode. + +Arguments: + + Same as ReportStatusCode service + +Returns: + + EFI_SUCCESS Always returns success. + +--*/ +{ + RtMemoryReportStatusCode (CodeType, Value, Instance, CallerId, Data); + if (EfiAtRuntime ()) { + // + // For now all we do is post code at runtime + // + return EFI_SUCCESS; + } + + BsDataHubReportStatusCode (CodeType, Value, Instance, CallerId, Data); + + // + // Call back into PEI to get status codes. This is because SecMain contains + // status code that reports to Win32. + // + if (mPeiReportStatusCode != NULL) { + return mPeiReportStatusCode (CodeType, Value, Instance, CallerId, Data); + } + + return EFI_SUCCESS; +} + +VOID +RtPlatformStatusCodeInitialize ( + VOID + ) +/*++ + +Routine Description: + + Initialize the status code listeners. + +Arguments: + + (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT) + +Returns: + + None + +--*/ +{ + EFI_HOB_GUID_TYPE *GuidHob; + void *Pointer; + + RtMemoryStatusCodeInitialize (); + BsDataHubStatusCodeInitialize (); + + // + // Play any prior status codes to the data hub. + // + PlaybackStatusCodes (BsDataHubReportStatusCode); + + // + // If PEI has a ReportStatusCode callback find it and use it before StdErr + // is connected. + // + mPeiReportStatusCode = NULL; + + GuidHob = GetFirstGuidHob (&gEfiStatusCodeRuntimeProtocolGuid); + if (NULL == GuidHob) { + return; + } + Pointer = GET_GUID_HOB_DATA (GuidHob); + mPeiReportStatusCode = (REPORT_STATUS_CODE_FUNCTION) (*(UINTN *) Pointer); +} diff --git a/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/RtPlatformStatusCode/RtPlatformStatusCode.mbd b/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/RtPlatformStatusCode/RtPlatformStatusCode.mbd new file mode 100644 index 0000000000..64591313c7 --- /dev/null +++ b/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/RtPlatformStatusCode/RtPlatformStatusCode.mbd @@ -0,0 +1,30 @@ + + + + + EdkRtPlatformStatusCodeLib + 68b157b5-9534-43ff-9cd3-6705e4e1d56c + 0 + FIX ME! + Copyright (c) 2004 - 2005, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + diff --git a/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/RtPlatformStatusCode/RtPlatformStatusCode.msa b/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/RtPlatformStatusCode/RtPlatformStatusCode.msa new file mode 100644 index 0000000000..2225ca5b2b --- /dev/null +++ b/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/RtPlatformStatusCode/RtPlatformStatusCode.msa @@ -0,0 +1,54 @@ + + + + + EdkRtPlatformStatusCodeLib + DXE_DRIVER + LIBRARY + 68b157b5-9534-43ff-9cd3-6705e4e1d56c + 0 + Component description file for the PEI library. + FIX ME! + Copyright (c) 2004 - 2005, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + EdkRtPlatformStatusCodeLib + UefiLib + DebugLib + BaseLib + DxeRuntimeDriverLib + ReportStatusCodeLib + PrintLib + HobLib + EdkBsDataHubStatusCodeLib + EdkRtMemoryStatusCodeLib + UefiBootServicesTableLib + + + RtPlatformStatusCode.c + + + MdePkg + EdkModulePkg + + diff --git a/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/RtPlatformStatusCode/build.xml b/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/RtPlatformStatusCode/build.xml new file mode 100644 index 0000000000..34d4d7563c --- /dev/null +++ b/EdkModulePkg/Library/EdkRuntimeStatusCodeLib/RtPlatformStatusCode/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Library/EdkScsiLib/EdkScsiLib.mbd b/EdkModulePkg/Library/EdkScsiLib/EdkScsiLib.mbd new file mode 100644 index 0000000000..18d03c26b1 --- /dev/null +++ b/EdkModulePkg/Library/EdkScsiLib/EdkScsiLib.mbd @@ -0,0 +1,30 @@ + + + + + EdkScsiLib + 46c9adef-aee6-410c-99e4-240e3af18d8b + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + diff --git a/EdkModulePkg/Library/EdkScsiLib/EdkScsiLib.msa b/EdkModulePkg/Library/EdkScsiLib/EdkScsiLib.msa new file mode 100644 index 0000000000..033d54847c --- /dev/null +++ b/EdkModulePkg/Library/EdkScsiLib/EdkScsiLib.msa @@ -0,0 +1,45 @@ + + + + + EdkScsiLib + DXE_DRIVER + LIBRARY + 46c9adef-aee6-410c-99e4-240e3af18d8b + 0 + Component description file for Scsi Dxe Library. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + EdkScsiLib + BaseMemoryLib + + + ScsiLib.c + + + MdePkg + EdkModulePkg + + diff --git a/EdkModulePkg/Library/EdkScsiLib/ScsiLib.c b/EdkModulePkg/Library/EdkScsiLib/ScsiLib.c new file mode 100644 index 0000000000..9a6eb6751e --- /dev/null +++ b/EdkModulePkg/Library/EdkScsiLib/ScsiLib.c @@ -0,0 +1,651 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ScsiLib.c + +Abstract: + + +Revision History +--*/ + + +#include + +EFI_STATUS +SubmitTestUnitReadyCommand ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + OUT VOID *SenseData, + OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus + ) +/*++ + +Routine Description: + Function tests the ready status of SCSI unit. + +Arguments: + ScsiIo - A pointer to SCSI IO protocol. + Timeout - The length of timeout period. + SenseData - A pointer to output sense data. + SenseDataLength - The length of output sense data. + HostAdapterStatus - The status of Host Adapter. + TargetStatus - The status of the target. + +Returns: + + Returns: + EFI_SUCCESS - The status of the unit is tested successfully. + EFI_WARN_BUFFER_TOO_SMALL - The SCSI Request Packet was executed, + but the entire DataBuffer could not be transferred. + The actual number of bytes transferred is returned + in InTransferLength. + EFI_NOT_READY - The SCSI Request Packet could not be sent because + there are too many SCSI Command Packets already + queued. + EFI_DEVICE_ERROR - A device error occurred while attempting to send + the SCSI Request Packet. + EFI_INVALID_PARAMETER - The contents of CommandPacket are invalid. + EFI_UNSUPPORTED - The command described by the SCSI Request Packet + is not supported by the SCSI initiator(i.e., SCSI + Host Controller). + EFI_TIMEOUT - A timeout occurred while waiting for the SCSI + Request Packet to execute. + +--*/ +{ + EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket; + UINT64 Lun; + UINT8 *Target; + EFI_STATUS Status; + UINT8 Cdb[6]; + + ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET)); + ZeroMem (Cdb, 6); + + CommandPacket.Timeout = Timeout; + CommandPacket.InDataBuffer = NULL; + CommandPacket.SenseData = SenseData; + CommandPacket.InTransferLength= 0; + CommandPacket.Cdb = Cdb; + // + // Fill Cdb for Test Unit Ready Command + // + ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun); + + Cdb[0] = EFI_SCSI_OP_TEST_UNIT_READY; + Cdb[1] = (UINT8) (Lun & 0xe0); + CommandPacket.CdbLength = (UINT8) 6; + CommandPacket.SenseDataLength = *SenseDataLength; + + Status = ScsiIo->ExecuteSCSICommand (ScsiIo, &CommandPacket, NULL); + + *HostAdapterStatus = CommandPacket.HostAdapterStatus; + *TargetStatus = CommandPacket.TargetStatus; + *SenseDataLength = CommandPacket.SenseDataLength; + + return Status; +} + +EFI_STATUS +SubmitInquiryCommand ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN VOID *SenseData, + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus, + IN OUT VOID *InquiryDataBuffer, + IN OUT UINT32 *InquiryDataLength, + IN BOOLEAN EnableVitalProductData + ) +/*++ + +Routine Description: + Function to submit SCSI inquiry command. + +Arguments: + ScsiIo - A pointer to SCSI IO protocol. + Timeout - The length of timeout period. + SenseData - A pointer to output sense data. + SenseDataLength - The length of output sense data. + HostAdapterStatus - The status of Host Adapter. + TargetStatus - The status of the target. + InquiryDataBuffer - A pointer to inquiry data buffer. + InquiryDataLength - The length of inquiry data buffer. + EnableVitalProductData - Boolean to enable Vital Product Data. + +Returns: + + Returns: + EFI_SUCCESS - The status of the unit is tested successfully. + EFI_WARN_BUFFER_TOO_SMALL - The SCSI Request Packet was executed, + but the entire DataBuffer could not be transferred. + The actual number of bytes transferred is returned + in TransferLength. + EFI_NOT_READY - The SCSI Request Packet could not be sent because + there are too many SCSI Command Packets already + queued. + EFI_DEVICE_ERROR - A device error occurred while attempting to send + the SCSI Request Packet. + EFI_INVALID_PARAMETER - The contents of CommandPacket are invalid. + EFI_UNSUPPORTED - The command described by the SCSI Request Packet + is not supported by the SCSI initiator(i.e., SCSI + Host Controller). + EFI_TIMEOUT - A timeout occurred while waiting for the SCSI + Request Packet to execute. + +--*/ +{ + EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket; + UINT64 Lun; + UINT8 *Target; + EFI_STATUS Status; + UINT8 Cdb[6]; + + ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET)); + ZeroMem (Cdb, 6); + + CommandPacket.Timeout = Timeout; + CommandPacket.InDataBuffer = InquiryDataBuffer; + CommandPacket.InTransferLength= *InquiryDataLength; + CommandPacket.SenseData = SenseData; + CommandPacket.SenseDataLength = *SenseDataLength; + CommandPacket.Cdb = Cdb; + + ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun); + + Cdb[0] = EFI_SCSI_OP_INQUIRY; + Cdb[1] = (UINT8) (Lun & 0xe0); + if (EnableVitalProductData) { + Cdb[1] |= 0x01; + } + + if (*InquiryDataLength > 0xff) { + *InquiryDataLength = 0xff; + } + + Cdb[4] = (UINT8) (*InquiryDataLength); + CommandPacket.CdbLength = (UINT8) 6; + CommandPacket.DataDirection = EFI_SCSI_DATA_IN; + + Status = ScsiIo->ExecuteSCSICommand (ScsiIo, &CommandPacket, NULL); + + *HostAdapterStatus = CommandPacket.HostAdapterStatus; + *TargetStatus = CommandPacket.TargetStatus; + *SenseDataLength = CommandPacket.SenseDataLength; + *InquiryDataLength = CommandPacket.InTransferLength; + + return Status; +} + +EFI_STATUS +SubmitModeSense10Command ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN VOID *SenseData, + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus, + IN VOID *DataBuffer, + IN OUT UINT32 *DataLength, + IN UINT8 DBDField, OPTIONAL + IN UINT8 PageControl, + IN UINT8 PageCode + ) +/*++ + +Routine Description: + Function to submit SCSI mode sense 10 command. + +Arguments: + ScsiIo - A pointer to SCSI IO protocol. + Timeout - The length of timeout period. + SenseData - A pointer to output sense data. + SenseDataLength - The length of output sense data. + HostAdapterStatus - The status of Host Adapter. + TargetStatus - The status of the target. + DataBuffer - A pointer to input data buffer. + DataLength - The length of input data buffer. + DBDField - The DBD Field (Optional). + PageControl - Page Control. + PageCode - Page code. + +Returns: + + Returns: + EFI_SUCCESS - The status of the unit is tested successfully. + EFI_WARN_BUFFER_TOO_SMALL - The SCSI Request Packet was executed, + but the entire DataBuffer could not be transferred. + The actual number of bytes transferred is returned + in TransferLength. + EFI_NOT_READY - The SCSI Request Packet could not be sent because + there are too many SCSI Command Packets already + queued. + EFI_DEVICE_ERROR - A device error occurred while attempting to send + the SCSI Request Packet. + EFI_INVALID_PARAMETER - The contents of CommandPacket are invalid. + EFI_UNSUPPORTED - The command described by the SCSI Request Packet + is not supported by the SCSI initiator(i.e., SCSI + Host Controller). + EFI_TIMEOUT - A timeout occurred while waiting for the SCSI + Request Packet to execute. + +--*/ +{ + EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket; + UINT64 Lun; + UINT8 *Target; + EFI_STATUS Status; + UINT8 Cdb[10]; + + ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET)); + ZeroMem (Cdb, 10); + + CommandPacket.Timeout = Timeout; + CommandPacket.InDataBuffer = DataBuffer; + CommandPacket.SenseData = SenseData; + CommandPacket.InTransferLength= *DataLength; + CommandPacket.Cdb = Cdb; + // + // Fill Cdb for Mode Sense (10) Command + // + ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun); + + Cdb[0] = EFI_SCSI_OP_MODE_SEN10; + Cdb[1] = (UINT8) ((Lun & 0xe0) + ((DBDField << 3) & 0x08)); + Cdb[2] = (UINT8) ((PageControl & 0xc0) | (PageCode & 0x3f)); + Cdb[7] = (UINT8) (*DataLength >> 8); + Cdb[8] = (UINT8) (*DataLength); + + CommandPacket.CdbLength = 10; + CommandPacket.DataDirection = EFI_SCSI_DATA_IN; + CommandPacket.SenseDataLength = *SenseDataLength; + + Status = ScsiIo->ExecuteSCSICommand (ScsiIo, &CommandPacket, NULL); + + *HostAdapterStatus = CommandPacket.HostAdapterStatus; + *TargetStatus = CommandPacket.TargetStatus; + *SenseDataLength = CommandPacket.SenseDataLength; + *DataLength = CommandPacket.InTransferLength; + + return Status; +} + +EFI_STATUS +SubmitRequestSenseCommand ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN VOID *SenseData, + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus + ) +/*++ + +Routine Description: + Function to submit SCSI request sense command. + +Arguments: + ScsiIo - A pointer to SCSI IO protocol. + Timeout - The length of timeout period. + SenseData - A pointer to output sense data. + SenseDataLength - The length of output sense data. + HostAdapterStatus - The status of Host Adapter. + TargetStatus - The status of the target. + +Returns: + + Returns: + EFI_SUCCESS - The status of the unit is tested successfully. + EFI_WARN_BUFFER_TOO_SMALL - The SCSI Request Packet was executed, + but the entire DataBuffer could not be transferred. + The actual number of bytes transferred is returned + in TransferLength. + EFI_NOT_READY - The SCSI Request Packet could not be sent because + there are too many SCSI Command Packets already + queued. + EFI_DEVICE_ERROR - A device error occurred while attempting to send + the SCSI Request Packet. + EFI_INVALID_PARAMETER - The contents of CommandPacket are invalid. + EFI_UNSUPPORTED - The command described by the SCSI Request Packet + is not supported by the SCSI initiator(i.e., SCSI + Host Controller). + EFI_TIMEOUT - A timeout occurred while waiting for the SCSI + Request Packet to execute. + +--*/ +{ + EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket; + UINT64 Lun; + UINT8 *Target; + EFI_STATUS Status; + UINT8 Cdb[6]; + + ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET)); + ZeroMem (Cdb, 6); +/* + if (*SenseDataLength > 0xff) { + *SenseDataLength = 0xff; + } +*/ + CommandPacket.Timeout = Timeout; + CommandPacket.InDataBuffer = SenseData; + CommandPacket.SenseData = NULL; + CommandPacket.InTransferLength= *SenseDataLength; + CommandPacket.Cdb = Cdb; + // + // Fill Cdb for Request Sense Command + // + ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun); + + Cdb[0] = EFI_SCSI_OP_REQUEST_SENSE; + Cdb[1] = (UINT8) (Lun & 0xe0); + Cdb[4] = (UINT8) (*SenseDataLength); + + CommandPacket.CdbLength = (UINT8) 6; + CommandPacket.DataDirection = EFI_SCSI_DATA_IN; + CommandPacket.SenseDataLength = 0; + + Status = ScsiIo->ExecuteSCSICommand (ScsiIo, &CommandPacket, NULL); + + *HostAdapterStatus = CommandPacket.HostAdapterStatus; + *TargetStatus = CommandPacket.TargetStatus; + *SenseDataLength = (UINT8) CommandPacket.InTransferLength; + + return Status; +} + +EFI_STATUS +SubmitReadCapacityCommand ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN VOID *SenseData, + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus, + OUT VOID *DataBuffer, + IN OUT UINT32 *DataLength, + IN BOOLEAN PMI + ) +/*++ + +Routine Description: + Function to submit read capacity command. + +Arguments: + ScsiIo - A pointer to SCSI IO protocol. + Timeout - The length of timeout period. + SenseData - A pointer to output sense data. + SenseDataLength - The length of output sense data. + HostAdapterStatus - The status of Host Adapter. + TargetStatus - The status of the target. + DataBuffer - A pointer to a data buffer. + DataLength - The length of data buffer. + PMI - Partial medium indicator. + +Returns: + + Returns: + EFI_SUCCESS - The status of the unit is tested successfully. + EFI_WARN_BUFFER_TOO_SMALL - The SCSI Request Packet was executed, + but the entire DataBuffer could not be transferred. + The actual number of bytes transferred is returned + in TransferLength. + EFI_NOT_READY - The SCSI Request Packet could not be sent because + there are too many SCSI Command Packets already + queued. + EFI_DEVICE_ERROR - A device error occurred while attempting to send + the SCSI Request Packet. + EFI_INVALID_PARAMETER - The contents of CommandPacket are invalid. + EFI_UNSUPPORTED - The command described by the SCSI Request Packet + is not supported by the SCSI initiator(i.e., SCSI + Host Controller). + EFI_TIMEOUT - A timeout occurred while waiting for the SCSI + Request Packet to execute. + +--*/ +{ + EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket; + UINT64 Lun; + UINT8 *Target; + EFI_STATUS Status; + UINT8 Cdb[10]; + + ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET)); + ZeroMem (Cdb, 10); + + CommandPacket.Timeout = Timeout; + CommandPacket.InDataBuffer = DataBuffer; + CommandPacket.SenseData = SenseData; + CommandPacket.InTransferLength= *DataLength; + CommandPacket.Cdb = Cdb; + // + // Fill Cdb for Read Capacity Command + // + ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun); + + Cdb[0] = EFI_SCSI_OP_READ_CAPACITY; + Cdb[1] = (UINT8) (Lun & 0xe0); + if (!PMI) { + // + // Partial medium indicator,if PMI is FALSE, the Cdb.2 ~ Cdb.5 MUST BE ZERO. + // + ZeroMem ((Cdb + 2), 4); + } else { + Cdb[8] |= 0x01; + } + + CommandPacket.CdbLength = 10; + CommandPacket.DataDirection = EFI_SCSI_DATA_IN; + CommandPacket.SenseDataLength = *SenseDataLength; + + Status = ScsiIo->ExecuteSCSICommand (ScsiIo, &CommandPacket, NULL); + + *HostAdapterStatus = CommandPacket.HostAdapterStatus; + *TargetStatus = CommandPacket.TargetStatus; + *SenseDataLength = CommandPacket.SenseDataLength; + *DataLength = CommandPacket.InTransferLength; + + return Status; +} + +EFI_STATUS +SubmitRead10Command ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN VOID *SenseData, + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus, + OUT VOID *DataBuffer, + IN OUT UINT32 *DataLength, + IN UINT32 StartLba, + IN UINT32 SectorSize + ) +/*++ + +Routine Description: + Function to submit read 10 command. + +Arguments: + ScsiIo - A pointer to SCSI IO protocol. + Timeout - The length of timeout period. + SenseData - A pointer to output sense data. + SenseDataLength - The length of output sense data. + HostAdapterStatus - The status of Host Adapter. + TargetStatus - The status of the target. + DataBuffer - A pointer to a data buffer. + DataLength - The length of data buffer. + StartLba - The start address of LBA. + SectorSize - The sector size. + +Returns: + + Returns: + EFI_SUCCESS - The status of the unit is tested successfully. + EFI_WARN_BUFFER_TOO_SMALL - The SCSI Request Packet was executed, + but the entire DataBuffer could not be transferred. + The actual number of bytes transferred is returned + in TransferLength. + EFI_NOT_READY - The SCSI Request Packet could not be sent because + there are too many SCSI Command Packets already + queued. + EFI_DEVICE_ERROR - A device error occurred while attempting to send + the SCSI Request Packet. + EFI_INVALID_PARAMETER - The contents of CommandPacket are invalid. + EFI_UNSUPPORTED - The command described by the SCSI Request Packet + is not supported by the SCSI initiator(i.e., SCSI + Host Controller). + EFI_TIMEOUT - A timeout occurred while waiting for the SCSI + Request Packet to execute. + +--*/ +{ + EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket; + UINT64 Lun; + UINT8 *Target; + EFI_STATUS Status; + UINT8 Cdb[10]; + + ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET)); + ZeroMem (Cdb, 10); + + CommandPacket.Timeout = Timeout; + CommandPacket.InDataBuffer = DataBuffer; + CommandPacket.SenseData = SenseData; + CommandPacket.InTransferLength= *DataLength; + CommandPacket.Cdb = Cdb; + // + // Fill Cdb for Read (10) Command + // + ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun); + + Cdb[0] = EFI_SCSI_OP_READ10; + Cdb[1] = (UINT8) (Lun & 0xe0); + Cdb[2] = (UINT8) (StartLba >> 24); + Cdb[3] = (UINT8) (StartLba >> 16); + Cdb[4] = (UINT8) (StartLba >> 8); + Cdb[5] = (UINT8) StartLba; + Cdb[7] = (UINT8) (SectorSize >> 8); + Cdb[8] = (UINT8) SectorSize; + + CommandPacket.CdbLength = 10; + CommandPacket.DataDirection = EFI_SCSI_DATA_IN; + CommandPacket.SenseDataLength = *SenseDataLength; + + Status = ScsiIo->ExecuteSCSICommand (ScsiIo, &CommandPacket, NULL); + + *HostAdapterStatus = CommandPacket.HostAdapterStatus; + *TargetStatus = CommandPacket.TargetStatus; + *SenseDataLength = CommandPacket.SenseDataLength; + *DataLength = CommandPacket.InTransferLength; + + return Status; +} + +EFI_STATUS +SubmitWrite10Command ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN VOID *SenseData, + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus, + OUT VOID *DataBuffer, + IN OUT UINT32 *DataLength, + IN UINT32 StartLba, + IN UINT32 SectorSize + ) +/*++ + +Routine Description: + Function to submit SCSI write 10 command. + +Arguments: + ScsiIo - A pointer to SCSI IO protocol. + Timeout - The length of timeout period. + SenseData - A pointer to output sense data. + SenseDataLength - The length of output sense data. + HostAdapterStatus - The status of Host Adapter. + TargetStatus - The status of the target. + DataBuffer - A pointer to a data buffer. + DataLength - The length of data buffer. + StartLba - The start address of LBA. + SectorSize - The sector size. + +Returns: + + Returns: + EFI_SUCCESS - The status of the unit is tested successfully. + EFI_WARN_BUFFER_TOO_SMALL - The SCSI Request Packet was executed, + but the entire DataBuffer could not be transferred. + The actual number of bytes transferred is returned + in InTransferLength. + EFI_NOT_READY - The SCSI Request Packet could not be sent because + there are too many SCSI Command Packets already + queued. + EFI_DEVICE_ERROR - A device error occurred while attempting to send + the SCSI Request Packet. + EFI_INVALID_PARAMETER - The contents of CommandPacket are invalid. + EFI_UNSUPPORTED - The command described by the SCSI Request Packet + is not supported by the SCSI initiator(i.e., SCSI + Host Controller). + EFI_TIMEOUT - A timeout occurred while waiting for the SCSI + Request Packet to execute. + +--*/ +{ + EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket; + UINT64 Lun; + UINT8 *Target; + EFI_STATUS Status; + UINT8 Cdb[10]; + + ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET)); + ZeroMem (Cdb, 10); + + CommandPacket.Timeout = Timeout; + CommandPacket.InDataBuffer = DataBuffer; + CommandPacket.SenseData = SenseData; + CommandPacket.InTransferLength= *DataLength; + CommandPacket.Cdb = Cdb; + // + // Fill Cdb for Write (10) Command + // + ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun); + + Cdb[0] = EFI_SCSI_OP_WRITE10; + Cdb[1] = (UINT8) (Lun & 0xe0); + Cdb[2] = (UINT8) (StartLba >> 24); + Cdb[3] = (UINT8) (StartLba >> 16); + Cdb[4] = (UINT8) (StartLba >> 8); + Cdb[5] = (UINT8) StartLba; + Cdb[7] = (UINT8) (SectorSize >> 8); + Cdb[8] = (UINT8) SectorSize; + + CommandPacket.CdbLength = 10; + CommandPacket.DataDirection = EFI_SCSI_DATA_OUT; + CommandPacket.SenseDataLength = *SenseDataLength; + + Status = ScsiIo->ExecuteSCSICommand (ScsiIo, &CommandPacket, NULL); + + *HostAdapterStatus = CommandPacket.HostAdapterStatus; + *TargetStatus = CommandPacket.TargetStatus; + *SenseDataLength = CommandPacket.SenseDataLength; + *DataLength = CommandPacket.InTransferLength; + + return Status; +} diff --git a/EdkModulePkg/Library/EdkScsiLib/build.xml b/EdkModulePkg/Library/EdkScsiLib/build.xml new file mode 100644 index 0000000000..511cf6fb7c --- /dev/null +++ b/EdkModulePkg/Library/EdkScsiLib/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Library/EdkUefiDebugLibConOut/DebugLib.c b/EdkModulePkg/Library/EdkUefiDebugLibConOut/DebugLib.c new file mode 100644 index 0000000000..911002e96c --- /dev/null +++ b/EdkModulePkg/Library/EdkUefiDebugLibConOut/DebugLib.c @@ -0,0 +1,255 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DebugLib.c + +Abstract: + + UEFI Debug Library that uses PrintLib to send messages to CONOUT + +--*/ + +static BOOLEAN mDebugLevelInstalled = FALSE; +static EFI_DEBUG_LEVEL_PROTOCOL mDebugLevel = { 0 }; + +EFI_STATUS +DebugLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + EFI_STATUS Status; + + // + // Initialize Debug Level Protocol + // + mDebugLevel.DebugLevel = PcdGet32(PcdDebugPrintErrorLevel); + + // + // Install Debug Level Protocol + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gEfiDebugLevelProtocolGuid, &mDebugLevel, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // + // Set flag to show that the Debug Level Protocol has been installed + // + mDebugLevelInstalled = TRUE; + + return EFI_SUCCESS; +} + +VOID +EFIAPI +DebugPrint ( + IN UINTN ErrorLevel, + IN CHAR8 *Format, + ... + ) +/*++ + +Routine Description: + + Wrapper for DebugVPrint () + +Arguments: + + ErrorLevel - If error level is set do the debug print. + + Format - String to use for the print, followed by Print arguments. + + ... - Print arguments. + +Returns: + + None + +--*/ +{ + CHAR16 Buffer[0x100]; + CHAR16 UnicodeBuffer[0x100]; + UINT32 Index; + VA_LIST Marker; + + // + // Check to see if CONOUT is avilable + // + if (gST->ConOut == NULL) { + return; + } + + // + // Check driver Debug Level value and global debug level + // + if (mDebugLevelInstalled) { + if ((ErrorLevel & mDebugLevel.DebugLevel) == 0) { + return; + } + } else { + if ((ErrorLevel & PcdGet32(PcdDebugPrintErrorLevel)) == 0) { + return; + } + } + + // + // BUGBUG: Need print that take CHAR8 Format and returns CHAR16 Buffer + // + for (Index = 0; Format[Index] != 0; Index++) { + UnicodeBuffer[Index] = Format[Index]; + } + UnicodeBuffer[Index] = Format[Index]; + + // + // Convert the DEBUG() message to a Unicode String + // + VA_START (Marker, Format); + UnicodeVSPrint (Buffer, sizeof (Buffer), UnicodeBuffer, Marker); + VA_END (Marker); + + // + // Send the print string to the Standard Error device + // + gST->ConOut->OutputString (gST->ConOut, Buffer); +} + +VOID +EFIAPI +DebugAssert ( + IN CHAR8 *FileName, + IN INTN LineNumber, + IN CHAR8 *Description + ) +/*++ + +Routine Description: + + Worker function for ASSERT(). If Error Logging hub is loaded log ASSERT + information. If Error Logging hub is not loaded CpuBreakpoint (). + + We use UINT64 buffers due to IPF alignment concerns. + +Arguments: + + FileName - File name of failing routine. + + LineNumber - Line number of failing ASSERT(). + + Description - Descritption, usally the assertion, + +Returns: + + None + +--*/ +{ + CHAR16 Buffer[0x100]; + + // + // Check to see if CONOUT is avilable + // + if (gST->ConOut == NULL) { + return; + } + + // + // Generate the ASSERT() message in Unicode format + // + UnicodeSPrint (Buffer, sizeof (Buffer), (CHAR16 *)L"ASSERT %s(%d): %s\n", FileName, LineNumber, Description); + + // + // Send the print string to the Standard Error device + // + gST->ConOut->OutputString (gST->ConOut, Buffer); + + // + // Put break point in module that contained the error. + // + CpuBreakpoint (); +} + +/** + 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 fill with PcdDebugClearMemoryValue. + @param Length Number of bytes in Buffer to fill with zeros PcdDebugClearMemoryValue. + + @return Buffer + +**/ +VOID * +EFIAPI +DebugClearMemory ( + OUT VOID *Buffer, + IN UINTN Length + ) +{ +// SetMem (Buffer, Length, PcdGet8(PcdDebugClearMemoryValue)); + SetMem (Buffer, Length, 0xAF); + return Buffer; +} + +BOOLEAN +EFIAPI +DebugAssertEnabled ( + VOID + ) +{ + return ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED) != 0); +} + +BOOLEAN +EFIAPI +DebugPrintEnabled ( + VOID + ) +{ + return ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_PRINT_ENABLED) != 0); +} + +BOOLEAN +EFIAPI +DebugCodeEnabled ( + VOID + ) +{ + return ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_CODE_ENABLED) != 0); +} + +BOOLEAN +EFIAPI +DebugClearMemoryEnabled ( + VOID + ) +{ + return ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED) != 0); +} diff --git a/EdkModulePkg/Library/EdkUefiDebugLibConOut/EdkUefiDebugLibConOut.mbd b/EdkModulePkg/Library/EdkUefiDebugLibConOut/EdkUefiDebugLibConOut.mbd new file mode 100644 index 0000000000..08bc04d0b0 --- /dev/null +++ b/EdkModulePkg/Library/EdkUefiDebugLibConOut/EdkUefiDebugLibConOut.mbd @@ -0,0 +1,30 @@ + + + + + EdkUefiDebugLibConOut + 7293fe0b-1fff-4f8f-b808-10cb55f6a174 + EDK_RELEASE_VERSION 0x00020000 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-31 13:14 + + diff --git a/EdkModulePkg/Library/EdkUefiDebugLibConOut/EdkUefiDebugLibConOut.msa b/EdkModulePkg/Library/EdkUefiDebugLibConOut/EdkUefiDebugLibConOut.msa new file mode 100644 index 0000000000..874c873cef --- /dev/null +++ b/EdkModulePkg/Library/EdkUefiDebugLibConOut/EdkUefiDebugLibConOut.msa @@ -0,0 +1,69 @@ + + + + + EdkUefiDebugLibConOut + DXE_DRIVER + LIBRARY + 7293fe0b-1fff-4f8f-b808-10cb55f6a174 + EDK_RELEASE_VERSION 0x00020000 + Debug Library for UEFI drivers + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + EFI_SPECIFICATION_VERSION 0x00000000 + 2006-03-12 17:09 + 2006-03-31 13:14 + + + DebugLib + PrintLib + PcdLib + UefiBootServicesTableLib + BaseMemoryLib + BaseLib + + + DebugLib.c + + + MdePkg + EdkModulePkg + + + DebugLevel + + + + DebugLibConstructor + + + + + PcdDebugPropertyMask + 0x00000005 + UINT8 + + + PcdDebugPrintErrorLevel + 0x00000006 + UINT32 + + + diff --git a/EdkModulePkg/Library/EdkUefiDebugLibConOut/build.xml b/EdkModulePkg/Library/EdkUefiDebugLibConOut/build.xml new file mode 100644 index 0000000000..4a7cb25121 --- /dev/null +++ b/EdkModulePkg/Library/EdkUefiDebugLibConOut/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Library/EdkUefiDebugLibStdErr/DebugLib.c b/EdkModulePkg/Library/EdkUefiDebugLibStdErr/DebugLib.c new file mode 100644 index 0000000000..1074d6a2ce --- /dev/null +++ b/EdkModulePkg/Library/EdkUefiDebugLibStdErr/DebugLib.c @@ -0,0 +1,255 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DebugLib.c + +Abstract: + + UEFI Debug Library that uses PrintLib to send messages to STDERR + +--*/ + +static BOOLEAN mDebugLevelInstalled = FALSE; +static EFI_DEBUG_LEVEL_PROTOCOL mDebugLevel = { 0 }; + +EFI_STATUS +DebugLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + EFI_STATUS Status; + + // + // Initialize Debug Level Protocol + // + mDebugLevel.DebugLevel = PcdGet32(PcdDebugPrintErrorLevel); + + // + // Install Debug Level Protocol + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gEfiDebugLevelProtocolGuid, &mDebugLevel, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // + // Set flag to show that the Debug Level Protocol has been installed + // + mDebugLevelInstalled = TRUE; + + return EFI_SUCCESS; +} + +VOID +EFIAPI +DebugPrint ( + IN UINTN ErrorLevel, + IN CHAR8 *Format, + ... + ) +/*++ + +Routine Description: + + Wrapper for DebugVPrint () + +Arguments: + + ErrorLevel - If error level is set do the debug print. + + Format - String to use for the print, followed by Print arguments. + + ... - Print arguments. + +Returns: + + None + +--*/ +{ + CHAR16 Buffer[0x100]; + CHAR16 UnicodeBuffer[0x100]; + UINT32 Index; + VA_LIST Marker; + + // + // Check to see if STDERR is avilable + // + if (gST->StdErr == NULL) { + return; + } + + // + // Check driver Debug Level value and global debug level + // + if (mDebugLevelInstalled) { + if ((ErrorLevel & mDebugLevel.DebugLevel) == 0) { + return; + } + } else { + if ((ErrorLevel & PcdGet32(PcdDebugPrintErrorLevel)) == 0) { + return; + } + } + + // + // BUGBUG: Need print that take CHAR8 Format and returns CHAR16 Buffer + // + for (Index = 0; Format[Index] != 0; Index++) { + UnicodeBuffer[Index] = Format[Index]; + } + UnicodeBuffer[Index] = Format[Index]; + + // + // Convert the DEBUG() message to a Unicode String + // + VA_START (Marker, Format); + UnicodeVSPrint (Buffer, sizeof (Buffer), UnicodeBuffer, Marker); + VA_END (Marker); + + // + // Send the print string to the Standard Error device + // + gST->StdErr->OutputString (gST->StdErr, Buffer); +} + +VOID +EFIAPI +DebugAssert ( + IN CHAR8 *FileName, + IN INTN LineNumber, + IN CHAR8 *Description + ) +/*++ + +Routine Description: + + Worker function for ASSERT(). If Error Logging hub is loaded log ASSERT + information. If Error Logging hub is not loaded CpuBreakpoint (). + + We use UINT64 buffers due to IPF alignment concerns. + +Arguments: + + FileName - File name of failing routine. + + LineNumber - Line number of failing ASSERT(). + + Description - Descritption, usally the assertion, + +Returns: + + None + +--*/ +{ + CHAR16 Buffer[0x100]; + + // + // Check to see if STDERR is avilable + // + if (gST->StdErr == NULL) { + return; + } + + // + // Generate the ASSERT() message in Unicode format + // + UnicodeSPrint (Buffer, sizeof (Buffer), (CHAR16 *)L"ASSERT %s(%d): %s\n", FileName, LineNumber, Description); + + // + // Send the print string to the Standard Error device + // + gST->StdErr->OutputString (gST->StdErr, Buffer); + + // + // Put break point in module that contained the error. + // + CpuBreakpoint (); +} + +/** + 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 fill with PcdDebugClearMemoryValue. + @param Length Number of bytes in Buffer to fill with zeros PcdDebugClearMemoryValue. + + @return Buffer + +**/ +VOID * +EFIAPI +DebugClearMemory ( + OUT VOID *Buffer, + IN UINTN Length + ) +{ +// SetMem (Buffer, Length, PcdGet8(PcdDebugClearMemoryValue)); + SetMem (Buffer, Length, 0xAF); + return Buffer; +} + +BOOLEAN +EFIAPI +DebugAssertEnabled ( + VOID + ) +{ + return ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED) != 0); +} + +BOOLEAN +EFIAPI +DebugPrintEnabled ( + VOID + ) +{ + return ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_PRINT_ENABLED) != 0); +} + +BOOLEAN +EFIAPI +DebugCodeEnabled ( + VOID + ) +{ + return ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_CODE_ENABLED) != 0); +} + +BOOLEAN +EFIAPI +DebugClearMemoryEnabled ( + VOID + ) +{ + return ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED) != 0); +} diff --git a/EdkModulePkg/Library/EdkUefiDebugLibStdErr/EdkUefiDebugLibStdErr.mbd b/EdkModulePkg/Library/EdkUefiDebugLibStdErr/EdkUefiDebugLibStdErr.mbd new file mode 100644 index 0000000000..833b2eea09 --- /dev/null +++ b/EdkModulePkg/Library/EdkUefiDebugLibStdErr/EdkUefiDebugLibStdErr.mbd @@ -0,0 +1,30 @@ + + + + + EdkUefiDebugLibStdErr + 8b9968e0-c76b-4b57-aec4-24e17fe602c0 + EDK_RELEASE_VERSION 0x00020000 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-31 13:14 + + diff --git a/EdkModulePkg/Library/EdkUefiDebugLibStdErr/EdkUefiDebugLibStdErr.msa b/EdkModulePkg/Library/EdkUefiDebugLibStdErr/EdkUefiDebugLibStdErr.msa new file mode 100644 index 0000000000..3c5fc2b901 --- /dev/null +++ b/EdkModulePkg/Library/EdkUefiDebugLibStdErr/EdkUefiDebugLibStdErr.msa @@ -0,0 +1,69 @@ + + + + + EdkUefiDebugLibStdErr + DXE_DRIVER + LIBRARY + 8b9968e0-c76b-4b57-aec4-24e17fe602c0 + EDK_RELEASE_VERSION 0x00020000 + Debug Library for UEFI drivers + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + EFI_SPECIFICATION_VERSION 0x00000000 + 2006-03-12 17:09 + 2006-03-31 13:14 + + + DebugLib + PrintLib + PcdLib + UefiBootServicesTableLib + BaseMemoryLib + BaseLib + + + DebugLib.c + + + MdePkg + EdkModulePkg + + + DebugLevel + + + + DebugLibConstructor + + + + + PcdDebugPropertyMask + 0x00000005 + UINT8 + + + PcdDebugPrintErrorLevel + 0x00000006 + UINT32 + + + diff --git a/EdkModulePkg/Library/EdkUefiDebugLibStdErr/build.xml b/EdkModulePkg/Library/EdkUefiDebugLibStdErr/build.xml new file mode 100644 index 0000000000..1479581406 --- /dev/null +++ b/EdkModulePkg/Library/EdkUefiDebugLibStdErr/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Library/EdkUsbLib/EdkUsbLib.mbd b/EdkModulePkg/Library/EdkUsbLib/EdkUsbLib.mbd new file mode 100644 index 0000000000..79fa4b10fc --- /dev/null +++ b/EdkModulePkg/Library/EdkUsbLib/EdkUsbLib.mbd @@ -0,0 +1,30 @@ + + + + + EdkUsbLib + 87eb5df9-722a-4241-ad7f-370d0b3a56d7 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + diff --git a/EdkModulePkg/Library/EdkUsbLib/EdkUsbLib.msa b/EdkModulePkg/Library/EdkUsbLib/EdkUsbLib.msa new file mode 100644 index 0000000000..f2aa74b28f --- /dev/null +++ b/EdkModulePkg/Library/EdkUsbLib/EdkUsbLib.msa @@ -0,0 +1,46 @@ + + + + + EdkUsbLib + DXE_DRIVER + LIBRARY + 87eb5df9-722a-4241-ad7f-370d0b3a56d7 + 0 + Component description file for UsbDxeLib module + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + EdkUsbLib + BaseMemoryLib + + + UsbDxelib.c + hid.c + + + MdePkg + EdkModulePkg + + diff --git a/EdkModulePkg/Library/EdkUsbLib/UsbDxeLib.c b/EdkModulePkg/Library/EdkUsbLib/UsbDxeLib.c new file mode 100644 index 0000000000..8bbd0893ae --- /dev/null +++ b/EdkModulePkg/Library/EdkUsbLib/UsbDxeLib.c @@ -0,0 +1,699 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + Module Name: + + UsbDxeLib.c + + Abstract: + + Common Dxe Libarary for USB + + Revision History + +--*/ + +// +// Get Device Descriptor +// +EFI_STATUS +UsbGetDescriptor ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT16 Value, + IN UINT16 Index, + IN UINT16 DescriptorLength, + OUT VOID *Descriptor, + OUT UINT32 *Status + ) +/*++ + +Routine Description: + + Usb Get Descriptor + +Arguments: + + UsbIo - EFI_USB_IO_PROTOCOL + Value - Device Request Value + Index - Device Request Index + DescriptorLength - Descriptor Length + Descriptor - Descriptor buffer to contain result + Status - Transfer Status +Returns: + EFI_INVALID_PARAMETER - Parameter is error + EFI_SUCCESS - Success + EFI_TIMEOUT - Device has no response + +--*/ +{ + EFI_USB_DEVICE_REQUEST DevReq; + + if (UsbIo == NULL) { + return EFI_INVALID_PARAMETER; + } + + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); + + DevReq.RequestType = USB_DEV_GET_DESCRIPTOR_REQ_TYPE; + DevReq.Request = USB_DEV_GET_DESCRIPTOR; + DevReq.Value = Value; + DevReq.Index = Index; + DevReq.Length = DescriptorLength; + + return UsbIo->UsbControlTransfer ( + UsbIo, + &DevReq, + EfiUsbDataIn, + TIMEOUT_VALUE, + Descriptor, + DescriptorLength, + Status + ); +} +// +// Set Device Descriptor +// +EFI_STATUS +UsbSetDescriptor ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT16 Value, + IN UINT16 Index, + IN UINT16 DescriptorLength, + IN VOID *Descriptor, + OUT UINT32 *Status + ) +/*++ + +Routine Description: + + Usb Set Descriptor + +Arguments: + + UsbIo - EFI_USB_IO_PROTOCOL + Value - Device Request Value + Index - Device Request Index + DescriptorLength - Descriptor Length + Descriptor - Descriptor buffer to set + Status - Transfer Status +Returns: + EFI_INVALID_PARAMETER - Parameter is error + EFI_SUCCESS - Success + EFI_TIMEOUT - Device has no response + +--*/ +{ + EFI_USB_DEVICE_REQUEST DevReq; + + if (UsbIo == NULL) { + return EFI_INVALID_PARAMETER; + } + + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); + + DevReq.RequestType = USB_DEV_SET_DESCRIPTOR_REQ_TYPE; + DevReq.Request = USB_DEV_SET_DESCRIPTOR; + DevReq.Value = Value; + DevReq.Index = Index; + DevReq.Length = DescriptorLength; + + return UsbIo->UsbControlTransfer ( + UsbIo, + &DevReq, + EfiUsbDataOut, + TIMEOUT_VALUE, + Descriptor, + DescriptorLength, + Status + ); +} + +// +// Get device Interface +// +EFI_STATUS +UsbGetDeviceInterface ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT16 Index, + OUT UINT8 *AltSetting, + OUT UINT32 *Status + ) +/*++ + +Routine Description: + + Usb Get Device Interface + +Arguments: + + UsbIo - EFI_USB_IO_PROTOCOL + Index - Interface index value + AltSetting - Alternate setting + Status - Trasnsfer status + +Returns: + + EFI_INVALID_PARAMETER - Parameter is error + EFI_SUCCESS - Success + EFI_TIMEOUT - Device has no response + + +--*/ +{ + EFI_USB_DEVICE_REQUEST DevReq; + + if (UsbIo == NULL) { + return EFI_INVALID_PARAMETER; + } + + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); + + DevReq.RequestType = USB_DEV_GET_INTERFACE_REQ_TYPE; + DevReq.Request = USB_DEV_GET_INTERFACE; + DevReq.Index = Index; + DevReq.Length = 1; + + return UsbIo->UsbControlTransfer ( + UsbIo, + &DevReq, + EfiUsbDataIn, + TIMEOUT_VALUE, + AltSetting, + 1, + Status + ); +} +// +// Set device interface +// +EFI_STATUS +UsbSetDeviceInterface ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT16 InterfaceNo, + IN UINT16 AltSetting, + OUT UINT32 *Status + ) +/*++ + +Routine Description: + + Usb Set Device Interface + +Arguments: + + UsbIo - EFI_USB_IO_PROTOCOL + InterfaceNo - Interface Number + AltSetting - Alternate setting + Status - Trasnsfer status + +Returns: + + EFI_INVALID_PARAMETER - Parameter is error + EFI_SUCCESS - Success + EFI_TIMEOUT - Device has no response + +--*/ +{ + EFI_USB_DEVICE_REQUEST DevReq; + + if (UsbIo == NULL) { + return EFI_INVALID_PARAMETER; + } + + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); + + DevReq.RequestType = USB_DEV_SET_INTERFACE_REQ_TYPE; + DevReq.Request = USB_DEV_SET_INTERFACE; + DevReq.Value = AltSetting; + DevReq.Index = InterfaceNo; + + + return UsbIo->UsbControlTransfer ( + UsbIo, + &DevReq, + EfiUsbNoData, + TIMEOUT_VALUE, + NULL, + 0, + Status + ); +} +// +// Get device configuration +// +EFI_STATUS +UsbGetDeviceConfiguration ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + OUT UINT8 *ConfigValue, + OUT UINT32 *Status + ) +/*++ + +Routine Description: + + Usb Get Device Configuration + +Arguments: + + UsbIo - EFI_USB_IO_PROTOCOL + ConfigValue - Config Value + Status - Transfer Status + +Returns: + + EFI_INVALID_PARAMETER - Parameter is error + EFI_SUCCESS - Success + EFI_TIMEOUT - Device has no response + +--*/ +{ + EFI_USB_DEVICE_REQUEST DevReq; + + if (UsbIo == NULL) { + return EFI_INVALID_PARAMETER; + } + + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); + + DevReq.RequestType = USB_DEV_GET_CONFIGURATION_REQ_TYPE; + DevReq.Request = USB_DEV_GET_CONFIGURATION; + DevReq.Length = 1; + + return UsbIo->UsbControlTransfer ( + UsbIo, + &DevReq, + EfiUsbDataIn, + TIMEOUT_VALUE, + ConfigValue, + 1, + Status + ); +} +// +// Set device configuration +// +EFI_STATUS +UsbSetDeviceConfiguration ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT16 Value, + OUT UINT32 *Status + ) +/*++ + +Routine Description: + + Usb Set Device Configuration + +Arguments: + + UsbIo - EFI_USB_IO_PROTOCOL + Value - Configuration Value to set + Status - Transfer status + +Returns: + + EFI_INVALID_PARAMETER - Parameter is error + EFI_SUCCESS - Success + EFI_TIMEOUT - Device has no response + +--*/ +{ + EFI_USB_DEVICE_REQUEST DevReq; + + if (UsbIo == NULL) { + return EFI_INVALID_PARAMETER; + } + + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); + + DevReq.RequestType = USB_DEV_SET_CONFIGURATION_REQ_TYPE; + DevReq.Request = USB_DEV_SET_CONFIGURATION; + DevReq.Value = Value; + + return UsbIo->UsbControlTransfer ( + UsbIo, + &DevReq, + EfiUsbNoData, + TIMEOUT_VALUE, + NULL, + 0, + Status + ); +} +// +// Set Device Feature +// +EFI_STATUS +UsbSetDeviceFeature ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN EFI_USB_RECIPIENT Recipient, + IN UINT16 Value, + IN UINT16 Target, + OUT UINT32 *Status + ) +/*++ + +Routine Description: + + Usb Set Device Feature + +Arguments: + + UsbIo - EFI_USB_IO_PROTOCOL + Recipient - Interface/Device/Endpoint + Value - Request value + Target - Request Index + Status - Transfer status + +Returns: + + EFI_INVALID_PARAMETER - Parameter is error + EFI_SUCCESS - Success + EFI_TIMEOUT - Device has no response + +--*/ +{ + EFI_USB_DEVICE_REQUEST DevReq; + + if (UsbIo == NULL) { + return EFI_INVALID_PARAMETER; + } + + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); + + switch (Recipient) { + + case EfiUsbDevice: + DevReq.RequestType = 0x00; + break; + + case EfiUsbInterface: + DevReq.RequestType = 0x01; + break; + + case EfiUsbEndpoint: + DevReq.RequestType = 0x02; + break; + } + // + // Fill device request, see USB1.1 spec + // + DevReq.Request = USB_DEV_SET_FEATURE; + DevReq.Value = Value; + DevReq.Index = Target; + + + return UsbIo->UsbControlTransfer ( + UsbIo, + &DevReq, + EfiUsbNoData, + TIMEOUT_VALUE, + NULL, + 0, + Status + ); +} +// +// Clear Device Feature +// +EFI_STATUS +UsbClearDeviceFeature ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN EFI_USB_RECIPIENT Recipient, + IN UINT16 Value, + IN UINT16 Target, + OUT UINT32 *Status + ) +/*++ + +Routine Description: + + Usb Clear Device Feature + +Arguments: + + UsbIo - EFI_USB_IO_PROTOCOL + Recipient - Interface/Device/Endpoint + Value - Request value + Target - Request Index + Status - Transfer status + +Returns: + + EFI_INVALID_PARAMETER - Parameter is error + EFI_SUCCESS - Success + EFI_TIMEOUT - Device has no response + +--*/ +{ + EFI_USB_DEVICE_REQUEST DevReq; + + if (UsbIo == NULL) { + return EFI_INVALID_PARAMETER; + } + + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); + + switch (Recipient) { + + case EfiUsbDevice: + DevReq.RequestType = 0x00; + break; + + case EfiUsbInterface: + DevReq.RequestType = 0x01; + break; + + case EfiUsbEndpoint: + DevReq.RequestType = 0x02; + break; + } + // + // Fill device request, see USB1.1 spec + // + DevReq.Request = USB_DEV_CLEAR_FEATURE; + DevReq.Value = Value; + DevReq.Index = Target; + + + return UsbIo->UsbControlTransfer ( + UsbIo, + &DevReq, + EfiUsbNoData, + TIMEOUT_VALUE, + NULL, + 0, + Status + ); +} +// +// Get Device Status +// +EFI_STATUS +UsbGetDeviceStatus ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN EFI_USB_RECIPIENT Recipient, + IN UINT16 Target, + OUT UINT16 *DevStatus, + OUT UINT32 *Status + ) +/*++ + +Routine Description: + + Usb Get Device Status + +Arguments: + + UsbIo - EFI_USB_IO_PROTOCOL + Recipient - Interface/Device/Endpoint + Target - Request index + DevStatus - Device status + Status - Transfer status + +Returns: + + EFI_INVALID_PARAMETER - Parameter is error + EFI_SUCCESS - Success + EFI_TIMEOUT - Device has no response + +--*/ +{ + EFI_USB_DEVICE_REQUEST DevReq; + + if (UsbIo == NULL) { + return EFI_INVALID_PARAMETER; + } + + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); + + switch (Recipient) { + + case EfiUsbDevice: + DevReq.RequestType = 0x80; + break; + + case EfiUsbInterface: + DevReq.RequestType = 0x81; + break; + + case EfiUsbEndpoint: + DevReq.RequestType = 0x82; + break; + } + // + // Fill device request, see USB1.1 spec + // + DevReq.Request = USB_DEV_GET_STATUS; + DevReq.Value = 0; + DevReq.Index = Target; + DevReq.Length = 2; + + return UsbIo->UsbControlTransfer ( + UsbIo, + &DevReq, + EfiUsbDataIn, + TIMEOUT_VALUE, + DevStatus, + 2, + Status + ); +} +// +// Usb Get String +// +EFI_STATUS +UsbGetString ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT16 LangID, + IN UINT8 Index, + IN VOID *Buf, + IN UINTN BufSize, + OUT UINT32 *Status + ) +/*++ + +Routine Description: + + Usb Get String + +Arguments: + + UsbIo - EFI_USB_IO_PROTOCOL + LangID - Language ID + Index - Request index + Buf - Buffer to store string + BufSize - Buffer size + Status - Transfer status + +Returns: + + EFI_INVALID_PARAMETER - Parameter is error + EFI_SUCCESS - Success + EFI_TIMEOUT - Device has no response + +--*/ +{ + UINT16 Value; + + if (UsbIo == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Fill value, see USB1.1 spec + // + Value = (UINT16) ((USB_DT_STRING << 8) | Index); + + return UsbGetDescriptor ( + UsbIo, + Value, + LangID, + (UINT16) BufSize, + Buf, + Status + ); +} + +EFI_STATUS +UsbClearEndpointHalt ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 EndpointNo, + OUT UINT32 *Status + ) +/*++ + +Routine Description: + + Clear endpoint stall + +Arguments: + + UsbIo - EFI_USB_IO_PROTOCOL + EndpointNo - Endpoint Number + Status - Transfer Status + +Returns: + + EFI_NOT_FOUND - Can't find the Endpoint + EFI_DEVICE_ERROR - Hardware error + EFI_SUCCESS - Success + +--*/ +{ + EFI_STATUS Result; + EFI_USB_ENDPOINT_DESCRIPTOR EndpointDescriptor; + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + UINT8 Index; + + ZeroMem (&EndpointDescriptor, sizeof (EFI_USB_ENDPOINT_DESCRIPTOR)); + // + // First seach the endpoint descriptor for that endpoint addr + // + Result = UsbIo->UsbGetInterfaceDescriptor ( + UsbIo, + &InterfaceDescriptor + ); + if (EFI_ERROR (Result)) { + return Result; + } + + for (Index = 0; Index < InterfaceDescriptor.NumEndpoints; Index++) { + Result = UsbIo->UsbGetEndpointDescriptor ( + UsbIo, + Index, + &EndpointDescriptor + ); + if (EFI_ERROR (Result)) { + continue; + } + + if (EndpointDescriptor.EndpointAddress == EndpointNo) { + break; + } + } + + if (Index == InterfaceDescriptor.NumEndpoints) { + // + // No such endpoint + // + return EFI_NOT_FOUND; + } + + Result = UsbClearDeviceFeature ( + UsbIo, + EfiUsbEndpoint, + EfiUsbEndpointHalt, + EndpointDescriptor.EndpointAddress, + Status + ); + + return Result; +} diff --git a/EdkModulePkg/Library/EdkUsbLib/build.xml b/EdkModulePkg/Library/EdkUsbLib/build.xml new file mode 100644 index 0000000000..0b9eaade6b --- /dev/null +++ b/EdkModulePkg/Library/EdkUsbLib/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Library/EdkUsbLib/hid.c b/EdkModulePkg/Library/EdkUsbLib/hid.c new file mode 100644 index 0000000000..edf9a94efc --- /dev/null +++ b/EdkModulePkg/Library/EdkUsbLib/hid.c @@ -0,0 +1,459 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + Module Name: + + hid.c + + Abstract: + + HID class request + + Revision History + +--*/ + +// +// Function to get HID descriptor +// +EFI_STATUS +UsbGetHidDescriptor ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 InterfaceNum, + OUT EFI_USB_HID_DESCRIPTOR *HidDescriptor + ) +/*++ + + Routine Description: + Get Hid Descriptor + + Arguments: + UsbIo - EFI_USB_IO_PROTOCOL + InterfaceNum - Hid interface number + HidDescriptor - Caller allocated buffer to store Usb hid descriptor + if successfully returned. + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + EFI_TIMEOUT + +--*/ +{ + UINT32 Status; + EFI_STATUS Result; + EFI_USB_DEVICE_REQUEST Request; + + Request.RequestType = 0x81; + Request.Request = 0x06; + Request.Value = (UINT16) (0x21 << 8); + Request.Index = InterfaceNum; + Request.Length = sizeof (EFI_USB_HID_DESCRIPTOR); + + Result = UsbIo->UsbControlTransfer ( + UsbIo, + &Request, + EfiUsbDataIn, + TIMEOUT_VALUE, + HidDescriptor, + sizeof (EFI_USB_HID_DESCRIPTOR), + &Status + ); + + return Result; + +} +// +// Function to get Report Class descriptor +// +EFI_STATUS +UsbGetReportDescriptor ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 InterfaceNum, + IN UINT16 DescriptorSize, + OUT UINT8 *DescriptorBuffer + ) +/*++ + + Routine Description: + get Report Class descriptor + + Arguments: + UsbIo - EFI_USB_IO_PROTOCOL. + InterfaceNum - Report interface number. + DescriptorSize - Length of DescriptorBuffer. + DescriptorBuffer - Caller allocated buffer to store Usb report descriptor + if successfully returned. + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + EFI_TIMEOUT + +--*/ +{ + UINT32 Status; + EFI_STATUS Result; + EFI_USB_DEVICE_REQUEST Request; + + // + // Fill Device request packet + // + Request.RequestType = 0x81; + Request.Request = 0x06; + Request.Value = (UINT16) (0x22 << 8); + Request.Index = InterfaceNum; + Request.Length = DescriptorSize; + + Result = UsbIo->UsbControlTransfer ( + UsbIo, + &Request, + EfiUsbDataIn, + TIMEOUT_VALUE, + DescriptorBuffer, + DescriptorSize, + &Status + ); + + return Result; + +} +// +// Following are HID class request +// +EFI_STATUS +UsbGetProtocolRequest ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 Interface, + IN UINT8 *Protocol + ) +/*++ + + Routine Description: + Get Hid Protocol Request + + Arguments: + UsbIo - EFI_USB_IO_PROTOCOL + Interface - Which interface the caller wants to get protocol + Protocol - Protocol value returned. + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + EFI_TIMEOUT + +--*/ +{ + UINT32 Status; + EFI_STATUS Result; + EFI_USB_DEVICE_REQUEST Request; + + // + // Fill Device request packet + // + Request.RequestType = 0xa1; + // + // 10100001b; + // + Request.Request = EFI_USB_GET_PROTOCOL_REQUEST; + Request.Value = 0; + Request.Index = Interface; + Request.Length = 1; + + Result = UsbIo->UsbControlTransfer ( + UsbIo, + &Request, + EfiUsbDataIn, + TIMEOUT_VALUE, + Protocol, + sizeof (UINT8), + &Status + ); + + return Result; +} + + +EFI_STATUS +UsbSetProtocolRequest ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 Interface, + IN UINT8 Protocol + ) +/*++ + + Routine Description: + Set Hid Protocol Request + + Arguments: + UsbIo - EFI_USB_IO_PROTOCOL + Interface - Which interface the caller wants to set protocol + Protocol - Protocol value the caller wants to set. + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + EFI_TIMEOUT + +--*/ +{ + UINT32 Status; + EFI_STATUS Result; + EFI_USB_DEVICE_REQUEST Request; + + // + // Fill Device request packet + // + Request.RequestType = 0x21; + // + // 00100001b; + // + Request.Request = EFI_USB_SET_PROTOCOL_REQUEST; + Request.Value = Protocol; + Request.Index = Interface; + Request.Length = 0; + + Result = UsbIo->UsbControlTransfer ( + UsbIo, + &Request, + EfiUsbNoData, + TIMEOUT_VALUE, + NULL, + 0, + &Status + ); + return Result; +} + + +EFI_STATUS +UsbSetIdleRequest ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 Interface, + IN UINT8 ReportId, + IN UINT8 Duration + ) +/*++ + + Routine Description: + Set Idel request. + + Arguments: + UsbIo - EFI_USB_IO_PROTOCOL + Interface - Which interface the caller wants to set. + ReportId - Which report the caller wants to set. + Duration - Idle rate the caller wants to set. + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + EFI_TIMEOUT + +--*/ +{ + UINT32 Status; + EFI_STATUS Result; + EFI_USB_DEVICE_REQUEST Request; + + // + // Fill Device request packet + // + Request.RequestType = 0x21; + // + // 00100001b; + // + Request.Request = EFI_USB_SET_IDLE_REQUEST; + Request.Value = (UINT16) ((Duration << 8) | ReportId); + Request.Index = Interface; + Request.Length = 0; + + Result = UsbIo->UsbControlTransfer ( + UsbIo, + &Request, + EfiUsbNoData, + TIMEOUT_VALUE, + NULL, + 0, + &Status + ); + return Result; +} + +EFI_STATUS +UsbGetIdleRequest ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 Interface, + IN UINT8 ReportId, + OUT UINT8 *Duration + ) +/*++ + + Routine Description: + Get Idel request. + + Arguments: + UsbIo - EFI_USB_IO_PROTOCOL + Interface - Which interface the caller wants to get. + ReportId - Which report the caller wants to get. + Duration - Idle rate the caller wants to get. + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + EFI_TIMEOUT + +--*/ +{ + UINT32 Status; + EFI_STATUS Result; + EFI_USB_DEVICE_REQUEST Request; + + // + // Fill Device request packet + // + Request.RequestType = 0xa1; + // + // 10100001b; + // + Request.Request = EFI_USB_GET_IDLE_REQUEST; + Request.Value = ReportId; + Request.Index = Interface; + Request.Length = 1; + + Result = UsbIo->UsbControlTransfer ( + UsbIo, + &Request, + EfiUsbDataIn, + TIMEOUT_VALUE, + Duration, + 1, + &Status + ); + + return Result; +} + + +EFI_STATUS +UsbSetReportRequest ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 Interface, + IN UINT8 ReportId, + IN UINT8 ReportType, + IN UINT16 ReportLen, + IN UINT8 *Report + ) +/*++ + + Routine Description: + Hid Set Report request. + + Arguments: + UsbIo - EFI_USB_IO_PROTOCOL + Interface - Which interface the caller wants to set. + ReportId - Which report the caller wants to set. + ReportType - Type of report. + ReportLen - Length of report descriptor. + Report - Report Descriptor buffer. + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + EFI_TIMEOUT + +--*/ +{ + UINT32 Status; + EFI_STATUS Result; + EFI_USB_DEVICE_REQUEST Request; + + // + // Fill Device request packet + // + Request.RequestType = 0x21; + // + // 00100001b; + // + Request.Request = EFI_USB_SET_REPORT_REQUEST; + Request.Value = (UINT16) ((ReportType << 8) | ReportId); + Request.Index = Interface; + Request.Length = ReportLen; + + Result = UsbIo->UsbControlTransfer ( + UsbIo, + &Request, + EfiUsbDataOut, + TIMEOUT_VALUE, + Report, + ReportLen, + &Status + ); + + return Result; +} + +EFI_STATUS +UsbGetReportRequest ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 Interface, + IN UINT8 ReportId, + IN UINT8 ReportType, + IN UINT16 ReportLen, + IN UINT8 *Report + ) +/*++ + + Routine Description: + Hid Set Report request. + + Arguments: + UsbIo - EFI_USB_IO_PROTOCOL + Interface - Which interface the caller wants to set. + ReportId - Which report the caller wants to set. + ReportType - Type of report. + ReportLen - Length of report descriptor. + Report - Caller allocated buffer to store Report Descriptor. + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + EFI_TIMEOUT + +--*/ +{ + UINT32 Status; + EFI_STATUS Result; + EFI_USB_DEVICE_REQUEST Request; + + // + // Fill Device request packet + // + Request.RequestType = 0xa1; + // + // 10100001b; + // + Request.Request = EFI_USB_GET_REPORT_REQUEST; + Request.Value = (UINT16) ((ReportType << 8) | ReportId); + Request.Index = Interface; + Request.Length = ReportLen; + + Result = UsbIo->UsbControlTransfer ( + UsbIo, + &Request, + EfiUsbDataIn, + TIMEOUT_VALUE, + Report, + ReportLen, + &Status + ); + + return Result; +} diff --git a/EdkModulePkg/Universal/Console/ConSplitter/Dxe/ComponentName.c b/EdkModulePkg/Universal/Console/ConSplitter/Dxe/ComponentName.c new file mode 100644 index 0000000000..dc2a22f447 --- /dev/null +++ b/EdkModulePkg/Universal/Console/ConSplitter/Dxe/ComponentName.c @@ -0,0 +1,531 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ComponentName.c + +Abstract: + +--*/ + +#include "ConSplitter.h" + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +ConSplitterComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +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 +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 +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 +EFIAPI +ConSplitterStdErrComponentNameGetControllerName ( + 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 +// +EFI_COMPONENT_NAME_PROTOCOL gConSplitterConInComponentName = { + ConSplitterComponentNameGetDriverName, + ConSplitterConInComponentNameGetControllerName, + "eng" +}; + +EFI_COMPONENT_NAME_PROTOCOL gConSplitterSimplePointerComponentName = { + ConSplitterComponentNameGetDriverName, + ConSplitterSimplePointerComponentNameGetControllerName, + "eng" +}; + +EFI_COMPONENT_NAME_PROTOCOL gConSplitterConOutComponentName = { + ConSplitterComponentNameGetDriverName, + ConSplitterConOutComponentNameGetControllerName, + "eng" +}; + +EFI_COMPONENT_NAME_PROTOCOL gConSplitterStdErrComponentName = { + ConSplitterComponentNameGetDriverName, + ConSplitterStdErrComponentNameGetControllerName, + "eng" +}; + +static EFI_UNICODE_STRING_TABLE mConSplitterDriverNameTable[] = { + { + "eng", + (CHAR16 *) L"Console Splitter Driver" + }, + { + NULL, + NULL + } +}; + +static EFI_UNICODE_STRING_TABLE mConSplitterConInControllerNameTable[] = { + { + "eng", + (CHAR16 *) L"Primary Console Input Device" + }, + { + NULL, + NULL + } +}; + +static EFI_UNICODE_STRING_TABLE mConSplitterSimplePointerControllerNameTable[] = { + { + "eng", + (CHAR16 *) L"Primary Simple Pointer Device" + }, + { + NULL, + NULL + } +}; + +static EFI_UNICODE_STRING_TABLE mConSplitterConOutControllerNameTable[] = { + { + "eng", + (CHAR16 *) L"Primary Console Output Device" + }, + { + NULL, + NULL + } +}; + +static EFI_UNICODE_STRING_TABLE mConSplitterStdErrControllerNameTable[] = { + { + "eng", + (CHAR16 *) L"Primary Standard Error Device" + }, + { + NULL, + NULL + } +}; + +EFI_STATUS +EFIAPI +ConSplitterComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gConSplitterConInComponentName.SupportedLanguages, + mConSplitterDriverNameTable, + DriverName + ); +} + +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 + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + 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. + 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. + + Returns: + 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. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + EFI_STATUS Status; + EFI_SIMPLE_TEXT_IN_PROTOCOL *TextIn; + // + // here ChildHandle is not an Optional parameter. + // + if (ChildHandle == NULL) { + return EFI_UNSUPPORTED; + } + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiSimpleTextInProtocolGuid, + (VOID **) &TextIn, + NULL, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + return LookupUnicodeString ( + Language, + gConSplitterConInComponentName.SupportedLanguages, + mConSplitterConInControllerNameTable, + ControllerName + ); +} + +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 + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + 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. + 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. + + Returns: + 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. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + EFI_STATUS Status; + EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer; + // + // here ChildHandle is not an Optional parameter. + // + if (ChildHandle == NULL) { + return EFI_UNSUPPORTED; + } + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiSimplePointerProtocolGuid, + (VOID **) &SimplePointer, + NULL, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + return LookupUnicodeString ( + Language, + gConSplitterSimplePointerComponentName.SupportedLanguages, + mConSplitterSimplePointerControllerNameTable, + ControllerName + ); +} + +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 + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + 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. + 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. + + Returns: + 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. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + EFI_STATUS Status; + EFI_SIMPLE_TEXT_OUT_PROTOCOL *TextOut; + // + // here ChildHandle is not an Optional parameter. + // + if (ChildHandle == NULL) { + return EFI_UNSUPPORTED; + } + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiSimpleTextOutProtocolGuid, + (VOID **) &TextOut, + NULL, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + return LookupUnicodeString ( + Language, + gConSplitterConOutComponentName.SupportedLanguages, + mConSplitterConOutControllerNameTable, + ControllerName + ); +} + +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 + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + 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. + 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. + + Returns: + 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. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + EFI_STATUS Status; + EFI_SIMPLE_TEXT_OUT_PROTOCOL *ErrOut; + // + // here ChildHandle is not an Optional parameter. + // + if (ChildHandle == NULL) { + return EFI_UNSUPPORTED; + } + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiSimpleTextOutProtocolGuid, + (VOID **) &ErrOut, + NULL, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + return LookupUnicodeString ( + Language, + gConSplitterStdErrComponentName.SupportedLanguages, + mConSplitterStdErrControllerNameTable, + ControllerName + ); +} diff --git a/EdkModulePkg/Universal/Console/ConSplitter/Dxe/ConSplitter.c b/EdkModulePkg/Universal/Console/ConSplitter/Dxe/ConSplitter.c new file mode 100644 index 0000000000..a9d39e945e --- /dev/null +++ b/EdkModulePkg/Universal/Console/ConSplitter/Dxe/ConSplitter.c @@ -0,0 +1,3193 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ConSplitter.c + +Abstract: + + Console Splitter Driver. Any Handle that attatched + EFI_CONSOLE_IDENTIFIER_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. + EFI_CONSOLE_SPLIT_PROTOCOL will be attatched onto each virtual handle to + identify the splitter type. + + Each virtual handle, that supports both the EFI_CONSOLE_SPLIT_PROTOCOL + and 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. + +--*/ + +#include "ConSplitter.h" + +// +// Global Variables +// +static TEXT_IN_SPLITTER_PRIVATE_DATA mConIn = { + TEXT_IN_SPLITTER_PRIVATE_DATA_SIGNATURE, + (EFI_HANDLE) NULL, + { + ConSplitterTextInReset, + ConSplitterTextInReadKeyStroke, + (EFI_EVENT) NULL + }, + 0, + (EFI_SIMPLE_TEXT_IN_PROTOCOL **) NULL, + 0, + + { + ConSplitterSimplePointerReset, + ConSplitterSimplePointerGetState, + (EFI_EVENT) NULL, + (EFI_SIMPLE_POINTER_MODE *) NULL + }, + { + 0x10000, + 0x10000, + 0x10000, + TRUE, + TRUE + }, + 0, + (EFI_SIMPLE_POINTER_PROTOCOL **) NULL, + 0, + + FALSE, + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + 0, + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + (EFI_EVENT) NULL, + + FALSE, + FALSE +}; + +static 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, + }, + { + ConSpliterUgaDrawGetMode, + ConSpliterUgaDrawSetMode, + ConSpliterUgaDrawBlt + }, + 0, + 0, + 0, + 0, + (EFI_UGA_PIXEL *) NULL, + + { + ConSpliterConsoleControlGetMode, + ConSpliterConsoleControlSetMode, + ConSpliterConsoleControlLockStdIn + }, + + 0, + (TEXT_OUT_AND_UGA_DATA *) NULL, + 0, + (TEXT_OUT_SPLITTER_QUERY_DATA *) NULL, + 0, + (INT32 *) NULL, + + EfiConsoleControlScreenText, + 0, + 0, + (CHAR16 *) NULL, + (INT32 *) NULL +}; + +static 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, + }, + { + ConSpliterUgaDrawGetMode, + ConSpliterUgaDrawSetMode, + ConSpliterUgaDrawBlt + }, + 0, + 0, + 0, + 0, + (EFI_UGA_PIXEL *) NULL, + + { + ConSpliterConsoleControlGetMode, + ConSpliterConsoleControlSetMode, + ConSpliterConsoleControlLockStdIn + }, + + 0, + (TEXT_OUT_AND_UGA_DATA *) NULL, + 0, + (TEXT_OUT_SPLITTER_QUERY_DATA *) NULL, + 0, + (INT32 *) NULL, + + EfiConsoleControlScreenText, + 0, + 0, + (CHAR16 *) NULL, + (INT32 *) NULL +}; + +EFI_DRIVER_BINDING_PROTOCOL gConSplitterConInDriverBinding = { + ConSplitterConInDriverBindingSupported, + ConSplitterConInDriverBindingStart, + ConSplitterConInDriverBindingStop, + 0x10, + NULL, + NULL +}; + +EFI_DRIVER_BINDING_PROTOCOL gConSplitterSimplePointerDriverBinding = { + ConSplitterSimplePointerDriverBindingSupported, + ConSplitterSimplePointerDriverBindingStart, + ConSplitterSimplePointerDriverBindingStop, + 0x10, + NULL, + NULL +}; + +EFI_DRIVER_BINDING_PROTOCOL gConSplitterConOutDriverBinding = { + ConSplitterConOutDriverBindingSupported, + ConSplitterConOutDriverBindingStart, + ConSplitterConOutDriverBindingStop, + 0x10, + NULL, + NULL +}; + +EFI_DRIVER_BINDING_PROTOCOL gConSplitterStdErrDriverBinding = { + ConSplitterStdErrDriverBindingSupported, + ConSplitterStdErrDriverBindingStart, + ConSplitterStdErrDriverBindingStop, + 0x10, + NULL, + NULL +}; + +EFI_STATUS +EFIAPI +ConSplitterDriverEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + Intialize a virtual console device to act as an agrigator of physical console + devices. + +Arguments: + ImageHandle - (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT) + SystemTable - (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT) +Returns: + EFI_SUCCESS + +--*/ +{ + EFI_STATUS Status; + + // + // The driver creates virtual handles for ConIn, ConOut, and 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 StdErr Splitter + // + Status = ConSplitterTextOutConstructor (&mStdErr); + if (!EFI_ERROR (Status)) { + Status = gBS->InstallMultipleProtocolInterfaces ( + &mStdErr.VirtualHandle, + &gEfiSimpleTextOutProtocolGuid, + &mStdErr.TextOut, + &gEfiPrimaryStandardErrorDeviceGuid, + NULL, + NULL + ); + } + // + // Create virtual device handle for ConIn Splitter + // + Status = ConSplitterTextInConstructor (&mConIn); + if (!EFI_ERROR (Status)) { + Status = gBS->InstallMultipleProtocolInterfaces ( + &mConIn.VirtualHandle, + &gEfiSimpleTextInProtocolGuid, + &mConIn.TextIn, + &gEfiSimplePointerProtocolGuid, + &mConIn.SimplePointer, + &gEfiPrimaryConsoleInDeviceGuid, + NULL, + NULL + ); + if (!EFI_ERROR (Status)) { + // + // Update the EFI System Table with new virtual console + // + 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, + &gEfiUgaDrawProtocolGuid, + &mConOut.UgaDraw, + &gEfiConsoleControlProtocolGuid, + &mConOut.ConsoleControl, + &gEfiPrimaryConsoleOutDeviceGuid, + NULL, + NULL + ); + if (!EFI_ERROR (Status)) { + // + // Update the EFI System Table with new virtual console + // + gST->ConsoleOutHandle = mConOut.VirtualHandle; + gST->ConOut = &mConOut.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; +} + + +EFI_STATUS +ConSplitterTextInConstructor ( + TEXT_IN_SPLITTER_PRIVATE_DATA *ConInPrivate + ) +/*++ + +Routine Description: + + Construct the ConSplitter. + +Arguments: + + ConInPrivate - A pointer to the TEXT_IN_SPLITTER_PRIVATE_DATA structure. + +Returns: + EFI_OUT_OF_RESOURCES - Out of resources. + +--*/ +{ + EFI_STATUS Status; + + // + // Initilize console input splitter's private data. + // + Status = ConSplitterGrowBuffer ( + sizeof (EFI_SIMPLE_TEXT_IN_PROTOCOL *), + &ConInPrivate->TextInListCount, + (VOID **) &ConInPrivate->TextInList + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + // + // Create Event to support locking StdIn Device + // + Status = gBS->CreateEvent ( + EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL, + EFI_TPL_CALLBACK, + ConSpliterConsoleControlLockStdInEvent, + NULL, + &ConInPrivate->LockEvent + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->CreateEvent ( + EFI_EVENT_NOTIFY_WAIT, + EFI_TPL_NOTIFY, + ConSplitterTextInWaitForKey, + ConInPrivate, + &ConInPrivate->TextIn.WaitForKey + ); + ASSERT_EFI_ERROR (Status); + + ConInPrivate->SimplePointer.Mode = &ConInPrivate->SimplePointerMode; + + Status = ConSplitterGrowBuffer ( + sizeof (EFI_SIMPLE_POINTER_PROTOCOL *), + &ConInPrivate->PointerListCount, + (VOID **) &ConInPrivate->PointerList + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + Status = gBS->CreateEvent ( + EFI_EVENT_NOTIFY_WAIT, + EFI_TPL_NOTIFY, + ConSplitterSimplePointerWaitForInput, + ConInPrivate, + &ConInPrivate->SimplePointer.WaitForInput + ); + + return Status; +} + + +EFI_STATUS +ConSplitterTextOutConstructor ( + TEXT_OUT_SPLITTER_PRIVATE_DATA *ConOutPrivate + ) +{ + EFI_STATUS Status; + + // + // Initilize console output splitter's private data. + // + ConOutPrivate->TextOut.Mode = &ConOutPrivate->TextOutMode; + + Status = ConSplitterGrowBuffer ( + sizeof (TEXT_OUT_AND_UGA_DATA), + &ConOutPrivate->TextOutListCount, + (VOID **) &ConOutPrivate->TextOutList + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + Status = ConSplitterGrowBuffer ( + sizeof (TEXT_OUT_SPLITTER_QUERY_DATA), + &ConOutPrivate->TextOutQueryDataCount, + (VOID **) &ConOutPrivate->TextOutQueryData + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + // + // Setup the DevNullTextOut console to 80 x 25 + // + ConOutPrivate->TextOutQueryData[0].Columns = 80; + ConOutPrivate->TextOutQueryData[0].Rows = 25; + DevNullTextOutSetMode (ConOutPrivate, 0); + + // + // Setup the DevNullUgaDraw to 800 x 600 x 32 bits per pixel + // + ConSpliterUgaDrawSetMode (&ConOutPrivate->UgaDraw, 800, 600, 32, 60); + + return Status; +} + + +EFI_STATUS +ConSplitterSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_GUID *Guid + ) +/*++ + +Routine Description: + Generic Supported Check + +Arguments: + This - Pointer to protocol. + ControllerHandle - Controller Handle. + Guid - Guid. + +Returns: + + EFI_UNSUPPORTED - unsupported. + EFI_SUCCESS - operation is OK. + +--*/ +{ + EFI_STATUS Status; + VOID *Instance; + + // + // Make sure the Console Splitter does not attempt to attach to itself + // + if (ControllerHandle == mConIn.VirtualHandle) { + return EFI_UNSUPPORTED; + } + + if (ControllerHandle == mConOut.VirtualHandle) { + return EFI_UNSUPPORTED; + } + + if (ControllerHandle == mStdErr.VirtualHandle) { + return EFI_UNSUPPORTED; + } + // + // Check to see whether the handle has the ConsoleInDevice GUID on it + // + 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; +} + + +EFI_STATUS +EFIAPI +ConSplitterConInDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + Console In Supported Check + +Arguments: + This - Pointer to protocol. + ControllerHandle - Controller handle. + RemainingDevicePath - Remaining device path. + +Returns: + + EFI_STATUS + +--*/ +{ + return ConSplitterSupported ( + This, + ControllerHandle, + &gEfiConsoleInDeviceGuid + ); +} + + +EFI_STATUS +EFIAPI +ConSplitterSimplePointerDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + Standard Error Supported Check + +Arguments: + This - Pointer to protocol. + ControllerHandle - Controller handle. + RemainingDevicePath - Remaining device path. + +Returns: + + EFI_STATUS + +--*/ +{ + return ConSplitterSupported ( + This, + ControllerHandle, + &gEfiSimplePointerProtocolGuid + ); +} + + +EFI_STATUS +EFIAPI +ConSplitterConOutDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + Console Out Supported Check + +Arguments: + This - Pointer to protocol. + ControllerHandle - Controller handle. + RemainingDevicePath - Remaining device path. + +Returns: + + EFI_STATUS + +--*/ +{ + return ConSplitterSupported ( + This, + ControllerHandle, + &gEfiConsoleOutDeviceGuid + ); +} + + +EFI_STATUS +EFIAPI +ConSplitterStdErrDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + Standard Error Supported Check + +Arguments: + This - Pointer to protocol. + ControllerHandle - Controller handle. + RemainingDevicePath - Remaining device path. + +Returns: + + EFI_STATUS + +--*/ +{ + return ConSplitterSupported ( + This, + ControllerHandle, + &gEfiStandardErrorDeviceGuid + ); +} + + +EFI_STATUS +EFIAPI +ConSplitterStart ( + 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 + ) +/*++ + +Routine Description: + Start ConSplitter on ControllerHandle, and create the virtual + agrogated console device on first call Start for a SimpleTextIn handle. + +Arguments: + (Standard DriverBinding Protocol Start() function) + +Returns: + EFI_ERROR if a SimpleTextIn protocol is not started. + +--*/ +{ + EFI_STATUS Status; + VOID *Instance; + + // + // Check to see whether the handle has the ConsoleInDevice GUID on it + // + Status = gBS->OpenProtocol ( + ControllerHandle, + DeviceGuid, + &Instance, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->OpenProtocol ( + ControllerHandle, + DeviceGuid, + &Instance, + This->DriverBindingHandle, + ConSplitterVirtualHandle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + return gBS->OpenProtocol ( + ControllerHandle, + InterfaceGuid, + Interface, + This->DriverBindingHandle, + ConSplitterVirtualHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); +} + + +EFI_STATUS +EFIAPI +ConSplitterConInDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + Start ConSplitter on ControllerHandle, and create the virtual + agrogated console device on first call Start for a SimpleTextIn handle. + +Arguments: + This - Pointer to protocol. + ControllerHandle - Controller handle. + RemainingDevicePath - Remaining device path. + +Returns: + + EFI_STATUS + EFI_ERROR if a SimpleTextIn protocol is not started. + +--*/ +{ + EFI_STATUS Status; + EFI_SIMPLE_TEXT_IN_PROTOCOL *TextIn; + + // + // 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; + } + + return ConSplitterTextInAddDevice (&mConIn, TextIn); +} + + +EFI_STATUS +EFIAPI +ConSplitterSimplePointerDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + Start ConSplitter on ControllerHandle, and create the virtual + agrogated console device on first call Start for a SimpleTextIn handle. + +Arguments: + This - Pointer to protocol. + ControllerHandle - Controller handle. + RemainingDevicePath - Remaining device path. + +Returns: + + EFI_ERROR if a SimpleTextIn protocol is not started. + +--*/ +{ + EFI_STATUS Status; + EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer; + + Status = ConSplitterStart ( + This, + ControllerHandle, + mConIn.VirtualHandle, + &gEfiSimplePointerProtocolGuid, + &gEfiSimplePointerProtocolGuid, + (VOID **) &SimplePointer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + return ConSplitterSimplePointerAddDevice (&mConIn, SimplePointer); +} + + +EFI_STATUS +EFIAPI +ConSplitterConOutDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + Start ConSplitter on ControllerHandle, and create the virtual + agrogated console device on first call Start for a SimpleTextIn handle. + +Arguments: + This - Pointer to protocol. + ControllerHandle - Controller handle. + RemainingDevicePath - Remaining device path. + +Returns: + EFI_ERROR if a SimpleTextIn protocol is not started. + +--*/ +{ + EFI_STATUS Status; + EFI_SIMPLE_TEXT_OUT_PROTOCOL *TextOut; + EFI_UGA_DRAW_PROTOCOL *UgaDraw; + + Status = ConSplitterStart ( + This, + ControllerHandle, + mConOut.VirtualHandle, + &gEfiConsoleOutDeviceGuid, + &gEfiSimpleTextOutProtocolGuid, + (VOID **) &TextOut + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Open UGA_DRAW protocol + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUgaDrawProtocolGuid, + (VOID **) &UgaDraw, + This->DriverBindingHandle, + mConOut.VirtualHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + UgaDraw = NULL; + } + // + // 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, UgaDraw); + ConSplitterTextOutSetAttribute (&mConOut.TextOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + // + // Match the UGA mode data of ConOut with the current mode + // + if (UgaDraw) { + UgaDraw->GetMode ( + UgaDraw, + &mConOut.UgaHorizontalResolution, + &mConOut.UgaVerticalResolution, + &mConOut.UgaColorDepth, + &mConOut.UgaRefreshRate + ); + } + return Status; +} + + +EFI_STATUS +EFIAPI +ConSplitterStdErrDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + Start ConSplitter on ControllerHandle, and create the virtual + agrogated console device on first call Start for a SimpleTextIn handle. + +Arguments: + This - Pointer to protocol. + ControllerHandle - Controller handle. + RemainingDevicePath - Remaining device path. + +Returns: + EFI_ERROR if a SimpleTextIn protocol is not started. + +--*/ +{ + EFI_STATUS Status; + EFI_SIMPLE_TEXT_OUT_PROTOCOL *TextOut; + + Status = ConSplitterStart ( + This, + ControllerHandle, + mStdErr.VirtualHandle, + &gEfiStandardErrorDeviceGuid, + &gEfiSimpleTextOutProtocolGuid, + (VOID **) &TextOut + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // 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); + ConSplitterTextOutSetAttribute (&mStdErr.TextOut, EFI_TEXT_ATTR (EFI_MAGENTA, EFI_BLACK)); + if (EFI_ERROR (Status)) { + return Status; + } + + if (mStdErr.CurrentNumberOfConsoles == 1) { + 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 Status; +} + + +EFI_STATUS +EFIAPI +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 + ) +/*++ + +Routine Description: + +Arguments: + (Standard DriverBinding Protocol Stop() function) + +Returns: + + None + +--*/ +{ + 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; +} + + +EFI_STATUS +EFIAPI +ConSplitterConInDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + +Routine Description: + +Arguments: + (Standard DriverBinding Protocol Stop() function) + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + EFI_SIMPLE_TEXT_IN_PROTOCOL *TextIn; + + if (NumberOfChildren == 0) { + return EFI_SUCCESS; + } + + Status = ConSplitterStop ( + This, + ControllerHandle, + mConIn.VirtualHandle, + &gEfiConsoleInDeviceGuid, + &gEfiSimpleTextInProtocolGuid, + (VOID **) &TextIn + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Delete this console input device's data structures. + // + return ConSplitterTextInDeleteDevice (&mConIn, TextIn); +} + + +EFI_STATUS +EFIAPI +ConSplitterSimplePointerDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + +Routine Description: + +Arguments: + (Standard DriverBinding Protocol Stop() function) + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer; + + if (NumberOfChildren == 0) { + return EFI_SUCCESS; + } + + Status = ConSplitterStop ( + This, + ControllerHandle, + mConIn.VirtualHandle, + &gEfiSimplePointerProtocolGuid, + &gEfiSimplePointerProtocolGuid, + (VOID **) &SimplePointer + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Delete this console input device's data structures. + // + return ConSplitterSimplePointerDeleteDevice (&mConIn, SimplePointer); +} + + +EFI_STATUS +EFIAPI +ConSplitterConOutDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + +Routine Description: + +Arguments: + (Standard DriverBinding Protocol Stop() function) + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + EFI_SIMPLE_TEXT_OUT_PROTOCOL *TextOut; + EFI_UGA_DRAW_PROTOCOL *UgaDraw; + + if (NumberOfChildren == 0) { + return EFI_SUCCESS; + } + + Status = ConSplitterStop ( + This, + ControllerHandle, + mConOut.VirtualHandle, + &gEfiConsoleOutDeviceGuid, + &gEfiSimpleTextOutProtocolGuid, + (VOID **) &TextOut + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Remove any UGA devices + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUgaDrawProtocolGuid, + (VOID **) &UgaDraw, + This->DriverBindingHandle, + mConOut.VirtualHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + // + // Delete this console output device's data structures. + // + return ConSplitterTextOutDeleteDevice (&mConOut, TextOut); +} + + +EFI_STATUS +EFIAPI +ConSplitterStdErrDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + +Routine Description: + +Arguments: + (Standard DriverBinding Protocol Stop() function) + +Returns: + + EFI_SUCCESS - Complete successfully. + +--*/ +{ + EFI_STATUS Status; + EFI_SIMPLE_TEXT_OUT_PROTOCOL *TextOut; + + if (NumberOfChildren == 0) { + return EFI_SUCCESS; + } + + 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. + // + Status = ConSplitterTextOutDeleteDevice (&mStdErr, TextOut); + if (EFI_ERROR (Status)) { + return Status; + } + + if (mStdErr.CurrentNumberOfConsoles == 0) { + gST->StandardErrorHandle = NULL; + gST->StdErr = NULL; + // + // 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 Status; +} + +EFI_STATUS +ConSplitterGrowBuffer ( + IN UINTN SizeOfCount, + IN UINTN *Count, + IN OUT VOID **Buffer + ) +/*++ + +Routine Description: + Take the passed in Buffer of size SizeOfCount and grow the buffer + by MAX (CONSOLE_SPLITTER_CONSOLES_ALLOC_UNIT, MaxGrow) * SizeOfCount + bytes. Copy the current data in Buffer to the new version of Buffer + and free the old version of buffer. + + +Arguments: + SizeOfCount - Size of element in array + Count - Current number of elements in array + Buffer - Bigger version of passed in Buffer with all the data + +Returns: + EFI_SUCCESS - Buffer size has grown + EFI_OUT_OF_RESOURCES - Could not grow the buffer size + + None + +--*/ +{ + UINTN NewSize; + UINTN OldSize; + 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. + // + OldSize = *Count * SizeOfCount; + *Count += CONSOLE_SPLITTER_CONSOLES_ALLOC_UNIT; + NewSize = *Count * SizeOfCount; + + Ptr = AllocateZeroPool (NewSize); + if (Ptr == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CopyMem (Ptr, *Buffer, OldSize); + + if (*Buffer != NULL) { + gBS->FreePool (*Buffer); + } + + *Buffer = Ptr; + + return EFI_SUCCESS; +} + +EFI_STATUS +ConSplitterTextInAddDevice ( + IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, + IN EFI_SIMPLE_TEXT_IN_PROTOCOL *TextIn + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + EFI_SUCCESS + EFI_OUT_OF_RESOURCES + +--*/ +{ + EFI_STATUS Status; + + // + // If the Text In List is full, enlarge it by calling growbuffer(). + // + if (Private->CurrentNumberOfConsoles >= Private->TextInListCount) { + Status = ConSplitterGrowBuffer ( + sizeof (EFI_SIMPLE_TEXT_IN_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() in UI.c + // + gBS->CheckEvent (TextIn->WaitForKey); + + return EFI_SUCCESS; +} + +EFI_STATUS +ConSplitterTextInDeleteDevice ( + IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, + IN EFI_SIMPLE_TEXT_IN_PROTOCOL *TextIn + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + EFI_SUCCESS + EFI_NOT_FOUND + +--*/ +{ + 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 = Index; Index < Private->CurrentNumberOfConsoles - 1; Index++) { + Private->TextInList[Index] = Private->TextInList[Index + 1]; + } + + Private->CurrentNumberOfConsoles--; + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +EFI_STATUS +ConSplitterSimplePointerAddDevice ( + IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, + IN EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + EFI_OUT_OF_RESOURCES + EFI_SUCCESS + +--*/ +{ + EFI_STATUS Status; + + // + // If the Text In List is full, enlarge it by calling growbuffer(). + // + 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 Text In List. + // + Private->PointerList[Private->CurrentNumberOfPointers] = SimplePointer; + Private->CurrentNumberOfPointers++; + return EFI_SUCCESS; +} + +EFI_STATUS +ConSplitterSimplePointerDeleteDevice ( + IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, + IN EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +{ + 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->CurrentNumberOfPointers; Index++) { + if (Private->PointerList[Index] == SimplePointer) { + for (Index = Index; Index < Private->CurrentNumberOfPointers - 1; Index++) { + Private->PointerList[Index] = Private->PointerList[Index + 1]; + } + + Private->CurrentNumberOfPointers--; + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +EFI_STATUS +ConSplitterGrowMapTable ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +{ + UINTN Size; + UINTN NewSize; + UINTN TotalSize; + INT32 *TextOutModeMap; + INT32 *OldTextOutModeMap; + INT32 *SrcAddress; + INT32 Index; + + NewSize = Private->TextOutListCount * sizeof (INT32); + OldTextOutModeMap = Private->TextOutModeMap; + TotalSize = NewSize * Private->TextOutQueryDataCount; + + TextOutModeMap = AllocateZeroPool (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; + + // + // Copy the old data to the new one + // + while (Index < Private->TextOutMode.MaxMode) { + CopyMem (TextOutModeMap, SrcAddress, Size); + TextOutModeMap += NewSize; + SrcAddress += Size; + Index++; + } + // + // Free the old buffer + // + gBS->FreePool (OldTextOutModeMap); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +ConSplitterAddOutputMode ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *TextOut + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +{ + 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) { + TextOut->QueryMode ( + TextOut, + Mode, + &Private->TextOutQueryData[Mode].Columns, + &Private->TextOutQueryData[Mode].Rows + ); + Private->TextOutModeMap[Index] = Mode; + Mode++; + Index += Private->TextOutListCount; + } + + return EFI_SUCCESS; +} + +VOID +ConSplitterGetIntersection ( + IN INT32 *TextOutModeMap, + IN INT32 *NewlyAddedMap, + IN UINTN MapStepSize, + IN UINTN NewMapStepSize, + OUT INT32 *MaxMode, + OUT INT32 *CurrentMode + ) +{ + INT32 Index; + INT32 *CurrentMapEntry; + INT32 *NextMapEntry; + INT32 CurrentMaxMode; + INT32 Mode; + + Index = 0; + CurrentMapEntry = TextOutModeMap; + NextMapEntry = TextOutModeMap; + CurrentMaxMode = *MaxMode; + Mode = *CurrentMode; + + while (Index < CurrentMaxMode) { + if (*NewlyAddedMap == -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; + NewlyAddedMap += NewMapStepSize; + Index++; + } + + *CurrentMode = Mode; + + return ; +} + +VOID +ConSplitterSyncOutputMode ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *TextOut + ) +/*++ + +Routine Description: + +Arguments: + Private - Private data structure. + TextOut - Text Out Protocol. +Returns: + + None + +--*/ +{ + INT32 CurrentMode; + INT32 CurrentMaxMode; + INT32 Mode; + INT32 Index; + INT32 *TextOutModeMap; + INT32 *MapTable; + TEXT_OUT_SPLITTER_QUERY_DATA *TextOutQueryData; + UINTN Rows; + UINTN Columns; + UINTN StepSize; + + // + // Must make sure that current mode won't change even if mode number changes + // + CurrentMode = Private->TextOutMode.Mode; + 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) { + TextOut->QueryMode (TextOut, Mode, &Columns, &Rows); + + // + // Search the QueryData database to see if they intersects + // + Index = 0; + while (Index < CurrentMaxMode) { + if ((TextOutQueryData[Index].Rows == Rows) && (TextOutQueryData[Index].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 ; +} + +EFI_STATUS +ConSplitterGetIntersectionBetweenConOutAndStrErr ( + VOID + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +{ + UINTN ConOutNumOfConsoles; + UINTN StdErrNumOfConsoles; + TEXT_OUT_AND_UGA_DATA *ConOutTextOutList; + TEXT_OUT_AND_UGA_DATA *StdErrTextOutList; + UINTN Indexi; + UINTN Indexj; + UINTN Rows; + UINTN Columns; + INT32 ConOutCurrentMode; + INT32 StdErrCurrentMode; + INT32 ConOutMaxMode; + INT32 StdErrMaxMode; + 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 + // + ConOutCurrentMode = mConOut.TextOutMode.Mode; + ConOutMaxMode = mConOut.TextOutMode.MaxMode; + ConOutModeMap = mConOut.TextOutModeMap; + ConOutStepSize = mConOut.TextOutListCount; + ConOutQueryData = mConOut.TextOutQueryData; + + StdErrCurrentMode = mStdErr.TextOutMode.Mode; + 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 + // correponding entry in the map table is set to 1. + // + Mode = 0; + while (Mode < ConOutMaxMode) { + // + // Search the other's QueryData database to see if they intersect + // + Index = 0; + Rows = ConOutQueryData[Mode].Rows; + Columns = ConOutQueryData[Mode].Columns; + while (Index < StdErrMaxMode) { + if ((StdErrQueryData[Index].Rows == Rows) && (StdErrQueryData[Index].Columns == Columns)) { + 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); + } + + gBS->FreePool (ConOutMapTable); + gBS->FreePool (StdErrMapTable); + + return EFI_SUCCESS; +} + +EFI_STATUS +ConSplitterTextOutAddDevice ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *TextOut, + IN EFI_UGA_DRAW_PROTOCOL *UgaDraw + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + UINTN CurrentNumOfConsoles; + INT32 CurrentMode; + INT32 MaxMode; + TEXT_OUT_AND_UGA_DATA *TextAndUga; + + Status = EFI_SUCCESS; + CurrentNumOfConsoles = Private->CurrentNumberOfConsoles; + + // + // If the Text Out List is full, enlarge it by calling growbuffer(). + // + while (CurrentNumOfConsoles >= Private->TextOutListCount) { + Status = ConSplitterGrowBuffer ( + sizeof (TEXT_OUT_AND_UGA_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; + } + } + + TextAndUga = &Private->TextOutList[CurrentNumOfConsoles]; + + TextAndUga->TextOut = TextOut; + TextAndUga->UgaDraw = UgaDraw; + if (UgaDraw == NULL) { + // + // If No UGA device then use the ConOut device + // + TextAndUga->TextOutEnabled = TRUE; + } else { + // + // If UGA device use ConOut device only used if UGA screen is in Text mode + // + TextAndUga->TextOutEnabled = (BOOLEAN) (Private->UgaMode == EfiConsoleControlScreenText); + } + + 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 (); + + CurrentMode = Private->TextOutMode.Mode; + MaxMode = Private->TextOutMode.MaxMode; + ASSERT (MaxMode >= 1); + + if (Private->UgaMode == EfiConsoleControlScreenGraphics && UgaDraw != NULL) { + // + // We just added a new UGA device in graphics mode + // + DevNullUgaSync (Private, UgaDraw); + + } else if ((CurrentMode >= 0) && (UgaDraw != NULL) && (CurrentMode < Private->TextOutMode.MaxMode)) { + // + // The new console supports the same mode of the current console so sync up + // + DevNullSyncUgaStdOut (Private); + } else { + // + // If ConOut, then set the mode to Mode #0 which us 80 x 25 + // + Private->TextOut.SetMode (&Private->TextOut, 0); + } + + return Status; +} + +EFI_STATUS +ConSplitterTextOutDeleteDevice ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *TextOut + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +{ + INT32 Index; + UINTN CurrentNumOfConsoles; + TEXT_OUT_AND_UGA_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) { + CopyMem (TextOutList, TextOutList + 1, sizeof (TEXT_OUT_AND_UGA_DATA) * Index); + CurrentNumOfConsoles--; + break; + } + + Index--; + TextOutList++; + } + // + // The specified TextOut is not managed by the ConSplitter driver + // + if (Index < 0) { + return EFI_NOT_FOUND; + } + + if (CurrentNumOfConsoles == 0) { + // + // If the number of consoles is zero clear the Dev NULL device + // + Private->CurrentNumberOfConsoles = 0; + Private->TextOutMode.MaxMode = 1; + Private->TextOutQueryData[0].Columns = 80; + Private->TextOutQueryData[0].Rows = 25; + DevNullTextOutSetMode (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) + ); + + gBS->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; +} +// +// ConSplitter TextIn member functions +// +EFI_STATUS +EFIAPI +ConSplitterTextInReset ( + IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + + Routine Description: + Reset the input device and optionaly run diagnostics + + Arguments: + This - Protocol instance pointer. + ExtendedVerification - Driver may perform diagnostics on reset. + + Returns: + EFI_SUCCESS - The device was reset. + EFI_DEVICE_ERROR - The device is not functioning properly and could + not be reset. + +--*/ +{ + 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; + } + } + + return ReturnStatus; +} + +EFI_STATUS +EFIAPI +ConSplitterTextInPrivateReadKeyStroke ( + IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, + OUT EFI_INPUT_KEY *Key + ) +/*++ + + Routine Description: + Reads the next keystroke from the input device. The WaitForKey Event can + be used to test for existance of a keystroke via WaitForEvent () call. + + Arguments: + This - Protocol instance pointer. + Key - Driver may perform diagnostics on reset. + + Returns: + EFI_SUCCESS - The keystroke information was returned. + EFI_NOT_READY - There was no keystroke data availiable. + EFI_DEVICE_ERROR - The keydtroke information was not returned due to + hardware errors. + +--*/ +{ + EFI_STATUS Status; + UINTN Index; + EFI_INPUT_KEY CurrentKey; + + 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; Index++) { + Status = Private->TextInList[Index]->ReadKeyStroke ( + Private->TextInList[Index], + &CurrentKey + ); + if (!EFI_ERROR (Status)) { + *Key = CurrentKey; + return Status; + } + } + + return EFI_NOT_READY; +} + +BOOLEAN +ConSpliterConssoleControlStdInLocked ( + VOID + ) +/*++ + +Routine Description: + Return TRUE if StdIn is locked. The ConIn device on the virtual handle is + the only device locked. + +Arguments: + NONE + +Returns: + TRUE - StdIn locked + FALSE - StdIn working normally + +--*/ +{ + return mConIn.PasswordEnabled; +} + +VOID +EFIAPI +ConSpliterConsoleControlLockStdInEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + This timer event will fire when StdIn is locked. It will check the key + sequence on StdIn to see if it matches the password. Any error in the + password will cause the check to reset. As long a mConIn.PasswordEnabled is + TRUE the StdIn splitter will not report any input. + +Arguments: + (Standard EFI_EVENT_NOTIFY) + +Returns: + None + +--*/ +{ + EFI_STATUS Status; + EFI_INPUT_KEY Key; + CHAR16 BackSpaceString[2]; + CHAR16 SpaceString[2]; + + do { + Status = ConSplitterTextInPrivateReadKeyStroke (&mConIn, &Key); + if (!EFI_ERROR (Status)) { + // + // if it's an ENTER, match password + // + if ((Key.UnicodeChar == CHAR_CARRIAGE_RETURN) && (Key.ScanCode == SCAN_NULL)) { + mConIn.PwdAttempt[mConIn.PwdIndex] = CHAR_NULL; + if (StrCmp (mConIn.Password, mConIn.PwdAttempt)) { + // + // Password not match + // + ConSplitterTextOutOutputString (&mConOut.TextOut, (CHAR16 *) L"\n\rPassword not correct\n\r"); + mConIn.PwdIndex = 0; + } else { + // + // Key matches password sequence + // + gBS->SetTimer (mConIn.LockEvent, TimerPeriodic, 0); + mConIn.PasswordEnabled = FALSE; + Status = EFI_NOT_READY; + } + } else if ((Key.UnicodeChar == CHAR_BACKSPACE) && (Key.ScanCode == SCAN_NULL)) { + // + // BackSpace met + // + if (mConIn.PwdIndex > 0) { + BackSpaceString[0] = CHAR_BACKSPACE; + BackSpaceString[1] = 0; + + SpaceString[0] = ' '; + SpaceString[1] = 0; + + ConSplitterTextOutOutputString (&mConOut.TextOut, BackSpaceString); + ConSplitterTextOutOutputString (&mConOut.TextOut, SpaceString); + ConSplitterTextOutOutputString (&mConOut.TextOut, BackSpaceString); + + mConIn.PwdIndex--; + } + } else if ((Key.ScanCode == SCAN_NULL) && (Key.UnicodeChar >= 32)) { + // + // If it's not an ENTER, neigher a function key, nor a CTRL-X or ALT-X, record the input + // + if (mConIn.PwdIndex < (MAX_STD_IN_PASSWORD - 1)) { + if (mConIn.PwdIndex == 0) { + ConSplitterTextOutOutputString (&mConOut.TextOut, (CHAR16 *) L"\n\r"); + } + + ConSplitterTextOutOutputString (&mConOut.TextOut, (CHAR16 *) L"*"); + mConIn.PwdAttempt[mConIn.PwdIndex] = Key.UnicodeChar; + mConIn.PwdIndex++; + } + } + } + } while (!EFI_ERROR (Status)); +} + +EFI_STATUS +EFIAPI +ConSpliterConsoleControlLockStdIn ( + IN EFI_CONSOLE_CONTROL_PROTOCOL *This, + IN CHAR16 *Password + ) +/*++ + +Routine Description: + If Password is NULL unlock the password state variable and set the event + timer. If the Password is too big return an error. If the Password is valid + Copy the Password and enable state variable and then arm the periodic timer + +Arguments: + +Returns: + EFI_SUCCESS - Lock the StdIn device + EFI_INVALID_PARAMETER - Password is NULL + EFI_OUT_OF_RESOURCES - Buffer allocation to store the password fails + +--*/ +{ + if (Password == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (StrLen (Password) >= MAX_STD_IN_PASSWORD) { + // + // Currently have a max password size + // + return EFI_OUT_OF_RESOURCES; + } + // + // Save the password, initialize state variables and arm event timer + // + StrCpy (mConIn.Password, Password); + mConIn.PasswordEnabled = TRUE; + mConIn.PwdIndex = 0; + gBS->SetTimer (mConIn.LockEvent, TimerPeriodic, (10000 * 25)); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +ConSplitterTextInReadKeyStroke ( + IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This, + OUT EFI_INPUT_KEY *Key + ) +/*++ + + Routine Description: + Reads the next keystroke from the input device. The WaitForKey Event can + be used to test for existance of a keystroke via WaitForEvent () call. + If the ConIn is password locked make it look like no keystroke is availible + + Arguments: + This - Protocol instance pointer. + Key - Driver may perform diagnostics on reset. + + Returns: + EFI_SUCCESS - The keystroke information was returned. + EFI_NOT_READY - There was no keystroke data availiable. + EFI_DEVICE_ERROR - The keydtroke information was not returned due to + hardware errors. + +--*/ +{ + TEXT_IN_SPLITTER_PRIVATE_DATA *Private; + + Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_THIS (This); + if (Private->PasswordEnabled) { + // + // If StdIn Locked return not ready + // + return EFI_NOT_READY; + } + + Private->KeyEventSignalState = FALSE; + + return ConSplitterTextInPrivateReadKeyStroke (Private, Key); +} + +VOID +EFIAPI +ConSplitterTextInWaitForKey ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + This event agregates all the events of the ConIn devices in the spliter. + If the ConIn is password locked then return. + If any events of physical ConIn devices are signaled, signal the ConIn + spliter event. This will cause the calling code to call + ConSplitterTextInReadKeyStroke (). + +Arguments: + Event - The Event assoicated with callback. + Context - Context registered when Event was created. + +Returns: + None + +--*/ +{ + EFI_STATUS Status; + TEXT_IN_SPLITTER_PRIVATE_DATA *Private; + UINTN Index; + + Private = (TEXT_IN_SPLITTER_PRIVATE_DATA *) Context; + if (Private->PasswordEnabled) { + // + // If StdIn Locked return not ready + // + return ; + } + + // + // if KeyEventSignalState is flagged before, and not cleared by Reset() or ReadKeyStroke() + // + if (Private->KeyEventSignalState) { + 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; + } + } +} + +EFI_STATUS +EFIAPI +ConSplitterSimplePointerReset ( + IN EFI_SIMPLE_POINTER_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + + Routine Description: + Reset the input device and optionaly run diagnostics + + Arguments: + This - Protocol instance pointer. + ExtendedVerification - Driver may perform diagnostics on reset. + + Returns: + EFI_SUCCESS - The device was reset. + EFI_DEVICE_ERROR - The device is not functioning properly and could + not be reset. + +--*/ +{ + 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; +} + +EFI_STATUS +EFIAPI +ConSplitterSimplePointerPrivateGetState ( + IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, + IN OUT EFI_SIMPLE_POINTER_STATE *State + ) +/*++ + + Routine Description: + Reads the next keystroke from the input device. The WaitForKey Event can + be used to test for existance of a keystroke via WaitForEvent () call. + + Arguments: + This - Protocol instance pointer. + State - + + Returns: + EFI_SUCCESS - The keystroke information was returned. + EFI_NOT_READY - There was no keystroke data availiable. + EFI_DEVICE_ERROR - The keydtroke information was not returned due to + hardware errors. + +--*/ +{ + 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; +} + +EFI_STATUS +EFIAPI +ConSplitterSimplePointerGetState ( + IN EFI_SIMPLE_POINTER_PROTOCOL *This, + IN OUT EFI_SIMPLE_POINTER_STATE *State + ) +/*++ + + Routine Description: + Reads the next keystroke from the input device. The WaitForKey Event can + be used to test for existance of a keystroke via WaitForEvent () call. + If the ConIn is password locked make it look like no keystroke is availible + + Arguments: + This - Protocol instance pointer. + State - + + Returns: + EFI_SUCCESS - The keystroke information was returned. + EFI_NOT_READY - There was no keystroke data availiable. + EFI_DEVICE_ERROR - The keydtroke information was not returned due to + hardware errors. + +--*/ +{ + TEXT_IN_SPLITTER_PRIVATE_DATA *Private; + + Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_SIMPLE_POINTER_THIS (This); + if (Private->PasswordEnabled) { + // + // If StdIn Locked return not ready + // + return EFI_NOT_READY; + } + + Private->InputEventSignalState = FALSE; + + return ConSplitterSimplePointerPrivateGetState (Private, State); +} + +VOID +EFIAPI +ConSplitterSimplePointerWaitForInput ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + This event agregates all the events of the ConIn devices in the spliter. + If the ConIn is password locked then return. + If any events of physical ConIn devices are signaled, signal the ConIn + spliter event. This will cause the calling code to call + ConSplitterTextInReadKeyStroke (). + +Arguments: + Event - The Event assoicated with callback. + Context - Context registered when Event was created. + +Returns: + None + +--*/ +{ + EFI_STATUS Status; + TEXT_IN_SPLITTER_PRIVATE_DATA *Private; + UINTN Index; + + Private = (TEXT_IN_SPLITTER_PRIVATE_DATA *) Context; + if (Private->PasswordEnabled) { + // + // If StdIn Locked return not ready + // + return ; + } + + // + // 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; + } + } +} + +EFI_STATUS +EFIAPI +ConSplitterTextOutReset ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + + Routine Description: + Reset the text output device hardware and optionaly run diagnostics + + Arguments: + This - Protocol instance pointer. + ExtendedVerification - Driver may perform more exhaustive verfication + operation of the device during reset. + + Returns: + EFI_SUCCESS - The text output device was reset. + EFI_DEVICE_ERROR - The text output device is not functioning correctly and + could not be reset. + +--*/ +{ + 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++) { + + if (Private->TextOutList[Index].TextOutEnabled) { + + 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_BACKGROUND_BLACK)); + + Status = DevNullTextOutSetMode (Private, 0); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + + return ReturnStatus; +} + +EFI_STATUS +EFIAPI +ConSplitterTextOutOutputString ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN CHAR16 *WString + ) +/*++ + + Routine Description: + Write a Unicode string to the output device. + + Arguments: + This - Protocol instance pointer. + String - 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. + + Returns: + EFI_SUCCESS - The string was output to the device. + EFI_DEVICE_ERROR - The device reported an error while attempting to output + the text. + EFI_UNSUPPORTED - The output device's mode is not currently in a + defined text mode. + 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 Status; + TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; + UINTN Index; + UINTN BackSpaceCount; + EFI_STATUS ReturnStatus; + CHAR16 *TargetString; + + This->SetAttribute (This, This->Mode->Attribute); + + Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This); + + BackSpaceCount = 0; + for (TargetString = WString; *TargetString; TargetString++) { + if (*TargetString == CHAR_BACKSPACE) { + BackSpaceCount++; + } + + } + + if (BackSpaceCount == 0) { + TargetString = WString; + } else { + TargetString = AllocatePool (sizeof (CHAR16) * (StrLen (WString) + BackSpaceCount + 1)); + StrCpy (TargetString, WString); + } + // + // return the worst status met + // + Status = DevNullTextOutOutputString (Private, TargetString); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + + for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) { + + if (Private->TextOutList[Index].TextOutEnabled) { + Status = Private->TextOutList[Index].TextOut->OutputString ( + Private->TextOutList[Index].TextOut, + TargetString + ); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + } + } + + if (BackSpaceCount) { + gBS->FreePool (TargetString); + } + + return ReturnStatus; +} + +EFI_STATUS +EFIAPI +ConSplitterTextOutTestString ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN CHAR16 *WString + ) +/*++ + + Routine Description: + Verifies that all characters in a Unicode string can be output to the + target device. + + Arguments: + This - Protocol instance pointer. + String - The NULL-terminated Unicode string to be examined for the output + device(s). + + Returns: + EFI_SUCCESS - The device(s) are capable of rendering the output string. + 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 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++) { + if (Private->TextOutList[Index].TextOutEnabled) { + 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; +} + +EFI_STATUS +EFIAPI +ConSplitterTextOutQueryMode ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN UINTN ModeNumber, + OUT UINTN *Columns, + OUT UINTN *Rows + ) +/*++ + + Routine Description: + Returns information for an available text mode that the output device(s) + supports. + + Arguments: + This - Protocol instance pointer. + ModeNumber - The mode number to return information on. + Columns, Rows - Returns the geometry of the text output device for the + requested ModeNumber. + + Returns: + EFI_SUCCESS - The requested mode information was returned. + EFI_DEVICE_ERROR - The device had an error and could not + complete the request. + EFI_UNSUPPORTED - The mode number was not valid. + +--*/ +{ + TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; + + 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; + } + + *Columns = Private->TextOutQueryData[ModeNumber].Columns; + *Rows = Private->TextOutQueryData[ModeNumber].Rows; + + if (*Columns <= 0 && *Rows <= 0) { + return EFI_UNSUPPORTED; + + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +ConSplitterTextOutSetMode ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN UINTN ModeNumber + ) +/*++ + + Routine Description: + Sets the output device(s) to a specified mode. + + Arguments: + This - Protocol instance pointer. + ModeNumber - The mode number to set. + + Returns: + EFI_SUCCESS - The requested text mode was set. + EFI_DEVICE_ERROR - The device had an error and + could not complete the request. + EFI_UNSUPPORTED - The mode number was not valid. + +--*/ +{ + 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++) { + + if (Private->TextOutList[Index].TextOutEnabled) { + Status = Private->TextOutList[Index].TextOut->SetMode ( + Private->TextOutList[Index].TextOut, + TextOutModeMap[Index] + ); + // + // If this console device is based on a UGA device, then sync up the bitmap from + // the UGA splitter and reclear the text portion of the display in the new mode. + // + if (Private->TextOutList[Index].UgaDraw != NULL) { + Private->TextOutList[Index].TextOut->ClearScreen (Private->TextOutList[Index].TextOut); + } + + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + } + } + // + // The DevNull Console will support any possible mode as it allocates memory + // + Status = DevNullTextOutSetMode (Private, ModeNumber); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + + return ReturnStatus; +} + +EFI_STATUS +EFIAPI +ConSplitterTextOutSetAttribute ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN UINTN Attribute + ) +/*++ + + Routine Description: + Sets the background and foreground colors for the OutputString () and + ClearScreen () functions. + + Arguments: + This - Protocol instance pointer. + 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. + + Returns: + EFI_SUCCESS - The attribute was set. + EFI_DEVICE_ERROR - The device had an error and + could not complete the request. + EFI_UNSUPPORTED - The attribute requested is not defined. + +--*/ +{ + 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 > (UINTN)(((UINT32)-1)>>1)) ) { + return EFI_UNSUPPORTED; + } + + // + // return the worst status met + // + for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) { + + if (Private->TextOutList[Index].TextOutEnabled) { + Status = Private->TextOutList[Index].TextOut->SetAttribute ( + Private->TextOutList[Index].TextOut, + Attribute + ); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + } + } + + Private->TextOutMode.Attribute = (INT32) Attribute; + + return ReturnStatus; +} + +EFI_STATUS +EFIAPI +ConSplitterTextOutClearScreen ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This + ) +/*++ + + Routine Description: + Clears the output device(s) display to the currently selected background + color. + + Arguments: + This - Protocol instance pointer. + + Returns: + EFI_SUCCESS - The operation completed successfully. + EFI_DEVICE_ERROR - The device had an error and + could not complete the request. + EFI_UNSUPPORTED - The output device is not in a valid text mode. + +--*/ +{ + 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++) { + + if (Private->TextOutList[Index].TextOutEnabled) { + Status = Private->TextOutList[Index].TextOut->ClearScreen (Private->TextOutList[Index].TextOut); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + } + } + + Status = DevNullTextOutClearScreen (Private); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + + return ReturnStatus; +} + +EFI_STATUS +EFIAPI +ConSplitterTextOutSetCursorPosition ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN UINTN Column, + IN UINTN Row + ) +/*++ + + Routine Description: + Sets the current coordinates of the cursor position + + Arguments: + This - Protocol instance pointer. + Column, 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 (). + + Returns: + EFI_SUCCESS - The operation completed successfully. + EFI_DEVICE_ERROR - The device had an error and + could not complete the request. + EFI_UNSUPPORTED - The output device is not in a valid text mode, or the + cursor position is invalid for the current mode. + +--*/ +{ + EFI_STATUS Status; + TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; + UINTN Index; + EFI_STATUS ReturnStatus; + UINTN MaxColumn; + UINTN MaxRow; + + Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This); + + MaxColumn = Private->TextOutQueryData[Private->TextOutMode.Mode].Columns; + MaxRow = Private->TextOutQueryData[Private->TextOutMode.Mode].Rows; + + if (Column >= MaxColumn || Row >= MaxRow) { + return EFI_UNSUPPORTED; + } + // + // return the worst status met + // + for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) { + + if (Private->TextOutList[Index].TextOutEnabled) { + Status = Private->TextOutList[Index].TextOut->SetCursorPosition ( + Private->TextOutList[Index].TextOut, + Column, + Row + ); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + } + } + + DevNullTextOutSetCursorPosition (Private, Column, Row); + + return ReturnStatus; +} + +EFI_STATUS +EFIAPI +ConSplitterTextOutEnableCursor ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN BOOLEAN Visible + ) +/*++ + + Routine Description: + Makes the cursor visible or invisible + + Arguments: + This - Protocol instance pointer. + Visible - If TRUE, the cursor is set to be visible. If FALSE, the cursor is + set to be invisible. + + Returns: + EFI_SUCCESS - The operation completed successfully. + EFI_DEVICE_ERROR - The device had an error and could not complete the + request, or the device does not support changing + the cursor mode. + EFI_UNSUPPORTED - The output device is not in a valid text mode. + +--*/ +{ + 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++) { + + if (Private->TextOutList[Index].TextOutEnabled) { + Status = Private->TextOutList[Index].TextOut->EnableCursor ( + Private->TextOutList[Index].TextOut, + Visible + ); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + } + } + + DevNullTextOutEnableCursor (Private, Visible); + + return ReturnStatus; +} diff --git a/EdkModulePkg/Universal/Console/ConSplitter/Dxe/ConSplitter.h b/EdkModulePkg/Universal/Console/ConSplitter/Dxe/ConSplitter.h new file mode 100644 index 0000000000..fc68f049a0 --- /dev/null +++ b/EdkModulePkg/Universal/Console/ConSplitter/Dxe/ConSplitter.h @@ -0,0 +1,623 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ConSplitter.h + +Abstract: + + Private data structures for the Console Splitter driver + +--*/ + +#ifndef SPLITER_H_ +#define SPLITER_H_ + +// +// Private Data Structures +// +#define CONSOLE_SPLITTER_CONSOLES_ALLOC_UNIT 32 +#define CONSOLE_SPLITTER_MODES_ALLOC_UNIT 32 +#define MAX_STD_IN_PASSWORD 80 + +typedef struct { + UINTN Columns; + UINTN Rows; +} TEXT_OUT_SPLITTER_QUERY_DATA; + +// +// Private data for the EFI_SIMPLE_INPUT_PROTOCOL splitter +// +#define TEXT_IN_SPLITTER_PRIVATE_DATA_SIGNATURE EFI_SIGNATURE_32 ('T', 'i', 'S', 'p') + +typedef struct { + UINT64 Signature; + EFI_HANDLE VirtualHandle; + + EFI_SIMPLE_TEXT_IN_PROTOCOL TextIn; + UINTN CurrentNumberOfConsoles; + EFI_SIMPLE_TEXT_IN_PROTOCOL **TextInList; + UINTN TextInListCount; + + EFI_SIMPLE_POINTER_PROTOCOL SimplePointer; + EFI_SIMPLE_POINTER_MODE SimplePointerMode; + UINTN CurrentNumberOfPointers; + EFI_SIMPLE_POINTER_PROTOCOL **PointerList; + UINTN PointerListCount; + + BOOLEAN PasswordEnabled; + CHAR16 Password[MAX_STD_IN_PASSWORD]; + UINTN PwdIndex; + CHAR16 PwdAttempt[MAX_STD_IN_PASSWORD]; + EFI_EVENT LockEvent; + + BOOLEAN KeyEventSignalState; + BOOLEAN InputEventSignalState; +} 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 \ + ) + +// +// Private data for the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL splitter +// +#define TEXT_OUT_SPLITTER_PRIVATE_DATA_SIGNATURE EFI_SIGNATURE_32 ('T', 'o', 'S', 'p') + +typedef struct { + EFI_UGA_DRAW_PROTOCOL *UgaDraw; + EFI_SIMPLE_TEXT_OUT_PROTOCOL *TextOut; + BOOLEAN TextOutEnabled; +} TEXT_OUT_AND_UGA_DATA; + +typedef struct { + UINT64 Signature; + EFI_HANDLE VirtualHandle; + EFI_SIMPLE_TEXT_OUT_PROTOCOL TextOut; + EFI_SIMPLE_TEXT_OUTPUT_MODE TextOutMode; + EFI_UGA_DRAW_PROTOCOL UgaDraw; + UINT32 UgaHorizontalResolution; + UINT32 UgaVerticalResolution; + UINT32 UgaColorDepth; + UINT32 UgaRefreshRate; + EFI_UGA_PIXEL *UgaBlt; + + EFI_CONSOLE_CONTROL_PROTOCOL ConsoleControl; + + UINTN CurrentNumberOfConsoles; + TEXT_OUT_AND_UGA_DATA *TextOutList; + UINTN TextOutListCount; + TEXT_OUT_SPLITTER_QUERY_DATA *TextOutQueryData; + UINTN TextOutQueryDataCount; + INT32 *TextOutModeMap; + + EFI_CONSOLE_CONTROL_SCREEN_MODE UgaMode; + + UINTN DevNullColumns; + UINTN DevNullRows; + CHAR16 *DevNullScreen; + INT32 *DevNullAttributes; + +} 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 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 +// +EFI_STATUS +EFIAPI +ConSplitterDriverEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +; + + +EFI_STATUS +ConSplitterTextInConstructor ( + TEXT_IN_SPLITTER_PRIVATE_DATA *Private + ) +; + + +EFI_STATUS +ConSplitterTextOutConstructor ( + TEXT_OUT_SPLITTER_PRIVATE_DATA *Private + ) +; + +// +// Driver Binding Functions +// + +EFI_STATUS +EFIAPI +ConSplitterConInDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +; + + +EFI_STATUS +EFIAPI +ConSplitterSimplePointerDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +; + + +EFI_STATUS +EFIAPI +ConSplitterConOutDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +; + + +EFI_STATUS +EFIAPI +ConSplitterStdErrDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +; + + +EFI_STATUS +EFIAPI +ConSplitterConInDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +; + + +EFI_STATUS +EFIAPI +ConSplitterSimplePointerDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +; + + +EFI_STATUS +EFIAPI +ConSplitterConOutDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +; + + +EFI_STATUS +EFIAPI +ConSplitterStdErrDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +; + + +EFI_STATUS +EFIAPI +ConSplitterConInDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +; + + +EFI_STATUS +EFIAPI +ConSplitterSimplePointerDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +; + + +EFI_STATUS +EFIAPI +ConSplitterConOutDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +; + + +EFI_STATUS +EFIAPI +ConSplitterStdErrDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +; + +// +// TextIn Constructor/Destructor functions +// +EFI_STATUS +ConSplitterTextInAddDevice ( + IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, + IN EFI_SIMPLE_TEXT_IN_PROTOCOL *TextIn + ) +; + +EFI_STATUS +ConSplitterTextInDeleteDevice ( + IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, + IN EFI_SIMPLE_TEXT_IN_PROTOCOL *TextIn + ) +; + +// +// SimplePointer Constuctor/Destructor functions +// +EFI_STATUS +ConSplitterSimplePointerAddDevice ( + IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, + IN EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer + ) +; + +EFI_STATUS +ConSplitterSimplePointerDeleteDevice ( + IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, + IN EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer + ) +; + +// +// TextOut Constuctor/Destructor functions +// +EFI_STATUS +ConSplitterTextOutAddDevice ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *TextOut, + IN EFI_UGA_DRAW_PROTOCOL *UgaDraw + ) +; + +EFI_STATUS +ConSplitterTextOutDeleteDevice ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *TextOut + ) +; + +// +// TextIn I/O Functions +// +EFI_STATUS +EFIAPI +ConSplitterTextInReset ( + IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +; + +EFI_STATUS +EFIAPI +ConSplitterTextInReadKeyStroke ( + IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This, + OUT EFI_INPUT_KEY *Key + ) +; + +VOID +EFIAPI +ConSplitterTextInWaitForKey ( + IN EFI_EVENT Event, + IN VOID *Context + ) +; + +BOOLEAN +ConSpliterConssoleControlStdInLocked ( + VOID + ) +; + +VOID +EFIAPI +ConSpliterConsoleControlLockStdInEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +; + +EFI_STATUS +EFIAPI +ConSpliterConsoleControlLockStdIn ( + IN EFI_CONSOLE_CONTROL_PROTOCOL *This, + IN CHAR16 *Password + ) +; + +EFI_STATUS +EFIAPI +ConSplitterTextInPrivateReadKeyStroke ( + IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, + OUT EFI_INPUT_KEY *Key + ) +; + +EFI_STATUS +EFIAPI +ConSplitterSimplePointerReset ( + IN EFI_SIMPLE_POINTER_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +; + +EFI_STATUS +EFIAPI +ConSplitterSimplePointerGetState ( + IN EFI_SIMPLE_POINTER_PROTOCOL *This, + IN OUT EFI_SIMPLE_POINTER_STATE *State + ) +; + +VOID +EFIAPI +ConSplitterSimplePointerWaitForInput ( + IN EFI_EVENT Event, + IN VOID *Context + ) +; + +// +// TextOut I/O Functions +// +VOID +ConSplitterSynchronizeModeData ( + TEXT_OUT_SPLITTER_PRIVATE_DATA *Private + ) +; + +EFI_STATUS +EFIAPI +ConSplitterTextOutReset ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +; + +EFI_STATUS +EFIAPI +ConSplitterTextOutOutputString ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN CHAR16 *WString + ) +; + +EFI_STATUS +EFIAPI +ConSplitterTextOutTestString ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN CHAR16 *WString + ) +; + +EFI_STATUS +EFIAPI +ConSplitterTextOutQueryMode ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN UINTN ModeNumber, + OUT UINTN *Columns, + OUT UINTN *Rows + ) +; + +EFI_STATUS +EFIAPI +ConSplitterTextOutSetMode ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN UINTN ModeNumber + ) +; + +EFI_STATUS +EFIAPI +ConSplitterTextOutSetAttribute ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN UINTN Attribute + ) +; + +EFI_STATUS +EFIAPI +ConSplitterTextOutClearScreen ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This + ) +; + +EFI_STATUS +EFIAPI +ConSplitterTextOutSetCursorPosition ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN UINTN Column, + IN UINTN Row + ) +; + +EFI_STATUS +EFIAPI +ConSplitterTextOutEnableCursor ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN BOOLEAN Visible + ) +; + +EFI_STATUS +ConSplitterGrowBuffer ( + IN UINTN SizeOfCount, + IN UINTN *Count, + IN OUT VOID **Buffer + ) +; + +EFI_STATUS +EFIAPI +ConSpliterConsoleControlGetMode ( + IN EFI_CONSOLE_CONTROL_PROTOCOL *This, + OUT EFI_CONSOLE_CONTROL_SCREEN_MODE *Mode, + OUT BOOLEAN *UgaExists, + OUT BOOLEAN *StdInLocked + ) +; + +EFI_STATUS +EFIAPI +ConSpliterConsoleControlSetMode ( + IN EFI_CONSOLE_CONTROL_PROTOCOL *This, + IN EFI_CONSOLE_CONTROL_SCREEN_MODE Mode + ) +; + +EFI_STATUS +EFIAPI +ConSpliterUgaDrawGetMode ( + IN EFI_UGA_DRAW_PROTOCOL *This, + OUT UINT32 *HorizontalResolution, + OUT UINT32 *VerticalResolution, + OUT UINT32 *ColorDepth, + OUT UINT32 *RefreshRate + ) +; + +EFI_STATUS +EFIAPI +ConSpliterUgaDrawSetMode ( + IN EFI_UGA_DRAW_PROTOCOL *This, + IN UINT32 HorizontalResolution, + IN UINT32 VerticalResolution, + IN UINT32 ColorDepth, + IN UINT32 RefreshRate + ) +; + +EFI_STATUS +EFIAPI +ConSpliterUgaDrawBlt ( + 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 +DevNullUgaSync ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, + IN EFI_UGA_DRAW_PROTOCOL *UgaDraw + ) +; + +EFI_STATUS +DevNullTextOutOutputString ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, + IN CHAR16 *WString + ) +; + +EFI_STATUS +DevNullTextOutSetMode ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, + IN UINTN ModeNumber + ) +; + +EFI_STATUS +DevNullTextOutClearScreen ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private + ) +; + +EFI_STATUS +DevNullTextOutSetCursorPosition ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, + IN UINTN Column, + IN UINTN Row + ) +; + +EFI_STATUS +DevNullTextOutEnableCursor ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, + IN BOOLEAN Visible + ) +; + +EFI_STATUS +DevNullSyncUgaStdOut ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private + ) +; + +#endif diff --git a/EdkModulePkg/Universal/Console/ConSplitter/Dxe/ConSplitter.mbd b/EdkModulePkg/Universal/Console/ConSplitter/Dxe/ConSplitter.mbd new file mode 100644 index 0000000000..d4b36b6f8f --- /dev/null +++ b/EdkModulePkg/Universal/Console/ConSplitter/Dxe/ConSplitter.mbd @@ -0,0 +1,41 @@ + + + + + ConSplitter + 408edcec-cf6d-477c-a5a8-b4844e3de281 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + + UefiBootServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + BaseLib + DxeMemoryAllocationLib + + diff --git a/EdkModulePkg/Universal/Console/ConSplitter/Dxe/ConSplitter.msa b/EdkModulePkg/Universal/Console/ConSplitter/Dxe/ConSplitter.msa new file mode 100644 index 0000000000..287556ad59 --- /dev/null +++ b/EdkModulePkg/Universal/Console/ConSplitter/Dxe/ConSplitter.msa @@ -0,0 +1,102 @@ + + + + + ConSplitter + DXE_DRIVER + BS_DRIVER + 408edcec-cf6d-477c-a5a8-b4844e3de281 + 0 + Component description file for DiskIo module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + UefiLib + BaseLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + + + ConSplitter.c + ConSplitter.h + ComponentName.c + ConSplitterGraphics.c + + + MdePkg + EdkModulePkg + + + UgaDraw + SimpleTextOut + SimpleTextIn + SimplePointer + ConsoleControl + + + + PrimaryStandardErrorDevice + + + PrimaryConsoleInDevice + + + PrimaryConsoleOutDevice + + + ConsoleOutDevice + + + StandardErrorDevice + + + ConsoleInDevice + + + + + ConSplitterDriverEntry + + + gConSplitterConInDriverBinding + gConSplitterConInComponentName + + + gConSplitterSimplePointerDriverBinding + gConSplitterSimplePointerComponentName + + + gConSplitterConOutDriverBinding + gConSplitterConOutComponentName + + + gConSplitterStdErrDriverBinding + gConSplitterStdErrComponentName + + + diff --git a/EdkModulePkg/Universal/Console/ConSplitter/Dxe/ConSplitterGraphics.c b/EdkModulePkg/Universal/Console/ConSplitter/Dxe/ConSplitterGraphics.c new file mode 100644 index 0000000000..412d695d77 --- /dev/null +++ b/EdkModulePkg/Universal/Console/ConSplitter/Dxe/ConSplitterGraphics.c @@ -0,0 +1,1076 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ConSplitterGraphics.c + +Abstract: + + Support for ConsoleControl protocol. Support for UGA Draw spliter. + Support for DevNull Console Out. This console uses memory buffers + to represnt the console. It allows a console to start very early and + when a new console is added it is synced up with the current console + +--*/ + + +#include "ConSplitter.h" + +static CHAR16 mCrLfString[3] = { CHAR_CARRIAGE_RETURN, CHAR_LINEFEED, CHAR_NULL }; + +EFI_STATUS +EFIAPI +ConSpliterConsoleControlGetMode ( + IN EFI_CONSOLE_CONTROL_PROTOCOL *This, + OUT EFI_CONSOLE_CONTROL_SCREEN_MODE *Mode, + OUT BOOLEAN *UgaExists, + OUT BOOLEAN *StdInLocked + ) +/*++ + + Routine Description: + Return the current video mode information. Also returns info about existence + of UGA Draw devices in system, and if the Std In device is locked. All the + arguments are optional and only returned if a non NULL pointer is passed in. + + Arguments: + This - Protocol instance pointer. + Mode - Are we in text of grahics mode. + UgaExists - TRUE if UGA Spliter has found a UGA device + StdInLocked - TRUE if StdIn device is keyboard locked + + Returns: + EFI_SUCCESS - Mode information returned. + EFI_INVALID_PARAMETER - Invalid parameters. + +--*/ +{ + TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; + UINTN Index; + + Private = CONSOLE_CONTROL_SPLITTER_PRIVATE_DATA_FROM_THIS (This); + + if (Mode == NULL) { + return EFI_INVALID_PARAMETER; + } + + *Mode = Private->UgaMode; + + if (UgaExists != NULL) { + *UgaExists = FALSE; + for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) { + if (Private->TextOutList[Index].UgaDraw != NULL) { + *UgaExists = TRUE; + break; + } + } + } + + if (StdInLocked != NULL) { + *StdInLocked = ConSpliterConssoleControlStdInLocked (); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +ConSpliterConsoleControlSetMode ( + IN EFI_CONSOLE_CONTROL_PROTOCOL *This, + IN EFI_CONSOLE_CONTROL_SCREEN_MODE Mode + ) +/*++ + + Routine Description: + Set the current mode to either text or graphics. Graphics is + for Quiet Boot. + + Arguments: + This - Protocol instance pointer. + Mode - Mode to set the + + Returns: + EFI_SUCCESS - Mode information returned. + EFI_INVALID_PARAMETER - Invalid parameter. + EFI_UNSUPPORTED - Operation unsupported. + +--*/ +{ + TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; + UINTN Index; + TEXT_OUT_AND_UGA_DATA *TextAndUga; + BOOLEAN Supported; + + Private = CONSOLE_CONTROL_SPLITTER_PRIVATE_DATA_FROM_THIS (This); + + if (Mode >= EfiConsoleControlScreenMaxValue) { + return EFI_INVALID_PARAMETER; + } + + Supported = FALSE; + TextAndUga = &Private->TextOutList[0]; + for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++, TextAndUga++) { + if (TextAndUga->UgaDraw != NULL) { + Supported = TRUE; + break; + } + } + + if ((!Supported) && (Mode == EfiConsoleControlScreenGraphics)) { + return EFI_UNSUPPORTED; + } + + Private->UgaMode = Mode; + + TextAndUga = &Private->TextOutList[0]; + for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++, TextAndUga++) { + + TextAndUga->TextOutEnabled = TRUE; + // + // If we are going into Graphics mode disable ConOut to any UGA device + // + if ((Mode == EfiConsoleControlScreenGraphics) && (TextAndUga->UgaDraw != NULL)) { + TextAndUga->TextOutEnabled = FALSE; + DevNullUgaSync (Private, TextAndUga->UgaDraw); + } + } + + if (Mode == EfiConsoleControlScreenText) { + DevNullSyncUgaStdOut (Private); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +ConSpliterUgaDrawGetMode ( + IN EFI_UGA_DRAW_PROTOCOL *This, + OUT UINT32 *HorizontalResolution, + OUT UINT32 *VerticalResolution, + OUT UINT32 *ColorDepth, + OUT UINT32 *RefreshRate + ) +/*++ + + Routine Description: + Return the current video mode information. + + Arguments: + This - Protocol instance pointer. + HorizontalResolution - Current video horizontal resolution in pixels + VerticalResolution - Current video vertical resolution in pixels + ColorDepth - Current video color depth in bits per pixel + RefreshRate - Current video refresh rate in Hz. + + Returns: + EFI_SUCCESS - Mode information returned. + EFI_NOT_STARTED - Video display is not initialized. Call SetMode () + EFI_INVALID_PARAMETER - One of the input args was NULL. + +--*/ +{ + TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; + + if (!(HorizontalResolution && VerticalResolution && RefreshRate && ColorDepth)) { + 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; +} + +EFI_STATUS +EFIAPI +ConSpliterUgaDrawSetMode ( + IN EFI_UGA_DRAW_PROTOCOL *This, + IN UINT32 HorizontalResolution, + IN UINT32 VerticalResolution, + IN UINT32 ColorDepth, + IN UINT32 RefreshRate + ) +/*++ + + Routine Description: + Return the current video mode information. + + Arguments: + This - Protocol instance pointer. + HorizontalResolution - Current video horizontal resolution in pixels + VerticalResolution - Current video vertical resolution in pixels + ColorDepth - Current video color depth in bits per pixel + RefreshRate - Current video refresh rate in Hz. + + Returns: + EFI_SUCCESS - Mode information returned. + EFI_NOT_STARTED - Video display is not initialized. Call SetMode () + EFI_OUT_OF_RESOURCES - Out of resources. + +--*/ +{ + EFI_STATUS Status; + TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; + UINTN Index; + EFI_STATUS ReturnStatus; + UINTN Size; + + Private = UGA_DRAW_SPLITTER_PRIVATE_DATA_FROM_THIS (This); + + // + // UgaDevNullSetMode () + // + ReturnStatus = EFI_SUCCESS; + + // + // Free the old version + // + gBS->FreePool (Private->UgaBlt); + + // + // Allocate the virtual Blt buffer + // + Size = HorizontalResolution * VerticalResolution * sizeof (EFI_UGA_PIXEL); + Private->UgaBlt = AllocateZeroPool (Size); + if (Private->UgaBlt == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Update the Mode data + // + Private->UgaHorizontalResolution = HorizontalResolution; + Private->UgaVerticalResolution = VerticalResolution; + Private->UgaColorDepth = ColorDepth; + Private->UgaRefreshRate = RefreshRate; + + if (Private->UgaMode != EfiConsoleControlScreenGraphics) { + return ReturnStatus; + } + // + // return the worst status met + // + for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) { + if (Private->TextOutList[Index].UgaDraw != NULL) { + Status = Private->TextOutList[Index].UgaDraw->SetMode ( + Private->TextOutList[Index].UgaDraw, + HorizontalResolution, + VerticalResolution, + ColorDepth, + RefreshRate + ); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + } + } + + return ReturnStatus; +} + +EFI_STATUS +DevNullUgaBlt ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, + 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 + ) +{ + UINTN SrcY; + UINTN Index; + EFI_UGA_PIXEL *BltPtr; + EFI_UGA_PIXEL *ScreenPtr; + UINT32 HorizontalResolution; + UINT32 VerticalResolution; + + if ((BltOperation < 0) || (BltOperation >= EfiUgaBltMax)) { + return EFI_INVALID_PARAMETER; + } + + if (Width == 0 || Height == 0) { + return EFI_INVALID_PARAMETER; + } + + if (Delta == 0) { + Delta = Width * sizeof (EFI_UGA_PIXEL); + } + + HorizontalResolution = Private->UgaHorizontalResolution; + VerticalResolution = Private->UgaVerticalResolution; + + // + // We need to fill the Virtual Screen buffer with the blt data. + // + if (BltOperation == EfiUgaVideoToBltBuffer) { + // + // Video to BltBuffer: Source is Video, destination is BltBuffer + // + if ((SourceY + Height) > VerticalResolution) { + return EFI_INVALID_PARAMETER; + } + + if ((SourceX + Width) > HorizontalResolution) { + return EFI_INVALID_PARAMETER; + } + + BltPtr = (EFI_UGA_PIXEL *) ((UINT8 *) BltBuffer + DestinationY * Delta + DestinationX * sizeof (EFI_UGA_PIXEL)); + ScreenPtr = &Private->UgaBlt[SourceY * HorizontalResolution + SourceX]; + while (Height) { + CopyMem (BltPtr, ScreenPtr, Width * sizeof (EFI_UGA_PIXEL)); + BltPtr = (EFI_UGA_PIXEL *) ((UINT8 *) BltPtr + Delta); + ScreenPtr += HorizontalResolution; + Height--; + } + } else { + // + // BltBuffer to Video: Source is BltBuffer, destination is Video + // + if (DestinationY + Height > VerticalResolution) { + return EFI_INVALID_PARAMETER; + } + + if (DestinationX + Width > HorizontalResolution) { + return EFI_INVALID_PARAMETER; + } + + ScreenPtr = &Private->UgaBlt[DestinationY * HorizontalResolution + DestinationX]; + SrcY = SourceY; + while (Height) { + if (BltOperation == EfiUgaVideoFill) { + for (Index = 0; Index < Width; Index++) { + ScreenPtr[Index] = *BltBuffer; + } + } else { + if (BltOperation == EfiUgaBltBufferToVideo) { + BltPtr = (EFI_UGA_PIXEL *) ((UINT8 *) BltBuffer + SrcY * Delta + SourceX * sizeof (EFI_UGA_PIXEL)); + } else { + BltPtr = &Private->UgaBlt[SrcY * HorizontalResolution + SourceX]; + } + + CopyMem (ScreenPtr, BltPtr, Width * sizeof (EFI_UGA_PIXEL)); + } + + ScreenPtr += HorizontalResolution; + SrcY++; + Height--; + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +ConSpliterUgaDrawBlt ( + 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 + ) +/*++ + + Routine Description: + 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. + + Arguments: + This - Protocol instance pointer. + BltBuffer - Buffer containing data to blit into video buffer. This + buffer has a size of Width*Height*sizeof(EFI_UGA_PIXEL) + BltOperation - Operation to perform on BlitBuffer and video memory + SourceX - X coordinate of source for the BltBuffer. + SourceY - Y coordinate of source for the BltBuffer. + DestinationX - X coordinate of destination for the BltBuffer. + DestinationY - Y coordinate of destination for the BltBuffer. + Width - Width of rectangle in BltBuffer in pixels. + Height - Hight of rectangle in BltBuffer in pixels. + Delta - + + Returns: + EFI_SUCCESS - The Blt operation completed. + EFI_INVALID_PARAMETER - BltOperation is not valid. + EFI_DEVICE_ERROR - A hardware error occured writting to the video + buffer. + +--*/ +{ + EFI_STATUS Status; + TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; + UINTN Index; + EFI_STATUS ReturnStatus; + + Private = UGA_DRAW_SPLITTER_PRIVATE_DATA_FROM_THIS (This); + + // + // Sync up DevNull UGA device + // + ReturnStatus = DevNullUgaBlt ( + Private, + BltBuffer, + BltOperation, + SourceX, + SourceY, + DestinationX, + DestinationY, + Width, + Height, + Delta + ); + if (Private->UgaMode != EfiConsoleControlScreenGraphics) { + return ReturnStatus; + } + // + // return the worst status met + // + for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) { + if (Private->TextOutList[Index].UgaDraw != NULL) { + 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; +} + +EFI_STATUS +DevNullUgaSync ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, + IN EFI_UGA_DRAW_PROTOCOL *UgaDraw + ) +{ + return UgaDraw->Blt ( + UgaDraw, + Private->UgaBlt, + EfiUgaBltBufferToVideo, + 0, + 0, + 0, + 0, + Private->UgaHorizontalResolution, + Private->UgaVerticalResolution, + Private->UgaHorizontalResolution * sizeof (EFI_UGA_PIXEL) + ); +} + +EFI_STATUS +DevNullTextOutOutputString ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, + IN CHAR16 *WString + ) +/*++ + + Routine Description: + Write a Unicode string to the output device. + + Arguments: + Private - Pointer to the console output splitter's private data. It + indicates the calling context. + 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. + + Returns: + EFI_SUCCESS - The string was output to the device. + EFI_DEVICE_ERROR - The device reported an error while attempting to + output the text. + EFI_UNSUPPORTED - The output device's mode is not currently in a + defined text mode. + EFI_WARN_UNKNOWN_GLYPH - This warning code indicates that some of the + characters in the Unicode string could not be + rendered and were skipped. + +--*/ +{ + UINTN SizeScreen; + UINTN SizeAttribute; + UINTN Index; + EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode; + CHAR16 *Screen; + CHAR16 *NullScreen; + CHAR16 InsertChar; + CHAR16 TempChar; + CHAR16 *PStr; + INT32 *Attribute; + INT32 *NullAttributes; + INT32 CurrentWidth; + UINTN LastRow; + UINTN MaxColumn; + + Mode = &Private->TextOutMode; + NullScreen = Private->DevNullScreen; + NullAttributes = Private->DevNullAttributes; + LastRow = Private->DevNullRows - 1; + MaxColumn = Private->DevNullColumns; + + if (Mode->Attribute & EFI_WIDE_ATTRIBUTE) { + CurrentWidth = 2; + } else { + CurrentWidth = 1; + } + + while (*WString) { + + if (*WString == CHAR_BACKSPACE) { + // + // If the cursor is at the left edge of the display, then move the cursor + // one row up. + // + if (Mode->CursorColumn == 0 && Mode->CursorRow > 0) { + Mode->CursorRow--; + Mode->CursorColumn = (INT32) MaxColumn; + } + + // + // If the cursor is not at the left edge of the display, + // then move the cursor left one column. + // + if (Mode->CursorColumn > 0) { + Mode->CursorColumn--; + if (Mode->CursorColumn > 0 && + NullAttributes[Mode->CursorRow * MaxColumn + Mode->CursorColumn - 1] & EFI_WIDE_ATTRIBUTE + ) { + Mode->CursorColumn--; + + // + // Insert an extra backspace + // + InsertChar = CHAR_BACKSPACE; + PStr = WString + 1; + while (*PStr) { + TempChar = *PStr; + *PStr = InsertChar; + InsertChar = TempChar; + PStr++; + } + + *PStr = InsertChar; + *(++PStr) = 0; + + WString++; + } + } + + 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 (Mode->CursorRow == (INT32) (LastRow)) { + // + // Scroll Screen Up One Row + // + SizeAttribute = LastRow * MaxColumn; + CopyMem ( + NullAttributes, + NullAttributes + MaxColumn, + SizeAttribute * sizeof (INT32) + ); + + // + // Each row has an ending CHAR_NULL. So one more character each line + // for DevNullScreen than DevNullAttributes + // + SizeScreen = SizeAttribute + LastRow; + CopyMem ( + NullScreen, + NullScreen + (MaxColumn + 1), + SizeScreen * sizeof (CHAR16) + ); + + // + // Print Blank Line at last line + // + Screen = NullScreen + SizeScreen; + Attribute = NullAttributes + SizeAttribute; + + for (Index = 0; Index < MaxColumn; Index++, Screen++, Attribute++) { + *Screen = ' '; + *Attribute = Mode->Attribute; + } + } else { + Mode->CursorRow++; + } + + WString++; + } else if (*WString == CHAR_CARRIAGE_RETURN) { + // + // Move the cursor to the beginning of the current row. + // + Mode->CursorColumn = 0; + 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. + // + Index = Mode->CursorRow * MaxColumn + Mode->CursorColumn; + + while (Mode->CursorColumn < (INT32) MaxColumn) { + if (*WString == CHAR_NULL) { + break; + } + + if (*WString == CHAR_BACKSPACE) { + break; + } + + if (*WString == CHAR_LINEFEED) { + break; + } + + if (*WString == CHAR_CARRIAGE_RETURN) { + break; + } + + if (*WString == WIDE_CHAR || *WString == NARROW_CHAR) { + CurrentWidth = (*WString == WIDE_CHAR) ? 2 : 1; + WString++; + continue; + } + + if (Mode->CursorColumn + CurrentWidth > (INT32) MaxColumn) { + // + // If a wide char is at the rightmost column, then move the char + // to the beginning of the next row + // + NullScreen[Index + Mode->CursorRow] = L' '; + NullAttributes[Index] = Mode->Attribute | (UINT32) EFI_WIDE_ATTRIBUTE; + Index++; + Mode->CursorColumn++; + } else { + NullScreen[Index + Mode->CursorRow] = *WString; + NullAttributes[Index] = Mode->Attribute; + if (CurrentWidth == 1) { + NullAttributes[Index] &= (~ (UINT32) EFI_WIDE_ATTRIBUTE); + } else { + NullAttributes[Index] |= (UINT32) EFI_WIDE_ATTRIBUTE; + NullAttributes[Index + 1] &= (~ (UINT32) EFI_WIDE_ATTRIBUTE); + } + + Index += CurrentWidth; + WString++; + Mode->CursorColumn += CurrentWidth; + } + } + // + // At the end of line, output carriage return and line feed + // + if (Mode->CursorColumn >= (INT32) MaxColumn) { + DevNullTextOutOutputString (Private, mCrLfString); + } + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +DevNullTextOutSetMode ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, + IN UINTN ModeNumber + ) +/*++ + + Routine Description: + Sets the output device(s) to a specified mode. + + Arguments: + Private - Private data structure pointer. + ModeNumber - The mode number to set. + + Returns: + EFI_SUCCESS - The requested text mode was set. + EFI_DEVICE_ERROR - The device had an error and + could not complete the request. + EFI_UNSUPPORTED - The mode number was not valid. + EFI_OUT_OF_RESOURCES - Out of resources. + +--*/ +{ + UINTN Size; + UINTN Row; + UINTN Column; + TEXT_OUT_SPLITTER_QUERY_DATA *Mode; + + // + // No extra check for ModeNumber here, as it has been checked in + // ConSplitterTextOutSetMode. And mode 0 should always be supported. + // + Mode = &(Private->TextOutQueryData[ModeNumber]); + Row = Mode->Rows; + Column = Mode->Columns; + + if (Row <= 0 && Column <= 0) { + return EFI_UNSUPPORTED; + } + + if (Private->DevNullColumns != Column || Private->DevNullRows != Row) { + + Private->TextOutMode.Mode = (INT32) ModeNumber; + Private->DevNullColumns = Column; + Private->DevNullRows = Row; + + gBS->FreePool (Private->DevNullScreen); + + Size = (Row * (Column + 1)) * sizeof (CHAR16); + Private->DevNullScreen = AllocateZeroPool (Size); + if (Private->DevNullScreen == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + gBS->FreePool (Private->DevNullAttributes); + + Size = Row * Column * sizeof (INT32); + Private->DevNullAttributes = AllocateZeroPool (Size); + if (Private->DevNullAttributes == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } + + DevNullTextOutClearScreen (Private); + + return EFI_SUCCESS; +} + +EFI_STATUS +DevNullTextOutClearScreen ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private + ) +/*++ + + Routine Description: + Clears the output device(s) display to the currently selected background + color. + + Arguments: + Private - Protocol instance pointer. + + Returns: + EFI_SUCCESS - The operation completed successfully. + EFI_DEVICE_ERROR - The device had an error and + could not complete the request. + EFI_UNSUPPORTED - The output device is not in a valid text mode. + +--*/ +{ + UINTN Row; + UINTN Column; + CHAR16 *Screen; + INT32 *Attributes; + INT32 CurrentAttribute; + + // + // Clear the DevNull Text Out Buffers. + // The screen is filled with spaces. + // The attributes are all synced with the current Simple Text Out Attribute + // + Screen = Private->DevNullScreen; + Attributes = Private->DevNullAttributes; + CurrentAttribute = Private->TextOutMode.Attribute; + + for (Row = 0; Row < Private->DevNullRows; Row++) { + for (Column = 0; Column < Private->DevNullColumns; Column++, Screen++, Attributes++) { + *Screen = ' '; + *Attributes = CurrentAttribute; + } + // + // Each line of the screen has a NULL on the end so we must skip over it + // + Screen++; + } + + DevNullTextOutSetCursorPosition (Private, 0, 0); + + return DevNullTextOutEnableCursor (Private, TRUE); +} + +EFI_STATUS +DevNullTextOutSetCursorPosition ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, + IN UINTN Column, + IN UINTN Row + ) +/*++ + + Routine Description: + Sets the current coordinates of the cursor position + + Arguments: + Private - Protocol instance pointer. + Column, 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 (). + + Returns: + EFI_SUCCESS - The operation completed successfully. + EFI_DEVICE_ERROR - The device had an error and + could not complete the request. + EFI_UNSUPPORTED - The output device is not in a valid text mode, or the + cursor position is invalid for the current mode. + +--*/ +{ + // + // 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 EFI_SUCCESS; +} + +EFI_STATUS +DevNullTextOutEnableCursor ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, + IN BOOLEAN Visible + ) +/*++ + Routine Description: + + Implements SIMPLE_TEXT_OUTPUT.EnableCursor(). + In this driver, the cursor cannot be hidden. + + Arguments: + + Private - Indicates the calling context. + + Visible - If TRUE, the cursor is set to be visible, If FALSE, the cursor + is set to be invisible. + + Returns: + + EFI_SUCCESS - The request is valid. + + +--*/ +{ + Private->TextOutMode.CursorVisible = Visible; + + return EFI_SUCCESS; +} + +EFI_STATUS +DevNullSyncUgaStdOut ( + IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private + ) +/*++ + Routine Description: + Take the DevNull TextOut device and update the Simple Text Out on every + UGA device. + + Arguments: + Private - Indicates the calling context. + + Returns: + EFI_SUCCESS - The request is valid. + other - Return status of TextOut->OutputString () + +--*/ +{ + EFI_STATUS Status; + EFI_STATUS ReturnStatus; + UINTN Row; + UINTN Column; + UINTN List; + UINTN MaxColumn; + UINTN CurrentColumn; + UINTN StartRow; + UINTN StartColumn; + INT32 StartAttribute; + BOOLEAN StartCursorState; + CHAR16 *Screen; + CHAR16 *Str; + CHAR16 *Buffer; + CHAR16 *BufferTail; + CHAR16 *ScreenStart; + INT32 CurrentAttribute; + INT32 *Attributes; + EFI_SIMPLE_TEXT_OUT_PROTOCOL *Sto; + + // + // Save the devices Attributes, Cursor enable state and location + // + StartColumn = Private->TextOutMode.CursorColumn; + StartRow = Private->TextOutMode.CursorRow; + StartAttribute = Private->TextOutMode.Attribute; + StartCursorState = Private->TextOutMode.CursorVisible; + + for (List = 0; List < Private->CurrentNumberOfConsoles; List++) { + + Sto = Private->TextOutList[List].TextOut; + + // + // Skip non UGA devices + // + if (Private->TextOutList[List].UgaDraw != NULL) { + Sto->EnableCursor (Sto, FALSE); + Sto->ClearScreen (Sto); + } + } + + ReturnStatus = EFI_SUCCESS; + Screen = Private->DevNullScreen; + Attributes = Private->DevNullAttributes; + MaxColumn = Private->DevNullColumns; + + Buffer = AllocateZeroPool ((MaxColumn + 1) * sizeof (CHAR16)); + + for (Row = 0; Row < Private->DevNullRows; Row++, Screen += (MaxColumn + 1), Attributes += MaxColumn) { + + if (Row == (Private->DevNullRows - 1)) { + // + // Don't ever sync the last character as it will scroll the screen + // + Screen[MaxColumn - 1] = 0x00; + } + + Column = 0; + while (Column < MaxColumn) { + if (Screen[Column]) { + CurrentAttribute = Attributes[Column]; + CurrentColumn = Column; + ScreenStart = &Screen[Column]; + + // + // the line end is alway 0x0. So Column should be less than MaxColumn + // It should be still in the same row + // + for (Str = ScreenStart, BufferTail = Buffer; *Str != 0; Str++, Column++) { + + if (Attributes[Column] != CurrentAttribute) { + Column--; + break; + } + + *BufferTail = *Str; + BufferTail++; + if (Attributes[Column] & EFI_WIDE_ATTRIBUTE) { + Str++; + Column++; + } + } + + *BufferTail = 0; + + for (List = 0; List < Private->CurrentNumberOfConsoles; List++) { + + Sto = Private->TextOutList[List].TextOut; + + // + // Skip non UGA devices + // + if (Private->TextOutList[List].UgaDraw != NULL) { + Sto->SetAttribute (Sto, CurrentAttribute); + Sto->SetCursorPosition (Sto, CurrentColumn, Row); + Status = Sto->OutputString (Sto, Buffer); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + } + } + + } + + Column++; + } + } + // + // Restore the devices Attributes, Cursor enable state and location + // + for (List = 0; List < Private->CurrentNumberOfConsoles; List++) { + Sto = Private->TextOutList[List].TextOut; + + // + // Skip non UGA devices + // + if (Private->TextOutList[List].UgaDraw != NULL) { + Sto->SetAttribute (Sto, StartAttribute); + Sto->SetCursorPosition (Sto, StartColumn, StartRow); + Status = Sto->EnableCursor (Sto, StartCursorState); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + } + } + + gBS->FreePool (Buffer); + + return ReturnStatus; +} diff --git a/EdkModulePkg/Universal/Console/ConSplitter/Dxe/build.xml b/EdkModulePkg/Universal/Console/ConSplitter/Dxe/build.xml new file mode 100644 index 0000000000..b49ce9027c --- /dev/null +++ b/EdkModulePkg/Universal/Console/ConSplitter/Dxe/build.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/ComponentName.c b/EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/ComponentName.c new file mode 100644 index 0000000000..5c615ba1c8 --- /dev/null +++ b/EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/ComponentName.c @@ -0,0 +1,139 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ComponentName.c + +Abstract: + +--*/ + +#include "GraphicsConsole.h" + +// +// EFI Component Name Protocol +// +EFI_COMPONENT_NAME_PROTOCOL gGraphicsConsoleComponentName = { + GraphicsConsoleComponentNameGetDriverName, + GraphicsConsoleComponentNameGetControllerName, + "eng" +}; + +STATIC EFI_UNICODE_STRING_TABLE mGraphicsConsoleDriverNameTable[] = { + { + "eng", + (CHAR16 *)L"UGA Console Driver" + }, + { + NULL, + NULL + } +}; + +EFI_STATUS +EFIAPI +GraphicsConsoleComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gGraphicsConsoleComponentName.SupportedLanguages, + mGraphicsConsoleDriverNameTable, + DriverName + ); +} + +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 + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + 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. + 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. + + Returns: + 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. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return EFI_UNSUPPORTED; +} diff --git a/EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/ComponentName.h b/EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/ComponentName.h new file mode 100644 index 0000000000..c5999b64d1 --- /dev/null +++ b/EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/ComponentName.h @@ -0,0 +1,51 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ComponentName.h + +Abstract: + + +Revision History + +--*/ + +#ifndef _GRAPHICS_CONSOLE_COMPONENT_NAME_H +#define _GRAPHICS_CONSOLE_COMPONENT_NAME_H + +extern EFI_COMPONENT_NAME_PROTOCOL gGraphicsConsoleComponentName; + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +GraphicsConsoleComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +; + +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 + ) +; + +#endif diff --git a/EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/GraphicsConsole.c b/EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/GraphicsConsole.c new file mode 100644 index 0000000000..a475723dfd --- /dev/null +++ b/EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/GraphicsConsole.c @@ -0,0 +1,1566 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + GraphicsConsole.c + +Abstract: + + This is the main routine for initializing the Graphics Console support routines. + +Revision History + +Remaining Tasks + Add all standard Glyphs from EFI 1.02 Specification + Implement optimal automatic Mode creation algorithm + Solve palette issues for mixed graphics and text + When does this protocol reset the palette? + +--*/ + +#include "GraphicsConsole.h" + +// +// Function Prototypes +// +EFI_STATUS +EFIAPI +GraphicsConsoleControllerDriverSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +GraphicsConsoleControllerDriverStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +GraphicsConsoleControllerDriverStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +EFI_STATUS +GetTextColors ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + OUT EFI_UGA_PIXEL *Foreground, + OUT EFI_UGA_PIXEL *Background + ); + +EFI_STATUS +DrawUnicodeWeightAtCursor ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN CHAR16 UnicodeWeight + ); + +EFI_STATUS +DrawUnicodeWeightAtCursorN ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN CHAR16 *UnicodeWeight, + IN UINTN Count + ); + +EFI_STATUS +EraseCursor ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This + ); + +// +// Globals +// +GRAPHICS_CONSOLE_DEV mGraphicsConsoleDevTemplate = { + GRAPHICS_CONSOLE_DEV_SIGNATURE, + (EFI_UGA_DRAW_PROTOCOL *) NULL, + { + GraphicsConsoleConOutReset, + GraphicsConsoleConOutOutputString, + GraphicsConsoleConOutTestString, + GraphicsConsoleConOutQueryMode, + GraphicsConsoleConOutSetMode, + GraphicsConsoleConOutSetAttribute, + GraphicsConsoleConOutClearScreen, + GraphicsConsoleConOutSetCursorPosition, + GraphicsConsoleConOutEnableCursor, + (EFI_SIMPLE_TEXT_OUTPUT_MODE *) NULL + }, + { + 0, + 0, + EFI_TEXT_ATTR(EFI_LIGHTGRAY, EFI_BLACK), + 0, + 0, + TRUE + }, + { + { 80, 25, 0, 0, 0, 0 }, // Mode 0 + { 0, 0, 0, 0, 0, 0 }, // Mode 1 + { 0, 0, 0, 0, 0, 0 } // Mode 2 + }, + (EFI_UGA_PIXEL *) NULL, + (EFI_HII_HANDLE) 0 +}; + +EFI_HII_PROTOCOL *mHii; + +static CHAR16 mCrLfString[3] = { CHAR_CARRIAGE_RETURN, CHAR_LINEFEED, CHAR_NULL }; + +static EFI_UGA_PIXEL mEfiColors[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 }, // LIGHTBROWN + { 0xff, 0xff, 0xff, 0x00 } // WHITE +}; + +static 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 } +}; + +static CHAR16 SpaceStr[] = { (CHAR16)NARROW_CHAR, ' ', 0 }; + + +EFI_DRIVER_BINDING_PROTOCOL gGraphicsConsoleDriverBinding = { + GraphicsConsoleControllerDriverSupported, + GraphicsConsoleControllerDriverStart, + GraphicsConsoleControllerDriverStop, + 0x10, + NULL, + NULL +}; + +EFI_STATUS +EFIAPI +GraphicsConsoleControllerDriverSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_UGA_DRAW_PROTOCOL *UgaDraw; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + // + // Open the IO Abstraction(s) needed to perform the supported test + // + 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: + gBS->CloseProtocol ( + Controller, + &gEfiUgaDrawProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return Status; +} + +EFI_STATUS +EFIAPI +GraphicsConsoleControllerDriverStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + + Start the controller. + + Arguments: + + This - A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + Controller - The handle of the controller to start. + RemainingDevicePath - A pointer to the remaining portion of a devcie path. + + Returns: + + EFI_SUCCESS - Return successfully. + EFI_OUT_OF_RESOURCES - Out of resources. + +--*/ +{ + EFI_STATUS Status; + GRAPHICS_CONSOLE_DEV *Private; + EFI_HII_PACKAGES *Package; + EFI_HII_FONT_PACK *FontPack; + UINTN NarrowFontSize; + UINT32 HorizontalResolution; + UINT32 VerticalResolution; + UINT32 ColorDepth; + UINT32 RefreshRate; + UINTN MaxMode; + UINTN Columns; + UINTN Rows; + UINT8 *Location; + // + // 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, + &gEfiUgaDrawProtocolGuid, + (VOID **) &Private->UgaDraw, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + goto Error; + } + // + // Get the HII protocol. If Supported() succeeds, do we really + // need to get HII protocol again? + // + Status = EfiLocateHiiProtocol (); + if (EFI_ERROR (Status)) { + goto Error; + } + + NarrowFontSize = ReturnNarrowFontSize (); + + FontPack = AllocateZeroPool (sizeof (EFI_HII_FONT_PACK) + NarrowFontSize); + ASSERT (FontPack); + + FontPack->Header.Length = (UINT32) (sizeof (EFI_HII_FONT_PACK) + NarrowFontSize); + FontPack->Header.Type = EFI_HII_FONT; + FontPack->NumberOfNarrowGlyphs = (UINT16) (NarrowFontSize / sizeof (EFI_NARROW_GLYPH)); + + Location = (UINT8 *) (&FontPack->NumberOfWideGlyphs + sizeof (UINT8)); + CopyMem (Location, UsStdNarrowGlyphData, NarrowFontSize); + + // + // Register our Fonts into the global database + // + Package = PreparePackages (1, NULL, FontPack); + mHii->NewPack (mHii, Package, &(Private->HiiHandle)); + gBS->FreePool (Package); + + // + // Free the font database + // + gBS->FreePool (FontPack); + + // + // If the current mode information can not be retrieved, then attemp to set the default mode + // of 800x600, 32 bit colot, 60 Hz refresh. + // + HorizontalResolution = 800; + VerticalResolution = 600; + ColorDepth = 32; + RefreshRate = 60; + Status = Private->UgaDraw->SetMode ( + Private->UgaDraw, + HorizontalResolution, + VerticalResolution, + ColorDepth, + RefreshRate + ); + if (EFI_ERROR (Status)) { + // + // Get the current mode information from the UGA Draw Protocol + // + Status = Private->UgaDraw->GetMode ( + Private->UgaDraw, + &HorizontalResolution, + &VerticalResolution, + &ColorDepth, + &RefreshRate + ); + if (EFI_ERROR (Status)) { + goto Error; + } + } + // + // Compute the maximum number of text Rows and Columns that this current graphics mode can support + // + Columns = HorizontalResolution / GLYPH_WIDTH; + Rows = VerticalResolution / GLYPH_HEIGHT; + + // + // See if the mode is too small to support the required 80x25 text mode + // + if (Columns < 80 || Rows < 25) { + goto Error; + } + // + // Add Mode #0 that must be 80x25 + // + MaxMode = 0; + Private->ModeData[MaxMode].UgaWidth = HorizontalResolution; + Private->ModeData[MaxMode].UgaHeight = VerticalResolution; + Private->ModeData[MaxMode].DeltaX = (HorizontalResolution - (80 * GLYPH_WIDTH)) >> 1; + Private->ModeData[MaxMode].DeltaY = (VerticalResolution - (25 * GLYPH_HEIGHT)) >> 1; + MaxMode++; + + // + // If it is possible to support Mode #1 - 80x50, than add it as an active mode + // + if (Rows >= 50) { + Private->ModeData[MaxMode].UgaWidth = HorizontalResolution; + Private->ModeData[MaxMode].UgaHeight = VerticalResolution; + Private->ModeData[MaxMode].DeltaX = (HorizontalResolution - (80 * GLYPH_WIDTH)) >> 1; + Private->ModeData[MaxMode].DeltaY = (VerticalResolution - (50 * GLYPH_HEIGHT)) >> 1; + MaxMode++; + } + // + // If the graphics mode is 800x600, than add a text mode that uses the entire display + // + if (HorizontalResolution == 800 && VerticalResolution == 600) { + + if (MaxMode < 2) { + Private->ModeData[MaxMode].Columns = 0; + Private->ModeData[MaxMode].Rows = 0; + Private->ModeData[MaxMode].UgaWidth = 800; + Private->ModeData[MaxMode].UgaHeight = 600; + Private->ModeData[MaxMode].DeltaX = 0; + Private->ModeData[MaxMode].DeltaY = 0; + MaxMode++; + } + + Private->ModeData[MaxMode].Columns = 800 / GLYPH_WIDTH; + Private->ModeData[MaxMode].Rows = 600 / GLYPH_HEIGHT; + Private->ModeData[MaxMode].UgaWidth = 800; + Private->ModeData[MaxMode].UgaHeight = 600; + Private->ModeData[MaxMode].DeltaX = (800 % GLYPH_WIDTH) >> 1; + Private->ModeData[MaxMode].DeltaY = (600 % GLYPH_HEIGHT) >> 1; + MaxMode++; + } + // + // Update the maximum number of modes + // + Private->SimpleTextOutputMode.MaxMode = (INT32) MaxMode; + + // + // Determine the number of text modes that this protocol can support + // + Status = GraphicsConsoleConOutSetMode (&Private->SimpleTextOutput, 0); + if (EFI_ERROR (Status)) { + goto Error; + } + + DEBUG_CODE ( + GraphicsConsoleConOutOutputString (&Private->SimpleTextOutput, (CHAR16 *)L"Graphics Console Started\n\r"); + ); + + // + // Install protocol interfaces for the Graphics Console device. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &Controller, + &gEfiSimpleTextOutProtocolGuid, + &Private->SimpleTextOutput, + NULL + ); + +Error: + if (EFI_ERROR (Status)) { + // + // Close the UGA IO Protocol + // + gBS->CloseProtocol ( + Controller, + &gEfiUgaDrawProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + // + // Free private data + // + if (Private != NULL) { + gBS->FreePool (Private->LineBuffer); + gBS->FreePool (Private); + } + } + + return Status; +} + +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_OUT_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 UGA IO Protocol + // + gBS->CloseProtocol ( + Controller, + &gEfiUgaDrawProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + // + // Remove the font pack + // + mHii->RemovePack (mHii, Private->HiiHandle); + + // + // Free our instance data + // + if (Private != NULL) { + gBS->FreePool (Private->LineBuffer); + gBS->FreePool (Private); + } + } + + return Status; +} + +EFI_STATUS +EfiLocateHiiProtocol ( + VOID + ) +/*++ + + Routine Description: + Find if the HII protocol is available. If yes, locate the HII protocol + + Arguments: + + Returns: + +--*/ +{ + EFI_HANDLE Handle; + UINTN Size; + EFI_STATUS Status; + + // + // There should only be one - so buffer size is this + // + Size = sizeof (EFI_HANDLE); + + Status = gBS->LocateHandle ( + ByProtocol, + &gEfiHiiProtocolGuid, + NULL, + &Size, + &Handle + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->HandleProtocol ( + Handle, + &gEfiHiiProtocolGuid, + (VOID **)&mHii + ); + + return Status; +} +// +// Body of the STO functions +// +EFI_STATUS +EFIAPI +GraphicsConsoleConOutReset ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + Routine Description: + + 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. + + Arguments: + + This - Indicates the calling context. + + ExtendedVerification - Indicates that the driver may perform a more exhaustive + verification operation of the device during reset. + + Returns: + + EFI_SUCCESS + The reset operation succeeds. + + EFI_DEVICE_ERROR + The Graphics Console is not functioning correctly + +--*/ +{ + This->SetAttribute (This, EFI_TEXT_ATTR (This->Mode->Attribute & 0x0F, EFI_BACKGROUND_BLACK)); + return This->SetMode (This, 0); +} + +EFI_STATUS +EFIAPI +GraphicsConsoleConOutOutputString ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN CHAR16 *WString + ) +/*++ + Routine Description: + + Implements SIMPLE_TEXT_OUTPUT.OutputString(). + The Unicode string will be converted to Glyphs and will be + sent to the Graphics Console. + + + Arguments: + + This - Indicates the calling context. + + WString - The Null-terminated Unicode string to be displayed on + the Graphics Console. + + Returns: + + EFI_SUCCESS + The string is output successfully. + + EFI_DEVICE_ERROR + The Graphics Console failed to send the string out. + + EFI_WARN_UNKNOWN_GLYPH + Indicates that some of the characters in the Unicode string could not + be rendered and are skipped. + +--*/ +{ + GRAPHICS_CONSOLE_DEV *Private; + EFI_UGA_DRAW_PROTOCOL *UgaDraw; + INTN Mode; + UINTN MaxColumn; + UINTN MaxRow; + UINTN Width; + UINTN Height; + UINTN Delta; + EFI_STATUS Status; + BOOLEAN Warning; + EFI_UGA_PIXEL Foreground; + EFI_UGA_PIXEL Background; + UINTN DeltaX; + UINTN DeltaY; + UINTN Count; + UINTN Index; + INT32 OriginAttribute; + + // + // Current mode + // + Mode = This->Mode->Mode; + Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (This); + UgaDraw = Private->UgaDraw; + + MaxColumn = Private->ModeData[Mode].Columns; + MaxRow = Private->ModeData[Mode].Rows; + DeltaX = Private->ModeData[Mode].DeltaX; + DeltaY = Private->ModeData[Mode].DeltaY; + Width = MaxColumn * GLYPH_WIDTH; + Height = (MaxRow - 1) * GLYPH_HEIGHT; + Delta = Width * sizeof (EFI_UGA_PIXEL); + + // + // The Attributes won't change when during the time OutputString is called + // + GetTextColors (This, &Foreground, &Background); + + EraseCursor (This); + + Warning = FALSE; + + // + // Backup attribute + // + OriginAttribute = This->Mode->Attribute; + + while (*WString) { + + 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); + EraseCursor (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); + EraseCursor (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)) { + // + // Scroll Screen Up One Row + // + UgaDraw->Blt ( + UgaDraw, + NULL, + EfiUgaVideoToVideo, + DeltaX, + DeltaY + GLYPH_HEIGHT, + DeltaX, + DeltaY, + Width, + Height, + Delta + ); + + // + // Print Blank Line at last line + // + UgaDraw->Blt ( + UgaDraw, + &Background, + EfiUgaVideoFill, + 0, + 0, + DeltaX, + DeltaY + Height, + Width, + 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) { + break; + } + + if (WString[Count] == CHAR_BACKSPACE) { + break; + } + + if (WString[Count] == CHAR_LINEFEED) { + break; + } + + if (WString[Count] == CHAR_CARRIAGE_RETURN) { + break; + } + + if (WString[Count] == WIDE_CHAR) { + break; + } + + if (WString[Count] == NARROW_CHAR) { + break; + } + // + // Is the wide attribute on? + // + if (This->Mode->Attribute & EFI_WIDE_ATTRIBUTE) { + // + // 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) { + EraseCursor (This); + This->OutputString (This, mCrLfString); + EraseCursor (This); + } + } + } + + This->Mode->Attribute = OriginAttribute; + + EraseCursor (This); + + if (Warning) { + return EFI_WARN_UNKNOWN_GLYPH; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +GraphicsConsoleConOutTestString ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN CHAR16 *WString + ) +/*++ + Routine Description: + + 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. + + + Arguments: + + This - Indicates the calling context. + + WString - The Null-terminated Unicode string to be tested. + + Returns: + + EFI_SUCCESS + The Graphics Console is capable of rendering the output string. + + EFI_UNSUPPORTED + Some of the characters in the Unicode string cannot be rendered. + +--*/ +{ + EFI_STATUS Status; + UINT16 GlyphWidth; + UINT32 GlyphStatus; + UINT16 Count; + GRAPHICS_CONSOLE_DEV *Private; + GLYPH_UNION *Glyph; + + Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (This); + GlyphStatus = 0; + Count = 0; + + while (WString[Count]) { + Status = mHii->GetGlyph ( + mHii, + WString, + &Count, + (UINT8 **) &Glyph, + &GlyphWidth, + &GlyphStatus + ); + + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +GraphicsConsoleConOutQueryMode ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN UINTN ModeNumber, + OUT UINTN *Columns, + OUT UINTN *Rows + ) +/*++ + Routine Description: + + 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. + + + Arguments: + + This - Indicates the calling context. + + ModeNumber - The mode number to return information on. + + Columns - The returned columns of the requested mode. + + Rows - The returned rows of the requested mode. + + Returns: + + EFI_SUCCESS + The requested mode information is returned. + + EFI_UNSUPPORTED + The mode number is not valid. + +--*/ +{ + GRAPHICS_CONSOLE_DEV *Private; + + if (ModeNumber >= (UINTN) This->Mode->MaxMode) { + return EFI_UNSUPPORTED; + } + + Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (This); + + *Columns = Private->ModeData[ModeNumber].Columns; + *Rows = Private->ModeData[ModeNumber].Rows; + + if (*Columns <= 0 && *Rows <= 0) { + return EFI_UNSUPPORTED; + + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +GraphicsConsoleConOutSetMode ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN UINTN ModeNumber + ) +/*++ + Routine Description: + + Implements SIMPLE_TEXT_OUTPUT.SetMode(). + Set the Graphics Console to a specified mode. + In this driver, we only support mode 0. + + Arguments: + + This - Indicates the calling context. + + ModeNumber - The text mode to set. + + Returns: + + EFI_SUCCESS + The requested text mode is set. + + EFI_DEVICE_ERROR + The requested text mode cannot be set because of Graphics Console device error. + + EFI_UNSUPPORTED + The text mode number is not valid. + +--*/ +{ + EFI_STATUS Status; + GRAPHICS_CONSOLE_DEV *Private; + EFI_UGA_DRAW_PROTOCOL *UgaDraw; + GRAPHICS_CONSOLE_MODE_DATA *ModeData; + EFI_UGA_PIXEL *NewLineBuffer; + UINT32 HorizontalResolution; + UINT32 VerticalResolution; + UINT32 ColorDepth; + UINT32 RefreshRate; + + Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (This); + UgaDraw = Private->UgaDraw; + ModeData = &(Private->ModeData[ModeNumber]); + + // + // Make sure the requested mode number is supported + // + if (ModeNumber >= (UINTN) This->Mode->MaxMode) { + return EFI_UNSUPPORTED; + } + + if (ModeData->Columns <= 0 && ModeData->Rows <= 0) { + return EFI_UNSUPPORTED; + } + // + // Attempt to allocate a line buffer for the requested mode number + // + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (EFI_UGA_PIXEL) * ModeData->Columns * GLYPH_WIDTH * GLYPH_HEIGHT, + (VOID **) &NewLineBuffer + ); + if (EFI_ERROR (Status)) { + // + // 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 + // + return Status; + } + // + // If the mode has been set at least one other time, then LineBuffer will not be NULL + // + if (Private->LineBuffer != NULL) { + // + // Clear the current text window on the current graphics console + // + This->ClearScreen (This); + + // + // If the new mode is the same as the old mode, then just return EFI_SUCCESS + // + if ((INT32) ModeNumber == This->Mode->Mode) { + gBS->FreePool (NewLineBuffer); + return EFI_SUCCESS; + } + // + // Otherwise, the size of the text console and/or the UGA mode will be changed, + // so turn off the cursor, and free the LineBuffer for the current mode + // + This->EnableCursor (This, FALSE); + + gBS->FreePool (Private->LineBuffer); + } + // + // Assign the current line buffer to the newly allocated line buffer + // + Private->LineBuffer = NewLineBuffer; + + // + // Get the current UGA Draw mode information + // + Status = UgaDraw->GetMode ( + UgaDraw, + &HorizontalResolution, + &VerticalResolution, + &ColorDepth, + &RefreshRate + ); + if (EFI_ERROR (Status) || HorizontalResolution != ModeData->UgaWidth || VerticalResolution != ModeData->UgaHeight) { + // + // Either no graphics mode is currently set, or it is set to the wrong resolution, so set the new grapghics mode + // + Status = UgaDraw->SetMode ( + UgaDraw, + ModeData->UgaWidth, + ModeData->UgaHeight, + 32, + 60 + ); + if (EFI_ERROR (Status)) { + // + // The mode set operation failed + // + return Status; + } + } else { + // + // The current graphics mode is correct, so simply clear the entire display + // + Status = UgaDraw->Blt ( + UgaDraw, + &mEfiColors[0], + EfiUgaVideoFill, + 0, + 0, + 0, + 0, + ModeData->UgaWidth, + ModeData->UgaHeight, + 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 displat and enable it + // + This->SetCursorPosition (This, 0, 0); + This->EnableCursor (This, TRUE); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +GraphicsConsoleConOutSetAttribute ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN UINTN Attribute + ) +/*++ + Routine Description: + + Implements SIMPLE_TEXT_OUTPUT.SetAttribute(). + + Arguments: + + This - Indicates the calling context. + + Attrubute - The attribute to set. Only bit0..6 are valid, all other bits + are undefined and must be zero. + + Returns: + + EFI_SUCCESS + The requested attribute is set. + + EFI_DEVICE_ERROR + The requested attribute cannot be set due to Graphics Console port error. + + EFI_UNSUPPORTED + The attribute requested is not defined by EFI spec. + +--*/ +{ + if ((Attribute | 0xFF) != 0xFF) { + return EFI_UNSUPPORTED; + } + + if ((INT32) Attribute == This->Mode->Attribute) { + return EFI_SUCCESS; + } + + EraseCursor (This); + + This->Mode->Attribute = (INT32) Attribute; + + EraseCursor (This); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +GraphicsConsoleConOutClearScreen ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This + ) +/*++ + Routine Description: + + Implements SIMPLE_TEXT_OUTPUT.ClearScreen(). + It clears the Graphics Console's display to the + currently selected background color. + + + Arguments: + + This - Indicates the calling context. + + Returns: + + EFI_SUCCESS + The operation completed successfully. + + EFI_DEVICE_ERROR + The Graphics Console cannot be cleared due to Graphics Console device error. + + EFI_UNSUPPORTED + The Graphics Console is not in a valid text mode. + +--*/ +{ + EFI_STATUS Status; + GRAPHICS_CONSOLE_DEV *Private; + GRAPHICS_CONSOLE_MODE_DATA *ModeData; + EFI_UGA_DRAW_PROTOCOL *UgaDraw; + EFI_UGA_PIXEL Foreground; + EFI_UGA_PIXEL Background; + + Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (This); + UgaDraw = Private->UgaDraw; + ModeData = &(Private->ModeData[This->Mode->Mode]); + + GetTextColors (This, &Foreground, &Background); + + Status = UgaDraw->Blt ( + UgaDraw, + &Background, + EfiUgaVideoFill, + 0, + 0, + 0, + 0, + ModeData->UgaWidth, + ModeData->UgaHeight, + 0 + ); + + This->Mode->CursorColumn = 0; + This->Mode->CursorRow = 0; + + EraseCursor (This); + + return Status; +} + +EFI_STATUS +EFIAPI +GraphicsConsoleConOutSetCursorPosition ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN UINTN Column, + IN UINTN Row + ) +/*++ + Routine Description: + + Implements SIMPLE_TEXT_OUTPUT.SetCursorPosition(). + + Arguments: + + This - Indicates the calling context. + + Column - The row to set cursor to. + + Row - The column to set cursor to. + + Returns: + + EFI_SUCCESS + The operation completed successfully. + + EFI_DEVICE_ERROR + The request fails due to Graphics Console device error. + + EFI_UNSUPPORTED + The Graphics Console is not in a valid text mode, or the cursor position + is invalid for current mode. + +--*/ +{ + GRAPHICS_CONSOLE_DEV *Private; + GRAPHICS_CONSOLE_MODE_DATA *ModeData; + + Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (This); + ModeData = &(Private->ModeData[This->Mode->Mode]); + + if ((Column >= ModeData->Columns) || (Row >= ModeData->Rows)) { + return EFI_UNSUPPORTED; + } + + if (((INT32) Column == This->Mode->CursorColumn) && ((INT32) Row == This->Mode->CursorRow)) { + return EFI_SUCCESS; + } + + EraseCursor (This); + + This->Mode->CursorColumn = (INT32) Column; + This->Mode->CursorRow = (INT32) Row; + + EraseCursor (This); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +GraphicsConsoleConOutEnableCursor ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN BOOLEAN Visible + ) +/*++ + Routine Description: + + Implements SIMPLE_TEXT_OUTPUT.EnableCursor(). + In this driver, the cursor cannot be hidden. + + Arguments: + + This - Indicates the calling context. + + Visible - If TRUE, the cursor is set to be visible, + If FALSE, the cursor is set to be invisible. + + Returns: + + EFI_SUCCESS + The request is valid. + + EFI_UNSUPPORTED + The Graphics Console does not support a hidden cursor. + +--*/ +{ + EraseCursor (This); + + This->Mode->CursorVisible = Visible; + + EraseCursor (This); + + return EFI_SUCCESS; +} + +EFI_STATUS +GetTextColors ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + OUT EFI_UGA_PIXEL *Foreground, + OUT EFI_UGA_PIXEL *Background + ) +{ + INTN Attribute; + + Attribute = This->Mode->Attribute & 0x7F; + + *Foreground = mEfiColors[Attribute & 0x0f]; + *Background = mEfiColors[Attribute >> 4]; + + return EFI_SUCCESS; +} + +EFI_STATUS +DrawUnicodeWeightAtCursorN ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN CHAR16 *UnicodeWeight, + IN UINTN Count + ) +{ + GRAPHICS_CONSOLE_DEV *Private; + EFI_STATUS Status; + EFI_STATUS ReturnStatus; + GLYPH_UNION *Glyph; + GLYPH_UNION GlyphData; + INTN GlyphX; + INTN GlyphY; + EFI_UGA_DRAW_PROTOCOL *UgaDraw; + EFI_UGA_PIXEL Foreground; + EFI_UGA_PIXEL Background; + UINTN Index; + UINTN ArrayIndex; + UINTN Counts; + UINT16 GlyphWidth; + UINT32 GlyphStatus; + + Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (This); + + ReturnStatus = EFI_SUCCESS; + GlyphStatus = 0; + GlyphWidth = 0x08; + + GetTextColors (This, &Foreground, &Background); + + Index = 0; + ArrayIndex = 0; + while (Index < Count) { + if (This->Mode->Attribute & EFI_WIDE_ATTRIBUTE) { + GlyphStatus = WIDE_CHAR; + } else { + GlyphStatus = NARROW_CHAR; + } + + Status = mHii->GetGlyph ( + mHii, + UnicodeWeight, + (UINT16 *) &Index, + (UINT8 **) &Glyph, + &GlyphWidth, + &GlyphStatus + ); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + + Counts = 0; + + CopyMem (&GlyphData, Glyph, sizeof (GLYPH_UNION)); + + do { + // + // We are creating the second half of the wide character's BLT buffer + // + if (GlyphWidth == 0x10 && Counts == 1) { + CopyMem (&GlyphData.NarrowGlyph.GlyphCol1, &Glyph->WideGlyph.GlyphCol2, sizeof (Glyph->WideGlyph.GlyphCol2)); + } + + Counts++; + + if (GlyphWidth == 0x10) { + mHii->GlyphToBlt ( + mHii, + (UINT8 *) &GlyphData, + Foreground, + Background, + Count * 2, + GLYPH_WIDTH, + GLYPH_HEIGHT, + &Private->LineBuffer[ArrayIndex * GLYPH_WIDTH] + ); + } else { + mHii->GlyphToBlt ( + mHii, + (UINT8 *) &GlyphData, + Foreground, + Background, + Count, + GLYPH_WIDTH, + GLYPH_HEIGHT, + &Private->LineBuffer[ArrayIndex * GLYPH_WIDTH] + ); + } + + ArrayIndex++; + + } while (Counts < 2 && GlyphWidth == 0x10); + + } + // + // If we are printing Wide characters, treat the BLT as if it is twice as many characters + // + if (GlyphWidth == 0x10) { + Count = Count * 2; + } + // + // Blt a character to the screen + // + GlyphX = This->Mode->CursorColumn * GLYPH_WIDTH; + GlyphY = This->Mode->CursorRow * GLYPH_HEIGHT; + UgaDraw = Private->UgaDraw; + UgaDraw->Blt ( + UgaDraw, + Private->LineBuffer, + EfiUgaBltBufferToVideo, + 0, + 0, + GlyphX + Private->ModeData[This->Mode->Mode].DeltaX, + GlyphY + Private->ModeData[This->Mode->Mode].DeltaY, + GLYPH_WIDTH * Count, + GLYPH_HEIGHT, + GLYPH_WIDTH * Count * sizeof (EFI_UGA_PIXEL) + ); + + return ReturnStatus; +} + +EFI_STATUS +EraseCursor ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This + ) +{ + GRAPHICS_CONSOLE_DEV *Private; + EFI_SIMPLE_TEXT_OUTPUT_MODE *CurrentMode; + INTN GlyphX; + INTN GlyphY; + EFI_UGA_DRAW_PROTOCOL *UgaDraw; + EFI_UGA_PIXEL_UNION Foreground; + EFI_UGA_PIXEL_UNION Background; + EFI_UGA_PIXEL_UNION BltChar[GLYPH_HEIGHT][GLYPH_WIDTH]; + UINTN X; + UINTN Y; + + CurrentMode = This->Mode; + + if (!CurrentMode->CursorVisible) { + return EFI_SUCCESS; + } + + Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (This); + UgaDraw = Private->UgaDraw; + + // + // BUGBUG - we need to think about what to do with wide and narrow character deletions. + // + // + // Blt a character to the screen + // + GlyphX = (CurrentMode->CursorColumn * GLYPH_WIDTH) + Private->ModeData[CurrentMode->Mode].DeltaX; + GlyphY = (CurrentMode->CursorRow * GLYPH_HEIGHT) + Private->ModeData[CurrentMode->Mode].DeltaY; + UgaDraw->Blt ( + UgaDraw, + (EFI_UGA_PIXEL *) BltChar, + EfiUgaVideoToBltBuffer, + GlyphX, + GlyphY, + 0, + 0, + GLYPH_WIDTH, + GLYPH_HEIGHT, + GLYPH_WIDTH * sizeof (EFI_UGA_PIXEL) + ); + + GetTextColors (This, &Foreground.Pixel, &Background.Pixel); + + // + // Convert Monochrome bitmap of the Glyph to BltBuffer structure + // + for (Y = 0; Y < GLYPH_HEIGHT; Y++) { + for (X = 0; X < GLYPH_WIDTH; X++) { + if ((mCursorGlyph.GlyphCol1[Y] & (1 << X)) != 0) { + BltChar[Y][GLYPH_WIDTH - X - 1].Raw ^= Foreground.Raw; + } + } + } + + UgaDraw->Blt ( + UgaDraw, + (EFI_UGA_PIXEL *) BltChar, + EfiUgaBltBufferToVideo, + 0, + 0, + GlyphX, + GlyphY, + GLYPH_WIDTH, + GLYPH_HEIGHT, + GLYPH_WIDTH * sizeof (EFI_UGA_PIXEL) + ); + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/GraphicsConsole.h b/EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/GraphicsConsole.h new file mode 100644 index 0000000000..cfbbbb2fa2 --- /dev/null +++ b/EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/GraphicsConsole.h @@ -0,0 +1,160 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + GraphicsConsole.h + +Abstract: + + +Revision History + +--*/ + +#ifndef _GRAPHICS_CONSOLE_H +#define _GRAPHICS_CONSOLE_H + + +#include "ComponentName.h" + +// +// Glyph database +// +#define GLYPH_WIDTH 8 +#define GLYPH_HEIGHT 19 + +typedef union { + EFI_NARROW_GLYPH NarrowGlyph; + EFI_WIDE_GLYPH WideGlyph; +} GLYPH_UNION; + +extern EFI_NARROW_GLYPH UsStdNarrowGlyphData[]; +extern EFI_WIDE_GLYPH UsStdWideGlyphData[]; + +// +// Device Structure +// +#define GRAPHICS_CONSOLE_DEV_SIGNATURE EFI_SIGNATURE_32 ('g', 's', 't', 'o') + +typedef struct { + UINTN Columns; + UINTN Rows; + INTN DeltaX; + INTN DeltaY; + UINT32 UgaWidth; + UINT32 UgaHeight; +} GRAPHICS_CONSOLE_MODE_DATA; + +#define GRAPHICS_MAX_MODE 3 + +typedef struct { + UINTN Signature; + EFI_UGA_DRAW_PROTOCOL *UgaDraw; + EFI_SIMPLE_TEXT_OUT_PROTOCOL SimpleTextOutput; + EFI_SIMPLE_TEXT_OUTPUT_MODE SimpleTextOutputMode; + GRAPHICS_CONSOLE_MODE_DATA ModeData[GRAPHICS_MAX_MODE]; + EFI_UGA_PIXEL *LineBuffer; + EFI_HII_HANDLE HiiHandle; +} GRAPHICS_CONSOLE_DEV; + +#define GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS(a) \ + CR (a, GRAPHICS_CONSOLE_DEV, SimpleTextOutput, GRAPHICS_CONSOLE_DEV_SIGNATURE) + +// +// Global Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gGraphicsConsoleDriverBinding; + +// +// Prototypes +// +UINTN +ReturnNarrowFontSize ( + VOID + ); + +UINTN +ReturnWideFontSize ( + VOID + ); + +EFI_STATUS +EFIAPI +GraphicsConsoleConOutReset ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +EFI_STATUS +EFIAPI +GraphicsConsoleConOutOutputString ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN CHAR16 *WString + ); + +EFI_STATUS +EFIAPI +GraphicsConsoleConOutTestString ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN CHAR16 *WString + ); + +EFI_STATUS +EFIAPI +GraphicsConsoleConOutQueryMode ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN UINTN ModeNumber, + OUT UINTN *Columns, + OUT UINTN *Rows + ); + +EFI_STATUS +EFIAPI +GraphicsConsoleConOutSetMode ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN UINTN ModeNumber + ); + +EFI_STATUS +EFIAPI +GraphicsConsoleConOutSetAttribute ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN UINTN Attribute + ); + +EFI_STATUS +EFIAPI +GraphicsConsoleConOutClearScreen ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This + ); + +EFI_STATUS +EFIAPI +GraphicsConsoleConOutSetCursorPosition ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN UINTN Column, + IN UINTN Row + ); + +EFI_STATUS +EFIAPI +GraphicsConsoleConOutEnableCursor ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN BOOLEAN Visible + ); + +EFI_STATUS +EfiLocateHiiProtocol ( + VOID + ); + +#endif diff --git a/EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/GraphicsConsole.mbd b/EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/GraphicsConsole.mbd new file mode 100644 index 0000000000..4b240ac60b --- /dev/null +++ b/EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/GraphicsConsole.mbd @@ -0,0 +1,42 @@ + + + + + GraphicsConsole + CCCB0C28-4B24-11d5-9A5A-0090273FC14D + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiLib + UefiMemoryLib + HiiLib + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + BaseLib + DxeMemoryAllocationLib + + diff --git a/EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/GraphicsConsole.msa b/EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/GraphicsConsole.msa new file mode 100644 index 0000000000..b919c7dea2 --- /dev/null +++ b/EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/GraphicsConsole.msa @@ -0,0 +1,69 @@ + + + + + GraphicsConsole + DXE_DRIVER + BS_DRIVER + CCCB0C28-4B24-11d5-9A5A-0090273FC14D + 0 + Component description file for GraphicsConsole module + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + BaseLib + UefiLib + HiiLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + + + GraphicsConsole.h + GraphicsConsole.c + LaffStd.c + ComponentName.c + + + MdePkg + + + UgaDraw + Hii + SimpleTextOut + DevicePath + + + + + + + gGraphicsConsoleDriverBinding + gGraphicsConsoleComponentName + + + diff --git a/EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/LaffStd.c b/EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/LaffStd.c new file mode 100644 index 0000000000..ac8dd16833 --- /dev/null +++ b/EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/LaffStd.c @@ -0,0 +1,290 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + LaffStd.c + +Abstract: + + +Revision History + +--*/ + +#include "GraphicsConsole.h" + +EFI_NARROW_GLYPH UsStdNarrowGlyphData[] = { + // + // 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 +}; + +UINTN +ReturnNarrowFontSize ( + VOID + ) +{ + // + // I need the size of this outside of this file, so here is a stub function to do that for me + // + return sizeof (UsStdNarrowGlyphData); +} diff --git a/EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/build.xml b/EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/build.xml new file mode 100644 index 0000000000..896302767b --- /dev/null +++ b/EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Universal/Console/Terminal/Dxe/ComponentName.c b/EdkModulePkg/Universal/Console/Terminal/Dxe/ComponentName.c new file mode 100644 index 0000000000..cc925b13c9 --- /dev/null +++ b/EdkModulePkg/Universal/Console/Terminal/Dxe/ComponentName.c @@ -0,0 +1,194 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ComponentName.c + +Abstract: + +--*/ + + +#include "Terminal.h" + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +TerminalComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +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 Component Name Protocol +// +EFI_COMPONENT_NAME_PROTOCOL gTerminalComponentName = { + TerminalComponentNameGetDriverName, + TerminalComponentNameGetControllerName, + "eng" +}; + +static EFI_UNICODE_STRING_TABLE mTerminalDriverNameTable[] = { + { + "eng", + (CHAR16 *) L"Serial Terminal Driver" + }, + { + NULL, + NULL + } +}; + +EFI_STATUS +EFIAPI +TerminalComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gTerminalComponentName.SupportedLanguages, + mTerminalDriverNameTable, + DriverName + ); +} + +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 + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + 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. + 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. + + Returns: + 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. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + EFI_STATUS Status; + EFI_SIMPLE_TEXT_OUT_PROTOCOL *SimpleTextOutput; + TERMINAL_DEV *TerminalDevice; + + // + // This is a bus driver, so ChildHandle can not be NULL. + // + if (ChildHandle == NULL) { + return EFI_UNSUPPORTED; + } + // + // 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 LookupUnicodeString ( + Language, + gTerminalComponentName.SupportedLanguages, + TerminalDevice->ControllerNameTable, + ControllerName + ); +} diff --git a/EdkModulePkg/Universal/Console/Terminal/Dxe/Terminal.c b/EdkModulePkg/Universal/Console/Terminal/Dxe/Terminal.c new file mode 100644 index 0000000000..d462e05d0c --- /dev/null +++ b/EdkModulePkg/Universal/Console/Terminal/Dxe/Terminal.c @@ -0,0 +1,1214 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Terminal.c + +Abstract: + +Revision History: + +--*/ + + +#include "Terminal.h" +#include + +// +// Function Prototypes +// +EFI_STATUS +EFIAPI +TerminalDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +TerminalDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +TerminalDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +// +// Globals +// +EFI_DRIVER_BINDING_PROTOCOL gTerminalDriverBinding = { + TerminalDriverBindingSupported, + TerminalDriverBindingStart, + TerminalDriverBindingStop, + 0x10, + NULL, + NULL +}; + + +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) { + + 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+ and VT-UTF8 terminal types + // + if (!CompareGuid (&Node->Guid, &gEfiPcAnsiGuid) && + !CompareGuid (&Node->Guid, &gEfiVT100Guid) && + !CompareGuid (&Node->Guid, &gEfiVT100PlusGuid) && + !CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) { + + return EFI_UNSUPPORTED; + } + } + // + // Open the IO Abstraction(s) 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; + } + + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + // + // 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 + ); + + return Status; +} + +EFI_STATUS +EFIAPI +TerminalDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + + Start the controller. + + Arguments: + + This - A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + Controller - The handle of the controller to start. + RemainingDevicePath - A pointer to the remaining portion of a devcie path. + + Returns: + + EFI_SUCCESS. + +--*/ +{ + EFI_STATUS Status; + EFI_SERIAL_IO_PROTOCOL *SerialIo; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + VENDOR_DEVICE_PATH *Node; + VENDOR_DEVICE_PATH *DefaultNode; + EFI_SERIAL_IO_MODE *Mode; + UINTN SerialInTimeOut; + TERMINAL_DEV *TerminalDevice; + UINT8 TerminalType; + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer; + UINTN EntryCount; + UINTN Index; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + TerminalDevice = NULL; + DefaultNode = NULL; + // + // 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 + ); + if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { + return Status; + } + // + // Report that the remote terminal is being enabled + // + DevicePath = ParentDevicePath; + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_PC_ENABLE, + DevicePath + ); + + // + // 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 + ); + if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { + return Status; + } + + if (Status != EFI_ALREADY_STARTED) { + // + // If Serial I/O is not already open by this driver, then tag the handle + // with the Terminal Driver GUID and update the ConInDev, ConOutDev, and + // StdErrDev variables with the list of possible terminal types on this + // serial port. + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiCallerIdGuid, + NULL, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (EFI_ERROR (Status)) { + Status = gBS->InstallMultipleProtocolInterfaces ( + &Controller, + &gEfiCallerIdGuid, + DuplicateDevicePath (ParentDevicePath), + NULL + ); + if (EFI_ERROR (Status)) { + goto Error; + } + // + // if the serial device is a hot plug device, do not update the + // ConInDev, ConOutDev, and StdErrDev variables. + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiHotPlugDeviceGuid, + NULL, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (EFI_ERROR (Status)) { + TerminalUpdateConsoleDevVariable ((CHAR16 *)VarConsoleInpDev, ParentDevicePath); + TerminalUpdateConsoleDevVariable ((CHAR16 *)VarConsoleOutDev, ParentDevicePath); + TerminalUpdateConsoleDevVariable ((CHAR16 *)VarErrorOutDev, ParentDevicePath); + } + } + } + // + // Make sure a child handle does not already exist. This driver can only + // produce one child per serial port. + // + Status = gBS->OpenProtocolInformation ( + Controller, + &gEfiSerialIoProtocolGuid, + &OpenInfoBuffer, + &EntryCount + ); + if (!EFI_ERROR (Status)) { + Status = EFI_SUCCESS; + for (Index = 0; Index < EntryCount; Index++) { + if (OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) { + Status = EFI_ALREADY_STARTED; + } + } + + gBS->FreePool (OpenInfoBuffer); + if (EFI_ERROR (Status)) { + return Status; + } + } + // + // If RemainingDevicePath is NULL, then create default device path node + // + if (RemainingDevicePath == NULL) { + DefaultNode = AllocatePool (sizeof (VENDOR_DEVICE_PATH)); + if (DefaultNode == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + + CopyMem (&DefaultNode->Guid, &gEfiPcAnsiGuid, sizeof (EFI_GUID)); + RemainingDevicePath = (EFI_DEVICE_PATH_PROTOCOL*) DefaultNode; + } + // + // Use the RemainingDevicePath to determine the terminal type + // + Node = (VENDOR_DEVICE_PATH *) RemainingDevicePath; + + if (CompareGuid (&Node->Guid, &gEfiPcAnsiGuid)) { + + TerminalType = PcAnsiType; + + } else if (CompareGuid (&Node->Guid, &gEfiVT100Guid)) { + + TerminalType = VT100Type; + + } else if (CompareGuid (&Node->Guid, &gEfiVT100PlusGuid)) { + + TerminalType = VT100PlusType; + + } else if (CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) { + + TerminalType = VTUTF8Type; + + } else { + goto Error; + } + // + // Initialize the Terminal Dev + // + TerminalDevice = AllocatePool (sizeof (TERMINAL_DEV)); + if (TerminalDevice == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + + ZeroMem (TerminalDevice, sizeof (TERMINAL_DEV)); + + TerminalDevice->Signature = TERMINAL_DEV_SIGNATURE; + + TerminalDevice->TerminalType = TerminalType; + + TerminalDevice->SerialIo = SerialIo; + + // + // Simple Input Protocol + // + TerminalDevice->SimpleInput.Reset = TerminalConInReset; + TerminalDevice->SimpleInput.ReadKeyStroke = TerminalConInReadKeyStroke; + + Status = gBS->CreateEvent ( + EFI_EVENT_NOTIFY_WAIT, + EFI_TPL_NOTIFY, + TerminalConInWaitForKey, + &TerminalDevice->SimpleInput, + &TerminalDevice->SimpleInput.WaitForKey + ); + if (EFI_ERROR (Status)) { + goto Error; + } + // + // initialize the FIFO buffer used for accommodating + // the pre-read pending characters + // + InitializeRawFiFo (TerminalDevice); + InitializeUnicodeFiFo (TerminalDevice); + InitializeEfiKeyFiFo (TerminalDevice); + + // + // 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, + Mode->Parity, + (UINT8) Mode->DataBits, + 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; + } + // + // Build the device path for the child device + // + Status = SetTerminalDevicePath ( + TerminalDevice->TerminalType, + ParentDevicePath, + &TerminalDevice->DevicePath + ); + if (EFI_ERROR (Status)) { + goto Error; + } + + DevicePath = TerminalDevice->DevicePath; + + Status = TerminalDevice->SimpleInput.Reset ( + &TerminalDevice->SimpleInput, + FALSE + ); + if (EFI_ERROR (Status)) { + // + // Need to report Error Code first + // + goto ReportError; + } + // + // Simple Text Output Protocol + // + TerminalDevice->SimpleTextOutput.Reset = TerminalConOutReset; + TerminalDevice->SimpleTextOutput.OutputString = TerminalConOutOutputString; + TerminalDevice->SimpleTextOutput.TestString = TerminalConOutTestString; + TerminalDevice->SimpleTextOutput.QueryMode = TerminalConOutQueryMode; + TerminalDevice->SimpleTextOutput.SetMode = TerminalConOutSetMode; + TerminalDevice->SimpleTextOutput.SetAttribute = TerminalConOutSetAttribute; + TerminalDevice->SimpleTextOutput.ClearScreen = TerminalConOutClearScreen; + TerminalDevice->SimpleTextOutput.SetCursorPosition = TerminalConOutSetCursorPosition; + TerminalDevice->SimpleTextOutput.EnableCursor = TerminalConOutEnableCursor; + TerminalDevice->SimpleTextOutput.Mode = &TerminalDevice->SimpleTextOutputMode; + + TerminalDevice->SimpleTextOutputMode.MaxMode = 1; + // + // For terminal devices, cursor is always visible + // + TerminalDevice->SimpleTextOutputMode.CursorVisible = TRUE; + TerminalDevice->SimpleTextOutputMode.Attribute = EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK); + + Status = TerminalDevice->SimpleTextOutput.Reset ( + &TerminalDevice->SimpleTextOutput, + FALSE + ); + if (EFI_ERROR (Status)) { + goto ReportError; + } + + Status = TerminalDevice->SimpleTextOutput.SetMode ( + &TerminalDevice->SimpleTextOutput, + 0 + ); + if (EFI_ERROR (Status)) { + goto ReportError; + } + + Status = TerminalDevice->SimpleTextOutput.EnableCursor ( + &TerminalDevice->SimpleTextOutput, + TRUE + ); + if (EFI_ERROR (Status)) { + goto ReportError; + } + // + // + // + TerminalDevice->InputState = INPUT_STATE_DEFAULT; + TerminalDevice->ResetState = RESET_STATE_DEFAULT; + + Status = gBS->CreateEvent ( + EFI_EVENT_TIMER, + EFI_TPL_CALLBACK, + NULL, + NULL, + &TerminalDevice->TwoSecondTimeOut + ); + + // + // Build the component name for the child device + // + TerminalDevice->ControllerNameTable = NULL; + switch (TerminalDevice->TerminalType) { + case PcAnsiType: + AddUnicodeString ( + "eng", + gTerminalComponentName.SupportedLanguages, + &TerminalDevice->ControllerNameTable, + (CHAR16 *)L"PC-ANSI Serial Console" + ); + break; + + case VT100Type: + AddUnicodeString ( + "eng", + gTerminalComponentName.SupportedLanguages, + &TerminalDevice->ControllerNameTable, + (CHAR16 *)L"VT-100 Serial Console" + ); + break; + + case VT100PlusType: + AddUnicodeString ( + "eng", + gTerminalComponentName.SupportedLanguages, + &TerminalDevice->ControllerNameTable, + (CHAR16 *)L"VT-100+ Serial Console" + ); + break; + + case VTUTF8Type: + AddUnicodeString ( + "eng", + gTerminalComponentName.SupportedLanguages, + &TerminalDevice->ControllerNameTable, + (CHAR16 *)L"VT-UTF8 Serial Console" + ); + break; + } + // + // Install protocol interfaces for the serial device. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &TerminalDevice->Handle, + &gEfiDevicePathProtocolGuid, + TerminalDevice->DevicePath, + &gEfiSimpleTextInProtocolGuid, + &TerminalDevice->SimpleInput, + &gEfiSimpleTextOutProtocolGuid, + &TerminalDevice->SimpleTextOutput, + NULL + ); + if (EFI_ERROR (Status)) { + goto Error; + } + // + // if the serial device is a hot plug device, attaches the HotPlugGuid + // onto the terminal device handle. + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiHotPlugDeviceGuid, + NULL, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + Status = gBS->InstallMultipleProtocolInterfaces ( + &TerminalDevice->Handle, + &gEfiHotPlugDeviceGuid, + NULL, + NULL + ); + } + // + // Register the Parent-Child relationship via + // EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiSerialIoProtocolGuid, + (VOID **) &TerminalDevice->SerialIo, + This->DriverBindingHandle, + TerminalDevice->Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + if (EFI_ERROR (Status)) { + goto Error; + } + + if (DefaultNode != NULL) { + gBS->FreePool (DefaultNode); + } + + return EFI_SUCCESS; + +ReportError: + // + // Report error code before exiting + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_CONTROLLER_ERROR, + DevicePath + ); + +Error: + // + // Use the Stop() function to free all resources allocated in Start() + // + if (TerminalDevice != NULL) { + + if (TerminalDevice->Handle != NULL) { + This->Stop (This, Controller, 1, &TerminalDevice->Handle); + } else { + + if (TerminalDevice->TwoSecondTimeOut != NULL) { + gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut); + } + + if (TerminalDevice->SimpleInput.WaitForKey != NULL) { + gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey); + } + + if (TerminalDevice->ControllerNameTable != NULL) { + FreeUnicodeStringTable (TerminalDevice->ControllerNameTable); + } + + if (TerminalDevice->DevicePath != NULL) { + gBS->FreePool (TerminalDevice->DevicePath); + } + + gBS->FreePool (TerminalDevice); + } + } + + if (DefaultNode != NULL) { + gBS->FreePool (DefaultNode); + } + + This->Stop (This, Controller, 0, NULL); + + return Status; +} + +EFI_STATUS +EFIAPI +TerminalDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + + Routine Description: + + Stop a device controller. + + Arguments: + + This - A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + Controller - A handle to the device being stopped. + NumberOfChildren - The number of child device handles in ChildHandleBuffer. + ChildHandleBuffer - An array of child handles to be freed. + + Returns: + + EFI_SUCCESS - Operation successful. + EFI_DEVICE_ERROR - Devices error. + +--*/ +{ + EFI_STATUS Status; + UINTN Index; + BOOLEAN AllChildrenStopped; + EFI_SIMPLE_TEXT_OUT_PROTOCOL *SimpleTextOutput; + TERMINAL_DEV *TerminalDevice; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_SERIAL_IO_PROTOCOL *SerialIo; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + Status = gBS->HandleProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &DevicePath + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Report that the remote terminal is being disabled + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_PC_DISABLE, + DevicePath + ); + + // + // Complete all outstanding transactions to Controller. + // Don't allow any new transaction to Controller to be started. + // + if (NumberOfChildren == 0) { + // + // Close the bus driver + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiCallerIdGuid, + (VOID **) &ParentDevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + // + // Remove Parent Device Path from + // the Console Device Environment Variables + // + TerminalRemoveConsoleDevVariable ((CHAR16 *)VarConsoleInpDev, ParentDevicePath); + TerminalRemoveConsoleDevVariable ((CHAR16 *)VarConsoleOutDev, ParentDevicePath); + TerminalRemoveConsoleDevVariable ((CHAR16 *)VarErrorOutDev, ParentDevicePath); + + // + // Uninstall the Terminal Driver's GUID Tag from the Serial controller + // + Status = gBS->UninstallMultipleProtocolInterfaces ( + Controller, + &gEfiCallerIdGuid, + ParentDevicePath, + NULL + ); + + // + // Free the ParentDevicePath that was duplicated in Start() + // + if (!EFI_ERROR (Status)) { + gBS->FreePool (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, + &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 { + + if (TerminalDevice->ControllerNameTable != NULL) { + FreeUnicodeStringTable (TerminalDevice->ControllerNameTable); + } + + Status = gBS->OpenProtocol ( + ChildHandleBuffer[Index], + &gEfiHotPlugDeviceGuid, + NULL, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + Status = gBS->UninstallMultipleProtocolInterfaces ( + ChildHandleBuffer[Index], + &gEfiHotPlugDeviceGuid, + NULL, + NULL + ); + } else { + Status = EFI_SUCCESS; + } + + gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut); + gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey); + gBS->FreePool (TerminalDevice->DevicePath); + gBS->FreePool (TerminalDevice); + } + } + + if (EFI_ERROR (Status)) { + AllChildrenStopped = FALSE; + } + } + + if (!AllChildrenStopped) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +VOID +TerminalUpdateConsoleDevVariable ( + IN CHAR16 *VariableName, + IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath + ) +{ + EFI_STATUS Status; + UINTN VariableSize; + UINT8 TerminalType; + EFI_DEVICE_PATH_PROTOCOL *Variable; + EFI_DEVICE_PATH_PROTOCOL *NewVariable; + EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; + + Variable = NULL; + + // + // Get global variable and its size according to the name given. + // + Variable = TerminalGetVariableAndSize ( + VariableName, + &gEfiGlobalVariableGuid, + &VariableSize + ); + // + // Append terminal device path onto the variable. + // + for (TerminalType = PcAnsiType; TerminalType <= VTUTF8Type; TerminalType++) { + SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath); + NewVariable = AppendDevicePathInstance (Variable, TempDevicePath); + if (Variable != NULL) { + gBS->FreePool (Variable); + } + + if (TempDevicePath != NULL) { + gBS->FreePool (TempDevicePath); + } + + Variable = NewVariable; + } + + VariableSize = GetDevicePathSize (Variable); + + Status = gRT->SetVariable ( + VariableName, + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + VariableSize, + Variable + ); + gBS->FreePool (Variable); + + return ; +} + +VOID +TerminalRemoveConsoleDevVariable ( + IN CHAR16 *VariableName, + IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath + ) +/*++ + + Routine Description: + + Remove console device variable. + + Arguments: + + VariableName - A pointer to the variable name. + ParentDevicePath - A pointer to the parent device path. + + Returns: + +--*/ +{ + EFI_STATUS Status; + BOOLEAN FoundOne; + BOOLEAN Match; + UINTN VariableSize; + UINTN InstanceSize; + UINT8 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; + + Variable = NULL; + Instance = NULL; + + // + // Get global variable and its size according to the name given. + // + Variable = TerminalGetVariableAndSize ( + VariableName, + &gEfiGlobalVariableGuid, + &VariableSize + ); + if (Variable == NULL) { + return ; + } + + FoundOne = FALSE; + OriginalVariable = Variable; + NewVariable = NULL; + + // + // Get first device path instance from Variable + // + Instance = GetNextDevicePathInstance (&Variable, &InstanceSize); + if (Instance == NULL) { + gBS->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 = PcAnsiType; TerminalType <= VTUTF8Type; TerminalType++) { + + SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath); + + // + // Compare the genterated device path to the current device path instance + // + if (TempDevicePath != NULL) { + if (CompareMem (Instance, TempDevicePath, InstanceSize) == 0) { + Match = TRUE; + FoundOne = TRUE; + } + + gBS->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) { + gBS->FreePool (SavedNewVariable); + } + } + // + // Get next device path instance from Variable + // + gBS->FreePool (Instance); + Instance = GetNextDevicePathInstance (&Variable, &InstanceSize); + } while (Instance != NULL); + + gBS->FreePool (OriginalVariable); + + if (FoundOne) { + VariableSize = GetDevicePathSize (NewVariable); + + Status = gRT->SetVariable ( + VariableName, + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + VariableSize, + NewVariable + ); + } + + if (NewVariable != NULL) { + gBS->FreePool (NewVariable); + } + + return ; +} + +VOID * +TerminalGetVariableAndSize ( + IN CHAR16 *Name, + IN EFI_GUID *VendorGuid, + OUT UINTN *VariableSize + ) +/*++ + +Routine Description: + Read the EFI variable (VendorGuid/Name) and return a dynamically allocated + buffer, and the size of the buffer. On failure return NULL. + +Arguments: + Name - String part of EFI variable name + + VendorGuid - GUID part of EFI variable name + + VariableSize - Returns the size of the EFI variable that was read + +Returns: + Dynamically allocated memory that contains a copy of the EFI variable. + Caller is repsoncible freeing the buffer. + + NULL - Variable was not read + +--*/ +{ + EFI_STATUS Status; + UINTN BufferSize; + VOID *Buffer; + + Buffer = NULL; + + // + // Pass in a small size buffer to find the actual variable size. + // + BufferSize = 1; + Buffer = AllocatePool (BufferSize); + if (Buffer == NULL) { + *VariableSize = 0; + return NULL; + } + + Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer); + + if (Status == EFI_SUCCESS) { + *VariableSize = BufferSize; + return Buffer; + + } else if (Status == EFI_BUFFER_TOO_SMALL) { + // + // Allocate the buffer to return + // + gBS->FreePool (Buffer); + Buffer = AllocatePool (BufferSize); + if (Buffer == NULL) { + *VariableSize = 0; + return NULL; + } + // + // Read variable into the allocated buffer. + // + Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer); + if (EFI_ERROR (Status)) { + BufferSize = 0; + gBS->FreePool (Buffer); + Buffer = NULL; + } + } else { + // + // Variable not found or other errors met. + // + BufferSize = 0; + gBS->FreePool (Buffer); + Buffer = NULL; + } + + *VariableSize = BufferSize; + return Buffer; +} + +EFI_STATUS +SetTerminalDevicePath ( + IN UINT8 TerminalType, + IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath, + OUT EFI_DEVICE_PATH_PROTOCOL **TerminalDevicePath + ) +{ + VENDOR_DEVICE_PATH Node; + + *TerminalDevicePath = NULL; + Node.Header.Type = MESSAGING_DEVICE_PATH; + Node.Header.SubType = MSG_VENDOR_DP; + + // + // generate terminal device path node according to terminal type. + // + switch (TerminalType) { + + case PcAnsiType: + CopyMem ( + &Node.Guid, + &gEfiPcAnsiGuid, + sizeof (EFI_GUID) + ); + break; + + case VT100Type: + CopyMem ( + &Node.Guid, + &gEfiVT100Guid, + sizeof (EFI_GUID) + ); + break; + + case VT100PlusType: + CopyMem ( + &Node.Guid, + &gEfiVT100PlusGuid, + sizeof (EFI_GUID) + ); + break; + + case VTUTF8Type: + CopyMem ( + &Node.Guid, + &gEfiVTUTF8Guid, + sizeof (EFI_GUID) + ); + break; + + default: + return EFI_UNSUPPORTED; + break; + } + + SetDevicePathNodeLength ( + &Node.Header, + sizeof (VENDOR_DEVICE_PATH) + ); + // + // 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; +} + +VOID +InitializeRawFiFo ( + IN TERMINAL_DEV *TerminalDevice + ) +{ + // + // Make the raw fifo empty. + // + TerminalDevice->RawFiFo.Head = TerminalDevice->RawFiFo.Tail; +} + +VOID +InitializeUnicodeFiFo ( + IN TERMINAL_DEV *TerminalDevice + ) +{ + // + // Make the unicode fifo empty + // + TerminalDevice->UnicodeFiFo.Head = TerminalDevice->UnicodeFiFo.Tail; +} + +VOID +InitializeEfiKeyFiFo ( + IN TERMINAL_DEV *TerminalDevice + ) +{ + // + // Make the efi key fifo empty + // + TerminalDevice->EfiKeyFiFo.Head = TerminalDevice->EfiKeyFiFo.Tail; +} diff --git a/EdkModulePkg/Universal/Console/Terminal/Dxe/Terminal.h b/EdkModulePkg/Universal/Console/Terminal/Dxe/Terminal.h new file mode 100644 index 0000000000..2382d86f7e --- /dev/null +++ b/EdkModulePkg/Universal/Console/Terminal/Dxe/Terminal.h @@ -0,0 +1,506 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + terminal.h + +Abstract: + + +Revision History + +--*/ + +#ifndef _TERMINAL_H +#define _TERMINAL_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; + +#define TERMINAL_DEV_SIGNATURE EFI_SIGNATURE_32 ('t', 'm', 'n', 'l') + +typedef struct { + UINTN Signature; + EFI_HANDLE Handle; + UINT8 TerminalType; + EFI_SERIAL_IO_PROTOCOL *SerialIo; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + VENDOR_DEVICE_PATH Node; + EFI_SIMPLE_TEXT_IN_PROTOCOL SimpleInput; + EFI_SIMPLE_TEXT_OUT_PROTOCOL SimpleTextOutput; + EFI_SIMPLE_TEXT_OUTPUT_MODE SimpleTextOutputMode; + UINTN SerialInTimeOut; + RAW_DATA_FIFO RawFiFo; + UNICODE_FIFO UnicodeFiFo; + EFI_KEY_FIFO EfiKeyFiFo; + EFI_UNICODE_STRING_TABLE *ControllerNameTable; + EFI_EVENT TwoSecondTimeOut; + UINT32 InputState; + UINT32 ResetState; + + // + // 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; +} 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 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) + +typedef union { + UINT8 Utf8_1; + UINT8 Utf8_2[2]; + UINT8 Utf8_3[3]; +} UTF8_CHAR; + +#define PcAnsiType 0 +#define VT100Type 1 +#define VT100PlusType 2 +#define VTUTF8Type 3 + +#define LEFTOPENBRACKET 0x5b // '[' +#define ACAP 0x41 +#define BCAP 0x42 +#define CCAP 0x43 +#define DCAP 0x44 + +#define MODE0_COLUMN_COUNT 80 +#define MODE0_ROW_COUNT 25 + +#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 + +typedef struct { + UINT16 Unicode; + CHAR8 PcAnsi; + CHAR8 Ascii; +} UNICODE_TO_CHAR; + +#define VarConsoleInpDev L"ConInDev" +#define VarConsoleOutDev L"ConOutDev" +#define VarErrorOutDev L"ErrOutDev" + +// +// Global Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gTerminalDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gTerminalComponentName; + +// +// Prototypes +// +EFI_STATUS +EFIAPI +InitializeTerminal ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +; + +EFI_STATUS +EFIAPI +TerminalConInReset ( + IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +; + +EFI_STATUS +EFIAPI +TerminalConInReadKeyStroke ( + IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This, + OUT EFI_INPUT_KEY *Key + ) +; + +VOID +EFIAPI +TerminalConInWaitForKey ( + IN EFI_EVENT Event, + IN VOID *Context + ) +; + +EFI_STATUS +EFIAPI +TerminalConOutReset ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +; + +EFI_STATUS +EFIAPI +TerminalConOutOutputString ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN CHAR16 *WString + ) +; + +EFI_STATUS +EFIAPI +TerminalConOutTestString ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN CHAR16 *WString + ) +; + +EFI_STATUS +EFIAPI +TerminalConOutQueryMode ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN UINTN ModeNumber, + OUT UINTN *Columns, + OUT UINTN *Rows + ) +; + +EFI_STATUS +EFIAPI +TerminalConOutSetMode ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN UINTN ModeNumber + ) +; + +EFI_STATUS +EFIAPI +TerminalConOutSetAttribute ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN UINTN Attribute + ) +; + +EFI_STATUS +EFIAPI +TerminalConOutClearScreen ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This + ) +; + +EFI_STATUS +EFIAPI +TerminalConOutSetCursorPosition ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN UINTN Column, + IN UINTN Row + ) +; + +EFI_STATUS +EFIAPI +TerminalConOutEnableCursor ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN BOOLEAN Visible + ) +; + +// +// internal functions +// +EFI_STATUS +TerminalConInCheckForKey ( + IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This + ) +; + +VOID +TerminalUpdateConsoleDevVariable ( + IN CHAR16 *VariableName, + IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath + ) +; + +VOID +TerminalRemoveConsoleDevVariable ( + IN CHAR16 *VariableName, + IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath + ) +; + +VOID * +TerminalGetVariableAndSize ( + IN CHAR16 *Name, + IN EFI_GUID *VendorGuid, + OUT UINTN *VariableSize + ) +; + +EFI_STATUS +SetTerminalDevicePath ( + IN UINT8 TerminalType, + IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath, + OUT EFI_DEVICE_PATH_PROTOCOL **TerminalDevicePath + ) +; + +VOID +InitializeRawFiFo ( + IN TERMINAL_DEV *TerminalDevice + ) +; + +VOID +InitializeUnicodeFiFo ( + IN TERMINAL_DEV *TerminalDevice + ) +; + +VOID +InitializeEfiKeyFiFo ( + IN TERMINAL_DEV *TerminalDevice + ) +; + +EFI_STATUS +GetOneKeyFromSerial ( + EFI_SERIAL_IO_PROTOCOL *SerialIo, + UINT8 *Input + ) +; + +BOOLEAN +RawFiFoInsertOneKey ( + TERMINAL_DEV *TerminalDevice, + UINT8 Input + ) +; + +BOOLEAN +RawFiFoRemoveOneKey ( + TERMINAL_DEV *TerminalDevice, + UINT8 *Output + ) +; + +BOOLEAN +IsRawFiFoEmpty ( + TERMINAL_DEV *TerminalDevice + ) +; + +BOOLEAN +IsRawFiFoFull ( + TERMINAL_DEV *TerminalDevice + ) +; + +BOOLEAN +EfiKeyFiFoInsertOneKey ( + TERMINAL_DEV *TerminalDevice, + EFI_INPUT_KEY Key + ) +; + +BOOLEAN +EfiKeyFiFoRemoveOneKey ( + TERMINAL_DEV *TerminalDevice, + EFI_INPUT_KEY *Output + ) +; + +BOOLEAN +IsEfiKeyFiFoEmpty ( + TERMINAL_DEV *TerminalDevice + ) +; + +BOOLEAN +IsEfiKeyFiFoFull ( + TERMINAL_DEV *TerminalDevice + ) +; + +BOOLEAN +UnicodeFiFoInsertOneKey ( + TERMINAL_DEV *TerminalDevice, + UINT16 Input + ) +; + +BOOLEAN +UnicodeFiFoRemoveOneKey ( + TERMINAL_DEV *TerminalDevice, + UINT16 *Output + ) +; + +BOOLEAN +IsUnicodeFiFoEmpty ( + TERMINAL_DEV *TerminalDevice + ) +; + +BOOLEAN +IsUnicodeFiFoFull ( + TERMINAL_DEV *TerminalDevice + ) +; + +UINT8 +UnicodeFiFoGetKeyCount ( + TERMINAL_DEV *TerminalDevice + ) +; + +VOID +TranslateRawDataToEfiKey ( + IN TERMINAL_DEV *TerminalDevice + ) +; + +// +// internal functions for PC ANSI +// +VOID +AnsiRawDataToUnicode ( + IN TERMINAL_DEV *PcAnsiDevice + ) +; + +VOID +UnicodeToEfiKey ( + IN TERMINAL_DEV *PcAnsiDevice + ) +; + +EFI_STATUS +AnsiTestString ( + IN TERMINAL_DEV *TerminalDevice, + IN CHAR16 *WString + ) +; + +// +// internal functions for VT100 +// +EFI_STATUS +VT100TestString ( + IN TERMINAL_DEV *VT100Device, + IN CHAR16 *WString + ) +; + +// +// internal functions for VT100Plus +// +EFI_STATUS +VT100PlusTestString ( + IN TERMINAL_DEV *TerminalDevice, + IN CHAR16 *WString + ) +; + +// +// internal functions for VTUTF8 +// +VOID +VTUTF8RawDataToUnicode ( + IN TERMINAL_DEV *VtUtf8Device + ) +; + +EFI_STATUS +VTUTF8TestString ( + IN TERMINAL_DEV *TerminalDevice, + IN CHAR16 *WString + ) +; + +VOID +UnicodeToUtf8 ( + IN CHAR16 Unicode, + OUT UTF8_CHAR *Utf8Char, + OUT UINT8 *ValidBytes + ) +; + +VOID +GetOneValidUtf8Char ( + IN TERMINAL_DEV *Utf8Device, + OUT UTF8_CHAR *Utf8Char, + OUT UINT8 *ValidBytes + ) +; + +VOID +Utf8ToUnicode ( + IN UTF8_CHAR Utf8Char, + IN UINT8 ValidBytes, + OUT CHAR16 *UnicodeChar + ) +; + +// +// functions for boxdraw unicode +// +BOOLEAN +TerminalIsValidTextGraphics ( + IN CHAR16 Graphic, + OUT CHAR8 *PcAnsi, OPTIONAL + OUT CHAR8 *Ascii OPTIONAL + ) +; + +BOOLEAN +TerminalIsValidAscii ( + IN CHAR16 Ascii + ) +; + +BOOLEAN +TerminalIsValidEfiCntlChar ( + IN CHAR16 CharC + ) +; + +#endif diff --git a/EdkModulePkg/Universal/Console/Terminal/Dxe/Terminal.mbd b/EdkModulePkg/Universal/Console/Terminal/Dxe/Terminal.mbd new file mode 100644 index 0000000000..7ec90ab781 --- /dev/null +++ b/EdkModulePkg/Universal/Console/Terminal/Dxe/Terminal.mbd @@ -0,0 +1,44 @@ + + + + + Terminal + 9E863906-A40F-4875-977F-5B93FF237FC6 + EDK_RELEASE_VERSION 0x00020000 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-22 19:05 + + + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + EdkDxePrintLib + BaseLib + DxeMemoryAllocationLib + UefiDevicePathLib + + diff --git a/EdkModulePkg/Universal/Console/Terminal/Dxe/Terminal.msa b/EdkModulePkg/Universal/Console/Terminal/Dxe/Terminal.msa new file mode 100644 index 0000000000..6382a8548c --- /dev/null +++ b/EdkModulePkg/Universal/Console/Terminal/Dxe/Terminal.msa @@ -0,0 +1,108 @@ + + + + + Terminal + DXE_DRIVER + BS_DRIVER + 9E863906-A40F-4875-977F-5B93FF237FC6 + EDK_RELEASE_VERSION 0x00020000 + Component description file for DiskIo module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + EFI_SPECIFICATION_VERSION 0x00000000 + 2006-03-12 17:09 + 2006-03-22 19:05 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + UefiLib + ReportStatusCodeLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + DevicePathLib + + + Terminal.h + Terminal.c + TerminalConIn.c + TerminalConOut.c + ansi.c + vtutf8.c + ComponentName.c + + + MdePkg + EdkModulePkg + + + SimpleTextOut + SimpleTextIn + DevicePath + SerialIo + + + + ConInDev + 0x8BE4DF61, 0x93CA, 0x11d2, 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C + + + ConOutDev + 0x8BE4DF61, 0x93CA, 0x11d2, 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C + + + ErrOutDev + 0x8BE4DF61, 0x93CA, 0x11d2, 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C + + + + + HotPlugDevice + + + GlobalVariable + + + PcAnsi + + + VT100Plus + + + VT100 + + + VTUTF8 + + + + + + + + gTerminalDriverBinding + gTerminalComponentName + + + diff --git a/EdkModulePkg/Universal/Console/Terminal/Dxe/TerminalConIn.c b/EdkModulePkg/Universal/Console/Terminal/Dxe/TerminalConIn.c new file mode 100644 index 0000000000..feaef5f557 --- /dev/null +++ b/EdkModulePkg/Universal/Console/Terminal/Dxe/TerminalConIn.c @@ -0,0 +1,1185 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + TerminalConIn.c + +Abstract: + + +Revision History +--*/ + + +#include +#include "Terminal.h" + + +EFI_STATUS +EFIAPI +TerminalConInReset ( + IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + Routine Description: + + Implements EFI_SIMPLE_TEXT_IN_PROTOCOL.Reset(). + This driver only perform dependent serial device reset regardless of + the value of ExtendeVerification + + Arguments: + + This - Indicates the calling context. + + ExtendedVerification - Skip by this driver. + + Returns: + + EFI_SUCCESS + The reset operation succeeds. + + EFI_DEVICE_ERROR + The dependent serial port reset fails. + +--*/ +{ + EFI_STATUS Status; + TERMINAL_DEV *TerminalDevice; + + TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (This); + + // + // Report progress code here + // + Status = 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); + + // + // clear all the internal buffer for keys + // + InitializeRawFiFo (TerminalDevice); + InitializeUnicodeFiFo (TerminalDevice); + InitializeEfiKeyFiFo (TerminalDevice); + + if (EFI_ERROR (Status)) { + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_CONTROLLER_ERROR, + TerminalDevice->DevicePath + ); + } + + return Status; +} + +EFI_STATUS +EFIAPI +TerminalConInReadKeyStroke ( + IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This, + OUT EFI_INPUT_KEY *Key + ) +/*++ + Routine Description: + + Implements EFI_SIMPLE_TEXT_IN_PROTOCOL.ReadKeyStroke(). + + Arguments: + + This - Indicates the calling context. + + Key - A pointer to a buffer that is filled in with the keystroke + information for the key that was sent from terminal. + + Returns: + + EFI_SUCCESS + The keystroke information is returned successfully. + + EFI_NOT_READY + There is no keystroke data available. + + EFI_DEVICE_ERROR + The dependent serial device encounters error. + +--*/ +{ + TERMINAL_DEV *TerminalDevice; + EFI_STATUS Status; + + // + // Initialize *Key to nonsense value. + // + Key->ScanCode = SCAN_NULL; + Key->UnicodeChar = 0; + // + // get TERMINAL_DEV from "This" parameter. + // + TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (This); + + Status = TerminalConInCheckForKey (This); + if (EFI_ERROR (Status)) { + return EFI_NOT_READY; + } + + EfiKeyFiFoRemoveOneKey (TerminalDevice, Key); + + return EFI_SUCCESS; + +} + +VOID +TranslateRawDataToEfiKey ( + IN TERMINAL_DEV *TerminalDevice + ) +/*++ + Step1: Turn raw data into Unicode (according to different encode). + Step2: Translate Unicode into key information. + (according to different terminal standard). +--*/ +{ + switch (TerminalDevice->TerminalType) { + + case PcAnsiType: + case VT100Type: + case VT100PlusType: + AnsiRawDataToUnicode (TerminalDevice); + UnicodeToEfiKey (TerminalDevice); + break; + + case VTUTF8Type: + // + // 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; + } +} + +VOID +EFIAPI +TerminalConInWaitForKey ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + Routine Description: + + Event notification function for EFI_SIMPLE_TEXT_IN_PROTOCOL.WaitForKey event + Signal the event if there is key available + + Arguments: + + Event - Indicates the event that invoke this function. + + Context - Indicates the calling context. + + Returns: + + N/A + +--*/ +{ + // + // Someone is waiting on the keystroke event, if there's + // a key pending, signal the event + // + // Context is the pointer to EFI_SIMPLE_TEXT_IN_PROTOCOL + // + if (!EFI_ERROR (TerminalConInCheckForKey (Context))) { + + gBS->SignalEvent (Event); + } +} + +EFI_STATUS +TerminalConInCheckForKey ( + IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This + ) +/*++ + Routine Description: + + Check for a pending key in the Efi Key FIFO or Serial device buffer. + + Arguments: + + This - Indicates the calling context. + + Returns: + + EFI_SUCCESS + There is key pending. + + EFI_NOT_READY + There is no key pending. + + EFI_DEVICE_ERROR + +--*/ +{ + EFI_STATUS Status; + TERMINAL_DEV *TerminalDevice; + UINT32 Control; + UINT8 Input; + EFI_SERIAL_IO_MODE *Mode; + EFI_SERIAL_IO_PROTOCOL *SerialIo; + UINTN SerialInTimeOut; + + TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (This); + + SerialIo = TerminalDevice->SerialIo; + if (SerialIo == NULL) { + return EFI_DEVICE_ERROR; + } + // + // 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) { + SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN) Mode->BaudRate; + } + + Status = SerialIo->SetAttributes ( + SerialIo, + Mode->BaudRate, + Mode->ReceiveFifoDepth, + (UINT32) SerialInTimeOut, + Mode->Parity, + (UINT8) Mode->DataBits, + Mode->StopBits + ); + + if (EFI_ERROR (Status)) { + TerminalDevice->SerialInTimeOut = 0; + } else { + TerminalDevice->SerialInTimeOut = SerialInTimeOut; + } + } + // + // check whether serial buffer is empty + // + Status = SerialIo->GetControl (SerialIo, &Control); + + if (Control & EFI_SERIAL_INPUT_BUFFER_EMPTY) { + // + // Translate all the raw data in RawFIFO into EFI Key, + // according to different terminal type supported. + // + TranslateRawDataToEfiKey (TerminalDevice); + + // + // if there is pre-fetched Efi Key in EfiKeyFIFO buffer, + // return directly. + // + if (!IsEfiKeyFiFoEmpty (TerminalDevice)) { + return EFI_SUCCESS; + } else { + return EFI_NOT_READY; + } + } + // + // Fetch all the keys in the serial buffer, + // and insert the byte stream into RawFIFO. + // + do { + + 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); + } while (TRUE); + + // + // Translate all the raw data in RawFIFO into EFI Key, + // according to different terminal type supported. + // + TranslateRawDataToEfiKey (TerminalDevice); + + if (IsEfiKeyFiFoEmpty (TerminalDevice)) { + return EFI_NOT_READY; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +GetOneKeyFromSerial ( + EFI_SERIAL_IO_PROTOCOL *SerialIo, + UINT8 *Input + ) +/*++ + Get one key out of serial buffer. + If serial buffer is empty, return EFI_NOT_READY; + if reading serial buffer encounter error, returns EFI_DEVICE_ERROR; + if reading serial buffer successfully, put the fetched key to + the parameter "Input", and return EFI_SUCCESS. +--*/ +{ + EFI_STATUS Status; + UINTN Size; + + Size = 1; + *Input = 0; + + Status = SerialIo->Read (SerialIo, &Size, Input); + + if (EFI_ERROR (Status)) { + + if (Status == EFI_TIMEOUT) { + return EFI_NOT_READY; + } + + return EFI_DEVICE_ERROR; + + } + + if (*Input == 0) { + return EFI_NOT_READY; + } + + return EFI_SUCCESS; +} + +BOOLEAN +RawFiFoInsertOneKey ( + TERMINAL_DEV *TerminalDevice, + UINT8 Input + ) +/*++ + Insert one byte raw data into the Raw Data FIFO. + If FIFO is FULL before data insertion, + return FALSE, and the key is lost. +--*/ +{ + 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; +} + +BOOLEAN +RawFiFoRemoveOneKey ( + TERMINAL_DEV *TerminalDevice, + UINT8 *Output + ) +/*++ + Remove one byte raw data out of the Raw Data FIFO. + If FIFO buffer is empty before remove operation, + return FALSE. +--*/ +{ + 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; +} + +BOOLEAN +IsRawFiFoEmpty ( + TERMINAL_DEV *TerminalDevice + ) +/*++ + Clarify whether FIFO buffer is empty. +--*/ +{ + if (TerminalDevice->RawFiFo.Head == TerminalDevice->RawFiFo.Tail) { + return TRUE; + } else { + return FALSE; + } +} + +BOOLEAN +IsRawFiFoFull ( + TERMINAL_DEV *TerminalDevice + ) +/*++ + Clarify whether FIFO buffer is full. +--*/ +{ + 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; +} + +BOOLEAN +EfiKeyFiFoInsertOneKey ( + TERMINAL_DEV *TerminalDevice, + EFI_INPUT_KEY Key + ) +/*++ + Insert one pre-fetched key into the FIFO buffer. + If FIFO buffer is FULL before key insertion, + return FALSE, and the key is lost. +--*/ +{ + UINT8 Tail; + + Tail = TerminalDevice->EfiKeyFiFo.Tail; + + if (IsEfiKeyFiFoFull (TerminalDevice)) { + // + // Efi Key FIFO is full + // + return FALSE; + } + + TerminalDevice->EfiKeyFiFo.Data[Tail] = Key; + + TerminalDevice->EfiKeyFiFo.Tail = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1)); + + return TRUE; +} + +BOOLEAN +EfiKeyFiFoRemoveOneKey ( + TERMINAL_DEV *TerminalDevice, + EFI_INPUT_KEY *Output + ) +/*++ + Remove one pre-fetched key out of the FIFO buffer. + If FIFO buffer is empty before remove operation, + return FALSE. +--*/ +{ + UINT8 Head; + + Head = TerminalDevice->EfiKeyFiFo.Head; + + if (IsEfiKeyFiFoEmpty (TerminalDevice)) { + // + // FIFO is empty + // + Output->ScanCode = SCAN_NULL; + Output->UnicodeChar = 0; + return FALSE; + } + + *Output = TerminalDevice->EfiKeyFiFo.Data[Head]; + + TerminalDevice->EfiKeyFiFo.Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1)); + + return TRUE; +} + +BOOLEAN +IsEfiKeyFiFoEmpty ( + TERMINAL_DEV *TerminalDevice + ) +/*++ + Clarify whether FIFO buffer is empty. +--*/ +{ + if (TerminalDevice->EfiKeyFiFo.Head == TerminalDevice->EfiKeyFiFo.Tail) { + return TRUE; + } else { + return FALSE; + } +} + +BOOLEAN +IsEfiKeyFiFoFull ( + TERMINAL_DEV *TerminalDevice + ) +/*++ + Clarify whether FIFO buffer is full. +--*/ +{ + UINT8 Tail; + UINT8 Head; + + Tail = TerminalDevice->EfiKeyFiFo.Tail; + Head = TerminalDevice->EfiKeyFiFo.Head; + + if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) { + + return TRUE; + } + + return FALSE; +} + +BOOLEAN +UnicodeFiFoInsertOneKey ( + TERMINAL_DEV *TerminalDevice, + UINT16 Input + ) +/*++ + Insert one pre-fetched key into the FIFO buffer. + If FIFO buffer is FULL before key insertion, + return FALSE, and the key is lost. +--*/ +{ + UINT8 Tail; + + Tail = TerminalDevice->UnicodeFiFo.Tail; + + 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; +} + +BOOLEAN +UnicodeFiFoRemoveOneKey ( + TERMINAL_DEV *TerminalDevice, + UINT16 *Output + ) +/*++ + Remove one pre-fetched key out of the FIFO buffer. + If FIFO buffer is empty before remove operation, + return FALSE. +--*/ +{ + UINT8 Head; + + Head = TerminalDevice->UnicodeFiFo.Head; + + if (IsUnicodeFiFoEmpty (TerminalDevice)) { + // + // FIFO is empty + // + Output = NULL; + return FALSE; + } + + *Output = TerminalDevice->UnicodeFiFo.Data[Head]; + + TerminalDevice->UnicodeFiFo.Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1)); + + return TRUE; +} + +BOOLEAN +IsUnicodeFiFoEmpty ( + TERMINAL_DEV *TerminalDevice + ) +/*++ + Clarify whether FIFO buffer is empty. +--*/ +{ + if (TerminalDevice->UnicodeFiFo.Head == TerminalDevice->UnicodeFiFo.Tail) { + return TRUE; + } else { + return FALSE; + } +} + +BOOLEAN +IsUnicodeFiFoFull ( + TERMINAL_DEV *TerminalDevice + ) +/*++ + Clarify whether FIFO buffer is full. +--*/ +{ + UINT8 Tail; + UINT8 Head; + + Tail = TerminalDevice->UnicodeFiFo.Tail; + Head = TerminalDevice->UnicodeFiFo.Head; + + if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) { + + return TRUE; + } + + return FALSE; +} + +UINT8 +UnicodeFiFoGetKeyCount ( + TERMINAL_DEV *TerminalDevice + ) +{ + UINT8 Tail; + UINT8 Head; + + Tail = TerminalDevice->UnicodeFiFo.Tail; + Head = TerminalDevice->UnicodeFiFo.Head; + + if (Tail >= Head) { + return (UINT8) (Tail - Head); + } else { + return (UINT8) (Tail + FIFO_MAX_NUMBER + 1 - Head); + } +} + +VOID +UnicodeToEfiKeyFlushState ( + IN TERMINAL_DEV *TerminalDevice + ) +{ + EFI_INPUT_KEY Key; + + if (TerminalDevice->InputState & INPUT_STATE_ESC) { + Key.ScanCode = SCAN_ESC; + Key.UnicodeChar = 0; + EfiKeyFiFoInsertOneKey (TerminalDevice, Key); + } + + if (TerminalDevice->InputState & INPUT_STATE_CSI) { + Key.ScanCode = SCAN_NULL; + Key.UnicodeChar = CSI; + EfiKeyFiFoInsertOneKey (TerminalDevice, Key); + } + + if (TerminalDevice->InputState & INPUT_STATE_LEFTOPENBRACKET) { + Key.ScanCode = SCAN_NULL; + Key.UnicodeChar = LEFTOPENBRACKET; + EfiKeyFiFoInsertOneKey (TerminalDevice, Key); + } + + if (TerminalDevice->InputState & INPUT_STATE_O) { + Key.ScanCode = SCAN_NULL; + Key.UnicodeChar = 'O'; + EfiKeyFiFoInsertOneKey (TerminalDevice, Key); + } + + if (TerminalDevice->InputState & INPUT_STATE_2) { + Key.ScanCode = SCAN_NULL; + Key.UnicodeChar = '2'; + EfiKeyFiFoInsertOneKey (TerminalDevice, Key); + } + + gBS->SetTimer ( + TerminalDevice->TwoSecondTimeOut, + TimerCancel, + 0 + ); + + TerminalDevice->InputState = INPUT_STATE_DEFAULT; +} + +VOID +UnicodeToEfiKey ( + IN TERMINAL_DEV *TerminalDevice + ) +/*++ + Routine Description: + + 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. + + Arguments: + + TerminaDevice : The terminal device to use to translate raw input into EFI Keys + + Returns: + + None + +Symbols used in table below +=========================== + ESC = 0x1B + CSI = 0x9B + DEL = 0x7f + ^ = CTRL + ++=========+======+===========+==========+==========+ +| | EFI | EFI 1.10 | | | +| | 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 | ++=========+======+===========+==========+=========+ + +Special Mappings +================ +ESC R ESC r ESC R = Reset System + +--*/ +{ + 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)) { + + if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) { + // + // Check to see if the 2 second 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 == VT100Type) { + TerminalDevice->InputState |= INPUT_STATE_O; + TerminalDevice->ResetState = RESET_STATE_DEFAULT; + continue; + } + + Key.ScanCode = SCAN_NULL; + + if (TerminalDevice->TerminalType == VT100PlusType || + TerminalDevice->TerminalType == VTUTF8Type) { + 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 '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 == VT100Type) { + 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; + } + } + + 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: + + TerminalDevice->ResetState = RESET_STATE_DEFAULT; + + Key.ScanCode = SCAN_NULL; + + if (TerminalDevice->TerminalType == PcAnsiType || + TerminalDevice->TerminalType == VT100Type || + TerminalDevice->TerminalType == VT100PlusType || + TerminalDevice->TerminalType == VTUTF8Type) { + 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 == PcAnsiType || + TerminalDevice->TerminalType == VT100Type) { + Key.ScanCode = SCAN_HOME; + } + break; + case 'F': + if (TerminalDevice->TerminalType == PcAnsiType) { + Key.ScanCode = SCAN_END; + } + break; + case 'K': + if (TerminalDevice->TerminalType == VT100Type) { + Key.ScanCode = SCAN_END; + } + break; + case 'L': + case '@': + if (TerminalDevice->TerminalType == PcAnsiType || + TerminalDevice->TerminalType == VT100Type) { + Key.ScanCode = SCAN_INSERT; + } + break; + case 'X': + if (TerminalDevice->TerminalType == PcAnsiType) { + Key.ScanCode = SCAN_DELETE; + } + break; + case 'P': + if (TerminalDevice->TerminalType == VT100Type) { + Key.ScanCode = SCAN_DELETE; + } else if (TerminalDevice->TerminalType == PcAnsiType) { + Key.ScanCode = SCAN_F4; + } + break; + case 'I': + if (TerminalDevice->TerminalType == PcAnsiType) { + Key.ScanCode = SCAN_PAGE_UP; + } + break; + case 'V': + if (TerminalDevice->TerminalType == PcAnsiType) { + Key.ScanCode = SCAN_F10; + } + case '?': + if (TerminalDevice->TerminalType == VT100Type) { + Key.ScanCode = SCAN_PAGE_UP; + } + break; + case 'G': + if (TerminalDevice->TerminalType == PcAnsiType) { + Key.ScanCode = SCAN_PAGE_DOWN; + } + break; + case 'U': + if (TerminalDevice->TerminalType == PcAnsiType) { + Key.ScanCode = SCAN_F9; + } + case '/': + if (TerminalDevice->TerminalType == VT100Type) { + Key.ScanCode = SCAN_PAGE_DOWN; + } + break; + case 'M': + if (TerminalDevice->TerminalType == PcAnsiType) { + Key.ScanCode = SCAN_F1; + } + break; + case 'N': + if (TerminalDevice->TerminalType == PcAnsiType) { + Key.ScanCode = SCAN_F2; + } + break; + case 'O': + if (TerminalDevice->TerminalType == PcAnsiType) { + Key.ScanCode = SCAN_F3; + } + break; + case 'Q': + if (TerminalDevice->TerminalType == PcAnsiType) { + Key.ScanCode = SCAN_F5; + } + break; + case 'R': + if (TerminalDevice->TerminalType == PcAnsiType) { + Key.ScanCode = SCAN_F6; + } + break; + case 'S': + if (TerminalDevice->TerminalType == PcAnsiType) { + Key.ScanCode = SCAN_F7; + } + break; + case 'T': + if (TerminalDevice->TerminalType == PcAnsiType) { + Key.ScanCode = SCAN_F8; + } + break; + default : + break; + } + } + + 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 (TerminalDevice->InputState != INPUT_STATE_DEFAULT) { + Status = gBS->SetTimer( + TerminalDevice->TwoSecondTimeOut, + TimerRelative, + (UINT64)20000000 + ); + continue; + } + + if (SetDefaultResetState) { + TerminalDevice->ResetState = RESET_STATE_DEFAULT; + } + + if (UnicodeChar == DEL) { + Key.ScanCode = SCAN_DELETE; + Key.UnicodeChar = 0; + } else { + Key.ScanCode = SCAN_NULL; + Key.UnicodeChar = UnicodeChar; + } + + EfiKeyFiFoInsertOneKey (TerminalDevice,Key); + } +} diff --git a/EdkModulePkg/Universal/Console/Terminal/Dxe/TerminalConOut.c b/EdkModulePkg/Universal/Console/Terminal/Dxe/TerminalConOut.c new file mode 100644 index 0000000000..4d98e59707 --- /dev/null +++ b/EdkModulePkg/Universal/Console/Terminal/Dxe/TerminalConOut.c @@ -0,0 +1,997 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + TerminalConOut.c + +Abstract: + + +Revision History +--*/ + + +#include "Terminal.h" +#include + +// +// 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. +// +// +STATIC UNICODE_TO_CHAR UnicodeToPcAnsiOrAscii[] = { + { BOXDRAW_HORIZONTAL, 0xc4, L'-' }, + { BOXDRAW_VERTICAL, 0xb3, L'|' }, + { BOXDRAW_DOWN_RIGHT, 0xda, L'/' }, + { BOXDRAW_DOWN_LEFT, 0xbf, L'\\' }, + { BOXDRAW_UP_RIGHT, 0xc0, L'\\' }, + { BOXDRAW_UP_LEFT, 0xd9, L'/' }, + { BOXDRAW_VERTICAL_RIGHT, 0xc3, L'|' }, + { BOXDRAW_VERTICAL_LEFT, 0xb4, L'|' }, + { BOXDRAW_DOWN_HORIZONTAL, 0xc2, L'+' }, + { BOXDRAW_UP_HORIZONTAL, 0xc1, L'+' }, + { BOXDRAW_VERTICAL_HORIZONTAL, 0xc5, L'+' }, + { BOXDRAW_DOUBLE_HORIZONTAL, 0xcd, L'-' }, + { BOXDRAW_DOUBLE_VERTICAL, 0xba, L'|' }, + { BOXDRAW_DOWN_RIGHT_DOUBLE, 0xd5, L'/' }, + { BOXDRAW_DOWN_DOUBLE_RIGHT, 0xd6, L'/' }, + { BOXDRAW_DOUBLE_DOWN_RIGHT, 0xc9, L'/' }, + { BOXDRAW_DOWN_LEFT_DOUBLE, 0xb8, L'\\' }, + { BOXDRAW_DOWN_DOUBLE_LEFT, 0xb7, L'\\' }, + { BOXDRAW_DOUBLE_DOWN_LEFT, 0xbb, L'\\' }, + { BOXDRAW_UP_RIGHT_DOUBLE, 0xd4, L'\\' }, + { BOXDRAW_UP_DOUBLE_RIGHT, 0xd3, L'\\' }, + { BOXDRAW_DOUBLE_UP_RIGHT, 0xc8, L'\\' }, + { BOXDRAW_UP_LEFT_DOUBLE, 0xbe, L'/' }, + { BOXDRAW_UP_DOUBLE_LEFT, 0xbd, L'/' }, + { BOXDRAW_DOUBLE_UP_LEFT, 0xbc, L'/' }, + { BOXDRAW_VERTICAL_RIGHT_DOUBLE, 0xc6, L'|' }, + { BOXDRAW_VERTICAL_DOUBLE_RIGHT, 0xc7, L'|' }, + { BOXDRAW_DOUBLE_VERTICAL_RIGHT, 0xcc, L'|' }, + { BOXDRAW_VERTICAL_LEFT_DOUBLE, 0xb5, L'|' }, + { BOXDRAW_VERTICAL_DOUBLE_LEFT, 0xb6, L'|' }, + { BOXDRAW_DOUBLE_VERTICAL_LEFT, 0xb9, L'|' }, + { BOXDRAW_DOWN_HORIZONTAL_DOUBLE, 0xd1, L'+' }, + { BOXDRAW_DOWN_DOUBLE_HORIZONTAL, 0xd2, L'+' }, + { BOXDRAW_DOUBLE_DOWN_HORIZONTAL, 0xcb, L'+' }, + { BOXDRAW_UP_HORIZONTAL_DOUBLE, 0xcf, L'+' }, + { BOXDRAW_UP_DOUBLE_HORIZONTAL, 0xd0, L'+' }, + { BOXDRAW_DOUBLE_UP_HORIZONTAL, 0xca, L'+' }, + { BOXDRAW_VERTICAL_HORIZONTAL_DOUBLE, 0xd8, L'+' }, + { BOXDRAW_VERTICAL_DOUBLE_HORIZONTAL, 0xd7, L'+' }, + { BOXDRAW_DOUBLE_VERTICAL_HORIZONTAL, 0xce, L'+' }, + + { BLOCKELEMENT_FULL_BLOCK, 0xdb, L'*' }, + { BLOCKELEMENT_LIGHT_SHADE, 0xb0, L'+' }, + + { GEOMETRICSHAPE_UP_TRIANGLE, 0x1e, L'^' }, + { GEOMETRICSHAPE_RIGHT_TRIANGLE, 0x10, L'>' }, + { GEOMETRICSHAPE_DOWN_TRIANGLE, 0x1f, L'v' }, + { GEOMETRICSHAPE_LEFT_TRIANGLE, 0x11, L'<' }, + + { ARROW_LEFT, 0x3c, L'<' }, + { ARROW_UP, 0x18, L'^' }, + { ARROW_RIGHT, 0x3e, L'>' }, + { ARROW_DOWN, 0x19, L'v' }, + + { 0x0000, 0x00, 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 }; + +// +// Body of the ConOut functions +// +EFI_STATUS +EFIAPI +TerminalConOutReset ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + Routine Description: + + Implements EFI_SIMPLE_TEXT_OUT_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. + + Arguments: + + This - Indicates the calling context. + + ExtendedVerification - Indicates that the driver may perform a more exhaustive + verification operation of the device during reset. + + Returns: + + EFI_SUCCESS + The reset operation succeeds. + + EFI_DEVICE_ERROR + The terminal is not functioning correctly or the serial port reset fails. + +--*/ +{ + 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_BACKGROUND_BLACK)); + + Status = This->SetMode (This, 0); + + return Status; +} + +EFI_STATUS +EFIAPI +TerminalConOutOutputString ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN CHAR16 *WString + ) +/*++ + Routine Description: + + Implements EFI_SIMPLE_TEXT_OUT_PROTOCOL.OutputString(). + The Unicode string will be converted to terminal expressible data stream + and send to terminal via serial port. + + + Arguments: + + This - Indicates the calling context. + + WString - The Null-terminated Unicode string to be displayed on + the terminal screen. + + Returns: + + EFI_SUCCESS + The string is output successfully. + + EFI_DEVICE_ERROR + The serial port fails to send the string out. + + EFI_WARN_UNKNOWN_GLYPH + Indicates that some of the characters in the Unicode string could not + be rendered and are skipped. + + EFI_UNSUPPORTED + +--*/ +{ + 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; + // + // flag used to indicate whether condition happens which will cause + // return EFI_WARN_UNKNOWN_GLYPH + // + BOOLEAN Warning; + + ValidBytes = 0; + Warning = FALSE; + + // + // get Terminal device data structure pointer. + // + TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This); + + // + // get current display mode + // Terminal driver only support mode 0 + // + Mode = This->Mode; + if (Mode->Mode != 0) { + return EFI_UNSUPPORTED; + } + + This->QueryMode ( + This, + Mode->Mode, + &MaxColumn, + &MaxRow + ); + + for (; *WString != CHAR_NULL; WString++) { + + switch (TerminalDevice->TerminalType) { + + case PcAnsiType: + case VT100Type: + case VT100PlusType: + + 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 != PcAnsiType) { + GraphicChar = AsciiChar; + } + + Length = 1; + + Status = TerminalDevice->SerialIo->Write ( + TerminalDevice->SerialIo, + &Length, + &GraphicChar + ); + + if (EFI_ERROR (Status)) { + goto OutputError; + } + + break; + + case VTUTF8Type: + 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++; + } + + } + 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; +} + +EFI_STATUS +EFIAPI +TerminalConOutTestString ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN CHAR16 *WString + ) +/*++ + Routine Description: + + Implements EFI_SIMPLE_TEXT_OUT_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. + + + Arguments: + + This - Indicates the calling context. + + WString - The Null-terminated Unicode string to be tested. + + Returns: + + EFI_SUCCESS + The terminal is capable of rendering the output string. + + EFI_UNSUPPORTED + Some of the characters in the Unicode string cannot be rendered. + +--*/ +{ + TERMINAL_DEV *TerminalDevice; + EFI_STATUS Status; + + // + // get Terminal device data structure pointer. + // + TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This); + + switch (TerminalDevice->TerminalType) { + + case PcAnsiType: + case VT100Type: + case VT100PlusType: + Status = AnsiTestString (TerminalDevice, WString); + break; + + case VTUTF8Type: + Status = VTUTF8TestString (TerminalDevice, WString); + break; + + default: + Status = EFI_UNSUPPORTED; + break; + } + + return Status; +} + +EFI_STATUS +EFIAPI +TerminalConOutQueryMode ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN UINTN ModeNumber, + OUT UINTN *Columns, + OUT UINTN *Rows + ) +/*++ + Routine Description: + + Implements EFI_SIMPLE_TEXT_OUT_PROTOCOL.QueryMode(). + It returns information for an available text mode + that the terminal supports. + In this driver, we only support text mode 80x25, which is + defined as mode 0. + + + Arguments: + + *This + Indicates the calling context. + + ModeNumber + The mode number to return information on. + + Columns + The returned columns of the requested mode. + + Rows + The returned rows of the requested mode. + + Returns: + + EFI_SUCCESS + The requested mode information is returned. + + EFI_UNSUPPORTED + The mode number is not valid. + + EFI_DEVICE_ERROR + +--*/ +{ + if (This->Mode->MaxMode > 1) { + return EFI_DEVICE_ERROR; + } + + if (ModeNumber == 0) { + + *Columns = MODE0_COLUMN_COUNT; + *Rows = MODE0_ROW_COUNT; + + return EFI_SUCCESS; + } + + return EFI_UNSUPPORTED; +} + +EFI_STATUS +EFIAPI +TerminalConOutSetMode ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN UINTN ModeNumber + ) +/*++ + Routine Description: + + Implements EFI_SIMPLE_TEXT_OUT.SetMode(). + Set the terminal to a specified display mode. + In this driver, we only support mode 0. + + Arguments: + + This + Indicates the calling context. + + ModeNumber + The text mode to set. + + Returns: + + EFI_SUCCESS + The requested text mode is set. + + EFI_DEVICE_ERROR + The requested text mode cannot be set because of serial device error. + + EFI_UNSUPPORTED + The text mode number is not valid. + +--*/ +{ + EFI_STATUS Status; + TERMINAL_DEV *TerminalDevice; + + // + // get Terminal device data structure pointer. + // + TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This); + + if (ModeNumber != 0) { + return EFI_UNSUPPORTED; + } + + This->Mode->Mode = 0; + + 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 = 0; + + Status = This->ClearScreen (This); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; + +} + +EFI_STATUS +EFIAPI +TerminalConOutSetAttribute ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN UINTN Attribute + ) +/*++ + Routine Description: + + Implements EFI_SIMPLE_TEXT_OUT_PROTOCOL.SetAttribute(). + + Arguments: + + This + Indicates the calling context. + + Attribute + The attribute to set. Only bit0..6 are valid, all other bits + are undefined and must be zero. + + Returns: + + EFI_SUCCESS + The requested attribute is set. + + EFI_DEVICE_ERROR + The requested attribute cannot be set due to serial port error. + + EFI_UNSUPPORTED + The attribute requested is not defined by EFI spec. + +--*/ +{ + 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; + } + // + // 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; + +} + +EFI_STATUS +EFIAPI +TerminalConOutClearScreen ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This + ) +/*++ + Routine Description: + + Implements EFI_SIMPLE_TEXT_OUT_PROTOCOL.ClearScreen(). + It clears the ANSI terminal's display to the + currently selected background color. + + + Arguments: + + This + Indicates the calling context. + + Returns: + + EFI_SUCCESS + The operation completed successfully. + + EFI_DEVICE_ERROR + The terminal screen cannot be cleared due to serial port error. + + EFI_UNSUPPORTED + The terminal is not in a valid display mode. + +--*/ +{ + 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; +} + +EFI_STATUS +EFIAPI +TerminalConOutSetCursorPosition ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN UINTN Column, + IN UINTN Row + ) +/*++ + Routine Description: + + Implements EFI_SIMPLE_TEXT_OUT_PROTOCOL.SetCursorPosition(). + + Arguments: + + This + Indicates the calling context. + + Column + The row to set cursor to. + + Row + The column to set cursor to. + + Returns: + + EFI_SUCCESS + The operation completed successfully. + + EFI_DEVICE_ERROR + The request fails due to serial port error. + + EFI_UNSUPPORTED + The terminal is not in a valid text mode, or the cursor position + is invalid for current mode. + +--*/ +{ + EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode; + UINTN MaxColumn; + UINTN MaxRow; + EFI_STATUS Status; + TERMINAL_DEV *TerminalDevice; + + 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 + // + 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)); + + TerminalDevice->OutputEscChar = TRUE; + Status = This->OutputString (This, mSetCursorPositionString); + 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; +} + +EFI_STATUS +EFIAPI +TerminalConOutEnableCursor ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN BOOLEAN Visible + ) +/*++ + Routine Description: + + Implements SIMPLE_TEXT_OUTPUT.EnableCursor(). + In this driver, the cursor cannot be hidden. + + Arguments: + + This + Indicates the calling context. + + Visible + If TRUE, the cursor is set to be visible, + If FALSE, the cursor is set to be invisible. + + Returns: + + EFI_SUCCESS + The request is valid. + + EFI_UNSUPPORTED + The terminal does not support cursor hidden. + +--*/ +{ + if (!Visible) { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +BOOLEAN +TerminalIsValidTextGraphics ( + IN CHAR16 Graphic, + OUT CHAR8 *PcAnsi, OPTIONAL + OUT CHAR8 *Ascii OPTIONAL + ) +/*++ + +Routine Description: + + Detects if a Unicode char is for Box Drawing text graphics. + +Arguments: + + Graphic - Unicode char to test. + + PcAnsi - Optional pointer to return PCANSI equivalent of Graphic. + + Ascii - Optional pointer to return ASCII equivalent of Graphic. + +Returns: + + TRUE if Graphic is a supported Unicode Box Drawing character. + +--*/ +{ + 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; +} + +BOOLEAN +TerminalIsValidAscii ( + IN CHAR16 Ascii + ) +{ + // + // valid ascii code lies in the extent of 0x20 ~ 0x7f + // + if ((Ascii >= 0x20) && (Ascii <= 0x7f)) { + return TRUE; + } + + return FALSE; +} + +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/EdkModulePkg/Universal/Console/Terminal/Dxe/ansi.c b/EdkModulePkg/Universal/Console/Terminal/Dxe/ansi.c new file mode 100644 index 0000000000..babc4bbedc --- /dev/null +++ b/EdkModulePkg/Universal/Console/Terminal/Dxe/ansi.c @@ -0,0 +1,68 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ansi.c + +Abstract: + + +Revision History +--*/ + + +#include "Terminal.h" + +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)) { + + RawFiFoRemoveOneKey (TerminalDevice, &RawData); + + UnicodeFiFoInsertOneKey (TerminalDevice, (UINT16) RawData); + } +} + +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/EdkModulePkg/Universal/Console/Terminal/Dxe/build.xml b/EdkModulePkg/Universal/Console/Terminal/Dxe/build.xml new file mode 100644 index 0000000000..a3c17133de --- /dev/null +++ b/EdkModulePkg/Universal/Console/Terminal/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Universal/Console/Terminal/Dxe/vtutf8.c b/EdkModulePkg/Universal/Console/Terminal/Dxe/vtutf8.c new file mode 100644 index 0000000000..062d0d429f --- /dev/null +++ b/EdkModulePkg/Universal/Console/Terminal/Dxe/vtutf8.c @@ -0,0 +1,270 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + vtutf8.c + +Abstract: + + +Revision History +--*/ + + +#include "Terminal.h" + +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)) { + + GetOneValidUtf8Char (TerminalDevice, &Utf8Char, &ValidBytes); + + if (ValidBytes < 1 || ValidBytes > 3) { + continue; + } + + Utf8ToUnicode (Utf8Char, ValidBytes, (CHAR16 *) &UnicodeChar); + + UnicodeFiFoInsertOneKey (TerminalDevice, UnicodeChar); + } +} + +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: + if ((Temp & 0xc0) == 0x80) { + + Utf8Char->Utf8_2[0] = Temp; + + FetchFlag = FALSE; + + } else { + + *ValidBytes = 0; + } + break; + + case 3: + if ((Temp & 0xc0) == 0x80) { + + Utf8Char->Utf8_3[2 - Index] = Temp; + Index++; + if (Index == 3) { + FetchFlag = FALSE; + } + } else { + + *ValidBytes = 0; + Index = 0; + } + break; + + default: + break; + } + + if (!FetchFlag) { + break; + } + } + + return ; +} + +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 ; +} + +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; + } +} + +EFI_STATUS +VTUTF8TestString ( + IN TERMINAL_DEV *TerminalDevice, + IN CHAR16 *WString + ) +{ + // + // to utf8, all kind of characters are supported. + // + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Universal/DataHub/DataHub/Dxe/DataHub.c b/EdkModulePkg/Universal/DataHub/DataHub/Dxe/DataHub.c new file mode 100644 index 0000000000..01e7a6ed69 --- /dev/null +++ b/EdkModulePkg/Universal/DataHub/DataHub/Dxe/DataHub.c @@ -0,0 +1,655 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DataHub.c + +Abstract: + + This code produces the Data Hub protocol. It preloads the data hub + with status information copied in from PEI HOBs. + + Only code that implements the Data Hub protocol should go in this file! + + The Term MTC stands for MonoTonicCounter. + + For more information please look at DataHub.doc + + NOTE: For extra security of the log GetNextDataRecord () could return a copy + of the data record. +--*/ + +#include "DataHub.h" + +CONST EFI_GUID gZeroGuid = { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } }; + +// +// Worker functions private to this file +// +STATIC +DATA_HUB_FILTER_DRIVER * +FindFilterDriverByEvent ( + IN LIST_ENTRY *Head, + IN EFI_EVENT Event + ); + +STATIC +EFI_DATA_RECORD_HEADER * +GetNextDataRecord ( + IN LIST_ENTRY *Head, + IN UINT64 ClassFilter, + IN OUT UINT64 *PtrCurrentMTC + ); + +EFI_STATUS +EFIAPI +DataHubLogData ( + IN EFI_DATA_HUB_PROTOCOL *This, + IN EFI_GUID *DataRecordGuid, + IN EFI_GUID *ProducerName, + IN UINT64 DataRecordClass, + IN VOID *RawData, + IN UINT32 RawDataSize + ) +/*++ + +Routine Description: + + Log data record into the data logging hub + +Arguments: + + This - Protocol instance structure + + DataRecordGuid - GUID that defines record contents + + ProducerName - GUID that defines the name of the producer of the data + + DataRecordClass - Class that defines generic record type + + RawData - Data Log record as defined by DataRecordGuid + + RawDataSize - Size of Data Log data in bytes + +Returns: + + EFI_SUCCESS - If data was logged + + EFI_OUT_OF_RESOURCES - If data was not logged due to lack of system + resources. +--*/ +{ + EFI_STATUS Status; + DATA_HUB_INSTANCE *Private; + EFI_DATA_ENTRY *LogEntry; + UINT32 TotalSize; + UINT32 RecordSize; + EFI_DATA_RECORD_HEADER *Record; + VOID *Raw; + DATA_HUB_FILTER_DRIVER *FilterEntry; + LIST_ENTRY *Link; + LIST_ENTRY *Head; + + Private = DATA_HUB_INSTANCE_FROM_THIS (This); + + // + // Combine the storage for the internal structs and a copy of the log record. + // Record follows PrivateLogEntry. The consumer will be returned a pointer + // to Record so we don't what it to be the thing that was allocated from + // pool, so the consumer can't free an data record by mistake. + // + RecordSize = sizeof (EFI_DATA_RECORD_HEADER) + RawDataSize; + TotalSize = sizeof (EFI_DATA_ENTRY) + RecordSize; + + // + // The Logging action is the critical section, so it is locked. + // The MTC asignment & update, time, and logging must be an + // atomic operation, so use the lock. + // + Status = EfiAcquireLockOrFail (&Private->DataLock); + if (EFI_ERROR (Status)) { + // + // Reentrancy detected so exit! + // + return Status; + } + + Status = gBS->AllocatePool (EfiBootServicesData, TotalSize, (VOID **) &LogEntry); + if (EFI_ERROR (Status)) { + EfiReleaseLock (&Private->DataLock); + return EFI_OUT_OF_RESOURCES; + } + + ZeroMem (LogEntry, TotalSize); + + Record = (EFI_DATA_RECORD_HEADER *) (LogEntry + 1); + Raw = (VOID *) (Record + 1); + + // + // Build Standard Log Header + // + Record->Version = EFI_DATA_RECORD_HEADER_VERSION; + Record->HeaderSize = sizeof (EFI_DATA_RECORD_HEADER); + Record->RecordSize = RecordSize; + CopyMem (&Record->DataRecordGuid, DataRecordGuid, sizeof (EFI_GUID)); + CopyMem (&Record->ProducerName, ProducerName, sizeof (EFI_GUID)); + Record->DataRecordClass = DataRecordClass; + + Record->LogMonotonicCount = Private->GlobalMonotonicCount++; + + gRT->GetTime (&Record->LogTime, NULL); + + // + // Insert log into the internal linked list. + // + LogEntry->Signature = EFI_DATA_ENTRY_SIGNATURE; + LogEntry->Record = Record; + LogEntry->RecordSize = sizeof (EFI_DATA_ENTRY) + RawDataSize; + InsertTailList (&Private->DataListHead, &LogEntry->Link); + + CopyMem (Raw, RawData, RawDataSize); + + EfiReleaseLock (&Private->DataLock); + + // + // Send Signal to all the filter drivers which are interested + // in the record's class and guid. + // + Head = &Private->FilterDriverListHead; + for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) { + FilterEntry = FILTER_ENTRY_FROM_LINK (Link); + if (((FilterEntry->ClassFilter & DataRecordClass) != 0) && + (CompareGuid (&FilterEntry->FilterDataRecordGuid, &gZeroGuid) || + CompareGuid (&FilterEntry->FilterDataRecordGuid, DataRecordGuid))) { + gBS->SignalEvent (FilterEntry->Event); + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +DataHubGetNextRecord ( + IN EFI_DATA_HUB_PROTOCOL *This, + IN OUT UINT64 *MonotonicCount, + IN EFI_EVENT *FilterDriverEvent, OPTIONAL + OUT EFI_DATA_RECORD_HEADER **Record + ) +/*++ + +Routine Description: + + Get a previously logged data record and the MonotonicCount for the next + availible Record. This allows all records or all records later + than a give MonotonicCount to be returned. If an optional FilterDriverEvent + is passed in with a MonotonicCout of zero return the first record + not yet read by the filter driver. If FilterDriverEvent is NULL and + MonotonicCount is zero return the first data record. + +Arguments: + + This - The EFI_DATA_HUB_PROTOCOL instance. + MonotonicCount - Specifies the Record to return. On input, zero means + return the first record. On output, contains the next + record to availible. Zero indicates no more records. + FilterDriverEvent - If FilterDriverEvent is not passed in a MonotonicCount + of zero, it means to return the first data record. + If FilterDriverEvent is passed in, then a MonotonicCount + of zero means to return the first data not yet read by + FilterDriverEvent. + Record - Returns a dynamically allocated memory buffer with a data + record that matches MonotonicCount. + +Returns: + + EFI_SUCCESS - Data was returned in Record. + EFI_INVALID_PARAMETER - FilterDriverEvent was passed in but does not exist. + EFI_NOT_FOUND - MonotonicCount does not match any data record in the + system. If a MonotonicCount of zero was passed in, then + no data records exist in the system. + EFI_OUT_OF_RESOURCES - Record was not returned due to lack of system resources. + +--*/ +{ + DATA_HUB_INSTANCE *Private; + DATA_HUB_FILTER_DRIVER *FilterDriver; + UINT64 ClassFilter; + UINT64 FilterMonotonicCount; + + Private = DATA_HUB_INSTANCE_FROM_THIS (This); + + FilterDriver = NULL; + FilterMonotonicCount = 0; + ClassFilter = EFI_DATA_RECORD_CLASS_DEBUG | + EFI_DATA_RECORD_CLASS_ERROR | + EFI_DATA_RECORD_CLASS_DATA | + EFI_DATA_RECORD_CLASS_PROGRESS_CODE; + + if (FilterDriverEvent != NULL) { + // + // For events the beginning is the last unread record. This info is + // stored in the instance structure, so we must look up the event + // to get the data. + // + FilterDriver = FindFilterDriverByEvent ( + &Private->FilterDriverListHead, + *FilterDriverEvent + ); + if (FilterDriver == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Use the Class filter the event was created with. + // + ClassFilter = FilterDriver->ClassFilter; + + if (*MonotonicCount == 0) { + // + // Use the MTC from the Filter Driver. + // + FilterMonotonicCount = FilterDriver->GetNextMonotonicCount; + if (FilterMonotonicCount != 0) { + // + // The GetNextMonotonicCount field remembers the last value from the previous time. + // But we already processed this vaule, so we need to find the next one. So if + // It is not the first time get the new record entry. + // + *Record = GetNextDataRecord (&Private->DataListHead, ClassFilter, &FilterMonotonicCount); + *MonotonicCount = FilterMonotonicCount; + if (FilterMonotonicCount == 0) { + // + // If there is no new record to get exit now. + // + return EFI_NOT_FOUND; + } + } + } + } + // + // Return the record + // + *Record = GetNextDataRecord (&Private->DataListHead, ClassFilter, MonotonicCount); + if (*Record == NULL) { + return EFI_NOT_FOUND; + } + + if (FilterDriver != NULL) { + // + // If we have a filter driver update the records that have been read. + // If MonotonicCount is zero No more reacords left. + // + if (*MonotonicCount == 0) { + if (FilterMonotonicCount != 0) { + // + // Return the result of our extra GetNextDataRecord. + // + FilterDriver->GetNextMonotonicCount = FilterMonotonicCount; + } + } else { + // + // Point to next undread record + // + FilterDriver->GetNextMonotonicCount = *MonotonicCount; + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +DataHubRegisterFilterDriver ( + IN EFI_DATA_HUB_PROTOCOL * This, + IN EFI_EVENT FilterEvent, + IN EFI_TPL FilterTpl, + IN UINT64 FilterClass, + IN EFI_GUID * FilterDataRecordGuid OPTIONAL + ) +/*++ + +Routine Description: + + This function registers the data hub filter driver that is represented + by FilterEvent. Only one instance of each FilterEvent can be registered. + After the FilterEvent is registered, it will be signaled so it can sync + with data records that have been recorded prior to the FilterEvent being + registered. + +Arguments: + + This - The EFI_DATA_HUB_PROTOCOL instance. + FilterEvent - The EFI_EVENT to signal whenever data that matches + FilterClass is logged in the system. + FilterTpl - The maximum EFI_TPL at which FilterEvent can be + signaled. It is strongly recommended that you use the + lowest EFI_TPL possible. + FilterClass - FilterEvent will be signaled whenever a bit in + EFI_DATA_RECORD_HEADER.DataRecordClass is also set in + FilterClass. If FilterClass is zero, no class-based + filtering will be performed. + FilterDataRecordGuid - FilterEvent will be signaled whenever FilterDataRecordGuid + matches EFI_DATA_RECORD_HEADER.DataRecordGuid. If + FilterDataRecordGuid is NULL, then no GUID-based filtering + will be performed. +Returns: + + EFI_SUCCESS - The filter driver event was registered. + EFI_ALREADY_STARTED - FilterEvent was previously registered and cannot be + registered again. + EFI_OUT_OF_RESOURCES - The filter driver event was not registered due to lack of + system resources. + +--*/ +{ + DATA_HUB_INSTANCE *Private; + DATA_HUB_FILTER_DRIVER *FilterDriver; + + Private = DATA_HUB_INSTANCE_FROM_THIS (This); + + FilterDriver = (DATA_HUB_FILTER_DRIVER *) AllocateZeroPool (sizeof (DATA_HUB_FILTER_DRIVER)); + if (FilterDriver == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Initialize filter driver info + // + FilterDriver->Signature = EFI_DATA_HUB_FILTER_DRIVER_SIGNATURE; + FilterDriver->Event = FilterEvent; + FilterDriver->Tpl = FilterTpl; + FilterDriver->GetNextMonotonicCount = 0; + if (FilterClass == 0) { + FilterDriver->ClassFilter = EFI_DATA_RECORD_CLASS_DEBUG | + EFI_DATA_RECORD_CLASS_ERROR | + EFI_DATA_RECORD_CLASS_DATA | + EFI_DATA_RECORD_CLASS_PROGRESS_CODE; + } else { + FilterDriver->ClassFilter = FilterClass; + } + + if (FilterDataRecordGuid != NULL) { + CopyMem (&FilterDriver->FilterDataRecordGuid, FilterDataRecordGuid, sizeof (EFI_GUID)); + } + // + // Search for duplicate entries + // + if (FindFilterDriverByEvent (&Private->FilterDriverListHead, FilterEvent) != NULL) { + gBS->FreePool (FilterDriver); + return EFI_ALREADY_STARTED; + } + // + // Make insertion an atomic operation with the lock. + // + EfiAcquireLock (&Private->DataLock); + InsertTailList (&Private->FilterDriverListHead, &FilterDriver->Link); + EfiReleaseLock (&Private->DataLock); + + // + // Signal the Filter driver we just loaded so they will recieve all the + // previous history. If we did not signal here we would have to wait until + // the next data was logged to get the history. In a case where no next + // data was logged we would never get synced up. + // + gBS->SignalEvent (FilterEvent); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +DataHubUnregisterFilterDriver ( + IN EFI_DATA_HUB_PROTOCOL *This, + IN EFI_EVENT FilterEvent + ) +/*++ + +Routine Description: + + Remove a Filter Driver, so it no longer gets called when data + information is logged. + +Arguments: + + This - Protocol instance structure + + FilterEvent - Event that represents a filter driver that is to be + Unregistered. + +Returns: + + EFI_SUCCESS - If FilterEvent was unregistered + + EFI_NOT_FOUND - If FilterEvent does not exist + +--*/ +{ + DATA_HUB_INSTANCE *Private; + DATA_HUB_FILTER_DRIVER *FilterDriver; + + Private = DATA_HUB_INSTANCE_FROM_THIS (This); + + // + // Search for duplicate entries + // + FilterDriver = FindFilterDriverByEvent ( + &Private->FilterDriverListHead, + FilterEvent + ); + if (FilterDriver == NULL) { + return EFI_NOT_FOUND; + } + // + // Make removal an atomic operation with the lock + // + EfiAcquireLock (&Private->DataLock); + RemoveEntryList (&FilterDriver->Link); + EfiReleaseLock (&Private->DataLock); + + return EFI_SUCCESS; +} +// +// STATIC Worker fucntions follow +// +STATIC +DATA_HUB_FILTER_DRIVER * +FindFilterDriverByEvent ( + IN LIST_ENTRY *Head, + IN EFI_EVENT Event + ) +/*++ + +Routine Description: + Search the Head list for a EFI_DATA_HUB_FILTER_DRIVER member that + represents Event and return it. + +Arguments: + + Head - Head of dual linked list of EFI_DATA_HUB_FILTER_DRIVER + structures. + + Event - Event to be search for in the Head list. + +Returns: + + EFI_DATA_HUB_FILTER_DRIVER - Returned if Event stored in the + Head doubly linked list. + + NULL - If Event is not in the list + +--*/ +{ + DATA_HUB_FILTER_DRIVER *FilterEntry; + LIST_ENTRY *Link; + + for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) { + FilterEntry = FILTER_ENTRY_FROM_LINK (Link); + if (FilterEntry->Event == Event) { + return FilterEntry; + } + } + + return NULL; +} + +STATIC +EFI_DATA_RECORD_HEADER * +GetNextDataRecord ( + IN LIST_ENTRY *Head, + IN UINT64 ClassFilter, + IN OUT UINT64 *PtrCurrentMTC + ) +/*++ + +Routine Description: + Search the Head doubly linked list for the passed in MTC. Return the + matching element in Head and the MTC on the next entry. + +Arguments: + + Head - Head of Data Log linked list. + + ClassFilter - Only match the MTC if it is in the same Class as the + ClassFilter. + + PtrCurrentMTC - On IN contians MTC to search for. On OUT contians next + MTC in the data log list or zero if at end of the list. + +Returns: + + EFI_DATA_LOG_ENTRY - Return pointer to data log data from Head list. + + NULL - If no data record exists. + +--*/ +{ + EFI_DATA_ENTRY *LogEntry; + LIST_ENTRY *Link; + BOOLEAN ReturnFirstEntry; + EFI_DATA_RECORD_HEADER *Record; + EFI_DATA_ENTRY *NextLogEntry; + + // + // If MonotonicCount == 0 just return the first one + // + ReturnFirstEntry = (BOOLEAN) (*PtrCurrentMTC == 0); + + Record = NULL; + for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) { + LogEntry = DATA_ENTRY_FROM_LINK (Link); + if ((LogEntry->Record->DataRecordClass & ClassFilter) == 0) { + // + // Skip any entry that does not have the correct ClassFilter + // + continue; + } + + if ((LogEntry->Record->LogMonotonicCount == *PtrCurrentMTC) || ReturnFirstEntry) { + // + // Return record to the user + // + Record = LogEntry->Record; + + // + // Calculate the next MTC value. If there is no next entry set + // MTC to zero. + // + *PtrCurrentMTC = 0; + for (Link = Link->ForwardLink; Link != Head; Link = Link->ForwardLink) { + NextLogEntry = DATA_ENTRY_FROM_LINK (Link); + if ((NextLogEntry->Record->DataRecordClass & ClassFilter) != 0) { + // + // Return the MTC of the next thing to search for if found + // + *PtrCurrentMTC = NextLogEntry->Record->LogMonotonicCount; + break; + } + } + // + // Record found exit loop and return + // + break; + } + } + + return Record; +} +// +// Module Global: +// Since this driver will only ever produce one instance of the Logging Hub +// protocol you are not required to dynamically allocate the PrivateData. +// +DATA_HUB_INSTANCE mPrivateData; + +EFI_STATUS +EFIAPI +DataHubInstall ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + Install Driver to produce Data Hub protocol. + +Arguments: + (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT) + +Returns: + + EFI_SUCCESS - Logging Hub protocol installed + + Other - No protocol installed, unload driver. + +--*/ +{ + EFI_STATUS Status; + UINT32 HighMontonicCount; + + mPrivateData.Signature = DATA_HUB_INSTANCE_SIGNATURE; + mPrivateData.DataHub.LogData = DataHubLogData; + mPrivateData.DataHub.GetNextRecord = DataHubGetNextRecord; + mPrivateData.DataHub.RegisterFilterDriver = DataHubRegisterFilterDriver; + mPrivateData.DataHub.UnregisterFilterDriver = DataHubUnregisterFilterDriver; + + // + // Initialize Private Data in CORE_LOGGING_HUB_INSTANCE that is + // required by this protocol + // + InitializeListHead (&mPrivateData.DataListHead); + InitializeListHead (&mPrivateData.FilterDriverListHead); + + EfiInitializeLock (&mPrivateData.DataLock, EFI_TPL_NOTIFY); + + // + // Make sure we get a bigger MTC number on every boot! + // + Status = gRT->GetNextHighMonotonicCount (&HighMontonicCount); + if (EFI_ERROR (Status)) { + // + // if system service fails pick a sane value. + // + mPrivateData.GlobalMonotonicCount = 0; + } else { + mPrivateData.GlobalMonotonicCount = LShiftU64 ((UINT64) HighMontonicCount, 32); + } + // + // Make a new handle and install the protocol + // + mPrivateData.Handle = NULL; + Status = gBS->InstallProtocolInterface ( + &mPrivateData.Handle, + &gEfiDataHubProtocolGuid, + EFI_NATIVE_INTERFACE, + &mPrivateData.DataHub + ); + return Status; +} diff --git a/EdkModulePkg/Universal/DataHub/DataHub/Dxe/DataHub.dxs b/EdkModulePkg/Universal/DataHub/DataHub/Dxe/DataHub.dxs new file mode 100644 index 0000000000..3483185b35 --- /dev/null +++ b/EdkModulePkg/Universal/DataHub/DataHub/Dxe/DataHub.dxs @@ -0,0 +1,26 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DataHub.dxs + +Abstract: + + Dependency expression source file. + +--*/ +#include +#include + +DEPENDENCY_START + TRUE +DEPENDENCY_END diff --git a/EdkModulePkg/Universal/DataHub/DataHub/Dxe/DataHub.h b/EdkModulePkg/Universal/DataHub/DataHub/Dxe/DataHub.h new file mode 100644 index 0000000000..fb364a3b38 --- /dev/null +++ b/EdkModulePkg/Universal/DataHub/DataHub/Dxe/DataHub.h @@ -0,0 +1,122 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DataHub.h + +Abstract: + This code supports a the private implementation + of the Data Hub protocol + +--*/ + +#ifndef _DATA_HUB_H_ +#define _DATA_HUB_H_ + + +#define DATA_HUB_INSTANCE_SIGNATURE EFI_SIGNATURE_32 ('D', 'H', 'u', 'b') +typedef struct { + UINT32 Signature; + + EFI_HANDLE Handle; + + // + // Produced protocol(s) + // + EFI_DATA_HUB_PROTOCOL DataHub; + + // + // Private Data + // + // + // Updates to GlobalMonotonicCount, LogListHead, and FilterDriverListHead + // must be locked. + // + EFI_LOCK DataLock; + + // + // Runing Monotonic Count to use for each error record. + // Increment AFTER use in an error record. + // + UINT64 GlobalMonotonicCount; + + // + // List of EFI_DATA_ENTRY structures. This is the data log! The list + // must be in assending order of LogMonotonicCount. + // + LIST_ENTRY DataListHead; + + // + // List of EFI_DATA_HUB_FILTER_DRIVER structures. Represents all + // the registered filter drivers. + // + LIST_ENTRY FilterDriverListHead; + +} DATA_HUB_INSTANCE; + +#define DATA_HUB_INSTANCE_FROM_THIS(this) CR (this, DATA_HUB_INSTANCE, DataHub, DATA_HUB_INSTANCE_SIGNATURE) + +// +// Private data structure to contain the data log. One record per +// structure. Head pointer to the list is the Log member of +// EFI_DATA_ENTRY. Record is a copy of the data passed in. +// +#define EFI_DATA_ENTRY_SIGNATURE EFI_SIGNATURE_32 ('D', 'r', 'e', 'c') +typedef struct { + UINT32 Signature; + LIST_ENTRY Link; + + EFI_DATA_RECORD_HEADER *Record; + + UINTN RecordSize; + +} EFI_DATA_ENTRY; + +#define DATA_ENTRY_FROM_LINK(link) CR (link, EFI_DATA_ENTRY, Link, EFI_DATA_ENTRY_SIGNATURE) + +// +// Private data to contain the filter driver Event and it's +// associated EFI_TPL. +// +#define EFI_DATA_HUB_FILTER_DRIVER_SIGNATURE EFI_SIGNATURE_32 ('D', 'h', 'F', 'd') + +typedef struct { + UINT32 Signature; + LIST_ENTRY Link; + + // + // Store Filter Driver Event and Tpl level it can be Signaled at. + // + EFI_EVENT Event; + EFI_TPL Tpl; + + // + // Monotonic count on the get next operation for Event. + // Zero indicates get next has not been called for this event yet. + // + UINT64 GetNextMonotonicCount; + + // + // Filter driver will register what class filter should be used. + // + UINT64 ClassFilter; + + // + // Filter driver will register what record guid filter should be used. + // + EFI_GUID FilterDataRecordGuid; + +} DATA_HUB_FILTER_DRIVER; + +#define FILTER_ENTRY_FROM_LINK(link) CR (link, DATA_HUB_FILTER_DRIVER, Link, EFI_DATA_HUB_FILTER_DRIVER_SIGNATURE) + +#endif diff --git a/EdkModulePkg/Universal/DataHub/DataHub/Dxe/DataHub.mbd b/EdkModulePkg/Universal/DataHub/DataHub/Dxe/DataHub.mbd new file mode 100644 index 0000000000..39b2c9393b --- /dev/null +++ b/EdkModulePkg/Universal/DataHub/DataHub/Dxe/DataHub.mbd @@ -0,0 +1,44 @@ + + + + + DataHub + 53BCC14F-C24F-434C-B294-8ED2D4CC1860 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + BaseLib + DxeMemoryAllocationLib + + + _ModuleEntryPoint + + diff --git a/EdkModulePkg/Universal/DataHub/DataHub/Dxe/DataHub.msa b/EdkModulePkg/Universal/DataHub/DataHub/Dxe/DataHub.msa new file mode 100644 index 0000000000..a9f318e1d7 --- /dev/null +++ b/EdkModulePkg/Universal/DataHub/DataHub/Dxe/DataHub.msa @@ -0,0 +1,61 @@ + + + + + DataHub + DXE_DRIVER + BS_DRIVER + 53BCC14F-C24F-434C-B294-8ED2D4CC1860 + 0 + Component description file for DiskIo module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + DebugLib + UefiDriverEntryPoint + UefiLib + BaseLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + + + DataHub.c + DataHub.h + DataHub.dxs + + + MdePkg + EdkModulePkg + + + DataHub + + + + DataHubInstall + + + diff --git a/EdkModulePkg/Universal/DataHub/DataHub/Dxe/build.xml b/EdkModulePkg/Universal/DataHub/DataHub/Dxe/build.xml new file mode 100644 index 0000000000..9d59b30b4b --- /dev/null +++ b/EdkModulePkg/Universal/DataHub/DataHub/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Universal/DataHub/DataHubStdErr/Dxe/DataHubStdErr.c b/EdkModulePkg/Universal/DataHub/DataHubStdErr/Dxe/DataHubStdErr.c new file mode 100644 index 0000000000..1a392ab703 --- /dev/null +++ b/EdkModulePkg/Universal/DataHub/DataHubStdErr/Dxe/DataHubStdErr.c @@ -0,0 +1,163 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DataHubStdErr.c + +Abstract: + + Data Hub filter driver that takes DEBUG () info from Data Hub and writes it + to StdErr if it exists. + +--*/ + + + +EFI_DATA_HUB_PROTOCOL *mDataHub = NULL; + +EFI_EVENT mDataHubStdErrEvent; + +STATIC +VOID +EFIAPI +DataHubStdErrEventHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + Event handler registered with the Data Hub to parse EFI_DEBUG_CODE. This + handler reads the Data Hub and sends any DEBUG info to StdErr. + +Arguments: + Event - The event that occured, not used + Context - DataHub Protocol Pointer + +Returns: + None. + +--*/ +{ + EFI_STATUS Status; + EFI_DATA_HUB_PROTOCOL *DataHub; + EFI_DATA_RECORD_HEADER *Record; + DATA_HUB_STATUS_CODE_DATA_RECORD *DataRecord; + UINT64 Mtc; + EFI_SIMPLE_TEXT_OUT_PROTOCOL *Sto; + INT32 OldAttribute; + + DataHub = (EFI_DATA_HUB_PROTOCOL *) Context; + + // + // If StdErr is not yet initialized just return a DEBUG print in the BDS + // after consoles are connect will make sure data gets flushed properly + // when StdErr is availible. + // + if (gST == NULL) { + return ; + } + + if (gST->StdErr == NULL) { + return ; + } + // + // Mtc of zero means return the next record that has not been read by the + // event handler. + // + Mtc = 0; + do { + Status = DataHub->GetNextRecord (DataHub, &Mtc, &mDataHubStdErrEvent, &Record); + if (!EFI_ERROR (Status)) { + if (CompareGuid (&Record->DataRecordGuid, &gEfiStatusCodeGuid)) { + DataRecord = (DATA_HUB_STATUS_CODE_DATA_RECORD *) (((CHAR8 *) Record) + Record->HeaderSize); + + if (DataRecord->Data.HeaderSize > 0) { + if (CompareGuid (&DataRecord->Data.Type, &gEfiStatusCodeDataTypeDebugGuid)) { + // + // If the Data record is from a DEBUG () then send it to Standard Error + // + Sto = gST->StdErr; + OldAttribute = Sto->Mode->Attribute; + Sto->SetAttribute (Sto, EFI_TEXT_ATTR (EFI_MAGENTA, EFI_BLACK)); + Sto->OutputString (Sto, (CHAR16 *) (DataRecord + 1)); + Sto->SetAttribute (Sto, OldAttribute); + } + } + } + } + } while ((Mtc != 0) && !EFI_ERROR (Status)); +} + +EFI_STATUS +EFIAPI +DataHubStdErrInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Register an event handler with the Data Hub to parse EFI_DEBUG_CODE. This + handler reads the Data Hub and sends any DEBUG info to StdErr. + +Arguments: + + ImageHandle - Image handle of this driver. + SystemTable - Pointer to EFI system table. + +Returns: + + EFI_SUCCESS - The event handler was registered. + EFI_OUT_OF_RESOURCES - The event hadler was not registered due to lack of + system resources. + +--*/ +{ + EFI_STATUS Status; + UINT64 DataClass; + + gBS->LocateProtocol (&gEfiDataHubProtocolGuid, NULL, (VOID **) &mDataHub); + // + // Should never fail due to Depex grammer. + // + ASSERT (mDataHub != NULL); + + // + // Create an event and register it with the filter driver + // + Status = gBS->CreateEvent ( + EFI_EVENT_NOTIFY_SIGNAL, + EFI_TPL_CALLBACK, + DataHubStdErrEventHandler, + mDataHub, + &mDataHubStdErrEvent + ); + if (EFI_ERROR (Status)) { + return Status; + } + + DataClass = EFI_DATA_RECORD_CLASS_DEBUG | EFI_DATA_RECORD_CLASS_ERROR; + Status = mDataHub->RegisterFilterDriver ( + mDataHub, + mDataHubStdErrEvent, + EFI_TPL_CALLBACK, + DataClass, + NULL + ); + if (EFI_ERROR (Status)) { + gBS->CloseEvent (mDataHubStdErrEvent); + } + + return Status; +} diff --git a/EdkModulePkg/Universal/DataHub/DataHubStdErr/Dxe/DataHubStdErr.dxs b/EdkModulePkg/Universal/DataHub/DataHubStdErr/Dxe/DataHubStdErr.dxs new file mode 100644 index 0000000000..ac6fb1db4d --- /dev/null +++ b/EdkModulePkg/Universal/DataHub/DataHubStdErr/Dxe/DataHubStdErr.dxs @@ -0,0 +1,27 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DataHubStdErr.dxs + +Abstract: + + Dependency expression source file. + +--*/ +#include +#include + + +DEPENDENCY_START + EFI_DATA_HUB_PROTOCOL_GUID +DEPENDENCY_END diff --git a/EdkModulePkg/Universal/DataHub/DataHubStdErr/Dxe/DataHubStdErr.mbd b/EdkModulePkg/Universal/DataHub/DataHubStdErr/Dxe/DataHubStdErr.mbd new file mode 100644 index 0000000000..8d03e0cf3b --- /dev/null +++ b/EdkModulePkg/Universal/DataHub/DataHubStdErr/Dxe/DataHubStdErr.mbd @@ -0,0 +1,41 @@ + + + + + DataHubStdErr + CA515306-00CE-4032-874E-11B755FF6866 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + + UefiBootServicesTableLib + UefiMemoryLib + UefiDriverEntryPoint + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + BaseLib + + + _ModuleEntryPoint + + diff --git a/EdkModulePkg/Universal/DataHub/DataHubStdErr/Dxe/DataHubStdErr.msa b/EdkModulePkg/Universal/DataHub/DataHubStdErr/Dxe/DataHubStdErr.msa new file mode 100644 index 0000000000..63b0d93cd2 --- /dev/null +++ b/EdkModulePkg/Universal/DataHub/DataHubStdErr/Dxe/DataHubStdErr.msa @@ -0,0 +1,64 @@ + + + + + DataHubStdErr + DXE_DRIVER + BS_DRIVER + CA515306-00CE-4032-874E-11B755FF6866 + 0 + Component description file for DiskIo module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + DebugLib + UefiDriverEntryPoint + BaseMemoryLib + UefiBootServicesTableLib + + + DataHubStdErr.c + DataHubStdErr.dxs + + + MdePkg + EdkModulePkg + + + DataHub + + + + StatusCode + + + StatusCodeDataTypeDebug + + + + + DataHubStdErrInitialize + + + diff --git a/EdkModulePkg/Universal/DataHub/DataHubStdErr/Dxe/build.xml b/EdkModulePkg/Universal/DataHub/DataHubStdErr/Dxe/build.xml new file mode 100644 index 0000000000..22bea3fd3b --- /dev/null +++ b/EdkModulePkg/Universal/DataHub/DataHubStdErr/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Universal/DebugSupport/Dxe/DebugSupport.c b/EdkModulePkg/Universal/DebugSupport/Dxe/DebugSupport.c new file mode 100644 index 0000000000..118e9b7979 --- /dev/null +++ b/EdkModulePkg/Universal/DebugSupport/Dxe/DebugSupport.c @@ -0,0 +1,151 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DebugSupport.c + +Abstract: + + Top level C file for debug support driver. Contains initialization function. + +Revision History + +--*/ + +// +// private header files +// +#include "plDebugSupport.h" + +// +// This is a global that is the actual interface +// +EFI_DEBUG_SUPPORT_PROTOCOL gDebugSupportProtocolInterface = { + EFI_ISA, + GetMaximumProcessorIndex, + RegisterPeriodicCallback, + RegisterExceptionCallback, + InvalidateInstructionCache +}; + +// +// Driver Entry Point +// +EFI_STATUS +InitializeDebugSupportDriver ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + Driver entry point. Checks to see there's not already a DebugSupport protocol + installed for the selected processor before installing protocol. + +Arguments: + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + +Returns: + + EFI_STATUS + +--*/ +// TODO: ImageHandle - add argument and description to function comment +// TODO: SystemTable - add argument and description to function comment +{ + EFI_LOADED_IMAGE_PROTOCOL *LoadedImageProtocolPtr; + EFI_STATUS Status; + EFI_HANDLE Handle; + EFI_HANDLE *HandlePtr; + UINTN NumHandles; + EFI_DEBUG_SUPPORT_PROTOCOL *DebugSupportProtocolPtr; + + // + // Install Protocol Interface... + // + // 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) { + gBS->FreePool (HandlePtr); + Status = EFI_ALREADY_STARTED; + goto ErrExit; + } + } while (NumHandles > 0); + gBS->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 platform specific initialization + // + Status = plInitializeDebugSupportDriver (); + ASSERT (!EFI_ERROR (Status)); + if (Status != EFI_SUCCESS) { + goto ErrExit; + } + + // + // Install DebugSupport protocol to new handle + // + Handle = NULL; + Status = gBS->InstallProtocolInterface ( + &Handle, + &gEfiDebugSupportProtocolGuid, + EFI_NATIVE_INTERFACE, + &gDebugSupportProtocolInterface + ); + ASSERT (!EFI_ERROR (Status)); + if (Status != EFI_SUCCESS) { + goto ErrExit; + } + +ErrExit: + return Status; +} diff --git a/EdkModulePkg/Universal/DebugSupport/Dxe/DebugSupport.dxs b/EdkModulePkg/Universal/DebugSupport/Dxe/DebugSupport.dxs new file mode 100644 index 0000000000..34f680a787 --- /dev/null +++ b/EdkModulePkg/Universal/DebugSupport/Dxe/DebugSupport.dxs @@ -0,0 +1,26 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DebugSupport.dxs + +Abstract: + + Dependency expression source file. + +--*/ +#include +#include + +DEPENDENCY_START + TRUE +DEPENDENCY_END diff --git a/EdkModulePkg/Universal/DebugSupport/Dxe/DebugSupport.mbd b/EdkModulePkg/Universal/DebugSupport/Dxe/DebugSupport.mbd new file mode 100644 index 0000000000..a38bf30903 --- /dev/null +++ b/EdkModulePkg/Universal/DebugSupport/Dxe/DebugSupport.mbd @@ -0,0 +1,42 @@ + + + + + DebugSupport + 911D584C-35F7-4955-BEF9-B452769DDC3A + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + + UefiBootServicesTableLib + BaseLib + UefiMemoryLib + UefiDriverEntryPoint + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + DxeMemoryAllocationLib + + + _ModuleEntryPoint + + diff --git a/EdkModulePkg/Universal/DebugSupport/Dxe/DebugSupport.msa b/EdkModulePkg/Universal/DebugSupport/Dxe/DebugSupport.msa new file mode 100644 index 0000000000..3cf5e12299 --- /dev/null +++ b/EdkModulePkg/Universal/DebugSupport/Dxe/DebugSupport.msa @@ -0,0 +1,68 @@ + + + + + DebugSupport + DXE_DRIVER + BS_DRIVER + 911D584C-35F7-4955-BEF9-B452769DDC3A + 0 + Component description file for DiskIo module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + DebugLib + UefiDriverEntryPoint + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + + + DebugSupport.c + DebugSupport.dxs + + ia32\AsmFuncs.asm + ia32\plDebugSupport.c + + + ipf\AsmFuncs.s + ipf\common.i + ipf\ds64macros.i + ipf\plDebugSupport.c + + + + MdePkg + EdkModulePkg + + + DebugSupport + LoadedImage + + + + InitializeDebugSupportDriver + + + diff --git a/EdkModulePkg/Universal/DebugSupport/Dxe/build.xml b/EdkModulePkg/Universal/DebugSupport/Dxe/build.xml new file mode 100644 index 0000000000..b879fc094a --- /dev/null +++ b/EdkModulePkg/Universal/DebugSupport/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Universal/DebugSupport/Dxe/ia32/AsmFuncs.asm b/EdkModulePkg/Universal/DebugSupport/Dxe/ia32/AsmFuncs.asm new file mode 100644 index 0000000000..89c9f83176 --- /dev/null +++ b/EdkModulePkg/Universal/DebugSupport/Dxe/ia32/AsmFuncs.asm @@ -0,0 +1,547 @@ +;****************************************************************************** +;* +;* Copyright (c) 2006, Intel Corporation +;* All rights reserved. This program and the accompanying materials +;* are licensed and made available under the terms and conditions of the BSD License +;* which accompanies this distribution. The full text of the license may be found at +;* http://opensource.org/licenses/bsd-license.php +;* +;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +;* +;****************************************************************************** + +.586p +.MODEL FLAT, C + +EXCPT32_DIVIDE_ERROR EQU 0 +EXCPT32_DEBUG EQU 1 +EXCPT32_NMI EQU 2 +EXCPT32_BREAKPOINT EQU 3 +EXCPT32_OVERFLOW EQU 4 +EXCPT32_BOUND EQU 5 +EXCPT32_INVALID_OPCODE EQU 6 +EXCPT32_DOUBLE_FAULT EQU 8 +EXCPT32_INVALID_TSS EQU 10 +EXCPT32_SEG_NOT_PRESENT EQU 11 +EXCPT32_STACK_FAULT EQU 12 +EXCPT32_GP_FAULT EQU 13 +EXCPT32_PAGE_FAULT EQU 14 +EXCPT32_FP_ERROR EQU 16 +EXCPT32_ALIGNMENT_CHECK EQU 17 +EXCPT32_MACHINE_CHECK EQU 18 +EXCPT32_SIMD EQU 19 + +FXSTOR_FLAG EQU 01000000h ; 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] +FXSTOR_EDI MACRO + db 0fh, 0aeh, 00000111y ; mod = 00, reg/op = 000, r/m = 111 = [edi] +ENDM + +;; fxrstor [esi] +FXRSTOR_ESI MACRO + db 0fh, 0aeh, 00001110y ; mod = 00, reg/op = 001, r/m = 110 = [esi] +ENDM +.DATA + +public OrigVector, InterruptEntryStub, StubSize, CommonIdtEntry, FxStorSupport + +StubSize dd InterruptEntryStubEnd - InterruptEntryStub +AppEsp dd 11111111h ; ? +DebugEsp dd 22222222h ; ? +ExtraPush dd 33333333h ; ? +ExceptData dd 44444444h ; ? +Eflags dd 55555555h ; ? +OrigVector dd 66666666h ; ? + +;; 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 FxSaveState; // 512 bytes, must be 16 byte aligned +;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; +;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; +;; UINT32 Ldtr, Tr; +;; UINT64 Gdtr, Idtr; +;; UINT32 EFlags; +;; UINT32 Eip; +;; UINT32 SegGs, SegFs, SegEs, SegDs, SegCs, SegSs; +;; 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 + dd 1ffdh dup (000000000h) ;; 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 ? ;; first entry will be the vector number pushed by the stub + +DebugStackBegin db "<<<< DbgStkBegin" ;; initial debug ESP == DebugStackBegin, set in stub + +.CODE + +externdef InterruptDistrubutionHub:near + +;------------------------------------------------------------------------------ +; BOOLEAN +; FxStorSupport ( +; void +; ) +; +; Abstract: Returns TRUE if FxStor instructions are supported +; +FxStorSupport PROC C PUBLIC + +; +; 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 +FxStorSupport ENDP + + +;------------------------------------------------------------------------------ +; DESCRIPTOR * +; GetIdtr ( +; void +; ) +; +; Abstract: Returns physical address of IDTR +; +GetIdtr PROC C PUBLIC + LOCAL IdtrBuf:FWORD + + sidt IdtrBuf + mov eax, DWORD PTR IdtrBuf + 2 + ret +GetIdtr ENDP + + +;------------------------------------------------------------------------------ +; BOOLEAN +; WriteInterruptFlag ( +; BOOLEAN NewState +; ) +; +; Abstract: Programs interrupt flag to the requested state and returns previous +; state. +; +WriteInterruptFlag PROC C PUBLIC State:DWORD + + pushfd + pop eax + and eax, 200h + shr eax, 9 + mov ecx, State + .IF ecx == 0 + cli + .ELSE + sti + .ENDIF + ret + +WriteInterruptFlag ENDP + + + +;------------------------------------------------------------------------------ +; void +; Vect2Desc ( +; DESCRIPTOR * DestDesc, +; void (*Vector) (void) +; ) +; +; Abstract: Encodes an IDT descriptor with the given physical address +; +Vect2Desc PROC C PUBLIC DestPtr:DWORD, Vector:DWORD + + mov eax, Vector + mov ecx, DestPtr + mov word ptr [ecx], ax ; write bits 15..0 of offset + mov word ptr [ecx+2], 20h ; SYS_CODE_SEL from GDT + mov word ptr [ecx+4], 0e00h OR 8000h ; type = 386 interrupt gate, present + shr eax, 16 + mov word ptr [ecx+6], ax ; write bits 31..16 of offset + + ret + +Vect2Desc ENDP + + + +;------------------------------------------------------------------------------ +; 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. +; +InterruptEntryStub:: + mov AppEsp, esp ; save stack top + mov esp, offset DebugStackBegin ; switch to debugger stack + push 0 ; push vector number - will be modified before installed + db 0e9h ; 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. +; +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 FxSaveState; +;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; +;; UINT32 Cr0, Cr2, Cr3, Cr4; +;; UINT32 Ldtr, Tr; +;; UINT64 Gdtr, Idtr; +;; UINT32 EFlags; +;; UINT32 Eip; +;; UINT32 SegGs, SegFs, SegEs, SegDs, SegCs, SegSs; +;; 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 dword ptr 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. + .IF ExceptionNumber == EXCPT32_DOUBLE_FAULT + mov ExtraPush, 1 + .ELSEIF ExceptionNumber == EXCPT32_INVALID_TSS + mov ExtraPush, 1 + .ELSEIF ExceptionNumber == EXCPT32_SEG_NOT_PRESENT + mov ExtraPush, 1 + .ELSEIF ExceptionNumber == EXCPT32_STACK_FAULT + mov ExtraPush, 1 + .ELSEIF ExceptionNumber == EXCPT32_GP_FAULT + mov ExtraPush, 1 + .ELSEIF ExceptionNumber == EXCPT32_PAGE_FAULT + mov ExtraPush, 1 + .ELSEIF ExceptionNumber == EXCPT32_ALIGNMENT_CHECK + mov ExtraPush, 1 + .ELSE + mov ExtraPush, 0 + .ENDIF + +;; If there's some extra data, save it also, and modify the saved AppEsp to effectively +;; pop this value off the application's stack. + .IF ExtraPush == 1 + mov eax, AppEsp + mov ebx, [eax] + mov ExceptData, ebx + add eax, 4 + mov AppEsp, eax + .ELSE + mov ExceptData, 0 + .ENDIF + +;; 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 ptr [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 ptr [eax] + +;; UINT64 Gdtr, Idtr; + push 0 + push 0 + sidt fword ptr [esp] + push 0 + push 0 + sgdt fword ptr [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 ptr [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, 208h + 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 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 + +;; 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 InterruptDistrubutionHub + add esp, 8 + +; restore context... +;; UINT32 ExceptionData; + add esp, 4 + +;; FX_SAVE_STATE 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 ptr [eax + 8] + +;; UINT16 Ldtr, Tr; +;; UINT64 Gdtr, Idtr; +;; Best not let anyone mess with these particular registers... + add esp, 24 + +;; UINT32 Eip; + pop dword ptr [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 [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 ExceptionNumber, 068h + 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, NOT 300h ; 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 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 +END + + + diff --git a/EdkModulePkg/Universal/DebugSupport/Dxe/ia32/plDebugSupport.c b/EdkModulePkg/Universal/DebugSupport/Dxe/ia32/plDebugSupport.c new file mode 100644 index 0000000000..2198192a04 --- /dev/null +++ b/EdkModulePkg/Universal/DebugSupport/Dxe/ia32/plDebugSupport.c @@ -0,0 +1,440 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + plDebugSupport.c + +Abstract: + + IA32 specific debug support functions + +Revision History + +--*/ + +// +// private header files +// +#include "plDebugSupport.h" + +// +// This the global main table to keep track of the interrupts +// +IDT_ENTRY *IdtEntryTable = NULL; +DESCRIPTOR NullDesc = 0; + +#ifndef EFI_NT_EMULATOR +STATIC +EFI_STATUS +CreateEntryStub ( + IN EFI_EXCEPTION_TYPE ExceptionType, + OUT VOID **Stub + ) +/*++ + +Routine Description: 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. + +Arguments: + ExceptionType - This is the exception type that the new stub will be created + for. + Stub - On successful exit, *Stub contains the newly allocated entry stub. +Returns: + Typically EFI_SUCCESS + other possibilities are passed through from AllocatePool + +--*/ +{ + EFI_STATUS Status; + UINT8 *StubCopy; + + // + // First, allocate a new buffer and copy the stub code into it + // + Status = gBS->AllocatePool (EfiBootServicesData, StubSize, Stub); + if (Status == EFI_SUCCESS) { + StubCopy = *Stub; + gBS->CopyMem (StubCopy, InterruptEntryStub, StubSize); + + // + // Next 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 Status; +} + +STATIC +EFI_STATUS +HookEntry ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN VOID (*NewCallback) () + ) +/*++ + +Routine Description: + 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. + +Arguments: + ExceptionType - specifies which vector to hook. + NewCallback - a pointer to the new function to be registered. + +Returns: + EFI_SUCCESS + Other possibilities are passed through by CreateEntryStub + +--*/ +// TODO: ) - add argument and description to function comment +{ + BOOLEAN OldIntFlagState; + EFI_STATUS Status; + + Status = CreateEntryStub (ExceptionType, (VOID **) &IdtEntryTable[ExceptionType].StubEntry); + if (Status == EFI_SUCCESS) { + OldIntFlagState = WriteInterruptFlag (0); + ReadIdt (ExceptionType, &(IdtEntryTable[ExceptionType].OrigDesc)); + + ((UINT16 *) &IdtEntryTable[ExceptionType].OrigVector)[0] = ((UINT16 *) &IdtEntryTable[ExceptionType].OrigDesc)[0]; + ((UINT16 *) &IdtEntryTable[ExceptionType].OrigVector)[1] = ((UINT16 *) &IdtEntryTable[ExceptionType].OrigDesc)[3]; + + Vect2Desc (&IdtEntryTable[ExceptionType].NewDesc, IdtEntryTable[ExceptionType].StubEntry); + IdtEntryTable[ExceptionType].RegisteredCallback = NewCallback; + WriteIdt (ExceptionType, &(IdtEntryTable[ExceptionType].NewDesc)); + WriteInterruptFlag (OldIntFlagState); + } + + return Status; +} + +STATIC +EFI_STATUS +UnhookEntry ( + IN EFI_EXCEPTION_TYPE ExceptionType + ) +/*++ + +Routine Description: + Undoes HookEntry. This code executes in boot services context. + +Arguments: + ExceptionType - specifies which entry to unhook + +Returns: + EFI_SUCCESS + Other values are passed through from FreePool + +--*/ +{ + BOOLEAN OldIntFlagState; + EFI_STATUS Status; + + OldIntFlagState = WriteInterruptFlag (0); + WriteIdt (ExceptionType, &(IdtEntryTable[ExceptionType].OrigDesc)); + Status = gBS->FreePool ((VOID *) (UINTN) IdtEntryTable[ExceptionType].StubEntry); + ZeroMem (&IdtEntryTable[ExceptionType], sizeof (IDT_ENTRY)); + WriteInterruptFlag (OldIntFlagState); + + return (Status); +} +#endif + +EFI_STATUS +ManageIdtEntryTable ( + VOID (*NewCallback)(), + EFI_EXCEPTION_TYPE ExceptionType + ) +/*++ + +Routine Description: + 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. + +Arguments: + NewCallback - If non-NULL, NewCallback specifies the new handler to register. + If NULL, specifies that the previously registered handler should + be uninstalled. + ExceptionType - Indicates which entry to manage + +Returns: + EFI_SUCCESS + EFI_INVALID_PARAMETER - requested uninstalling a handler from a vector that has + no handler registered for it + EFI_ALREADY_STARTED - requested install to a vector that already has a handler registered. + + Other possible return values are passed through from UnHookEntry and HookEntry. + +--*/ +// TODO: ) - add argument and description to function comment +{ + EFI_STATUS Status; + + Status = EFI_SUCCESS; + +#ifndef EFI_NT_EMULATOR + if (CompareDescriptor (&IdtEntryTable[ExceptionType].NewDesc, &NullDesc)) { + // + // we've already installed to this vector + // + if (NewCallback != NULL) { + // + // if the input handler is non-null, error + // + Status = EFI_ALREADY_STARTED; + } else { + Status = 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 { + Status = HookEntry (ExceptionType, NewCallback); + } + } +#endif + return Status; +} + +EFI_STATUS +EFIAPI +GetMaximumProcessorIndex ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + OUT UINTN *MaxProcessorIndex + ) +/*++ + +Routine Description: This is a DebugSupport protocol member function. + +Arguments: + +Returns: Always returns EFI_SUCCESS with *MaxProcessorIndex set to 0 + +--*/ +// TODO: This - add argument and description to function comment +// TODO: MaxProcessorIndex - add argument and description to function comment +{ + *MaxProcessorIndex = 0; + return (EFI_SUCCESS); +} + +EFI_STATUS +EFIAPI +RegisterPeriodicCallback ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + IN UINTN ProcessorIndex, + IN EFI_PERIODIC_CALLBACK PeriodicCallback + ) +/*++ + +Routine Description: This is a DebugSupport protocol member function. + +Arguments: + +Returns: + +--*/ +// TODO: This - add argument and description to function comment +// TODO: ProcessorIndex - add argument and description to function comment +// TODO: PeriodicCallback - add argument and description to function comment +{ + return ManageIdtEntryTable (PeriodicCallback, SYSTEM_TIMER_VECTOR); +} + +EFI_STATUS +EFIAPI +RegisterExceptionCallback ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + IN UINTN ProcessorIndex, + IN EFI_EXCEPTION_CALLBACK NewCallback, + IN EFI_EXCEPTION_TYPE ExceptionType + ) +/*++ + +Routine Description: + This is a DebugSupport protocol member function. + + This code executes in boot services context. + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: ProcessorIndex - add argument and description to function comment +// TODO: NewCallback - add argument and description to function comment +// TODO: ExceptionType - add argument and description to function comment +{ + return ManageIdtEntryTable (NewCallback, ExceptionType); +} + +EFI_STATUS +EFIAPI +InvalidateInstructionCache ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + IN UINTN ProcessorIndex, + IN VOID *Start, + IN UINT64 Length + ) +/*++ + +Routine Description: + This is a DebugSupport protocol member function. + For IA32, this is a no-op since the instruction and data caches are coherent. + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: ProcessorIndex - add argument and description to function comment +// TODO: Start - add argument and description to function comment +// TODO: Length - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + return EFI_SUCCESS; +} + +EFI_STATUS +plInitializeDebugSupportDriver ( + VOID + ) +/*++ + +Routine Description: + Initializes driver's handler registration database. + + This code executes in boot services context. + +Arguments: + None + +Returns: + EFI_SUCCESS + EFI_UNSUPPORTED - if IA32 processor does not support FXSTOR/FXRSTOR instructions, + the context save will fail, so these processor's are not supported. + +--*/ +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +{ + if (!FxStorSupport ()) { + return EFI_UNSUPPORTED; + } else { + IdtEntryTable = AllocateZeroPool (sizeof (IDT_ENTRY) * NUM_IDT_ENTRIES); + if (IdtEntryTable != NULL) { + return EFI_SUCCESS; + } else { + return EFI_OUT_OF_RESOURCES; + } + } +} + +EFI_STATUS +EFIAPI +plUnloadDebugSupportDriver ( + IN EFI_HANDLE ImageHandle + ) +/*++ + +Routine Description: + 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. + + This code executes in boot services context. + +Arguments: + ImageHandle - The image handle of the unload handler + +Returns: + + None + +--*/ +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_EXCEPTION_TYPE ExceptionType; + + for (ExceptionType = 0; ExceptionType < NUM_IDT_ENTRIES; ExceptionType++) { + ManageIdtEntryTable (NULL, ExceptionType); + } + + gBS->FreePool (IdtEntryTable); + return EFI_SUCCESS; +} + +VOID +InterruptDistrubutionHub ( + EFI_EXCEPTION_TYPE ExceptionType, + EFI_SYSTEM_CONTEXT_IA32 *ContextRecord + ) +/*++ + +Routine Description: Common piece of code that invokes the registered handlers. + + This code executes in exception context so no efi calls are allowed. + +Arguments: + +Returns: + + None + +--*/ +// TODO: ExceptionType - add argument and description to function comment +// TODO: ContextRecord - add argument and description to function comment +{ + if (IdtEntryTable[ExceptionType].RegisteredCallback != NULL) { + if (ExceptionType != SYSTEM_TIMER_VECTOR) { + IdtEntryTable[ExceptionType].RegisteredCallback (ExceptionType, ContextRecord); + } else { + OrigVector = IdtEntryTable[ExceptionType].OrigVector; + IdtEntryTable[ExceptionType].RegisteredCallback (ContextRecord); + } + } +} diff --git a/EdkModulePkg/Universal/DebugSupport/Dxe/ia32/plDebugSupport.h b/EdkModulePkg/Universal/DebugSupport/Dxe/ia32/plDebugSupport.h new file mode 100644 index 0000000000..abb6967dea --- /dev/null +++ b/EdkModulePkg/Universal/DebugSupport/Dxe/ia32/plDebugSupport.h @@ -0,0 +1,312 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + plDebugSupport.h + +Abstract: + + IA32 specific debug support macros, typedefs and prototypes. + +Revision History + +--*/ + +#ifndef _PLDEBUG_SUPPORT_H +#define _PLDEBUG_SUPPORT_H + +#define NUM_IDT_ENTRIES 0x78 +#define SYSTEM_TIMER_VECTOR 0x68 +#define VECTOR_ENTRY_PAGES 1 +#define CopyDescriptor(Dest, Src) CopyMem ((Dest), (Src), sizeof (DESCRIPTOR)) +#define ZeroDescriptor(Dest) CopyDescriptor ((Dest), &NullDesc) +#define ReadIdt(Vector, Dest) CopyDescriptor ((Dest), &((GetIdtr ())[(Vector)])) +#define WriteIdt(Vector, Src) CopyDescriptor (&((GetIdtr ())[(Vector)]), (Src)) +#define CompareDescriptor(Desc1, Desc2) CompareMem ((Desc1), (Desc2), sizeof (DESCRIPTOR)) +#define EFI_ISA IsaIa32 +#define FF_FXSR (1 << 24) + +typedef UINT64 DESCRIPTOR; + +typedef struct { + DESCRIPTOR OrigDesc; + VOID (*OrigVector) (VOID); + DESCRIPTOR NewDesc; + VOID (*StubEntry) (VOID); + VOID (*RegisteredCallback) (); +} IDT_ENTRY; + +extern EFI_SYSTEM_CONTEXT SystemContext; +extern UINT8 InterruptEntryStub[]; +extern UINT32 StubSize; +extern VOID (*OrigVector) (VOID); + +VOID +CommonIdtEntry ( + VOID + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + None + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +FxStorSupport ( + VOID + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + None + +Returns: + + TODO: add return values + +--*/ +; + +DESCRIPTOR * +GetIdtr ( + VOID + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + None + +Returns: + + TODO: add return values + +--*/ +; + +VOID +Vect2Desc ( + DESCRIPTOR * DestDesc, + VOID (*Vector) (VOID) + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + DestDesc - TODO: add argument description + ) - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +WriteInterruptFlag ( + BOOLEAN NewState + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + NewState - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +plInitializeDebugSupportDriver ( + VOID + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + None + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +plUnloadDebugSupportDriver ( + IN EFI_HANDLE ImageHandle + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ImageHandle - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +// +// DebugSupport protocol member functions +// +EFI_STATUS +EFIAPI +GetMaximumProcessorIndex ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + OUT UINTN *MaxProcessorIndex + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + MaxProcessorIndex - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +RegisterPeriodicCallback ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + IN UINTN ProcessorIndex, + IN EFI_PERIODIC_CALLBACK PeriodicCallback + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + ProcessorIndex - TODO: add argument description + PeriodicCallback - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +RegisterExceptionCallback ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + IN UINTN ProcessorIndex, + IN EFI_EXCEPTION_CALLBACK NewCallback, + IN EFI_EXCEPTION_TYPE ExceptionType + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + ProcessorIndex - TODO: add argument description + NewCallback - TODO: add argument description + ExceptionType - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +InvalidateInstructionCache ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + IN UINTN ProcessorIndex, + IN VOID *Start, + IN UINT64 Length + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + ProcessorIndex - TODO: add argument description + Start - TODO: add argument description + Length - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/EdkModulePkg/Universal/DebugSupport/Dxe/ipf/AsmFuncs.s b/EdkModulePkg/Universal/DebugSupport/Dxe/ipf/AsmFuncs.s new file mode 100644 index 0000000000..1ac4a7e503 --- /dev/null +++ b/EdkModulePkg/Universal/DebugSupport/Dxe/ipf/AsmFuncs.s @@ -0,0 +1,1389 @@ +//++ +// Copyright (c) 2006, Intel Corporation +// All rights reserved. This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// Module Name: +// +// AsmFuncs.s +// +// Abstract: +// +// Low level IPF routines used by the debug support driver +// +// Revision History: +// +//-- + + +#include "common.i" +#include "Ds64Macros.i" + +.global PatchSaveBuffer +.global IpfContextBuf +.global CommonHandler +.global ExternalInterruptCount + + +///////////////////////////////////////////// +// +// Name: +// InstructionCacheFlush +// +// Description: +// Flushes instruction cache for specified number of bytes +// + .global InstructionCacheFlush + .proc InstructionCacheFlush + .align 32 +InstructionCacheFlush:: + { .mii + alloc r3=2, 0, 0, 0 + cmp4.leu p0,p6=32, r33;; + (p6) mov r33=32;; + } + { .mii + nop.m 0 + zxt4 r29=r33;; + dep.z r30=r29, 0, 5;; + } + { .mii + cmp4.eq p0,p7=r0, r30 + shr.u r28=r29, 5;; + (p7) adds r28=1, r28;; + } + { .mii + nop.m 0 + shl r27=r28, 5;; + zxt4 r26=r27;; + } + { .mfb + add r31=r26, r32 + nop.f 0 + nop.b 0 + } +LoopBack: // $L143: + { .mii + fc r32 + adds r32=32, r32;; + cmp.ltu p14,p15=r32, r31 + } + { .mfb + nop.m 0 + nop.f 0 + //(p14) br.cond.dptk.few $L143#;; + (p14) br.cond.dptk.few LoopBack;; + } + { .mmi + sync.i;; + srlz.i + nop.i 0;; + } + { .mfb + nop.m 0 + nop.f 0 + br.ret.sptk.few b0;; + } + .endp InstructionCacheFlush + + +///////////////////////////////////////////// +// +// Name: +// ChainHandler +// +// Description: +// Chains an interrupt handler +// +// The purpose of this function is to enable chaining of the external interrupt. +// Since there's no clean SAL abstraction for doing this, we must do it +// surreptitiously. +// +// The reserved IVT entry at offset 0x3400 is coopted for use by this handler. +// According to Itanium architecture, it is reserved. Strictly speaking, this is +// not safe, as we're cheating and violating the Itanium architecture. However, +// as long as we're the only ones cheating, we should be OK. Without hooks in +// the SAL to enable IVT management, there aren't many good options. +// +// The strategy is to replace the first bundle of the external interrupt handler +// with our own that will branch into a piece of code we've supplied and located +// in the reserved IVT entry. Only the first bundle of the external interrupt +// IVT entry is modified. +// +// The original bundle is moved and relocated to space +// allocated within the reserved IVT entry. The next bundle following is +// is generated to go a hard coded branch back to the second bundle of the +// external interrupt IVT entry just in case the first bundle had no branch. +// +// Our new code will execute our handler, and then fall through to the +// original bundle after restoring all context appropriately. +// +// The following is a representation of what the IVT memory map looks like with +// our chained handler installed: +// +// +// +// +// +// This IVT entry is Failsafe bundle +// reserved by the +// Itanium architecture Original bundle 0 +// and is used for +// for locating our +// handler and the +// original bundle Patch code... +// zero of the ext +// interrupt handler +// +// RSVD (3400) Unused +// +// +// +// +// +// +// +// +// +// +// +// +// EXT_INT (3000) Bundle 0 Bundle zero - This one is +// modified, all other bundles +// in the EXT_INT entry are +// untouched. +// +// +// Arguments: +// +// Returns: +// +// Notes: +// +// + .global ChainHandler + .proc ChainHandler +ChainHandler: + + NESTED_SETUP( 0,2+3,3,0 ) + + mov r8=1 // r8 = success + mov r2=cr.iva;; +// +// NOTE: There's a potential hazard here in that we're simply stealing a bunch of +// bundles (memory) from the IVT and assuming there's no catastrophic side effect. +// +// First, save IVT area we're taking over with the patch so we can restore it later +// + addl out0=PATCH_ENTRY_OFFSET, r2 // out0 = source buffer + movl out1=PatchSaveBuffer // out1 = destination buffer + mov out2=0x40;; // out2 = number of bundles to copy... save entire IDT entry + br.call.sptk.few b0 = CopyBundles + +// Next, copy the patch code into the IVT + movl out0=PatchCode // out0 = source buffer of patch code + addl out1=PATCH_OFFSET, r2 // out1 = destination buffer - in IVT + mov out2=NUM_PATCH_BUNDLES;; // out2 = number of bundles to copy + br.call.sptk.few b0 = CopyBundles + + +// copy original bundle 0 from the external interrupt handler to the +// appropriate place in the reserved IVT interrupt slot + addl out0=EXT_INT_ENTRY_OFFSET, r2 // out0 = source buffer + addl out1=RELOCATED_EXT_INT, r2 // out1 = destination buffer - in reserved IVT + mov out2=1;; // out2 = copy 1 bundle + br.call.sptk.few b0 = CopyBundles + +// Now relocate it there because it very likely had a branch instruction that +// that must now be fixed up. + addl out0=RELOCATED_EXT_INT, r2 // out0 = new runtime address of bundle - in reserved IVT + addl out1=EXT_INT_ENTRY_OFFSET, r2;;// out1 = IP address of previous location + mov out2=out0;; // out2 = IP address of new location + br.call.sptk.few b0 = RelocateBundle + +// Now copy into the failsafe branch into the next bundle just in case +// the original ext int bundle 0 bundle did not contain a branch instruction + movl out0=FailsafeBranch // out0 = source buffer + addl out1=FAILSAFE_BRANCH_OFFSET, r2 // out1 = destination buffer - in reserved IVT + mov out2=1;; // out2 = copy 1 bundle + br.call.sptk.few b0 = CopyBundles + +// Last, copy in our replacement for the external interrupt IVT entry bundle 0 + movl out0=PatchCodeNewBun0 // out0 = source buffer - our replacement bundle 0 + addl out1=EXT_INT_ENTRY_OFFSET, r2 // out1 = destination buffer - bundle 0 of External interrupt entry + mov out2=1;; // out2 = copy 1 bundle + br.call.sptk.few b0 = CopyBundles + +ChainHandlerDone: + NESTED_RETURN + + .endp ChainHandler + + +///////////////////////////////////////////// +// +// Name: +// UnchainHandler +// +// Description: +// Unchains an interrupt handler +// +// Arguments: +// +// Returns: +// +// Notes: +// +// + .global UnchainHandler + .proc UnchainHandler + +UnchainHandler: + + NESTED_SETUP( 0,2+3,3,0 ) + + mov r8=1 // r8 = success + mov r2=cr.iva;; // r2 = interrupt vector address + +// First copy original Ext Int bundle 0 back to it's proper home... + addl out0=RELOCATED_EXT_INT, r2 // out0 = source - in reserved IVT + addl out1=EXT_INT_ENTRY_OFFSET, r2 // out1 = destination buffer - first bundle of Ext Int entry + mov out2=1;; // out2 = copy 1 bundle + br.call.sptk.few b0 = CopyBundles + +// Now, relocate it again... + addl out0=EXT_INT_ENTRY_OFFSET, r2 // out1 = New runtime address + addl out1=RELOCATED_EXT_INT, r2;; // out0 = IP address of previous location + mov out2=out0;; // out2 = IP address of new location + br.call.sptk.few b0 = RelocateBundle + +// Last, restore the patch area + movl out0=PatchSaveBuffer // out0 = source buffer + addl out1=PATCH_ENTRY_OFFSET, r2 // out1 = destination buffer + mov out2=0x40;; // out2 = number of bundles to copy... save entire IDT entry + br.call.sptk.few b0 = CopyBundles + +UnchainHandlerDone: + NESTED_RETURN + + .endp UnchainHandler + + +///////////////////////////////////////////// +// +// Name: +// CopyBundles +// +// Description: +// Copies instruction bundles - flushes icache as necessary +// +// Arguments: +// in0 - Bundle source +// in1 - Bundle destination +// in2 - Bundle count +// +// Returns: +// +// Notes: +// This procedure is a leaf routine +// + .proc CopyBundles + +CopyBundles: + + NESTED_SETUP(3,2+1,0,0) + + shl in2=in2, 1;; // in2 = count of 8 byte blocks to copy + +CopyBundlesLoop: + + cmp.eq p14, p15 = 0, in2;; // Check if done +(p14) br.sptk.few CopyBundlesDone;; + + ld8 loc2=[in0], 0x8;; // loc2 = source bytes + st8 [in1]=loc2;; // [in1] = destination bytes + fc in1;; // Flush instruction cache + sync.i;; // Ensure local and remote data/inst caches in sync + srlz.i;; // Ensure sync has been observed + add in1=0x8, in1;; // in1 = next destination + add in2=-1, in2;; // in2 = decrement 8 bytes blocks to copy + br.sptk.few CopyBundlesLoop;; + +CopyBundlesDone: + NESTED_RETURN + + .endp CopyBundles + + +///////////////////////////////////////////// +// +// Name: +// RelocateBundle +// +// Description: +// Relocates an instruction bundle by updating any ip-relative branch instructions. +// +// Arguments: +// in0 - Runtime address of bundle +// in1 - IP address of previous location of bundle +// in2 - IP address of new location of bundle +// +// Returns: +// in0 - 1 if successful or 0 if unsuccessful +// +// Notes: +// This routine examines all slots in the given bundle that are destined for the +// branch execution unit. If any of these slots contain an IP-relative branch +// namely instructions B1, B2, B3, or B6, the slot is fixed-up with a new relative +// address. Errors can occur if a branch cannot be reached. +// + .proc RelocateBundle + +RelocateBundle: + + NESTED_SETUP(3,2+4,3,0) + + mov loc2=SLOT0 // loc2 = slot index + mov loc5=in0;; // loc5 = runtime address of bundle + mov in0=1;; // in0 = success + +RelocateBundleNextSlot: + + cmp.ge p14, p15 = SLOT2, loc2;; // Check if maximum slot +(p15) br.sptk.few RelocateBundleDone + + mov out0=loc5;; // out0 = runtime address of bundle + br.call.sptk.few b0 = GetTemplate + mov loc3=out0;; // loc3 = instruction template + mov out0=loc5 // out0 = runtime address of bundle + mov out1=loc2;; // out1 = instruction slot number + br.call.sptk.few b0 = GetSlot + mov loc4=out0;; // loc4 = instruction encoding + mov out0=loc4 // out0 = instuction encoding + mov out1=loc2 // out1 = instruction slot number + mov out2=loc3;; // out2 = instruction template + br.call.sptk.few b0 = IsSlotBranch + cmp.eq p14, p15 = 1, out0;; // Check if branch slot +(p15) add loc2=1,loc2 // Increment slot +(p15) br.sptk.few RelocateBundleNextSlot + mov out0=loc4 // out0 = instuction encoding + mov out1=in1 // out1 = IP address of previous location + mov out2=in2;; // out2 = IP address of new location + br.call.sptk.few b0 = RelocateSlot + cmp.eq p14, p15 = 1, out1;; // Check if relocated slot +(p15) mov in0=0 // in0 = failure +(p15) br.sptk.few RelocateBundleDone + mov out2=out0;; // out2 = instruction encoding + mov out0=loc5 // out0 = runtime address of bundle + mov out1=loc2;; // out1 = instruction slot number + br.call.sptk.few b0 = SetSlot + add loc2=1,loc2;; // Increment slot + br.sptk.few RelocateBundleNextSlot + +RelocateBundleDone: + NESTED_RETURN + + .endp RelocateBundle + + +///////////////////////////////////////////// +// +// Name: +// RelocateSlot +// +// Description: +// Relocates an instruction bundle by updating any ip-relative branch instructions. +// +// Arguments: +// in0 - Instruction encoding (41-bits, right justified) +// in1 - IP address of previous location of bundle +// in2 - IP address of new location of bundle +// +// Returns: +// in0 - Instruction encoding (41-bits, right justified) +// in1 - 1 if successful otherwise 0 +// +// Notes: +// This procedure is a leaf routine +// + .proc RelocateSlot + +RelocateSlot: + NESTED_SETUP(3,2+5,0,0) + extr.u loc2=in0, 37, 4;; // loc2 = instruction opcode + cmp.eq p14, p15 = 4, loc2;; // IP-relative branch (B1) or + // IP-relative counted branch (B2) +(p15) cmp.eq p14, p15 = 5, loc2;; // IP-relative call (B3) +(p15) cmp.eq p14, p15 = 7, loc2;; // IP-relative predict (B6) +(p15) mov in1=1 // Instruction did not need to be reencoded +(p15) br.sptk.few RelocateSlotDone + tbit.nz p14, p15 = in0, 36;; // put relative offset sign bit in p14 + extr.u loc2=in0, 13, 20;; // loc2 = relative offset in instruction +(p14) movl loc3=0xfffffffffff00000;; // extend sign +(p14) or loc2=loc2, loc3;; + shl loc2=loc2,4;; // convert to byte offset instead of bundle offset + add loc3=loc2, in1;; // loc3 = physical address of branch target +(p14) sub loc2=r0,loc2;; // flip sign in loc2 if offset is negative + sub loc4=loc3,in2;; // loc4 = relative offset from new ip to branch target + cmp.lt p15, p14 = 0, loc4;; // get new sign bit +(p14) sub loc5=r0,loc4 // get absolute value of offset +(p15) mov loc5=loc4;; + movl loc6=0x0FFFFFF;; // maximum offset in bytes for ip-rel branch + cmp.gt p14, p15 = loc5, loc6;; // check to see we're not out of range for an ip-relative branch +(p14) br.sptk.few RelocateSlotError + cmp.lt p15, p14 = 0, loc4;; // store sign in p14 again +(p14) dep in0=1,in0,36,1 // store sign bit in instruction +(p15) dep in0=0,in0,36,1 + shr loc4=loc4, 4;; // convert back to bundle offset + dep in0=loc4,in0,13,16;; // put first 16 bits of new offset into instruction + shr loc4=loc4,16;; + dep in0=loc4,in0,13+16,4 // put last 4 bits of new offset into instruction + mov in1=1;; // in1 = success + br.sptk.few RelocateSlotDone;; + +RelocateSlotError: + mov in1=0;; // in1 = failure + +RelocateSlotDone: + NESTED_RETURN + + .endp RelocateSlot + + +///////////////////////////////////////////// +// +// Name: +// IsSlotBranch +// +// Description: +// Determines if the given instruction is a branch instruction. +// +// Arguments: +// in0 - Instruction encoding (41-bits, right justified) +// in1 - Instruction slot number +// in2 - Bundle template +// +// Returns: +// in0 - 1 if branch or 0 if not branch +// +// Notes: +// This procedure is a leaf routine +// +// IsSlotBranch recognizes all branch instructions by looking at the provided template. +// The instruction encoding is only passed to this routine for future expansion. +// + .proc IsSlotBranch + +IsSlotBranch: + + NESTED_SETUP (3,2+0,0,0) + + mov in0=1;; // in0 = 1 which destroys the instruction + andcm in2=in2,in0;; // in2 = even template to reduce compares + mov in0=0;; // in0 = not a branch + cmp.eq p14, p15 = 0x16, in2;; // Template 0x16 is BBB +(p14) br.sptk.few IsSlotBranchTrue + cmp.eq p14, p15 = SLOT0, in1;; // Slot 0 has no other possiblities +(p14) br.sptk.few IsSlotBranchDone + cmp.eq p14, p15 = 0x12, in2;; // Template 0x12 is MBB +(p14) br.sptk.few IsSlotBranchTrue + cmp.eq p14, p15 = SLOT1, in1;; // Slot 1 has no other possiblities +(p14) br.sptk.few IsSlotBranchDone + cmp.eq p14, p15 = 0x10, in2;; // Template 0x10 is MIB +(p14) br.sptk.few IsSlotBranchTrue + cmp.eq p14, p15 = 0x18, in2;; // Template 0x18 is MMB +(p14) br.sptk.few IsSlotBranchTrue + cmp.eq p14, p15 = 0x1C, in2;; // Template 0x1C is MFB +(p14) br.sptk.few IsSlotBranchTrue + br.sptk.few IsSlotBranchDone + +IsSlotBranchTrue: + mov in0=1;; // in0 = branch + +IsSlotBranchDone: + NESTED_RETURN + + .endp IsSlotBranch + + +///////////////////////////////////////////// +// +// Name: +// GetTemplate +// +// Description: +// Retrieves the instruction template for an instruction bundle +// +// Arguments: +// in0 - Runtime address of bundle +// +// Returns: +// in0 - Instruction template (5-bits, right-justified) +// +// Notes: +// This procedure is a leaf routine +// + .proc GetTemplate + +GetTemplate: + + NESTED_SETUP (1,2+2,0,0) + + ld8 loc2=[in0], 0x8 // loc2 = first 8 bytes of branch bundle + movl loc3=MASK_0_4;; // loc3 = template mask + and loc2=loc2,loc3;; // loc2 = template, right justified + mov in0=loc2;; // in0 = template, right justified + + NESTED_RETURN + + .endp GetTemplate + + +///////////////////////////////////////////// +// +// Name: +// GetSlot +// +// Description: +// Gets the instruction encoding for an instruction slot and bundle +// +// Arguments: +// in0 - Runtime address of bundle +// in1 - Instruction slot (either 0, 1, or 2) +// +// Returns: +// in0 - Instruction encoding (41-bits, right justified) +// +// Notes: +// This procedure is a leaf routine +// +// Slot0 - [in0 + 0x8] Bits 45-5 +// Slot1 - [in0 + 0x8] Bits 63-46 and [in0] Bits 22-0 +// Slot2 - [in0] Bits 63-23 +// + .proc GetSlot + +GetSlot: + NESTED_SETUP (2,2+3,0,0) + + ld8 loc2=[in0], 0x8;; // loc2 = first 8 bytes of branch bundle + ld8 loc3=[in0];; // loc3 = second 8 bytes of branch bundle + cmp.eq p14, p15 = 2, in1;; // check if slot 2 specified + (p14) br.cond.sptk.few GetSlot2;; // get slot 2 + cmp.eq p14, p15 = 1, in1;; // check if slot 1 specified + (p14) br.cond.sptk.few GetSlot1;; // get slot 1 + +GetSlot0: + extr.u in0=loc2, 5, 45 // in0 = extracted slot 0 + br.sptk.few GetSlotDone;; + +GetSlot1: + extr.u in0=loc2, 46, 18 // in0 = bits 63-46 of loc2 right-justified + extr.u loc4=loc3, 0, 23;; // loc4 = bits 22-0 of loc3 right-justified + dep in0=loc4, in0, 18, 15;; + shr.u loc4=loc4,15;; + dep in0=loc4, in0, 33, 8;; // in0 = extracted slot 1 + br.sptk.few GetSlotDone;; + +GetSlot2: + extr.u in0=loc3, 23, 41;; // in0 = extracted slot 2 + +GetSlotDone: + NESTED_RETURN + + .endp GetSlot + + +///////////////////////////////////////////// +// +// Name: +// SetSlot +// +// Description: +// Sets the instruction encoding for an instruction slot and bundle +// +// Arguments: +// in0 - Runtime address of bundle +// in1 - Instruction slot (either 0, 1, or 2) +// in2 - Instruction encoding (41-bits, right justified) +// +// Returns: +// +// Notes: +// This procedure is a leaf routine +// + .proc SetSlot + +SetSlot: + NESTED_SETUP (3,2+3,0,0) + + ld8 loc2=[in0], 0x8;; // loc2 = first 8 bytes of bundle + ld8 loc3=[in0];; // loc3 = second 8 bytes of bundle + cmp.eq p14, p15 = 2, in1;; // check if slot 2 specified + (p14) br.cond.sptk.few SetSlot2;; // set slot 2 + cmp.eq p14, p15 = 1, in1;; // check if slot 1 specified + (p14) br.cond.sptk.few SetSlot1;; // set slot 1 + +SetSlot0: + dep loc2=0, loc2, 5, 41;; // remove old instruction from slot 0 + shl loc4=in2, 5;; // loc4 = new instruction ready to be inserted + or loc2=loc2, loc4;; // loc2 = updated first 8 bytes of bundle + add loc4=0x8,in0;; // loc4 = address to store first 8 bytes of bundle + st8 [loc4]=loc2 // [loc4] = updated bundle + br.sptk.few SetSlotDone;; + ;; + +SetSlot1: + dep loc2=0, loc2, 46, 18 // remove old instruction from slot 1 + dep loc3=0, loc3, 0, 23;; + shl loc4=in2, 46;; // loc4 = partial instruction ready to be inserted + or loc2=loc2, loc4;; // loc2 = updated first 8 bytes of bundle + add loc4=0x8,in0;; // loc4 = address to store first 8 bytes of bundle + st8 [loc4]=loc2;; // [loc4] = updated bundle + shr.u loc4=in2, 18;; // loc4 = partial instruction ready to be inserted + or loc3=loc3, loc4;; // loc3 = updated second 8 bytes of bundle + st8 [in0]=loc3;; // [in0] = updated bundle + br.sptk.few SetSlotDone;; + +SetSlot2: + dep loc3=0, loc3, 23, 41;; // remove old instruction from slot 2 + shl loc4=in2, 23;; // loc4 = instruction ready to be inserted + or loc3=loc3, loc4;; // loc3 = updated second 8 bytes of bundle + st8 [in0]=loc3;; // [in0] = updated bundle + +SetSlotDone: + + NESTED_RETURN + .endp SetSlot + + +///////////////////////////////////////////// +// +// Name: +// GetIva +// +// Description: +// C callable function to obtain the current value of IVA +// +// Returns: +// Current value if IVA + + .global GetIva + .proc GetIva +GetIva: + mov r8=cr2;; + br.ret.sptk.many b0 + + .endp GetIva + + +///////////////////////////////////////////// +// +// Name: +// ProgramInterruptFlags +// +// Description: +// C callable function to enable/disable interrupts +// +// Returns: +// Previous state of psr.ic +// + .global ProgramInterruptFlags + .proc ProgramInterruptFlags +ProgramInterruptFlags: + alloc loc0=1,2,0,0;; + mov loc0=psr + mov loc1=0x6000;; + and r8=loc0, loc1 // obtain current psr.ic and psr.i state + and in0=in0, loc1 // insure no extra bits set in input + andcm loc0=loc0,loc1;; // clear original psr.i and psr.ic + or loc0=loc0,in0;; // OR in new psr.ic value + mov psr.l=loc0;; // write new psr + srlz.d + br.ret.sptk.many b0 // return + + .endp ProgramInterruptFlags + + +///////////////////////////////////////////// +// +// Name: +// SpillContext +// +// Description: +// Saves system context to context record. +// +// Arguments: +// in0 = 512 byte aligned context record address +// in1 = original B0 +// in2 = original ar.bsp +// in3 = original ar.bspstore +// in4 = original ar.rnat +// in5 = original ar.pfs +// +// Notes: +// loc0 - scratch +// loc1 - scratch +// loc2 - temporary application unat storage +// loc3 - temporary exception handler unat storage + + .proc SpillContext + +SpillContext: + alloc loc0=6,4,0,0;; // alloc 6 input, 4 locals, 0 outs + mov loc2=ar.unat;; // save application context unat (spilled later) + mov ar.unat=r0;; // set UNAT=0 + st8.spill [in0]=r0,8;; + st8.spill [in0]=r1,8;; // save R1 - R31 + st8.spill [in0]=r2,8;; + st8.spill [in0]=r3,8;; + st8.spill [in0]=r4,8;; + st8.spill [in0]=r5,8;; + st8.spill [in0]=r6,8;; + st8.spill [in0]=r7,8;; + st8.spill [in0]=r8,8;; + st8.spill [in0]=r9,8;; + st8.spill [in0]=r10,8;; + st8.spill [in0]=r11,8;; + st8.spill [in0]=r12,8;; + st8.spill [in0]=r13,8;; + st8.spill [in0]=r14,8;; + st8.spill [in0]=r15,8;; + st8.spill [in0]=r16,8;; + st8.spill [in0]=r17,8;; + st8.spill [in0]=r18,8;; + st8.spill [in0]=r19,8;; + st8.spill [in0]=r20,8;; + st8.spill [in0]=r21,8;; + st8.spill [in0]=r22,8;; + st8.spill [in0]=r23,8;; + st8.spill [in0]=r24,8;; + st8.spill [in0]=r25,8;; + st8.spill [in0]=r26,8;; + st8.spill [in0]=r27,8;; + st8.spill [in0]=r28,8;; + st8.spill [in0]=r29,8;; + st8.spill [in0]=r30,8;; + st8.spill [in0]=r31,8;; + mov loc3=ar.unat;; // save debugger context unat (spilled later) + stf.spill [in0]=f2,16;; // save f2 - f31 + stf.spill [in0]=f3,16;; + stf.spill [in0]=f4,16;; + stf.spill [in0]=f5,16;; + stf.spill [in0]=f6,16;; + stf.spill [in0]=f7,16;; + stf.spill [in0]=f8,16;; + stf.spill [in0]=f9,16;; + stf.spill [in0]=f10,16;; + stf.spill [in0]=f11,16;; + stf.spill [in0]=f12,16;; + stf.spill [in0]=f13,16;; + stf.spill [in0]=f14,16;; + stf.spill [in0]=f15,16;; + stf.spill [in0]=f16,16;; + stf.spill [in0]=f17,16;; + stf.spill [in0]=f18,16;; + stf.spill [in0]=f19,16;; + stf.spill [in0]=f20,16;; + stf.spill [in0]=f21,16;; + stf.spill [in0]=f22,16;; + stf.spill [in0]=f23,16;; + stf.spill [in0]=f24,16;; + stf.spill [in0]=f25,16;; + stf.spill [in0]=f26,16;; + stf.spill [in0]=f27,16;; + stf.spill [in0]=f28,16;; + stf.spill [in0]=f29,16;; + stf.spill [in0]=f30,16;; + stf.spill [in0]=f31,16;; + mov loc0=pr;; // save predicates + st8.spill [in0]=loc0,8;; + st8.spill [in0]=in1,8;; // save b0 - b7... in1 already equals saved b0 + mov loc0=b1;; + st8.spill [in0]=loc0,8;; + mov loc0=b2;; + st8.spill [in0]=loc0,8;; + mov loc0=b3;; + st8.spill [in0]=loc0,8;; + mov loc0=b4;; + st8.spill [in0]=loc0,8;; + mov loc0=b5;; + st8.spill [in0]=loc0,8;; + mov loc0=b6;; + st8.spill [in0]=loc0,8;; + mov loc0=b7;; + st8.spill [in0]=loc0,8;; + mov loc0=ar.rsc;; // save ar.rsc + st8.spill [in0]=loc0,8;; + st8.spill [in0]=in2,8;; // save ar.bsp (in2) + st8.spill [in0]=in3,8;; // save ar.bspstore (in3) + st8.spill [in0]=in4,8;; // save ar.rnat (in4) + mov loc0=ar.fcr;; // save ar.fcr (ar21 - IA32 floating-point control register) + st8.spill [in0]=loc0,8;; + mov loc0=ar.eflag;; // save ar.eflag (ar24) + st8.spill [in0]=loc0,8;; + mov loc0=ar.csd;; // save ar.csd (ar25 - ia32 CS descriptor) + st8.spill [in0]=loc0,8;; + mov loc0=ar.ssd;; // save ar.ssd (ar26 - ia32 ss descriptor) + st8.spill [in0]=loc0,8;; + mov loc0=ar.cflg;; // save ar.cflg (ar27 - ia32 cr0 and cr4) + st8.spill [in0]=loc0,8;; + mov loc0=ar.fsr;; // save ar.fsr (ar28 - ia32 floating-point status register) + st8.spill [in0]=loc0,8;; + mov loc0=ar.fir;; // save ar.fir (ar29 - ia32 floating-point instruction register) + st8.spill [in0]=loc0,8;; + mov loc0=ar.fdr;; // save ar.fdr (ar30 - ia32 floating-point data register) + st8.spill [in0]=loc0,8;; + mov loc0=ar.ccv;; // save ar.ccv + st8.spill [in0]=loc0,8;; + st8.spill [in0]=loc2,8;; // save ar.unat (saved to loc2 earlier) + mov loc0=ar.fpsr;; // save floating point status register + st8.spill [in0]=loc0,8;; + st8.spill [in0]=in5,8;; // save ar.pfs + mov loc0=ar.lc;; // save ar.lc + st8.spill [in0]=loc0,8;; + mov loc0=ar.ec;; // save ar.ec + st8.spill [in0]=loc0,8;; + + // save control registers + mov loc0=cr.dcr;; // save dcr + st8.spill [in0]=loc0,8;; + mov loc0=cr.itm;; // save itm + st8.spill [in0]=loc0,8;; + mov loc0=cr.iva;; // save iva + st8.spill [in0]=loc0,8;; + mov loc0=cr.pta;; // save pta + st8.spill [in0]=loc0,8;; + mov loc0=cr.ipsr;; // save ipsr + st8.spill [in0]=loc0,8;; + mov loc0=cr.isr;; // save isr + st8.spill [in0]=loc0,8;; + mov loc0=cr.iip;; // save iip + st8.spill [in0]=loc0,8;; + mov loc0=cr.ifa;; // save ifa + st8.spill [in0]=loc0,8;; + mov loc0=cr.itir;; // save itir + st8.spill [in0]=loc0,8;; + mov loc0=cr.iipa;; // save iipa + st8.spill [in0]=loc0,8;; + mov loc0=cr.ifs;; // save ifs + st8.spill [in0]=loc0,8;; + mov loc0=cr.iim;; // save iim + st8.spill [in0]=loc0,8;; + mov loc0=cr.iha;; // save iha + st8.spill [in0]=loc0,8;; + + // save debug registers + mov loc0=dbr[r0];; // save dbr0 - dbr7 + st8.spill [in0]=loc0,8;; + movl loc1=1;; + mov loc0=dbr[loc1];; + st8.spill [in0]=loc0,8;; + movl loc1=2;; + mov loc0=dbr[loc1];; + st8.spill [in0]=loc0,8;; + movl loc1=3;; + mov loc0=dbr[loc1];; + st8.spill [in0]=loc0,8;; + movl loc1=4;; + mov loc0=dbr[loc1];; + st8.spill [in0]=loc0,8;; + movl loc1=5;; + mov loc0=dbr[loc1];; + st8.spill [in0]=loc0,8;; + movl loc1=6;; + mov loc0=dbr[loc1];; + st8.spill [in0]=loc0,8;; + movl loc1=7;; + mov loc0=dbr[loc1];; + st8.spill [in0]=loc0,8;; + mov loc0=ibr[r0];; // save ibr0 - ibr7 + st8.spill [in0]=loc0,8;; + movl loc1=1;; + mov loc0=ibr[loc1];; + st8.spill [in0]=loc0,8;; + movl loc1=2;; + mov loc0=ibr[loc1];; + st8.spill [in0]=loc0,8;; + movl loc1=3;; + mov loc0=ibr[loc1];; + st8.spill [in0]=loc0,8;; + movl loc1=4;; + mov loc0=ibr[loc1];; + st8.spill [in0]=loc0,8;; + movl loc1=5;; + mov loc0=ibr[loc1];; + st8.spill [in0]=loc0,8;; + movl loc1=6;; + mov loc0=ibr[loc1];; + st8.spill [in0]=loc0,8;; + movl loc1=7;; + mov loc0=ibr[loc1];; + st8.spill [in0]=loc0,8;; + st8.spill [in0]=loc3;; + + br.ret.sptk.few b0 + + .endp SpillContext + + +///////////////////////////////////////////// +// +// Name: +// FillContext +// +// Description: +// Restores register context from context record. +// +// Arguments: +// in0 = address of last element 512 byte aligned context record address +// in1 = modified B0 +// in2 = modified ar.bsp +// in3 = modified ar.bspstore +// in4 = modified ar.rnat +// in5 = modified ar.pfs +// +// Notes: +// loc0 - scratch +// loc1 - scratch +// loc2 - temporary application unat storage +// loc3 - temporary exception handler unat storage + + .proc FillContext +FillContext: + alloc loc0=6,4,0,0;; // alloc 6 inputs, 4 locals, 0 outs + ld8.fill loc3=[in0],-8;; // int_nat (nat bits for R1-31) + movl loc1=7;; // ibr7 + ld8.fill loc0=[in0],-8;; + mov ibr[loc1]=loc0;; + movl loc1=6;; // ibr6 + ld8.fill loc0=[in0],-8;; + mov ibr[loc1]=loc0;; + movl loc1=5;; // ibr5 + ld8.fill loc0=[in0],-8;; + mov ibr[loc1]=loc0;; + movl loc1=4;; // ibr4 + ld8.fill loc0=[in0],-8;; + mov ibr[loc1]=loc0;; + movl loc1=3;; // ibr3 + ld8.fill loc0=[in0],-8;; + mov ibr[loc1]=loc0;; + movl loc1=2;; // ibr2 + ld8.fill loc0=[in0],-8;; + mov ibr[loc1]=loc0;; + movl loc1=1;; // ibr1 + ld8.fill loc0=[in0],-8;; + mov ibr[loc1]=loc0;; + ld8.fill loc0=[in0],-8;; // ibr0 + mov ibr[r0]=loc0;; + movl loc1=7;; // dbr7 + ld8.fill loc0=[in0],-8;; + mov dbr[loc1]=loc0;; + movl loc1=6;; // dbr6 + ld8.fill loc0=[in0],-8;; + mov dbr[loc1]=loc0;; + movl loc1=5;; // dbr5 + ld8.fill loc0=[in0],-8;; + mov dbr[loc1]=loc0;; + movl loc1=4;; // dbr4 + ld8.fill loc0=[in0],-8;; + mov dbr[loc1]=loc0;; + movl loc1=3;; // dbr3 + ld8.fill loc0=[in0],-8;; + mov dbr[loc1]=loc0;; + movl loc1=2;; // dbr2 + ld8.fill loc0=[in0],-8;; + mov dbr[loc1]=loc0;; + movl loc1=1;; // dbr1 + ld8.fill loc0=[in0],-8;; + mov dbr[loc1]=loc0;; + ld8.fill loc0=[in0],-8;; // dbr0 + mov dbr[r0]=loc0;; + ld8.fill loc0=[in0],-8;; // iha + mov cr.iha=loc0;; + ld8.fill loc0=[in0],-8;; // iim + mov cr.iim=loc0;; + ld8.fill loc0=[in0],-8;; // ifs + mov cr.ifs=loc0;; + ld8.fill loc0=[in0],-8;; // iipa + mov cr.iipa=loc0;; + ld8.fill loc0=[in0],-8;; // itir + mov cr.itir=loc0;; + ld8.fill loc0=[in0],-8;; // ifa + mov cr.ifa=loc0;; + ld8.fill loc0=[in0],-8;; // iip + mov cr.iip=loc0;; + ld8.fill loc0=[in0],-8;; // isr + mov cr.isr=loc0;; + ld8.fill loc0=[in0],-8;; // ipsr + mov cr.ipsr=loc0;; + ld8.fill loc0=[in0],-8;; // pta + mov cr.pta=loc0;; + ld8.fill loc0=[in0],-8;; // iva + mov cr.iva=loc0;; + ld8.fill loc0=[in0],-8;; // itm + mov cr.itm=loc0;; + ld8.fill loc0=[in0],-8;; // dcr + mov cr.dcr=loc0;; + ld8.fill loc0=[in0],-8;; // ec + mov ar.ec=loc0;; + ld8.fill loc0=[in0],-8;; // lc + mov ar.lc=loc0;; + ld8.fill in5=[in0],-8;; // ar.pfs + ld8.fill loc0=[in0],-8;; // ar.fpsr + mov ar.fpsr=loc0;; + ld8.fill loc2=[in0],-8;; // ar.unat - restored later... + ld8.fill loc0=[in0],-8;; // ar.ccv + mov ar.ccv=loc0;; + ld8.fill loc0=[in0],-8;; // ar.fdr + mov ar.fdr=loc0;; + ld8.fill loc0=[in0],-8;; // ar.fir + mov ar.fir=loc0;; + ld8.fill loc0=[in0],-8;; // ar.fsr + mov ar.fsr=loc0;; + ld8.fill loc0=[in0],-8;; // ar.cflg + mov ar.cflg=loc0;; + ld8.fill loc0=[in0],-8;; // ar.ssd + mov ar.ssd=loc0;; + ld8.fill loc0=[in0],-8;; // ar.csd + mov ar.csd=loc0;; + ld8.fill loc0=[in0],-8;; // ar.eflag + mov ar.eflag=loc0;; + ld8.fill loc0=[in0],-8;; // ar.fcr + mov ar.fcr=loc0;; + ld8.fill in4=[in0],-8;; // ar.rnat + ld8.fill in3=[in0],-8;; // bspstore + ld8.fill in2=[in0],-8;; // bsp + ld8.fill loc0=[in0],-8;; // ar.rsc + mov ar.rsc=loc0;; + ld8.fill loc0=[in0],-8;; // B7 - B0 + mov b7=loc0;; + ld8.fill loc0=[in0],-8;; + mov b6=loc0;; + ld8.fill loc0=[in0],-8;; + mov b5=loc0;; + ld8.fill loc0=[in0],-8;; + mov b4=loc0;; + ld8.fill loc0=[in0],-8;; + mov b3=loc0;; + ld8.fill loc0=[in0],-8;; + mov b2=loc0;; + ld8.fill loc0=[in0],-8;; + mov b1=loc0;; + ld8.fill in1=[in0],-8;; // b0 is temporarily stored in in1 + ld8.fill loc0=[in0],-16;; // predicates + mov pr=loc0;; + ldf.fill f31=[in0],-16;; + ldf.fill f30=[in0],-16;; + ldf.fill f29=[in0],-16;; + ldf.fill f28=[in0],-16;; + ldf.fill f27=[in0],-16;; + ldf.fill f26=[in0],-16;; + ldf.fill f25=[in0],-16;; + ldf.fill f24=[in0],-16;; + ldf.fill f23=[in0],-16;; + ldf.fill f22=[in0],-16;; + ldf.fill f21=[in0],-16;; + ldf.fill f20=[in0],-16;; + ldf.fill f19=[in0],-16;; + ldf.fill f18=[in0],-16;; + ldf.fill f17=[in0],-16;; + ldf.fill f16=[in0],-16;; + ldf.fill f15=[in0],-16;; + ldf.fill f14=[in0],-16;; + ldf.fill f13=[in0],-16;; + ldf.fill f12=[in0],-16;; + ldf.fill f11=[in0],-16;; + ldf.fill f10=[in0],-16;; + ldf.fill f9=[in0],-16;; + ldf.fill f8=[in0],-16;; + ldf.fill f7=[in0],-16;; + ldf.fill f6=[in0],-16;; + ldf.fill f5=[in0],-16;; + ldf.fill f4=[in0],-16;; + ldf.fill f3=[in0],-16;; + ldf.fill f2=[in0],-8;; + mov ar.unat=loc3;; // restore unat (int_nat) before fill of general registers + ld8.fill r31=[in0],-8;; + ld8.fill r30=[in0],-8;; + ld8.fill r29=[in0],-8;; + ld8.fill r28=[in0],-8;; + ld8.fill r27=[in0],-8;; + ld8.fill r26=[in0],-8;; + ld8.fill r25=[in0],-8;; + ld8.fill r24=[in0],-8;; + ld8.fill r23=[in0],-8;; + ld8.fill r22=[in0],-8;; + ld8.fill r21=[in0],-8;; + ld8.fill r20=[in0],-8;; + ld8.fill r19=[in0],-8;; + ld8.fill r18=[in0],-8;; + ld8.fill r17=[in0],-8;; + ld8.fill r16=[in0],-8;; + ld8.fill r15=[in0],-8;; + ld8.fill r14=[in0],-8;; + ld8.fill r13=[in0],-8;; + ld8.fill r12=[in0],-8;; + ld8.fill r11=[in0],-8;; + ld8.fill r10=[in0],-8;; + ld8.fill r9=[in0],-8;; + ld8.fill r8=[in0],-8;; + ld8.fill r7=[in0],-8;; + ld8.fill r6=[in0],-8;; + ld8.fill r5=[in0],-8;; + ld8.fill r4=[in0],-8;; + ld8.fill r3=[in0],-8;; + ld8.fill r2=[in0],-8;; + ld8.fill r1=[in0],-8;; + mov ar.unat=loc2;; // restore application context unat + + br.ret.sptk.many b0 + + .endp FillContext + + +///////////////////////////////////////////// +// +// Name: +// HookHandler +// +// Description: +// Common branch target from hooked IVT entries. Runs in interrupt context. +// Responsible for saving and restoring context and calling common C +// handler. Banked registers running on bank 0 at entry. +// +// Arguments: +// All arguments are passed in banked registers: +// B0_REG = Original B0 +// SCRATCH_REG1 = IVT entry index +// +// Returns: +// Returns via rfi +// +// Notes: +// loc0 - scratch +// loc1 - scratch +// loc2 - vector number / mask +// loc3 - 16 byte aligned context record address +// loc4 - temporary storage of last address in context record + +HookHandler: + flushrs;; // Synch RSE with backing store + mov SCRATCH_REG2=ar.bsp // save interrupted context bsp + mov SCRATCH_REG3=ar.bspstore // save interrupted context bspstore + mov SCRATCH_REG4=ar.rnat // save interrupted context rnat + mov SCRATCH_REG6=cr.ifs;; // save IFS in case we need to chain... + cover;; // creates new frame, moves old + // CFM to IFS. + alloc SCRATCH_REG5=0,5,6,0 // alloc 5 locals, 6 outs + ;; + // save banked registers to locals + mov out1=B0_REG // out1 = Original B0 + mov out2=SCRATCH_REG2 // out2 = original ar.bsp + mov out3=SCRATCH_REG3 // out3 = original ar.bspstore + mov out4=SCRATCH_REG4 // out4 = original ar.rnat + mov out5=SCRATCH_REG5 // out5 = original ar.pfs + mov loc2=SCRATCH_REG1;; // loc2 = vector number + chain flag + bsw.1;; // switch banked registers to bank 1 + srlz.d // explicit serialize required + // now fill in context record structure + movl loc3=IpfContextBuf // Insure context record is aligned + add loc0=-0x200,r0;; // mask the lower 9 bits (align on 512 byte boundary) + and loc3=loc3,loc0;; + add loc3=0x200,loc3;; // move to next 512 byte boundary + // loc3 now contains the 512 byte aligned context record + // spill register context into context record + mov out0=loc3;; // Context record base in out0 + // original B0 in out1 already + // original ar.bsp in out2 already + // original ar.bspstore in out3 already + br.call.sptk.few b0=SpillContext;; // spill context + mov loc4=out0 // save modified address + + // At this point, the context has been saved to the context record and we're + // ready to call the C part of the handler... + + movl loc0=CommonHandler;; // obtain address of plabel + ld8 loc1=[loc0];; // get entry point of CommonHandler + mov b6=loc1;; // put it in a branch register + adds loc1= 8, loc0;; // index to GP in plabel + ld8 r1=[loc1];; // set up gp for C call + mov loc1=0xfffff;; // mask off so only vector bits are present + and out0=loc2,loc1;; // pass vector number (exception type) + mov out1=loc3;; // pass context record address + br.call.sptk.few b0=b6;; // call C handler + + // We've returned from the C call, so restore the context and either rfi + // back to interrupted thread, or chain into the SAL if this was an external interrupt + mov out0=loc4;; // pass address of last element in context record + br.call.sptk.few b0=FillContext;; // Fill context + mov b0=out1 // fill in b0 + mov ar.rnat=out4 + mov ar.pfs=out5 + + // Loadrs is necessary because the debugger may have changed some values in + // the backing store. The processor, however may not be aware that the + // stacked registers need to be reloaded from the backing store. Therefore, + // we explicitly cause the RSE to refresh the stacked register's contents + // from the backing store. + mov loc0=ar.rsc // get RSC value + mov loc1=ar.rsc // save it so we can restore it + movl loc3=0xffffffffc000ffff;; // create mask for clearing RSC.loadrs + and loc0=loc0,loc3;; // create value for RSC with RSC.loadrs==0 + mov ar.rsc=loc0;; // modify RSC + loadrs;; // invalidate register stack + mov ar.rsc=loc1;; // restore original RSC + + bsw.0;; // switch banked registers back to bank 0 + srlz.d;; // explicit serialize required + mov PR_REG=pr // save predicates - to be restored after chaining decision + mov B0_REG=b0 // save b0 - required by chain code + mov loc2=EXCPT_EXTERNAL_INTERRUPT;; + cmp.eq p7,p0=SCRATCH_REG1,loc2;; // check to see if this is the timer tick + (p7) br.cond.dpnt.few DO_CHAIN;; + +NO_CHAIN: + mov pr=PR_REG;; + rfi;; // we're outa here. + +DO_CHAIN: + mov pr=PR_REG + mov SCRATCH_REG1=cr.iva + mov SCRATCH_REG2=PATCH_RETURN_OFFSET;; + add SCRATCH_REG1=SCRATCH_REG1, SCRATCH_REG2;; + mov b0=SCRATCH_REG1;; + br.cond.sptk.few b0;; + +EndHookHandler: + + +///////////////////////////////////////////// +// +// Name: +// HookStub +// +// Description: +// HookStub will be copied from it's loaded location into the IVT when +// an IVT entry is hooked. The IVT entry does an indirect jump via B0 to +// HookHandler, which in turn calls into the default C handler, which calls +// the user-installed C handler. The calls return and HookHandler executes +// an rfi. +// +// Notes: +// Saves B0 to B0_REG +// Saves IVT index to SCRATCH_REG1 (immediate value is fixed up when code is copied +// to the IVT entry. + + .global HookStub + .proc HookStub +HookStub: + + mov B0_REG=b0 + movl SCRATCH_REG1=HookHandler;; + mov b0=SCRATCH_REG1;; + mov SCRATCH_REG1=0;;// immediate value is fixed up during install of handler to be the vector number + br.cond.sptk.few b0 + + .endp HookStub + + +///////////////////////////////////////////// +// The following code is moved into IVT entry 14 (offset 3400) which is reserved +// in the Itanium architecture. The patch code is located at the end of the +// IVT entry. + +PatchCode: + mov SCRATCH_REG0=psr + mov SCRATCH_REG6=cr.ipsr + mov PR_REG=pr + mov B0_REG=b0;; + + // turn off any virtual translations + movl SCRATCH_REG1 = ~( MASK(PSR_DT,1) | MASK(PSR_RT,1));; + and SCRATCH_REG1 = SCRATCH_REG0, SCRATCH_REG1;; + mov psr.l = SCRATCH_REG1;; + srlz.d + tbit.z p14, p15 = SCRATCH_REG6, PSR_IS;; // Check to see if we were + // interrupted from IA32 + // context. If so, bail out + // and chain to SAL immediately + (p15) br.cond.sptk.few Stub_IVT_Passthru;; + // we only want to take 1 out of 32 external interrupts to minimize the + // impact to system performance. Check our interrupt count and bail + // out if we're not up to 32 + movl SCRATCH_REG1=ExternalInterruptCount;; + ld8 SCRATCH_REG2=[SCRATCH_REG1];; // ExternalInterruptCount + tbit.z p14, p15 = SCRATCH_REG2, 5;; // bit 5 set? + (p14) add SCRATCH_REG2=1, SCRATCH_REG2;; // No? Then increment + // ExternalInterruptCount + // and Chain to SAL + // immediately + (p14) st8 [SCRATCH_REG1]=SCRATCH_REG2;; + (p14) br.cond.sptk.few Stub_IVT_Passthru;; + (p15) mov SCRATCH_REG2=0;; // Yes? Then reset + // ExternalInterruptCount + // and branch to + // HookHandler + (p15) st8 [SCRATCH_REG1]=SCRATCH_REG2;; + mov pr=PR_REG + movl SCRATCH_REG1=HookHandler;; // SCRATCH_REG1 = entrypoint of HookHandler + mov b0=SCRATCH_REG1;; // b0 = entrypoint of HookHandler + mov SCRATCH_REG1=EXCPT_EXTERNAL_INTERRUPT;; + br.sptk.few b0;; // branch to HookHandler + +PatchCodeRet: + // fake-up an rfi to get RSE back to being coherent and insure psr has + // original contents when interrupt occured, then exit to SAL + // at this point: + // cr.ifs has been modified by previous "cover" + // SCRATCH_REG6 has original cr.ifs + + mov SCRATCH_REG5=cr.ipsr + mov SCRATCH_REG4=cr.iip;; + mov cr.ipsr=SCRATCH_REG0 + mov SCRATCH_REG1=ip;; + add SCRATCH_REG1=0x30, SCRATCH_REG1;; + mov cr.iip=SCRATCH_REG1;; + rfi;; // rfi to next instruction + +Stub_RfiTarget: + mov cr.ifs=SCRATCH_REG6 + mov cr.ipsr=SCRATCH_REG5 + mov cr.iip=SCRATCH_REG4;; + +Stub_IVT_Passthru: + mov pr=PR_REG // pr = saved predicate registers + mov b0=B0_REG;; // b0 = saved b0 +EndPatchCode: + + +///////////////////////////////////////////// +// The following bundle is moved into IVT entry 14 (offset 0x3400) which is reserved +// in the Itanium architecture. This bundle will be the last bundle and will +// be located at offset 0x37F0 in the IVT. + +FailsafeBranch: +{ + .mib + nop.m 0 + nop.i 0 + br.sptk.few -(FAILSAFE_BRANCH_OFFSET - EXT_INT_ENTRY_OFFSET - 0x10) +} + + +///////////////////////////////////////////// +// The following bundle is moved into IVT entry 13 (offset 0x3000) which is the +// external interrupt. It branches to the patch code. + +PatchCodeNewBun0: +{ + .mib + nop.m 0 + nop.i 0 + br.cond.sptk.few PATCH_BRANCH +} diff --git a/EdkModulePkg/Universal/DebugSupport/Dxe/ipf/Ds64Macros.i b/EdkModulePkg/Universal/DebugSupport/Dxe/ipf/Ds64Macros.i new file mode 100644 index 0000000000..6088ce70fd --- /dev/null +++ b/EdkModulePkg/Universal/DebugSupport/Dxe/ipf/Ds64Macros.i @@ -0,0 +1,85 @@ +//++ +// Copyright (c) 2006, Intel Corporation +// All rights reserved. This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// Module Name: +// +// Ds64Macros.i +// +// Abstract: +// +// This is set of macros used in calculating offsets in the IVT +// +// Revision History: +// +//-- + +#define EXCPT_EXTERNAL_INTERRUPT 12 +#define MASK_0_4 0x000000000000001F // mask bits 0 through 4 +#define SLOT0 0 +#define SLOT1 1 +#define SLOT2 2 + +#define PSR_DT 17 +#define PSR_TB 26 +#define PSR_RT 27 +#define PSR_IS 34 +#define PSR_IT 36 +#define PSR_IC 13 +#define PSR_I 14 +#define PSR_SS 40 +#define PSR_BN 44 +#define PSR_RI_MASK 0x60000000000 + +#define EXCPT_EXTERNAL_INTERRUPT 12 + +#define SCRATCH_REG0 r23 +#define SCRATCH_REG1 r24 +#define SCRATCH_REG2 r25 +#define SCRATCH_REG3 r26 +#define SCRATCH_REG4 r27 +#define SCRATCH_REG5 r28 +#define SCRATCH_REG6 r29 +#define PR_REG r30 +#define B0_REG r31 + + +// EXT_INT_OFFSET is the offset of the external interrupt entry in the IVT +#define EXT_INT_ENTRY_OFFSET 0x03000 + +// PATCH_ENTRY_OFFSET is the offset into the IVT of the entry that is coopted (stolen) +// for use by the handler. The entire entry is restored when the handler is +// unloaded. +#define PATCH_ENTRY_OFFSET 0x03400 + +// PATCH_BUNDLES is the number of bundles actually in the patch +#define NUM_PATCH_BUNDLES ((EndPatchCode - PatchCode) / 0x10) + +// A hard coded branch back into the external interrupt IVT entry's second bundle +// is put here, just in case the original bundle zero did not have a branch +// This is the last bundle in the reserved IVT entry +#define FAILSAFE_BRANCH_OFFSET (PATCH_ENTRY_OFFSET + 0x400 - 0x10) + +// the original external interrupt IVT entry bundle zero is copied and relocated +// here... also in the reserved IVT entry +// This is the second-to-last bundle in the reserved IVT entry +#define RELOCATED_EXT_INT (PATCH_ENTRY_OFFSET + 0x400 - 0x20) + +// The patch is actually stored at the end of IVT:PATCH_ENTRY. The PATCH_OFFSET +// is the offset into IVT where the patch is actually stored. It is carefully +// located so that when we run out of patch code, the next bundle is the +// relocated bundle 0 from the original external interrupt handler +#define PATCH_OFFSET (PATCH_ENTRY_OFFSET + 0x400 - ( EndPatchCode - PatchCode ) - 0x20) + +#define PATCH_RETURN_OFFSET (PATCH_ENTRY_OFFSET + 0x400 - ( EndPatchCode - PatchCodeRet ) - 0x20) + +// PATCH_BRANCH is used only in the new bundle that is placed at the beginning +// of the external interrupt IVT entry. +#define PATCH_BRANCH (PATCH_OFFSET - EXT_INT_ENTRY_OFFSET) + diff --git a/EdkModulePkg/Universal/DebugSupport/Dxe/ipf/common.i b/EdkModulePkg/Universal/DebugSupport/Dxe/ipf/common.i new file mode 100644 index 0000000000..a7b571b308 --- /dev/null +++ b/EdkModulePkg/Universal/DebugSupport/Dxe/ipf/common.i @@ -0,0 +1,34 @@ +//++ +// Copyright (c) 2006, Intel Corporation +// All rights reserved. This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// Module Name: +// +// Common.i +// +// Abstract: +// +// This is set of useful macros +// +// Revision History: +// +//-- + +#define NESTED_SETUP(i,l,o,r) \ + alloc loc1=ar##.##pfs,i,l,o,r ; \ + mov loc0=b0 ;; + + +#define NESTED_RETURN \ + mov b0=loc0 ; \ + mov ar##.##pfs=loc1 ;; \ + br##.##ret##.##dpnt b0 ;; + +#define MASK(bp,value) (value << bp) + diff --git a/EdkModulePkg/Universal/DebugSupport/Dxe/ipf/plDebugSupport.c b/EdkModulePkg/Universal/DebugSupport/Dxe/ipf/plDebugSupport.c new file mode 100644 index 0000000000..6f2ded213e --- /dev/null +++ b/EdkModulePkg/Universal/DebugSupport/Dxe/ipf/plDebugSupport.c @@ -0,0 +1,625 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PlDebugSupport.c + +Abstract: + + IPF specific debug support functions + +Revision History + +--*/ + +// +// Master EFI header file +// +#include "Tiano.h" + +// +// Common library header files +// +#include "EfiDriverLib.h" + +// +// Produced protocols +// +#include EFI_PROTOCOL_DEFINITION (DebugSupport) + +// +// private header files +// +#include "plDebugSupport.h" + +typedef struct { + UINT64 low; + UINT64 high; +} BUNDLE; + +// +// number of bundles to swap in ivt +// +#define NUM_BUNDLES_IN_STUB 5 +#define NUM_IVT_ENTRIES 64 + +typedef struct { + BUNDLE OrigBundles[NUM_BUNDLES_IN_STUB]; + VOID (*RegisteredCallback) (); +} IVT_ENTRY; + +STATIC +EFI_STATUS +ManageIvtEntryTable ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN BUNDLE NewBundles[4], + IN VOID (*NewCallback) () + ); + +STATIC +VOID +HookEntry ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN BUNDLE NewBundles[4], + IN VOID (*NewCallback) () + ); + +STATIC +VOID +UnhookEntry ( + IN EFI_EXCEPTION_TYPE ExceptionType + ); + +STATIC +VOID +ChainExternalInterrupt ( + IN VOID (*NewCallback) () + ); + +STATIC +VOID +UnchainExternalInterrupt ( + VOID + ); + +STATIC +VOID +GetHandlerEntryPoint ( + UINTN HandlerIndex, + VOID **EntryPoint + ); + +IVT_ENTRY IvtEntryTable[NUM_IVT_ENTRIES]; + +// +// IPF context record is overallocated by 512 bytes to guarantee a 512 byte alignment exists +// within the buffer and still have a large enough buffer to hold a whole IPF context record. +// +UINT8 IpfContextBuf[sizeof (EFI_SYSTEM_CONTEXT_IPF) + 512]; + +// +// The PatchSaveBuffer is used to store the original bundles from the IVT where it is patched +// with the common handler. +// +UINT8 PatchSaveBuffer[0x400]; +UINTN ExternalInterruptCount; + +EFI_STATUS +plInitializeDebugSupportDriver ( + VOID + ) +/*++ + +Routine Description: + IPF specific DebugSupport driver initialization. Must be public because it's + referenced from DebugSupport.c + +Arguments: + +Returns: + + EFI_SUCCESS + +--*/ +{ + gBS->SetMem (IvtEntryTable, sizeof (IvtEntryTable), 0); + ExternalInterruptCount = 0; + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +plUnloadDebugSupportDriver ( + IN EFI_HANDLE ImageHandle + ) +/*++ + +Routine Description: + Unload handler that is called during UnloadImage() - deallocates pool memory + used by the driver. Must be public because it's referenced from DebugSuport.c + +Arguments: + IN EFI_HANDLE ImageHandle + +Returns: + + EFI_STATUS - anything other than EFI_SUCCESS indicates the callback was not registered. + +--*/ +// TODO: ImageHandle - add argument and description to function comment +{ + EFI_EXCEPTION_TYPE ExceptionType; + + for (ExceptionType = 0; ExceptionType < NUM_IVT_ENTRIES; ExceptionType++) { + ManageIvtEntryTable (ExceptionType, NULL, NULL); + } + + return EFI_SUCCESS; +} + +VOID +CommonHandler ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN EFI_SYSTEM_CONTEXT Context + ) +/*++ + +Routine Description: + C routine that is called for all registered exceptions. This is the main + exception dispatcher. Must be public because it's referenced from AsmFuncs.s. + +Arguments: + IN EFI_EXCEPTION_TYPE ExceptionType, + IN EFI_SYSTEM_CONTEXT Context + +Returns: + + Nothing + +--*/ +// TODO: ExceptionType - add argument and description to function comment +// TODO: Context - add argument and description to function comment +{ + static BOOLEAN InHandler = FALSE; + + DEBUG_CODE ( + if (InHandler) { + EfiDebugPrint (EFI_D_GENERIC, "ERROR: Re-entered debugger!\n" + " ExceptionType == %X\n" + " Context == %X\n" + " Context.SystemContextIpf->CrIip == %X\n" + " Context.SystemContextIpf->CrIpsr == %X\n" + " InHandler == %X\n", + ExceptionType, + Context, + Context.SystemContextIpf->CrIip, + Context.SystemContextIpf->CrIpsr, + InHandler); + } + ) + ASSERT (!InHandler); + InHandler = TRUE; + if (IvtEntryTable[ExceptionType].RegisteredCallback != NULL) { + if (ExceptionType != EXCEPT_IPF_EXTERNAL_INTERRUPT) { + IvtEntryTable[ExceptionType].RegisteredCallback (ExceptionType, Context.SystemContextIpf); + } else { + IvtEntryTable[ExceptionType].RegisteredCallback (Context.SystemContextIpf); + } + } else { + ASSERT (0); + } + + InHandler = FALSE; +} + +STATIC +VOID +GetHandlerEntryPoint ( + UINTN HandlerIndex, + VOID **EntryPoint + ) +/*++ + +Routine Description: + Given an integer number, return the physical address of the entry point in the IFT + +Arguments: + UINTN HandlerIndex, + VOID ** EntryPoint + +Returns: + + Nothing + +--*/ +// TODO: HandlerIndex - add argument and description to function comment +// TODO: EntryPoint - add argument and description to function comment +{ + UINT8 *TempPtr; + + // + // get base address of IVT + // + TempPtr = GetIva (); + + if (HandlerIndex < 20) { + // + // first 20 provide 64 bundles per vector + // + TempPtr += 0x400 * HandlerIndex; + } else { + // + // the rest provide 16 bundles per vector + // + TempPtr += 0x5000 + 0x100 * (HandlerIndex - 20); + } + + *EntryPoint = (VOID *) TempPtr; +} + +STATIC +EFI_STATUS +ManageIvtEntryTable ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN BUNDLE NewBundles[NUM_BUNDLES_IN_STUB], + IN VOID (*NewCallback) () + ) +/*++ + +Routine Description: + This is the worker function that installs and removes all handlers + +Arguments: + IN EFI_EXCEPTION_TYPE ExceptionType, + IN BUNDLE NewBundles[NUM_BUNDLES_IN_STUB], + IN VOID (*NewCallback) () + +Returns: + + EFI_STATUS - any return other than EFI_SUCCESS indicates the request was not + satisfied. + +--*/ +// TODO: ExceptionType - add argument and description to function comment +// TODO: ] - add argument and description to function comment +// TODO: ) - add argument and description to function comment +// TODO: EFI_ALREADY_STARTED - add return value to function comment +{ + BUNDLE *B0Ptr; + UINT64 InterruptFlags; + EFI_TPL OldTpl; + + // + // Get address of bundle 0 + // + GetHandlerEntryPoint (ExceptionType, (VOID **) &B0Ptr); + + if (IvtEntryTable[ExceptionType].RegisteredCallback != NULL) { + // + // we've already installed to this vector + // + if (NewCallback != NULL) { + // + // if the input handler is non-null, error + // + return EFI_ALREADY_STARTED; + } else { + // + // else remove the previously installed handler + // + OldTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL); + InterruptFlags = ProgramInterruptFlags (DISABLE_INTERRUPTS); + if (ExceptionType == EXCEPT_IPF_EXTERNAL_INTERRUPT) { + UnchainExternalInterrupt (); + } else { + UnhookEntry (ExceptionType); + } + + ProgramInterruptFlags (InterruptFlags); + gBS->RestoreTPL (OldTpl); + // + // re-init IvtEntryTable + // + gBS->SetMem (&IvtEntryTable[ExceptionType], sizeof (IVT_ENTRY), 0); + } + } else { + // + // no user handler installed on this vector + // + if (NewCallback != NULL) { + OldTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL); + InterruptFlags = ProgramInterruptFlags (DISABLE_INTERRUPTS); + if (ExceptionType == EXCEPT_IPF_EXTERNAL_INTERRUPT) { + ChainExternalInterrupt (NewCallback); + } else { + HookEntry (ExceptionType, NewBundles, NewCallback); + } + + ProgramInterruptFlags (InterruptFlags); + gBS->RestoreTPL (OldTpl); + } + } + + return EFI_SUCCESS; +} + +STATIC +VOID +HookEntry ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN BUNDLE NewBundles[4], + IN VOID (*NewCallback) () + ) +/*++ + +Routine Description: + Saves original IVT contents and inserts a few new bundles which are fixed up + to store the ExceptionType and then call the common handler. + +Arguments: + IN EFI_EXCEPTION_TYPE ExceptionType, + IN BUNDLE NewBundles[4], + IN VOID (*NewCallback) () + +Returns: + + Nothing + +--*/ +// TODO: ExceptionType - add argument and description to function comment +// TODO: ] - add argument and description to function comment +// TODO: ) - add argument and description to function comment +{ + BUNDLE *FixupBundle; + BUNDLE *B0Ptr; + + // + // Get address of bundle 0 + // + GetHandlerEntryPoint (ExceptionType, (VOID **) &B0Ptr); + + // + // copy original bundles from IVT to IvtEntryTable so we can restore them later + // + gBS->CopyMem ( + IvtEntryTable[ExceptionType].OrigBundles, + B0Ptr, + sizeof (BUNDLE) * NUM_BUNDLES_IN_STUB + ); + // + // insert new B0 + // + gBS->CopyMem (B0Ptr, NewBundles, sizeof (BUNDLE) * NUM_BUNDLES_IN_STUB); + + // + // fixup IVT entry so it stores its index and whether or not to chain... + // + FixupBundle = B0Ptr + 2; + FixupBundle->high |= ExceptionType << 36; + + InstructionCacheFlush (B0Ptr, 5); + IvtEntryTable[ExceptionType].RegisteredCallback = NewCallback; +} + +STATIC +VOID +UnhookEntry ( + IN EFI_EXCEPTION_TYPE ExceptionType + ) +/*++ + +Routine Description: + Restores original IVT contents when unregistering a callback function + +Arguments: + IN EFI_EXCEPTION_TYPE ExceptionType, + +Returns: + + Nothing + +--*/ +// TODO: ExceptionType - add argument and description to function comment +{ + BUNDLE *B0Ptr; + + // + // Get address of bundle 0 + // + GetHandlerEntryPoint (ExceptionType, (VOID **) &B0Ptr); + // + // restore original bundles in IVT + // + gBS->CopyMem ( + B0Ptr, + IvtEntryTable[ExceptionType].OrigBundles, + sizeof (BUNDLE) * NUM_BUNDLES_IN_STUB + ); + InstructionCacheFlush (B0Ptr, 5); +} + +STATIC +VOID +ChainExternalInterrupt ( + IN VOID (*NewCallback) () + ) +/*++ + +Routine Description: + Sets up cache flush and calls assembly function to chain external interrupt. + Records new callback in IvtEntryTable. + +Arguments: + IN VOID (*NewCallback) () + +Returns: + + Nothing + +--*/ +// TODO: ) - add argument and description to function comment +{ + VOID *Start; + + Start = (VOID *) ((UINT8 *) GetIva () + 0x400 * EXCEPT_IPF_EXTERNAL_INTERRUPT + 0x400); + IvtEntryTable[EXCEPT_IPF_EXTERNAL_INTERRUPT].RegisteredCallback = NewCallback; + ChainHandler (); + InstructionCacheFlush (Start, 0x400); +} + +STATIC +VOID +UnchainExternalInterrupt ( + VOID + ) +/*++ + +Routine Description: + Sets up cache flush and calls assembly function to restore external interrupt. + Removes registered callback from IvtEntryTable. + +Arguments: + Nothing + +Returns: + + Nothing + +--*/ +{ + VOID *Start; + + Start = (VOID *) ((UINT8 *) GetIva () + 0x400 * EXCEPT_IPF_EXTERNAL_INTERRUPT + 0x400); + UnchainHandler (); + InstructionCacheFlush (Start, 0x400); + IvtEntryTable[EXCEPT_IPF_EXTERNAL_INTERRUPT].RegisteredCallback = NULL; +} + +// +// The rest of the functions in this file are all member functions for the +// DebugSupport protocol +// + +EFI_STATUS +EFIAPI +GetMaximumProcessorIndex ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + OUT UINTN *MaxProcessorIndex + ) +/*++ + +Routine Description: This is a DebugSupport protocol member function. Hard + coded to support only 1 processor for now. + +Arguments: + +Returns: Always returns EFI_SUCCESS with *MaxProcessorIndex set to 0 + +--*/ +// TODO: This - add argument and description to function comment +// TODO: MaxProcessorIndex - add argument and description to function comment +{ + *MaxProcessorIndex = 0; + return (EFI_SUCCESS); +} + +EFI_STATUS +EFIAPI +RegisterPeriodicCallback ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + IN UINTN ProcessorIndex, + IN EFI_PERIODIC_CALLBACK NewPeriodicCallback + ) +/*++ + +Routine Description: + DebugSupport protocol member function + +Arguments: + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + IN UINTN ProcessorIndex, + IN EFI_PERIODIC_CALLBACK NewPeriodicCallback + +Returns: + + EFI_STATUS - anything other than EFI_SUCCESS indicates the callback was not registered. + +--*/ +// TODO: This - add argument and description to function comment +// TODO: ProcessorIndex - add argument and description to function comment +// TODO: NewPeriodicCallback - add argument and description to function comment +{ + return ManageIvtEntryTable (EXCEPT_IPF_EXTERNAL_INTERRUPT, NULL, NewPeriodicCallback); +} + +EFI_STATUS +EFIAPI +RegisterExceptionCallback ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + IN UINTN ProcessorIndex, + IN EFI_EXCEPTION_CALLBACK NewCallback, + IN EFI_EXCEPTION_TYPE ExceptionType + ) +/*++ + +Routine Description: + DebugSupport protocol member function + +Arguments: + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + IN EFI_EXCEPTION_CALLBACK NewCallback, + IN EFI_EXCEPTION_TYPE ExceptionType + +Returns: + + EFI_STATUS - anything other than EFI_SUCCESS indicates the callback was not registered. + +--*/ +// TODO: This - add argument and description to function comment +// TODO: ProcessorIndex - add argument and description to function comment +// TODO: NewCallback - add argument and description to function comment +// TODO: ExceptionType - add argument and description to function comment +{ + return ManageIvtEntryTable ( + ExceptionType, + (BUNDLE *) ((EFI_PLABEL *) HookStub)->EntryPoint, + NewCallback + ); +} + +EFI_STATUS +EFIAPI +InvalidateInstructionCache ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + IN UINTN ProcessorIndex, + IN VOID *Start, + IN UINTN Length + ) +/*++ + +Routine Description: + DebugSupport protocol member function. Calls assembly routine to flush cache. + +Arguments: + +Returns: + EFI_SUCCESS + +--*/ +// TODO: This - add argument and description to function comment +// TODO: ProcessorIndex - add argument and description to function comment +// TODO: Start - add argument and description to function comment +// TODO: Length - add argument and description to function comment +{ + InstructionCacheFlush (Start, Length); + return (EFI_SUCCESS); +} diff --git a/EdkModulePkg/Universal/Debugger/Debugport/Dxe/ComponentName.c b/EdkModulePkg/Universal/Debugger/Debugport/Dxe/ComponentName.c new file mode 100644 index 0000000000..078bdab54d --- /dev/null +++ b/EdkModulePkg/Universal/Debugger/Debugport/Dxe/ComponentName.c @@ -0,0 +1,108 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + ComponentName.c + +Abstract: + Component name protocol member functions for DebugPort... + +--*/ + +#include "DebugPort.h" + +// +// EFI Component Name Protocol +// +EFI_COMPONENT_NAME_PROTOCOL gDebugPortComponentName = { + DebugPortComponentNameGetDriverName, + DebugPortComponentNameGetControllerName, + "eng" +}; + +static EFI_UNICODE_STRING_TABLE mDebugPortDriverNameTable[] = { + { + "eng", + (CHAR16 *) L"DebugPort Driver" + }, + { + NULL, + NULL + } +}; + +EFI_STATUS +EFIAPI +DebugPortComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gDebugPortComponentName.SupportedLanguages, + mDebugPortDriverNameTable, + DriverName + ); +} + +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 + ) +/*++ + + Routine Description: + The debug port driver does not support GetControllerName, so this function + is just stubbed and returns EFI_UNSUPPORTED. + + Arguments: + Per EFI 1.10 driver model + + Returns: + EFI_UNSUPPORTED + +--*/ +{ + return EFI_UNSUPPORTED; +} diff --git a/EdkModulePkg/Universal/Debugger/Debugport/Dxe/DebugPort.c b/EdkModulePkg/Universal/Debugger/Debugport/Dxe/DebugPort.c new file mode 100644 index 0000000000..a24bfd06d5 --- /dev/null +++ b/EdkModulePkg/Universal/Debugger/Debugport/Dxe/DebugPort.c @@ -0,0 +1,833 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DebugPort.c + +Abstract: + + 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. + +Revision History + +--*/ + + +#include "DebugPort.h" + +// +// Misc. functions local to this module +// +STATIC +VOID +GetDebugPortVariable ( + DEBUGPORT_DEVICE *DebugPortDevice + ); + +EFI_STATUS +EFIAPI +ImageUnloadHandler ( + EFI_HANDLE ImageHandle + ); + +// +// Globals +// + +EFI_DRIVER_BINDING_PROTOCOL gDebugPortDriverBinding = { + DebugPortSupported, + DebugPortStart, + DebugPortStop, + DEBUGPORT_DRIVER_VERSION, + NULL, + NULL +}; + +DEBUGPORT_DEVICE *gDebugPortDevice; +static UINT32 mHid16550; +static UINT32 mHidStdPcComPort; + +// +// implementation code +// + +EFI_STATUS +EFIAPI +InitializeDebugPortDriver ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + 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. + + Creates debugport and devicepath protocols on new handle. + +Arguments: + ImageHandle, + SystemTable + +Returns: + + EFI_UNSUPPORTED + EFI_OUT_OF_RESOURCES + +--*/ +{ + mHid16550 = EFI_ACPI_16550UART_HID; + mHidStdPcComPort = EFI_ACPI_PC_COMPORT_HID; + + // + // Allocate and Initialize dev structure + // + gDebugPortDevice = AllocateZeroPool (sizeof (DEBUGPORT_DEVICE)); + if (gDebugPortDevice == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Fill in static and default pieces of device structure first. + // + gDebugPortDevice->Signature = DEBUGPORT_DEVICE_SIGNATURE; + + gDebugPortDevice->DebugPortInterface.Reset = DebugPortReset; + gDebugPortDevice->DebugPortInterface.Read = DebugPortRead; + gDebugPortDevice->DebugPortInterface.Write = DebugPortWrite; + gDebugPortDevice->DebugPortInterface.Poll = DebugPortPoll; + + gDebugPortDevice->BaudRate = DEBUGPORT_UART_DEFAULT_BAUDRATE; + gDebugPortDevice->ReceiveFifoDepth = DEBUGPORT_UART_DEFAULT_FIFO_DEPTH; + gDebugPortDevice->Timeout = DEBUGPORT_UART_DEFAULT_TIMEOUT; + gDebugPortDevice->Parity = DEBUGPORT_UART_DEFAULT_PARITY; + gDebugPortDevice->DataBits = DEBUGPORT_UART_DEFAULT_DATA_BITS; + gDebugPortDevice->StopBits = DEBUGPORT_UART_DEFAULT_STOP_BITS; + + return EFI_SUCCESS; +} +// +// DebugPort driver binding member functions... +// +EFI_STATUS +EFIAPI +DebugPortSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + Checks to see that there's not already a DebugPort interface somewhere. If so, + fail. + + 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. + +Arguments: + This + ControllerHandle + RemainingDevicePath + +Returns: + EFI_UNSUPPORTED + EFI_OUT_OF_RESOURCES + EFI_SUCCESS + +--*/ +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *Dp1; + EFI_DEVICE_PATH_PROTOCOL *Dp2; + EFI_SERIAL_IO_PROTOCOL *SerialIo; + EFI_DEBUGPORT_PROTOCOL *DebugPortInterface; + EFI_HANDLE TempHandle; + + // + // Check to see that there's not a debugport protocol already published + // + if (gBS->LocateProtocol (&gEfiDebugPortProtocolGuid, NULL, (VOID **) &DebugPortInterface) != EFI_NOT_FOUND) { + return EFI_UNSUPPORTED; + } + // + // Read DebugPort variable to determine debug port selection and parameters + // + GetDebugPortVariable (gDebugPortDevice); + + if (gDebugPortDevice->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. + // + Dp1 = DuplicateDevicePath ((EFI_DEVICE_PATH_PROTOCOL *) gDebugPortDevice->DebugPortVariable); + if (Dp1 == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Dp2 = Dp1; + + Status = gBS->LocateDevicePath ( + &gEfiSerialIoProtocolGuid, + &Dp2, + &TempHandle + ); + + if (Status == EFI_SUCCESS && TempHandle != ControllerHandle) { + Status = EFI_UNSUPPORTED; + } + + if (Status == EFI_SUCCESS && (Dp2->Type != 3 || Dp2->SubType != 10 || *((UINT16 *) Dp2->Length) != 20)) { + Status = EFI_UNSUPPORTED; + } + + if (Status == EFI_SUCCESS && CompareMem (&gEfiDebugPortDevicePathGuid, Dp2 + 1, sizeof (EFI_GUID))) { + Status = EFI_UNSUPPORTED; + } + + gBS->FreePool (Dp1); + 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; + } + + gBS->CloseProtocol ( + ControllerHandle, + &gEfiSerialIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +DebugPortStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + Binds exclusively to serial io on the controller handle. Produces DebugPort + protocol and DevicePath on new handle. + +Arguments: + This + ControllerHandle + RemainingDevicePath + +Returns: + EFI_OUT_OF_RESOURCES + EFI_SUCCESS +--*/ +{ + EFI_STATUS Status; + DEBUGPORT_DEVICE_PATH DebugPortDP; + EFI_DEVICE_PATH_PROTOCOL EndDP; + EFI_DEVICE_PATH_PROTOCOL *Dp1; + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiSerialIoProtocolGuid, + (VOID **) &gDebugPortDevice->SerialIoBinding, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE + ); + if (EFI_ERROR (Status)) { + return Status; + } + + gDebugPortDevice->SerialIoDeviceHandle = ControllerHandle; + + // + // Initialize the Serial Io interface... + // + Status = gDebugPortDevice->SerialIoBinding->SetAttributes ( + gDebugPortDevice->SerialIoBinding, + gDebugPortDevice->BaudRate, + gDebugPortDevice->ReceiveFifoDepth, + gDebugPortDevice->Timeout, + gDebugPortDevice->Parity, + gDebugPortDevice->DataBits, + gDebugPortDevice->StopBits + ); + if (EFI_ERROR (Status)) { + gDebugPortDevice->BaudRate = 0; + gDebugPortDevice->Parity = DefaultParity; + gDebugPortDevice->DataBits = 0; + gDebugPortDevice->StopBits = DefaultStopBits; + gDebugPortDevice->ReceiveFifoDepth = 0; + Status = gDebugPortDevice->SerialIoBinding->SetAttributes ( + gDebugPortDevice->SerialIoBinding, + gDebugPortDevice->BaudRate, + gDebugPortDevice->ReceiveFifoDepth, + gDebugPortDevice->Timeout, + gDebugPortDevice->Parity, + gDebugPortDevice->DataBits, + gDebugPortDevice->StopBits + ); + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiSerialIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + return Status; + } + } + + gDebugPortDevice->SerialIoBinding->Reset (gDebugPortDevice->SerialIoBinding); + + // + // Create device path instance for DebugPort + // + DebugPortDP.Header.Type = MESSAGING_DEVICE_PATH; + DebugPortDP.Header.SubType = MSG_VENDOR_DP; + SetDevicePathNodeLength (&(DebugPortDP.Header), sizeof (DebugPortDP)); + gBS->CopyMem (&DebugPortDP.Guid, &gEfiDebugPortDevicePathGuid, sizeof (EFI_GUID)); + + Dp1 = DevicePathFromHandle (ControllerHandle); + if (Dp1 == NULL) { + Dp1 = &EndDP; + SetDevicePathEndNode (Dp1); + } + + gDebugPortDevice->DebugPortDevicePath = AppendDevicePathNode (Dp1, (EFI_DEVICE_PATH_PROTOCOL *) &DebugPortDP); + if (gDebugPortDevice->DebugPortDevicePath == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Publish DebugPort and Device Path protocols + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &gDebugPortDevice->DebugPortDeviceHandle, + &gEfiDevicePathProtocolGuid, + gDebugPortDevice->DebugPortDevicePath, + &gEfiDebugPortProtocolGuid, + &gDebugPortDevice->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 **) &gDebugPortDevice->SerialIoBinding, + This->DriverBindingHandle, + gDebugPortDevice->DebugPortDeviceHandle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + + if (EFI_ERROR (Status)) { + DEBUG_CODE ( + UINTN BufferSize; + + BufferSize = 48; + DebugPortWrite ( + &gDebugPortDevice->DebugPortInterface, + 0, + &BufferSize, + "DebugPort driver failed to open child controller\n\n" + ); + ); + + gBS->CloseProtocol ( + ControllerHandle, + &gEfiSerialIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + return Status; + } + + DEBUG_CODE ( + UINTN BufferSize; + + BufferSize = 38; + DebugPortWrite ( + &gDebugPortDevice->DebugPortInterface, + 0, + &BufferSize, + "Hello World from the DebugPort driver\n\n" + ); + ); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +DebugPortStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + +Routine Description: + We're never intending to be stopped via the driver model so this just returns + EFI_UNSUPPORTED + +Arguments: + Per EFI 1.10 driver model + +Returns: + EFI_UNSUPPORTED + EFI_SUCCESS + +--*/ +{ + EFI_STATUS Status; + + if (NumberOfChildren == 0) { + // + // Close the bus driver + // + gBS->CloseProtocol ( + ControllerHandle, + &gEfiSerialIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + + gDebugPortDevice->SerialIoBinding = NULL; + + gBS->CloseProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + + gBS->FreePool (gDebugPortDevice->DebugPortDevicePath); + + return EFI_SUCCESS; + } else { + // + // Disconnect SerialIo child handle + // + Status = gBS->CloseProtocol ( + gDebugPortDevice->SerialIoDeviceHandle, + &gEfiSerialIoProtocolGuid, + This->DriverBindingHandle, + gDebugPortDevice->DebugPortDeviceHandle + ); + + if (EFI_ERROR (Status)) { + return Status; + } + // + // Unpublish our protocols (DevicePath, DebugPort) + // + Status = gBS->UninstallMultipleProtocolInterfaces ( + gDebugPortDevice->DebugPortDeviceHandle, + &gEfiDevicePathProtocolGuid, + gDebugPortDevice->DebugPortDevicePath, + &gEfiDebugPortProtocolGuid, + &gDebugPortDevice->DebugPortInterface, + NULL + ); + + if (EFI_ERROR (Status)) { + gBS->OpenProtocol ( + ControllerHandle, + &gEfiSerialIoProtocolGuid, + (VOID **) &gDebugPortDevice->SerialIoBinding, + This->DriverBindingHandle, + gDebugPortDevice->DebugPortDeviceHandle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + } else { + gDebugPortDevice->DebugPortDeviceHandle = NULL; + } + } + + return Status; +} +// +// Debugport protocol member functions +// +EFI_STATUS +EFIAPI +DebugPortReset ( + IN EFI_DEBUGPORT_PROTOCOL *This + ) +/*++ + +Routine Description: + 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. + +Arguments: + This + +Returns: + + EFI_SUCCESS + +--*/ +{ + DEBUGPORT_DEVICE *DebugPortDevice; + UINTN BufferSize; + UINTN BitBucket; + + DebugPortDevice = DEBUGPORT_DEVICE_FROM_THIS (This); + while (This->Poll (This) == EFI_SUCCESS) { + BufferSize = 1; + This->Read (This, 0, &BufferSize, &BitBucket); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +DebugPortRead ( + IN EFI_DEBUGPORT_PROTOCOL *This, + IN UINT32 Timeout, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +/*++ + +Routine Description: + DebugPort protocol member function. Calls SerialIo:Read() after setting + if it's different than the last SerialIo access. + +Arguments: + IN EFI_DEBUGPORT_PROTOCOL *This + IN UINT32 Timeout, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + +Returns: + + EFI_STATUS + +--*/ +{ + 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 - (UINT8 *) Buffer); + + return Status; +} + +EFI_STATUS +EFIAPI +DebugPortWrite ( + IN EFI_DEBUGPORT_PROTOCOL *This, + IN UINT32 Timeout, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + 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.. + +Arguments: + This - Pointer to DebugPort protocol + Timeout - Timeout value + BufferSize - On input, the size of Buffer. + On output, the amount of data actually written. + Buffer - Pointer to buffer to write + +Returns: + EFI_SUCCESS - The data was written. + EFI_DEVICE_ERROR - The device reported an error. + EFI_TIMEOUT - The data write was stopped due to a timeout. + +--*/ +{ + 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; +} + +EFI_STATUS +EFIAPI +DebugPortPoll ( + IN EFI_DEBUGPORT_PROTOCOL *This + ) +/*++ + +Routine Description: + DebugPort protocol member function. Calls SerialIo:Write() after setting + if it's different than the last SerialIo access. + +Arguments: + IN EFI_DEBUGPORT_PROTOCOL *This + +Returns: + EFI_SUCCESS - At least 1 character is ready to be read from the DebugPort interface + EFI_NOT_READY - There are no characters ready to read from the DebugPort interface + EFI_DEVICE_ERROR - A hardware failure occured... (from SerialIo) + +--*/ +{ + 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) { + Status = EFI_NOT_READY; + } else { + Status = EFI_SUCCESS; + } + } + + return Status; +} +// +// Misc. functions local to this module.. +// +STATIC +VOID +GetDebugPortVariable ( + DEBUGPORT_DEVICE *DebugPortDevice + ) +/*++ + +Routine Description: + Local worker function to obtain device path information from DebugPort variable. + Records requested settings in DebugPort device structure. + +Arguments: + DEBUGPORT_DEVICE *DebugPortDevice, + +Returns: + + Nothing + +--*/ +{ + UINTN DataSize; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_STATUS Status; + + DataSize = 0; + + Status = gRT->GetVariable ( + (CHAR16 *) EFI_DEBUGPORT_VARIABLE_NAME, + &gEfiDebugPortVariableGuid, + NULL, + &DataSize, + DebugPortDevice->DebugPortVariable + ); + + if (Status == EFI_BUFFER_TOO_SMALL) { + if (gDebugPortDevice->DebugPortVariable != NULL) { + gBS->FreePool (gDebugPortDevice->DebugPortVariable); + } + + DebugPortDevice->DebugPortVariable = AllocatePool (DataSize); + if (DebugPortDevice->DebugPortVariable != NULL) { + gRT->GetVariable ( + (CHAR16 *) EFI_DEBUGPORT_VARIABLE_NAME, + &gEfiDebugPortVariableGuid, + NULL, + &DataSize, + DebugPortDevice->DebugPortVariable + ); + DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) DebugPortDevice->DebugPortVariable; + while (!EfiIsDevicePathEnd (DevicePath) && !EfiIsUartDevicePath (DevicePath)) { + DevicePath = EfiNextDevicePathNode (DevicePath); + } + + if (EfiIsDevicePathEnd (DevicePath)) { + gBS->FreePool (gDebugPortDevice->DebugPortVariable); + DebugPortDevice->DebugPortVariable = NULL; + } else { + gBS->CopyMem ( + &DebugPortDevice->BaudRate, + &((UART_DEVICE_PATH *) DevicePath)->BaudRate, + sizeof (((UART_DEVICE_PATH *) DevicePath)->BaudRate) + ); + DebugPortDevice->ReceiveFifoDepth = DEBUGPORT_UART_DEFAULT_FIFO_DEPTH; + DebugPortDevice->Timeout = DEBUGPORT_UART_DEFAULT_TIMEOUT; + gBS->CopyMem ( + &DebugPortDevice->Parity, + &((UART_DEVICE_PATH *) DevicePath)->Parity, + sizeof (((UART_DEVICE_PATH *) DevicePath)->Parity) + ); + gBS->CopyMem ( + &DebugPortDevice->DataBits, + &((UART_DEVICE_PATH *) DevicePath)->DataBits, + sizeof (((UART_DEVICE_PATH *) DevicePath)->DataBits) + ); + gBS->CopyMem ( + &DebugPortDevice->StopBits, + &((UART_DEVICE_PATH *) DevicePath)->StopBits, + sizeof (((UART_DEVICE_PATH *) DevicePath)->StopBits) + ); + } + } + } +} + +EFI_STATUS +EFIAPI +ImageUnloadHandler ( + EFI_HANDLE ImageHandle + ) +/*++ + +Routine Description: + 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. + +Arguments: + EFI_HANDLE ImageHandle + +Returns: + + EFI_SUCCESS + +--*/ +{ + EFI_STATUS Status; + + if (gDebugPortDevice->SerialIoBinding != NULL) { + return EFI_ABORTED; + } + + Status = gBS->UninstallMultipleProtocolInterfaces ( + ImageHandle, + &gEfiDriverBindingProtocolGuid, + &gDebugPortDevice->DriverBindingInterface, + &gEfiComponentNameProtocolGuid, + &gDebugPortDevice->ComponentNameInterface, + NULL + ); + + if (EFI_ERROR (Status)) { + return Status; + } + // + // Clean up allocations + // + if (gDebugPortDevice->DebugPortVariable != NULL) { + gBS->FreePool (gDebugPortDevice->DebugPortVariable); + } + + gBS->FreePool (gDebugPortDevice); + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Universal/Debugger/Debugport/Dxe/DebugPort.dxs b/EdkModulePkg/Universal/Debugger/Debugport/Dxe/DebugPort.dxs new file mode 100644 index 0000000000..280931b5c0 --- /dev/null +++ b/EdkModulePkg/Universal/Debugger/Debugport/Dxe/DebugPort.dxs @@ -0,0 +1,26 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DebugPort.dxs + +Abstract: + + Dependency expression source file. + +--*/ +#include +#include + +DEPENDENCY_START + TRUE +DEPENDENCY_END diff --git a/EdkModulePkg/Universal/Debugger/Debugport/Dxe/DebugPort.h b/EdkModulePkg/Universal/Debugger/Debugport/Dxe/DebugPort.h new file mode 100644 index 0000000000..bb486c3147 --- /dev/null +++ b/EdkModulePkg/Universal/Debugger/Debugport/Dxe/DebugPort.h @@ -0,0 +1,172 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + DebugPort.h + +Abstract: + Definitions and prototypes for DebugPort driver + +--*/ + +#ifndef __DEBUGPORT_H__ +#define __DEBUGPORT_H__ + + +// +// local type definitions +// +#define DEBUGPORT_DEVICE_SIGNATURE EFI_SIGNATURE_32 ('D', 'B', 'G', 'P') + +// +// Device structure used by driver +// +typedef struct { + UINT32 Signature; + EFI_HANDLE DriverBindingHandle; + EFI_HANDLE DebugPortDeviceHandle; + VOID *DebugPortVariable; + + EFI_DRIVER_BINDING_PROTOCOL DriverBindingInterface; + EFI_COMPONENT_NAME_PROTOCOL ComponentNameInterface; + 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 EfiIsUartDevicePath(dp) (DevicePathType (dp) == MESSAGING_DEVICE_PATH && DevicePathSubType (dp) == MSG_UART_DP) + +// +// globals +// +extern DEBUGPORT_DEVICE *gDebugPortDevice; + +// +// Driver binding interface functions... +// +EFI_STATUS +DebugPortEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +; + +EFI_STATUS +EFIAPI +DebugPortSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +; + +EFI_STATUS +EFIAPI +DebugPortStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +; + +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 +// +EFI_STATUS +EFIAPI +DebugPortComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +; + +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 member functions +// +EFI_STATUS +EFIAPI +DebugPortReset ( + IN EFI_DEBUGPORT_PROTOCOL *This + ) +; + +EFI_STATUS +EFIAPI +DebugPortRead ( + IN EFI_DEBUGPORT_PROTOCOL *This, + IN UINT32 Timeout, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +; + +EFI_STATUS +EFIAPI +DebugPortWrite ( + IN EFI_DEBUGPORT_PROTOCOL *This, + IN UINT32 Timeout, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +; + +EFI_STATUS +EFIAPI +DebugPortPoll ( + IN EFI_DEBUGPORT_PROTOCOL *This + ) +; + +#endif diff --git a/EdkModulePkg/Universal/Debugger/Debugport/Dxe/DebugPort.mbd b/EdkModulePkg/Universal/Debugger/Debugport/Dxe/DebugPort.mbd new file mode 100644 index 0000000000..62abeee2d6 --- /dev/null +++ b/EdkModulePkg/Universal/Debugger/Debugport/Dxe/DebugPort.mbd @@ -0,0 +1,46 @@ + + + + + DebugPort + 73E9457A-CEA1-4917-9A9C-9F1F0F0FD322 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + BaseLib + DxeMemoryAllocationLib + UefiDevicePathLib + + + _ModuleEntryPoint + + diff --git a/EdkModulePkg/Universal/Debugger/Debugport/Dxe/DebugPort.msa b/EdkModulePkg/Universal/Debugger/Debugport/Dxe/DebugPort.msa new file mode 100644 index 0000000000..6762026c3f --- /dev/null +++ b/EdkModulePkg/Universal/Debugger/Debugport/Dxe/DebugPort.msa @@ -0,0 +1,77 @@ + + + + + DebugPort + UEFI_DRIVER + BS_DRIVER + 73E9457A-CEA1-4917-9A9C-9F1F0F0FD322 + 0 + Component description file for DiskIo module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + UefiLib + BaseLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + DevicePathLib + + + DebugPort.h + DebugPort.c + ComponentName.c + DebugPort.dxs + + + MdePkg + EdkModulePkg + + + DebugPort + DevicePath + SerialIo + + + + DEBUGPORT + 0xEBA4E8D2, 0x3858, 0x41EC, 0xA2, 0x81, 0x26, 0x47, 0xBA, 0x96, 0x60, 0xD0 + + + + + InitializeDebugPortDriver + ImageUnloadHandler + + + gDebugPortDriverBinding + gDebugPortComponentName + + + diff --git a/EdkModulePkg/Universal/Debugger/Debugport/Dxe/build.xml b/EdkModulePkg/Universal/Debugger/Debugport/Dxe/build.xml new file mode 100644 index 0000000000..89b603c257 --- /dev/null +++ b/EdkModulePkg/Universal/Debugger/Debugport/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Universal/Disk/DiskIo/Dxe/ComponentName.c b/EdkModulePkg/Universal/Disk/DiskIo/Dxe/ComponentName.c new file mode 100644 index 0000000000..35ca70d8f8 --- /dev/null +++ b/EdkModulePkg/Universal/Disk/DiskIo/Dxe/ComponentName.c @@ -0,0 +1,160 @@ + /*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ComponentName.c + +Abstract: + +--*/ + +#include "DiskIo.h" + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +DiskIoComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +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 + ); + +// +// EFI Component Name Protocol +// +EFI_COMPONENT_NAME_PROTOCOL gDiskIoComponentName = { + DiskIoComponentNameGetDriverName, + DiskIoComponentNameGetControllerName, + "eng" +}; + +static EFI_UNICODE_STRING_TABLE mDiskIoDriverNameTable[] = { + { + "eng", + (CHAR16 *)L"Generic Disk I/O Driver" + }, + { + NULL, + NULL + } +}; + +EFI_STATUS +EFIAPI +DiskIoComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gDiskIoComponentName.SupportedLanguages, + mDiskIoDriverNameTable, + DriverName + ); +} + +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 + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + 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. + 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. + + Returns: + 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. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return EFI_UNSUPPORTED; +} diff --git a/EdkModulePkg/Universal/Disk/DiskIo/Dxe/DiskIo.mbd b/EdkModulePkg/Universal/Disk/DiskIo/Dxe/DiskIo.mbd new file mode 100644 index 0000000000..087bedf5bb --- /dev/null +++ b/EdkModulePkg/Universal/Disk/DiskIo/Dxe/DiskIo.mbd @@ -0,0 +1,41 @@ + + + + + DiskIo + 6B38F7B4-AD98-40e9-9093-ACA2B5A253C4 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + + UefiBootServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + BaseLib + DxeMemoryAllocationLib + + diff --git a/EdkModulePkg/Universal/Disk/DiskIo/Dxe/DiskIo.msa b/EdkModulePkg/Universal/Disk/DiskIo/Dxe/DiskIo.msa new file mode 100644 index 0000000000..2ddc5233f2 --- /dev/null +++ b/EdkModulePkg/Universal/Disk/DiskIo/Dxe/DiskIo.msa @@ -0,0 +1,65 @@ + + + + + DiskIo + UEFI_DRIVER + BS_DRIVER + 6B38F7B4-AD98-40e9-9093-ACA2B5A253C4 + 0 + Component description file for DiskIo module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + UefiLib + BaseLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + + + diskio.c + diskio.h + ComponentName.c + + + MdePkg + + + BlockIo + DiskIo + + + + + + + gDiskIoDriverBinding + gDiskIoComponentName + + + diff --git a/EdkModulePkg/Universal/Disk/DiskIo/Dxe/build.xml b/EdkModulePkg/Universal/Disk/DiskIo/Dxe/build.xml new file mode 100644 index 0000000000..8a6ff7b7bc --- /dev/null +++ b/EdkModulePkg/Universal/Disk/DiskIo/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Universal/Disk/DiskIo/Dxe/diskio.c b/EdkModulePkg/Universal/Disk/DiskIo/Dxe/diskio.c new file mode 100644 index 0000000000..4998c9b0f7 --- /dev/null +++ b/EdkModulePkg/Universal/Disk/DiskIo/Dxe/diskio.c @@ -0,0 +1,876 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DiskIo.c + +Abstract: + + DiskIo driver that layers it's self on every Block IO protocol in the system. + DiskIo converts a block oriented device to a byte oriented device. + + ReadDisk may have to do 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. + +--*/ + +#include "DiskIo.h" + +// +// Prototypes +// Driver model protocol interface +// +EFI_STATUS +EFIAPI +DiskIoDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +DiskIoDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +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 +// +EFI_STATUS +EFIAPI +DiskIoReadDisk ( + IN EFI_DISK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN UINT64 Offset, + IN UINTN BufferSize, + OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +DiskIoWriteDisk ( + IN EFI_DISK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN UINT64 Offset, + IN UINTN BufferSize, + IN VOID *Buffer + ); + +EFI_DRIVER_BINDING_PROTOCOL gDiskIoDriverBinding = { + DiskIoDriverBindingSupported, + DiskIoDriverBindingStart, + DiskIoDriverBindingStop, + 0x10, + NULL, + NULL +}; + +DISK_IO_PRIVATE_DATA gDiskIoPrivateDataTemplate = { + DISK_IO_PRIVATE_DATA_SIGNATURE, + { + EFI_DISK_IO_PROTOCOL_REVISION, + DiskIoReadDisk, + DiskIoWriteDisk + }, + NULL +}; + +EFI_STATUS +EFIAPI +DiskIoDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +/*++ + + Routine Description: + Test to see if this driver supports ControllerHandle. Any ControllerHandle + than contains a BlockIo protocol can be supported. + + Arguments: + This - Protocol instance pointer. + ControllerHandle - Handle of device to test. + RemainingDevicePath - Not used. + + Returns: + EFI_SUCCESS - This driver supports this device. + EFI_ALREADY_STARTED - This driver is already running on this device. + other - This driver does not support this device. + +--*/ +{ + EFI_STATUS Status; + EFI_BLOCK_IO_PROTOCOL *BlockIo; +/* + DEBUG_CODE_BEGIN + UINT32 Bar; + UINT32 Foo; + UINT32 HotPlug; + + // + // Get TYPE 0 + // + Bar = PcdGet32 (PciExpressBaseVersion); + DEBUG ((EFI_D_ERROR, "PciExpressBaseVersion = %08x\n", Bar)); + + // + // Get TYPE 1 + // + Foo = PcdGet32 (PciExpressBaseAddress); + DEBUG ((EFI_D_ERROR, "PciExpressBaseAddress = %08x\n", Foo)); + + // + // Set TYPE 1 + // + PcdSet32 (PciExpressBaseAddress, Foo + 1); + + // + // Get TYPE 1 + // + Foo = PcdGet32 (PciExpressBaseAddress); + DEBUG ((EFI_D_ERROR, "PciExpressBaseAddress = %08x\n", Foo)); + + // + // Get TYPE 2 + // + HotPlug = PcdGet32 (PciExpressBaseHotPlug); + DEBUG ((EFI_D_ERROR, "PciExpressHotPlug = %08x\n", HotPlug)); + + // + // Set TYPE 1 + // + PcdSet32 (PciExpressBaseHotPlug, HotPlug + 1); + + // + // Get TYPE 1 + // + HotPlug = PcdGet32 (PciExpressBaseHotPlug); + DEBUG ((EFI_D_ERROR, "PciExpressHotPlug = %08x\n", HotPlug)); + + DEBUG_CODE_END + + DEBUG_CODE_BEGIN + UINT32 MyVariable; + + if (ControllerHandle == NULL) { + MyVariable = 32 * (UINTN)This; + ControllerHandle = (EFI_HANDLE)MyVariable; + DEBUG ((EFI_D_ERROR, "DiskIoSupported-DebugCode. MyVariable = %08x\n", MyVariable)); + ASSERT (MyVariable != 32); + } + DEBUG_CODE_END +*/ + DEBUG ((EFI_D_ERROR, "DiskIoSupported\n")); + +// Io8Or (0x400, 1); +// Io8And (0x400, 1); +// Io8AndThenOr (0x400, 1, 2); + +// Mmio8Or (0xa0000000, 1); +// Mmio8And (0xa0000000, 1); +// Mmio8AndThenOr (0xa0000000, 1, 2); + +/* + PciRead8 (PCI_LIB_ADDRESS (1,2,3,4)); + PciRead16 (PCI_LIB_ADDRESS (1,2,3,4)); + PciRead32 (PCI_LIB_ADDRESS (1,2,3,4)); + + PciWrite8 (PCI_LIB_ADDRESS (1,2,3,4), 0xAA); + PciWrite16 (PCI_LIB_ADDRESS (1,2,3,4), 0xAA55); + PciWrite32 (PCI_LIB_ADDRESS (1,2,3,4), 0xAA55A55A); + + Pci8Or (PCI_LIB_ADDRESS (1,2,3,4), 0xAA); + Pci8And (PCI_LIB_ADDRESS (1,2,3,4), 0x55); + Pci8AndThenOr (PCI_LIB_ADDRESS (1,2,3,4), 0xAA, 0x55); + + Pci16Or (PCI_LIB_ADDRESS (1,2,3,4), 0xAA55); + Pci16And (PCI_LIB_ADDRESS (1,2,3,4), 0x55AA); + Pci16AndThenOr (PCI_LIB_ADDRESS (1,2,3,4), 0xAA55, 0x55AA); + + Pci32Or (PCI_LIB_ADDRESS (1,2,3,4), 0xAA55A55A); + Pci32And (PCI_LIB_ADDRESS (1,2,3,4), 0x55AA5AA5); + Pci32AndThenOr (PCI_LIB_ADDRESS (1,2,3,4), 0xAA555AA5, 0x55AAA55A); +*/ + // + // 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; +} + +EFI_STATUS +EFIAPI +DiskIoDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +/*++ + + Routine Description: + Start this driver on ControllerHandle by opening a Block IO protocol and + installing a Disk IO protocol on ControllerHandle. + + Arguments: + This - Protocol instance pointer. + ControllerHandle - Handle of device to bind driver to. + RemainingDevicePath - Not used, always produce all possible children. + + Returns: + EFI_SUCCESS - This driver is added to ControllerHandle. + EFI_ALREADY_STARTED - This driver is already running on ControllerHandle. + other - This driver does not support this device. + +--*/ +{ + EFI_STATUS Status; + DISK_IO_PRIVATE_DATA *Private; + + Private = NULL; + + DEBUG ((EFI_D_ERROR, "DiskIoStart\n")); + // + // Connect to the Block IO interface on ControllerHandle. + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiBlockIoProtocolGuid, + (VOID **) &gDiskIoPrivateDataTemplate.BlockIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Initialize the Disk IO device instance. + // + Private = AllocateCopyPool (sizeof (DISK_IO_PRIVATE_DATA), &gDiskIoPrivateDataTemplate); + if (Private == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + // + // Install protocol interfaces for the Disk IO device. + // + Status = gBS->InstallProtocolInterface ( + &ControllerHandle, + &gEfiDiskIoProtocolGuid, + EFI_NATIVE_INTERFACE, + &Private->DiskIo + ); + +ErrorExit: + if (EFI_ERROR (Status)) { + + if (Private != NULL) { + gBS->FreePool (Private); + } + + gBS->CloseProtocol ( + ControllerHandle, + &gEfiBlockIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + } + + return Status; +} + +EFI_STATUS +EFIAPI +DiskIoDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + + Routine Description: + Stop this driver on ControllerHandle by removing Disk IO protocol and closing + the Block IO protocol on ControllerHandle. + + Arguments: + This - Protocol instance pointer. + ControllerHandle - Handle of device to stop driver on. + NumberOfChildren - Not used. + ChildHandleBuffer - Not used. + + Returns: + EFI_SUCCESS - This driver is removed ControllerHandle. + other - This driver was not removed from this device. + EFI_UNSUPPORTED + +--*/ +{ + EFI_STATUS Status; + EFI_DISK_IO_PROTOCOL *DiskIo; + DISK_IO_PRIVATE_DATA *Private; + + DEBUG ((EFI_D_ERROR, "DiskIoStop\n")); + // + // Get our context back. + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiDiskIoProtocolGuid, + (VOID **) &DiskIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Private = DISK_IO_PRIVATE_DATA_FROM_THIS (DiskIo); + + Status = gBS->UninstallProtocolInterface ( + ControllerHandle, + &gEfiDiskIoProtocolGuid, + &Private->DiskIo + ); + if (!EFI_ERROR (Status)) { + + Status = gBS->CloseProtocol ( + ControllerHandle, + &gEfiBlockIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + } + + if (!EFI_ERROR (Status)) { + gBS->FreePool (Private); + } + + return Status; +} + +EFI_STATUS +EFIAPI +DiskIoReadDisk ( + IN EFI_DISK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN UINT64 Offset, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +/*++ + + Routine Description: + 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. + + + Arguments: + This - Protocol instance pointer. + MediaId - Id of the media, changes every time the media is replaced. + Offset - The starting byte offset to read from. + BufferSize - Size of Buffer. + Buffer - Buffer containing read data. + + Returns: + EFI_SUCCESS - The data was read correctly from the device. + EFI_DEVICE_ERROR - The device reported an error while performing the read. + EFI_NO_MEDIA - There is no media in the device. + EFI_MEDIA_CHNAGED - The MediaId does not matched the current device. + EFI_INVALID_PARAMETER - The read request contains device addresses that are not + valid for the device. + EFI_OUT_OF_RESOURCES + +--*/ +{ + EFI_STATUS Status; + DISK_IO_PRIVATE_DATA *Private; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + EFI_BLOCK_IO_MEDIA *Media; + UINT32 BlockSize; + UINT64 Lba; + UINT64 OverRunLba; + UINT32 UnderRun; + UINT32 OverRun; + BOOLEAN TransactionComplete; + UINTN WorkingBufferSize; + UINT8 *WorkingBuffer; + UINTN Length; + UINT8 *Data; + UINT8 *PreData; + UINTN IsBufferAligned; + UINTN DataBufferSize; + BOOLEAN LastRead; + + DEBUG ((EFI_D_ERROR, "DiskIoReadDisk\n")); + + Private = DISK_IO_PRIVATE_DATA_FROM_THIS (This); + + BlockIo = Private->BlockIo; + Media = BlockIo->Media; + BlockSize = Media->BlockSize; + + if (Media->MediaId != MediaId) { + return EFI_MEDIA_CHANGED; + } + + WorkingBuffer = Buffer; + WorkingBufferSize = BufferSize; + + // + // Allocate a temporary buffer for operation + // + DataBufferSize = BlockSize * DATA_BUFFER_BLOCK_NUM; + + if (Media->IoAlign > 1) { + PreData = AllocatePool (DataBufferSize + Media->IoAlign); + Data = PreData - ((UINTN) PreData & (Media->IoAlign - 1)) + Media->IoAlign; + } else { + PreData = AllocatePool (DataBufferSize); + Data = PreData; + } + + if (PreData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Lba = DivU64x32Remainder (Offset, BlockSize, &UnderRun); + + Length = BlockSize - UnderRun; + TransactionComplete = FALSE; + + Status = EFI_SUCCESS; + if (UnderRun != 0) { + // + // Offset starts in the middle of an Lba, so read the entire block. + // + Status = BlockIo->ReadBlocks ( + BlockIo, + MediaId, + Lba, + BlockSize, + Data + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + + if (Length > BufferSize) { + Length = BufferSize; + TransactionComplete = TRUE; + } + + CopyMem (WorkingBuffer, Data + UnderRun, Length); + + WorkingBuffer += Length; + + WorkingBufferSize -= Length; + if (WorkingBufferSize == 0) { + goto Done; + } + + Lba += 1; + } + + OverRunLba = Lba + DivU64x32Remainder (WorkingBufferSize, BlockSize, &OverRun); + + if (!TransactionComplete && WorkingBufferSize >= BlockSize) { + // + // If the DiskIo maps directly to a BlockIo device do the read. + // + if (OverRun != 0) { + WorkingBufferSize -= OverRun; + } + // + // Check buffer alignment + // + IsBufferAligned = (UINTN) WorkingBuffer & (UINTN) (Media->IoAlign - 1); + + if (Media->IoAlign <= 1 || IsBufferAligned == 0) { + // + // Alignment is satisfied, so read them together + // + Status = BlockIo->ReadBlocks ( + BlockIo, + MediaId, + Lba, + WorkingBufferSize, + WorkingBuffer + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + + WorkingBuffer += WorkingBufferSize; + + } else { + // + // Use the allocated buffer instead of the original buffer + // to avoid alignment issue. + // Here, the allocated buffer (8-byte align) can satisfy the alignment + // + LastRead = FALSE; + do { + if (WorkingBufferSize <= DataBufferSize) { + // + // It is the last calling to readblocks in this loop + // + DataBufferSize = WorkingBufferSize; + LastRead = TRUE; + } + + Status = BlockIo->ReadBlocks ( + BlockIo, + MediaId, + Lba, + DataBufferSize, + Data + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + CopyMem (WorkingBuffer, Data, DataBufferSize); + WorkingBufferSize -= DataBufferSize; + WorkingBuffer += DataBufferSize; + Lba += DATA_BUFFER_BLOCK_NUM; + } while (!LastRead); + } + } + + if (!TransactionComplete && OverRun != 0) { + // + // Last read is not a complete block. + // + Status = BlockIo->ReadBlocks ( + BlockIo, + MediaId, + OverRunLba, + BlockSize, + Data + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + + CopyMem (WorkingBuffer, Data, OverRun); + } + +Done: + if (PreData != NULL) { + gBS->FreePool (PreData); + } + + return Status; +} + +EFI_STATUS +EFIAPI +DiskIoWriteDisk ( + IN EFI_DISK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN UINT64 Offset, + IN UINTN BufferSize, + IN VOID *Buffer + ) +/*++ + + Routine Description: + Read BufferSize bytes from Offset into Buffer. + + 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. + + Arguments: + This - Protocol instance pointer. + MediaId - Id of the media, changes every time the media is replaced. + Offset - The starting byte offset to read from. + BufferSize - Size of Buffer. + Buffer - Buffer containing read data. + + Returns: + EFI_SUCCESS - The data was written correctly to the device. + EFI_WRITE_PROTECTED - The device can not be written to. + EFI_DEVICE_ERROR - The device reported an error while performing the write. + EFI_NO_MEDIA - There is no media in the device. + EFI_MEDIA_CHNAGED - The MediaId does not matched the current device. + EFI_INVALID_PARAMETER - The write request contains device addresses that are not + valid for the device. + EFI_OUT_OF_RESOURCES + +--*/ +{ + EFI_STATUS Status; + DISK_IO_PRIVATE_DATA *Private; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + EFI_BLOCK_IO_MEDIA *Media; + UINT32 BlockSize; + UINT64 Lba; + UINT64 OverRunLba; + UINT32 UnderRun; + UINT32 OverRun; + BOOLEAN TransactionComplete; + UINTN WorkingBufferSize; + UINT8 *WorkingBuffer; + UINTN Length; + UINT8 *Data; + UINT8 *PreData; + UINTN IsBufferAligned; + UINTN DataBufferSize; + BOOLEAN LastWrite; + + DEBUG ((EFI_D_ERROR, "DiskIoWriteDisk\n")); + + Private = DISK_IO_PRIVATE_DATA_FROM_THIS (This); + + BlockIo = Private->BlockIo; + Media = BlockIo->Media; + BlockSize = Media->BlockSize; + + if (Media->ReadOnly) { + return EFI_WRITE_PROTECTED; + } + + if (Media->MediaId != MediaId) { + return EFI_MEDIA_CHANGED; + } + + DataBufferSize = BlockSize * DATA_BUFFER_BLOCK_NUM; + + if (Media->IoAlign > 1) { + PreData = AllocatePool (DataBufferSize + Media->IoAlign); + Data = PreData - ((UINTN) PreData & (Media->IoAlign - 1)) + Media->IoAlign; + } else { + PreData = AllocatePool (DataBufferSize); + Data = PreData; + } + + if (PreData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + WorkingBuffer = Buffer; + WorkingBufferSize = BufferSize; + + Lba = DivU64x32Remainder (Offset, BlockSize, &UnderRun); + + Length = BlockSize - UnderRun; + TransactionComplete = FALSE; + + Status = EFI_SUCCESS; + if (UnderRun != 0) { + // + // Offset starts in the middle of an Lba, so do read modify write. + // + Status = BlockIo->ReadBlocks ( + BlockIo, + MediaId, + Lba, + BlockSize, + Data + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + + if (Length > BufferSize) { + Length = BufferSize; + TransactionComplete = TRUE; + } + + CopyMem (Data + UnderRun, WorkingBuffer, Length); + + Status = BlockIo->WriteBlocks ( + BlockIo, + MediaId, + Lba, + BlockSize, + Data + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + WorkingBuffer += Length; + WorkingBufferSize -= Length; + if (WorkingBufferSize == 0) { + goto Done; + } + + Lba += 1; + } + + OverRunLba = Lba + DivU64x32Remainder (WorkingBufferSize, BlockSize, &OverRun); + + if (!TransactionComplete && WorkingBufferSize >= BlockSize) { + // + // If the DiskIo maps directly to a BlockIo device do the write. + // + if (OverRun != 0) { + WorkingBufferSize -= OverRun; + } + // + // Check buffer alignment + // + IsBufferAligned = (UINTN) WorkingBuffer & (UINTN) (Media->IoAlign - 1); + + if (Media->IoAlign <= 1 || IsBufferAligned == 0) { + // + // Alignment is satisfied, so write them together + // + Status = BlockIo->WriteBlocks ( + BlockIo, + MediaId, + Lba, + WorkingBufferSize, + WorkingBuffer + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + + WorkingBuffer += WorkingBufferSize; + + } else { + // + // The buffer parameter is not aligned with the request + // So use the allocated instead. + // It can fit almost all the cases. + // + LastWrite = FALSE; + do { + if (WorkingBufferSize <= DataBufferSize) { + // + // It is the last calling to writeblocks in this loop + // + DataBufferSize = WorkingBufferSize; + LastWrite = TRUE; + } + + CopyMem (Data, WorkingBuffer, DataBufferSize); + Status = BlockIo->WriteBlocks ( + BlockIo, + MediaId, + Lba, + DataBufferSize, + Data + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + WorkingBufferSize -= DataBufferSize; + WorkingBuffer += DataBufferSize; + Lba += DATA_BUFFER_BLOCK_NUM; + } while (!LastWrite); + } + } + + if (!TransactionComplete && OverRun != 0) { + // + // Last bit is not a complete block, so do a read modify write. + // + Status = BlockIo->ReadBlocks ( + BlockIo, + MediaId, + OverRunLba, + BlockSize, + Data + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + + CopyMem (Data, WorkingBuffer, OverRun); + + Status = BlockIo->WriteBlocks ( + BlockIo, + MediaId, + OverRunLba, + BlockSize, + Data + ); + if (EFI_ERROR (Status)) { + goto Done; + } + } + +Done: + if (PreData != NULL) { + gBS->FreePool (PreData); + } + + return Status; +} diff --git a/EdkModulePkg/Universal/Disk/DiskIo/Dxe/diskio.h b/EdkModulePkg/Universal/Disk/DiskIo/Dxe/diskio.h new file mode 100644 index 0000000000..39d87661c6 --- /dev/null +++ b/EdkModulePkg/Universal/Disk/DiskIo/Dxe/diskio.h @@ -0,0 +1,44 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DiskIo.h + +Abstract: + Private Data definition for Disk IO driver + +--*/ + +#ifndef _DISK_IO_H +#define _DISK_IO_H + + + +#define DISK_IO_PRIVATE_DATA_SIGNATURE EFI_SIGNATURE_32 ('d', 's', 'k', 'I') + +#define DATA_BUFFER_BLOCK_NUM (64) + +typedef struct { + UINTN Signature; + EFI_DISK_IO_PROTOCOL DiskIo; + EFI_BLOCK_IO_PROTOCOL *BlockIo; +} DISK_IO_PRIVATE_DATA; + +#define DISK_IO_PRIVATE_DATA_FROM_THIS(a) CR (a, DISK_IO_PRIVATE_DATA, DiskIo, DISK_IO_PRIVATE_DATA_SIGNATURE) + +// +// Global Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gDiskIoDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gDiskIoComponentName; + +#endif diff --git a/EdkModulePkg/Universal/Disk/DiskIoPartition/dxe/DiskIoPartition.mbd b/EdkModulePkg/Universal/Disk/DiskIoPartition/dxe/DiskIoPartition.mbd new file mode 100644 index 0000000000..ed89f0716e --- /dev/null +++ b/EdkModulePkg/Universal/Disk/DiskIoPartition/dxe/DiskIoPartition.mbd @@ -0,0 +1,42 @@ + + + + + DiskIoPartition + 854E153A-8AC8-40f4-A5A9-4C51F18CFB1B + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + + UefiBootServicesTableLib + BaseLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + DxeMemoryAllocationLib + UefiDevicePathLib + + diff --git a/EdkModulePkg/Universal/Disk/DiskIoPartition/dxe/DiskIoPartition.msa b/EdkModulePkg/Universal/Disk/DiskIoPartition/dxe/DiskIoPartition.msa new file mode 100644 index 0000000000..930f57b96a --- /dev/null +++ b/EdkModulePkg/Universal/Disk/DiskIoPartition/dxe/DiskIoPartition.msa @@ -0,0 +1,88 @@ + + + + + DiskIoPartition + UEFI_DRIVER + BS_DRIVER + 854E153A-8AC8-40f4-A5A9-4C51F18CFB1B + 0 + Component description file for DiskIo module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + BaseLib + UefiLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + DevicePathLib + + + ..\..\DiskIo\Dxe\diskio.c + ..\..\DiskIo\Dxe\diskio.h + ..\..\DiskIo\Dxe\ComponentName.c + ..\..\Partition\Dxe\Partition.h + ..\..\Partition\Dxe\ElTorito.h + ..\..\Partition\Dxe\Gpt.h + ..\..\Partition\Dxe\Mbr.h + ..\..\Partition\Dxe\Partition.c + ..\..\Partition\Dxe\Eltorito.c + ..\..\Partition\Dxe\Gpt.c + ..\..\Partition\Dxe\Mbr.c + ..\..\Partition\Dxe\ComponentName.c + + + MdePkg + + + BlockIo + DiskIo + DevicePath + + + + PartTypeSystemPart + + + PartTypeUnused + + + + + + + + gPartitionDriverBinding + gPartitionComponentName + + + gDiskIoDriverBinding + gDiskIoComponentName + + + diff --git a/EdkModulePkg/Universal/Disk/DiskIoPartition/dxe/build.xml b/EdkModulePkg/Universal/Disk/DiskIoPartition/dxe/build.xml new file mode 100644 index 0000000000..4b1c1f88cf --- /dev/null +++ b/EdkModulePkg/Universal/Disk/DiskIoPartition/dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Universal/Disk/Partition/Dxe/ComponentName.c b/EdkModulePkg/Universal/Disk/Partition/Dxe/ComponentName.c new file mode 100644 index 0000000000..3821690f0c --- /dev/null +++ b/EdkModulePkg/Universal/Disk/Partition/Dxe/ComponentName.c @@ -0,0 +1,160 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ComponentName.c + +Abstract: + +--*/ + +#include "Partition.h" + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +PartitionComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +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 + ); + +// +// EFI Component Name Protocol +// +EFI_COMPONENT_NAME_PROTOCOL gPartitionComponentName = { + PartitionComponentNameGetDriverName, + PartitionComponentNameGetControllerName, + "eng" +}; + +static EFI_UNICODE_STRING_TABLE mPartitionDriverNameTable[] = { + { + "eng", + (CHAR16 *)L"Partition Driver(MBR/GPT/El Torito)" + }, + { + NULL, + NULL + } +}; + +EFI_STATUS +EFIAPI +PartitionComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gPartitionComponentName.SupportedLanguages, + mPartitionDriverNameTable, + DriverName + ); +} + +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 + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + 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. + 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. + + Returns: + 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. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return EFI_UNSUPPORTED; +} diff --git a/EdkModulePkg/Universal/Disk/Partition/Dxe/ElTorito.c b/EdkModulePkg/Universal/Disk/Partition/Dxe/ElTorito.c new file mode 100644 index 0000000000..27beba171b --- /dev/null +++ b/EdkModulePkg/Universal/Disk/Partition/Dxe/ElTorito.c @@ -0,0 +1,277 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ElTorito.c + +Abstract: + + Decode an El Torito formatted CD-ROM + +Revision History + +--*/ + +#include "Partition.h" +#include "ElTorito.h" + +BOOLEAN +PartitionInstallElToritoChildHandles ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +/*++ + +Routine Description: + Install child handles if the Handle supports El Torito format. + +Arguments: + This - Calling context. + Handle - Parent Handle + DiskIo - Parent DiskIo interface + BlockIo - Parent BlockIo interface + DevicePath - Parent Device Path + +Returns: + TRUE - some child handle(s) was added + FALSE - no child handle was added + +--*/ +{ + EFI_STATUS Status; + UINT32 VolDescriptorLba; + UINT32 Lba; + 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; + BOOLEAN Found; + UINT32 VolSpaceSize; + + Found = FALSE; + Media = BlockIo->Media; + VolSpaceSize = 0; + + // + // CD_ROM has the fixed block size as 2048 bytes + // + if (Media->BlockSize != 2048) { + return FALSE; + } + + VolDescriptor = AllocatePool ((UINTN) Media->BlockSize); + + if (VolDescriptor == NULL) { + return FALSE; + } + + Catalog = (ELTORITO_CATALOG *) VolDescriptor; + + // + // the ISO-9660 volume descriptor starts at 32k on the media + // and CD_ROM has the fixed block size as 2048 bytes, so... + // + // + // ((16*2048) / Media->BlockSize) - 1; + // + VolDescriptorLba = 15; + // + // Loop: handle one volume descriptor per time + // + while (TRUE) { + + VolDescriptorLba += 1; + if (VolDescriptorLba > Media->LastBlock) { + // + // We are pointing past the end of the device so exit + // + break; + } + + Status = BlockIo->ReadBlocks ( + BlockIo, + Media->MediaId, + VolDescriptorLba, + Media->BlockSize, + VolDescriptor + ); + if (EFI_ERROR (Status)) { + break; + } + // + // Check for valid volume descriptor signature + // + if (VolDescriptor->Type == CDVOL_TYPE_END || + CompareMem (VolDescriptor->Id, CDVOL_ID, sizeof (VolDescriptor->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->Type == CDVOL_TYPE_CODED) { + VolSpaceSize = VolDescriptor->VolSpaceSize[1]; + } + // + // Is it an El Torito volume descriptor? + // + if (CompareMem (VolDescriptor->SystemId, CDVOL_ELTORITO_ID, sizeof (CDVOL_ELTORITO_ID) - 1) != 0) { + continue; + } + // + // Read in the boot El Torito boot catalog + // + Lba = UNPACK_INT32 (VolDescriptor->EltCatalog); + if (Lba > Media->LastBlock) { + continue; + } + + Status = BlockIo->ReadBlocks ( + BlockIo, + Media->MediaId, + Lba, + Media->BlockSize, + 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) { + 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; + if (SectorCount < 2) { + CdDev.PartitionSize = VolSpaceSize; + } else { + CdDev.PartitionSize = DivU64x32 ( + MultU64x32 ( + SectorCount, + SubBlockSize + ) + Media->BlockSize - 1, + Media->BlockSize + ); + } + + Status = PartitionInstallChildHandle ( + This, + Handle, + DiskIo, + BlockIo, + DevicePath, + (EFI_DEVICE_PATH_PROTOCOL *) &CdDev, + Catalog->Boot.Lba, + Catalog->Boot.Lba + CdDev.PartitionSize - 1, + SubBlockSize, + FALSE + ); + if (!EFI_ERROR (Status)) { + Found = TRUE; + } + } + } + + gBS->FreePool (VolDescriptor); + + return Found; +} diff --git a/EdkModulePkg/Universal/Disk/Partition/Dxe/ElTorito.h b/EdkModulePkg/Universal/Disk/Partition/Dxe/ElTorito.h new file mode 100644 index 0000000000..f085315b4d --- /dev/null +++ b/EdkModulePkg/Universal/Disk/Partition/Dxe/ElTorito.h @@ -0,0 +1,130 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ElTorito.h + +Abstract: + + Data Structures required for detecting ElTorito Partitions + +Revision History + +--*/ + +#ifndef _ELTORITO_H_ +#define _ELTORITO_H_ + +#pragma pack(1) +// +// CDROM_VOLUME_DESCRIPTOR.Types +// +#define CDVOL_TYPE_STANDARD 0x0 +#define CDVOL_TYPE_CODED 0x1 +#define CDVOL_TYPE_END 0xFF + +// +// CDROM_VOLUME_DESCRIPTOR.Id +// +#define CDVOL_ID "CD001" + +// +// CDROM_VOLUME_DESCRIPTOR.SystemId +// +#define CDVOL_ELTORITO_ID "EL TORITO SPECIFICATION" + +// +// Indicator types +// +#define ELTORITO_ID_CATALOG 0x01 +#define ELTORITO_ID_SECTION_BOOTABLE 0x88 +#define ELTORITO_ID_SECTION_NOT_BOOTABLE 0x00 +#define ELTORITO_ID_SECTION_HEADER 0x90 +#define ELTORITO_ID_SECTION_HEADER_FINAL 0x91 + +// +// ELTORITO_CATALOG.Boot.MediaTypes +// +#define ELTORITO_NO_EMULATION 0x00 +#define ELTORITO_12_DISKETTE 0x01 +#define ELTORITO_14_DISKETTE 0x02 +#define ELTORITO_28_DISKETTE 0x03 +#define ELTORITO_HARD_DISK 0x04 + +// +// El Torito Volume Descriptor +// Note that the CDROM_VOLUME_DESCRIPTOR does not match the ISO-9660 +// descriptor. For some reason descriptor used by El Torito is +// different, but they start the same. The El Torito descriptor +// is left shifted 1 byte starting with the SystemId. (Note this +// causes the field to get unaligned) +// +typedef struct { + UINT8 Type; + CHAR8 Id[5]; // CD001 + UINT8 Version; + CHAR8 SystemId[26]; + CHAR8 Unused[38]; + UINT8 EltCatalog[4]; + CHAR8 Unused2[5]; + UINT32 VolSpaceSize[2]; +} CDROM_VOLUME_DESCRIPTOR; + +// +// Catalog Entry +// +typedef union { + struct { + CHAR8 Reserved[0x20]; + } Unknown; + + // + // Catalog validation entry (Catalog header) + // + struct { + UINT8 Indicator; + UINT8 PlatformId; + UINT16 Reserved; + CHAR8 ManufacId[24]; + UINT16 Checksum; + UINT16 Id55AA; + } Catalog; + + // + // Initial/Default Entry or Section Entry + // + struct { + UINT8 Indicator; + UINT8 MediaType : 4; + UINT8 Reserved1 : 4; + UINT16 LoadSegment; + UINT8 SystemType; + UINT8 Reserved2; + UINT16 SectorCount; + UINT32 Lba; + } Boot; + + // + // Section Header Entry + // + struct { + UINT8 Indicator; + UINT8 PlatformId; + UINT16 SectionEntries; + CHAR8 Id[28]; + } Section; + +} ELTORITO_CATALOG; + +#pragma pack() + +#endif diff --git a/EdkModulePkg/Universal/Disk/Partition/Dxe/Gpt.c b/EdkModulePkg/Universal/Disk/Partition/Dxe/Gpt.c new file mode 100644 index 0000000000..35ff1a8606 --- /dev/null +++ b/EdkModulePkg/Universal/Disk/Partition/Dxe/Gpt.c @@ -0,0 +1,768 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Gpt.c + +Abstract: + + Decode a hard disk partitioned with the GPT scheme in the EFI 1.0 + specification. + +--*/ + +#include "Partition.h" +#include "Gpt.h" +#include "Mbr.h" + +BOOLEAN +PartitionValidGptTable ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN EFI_LBA Lba, + OUT EFI_PARTITION_TABLE_HEADER *PartHeader + ); + +BOOLEAN +PartitionCheckGptEntryArrayCRC ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN EFI_PARTITION_TABLE_HEADER *PartHeader + ); + +BOOLEAN +PartitionRestoreGptTable ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN EFI_PARTITION_TABLE_HEADER *PartHeader + ); + +VOID +PartitionCheckGptEntry ( + IN EFI_PARTITION_TABLE_HEADER *PartHeader, + IN EFI_PARTITION_ENTRY *PartEntry, + OUT EFI_PARTITION_ENTRY_STATUS *PEntryStatus + ); + +BOOLEAN +PartitionCheckCrcAltSize ( + IN UINTN MaxSize, + IN UINTN Size, + IN OUT EFI_TABLE_HEADER *Hdr + ); + +BOOLEAN +PartitionCheckCrc ( + IN UINTN MaxSize, + IN OUT EFI_TABLE_HEADER *Hdr + ); + +VOID +PartitionSetCrcAltSize ( + IN UINTN Size, + IN OUT EFI_TABLE_HEADER *Hdr + ); + +VOID +PartitionSetCrc ( + IN OUT EFI_TABLE_HEADER *Hdr + ); + +BOOLEAN +PartitionInstallGptChildHandles ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +/*++ + +Routine Description: + Install child handles if the Handle supports GPT partition structure. + +Arguments: + This - Calling context. + Handle - Parent Handle + DiskIo - Parent DiskIo interface + BlockIo - Parent BlockIo interface + DevicePath - Parent Device Path + +Returns: + TRUE - Valid GPT disk + FALSE - Not a valid GPT disk + +--*/ +{ + 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_STATUS *PEntryStatus; + UINTN Index; + BOOLEAN GptValid; + HARDDRIVE_DEVICE_PATH HdDev; + + ProtectiveMbr = NULL; + PrimaryHeader = NULL; + BackupHeader = NULL; + PartEntry = NULL; + PEntryStatus = NULL; + + BlockSize = BlockIo->Media->BlockSize; + LastBlock = BlockIo->Media->LastBlock; + + DEBUG ((EFI_D_INFO, " BlockSize : %d \n", BlockSize)); + DEBUG ((EFI_D_INFO, " LastBlock : %x \n", LastBlock)); + + GptValid = FALSE; + + // + // Allocate a buffer for the Protective MBR + // + ProtectiveMbr = AllocatePool (BlockSize); + if (ProtectiveMbr == NULL) { + return FALSE; + } + + // + // Read the Protective MBR from LBA #0 + // + Status = BlockIo->ReadBlocks ( + BlockIo, + BlockIo->Media->MediaId, + 0, + BlockIo->Media->BlockSize, + ProtectiveMbr + ); + if (EFI_ERROR (Status)) { + goto Done; + } + // + // Verify that the Protective MBR is valid + // + if (ProtectiveMbr->Partition[0].BootIndicator != 0x00 || + ProtectiveMbr->Partition[0].OSIndicator != 0xEE || + UNPACK_UINT32 (ProtectiveMbr->Partition[0].StartingLBA) != 1 + ) { + 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 * sizeof (EFI_PARTITION_ENTRY)); + if (PartEntry == NULL) { + DEBUG ((EFI_D_ERROR, "Allocate pool error\n")); + goto Done; + } + + Status = DiskIo->ReadDisk ( + DiskIo, + BlockIo->Media->MediaId, + MultU64x32(PrimaryHeader->PartitionEntryLBA, BlockSize), + PrimaryHeader->NumberOfPartitionEntries * (PrimaryHeader->SizeOfPartitionEntry), + PartEntry + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_INFO, " Partition Entry ReadBlocks 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 + // + GptValid = TRUE; + + // + // Create child device handles + // + for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) { + if (CompareGuid (&PartEntry[Index].PartitionTypeGUID, &gEfiPartTypeUnusedGuid) || + PEntryStatus[Index].OutOfRange || + PEntryStatus[Index].Overlap + ) { + // + // Don't use null EFI Partition Entries or Invalid 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 = PartEntry[Index].StartingLBA; + HdDev.PartitionSize = PartEntry[Index].EndingLBA - PartEntry[Index].StartingLBA + 1; + CopyMem (HdDev.Signature, &PartEntry[Index].UniquePartitionGUID, sizeof (EFI_GUID)); + + DEBUG ((EFI_D_INFO, " Index : %d\n", Index)); + DEBUG ((EFI_D_INFO, " Start LBA : %x\n", HdDev.PartitionStart)); + DEBUG ((EFI_D_INFO, " End LBA : %x\n", PartEntry[Index].EndingLBA)); + DEBUG ((EFI_D_INFO, " Partition size: %x\n", HdDev.PartitionSize)); + DEBUG ((EFI_D_INFO, " Start : %x", MultU64x32 (PartEntry[Index].StartingLBA, BlockSize))); + DEBUG ((EFI_D_INFO, " End : %x\n", MultU64x32 (PartEntry[Index].EndingLBA, BlockSize))); + + Status = PartitionInstallChildHandle ( + This, + Handle, + DiskIo, + BlockIo, + DevicePath, + (EFI_DEVICE_PATH_PROTOCOL *) &HdDev, + PartEntry[Index].StartingLBA, + PartEntry[Index].EndingLBA, + BlockSize, + CompareGuid(&PartEntry[Index].PartitionTypeGUID, &gEfiPartTypeSystemPartGuid) + ); + } + + DEBUG ((EFI_D_INFO, "Prepare to Free Pool\n")); + +Done: + if (ProtectiveMbr != NULL) { + gBS->FreePool (ProtectiveMbr); + } + if (PrimaryHeader != NULL) { + gBS->FreePool (PrimaryHeader); + } + if (BackupHeader != NULL) { + gBS->FreePool (BackupHeader); + } + if (PartEntry != NULL) { + gBS->FreePool (PartEntry); + } + if (PEntryStatus != NULL) { + gBS->FreePool (PEntryStatus); + } + + return GptValid; +} + +BOOLEAN +PartitionValidGptTable ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN EFI_LBA Lba, + OUT EFI_PARTITION_TABLE_HEADER *PartHeader + ) +/*++ + +Routine Description: + Check if the GPT partition table is valid + +Arguments: + BlockIo - Parent BlockIo interface + DiskIo - Disk Io protocol. + Lba - The starting Lba of the Partition Table + PartHeader - Stores the partition table that is read + +Returns: + TRUE - The partition table is valid + FALSE - The partition table is not valid + +--*/ +{ + EFI_STATUS Status; + UINT32 BlockSize; + EFI_PARTITION_TABLE_HEADER *PartHdr; + + BlockSize = BlockIo->Media->BlockSize; + + PartHdr = AllocateZeroPool (BlockSize); + + if (PartHdr == NULL) { + DEBUG ((EFI_D_ERROR, "Allocate pool error\n")); + return FALSE; + } + // + // Read the EFI Partition Table Header + // + Status = BlockIo->ReadBlocks ( + BlockIo, + BlockIo->Media->MediaId, + Lba, + BlockSize, + PartHdr + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (PartHdr); + return FALSE; + } + + if (CompareMem (&PartHdr->Header.Signature, EFI_PTAB_HEADER_ID, sizeof (UINT64)) != 0 || + !PartitionCheckCrc (BlockSize, &PartHdr->Header) || + PartHdr->MyLBA != Lba + ) { + DEBUG ((EFI_D_INFO, " !Valid efi partition table header\n")); + gBS->FreePool (PartHdr); + return FALSE; + } + + CopyMem (PartHeader, PartHdr, sizeof (EFI_PARTITION_TABLE_HEADER)); + if (!PartitionCheckGptEntryArrayCRC (BlockIo, DiskIo, PartHeader)) { + gBS->FreePool (PartHdr); + return FALSE; + } + + DEBUG ((EFI_D_INFO, " Valid efi partition table header\n")); + gBS->FreePool (PartHdr); + return TRUE; +} + +BOOLEAN +PartitionCheckGptEntryArrayCRC ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN EFI_PARTITION_TABLE_HEADER *PartHeader + ) +/*++ + +Routine Description: + + Check if the CRC field in the Partition table header is valid + for Partition entry array + +Arguments: + + BlockIo - parent BlockIo interface + DiskIo - Disk Io Protocol. + PartHeader - Partition table header structure + +Returns: + + TRUE - the CRC is valid + FALSE - the CRC is invalid + +--*/ +{ + 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)) { + gBS->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")); + gBS->FreePool (Ptr); + return FALSE; + } + + gBS->FreePool (Ptr); + + return (BOOLEAN) (PartHeader->PartitionEntryArrayCRC32 == Crc); +} + +BOOLEAN +PartitionRestoreGptTable ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN EFI_PARTITION_TABLE_HEADER *PartHeader + ) +/*++ + +Routine Description: + + Restore Partition Table to its alternate place + (Primary -> Backup or Backup -> Primary) + +Arguments: + + BlockIo - parent BlockIo interface + DiskIo - Disk Io Protocol. + PartHeader - the source Partition table header structure + +Returns: + + TRUE - Restoring succeeds + FALSE - Restoring failed + +--*/ +{ + EFI_STATUS Status; + UINTN BlockSize; + EFI_PARTITION_TABLE_HEADER *PartHdr; + EFI_LBA PEntryLBA; + UINT8 *Ptr; + + PartHdr = NULL; + Ptr = NULL; + + BlockSize = BlockIo->Media->BlockSize; + + 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 = BlockIo->WriteBlocks (BlockIo, BlockIo->Media->MediaId, PartHdr->MyLBA, BlockSize, PartHdr); + if (EFI_ERROR (Status)) { + goto Done; + } + + Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry); + if (Ptr == NULL) { + DEBUG ((EFI_D_ERROR, " Allocate pool effor\n")); + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + Status = DiskIo->ReadDisk ( + DiskIo, + BlockIo->Media->MediaId, + MultU64x32(PartHeader->PartitionEntryLBA, BlockIo->Media->BlockSize), + PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry, + Ptr + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = DiskIo->WriteDisk ( + DiskIo, + BlockIo->Media->MediaId, + MultU64x32(PEntryLBA, BlockIo->Media->BlockSize), + PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry, + Ptr + ); + +Done: + gBS->FreePool (PartHdr); + gBS->FreePool (Ptr); + + if (EFI_ERROR (Status)) { + return FALSE; + } + + return TRUE; +} + +VOID +PartitionCheckGptEntry ( + IN EFI_PARTITION_TABLE_HEADER *PartHeader, + IN EFI_PARTITION_ENTRY *PartEntry, + OUT EFI_PARTITION_ENTRY_STATUS *PEntryStatus + ) +/*++ + +Routine Description: + + Check each partition entry for its range + +Arguments: + + PartHeader - the partition table header + PartEntry - the partition entry array + PEntryStatus - the partition entry status array recording the status of + each partition + +Returns: + VOID + +--*/ +{ + EFI_LBA StartingLBA; + EFI_LBA EndingLBA; + UINTN Index1; + UINTN Index2; + + DEBUG ((EFI_D_INFO, " start check partition entries\n")); + for (Index1 = 0; Index1 < PartHeader->NumberOfPartitionEntries; Index1++) { + if (CompareGuid (&PartEntry[Index1].PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) { + continue; + } + + StartingLBA = PartEntry[Index1].StartingLBA; + EndingLBA = PartEntry[Index1].EndingLBA; + if (StartingLBA > EndingLBA || + StartingLBA < PartHeader->FirstUsableLBA || + StartingLBA > PartHeader->LastUsableLBA || + EndingLBA < PartHeader->FirstUsableLBA || + EndingLBA > PartHeader->LastUsableLBA + ) { + PEntryStatus[Index1].OutOfRange = TRUE; + continue; + } + + for (Index2 = Index1 + 1; Index2 < PartHeader->NumberOfPartitionEntries; Index2++) { + + if (CompareGuid (&PartEntry[Index2].PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) { + continue; + } + + if (PartEntry[Index2].EndingLBA >= StartingLBA && PartEntry[Index2].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")); +} + +VOID +PartitionSetCrc ( + IN OUT EFI_TABLE_HEADER *Hdr + ) +/*++ + +Routine Description: + + Updates the CRC32 value in the table header + +Arguments: + + Hdr - The table to update + +Returns: + + None + +--*/ +{ + PartitionSetCrcAltSize (Hdr->HeaderSize, Hdr); +} + +VOID +PartitionSetCrcAltSize ( + IN UINTN Size, + IN OUT EFI_TABLE_HEADER *Hdr + ) +/*++ + +Routine Description: + + Updates the CRC32 value in the table header + +Arguments: + + Size - The size of the table + Hdr - The table to update + +Returns: + + None + +--*/ +{ + UINT32 Crc; + + Hdr->CRC32 = 0; + gBS->CalculateCrc32 ((UINT8 *) Hdr, Size, &Crc); + Hdr->CRC32 = Crc; +} + +BOOLEAN +PartitionCheckCrc ( + IN UINTN MaxSize, + IN OUT EFI_TABLE_HEADER *Hdr + ) +/*++ + +Routine Description: + + Checks the CRC32 value in the table header + +Arguments: + + MaxSize - Max Size limit + Hdr - The table to check + +Returns: + + TRUE if the CRC is OK in the table + +--*/ +{ + return PartitionCheckCrcAltSize (MaxSize, Hdr->HeaderSize, Hdr); +} + +BOOLEAN +PartitionCheckCrcAltSize ( + IN UINTN MaxSize, + IN UINTN Size, + IN OUT EFI_TABLE_HEADER *Hdr + ) +/*++ + +Routine Description: + + Checks the CRC32 value in the table header + +Arguments: + + MaxSize - Max Size Limit + Size - The size of the table + Hdr - The table to check + +Returns: + + TRUE if the CRC is OK in the table + +--*/ +{ + 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 && 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 ( + if (OrgCrc != Crc) { + DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc check failed\n")); + } + ); + + return (BOOLEAN) (OrgCrc == Crc); +} diff --git a/EdkModulePkg/Universal/Disk/Partition/Dxe/Gpt.h b/EdkModulePkg/Universal/Disk/Partition/Dxe/Gpt.h new file mode 100644 index 0000000000..fbcd93db12 --- /dev/null +++ b/EdkModulePkg/Universal/Disk/Partition/Dxe/Gpt.h @@ -0,0 +1,76 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Gpt.h + +Abstract: + + Data Structures required for detecting GPT Partitions + +Revision History + +--*/ + +#ifndef _GPT_H_ +#define _GPT_H_ + +#pragma pack(1) + +#define PRIMARY_PART_HEADER_LBA 1 + +#define EFI_PTAB_HEADER_ID "EFI PART" + +// +// EFI Partition Attributes +// +#define EFI_PART_REQUIRED_TO_FUNCTION 0x0000000000000001 + +// +// GPT Partition Table Header +// +typedef struct { + EFI_TABLE_HEADER Header; + EFI_LBA MyLBA; + EFI_LBA AlternateLBA; + EFI_LBA FirstUsableLBA; + EFI_LBA LastUsableLBA; + EFI_GUID DiskGUID; + EFI_LBA PartitionEntryLBA; + UINT32 NumberOfPartitionEntries; + UINT32 SizeOfPartitionEntry; + UINT32 PartitionEntryArrayCRC32; +} EFI_PARTITION_TABLE_HEADER; + +// +// GPT Partition Entry +// +typedef struct { + EFI_GUID PartitionTypeGUID; + EFI_GUID UniquePartitionGUID; + EFI_LBA StartingLBA; + EFI_LBA EndingLBA; + UINT64 Attributes; + CHAR16 PartitionName[36]; +} EFI_PARTITION_ENTRY; + +// +// GPT Partition Entry Status +// +typedef struct { + BOOLEAN OutOfRange; + BOOLEAN Overlap; +} EFI_PARTITION_ENTRY_STATUS; + +#pragma pack() + +#endif diff --git a/EdkModulePkg/Universal/Disk/Partition/Dxe/Mbr.c b/EdkModulePkg/Universal/Disk/Partition/Dxe/Mbr.c new file mode 100644 index 0000000000..07e3cbe459 --- /dev/null +++ b/EdkModulePkg/Universal/Disk/Partition/Dxe/Mbr.c @@ -0,0 +1,317 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Mbr.c + +Abstract: + + 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 - Boot(?) 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. + +--*/ + +#include "Partition.h" +#include "Mbr.h" + +BOOLEAN +PartitionValidMbr ( + IN MASTER_BOOT_RECORD *Mbr, + IN EFI_LBA LastLba + ) +/*++ + +Routine Description: + Test to see if the Mbr buffer is a valid MBR + +Arguments: + Mbr - Parent Handle + LastLba - Last Lba address on the device. + +Returns: + TRUE - Mbr is a Valid MBR + FALSE - Mbr is not a Valid MBR + +--*/ +{ + 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 + // + 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; + } + } + } + // + // Non of the regions overlapped so MBR is O.K. + // + return MbrValid; +} + +BOOLEAN +PartitionInstallMbrChildHandles ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +/*++ + +Routine Description: + Install child handles if the Handle supports MBR format. + +Arguments: + This - Calling context. + Handle - Parent Handle + DiskIo - Parent DiskIo interface + BlockIo - Parent BlockIo interface + DevicePath - Parent Device Path + +Returns: + EFI_SUCCESS - If a child handle was added + other - A child handle was not added + +--*/ +{ + EFI_STATUS Status; + MASTER_BOOT_RECORD *Mbr; + UINT32 ExtMbrStartingLba; + UINTN Index; + HARDDRIVE_DEVICE_PATH HdDev; + HARDDRIVE_DEVICE_PATH ParentHdDev; + BOOLEAN Found; + UINT32 PartitionNumber; + EFI_DEVICE_PATH_PROTOCOL *DevicePathNode; + EFI_DEVICE_PATH_PROTOCOL *LastDevicePathNode; + + Mbr = NULL; + Found = FALSE; + + Mbr = AllocatePool (BlockIo->Media->BlockSize); + if (Mbr == NULL) { + goto Done; + } + + Status = BlockIo->ReadBlocks ( + BlockIo, + BlockIo->Media->MediaId, + 0, + BlockIo->Media->BlockSize, + Mbr + ); + if (EFI_ERROR (Status) || !PartitionValidMbr (Mbr, BlockIo->Media->LastBlock)) { + 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 (!EfiIsDevicePathEnd (DevicePathNode)) { + LastDevicePathNode = DevicePathNode; + DevicePathNode = EfiNextDevicePathNode (DevicePathNode); + } + + if (LastDevicePathNode != NULL) { + if (DevicePathType (LastDevicePathNode) == MEDIA_DEVICE_PATH && + DevicePathSubType (LastDevicePathNode) == MEDIA_HARDDRIVE_DP + ) { + gBS->CopyMem (&ParentHdDev, LastDevicePathNode, sizeof (ParentHdDev)); + } else { + LastDevicePathNode = NULL; + } + } + + PartitionNumber = 1; + + 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 == 0xEE) { + // + // 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 = PartitionNumber ++; + HdDev.PartitionStart = UNPACK_UINT32 (Mbr->Partition[Index].StartingLBA); + HdDev.PartitionSize = UNPACK_UINT32 (Mbr->Partition[Index].SizeInLBA); + CopyMem (HdDev.Signature, &(Mbr->UniqueMbrSignature[0]), sizeof (UINT32)); + + Status = PartitionInstallChildHandle ( + This, + Handle, + DiskIo, + BlockIo, + DevicePath, + (EFI_DEVICE_PATH_PROTOCOL *) &HdDev, + HdDev.PartitionStart, + HdDev.PartitionStart + HdDev.PartitionSize - 1, + MBR_SIZE, + (BOOLEAN) (Mbr->Partition[Index].OSIndicator == EFI_PARTITION) + ); + + if (!EFI_ERROR (Status)) { + Found = TRUE; + } + } + } else { + // + // It's an extended partition. Follow the extended partition + // chain to get all the logical drives + // + ExtMbrStartingLba = 0; + + do { + + Status = BlockIo->ReadBlocks ( + BlockIo, + BlockIo->Media->MediaId, + ExtMbrStartingLba, + BlockIo->Media->BlockSize, + Mbr + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (Mbr->Partition[0].OSIndicator == 0) { + break; + } + + HdDev.PartitionNumber = PartitionNumber ++; + 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) { + break; + } + + // + // The signature in EBR(Extended Boot Record) should always be 0. + // + *((UINT32 *) &HdDev.Signature[0]) = 0; + + Status = PartitionInstallChildHandle ( + This, + Handle, + DiskIo, + BlockIo, + DevicePath, + (EFI_DEVICE_PATH_PROTOCOL *) &HdDev, + HdDev.PartitionStart - ParentHdDev.PartitionStart, + HdDev.PartitionStart - ParentHdDev.PartitionStart + HdDev.PartitionSize - 1, + MBR_SIZE, + (BOOLEAN) (Mbr->Partition[0].OSIndicator == EFI_PARTITION) + ); + if (!EFI_ERROR (Status)) { + Found = TRUE; + } + + 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: + gBS->FreePool (Mbr); + + return Found; +} diff --git a/EdkModulePkg/Universal/Disk/Partition/Dxe/Mbr.h b/EdkModulePkg/Universal/Disk/Partition/Dxe/Mbr.h new file mode 100644 index 0000000000..c0022c88ad --- /dev/null +++ b/EdkModulePkg/Universal/Disk/Partition/Dxe/Mbr.h @@ -0,0 +1,68 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Mbr.h + +Abstract: + + Data Structures required for detecting MBR Partitions + +Revision History + +--*/ + +#ifndef _MBR_H_ +#define _MBR_H_ + +#pragma pack(1) + +#define MBR_SIGNATURE 0xaa55 +#define MIN_MBR_DEVICE_SIZE 0x80000 +#define MBR_ERRATA_PAD 0x40000 // 128 MB +#define EXTENDED_DOS_PARTITION 0x05 +#define EXTENDED_WINDOWS_PARTITION 0x0F +#define MAX_MBR_PARTITIONS 4 + +#define EFI_PARTITION 0xef +#define MBR_SIZE 512 + +// +// MBR Partition Entry +// +typedef struct { + UINT8 BootIndicator; + UINT8 StartHead; + UINT8 StartSector; + UINT8 StartTrack; + UINT8 OSIndicator; + UINT8 EndHead; + UINT8 EndSector; + UINT8 EndTrack; + UINT8 StartingLBA[4]; + UINT8 SizeInLBA[4]; +} MBR_PARTITION_RECORD; + +// +// MBR Partition table +// +typedef struct { + UINT8 BootStrapCode[440]; + UINT8 UniqueMbrSignature[4]; + UINT8 Unknown[2]; + MBR_PARTITION_RECORD Partition[MAX_MBR_PARTITIONS]; + UINT16 Signature; +} MASTER_BOOT_RECORD; + +#pragma pack() + +#endif diff --git a/EdkModulePkg/Universal/Disk/Partition/Dxe/Partition.c b/EdkModulePkg/Universal/Disk/Partition/Dxe/Partition.c new file mode 100644 index 0000000000..59e33b27c1 --- /dev/null +++ b/EdkModulePkg/Universal/Disk/Partition/Dxe/Partition.c @@ -0,0 +1,735 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Partition.c + +Abstract: + + 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", Legacy + MBR, and GPT partition schemes are supported. + +--*/ + +#include "Partition.h" + +// +// Function Prototypes +// +EFI_STATUS +EFIAPI +PartitionEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +EFI_STATUS +EFIAPI +PartitionDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +PartitionDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +PartitionDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +// +// Partition Driver Global Variables +// +EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding = { + PartitionDriverBindingSupported, + PartitionDriverBindingStart, + PartitionDriverBindingStop, + 0x10, + NULL, + NULL +}; + +EFI_STATUS +EFIAPI +PartitionDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + Test to see if this driver supports ControllerHandle. Any ControllerHandle + than contains a BlockIo and DiskIo protocol can be supported. + + Arguments: + This - Protocol instance pointer. + ControllerHandle - Handle of device to test + RemainingDevicePath - Not used + + Returns: + EFI_SUCCESS - This driver supports this device + EFI_ALREADY_STARTED - This driver is already running on this device + EFI_UNSUPPORTED - This driver does not support this device + +--*/ +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_DISK_IO_PROTOCOL *DiskIo; + EFI_DEV_PATH *Node; + + if (RemainingDevicePath != NULL) { + 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, + &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 the I/O Abstraction(s) used to perform the supported test + // + gBS->CloseProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + + // + // 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 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; +} + +EFI_STATUS +EFIAPI +PartitionDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + 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. + + Arguments: + This - Protocol instance pointer. + ControllerHandle - Handle of device to bind driver to + RemainingDevicePath - Not used + + Returns: + EFI_SUCCESS - This driver is added to DeviceHandle + EFI_ALREADY_STARTED - This driver is already running on DeviceHandle + other - This driver does not support this device + +--*/ +{ + EFI_STATUS Status; + EFI_STATUS OpenStatus; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + EFI_DISK_IO_PROTOCOL *DiskIo; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiBlockIoProtocolGuid, + (VOID **) &BlockIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // 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) { + return Status; + } + + 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 + ); + return Status; + } + + OpenStatus = Status; + + // + // If no media is present, do nothing here. + // + Status = EFI_UNSUPPORTED; + if (BlockIo->Media->MediaPresent) { + // + // Try for GPT, then El Torito, and then legacy MBR partition types. If the + // media supports a given partition type install child handles to represent + // the partitions described by the media. + // + if (PartitionInstallGptChildHandles ( + This, + ControllerHandle, + DiskIo, + BlockIo, + ParentDevicePath + ) || + + PartitionInstallElToritoChildHandles ( + This, + ControllerHandle, + DiskIo, + BlockIo, + ParentDevicePath + ) || + + PartitionInstallMbrChildHandles ( + This, + ControllerHandle, + DiskIo, + BlockIo, + ParentDevicePath + )) { + Status = EFI_SUCCESS; + } else { + Status = EFI_NOT_FOUND; + } + } + // + // 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. + // + if (EFI_ERROR (Status) && !EFI_ERROR (OpenStatus)) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiDiskIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + + gBS->CloseProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + } + + return Status; +} + +EFI_STATUS +EFIAPI +PartitionDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + + Routine Description: + Stop this driver on ControllerHandle. Support stoping any child handles + created by this driver. + + Arguments: + This - Protocol instance pointer. + ControllerHandle - Handle of device to stop driver on + NumberOfChildren - Number of Children in the ChildHandleBuffer + ChildHandleBuffer - List of handles for the children we need to stop. + + Returns: + EFI_SUCCESS - This driver is removed DeviceHandle + EFI_DEVICE_ERROR - This driver was not removed from this device + +--*/ +{ + EFI_STATUS Status; + UINTN Index; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + BOOLEAN AllChildrenStopped; + PARTITION_PRIVATE_DATA *Private; + EFI_DISK_IO_PROTOCOL *DiskIo; + + if (NumberOfChildren == 0) { + // + // Close the bus driver + // + gBS->CloseProtocol ( + ControllerHandle, + &gEfiDiskIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + + gBS->CloseProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + + return EFI_SUCCESS; + } + + AllChildrenStopped = TRUE; + for (Index = 0; Index < NumberOfChildren; Index++) { + Status = gBS->OpenProtocol ( + ChildHandleBuffer[Index], + &gEfiBlockIoProtocolGuid, + (VOID **) &BlockIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + + Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo); + + // + // All Software protocols have be freed from the handle so remove it. + // + BlockIo->FlushBlocks (BlockIo); + + Status = gBS->CloseProtocol ( + ControllerHandle, + &gEfiDiskIoProtocolGuid, + This->DriverBindingHandle, + ChildHandleBuffer[Index] + ); + + Status = gBS->UninstallMultipleProtocolInterfaces ( + ChildHandleBuffer[Index], + &gEfiDevicePathProtocolGuid, + Private->DevicePath, + &gEfiBlockIoProtocolGuid, + &Private->BlockIo, + Private->EspGuid, + NULL, + NULL + ); + if (EFI_ERROR (Status)) { + gBS->OpenProtocol ( + ControllerHandle, + &gEfiDiskIoProtocolGuid, + (VOID **) &DiskIo, + This->DriverBindingHandle, + ChildHandleBuffer[Index], + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + } else { + gBS->FreePool (Private->DevicePath); + gBS->FreePool (Private); + } + + } + + if (EFI_ERROR (Status)) { + AllChildrenStopped = FALSE; + } + } + + if (!AllChildrenStopped) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PartitionReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + + Routine Description: + Reset the parent Block Device. + + Arguments: + This - Protocol instance pointer. + ExtendedVerification - Driver may perform diagnostics on reset. + + Returns: + EFI_SUCCESS - The device was reset. + EFI_DEVICE_ERROR - The device is not functioning properly and could + not be reset. + +--*/ +{ + PARTITION_PRIVATE_DATA *Private; + + Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This); + + return Private->ParentBlockIo->Reset ( + Private->ParentBlockIo, + ExtendedVerification + ); +} + +EFI_STATUS +EFIAPI +PartitionReadBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +/*++ + + Routine Description: + Read by using the Disk IO protocol on the parent device. Lba addresses + must be converted to byte offsets. + + Arguments: + This - Protocol instance pointer. + MediaId - Id of the media, changes every time the media is replaced. + Lba - The starting Logical Block Address to read from + BufferSize - Size of Buffer, must be a multiple of device block size. + Buffer - Buffer containing read data + + Returns: + EFI_SUCCESS - The data was read correctly from the device. + EFI_DEVICE_ERROR - The device reported an error while performing the read. + EFI_NO_MEDIA - There is no media in the device. + EFI_MEDIA_CHANGED - The MediaId does not matched the current device. + EFI_BAD_BUFFER_SIZE - The Buffer was not a multiple of the block size of the + device. + EFI_INVALID_PARAMETER - The read request contains device addresses that are not + valid for the device. + +--*/ +{ + PARTITION_PRIVATE_DATA *Private; + UINT64 Offset; + + Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This); + + if (BufferSize % Private->BlockSize != 0) { + return EFI_BAD_BUFFER_SIZE; + } + + Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start; + if (Offset + BufferSize > Private->End) { + return 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); +} + +EFI_STATUS +EFIAPI +PartitionWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +/*++ + + Routine Description: + Write by using the Disk IO protocol on the parent device. Lba addresses + must be converted to byte offsets. + + Arguments: + This - Protocol instance pointer. + MediaId - Id of the media, changes every time the media is replaced. + Lba - The starting Logical Block Address to read from + BufferSize - Size of Buffer, must be a multiple of device block size. + Buffer - Buffer containing read data + + Returns: + EFI_SUCCESS - The data was written correctly to the device. + EFI_WRITE_PROTECTED - The device can not be written to. + EFI_DEVICE_ERROR - The device reported an error while performing the write. + EFI_NO_MEDIA - There is no media in the device. + EFI_MEDIA_CHNAGED - The MediaId does not matched the current device. + EFI_BAD_BUFFER_SIZE - The Buffer was not a multiple of the block size of the + device. + EFI_INVALID_PARAMETER - The write request contains a LBA that is not + valid for the device. + +--*/ +{ + PARTITION_PRIVATE_DATA *Private; + UINT64 Offset; + + Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This); + + if (BufferSize % Private->BlockSize != 0) { + return EFI_BAD_BUFFER_SIZE; + } + + Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start; + if (Offset + BufferSize > Private->End) { + return 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); +} + +EFI_STATUS +EFIAPI +PartitionFlushBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This + ) +/*++ + + Routine Description: + Flush the parent Block Device. + + Arguments: + This - Protocol instance pointer. + + Returns: + EFI_SUCCESS - All outstanding data was written to the device + EFI_DEVICE_ERROR - The device reported an error while writing back the data + EFI_NO_MEDIA - There is no media in the device. + +--*/ +{ + PARTITION_PRIVATE_DATA *Private; + + Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This); + + return Private->ParentBlockIo->FlushBlocks (Private->ParentBlockIo); +} + +EFI_STATUS +PartitionInstallChildHandle ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ParentHandle, + IN EFI_DISK_IO_PROTOCOL *ParentDiskIo, + IN EFI_BLOCK_IO_PROTOCOL *ParentBlockIo, + IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN EFI_LBA Start, + IN EFI_LBA End, + IN UINT32 BlockSize, + IN BOOLEAN InstallEspGuid + ) +/*++ + +Routine Description: + Create a child handle for a logical block device that represents the + bytes Start to End of the Parent Block IO device. + +Arguments: + This - Calling context. + ParentHandle - Parent Handle for new child + ParentDiskIo - Parent DiskIo interface + ParentBlockIo - Parent BlockIo interface + ParentDevicePath - Parent Device Path + DevicePathNode - Child Device Path node + Start - Start Block + End - End Block + BlockSize - Child block size + InstallEspGuid - Flag to install EFI System Partition GUID on handle + +Returns: + EFI_SUCCESS - If a child handle was added + EFI_OUT_OF_RESOURCES - A child handle was not added + +--*/ +{ + EFI_STATUS Status; + PARTITION_PRIVATE_DATA *Private; + + Private = AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA)); + if (Private == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Private->Signature = PARTITION_PRIVATE_DATA_SIGNATURE; + + Private->Start = MultU64x32 (Start, ParentBlockIo->Media->BlockSize); + Private->End = MultU64x32 (End + 1, ParentBlockIo->Media->BlockSize); + + Private->BlockSize = BlockSize; + Private->ParentBlockIo = ParentBlockIo; + Private->DiskIo = ParentDiskIo; + + Private->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION; + + Private->BlockIo.Media = &Private->Media; + CopyMem (Private->BlockIo.Media, ParentBlockIo->Media, sizeof (EFI_BLOCK_IO_MEDIA)); + Private->Media.LogicalPartition = TRUE; + Private->Media.LastBlock = DivU64x32 ( + MultU64x32 ( + End - Start + 1, + ParentBlockIo->Media->BlockSize + ), + BlockSize + ) - 1; + + Private->Media.BlockSize = (UINT32) BlockSize; + + Private->BlockIo.Reset = PartitionReset; + Private->BlockIo.ReadBlocks = PartitionReadBlocks; + Private->BlockIo.WriteBlocks = PartitionWriteBlocks; + Private->BlockIo.FlushBlocks = PartitionFlushBlocks; + + Private->DevicePath = AppendDevicePathNode (ParentDevicePath, DevicePathNode); + + if (Private->DevicePath == NULL) { + gBS->FreePool (Private); + return EFI_OUT_OF_RESOURCES; + } + + if (InstallEspGuid) { + Private->EspGuid = &gEfiPartTypeSystemPartGuid; + } else { + // + // If NULL InstallMultipleProtocolInterfaces will ignore it. + // + Private->EspGuid = NULL; + } + // + // Create the new handle + // + Private->Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &Private->Handle, + &gEfiDevicePathProtocolGuid, + Private->DevicePath, + &gEfiBlockIoProtocolGuid, + &Private->BlockIo, + Private->EspGuid, + 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 { + gBS->FreePool (Private->DevicePath); + gBS->FreePool (Private); + } + + return Status; +} diff --git a/EdkModulePkg/Universal/Disk/Partition/Dxe/Partition.h b/EdkModulePkg/Universal/Disk/Partition/Dxe/Partition.h new file mode 100644 index 0000000000..de6fbf12ef --- /dev/null +++ b/EdkModulePkg/Universal/Disk/Partition/Dxe/Partition.h @@ -0,0 +1,123 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Partition.h + +Abstract: + + 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", Legacy + MBR, and GPT partition schemes are supported. + +Revision History + +--*/ + +#ifndef __PARTITION_H__ +#define __PARTITION_H__ + + + +// +// Partition private data +// +#define PARTITION_PRIVATE_DATA_SIGNATURE EFI_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_IO_MEDIA Media; + + EFI_DISK_IO_PROTOCOL *DiskIo; + EFI_BLOCK_IO_PROTOCOL *ParentBlockIo; + UINT64 Start; + UINT64 End; + UINT32 BlockSize; + + EFI_GUID *EspGuid; + +} PARTITION_PRIVATE_DATA; + +#define PARTITION_DEVICE_FROM_BLOCK_IO_THIS(a) CR (a, PARTITION_PRIVATE_DATA, BlockIo, PARTITION_PRIVATE_DATA_SIGNATURE) + +// +// Global Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gPartitionComponentName; + +// +// 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) ) + +EFI_STATUS +PartitionInstallChildHandle ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ParentHandle, + IN EFI_DISK_IO_PROTOCOL *ParentDiskIo, + IN EFI_BLOCK_IO_PROTOCOL *ParentBlockIo, + IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN UINT64 Start, + IN UINT64 End, + IN UINT32 BlockSize, + IN BOOLEAN InstallEspGuid + ) +; + +BOOLEAN +PartitionInstallGptChildHandles ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +; + +BOOLEAN +PartitionInstallElToritoChildHandles ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +; + +BOOLEAN +PartitionInstallMbrChildHandles ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +; + +#endif diff --git a/EdkModulePkg/Universal/Disk/Partition/Dxe/Partition.mbd b/EdkModulePkg/Universal/Disk/Partition/Dxe/Partition.mbd new file mode 100644 index 0000000000..7be0d52c92 --- /dev/null +++ b/EdkModulePkg/Universal/Disk/Partition/Dxe/Partition.mbd @@ -0,0 +1,42 @@ + + + + + Partition + 1FA1F39E-FEFF-4aae-BD7B-38A070A3B609 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + + UefiBootServicesTableLib + BaseLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeMemoryAllocationLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + UefiDevicePathLib + + diff --git a/EdkModulePkg/Universal/Disk/Partition/Dxe/Partition.msa b/EdkModulePkg/Universal/Disk/Partition/Dxe/Partition.msa new file mode 100644 index 0000000000..a4eed02ef1 --- /dev/null +++ b/EdkModulePkg/Universal/Disk/Partition/Dxe/Partition.msa @@ -0,0 +1,81 @@ + + + + + Partition + UEFI_DRIVER + BS_DRIVER + 1FA1F39E-FEFF-4aae-BD7B-38A070A3B609 + 0 + Component description file for Partition module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + BaseLib + UefiLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + DevicePathLib + + + Partition.h + ElTorito.h + Gpt.h + Mbr.h + Partition.c + Eltorito.c + Gpt.c + Mbr.c + ComponentName.c + + + MdePkg + + + BlockIo + DiskIo + DevicePath + + + + PartTypeSystemPart + + + PartTypeUnused + + + + + + + + gPartitionDriverBinding + gPartitionComponentName + + + diff --git a/EdkModulePkg/Universal/Disk/Partition/Dxe/build.xml b/EdkModulePkg/Universal/Disk/Partition/Dxe/build.xml new file mode 100644 index 0000000000..ea4ea4e1ed --- /dev/null +++ b/EdkModulePkg/Universal/Disk/Partition/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Universal/Disk/UnicodeCollation/English/Dxe/English.mbd b/EdkModulePkg/Universal/Disk/UnicodeCollation/English/Dxe/English.mbd new file mode 100644 index 0000000000..46b51cffdd --- /dev/null +++ b/EdkModulePkg/Universal/Disk/UnicodeCollation/English/Dxe/English.mbd @@ -0,0 +1,38 @@ + + + + + English + CD3BAFB6-50FB-4fe8-8E4E-AB74D2C1A600 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + + UefiBootServicesTableLib + BaseLib + UefiMemoryLib + UefiDriverEntryPoint + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + + diff --git a/EdkModulePkg/Universal/Disk/UnicodeCollation/English/Dxe/English.msa b/EdkModulePkg/Universal/Disk/UnicodeCollation/English/Dxe/English.msa new file mode 100644 index 0000000000..9abe3284ad --- /dev/null +++ b/EdkModulePkg/Universal/Disk/UnicodeCollation/English/Dxe/English.msa @@ -0,0 +1,53 @@ + + + + + English + UEFI_DRIVER + BS_DRIVER + CD3BAFB6-50FB-4fe8-8E4E-AB74D2C1A600 + 0 + Component description file for English module for unicode collation. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + DebugLib + UefiDriverEntryPoint + UefiBootServicesTableLib + + + UnicodeCollationEng.c + + + MdePkg + + + UnicodeCollation + + + + InitializeUnicodeCollationEng + + + diff --git a/EdkModulePkg/Universal/Disk/UnicodeCollation/English/Dxe/UnicodeCollationEng.c b/EdkModulePkg/Universal/Disk/UnicodeCollation/English/Dxe/UnicodeCollationEng.c new file mode 100644 index 0000000000..f043f37a5c --- /dev/null +++ b/EdkModulePkg/Universal/Disk/UnicodeCollation/English/Dxe/UnicodeCollationEng.c @@ -0,0 +1,478 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + UnicodeCollationEng.c + +Abstract: + + Unicode Collation Protocol (English) + +Revision History + +--*/ + +#include "UnicodeCollationEng.h" + +CHAR8 mEngUpperMap[0x100]; +CHAR8 mEngLowerMap[0x100]; +CHAR8 mEngInfoMap[0x100]; + +CHAR8 mOtherChars[] = { + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '\\', + '.', + '_', + '^', + '$', + '~', + '!', + '#', + '%', + '&', + '-', + '{', + '}', + '(', + ')', + '@', + '`', + '\'', + '\0' +}; + +EFI_HANDLE mHandle = NULL; + +EFI_UNICODE_COLLATION_PROTOCOL UnicodeEng = { + EngStriColl, + EngMetaiMatch, + EngStrLwr, + EngStrUpr, + EngFatToStr, + EngStrToFat, + "eng" +}; + +// +// +// +EFI_STATUS +InitializeUnicodeCollationEng ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Initializes the Unicode Collation Driver + +Arguments: + + ImageHandle - + + SystemTable - + +Returns: + + EFI_SUCCESS + EFI_OUT_OF_RESOURCES + +--*/ +{ + UINTN Index; + UINTN Index2; + + // + // Initialize mapping tables for the supported languages + // + for (Index = 0; Index < 0x100; 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]; Index++) { + Index2 = mOtherChars[Index]; + mEngInfoMap[Index2] |= CHAR_FAT_VALID; + } + // + // Create a handle for the device + // + return gBS->InstallProtocolInterface ( + &mHandle, + &gEfiUnicodeCollationProtocolGuid, + EFI_NATIVE_INTERFACE, + &UnicodeEng + ); +} + +INTN +EFIAPI +EngStriColl ( + IN EFI_UNICODE_COLLATION_PROTOCOL *This, + IN CHAR16 *s1, + IN CHAR16 *s2 + ) +/*++ + +Routine Description: + + Performs a case-insensitive comparison of two Null-terminated Unicode strings. + +Arguments: + + This + s1 + s2 + +Returns: + +--*/ +{ + while (*s1) { + if (ToUpper (*s1) != ToUpper (*s2)) { + break; + } + + s1 += 1; + s2 += 1; + } + + return ToUpper (*s1) - ToUpper (*s2); +} + +VOID +EFIAPI +EngStrLwr ( + IN EFI_UNICODE_COLLATION_PROTOCOL *This, + IN OUT CHAR16 *Str + ) +/*++ + +Routine Description: + + Converts all the Unicode characters in a Null-terminated Unicode string + to lower case Unicode characters. + +Arguments: + + This - A pointer to the EFI_UNICODE_COLLATION_PROTOCOL instance. + Str1 - A pointer to a Null-terminated Unicode string. + Str2 - A pointer to a Null-terminated Unicode string. + +Returns: + + 0 - s1 is equivalent to s2. + > 0 - s1 is lexically greater than s2. + < 0 - s1 is lexically less than s2. + +--*/ +{ + while (*Str) { + *Str = ToLower (*Str); + Str += 1; + } +} + +VOID +EFIAPI +EngStrUpr ( + IN EFI_UNICODE_COLLATION_PROTOCOL *This, + IN OUT CHAR16 *Str + ) +/*++ + +Routine Description: + + Converts all the Unicode characters in a Null-terminated + Unicode string to upper case Unicode characters. + +Arguments: + This + Str + +Returns: + None + +--*/ +{ + while (*Str) { + *Str = ToUpper (*Str); + Str += 1; + } +} + +BOOLEAN +EFIAPI +EngMetaiMatch ( + IN EFI_UNICODE_COLLATION_PROTOCOL *This, + IN CHAR16 *String, + IN CHAR16 *Pattern + ) +/*++ + +Routine Description: + + Performs a case-insensitive comparison between a Null-terminated + Unicode pattern string and a Null-terminated Unicode string. + + The pattern string can use the '?' wildcard to match any character, + and the '*' wildcard to match any sub-string. + +Arguments: + + This - A pointer to the EFI_UNICODE_COLLATION_PROTOCOL instance. + String - A pointer to a Null-terminated Unicode string. + Pattern - A pointer to a Null-terminated Unicode pattern string. + +Returns: + + TRUE - Pattern was found in String. + FALSE - Pattern was not found in String. + +--*/ +{ + 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) { + return FALSE; + } else { + return TRUE; + } + + case '*': + // + // Match zero or more chars + // + while (*String) { + if (EngMetaiMatch (This, String, Pattern)) { + return TRUE; + } + + String += 1; + } + + return EngMetaiMatch (This, String, Pattern); + + case '?': + // + // Match any one char + // + if (!*String) { + return FALSE; + } + + String += 1; + break; + + case '[': + // + // Match char set + // + CharC = *String; + if (!CharC) { + // + // syntax problem + // + return FALSE; + } + + Index3 = 0; + CharP = *Pattern++; + while (CharP) { + if (CharP == ']') { + return FALSE; + } + + if (CharP == '-') { + // + // if range of chars, get high range + // + CharP = *Pattern; + if (CharP == 0 || CharP == ']') { + // + // syntax problem + // + return FALSE; + } + + if (ToUpper (CharC) >= ToUpper (Index3) && ToUpper (CharC) <= ToUpper (CharP)) { + // + // if in range, it's a match + // + break; + } + } + + Index3 = CharP; + if (ToUpper (CharC) == ToUpper (CharP)) { + // + // if char matches + // + break; + } + + CharP = *Pattern++; + } + // + // skip to end of match char set + // + while (CharP && CharP != ']') { + CharP = *Pattern; + Pattern += 1; + } + + String += 1; + break; + + default: + CharC = *String; + if (ToUpper (CharC) != ToUpper (CharP)) { + return FALSE; + } + + String += 1; + break; + } + } +} + +VOID +EFIAPI +EngFatToStr ( + IN EFI_UNICODE_COLLATION_PROTOCOL *This, + IN UINTN FatSize, + IN CHAR8 *Fat, + OUT CHAR16 *String + ) +/*++ + +Routine Description: + + Converts an 8.3 FAT file name using an OEM character set + to a Null-terminated Unicode string. + + BUGBUG: Function has to expand DBCS FAT chars, currently not. + +Arguments: + This + FatSize + Fat + String + +Returns: + +--*/ +{ + // + // No DBCS issues, just expand and add null terminate to end of string + // + while (*Fat && FatSize) { + *String = *Fat; + String += 1; + Fat += 1; + FatSize -= 1; + } + + *String = 0; +} + +BOOLEAN +EFIAPI +EngStrToFat ( + IN EFI_UNICODE_COLLATION_PROTOCOL *This, + IN CHAR16 *String, + IN UINTN FatSize, + OUT CHAR8 *Fat + ) +/*++ + +Routine Description: + + Converts a Null-terminated Unicode string to legal characters + in a FAT filename using an OEM character set. + + Functions has to crunch string to a fat string. Replacing + any chars that can't be represented in the fat name. + +Arguments: + This + String + FatSize + Fat + +Returns: + TRUE + FALSE +--*/ +{ + BOOLEAN SpecialCharExist; + + SpecialCharExist = FALSE; + while (*String && FatSize) { + // + // 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 an Lfn + // + if (*String < 0x100 && (mEngInfoMap[*String] & CHAR_FAT_VALID)) { + *Fat = mEngUpperMap[*String]; + } else { + *Fat = '_'; + SpecialCharExist = TRUE; + } + + Fat += 1; + FatSize -= 1; + } + + String += 1; + } + // + // Do not terminate that fat string + // + return SpecialCharExist; +} diff --git a/EdkModulePkg/Universal/Disk/UnicodeCollation/English/Dxe/UnicodeCollationEng.h b/EdkModulePkg/Universal/Disk/UnicodeCollation/English/Dxe/UnicodeCollationEng.h new file mode 100644 index 0000000000..6bd547997f --- /dev/null +++ b/EdkModulePkg/Universal/Disk/UnicodeCollation/English/Dxe/UnicodeCollationEng.h @@ -0,0 +1,102 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + UnicodeCollationEng.h + +Abstract: + + Head file for Unicode Collation Protocol (English) + +Revision History + +--*/ + +#ifndef _UNICODE_COLLATION_ENG_H +#define _UNICODE_COLLATION_ENG_H + + + +// +// Defines +// +#define CHAR_FAT_VALID 0x01 + +#define ToUpper(a) (CHAR16) (a <= 0xFF ? mEngUpperMap[a] : a) +#define ToLower(a) (CHAR16) (a <= 0xFF ? mEngLowerMap[a] : a) + +// +// Prototypes +// +INTN +EFIAPI +EngStriColl ( + IN EFI_UNICODE_COLLATION_PROTOCOL *This, + IN CHAR16 *s1, + IN CHAR16 *s2 + ) +; + +BOOLEAN +EFIAPI +EngMetaiMatch ( + IN EFI_UNICODE_COLLATION_PROTOCOL *This, + IN CHAR16 *String, + IN CHAR16 *Pattern + ) +; + +VOID +EFIAPI +EngStrLwr ( + IN EFI_UNICODE_COLLATION_PROTOCOL *This, + IN OUT CHAR16 *Str + ) +; + +VOID +EFIAPI +EngStrUpr ( + IN EFI_UNICODE_COLLATION_PROTOCOL *This, + IN OUT CHAR16 *Str + ) +; + +VOID +EFIAPI +EngFatToStr ( + IN EFI_UNICODE_COLLATION_PROTOCOL *This, + IN UINTN FatSize, + IN CHAR8 *Fat, + OUT CHAR16 *String + ) +; + +BOOLEAN +EFIAPI +EngStrToFat ( + IN EFI_UNICODE_COLLATION_PROTOCOL *This, + IN CHAR16 *String, + IN UINTN FatSize, + OUT CHAR8 *Fat + ) +; + +EFI_STATUS +EFIAPI +InitializeUnicodeCollationEng ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +; + +#endif diff --git a/EdkModulePkg/Universal/Disk/UnicodeCollation/English/Dxe/build.xml b/EdkModulePkg/Universal/Disk/UnicodeCollation/English/Dxe/build.xml new file mode 100644 index 0000000000..81fd524667 --- /dev/null +++ b/EdkModulePkg/Universal/Disk/UnicodeCollation/English/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Universal/Ebc/Dxe/Ebc.dxs b/EdkModulePkg/Universal/Ebc/Dxe/Ebc.dxs new file mode 100644 index 0000000000..662aa1cb11 --- /dev/null +++ b/EdkModulePkg/Universal/Ebc/Dxe/Ebc.dxs @@ -0,0 +1,26 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Ebc.dxs + +Abstract: + + Dependency expression file for EBC VM. + +--*/ +#include +#include + +DEPENDENCY_START + TRUE +DEPENDENCY_END diff --git a/EdkModulePkg/Universal/Ebc/Dxe/Ebc.mbd b/EdkModulePkg/Universal/Ebc/Dxe/Ebc.mbd new file mode 100644 index 0000000000..61073596f3 --- /dev/null +++ b/EdkModulePkg/Universal/Ebc/Dxe/Ebc.mbd @@ -0,0 +1,43 @@ + + + + + Ebc + 13AC6DD0-73D0-11D4-B06B-00AA00BD6DE7 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-22 14:03 + + + UefiBootServicesTableLib + BaseLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + EdkDxePrintLib + DxeMemoryAllocationLib + + + _ModuleEntryPoint + + diff --git a/EdkModulePkg/Universal/Ebc/Dxe/Ebc.msa b/EdkModulePkg/Universal/Ebc/Dxe/Ebc.msa new file mode 100644 index 0000000000..e736450b39 --- /dev/null +++ b/EdkModulePkg/Universal/Ebc/Dxe/Ebc.msa @@ -0,0 +1,80 @@ + + + + + Ebc + DXE_DRIVER + BS_DRIVER + 13AC6DD0-73D0-11D4-B06B-00AA00BD6DE7 + 0 + Component description file for DiskIo module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-22 15:19 + + + DebugLib + UefiDriverEntryPoint + ReportStatusCodeLib + UefiLib + BaseLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + + + EbcInt.c + EbcInt.h + EbcExecute.c + EbcExecute.h + Ebc.dxs + + Ia32\EbcLowLevel.asm + Ia32\Ia32Math.asm + Ia32\EbcSupport.c + + + x64\EbcLowLevel.asm + x64\x64Math.c + x64\EbcSupport.c + + + Ipf\EbcLowLevel.s + Ipf\IpfMath.c + Ipf\IpfMul.s + Ipf\EbcSupport.c + + + + MdePkg + EdkModulePkg + + + Ebc + DebugSupport + + + + InitializeEbcDriver + + + diff --git a/EdkModulePkg/Universal/Ebc/Dxe/EbcExecute.c b/EdkModulePkg/Universal/Ebc/Dxe/EbcExecute.c new file mode 100644 index 0000000000..9d375a5461 --- /dev/null +++ b/EdkModulePkg/Universal/Ebc/Dxe/EbcExecute.c @@ -0,0 +1,4603 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + EbcExecute.c + +Abstract: + + Contains code that implements the virtual machine. + +--*/ + +#include "EbcInt.h" +#include "EbcExecute.h" + +// +// VM major/minor version +// +#define VM_MAJOR_VERSION 1 +#define VM_MINOR_VERSION 0 + +// +// 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 + ); + +STATIC +INT16 +VmReadIndex16 ( + IN VM_CONTEXT *VmPtr, + IN UINT32 CodeOffset + ); + +STATIC +INT32 +VmReadIndex32 ( + IN VM_CONTEXT *VmPtr, + IN UINT32 CodeOffset + ); + +STATIC +INT64 +VmReadIndex64 ( + IN VM_CONTEXT *VmPtr, + IN UINT32 CodeOffset + ); + +STATIC +UINT8 +VmReadMem8 ( + IN VM_CONTEXT *VmPtr, + IN UINTN Addr + ); + +STATIC +UINT16 +VmReadMem16 ( + IN VM_CONTEXT *VmPtr, + IN UINTN Addr + ); + +STATIC +UINT32 +VmReadMem32 ( + IN VM_CONTEXT *VmPtr, + IN UINTN Addr + ); + +STATIC +UINT64 +VmReadMem64 ( + IN VM_CONTEXT *VmPtr, + IN UINTN Addr + ); + +STATIC +UINTN +VmReadMemN ( + IN VM_CONTEXT *VmPtr, + IN UINTN Addr + ); + +STATIC +EFI_STATUS +VmWriteMem8 ( + IN VM_CONTEXT *VmPtr, + UINTN Addr, + IN UINT8 Data + ); + +STATIC +EFI_STATUS +VmWriteMem16 ( + IN VM_CONTEXT *VmPtr, + UINTN Addr, + IN UINT16 Data + ); + +STATIC +EFI_STATUS +VmWriteMem32 ( + IN VM_CONTEXT *VmPtr, + UINTN Addr, + IN UINT32 Data + ); + +EFI_STATUS +VmWriteMemN ( + IN VM_CONTEXT *VmPtr, + UINTN Addr, + IN UINTN Data + ); + +EFI_STATUS +VmWriteMem64 ( + IN VM_CONTEXT *VmPtr, + UINTN Addr, + IN UINT64 Data + ); + +STATIC +UINT16 +VmReadCode16 ( + IN VM_CONTEXT *VmPtr, + IN UINT32 Offset + ); + +STATIC +UINT32 +VmReadCode32 ( + IN VM_CONTEXT *VmPtr, + IN UINT32 Offset + ); + +STATIC +UINT64 +VmReadCode64 ( + IN VM_CONTEXT *VmPtr, + IN UINT32 Offset + ); + +STATIC +INT8 +VmReadImmed8 ( + IN VM_CONTEXT *VmPtr, + IN UINT32 Offset + ); + +STATIC +INT16 +VmReadImmed16 ( + IN VM_CONTEXT *VmPtr, + IN UINT32 Offset + ); + +STATIC +INT32 +VmReadImmed32 ( + IN VM_CONTEXT *VmPtr, + IN UINT32 Offset + ); + +STATIC +INT64 +VmReadImmed64 ( + IN VM_CONTEXT *VmPtr, + IN UINT32 Offset + ); + +STATIC +UINTN +ConvertStackAddr ( + IN VM_CONTEXT *VmPtr, + IN UINTN Addr + ); + +STATIC +EFI_STATUS +ExecuteDataManip ( + IN VM_CONTEXT *VmPtr, + IN BOOLEAN IsSignedOperation + ); + +// +// Functions that execute VM opcodes +// +STATIC +EFI_STATUS +ExecuteBREAK ( + IN VM_CONTEXT *VmPtr + ); + +STATIC +EFI_STATUS +ExecuteJMP ( + IN VM_CONTEXT *VmPtr + ); + +STATIC +EFI_STATUS +ExecuteJMP8 ( + IN VM_CONTEXT *VmPtr + ); + +STATIC +EFI_STATUS +ExecuteCALL ( + IN VM_CONTEXT *VmPtr + ); + +STATIC +EFI_STATUS +ExecuteRET ( + IN VM_CONTEXT *VmPtr + ); + +STATIC +EFI_STATUS +ExecuteCMP ( + IN VM_CONTEXT *VmPtr + ); + +STATIC +EFI_STATUS +ExecuteCMPI ( + IN VM_CONTEXT *VmPtr + ); + +STATIC +EFI_STATUS +ExecuteMOVxx ( + IN VM_CONTEXT *VmPtr + ); + +STATIC +EFI_STATUS +ExecuteMOVI ( + IN VM_CONTEXT *VmPtr + ); + +STATIC +EFI_STATUS +ExecuteMOVIn ( + IN VM_CONTEXT *VmPtr + ); + +STATIC +EFI_STATUS +ExecuteMOVREL ( + IN VM_CONTEXT *VmPtr + ); + +STATIC +EFI_STATUS +ExecutePUSHn ( + IN VM_CONTEXT *VmPtr + ); + +STATIC +EFI_STATUS +ExecutePUSH ( + IN VM_CONTEXT *VmPtr + ); + +STATIC +EFI_STATUS +ExecutePOPn ( + IN VM_CONTEXT *VmPtr + ); + +STATIC +EFI_STATUS +ExecutePOP ( + IN VM_CONTEXT *VmPtr + ); + +STATIC +EFI_STATUS +ExecuteSignedDataManip ( + IN VM_CONTEXT *VmPtr + ); + +STATIC +EFI_STATUS +ExecuteUnsignedDataManip ( + IN VM_CONTEXT *VmPtr + ); + +STATIC +EFI_STATUS +ExecuteLOADSP ( + IN VM_CONTEXT *VmPtr + ); + +STATIC +EFI_STATUS +ExecuteSTORESP ( + IN VM_CONTEXT *VmPtr + ); + +STATIC +EFI_STATUS +ExecuteMOVsnd ( + IN VM_CONTEXT *VmPtr + ); + +STATIC +EFI_STATUS +ExecuteMOVsnw ( + IN VM_CONTEXT *VmPtr + ); + +// +// Data manipulation subfunctions +// +STATIC +UINT64 +ExecuteNOT ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ); + +STATIC +UINT64 +ExecuteNEG ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ); + +STATIC +UINT64 +ExecuteADD ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ); + +STATIC +UINT64 +ExecuteSUB ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ); + +STATIC +UINT64 +ExecuteMUL ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ); + +STATIC +UINT64 +ExecuteMULU ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ); + +STATIC +UINT64 +ExecuteDIV ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ); + +STATIC +UINT64 +ExecuteDIVU ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ); + +STATIC +UINT64 +ExecuteMOD ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ); + +STATIC +UINT64 +ExecuteMODU ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ); + +STATIC +UINT64 +ExecuteAND ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ); + +STATIC +UINT64 +ExecuteOR ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ); + +STATIC +UINT64 +ExecuteXOR ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ); + +STATIC +UINT64 +ExecuteSHL ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ); + +STATIC +UINT64 +ExecuteSHR ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ); + +STATIC +UINT64 +ExecuteASHR ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ); + +STATIC +UINT64 +ExecuteEXTNDB ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ); + +STATIC +UINT64 +ExecuteEXTNDW ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ); + +STATIC +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. +// +static 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, +}; + +static 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 +}; + +// +// Length of JMP instructions, depending on upper two bits of opcode. +// +static CONST UINT8 mJMPLen[] = { 2, 2, 6, 10 }; + +// +// Simple Debugger Protocol GUID +// +EFI_GUID mEbcSimpleDebuggerProtocolGuid = EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL_GUID; + +EFI_STATUS +EbcExecuteInstructions ( + IN EFI_EBC_VM_TEST_PROTOCOL *This, + IN VM_CONTEXT *VmPtr, + IN OUT UINTN *InstructionCount + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + This - pointer to protocol interface + VmPtr - pointer to a VM context + InstructionCount - how many instructions to execute. 0 if don't count. + +Returns: + + EFI_UNSUPPORTED + EFI_SUCCESS + +--*/ +{ + 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 & 0x3F)].ExecuteFunction; + if (ExecFunc == (UINTN) NULL) { + EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE, EXCEPTION_FLAG_FATAL, VmPtr); + return EFI_UNSUPPORTED; + } else { + mVmOpcodeTable[(*VmPtr->Ip & 0x3F)].ExecuteFunction (VmPtr); + *InstructionCount = *InstructionCount + 1; + } + + // + // Decrement counter if applicable + // + if (SavedInstructionCount != 0) { + InstructionsLeft--; + } + } + + return Status; +} + +EFI_STATUS +EbcExecute ( + IN VM_CONTEXT *VmPtr + ) +/*++ + +Routine Description: + + Execute an EBC image from an entry point or from a published protocol. + +Arguments: + + VmPtr - pointer to prepared VM context. + +Returns: + + Standard EBC status. + +--*/ +{ + UINTN ExecFunc; + UINT8 StackCorrupted; + EFI_STATUS Status; + EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL *EbcSimpleDebugger; + + // + // end DEBUG_CODE + // + 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->R[0] + 8); + + // + // Try to get the debug support for EBC + // + DEBUG_CODE ( + Status = gBS->LocateProtocol ( + &mEbcSimpleDebuggerProtocolGuid, + NULL, + (VOID **) &EbcSimpleDebugger + ); + if (EFI_ERROR (Status)) { + EbcSimpleDebugger = NULL; + } + ); + + // + // 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)) { + // + // If we've found a simple debugger protocol, call it + // + DEBUG_CODE ( + if (EbcSimpleDebugger != NULL) { + EbcSimpleDebugger->Debugger (EbcSimpleDebugger, VmPtr); + } + ); + + // + // Verify the opcode is in range. Otherwise generate an exception. + // + if ((*VmPtr->Ip & OPCODE_M_OPCODE) >= (sizeof (mVmOpcodeTable) / sizeof (mVmOpcodeTable[0]))) { + EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE, EXCEPTION_FLAG_FATAL, VmPtr); + Status = EFI_UNSUPPORTED; + goto Done; + } + // + // 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; + } + // + // 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 (); + + // + // 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 && (*VmPtr->StackMagicPtr != (UINTN) VM_STACK_KEY_VALUE)) { + EbcDebugSignalException (EXCEPT_EBC_STACK_FAULT, EXCEPTION_FLAG_FATAL, VmPtr); + StackCorrupted = 1; + } + } + +Done: + return Status; +} + +STATIC +EFI_STATUS +ExecuteMOVxx ( + IN VM_CONTEXT *VmPtr + ) +/*++ + +Routine Description: + + Execute the MOVxx instructions. + +Arguments: + + VmPtr - pointer to a VM context. + +Returns: + + EFI_UNSUPPORTED + EFI_SUCCESS + +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. + +--*/ +{ + 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)) { + // + // 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) { + Index16 = VmReadIndex16 (VmPtr, 2); + Index64Op1 = (INT64) Index16; + Size += sizeof (UINT16); + } + + if (Opcode & OPCODE_M_IMMED_OP2) { + 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) { + Index32 = VmReadIndex32 (VmPtr, 2); + Index64Op1 = (INT64) Index32; + Size += sizeof (UINT32); + } + + if (Opcode & OPCODE_M_IMMED_OP2) { + 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) { + Index64Op1 = VmReadIndex64 (VmPtr, 2); + Size += sizeof (UINT64); + } + + if (Opcode & OPCODE_M_IMMED_OP2) { + 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->R[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 = VmPtr->R[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) { + // + // 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->R[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) { + 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->R[OPERAND1_REGNUM (Operands)] = Data64 & DataMask; + } + // + // Advance the instruction pointer + // + VmPtr->Ip += Size; + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +ExecuteBREAK ( + IN VM_CONTEXT *VmPtr + ) +/*++ + +Routine Description: + + Execute the EBC BREAK instruction + +Arguments: + + VmPtr - pointer to current VM context + +Returns: + + EFI_UNSUPPORTED + EFI_SUCCESS + +--*/ +{ + UINT8 Operands; + VOID *EbcEntryPoint; + VOID *Thunk; + EFI_STATUS Status; + UINT64 U64EbcEntryPoint; + INT32 Offset; + + 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->R[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 + ); + // + // Don't advance the IP + // + return EFI_UNSUPPORTED; + 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->R[7]); + U64EbcEntryPoint = (UINT64) (VmPtr->R[7] + Offset + 4); + EbcEntryPoint = (VOID *) (UINTN) U64EbcEntryPoint; + + // + // Now create a new thunk + // + Status = EbcCreateThunks (VmPtr->ImageHandle, EbcEntryPoint, &Thunk, 0); + + // + // Finally replace the EBC entry point memory with the thunk address + // + VmWriteMem64 (VmPtr, (UINTN) VmPtr->R[7], (UINT64) (UINTN) Thunk); + break; + + // + // Compiler setting version per value in R7 + // + case 6: + VmPtr->CompilerVersion = (UINT32) VmPtr->R[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; +} + +STATIC +EFI_STATUS +ExecuteJMP ( + IN VM_CONTEXT *VmPtr + ) +/*++ + +Routine Description: + Execute the JMP instruction + +Arguments: + VmPtr - pointer to VM context + +Returns: + Standard EFI_STATUS + +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 + +--*/ +{ + 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) ? 1 : 0); + ConditionFlag = (UINT8) VMFLAG_ISSET (VmPtr, VMFLAGS_CC); + if (Operand & CONDITION_M_CONDITIONAL) { + if (CompareSet != ConditionFlag) { + VmPtr->Ip += Size; + 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) { + // + // Double check for immediate-data, which is required. If not there, + // then signal an exception + // + if (!(Opcode & OPCODE_M_IMMDATA)) { + 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 = 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 + // + if (Operand & JMP_M_RELATIVE) { + VmPtr->Ip += (UINTN) Data64 + Size; + } else { + VmPtr->Ip = (VMIP) (UINTN) Data64; + } + + 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) { + 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 = 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; + } + + if (Operand & JMP_M_RELATIVE) { + VmPtr->Ip += (UINTN) Addr + Size; + } else { + VmPtr->Ip = (VMIP) Addr; + } + } 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; + } + + if (Operand & JMP_M_RELATIVE) { + VmPtr->Ip += (UINTN) Addr + Size; + } else { + VmPtr->Ip = (VMIP) Addr; + } + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +ExecuteJMP8 ( + IN VM_CONTEXT *VmPtr + ) +/*++ + +Routine Description: + Execute the EBC JMP8 instruction + +Arguments: + VmPtr - pointer to a VM context + +Returns: + Standard EFI_STATUS + +Instruction syntax: + JMP8{cs|cc} Offset/2 + +--*/ +{ + UINT8 Opcode; + UINT8 ConditionFlag; + UINT8 CompareSet; + INT8 Offset; + + // + // Decode instruction. + // + Opcode = GETOPCODE (VmPtr); + CompareSet = (UINT8) ((Opcode & JMP_M_CS) ? 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) { + if (CompareSet != ConditionFlag) { + VmPtr->Ip += 2; + 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? + // + VmPtr->Ip += (Offset * 2) + 2; + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +ExecuteMOVI ( + IN VM_CONTEXT *VmPtr + ) +/*++ + +Routine Description: + + Execute the EBC MOVI + +Arguments: + + VmPtr - pointer to a VM context + +Returns: + + Standard EFI_STATUS + +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. + +--*/ +{ + 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) { + 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) { + 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->R[OPERAND1_REGNUM (Operands)] = ImmData64 & Mask64; + } else { + // + // Get the address then write back based on size of the move + // + Op1 = (UINT64) VmPtr->R[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, ImmData64); + } + } + // + // Advance the instruction pointer + // + VmPtr->Ip += Size; + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +ExecuteMOVIn ( + IN VM_CONTEXT *VmPtr + ) +/*++ + +Routine Description: + + Execute the EBC MOV immediate natural. This instruction moves an immediate + index value into a register or memory location. + +Arguments: + + VmPtr - pointer to a VM context + +Returns: + + Standard EFI_STATUS + +Instruction syntax: + + MOVIn[w|d|q] {@}R1 {Index16}, Index16|32|64 + +--*/ +{ + 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) { + 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) { + EbcDebugSignalException ( + EXCEPT_EBC_INSTRUCTION_ENCODING, + EXCEPTION_FLAG_FATAL, + VmPtr + ); + return EFI_UNSUPPORTED; + } + + VmPtr->R[OPERAND1_REGNUM (Operands)] = ImmedIndex64; + } else { + // + // Get the address + // + Op1 = (UINT64) VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16; + VmWriteMemN (VmPtr, (UINTN) Op1, (INTN) ImmedIndex64); + } + // + // Advance the instruction pointer + // + VmPtr->Ip += Size; + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +ExecuteMOVREL ( + IN VM_CONTEXT *VmPtr + ) +/*++ + +Routine Description: + + Execute the EBC MOVREL instruction. + Dest <- Ip + ImmData + +Arguments: + + VmPtr - pointer to a VM context + +Returns: + + Standard EFI_STATUS + +Instruction syntax: + + MOVREL[w|d|q] {@}R1 {Index16}, ImmData16|32|64 + +--*/ +{ + 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) { + 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) { + EbcDebugSignalException ( + EXCEPT_EBC_INSTRUCTION_ENCODING, + EXCEPTION_FLAG_FATAL, + VmPtr + ); + return EFI_UNSUPPORTED; + } + + VmPtr->R[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->R[OPERAND1_REGNUM (Operands)] + Index16; + VmWriteMemN (VmPtr, (UINTN) Op1, (UINTN) Op2); + } + // + // Advance the instruction pointer + // + VmPtr->Ip += Size; + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +ExecuteMOVsnw ( + IN VM_CONTEXT *VmPtr + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + VmPtr - pointer to a VM context + +Returns: + + Standard EFI_STATUS + +Instruction syntax: + + MOVsnw {@}R1 {Index16}, {@}R2 {Index16|Immed16} + + 0:7 1=>operand1 index present + 0:6 1=>operand2 index present + +--*/ +{ + 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) { + 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) { + if (OPERAND2_INDIRECT (Operands)) { + Op2Index = VmReadIndex16 (VmPtr, Size); + } else { + Op2Index = VmReadImmed16 (VmPtr, Size); + } + + Size += sizeof (UINT16); + } + // + // Get the data from the source. + // + Op2 = (INT64) ((INTN) (VmPtr->R[OPERAND2_REGNUM (Operands)] + Op2Index)); + if (OPERAND2_INDIRECT (Operands)) { + Op2 = (INT64) (INTN) VmReadMemN (VmPtr, (UINTN) Op2); + } + // + // Now write back the result. + // + if (!OPERAND1_INDIRECT (Operands)) { + VmPtr->R[OPERAND1_REGNUM (Operands)] = Op2; + } else { + VmWriteMemN (VmPtr, (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Op1Index), (UINTN) Op2); + } + // + // Advance the instruction pointer + // + VmPtr->Ip += Size; + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +ExecuteMOVsnd ( + IN VM_CONTEXT *VmPtr + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + VmPtr - pointer to a VM context + +Returns: + + Standard EFI_STATUS + +Instruction syntax: + + MOVsnd {@}R1 {Indx32}, {@}R2 {Index32|Immed32} + + 0:7 1=>operand1 index present + 0:6 1=>operand2 index present + +--*/ +{ + 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) { + 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) { + if (OPERAND2_INDIRECT (Operands)) { + Op2Index = VmReadIndex32 (VmPtr, Size); + } else { + Op2Index = VmReadImmed32 (VmPtr, Size); + } + + Size += sizeof (UINT32); + } + // + // Get the data from the source. + // + Op2 = (INT64) ((INTN) (VmPtr->R[OPERAND2_REGNUM (Operands)] + Op2Index)); + if (OPERAND2_INDIRECT (Operands)) { + Op2 = (INT64) (INTN) VmReadMemN (VmPtr, (UINTN) Op2); + } + // + // Now write back the result. + // + if (!OPERAND1_INDIRECT (Operands)) { + VmPtr->R[OPERAND1_REGNUM (Operands)] = Op2; + } else { + VmWriteMemN (VmPtr, (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Op1Index), (UINTN) Op2); + } + // + // Advance the instruction pointer + // + VmPtr->Ip += Size; + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +ExecutePUSHn ( + IN VM_CONTEXT *VmPtr + ) +/*++ + +Routine Description: + Execute the EBC PUSHn instruction + +Arguments: + VmPtr - pointer to a VM context + +Returns: + Standard EFI_STATUS + +Instruction syntax: + PUSHn {@}R1 {Index16|Immed16} + +--*/ +{ + 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) { + 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->R[OPERAND1_REGNUM (Operands)] + Index16)); + } else { + DataN = (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16); + } + // + // Adjust the stack down. + // + VmPtr->R[0] -= sizeof (UINTN); + VmWriteMemN (VmPtr, (UINTN) VmPtr->R[0], DataN); + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +ExecutePUSH ( + IN VM_CONTEXT *VmPtr + ) +/*++ + +Routine Description: + Execute the EBC PUSH instruction + +Arguments: + VmPtr - pointer to a VM context + +Returns: + Standard EFI_STATUS + +Instruction syntax: + PUSH[32|64] {@}R1 {Index16|Immed16} + +--*/ +{ + 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) { + 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) { + if (OPERAND1_INDIRECT (Operands)) { + Data64 = VmReadMem64 (VmPtr, (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16)); + } else { + Data64 = (UINT64) VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16; + } + // + // Adjust the stack down, then write back the data + // + VmPtr->R[0] -= sizeof (UINT64); + VmWriteMem64 (VmPtr, (UINTN) VmPtr->R[0], Data64); + } else { + // + // 32-bit data + // + if (OPERAND1_INDIRECT (Operands)) { + Data32 = VmReadMem32 (VmPtr, (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16)); + } else { + Data32 = (UINT32) VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16; + } + // + // Adjust the stack down and write the data + // + VmPtr->R[0] -= sizeof (UINT32); + VmWriteMem32 (VmPtr, (UINTN) VmPtr->R[0], Data32); + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +ExecutePOPn ( + IN VM_CONTEXT *VmPtr + ) +/*++ + +Routine Description: + Execute the EBC POPn instruction + +Arguments: + VmPtr - pointer to a VM context + +Returns: + Standard EFI_STATUS + +Instruction syntax: + POPn {@}R1 {Index16|Immed16} + +--*/ +{ + 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) { + 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->R[0]); + VmPtr->R[0] += sizeof (UINTN); + // + // Do the write-back + // + if (OPERAND1_INDIRECT (Operands)) { + VmWriteMemN (VmPtr, (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16), DataN); + } else { + VmPtr->R[OPERAND1_REGNUM (Operands)] = (INT64) (UINT64) ((UINTN) DataN + Index16); + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +ExecutePOP ( + IN VM_CONTEXT *VmPtr + ) +/*++ + +Routine Description: + Execute the EBC POP instruction + +Arguments: + VmPtr - pointer to a VM context + +Returns: + Standard EFI_STATUS + +Instruction syntax: + POP {@}R1 {Index16|Immed16} + +--*/ +{ + 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) { + 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) { + // + // Read the data off the stack, then adjust the stack pointer + // + Data64 = VmReadMem64 (VmPtr, (UINTN) VmPtr->R[0]); + VmPtr->R[0] += sizeof (UINT64); + // + // Do the write-back + // + if (OPERAND1_INDIRECT (Operands)) { + VmWriteMem64 (VmPtr, (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16), Data64); + } else { + VmPtr->R[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->R[0]); + VmPtr->R[0] += sizeof (UINT32); + // + // Do the write-back + // + if (OPERAND1_INDIRECT (Operands)) { + VmWriteMem32 (VmPtr, (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16), Data32); + } else { + VmPtr->R[OPERAND1_REGNUM (Operands)] = (INT64) Data32 + Index16; + } + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +ExecuteCALL ( + IN VM_CONTEXT *VmPtr + ) +/*++ + +Routine Description: + 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. + +Arguments: + VmPtr - pointer to a VM context. + +Returns: + Standard EFI_STATUS + +--*/ +{ + UINT8 Opcode; + UINT8 Operands; + INT32 Immed32; + UINT8 Size; + INT64 Immed64; + VOID *FramePtr; + + // + // Get opcode and operands + // + Opcode = GETOPCODE (VmPtr); + Operands = GETOPERANDS (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) { + if (Opcode & OPCODE_M_IMMDATA64) { + 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->R[0] -= 8; + VmWriteMemN (VmPtr, (UINTN) VmPtr->R[0], (UINTN) FramePtr); + VmPtr->FramePtr = (VOID *) (UINTN) VmPtr->R[0]; + VmPtr->R[0] -= 8; + VmWriteMem64 (VmPtr, (UINTN) VmPtr->R[0], (UINT64) (UINTN) (VmPtr->Ip + Size)); + } + // + // If 64-bit data, then absolute jump only + // + if (Opcode & OPCODE_M_IMMDATA64) { + // + // 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->R[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->R[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) { + VmPtr->Ip += Immed64 + Size; + } else { + VmPtr->Ip = (VMIP) (UINTN) Immed64; + } + } else { + // + // Native call. Relative or absolute? + // + if (Operands & OPERAND_M_RELATIVE_ADDR) { + EbcLLCALLEX (VmPtr, (UINTN) (Immed64 + VmPtr->Ip + Size), (UINTN) VmPtr->R[0], FramePtr, Size); + } else { + if (VmPtr->StopFlags & STOPFLAG_BREAK_ON_CALLEX) { + CpuBreakpoint (); + } + + EbcLLCALLEX (VmPtr, (UINTN) Immed64, (UINTN) VmPtr->R[0], FramePtr, Size); + } + } + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +ExecuteRET ( + IN VM_CONTEXT *VmPtr + ) +/*++ + +Routine Description: + Execute the EBC RET instruction + +Arguments: + VmPtr - pointer to a VM context + +Returns: + Standard EFI_STATUS + +Instruction syntax: + RET + +--*/ +{ + // + // If we're at the top of the stack, then simply set the done + // flag and return + // + if (VmPtr->StackRetAddr == (UINT64) VmPtr->R[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->R[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->R[0]); + VmPtr->R[0] += 8; + VmPtr->FramePtr = (VOID *) VmReadMemN (VmPtr, (UINTN) VmPtr->R[0]); + VmPtr->R[0] += 8; + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +ExecuteCMP ( + IN VM_CONTEXT *VmPtr + ) +/*++ + +Routine Description: + Execute the EBC CMP instruction + +Arguments: + VmPtr - pointer to a VM context + +Returns: + Standard EFI_STATUS + +Instruction syntax: + CMP[32|64][eq|lte|gte|ulte|ugte] R1, {@}R2 {Index16|Immed16} + +--*/ +{ + 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->R[OPERAND1_REGNUM (Operands)]; + // + // Get immediate data + // + if (Opcode & OPCODE_M_IMMDATA) { + 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) { + Op2 = (INT64) VmReadMem64 (VmPtr, (UINTN) (VmPtr->R[OPERAND2_REGNUM (Operands)] + Index16)); + } else { + // + // 32-bit operations. 0-extend the values for all cases. + // + Op2 = (INT64) (UINT64) ((UINT32) VmReadMem32 (VmPtr, (UINTN) (VmPtr->R[OPERAND2_REGNUM (Operands)] + Index16))); + } + } else { + Op2 = VmPtr->R[OPERAND2_REGNUM (Operands)] + Index16; + } + // + // Now do the compare + // + Flag = 0; + if (Opcode & OPCODE_M_64BIT) { + // + // 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) { + VMFLAG_SET (VmPtr, VMFLAGS_CC); + } else { + VMFLAG_CLEAR (VmPtr, VMFLAGS_CC); + } + // + // Advance the IP + // + VmPtr->Ip += Size; + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +ExecuteCMPI ( + IN VM_CONTEXT *VmPtr + ) +/*++ + +Routine Description: + Execute the EBC CMPI instruction + +Arguments: + VmPtr - pointer to a VM context + +Returns: + Standard EFI_STATUS + +Instruction syntax: + CMPI[32|64]{w|d}[eq|lte|gte|ulte|ugte] {@}Rx {Index16}, Immed16|Immed32 + +--*/ +{ + 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) { + Index16 = VmReadIndex16 (VmPtr, 2); + Size += 2; + } else { + Index16 = 0; + } + // + // Get operand1 data we're going to compare to + // + Op1 = (INT64) VmPtr->R[OPERAND1_REGNUM (Operands)]; + if (OPERAND1_INDIRECT (Operands)) { + // + // Indirect operand1. Fetch 32 or 64-bit value based on compare size. + // + if (Opcode & OPCODE_M_CMPI64) { + 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) { + 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) { + 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) { + // + // 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) { + VMFLAG_SET (VmPtr, VMFLAGS_CC); + } else { + VMFLAG_CLEAR (VmPtr, VMFLAGS_CC); + } + // + // Advance the IP + // + VmPtr->Ip += Size; + return EFI_SUCCESS; +} + +STATIC +UINT64 +ExecuteNOT ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ) +/*++ + +Routine Description: + Execute the EBC NOT instruction + +Arguments: + VmPtr - pointer to a VM context + Op1 - Operand 1 from the instruction + Op2 - Operand 2 from the instruction + +Returns: + ~Op2 + +Instruction syntax: + NOT[32|64] {@}R1, {@}R2 {Index16|Immed16} + +--*/ +{ + return ~Op2; +} + +STATIC +UINT64 +ExecuteNEG ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ) +/*++ + +Routine Description: + Execute the EBC NEG instruction + +Arguments: + VmPtr - pointer to a VM context + Op1 - Operand 1 from the instruction + Op2 - Operand 2 from the instruction + +Returns: + Op2 * -1 + +Instruction syntax: + NEG[32|64] {@}R1, {@}R2 {Index16|Immed16} + +--*/ +{ + return ~Op2 + 1; +} + +STATIC +UINT64 +ExecuteADD ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ) +/*++ + +Routine Description: + + Execute the EBC ADD instruction + +Arguments: + VmPtr - pointer to a VM context + Op1 - Operand 1 from the instruction + Op2 - Operand 2 from the instruction + +Returns: + Op1 + Op2 + +Instruction syntax: + ADD[32|64] {@}R1, {@}R2 {Index16} + +--*/ +{ + return Op1 + Op2; +} + +STATIC +UINT64 +ExecuteSUB ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ) +/*++ + +Routine Description: + Execute the EBC SUB instruction + +Arguments: + VmPtr - pointer to a VM context + Op1 - Operand 1 from the instruction + Op2 - Operand 2 from the instruction + +Returns: + Op1 - Op2 + Standard EFI_STATUS + +Instruction syntax: + SUB[32|64] {@}R1, {@}R2 {Index16|Immed16} + +--*/ +{ + if (*VmPtr->Ip & DATAMANIP_M_64) { + return (UINT64) ((INT64) ((INT64) Op1 - (INT64) Op2)); + } else { + return (UINT64) ((INT64) ((INT32) Op1 - (INT32) Op2)); + } +} + +STATIC +UINT64 +ExecuteMUL ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ) +/*++ + +Routine Description: + + Execute the EBC MUL instruction + +Arguments: + VmPtr - pointer to a VM context + Op1 - Operand 1 from the instruction + Op2 - Operand 2 from the instruction + +Returns: + Op1 * Op2 + +Instruction syntax: + MUL[32|64] {@}R1, {@}R2 {Index16|Immed16} + +--*/ +{ + INT64 ResultHigh; + + if (*VmPtr->Ip & DATAMANIP_M_64) { + return MulS64x64 (Op1, Op2, &ResultHigh); + } else { + return (UINT64) ((INT64) ((INT32) Op1 * (INT32) Op2)); + } +} + +STATIC +UINT64 +ExecuteMULU ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ) +/*++ + +Routine Description: + Execute the EBC MULU instruction + +Arguments: + VmPtr - pointer to a VM context + Op1 - Operand 1 from the instruction + Op2 - Operand 2 from the instruction + +Returns: + (unsigned)Op1 * (unsigned)Op2 + +Instruction syntax: + MULU[32|64] {@}R1, {@}R2 {Index16|Immed16} + +--*/ +{ + INT64 ResultHigh; + if (*VmPtr->Ip & DATAMANIP_M_64) { + return MulU64x64 (Op1, Op2, (UINT64 *)&ResultHigh); + } else { + return (UINT64) ((UINT32) Op1 * (UINT32) Op2); + } +} + +STATIC +UINT64 +ExecuteDIV ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ) +/*++ + +Routine Description: + + Execute the EBC DIV instruction + +Arguments: + VmPtr - pointer to a VM context + Op1 - Operand 1 from the instruction + Op2 - Operand 2 from the instruction + +Returns: + Op1/Op2 + +Instruction syntax: + DIV[32|64] {@}R1, {@}R2 {Index16|Immed16} + +--*/ +{ + INT64 Remainder; + UINT32 Error; + + // + // 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) { + return (UINT64) (DivS64x64 (Op1, Op2, &Remainder, &Error)); + } else { + return (UINT64) ((INT64) ((INT32) Op1 / (INT32) Op2)); + } + } +} + +STATIC +UINT64 +ExecuteDIVU ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ) +/*++ + +Routine Description: + Execute the EBC DIVU instruction + +Arguments: + VmPtr - pointer to a VM context + Op1 - Operand 1 from the instruction + Op2 - Operand 2 from the instruction + +Returns: + (unsigned)Op1 / (unsigned)Op2 + +Instruction syntax: + DIVU[32|64] {@}R1, {@}R2 {Index16|Immed16} + +--*/ +{ + UINT64 Remainder; + UINT32 Error; + + // + // 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) { + return (UINT64) (DivU64x64 (Op1, Op2, &Remainder, &Error)); + } else { + return (UINT64) ((UINT32) Op1 / (UINT32) Op2); + } + } +} + +STATIC +UINT64 +ExecuteMOD ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ) +/*++ + +Routine Description: + Execute the EBC MOD instruction + +Arguments: + VmPtr - pointer to a VM context + Op1 - Operand 1 from the instruction + Op2 - Operand 2 from the instruction + +Returns: + Op1 MODULUS Op2 + +Instruction syntax: + MOD[32|64] {@}R1, {@}R2 {Index16|Immed16} + +--*/ +{ + INT64 Remainder; + UINT32 Error; + + // + // Check for divide-by-0 + // + if (Op2 == 0) { + EbcDebugSignalException ( + EXCEPT_EBC_DIVIDE_ERROR, + EXCEPTION_FLAG_FATAL, + VmPtr + ); + return 0; + } else { + DivS64x64 ((INT64) Op1, (INT64) Op2, &Remainder, &Error); + return Remainder; + } +} + +STATIC +UINT64 +ExecuteMODU ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ) +/*++ + +Routine Description: + Execute the EBC MODU instruction + +Arguments: + VmPtr - pointer to a VM context + Op1 - Operand 1 from the instruction + Op2 - Operand 2 from the instruction + +Returns: + Op1 UNSIGNED_MODULUS Op2 + +Instruction syntax: + MODU[32|64] {@}R1, {@}R2 {Index16|Immed16} + +--*/ +{ + UINT64 Remainder; + UINT32 Error; + + // + // Check for divide-by-0 + // + if (Op2 == 0) { + EbcDebugSignalException ( + EXCEPT_EBC_DIVIDE_ERROR, + EXCEPTION_FLAG_FATAL, + VmPtr + ); + return 0; + } else { + DivU64x64 (Op1, Op2, &Remainder, &Error); + return Remainder; + } +} + +STATIC +UINT64 +ExecuteAND ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ) +/*++ + +Routine Description: + Execute the EBC AND instruction + +Arguments: + VmPtr - pointer to a VM context + Op1 - Operand 1 from the instruction + Op2 - Operand 2 from the instruction + +Returns: + Op1 AND Op2 + +Instruction syntax: + AND[32|64] {@}R1, {@}R2 {Index16|Immed16} + +--*/ +{ + return Op1 & Op2; +} + +STATIC +UINT64 +ExecuteOR ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ) +/*++ + +Routine Description: + Execute the EBC OR instruction + +Arguments: + VmPtr - pointer to a VM context + Op1 - Operand 1 from the instruction + Op2 - Operand 2 from the instruction + +Returns: + Op1 OR Op2 + +Instruction syntax: + OR[32|64] {@}R1, {@}R2 {Index16|Immed16} + +--*/ +{ + return Op1 | Op2; +} + +STATIC +UINT64 +ExecuteXOR ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ) +/*++ + +Routine Description: + Execute the EBC XOR instruction + +Arguments: + VmPtr - pointer to a VM context + Op1 - Operand 1 from the instruction + Op2 - Operand 2 from the instruction + +Returns: + Op1 XOR Op2 + +Instruction syntax: + XOR[32|64] {@}R1, {@}R2 {Index16|Immed16} + +--*/ +{ + return Op1 ^ Op2; +} + +STATIC +UINT64 +ExecuteSHL ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ) +/*++ + +Routine Description: + + Execute the EBC SHL shift left instruction + +Arguments: + VmPtr - pointer to a VM context + Op1 - Operand 1 from the instruction + Op2 - Operand 2 from the instruction + +Returns: + Op1 << Op2 + +Instruction syntax: + SHL[32|64] {@}R1, {@}R2 {Index16|Immed16} + +--*/ +{ + if (*VmPtr->Ip & DATAMANIP_M_64) { + return LeftShiftU64 (Op1, Op2); + } else { + return (UINT64) ((UINT32) ((UINT32) Op1 << (UINT32) Op2)); + } +} + +STATIC +UINT64 +ExecuteSHR ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ) +/*++ + +Routine Description: + Execute the EBC SHR instruction + +Arguments: + VmPtr - pointer to a VM context + Op1 - Operand 1 from the instruction + Op2 - Operand 2 from the instruction + +Returns: + Op1 >> Op2 (unsigned operands) + +Instruction syntax: + SHR[32|64] {@}R1, {@}R2 {Index16|Immed16} + +--*/ +{ + if (*VmPtr->Ip & DATAMANIP_M_64) { + return RightShiftU64 (Op1, Op2); + } else { + return (UINT64) ((UINT32) Op1 >> (UINT32) Op2); + } +} + +STATIC +UINT64 +ExecuteASHR ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ) +/*++ + +Routine Description: + Execute the EBC ASHR instruction + +Arguments: + VmPtr - pointer to a VM context + Op1 - Operand 1 from the instruction + Op2 - Operand 2 from the instruction + +Returns: + Op1 >> Op2 (signed) + +Instruction syntax: + ASHR[32|64] {@}R1, {@}R2 {Index16|Immed16} + +--*/ +{ + if (*VmPtr->Ip & DATAMANIP_M_64) { + return ARightShift64 (Op1, Op2); + } else { + return (UINT64) ((INT64) ((INT32) Op1 >> (UINT32) Op2)); + } +} + +STATIC +UINT64 +ExecuteEXTNDB ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ) +/*++ + +Routine Description: + Execute the EBC EXTNDB instruction to sign-extend a byte value. + +Arguments: + VmPtr - pointer to a VM context + Op1 - Operand 1 from the instruction + Op2 - Operand 2 from the instruction + +Returns: + (INT64)(INT8)Op2 + +Instruction syntax: + EXTNDB[32|64] {@}R1, {@}R2 {Index16|Immed16} + + +--*/ +{ + 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; +} + +STATIC +UINT64 +ExecuteEXTNDW ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ) +/*++ + +Routine Description: + Execute the EBC EXTNDW instruction to sign-extend a 16-bit value. + +Arguments: + VmPtr - pointer to a VM context + Op1 - Operand 1 from the instruction + Op2 - Operand 2 from the instruction + +Returns: + (INT64)(INT16)Op2 + +Instruction syntax: + EXTNDW[32|64] {@}R1, {@}R2 {Index16|Immed16} + + +--*/ +{ + 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)) +// +STATIC +UINT64 +ExecuteEXTNDD ( + IN VM_CONTEXT *VmPtr, + IN UINT64 Op1, + IN UINT64 Op2 + ) +/*++ + +Routine Description: + Execute the EBC EXTNDD instruction to sign-extend a 32-bit value. + +Arguments: + VmPtr - pointer to a VM context + Op1 - Operand 1 from the instruction + Op2 - Operand 2 from the instruction + +Returns: + (INT64)(INT32)Op2 + +Instruction syntax: + EXTNDD[32|64] {@}R1, {@}R2 {Index16|Immed16} + + +--*/ +{ + 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; +} + +STATIC +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); +} + +STATIC +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); +} + +STATIC +EFI_STATUS +ExecuteDataManip ( + IN VM_CONTEXT *VmPtr, + IN BOOLEAN IsSignedOp + ) +/*++ + +Routine Description: + 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. + +Arguments: + VmPtr - pointer to VM context + +Returns: + Standard EBC status + +Format: + INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16} + +--*/ +{ + UINT8 Opcode; + INT16 Index16; + UINT8 Operands; + UINT8 Size; + UINT64 Op1; + UINT64 Op2; + + // + // Get opcode and operands + // + Opcode = GETOPCODE (VmPtr); + Operands = GETOPERANDS (VmPtr); + + // + // Determine if we have immediate data by the opcode + // + if (Opcode & DATAMANIP_M_IMMDATA) { + // + // 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->R[OPERAND2_REGNUM (Operands)] + Index16; + if (OPERAND2_INDIRECT (Operands)) { + // + // Indirect form: @R2 Index16. Fetch as 32- or 64-bit data + // + if (Opcode & DATAMANIP_M_64) { + 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 = VmPtr->R[OPERAND1_REGNUM (Operands)]; + if (OPERAND1_INDIRECT (Operands)) { + if (Opcode & DATAMANIP_M_64) { + 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 + // + if (((Opcode & OPCODE_M_OPCODE) - OPCODE_NOT) >= + (sizeof (mDataManipDispatchTable) / sizeof (mDataManipDispatchTable[0])) + ) { + EbcDebugSignalException ( + EXCEPT_EBC_INVALID_OPCODE, + EXCEPTION_FLAG_ERROR, + VmPtr + ); + // + // Advance and return + // + VmPtr->Ip += Size; + return EFI_UNSUPPORTED; + } else { + Op2 = mDataManipDispatchTable[(Opcode & OPCODE_M_OPCODE) - OPCODE_NOT](VmPtr, Op1, Op2); + } + // + // Write back the result. + // + if (OPERAND1_INDIRECT (Operands)) { + Op1 = VmPtr->R[OPERAND1_REGNUM (Operands)]; + if (Opcode & DATAMANIP_M_64) { + 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->R[OPERAND1_REGNUM (Operands)] = Op2; + if ((Opcode & DATAMANIP_M_64) == 0) { + VmPtr->R[OPERAND1_REGNUM (Operands)] &= 0xFFFFFFFF; + } + } + // + // Advance the instruction pointer + // + VmPtr->Ip += Size; + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +ExecuteLOADSP ( + IN VM_CONTEXT *VmPtr + ) +/*++ + +Routine Description: + Execute the EBC LOADSP instruction + +Arguments: + VmPtr - pointer to a VM context + +Returns: + Standard EFI_STATUS + +Instruction syntax: + LOADSP SP1, R2 + +--*/ +{ + 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->R[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; +} + +STATIC +EFI_STATUS +ExecuteSTORESP ( + IN VM_CONTEXT *VmPtr + ) +/*++ + +Routine Description: + Execute the EBC STORESP instruction + +Arguments: + VmPtr - pointer to a VM context + +Returns: + Standard EFI_STATUS + +Instruction syntax: + STORESP Rx, FLAGS|IP + +--*/ +{ + 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->R[OPERAND1_REGNUM (Operands)] = (UINT64) (VmPtr->Flags & VMFLAGS_ALL_VALID); + break; + + // + // Get IP -- address of following instruction + // + case 1: + VmPtr->R[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; +} + +STATIC +INT16 +VmReadIndex16 ( + IN VM_CONTEXT *VmPtr, + IN UINT32 CodeOffset + ) +/*++ + +Routine Description: + 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 = C + b0:a - natural units = N + + Given this info, the offset can be computed by: + offset = sign_bit * (C + N * 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 = + +Arguments: + VmPtr - pointer to VM context + CodeOffset - offset from IP of the location of the 16-bit index to decode + +Returns: + The decoded offset. + +--*/ +{ + UINT16 Index; + INT16 Offset; + INT16 C; + INT16 N; + INT16 NBits; + INT16 Mask; + + // + // First read the index from the code stream + // + Index = VmReadCode16 (VmPtr, CodeOffset); + + // + // Get the mask for N. 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 N from the lower bits of the index. + // + N = (INT16) (Index &~Mask); + + // + // Now compute C + // + C = (INT16) (((Index &~0xF000) & Mask) >> NBits); + + Offset = (INT16) (N * sizeof (UINTN) + C); + + // + // Now set the sign + // + if (Index & 0x8000) { + // + // Do it the hard way to work around a bogus compiler warning + // + // Offset = -1 * Offset; + // + Offset = (INT16) ((INT32) Offset * -1); + } + + return Offset; +} + +STATIC +INT32 +VmReadIndex32 ( + IN VM_CONTEXT *VmPtr, + IN UINT32 CodeOffset + ) +/*++ + +Routine Description: + Decode a 32-bit index to determine the offset. + +Arguments: + VmPtr - pointer to VM context + CodeOffset - offset from IP of the location of the 32-bit index to decode + +Returns: + Converted index per EBC VM specification + +--*/ +{ + UINT32 Index; + INT32 Offset; + INT32 C; + INT32 N; + INT32 NBits; + INT32 Mask; + + Index = VmReadImmed32 (VmPtr, CodeOffset); + + // + // Get the mask for N. 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 N from the lower bits of the index. + // + N = Index &~Mask; + + // + // Now compute C + // + C = ((Index &~0xF0000000) & Mask) >> NBits; + + Offset = N * sizeof (UINTN) + C; + + // + // Now set the sign + // + if (Index & 0x80000000) { + Offset = Offset * -1; + } + + return Offset; +} + +STATIC +INT64 +VmReadIndex64 ( + IN VM_CONTEXT *VmPtr, + IN UINT32 CodeOffset + ) +/*++ + +Routine Description: + Decode a 64-bit index to determine the offset. + +Arguments: + VmPtr - pointer to VM context + CodeOffset - offset from IP of the location of the 64-bit index to decode + +Returns: + Converted index per EBC VM specification + +--*/ +{ + UINT64 Index; + UINT64 Remainder; + INT64 Offset; + INT64 C; + INT64 N; + INT64 NBits; + INT64 Mask; + + Index = VmReadCode64 (VmPtr, CodeOffset); + + // + // Get the mask for N. First get the number of bits from the index. + // + NBits = RightShiftU64 ((Index & 0x7000000000000000ULL), 60); + + // + // Scale it for 64-bit indexes (multiply by 8 by shifting left 3) + // + NBits = LeftShiftU64 (NBits, 3); + + // + // Now using the number of bits, create a mask. + // + Mask = (LeftShiftU64 ((UINT64)~0, (UINT64) NBits)); + + // + // Now using the mask, extract N from the lower bits of the index. + // + N = Index &~Mask; + + // + // Now compute C + // + C = ARightShift64 (((Index &~0xF000000000000000ULL) & Mask), (UINTN) NBits); + + Offset = MulU64x64 (N, sizeof (UINTN), &Remainder) + C; + + // + // Now set the sign + // + if (Index & 0x8000000000000000ULL) { + Offset = MulS64x64 (Offset, -1, (INT64 *)&Index); + } + + return Offset; +} + +STATIC +EFI_STATUS +VmWriteMem8 ( + IN VM_CONTEXT *VmPtr, + IN UINTN Addr, + IN UINT8 Data + ) +/*++ + +Routine Description: + The following VmWriteMem? routines are 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. + +Arguments: + VmPtr - pointer to a VM context + Addr - adddress to write to + Data - value to write to Addr + +Returns: + Standard EFI_STATUS + +--*/ +{ + // + // Convert the address if it's in the stack gap + // + Addr = ConvertStackAddr (VmPtr, Addr); + *(UINT8 *) Addr = Data; + return EFI_SUCCESS; +} + +STATIC +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; +} + +STATIC +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; +} + +EFI_STATUS +VmWriteMem64 ( + IN VM_CONTEXT *VmPtr, + IN UINTN Addr, + IN UINT64 Data + ) +{ + EFI_STATUS Status; + UINT32 Data32; + + // + // 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 (); + Data32 = (UINT32) (((UINT32 *) &Data)[1]); + if ((Status = VmWriteMem32 (VmPtr, Addr + sizeof (UINT32), Data32)) != EFI_SUCCESS) { + return Status; + } + + MemoryFence (); + } + + return EFI_SUCCESS; +} + +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; +} + +STATIC +INT8 +VmReadImmed8 ( + IN VM_CONTEXT *VmPtr, + IN UINT32 Offset + ) +/*++ + +Routine Description: + + The following VmReadImmed routines are 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. + +Arguments: + VmPtr - pointer to a VM context + Offset - offset from IP of the code bytes to read. + +Returns: + Signed data of the requested size from the specified address. + +--*/ +{ + // + // Simply return the data in flat memory space + // + return * (INT8 *) (VmPtr->Ip + Offset); +} + +STATIC +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)); +} + +STATIC +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; +} + +STATIC +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; +} + +STATIC +UINT16 +VmReadCode16 ( + IN VM_CONTEXT *VmPtr, + IN UINT32 Offset + ) +/*++ + +Routine Description: + The following VmReadCode() routines provide the ability to read raw + unsigned data from the code stream. + +Arguments: + VmPtr - pointer to VM context + Offset - offset from current IP to the raw data to read. + +Returns: + The raw unsigned 16-bit value from the code stream. + +--*/ +{ + // + // 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)); +} + +STATIC +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; +} + +STATIC +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; +} + +STATIC +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; +} + +STATIC +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)); +} + +STATIC +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; +} + +STATIC +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. + // + Data = (UINT64) VmReadMem32 (VmPtr, Addr); + Data32 = VmReadMem32 (VmPtr, Addr + sizeof (UINT32)); + *(UINT32 *) ((UINT32 *) &Data + 1) = Data32; + return Data; +} + +STATIC +UINTN +ConvertStackAddr ( + IN VM_CONTEXT *VmPtr, + IN UINTN Addr + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + VmPtr - pointer to VM context + Addr - address of interest + +Returns: + + The unchanged address if it's not in the VM stack region. Otherwise, + adjust for the stack gap and return the modified address. + +--*/ +{ + if ((Addr >= VmPtr->LowStackTop) && (Addr < VmPtr->HighStackBottom)) { + // + // In the stack gap -- now make sure it's not in the VM itself, which + // would be the case if it's accessing VM register contents. + // + if ((Addr < (UINTN) VmPtr) || (Addr > (UINTN) VmPtr + sizeof (VM_CONTEXT))) { + VmPtr->LastAddrConverted = Addr; + VmPtr->LastAddrConvertedValue = Addr - VmPtr->LowStackTop + VmPtr->HighStackBottom; + return Addr - VmPtr->LowStackTop + VmPtr->HighStackBottom; + } + } + + return Addr; +} + +STATIC +UINTN +VmReadMemN ( + IN VM_CONTEXT *VmPtr, + IN UINTN Addr + ) +/*++ + +Routine Description: + Read a natural value from memory. May or may not be aligned. + +Arguments: + VmPtr - current VM context + Addr - the address to read from + +Returns: + The natural value at address Addr. + +--*/ +{ + UINTN Data; + 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; +} + +UINT64 +GetVmVersion ( + VOID + ) +{ + return (UINT64) (((VM_MAJOR_VERSION & 0xFFFF) << 16) | ((VM_MINOR_VERSION & 0xFFFF))); +} diff --git a/EdkModulePkg/Universal/Ebc/Dxe/EbcExecute.h b/EdkModulePkg/Universal/Ebc/Dxe/EbcExecute.h new file mode 100644 index 0000000000..62b530b952 --- /dev/null +++ b/EdkModulePkg/Universal/Ebc/Dxe/EbcExecute.h @@ -0,0 +1,383 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + EbcExecute.h + +Abstract: + + 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. + +--*/ + +#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)) + +// +// 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) + +// +// Bit masks for opcode encodings +// +#define OPCODE_M_OPCODE 0x3F // bits of interest for first level decode +#define OPCODE_M_IMMDATA 0x80 +#define OPCODE_M_IMMDATA64 0x40 +#define OPCODE_M_64BIT 0x40 // for CMP +#define OPCODE_M_RELADDR 0x10 // for CALL instruction +#define OPCODE_M_CMPI32_DATA 0x80 // for CMPI +#define OPCODE_M_CMPI64 0x40 // for CMPI 32 or 64 bit comparison +#define OPERAND_M_MOVIN_N 0x80 +#define OPERAND_M_CMPI_INDEX 0x10 + +// +// Masks for instructions that encode presence of indexes for operand1 and/or +// operand2. +// +#define OPCODE_M_IMMED_OP1 0x80 +#define OPCODE_M_IMMED_OP2 0x40 + +// +// Bit masks for operand encodings +// +#define OPERAND_M_INDIRECT1 0x08 +#define OPERAND_M_INDIRECT2 0x80 +#define OPERAND_M_OP1 0x07 +#define OPERAND_M_OP2 0x70 + +// +// Masks for data manipulation instructions +// +#define DATAMANIP_M_64 0x40 // 64-bit width operation +#define DATAMANIP_M_IMMDATA 0x80 + +// +// For MOV instructions, need a mask for the opcode when immediate +// data applies to R2. +// +#define OPCODE_M_IMMED_OP2 0x40 + +// +// The MOVI/MOVIn instructions use bit 6 of operands byte to indicate +// if an index is present. Then bits 4 and 5 are used to indicate the width +// of the move. +// +#define MOVI_M_IMMDATA 0x40 +#define MOVI_M_DATAWIDTH 0xC0 +#define MOVI_DATAWIDTH16 0x40 +#define MOVI_DATAWIDTH32 0x80 +#define MOVI_DATAWIDTH64 0xC0 +#define MOVI_M_MOVEWIDTH 0x30 +#define MOVI_MOVEWIDTH8 0x00 +#define MOVI_MOVEWIDTH16 0x10 +#define MOVI_MOVEWIDTH32 0x20 +#define MOVI_MOVEWIDTH64 0x30 + +// +// Masks for CALL instruction encodings +// +#define OPERAND_M_RELATIVE_ADDR 0x10 +#define OPERAND_M_NATIVE_CALL 0x20 + +// +// Masks for decoding push/pop instructions +// +#define PUSHPOP_M_IMMDATA 0x80 // opcode bit indicating immediate data +#define PUSHPOP_M_64 0x40 // opcode bit indicating 64-bit operation +// +// Mask for operand of JMP instruction +// +#define JMP_M_RELATIVE 0x10 +#define JMP_M_CONDITIONAL 0x80 +#define JMP_M_CS 0x40 + +// +// Macros to determine if a given operand is indirect +// +#define OPERAND1_INDIRECT(op) ((op) & OPERAND_M_INDIRECT1) +#define OPERAND2_INDIRECT(op) ((op) & OPERAND_M_INDIRECT2) + +// +// Macros to extract the operands from second byte of instructions +// +#define OPERAND1_REGNUM(op) ((op) & OPERAND_M_OP1) +#define OPERAND2_REGNUM(op) (((op) & OPERAND_M_OP2) >> 4) + +#define OPERAND1_CHAR(op) ('0' + OPERAND1_REGNUM (op)) +#define OPERAND2_CHAR(op) ('0' + OPERAND2_REGNUM (op)) + +#define OPERAND1_REGDATA(pvm, op) pvm->R[OPERAND1_REGNUM (op)] +#define OPERAND2_REGDATA(pvm, op) pvm->R[OPERAND2_REGNUM (op)] + +// +// Condition masks usually for byte 1 encodings of code +// +#define CONDITION_M_CONDITIONAL 0x80 +#define CONDITION_M_CS 0x40 + +// +// 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)) + +// +// Debug macro +// +#define EBCMSG(s) gST->ConOut->OutputString (gST->ConOut, s) + +// +// Define OPCODES +// +#define OPCODE_BREAK 0x00 +#define OPCODE_JMP 0x01 +#define OPCODE_JMP8 0x02 +#define OPCODE_CALL 0x03 +#define OPCODE_RET 0x04 +#define OPCODE_CMPEQ 0x05 +#define OPCODE_CMPLTE 0x06 +#define OPCODE_CMPGTE 0x07 +#define OPCODE_CMPULTE 0x08 +#define OPCODE_CMPUGTE 0x09 +#define OPCODE_NOT 0x0A +#define OPCODE_NEG 0x0B +#define OPCODE_ADD 0x0C +#define OPCODE_SUB 0x0D +#define OPCODE_MUL 0x0E +#define OPCODE_MULU 0x0F +#define OPCODE_DIV 0x10 +#define OPCODE_DIVU 0x11 +#define OPCODE_MOD 0x12 +#define OPCODE_MODU 0x13 +#define OPCODE_AND 0x14 +#define OPCODE_OR 0x15 +#define OPCODE_XOR 0x16 +#define OPCODE_SHL 0x17 +#define OPCODE_SHR 0x18 +#define OPCODE_ASHR 0x19 +#define OPCODE_EXTNDB 0x1A +#define OPCODE_EXTNDW 0x1B +#define OPCODE_EXTNDD 0x1C +#define OPCODE_MOVBW 0x1D +#define OPCODE_MOVWW 0x1E +#define OPCODE_MOVDW 0x1F +#define OPCODE_MOVQW 0x20 +#define OPCODE_MOVBD 0x21 +#define OPCODE_MOVWD 0x22 +#define OPCODE_MOVDD 0x23 +#define OPCODE_MOVQD 0x24 +#define OPCODE_MOVSNW 0x25 // Move signed natural with word index +#define OPCODE_MOVSND 0x26 // Move signed natural with dword index +// +// #define OPCODE_27 0x27 +// +#define OPCODE_MOVQQ 0x28 // Does this go away? +#define OPCODE_LOADSP 0x29 +#define OPCODE_STORESP 0x2A +#define OPCODE_PUSH 0x2B +#define OPCODE_POP 0x2C +#define OPCODE_CMPIEQ 0x2D +#define OPCODE_CMPILTE 0x2E +#define OPCODE_CMPIGTE 0x2F +#define OPCODE_CMPIULTE 0x30 +#define OPCODE_CMPIUGTE 0x31 +#define OPCODE_MOVNW 0x32 +#define OPCODE_MOVND 0x33 +// +// #define OPCODE_34 0x34 +// +#define OPCODE_PUSHN 0x35 +#define OPCODE_POPN 0x36 +#define OPCODE_MOVI 0x37 +#define OPCODE_MOVIN 0x38 +#define OPCODE_MOVREL 0x39 + +EFI_STATUS +EbcExecute ( + IN VM_CONTEXT *VmPtr + ) +; + +// +// Math library routines +// +INT64 +DivS64x64 ( + IN INT64 Value1, + IN INT64 Value2, + OUT INT64 *Remainder, + OUT UINT32 *Error + ) +; +#if 0 +UINT64 +DivU64x64 ( + IN UINT64 Value1, + IN UINT64 Value2, + OUT UINT64 *Remainder, + OUT UINT32 *Error + ) +; +#endif + +INT64 +MulS64x64 ( + IN INT64 Value1, + IN INT64 Value2, + OUT INT64 *ResultHigh + ) +; + +UINT64 +MulU64x64 ( + IN UINT64 Value1, + IN UINT64 Value2, + OUT UINT64 *ResultHigh + ) +; + +UINT64 +DivU64x64 ( + IN UINT64 Value1, + IN UINT64 Value2, + OUT UINT64 *Remainder, + OUT UINT32 *Error + ) +; + +INT64 +ARightShift64 ( + IN INT64 Operand, + IN INT64 Count + ) +; + +UINT64 +LeftShiftU64 ( + IN UINT64 Operand, + IN UINT64 Count + ) +; + +UINT64 +RightShiftU64 ( + IN UINT64 Operand, + IN UINT64 Count + ) +; + +UINT64 +GetVmVersion ( + VOID + ) +; + +EFI_STATUS +VmWriteMemN ( + IN VM_CONTEXT *VmPtr, + IN UINTN Addr, + IN UINTN Data + ) +; + +EFI_STATUS +VmWriteMem64 ( + IN VM_CONTEXT *VmPtr, + UINTN Addr, + IN UINT64 Data + ) +; + +// +// Define a protocol for an EBC VM test interface. +// +#define EFI_EBC_VM_TEST_PROTOCOL_GUID \ + { \ + 0xAAEACCFDL, 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; + +typedef +EFI_STATUS +(*EBC_VM_TEST_EXECUTE) ( + IN EFI_EBC_VM_TEST_PROTOCOL * This, + IN VM_CONTEXT * VmPtr, + IN OUT UINTN *InstructionCount + ); + +typedef +EFI_STATUS +(*EBC_VM_TEST_ASM) ( + IN EFI_EBC_VM_TEST_PROTOCOL * This, + IN CHAR16 *AsmText, + IN OUT INT8 *Buffer, + IN OUT UINTN *BufferLen + ); + +typedef +EFI_STATUS +(*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; +}; + +EFI_STATUS +EbcExecuteInstructions ( + IN EFI_EBC_VM_TEST_PROTOCOL *This, + IN VM_CONTEXT *VmPtr, + IN OUT UINTN *InstructionCount + ) +; + +#endif // ifndef _EBC_EXECUTE_H_ diff --git a/EdkModulePkg/Universal/Ebc/Dxe/EbcInt.c b/EdkModulePkg/Universal/Ebc/Dxe/EbcInt.c new file mode 100644 index 0000000000..220c8fefac --- /dev/null +++ b/EdkModulePkg/Universal/Ebc/Dxe/EbcInt.c @@ -0,0 +1,932 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + EbcInt.c + +Abstract: + + Top level module for the EBC virtual machine implementation. + Provides auxilliary support routines for the VM. That is, routines + that are not particularly related to VM execution of EBC instructions. + +--*/ + +#include "EbcInt.h" +#include "EbcExecute.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 { + VOID *ThunkBuffer; + struct _EBC_THUNK_LIST *Next; +} EBC_THUNK_LIST; + +typedef struct _EBC_IMAGE_LIST { + struct _EBC_IMAGE_LIST *Next; + EFI_HANDLE ImageHandle; + EBC_THUNK_LIST *ThunkList; +} EBC_IMAGE_LIST; + +// +// Function prototypes +// +EFI_STATUS +EFIAPI +InitializeEbcDriver ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +STATIC +EFI_STATUS +EFIAPI +EbcUnloadImage ( + IN EFI_EBC_PROTOCOL *This, + IN EFI_HANDLE ImageHandle + ); + +STATIC +EFI_STATUS +EFIAPI +EbcCreateThunk ( + IN EFI_EBC_PROTOCOL *This, + IN EFI_HANDLE ImageHandle, + IN VOID *EbcEntryPoint, + OUT VOID **Thunk + ); + +STATIC +EFI_STATUS +EFIAPI +EbcGetVersion ( + IN EFI_EBC_PROTOCOL *This, + IN OUT UINT64 *Version + ); + +// +// These two functions and the GUID are used to produce an EBC test protocol. +// This functionality is definitely not required for execution. +// +STATIC +EFI_STATUS +InitEbcVmTestProtocol ( + IN EFI_HANDLE *Handle + ); + +STATIC +EFI_STATUS +EbcVmTestUnsupported ( + VOID + ); + +STATIC +EFI_STATUS +EFIAPI +EbcRegisterICacheFlush ( + IN EFI_EBC_PROTOCOL *This, + IN EBC_ICACHE_FLUSH Flush + ); + +STATIC +EFI_STATUS +EFIAPI +EbcDebugGetMaximumProcessorIndex ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + OUT UINTN *MaxProcessorIndex + ); + +STATIC +EFI_STATUS +EFIAPI +EbcDebugRegisterPeriodicCallback ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + IN UINTN ProcessorIndex, + IN EFI_PERIODIC_CALLBACK PeriodicCallback + ); + +STATIC +EFI_STATUS +EFIAPI +EbcDebugRegisterExceptionCallback ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + IN UINTN ProcessorIndex, + IN EFI_EXCEPTION_CALLBACK ExceptionCallback, + IN EFI_EXCEPTION_TYPE ExceptionType + ); + +STATIC +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. +// +static EBC_IMAGE_LIST *mEbcImageList = NULL; + +// +// Callback function to flush the icache after thunk creation +// +static EBC_ICACHE_FLUSH mEbcICacheFlush; + +// +// These get set via calls by the debug agent +// +static EFI_PERIODIC_CALLBACK mDebugPeriodicCallback = NULL; +static EFI_EXCEPTION_CALLBACK mDebugExceptionCallback = NULL; +static EFI_GUID mEfiEbcVmTestProtocolGuid = EFI_EBC_VM_TEST_PROTOCOL_GUID; + +EFI_STATUS +EFIAPI +InitializeEbcDriver ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Initializes the VM EFI interface. Allocates memory for the VM interface + and registers the VM protocol. + +Arguments: + + ImageHandle - EFI image handle. + SystemTable - Pointer to the EFI system table. + +Returns: + Standard EFI status code. + +--*/ +{ + 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; + + // + // Allocate memory for our protocol. Then fill in the blanks. + // + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (EFI_EBC_PROTOCOL), + (VOID **) &EbcProtocol + ); + if (Status != EFI_SUCCESS) { + 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) { + gBS->FreePool (HandleBuffer); + HandleBuffer = NULL; + } + // + // Add the protocol so someone can locate us if we haven't already. + // + if (!Installed) { + Status = gBS->InstallProtocolInterface ( + &ImageHandle, + &gEfiEbcProtocolGuid, + EFI_NATIVE_INTERFACE, + EbcProtocol + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (EbcProtocol); + return Status; + } + } + // + // Allocate memory for our debug protocol. Then fill in the blanks. + // + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (EFI_DEBUG_SUPPORT_PROTOCOL), + (VOID **) &EbcDebugProtocol + ); + if (Status != EFI_SUCCESS) { + return EFI_OUT_OF_RESOURCES; + } + + 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)) { + gBS->FreePool (EbcDebugProtocol); + } + // + // Produce a VM test interface protocol. Not required for execution. + // + DEBUG_CODE ( + InitEbcVmTestProtocol (&ImageHandle); + ); + + return Status; +} + +STATIC +EFI_STATUS +EFIAPI +EbcCreateThunk ( + IN EFI_EBC_PROTOCOL *This, + IN EFI_HANDLE ImageHandle, + IN VOID *EbcEntryPoint, + OUT VOID **Thunk + ) +/*++ + +Routine Description: + + 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(). + +Arguments: + + This - protocol instance pointer + ImageHandle - handle to the image. The EBC interpreter may use this to keep + track of any resource allocations performed in loading and + executing the image. + EbcEntryPoint - the entry point for the image (as defined in the file header) + Thunk - pointer to thunk pointer where the address of the created + thunk is returned. + +Returns: + + EFI_STATUS + +--*/ +{ + EFI_STATUS Status; + + Status = EbcCreateThunks ( + ImageHandle, + EbcEntryPoint, + Thunk, + FLAG_THUNK_ENTRY_POINT + ); + return Status; +} + +STATIC +EFI_STATUS +EFIAPI +EbcDebugGetMaximumProcessorIndex ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + OUT UINTN *MaxProcessorIndex + ) +/*++ + +Routine Description: + + This EBC debugger protocol service is called by the debug agent + +Arguments: + + This - pointer to the caller's debug support protocol interface + MaxProcessorIndex - pointer to a caller allocated UINTN in which the maximum + processor index is returned. + +Returns: + + Standard EFI_STATUS + +--*/ +{ + *MaxProcessorIndex = 0; + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +EbcDebugRegisterPeriodicCallback ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + IN UINTN ProcessorIndex, + IN EFI_PERIODIC_CALLBACK PeriodicCallback + ) +/*++ + +Routine Description: + + This protocol service is called by the debug agent to register a function + for us to call on a periodic basis. + + +Arguments: + + This - pointer to the caller's debug support protocol interface + PeriodicCallback - pointer to the function to call periodically + +Returns: + + Always EFI_SUCCESS + +--*/ +{ + mDebugPeriodicCallback = PeriodicCallback; + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +EbcDebugRegisterExceptionCallback ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + IN UINTN ProcessorIndex, + IN EFI_EXCEPTION_CALLBACK ExceptionCallback, + IN EFI_EXCEPTION_TYPE ExceptionType + ) +/*++ + +Routine Description: + + This protocol service is called by the debug agent to register a function + for us to call when we detect an exception. + + +Arguments: + + This - pointer to the caller's debug support protocol interface + PeriodicCallback - pointer to the function to call periodically + +Returns: + + Always EFI_SUCCESS + +--*/ +{ + mDebugExceptionCallback = ExceptionCallback; + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +EbcDebugInvalidateInstructionCache ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + IN UINTN ProcessorIndex, + IN VOID *Start, + IN UINT64 Length + ) +/*++ + +Routine Description: + + This EBC debugger protocol service is called by the debug agent. Required + for DebugSupport compliance but is only stubbed out for EBC. + +Arguments: + +Returns: + + EFI_SUCCESS + +--*/ +{ + return EFI_SUCCESS; +} + +EFI_STATUS +EbcDebugSignalException ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN EXCEPTION_FLAGS ExceptionFlags, + IN VM_CONTEXT *VmPtr + ) +/*++ + +Routine Description: + + The VM interpreter calls this function when an exception is detected. + +Arguments: + + VmPtr - pointer to a VM context for passing info to the EFI debugger. + +Returns: + + EFI_SUCCESS if it returns at all + +--*/ +{ + EFI_SYSTEM_CONTEXT_EBC EbcContext; + EFI_SYSTEM_CONTEXT SystemContext; + EFI_STATUS_CODE_VALUE StatusCodeValue; + BOOLEAN Report; + // + // Save the exception in the context passed in + // + VmPtr->ExceptionFlags |= ExceptionFlags; + VmPtr->LastException = 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) { + VmPtr->StopFlags |= STOPFLAG_APP_DONE; + } + // + // Initialize the context structure + // + EbcContext.R0 = VmPtr->R[0]; + EbcContext.R1 = VmPtr->R[1]; + EbcContext.R2 = VmPtr->R[2]; + EbcContext.R3 = VmPtr->R[3]; + EbcContext.R4 = VmPtr->R[4]; + EbcContext.R5 = VmPtr->R[5]; + EbcContext.R6 = VmPtr->R[6]; + EbcContext.R7 = VmPtr->R[7]; + EbcContext.Ip = (UINT64) (UINTN) VmPtr->Ip; + EbcContext.Flags = VmPtr->Flags; + SystemContext.SystemContextEbc = &EbcContext; + // + // If someone's registered for exception callbacks, then call them. + // Otherwise report the status code via the status code API + // + if (mDebugExceptionCallback != NULL) { + mDebugExceptionCallback (ExceptionType, SystemContext); + } + // + // Determine if we should report the exception. We report all of them by default, + // but if a debugger is attached don't report the breakpoint, debug, and step exceptions. + // Note that EXCEPT_EBC_OVERFLOW is never reported by this VM implementation, so is + // not included in the switch statement. + // + Report = TRUE; + switch (ExceptionType) { + case EXCEPT_EBC_UNDEFINED: + StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_UNDEFINED; + break; + + case EXCEPT_EBC_DIVIDE_ERROR: + StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_DIVIDE_ERROR; + break; + + case EXCEPT_EBC_DEBUG: + StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_DEBUG; + Report = (BOOLEAN) ((mDebugExceptionCallback == NULL) ? TRUE : FALSE); + break; + + case EXCEPT_EBC_BREAKPOINT: + StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_BREAKPOINT; + Report = (BOOLEAN) ((mDebugExceptionCallback == NULL) ? TRUE : FALSE); + break; + + case EXCEPT_EBC_INVALID_OPCODE: + StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_INVALID_OPCODE; + break; + + case EXCEPT_EBC_STACK_FAULT: + StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_STACK_FAULT; + break; + + case EXCEPT_EBC_ALIGNMENT_CHECK: + StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_ALIGNMENT_CHECK; + break; + + case EXCEPT_EBC_INSTRUCTION_ENCODING: + StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_INSTRUCTION_ENCODING; + break; + + case EXCEPT_EBC_BAD_BREAK: + StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_BAD_BREAK; + break; + + case EXCEPT_EBC_STEP: + StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_STEP; + Report = (BOOLEAN) ((mDebugExceptionCallback == NULL) ? TRUE : FALSE); + break; + + default: + StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_NON_SPECIFIC; + break; + } + // + // If we determined that we should report the condition, then do so now. + // + if (Report) { + REPORT_STATUS_CODE (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED, StatusCodeValue); + } + + switch (ExceptionType) { + // + // If ReportStatusCode returned, then for most exceptions we do an assert. The + // ExceptionType++ is done simply to force the ASSERT() condition to be met. + // For breakpoints, assume a debugger did not insert a software breakpoint + // and skip the instruction. + // + case EXCEPT_EBC_BREAKPOINT: + VmPtr->Ip += 2; + break; + + case EXCEPT_EBC_STEP: + break; + + case EXCEPT_EBC_UNDEFINED: + ExceptionType++; + ASSERT (ExceptionType == EXCEPT_EBC_UNDEFINED); + break; + + case EXCEPT_EBC_DIVIDE_ERROR: + ExceptionType++; + ASSERT (ExceptionType == EXCEPT_EBC_DIVIDE_ERROR); + break; + + case EXCEPT_EBC_DEBUG: + ExceptionType++; + ASSERT (ExceptionType == EXCEPT_EBC_DEBUG); + break; + + case EXCEPT_EBC_INVALID_OPCODE: + ExceptionType++; + ASSERT (ExceptionType == EXCEPT_EBC_INVALID_OPCODE); + break; + + case EXCEPT_EBC_STACK_FAULT: + ExceptionType++; + ASSERT (ExceptionType == EXCEPT_EBC_STACK_FAULT); + break; + + case EXCEPT_EBC_ALIGNMENT_CHECK: + ExceptionType++; + ASSERT (ExceptionType == EXCEPT_EBC_ALIGNMENT_CHECK); + break; + + case EXCEPT_EBC_INSTRUCTION_ENCODING: + ExceptionType++; + ASSERT (ExceptionType == EXCEPT_EBC_INSTRUCTION_ENCODING); + break; + + case EXCEPT_EBC_BAD_BREAK: + ExceptionType++; + ASSERT (ExceptionType == EXCEPT_EBC_BAD_BREAK); + break; + + default: + // + // Unknown + // + ASSERT (0); + break; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EbcDebugPeriodic ( + IN VM_CONTEXT *VmPtr + ) +/*++ + +Routine Description: + + The VM interpreter calls this function on a periodic basis to support + the EFI debug support protocol. + +Arguments: + + VmPtr - pointer to a VM context for passing info to the debugger. + +Returns: + + Standard EFI status. + +--*/ +{ + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +EbcUnloadImage ( + IN EFI_EBC_PROTOCOL *This, + IN EFI_HANDLE ImageHandle + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + This - protocol instance pointer + ImageHandle - handle to the image being unloaded. + +Returns: + + EFI_INVALID_PARAMETER - the ImageHandle passed in was not found in + the internal list of EBC image handles. + EFI_STATUS - completed successfully + +--*/ +{ + 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. + // + 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; + gBS->FreePool (ThunkList->ThunkBuffer); + gBS->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 + // + gBS->FreePool (ImageList); + return EFI_SUCCESS; +} + +EFI_STATUS +EbcAddImageThunk ( + IN EFI_HANDLE ImageHandle, + IN VOID *ThunkBuffer, + IN UINT32 ThunkSize + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + ImageHandle - the image handle to which the thunk is tied + ThunkBuffer - the buffer we've created/allocated + ThunkSize - the size of the thunk memory allocated + +Returns: + + EFI_OUT_OF_RESOURCES - memory allocation failed + EFI_SUCCESS - successful completion + +--*/ +{ + 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 + // + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (EBC_IMAGE_LIST), + (VOID **) &ImageList + ); + if (Status != EFI_SUCCESS) { + 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 + // + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (EBC_THUNK_LIST), + (VOID **) &ThunkList + ); + if (Status != EFI_SUCCESS) { + 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; +} + +STATIC +EFI_STATUS +EFIAPI +EbcRegisterICacheFlush ( + IN EFI_EBC_PROTOCOL *This, + IN EBC_ICACHE_FLUSH Flush + ) +{ + mEbcICacheFlush = Flush; + return EFI_SUCCESS; +} + +STATIC +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; +} + +STATIC +EFI_STATUS +InitEbcVmTestProtocol ( + IN EFI_HANDLE *IHandle + ) +/*++ + +Routine Description: + + Produce an EBC VM test protocol that can be used for regression tests. + +Arguments: + + IHandle - handle on which to install the protocol. + +Returns: + + EFI_OUT_OF_RESOURCES - memory allocation failed + EFI_SUCCESS - successful completion + +--*/ +{ + EFI_HANDLE Handle; + EFI_STATUS Status; + EFI_EBC_VM_TEST_PROTOCOL *EbcVmTestProtocol; + + // + // Allocate memory for the protocol, then fill in the fields + // + Status = gBS->AllocatePool (EfiBootServicesData, sizeof (EFI_EBC_VM_TEST_PROTOCOL), (VOID **) &EbcVmTestProtocol); + if (Status != EFI_SUCCESS) { + return EFI_OUT_OF_RESOURCES; + } + EbcVmTestProtocol->Execute = (EBC_VM_TEST_EXECUTE) EbcExecuteInstructions; + + DEBUG_CODE( + EbcVmTestProtocol->Assemble = (EBC_VM_TEST_ASM) EbcVmTestUnsupported; + EbcVmTestProtocol->Disassemble = (EBC_VM_TEST_DASM) EbcVmTestUnsupported; + ); + + // + // Publish the protocol + // + Handle = NULL; + Status = gBS->InstallProtocolInterface (&Handle, &mEfiEbcVmTestProtocolGuid, EFI_NATIVE_INTERFACE, EbcVmTestProtocol); + if (EFI_ERROR (Status)) { + gBS->FreePool (EbcVmTestProtocol); + } + return Status; +} +STATIC +EFI_STATUS +EbcVmTestUnsupported () +{ + return EFI_UNSUPPORTED; +} + diff --git a/EdkModulePkg/Universal/Ebc/Dxe/EbcInt.h b/EdkModulePkg/Universal/Ebc/Dxe/EbcInt.h new file mode 100644 index 0000000000..51bd785a53 --- /dev/null +++ b/EdkModulePkg/Universal/Ebc/Dxe/EbcInt.h @@ -0,0 +1,231 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + EbcInt.h + +Abstract: + + Main routines for the EBC interpreter. Includes the initialization and + main interpreter routines. + +--*/ + +#ifndef _EBC_INT_H_ +#define _EBC_INT_H_ + +typedef INT64 VM_REGISTER; +typedef UINT8 *VMIP; // instruction pointer for the VM +typedef UINT32 EXCEPTION_FLAGS; + +typedef struct { + VM_REGISTER R[8]; // General purpose registers. + UINT64 Flags; // Flags register: + // 0 Set to 1 if the result of the last compare was true + // 1 Set to 1 if stepping + // 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; +} VM_CONTEXT; + +// +// 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 +// +// 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 + +EFI_STATUS +EbcCreateThunks ( + IN EFI_HANDLE ImageHandle, + IN VOID *EbcEntryPoint, + OUT VOID **Thunk, + IN UINT32 Flags + ) +; + +EFI_STATUS +EbcAddImageThunk ( + IN EFI_HANDLE ImageHandle, + IN VOID *ThunkBuffer, + IN UINT32 ThunkSize + ) +; + +// +// The interpreter calls these when an exception is detected, +// or as a periodic callback. +// +EFI_STATUS +EbcDebugSignalException ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN EXCEPTION_FLAGS ExceptionFlags, + IN VM_CONTEXT *VmPtr + ) +; + +// +// Define a constant of how often to call the debugger periodic callback +// function. +// +#define EBC_VM_PERIODIC_CALLBACK_RATE 1000 + +EFI_STATUS +EbcDebugSignalPeriodic ( + IN VM_CONTEXT *VmPtr + ) +; + +// +// External low level functions that are native-processor dependent +// +UINTN +EbcLLGetEbcEntryPoint ( + VOID + ) +; + +UINTN +EbcLLGetStackPointer ( + VOID + ) +; + +VOID +EbcLLCALLEXNative ( + IN UINTN CallAddr, + IN UINTN EbcSp, + IN VOID *FramePtr + ) +; + +VOID +EbcLLCALLEX ( + IN VM_CONTEXT *VmPtr, + IN UINTN CallAddr, + IN UINTN EbcSp, + IN VOID *FramePtr, + IN UINT8 Size + ) +; + +INT64 +EbcLLGetReturnValue ( + VOID + ) +; + +// +// Defines for a simple EBC debugger interface +// +typedef struct _EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL; + +#define EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL_GUID \ + { \ + 0x2a72d11e, 0x7376, 0x40f6, { 0x9c, 0x68, 0x23, 0xfa, 0x2f, 0xe3, 0x63, 0xf1 } \ + } + +typedef +EFI_STATUS +(*EBC_DEBUGGER_SIGNAL_EXCEPTION) ( + IN EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL * This, + IN VM_CONTEXT * VmPtr, + IN EFI_EXCEPTION_TYPE ExceptionType + ); + +typedef +VOID +(*EBC_DEBUGGER_DEBUG) ( + IN EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL * This, + IN VM_CONTEXT * VmPtr + ); + +typedef +UINT32 +(*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. +// +typedef +EFI_STATUS +(*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; +}; + +typedef struct { + EFI_EBC_PROTOCOL *This; + VOID *EntryPoint; + EFI_HANDLE ImageHandle; + VM_CONTEXT VmContext; +} EFI_EBC_THUNK_DATA; + +#define EBC_PROTOCOL_PRIVATE_DATA_SIGNATURE EFI_SIGNATURE_32 ('e', 'b', 'c', 'p') + +struct _EBC_PROTOCOL_PRIVATE_DATA { + UINT32 Signature; + EFI_EBC_PROTOCOL EbcProtocol; + UINTN StackBase; + UINTN StackTop; + UINTN StackSize; +} ; + +#define EBC_PROTOCOL_PRIVATE_DATA_FROM_THIS(a) \ + CR(a, EBC_PROTOCOL_PRIVATE_DATA, EbcProtocol, EBC_PROTOCOL_PRIVATE_DATA_SIGNATURE) + + +#endif // #ifndef _EBC_INT_H_ diff --git a/EdkModulePkg/Universal/Ebc/Dxe/Ia32/EbcLowLevel.asm b/EdkModulePkg/Universal/Ebc/Dxe/Ia32/EbcLowLevel.asm new file mode 100644 index 0000000000..b485bc9fd2 --- /dev/null +++ b/EdkModulePkg/Universal/Ebc/Dxe/Ia32/EbcLowLevel.asm @@ -0,0 +1,148 @@ + page ,132 + title VM ASSEMBLY LANGUAGE ROUTINES +;**************************************************************************** +;* +;* Copyright (c) 2006, Intel Corporation +;* All rights reserved. This program and the accompanying materials +;* are licensed and made available under the terms and conditions of the BSD License +;* which accompanies this distribution. The full text of the license may be found at +;* http://opensource.org/licenses/bsd-license.php +;* +;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +;* +;**************************************************************************** +;**************************************************************************** +; REV 1.0 +;**************************************************************************** +; +; Rev Date Description +; --- -------- ------------------------------------------------------------ +; 1.0 03/14/01 Initial creation of file. +; +;**************************************************************************** + +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +; This code provides low level routines that support the Virtual Machine +; for option ROMs. +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +;--------------------------------------------------------------------------- +; Equate files needed. +;--------------------------------------------------------------------------- + +.XLIST + +.LIST + +;--------------------------------------------------------------------------- +; Assembler options +;--------------------------------------------------------------------------- + +.686p +.model flat +.code +;--------------------------------------------------------------------------- +;;GenericPostSegment SEGMENT USE16 +;--------------------------------------------------------------------------- + +;**************************************************************************** +; 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. +;**************************************************************************** +; VOID EbcLLCALLEXNative(UINTN FuncAddr, UINTN NewStackPointer, VOID *FramePtr) +_EbcLLCALLEXNative PROC NEAR PUBLIC + push ebp + mov ebp, esp ; standard function prolog + + ; Get function address in a register + ; mov ecx, FuncAddr => mov ecx, dword ptr [FuncAddr] + mov ecx, dword ptr [esp]+8 + + ; Set stack pointer to new value + ; mov eax, NewStackPointer => mov eax, dword ptr [NewSp] + mov eax, dword ptr [esp] + 0Ch + mov esp, eax + + ; 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 ebp + ret +_EbcLLCALLEXNative ENDP + + +; UINTN EbcLLGetEbcEntryPoint(VOID); +; Routine Description: +; 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. +; +; Arguments: +; None. +; +; Returns: +; The contents of the register in which the entry point is passed. +; +_EbcLLGetEbcEntryPoint PROC NEAR PUBLIC + ret +_EbcLLGetEbcEntryPoint ENDP + +;/*++ +; +;Routine Description: +; +; Return the caller's value of the stack pointer. +; +;Arguments: +; +; None. +; +;Returns: +; +; The current value of the stack pointer for the caller. We +; adjust it by 4 here because when they called us, the return address +; is put on the stack, thereby lowering it by 4 bytes. +; +;--*/ + +; UINTN EbcLLGetStackPointer() +_EbcLLGetStackPointer PROC NEAR PUBLIC + mov eax, esp ; get current stack pointer + add eax, 4 ; stack adjusted by this much when we were called + ret +_EbcLLGetStackPointer ENDP + +; UINT64 EbcLLGetReturnValue(VOID); +; Routine Description: +; When EBC calls native, on return the VM has to stuff the return +; value into a VM register. It's assumed here that the value is still +; in the register, so simply return and the caller should get the +; return result properly. +; +; Arguments: +; None. +; +; Returns: +; The unmodified value returned by the native code. +; +_EbcLLGetReturnValue PROC NEAR PUBLIC + ret +_EbcLLGetReturnValue ENDP + +END diff --git a/EdkModulePkg/Universal/Ebc/Dxe/Ia32/EbcSupport.c b/EdkModulePkg/Universal/Ebc/Dxe/Ia32/EbcSupport.c new file mode 100644 index 0000000000..14059d71e5 --- /dev/null +++ b/EdkModulePkg/Universal/Ebc/Dxe/Ia32/EbcSupport.c @@ -0,0 +1,482 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + EbcSupport.c + +Abstract: + + This module contains EBC support routines that are customized based on + the target processor. + +--*/ + +#include "EbcInt.h" +#include "EbcExecute.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 EBC_THUNK_SIZE 32 + +VOID +EbcLLCALLEX ( + IN VM_CONTEXT *VmPtr, + IN UINTN FuncAddr, + IN UINTN NewStackPointer, + IN VOID *FramePtr, + IN UINT8 Size + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + VmPtr - Pointer to a VM context. + FuncAddr - Callee's address + NewStackPointer - New stack pointer after the call + FramePtr - New frame pointer after the call + Size - The size of call instruction + +Returns: + + None. + +--*/ +{ + UINTN IsThunk; + UINTN TargetEbcAddr; + + IsThunk = 1; + TargetEbcAddr = 0; + + // + // Processor specific code to check whether the callee is a thunk to EBC. + // + if (*((UINT8 *)FuncAddr) != 0xB8) { + IsThunk = 0; + goto Action; + } + if (*((UINT8 *)FuncAddr + 1) != 0xBC) { + IsThunk = 0; + goto Action; + } + if (*((UINT8 *)FuncAddr + 2) != 0x2E) { + IsThunk = 0; + goto Action; + } + if (*((UINT8 *)FuncAddr + 3) != 0x11) { + IsThunk = 0; + goto Action; + } + if (*((UINT8 *)FuncAddr + 4) != 0xCA) { + IsThunk = 0; + goto Action; + } + if (*((UINT8 *)FuncAddr + 5) != 0xB8) { + IsThunk = 0; + goto Action; + } + if (*((UINT8 *)FuncAddr + 10) != 0xB9) { + IsThunk = 0; + goto Action; + } + if (*((UINT8 *)FuncAddr + 15) != 0xFF) { + IsThunk = 0; + goto Action; + } + if (*((UINT8 *)FuncAddr + 16) != 0xE1) { + IsThunk = 0; + goto Action; + } + + TargetEbcAddr = ((UINTN)(*((UINT8 *)FuncAddr + 9)) << 24) + ((UINTN)(*((UINT8 *)FuncAddr + 8)) << 16) + + ((UINTN)(*((UINT8 *)FuncAddr + 7)) << 8) + ((UINTN)(*((UINT8 *)FuncAddr + 6))); + +Action: + 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->R[0] -= 8; + VmWriteMemN (VmPtr, (UINTN) VmPtr->R[0], (UINTN) FramePtr); + VmPtr->FramePtr = (VOID *) (UINTN) VmPtr->R[0]; + VmPtr->R[0] -= 8; + VmWriteMem64 (VmPtr, (UINTN) VmPtr->R[0], (UINT64) (UINTN) (VmPtr->Ip + Size)); + + VmPtr->Ip = (VMIP) (UINTN) TargetEbcAddr; + } else { + // + // The callee is not a thunk to EBC, call native code. + // + EbcLLCALLEXNative (FuncAddr, NewStackPointer, FramePtr); + + // + // Get return value and advance the IP. + // + VmPtr->R[7] = EbcLLGetReturnValue (); + VmPtr->Ip += Size; + } +} + +STATIC +UINT64 +EbcInterpret ( + IN OUT UINTN Arg1, + IN OUT UINTN Arg2, + IN OUT UINTN Arg3, + IN OUT UINTN Arg4, + IN OUT UINTN Arg5, + IN OUT UINTN Arg6, + IN OUT UINTN Arg7, + IN OUT UINTN Arg8 + ) +/*++ + +Routine Description: + + Begin executing an EBC image. The address of the entry point is passed + in via a processor register, so we'll need to make a call to get the + value. + +Arguments: + + None. Since we're called from a fixed up thunk (which we want to keep + small), our only so-called argument is the EBC entry point passed in + to us in a processor register. + +Returns: + + The value returned by the EBC application we're going to run. + +--*/ +{ + // + // Create a new VM context on the stack + // + VM_CONTEXT VmContext; + UINTN Addr; + + // + // Get the EBC entry point from the processor register. + // + Addr = EbcLLGetEbcEntryPoint (); + + // + // 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. + // + Addr = EbcLLGetStackPointer (); + + VmContext.R[0] = (UINT64) Addr; + VmContext.R[0] -= VM_STACK_SIZE; + + // + // Align the stack on a natural boundary + // + VmContext.R[0] &= ~(sizeof (UINTN) - 1); + + // + // Put a magic value in the stack gap, then adjust down again + // + *(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) VM_STACK_KEY_VALUE; + VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.R[0]; + VmContext.R[0] -= sizeof (UINTN); + + // + // For IA32, this is where we say our return address is + // + VmContext.StackRetAddr = (UINT64) VmContext.R[0]; + VmContext.LowStackTop = (UINTN) VmContext.R[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)); + // + VmContext.HighStackBottom = (UINTN) &Arg1 - 16; + // + // Begin executing the EBC code + // + EbcExecute (&VmContext); + + // + // Return the value in R[7] unless there was an error + // + return (UINT64) VmContext.R[7]; +} + +STATIC +UINT64 +ExecuteEbcImageEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Begin executing an EBC image. The address of the entry point is passed + in via a processor register, so we'll need to make a call to get the + value. + +Arguments: + + ImageHandle - image handle for the EBC application we're executing + SystemTable - standard system table passed into an driver's entry point + +Returns: + + The value returned by the EBC application we're going to run. + +--*/ +{ + // + // Create a new VM context on the stack + // + VM_CONTEXT VmContext; + UINTN Addr; + + // + // Get the EBC entry point from the processor register. Make sure you don't + // call any functions before this or you could mess up the register the + // entry point is passed in. + // + Addr = EbcLLGetEbcEntryPoint (); + + // + // Print(L"*** Thunked into EBC entry point - ImageHandle = 0x%X\n", (UINTN)ImageHandle); + // Print(L"EBC entry point is 0x%X\n", (UINT32)(UINTN)Addr); + // + // 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. + // + Addr = EbcLLGetStackPointer (); + VmContext.R[0] = (UINT64) Addr; + VmContext.R[0] -= VM_STACK_SIZE; + // + // Put a magic value in the stack gap, then adjust down again + // + *(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) VM_STACK_KEY_VALUE; + VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.R[0]; + VmContext.R[0] -= sizeof (UINTN); + + // + // Align the stack on a natural boundary + // VmContext.R[0] &= ~(sizeof(UINTN) - 1); + // + VmContext.StackRetAddr = (UINT64) VmContext.R[0]; + VmContext.LowStackTop = (UINTN) VmContext.R[0]; + // + // VM pushes 16-bytes for return address. Simulate that here. + // + VmContext.HighStackBottom = (UINTN) &ImageHandle - 16; + + // + // Begin executing the EBC code + // + EbcExecute (&VmContext); + + // + // Return the value in R[7] unless there was an error + // + return (UINT64) VmContext.R[7]; +} + +EFI_STATUS +EbcCreateThunks ( + IN EFI_HANDLE ImageHandle, + IN VOID *EbcEntryPoint, + OUT VOID **Thunk, + IN UINT32 Flags + ) +/*++ + +Routine Description: + + Create an IA32 thunk for the given EBC entry point. + +Arguments: + + ImageHandle - Handle of image for which this thunk is being created + EbcEntryPoint - Address of the EBC code that the thunk is to call + Thunk - Returned thunk we create here + +Returns: + + Standard EFI status. + +--*/ +{ + UINT8 *Ptr; + UINT8 *ThunkBase; + UINT32 I; + UINT32 Addr; + INT32 Size; + INT32 ThunkSize; + EFI_STATUS Status; + + // + // Check alignment of pointer to EBC code + // + if ((UINT32) (UINTN) EbcEntryPoint & 0x01) { + return EFI_INVALID_PARAMETER; + } + + Size = EBC_THUNK_SIZE; + ThunkSize = Size; + + Status = gBS->AllocatePool ( + EfiBootServicesData, + Size, + (VOID *) &Ptr + ); + if (Status != EFI_SUCCESS) { + 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; + + // + // Add a magic code here to help the VM recognize the thunk.. + // mov eax, 0xca112ebc => B8 BC 2E 11 CA + // + *Ptr = 0xB8; + Ptr++; + Size--; + Addr = (UINT32) 0xCA112EBC; + for (I = 0; I < sizeof (Addr); I++) { + *Ptr = (UINT8) (UINTN) Addr; + Addr >>= 8; + Ptr++; + Size--; + } + + // + // Add code bytes to load up a processor register with the EBC entry point. + // mov eax, 0xaa55aa55 => B8 55 AA 55 AA + // The first 8 bytes of the thunk entry is the address of the EBC + // entry point. + // + *Ptr = 0xB8; + Ptr++; + Size--; + Addr = (UINT32) EbcEntryPoint; + for (I = 0; I < sizeof (Addr); I++) { + *Ptr = (UINT8) (UINTN) Addr; + Addr >>= 8; + Ptr++; + Size--; + } + // + // Stick in a load of ecx with the address of appropriate VM function. + // mov ecx 12345678h => 0xB9 0x78 0x56 0x34 0x12 + // + if (Flags & FLAG_THUNK_ENTRY_POINT) { + Addr = (UINT32) (UINTN) ExecuteEbcImageEntryPoint; + } else { + Addr = (UINT32) (UINTN) EbcInterpret; + } + + // + // MOV ecx + // + *Ptr = 0xB9; + Ptr++; + Size--; + for (I = 0; I < sizeof (Addr); I++) { + *Ptr = (UINT8) Addr; + Addr >>= 8; + Ptr++; + Size--; + } + // + // Stick in jump opcode bytes for jmp ecx => 0xFF 0xE1 + // + *Ptr = 0xFF; + Ptr++; + Size--; + *Ptr = 0xE1; + Size--; + + // + // Double check that our defined size is ok (application error) + // + if (Size < 0) { + ASSERT (FALSE); + return EFI_BUFFER_TOO_SMALL; + } + // + // 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/EdkModulePkg/Universal/Ebc/Dxe/Ia32/Ia32Math.asm b/EdkModulePkg/Universal/Ebc/Dxe/Ia32/Ia32Math.asm new file mode 100644 index 0000000000..4c91a2730b --- /dev/null +++ b/EdkModulePkg/Universal/Ebc/Dxe/Ia32/Ia32Math.asm @@ -0,0 +1,622 @@ + TITLE Ia32math.asm: Generic math routines for EBC interpreter running on IA32 processor + +;------------------------------------------------------------------------------ +; +; Copyright (c) 2006, Intel Corporation +; All rights reserved. This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +; Module Name: +; +; Ia32math.asm +; +; Abstract: +; +; Generic math routines for EBC interpreter running on IA32 processor +; +;------------------------------------------------------------------------------ + + .686P + .XMM + .MODEL SMALL + .CODE + +LeftShiftU64 PROTO C Operand: QWORD, CountIn: QWORD +RightShiftU64 PROTO C Operand: QWORD, CountIn: QWORD +ARightShift64 PROTO C Operand: QWORD, CountIn: QWORD +MulU64x64 PROTO C Value1: QWORD, Value2: QWORD, ResultHigh: DWORD +MulS64x64 PROTO C Value1: QWORD, Value2: QWORD, ResultHigh: DWORD +DivU64x64 PROTO C Dividend: QWORD, Divisor: QWORD, Remainder: DWORD, Error: DWORD +DivS64x64 PROTO C Dividend: QWORD, Divisor: QWORD, Remainder: DWORD, Error: DWORD + + +LeftShiftU64 PROC C Operand: QWORD, CountIn: QWORD + +;------------------------------------------------------------------------------ +; UINT64 +; LeftShiftU64 ( +; IN UINT64 Operand, +; IN UINT64 CountIn +; ) +; +; Routine Description: +; +; Left-shift a 64-bit value. +; +; Arguments: +; +; Operand - the value to shift +; Count - shift count +; +; Returns: +; +; Operand << Count +;------------------------------------------------------------------------------ + + push ecx + ; + ; if (CountIn > 63) return 0; + ; + cmp dword ptr CountIn[4], 0 + jne _LeftShiftU64_Overflow + mov ecx, dword ptr CountIn[0] + cmp ecx, 63 + jbe _LeftShiftU64_Calc + +_LeftShiftU64_Overflow: + xor eax, eax + xor edx, edx + jmp _LeftShiftU64_Done + +_LeftShiftU64_Calc: + mov eax, dword ptr Operand[0] + mov edx, dword ptr Operand[4] + + shld edx, eax, cl + shl eax, cl + cmp ecx, 32 + jc short _LeftShiftU64_Done + + mov edx, eax + xor eax, eax + +_LeftShiftU64_Done: + pop ecx + ret + +LeftShiftU64 ENDP + + +RightShiftU64 PROC C Operand: QWORD, CountIn: QWORD + +;------------------------------------------------------------------------------ +; UINT64 +; RightShiftU64 ( +; IN UINT64 Operand, +; IN UINT64 CountIn +; ) +; +; Routine Description: +; +; Right-shift an unsigned 64-bit value. +; +; Arguments: +; +; Operand - the value to shift +; Count - shift count +; +; Returns: +; +; Operand >> Count +;------------------------------------------------------------------------------ + + push ecx + ; + ; if (CountIn > 63) return 0; + ; + cmp dword ptr CountIn[4], 0 + jne _RightShiftU64_Overflow + mov ecx, dword ptr CountIn[0] + cmp ecx, 63 + jbe _RightShiftU64_Calc + +_RightShiftU64_Overflow: + xor eax, eax + xor edx, edx + jmp _RightShiftU64_Done + +_RightShiftU64_Calc: + mov eax, dword ptr Operand[0] + mov edx, dword ptr Operand[4] + + shrd edx, eax, cl + shr eax, cl + cmp ecx, 32 + jc short _RightShiftU64_Done + + mov eax, edx + xor edx, edx + +_RightShiftU64_Done: + pop ecx + ret + +RightShiftU64 ENDP + + +ARightShift64 PROC C Operand: QWORD, CountIn: QWORD + +;------------------------------------------------------------------------------ +; INT64 +; ARightShift64 ( +; IN INT64 Operand, +; IN UINT64 CountIn +; ) +; +; Routine Description: +; +; Arithmatic shift a 64 bit signed value. +; +; Arguments: +; +; Operand - the value to shift +; Count - shift count +; +; Returns: +; +; Operand >> Count +;------------------------------------------------------------------------------ + + push ecx + ; + ; If they exceeded the max shift count, then return either 0 or all F's + ; depending on the sign bit. + ; + cmp dword ptr CountIn[4], 0 + jne _ARightShiftU64_Overflow + mov ecx, dword ptr CountIn[0] + cmp ecx, 63 + jbe _ARightShiftU64_Calc + +_ARightShiftU64_Overflow: + ; + ; Check the sign bit of Operand + ; + bt dword ptr Operand[4], 31 + jnc _ARightShiftU64_Return_Zero + ; + ; return -1 + ; + or eax, 0FFFFFFFFh + or edx, 0FFFFFFFFh + jmp _ARightShiftU64_Done + +_ARightShiftU64_Return_Zero: + xor eax, eax + xor edx, edx + jmp _ARightShiftU64_Done + +_ARightShiftU64_Calc: + mov eax, dword ptr Operand[0] + mov edx, dword ptr Operand[4] + + shrd eax, edx, cl + sar edx, cl + cmp ecx, 32 + jc short _ARightShiftU64_Done + + ; + ; if ecx >= 32, then eax = edx, and edx = sign bit + ; + mov eax, edx + sar edx, 31 + +_ARightShiftU64_Done: + pop ecx + ret + +ARightShift64 ENDP + + +MulU64x64 PROC C Value1: QWORD, Value2: QWORD, ResultHigh: DWORD + +;------------------------------------------------------------------------------ +; UINT64 +; MulU64x64 ( +; UINT64 Value1, +; UINT64 Value2, +; UINT64 *ResultHigh +; ) +; +; Routine Description: +; +; Multiply two unsigned 64-bit values. +; +; Arguments: +; +; Value1 - first value to multiply +; Value2 - value to multiply by Value1 +; ResultHigh - result to flag overflows +; +; Returns: +; +; Value1 * Value2 +; The 128-bit result is the concatenation of *ResultHigh and the return value +;------------------------------------------------------------------------------ + + push ebx + push ecx + mov ebx, ResultHigh ; ebx points to the high 4 words of result + ; + ; The result consists of four double-words. + ; Here we assume their names from low to high: dw0, dw1, dw2, dw3 + ; + mov eax, dword ptr Value1[0] + mul dword ptr Value2[0] + push eax ; eax contains final result of dw0, push it + mov ecx, edx ; ecx contains partial result of dw1 + + mov eax, dword ptr Value1[4] + mul dword ptr Value2[0] + add ecx, eax ; add eax to partial result of dw1 + adc edx, 0 + mov dword ptr [ebx], edx ; lower double-word of ResultHigh contains partial result of dw2 + + mov eax, dword ptr Value1[0] + mul dword ptr Value2[4] + add ecx, eax ; add eax to partial result of dw1 + push ecx ; ecx contains final result of dw1, push it + adc edx, 0 + mov ecx, edx ; ecx contains partial result of dw2, together with ResultHigh + + mov eax, dword ptr Value1[4] + mul dword ptr Value2[4] + add ecx, eax ; add eax to partial result of dw2 + adc edx, 0 + add dword ptr [ebx], ecx ; lower double-word of ResultHigh contains final result of dw2 + adc edx, 0 + mov dword ptr [ebx + 4], edx ; high double-word of ResultHigh contains final result of dw3 + + pop edx ; edx contains the final result of dw1 + pop eax ; edx contains the final result of dw0 + pop ecx + pop ebx + ret + +MulU64x64 ENDP + + +MulS64x64 PROC C Value1: QWORD, Value2: QWORD, ResultHigh: DWORD + +;------------------------------------------------------------------------------ +; INT64 +; MulS64x64 ( +; INT64 Value1, +; INT64 Value2, +; INT64 *ResultHigh +; ) +; +; Routine Description: +; +; Multiply two signed 64-bit values. +; +; Arguments: +; +; Value1 - first value to multiply +; Value2 - value to multiply by Value1 +; ResultHigh - result to flag overflows +; +; Returns: +; +; Value1 * Value2 +; The 128-bit result is the concatenation of *ResultHigh and the return value +;------------------------------------------------------------------------------ + + push ebx + push ecx + mov ebx, ResultHigh ; ebx points to the high 4 words of result + xor ecx, ecx ; the lowest bit of ecx flags the sign + + mov edx, dword ptr Value1[4] + bt edx, 31 + jnc short _MulS64x64_A_Positive + ; + ; a is negative + ; + mov eax, dword ptr Value1[0] + not edx + not eax + add eax, 1 + adc edx, 0 + mov dword ptr Value1[0], eax + mov dword ptr Value1[4], edx + btc ecx, 0 + +_MulS64x64_A_Positive: + mov edx, dword ptr Value2[4] + bt edx, 31 + jnc short _MulS64x64_B_Positive + ; + ; b is negative + ; + mov eax, dword ptr Value2[0] + not edx + not eax + add eax, 1 + adc edx, 0 + mov dword ptr Value2[0], eax + mov dword ptr Value2[4], edx + btc ecx, 0 + +_MulS64x64_B_Positive: + invoke MulU64x64, Value1, Value2, ResultHigh + bt ecx, 0 + jnc short _MulS64x64_Done + ; + ;negate the result + ; + not eax + not edx + not dword ptr [ebx] + not dword ptr [ebx + 4] + add eax, 1 + adc edx, 0 + adc dword ptr [ebx], 0 + adc dword ptr [ebx + 4], 0 + +_MulS64x64_Done: + pop ecx + pop ebx + ret + +MulS64x64 ENDP + + +DivU64x64 PROC C Dividend: QWORD, Divisor: QWORD, Remainder: DWORD, Error: DWORD, + +;------------------------------------------------------------------------------ +; UINT64 +; DivU64x64 ( +; IN UINT64 Dividend, +; IN UINT64 Divisor, +; OUT UINT64 *Remainder OPTIONAL, +; OUT UINT32 *Error +; ) +; +; Routine Description: +; +; This routine allows a 64 bit value to be divided with a 64 bit value returns +; 64bit result and the Remainder +; +; Arguments: +; +; Dividend - dividend +; Divisor - divisor +; ResultHigh - result to flag overflows +; Error - flag for error +; +; Returns: +; +; Dividend / Divisor +; Remainder = Dividend mod Divisor +;------------------------------------------------------------------------------ + + push ecx + + mov eax, Error + mov dword ptr [eax], 0 + + cmp dword ptr Divisor[0], 0 + jne _DivU64x64_Valid + cmp dword ptr Divisor[4], 0 + jne _DivU64x64_Valid + ; + ; the divisor is zero + ; + mov dword ptr [eax], 1 + cmp Remainder, 0 + je _DivU64x64_Invalid_Return + ; + ; fill the remainder if the pointer is not null + ; + mov eax, Remainder + mov dword ptr [eax], 0 + mov dword ptr [eax + 4], 80000000h + +_DivU64x64_Invalid_Return: + xor eax, eax + mov edx, 80000000h + jmp _DivU64x64_Done + +_DivU64x64_Valid: + ; + ; let edx and eax contain the intermediate result of remainder + ; + xor edx, edx + xor eax, eax + mov ecx, 64 + +_DivU64x64_Wend: + ; + ; shift dividend left one + ; + shl dword ptr Dividend[0], 1 + rcl dword ptr Dividend[4], 1 + ; + ; rotate intermediate result of remainder left one + ; + rcl eax, 1 + rcl edx, 1 + + cmp edx, dword ptr Divisor[4] + ja _DivU64x64_Sub_Divisor + jb _DivU64x64_Cont + cmp eax, dword ptr Divisor[0] + jb _DivU64x64_Cont + +_DivU64x64_Sub_Divisor: + ; + ; If intermediate result of remainder is larger than + ; or equal to divisor, then set the lowest bit of dividend, + ; and subtract divisor from intermediate remainder + ; + bts dword ptr Dividend[0], 0 + sub eax, dword ptr Divisor[0] + sbb edx, dword ptr Divisor[4] + +_DivU64x64_Cont: + loop _DivU64x64_Wend + + cmp Remainder, 0 + je _DivU64x64_Assign + mov ecx, Remainder + mov dword ptr [ecx], eax + mov dword ptr [ecx + 4], edx + +_DivU64x64_Assign: + mov eax, dword ptr Dividend[0] + mov edx, dword ptr Dividend[4] + +_DivU64x64_Done: + pop ecx + ret + +DivU64x64 ENDP + +DivS64x64 PROC C Dividend: QWORD, Divisor: QWORD, Remainder: DWORD, Error: DWORD, + +;------------------------------------------------------------------------------ +; INT64 +; DivU64x64 ( +; IN INT64 Dividend, +; IN INT64 Divisor, +; OUT UINT64 *Remainder OPTIONAL, +; OUT UINT32 *Error +; ) +; +; Routine Description: +; +; This routine allows a 64 bit signed value to be divided with a 64 bit +; signed value returns 64bit result and the Remainder. +; +; Arguments: +; +; Dividend - dividend +; Divisor - divisor +; ResultHigh - result to flag overflows +; Error - flag for error +; +; Returns: +; +; Dividend / Divisor +; Remainder = Dividend mod Divisor +;------------------------------------------------------------------------------ + + push ecx + + mov eax, Error + mov dword ptr [eax], 0 + + cmp dword ptr Divisor[0], 0 + jne _DivS64x64_Valid + cmp dword ptr Divisor[4], 0 + jne _DivS64x64_Valid + ; + ; the divisor is zero + ; + mov dword ptr [eax], 1 + cmp Remainder, 0 + je _DivS64x64_Invalid_Return + ; + ; fill the remainder if the pointer is not null + ; + mov eax, Remainder + mov dword ptr [eax], 0 + mov dword ptr [eax + 4], 80000000h + +_DivS64x64_Invalid_Return: + xor eax, eax + mov edx, 80000000h + jmp _DivS64x64_Done + +_DivS64x64_Valid: + ; + ; The lowest bit of ecx flags the sign of quotient, + ; The seconde lowest bit flags the sign of remainder + ; + xor ecx, ecx + + mov edx, dword ptr Dividend[4] + bt edx, 31 + jnc short _DivS64x64_Dividend_Positive + ; + ; dividend is negative + ; + mov eax, dword ptr Dividend[0] + not edx + not eax + add eax, 1 + adc edx, 0 + mov dword ptr Dividend[0], eax + mov dword ptr Dividend[4], edx + ; + ; set both the flags for signs of quotient and remainder + ; + btc ecx, 0 + btc ecx, 1 + +_DivS64x64_Dividend_Positive: + mov edx, dword ptr Divisor[4] + bt edx, 31 + jnc short _DivS64x64_Divisor_Positive + ; + ; divisor is negative + ; + mov eax, dword ptr Divisor[0] + not edx + not eax + add eax, 1 + adc edx, 0 + mov dword ptr Divisor[0], eax + mov dword ptr Divisor[4], edx + ; + ; just complement the flag for sign of quotient + ; + btc ecx, 0 + +_DivS64x64_Divisor_Positive: + invoke DivU64x64, Dividend, Divisor, Remainder, Error + bt ecx, 0 + jnc short _DivS64x64_Remainder + ; + ; negate the quotient + ; + not eax + not edx + add eax, 1 + adc edx, 0 + +_DivS64x64_Remainder: + bt ecx, 1 + jnc short _DivS64x64_Done + ; + ; negate the remainder + ; + mov ecx, remainder + not dword ptr [ecx] + not dword ptr [ecx + 4] + add dword ptr [ecx], 1 + adc dword ptr [ecx + 4], 0 + +_DivS64x64_Done: + pop ecx + ret + +DivS64x64 ENDP + +END \ No newline at end of file diff --git a/EdkModulePkg/Universal/Ebc/Dxe/Ipf/EbcLowLevel.s b/EdkModulePkg/Universal/Ebc/Dxe/Ipf/EbcLowLevel.s new file mode 100644 index 0000000000..fe2ca3f572 --- /dev/null +++ b/EdkModulePkg/Universal/Ebc/Dxe/Ipf/EbcLowLevel.s @@ -0,0 +1,167 @@ +//++ +// Copyright (c) 2006, Intel Corporation +// All rights reserved. This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// Module Name: +// +// EbcLowLevel.s +// +// Abstract: +// +// Contains low level routines for the Virtual Machine implementation +// on an Itanium-based platform. +// +// +//-- + +.file "EbcLowLevel.s" + +#define PROCEDURE_ENTRY(name) .##text; \ + .##type name, @function; \ + .##proc name; \ +name:: + +#define PROCEDURE_EXIT(name) .##endp name + +// Note: use of NESTED_SETUP requires number of locals (l) >= 3 + +#define NESTED_SETUP(i,l,o,r) \ + alloc loc1=ar##.##pfs,i,l,o,r ;\ + mov loc0=b0 + +#define NESTED_RETURN \ + mov b0=loc0 ;\ + mov ar##.##pfs=loc1 ;;\ + br##.##ret##.##dpnt b0;; + + +//----------------------------------------------------------------------------- +//++ +// EbcAsmLLCALLEX +// +// Implements the low level EBC CALLEX instruction. Sets up the +// stack pointer, does the spill of function arguments, and +// calls the native function. On return it restores the original +// stack pointer and returns to the caller. +// +// Arguments : +// +// On Entry : +// in0 = Address of native code to call +// in1 = New stack pointer +// +// Return Value: +// +// As per static calling conventions. +// +//-- +//--------------------------------------------------------------------------- +;// void EbcAsmLLCALLEX (UINTN FunctionAddr, UINTN EbcStackPointer) +PROCEDURE_ENTRY(EbcAsmLLCALLEX) + NESTED_SETUP (2,6,8,0) + + // NESTED_SETUP uses loc0 and loc1 for context save + + // + // Save a copy of the EBC VM stack pointer + // + mov r8 = in1;; + + // + // Copy stack arguments from EBC stack into registers. + // Assume worst case and copy 8. + // + ld8 out0 = [r8], 8;; + ld8 out1 = [r8], 8;; + ld8 out2 = [r8], 8;; + ld8 out3 = [r8], 8;; + ld8 out4 = [r8], 8;; + ld8 out5 = [r8], 8;; + ld8 out6 = [r8], 8;; + ld8 out7 = [r8], 8;; + + // + // Save the original stack pointer + // + mov loc2 = r12; + + // + // Save the gp + // + or loc3 = r1, r0 + + // + // Set the new aligned stack pointer. Reserve space for the required + // 16-bytes of scratch area as well. + // + add r12 = 48, in1 + + // + // Now call the function. Load up the function address from the descriptor + // pointed to by in0. Then get the gp from the descriptor at the following + // address in the descriptor. + // + ld8 r31 = [in0], 8;; + ld8 r30 = [in0];; + mov b1 = r31 + mov r1 = r30 + (p0) br.call.dptk.many b0 = b1;; + + // + // Restore the original stack pointer and gp + // + mov r12 = loc2 + or r1 = loc3, r0 + + // + // Now return + // + NESTED_RETURN + +PROCEDURE_EXIT(EbcAsmLLCALLEX) + +// +// UINTN EbcLLGetEbcEntryPoint(VOID) +// +// Description: +// Simply return, so that the caller retrieves the return register +// contents (R8). That's where the thunk-to-ebc code stuffed the +// EBC entry point. +// +PROCEDURE_ENTRY(EbcLLGetEbcEntryPoint) + br.ret.sptk b0 ;; +PROCEDURE_EXIT(EbcLLGetEbcEntryPoint) + +// +// INT64 EbcLLGetReturnValue(VOID) +// +// Description: +// This function is called to get the value returned by native code +// to EBC. It simply returns because the return value should still +// be in the register, so the caller just gets the unmodified value. +// +PROCEDURE_ENTRY(EbcLLGetReturnValue) + br.ret.sptk b0 ;; +PROCEDURE_EXIT(EbcLLGetReturnValue) + +// +// UINTN EbcLLGetStackPointer(VOID) +// +PROCEDURE_ENTRY(EbcLLGetStackPointer) + mov r8 = r12 ;; + br.ret.sptk b0 ;; + br.sptk.few b6 +PROCEDURE_EXIT(EbcLLGetStackPointer) + + + + + + + diff --git a/EdkModulePkg/Universal/Ebc/Dxe/Ipf/EbcSupport.c b/EdkModulePkg/Universal/Ebc/Dxe/Ipf/EbcSupport.c new file mode 100644 index 0000000000..50402aadd5 --- /dev/null +++ b/EdkModulePkg/Universal/Ebc/Dxe/Ipf/EbcSupport.c @@ -0,0 +1,906 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + EbcSupport.c + +Abstract: + + This module contains EBC support routines that are customized based on + the target processor. + +--*/ + +#include "EbcInt.h" +#include "EbcExecute.h" + +#define VM_STACK_SIZE (1024 * 32) + +#define EBC_THUNK_SIZE 128 + +// +// For code execution, thunks must be aligned on 16-byte boundary +// +#define EBC_THUNK_ALIGNMENT 16 + +// +// Per the IA-64 Software Conventions and Runtime Architecture Guide, +// section 3.3.4, IPF stack must always be 16-byte aligned. +// +#define IPF_STACK_ALIGNMENT 16 + +// +// Opcodes for IPF instructions. We'll need to hand-create thunk code (stuffing +// bits) to insert a jump to the interpreter. +// +#define OPCODE_NOP (UINT64) 0x00008000000 +#define OPCODE_BR_COND_SPTK_FEW (UINT64) 0x00100000000 +#define OPCODE_MOV_BX_RX (UINT64) 0x00E00100000 + +// +// Opcode for MOVL instruction +// +#define MOVL_OPCODE 0x06 + +VOID +EbcAsmLLCALLEX ( + IN UINTN CallAddr, + IN UINTN EbcSp + ); + +STATIC +EFI_STATUS +WriteBundle ( + IN VOID *MemPtr, + IN UINT8 Template, + IN UINT64 Slot0, + IN UINT64 Slot1, + IN UINT64 Slot2 + ); + +STATIC +VOID +PushU64 ( + VM_CONTEXT *VmPtr, + UINT64 Arg + ) +{ + // + // Advance the VM stack down, and then copy the argument to the stack. + // Hope it's aligned. + // + VmPtr->R[0] -= sizeof (UINT64); + *(UINT64 *) VmPtr->R[0] = Arg; +} + +UINT64 +EbcInterpret ( + UINT64 Arg1, + ... + ) +{ + // + // Create a new VM context on the stack + // + VM_CONTEXT VmContext; + UINTN Addr; + VA_LIST List; + UINT64 Arg2; + UINT64 Arg3; + UINT64 Arg4; + UINT64 Arg5; + UINT64 Arg6; + UINT64 Arg7; + UINT64 Arg8; + UINTN Arg9Addr; + // + // Get the EBC entry point from the processor register. Make sure you don't + // call any functions before this or you could mess up the register the + // entry point is passed in. + // + Addr = EbcLLGetEbcEntryPoint (); + // + // Need the args off the stack. + // + VA_START (List, Arg1); + Arg2 = VA_ARG (List, UINT64); + Arg3 = VA_ARG (List, UINT64); + Arg4 = VA_ARG (List, UINT64); + Arg5 = VA_ARG (List, UINT64); + Arg6 = VA_ARG (List, UINT64); + Arg7 = VA_ARG (List, UINT64); + Arg8 = VA_ARG (List, UINT64); + Arg9Addr = (UINTN) List; + // + // 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. + // + Addr = (UINTN) Arg9Addr; + // + // NOTE: Eventually we should have the interpreter allocate memory + // for stack space which it will use during its execution. This + // would likely improve performance because the interpreter would + // no longer be required to test each memory access and adjust + // those reading from the stack gap. + // + // For IPF, the stack looks like (assuming 10 args passed) + // arg10 + // arg9 (Bottom of high stack) + // [ stack gap for interpreter execution ] + // [ magic value for detection of stack corruption ] + // arg8 (Top of low stack) + // arg7.... + // arg1 + // [ 64-bit return address ] + // [ ebc stack ] + // If the EBC accesses memory in the stack gap, then we assume that it's + // actually trying to access args9 and greater. Therefore we need to + // adjust memory accesses in this region to point above the stack gap. + // + VmContext.HighStackBottom = (UINTN) Addr; + // + // Now adjust the EBC stack pointer down to leave a gap for interpreter + // execution. Then stuff a magic value there. + // + VmContext.R[0] = (UINT64) Addr; + VmContext.R[0] -= VM_STACK_SIZE; + PushU64 (&VmContext, (UINT64) VM_STACK_KEY_VALUE); + VmContext.StackMagicPtr = (UINTN *) VmContext.R[0]; + VmContext.LowStackTop = (UINTN) VmContext.R[0]; + // + // Push the EBC arguments on the stack. Does not matter that they may not + // all be valid. + // + PushU64 (&VmContext, Arg8); + PushU64 (&VmContext, Arg7); + PushU64 (&VmContext, Arg6); + PushU64 (&VmContext, Arg5); + PushU64 (&VmContext, Arg4); + PushU64 (&VmContext, Arg3); + PushU64 (&VmContext, Arg2); + PushU64 (&VmContext, Arg1); + // + // Push a bogus return address on the EBC stack because the + // interpreter expects one there. For stack alignment purposes on IPF, + // EBC return addresses are always 16 bytes. Push a bogus value as well. + // + PushU64 (&VmContext, 0); + PushU64 (&VmContext, 0xDEADBEEFDEADBEEF); + VmContext.StackRetAddr = (UINT64) VmContext.R[0]; + // + // Begin executing the EBC code + // + EbcExecute (&VmContext); + // + // Return the value in R[7] unless there was an error + // + return (UINT64) VmContext.R[7]; +} + +UINT64 +ExecuteEbcImageEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + IPF implementation. + + Begin executing an EBC image. The address of the entry point is passed + in via a processor register, so we'll need to make a call to get the + value. + +Arguments: + + ImageHandle - image handle for the EBC application we're executing + SystemTable - standard system table passed into an driver's entry point + +Returns: + + The value returned by the EBC application we're going to run. + +--*/ +{ + // + // Create a new VM context on the stack + // + VM_CONTEXT VmContext; + UINTN Addr; + + // + // Get the EBC entry point from the processor register. Make sure you don't + // call any functions before this or you could mess up the register the + // entry point is passed in. + // + Addr = EbcLLGetEbcEntryPoint (); + + // + // 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; + + // + // Get the stack pointer. This is the bottom of the upper stack. + // + Addr = EbcLLGetStackPointer (); + VmContext.HighStackBottom = (UINTN) Addr; + VmContext.R[0] = (INT64) Addr; + + // + // Allocate stack space for the interpreter. Then put a magic value + // at the bottom so we can detect stack corruption. + // + VmContext.R[0] -= VM_STACK_SIZE; + PushU64 (&VmContext, (UINT64) VM_STACK_KEY_VALUE); + VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.R[0]; + + // + // When we thunk to external native code, we copy the last 8 qwords from + // the EBC stack into the processor registers, and adjust the stack pointer + // up. If the caller is not passing 8 parameters, then we've moved the + // stack pointer up into the stack gap. If this happens, then the caller + // can mess up the stack gap contents (in particular our magic value). + // Therefore, leave another gap below the magic value. Pick 10 qwords down, + // just as a starting point. + // + VmContext.R[0] -= 10 * sizeof (UINT64); + + // + // Align the stack pointer such that after pushing the system table, + // image handle, and return address on the stack, it's aligned on a 16-byte + // boundary as required for IPF. + // + VmContext.R[0] &= (INT64)~0x0f; + VmContext.LowStackTop = (UINTN) VmContext.R[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); + + // + // Interpreter assumes 64-bit return address is pushed on the stack. + // IPF does not do this so pad the stack accordingly. Also, a + // "return address" is 16 bytes as required for IPF stack alignments. + // + PushU64 (&VmContext, (UINT64) 0); + PushU64 (&VmContext, (UINT64) 0x1234567887654321); + VmContext.StackRetAddr = (UINT64) VmContext.R[0]; + + // + // Begin executing the EBC code + // + EbcExecute (&VmContext); + + // + // Return the value in R[7] unless there was an error + // + return (UINT64) VmContext.R[7]; +} + +EFI_STATUS +EbcCreateThunks ( + IN EFI_HANDLE ImageHandle, + IN VOID *EbcEntryPoint, + OUT VOID **Thunk, + IN UINT32 Flags + ) +/*++ + +Routine Description: + + Create thunks for an EBC image entry point, or an EBC protocol service. + +Arguments: + + ImageHandle - Image handle for the EBC image. If not null, then we're + creating a thunk for an image entry point. + EbcEntryPoint - Address of the EBC code that the thunk is to call + Thunk - Returned thunk we create here + Flags - Flags indicating options for creating the thunk + +Returns: + + Standard EFI status. + +--*/ +{ + UINT8 *Ptr; + UINT8 *ThunkBase; + UINT64 Addr; + UINT64 Code[3]; // Code in a bundle + UINT64 RegNum; // register number for MOVL + UINT64 I; // bits of MOVL immediate data + UINT64 Ic; // bits of MOVL immediate data + UINT64 Imm5c; // bits of MOVL immediate data + UINT64 Imm9d; // bits of MOVL immediate data + UINT64 Imm7b; // bits of MOVL immediate data + UINT64 Br; // branch register for loading and jumping + UINT64 *Data64Ptr; + UINT32 ThunkSize; + UINT32 Size; + EFI_STATUS Status; + + // + // Check alignment of pointer to EBC code, which must always be aligned + // on a 2-byte boundary. + // + if ((UINT32) (UINTN) EbcEntryPoint & 0x01) { + return EFI_INVALID_PARAMETER; + } + // + // Allocate memory for the thunk. Make the (most likely incorrect) assumption + // that the returned buffer is not aligned, so round up to the next + // alignment size. + // + Size = EBC_THUNK_SIZE + EBC_THUNK_ALIGNMENT - 1; + ThunkSize = Size; + Status = gBS->AllocatePool ( + EfiBootServicesData, + Size, + (VOID *) &Ptr + ); + if (Status != EFI_SUCCESS) { + return EFI_OUT_OF_RESOURCES; + } + // + // Save the start address of the buffer. + // + ThunkBase = Ptr; + + // + // Make sure it's aligned for code execution. If not, then + // round up. + // + if ((UINT32) (UINTN) Ptr & (EBC_THUNK_ALIGNMENT - 1)) { + Ptr = (UINT8 *) (((UINTN) Ptr + (EBC_THUNK_ALIGNMENT - 1)) &~ (UINT64) (EBC_THUNK_ALIGNMENT - 1)); + } + // + // Return the pointer to the thunk to the caller to user as the + // image entry point. + // + *Thunk = (VOID *) Ptr; + + // + // Clear out the thunk entry + // ZeroMem(Ptr, Size); + // + // For IPF, when you do a call via a function pointer, the function pointer + // actually points to a function descriptor which consists of a 64-bit + // address of the function, followed by a 64-bit gp for the function being + // called. See the the Software Conventions and Runtime Architecture Guide + // for details. + // So first off in our thunk, create a descriptor for our actual thunk code. + // This means we need to create a pointer to the thunk code (which follows + // the descriptor we're going to create), followed by the gp of the Vm + // interpret function we're going to eventually execute. + // + Data64Ptr = (UINT64 *) Ptr; + + // + // Write the function's entry point (which is our thunk code that follows + // this descriptor we're creating). + // + *Data64Ptr = (UINT64) (Data64Ptr + 2); + // + // Get the gp from the descriptor for EbcInterpret and stuff it in our thunk + // descriptor. + // + *(Data64Ptr + 1) = *(UINT64 *) ((UINT64 *) (UINTN) EbcInterpret + 1); + // + // Advance our thunk data pointer past the descriptor. Since the + // descriptor consists of 16 bytes, the pointer is still aligned for + // IPF code execution (on 16-byte boundary). + // + Ptr += sizeof (UINT64) * 2; + + // + // *************************** MAGIC BUNDLE ******************************** + // + // Write magic code bundle for: movl r8 = 0xca112ebcca112ebc to help the VM + // to recognize it is a thunk. + // + Addr = (UINT64) 0xCA112EBCCA112EBC; + + // + // Now generate the code bytes. First is nop.m 0x0 + // + Code[0] = OPCODE_NOP; + + // + // Next is simply Addr[62:22] (41 bits) of the address + // + Code[1] = RightShiftU64 (Addr, 22) & 0x1ffffffffff; + + // + // Extract bits from the address for insertion into the instruction + // i = Addr[63:63] + // + I = RightShiftU64 (Addr, 63) & 0x01; + // + // ic = Addr[21:21] + // + Ic = RightShiftU64 (Addr, 21) & 0x01; + // + // imm5c = Addr[20:16] for 5 bits + // + Imm5c = RightShiftU64 (Addr, 16) & 0x1F; + // + // imm9d = Addr[15:7] for 9 bits + // + Imm9d = RightShiftU64 (Addr, 7) & 0x1FF; + // + // imm7b = Addr[6:0] for 7 bits + // + Imm7b = Addr & 0x7F; + + // + // The EBC entry point will be put into r8, so r8 can be used here + // temporary. R8 is general register and is auto-serialized. + // + RegNum = 8; + + // + // Next is jumbled data, including opcode and rest of address + // + Code[2] = LeftShiftU64 (Imm7b, 13) + | LeftShiftU64 (0x00, 20) // vc + | LeftShiftU64 (Ic, 21) + | LeftShiftU64 (Imm5c, 22) + | LeftShiftU64 (Imm9d, 27) + | LeftShiftU64 (I, 36) + | LeftShiftU64 ((UINT64)MOVL_OPCODE, 37) + | LeftShiftU64 ((RegNum & 0x7F), 6); + + WriteBundle ((VOID *) Ptr, 0x05, Code[0], Code[1], Code[2]); + + // + // *************************** FIRST BUNDLE ******************************** + // + // Write code bundle for: movl r8 = EBC_ENTRY_POINT so we pass + // the ebc entry point in to the interpreter function via a processor + // register. + // Note -- we could easily change this to pass in a pointer to a structure + // that contained, among other things, the EBC image's entry point. But + // for now pass it directly. + // + Ptr += 16; + Addr = (UINT64) EbcEntryPoint; + + // + // Now generate the code bytes. First is nop.m 0x0 + // + Code[0] = OPCODE_NOP; + + // + // Next is simply Addr[62:22] (41 bits) of the address + // + Code[1] = RightShiftU64 (Addr, 22) & 0x1ffffffffff; + + // + // Extract bits from the address for insertion into the instruction + // i = Addr[63:63] + // + I = RightShiftU64 (Addr, 63) & 0x01; + // + // ic = Addr[21:21] + // + Ic = RightShiftU64 (Addr, 21) & 0x01; + // + // imm5c = Addr[20:16] for 5 bits + // + Imm5c = RightShiftU64 (Addr, 16) & 0x1F; + // + // imm9d = Addr[15:7] for 9 bits + // + Imm9d = RightShiftU64 (Addr, 7) & 0x1FF; + // + // imm7b = Addr[6:0] for 7 bits + // + Imm7b = Addr & 0x7F; + + // + // Put the EBC entry point in r8, which is the location of the return value + // for functions. + // + RegNum = 8; + + // + // Next is jumbled data, including opcode and rest of address + // + Code[2] = LeftShiftU64 (Imm7b, 13) + | LeftShiftU64 (0x00, 20) // vc + | LeftShiftU64 (Ic, 21) + | LeftShiftU64 (Imm5c, 22) + | LeftShiftU64 (Imm9d, 27) + | LeftShiftU64 (I, 36) + | LeftShiftU64 ((UINT64)MOVL_OPCODE, 37) + | LeftShiftU64 ((RegNum & 0x7F), 6); + + WriteBundle ((VOID *) Ptr, 0x05, Code[0], Code[1], Code[2]); + + // + // *************************** NEXT BUNDLE ********************************* + // + // Write code bundle for: + // movl rx = offset_of(EbcInterpret|ExecuteEbcImageEntryPoint) + // + // Advance pointer to next bundle, then compute the offset from this bundle + // to the address of the entry point of the interpreter. + // + Ptr += 16; + if (Flags & FLAG_THUNK_ENTRY_POINT) { + Addr = (UINT64) ExecuteEbcImageEntryPoint; + } else { + Addr = (UINT64) EbcInterpret; + } + // + // Indirection on Itanium-based systems + // + Addr = *(UINT64 *) Addr; + + // + // Now write the code to load the offset into a register + // + Code[0] = OPCODE_NOP; + + // + // Next is simply Addr[62:22] (41 bits) of the address + // + Code[1] = RightShiftU64 (Addr, 22) & 0x1ffffffffff; + + // + // Extract bits from the address for insertion into the instruction + // i = Addr[63:63] + // + I = RightShiftU64 (Addr, 63) & 0x01; + // + // ic = Addr[21:21] + // + Ic = RightShiftU64 (Addr, 21) & 0x01; + // + // imm5c = Addr[20:16] for 5 bits + // + Imm5c = RightShiftU64 (Addr, 16) & 0x1F; + // + // imm9d = Addr[15:7] for 9 bits + // + Imm9d = RightShiftU64 (Addr, 7) & 0x1FF; + // + // imm7b = Addr[6:0] for 7 bits + // + Imm7b = Addr & 0x7F; + + // + // Put it in r31, a scratch register + // + RegNum = 31; + + // + // Next is jumbled data, including opcode and rest of address + // + Code[2] = LeftShiftU64(Imm7b, 13) + | LeftShiftU64 (0x00, 20) // vc + | LeftShiftU64 (Ic, 21) + | LeftShiftU64 (Imm5c, 22) + | LeftShiftU64 (Imm9d, 27) + | LeftShiftU64 (I, 36) + | LeftShiftU64 ((UINT64)MOVL_OPCODE, 37) + | LeftShiftU64 ((RegNum & 0x7F), 6); + + WriteBundle ((VOID *) Ptr, 0x05, Code[0], Code[1], Code[2]); + + // + // *************************** NEXT BUNDLE ********************************* + // + // Load branch register with EbcInterpret() function offset from the bundle + // address: mov b6 = RegNum + // + // See volume 3 page 4-29 of the Arch. Software Developer's Manual. + // + // Advance pointer to next bundle + // + Ptr += 16; + Code[0] = OPCODE_NOP; + Code[1] = OPCODE_NOP; + Code[2] = OPCODE_MOV_BX_RX; + + // + // Pick a branch register to use. Then fill in the bits for the branch + // register and user register (same user register as previous bundle). + // + Br = 6; + Code[2] |= LeftShiftU64 (Br, 6); + Code[2] |= LeftShiftU64 (RegNum, 13); + WriteBundle ((VOID *) Ptr, 0x0d, Code[0], Code[1], Code[2]); + + // + // *************************** NEXT BUNDLE ********************************* + // + // Now do the branch: (p0) br.cond.sptk.few b6 + // + // Advance pointer to next bundle. + // Fill in the bits for the branch register (same reg as previous bundle) + // + Ptr += 16; + Code[0] = OPCODE_NOP; + Code[1] = OPCODE_NOP; + Code[2] = OPCODE_BR_COND_SPTK_FEW; + Code[2] |= LeftShiftU64 (Br, 13); + WriteBundle ((VOID *) Ptr, 0x1d, Code[0], Code[1], Code[2]); + + // + // Add the thunk to our list of allocated thunks so we can do some cleanup + // when the image is unloaded. Do this last since the Add function flushes + // the instruction cache for us. + // + EbcAddImageThunk (ImageHandle, (VOID *) ThunkBase, ThunkSize); + + // + // Done + // + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +WriteBundle ( + IN VOID *MemPtr, + IN UINT8 Template, + IN UINT64 Slot0, + IN UINT64 Slot1, + IN UINT64 Slot2 + ) +/*++ + +Routine Description: + + Given raw bytes of Itanium based code, format them into a bundle and + write them out. + +Arguments: + + MemPtr - pointer to memory location to write the bundles to + Template - 5-bit template + Slot0-2 - instruction slot data for the bundle + +Returns: + + EFI_INVALID_PARAMETER - Pointer is not aligned + - No more than 5 bits in template + - More than 41 bits used in code + EFI_SUCCESS - All data is written. + +--*/ +{ + UINT8 *BPtr; + UINT32 Index; + UINT64 Low64; + UINT64 High64; + + // + // Verify pointer is aligned + // + if ((UINT64) MemPtr & 0xF) { + return EFI_INVALID_PARAMETER; + } + // + // Verify no more than 5 bits in template + // + if (Template &~0x1F) { + return EFI_INVALID_PARAMETER; + } + // + // Verify max of 41 bits used in code + // + if ((Slot0 | Slot1 | Slot2) &~0x1ffffffffff) { + return EFI_INVALID_PARAMETER; + } + + Low64 = LeftShiftU64 (Slot1, 46) | LeftShiftU64 (Slot0, 5) | Template; + High64 = RightShiftU64 (Slot1, 18) | LeftShiftU64 (Slot2, 23); + + // + // Now write it all out + // + BPtr = (UINT8 *) MemPtr; + for (Index = 0; Index < 8; Index++) { + *BPtr = (UINT8) Low64; + Low64 = RightShiftU64 (Low64, 8); + BPtr++; + } + + for (Index = 0; Index < 8; Index++) { + *BPtr = (UINT8) High64; + High64 = RightShiftU64 (High64, 8); + BPtr++; + } + + return EFI_SUCCESS; +} + +VOID +EbcLLCALLEX ( + IN VM_CONTEXT *VmPtr, + IN UINTN FuncAddr, + IN UINTN NewStackPointer, + IN VOID *FramePtr, + IN UINT8 Size + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + VmPtr - Pointer to a VM context. + FuncAddr - Callee's address + NewStackPointer - New stack pointer after the call + FramePtr - New frame pointer after the call + Size - The size of call instruction + +Returns: + + None. + +--*/ +{ + UINTN IsThunk; + UINTN TargetEbcAddr; + UINTN CodeOne18; + UINTN CodeOne23; + UINTN CodeTwoI; + UINTN CodeTwoIc; + UINTN CodeTwo7b; + UINTN CodeTwo5c; + UINTN CodeTwo9d; + UINTN CalleeAddr; + + IsThunk = 1; + TargetEbcAddr = 0; + + // + // FuncAddr points to the descriptor of the target instructions. + // + CalleeAddr = *((UINT64 *)FuncAddr); + + // + // Processor specific code to check whether the callee is a thunk to EBC. + // + if (*((UINT64 *)CalleeAddr) != 0xBCCA000100000005) { + IsThunk = 0; + goto Action; + } + if (*((UINT64 *)CalleeAddr + 1) != 0x697623C1004A112E) { + IsThunk = 0; + goto Action; + } + + CodeOne18 = RightShiftU64 (*((UINT64 *)CalleeAddr + 2), 46) & 0x3FFFF; + CodeOne23 = (*((UINT64 *)CalleeAddr + 3)) & 0x7FFFFF; + CodeTwoI = RightShiftU64 (*((UINT64 *)CalleeAddr + 3), 59) & 0x1; + CodeTwoIc = RightShiftU64 (*((UINT64 *)CalleeAddr + 3), 44) & 0x1; + CodeTwo7b = RightShiftU64 (*((UINT64 *)CalleeAddr + 3), 36) & 0x7F; + CodeTwo5c = RightShiftU64 (*((UINT64 *)CalleeAddr + 3), 45) & 0x1F; + CodeTwo9d = RightShiftU64 (*((UINT64 *)CalleeAddr + 3), 50) & 0x1FF; + + TargetEbcAddr = CodeTwo7b + | LeftShiftU64 (CodeTwo9d, 7) + | LeftShiftU64 (CodeTwo5c, 16) + | LeftShiftU64 (CodeTwoIc, 21) + | LeftShiftU64 (CodeOne18, 22) + | LeftShiftU64 (CodeOne23, 40) + | LeftShiftU64 (CodeTwoI, 63) + ; + +Action: + 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->R[0] -= 8; + VmWriteMemN (VmPtr, (UINTN) VmPtr->R[0], (UINTN) FramePtr); + VmPtr->FramePtr = (VOID *) (UINTN) VmPtr->R[0]; + VmPtr->R[0] -= 8; + VmWriteMem64 (VmPtr, (UINTN) VmPtr->R[0], (UINT64) (VmPtr->Ip + Size)); + + VmPtr->Ip = (VMIP) (UINTN) TargetEbcAddr; + } else { + // + // The callee is not a thunk to EBC, call native code. + // + EbcLLCALLEXNative (FuncAddr, NewStackPointer, FramePtr); + + // + // Get return value and advance the IP. + // + VmPtr->R[7] = EbcLLGetReturnValue (); + VmPtr->Ip += Size; + } +} + +VOID +EbcLLCALLEXNative ( + IN UINTN CallAddr, + IN UINTN EbcSp, + IN VOID *FramePtr + ) +/*++ + +Routine Description: + Implements the EBC CALLEX instruction to call an external function, which + seems to be native code. + + We'll copy the entire EBC stack frame down below itself in memory and use + that copy for passing parameters. + +Arguments: + CallAddr - address (function pointer) of function to call + EbcSp - current EBC stack pointer + FramePtr - current EBC frame pointer. + +Returns: + NA + +--*/ +{ + UINTN FrameSize; + VOID *Destination; + VOID *Source; + // + // The stack for an EBC function looks like this: + // FramePtr (8) + // RetAddr (8) + // Locals (n) + // Stack for passing args (m) + // + // Pad the frame size with 64 bytes because the low-level code we call + // will move the stack pointer up assuming worst-case 8 args in registers. + // + FrameSize = (UINTN) FramePtr - (UINTN) EbcSp + 64; + Source = (VOID *) EbcSp; + Destination = (VOID *) ((UINT8 *) EbcSp - FrameSize - IPF_STACK_ALIGNMENT); + Destination = (VOID *) ((UINTN) ((UINTN) Destination + IPF_STACK_ALIGNMENT - 1) &~((UINTN) IPF_STACK_ALIGNMENT - 1)); + gBS->CopyMem (Destination, Source, FrameSize); + EbcAsmLLCALLEX ((UINTN) CallAddr, (UINTN) Destination); +} diff --git a/EdkModulePkg/Universal/Ebc/Dxe/Ipf/IpfMath.c b/EdkModulePkg/Universal/Ebc/Dxe/Ipf/IpfMath.c new file mode 100644 index 0000000000..f35f1b9ad1 --- /dev/null +++ b/EdkModulePkg/Universal/Ebc/Dxe/Ipf/IpfMath.c @@ -0,0 +1,375 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Ipfmath.c + +Abstract: + + Math routines for IPF. + +--*/ + +UINT64 +LeftShiftU64 ( + IN UINT64 Operand, + IN UINT64 Count + ) +/*++ + +Routine Description: + + Left-shift a 64 bit value. + +Arguments: + + Operand - 64-bit value to shift + Count - shift count + +Returns: + + Operand << Count + +--*/ +{ + if (Count > 63) { + return 0; + } + + return Operand << Count; +} + +UINT64 +RightShiftU64 ( + IN UINT64 Operand, + IN UINT64 Count + ) +/*++ + +Routine Description: + + Right-shift a 64 bit value. + +Arguments: + + Operand - 64-bit value to shift + Count - shift count + +Returns: + + Operand >> Count + +--*/ +{ + if (Count > 63) { + return 0; + } + + return Operand >> Count; +} + +INT64 +ARightShift64 ( + IN INT64 Operand, + IN UINT64 Count + ) +/*++ + +Routine Description: + + Right-shift a 64 bit signed value. + +Arguments: + + Operand - 64-bit value to shift + Count - shift count + +Returns: + + Operand >> Count + +--*/ +{ + if (Count > 63) { + + if (Operand & (0x01 << 63)) { + return (INT64)~0; + } + + return 0; + } + + return Operand >> Count; +} + +#if 0 +// +// The compiler generates true assembly for these, so we don't need them. +// +INT32 +ARightShift32 ( + IN INT32 Operand, + IN UINTN Count + ) +/*++ + +Routine Description: + + Right shift a 32-bit value + +Arguments: + + Operand - value to shift + Count - shift count + +Returns: + + Operand >> Count + +--*/ +{ + return Operand >> (Count & 0x1f); +} + +INT32 +MulS32x32 ( + INT32 Value1, + INT32 Value2, + INT32 *ResultHigh + ) +/*++ + +Routine Description: + + Multiply two signed 32-bit numbers. + +Arguments: + + Value1 - first value to multiply + Value2 - value to multiply Value1 by + ResultHigh - overflow + +Returns: + + Value1 * Value2 + +Notes: + + The 64-bit result is the concatenation of *ResultHigh and the return value + + The product fits in 32 bits if + (*ResultHigh == 0x00000000 AND *ResultLow_bit31 == 0) + OR + (*ResultHigh == 0xffffffff AND *ResultLow_bit31 == 1) + +--*/ +{ + INT64 Rres64; + INT32 Result; + + Res64 = (INT64) Value1 * (INT64) Value2; + *ResultHigh = (Res64 >> 32) & 0xffffffff; + Result = Res64 & 0xffffffff; + return Result; +} + +UINT32 +MulU32x32 ( + UINT32 Value1, + UINT32 Value2, + UINT32 *ResultHigh + ) +/*++ + +Routine Description: + + Multiply two unsigned 32-bit values. + +Arguments: + + Value1 - first number + Value2 - number to multiply by Value1 + ResultHigh - overflow + +Returns: + + Value1 * Value2 + +Notes: + + The 64-bit result is the concatenation of *ResultHigh and the return value. + The product fits in 32 bits if *ResultHigh == 0x00000000 + +--*/ +{ + UINT64 Res64; + UINT32 Result; + + Res64 = (INT64) Value1 * (INT64) Value2; + *ResultHigh = (Res64 >> 32) & 0xffffffff; + Result = Res64 & 0xffffffff; + return Result; +} + +INT32 +DivS32x32 ( + INT32 Value1, + INT32 Value2, + INT32 *Remainder, + UINTN *error + ) +// +// signed 32-bit by signed 32-bit divide; the 32-bit remainder is +// in *Remainder and the quotient is the return value; *error = 1 if the +// divisor is 0, and it is 1 otherwise +// +{ + INT32 Result; + + *error = 0; + + if (Value2 == 0x0) { + *error = 1; + Result = 0x80000000; + *Remainder = 0x80000000; + } else { + Result = Value1 / Value2; + *Remainder = Value1 - Result * Value2; + } + + return Result; +} + +UINT32 +DivU32x32 ( + UINT32 Value1, + UINT32 Value2, + UINT32 *Remainder, + UINTN *Error + ) +// +// unsigned 32-bit by unsigned 32-bit divide; the 32-bit remainder is +// in *Remainder and the quotient is the return value; *error = 1 if the +// divisor is 0, and it is 1 otherwise +// +{ + UINT32 Result; + + *Error = 0; + + if (Value2 == 0x0) { + *Error = 1; + Result = 0x80000000; + *Remainder = 0x80000000; + } else { + Result = Value1 / Value2; + *Remainder = Value1 - Result * Value2; + } + + return Result; +} + +#endif + +INT64 +DivS64x64 ( + INT64 Value1, + INT64 Value2, + INT64 *Remainder, + UINTN *Error + ) +/*++ + +Routine Description: + + Divide two 64-bit signed values. + +Arguments: + + Value1 - dividend + Value2 - divisor + Remainder - remainder of Value1/Value2 + Error - to flag errors (divide-by-0) + +Returns: + + Value1 / Valu2 + +Note: + + The 64-bit remainder is in *Remainder and the quotient is the return value. + *Error = 1 if the divisor is 0, and it is 1 otherwise + +--*/ +{ + INT64 Result; + + *Error = 0; + + if (Value2 == 0x0) { + *Error = 1; + Result = 0x8000000000000000; + *Remainder = 0x8000000000000000; + } else { + Result = Value1 / Value2; + *Remainder = Value1 - Result * Value2; + } + + return Result; +} + +UINT64 +DivU64x64 ( + UINT64 Value1, + UINT64 Value2, + UINT64 *Remainder, + UINTN *Error + ) +/*++ + +Routine Description: + + Divide two 64-bit unsigned values. + +Arguments: + + Value1 - dividend + Value2 - divisor + Remainder - remainder of Value1/Value2 + Error - to flag errors (divide-by-0) + +Returns: + + Value1 / Valu2 + +Note: + + The 64-bit remainder is in *Remainder and the quotient is the return value. + *Error = 1 if the divisor is 0, and it is 1 otherwise + +--*/ +{ + UINT64 Result; + + *Error = 0; + + if (Value2 == 0x0) { + *Error = 1; + Result = 0x8000000000000000; + *Remainder = 0x8000000000000000; + } else { + Result = Value1 / Value2; + *Remainder = Value1 - Result * Value2; + } + + return Result; +} diff --git a/EdkModulePkg/Universal/Ebc/Dxe/Ipf/IpfMul.s b/EdkModulePkg/Universal/Ebc/Dxe/Ipf/IpfMul.s new file mode 100644 index 0000000000..e887dd61ef --- /dev/null +++ b/EdkModulePkg/Universal/Ebc/Dxe/Ipf/IpfMul.s @@ -0,0 +1,144 @@ +///*++ +// +// Copyright (c) 2006, Intel Corporation +// All rights reserved. This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +//Module Name: +// +// IpfMul.s +// +//Abstract: +// +// Low level routines for IPF multiply support +// +//--*/ + +.file "IpfMul.s" +.section .text + + .proc MulS64x64# + .align 32 + .global MulS64x64# + .align 32 + +///*++ +// +//Routine Description: +// +// Multiply two 64-bit signed numbers. +// +// +//Arguments: +// +// INT64 +// MulS64x64 ( +// IN INT64 Value1, +// IN INT64 Value2, +// OUT INT64 *ResultHigh); +// +//Returns: +// +// 64-bit signed result +// +//--*/ + +MulS64x64: + // signed 64x64->128-bit multiply + // A in r32, B in r33, Q_hi stored in [r34], Q_lo returned in r8 +{ .mfi + alloc r31=ar.pfs,3,0,0,0 // r32-r34 + nop.f 0 + nop.i 0;; +} +{.mmi + setf.sig f6=r32 + setf.sig f7=r33 + nop.i 0;; +} + +{.mfi + nop.m 0 + xma.h f8=f6,f7,f0 + nop.i 0 +} +{.mfi + nop.m 0 + xma.l f6=f6,f7,f0 + nop.i 0;; +} + + +{.mmb + stf8 [r34]=f8 + getf.sig r8=f6 + br.ret.sptk b0;; +} + +.endp MulS64x64 + + .proc MulU64x64# + .align 32 + .global MulU64x64# + .align 32 + + +///*++ +// +//Routine Description: +// +// Multiply two 64-bit unsigned numbers. +// +// +//Arguments: +// +// UINT64 +// MulU64x64 ( +// IN UINT64 Value1, +// IN UINT64 Value2, +// OUT UINT64 *ResultHigh); +// +//Returns: +// +// 64-bit unsigned result +// +//--*/ +MulU64x64: + // A in r32, B in r33, Q_hi stored in [r34], Q_lo returned in r8 +{ .mfi + alloc r31=ar.pfs,3,0,0,0 // r32-r34 + nop.f 0 + nop.i 0;; +} +{.mmi + setf.sig f6=r32 + setf.sig f7=r33 + nop.i 0;; +} + +{.mfi + nop.m 0 + xma.hu f8=f6,f7,f0 + nop.i 0 +} +{.mfi + nop.m 0 + xma.l f6=f6,f7,f0 + nop.i 0;; +} + + +{.mmb + stf8 [r34]=f8 + getf.sig r8=f6 + br.ret.sptk b0;; +} + +.endp MulU64x64 + + diff --git a/EdkModulePkg/Universal/Ebc/Dxe/build.xml b/EdkModulePkg/Universal/Ebc/Dxe/build.xml new file mode 100644 index 0000000000..2145923e2a --- /dev/null +++ b/EdkModulePkg/Universal/Ebc/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Universal/Ebc/Dxe/x64/EbcLowLevel.asm b/EdkModulePkg/Universal/Ebc/Dxe/x64/EbcLowLevel.asm new file mode 100644 index 0000000000..59394621ba --- /dev/null +++ b/EdkModulePkg/Universal/Ebc/Dxe/x64/EbcLowLevel.asm @@ -0,0 +1,145 @@ + page ,132 + title VM ASSEMBLY LANGUAGE ROUTINES +;**************************************************************************** +;* +;* Copyright (c) 2006, Intel Corporation +;* All rights reserved. This program and the accompanying materials +;* are licensed and made available under the terms and conditions of the BSD License +;* which accompanies this distribution. The full text of the license may be found at +;* http://opensource.org/licenses/bsd-license.php +;* +;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +;* +;**************************************************************************** +;**************************************************************************** +; REV 1.0 +;**************************************************************************** +; +; Rev Date Description +; --- -------- ------------------------------------------------------------ +; 1.0 05/09/12 Initial creation of file. +; +;**************************************************************************** + +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +; This code provides low level routines that support the Virtual Machine +; for option ROMs. +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +;--------------------------------------------------------------------------- +; Equate files needed. +;--------------------------------------------------------------------------- + +text SEGMENT + +;--------------------------------------------------------------------------- +;;GenericPostSegment SEGMENT USE16 +;--------------------------------------------------------------------------- + +;**************************************************************************** +; 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. +;**************************************************************************** +; VOID EbcLLCALLEXNative(UINTN FuncAddr, UINTN NewStackPointer, VOID *FramePtr) +EbcLLCALLEXNative PROC + push rbp + push rbx + mov rbp, rsp + ; Function prolog + + ; Copy FuncAddr to a preserved register. + mov rbx, rcx + + ; Set stack pointer to new value + mov rsp, rdx + + ; Considering the worst case, load 4 potiential arguments + ; into registers. + mov rcx, qword ptr [rsp] + mov rdx, qword ptr [rsp+8h] + mov r8, qword ptr [rsp+10h] + mov r9, qword ptr [rsp+18h] + + ; Now call the external routine + call rbx + + ; Function epilog + mov rsp, rbp + pop rbx + pop rbp + ret +EbcLLCALLEXNative ENDP + + +; UINTN EbcLLGetEbcEntryPoint(VOID); +; Routine Description: +; 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. +; +; Arguments: +; None. +; +; Returns: +; The contents of the register in which the entry point is passed. +; +EbcLLGetEbcEntryPoint PROC + ret +EbcLLGetEbcEntryPoint ENDP + +;/*++ +; +;Routine Description: +; +; Return the caller's value of the stack pointer. +; +;Arguments: +; +; None. +; +;Returns: +; +; The current value of the stack pointer for the caller. We +; adjust it by 4 here because when they called us, the return address +; is put on the stack, thereby lowering it by 4 bytes. +; +;--*/ + +; UINTN EbcLLGetStackPointer() +EbcLLGetStackPointer PROC + mov rax, rsp ; get current stack pointer + ; Stack adjusted by this much when we were called, + ; For this function, it's 4. + add rax, 4 + ret +EbcLLGetStackPointer ENDP + +; UINT64 EbcLLGetReturnValue(VOID); +; Routine Description: +; When EBC calls native, on return the VM has to stuff the return +; value into a VM register. It's assumed here that the value is still +; in the register, so simply return and the caller should get the +; return result properly. +; +; Arguments: +; None. +; +; Returns: +; The unmodified value returned by the native code. +; +EbcLLGetReturnValue PROC + ret +EbcLLGetReturnValue ENDP + +text ENDS +END + diff --git a/EdkModulePkg/Universal/Ebc/Dxe/x64/EbcSupport.c b/EdkModulePkg/Universal/Ebc/Dxe/x64/EbcSupport.c new file mode 100644 index 0000000000..d111f3c0bf --- /dev/null +++ b/EdkModulePkg/Universal/Ebc/Dxe/x64/EbcSupport.c @@ -0,0 +1,579 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + EbcSupport.c + +Abstract: + + This module contains EBC support routines that are customized based on + the target x64 processor. + +--*/ + +#include "EbcInt.h" +#include "EbcExecute.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 EBC_THUNK_SIZE 64 + +STATIC +VOID +PushU64 ( + VM_CONTEXT *VmPtr, + UINT64 Arg + ) +/*++ + +Routine Description: + + Push a 64 bit unsigned value to the VM stack. + +Arguments: + + VmPtr - The pointer to current VM context. + Arg - The value to be pushed + +Returns: + + VOID + +--*/ +{ + // + // Advance the VM stack down, and then copy the argument to the stack. + // Hope it's aligned. + // + VmPtr->R[0] -= sizeof (UINT64); + *(UINT64 *) VmPtr->R[0] = Arg; + return; +} + +STATIC +UINT64 +EbcInterpret ( + UINTN Arg1, + UINTN Arg2, + UINTN Arg3, + UINTN Arg4, + UINTN Arg5 + ) +/*++ + +Routine Description: + + Begin executing an EBC image. The address of the entry point is passed + in via a processor register, so we'll need to make a call to get the + value. + +Arguments: + + 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. + +Returns: + + The value returned by the EBC application we're going to run. + +--*/ +{ + // + // Create a new VM context on the stack + // + VM_CONTEXT VmContext; + UINTN Addr; + + // + // Get the EBC entry point from the processor register. + // Don't call any function before getting the EBC entry + // point because this will collab the return register. + // + Addr = EbcLLGetEbcEntryPoint (); + + // + // 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. + // + Addr = EbcLLGetStackPointer (); + + // + // Adjust the VM's stack pointer down. + // + VmContext.R[0] = (UINT64) Addr; + VmContext.R[0] -= VM_STACK_SIZE; + + // + // Align the stack on a natural boundary. + // + VmContext.R[0] &= ~(sizeof (UINTN) - 1); + + // + // Put a magic value in the stack gap, then adjust down again. + // + *(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) VM_STACK_KEY_VALUE; + VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.R[0]; + + // + // The stack upper to LowStackTop is belong to the VM. + // + VmContext.LowStackTop = (UINTN) VmContext.R[0]; + + // + // For the worst case, assume there are 4 arguments passed in registers, store + // them to VM's stack. + // + 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) 0x1234567887654321); + + // + // For x64, this is where we say our return address is + // + VmContext.StackRetAddr = (UINT64) VmContext.R[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)); + // + VmContext.HighStackBottom = (UINTN) &Arg5; + + // + // Begin executing the EBC code + // + EbcExecute (&VmContext); + + // + // Return the value in R[7] unless there was an error + // + return (UINT64) VmContext.R[7]; +} + +STATIC +UINT64 +ExecuteEbcImageEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Begin executing an EBC image. The address of the entry point is passed + in via a processor register, so we'll need to make a call to get the + value. + +Arguments: + + ImageHandle - image handle for the EBC application we're executing + SystemTable - standard system table passed into an driver's entry point + +Returns: + + The value returned by the EBC application we're going to run. + +--*/ +{ + // + // Create a new VM context on the stack + // + VM_CONTEXT VmContext; + UINTN Addr; + + // + // Get the EBC entry point from the processor register. Make sure you don't + // call any functions before this or you could mess up the register the + // entry point is passed in. + // + Addr = EbcLLGetEbcEntryPoint (); + + // + // 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. + // + Addr = EbcLLGetStackPointer (); + VmContext.R[0] = (UINT64) Addr; + VmContext.R[0] -= VM_STACK_SIZE; + + // + // Put a magic value in the stack gap, then adjust down again + // + *(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) VM_STACK_KEY_VALUE; + VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.R[0]; + + // + // Align the stack on a natural boundary + VmContext.R[0] &= ~(sizeof(UINTN) - 1); + // + VmContext.LowStackTop = (UINTN) VmContext.R[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) 0x1234567887654321); + + // + // For x64, this is where we say our return address is + // + VmContext.StackRetAddr = (UINT64) VmContext.R[0]; + + // + // Entry function needn't access high stack context, simply + // put the stack pointer here. + // + VmContext.HighStackBottom = (UINTN) Addr; + + // + // Begin executing the EBC code + // + EbcExecute (&VmContext); + + // + // Return the value in R[7] unless there was an error + // + return (UINT64) VmContext.R[7]; +} + +EFI_STATUS +EbcCreateThunks ( + IN EFI_HANDLE ImageHandle, + IN VOID *EbcEntryPoint, + OUT VOID **Thunk, + IN UINT32 Flags + ) +/*++ + +Routine Description: + + Create an IA32 thunk for the given EBC entry point. + +Arguments: + + ImageHandle - Handle of image for which this thunk is being created + EbcEntryPoint - Address of the EBC code that the thunk is to call + Thunk - Returned thunk we create here + +Returns: + + Standard EFI status. + +--*/ +{ + UINT8 *Ptr; + UINT8 *ThunkBase; + UINT32 I; + UINT64 Addr; + INT32 Size; + INT32 ThunkSize; + EFI_STATUS Status; + + // + // Check alignment of pointer to EBC code + // + if ((UINT32) (UINTN) EbcEntryPoint & 0x01) { + return EFI_INVALID_PARAMETER; + } + + Size = EBC_THUNK_SIZE; + ThunkSize = Size; + + Status = gBS->AllocatePool ( + EfiBootServicesData, + Size, + (VOID *) &Ptr + ); + if (Status != EFI_SUCCESS) { + 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; + + // + // Add a magic code here to help the VM recognize the thunk.. + // mov rax, ca112ebccall2ebch => 48 B8 BC 2E 11 CA BC 2E 11 CA + // + *Ptr = 0x48; + Ptr++; + Size--; + *Ptr = 0xB8; + Ptr++; + Size--; + Addr = (UINT64) 0xCA112EBCCA112EBC; + for (I = 0; I < sizeof (Addr); I++) { + *Ptr = (UINT8) (UINTN) Addr; + Addr >>= 8; + Ptr++; + Size--; + } + + // + // Add code bytes to load up a processor register with the EBC entry point. + // mov rax, 123456789abcdef0h => 48 B8 F0 DE BC 9A 78 56 34 12 + // The first 8 bytes of the thunk entry is the address of the EBC + // entry point. + // + *Ptr = 0x48; + Ptr++; + Size--; + *Ptr = 0xB8; + Ptr++; + Size--; + Addr = (UINT64) EbcEntryPoint; + for (I = 0; I < sizeof (Addr); I++) { + *Ptr = (UINT8) (UINTN) Addr; + Addr >>= 8; + Ptr++; + Size--; + } + + // + // Stick in a load of ecx with the address of appropriate VM function. + // Using r11 because it's a volatile register and won't be used in this + // point. + // mov r11 123456789abcdef0h => 49 BB F0 DE BC 9A 78 56 34 12 + // + if (Flags & FLAG_THUNK_ENTRY_POINT) { + Addr = (UINTN) ExecuteEbcImageEntryPoint; + } else { + Addr = (UINTN) EbcInterpret; + } + + // + // mov r11 Addr => 0x49 0xBB + // + *Ptr = 0x49; + Ptr++; + Size--; + *Ptr = 0xBB; + Ptr++; + Size--; + for (I = 0; I < sizeof (Addr); I++) { + *Ptr = (UINT8) Addr; + Addr >>= 8; + Ptr++; + Size--; + } + // + // Stick in jump opcode bytes for jmp r11 => 0x41 0xFF 0xE3 + // + *Ptr = 0x41; + Ptr++; + Size--; + *Ptr = 0xFF; + Ptr++; + Size--; + *Ptr = 0xE3; + Size--; + + // + // Double check that our defined size is ok (application error) + // + if (Size < 0) { + ASSERT (FALSE); + return EFI_BUFFER_TOO_SMALL; + } + // + // 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; +} + +VOID +EbcLLCALLEX ( + IN VM_CONTEXT *VmPtr, + IN UINTN FuncAddr, + IN UINTN NewStackPointer, + IN VOID *FramePtr, + IN UINT8 Size + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + VmPtr - Pointer to a VM context. + FuncAddr - Callee's address + NewStackPointer - New stack pointer after the call + FramePtr - New frame pointer after the call + Size - The size of call instruction + +Returns: + + None. + +--*/ +{ + UINTN IsThunk; + UINTN TargetEbcAddr; + + IsThunk = 1; + TargetEbcAddr = 0; + + // + // Processor specific code to check whether the callee is a thunk to EBC. + // + if (*((UINT8 *)FuncAddr) != 0x48) { + IsThunk = 0; + goto Action; + } + if (*((UINT8 *)FuncAddr + 1) != 0xB8) { + IsThunk = 0; + goto Action; + } + if (*((UINT8 *)FuncAddr + 2) != 0xBC) { + IsThunk = 0; + goto Action; + } + if (*((UINT8 *)FuncAddr + 3) != 0x2E) { + IsThunk = 0; + goto Action; + } + if (*((UINT8 *)FuncAddr + 4) != 0x11) { + IsThunk = 0; + goto Action; + } + if (*((UINT8 *)FuncAddr + 5) != 0xCA) { + IsThunk = 0; + goto Action; + } + if (*((UINT8 *)FuncAddr + 6) != 0xBC) { + IsThunk = 0; + goto Action; + } + if (*((UINT8 *)FuncAddr + 7) != 0x2E) { + IsThunk = 0; + goto Action; + } + if (*((UINT8 *)FuncAddr + 8) != 0x11) { + IsThunk = 0; + goto Action; + } + if (*((UINT8 *)FuncAddr + 9) != 0xCA) { + IsThunk = 0; + goto Action; + } + if (*((UINT8 *)FuncAddr + 10) != 0x48) { + IsThunk = 0; + goto Action; + } + if (*((UINT8 *)FuncAddr + 11) != 0xB8) { + IsThunk = 0; + goto Action; + } + + CopyMem (&TargetEbcAddr, (UINT8 *)FuncAddr + 12, 8); + +Action: + 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->R[0] -= 8; + VmWriteMemN (VmPtr, (UINTN) VmPtr->R[0], (UINTN) FramePtr); + VmPtr->FramePtr = (VOID *) (UINTN) VmPtr->R[0]; + VmPtr->R[0] -= 8; + VmWriteMem64 (VmPtr, (UINTN) VmPtr->R[0], (UINT64) (VmPtr->Ip + Size)); + + VmPtr->Ip = (VMIP) (UINTN) TargetEbcAddr; + } else { + // + // The callee is not a thunk to EBC, call native code. + // + EbcLLCALLEXNative (FuncAddr, NewStackPointer, FramePtr); + + // + // Get return value and advance the IP. + // + VmPtr->R[7] = EbcLLGetReturnValue (); + VmPtr->Ip += Size; + } +} + diff --git a/EdkModulePkg/Universal/Ebc/Dxe/x64/x64Math.c b/EdkModulePkg/Universal/Ebc/Dxe/x64/x64Math.c new file mode 100644 index 0000000000..0842490732 --- /dev/null +++ b/EdkModulePkg/Universal/Ebc/Dxe/x64/x64Math.c @@ -0,0 +1,451 @@ +/*++ + +Copyright (c) 2006 , Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + x64math.c + +Abstract: + + Math routines for x64. + +--*/ + +UINT64 +LeftShiftU64 ( + IN UINT64 Operand, + IN UINT64 Count + ) +/*++ + +Routine Description: + + Left-shift a 64 bit value. + +Arguments: + + Operand - 64-bit value to shift + Count - shift count + +Returns: + + Operand << Count + +--*/ +{ + if (Count > 63) { + return 0; + } + + return Operand << Count; +} + +UINT64 +RightShiftU64 ( + IN UINT64 Operand, + IN UINT64 Count + ) +/*++ + +Routine Description: + + Right-shift a 64 bit value. + +Arguments: + + Operand - 64-bit value to shift + Count - shift count + +Returns: + + Operand >> Count + +--*/ +{ + if (Count > 63) { + return 0; + } + + return Operand >> Count; +} + +INT64 +ARightShift64 ( + IN INT64 Operand, + IN UINT64 Count + ) +/*++ + +Routine Description: + + Right-shift a 64 bit signed value. + +Arguments: + + Operand - 64-bit value to shift + Count - shift count + +Returns: + + Operand >> Count + +--*/ +{ + if (Count > 63) { + + if (Operand & 0x8000000000000000ULL) { + return (INT64)~0; + } + + return 0; + } + + return Operand >> Count; +} + +#if 0 +// +// The compiler generates true assembly for these, so we don't need them. +// +INT32 +ARightShift32 ( + IN INT32 Operand, + IN UINTN Count + ) +/*++ + +Routine Description: + + Right shift a 32-bit value + +Arguments: + + Operand - value to shift + Count - shift count + +Returns: + + Operand >> Count + +--*/ +{ + return Operand >> (Count & 0x1f); +} + +INT32 +MulS32x32 ( + INT32 Value1, + INT32 Value2, + INT32 *ResultHigh + ) +/*++ + +Routine Description: + + Multiply two signed 32-bit numbers. + +Arguments: + + Value1 - first value to multiply + Value2 - value to multiply Value1 by + ResultHigh - overflow + +Returns: + + Value1 * Value2 + +Notes: + + The 64-bit result is the concatenation of *ResultHigh and the return value + + The product fits in 32 bits if + (*ResultHigh == 0x00000000 AND *ResultLow_bit31 == 0) + OR + (*ResultHigh == 0xffffffff AND *ResultLow_bit31 == 1) + +--*/ +{ + INT64 Rres64; + INT32 Result; + + Res64 = (INT64) Value1 * (INT64) Value2; + *ResultHigh = (Res64 >> 32) & 0xffffffff; + Result = Res64 & 0xffffffff; + return Result; +} + +UINT32 +MulU32x32 ( + UINT32 Value1, + UINT32 Value2, + UINT32 *ResultHigh + ) +/*++ + +Routine Description: + + Multiply two unsigned 32-bit values. + +Arguments: + + Value1 - first number + Value2 - number to multiply by Value1 + ResultHigh - overflow + +Returns: + + Value1 * Value2 + +Notes: + + The 64-bit result is the concatenation of *ResultHigh and the return value. + The product fits in 32 bits if *ResultHigh == 0x00000000 + +--*/ +{ + UINT64 Res64; + UINT32 Result; + + Res64 = (INT64) Value1 * (INT64) Value2; + *ResultHigh = (Res64 >> 32) & 0xffffffff; + Result = Res64 & 0xffffffff; + return Result; +} + +INT32 +DivS32x32 ( + INT32 Value1, + INT32 Value2, + INT32 *Remainder, + UINTN *error + ) +// +// signed 32-bit by signed 32-bit divide; the 32-bit remainder is +// in *Remainder and the quotient is the return value; *error = 1 if the +// divisor is 0, and it is 1 otherwise +// +{ + INT32 Result; + + *error = 0; + + if (Value2 == 0x0) { + *error = 1; + Result = 0x80000000; + *Remainder = 0x80000000; + } else { + Result = Value1 / Value2; + *Remainder = Value1 - Result * Value2; + } + + return Result; +} + +UINT32 +DivU32x32 ( + UINT32 Value1, + UINT32 Value2, + UINT32 *Remainder, + UINTN *Error + ) +// +// unsigned 32-bit by unsigned 32-bit divide; the 32-bit remainder is +// in *Remainder and the quotient is the return value; *error = 1 if the +// divisor is 0, and it is 1 otherwise +// +{ + UINT32 Result; + + *Error = 0; + + if (Value2 == 0x0) { + *Error = 1; + Result = 0x80000000; + *Remainder = 0x80000000; + } else { + Result = Value1 / Value2; + *Remainder = Value1 - Result * Value2; + } + + return Result; +} + +#endif + +INT64 +MulS64x64 ( + INT64 Value1, + INT64 Value2, + INT64 *ResultHigh + ) +/*++ + +Routine Description: + + Multiply two signed 32-bit numbers. + +Arguments: + + Value1 - first value to multiply + Value2 - value to multiply Value1 by + ResultHigh - overflow + +Returns: + + Value1 * Value2 + +Notes: + + The 64-bit result is the concatenation of *ResultHigh and the return value + + The product fits in 32 bits if + (*ResultHigh == 0x00000000 AND *ResultLow_bit31 == 0) + OR + (*ResultHigh == 0xffffffff AND *ResultLow_bit31 == 1) + +--*/ +{ + INT64 Result; + + Result = Value1 * Value2; + + return Result; +} + +UINT64 +MulU64x64 ( + UINT64 Value1, + UINT64 Value2, + UINT64 *ResultHigh + ) +/*++ + +Routine Description: + + Multiply two unsigned 32-bit values. + +Arguments: + + Value1 - first number + Value2 - number to multiply by Value1 + ResultHigh - overflow + +Returns: + + Value1 * Value2 + +Notes: + + The 64-bit result is the concatenation of *ResultHigh and the return value. + The product fits in 32 bits if *ResultHigh == 0x00000000 + +--*/ +{ + UINT64 Result; + + Result = Value1 * Value2; + + return Result; +} + +INT64 +DivS64x64 ( + INT64 Value1, + INT64 Value2, + INT64 *Remainder, + UINTN *Error + ) +/*++ + +Routine Description: + + Divide two 64-bit signed values. + +Arguments: + + Value1 - dividend + Value2 - divisor + Remainder - remainder of Value1/Value2 + Error - to flag errors (divide-by-0) + +Returns: + + Value1 / Valu2 + +Note: + + The 64-bit remainder is in *Remainder and the quotient is the return value. + *Error = 1 if the divisor is 0, and it is 1 otherwise + +--*/ +{ + INT64 Result; + + *Error = 0; + + if (Value2 == 0x0) { + *Error = 1; + Result = 0x8000000000000000; + *Remainder = 0x8000000000000000; + } else { + Result = Value1 / Value2; + *Remainder = Value1 - Result * Value2; + } + + return Result; +} + +UINT64 +DivU64x64 ( + UINT64 Value1, + UINT64 Value2, + UINT64 *Remainder, + UINTN *Error + ) +/*++ + +Routine Description: + + Divide two 64-bit unsigned values. + +Arguments: + + Value1 - dividend + Value2 - divisor + Remainder - remainder of Value1/Value2 + Error - to flag errors (divide-by-0) + +Returns: + + Value1 / Valu2 + +Note: + + The 64-bit remainder is in *Remainder and the quotient is the return value. + *Error = 1 if the divisor is 0, and it is 1 otherwise + +--*/ +{ + UINT64 Result; + + *Error = 0; + + if (Value2 == 0x0) { + *Error = 1; + Result = 0x8000000000000000; + *Remainder = 0x8000000000000000; + } else { + Result = Value1 / Value2; + *Remainder = Value1 - Result * Value2; + } + + return Result; +} diff --git a/EdkModulePkg/Universal/EmuVariable/RuntimeDxe/EmuVariable.c b/EdkModulePkg/Universal/EmuVariable/RuntimeDxe/EmuVariable.c new file mode 100644 index 0000000000..beb404f42c --- /dev/null +++ b/EdkModulePkg/Universal/EmuVariable/RuntimeDxe/EmuVariable.c @@ -0,0 +1,754 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + EmuVariable.c + +Abstract: + +Revision History + +--*/ + +#include "Variable.h" + +// +// Don't use module globals after the SetVirtualAddress map is signaled +// +ESAL_VARIABLE_GLOBAL *mVariableModuleGlobal; + +UINT32 +EFIAPI +ArrayLength ( + IN CHAR16 *String + ) +/*++ + +Routine Description: + + Determine the length of null terminated char16 array. + +Arguments: + + String Null-terminated CHAR16 array pointer. + +Returns: + + UINT32 Number of bytes in the string, including the double NULL at the end; + +--*/ +{ + UINT32 Count; + + if (NULL == String) { + return 0; + } + + Count = 0; + + while (0 != String[Count]) { + Count++; + } + + return (Count * 2) + 2; +} + +UINTN +EFIAPI +GetPadSize ( + IN UINTN Value + ) +/*++ + +Routine Description: + + This function return the pad size for alignment + +Arguments: + + Value The value need to align + +Returns: + + Pad size for value + +--*/ +{ + // + // If alignment is 0 or 1, means no alignment required + // + if (ALIGNMENT == 0 || ALIGNMENT == 1) { + return 0; + } + + return ALIGNMENT - (Value % ALIGNMENT); +} + +VARIABLE_STORE_STATUS +EFIAPI +GetVariableStoreStatus ( + IN VARIABLE_STORE_HEADER *VarStoreHeader + ) +/*++ + +Routine Description: + + This code gets the pointer to the variable name. + +Arguments: + + VarStoreHeader Pointer to the Variable Store Header. + +Returns: + + EfiHealthy Variable store is healthy + EfiRaw Variable store is raw + EfiInvalid Variable store is invalid + +--*/ +{ + if (VarStoreHeader->Signature == VARIABLE_STORE_SIGNATURE && + VarStoreHeader->Format == VARIABLE_STORE_FORMATTED && + VarStoreHeader->State == VARIABLE_STORE_HEALTHY + ) { + + return EfiValid; + } else if (VarStoreHeader->Signature == 0xffffffff && + VarStoreHeader->Size == 0xffffffff && + VarStoreHeader->Format == 0xff && + VarStoreHeader->State == 0xff + ) { + + return EfiRaw; + } else { + return EfiInvalid; + } +} + +UINT8 * +EFIAPI +GetVariableDataPtr ( + IN VARIABLE_HEADER *Variable + ) +/*++ + +Routine Description: + + This code gets the pointer to the variable data. + +Arguments: + + Variable Pointer to the Variable Header. + +Returns: + + UINT8* Pointer to Variable Data + +--*/ +{ + if (Variable->StartId != VARIABLE_DATA) { + return NULL; + } + // + // Be careful about pad size for alignment + // + return (UINT8 *) ((UINTN) GET_VARIABLE_NAME_PTR (Variable) + Variable->NameSize + GetPadSize (Variable->NameSize)); +} + +VARIABLE_HEADER * +EFIAPI +GetNextVariablePtr ( + IN VARIABLE_HEADER *Variable + ) +/*++ + +Routine Description: + + This code gets the pointer to the next variable header. + +Arguments: + + Variable Pointer to the Variable Header. + +Returns: + + VARIABLE_HEADER* Pointer to next variable header. + +--*/ +{ + VARIABLE_HEADER *VarHeader; + + if (Variable->StartId != VARIABLE_DATA) { + return NULL; + } + // + // Be careful about pad size for alignment + // + VarHeader = (VARIABLE_HEADER *) (GetVariableDataPtr (Variable) + Variable->DataSize + GET_PAD_SIZE (Variable->DataSize)); + + if (VarHeader->StartId != VARIABLE_DATA || + (sizeof (VARIABLE_HEADER) + VarHeader->DataSize + VarHeader->NameSize) > MAX_VARIABLE_SIZE + ) { + return NULL; + } + + return VarHeader; +} + +VARIABLE_HEADER * +EFIAPI +GetEndPointer ( + IN VARIABLE_STORE_HEADER *VolHeader + ) +/*++ + +Routine Description: + + This code gets the pointer to the last variable memory pointer byte + +Arguments: + + Variable Pointer to the Variable Header. + +Returns: + + VARIABLE_HEADER* Pointer to last unavailable Variable Header + +--*/ +{ + // + // The end of variable store + // + return (VARIABLE_HEADER *) ((UINTN) VolHeader + VolHeader->Size); +} + +EFI_STATUS +EFIAPI +FindVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT VARIABLE_POINTER_TRACK *PtrTrack, + IN VARIABLE_GLOBAL *Global + ) +/*++ + +Routine Description: + + This code finds variable in storage blocks (Volatile or Non-Volatile) + +Arguments: + + VariableName Name of the variable to be found + VendorGuid Vendor GUID to be found. + PtrTrack Variable Track Pointer structure that contains + Variable Information. + Contains the pointer of Variable header. + Global VARIABLE_GLOBAL pointer + +Returns: + + EFI STATUS + +--*/ +{ + VARIABLE_HEADER *Variable[2]; + VARIABLE_STORE_HEADER *VariableStoreHeader[2]; + UINTN Index; + + // + // 0: Non-Volatile, 1: Volatile + // + VariableStoreHeader[0] = (VARIABLE_STORE_HEADER *) ((UINTN) Global->NonVolatileVariableBase); + VariableStoreHeader[1] = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase); + + // + // Start Pointers for the variable. + // Actual Data Pointer where data can be written. + // + Variable[0] = (VARIABLE_HEADER *) (VariableStoreHeader[0] + 1); + Variable[1] = (VARIABLE_HEADER *) (VariableStoreHeader[1] + 1); + + if (VariableName[0] != 0 && VendorGuid == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Find the variable by walk through non-volatile and volatile variable store + // + for (Index = 0; Index < 2; Index++) { + PtrTrack->StartPtr = (VARIABLE_HEADER *) (VariableStoreHeader[Index] + 1); + PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index]); + + while ((Variable[Index] != NULL) && (Variable[Index] <= GetEndPointer (VariableStoreHeader[Index]))) { + if (Variable[Index]->StartId == VARIABLE_DATA && Variable[Index]->State == VAR_ADDED) { + if (!(EfiAtRuntime () && !(Variable[Index]->Attributes & EFI_VARIABLE_RUNTIME_ACCESS))) { + if (VariableName[0] == 0) { + PtrTrack->CurrPtr = Variable[Index]; + PtrTrack->Volatile = (BOOLEAN) Index; + return EFI_SUCCESS; + } else { + if (CompareGuid (VendorGuid, &Variable[Index]->VendorGuid)) { + if (!CompareMem (VariableName, GET_VARIABLE_NAME_PTR (Variable[Index]), ArrayLength (VariableName))) { + PtrTrack->CurrPtr = Variable[Index]; + PtrTrack->Volatile = (BOOLEAN) Index; + return EFI_SUCCESS; + } + } + } + } + } + + Variable[Index] = GetNextVariablePtr (Variable[Index]); + } + } + PtrTrack->CurrPtr = NULL; + return EFI_NOT_FOUND; +} + +EFI_STATUS +EFIAPI +GetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID * VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, + OUT VOID *Data, + IN VARIABLE_GLOBAL * Global, + IN UINT32 Instance + ) +/*++ + +Routine Description: + + This code finds variable in storage blocks (Volatile or Non-Volatile) + +Arguments: + + VariableName Name of Variable to be found + VendorGuid Variable vendor GUID + Attributes OPTIONAL Attribute value of the variable found + DataSize Size of Data found. If size is less than the + data, this value contains the required size. + Data Data pointer + Global Pointer to VARIABLE_GLOBAL structure + Instance Instance of the Firmware Volume. + +Returns: + + EFI STATUS + +--*/ +{ + VARIABLE_POINTER_TRACK Variable; + UINTN VarDataSize; + EFI_STATUS Status; + + if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Find existing variable + // + Status = FindVariable (VariableName, VendorGuid, &Variable, Global); + + if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) { + return Status; + } + // + // Get data size + // + VarDataSize = Variable.CurrPtr->DataSize; + if (*DataSize >= VarDataSize) { + CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize); + if (Attributes) { + *Attributes = Variable.CurrPtr->Attributes; + } + + *DataSize = VarDataSize; + return EFI_SUCCESS; + } else { + *DataSize = VarDataSize; + return EFI_BUFFER_TOO_SMALL; + } +} + +EFI_STATUS +EFIAPI +GetNextVariableName ( + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VendorGuid, + IN VARIABLE_GLOBAL *Global, + IN UINT32 Instance + ) +/*++ + +Routine Description: + + This code Finds the Next available variable + +Arguments: + + VariableNameSize Size of the variable + VariableName Pointer to variable name + VendorGuid Variable Vendor Guid + Global VARIABLE_GLOBAL structure pointer. + Instance FV instance + +Returns: + + EFI STATUS + +--*/ +{ + VARIABLE_POINTER_TRACK Variable; + UINTN VarNameSize; + EFI_STATUS Status; + + if (VariableNameSize == NULL || VendorGuid == NULL) { + return EFI_INVALID_PARAMETER; + } + + Status = FindVariable (VariableName, VendorGuid, &Variable, Global); + + if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) { + return Status; + } + + while (TRUE) { + if (VariableName[0] != 0) { + // + // If variable name is not NULL, get next variable + // + Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); + } + // + // If both volatile and non-volatile variable store are parsed, + // return not found + // + if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL) { + Variable.Volatile = (BOOLEAN) (Variable.Volatile ^ ((BOOLEAN) 0x1)); + if (Variable.Volatile) { + Variable.StartPtr = (VARIABLE_HEADER *) ((UINTN) (Global->VolatileVariableBase + sizeof (VARIABLE_STORE_HEADER))); + Variable.EndPtr = (VARIABLE_HEADER *) GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase)); + } else { + return EFI_NOT_FOUND; + } + + Variable.CurrPtr = Variable.StartPtr; + if (Variable.CurrPtr->StartId != VARIABLE_DATA) { + continue; + } + } + // + // Variable is found + // + if (Variable.CurrPtr->StartId == VARIABLE_DATA && Variable.CurrPtr->State == VAR_ADDED) { + if (!(EfiAtRuntime () && !(Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS))) { + VarNameSize = Variable.CurrPtr->NameSize; + if (VarNameSize <= *VariableNameSize) { + CopyMem ( + VariableName, + GET_VARIABLE_NAME_PTR (Variable.CurrPtr), + VarNameSize + ); + CopyMem ( + VendorGuid, + &Variable.CurrPtr->VendorGuid, + sizeof (EFI_GUID) + ); + Status = EFI_SUCCESS; + } else { + Status = EFI_BUFFER_TOO_SMALL; + } + + *VariableNameSize = VarNameSize; + return Status; + } + } + } + + return EFI_NOT_FOUND; +} + +EFI_STATUS +EFIAPI +SetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data, + IN VARIABLE_GLOBAL *Global, + IN UINTN *VolatileOffset, + IN UINTN *NonVolatileOffset, + IN UINT32 Instance + ) +/*++ + +Routine Description: + + This code sets variable in storage blocks (Volatile or Non-Volatile) + +Arguments: + + VariableName Name of Variable to be found + VendorGuid Variable vendor GUID + Attributes Attribute value of the variable found + DataSize Size of Data found. If size is less than the + data, this value contains the required size. + Data Data pointer + Global Pointer to VARIABLE_GLOBAL structure + VolatileOffset The offset of last volatile variable + NonVolatileOffset The offset of last non-volatile variable + Instance Instance of the Firmware Volume. + +Returns: + + EFI STATUS + +--*/ +{ + VARIABLE_POINTER_TRACK Variable; + EFI_STATUS Status; + VARIABLE_HEADER *NextVariable; + UINTN VarNameSize; + UINTN VarNameOffset; + UINTN VarDataOffset; + UINTN VarSize; + + if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) { + return EFI_INVALID_PARAMETER; + } + + Status = FindVariable (VariableName, VendorGuid, &Variable, Global); + + if (Status == EFI_INVALID_PARAMETER) { + return Status; + } + // + // The size of the VariableName, including the Unicode Null in bytes plus + // the DataSize is limited to maximum size of MAX_VARIABLE_SIZE (1024) bytes. + // + else if (sizeof (VARIABLE_HEADER) + (ArrayLength (VariableName) + DataSize) > MAX_VARIABLE_SIZE) { + return EFI_INVALID_PARAMETER; + } + // + // Make sure if runtime bit is set, boot service bit is set also + // + else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS + ) { + return EFI_INVALID_PARAMETER; + } + // + // Runtime but Attribute is not Runtime + // + else if (EfiAtRuntime () && Attributes && !(Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) { + return EFI_INVALID_PARAMETER; + } + // + // Cannot set volatile variable in Runtime + // + else if (EfiAtRuntime () && Attributes && !(Attributes & EFI_VARIABLE_NON_VOLATILE)) { + return EFI_INVALID_PARAMETER; + } + // + // Setting a data variable with no access, or zero DataSize attributes + // specified causes it to be deleted. + // + else if (DataSize == 0 || Attributes == 0) { + if (!EFI_ERROR (Status)) { + Variable.CurrPtr->State &= VAR_DELETED; + return EFI_SUCCESS; + } + + return EFI_NOT_FOUND; + } else { + if (!EFI_ERROR (Status)) { + // + // If the variable is marked valid and the same data has been passed in + // then return to the caller immediately. + // + if (Variable.CurrPtr->DataSize == DataSize && + !CompareMem (Data, GetVariableDataPtr (Variable.CurrPtr), DataSize) + ) { + return EFI_SUCCESS; + } else if (Variable.CurrPtr->State == VAR_ADDED) { + // + // Mark the old variable as in delete transition + // + Variable.CurrPtr->State &= VAR_IN_DELETED_TRANSITION; + } + } + // + // Create a new variable and copy the data. + // + VarNameOffset = sizeof (VARIABLE_HEADER); + VarNameSize = ArrayLength (VariableName); + VarDataOffset = VarNameOffset + VarNameSize + GetPadSize (VarNameSize); + VarSize = VarDataOffset + DataSize + GetPadSize (DataSize); + + if (Attributes & EFI_VARIABLE_NON_VOLATILE) { + if ((UINT32) (VarSize +*NonVolatileOffset) > + ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->NonVolatileVariableBase)))->Size + ) { + return EFI_OUT_OF_RESOURCES; + } + + NextVariable = (VARIABLE_HEADER *) (UINT8 *) (*NonVolatileOffset + (UINTN) Global->NonVolatileVariableBase); + *NonVolatileOffset = *NonVolatileOffset + VarSize; + } else { + if (EfiAtRuntime ()) { + return EFI_INVALID_PARAMETER; + } + + if ((UINT32) (VarSize +*VolatileOffset) > + ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->VolatileVariableBase)))->Size + ) { + return EFI_OUT_OF_RESOURCES; + } + + NextVariable = (VARIABLE_HEADER *) (UINT8 *) (*VolatileOffset + (UINTN) Global->VolatileVariableBase); + *VolatileOffset = *VolatileOffset + VarSize; + } + + NextVariable->StartId = VARIABLE_DATA; + NextVariable->Attributes = Attributes; + NextVariable->State = VAR_ADDED; + NextVariable->Reserved = 0; + + // + // There will be pad bytes after Data, the NextVariable->NameSize and + // NextVariable->NameSize should not include pad size so that variable + // service can get actual size in GetVariable + // + NextVariable->NameSize = (UINT32)VarNameSize; + NextVariable->DataSize = (UINT32)DataSize; + + CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID)); + CopyMem ( + (UINT8 *) ((UINTN) NextVariable + VarNameOffset), + VariableName, + VarNameSize + ); + CopyMem ( + (UINT8 *) ((UINTN) NextVariable + VarDataOffset), + Data, + DataSize + ); + + // + // Mark the old variable as deleted + // + if (!EFI_ERROR (Status)) { + Variable.CurrPtr->State &= VAR_DELETED; + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +InitializeVariableStore ( + OUT EFI_PHYSICAL_ADDRESS *VariableBase, + OUT UINTN *LastVariableOffset + ) +/*++ + +Routine Description: + This function initializes variable store + +Arguments: + +Returns: + +--*/ +{ + VARIABLE_STORE_HEADER *VariableStore; + + // + // Allocate memory for volatile variable store + // + VariableStore = (VARIABLE_STORE_HEADER *) AllocateRuntimePool ( + VARIABLE_STORE_SIZE + ); + if (NULL == VariableStore) { + return EFI_OUT_OF_RESOURCES; + } + + SetMem (VariableStore, VARIABLE_STORE_SIZE, 0xff); + + // + // Variable Specific Data + // + *VariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStore; + *LastVariableOffset = sizeof (VARIABLE_STORE_HEADER); + + VariableStore->Signature = VARIABLE_STORE_SIGNATURE; + VariableStore->Size = VARIABLE_STORE_SIZE; + VariableStore->Format = VARIABLE_STORE_FORMATTED; + VariableStore->State = VARIABLE_STORE_HEALTHY; + VariableStore->Reserved = 0; + VariableStore->Reserved1 = 0; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +VariableCommonInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + This function does common initialization for variable services + +Arguments: + +Returns: + +--*/ +{ + EFI_STATUS Status; + + // + // Allocate memory for mVariableModuleGlobal + // + mVariableModuleGlobal = (ESAL_VARIABLE_GLOBAL *) AllocateRuntimePool ( + sizeof (ESAL_VARIABLE_GLOBAL) + ); + if (NULL == mVariableModuleGlobal) { + return EFI_OUT_OF_RESOURCES; + } + // + // Intialize volatile variable store + // + Status = InitializeVariableStore ( + &mVariableModuleGlobal->VariableBase[Physical].VolatileVariableBase, + &mVariableModuleGlobal->VolatileLastVariableOffset + ); + + if (EFI_ERROR (Status)) { + return Status; + } + // + // Intialize non volatile variable store + // + Status = InitializeVariableStore ( + &mVariableModuleGlobal->VariableBase[Physical].NonVolatileVariableBase, + &mVariableModuleGlobal->NonVolatileLastVariableOffset + ); + + return Status; +} diff --git a/EdkModulePkg/Universal/EmuVariable/RuntimeDxe/EmuVariable.dxs b/EdkModulePkg/Universal/EmuVariable/RuntimeDxe/EmuVariable.dxs new file mode 100644 index 0000000000..51c93d7657 --- /dev/null +++ b/EdkModulePkg/Universal/EmuVariable/RuntimeDxe/EmuVariable.dxs @@ -0,0 +1,25 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + EmuVariable.dxs + +Abstract: + + Dependency expression source file. + +--*/ +#include "DxeDepex.h" + +DEPENDENCY_START + TRUE +DEPENDENCY_END \ No newline at end of file diff --git a/EdkModulePkg/Universal/EmuVariable/RuntimeDxe/EmuVariable.mbd b/EdkModulePkg/Universal/EmuVariable/RuntimeDxe/EmuVariable.mbd new file mode 100644 index 0000000000..4cc2c2085d --- /dev/null +++ b/EdkModulePkg/Universal/EmuVariable/RuntimeDxe/EmuVariable.mbd @@ -0,0 +1,45 @@ + + + + + EmuVariable + CBD2E4D5-7068-4FF5-B866-9822B4AD8D60 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-23 16:05 + + + UefiBootServicesTableLib + BaseMemoryLib + BaseDebugLibReportStatusCode + UefiDriverEntryPoint + EdkDxeRuntimeDriverLib + DxeMemoryAllocationLib + BaseLib + DxeReportStatusCodeLib + + EdkDxeSalLib + + + + _ModuleEntryPoint + + diff --git a/EdkModulePkg/Universal/EmuVariable/RuntimeDxe/EmuVariable.msa b/EdkModulePkg/Universal/EmuVariable/RuntimeDxe/EmuVariable.msa new file mode 100644 index 0000000000..e5142bed73 --- /dev/null +++ b/EdkModulePkg/Universal/EmuVariable/RuntimeDxe/EmuVariable.msa @@ -0,0 +1,76 @@ + + + + + EmuVariable + DXE_RUNTIME_DRIVER + RT_DRIVER + CBD2E4D5-7068-4FF5-B866-9822B4AD8D60 + 0 + Component description file for DiskIo module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-23 16:05 + + + BaseLib + BaseMemoryLib + MemoryAllocationLib + DebugLib + DxeRuntimeDriverLib + UefiDriverEntryPoint + EdkDxeSalLib + UefiBootServicesTableLib + + + EmuVariable.c + EmuVariable.dxs + + InitVariable.c + + + InitVariable.c + + + InitVariable.c + + + Ipf\InitVariable.c + + + + MdePkg + EdkModulePkg + + + VariableWrite + Variable + VariableWrite + Variable + ExtendedSalVariableServices + ExtendedSalBootService + + + + VariableServiceInitialize + + + diff --git a/EdkModulePkg/Universal/EmuVariable/RuntimeDxe/InitVariable.c b/EdkModulePkg/Universal/EmuVariable/RuntimeDxe/InitVariable.c new file mode 100644 index 0000000000..0ad86642ea --- /dev/null +++ b/EdkModulePkg/Universal/EmuVariable/RuntimeDxe/InitVariable.c @@ -0,0 +1,185 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + InitVariable.c + +Abstract: + +Revision History + +--*/ + +#include "Variable.h" + +// +// Don't use module globals after the SetVirtualAddress map is signaled +// +extern ESAL_VARIABLE_GLOBAL *mVariableModuleGlobal; + +EFI_STATUS +EFIAPI +RuntimeServiceGetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID * VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, + OUT VOID *Data + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + return GetVariable ( + VariableName, + VendorGuid, + Attributes OPTIONAL, + DataSize, + Data, + &mVariableModuleGlobal->VariableBase[Physical], + mVariableModuleGlobal->FvbInstance + ); +} + +EFI_STATUS +EFIAPI +RuntimeServiceGetNextVariableName ( + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VendorGuid + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + return GetNextVariableName ( + VariableNameSize, + VariableName, + VendorGuid, + &mVariableModuleGlobal->VariableBase[Physical], + mVariableModuleGlobal->FvbInstance + ); +} + +EFI_STATUS +EFIAPI +RuntimeServiceSetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + return SetVariable ( + VariableName, + VendorGuid, + Attributes, + DataSize, + Data, + &mVariableModuleGlobal->VariableBase[Physical], + &mVariableModuleGlobal->VolatileLastVariableOffset, + &mVariableModuleGlobal->NonVolatileLastVariableOffset, + mVariableModuleGlobal->FvbInstance + ); +} + +VOID +EFIAPI +VariableClassAddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + EfiConvertPointer ( + 0x0, + (VOID **) &mVariableModuleGlobal->VariableBase[Physical].NonVolatileVariableBase + ); + EfiConvertPointer ( + 0x0, + (VOID **) &mVariableModuleGlobal->VariableBase[Physical].VolatileVariableBase + ); + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal); +} + +EFI_STATUS +EFIAPI +VariableServiceInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + EFI_HANDLE NewHandle; + EFI_STATUS Status; + + Status = VariableCommonInitialize (ImageHandle, SystemTable); + ASSERT_EFI_ERROR (Status); + + SystemTable->RuntimeServices->GetVariable = RuntimeServiceGetVariable; + SystemTable->RuntimeServices->GetNextVariableName = RuntimeServiceGetNextVariableName; + SystemTable->RuntimeServices->SetVariable = RuntimeServiceSetVariable; + + // + // Now install the Variable Runtime Architectural Protocol on a new handle + // + NewHandle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &NewHandle, + &gEfiVariableArchProtocolGuid, + NULL, + &gEfiVariableWriteArchProtocolGuid, + NULL, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Universal/EmuVariable/RuntimeDxe/Ipf/InitVariable.c b/EdkModulePkg/Universal/EmuVariable/RuntimeDxe/Ipf/InitVariable.c new file mode 100644 index 0000000000..061e6db73d --- /dev/null +++ b/EdkModulePkg/Universal/EmuVariable/RuntimeDxe/Ipf/InitVariable.c @@ -0,0 +1,167 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + IpfVariable.c + +Abstract: + +Revision History + +--*/ + +#include "Variable.h" + +// +// Don't use module globals after the SetVirtualAddress map is signaled +// +extern ESAL_VARIABLE_GLOBAL *mVariableModuleGlobal; + +SAL_RETURN_REGS +EsalVariableCommonEntry ( + IN UINT64 FunctionId, + IN UINT64 Arg2, + IN UINT64 Arg3, + IN UINT64 Arg4, + IN UINT64 Arg5, + IN UINT64 Arg6, + IN UINT64 Arg7, + IN UINT64 Arg8, + IN SAL_EXTENDED_SAL_PROC ExtendedSalProc, + IN BOOLEAN VirtualMode, + IN ESAL_VARIABLE_GLOBAL *Global + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + SAL_RETURN_REGS ReturnVal; + + switch (FunctionId) { + case EsalGetVariable: + ReturnVal.Status = GetVariable ( + (CHAR16 *) Arg2, + (EFI_GUID *) Arg3, + (UINT32 *) Arg4, + (UINTN *) Arg5, + (VOID *) Arg6, + &Global->VariableBase[VirtualMode], + Global->FvbInstance + ); + return ReturnVal; + + case EsalGetNextVariableName: + ReturnVal.Status = GetNextVariableName ( + (UINTN *) Arg2, + (CHAR16 *) Arg3, + (EFI_GUID *) Arg4, + &Global->VariableBase[VirtualMode], + Global->FvbInstance + ); + return ReturnVal; + + case EsalSetVariable: + ReturnVal.Status = SetVariable ( + (CHAR16 *) Arg2, + (EFI_GUID *) Arg3, + (UINT32) Arg4, + (UINTN) Arg5, + (VOID *) Arg6, + &Global->VariableBase[VirtualMode], + (UINTN *) &Global->VolatileLastVariableOffset, + (UINTN *) &Global->NonVolatileLastVariableOffset, + Global->FvbInstance + ); + return ReturnVal; + + default: + ReturnVal.Status = EFI_SAL_INVALID_ARGUMENT; + return ReturnVal; + } +} + + +VOID +VariableClassAddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + CopyMem ( + &mVariableModuleGlobal->VariableBase[Virtual], + &mVariableModuleGlobal->VariableBase[Physical], + sizeof (VARIABLE_GLOBAL) + ); + + EfiConvertPointer ( + 0x0, + (VOID **) &mVariableModuleGlobal->VariableBase[Virtual].NonVolatileVariableBase + ); + EfiConvertPointer ( + 0x0, + (VOID **) &mVariableModuleGlobal->VariableBase[Virtual].VolatileVariableBase + ); + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal); +} + +EFI_STATUS +VariableServiceInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + EFI_STATUS Status; + + Status = VariableCommonInitialize (ImageHandle, SystemTable); + ASSERT_EFI_ERROR (Status); + + // + // Register All the Functions with Extended Sal. + // + RegisterEsalClass ( + &gEfiExtendedSalVariableServicesProtocolGuid, + mVariableModuleGlobal, + EsalVariableCommonEntry, + EsalGetVariable, + EsalVariableCommonEntry, + EsalGetNextVariableName, + EsalVariableCommonEntry, + EsalSetVariable, + NULL + ); + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Universal/EmuVariable/RuntimeDxe/Variable.h b/EdkModulePkg/Universal/EmuVariable/RuntimeDxe/Variable.h new file mode 100644 index 0000000000..d1fd5e271e --- /dev/null +++ b/EdkModulePkg/Universal/EmuVariable/RuntimeDxe/Variable.h @@ -0,0 +1,143 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Variable.h + +Abstract: + +--*/ + +#ifndef _VARIABLE_H +#define _VARIABLE_H + +// +// Statements that include other header files +// + +// +// BugBug: We need relcate the head file. +// +#include + +#if defined (MDE_CPU_IPF) +#define ALIGNMENT 8 +#else +#define ALIGNMENT 1 +#endif + + +#define VARIABLE_STORE_SIZE (64 * 1024) +#define SCRATCH_SIZE (4 * 1024) + +// +// Define GET_PAD_SIZE to optimize compiler +// +#if ((ALIGNMENT == 0) || (ALIGNMENT == 1)) +#define GET_PAD_SIZE(a) (0) +#else +#define GET_PAD_SIZE(a) (((~a) + 1) & (ALIGNMENT - 1)) +#endif + +#define GET_VARIABLE_NAME_PTR(a) (CHAR16 *) ((UINTN) (a) + sizeof (VARIABLE_HEADER)) + +typedef enum { + Physical, + Virtual +} VARIABLE_POINTER_TYPE; + +typedef struct { + VARIABLE_HEADER *CurrPtr; + VARIABLE_HEADER *EndPtr; + VARIABLE_HEADER *StartPtr; + BOOLEAN Volatile; +} VARIABLE_POINTER_TRACK; + +typedef struct { + EFI_PHYSICAL_ADDRESS VolatileVariableBase; + EFI_PHYSICAL_ADDRESS NonVolatileVariableBase; +} VARIABLE_GLOBAL; + +typedef struct { + VARIABLE_GLOBAL VariableBase[2]; + UINTN VolatileLastVariableOffset; + UINTN NonVolatileLastVariableOffset; + UINT32 FvbInstance; +} ESAL_VARIABLE_GLOBAL; + +// +// Functions +// +EFI_STATUS +EFIAPI +VariableCommonInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +; + +EFI_STATUS +EFIAPI +VariableServiceInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +; + +VOID +EFIAPI +VariableClassAddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +; + +EFI_STATUS +EFIAPI +GetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID * VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, + OUT VOID *Data, + IN VARIABLE_GLOBAL * Global, + IN UINT32 Instance + ) +; + +EFI_STATUS +EFIAPI +GetNextVariableName ( + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VendorGuid, + IN VARIABLE_GLOBAL *Global, + IN UINT32 Instance + ) +; + +EFI_STATUS +EFIAPI +SetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data, + IN VARIABLE_GLOBAL *Global, + IN UINTN *VolatileOffset, + IN UINTN *NonVolatileOffset, + IN UINT32 Instance + ) +; + +#endif diff --git a/EdkModulePkg/Universal/EmuVariable/RuntimeDxe/build.xml b/EdkModulePkg/Universal/EmuVariable/RuntimeDxe/build.xml new file mode 100644 index 0000000000..b2767a2608 --- /dev/null +++ b/EdkModulePkg/Universal/EmuVariable/RuntimeDxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwLite.c b/EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwLite.c new file mode 100644 index 0000000000..0d20e88058 --- /dev/null +++ b/EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwLite.c @@ -0,0 +1,951 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +Module Name: + + FtwLite.c + +Abstract: + + This is a simple fault tolerant write driver, based on PlatformFd library. + And it only supports write BufferSize <= SpareAreaLength. + + This boot service only protocol 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. + +Notes: + + The implementation uses an FTW Lite (Fault Tolerant Write) Work Space. + This work space is a memory copy of the work space on the Woring Block, + the size of the work space is the FTW_WORK_SPACE_SIZE bytes. + +--*/ + +#include + +// +// In write function, we should check the target range to prevent the user +// from writing Spare block and Working space directly. +// +// +// Fault Tolerant Write Protocol API +// +EFI_STATUS +EFIAPI +FtwLiteWrite ( + IN EFI_FTW_LITE_PROTOCOL *This, + IN EFI_HANDLE FvbHandle, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN VOID *Buffer + ) +/*++ + +Routine Description: + 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. + +Arguments: + This - Calling context + FvbHandle - The handle of FVB protocol that provides services for + reading, writing, and erasing the target block. + Lba - The logical block address of the target block. + Offset - The offset within the target block to place the data. + NumBytes - The number of bytes to write to the target block. + Buffer - The data to write. + +Returns: + EFI_SUCCESS - The function completed successfully + EFI_BAD_BUFFER_SIZE - The write would span a target block, which is not + a valid action. + EFI_ACCESS_DENIED - No writes have been allocated. + EFI_NOT_FOUND - Cannot find FVB by handle. + EFI_OUT_OF_RESOURCES - Cannot allocate memory. + EFI_ABORTED - The function could not complete successfully. + +--*/ +{ + EFI_STATUS Status; + EFI_FTW_LITE_DEVICE *FtwLiteDevice; + EFI_FTW_LITE_RECORD *Record; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; + EFI_PHYSICAL_ADDRESS FvbPhysicalAddress; + UINTN MyLength; + UINTN MyOffset; + UINTN MyBufferSize; + UINT8 *MyBuffer; + UINTN SpareBufferSize; + UINT8 *SpareBuffer; + UINTN Index; + UINT8 *Ptr; + EFI_DEV_PATH_PTR DevPtr; + + // + // Refresh work space and get last record + // + FtwLiteDevice = FTW_LITE_CONTEXT_FROM_THIS (This); + Status = WorkSpaceRefresh (FtwLiteDevice); + if (EFI_ERROR (Status)) { + return EFI_ABORTED; + } + + Record = FtwLiteDevice->FtwLastRecord; + + // + // Check the flags of last write record + // + if ((Record->WriteAllocated == FTW_VALID_STATE) || (Record->SpareCompleted == FTW_VALID_STATE)) { + return EFI_ACCESS_DENIED; + } + // + // IF former record has completed, THEN use next record + // + if (Record->WriteCompleted == FTW_VALID_STATE) { + Record++; + FtwLiteDevice->FtwLastRecord = Record; + } + + MyOffset = (UINT8 *) Record - FtwLiteDevice->FtwWorkSpace; + + // + // Check if the input data can fit within the target block + // + if ((Offset +*NumBytes) > FtwLiteDevice->SpareAreaLength) { + return EFI_BAD_BUFFER_SIZE; + } + // + // Check if there is enough free space for allocate a record + // + if ((MyOffset + WRITE_TOTAL_SIZE) > FtwLiteDevice->FtwWorkSpaceSize) { + Status = FtwReclaimWorkSpace (FtwLiteDevice); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "FtwLite: Reclaim work space - %r", Status)); + return EFI_ABORTED; + } + } + // + // Get the FVB protocol by handle + // + Status = FtwGetFvbByHandle (FvbHandle, &Fvb); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + // + // Allocate a write record in workspace. + // Update Header->WriteAllocated as VALID + // + Status = FtwUpdateFvState ( + FtwLiteDevice->FtwFvBlock, + FtwLiteDevice->FtwWorkSpaceLba, + FtwLiteDevice->FtwWorkSpaceBase + MyOffset, + WRITE_ALLOCATED + ); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_FTW_LITE, "FtwLite: Allocate record - %r\n", Status)); + return EFI_ABORTED; + } + + Record->WriteAllocated = FTW_VALID_STATE; + + // + // Prepare data of write record, filling DevPath with memory mapped address. + // + DevPtr.MemMap = (MEMMAP_DEVICE_PATH *) &Record->DevPath; + DevPtr.MemMap->Header.Type = HARDWARE_DEVICE_PATH; + DevPtr.MemMap->Header.SubType = HW_MEMMAP_DP; + SetDevicePathNodeLength (&DevPtr.MemMap->Header, sizeof (MEMMAP_DEVICE_PATH)); + + Status = Fvb->GetPhysicalAddress (Fvb, &FvbPhysicalAddress); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_FTW_LITE, "FtwLite: Get FVB physical address - %r\n", Status)); + return EFI_ABORTED; + } + + DevPtr.MemMap->MemoryType = EfiMemoryMappedIO; + DevPtr.MemMap->StartingAddress = FvbPhysicalAddress; + DevPtr.MemMap->EndingAddress = FvbPhysicalAddress +*NumBytes; + // + // ignored! + // + Record->Lba = Lba; + Record->Offset = Offset; + Record->NumBytes = *NumBytes; + + // + // Write the record to the work space. + // + MyOffset = (UINT8 *) Record - FtwLiteDevice->FtwWorkSpace; + MyLength = FTW_LITE_RECORD_SIZE; + + Status = FtwLiteDevice->FtwFvBlock->Write ( + FtwLiteDevice->FtwFvBlock, + FtwLiteDevice->FtwWorkSpaceLba, + FtwLiteDevice->FtwWorkSpaceBase + MyOffset, + &MyLength, + (UINT8 *) Record + ); + if (EFI_ERROR (Status)) { + return EFI_ABORTED; + } + // + // Record has been written to working block, then write data. + // + // + // Allocate a memory buffer + // + MyBufferSize = FtwLiteDevice->SpareAreaLength; + MyBuffer = AllocatePool (MyBufferSize); + if (MyBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Starting at Lba, if the number of the rest blocks on Fvb is less + // than NumberOfSpareBlock. + // + // + // Read all original data from target block to memory buffer + // + if (IsInWorkingBlock (FtwLiteDevice, Fvb, Lba)) { + // + // If target block falls into working block, we must follow the process of + // updating working block. + // + Ptr = MyBuffer; + for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) { + MyLength = FtwLiteDevice->SizeOfSpareBlock; + Status = FtwLiteDevice->FtwFvBlock->Read ( + FtwLiteDevice->FtwFvBlock, + FtwLiteDevice->FtwWorkBlockLba + Index, + 0, + &MyLength, + Ptr + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (MyBuffer); + return EFI_ABORTED; + } + + Ptr += MyLength; + } + // + // Update Offset by adding the offset from the start LBA of working block to + // the target LBA. The target block can not span working block! + // + Offset = (((UINTN) (Lba - FtwLiteDevice->FtwWorkBlockLba)) * FtwLiteDevice->SizeOfSpareBlock + Offset); + ASSERT ((Offset +*NumBytes) <= FtwLiteDevice->SpareAreaLength); + + } else { + + Ptr = MyBuffer; + for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) { + MyLength = FtwLiteDevice->SizeOfSpareBlock; + Status = Fvb->Read (Fvb, Lba + Index, 0, &MyLength, Ptr); + if (EFI_ERROR (Status)) { + gBS->FreePool (MyBuffer); + return EFI_ABORTED; + } + + Ptr += MyLength; + } + } + // + // Overwrite the updating range data with + // the input buffer content + // + CopyMem (MyBuffer + Offset, Buffer, *NumBytes); + + // + // Try to keep the content of spare block + // Save spare block into a spare backup memory buffer (Sparebuffer) + // + SpareBufferSize = FtwLiteDevice->SpareAreaLength; + SpareBuffer = AllocatePool (SpareBufferSize); + if (SpareBuffer == NULL) { + gBS->FreePool (MyBuffer); + return EFI_OUT_OF_RESOURCES; + } + + Ptr = SpareBuffer; + for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) { + MyLength = FtwLiteDevice->SizeOfSpareBlock; + Status = FtwLiteDevice->FtwBackupFvb->Read ( + FtwLiteDevice->FtwBackupFvb, + FtwLiteDevice->FtwSpareLba + Index, + 0, + &MyLength, + Ptr + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (MyBuffer); + gBS->FreePool (SpareBuffer); + return EFI_ABORTED; + } + + Ptr += MyLength; + } + // + // Write the memory buffer to spare block + // Don't forget to erase Flash first. + // + Status = FtwEraseSpareBlock (FtwLiteDevice); + Ptr = MyBuffer; + for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) { + MyLength = FtwLiteDevice->SizeOfSpareBlock; + Status = FtwLiteDevice->FtwBackupFvb->Write ( + FtwLiteDevice->FtwBackupFvb, + FtwLiteDevice->FtwSpareLba + Index, + 0, + &MyLength, + Ptr + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (MyBuffer); + gBS->FreePool (SpareBuffer); + return EFI_ABORTED; + } + + Ptr += MyLength; + } + // + // Free MyBuffer + // + gBS->FreePool (MyBuffer); + + // + // Set the SpareCompleteD in the FTW record, + // + MyOffset = (UINT8 *) Record - FtwLiteDevice->FtwWorkSpace; + Status = FtwUpdateFvState ( + FtwLiteDevice->FtwFvBlock, + FtwLiteDevice->FtwWorkSpaceLba, + FtwLiteDevice->FtwWorkSpaceBase + MyOffset, + SPARE_COMPLETED + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (SpareBuffer); + return EFI_ABORTED; + } + + Record->SpareCompleted = 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 (FtwLiteDevice, Fvb); + if (EFI_ERROR (Status)) { + gBS->FreePool (SpareBuffer); + return EFI_ABORTED; + } + + Record++; + FtwLiteDevice->FtwLastRecord = Record; + + // + // Restore spare backup buffer into spare block , if no failure happened during FtwWrite. + // + Status = FtwEraseSpareBlock (FtwLiteDevice); + Ptr = SpareBuffer; + for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) { + MyLength = FtwLiteDevice->SizeOfSpareBlock; + Status = FtwLiteDevice->FtwBackupFvb->Write ( + FtwLiteDevice->FtwBackupFvb, + FtwLiteDevice->FtwSpareLba + Index, + 0, + &MyLength, + Ptr + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (SpareBuffer); + return EFI_ABORTED; + } + + Ptr += MyLength; + } + // + // All success. + // + gBS->FreePool (SpareBuffer); + + DEBUG ( + (EFI_D_FTW_LITE, + "FtwLite: Write() success, (Lba:Offset)=(%lx:0x%x), NumBytes: 0x%x\n", + Lba, + Offset, + *NumBytes) + ); + + return EFI_SUCCESS; +} + + +EFI_STATUS +FtwWriteRecord ( + IN EFI_FTW_LITE_DEVICE *FtwLiteDevice, + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb + ) +/*++ + +Routine Description: + Write a record with fault tolerant mannaer. + Since the content has already backuped in spare block, the write is + guaranteed to be completed with fault tolerant manner. + +Arguments: + FtwLiteDevice - The private data of FTW_LITE driver + Fvb - The FVB protocol that provides services for + reading, writing, and erasing the target block. + +Returns: + EFI_SUCCESS - The function completed successfully + EFI_ABORTED - The function could not complete successfully + +--*/ +{ + EFI_STATUS Status; + EFI_FTW_LITE_RECORD *Record; + EFI_LBA WorkSpaceLbaOffset; + UINTN Offset; + + // + // Spare Complete but Destination not complete, + // Recover the targt block with the spare block. + // + Record = FtwLiteDevice->FtwLastRecord; + + // + // IF target block is working block, THEN Flush Spare Block To Working Block; + // ELSE IF target block is boot block, THEN Flush Spare Block To boot Block; + // ELSE flush spare block to normal target block.ENDIF + // + if (IsInWorkingBlock (FtwLiteDevice, Fvb, Record->Lba)) { + // + // If target block is working block, Attention: + // it's required to set SPARE_COMPLETED to spare block. + // + WorkSpaceLbaOffset = FtwLiteDevice->FtwWorkSpaceLba - FtwLiteDevice->FtwWorkBlockLba; + Offset = (UINT8 *) Record - FtwLiteDevice->FtwWorkSpace; + Status = FtwUpdateFvState ( + FtwLiteDevice->FtwBackupFvb, + FtwLiteDevice->FtwSpareLba + WorkSpaceLbaOffset, + FtwLiteDevice->FtwWorkSpaceBase + Offset, + SPARE_COMPLETED + ); + ASSERT_EFI_ERROR (Status); + + Status = FlushSpareBlockToWorkingBlock (FtwLiteDevice); + } else if (IsBootBlock (FtwLiteDevice, Fvb, Record->Lba)) { + // + // Update boot block + // + Status = FlushSpareBlockToBootBlock (FtwLiteDevice); + } else { + // + // Update blocks other than working block or boot block + // + Status = FlushSpareBlockToTargetBlock (FtwLiteDevice, Fvb, Record->Lba); + } + + ASSERT_EFI_ERROR (Status); + + // + // Set WriteCompleted flag in record + // + Offset = (UINT8 *) Record - FtwLiteDevice->FtwWorkSpace; + Status = FtwUpdateFvState ( + FtwLiteDevice->FtwFvBlock, + FtwLiteDevice->FtwWorkSpaceLba, + FtwLiteDevice->FtwWorkSpaceBase + Offset, + WRITE_COMPLETED + ); + ASSERT_EFI_ERROR (Status); + + Record->WriteCompleted = FTW_VALID_STATE; + return EFI_SUCCESS; +} + + +EFI_STATUS +FtwRestart ( + IN EFI_FTW_LITE_DEVICE *FtwLiteDevice + ) +/*++ + +Routine Description: + Restarts a previously interrupted write. The caller must provide the + block protocol needed to complete the interrupted write. + +Arguments: + FtwLiteDevice - The private data of FTW_LITE driver + FvbHandle - The handle of FVB protocol that provides services for + reading, writing, and erasing the target block. + +Returns: + EFI_SUCCESS - The function completed successfully + EFI_ACCESS_DENIED - No pending writes exist + EFI_NOT_FOUND - FVB protocol not found by the handle + EFI_ABORTED - The function could not complete successfully + +--*/ +{ + EFI_STATUS Status; + EFI_FTW_LITE_RECORD *Record; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; + EFI_DEV_PATH_PTR DevPathPtr; + + // + // Spare Completed but Destination not complete, + // Recover the targt block with the spare block. + // + Record = FtwLiteDevice->FtwLastRecord; + + // + // Only support memory mapped FVB device path by now. + // + DevPathPtr.MemMap = (MEMMAP_DEVICE_PATH *) &Record->DevPath; + if (!((DevPathPtr.MemMap->Header.Type == HARDWARE_DEVICE_PATH) && (DevPathPtr.MemMap->Header.SubType == HW_MEMMAP_DP)) + ) { + DEBUG ((EFI_D_FTW_LITE, "FtwLite: FVB Device Path is not memory mapped\n")); + return EFI_ABORTED; + } + + Status = GetFvbByAddress (DevPathPtr.MemMap->StartingAddress, &Fvb); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + // + // Since the content has already backuped in spare block, the write is + // guaranteed to be completed with fault tolerant manner. + // + Status = FtwWriteRecord (FtwLiteDevice, Fvb); + DEBUG ((EFI_D_FTW_INFO, "FtwLite: Restart() - %r\n", Status)); + + Record++; + FtwLiteDevice->FtwLastRecord = Record; + + // + // Erase Spare block + // This is restart, no need to keep spareblock content. + // + FtwEraseSpareBlock (FtwLiteDevice); + + return Status; +} + + +EFI_STATUS +FtwAbort ( + IN EFI_FTW_LITE_DEVICE *FtwLiteDevice + ) +/*++ + +Routine Description: + Aborts all previous allocated writes. + +Arguments: + FtwLiteDevice - The private data of FTW_LITE driver + +Returns: + EFI_SUCCESS - The function completed successfully + EFI_ABORTED - The function could not complete successfully. + EFI_NOT_FOUND - No allocated writes exist. + +--*/ +{ + EFI_STATUS Status; + UINTN Offset; + + if (FtwLiteDevice->FtwLastRecord->WriteCompleted == FTW_VALID_STATE) { + return EFI_NOT_FOUND; + } + // + // Update the complete state of the header as VALID and abort. + // + Offset = (UINT8 *) FtwLiteDevice->FtwLastRecord - FtwLiteDevice->FtwWorkSpace; + Status = FtwUpdateFvState ( + FtwLiteDevice->FtwFvBlock, + FtwLiteDevice->FtwWorkSpaceLba, + FtwLiteDevice->FtwWorkSpaceBase + Offset, + WRITE_COMPLETED + ); + if (EFI_ERROR (Status)) { + return EFI_ABORTED; + } + + FtwLiteDevice->FtwLastRecord->WriteCompleted = FTW_VALID_STATE; + + Status = FtwGetLastRecord (FtwLiteDevice, &FtwLiteDevice->FtwLastRecord); + + // + // Erase the spare block + // + Status = FtwEraseSpareBlock (FtwLiteDevice); + + DEBUG ((EFI_D_FTW_INFO, "FtwLite: Abort() success \n")); + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +InitializeFtwLite ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + Routine Description: + This function is the entry point of the Fault Tolerant Write driver. + + Arguments: + ImageHandle - EFI_HANDLE: A handle for the image that is initializing + this driver + SystemTable - EFI_SYSTEM_TABLE: A pointer to the EFI system table + + Returns: + EFI_SUCCESS - FTW has finished the initialization + EFI_ABORTED - FTW initialization error + +--*/ +{ + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; + UINTN Index; + EFI_HANDLE *HandleBuffer; + UINTN HandleCount; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_PHYSICAL_ADDRESS BaseAddress; + EFI_FTW_LITE_DEVICE *FtwLiteDevice; + EFI_FTW_LITE_RECORD *Record; + UINTN Length; + EFI_STATUS Status; + UINTN Offset; + EFI_FLASH_MAP_ENTRY_DATA *FlashMapEntry; + EFI_FV_BLOCK_MAP_ENTRY *FvbMapEntry; + UINT32 LbaIndex; + EFI_PEI_HOB_POINTERS GuidHob; + + // + // Allocate Private data of this driver, + // INCLUDING THE FtwWorkSpace[FTW_WORK_SPACE_SIZE]. + // + FtwLiteDevice = NULL; + FtwLiteDevice = AllocatePool (sizeof (EFI_FTW_LITE_DEVICE) + FTW_WORK_SPACE_SIZE); + if (FtwLiteDevice != NULL) { + Status = EFI_SUCCESS; + } else { + Status = EFI_OUT_OF_RESOURCES; + } + + ASSERT_EFI_ERROR (Status); + + ZeroMem (FtwLiteDevice, sizeof (EFI_FTW_LITE_DEVICE)); + FtwLiteDevice->Signature = FTW_LITE_DEVICE_SIGNATURE; + + // + // Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE. + // + FtwLiteDevice->FtwWorkSpace = (UINT8 *) (FtwLiteDevice + 1); + FtwLiteDevice->FtwWorkSpaceSize = FTW_WORK_SPACE_SIZE; + SetMem ( + FtwLiteDevice->FtwWorkSpace, + FtwLiteDevice->FtwWorkSpaceSize, + FTW_ERASED_BYTE + ); + FtwLiteDevice->FtwWorkSpaceHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) FtwLiteDevice->FtwWorkSpace; + + FtwLiteDevice->FtwLastRecord = NULL; + + FtwLiteDevice->SpareAreaLength = 0; + FtwLiteDevice->WorkSpaceLength = 0; + + GuidHob.Raw = GetHobList (); + while (NULL != (GuidHob.Raw = GetNextGuidHob (&gEfiFlashMapHobGuid, GuidHob.Raw))) { + FlashMapEntry = (EFI_FLASH_MAP_ENTRY_DATA *) GET_GUID_HOB_DATA (GuidHob.Guid); + // + // Get the FTW work space Flash Map SUB area + // + if ((FlashMapEntry->AreaType == EFI_FLASH_AREA_FTW_STATE) && (FlashMapEntry->NumEntries == 1)) { + FtwLiteDevice->WorkSpaceAddress = FlashMapEntry->Entries[0].Base; + FtwLiteDevice->WorkSpaceLength = (UINTN) FlashMapEntry->Entries[0].Length; + } + // + // Get the FTW backup SUB area + // + if ((FlashMapEntry->AreaType == EFI_FLASH_AREA_FTW_BACKUP) && (FlashMapEntry->NumEntries == 1)) { + FtwLiteDevice->SpareAreaAddress = FlashMapEntry->Entries[0].Base; + FtwLiteDevice->SpareAreaLength = (UINTN) FlashMapEntry->Entries[0].Length; + } + + GuidHob.Raw = GET_NEXT_HOB (GuidHob); + } + + ASSERT ((FtwLiteDevice->WorkSpaceLength != 0) && (FtwLiteDevice->SpareAreaLength != 0)); + + // + // Locate FVB protocol + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiFirmwareVolumeBlockProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + ASSERT_EFI_ERROR (Status); + + ASSERT (HandleCount > 0); + + FtwLiteDevice->FtwFvBlock = NULL; + FtwLiteDevice->FtwBackupFvb = NULL; + FtwLiteDevice->FtwWorkSpaceLba = (EFI_LBA) (-1); + FtwLiteDevice->FtwSpareLba = (EFI_LBA) (-1); + for (Index = 0; Index < HandleCount; Index += 1) { + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiFirmwareVolumeBlockProtocolGuid, + (VOID **) &Fvb + ); + ASSERT_EFI_ERROR (Status); + + Status = Fvb->GetPhysicalAddress (Fvb, &BaseAddress); + if (EFI_ERROR (Status)) { + continue; + } + + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) BaseAddress); + + if ((FtwLiteDevice->WorkSpaceAddress >= BaseAddress) && + (FtwLiteDevice->WorkSpaceAddress <= (BaseAddress + FwVolHeader->FvLength)) + ) { + FtwLiteDevice->FtwFvBlock = Fvb; + // + // To get the LBA of work space + // + if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) { + // + // FV may have multiple types of BlockLength + // + FvbMapEntry = &FwVolHeader->FvBlockMap[0]; + while (!((FvbMapEntry->NumBlocks == 0) && (FvbMapEntry->BlockLength == 0))) { + for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) { + if (FtwLiteDevice->WorkSpaceAddress < (BaseAddress + FvbMapEntry->BlockLength * LbaIndex)) { + FtwLiteDevice->FtwWorkSpaceLba = LbaIndex - 1; + // + // Get the Work space size and Base(Offset) + // + FtwLiteDevice->FtwWorkSpaceSize = FtwLiteDevice->WorkSpaceLength; + FtwLiteDevice->FtwWorkSpaceBase = (UINTN) (FtwLiteDevice->WorkSpaceAddress - (BaseAddress + FvbMapEntry->BlockLength * (LbaIndex - 1))); + break; + } + } + // + // end for + // + FvbMapEntry++; + } + // + // end while + // + } + } + + if ((FtwLiteDevice->SpareAreaAddress >= BaseAddress) && + (FtwLiteDevice->SpareAreaAddress <= (BaseAddress + FwVolHeader->FvLength)) + ) { + FtwLiteDevice->FtwBackupFvb = Fvb; + // + // To get the LBA of spare + // + if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) { + // + // FV may have multiple types of BlockLength + // + FvbMapEntry = &FwVolHeader->FvBlockMap[0]; + while (!((FvbMapEntry->NumBlocks == 0) && (FvbMapEntry->BlockLength == 0))) { + for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) { + if (FtwLiteDevice->SpareAreaAddress < (BaseAddress + FvbMapEntry->BlockLength * LbaIndex)) { + // + // Get the NumberOfSpareBlock and SizeOfSpareBlock + // + FtwLiteDevice->FtwSpareLba = LbaIndex - 1; + FtwLiteDevice->SizeOfSpareBlock = FvbMapEntry->BlockLength; + FtwLiteDevice->NumberOfSpareBlock = FtwLiteDevice->SpareAreaLength / FtwLiteDevice->SizeOfSpareBlock; + // + // Check the range of spare area to make sure that it's in FV range + // + ASSERT ((FtwLiteDevice->FtwSpareLba + FtwLiteDevice->NumberOfSpareBlock) <= FvbMapEntry->NumBlocks); + break; + } + } + + FvbMapEntry++; + } + // + // end while + // + } + } + } + // + // Calculate the start LBA of working block. 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. + // + FtwLiteDevice->FtwWorkBlockLba = FtwLiteDevice->FtwWorkSpaceLba - FtwLiteDevice->NumberOfSpareBlock + 1; + if ((INT64) (FtwLiteDevice->FtwWorkBlockLba) < 0) { + FtwLiteDevice->FtwWorkBlockLba = 0; + } + + if ((FtwLiteDevice->FtwFvBlock == NULL) || + (FtwLiteDevice->FtwBackupFvb == NULL) || + (FtwLiteDevice->FtwWorkSpaceLba == (EFI_LBA) (-1)) || + (FtwLiteDevice->FtwSpareLba == (EFI_LBA) (-1)) + ) { + DEBUG ((EFI_D_ERROR, "FtwLite: Working or spare FVB not ready\n")); + ASSERT_EFI_ERROR (Status); + } + // + // Refresh workspace data from working block + // + Status = WorkSpaceRefresh (FtwLiteDevice); + ASSERT_EFI_ERROR (Status); + + // + // If the working block workspace is not valid, try the spare block + // + if (!IsValidWorkSpace (FtwLiteDevice->FtwWorkSpaceHeader)) { + DEBUG ((EFI_D_FTW_LITE, "FtwLite: Workspace invalid, read from backup\n")); + // + // Read from spare block + // + Length = FtwLiteDevice->FtwWorkSpaceSize; + Status = FtwLiteDevice->FtwBackupFvb->Read ( + FtwLiteDevice->FtwBackupFvb, + FtwLiteDevice->FtwSpareLba, + FtwLiteDevice->FtwWorkSpaceBase, + &Length, + FtwLiteDevice->FtwWorkSpace + ); + ASSERT_EFI_ERROR (Status); + + // + // If spare block is valid, then replace working block content. + // + if (IsValidWorkSpace (FtwLiteDevice->FtwWorkSpaceHeader)) { + Status = FlushSpareBlockToWorkingBlock (FtwLiteDevice); + DEBUG ((EFI_D_FTW_LITE, "FtwLite: Restart working block in Init() - %r\n", Status)); + ASSERT_EFI_ERROR (Status); + + FtwAbort (FtwLiteDevice); + // + // Refresh work space. + // + Status = WorkSpaceRefresh (FtwLiteDevice); + if (EFI_ERROR (Status)) { + return EFI_ABORTED; + } + } else { + DEBUG ((EFI_D_FTW_LITE, "FtwLite: Both are invalid, init workspace\n")); + // + // If both are invalid, then initialize work space. + // + SetMem ( + FtwLiteDevice->FtwWorkSpace, + FtwLiteDevice->FtwWorkSpaceSize, + FTW_ERASED_BYTE + ); + InitWorkSpaceHeader (FtwLiteDevice->FtwWorkSpaceHeader); + // + // Write to work space on the working block + // + Length = FtwLiteDevice->FtwWorkSpaceSize; + Status = FtwLiteDevice->FtwFvBlock->Write ( + FtwLiteDevice->FtwFvBlock, + FtwLiteDevice->FtwWorkSpaceLba, + FtwLiteDevice->FtwWorkSpaceBase, + &Length, + FtwLiteDevice->FtwWorkSpace + ); + if (EFI_ERROR (Status)) { + return EFI_ABORTED; + } + } + } + // + // Hook the protocol API + // + FtwLiteDevice->FtwLiteInstance.Write = FtwLiteWrite; + + // + // Install protocol interface + // + Status = gBS->InstallProtocolInterface ( + &FtwLiteDevice->Handle, + &gEfiFaultTolerantWriteLiteProtocolGuid, + EFI_NATIVE_INTERFACE, + &FtwLiteDevice->FtwLiteInstance + ); + if (EFI_ERROR (Status)) { + return EFI_ABORTED; + } + // + // If (!SpareCompleted) THEN Abort to rollback. + // + if ((FtwLiteDevice->FtwLastRecord->WriteAllocated == FTW_VALID_STATE) && + (FtwLiteDevice->FtwLastRecord->SpareCompleted != FTW_VALID_STATE) + ) { + DEBUG ((EFI_D_FTW_LITE, "FtwLite: Init.. record not SpareCompleted, abort()\n")); + FtwAbort (FtwLiteDevice); + } + // + // if (SpareCompleted) THEN Restart to fault tolerant write. + // + if ((FtwLiteDevice->FtwLastRecord->SpareCompleted == FTW_VALID_STATE) && + (FtwLiteDevice->FtwLastRecord->WriteCompleted != FTW_VALID_STATE) + ) { + + Status = FtwRestart (FtwLiteDevice); + DEBUG ((EFI_D_FTW_LITE, "FtwLite: Restart last write - %r\n", Status)); + if (EFI_ERROR (Status)) { + return Status; + } + } + // + // To check the workspace buffer behind last records is EMPTY or not. + // If it's not EMPTY, FTW_LITE also need to call reclaim(). + // + Record = FtwLiteDevice->FtwLastRecord; + Offset = (UINT8 *) Record - FtwLiteDevice->FtwWorkSpace; + if (FtwLiteDevice->FtwWorkSpace[Offset] != FTW_ERASED_BYTE) { + Offset += WRITE_TOTAL_SIZE; + } + + if (!IsErasedFlashBuffer ( + FTW_ERASE_POLARITY, + FtwLiteDevice->FtwWorkSpace + Offset, + FtwLiteDevice->FtwWorkSpaceSize - Offset + )) { + DEBUG ((EFI_D_FTW_LITE, "FtwLite: Workspace is dirty, call reclaim...\n")); + Status = FtwReclaimWorkSpace (FtwLiteDevice); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_FTW_LITE, "FtwLite: Workspace reclaim - %r\n", Status)); + return EFI_ABORTED; + } + } + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwLite.dxs b/EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwLite.dxs new file mode 100644 index 0000000000..f2a6221b5d --- /dev/null +++ b/EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwLite.dxs @@ -0,0 +1,28 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +Module Name: + + FtwLite.dxs + +Abstract: + + Dependency expression source file. + +--*/ +#include +#include + + +DEPENDENCY_START + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL_GUID AND EFI_ALTERNATE_FV_BLOCK_GUID +DEPENDENCY_END diff --git a/EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwLite.h b/EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwLite.h new file mode 100644 index 0000000000..8754827e2d --- /dev/null +++ b/EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwLite.h @@ -0,0 +1,675 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +Module Name: + + FtwLite.h + +Abstract: + + This is a simple fault tolerant write driver, based on PlatformFd library. + And it only supports write BufferSize <= SpareAreaLength. + + This boot service only protocol 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. + +--*/ + +#ifndef _EFI_FAULT_TOLERANT_WRITE_LITE_H_ +#define _EFI_FAULT_TOLERANT_WRITE_LITE_H_ + +#include +#include + +#define EFI_D_FTW_LITE EFI_D_ERROR +#define EFI_D_FTW_INFO EFI_D_INFO + +// +// Flash erase polarity is 1 +// +#define FTW_ERASE_POLARITY 1 + +#define FTW_VALID_STATE 0 +#define FTW_INVALID_STATE 1 + +#define FTW_ERASED_BYTE ((UINT8) (255)) +#define FTW_POLARITY_REVERT ((UINT8) (255)) + +typedef struct { + UINT8 WriteAllocated : 1; + UINT8 SpareCompleted : 1; + UINT8 WriteCompleted : 1; + UINT8 Reserved : 5; +#define WRITE_ALLOCATED 0x1 +#define SPARE_COMPLETED 0x2 +#define WRITE_COMPLETED 0x4 + + EFI_DEV_PATH DevPath; + EFI_LBA Lba; + UINTN Offset; + UINTN NumBytes; + // + // UINTN SpareAreaOffset; + // +} EFI_FTW_LITE_RECORD; + +#define FTW_LITE_DEVICE_SIGNATURE EFI_SIGNATURE_32 ('F', 'T', 'W', 'L') + +// +// MACRO for Block size. +// Flash Erasing will do in block granularity. +// +#ifdef FV_BLOCK_SIZE +#define FTW_BLOCK_SIZE FV_BLOCK_SIZE +#else +#define FV_BLOCK_SIZE 0x10000 +#define FTW_BLOCK_SIZE FV_BLOCK_SIZE +#endif +// +// MACRO for FTW WORK SPACE Base & Size +// +#ifdef EFI_FTW_WORKING_OFFSET +#define FTW_WORK_SPACE_BASE EFI_FTW_WORKING_OFFSET +#else +#define FTW_WORK_SPACE_BASE 0x00E000 +#endif + +#ifdef EFI_FTW_WORKING_LENGTH +#define FTW_WORK_SPACE_SIZE EFI_FTW_WORKING_LENGTH +#else +#define FTW_WORK_SPACE_SIZE 0x002000 +#endif +// +// MACRO for FTW header and record +// +#define FTW_WORKING_QUEUE_SIZE (FTW_WORK_SPACE_SIZE - sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)) +#define FTW_LITE_RECORD_SIZE (sizeof (EFI_FTW_LITE_RECORD)) +#define WRITE_TOTAL_SIZE FTW_LITE_RECORD_SIZE + +// +// EFI Fault tolerant protocol private data structure +// +typedef struct { + UINTN Signature; + EFI_HANDLE Handle; + EFI_FTW_LITE_PROTOCOL FtwLiteInstance; + EFI_PHYSICAL_ADDRESS WorkSpaceAddress; + UINTN WorkSpaceLength; + EFI_PHYSICAL_ADDRESS SpareAreaAddress; + UINTN SpareAreaLength; + UINTN NumberOfSpareBlock; // Number of the blocks in spare block + UINTN SizeOfSpareBlock; // Block size in bytes of the blocks in spare block + EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *FtwWorkSpaceHeader; + EFI_FTW_LITE_RECORD *FtwLastRecord; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FtwFvBlock; // FVB of working block + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FtwBackupFvb; // FVB of spare block + EFI_LBA FtwSpareLba; + EFI_LBA FtwWorkBlockLba; // Start LBA of working block + EFI_LBA FtwWorkSpaceLba; // Start LBA of working space + UINTN FtwWorkSpaceBase; // Offset from LBA start addr + UINTN FtwWorkSpaceSize; + UINT8 *FtwWorkSpace; + // + // Following a buffer of FtwWorkSpace[FTW_WORK_SPACE_SIZE], + // Allocated with EFI_FTW_LITE_DEVICE. + // +} EFI_FTW_LITE_DEVICE; + +#define FTW_LITE_CONTEXT_FROM_THIS(a) CR (a, EFI_FTW_LITE_DEVICE, FtwLiteInstance, FTW_LITE_DEVICE_SIGNATURE) + +// +// Driver entry point +// +EFI_STATUS +EFIAPI +InitializeFtwLite ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + This function is the entry point of the Fault Tolerant Write driver. + +Arguments: + ImageHandle - EFI_HANDLE: A handle for the image that is initializing + this driver + SystemTable - EFI_SYSTEM_TABLE: A pointer to the EFI system table + +Returns: + EFI_SUCCESS - FTW has finished the initialization + EFI_ABORTED - FTW initialization error + +--*/ +; + +// +// Fault Tolerant Write Protocol API +// +EFI_STATUS +EFIAPI +FtwLiteWrite ( + IN EFI_FTW_LITE_PROTOCOL *This, + IN EFI_HANDLE FvbHandle, + IN EFI_LBA Lba, + IN UINTN Offset, + IN UINTN *NumBytes, + IN VOID *Buffer + ) +/*++ + +Routine Description: + 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. + +Arguments: + This - Calling context + FvbHandle - The handle of FVB protocol that provides services for + reading, writing, and erasing the target block. + Lba - The logical block address of the target block. + Offset - The offset within the target block to place the data. + NumBytes - The number of bytes to write to the target block. + Buffer - The data to write. + +Returns: + EFI_SUCCESS - The function completed successfully + EFI_BAD_BUFFER_SIZE - The write would span a target block, which is not + a valid action. + EFI_ACCESS_DENIED - No writes have been allocated. + EFI_NOT_FOUND - Cannot find FVB by handle. + EFI_OUT_OF_RESOURCES - Cannot allocate memory. + EFI_ABORTED - The function could not complete successfully. + +--*/ +; + +// +// Internal functions +// +EFI_STATUS +FtwRestart ( + IN EFI_FTW_LITE_DEVICE *FtwLiteDevice + ) +/*++ + +Routine Description: + Restarts a previously interrupted write. The caller must provide the + block protocol needed to complete the interrupted write. + +Arguments: + FtwLiteDevice - The private data of FTW_LITE driver + FvbHandle - The handle of FVB protocol that provides services for + reading, writing, and erasing the target block. + +Returns: + EFI_SUCCESS - The function completed successfully + EFI_ACCESS_DENIED - No pending writes exist + EFI_NOT_FOUND - FVB protocol not found by the handle + EFI_ABORTED - The function could not complete successfully + +--*/ +; + +EFI_STATUS +FtwAbort ( + IN EFI_FTW_LITE_DEVICE *FtwLiteDevice + ) +/*++ + +Routine Description: + Aborts all previous allocated writes. + +Arguments: + FtwLiteDevice - The private data of FTW_LITE driver + +Returns: + EFI_SUCCESS - The function completed successfully + EFI_ABORTED - The function could not complete successfully. + EFI_NOT_FOUND - No allocated writes exist. + +--*/ +; + + +EFI_STATUS +FtwWriteRecord ( + IN EFI_FTW_LITE_DEVICE *FtwLiteDevice, + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb + ) +/*++ + +Routine Description: + Write a record with fault tolerant mannaer. + Since the content has already backuped in spare block, the write is + guaranteed to be completed with fault tolerant manner. + +Arguments: + FtwLiteDevice - The private data of FTW_LITE driver + Fvb - The FVB protocol that provides services for + reading, writing, and erasing the target block. + +Returns: + EFI_SUCCESS - The function completed successfully + EFI_ABORTED - The function could not complete successfully + +--*/ +; + +EFI_STATUS +FtwEraseBlock ( + IN EFI_FTW_LITE_DEVICE *FtwLiteDevice, + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock, + EFI_LBA Lba + ) +/*++ + +Routine Description: + To Erase one block. The size is FTW_BLOCK_SIZE + +Arguments: + FtwLiteDevice - Calling context + FvBlock - FVB Protocol interface + Lba - Lba of the firmware block + +Returns: + EFI_SUCCESS - Block LBA is Erased successfully + Others - Error occurs + +--*/ +; + +EFI_STATUS +FtwEraseSpareBlock ( + IN EFI_FTW_LITE_DEVICE *FtwLiteDevice + ) +/*++ + +Routine Description: + + Erase spare block. + +Arguments: + + FtwLiteDevice - Calling context + +Returns: + + Status code + +--*/ +; + +EFI_STATUS +FtwGetFvbByHandle ( + IN EFI_HANDLE FvBlockHandle, + OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock + ) +/*++ + +Routine Description: + Retrive the proper FVB protocol interface by HANDLE. + +Arguments: + FvBlockHandle - The handle of FVB protocol that provides services for + reading, writing, and erasing the target block. + FvBlock - The interface of FVB protocol + +Returns: + EFI_SUCCESS - The function completed successfully + EFI_ABORTED - The function could not complete successfully +--*/ +; + +EFI_STATUS +GetFvbByAddress ( + IN EFI_PHYSICAL_ADDRESS Address, + OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock + ) +/*++ + +Routine Description: + + Get firmware block by address. + +Arguments: + + Address - Address specified the block + FvBlock - The block caller wanted + +Returns: + + Status code + + EFI_NOT_FOUND - Block not found + +--*/ +; + +BOOLEAN +IsInWorkingBlock ( + EFI_FTW_LITE_DEVICE *FtwLiteDevice, + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock, + EFI_LBA Lba + ) +/*++ + +Routine Description: + + Is it in working block? + +Arguments: + + FtwLiteDevice - Calling context + FvBlock - Fvb protocol instance + Lba - The block specified + +Returns: + + In working block or not + +--*/ +; + +BOOLEAN +IsBootBlock ( + EFI_FTW_LITE_DEVICE *FtwLiteDevice, + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock, + EFI_LBA Lba + ) +/*++ + +Routine Description: + + Check whether the block is a boot block. + +Arguments: + + FtwLiteDevice - Calling context + FvBlock - Fvb protocol instance + Lba - Lba value + +Returns: + + Is a boot block or not + +--*/ +; + +EFI_STATUS +FlushSpareBlockToTargetBlock ( + EFI_FTW_LITE_DEVICE *FtwLiteDevice, + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock, + EFI_LBA Lba + ) +/*++ + +Routine Description: + 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. LBA is + FtwLiteDevice->FtwSpareLba. + Target block is accessed by FvBlock protocol interface. LBA is Lba. + +Arguments: + FtwLiteDevice - The private data of FTW_LITE driver + FvBlock - FVB Protocol interface to access target block + Lba - Lba of the target block + +Returns: + EFI_SUCCESS - Spare block content is copied to target block + EFI_INVALID_PARAMETER - Input parameter error + EFI_OUT_OF_RESOURCES - Allocate memory error + EFI_ABORTED - The function could not complete successfully + +--*/ +; + +EFI_STATUS +FlushSpareBlockToWorkingBlock ( + EFI_FTW_LITE_DEVICE *FtwLiteDevice + ) +/*++ + +Routine Description: + 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 + FtwLiteDevice->FtwSpareLba. + Working block is accessed by FTW working FVB protocol interface. LBA is + FtwLiteDevice->FtwWorkBlockLba. + +Arguments: + FtwLiteDevice - The private data of FTW_LITE driver + +Returns: + EFI_SUCCESS - Spare block content is copied to target block + EFI_OUT_OF_RESOURCES - Allocate memory error + EFI_ABORTED - The function could not complete successfully + +Notes: + 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. + +--*/ +; + +EFI_STATUS +FlushSpareBlockToBootBlock ( + EFI_FTW_LITE_DEVICE *FtwLiteDevice + ) +/*++ + +Routine Description: + Copy the content of spare block to a boot block. Size is FTW_BLOCK_SIZE. + Spare block is accessed by FTW backup FVB protocol interface. LBA is + FtwLiteDevice->FtwSpareLba. + Boot block is accessed by BootFvb protocol interface. LBA is 0. + +Arguments: + FtwLiteDevice - The private data of FTW_LITE driver + +Returns: + EFI_SUCCESS - Spare block content is copied to boot block + EFI_INVALID_PARAMETER - Input parameter error + EFI_OUT_OF_RESOURCES - Allocate memory error + EFI_ABORTED - The function could not complete successfully + +Notes: + +--*/ +; + +EFI_STATUS +FtwUpdateFvState ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock, + IN EFI_LBA Lba, + IN UINTN Offset, + IN UINT8 NewBit + ) +/*++ + +Routine Description: + 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. + +Arguments: + FvBlock - FVB Protocol interface to access SrcBlock and DestBlock + Lba - Lba of a block + Offset - Offset on the Lba + NewBit - New value that will override the old value if it can be change + +Returns: + EFI_SUCCESS - A state bit has been updated successfully + Others - Access block device error. + +Notes: + Assume all bits of State are inside the same BYTE. + + EFI_ABORTED - Read block fail +--*/ +; + +EFI_STATUS +FtwGetLastRecord ( + IN EFI_FTW_LITE_DEVICE *FtwLiteDevice, + OUT EFI_FTW_LITE_RECORD **FtwLastRecord + ) +/*++ + +Routine Description: + Get the last Write record pointer. + The last record is the record whose 'complete' state hasn't been set. + After all, this header may be a EMPTY header entry for next Allocate. + +Arguments: + FtwLiteDevice - Private data of this driver + FtwLastRecord - Pointer to retrieve the last write record + +Returns: + EFI_SUCCESS - Get the last write record successfully + EFI_ABORTED - The FTW work space is damaged + +--*/ +; + +BOOLEAN +IsErasedFlashBuffer ( + IN BOOLEAN Polarity, + IN UINT8 *Buffer, + IN UINTN BufferSize + ) +/*++ + +Routine Description: + + Check whether a flash buffer is erased. + +Arguments: + + Polarity - All 1 or all 0 + Buffer - Buffer to check + BufferSize - Size of the buffer + +Returns: + + Erased or not. + +--*/ +; + +EFI_STATUS +InitWorkSpaceHeader ( + IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader + ) +/*++ + +Routine Description: + Initialize a work space when there is no work space. + +Arguments: + WorkingHeader - Pointer of working block header + +Returns: + EFI_SUCCESS - The function completed successfully + EFI_ABORTED - The function could not complete successfully. + +--*/ +; + +EFI_STATUS +WorkSpaceRefresh ( + IN EFI_FTW_LITE_DEVICE *FtwLiteDevice + ) +/*++ + +Routine Description: + Read from working block to refresh the work space in memory. + +Arguments: + FtwLiteDevice - Point to private data of FTW driver + +Returns: + EFI_SUCCESS - The function completed successfully + EFI_ABORTED - The function could not complete successfully. + +--*/ +; + +BOOLEAN +IsValidWorkSpace ( + IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader + ) +/*++ + +Routine Description: + Check to see if it is a valid work space. + +Arguments: + WorkingHeader - Pointer of working block header + +Returns: + EFI_SUCCESS - The function completed successfully + EFI_ABORTED - The function could not complete successfully. + +--*/ +; + +EFI_STATUS +CleanupWorkSpace ( + IN EFI_FTW_LITE_DEVICE *FtwLiteDevice, + IN OUT UINT8 *BlockBuffer, + IN UINTN BufferSize + ) +/*++ + +Routine Description: + Reclaim the work space. Get rid of all the completed write records + and write records in the Fault Tolerant work space. + +Arguments: + FtwLiteDevice - Point to private data of FTW driver + FtwSpaceBuffer - Buffer to contain the reclaimed clean data + BufferSize - Size of the FtwSpaceBuffer + +Returns: + EFI_SUCCESS - The function completed successfully + EFI_BUFFER_TOO_SMALL - The FtwSpaceBuffer is too small + EFI_ABORTED - The function could not complete successfully. + +--*/ +; + +EFI_STATUS +FtwReclaimWorkSpace ( + IN EFI_FTW_LITE_DEVICE *FtwLiteDevice + ) +/*++ + +Routine Description: + Reclaim the work space on the working block. + +Arguments: + FtwLiteDevice - Point to private data of FTW driver + +Returns: + EFI_SUCCESS - The function completed successfully + EFI_OUT_OF_RESOURCES - Allocate memory error + EFI_ABORTED - The function could not complete successfully + +--*/ +; + +#endif diff --git a/EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwLite.mbd b/EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwLite.mbd new file mode 100644 index 0000000000..a56e9defc0 --- /dev/null +++ b/EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwLite.mbd @@ -0,0 +1,44 @@ + + + + + FtwLite + 4C862FC6-0E54-4e36-8C8F-FF6F3167951F + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-22 14:11 + + + UefiBootServicesTableLib + BaseLib + UefiMemoryLib + DxeHobLib + UefiLib + UefiDriverEntryPoint + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + EdkDxePrintLib + DxeMemoryAllocationLib + + + _ModuleEntryPoint + + diff --git a/EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwLite.msa b/EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwLite.msa new file mode 100644 index 0000000000..06eb47c2a2 --- /dev/null +++ b/EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwLite.msa @@ -0,0 +1,90 @@ + + + + + FtwLite + DXE_DRIVER + BS_DRIVER + 4C862FC6-0E54-4e36-8C8F-FF6F3167951F + 0 + Component description file for DiskIo module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-22 14:11 + + + DebugLib + UefiDriverEntryPoint + UefiLib + BaseLib + HobLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + + + FtwLite.c + FtwMisc.c + FtwWorkSpace.c + FtwLite.dxs + + ia32\Ia32FtwMisc.c + + + x64\x64FtwMisc.c + + + Ipf\IpfFtwMisc.c + + + ia32\Ia32FtwMisc.c + + + + MdePkg + EdkModulePkg + + + FaultTolerantWriteLite + PciRootBridgeIo + FirmwareVolumeBlock + + + + FlashMapHob + gEfiFlashMapHobGuid + 0xb091e7d2, 0x5a0, 0x4198, 0x94, 0xf0, 0x74, 0xb7, 0xb8, 0xc5, 0x54, 0x59 + + + + + FlashMapHob + + + SystemNvDataFv + + + + + InitializeFtwLite + + + diff --git a/EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwMisc.c b/EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwMisc.c new file mode 100644 index 0000000000..025ec33f7b --- /dev/null +++ b/EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwMisc.c @@ -0,0 +1,530 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FtwMisc.c + +Abstract: + + Internal functions to support fault tolerant write. + +Revision History + +--*/ + +#include + +BOOLEAN +IsErasedFlashBuffer ( + IN BOOLEAN Polarity, + IN UINT8 *Buffer, + IN UINTN BufferSize + ) +/*++ + +Routine Description: + + Check whether a flash buffer is erased. + +Arguments: + + Polarity - All 1 or all 0 + Buffer - Buffer to check + BufferSize - Size of the buffer + +Returns: + + Erased or not. + +--*/ +{ + UINT8 ErasedValue; + UINT8 *Ptr; + + if (Polarity) { + ErasedValue = 0xFF; + } else { + ErasedValue = 0; + } + + Ptr = Buffer; + while (BufferSize--) { + if (*Ptr++ != ErasedValue) { + return FALSE; + } + } + + return TRUE; +} + +EFI_STATUS +FtwEraseBlock ( + IN EFI_FTW_LITE_DEVICE *FtwLiteDevice, + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock, + EFI_LBA Lba + ) +/*++ + +Routine Description: + To Erase one block. The size is FTW_BLOCK_SIZE + +Arguments: + FtwLiteDevice - Calling context + FvBlock - FVB Protocol interface + Lba - Lba of the firmware block + +Returns: + EFI_SUCCESS - Block LBA is Erased successfully + Others - Error occurs + +--*/ +{ + return FvBlock->EraseBlocks ( + FvBlock, + Lba, + FtwLiteDevice->NumberOfSpareBlock, + EFI_LBA_LIST_TERMINATOR + ); +} + +EFI_STATUS +FtwEraseSpareBlock ( + IN EFI_FTW_LITE_DEVICE *FtwLiteDevice + ) +/*++ + +Routine Description: + + Erase spare block. + +Arguments: + + FtwLiteDevice - Calling context + +Returns: + + Status code + +--*/ +{ + return FtwLiteDevice->FtwBackupFvb->EraseBlocks ( + FtwLiteDevice->FtwBackupFvb, + FtwLiteDevice->FtwSpareLba, + FtwLiteDevice->NumberOfSpareBlock, + EFI_LBA_LIST_TERMINATOR + ); +} + +EFI_STATUS +FtwGetFvbByHandle ( + IN EFI_HANDLE FvBlockHandle, + OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock + ) +/*++ + +Routine Description: + Retrive the proper FVB protocol interface by HANDLE. + +Arguments: + FvBlockHandle - The handle of FVB protocol that provides services for + reading, writing, and erasing the target block. + FvBlock - The interface of FVB protocol + +Returns: + EFI_SUCCESS - The function completed successfully + EFI_ABORTED - The function could not complete successfully +--*/ +{ + // + // To get the FVB protocol interface on the handle + // + return gBS->HandleProtocol ( + FvBlockHandle, + &gEfiFirmwareVolumeBlockProtocolGuid, + (VOID **) FvBlock + ); +} + +EFI_STATUS +GetFvbByAddress ( + IN EFI_PHYSICAL_ADDRESS Address, + OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock + ) +/*++ + +Routine Description: + + Get firmware block by address. + +Arguments: + + Address - Address specified the block + FvBlock - The block caller wanted + +Returns: + + Status code + + EFI_NOT_FOUND - Block not found + +--*/ +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN HandleCount; + UINTN Index; + EFI_PHYSICAL_ADDRESS FvbBaseAddress; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + + *FvBlock = NULL; + // + // Locate all handles of Fvb protocol + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiFirmwareVolumeBlockProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + // + // Search all FVB until find the right one + // + for (Index = 0; Index < HandleCount; Index += 1) { + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiFirmwareVolumeBlockProtocolGuid, + (VOID **) &Fvb + ); + if (EFI_ERROR (Status)) { + Status = EFI_NOT_FOUND; + break; + } + // + // Compare the address and select the right one + // + Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress); + if (EFI_ERROR (Status)) { + continue; + } + + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress); + if ((Address >= FvbBaseAddress) && (Address <= (FvbBaseAddress + (FwVolHeader->FvLength - 1)))) { + *FvBlock = Fvb; + Status = EFI_SUCCESS; + break; + } + } + + gBS->FreePool (HandleBuffer); + return Status; +} + +BOOLEAN +IsInWorkingBlock ( + EFI_FTW_LITE_DEVICE *FtwLiteDevice, + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock, + EFI_LBA Lba + ) +/*++ + +Routine Description: + + Is it in working block? + +Arguments: + + FtwLiteDevice - Calling context + FvBlock - Fvb protocol instance + Lba - The block specified + +Returns: + + In working block or not + +--*/ +{ + // + // 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 == FtwLiteDevice->FtwFvBlock) && + (Lba >= FtwLiteDevice->FtwWorkBlockLba) && + (Lba <= FtwLiteDevice->FtwWorkSpaceLba) + ); +} + +EFI_STATUS +FlushSpareBlockToTargetBlock ( + EFI_FTW_LITE_DEVICE *FtwLiteDevice, + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock, + EFI_LBA Lba + ) +/*++ + +Routine Description: + 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. LBA is + FtwLiteDevice->FtwSpareLba. + Target block is accessed by FvBlock protocol interface. LBA is Lba. + +Arguments: + FtwLiteDevice - The private data of FTW_LITE driver + FvBlock - FVB Protocol interface to access target block + Lba - Lba of the target block + +Returns: + EFI_SUCCESS - Spare block content is copied to target block + EFI_INVALID_PARAMETER - Input parameter error + EFI_OUT_OF_RESOURCES - Allocate memory error + EFI_ABORTED - The function could not complete successfully + +--*/ +{ + EFI_STATUS Status; + UINTN Length; + UINT8 *Buffer; + UINTN Count; + UINT8 *Ptr; + UINTN Index; + + if ((FtwLiteDevice == NULL) || (FvBlock == NULL)) { + return EFI_INVALID_PARAMETER; + } + // + // Allocate a memory buffer + // + Length = FtwLiteDevice->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 < FtwLiteDevice->NumberOfSpareBlock; Index += 1) { + Count = FtwLiteDevice->SizeOfSpareBlock; + Status = FtwLiteDevice->FtwBackupFvb->Read ( + FtwLiteDevice->FtwBackupFvb, + FtwLiteDevice->FtwSpareLba + Index, + 0, + &Count, + Ptr + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (Buffer); + return Status; + } + + Ptr += Count; + } + // + // Erase the target block + // + Status = FtwEraseBlock (FtwLiteDevice, FvBlock, Lba); + if (EFI_ERROR (Status)) { + gBS->FreePool (Buffer); + return EFI_ABORTED; + } + // + // Write memory buffer to block, using the FvbBlock protocol interface + // + Ptr = Buffer; + for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) { + Count = FtwLiteDevice->SizeOfSpareBlock; + Status = FvBlock->Write (FvBlock, Lba + Index, 0, &Count, Ptr); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_FTW_LITE, "FtwLite: FVB Write block - %r\n", Status)); + gBS->FreePool (Buffer); + return Status; + } + + Ptr += Count; + } + + gBS->FreePool (Buffer); + + return Status; +} + +EFI_STATUS +FlushSpareBlockToWorkingBlock ( + EFI_FTW_LITE_DEVICE *FtwLiteDevice + ) +/*++ + +Routine Description: + 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 + FtwLiteDevice->FtwSpareLba. + Working block is accessed by FTW working FVB protocol interface. LBA is + FtwLiteDevice->FtwWorkBlockLba. + +Arguments: + FtwLiteDevice - The private data of FTW_LITE driver + +Returns: + EFI_SUCCESS - Spare block content is copied to target block + EFI_OUT_OF_RESOURCES - Allocate memory error + EFI_ABORTED - The function could not complete successfully + +Notes: + 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. + +--*/ +{ + EFI_STATUS Status; + UINTN Length; + UINT8 *Buffer; + EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingBlockHeader; + EFI_LBA WorkSpaceLbaOffset; + UINTN Count; + UINT8 *Ptr; + UINTN Index; + + // + // Allocate a memory buffer + // + Length = FtwLiteDevice->SpareAreaLength; + Buffer = AllocatePool (Length); + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // To guarantee that the WorkingBlockValid is set on spare block + // + WorkSpaceLbaOffset = FtwLiteDevice->FtwWorkSpaceLba - FtwLiteDevice->FtwWorkBlockLba; + FtwUpdateFvState ( + FtwLiteDevice->FtwBackupFvb, + FtwLiteDevice->FtwSpareLba + WorkSpaceLbaOffset, + FtwLiteDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32), + WORKING_BLOCK_VALID + ); + // + // Read from spare block to memory buffer + // + Ptr = Buffer; + for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) { + Count = FtwLiteDevice->SizeOfSpareBlock; + Status = FtwLiteDevice->FtwBackupFvb->Read ( + FtwLiteDevice->FtwBackupFvb, + FtwLiteDevice->FtwSpareLba + Index, + 0, + &Count, + Ptr + ); + if (EFI_ERROR (Status)) { + gBS->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) WorkSpaceLbaOffset * FtwLiteDevice->SizeOfSpareBlock + FtwLiteDevice->FtwWorkSpaceBase); + 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 = EFI_FIELD_OFFSET(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER, + // WorkingBlockInvalid); + // To skip Signature and Crc: sizeof(EFI_GUID)+sizeof(UINT32). + // + Status = FtwUpdateFvState ( + FtwLiteDevice->FtwFvBlock, + FtwLiteDevice->FtwWorkSpaceLba, + FtwLiteDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32), + WORKING_BLOCK_INVALID + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (Buffer); + return EFI_ABORTED; + } + + FtwLiteDevice->FtwWorkSpaceHeader->WorkingBlockInvalid = FTW_VALID_STATE; + + // + // Erase the working block + // + Status = FtwEraseBlock ( + FtwLiteDevice, + FtwLiteDevice->FtwFvBlock, + FtwLiteDevice->FtwWorkBlockLba + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (Buffer); + return EFI_ABORTED; + } + // + // Write memory buffer to working block, using the FvbBlock protocol interface + // + Ptr = Buffer; + for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) { + Count = FtwLiteDevice->SizeOfSpareBlock; + Status = FtwLiteDevice->FtwFvBlock->Write ( + FtwLiteDevice->FtwFvBlock, + FtwLiteDevice->FtwWorkBlockLba + Index, + 0, + &Count, + Ptr + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_FTW_LITE, "FtwLite: FVB Write block - %r\n", Status)); + gBS->FreePool (Buffer); + return Status; + } + + Ptr += Count; + } + // + // Since the memory buffer will not be used, free memory Buffer. + // + gBS->FreePool (Buffer); + + // + // Update the VALID of the working block + // + // Offset = EFI_FIELD_OFFSET(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER, + // WorkingBlockValid); + // Hardcode offset sizeof(EFI_GUID)+sizeof(UINT32), to skip Signature and Crc + // + Status = FtwUpdateFvState ( + FtwLiteDevice->FtwFvBlock, + FtwLiteDevice->FtwWorkSpaceLba, + FtwLiteDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32), + WORKING_BLOCK_VALID + ); + if (EFI_ERROR (Status)) { + return EFI_ABORTED; + } + + FtwLiteDevice->FtwWorkSpaceHeader->WorkingBlockValid = FTW_VALID_STATE; + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwWorkSpace.c b/EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwWorkSpace.c new file mode 100644 index 0000000000..820655c76b --- /dev/null +++ b/EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwWorkSpace.c @@ -0,0 +1,567 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FtwWorkSpace.c + +Abstract: + +Revision History + +--*/ + + +#include + +BOOLEAN +IsValidWorkSpace ( + IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader + ) +/*++ + +Routine Description: + Check to see if it is a valid work space. + +Arguments: + WorkingHeader - Pointer of working block header + +Returns: + EFI_SUCCESS - The function completed successfully + EFI_ABORTED - The function could not complete successfully. + +--*/ +{ + EFI_STATUS Status; + EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER WorkingBlockHeader; + + ASSERT (WorkingHeader != NULL); + if (WorkingHeader->WorkingBlockValid != FTW_VALID_STATE) { + return FALSE; + } + // + // Check signature with gEfiSystemNvDataFvGuid + // + if (!CompareGuid (&gEfiSystemNvDataFvGuid, &WorkingHeader->Signature)) { + return FALSE; + } + // + // Check the CRC of header + // + CopyMem ( + &WorkingBlockHeader, + WorkingHeader, + sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER) + ); + + // + // Filter out the Crc and State fields + // + SetMem ( + &WorkingBlockHeader.Crc, + sizeof (UINT32), + FTW_ERASED_BYTE + ); + WorkingBlockHeader.WorkingBlockValid = FTW_ERASE_POLARITY; + WorkingBlockHeader.WorkingBlockInvalid = FTW_ERASE_POLARITY; + + // + // Calculate the Crc of woking block header + // + Status = gBS->CalculateCrc32 ( + (UINT8 *) &WorkingBlockHeader, + sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER), + &WorkingBlockHeader.Crc + ); + ASSERT_EFI_ERROR (Status); + + if (WorkingBlockHeader.Crc != WorkingHeader->Crc) { + DEBUG ((EFI_D_FTW_LITE, "FtwLite: Work block header CRC check error\n")); + return FALSE; + } + + return TRUE; +} + +EFI_STATUS +InitWorkSpaceHeader ( + IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader + ) +/*++ + +Routine Description: + Initialize a work space when there is no work space. + +Arguments: + WorkingHeader - Pointer of working block header + +Returns: + EFI_SUCCESS - The function completed successfully + EFI_ABORTED - The function could not complete successfully. + +--*/ +{ + EFI_STATUS Status; + + ASSERT (WorkingHeader != NULL); + + // + // Here using gEfiSystemNvDataFvGuid as the signature. + // + CopyMem ( + &WorkingHeader->Signature, + &gEfiSystemNvDataFvGuid, + sizeof (EFI_GUID) + ); + WorkingHeader->WriteQueueSize = FTW_WORKING_QUEUE_SIZE; + + // + // Crc is calculated with all the fields except Crc and STATE + // + WorkingHeader->WorkingBlockValid = FTW_ERASE_POLARITY; + WorkingHeader->WorkingBlockInvalid = FTW_ERASE_POLARITY; + SetMem (&WorkingHeader->Crc, sizeof (UINT32), FTW_ERASED_BYTE); + + // + // Calculate the CRC value + // + Status = gBS->CalculateCrc32 ( + (UINT8 *) WorkingHeader, + sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER), + &WorkingHeader->Crc + ); + ASSERT_EFI_ERROR (Status); + + // + // Restore the WorkingBlockValid flag to VALID state + // + WorkingHeader->WorkingBlockValid = FTW_VALID_STATE; + WorkingHeader->WorkingBlockInvalid = FTW_INVALID_STATE; + + return EFI_SUCCESS; +} + +EFI_STATUS +FtwUpdateFvState ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock, + IN EFI_LBA Lba, + IN UINTN Offset, + IN UINT8 NewBit + ) +/*++ + +Routine Description: + 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. + +Arguments: + FvBlock - FVB Protocol interface to access SrcBlock and DestBlock + Lba - Lba of a block + Offset - Offset on the Lba + NewBit - New value that will override the old value if it can be change + +Returns: + EFI_SUCCESS - A state bit has been updated successfully + Others - Access block device error. + +Notes: + Assume all bits of State are inside the same BYTE. + + EFI_ABORTED - Read block fail +--*/ +{ + EFI_STATUS Status; + UINT8 State; + UINTN Length; + + // + // 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 |= NewBit; + State ^= FTW_POLARITY_REVERT; + + // + // Write state back to device + // + Length = sizeof (UINT8); + Status = FvBlock->Write (FvBlock, Lba, Offset, &Length, &State); + + return Status; +} + +EFI_STATUS +FtwGetLastRecord ( + IN EFI_FTW_LITE_DEVICE *FtwLiteDevice, + OUT EFI_FTW_LITE_RECORD **FtwLastRecord + ) +/*++ + +Routine Description: + Get the last Write record pointer. + The last record is the record whose 'complete' state hasn't been set. + After all, this header may be a EMPTY header entry for next Allocate. + +Arguments: + FtwLiteDevice - Private data of this driver + FtwLastRecord - Pointer to retrieve the last write record + +Returns: + EFI_SUCCESS - Get the last write record successfully + EFI_ABORTED - The FTW work space is damaged + +--*/ +{ + EFI_FTW_LITE_RECORD *Record; + + Record = (EFI_FTW_LITE_RECORD *) (FtwLiteDevice->FtwWorkSpaceHeader + 1); + while (Record->WriteCompleted == FTW_VALID_STATE) { + // + // If Offset exceed the FTW work space boudary, return error. + // + if ((UINTN) ((UINT8 *) Record - FtwLiteDevice->FtwWorkSpace) > FtwLiteDevice->FtwWorkSpaceSize) { + return EFI_ABORTED; + } + + Record++; + } + // + // Last write record is found + // + *FtwLastRecord = Record; + return EFI_SUCCESS; +} + +EFI_STATUS +WorkSpaceRefresh ( + IN EFI_FTW_LITE_DEVICE *FtwLiteDevice + ) +/*++ + +Routine Description: + Read from working block to refresh the work space in memory. + +Arguments: + FtwLiteDevice - Point to private data of FTW driver + +Returns: + EFI_SUCCESS - The function completed successfully + EFI_ABORTED - The function could not complete successfully. + +--*/ +{ + EFI_STATUS Status; + UINTN Length; + UINTN Offset; + EFI_FTW_LITE_RECORD *Record; + + // + // Initialize WorkSpace as FTW_ERASED_BYTE + // + SetMem ( + FtwLiteDevice->FtwWorkSpace, + FtwLiteDevice->FtwWorkSpaceSize, + FTW_ERASED_BYTE + ); + + // + // Read from working block + // + Length = FtwLiteDevice->FtwWorkSpaceSize; + Status = FtwLiteDevice->FtwFvBlock->Read ( + FtwLiteDevice->FtwFvBlock, + FtwLiteDevice->FtwWorkSpaceLba, + FtwLiteDevice->FtwWorkSpaceBase, + &Length, + FtwLiteDevice->FtwWorkSpace + ); + if (EFI_ERROR (Status)) { + return EFI_ABORTED; + } + // + // Refresh the FtwLastRecord + // + Status = FtwGetLastRecord (FtwLiteDevice, &FtwLiteDevice->FtwLastRecord); + + Record = FtwLiteDevice->FtwLastRecord; + Offset = (UINTN) (UINT8 *) Record - (UINTN) FtwLiteDevice->FtwWorkSpace; + + // + // IF work space has error or Record is out of the workspace limit, THEN + // call reclaim. + // + if (EFI_ERROR (Status) || (Offset + WRITE_TOTAL_SIZE >= FtwLiteDevice->FtwWorkSpaceSize)) { + // + // reclaim work space in working block. + // + Status = FtwReclaimWorkSpace (FtwLiteDevice); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_FTW_LITE, "FtwLite: Reclaim workspace - %r\n", Status)); + return EFI_ABORTED; + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +CleanupWorkSpace ( + IN EFI_FTW_LITE_DEVICE *FtwLiteDevice, + IN OUT UINT8 *FtwSpaceBuffer, + IN UINTN BufferSize + ) +/*++ + +Routine Description: + Reclaim the work space. Get rid of all the completed write records + and write records in the Fault Tolerant work space. + +Arguments: + FtwLiteDevice - Point to private data of FTW driver + FtwSpaceBuffer - Buffer to contain the reclaimed clean data + BufferSize - Size of the FtwSpaceBuffer + +Returns: + EFI_SUCCESS - The function completed successfully + EFI_BUFFER_TOO_SMALL - The FtwSpaceBuffer is too small + EFI_ABORTED - The function could not complete successfully. + +--*/ +{ + UINTN Length; + EFI_FTW_LITE_RECORD *Record; + + // + // To check if the buffer is large enough + // + Length = FtwLiteDevice->FtwWorkSpaceSize; + if (BufferSize < Length) { + return EFI_BUFFER_TOO_SMALL; + } + // + // Clear the content of buffer that will save the new work space data + // + SetMem (FtwSpaceBuffer, Length, FTW_ERASED_BYTE); + + // + // Copy EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER to buffer + // + CopyMem ( + FtwSpaceBuffer, + FtwLiteDevice->FtwWorkSpaceHeader, + sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER) + ); + + // + // Get the last record + // + Record = FtwLiteDevice->FtwLastRecord; + if ((Record != NULL) && (Record->WriteAllocated == FTW_VALID_STATE) && (Record->WriteCompleted != FTW_VALID_STATE)) { + CopyMem ( + (UINT8 *) FtwSpaceBuffer + sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER), + Record, + WRITE_TOTAL_SIZE + ); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +FtwReclaimWorkSpace ( + IN EFI_FTW_LITE_DEVICE *FtwLiteDevice + ) +/*++ + +Routine Description: + Reclaim the work space on the working block. + +Arguments: + FtwLiteDevice - Point to private data of FTW driver + +Returns: + EFI_SUCCESS - The function completed successfully + EFI_OUT_OF_RESOURCES - Allocate memory error + EFI_ABORTED - The function could not complete successfully + +--*/ +{ + EFI_STATUS Status; + UINT8 *TempBuffer; + UINTN TempBufferSize; + UINT8 *Ptr; + UINTN Length; + UINTN Index; + UINTN SpareBufferSize; + UINT8 *SpareBuffer; + EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingBlockHeader; + + DEBUG ((EFI_D_FTW_LITE, "FtwLite: start to reclaim work space\n")); + + // + // Read all original data from working block to a memory buffer + // + TempBufferSize = FtwLiteDevice->SpareAreaLength; + Status = gBS->AllocatePool ( + EfiBootServicesData, + TempBufferSize, + (VOID **) &TempBuffer + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + ZeroMem (TempBuffer, TempBufferSize); + + Ptr = TempBuffer; + for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) { + Length = FtwLiteDevice->SizeOfSpareBlock; + Status = FtwLiteDevice->FtwFvBlock->Read ( + FtwLiteDevice->FtwFvBlock, + FtwLiteDevice->FtwWorkBlockLba + Index, + 0, + &Length, + Ptr + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (TempBuffer); + return EFI_ABORTED; + } + + Ptr += Length; + } + // + // Clean up the workspace, remove all the completed records. + // + Ptr = TempBuffer + + ((UINTN) (FtwLiteDevice->FtwWorkSpaceLba - FtwLiteDevice->FtwWorkBlockLba)) * + FtwLiteDevice->SizeOfSpareBlock + + FtwLiteDevice->FtwWorkSpaceBase; + Status = CleanupWorkSpace ( + FtwLiteDevice, + Ptr, + FtwLiteDevice->FtwWorkSpaceSize + ); + + CopyMem ( + FtwLiteDevice->FtwWorkSpace, + Ptr, + FtwLiteDevice->FtwWorkSpaceSize + ); + + Status = FtwGetLastRecord (FtwLiteDevice, &FtwLiteDevice->FtwLastRecord); + + // + // Set the WorkingBlockValid and WorkingBlockInvalid as INVALID + // + WorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) Ptr; + 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 = FtwLiteDevice->SpareAreaLength; + SpareBuffer = AllocatePool (SpareBufferSize); + if (SpareBuffer == NULL) { + gBS->FreePool (TempBuffer); + return EFI_OUT_OF_RESOURCES; + } + + Ptr = SpareBuffer; + for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) { + Length = FtwLiteDevice->SizeOfSpareBlock; + Status = FtwLiteDevice->FtwBackupFvb->Read ( + FtwLiteDevice->FtwBackupFvb, + FtwLiteDevice->FtwSpareLba + Index, + 0, + &Length, + Ptr + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (TempBuffer); + gBS->FreePool (SpareBuffer); + return EFI_ABORTED; + } + + Ptr += Length; + } + // + // Write the memory buffer to spare block + // + Status = FtwEraseSpareBlock (FtwLiteDevice); + Ptr = TempBuffer; + for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) { + Length = FtwLiteDevice->SizeOfSpareBlock; + Status = FtwLiteDevice->FtwBackupFvb->Write ( + FtwLiteDevice->FtwBackupFvb, + FtwLiteDevice->FtwSpareLba + Index, + 0, + &Length, + Ptr + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (TempBuffer); + gBS->FreePool (SpareBuffer); + return EFI_ABORTED; + } + + Ptr += Length; + } + // + // Free TempBuffer + // + gBS->FreePool (TempBuffer); + + // + // Write the spare block to working block + // + Status = FlushSpareBlockToWorkingBlock (FtwLiteDevice); + if (EFI_ERROR (Status)) { + gBS->FreePool (SpareBuffer); + return Status; + } + // + // Restore spare backup buffer into spare block , if no failure happened during FtwWrite. + // + Status = FtwEraseSpareBlock (FtwLiteDevice); + Ptr = SpareBuffer; + for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) { + Length = FtwLiteDevice->SizeOfSpareBlock; + Status = FtwLiteDevice->FtwBackupFvb->Write ( + FtwLiteDevice->FtwBackupFvb, + FtwLiteDevice->FtwSpareLba + Index, + 0, + &Length, + Ptr + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (SpareBuffer); + return EFI_ABORTED; + } + + Ptr += Length; + } + + gBS->FreePool (SpareBuffer); + + DEBUG ((EFI_D_FTW_LITE, "FtwLite: reclaim work space success\n")); + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/Ia32/Ia32FtwMisc.c b/EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/Ia32/Ia32FtwMisc.c new file mode 100644 index 0000000000..80258f4cc3 --- /dev/null +++ b/EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/Ia32/Ia32FtwMisc.c @@ -0,0 +1,399 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Ia32FtwMisc.c + +Abstract: + + Ia32 platform related code to support FtwLite.. + +Revision History + +--*/ + + +#include + +// +// MACROs for boot block update +// +#define BOOT_BLOCK_BASE 0xFFFF0000 + +// +// (LPC -- D31:F0) +// +#define LPC_BUS_NUMBER 0x00 +#define LPC_DEVICE_NUMBER 0x1F +#define LPC_IF 0xF0 +// +// Top swap +// +#define GEN_STATUS 0xD4 +#define TOP_SWAP_BIT (1 << 13) + +STATIC +UINT32 +ReadPciRegister ( + IN UINT32 Offset + ) +/*++ + +Routine Description: + + Read PCI register value. + +Arguments: + + Offset - Offset of the register + +Returns: + + The value. + +--*/ +{ + EFI_STATUS Status; + UINT32 Value; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; + + Value = 0; + Status = gBS->LocateProtocol (&gEfiPciRootBridgeIoProtocolGuid, NULL, (VOID **) &PciRootBridgeIo); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "FtwLite: Locate PCI root bridge io protocol - %r", Status)); + return 0; + } + + Status = PciRootBridgeIo->Pci.Read ( + PciRootBridgeIo, + EfiPciWidthUint32, + EFI_PCI_ADDRESS (LPC_BUS_NUMBER, + LPC_DEVICE_NUMBER, + LPC_IF, + Offset), + 1, + &Value + ); + ASSERT_EFI_ERROR (Status); + + return Value; +} + +STATIC +EFI_STATUS +GetSwapState ( + IN EFI_FTW_LITE_DEVICE *FtwLiteDevice, + OUT BOOLEAN *SwapState + ) +/*++ + +Routine Description: + + Get swap state + +Arguments: + + FtwLiteDevice - Calling context + SwapState - Swap state + +Returns: + + EFI_SUCCESS - State successfully got + +--*/ +{ + // + // Top swap status is 13 bit + // + *SwapState = (BOOLEAN) ((ReadPciRegister (GEN_STATUS) & TOP_SWAP_BIT) != 0); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +SetSwapState ( + IN EFI_FTW_LITE_DEVICE *FtwLiteDevice, + IN BOOLEAN TopSwap + ) +/*++ + +Routine Description: + Set swap state. + +Arguments: + FtwLiteDevice - Indicates a pointer to the calling context. + TopSwap - New swap state + +Returns: + EFI_SUCCESS - The function completed successfully + +Note: + the Top-Swap bit (bit 13, D31: F0, Offset D4h). Note that + software will not be able to clear the Top-Swap bit until the system is + rebooted without GNT[A]# being pulled down. + +--*/ +{ + UINT32 GenStatus; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; + EFI_STATUS Status; + + // + // Top-Swap bit (bit 13, D31: F0, Offset D4h) + // + GenStatus = ReadPciRegister (GEN_STATUS); + + // + // Set 13 bit, according to input NewSwapState + // + if (TopSwap) { + GenStatus |= TOP_SWAP_BIT; + } else { + GenStatus &= ~TOP_SWAP_BIT; + } + + Status = gBS->LocateProtocol (&gEfiPciRootBridgeIoProtocolGuid, NULL, (VOID **) &PciRootBridgeIo); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "FtwLite: Locate PCI root bridge io protocol - %r", Status)); + return Status; + } + // + // Write back the GenStatus register + // + Status = PciRootBridgeIo->Pci.Write ( + PciRootBridgeIo, + EfiPciWidthUint32, + EFI_PCI_ADDRESS (LPC_BUS_NUMBER, + LPC_DEVICE_NUMBER, + LPC_IF, + GEN_STATUS), + 1, + &GenStatus + ); + + DEBUG_CODE ( + if (TopSwap) { + DEBUG ((EFI_D_ERROR, "SAR: Set top swap\n")); + } else { + DEBUG ((EFI_D_ERROR, "SAR: Clear top swap\n")); + } + ); + + return EFI_SUCCESS; +} + +BOOLEAN +IsBootBlock ( + EFI_FTW_LITE_DEVICE *FtwLiteDevice, + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock, + EFI_LBA Lba + ) +/*++ + +Routine Description: + + Check whether the block is a boot block. + +Arguments: + + FtwLiteDevice - Calling context + FvBlock - Fvb protocol instance + Lba - Lba value + +Returns: + + Is a boot block or not + +--*/ +{ + EFI_STATUS Status; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *BootFvb; + + Status = GetFvbByAddress (BOOT_BLOCK_BASE, &BootFvb); + if (EFI_ERROR (Status)) { + return FALSE; + } + // + // Compare the Fvb + // + return (BOOLEAN) (FvBlock == BootFvb); +} + +EFI_STATUS +FlushSpareBlockToBootBlock ( + EFI_FTW_LITE_DEVICE *FtwLiteDevice + ) +/*++ + +Routine Description: + Copy the content of spare block to a boot block. Size is FTW_BLOCK_SIZE. + Spare block is accessed by FTW backup FVB protocol interface. LBA is + FtwLiteDevice->FtwSpareLba. + Boot block is accessed by BootFvb protocol interface. LBA is 0. + +Arguments: + FtwLiteDevice - The private data of FTW_LITE driver + +Returns: + EFI_SUCCESS - Spare block content is copied to boot block + EFI_INVALID_PARAMETER - Input parameter error + EFI_OUT_OF_RESOURCES - Allocate memory error + EFI_ABORTED - The function could not complete successfully + +Notes: + 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: + 1. Erase top swap block (0xFFFE-0xFFFEFFFF) and write data to it ready + 2. Read data from top swap block to memory buffer + 3. SetSwapState(EFI_SWAPPED) + 4. Erasing boot block (0xFFFF-0xFFFFFFFF) + 5. Programming boot block until the boot block is ok. + 6. SetSwapState(UNSWAPPED) + + Notes: + 1. Since the SwapState bit is saved in CMOS, FTW can restore and continue + even in the scenario of power failure. + 2. FTW shall not allow to update boot block when battery state is error. + +--*/ +{ + EFI_STATUS Status; + UINTN Length; + UINT8 *Buffer; + UINTN Count; + UINT8 *Ptr; + UINTN Index; + BOOLEAN TopSwap; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *BootFvb; + EFI_LBA BootLba; + + // + // Allocate a memory buffer + // + Length = FtwLiteDevice->SpareAreaLength; + Buffer = AllocatePool (Length); + if (Buffer == NULL) { + } + // + // Get TopSwap bit state + // + Status = GetSwapState (FtwLiteDevice, &TopSwap); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "FtwLite: Get Top Swapped status - %r\n", Status)); + gBS->FreePool (Buffer); + return EFI_ABORTED; + } + + if (TopSwap) { + // + // Get FVB of current boot block + // + Status = GetFvbByAddress (FtwLiteDevice->SpareAreaAddress + FTW_BLOCK_SIZE, &BootFvb); + if (EFI_ERROR (Status)) { + gBS->FreePool (Buffer); + return Status; + } + // + // Read data from current boot block + // + BootLba = 0; + Ptr = Buffer; + for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) { + Count = FtwLiteDevice->SizeOfSpareBlock; + Status = BootFvb->Read ( + BootFvb, + BootLba + Index, + 0, + &Count, + Ptr + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (Buffer); + return Status; + } + + Ptr += Count; + } + + } else { + // + // Read data from spare block + // + Ptr = Buffer; + for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) { + Count = FtwLiteDevice->SizeOfSpareBlock; + Status = FtwLiteDevice->FtwBackupFvb->Read ( + FtwLiteDevice->FtwBackupFvb, + FtwLiteDevice->FtwSpareLba + Index, + 0, + &Count, + Ptr + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (Buffer); + return Status; + } + + Ptr += Count; + } + // + // Set TopSwap bit + // + Status = SetSwapState (FtwLiteDevice, TRUE); + DEBUG ((EFI_D_ERROR, "FtwLite: Set Swap State - %r\n", Status)); + ASSERT_EFI_ERROR (Status); + } + // + // Erase boot block. After setting TopSwap bit, it's spare block now! + // + Status = FtwEraseSpareBlock (FtwLiteDevice); + if (EFI_ERROR (Status)) { + gBS->FreePool (Buffer); + return EFI_ABORTED; + } + // + // Write memory buffer to currenet spare block + // + Ptr = Buffer; + for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) { + Count = FtwLiteDevice->SizeOfSpareBlock; + Status = FtwLiteDevice->FtwBackupFvb->Write ( + FtwLiteDevice->FtwBackupFvb, + FtwLiteDevice->FtwSpareLba + Index, + 0, + &Count, + Ptr + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_FTW_LITE, "FtwLite: FVB Write boot block - %r\n", Status)); + gBS->FreePool (Buffer); + return Status; + } + + Ptr += Count; + } + + gBS->FreePool (Buffer); + + // + // Clear TopSwap bit + // + Status = SetSwapState (FtwLiteDevice, FALSE); + DEBUG ((EFI_D_ERROR, "FtwLite: Clear Swap State - %r\n", Status)); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/Ipf/IpfFtwMisc.c b/EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/Ipf/IpfFtwMisc.c new file mode 100644 index 0000000000..d31883b2ee --- /dev/null +++ b/EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/Ipf/IpfFtwMisc.c @@ -0,0 +1,143 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + IpfFtwMisc.c + +Abstract: + + Ipf platform related code to support FtwLite.. + +Revision History + +--*/ + + +#include + +// +// MACROs for boot block update +// +#define BOOT_BLOCK_BASE + +STATIC +EFI_STATUS +GetSwapState ( + IN EFI_FTW_LITE_DEVICE *FtwLiteDevice, + OUT BOOLEAN *SwapState + ) +/*++ + +Routine Description: + + Get swap state + +Arguments: + + FtwLiteDevice - Calling context + SwapState - Swap state + +Returns: + + EFI_SUCCESS - State successfully got + +--*/ +{ + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +SetSwapState ( + IN EFI_FTW_LITE_DEVICE *FtwLiteDevice, + IN BOOLEAN TopSwap + ) +/*++ + +Routine Description: + Set swap state. + +Arguments: + FtwLiteDevice - Indicates a pointer to the calling context. + TopSwap - New swap state + +Returns: + EFI_SUCCESS - The function completed successfully + +Note: + the Top-Swap bit (bit 13, D31: F0, Offset D4h). Note that + software will not be able to clear the Top-Swap bit until the system is + rebooted without GNT[A]# being pulled down. + +--*/ +{ + return EFI_SUCCESS; +} + +BOOLEAN +IsBootBlock ( + EFI_FTW_LITE_DEVICE *FtwLiteDevice, + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock, + EFI_LBA Lba + ) +/*++ + +Routine Description: + + Check whether the block is a boot block. + +Arguments: + + FtwLiteDevice - Calling context + FvBlock - Fvb protocol instance + Lba - Lba value + +Returns: + + Is a boot block or not + +--*/ +{ + // + // IPF doesn't support safe bootblock update + // so treat bootblock as normal block + // + return FALSE; +} + +EFI_STATUS +FlushSpareBlockToBootBlock ( + EFI_FTW_LITE_DEVICE *FtwLiteDevice + ) +/*++ + +Routine Description: + Copy the content of spare block to a boot block. Size is FTW_BLOCK_SIZE. + Spare block is accessed by FTW backup FVB protocol interface. LBA is + FtwLiteDevice->FtwSpareLba. + Boot block is accessed by BootFvb protocol interface. LBA is 0. + +Arguments: + FtwLiteDevice - The private data of FTW_LITE driver + +Returns: + EFI_SUCCESS - Spare block content is copied to boot block + EFI_INVALID_PARAMETER - Input parameter error + EFI_OUT_OF_RESOURCES - Allocate memory error + EFI_ABORTED - The function could not complete successfully + +Notes: + +--*/ +{ + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/build.xml b/EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/build.xml new file mode 100644 index 0000000000..0883c25cba --- /dev/null +++ b/EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/x64/x64FtwMisc.c b/EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/x64/x64FtwMisc.c new file mode 100644 index 0000000000..067bfcf179 --- /dev/null +++ b/EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/x64/x64FtwMisc.c @@ -0,0 +1,140 @@ + +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + x64FtwMisc.c + +Abstract: + + X64 platform related code to support FtwLite.. + +Revision History + +--*/ + + +#include + +// +// MACROs for boot block update +// +#define BOOT_BLOCK_BASE + +STATIC +EFI_STATUS +GetSwapState ( + IN EFI_FTW_LITE_DEVICE *FtwLiteDevice, + OUT BOOLEAN *SwapState + ) +/*++ + +Routine Description: + + Get swap state + +Arguments: + + FtwLiteDevice - Calling context + SwapState - Swap state + +Returns: + + EFI_SUCCESS - State successfully got + +--*/ +{ + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +SetSwapState ( + IN EFI_FTW_LITE_DEVICE *FtwLiteDevice, + IN BOOLEAN TopSwap + ) +/*++ + +Routine Description: + Set swap state. + +Arguments: + FtwLiteDevice - Indicates a pointer to the calling context. + TopSwap - New swap state + +Returns: + EFI_SUCCESS - The function completed successfully + +Note: + the Top-Swap bit (bit 13, D31: F0, Offset D4h). Note that + software will not be able to clear the Top-Swap bit until the system is + rebooted without GNT[A]# being pulled down. + +--*/ +{ + return EFI_SUCCESS; +} + +BOOLEAN +IsBootBlock ( + EFI_FTW_LITE_DEVICE *FtwLiteDevice, + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock, + EFI_LBA Lba + ) +/*++ + +Routine Description: + + Check whether the block is a boot block. + +Arguments: + + FtwLiteDevice - Calling context + FvBlock - Fvb protocol instance + Lba - Lba value + +Returns: + + Is a boot block or not + +--*/ +{ + return FALSE; +} + +EFI_STATUS +FlushSpareBlockToBootBlock ( + EFI_FTW_LITE_DEVICE *FtwLiteDevice + ) +/*++ + +Routine Description: + Copy the content of spare block to a boot block. Size is FTW_BLOCK_SIZE. + Spare block is accessed by FTW backup FVB protocol interface. LBA is + FtwLiteDevice->FtwSpareLba. + Boot block is accessed by BootFvb protocol interface. LBA is 0. + +Arguments: + FtwLiteDevice - The private data of FTW_LITE driver + +Returns: + EFI_SUCCESS - Spare block content is copied to boot block + EFI_INVALID_PARAMETER - Input parameter error + EFI_OUT_OF_RESOURCES - Allocate memory error + EFI_ABORTED - The function could not complete successfully + +Notes: + +--*/ +{ + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/Crc32SectionExtract.c b/EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/Crc32SectionExtract.c new file mode 100644 index 0000000000..dc7ed07baa --- /dev/null +++ b/EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/Crc32SectionExtract.c @@ -0,0 +1,234 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Crc32SectionExtract.c + +Abstract: + + Implements GUIDed section extraction protocol interface with + a specific GUID: CRC32. + + Please refer to the Tiano File Image Format Specification, + FV spec 0.3.6 + +--*/ + + +#include +#include + +EFI_STATUS +InitializeCrc32GuidedSectionExtractionProtocol ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +EFI_STATUS +InitializeCrc32GuidedSectionExtractionProtocol ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Entry point of the CRC32 GUIDed section extraction protocol. + Creates and initializes an instance of the GUIDed section + extraction protocol with CRC32 GUID. + +Arguments: + + ImageHandle EFI_HANDLE: A handle for the image that is initializing + this driver + SystemTable EFI_SYSTEM_TABLE: A pointer to the EFI system table + +Returns: + + EFI_SUCCESS: Driver initialized successfully + EFI_LOAD_ERROR: Failed to Initialize or has been loaded + EFI_OUT_OF_RESOURCES: Could not allocate needed resources + +--*/ +{ + EFI_STATUS Status; + EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *Crc32GuidedSep; + EFI_HANDLE Handle; + + // + // Call all constructors per produced protocols + // + Status = GuidedSectionExtractionProtocolConstructor ( + &Crc32GuidedSep, + (EFI_EXTRACT_GUIDED_SECTION) Crc32ExtractSection + ); + if (EFI_ERROR (Status)) { + if (Crc32GuidedSep != NULL) { + gBS->FreePool (Crc32GuidedSep); + } + + return Status; + } + // + // Pass in a NULL to install to a new handle + // + Handle = NULL; + Status = gBS->InstallProtocolInterface ( + &Handle, + &gEfiCrc32GuidedSectionExtractionProtocolGuid, + EFI_NATIVE_INTERFACE, + Crc32GuidedSep + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (Crc32GuidedSep); + return EFI_LOAD_ERROR; + } + + return EFI_SUCCESS; +} + +STATIC +UINT32 +GetSectionLength ( + IN EFI_COMMON_SECTION_HEADER *CommonHeader + ) +/*++ + + Routine Description: + Get a length of section. + + Parameters: + CommonHeader - Pointer to the common section header. + + Return Value: + The length of the section, including the section header. + +--*/ +// TODO: function comment is missing 'Arguments:' +// TODO: function comment is missing 'Returns:' +// TODO: CommonHeader - add argument and description to function comment +{ + UINT32 Size; + + Size = *(UINT32 *) CommonHeader->Size & 0x00FFFFFF; + + return Size; +} + +STATIC +EFI_STATUS +Crc32ExtractSection ( + IN EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *This, + IN VOID *InputSection, + OUT VOID **OutputBuffer, + OUT UINTN *OutputSize, + OUT UINT32 *AuthenticationStatus + ) +/*++ + + Routine Description: + This function reads and extracts contents of a section from an + encapsulating section. + + Parameters: + This - Indicates the calling context. + InputSection - Buffer containing the input GUIDed section + to be processed. + OutputBuffer - *OutputBuffer is allocated from boot services + pool memory and containing the new section + stream. The caller is responsible for freeing + this buffer. + AuthenticationStatus - Pointer to a caller allocated UINT32 that + indicates the authentication status of the + output buffer + + Return Value: + EFI_SUCCESS + EFI_OUT_OF_RESOURCES + EFI_INVALID_PARAMETER + EFI_NOT_AVAILABLE_YET + +--*/ +// TODO: function comment is missing 'Arguments:' +// TODO: function comment is missing 'Returns:' +// TODO: This - add argument and description to function comment +// TODO: InputSection - add argument and description to function comment +// TODO: OutputBuffer - add argument and description to function comment +// TODO: OutputSize - add argument and description to function comment +// TODO: AuthenticationStatus - add argument and description to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + CRC32_SECTION_HEADER *Crc32SectionHeader; + EFI_GUID_DEFINED_SECTION *GuidedSectionHeader; + UINT8 *Image; + UINT32 Crc32Checksum; + VOID *DummyInterface; + + if (OutputBuffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + *OutputBuffer = NULL; + + // + // Points to the section header + // + Crc32SectionHeader = (CRC32_SECTION_HEADER *) InputSection; + GuidedSectionHeader = (EFI_GUID_DEFINED_SECTION *) InputSection; + + // + // Check if the GUID is a CRC32 section GUID + // + if (!CompareGuid ( + &(GuidedSectionHeader->SectionDefinitionGuid), + &gEfiCrc32GuidedSectionExtractionProtocolGuid + )) { + return EFI_INVALID_PARAMETER; + } + + Image = (UINT8 *) InputSection + (UINT32) (GuidedSectionHeader->DataOffset); + *OutputSize = GetSectionLength ((EFI_COMMON_SECTION_HEADER *) InputSection) - (UINT32) GuidedSectionHeader->DataOffset; + + Status = gBS->AllocatePool (EfiBootServicesData, *OutputSize, OutputBuffer); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + // + // Implictly CRC32 GUIDed section should have STATUS_VALID bit set + // + ASSERT (GuidedSectionHeader->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID); + *AuthenticationStatus = EFI_LOCAL_AUTH_STATUS_IMAGE_SIGNED | EFI_AGGREGATE_AUTH_STATUS_IMAGE_SIGNED; + + // + // Check whether there exists EFI_SECURITY_POLICY_PROTOCOL_GUID. + // + Status = gBS->LocateProtocol (&gEfiSecurityPolicyProtocolGuid, NULL, &DummyInterface); + if (!EFI_ERROR (Status)) { + *AuthenticationStatus |= EFI_LOCAL_AUTH_STATUS_PLATFORM_OVERRIDE | EFI_AGGREGATE_AUTH_STATUS_PLATFORM_OVERRIDE; + } else { + // + // Calculate CRC32 Checksum of Image + // + gBS->CalculateCrc32 (Image, *OutputSize, &Crc32Checksum); + if (Crc32Checksum != Crc32SectionHeader->CRC32Checksum) { + *AuthenticationStatus |= EFI_LOCAL_AUTH_STATUS_TEST_FAILED | EFI_AGGREGATE_AUTH_STATUS_TEST_FAILED; + } + } + + CopyMem (*OutputBuffer, Image, *OutputSize); + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/Crc32SectionExtract.dxs b/EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/Crc32SectionExtract.dxs new file mode 100644 index 0000000000..033ff94ac3 --- /dev/null +++ b/EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/Crc32SectionExtract.dxs @@ -0,0 +1,28 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Crc32SectionExtraction.dxs + +Abstract: + + Dependency expression file. + +--*/ + +#include +#include "DxeDepex.h" + +DEPENDENCY_START + EFI_RUNTIME_ARCH_PROTOCOL_GUID +DEPENDENCY_END + diff --git a/EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/Crc32SectionExtract.h b/EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/Crc32SectionExtract.h new file mode 100644 index 0000000000..8e32d6d7bb --- /dev/null +++ b/EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/Crc32SectionExtract.h @@ -0,0 +1,65 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Crc32SectionExtract.h + +Abstract: + + Header file for Crc32SectionExtract.c + Please refer to Tiano File Image Format specification + FV spec 0.3.6 + +--*/ + +#ifndef _CRC32_GUIDED_SECTION_EXTRACTION_H +#define _CRC32_GUIDED_SECTION_EXTRACTION_H + +typedef struct { + EFI_GUID_DEFINED_SECTION GuidedSectionHeader; + UINT32 CRC32Checksum; +} CRC32_SECTION_HEADER; + +// +// Function prototype declarations +// +STATIC +EFI_STATUS +Crc32ExtractSection ( + IN EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *This, + IN VOID *InputSection, + OUT VOID **OutputBuffer, + OUT UINTN *OutputSize, + OUT UINT32 *AuthenticationStatus + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + InputSection - TODO: add argument description + OutputBuffer - TODO: add argument description + OutputSize - TODO: add argument description + AuthenticationStatus - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/Crc32SectionExtract.mbd b/EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/Crc32SectionExtract.mbd new file mode 100644 index 0000000000..67ea3cd4b9 --- /dev/null +++ b/EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/Crc32SectionExtract.mbd @@ -0,0 +1,40 @@ + + + + + Crc32SectionExtract + 51C9F40C-5243-4473-B265-B3C8FFAFF9FA + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + + UefiBootServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + EdkDxePrintLib + BaseLib + + diff --git a/EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/Crc32SectionExtract.msa b/EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/Crc32SectionExtract.msa new file mode 100644 index 0000000000..da82d561a0 --- /dev/null +++ b/EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/Crc32SectionExtract.msa @@ -0,0 +1,61 @@ + + + + + Crc32SectionExtract + DXE_DRIVER + BS_DRIVER + 51C9F40C-5243-4473-B265-B3C8FFAFF9FA + 0 + Component description file for DiskIo module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + DebugLib + UefiDriverEntryPoint + UefiLib + BaseLib + BaseMemoryLib + UefiBootServicesTableLib + + + Crc32SectionExtract.c + Crc32SectionExtract.h + GuidedSection.c + GuidedSection.h + + + MdePkg + EdkModulePkg + + + SecurityPolicy + Crc32GuidedSectionExtraction + + + + InitializeCrc32GuidedSectionExtractionProtocol + + + diff --git a/EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/GuidedSection.c b/EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/GuidedSection.c new file mode 100644 index 0000000000..3c3f22f760 --- /dev/null +++ b/EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/GuidedSection.c @@ -0,0 +1,75 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + GuidedSection.c + +Abstract: + + GUIDed section extraction protocol implementation. + This contains the common constructor of GUIDed section + extraction protocol. GUID specific implementation of each + GUIDed section extraction protocol can be found in other + files under the same directory. + + Please refer to the Tiano File Image Format Specification, + FV spec 0.3.6 + + Acronyms used Meaning + + +--*/ + + +#include "Common/FirmwareFileSystem.h" + +EFI_STATUS +GuidedSectionExtractionProtocolConstructor ( + OUT EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL **GuidedSep, + IN EFI_EXTRACT_GUIDED_SECTION ExtractSection + ) +/*++ + +Routine Description: + + Constructor for the GUIDed section extraction protocol. Initializes + instance data. + +Arguments: + + This Instance to construct + +Returns: + + EFI_SUCCESS: Instance initialized. + +--*/ +// TODO: GuidedSep - add argument and description to function comment +// TODO: ExtractSection - add argument and description to function comment +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +{ + EFI_STATUS Status; + + *GuidedSep = NULL; + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL), + (VOID **) GuidedSep + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + (*GuidedSep)->ExtractSection = ExtractSection; + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/GuidedSection.h b/EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/GuidedSection.h new file mode 100644 index 0000000000..1399edf4f6 --- /dev/null +++ b/EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/GuidedSection.h @@ -0,0 +1,53 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + GuidedSection.h + +Abstract: + + Header file for GuidedSection.c + Please refer to Tiano File Image Format specification + FV spec 0.3.6 + +--*/ + +#ifndef _GUIDED_SECTION_EXTRACTION_H +#define _GUIDED_SECTION_EXTRACTION_H + +// +// Function prototype declarations +// +EFI_STATUS +GuidedSectionExtractionProtocolConstructor ( + OUT EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL **GuidedSep, + IN EFI_EXTRACT_GUIDED_SECTION ExtractSection + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + GuidedSep - TODO: add argument description + ExtractSection - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/build.xml b/EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/build.xml new file mode 100644 index 0000000000..7582701719 --- /dev/null +++ b/EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Universal/GenericMemoryTest/Dxe/Common.h b/EdkModulePkg/Universal/GenericMemoryTest/Dxe/Common.h new file mode 100644 index 0000000000..7a1ab78a1e --- /dev/null +++ b/EdkModulePkg/Universal/GenericMemoryTest/Dxe/Common.h @@ -0,0 +1,59 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Common.h + +Abstract: + The generic memory test driver definition + +--*/ + +#ifndef _COMMON_H +#define _COMMON_H + +// +// Some global define +// +#define GENERIC_CACHELINE_SIZE 0x40 + +// +// 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 EFI_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 EFI_SIGNATURE_32 ('G', 'E', 'M', 'T') + +#endif diff --git a/EdkModulePkg/Universal/GenericMemoryTest/Dxe/NullMemoryTest.c b/EdkModulePkg/Universal/GenericMemoryTest/Dxe/NullMemoryTest.c new file mode 100644 index 0000000000..7bad347f24 --- /dev/null +++ b/EdkModulePkg/Universal/GenericMemoryTest/Dxe/NullMemoryTest.c @@ -0,0 +1,214 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + NullMemoryTest.c + +Abstract: + +--*/ + + +#include "NullMemoryTest.h" + +// +// Module global members +// +UINT64 mTestedSystemMemory = 0; +UINT64 mTotalSystemMemory = 0; +EFI_HANDLE mGenericMemoryTestHandle; + +// +// Driver entry here +// +EFI_GENERIC_MEMORY_TEST_PROTOCOL mGenericMemoryTest = { + InitializeMemoryTest, + GenPerformMemoryTest, + GenMemoryTestFinished, + GenCompatibleRangeTest +}; + +EFI_STATUS +EFIAPI +GenericMemoryTestEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + The generic memory test driver's entry point, it can initialize private data + to default value + +Arguments: + + ImageHandle of the loaded driver + Pointer to the System Table + +Returns: + + Status + + EFI_SUCCESS - Protocol successfully installed + EFI_OUT_OF_RESOURCES - Can not allocate protocol data structure in base + memory + +--*/ +{ + EFI_STATUS Status; + + // + // Install the protocol + // + Status = gBS->InstallProtocolInterface ( + &mGenericMemoryTestHandle, + &gEfiGenericMemTestProtocolGuid, + EFI_NATIVE_INTERFACE, + &mGenericMemoryTest + ); + + return Status; +} +// +// EFI_GENERIC_MEMORY_TEST_PROTOCOL implementation +// +EFI_STATUS +EFIAPI +InitializeMemoryTest ( + IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This, + IN EXTENDMEM_COVERAGE_LEVEL Level, + OUT BOOLEAN *RequireSoftECCInit + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + 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) + ) { + gDS->RemoveMemorySpace ( + MemorySpaceMap[Index].BaseAddress, + MemorySpaceMap[Index].Length + ); + + gDS->AddMemorySpace ( + EfiGcdMemoryTypeSystemMemory, + MemorySpaceMap[Index].BaseAddress, + MemorySpaceMap[Index].Length, + MemorySpaceMap[Index].Capabilities &~ + (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME) + ); + + mTestedSystemMemory += MemorySpaceMap[Index].Length; + mTotalSystemMemory += MemorySpaceMap[Index].Length; + } else if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeSystemMemory) { + mTotalSystemMemory += MemorySpaceMap[Index].Length; + } + } + + gBS->FreePool (MemorySpaceMap); + + *RequireSoftECCInit = FALSE; + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +GenPerformMemoryTest ( + IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This, + IN OUT UINT64 *TestedMemorySize, + OUT UINT64 *TotalMemorySize, + OUT BOOLEAN *ErrorOut, + IN BOOLEAN TestAbort + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + *ErrorOut = FALSE; + *TestedMemorySize = mTestedSystemMemory; + *TotalMemorySize = mTotalSystemMemory; + + return EFI_NOT_FOUND; + +} + +EFI_STATUS +EFIAPI +GenMemoryTestFinished ( + IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +GenCompatibleRangeTest ( + IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS StartAddress, + IN UINT64 Length + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + EFI_GCD_MEMORY_SPACE_DESCRIPTOR descriptor; + + gDS->GetMemorySpaceDescriptor (StartAddress, &descriptor); + + gDS->RemoveMemorySpace (StartAddress, Length); + + gDS->AddMemorySpace ( + EfiGcdMemoryTypeSystemMemory, + StartAddress, + Length, + descriptor.Capabilities &~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME) + ); + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Universal/GenericMemoryTest/Dxe/NullMemoryTest.dxs b/EdkModulePkg/Universal/GenericMemoryTest/Dxe/NullMemoryTest.dxs new file mode 100644 index 0000000000..9f281b3d7d --- /dev/null +++ b/EdkModulePkg/Universal/GenericMemoryTest/Dxe/NullMemoryTest.dxs @@ -0,0 +1,26 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + NullMemoryTest.dxs + +Abstract: + + Dependency expression source file. + +--*/ +#include +#include + +DEPENDENCY_START + TRUE +DEPENDENCY_END diff --git a/EdkModulePkg/Universal/GenericMemoryTest/Dxe/NullMemoryTest.h b/EdkModulePkg/Universal/GenericMemoryTest/Dxe/NullMemoryTest.h new file mode 100644 index 0000000000..b4a0720f6b --- /dev/null +++ b/EdkModulePkg/Universal/GenericMemoryTest/Dxe/NullMemoryTest.h @@ -0,0 +1,65 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + NullMemoryTest.h + +Abstract: + The generic memory test driver definition + +--*/ + +#ifndef _NULL_MEMORY_TEST_H +#define _NULL_MEMORY_TEST_H + +#include "Common.h" + +// +// Function Prototypes +// +EFI_STATUS +EFIAPI +InitializeMemoryTest ( + IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This, + IN EXTENDMEM_COVERAGE_LEVEL Level, + OUT BOOLEAN *RequireSoftECCInit + ) +; + +EFI_STATUS +EFIAPI +GenPerformMemoryTest ( + IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This, + IN OUT UINT64 *TestedMemorySize, + OUT UINT64 *TotalMemorySize, + OUT BOOLEAN *ErrorOut, + IN BOOLEAN TestAbort + ) +; + +EFI_STATUS +EFIAPI +GenMemoryTestFinished ( + IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This + ) +; + +EFI_STATUS +EFIAPI +GenCompatibleRangeTest ( + IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS StartAddress, + IN UINT64 Length + ) +; + +#endif diff --git a/EdkModulePkg/Universal/GenericMemoryTest/Dxe/NullMemoryTest.mbd b/EdkModulePkg/Universal/GenericMemoryTest/Dxe/NullMemoryTest.mbd new file mode 100644 index 0000000000..2b770fe63d --- /dev/null +++ b/EdkModulePkg/Universal/GenericMemoryTest/Dxe/NullMemoryTest.mbd @@ -0,0 +1,44 @@ + + + + + NullMemoryTest + 96B5C032-DF4C-4b6e-8232-438DCF448D0E + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + + UefiBootServicesTableLib + BaseLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + DxeServicesTableLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + DxeMemoryAllocationLib + + + _ModuleEntryPoint + + diff --git a/EdkModulePkg/Universal/GenericMemoryTest/Dxe/NullMemoryTest.msa b/EdkModulePkg/Universal/GenericMemoryTest/Dxe/NullMemoryTest.msa new file mode 100644 index 0000000000..89c1b40348 --- /dev/null +++ b/EdkModulePkg/Universal/GenericMemoryTest/Dxe/NullMemoryTest.msa @@ -0,0 +1,60 @@ + + + + + NullMemoryTest + DXE_DRIVER + BS_DRIVER + 96B5C032-DF4C-4b6e-8232-438DCF448D0E + 0 + Component description file for DiskIo module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + DebugLib + UefiDriverEntryPoint + DxeServicesTableLib + BaseLib + MemoryAllocationLib + UefiBootServicesTableLib + + + Common.h + NullMemoryTest.c + NullMemoryTest.h + NullMemoryTest.dxs + + + MdePkg + EdkModulePkg + + + GenericMemTest + + + + GenericMemoryTestEntryPoint + + + diff --git a/EdkModulePkg/Universal/GenericMemoryTest/Dxe/build.xml b/EdkModulePkg/Universal/GenericMemoryTest/Dxe/build.xml new file mode 100644 index 0000000000..c392081b01 --- /dev/null +++ b/EdkModulePkg/Universal/GenericMemoryTest/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Universal/GenericMemoryTest/Pei/BaseMemoryTest.c b/EdkModulePkg/Universal/GenericMemoryTest/Pei/BaseMemoryTest.c new file mode 100644 index 0000000000..e091ae18fb --- /dev/null +++ b/EdkModulePkg/Universal/GenericMemoryTest/Pei/BaseMemoryTest.c @@ -0,0 +1,154 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + BaseMemoryTest.c + +Abstract: + + The PEI memory test support + +--*/ + +#include +#include + +static PEI_BASE_MEMORY_TEST_PPI mPeiBaseMemoryTestPpi = { BaseMemoryTest }; + +static EFI_PEI_PPI_DESCRIPTOR PpiListPeiBaseMemoryTest = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gPeiBaseMemoryTestPpiGuid, + &mPeiBaseMemoryTestPpi +}; + +EFI_STATUS +EFIAPI +PeiBaseMemoryTestInit ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices + ) +/*++ +Description: + + Entry point function of BaseMemoryTestInit Peim. + +Arguments: + + PeiServices - General purpose services available to every PEIM. + FfsHeader - Ffs header pointer + +Returns: + + Status - Result of InstallPpi + +--*/ +{ + EFI_STATUS Status; + + Status = (**PeiServices).InstallPpi (PeiServices, &PpiListPeiBaseMemoryTest); + + return Status; +} + +EFI_STATUS +EFIAPI +BaseMemoryTest ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_BASE_MEMORY_TEST_PPI *This, + IN EFI_PHYSICAL_ADDRESS BeginAddress, + IN UINT64 MemoryLength, + IN PEI_MEMORY_TEST_OP Operation, + OUT EFI_PHYSICAL_ADDRESS *ErrorAddress + ) +/*++ +Description: + + Test base memory. + +Arguments: + + PeiServices - General purpose services available to every PEIM. + This - Pei memory test PPI pointer. + BeginAddress - Beginning of the memory address to be checked. + MemoryLength - Bytes of memory range to be checked. + Operation - Type of memory check operation to be performed. + ErrorAddress - Return the address of the error memory address. + ErrorAddress - Address which has error when checked. + +Returns: + + Status - Result of InstallPpi + +--*/ +{ + UINT32 TestPattern; + UINT32 TestMask; + EFI_PHYSICAL_ADDRESS TempAddress; + UINT32 SpanSize; + + REPORT_STATUS_CODE ( + EFI_PROGRESS_CODE, + EFI_COMPUTING_UNIT_MEMORY + EFI_CU_MEMORY_PC_TEST + ); + + TestPattern = TEST_PATTERN; + TestMask = 0; + SpanSize = 0; + + // + // Make sure we don't try and test anything above the max physical address range + // + ASSERT_EFI_ERROR (BeginAddress + MemoryLength < EFI_MAX_ADDRESS); + + switch (Operation) { + case Extensive: + SpanSize = 0x4; + break; + + case Sparse: + case Quick: + SpanSize = COVER_SPAN; + break; + + case Ignore: + goto Done; + break; + } + // + // Write the test pattern into memory range + // + TempAddress = BeginAddress; + while (TempAddress < BeginAddress + MemoryLength) { + (*(UINT32 *) (UINTN) TempAddress) = TestPattern; + TempAddress += SpanSize; + } + // + // Read pattern from memory and compare it + // + TempAddress = BeginAddress; + while (TempAddress < BeginAddress + MemoryLength) { + if ((*(UINT32 *) (UINTN) TempAddress) != TestPattern) { + *ErrorAddress = TempAddress; + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED, + EFI_COMPUTING_UNIT_MEMORY | EFI_CU_MEMORY_EC_UNCORRECTABLE + ); + + return EFI_DEVICE_ERROR; + } + + TempAddress += SpanSize; + } + +Done: + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Universal/GenericMemoryTest/Pei/BaseMemoryTest.h b/EdkModulePkg/Universal/GenericMemoryTest/Pei/BaseMemoryTest.h new file mode 100644 index 0000000000..15d6c61bd4 --- /dev/null +++ b/EdkModulePkg/Universal/GenericMemoryTest/Pei/BaseMemoryTest.h @@ -0,0 +1,89 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + BaseMemoryTest.h + +Abstract: + + Tiano PEIM to provide a PEI memory test service. + +--*/ + +#ifndef _PEI_BASE_MEMORY_TEST_H_ +#define _PEI_BASE_MEMORY_TEST_H_ + +#include + +// +// Some global define +// +#define COVER_SPAN 0x40000 +#define TEST_PATTERN 0x5A5A5A5A + +EFI_STATUS +EFIAPI +PeiBaseMemoryTestInit ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + FfsHeader - TODO: add argument description + PeiServices - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +BaseMemoryTest ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_BASE_MEMORY_TEST_PPI *This, + IN EFI_PHYSICAL_ADDRESS BeginAddress, + IN UINT64 MemoryLength, + IN PEI_MEMORY_TEST_OP Operation, + OUT EFI_PHYSICAL_ADDRESS *ErrorAddress + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PeiServices - TODO: add argument description + This - TODO: add argument description + BeginAddress - TODO: add argument description + MemoryLength - TODO: add argument description + Operation - TODO: add argument description + ErrorAddress - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/EdkModulePkg/Universal/GenericMemoryTest/Pei/BaseMemoryTest.mbd b/EdkModulePkg/Universal/GenericMemoryTest/Pei/BaseMemoryTest.mbd new file mode 100644 index 0000000000..59c52c9718 --- /dev/null +++ b/EdkModulePkg/Universal/GenericMemoryTest/Pei/BaseMemoryTest.mbd @@ -0,0 +1,39 @@ + + + + + PeiBaseMemoryTestInit + 736EB068-8C01-47c5-964B-1C57BD5D4D64 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + + PeimEntryPoint + PeiReportStatusCodeLib + BaseDebugLibReportStatusCode + PeiServicesTablePointerLib + PeiMemoryLib + PeiCoreLib + BaseLib + + diff --git a/EdkModulePkg/Universal/GenericMemoryTest/Pei/BaseMemoryTest.msa b/EdkModulePkg/Universal/GenericMemoryTest/Pei/BaseMemoryTest.msa new file mode 100644 index 0000000000..ff96a6b210 --- /dev/null +++ b/EdkModulePkg/Universal/GenericMemoryTest/Pei/BaseMemoryTest.msa @@ -0,0 +1,54 @@ + + + + + PeiBaseMemoryTestInit + PEIM + PE32_PEIM + 736EB068-8C01-47c5-964B-1C57BD5D4D64 + 0 + Component description file for DiskIo module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + DebugLib + PeimEntryPoint + PeiCoreLib + + + BaseMemoryTest.c + + + MdePkg + EdkModulePkg + + + BaseMemoryTest + + + + PeiBaseMemoryTestInit + + + diff --git a/EdkModulePkg/Universal/GenericMemoryTest/Pei/build.xml b/EdkModulePkg/Universal/GenericMemoryTest/Pei/build.xml new file mode 100644 index 0000000000..4a96b6bda8 --- /dev/null +++ b/EdkModulePkg/Universal/GenericMemoryTest/Pei/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Universal/MonotonicCounter/RuntimeDxe/MonotonicCounter.c b/EdkModulePkg/Universal/MonotonicCounter/RuntimeDxe/MonotonicCounter.c new file mode 100644 index 0000000000..6e4350f0ed --- /dev/null +++ b/EdkModulePkg/Universal/MonotonicCounter/RuntimeDxe/MonotonicCounter.c @@ -0,0 +1,266 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + MonotonicCounter.c + +Abstract: + + Produced the Monotonic Counter Services as defined in the DXE CIS + +Revision History: + +--*/ + +#include "MonotonicCounter.h" + +// +// The Monotonic Counter Handle +// +EFI_HANDLE mMonotonicCounterHandle = NULL; + +// +// The current Monotonic count value +// +UINT64 mEfiMtc; + + +// +// Event to use to update the Mtc's high part when wrapping +// +EFI_EVENT mEfiMtcEvent; + +// +// EfiMtcName - Variable name of the MTC value +// +CHAR16 *mEfiMtcName = (CHAR16 *) L"MTC"; + +// +// EfiMtcGuid - Guid of the MTC value +// +EFI_GUID mEfiMtcGuid = { 0xeb704011, 0x1402, 0x11d3, { 0x8e, 0x77, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } }; + +// +// Worker functions +// +EFI_STATUS +EFIAPI +MonotonicCounterDriverGetNextMonotonicCount ( + OUT UINT64 *Count + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + EFI_TPL OldTpl; + + // + // Can not 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 (EFI_TPL_HIGH_LEVEL); + *Count = mEfiMtc; + mEfiMtc++; + gBS->RestoreTPL (OldTpl); + + // + // If the MSB bit of the low part toggled, then signal that the high + // part needs updated now + // + if ((((UINT32) mEfiMtc) ^ ((UINT32) *Count)) & 0x80000000) { + gBS->SignalEvent (mEfiMtcEvent); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +MonotonicCounterDriverGetNextHighMonotonicCount ( + OUT UINT32 *HighCount + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + EFI_STATUS Status; + 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 (EFI_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 NvRam store to match the new high part + // + Status = gRT->SetVariable ( + mEfiMtcName, + &mEfiMtcGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof (UINT32), + HighCount + ); + + return Status; +} + +VOID +EFIAPI +EfiMtcEventHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + + Monotonic count event handler. This handler updates the high monotonic count. + +Arguments: + + Event The event to handle + Context The event context + +Returns: + + EFI_SUCCESS The event has been handled properly + EFI_NOT_FOUND An error occurred updating the variable. + +--*/ +{ + UINT32 HighCount; + + MonotonicCounterDriverGetNextHighMonotonicCount (&HighCount); +} + +EFI_STATUS +EFIAPI +MonotonicCounterDriverInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + +Arguments: + (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT) + +Returns: + +--*/ +{ + EFI_STATUS Status; + UINT32 HighCount; + UINTN BufferSize; + + // + // Make sure the Monotonic Counter Architectural Protocol is not already installed in the system + // + ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiMonotonicCounterArchProtocolGuid); + + // + // Initialize event to handle overflows + // + Status = gBS->CreateEvent ( + EFI_EVENT_NOTIFY_SIGNAL, + EFI_TPL_CALLBACK, + EfiMtcEventHandler, + NULL, + &mEfiMtcEvent + ); + + ASSERT_EFI_ERROR (Status); + + // + // Read the last high part + // + BufferSize = sizeof (UINT32); + Status = gRT->GetVariable ( + mEfiMtcName, + &mEfiMtcGuid, + 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. + // + Status = 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/EdkModulePkg/Universal/MonotonicCounter/RuntimeDxe/MonotonicCounter.dxs b/EdkModulePkg/Universal/MonotonicCounter/RuntimeDxe/MonotonicCounter.dxs new file mode 100644 index 0000000000..d32e0288ff --- /dev/null +++ b/EdkModulePkg/Universal/MonotonicCounter/RuntimeDxe/MonotonicCounter.dxs @@ -0,0 +1,27 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + MonotonicCounter.dxs + +Abstract: + + Dependency expression source file. + +--*/ +#include +#include + +DEPENDENCY_START + EFI_VARIABLE_ARCH_PROTOCOL_GUID AND + EFI_VARIABLE_WRITE_ARCH_PROTOCOL_GUID +DEPENDENCY_END diff --git a/EdkModulePkg/Universal/MonotonicCounter/RuntimeDxe/MonotonicCounter.h b/EdkModulePkg/Universal/MonotonicCounter/RuntimeDxe/MonotonicCounter.h new file mode 100644 index 0000000000..c86b15dd26 --- /dev/null +++ b/EdkModulePkg/Universal/MonotonicCounter/RuntimeDxe/MonotonicCounter.h @@ -0,0 +1,36 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + MonotonicCounter.h + +Abstract: + + Produces the Monotonic Counter services as defined in the DXE CIS + +--*/ + +#ifndef _MONOTONIC_COUNTER_DRIVER_H_ +#define _MONOTONIC_COUNTER_DRIVER_H_ + +// +// Function Prototypes +// +EFI_STATUS +EFIAPI +MonotonicCounterDriverInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +; + +#endif diff --git a/EdkModulePkg/Universal/MonotonicCounter/RuntimeDxe/MonotonicCounter.mbd b/EdkModulePkg/Universal/MonotonicCounter/RuntimeDxe/MonotonicCounter.mbd new file mode 100644 index 0000000000..6a5fa71a76 --- /dev/null +++ b/EdkModulePkg/Universal/MonotonicCounter/RuntimeDxe/MonotonicCounter.mbd @@ -0,0 +1,47 @@ + + + + + MonotonicCounter + AD608272-D07F-4964-801E-7BD3B7888652 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-22 14:36 + + + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + BaseLib + BaseMemoryLib + UefiLib + UefiDriverEntryPoint + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + DxeMemoryAllocationLib + EdkDxeRuntimeDriverLib + + EdkDxeSalLib + + + + _ModuleEntryPoint + + diff --git a/EdkModulePkg/Universal/MonotonicCounter/RuntimeDxe/MonotonicCounter.msa b/EdkModulePkg/Universal/MonotonicCounter/RuntimeDxe/MonotonicCounter.msa new file mode 100644 index 0000000000..c86e89ee48 --- /dev/null +++ b/EdkModulePkg/Universal/MonotonicCounter/RuntimeDxe/MonotonicCounter.msa @@ -0,0 +1,70 @@ + + + + + MonotonicCounter + DXE_RUNTIME_DRIVER + RT_DRIVER + AD608272-D07F-4964-801E-7BD3B7888652 + 0 + Component description file for DiskIo module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-22 14:36 + + + BaseLib + UefiLib + UefiDriverEntryPoint + DxeRuntimeDriverLib + DebugLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + + + MonotonicCounter.c + MonotonicCounter.h + MonotonicCounter.dxs + + + MdePkg + EdkModulePkg + + + MonotonicCounter + + + + MTC + 0xeb704011, 0x1402, 0x11d3, 0x8e, 0x77, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b + + + + + MonotonicCounterDriverInitialize + + + + + + + diff --git a/EdkModulePkg/Universal/MonotonicCounter/RuntimeDxe/build.xml b/EdkModulePkg/Universal/MonotonicCounter/RuntimeDxe/build.xml new file mode 100644 index 0000000000..ef6b8c4aa9 --- /dev/null +++ b/EdkModulePkg/Universal/MonotonicCounter/RuntimeDxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/BC.mbd b/EdkModulePkg/Universal/Network/PxeBc/Dxe/BC.mbd new file mode 100644 index 0000000000..2262fc64c7 --- /dev/null +++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/BC.mbd @@ -0,0 +1,42 @@ + + + + + BC + A3f436EA-A127-4EF8-957C-8048606FF670 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + + UefiBootServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + EdkDxePrintLib + BaseLib + DxeMemoryAllocationLib + + diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/BC.msa b/EdkModulePkg/Universal/Network/PxeBc/Dxe/BC.msa new file mode 100644 index 0000000000..e94492bac8 --- /dev/null +++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/BC.msa @@ -0,0 +1,94 @@ + + + + + BC + UEFI_DRIVER + BS_DRIVER + A3f436EA-A127-4EF8-957C-8048606FF670 + 0 + Component description file for DiskIo module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + UefiLib + BaseLib + PrintLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + + + bc.c + pxe_bc_arp.c + pxe_bc_dhcp.c + pxe_bc_igmp.c + pxe_bc_ip.c + pxe_bc_mtftp.c + pxe_bc_udp.c + pxe_loadfile.c + dhcp.h + bc.h + ip.h + ComponentName.c + Print.c + + + MdePkg + EdkModulePkg + + + Bis + LoadFile + PxeBaseCodeCallBack + SimpleNetwork + DevicePath + NetworkInterfaceIdentifier + NetworkInterfaceIdentifier2 + PxeBaseCode + + + + gEfiSmbiosTableGuid + + + + + SmbiosTable + + + + + InitializeBCDriver + + + + gPxeBcDriverBinding + gPxeBcComponentName + + + diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/ComponentName.c b/EdkModulePkg/Universal/Network/PxeBc/Dxe/ComponentName.c new file mode 100644 index 0000000000..2c11dc4556 --- /dev/null +++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/ComponentName.c @@ -0,0 +1,160 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + ComponentName.c + +Abstract: + +--*/ + + +#include "Bc.h" + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +PxeBcComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +EFI_STATUS +EFIAPI +PxeBcComponentNameGetControllerName ( + 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 +// +EFI_COMPONENT_NAME_PROTOCOL gPxeBcComponentName = { + PxeBcComponentNameGetDriverName, + PxeBcComponentNameGetControllerName, + "eng" +}; + +static EFI_UNICODE_STRING_TABLE mPxeBcDriverNameTable[] = { + { + "eng", + (CHAR16 *) L"PXE Base Code Driver" + }, + { + NULL, + NULL + } +}; + +EFI_STATUS +EFIAPI +PxeBcComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gPxeBcComponentName.SupportedLanguages, + mPxeBcDriverNameTable, + DriverName + ); +} + +EFI_STATUS +EFIAPI +PxeBcComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + 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. + 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. + + Returns: + 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. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return EFI_UNSUPPORTED; +} diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/Print.c b/EdkModulePkg/Universal/Network/PxeBc/Dxe/Print.c new file mode 100644 index 0000000000..4ea5cbadab --- /dev/null +++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/Print.c @@ -0,0 +1,81 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + Print.c + +Abstract: + +--*/ + + +#include + +UINTN +EFIAPI +AsciiPrint ( + IN CONST CHAR8 *Format, + ... + ) +/*++ + +Routine Description: + + Print function for a maximum of PXE_MAX_PRINT_BUFFER ascii + characters. + +Arguments: + + Format - Ascii format string see file header for more details. + + ... - Vararg list consumed by processing Format. + +Returns: + + Number of characters printed. + +--*/ +{ + UINTN Return; + VA_LIST Marker; + UINTN Index; + UINTN MaxIndex; + CHAR16 Buffer[PXE_MAX_PRINT_BUFFER]; + CHAR16 UnicodeFormat[PXE_MAX_PRINT_BUFFER]; + + MaxIndex = AsciiStrLen ((CHAR8 *) Format); + if (MaxIndex > PXE_MAX_PRINT_BUFFER) { + // + // Format string was too long for use to process. + // + return 0; + } + + for (Index = 0; Index < PXE_MAX_PRINT_BUFFER; Index++) { + UnicodeFormat[Index] = (CHAR16) Format[Index]; + } + + VA_START (Marker, Format); + Return = UnicodeVSPrint (Buffer, sizeof (Buffer), UnicodeFormat, Marker); + VA_END (Marker); + + // + // Need to convert to Unicode to do an OutputString + // + + if (gST->ConOut != NULL) { + // + // To be extra safe make sure ConOut has been initialized + // + gST->ConOut->OutputString (gST->ConOut, Buffer); + } + + return Return; +} diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/bc.c b/EdkModulePkg/Universal/Network/PxeBc/Dxe/bc.c new file mode 100644 index 0000000000..b9f48912e2 --- /dev/null +++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/bc.c @@ -0,0 +1,2510 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + bc.c + +Abstract: + +--*/ + +#include "bc.h" + +// +// +// +EFI_STATUS +EFIAPI +PxeBcDriverSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +PxeBcDriverStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +PxeBcDriverStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +extern +VOID +InitArpHeader ( + VOID + ); +extern +VOID +OptionsStrucInit ( + VOID + ); + +// +// helper routines +// +VOID +CvtNum ( + IN UINTN Number, + IN UINT8 *Buffer, + IN INTN Length + ) +/*++ + + Routine Description: + Convert number to ASCII value + + Arguments: + Number - Numeric value to convert to decimal ASCII value. + Buffer - Buffer to place ASCII version of the Number + Length - Length of Buffer. + + Returns: + none - none + +--*/ +{ + UINTN Remainder; + + while (Length--) { + Remainder = Number % 10; + Number /= 10; + Buffer[Length] = (UINT8) ('0' + Remainder); + } +} + +VOID +UtoA10 ( + IN UINTN Number, + IN UINT8 *Buffer + ) +/*++ + + Routine Description: + Convert number to decimal ASCII value at Buffer location + + Arguments: + Number - Numeric value to convert to decimal ASCII value. + Buffer - Buffer to place ASCII version of the Number + + Returns: + none - none + +--*/ +{ + INTN Index; + UINT8 BuffArray[31]; + + BuffArray[30] = 0; + CvtNum (Number, BuffArray, 30); + + for (Index = 0; Index < 30; ++Index) { + if (BuffArray[Index] != '0') { + break; + } + } + + CopyMem (Buffer, BuffArray + Index, 31 - Index); +} + +UINTN +AtoU ( + IN UINT8 *Buffer + ) +/*++ + + Routine Description: + Convert ASCII numeric string to a UINTN value + + Arguments: + Number - Numeric value to convert to decimal ASCII value. + Buffer - Buffer to place ASCII version of the Number + + Returns: + Value - UINTN value of the ASCII string. + +--*/ +{ + UINTN Value; + INT8 Character; + + Value = 0; + Character = *Buffer++; + do { + Value = Value * 10 + Character - '0'; + Character = *Buffer++; + } while (Character); + + return Value; +} + +UINT64 +AtoU64 ( + IN UINT8 *Buffer + ) +/*++ + + Routine Description: + Convert ASCII numeric string to a UINTN value + + Arguments: + Number - Numeric value to convert to decimal ASCII value. + Buffer - Buffer to place ASCII version of the Number + + Returns: + Value - UINTN value of the ASCII string. + +--*/ +{ + UINT64 Value; + UINT8 Character; + + Value = 0; + while ((Character = *Buffer++) != '\0') { + Value = MultU64x32 (Value, 10) + (Character - '0'); + } + + return Value; +} +// +// random number generator +// +#define RANDOM_MULTIPLIER 2053 +#define RANDOM_ADD_IN_VALUE 19 + +VOID +SeedRandom ( + IN PXE_BASECODE_DEVICE *Private, + IN UINT16 InitialSeed + ) +/*++ + + Routine Description: + Initialize the Seed for the random number generator + + Arguments: + + Returns: + none - + +--*/ +{ + if (Private != NULL) { + Private->RandomSeed = InitialSeed; + } +} + +UINT16 +Random ( + IN PXE_BASECODE_DEVICE *Private + ) +/*++ + + Routine Description: + Generate and return a pseudo-random number + + Arguments: + + Returns: + Number - UINT16 random number + +--*/ +{ + UINTN Number; + + if (Private != NULL) { + Number = -(INTN) Private->RandomSeed * RANDOM_MULTIPLIER + RANDOM_ADD_IN_VALUE; + + return Private->RandomSeed = (UINT16) Number; + } else { + return 0; + } +} +// +// calculate the internet checksum (RFC 1071) +// return 16 bit ones complement of ones complement sum of 16 bit words +// +UINT16 +IpChecksum ( + IN UINT16 *Packet, + IN UINTN Length + ) +/*++ + + Routine Description: + Calculate the internet checksum (see RFC 1071) + + Arguments: + Packet - Buffer which contains the data to be checksummed + Length - Length to be checksummed + + Returns: + Checksum - Returns the 16 bit ones complement of + ones complement sum of 16 bit words + +--*/ +{ + UINT32 Sum; + UINT8 Odd; + + Sum = 0; + Odd = (UINT8) (Length & 1); + Length >>= 1; + while (Length--) { + Sum += *Packet++; + } + + if (Odd) { + Sum += *(UINT8 *) Packet; + } + + Sum = (Sum & 0xffff) + (Sum >> 16); + // + // in case above carried + // + Sum += Sum >> 16; + + return (UINT16) (~ (UINT16) Sum); +} + +UINT16 +IpChecksum2 ( + IN UINT16 *Header, + IN UINTN HeaderLen, + IN UINT16 *Message, + IN UINTN MessageLen + ) +/*++ + + Routine Description: + Calculate the internet checksum (see RFC 1071) + on a non contiguous header and data + + Arguments: + Header - Buffer which contains the data to be checksummed + HeaderLen - Length to be checksummed + Message - Buffer which contains the data to be checksummed + MessageLen - Length to be checksummed + + Returns: + Checksum - Returns the 16 bit ones complement of + ones complement sum of 16 bit words + +--*/ +{ + UINT32 Sum; + + Sum = (UINT16)~IpChecksum (Header, HeaderLen) + (UINT16)~IpChecksum (Message, MessageLen); + + // + // in case above carried + // + Sum += Sum >> 16; + + return (UINT16) (~ (UINT16) Sum); +} + +UINT16 +UpdateChecksum ( + IN UINT16 OldChksum, + IN UINT16 OldWord, + IN UINT16 NewWord + ) +/*++ + + Routine Description: + Adjust the internet checksum (see RFC 1071) on a single word update. + + Arguments: + OldChkSum - Checksum previously calculated + OldWord - Value + NewWord - New Value + + Returns: + Checksum - Returns the 16 bit ones complement of + ones complement sum of 16 bit words + +--*/ +{ + UINT32 sum; + + sum = ~OldChksum + NewWord - OldWord; + // + // in case above carried + // + sum += sum >> 16; + return (UINT16) (~ (UINT16) sum); +} + +STATIC +BOOLEAN +SetMakeCallback ( + IN PXE_BASECODE_DEVICE *Private + ) +/*++ + + Routine Description: + See if a callback is in play + + Arguments: + Private - Pointer to Pxe BaseCode Protocol + + Returns: + 0 - Callbacks are active on the handle + 1 - Callbacks are not active on the handle + +--*/ +{ + Private->EfiBc.Mode->MakeCallbacks = (BOOLEAN) (gBS->HandleProtocol ( + Private->Handle, + &gEfiPxeBaseCodeCallbackProtocolGuid, + (VOID *) &Private->CallbackProtocolPtr + ) == EFI_SUCCESS); + + DEBUG ( + (EFI_D_INFO, + "\nMode->MakeCallbacks == %d ", + Private->EfiBc.Mode->MakeCallbacks) + ); + + DEBUG ( + (EFI_D_INFO, + "\nPrivate->CallbackProtocolPtr == %xh ", + Private->CallbackProtocolPtr) + ); + + if (Private->CallbackProtocolPtr != NULL) { + DEBUG ( + (EFI_D_INFO, + "\nCallbackProtocolPtr->Revision = %xh ", + Private->CallbackProtocolPtr->Revision) + ); + + DEBUG ( + (EFI_D_INFO, + "\nCallbackProtocolPtr->Callback = %xh ", + Private->CallbackProtocolPtr->Callback) + ); + } + + return Private->EfiBc.Mode->MakeCallbacks; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +EFI_STATUS +WaitForReceive ( + IN PXE_BASECODE_DEVICE *Private, + IN EFI_PXE_BASE_CODE_FUNCTION Function, + IN EFI_EVENT TimeoutEvent, + IN OUT UINTN *HeaderSizePtr, + IN OUT UINTN *BufferSizePtr, + IN OUT UINT16 *ProtocolPtr + ) +/*++ + + Routine Description: + Routine which does an SNP->Receive over a timeout period and doing callbacks + + Arguments: + Private - Pointer to Pxe BaseCode Protocol + Function - What PXE function to callback + TimeoutEvent - Timer event that will trigger when we have waited too + long for an incoming packet + HeaderSizePtr - Pointer to the size of the Header size + BufferSizePtr - Pointer to the size of the Buffer size + ProtocolPtr - The protocol to sniff for (namely, UDP/etc) + + Returns: + 0 - Something was returned + !0 - Like there was nothing to receive (EFI_TIMEOUT/NOT_READY) + +--*/ +{ + EFI_SIMPLE_NETWORK_PROTOCOL *SnpPtr; + EFI_PXE_CALLBACK CallbackPtr; + EFI_STATUS StatCode; + EFI_EVENT CallbackEvent; + + // + // Initialize pointer to SNP interface + // + SnpPtr = Private->SimpleNetwork; + + // + // Initialize pointer to PxeBc callback routine - if any + // + CallbackPtr = (Private->EfiBc.Mode->MakeCallbacks) ? Private->CallbackProtocolPtr->Callback : NULL; + + // + // Create callback event and set timer + // + StatCode = gBS->CreateEvent ( + EFI_EVENT_TIMER, + EFI_TPL_CALLBACK, + NULL, + NULL, + &CallbackEvent + ); + + if (EFI_ERROR (StatCode)) { + return EFI_DEVICE_ERROR; + } + + // + // every 100 milliseconds + // + StatCode = gBS->SetTimer ( + CallbackEvent, + TimerPeriodic, + 1000000 + ); + + if (EFI_ERROR (StatCode)) { + gBS->CloseEvent (CallbackEvent); + return EFI_DEVICE_ERROR; + } + // + // Loop until a packet is received or a receive error is detected or + // a callback abort is detected or a timeout event occurs. + // + for (;;) + { +#if 0 + // + // Check for received packet event. + // + if (!EFI_ERROR (gBS->CheckEvent (SnpPtr->WaitForPacket))) { + // + // Packet should be available. Attempt to read it. + // + *BufferSizePtr = BUFFER_ALLOCATE_SIZE; + + StatCode = SnpPtr->Receive ( + SnpPtr, + HeaderSizePtr, + BufferSizePtr, + Private->ReceiveBufferPtr, + 0, + 0, + ProtocolPtr + ); + + if (EFI_ERROR (StatCode)) { + break; + } + // + // Packet was received. Make received callback then return. + // + if (CallbackPtr != NULL) { + StatCode = CallbackPtr ( + Private->CallbackProtocolPtr, + Function, + TRUE, + (UINT32) *BufferSizePtr, + (EFI_PXE_BASE_CODE_PACKET *) Private->ReceiveBufferPtr + ); + + if (StatCode != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) { + StatCode = EFI_ABORTED; + } else { + StatCode = EFI_SUCCESS; + } + } + + break; + } + +#else + // + // Poll for received packet. + // + *BufferSizePtr = BUFFER_ALLOCATE_SIZE; + + StatCode = SnpPtr->Receive ( + SnpPtr, + HeaderSizePtr, + BufferSizePtr, + Private->ReceiveBufferPtr, + 0, + 0, + ProtocolPtr + ); + + if (!EFI_ERROR (StatCode)) { + // + // Packet was received. Make received callback then return. + // + if (CallbackPtr != NULL) { + StatCode = CallbackPtr ( + Private->CallbackProtocolPtr, + Function, + TRUE, + (UINT32) *BufferSizePtr, + (EFI_PXE_BASE_CODE_PACKET *) Private->ReceiveBufferPtr + ); + + if (StatCode != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) { + StatCode = EFI_ABORTED; + } else { + StatCode = EFI_SUCCESS; + } + } + + break; + } + + if (StatCode != EFI_NOT_READY) { + break; + } +#endif + // + // Check for callback event. + // + if (!EFI_ERROR (gBS->CheckEvent (CallbackEvent))) { + // + // Make periodic callback if callback pointer is initialized. + // + if (CallbackPtr != NULL) { + StatCode = CallbackPtr ( + Private->CallbackProtocolPtr, + Function, + FALSE, + 0, + NULL + ); + + // + // Abort if directed to by callback routine. + // + if (StatCode != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) { + StatCode = EFI_ABORTED; + break; + } + } + } + // + // Check for timeout event. + // + if (TimeoutEvent == 0) { + StatCode = EFI_TIMEOUT; + break; + } + + if (!EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) { + StatCode = EFI_TIMEOUT; + break; + } + // + // Check IGMP timer events. + // + IgmpCheckTimers (Private); + } + + gBS->CloseEvent (CallbackEvent); + + return StatCode; +} + +EFI_STATUS +SendPacket ( + PXE_BASECODE_DEVICE *Private, + VOID *HeaderPtr, + VOID *PacketPtr, + INTN PacketLen, + VOID *HardwareAddr, + UINT16 MediaProtocol, + IN EFI_PXE_BASE_CODE_FUNCTION Function + ) +/*++ + + Routine Description: + Routine which does an SNP->Transmit of a buffer + + Arguments: + Private - Pointer to Pxe BaseCode Protocol + HeaderPtr - Pointer to the buffer + PacketPtr - Pointer to the packet to send + PacketLen - The length of the entire packet to send + HardwareAddr - Pointer to the MAC address of the destination + MediaProtocol - What type of frame to create (RFC 1700) - IE. Ethernet + Function - What PXE function to callback + + Returns: + 0 - Something was sent + !0 - An error was encountered during sending of a packet + +--*/ +{ + EFI_SIMPLE_NETWORK_PROTOCOL *SnpPtr; + EFI_SIMPLE_NETWORK_MODE *SnpModePtr; + EFI_PXE_CALLBACK CallbackPtr; + EFI_STATUS StatCode; + EFI_EVENT TimeoutEvent; + UINT32 IntStatus; + VOID *TxBuf; + + // + // + // + CallbackPtr = Private->EfiBc.Mode->MakeCallbacks ? Private->CallbackProtocolPtr->Callback : 0; + + SnpPtr = Private->SimpleNetwork; + SnpModePtr = SnpPtr->Mode; + + // + // clear prior interrupt status + // + StatCode = SnpPtr->GetStatus (SnpPtr, &IntStatus, 0); + + if (EFI_ERROR (StatCode)) { + DEBUG ( + (EFI_D_WARN, + "\nSendPacket() Exit #1 %xh (%r)", + StatCode, + StatCode) + ); + return StatCode; + } + + Private->DidTransmit = FALSE; + + if (CallbackPtr != NULL) { + if (CallbackPtr ( + Private->CallbackProtocolPtr, + Function, + FALSE, + (UINT32) PacketLen, + PacketPtr + ) != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) { + DEBUG ( + (EFI_D_WARN, + "\nSendPacket() Exit #2 %xh (%r)", + EFI_ABORTED, + EFI_ABORTED) + ); + return EFI_ABORTED; + } + } + // + // put packet in transmit queue + // headersize should be zero if not filled in + // + StatCode = gBS->CreateEvent ( + EFI_EVENT_TIMER, + EFI_TPL_CALLBACK, + NULL, + NULL, + &TimeoutEvent + ); + + if (EFI_ERROR (StatCode)) { + DEBUG ( + (EFI_D_ERROR, + "Could not create transmit timeout event. %r\n", + StatCode) + ); + return EFI_DEVICE_ERROR; + } + + // + // 5 milliseconds + // + StatCode = gBS->SetTimer ( + TimeoutEvent, + TimerRelative, + 50000 + ); + + if (EFI_ERROR (StatCode)) { + DEBUG ( + (EFI_D_ERROR, + "Could not set transmit timeout event timer. %r\n", + StatCode) + ); + gBS->CloseEvent (TimeoutEvent); + return EFI_DEVICE_ERROR; + } + + for (;;) { + StatCode = SnpPtr->Transmit ( + SnpPtr, + (UINTN) SnpPtr->Mode->MediaHeaderSize, + (UINTN) (PacketLen + SnpPtr->Mode->MediaHeaderSize), + HeaderPtr, + &SnpModePtr->CurrentAddress, + (EFI_MAC_ADDRESS *) HardwareAddr, + &MediaProtocol + ); + + if (StatCode != EFI_NOT_READY) { + break; + } + + if (!EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) { + StatCode = EFI_TIMEOUT; + break; + } + } + + gBS->CloseEvent (TimeoutEvent); + + if (EFI_ERROR (StatCode)) { + DEBUG ( + (EFI_D_WARN, + "\nSendPacket() Exit #3 %xh (%r)", + StatCode, + StatCode) + ); + return StatCode; + } + // + // remove transmit buffer from snp's unused queue + // done this way in case someday things are buffered and we don't get it back + // immediately + // + StatCode = gBS->CreateEvent ( + EFI_EVENT_TIMER, + EFI_TPL_CALLBACK, + NULL, + NULL, + &TimeoutEvent + ); + + if (EFI_ERROR (StatCode)) { + DEBUG ( + (EFI_D_ERROR, + "Could not create transmit status timeout event. %r\n", + StatCode) + ); + return EFI_DEVICE_ERROR; + } + + // + // 5 milliseconds + // + StatCode = gBS->SetTimer ( + TimeoutEvent, + TimerRelative, + 50000 + ); + + if (EFI_ERROR (StatCode)) { + DEBUG ( + (EFI_D_ERROR, + "Could not set transmit status timeout event timer. %r\n", + StatCode) + ); + gBS->CloseEvent (TimeoutEvent); + return EFI_DEVICE_ERROR; + } + + for (;;) { + StatCode = SnpPtr->GetStatus (SnpPtr, &IntStatus, &TxBuf); + + if (EFI_ERROR (StatCode)) { + DEBUG ( + (EFI_D_WARN, + "\nSendPacket() Exit #4 %xh (%r)", + StatCode, + StatCode) + ); + break; + } + + if (IntStatus & EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT) { + Private->DidTransmit = TRUE; + } + + if (TxBuf != NULL) { + break; + } + + if (!EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) { + StatCode = EFI_TIMEOUT; + break; + } + } + + gBS->CloseEvent (TimeoutEvent); + + return StatCode; +} +// +// +// +EFI_BIS_PROTOCOL * +PxebcBisStart ( + IN PXE_BASECODE_DEVICE *Private, + OUT BIS_APPLICATION_HANDLE *BisAppHandle, + OUT OPTIONAL EFI_BIS_DATA **BisDataSigInfo + ) +/*++ +Routine description: + Locate BIS interface and if found, try to start it. + +Parameters: + Private := Pointer to PxeBc protocol + BisAppHandle := Pointer to BIS application handle storage + BisDataSigInfo := Pointer to BIS signature information storage +Returns: +--*/ +{ + EFI_STATUS EfiStatus; + EFI_HANDLE BisHandleBuffer; + UINTN BisHandleCount; + EFI_BIS_PROTOCOL *BisPtr; + EFI_BIS_VERSION BisInterfaceVersion; + BOOLEAN BisCheckFlag; + + BisHandleCount = sizeof (EFI_HANDLE); + BisCheckFlag = FALSE; + + // + // Locate BIS protocol handle (if present). + // If BIS protocol handle is not found, return NULL. + // + DEBUG ((EFI_D_INFO, "\ngBS->LocateHandle() ")); + + EfiStatus = gBS->LocateHandle ( + ByProtocol, + &gEfiBisProtocolGuid, + NULL, + &BisHandleCount, + &BisHandleBuffer + ); + + if (EFI_ERROR (EfiStatus)) { + // + // Any error means that there is no BIS. + // Note - It could mean that there are more than + // one BIS protocols installed, but that scenario + // is not yet supported. + // + DEBUG ( + (EFI_D_WARN, + "\nPxebcBisStart()""\n gBS->LocateHandle() %r (%xh)\n", + EfiStatus, + EfiStatus) + ); + + return NULL; + } + + if (BisHandleCount != sizeof BisHandleBuffer) { + // + // This really should never happen, but I am paranoid. + // + DEBUG ( + (EFI_D_NET, + "\nPxebcBisStart() BisHandleCount != %d\n", + sizeof BisHandleBuffer) + ); + + return NULL; + } + + DEBUG ((EFI_D_INFO, "BIS handle found.")); + + // + // Locate BIS protocol interface. + // If the BIS protocol interface cannot be found, return NULL. + // + DEBUG ((EFI_D_INFO, "\ngBS->HandleProtocol() ")); + + EfiStatus = gBS->HandleProtocol ( + BisHandleBuffer, + &gEfiBisProtocolGuid, + (VOID **) &BisPtr + ); + + if (EFI_ERROR (EfiStatus)) { + DEBUG ( + (EFI_D_WARN, + "\nPxebcBisStart()""\n gBS->HandleProtocol() %r (%xh)\n", + EfiStatus, + EfiStatus) + ); + + return NULL; + } + + if (BisPtr == NULL) { + // + // This really should never happen. + // + DEBUG ( + (EFI_D_NET, + "\nPxebcBisStart()""\n gBS->HandleProtocoL() ""BIS protocol interface pointer is NULL!\n") + ); + + return NULL; + } + + DEBUG ((EFI_D_INFO, "BIS protocol interface found.")); + + // + // Check that all of the BIS API function pointers are not NULL. + // + if (BisPtr->Initialize == NULL || + BisPtr->Shutdown == NULL || + BisPtr->Free == NULL || + BisPtr->GetBootObjectAuthorizationCertificate == NULL || + BisPtr->GetBootObjectAuthorizationCheckFlag == NULL || + BisPtr->GetBootObjectAuthorizationUpdateToken == NULL || + BisPtr->GetSignatureInfo == NULL || + BisPtr->UpdateBootObjectAuthorization == NULL || + BisPtr->VerifyBootObject == NULL || + BisPtr->VerifyObjectWithCredential == NULL + ) { + DEBUG ( + ( + EFI_D_NET, + "\nPxebcBisStart()""\n BIS protocol interface is invalid." + "\n At least one BIS protocol function pointer is NULL.\n" + ) + ); + + return NULL; + } + // + // Initialize BIS. + // If BIS does not initialize, return NULL. + // + DEBUG ((EFI_D_INFO, "\nBisPtr->Initialize() ")); + + BisInterfaceVersion.Major = BIS_VERSION_1; + + EfiStatus = BisPtr->Initialize ( + BisPtr, + BisAppHandle, + &BisInterfaceVersion, + NULL + ); + + if (EFI_ERROR (EfiStatus)) { + DEBUG ( + (EFI_D_WARN, + "\nPxebcBisStart()""\n BisPtr->Initialize() %r (%xh)\n", + EfiStatus, + EfiStatus) + ); + + return NULL; + } + + DEBUG ( + (EFI_D_INFO, + " BIS version: %d.%d", + BisInterfaceVersion.Major, + BisInterfaceVersion.Minor) + ); + + // + // If the requested BIS API version is not supported, + // shutdown BIS and return NULL. + // + if (BisInterfaceVersion.Major != BIS_VERSION_1) { + DEBUG ( + (EFI_D_WARN, + "\nPxebcBisStart()""\n BIS version %d.%d not supported by PXE BaseCode.\n", + BisInterfaceVersion.Major, + BisInterfaceVersion.Minor) + ); + + BisPtr->Shutdown (*BisAppHandle); + return NULL; + } + // + // Get BIS check flag. + // If the BIS check flag cannot be read, shutdown BIS and return NULL. + // + DEBUG ((EFI_D_INFO, "\nBisPtr->GetBootObjectAuthorizationCheckFlag() ")); + + EfiStatus = BisPtr->GetBootObjectAuthorizationCheckFlag (*BisAppHandle, &BisCheckFlag); + + if (EFI_ERROR (EfiStatus)) { + DEBUG ( + (EFI_D_WARN, + "\nPxebcBisStart()""\n BisPtr->GetBootObjectAuthorizationCheckFlag() %r (%xh)\n", + EfiStatus, + EfiStatus) + ); + + BisPtr->Shutdown (*BisAppHandle); + return NULL; + } + // + // If the BIS check flag is FALSE, shutdown BIS and return NULL. + // + if (!BisCheckFlag) { + DEBUG ((EFI_D_INFO, "\nBIS check flag is FALSE.\n")); + BisPtr->Shutdown (*BisAppHandle); + return NULL; + } else { + DEBUG ((EFI_D_INFO, "\nBIS check flag is TRUE.")); + } + // + // Early out if caller does not want signature information. + // + if (BisDataSigInfo == NULL) { + return BisPtr; + } + // + // Get BIS signature information. + // If the signature information cannot be read or is invalid, + // shutdown BIS and return NULL. + // + DEBUG ((EFI_D_INFO, "\nBisPtr->GetSignatureInfo() ")); + + EfiStatus = BisPtr->GetSignatureInfo (*BisAppHandle, BisDataSigInfo); + + if (EFI_ERROR (EfiStatus)) { + DEBUG ( + (EFI_D_WARN, + "\nPxebcBisStart()""\n BisPtr_GetSignatureInfo() %r (%xh)\n", + EfiStatus, + EfiStatus) + ); + + BisPtr->Shutdown (*BisAppHandle); + return NULL; + } + + if (*BisDataSigInfo == NULL) { + // + // This should never happen. + // + DEBUG ( + (EFI_D_NET, + "\nPxebcBisStart()""\n BisPtr->GetSignatureInfo() Data pointer is NULL!\n") + ); + + BisPtr->Shutdown (*BisAppHandle); + return NULL; + } + + if ((*BisDataSigInfo)->Length < sizeof (EFI_BIS_SIGNATURE_INFO) || + (*BisDataSigInfo)->Length % sizeof (EFI_BIS_SIGNATURE_INFO) || + (*BisDataSigInfo)->Length > sizeof (EFI_BIS_SIGNATURE_INFO) * 63 + ) { + // + // This should never happen. + // + DEBUG ( + (EFI_D_NET, + "\nPxebcBisStart()""\n BisPtr->GetSignatureInfo() Invalid BIS siginfo length.\n") + ); + + BisPtr->Free (*BisAppHandle, *BisDataSigInfo); + BisPtr->Shutdown (*BisAppHandle); + return NULL; + } + + return BisPtr; +} + +VOID +PxebcBisStop ( + EFI_BIS_PROTOCOL *BisPtr, + BIS_APPLICATION_HANDLE BisAppHandle, + EFI_BIS_DATA *BisDataSigInfo + ) +/*++ +Routine description: + Stop the BIS interface and release allocations. + +Parameters: + BisPtr := Pointer to BIS interface + BisAppHandle := BIS application handle + BisDataSigInfo := Pointer to BIS signature information data + +Returns: + +--*/ +{ + if (BisPtr == NULL) { + return ; + } + // + // Free BIS allocated resources and shutdown BIS. + // Return TRUE - BIS support is officially detected. + // + if (BisDataSigInfo != NULL) { + BisPtr->Free (BisAppHandle, BisDataSigInfo); + } + + BisPtr->Shutdown (BisAppHandle); +} + +BOOLEAN +PxebcBisVerify ( + PXE_BASECODE_DEVICE *Private, + VOID *FileBuffer, + UINTN FileLength, + VOID *CredentialBuffer, + UINTN CredentialLength + ) +/*++ +Routine description: + Verify image and credential file. + +Parameters: + Private := Pointer to PxeBc interface + FileBuffer := Pointer to image buffer + FileLength := Image length in bytes + CredentialBuffer := Pointer to credential buffer + CredentialLength := Credential length in bytes + +Returns: + TRUE := verified + FALSE := not verified +--*/ +{ + EFI_BIS_PROTOCOL *BisPtr; + BIS_APPLICATION_HANDLE BisAppHandle; + EFI_BIS_DATA FileData; + EFI_BIS_DATA CredentialData; + EFI_STATUS EfiStatus; + BOOLEAN IsVerified; + + if (Private == NULL || FileBuffer == NULL || FileLength == 0 || CredentialBuffer == NULL || CredentialLength == 0) { + return FALSE; + } + + BisPtr = PxebcBisStart (Private, &BisAppHandle, NULL); + + if (BisPtr == NULL) { + return FALSE; + } + + FileData.Length = (UINT32) FileLength; + FileData.Data = FileBuffer; + CredentialData.Length = (UINT32) CredentialLength; + CredentialData.Data = CredentialBuffer; + + EfiStatus = BisPtr->VerifyBootObject ( + BisAppHandle, + &CredentialData, + &FileData, + &IsVerified + ); + + PxebcBisStop (BisPtr, BisAppHandle, NULL); + + return (BOOLEAN) ((EFI_ERROR (EfiStatus)) ? FALSE : (IsVerified ? TRUE : FALSE)); +} + +BOOLEAN +PxebcBisDetect ( + PXE_BASECODE_DEVICE *Private + ) +/*++ +Routine description: + Check for BIS interface presence. + +Parameters: + Private := Pointer to PxeBc interface + +Returns: + TRUE := BIS present + FALSE := BIS not present +--*/ +{ + EFI_BIS_PROTOCOL *BisPtr; + BIS_APPLICATION_HANDLE BisAppHandle; + EFI_BIS_DATA *BisDataSigInfo; + + BisPtr = PxebcBisStart (Private, &BisAppHandle, &BisDataSigInfo); + + if (BisPtr == NULL) { + return FALSE; + } + + PxebcBisStop (BisPtr, BisAppHandle, BisDataSigInfo); + + return TRUE; +} + +VOID *BCNotifyReg; + +EFI_STATUS +EFIAPI +BcStart ( + IN EFI_PXE_BASE_CODE_PROTOCOL *This, + IN BOOLEAN UseIPv6 + ) +/*++ + + Routine Description: + Start and initialize the BaseCode protocol, Simple Network protocol and UNDI. + + Arguments: + Private - Pointer to Pxe BaseCode Protocol + UseIPv6 - Do we want to support IPv6? + + Returns: + EFI_SUCCESS + EFI_INVALID_PARAMETER + EFI_UNSUPPORTED + EFI_ALREADY_STARTED + EFI_OUT_OF_RESOURCES + Status is also returned from SNP.Start() and SNP.Initialize(). + +--*/ +{ + EFI_SIMPLE_NETWORK_PROTOCOL *SnpPtr; + EFI_SIMPLE_NETWORK_MODE *SnpModePtr; + EFI_STATUS Status; + EFI_STATUS StatCode; + PXE_BASECODE_DEVICE *Private; + + // + // Lock the instance data + // + StatCode = EFI_SUCCESS; + + if (This == NULL) { + DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL")); + return EFI_INVALID_PARAMETER; + } + + Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE); + + if (Private == NULL) { + DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE pointer == NULL")); + return EFI_INVALID_PARAMETER; + } + + EfiAcquireLock (&Private->Lock); + + // + // Make sure BaseCode is not already started. + // + if (This->Mode->Started) { + DEBUG ((EFI_D_WARN, "\nBcStart() BC is already started.\n")); + EfiReleaseLock (&Private->Lock); + return EFI_ALREADY_STARTED; + } + +#if !SUPPORT_IPV6 + // + // Fail if IPv6 is requested and not supported. + // + if (UseIPv6) { + DEBUG ((EFI_D_WARN, "\nBcStart() IPv6 is not supported.\n")); + EfiReleaseLock (&Private->Lock); + return EFI_UNSUPPORTED; + } +#endif + // + // Setup shortcuts to SNP protocol and data structure. + // + SnpPtr = Private->SimpleNetwork; + SnpModePtr = SnpPtr->Mode; + + // + // Start and initialize SNP. + // + if (SnpModePtr->State == EfiSimpleNetworkStopped) { + StatCode = (*SnpPtr->Start) (SnpPtr); + + if (SnpModePtr->State != EfiSimpleNetworkStarted) { + DEBUG ((EFI_D_WARN, "\nBcStart() Could not start SNP.\n")); + EfiReleaseLock (&Private->Lock); + return StatCode; + } + } + // + // acquire memory for mode and transmit/receive buffers + // + if (SnpModePtr->State == EfiSimpleNetworkStarted) { + StatCode = (*SnpPtr->Initialize) (SnpPtr, 0, 0); + + if (SnpModePtr->State != EfiSimpleNetworkInitialized) { + DEBUG ((EFI_D_WARN, "\nBcStart() Could not initialize SNP.")); + EfiReleaseLock (&Private->Lock); + return StatCode; + } + } + // + // Dump debug info. + // + DEBUG ((EFI_D_INFO, "\nBC Start()")); + DEBUG ( + (EFI_D_INFO, + "\nSnpModePtr->State %Xh", + SnpModePtr->State) + ); + DEBUG ( + (EFI_D_INFO, + "\nSnpModePtr->HwAddressSize %Xh", + SnpModePtr->HwAddressSize) + ); + DEBUG ( + (EFI_D_INFO, + "\nSnpModePtr->MediaHeaderSize %Xh", + SnpModePtr->MediaHeaderSize) + ); + DEBUG ( + (EFI_D_INFO, + "\nSnpModePtr->MaxPacketSize %Xh", + SnpModePtr->MaxPacketSize) + ); + DEBUG ( + (EFI_D_INFO, + "\nSnpModePtr->MacAddressChangeable %Xh", + SnpModePtr->MacAddressChangeable) + ); + DEBUG ( + (EFI_D_INFO, + "\nSnpModePtr->MultipleTxSupported %Xh", + SnpModePtr->MultipleTxSupported) + ); + DEBUG ( + (EFI_D_INFO, + "\nSnpModePtr->CurrentAddress %Xh", + *((UINTN *)&SnpModePtr->CurrentAddress)) + ); + DEBUG ( + (EFI_D_INFO, + "\nSnpModePtr->BroadcastAddress %Xh", + *((UINTN *)&SnpModePtr->BroadcastAddress)) + ); + DEBUG ( + (EFI_D_INFO, + "\nSnpModePtr->PermanentAddress %Xh", + *((UINTN *)&SnpModePtr->PermanentAddress)) + ); + DEBUG ( + (EFI_D_INFO, + "\nSnpModePtr->NvRamSize %Xh", + SnpModePtr->NvRamSize) + ); + DEBUG ( + (EFI_D_INFO, + "\nSnpModePtr->NvRamAccessSize %Xh", + SnpModePtr->NvRamAccessSize) + ); + DEBUG ( + (EFI_D_INFO, + "\nSnpModePtr->ReceiveFilterMask %Xh", + SnpModePtr->ReceiveFilterMask) + ); + DEBUG ( + (EFI_D_INFO, + "\nSnpModePtr->ReceiveFilterSetting %Xh", + SnpModePtr->ReceiveFilterSetting) + ); + DEBUG ( + (EFI_D_INFO, + "\nSnpModePtr->MCastFilterCount %Xh", + SnpModePtr->MCastFilterCount) + ); + DEBUG ( + (EFI_D_INFO, + "\nSnpModePtr->MCastFilter %Xh", + SnpModePtr->MCastFilter) + ); + DEBUG ( + (EFI_D_INFO, + "\nSnpModePtr->IfType %Xh", + SnpModePtr->IfType) + ); + DEBUG ( + (EFI_D_INFO, + "\nSnpModePtr->MediaPresentSupported %Xh", + SnpModePtr->MediaPresentSupported) + ); + DEBUG ( + (EFI_D_INFO, + "\nSnpModePtr->MediaPresent %Xh", + SnpModePtr->MediaPresent) + ); + + // + // If media check is supported and there is no media, + // return error to caller. + // + if (SnpModePtr->MediaPresentSupported && !SnpModePtr->MediaPresent) { + DEBUG ((EFI_D_WARN, "\nBcStart() Media not present.\n")); + EfiReleaseLock (&Private->Lock); + return EFI_NO_MEDIA; + } + // + // Allocate Tx/Rx buffers + // + Status = gBS->AllocatePool ( + EfiBootServicesData, + BUFFER_ALLOCATE_SIZE, + (VOID **) &Private->TransmitBufferPtr + ); + + if (!EFI_ERROR (Status)) { + ZeroMem (Private->TransmitBufferPtr, BUFFER_ALLOCATE_SIZE); + } else { + DEBUG ((EFI_D_NET, "\nBcStart() Could not alloc TxBuf.\n")); + EfiReleaseLock (&Private->Lock); + return EFI_OUT_OF_RESOURCES; + } + + Status = gBS->AllocatePool ( + EfiBootServicesData, + BUFFER_ALLOCATE_SIZE, + (VOID **) &Private->ReceiveBufferPtr + ); + + if (!EFI_ERROR (Status)) { + ZeroMem (Private->ReceiveBufferPtr, BUFFER_ALLOCATE_SIZE); + } else { + DEBUG ((EFI_D_NET, "\nBcStart() Could not alloc RxBuf.\n")); + gBS->FreePool (Private->TransmitBufferPtr); + EfiReleaseLock (&Private->Lock); + return EFI_OUT_OF_RESOURCES; + } + + Status = gBS->AllocatePool ( + EfiBootServicesData, + 256, + (VOID **) &Private->TftpErrorBuffer + ); + + if (EFI_ERROR (Status)) { + gBS->FreePool (Private->ReceiveBufferPtr); + gBS->FreePool (Private->TransmitBufferPtr); + EfiReleaseLock (&Private->Lock); + return EFI_OUT_OF_RESOURCES; + } + + Status = gBS->AllocatePool (EfiBootServicesData, 256, (VOID **) &Private->TftpAckBuffer); + + if (EFI_ERROR (Status)) { + gBS->FreePool (Private->TftpErrorBuffer); + gBS->FreePool (Private->ReceiveBufferPtr); + gBS->FreePool (Private->TransmitBufferPtr); + EfiReleaseLock (&Private->Lock); + return EFI_OUT_OF_RESOURCES; + } + // + // Initialize private BaseCode instance data + // + do { + Private->RandomPort = (UINT16) (Private->RandomPort + PXE_RND_PORT_LOW + Random (Private)); + } while (Private->RandomPort < PXE_RND_PORT_LOW); + + Private->Igmpv1TimeoutEvent = NULL; + Private->UseIgmpv1Reporting = TRUE; + Private->IpLength = IP_ADDRESS_LENGTH (Private->EfiBc.Mode); + + // + // Initialize Mode structure + // + // + // check for callback protocol and set boolean + // + SetMakeCallback (Private); + Private->EfiBc.Mode->Started = TRUE; + Private->EfiBc.Mode->TTL = DEFAULT_TTL; + Private->EfiBc.Mode->ToS = DEFAULT_ToS; + Private->EfiBc.Mode->UsingIpv6 = UseIPv6; + Private->EfiBc.Mode->DhcpDiscoverValid = FALSE; + Private->EfiBc.Mode->DhcpAckReceived = FALSE; + Private->EfiBc.Mode->ProxyOfferReceived = FALSE; + Private->EfiBc.Mode->PxeDiscoverValid = FALSE; + Private->EfiBc.Mode->PxeReplyReceived = FALSE; + Private->EfiBc.Mode->PxeBisReplyReceived = FALSE; + Private->EfiBc.Mode->IcmpErrorReceived = FALSE; + Private->EfiBc.Mode->TftpErrorReceived = FALSE; + ZeroMem (&Private->EfiBc.Mode->StationIp, sizeof (EFI_IP_ADDRESS)); + ZeroMem (&Private->EfiBc.Mode->SubnetMask, sizeof (EFI_IP_ADDRESS)); + Private->EfiBc.Mode->IpFilter.Filters = 0; + Private->EfiBc.Mode->IpFilter.IpCnt = 0; + Private->EfiBc.Mode->ArpCacheEntries = 0; + Private->EfiBc.Mode->RouteTableEntries = 0; + ZeroMem (&Private->EfiBc.Mode->IcmpError, sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)); + ZeroMem (&Private->EfiBc.Mode->TftpError, sizeof (EFI_PXE_BASE_CODE_TFTP_ERROR)); + + // + // Set to PXE_TRUE by the BC constructor if this BC implementation + // supports IPv6. + // + Private->EfiBc.Mode->Ipv6Supported = SUPPORT_IPV6; + +#if SUPPORT_IPV6 + Private->EfiBc.Mode->Ipv6Available = Private->NiiPtr->Ipv6Supported; +#else + Private->EfiBc.Mode->Ipv6Available = FALSE; +#endif + // + // Set to TRUE by the BC constructor if this BC implementation + // supports BIS. + // + Private->EfiBc.Mode->BisSupported = TRUE; + Private->EfiBc.Mode->BisDetected = PxebcBisDetect (Private); + + // + // This field is set to PXE_TRUE by the BC Start() function. When this + // field is PXE_TRUE, ARP packets are sent as needed to get IP and MAC + // addresses. This can cause unexpected delays in the DHCP(), Discover() + // and MTFTP() functions. Setting this to PXE_FALSE will cause these + // functions to fail if the required IP/MAC information is not in the + // ARP cache. The value of this field can be changed by an application + // at any time. + // + Private->EfiBc.Mode->AutoArp = TRUE; + + // + // Unlock the instance data + // + EfiReleaseLock (&Private->Lock); + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +BcStop ( + IN EFI_PXE_BASE_CODE_PROTOCOL *This + ) +/*++ + + Routine Description: + Stop the BaseCode protocol, Simple Network protocol and UNDI. + + Arguments: + Private - Pointer to Pxe BaseCode Protocol + + Returns: + + 0 - Successfully stopped + !0 - Failed +--*/ +{ + // + // Lock the instance data + // + EFI_PXE_BASE_CODE_MODE *PxebcMode; + EFI_SIMPLE_NETWORK_PROTOCOL *SnpPtr; + EFI_SIMPLE_NETWORK_MODE *SnpModePtr; + EFI_STATUS StatCode; + PXE_BASECODE_DEVICE *Private; + + StatCode = EFI_SUCCESS; + + if (This == NULL) { + DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL")); + return EFI_INVALID_PARAMETER; + } + + Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE); + + if (Private == NULL) { + DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL")); + return EFI_INVALID_PARAMETER; + } + + EfiAcquireLock (&Private->Lock); + + PxebcMode = Private->EfiBc.Mode; + SnpPtr = Private->SimpleNetwork; + SnpModePtr = SnpPtr->Mode; + + // + // Issue BC command + // + StatCode = EFI_NOT_STARTED; + + if (SnpModePtr->State == EfiSimpleNetworkInitialized) { + StatCode = (*SnpPtr->Shutdown) (SnpPtr); + } + + if (SnpModePtr->State == EfiSimpleNetworkStarted) { + StatCode = (*SnpPtr->Stop) (SnpPtr); + } + + if (Private->TransmitBufferPtr != NULL) { + gBS->FreePool (Private->TransmitBufferPtr); + Private->TransmitBufferPtr = NULL; + } + + if (Private->ReceiveBufferPtr != NULL) { + gBS->FreePool (Private->ReceiveBufferPtr); + Private->ReceiveBufferPtr = NULL; + } + + if (Private->ArpBuffer != NULL) { + gBS->FreePool (Private->ArpBuffer); + Private->ArpBuffer = NULL; + } + + if (Private->TftpErrorBuffer != NULL) { + gBS->FreePool (Private->TftpErrorBuffer); + Private->TftpErrorBuffer = NULL; + } + + if (Private->TftpAckBuffer != NULL) { + gBS->FreePool (Private->TftpAckBuffer); + Private->TftpAckBuffer = NULL; + } + + if (Private->Igmpv1TimeoutEvent != NULL) { + gBS->CloseEvent (Private->Igmpv1TimeoutEvent); + Private->Igmpv1TimeoutEvent = NULL; + } + + Private->FileSize = 0; + Private->EfiBc.Mode->Started = FALSE; + + // + // Unlock the instance data + // + EfiReleaseLock (&Private->Lock); + return StatCode; +} + +const IPV4_ADDR AllSystemsGroup = { { 224, 0, 0, 1 } }; + +EFI_STATUS +IpFilter ( + IN PXE_BASECODE_DEVICE *Private, + IN EFI_PXE_BASE_CODE_IP_FILTER *Filter + ) +/*++ + + Routine Description: + Set up the IP filter + + Arguments: + Private - Pointer to Pxe BaseCode Protocol + Filter - Pointer to the filter + + Returns: + + 0 - Successfully set the filter + !0 - Failed +--*/ +{ + EFI_STATUS StatCode; + EFI_MAC_ADDRESS MACadds[PXE_IP_FILTER_SIZE]; + EFI_PXE_BASE_CODE_MODE *PxebcMode; + EFI_SIMPLE_NETWORK_PROTOCOL *SnpPtr; + EFI_SIMPLE_NETWORK_MODE *SnpModePtr; + UINT32 Enable; + UINT32 Disable; + UINTN Index; + UINTN Index2; + + PxebcMode = Private->EfiBc.Mode; + SnpPtr = Private->SimpleNetwork; + SnpModePtr = SnpPtr->Mode; + + // + // validate input parameters + // must have a filter + // must not have any extra filter bits set + // + if (Filter == NULL || + (Filter->Filters &~FILTER_BITS) + // + // must not have a count which is too large or with no IP list + // + || + (Filter->IpCnt && (!Filter->IpList || Filter->IpCnt > PXE_IP_FILTER_SIZE)) + // + // must not have incompatible filters - promiscuous incompatible with anything else + // + || + ( + (Filter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) && + ((Filter->Filters &~EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) || Filter->IpCnt) + ) + ) { + DEBUG ((EFI_D_INFO, "\nIpFilter() Exit #1")); + return EFI_INVALID_PARAMETER; + } + // + // promiscuous multicast incompatible with multicast in IP list + // + if (Filter->IpCnt && (Filter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST)) { + for (Index = 0; Index < Filter->IpCnt; ++Index) { + if (IS_MULTICAST (&Filter->IpList[Index])) { + DEBUG ((EFI_D_INFO, "\nIpFilter() Exit #2")); + return EFI_INVALID_PARAMETER; + } + } + } + // + // leave groups for all those multicast which are no longer enabled + // + for (Index = 0; Index < PxebcMode->IpFilter.IpCnt; ++Index) { + if (!IS_MULTICAST (&PxebcMode->IpFilter.IpList[Index])) { + continue; + } + + for (Index2 = 0; Index2 < Filter->IpCnt; ++Index2) { + if (!CompareMem (&PxebcMode->IpFilter.IpList[Index], &Filter->IpList[Index2], IP_ADDRESS_LENGTH (PxebcMode))) { + // + // still enabled + // + break; + } + } + // + // if we didn't find it, remove from group + // + if (Index2 == Filter->IpCnt) { + IgmpLeaveGroup (Private, &PxebcMode->IpFilter.IpList[Index]); + } + } + // + // set enable bits, convert multicast ip adds, join groups + // allways leave receive broadcast enabled at hardware layer + // + Index2 = 0; + + if (Filter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) { + Enable = EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS; + } else { + if (Filter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST) { + Enable = EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST; + } else { + Enable = EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST; + + for (Index = 0; Index < Filter->IpCnt; ++Index) { + CopyMem (&(PxebcMode->IpFilter.IpList[Index]), &(Filter->IpList[Index]), sizeof (EFI_IP_ADDRESS)); + + if (IS_MULTICAST (&Filter->IpList[Index])) { + EFI_IP_ADDRESS *TmpIp; + + Enable |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST; + + // + // if this is the first group, add the all systems group to mcast list + // + if (!Index2) + { +#if SUPPORT_IPV6 + if (PxebcMode->UsingIpv6) { + // + // TBD + // + } else +#endif + TmpIp = (EFI_IP_ADDRESS *) &AllSystemsGroup; + --Index; + } else { + TmpIp = (EFI_IP_ADDRESS *) &Filter->IpList[Index]; + } + // + // get MAC address of IP + // + StatCode = (*SnpPtr->MCastIpToMac) (SnpPtr, PxebcMode->UsingIpv6, TmpIp, &MACadds[Index2++]); + + if (EFI_ERROR (StatCode)) { + DEBUG ( + (EFI_D_INFO, + "\nIpFilter() Exit #2 %Xh (%r)", + StatCode, + StatCode) + ); + return StatCode; + } + } else { + Enable |= EFI_SIMPLE_NETWORK_RECEIVE_UNICAST; + } + } + } + + if (Filter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) { + Enable |= EFI_SIMPLE_NETWORK_RECEIVE_UNICAST; + } + } + // + // if nothing changed, just return + // + DEBUG ( + (EFI_D_INFO, + "\nsnp->ReceiveFilterSetting == %Xh Filter->IpCnt == %Xh", + SnpModePtr->ReceiveFilterSetting, + Filter->IpCnt) + ); + + if (SnpModePtr->ReceiveFilterSetting == Enable && !Filter->IpCnt) { + DEBUG ((EFI_D_INFO, "\nIpFilter() Exit #4")); + return EFI_SUCCESS; + } + // + // disable those currently set but not set in new filter + // + Disable = SnpModePtr->ReceiveFilterSetting &~Enable; + + StatCode = SnpPtr->ReceiveFilters (SnpPtr, Enable, Disable, FALSE, Index2, MACadds); + + PxebcMode->IpFilter.IpCnt = Filter->IpCnt; + + // + // join groups for all multicast in list + // + for (Index = 0; Index < Filter->IpCnt; ++Index) { + if (IS_MULTICAST (&Filter->IpList[Index])) { + IgmpJoinGroup (Private, &Filter->IpList[Index]); + } + } + + DEBUG ((EFI_D_INFO, "\nIpFilter() Exit #5 %Xh (%r)", StatCode, StatCode)); + + return StatCode; +} + +EFI_STATUS +EFIAPI +BcIpFilter ( + IN EFI_PXE_BASE_CODE_PROTOCOL *This, + IN EFI_PXE_BASE_CODE_IP_FILTER *Filter + ) +/*++ + + Routine Description: + Call the IP filter + + Arguments: + Private - Pointer to Pxe BaseCode Protocol + Filter - Pointer to the filter + + Returns: + + 0 - Successfully set the filter + !0 - Failed +--*/ +{ + EFI_STATUS StatCode; + PXE_BASECODE_DEVICE *Private; + + // + // Lock the instance data and make sure started + // + StatCode = EFI_SUCCESS; + + if (This == NULL) { + DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL")); + return EFI_INVALID_PARAMETER; + } + + Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE); + + if (Private == NULL) { + DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL")); + return EFI_INVALID_PARAMETER; + } + + EfiAcquireLock (&Private->Lock); + + if (This->Mode == NULL || !This->Mode->Started) { + DEBUG ((EFI_D_ERROR, "BC was not started.")); + EfiReleaseLock (&Private->Lock); + return EFI_NOT_STARTED; + } + + if (Filter == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Issue BC command + // + StatCode = IpFilter (Private, Filter); + + // + // Unlock the instance data + // + EfiReleaseLock (&Private->Lock); + return StatCode; +} + +EFI_STATUS +EFIAPI +BcSetParameters ( + EFI_PXE_BASE_CODE_PROTOCOL *This, + BOOLEAN *AutoArpPtr, + BOOLEAN *SendGuidPtr, + UINT8 *TimeToLivePtr, + UINT8 *TypeOfServicePtr, + BOOLEAN *MakeCallbackPtr + ) +/*++ + + Routine Description: + Set the Base Code behavior parameters + + Arguments: + This - Pointer to Pxe BaseCode Protocol + AutoArpPtr - Boolean to do ARP stuff + SendGuidPtr - Boolean whether or not to send GUID info + TimeToLivePtr - Value for Total time to live + TypeOfServicePtr - Value for Type of Service + MakeCallbackPtr - Boolean to determine if we make callbacks + + Returns: + + 0 - Successfully set the parameters + !0 - Failed +--*/ +{ + EFI_PXE_BASE_CODE_MODE *PxebcMode; + EFI_GUID TmpGuid; + CHAR8 *SerialNumberPtr; + EFI_STATUS StatCode; + PXE_BASECODE_DEVICE *Private; + + // + // Lock the instance data and make sure started + // + StatCode = EFI_SUCCESS; + + if (This == NULL) { + DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL")); + return EFI_INVALID_PARAMETER; + } + + Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE); + + if (Private == NULL) { + DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL")); + return EFI_INVALID_PARAMETER; + } + + EfiAcquireLock (&Private->Lock); + + if (This->Mode == NULL || !This->Mode->Started) { + DEBUG ((EFI_D_ERROR, "BC was not started.")); + EfiReleaseLock (&Private->Lock); + return EFI_NOT_STARTED; + } + + DEBUG ((EFI_D_INFO, "\nSetParameters() Entry. ")); + + PxebcMode = Private->EfiBc.Mode; + StatCode = EFI_SUCCESS; + + if (SendGuidPtr != NULL) { + if (*SendGuidPtr) { + if (PxeBcLibGetSmbiosSystemGuidAndSerialNumber (&TmpGuid, &SerialNumberPtr) != EFI_SUCCESS) { + return EFI_INVALID_PARAMETER; + } + } + } + + if (MakeCallbackPtr != NULL) { + if (*MakeCallbackPtr) { + if (!SetMakeCallback (Private)) { + return EFI_INVALID_PARAMETER; + } + } + + PxebcMode->MakeCallbacks = *MakeCallbackPtr; + } + + if (AutoArpPtr != NULL) { + PxebcMode->AutoArp = *AutoArpPtr; + } + + if (SendGuidPtr != NULL) { + PxebcMode->SendGUID = *SendGuidPtr; + } + + if (TimeToLivePtr != NULL) { + PxebcMode->TTL = *TimeToLivePtr; + } + + if (TypeOfServicePtr != NULL) { + PxebcMode->ToS = *TypeOfServicePtr; + } + // + // Unlock the instance data + // + DEBUG ((EFI_D_INFO, "\nSetparameters() Exit = %xh ", StatCode)); + + EfiReleaseLock (&Private->Lock); + return StatCode; +} +// +// ////////////////////////////////////////////////////////// +// +// BC Set Station IP Routine +// +EFI_STATUS +EFIAPI +BcSetStationIP ( + IN EFI_PXE_BASE_CODE_PROTOCOL *This, + IN EFI_IP_ADDRESS *StationIpPtr, + IN EFI_IP_ADDRESS *SubnetMaskPtr + ) +/*++ + + Routine Description: + Set the station IP address + + Arguments: + This - Pointer to Pxe BaseCode Protocol + StationIpPtr - Pointer to the requested IP address to set in base code + SubnetMaskPtr - Pointer to the requested subnet mask for the base code + + Returns: + + EFI_SUCCESS - Successfully set the parameters + EFI_NOT_STARTED - BC has not started +--*/ +{ + EFI_PXE_BASE_CODE_MODE *PxebcMode; + EFI_STATUS StatCode; + PXE_BASECODE_DEVICE *Private; + + // + // Lock the instance data and make sure started + // + StatCode = EFI_SUCCESS; + + if (This == NULL) { + DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL")); + return EFI_INVALID_PARAMETER; + } + + Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE); + + if (Private == NULL) { + DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL")); + return EFI_INVALID_PARAMETER; + } + + EfiAcquireLock (&Private->Lock); + + if (This->Mode == NULL || !This->Mode->Started) { + DEBUG ((EFI_D_ERROR, "BC was not started.")); + EfiReleaseLock (&Private->Lock); + return EFI_NOT_STARTED; + } + + PxebcMode = Private->EfiBc.Mode; + + if (StationIpPtr != NULL) { + CopyMem (&PxebcMode->StationIp, StationIpPtr, sizeof (EFI_IP_ADDRESS)); + Private->GoodStationIp = TRUE; + } + + if (SubnetMaskPtr != NULL) { + CopyMem (&PxebcMode->SubnetMask, SubnetMaskPtr, sizeof (EFI_IP_ADDRESS)); + } + // + // Unlock the instance data + // + EfiReleaseLock (&Private->Lock); + + return EFI_SUCCESS; +} + +EFI_DRIVER_BINDING_PROTOCOL gPxeBcDriverBinding = { + PxeBcDriverSupported, + PxeBcDriverStart, + PxeBcDriverStop, + 0x10, + NULL, + NULL +}; + +EFI_STATUS +EFIAPI +PxeBcDriverSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + Test to see if this driver supports Controller. Any Controller + than contains a Snp protocol can be supported. + + Arguments: + This - Protocol instance pointer. + Controller - Handle of device to test. + RemainingDevicePath - Not used. + + Returns: + EFI_SUCCESS - This driver supports this device. + EFI_ALREADY_STARTED - This driver is already running on this device. + other - This driver does not support this device. + +--*/ +{ + EFI_STATUS Status; + EFI_SIMPLE_NETWORK_PROTOCOL *SnpPtr; + + Status = gBS->OpenProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + NULL, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->OpenProtocol ( + Controller, + &gEfiSimpleNetworkProtocolGuid, + (VOID **) &SnpPtr, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + gBS->CloseProtocol ( + Controller, + &gEfiSimpleNetworkProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return Status; +} + +EFI_STATUS +EFIAPI +PxeBcDriverStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + Start the Base code driver. + + Arguments: + This - Protocol instance pointer. + Controller - Handle of device to test. + RemainingDevicePath - Not used. + + Returns: + EFI_SUCCESS - This driver supports this device. + EFI_ALREADY_STARTED - This driver is already running on this device. + other - This driver does not support this device. + +--*/ +{ + EFI_STATUS Status; + PXE_BASECODE_DEVICE *Private; + LOADFILE_DEVICE *pLF; + + // + // Allocate structures needed by BaseCode and LoadFile protocols. + // + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (PXE_BASECODE_DEVICE), + (VOID **) &Private + ); + + if (!EFI_ERROR (Status)) { + ZeroMem (Private, sizeof (PXE_BASECODE_DEVICE)); + } else { + DEBUG ((EFI_D_NET, "\nBcNotifySnp() Could not alloc PXE_BASECODE_DEVICE structure.\n")); + return Status; + } + + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (LOADFILE_DEVICE), + (VOID **) &pLF + ); + + if (!EFI_ERROR (Status)) { + ZeroMem (pLF, sizeof (LOADFILE_DEVICE)); + } else { + DEBUG ((EFI_D_NET, "\nBcNotifySnp() Could not alloc LOADFILE_DEVICE structure.\n")); + gBS->FreePool (Private); + return Status; + } + + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (EFI_PXE_BASE_CODE_MODE), + (VOID **) &Private->EfiBc.Mode + ); + + if (!EFI_ERROR (Status)) { + ZeroMem (Private->EfiBc.Mode, sizeof (EFI_PXE_BASE_CODE_MODE)); + } else { + DEBUG ((EFI_D_NET, "\nBcNotifySnp() Could not alloc Mode structure.\n")); + gBS->FreePool (Private); + gBS->FreePool (pLF); + return Status; + } + // + // Lock access, just in case + // + EfiInitializeLock (&Private->Lock, EFI_TPL_CALLBACK); + EfiAcquireLock (&Private->Lock); + + EfiInitializeLock (&pLF->Lock, EFI_TPL_CALLBACK); + EfiAcquireLock (&pLF->Lock); + + // + // Initialize PXE structure + // + // + // First initialize the internal 'private' data that the application + // does not see. + // + Private->Signature = PXE_BASECODE_DEVICE_SIGNATURE; + Private->Handle = Controller; + + // + // Get the NII interface + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiNetworkInterfaceIdentifierProtocolGuid_31, + (VOID **) &Private->NiiPtr, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + Status = gBS->OpenProtocol ( + Controller, + &gEfiNetworkInterfaceIdentifierProtocolGuid, + (VOID **) &Private->NiiPtr, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + goto PxeBcError; + } + } + // + // Get the Snp interface + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiSimpleNetworkProtocolGuid, + (VOID **) &Private->SimpleNetwork, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (Status)) { + goto PxeBcError; + } + + // + // Next, initialize the external 'public' data that + // the application does see. + // + Private->EfiBc.Revision = EFI_PXE_BASE_CODE_INTERFACE_REVISION; + Private->EfiBc.Start = BcStart; + Private->EfiBc.Stop = BcStop; + Private->EfiBc.Dhcp = BcDhcp; + Private->EfiBc.Discover = BcDiscover; + Private->EfiBc.Mtftp = BcMtftp; + Private->EfiBc.UdpWrite = BcUdpWrite; + Private->EfiBc.UdpRead = BcUdpRead; + Private->EfiBc.Arp = BcArp; + Private->EfiBc.SetIpFilter = BcIpFilter; + Private->EfiBc.SetParameters = BcSetParameters; + Private->EfiBc.SetStationIp = BcSetStationIP; + Private->EfiBc.SetPackets = BcSetPackets; + + // + // Initialize BaseCode Mode structure + // + Private->EfiBc.Mode->Started = FALSE; + Private->EfiBc.Mode->TTL = DEFAULT_TTL; + Private->EfiBc.Mode->ToS = DEFAULT_ToS; + Private->EfiBc.Mode->UsingIpv6 = FALSE; + Private->EfiBc.Mode->AutoArp = TRUE; + + // + // Set to PXE_TRUE by the BC constructor if this BC + // implementation supports IPv6. + // + Private->EfiBc.Mode->Ipv6Supported = SUPPORT_IPV6; + +#if SUPPORT_IPV6 + Private->EfiBc.Mode->Ipv6Available = Private->NiiPtr->Ipv6Supported; +#else + Private->EfiBc.Mode->Ipv6Available = FALSE; +#endif + // + // Set to TRUE by the BC constructor if this BC + // implementation supports BIS. + // + Private->EfiBc.Mode->BisSupported = TRUE; + Private->EfiBc.Mode->BisDetected = PxebcBisDetect (Private); + + // + // Initialize LoadFile structure. + // + pLF->Signature = LOADFILE_DEVICE_SIGNATURE; + pLF->LoadFile.LoadFile = LoadFile; + pLF->Private = Private; + + // + // Install protocol interfaces. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &Controller, + &gEfiPxeBaseCodeProtocolGuid, + &Private->EfiBc, + &gEfiLoadFileProtocolGuid, + &pLF->LoadFile, + NULL + ); + + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + Controller, + &gEfiSimpleNetworkProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + goto PxeBcError; + } + // + // Release locks. + // + EfiReleaseLock (&pLF->Lock); + EfiReleaseLock (&Private->Lock); + return Status; + +PxeBcError: ; + gBS->FreePool (Private->EfiBc.Mode); + gBS->FreePool (Private); + gBS->FreePool (pLF); + return Status; +} + +EFI_STATUS +EFIAPI +PxeBcDriverStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + + Routine Description: + Stop the Base code driver. + + Arguments: + This - Protocol instance pointer. + Controller - Handle of device to test. + NumberOfChildren - Not used + ChildHandleBuffer - Not used + + Returns: + EFI_SUCCESS - This driver supports this device. + EFI_ALREADY_STARTED - This driver is already running on this device. + other - This driver does not support this device. + +--*/ +{ + EFI_STATUS Status; + EFI_LOAD_FILE_PROTOCOL *LfProtocol; + LOADFILE_DEVICE *LoadDevice; + + // + // Get our context back. + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiLoadFileProtocolGuid, + (VOID **) &LfProtocol, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + LoadDevice = EFI_LOAD_FILE_DEV_FROM_THIS (LfProtocol); + + Status = gBS->UninstallMultipleProtocolInterfaces ( + Controller, + &gEfiLoadFileProtocolGuid, + &LoadDevice->LoadFile, + &gEfiPxeBaseCodeProtocolGuid, + &LoadDevice->Private->EfiBc, + NULL + ); + + if (!EFI_ERROR (Status)) { + + Status = gBS->CloseProtocol ( + Controller, + &gEfiSimpleNetworkProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + gBS->FreePool (LoadDevice->Private->EfiBc.Mode); + gBS->FreePool (LoadDevice->Private); + gBS->FreePool (LoadDevice); + } + + return Status; +} + +EFI_STATUS +EFIAPI +InitializeBCDriver ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + + Routine Description: + Initialize the base code drivers and install the driver binding + + Arguments: + Standard EFI Image Entry + + Returns: + EFI_SUCCESS - This driver was successfully bound + +--*/ +{ + InitArpHeader (); + OptionsStrucInit (); + + return EFI_SUCCESS; +} + +/* eof - bc.c */ diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/bc.h b/EdkModulePkg/Universal/Network/PxeBc/Dxe/bc.h new file mode 100644 index 0000000000..a391709c9e --- /dev/null +++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/bc.h @@ -0,0 +1,499 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + bc.h + +Abstract: + +--*/ + +#ifndef _BC_H +#define _BC_H + +#ifndef EFI_MIN +#define EFI_MIN(_a, _b) ((_a) < (_b) ? (_a) : (_b)) +#endif + +#define CALLBACK_INTERVAL 100 // ten times a second +#define FILTER_BITS (EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP | \ + EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST | \ + EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS | \ + EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST \ + ) + +#define WAIT_TX_TIMEOUT 1000 + +#define SUPPORT_IPV6 0 + +#define PXE_BASECODE_DEVICE_SIGNATURE EFI_SIGNATURE_32('p','x','e','d') + +// +// Determine the classes of IPv4 address +// +#define IS_CLASSA_IPADDR(x) ((((EFI_IP_ADDRESS*)x)->v4.Addr[0] & 0x80) == 0x00) +#define IS_CLASSB_IPADDR(x) ((((EFI_IP_ADDRESS*)x)->v4.Addr[0] & 0xc0) == 0x80) +#define IS_CLASSC_IPADDR(x) ((((EFI_IP_ADDRESS*)x)->v4.Addr[0] & 0xe0) == 0xc0) +#define IS_INADDR_UNICAST(x) ((IS_CLASSA_IPADDR(x) || IS_CLASSB_IPADDR(x) || IS_CLASSC_IPADDR(x)) && (((EFI_IP_ADDRESS*)x)->Addr[0] != 0) ) + +// +// Definitions for internet group management protocol version 2 message +// structure +// Per RFC 2236, November 1997 +// +#pragma pack(1) + +typedef struct { + UINT8 Type; + UINT8 MaxRespTime; // in tenths of a second + UINT16 Checksum; // ones complement of ones complement sum of + // 16 bit words of message + UINT32 GroupAddress; // for general query, all systems group, + // for group specific, the group +} IGMPV2_MESSAGE; + +#define IGMP_TYPE_QUERY 0x11 +#define IGMP_TYPE_REPORT 0x16 +#define IGMP_TYPE_V1REPORT 0x12 +#define IGMP_TYPE_LEAVE_GROUP 0x17 + +#define IGMP_DEFAULT_MAX_RESPONSE_TIME 10 // 10 second default +#pragma pack() + +#define MAX_MCAST_GROUPS 8 // most we allow ourselves to join at once +#define MAX_OFFERS 16 + +typedef struct { + UINTN Signature; + EFI_LOCK Lock; + BOOLEAN ShowErrorMessages; + EFI_PXE_BASE_CODE_PROTOCOL EfiBc; + EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL *CallbackProtocolPtr; + EFI_HANDLE Handle; + + EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NiiPtr; + EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork; + UINT8 *TransmitBufferPtr; + UINT8 *ReceiveBufferPtr; + EFI_PXE_BASE_CODE_FUNCTION Function; + + UINTN OldestArpEntry; + UINTN MCastGroupCount; + EFI_EVENT Igmpv1TimeoutEvent; + BOOLEAN UseIgmpv1Reporting; + EFI_EVENT IgmpGroupEvent[MAX_MCAST_GROUPS]; + UINT16 RandomPort; + +#if SUPPORT_IPV6 + // + // TBD + // +#else + UINT32 MCastGroup[MAX_MCAST_GROUPS]; +#endif + + BOOLEAN GoodStationIp; + BOOLEAN DidTransmit; + UINTN IpLength; + VOID *DhcpPacketBuffer; + UINTN FileSize; + VOID *BootServerReceiveBuffer; + EFI_IP_ADDRESS ServerIp; + + // + // work area + // for dhcp + // + VOID *ReceiveBuffers; + VOID *TransmitBuffer; + UINTN NumOffersReceived; + UINT16 TotalSeconds; + + // + // arrays for different types of offers + // + UINT8 ServerCount[4]; + UINT8 OfferCount[4][MAX_OFFERS]; + UINT8 GotBootp; + UINT8 GotProxy[4]; + UINT8 BinlProxies[MAX_OFFERS]; + + UINT8 *ArpBuffer; + UINT8 *TftpAckBuffer; + UINT8 *TftpErrorBuffer; + IGMPV2_MESSAGE IgmpMessage; + BOOLEAN BigBlkNumFlag; + UINT8 Timeout; + UINT16 RandomSeed; +} PXE_BASECODE_DEVICE; + +// +// type index +// +#define DHCP_ONLY_IX 0 +#define PXE10_IX 1 +#define WfM11a_IX 2 +#define BINL_IX 3 + +#define PXE_RND_PORT_LOW 2070 + +#define PXE_MAX_PRINT_BUFFER 128 + +// +// +// +#define LOADFILE_DEVICE_SIGNATURE EFI_SIGNATURE_32('p','x','e','l') + +typedef struct { + UINTN Signature; + EFI_LOCK Lock; + EFI_LOAD_FILE_PROTOCOL LoadFile; + PXE_BASECODE_DEVICE *Private; +} LOADFILE_DEVICE; + +#define EFI_BASE_CODE_DEV_FROM_THIS(a) CR (a, PXE_BASECODE_DEVICE, efi_bc, PXE_BASECODE_DEVICE_SIGNATURE); + +#define EFI_LOAD_FILE_DEV_FROM_THIS(a) CR (a, LOADFILE_DEVICE, LoadFile, LOADFILE_DEVICE_SIGNATURE) + +EFI_BIS_PROTOCOL * +PxebcBisStart ( + PXE_BASECODE_DEVICE *Private, + BIS_APPLICATION_HANDLE *BisAppHandle, + EFI_BIS_DATA **BisDataSigInfo + ) +; + +VOID +PxebcBisStop ( + EFI_BIS_PROTOCOL *Bis, + BIS_APPLICATION_HANDLE BisAppHandle, + EFI_BIS_DATA *BisDataSigInfo + ) +; + +BOOLEAN +PxebcBisVerify ( + PXE_BASECODE_DEVICE *Private, + VOID *FileBuffer, + UINTN FileBufferLength, + VOID *CredentialBuffer, + UINTN CredentialBufferLength + ) +; + +BOOLEAN +PxebcBisDetect ( + PXE_BASECODE_DEVICE *Private + ) +; + +// +// Global Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gPxeBcDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gPxeBcComponentName; + +// +// ////////////////////////////////////////////////////////// +// +// prototypes +// +EFI_STATUS +EFIAPI +InitializeBCDriver ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +; + +EFI_STATUS +EFIAPI +BcStart ( + IN EFI_PXE_BASE_CODE_PROTOCOL *This, + IN BOOLEAN UseIpv6 + ) +; + +EFI_STATUS +EFIAPI +BcStop ( + IN EFI_PXE_BASE_CODE_PROTOCOL *This + ) +; + +EFI_STATUS +EFIAPI +BcDhcp ( + IN EFI_PXE_BASE_CODE_PROTOCOL *This, + IN BOOLEAN SortOffers + ) +; + +EFI_STATUS +EFIAPI +BcDiscover ( + IN EFI_PXE_BASE_CODE_PROTOCOL * This, + IN UINT16 Type, + IN UINT16 *Layer, + IN BOOLEAN UseBis, + IN EFI_PXE_BASE_CODE_DISCOVER_INFO * Info OPTIONAL + ) +; + +EFI_STATUS +EFIAPI +BcMtftp ( + IN EFI_PXE_BASE_CODE_PROTOCOL * This, + IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation, + IN OUT VOID *BufferPtr, + IN BOOLEAN Overwrite, + IN OUT UINT64 *BufferSize, + IN UINTN *BlockSize OPTIONAL, + IN EFI_IP_ADDRESS * ServerIp, + IN UINT8 *Filename, + IN EFI_PXE_BASE_CODE_MTFTP_INFO * Info OPTIONAL, + IN BOOLEAN DontUseBuffer + ) +; + +EFI_STATUS +EFIAPI +BcUdpWrite ( + IN EFI_PXE_BASE_CODE_PROTOCOL *This, + IN UINT16 OpFlags, + IN EFI_IP_ADDRESS *DestIp, + IN EFI_PXE_BASE_CODE_UDP_PORT *DestPort, + IN EFI_IP_ADDRESS *GatewayIp, OPTIONAL + IN EFI_IP_ADDRESS *SrcIp, OPTIONAL + IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort, OPTIONAL + IN UINTN *HeaderSize, OPTIONAL + IN VOID *HeaderPtr, OPTIONAL + IN UINTN *BufferSize, + IN VOID *BufferPtr + ) +; + +EFI_STATUS +EFIAPI +BcUdpRead ( + IN EFI_PXE_BASE_CODE_PROTOCOL *This, + IN UINT16 OpFlags, + IN OUT EFI_IP_ADDRESS *DestIp, OPTIONAL + IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPort, OPTIONAL + IN OUT EFI_IP_ADDRESS *SrcIp, OPTIONAL + IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort, OPTIONAL + IN UINTN *HeaderSize, OPTIONAL + IN VOID *HeaderPtr, OPTIONAL + IN OUT UINTN *BufferSize, + IN VOID *BufferPtr + ) +; + +EFI_STATUS +EFIAPI +BcArp ( + IN EFI_PXE_BASE_CODE_PROTOCOL * This, + IN EFI_IP_ADDRESS * IpAddr, + IN EFI_MAC_ADDRESS * MacAddr OPTIONAL + ) +; + +EFI_STATUS +EFIAPI +BcIpFilter ( + IN EFI_PXE_BASE_CODE_PROTOCOL *This, + IN EFI_PXE_BASE_CODE_IP_FILTER *NewFilter + ) +; + +EFI_STATUS +EFIAPI +BcSetParameters ( + IN EFI_PXE_BASE_CODE_PROTOCOL * This, + IN BOOLEAN *NewAutoArp, OPTIONAL + IN BOOLEAN *NewSendGUID, OPTIONAL + IN UINT8 *NewTTL, OPTIONAL + IN UINT8 *NewToS, OPTIONAL + IN BOOLEAN *NewMakeCallback OPTIONAL + ) +; + +EFI_STATUS +EFIAPI +BcSetStationIP ( + IN EFI_PXE_BASE_CODE_PROTOCOL * This, + IN EFI_IP_ADDRESS * NewStationIp, OPTIONAL + IN EFI_IP_ADDRESS * NewSubnetMask OPTIONAL + ) +; + +EFI_STATUS +EFIAPI +BcSetPackets ( + IN EFI_PXE_BASE_CODE_PROTOCOL * This, + BOOLEAN *NewDhcpDiscoverValid, OPTIONAL + BOOLEAN *NewDhcpAckReceived, OPTIONAL + BOOLEAN *NewProxyOfferReceived, OPTIONAL + BOOLEAN *NewPxeDiscoverValid, OPTIONAL + BOOLEAN *NewPxeReplyReceived, OPTIONAL + BOOLEAN *NewPxeBisReplyReceived, OPTIONAL + IN EFI_PXE_BASE_CODE_PACKET * NewDhcpDiscover, OPTIONAL + IN EFI_PXE_BASE_CODE_PACKET * NewDhcpAck, OPTIONAL + IN EFI_PXE_BASE_CODE_PACKET * NewProxyOffer, OPTIONAL + IN EFI_PXE_BASE_CODE_PACKET * NewPxeDiscover, OPTIONAL + IN EFI_PXE_BASE_CODE_PACKET * NewPxeReply, OPTIONAL + IN EFI_PXE_BASE_CODE_PACKET * NewPxeBisReply OPTIONAL + ) +; + +EFI_STATUS +EFIAPI +LoadFile ( + IN EFI_LOAD_FILE_PROTOCOL *This, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + IN BOOLEAN BootPolicy, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +; + +EFI_STATUS +PxeBcLibGetSmbiosSystemGuidAndSerialNumber ( + IN EFI_GUID *SystemGuid, + OUT CHAR8 **SystemSerialNumber + ) +; + +UINTN +EFIAPI +AsciiPrint ( + IN CONST CHAR8 *Format, + ... + ) +; + +// +// Define SMBIOS tables. +// +#pragma pack(1) +typedef struct { + UINT8 AnchorString[4]; + UINT8 EntryPointStructureChecksum; + UINT8 EntryPointLength; + UINT8 MajorVersion; + UINT8 MinorVersion; + UINT16 MaxStructureSize; + UINT8 EntryPointRevision; + UINT8 FormattedArea[5]; + UINT8 IntermediateAnchorString[5]; + UINT8 IntermediateChecksum; + UINT16 TableLength; + UINT32 TableAddress; + UINT16 NumberOfSmbiosStructures; + UINT8 SmbiosBcdRevision; +} SMBIOS_STRUCTURE_TABLE; + +// +// Please note that SMBIOS structures can be odd byte aligned since the +// unformated section of each record is a set of arbitrary size strings. +// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Handle[2]; +} SMBIOS_HEADER; + +typedef UINT8 SMBIOS_STRING; + +typedef struct { + SMBIOS_HEADER Hdr; + SMBIOS_STRING Vendor; + SMBIOS_STRING BiosVersion; + UINT8 BiosSegment[2]; + SMBIOS_STRING BiosReleaseDate; + UINT8 BiosSize; + UINT8 BiosCharacteristics[8]; +} SMBIOS_TYPE0; + +typedef struct { + SMBIOS_HEADER Hdr; + SMBIOS_STRING Manufacturer; + SMBIOS_STRING ProductName; + SMBIOS_STRING Version; + SMBIOS_STRING SerialNumber; + + // + // always byte copy this data to prevent alignment faults! + // + EFI_GUID Uuid; + + UINT8 WakeUpType; +} SMBIOS_TYPE1; + +typedef struct { + SMBIOS_HEADER Hdr; + SMBIOS_STRING Manufacturer; + SMBIOS_STRING ProductName; + SMBIOS_STRING Version; + SMBIOS_STRING SerialNumber; +} SMBIOS_TYPE2; + +typedef struct { + SMBIOS_HEADER Hdr; + SMBIOS_STRING Manufacturer; + UINT8 Type; + SMBIOS_STRING Version; + SMBIOS_STRING SerialNumber; + SMBIOS_STRING AssetTag; + UINT8 BootupState; + UINT8 PowerSupplyState; + UINT8 ThermalState; + UINT8 SecurityStatus; + UINT8 OemDefined[4]; +} SMBIOS_TYPE3; + +typedef struct { + SMBIOS_HEADER Hdr; + UINT8 Socket; + UINT8 ProcessorType; + UINT8 ProcessorFamily; + SMBIOS_STRING ProcessorManufacture; + UINT8 ProcessorId[8]; + SMBIOS_STRING ProcessorVersion; + UINT8 Voltage; + UINT8 ExternalClock[2]; + UINT8 MaxSpeed[2]; + UINT8 CurrentSpeed[2]; + UINT8 Status; + UINT8 ProcessorUpgrade; + UINT8 L1CacheHandle[2]; + UINT8 L2CacheHandle[2]; + UINT8 L3CacheHandle[2]; +} SMBIOS_TYPE4; + +typedef union { + SMBIOS_HEADER *Hdr; + SMBIOS_TYPE0 *Type0; + SMBIOS_TYPE1 *Type1; + SMBIOS_TYPE2 *Type2; + SMBIOS_TYPE3 *Type3; + SMBIOS_TYPE4 *Type4; + UINT8 *Raw; +} SMBIOS_STRUCTURE_POINTER; +#pragma pack() + +#include "ip.h" +#include "dhcp.h" +#include "tftp.h" + +#endif /* _BC_H */ + +/* EOF - bc.h */ diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/build.xml b/EdkModulePkg/Universal/Network/PxeBc/Dxe/build.xml new file mode 100644 index 0000000000..8ead9eabcc --- /dev/null +++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/dhcp.h b/EdkModulePkg/Universal/Network/PxeBc/Dxe/dhcp.h new file mode 100644 index 0000000000..cd448b37a5 --- /dev/null +++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/dhcp.h @@ -0,0 +1,627 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +--*/ + +#ifndef _DHCP_H +#define _DHCP_H + +// +// Definitions for DHCP version 4 UDP packet. +// The field names in this structure are defined and described in RFC 2131. +// +#pragma pack(1) + +typedef struct { + UINT8 op; +#define BOOTP_REQUEST 1 +#define BOOTP_REPLY 2 + + UINT8 htype; + UINT8 hlen; + UINT8 hops; + UINT32 xid; + UINT16 secs; + UINT16 flags; +#define DHCP_BROADCAST_FLAG 0x8000 + + UINT32 ciaddr; + UINT32 yiaddr; + UINT32 siaddr; + UINT32 giaddr; + UINT8 chaddr[16]; + UINT8 sname[64]; + UINT8 file[128]; + UINT8 options[312]; +#define OP_PAD 0 +#define OP_END 255 +#define OP_SUBNET_MASK 1 +#define OP_TIME_OFFSET 2 +#define OP_ROUTER_LIST 3 +#define OP_TIME_SERVERS 4 +#define OP_NAME_SERVERS 5 +#define OP_DNS_SERVERS 6 +#define OP_LOG_SERVERS 7 +#define OP_COOKIE_SERVERS 8 +#define OP_LPR_SREVERS 9 +#define OP_IMPRESS_SERVERS 10 +#define OP_RES_LOC_SERVERS 11 +#define OP_HOST_NAME 12 +#define OP_BOOT_FILE_SZ 13 +#define OP_DUMP_FILE 14 +#define OP_DOMAIN_NAME 15 +#define OP_SWAP_SERVER 16 +#define OP_ROOT_PATH 17 +#define OP_EXTENSION_PATH 18 +#define OP_IP_FORWARDING 19 +#define OP_NON_LOCAL_SRC_RTE 20 +#define OP_POLICY_FILTER 21 +#define OP_MAX_DATAGRAM_SZ 22 +#define OP_DEFAULT_TTL 23 +#define OP_MTU_AGING_TIMEOUT 24 +#define OP_MTU_SIZES 25 +#define OP_MTU_TO_USE 26 +#define OP_ALL_SUBNETS_LOCAL 27 +#define OP_BROADCAST_ADD 28 +#define OP_PERFORM_MASK_DISCOVERY 29 +#define OP_RESPOND_TO_MASK_REQ 30 +#define OP_PERFORM_ROUTER_DISCOVERY 31 +#define OP_ROUTER_SOLICIT_ADDRESS 32 +#define OP_STATIC_ROUTER_LIST 33 +#define OP_USE_ARP_TRAILERS 34 +#define OP_ARP_CACHE_TIMEOUT 35 +#define OP_ETHERNET_ENCAPSULATION 36 +#define OP_TCP_DEFAULT_TTL 37 +#define OP_TCP_KEEP_ALIVE_INT 38 +#define OP_KEEP_ALIVE_GARBAGE 39 +#define OP_NIS_DOMAIN_NAME 40 +#define OP_NIS_SERVERS 41 +#define OP_NTP_SERVERS 42 +#define OP_VENDOR_SPECIFIC 43 +#define VEND_PXE_MTFTP_IP 1 +#define VEND_PXE_MTFTP_CPORT 2 +#define VEND_PXE_MTFTP_SPORT 3 +#define VEND_PXE_MTFTP_TMOUT 4 +#define VEND_PXE_MTFTP_DELAY 5 +#define VEND_PXE_DISCOVERY_CONTROL 6 +#define VEND_PXE_DISCOVERY_MCAST_ADDR 7 +#define VEND_PXE_BOOT_SERVERS 8 +#define VEND_PXE_BOOT_MENU 9 +#define VEND_PXE_BOOT_PROMPT 10 +#define VEND_PXE_MCAST_ADDRS_ALLOC 11 +#define VEND_PXE_CREDENTIAL_TYPES 12 +#define VEND_PXE_BOOT_ITEM 71 +#define OP_NBNS_SERVERS 44 +#define OP_NBDD_SERVERS 45 +#define OP_NETBIOS_NODE_TYPE 46 +#define OP_NETBIOS_SCOPE 47 +#define OP_XWINDOW_SYSTEM_FONT_SERVERS 48 +#define OP_XWINDOW_SYSTEM_DISPLAY_MANAGERS 49 +#define OP_DHCP_REQ_IP_ADD 50 +#define OP_DHCP_LEASE_TIME 51 +#define OP_DHCP_OPTION_OVERLOAD 52 +#define OVLD_FILE 1 +#define OVLD_SRVR_NAME 2 +#define OP_DHCP_MESSAGE_TYPE 53 +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPDECLINE 4 +#define DHCPACK 5 +#define DHCPNAK 6 +#define DHCPRELEASE 7 +#define DHCPINFORM 8 +#define OP_DHCP_SERVER_IP 54 +#define OP_DHCP_PARM_REQ_LIST 55 +#define OP_DHCP_ERROR_MESSAGE 56 +#define OP_DHCP_MAX_MESSAGE_SZ 57 +#define OP_DHCP_RENEWAL_TIME 58 +#define OP_DHCP_REBINDING_TIME 59 +#define OP_DHCP_CLASS_IDENTIFIER 60 +#define OP_DHCP_CLIENT_IDENTIFIER 61 +#define OP_NISPLUS_DOMAIN_NAME 64 +#define OP_NISPLUS_SERVERS 65 +#define OP_DHCP_TFTP_SERVER_NAME 66 +#define OP_DHCP_BOOTFILE 67 +#define OP_MOBILE_IP_HOME_AGENTS 68 +#define OP_SMPT_SERVERS 69 +#define OP_POP3_SERVERS 70 +#define OP_NNTP_SERVERS 71 +#define OP_WWW_SERVERS 72 +#define OP_FINGER_SERVERS 73 +#define OP_IRC_SERVERS 74 +#define OP_STREET_TALK_SERVERS 75 +#define OP_STREET_TALK_DIR_ASSIST_SERVERS 76 +#define OP_NDS_SERVERS 85 +#define OP_NDS_TREE_NAME 86 +#define OP_NDS_CONTEXT 87 +#define OP_DHCP_SYSTEM_ARCH 93 +#define OP_DHCP_NETWORK_ARCH 94 +#define OP_DHCP_PLATFORM_ID 97 +} DHCPV4_STRUCT; + +// +// DHCPv4 option header +// +typedef struct { + UINT8 OpCode; + UINT8 Length; + // + // followed by Data[] + // +} DHCPV4_OP_HEADER; + +// +// Generic DHCPv4 option (header followed by data) +// +typedef struct { + DHCPV4_OP_HEADER Header; + UINT8 Data[1]; +} DHCPV4_OP_STRUCT; + +// +// Maximum DHCP packet size on ethernet +// +#define MAX_DHCP_MSG_SZ (MAX_ENET_DATA_SIZE - sizeof (IPV4_HEADER) - sizeof (UDPV4_HEADER)) + +// +// Macros used in pxe_bc_dhcp.c and pxe_loadfile.c +// +#define DHCPV4_TRANSMIT_BUFFER (*(DHCPV4_STRUCT *) (Private->TransmitBuffer)) +#define DHCPV4_OPTIONS_BUFFER (*(struct optionsstr *) DHCPV4_TRANSMIT_BUFFER.options) + +#define DHCPV4_ACK_INDEX 0 +#define PXE_BINL_INDEX 1 +#define PXE_OFFER_INDEX 1 +#define PXE_ACK_INDEX 2 +#define PXE_BIS_INDEX 3 + +#define DHCPV4_ACK_BUFFER ((struct DhcpReceiveBufferStruct *) Private->DhcpPacketBuffer)[DHCPV4_ACK_INDEX] +#define PXE_BINL_BUFFER ((struct DhcpReceiveBufferStruct *) Private->DhcpPacketBuffer)[PXE_BINL_INDEX] +#define PXE_OFFER_BUFFER ((struct DhcpReceiveBufferStruct *) Private->DhcpPacketBuffer)[PXE_OFFER_INDEX] +#define PXE_ACK_BUFFER ((struct DhcpReceiveBufferStruct *) Private->DhcpPacketBuffer)[PXE_ACK_INDEX] +#define PXE_BIS_BUFFER ((struct DhcpReceiveBufferStruct *) Private->DhcpPacketBuffer)[PXE_BIS_INDEX] + +#define DHCPV4_ACK_PACKET DHCPV4_ACK_BUFFER.u.Dhcpv4 +#define PXE_BINL_PACKET PXE_BINL_BUFFER.u.Dhcpv4 +#define PXE_OFFER_PACKET PXE_OFFER_BUFFER.u.Dhcpv4 +#define PXE_ACK_PACKET PXE_ACK_BUFFER.u.Dhcpv4 +#define PXE_BIS_PACKET PXE_BIS_BUFFER.u.Dhcpv4 + +// +// network structure definitions +// +// +// some option definitions +// +#define DHCPV4_OPTION_LENGTH(type) (sizeof (type) - sizeof (DHCPV4_OP_HEADER)) + +typedef struct { + DHCPV4_OP_HEADER Header; + UINT8 Type; +} DHCPV4_OP_MESSAGE_TYPE; + +typedef struct { + DHCPV4_OP_HEADER Header; + UINT8 Overload; +} DHCPV4_OP_OVERLOAD; + +// +// boot server list structure +// one or more contained in a pxe boot servers structure +// +typedef struct { + UINT8 IpCount; + EFI_IPv4_ADDRESS IpList[1]; // IP count of IPs +} PXEV4_SERVER_LIST; + +typedef struct { + UINT8 IpCount; + EFI_IPv6_ADDRESS IpList[1]; // IP count of IPs +} PXEV6_SERVER_LIST; + +typedef union { + PXEV4_SERVER_LIST Ipv4List; + PXEV6_SERVER_LIST Ipv6List; +} PXE_SERVER_LISTS; + +typedef struct { + UINT16 Type; + PXE_SERVER_LISTS u; +} PXE_SERVER_LIST; + +// +// pxe boot servers structure +// +typedef struct { + DHCPV4_OP_HEADER Header; + PXE_SERVER_LIST ServerList[1]; // one or more +} PXE_OP_SERVER_LIST; + +// +// pxe boot item structure +// +typedef struct { + DHCPV4_OP_HEADER Header; + UINT16 Type; + UINT16 Layer; +} PXE_OP_BOOT_ITEM; + +// +// pxe boot menu item structure +// +typedef struct { + UINT16 Type; + UINT8 DataLen; + UINT8 Data[1]; +} PXE_BOOT_MENU_ENTRY; + +// +// pxe boot menu structure +// +typedef struct { + DHCPV4_OP_HEADER Header; + PXE_BOOT_MENU_ENTRY MenuItem[1]; +} PXE_OP_BOOT_MENU; + +// +// pxe boot prompt structure +// +typedef struct { + DHCPV4_OP_HEADER Header; + UINT8 Timeout; + UINT8 Prompt[1]; +} PXE_OP_BOOT_PROMPT; + +#define PXE_BOOT_PROMPT_AUTO_SELECT 0 +#define PXE_BOOT_PROMPT_NO_TIMEOUT 255 + +typedef struct { + DHCPV4_OP_HEADER Header; + UINT8 Class[1]; +} DHCPV4_OP_CLASS; + +typedef struct { + DHCPV4_OP_HEADER Header; + UINT8 File[1]; +} DHCPV4_OP_BOOTFILE; + +typedef struct { + DHCPV4_OP_HEADER Header; + UINT8 VendorOptions[1]; +} DHCPV4_OP_VENDOR_OPTIONS; + +typedef struct { + DHCPV4_OP_HEADER Header; + UINT8 MaxSize[2]; +} DHCPV4_OP_MAX_MESSAGE_SIZE; + +typedef struct { + UINT8 _OP_SUBNET_MASK; /* 1 */ + UINT8 _OP_TIME_OFFSET; /* 2 */ + UINT8 _OP_ROUTER_LIST; /* 3 */ + UINT8 _OP_TIME_SERVERS; /* 4 */ + UINT8 _OP_NAME_SERVERS; /* 5 */ + UINT8 _OP_DNS_SERVERS; /* 6 */ + UINT8 _OP_HOST_NAME; /* 12 */ + UINT8 _OP_BOOT_FILE_SZ; /* 13 */ + UINT8 _OP_DOMAIN_NAME; /* 15 */ + UINT8 _OP_ROOT_PATH; /* 17 */ + UINT8 _OP_EXTENSION_PATH; /* 18 */ + UINT8 _OP_MAX_DATAGRAM_SZ; /* 22 */ + UINT8 _OP_DEFAULT_TTL; /* 23 */ + UINT8 _OP_BROADCAST_ADD; /* 28 */ + UINT8 _OP_NIS_DOMAIN_NAME; /* 40 */ + UINT8 _OP_NIS_SERVERS; /* 41 */ + UINT8 _OP_NTP_SERVERS; /* 42 */ + UINT8 _OP_VENDOR_SPECIFIC; /* 43 */ + UINT8 _OP_DHCP_REQ_IP_ADD; /* 50 */ + UINT8 _OP_DHCP_LEASE_TIME; /* 51 */ + UINT8 _OP_DHCP_SERVER_IP; /* 54 */ + UINT8 _OP_DHCP_RENEWAL_TIME; /* 58 */ + UINT8 _OP_DHCP_REBINDING_TIME; /* 59 */ + UINT8 _OP_DHCP_CLASS_IDENTIFIER; /* 60 */ + UINT8 _OP_DHCP_TFTP_SERVER_NAME; /* 66 */ + UINT8 _OP_DHCP_BOOTFILE; /* 67 */ + UINT8 _OP_DHCP_PLATFORM_ID; /* 97 */ + UINT8 VendorOption128; // vendor option 128 + UINT8 VendorOption129; // vendor option 129 + UINT8 VendorOption130; // vendor option 130 + UINT8 VendorOption131; // vendor option 131 + UINT8 VendorOption132; // vendor option 132 + UINT8 VendorOption133; // vendor option 133 + UINT8 VendorOption134; // vendor option 134 + UINT8 VendorOption135; // vendor option 135 +} DHCPV4_REQUESTED_OPTIONS_DATA; + +typedef struct { + DHCPV4_OP_HEADER Header; + DHCPV4_REQUESTED_OPTIONS_DATA Data; +} DHCPV4_OP_REQUESTED_OPTIONS; + +typedef struct opipstr { + DHCPV4_OP_HEADER Header; + EFI_IPv4_ADDRESS Ip; +} DHCPV4_OP_IP_ADDRESS; + +// +// ip list structure - e.g. router list +// +typedef struct { + DHCPV4_OP_HEADER Header; + EFI_IPv4_ADDRESS IpList[1]; +} DHCPV4_OP_IP_LIST; + +typedef struct { + DHCPV4_OP_HEADER Header; + UINT8 Type; + UINT8 Guid[sizeof (EFI_GUID)]; +} DHCPV4_OP_CLIENT_ID; + +// +// special options start - someday obsolete ??? +// +#define DHCPV4_OP_PLATFORM_ID DHCPV4_OP_CLIENT_ID + +typedef struct { + DHCPV4_OP_HEADER Header; + UINT8 Type; // SNP = 2 + UINT8 MajorVersion; + UINT8 MinorVersion; +} DHCPV4_OP_NETWORK_INTERFACE; + +#define UNDI_TYPE 1 +#define SNP_TYPE 2 + +typedef struct { + DHCPV4_OP_HEADER Header; + UINT16 Type; +} DHCPV4_OP_ARCHITECTURE_TYPE; +// +// special options end - someday obsolete ??? +// +typedef struct { + UINT8 ClassIdentifier[10]; // PXEClient: + UINT8 Lit2[5]; // Arch: + UINT8 ArchitectureType[5]; // 00000 - 65536 + UINT8 Lit3[1]; // : + UINT8 InterfaceName[4]; // e.g. UNDI + UINT8 Lit4[1]; // : + UINT8 UndiMajor[3]; // 000 - 255 + UINT8 UndiMinor[3]; // 000 - 255 +} DHCPV4_CLASS_ID_DATA; + +typedef struct { + DHCPV4_OP_HEADER Header; + DHCPV4_CLASS_ID_DATA Data; +} DHCPV4_OP_CLASS_ID; + +typedef struct { + DHCPV4_OP_HEADER Header; + EFI_IPv4_ADDRESS Ip; +} DHCPV4_OP_REQUESTED_IP; + +typedef struct { + DHCPV4_OP_HEADER Header; + EFI_IPv4_ADDRESS Ip; +} DHCPV4_OP_SERVER_IP; + +typedef struct { + DHCPV4_OP_HEADER Header; + EFI_IPv4_ADDRESS Ip; +} DHCPV4_OP_SUBNET_MASK; + +typedef struct { // oppxedisctlstr { + DHCPV4_OP_HEADER Header; + UINT8 ControlBits; +} PXE_OP_DISCOVERY_CONTROL; + +#define DISABLE_BCAST (1 << 0) +#define DISABLE_MCAST (1 << 1) +#define USE_ACCEPT_LIST (1 << 2) +#define USE_BOOTFILE (1 << 3) + +#pragma pack() +// +// definitions of indices to populate option interest array +// +#define VEND_PXE_MTFTP_IP_IX 1 // multicast IP address of bootfile for MTFTP listen +#define VEND_PXE_MTFTP_CPORT_IX 2 // UDP Port to monitor for MTFTP responses - Intel order +#define VEND_PXE_MTFTP_SPORT_IX 3 // Server UDP Port for MTFTP open - Intel order +#define VEND_PXE_MTFTP_TMOUT_IX 4 // Listen timeout - secs +#define VEND_PXE_MTFTP_DELAY_IX 5 // Transmission timeout - secs +#define VEND_PXE_DISCOVERY_CONTROL_IX 6 // bit field +#define VEND_PXE_DISCOVERY_MCAST_ADDR_IX 7 // boot server discovery multicast address +#define VEND_PXE_BOOT_SERVERS_IX 8 // list of boot servers of form tp(2) cnt(1) ips[cnt] +#define VEND_PXE_BOOT_MENU_IX 9 +#define VEND_PXE_BOOT_PROMPT_IX 10 +#define VEND_PXE_MCAST_ADDRS_ALLOC_IX 0 // not used by PXE client +#define VEND_PXE_CREDENTIAL_TYPES_IX 11 +#define VEND_13_IX 0 // not used by PXE client +#define VEND_14_IX 0 // not used by PXE client +#define VEND_15_IX 0 // not used by PXE client +#define VEND_16_IX 0 // not used by PXE client +#define VEND_17_IX 0 // not used by PXE client +#define VEND_18_IX 0 // not used by PXE client +#define VEND_19_IX 0 // not used by PXE client +#define VEND_20_IX 0 // not used by PXE client +#define VEND_21_IX 0 // not used by PXE client +#define VEND_22_IX 0 // not used by PXE client +#define VEND_23_IX 0 // not used by PXE client +#define VEND_24_IX 0 // not used by PXE client +#define VEND_25_IX 0 // not used by PXE client +#define VEND_26_IX 0 // not used by PXE client +#define VEND_27_IX 0 // not used by PXE client +#define VEND_28_IX 0 // not used by PXE client +#define VEND_29_IX 0 // not used by PXE client +#define VEND_30_IX 0 // not used by PXE client +#define VEND_31_IX 0 // not used by PXE client +#define VEND_32_IX 0 // not used by PXE client +#define VEND_33_IX 0 // not used by PXE client +#define VEND_34_IX 0 // not used by PXE client +#define VEND_35_IX 0 // not used by PXE client +#define VEND_36_IX 0 // not used by PXE client +#define VEND_37_IX 0 // not used by PXE client +#define VEND_38_IX 0 // not used by PXE client +#define VEND_39_IX 0 // not used by PXE client +#define VEND_40_IX 0 // not used by PXE client +#define VEND_41_IX 0 // not used by PXE client +#define VEND_42_IX 0 // not used by PXE client +#define VEND_43_IX 0 // not used by PXE client +#define VEND_44_IX 0 // not used by PXE client +#define VEND_45_IX 0 // not used by PXE client +#define VEND_46_IX 0 // not used by PXE client +#define VEND_47_IX 0 // not used by PXE client +#define VEND_48_IX 0 // not used by PXE client +#define VEND_49_IX 0 // not used by PXE client +#define VEND_50_IX 0 // not used by PXE client +#define VEND_51_IX 0 // not used by PXE client +#define VEND_52_IX 0 // not used by PXE client +#define VEND_53_IX 0 // not used by PXE client +#define VEND_54_IX 0 // not used by PXE client +#define VEND_55_IX 0 // not used by PXE client +#define VEND_56_IX 0 // not used by PXE client +#define VEND_57_IX 0 // not used by PXE client +#define VEND_58_IX 0 // not used by PXE client +#define VEND_59_IX 0 // not used by PXE client +#define VEND_60_IX 0 // not used by PXE client +#define VEND_61_IX 0 // not used by PXE client +#define VEND_62_IX 0 // not used by PXE client +#define VEND_63_IX 0 // not used by PXE client +#define VEND_64_IX 0 // not used by PXE client +#define VEND_65_IX 0 // not used by PXE client +#define VEND_66_IX 0 // not used by PXE client +#define VEND_67_IX 0 // not used by PXE client +#define VEND_68_IX 0 // not used by PXE client +#define VEND_69_IX 0 // not used by PXE client +#define VEND_70_IX 0 // not used by PXE client +#define VEND_PXE_BOOT_ITEM_IX 12 + +#define MAX_OUR_PXE_OPT VEND_PXE_BOOT_ITEM // largest PXE option in which we are interested +#define MAX_OUR_PXE_IX VEND_PXE_BOOT_ITEM_IX // largest PXE option index +// +// define various types by options that are sent +// +#define WfM11a_OPTS ((1<> 8) & 0x00ff)) + +#define HTONL(v) \ + (UINT32) ((((v) << 24) & 0xff000000) + (((v) << 8) & 0x00ff0000) + (((v) >> 8) & 0x0000ff00) + (((v) >> 24) & 0x000000ff)) + +#define HTONLL(v) swap64 (v) + +#define U8PTR(na) ((UINT8 *) &(na)) + +#define NTOHS(ns) ((UINT16) (((*U8PTR (ns)) << 8) +*(U8PTR (ns) + 1))) + +#define NTOHL(ns) \ + ((UINT32) (((*U8PTR (ns)) << 24) + ((*(U8PTR (ns) + 1)) << 16) + ((*(U8PTR (ns) + 2)) << 8) +*(U8PTR (ns) + 3))) + +#endif /* _HTON_H_ */ + +/* EOF - hton.h */ diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/ip.h b/EdkModulePkg/Universal/Network/PxeBc/Dxe/ip.h new file mode 100644 index 0000000000..fcfc264763 --- /dev/null +++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/ip.h @@ -0,0 +1,741 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +--*/ + +#ifndef _IP_H_ +#define _IP_H_ + +#include "hton.h" + +// +// Client architecture types +// +#define IA64 2 +#define SYS_ARCH_EFI32 6 + +// +// portability macros +// +#define UDP_FILTER_MASK (EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | \ + EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT | \ + EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP | \ + EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT | \ + EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER \ + ) + +#define PXE_BOOT_LAYER_MASK 0x7FFF +#define PXE_BOOT_LAYER_INITIAL 0x0000 +#define PXE_BOOT_LAYER_CREDENTIAL_FLAG 0x8000 +#define MAX_BOOT_SERVERS 32 + +// +// macro to evaluate IP address as TRUE if it is a multicast IP address +// +#define IS_MULTICAST(ptr) ((*((UINT8 *) ptr) & 0xf0) == 0xe0) + +// +// length macros +// +#define IP_ADDRESS_LENGTH(qp) (((qp)->UsingIpv6) ? sizeof (EFI_IPv6_ADDRESS) : sizeof (EFI_IPv4_ADDRESS)) + +#define MAX_FRAME_DATA_SIZE 1488 +#define ALLOCATE_SIZE(X) (((X) + 7) & 0xfff8) +#define MODE_ALLOCATE_SIZE ALLOCATE_SIZE (sizeof (EFI_PXE_BASE_CODE_MODE)) +#define BUFFER_ALLOCATE_SIZE (8192 + 512) +#define ROUTER_ALLOCATE_SIZE ALLOCATE_SIZE ((sizeof (EFI_PXE_BASE_CODE_ROUTE_ENTRY) * PXE_ROUTER_TABLE_SIZE)) +#define ARP_ALLOCATE_SIZE ALLOCATE_SIZE ((sizeof (EFI_PXE_BASE_CODE_ARP_ENTRY) * PXE_ARP_CACHE_SIZE)) +#define FILTER_ALLOCATE_SIZE ALLOCATE_SIZE ((sizeof (EFI_IP_ADDRESS) * PXE_IP_FILTER_SIZE)) +#define PXE_ARP_CACHE_SIZE 8 +#define PXE_ROUTER_TABLE_SIZE 8 +#define PXE_IP_FILTER_SIZE 8 +#define ICMP_ALLOCATE_SIZE ALLOCATE_SIZE (sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)) +#define TFTP_ERR_ALLOCATE_SIZE ALLOCATE_SIZE (sizeof (EFI_PXE_BASE_CODE_TFTP_ERROR)) + +// +// DHCP discover/request packets are sent to this UDP port. ProxyDHCP +// servers listen on this port for DHCP discover packets that have a +// class identifier (option 60) with 'PXEClient' in the first 9 bytes. +// Bootservers also listen on this port for PXE broadcast discover +// requests from PXE clients. +// +#define DHCP_SERVER_PORT 67 + +// +// When DHCP, proxyDHCP and Bootservers respond to DHCP and PXE broadcast +// discover requests by broadcasting the reply packet, the packet is +// broadcast to this port. +// +#define DHCP_CLIENT_PORT 68 + +// +// TFTP servers listen for TFTP open requests on this port. +// +#define TFTP_OPEN_PORT 69 + +// +// proxyDHCP and Bootservers listen on this port for a PXE unicast and/or +// multicast discover requests from PXE clients. A PXE discover request +// looks like a DHCP discover or DHCP request packet. +// +#define PXE_DISCOVERY_PORT 4011 + +// +// This port is used by the PXE client/server protocol tests. +// +#define PXE_PORT_PXETEST_PORT 0x8080 + +// +// Definitions for Ethertype protocol numbers and interface types +// Per RFC 1700, +// +#define PXE_PROTOCOL_ETHERNET_IP 0x0800 +#define PXE_PROTOCOL_ETHERNET_ARP 0x0806 +#define PXE_PROTOCOL_ETHERNET_RARP 0x8035 + +#define PXE_IFTYPE_ETHERNET 0x01 +#define PXE_IFTYPE_TOKENRING 0x04 +#define PXE_IFTYPE_FIBRE_CHANNEL 0x12 + +// +// Definitions for internet protocol version 4 header +// Per RFC 791, September 1981. +// +#define IPVER4 4 + +#pragma pack(1) // make network structures packed byte alignment +typedef union { + UINT8 B[4]; + UINT32 L; +} IPV4_ADDR; + +#define IPV4_HEADER_LENGTH(IpHeaderPtr) (((IpHeaderPtr)->VersionIhl & 0xf) << 2) + +#define SET_IPV4_VER_HDL(IpHeaderPtr, IpHeaderLen) { \ + (IpHeaderPtr)->VersionIhl = (UINT8) ((IPVER4 << 4) | ((IpHeaderLen) >> 2)); \ + } + +typedef struct { + UINT8 VersionIhl; + UINT8 TypeOfService; + UINT16 TotalLength; + UINT16 Id; + UINT16 FragmentFields; + UINT8 TimeToLive; + UINT8 Protocol; + UINT16 HeaderChecksum; + IPV4_ADDR SrcAddr; + IPV4_ADDR DestAddr; + // + // options are not implemented + // +} IPV4_HEADER; + +#define IP_FRAG_RSVD 0x8000 // reserved bit - must be zero +#define IP_NO_FRAG 0x4000 // do not fragment bit +#define IP_MORE_FRAG 0x2000 // not last fragment +#define IP_FRAG_OFF_MSK 0x1fff // fragment offset in 8 byte chunks +#define DEFAULT_RFC_TTL 64 + +#define PROT_ICMP 1 +#define PROT_IGMP 2 +#define PROT_TCP 6 +#define PROT_UDP 17 + +/* + * Definitions for internet control message protocol version 4 message + * structure. Per RFC 792, September 1981. + */ + +// +// icmp header for all icmp messages +// +typedef struct { + UINT8 Type; // message type + UINT8 Code; // type specific - 0 for types we implement + UINT16 Checksum; // ones complement of ones complement sum of 16 bit words of message +} ICMPV4_HEADER; + +#define ICMP_DEST_UNREACHABLE 3 +#define ICMP_SOURCE_QUENCH 4 +#define ICMP_REDIRECT 5 +#define ICMP_ECHO 8 +#define ICMP_ECHO_REPLY 0 +#define ICMP_ROUTER_ADV 9 +#define ICMP_ROUTER_SOLICIT 10 +#define ICMP_TIME_EXCEEDED 11 +#define ICMP_PARAMETER_PROBLEM 12 +#define ICMP_TIMESTAMP 13 +#define ICMP_TIMESTAMP_REPLY 14 +#define ICMP_INFO_REQ 15 +#define ICMP_INFO_REQ_REPLY 16 +#define ICMP_SUBNET_MASK_REQ 17 +#define ICMP_SUBNET_MASK_REPLY 18 +// +// other ICMP message types ignored in this implementation +// +// icmp general messages +// +typedef struct { + ICMPV4_HEADER Header; + // + // generally unused except byte [0] for + // parameter problem message + // + UINT8 GenerallyUnused[4]; + // + // original message ip header of plus 64 + // bits of data + // + IPV4_HEADER IpHeader; +} ICMPV4_GENERAL_MESSAGE; + +// +// icmp req/rply message header +// +typedef struct { + ICMPV4_HEADER Header; + UINT16 Id; + UINT16 SequenceNumber; +} ICMPV4_REQUEST_REPLY_HEADER; + +// +// icmp echo message +// +typedef struct { + ICMPV4_REQUEST_REPLY_HEADER Header; + UINT8 EchoData[1]; // variable length data to be echoed +} ICMPV4_ECHO_MESSAGE; + +// +// icmp timestamp message - times are milliseconds since midnight UT - +// if non std, set high order bit +// +typedef struct { + ICMPV4_REQUEST_REPLY_HEADER Header; + UINT32 OriginalTime; // originating timestamp + UINT32 ReceiveTime; // receiving timestamp + UINT32 TransmitTime; // transmitting timestamp +} ICMPV4_TIMESTAMP_MESSAGE; + +// +// icmp info request structure - fill in source and dest net ip address on reply +// +typedef struct { + ICMPV4_REQUEST_REPLY_HEADER Header; +} ICMPV4_INFO_MESSAGE; + +// +// Definitions for internet control message protocol version 4 message structure +// Router discovery +// Per RFC 1256, September 1991. +// +// +// icmp router advertisement message +// +typedef struct { + ICMPV4_HEADER Header; + UINT8 NumberEntries; // number of address entries + UINT8 EntrySize; // number of 32 bit words per address entry + UINT16 Lifetime; // seconds to consider info valid + UINT32 RouterIp; + UINT32 Preferance; +} ICMPV4_ROUTER_ADVERTISE_MESSAGE; + +// +// icmp router solicitation message +// +typedef struct { + ICMPV4_HEADER Header; + UINT32 Reserved; +} ICMPV4_ROUTER_SOLICIT_MESSAGE; + +#define MAX_SOLICITATION_DELAY 1 // 1 second +#define SOLICITATION_INTERVAL 3 // 3 seconds +#define MAX_SOLICITATIONS 3 // 3 transmissions +#define V1ROUTER_PRESENT_TIMEOUT 400 // 400 second timeout until v2 reports can be sent +#define UNSOLICITED_REPORT_INTERVAL 10 // 10 seconds between unsolicited reports +#define BROADCAST_IPv4 0xffffffff + +// +// Definitions for address resolution protocol message structure +// Per RFC 826, November 1982 +// +typedef struct { + UINT16 HwType; // hardware type - e.g. ethernet (1) + UINT16 ProtType; // protocol type - for ethernet, 0x800 for IP + UINT8 HwAddLen; // byte length of a hardware address (e.g. 6 for ethernet) + UINT8 ProtAddLen; // byte length of a protocol address (e.g. 4 for ipv4) + UINT16 OpCode; + // + // source and dest hw and prot addresses follow - see example below + // +} ARP_HEADER; + +#define ETHERNET_ADD_SPC 1 + +#define ETHER_TYPE_IP 0x800 + +#define ARP_REQUEST 1 +#define ARP_REPLY 2 + +// +// generic ARP packet +// +typedef struct { + ARP_HEADER ArpHeader; + EFI_MAC_ADDRESS SrcHardwareAddr; + EFI_IP_ADDRESS SrcProtocolAddr; + EFI_MAC_ADDRESS DestHardwareAddr; + EFI_IP_ADDRESS DestProtocolAddr; +} ARP_PACKET; + +#define ENET_HWADDLEN 6 +#define IPV4_PROTADDLEN 4 + +// +// Definitions for user datagram protocol version 4 pseudo header & header +// Per RFC 768, 28 August 1980 +// +typedef struct { + IPV4_ADDR SrcAddr; // source ip address + IPV4_ADDR DestAddr; // dest ip address + UINT8 Zero; // 0 + UINT8 Protocol; // protocol + UINT16 TotalLength; // UDP length - sizeof udpv4hdr + data length +} UDPV4_PSEUDO_HEADER; + +typedef struct { + UINT16 SrcPort; // source port identifier + UINT16 DestPort; // destination port identifier + UINT16 TotalLength; // total length header plus data + // + // ones complement of ones complement sum of 16 bit + // words of pseudo header, UDP header, and data + // zero checksum is transmitted as -0 (ones comp) + // zero transmitted means checksum not computed + // data follows + // + UINT16 Checksum; +} UDPV4_HEADER; + +typedef struct { + UDPV4_PSEUDO_HEADER Udpv4PseudoHeader; + UDPV4_HEADER Udpv4Header; +} UDPV4_HEADERS; + +// +// Definitions for transmission control protocol header +// Per RFC 793, September, 1981 +// +typedef struct { + IPV4_ADDR SrcAddr; // source ip address + IPV4_ADDR DestAddr; // dest ip address + UINT8 Zero; // 0 + UINT8 Protocol; // protocol + UINT16 TotalLength; // TCP length - TCP header length + data length +} TCPV4_PSEUDO_HEADER; + +typedef struct { + UINT16 SrcPort; // source port identifier + UINT16 DestPort; // destination port identifier + UINT32 SeqNumber; // Sequence number + UINT32 AckNumber; // Acknowledgement Number + // + // Nibble of HLEN (length of header in 32-bit multiples) + // 6bits of RESERVED + // Nibble of Code Bits + // + UINT16 HlenResCode; + UINT16 Window; // Software buffer size (sliding window size) in network-standard byte order + // + // ones complement of ones complement sum of 16 bit words of + // pseudo header, TCP header, and data + // zero checksum is transmitted as -0 (ones comp) + // zero transmitted means checksum not computed + // + UINT16 Checksum; + UINT16 UrgentPointer; // pointer to urgent data (allows sender to specify urgent data) +} TCPV4_HEADER; + +typedef struct { + TCPV4_PSEUDO_HEADER Tcpv4PseudoHeader; + TCPV4_HEADER Tcpv4Header; +} TCPV4_HEADERS; + +typedef struct { + UINT8 Kind; // one of the following: + UINT8 Length; // total option length including Kind and Lth + UINT8 Data[1]; // length = Lth - 2 +} TCPV4_OPTION; + +#define TCP_OP_END 0 // only used to pad to end of TCP header +#define TCP_NOP 1 // optional - may be used to pad between options to get alignment +#define TCP_MAX_SEG 2 // maximum receive segment size - only send at initial connection request +#define MAX_MEDIA_HDR_SIZE 64 +#define MIN_ENET_DATA_SIZE 64 +#define MAX_ENET_DATA_SIZE 1500 // temp def - make a network based var +#define MAX_IPV4_PKT_SIZE 65535 // maximum IP packet size +#define MAX_IPV4_DATA_SIZE (MAX_IPV4_PKT_SIZE - sizeof (IPV4_HEADER)) +#define MAX_IPV4_FRAME_DATA_SIZE (MAX_FRAME_DATA_SIZE - sizeof (IPV4_HEADER)) +#define REAS_IPV4_PKT_SIZE 576 // minimum IP packet size all IP host can handle +#define REAS_IPV4_DATA_SIZE (REAS_IPV4_PKT_SIZE - sizeof (IPV4_HEADER)) + +// +// +// +typedef union { + UINT8 Data[MAX_ENET_DATA_SIZE]; + ICMPV4_HEADER IcmpHeader; + IGMPV2_MESSAGE IgmpMessage; + struct { + UDPV4_HEADER UdpHeader; + UINT8 Data[1]; + } Udp; + struct { + TCPV4_HEADER TcpHeader; + UINT8 Data[1]; + } Tcp; +} PROTOCOL_UNION; + +// +// out buffer structure +// +typedef struct { + UINT8 MediaHeader[MAX_MEDIA_HDR_SIZE]; + IPV4_HEADER IpHeader; + // + // following union placement only valid if no option IP header + // + PROTOCOL_UNION u; +} IPV4_BUFFER; + +typedef struct { + IPV4_HEADER IpHeader; + // + // following union placement only valid if no option IP header + // + PROTOCOL_UNION u; +} IPV4_STRUCT; + +#pragma pack() // reset to default + + //////////////////////////////////////////////////////////// +// +// BC IP Filter Routine +// +EFI_STATUS +IpFilter ( + PXE_BASECODE_DEVICE *Private, + IN EFI_PXE_BASE_CODE_IP_FILTER *Filter + ) +; + +// +// ////////////////////////////////////////////////////////////////////// +// +// Udp Write Routine - called by base code - e.g. TFTP - already locked +// +EFI_STATUS +UdpWrite ( + IN PXE_BASECODE_DEVICE *Private, + IN UINT16 OpFlags, + IN EFI_IP_ADDRESS *DestIpPtr, + IN EFI_PXE_BASE_CODE_UDP_PORT *DestPortptr, + IN EFI_IP_ADDRESS *GatewayIpPtr, OPTIONAL + IN EFI_IP_ADDRESS *SrcIpPtr, OPTIONAL + IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPortPtr, OPTIONAL + IN UINTN *HeaderSizePtr, OPTIONAL + IN VOID *HeaderPtr, OPTIONAL + IN UINTN *BufferSizePtr, + IN VOID *BufferPtr + ) +; + +// +// ///////////////////////////////////////////////////////////////////// +// +// Udp Read Routine - called by base code - e.g. TFTP - already locked +// +EFI_STATUS +UdpRead ( + IN PXE_BASECODE_DEVICE *Private, + IN UINT16 OpFlags, + IN OUT EFI_IP_ADDRESS *DestIpPtr, OPTIONAL + IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPorPtrt, OPTIONAL + IN OUT EFI_IP_ADDRESS *SrcIpPtr, OPTIONAL + IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPortPtr, OPTIONAL + IN UINTN *HeaderSizePtr, OPTIONAL + IN VOID *HeaderPtr, OPTIONAL + IN OUT UINTN *BufferSizePtr, + IN VOID *BufferPtr, + IN EFI_EVENT TimeoutEvent + ) +; + +VOID +IgmpLeaveGroup ( + PXE_BASECODE_DEVICE *Private, + EFI_IP_ADDRESS * + ) +; + +VOID +IgmpJoinGroup ( + PXE_BASECODE_DEVICE *Private, + EFI_IP_ADDRESS * + ) +; + +// +// convert number to zero filled ascii value of length lth +// +VOID +CvtNum ( + UINTN Number, + UINT8 *BufferPtr, + INTN BufferLen + ) +; + +// +// convert number to ascii string at ptr +// +VOID +UtoA10 ( + UINTN Number, + UINT8 *BufferPtr + ) +; + +// +// convert ascii numeric string to UINTN +// +UINTN +AtoU ( + UINT8 *BufferPtr + ) +; + +UINT64 +AtoU64 ( + UINT8 *BufferPtr + ) +; + +// +// calculate the internet checksum (RFC 1071) +// return 16 bit ones complement of ones complement sum of 16 bit words +// +UINT16 +IpChecksum ( + UINT16 *MessagePtr, + UINTN ByteLength + ) +; + +// +// do checksum on non contiguous header and data +// +UINT16 +IpChecksum2 ( + UINT16 *Header, + UINTN HeaderLength, + UINT16 *Message, + UINTN MessageLength + ) +; + +// +// update checksum when only a single word changes +// +UINT16 +UpdateChecksum ( + UINT16 OldChecksum, + UINT16 OldWord, + UINT16 NewWord + ) +; + +VOID +SeedRandom ( + IN PXE_BASECODE_DEVICE *Private, + IN UINT16 InitialSeed + ) +; + +UINT16 +Random ( + IN PXE_BASECODE_DEVICE *Private + ) +; + +EFI_STATUS +SendPacket ( + PXE_BASECODE_DEVICE *Private, + VOID *HeaderPtr, + VOID *PacketPtr, + INTN PacketLength, + VOID *HardwareAddress, + UINT16 MediaProtocol, + IN EFI_PXE_BASE_CODE_FUNCTION Function + ) +; + +VOID +HandleArpReceive ( + PXE_BASECODE_DEVICE *Private, + ARP_PACKET *ArpPacketPtr, + VOID *HeaderPtr + ) +; + +VOID +HandleIgmp ( + PXE_BASECODE_DEVICE *Private, + IGMPV2_MESSAGE *IgmpMessageptr, + UINTN IgmpMessageLen + ) +; + +VOID +IgmpCheckTimers ( + PXE_BASECODE_DEVICE *Private + ) +; // poll when doing a receive +// return hw add of IP and TRUE if available, otherwise FALSE +// +BOOLEAN +GetHwAddr ( + IN PXE_BASECODE_DEVICE *Private, + EFI_IP_ADDRESS *ProtocolAddressPtr, + EFI_MAC_ADDRESS *HardwareAddressPtr + ) +; + +EFI_STATUS +DoArp ( + IN PXE_BASECODE_DEVICE *Private, + IN EFI_IP_ADDRESS *ProtocolAddressPtr, + OUT EFI_MAC_ADDRESS *HardwareAddressptr + ) +; + +BOOLEAN +OnSameSubnet ( + UINTN IpAddressLen, + EFI_IP_ADDRESS *Ip1, + EFI_IP_ADDRESS *Ip2, + EFI_IP_ADDRESS *SubnetMask + ) +; + +VOID +IpAddRouter ( + PXE_BASECODE_DEVICE *Private, + EFI_IP_ADDRESS *RouterIp + ) +; + +#define Ip4AddRouter(Private, Ipv4Ptr) IpAddRouter (Private, (EFI_IP_ADDRESS *) Ipv4Ptr) + +// +// routine to send ipv4 packet +// ipv4 + upper protocol header for length TotHdrLth in xmtbuf, ipv4 header length IpHdrLth +// routine fills in ipv4hdr Ver_Hdl, TotLth, and Checksum, moves in Data, and gets dest MAC address +// +EFI_STATUS +Ipv4Xmt ( + PXE_BASECODE_DEVICE *Private, + UINT32 GatewayIP, + UINTN IpHeaderLen, + UINTN TotalHeaderLen, + VOID *Data, + UINTN DataLen, + EFI_PXE_BASE_CODE_FUNCTION Function + ) +; + +// +// send ipv4 packet with ipv4 option +// +EFI_STATUS +Ipv4SendWOp ( + PXE_BASECODE_DEVICE *Private, + UINT32 GatewayIP, + UINT8 *MessagePtr, + UINTN MessageLth, + UINT8 Protocol, + UINT8 *Option, + UINTN OptionLen, + UINT32 DestIp, + EFI_PXE_BASE_CODE_FUNCTION Function + ) +; + +// +// send MsgLth message at MsgPtr - higher level protocol header already in xmtbuf, length HdrSize +// +EFI_STATUS +Ip4Send ( + IN PXE_BASECODE_DEVICE *Private, // pointer to instance data + IN UINTN MayFragment, // + IN UINT8 Protocol, // protocol + IN UINT32 SrcIp, // Source IP address + IN UINT32 DestIp, // Destination IP address + IN UINT32 GatewayIp, // used if not NULL and needed + IN UINTN HeaderSize, // protocol header byte length + IN UINT8 *MsgPtr, // pointer to data + IN UINTN MsgLength + ) +; // data byte length +// receive up to MsgLth message into MsgPtr for protocol Prot +// return message length, src/dest ips if select any, and pointer to protocol header +// +EFI_STATUS +IpReceive ( + IN PXE_BASECODE_DEVICE *Private, // pointer to instance data + UINT16 OpFlags, // Flags to determine if filtering on IP addresses + EFI_IP_ADDRESS *SrcIpPtr, // if filtering, O if accept any + EFI_IP_ADDRESS *DstIpPtr, // if filtering, O if accept any + UINT8 Protocol, // protocol + VOID *HeaderPtr, // address of where to put protocol header + UINTN HeaderSize, // protocol header byte length + UINT8 *MsgPtr, // pointer to data buffer + UINTN *MsgLenPtr, // pointer to data buffer length/ O - returned data length + IN EFI_EVENT TimeoutEvent + ) +; + +#if 0 +VOID +WaitForTxComplete ( + IN PXE_BASECODE_DEVICE *Private + ) +; +#endif +// +// routine to cycle waiting for a receive or timeout +// +EFI_STATUS +WaitForReceive ( + IN PXE_BASECODE_DEVICE *Private, + IN EFI_PXE_BASE_CODE_FUNCTION Function, + IN EFI_EVENT TimeoutEvent, + IN OUT UINTN *HeaderSizePtr, + IN OUT UINTN *BufferSizePtr, + IN OUT UINT16 *ProtocolPtr + ) +; + +#endif /* _IP_H_ */ + +/* EOF - ip.h */ diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_arp.c b/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_arp.c new file mode 100644 index 0000000000..801f592042 --- /dev/null +++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_arp.c @@ -0,0 +1,617 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + pxe_bc_arp.c + +Abstract: + +--*/ + + +#include "bc.h" + +// +// Definitions for ARP +// Per RFC 826 +// +STATIC ARP_HEADER ArpHeader; + +#pragma pack(1) +STATIC struct { + UINT8 MediaHeader[14]; + ARP_HEADER ArpHeader; + UINT8 ArpData[64]; +} ArpReplyPacket; +#pragma pack() + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +VOID +InitArpHeader ( + VOID + ) +/*++ +Routine description: + Initialize ARP packet header. + +Parameters: + none + +Returns: + none + +--*/ +{ + ArpHeader.HwType = HTONS (ETHERNET_ADD_SPC); + ArpHeader.ProtType = HTONS (ETHER_TYPE_IP); + ArpHeader.HwAddLen = ENET_HWADDLEN; + ArpHeader.ProtAddLen = IPV4_PROTADDLEN; + ArpHeader.OpCode = HTONS (ARP_REQUEST); + + CopyMem (&ArpReplyPacket.ArpHeader, &ArpHeader, sizeof (ARP_HEADER)); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +VOID +HandleArpReceive ( + IN PXE_BASECODE_DEVICE *Private, + IN ARP_PACKET *ArpPacketPtr, + IN VOID *MediaHeader + ) +/*++ +Routine description: + Process ARP packet. + +Parameters: + Private := Pointer to PxeBc interface + ArpPacketPtr := Pointer to ARP packet + MediaHeader := Pointer to media header. +Returns: +--*/ +{ + EFI_PXE_BASE_CODE_MODE *PxeBcMode; + EFI_SIMPLE_NETWORK_MODE *SnpMode; + EFI_MAC_ADDRESS TmpMacAddr; + UINTN Index; + UINT8 *SrcHwAddr; + UINT8 *SrcPrAddr; + UINT8 *DstHwAddr; + UINT8 *DstPrAddr; + UINT8 *TmpPtr; + + // + // + // + PxeBcMode = Private->EfiBc.Mode; + SnpMode = Private->SimpleNetwork->Mode; + + // + // For now only ethernet addresses are supported. + // This will need to be updated when other media + // layers are supported by PxeBc, Snp and UNDI. + // + if (ArpPacketPtr->ArpHeader.HwType != HTONS (ETHERNET_ADD_SPC)) { + return ; + } + // + // For now only IP protocol addresses are supported. + // This will need to be updated when other protocol + // types are supported by PxeBc, Snp and UNDI. + // + if (ArpPacketPtr->ArpHeader.ProtType != HTONS (ETHER_TYPE_IP)) { + return ; + } + // + // For now only SNP hardware address sizes are supported. + // + if (ArpPacketPtr->ArpHeader.HwAddLen != SnpMode->HwAddressSize) { + return ; + } + // + // For now only PxeBc protocol address sizes are supported. + // + if (ArpPacketPtr->ArpHeader.ProtAddLen != Private->IpLength) { + return ; + } + // + // Ignore out of range opcodes + // + switch (ArpPacketPtr->ArpHeader.OpCode) { + case HTONS (ARP_REPLY): + case HTONS (ARP_REQUEST): + break; + + default: + return ; + } + // + // update entry in our ARP cache if we have it + // + SrcHwAddr = (UINT8 *) &ArpPacketPtr->SrcHardwareAddr; + SrcPrAddr = SrcHwAddr + SnpMode->HwAddressSize; + + for (Index = 0; Index < PxeBcMode->ArpCacheEntries; ++Index) { + if (CompareMem ( + &PxeBcMode->ArpCache[Index].IpAddr, + SrcPrAddr, + Private->IpLength + )) { + continue; + } + + CopyMem ( + &PxeBcMode->ArpCache[Index].MacAddr, + SrcHwAddr, + SnpMode->HwAddressSize + ); + + break; + } + // + // Done if ARP packet was not for us. + // + DstHwAddr = SrcPrAddr + Private->IpLength; + DstPrAddr = DstHwAddr + SnpMode->HwAddressSize; + + if (CompareMem (DstPrAddr, &PxeBcMode->StationIp, Private->IpLength)) { + return ; + // + // not for us + // + } + // + // for us - if we did not update entry, add it + // + if (Index == PxeBcMode->ArpCacheEntries) { + // + // if we have a full table, get rid of oldest + // + if (Index == PXE_ARP_CACHE_SIZE) { + Index = Private->OldestArpEntry; + + if (++Private->OldestArpEntry == PXE_ARP_CACHE_SIZE) { + Private->OldestArpEntry = 0; + } + } else { + ++PxeBcMode->ArpCacheEntries; + } + + CopyMem ( + &PxeBcMode->ArpCache[Index].MacAddr, + SrcHwAddr, + SnpMode->HwAddressSize + ); + + CopyMem ( + &PxeBcMode->ArpCache[Index].IpAddr, + SrcPrAddr, + Private->IpLength + ); + } + // + // if this is not a request or we don't yet have an IP, finished + // + if (ArpPacketPtr->ArpHeader.OpCode != HTONS (ARP_REQUEST) || !Private->GoodStationIp) { + return ; + } + // + // Assemble ARP reply. + // + // + // Create media header. [ dest mac | src mac | prot ] + // + CopyMem ( + &ArpReplyPacket.MediaHeader[0], + SrcHwAddr, + SnpMode->HwAddressSize + ); + + CopyMem ( + &ArpReplyPacket.MediaHeader[SnpMode->HwAddressSize], + &SnpMode->CurrentAddress, + SnpMode->HwAddressSize + ); + + CopyMem ( + &ArpReplyPacket.MediaHeader[2 * SnpMode->HwAddressSize], + &((UINT8 *) MediaHeader)[2 * SnpMode->HwAddressSize], + sizeof (UINT16) + ); + + // + // ARP reply header is almost filled in, + // just insert the correct opcode. + // + ArpReplyPacket.ArpHeader.OpCode = HTONS (ARP_REPLY); + + // + // Now fill in ARP data. [ src mac | src prot | dest mac | dest prot ] + // + TmpPtr = ArpReplyPacket.ArpData; + CopyMem (TmpPtr, &SnpMode->CurrentAddress, SnpMode->HwAddressSize); + + TmpPtr += SnpMode->HwAddressSize; + CopyMem (TmpPtr, &PxeBcMode->StationIp, Private->IpLength); + + TmpPtr += Private->IpLength; + CopyMem (TmpPtr, SrcHwAddr, SnpMode->HwAddressSize); + + TmpPtr += SnpMode->HwAddressSize; + CopyMem (TmpPtr, SrcPrAddr, Private->IpLength); + + // + // Now send out the ARP reply. + // + CopyMem (&TmpMacAddr, SrcHwAddr, sizeof (EFI_MAC_ADDRESS)); + + SendPacket ( + Private, + &ArpReplyPacket.MediaHeader, + &ArpReplyPacket.ArpHeader, + sizeof (ARP_HEADER) + 2 * (Private->IpLength + SnpMode->HwAddressSize), + &TmpMacAddr, + PXE_PROTOCOL_ETHERNET_ARP, + EFI_PXE_BASE_CODE_FUNCTION_ARP + ); + + // + // Give time (100 microseconds) for ARP reply to get onto wire. + // + gBS->Stall (1000); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +BOOLEAN +GetHwAddr ( + IN PXE_BASECODE_DEVICE *Private, + IN EFI_IP_ADDRESS *ProtocolAddrPtr, + OUT EFI_MAC_ADDRESS *HardwareAddrPtr + ) +/*++ +Routine description: + Locate IP address in ARP cache and return MAC address. + +Parameters: + Private := Pointer to PxeBc interface + ProtocolAddrPtr := Pointer to IP address + HardwareAddrPtr := Pointer to MAC address storage + +Returns: + TRUE := If IP address was found and MAC address was stored + FALSE := If IP address was not found +--*/ +{ + EFI_PXE_BASE_CODE_MODE *PxeBcMode; + UINTN HardwareAddrLength; + UINTN Index; + + PxeBcMode = Private->EfiBc.Mode; + HardwareAddrLength = Private->SimpleNetwork->Mode->HwAddressSize; + + for (Index = 0; Index < PxeBcMode->ArpCacheEntries; ++Index) { + if (!CompareMem ( + ProtocolAddrPtr, + &PxeBcMode->ArpCache[Index].IpAddr, + Private->IpLength + )) { + CopyMem ( + HardwareAddrPtr, + &PxeBcMode->ArpCache[Index].MacAddr, + HardwareAddrLength + ); + + return TRUE; + } + } + + return FALSE; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +STATIC +EFI_STATUS +SendRequest ( + IN PXE_BASECODE_DEVICE *Private, + IN EFI_IP_ADDRESS *ProtocolAddrPtr, + IN EFI_MAC_ADDRESS *HardwareAddrPtr + ) +/*++ +Routine description: + Transmit ARP request packet + +Parameters: + Private := Pointer to PxeBc interface + ProtocolAddrPtr := Pointer IP address to find + HardwareAddrPtr := Pointer to MAC address to find + +Returns: + EFI_SUCCESS := ARP request sent + other := ARP request could not be sent +--*/ +{ + EFI_PXE_BASE_CODE_MODE *PxeBcMode; + EFI_SIMPLE_NETWORK_MODE *SnpMode; + ARP_PACKET *ArpPacket; + EFI_STATUS Status; + UINTN HardwareAddrLength; + UINT8 *SrcProtocolAddrPtr; + UINT8 *DestHardwareAddrptr; + UINT8 *DestProtocolAddrPtr; + + // + // + // + PxeBcMode = Private->EfiBc.Mode; + SnpMode = Private->SimpleNetwork->Mode; + HardwareAddrLength = SnpMode->HwAddressSize; + + // + // Allocate ARP buffer + // + if (Private->ArpBuffer == NULL) { + Status = gBS->AllocatePool ( + EfiBootServicesData, + SnpMode->MediaHeaderSize + sizeof (ARP_PACKET), + (VOID **) &Private->ArpBuffer + ); + + if (EFI_ERROR (Status)) { + return Status; + } + } + + ArpPacket = (VOID *) (Private->ArpBuffer + SnpMode->MediaHeaderSize); + + // + // for now, only handle one kind of hw and pr address + // + ArpPacket->ArpHeader = ArpHeader; + ArpPacket->ArpHeader.HwAddLen = (UINT8) HardwareAddrLength; + ArpPacket->ArpHeader.ProtAddLen = (UINT8) Private->IpLength; + + // + // rest more generic + // + SrcProtocolAddrPtr = (UINT8 *) (&ArpPacket->SrcHardwareAddr) + HardwareAddrLength; + DestHardwareAddrptr = SrcProtocolAddrPtr + Private->IpLength; + DestProtocolAddrPtr = DestHardwareAddrptr + HardwareAddrLength; + + CopyMem (DestProtocolAddrPtr, ProtocolAddrPtr, Private->IpLength); + CopyMem (DestHardwareAddrptr, HardwareAddrPtr, HardwareAddrLength); + CopyMem (SrcProtocolAddrPtr, &PxeBcMode->StationIp, Private->IpLength); + CopyMem ( + &ArpPacket->SrcHardwareAddr, + &SnpMode->CurrentAddress, + HardwareAddrLength + ); + + return SendPacket ( + Private, + Private->ArpBuffer, + ArpPacket, + sizeof (ARP_HEADER) + ((Private->IpLength + HardwareAddrLength) << 1), + &SnpMode->BroadcastAddress, + PXE_PROTOCOL_ETHERNET_ARP, + EFI_PXE_BASE_CODE_FUNCTION_ARP + ); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +// +// check for address - if not there, send ARP request, wait and check again +// not how it would be done in a full system +// +#define ARP_REQUEST_TIMEOUT_MS 500 // try for half a second + + //////////////////////////////////////////////////////////// +// +// BC Arp Routine +// +EFI_STATUS +EFIAPI +BcArp ( + IN EFI_PXE_BASE_CODE_PROTOCOL * This, + IN EFI_IP_ADDRESS * ProtocolAddrPtr, + OUT EFI_MAC_ADDRESS * HardwareAddrPtr OPTIONAL + ) +/*++ +Routine description: + PxeBc ARP API. + +Parameters: + This := Pointer to PxeBc interface + ProtocolAddrPtr := Pointer to IP address to find + HardwareAddrPtr := Pointer to MAC address found. + +Returns: +--*/ +{ + EFI_MAC_ADDRESS Mac; + EFI_STATUS StatCode; + PXE_BASECODE_DEVICE *Private; + + // + // Lock the instance data and make sure started + // + StatCode = EFI_SUCCESS; + + if (This == NULL) { + DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL")); + return EFI_INVALID_PARAMETER; + } + + Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE); + + if (Private == NULL) { + DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL")); + return EFI_INVALID_PARAMETER; + } + + EfiAcquireLock (&Private->Lock); + + if (This->Mode == NULL || !This->Mode->Started) { + DEBUG ((EFI_D_ERROR, "BC was not started.")); + EfiReleaseLock (&Private->Lock); + return EFI_NOT_STARTED; + } + + DEBUG ((EFI_D_INFO, "\nBcArp()")); + + // + // Issue BC command + // + if (ProtocolAddrPtr == NULL) { + DEBUG ( + (EFI_D_INFO, + "\nBcArp() Exit #1 %Xh (%r)", + EFI_INVALID_PARAMETER, + EFI_INVALID_PARAMETER) + ); + + EfiReleaseLock (&Private->Lock); + return EFI_INVALID_PARAMETER; + } + + if (HardwareAddrPtr == NULL) { + HardwareAddrPtr = &Mac; + } + + ZeroMem (HardwareAddrPtr, Private->SimpleNetwork->Mode->HwAddressSize); + + if (GetHwAddr (Private, ProtocolAddrPtr, HardwareAddrPtr)) { + DEBUG ( + (EFI_D_INFO, + "\nBcArp() Exit #2 %Xh (%r)", + EFI_SUCCESS, + EFI_SUCCESS) + ); + + EfiReleaseLock (&Private->Lock); + return EFI_SUCCESS; + } + + StatCode = DoArp (Private, ProtocolAddrPtr, HardwareAddrPtr); + + DEBUG ((EFI_D_INFO, "\nBcArp() Exit #3 %Xh (%r)", StatCode, StatCode)); + + EfiReleaseLock (&Private->Lock); + return StatCode; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +EFI_STATUS +DoArp ( + IN PXE_BASECODE_DEVICE *Private, + IN EFI_IP_ADDRESS *ProtocolAddrPtr, + OUT EFI_MAC_ADDRESS *HardwareAddrPtr + ) +/*++ +Routine description: + Internal ARP implementation. + +Parameters: + Private := Pointer to PxeBc interface + ProtocolAddrPtr := Pointer to IP address to find + HardwareAddrPtr := Pointer to MAC address found + +Returns: + EFI_SUCCESS := MAC address found + other := MAC address could not be found +--*/ +{ + EFI_STATUS StatCode; + EFI_EVENT TimeoutEvent; + UINTN HeaderSize; + UINTN BufferSize; + UINT16 Protocol; + + DEBUG ((EFI_D_INFO, "\nDoArp()")); + + // + // + // + StatCode = SendRequest (Private, ProtocolAddrPtr, HardwareAddrPtr); + + if (EFI_ERROR (StatCode)) { + DEBUG ((EFI_D_INFO, "\nDoArp() Exit #1 %Xh (%r)", StatCode, StatCode)); + return StatCode; + } + // + // + // + StatCode = gBS->CreateEvent ( + EFI_EVENT_TIMER, + EFI_TPL_CALLBACK, + NULL, + NULL, + &TimeoutEvent + ); + + if (EFI_ERROR (StatCode)) { + return StatCode; + } + + StatCode = gBS->SetTimer ( + TimeoutEvent, + TimerRelative, + ARP_REQUEST_TIMEOUT_MS * 10000 + ); + + if (EFI_ERROR (StatCode)) { + gBS->CloseEvent (TimeoutEvent); + return StatCode; + } + // + // + // + for (;;) { + StatCode = WaitForReceive ( + Private, + EFI_PXE_BASE_CODE_FUNCTION_ARP, + TimeoutEvent, + &HeaderSize, + &BufferSize, + &Protocol + ); + + if (EFI_ERROR (StatCode)) { + break; + } + + if (Protocol != PXE_PROTOCOL_ETHERNET_ARP) { + continue; + } + + HandleArpReceive ( + Private, + (ARP_PACKET *) (Private->ReceiveBufferPtr + HeaderSize), + Private->ReceiveBufferPtr + ); + + if (GetHwAddr (Private, ProtocolAddrPtr, HardwareAddrPtr)) { + break; + } + } + + DEBUG ( + (EFI_D_INFO, + "\nDoArp() Exit #2 %Xh, (%r)", + StatCode, + StatCode) + ); + + gBS->CloseEvent (TimeoutEvent); + + return StatCode; +} + +/* eof - pxe_bc_arp.c */ diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_dhcp.c b/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_dhcp.c new file mode 100644 index 0000000000..012b61cf37 --- /dev/null +++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_dhcp.c @@ -0,0 +1,3332 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + pxe_bc_dhcp.c + +Abstract: + DHCP and PXE discovery protocol implementations. + +--*/ + + +#include "bc.h" + +STATIC EFI_PXE_BASE_CODE_UDP_PORT DhcpServerPort = DHCP_SERVER_PORT; +STATIC EFI_PXE_BASE_CODE_UDP_PORT DHCPClientPort = DHCP_CLIENT_PORT; +STATIC EFI_PXE_BASE_CODE_UDP_PORT PseudoDhcpServerPort = PXE_DISCOVERY_PORT; +#define PSEUDO_DHCP_CLIENT_PORT PseudoDhcpServerPort +STATIC EFI_IP_ADDRESS BroadcastIP = { { 0xffffffff } }; +STATIC EFI_IP_ADDRESS DefaultSubnetMask = { { 0xffffff00 } }; + +typedef union { + DHCPV4_OP_STRUCT *OpPtr; + PXE_OP_SERVER_LIST *BootServersStr; + PXE_SERVER_LIST *BootServerList; + PXE_BOOT_MENU_ENTRY *BootMenuItem; + PXE_OP_DISCOVERY_CONTROL *DiscoveryControl; + PXE_OP_BOOT_MENU *BootMenu; + PXE_OP_BOOT_ITEM *BootItem; + DHCPV4_OP_VENDOR_OPTIONS *VendorOptions; + DHCPV4_OP_OVERLOAD *Overload; + DHCPV4_OP_CLASS *PxeClassStr; + DHCPV4_OP_SUBNET_MASK *SubnetMaskStr; + DHCPV4_OP_MESSAGE_TYPE *MessageType; + UINT8 *BytePtr; +} UNION_PTR; + +// +// 1 for Itanium-based, 0 for IA32 +// +#define IA64SZ ((sizeof (UINTN) / sizeof (UINT32)) - 1) + +#define SYS_ARCH (SYS_ARCH_EFI32 - (SYS_ARCH_EFI32 - IA64) * IA64SZ) + +#pragma pack(1) +// +// option structure for DHCPREQUEST at end of DISCOVER options +// and for DHCPDECLINE +// +STATIC const struct requestopendstr { + DHCPV4_OP_REQUESTED_IP OpReqIP; + DHCPV4_OP_SERVER_IP DhcServerIpPtr; + UINT8 End[1]; +} +RequestOpEndStr = { + { + { + OP_DHCP_REQ_IP_ADD, + DHCPV4_OPTION_LENGTH(DHCPV4_OP_REQUESTED_IP) + } + }, + { + { + OP_DHCP_SERVER_IP, + DHCPV4_OPTION_LENGTH(DHCPV4_OP_SERVER_IP) + } + }, + { + OP_END + } +}; + +#define DHCP_REQ_OPTIONS (*(struct requestopendstr *) DHCPV4_OPTIONS_BUFFER.End) + +PXE_OP_BOOT_ITEM DefaultBootItem = { + { + VEND_PXE_BOOT_ITEM, + DHCPV4_OPTION_LENGTH(PXE_OP_BOOT_ITEM) + }, + 0, 0, +}; + +// +// PXE discovery control default structure +// +STATIC PXE_OP_DISCOVERY_CONTROL DefaultDisCtl = { + { VEND_PXE_DISCOVERY_CONTROL, DHCPV4_OPTION_LENGTH(PXE_OP_DISCOVERY_CONTROL) }, + 0 +}; + +// +// PXE credentials option structure +// +typedef struct { + UINT8 c[4]; +} PXE_CREDENTIAL; + +typedef struct { + DHCPV4_OP_HEADER Header; + PXE_CREDENTIAL Credentials[1]; +} PXE_OP_CREDENTIAL_TYPES; + +// +// option structure for PXE discover (without credentials) +// +typedef struct { // discoveropendstr { + DHCPV4_OP_HEADER Header; // vendor options + PXE_OP_BOOT_ITEM BootItem; + UINT8 End[1]; // if credentials option, it starts here +} PXE_DISCOVER_OPTIONS; + +#define DISCOVERoptions (*(PXE_DISCOVER_OPTIONS *) DHCPV4_OPTIONS_BUFFER.End) +#define DISCREDoptions (*(PXE_OP_CREDENTIAL_TYPES *) DISCOVERoptions.End) + +// +// common option beginning for all our DHCP messages except +// DHCPDECLINE and DHCPRELEASE +// +STATIC struct optionsstr { + UINT8 DhcpCookie[4]; + DHCPV4_OP_MESSAGE_TYPE DhcpMessageType; + DHCPV4_OP_MAX_MESSAGE_SIZE DhcpMaxMessageSize; + DHCPV4_OP_REQUESTED_OPTIONS DhcpRequestedOptions; + DHCPV4_OP_PLATFORM_ID DhcpPlatformId; + DHCPV4_OP_NETWORK_INTERFACE DhcpNetworkInterface; + DHCPV4_OP_ARCHITECTURE_TYPE DhcpClientArchitecture; + DHCPV4_OP_CLASS_ID DhcpClassIdentifier; + UINT8 End[1]; +} DHCPOpStart; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +VOID +OptionsStrucInit ( + VOID + ) +{ + DHCPOpStart.DhcpCookie[0] = 99; + DHCPOpStart.DhcpCookie[1] = 130; + DHCPOpStart.DhcpCookie[2] = 83; + DHCPOpStart.DhcpCookie[3] = 99; + DHCPOpStart.DhcpMessageType.Header.OpCode = OP_DHCP_MESSAGE_TYPE; + DHCPOpStart.DhcpMessageType.Header.Length = 1; + DHCPOpStart.DhcpMessageType.Type = DHCPDISCOVER; + DHCPOpStart.DhcpMaxMessageSize.Header.OpCode = OP_DHCP_MAX_MESSAGE_SZ; + DHCPOpStart.DhcpMaxMessageSize.Header.Length = 2; + DHCPOpStart.DhcpMaxMessageSize.MaxSize[0] = MAX_DHCP_MSG_SZ >> 8; + DHCPOpStart.DhcpMaxMessageSize.MaxSize[1] = MAX_DHCP_MSG_SZ & 0xff; + DHCPOpStart.DhcpRequestedOptions.Header.OpCode = OP_DHCP_PARM_REQ_LIST; + DHCPOpStart.DhcpRequestedOptions.Header.Length = sizeof (DHCPV4_REQUESTED_OPTIONS_DATA); + DHCPOpStart.DhcpRequestedOptions.Data._OP_SUBNET_MASK = OP_SUBNET_MASK; /* 1 */ + DHCPOpStart.DhcpRequestedOptions.Data._OP_TIME_OFFSET = OP_TIME_OFFSET; /* 2 */ + DHCPOpStart.DhcpRequestedOptions.Data._OP_ROUTER_LIST = OP_ROUTER_LIST; /* 3 */ + DHCPOpStart.DhcpRequestedOptions.Data._OP_TIME_SERVERS = OP_TIME_SERVERS; /* 4 */ + DHCPOpStart.DhcpRequestedOptions.Data._OP_NAME_SERVERS = OP_NAME_SERVERS; /* 5 */ + DHCPOpStart.DhcpRequestedOptions.Data._OP_DNS_SERVERS = OP_DNS_SERVERS; /* 6 */ + DHCPOpStart.DhcpRequestedOptions.Data._OP_HOST_NAME = OP_HOST_NAME; /* 12 */ + DHCPOpStart.DhcpRequestedOptions.Data._OP_BOOT_FILE_SZ = OP_BOOT_FILE_SZ; /* 13 */ + DHCPOpStart.DhcpRequestedOptions.Data._OP_DOMAIN_NAME = OP_DOMAIN_NAME; /* 15 */ + DHCPOpStart.DhcpRequestedOptions.Data._OP_ROOT_PATH = OP_ROOT_PATH; /* 17 */ + DHCPOpStart.DhcpRequestedOptions.Data._OP_EXTENSION_PATH = OP_EXTENSION_PATH; /* 18 */ + DHCPOpStart.DhcpRequestedOptions.Data._OP_MAX_DATAGRAM_SZ = OP_MAX_DATAGRAM_SZ; /* 22 */ + DHCPOpStart.DhcpRequestedOptions.Data._OP_DEFAULT_TTL = OP_DEFAULT_TTL; /* 23 */ + DHCPOpStart.DhcpRequestedOptions.Data._OP_BROADCAST_ADD = OP_BROADCAST_ADD; /* 28 */ + DHCPOpStart.DhcpRequestedOptions.Data._OP_NIS_DOMAIN_NAME = OP_NIS_DOMAIN_NAME; /* 40 */ + DHCPOpStart.DhcpRequestedOptions.Data._OP_NIS_SERVERS = OP_NIS_SERVERS; /* 41 */ + DHCPOpStart.DhcpRequestedOptions.Data._OP_NTP_SERVERS = OP_NTP_SERVERS; /* 42 */ + DHCPOpStart.DhcpRequestedOptions.Data._OP_VENDOR_SPECIFIC = OP_VENDOR_SPECIFIC; /* 43 */ + DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_REQ_IP_ADD = OP_DHCP_REQ_IP_ADD; /* 50 */ + DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_LEASE_TIME = OP_DHCP_LEASE_TIME; /* 51 */ + DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_SERVER_IP = OP_DHCP_SERVER_IP; /* 54 */ + DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_RENEWAL_TIME = OP_DHCP_RENEWAL_TIME; /* 58 */ + DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_REBINDING_TIME = OP_DHCP_REBINDING_TIME; /* 59 */ + DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_CLASS_IDENTIFIER = OP_DHCP_CLASS_IDENTIFIER; /* 60 */ + DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_TFTP_SERVER_NAME = OP_DHCP_TFTP_SERVER_NAME; /* 66 */ + DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_BOOTFILE = OP_DHCP_BOOTFILE; /* 67 */ + DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_PLATFORM_ID = OP_DHCP_PLATFORM_ID; /* 97 */ + DHCPOpStart.DhcpRequestedOptions.Data.VendorOption128 = 128; + DHCPOpStart.DhcpRequestedOptions.Data.VendorOption129 = 129; + DHCPOpStart.DhcpRequestedOptions.Data.VendorOption130 = 130; + DHCPOpStart.DhcpRequestedOptions.Data.VendorOption131 = 131; + DHCPOpStart.DhcpRequestedOptions.Data.VendorOption132 = 132; + DHCPOpStart.DhcpRequestedOptions.Data.VendorOption133 = 133, DHCPOpStart.DhcpRequestedOptions.Data.VendorOption134 = 134; + DHCPOpStart.DhcpRequestedOptions.Data.VendorOption135 = 135; + DHCPOpStart.DhcpPlatformId.Header.OpCode = OP_DHCP_PLATFORM_ID; + DHCPOpStart.DhcpPlatformId.Header.Length = DHCPV4_OPTION_LENGTH (DHCPV4_OP_PLATFORM_ID); + DHCPOpStart.DhcpNetworkInterface.Header.OpCode = OP_DHCP_NETWORK_ARCH; + DHCPOpStart.DhcpNetworkInterface.Header.Length = DHCPV4_OPTION_LENGTH (DHCPV4_OP_NETWORK_INTERFACE); + DHCPOpStart.DhcpNetworkInterface.Type = 0; + DHCPOpStart.DhcpNetworkInterface.MajorVersion = 0; + DHCPOpStart.DhcpNetworkInterface.MinorVersion = 0; + DHCPOpStart.DhcpClientArchitecture.Header.OpCode = OP_DHCP_SYSTEM_ARCH; + DHCPOpStart.DhcpClientArchitecture.Header.Length = DHCPV4_OPTION_LENGTH (DHCPV4_OP_ARCHITECTURE_TYPE); + DHCPOpStart.DhcpClientArchitecture.Type = HTONS (SYS_ARCH); + DHCPOpStart.DhcpClassIdentifier.Header.OpCode = OP_DHCP_CLASS_IDENTIFIER; + DHCPOpStart.DhcpClassIdentifier.Header.Length = sizeof (DHCPV4_CLASS_ID_DATA); + CopyMem ( + DHCPOpStart.DhcpClassIdentifier.Data.ClassIdentifier, + "PXEClient:", + sizeof ("PXEClient:") + ); + CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.Lit2, "Arch:", sizeof ("Arch:")); + CopyMem ( + DHCPOpStart.DhcpClassIdentifier.Data.ArchitectureType, + "xxxxx", + sizeof ("xxxxx") + ); + CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.Lit3, ":", sizeof (":")); + CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.InterfaceName, "XXXX", sizeof ("XXXX")); + CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.Lit4, ":", sizeof (":")); + CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.UndiMajor, "yyy", sizeof ("yyy")); + CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.UndiMinor, "xxx", sizeof ("xxx")); + DHCPOpStart.End[0] = OP_END; +}; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +// +// DHCPDECLINE option structure +// +struct opdeclinestr { + UINT8 DhcpCookie[4]; + DHCPV4_OP_MESSAGE_TYPE DhcpMessageType; + struct requestopendstr OpDeclineEnd; +}; + +#define DHCPDECLINEoptions (*(struct opdeclinestr *) DHCPV4_TRANSMIT_BUFFER.options) + +// +// DHCPRELEASE option structure +// +struct opreleasestr { + UINT8 DhcpCookie[4]; + DHCPV4_OP_MESSAGE_TYPE DhcpMessageType; + DHCPV4_OP_SERVER_IP DhcServerIpPtr; + UINT8 End[1]; +}; + +#define DHCPRELEASEoptions (*(struct opreleasestr *) DHCPV4_TRANSMIT_BUFFER.options) + +// +// array of PXE vendor options in which we are interested +// value 0 -> not of interest, else value is index into PXE OPTION array +// option values from 1 to MAX_OUR_PXE_OPT +// +STATIC UINT8 ourPXEopts[MAX_OUR_PXE_OPT] = { + VEND_PXE_MTFTP_IP_IX, // multicast IP address of bootfile for MTFTP listen + VEND_PXE_MTFTP_CPORT_IX, // UDP Port to monitor for MTFTP responses - Intel order + VEND_PXE_MTFTP_SPORT_IX, // Server UDP Port for MTFTP open - Intel order + VEND_PXE_MTFTP_TMOUT_IX, // Listen timeout - secs + VEND_PXE_MTFTP_DELAY_IX, // Transmission timeout - secs + VEND_PXE_DISCOVERY_CONTROL_IX, // bit field + VEND_PXE_DISCOVERY_MCAST_ADDR_IX, // boot server discovery multicast address + VEND_PXE_BOOT_SERVERS_IX, // list of boot servers of form tp(2) cnt(1) ips[cnt] + VEND_PXE_BOOT_MENU_IX, + VEND_PXE_BOOT_PROMPT_IX, + VEND_PXE_MCAST_ADDRS_ALLOC_IX, // not used by client + VEND_PXE_CREDENTIAL_TYPES_IX, + VEND_13_IX, // not used by client + VEND_14_IX, // not used by client + VEND_15_IX, // not used by client + VEND_16_IX, // not used by client + VEND_17_IX, // not used by client + VEND_18_IX, // not used by client + VEND_19_IX, // not used by client + VEND_20_IX, // not used by client + VEND_21_IX, // not used by client + VEND_22_IX, // not used by client + VEND_23_IX, // not used by client + VEND_24_IX, // not used by client + VEND_25_IX, // not used by client + VEND_26_IX, // not used by client + VEND_27_IX, // not used by client + VEND_28_IX, // not used by client + VEND_29_IX, // not used by client + VEND_30_IX, // not used by client + VEND_31_IX, // not used by client + VEND_32_IX, // not used by client + VEND_33_IX, // not used by client + VEND_34_IX, // not used by client + VEND_35_IX, // not used by client + VEND_36_IX, // not used by client + VEND_37_IX, // not used by client + VEND_38_IX, // not used by client + VEND_39_IX, // not used by client + VEND_40_IX, // not used by client + VEND_41_IX, // not used by client + VEND_42_IX, // not used by client + VEND_43_IX, // not used by client + VEND_44_IX, // not used by client + VEND_45_IX, // not used by client + VEND_46_IX, // not used by client + VEND_47_IX, // not used by client + VEND_48_IX, // not used by client + VEND_49_IX, // not used by client + VEND_50_IX, // not used by client + VEND_51_IX, // not used by client + VEND_52_IX, // not used by client + VEND_53_IX, // not used by client + VEND_54_IX, // not used by client + VEND_55_IX, // not used by client + VEND_56_IX, // not used by client + VEND_57_IX, // not used by client + VEND_58_IX, // not used by client + VEND_59_IX, // not used by client + VEND_60_IX, // not used by client + VEND_61_IX, // not used by client + VEND_62_IX, // not used by client + VEND_63_IX, // not used by client + VEND_64_IX, // not used by client + VEND_65_IX, // not used by client + VEND_66_IX, // not used by client + VEND_67_IX, // not used by client + VEND_68_IX, // not used by client + VEND_69_IX, // not used by client + VEND_70_IX, // not used by client + VEND_PXE_BOOT_ITEM_IX +}; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +// +// array of options in which we are interested +// value 0 -> not of interest, else value is index into OPTION array +// option values from 1 to MAX_OUR_OPT +// +STATIC UINT8 OurDhcpOptions[MAX_OUR_OPT] = { + OP_SUBNET_MASK_IX, // OP_SUBNET_MASK 1 // data is the subnet mask + OP_TIME_OFFSET_IX, // OP_TIME_OFFSET 2 // data is the time offset of subnet to UTC in seconds + OP_ROUTER_LIST_IX, // OP_ROUTER_LIST 3 // list of routers on subnet + OP_TIME_SERVERS_IX, // OP_TIME_SERVERS 4 // list of time servers available + OP_NAME_SERVERS_IX, // OP_NAME_SERVERS 5 // list of name servers available + OP_DNS_SERVERS_IX, // OP_DNS_SERVERS 6 // list of DNS servers available + OP_LOG_SERVERS_IX, // OP_LOG_SERVERS 7 + OP_COOKIE_SERVERS_IX, // OP_COOKIE_SERVERS 8 + OP_LPR_SREVERS_IX, // OP_LPR_SREVERS 9 + OP_IMPRESS_SERVERS_IX, // OP_IMPRESS_SERVERS 10 + OP_RES_LOC_SERVERS_IX, // OP_RES_LOC_SERVERS 11 + OP_HOST_NAME_IX, // OP_HOST_NAME 12 // client name + OP_BOOT_FILE_SZ_IX, // OP_BOOT_FILE_SZ 13 // number of 512 blocks of boot file + OP_DUMP_FILE_IX, // OP_DUMP_FILE 14 // path name of dump file if client crashes + OP_DOMAIN_NAME_IX, // OP_DOMAIN_NAME 15 // domain name to use + OP_SWAP_SERVER_IX, // OP_SWAP_SERVER 16 + OP_ROOT_PATH_IX, // OP_ROOT_PATH 17 // path name containing root disk + OP_EXTENSION_PATH_IX, // OP_EXTENSION_PATH 18 // name of TFTP downloadable file of form of OP + OP_IP_FORWARDING_IX, // OP_IP_FORWARDING 19 // enable/disable IP packet forwarding + OP_NON_LOCAL_SRC_RTE_IX, // OP_NON_LOCAL_SRC_RTE 20 // enable/disable non local source routing + OP_POLICY_FILTER_IX, // OP_POLICY_FILTER 21 // policy filters for non local source routing + OP_MAX_DATAGRAM_SZ_IX, // OP_MAX_DATAGRAM_SZ 22 // maximum datagram reassembly size + OP_DEFAULT_TTL_IX, // OP_DEFAULT_TTL 23 // default IP time to live + OP_MTU_AGING_TIMEOUT_IX, // OP_MTU_AGING_TIMEOUT 24 + OP_MTU_SIZES_IX, // OP_MTU_SIZES 25 + OP_MTU_TO_USE_IX, // OP_MTU_TO_USE 26 + OP_ALL_SUBNETS_LOCAL_IX, // OP_ALL_SUBNETS_LOCAL 27 + OP_BROADCAST_ADD_IX, // OP_BROADCAST_ADD 28 // broadcast address used on subnet + OP_PERFORM_MASK_DISCOVERY_IX, // OP_PERFORM_MASK_DISCOVERY 29 // perform mask discovery using ICMP + OP_RESPOND_TO_MASK_REQ_IX, // OP_RESPOND_TO_MASK_REQ 30 // respond to subnet mask requests using ICMP + OP_PERFORM_ROUTER_DISCOVERY_IX, // OP_PERFORM_ROUTER_DISCOVERY 31 + OP_ROUTER_SOLICIT_ADDRESS_IX, // OP_ROUTER_SOLICIT_ADDRESS 32 + OP_STATIC_ROUTER_LIST_IX, // OP_STATIC_ROUTER_LIST 33 // list of dest/route pairs + OP_USE_ARP_TRAILERS_IX, // OP_USE_ARP_TRAILERS 34 + OP_ARP_CACHE_TIMEOUT_IX, // OP_ARP_CACHE_TIMEOUT 35 + OP_ETHERNET_ENCAPSULATION_IX, // OP_ETHERNET_ENCAPSULATION 36 // 0 -> RFC 894, 1 -> IEEE 802.3 (RFC 1042) + OP_TCP_DEFAULT_TTL_IX, // OP_TCP_DEFAULT_TTL 37 // default time to live when sending TCP segments + OP_TCP_KEEP_ALIVE_INT_IX, // OP_TCP_KEEP_ALIVE_INT 38 // keep alive interval in seconds + OP_KEEP_ALIVE_GARBAGE_IX, // OP_KEEP_ALIVE_GARBAGE 39 + OP_NIS_DOMAIN_NAME_IX, // OP_NIS_DOMAIN_NAME 40 + OP_NIS_SERVERS_IX, // OP_NIS_SERVERS 41 + OP_NTP_SERVERS_IX, // OP_NTP_SERVERS 42 + OP_VENDOR_SPECIFIC_IX, // OP_VENDOR_SPECIFIC 43 + OP_NBNS_SERVERS_IX, // OP_NBNS_SERVERS 44 + OP_NBDD_SERVERS_IX, // OP_NBDD_SERVERS 45 + OP_NETBIOS_NODE_TYPE_IX, // OP_NETBIOS_NODE_TYPE 46 + OP_NETBIOS_SCOPE_IX, // OP_NETBIOS_SCOPE 47 + OP_XWINDOW_SYSTEM_FONT_SERVERS_IX, // OP_XWINDOW_SYSTEM_FONT_SERVERS 48 + OP_XWINDOW_SYSTEM_DISPLAY_MANAGERS_IX, // OP_XWINDOW_SYSTEM_DISPLAY_MANAGERS 49 + OP_DHCP_REQ_IP_ADD_IX, // OP_DHCP_REQ_IP_ADD 50 // requested IP address - in DHCPDISCOVER + OP_DHCP_LEASE_TIME_IX, // OP_DHCP_LEASE_TIME 51 // lease time requested/granted + OP_DHCP_OPTION_OVERLOAD_IX, // OP_DHCP_OPTION_OVERLOAD 52 // file/server name/both used to hold options + OP_DHCP_MESSAGE_TYPE_IX, // OP_DHCP_MESSAGE_TYPE 53 // message type + OP_DHCP_SERVER_IP_IX, // OP_DHCP_SERVER_IP 54 // IP of server + OP_DHCP_PARM_REQ_LIST_IX, // OP_DHCP_PARM_REQ_LIST 55 // list of requested parameters + OP_DHCP_ERROR_MESSAGE_IX, // OP_DHCP_ERROR_MESSAGE 56 // in DHCPNAK or DECLINE messages + OP_DHCP_MAX_MESSAGE_SZ_IX, // OP_DHCP_MAX_MESSAGE_SZ 57 // maximum DHCP message size client will accept + OP_DHCP_RENEWAL_TIME_IX, // OP_DHCP_RENEWAL_TIME 58 // time in seconds before transitioning to RENEWING state + OP_DHCP_REBINDING_TIME_IX, // OP_DHCP_REBINDING_TIME 59 // time in seconds before transitioning to REBINDING state + OP_DHCP_CLASS_IDENTIFIER_IX, // OP_DHCP_CLASS_IDENTIFIER 60 + OP_DHCP_CLIENT_IDENTIFIER_IX, // OP_DHCP_CLIENT_IDENTIFIER 61 + OP_RESERVED62_IX, // OP_RESERVED62 + OP_RESERVED63_IX, // OP_RESERVED63 + OP_NISPLUS_DOMAIN_NAME_IX, // OP_NISPLUS_DOMAIN_NAME 64 + OP_NISPLUS_SERVERS_IX, // OP_NISPLUS_SERVERS 65 + OP_DHCP_TFTP_SERVER_NAME_IX, // OP_DHCP_TFTP_SERVER_NAME 66 + OP_DHCP_BOOTFILE_IX // OP_DHCP_BOOTFILE 67 +}; + +#define RxBuf ((DHCP_RECEIVE_BUFFER *) (Private->ReceiveBuffers)) + +#pragma pack() + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +CHAR8 * +PxeBcLibGetSmbiosString ( + IN SMBIOS_STRUCTURE_POINTER *Smbios, + IN UINT16 StringNumber + ) +/*++ +Routine description: + Return SMBIOS string given the string number. + +Arguments: + Smbios - Pointer to SMBIOS structure + StringNumber - String number to return. 0 is used to skip all strings and + point to the next SMBIOS structure. + +Returns: + Pointer to string, or pointer to next SMBIOS strcuture if StringNumber == 0 +--*/ +{ + UINT16 Index; + CHAR8 *String; + + // + // Skip over formatted section + // + String = (CHAR8 *) (Smbios->Raw + Smbios->Hdr->Length); + + // + // Look through unformated section + // + for (Index = 1; Index <= StringNumber || StringNumber == 0; Index++) { + if (StringNumber == Index) { + return String; + } + // + // Skip string + // + for (; *String != 0; String++) + ; + String++; + + if (*String == 0) { + // + // If double NULL then we are done. + // Return pointer to next structure in Smbios. + // if you pass in a 0 you will always get here + // + Smbios->Raw = (UINT8 *)++String; + return NULL; + } + } + + return NULL; +} + +EFI_STATUS +PxeBcLibGetSmbiosSystemGuidAndSerialNumber ( + IN EFI_GUID *SystemGuid, + OUT CHAR8 **SystemSerialNumber + ) +/*++ + +Routine Description: + This function gets system guid and serial number from the smbios table + +Arguments: + SystemGuid - The pointer of returned system guid + SystemSerialNumber - The pointer of returned system serial number + +Returns: + EFI_SUCCESS - Successfully get the system guid and system serial number + EFI_NOT_FOUND - Not find the SMBIOS table +--*/ +{ + EFI_STATUS Status; + SMBIOS_STRUCTURE_TABLE *SmbiosTable; + SMBIOS_STRUCTURE_POINTER Smbios; + SMBIOS_STRUCTURE_POINTER SmbiosEnd; + UINT16 Index; + + Status = EfiGetSystemConfigurationTable (&gEfiSmbiosTableGuid, (VOID **) &SmbiosTable); + + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + Smbios.Hdr = (SMBIOS_HEADER *) (UINTN) SmbiosTable->TableAddress; + SmbiosEnd.Raw = (UINT8 *) (UINTN) (SmbiosTable->TableAddress + SmbiosTable->TableLength); + + for (Index = 0; Index < SmbiosTable->TableLength; Index++) { + if (Smbios.Hdr->Type == 1) { + if (Smbios.Hdr->Length < 0x19) { + // + // Older version did not support Guid and Serial number + // + continue; + } + // + // SMBIOS tables are byte packed so we need to do a byte copy to + // prevend alignment faults on Itanium-based platform. + // + CopyMem (SystemGuid, &Smbios.Type1->Uuid, sizeof (EFI_GUID)); + *SystemSerialNumber = PxeBcLibGetSmbiosString (&Smbios, Smbios.Type1->SerialNumber); + + return EFI_SUCCESS; + } + // + // Make Smbios point to the next record + // + PxeBcLibGetSmbiosString (&Smbios, 0); + + if (Smbios.Raw >= SmbiosEnd.Raw) { + // + // SMBIOS 2.1 incorrectly stated the length of SmbiosTable as 0x1e. + // given this we must double check against the lenght of + // the structure. + // + return EFI_SUCCESS; + } + } + + return EFI_SUCCESS; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +// +// add router list to list +// +STATIC +VOID +Ip4AddRouterList ( + PXE_BASECODE_DEVICE *Private, + DHCPV4_OP_IP_LIST *IpListPtr + ) +{ + EFI_IP_ADDRESS TmpIp; + INTN Index; + INTN num; + + if (IpListPtr == NULL) { + return ; + } + + for (Index = 0, num = IpListPtr->Header.Length >> 2; Index < num; ++Index) { + CopyMem (&TmpIp, &IpListPtr->IpList[Index], 4); + Ip4AddRouter (Private, &TmpIp); + } +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +// +// send ARP for our IP - fail if someone has it +// +STATIC +BOOLEAN +SetStationIP ( + PXE_BASECODE_DEVICE *Private + ) +{ + EFI_MAC_ADDRESS DestMac; + EFI_STATUS EfiStatus; + + ZeroMem (&DestMac, sizeof DestMac); + + if (GetHwAddr(Private, (EFI_IP_ADDRESS *)&DHCP_REQ_OPTIONS.OpReqIP.Ip, (EFI_MAC_ADDRESS *)&DestMac) + || DoArp(Private, (EFI_IP_ADDRESS *)&DHCP_REQ_OPTIONS.OpReqIP.Ip, (EFI_MAC_ADDRESS *)&DestMac) == EFI_SUCCESS) { + return FALSE; // somebody else has this IP + } + + CopyMem ( + (EFI_IPv4_ADDRESS *) &Private->EfiBc.Mode->StationIp, + &DHCP_REQ_OPTIONS.OpReqIP.Ip, + sizeof (EFI_IPv4_ADDRESS) + ); + + Private->GoodStationIp = TRUE; + + if (!Private->UseIgmpv1Reporting) { + return TRUE; + } + + if (Private->Igmpv1TimeoutEvent != NULL) { + return TRUE; + } + + EfiStatus = gBS->CreateEvent ( + EFI_EVENT_TIMER, + EFI_TPL_CALLBACK, + NULL, + NULL, + &Private->Igmpv1TimeoutEvent + ); + + if (EFI_ERROR (EfiStatus)) { + Private->Igmpv1TimeoutEvent = NULL; + return TRUE; + } + + EfiStatus = gBS->SetTimer ( + Private->Igmpv1TimeoutEvent, + TimerRelative, + (UINT64) V1ROUTER_PRESENT_TIMEOUT * 10000000 + ); /* 400 seconds */ + + if (EFI_ERROR (EfiStatus)) { + gBS->CloseEvent (Private->Igmpv1TimeoutEvent); + Private->Igmpv1TimeoutEvent = NULL; + } + + return TRUE; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +STATIC +VOID +AddRouters ( + PXE_BASECODE_DEVICE *Private, + DHCP_RECEIVE_BUFFER *RxBufPtr + ) +{ + Ip4AddRouter (Private, &RxBufPtr->u.Dhcpv4.giaddr); + + Ip4AddRouterList ( + Private, + (DHCPV4_OP_IP_LIST *) RxBufPtr->OpAdds.PktOptAdds[OP_ROUTER_LIST_IX - 1] + ); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +STATIC +EFI_STATUS +DoUdpWrite ( + PXE_BASECODE_DEVICE *Private, + EFI_IP_ADDRESS *ServerIpPtr, + EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr, + EFI_IP_ADDRESS *ClientIpPtr, + EFI_PXE_BASE_CODE_UDP_PORT *ClientPortPtr + ) +{ + UINTN Len; + + Len = sizeof DHCPV4_TRANSMIT_BUFFER; + + return UdpWrite ( + Private, + EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT, + ServerIpPtr, + ServerPortPtr, + 0, + ClientIpPtr, + ClientPortPtr, + 0, + 0, + &Len, + Private->TransmitBuffer + ); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +// +// initialize the DHCP structure +// +typedef struct { + UINT8 x[4]; +} C4Str; + +STATIC +VOID +InitDhcpv4TxBuf ( + PXE_BASECODE_DEVICE *Private + ) +{ + UINTN HwAddrLen; + UINT8 *String; + CHAR8 *SystemSerialNumber; + EFI_PXE_BASE_CODE_MODE *PxebcMode; + + PxebcMode = Private->EfiBc.Mode; + + ZeroMem (&DHCPV4_TRANSMIT_BUFFER, sizeof (DHCPV4_STRUCT)); + DHCPV4_TRANSMIT_BUFFER.op = BOOTP_REQUEST; + DHCPV4_TRANSMIT_BUFFER.htype = Private->SimpleNetwork->Mode->IfType; + DHCPV4_TRANSMIT_BUFFER.flags = HTONS (DHCP_BROADCAST_FLAG); + CopyMem (&DHCPV4_OPTIONS_BUFFER, (VOID *) &DHCPOpStart, sizeof (DHCPOpStart)); + + // + // default to hardware address + // + HwAddrLen = Private->SimpleNetwork->Mode->HwAddressSize; + + if (HwAddrLen > sizeof DHCPV4_TRANSMIT_BUFFER.chaddr) { + HwAddrLen = sizeof DHCPV4_TRANSMIT_BUFFER.chaddr; + } + + String = (UINT8 *) &Private->SimpleNetwork->Mode->CurrentAddress; + + if (PxeBcLibGetSmbiosSystemGuidAndSerialNumber ( + (EFI_GUID *) DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, + &SystemSerialNumber + ) == EFI_SUCCESS) { + if (PxebcMode->SendGUID) { + HwAddrLen = sizeof (EFI_GUID); + String = (UINT8 *) DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid; + } + } else { + // + // GUID not yet set - send all 0xff's to show programable (via SetVariable) + // SetMem(DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof(EFI_GUID), 0xff); + // GUID not yet set - send all 0's to show not programable + // + ZeroMem (DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof (EFI_GUID)); + } + + DHCPV4_TRANSMIT_BUFFER.hlen = (UINT8) HwAddrLen; + CopyMem (DHCPV4_TRANSMIT_BUFFER.chaddr, String, HwAddrLen); + + CvtNum ( + SYS_ARCH, + (UINT8 *) DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.ArchitectureType, + sizeof DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.ArchitectureType + ); + + DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.Type = Private->NiiPtr->Type; + DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.MajorVersion = Private->NiiPtr->MajorVer; + DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.MinorVersion = Private->NiiPtr->MinorVer; + + *(C4Str *) DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.InterfaceName = *(C4Str *) Private->NiiPtr->StringId; + + CvtNum ( + DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.MajorVersion, + (UINT8 *) DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.UndiMajor, + sizeof DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.UndiMajor + ); + + CvtNum ( + DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.MinorVersion, + (UINT8 *) DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.UndiMinor, + sizeof DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.UndiMinor + ); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +STATIC +UINT32 +DecodePxeOptions ( + DHCP_RECEIVE_BUFFER *RxBufPtr, + UINT8 *ptr, + INTN Len + ) +{ + UINT8 Op; + UINT8 *EndPtr; + INTN Index; + UNION_PTR LocalPtr; + UINT32 status; + + status = 0; + + for (EndPtr = ptr + Len; ptr < EndPtr; ptr += Len + 2) { + Op = ptr[0]; + Len = ptr[1]; + + switch (Op) { + case OP_PAD: + Len = -1; + break; + + case OP_END: + return status; + + default: + LocalPtr.BytePtr = ptr; + if (Op <= MAX_OUR_PXE_OPT) { + Index = ourPXEopts[Op - 1]; + if (Index) { + RxBufPtr->OpAdds.PxeOptAdds[Index - 1] = LocalPtr.OpPtr; + status |= 1 << Index; + if (Index == VEND_PXE_BOOT_ITEM && LocalPtr.BootItem->Header.Length == 3) { + RxBufPtr->OpAdds.Status |= USE_THREE_BYTE; + } + } + } + break; + } + } + + return status; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +STATIC +VOID +DecodeOptions ( + DHCP_RECEIVE_BUFFER *RxBufPtr, + UINT8 *ptr, + INTN Len + ) +{ + UINT8 Op; + UINT8 *EndPtr; + INTN Index; + UNION_PTR LocalPtr; + + for (EndPtr = ptr + Len; ptr < EndPtr; ptr += Len + 2) { + Op = ptr[0]; + Len = ptr[1]; + + switch (Op) { + case OP_PAD: + Len = -1; + break; + + case OP_END: + return ; + + default: + LocalPtr.BytePtr = ptr; + if (Op <= MAX_OUR_OPT) { + Index = OurDhcpOptions[Op - 1]; + if (Index) { + RxBufPtr->OpAdds.PktOptAdds[Index - 1] = LocalPtr.OpPtr; + if (Index == OP_VENDOR_SPECIFIC_IX) { + UINT32 status; + status = DecodePxeOptions ( + RxBufPtr, + (UINT8 *) LocalPtr.VendorOptions->VendorOptions, + LocalPtr.VendorOptions->Header.Length + ); + if (status) { + RxBufPtr->OpAdds.Status |= PXE_TYPE; + // + // check for all the MTFTP info options present - any missing is a nogo + // + if ((status & WfM11a_OPTS) == WfM11a_OPTS) { + RxBufPtr->OpAdds.Status |= WfM11a_TYPE; + } + + if (status & DISCOVER_OPTS) { + RxBufPtr->OpAdds.Status |= DISCOVER_TYPE; + } + + if (status & CREDENTIALS_OPT) { + RxBufPtr->OpAdds.Status |= CREDENTIALS_TYPE; + } + } + } + } + } + break; + } + } +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +VOID +Parse ( + DHCP_RECEIVE_BUFFER *RxBufPtr, + INTN Len + ) +{ + UNION_PTR LocalPtr; + + // + // initialize + // + SetMem (&RxBufPtr->OpAdds, sizeof RxBufPtr->OpAdds, 0); + + DecodeOptions ( + RxBufPtr, + RxBufPtr->u.Dhcpv4.options + 4, + Len - (sizeof RxBufPtr->u.Dhcpv4 - sizeof RxBufPtr->u.Dhcpv4.options + 4) + ); + + LocalPtr.OpPtr = RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_OPTION_OVERLOAD_IX - 1]; + + if ((LocalPtr.OpPtr) && (LocalPtr.Overload->Overload & OVLD_SRVR_NAME)) { + DecodeOptions (RxBufPtr, RxBufPtr->u.Dhcpv4.sname, sizeof RxBufPtr->u.Dhcpv4.sname); + } + + if (LocalPtr.OpPtr && (LocalPtr.Overload->Overload & OVLD_FILE)) { + DecodeOptions (RxBufPtr, RxBufPtr->u.Dhcpv4.file, sizeof RxBufPtr->u.Dhcpv4.file); + } else if (!RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1] && RxBufPtr->u.Dhcpv4.file[0]) { + RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1] = (DHCPV4_OP_STRUCT *) (RxBufPtr->u.Dhcpv4.file - sizeof (DHCPV4_OP_HEADER)); + + RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Header.Length = (UINT8) AsciiStrLen ((CHAR8 *)RxBufPtr->u.Dhcpv4.file); + } + + LocalPtr.OpPtr = RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_CLASS_IDENTIFIER_IX - 1]; + + if ((LocalPtr.OpPtr) && + LocalPtr.PxeClassStr->Header.Length >= 9 && + !CompareMem (LocalPtr.PxeClassStr->Class, "PXEClient", 9) + ) { + RxBufPtr->OpAdds.Status |= PXE_TYPE; + } +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +STATIC +VOID +CopyParseRxBuf ( + PXE_BASECODE_DEVICE *Private, + INTN RxBufIndex, + INTN PacketIndex + ) +{ + DHCP_RECEIVE_BUFFER *RxBufPtr; + + RxBufPtr = &((DHCP_RECEIVE_BUFFER *) Private->DhcpPacketBuffer)[PacketIndex]; + + CopyMem ( + &RxBufPtr->u.Dhcpv4, + &RxBuf[RxBufIndex].u.Dhcpv4, + sizeof (RxBuf[RxBufIndex].u.Dhcpv4) + ); + + Parse (RxBufPtr, sizeof RxBufPtr->u.ReceiveBuffer); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +STATIC +VOID +CopyProxyRxBuf ( + PXE_BASECODE_DEVICE *Private, + INTN RxBufIndex + ) +{ + Private->EfiBc.Mode->ProxyOfferReceived = TRUE; + CopyParseRxBuf (Private, RxBufIndex, PXE_OFFER_INDEX); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +STATIC +VOID +CopyParse ( + PXE_BASECODE_DEVICE *Private, + EFI_PXE_BASE_CODE_PACKET *PacketPtr, + EFI_PXE_BASE_CODE_PACKET *NewPacketPtr, + INTN Index + ) +{ + DHCP_RECEIVE_BUFFER *DhcpRxBuf; + + DhcpRxBuf = &((DHCP_RECEIVE_BUFFER *) Private->DhcpPacketBuffer)[Index]; + + CopyMem ( + (EFI_PXE_BASE_CODE_PACKET *) &DhcpRxBuf->u.Dhcpv4, + NewPacketPtr, + sizeof (*NewPacketPtr) + ); + + CopyMem (&*PacketPtr, &*NewPacketPtr, sizeof (*NewPacketPtr)); + + Parse (DhcpRxBuf, sizeof DhcpRxBuf->u.ReceiveBuffer); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +BOOLEAN +AckEdit ( + DHCP_RECEIVE_BUFFER *DhcpRxBuf + ) +{ + UNION_PTR LocalPtr; + + LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_MESSAGE_TYPE_IX - 1]; + + // + // check that an ACK + // if a DHCP type, must be DHCPOFFER and must have server id + // + return (BOOLEAN) + ( + (LocalPtr.OpPtr) && + (LocalPtr.MessageType->Type == DHCPACK) && + DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1] + ); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +// +// if a discover type packet, make sure all required fields are present +// +BOOLEAN +DHCPOfferAckEdit ( + DHCP_RECEIVE_BUFFER *DhcpRxBuf + ) +{ + PXE_OP_SERVER_LIST *BootServerOpPtr; + UNION_PTR LocalPtr; + + if ((DhcpRxBuf->OpAdds.Status & DISCOVER_TYPE) == 0) { + return TRUE; + } + + LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_CONTROL_IX - 1]; + + if (LocalPtr.OpPtr == NULL) { + LocalPtr.OpPtr = (DHCPV4_OP_STRUCT *) &DefaultDisCtl; + DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_CONTROL_IX - 1] = (DHCPV4_OP_STRUCT *) &DefaultDisCtl; + } + // + // make sure all required fields are here + // if mucticast enabled, need multicast address + // + if (!(LocalPtr.DiscoveryControl->ControlBits & DISABLE_MCAST) && + (!DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_MCAST_ADDR_IX - 1] || !IS_MULTICAST (((DHCPV4_OP_STRUCT *) DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_MCAST_ADDR_IX - 1])->Data)) + ) { + return FALSE; + // + // missing required field + // + } + // + // if a list, it better be good + // + BootServerOpPtr = (PXE_OP_SERVER_LIST *) DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_SERVERS_IX - 1]; + + if (BootServerOpPtr != NULL) { + PXE_SERVER_LIST *BootServerListPtr; + INTN ServerListLen; + INTN ServerEntryLen; + + BootServerListPtr = BootServerOpPtr->ServerList; + ServerListLen = BootServerOpPtr->Header.Length; + + do { + EFI_IPv4_ADDRESS *IpListPtr; + INTN IpCnt; + + IpCnt = BootServerListPtr->u.Ipv4List.IpCount; + + ServerEntryLen = sizeof (PXEV4_SERVER_LIST) + 2 + (IpCnt - 1) * sizeof (EFI_IPv4_ADDRESS); + + if (ServerListLen < ServerEntryLen) { + // + // missing required field + // + return FALSE; + } + + IpListPtr = BootServerListPtr->u.Ipv4List.IpList; + + while (IpCnt--) { + if (IS_MULTICAST (IpListPtr)) { + // + // missing required field + // + return FALSE; + } else { + ++IpListPtr; + } + } + + BootServerListPtr = (PXE_SERVER_LIST *) IpListPtr; + } while (ServerListLen -= ServerEntryLen); + } + // + // else there must be a list if use list enabled or multicast and + // broadcast disabled + // + else if ((LocalPtr.DiscoveryControl->ControlBits & USE_ACCEPT_LIST) || + ((LocalPtr.DiscoveryControl->ControlBits & (DISABLE_MCAST | DISABLE_BCAST)) == (DISABLE_MCAST | DISABLE_BCAST)) + ) { + // + // missing required field + // + return FALSE; + } + // + // if not USE_BOOTFILE or no bootfile given, must have menu stuff + // + if (!(LocalPtr.DiscoveryControl->ControlBits & USE_BOOTFILE) || + !DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1] + ) { + INTN MenuLth; + + LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_MENU_IX - 1]; + + if (LocalPtr.OpPtr == NULL || !DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_PROMPT_IX - 1]) { + // + // missing required field + // + return FALSE; + } + // + // make sure menu valid + // + MenuLth = LocalPtr.BootMenu->Header.Length; + LocalPtr.BootMenuItem = LocalPtr.BootMenu->MenuItem; + + do { + INTN MenuItemLen; + + MenuItemLen = LocalPtr.BootMenuItem->DataLen; + + if (MenuItemLen == 0) { + // + // missing required field + // + return FALSE; + } + + MenuItemLen += sizeof (*LocalPtr.BootMenuItem) - sizeof (LocalPtr.BootMenuItem->Data); + + MenuLth -= MenuItemLen; + LocalPtr.BytePtr += MenuItemLen; + } while (MenuLth > 0); + + if (MenuLth != 0) { + // + // missing required field + // + return FALSE; + } + } + + if (!DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1]) { + DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1] = (DHCPV4_OP_STRUCT *) &DefaultBootItem; + } + + return TRUE; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +BOOLEAN +DHCPAckEdit ( + DHCP_RECEIVE_BUFFER *RxBufPtr + ) +{ + return (BOOLEAN) (DHCPOfferAckEdit (RxBufPtr) ? AckEdit (RxBufPtr) : FALSE); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +// +// get an offer/ack +// +EFI_STATUS +GetOfferAck ( + PXE_BASECODE_DEVICE *Private, + BOOLEAN (*ExtraEdit)(DHCP_RECEIVE_BUFFER *DhcpRxBuf), + UINT16 OpFlags, // for Udp read + EFI_IP_ADDRESS *ServerIpPtr, + EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr, + EFI_IP_ADDRESS *ClientIpPtr, + EFI_PXE_BASE_CODE_UDP_PORT *ClientPortPtr, + DHCP_RECEIVE_BUFFER *DhcpRxBuf, + EFI_EVENT TimeoutEvent + ) +/*++ +Routine description: + Wait for an OFFER/ACK packet. + +Parameters: + Private := Pointer to PxeBc interface + ExtraEdit := Pointer to extra option checking function + OpFlags := UdpRead() option flags + ServerIpPtr := + ServerPortPtr := + ClientIpPtr := + ClientPortPtr := + DhcpRxBuf := + TimeoutEvent := + +Returns: +--*/ +{ + EFI_IP_ADDRESS ServerIp; + EFI_STATUS StatCode; + INTN RxBufLen; + + for (;;) { + // + // Wait until we get a UDP packet. + // + ZeroMem (&ServerIp, sizeof (EFI_IP_ADDRESS)); + RxBufLen = sizeof RxBuf[0].u.ReceiveBuffer; + + if ((StatCode = UdpRead ( + Private, + OpFlags, + ClientIpPtr, + ClientPortPtr, + ServerIpPtr, + ServerPortPtr, + 0, + 0, + (UINTN *) &RxBufLen, + &DhcpRxBuf->u.Dhcpv4, + TimeoutEvent + )) != EFI_SUCCESS) { + if (StatCode == EFI_TIMEOUT) { + StatCode = EFI_NO_RESPONSE; + } + + break; + } + // + // got a packet - see if a good offer + // + if (DhcpRxBuf->u.Dhcpv4.op != BOOTP_REPLY) { + continue; + } + + if (DhcpRxBuf->u.Dhcpv4.xid != DHCPV4_TRANSMIT_BUFFER.xid) { + continue; + } + + if (*(UINT32 *) DHCPV4_TRANSMIT_BUFFER.options != * (UINT32 *) DhcpRxBuf->u.Dhcpv4.options) { + continue; + } + + if (*(UINT8 *) &DhcpRxBuf->u.Dhcpv4.yiaddr > 223) { + continue; + } + + if (CompareMem ( + DhcpRxBuf->u.Dhcpv4.chaddr, + DHCPV4_TRANSMIT_BUFFER.chaddr, + sizeof DhcpRxBuf->u.Dhcpv4.chaddr + )) { + // + // no good + // + continue; + } + + Parse (DhcpRxBuf, RxBufLen); + + if (!(*ExtraEdit) (DhcpRxBuf)) { + continue; + } + // + // Good DHCP packet. + // + StatCode = EFI_SUCCESS; + break; + } + + return StatCode; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +// +// get DHCPOFFER's +// +EFI_STATUS +GetOffers ( + PXE_BASECODE_DEVICE *Private + ) +{ + EFI_IP_ADDRESS ClientIp; + EFI_IP_ADDRESS ServerIp; + EFI_STATUS StatCode; + EFI_EVENT TimeoutEvent; + INTN NumOffers; + INTN Index; + + // + // + // + ZeroMem (&ServerIp, sizeof (EFI_IP_ADDRESS)); + NumOffers = 0; + + for (Index = 0; Index < (sizeof Private->ServerCount) / sizeof Private->ServerCount[0]; ++Index) { + Private->ServerCount[Index] = 0; + Private->GotProxy[Index] = 0; + } + + Private->GotBootp = 0; + // + // these we throw away + // + Private->GotProxy[DHCP_ONLY_IX] = 1; + StatCode = gBS->CreateEvent ( + EFI_EVENT_TIMER, + EFI_TPL_CALLBACK, + NULL, + NULL, + &TimeoutEvent + ); + + if (EFI_ERROR (StatCode)) { + return StatCode; + } + + StatCode = gBS->SetTimer ( + TimeoutEvent, + TimerRelative, + Private->Timeout * 10000000 + 1000000 + ); + + if (EFI_ERROR (StatCode)) { + gBS->CloseEvent (TimeoutEvent); + return StatCode; + } + // + // get offers + // + for (;;) { + DHCP_RECEIVE_BUFFER *DhcpRxBuf; + UNION_PTR LocalPtr; + + DhcpRxBuf = &RxBuf[NumOffers]; + + if (( + StatCode = GetOfferAck ( + Private, + DHCPOfferAckEdit, + EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | + EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP | + EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT, + &ServerIp, + &DhcpServerPort, + &ClientIp, + &DHCPClientPort, + DhcpRxBuf, + TimeoutEvent + ) +) != EFI_SUCCESS + ) { + break; + } + + LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_MESSAGE_TYPE_IX - 1]; + + // + // check type of offer + // + if (LocalPtr.OpPtr == NULL) { + // + // bootp - we only need one and make sure has bootfile + // + if (Private->GotBootp || !DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]) { + continue; + } + + Private->GotBootp = (UINT8) (NumOffers + 1); + } + // + // if a DHCP type, must be DHCPOFFER and must have server id + // + else if (LocalPtr.MessageType->Type != DHCPOFFER || !DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1]) { + continue; + } else { + INTN TypeIx; + + // + // get type - PXE10, WfM11a, or BINL + // + if (DhcpRxBuf->OpAdds.Status & DISCOVER_TYPE) { + TypeIx = PXE10_IX; + } else if (DhcpRxBuf->OpAdds.Status & WfM11a_TYPE) { + // + // WfM - make sure it has a bootfile + // + if (!DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]) { + continue; + } + + TypeIx = WfM11a_IX; + } else { + TypeIx = (DhcpRxBuf->OpAdds.Status & PXE_TYPE) ? BINL_IX : DHCP_ONLY_IX; + } + // + // check DHCP or proxy + // + if (DhcpRxBuf->u.Dhcpv4.yiaddr == 0) { + // + // proxy - only need one of each type if not BINL + // and must have at least PXE_TYPE + // + if (TypeIx == BINL_IX) { + Private->BinlProxies[Private->GotProxy[BINL_IX]++] = (UINT8) NumOffers; + } else if (Private->GotProxy[TypeIx]) { + continue; + } else { + Private->GotProxy[TypeIx] = (UINT8) (NumOffers + 1); + } + } else { + Private->OfferCount[TypeIx][Private->ServerCount[TypeIx]++] = (UINT8) NumOffers; + } + } + + if (++NumOffers == MAX_OFFERS) { + break; + } + } + + gBS->CloseEvent (TimeoutEvent); + Private->NumOffersReceived = NumOffers; + + return (Private->NumOffersReceived) ? EFI_SUCCESS : EFI_NO_RESPONSE; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +// +// send DHCPDECLINE +// +STATIC +VOID +DeclineOffer ( + PXE_BASECODE_DEVICE *Private + ) +{ + EFI_PXE_BASE_CODE_MODE *PxebcMode; + UINT16 SaveSecs; + + PxebcMode = Private->EfiBc.Mode; + SaveSecs = DHCPV4_TRANSMIT_BUFFER.secs; + + DHCPV4_TRANSMIT_BUFFER.secs = 0; + DHCPV4_TRANSMIT_BUFFER.flags = 0; + SetMem ( + DHCPV4_TRANSMIT_BUFFER.options + sizeof (struct opdeclinestr), + sizeof (DHCPOpStart) - sizeof (struct opdeclinestr), + OP_PAD + ); + DHCPDECLINEoptions.DhcpMessageType.Type = DHCPDECLINE; + CopyMem (&DHCPDECLINEoptions.OpDeclineEnd, &DHCP_REQ_OPTIONS, sizeof (struct requestopendstr)); + // DHCPDECLINEoptions.OpDeclineEnd = DHCP_REQ_OPTIONS; + + { + EFI_IP_ADDRESS TmpIp; + + CopyMem (&TmpIp, &DHCP_REQ_OPTIONS.DhcServerIpPtr.Ip, sizeof TmpIp); + + DoUdpWrite ( + Private, + &TmpIp, + &DhcpServerPort, + &PxebcMode->StationIp, + &DHCPClientPort + ); + } + + InitDhcpv4TxBuf (Private); + DHCPV4_TRANSMIT_BUFFER.secs = SaveSecs; + Private->GoodStationIp = FALSE; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +// +// send DHCPRELEASE +// +STATIC +BOOLEAN +Release ( + PXE_BASECODE_DEVICE *Private + ) +{ + EFI_PXE_BASE_CODE_MODE *PxebcMode; + UINT16 SaveSecs; + DHCPV4_OP_SERVER_IP *Point; + + PxebcMode = Private->EfiBc.Mode; + SaveSecs = DHCPV4_TRANSMIT_BUFFER.secs; + DHCPV4_TRANSMIT_BUFFER.secs = 0; + + SetMem ( + DHCPV4_TRANSMIT_BUFFER.options + sizeof (struct opreleasestr), + sizeof (DHCPOpStart) - sizeof (struct opreleasestr), + OP_PAD + ); + + DHCPRELEASEoptions.DhcpMessageType.Type = DHCPRELEASE; + Point = (DHCPV4_OP_SERVER_IP *) DHCPV4_ACK_BUFFER.OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1]; + CopyMem ( + &DHCPRELEASEoptions.DhcServerIpPtr, + &Point, + sizeof DHCPRELEASEoptions.DhcServerIpPtr + ); + + DHCPRELEASEoptions.End[0] = OP_END; + + { + EFI_IP_ADDRESS TmpIp; + + CopyMem (&TmpIp, &DHCPRELEASEoptions.DhcServerIpPtr.Ip, sizeof TmpIp); + + DoUdpWrite ( + Private, + &TmpIp, + &DhcpServerPort, + &PxebcMode->StationIp, + &DHCPClientPort + ); + } + + InitDhcpv4TxBuf (Private); + + DHCPV4_TRANSMIT_BUFFER.secs = SaveSecs; + Private->GoodStationIp = FALSE; + return FALSE; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +STATIC +BOOLEAN +GetBINLAck ( + PXE_BASECODE_DEVICE *Private, + EFI_IP_ADDRESS *ServerIpPtr + ) +{ + DHCP_RECEIVE_BUFFER *DhcpRxBuf; + EFI_STATUS StatCode; + EFI_EVENT TimeoutEvent; + + // + // + // + StatCode = gBS->CreateEvent ( + EFI_EVENT_TIMER, + EFI_TPL_CALLBACK, + NULL, + NULL, + &TimeoutEvent + ); + + if (EFI_ERROR (StatCode)) { + return FALSE; + } + + StatCode = gBS->SetTimer ( + TimeoutEvent, + TimerRelative, + Private->Timeout * 10000000 + 1000000 + ); + + if (EFI_ERROR (StatCode)) { + gBS->CloseEvent (TimeoutEvent); + return FALSE; + } + // + // + // + DhcpRxBuf = &PXE_BINL_BUFFER; + + for (;;) { + EFI_PXE_BASE_CODE_UDP_PORT BINLSrvPort; + + BINLSrvPort = 0; + + if (GetOfferAck ( + Private, + AckEdit, + EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT, + ServerIpPtr, + &BINLSrvPort, + &Private->EfiBc.Mode->StationIp, + &PSEUDO_DHCP_CLIENT_PORT, + DhcpRxBuf, + TimeoutEvent + ) != EFI_SUCCESS) { + break; + } + // + // make sure from whom we wanted + // + if (!DhcpRxBuf->u.Dhcpv4.yiaddr && !CompareMem ( + &ServerIpPtr->v4, + &((DHCPV4_OP_SERVER_IP *) DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip, + sizeof (ServerIpPtr->v4) + )) { + gBS->CloseEvent (TimeoutEvent); + // + // got an ACK from server + // + return TRUE; + } + } + + gBS->CloseEvent (TimeoutEvent); + return FALSE; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +// +// make sure we can get BINL +// send DHCPREQUEST to PXE server +// +STATIC +BOOLEAN +TryBINL ( + PXE_BASECODE_DEVICE *Private, + INTN OfferIx + ) +{ + DHCP_RECEIVE_BUFFER *DhcpRxBuf; + EFI_IP_ADDRESS ServerIp; + UINT16 SaveSecs; + INTN Index; + + DhcpRxBuf = &RxBuf[OfferIx]; + + // + // send DHCP request + // if fail return false + // + CopyMem ( + ((EFI_IPv4_ADDRESS *) &ServerIp), + &((DHCPV4_OP_SERVER_IP *) DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip, + sizeof (EFI_IPv4_ADDRESS) + ); + + // + // client IP address - filled in by client if it knows it + // + CopyMem ( + ((EFI_IPv4_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr), + &DHCP_REQ_OPTIONS.OpReqIP.Ip, + sizeof (EFI_IPv4_ADDRESS) + ); + + SetMem (&DHCP_REQ_OPTIONS, sizeof DHCP_REQ_OPTIONS, OP_PAD); + DHCPV4_TRANSMIT_BUFFER.flags = 0; + DHCPV4_OPTIONS_BUFFER.End[0] = OP_END; + AddRouters (Private, DhcpRxBuf); + SaveSecs = DHCPV4_TRANSMIT_BUFFER.secs; + + for (Index = 0; Index < 3; Private->TotalSeconds = (UINT16) (Private->TotalSeconds + Private->Timeout), ++Index) { + DHCPV4_TRANSMIT_BUFFER.secs = HTONS (Private->TotalSeconds); + + // + // unicast DHCPREQUEST to PXE server + // + if (DoUdpWrite ( + Private, + &ServerIp, + &PseudoDhcpServerPort, + (EFI_IP_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr, + &PSEUDO_DHCP_CLIENT_PORT + ) != EFI_SUCCESS) { + break; + } + + if (!GetBINLAck (Private, &ServerIp)) { + continue; + } + // + // early exit failures + // make sure a good ACK + // + if (!DHCPOfferAckEdit (&PXE_BINL_BUFFER) || ( + !(PXE_BINL_BUFFER.OpAdds.Status & DISCOVER_TYPE) && !PXE_BINL_BUFFER.OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1] + ) + ) { + break; + } + + Private->EfiBc.Mode->ProxyOfferReceived = TRUE; + return TRUE; + } + // + // failed - reset seconds field, etc. + // + Private->EfiBc.Mode->RouteTableEntries = 0; + // + // reset + // + DHCPV4_TRANSMIT_BUFFER.secs = SaveSecs; + return FALSE; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +STATIC +BOOLEAN +TryFinishBINL ( + PXE_BASECODE_DEVICE *Private, + INTN OfferIx + ) +{ + if (TryBINL (Private, OfferIx)) { + return TRUE; + } + + return Release (Private); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +STATIC +BOOLEAN +TryFinishProxyBINL ( + PXE_BASECODE_DEVICE *Private + ) +{ + INTN Index; + + for (Index = 0; Index < Private->GotProxy[BINL_IX]; ++Index) { + if (TryBINL (Private, Private->BinlProxies[Index])) { + return TRUE; + } + } + + return Release (Private); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +// +// try to finish DORA - send DHCP request, wait for ACK, check with ARP +// +STATIC +BOOLEAN +TryFinishDORA ( + PXE_BASECODE_DEVICE *Private, + INTN OfferIx + ) +{ + DHCP_RECEIVE_BUFFER *DhcpRxBuf; + EFI_IP_ADDRESS ClientIp; + EFI_IP_ADDRESS ServerIp; + EFI_STATUS StatCode; + UNION_PTR LocalPtr; + EFI_EVENT TimeoutEvent; + + // + // send DHCP request + // if fail return false + // + DhcpRxBuf = &DHCPV4_ACK_BUFFER; + DHCPV4_OPTIONS_BUFFER.DhcpMessageType.Type = DHCPREQUEST; + CopyMem (&DHCP_REQ_OPTIONS, &RequestOpEndStr, sizeof (RequestOpEndStr)); +// DHCP_REQ_OPTIONS = RequestOpEndStr; + DHCP_REQ_OPTIONS.OpReqIP.Ip = *(EFI_IPv4_ADDRESS *) &RxBuf[OfferIx].u.Dhcpv4.yiaddr; + + CopyMem ( + &DHCP_REQ_OPTIONS.DhcServerIpPtr.Ip, + &((DHCPV4_OP_SERVER_IP *) RxBuf[OfferIx].OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip, + sizeof DHCP_REQ_OPTIONS.DhcServerIpPtr.Ip + ); + + CopyMem ( + Private->EfiBc.Mode->SubnetMask.Addr, + &DefaultSubnetMask, + 4 + ); + + // + // broadcast DHCPREQUEST + // + if (DoUdpWrite ( + Private, + &BroadcastIP, + &DhcpServerPort, + (EFI_IP_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr, + &DHCPClientPort + ) != EFI_SUCCESS) { + return FALSE; + } + // + // + // + StatCode = gBS->CreateEvent ( + EFI_EVENT_TIMER, + EFI_TPL_CALLBACK, + NULL, + NULL, + &TimeoutEvent + ); + + if (EFI_ERROR (StatCode)) { + return FALSE; + } + + StatCode = gBS->SetTimer ( + TimeoutEvent, + TimerPeriodic, + Private->Timeout * 10000000 + 1000000 + ); + + if (EFI_ERROR (StatCode)) { + gBS->CloseEvent (TimeoutEvent); + return FALSE; + } + // + // wait for ACK + // + for (;;) { + if (GetOfferAck ( + Private, + DHCPAckEdit, + EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP, + &ServerIp, + &DhcpServerPort, + &ClientIp, + &DHCPClientPort, + DhcpRxBuf, + TimeoutEvent + ) != EFI_SUCCESS) { + break; + } + // + // check type of response - need DHCPACK + // + if (CompareMem ( + &DHCP_REQ_OPTIONS.OpReqIP.Ip, + &DhcpRxBuf->u.Dhcpv4.yiaddr, + sizeof (EFI_IPv4_ADDRESS) + ) || CompareMem ( + &DHCP_REQ_OPTIONS.DhcServerIpPtr.Ip, + &((DHCPV4_OP_SERVER_IP *) DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip, + sizeof (EFI_IPv4_ADDRESS) + )) { + continue; + } + // + // got ACK + // check with ARP that IP unused - good return true + // + if (!SetStationIP (Private)) { + // + // fail - send DHCPDECLINE and return false + // + DeclineOffer (Private); + break; + } + + LocalPtr.OpPtr = DHCPV4_ACK_BUFFER.OpAdds.PktOptAdds[OP_SUBNET_MASK_IX - 1]; + + if (LocalPtr.OpPtr != NULL) { + CopyMem ( + (EFI_IPv4_ADDRESS *) &Private->EfiBc.Mode->SubnetMask, + &LocalPtr.SubnetMaskStr->Ip, + sizeof (EFI_IPv4_ADDRESS) + ); + } + + AddRouters (Private, DhcpRxBuf); + gBS->CloseEvent (TimeoutEvent); + return TRUE; + } + + gBS->CloseEvent (TimeoutEvent); + return FALSE; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +// +// try a DHCP server of appropriate type +// +STATIC +BOOLEAN +TryDHCPFinishDORA ( + PXE_BASECODE_DEVICE *Private, + INTN TypeIx + ) +{ + INTN Index; + + // + // go through the DHCP servers of the requested type + // + for (Index = 0; Index < Private->ServerCount[TypeIx]; ++Index) { + if (TryFinishDORA (Private, Index = Private->OfferCount[TypeIx][Index])) { + if (TypeIx == BINL_IX && !TryFinishBINL (Private, Index)) { + continue; + } + + return TRUE; + } + } + + return FALSE; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +// +// try a DHCP only server and a proxy of appropriate type +// +STATIC +BOOLEAN +TryProxyFinishDORA ( + PXE_BASECODE_DEVICE *Private, + INTN TypeIx + ) +{ + INTN Index; + + if (!Private->GotProxy[TypeIx]) { + // + // no proxies of the type wanted + // + return FALSE; + } + // + // go through the DHCP only servers + // + for (Index = 0; Index < Private->ServerCount[DHCP_ONLY_IX]; ++Index) { + if (TryFinishDORA (Private, Private->OfferCount[DHCP_ONLY_IX][Index])) { + if (TypeIx != BINL_IX) { + CopyProxyRxBuf (Private, Private->GotProxy[TypeIx] - 1); + } else if (!TryFinishProxyBINL (Private)) { + // + // if didn't work with this DHCP, won't work with any + // + return FALSE; + } + + return TRUE; + } + } + + return FALSE; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +// +// getting to the bottom of the barrel +// +STATIC +BOOLEAN +TryAnyWithBootfileFinishDORA ( + PXE_BASECODE_DEVICE *Private + ) +{ + // + // try a DHCP only server who has a bootfile + // + UNION_PTR LocalPtr; + INTN Index; + + for (Index = 0; Index < Private->ServerCount[DHCP_ONLY_IX]; ++Index) { + INTN offer; + + offer = Private->OfferCount[DHCP_ONLY_IX][Index]; + + if (RxBuf[offer].OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1] && TryFinishDORA (Private, offer)) { + return TRUE; + } + } + // + // really at bottom - see if be have any bootps + // + if (!Private->GotBootp) { + return FALSE; + } + + DHCP_REQ_OPTIONS.OpReqIP.Ip = *(EFI_IPv4_ADDRESS *) &RxBuf[Private->GotBootp - 1].u.Dhcpv4.yiaddr; + + if (!SetStationIP (Private)) { + return FALSE; + } + // + // treat BOOTP response as DHCP ACK packet + // + CopyParseRxBuf (Private, Private->GotBootp - 1, DHCPV4_ACK_INDEX); + + LocalPtr.OpPtr = RxBuf[Private->GotBootp - 1].OpAdds.PktOptAdds[OP_SUBNET_MASK_IX - 1]; + + if (LocalPtr.OpPtr != NULL) { + *(EFI_IPv4_ADDRESS *) &Private->EfiBc.Mode->SubnetMask = LocalPtr.SubnetMaskStr->Ip; + } + + return TRUE; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* DoDhcpDora() + */ +STATIC +EFI_STATUS +DoDhcpDora ( + PXE_BASECODE_DEVICE *Private, + BOOLEAN SortOffers + ) +{ + EFI_PXE_BASE_CODE_IP_FILTER Filter; + EFI_STATUS StatCode; + INTN NumOffers; + + Filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP | EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST; + + Filter.IpCnt = 0; + Filter.reserved = 0; + + // + // set filter unicast or broadcast + // + if ((StatCode = IpFilter (Private, &Filter)) != EFI_SUCCESS) { + return StatCode; + } + // + // seed random number with hardware address + // + SeedRandom (Private, *(UINT16 *) &Private->SimpleNetwork->Mode->CurrentAddress); + + for (Private->Timeout = 1; + Private->Timeout < 17; + Private->TotalSeconds = (UINT16) (Private->TotalSeconds + Private->Timeout), Private->Timeout <<= 1 + ) { + INTN Index; + + InitDhcpv4TxBuf (Private); + DHCPV4_TRANSMIT_BUFFER.xid = Random (Private); + DHCPV4_TRANSMIT_BUFFER.secs = HTONS (Private->TotalSeconds); + + // + // broadcast DHCPDISCOVER + // + StatCode = DoUdpWrite ( + Private, + &BroadcastIP, + &DhcpServerPort, + (EFI_IP_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr, + &DHCPClientPort + ); + + if (StatCode != EFI_SUCCESS) { + return StatCode; + } + + CopyMem ( + &Private->EfiBc.Mode->DhcpDiscover, + (EFI_PXE_BASE_CODE_PACKET *) &DHCPV4_TRANSMIT_BUFFER, + sizeof (EFI_PXE_BASE_CODE_PACKET) + ); + + // + // get DHCPOFFER's + // + if ((StatCode = GetOffers (Private)) != EFI_SUCCESS) { + if (StatCode != EFI_NO_RESPONSE) { + return StatCode; + } + + continue; + } + // + // select offer and reply DHCPREQUEST + // + if (SortOffers) { + if (TryDHCPFinishDORA(Private, PXE10_IX) || // try DHCP with PXE10 + TryDHCPFinishDORA(Private, WfM11a_IX) || // no - try with WfM + TryProxyFinishDORA(Private, PXE10_IX) || // no - try DHCP only and proxy with PXE10 + TryProxyFinishDORA(Private, WfM11a_IX) || // no - try DHCP only and proxy with WfM + TryDHCPFinishDORA(Private, BINL_IX) || // no - try with WfM + TryProxyFinishDORA(Private, BINL_IX) || // no - try DHCP only and proxy with PXE10 + TryAnyWithBootfileFinishDORA(Private)) + { + return EFI_SUCCESS; + } + + continue; + } + // + // FIFO order + // + NumOffers = Private->NumOffersReceived; + + for (Index = 0; Index < NumOffers; ++Index) { + // + // ignore proxies + // + if (!RxBuf[Index].u.Dhcpv4.yiaddr) { + continue; + } + // + // check if a bootp server + // + if (!RxBuf[Index].OpAdds.PktOptAdds[OP_DHCP_MESSAGE_TYPE_IX - 1]) { + // + // it is - just check ARP + // + if (!SetStationIP (Private)) { + continue; + } + } + // + // else check if a DHCP only server + // + else if (!(RxBuf[Index].OpAdds.Status & (DISCOVER_TYPE | WfM11a_TYPE | PXE_TYPE))) { + // + // it is a normal DHCP offer (without any PXE options), just finish the D.O.R.A by sending DHCP request. + // + if (!TryFinishDORA (Private, Index)) { + continue; + } + } else if (TryFinishDORA (Private, Index)) { + if (!(RxBuf[Index].OpAdds.Status & (DISCOVER_TYPE | WfM11a_TYPE)) && !TryFinishBINL (Private, Index)) { + continue; + } + } + + DEBUG ((EFI_D_WARN, "\nDoDhcpDora() Got packets. ")); + return EFI_SUCCESS; + } + // + // now look for DHCP onlys and a Proxy + // + for (Index = 0; Index < NumOffers; ++Index) { + INT8 Index2; + + // + // ignore proxies, bootps, non DHCP onlys, and bootable DHCPS + // + if (!RxBuf[Index].u.Dhcpv4.yiaddr || + !RxBuf[Index].OpAdds.PktOptAdds[OP_DHCP_MESSAGE_TYPE_IX - 1] || + RxBuf[Index].OpAdds.Status & (DISCOVER_TYPE | WfM11a_TYPE | PXE_TYPE) || + RxBuf[Index].OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1] + ) { + continue; + } + // + // found non bootable DHCP only - try to find a proxy + // + for (Index2 = 0; Index2 < NumOffers; ++Index2) { + if (!RxBuf[Index2].u.Dhcpv4.yiaddr) { + if (!TryFinishDORA (Private, Index)) { + // + // DHCP no ACK + // + break; + } + + if (RxBuf[Index2].OpAdds.Status & (DISCOVER_TYPE | WfM11a_TYPE)) { + CopyProxyRxBuf (Private, Index2); + } else if (!TryFinishBINL (Private, Index2)) { + continue; + } + + DEBUG ((EFI_D_WARN, "\nDoDhcpDora() Got packets. ")); + return EFI_SUCCESS; + } + } + } + } + + return EFI_NO_RESPONSE; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +// +// determine if the server ip is in the ip list +// +BOOLEAN +InServerList ( + EFI_IP_ADDRESS *ServerIpPtr, + PXE_SERVER_LISTS *ServerListPtr + ) +{ + UINTN Index; + + if (!ServerListPtr || !ServerListPtr->Ipv4List.IpCount) { + return TRUE; + } + + for (Index = 0; Index < ServerListPtr->Ipv4List.IpCount; ++Index) { + if (!CompareMem ( + ServerIpPtr, + &ServerListPtr->Ipv4List.IpList[Index], + sizeof (EFI_IPv4_ADDRESS) + )) { + return TRUE; + } + } + + return FALSE; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +BOOLEAN +ExtractBootServerList ( + UINT16 Type, + DHCPV4_OP_STRUCT *ptr, + PXE_SERVER_LISTS **ServerListPtr + ) +{ + UNION_PTR LocalPtr; + INTN ServerListLen; + + LocalPtr.OpPtr = ptr; + ServerListLen = LocalPtr.BootServersStr->Header.Length; + + // + // find type + // + LocalPtr.BootServerList = LocalPtr.BootServersStr->ServerList; + + while (ServerListLen) { + INTN ServerEntryLen; + + ServerEntryLen = sizeof (PXEV4_SERVER_LIST) + 2 + (LocalPtr.BootServerList->u.Ipv4List.IpCount - 1) * + sizeof (EFI_IPv4_ADDRESS); + + if (NTOHS (LocalPtr.BootServerList->Type) == Type) { + *ServerListPtr = &LocalPtr.BootServerList->u; + return TRUE; + } + + (LocalPtr.BytePtr) += ServerEntryLen; + ServerListLen -= ServerEntryLen; + } + + return FALSE; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +VOID +FreeMem ( + PXE_BASECODE_DEVICE *Private + ) +{ + if (Private->TransmitBuffer != NULL) { + gBS->FreePool (Private->TransmitBuffer); + Private->TransmitBuffer = NULL; + } + + if (Private->ReceiveBuffers != NULL) { + gBS->FreePool (Private->ReceiveBuffers); + Private->ReceiveBuffers = NULL; + } +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +BOOLEAN +GetMem ( + PXE_BASECODE_DEVICE *Private + ) +{ + EFI_STATUS Status; + + if (Private->DhcpPacketBuffer == NULL) { + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (DHCP_RECEIVE_BUFFER) * (PXE_BIS_INDEX + 1), + &Private->DhcpPacketBuffer + ); + + if (EFI_ERROR (Status) || Private->DhcpPacketBuffer == NULL) { + Private->DhcpPacketBuffer = NULL; + FreeMem (Private); + return FALSE; + } + } + + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (EFI_PXE_BASE_CODE_PACKET), + &Private->TransmitBuffer + ); + + if (EFI_ERROR (Status) || Private->TransmitBuffer == NULL) { + gBS->FreePool (Private->DhcpPacketBuffer); + Private->DhcpPacketBuffer = NULL; + Private->TransmitBuffer = NULL; + FreeMem (Private); + return FALSE; + } + + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (DHCP_RECEIVE_BUFFER) * (MAX_OFFERS), + &Private->ReceiveBuffers + ); + + if (EFI_ERROR (Status) || Private->ReceiveBuffers == NULL) { + gBS->FreePool (Private->TransmitBuffer); + gBS->FreePool (Private->DhcpPacketBuffer); + Private->DhcpPacketBuffer = NULL; + Private->TransmitBuffer = NULL; + Private->ReceiveBuffers = NULL; + FreeMem (Private); + return FALSE; + } + + return TRUE; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +EFI_STATUS +EFIAPI +BcDhcp ( + IN EFI_PXE_BASE_CODE_PROTOCOL *This, + IN BOOLEAN SortOffers + ) +/*++ +Routine description: + standard DHCP Discover/Offer/Request/Ack session + broadcast DHCPDISCOVER + receive DHCPOFFER's + broadcast DHCPREQUEST + receive DHCPACK + check (ARP) good IP + +Parameters: + This := Pointer to PxeBc interface + SortOffers := + +Returns: +--*/ +{ + EFI_PXE_BASE_CODE_IP_FILTER Filter; + EFI_PXE_BASE_CODE_MODE *PxebcMode; + PXE_BASECODE_DEVICE *Private; + EFI_STATUS StatCode; + + // + // Lock the instance data and make sure started + // + StatCode = EFI_SUCCESS; + + if (This == NULL) { + DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL")); + return EFI_INVALID_PARAMETER; + } + + Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE); + + if (Private == NULL) { + DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE pointer == NULL")); + return EFI_INVALID_PARAMETER; + } + + EfiAcquireLock (&Private->Lock); + + if (This->Mode == NULL || !This->Mode->Started) { + DEBUG ((EFI_D_ERROR, "BC was not started.")); + EfiReleaseLock (&Private->Lock); + return EFI_NOT_STARTED; + } + + Filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP; + Filter.IpCnt = 0; + Filter.reserved = 0; + + DEBUG ((EFI_D_INFO, "\nBcDhcp() Enter. ")); + + PxebcMode = Private->EfiBc.Mode; + + if (!GetMem (Private)) { + DEBUG ((EFI_D_ERROR, "\nBcDhcp() GetMem() failed.\n")); + EfiReleaseLock (&Private->Lock); + return EFI_OUT_OF_RESOURCES; + } + + PxebcMode->DhcpDiscoverValid = FALSE; + PxebcMode->DhcpAckReceived = FALSE; + PxebcMode->ProxyOfferReceived = FALSE; + + Private->Function = EFI_PXE_BASE_CODE_FUNCTION_DHCP; + + // + // Issue BC command + // + if (Private->TotalSeconds == 0) { + // + // put in seconds field of DHCP send packets + // + Private->TotalSeconds = 4; + } + + if ((StatCode = DoDhcpDora (Private, SortOffers)) == EFI_SUCCESS) { + // + // success - copy packets + // + PxebcMode->DhcpDiscoverValid = PxebcMode->DhcpAckReceived = TRUE; + + CopyMem ( + &PxebcMode->DhcpAck, + (EFI_PXE_BASE_CODE_PACKET *) &DHCPV4_ACK_PACKET, + sizeof (EFI_PXE_BASE_CODE_PACKET) + ); + + if (PxebcMode->ProxyOfferReceived) { + CopyMem ( + &PxebcMode->ProxyOffer, + (EFI_PXE_BASE_CODE_PACKET *) &PXE_OFFER_PACKET, + sizeof (EFI_PXE_BASE_CODE_PACKET) + ); + } + } + // + // set filter back to unicast + // + IpFilter (Private, &Filter); + + FreeMem (Private); + + // + // Unlock the instance data + // + DEBUG ((EFI_D_WARN, "\nBcDhcp() Exit = %xh ", StatCode)); + + EfiReleaseLock (&Private->Lock); + return StatCode; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +STATIC +BOOLEAN +VerifyCredentialOption ( + UINT8 *tx, + UINT8 *rx + ) +{ + UINTN n; + + // + // Fail verification if either pointer is NULL. + // + if (tx == NULL || rx == NULL) { + return FALSE; + } + // + // Fail verification if tx[0] is not a credential type option + // or if the length is zero or not a multiple of four. + // + if (tx[0] != VEND_PXE_CREDENTIAL_TYPES || tx[1] == 0 || tx[1] % 4 != 0) { + return FALSE; + } + // + // Fail verification if rx[0] is not a credential type option + // or if the length is not equal to four. + // + if (rx[0] != VEND_PXE_CREDENTIAL_TYPES || rx[1] != 4) { + return FALSE; + } + // + // Look through transmitted credential types for a copy + // of the received credential type. + // + for (n = 0; n < tx[1]; n += 4) { + if (!CompareMem (&tx[n + 2], &rx[2], 4)) { + return TRUE; + } + } + + return FALSE; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +EFI_STATUS +DoDiscover ( + PXE_BASECODE_DEVICE *Private, + UINT16 OpFlags, + IN UINT16 Type, + IN UINT16 *LayerPtr, + IN BOOLEAN UseBis, + EFI_IP_ADDRESS *DestPtr, + PXE_SERVER_LISTS *ServerListPtr + ) +/*++ +Routine description: + This function tries to complete the PXE Bootserver and/or boot image + discovery sequence. When this command completes successfully, the + PXEdiscover and PXEreply fields in the BC instance data structure are + updated. If the Info pointer is set to NULL, the discovery information + in the DHCPack and ProxyOffer packets must be valid and will be used. + If Info is not set to NULL, the discovery methods in the Info field + must be set and will be used. When discovering any layer number other + than zero (the credential flag does not count), only unicast discovery + is used. + +Parameters: + Private := Pointer to PxeBc interface + OpFlags := + Type := + LayerPtr := + UseBis := + DestPtr := + ServerListPtr := + +Returns: +--*/ +{ + EFI_PXE_BASE_CODE_UDP_PORT ClientPort; + EFI_PXE_BASE_CODE_UDP_PORT ServerPort; + EFI_PXE_BASE_CODE_MODE *PxebcMode; + EFI_STATUS StatCode; + EFI_EVENT TimeoutEvent; + UINT8 OpLen; + + PxebcMode = Private->EfiBc.Mode; + + if (DestPtr->Addr[0] == 0) { + DEBUG ((EFI_D_WARN, "\nDoDiscover() !DestPtr->Addr[0]")); + return EFI_INVALID_PARAMETER; + } + // + // seed random number with hardware address + // + SeedRandom (Private, *(UINT16 *) &Private->SimpleNetwork->Mode->CurrentAddress); + + if (DestPtr->Addr[0] == BroadcastIP.Addr[0]) { + ClientPort = DHCPClientPort; + ServerPort = DhcpServerPort; + } else { + ClientPort = PSEUDO_DHCP_CLIENT_PORT; + ServerPort = PseudoDhcpServerPort; + } + + if (UseBis) { + *LayerPtr |= PXE_BOOT_LAYER_CREDENTIAL_FLAG; + } else { + *LayerPtr &= PXE_BOOT_LAYER_MASK; + } + + for (Private->Timeout = 1; + Private->Timeout < 5; + Private->TotalSeconds = (UINT16) (Private->TotalSeconds + Private->Timeout), ++Private->Timeout + ) { + InitDhcpv4TxBuf (Private); + // + // initialize DHCP message structure + // + DHCPV4_TRANSMIT_BUFFER.xid = Random (Private); + DHCPV4_TRANSMIT_BUFFER.secs = HTONS (Private->TotalSeconds); + CopyMem ( + &DHCPV4_TRANSMIT_BUFFER.ciaddr, + &PxebcMode->StationIp, + sizeof DHCPV4_TRANSMIT_BUFFER.ciaddr + ); + + DHCPV4_OPTIONS_BUFFER.DhcpMessageType.Type = DHCPREQUEST; + DISCOVERoptions.Header.OpCode = OP_VENDOR_SPECIFIC; + DISCOVERoptions.BootItem.Header.OpCode = VEND_PXE_BOOT_ITEM; + DISCOVERoptions.BootItem.Header.Length = DHCPV4_OPTION_LENGTH (PXE_OP_BOOT_ITEM); + DISCOVERoptions.BootItem.Type = HTONS (Type); + DISCOVERoptions.BootItem.Layer = HTONS (*LayerPtr); + + if (UseBis) { + EFI_BIS_PROTOCOL *BisPtr; + BIS_APPLICATION_HANDLE BisAppHandle; + EFI_BIS_DATA *BisDataSigInfo; + EFI_BIS_SIGNATURE_INFO *BisSigInfo; + UINTN Index; + UINTN Index2; + + BisPtr = PxebcBisStart ( + Private, + &BisAppHandle, + &BisDataSigInfo + ); + + if (BisPtr == NULL) { + // + // %%TBD - In order to get here, BIS must have + // been present when PXEBC.Start() was called. + // BIS had to be shutdown/removed/damaged + // before PXEBC.Discover() was called. + // Do we need to document a specific error + // for this case? + // + return EFI_OUT_OF_RESOURCES; + } + // + // Compute number of credential types. + // + Index2 = BisDataSigInfo->Length / sizeof (EFI_BIS_SIGNATURE_INFO); + + DISCREDoptions.Header.OpCode = VEND_PXE_CREDENTIAL_TYPES; + + DISCREDoptions.Header.Length = (UINT8) (Index2 * sizeof (PXE_CREDENTIAL)); + + OpLen = (UINT8) (DHCPV4_OPTION_LENGTH (PXE_DISCOVER_OPTIONS) + sizeof (DHCPV4_OP_HEADER) + DISCREDoptions.Header.Length); + + BisSigInfo = (EFI_BIS_SIGNATURE_INFO *) BisDataSigInfo->Data; + + for (Index = 0; Index < Index2; ++Index) { + UINT32 x; + + CopyMem (&x, &BisSigInfo[Index], sizeof x); + x = HTONL (x); + CopyMem (&DISCREDoptions.Credentials[Index], &x, sizeof x); + } + + PxebcBisStop (BisPtr, BisAppHandle, BisDataSigInfo); + } else { + OpLen = DHCPV4_OPTION_LENGTH (PXE_DISCOVER_OPTIONS); + } + + DISCOVERoptions.Header.Length = OpLen; + + ((UINT8 *) &DISCOVERoptions)[sizeof (DHCPV4_OP_HEADER) + OpLen - 1] = OP_END; + ((UINT8 *) &DISCOVERoptions)[sizeof (DHCPV4_OP_HEADER) + OpLen] = OP_END; + + StatCode = DoUdpWrite ( + Private, + DestPtr, + &ServerPort, + (EFI_IP_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr, + &ClientPort + ); + + if (StatCode != EFI_SUCCESS) { + return StatCode; + } + // + // + // + StatCode = gBS->CreateEvent ( + EFI_EVENT_TIMER, + EFI_TPL_CALLBACK, + NULL, + NULL, + &TimeoutEvent + ); + + if (EFI_ERROR (StatCode)) { + return StatCode; + } + + StatCode = gBS->SetTimer ( + TimeoutEvent, + TimerRelative, + Private->Timeout * 10000000 + 1000000 + ); + + if (EFI_ERROR (StatCode)) { + gBS->CloseEvent (TimeoutEvent); + return StatCode; + } + // + // wait for ACK + // + for (;;) { + DHCP_RECEIVE_BUFFER *RxBufPtr; + UINT16 TmpType; + UINT16 TmpLayer; + + RxBufPtr = UseBis ? &PXE_BIS_BUFFER : &PXE_ACK_BUFFER; + ZeroMem (&Private->ServerIp, sizeof (EFI_IP_ADDRESS)); + + if (GetOfferAck ( + Private, + AckEdit, + OpFlags, + (EFI_IP_ADDRESS *) &Private->ServerIp, + 0, + (EFI_IP_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr, + &ClientPort, + RxBufPtr, + TimeoutEvent + ) != EFI_SUCCESS) { + break; + } + // + // check type of response - need PXEClient DHCPACK of proper type with bootfile + // + if (!(RxBufPtr->OpAdds.Status & PXE_TYPE) || + (UseBis && (RxBufPtr->OpAdds.Status & USE_THREE_BYTE)) || + !RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1] || + !RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1] || + !InServerList((EFI_IP_ADDRESS *)&((DHCPV4_OP_SERVER_IP *)RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX-1])->Ip, ServerListPtr)) { + + continue; + } + + TmpType = TmpLayer = 0; + + if (RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1]) { + TmpType = NTOHS (((PXE_OP_BOOT_ITEM *) RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1])->Type); + + if (RxBufPtr->OpAdds.Status & USE_THREE_BYTE) { + TmpLayer = (UINT16) (((PXE_OP_BOOT_ITEM *) RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1])->Layer >> 8); + } else { + TmpLayer = NTOHS (((PXE_OP_BOOT_ITEM *) RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1])->Layer); + } + } + + if (TmpType != Type) { + continue; + } + + if (UseBis) { + if (!RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_CREDENTIAL_TYPES_IX - 1]) { + continue; + } + + if (!VerifyCredentialOption ( + (UINT8 *) &DISCREDoptions.Header, + (UINT8 *) RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_CREDENTIAL_TYPES_IX - 1] + )) { + continue; + } + } + + *LayerPtr = TmpLayer; + + if (UseBis) { + CopyMem ( + &PxebcMode->PxeBisReply, + &RxBufPtr->u.Dhcpv4, + sizeof (EFI_PXE_BASE_CODE_PACKET) + ); + + PxebcMode->PxeBisReplyReceived = TRUE; + + StatCode = DoDiscover ( + Private, + EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT, + Type, + LayerPtr, + FALSE, + &Private->ServerIp, + 0 + ); + + gBS->CloseEvent (TimeoutEvent); + return StatCode; + } + + PxebcMode->PxeDiscoverValid = PxebcMode->PxeReplyReceived = TRUE; + + CopyMem ( + &PxebcMode->PxeDiscover, + &*(EFI_PXE_BASE_CODE_PACKET *) &DHCPV4_TRANSMIT_BUFFER, + sizeof (*(EFI_PXE_BASE_CODE_PACKET *) &DHCPV4_TRANSMIT_BUFFER) + ); + + CopyMem ( + &PxebcMode->PxeReply, + &*(EFI_PXE_BASE_CODE_PACKET *) &RxBufPtr->u.Dhcpv4, + sizeof (*(EFI_PXE_BASE_CODE_PACKET *) &RxBufPtr->u.Dhcpv4) + ); + + AddRouters (Private, RxBufPtr); + + gBS->CloseEvent (TimeoutEvent); + return EFI_SUCCESS; + } + + gBS->CloseEvent (TimeoutEvent); + } + // + // end for loop + // + return EFI_TIMEOUT; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +STATIC +EFI_STATUS +Discover ( + PXE_BASECODE_DEVICE *Private, + IN UINT16 Type, + IN UINT16 *LayerPtr, + IN BOOLEAN UseBis, + IN EFI_PXE_BASE_CODE_DISCOVER_INFO *DiscoverInfoPtr, + PXE_SERVER_LISTS *McastServerListPtr, + PXE_SERVER_LISTS *ServerListPtr + ) +/*++ +Routine Description: + +Parameters: + Private := Pointer to PxeBc interface + Type := + LayerPtr := + UseBis := + DiscoverInfoPtr := + McastServerListPtr := + ServerListPtr := + +Returns: +--*/ +{ + EFI_IP_ADDRESS DestIp; + EFI_STATUS StatCode; + + DEBUG ((EFI_D_INFO, "\nDiscover() Type=%d Layer=%d ", Type, *LayerPtr)); + + if (UseBis) { + DEBUG ((EFI_D_INFO, "BIS ")); + } + // + // get dest IP addr - mcast, bcast, or unicast + // + if (DiscoverInfoPtr->UseMCast) { + DestIp.v4 = DiscoverInfoPtr->ServerMCastIp.v4; + + DEBUG ( + (EFI_D_INFO, + "\nDiscover() MCast %d.%d.%d.%d ", + DestIp.v4.Addr[0], + DestIp.v4.Addr[1], + DestIp.v4.Addr[2], + DestIp.v4.Addr[3]) + ); + + if ((StatCode = DoDiscover ( + Private, + EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT, + Type, + LayerPtr, + UseBis, + &DestIp, + McastServerListPtr + )) != EFI_TIMEOUT) { + DEBUG ( + (EFI_D_WARN, + "\nDiscover() status == %r (%Xh)", + StatCode, + StatCode) + ); + + return StatCode; + } + } + + if (DiscoverInfoPtr->UseBCast) { + DEBUG ((EFI_D_INFO, "\nDiscver() BCast ")); + + if ((StatCode = DoDiscover ( + Private, + EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT, + Type, + LayerPtr, + UseBis, + &BroadcastIP, + McastServerListPtr + )) != EFI_TIMEOUT) { + + DEBUG ((EFI_D_WARN, "\nDiscover() status == %r (%Xh)", StatCode, StatCode)); + + return StatCode; + } + } + + if (DiscoverInfoPtr->UseUCast) { + UINTN Index; + + DEBUG ( + (EFI_D_INFO, + "\nDiscover() UCast IP#=%d ", + ServerListPtr->Ipv4List.IpCount) + ); + + for (Index = 0; Index < ServerListPtr->Ipv4List.IpCount; ++Index) { + CopyMem (&DestIp, &ServerListPtr->Ipv4List.IpList[Index], 4); + + DEBUG ( + (EFI_D_INFO, + "\nDiscover() UCast %d.%d.%d.%d ", + DestIp.v4.Addr[0], + DestIp.v4.Addr[1], + DestIp.v4.Addr[2], + DestIp.v4.Addr[3]) + ); + + if ((StatCode = DoDiscover ( + Private, + EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT, + Type, + LayerPtr, + UseBis, + &DestIp, + 0 + )) != EFI_TIMEOUT) { + DEBUG ( + (EFI_D_WARN, + "\nDiscover() status == %r (%Xh)", + StatCode, + StatCode) + ); + + return StatCode; + } + } + } + + DEBUG ((EFI_D_WARN, "\nDiscover() TIMEOUT")); + + return EFI_TIMEOUT; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* BcDiscover() + */ +EFI_STATUS +EFIAPI +BcDiscover ( + IN EFI_PXE_BASE_CODE_PROTOCOL * This, + IN UINT16 Type, + IN UINT16 *LayerPtr, + IN BOOLEAN UseBis, + IN EFI_PXE_BASE_CODE_DISCOVER_INFO * DiscoverInfoPtr OPTIONAL + ) +/*++ +Routine description: + +Parameters: + This := + Type := + LayerPtr := + UseBis := + DiscoverInfoPtr := + +Returns: +--*/ +{ + EFI_PXE_BASE_CODE_DISCOVER_INFO DefaultInfo; + EFI_PXE_BASE_CODE_MODE *PxebcMode; + DHCP_RECEIVE_BUFFER *DhcpRxBuf; + PXE_SERVER_LISTS DefaultSrvList; + PXE_SERVER_LISTS *ServerListPtr; + PXE_SERVER_LISTS *McastServerListPtr; + EFI_STATUS Status; + UNION_PTR LocalPtr; + UINTN Index; + UINTN Index2; + BOOLEAN AcquiredSrvList; + EFI_STATUS StatCode; + PXE_BASECODE_DEVICE *Private; + + // + // Lock the instance data and make sure started + // + StatCode = EFI_SUCCESS; + + if (This == NULL) { + DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL")); + return EFI_INVALID_PARAMETER; + } + + Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE); + + if (Private == NULL) { + DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL")); + return EFI_INVALID_PARAMETER; + } + + EfiAcquireLock (&Private->Lock); + + if (This->Mode == NULL || !This->Mode->Started) { + DEBUG ((EFI_D_ERROR, "BC was not started.")); + EfiReleaseLock (&Private->Lock); + return EFI_NOT_STARTED; + } + + ServerListPtr = NULL; + McastServerListPtr = NULL; + AcquiredSrvList = FALSE; + + PxebcMode = Private->EfiBc.Mode; + + if (!GetMem (Private)) { + EfiReleaseLock (&Private->Lock); + return EFI_OUT_OF_RESOURCES; + } + + if (UseBis) { + if (!PxebcMode->BisSupported) { + EfiReleaseLock (&Private->Lock); + return EFI_INVALID_PARAMETER; + } + } + + Private->Function = EFI_PXE_BASE_CODE_FUNCTION_DISCOVER; + + if (Private->TotalSeconds == 0) { + // + // put in seconds field of DHCP send packets + // + Private->TotalSeconds = 4; + } + + ZeroMem (&DefaultInfo, sizeof (EFI_PXE_BASE_CODE_DISCOVER_INFO)); + + // + // if layer number not zero, use previous discover + // + if (*LayerPtr != 0) { + DEBUG ((EFI_D_WARN, "\nBcDiscover() layer != 0")); + + if (DiscoverInfoPtr != NULL) { + DEBUG ((EFI_D_WARN, "\nBcDiscover() layer != 0 && DiscoverInfoPtr != NULL\n")); + + EfiReleaseLock (&Private->Lock); + return EFI_INVALID_PARAMETER; + } + + if (!PxebcMode->PxeDiscoverValid) { + DEBUG ((EFI_D_WARN, "\nBcDiscover() layer != 0 && PxeDiscoverValid == 0\n")); + + EfiReleaseLock (&Private->Lock); + return EFI_INVALID_PARAMETER; + } + + if (!PxebcMode->PxeReplyReceived) { + DEBUG ((EFI_D_WARN, "\nBcDiscover() layer != 0 && PxeReplyReceived == 0\n")); + + EfiReleaseLock (&Private->Lock); + return EFI_INVALID_PARAMETER; + } + + if (UseBis && !PxebcMode->PxeBisReplyReceived) { + DEBUG ((EFI_D_WARN, "\nBcDiscover() layer != 0 && PxeBisReplyReceived == 0\n")); + + EfiReleaseLock (&Private->Lock); + return EFI_INVALID_PARAMETER; + } + + DefaultInfo.UseUCast = TRUE; + DiscoverInfoPtr = &DefaultInfo; + + DefaultSrvList.Ipv4List.IpCount = 1; + CopyMem (&DefaultSrvList.Ipv4List.IpList[0], &Private->ServerIp, 4); + + ServerListPtr = &DefaultSrvList; + } + // + // layer is zero - see if info is supplied or if we need to use info from a cached offer + // + else if (!DiscoverInfoPtr) { + // + // not supplied - generate it + // make sure that there is cached, appropriate information + // if neither DhcpAck packet nor ProxyOffer packet has pxe info, fail + // + DhcpRxBuf = (PxebcMode->ProxyOfferReceived) ? &PXE_OFFER_BUFFER : &DHCPV4_ACK_BUFFER; + + if (!PxebcMode->DhcpAckReceived || !(DhcpRxBuf->OpAdds.Status & DISCOVER_TYPE)) { + DEBUG ((EFI_D_WARN, "\nBcDiscover() !ack && !proxy")); + EfiReleaseLock (&Private->Lock); + return EFI_INVALID_PARAMETER; + } + + DiscoverInfoPtr = &DefaultInfo; + + LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_CONTROL_IX - 1]; + + // + // if multicast enabled, need multicast address + // + if (!(LocalPtr.DiscoveryControl->ControlBits & DISABLE_MCAST)) { + DefaultInfo.UseMCast = TRUE; + + CopyMem ( + ((EFI_IPv4_ADDRESS *) &DefaultInfo.ServerMCastIp), + &((DHCPV4_OP_IP_ADDRESS *) DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_MCAST_ADDR_IX - 1])->Ip, + sizeof (EFI_IPv4_ADDRESS) + ); + } + + DefaultInfo.UseBCast = (BOOLEAN) ((LocalPtr.DiscoveryControl->ControlBits & DISABLE_BCAST) == 0); + + DefaultInfo.MustUseList = (BOOLEAN) ((LocalPtr.DiscoveryControl->ControlBits & USE_ACCEPT_LIST) != 0); + + DefaultInfo.UseUCast = (BOOLEAN) + ( + (DefaultInfo.MustUseList) || + ((LocalPtr.DiscoveryControl->ControlBits & (DISABLE_MCAST | DISABLE_BCAST)) == (DISABLE_MCAST | DISABLE_BCAST)) + ); + + if ((DefaultInfo.UseUCast | DefaultInfo.MustUseList) && !ExtractBootServerList ( + Type, + DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_SERVERS_IX - 1], + &ServerListPtr + )) { + DEBUG ((EFI_D_WARN, "\nBcDiscover() type not in list")); + EfiReleaseLock (&Private->Lock); + return EFI_INVALID_PARAMETER; + } + } + // + // Info supplied - make SrvList if required + // if we use ucast discovery or must use list, there better be one + // + else if (DiscoverInfoPtr->UseUCast || DiscoverInfoPtr->MustUseList) { + // + // there better be a list + // + if (DiscoverInfoPtr->IpCnt == 0) { + DEBUG ((EFI_D_WARN, "\nBcDiscover() no bootserver list")); + EfiReleaseLock (&Private->Lock); + return EFI_INVALID_PARAMETER; + } + // + // get its size + // + for (Index = Index2 = 0; Index < DiscoverInfoPtr->IpCnt; ++Index) { + if (DiscoverInfoPtr->SrvList[Index].Type == Type) { + if (DiscoverInfoPtr->SrvList[Index].AcceptAnyResponse) { + if (Index2 != 0) { + DEBUG ((EFI_D_WARN, "\nBcDiscover() accept any?")); + EfiReleaseLock (&Private->Lock); + return EFI_INVALID_PARAMETER; + } else { + Index2 = 1; + DefaultSrvList.Ipv4List.IpCount = 0; + ServerListPtr = &DefaultSrvList; + break; + } + } else { + ++Index2; + } + } + } + + if (Index2 == 0) { + DEBUG ((EFI_D_WARN, "\nBcDiscover() !Index2?")); + EfiReleaseLock (&Private->Lock); + return EFI_INVALID_PARAMETER; + } + + if (ServerListPtr == NULL) { + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (PXEV4_SERVER_LIST) + (Index2 - 1) * sizeof (EFI_IPv4_ADDRESS), + (VOID **) &ServerListPtr + ); + + if (EFI_ERROR (Status) || ServerListPtr == NULL) { + ServerListPtr = NULL; + EfiReleaseLock (&Private->Lock); + return EFI_OUT_OF_RESOURCES; + } + // + // build an array of IP addresses from the server list + // + AcquiredSrvList = TRUE; + ServerListPtr->Ipv4List.IpCount = (UINT8) Index2; + + for (Index = Index2 = 0; Index < DiscoverInfoPtr->IpCnt; ++Index) { + if (DiscoverInfoPtr->SrvList[Index].Type == Type) { + CopyMem ( + &ServerListPtr->Ipv4List.IpList[Index2++], + &DiscoverInfoPtr->SrvList[Index].IpAddr.v4, + sizeof ServerListPtr->Ipv4List.IpList[0] + ); + } + } + } + } + + if (DiscoverInfoPtr->MustUseList) { + McastServerListPtr = ServerListPtr; + } + + if (!(DiscoverInfoPtr->UseMCast || DiscoverInfoPtr->UseBCast || DiscoverInfoPtr->UseUCast)) { + DEBUG ((EFI_D_WARN, "\nBcDiscover() Nothing to use!\n")); + + EfiReleaseLock (&Private->Lock); + return EFI_INVALID_PARAMETER; + } + + PxebcMode->PxeDiscoverValid = PxebcMode->PxeReplyReceived = PxebcMode->PxeBisReplyReceived = FALSE; + + StatCode = Discover ( + Private, + Type, + LayerPtr, + UseBis, + DiscoverInfoPtr, + McastServerListPtr, + ServerListPtr + ); + + if (AcquiredSrvList) { + gBS->FreePool (ServerListPtr); + } + + FreeMem (Private); + + // + // Unlock the instance data + // + DEBUG ( + (EFI_D_INFO, + "\nBcDiscover() status == %r (%Xh)\n", + StatCode, + StatCode) + ); + + EfiReleaseLock (&Private->Lock); + return StatCode; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +EFI_STATUS +EFIAPI +BcSetPackets ( + IN EFI_PXE_BASE_CODE_PROTOCOL * This, + BOOLEAN *NewDhcpDiscoverValid, OPTIONAL + BOOLEAN *NewDhcpAckReceived, OPTIONAL + BOOLEAN *NewProxyOfferReceived, OPTIONAL + BOOLEAN *NewPxeDiscoverValid, OPTIONAL + BOOLEAN *NewPxeReplyReceived, OPTIONAL + BOOLEAN *NewPxeBisReplyReceived, OPTIONAL + IN EFI_PXE_BASE_CODE_PACKET * NewDhcpDiscover, OPTIONAL + IN EFI_PXE_BASE_CODE_PACKET * NewDhcpAck, OPTIONAL + IN EFI_PXE_BASE_CODE_PACKET * NewProxyOffer, OPTIONAL + IN EFI_PXE_BASE_CODE_PACKET * NewPxeDiscover, OPTIONAL + IN EFI_PXE_BASE_CODE_PACKET * NewPxeReply, OPTIONAL + IN EFI_PXE_BASE_CODE_PACKET * NewPxeBisReply OPTIONAL + ) +/*++ +Routine description: + +Parameters: + +Returns: +--*/ +{ + EFI_PXE_BASE_CODE_MODE *PxebcMode; + EFI_STATUS Status; + EFI_STATUS StatCode; + PXE_BASECODE_DEVICE *Private; + + // + // Lock the instance data and make sure started + // + StatCode = EFI_SUCCESS; + + if (This == NULL) { + DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL")); + return EFI_INVALID_PARAMETER; + } + + Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE); + + if (Private == NULL) { + DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL")); + return EFI_INVALID_PARAMETER; + } + + EfiAcquireLock (&Private->Lock); + + if (This->Mode == NULL || !This->Mode->Started) { + DEBUG ((EFI_D_ERROR, "BC was not started.")); + EfiReleaseLock (&Private->Lock); + return EFI_NOT_STARTED; + } + + PxebcMode = Private->EfiBc.Mode; + + if (Private->DhcpPacketBuffer == NULL) { + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (DHCP_RECEIVE_BUFFER) * (PXE_BIS_INDEX + 1), + &Private->DhcpPacketBuffer + ); + + if (EFI_ERROR (Status) || Private->DhcpPacketBuffer == NULL) { + Private->DhcpPacketBuffer = NULL; + EfiReleaseLock (&Private->Lock); + return EFI_OUT_OF_RESOURCES; + } + } + // + // Issue BC command + // + // + // reset + // + Private->FileSize = 0; + if (NewDhcpDiscoverValid != NULL) { + PxebcMode->DhcpDiscoverValid = *NewDhcpDiscoverValid; + } + + if (NewDhcpAckReceived != NULL) { + PxebcMode->DhcpAckReceived = *NewDhcpAckReceived; + } + + if (NewProxyOfferReceived != NULL) { + PxebcMode->ProxyOfferReceived = *NewProxyOfferReceived; + } + + if (NewPxeDiscoverValid != NULL) { + PxebcMode->PxeDiscoverValid = *NewPxeDiscoverValid; + } + + if (NewPxeReplyReceived != NULL) { + PxebcMode->PxeReplyReceived = *NewPxeReplyReceived; + } + + if (NewPxeBisReplyReceived != NULL) { + PxebcMode->PxeBisReplyReceived = *NewPxeBisReplyReceived; + } + + if (NewDhcpDiscover != NULL) { + CopyMem ( + &PxebcMode->DhcpDiscover, + NewDhcpDiscover, + sizeof *NewDhcpDiscover + ); + } + + if (NewDhcpAck != NULL) { + CopyParse (Private, &PxebcMode->DhcpAck, NewDhcpAck, DHCPV4_ACK_INDEX); + } + + if (NewProxyOffer != NULL) { + CopyParse (Private, &PxebcMode->ProxyOffer, NewProxyOffer, PXE_OFFER_INDEX); + } + + if (NewPxeDiscover != NULL) { + CopyMem ( + &PxebcMode->PxeDiscover, + NewPxeDiscover, + sizeof *NewPxeDiscover + ); + } + + if (NewPxeReply != NULL) { + CopyParse (Private, &PxebcMode->PxeReply, NewPxeReply, PXE_ACK_INDEX); + } + + if (NewPxeBisReply != NULL) { + CopyParse (Private, &PxebcMode->PxeBisReply, NewPxeBisReply, PXE_BIS_INDEX); + } + // + // Unlock the instance data + // + EfiReleaseLock (&Private->Lock); + return EFI_SUCCESS; +} + +/* eof - pxe_bc_dhcp.c */ diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_igmp.c b/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_igmp.c new file mode 100644 index 0000000000..6737ede9b8 --- /dev/null +++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_igmp.c @@ -0,0 +1,476 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +--*/ + + + + +#define RAND_MAX 0x10000 +#include "bc.h" + +// +// Definitions for internet group management protocol version 2 message +// structure Per RFC 2236, November 1997 +// +STATIC UINT8 RouterAlertOption[4] = { 0x80 | 20, 4, 0, 0 }; +STATIC IPV4_ADDR AllRoutersGroup = { { 224, 0, 0, 2 } }; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +STATIC +VOID +ClearGroupTimer ( + PXE_BASECODE_DEVICE *Private, + UINTN TimerId + ) +{ + if (Private == NULL) { + return ; + } + + if (TimerId >= Private->MCastGroupCount) { + return ; + } + + if (Private->IgmpGroupEvent[TimerId] == NULL) { + return ; + } + + gBS->CloseEvent (Private->IgmpGroupEvent[TimerId]); + Private->IgmpGroupEvent[TimerId] = NULL; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +STATIC +VOID +SetGroupTimer ( + PXE_BASECODE_DEVICE *Private, + UINTN TimerId, + UINTN MaxRespTime + ) +/*++ +Routine description: + Set IGMP response timeout value. + +Parameters: + Private := Pointer to PxeBc interface + TimerId := Timer ID# + MaxRespTime := Base response timeout value in tenths of seconds + +Returns: +--*/ +{ + EFI_STATUS EfiStatus; + + if (Private == NULL) { + return ; + } + + if (TimerId >= Private->MCastGroupCount) { + return ; + } + + if (Private->IgmpGroupEvent[TimerId] != NULL) { + gBS->CloseEvent (Private->IgmpGroupEvent[TimerId]); + } + + EfiStatus = gBS->CreateEvent ( + EFI_EVENT_TIMER, + EFI_TPL_CALLBACK, + NULL, + NULL, + &Private->IgmpGroupEvent[TimerId] + ); + + if (EFI_ERROR (EfiStatus)) { + Private->IgmpGroupEvent[TimerId] = NULL; + return ; + } + + EfiStatus = gBS->SetTimer ( + Private->IgmpGroupEvent[TimerId], + TimerRelative, + MaxRespTime * 1000000 + Random (Private) % RAND_MAX + ); + + if (EFI_ERROR (EfiStatus)) { + gBS->CloseEvent (Private->IgmpGroupEvent[TimerId]); + Private->IgmpGroupEvent[TimerId] = NULL; + } +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +STATIC +VOID +SendIgmpMessage ( + PXE_BASECODE_DEVICE *Private, + UINT8 Type, + INTN GroupId + ) +/*++ +Routine description: + Send an IGMP message + +Parameters: + Private := Pointer to PxeBc interface + Type := Message type opcode + GroupId := Group ID# + +Returns: +--*/ +{ + Private->IgmpMessage.Type = Type; + Private->IgmpMessage.MaxRespTime = 0; + Private->IgmpMessage.Checksum = 0; + Private->IgmpMessage.GroupAddress = Private->MCastGroup[GroupId]; + Private->IgmpMessage.Checksum = IpChecksum ( + (UINT16 *) &Private->IgmpMessage, + sizeof Private->IgmpMessage + ); + + Ipv4SendWOp ( + Private, + 0, + (UINT8 *) &Private->IgmpMessage, + sizeof Private->IgmpMessage, + PROT_IGMP, + RouterAlertOption, + sizeof RouterAlertOption, + ((Type == IGMP_TYPE_LEAVE_GROUP) ? AllRoutersGroup.L : Private->IgmpMessage.GroupAddress), + EFI_PXE_BASE_CODE_FUNCTION_IGMP + ); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +STATIC +VOID +ReportIgmp ( + PXE_BASECODE_DEVICE *Private, + INTN GroupId + ) +/*++ +Routine description: + Send an IGMP report message. + +Parameters: + Private := Pointer to PxeBc interface + GroupId := Group ID# + +Returns: +--*/ +{ + // + // if version 1 querier, send v1 report + // + UINT8 Type; + + if (Private->Igmpv1TimeoutEvent != NULL) { + if (!EFI_ERROR (gBS->CheckEvent (Private->Igmpv1TimeoutEvent))) { + gBS->CloseEvent (Private->Igmpv1TimeoutEvent); + Private->Igmpv1TimeoutEvent = NULL; + Private->UseIgmpv1Reporting = TRUE; + } + } + + Type = (UINT8) (Private->UseIgmpv1Reporting ? IGMP_TYPE_V1REPORT : IGMP_TYPE_REPORT); + + SendIgmpMessage (Private, Type, GroupId); + ClearGroupTimer (Private, GroupId); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +VOID +IgmpCheckTimers ( + PXE_BASECODE_DEVICE *Private + ) +/*++ +Routine description: + Check IGMP timers and send reports for all groups that have expired. +Parameters: + Private := Pointer to PxeBc interface + +Returns: +--*/ +{ + UINTN GroupId; + + if (Private == NULL) { + return ; + } + + for (GroupId = 0; GroupId < Private->MCastGroupCount; ++GroupId) { + if (Private->IgmpGroupEvent[GroupId] == NULL) { + continue; + } + + if (!EFI_ERROR (gBS->CheckEvent (Private->IgmpGroupEvent[GroupId]))) { + // + // send a report + // + ReportIgmp (Private, GroupId); + } + } +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +STATIC +INTN +FindMulticastGroup ( + PXE_BASECODE_DEVICE *Private, + UINT32 GroupAddress + ) +/*++ +Routine description: + Fund group ID# (index). + +Parameters: + Private := Pointer to PxeBc interface + GroupAddress := Group multicast address + +Returns: + 0 := Group not found + other := Group ID# +--*/ +{ + UINTN GroupId; + + for (GroupId = 0; GroupId < Private->MCastGroupCount; ++GroupId) { + if (Private->MCastGroup[GroupId] == GroupAddress) { + return GroupId + 1; + } + } + + return 0; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +VOID +IgmpJoinGroup ( + PXE_BASECODE_DEVICE *Private, + EFI_IP_ADDRESS *GroupPtr + ) +/*++ +Routine description: + Join multicast group. + +Parameters: + Private := Pointer to PxeBc interface + GroupPtr := Pointer to group mutlicast IP address. + +Returns: +--*/ +{ + UINT32 Grp; + + Grp = *(UINT32 *) GroupPtr; + +#if SUPPORT_IPV6 + if (Private->EfiBc.Mode->UsingIpv6) { + // + // TBD + // + } +#endif + // + // see if we already have it or if we can't take anymore + // + if (FindMulticastGroup (Private, Grp) || Private->MCastGroupCount == MAX_MCAST_GROUPS) { + return ; + } + // + // add the group + // + Private->MCastGroup[Private->MCastGroupCount] = Grp; + + ReportIgmp (Private, Private->MCastGroupCount); + // + // send a report + // so it will get sent again per RFC 2236 + // + SetGroupTimer ( + Private, + Private->MCastGroupCount++, + UNSOLICITED_REPORT_INTERVAL * 10 + ); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +VOID +IgmpLeaveGroup ( + PXE_BASECODE_DEVICE *Private, + EFI_IP_ADDRESS *GroupPtr + ) +/*++ +Routine description: + Leave multicast group. + +Parameters: + Private := Pointer to PxeBc interface + GroupPtr := Mutlicast group IP address. + +Returns: +--*/ +{ + UINT32 Grp; + UINTN GroupId; + + Grp = *(UINT32 *) GroupPtr; + +#if SUPPORT_IPV6 + if (Private->EfiBc.Mode->UsingIpv6) { + // + // TBD + // + } +#endif + // + // if not in group, ignore + // + GroupId = FindMulticastGroup (Private, Grp); + + if (GroupId == 0) { + return ; + } + // + // if not v1 querrier, send leave group IGMP message + // + if (Private->Igmpv1TimeoutEvent != NULL) { + if (!EFI_ERROR (gBS->CheckEvent (Private->Igmpv1TimeoutEvent))) { + gBS->CloseEvent (Private->Igmpv1TimeoutEvent); + Private->Igmpv1TimeoutEvent = NULL; + Private->UseIgmpv1Reporting = TRUE; + } else { + SendIgmpMessage (Private, IGMP_TYPE_LEAVE_GROUP, GroupId - 1); + } + } + + while (GroupId < Private->MCastGroupCount) { + Private->MCastGroup[GroupId - 1] = Private->MCastGroup[GroupId]; + Private->IgmpGroupEvent[GroupId - 1] = Private->IgmpGroupEvent[GroupId]; + ++GroupId; + } + + --Private->MCastGroupCount; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +VOID +HandleIgmp ( + PXE_BASECODE_DEVICE *Private, + IGMPV2_MESSAGE *IgmpMessagePtr, + UINTN IgmpLength + ) +/*++ +Routine description: + Handle received IGMP packet + +Parameters: + Private := Pointer to PxeBc interface + IgmpMessagePtr := Pointer to IGMP packet + IgmpLength := packet length in bytes + +Returns: +--*/ +{ + EFI_STATUS EfiStatus; + UINTN GroupId; + INTN MaxRespTime; + + if (Private == NULL) { + return ; + } + + if (Private->MCastGroupCount == 0) { + // + // if we don't belong to any multicast groups, ignore + // + return ; + } + // + // verify checksum + // + if (IpChecksum ((UINT16 *) IgmpMessagePtr, IgmpLength)) { + // + // bad checksum - ignore packet + // + return ; + } + + switch (IgmpMessagePtr->Type) { + case IGMP_TYPE_QUERY: + // + // if a version 1 querier, note the fact and set max resp time + // + MaxRespTime = IgmpMessagePtr->MaxRespTime; + + if (MaxRespTime == 0) { + Private->UseIgmpv1Reporting = TRUE; + + if (Private->Igmpv1TimeoutEvent != NULL) { + gBS->CloseEvent (Private->Igmpv1TimeoutEvent); + } + + EfiStatus = gBS->CreateEvent ( + EFI_EVENT_TIMER, + EFI_TPL_CALLBACK, + NULL, + NULL, + &Private->Igmpv1TimeoutEvent + ); + + if (EFI_ERROR (EfiStatus)) { + Private->Igmpv1TimeoutEvent = NULL; + } else { + EfiStatus = gBS->SetTimer ( + Private->Igmpv1TimeoutEvent, + TimerRelative, + (UINT64) V1ROUTER_PRESENT_TIMEOUT * 10000000 + ); + } + + MaxRespTime = IGMP_DEFAULT_MAX_RESPONSE_TIME * 10; + } + // + // if a general query (!GroupAddress), set all our group timers + // + if (!IgmpMessagePtr->GroupAddress) { + for (GroupId = 0; GroupId < Private->MCastGroupCount; ++GroupId) { + SetGroupTimer (Private, GroupId, MaxRespTime); + } + } else { + // + // specific query - set only specific group + // + GroupId = FindMulticastGroup (Private, IgmpMessagePtr->GroupAddress); + + if (GroupId != 0) { + SetGroupTimer (Private, GroupId - 1, MaxRespTime); + } + } + + break; + + // + // if we have a timer running for this group, clear it + // + case IGMP_TYPE_V1REPORT: + case IGMP_TYPE_REPORT: + GroupId = FindMulticastGroup (Private, IgmpMessagePtr->GroupAddress); + + if (GroupId != 0) { + ClearGroupTimer (Private, GroupId - 1); + } + + break; + } +} + +/* EOF - pxe_bc_igmp.c */ diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_ip.c b/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_ip.c new file mode 100644 index 0000000000..26bc2109ae --- /dev/null +++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_ip.c @@ -0,0 +1,861 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + pxe_bc_ip.c + +Abstract: + +--*/ + + +#include "bc.h" + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +BOOLEAN +OnSameSubnet ( + IN UINTN IpLength, + IN EFI_IP_ADDRESS *Ip1, + IN EFI_IP_ADDRESS *Ip2, + IN EFI_IP_ADDRESS *SubnetMask + ) +/*++ + + Routine Description: + Check if two IP addresses are on the same subnet. + + Arguments: + IpLength - Length of IP address in bytes. + Ip1 - IP address to check. + Ip2 - IP address to check. + SubnetMask - Subnet mask to check with. + + Returns: + TRUE - IP addresses are on the same subnet. + FALSE - IP addresses are on different subnets. + +--*/ +{ + if (IpLength == 0 || Ip1 == NULL || Ip2 == NULL || SubnetMask == NULL) { + return FALSE; + } + + while (IpLength-- != 0) { + if ((Ip1->v6.Addr[IpLength] ^ Ip2->v6.Addr[IpLength]) & SubnetMask->v6.Addr[IpLength]) { + return FALSE; + } + } + + return TRUE; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +VOID +IpAddRouter ( + IN PXE_BASECODE_DEVICE *Private, + IN EFI_IP_ADDRESS *RouterIpPtr + ) +/*++ + + Routine Description: + Add router to router table. + + Arguments: + Private - Pointer PxeBc instance data. + RouterIpPtr - Pointer to router IP address. + + Returns: + Nothing + +--*/ +{ + EFI_PXE_BASE_CODE_MODE *PxeBcMode; + UINTN Index; + + if (Private == NULL || RouterIpPtr == NULL) { + return ; + } + + PxeBcMode = Private->EfiBc.Mode; + + // + // if we are filled up or this is not on the same subnet, forget it + // + if ((PxeBcMode->RouteTableEntries == PXE_ROUTER_TABLE_SIZE) || + !OnSameSubnet(Private->IpLength, &PxeBcMode->StationIp, RouterIpPtr, &PxeBcMode->SubnetMask)) { + return ; + } + // + // make sure we don't already have it + // + for (Index = 0; Index < PxeBcMode->RouteTableEntries; ++Index) { + if (!CompareMem ( + &PxeBcMode->RouteTable[Index].GwAddr, + RouterIpPtr, + Private->IpLength + )) { + return ; + } + } + // + // keep it + // + ZeroMem ( + &PxeBcMode->RouteTable[PxeBcMode->RouteTableEntries], + sizeof (EFI_PXE_BASE_CODE_ROUTE_ENTRY) + ); + + CopyMem ( + &PxeBcMode->RouteTable[PxeBcMode->RouteTableEntries++].GwAddr, + RouterIpPtr, + Private->IpLength + ); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +// +// return router ip to use for DestIp (0 if none) +// +STATIC +EFI_IP_ADDRESS * +GetRouterIp ( + PXE_BASECODE_DEVICE *Private, + EFI_IP_ADDRESS *DestIpPtr + ) +{ + EFI_PXE_BASE_CODE_MODE *PxeBcMode; + UINTN Index; + + if (Private == NULL || DestIpPtr == NULL) { + return NULL; + } + + PxeBcMode = Private->EfiBc.Mode; + + for (Index = 0; Index < PxeBcMode->RouteTableEntries; ++Index) { + if (OnSameSubnet ( + Private->IpLength, + &PxeBcMode->RouteTable[Index].IpAddr, + DestIpPtr, + &PxeBcMode->RouteTable[Index].SubnetMask + )) { + return &PxeBcMode->RouteTable[Index].GwAddr; + } + } + + return NULL; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +// +// routine to send ipv4 packet +// ipv4 header of length HdrLth in TransmitBufferPtr +// routine fills in ipv4hdr Ver_Hdl, TotalLength, and Checksum, moves in Data +// and gets dest MAC address +// +#define IP_TX_BUFFER ((IPV4_BUFFER *) Private->TransmitBufferPtr) +#define IP_TX_HEADER IP_TX_BUFFER->IpHeader + +EFI_STATUS +Ipv4Xmt ( + PXE_BASECODE_DEVICE *Private, + UINT32 GatewayIp, + UINTN IpHeaderLength, + UINTN TotalHeaderLength, + VOID *Data, + UINTN DataLength, + EFI_PXE_BASE_CODE_FUNCTION Function + ) +{ + EFI_MAC_ADDRESS DestMac; + EFI_SIMPLE_NETWORK_PROTOCOL *Snp; + EFI_PXE_BASE_CODE_MODE *PxeBcMode; + EFI_STATUS StatCode; + UINTN PacketLength; + + Snp = Private->SimpleNetwork; + PxeBcMode = Private->EfiBc.Mode; + StatCode = EFI_SUCCESS; + PacketLength = TotalHeaderLength + DataLength; + + // + // get dest MAC address + // multicast - convert to hw equiv + // unicast on same net, use arp + // on different net, arp for router + // + if (IP_TX_HEADER.DestAddr.L == BROADCAST_IPv4) { + CopyMem (&DestMac, &Snp->Mode->BroadcastAddress, sizeof (DestMac)); + } else if (IS_MULTICAST (&IP_TX_HEADER.DestAddr)) { + StatCode = (*Snp->MCastIpToMac) (Snp, PxeBcMode->UsingIpv6, (EFI_IP_ADDRESS *) &IP_TX_HEADER.DestAddr, &DestMac); + } else { + UINT32 Ip; + + if (OnSameSubnet ( + Private->IpLength, + &PxeBcMode->StationIp, + (EFI_IP_ADDRESS *) &IP_TX_HEADER.DestAddr, + &PxeBcMode->SubnetMask + )) { + Ip = IP_TX_HEADER.DestAddr.L; + } else if (GatewayIp != 0) { + Ip = GatewayIp; + } else { + EFI_IP_ADDRESS *TmpIp; + + TmpIp = GetRouterIp (Private, (EFI_IP_ADDRESS *) &IP_TX_HEADER.DestAddr); + + if (TmpIp == NULL) { + DEBUG ( + (EFI_D_WARN, + "\nIpv4Xmit() Exit #1 %xh (%r)", + EFI_NO_RESPONSE, + EFI_NO_RESPONSE) + ); + + return EFI_NO_RESPONSE; + // + // no router + // + } + + Ip = TmpIp->Addr[0]; + } + + if (!GetHwAddr ( + Private, + (EFI_IP_ADDRESS *) &Ip, + (EFI_MAC_ADDRESS *) &DestMac + )) { + if (!PxeBcMode->AutoArp) { + DEBUG ( + (EFI_D_WARN, + "\nIpv4Xmit() Exit #2 %xh (%r)", + EFI_DEVICE_ERROR, + EFI_DEVICE_ERROR) + ); + + return EFI_DEVICE_ERROR; + } else { + StatCode = DoArp ( + Private, + (EFI_IP_ADDRESS *) &Ip, + (EFI_MAC_ADDRESS *) &DestMac + ); + } + } + } + + if (EFI_ERROR (StatCode)) { + DEBUG ((EFI_D_WARN, "\nIpv4Xmit() Exit #3 %xh (%r)", StatCode, StatCode)); + return StatCode; + } + // + // fill in packet info + // + SET_IPV4_VER_HDL (&IP_TX_HEADER, IpHeaderLength); + IP_TX_HEADER.TotalLength = HTONS (PacketLength); + IP_TX_HEADER.HeaderChecksum = IpChecksum ((UINT16 *) &IP_TX_HEADER, IpHeaderLength); + CopyMem (((UINT8 *) &IP_TX_HEADER) + TotalHeaderLength, Data, DataLength); + + // + // send it + // + return SendPacket ( + Private, + (UINT8 *) &IP_TX_HEADER - Snp->Mode->MediaHeaderSize, + &IP_TX_HEADER, + PacketLength, + &DestMac, + PXE_PROTOCOL_ETHERNET_IP, + Function + ); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +// +// send ipv4 packet with option +// +EFI_STATUS +Ipv4SendWOp ( + PXE_BASECODE_DEVICE *Private, + UINT32 GatewayIp, + UINT8 *Msg, + UINTN MessageLength, + UINT8 Prot, + UINT8 *Option, + UINTN OptionLength, + UINT32 DestIp, + EFI_PXE_BASE_CODE_FUNCTION Function + ) +{ + EFI_PXE_BASE_CODE_MODE *PxeBcMode; + UINTN HdrLth; + + PxeBcMode = Private->EfiBc.Mode; + HdrLth = sizeof (IPV4_HEADER) + OptionLength; + + ZeroMem ((VOID *) &IP_TX_HEADER, sizeof (IPV4_HEADER)); + IP_TX_HEADER.TimeToLive = PxeBcMode->TTL; + IP_TX_HEADER.TypeOfService = PxeBcMode->ToS; + IP_TX_HEADER.Protocol = Prot; + IP_TX_HEADER.SrcAddr.L = *(UINT32 *) &PxeBcMode->StationIp; + IP_TX_HEADER.DestAddr.L = DestIp; + IP_TX_HEADER.Id = Random (Private); + CopyMem (IP_TX_BUFFER->u.Data, Option, OptionLength); + return Ipv4Xmt ( + Private, + GatewayIp, + HdrLth, + HdrLth, + Msg, + MessageLength, + Function + ); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +// +// send MessageLength message at MessagePtr - higher level protocol header already in TransmitBufferPtr, length HdrSize +// +EFI_STATUS +Ip4Send ( + PXE_BASECODE_DEVICE *Private, // pointer to instance data + UINTN MayFrag, // + UINT8 Prot, // protocol + UINT32 SrcIp, // Source IP address + UINT32 DestIp, // Destination IP address + UINT32 GatewayIp, // used if not NULL and needed + UINTN HdrSize, // protocol header byte length + UINT8 *MessagePtr, // pointer to data + UINTN MessageLength // data byte length + ) +{ + EFI_STATUS StatCode; + UINTN TotDataLength; + + TotDataLength = HdrSize + MessageLength; + + if (TotDataLength > MAX_IPV4_DATA_SIZE) { + DEBUG ( + (EFI_D_WARN, + "\nIp4Send() Exit #1 %xh (%r)", + EFI_BAD_BUFFER_SIZE, + EFI_BAD_BUFFER_SIZE) + ); + + return EFI_BAD_BUFFER_SIZE; + } + + ZeroMem ((VOID *) &IP_TX_HEADER, sizeof (IPV4_HEADER)); + IP_TX_HEADER.TimeToLive = DEFAULT_TTL; + IP_TX_HEADER.Protocol = Prot; + IP_TX_HEADER.SrcAddr.L = SrcIp; + IP_TX_HEADER.DestAddr.L = DestIp; + IP_TX_HEADER.Id = Random (Private); + + if (!MayFrag) { + *(UINT8 *) (&IP_TX_HEADER.FragmentFields) = IP_NO_FRAG >> 8; + } + // + // check for need to fragment + // + if (TotDataLength > MAX_IPV4_FRAME_DATA_SIZE) { + UINTN DataLengthSent; + UINT16 FragmentOffset; + + FragmentOffset = IP_MORE_FRAG; + // + // frag offset field + // + if (!MayFrag) { + DEBUG ( + (EFI_D_WARN, + "\nIp4Send() Exit #2 %xh (%r)", + EFI_BAD_BUFFER_SIZE, + EFI_BAD_BUFFER_SIZE) + ); + + return EFI_BAD_BUFFER_SIZE; + } + // + // send out in fragments - first includes upper level header + // all are max and include more frag bit except last + // + * (UINT8 *) (&IP_TX_HEADER.FragmentFields) = IP_MORE_FRAG >> 8; + +#define IPV4_FRAG_SIZE (MAX_IPV4_FRAME_DATA_SIZE & 0xfff8) +#define IPV4_FRAG_OFF_INC (IPV4_FRAG_SIZE >> 3) + + DataLengthSent = IPV4_FRAG_SIZE - HdrSize; + + StatCode = Ipv4Xmt ( + Private, + GatewayIp, + sizeof (IPV4_HEADER), + sizeof (IPV4_HEADER) + HdrSize, + MessagePtr, + DataLengthSent, + Private->Function + ); + + if (EFI_ERROR (StatCode)) { + DEBUG ( + (EFI_D_WARN, + "\nIp4Send() Exit #3 %xh (%r)", + StatCode, + StatCode) + ); + + return StatCode; + } + + MessagePtr += DataLengthSent; + MessageLength -= DataLengthSent; + FragmentOffset += IPV4_FRAG_OFF_INC; + IP_TX_HEADER.FragmentFields = HTONS (FragmentOffset); + + while (MessageLength > IPV4_FRAG_SIZE) { + StatCode = Ipv4Xmt ( + Private, + GatewayIp, + sizeof (IPV4_HEADER), + sizeof (IPV4_HEADER), + MessagePtr, + IPV4_FRAG_SIZE, + Private->Function + ); + + if (EFI_ERROR (StatCode)) { + DEBUG ( + (EFI_D_WARN, + "\nIp4Send() Exit #3 %xh (%r)", + StatCode, + StatCode) + ); + + return StatCode; + } + + MessagePtr += IPV4_FRAG_SIZE; + MessageLength -= IPV4_FRAG_SIZE; + FragmentOffset += IPV4_FRAG_OFF_INC; + IP_TX_HEADER.FragmentFields = HTONS (FragmentOffset); + } + + * (UINT8 *) (&IP_TX_HEADER.FragmentFields) &= ~(IP_MORE_FRAG >> 8); + HdrSize = 0; + } + // + // transmit + // + return Ipv4Xmt ( + Private, + GatewayIp, + sizeof (IPV4_HEADER), + sizeof (IPV4_HEADER) + HdrSize, + MessagePtr, + MessageLength, + Private->Function + ); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +// +// return true if dst IP in receive header matched with what's enabled +// +STATIC +BOOLEAN +IPgood ( + PXE_BASECODE_DEVICE *Private, + IPV4_HEADER *IpHeader + ) +{ + EFI_PXE_BASE_CODE_MODE *PxeBcMode; + UINTN Index; + + PxeBcMode = Private->EfiBc.Mode; + + if (PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) { + return TRUE; + } + + if ((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST) && + IS_MULTICAST (&IpHeader->DestAddr) + ) { + return TRUE; + } + + if ((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) && + PxeBcMode->StationIp.Addr[0] == IpHeader->DestAddr.L + ) { + return TRUE; + } + + if ((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST) && IpHeader->DestAddr.L == BROADCAST_IPv4) { + return TRUE; + } + + for (Index = 0; Index < PxeBcMode->IpFilter.IpCnt; ++Index) { + if (IpHeader->DestAddr.L == PxeBcMode->IpFilter.IpList[Index].Addr[0]) { + return TRUE; + } + } + + return FALSE; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +// +// receive up to MessageLength message into MessagePtr for protocol Prot +// return message length, src/dest ips if select any, and pointer to protocol +// header routine will filter based on source and/or dest ip if OpFlags set. +// +EFI_STATUS +IpReceive ( + PXE_BASECODE_DEVICE *Private, + PXE_OPFLAGS OpFlags, + EFI_IP_ADDRESS *SrcIpPtr, + EFI_IP_ADDRESS *DestIpPtr, + UINT8 Prot, + VOID *HeaderPtr, + UINTN HdrSize, + UINT8 *MessagePtr, + UINTN *MessageLengthPtr, + EFI_EVENT TimeoutEvent + ) +{ + EFI_PXE_BASE_CODE_MODE *PxeBcMode; + EFI_STATUS StatCode; + UINTN ByteCount; + UINTN FragmentCount; + UINTN ExpectedPacketLength; + UINTN Id; + BOOLEAN GotFirstFragment; + BOOLEAN GotLastFragment; + + DEBUG ( + (EFI_D_NET, + "\nIpReceive() Hdr=%Xh HdrSz=%d Data=%Xh DataSz=%d", + HeaderPtr, + HdrSize, + MessagePtr, + *MessageLengthPtr) + ); + + PxeBcMode = Private->EfiBc.Mode; + PxeBcMode->IcmpErrorReceived = FALSE; + + ExpectedPacketLength = 0; + GotFirstFragment = FALSE; + GotLastFragment = FALSE; + FragmentCount = 0; + ByteCount = 0; + Id = 0; + + for (;;) { + IPV4_HEADER IpHdr; + UINTN FFlds; + UINTN TotalLength; + UINTN FragmentOffset; + UINTN HeaderSize; + UINTN BufferSize; + UINTN IpHeaderLength; + UINTN DataLength; + UINT16 Protocol; + UINT8 *NextHdrPtr; + UINT8 *PacketPtr; + + StatCode = WaitForReceive ( + Private, + Private->Function, + TimeoutEvent, + &HeaderSize, + &BufferSize, + &Protocol + ); + + if (EFI_ERROR (StatCode)) { + return StatCode; + } + + PacketPtr = Private->ReceiveBufferPtr + HeaderSize; + + if (Protocol == PXE_PROTOCOL_ETHERNET_ARP) { + HandleArpReceive ( + Private, + (ARP_PACKET *) PacketPtr, + Private->ReceiveBufferPtr + ); + + continue; + } + + if (Protocol != PXE_PROTOCOL_ETHERNET_IP) { + continue; + } + +#if SUPPORT_IPV6 + if (PxeBcMode->UsingIpv6) { + // + // TBD + // + } +#endif + +#define IpRxHeader ((IPV4_HEADER *) PacketPtr) + + // + // filter for version & check sum + // + IpHeaderLength = IPV4_HEADER_LENGTH (IpRxHeader); + + if ((IpRxHeader->VersionIhl >> 4) != IPVER4) { + continue; + } + + if (IpChecksum ((UINT16 *) IpRxHeader, IpHeaderLength)) { + continue; + } + + CopyMem (&IpHdr, IpRxHeader, sizeof (IpHdr)); + //IpHdr = *IpRxHeader; + TotalLength = NTOHS (IpHdr.TotalLength); + + if (IpHdr.Protocol == PROT_TCP) { + // + // The NextHdrPtr is used to seed the header buffer we are passing back. + // That being the case, we want to see everything in pPkt which contains + // everything but the ethernet (or whatever) frame. IP + TCP in this case. + // + DataLength = TotalLength; + NextHdrPtr = PacketPtr; + } else { + DataLength = TotalLength - IpHeaderLength; + NextHdrPtr = PacketPtr + IpHeaderLength; + } + // + // If this is an ICMP, it might not be for us. + // Double check the state of the IP stack and the + // packet fields before assuming it is an ICMP + // error. ICMP requests are not supported by the + // PxeBc IP stack and should be ignored. + // + if (IpHdr.Protocol == PROT_ICMP) { + ICMPV4_HEADER *Icmpv4; + + Icmpv4 = (ICMPV4_HEADER *) NextHdrPtr; + + // + // For now only obvious ICMP error replies will be accepted by + // this stack. This still makes us vulnerable to DoS attacks. + // But at least we will not be killed by DHCP daemons. + // + switch (Icmpv4->Type) { + case ICMP_REDIRECT: + case ICMP_ECHO: + case ICMP_ROUTER_ADV: + case ICMP_ROUTER_SOLICIT: + case ICMP_TIMESTAMP: + case ICMP_TIMESTAMP_REPLY: + case ICMP_INFO_REQ: + case ICMP_INFO_REQ_REPLY: + case ICMP_SUBNET_MASK_REQ: + case ICMP_SUBNET_MASK_REPLY: + default: + continue; + + // + // %%TBD - This should be implemented. + // + case ICMP_ECHO_REPLY: + continue; + + case ICMP_DEST_UNREACHABLE: + case ICMP_TIME_EXCEEDED: + case ICMP_PARAMETER_PROBLEM: + case ICMP_SOURCE_QUENCH: + PxeBcMode->IcmpErrorReceived = TRUE; + + CopyMem ( + &PxeBcMode->IcmpError, + NextHdrPtr, + sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR) + ); + + DEBUG ( + (EFI_D_NET, + "\nIpReceive() Exit #1 %Xh (%r)", + EFI_ICMP_ERROR, + EFI_ICMP_ERROR) + ); + } + + return EFI_ICMP_ERROR; + } + + if (IpHdr.Protocol == PROT_IGMP) { + HandleIgmp (Private, (IGMPV2_MESSAGE *) NextHdrPtr, DataLength); + + DEBUG ((EFI_D_NET, "\n IGMP")); + continue; + } + // + // check for protocol + // + if (IpHdr.Protocol != Prot) { + continue; + } + // + // do filtering + // + if (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) && SrcIpPtr && SrcIpPtr->Addr[0] != IpHdr.SrcAddr.L) { + DEBUG ((EFI_D_NET, "\n Not expected source IP address.")); + continue; + } + + if (OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER) { + if (!IPgood (Private, &IpHdr)) { + continue; + } + } else if (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP)) { + if (DestIpPtr == NULL) { + if (PxeBcMode->StationIp.Addr[0] != IpHdr.DestAddr.L) { + continue; + } + } else if (DestIpPtr->Addr[0] != IpHdr.DestAddr.L) { + continue; + } + } + // + // get some data we need + // + FFlds = NTOHS (IpHdr.FragmentFields); + FragmentOffset = ((FFlds & IP_FRAG_OFF_MSK) << 3); + + /* Keep count of fragments that belong to this session. + * If we get packets with a different IP ID number, + * ignore them. Ignored packets should be handled + * by the upper level protocol. + */ + if (FragmentCount == 0) { + Id = IpHdr.Id; + + if (DestIpPtr != NULL) { + DestIpPtr->Addr[0] = IpHdr.DestAddr.L; + } + + if (SrcIpPtr != NULL) { + SrcIpPtr->Addr[0] = IpHdr.SrcAddr.L; + } + } else { + if (IpHdr.Id != Id) { + continue; + } + } + + ++FragmentCount; + + /* Fragment management. + */ + if (FragmentOffset == 0) { + /* This is the first fragment (may also be the + * only fragment). + */ + GotFirstFragment = TRUE; + + /* If there is a separate protocol header buffer, + * copy the header, adjust the data pointer and + * the data length. + */ + if (HdrSize != 0) { + CopyMem (HeaderPtr, NextHdrPtr, HdrSize); + + NextHdrPtr += HdrSize; + DataLength -= HdrSize; + } + } else { + /* If there is a separate protocol header buffer, + * adjust the fragment offset. + */ + FragmentOffset -= HdrSize; + } + + /* See if this is the last fragment. + */ + if (!(FFlds & IP_MORE_FRAG)) { + // + // This is the last fragment (may also be the only fragment). + // + GotLastFragment = TRUE; + + /* Compute the expected length of the assembled + * packet. This will be used to decide if we + * have gotten all of the fragments. + */ + ExpectedPacketLength = FragmentOffset + DataLength; + } + + DEBUG ( + (EFI_D_NET, + "\n ID = %Xh Off = %d Len = %d", + Id, + FragmentOffset, + DataLength) + ); + + /* Check for receive buffer overflow. + */ + if (FragmentOffset + DataLength > *MessageLengthPtr) { + /* There is not enough space in the receive + * buffer for the fragment. + */ + DEBUG ( + (EFI_D_NET, + "\nIpReceive() Exit #3 %Xh (%r)", + EFI_BUFFER_TOO_SMALL, + EFI_BUFFER_TOO_SMALL) + ); + + return EFI_BUFFER_TOO_SMALL; + } + + /* Copy data into receive buffer. + */ + if (DataLength != 0) { + DEBUG ((EFI_D_NET, " To = %Xh", MessagePtr + FragmentOffset)); + + CopyMem (MessagePtr + FragmentOffset, NextHdrPtr, DataLength); + ByteCount += DataLength; + } + + /* If we have seen the first and last fragments and + * the receive byte count is at least as large as the + * expected byte count, return SUCCESS. + * + * We could be tricked by receiving a fragment twice + * but the upper level protocol should figure this + * out. + */ + if (GotFirstFragment && GotLastFragment && ByteCount >= ExpectedPacketLength) { + *MessageLengthPtr = ExpectedPacketLength; + return EFI_SUCCESS; + } + } +} + +/* eof - pxe_bc_ip.c */ diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_mtftp.c b/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_mtftp.c new file mode 100644 index 0000000000..3e0b0f547f --- /dev/null +++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_mtftp.c @@ -0,0 +1,2391 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + pxe_bc_mtftp.c + +Abstract: + TFTP and MTFTP (multicast TFTP) implementation. + +Revision History + +--*/ + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +// +// The following #define is used to create a version that does not wait to +// open after a listen. This is just for a special regression test of MTFTP +// server to make sure multiple opens are handled correctly. Normally this +// next line should be a comment. +// #define SpecialNowaitVersion // comment out for normal operation +// + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + +#include "bc.h" + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +UINT64 +Swap64 ( + UINT64 n + ) +{ + union { + UINT64 n; + UINT8 b[8]; + } u; + + UINT8 t; + + u.n = n; + + t = u.b[0]; + u.b[0] = u.b[7]; + u.b[7] = t; + + t = u.b[1]; + u.b[1] = u.b[6]; + u.b[6] = t; + + t = u.b[2]; + u.b[2] = u.b[5]; + u.b[5] = t; + + t = u.b[3]; + u.b[3] = u.b[4]; + u.b[4] = t; + + return u.n; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +STATIC +EFI_STATUS +TftpUdpRead ( + PXE_BASECODE_DEVICE *Private, + UINT16 Operation, + VOID *HeaderPtr, + UINTN *BufferSizePtr, + VOID *BufferPtr, + EFI_IP_ADDRESS *ServerIpPtr, + EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr, + EFI_IP_ADDRESS *OurIpPtr, + EFI_PXE_BASE_CODE_UDP_PORT *OurPortPtr, + UINT16 Timeout + ) +/*++ +Routine description: + Read TFTP packet. If TFTP ERROR packet is read, fill in TFTP error + information in Mode structure and return TFTP_ERROR status. + +Parameters: + Private := + Operation := + HeaderPtr := + BufferSizePtr := + BufferPtr := + ServerIpPtr := + ServerPortPtr := + OurIpPtr := + OurPortPtr := + Timeout := + +Returns: + EFI_SUCCESS := + EFI_TFTP_ERROR := + other := +--*/ +{ + EFI_PXE_BASE_CODE_MODE *PxeBcMode; + EFI_STATUS Status; + EFI_EVENT TimeoutEvent; + UINTN HeaderSize; + + // + // + // + Status = gBS->CreateEvent ( + EFI_EVENT_TIMER, + EFI_TPL_CALLBACK, + NULL, + NULL, + &TimeoutEvent + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->SetTimer ( + TimeoutEvent, + TimerRelative, + Timeout * 10000000 + 1000000 + ); + + if (EFI_ERROR (Status)) { + gBS->CloseEvent (TimeoutEvent); + return Status; + } + // + // + // + HeaderSize = Private->BigBlkNumFlag ? sizeof (struct Tftpv4Ack8) : sizeof (struct Tftpv4Ack); + +#define ERROR_MESSAGE_PTR ((struct Tftpv4Error *) HeaderPtr) + + Status = UdpRead ( + Private, + Operation, + OurIpPtr, + OurPortPtr, + ServerIpPtr, + ServerPortPtr, + &HeaderSize, + HeaderPtr, + BufferSizePtr, + BufferPtr, + TimeoutEvent + ); + + if (Status != EFI_SUCCESS || ERROR_MESSAGE_PTR->OpCode != HTONS (TFTP_ERROR)) { + gBS->CloseEvent (TimeoutEvent); + return Status; + } + // + // got an error packet + // write one byte error code followed by error message + // + PxeBcMode = Private->EfiBc.Mode; + PxeBcMode->TftpErrorReceived = TRUE; + PxeBcMode->TftpError.ErrorCode = (UINT8) NTOHS (ERROR_MESSAGE_PTR->ErrCode); + HeaderSize = EFI_MIN (*BufferSizePtr, sizeof PxeBcMode->TftpError.ErrorString); + CopyMem (PxeBcMode->TftpError.ErrorString, BufferPtr, HeaderSize); + + gBS->CloseEvent (TimeoutEvent); + return EFI_TFTP_ERROR; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +STATIC +VOID +SendError ( + PXE_BASECODE_DEVICE *Private, + EFI_IP_ADDRESS *ServerIpPtr, + EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr, + EFI_PXE_BASE_CODE_UDP_PORT *OurPortPtr + ) +/*++ +Routine description: + Send TFTP ERROR message to TFTP server + +Parameters: + Private := + ServerIpPtr := + ServerPortPtr := + OurPortPtr := + +Returns: +--*/ +{ + struct Tftpv4Error *ErrStr; + UINTN Len; + + ErrStr = (VOID *) Private->TftpErrorBuffer; + Len = sizeof *ErrStr; + + ErrStr->OpCode = HTONS (TFTP_ERROR); + ErrStr->ErrCode = HTONS (TFTP_ERR_OPTION); + ErrStr->ErrMsg[0] = 0; + + UdpWrite ( + Private, + EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT, + ServerIpPtr, + ServerPortPtr, + 0, + 0, + OurPortPtr, + 0, + 0, + &Len, + ErrStr + ); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +STATIC +EFI_STATUS +SendAckAndGetData ( + PXE_BASECODE_DEVICE *Private, + EFI_IP_ADDRESS *ServerIpPtr, + EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr, + EFI_IP_ADDRESS *ReplyIpPtr, + EFI_PXE_BASE_CODE_UDP_PORT *OurPortPtr, + UINT16 Timeout, + UINTN *ReplyLenPtr, + UINT8 *PxeBcMode, + UINT64 *BlockNumPtr, + BOOLEAN AckOnly + ) +/*++ +Routine description: + Send TFTP ACK packet to server and read next DATA packet. + +Parameters: + Private := Pointer to PxeBc interface + ServerIpPtr := Pointer to TFTP server IP address + ServerPortPtr := Pointer to TFTP server UDP port + ReplyIpPtr := Pointer to TFTP DATA packet destination IP address + OurPortPtr := Pointer to TFTP client UDP port + Timeout := + ReplyLenPtr := Pointer to packet length + PxeBcMode := Pointer to packet buffer + BlockNumPtr := Pointer to block number + AckOnly := TRUE == Send last ack - do not wait for reply + +Returns: +--*/ +{ + struct Tftpv4Data DataBuffer; + struct Tftpv4Ack *Ack2Ptr; + struct Tftpv4Ack8 *Ack8Ptr; + EFI_STATUS Status; + UINTN Len; + + Ack2Ptr = (VOID *) Private->TftpAckBuffer; + Ack8Ptr = (VOID *) Private->TftpAckBuffer; + + if (Private->BigBlkNumFlag) { + Len = sizeof (struct Tftpv4Ack8); + + Ack8Ptr->OpCode = HTONS (TFTP_ACK8); + Ack8Ptr->BlockNum = Swap64 (*BlockNumPtr); + + Status = UdpWrite ( + Private, + EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT, + ServerIpPtr, + ServerPortPtr, + 0, + 0, + OurPortPtr, + 0, + 0, + &Len, + Ack8Ptr + ); + + if (EFI_ERROR (Status)) { + return Status; + } + } else { + Len = sizeof (struct Tftpv4Ack); + + Ack2Ptr->OpCode = HTONS (TFTP_ACK); + Ack2Ptr->BlockNum = HTONS ((UINT16) *BlockNumPtr); + + Status = UdpWrite ( + Private, + EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT, + ServerIpPtr, + ServerPortPtr, + 0, + 0, + OurPortPtr, + 0, + 0, + &Len, + Ack2Ptr + ); + + if (EFI_ERROR (Status)) { + return Status; + } + } + + if (AckOnly) { + // + // ACK of last packet. This is just a courtesy. + // Do not wait for response. + // + return EFI_SUCCESS; + } + // + // read reply + // + Status = TftpUdpRead ( + Private, + 0, + &DataBuffer, + ReplyLenPtr, + PxeBcMode, + ServerIpPtr, + ServerPortPtr, + ReplyIpPtr, + OurPortPtr, + Timeout + ); + + if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) { + return Status; + } + // + // got a good reply (so far) + // check for next data packet + // + if (!Private->BigBlkNumFlag && DataBuffer.Header.OpCode == HTONS (TFTP_DATA)) { + if (Status == EFI_BUFFER_TOO_SMALL) { + SendError (Private, ServerIpPtr, ServerPortPtr, OurPortPtr); + } + + *BlockNumPtr = NTOHS (DataBuffer.Header.BlockNum); + return Status; + } + + if (Private->BigBlkNumFlag && DataBuffer.Header.OpCode == HTONS (TFTP_DATA8)) { + if (Status == EFI_BUFFER_TOO_SMALL) { + SendError (Private, ServerIpPtr, ServerPortPtr, OurPortPtr); + } + + *BlockNumPtr = Swap64 (*(UINT64 *) &DataBuffer.Header.BlockNum); + return Status; + } + + return EFI_PROTOCOL_ERROR; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +STATIC +EFI_STATUS +LockStepReceive ( + PXE_BASECODE_DEVICE *Private, + UINTN PacketSize, + UINT64 *BufferSizePtr, + UINT64 Offset, + UINT8 *BufferPtr, + EFI_IP_ADDRESS *ServerIpPtr, + EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr, + EFI_IP_ADDRESS *ReplyIpPtr, + EFI_PXE_BASE_CODE_UDP_PORT *OurPortPtr, + UINT64 LastBlock, + UINT16 Timeout, + IN BOOLEAN DontUseBuffer + ) +/*++ +Routine description: + Read rest of file after successfull M/TFTP request. + +Parameters: + Private := Pointer to PxeBc interface + PacketSize := Pointer to packet size + BufferSizePtr := Pointer to buffer (file) size + Offset := Offset into buffer of next packet + BufferPtr := Pointer to receive buffer + ServerIpPtr := Pointer to TFTP server IP address + ServerPortPtr := Pointer to TFTP server UDP port + ReplyIpPtr := Pointer to TFTP DATA packet destination IP address + OurPortPtr := Pointer to TFTP client UDP port + LastBlock := Last block number received + Timeout := + DontUseBuffer := TRUE == throw away data, just count # of bytes + +Returns: +--*/ +{ + EFI_STATUS Status; + UINT64 BlockNum; + UINT64 BufferSize; + UINTN Retries; + UINTN SaveLen; + UINTN ReplyLen; + + ReplyLen = PacketSize; + BlockNum = LastBlock; + + DEBUG ((EFI_D_INFO, "\nLockStepReceive() PacketSize = %d", PacketSize)); + + if (DontUseBuffer) { + BufferSize = PacketSize; + } else { + BufferSize = *BufferSizePtr - Offset; + BufferPtr += Offset; + } + + while (ReplyLen >= 512 && ReplyLen == PacketSize) { + if (BufferSize < PacketSize) { + ReplyLen = (UINTN) ((BufferSize > 0) ? BufferSize : 0); + } + + SaveLen = ReplyLen; + + // + // write an ack packet and get data - retry up to NUM_ACK_RETRIES on timeout + // + Retries = NUM_ACK_RETRIES; + + do { + ReplyLen = SaveLen; + + Status = SendAckAndGetData ( + Private, + ServerIpPtr, + ServerPortPtr, + ReplyIpPtr, + OurPortPtr, + Timeout, + (UINTN *) &ReplyLen, + BufferPtr, + &BlockNum, + FALSE + ); + + if (!EFI_ERROR (Status) || Status == EFI_BUFFER_TOO_SMALL) { + if (BlockNum == LastBlock) { + DEBUG ((EFI_D_NET, "\nresend")); + // + // a resend - continue + // + Status = EFI_TIMEOUT; + } else if (Private->BigBlkNumFlag) { + if (BlockNum != ++LastBlock) { + DEBUG ((EFI_D_NET, "\nLockStepReceive() Exit #1a")); + // + // not correct blocknum - error + // + return EFI_PROTOCOL_ERROR; + } + } else { + LastBlock = (LastBlock + 1) & 0xFFFF; + if (BlockNum != LastBlock) { + DEBUG ((EFI_D_NET, "\nLockStepReceive() Exit #1b")); + return EFI_PROTOCOL_ERROR; + // + // not correct blocknum - error + // + } + } + } + } while (Status == EFI_TIMEOUT && --Retries); + + if (EFI_ERROR (Status)) { + if (Status != EFI_BUFFER_TOO_SMALL) { + SendError (Private, ServerIpPtr, ServerPortPtr, OurPortPtr); + } + + return Status; + } + + if (DontUseBuffer) { + BufferSize += ReplyLen; + } else { + BufferPtr += ReplyLen; + BufferSize -= ReplyLen; + } + } + // + // while (ReplyLen == PacketSize); + // + if (DontUseBuffer) { + if (BufferSizePtr != NULL) { + *BufferSizePtr = (BufferSize - PacketSize); + } + } else { + *BufferSizePtr -= BufferSize; + } + + /* Send ACK of last packet. */ + ReplyLen = 0; + + SendAckAndGetData ( + Private, + ServerIpPtr, + ServerPortPtr, + ReplyIpPtr, + OurPortPtr, + Timeout, + (UINTN *) &ReplyLen, + BufferPtr, + &BlockNum, + TRUE + ); + + return EFI_SUCCESS; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +// +// some literals +// +STATIC UINT8 Mode[] = MODE_BINARY; +STATIC UINT8 BlockSizeOp[] = OP_BLKSIZE; +STATIC UINT8 TsizeOp[] = OP_TFRSIZE; +STATIC UINT8 OverwriteOp[] = OP_OVERWRITE; +STATIC UINT8 BigBlkNumOp[] = OP_BIGBLKNUM; +STATIC EFI_PXE_BASE_CODE_UDP_PORT TftpRequestPort = TFTP_OPEN_PORT; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +STATIC +UINT8 * +FindOption ( + UINT8 *OptionPtr, + INTN OpLen, + UINT8 *OackPtr, + INTN OackSize + ) +/*++ +Routine description: + Check TFTP OACK packet for option. + +Parameters: + OptionPtr := Pointer to option string to find + OpLen := Length of option string + OackPtr := Pointer to OACK data + OackSize := Length of OACK data + +Returns: + Pointer to value field if option found or NULL if not found. +--*/ +{ + if ((OackSize -= OpLen) <= 0) { + return NULL; + } + + do { + if (!CompareMem (OackPtr, OptionPtr, OpLen)) { + return OackPtr + OpLen; + } + + ++OackPtr; + } while (--OackSize); + + return NULL; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +#define BKSZOP 1 // block size +#define TSIZEOP 2 // transfer size +#define OVERWRITEOP 4 // overwrite +#define BIGBLKNUMOP 8 // big block numbers +STATIC +EFI_STATUS +TftpRwReq ( + UINT16 Req, + UINT16 Options, + PXE_BASECODE_DEVICE *Private, + EFI_IP_ADDRESS *ServerIpPtr, + EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr, + EFI_PXE_BASE_CODE_UDP_PORT *OurPortPtr, + UINT8 *FilenamePtr, + UINTN *PacketSizePtr, + VOID *Buffer + ) +/*++ +Routine description: + Send TFTP RRQ/WRQ packet. + +Parameters: + Req := Type of request to send + Options := One or more of the #define values above + Private := Pointer to PxeBc interface + ServerIpPtr := Pointer to TFTP server IP address + ServerPortPtr := Pointer to TFTP server UDP port + OurPortPtr := Pointer to TFTP client UDP port + FilenamePtr := Pointer to TFTP file or directory name + PacketSizePtr := Pointer to block size + Buffer := + +Returns: +--*/ +{ + union { + UINT8 Data[514]; + struct Tftpv4Req ReqStr; + } *u; + + UINT16 OpFlags; + INTN Len; + INTN TotalLen; + UINT8 *Ptr; + + if (*OurPortPtr == 0) { + OpFlags = EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT; + } else { + OpFlags = EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT; + } + // + // build the basic request - opcode, filename, mode + // + u = Buffer; + u->ReqStr.OpCode = HTONS (Req); + TotalLen = sizeof (Mode) + sizeof (u->ReqStr.OpCode) + (Len = 1 + AsciiStrLen ((CHAR8 *)FilenamePtr)); + + CopyMem (u->ReqStr.FileName, FilenamePtr, Len); + Ptr = (UINT8 *) (u->ReqStr.FileName + Len); + + CopyMem (Ptr, Mode, sizeof (Mode)); + Ptr += sizeof (Mode); + + if (Options & BKSZOP) { + CopyMem (Ptr, BlockSizeOp, sizeof (BlockSizeOp)); + UtoA10 (*PacketSizePtr, Ptr + sizeof (BlockSizeOp)); + + TotalLen += (Len = 1 + AsciiStrLen ((CHAR8 *)Ptr + sizeof (BlockSizeOp)) + sizeof (BlockSizeOp)); + + Ptr += Len; + } + + if (Options & TSIZEOP) { + CopyMem (Ptr, TsizeOp, sizeof (TsizeOp)); + CopyMem (Ptr + sizeof (TsizeOp), "0", 2); + TotalLen += sizeof (TsizeOp) + 2; + Ptr += sizeof (TsizeOp) + 2; + } + + if (Options & OVERWRITEOP) { + CopyMem (Ptr, OverwriteOp, sizeof (OverwriteOp)); + CopyMem (Ptr + sizeof (OverwriteOp), "1", 2); + TotalLen += sizeof (OverwriteOp) + 2; + Ptr += sizeof (OverwriteOp) + 2; + } + + if (Options & BIGBLKNUMOP) { + CopyMem (Ptr, BigBlkNumOp, sizeof (BigBlkNumOp)); + CopyMem (Ptr + sizeof (BigBlkNumOp), "8", 2); + TotalLen += sizeof (BigBlkNumOp) + 2; + Ptr += sizeof (BigBlkNumOp) + 2; + } + // + // send it + // + return UdpWrite ( + Private, + OpFlags, + ServerIpPtr, + ServerPortPtr, + 0, + 0, + OurPortPtr, + 0, + 0, + (UINTN *) &TotalLen, + u + ); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +STATIC +EFI_STATUS +TftpRwReqwResp ( + UINT16 Req, + UINT16 Options, + PXE_BASECODE_DEVICE *Private, + VOID *HeaderPtr, + UINTN *PacketSizePtr, + UINTN *ReplyLenPtr, + VOID *BufferPtr, + EFI_IP_ADDRESS *ServerIpPtr, + EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr, + EFI_PXE_BASE_CODE_UDP_PORT *ServerReplyPortPtr, + EFI_PXE_BASE_CODE_UDP_PORT *OurPortPtr, + UINT8 *FilenamePtr, + UINT16 Timeout + ) +/*++ +Routine description: + Start TFTP session. Issue request and wait for response. + Retry three times on error. If failed using options, + retry three times w/o options on error. + +Parameters: + Req := TFTP request type + Options := TFTP option bits + Private := Pointer to PxeBc interface + HeaderPtr := + PacketSizePtr := Pointer to block size + ReplyLenPtr := + BufferPtr := + ServerIpPtr := Pointer to TFTP server IP address + ServerPortPtr := Pointer to TFTP server UDP port + ServerReplyPortPtr := + OurPortPtr := Pointer to TFTP client UDP Port + FilenamePtr := Pointer to file or directory name + Timeout := + +Returns: +--*/ +{ + EFI_STATUS Status; + UINTN SaveReplyLen; + INTN Retries; + UINT8 Buffer[514]; + + SaveReplyLen = *ReplyLenPtr; + Retries = 3; + Private->BigBlkNumFlag = FALSE; + *OurPortPtr = 0; + // + // generate random + // + do { + if (*OurPortPtr != 0) { + if (++ *OurPortPtr == 0) { + *OurPortPtr = PXE_RND_PORT_LOW; + } + } + // + // send request from our Ip = StationIp + // + if ((Status = TftpRwReq ( + Req, + Options, + Private, + ServerIpPtr, + ServerPortPtr, + OurPortPtr, + FilenamePtr, + PacketSizePtr, + Buffer + )) != EFI_SUCCESS) { + DEBUG ( + (EFI_D_WARN, + "\nTftpRwReqwResp() Exit #1 %xh (%r)", + Status, + Status) + ); + + return Status; + } + // + // read reply to our Ip = StationIp + // + *ReplyLenPtr = SaveReplyLen; + + Status = TftpUdpRead ( + Private, + EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT, + HeaderPtr, + ReplyLenPtr, + BufferPtr, + ServerIpPtr, + ServerReplyPortPtr, + 0, + OurPortPtr, + Timeout + ); + } while (Status == EFI_TIMEOUT && --Retries); + + if (!Options || Status != EFI_TFTP_ERROR) { + DEBUG ( + (EFI_D_WARN, + "\nTftpRwReqwResp() Exit #2 %xh (%r)", + Status, + Status) + ); + return Status; + } + + Status = TftpRwReqwResp ( + Req, + 0, + Private, + HeaderPtr, + PacketSizePtr, + ReplyLenPtr, + BufferPtr, + ServerIpPtr, + ServerPortPtr, + ServerReplyPortPtr, + OurPortPtr, + FilenamePtr, + Timeout + ); + + DEBUG ((EFI_D_WARN, "\nTftpRwReqwResp() Exit #3 %xh (%r)", Status, Status)); + + return Status; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +// +// mtftp listen +// read on mcast ip, cport, from sport, for data packet +// returns success if gets multicast last packet or all up to last block +// if not missing, then finished +// +STATIC +EFI_STATUS +MtftpListen ( + PXE_BASECODE_DEVICE *Private, + UINT64 *BufferSizePtr, + UINT8 *BufferPtr, + EFI_IP_ADDRESS *ServerIpPtr, + EFI_PXE_BASE_CODE_MTFTP_INFO *MtftpInfoPtr, + UINT64 *StartBlockPtr, + UINTN *NumMissedPtr, + UINT16 TransTimeout, + UINT16 ListenTimeout, + UINT64 FinalBlock, + IN BOOLEAN DontUseBuffer + ) +/*++ +Routine description: + Listen for MTFTP traffic and save desired packets. + +Parameters: + Private := Pointer to PxeBc interface + BufferSizePtr := + BufferPtr := + ServerIpPtr := Pointer to TFTP server IP address + MtftpInfoPtr := Pointer to MTFTP session information + StartBlockPtr := IN=first block we are looking for OUT=first block received + NumMissedPtr := Number of blocks missed + TransTimeout := + ListenTimeout := + FinalBlock := + DontUseBuffer := TRUE == throw packets away, just count bytes + +Returns: +--*/ +{ + EFI_STATUS Status; + struct Tftpv4Ack Header; + UINT64 Offset; + UINT64 BlockNum; + UINT64 LastBlockNum; + UINT64 BufferSize; + UINTN NumMissed; + UINTN PacketSize; + UINTN SaveReplyLen; + UINTN ReplyLen; + UINT16 Timeout; + + LastBlockNum = *StartBlockPtr; + Timeout = ListenTimeout; + *NumMissedPtr = 0; + PacketSize = 0; + BufferSize = *BufferSizePtr; + ReplyLen = MAX_TFTP_PKT_SIZE;; + + // + // receive + // + do { + if ((SaveReplyLen = ReplyLen) > BufferSize) { + SaveReplyLen = (UINTN) BufferSize; + } + + /* %%TBD - add big block number support */ + + // + // get data - loop on resends + // + do { + ReplyLen = SaveReplyLen; + + if ((Status = TftpUdpRead ( + Private, + 0, + &Header, + &ReplyLen, + BufferPtr, + ServerIpPtr, + &MtftpInfoPtr->SPort, + &MtftpInfoPtr->MCastIp, + &MtftpInfoPtr->CPort, + Timeout + )) != EFI_SUCCESS) { + return Status; + } + // + // make sure a data packet + // + if (Header.OpCode != HTONS (TFTP_DATA)) { + return EFI_PROTOCOL_ERROR; + } + } while ((BlockNum = NTOHS (Header.BlockNum)) == LastBlockNum); + + // + // make sure still going up + // + if (LastBlockNum > BlockNum) { + return EFI_PROTOCOL_ERROR; + } + + if (BlockNum - LastBlockNum > 0xFFFFFFFF) { + return EFI_PROTOCOL_ERROR; + } else { + NumMissed = (UINTN) (BlockNum - LastBlockNum - 1); + } + + LastBlockNum = BlockNum; + + // + // if first time through, some reinitialization + // + if (!PacketSize) { + *StartBlockPtr = BlockNum; + PacketSize = ReplyLen; + Timeout = TransTimeout; + } else { + *NumMissedPtr = (UINT16) (*NumMissedPtr + NumMissed); + } + // + // if missed packets, update start block, + // etc. and move packet to proper place in buffer + // + if (NumMissed) { + *StartBlockPtr = BlockNum; + if (!DontUseBuffer) { + Offset = NumMissed * PacketSize; + CopyMem (BufferPtr + Offset, BufferPtr, ReplyLen); + BufferPtr += Offset; + BufferSize -= Offset; + } + } + + if (!DontUseBuffer) { + BufferPtr += ReplyLen; + BufferSize -= ReplyLen; + } + } while (ReplyLen == PacketSize && BlockNum != FinalBlock); + + *BufferSizePtr = BufferSize; + + return EFI_SUCCESS; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +STATIC +EFI_STATUS +MtftpOpen ( + PXE_BASECODE_DEVICE * Private, + UINT64 *BufferSizePtr, + UINT8 *BufferPtr, + UINTN *PacketSizePtr, + EFI_IP_ADDRESS * ServerIpPtr, + UINT8 *FilenamePtr, + EFI_PXE_BASE_CODE_MTFTP_INFO * MtftpInfoPtr, + UINT8 *CompletionStatusPtr, +#define GOTUNI 1 +#define GOTMULTI 2 + IN BOOLEAN DontUseBuffer + ) +/*++ +Routine description: + Open MTFTP session. + +Parameters: + Private := Pointer to PxeBc interface + BufferSizePtr := IN=buffer size OUT=transfer size + BufferPtr := + PacketSizePtr := + ServerIpPtr := + FilenamePtr := + MtftpInfoPtr := + CompletionStatusPtr := + DontUseBuffer := + +Returns: +// mtftp open session +// return code EFI_SUCCESS +// and *CompletionStatusPtr = GOTUNI | GOTMULTI means done +// and *CompletionStatusPtr = GOTMULTI means got first two multicast packets, use listen for rest +// and *CompletionStatusPtr = 0 means did not get first two multicast packets, use listen for all +// (do not get = GOTUNI - returns NO_DATA go will go to TFTP session) +--*/ +{ + EFI_STATUS Status; + EFI_IP_ADDRESS OurReplyIp; + struct Tftpv4Ack Header; + INTN ReplyLen; + INTN Retries; + UINT8 *BufferPtr2; + UINT8 TmpBuf[514]; + + Retries = NUM_MTFTP_OPEN_RETRIES; + BufferPtr2 = BufferPtr; + *PacketSizePtr = (UINTN) (EFI_MIN (*BufferSizePtr, MAX_TFTP_PKT_SIZE)); + + do { + // + // send a read request + // + *CompletionStatusPtr = 0; + + if ((Status = TftpRwReq ( + TFTP_RRQ, + 0, + Private, + ServerIpPtr, + &MtftpInfoPtr->SPort, + &MtftpInfoPtr->CPort, + FilenamePtr, + PacketSizePtr, + TmpBuf + )) != EFI_SUCCESS) { + return Status; + } + + for (;;) { + // + // read reply + // + ZeroMem (&OurReplyIp, Private->IpLength); + ReplyLen = *PacketSizePtr; + + if ((Status = TftpUdpRead ( + Private, + EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER, + &Header, + (UINTN *) &ReplyLen, + BufferPtr2, + ServerIpPtr, + &MtftpInfoPtr->SPort, + &OurReplyIp, + &MtftpInfoPtr->CPort, + MtftpInfoPtr->TransmitTimeout + )) == EFI_SUCCESS) { + // + // check for first data packet + // + if (Header.OpCode != HTONS (TFTP_DATA)) { + return EFI_PROTOCOL_ERROR; + } + // + // check block num + // + if (Header.BlockNum != HTONS (1)) { + // + // it's not first + // if we are not the primary client, + // we probably got first and now second + // multicast but no unicast, so + // *CompletionStatusPtr = GOTMULTI - if this is + // the second, can just go on to listen + // starting with 2 as the last block + // received + // + if (Header.BlockNum != HTONS (2)) { + // + // not second + // + *CompletionStatusPtr = 0; + } + + return Status; + } + + // + // now actual + // + *PacketSizePtr = ReplyLen; + // + // see if a unicast data packet + // + if (!CompareMem ( + &OurReplyIp, + &Private->EfiBc.Mode->StationIp, + Private->IpLength + )) { + *CompletionStatusPtr |= GOTUNI; + // + // it is + // if already got multicast packet, + // got em both + // + if (*CompletionStatusPtr & GOTMULTI) { + break; + } + } else if (!CompareMem ( + &OurReplyIp, + &MtftpInfoPtr->MCastIp, + Private->IpLength + )) { + // + // otherwise see if a multicast data packet + // + *CompletionStatusPtr |= GOTMULTI; + // + // it is + // got first - bump pointer so that if + // second multi comes along, we're OK + // + if (!DontUseBuffer) { + BufferPtr2 = (UINT8 *) BufferPtr + ReplyLen; + } + // + // if already got unicast packet, + // got em both + // + if (*CompletionStatusPtr & GOTUNI) { + break; + } + } else { + // + // else protocol error + // + return EFI_PROTOCOL_ERROR; + } + } else if (Status == EFI_TIMEOUT) { + // + // bad return code - if timed out, retry + // + break; + } else { + // + // else just bad - failed MTFTP open + // + return Status; + } + } + } while (Status == EFI_TIMEOUT && --Retries); + + if (Status != EFI_SUCCESS) { + // + // open failed + // + return Status; + } + // + // got em both - go into receive mode + // routine to read rest of file after a successful open (TFTP or MTFTP) + // sends ACK and gets next data packet until short packet arrives, + // then sends ACK and (hopefully) times out + // + return LockStepReceive ( + Private, + (UINT16) ReplyLen, + BufferSizePtr, + ReplyLen, + BufferPtr, + ServerIpPtr, + &MtftpInfoPtr->SPort, + &MtftpInfoPtr->MCastIp, + &MtftpInfoPtr->CPort, + 1, + MtftpInfoPtr->TransmitTimeout, + DontUseBuffer + ); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +EFI_STATUS +MtftpDownload ( + PXE_BASECODE_DEVICE *Private, + UINT64 *BufferSizePtr, + UINT8 *BufferPtr, + EFI_IP_ADDRESS *ServerIpPtr, + UINT8 *FilenamePtr, + EFI_PXE_BASE_CODE_MTFTP_INFO *MtftpInfoPtr, + IN BOOLEAN DontUseBuffer + ) +/*++ +Routine description: +// mtftp +// loop +// listen +// if did not get any packets, try MTFTP open +// if got all packets, return +// compute listen timeout and loop + +Parameters: + Private := Pointer to PxeBc interface + BufferSizePtr := + BufferPtr := + ServerIpPtr := + FilenamePtr := + MtftpInfoPtr := + DontUseBuffer := + +Returns: +--*/ +{ + EFI_PXE_BASE_CODE_IP_FILTER Filter; + EFI_STATUS Status; + UINT64 StartBlock; + UINT64 LastBlock; + UINT64 LastStartBlock; + UINT64 BufferSize; + UINTN Offset; + UINTN NumMissed; + UINT16 TransTimeout; + UINT16 ListenTimeout; + UINT8 *BufferPtrLocal; + + TransTimeout = MtftpInfoPtr->TransmitTimeout; + ListenTimeout = MtftpInfoPtr->ListenTimeout; + LastBlock = 0; + LastStartBlock = 0; + Offset = 0; + + Filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST; + Filter.IpCnt = 2; + CopyMem (&Filter.IpList[0], &Private->EfiBc.Mode->StationIp, sizeof (EFI_IP_ADDRESS)); + CopyMem (&Filter.IpList[1], &MtftpInfoPtr->MCastIp, sizeof (EFI_IP_ADDRESS)); + + if ((Status = IpFilter (Private, &Filter)) != EFI_SUCCESS) { + return Status; + } + + for (;;) { + StartBlock = LastStartBlock; + BufferSize = *BufferSizePtr - Offset; + + if (DontUseBuffer) { + // + // overwrie the temp buf + // + BufferPtrLocal = BufferPtr; + } else { + BufferPtrLocal = BufferPtr + Offset; + + } + // + // special !!! do not leave enabled in saved version on Source Safe + // Following code put in in order to create a special version for regression + // test of MTFTP server to make sure it handles mulitple opens correctly. + // This code should NOT be enabled normally. + // +#ifdef SpecialNowaitVersion +#pragma message ("This is special version for MTFTP regression test") + if (StartBlock || !LastBlock) +#endif + if (((Status = MtftpListen ( + Private, + &BufferSize, + BufferPtrLocal, + ServerIpPtr, + MtftpInfoPtr, + &StartBlock, + &NumMissed, + TransTimeout, + ListenTimeout, + LastBlock, + DontUseBuffer + )) != EFI_SUCCESS) && (Status != EFI_TIMEOUT)) { + return Status; + // + // failed + // + } + // + // if none were received, start block is not reset + // + if (StartBlock == LastStartBlock) { + UINT8 CompStat; + + // + // timed out with none received - try MTFTP open + // + if ((Status = MtftpOpen ( + Private, + BufferSizePtr, + BufferPtr, + &Offset, + ServerIpPtr, + FilenamePtr, + MtftpInfoPtr, + &CompStat, + DontUseBuffer + )) != EFI_SUCCESS) { + // + // open failure - try TFTP + // + return Status; + } + // + // return code EFI_SUCCESS + // and *CompletionStatusPtr = GOTUNI | GOTMULTI means done + // and *CompletionStatusPtr = GOTMULTI means got first two multicast packets, use listen for rest + // and *CompletionStatusPtr = 0 means did not get first two multicast packets, use listen for all + // (do not get = GOTUNI - returns NO_DATA go will go to TFTP session) + // + if (CompStat == (GOTUNI | GOTMULTI)) { + // + // finished - got it all + // + return Status; + } + + if (CompStat) { + // + // offset is two packet lengths + // + Offset <<= 1; + // + // last block received + // + LastStartBlock = 2; + } else { + Offset = 0; + LastStartBlock = 0; + } + + ListenTimeout = TransTimeout; + continue; + } + // + // did we get the last block + // + if (Status == EFI_SUCCESS) { + // + // yes - set the file size if this was first time + // + if (!LastBlock) { + *BufferSizePtr -= BufferSize; + } + // + // if buffer was too small, finished + // + if (!DontUseBuffer) { + return EFI_BUFFER_TOO_SMALL; + } + // + // if we got them all, finished + // + if (!NumMissed && StartBlock == LastStartBlock + 1) { + return Status; + } + // + // did not get them all - set last block + // + LastBlock = (UINT16) (StartBlock - 1); + } + // + // compute listen timeout + // + ListenTimeout = (UINT16) ((NumMissed > MtftpInfoPtr->ListenTimeout) ? 0 : (MtftpInfoPtr->ListenTimeout - NumMissed)); + + // + // reset + // + Offset = 0; + LastStartBlock = 0; + } +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +STATIC +EFI_STATUS +TftpInfo ( + PXE_BASECODE_DEVICE *Private, + UINT64 *BufferSizePtr, + EFI_IP_ADDRESS *ServerIpPtr, + EFI_PXE_BASE_CODE_UDP_PORT SrvPort, + UINT8 *FilenamePtr, + UINTN *PacketSizePtr + ) +/*++ +Routine description: +// TFTP info request routine +// send read request with block size and transfer size options +// get reply +// send error to terminate session +// if OACK received, set info + +Parameters: + Private := + BufferSizePtr := + ServerIpPtr := + SrvPort := + FilenamePtr := + PacketSizePtr := + +Returns: +--*/ +{ + EFI_PXE_BASE_CODE_UDP_PORT OurPort; + EFI_PXE_BASE_CODE_UDP_PORT ServerReplyPort; + EFI_STATUS Status; + UINT64 BlockNum; + UINTN Offset; + UINTN ReplyLen; + UINT8 *Ptr; + + union { + struct Tftpv4Oack OAck2Ptr; + struct Tftpv4Ack Ack2Ptr; + struct Tftpv4Data Datastr; + } u; + + OurPort = 0; + ServerReplyPort = 0; + ReplyLen = sizeof (u.Datastr.Data); + + // + // send a write request with the blocksize option - + // sets our IP and port - and receive reply - sets his port + // will retry operation up to 3 times if no response, + // and will retry without options on an error reply + // + if ((Status = TftpRwReqwResp ( + TFTP_RRQ, + /* BIGBLKNUMOP | */BKSZOP | TSIZEOP, + Private, + &u, + PacketSizePtr, + &ReplyLen, + u.Datastr.Data, + ServerIpPtr, + &SrvPort, + &ServerReplyPort, + &OurPort, + FilenamePtr, + REQ_RESP_TIMEOUT + )) != EFI_SUCCESS) { + DEBUG ((EFI_D_WARN, "\nTftpInfo() Exit #1")); + return Status; + } + // + // check for good OACK + // + if (u.OAck2Ptr.OpCode == HTONS (TFTP_OACK)) { + // + // now parse it for options + // bigblk# + // + Ptr = FindOption ( + BigBlkNumOp, + sizeof (BigBlkNumOp), + u.OAck2Ptr.OpAck[0].Option, + ReplyLen + sizeof (u.Ack2Ptr.BlockNum) + ); + + if (Ptr != NULL) { + if (AtoU (Ptr) == 8) { + Private->BigBlkNumFlag = TRUE; + } else { + return EFI_PROTOCOL_ERROR; + } + } + // + // blksize + // + Ptr = FindOption ( + BlockSizeOp, + sizeof (BlockSizeOp), + u.OAck2Ptr.OpAck[0].Option, + ReplyLen += sizeof (u.Ack2Ptr.BlockNum) + ); + + *PacketSizePtr = (Ptr) ? AtoU (Ptr) : 512; + + // + // tsize + // + Ptr = FindOption ( + TsizeOp, + sizeof (TsizeOp), + u.OAck2Ptr.OpAck[0].Option, + ReplyLen + ); + + if (Ptr != NULL) { + *BufferSizePtr = AtoU64 (Ptr); + + // + // teminate session with error + // + SendError (Private, ServerIpPtr, &ServerReplyPort, &OurPort); + + return EFI_SUCCESS; + } + + Offset = 0; + BlockNum = 0; + } else { + // + // if MTFTP get filesize, return unsupported + // + if (SrvPort != TftpRequestPort) { + SendError (Private, ServerIpPtr, &ServerReplyPort, &OurPort); + DEBUG ((EFI_D_WARN, "\nTftpInfo() Exit #3")); + return EFI_UNSUPPORTED; + } + + Offset = ReplyLen; + // + // last block received + // + BlockNum = 1; + } + // + // does not support the option - do a download with no buffer + // + *BufferSizePtr = 0; + + Status = LockStepReceive ( + Private, + (UINT16) ReplyLen, + BufferSizePtr, + Offset, + (UINT8 *) &u, + ServerIpPtr, + &ServerReplyPort, + &Private->EfiBc.Mode->StationIp, + &OurPort, + BlockNum, + ACK_TIMEOUT, + TRUE + ); + + if (Status != EFI_SUCCESS) { + DEBUG ((EFI_D_WARN, "\nTftpInfo() LockStepReceive() == %Xh", Status)); + } + + if (Status != EFI_BUFFER_TOO_SMALL) { + return Status; + } + + return EFI_SUCCESS; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +STATIC +EFI_STATUS +TftpDownload ( + PXE_BASECODE_DEVICE *Private, + UINT64 *BufferSizePtr, + UINT8 *BufferPtr, + EFI_IP_ADDRESS *ServerIpPtr, + UINT8 *FilenamePtr, + UINTN *PacketSizePtr, + EFI_PXE_BASE_CODE_UDP_PORT SrvPort, + UINT16 Req, + IN BOOLEAN DontUseBuffer + ) +/*++ +Routine description: +// tftp read session +// send read request +// [get OACK +// send ACK] +// loop +// get data +// send ACK +// while data size is max + +Parameters: + Private := + BufferSizePtr := + BufferPtr := + ServerIpPtr := + FilenamePtr := + PacketSizePtr := + SrvPort := + Req := + DontUseBuffer := + +Returns: +--*/ +{ + EFI_PXE_BASE_CODE_UDP_PORT OurPort; + EFI_PXE_BASE_CODE_UDP_PORT ServerReplyPort; + EFI_STATUS Status; + UINT64 Offset; + UINT64 BlockNum; + UINTN ReplyLen; + UINT8 *Ptr; + + union { + struct Tftpv4Ack Ack2Ptr; + struct Tftpv4Oack OAck2Ptr; + struct Tftpv4Data Data; + struct Tftpv4Ack8 Ack8Ptr; + struct Tftpv4Data8 Data8; + } U; + + OurPort = 0; + ServerReplyPort = 0; + ReplyLen = (UINTN) ((*BufferSizePtr > 0xFFFF) ? 0xFFFF : *BufferSizePtr); + + // + // send a read request with the blocksize option - sets our IP and port + // - and receive reply - sets his port will retry operation up to 3 + // times if no response, and will retry without options on an error + // reply + // + if ((Status = TftpRwReqwResp ( + Req, + /* BIGBLKNUMOP | */BKSZOP, + Private, + &U, + PacketSizePtr, + &ReplyLen, + BufferPtr, + ServerIpPtr, + &SrvPort, + &ServerReplyPort, + &OurPort, + FilenamePtr, + REQ_RESP_TIMEOUT + )) != EFI_SUCCESS) { + DEBUG ((EFI_D_WARN, "\nTftpDownload() Exit #1 %xh (%r)", Status, Status)); + return Status; + } + // + // check for OACK + // + if (U.OAck2Ptr.OpCode == HTONS (TFTP_OACK)) { + // + // get the OACK + // + CopyMem (U.Data.Data, BufferPtr, ReplyLen); + + Ptr = FindOption ( + BigBlkNumOp, + sizeof (BigBlkNumOp), + U.OAck2Ptr.OpAck[0].Option, + ReplyLen + sizeof (U.Ack2Ptr.BlockNum) + ); + + if (Ptr != NULL) { + if (AtoU (Ptr) == 8) { + Private->BigBlkNumFlag = TRUE; + } else { + return EFI_PROTOCOL_ERROR; + } + } + // + // now parse it for blocksize option + // + Ptr = FindOption ( + BlockSizeOp, + sizeof (BlockSizeOp), + U.OAck2Ptr.OpAck[0].Option, + ReplyLen += sizeof (U.Ack2Ptr.BlockNum) + ); + + ReplyLen = (Ptr != NULL) ? AtoU (Ptr) : 512; + + Offset = 0; + // + // last block received + // + BlockNum = 0; + } else if (U.Ack2Ptr.OpCode != HTONS (TFTP_DATA) || U.Ack2Ptr.BlockNum != HTONS (1)) { + // + // or data + // + DEBUG ((EFI_D_WARN, "\nTftpDownload() Exit #2 %xh (%r)", Status, Status)); + + return EFI_PROTOCOL_ERROR; + } else { + // + // got good data packet + // + Offset = ReplyLen; + // + // last block received + // + BlockNum = 1; + } + + if (PacketSizePtr != NULL) { + *PacketSizePtr = ReplyLen; + } + // + // routine to read rest of file after a successful open (TFTP or MTFTP) + // sends ACK and gets next data packet until short packet arrives, then sends + // ACK and (hopefully) times out + // if first packet has been read, BufferPtr and BufferSize must reflect fact + // + Status = LockStepReceive ( + Private, + ReplyLen, + BufferSizePtr, + Offset, + BufferPtr, + ServerIpPtr, + &ServerReplyPort, + &Private->EfiBc.Mode->StationIp, + &OurPort, + BlockNum, + ACK_TIMEOUT, + DontUseBuffer + ); + + if (Status != EFI_SUCCESS) { + DEBUG ((EFI_D_WARN, "\nTftpDownload() Exit #3 %xh (%r)", Status, Status)); + + if (Status == EFI_BUFFER_TOO_SMALL) { + Status = TftpInfo ( + Private, + BufferSizePtr, + ServerIpPtr, + SrvPort, + FilenamePtr, + PacketSizePtr + ); + + if (!EFI_ERROR (Status)) { + Status = EFI_BUFFER_TOO_SMALL; + } + } + } + + return Status; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +STATIC +EFI_STATUS +TftpUpload ( + PXE_BASECODE_DEVICE *Private, + UINT64 *BufferSizePtr, + VOID *BufferPtr, + EFI_IP_ADDRESS *ServerIpPtr, + UINT8 *FilenamePtr, + UINTN *PacketSizePtr, + BOOLEAN Overwrite + ) +/*++ +Routine description: +// tftp write session +// send write request +// get OACK or ACK +// loop +// send min (rest of data, max data packet) +// get ACK +// while data size is max + +Parameters: + Private := + BufferSizePtr := + BufferPtr := + ServerIpPtr := + FilenamePtr := + PacketSizePtr := + Overwrite := + +Returns: +--*/ +{ + struct Tftpv4Ack Header; + EFI_PXE_BASE_CODE_UDP_PORT OurPort; + EFI_PXE_BASE_CODE_UDP_PORT ServerReplyPort; + EFI_STATUS Status; + UINT64 BlockNum; + UINT64 TransferSize; + UINTN ReplyLen; + UINTN TransferLen; + UINT16 Options; + UINT8 *Ptr; + + union { + struct Tftpv4Oack OAck2Ptr; + struct Tftpv4Ack Ack2Ptr; + struct Tftpv4Data Datastr; + } u; + + OurPort = 0; + ServerReplyPort = 0; + TransferSize = *BufferSizePtr; + ReplyLen = sizeof (u.Datastr.Data); + Options = (UINT16) ((Overwrite) ? OVERWRITEOP | BKSZOP : BKSZOP); + + // + // send a write request with the blocksize option - sets our IP and port - + // and receive reply - sets his port + // will retry operation up to 3 times if no response, and will retry without + // options on an error reply + // + if ((Status = TftpRwReqwResp ( + TFTP_WRQ, + Options, + Private, + &u, + PacketSizePtr, + &ReplyLen, + u.Datastr.Data, + ServerIpPtr, + &TftpRequestPort, + &ServerReplyPort, + &OurPort, + FilenamePtr, + REQ_RESP_TIMEOUT + )) != EFI_SUCCESS) { + return Status; + } + // + // check for OACK + // + if (u.OAck2Ptr.OpCode == HTONS (TFTP_OACK)) { + // + // parse it for blocksize option + // + Ptr = FindOption ( + BlockSizeOp, + sizeof (BlockSizeOp), + u.OAck2Ptr.OpAck[0].Option, + ReplyLen += sizeof (u.Ack2Ptr.BlockNum) + ); + *PacketSizePtr = (Ptr) ? AtoU (Ptr) : 512; + } + // + // or ACK + // + else if (u.Ack2Ptr.OpCode == HTONS (TFTP_ACK)) { + // + // option was not supported + // + *PacketSizePtr = 512; + } else { + return EFI_PROTOCOL_ERROR; + } + // + // loop + // + Header.OpCode = HTONS (TFTP_DATA); + BlockNum = 1; + Header.BlockNum = HTONS (1); + + do { + UINTN HeaderSize; + INTN Retries; + + Retries = NUM_ACK_RETRIES; + HeaderSize = sizeof (Header); + TransferLen = (UINTN) (EFI_MIN (*PacketSizePtr, TransferSize)); + + // + // write a data packet and get an ack + // + do { + // + // write + // + if ((Status = UdpWrite ( + Private, + EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT, + ServerIpPtr, + &ServerReplyPort, + 0, + 0, + &OurPort, + &HeaderSize, + &Header, + &TransferLen, + BufferPtr + )) != EFI_SUCCESS) { + return Status; + } + // + // read reply + // + ReplyLen = sizeof (u.Datastr.Data); + + if ((Status = TftpUdpRead ( + Private, + 0, + &u, + &ReplyLen, + u.Datastr.Data, + ServerIpPtr, + &ServerReplyPort, + 0, + &OurPort, + ACK_TIMEOUT + )) == EFI_SUCCESS) { + // + // check for ACK for this data packet + // + if (u.Ack2Ptr.OpCode != HTONS (TFTP_ACK)) { + return EFI_PROTOCOL_ERROR; + } + + if (u.Ack2Ptr.BlockNum != Header.BlockNum) { + // + // not for this packet - continue + // + Status = EFI_TIMEOUT; + } + } + } while (Status == EFI_TIMEOUT && --Retries); + + if (Status != EFI_SUCCESS) { + return Status; + } + + BufferPtr = (VOID *) ((UINT8 *) (BufferPtr) + TransferLen); + TransferSize -= TransferLen; + ++BlockNum; + Header.BlockNum = HTONS ((UINT16) BlockNum); + } while (TransferLen == *PacketSizePtr); + + return EFI_SUCCESS; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +EFI_STATUS +PxeBcMtftp ( + PXE_BASECODE_DEVICE *Private, + IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation, + UINT64 *BufferSizePtr, + VOID *BufferPtr, + EFI_IP_ADDRESS *ServerIpPtr, + UINT8 *FilenamePtr, + UINTN *PacketSizePtr, + IN EFI_PXE_BASE_CODE_MTFTP_INFO *MtftpInfoPtr, OPTIONAL + IN BOOLEAN Overwrite, + IN BOOLEAN DontUseBuffer + ) +/*++ +Routine description: + MTFTP API entry point + +Parameters: + Private := + Operation := + BufferSizePtr := + BufferPtr := + ServerIpPtr := + FilenamePtr := + PacketSizePtr := + MtftpInfoPtr := + Overwrite := + DontUseBuffer := + +Returns: + * EFI_INVALID_PARAMETER + * EFI_OUT_OF_RESOURCES + * EFI_BAD_BUFFER_SIZE + * Status is also returned from IpFilter(), TftpInfo(), MtftpDownload(), + * TftpDownload() and TftpUpload(). +--*/ +{ + EFI_PXE_BASE_CODE_IP_FILTER Filter; + EFI_STATUS StatCode; + EFI_STATUS Status; + UINT64 BufferSizeLocal; + UINTN PacketSize; + UINT8 *BufferPtrLocal; + + Filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP; + Filter.IpCnt = 0; + Filter.reserved = 0; + + /* No error has occurred, yet. */ + Private->EfiBc.Mode->TftpErrorReceived = FALSE; + + /* We must at least have an MTFTP server IP address and + * a pointer to the buffer size. + */ + if (!ServerIpPtr || !BufferSizePtr) { + DEBUG ((EFI_D_WARN, "\nPxeBcMtftp() Exit #1")); + + return EFI_INVALID_PARAMETER; + } + + Private->Function = EFI_PXE_BASE_CODE_FUNCTION_MTFTP; + + // + // make sure filter set to unicast at start + // + if ((StatCode = IpFilter (Private, &Filter)) != EFI_SUCCESS) { + DEBUG ( + (EFI_D_NET, + "\nPxeBcMtftp() Exit IpFilter() == %Xh", + StatCode) + ); + + return StatCode; + } + // + // set unset parms to default values + // + if (!PacketSizePtr) { + *(PacketSizePtr = &PacketSize) = MAX_TFTP_PKT_SIZE; + } + + if (*PacketSizePtr > *BufferSizePtr) { + *PacketSizePtr = (UINTN) *BufferSizePtr; + } + + if (*PacketSizePtr < MIN_TFTP_PKT_SIZE) { + *PacketSizePtr = MIN_TFTP_PKT_SIZE; + } + + if (*PacketSizePtr > BUFFER_ALLOCATE_SIZE) { + *PacketSizePtr = BUFFER_ALLOCATE_SIZE; + } + + if (*PacketSizePtr > MAX_TFTP_PKT_SIZE) { + *PacketSizePtr = MAX_TFTP_PKT_SIZE; + } + + if (Operation == EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE) { + StatCode = TftpInfo ( + Private, + BufferSizePtr, + ServerIpPtr, + TftpRequestPort, + FilenamePtr, + PacketSizePtr + ); + + if (StatCode != EFI_SUCCESS) { + DEBUG ( + (EFI_D_WARN, + "\nPxeBcMtftp() Exit TftpInfo() == %Xh", + StatCode) + ); + } + + return StatCode; + } + + if (Operation == EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE) { + if (!MtftpInfoPtr || !MtftpInfoPtr->SPort) { + DEBUG ((EFI_D_WARN, "\nPxeBcMtftp() Exit #2")); + return EFI_INVALID_PARAMETER; + } else { + StatCode = TftpInfo ( + Private, + BufferSizePtr, + ServerIpPtr, + MtftpInfoPtr->SPort, + FilenamePtr, + PacketSizePtr + ); + + gBS->Stall (10000); + + if (StatCode != EFI_SUCCESS) { + DEBUG ( + (EFI_D_WARN, + "\nPxeBcMtftp() Exit TftpInfo() == %Xh", + StatCode) + ); + } + + return StatCode; + } + } + + if (!BufferPtr && !DontUseBuffer) { + // + // if dontusebuffer is false and no buffer??? + // + DEBUG ((EFI_D_WARN, "\nPxeBcMtftp() Exit #3")); + // + // DontUseBuffer can be true only for read_file operation + // + return EFI_INVALID_PARAMETER; + } + + if (DontUseBuffer) { + Status = gBS->AllocatePool ( + EfiBootServicesData, + BUFFER_ALLOCATE_SIZE, + (VOID **) &BufferPtrLocal + ); + + if (EFI_ERROR (Status) || BufferPtrLocal == NULL) { + DEBUG ((EFI_D_NET, "\nPxeBcMtftp() Exit #4")); + return EFI_OUT_OF_RESOURCES; + } + + BufferSizeLocal = BUFFER_ALLOCATE_SIZE; + } else { + if (!*BufferSizePtr && Operation != EFI_PXE_BASE_CODE_TFTP_WRITE_FILE) { + DEBUG ((EFI_D_WARN, "\nPxeBcMtftp() Exit #5")); + return EFI_BAD_BUFFER_SIZE; + } + + BufferPtrLocal = BufferPtr; + BufferSizeLocal = *BufferSizePtr; + } + + switch (Operation) { + case EFI_PXE_BASE_CODE_MTFTP_READ_FILE: + if (FilenamePtr == NULL || + MtftpInfoPtr == NULL || + MtftpInfoPtr->MCastIp.Addr[0] == 0 || + MtftpInfoPtr->SPort == 0 || + MtftpInfoPtr->CPort == 0 || + MtftpInfoPtr->ListenTimeout == 0 || + MtftpInfoPtr->TransmitTimeout == 0 + ) { + StatCode = EFI_INVALID_PARAMETER; + break; + } + // + // try MTFTP - if fails, drop into TFTP read + // + if ((StatCode = MtftpDownload ( + Private, + &BufferSizeLocal, + BufferPtrLocal, + ServerIpPtr, + FilenamePtr, + MtftpInfoPtr, + DontUseBuffer + )) == EFI_SUCCESS || StatCode == EFI_BUFFER_TOO_SMALL) { + if (BufferSizePtr /* %% !DontUseBuffer */ ) { + *BufferSizePtr = BufferSizeLocal; + } + + break; + } + // + // go back to unicast + // + if ((StatCode = IpFilter (Private, &Filter)) != EFI_SUCCESS) { + break; + } + + /* fall thru */ + case EFI_PXE_BASE_CODE_TFTP_READ_FILE: + if (FilenamePtr == NULL) { + StatCode = EFI_INVALID_PARAMETER; + break; + } + + StatCode = TftpDownload ( + Private, + &BufferSizeLocal, + BufferPtrLocal, + ServerIpPtr, + FilenamePtr, + PacketSizePtr, + TftpRequestPort, + TFTP_RRQ, + DontUseBuffer + ); + + if (StatCode == EFI_SUCCESS || StatCode == EFI_BUFFER_TOO_SMALL) { + if (BufferSizePtr /* !DontUseBuffer */ ) { + *BufferSizePtr = BufferSizeLocal; + } + } + + break; + + case EFI_PXE_BASE_CODE_TFTP_WRITE_FILE: + if (FilenamePtr == NULL || DontUseBuffer) { + // + // not a valid option + // + StatCode = EFI_INVALID_PARAMETER; + break; + } + + StatCode = TftpUpload ( + Private, + BufferSizePtr, + BufferPtr, + ServerIpPtr, + FilenamePtr, + PacketSizePtr, + Overwrite + ); + + if (StatCode != EFI_SUCCESS) { + DEBUG ( + (EFI_D_WARN, + "\nPxeBcMtftp() Exit #6 %xh (%r)", + StatCode, + StatCode) + ); + } + + return StatCode; + + case EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY: + if (FilenamePtr == NULL || DontUseBuffer) { + // + // not a valid option + // + StatCode = EFI_INVALID_PARAMETER; + break; + } + + StatCode = TftpDownload ( + Private, + BufferSizePtr, + BufferPtr, + ServerIpPtr, + FilenamePtr, + PacketSizePtr, + TftpRequestPort, + TFTP_DIR, + DontUseBuffer + ); + + if (StatCode != EFI_SUCCESS) { + DEBUG ( + (EFI_D_WARN, + "\nPxeBcMtftp() Exit #7 %xh (%r)", + StatCode, + StatCode) + ); + } + + return StatCode; + + case EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY: + if (DontUseBuffer) { + StatCode = EFI_INVALID_PARAMETER; + break; + } + + if (MtftpInfoPtr == NULL || !MtftpInfoPtr->SPort) { + DEBUG ( + (EFI_D_WARN, + "\nPxeBcMtftp() Exit #9 %xh (%r)", + EFI_INVALID_PARAMETER, + EFI_INVALID_PARAMETER) + ); + + return EFI_INVALID_PARAMETER; + } + + StatCode = TftpDownload ( + Private, + BufferSizePtr, + BufferPtr, + ServerIpPtr, + (UINT8 *) "/", + PacketSizePtr, + MtftpInfoPtr->SPort, + TFTP_DIR, + DontUseBuffer + ); + + break; + + default: + StatCode = EFI_INVALID_PARAMETER; + } + + if (DontUseBuffer) { + gBS->FreePool (BufferPtrLocal); + } + + if (StatCode != EFI_SUCCESS) { + DEBUG ( + (EFI_D_WARN, + "\nPxeBcMtftp() Exit #8 %xh (%r)", + StatCode, + StatCode) + ); + } + + gBS->Stall (10000); + + return StatCode; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +EFI_STATUS +EFIAPI +BcMtftp ( + IN EFI_PXE_BASE_CODE_PROTOCOL * This, + IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation, + IN OUT VOID *BufferPtr, + IN BOOLEAN Overwrite, + IN OUT UINT64 *BufferSizePtr, + IN UINTN *BlockSizePtr OPTIONAL, + IN EFI_IP_ADDRESS * ServerIpPtr, + IN UINT8 *FilenamePtr, + IN EFI_PXE_BASE_CODE_MTFTP_INFO * MtftpInfoPtr OPTIONAL, + IN BOOLEAN DontUseBuffer + ) +/*++ +Routine description: + MTFTP API entry point. + +Parameters: + This := + Operation := + BufferPtr := + Overwrite := + BufferSizePtr := + BlockSizePtr := + ServerIpPtr := + FilenamePtr := + MtftpInfoPtr := + DontUseBuffer := + +Returns: + * EFI_INVALID_PARAMETER + * Status is also returned from PxeBcMtftp(); +--*/ +{ + EFI_PXE_BASE_CODE_IP_FILTER Filter; + EFI_STATUS StatCode; + PXE_BASECODE_DEVICE *Private; + + // + // Lock the instance data and make sure started + // + StatCode = EFI_SUCCESS; + + if (This == NULL) { + DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL")); + return EFI_INVALID_PARAMETER; + } + + Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE); + + if (Private == NULL) { + DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL")); + return EFI_INVALID_PARAMETER; + } + + EfiAcquireLock (&Private->Lock); + + if (This->Mode == NULL || !This->Mode->Started) { + DEBUG ((EFI_D_ERROR, "BC was not started.")); + EfiReleaseLock (&Private->Lock); + return EFI_NOT_STARTED; + } + // + // Issue BC command + // + Filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP; + Filter.IpCnt = 0; + Filter.reserved = 0; + + DEBUG ((EFI_D_WARN, "\nBcMtftp() Op=%d Buf=%Xh", Operation, BufferPtr)); + + StatCode = PxeBcMtftp ( + Private, + Operation, + BufferSizePtr, + BufferPtr, + ServerIpPtr, + FilenamePtr, + BlockSizePtr, + MtftpInfoPtr, + Overwrite, + DontUseBuffer + ); + + // + // restore to unicast + // + IpFilter (Private, &Filter); + + // + // Unlock the instance data + // + EfiReleaseLock (&Private->Lock); + return StatCode; +} + +/* eof - PxeBcMtftp.c */ diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_udp.c b/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_udp.c new file mode 100644 index 0000000000..ab9d3b794b --- /dev/null +++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_udp.c @@ -0,0 +1,577 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + pxe_bc_udp.c + +Abstract: + +--*/ + + +#include "bc.h" + +// +// ////////////////////////////////////////////////////////////////////// +// +// Udp Write Routine - called by base code - e.g. TFTP - already locked +// +EFI_STATUS +UdpWrite ( + IN PXE_BASECODE_DEVICE *Private, + IN UINT16 OpFlags, + IN EFI_IP_ADDRESS *DestIpPtr, + IN EFI_PXE_BASE_CODE_UDP_PORT *DestPortPtr, + IN EFI_IP_ADDRESS *GatewayIpPtr, OPTIONAL + IN EFI_IP_ADDRESS *SrcIpPtr, OPTIONAL + IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPortPtr, OPTIONAL + IN UINTN *HeaderSizePtr, OPTIONAL + IN VOID *HeaderPtr, OPTIONAL + IN UINTN *BufferSizeptr, + IN VOID *BufferPtr + ) +/*++ +Routine description: + UDP write packet. + +Parameters: + Private := Pointer to PxeBc interface + OpFlags := + DestIpPtr := + DestPortPtr := + GatewayIpPtr := + SrcIpPtr := + SrcPortPtr := + HeaderSizePtr := + HeaderPtr := + BufferSizeptr := + BufferPtr := + +Returns: + EFI_SUCCESS := + EFI_INVALID_PARAMETER := + other := +--*/ +{ + UINTN TotalLength; + UINTN HeaderSize; + EFI_PXE_BASE_CODE_UDP_PORT DefaultSrcPort; + + // + // + // + HeaderSize = (HeaderSizePtr != NULL) ? *HeaderSizePtr : 0; + DefaultSrcPort = 0; + + // + // check parameters + // + if (BufferSizeptr == NULL || + BufferPtr == NULL || + DestIpPtr == NULL || + DestPortPtr == NULL || + (HeaderSizePtr != NULL && *HeaderSizePtr == 0) || + (HeaderSize != 0 && HeaderPtr == NULL) || + (GatewayIpPtr != NULL && !IS_INADDR_UNICAST(GatewayIpPtr)) || + (OpFlags &~(EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT)) + ) { + DEBUG ( + (EFI_D_WARN, + "\nUdpWrite() Exit #1 %xh (%r)", + EFI_INVALID_PARAMETER, + EFI_INVALID_PARAMETER) + ); + + return EFI_INVALID_PARAMETER; + } + + TotalLength = *BufferSizeptr + HeaderSize + sizeof (UDPV4_HEADER); + + if (TotalLength > 0x0000ffff) { + DEBUG ( + (EFI_D_WARN, + "\nUdpWrite() Exit #2 %xh (%r)", + EFI_BAD_BUFFER_SIZE, + EFI_BAD_BUFFER_SIZE) + ); + + return EFI_BAD_BUFFER_SIZE; + } + + if (SrcIpPtr == NULL) { + SrcIpPtr = &Private->EfiBc.Mode->StationIp; + } + + if (SrcPortPtr == NULL) { + SrcPortPtr = &DefaultSrcPort; + OpFlags |= EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT; + } + + if (OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) { + *SrcPortPtr = Private->RandomPort; + + if (++Private->RandomPort == 0) { + Private->RandomPort = PXE_RND_PORT_LOW; + } + } + +#define IpTxBuffer ((IPV4_BUFFER *) Private->TransmitBufferPtr) + // + // build pseudo header and udp header in transmit buffer + // +#define Udpv4Base ((UDPV4_HEADERS *) (IpTxBuffer->u.Data - sizeof (UDPV4_PSEUDO_HEADER))) + + Udpv4Base->Udpv4PseudoHeader.SrcAddr.L = SrcIpPtr->Addr[0]; + Udpv4Base->Udpv4PseudoHeader.DestAddr.L = DestIpPtr->Addr[0]; + Udpv4Base->Udpv4PseudoHeader.Zero = 0; + Udpv4Base->Udpv4PseudoHeader.Protocol = PROT_UDP; + Udpv4Base->Udpv4PseudoHeader.TotalLength = HTONS (TotalLength); + Udpv4Base->Udpv4Header.SrcPort = HTONS (*SrcPortPtr); + Udpv4Base->Udpv4Header.DestPort = HTONS (*DestPortPtr); + Udpv4Base->Udpv4Header.TotalLength = Udpv4Base->Udpv4PseudoHeader.TotalLength; + Udpv4Base->Udpv4Header.Checksum = 0; + + if (HeaderSize != 0) { + CopyMem (IpTxBuffer->u.Udp.Data, HeaderPtr, HeaderSize); + } + + HeaderSize += sizeof (UDPV4_HEADER); + + Udpv4Base->Udpv4Header.Checksum = IpChecksum2 ( + (UINT16 *) Udpv4Base, + HeaderSize + sizeof (UDPV4_PSEUDO_HEADER), + (UINT16 *) BufferPtr, + (UINT16) *BufferSizeptr + ); + + if (Udpv4Base->Udpv4Header.Checksum == 0) { + Udpv4Base->Udpv4Header.Checksum = 0xffff; + // + // transmit zero checksum as ones complement + // + } + + return Ip4Send ( + Private, + OpFlags, + PROT_UDP, + Udpv4Base->Udpv4PseudoHeader.SrcAddr.L, + Udpv4Base->Udpv4PseudoHeader.DestAddr.L, + (GatewayIpPtr) ? GatewayIpPtr->Addr[0] : 0, + HeaderSize, + BufferPtr, + *BufferSizeptr + ); +} +// +// ////////////////////////////////////////////////////////// +// +// BC Udp Write Routine +// +EFI_STATUS +EFIAPI +BcUdpWrite ( + IN EFI_PXE_BASE_CODE_PROTOCOL *This, + IN UINT16 OpFlags, + IN EFI_IP_ADDRESS *DestIpPtr, + IN EFI_PXE_BASE_CODE_UDP_PORT *DestPortPtr, + IN EFI_IP_ADDRESS *GatewayIpPtr, OPTIONAL + IN EFI_IP_ADDRESS *SrcIpPtr, OPTIONAL + IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPortPtr, OPTIONAL + IN UINTN *HeaderSizePtr, OPTIONAL + IN VOID *HeaderPtr, OPTIONAL + IN UINTN *BufferSizeptr, + IN VOID *BufferPtr + ) +/*++ +Routine description: + UDP write API entry point. + +Parameters: + This := Pointer to PxeBc interface. + OpFlags := + DestIpPtr := + DestPortPtr := + GatewayIpPtr := + SrcIpPtr := + SrcPortPtr := + HeaderSizePtr := + HeaderPtr := + BufferSizeptr := + BufferPtr := + +Returns: + EFI_SUCCESS := + other := +--*/ +{ + EFI_STATUS StatCode; + PXE_BASECODE_DEVICE *Private; + + // + // Lock the instance data and make sure started + // + StatCode = EFI_SUCCESS; + + if (This == NULL) { + DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL")); + return EFI_INVALID_PARAMETER; + } + + Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE); + + if (Private == NULL) { + DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL")); + return EFI_INVALID_PARAMETER; + } + + EfiAcquireLock (&Private->Lock); + + if (This->Mode == NULL || !This->Mode->Started) { + DEBUG ((EFI_D_ERROR, "BC was not started.")); + EfiReleaseLock (&Private->Lock); + return EFI_NOT_STARTED; + } + + Private->Function = EFI_PXE_BASE_CODE_FUNCTION_UDP_WRITE; + + // + // Issue BC command + // + StatCode = UdpWrite ( + Private, + OpFlags, + DestIpPtr, + DestPortPtr, + GatewayIpPtr, + SrcIpPtr, + SrcPortPtr, + HeaderSizePtr, + HeaderPtr, + BufferSizeptr, + BufferPtr + ); + + // + // Unlock the instance data + // + EfiReleaseLock (&Private->Lock); + return StatCode; +} +// +// ///////////////////////////////////////////////////////////////////// +// +// Udp Read Routine - called by base code - e.g. TFTP - already locked +// +EFI_STATUS +UdpRead ( + IN PXE_BASECODE_DEVICE *Private, + IN UINT16 OpFlags, + IN OUT EFI_IP_ADDRESS *DestIpPtr, OPTIONAL + IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPortPtr, OPTIONAL + IN OUT EFI_IP_ADDRESS *SrcIpPtr, OPTIONAL + IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPortPtr, OPTIONAL + IN UINTN *HeaderSizePtr, OPTIONAL + IN VOID *HeaderPtr, OPTIONAL + IN OUT UINTN *BufferSizeptr, + IN VOID *BufferPtr, + EFI_EVENT TimeoutEvent + ) +/*++ +Routine description: + UDP read packet. + +Parameters: + Private := Pointer to PxeBc interface + OpFlags := + DestIpPtr := + DestPortPtr := + SrcIpPtr := + SrcPortPtr := + HeaderSizePtr := + HeaderPtr := + BufferSizeptr := + BufferPtr := + TimeoutEvent := + +Returns: + EFI_SUCCESS := + EFI_INVALID_PARAMETER := + other := +--*/ +{ + EFI_STATUS StatCode; + EFI_IP_ADDRESS TmpSrcIp; + EFI_IP_ADDRESS TmpDestIp; + UINTN BufferSize; + UINTN HeaderSize; + + // + // combination structure of pseudo header/udp header + // +#pragma pack (1) + struct { + UDPV4_PSEUDO_HEADER Udpv4PseudoHeader; + UDPV4_HEADER Udpv4Header; + UINT8 ProtHdr[64]; + } Hdrs; +#pragma pack () + + HeaderSize = (HeaderSizePtr != NULL) ? *HeaderSizePtr : 0; + // + // read [with filtering] + // check parameters + // + if (BufferSizeptr == NULL || + BufferPtr == NULL || + (HeaderSize != 0 && HeaderPtr == NULL) || + (OpFlags &~UDP_FILTER_MASK) + // + // if filtering on a particular IP/Port, need it + // + || + (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) && SrcIpPtr == NULL) || + (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) && SrcPortPtr == NULL) || + (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) && DestPortPtr == NULL) + ) { + DEBUG ((EFI_D_INFO, "\nUdpRead() Exit #1 Invalid Parameter")); + return EFI_INVALID_PARAMETER; + } + + // + // in case we loop + // + BufferSize = *BufferSizeptr; + // + // we need source and dest IPs for pseudo header + // + if (SrcIpPtr == NULL) { + SrcIpPtr = &TmpSrcIp; + } + + if (DestIpPtr == NULL) { + DestIpPtr = &TmpDestIp; + CopyMem (&TmpDestIp, &Private->EfiBc.Mode->StationIp, sizeof (TmpDestIp)); + } + +#if SUPPORT_IPV6 + if (Private->EfiBc.Mode->UsingIpv6) { + // + // %%TBD + // + } +#endif + + for (;;) { + *BufferSizeptr = BufferSize; + + StatCode = IpReceive ( + Private, + OpFlags, + SrcIpPtr, + DestIpPtr, + PROT_UDP, + &Hdrs.Udpv4Header, + HeaderSize + sizeof Hdrs.Udpv4Header, + BufferPtr, + BufferSizeptr, + TimeoutEvent + ); + + if (StatCode == EFI_SUCCESS || StatCode == EFI_BUFFER_TOO_SMALL) { + UINT16 SPort; + UINT16 DPort; + + SPort = NTOHS (Hdrs.Udpv4Header.SrcPort); + DPort = NTOHS (Hdrs.Udpv4Header.DestPort); + + // + // do filtering + // + if (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) && *SrcPortPtr != SPort) { + continue; + } + + if (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) && *DestPortPtr != DPort) { + continue; + } + // + // check checksum + // + if (StatCode == EFI_SUCCESS && Hdrs.Udpv4Header.Checksum) { + Hdrs.Udpv4PseudoHeader.SrcAddr.L = SrcIpPtr->Addr[0]; + Hdrs.Udpv4PseudoHeader.DestAddr.L = DestIpPtr->Addr[0]; + Hdrs.Udpv4PseudoHeader.Zero = 0; + Hdrs.Udpv4PseudoHeader.Protocol = PROT_UDP; + Hdrs.Udpv4PseudoHeader.TotalLength = Hdrs.Udpv4Header.TotalLength; + + if (Hdrs.Udpv4Header.Checksum == 0xffff) { + Hdrs.Udpv4Header.Checksum = 0; + } + + if (IpChecksum2 ( + (UINT16 *) &Hdrs.Udpv4PseudoHeader, + HeaderSize + sizeof (Hdrs.Udpv4PseudoHeader) + sizeof (Hdrs.Udpv4Header), + (UINT16 *) BufferPtr, + *BufferSizeptr + )) { + DEBUG ( + (EFI_D_INFO, + "\nUdpRead() Hdrs.Udpv4PseudoHeader == %Xh", + &Hdrs.Udpv4PseudoHeader) + ); + DEBUG ( + (EFI_D_INFO, + "\nUdpRead() Header size == %d", + HeaderSize + sizeof (Hdrs.Udpv4PseudoHeader)) + ); + DEBUG ( + (EFI_D_INFO, + "\nUdpRead() BufferPtr == %Xh", + BufferPtr) + ); + DEBUG ( + (EFI_D_INFO, + "\nUdpRead() Buffer size == %d", + *BufferSizeptr) + ); + DEBUG ((EFI_D_INFO, "\nUdpRead() Exit #2 Device Error")); + return EFI_DEVICE_ERROR; + } + } + // + // all passed + // + if (SrcPortPtr != NULL) { + *SrcPortPtr = SPort; + } + + if (DestPortPtr != NULL) { + *DestPortPtr = DPort; + } + + if (HeaderSize != 0) { + CopyMem (HeaderPtr, Hdrs.ProtHdr, HeaderSize); + } + } + + switch (StatCode) { + case EFI_SUCCESS: + case EFI_TIMEOUT: + break; + + default: + DEBUG ( + (EFI_D_INFO, + "\nUdpRead() Exit #3 %Xh %r", + StatCode, + StatCode) + ); + } + + return StatCode; + } +} +// +// ////////////////////////////////////////////////////////// +// +// BC Udp Read Routine +// +EFI_STATUS +EFIAPI +BcUdpRead ( + IN EFI_PXE_BASE_CODE_PROTOCOL *This, + IN UINT16 OpFlags, + IN OUT EFI_IP_ADDRESS *DestIp, OPTIONAL + IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPort, OPTIONAL + IN OUT EFI_IP_ADDRESS *SrcIp, OPTIONAL + IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort, OPTIONAL + IN UINTN *HeaderSize, OPTIONAL + IN VOID *HeaderPtr, OPTIONAL + IN OUT UINTN *BufferSize, + IN VOID *BufferPtr + ) +/*++ +Routine description: + UDP read API entry point. + +Parameters: + This := Pointer to PxeBc interface. + OpFlags := + DestIpPtr := + DestPortPtr := + SrcIpPtr := + SrcPortPtr := + HeaderSizePtr := + HeaderPtr := + BufferSizeptr := + BufferPtr := + +Returns: + EFI_SUCCESS := + other := +--*/ +{ + EFI_STATUS StatCode; + PXE_BASECODE_DEVICE *Private; + + // + // Lock the instance data and make sure started + // + StatCode = EFI_SUCCESS; + + if (This == NULL) { + DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL")); + return EFI_INVALID_PARAMETER; + } + + Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE); + + if (Private == NULL) { + DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL")); + return EFI_INVALID_PARAMETER; + } + + EfiAcquireLock (&Private->Lock); + + if (This->Mode == NULL || !This->Mode->Started) { + DEBUG ((EFI_D_ERROR, "BC was not started.")); + EfiReleaseLock (&Private->Lock); + return EFI_NOT_STARTED; + } + + Private->Function = EFI_PXE_BASE_CODE_FUNCTION_UDP_READ; + + // + // Issue BC command + // + StatCode = UdpRead ( + Private, + OpFlags, + DestIp, + DestPort, + SrcIp, + SrcPort, + HeaderSize, + HeaderPtr, + BufferSize, + BufferPtr, + 0 + ); + + // + // Unlock the instance data and return + // + EfiReleaseLock (&Private->Lock); + return StatCode; +} + +/* eof - pxe_bc_udp.c */ diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_loadfile.c b/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_loadfile.c new file mode 100644 index 0000000000..8897bc726e --- /dev/null +++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_loadfile.c @@ -0,0 +1,1697 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + pxe_loadfile.c + +Abstract: + An implementation of the load file protocol for network devices. + +--*/ + + +#include "bc.h" + +#define DO_MENU (EFI_SUCCESS) +#define NO_MENU (DO_MENU + 1) +#define LOCAL_BOOT (EFI_ABORTED) +#define AUTO_SELECT (NO_MENU) + +#define NUMBER_ROWS 25 // we set to mode 0 +#define MAX_MENULIST 23 + +#define Ctl(x) (0x1F & (x)) + +typedef union { + DHCPV4_OP_STRUCT *OpPtr; + PXE_BOOT_MENU_ENTRY *CurrentMenuItemPtr; + PXE_OP_DISCOVERY_CONTROL *DiscCtlOpStr; + PXE_OP_BOOT_MENU *MenuPtr; + UINT8 *BytePtr; +} UNION_PTR; + + +STATIC +EFI_PXE_BASE_CODE_CALLBACK_STATUS +EFIAPI +bc_callback ( + IN EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL * This, + IN EFI_PXE_BASE_CODE_FUNCTION Function, + IN BOOLEAN Received, + IN UINT32 PacketLength, + IN EFI_PXE_BASE_CODE_PACKET * PacketPtr OPTIONAL + ) +/*++ + +Routine Description: + + PxeBc callback routine for status updates and aborts. + +Arguments: + + This - Pointer to PxeBcCallback interface + Function - PxeBc function ID# + Received - Receive/transmit flag + PacketLength - Length of received packet (0 == idle callback) + PacketPtr - Pointer to received packet (NULL == idle callback) + +Returns: + + EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE - + EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT - + +--*/ +{ + STATIC UINTN Propeller; + + EFI_INPUT_KEY Key; + UINTN Row; + UINTN Col; + + Propeller = 0; + // + // Resolve Warning 4 unreferenced parameter problem + // + This = This; + + // + // Check for user abort. + // + if (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key) == EFI_SUCCESS) { + if (!Key.ScanCode) { + if (Key.UnicodeChar == Ctl ('c')) { + return EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT; + } + } else if (Key.ScanCode == SCAN_ESC) { + return EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT; + } + } + // + // Do nothing if this is a receive. + // + if (Received) { + return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE; + } + // + // The display code is only for these functions. + // + switch (Function) { + case EFI_PXE_BASE_CODE_FUNCTION_MTFTP: + // + // If this is a transmit and not a M/TFTP open request, + // return now. Do not print a dot for each M/TFTP packet + // that is sent, only for the open packets. + // + if (PacketLength != 0 && PacketPtr != NULL) { + if (PacketPtr->Raw[0x1C] != 0x00 || PacketPtr->Raw[0x1D] != 0x01) { + return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE; + } + } + + break; + + case EFI_PXE_BASE_CODE_FUNCTION_DHCP: + case EFI_PXE_BASE_CODE_FUNCTION_DISCOVER: + break; + + default: + return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE; + } + // + // Display routines + // + if (PacketLength != 0 && PacketPtr != NULL) { + // + // Display a '.' when a packet is transmitted. + // + AsciiPrint ("."); + } else if (PacketLength == 0 && PacketPtr == NULL) { + // + // Display a propeller when waiting for packets if at + // least 200 ms have passed. + // + Row = gST->ConOut->Mode->CursorRow; + Col = gST->ConOut->Mode->CursorColumn; + + AsciiPrint ("%c", "/-\\|"[Propeller]); + gST->ConOut->SetCursorPosition (gST->ConOut, Col, Row); + + Propeller = (Propeller + 1) & 3; + } + + return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE; +} + +STATIC EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL _bc_callback = { + EFI_PXE_BASE_CODE_CALLBACK_INTERFACE_REVISION, + &bc_callback +}; + +STATIC +VOID +PrintIpv4 ( + UINT8 *Ptr + ) +/*++ + +Routine Description: + + Display an IPv4 address in dot notation. + +Arguments: + + Ptr - Pointer to IPv4 address. + +Returns: + + None + +--*/ +{ + if (Ptr != NULL) { + AsciiPrint ("%d.%d.%d.%d", Ptr[0], Ptr[1], Ptr[2], Ptr[3]); + } +} + +STATIC +VOID +ShowMyInfo ( + IN PXE_BASECODE_DEVICE *Private + ) +/*++ + +Routine Description: + + Display client and server IP information. + +Arguments: + + Private - Pointer to PxeBc interface + +Returns: + + None + +--*/ +{ + EFI_PXE_BASE_CODE_MODE *PxeBcMode; + UINTN Index; + + // + // Do nothing if a NULL pointer is passed in. + // + if (Private == NULL) { + return ; + } + // + // Get pointer to PXE BaseCode mode structure + // + PxeBcMode = Private->EfiBc.Mode; + + // + // Display client IP address + // + AsciiPrint ("\rCLIENT IP: "); + PrintIpv4 (PxeBcMode->StationIp.v4.Addr); + + // + // Display subnet mask + // + AsciiPrint (" MASK: "); + PrintIpv4 (PxeBcMode->SubnetMask.v4.Addr); + + // + // Display DHCP and proxyDHCP IP addresses + // + if (PxeBcMode->ProxyOfferReceived) { + AsciiPrint ("\nDHCP IP: "); + PrintIpv4 (((DHCPV4_OP_SERVER_IP *) DHCPV4_ACK_BUFFER.OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip.Addr); + + AsciiPrint (" PROXY IP: "); + PrintIpv4 (((DHCPV4_OP_SERVER_IP *) PXE_OFFER_BUFFER.OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip.Addr); + } else { + AsciiPrint (" DHCP IP: "); + PrintIpv4 (((DHCPV4_OP_SERVER_IP *) DHCPV4_ACK_BUFFER.OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip.Addr); + } + // + // Display gateway IP addresses + // + for (Index = 0; Index < PxeBcMode->RouteTableEntries; ++Index) { + if ((Index % 3) == 0) { + AsciiPrint ("\r\nGATEWAY IP:"); + } + + AsciiPrint (" "); + PrintIpv4 (PxeBcMode->RouteTable[Index].GwAddr.v4.Addr); + AsciiPrint (" "); + } + + AsciiPrint ("\n"); +} + +STATIC +EFI_STATUS +DoPrompt ( + PXE_BASECODE_DEVICE *Private, + PXE_OP_BOOT_PROMPT *BootPromptPtr + ) +/*++ + +Routine Description: + + Display prompt and wait for input. + +Arguments: + + Private - Pointer to PxeBc interface + BootPromptPtr - Pointer to PXE boot prompt option + +Returns: + + AUTO_SELECT - + DO_MENU - + NO_MENU - + LOCAL_BOOT - + +--*/ +{ + EFI_STATUS Status; + EFI_EVENT TimeoutEvent; + EFI_EVENT SecondsEvent; + INT32 SecColumn; + INT32 SecRow; + UINT8 SaveChar; + UINT8 SecsLeft; + + // + // if auto select, just get right to it + // + if (BootPromptPtr->Timeout == PXE_BOOT_PROMPT_AUTO_SELECT) { + return AUTO_SELECT; + } + // + // if no timeout, go directly to display of menu + // + if (BootPromptPtr->Timeout == PXE_BOOT_PROMPT_NO_TIMEOUT) { + return DO_MENU; + } + // + // + // + Status = gBS->CreateEvent ( + EFI_EVENT_TIMER, + EFI_TPL_CALLBACK, + NULL, + NULL, + &TimeoutEvent + ); + + if (EFI_ERROR (Status)) { + return DO_MENU; + } + + Status = gBS->SetTimer ( + TimeoutEvent, + TimerRelative, + BootPromptPtr->Timeout * 10000000 + 100000 + ); + + if (EFI_ERROR (Status)) { + gBS->CloseEvent (TimeoutEvent); + return DO_MENU; + } + // + // + // + Status = gBS->CreateEvent ( + EFI_EVENT_TIMER, + EFI_TPL_CALLBACK, + NULL, + NULL, + &SecondsEvent + ); + + if (EFI_ERROR (Status)) { + gBS->CloseEvent (TimeoutEvent); + return DO_MENU; + } + + Status = gBS->SetTimer ( + SecondsEvent, + TimerPeriodic, + 10000000 + ); /* 1 second */ + + if (EFI_ERROR (Status)) { + gBS->CloseEvent (SecondsEvent); + gBS->CloseEvent (TimeoutEvent); + return DO_MENU; + } + // + // display the prompt + // IMPORTANT! This prompt is an ASCII character string that may + // not be terminated with a NULL byte. + // + SaveChar = BootPromptPtr->Prompt[BootPromptPtr->Header.Length - 1]; + BootPromptPtr->Prompt[BootPromptPtr->Header.Length - 1] = 0; + + AsciiPrint ("%a ", BootPromptPtr->Prompt); + BootPromptPtr->Prompt[BootPromptPtr->Header.Length - 1] = SaveChar; + + // + // wait until time expires or selection made - menu or local + // + SecColumn = gST->ConOut->Mode->CursorColumn; + SecRow = gST->ConOut->Mode->CursorRow; + SecsLeft = BootPromptPtr->Timeout; + + gST->ConOut->SetCursorPosition (gST->ConOut, SecColumn, SecRow); + AsciiPrint ("(%d) ", SecsLeft); + + // + // set the default action to be AUTO_SELECT + // + Status = AUTO_SELECT; + + while (EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) { + EFI_INPUT_KEY Key; + + if (!EFI_ERROR (gBS->CheckEvent (SecondsEvent))) { + --SecsLeft; + gST->ConOut->SetCursorPosition (gST->ConOut, SecColumn, SecRow); + AsciiPrint ("(%d) ", SecsLeft); + } + + if (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key) == EFI_NOT_READY) { + UINT8 Buffer[512]; + UINTN BufferSize; + EFI_STATUS Status; + + BufferSize = sizeof Buffer; + + Status = Private->EfiBc.UdpRead ( + &Private->EfiBc, + EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | + EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT | + EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT, + NULL, /* dest ip */ + NULL, /* dest port */ + NULL, /* src ip */ + NULL, /* src port */ + NULL, /* hdr size */ + NULL, /* hdr ptr */ + &BufferSize, + Buffer + ); + + continue; + } + + if (Key.ScanCode == 0) { + switch (Key.UnicodeChar) { + case Ctl ('c'): + Status = LOCAL_BOOT; + break; + + case Ctl ('m'): + case 'm': + case 'M': + Status = DO_MENU; + break; + + default: + continue; + } + } else { + switch (Key.ScanCode) { + case SCAN_F8: + Status = DO_MENU; + break; + + case SCAN_ESC: + Status = LOCAL_BOOT; + break; + + default: + continue; + } + } + + break; + } + + gBS->CloseEvent (SecondsEvent); + gBS->CloseEvent (TimeoutEvent); + + gST->ConOut->SetCursorPosition (gST->ConOut, SecColumn, SecRow); + AsciiPrint (" "); + + return Status; +} + +STATIC +VOID +PrintMenuItem ( + PXE_BOOT_MENU_ENTRY *MenuItemPtr + ) +/*++ + +Routine Description: + + Display one menu item. + +Arguments: + + MenuItemPtr - Pointer to PXE menu item option. + +Returns: + + None + +--*/ +{ + UINT8 Length; + UINT8 SaveChar; + + Length = (UINT8) EFI_MIN (70, MenuItemPtr->DataLen); + SaveChar = MenuItemPtr->Data[Length]; + + MenuItemPtr->Data[Length] = 0; + AsciiPrint (" %a\n", MenuItemPtr->Data); + MenuItemPtr->Data[Length] = SaveChar; +} + +STATIC +EFI_STATUS +DoMenu ( + PXE_BASECODE_DEVICE *Private, + DHCP_RECEIVE_BUFFER *RxBufferPtr + ) +/*++ + +Routine Description: + + Display and process menu. + +Arguments: + + Private - Pointer to PxeBc interface + RxBufferPtr - Pointer to receive buffer + +Returns: + + NO_MENU - + LOCAL_BOOT - + +--*/ +{ + PXE_OP_DISCOVERY_CONTROL *DiscoveryControlPtr; + PXE_BOOT_MENU_ENTRY *MenuItemPtrs[MAX_MENULIST]; + EFI_STATUS Status; + UNION_PTR Ptr; + UINTN SaveNumRte; + UINTN TopRow; + UINTN MenuLth; + UINTN NumMenuItems; + UINTN Index; + UINTN Longest; + UINTN Selected; + UINT16 Type; + UINT16 Layer; + BOOLEAN Done; + + Selected = 0; + Layer = 0; + + DEBUG ((EFI_D_WARN, "\nDoMenu() Enter.")); + + /* see if we have a menu/prompt */ + if (!(RxBufferPtr->OpAdds.Status & DISCOVER_TYPE)) { + DEBUG ( + (EFI_D_WARN, + "\nDoMenu() No menu/prompt info. OpAdds.Status == %xh ", + RxBufferPtr->OpAdds.Status) + ); + + return NO_MENU; + } + + DiscoveryControlPtr = (PXE_OP_DISCOVERY_CONTROL *) RxBufferPtr->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_CONTROL_IX - 1]; + + // + // if not USE_BOOTFILE or no bootfile given, must have menu stuff + // + if ((DiscoveryControlPtr->ControlBits & USE_BOOTFILE) && RxBufferPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]) { + DEBUG ((EFI_D_WARN, "\nDoMenu() DHCP w/ bootfile. ")); + return NO_MENU; + } + // + // do prompt & menu if necessary + // + Status = DoPrompt (Private, (PXE_OP_BOOT_PROMPT *) RxBufferPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_PROMPT_IX - 1]); + + if (Status == LOCAL_BOOT) { + DEBUG ((EFI_D_WARN, "\nDoMenu() DoPrompt() returned LOCAL_BOOT. ")); + + return Status; + } + + Ptr.BytePtr = (UINT8 *) RxBufferPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_MENU_IX - 1]; + + MenuLth = Ptr.MenuPtr->Header.Length; + Ptr.CurrentMenuItemPtr = Ptr.MenuPtr->MenuItem; + + // + // build menu items array + // + for (Longest = NumMenuItems = Index = 0; Index < MenuLth && NumMenuItems <= MAX_MENULIST;) { + UINTN lth; + + lth = Ptr.CurrentMenuItemPtr->DataLen + sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data); + + MenuItemPtrs[NumMenuItems++] = Ptr.CurrentMenuItemPtr; + + if (lth > Longest) { + // + // check if too long + // + if ((Longest = lth) > 70 + (sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data))) { + Longest = 70 + (sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data)); + } + } + + Index += lth; + Ptr.BytePtr += lth; + } + + if (Status != AUTO_SELECT) { + UINT8 BlankBuf[75]; + + SetMem (BlankBuf, sizeof BlankBuf, ' '); + BlankBuf[Longest + 5 - (sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data))] = 0; + AsciiPrint ("\n"); + + // + // now put up menu + // + for (Index = 0; Index < NumMenuItems; ++Index) { + PrintMenuItem (MenuItemPtrs[Index]); + } + + TopRow = gST->ConOut->Mode->CursorRow - NumMenuItems; + + // + // now wait for a selection + // + Done = FALSE; + do { + // + // highlight selection + // + EFI_INPUT_KEY Key; + UINTN NewSelected; + + NewSelected = Selected; + + // + // highlight selected row + // + gST->ConOut->SetAttribute ( + gST->ConOut, + EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY) + ); + gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + Selected); + + AsciiPrint (" --->%a\r", BlankBuf); + + PrintMenuItem (MenuItemPtrs[Selected]); + gST->ConOut->SetAttribute ( + gST->ConOut, + EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK) + ); + gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + NumMenuItems); + + // + // wait for a keystroke + // + while (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key) == EFI_NOT_READY) { + UINT8 TmpBuf[512]; + UINTN TmpBufLen; + + TmpBufLen = sizeof TmpBuf; + + Private->EfiBc.UdpRead ( + &Private->EfiBc, + EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | + EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT | + EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT, + NULL, /* dest ip */ + NULL, /* dest port */ + NULL, /* src ip */ + NULL, /* src port */ + NULL, /* hdr size */ + NULL, /* hdr ptr */ + &TmpBufLen, + TmpBuf + ); + } + + if (!Key.ScanCode) { + switch (Key.UnicodeChar) { + case Ctl ('c'): + Key.ScanCode = SCAN_ESC; + break; + + case Ctl ('j'): /* linefeed */ + case Ctl ('m'): /* return */ + Done = TRUE; + break; + + case Ctl ('i'): /* tab */ + case ' ': + case 'd': + case 'D': + Key.ScanCode = SCAN_DOWN; + break; + + case Ctl ('h'): /* backspace */ + case 'u': + case 'U': + Key.ScanCode = SCAN_UP; + break; + + default: + Key.ScanCode = 0; + } + } + + switch (Key.ScanCode) { + case SCAN_LEFT: + case SCAN_UP: + if (NewSelected) { + --NewSelected; + } + + break; + + case SCAN_DOWN: + case SCAN_RIGHT: + if (++NewSelected == NumMenuItems) { + --NewSelected; + } + + break; + + case SCAN_PAGE_UP: + case SCAN_HOME: + NewSelected = 0; + break; + + case SCAN_PAGE_DOWN: + case SCAN_END: + NewSelected = NumMenuItems - 1; + break; + + case SCAN_ESC: + return LOCAL_BOOT; + } + + /* unhighlight last selected row */ + gST->ConOut->SetCursorPosition (gST->ConOut, 5, TopRow + Selected); + + AsciiPrint ("%a\r", BlankBuf); + + PrintMenuItem (MenuItemPtrs[Selected]); + + Selected = NewSelected; + } while (!Done); + } + + SaveNumRte = Private->EfiBc.Mode->RouteTableEntries; + + Type = NTOHS (MenuItemPtrs[Selected]->Type); + + if (Type == 0) { + DEBUG ((EFI_D_WARN, "\nDoMenu() Local boot selected. ")); + return LOCAL_BOOT; + } + + AsciiPrint ("Discover"); + + Status = Private->EfiBc.Discover ( + &Private->EfiBc, + Type, + &Layer, + (BOOLEAN) (Private->EfiBc.Mode->BisSupported && Private->EfiBc.Mode->BisDetected), + 0 + ); + + if (EFI_ERROR (Status)) { + AsciiPrint ("\r \r"); + + DEBUG ( + (EFI_D_WARN, + "\nDoMenu() Return w/ %xh (%r).", + Status, + Status) + ); + + return Status; + } + + AsciiPrint ("\rBOOT_SERVER_IP: "); + PrintIpv4 ((UINT8 *) &Private->ServerIp); + + for (Index = SaveNumRte; Index < Private->EfiBc.Mode->RouteTableEntries; ++Index) { + if ((Index % 3) == 0) { + AsciiPrint ("\r\nGATEWAY IP:"); + } + + AsciiPrint (" "); + PrintIpv4 ((UINT8 *) &Private->EfiBc.Mode->RouteTable[Index].GwAddr); + AsciiPrint (" "); + } + + AsciiPrint ("\n"); + + DEBUG ((EFI_D_WARN, "\nDoMenu() Return w/ EFI_SUCCESS. ")); + + return EFI_SUCCESS; +} + +STATIC +UINT16 +GetValue ( + DHCPV4_OP_STRUCT *OpPtr + ) +/*++ + +Routine Description: + + Get value 8- or 16-bit value from DHCP option. + +Arguments: + + OpPtr - Pointer to DHCP option + +Returns: + + Value from DHCP option + +--*/ +{ + if (OpPtr->Header.Length == 1) { + return OpPtr->Data[0]; + } else { + return NTOHS (OpPtr->Data); + } +} + +STATIC +UINT8 * +_PxeBcFindOpt ( + UINT8 *BufferPtr, + UINTN BufferLen, + UINT8 OpCode + ) +/*++ + +Routine Description: + + Locate opcode in buffer. + +Arguments: + + BufferPtr - Pointer to buffer + BufferLen - Length of buffer + OpCode - Option number + +Returns: + + Pointer to opcode, may be NULL + +--*/ +{ + if (BufferPtr == NULL) { + return NULL; + } + + while (BufferLen != 0) { + if (*BufferPtr == OpCode) { + return BufferPtr; + } + + switch (*BufferPtr) { + case OP_END: + return NULL; + + case OP_PAD: + ++BufferPtr; + --BufferLen; + continue; + } + + if ((UINTN) BufferLen <= (UINTN) 2 + BufferPtr[1]) { + return NULL; + } + + BufferLen -= 2 + BufferPtr[1]; + BufferPtr += 2 + BufferPtr[1]; + } + + return NULL; +} + +UINT8 * +PxeBcFindDhcpOpt ( + EFI_PXE_BASE_CODE_PACKET *PacketPtr, + UINT8 OpCode + ) +/*++ + +Routine Description: + + Find option in packet + +Arguments: + + PacketPtr - Pointer to packet + OpCode - option number + +Returns: + + Pointer to option in packet + +--*/ +{ + UINTN PacketLen; + UINT8 Overload; + UINT8 *OptionBufferPtr; + + // + // + // + PacketLen = 380; + Overload = 0; + + // + // Figure size of DHCP option space. + // + OptionBufferPtr = _PxeBcFindOpt ( + PacketPtr->Dhcpv4.DhcpOptions, + 380, + OP_DHCP_MAX_MESSAGE_SZ + ); + + if (OptionBufferPtr != NULL) { + if (OptionBufferPtr[1] == 2) { + UINT16 n; + + CopyMem (&n, &OptionBufferPtr[2], 2); + PacketLen = HTONS (n); + + if (PacketLen < sizeof (EFI_PXE_BASE_CODE_DHCPV4_PACKET)) { + PacketLen = 380; + } else { + PacketLen -= (PacketPtr->Dhcpv4.DhcpOptions - &PacketPtr->Dhcpv4.BootpOpcode) + 28; + } + } + } + // + // Look for option overloading. + // + OptionBufferPtr = _PxeBcFindOpt ( + PacketPtr->Dhcpv4.DhcpOptions, + PacketLen, + OP_DHCP_OPTION_OVERLOAD + ); + + if (OptionBufferPtr != NULL) { + if (OptionBufferPtr[1] == 1) { + Overload = OptionBufferPtr[2]; + } + } + // + // Look for caller's option. + // + OptionBufferPtr = _PxeBcFindOpt ( + PacketPtr->Dhcpv4.DhcpOptions, + PacketLen, + OpCode + ); + + if (OptionBufferPtr != NULL) { + return OptionBufferPtr; + } + + if (Overload & OVLD_FILE) { + OptionBufferPtr = _PxeBcFindOpt (PacketPtr->Dhcpv4.BootpBootFile, 128, OpCode); + + if (OptionBufferPtr != NULL) { + return OptionBufferPtr; + } + } + + if (Overload & OVLD_SRVR_NAME) { + OptionBufferPtr = _PxeBcFindOpt (PacketPtr->Dhcpv4.BootpSrvName, 64, OpCode); + + if (OptionBufferPtr != NULL) { + return OptionBufferPtr; + } + } + + return NULL; +} + +STATIC +EFI_STATUS +DownloadFile ( + IN PXE_BASECODE_DEVICE *Private, + IN OUT UINT64 *BufferSize, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Download file into buffer + +Arguments: + + Private - Pointer to PxeBc interface + BufferSize - pointer to size of download buffer + Buffer - Pointer to buffer + +Returns: + + EFI_BUFFER_TOO_SMALL - + EFI_NOT_FOUND - + EFI_PROTOCOL_ERROR - + +--*/ +{ + EFI_PXE_BASE_CODE_MTFTP_INFO MtftpInfo; + EFI_PXE_BASE_CODE_TFTP_OPCODE OpCode; + DHCP_RECEIVE_BUFFER *RxBuf; + EFI_STATUS Status; + UINTN BlockSize; + + RxBuf = (DHCP_RECEIVE_BUFFER *) Private->BootServerReceiveBuffer; + BlockSize = 0x8000; + + DEBUG ((EFI_D_WARN, "\nDownloadFile() Enter.")); + + if (Buffer == NULL || *BufferSize == 0 || *BufferSize < Private->FileSize) { + if (Private->FileSize != 0) { + *BufferSize = Private->FileSize; + return EFI_BUFFER_TOO_SMALL; + } + + AsciiPrint ("\nTSize"); + + OpCode = EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE; + } else if (RxBuf->OpAdds.Status & WfM11a_TYPE) { + OpCode = EFI_PXE_BASE_CODE_MTFTP_READ_FILE; + + ZeroMem (&MtftpInfo, sizeof MtftpInfo); + + *(IPV4_ADDR *) &MtftpInfo.MCastIp = *(IPV4_ADDR *) RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_IP - 1]->Data; + + CopyMem ( + &MtftpInfo.CPort, + RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_CPORT - 1]->Data, + sizeof MtftpInfo.CPort + ); + + CopyMem ( + &MtftpInfo.SPort, + RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_SPORT - 1]->Data, + sizeof MtftpInfo.SPort + ); + + MtftpInfo.ListenTimeout = GetValue (RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_TMOUT - 1]); + + MtftpInfo.TransmitTimeout = GetValue (RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_DELAY - 1]); + + AsciiPrint ("\nMTFTP"); + } else { + AsciiPrint ("\nTFTP"); + + OpCode = EFI_PXE_BASE_CODE_TFTP_READ_FILE; + } + + Private->FileSize = 0; + + RxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Data[RxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Header.Length] = 0; + + Status = Private->EfiBc.Mtftp ( + &Private->EfiBc, + OpCode, + Buffer, + FALSE, + BufferSize, + &BlockSize, + &Private->ServerIp, + (UINT8 *) RxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Data, + &MtftpInfo, + FALSE + ); + + if (Status != EFI_SUCCESS && Status != EFI_BUFFER_TOO_SMALL) { + DEBUG ((EFI_D_WARN, "\nDownloadFile() Exit #1 %Xh", Status)); + return Status; + } + + if (sizeof (UINTN) < sizeof (UINT64) && *BufferSize > 0xFFFFFFFF) { + Private->FileSize = 0xFFFFFFFF; + } else { + Private->FileSize = (UINTN) *BufferSize; + } + + if (OpCode == EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE) { + DEBUG ((EFI_D_WARN, "\nDownloadFile() Exit #2")); + return EFI_BUFFER_TOO_SMALL; + } + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_WARN, "\nDownloadFile() Exit #3 %Xh", Status)); + return Status; + } + + if (Private->EfiBc.Mode->BisSupported && Private->EfiBc.Mode->BisDetected && Private->EfiBc.Mode->PxeBisReplyReceived) { + UINT64 CredentialLen; + UINTN BlockSize; + UINT8 CredentialFilename[256]; + UINT8 *op; + VOID *CredentialBuffer; + + // + // Get name of credential file. It may be in the BOOTP + // bootfile field or a DHCP option. + // + ZeroMem (CredentialFilename, sizeof CredentialFilename); + + op = PxeBcFindDhcpOpt (&Private->EfiBc.Mode->PxeBisReply, OP_DHCP_BOOTFILE); + + if (op != NULL) { + if (op[1] == 0) { + /* No credential filename */ + return EFI_NOT_FOUND; + } + + CopyMem (CredentialFilename, &op[2], op[1]); + } else { + if (Private->EfiBc.Mode->PxeBisReply.Dhcpv4.BootpBootFile[0] == 0) { + /* No credential filename */ + return EFI_NOT_FOUND; + } + + CopyMem (CredentialFilename, &op[2], 128); + } + // + // Get size of credential file. It may be available as a + // DHCP option. If not, use the TFTP get file size. + // + CredentialLen = 0; + + op = PxeBcFindDhcpOpt (&Private->EfiBc.Mode->PxeBisReply, OP_BOOT_FILE_SZ); + + if (op != NULL) { + /* + * This is actually the size of the credential file + * buffer. The actual credential file size will be + * returned when we download the file. + */ + if (op[1] == 2) { + UINT16 n; + + CopyMem (&n, &op[2], 2); + CredentialLen = HTONS (n) * 512; + } + } + + if (CredentialLen == 0) { + BlockSize = 8192; + + Status = Private->EfiBc.Mtftp ( + &Private->EfiBc, + EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, + NULL, + FALSE, + &CredentialLen, + &BlockSize, + &Private->ServerIp, + CredentialFilename, + NULL, + FALSE + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + if (CredentialLen == 0) { + // + // %%TBD -- EFI error for invalid credential + // file. + // + return EFI_PROTOCOL_ERROR; + } + } + // + // Allocate credential file buffer. + // + Status = gBS->AllocatePool ( + EfiBootServicesData, + (UINTN) CredentialLen, + &CredentialBuffer + ); + + if (EFI_ERROR (Status)) { + return Status; + } + // + // Download credential file. + // + BlockSize = 8192; + + Status = Private->EfiBc.Mtftp ( + &Private->EfiBc, + EFI_PXE_BASE_CODE_TFTP_READ_FILE, + CredentialBuffer, + FALSE, + &CredentialLen, + &BlockSize, + &Private->ServerIp, + CredentialFilename, + NULL, + FALSE + ); + + if (EFI_ERROR (Status)) { + gBS->FreePool (CredentialBuffer); + return Status; + } + // + // Verify credentials. + // + if (PxebcBisVerify (Private, Buffer, Private->FileSize, CredentialBuffer, (UINTN) CredentialLen)) { + Status = EFI_SUCCESS; + } else { + // + // %%TBD -- An EFI error code for failing credential verification. + // + Status = EFI_PROTOCOL_ERROR; + } + + gBS->FreePool (CredentialBuffer); + } + + return Status; +} + +STATIC +EFI_STATUS +LoadfileStart ( + IN PXE_BASECODE_DEVICE *Private, + IN OUT UINT64 *BufferSize, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Start PXE DHCP. Get DHCP and proxyDHCP information. + Display remote boot menu and prompt. Select item from menu. + +Arguments: + + Private - Pointer to PxeBc interface + BufferSize - Pointer to download buffer size + Buffer - Pointer to download buffer + +Returns: + + EFI_SUCCESS - + EFI_NOT_READY - + +--*/ +{ + EFI_PXE_BASE_CODE_MODE *PxeBcMode; + EFI_SIMPLE_NETWORK_PROTOCOL *Snp; + EFI_SIMPLE_NETWORK_MODE *SnpMode; + EFI_STATUS Status; + VOID *RxBuf; + + DEBUG ((EFI_D_WARN, "\nLoadfileStart() Enter.")); + + // + // Try to start BaseCode, for now only IPv4 is supported + // so don't try to start using IPv6. + // + Status = Private->EfiBc.Start (&Private->EfiBc, FALSE); + + if (EFI_ERROR (Status)) { + if (Status != EFI_ALREADY_STARTED) { + DEBUG ((EFI_D_NET, "\nLoadfileStart() Exit BC.Start() == %xh", Status)); + return Status; + } + } + // + // Get pointers to PXE mode structure, SNP protocol structure + // and SNP mode structure. + // + PxeBcMode = Private->EfiBc.Mode; + Snp = Private->SimpleNetwork; + SnpMode = Snp->Mode; + + // + // Display client MAC address, like 16-bit PXE ROMs + // + AsciiPrint ("\nCLIENT MAC ADDR: "); + + { + UINTN Index; + UINTN hlen; + + hlen = SnpMode->HwAddressSize; + + for (Index = 0; Index < hlen; ++Index) { + AsciiPrint ("%02x ", SnpMode->CurrentAddress.Addr[Index]); + } + } + + AsciiPrint ("\nDHCP"); + + Status = Private->EfiBc.Dhcp (&Private->EfiBc, TRUE); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_WARN, "\nLoadfileStart() Exit BC.Dhcp() == %Xh", Status)); + AsciiPrint ("\r \r"); + return Status; + } + + ShowMyInfo (Private); + + RxBuf = PxeBcMode->ProxyOfferReceived ? &PXE_OFFER_BUFFER : &DHCPV4_ACK_BUFFER; +#define RxBufferPtr ((DHCP_RECEIVE_BUFFER *) RxBuf) + + Status = DoMenu (Private, RxBufferPtr); + + if (Status == EFI_SUCCESS) { + // + // did a discovery - take info from discovery packet + // + RxBuf = &PXE_ACK_BUFFER; + } else if (Status == NO_MENU) { + // + // did not do a discovery - take info from rxbuf + // + Private->ServerIp.Addr[0] = RxBufferPtr->u.Dhcpv4.siaddr; + + if (!(Private->ServerIp.Addr[0])) { + *(IPV4_ADDR *) &Private->ServerIp = *(IPV4_ADDR *) RxBufferPtr->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1]->Data; + } + } else { + DEBUG ((EFI_D_WARN, "\nLoadfileStart() Exit DoMenu() == %Xh", Status)); + return Status; + } + + if (!RxBufferPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]) { + DEBUG ((EFI_D_WARN, "\nLoadfileStart() Exit Not ready?")); + return EFI_NOT_READY; + } + // + // check for file size option sent + // + if (RxBufferPtr->OpAdds.PktOptAdds[OP_BOOT_FILE_SZ_IX - 1]) { + Private->FileSize = 512 * NTOHS (RxBufferPtr->OpAdds.PktOptAdds[OP_BOOT_FILE_SZ_IX - 1]->Data); + } + + Private->BootServerReceiveBuffer = RxBufferPtr; + + Status = DownloadFile (Private, BufferSize, Buffer); + + DEBUG ( + (EFI_D_WARN, + "\nLoadfileStart() Exit. DownloadFile() = %Xh", + Status) + ); + + return Status; +} + +EFI_STATUS +EFIAPI +LoadFile ( + IN EFI_LOAD_FILE_PROTOCOL *This, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + IN BOOLEAN BootPolicy, + IN OUT UINTN *BufferSize, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Loadfile interface for PxeBc interface + +Arguments: + + This - Pointer to Loadfile interface + FilePath - Not used and not checked + BootPolicy - Must be TRUE + BufferSize - Pointer to buffer size + Buffer - Pointer to download buffer or NULL + +Returns: + + EFI_INVALID_PARAMETER - + EFI_UNSUPPORTED - + EFI_SUCCESS - + EFI_BUFFER_TOO_SMALL - + +--*/ +{ + LOADFILE_DEVICE *LoadfilePtr; + UINT64 TmpBufSz; + INT32 OrigMode; + INT32 OrigAttribute; + BOOLEAN RemoveCallback; + BOOLEAN NewMakeCallback; + EFI_STATUS Status; + EFI_STATUS TempStatus; + // + // + // + OrigMode = gST->ConOut->Mode->Mode; + OrigAttribute = gST->ConOut->Mode->Attribute; + RemoveCallback = FALSE; + + AsciiPrint ("Running LoadFile()\n"); + + // + // Resolve Warning 4 unreferenced parameter problem + // + FilePath = NULL; + + // + // If either if these parameters are NULL, we cannot continue. + // + if (This == NULL || BufferSize == NULL) { + DEBUG ((EFI_D_WARN, "\nLoadFile() This or BufferSize == NULL")); + return EFI_INVALID_PARAMETER; + } + // + // We only support BootPolicy == TRUE + // + if (!BootPolicy) { + DEBUG ((EFI_D_WARN, "\nLoadFile() BootPolicy == FALSE")); + return EFI_UNSUPPORTED; + } + // + // Get pointer to LoadFile protocol structure. + // + LoadfilePtr = CR (This, LOADFILE_DEVICE, LoadFile, LOADFILE_DEVICE_SIGNATURE); + + if (LoadfilePtr == NULL) { + DEBUG ( + (EFI_D_NET, + "\nLoadFile() Could not get pointer to LoadFile structure") + ); + return EFI_INVALID_PARAMETER; + } + // + // Lock interface + // + EfiAcquireLock (&LoadfilePtr->Lock); + + // + // Set console output mode and display attribute + // + if (OrigMode != 0) { + gST->ConOut->SetMode (gST->ConOut, 0); + } + + gST->ConOut->SetAttribute ( + gST->ConOut, + EFI_TEXT_ATTR (EFI_LIGHTGRAY,EFI_BLACK) + ); + + // + // See if BaseCode already has a Callback protocol attached. + // If there is none, attach our own Callback protocol. + // + Status = gBS->HandleProtocol ( + LoadfilePtr->Private->Handle, + &gEfiPxeBaseCodeCallbackProtocolGuid, + (VOID *) &LoadfilePtr->Private->CallbackProtocolPtr + ); + + switch (Status) { + case EFI_SUCCESS: + // + // There is already a callback routine. Do nothing. + // + DEBUG ((EFI_D_WARN, "\nLoadFile() BC callback exists.")); + break; + + case EFI_UNSUPPORTED: + // + // No BaseCode Callback protocol found. Add our own. + // + Status = gBS->InstallProtocolInterface ( + &LoadfilePtr->Private->Handle, + &gEfiPxeBaseCodeCallbackProtocolGuid, + EFI_NATIVE_INTERFACE, + &_bc_callback + ); + + DEBUG ((EFI_D_WARN, "\nLoadFile() Callback install status == %xh", Status)); + + RemoveCallback = (BOOLEAN) (Status == EFI_SUCCESS); + + if (LoadfilePtr->Private->EfiBc.Mode != NULL && LoadfilePtr->Private->EfiBc.Mode->Started) { + NewMakeCallback = TRUE; + LoadfilePtr->Private->EfiBc.SetParameters ( + &LoadfilePtr->Private->EfiBc, + NULL, + NULL, + NULL, + NULL, + &NewMakeCallback + ); + } + + break; + + default: + DEBUG ((EFI_D_WARN, "\nLoadFile() Callback check status == %xh", Status)); + } + // + // Check for starting or for continuing after already getting + // the file size. + // + if (LoadfilePtr->Private->FileSize == 0) { + TmpBufSz = 0; + Status = LoadfileStart (LoadfilePtr->Private, &TmpBufSz, Buffer); + + if (sizeof (UINTN) < sizeof (UINT64) && TmpBufSz > 0xFFFFFFFF) { + *BufferSize = 0xFFFFFFFF; + } else { + *BufferSize = (UINTN) TmpBufSz; + } + + if (Status == EFI_BUFFER_TOO_SMALL) { + // + // This is done so loadfile will work even if the boot manager + // did not make the first call with Buffer == NULL. + // + Buffer = NULL; + } + } else if (Buffer == NULL) { + DEBUG ((EFI_D_WARN, "\nLoadfile() Get buffer size")); + + // + // Continuing from previous LoadFile request. Make sure there + // is a buffer and that it is big enough. + // + *BufferSize = LoadfilePtr->Private->FileSize; + Status = EFI_BUFFER_TOO_SMALL; + } else { + DEBUG ((EFI_D_WARN, "\nLoadFile() Download file")); + + // + // Everything looks good, try to download the file. + // + TmpBufSz = *BufferSize; + Status = DownloadFile (LoadfilePtr->Private, &TmpBufSz, Buffer); + + // + // Next call to loadfile will start DHCP process again. + // + LoadfilePtr->Private->FileSize = 0; + } + // + // If we added a callback protocol, now is the time to remove it. + // + if (RemoveCallback) { + NewMakeCallback = FALSE; + TempStatus = LoadfilePtr->Private->EfiBc.SetParameters ( + &LoadfilePtr->Private->EfiBc, + NULL, + NULL, + NULL, + NULL, + &NewMakeCallback + ); + + if (TempStatus == EFI_SUCCESS) { + gBS->UninstallProtocolInterface ( + LoadfilePtr->Private->Handle, + &gEfiPxeBaseCodeCallbackProtocolGuid, + &_bc_callback + ); + } + } + // + // Restore display mode and attribute + // + if (OrigMode != 0) { + gST->ConOut->SetMode (gST->ConOut, OrigMode); + } + + gST->ConOut->SetAttribute (gST->ConOut, OrigAttribute); + + // + // Unlock interface + // + EfiReleaseLock (&LoadfilePtr->Lock); + + DEBUG ((EFI_D_WARN, "\nBC.Loadfile() Status == %xh\n", Status)); + + switch (Status) { + case EFI_SUCCESS: /* 0 */ + return EFI_SUCCESS; + + case EFI_BUFFER_TOO_SMALL: /* 5 */ + // + // Error is only displayed when we are actually trying to + // download the boot image. + // + if (Buffer == NULL) { + return EFI_BUFFER_TOO_SMALL; + } + + AsciiPrint ("\nPXE-E05: Download buffer is smaller than requested file.\n"); + break; + + case EFI_DEVICE_ERROR: /* 7 */ + AsciiPrint ("\nPXE-E07: Network device error. Check network connection.\n"); + break; + + case EFI_OUT_OF_RESOURCES: /* 9 */ + AsciiPrint ("\nPXE-E09: Could not allocate I/O buffers.\n"); + break; + + case EFI_NO_MEDIA: /* 12 */ + AsciiPrint ("\nPXE-E12: Could not detect network connection. Check cable.\n"); + break; + + case EFI_NO_RESPONSE: /* 16 */ + AsciiPrint ("\nPXE-E16: Valid PXE offer not received.\n"); + break; + + case EFI_TIMEOUT: /* 18 */ + AsciiPrint ("\nPXE-E18: Timeout. Server did not respond.\n"); + break; + + case EFI_ABORTED: /* 21 */ + AsciiPrint ("\nPXE-E21: Remote boot cancelled.\n"); + break; + + case EFI_ICMP_ERROR: /* 22 */ + AsciiPrint ("\nPXE-E22: Client received ICMP error from server.\n"); + + if (LoadfilePtr->Private->EfiBc.Mode == NULL) { + break; + } + + if (!LoadfilePtr->Private->EfiBc.Mode->IcmpErrorReceived) { + break; + } + + AsciiPrint ( + "PXE-E98: Type: %xh Code: %xh ", + LoadfilePtr->Private->EfiBc.Mode->IcmpError.Type, + LoadfilePtr->Private->EfiBc.Mode->IcmpError.Code + ); + + switch (LoadfilePtr->Private->EfiBc.Mode->IcmpError.Type) { + case 0x03: + switch (LoadfilePtr->Private->EfiBc.Mode->IcmpError.Code) { + case 0x00: /* net unreachable */ + AsciiPrint ("Net unreachable"); + break; + + case 0x01: /* host unreachable */ + AsciiPrint ("Host unreachable"); + break; + + case 0x02: /* protocol unreachable */ + AsciiPrint ("Protocol unreachable"); + break; + + case 0x03: /* port unreachable */ + AsciiPrint ("Port unreachable"); + break; + + case 0x04: /* Fragmentation needed */ + AsciiPrint ("Fragmentation needed"); + break; + + case 0x05: /* Source route failed */ + AsciiPrint ("Source route failed"); + break; + } + + break; + } + + AsciiPrint ("\n"); + + break; + + case EFI_TFTP_ERROR: /* 23 */ + AsciiPrint ("\nPXE-E23: Client received TFTP error from server.\n"); + + if (LoadfilePtr->Private->EfiBc.Mode == NULL) { + break; + } + + if (LoadfilePtr->Private->EfiBc.Mode->TftpErrorReceived) { + AsciiPrint ( + "PXE-E98: Code: %xh %a\n", + LoadfilePtr->Private->EfiBc.Mode->TftpError.ErrorCode, + LoadfilePtr->Private->EfiBc.Mode->TftpError.ErrorString + ); + } + + break; + + default: + AsciiPrint ("\nPXE-E99: Unexpected network error: %xh\n", Status); + } + + LoadfilePtr->Private->EfiBc.Stop (&LoadfilePtr->Private->EfiBc); + + return Status; +} diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/tftp.h b/EdkModulePkg/Universal/Network/PxeBc/Dxe/tftp.h new file mode 100644 index 0000000000..3cc0724e9c --- /dev/null +++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/tftp.h @@ -0,0 +1,153 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + tftp.h + +Abstract: + +--*/ + +#ifndef __TFTP_H__ +#define __TFTP_H__ + +// +// Definitions for trivial file transfer protocol functionality with IP v4 +// Per RFC 1350, July 1992 and RFC 2347, 8, and 9, May 1998 +// +#pragma pack(1) +// +// max and min packet sizes +// (all data packets in transmission except last) +// +#define MAX_TFTP_PKT_SIZE (BUFFER_ALLOCATE_SIZE - 512) +#define MIN_TFTP_PKT_SIZE 512 + +// +// TFTPv4 OpCodes +// +#define TFTP_RRQ 1 // read request +#define TFTP_WRQ 2 // write request +#define TFTP_DATA 3 // data +#define TFTP_ACK 4 // acknowledgement +#define TFTP_ERROR 5 // error packet +#define TFTP_OACK 6 // option acknowledge +#define TFTP_DIR 7 // read directory request +#define TFTP_DATA8 8 +#define TFTP_ACK8 9 + +// +// request packet (read or write) +// Fields shown (except file name) are not to be referenced directly, +// since their placement is variable within a request packet. +// All are null terminated case insensitive ascii strings. +// +struct Tftpv4Req { + UINT16 OpCode; // TFTP Op code + UINT8 FileName[2]; // file name + UINT8 Mode[2]; // "netascii" or "octet" + struct { // optionally, one or more option requests + UINT8 Option[2]; // option name + UINT8 Value[2]; // value requested + } OpReq[1]; +}; + +// +// modes +// +#define MODE_ASCII "netascii" +#define MODE_BINARY "octet" + +// +// option strings +// +#define OP_BLKSIZE "blksize" // block size option +#define OP_TIMEOUT "timeout" // time to wait before retransmitting +#define OP_TFRSIZE "tsize" // total transfer size option +#define OP_OVERWRITE "overwrite" // overwrite file option +#define OP_BIGBLKNUM "bigblk#" // big block number +// See RFC 2347, 8, and 9 for more information on TFTP options +// option acknowledge packet (optional) +// options not acknowledged are rejected +// +struct Tftpv4Oack { + UINT16 OpCode; // TFTP Op code + struct { // optionally, one or more option acknowledgements + UINT8 Option[2]; // option name (of those requested) + UINT8 Value[2]; // value acknowledged + } OpAck[1]; +}; + +// +// acknowledge packet +// +struct Tftpv4Ack { + UINT16 OpCode; // TFTP Op code + UINT16 BlockNum; +}; + +// +// data packet +// +struct Tftpv4Data { + struct Tftpv4Ack Header; + UINT8 Data[512]; +}; + +// +// big block number ack packet +// +struct Tftpv4Ack8 { + UINT16 OpCode; + UINT64 BlockNum; +}; + +// +// big block number data packet +// +struct Tftpv4Data8 { + struct Tftpv4Ack8 Header; + UINT8 Data[506]; +}; + +// +// error packet +// +struct Tftpv4Error { + UINT16 OpCode; // TFTP Op code + UINT16 ErrCode; // error code + UINT8 ErrMsg[1]; // error message (nul terminated) +}; + +#pragma pack() +// +// error codes +// +#define TFTP_ERR_UNDEF 0 // Not defined, see error message (if any). +#define TFTP_ERR_NOT_FOUND 1 // File not found. +#define TFTP_ERR_ACCESS 2 // Access violation. +#define TFTP_ERR_FULL 3 // Disk full or allocation exceeded. +#define TFTP_ERR_ILLEGAL 4 // Illegal TFTP operation. +#define TFTP_ERR_BAD_ID 5 // Unknown transfer ID. +#define TFTP_ERR_EXISTS 6 // File already exists. +#define TFTP_ERR_NO_USER 7 // No such user. +#define TFTP_ERR_OPTION 8 // Option negotiation termination +// +// some defines +// +#define REQ_RESP_TIMEOUT 5 // Wait five seconds for request response. +#define ACK_TIMEOUT 4 // Wait four seconds for ack response. +#define NUM_ACK_RETRIES 3 +#define NUM_MTFTP_OPEN_RETRIES 3 + +#endif /* __TFTP_H__ */ + +/* EOF - tftp.h */ diff --git a/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/ComponentName.c b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/ComponentName.c new file mode 100644 index 0000000000..b48b5d0b85 --- /dev/null +++ b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/ComponentName.c @@ -0,0 +1,169 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + ComponentName.c + +Abstract: + PxeDhcp4 component name protocol declarations + +--*/ + + +#include "PxeDhcp4.h" + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +PxeDhcp4ComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +EFI_STATUS +EFIAPI +PxeDhcp4ComponentNameGetControllerName ( + 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 +// +EFI_COMPONENT_NAME_PROTOCOL gPxeDhcp4ComponentName = { + PxeDhcp4ComponentNameGetDriverName, + PxeDhcp4ComponentNameGetControllerName, + "eng" +}; + +static EFI_UNICODE_STRING_TABLE mPxeDhcp4DriverNameTable[] = { + { + "eng", + (CHAR16 *) L"PXE DHCPv4 Driver" + }, + { + NULL, + NULL + } +}; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +EFI_STATUS +EFIAPI +PxeDhcp4ComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gPxeDhcp4ComponentName.SupportedLanguages, + mPxeDhcp4DriverNameTable, + DriverName + ); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +EFI_STATUS +EFIAPI +PxeDhcp4ComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + 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. + 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. + + Returns: + 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. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return EFI_UNSUPPORTED; +} + +/* EOF - ComponentName.c */ diff --git a/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/Dhcp4.mbd b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/Dhcp4.mbd new file mode 100644 index 0000000000..090884a8a8 --- /dev/null +++ b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/Dhcp4.mbd @@ -0,0 +1,41 @@ + + + + + Dhcp4 + a46c3330-be36-4977-9d24-a7cf92eef0fe + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + + UefiBootServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + BaseLib + DxeMemoryAllocationLib + + diff --git a/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/Dhcp4.msa b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/Dhcp4.msa new file mode 100644 index 0000000000..96bfc9b931 --- /dev/null +++ b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/Dhcp4.msa @@ -0,0 +1,74 @@ + + + + + Dhcp4 + UEFI_DRIVER + BS_DRIVER + a46c3330-be36-4977-9d24-a7cf92eef0fe + 0 + Component description file for DiskIo module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + UefiLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + + + ComponentName.c + PxeDhcp4.c + PxeDhcp4.h + PxeDhcp4InitSelect.c + PxeDhcp4Release.c + PxeDhcp4RenewRebind.c + PxeDhcp4Run.c + PxeDhcp4Setup.c + support.c + + + MdePkg + EdkModulePkg + + + PxeDhcp4Callback + PxeDhcp4 + SimpleNetwork + PxeBaseCode + + + + + + + + gPxeDhcp4DriverBinding + gPxeDhcp4ComponentName + + + diff --git a/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4.c b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4.c new file mode 100644 index 0000000000..57a44a02b4 --- /dev/null +++ b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4.c @@ -0,0 +1,342 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + PxeDhcp4.c + +Abstract: + +--*/ + + +#include "PxeDhcp4.h" + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +// +// Prototypes +// Driver model protocol interface +// +EFI_STATUS +EFIAPI +PxeDhcp4DriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +EFI_STATUS +EFIAPI +PxeDhcp4DriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +PxeDhcp4DriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +PxeDhcp4DriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +// +// PXE DHCP Protocol Interface +// +EFI_DRIVER_BINDING_PROTOCOL gPxeDhcp4DriverBinding = { + PxeDhcp4DriverBindingSupported, + PxeDhcp4DriverBindingStart, + PxeDhcp4DriverBindingStop, + 0x10, + NULL, + NULL +}; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +EFI_STATUS +EFIAPI +PxeDhcp4DriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL * This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL + ) +/*++ + + Routine Description: + Test to see if this driver supports ControllerHandle. Any + ControllerHandle that contains a PxeBaseCode protocol can be + supported. + + Arguments: + This - Protocol instance pointer. + ControllerHandle - Handle of device to test. + RemainingDevicePath - Not used. + + Returns: + EFI_SUCCESS - This driver supports this device. + EFI_ALREADY_STARTED - This driver is already running on this + device. + other - This driver does not support this device. + +--*/ +{ + EFI_STATUS Status; + EFI_PXE_BASE_CODE_PROTOCOL *PxeBc; + + // + // Open the IO Abstraction(s) needed to perform the supported test. + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiPxeBaseCodeProtocolGuid, + (VOID **) &PxeBc, + 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. + // + return gBS->CloseProtocol ( + ControllerHandle, + &gEfiPxeBaseCodeProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +EFI_STATUS +EFIAPI +PxeDhcp4DriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL * This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL + ) +/*++ + + Routine Description: + Start this driver on ControllerHandle by opening a PxeBaseCode + protocol and installing a PxeDhcp4 protocol on ControllerHandle. + + Arguments: + This - Protocol instance pointer. + ControllerHandle - Handle of device to bind driver to. + RemainingDevicePath - Not used, always produce all possible + children. + + Returns: + EFI_SUCCESS - This driver is added to ControllerHandle. + EFI_ALREADY_STARTED - This driver is already running on + ControllerHandle. + other - This driver does not support this device. + +--*/ +{ + EFI_STATUS Status; + EFI_PXE_BASE_CODE_PROTOCOL *PxeBc; + EFI_SIMPLE_NETWORK_PROTOCOL *Snp; + PXE_DHCP4_PRIVATE_DATA *Private; + + // + // Connect to the PxeBaseCode interface on ControllerHandle. + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiPxeBaseCodeProtocolGuid, + (VOID **) &PxeBc, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (Status)) { + return Status; + } + // + // BaseCode has already grabbed the SimpleNetwork interface + // so just do a HandleProtocol() to get it. + // + Status = gBS->HandleProtocol ( + ControllerHandle, + &gEfiSimpleNetworkProtocolGuid, + (VOID **) &Snp + ); + + if (EFI_ERROR (Status)) { + goto error_exit; + } + + ASSERT (Snp); + + // + // Initialize the PXE DHCP device instance. + // + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (PXE_DHCP4_PRIVATE_DATA), + (VOID **) &Private + ); + + if (EFI_ERROR (Status)) { + goto error_exit; + } + // + // + // + ZeroMem (Private, sizeof (PXE_DHCP4_PRIVATE_DATA)); + + Private->Signature = PXE_DHCP4_PRIVATE_DATA_SIGNATURE; + Private->PxeBc = PxeBc; + Private->Snp = Snp; + Private->Handle = ControllerHandle; + Private->PxeDhcp4.Revision = EFI_PXE_DHCP4_PROTOCOL_REVISION; + Private->PxeDhcp4.Run = PxeDhcp4Run; + Private->PxeDhcp4.Setup = PxeDhcp4Setup; + Private->PxeDhcp4.Init = PxeDhcp4Init; + Private->PxeDhcp4.Select = PxeDhcp4Select; + Private->PxeDhcp4.Renew = PxeDhcp4Renew; + Private->PxeDhcp4.Rebind = PxeDhcp4Rebind; + Private->PxeDhcp4.Release = PxeDhcp4Release; + Private->PxeDhcp4.Data = NULL; + + // + // Install protocol interfaces for the PXE DHCP device. + // + Status = gBS->InstallProtocolInterface ( + &ControllerHandle, + &gEfiPxeDhcp4ProtocolGuid, + EFI_NATIVE_INTERFACE, + &Private->PxeDhcp4 + ); + + if (!EFI_ERROR (Status)) { + return Status; + } + +error_exit: ; + gBS->CloseProtocol ( + ControllerHandle, + &gEfiPxeBaseCodeProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + + return Status; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +EFI_STATUS +EFIAPI +PxeDhcp4DriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + + Routine Description: + Stop this driver on ControllerHandle by removing PXE DHCP + protocol and closing the PXE Base Code protocol on + ControllerHandle. + + Arguments: + This - Protocol instance pointer. + ControllerHandle - Handle of device to stop driver on. + NumberOfChildren - Not used. + ChildHandleBuffer - Not used. + + Returns: + EFI_SUCCESS - This driver is removed ControllerHandle. + other - This driver was not removed from this + device. + +--*/ +{ + EFI_STATUS Status; + EFI_PXE_DHCP4_PROTOCOL *PxeDhcp4; + PXE_DHCP4_PRIVATE_DATA *Private; + + // + // Get our context back. + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiPxeDhcp4ProtocolGuid, + (VOID **) &PxeDhcp4, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Private = PXE_DHCP4_PRIVATE_DATA_FROM_THIS (PxeDhcp4); + + // + // Release allocated resources + // + if (Private->PxeDhcp4.Data) { + gBS->FreePool (Private->PxeDhcp4.Data); + Private->PxeDhcp4.Data = NULL; + } + // + // Uninstall our protocol + // + Status = gBS->UninstallProtocolInterface ( + ControllerHandle, + &gEfiPxeDhcp4ProtocolGuid, + &Private->PxeDhcp4 + ); + + if (EFI_ERROR (Status)) { + return Status; + } + // + // Close any consumed protocols + // + Status = gBS->CloseProtocol ( + ControllerHandle, + &gEfiPxeBaseCodeProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + + if (EFI_ERROR (Status)) { + return Status; + } + // + // Release our private data + // + gBS->FreePool (Private); + + return Status; +} + +/* EOF - PxeDhcp4.c */ diff --git a/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4.h b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4.h new file mode 100644 index 0000000000..136d392504 --- /dev/null +++ b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4.h @@ -0,0 +1,307 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + PxeDhcp4.h + +Abstract: + Common header for PxeDhcp4 protocol driver + +--*/ +#ifndef _PXEDHCP4_H +#define _PXEDHCP4_H + +// +// PxeDhcp4 protocol instance data +// +typedef struct { + // + // Signature field used to locate beginning of containment record. + // + UINTN Signature; + +#define PXE_DHCP4_PRIVATE_DATA_SIGNATURE EFI_SIGNATURE_32 ('p', 'x', 'D', '4') + // + // Device handle the protocol is bound to. + // + EFI_HANDLE Handle; + + // + // Public PxeDhcp4 protocol interface. + // + EFI_PXE_DHCP4_PROTOCOL PxeDhcp4; + + // + // Consumed PxeBc, Snp and PxeDhcp4Callback protocol interfaces. + // + EFI_PXE_BASE_CODE_PROTOCOL *PxeBc; + EFI_SIMPLE_NETWORK_PROTOCOL *Snp; + EFI_PXE_DHCP4_CALLBACK_PROTOCOL *callback; + + // + // PxeDhcp4 called function for PxeDhcp4Callback. + // + EFI_PXE_DHCP4_FUNCTION function; + + // + // Timeout event and flag for PxeDhcp4Callback. + // + EFI_EVENT TimeoutEvent; + BOOLEAN TimeoutOccurred; + + // + // Periodic event and flag for PxeDhcp4Callback. + // + EFI_EVENT PeriodicEvent; + BOOLEAN PeriodicOccurred; + + // + // DHCP server IP address. + // + UINT32 ServerIp; + + // + // DHCP renewal and rebinding times, in seconds. + // + UINT32 RenewTime; + UINT32 RebindTime; + UINT32 LeaseTime; + + // + // Number of offers received & allocated offer list. + // + UINTN offers; + DHCP4_PACKET *offer_list; + + // + // + // + BOOLEAN StopPxeBc; + +} PXE_DHCP4_PRIVATE_DATA; + +#define PXE_DHCP4_PRIVATE_DATA_FROM_THIS(a) CR (a, PXE_DHCP4_PRIVATE_DATA, PxeDhcp4, PXE_DHCP4_PRIVATE_DATA_SIGNATURE) + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +// +// Protocol function prototypes. +// +extern +EFI_STATUS +EFIAPI +PxeDhcp4Run ( + IN EFI_PXE_DHCP4_PROTOCOL *This, + IN OPTIONAL UINTN OpLen, + IN OPTIONAL VOID *OpList + ) +; + +extern +EFI_STATUS +EFIAPI +PxeDhcp4Setup ( + IN EFI_PXE_DHCP4_PROTOCOL *This, + IN EFI_PXE_DHCP4_DATA *Data + ) +; + +extern +EFI_STATUS +EFIAPI +PxeDhcp4Init ( + IN EFI_PXE_DHCP4_PROTOCOL *This, + IN UINTN seconds_timeout, + OUT UINTN *offer_list_entries, + OUT DHCP4_PACKET **offer_list + ) +; + +extern +EFI_STATUS +EFIAPI +PxeDhcp4Select ( + IN EFI_PXE_DHCP4_PROTOCOL *This, + IN UINTN seconds_timeout, + IN DHCP4_PACKET *offer_list + ) +; + +extern +EFI_STATUS +EFIAPI +PxeDhcp4Renew ( + IN EFI_PXE_DHCP4_PROTOCOL *This, + UINTN seconds_timeout + ) +; + +extern +EFI_STATUS +EFIAPI +PxeDhcp4Rebind ( + IN EFI_PXE_DHCP4_PROTOCOL *This, + UINTN seconds_timeout + ) +; + +extern +EFI_STATUS +EFIAPI +PxeDhcp4Release ( + IN EFI_PXE_DHCP4_PROTOCOL *This + ) +; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +// +// Support function prototypes. +// +extern +UINT16 +htons ( + UINTN n + ) +; + +extern +UINT32 +htonl ( + UINTN n + ) +; + +extern +VOID +EFIAPI +timeout_notify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +; + +extern +VOID +EFIAPI +periodic_notify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +; + +extern +EFI_STATUS +find_opt ( + IN DHCP4_PACKET *Packet, + IN UINT8 OpCode, + IN UINTN Skip, + OUT DHCP4_OP **OpPtr + ) +; + +extern +EFI_STATUS +add_opt ( + IN DHCP4_PACKET *Packet, + IN DHCP4_OP *OpPtr + ) +; + +extern +EFI_STATUS +start_udp ( + IN PXE_DHCP4_PRIVATE_DATA *Private, + IN OPTIONAL EFI_IP_ADDRESS *station_ip, + IN OPTIONAL EFI_IP_ADDRESS *subnet_mask + ) +; + +extern +VOID +stop_udp ( + IN PXE_DHCP4_PRIVATE_DATA *Private + ) +; + +extern +EFI_STATUS +start_receive_events ( + IN PXE_DHCP4_PRIVATE_DATA *Private, + IN UINTN seconds_timeout + ) +; + +extern +VOID +stop_receive_events ( + IN PXE_DHCP4_PRIVATE_DATA *Private + ) +; + +extern +EFI_STATUS +tx_udp ( + IN PXE_DHCP4_PRIVATE_DATA *Private, + IN EFI_IP_ADDRESS *dest_ip, + IN OPTIONAL EFI_IP_ADDRESS *gateway_ip, + IN EFI_IP_ADDRESS *src_ip, + IN VOID *buffer, + IN UINTN BufferSize + ) +; + +extern +EFI_STATUS +rx_udp ( + IN PXE_DHCP4_PRIVATE_DATA *Private, + OUT VOID *buffer, + OUT UINTN *BufferSize, + IN OUT EFI_IP_ADDRESS *dest_ip, + IN OUT EFI_IP_ADDRESS *src_ip, + IN UINT16 op_flags + ) +; + +extern +EFI_STATUS +tx_rx_udp ( + IN PXE_DHCP4_PRIVATE_DATA *Private, + IN OUT EFI_IP_ADDRESS *ServerIp, + IN OPTIONAL EFI_IP_ADDRESS *gateway_ip, + IN OPTIONAL EFI_IP_ADDRESS *client_ip, + IN OPTIONAL EFI_IP_ADDRESS *subnet_mask, + IN DHCP4_PACKET *tx_pkt, + OUT DHCP4_PACKET *rx_pkt, + IN INTN + ( + *rx_vfy) + ( + IN PXE_DHCP4_PRIVATE_DATA *Private, + IN DHCP4_PACKET *tx_pkt, + IN DHCP4_PACKET *rx_pkt, + IN UINTN rx_pkt_size + ), + IN UINTN seconds_timeout + ) +; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +// +// Global variable definitions. +// +extern EFI_DRIVER_BINDING_PROTOCOL gPxeDhcp4DriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gPxeDhcp4ComponentName; + +#endif /* _PXEDHCP4_H */ + +/* EOF - PxeDhcp4.h */ diff --git a/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4InitSelect.c b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4InitSelect.c new file mode 100644 index 0000000000..8b7cd28810 --- /dev/null +++ b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4InitSelect.c @@ -0,0 +1,786 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + PxeDhcp4InitSelect.c + +Abstract: + +--*/ + + +#include "PxeDhcp4.h" + +#define DebugPrint(x) +// +// #define DebugPrint(x) Aprint x +// +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +STATIC +INTN +offer_verify ( + IN PXE_DHCP4_PRIVATE_DATA *Private, + IN DHCP4_PACKET *tx_pkt, + IN DHCP4_PACKET *rx_pkt, + IN UINTN rx_pkt_size + ) +/*++ + -2 = ignore, stop waiting + -1 = ignore, keep waiting + 0 = accept, keep waiting + 1 = accept, stop waiting +--*/ +{ + EFI_STATUS EfiStatus; + DHCP4_PACKET *tmp; + DHCP4_OP *msg_type_op; + DHCP4_OP *srvid_op; + UINT32 magik; + + // + // Verify parameters. Touch unused parameters to keep + // compiler happy. + // + ASSERT (Private); + ASSERT (rx_pkt); + + if (Private == NULL || rx_pkt == NULL) { + return -2; + } + + tx_pkt = tx_pkt; + rx_pkt_size = rx_pkt_size; + + // + // This may be a BOOTP Reply or DHCP Offer packet. + // If there is no DHCP magik number, assume that + // this is a BOOTP Reply packet. + // + magik = htonl (DHCP4_MAGIK_NUMBER); + + while (!CompareMem (&rx_pkt->dhcp4.magik, &magik, 4)) { + // + // If there is no DHCP message type option, assume + // this is a BOOTP reply packet and cache it. + // + EfiStatus = find_opt (rx_pkt, DHCP4_MESSAGE_TYPE, 0, &msg_type_op); + + if (EFI_ERROR (EfiStatus)) { + break; + } + // + // If there is a DHCP message type option, it must be a + // DHCP offer packet + // + if (msg_type_op->len != 1) { + return -1; + } + + if (msg_type_op->data[0] != DHCP4_MESSAGE_TYPE_OFFER) { + return -1; + } + // + // There must be a server identifier option. + // + EfiStatus = find_opt ( + rx_pkt, + DHCP4_SERVER_IDENTIFIER, + 0, + &srvid_op + ); + + if (EFI_ERROR (EfiStatus)) { + return -1; + } + + if (srvid_op->len != 4) { + return -1; + } + // + // Good DHCP offer packet. + // + break; + } + // + // Good DHCP (or BOOTP) packet. Cache it! + // + EfiStatus = gBS->AllocatePool ( + EfiBootServicesData, + (Private->offers + 1) * sizeof (DHCP4_PACKET), + (VOID **) &tmp + ); + + if (EFI_ERROR (EfiStatus)) { + return -2; + } + + ASSERT (tmp); + + if (Private->offers != 0) { + CopyMem ( + tmp, + Private->offer_list, + Private->offers * sizeof (DHCP4_PACKET) + ); + + gBS->FreePool (Private->offer_list); + } + + CopyMem (&tmp[Private->offers++], rx_pkt, sizeof (DHCP4_PACKET)); + + Private->offer_list = tmp; + + return 0; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +STATIC +INTN +acknak_verify ( + IN PXE_DHCP4_PRIVATE_DATA *Private, + IN DHCP4_PACKET *tx_pkt, + IN DHCP4_PACKET *rx_pkt, + IN UINTN rx_pkt_size + ) +/*++ + -2 = ignore, stop waiting + -1 = ignore, keep waiting + 0 = accept, keep waiting + 1 = accept, stop waiting +--*/ +{ + EFI_STATUS EfiStatus; + DHCP4_OP *msg_type_op; + DHCP4_OP *srvid_op; + DHCP4_OP *renew_op; + DHCP4_OP *rebind_op; + DHCP4_OP *lease_time_op; + UINT32 magik; + + // + // Verify parameters. Touch unused parameters to + // keep compiler happy. + // + ASSERT (Private); + ASSERT (rx_pkt); + + if (Private == NULL || rx_pkt == NULL) { + return -2; + } + + tx_pkt = tx_pkt; + rx_pkt_size = rx_pkt_size; + + // + // This must be a DHCP Ack message. + // + magik = htonl (DHCP4_MAGIK_NUMBER); + + if (CompareMem (&rx_pkt->dhcp4.magik, &magik, 4)) { + return -1; + } + + EfiStatus = find_opt (rx_pkt, DHCP4_MESSAGE_TYPE, 0, &msg_type_op); + + if (EFI_ERROR (EfiStatus)) { + return -1; + } + + if (msg_type_op->len != 1) { + return -1; + } + + if (msg_type_op->data[0] != DHCP4_MESSAGE_TYPE_ACK) { + return -1; + } + // + // There must be a server identifier. + // + EfiStatus = find_opt (rx_pkt, DHCP4_SERVER_IDENTIFIER, 0, &srvid_op); + + if (EFI_ERROR (EfiStatus)) { + return -1; + } + + if (srvid_op->len != 4) { + return -1; + } + // + // There should be a renewal time. + // If there is not, we will default to the 7/8 of the rebinding time. + // + EfiStatus = find_opt (rx_pkt, DHCP4_RENEWAL_TIME, 0, &renew_op); + + if (EFI_ERROR (EfiStatus)) { + renew_op = NULL; + } else if (renew_op->len != 4) { + renew_op = NULL; + } + // + // There should be a rebinding time. + // If there is not, we will default to 7/8 of the lease time. + // + EfiStatus = find_opt (rx_pkt, DHCP4_REBINDING_TIME, 0, &rebind_op); + + if (EFI_ERROR (EfiStatus)) { + rebind_op = NULL; + } else if (rebind_op->len != 4) { + rebind_op = NULL; + } + // + // There should be a lease time. + // If there is not, we will default to one week. + // + EfiStatus = find_opt (rx_pkt, DHCP4_LEASE_TIME, 0, &lease_time_op); + + if (EFI_ERROR (EfiStatus)) { + lease_time_op = NULL; + } else if (lease_time_op->len != 4) { + lease_time_op = NULL; + } + // + // Packet looks good. Double check the renew, rebind and lease times. + // + CopyMem (&Private->ServerIp, srvid_op->data, 4); + + if (renew_op != NULL) { + CopyMem (&Private->RenewTime, renew_op->data, 4); + Private->RenewTime = htonl (Private->RenewTime); + } else { + Private->RenewTime = 0; + } + + if (rebind_op != NULL) { + CopyMem (&Private->RebindTime, rebind_op->data, 4); + Private->RebindTime = htonl (Private->RebindTime); + } else { + Private->RebindTime = 0; + } + + if (lease_time_op != NULL) { + CopyMem (&Private->LeaseTime, lease_time_op->data, 4); + Private->LeaseTime = htonl (Private->LeaseTime); + } else { + Private->LeaseTime = 0; + } + + if (Private->LeaseTime < 60) { + Private->LeaseTime = 7 * 86400; + } + + if (Private->RebindTime < 52 || Private->RebindTime >= Private->LeaseTime) { + Private->RebindTime = Private->LeaseTime / 2 + Private->LeaseTime / 4 + Private->LeaseTime / 8; + } + + if (Private->RenewTime < 45 || Private->RenewTime >= Private->RebindTime) { + Private->RenewTime = Private->RebindTime / 2 + Private->RebindTime / 4 + Private->RebindTime / 8; + } + + return 1; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +EFI_STATUS +EFIAPI +PxeDhcp4Init ( + IN EFI_PXE_DHCP4_PROTOCOL *This, + IN UINTN seconds_timeout, + OUT UINTN *Offers, + OUT DHCP4_PACKET **OfferList + ) +{ + PXE_DHCP4_PRIVATE_DATA *Private; + DHCP4_PACKET offer; + EFI_IP_ADDRESS bcast_ip; + EFI_STATUS EfiStatus; + + // + // Verify parameters and protocol state. + // + if (This == NULL || + seconds_timeout < DHCP4_MIN_SECONDS || + seconds_timeout > DHCP4_MAX_SECONDS || + Offers == NULL || + OfferList == NULL + ) { + // + // Return parameters are not initialized when + // parameters are invalid! + // + return EFI_INVALID_PARAMETER; + } + + *Offers = 0; + *OfferList = NULL; + + // + // Check protocol state. + // + if (This->Data == NULL) { + return EFI_NOT_STARTED; + } + + if (!This->Data->SetupCompleted) { + return EFI_NOT_READY; + } + +#if 0 + if (!is_good_discover (&This->Data->Discover)) { + // + // %%TBD - check discover packet fields + // + } +#endif + // + // Get pointer to our instance data. + // + Private = PXE_DHCP4_PRIVATE_DATA_FROM_THIS (This); + + if (Private == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Private->PxeBc == NULL) { + return EFI_DEVICE_ERROR; + } + // + // Setup variables... + // + Private->offers = 0; + Private->offer_list = NULL; + + EfiStatus = gBS->HandleProtocol ( + Private->Handle, + &gEfiPxeDhcp4CallbackProtocolGuid, + (VOID *) &Private->callback + ); + + if (EFI_ERROR (EfiStatus)) { + Private->callback = NULL; + } + + Private->function = EFI_PXE_DHCP4_FUNCTION_INIT; + + // + // Increment the transaction ID. + // + { + UINT32 xid; + + CopyMem (&xid, &This->Data->Discover.dhcp4.xid, sizeof (UINT32)); + + xid = htonl (htonl (xid) + 1); + + CopyMem (&This->Data->Discover.dhcp4.xid, &xid, sizeof (UINT32)); + } + // + // Transmit discover and wait for offers... + // + SetMem (&bcast_ip, sizeof (EFI_IP_ADDRESS), 0xFF); + + EfiStatus = tx_rx_udp ( + Private, + &bcast_ip, + NULL, + NULL, + NULL, + &This->Data->Discover, + &offer, + &offer_verify, + seconds_timeout + ); + + if (EFI_ERROR (EfiStatus)) { + if (Private->offer_list) { + gBS->FreePool (Private->offer_list); + } + + Private->offers = 0; + Private->offer_list = NULL; + Private->callback = NULL; + + DebugPrint (("%a:%d:%r\n", __FILE__, __LINE__, EfiStatus)); + return EfiStatus; + } + + *Offers = Private->offers; + *OfferList = Private->offer_list; + + Private->offers = 0; + Private->offer_list = NULL; + Private->callback = NULL; + + This->Data->InitCompleted = TRUE; + This->Data->SelectCompleted = FALSE; + This->Data->IsBootp = FALSE; + This->Data->IsAck = FALSE; + + return EFI_SUCCESS; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +EFI_STATUS +EFIAPI +PxeDhcp4Select ( + IN EFI_PXE_DHCP4_PROTOCOL *This, + IN UINTN seconds_timeout, + IN DHCP4_PACKET *Offer + ) +{ + PXE_DHCP4_PRIVATE_DATA *Private; + EFI_STATUS EfiStatus; + DHCP4_PACKET request; + DHCP4_PACKET acknak; + EFI_IP_ADDRESS bcast_ip; + EFI_IP_ADDRESS zero_ip; + EFI_IP_ADDRESS local_ip; + DHCP4_OP *srvid; + DHCP4_OP *op; + UINT32 dhcp4_magik; + UINT8 buf[16]; + BOOLEAN is_bootp; + + // + // Verify parameters. + // + if (This == NULL || seconds_timeout < DHCP4_MIN_SECONDS || seconds_timeout > DHCP4_MAX_SECONDS || Offer == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Check protocol state. + // + if (This->Data == NULL) { + return EFI_NOT_STARTED; + } + + if (!This->Data->SetupCompleted) { + return EFI_NOT_READY; + } + // + // Get pointer to instance data. + // + Private = PXE_DHCP4_PRIVATE_DATA_FROM_THIS (This); + + if (Private == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Private->PxeBc == NULL) { + return EFI_DEVICE_ERROR; + } + +#if 0 + if (!is_good_discover (&This->Data->Discover)) { + // + // %%TBD - check discover packet fields + // + } +#endif + // + // Setup useful variables... + // + SetMem (&bcast_ip, sizeof (EFI_IP_ADDRESS), 0xFF); + + ZeroMem (&zero_ip, sizeof (EFI_IP_ADDRESS)); + + ZeroMem (&local_ip, sizeof (EFI_IP_ADDRESS)); + local_ip.v4.Addr[0] = 127; + local_ip.v4.Addr[3] = 1; + + This->Data->SelectCompleted = FALSE; + This->Data->IsBootp = FALSE; + This->Data->IsAck = FALSE; + + EfiStatus = gBS->HandleProtocol ( + Private->Handle, + &gEfiPxeDhcp4CallbackProtocolGuid, + (VOID *) &Private->callback + ); + + if (EFI_ERROR (EfiStatus)) { + Private->callback = NULL; + } + + Private->function = EFI_PXE_DHCP4_FUNCTION_SELECT; + + // + // Verify offer packet fields. + // + if (Offer->dhcp4.op != BOOTP_REPLY) { + Private->callback = NULL; + return EFI_INVALID_PARAMETER; + } + + if (Offer->dhcp4.htype != This->Data->Discover.dhcp4.htype) { + Private->callback = NULL; + return EFI_INVALID_PARAMETER; + } + + if (Offer->dhcp4.hlen != This->Data->Discover.dhcp4.hlen) { + Private->callback = NULL; + return EFI_INVALID_PARAMETER; + } + + if (CompareMem (&Offer->dhcp4.xid, &This->Data->Discover.dhcp4.xid, 4)) { + Private->callback = NULL; + return EFI_INVALID_PARAMETER; + } + + if (!CompareMem (&Offer->dhcp4.yiaddr, &bcast_ip, 4)) { + Private->callback = NULL; + return EFI_INVALID_PARAMETER; + } + + if (!CompareMem (&Offer->dhcp4.yiaddr, &zero_ip, 4)) { + Private->callback = NULL; + return EFI_INVALID_PARAMETER; + } + + if (!CompareMem (&Offer->dhcp4.yiaddr, &local_ip, 4)) { + Private->callback = NULL; + return EFI_INVALID_PARAMETER; + } + + if (CompareMem ( + &Offer->dhcp4.chaddr, + &This->Data->Discover.dhcp4.chaddr, + 16 + )) { + Private->callback = NULL; + return EFI_INVALID_PARAMETER; + } + // + // DHCP option checks + // + dhcp4_magik = htonl (DHCP4_MAGIK_NUMBER); + is_bootp = TRUE; + + if (!CompareMem (&Offer->dhcp4.magik, &dhcp4_magik, 4)) { + // + // If present, DHCP message type must be offer. + // + EfiStatus = find_opt (Offer, DHCP4_MESSAGE_TYPE, 0, &op); + + if (!EFI_ERROR (EfiStatus)) { + if (op->len != 1 || op->data[0] != DHCP4_MESSAGE_TYPE_OFFER) { + Private->callback = NULL; + return EFI_INVALID_PARAMETER; + } + + is_bootp = FALSE; + } + // + // If present, DHCP max message size must be valid. + // + EfiStatus = find_opt (Offer, DHCP4_MAX_MESSAGE_SIZE, 0, &op); + + if (!EFI_ERROR (EfiStatus)) { + if (op->len != 2 || ((op->data[0] << 8) | op->data[1]) < DHCP4_DEFAULT_MAX_MESSAGE_SIZE) { + Private->callback = NULL; + return EFI_INVALID_PARAMETER; + } + } + // + // If present, DHCP server identifier must be valid. + // + EfiStatus = find_opt (Offer, DHCP4_SERVER_IDENTIFIER, 0, &op); + + if (!EFI_ERROR (EfiStatus)) { + if (op->len != 4 || !CompareMem (op->data, &bcast_ip, 4) || !CompareMem (op->data, &zero_ip, 4)) { + Private->callback = NULL; + return EFI_INVALID_PARAMETER; + } + } + // + // If present, DHCP subnet mask must be valid. + // + EfiStatus = find_opt ( + Offer, + DHCP4_SUBNET_MASK, + 0, + &op + ); + + if (!EFI_ERROR (EfiStatus)) { + if (op->len != 4) { + Private->callback = NULL; + return EFI_INVALID_PARAMETER; + } + } + } + // + // Early out for BOOTP. + // + This->Data->IsBootp = is_bootp; + if (is_bootp) { + // + // Copy offer packet to instance data. + // + CopyMem (&This->Data->Offer, Offer, sizeof (DHCP4_PACKET)); + + // + // Copy discover to request and offer to acknak. + // + CopyMem ( + &This->Data->Request, + &This->Data->Discover, + sizeof (DHCP4_PACKET) + ); + + CopyMem ( + &This->Data->AckNak, + &This->Data->Offer, + sizeof (DHCP4_PACKET) + ); + + // + // Set state flags. + // + This->Data->SelectCompleted = TRUE; + This->Data->IsAck = TRUE; + + Private->callback = NULL; + return EFI_SUCCESS; + } + // + // Copy discover packet contents to request packet. + // + CopyMem (&request, &This->Data->Discover, sizeof (DHCP4_PACKET)); + + This->Data->IsAck = FALSE; + + // + // Change DHCP message type from discover to request. + // + EfiStatus = find_opt (&request, DHCP4_MESSAGE_TYPE, 0, &op); + + if (EFI_ERROR (EfiStatus) && EfiStatus != EFI_NOT_FOUND) { + Private->callback = NULL; + return EFI_INVALID_PARAMETER; + } + + if (EfiStatus == EFI_NOT_FOUND) { + EfiStatus = find_opt (&request, DHCP4_END, 0, &op); + + if (EFI_ERROR (EfiStatus)) { + Private->callback = NULL; + return EFI_INVALID_PARAMETER; + } + + op->op = DHCP4_MESSAGE_TYPE; + op->len = 1; + + op->data[1] = DHCP4_END; + } + + op->data[0] = DHCP4_MESSAGE_TYPE_REQUEST; + + // + // Copy server identifier option from offer to request. + // + EfiStatus = find_opt (Offer, DHCP4_SERVER_IDENTIFIER, 0, &srvid); + + if (EFI_ERROR (EfiStatus)) { + Private->callback = NULL; + return EFI_INVALID_PARAMETER; + } + + if (srvid->len != 4) { + Private->callback = NULL; + return EFI_INVALID_PARAMETER; + } + + EfiStatus = add_opt (&request, srvid); + + if (EFI_ERROR (EfiStatus)) { + DebugPrint (("%a:%d:%r\n", __FILE__, __LINE__, EfiStatus)); + Private->callback = NULL; + return EfiStatus; + } + // + // Add requested IP address option to request packet. + // + op = (DHCP4_OP *) buf; + op->op = DHCP4_REQUESTED_IP_ADDRESS; + op->len = 4; + CopyMem (op->data, &Offer->dhcp4.yiaddr, 4); + + EfiStatus = add_opt (&request, op); + + if (EFI_ERROR (EfiStatus)) { + DebugPrint (("%a:%d:%r\n", __FILE__, __LINE__, EfiStatus)); + Private->callback = NULL; + return EfiStatus; + } + // + // Transimit DHCP request and wait for DHCP ack... + // + SetMem (&bcast_ip, sizeof (EFI_IP_ADDRESS), 0xFF); + + EfiStatus = tx_rx_udp ( + Private, + &bcast_ip, + NULL, + NULL, + NULL, + &request, + &acknak, + &acknak_verify, + seconds_timeout + ); + + if (EFI_ERROR (EfiStatus)) { + DebugPrint (("%a:%d:%r\n", __FILE__, __LINE__, EfiStatus)); + Private->callback = NULL; + return EfiStatus; + } + // + // Set Data->IsAck and return. + // + EfiStatus = find_opt (&acknak, DHCP4_MESSAGE_TYPE, 0, &op); + + if (EFI_ERROR (EfiStatus)) { + Private->callback = NULL; + return EFI_DEVICE_ERROR; + } + + if (op->len != 1) { + Private->callback = NULL; + return EFI_DEVICE_ERROR; + } + + switch (op->data[0]) { + case DHCP4_MESSAGE_TYPE_ACK: + This->Data->IsAck = TRUE; + break; + + case DHCP4_MESSAGE_TYPE_NAK: + This->Data->IsAck = FALSE; + break; + + default: + Private->callback = NULL; + return EFI_DEVICE_ERROR; + } + // + // Copy packets into instance data... + // + CopyMem (&This->Data->Offer, Offer, sizeof (DHCP4_PACKET)); + CopyMem (&This->Data->Request, &request, sizeof (DHCP4_PACKET)); + CopyMem (&This->Data->AckNak, &acknak, sizeof (DHCP4_PACKET)); + + This->Data->SelectCompleted = TRUE; + + Private->callback = NULL; + return EFI_SUCCESS; +} + +/* eof - PxeDhcp4InitSelect.c */ diff --git a/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4Release.c b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4Release.c new file mode 100644 index 0000000000..6086e55eba --- /dev/null +++ b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4Release.c @@ -0,0 +1,246 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + PxeDhcp4Release.c + +Abstract: + Transmit release packet, free allocations and shutdown PxeDhcp4. + +--*/ + + +#include "PxeDhcp4.h" + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +EFI_STATUS +EFIAPI +PxeDhcp4Release ( + IN EFI_PXE_DHCP4_PROTOCOL *This + ) +{ + PXE_DHCP4_PRIVATE_DATA *Private; + EFI_IP_ADDRESS ServerIp; + EFI_IP_ADDRESS client_ip; + EFI_IP_ADDRESS gateway_ip; + EFI_IP_ADDRESS subnet_mask; + EFI_STATUS efi_status; + DHCP4_OP *op; + UINT8 op_list[20]; + + // + // Check for invalid parameters. + // + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Release does nothing if the protocol has never been setup. + // + if (This->Data == NULL) { + return EFI_NOT_STARTED; + } + // + // Fail if we do not have valid instance data. + // + Private = PXE_DHCP4_PRIVATE_DATA_FROM_THIS (This); + + if (Private == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Private->PxeBc == NULL) { + return EFI_DEVICE_ERROR; + } + // + // If this is a BOOTP session and there is not a DHCP Ack + // packet, just release storage and return. + // + if (This->Data->IsBootp || !This->Data->IsAck) { + gBS->FreePool (This->Data); + This->Data = NULL; + + if (Private->StopPxeBc) { + Private->PxeBc->Stop (Private->PxeBc); + } + + return EFI_SUCCESS; + } + // + // Build option list for DHCP Release packet. + // If any errors occur, just release storage and return. + // + // + // Message type is first. + // + op_list[0] = DHCP4_MESSAGE_TYPE; + op_list[1] = 1; + op_list[2] = DHCP4_MESSAGE_TYPE_RELEASE; + + // + // Followed by server identifier. + // + efi_status = find_opt ( + &This->Data->Request, + DHCP4_SERVER_IDENTIFIER, + 0, + &op + ); + + if (EFI_ERROR (efi_status)) { + gBS->FreePool (This->Data); + This->Data = NULL; + + if (Private->StopPxeBc) { + Private->PxeBc->Stop (Private->PxeBc); + } + + return EFI_SUCCESS; + } + + if (op->len != 4) { + gBS->FreePool (This->Data); + This->Data = NULL; + + if (Private->StopPxeBc) { + Private->PxeBc->Stop (Private->PxeBc); + } + + return EFI_SUCCESS; + } + + CopyMem (&ServerIp, op->data, 4); + + op_list[3] = DHCP4_SERVER_IDENTIFIER; + op_list[4] = 4; + CopyMem (&op_list[5], &ServerIp, 4); + + // + // Followed by end. + // + op_list[9] = DHCP4_END; + + // + // We need a subnet mask for IP stack operation. + // + efi_status = find_opt ( + &This->Data->AckNak, + DHCP4_SUBNET_MASK, + 0, + &op + ); + + if (EFI_ERROR (efi_status)) { + gBS->FreePool (This->Data); + This->Data = NULL; + + if (Private->StopPxeBc) { + Private->PxeBc->Stop (Private->PxeBc); + } + + return EFI_SUCCESS; + } + + if (op->len != 4) { + gBS->FreePool (This->Data); + This->Data = NULL; + + if (Private->StopPxeBc) { + Private->PxeBc->Stop (Private->PxeBc); + } + + return EFI_SUCCESS; + } + + ZeroMem (&subnet_mask, sizeof (EFI_IP_ADDRESS)); + CopyMem (&subnet_mask, op->data, 4); + + // + // Gateway IP address may be needed. + // + ZeroMem (&gateway_ip, sizeof (EFI_IP_ADDRESS)); + CopyMem (&gateway_ip, &This->Data->AckNak.dhcp4.giaddr, 4); + + // + // Client IP address needed for IP stack operation. + // + ZeroMem (&client_ip, sizeof (EFI_IP_ADDRESS)); + CopyMem (&client_ip, &This->Data->AckNak.dhcp4.yiaddr, 4); + + // + // Enable UDP... + // + efi_status = start_udp (Private, &client_ip, &subnet_mask); + + if (EFI_ERROR (efi_status)) { + gBS->FreePool (This->Data); + This->Data = NULL; + + if (Private->StopPxeBc) { + Private->PxeBc->Stop (Private->PxeBc); + } + + return efi_status; + } + // + // Gather information out of DHCP request packet needed for + // DHCP release packet. + // + // + // Setup DHCP Release packet. + // + CopyMem (&This->Data->Request.dhcp4.ciaddr, &client_ip, 4); + + ZeroMem (&This->Data->Request.dhcp4.yiaddr, 12); + + ZeroMem (&This->Data->Request.dhcp4.sname, 64 + 128); + + This->Data->Request.dhcp4.hops = 0; + This->Data->Request.dhcp4.secs = 0; + This->Data->Request.dhcp4.flags = 0; + + ZeroMem ( + &This->Data->Request.dhcp4.options, + sizeof This->Data->Request.dhcp4.options + ); + + CopyMem (&This->Data->Request.dhcp4.options, op_list, 10); + + // + // Transmit DHCP Release packet. + // + tx_udp ( + Private, + &ServerIp, + &gateway_ip, + &client_ip, + &This->Data->Request, + DHCP4_MAX_PACKET_SIZE - (DHCP4_UDP_HEADER_SIZE + DHCP4_IP_HEADER_SIZE) + ); + + gBS->Stall (1000000); /* 1/10th second */ + + // + // Shutdown PXE BaseCode and release local storage. + // + stop_udp (Private); + + gBS->FreePool (This->Data); + This->Data = NULL; + + if (Private->StopPxeBc) { + Private->PxeBc->Stop (Private->PxeBc); + } + + return EFI_SUCCESS; +} + +/* eof - PxeDhcp4Release.c */ diff --git a/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4RenewRebind.c b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4RenewRebind.c new file mode 100644 index 0000000000..2905255faa --- /dev/null +++ b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4RenewRebind.c @@ -0,0 +1,408 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + PxeDhcp4RenewRebind.c + +Abstract: + +--*/ + + +#include "PxeDhcp4.h" + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +STATIC +INTN +acknak_verify ( + IN PXE_DHCP4_PRIVATE_DATA *Private, + IN DHCP4_PACKET *tx_pkt, + IN DHCP4_PACKET *rx_pkt, + IN UINTN rx_pkt_size + ) +/*++ +Routine Description: + +Parameters: + +Returns: + -2 = ignore, stop waiting + -1 = ignore, keep waiting + 0 = accept, keep waiting + 1 = accept, stop waiting +--*/ +{ + EFI_STATUS efi_status; + DHCP4_OP *msg_type_op; + DHCP4_OP *srvid_op; + DHCP4_OP *renew_op; + DHCP4_OP *rebind_op; + DHCP4_OP *lease_time_op; + UINT32 magik; + + // + // Verify parameters. Unused parameters are also touched + // to make the compiler happy. + // + ASSERT (Private); + ASSERT (rx_pkt); + + if (Private == NULL || rx_pkt == NULL) { + return -2; + } + + tx_pkt = tx_pkt; + rx_pkt_size = rx_pkt_size; + + // + // This must be a DHCP Ack message. + // + magik = htonl (DHCP4_MAGIK_NUMBER); + + if (CompareMem (&rx_pkt->dhcp4.magik, &magik, 4)) { + return -1; + } + + efi_status = find_opt (rx_pkt, DHCP4_MESSAGE_TYPE, 0, &msg_type_op); + + if (EFI_ERROR (efi_status)) { + return -1; + } + + if (msg_type_op->len != 1) { + return -1; + } + + if (msg_type_op->data[0] != DHCP4_MESSAGE_TYPE_ACK) { + return -1; + } + // + // There must be a server identifier. + // + efi_status = find_opt (rx_pkt, DHCP4_SERVER_IDENTIFIER, 0, &srvid_op); + + if (EFI_ERROR (efi_status)) { + return -1; + } + + if (srvid_op->len != 4) { + return -1; + } + // + // There should be a renewal time. + // If there is not, we will default to the 7/8 of the rebinding time. + // + efi_status = find_opt (rx_pkt, DHCP4_RENEWAL_TIME, 0, &renew_op); + + if (EFI_ERROR (efi_status)) { + renew_op = NULL; + } else if (renew_op->len != 4) { + renew_op = NULL; + } + // + // There should be a rebinding time. + // If there is not, we will default to 7/8 of the lease time. + // + efi_status = find_opt (rx_pkt, DHCP4_REBINDING_TIME, 0, &rebind_op); + + if (EFI_ERROR (efi_status)) { + rebind_op = NULL; + } else if (rebind_op->len != 4) { + rebind_op = NULL; + } + // + // There should be a lease time. + // If there is not, we will default to one week. + // + efi_status = find_opt (rx_pkt, DHCP4_LEASE_TIME, 0, &lease_time_op); + + if (EFI_ERROR (efi_status)) { + lease_time_op = NULL; + } else if (lease_time_op->len != 4) { + lease_time_op = NULL; + } + // + // Packet looks good. Double check the renew, rebind and lease times. + // + CopyMem (&Private->ServerIp, srvid_op->data, 4); + + if (renew_op != NULL) { + CopyMem (&Private->RenewTime, renew_op->data, 4); + Private->RenewTime = htonl (Private->RenewTime); + } else { + Private->RenewTime = 0; + } + + if (rebind_op != NULL) { + CopyMem (&Private->RebindTime, rebind_op->data, 4); + Private->RebindTime = htonl (Private->RebindTime); + } else { + Private->RebindTime = 0; + } + + if (lease_time_op != NULL) { + CopyMem (&Private->LeaseTime, lease_time_op->data, 4); + Private->LeaseTime = htonl (Private->LeaseTime); + } else { + Private->LeaseTime = 0; + } + + if (Private->LeaseTime < 60) { + Private->LeaseTime = 7 * 86400; + } + + if (Private->RebindTime < 52 || Private->RebindTime >= Private->LeaseTime) { + Private->RebindTime = Private->LeaseTime / 2 + Private->LeaseTime / 4 + Private->LeaseTime / 8; + } + + if (Private->RenewTime < 45 || Private->RenewTime >= Private->RebindTime) { + Private->RenewTime = Private->RebindTime / 2 + Private->RebindTime / 4 + Private->RebindTime / 8; + } + + return 1; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +STATIC +EFI_STATUS +EFIAPI +renew_rebind ( + IN EFI_PXE_DHCP4_PROTOCOL *This, + IN UINTN seconds_timeout, + IN BOOLEAN renew + ) +{ + PXE_DHCP4_PRIVATE_DATA *Private; + EFI_IP_ADDRESS ServerIp; + EFI_IP_ADDRESS client_ip; + EFI_IP_ADDRESS subnet_mask; + EFI_IP_ADDRESS gateway_ip; + DHCP4_PACKET Request; + DHCP4_PACKET AckNak; + DHCP4_OP *op; + EFI_STATUS efi_status; + + // + // Check for invalid parameters. + // + if (This == NULL || seconds_timeout < DHCP4_MIN_SECONDS || seconds_timeout > DHCP4_MAX_SECONDS) { + return EFI_INVALID_PARAMETER; + } + // + // Check for proper protocol state. + // + if (This->Data == NULL) { + return EFI_NOT_STARTED; + } + + if (!This->Data->SelectCompleted) { + return EFI_NOT_READY; + } + + if (This->Data->IsBootp) { + return EFI_SUCCESS; + } + + if (!This->Data->IsAck) { + return EFI_INVALID_PARAMETER; + } + // + // Get pointer to instance data. + // + Private = PXE_DHCP4_PRIVATE_DATA_FROM_THIS (This); + + if (Private == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Private->PxeBc == NULL) { + return EFI_DEVICE_ERROR; + } + // + // Copy Discover packet to temporary request packet + // to be used for Renew/Rebind operation. + // + CopyMem (&Request, &This->Data->Discover, sizeof (DHCP4_PACKET)); + + CopyMem (&Request.dhcp4.ciaddr, &This->Data->AckNak.dhcp4.yiaddr, 4); + + Request.dhcp4.flags = 0; /* Reply does not need to be broadcast. */ + + // + // Change message type from discover to request. + // + efi_status = find_opt (&Request, DHCP4_MESSAGE_TYPE, 0, &op); + + if (EFI_ERROR (efi_status)) { + return EFI_INVALID_PARAMETER; + } + + if (op->len != 1) { + return EFI_INVALID_PARAMETER; + } + + op->data[0] = DHCP4_MESSAGE_TYPE_REQUEST; + + // + // Need a subnet mask. + // + efi_status = find_opt ( + &This->Data->AckNak, + DHCP4_SUBNET_MASK, + 0, + &op + ); + + if (EFI_ERROR (efi_status)) { + return EFI_INVALID_PARAMETER; + } + + if (op->len != 4) { + return EFI_INVALID_PARAMETER; + } + + ZeroMem (&subnet_mask, sizeof (EFI_IP_ADDRESS)); + CopyMem (&subnet_mask, op->data, 4); + + // + // Need a server IP address (renew) or a broadcast + // IP address (rebind). + // + ZeroMem (&gateway_ip, sizeof (EFI_IP_ADDRESS)); + + if (renew) { + efi_status = find_opt ( + &This->Data->AckNak, + DHCP4_SERVER_IDENTIFIER, + 0, + &op + ); + + if (EFI_ERROR (efi_status)) { + return EFI_INVALID_PARAMETER; + } + + if (op->len != 4) { + return EFI_INVALID_PARAMETER; + } + + ZeroMem (&ServerIp, sizeof (EFI_IP_ADDRESS)); + CopyMem (&ServerIp, op->data, 4); + + // + // + // + if (CompareMem (&This->Data->AckNak.dhcp4.giaddr, &gateway_ip, 4)) { + CopyMem (&gateway_ip, &This->Data->AckNak.dhcp4.giaddr, 4); + } + } else { + SetMem (&ServerIp, sizeof (EFI_IP_ADDRESS), 0xFF); + } + // + // Need a client IP address. + // + ZeroMem (&client_ip, sizeof (EFI_IP_ADDRESS)); + CopyMem (&client_ip, &Request.dhcp4.ciaddr, 4); + + // + // + // + efi_status = gBS->HandleProtocol ( + Private->Handle, + &gEfiPxeDhcp4CallbackProtocolGuid, + (VOID *) &Private->callback + ); + + if (EFI_ERROR (efi_status)) { + Private->callback = NULL; + } + + Private->function = renew ? EFI_PXE_DHCP4_FUNCTION_RENEW : EFI_PXE_DHCP4_FUNCTION_REBIND; + + // + // Transimit DHCP request and wait for DHCP ack... + // + efi_status = tx_rx_udp ( + Private, + &ServerIp, + &gateway_ip, + &client_ip, + &subnet_mask, + &Request, + &AckNak, + &acknak_verify, + seconds_timeout + ); + + if (EFI_ERROR (efi_status)) { + Private->callback = NULL; + return efi_status; + } + // + // Copy server identifier, renewal time and rebinding time + // from temporary ack/nak packet into cached ack/nak packet. + // + efi_status = find_opt ( + &This->Data->AckNak, + DHCP4_SERVER_IDENTIFIER, + 0, + &op + ); + + if (!EFI_ERROR (efi_status)) { + if (op->len == 4) { + CopyMem (op->data, &Private->ServerIp, 4); + } + } + + efi_status = find_opt (&This->Data->AckNak, DHCP4_RENEWAL_TIME, 0, &op); + + if (!EFI_ERROR (efi_status)) { + if (op->len == 4) { + CopyMem (op->data, &Private->RenewTime, 4); + } + } + + efi_status = find_opt (&This->Data->AckNak, DHCP4_REBINDING_TIME, 0, &op); + + if (!EFI_ERROR (efi_status)) { + if (op->len == 4) { + CopyMem (op->data, &Private->RebindTime, 4); + } + } + + Private->callback = NULL; + return efi_status; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +EFI_STATUS +EFIAPI +PxeDhcp4Renew ( + IN EFI_PXE_DHCP4_PROTOCOL *This, + IN UINTN seconds_timeout + ) +{ + return renew_rebind (This, seconds_timeout, TRUE); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +EFI_STATUS +EFIAPI +PxeDhcp4Rebind ( + IN EFI_PXE_DHCP4_PROTOCOL *This, + IN UINTN seconds_timeout + ) +{ + return renew_rebind (This, seconds_timeout, FALSE); +} + +/* eof - PxeDhcp4RenewRebind.c */ diff --git a/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4Run.c b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4Run.c new file mode 100644 index 0000000000..50f97a8915 --- /dev/null +++ b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4Run.c @@ -0,0 +1,196 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + PxeDhcp4Run.c + +Abstract: + Simplified entry point for starting basic PxeDhcp4 client operation. + +--*/ + + +#include "PxeDhcp4.h" + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +EFI_STATUS +EFIAPI +PxeDhcp4Run ( + IN EFI_PXE_DHCP4_PROTOCOL *This, + IN OPTIONAL UINTN OpLen, + IN OPTIONAL VOID *OpList + ) +{ + PXE_DHCP4_PRIVATE_DATA *Private; + DHCP4_PACKET *offer_list; + EFI_STATUS efi_status; + EFI_IP_ADDRESS zero_ip; + UINTN offers; + UINTN timeout; + UINTN n; + UINT16 seconds; + + // + // Validate parameters. + // + if (This == NULL || (OpLen != 0 && OpList == NULL) || (OpLen == 0 && OpList != NULL)) { + return EFI_INVALID_PARAMETER; + } + + for (n = 0; n < OpLen;) { + switch (((UINT8 *) OpList)[n]) { + case DHCP4_PAD: + ++n; + continue; + + case DHCP4_END: + ++n; + break; + + default: + n += 2 + ((UINT8 *) OpList)[n + 1]; + continue; + } + + break; + } + + if (n != OpLen) { + return EFI_INVALID_PARAMETER; + } + // + // Get pointer to instance data. + // + Private = PXE_DHCP4_PRIVATE_DATA_FROM_THIS (This); + + if (Private == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Private->PxeBc == NULL) { + return EFI_DEVICE_ERROR; + } + // + // Initialize DHCP discover packet. + // + efi_status = PxeDhcp4Setup (This, NULL); + + if (EFI_ERROR (efi_status)) { + return efi_status; + } + + for (n = 0; n < OpLen;) { + switch (((UINT8 *) OpList)[n]) { + case DHCP4_PAD: + ++n; + continue; + + case DHCP4_END: + ++n; + break; + + default: + efi_status = add_opt ( + &This->Data->Discover, + (DHCP4_OP *) &(((UINT8 *) OpList)[n]) + ); + + if (EFI_ERROR (efi_status)) { + return efi_status; + } + + n += 2 + ((UINT8 *) OpList)[n + 1]; + continue; + } + + break; + } + // + // Basic DHCP D.O.R.A. + // 1, 2, 4, 8, 16 & 32 second timeouts. + // Callback routine can be used to break out earlier. + // + ZeroMem (&zero_ip, sizeof (EFI_IP_ADDRESS)); + + for (timeout = 1;;) { + // + // Broadcast DHCP discover and wait for DHCP offers. + // + efi_status = PxeDhcp4Init (This, timeout, &offers, &offer_list); + + switch (efi_status) { + case EFI_NO_RESPONSE: + case EFI_TIMEOUT: + case EFI_SUCCESS: + break; + + case EFI_ABORTED: + default: + return efi_status; + } + // + // Try to select from each DHCP or BOOTP offer. + // + for (n = 0; n < offers; ++n) { + // + // Ignore proxyDHCP offers. + // + if (!CompareMem (&offer_list[n].dhcp4.yiaddr, &zero_ip, 4)) { + continue; + } + // + // Issue DHCP Request and wait for DHCP Ack/Nak. + // + efi_status = PxeDhcp4Select ( + This, + timeout, + &offer_list[n] + ); + + if (EFI_ERROR (efi_status)) { + continue; + } + // + // Exit when we have got our DHCP Ack. + // + if (This->Data->IsAck) { + return EFI_SUCCESS; + } + } + // + // No DHCP Acks. Release DHCP Offer list storage. + // + if (offer_list != NULL) { + gBS->FreePool (offer_list); + offer_list = NULL; + } + // + // Try again until we have used up >= DHCP4_MAX_SECONDS. + // + if ((timeout <<= 1) > DHCP4_MAX_SECONDS) { + if (!EFI_ERROR (efi_status)) { + efi_status = EFI_TIMEOUT; + } + + return efi_status; + } + // + // Next timeout value. + // + CopyMem (&seconds, &This->Data->Discover.dhcp4.secs, 2); + + seconds = htons (htons (seconds) + timeout); + + CopyMem (&This->Data->Discover.dhcp4.secs, &seconds, 2); + } +} + +/* eof - PxeDhcp4Run.c */ diff --git a/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4Setup.c b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4Setup.c new file mode 100644 index 0000000000..09ba041ea6 --- /dev/null +++ b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4Setup.c @@ -0,0 +1,268 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + PxeDhcp4Setup.c + +Abstract: + +--*/ + + +#include "PxeDhcp4.h" + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +EFI_STATUS +EFIAPI +PxeDhcp4Setup ( + IN EFI_PXE_DHCP4_PROTOCOL *This, + IN EFI_PXE_DHCP4_DATA *Data + ) +{ + PXE_DHCP4_PRIVATE_DATA *Private; + DHCP4_HEADER *Packet; + EFI_STATUS EfiStatus; + UINT8 *OpLen; + UINT8 *OpPtr; + + // + // Return error if parameters are invalid. + // + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + Private = PXE_DHCP4_PRIVATE_DATA_FROM_THIS (This); + + if (Private == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (This->Data != NULL) { + return EFI_ALREADY_STARTED; + } + + if (Private->PxeBc == NULL) { + return EFI_DEVICE_ERROR; + } + // + // Check contents of provided Data structure. + // + if (Data != NULL) { + // + // Do protocol state checks first. + // + if (Data->SelectCompleted) { + if (!Data->InitCompleted || !Data->SetupCompleted) { + return EFI_INVALID_PARAMETER; + } + + if (Data->IsBootp && !Data->IsAck) { + return EFI_INVALID_PARAMETER; + } + } else if (Data->InitCompleted) { + if (!Data->SetupCompleted || Data->IsBootp || Data->IsAck) { + return EFI_INVALID_PARAMETER; + } + } else if (Data->SetupCompleted) { + if (Data->IsBootp || Data->IsAck) { + return EFI_INVALID_PARAMETER; + } + } + // + // Do packet content checks. + // + if (Data->SetupCompleted) { + // + // %%TBD - check discover packet + // + } + + if (Data->SelectCompleted) { + if (Data->IsBootp) { + // + // %%TBD - check offer packet + // + if (CompareMem ( + &Data->Discover, + &Data->Request, + sizeof (DHCP4_PACKET) + )) { + return EFI_INVALID_PARAMETER; + } + + if (CompareMem ( + &Data->Offer, + &Data->AckNak, + sizeof (DHCP4_PACKET) + )) { + return EFI_INVALID_PARAMETER; + } + } else { + // + // %%TBD - check offer, request & acknak packets + // + } + } + } + // + // Allocate data structure. Return error + // if there is not enough available memory. + // + EfiStatus = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (EFI_PXE_DHCP4_DATA), + (VOID **) &This->Data + ); + + if (EFI_ERROR (EfiStatus)) { + This->Data = NULL; + return EfiStatus; + } + + if (This->Data == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Start PxeBc because we want to use its UdpWrite, UdpRead and + // SetFilter calls. + // + EfiStatus = Private->PxeBc->Start (Private->PxeBc, FALSE); + + if (EFI_ERROR (EfiStatus)) { + if (EfiStatus != EFI_ALREADY_STARTED) { + gBS->FreePool (This->Data); + This->Data = NULL; + Private->PxeBc->Stop (Private->PxeBc); + return EfiStatus; + } + + Private->StopPxeBc = FALSE; + } else { + Private->StopPxeBc = TRUE; + } + // + // Use new data. + // + if (Data != NULL) { + CopyMem (This->Data, Data, sizeof (EFI_PXE_DHCP4_DATA)); + return EFI_SUCCESS; + } + // + // Initialize new public data structure. + // + ZeroMem (This->Data, sizeof (EFI_PXE_DHCP4_DATA)); + + // + // Fill in default DHCP discover packet. + // Check for MAC addresses of strange lengths, just in case. + // + Packet = &This->Data->Discover.dhcp4; + + Packet->op = BOOTP_REQUEST; + + Packet->htype = Private->Snp->Mode->IfType; + + if (Private->Snp->Mode->HwAddressSize > 16) { + Packet->hlen = 16; + } else { + Packet->hlen = (UINT8) Private->Snp->Mode->HwAddressSize; + } + + Packet->hops = 0; /* Set to zero per RFC 2131. */ + + if (Packet->hlen < sizeof Packet->xid) { + if (Packet->hlen != 0) { + CopyMem ( + &Packet->xid, + &Private->Snp->Mode->CurrentAddress, + Packet->hlen + ); + } + } else { + CopyMem ( + &Packet->xid, + &Private->Snp->Mode->CurrentAddress.Addr[Packet->hlen - sizeof Packet->xid], + sizeof Packet->xid + ); + } + // + // %%TBD - xid should be randomized + // + Packet->secs = htons (DHCP4_INITIAL_SECONDS); + + Packet->flags = htons (DHCP4_BROADCAST_FLAG); + + if (Packet->hlen != 0) { + CopyMem (Packet->chaddr, &Private->Snp->Mode->CurrentAddress, Packet->hlen); + } + + Packet->magik = htonl (DHCP4_MAGIK_NUMBER); + + OpPtr = Packet->options; + + *OpPtr++ = DHCP4_MESSAGE_TYPE; + *OpPtr++ = 1; + *OpPtr++ = DHCP4_MESSAGE_TYPE_DISCOVER; + + *OpPtr++ = DHCP4_MAX_MESSAGE_SIZE; + *OpPtr++ = 2; + *OpPtr++ = (UINT8) ((DHCP4_DEFAULT_MAX_MESSAGE_SIZE >> 8) & 0xFF); + *OpPtr++ = (UINT8) (DHCP4_DEFAULT_MAX_MESSAGE_SIZE & 0xFF); + + *OpPtr++ = DHCP4_PARAMETER_REQUEST_LIST; + OpLen = OpPtr; + *OpPtr++ = 0; + *OpPtr++ = DHCP4_SUBNET_MASK; + *OpPtr++ = DHCP4_TIME_OFFSET; + *OpPtr++ = DHCP4_ROUTER_LIST; + *OpPtr++ = DHCP4_TIME_SERVERS; + *OpPtr++ = DHCP4_NAME_SERVERS; + *OpPtr++ = DHCP4_DNS_SERVERS; + *OpPtr++ = DHCP4_HOST_NAME; + *OpPtr++ = DHCP4_BOOT_FILE_SIZE; + *OpPtr++ = DHCP4_MESSAGE_TYPE; + *OpPtr++ = DHCP4_DOMAIN_NAME; + *OpPtr++ = DHCP4_ROOT_PATH; + *OpPtr++ = DHCP4_EXTENSION_PATH; + *OpPtr++ = DHCP4_MAX_DATAGRAM_SIZE; + *OpPtr++ = DHCP4_DEFAULT_TTL; + *OpPtr++ = DHCP4_BROADCAST_ADDRESS; + *OpPtr++ = DHCP4_NIS_DOMAIN_NAME; + *OpPtr++ = DHCP4_NIS_SERVERS; + *OpPtr++ = DHCP4_NTP_SERVERS; + *OpPtr++ = DHCP4_VENDOR_SPECIFIC; + *OpPtr++ = DHCP4_REQUESTED_IP_ADDRESS; + *OpPtr++ = DHCP4_LEASE_TIME; + *OpPtr++ = DHCP4_SERVER_IDENTIFIER; + *OpPtr++ = DHCP4_RENEWAL_TIME; + *OpPtr++ = DHCP4_REBINDING_TIME; + *OpPtr++ = DHCP4_CLASS_IDENTIFIER; + *OpPtr++ = DHCP4_TFTP_SERVER_NAME; + *OpPtr++ = DHCP4_BOOTFILE; + *OpPtr++ = 128; + *OpPtr++ = 129; + *OpPtr++ = 130; + *OpPtr++ = 131; + *OpPtr++ = 132; + *OpPtr++ = 133; + *OpPtr++ = 134; + *OpPtr++ = 135; + *OpLen = (UINT8) ((OpPtr - OpLen) - 1); + + *OpPtr++ = DHCP4_END; + + This->Data->SetupCompleted = TRUE; + + return EFI_SUCCESS; +} + +/* eof - PxeDhcp4Setup.c */ diff --git a/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/build.xml b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/build.xml new file mode 100644 index 0000000000..e7afd62b68 --- /dev/null +++ b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/support.c b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/support.c new file mode 100644 index 0000000000..50c991372d --- /dev/null +++ b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/support.c @@ -0,0 +1,1126 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + support.c + +Abstract: + Miscellaneous support routines for PxeDhcp4 protocol. + +--*/ + + +#include "PxeDhcp4.h" + +#define DebugPrint(x) +// +// #define DebugPrint(x) Aprint x +// + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +UINT16 +htons ( + UINTN n + ) +{ + return (UINT16) ((n >> 8) | (n << 8)); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +UINT32 +htonl ( + UINTN n + ) +{ + return (UINT32) ((n >> 24) | ((n >> 8) & 0xFF00) | ((n & 0xFF00) << 8) | (n << 24)); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +VOID +EFIAPI +timeout_notify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + ASSERT (Context); + + if (Context != NULL) { + ((PXE_DHCP4_PRIVATE_DATA *) Context)->TimeoutOccurred = TRUE; + } +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +VOID +EFIAPI +periodic_notify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + ASSERT (Context); + + if (Context != NULL) { + ((PXE_DHCP4_PRIVATE_DATA *) Context)->PeriodicOccurred = TRUE; + } +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +EFI_STATUS +find_opt ( + IN DHCP4_PACKET *Packet, + IN UINT8 OpCode, + IN UINTN Skip, + OUT DHCP4_OP **OpPtr + ) +/*++ +Routine description: + Locate option inside DHCP packet. + +Parameters: + Packet := Pointer to DHCP packet structure. + OpCode := Option op-code to find. + Skip := Number of found op-codes to skip. + OpPtr := Pointer to found op-code pointer. + +Returns: + EFI_SUCCESS := Option was found + EFI_INVALID_PARAMETER := Packet == NULL || OpPtr == NULL + EFI_INVALID_PARAMETER := OpCode == DHCP4_PAD + EFI_INVALID_PARAMETER := OpCode == DHCP4_END && Skip != 0 + EFI_INVALID_PARAMETER := DHCP magik number in Packet is not valid + EFI_NOT_FOUND := op-code was not found in packet + EFI_INVALID_PARAMETER := If present, DHCP_MAX_MESSAGE_SIZE option + does not have a valid value. +--*/ +{ + UINTN msg_size; + UINTN buf_len; + UINTN n; + UINT8 *buf; + UINT8 *end_ptr; + UINT8 overload; + + // + // Verify parameters. + // + if (Packet == NULL || OpPtr == NULL || OpCode == DHCP4_PAD || (OpCode == DHCP4_END && Skip != 0)) { + return EFI_INVALID_PARAMETER; + } + + if (Packet->dhcp4.magik != htonl (DHCP4_MAGIK_NUMBER)) { + return EFI_INVALID_PARAMETER; + } + // + // Initialize search variables. + // + *OpPtr = NULL; + + msg_size = DHCP4_MAX_PACKET_SIZE - (DHCP4_UDP_HEADER_SIZE + DHCP4_IP_HEADER_SIZE); + + overload = 0; + end_ptr = NULL; + + buf = Packet->dhcp4.options; + buf_len = msg_size - (Packet->dhcp4.options - Packet->raw); + + // + // Start searching for requested option. + // + for (n = 0;;) { + // + // If match is found, decrement skip count and return + // when desired match is found. + // + if (buf[n] == OpCode) { + *OpPtr = (DHCP4_OP *) &buf[n]; + + if (Skip-- == 0) { + return EFI_SUCCESS; + } + } + // + // Skip past current option. Check for option overload + // and message size options since these will affect the + // amount of data to be searched. + // + switch (buf[n]) { + case DHCP4_PAD: + // + // Remember the first pad byte of a group. This + // could be the end of a badly formed packet. + // + if (end_ptr == NULL) { + end_ptr = &buf[n]; + } + + ++n; + break; + + case DHCP4_END: + // + // If we reach the end we are done. + // + end_ptr = NULL; + return EFI_NOT_FOUND; + + case DHCP4_OPTION_OVERLOAD: + // + // Remember the option overload value since it + // could cause the search to continue into + // the fname and sname fields. + // + end_ptr = NULL; + + if (buf[n + 1] == 1) { + overload = buf[n + 2]; + } + + n += 2 + buf[n + 1]; + break; + + case DHCP4_MAX_MESSAGE_SIZE: + // + // Remember the message size value since it could + // change the amount of option buffer to search. + // + end_ptr = NULL; + + if (buf[n + 1] == 2 && buf == Packet->dhcp4.options) { + msg_size = ((buf[n + 2] << 8) | buf[n + 3]) - (DHCP4_UDP_HEADER_SIZE + DHCP4_IP_HEADER_SIZE); + + if (msg_size < 328) { + return EFI_INVALID_PARAMETER; + } + + buf_len = msg_size - (Packet->dhcp4.options - Packet->raw); + + if (n + 2 + buf[n + 1] > buf_len) { + return EFI_INVALID_PARAMETER; + } + } + + /* fall thru */ + default: + end_ptr = NULL; + + n += 2 + buf[n + 1]; + } + // + // Keep searching until the end of the buffer is reached. + // + if (n < buf_len) { + continue; + } + // + // Reached end of current buffer. Check if we are supposed + // to search the fname and sname buffers. + // + if (buf == Packet->dhcp4.options && + (overload == DHCP4_OVERLOAD_FNAME || overload == DHCP4_OVERLOAD_FNAME_AND_SNAME) + ) { + buf = Packet->dhcp4.fname; + buf_len = 128; + n = 0; + continue; + } + + if (buf != Packet->dhcp4.sname && (overload == DHCP4_OVERLOAD_SNAME || overload == DHCP4_OVERLOAD_FNAME_AND_SNAME)) { + buf = Packet->dhcp4.sname; + buf_len = 64; + n = 0; + continue; + } + // + // End of last buffer reached. If this was a search + // for the end of the options, go back to the start + // of the current pad block. + // + if (OpCode == DHCP4_END && end_ptr != NULL) { + *OpPtr = (DHCP4_OP *) end_ptr; + return EFI_SUCCESS; + } + + return EFI_NOT_FOUND; + } +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +EFI_STATUS +add_opt ( + IN DHCP4_PACKET *Packet, + IN DHCP4_OP *OpPtr + ) +/*++ +Routine description: + Add option to DHCP packet. + +Parameters: + Packet := Pointer to DHCP packet structure. + OpPtr := Pointer to DHCP option. + +Returns: + EFI_INVALID_PARAMETER := Packet == NULL || OpPtr == NULL + EFI_INVALID_PARAMETER := OpPtr->op == DHCP4_PAD || OpPtr->op == DHCP4_END + EFI_INVALID_PARAMETER := DHCP magik number in DHCP packet is not valid + EFI_INVALID_PARAMETER := If DHCP_MAX_MESSAGE_SIZE option is present and + is not valid + EFI_INVALID_PARAMETER := If DHCP_OPTION_OVERLOAD option is present and + is not valid + EFI_DEVICE_ERROR := Cannot determine end of packet + EFI_BUFFER_TOO_SMALL := Not enough room in packet to add option + EFI_SUCCESS := Option added to DHCP packet +--*/ +{ + EFI_STATUS efi_status; + DHCP4_OP *msg_size_op; + DHCP4_OP *overload_op; + DHCP4_OP *op; + UINTN msg_size; + UINTN buf_len; + UINT32 magik; + UINT8 *buf; + + // + // Verify parameters. + // + ASSERT (Packet); + ASSERT (OpPtr); + + if (Packet == NULL || OpPtr == NULL) { + return EFI_INVALID_PARAMETER; + } + + switch (OpPtr->op) { + case DHCP4_PAD: + case DHCP4_END: + // + // No adding PAD or END. + // + return EFI_INVALID_PARAMETER; + } + // + // Check the DHCP magik number. + // + CopyMem (&magik, &Packet->dhcp4.magik, 4); + + if (magik != htonl (DHCP4_MAGIK_NUMBER)) { + return EFI_INVALID_PARAMETER; + } + // + // Find the DHCP message size option. + // + msg_size = DHCP4_DEFAULT_MAX_MESSAGE_SIZE; + + efi_status = find_opt ( + Packet, + DHCP4_MAX_MESSAGE_SIZE, + 0, + &msg_size_op + ); + + if (EFI_ERROR (efi_status)) { + if (efi_status != EFI_NOT_FOUND) { + DebugPrint ( + ("%s:%d:%r\n", + __FILE__, + __LINE__, + efi_status) + ); + return efi_status; + } + + msg_size_op = NULL; + } else { + CopyMem (&msg_size, msg_size_op->data, 2); + msg_size = htons (msg_size); + + if (msg_size < DHCP4_DEFAULT_MAX_MESSAGE_SIZE) { + return EFI_INVALID_PARAMETER; + } + } + // + // Find the DHCP option overload option. + // + efi_status = find_opt ( + Packet, + DHCP4_OPTION_OVERLOAD, + 0, + &overload_op + ); + + if (EFI_ERROR (efi_status)) { + if (efi_status != EFI_NOT_FOUND) { + DebugPrint ( + ("%s:%d:%r\n", + __FILE__, + __LINE__, + efi_status) + ); + return efi_status; + } + + overload_op = NULL; + } else { + if (overload_op->len != 1) { + return EFI_INVALID_PARAMETER; + } + + switch (overload_op->data[0]) { + case 1: + case 2: + case 3: + break; + + default: + return EFI_INVALID_PARAMETER; + } + } + // + // Find the end of the packet. + // + efi_status = find_opt (Packet, DHCP4_END, 0, &op); + + if (EFI_ERROR (efi_status)) { + return EFI_INVALID_PARAMETER; + } + // + // Find which buffer the end is in. + // + if ((UINTN) op >= (UINTN) (buf = Packet->dhcp4.options)) { + buf_len = (msg_size - ((UINT8 *) &Packet->dhcp4.options - (UINT8 *) &Packet->raw)) - (DHCP4_UDP_HEADER_SIZE + DHCP4_IP_HEADER_SIZE); + } else if ((UINTN) op >= (UINTN) (buf = Packet->dhcp4.fname)) { + buf_len = 128; + } else if ((UINTN) op >= (UINTN) (buf = Packet->dhcp4.sname)) { + buf_len = 64; + } else { + return EFI_DEVICE_ERROR; + } + // + // Add option to current buffer if there is no overlow. + // + if ((UINTN) ((&op->op - buf) + 3 + op->len) < buf_len) { + CopyMem (op, OpPtr, OpPtr->len + 2); + + op->data[op->len] = DHCP4_END; + + return EFI_SUCCESS; + } + // + // Error if there is no space for option. + // + return EFI_BUFFER_TOO_SMALL; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +EFI_STATUS +start_udp ( + IN PXE_DHCP4_PRIVATE_DATA *Private, + IN OPTIONAL EFI_IP_ADDRESS *StationIp, + IN OPTIONAL EFI_IP_ADDRESS *SubnetMask + ) +/*++ +Routine description: + Setup PXE BaseCode UDP stack. + +Parameters: + Private := Pointer to PxeDhcp4 private data. + StationIp := Pointer to IP address or NULL if not known. + SubnetMask := Pointer to subnet mask or NULL if not known. + +Returns: + EFI_INVALID_PARAMETER := Private == NULL || Private->PxeBc == NULL + EFI_INVALID_PARAMETER := Only one of StationIp and SubnetMask is given + EFI_SUCCESS := UDP stack is ready + other := Error from PxeBc->SetIpFilter() or PxeBc->SetStationIp() +--*/ +{ + EFI_PXE_BASE_CODE_IP_FILTER bcast_filter; + EFI_STATUS efi_status; + + // + // + // + ASSERT (Private); + ASSERT (Private->PxeBc); + + if (Private == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Private->PxeBc == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (StationIp != NULL && SubnetMask == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (StationIp == NULL && SubnetMask != NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Setup broadcast receive filter... + // + ZeroMem (&bcast_filter, sizeof (EFI_PXE_BASE_CODE_IP_FILTER)); + + bcast_filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST; + bcast_filter.IpCnt = 0; + + efi_status = Private->PxeBc->SetIpFilter ( + Private->PxeBc, + &bcast_filter + ); + + if (EFI_ERROR (efi_status)) { + DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status)); + return efi_status; + } + // + // Configure station IP address and subnet mask... + // + efi_status = Private->PxeBc->SetStationIp ( + Private->PxeBc, + StationIp, + SubnetMask + ); + + if (EFI_ERROR (efi_status)) { + DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status)); + } + + return efi_status; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +VOID +stop_udp ( + IN PXE_DHCP4_PRIVATE_DATA *Private + ) +{ + // + // + // + ASSERT (Private); + ASSERT (Private->PxeBc); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +EFI_STATUS +start_receive_events ( + IN PXE_DHCP4_PRIVATE_DATA *Private, + IN UINTN SecondsTimeout + ) +/*++ +Routine description: + Create periodic and timeout receive events. + +Parameters: + Private := Pointer to PxeDhcp4 private data. + SecondsTimeout := Number of seconds to wait before timeout. + +Returns: +--*/ +{ + EFI_STATUS efi_status; + UINTN random; + + // + // + // + ASSERT (Private); + ASSERT (SecondsTimeout); + + if (Private == NULL || SecondsTimeout == 0) { + return EFI_INVALID_PARAMETER; + } + // + // Need a bettern randomizer... + // For now adjust the timeout value by the least significant + // digit in the MAC address. + // + random = 0; + + if (Private->PxeDhcp4.Data != NULL) { + if (Private->PxeDhcp4.Data->Discover.dhcp4.hlen != 0 && Private->PxeDhcp4.Data->Discover.dhcp4.hlen <= 16) { + random = 0xFFF & Private->PxeDhcp4.Data->Discover.dhcp4.chaddr[Private->PxeDhcp4.Data->Discover.dhcp4.hlen - 1]; + } + } + // + // Setup timeout event and start timer. + // + efi_status = gBS->CreateEvent ( + EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL, + EFI_TPL_NOTIFY, + &timeout_notify, + Private, + &Private->TimeoutEvent + ); + + if (EFI_ERROR (efi_status)) { + DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status)); + return efi_status; + } + + efi_status = gBS->SetTimer ( + Private->TimeoutEvent, + TimerRelative, + SecondsTimeout * 10000000 + random + ); + + if (EFI_ERROR (efi_status)) { + DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status)); + gBS->CloseEvent (Private->TimeoutEvent); + return efi_status; + } + + Private->TimeoutOccurred = FALSE; + + // + // Setup periodic event for callbacks + // + efi_status = gBS->CreateEvent ( + EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL, + EFI_TPL_NOTIFY, + &periodic_notify, + Private, + &Private->PeriodicEvent + ); + + if (EFI_ERROR (efi_status)) { + DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status)); + gBS->CloseEvent (Private->TimeoutEvent); + return efi_status; + } + + efi_status = gBS->SetTimer ( + Private->PeriodicEvent, + TimerPeriodic, + 1000000 + ); /* 1/10th second */ + + if (EFI_ERROR (efi_status)) { + DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status)); + gBS->CloseEvent (Private->TimeoutEvent); + gBS->CloseEvent (Private->PeriodicEvent); + return efi_status; + } + + Private->PeriodicOccurred = FALSE; + + return EFI_SUCCESS; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +VOID +stop_receive_events ( + IN PXE_DHCP4_PRIVATE_DATA *Private + ) +{ + // + // + // + ASSERT (Private); + + if (Private == NULL) { + return ; + } + // + // + // + gBS->CloseEvent (Private->TimeoutEvent); + Private->TimeoutOccurred = FALSE; + + // + // + // + gBS->CloseEvent (Private->PeriodicEvent); + Private->PeriodicOccurred = FALSE; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +EFI_STATUS +tx_udp ( + IN PXE_DHCP4_PRIVATE_DATA *Private, + IN EFI_IP_ADDRESS *dest_ip, + IN OPTIONAL EFI_IP_ADDRESS *gateway_ip, + IN EFI_IP_ADDRESS *src_ip, + IN VOID *buffer, + IN UINTN BufferSize + ) +/*++ +Routine description: + Transmit DHCP packet. + +Parameters: + Private := Pointer to PxeDhcp4 private data + dest_ip := Pointer to destination IP address + gateway_ip := Pointer to gateway IP address or NULL + src_ip := Pointer to source IP address or NULL + buffer := Pointer to buffer to transmit + BufferSize := Size of buffer in bytes + +Returns: + EFI_INVALID_PARAMETER := Private == NULL || dest_ip == NULL || + buffer == NULL || BufferSize < 300 || Private->PxeBc == NULL + EFI_SUCCESS := Buffer was transmitted + other := Return from PxeBc->UdpWrite() +--*/ +{ + EFI_PXE_BASE_CODE_UDP_PORT dest_port; + EFI_PXE_BASE_CODE_UDP_PORT src_port; + EFI_IP_ADDRESS zero_ip; + + // + // + // + ASSERT (Private); + ASSERT (dest_ip); + ASSERT (buffer); + ASSERT (BufferSize >= 300); + + if (Private == NULL || dest_ip == NULL || buffer == NULL || BufferSize < 300) { + return EFI_INVALID_PARAMETER; + } + + ASSERT (Private->PxeBc); + + if (Private->PxeBc == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Transmit DHCP discover packet... + // + ZeroMem (&zero_ip, sizeof (EFI_IP_ADDRESS)); + + if (src_ip == NULL) { + src_ip = &zero_ip; + } + + dest_port = DHCP4_SERVER_PORT; + src_port = DHCP4_CLIENT_PORT; + + return Private->PxeBc->UdpWrite ( + Private->PxeBc, + EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT, + dest_ip, + &dest_port, + gateway_ip, + src_ip, + &src_port, + NULL, + NULL, + &BufferSize, + buffer + ); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +EFI_STATUS +rx_udp ( + IN PXE_DHCP4_PRIVATE_DATA *Private, + OUT VOID *buffer, + IN OUT UINTN *BufferSize, + IN OUT EFI_IP_ADDRESS *dest_ip, + IN OUT EFI_IP_ADDRESS *src_ip, + IN UINT16 op_flags + ) +/*++ +Routine description: + Receive DHCP packet. + +Parameters: + Private := Pointer to PxeDhcp4 private data + buffer := Pointer to buffer to receive DHCP packet + BufferSize := Pointer to buffer size in bytes + dest_ip := Pointer to destination IP address + src_ip := Pointer to source IP address + op_flags := UDP receive operation flags + +Returns: + EFI_INVALID_PARAMETER := + EFI_SUCCESS := Packet received + other := Return from PxeBc->UdpRead() +--*/ +{ + EFI_PXE_BASE_CODE_UDP_PORT dest_port; + EFI_PXE_BASE_CODE_UDP_PORT src_port; + + // + // + // + ASSERT (Private); + ASSERT (buffer); + ASSERT (dest_ip); + ASSERT (src_ip); + + if (Private == NULL || buffer == NULL || dest_ip == NULL || src_ip == NULL || BufferSize == NULL) { + return EFI_INVALID_PARAMETER; + } + + ASSERT (Private->PxeBc); + + if (Private->PxeBc == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Check for packet + // + *BufferSize = sizeof (DHCP4_PACKET); + + dest_port = DHCP4_CLIENT_PORT; + src_port = DHCP4_SERVER_PORT; + + return Private->PxeBc->UdpRead ( + Private->PxeBc, + op_flags, + dest_ip, + &dest_port, + src_ip, + &src_port, + NULL, + NULL, + BufferSize, + buffer + ); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +EFI_STATUS +tx_rx_udp ( + IN PXE_DHCP4_PRIVATE_DATA *Private, + IN OUT EFI_IP_ADDRESS *ServerIp, + IN OPTIONAL EFI_IP_ADDRESS *gateway_ip, + IN OPTIONAL EFI_IP_ADDRESS *client_ip, + IN OPTIONAL EFI_IP_ADDRESS *SubnetMask, + IN DHCP4_PACKET *tx_pkt, + OUT DHCP4_PACKET *rx_pkt, + IN INTN (*rx_vfy)( + IN PXE_DHCP4_PRIVATE_DATA *Private, + IN DHCP4_PACKET *tx_pkt, + IN DHCP4_PACKET *rx_pkt, + IN UINTN rx_pkt_size + ), + IN UINTN SecondsTimeout + ) +/*++ +Routine description: + Transmit DHCP packet and wait for replies. + +Parameters: + Private := Pointer to PxeDhcp4 private data + ServerIp := Pointer to server IP address + gateway_ip := Pointer to gateway IP address or NULL + client_ip := Pointer to client IP address or NULL + SubnetMask := Pointer to subnet mask or NULL + tx_pkt := Pointer to DHCP packet to transmit + rx_pkt := Pointer to DHCP packet receive buffer + rx_vfy := Pointer to DHCP packet receive verification routine + SecondsTimeout := Number of seconds until timeout + +Returns: + EFI_INVALID_PARAMETER := Private == NULL || ServerIp == NULL || + tx_pkt == NULL || rx_pkt == NULL || rx_vfy == NULL || Private->PxeBc == NULL + EFI_ABORTED := Receive aborted + EFI_TIMEOUT := No packets received + EFI_SUCCESS := Packet(s) received + other := Returns from other PxeDhcp4 support routines +--*/ +{ + EFI_PXE_DHCP4_CALLBACK_STATUS CallbackStatus; + EFI_IP_ADDRESS dest_ip; + EFI_IP_ADDRESS src_ip; + EFI_STATUS efi_status; + DHCP4_OP *msg_size_op; + UINTN pkt_size; + UINTN n; + UINT16 msg_size; + UINT16 op_flags; + BOOLEAN done_flag; + BOOLEAN got_packet; + + // + // Bad programmer check... + // + ASSERT (Private); + ASSERT (ServerIp); + ASSERT (tx_pkt); + ASSERT (rx_pkt); + ASSERT (rx_vfy); + + if (Private == NULL || ServerIp == NULL || tx_pkt == NULL || rx_pkt == NULL || rx_vfy == NULL) { + return EFI_INVALID_PARAMETER; + } + + ASSERT (Private->PxeBc); + + if (Private->PxeBc == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Enable UDP... + // + efi_status = start_udp (Private, client_ip, SubnetMask); + + if (EFI_ERROR (efi_status)) { + DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status)); + return efi_status; + } + // + // Get length of transmit packet... + // + msg_size = DHCP4_DEFAULT_MAX_MESSAGE_SIZE; + + efi_status = find_opt ( + tx_pkt, + DHCP4_MAX_MESSAGE_SIZE, + 0, + &msg_size_op + ); + + if (!EFI_ERROR (efi_status)) { + CopyMem (&msg_size, msg_size_op->data, 2); + + if ((msg_size = htons (msg_size)) < 328) { + msg_size = 328; + } + } + // + // Transmit packet... + // + efi_status = tx_udp ( + Private, + ServerIp, + gateway_ip, + client_ip, + tx_pkt, + msg_size - (DHCP4_UDP_HEADER_SIZE + DHCP4_IP_HEADER_SIZE) + ); + + if (EFI_ERROR (efi_status)) { + DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status)); + stop_udp (Private); + return efi_status; + } + // + // Enable periodic and timeout events... + // + efi_status = start_receive_events (Private, SecondsTimeout); + + if (EFI_ERROR (efi_status)) { + DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status)); + stop_udp (Private); + return efi_status; + } + // + // Wait for packet(s)... + // +#if 0 + if (!client_ip) { + Aprint ("client_ip == NULL "); + } else { + Aprint ( + "client_ip == %d.%d.%d.%d ", + client_ip->v4.Addr[0], + client_ip->v4.Addr[1], + client_ip->v4.Addr[2], + client_ip->v4.Addr[3] + ); + } + + if (!ServerIp) { + Aprint ("ServerIp == NULL\n"); + } else { + Aprint ( + "ServerIp == %d.%d.%d.%d\n", + ServerIp->v4.Addr[0], + ServerIp->v4.Addr[1], + ServerIp->v4.Addr[2], + ServerIp->v4.Addr[3] + ); + } +#endif + + done_flag = FALSE; + got_packet = FALSE; + + while (!done_flag) { + // + // Check for timeout event... + // + if (Private->TimeoutOccurred) { + efi_status = EFI_SUCCESS; + break; + } + // + // Check for periodic event... + // + if (Private->PeriodicOccurred && Private->callback != NULL) { + CallbackStatus = EFI_PXE_DHCP4_CALLBACK_STATUS_CONTINUE; + + if (Private->callback->Callback != NULL) { + CallbackStatus = (Private->callback->Callback) (&Private->PxeDhcp4, Private->function, 0, NULL); + } + + switch (CallbackStatus) { + case EFI_PXE_DHCP4_CALLBACK_STATUS_CONTINUE: + break; + + case EFI_PXE_DHCP4_CALLBACK_STATUS_ABORT: + default: + stop_receive_events (Private); + stop_udp (Private); + return EFI_ABORTED; + } + + Private->PeriodicOccurred = FALSE; + } + // + // Check for packet... + // + if (client_ip == NULL) { + SetMem (&dest_ip, sizeof (EFI_IP_ADDRESS), 0xFF); + } else { + CopyMem (&dest_ip, client_ip, sizeof (EFI_IP_ADDRESS)); + } + + SetMem (&src_ip, sizeof (EFI_IP_ADDRESS), 0xFF); + + if (CompareMem (&src_ip, &ServerIp, sizeof (EFI_IP_ADDRESS))) { + ZeroMem (&src_ip, sizeof (EFI_IP_ADDRESS)); + op_flags = EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP; + } else { + op_flags = 0; + } + + efi_status = rx_udp ( + Private, + rx_pkt, + &pkt_size, + &dest_ip, + &src_ip, + op_flags + ); + + if (efi_status == EFI_TIMEOUT) { + efi_status = EFI_SUCCESS; + continue; + } + + if (EFI_ERROR (efi_status)) { + break; + } + // + // Some basic packet sanity checks.. + // + if (pkt_size < 300) { + continue; + } + + if (rx_pkt->dhcp4.op != BOOTP_REPLY) { + continue; + } + + if (tx_pkt->dhcp4.htype != rx_pkt->dhcp4.htype) { + continue; + } + + if ((n = tx_pkt->dhcp4.hlen) != rx_pkt->dhcp4.hlen) { + continue; + } + + if (CompareMem (&tx_pkt->dhcp4.xid, &rx_pkt->dhcp4.xid, 4)) { + continue; + } + + if (n != 0) { + if (n >= 16) { + n = 16; + } + + if (CompareMem (tx_pkt->dhcp4.chaddr, rx_pkt->dhcp4.chaddr, n)) { + continue; + } + } + // + // Internal callback packet verification... + // + switch ((*rx_vfy) (Private, tx_pkt, rx_pkt, pkt_size)) { + case -2: /* ignore and stop */ + stop_receive_events (Private); + stop_udp (Private); + return EFI_ABORTED; + + case -1: /* ignore and wait */ + continue; + + case 0: /* accept and wait */ + break; + + case 1: /* accept and stop */ + done_flag = TRUE; + break; + + default: + ASSERT (0); + } + // + // External callback packet verification... + // + CallbackStatus = EFI_PXE_DHCP4_CALLBACK_STATUS_KEEP_CONTINUE; + + if (Private->callback != NULL) { + if (Private->callback->Callback != NULL) { + CallbackStatus = (Private->callback->Callback) (&Private->PxeDhcp4, Private->function, (UINT32) pkt_size, rx_pkt); + } + } + + switch (CallbackStatus) { + case EFI_PXE_DHCP4_CALLBACK_STATUS_IGNORE_CONTINUE: + continue; + + case EFI_PXE_DHCP4_CALLBACK_STATUS_KEEP_ABORT: + done_flag = TRUE; + break; + + case EFI_PXE_DHCP4_CALLBACK_STATUS_IGNORE_ABORT: + stop_receive_events (Private); + stop_udp (Private); + return EFI_ABORTED; + + case EFI_PXE_DHCP4_CALLBACK_STATUS_KEEP_CONTINUE: + default: + break; + } + // + // We did! We did get a packet! + // + got_packet = TRUE; + } + // + // + // + stop_receive_events (Private); + stop_udp (Private); + + if (EFI_ERROR (efi_status)) { + DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status)); + return efi_status; + } + + if (got_packet) { + return EFI_SUCCESS; + } else { + return EFI_TIMEOUT; + } +} + +/* eof - support.c */ diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/ComponentName.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/ComponentName.c new file mode 100644 index 0000000000..3cc2d98440 --- /dev/null +++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/ComponentName.c @@ -0,0 +1,160 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ComponentName.c + +Abstract: + +--*/ + +#include "Snp.h" + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +SimpleNetworkComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +EFI_STATUS +EFIAPI +SimpleNetworkComponentNameGetControllerName ( + 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 +// +EFI_COMPONENT_NAME_PROTOCOL gSimpleNetworkComponentName = { + SimpleNetworkComponentNameGetDriverName, + SimpleNetworkComponentNameGetControllerName, + "eng" +}; + +static EFI_UNICODE_STRING_TABLE mSimpleNetworkDriverNameTable[] = { + { + "eng", + (CHAR16 *) L"Simple Network Protocol Driver" + }, + { + NULL, + NULL + } +}; + +EFI_STATUS +EFIAPI +SimpleNetworkComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gSimpleNetworkComponentName.SupportedLanguages, + mSimpleNetworkDriverNameTable, + DriverName + ); +} + +EFI_STATUS +EFIAPI +SimpleNetworkComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + 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. + 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. + + Returns: + 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. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return EFI_UNSUPPORTED; +} diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/SNP.mbd b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/SNP.mbd new file mode 100644 index 0000000000..293812b304 --- /dev/null +++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/SNP.mbd @@ -0,0 +1,41 @@ + + + + + SNP + A2f436EA-A127-4EF8-957C-8048606FF670 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + + UefiBootServicesTableLib + BaseMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + BaseLib + DxeMemoryAllocationLib + + diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/SNP.msa b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/SNP.msa new file mode 100644 index 0000000000..c8ce3d78dd --- /dev/null +++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/SNP.msa @@ -0,0 +1,85 @@ + + + + + SNP + UEFI_DRIVER + BS_DRIVER + A2f436EA-A127-4EF8-957C-8048606FF670 + 0 + Component description file for DiskIo module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + UefiLib + BaseLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + + + callback.c + get_status.c + initialize.c + mcast_ip_to_mac.c + nvdata.c + receive.c + receive_filters.c + reset.c + shutdown.c + snp.c + snp.h + start.c + station_address.c + statistics.c + stop.c + transmit.c + WaitForPacket.c + ComponentName.c + + + MdePkg + EdkModulePkg + + + SimpleNetwork + PciIo + DevicePath + NetworkInterfaceIdentifier + NetworkInterfaceIdentifier2 + + + + + + + + mSimpleNetworkDriverBinding + gSimpleNetworkComponentName + + + diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/WaitForPacket.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/WaitForPacket.c new file mode 100644 index 0000000000..dff0da1a63 --- /dev/null +++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/WaitForPacket.c @@ -0,0 +1,100 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module name: + WaitForPacket.c + +Abstract: + Event handler to check for available packet. + +--*/ + + +#include "snp.h" + +VOID +EFIAPI +SnpWaitForPacketNotify ( + EFI_EVENT Event, + VOID *SnpPtr + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + PXE_DB_GET_STATUS PxeDbGetStatus; + + // + // Do nothing if either parameter is a NULL pointer. + // + if (Event == NULL || SnpPtr == NULL) { + return ; + } + // + // Do nothing if the SNP interface is not initialized. + // + switch (((SNP_DRIVER *) SnpPtr)->mode.State) { + case EfiSimpleNetworkInitialized: + break; + + case EfiSimpleNetworkStopped: + case EfiSimpleNetworkStarted: + default: + return ; + } + // + // Fill in CDB for UNDI GetStatus(). + // + ((SNP_DRIVER *) SnpPtr)->cdb.OpCode = PXE_OPCODE_GET_STATUS; + ((SNP_DRIVER *) SnpPtr)->cdb.OpFlags = 0; + ((SNP_DRIVER *) SnpPtr)->cdb.CPBsize = PXE_CPBSIZE_NOT_USED; + ((SNP_DRIVER *) SnpPtr)->cdb.CPBaddr = PXE_CPBADDR_NOT_USED; + ((SNP_DRIVER *) SnpPtr)->cdb.DBsize = sizeof (UINT32) * 2; + ((SNP_DRIVER *) SnpPtr)->cdb.DBaddr = (UINT64) (UINTN) (((SNP_DRIVER *) SnpPtr)->db); + ((SNP_DRIVER *) SnpPtr)->cdb.StatCode = PXE_STATCODE_INITIALIZE; + ((SNP_DRIVER *) SnpPtr)->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE; + ((SNP_DRIVER *) SnpPtr)->cdb.IFnum = ((SNP_DRIVER *) SnpPtr)->if_num; + ((SNP_DRIVER *) SnpPtr)->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST; + + // + // Clear contents of DB buffer. + // + ZeroMem (((SNP_DRIVER *) SnpPtr)->db, sizeof (UINT32) * 2); + + // + // Issue UNDI command and check result. + // + (*((SNP_DRIVER *) SnpPtr)->issue_undi32_command) ((UINT64) (UINTN) &((SNP_DRIVER *) SnpPtr)->cdb); + + if (((SNP_DRIVER *) SnpPtr)->cdb.StatCode != EFI_SUCCESS) { + return ; + } + // + // We might have a packet. Check the receive length and signal + // the event if the length is not zero. + // + CopyMem ( + &PxeDbGetStatus, + ((SNP_DRIVER *) SnpPtr)->db, + sizeof (UINT32) * 2 + ); + + if (PxeDbGetStatus.RxFrameLen != 0) { + gBS->SignalEvent (Event); + } +} + +/* eof - WaitForPacket.c */ diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/build.xml b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/build.xml new file mode 100644 index 0000000000..7387603fb3 --- /dev/null +++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/callback.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/callback.c new file mode 100644 index 0000000000..488efc6a01 --- /dev/null +++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/callback.c @@ -0,0 +1,613 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module name: + callback.c + +Abstract: + This file contains two sets of callback routines for undi3.0 and undi3.1. + the callback routines for Undi3.1 have an extra parameter UniqueId which + stores the interface context for the NIC that snp is trying to talk.. + +--*/ + + +#include "snp.h" + +// +// Global variables +// these 2 global variables are used only for 3.0 undi. we could not place +// them in the snp structure because we will not know which snp structure +// in the callback context! +// +STATIC BOOLEAN mInitializeLock = TRUE; +STATIC EFI_LOCK mLock; + +// +// End Global variables +// +extern EFI_PCI_IO_PROTOCOL *mPciIoFncs; + +VOID +snp_undi32_callback_v2p_30 ( + IN UINT64 CpuAddr, + IN OUT UINT64 DeviceAddrPtr + ) +/*++ + +Routine Description: + This is a callback routine supplied to UNDI at undi_start time. + UNDI call this routine with a virtual or CPU address that SNP provided + to convert it to a physical or device address. Since EFI uses the identical + mapping, this routine returns the physical address same as the virtual address + for most of the addresses. an address above 4GB cannot generally be used as a + device address, it needs to be mapped to a lower physical address. This routine + does not call the map routine itself, but it assumes that the mapping was done + at the time of providing the address to UNDI. This routine just looks up the + address in a map table (which is the v2p structure chain) + +Arguments: + CpuAddr - virtual address of a buffer + DeviceAddrPtr - pointer to the physical address + +Returns: + void - The DeviceAddrPtr will contain 0 in case of any error + +--*/ +{ + struct s_v2p *v2p; + // + // Do nothing if virtual address is zero or physical pointer is NULL. + // No need to map if the virtual address is within 4GB limit since + // EFI uses identical mapping + // + if ((CpuAddr == 0) || (DeviceAddrPtr == 0)) { + DEBUG ((EFI_D_ERROR, "\nv2p: Null virtual address or physical pointer.\n")); + return ; + } + + if (CpuAddr < FOUR_GIGABYTES) { + *(UINT64 *) (UINTN) DeviceAddrPtr = CpuAddr; + return ; + } + // + // SNP creates a vaddr tp paddr mapping at the time of calling undi with any + // big address, this callback routine just looks up in the v2p list and + // returns the physical address for any given virtual address. + // + if (find_v2p (&v2p, (VOID *) (UINTN) CpuAddr) != EFI_SUCCESS) { + *(UINT64 *) (UINTN) DeviceAddrPtr = CpuAddr; + } else { + *(UINT64 *) (UINTN) DeviceAddrPtr = v2p->paddr; + } +} + +VOID +snp_undi32_callback_block_30 ( + IN UINT32 Enable + ) +/*++ + +Routine Description: + This is a callback routine supplied to UNDI at undi_start time. + UNDI call this routine when it wants to have exclusive access to a critical + section of the code/data + +Arguments: + Enable - non-zero indicates acquire + zero indicates release + +Returns: + void +--*/ +{ + // + // tcpip was calling snp at tpl_notify and if we acquire a lock that was + // created at a lower level (TPL_CALLBACK) it gives an assert! + // + if (mInitializeLock) { + EfiInitializeLock (&mLock, EFI_TPL_NOTIFY); + mInitializeLock = FALSE; + } + + if (Enable != 0) { + EfiAcquireLock (&mLock); + } else { + EfiReleaseLock (&mLock); + } +} + +VOID +snp_undi32_callback_delay_30 ( + IN UINT64 MicroSeconds + ) +/*++ + +Routine Description: + This is a callback routine supplied to UNDI at undi_start time. + UNDI call this routine with the number of micro seconds when it wants to + pause. + +Arguments: + MicroSeconds - number of micro seconds to pause, ususlly multiple of 10 + +Returns: + void +--*/ +{ + if (MicroSeconds != 0) { + gBS->Stall ((UINTN) MicroSeconds); + } +} + +VOID +snp_undi32_callback_memio_30 ( + IN UINT8 ReadOrWrite, + IN UINT8 NumBytes, + IN UINT64 Address, + IN OUT UINT64 BufferAddr + ) +/*++ + +Routine Description: + This is a callback routine supplied to UNDI at undi_start time. + This is the IO routine for UNDI. This is not currently being used by UNDI3.0 + because Undi3.0 uses io/mem offsets relative to the beginning of the device + io/mem address and so it needs to use the PCI_IO_FUNCTION that abstracts the + start of the device's io/mem addresses. Since SNP cannot retrive the context + of the undi3.0 interface it cannot use the PCI_IO_FUNCTION that specific for + that NIC and uses one global IO functions structure, this does not work. + This however works fine for EFI1.0 Undis because they use absolute addresses + for io/mem access. + +Arguments: + ReadOrWrite - indicates read or write, IO or Memory + NumBytes - number of bytes to read or write + Address - IO or memory address to read from or write to + BufferAddr - memory location to read into or that contains the bytes + to write + +Returns: + +--*/ +{ + EFI_PCI_IO_PROTOCOL_WIDTH Width; + + switch (NumBytes) { + case 2: + Width = 1; + break; + + case 4: + Width = 2; + break; + + case 8: + Width = 3; + break; + + default: + Width = 0; + } + + switch (ReadOrWrite) { + case PXE_IO_READ: + mPciIoFncs->Io.Read ( + mPciIoFncs, + Width, + 1, // BAR 1, IO base address + Address, + 1, // count + (VOID *) (UINTN) BufferAddr + ); + break; + + case PXE_IO_WRITE: + mPciIoFncs->Io.Write ( + mPciIoFncs, + Width, + 1, // BAR 1, IO base address + Address, + 1, // count + (VOID *) (UINTN) BufferAddr + ); + break; + + case PXE_MEM_READ: + mPciIoFncs->Mem.Read ( + mPciIoFncs, + Width, + 0, // BAR 0, Memory base address + Address, + 1, // count + (VOID *) (UINTN) BufferAddr + ); + break; + + case PXE_MEM_WRITE: + mPciIoFncs->Mem.Write ( + mPciIoFncs, + Width, + 0, // BAR 0, Memory base address + Address, + 1, // count + (VOID *) (UINTN) BufferAddr + ); + break; + } + + return ; +} +// +// New callbacks for 3.1: +// there won't be a virtual2physical callback for UNDI 3.1 because undi3.1 uses +// the MemMap call to map the required address by itself! +// +VOID +snp_undi32_callback_block ( + IN UINT64 UniqueId, + IN UINT32 Enable + ) +/*++ + +Routine Description: + This is a callback routine supplied to UNDI3.1 at undi_start time. + UNDI call this routine when it wants to have exclusive access to a critical + section of the code/data + +Arguments: + UniqueId - This was supplied to UNDI at Undi_Start, SNP uses this to store + Undi interface context (Undi does not read or write this variable) + Enable - non-zero indicates acquire + zero indicates release + +Returns: + void + +--*/ +{ + SNP_DRIVER *snp; + + snp = (SNP_DRIVER *) (UINTN) UniqueId; + // + // tcpip was calling snp at tpl_notify and when we acquire a lock that was + // created at a lower level (TPL_CALLBACK) it gives an assert! + // + if (Enable != 0) { + EfiAcquireLock (&snp->lock); + } else { + EfiReleaseLock (&snp->lock); + } +} + +VOID +snp_undi32_callback_delay ( + IN UINT64 UniqueId, + IN UINT64 MicroSeconds + ) +/*++ + +Routine Description: + This is a callback routine supplied to UNDI at undi_start time. + UNDI call this routine with the number of micro seconds when it wants to + pause. + +Arguments: + MicroSeconds - number of micro seconds to pause, ususlly multiple of 10 + +Returns: + void +--*/ +{ + if (MicroSeconds != 0) { + gBS->Stall ((UINTN) MicroSeconds); + } +} + +/* + * IO routine for UNDI start CPB. + */ +VOID +snp_undi32_callback_memio ( + UINT64 UniqueId, + UINT8 ReadOrWrite, + UINT8 NumBytes, + UINT64 Address, + UINT64 BufferAddr + ) +/*++ + +Routine Description: + This is a callback routine supplied to UNDI at undi_start time. + This is the IO routine for UNDI3.1. + +Arguments: + ReadOrWrite - indicates read or write, IO or Memory + NumBytes - number of bytes to read or write + Address - IO or memory address to read from or write to + BufferAddr - memory location to read into or that contains the bytes + to write + +Returns: + +--*/ +{ + SNP_DRIVER *snp; + EFI_PCI_IO_PROTOCOL_WIDTH Width; + + snp = (SNP_DRIVER *) (UINTN) UniqueId; + + Width = 0; + switch (NumBytes) { + case 2: + Width = 1; + break; + + case 4: + Width = 2; + break; + + case 8: + Width = 3; + break; + } + + switch (ReadOrWrite) { + case PXE_IO_READ: + snp->IoFncs->Io.Read ( + snp->IoFncs, + Width, + snp->IoBarIndex, // BAR 1 (for 32bit regs), IO base address + Address, + 1, // count + (VOID *) (UINTN) BufferAddr + ); + break; + + case PXE_IO_WRITE: + snp->IoFncs->Io.Write ( + snp->IoFncs, + Width, + snp->IoBarIndex, // BAR 1 (for 32bit regs), IO base address + Address, + 1, // count + (VOID *) (UINTN) BufferAddr + ); + break; + + case PXE_MEM_READ: + snp->IoFncs->Mem.Read ( + snp->IoFncs, + Width, + snp->MemoryBarIndex, // BAR 0, Memory base address + Address, + 1, // count + (VOID *) (UINTN) BufferAddr + ); + break; + + case PXE_MEM_WRITE: + snp->IoFncs->Mem.Write ( + snp->IoFncs, + Width, + snp->MemoryBarIndex, // BAR 0, Memory base address + Address, + 1, // count + (VOID *) (UINTN) BufferAddr + ); + break; + } + + return ; +} + +VOID +snp_undi32_callback_map ( + IN UINT64 UniqueId, + IN UINT64 CpuAddr, + IN UINT32 NumBytes, + IN UINT32 Direction, + IN OUT UINT64 DeviceAddrPtr + ) +/*++ + +Routine Description: + This is a callback routine supplied to UNDI at undi_start time. + UNDI call this routine when it has to map a CPU address to a device + address. + +Arguments: + UniqueId - This was supplied to UNDI at Undi_Start, SNP uses this to store + Undi interface context (Undi does not read or write this variable) + CpuAddr - Virtual address to be mapped! + NumBytes - size of memory to be mapped + Direction - direction of data flow for this memory's usage: + cpu->device, device->cpu or both ways + DeviceAddrPtr - pointer to return the mapped device address + +Returns: + None + +--*/ +{ + EFI_PHYSICAL_ADDRESS *DevAddrPtr; + EFI_PCI_IO_PROTOCOL_OPERATION DirectionFlag; + UINTN BuffSize; + SNP_DRIVER *snp; + UINTN Index; + EFI_STATUS Status; + + BuffSize = (UINTN) NumBytes; + snp = (SNP_DRIVER *) (UINTN) UniqueId; + DevAddrPtr = (EFI_PHYSICAL_ADDRESS *) (UINTN) DeviceAddrPtr; + + if (CpuAddr == 0) { + *DevAddrPtr = 0; + return ; + } + + switch (Direction) { + case TO_AND_FROM_DEVICE: + DirectionFlag = EfiPciIoOperationBusMasterCommonBuffer; + break; + + case FROM_DEVICE: + DirectionFlag = EfiPciIoOperationBusMasterWrite; + break; + + case TO_DEVICE: + DirectionFlag = EfiPciIoOperationBusMasterRead; + break; + + default: + *DevAddrPtr = 0; + // + // any non zero indicates error! + // + return ; + } + // + // find an unused map_list entry + // + for (Index = 0; Index < MAX_MAP_LENGTH; Index++) { + if (snp->map_list[Index].virt == 0) { + break; + } + } + + if (Index >= MAX_MAP_LENGTH) { + SNP_PRINT (L"SNP maplist is FULL\n"); + *DevAddrPtr = 0; + return ; + } + + snp->map_list[Index].virt = (EFI_PHYSICAL_ADDRESS) CpuAddr; + + Status = snp->IoFncs->Map ( + snp->IoFncs, + DirectionFlag, + (VOID *) (UINTN) CpuAddr, + &BuffSize, + DevAddrPtr, + &(snp->map_list[Index].map_cookie) + ); + if (Status != EFI_SUCCESS) { + *DevAddrPtr = 0; + snp->map_list[Index].virt = 0; + } + + return ; +} + +VOID +snp_undi32_callback_unmap ( + IN UINT64 UniqueId, + IN UINT64 CpuAddr, + IN UINT32 NumBytes, + IN UINT32 Direction, + IN UINT64 DeviceAddr + ) +/*++ + +Routine Description: + This is a callback routine supplied to UNDI at undi_start time. + UNDI call this routine when it wants to unmap an address that was previously + mapped using map callback + +Arguments: + UniqueId - This was supplied to UNDI at Undi_Start, SNP uses this to store + Undi interface context (Undi does not read or write this variable) + CpuAddr - Virtual address that was mapped! + NumBytes - size of memory mapped + Direction- direction of data flow for this memory's usage: + cpu->device, device->cpu or both ways + DeviceAddr - the mapped device address + +Returns: + +--*/ +{ + SNP_DRIVER *snp; + UINT16 Index; + + snp = (SNP_DRIVER *) (UINTN) UniqueId; + + for (Index = 0; Index < MAX_MAP_LENGTH; Index++) { + if (snp->map_list[Index].virt == CpuAddr) { + break; + } + } + + if (Index >= MAX_MAP_LENGTH) + { +#if SNP_DEBUG + Print (L"SNP could not find a mapping, failed to unmap.\n"); +#endif + return ; + } + + snp->IoFncs->Unmap (snp->IoFncs, snp->map_list[Index].map_cookie); + snp->map_list[Index].virt = 0; + snp->map_list[Index].map_cookie = NULL; + return ; +} + +VOID +snp_undi32_callback_sync ( + UINT64 UniqueId, + UINT64 CpuAddr, + UINT32 NumBytes, + UINT32 Direction, + UINT64 DeviceAddr + ) +/*++ + +Routine Description: + This is a callback routine supplied to UNDI at undi_start time. + UNDI call this routine when it wants synchronize the virtual buffer contents + with the mapped buffer contents. The virtual and mapped buffers need not + correspond to the same physical memory (especially if the virtual address is + > 4GB). Depending on the direction for which the buffer is mapped, undi will + need to synchronize their contents whenever it writes to/reads from the buffer + using either the cpu address or the device address. + + EFI does not provide a sync call, since virt=physical, we sould just do + the synchronization ourself here! + +Arguments: + UniqueId - This was supplied to UNDI at Undi_Start, SNP uses this to store + Undi interface context (Undi does not read or write this variable) + CpuAddr - Virtual address that was mapped! + NumBytes - size of memory mapped + Direction- direction of data flow for this memory's usage: + cpu->device, device->cpu or both ways + DeviceAddr - the mapped device address + +Returns: + +--*/ +{ + if ((CpuAddr == 0) || (DeviceAddr == 0) || (NumBytes == 0)) { + return ; + + } + + switch (Direction) { + case FROM_DEVICE: + CopyMem ((UINT8 *) (UINTN) CpuAddr, (UINT8 *) (UINTN) DeviceAddr, NumBytes); + break; + + case TO_DEVICE: + CopyMem ((UINT8 *) (UINTN) DeviceAddr, (UINT8 *) (UINTN) CpuAddr, NumBytes); + break; + } + + return ; +} diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/get_status.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/get_status.c new file mode 100644 index 0000000000..a3fa173d3e --- /dev/null +++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/get_status.c @@ -0,0 +1,193 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module name: + get_status.c + +Abstract: + +Revision history: + 2000-Feb-03 M(f)J Genesis. +--*/ + + +#include "snp.h" + +EFI_STATUS +pxe_getstatus ( + SNP_DRIVER *snp, + UINT32 *InterruptStatusPtr, + VOID **TransmitBufferListPtr + ) +/*++ + +Routine Description: + this routine calls undi to get the status of the interrupts, get the list of + transmit buffers that completed transmitting! + +Arguments: + snp - pointer to snp driver structure + InterruptStatusPtr - a non null pointer gets the interrupt status + TransmitBufferListPtrs - a non null ointer gets the list of pointers of previously + transmitted buffers whose transmission was completed + asynchrnously. + +Returns: + +--*/ +{ + PXE_DB_GET_STATUS *db; + UINT16 InterruptFlags; + UINT64 TempData; + + db = snp->db; + snp->cdb.OpCode = PXE_OPCODE_GET_STATUS; + + snp->cdb.OpFlags = 0; + + if (TransmitBufferListPtr != NULL) { + snp->cdb.OpFlags |= PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS; + } + + if (InterruptStatusPtr != NULL) { + snp->cdb.OpFlags |= PXE_OPFLAGS_GET_INTERRUPT_STATUS; + } + + snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED; + snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED; + + // + // size DB for return of one buffer + // + snp->cdb.DBsize = (UINT16) (((UINT16) (sizeof (PXE_DB_GET_STATUS)) - (UINT16) (sizeof db->TxBuffer)) + (UINT16) (sizeof db->TxBuffer[0])); + + snp->cdb.DBaddr = (UINT64) (UINTN) db; + + snp->cdb.StatCode = PXE_STATCODE_INITIALIZE; + snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE; + snp->cdb.IFnum = snp->if_num; + snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST; + + // + // Issue UNDI command and check result. + // + DEBUG ((EFI_D_NET, "\nsnp->undi.get_status() ")); + + (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb); + + if (snp->cdb.StatCode != EFI_SUCCESS) { + DEBUG ( + (EFI_D_NET, + "\nsnp->undi.get_status() %xh:%xh\n", + snp->cdb.StatFlags, + snp->cdb.StatFlags) + ); + + return EFI_DEVICE_ERROR; + } + // + // report the values back.. + // + if (InterruptStatusPtr != NULL) { + InterruptFlags = (UINT16) (snp->cdb.StatFlags & PXE_STATFLAGS_GET_STATUS_INTERRUPT_MASK); + + *InterruptStatusPtr = 0; + + if (InterruptFlags & PXE_STATFLAGS_GET_STATUS_RECEIVE) { + *InterruptStatusPtr |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT; + } + + if (InterruptFlags & PXE_STATFLAGS_GET_STATUS_TRANSMIT) { + *InterruptStatusPtr |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT; + } + + if (InterruptFlags & PXE_STATFLAGS_GET_STATUS_COMMAND) { + *InterruptStatusPtr |= EFI_SIMPLE_NETWORK_COMMAND_INTERRUPT; + } + + if (InterruptFlags & PXE_STATFLAGS_GET_STATUS_SOFTWARE) { + *InterruptStatusPtr |= EFI_SIMPLE_NETWORK_COMMAND_INTERRUPT; + } + + } + + if (TransmitBufferListPtr != NULL) { + *TransmitBufferListPtr = + ( + (snp->cdb.StatFlags & PXE_STATFLAGS_GET_STATUS_NO_TXBUFS_WRITTEN) || + (snp->cdb.StatFlags & PXE_STATFLAGS_GET_STATUS_TXBUF_QUEUE_EMPTY) + ) ? 0 : (VOID *) (UINTN) db->TxBuffer[0]; + + TempData = (UINT64) (UINTN) (*TransmitBufferListPtr); + if (snp->IsOldUndi && (TempData >= FOUR_GIGABYTES)) { + del_v2p ((VOID *) (UINTN) (db->TxBuffer[0])); + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +snp_undi32_get_status ( + IN EFI_SIMPLE_NETWORK_PROTOCOL * this, + OUT UINT32 *InterruptStatusPtr OPTIONAL, + OUT VOID **TransmitBufferListPtr OPTIONAL + ) +/*++ + +Routine Description: + This is the SNP interface routine for getting the status + This routine basically retrieves snp structure, checks the SNP state and + calls the pxe_getstatus routine to actually get the undi status + +Arguments: + this - context pointer + InterruptStatusPtr - a non null pointer gets the interrupt status + TransmitBufferListPtrs - a non null ointer gets the list of pointers of previously + transmitted buffers whose transmission was completed + asynchrnously. + +Returns: + +--*/ +{ + SNP_DRIVER *snp; + + if (this == NULL) { + return EFI_INVALID_PARAMETER; + } + + snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this); + + if (snp == NULL) { + return EFI_DEVICE_ERROR; + } + + switch (snp->mode.State) { + case EfiSimpleNetworkInitialized: + break; + + case EfiSimpleNetworkStopped: + return EFI_NOT_STARTED; + + case EfiSimpleNetworkStarted: + return EFI_DEVICE_ERROR; + + default: + return EFI_DEVICE_ERROR; + } + + if (InterruptStatusPtr == NULL && TransmitBufferListPtr == NULL) { + return EFI_INVALID_PARAMETER; + } + + return pxe_getstatus (snp, InterruptStatusPtr, TransmitBufferListPtr); +} diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/initialize.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/initialize.c new file mode 100644 index 0000000000..d05395bd19 --- /dev/null +++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/initialize.c @@ -0,0 +1,244 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module name: + initialize.c + +Abstract: + +Revision history: + 2000-Feb-09 M(f)J Genesis. +--*/ + + +#include "snp.h" + +VOID +EFIAPI +SnpWaitForPacketNotify ( + IN EFI_EVENT Event, + IN VOID *SnpPtr + ); + +EFI_STATUS +pxe_init ( + SNP_DRIVER *snp, + UINT16 CableDetectFlag + ) +/*++ + +Routine Description: + this routine calls undi to initialize the interface. + +Arguments: + snp - pointer to snp driver structure + CableDetectFlag - Do/don't detect the cable (depending on what undi supports) + +Returns: + +--*/ +{ + PXE_CPB_INITIALIZE *cpb; + VOID *addr; + EFI_STATUS Status; + + cpb = snp->cpb; + if (snp->tx_rx_bufsize != 0) { + Status = snp->IoFncs->AllocateBuffer ( + snp->IoFncs, + AllocateAnyPages, + EfiBootServicesData, + SNP_MEM_PAGES (snp->tx_rx_bufsize), + &addr, + 0 + ); + + if (Status != EFI_SUCCESS) { + DEBUG ( + (EFI_D_ERROR, + "\nsnp->pxe_init() AllocateBuffer %xh (%r)\n", + Status, + Status) + ); + + return Status; + } + + ASSERT (addr); + + snp->tx_rx_buffer = addr; + } + + cpb->MemoryAddr = (UINT64) (UINTN) snp->tx_rx_buffer; + + cpb->MemoryLength = snp->tx_rx_bufsize; + + // + // let UNDI decide/detect these values + // + cpb->LinkSpeed = 0; + cpb->TxBufCnt = 0; + cpb->TxBufSize = 0; + cpb->RxBufCnt = 0; + cpb->RxBufSize = 0; + + cpb->DuplexMode = PXE_DUPLEX_DEFAULT; + + cpb->LoopBackMode = LOOPBACK_NORMAL; + + snp->cdb.OpCode = PXE_OPCODE_INITIALIZE; + snp->cdb.OpFlags = CableDetectFlag; + + snp->cdb.CPBsize = sizeof (PXE_CPB_INITIALIZE); + snp->cdb.DBsize = sizeof (PXE_DB_INITIALIZE); + + snp->cdb.CPBaddr = (UINT64) (UINTN) snp->cpb; + snp->cdb.DBaddr = (UINT64) (UINTN) snp->db; + + snp->cdb.StatCode = PXE_STATCODE_INITIALIZE; + snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE; + snp->cdb.IFnum = snp->if_num; + snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST; + + DEBUG ((EFI_D_NET, "\nsnp->undi.initialize() ")); + + (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb); + + if (snp->cdb.StatCode == PXE_STATCODE_SUCCESS) { + snp->mode.State = EfiSimpleNetworkInitialized; + + Status = EFI_SUCCESS; + } else { + DEBUG ( + (EFI_D_WARN, + "\nsnp->undi.initialize() %xh:%xh\n", + snp->cdb.StatFlags, + snp->cdb.StatCode) + ); + + if (snp->tx_rx_buffer != NULL) { + snp->IoFncs->FreeBuffer ( + snp->IoFncs, + SNP_MEM_PAGES (snp->tx_rx_bufsize), + (VOID *) snp->tx_rx_buffer + ); + } + + snp->tx_rx_buffer = NULL; + + Status = EFI_DEVICE_ERROR; + } + + return Status; +} + +EFI_STATUS +EFIAPI +snp_undi32_initialize ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *this, + IN UINTN extra_rx_buffer_size OPTIONAL, + IN UINTN extra_tx_buffer_size OPTIONAL + ) +/*++ + +Routine Description: + This is the SNP interface routine for initializing the interface + This routine basically retrieves snp structure, checks the SNP state and + calls the pxe_initialize routine to actually do the undi initialization + +Arguments: + this - context pointer + extra_rx_buffer_size - optional parameter, indicates extra space for rx_buffers + extra_tx_buffer_size - optional parameter, indicates extra space for tx_buffers + +Returns: + +--*/ +{ + EFI_STATUS EfiStatus; + SNP_DRIVER *snp; + + // + // + // + if (this == NULL) { + return EFI_INVALID_PARAMETER; + } + + snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this); + + if (snp == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // + // + switch (snp->mode.State) { + case EfiSimpleNetworkStarted: + break; + + case EfiSimpleNetworkStopped: + return EFI_NOT_STARTED; + + case EfiSimpleNetworkInitialized: + return EFI_DEVICE_ERROR; + + default: + return EFI_DEVICE_ERROR; + } + // + // + // + EfiStatus = gBS->CreateEvent ( + EFI_EVENT_NOTIFY_WAIT, + EFI_TPL_NOTIFY, + &SnpWaitForPacketNotify, + snp, + &snp->snp.WaitForPacket + ); + + if (EFI_ERROR (EfiStatus)) { + snp->snp.WaitForPacket = NULL; + return EFI_DEVICE_ERROR; + } + // + // + // + snp->mode.MCastFilterCount = 0; + snp->mode.ReceiveFilterSetting = 0; + ZeroMem (snp->mode.MCastFilter, sizeof snp->mode.MCastFilter); + CopyMem ( + &snp->mode.CurrentAddress, + &snp->mode.PermanentAddress, + sizeof (EFI_MAC_ADDRESS) + ); + + // + // Compute tx/rx buffer sizes based on UNDI init info and parameters. + // + snp->tx_rx_bufsize = (UINT32) (snp->init_info.MemoryRequired + extra_rx_buffer_size + extra_tx_buffer_size); + + if (snp->mode.MediaPresentSupported) { + if (pxe_init (snp, PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) == EFI_SUCCESS) { + snp->mode.MediaPresent = TRUE; + return EFI_SUCCESS; + } + } + + snp->mode.MediaPresent = FALSE; + + EfiStatus = pxe_init (snp, PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE); + + if (EFI_ERROR (EfiStatus)) { + gBS->CloseEvent (snp->snp.WaitForPacket); + } + + return EfiStatus; +} diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/mcast_ip_to_mac.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/mcast_ip_to_mac.c new file mode 100644 index 0000000000..995e33e27d --- /dev/null +++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/mcast_ip_to_mac.c @@ -0,0 +1,167 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module name: + mcast_ip_to_mac.c + +Abstract: + +Revision history: + 2000-Feb-17 M(f)J Genesis. +--*/ + + +#include "snp.h" + +EFI_STATUS +pxe_ip2mac ( + IN SNP_DRIVER *snp, + IN BOOLEAN IPv6, + IN EFI_IP_ADDRESS *IP, + IN OUT EFI_MAC_ADDRESS *MAC + ) +/*++ + +Routine Description: + this routine calls undi to convert an multicast IP address to a MAC address + +Arguments: + snp - pointer to snp driver structure + IPv6 - flag to indicate if this is an ipv6 address + IP - multicast IP address + MAC - pointer to hold the return MAC address + +Returns: + +--*/ +{ + PXE_CPB_MCAST_IP_TO_MAC *cpb; + PXE_DB_MCAST_IP_TO_MAC *db; + + cpb = snp->cpb; + db = snp->db; + snp->cdb.OpCode = PXE_OPCODE_MCAST_IP_TO_MAC; + snp->cdb.OpFlags = (UINT16) (IPv6 ? PXE_OPFLAGS_MCAST_IPV6_TO_MAC : PXE_OPFLAGS_MCAST_IPV4_TO_MAC); + snp->cdb.CPBsize = sizeof (PXE_CPB_MCAST_IP_TO_MAC); + snp->cdb.DBsize = sizeof (PXE_DB_MCAST_IP_TO_MAC); + + snp->cdb.CPBaddr = (UINT64) (UINTN) cpb; + snp->cdb.DBaddr = (UINT64) (UINTN) db; + + snp->cdb.StatCode = PXE_STATCODE_INITIALIZE; + snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE; + snp->cdb.IFnum = snp->if_num; + snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST; + + CopyMem (&cpb->IP, IP, sizeof (PXE_IP_ADDR)); + + // + // Issue UNDI command and check result. + // + DEBUG ((EFI_D_NET, "\nsnp->undi.mcast_ip_to_mac() ")); + + (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb); + + switch (snp->cdb.StatCode) { + case PXE_STATCODE_SUCCESS: + break; + + case PXE_STATCODE_INVALID_CPB: + return EFI_INVALID_PARAMETER; + + case PXE_STATCODE_UNSUPPORTED: + DEBUG ( + (EFI_D_NET, + "\nsnp->undi.mcast_ip_to_mac() %xh:%xh\n", + snp->cdb.StatFlags, + snp->cdb.StatCode) + ); + return EFI_UNSUPPORTED; + + default: + // + // UNDI command failed. Return EFI_DEVICE_ERROR + // to caller. + // + DEBUG ( + (EFI_D_NET, + "\nsnp->undi.mcast_ip_to_mac() %xh:%xh\n", + snp->cdb.StatFlags, + snp->cdb.StatCode) + ); + + return EFI_DEVICE_ERROR; + } + + CopyMem (MAC, &db->MAC, sizeof (PXE_MAC_ADDR)); + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +snp_undi32_mcast_ip_to_mac ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *this, + IN BOOLEAN IPv6, + IN EFI_IP_ADDRESS *IP, + OUT EFI_MAC_ADDRESS *MAC + ) +/*++ + +Routine Description: + This is the SNP interface routine for converting a multicast IP address to + a MAC address. + This routine basically retrieves snp structure, checks the SNP state and + calls the pxe_ip2mac routine to actually do the conversion + +Arguments: + this - context pointer + IPv6 - flag to indicate if this is an ipv6 address + IP - multicast IP address + MAC - pointer to hold the return MAC address + +Returns: + +--*/ +{ + SNP_DRIVER *snp; + + // + // Get pointer to SNP driver instance for *this. + // + if (this == NULL) { + return EFI_INVALID_PARAMETER; + } + + snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this); + + if (snp == NULL) { + return EFI_DEVICE_ERROR; + } + + switch (snp->mode.State) { + case EfiSimpleNetworkInitialized: + break; + + case EfiSimpleNetworkStopped: + return EFI_NOT_STARTED; + + case EfiSimpleNetworkStarted: + return EFI_DEVICE_ERROR; + + default: + return EFI_DEVICE_ERROR; + } + + if (IP == NULL || MAC == NULL) { + return EFI_INVALID_PARAMETER; + } + + return pxe_ip2mac (snp, IPv6, IP, MAC); +} diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/nvdata.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/nvdata.c new file mode 100644 index 0000000000..0167e4db30 --- /dev/null +++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/nvdata.c @@ -0,0 +1,183 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module name: + nvdata.c + +Abstract: + +Revision history: + 2000-Feb-03 M(f)J Genesis. +--*/ + + +#include "snp.h" + +EFI_STATUS +pxe_nvdata_read ( + IN SNP_DRIVER *snp, + IN UINTN RegOffset, + IN UINTN NumBytes, + IN OUT VOID *BufferPtr + ) +/*++ + +Routine Description: + This routine calls Undi to read the desired number of eeprom bytes. + +Arguments: + snp - pointer to the snp driver structure + RegOffset - eeprom register value relative to the base address + NumBytes - number of bytes to read + BufferPtr - pointer where to read into + +Returns: + +--*/ +{ + PXE_DB_NVDATA *db; + + db = snp->db; + snp->cdb.OpCode = PXE_OPCODE_NVDATA; + + snp->cdb.OpFlags = PXE_OPFLAGS_NVDATA_READ; + + snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED; + snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED; + + snp->cdb.DBsize = sizeof (PXE_DB_NVDATA); + snp->cdb.DBaddr = (UINT64) (UINTN) db; + + snp->cdb.StatCode = PXE_STATCODE_INITIALIZE; + snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE; + snp->cdb.IFnum = snp->if_num; + snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST; + + // + // Issue UNDI command and check result. + // + DEBUG ((EFI_D_NET, "\nsnp->undi.nvdata () ")); + + (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb); + + switch (snp->cdb.StatCode) { + case PXE_STATCODE_SUCCESS: + break; + + case PXE_STATCODE_UNSUPPORTED: + DEBUG ( + (EFI_D_NET, + "\nsnp->undi.nvdata() %xh:%xh\n", + snp->cdb.StatFlags, + snp->cdb.StatCode) + ); + + return EFI_UNSUPPORTED; + + default: + DEBUG ( + (EFI_D_NET, + "\nsnp->undi.nvdata() %xh:%xh\n", + snp->cdb.StatFlags, + snp->cdb.StatCode) + ); + + return EFI_DEVICE_ERROR; + } + + CopyMem (BufferPtr, db->Data.Byte + RegOffset, NumBytes); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +snp_undi32_nvdata ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *this, + IN BOOLEAN ReadOrWrite, + IN UINTN RegOffset, + IN UINTN NumBytes, + IN OUT VOID *BufferPtr + ) +/*++ + +Routine Description: + This is an interface call provided by SNP. + It does the basic checking on the input parameters and retrieves snp structure + and then calls the read_nvdata() call which does the actual reading + +Arguments: + this - context pointer + ReadOrWrite - true for reading and false for writing + RegOffset - eeprom register relative to the base + NumBytes - how many bytes to read + BufferPtr - address of memory to read into + +Returns: + +--*/ +{ + SNP_DRIVER *snp; + + // + // Get pointer to SNP driver instance for *this. + // + if (this == NULL) { + return EFI_INVALID_PARAMETER; + } + + snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this); + + if (snp == NULL) { + return EFI_DEVICE_ERROR; + } + // + // Return error if the SNP is not initialized. + // + switch (snp->mode.State) { + case EfiSimpleNetworkInitialized: + break; + + case EfiSimpleNetworkStopped: + return EFI_NOT_STARTED; + + case EfiSimpleNetworkStarted: + return EFI_DEVICE_ERROR; + + default: + return EFI_DEVICE_ERROR; + } + // + // Return error if non-volatile memory variables are not valid. + // + if (snp->mode.NvRamSize == 0 || snp->mode.NvRamAccessSize == 0) { + return EFI_UNSUPPORTED; + } + // + // Check for invalid parameter combinations. + // + if ((NumBytes == 0) || + (BufferPtr == NULL) || + (RegOffset >= snp->mode.NvRamSize) || + (RegOffset + NumBytes > snp->mode.NvRamSize) || + (NumBytes % snp->mode.NvRamAccessSize != 0) || + (RegOffset % snp->mode.NvRamAccessSize != 0) + ) { + return EFI_INVALID_PARAMETER; + } + // + // check the implementation flags of undi if we can write the nvdata! + // + if (!ReadOrWrite) { + return EFI_UNSUPPORTED; + } else { + return pxe_nvdata_read (snp, RegOffset, NumBytes, BufferPtr); + } +} diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/receive.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/receive.c new file mode 100644 index 0000000000..5a41b8a1ee --- /dev/null +++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/receive.c @@ -0,0 +1,255 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module name: + receive.c + +Abstract: + +Revision history: + 2000-Feb-03 M(f)J Genesis. +--*/ + + +#include "snp.h" + +EFI_STATUS +pxe_receive ( + SNP_DRIVER *snp, + VOID *BufferPtr, + UINTN *BuffSizePtr, + UINTN *HeaderSizePtr, + EFI_MAC_ADDRESS *SourceAddrPtr, + EFI_MAC_ADDRESS *DestinationAddrPtr, + UINT16 *ProtocolPtr + ) +/*++ + +Routine Description: + this routine calls undi to receive a packet and fills in the data in the + input pointers! + +Arguments: + snp - pointer to snp driver structure + BufferPtr - pointer to the memory for the received data + BuffSizePtr - is a pointer to the length of the buffer on entry and contains + the length of the received data on return + HeaderSizePtr - pointer to the header portion of the data received. + SourceAddrPtr - optional parameter, is a pointer to contain the source + ethernet address on return + DestinationAddrPtr - optional parameter, is a pointer to contain the destination + ethernet address on return + ProtocolPtr - optional parameter, is a pointer to contain the protocol type + from the ethernet header on return + + +Returns: + +--*/ +{ + PXE_CPB_RECEIVE *cpb; + PXE_DB_RECEIVE *db; + UINTN buf_size; + UINT64 TempData; + + cpb = snp->cpb; + db = snp->db; + buf_size = *BuffSizePtr; + // + // IMPORTANT NOTE: + // In case of the older 3.0 UNDI, if the input buffer address is beyond 4GB, + // DO NOT call the map function on the given buffer, instead use + // a global buffer. The reason is that UNDI3.0 has some unnecessary check of + // making sure that all the addresses (whether or not they will be given + // to the NIC ) supplied to it are below 4GB. It may or may not use + // the mapped address after all (like in case of CPB and DB)! + // Instead of using the global buffer whose address is allocated within the + // 2GB limit if I start mapping the given buffer we lose the data, here is + // why!!! + // if our address is > 4GB, the map call creates another buffer below 2GB and + // copies data to/from the original buffer to the mapped buffer either at + // map time or unmap time depending on the map direction. + // UNDI will not complain since we already mapped the buffer to be + // within the 2GB limit but will not use (I know undi) the mapped address + // since it does not give the user buffers to the NIC's receive unit, + // It just copies the received packet into the user buffer using the virtual + // (CPU) address rather than the mapped (device or physical) address. + // When the UNDI call returns, if we then unmap the buffer, we will lose + // the contents because unmap copies the contents of the mapped buffer into + // the original buffer (since the direction is FROM_DEVICE) !!! + // + // this is not a problem in Undi 3.1 because this undi uses it's map callback + // routine to map a cpu address to device address and it does it only if + // it is giving the address to the device and unmaps it before using the cpu + // address! + // + TempData = (UINT64) (UINTN) BufferPtr; + if (snp->IsOldUndi && (TempData >= FOUR_GIGABYTES)) { + cpb->BufferAddr = (UINT64) (UINTN) snp->receive_buf; + cpb->BufferLen = (UINT32) (snp->init_info.MediaHeaderLen + snp->init_info.FrameDataLen); + } else { + cpb->BufferAddr = (UINT64) (UINTN) BufferPtr; + cpb->BufferLen = (UINT32) *BuffSizePtr; + } + + cpb->reserved = 0; + + snp->cdb.OpCode = PXE_OPCODE_RECEIVE; + snp->cdb.OpFlags = PXE_OPFLAGS_NOT_USED; + + snp->cdb.CPBsize = sizeof (PXE_CPB_RECEIVE); + snp->cdb.CPBaddr = (UINT64) (UINTN) cpb; + + snp->cdb.DBsize = sizeof (PXE_DB_RECEIVE); + snp->cdb.DBaddr = (UINT64) (UINTN) db; + + snp->cdb.StatCode = PXE_STATCODE_INITIALIZE; + snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE; + snp->cdb.IFnum = snp->if_num; + snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST; + + // + // Issue UNDI command and check result. + // + DEBUG ((EFI_D_INFO, "\nsnp->undi.receive () ")); + + (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb); + + switch (snp->cdb.StatCode) { + case PXE_STATCODE_SUCCESS: + break; + + case PXE_STATCODE_NO_DATA: + DEBUG ( + (EFI_D_INFO, + "\nsnp->undi.receive () %xh:%xh\n", + snp->cdb.StatFlags, + snp->cdb.StatCode) + ); + + return EFI_NOT_READY; + + default: + DEBUG ( + (EFI_D_ERROR, + "\nsnp->undi.receive() %xh:%xh\n", + snp->cdb.StatFlags, + snp->cdb.StatCode) + ); + + return EFI_DEVICE_ERROR; + } + + *BuffSizePtr = db->FrameLen; + + if (HeaderSizePtr != NULL) { + *HeaderSizePtr = db->MediaHeaderLen; + } + + if (SourceAddrPtr != NULL) { + CopyMem (SourceAddrPtr, &db->SrcAddr, snp->mode.HwAddressSize); + } + + if (DestinationAddrPtr != NULL) { + CopyMem (DestinationAddrPtr, &db->DestAddr, snp->mode.HwAddressSize); + } + + if (ProtocolPtr != NULL) { + *ProtocolPtr = (UINT16) PXE_SWAP_UINT16 (db->Protocol); /* we need to do the byte swapping */ + } + + TempData = (UINT64) (UINTN) BufferPtr; + if (snp->IsOldUndi && (TempData >= FOUR_GIGABYTES)) { + CopyMem (BufferPtr, snp->receive_buf, snp->init_info.MediaHeaderLen + snp->init_info.FrameDataLen); + } + + return (*BuffSizePtr <= buf_size) ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL; +} + +EFI_STATUS +EFIAPI +snp_undi32_receive ( + IN EFI_SIMPLE_NETWORK_PROTOCOL * this, + OUT UINTN *HeaderSizePtr OPTIONAL, + IN OUT UINTN *BuffSizePtr, + OUT VOID *BufferPtr, + OUT EFI_MAC_ADDRESS * SourceAddrPtr OPTIONAL, + OUT EFI_MAC_ADDRESS * DestinationAddrPtr OPTIONAL, + OUT UINT16 *ProtocolPtr OPTIONAL + ) +/*++ + +Routine Description: + This is the SNP interface routine for receiving network data. + This routine basically retrieves snp structure, checks the SNP state and + calls the pxe_receive routine to actually do the receive! + +Arguments: + this - context pointer + HeaderSizePtr - optional parameter and is a pointer to the header portion of + the data received. + BuffSizePtr - is a pointer to the length of the buffer on entry and contains + the length of the received data on return + BufferPtr - pointer to the memory for the received data + SourceAddrPtr - optional parameter, is a pointer to contain the source + ethernet address on return + DestinationAddrPtr - optional parameter, is a pointer to contain the destination + ethernet address on return + ProtocolPtr - optional parameter, is a pointer to contain the protocol type + from the ethernet header on return + +Returns: + +--*/ +{ + SNP_DRIVER *snp; + + if (this == NULL) { + return EFI_INVALID_PARAMETER; + } + + snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this); + + if (snp == NULL) { + return EFI_DEVICE_ERROR; + } + + switch (snp->mode.State) { + case EfiSimpleNetworkInitialized: + break; + + case EfiSimpleNetworkStopped: + return EFI_NOT_STARTED; + + case EfiSimpleNetworkStarted: + return EFI_DEVICE_ERROR; + + default: + return EFI_DEVICE_ERROR; + } + + if ((BuffSizePtr == NULL) || (BufferPtr == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (!snp->mode.ReceiveFilterSetting) { + return EFI_DEVICE_ERROR; + } + + return pxe_receive ( + snp, + BufferPtr, + BuffSizePtr, + HeaderSizePtr, + SourceAddrPtr, + DestinationAddrPtr, + ProtocolPtr + ); +} diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/receive_filters.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/receive_filters.c new file mode 100644 index 0000000000..233448cda5 --- /dev/null +++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/receive_filters.c @@ -0,0 +1,411 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module name: + receive_filters.c + +Abstract: + +Revision history: + 2000-Feb-17 M(f)J Genesis. +--*/ + + +#include "snp.h" + +EFI_STATUS +pxe_rcvfilter_enable ( + SNP_DRIVER *snp, + UINT32 EnableFlags, + UINTN MCastAddressCount, + EFI_MAC_ADDRESS *MCastAddressList + ) +/*++ + +Routine Description: + this routine calls undi to enable the receive filters. + +Arguments: + snp - pointer to snp driver structure + EnableFlags - bit mask for enabling the receive filters + MCastAddressCount - multicast address count for a new multicast address list + MCastAddressList - list of new multicast addresses + +Returns: + +--*/ +{ + snp->cdb.OpCode = PXE_OPCODE_RECEIVE_FILTERS; + snp->cdb.OpFlags = PXE_OPFLAGS_RECEIVE_FILTER_ENABLE; + snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED; + snp->cdb.DBsize = PXE_DBSIZE_NOT_USED; + snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED; + snp->cdb.DBaddr = PXE_DBADDR_NOT_USED; + snp->cdb.StatCode = PXE_STATCODE_INITIALIZE; + snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE; + snp->cdb.IFnum = snp->if_num; + snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST; + + if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) != 0) { + snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_UNICAST; + } + + if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) != 0) { + snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST; + } + + if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) { + snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS; + } + + if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) { + snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST; + } + + if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) { + snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST; + } + + if (MCastAddressCount != 0) { + snp->cdb.CPBsize = (UINT16) (MCastAddressCount * sizeof (EFI_MAC_ADDRESS)); + snp->cdb.CPBaddr = (UINT64) (UINTN) snp->cpb; + CopyMem (snp->cpb, MCastAddressList, snp->cdb.CPBsize); + } + // + // Issue UNDI command and check result. + // + DEBUG ((EFI_D_NET, "\nsnp->undi.receive_filters() ")); + + (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb); + + if (snp->cdb.StatCode != EFI_SUCCESS) { + // + // UNDI command failed. Return UNDI status to caller. + // + DEBUG ( + (EFI_D_ERROR, + "\nsnp->undi.receive_filters() %xh:%xh\n", + snp->cdb.StatFlags, + snp->cdb.StatCode) + ); + + switch (snp->cdb.StatCode) { + case PXE_STATCODE_INVALID_CDB: + case PXE_STATCODE_INVALID_CPB: + case PXE_STATCODE_INVALID_PARAMETER: + return EFI_INVALID_PARAMETER; + + case PXE_STATCODE_UNSUPPORTED: + return EFI_UNSUPPORTED; + } + + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +pxe_rcvfilter_disable ( + SNP_DRIVER *snp, + UINT32 DisableFlags, + BOOLEAN ResetMCastList + ) +/*++ + +Routine Description: + this routine calls undi to disable the receive filters. + +Arguments: + snp - pointer to snp driver structure + DisableFlags - bit mask for disabling the receive filters + ResetMCastList - boolean flag to reset/delete the multicast filter list + +Returns: + +--*/ +{ + snp->cdb.OpCode = PXE_OPCODE_RECEIVE_FILTERS; + snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED; + snp->cdb.DBsize = PXE_DBSIZE_NOT_USED; + snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED; + snp->cdb.DBaddr = PXE_DBADDR_NOT_USED; + snp->cdb.StatCode = PXE_STATCODE_INITIALIZE; + snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE; + snp->cdb.IFnum = snp->if_num; + snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST; + + snp->cdb.OpFlags = (UINT16) (DisableFlags ? PXE_OPFLAGS_RECEIVE_FILTER_DISABLE : PXE_OPFLAGS_NOT_USED); + + if (ResetMCastList) { + snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST; + } + + if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) != 0) { + snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_UNICAST; + } + + if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) != 0) { + snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST; + } + + if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) { + snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS; + } + + if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) { + snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST; + } + + if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) { + snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST; + } + // + // Issue UNDI command and check result. + // + DEBUG ((EFI_D_NET, "\nsnp->undi.receive_filters() ")); + + (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb); + + if (snp->cdb.StatCode != EFI_SUCCESS) { + // + // UNDI command failed. Return UNDI status to caller. + // + DEBUG ( + (EFI_D_ERROR, + "\nsnp->undi.receive_filters() %xh:%xh\n", + snp->cdb.StatFlags, + snp->cdb.StatCode) + ); + + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +pxe_rcvfilter_read ( + SNP_DRIVER *snp + ) +/*++ + +Routine Description: + this routine calls undi to read the receive filters. + +Arguments: + snp - pointer to snp driver structure + +Returns: + +--*/ +{ + snp->cdb.OpCode = PXE_OPCODE_RECEIVE_FILTERS; + snp->cdb.OpFlags = PXE_OPFLAGS_RECEIVE_FILTER_READ; + snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED; + snp->cdb.DBsize = (UINT16) (snp->mode.MaxMCastFilterCount * sizeof (EFI_MAC_ADDRESS)); + snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED; + if (snp->cdb.DBsize == 0) { + snp->cdb.DBaddr = (UINT64) NULL; + } else { + snp->cdb.DBaddr = (UINT64) (UINTN) snp->db; + ZeroMem (snp->db, snp->cdb.DBsize); + } + + snp->cdb.StatCode = PXE_STATCODE_INITIALIZE; + snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE; + snp->cdb.IFnum = snp->if_num; + snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST; + + DEBUG ((EFI_D_NET, "\nsnp->undi.receive_filters() ")); + + (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb); + + if (snp->cdb.StatCode != EFI_SUCCESS) { + // + // UNDI command failed. Return UNDI status to caller. + // + DEBUG ( + (EFI_D_ERROR, + "\nsnp->undi.receive_filters() %xh:%xh\n", + snp->cdb.StatFlags, + snp->cdb.StatCode) + ); + + return EFI_DEVICE_ERROR; + } + // + // Convert UNDI32 StatFlags to EFI SNP filter flags. + // + snp->mode.ReceiveFilterSetting = 0; + + if ((snp->cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_UNICAST) != 0) { + snp->mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_UNICAST; + } + + if ((snp->cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_BROADCAST) != 0) { + snp->mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST; + } + + if ((snp->cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_PROMISCUOUS) != 0) { + snp->mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS; + } + + if ((snp->cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) { + snp->mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST; + } + + if ((snp->cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) { + snp->mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST; + } + + CopyMem (snp->mode.MCastFilter, snp->db, snp->cdb.DBsize); + + // + // Count number of active entries in multicast filter list. + // + { + EFI_MAC_ADDRESS ZeroMacAddr; + + SetMem (&ZeroMacAddr, sizeof ZeroMacAddr, 0); + + for (snp->mode.MCastFilterCount = 0; + snp->mode.MCastFilterCount < snp->mode.MaxMCastFilterCount; + snp->mode.MCastFilterCount++ + ) { + if (CompareMem ( + &snp->mode.MCastFilter[snp->mode.MCastFilterCount], + &ZeroMacAddr, + sizeof ZeroMacAddr + ) == 0) { + break; + } + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +snp_undi32_receive_filters ( + IN EFI_SIMPLE_NETWORK_PROTOCOL * this, + IN UINT32 EnableFlags, + IN UINT32 DisableFlags, + IN BOOLEAN ResetMCastList, + IN UINTN MCastAddressCount OPTIONAL, + IN EFI_MAC_ADDRESS * MCastAddressList OPTIONAL + ) +/*++ + +Routine Description: + This is the SNP interface routine for reading/enabling/disabling the + receive filters. + This routine basically retrieves snp structure, checks the SNP state and + checks the parameter validity, calls one of the above routines to actually + do the work + +Arguments: + this - context pointer + EnableFlags - bit mask for enabling the receive filters + DisableFlags - bit mask for disabling the receive filters + ResetMCastList - boolean flag to reset/delete the multicast filter list + MCastAddressCount - multicast address count for a new multicast address list + MCastAddressList - list of new multicast addresses + +Returns: + +--*/ +{ + SNP_DRIVER *snp; + EFI_STATUS Status; + + if (this == NULL) { + return EFI_INVALID_PARAMETER; + } + + snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this); + + if (snp == NULL) { + return EFI_DEVICE_ERROR; + } + + switch (snp->mode.State) { + case EfiSimpleNetworkInitialized: + break; + + case EfiSimpleNetworkStopped: + return EFI_NOT_STARTED; + + case EfiSimpleNetworkStarted: + return EFI_DEVICE_ERROR; + + default: + return EFI_DEVICE_ERROR; + } + // + // check if we are asked to enable or disable something that the UNDI + // does not even support! + // + if ((EnableFlags &~snp->mode.ReceiveFilterMask) != 0) { + return EFI_INVALID_PARAMETER; + } + + if ((DisableFlags &~snp->mode.ReceiveFilterMask) != 0) { + return EFI_INVALID_PARAMETER; + } + + if (ResetMCastList) { + DisableFlags |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST & snp->mode.ReceiveFilterMask; + MCastAddressCount = 0; + MCastAddressList = NULL; + } else { + if (MCastAddressCount != 0) { + if (MCastAddressCount > snp->mode.MaxMCastFilterCount) { + return EFI_INVALID_PARAMETER; + } + + if (MCastAddressList == NULL) { + return EFI_INVALID_PARAMETER; + } + } + } + + if (EnableFlags == 0 && DisableFlags == 0 && !ResetMCastList && MCastAddressCount == 0) { + return EFI_SUCCESS; + } + + if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0 && MCastAddressCount == 0) { + return EFI_INVALID_PARAMETER; + } + + if ((EnableFlags != 0) || (MCastAddressCount != 0)) { + Status = pxe_rcvfilter_enable ( + snp, + EnableFlags, + MCastAddressCount, + MCastAddressList + ); + + if (Status != EFI_SUCCESS) { + return Status; + } + } + + if ((DisableFlags != 0) || ResetMCastList) { + Status = pxe_rcvfilter_disable (snp, DisableFlags, ResetMCastList); + + if (Status != EFI_SUCCESS) { + return Status; + } + } + + return pxe_rcvfilter_read (snp); +} diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/reset.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/reset.c new file mode 100644 index 0000000000..8d56ecf361 --- /dev/null +++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/reset.c @@ -0,0 +1,129 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module name: + reset.c + +Abstract: + +Revision history: + 2000-Feb-09 M(f)J Genesis. +--*/ + + +#include "snp.h" + +EFI_STATUS +pxe_reset ( + SNP_DRIVER *snp + ) +/*++ + +Routine Description: + This routine calls undi to reset the nic. + +Arguments: + snp - pointer to the snp driver structure + +Returns: + EFI_SUCCESSFUL for a successful completion + other for failed calls + +--*/ +{ + snp->cdb.OpCode = PXE_OPCODE_RESET; + snp->cdb.OpFlags = PXE_OPFLAGS_NOT_USED; + snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED; + snp->cdb.DBsize = PXE_DBSIZE_NOT_USED; + snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED; + snp->cdb.DBaddr = PXE_DBADDR_NOT_USED; + snp->cdb.StatCode = PXE_STATCODE_INITIALIZE; + snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE; + snp->cdb.IFnum = snp->if_num; + snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST; + + // + // Issue UNDI command and check result. + // + DEBUG ((EFI_D_NET, "\nsnp->undi.reset() ")); + + (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb); + + if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) { + DEBUG ( + (EFI_D_WARN, + "\nsnp->undi32.reset() %xh:%xh\n", + snp->cdb.StatFlags, + snp->cdb.StatCode) + ); + + // + // UNDI could not be reset. Return UNDI error. + // + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +snp_undi32_reset ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *this, + IN BOOLEAN ExtendedVerification + ) +/*++ + +Routine Description: + This is the SNP interface routine for resetting the NIC + This routine basically retrieves snp structure, checks the SNP state and + calls the pxe_reset routine to actually do the reset! + +Arguments: + this - context pointer + ExtendedVerification - not implemented + +Returns: + +--*/ +{ + SNP_DRIVER *snp; + + // + // Resolve Warning 4 unreferenced parameter problem + // + ExtendedVerification = 0; + + if (this == NULL) { + return EFI_INVALID_PARAMETER; + } + + snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this); + + if (snp == NULL) { + return EFI_DEVICE_ERROR; + } + + switch (snp->mode.State) { + case EfiSimpleNetworkInitialized: + break; + + case EfiSimpleNetworkStopped: + return EFI_NOT_STARTED; + + case EfiSimpleNetworkStarted: + return EFI_DEVICE_ERROR; + + default: + return EFI_DEVICE_ERROR; + } + + return pxe_reset (snp); +} diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/shutdown.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/shutdown.c new file mode 100644 index 0000000000..efa6cf7302 --- /dev/null +++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/shutdown.c @@ -0,0 +1,152 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module name: + shutdown.c + +Abstract: + +Revision history: + 2000-Feb-14 M(f)J Genesis. +--*/ + + +#include "snp.h" + +EFI_STATUS +pxe_shutdown ( + IN SNP_DRIVER *snp + ) +/*++ + +Routine Description: + this routine calls undi to shut down the interface. + +Arguments: + snp - pointer to snp driver structure + +Returns: + +--*/ +{ + snp->cdb.OpCode = PXE_OPCODE_SHUTDOWN; + snp->cdb.OpFlags = PXE_OPFLAGS_NOT_USED; + snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED; + snp->cdb.DBsize = PXE_DBSIZE_NOT_USED; + snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED; + snp->cdb.DBaddr = PXE_DBADDR_NOT_USED; + snp->cdb.StatCode = PXE_STATCODE_INITIALIZE; + snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE; + snp->cdb.IFnum = snp->if_num; + snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST; + + // + // Issue UNDI command and check result. + // + DEBUG ((EFI_D_NET, "\nsnp->undi.shutdown() ")); + + (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb); + + if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) { + // + // UNDI could not be shutdown. Return UNDI error. + // + DEBUG ((EFI_D_WARN, "\nsnp->undi.shutdown() %xh:%xh\n", snp->cdb.StatFlags, snp->cdb.StatCode)); + + return EFI_DEVICE_ERROR; + } + // + // Free allocated memory. + // + if (snp->tx_rx_buffer != NULL) { + snp->IoFncs->FreeBuffer ( + snp->IoFncs, + SNP_MEM_PAGES (snp->tx_rx_bufsize), + (VOID *) snp->tx_rx_buffer + ); + } + + snp->tx_rx_buffer = NULL; + snp->tx_rx_bufsize = 0; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +snp_undi32_shutdown ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *this + ) +/*++ + +Routine Description: + This is the SNP interface routine for shutting down the interface + This routine basically retrieves snp structure, checks the SNP state and + calls the pxe_shutdown routine to actually do the undi shutdown + +Arguments: + this - context pointer + +Returns: + +--*/ +{ + SNP_DRIVER *snp; + EFI_STATUS status; + + // + // + // + if (this == NULL) { + return EFI_INVALID_PARAMETER; + } + + snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this); + + if (snp == NULL) { + return EFI_DEVICE_ERROR; + } + // + // + // + switch (snp->mode.State) { + case EfiSimpleNetworkInitialized: + break; + + case EfiSimpleNetworkStopped: + return EFI_NOT_STARTED; + + case EfiSimpleNetworkStarted: + return EFI_DEVICE_ERROR; + + default: + return EFI_DEVICE_ERROR; + } + // + // + // + status = pxe_shutdown (snp); + + snp->mode.State = EfiSimpleNetworkStarted; + snp->mode.ReceiveFilterSetting = 0; + + snp->mode.MCastFilterCount = 0; + snp->mode.ReceiveFilterSetting = 0; + ZeroMem (snp->mode.MCastFilter, sizeof snp->mode.MCastFilter); + CopyMem ( + &snp->mode.CurrentAddress, + &snp->mode.PermanentAddress, + sizeof (EFI_MAC_ADDRESS) + ); + + gBS->CloseEvent (snp->snp.WaitForPacket); + + return status; +} diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/snp.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/snp.c new file mode 100644 index 0000000000..ab3c997448 --- /dev/null +++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/snp.c @@ -0,0 +1,1315 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module name: + snp.c + +Abstract: + +--*/ + + +#include "snp.h" + +EFI_STATUS +pxe_start ( + SNP_DRIVER *snp + ); +EFI_STATUS +pxe_stop ( + SNP_DRIVER *snp + ); +EFI_STATUS +pxe_init ( + SNP_DRIVER *snp, + UINT16 OpFlags + ); +EFI_STATUS +pxe_shutdown ( + SNP_DRIVER *snp + ); +EFI_STATUS +pxe_get_stn_addr ( + SNP_DRIVER *snp + ); + +EFI_STATUS +EFIAPI +InitializeSnpNiiDriver ( + IN EFI_HANDLE image_handle, + IN EFI_SYSTEM_TABLE *system_table + ); + +EFI_STATUS +EFIAPI +SimpleNetworkDriverSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +SimpleNetworkDriverStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +SimpleNetworkDriverStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +// +// Simple Network Protocol Driver Global Variables +// +EFI_DRIVER_BINDING_PROTOCOL mSimpleNetworkDriverBinding = { + SimpleNetworkDriverSupported, + SimpleNetworkDriverStart, + SimpleNetworkDriverStop, + 0x10, + NULL, + NULL +}; + +// +// Module global variables needed to support undi 3.0 interface +// +EFI_PCI_IO_PROTOCOL *mPciIoFncs; +struct s_v2p *_v2p = NULL; // undi3.0 map_list head +// End Global variables +// +EFI_STATUS +add_v2p ( + IN OUT struct s_v2p **v2p, + EFI_PCI_IO_PROTOCOL_OPERATION type, + VOID *vaddr, + UINTN bsize + ) +/*++ + +Routine Description: + This routine maps the given CPU address to a Device address. It creates a + an entry in the map list with the virtual and physical addresses and the + un map cookie. + +Arguments: + v2p - pointer to return a map list node pointer. + type - the direction in which the data flows from the given virtual address + device->cpu or cpu->device or both ways. + vaddr - virtual address (or CPU address) to be mapped + bsize - size of the buffer to be mapped. + +Returns: + + EFI_SUCEESS - routine has completed the mapping + other - error as indicated. + +--*/ +{ + EFI_STATUS Status; + + if ((v2p == NULL) || (vaddr == NULL) || (bsize == 0)) { + return EFI_INVALID_PARAMETER; + } + + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (struct s_v2p), + (VOID **) v2p + ); + + if (Status != EFI_SUCCESS) { + return Status; + } + + Status = mPciIoFncs->Map ( + mPciIoFncs, + type, + vaddr, + &bsize, + &(*v2p)->paddr, + &(*v2p)->unmap + ); + if (Status != EFI_SUCCESS) { + gBS->FreePool (*v2p); + return Status; + } + (*v2p)->vaddr = vaddr; + (*v2p)->bsize = bsize; + (*v2p)->next = _v2p; + _v2p = *v2p; + + return EFI_SUCCESS; +} + +EFI_STATUS +find_v2p ( + struct s_v2p **v2p, + VOID *vaddr + ) +/*++ + +Routine Description: + This routine searches the linked list of mapped address nodes (for undi3.0 + interface) to find the node that corresponds to the given virtual address and + returns a pointer to that node. + +Arguments: + v2p - pointer to return a map list node pointer. + vaddr - virtual address (or CPU address) to be searched in the map list + +Returns: + + EFI_SUCEESS - if a match found! + Other - match not found + +--*/ +{ + struct s_v2p *v; + + if (v2p == NULL || vaddr == NULL) { + return EFI_INVALID_PARAMETER; + } + + for (v = _v2p; v != NULL; v = v->next) { + if (v->vaddr == vaddr) { + *v2p = v; + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +EFI_STATUS +del_v2p ( + VOID *vaddr + ) +/*++ + +Routine Description: + This routine unmaps the given virtual address and frees the memory allocated + for the map list node corresponding to that address. + +Arguments: + vaddr - virtual address (or CPU address) to be unmapped + +Returns: + EFI_SUCEESS - if successfully unmapped + Other - as indicated by the error + + +--*/ +{ + struct s_v2p *v; + struct s_v2p *t; + EFI_STATUS Status; + + if (vaddr == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (_v2p == NULL) { + return EFI_NOT_FOUND; + } + // + // Is our node at the head of the list?? + // + if ((v = _v2p)->vaddr == vaddr) { + _v2p = _v2p->next; + + Status = mPciIoFncs->Unmap (mPciIoFncs, v->unmap); + + gBS->FreePool (v); + +#if SNP_DEBUG + if (Status) { + Print (L"Unmap failed with status = %x\n", Status); + } +#endif + return Status; + } + + for (; v->next != NULL; v = t) { + if ((t = v->next)->vaddr == vaddr) { + v->next = t->next; + Status = mPciIoFncs->Unmap (mPciIoFncs, t->unmap); + gBS->FreePool (t); +#if SNP_DEBUG + if (Status) { + Print (L"Unmap failed with status = %x\n", Status); + } +#endif + return Status; + } + } + + return EFI_NOT_FOUND; +} + +#if SNP_DEBUG +VOID +snp_wait_for_key ( + VOID + ) +/*++ + +Routine Description: + Wait for a key stroke, used for debugging purposes + +Arguments: + none + +Returns: + none + +--*/ +{ + EFI_INPUT_KEY key; + + Aprint ("\nPress any key to continue\n"); + + while (gST->ConIn->ReadKeyStroke (gST->ConIn, &key) == EFI_NOT_READY) { + ; + } +} +#endif + +STATIC +EFI_STATUS +issue_hwundi_command ( + UINT64 cdb + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ +#if SNP_DEBUG + Aprint ("\nissue_hwundi_command() - This should not be called!"); + snp_wait_for_key (); +#endif + if (cdb == 0) { + return EFI_INVALID_PARAMETER; + + } + // + // %%TBD - For now, nothing is done. + // + return EFI_UNSUPPORTED; +} + +STATIC +UINT8 +calc_8bit_cksum ( + VOID *ptr, + UINTN len + ) +/*++ + +Routine Description: + Compute 8-bit checksum of a buffer. + +Arguments: + ptr - Pointer to buffer. + len - Length of buffer in bytes. + +Returns: + 8-bit checksum of all bytes in buffer. + If ptr is NULL or len is zero, zero is returned. + +--*/ +{ + UINT8 *bptr; + UINT8 cksum; + + bptr = ptr; + cksum = 0; + + if (ptr == NULL || len == 0) { + return 0; + } + + while (len--) { + cksum = (UINT8) (cksum +*bptr++); + } + + return cksum; +} + +EFI_STATUS +EFIAPI +SimpleNetworkDriverSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + Test to see if this driver supports Controller. Any Controller + that contains a Nii protocol can be supported. + + Arguments: + This - Protocol instance pointer. + Controller - Handle of device to test. + RemainingDevicePath - Not used. + + Returns: + EFI_SUCCESS - This driver supports this device. + EFI_ALREADY_STARTED - This driver is already running on this device. + other - This driver does not support this device. + +--*/ +{ + EFI_STATUS Status; + EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NiiProtocol; + PXE_UNDI *pxe; + BOOLEAN IsUndi31; + + IsUndi31 = FALSE; + Status = gBS->OpenProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + NULL, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->OpenProtocol ( + Controller, + &gEfiNetworkInterfaceIdentifierProtocolGuid_31, + (VOID **) &NiiProtocol, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (Status == EFI_ALREADY_STARTED) + { +#if SNP_DEBUG + Aprint ("Support(): Already Started. on handle %x\n", Controller); +#endif + return EFI_ALREADY_STARTED; + } + + if (!EFI_ERROR (Status)) + { + +#if SNP_DEBUG + Aprint ("Support(): UNDI3.1 found on handle %x\n", Controller); + snp_wait_for_key (); +#endif + IsUndi31 = TRUE; + } else { + // + // try the older 3.0 driver + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiNetworkInterfaceIdentifierProtocolGuid, + (VOID **) &NiiProtocol, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + +#if SNP_DEBUG + Aprint ("Support(): UNDI3.0 found on handle %x\n", Controller); + snp_wait_for_key (); +#endif + } + // + // check the version, we don't want to connect to the undi16 + // + if (NiiProtocol->Type != EfiNetworkInterfaceUndi) { + Status = EFI_UNSUPPORTED; + goto Done; + } + // + // Check to see if !PXE structure is valid. Paragraph alignment of !PXE structure is required. + // + if (NiiProtocol->ID & 0x0F) { + DEBUG ((EFI_D_NET, "\n!PXE structure is not paragraph aligned.\n")); + Status = EFI_UNSUPPORTED; + goto Done; + } + + pxe = (PXE_UNDI *) (UINTN) (NiiProtocol->ID); + + // + // Verify !PXE revisions. + // + if (pxe->hw.Signature != PXE_ROMID_SIGNATURE) { + DEBUG ((EFI_D_NET, "\n!PXE signature is not valid.\n")); + Status = EFI_UNSUPPORTED; + goto Done; + } + + if (pxe->hw.Rev < PXE_ROMID_REV) { + DEBUG ((EFI_D_NET, "\n!PXE.Rev is not supported.\n")); + Status = EFI_UNSUPPORTED; + goto Done; + } + + if (pxe->hw.MajorVer < PXE_ROMID_MAJORVER) { + + DEBUG ((EFI_D_NET, "\n!PXE.MajorVer is not supported.\n")); + Status = EFI_UNSUPPORTED; + goto Done; + + } else if (pxe->hw.MajorVer == PXE_ROMID_MAJORVER && pxe->hw.MinorVer < PXE_ROMID_MINORVER) { + DEBUG ((EFI_D_NET, "\n!PXE.MinorVer is not supported.")); + Status = EFI_UNSUPPORTED; + goto Done; + } + // + // Do S/W UNDI specific checks. + // + if ((pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) == 0) { + if (pxe->sw.EntryPoint < pxe->sw.Len) { + DEBUG ((EFI_D_NET, "\n!PXE S/W entry point is not valid.")); + Status = EFI_UNSUPPORTED; + goto Done; + } + + if (pxe->sw.BusCnt == 0) { + DEBUG ((EFI_D_NET, "\n!PXE.BusCnt is zero.")); + Status = EFI_UNSUPPORTED; + goto Done; + } + } + + Status = EFI_SUCCESS; +#if SNP_DEBUG + Aprint ("Support(): supported on %x\n", Controller); + snp_wait_for_key (); +#endif + +Done: + if (IsUndi31) { + gBS->CloseProtocol ( + Controller, + &gEfiNetworkInterfaceIdentifierProtocolGuid_31, + This->DriverBindingHandle, + Controller + ); + + } else { + gBS->CloseProtocol ( + Controller, + &gEfiNetworkInterfaceIdentifierProtocolGuid, + This->DriverBindingHandle, + Controller + ); + } + + return Status; +} + +EFI_STATUS +EFIAPI +SimpleNetworkDriverStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + called for any handle that we said "supported" in the above call! + +Arguments: + This - Protocol instance pointer. + Controller - Handle of device to start + RemainingDevicePath - Not used. + + Returns: + EFI_SUCCESS - This driver supports this device. + other - This driver failed to start this device. + +--*/ +{ + EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *Nii; + EFI_DEVICE_PATH_PROTOCOL *NiiDevicePath; + EFI_STATUS Status; + PXE_UNDI *pxe; + SNP_DRIVER *snp; + VOID *addr; + VOID *addrUnmap; + EFI_PHYSICAL_ADDRESS paddr; + EFI_HANDLE Handle; + UINTN Size; + BOOLEAN UndiNew; + PXE_PCI_CONFIG_INFO ConfigInfo; + PCI_TYPE00 *ConfigHeader; + UINT32 *TempBar; + UINT8 BarIndex; + PXE_STATFLAGS InitStatFlags; + + DEBUG ((EFI_D_NET, "\nSnpNotifyNetworkInterfaceIdentifier() ")); + + Status = gBS->OpenProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &NiiDevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->LocateDevicePath ( + &gEfiPciIoProtocolGuid, + &NiiDevicePath, + &Handle + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->OpenProtocol ( + Handle, + &gEfiPciIoProtocolGuid, + (VOID **) &mPciIoFncs, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Get the NII interface. look for 3.1 undi first, if it is not there + // then look for 3.0, validate the interface. + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiNetworkInterfaceIdentifierProtocolGuid_31, + (VOID **) &Nii, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (Status == EFI_ALREADY_STARTED) { + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return Status; + } + + if (!EFI_ERROR (Status)) { + // + // probably not a 3.1 UNDI + // + UndiNew = TRUE; +#if SNP_DEBUG + Aprint ("Start(): UNDI3.1 found\n"); + snp_wait_for_key (); +#endif + } else { + UndiNew = FALSE; + Status = gBS->OpenProtocol ( + Controller, + &gEfiNetworkInterfaceIdentifierProtocolGuid, + (VOID **) &Nii, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return Status; + } + +#if SNP_DEBUG + Aprint ("Start(): UNDI3.0 found\n"); + snp_wait_for_key (); +#endif + } + + pxe = (PXE_UNDI *) (UINTN) (Nii->ID); + + if (calc_8bit_cksum (pxe, pxe->hw.Len) != 0) { + DEBUG ((EFI_D_NET, "\n!PXE checksum is not correct.\n")); + goto NiiError; + } + + if ((pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) { + // + // We can get any packets. + // + } else if ((pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) { + // + // We need to be able to get broadcast packets for DHCP. + // If we do not have promiscuous support, we must at least have + // broadcast support or we cannot do DHCP! + // + } else { + DEBUG ((EFI_D_NET, "\nUNDI does not have promiscuous or broadcast support.")); + goto NiiError; + } + // + // OK, we like this UNDI, and we know snp is not already there on this handle + // Allocate and initialize a new simple network protocol structure. + // + Status = mPciIoFncs->AllocateBuffer ( + mPciIoFncs, + AllocateAnyPages, + EfiBootServicesData, + SNP_MEM_PAGES (sizeof (SNP_DRIVER)), + &addr, + 0 + ); + + if (Status != EFI_SUCCESS) { + DEBUG ((EFI_D_NET, "\nCould not allocate SNP_DRIVER structure.\n")); + goto NiiError; + } + + snp = (SNP_DRIVER *) (UINTN) addr; + + if (!UndiNew) { + Size = SNP_MEM_PAGES (sizeof (SNP_DRIVER)); + + Status = mPciIoFncs->Map ( + mPciIoFncs, + EfiPciIoOperationBusMasterCommonBuffer, + addr, + &Size, + &paddr, + &addrUnmap + ); + + ASSERT (paddr); + + DEBUG ((EFI_D_NET, "\nSNP_DRIVER @ %Xh, sizeof(SNP_DRIVER) == %d", addr, sizeof (SNP_DRIVER))); + snp = (SNP_DRIVER *) (UINTN) paddr; + snp->SnpDriverUnmap = addrUnmap; + } + + ZeroMem (snp, sizeof (SNP_DRIVER)); + + snp->IoFncs = mPciIoFncs; + snp->IsOldUndi = (BOOLEAN) (!UndiNew); + + snp->Signature = SNP_DRIVER_SIGNATURE; + + EfiInitializeLock (&snp->lock, EFI_TPL_NOTIFY); + + snp->snp.Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION; + snp->snp.Start = snp_undi32_start; + snp->snp.Stop = snp_undi32_stop; + snp->snp.Initialize = snp_undi32_initialize; + snp->snp.Reset = snp_undi32_reset; + snp->snp.Shutdown = snp_undi32_shutdown; + snp->snp.ReceiveFilters = snp_undi32_receive_filters; + snp->snp.StationAddress = snp_undi32_station_address; + snp->snp.Statistics = snp_undi32_statistics; + snp->snp.MCastIpToMac = snp_undi32_mcast_ip_to_mac; + snp->snp.NvData = snp_undi32_nvdata; + snp->snp.GetStatus = snp_undi32_get_status; + snp->snp.Transmit = snp_undi32_transmit; + snp->snp.Receive = snp_undi32_receive; + snp->snp.WaitForPacket = NULL; + + snp->snp.Mode = &snp->mode; + + snp->tx_rx_bufsize = 0; + snp->tx_rx_buffer = NULL; + + snp->if_num = Nii->IfNum; + + if ((pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) != 0) { + snp->is_swundi = FALSE; + snp->issue_undi32_command = &issue_hwundi_command; + } else { + snp->is_swundi = TRUE; + + if ((pxe->sw.Implementation & PXE_ROMID_IMP_SW_VIRT_ADDR) != 0) { + snp->issue_undi32_command = (issue_undi32_command) (UINTN) pxe->sw.EntryPoint; + } else { + snp->issue_undi32_command = (issue_undi32_command) (UINTN) ((UINT8) (UINTN) pxe + pxe->sw.EntryPoint); + } + } + // + // Allocate a global CPB and DB buffer for this UNDI interface. + // we do this because: + // + // -UNDI 3.0 wants all the addresses passed to it (even the cpb and db) to be + // within 2GB limit, create them here and map them so that when undi calls + // v2p callback to check if the physical address is < 2gb, we will pass. + // + // -This is not a requirement for 3.1 or later UNDIs but the code looks + // simpler if we use the same cpb, db variables for both old and new undi + // interfaces from all the SNP interface calls (we don't map the buffers + // for the newer undi interfaces though) + // . + // -it is OK to allocate one global set of CPB, DB pair for each UNDI + // interface as EFI does not multi-task and so SNP will not be re-entered! + // + Status = mPciIoFncs->AllocateBuffer ( + mPciIoFncs, + AllocateAnyPages, + EfiBootServicesData, + SNP_MEM_PAGES (4096), + &addr, + 0 + ); + + if (Status != EFI_SUCCESS) { + DEBUG ((EFI_D_NET, "\nCould not allocate CPB and DB structures.\n")); + goto Error_DeleteSNP; + } + + if (snp->IsOldUndi) { + Size = SNP_MEM_PAGES (4096); + + Status = mPciIoFncs->Map ( + mPciIoFncs, + EfiPciIoOperationBusMasterCommonBuffer, + addr, + &Size, + &paddr, + &snp->CpbUnmap + ); + + ASSERT (paddr); + + snp->cpb = (VOID *) (UINTN) paddr; + snp->db = (VOID *) ((UINTN) paddr + 2048); + } else { + snp->cpb = (VOID *) (UINTN) addr; + snp->db = (VOID *) ((UINTN) addr + 2048); + } + // + // pxe_start call is going to give the callback functions to UNDI, these callback + // functions use the BarIndex values from the snp structure, so these must be initialized + // with default values before doing a pxe_start. The correct values can be obtained after + // getting the config information from UNDI + // + snp->MemoryBarIndex = 0; + snp->IoBarIndex = 1; + + // + // we need the undi init information many times in this snp code, just get it + // once here and store it in the snp driver structure. to get Init Info + // from UNDI we have to start undi first. + // + Status = pxe_start (snp); + + if (Status != EFI_SUCCESS) { + goto Error_DeleteCPBDB; + } + + snp->cdb.OpCode = PXE_OPCODE_GET_INIT_INFO; + snp->cdb.OpFlags = PXE_OPFLAGS_NOT_USED; + + snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED; + snp->cdb.CPBaddr = PXE_DBADDR_NOT_USED; + + snp->cdb.DBsize = sizeof snp->init_info; + snp->cdb.DBaddr = (UINT64) (UINTN) &snp->init_info; + + snp->cdb.StatCode = PXE_STATCODE_INITIALIZE; + snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE; + + snp->cdb.IFnum = snp->if_num; + snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST; + + DEBUG ((EFI_D_NET, "\nsnp->undi.get_init_info() ")); + + (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb); + + // + // Save the INIT Stat Code... + // + InitStatFlags = snp->cdb.StatFlags; + + if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) { + DEBUG ((EFI_D_NET, "\nsnp->undi.init_info() %xh:%xh\n", snp->cdb.StatFlags, snp->cdb.StatCode)); + pxe_stop (snp); + goto Error_DeleteCPBDB; + } + + snp->cdb.OpCode = PXE_OPCODE_GET_CONFIG_INFO; + snp->cdb.OpFlags = PXE_OPFLAGS_NOT_USED; + + snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED; + snp->cdb.CPBaddr = PXE_DBADDR_NOT_USED; + + snp->cdb.DBsize = sizeof ConfigInfo; + snp->cdb.DBaddr = (UINT64) (UINTN) &ConfigInfo; + + snp->cdb.StatCode = PXE_STATCODE_INITIALIZE; + snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE; + + snp->cdb.IFnum = snp->if_num; + snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST; + + DEBUG ((EFI_D_NET, "\nsnp->undi.get_config_info() ")); + + (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb); + + if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) { + DEBUG ((EFI_D_NET, "\nsnp->undi.config_info() %xh:%xh\n", snp->cdb.StatFlags, snp->cdb.StatCode)); + pxe_stop (snp); + goto Error_DeleteCPBDB; + } + // + // Find the correct BAR to do IO. + // + // + // Enumerate through the PCI BARs for the device to determine which one is + // the IO BAR. Save the index of the BAR into the adapter info structure. + // for regular 32bit BARs, 0 is memory mapped, 1 is io mapped + // + ConfigHeader = (PCI_TYPE00 *) &ConfigInfo.Config.Byte[0]; + TempBar = (UINT32 *) &ConfigHeader->Device.Bar[0]; + for (BarIndex = 0; BarIndex <= 5; BarIndex++) { + if ((*TempBar & PCI_BAR_MEM_MASK) == PCI_BAR_MEM_64BIT) { + // + // This is a 64-bit memory bar, skip this and the + // next bar as well. + // + TempBar++; + } + + if ((*TempBar & PCI_BAR_IO_MASK) == PCI_BAR_IO_MODE) { + snp->IoBarIndex = BarIndex; + break; + } + + TempBar++; + } + + // + // We allocate 2 more global buffers for undi 3.0 interface. We use these + // buffers to pass to undi when the user buffers are beyond 4GB. + // UNDI 3.0 wants all the addresses passed to it to be + // within 2GB limit, create them here and map them so that when undi calls + // v2p callback to check if the physical address is < 2gb, we will pass. + // + // For 3.1 and later UNDIs, we do not do this because undi is + // going to call the map() callback if and only if it wants to use the + // device address for any address it receives. + // + if (snp->IsOldUndi) { + // + // buffer for receive + // + Size = SNP_MEM_PAGES (snp->init_info.MediaHeaderLen + snp->init_info.FrameDataLen); + Status = mPciIoFncs->AllocateBuffer ( + mPciIoFncs, + AllocateAnyPages, + EfiBootServicesData, + Size, + &addr, + 0 + ); + + if (Status != EFI_SUCCESS) { + DEBUG ((EFI_D_ERROR, "\nCould not allocate receive buffer.\n")); + goto Error_DeleteCPBDB; + } + + Status = mPciIoFncs->Map ( + mPciIoFncs, + EfiPciIoOperationBusMasterCommonBuffer, + addr, + &Size, + &paddr, + &snp->ReceiveBufUnmap + ); + + ASSERT (paddr); + + snp->receive_buf = (UINT8 *) (UINTN) paddr; + + // + // buffer for fill_header + // + Size = SNP_MEM_PAGES (snp->init_info.MediaHeaderLen); + Status = mPciIoFncs->AllocateBuffer ( + mPciIoFncs, + AllocateAnyPages, + EfiBootServicesData, + Size, + &addr, + 0 + ); + + if (Status != EFI_SUCCESS) { + DEBUG ((EFI_D_ERROR, "\nCould not allocate fill_header buffer.\n")); + goto Error_DeleteRCVBuf; + } + + Status = mPciIoFncs->Map ( + mPciIoFncs, + EfiPciIoOperationBusMasterCommonBuffer, + addr, + &Size, + &paddr, + &snp->FillHdrBufUnmap + ); + + ASSERT (paddr); + snp->fill_hdr_buf = (UINT8 *) (UINTN) paddr; + } + // + // Initialize simple network protocol mode structure + // + snp->mode.State = EfiSimpleNetworkStopped; + snp->mode.HwAddressSize = snp->init_info.HWaddrLen; + snp->mode.MediaHeaderSize = snp->init_info.MediaHeaderLen; + snp->mode.MaxPacketSize = snp->init_info.FrameDataLen; + snp->mode.NvRamAccessSize = snp->init_info.NvWidth; + snp->mode.NvRamSize = snp->init_info.NvCount * snp->mode.NvRamAccessSize; + snp->mode.IfType = snp->init_info.IFtype; + snp->mode.MaxMCastFilterCount = snp->init_info.MCastFilterCnt; + snp->mode.MCastFilterCount = 0; + + switch (InitStatFlags & PXE_STATFLAGS_CABLE_DETECT_MASK) { + case PXE_STATFLAGS_CABLE_DETECT_SUPPORTED: + snp->mode.MediaPresentSupported = TRUE; + break; + + case PXE_STATFLAGS_CABLE_DETECT_NOT_SUPPORTED: + default: + snp->mode.MediaPresentSupported = FALSE; + } + + if ((pxe->hw.Implementation & PXE_ROMID_IMP_STATION_ADDR_SETTABLE) != 0) { + snp->mode.MacAddressChangeable = TRUE; + } else { + snp->mode.MacAddressChangeable = FALSE; + } + + if ((pxe->hw.Implementation & PXE_ROMID_IMP_MULTI_FRAME_SUPPORTED) != 0) { + snp->mode.MultipleTxSupported = TRUE; + } else { + snp->mode.MultipleTxSupported = FALSE; + } + + snp->mode.ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST; + + if ((pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) != 0) { + snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST; + + } + + if ((pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) { + snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS; + + } + + if ((pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) { + snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST; + + } + + if ((pxe->hw.Implementation & PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED) != 0) { + snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST; + + } + + if (pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) { + snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST; + + } + + snp->mode.ReceiveFilterSetting = 0; + + // + // need to get the station address to save in the mode structure. we need to + // initialize the UNDI first for this. + // + snp->tx_rx_bufsize = snp->init_info.MemoryRequired; + Status = pxe_init (snp, PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE); + + if (Status) { + pxe_stop (snp); + goto Error_DeleteHdrBuf; + } + + Status = pxe_get_stn_addr (snp); + + if (Status != EFI_SUCCESS) { + DEBUG ((EFI_D_ERROR, "\nsnp->undi.get_station_addr() failed.\n")); + pxe_shutdown (snp); + pxe_stop (snp); + goto Error_DeleteHdrBuf; + } + + snp->mode.MediaPresent = FALSE; + + // + // We should not leave UNDI started and initialized here. this DriverStart() + // routine must only find and attach the SNP interface to UNDI layer that it + // finds on the given handle! + // The UNDI layer will be started when upper layers call snp->start. + // How ever, this DriverStart() must fill up the snp mode structure which + // contains the MAC address of the NIC. For this reason we started and + // initialized UNDI here, now we are done, do a shutdown and stop of the + // UNDI interface! + // + pxe_shutdown (snp); + pxe_stop (snp); + + // + // add SNP to the undi handle + // + Status = gBS->InstallProtocolInterface ( + &Controller, + &gEfiSimpleNetworkProtocolGuid, + EFI_NATIVE_INTERFACE, + &(snp->snp) + ); + + if (!EFI_ERROR (Status)) { + return Status; + } + +Error_DeleteHdrBuf: + if (snp->IsOldUndi) { + Status = mPciIoFncs->Unmap ( + mPciIoFncs, + snp->FillHdrBufUnmap + ); + Size = SNP_MEM_PAGES (snp->init_info.MediaHeaderLen); + mPciIoFncs->FreeBuffer ( + mPciIoFncs, + Size, + snp->fill_hdr_buf + ); + } + +Error_DeleteRCVBuf: + if (snp->IsOldUndi) { + Status = mPciIoFncs->Unmap ( + mPciIoFncs, + snp->ReceiveBufUnmap + ); + Size = SNP_MEM_PAGES (snp->init_info.MediaHeaderLen + snp->init_info.FrameDataLen); + mPciIoFncs->FreeBuffer ( + mPciIoFncs, + Size, + snp->receive_buf + ); + + } + +Error_DeleteCPBDB: + if (snp->IsOldUndi) { + Status = mPciIoFncs->Unmap ( + mPciIoFncs, + snp->CpbUnmap + ); + } + + Status = mPciIoFncs->FreeBuffer ( + mPciIoFncs, + SNP_MEM_PAGES (4096), + snp->cpb + ); + +Error_DeleteSNP: + if (snp->IsOldUndi) { + Status = mPciIoFncs->Unmap ( + mPciIoFncs, + snp->SnpDriverUnmap + ); + } + + mPciIoFncs->FreeBuffer ( + mPciIoFncs, + SNP_MEM_PAGES (sizeof (SNP_DRIVER)), + snp + ); +NiiError: + if (!UndiNew) { + gBS->CloseProtocol ( + Controller, + &gEfiNetworkInterfaceIdentifierProtocolGuid, + This->DriverBindingHandle, + Controller + ); + } else { + gBS->CloseProtocol ( + Controller, + &gEfiNetworkInterfaceIdentifierProtocolGuid_31, + This->DriverBindingHandle, + Controller + ); + } + + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return Status; +} + +EFI_STATUS +EFIAPI +SimpleNetworkDriverStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + EFI_STATUS Status; + EFI_SIMPLE_NETWORK_PROTOCOL *SnpProtocol; + SNP_DRIVER *Snp; + + // + // Get our context back. + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiSimpleNetworkProtocolGuid, + (VOID **) &SnpProtocol, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (SnpProtocol); + + Status = gBS->UninstallProtocolInterface ( + Controller, + &gEfiSimpleNetworkProtocolGuid, + &Snp->snp + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + if (!Snp->IsOldUndi) { + Status = gBS->CloseProtocol ( + Controller, + &gEfiNetworkInterfaceIdentifierProtocolGuid_31, + This->DriverBindingHandle, + Controller + ); + } else { + Status = gBS->CloseProtocol ( + Controller, + &gEfiNetworkInterfaceIdentifierProtocolGuid, + This->DriverBindingHandle, + Controller + ); + } + + Status = gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + pxe_shutdown (Snp); + pxe_stop (Snp); + + if (Snp->IsOldUndi) { + Status = mPciIoFncs->Unmap ( + mPciIoFncs, + Snp->FillHdrBufUnmap + ); + + mPciIoFncs->FreeBuffer ( + mPciIoFncs, + SNP_MEM_PAGES (Snp->init_info.MediaHeaderLen), + Snp->fill_hdr_buf + ); + Status = mPciIoFncs->Unmap ( + mPciIoFncs, + Snp->ReceiveBufUnmap + ); + + mPciIoFncs->FreeBuffer ( + mPciIoFncs, + SNP_MEM_PAGES (Snp->init_info.MediaHeaderLen + Snp->init_info.FrameDataLen), + Snp->receive_buf + ); + + Status = mPciIoFncs->Unmap ( + mPciIoFncs, + Snp->CpbUnmap + ); + Status = mPciIoFncs->Unmap ( + mPciIoFncs, + Snp->SnpDriverUnmap + ); + } + + mPciIoFncs->FreeBuffer ( + mPciIoFncs, + SNP_MEM_PAGES (4096), + Snp->cpb + ); + + mPciIoFncs->FreeBuffer ( + mPciIoFncs, + SNP_MEM_PAGES (sizeof (SNP_DRIVER)), + Snp + ); + + return Status; +} + diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/snp.h b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/snp.h new file mode 100644 index 0000000000..05c5a8bb92 --- /dev/null +++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/snp.h @@ -0,0 +1,410 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module name: + snp.h + +Abstract: + +Revision history: + 2000-Feb-03 M(f)J Genesis. +--*/ +#ifndef _SNP_H +#define _SNP_H + + +#include "IndustryStandard/pci22.h" + +#define SNP_DEBUG 0 +#define FOUR_GIGABYTES (UINT64) 0x100000000ULL + +#if SNP_DEBUG +#undef D_NET +#define D_NET D_WARN +#define SNP_PRINT(DebugInfo) Print (DebugInfo) +#else +#define SNP_PRINT(DebugInfo) +#endif + +#define SNP_DRIVER_SIGNATURE EFI_SIGNATURE_32 ('s', 'n', 'd', 's') +#define MAX_MAP_LENGTH 100 + +#define PCI_BAR_IO_MASK 0x00000003 +#define PCI_BAR_IO_MODE 0x00000001 + +#define PCI_BAR_MEM_MASK 0x0000000F +#define PCI_BAR_MEM_MODE 0x00000000 +#define PCI_BAR_MEM_64BIT 0x00000004 + +typedef struct { + UINT32 Signature; + EFI_LOCK lock; + + EFI_SIMPLE_NETWORK_PROTOCOL snp; + EFI_SIMPLE_NETWORK_MODE mode; + + EFI_HANDLE device_handle; + EFI_DEVICE_PATH_PROTOCOL *device_path; + + // + // Local instance data needed by SNP driver + // + // Pointer to S/W UNDI API entry point + // This will be NULL for H/W UNDI + // + EFI_STATUS (*issue_undi32_command) (UINT64 cdb); + + BOOLEAN is_swundi; + + // + // undi interface number, if one undi manages more nics + // + PXE_IFNUM if_num; + + // + // Allocated tx/rx buffer that was passed to UNDI Initialize. + // + UINT32 tx_rx_bufsize; + VOID *tx_rx_buffer; + // + // mappable buffers for receive and fill header for undi3.0 + // these will be used if the user buffers are above 4GB limit (instead of + // mapping the user buffers) + // + UINT8 *receive_buf; + VOID *ReceiveBufUnmap; + UINT8 *fill_hdr_buf; + VOID *FillHdrBufUnmap; + + EFI_PCI_IO_PROTOCOL *IoFncs; + UINT8 IoBarIndex; + UINT8 MemoryBarIndex; + BOOLEAN IsOldUndi; // true for EFI1.0 UNDI (3.0) drivers + // + // Buffers for command descriptor block, command parameter block + // and data block. + // + PXE_CDB cdb; + VOID *cpb; + VOID *CpbUnmap; + VOID *db; + + // + // UNDI structure, we need to remember the init info for a long time! + // + PXE_DB_GET_INIT_INFO init_info; + + VOID *SnpDriverUnmap; + // + // when ever we map an address, we must remember it's address and the un-map + // cookie so that we can unmap later + // + struct s_map_list { + EFI_PHYSICAL_ADDRESS virt; + VOID *map_cookie; + } map_list[MAX_MAP_LENGTH]; +} +SNP_DRIVER; + +#define EFI_SIMPLE_NETWORK_DEV_FROM_THIS(a) CR (a, SNP_DRIVER, snp, SNP_DRIVER_SIGNATURE) + +// +// Global Variables +// +extern EFI_COMPONENT_NAME_PROTOCOL gSimpleNetworkComponentName; +extern EFI_DRIVER_BINDING_PROTOCOL gSimpleNetworkDriverBinding; + +// +// Virtual to physical mapping for all UNDI 3.0s. +// +extern struct s_v2p { + struct s_v2p *next; + VOID *vaddr; + UINTN bsize; + EFI_PHYSICAL_ADDRESS paddr; + VOID *unmap; +} +*_v2p; + +EFI_STATUS +add_v2p ( + struct s_v2p **v2p, + EFI_PCI_IO_PROTOCOL_OPERATION type, + VOID *vaddr, + UINTN bsize + ) +; + +EFI_STATUS +find_v2p ( + struct s_v2p **v2p, + VOID *vaddr + ) +; + +EFI_STATUS +del_v2p ( + VOID *vaddr + ) +; + +extern +VOID +snp_undi32_callback_block_30 ( + IN UINT32 Enable + ) +; + +extern +VOID +snp_undi32_callback_delay_30 ( + IN UINT64 MicroSeconds + ) +; + +extern +VOID +snp_undi32_callback_memio_30 ( + IN UINT8 ReadOrWrite, + IN UINT8 NumBytes, + IN UINT64 MemOrPortAddress, + IN OUT UINT64 BufferPtr + ) +; + +extern +VOID +snp_undi32_callback_v2p_30 ( + IN UINT64 CpuAddr, + IN OUT UINT64 DeviceAddrPtr + ) +; + +extern +VOID +snp_undi32_callback_block ( + IN UINT64 UniqueId, + IN UINT32 Enable + ) +; + +extern +VOID +snp_undi32_callback_delay ( + IN UINT64 UniqueId, + IN UINT64 MicroSeconds + ) +; + +extern +VOID +snp_undi32_callback_memio ( + IN UINT64 UniqueId, + IN UINT8 ReadOrWrite, + IN UINT8 NumBytes, + IN UINT64 MemOrPortAddr, + IN OUT UINT64 BufferPtr + ) +; + +extern +VOID +snp_undi32_callback_map ( + IN UINT64 UniqueId, + IN UINT64 CpuAddr, + IN UINT32 NumBytes, + IN UINT32 Direction, + IN OUT UINT64 DeviceAddrPtr + ) +; + +extern +VOID +snp_undi32_callback_unmap ( + IN UINT64 UniqueId, + IN UINT64 CpuAddr, + IN UINT32 NumBytes, + IN UINT32 Direction, + IN UINT64 DeviceAddr // not a pointer to device address + ) +; + +extern +VOID +snp_undi32_callback_sync ( + IN UINT64 UniqueId, + IN UINT64 CpuAddr, + IN UINT32 NumBytes, + IN UINT32 Direction, + IN UINT64 DeviceAddr // not a pointer to device address + ) +; + +extern +EFI_STATUS +EFIAPI +snp_undi32_start ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *this + ) +; + +extern +EFI_STATUS +EFIAPI +snp_undi32_stop ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *this + ) +; + +extern +EFI_STATUS +EFIAPI +snp_undi32_initialize ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *this, + IN UINTN extra_rx_buffer_size OPTIONAL, + IN UINTN extra_tx_buffer_size OPTIONAL + ) +; + +extern +EFI_STATUS +EFIAPI +snp_undi32_reset ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *this, + IN BOOLEAN ExtendedVerification + ) +; + +extern +EFI_STATUS +EFIAPI +snp_undi32_shutdown ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *this + ) +; + +extern +EFI_STATUS +EFIAPI +snp_undi32_receive_filters ( + IN EFI_SIMPLE_NETWORK_PROTOCOL * this, + IN UINT32 enable, + IN UINT32 disable, + IN BOOLEAN reset_mcast_filter, + IN UINTN mcast_filter_count OPTIONAL, + IN EFI_MAC_ADDRESS * mcast_filter OPTIONAL + ) +; + +extern +EFI_STATUS +EFIAPI +snp_undi32_station_address ( + IN EFI_SIMPLE_NETWORK_PROTOCOL * this, + IN BOOLEAN reset, + IN EFI_MAC_ADDRESS *new OPTIONAL + ) +; + +extern +EFI_STATUS +EFIAPI +snp_undi32_statistics ( + IN EFI_SIMPLE_NETWORK_PROTOCOL * this, + IN BOOLEAN reset, + IN OUT UINTN *statistics_size OPTIONAL, + IN OUT EFI_NETWORK_STATISTICS * statistics_table OPTIONAL + ) +; + +extern +EFI_STATUS +EFIAPI +snp_undi32_mcast_ip_to_mac ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *this, + IN BOOLEAN IPv6, + IN EFI_IP_ADDRESS *IP, + OUT EFI_MAC_ADDRESS *MAC + ) +; + +extern +EFI_STATUS +EFIAPI +snp_undi32_nvdata ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *this, + IN BOOLEAN read_write, + IN UINTN offset, + IN UINTN buffer_size, + IN OUT VOID *buffer + ) +; + +extern +EFI_STATUS +EFIAPI +snp_undi32_get_status ( + IN EFI_SIMPLE_NETWORK_PROTOCOL * this, + OUT UINT32 *interrupt_status OPTIONAL, + OUT VOID **tx_buffer OPTIONAL + ) +; + +extern +EFI_STATUS +EFIAPI +snp_undi32_transmit ( + IN EFI_SIMPLE_NETWORK_PROTOCOL * this, + IN UINTN header_size, + IN UINTN buffer_size, + IN VOID *buffer, + IN EFI_MAC_ADDRESS * src_addr OPTIONAL, + IN EFI_MAC_ADDRESS * dest_addr OPTIONAL, + IN UINT16 *protocol OPTIONAL + ) +; + +extern +EFI_STATUS +EFIAPI +snp_undi32_receive ( + IN EFI_SIMPLE_NETWORK_PROTOCOL * this, + OUT UINTN *header_size OPTIONAL, + IN OUT UINTN *buffer_size, + OUT VOID *buffer, + OUT EFI_MAC_ADDRESS * src_addr OPTIONAL, + OUT EFI_MAC_ADDRESS * dest_addr OPTIONAL, + OUT UINT16 *protocol OPTIONAL + ) +; + +typedef +EFI_STATUS +(*issue_undi32_command) ( + UINT64 cdb + ); +typedef +VOID +(*ptr) ( + VOID + ); + +#define SNP_MEM_PAGES(x) (((x) - 1) / 4096 + 1) + +#if SNP_DEBUG +extern +VOID +snp_wait_for_key ( + VOID + ) +; +#endif + +#endif /* _SNP_H */ diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/start.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/start.c new file mode 100644 index 0000000000..1fab0de8ef --- /dev/null +++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/start.c @@ -0,0 +1,191 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module name: + start.c + +Abstract: + +Revision history: + 2000-Feb-07 M(f)J Genesis. +--*/ + + +#include "snp.h" + +EFI_STATUS +pxe_start ( + SNP_DRIVER *snp + ) +/*++ + +Routine Description: + this routine calls undi to start the interface and changes the snp state! + +Arguments: + snp - pointer to snp driver structure + +Returns: + +--*/ +{ + PXE_CPB_START_30 *cpb; + PXE_CPB_START_31 *cpb_31; + + cpb = snp->cpb; + cpb_31 = snp->cpb; + // + // Initialize UNDI Start CDB for H/W UNDI + // + snp->cdb.OpCode = PXE_OPCODE_START; + snp->cdb.OpFlags = PXE_OPFLAGS_NOT_USED; + snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED; + snp->cdb.DBsize = PXE_DBSIZE_NOT_USED; + snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED; + snp->cdb.DBaddr = PXE_DBADDR_NOT_USED; + snp->cdb.StatCode = PXE_STATCODE_INITIALIZE; + snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE; + snp->cdb.IFnum = snp->if_num; + snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST; + + // + // Make changes to H/W UNDI Start CDB if this is + // a S/W UNDI. + // + if (snp->is_swundi) { + if (snp->IsOldUndi) { + snp->cdb.CPBsize = sizeof (PXE_CPB_START_30); + snp->cdb.CPBaddr = (UINT64) (UINTN) cpb; + + cpb->Delay = (UINT64) &snp_undi32_callback_delay_30; + cpb->Block = (UINT64) &snp_undi32_callback_block_30; + + // + // Virtual == Physical. This can be set to zero. + // + cpb->Virt2Phys = (UINT64) &snp_undi32_callback_v2p_30; + cpb->Mem_IO = (UINT64) &snp_undi32_callback_memio_30; + } else { + snp->cdb.CPBsize = sizeof (PXE_CPB_START_31); + snp->cdb.CPBaddr = (UINT64) (UINTN) cpb_31; + + cpb_31->Delay = (UINT64) &snp_undi32_callback_delay; + cpb_31->Block = (UINT64) &snp_undi32_callback_block; + + // + // Virtual == Physical. This can be set to zero. + // + cpb_31->Virt2Phys = (UINT64) 0; + cpb_31->Mem_IO = (UINT64) &snp_undi32_callback_memio; + + cpb_31->Map_Mem = (UINT64) &snp_undi32_callback_map; + cpb_31->UnMap_Mem = (UINT64) &snp_undi32_callback_unmap; + cpb_31->Sync_Mem = (UINT64) &snp_undi32_callback_sync; + + cpb_31->Unique_ID = (UINT64) (UINTN) snp; + } + } + // + // Issue UNDI command and check result. + // + DEBUG ((EFI_D_NET, "\nsnp->undi.start() ")); + + (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb); + + if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) { + // + // UNDI could not be started. Return UNDI error. + // + DEBUG ( + (EFI_D_ERROR, + "\nsnp->undi.start() %xh:%xh\n", + snp->cdb.StatCode, + snp->cdb.StatFlags) + ); + + return EFI_DEVICE_ERROR; + } + // + // Set simple network state to Started and return success. + // + snp->mode.State = EfiSimpleNetworkStarted; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +snp_undi32_start ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This + ) +/*++ + +Routine Description: + This is the SNP interface routine for starting the interface + This routine basically retrieves snp structure, checks the SNP state and + calls the pxe_start routine to actually do start undi interface + +Arguments: + This - context pointer + +Returns: + EFI_INVALID_PARAMETER - "This" is Null + - No SNP driver can be extracted from "This" + EFI_ALREADY_STARTED - The state of SNP is EfiSimpleNetworkStarted + or EfiSimpleNetworkInitialized + EFI_DEVICE_ERROR - The state of SNP is other than EfiSimpleNetworkStarted, + EfiSimpleNetworkInitialized, and EfiSimpleNetworkStopped + EFI_SUCCESS - UNDI interface is succesfully started + Other - Error occurs while calling pxe_start function. + +--*/ +{ + SNP_DRIVER *Snp; + EFI_STATUS Status; + UINTN Index; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This); + + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + switch (Snp->mode.State) { + case EfiSimpleNetworkStopped: + break; + + case EfiSimpleNetworkStarted: + case EfiSimpleNetworkInitialized: + return EFI_ALREADY_STARTED; + + default: + return EFI_DEVICE_ERROR; + } + + Status = pxe_start (Snp); + if (Status != EFI_SUCCESS) { + return Status; + } + // + // clear the map_list in SNP structure + // + for (Index = 0; Index < MAX_MAP_LENGTH; Index++) { + Snp->map_list[Index].virt = 0; + Snp->map_list[Index].map_cookie = 0; + } + + Snp->mode.MCastFilterCount = 0; + + return Status; +} diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/station_address.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/station_address.c new file mode 100644 index 0000000000..2d143ef9a5 --- /dev/null +++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/station_address.c @@ -0,0 +1,248 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module name: + station_address.c + +Abstract: + +Revision history: + 2000-Feb-17 M(f)J Genesis. +--*/ + + +#include "snp.h" + +EFI_STATUS +pxe_get_stn_addr ( + SNP_DRIVER *snp + ) +/*++ + +Routine Description: + this routine calls undi to read the MAC address of the NIC and updates the + mode structure with the address. + +Arguments: + snp - pointer to snp driver structure + +Returns: + +--*/ +{ + PXE_DB_STATION_ADDRESS *db; + + db = snp->db; + snp->cdb.OpCode = PXE_OPCODE_STATION_ADDRESS; + snp->cdb.OpFlags = PXE_OPFLAGS_STATION_ADDRESS_READ; + + snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED; + snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED; + + snp->cdb.DBsize = sizeof (PXE_DB_STATION_ADDRESS); + snp->cdb.DBaddr = (UINT64) (UINTN) db; + + snp->cdb.StatCode = PXE_STATCODE_INITIALIZE; + snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE; + snp->cdb.IFnum = snp->if_num; + snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST; + + // + // Issue UNDI command and check result. + // + DEBUG ((EFI_D_NET, "\nsnp->undi.station_addr() ")); + + (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb); + + if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) { + DEBUG ( + (EFI_D_ERROR, + "\nsnp->undi.station_addr() %xh:%xh\n", + snp->cdb.StatFlags, + snp->cdb.StatCode) + ); + + return EFI_DEVICE_ERROR; + } + // + // Set new station address in SNP->Mode structure and return success. + // + CopyMem ( + &(snp->mode.CurrentAddress), + &db->StationAddr, + snp->mode.HwAddressSize + ); + + CopyMem ( + &snp->mode.BroadcastAddress, + &db->BroadcastAddr, + snp->mode.HwAddressSize + ); + + CopyMem ( + &snp->mode.PermanentAddress, + &db->PermanentAddr, + snp->mode.HwAddressSize + ); + + return EFI_SUCCESS; +} + +EFI_STATUS +pxe_set_stn_addr ( + SNP_DRIVER *snp, + EFI_MAC_ADDRESS *NewMacAddr + ) +/*++ + +Routine Description: + this routine calls undi to set a new MAC address for the NIC, + +Arguments: + snp - pointer to snp driver structure + NewMacAddr - pointer to a mac address to be set for the nic, if this is NULL + then this routine resets the mac address to the NIC's original + address. + +Returns: + +--*/ +{ + PXE_CPB_STATION_ADDRESS *cpb; + PXE_DB_STATION_ADDRESS *db; + + cpb = snp->cpb; + db = snp->db; + snp->cdb.OpCode = PXE_OPCODE_STATION_ADDRESS; + + if (NewMacAddr == NULL) { + snp->cdb.OpFlags = PXE_OPFLAGS_STATION_ADDRESS_RESET; + snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED; + snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED; + } else { + snp->cdb.OpFlags = PXE_OPFLAGS_STATION_ADDRESS_READ; + // + // even though the OPFLAGS are set to READ, supplying a new address + // in the CPB will make undi change the mac address to the new one. + // + CopyMem (&cpb->StationAddr, NewMacAddr, snp->mode.HwAddressSize); + + snp->cdb.CPBsize = sizeof (PXE_CPB_STATION_ADDRESS); + snp->cdb.CPBaddr = (UINT64) (UINTN) cpb; + } + + snp->cdb.DBsize = sizeof (PXE_DB_STATION_ADDRESS); + snp->cdb.DBaddr = (UINT64) (UINTN) db; + + snp->cdb.StatCode = PXE_STATCODE_INITIALIZE; + snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE; + snp->cdb.IFnum = snp->if_num; + snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST; + + // + // Issue UNDI command and check result. + // + DEBUG ((EFI_D_NET, "\nsnp->undi.station_addr() ")); + + (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb); + + if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) { + DEBUG ( + (EFI_D_ERROR, + "\nsnp->undi.station_addr() %xh:%xh\n", + snp->cdb.StatFlags, + snp->cdb.StatCode) + ); + + // + // UNDI command failed. Return UNDI status to caller. + // + return EFI_DEVICE_ERROR; + } + // + // read the changed address and save it in SNP->Mode structure + // + pxe_get_stn_addr (snp); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +snp_undi32_station_address ( + IN EFI_SIMPLE_NETWORK_PROTOCOL * this, + IN BOOLEAN ResetFlag, + IN EFI_MAC_ADDRESS * NewMacAddr OPTIONAL + ) +/*++ + +Routine Description: + This is the SNP interface routine for changing the NIC's mac address. + This routine basically retrieves snp structure, checks the SNP state and + calls the above routines to actually do the work + +Arguments: + this - context pointer + NewMacAddr - pointer to a mac address to be set for the nic, if this is NULL + then this routine resets the mac address to the NIC's original + address. + ResetFlag - If true, the mac address will change to NIC's original address + +Returns: + +--*/ +{ + SNP_DRIVER *snp; + EFI_STATUS Status; + + // + // Get pointer to SNP driver instance for *this. + // + if (this == NULL) { + return EFI_INVALID_PARAMETER; + } + + snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this); + + if (snp == NULL) { + return EFI_DEVICE_ERROR; + } + // + // Return error if the SNP is not initialized. + // + switch (snp->mode.State) { + case EfiSimpleNetworkInitialized: + break; + + case EfiSimpleNetworkStopped: + return EFI_NOT_STARTED; + + case EfiSimpleNetworkStarted: + return EFI_DEVICE_ERROR; + + default: + return EFI_DEVICE_ERROR; + } + // + // Check for invalid parameter combinations. + // + if (!ResetFlag && NewMacAddr == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (ResetFlag) { + Status = pxe_set_stn_addr (snp, NULL); + } else { + Status = pxe_set_stn_addr (snp, NewMacAddr); + + } + + return Status; +} diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/statistics.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/statistics.c new file mode 100644 index 0000000000..1c148a7e3f --- /dev/null +++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/statistics.c @@ -0,0 +1,193 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module name: + statistics.c + +Abstract: + +Revision history: + 2000-Feb-17 M(f)J Genesis. +--*/ + + +#include "Snp.h" + +EFI_STATUS +EFIAPI +snp_undi32_statistics ( + IN EFI_SIMPLE_NETWORK_PROTOCOL * this, + IN BOOLEAN ResetFlag, + IN OUT UINTN *StatTableSizePtr OPTIONAL, + IN OUT EFI_NETWORK_STATISTICS * StatTablePtr OPTIONAL + ) +/*++ + +Routine Description: + This is the SNP interface routine for getting the NIC's statistics. + This routine basically retrieves snp structure, checks the SNP state and + calls the pxe_ routine to actually do the + +Arguments: + this - context pointer + ResetFlag - true to reset the NIC's statistics counters to zero. + StatTableSizePtr - pointer to the statistics table size + StatTablePtr - pointer to the statistics table + +Returns: + +--*/ +{ + SNP_DRIVER *snp; + PXE_DB_STATISTICS *db; + UINT64 *stp; + UINT64 mask; + UINTN size; + UINTN n; + + // + // Get pointer to SNP driver instance for *this. + // + if (this == NULL) { + return EFI_INVALID_PARAMETER; + } + + snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this); + + if (snp == NULL) { + return EFI_DEVICE_ERROR; + } + // + // Return error if the SNP is not initialized. + // + switch (snp->mode.State) { + case EfiSimpleNetworkInitialized: + break; + + case EfiSimpleNetworkStopped: + return EFI_NOT_STARTED; + + case EfiSimpleNetworkStarted: + return EFI_DEVICE_ERROR; + + default: + return EFI_DEVICE_ERROR; + } + // + // if we are not resetting the counters, we have to have a valid stat table + // with >0 size. if no reset, no table and no size, return success. + // + if (!ResetFlag && StatTableSizePtr == NULL) { + return StatTablePtr ? EFI_INVALID_PARAMETER : EFI_SUCCESS; + } + // + // Initialize UNDI Statistics CDB + // + snp->cdb.OpCode = PXE_OPCODE_STATISTICS; + snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED; + snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED; + snp->cdb.StatCode = PXE_STATCODE_INITIALIZE; + snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE; + snp->cdb.IFnum = snp->if_num; + snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST; + + if (ResetFlag) { + snp->cdb.OpFlags = PXE_OPFLAGS_STATISTICS_RESET; + snp->cdb.DBsize = PXE_DBSIZE_NOT_USED; + snp->cdb.DBaddr = PXE_DBADDR_NOT_USED; + db = snp->db; + } else { + snp->cdb.OpFlags = PXE_OPFLAGS_STATISTICS_READ; + snp->cdb.DBsize = sizeof (PXE_DB_STATISTICS); + snp->cdb.DBaddr = (UINT64) (UINTN) (db = snp->db); + } + // + // Issue UNDI command and check result. + // + DEBUG ((EFI_D_NET, "\nsnp->undi.statistics() ")); + + (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb); + + switch (snp->cdb.StatCode) { + case PXE_STATCODE_SUCCESS: + break; + + case PXE_STATCODE_UNSUPPORTED: + DEBUG ( + (EFI_D_ERROR, + "\nsnp->undi.statistics() %xh:%xh\n", + snp->cdb.StatFlags, + snp->cdb.StatCode) + ); + + return EFI_UNSUPPORTED; + + default: + DEBUG ( + (EFI_D_ERROR, + "\nsnp->undi.statistics() %xh:%xh\n", + snp->cdb.StatFlags, + snp->cdb.StatCode) + ); + + return EFI_DEVICE_ERROR; + } + + if (ResetFlag) { + return EFI_SUCCESS; + } + + if (StatTablePtr == NULL) { + *StatTableSizePtr = sizeof (EFI_NETWORK_STATISTICS); + return EFI_BUFFER_TOO_SMALL; + } + // + // Convert the UNDI statistics information to SNP statistics + // information. + // + ZeroMem (StatTablePtr, *StatTableSizePtr); + stp = (UINT64 *) StatTablePtr; + size = 0; + + for (n = 0, mask = 1; n < 64; n++, mask = LShiftU64 (mask, 1), stp++) { + // + // There must be room for a full UINT64. Partial + // numbers will not be stored. + // + if ((n + 1) * sizeof (UINT64) > *StatTableSizePtr) { + break; + } + + if (db->Supported & mask) { + *stp = db->Data[n]; + size = n + 1; + } else { + SetMem (stp, sizeof (UINT64), 0xFF); + } + } + // + // Compute size up to last supported statistic. + // + while (++n < 64) { + if (db->Supported & (mask = LShiftU64 (mask, 1))) { + size = n; + } + } + + size *= sizeof (UINT64); + + if (*StatTableSizePtr >= size) { + *StatTableSizePtr = size; + return EFI_SUCCESS; + } else { + *StatTableSizePtr = size; + return EFI_BUFFER_TOO_SMALL; + } +} diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/stop.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/stop.c new file mode 100644 index 0000000000..c68731df26 --- /dev/null +++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/stop.c @@ -0,0 +1,120 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module name: + stop.c + +Abstract: + +Revision history: + 2000-Feb-09 M(f)J Genesis. +--*/ + + +#include "snp.h" + +EFI_STATUS +pxe_stop ( + SNP_DRIVER *snp + ) +/*++ + +Routine Description: + this routine calls undi to stop the interface and changes the snp state + +Arguments: + snp - pointer to snp driver structure + +Returns: + +--*/ +{ + snp->cdb.OpCode = PXE_OPCODE_STOP; + snp->cdb.OpFlags = PXE_OPFLAGS_NOT_USED; + snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED; + snp->cdb.DBsize = PXE_DBSIZE_NOT_USED; + snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED; + snp->cdb.DBaddr = PXE_DBADDR_NOT_USED; + snp->cdb.StatCode = PXE_STATCODE_INITIALIZE; + snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE; + snp->cdb.IFnum = snp->if_num; + snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST; + + // + // Issue UNDI command + // + DEBUG ((EFI_D_NET, "\nsnp->undi.stop() ")); + + (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb); + + if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) { + DEBUG ( + (EFI_D_WARN, + "\nsnp->undi.stop() %xh:%xh\n", + snp->cdb.StatCode, + snp->cdb.StatFlags) + ); + + return EFI_DEVICE_ERROR; + } + // + // Set simple network state to Started and return success. + // + snp->mode.State = EfiSimpleNetworkStopped; + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +snp_undi32_stop ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *this + ) +/*++ + +Routine Description: + This is the SNP interface routine for stopping the interface. + This routine basically retrieves snp structure, checks the SNP state and + calls the pxe_stop routine to actually stop the undi interface + +Arguments: + this - context pointer + +Returns: + +--*/ +{ + SNP_DRIVER *snp; + + if (this == NULL) { + return EFI_INVALID_PARAMETER; + } + + snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this); + + if (snp == NULL) { + return EFI_DEVICE_ERROR; + } + + switch (snp->mode.State) { + case EfiSimpleNetworkStarted: + break; + + case EfiSimpleNetworkStopped: + return EFI_NOT_STARTED; + + case EfiSimpleNetworkInitialized: + return EFI_DEVICE_ERROR; + + default: + return EFI_DEVICE_ERROR; + } + + return pxe_stop (snp); +} diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/transmit.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/transmit.c new file mode 100644 index 0000000000..b48e2c79e8 --- /dev/null +++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/transmit.c @@ -0,0 +1,396 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module name: + + transmit.c + +Abstract: + +Revision history: + 2000-Feb-03 M(f)J Genesis. +--*/ + + +#include "snp.h" + +EFI_STATUS +pxe_fillheader ( + SNP_DRIVER *snp, + VOID *MacHeaderPtr, + UINTN MacHeaderSize, + VOID *BufferPtr, + UINTN BufferLength, + EFI_MAC_ADDRESS *DestinationAddrPtr, + EFI_MAC_ADDRESS *SourceAddrPtr, + UINT16 *ProtocolPtr + ) +/*++ + +Routine Description: + This routine calls undi to create the meadia header for the given data buffer. + +Arguments: + snp - pointer to SNP driver structure + MacHeaderPtr - address where the media header will be filled in. + MacHeaderSize - size of the memory at MacHeaderPtr + BufferPtr - data buffer pointer + BufferLength - Size of data in the BufferPtr + DestinationAddrPtr - address of the destination mac address buffer + SourceAddrPtr - address of the source mac address buffer + ProtocolPtr - address of the protocol type + +Returns: + EFI_SUCCESS - if successfully completed the undi call + Other - error return from undi call. + +--*/ +{ + PXE_CPB_FILL_HEADER_FRAGMENTED *cpb; + EFI_STATUS Status; + struct s_v2p *pkt_v2p; + UINT64 TempData; + + cpb = snp->cpb; + if (SourceAddrPtr) { + CopyMem ( + (VOID *) cpb->SrcAddr, + (VOID *) SourceAddrPtr, + snp->mode.HwAddressSize + ); + } else { + CopyMem ( + (VOID *) cpb->SrcAddr, + (VOID *) &(snp->mode.CurrentAddress), + snp->mode.HwAddressSize + ); + } + + CopyMem ( + (VOID *) cpb->DestAddr, + (VOID *) DestinationAddrPtr, + snp->mode.HwAddressSize + ); + + // + // we need to do the byte swapping + // + cpb->Protocol = (UINT16) PXE_SWAP_UINT16 (*ProtocolPtr); + + cpb->PacketLen = (UINT32) (BufferLength); + cpb->MediaHeaderLen = (UINT16) MacHeaderSize; + + cpb->FragCnt = 2; + cpb->reserved = 0; + + cpb->FragDesc[0].FragAddr = (UINT64) (UINTN) MacHeaderPtr; + cpb->FragDesc[0].FragLen = (UINT32) MacHeaderSize; + cpb->FragDesc[1].FragAddr = (UINT64) (UINTN) BufferPtr; + cpb->FragDesc[1].FragLen = (UINT32) BufferLength; + + cpb->FragDesc[0].reserved = cpb->FragDesc[1].reserved = 0; + + if (snp->IsOldUndi) { + TempData = (UINT64) (UINTN) MacHeaderPtr; + if (TempData >= FOUR_GIGABYTES) { + cpb->FragDesc[0].FragAddr = (UINT64) (UINTN) snp->fill_hdr_buf; + cpb->FragDesc[0].FragLen = (UINT32) snp->init_info.MediaHeaderLen; + } + + TempData = (UINT64) (UINTN) (BufferPtr); + if (TempData >= FOUR_GIGABYTES) { + // + // Let the device just read this buffer + // + Status = add_v2p ( + &pkt_v2p, + EfiPciIoOperationBusMasterRead, + BufferPtr, + BufferLength + ); + if (Status != EFI_SUCCESS) { + return Status; + } + // + // give the virtual address to UNDI and it will call back on Virt2Phys + // to get the mapped address, if it needs it + // + cpb->FragDesc[1].FragLen = (UINT32) pkt_v2p->bsize; + } + } + + snp->cdb.OpCode = PXE_OPCODE_FILL_HEADER; + snp->cdb.OpFlags = PXE_OPFLAGS_FILL_HEADER_FRAGMENTED; + + snp->cdb.DBsize = PXE_DBSIZE_NOT_USED; + snp->cdb.DBaddr = PXE_DBADDR_NOT_USED; + + snp->cdb.CPBsize = sizeof (PXE_CPB_FILL_HEADER_FRAGMENTED); + snp->cdb.CPBaddr = (UINT64) (UINTN) cpb; + + snp->cdb.StatCode = PXE_STATCODE_INITIALIZE; + snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE; + snp->cdb.IFnum = snp->if_num; + snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST; + + // + // Issue UNDI command and check result. + // + DEBUG ((EFI_D_NET, "\nsnp->undi.fill_header() ")); + + (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb); + + if (snp->IsOldUndi) { + TempData = (UINT64) (UINTN) (BufferPtr); + if (TempData >= FOUR_GIGABYTES) { + del_v2p (BufferPtr); + } + // + // if we used the global buffer for header, copy the contents + // + TempData = (UINT64) (UINTN) MacHeaderPtr; + if (TempData >= FOUR_GIGABYTES) { + CopyMem ( + MacHeaderPtr, + snp->fill_hdr_buf, + snp->init_info.MediaHeaderLen + ); + } + } + + switch (snp->cdb.StatCode) { + case PXE_STATCODE_SUCCESS: + return EFI_SUCCESS; + + case PXE_STATCODE_INVALID_PARAMETER: + DEBUG ( + (EFI_D_ERROR, + "\nsnp->undi.fill_header() %xh:%xh\n", + snp->cdb.StatFlags, + snp->cdb.StatCode) + ); + + return EFI_INVALID_PARAMETER; + + default: + DEBUG ( + (EFI_D_ERROR, + "\nsnp->undi.fill_header() %xh:%xh\n", + snp->cdb.StatFlags, + snp->cdb.StatCode) + ); + + return EFI_DEVICE_ERROR; + } +} + +EFI_STATUS +pxe_transmit ( + SNP_DRIVER *snp, + VOID *BufferPtr, + UINTN BufferLength + ) +/*++ + +Routine Description: + This routine calls undi to transmit the given data buffer + +Arguments: + snp - pointer to SNP driver structure + BufferPtr - data buffer pointer + BufferLength - Size of data in the BufferPtr + +Returns: + EFI_SUCCESS - if successfully completed the undi call + Other - error return from undi call. + +--*/ +{ + PXE_CPB_TRANSMIT *cpb; + EFI_STATUS Status; + struct s_v2p *v2p; + UINT64 TempData; + + cpb = snp->cpb; + cpb->FrameAddr = (UINT64) (UINTN) BufferPtr; + cpb->DataLen = (UINT32) BufferLength; + + TempData = (UINT64) (UINTN) BufferPtr; + if (snp->IsOldUndi && (TempData >= FOUR_GIGABYTES)) { + // + // we need to create a mapping now and give it to the undi when it calls + // the Virt2Phys on this address. + // this is a transmit, just map it for the device to READ + // + Status = add_v2p ( + &v2p, + EfiPciIoOperationBusMasterRead, + BufferPtr, + BufferLength + ); + if (Status != EFI_SUCCESS) { + return Status; + } + + cpb->DataLen = (UINT32) v2p->bsize; + } + + cpb->MediaheaderLen = 0; + cpb->reserved = 0; + + snp->cdb.OpFlags = PXE_OPFLAGS_TRANSMIT_WHOLE; + + snp->cdb.CPBsize = sizeof (PXE_CPB_TRANSMIT); + snp->cdb.CPBaddr = (UINT64) (UINTN) cpb; + + snp->cdb.OpCode = PXE_OPCODE_TRANSMIT; + snp->cdb.DBsize = PXE_DBSIZE_NOT_USED; + snp->cdb.DBaddr = PXE_DBADDR_NOT_USED; + + snp->cdb.StatCode = PXE_STATCODE_INITIALIZE; + snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE; + snp->cdb.IFnum = snp->if_num; + snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST; + + // + // Issue UNDI command and check result. + // + DEBUG ((EFI_D_NET, "\nsnp->undi.transmit() ")); + DEBUG ((EFI_D_NET, "\nsnp->cdb.OpCode == %x", snp->cdb.OpCode)); + DEBUG ((EFI_D_NET, "\nsnp->cdb.CPBaddr == %X", snp->cdb.CPBaddr)); + DEBUG ((EFI_D_NET, "\nsnp->cdb.DBaddr == %X", snp->cdb.DBaddr)); + DEBUG ((EFI_D_NET, "\ncpb->FrameAddr == %X\n", cpb->FrameAddr)); + + (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb); + + DEBUG ((EFI_D_NET, "\nexit snp->undi.transmit() ")); + DEBUG ((EFI_D_NET, "\nsnp->cdb.StatCode == %r", snp->cdb.StatCode)); + + // + // we will unmap the buffers in get_status call, not here + // + switch (snp->cdb.StatCode) { + case PXE_STATCODE_SUCCESS: + return EFI_SUCCESS; + + case PXE_STATCODE_QUEUE_FULL: + case PXE_STATCODE_BUSY: + Status = EFI_NOT_READY; + break; + + default: + Status = EFI_DEVICE_ERROR; + } + + DEBUG ( + (EFI_D_ERROR, + "\nsnp->undi.transmit() %xh:%xh\n", + snp->cdb.StatFlags, + snp->cdb.StatCode) + ); + + return Status; +} + +EFI_STATUS +EFIAPI +snp_undi32_transmit ( + IN EFI_SIMPLE_NETWORK_PROTOCOL * this, + IN UINTN MacHeaderSize, + IN UINTN BufferLength, + IN VOID *BufferPtr, + IN EFI_MAC_ADDRESS * SourceAddrPtr OPTIONAL, + IN EFI_MAC_ADDRESS * DestinationAddrPtr OPTIONAL, + IN UINT16 *ProtocolPtr OPTIONAL + ) +/*++ + +Routine Description: + This is the snp interface routine for transmitting a packet. this routine + basically retrieves the snp structure, checks the snp state and calls + pxe_fill_header and pxe_transmit calls to complete the transmission. + +Arguments: + this - pointer to SNP driver context + MacHeaderSize - size of the memory at MacHeaderPtr + BufferLength - Size of data in the BufferPtr + BufferPtr - data buffer pointer + SourceAddrPtr - address of the source mac address buffer + DestinationAddrPtr - address of the destination mac address buffer + ProtocolPtr - address of the protocol type + +Returns: + EFI_SUCCESS - if successfully completed the undi call + Other - error return from undi call. + +--*/ +{ + SNP_DRIVER *snp; + EFI_STATUS Status; + + if (this == NULL) { + return EFI_INVALID_PARAMETER; + } + + snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this); + + if (snp == NULL) { + return EFI_DEVICE_ERROR; + } + + switch (snp->mode.State) { + case EfiSimpleNetworkInitialized: + break; + + case EfiSimpleNetworkStopped: + return EFI_NOT_STARTED; + + case EfiSimpleNetworkStarted: + return EFI_DEVICE_ERROR; + + default: + return EFI_DEVICE_ERROR; + } + + if (BufferPtr == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (BufferLength < snp->mode.MediaHeaderSize) { + return EFI_BUFFER_TOO_SMALL; + } + + // + // if the MacHeaderSize is non-zero, we need to fill up the header and for that + // we need the destination address and the protocol + // + if (MacHeaderSize != 0) { + if (MacHeaderSize != snp->mode.MediaHeaderSize || DestinationAddrPtr == 0 || ProtocolPtr == 0) { + return EFI_INVALID_PARAMETER; + } + + Status = pxe_fillheader ( + snp, + BufferPtr, + MacHeaderSize, + (UINT8 *) BufferPtr + MacHeaderSize, + BufferLength - MacHeaderSize, + DestinationAddrPtr, + SourceAddrPtr, + ProtocolPtr + ); + + if (Status != EFI_SUCCESS) { + return Status; + } + } + + return pxe_transmit (snp, BufferPtr, BufferLength); +} diff --git a/EdkModulePkg/Universal/PCD/Common/PcdCommon.c b/EdkModulePkg/Universal/PCD/Common/PcdCommon.c new file mode 100644 index 0000000000..1af93c18d8 --- /dev/null +++ b/EdkModulePkg/Universal/PCD/Common/PcdCommon.c @@ -0,0 +1,592 @@ +/** @file +Common functions used by PCD PEIM and PCD DXE. + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +Module Name: PcdCommon.c + +**/ +#include "PcdCommon.h" + + + +/** + The function retrieves the PCD data value according to + the PCD_DATA_TYPE specified. + + @param[in] Type The PCD_DATA_TYPE used to interpret the data. + @param[in] InData The input data. + @param[in] OutData The output data. + @param[in] Len The length of the data; it is mainly used for PcdPointer type. + + @retval VOID +--*/ +VOID +GetDataBasedOnType ( + IN PCD_DATA_TYPE Type, + IN VOID *InData, + OUT VOID *OutData, + IN UINTN Len + ) +{ + if (Type == PcdPointer) { + // + // When the Type is PcdPointer, we are returning + // the address of the internal buffer kpet by + // PCD database. Therefore, we treat OutData as + // a pointer to a "VOID *". Thus, the ugly type cast + // (VOID **) is used. + // + + *((VOID **) OutData) = InData; + } else { + CopyMem (OutData, InData, Len); + } + + return; + +} + +UINTN +GetExtendedDataOffset ( + IN CONST PCD_INDEX *PcdIndex, + IN UINTN SkuIdx, + IN CONST PCD_DATABASE_HEADER *Info + ) +{ + UINT8 *OffsetAddress; + UINTN Offset; + + OffsetAddress = GetAbsoluteAddress (PcdIndex->ExtendedDataOffset, + Info->ImageIndexOffset, + Info + ); + + OffsetAddress += (SkuIdx * Info->ExtendedOffsetLength); + + + CopyMem (&Offset, OffsetAddress, Info->ExtendedOffsetLength); + + return Offset; +} + + + +VOID +GetHiiDataProperty ( + IN CONST PCD_INDEX *PcdIndex, + IN UINTN SkuIdx, + IN CONST PCD_DATABASE_HEADER *Info, + OUT EFI_GUID **VariableGuid, + OUT UINT16 **VariableName + ) +{ + UINT16 NameOffset; + UINT16 GuidOffset; + UINT8 *HiiDataOffset; + + HiiDataOffset = GetAbsoluteAddress (PcdIndex->HiiData, Info->ImageIndexOffset, Info); + HiiDataOffset += (SkuIdx * (Info->HiiGuidOffsetLength + Info->HiiVariableOffsetLength)); + + CopyMem (&GuidOffset, HiiDataOffset, Info->HiiGuidOffsetLength); + CopyMem (&NameOffset, HiiDataOffset + Info->HiiGuidOffsetLength, Info->HiiVariableOffsetLength); + + *VariableGuid = (EFI_GUID *) GetAbsoluteAddress (GuidOffset * sizeof (EFI_GUID), Info->GuidTableOffset, Info); + *VariableName = (UINT16 *) GetAbsoluteAddress (NameOffset * sizeof (UINT16) , Info->StringTableOffset, Info); + + return; +} + + + +UINTN +GetSkuIdIdx ( + IN CONST PCD_INDEX *PcdIndex, + IN CONST PCD_DATABASE_HEADER *Info + ) +{ + UINT8 *SkuIdArray; + UINTN SkuIdx; + + SkuIdArray = GetAbsoluteAddress (PcdIndex->SkuIdArray, Info->ImageIndexOffset, Info); + + SkuIdx = 0; + + if (PcdIndex->StateByte.SkuEnable) { + + for (; SkuIdx < PcdIndex->SkuCount; SkuIdx++) { + if (SkuIdArray[SkuIdx] == Info->SkuId) { + break; + } + } + + if (SkuIdx > PcdIndex->SkuCount) { + if (Info->SkuId == 0) { + // + // If no SKU_ID is set previously + // Just retrieve the first value + // + SkuIdx = 0; + } else { + // + // Just can't find the SKU_ID, ASSERT according to Spec. + // + ASSERT (FALSE); + } + } + + } + + return SkuIdx; + +} + + + +/** + The function is the worker function to get the data of a PCD entry. + + @param[in] PcdIndex The PCD Index. + @param[in] Info The attributes of the PCD database. + @param[out] Data The output data. + + @retval VOID +--*/ +UINT8* +GetPcdDataPtr ( + IN CONST PCD_INDEX *PcdIndex, + IN CONST PCD_DATABASE_HEADER *Info + ) +{ + UINTN VariableDataSize; + VOID *VariableData; + UINT16 *VariableName; + UINT8 *PcdData; + EFI_GUID *VariableGuid; + EFI_STATUS Status; + UINTN SkuIdx; + UINTN ExtendedOffset; + + // + // If Sku is not enalbed for this PCD Entry. + // SkuIdx 0 will be used to compute PcdData + // + SkuIdx = GetSkuIdIdx (PcdIndex, Info); + + if (PcdIndex->StateByte.HiiEnable) { + + GetHiiDataProperty (PcdIndex, SkuIdx, Info, &VariableGuid, &VariableName); + + Status = GetHiiVariable (VariableGuid, VariableName, &VariableData, &VariableDataSize); + ASSERT_EFI_ERROR (Status); + ASSERT (VariableDataSize >= (PcdIndex->DatumSize + PcdIndex->ExtendedDataOffset)); + + PcdData = (UINT8 *) VariableData + PcdIndex->ExtendedDataOffset; + + return PcdData; + } + + // + // For VPD and Data type, we need the ExtendedOffset. + // So get it here. + // + ExtendedOffset = GetExtendedDataOffset (PcdIndex, SkuIdx, Info); + + if (PcdIndex->StateByte.VpdEnable) { + + PcdData = (VOID *) (Info->VpdStart + ExtendedOffset); + + return PcdData; + } + + // + // For data type, we just need the pointer + // + PcdData = GetAbsoluteAddress ( + ExtendedOffset, + Info->DataBufferOffset, + Info + ); + + return PcdData; + +} + + + +/** + The function locates the PCD_INDEX according to TokeNumber and GUID space given. + + @param[in] TokenNumber The token number. + @param[in] Guid The GUID token space. + @param[out] Info The attributes of the PCD database. + + @retval PCD_INDEX* The PCD_INDEX found. +--*/ +PCD_INDEX * +FindPcdIndex ( + IN UINTN TokenNumber, + IN CONST EFI_GUID *Guid, + IN CONST PCD_DATABASE_HEADER *Info, + OUT UINTN *Index + ) +{ + PCD_INDEX *PcdIndex; + UINTN Idx; + EFI_GUID *GuidSpace; + + PcdIndex = (PCD_INDEX *) GetAbsoluteAddress (0, Info->PcdIndexOffset, Info); + + for (Idx = 0; Idx < Info->EntryCount; Idx++, PcdIndex++) { + if (Index != NULL) { + *Index = Idx; + } + + if (PcdIndex->TokenNumber == TokenNumber) { + if (Guid == NULL) { + if (!PcdIndex->StateByte.ExtendedGuidPresent) { + return PcdIndex; + } + } else { + if (PcdIndex->StateByte.ExtendedGuidPresent) { + GuidSpace = (EFI_GUID *) GetAbsoluteAddress (PcdIndex->DynamicExGuid, Info->GuidTableOffset, Info); + if (CompareGuid (GuidSpace, Guid)) { + return PcdIndex; + } + } + } + } + + } + + if (Index != NULL) { + *Index = 0; + } + + return NULL; + +} + + + +/** + The function set the PCD Entry data value according to the + PCD_DATA_TYPE given. + + @param[out] OutData The output data. + @param[in] InData The input data. + @param[in] Len The length of the data. + + + @retval EFI_SUCESS If data value is found according to SKU_ID. + @retval EFI_NOT_FOUND If not such a value is found. + +--*/ +VOID +SetDataBasedOnType ( + OUT VOID * OutData, + IN CONST VOID * InData, + IN UINTN Len +) +{ + CopyMem (OutData, InData, Len); + + return; +} + + + +/** + The function returns the actual address of item in the PCD + database according to its Segment and Offset. + + @param[out] Offset The offset within the segment. + @param[in] SegmentStart The starting address of the segment. + @param[in] DatabaseStart The base address of the PCD DataBase. + + + @retval UINT8* The absolute address. + +--*/ +UINT8 * +GetAbsoluteAddress ( + IN UINTN Offset, + IN UINTN SegmentStart, + IN CONST PCD_DATABASE_HEADER *DatabaseStart + ) +{ + UINT8 *Address; + + Address = (UINT8 *) DatabaseStart + SegmentStart + Offset; + + return Address; +} + + + +/** + The function retrieves the PCD data value according to + TokenNumber and Guid space given. + + @param[in] Database The PCD Database Instance. + @param[in] TokenNumber The token number. + @param[in] Guid The Guid space. + @param[in] Type The storage type. + @param[out] Data The output data. + + @retval VOID + +--*/ +VOID +GetPcdEntryWorker ( + IN CONST PCD_DATABASE_HEADER *Info, + IN UINTN TokenNumber, + IN CONST EFI_GUID *Guid, OPTIONAL + IN PCD_DATA_TYPE Type, + OUT VOID *Data + ) +{ + PCD_INDEX *PcdIndex; + UINT8 *PcdData; + + ASSERT (Data != NULL); + + // + // Find the PCD entry in list in memory first + // + PcdIndex = FindPcdIndex (TokenNumber, Guid, Info, NULL); + + ASSERT (PcdIndex != NULL); + + ASSERT (PcdIndex->StateByte.DataType == Type); + + PcdData = GetPcdDataPtr (PcdIndex, Info); + + GetDataBasedOnType (PcdIndex->StateByte.DataType, PcdData, Data, PcdIndex->DatumSize); + + return; +} + + + +/** + The function retrieves the PCD data value according to + TokenNumber and Guid space given. + + @param[in] Database The PCD Database Instance. + @param[in] TokenNumber The token number. + @param[in] Guid The Guid space. + + @retval UINTN The size of the PCD Entry. + +--*/ +UINTN +GetPcdEntrySizeWorker ( + IN CONST PCD_DATABASE_HEADER *Info, + IN UINTN TokenNumber, + IN CONST EFI_GUID *Guid OPTIONAL + ) +{ + PCD_INDEX *PcdIndex; + + // + // Find the PCD entry in list in memory first + // + PcdIndex = FindPcdIndex (TokenNumber, Guid, Info, NULL); + + ASSERT (PcdIndex != NULL); + + return PcdIndex->DatumSize; + +} + + + +/** + The function checks if given GUID space match the record + in the PCD_INDEX. + + @param[in] Guid The GUID space. + @param[in] PcdIndex The PCD_INDEX. + @param[in] Info The attribute of the PCD DATABASE. + + @retval TRUE The GUID space match the record. + @retval FALSE Othewise. + +--*/ +BOOLEAN +PeiImageIndexMatchGuidSpace ( + IN CONST EFI_GUID *Guid, + IN CONST PCD_INDEX *PcdIndex, + IN CONST PCD_DATABASE_HEADER *Info +) +{ + EFI_GUID *GuidSpace; + + if (PcdIndex->StateByte.ExtendedGuidPresent) { + GuidSpace = (EFI_GUID *) GetAbsoluteAddress (PcdIndex->DynamicExGuid, Info->GuidTableOffset, Info); + return CompareGuid (GuidSpace, Guid); + } + + return FALSE; +} + + +/** + The function looks for the next PCD ENTRY. + If *TokenNumber is 0, the first TokenNumber in + the GUID token space is return. + If there is no next TokenNumber found, + *TokenNumber will be 0. + + @param[in] Database The PCD Database Instance. + @param[in,out] TokenNumber The token number. + @param[in] Guid The Guid space. + + @retval EFI_NOT_FOUND Can't find the PCD_ENTRY. + @retval EFI_SUCCESS Operation succesful. + +--*/ +EFI_STATUS +GetNextTokenWorker ( + IN CONST PCD_DATABASE_HEADER *Info, + IN OUT UINTN *TokenNumber, + IN CONST EFI_GUID *Guid OPTIONAL + ) +{ + PCD_INDEX *PcdIndex; + UINTN Idx; + BOOLEAN Found; + + Idx = 0; + Found = FALSE; + PcdIndex = (PCD_INDEX *) GetAbsoluteAddress (0, Info->PcdIndexOffset, Info); + + while ((Idx < Info->EntryCount) && !Found) { + if (*TokenNumber == 0) { + if (Guid == NULL || PeiImageIndexMatchGuidSpace (Guid, PcdIndex, Info)) { + *TokenNumber = PcdIndex->TokenNumber; + return EFI_SUCCESS; + } + } else { + if (PcdIndex->TokenNumber == *TokenNumber) { + if (Guid == NULL || PeiImageIndexMatchGuidSpace (Guid, PcdIndex, Info)) { + Found = TRUE; + } + } + } + + PcdIndex++; + Idx++; + } + + // + // No PCD Entry in the database match the GUID space given. + // + if (*TokenNumber == 0) { + return EFI_SUCCESS; + } + + // + // Can't find the PCD Entry + // + if (!Found) { + return EFI_NOT_FOUND; + } + + // + // Move to the Next Entry + // + Idx++; + PcdIndex++; + + // + // Now look for the Next TokenNumber + // + while (Idx < Info->EntryCount) { + if (Guid == NULL || PeiImageIndexMatchGuidSpace (Guid, PcdIndex, Info)) { + *TokenNumber = PcdIndex->TokenNumber; + return EFI_SUCCESS; + } + PcdIndex++; + Idx++; + } + + // + // Reache the last TokeNumber. + // + *TokenNumber = 0; + return EFI_SUCCESS; +} + + +/** + The function is the worker function to set the data of a PCD entry. + + @param[in] PcdIndex The PCD Index. + @param[in] Info The attributes of the PCD database. + @param[in] Data The input data. + + @retval VOID +--*/ +EFI_STATUS +SetPcdData ( + IN CONST PCD_INDEX *PcdIndex, + IN CONST PCD_DATABASE_HEADER *Info, + IN CONST VOID *Data + ) +{ + UINT16 *VariableName; + UINT8 *PcdData; + EFI_GUID *VariableGuid; + EFI_STATUS Status; + UINTN SkuIdx; + UINTN ExtendedOffset; + + if (PcdIndex->StateByte.VpdEnable) { + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + SkuIdx = GetSkuIdIdx (PcdIndex, Info); + + // + // For Hii and Data type, we need the ExtendedOffset. + // So get it here. + // + ExtendedOffset = GetExtendedDataOffset (PcdIndex, SkuIdx, Info); + + if (PcdIndex->StateByte.HiiEnable) { + GetHiiDataProperty (PcdIndex, SkuIdx, Info, &VariableGuid, &VariableName); + + Status = SetHiiVariable (VariableGuid, + VariableName, + Data, + PcdIndex->DatumSize, + ExtendedOffset + ); + + return Status; + } + + + PcdData = GetAbsoluteAddress ( + ExtendedOffset, + Info->DataBufferOffset, + Info + ); + + CopyMem (PcdData, Data, PcdIndex->DatumSize); + + return EFI_SUCCESS; + +} + diff --git a/EdkModulePkg/Universal/PCD/Common/PcdCommon.h b/EdkModulePkg/Universal/PCD/Common/PcdCommon.h new file mode 100644 index 0000000000..f61aa5be6a --- /dev/null +++ b/EdkModulePkg/Universal/PCD/Common/PcdCommon.h @@ -0,0 +1,386 @@ +/** @file +Common functions used by PCD PEIM and PCD DXE. + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +Module Name: PcdCommon.h + +**/ + +#ifndef __PCD_COMMON_H__ +#define __PCD_COMMON_H__ + +// +// Enumeration for PCD_DATA_TYPE +// +typedef enum { + PcdByte8, + PcdByte16, + PcdByte32, + PcdByte64, + PcdPointer, + PcdBoolean +} PCD_DATA_TYPE; + + +// +// The definitions for Global PCD Length Fields +// +#define PCD_LENGTH_BIT8 0x01 +#define PCD_LENGTH_BIT16 0x02 +#define PCD_LENGTH_BIT24 0x03 +#define PCD_LENGTH_BIT32 0x04 + + + +/* + * This data structure is used in transverse + */ +typedef struct { + UINTN EntryCount; + UINTN GlobalOffsetLength; + UINTN GlobalTokenLength; + UINTN GlobalGuidTabIdxLength; + UINTN GlobalDatumLength; + UINTN GlobalStrTabIdxLength; + + CONST UINT8 *DataDefaultStart; + UINTN DataDefaultLength; + UINTN WholeDataDefaultLength; + CONST UINT8 *IndexStart; + UINTN IndexLength; + CONST GUID *GuidTableStart; + UINTN GuidTableLength; + CONST UINT16 *StringTableStart; + UINTN StringTableLength; + /* Length of the in byte. + This info is from Section header + in FFS */ + UINTN ImageLength; + CONST UINT8 *ImageStart; + +} PCD_IMAGE_RECORD; + + + +typedef struct { + BOOLEAN HiiEnable; + BOOLEAN SkuEnable; + BOOLEAN VpdEnable; + BOOLEAN SkuDataArrayEnable; + PCD_DATA_TYPE DataType; + BOOLEAN ExtendedGuidPresent; +} PCD_STATEBYTE; + + + +typedef struct { + // + // All Pointer's Offset in byte + // + UINT32 TokenNumber; + PCD_STATEBYTE StateByte; + UINT32 HiiData; + UINT32 SkuIdArray; //Pointer + UINT32 ExtendedDataOffset; + UINT32 DatumSize; + UINT16 DynamicExGuid; //Pointer + UINT8 SkuCount; +} PCD_INDEX; + + + +/* + * PCD Image Definition according PCD Specification 0.51. + * + */ +#pragma pack(1) +typedef struct { + UINT8 ImageLength[3]; + // + // The length of PCD_FFS_ENCODING is included + // in ImageLength + // + UINT8 DataBufferLength[3]; + UINT8 WholeDataBufferLength[3]; + UINT8 PcdIndexLength[3]; + UINT8 GuidTableLength[3]; + // + // The StringTable can be computed using: + // ImageLength, DataBufferLength, PcdIndexLength, GuidTableLength, + // and length of PCD_FFS_ENCODING + // + UINT8 EntryCount[3]; + UINT8 GlobalOffsetLength[1]; + UINT8 GlobalTokenLength[1]; + UINT8 GuidLength[1]; + UINT8 GlobalDatumLength[1]; + UINT8 GlobalStrTabIdxLength[1]; +} PCD_FFS_ENCODING; +#pragma pack() + + + +typedef struct { + UINTN DatabaseLen; + UINTN EntryCount; + UINTN InfoLength; + UINTN GuidTableOffset; + UINTN PcdIndexOffset; + UINTN StringTableOffset; + UINTN CallbackTableOffset; + UINTN ImageIndexOffset; + UINTN DataBufferOffset; + UINTN MaxCallbackNum; + UINTN HiiVariableOffsetLength; + UINTN HiiGuidOffsetLength; + UINTN ExtendedOffsetLength; + UINT8 *VpdStart; + UINTN SkuId; +} PCD_DATABASE_HEADER; + + + +typedef struct { + PCD_DATABASE_HEADER Info; + EFI_GUID GuidTable[1]; +} PCD_DATABASE; + +extern EFI_GUID gPcdDataBaseHobGuid; + + +/** + The function returns the actual address of item in the PCD + database according to its Segment and Offset. + + @param[out] Offset The offset within the segment. + @param[in] SegmentStart The starting address of the segment. + @param[in] DatabaseStart The base address of the PCD DataBase. + + + @retval EFI_SUCESS If data value is found according to SKU_ID. + @retval EFI_NOT_FOUND If not such a value is found. + +--*/ +UINT8 * +GetAbsoluteAddress ( + IN UINTN Offset, + IN UINTN SegmentStart, + IN CONST VOID *Base + ) +; + + + +/** + The function return the number of Unicode Character in a NULL terminated string. + The NULL is NOT counted. + + @param[in] String The unicode string starts from an unaligned address. + + @retval UINTN The number of Unicode characters. +--*/ +UINTN +GetUnalignedStrLen ( + UINT16 *String +); + + +/** + The function retrieves the PCD data value according to + TokenNumber and Guid space given. + + @param[in] Info The PCD Database Info. + @param[in] TokenNumber The token number. + @param[in] Guid The Guid space. + @param[in] Type The storage type. + @param[out] Data The output data. + + @retval VOID + +--*/ +VOID +GetPcdEntryWorker ( + IN CONST PCD_DATABASE_HEADER *Info, + IN UINTN TokenNumber, + IN CONST GUID *Guid, OPTIONAL + IN PCD_DATA_TYPE Type, + OUT VOID *Data + ) +; + + + +/** + The function retrieves the PCD data value according to + TokenNumber and Guid space given. + + @param[in] Info The PCD Database info. + @param[in] TokenNumber The token number. + @param[in] Guid The Guid space. + + @retval UINTN The size of the PCD Entry. + +--*/ +UINTN +GetPcdEntrySizeWorker ( + IN CONST PCD_DATABASE_HEADER *Info, + IN UINTN TokenNumber, + IN CONST GUID *Guid OPTIONAL + ) +; + + + +/** + The function looks for the next PCD ENTRY. + If *TokenNumber is 0, the first TokenNumber in + the GUID token space is return. + If there is no next TokenNumber found, + *TokenNumber will be 0. + + @param[in] Info The PCD Database info. + @param[in,out] TokenNumber The token number. + @param[in] Guid The Guid space. + + @retval EFI_NOT_FOUND Can't find the PCD_ENTRY. + @retval EFI_SUCCESS Operation succesful. + +--*/ +EFI_STATUS +GetNextTokenWorker ( + IN CONST PCD_DATABASE_HEADER *Info, + IN OUT UINTN *TokenNumber, + IN CONST GUID *Guid OPTIONAL + ) +; + + + +/** + The function is the worker function to set the data of a PCD entry. + + @param[in] PcdIndex The PCD Index. + @param[in] Info The attributes of the PCD database. + @param[in] Data The input data. + + @retval VOID +--*/ +EFI_STATUS +SetPcdData ( + IN CONST PCD_INDEX *PcdIndex, + IN CONST PCD_DATABASE_HEADER *Info, + IN CONST VOID *Data + ) +; + + +/** + The function is provided by PCD PEIM and PCD DXE driver to + do the work of reading a HII variable from variable service. + + @param[in] VariableGuid The Variable GUID. + @param[in] VariableName The Variable Name. + @param[out] VariableData The output data. + @param[out] VariableSize The size of the variable. + + @retval EFI_SUCCESS Operation successful. + @retval EFI_SUCCESS Variablel not found. +--*/ +EFI_STATUS +GetHiiVariable ( + IN EFI_GUID *VariableGuid, + IN UINT16 *VariableName, + OUT VOID **VariableData, + OUT UINTN *VariableSize + ) +; + + + +/** + The function is provided by PCD PEIM and PCD DXE driver to + do the work of reading a HII variable from variable service. + + @param[in] VariableGuid The Variable GUID. + @param[in] VariableName The Variable Name. + @param[in] Data The input data. + @param[out] VariableSize The size of the variable. + @param[in] Offset The offset of the variable data that a PCD entry will starts from. + + @retval EFI_SUCCESS Operation successful. + @retval EFI_SUCCESS Variablel not found. +--*/ +EFI_STATUS +SetHiiVariable ( + IN EFI_GUID *VariableGuid, + IN UINT16 *VariableName, + IN CONST VOID *Data, + IN UINTN VariableSize, + IN UINTN Offset + ) +; + +/** + The function locates the PCD_INDEX according to TokeNumber and GUID space given. + + @param[in] TokenNumber The token number. + @param[in] Guid The GUID token space. + @param[out] Info The attributes of the PCD database. + + @retval PCD_INDEX* The PCD_INDEX found. +--*/ +PCD_INDEX * +FindPcdIndex ( + IN UINTN TokenNumber, + IN CONST GUID *Guid, + IN CONST PCD_DATABASE_HEADER *Info, + OUT UINTN *Index + ) +; + +/** + (WQBUGBUG: You must handle the new SKU_ID encoding. + The function is the worker function to get the data of a PCD entry. + + @param[in] PcdIndex The PCD Index. + @param[in] Info The attributes of the PCD database. + @param[out] Data The output data. + + @retval VOID +--*/ +UINT8* +GetPcdDataPtr ( + IN CONST PCD_INDEX *PcdIndex, + IN CONST PCD_DATABASE_HEADER *Info + ) +; + +/** + The function retrieves the PCD data value according to + the PCD_DATA_TYPE specified. + + @param[in] Type The PCD_DATA_TYPE used to interpret the data. + @param[in] InData The input data. + @param[in] OutData The output data. + @param[in] Len The length of the data; it is mainly used for PcdPointer type. + + @retval VOID +--*/ +VOID +GetDataBasedOnType ( + IN PCD_DATA_TYPE Type, + IN VOID *InData, + OUT VOID *OutData, + IN UINTN Len + ) +; +#endif diff --git a/EdkModulePkg/Universal/PCD/Dxe/Pcd.c b/EdkModulePkg/Universal/PCD/Dxe/Pcd.c new file mode 100644 index 0000000000..4ed7eb0cd0 --- /dev/null +++ b/EdkModulePkg/Universal/PCD/Dxe/Pcd.c @@ -0,0 +1,472 @@ +/** @file +PCD DXE driver + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +Module Name: Pcd.c + +**/ + +#include "../Common/PcdCommon.h" +#include "Service.h" + + +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, + + PcdRegisterCallBackOnSet, + PcdUnRegisterCallBackOnSet, + DxePcdGetNextToken +}; + + +// +// Static global to reduce the code size +// +static EFI_HANDLE NewHandle = NULL; + +EFI_STATUS +EFIAPI +PcdDxeInit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + InitPcdDxeDataBase (); + + Status = gBS->InstallProtocolInterface ( + &NewHandle, + &gPcdProtocolGuid, + EFI_NATIVE_INTERFACE, + &mPcdInstance + ); + + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; + +} + + +EFI_STATUS +EFIAPI +DxePcdSetSku ( + IN UINTN SkuId + ) +{ + return DxeSetSku(SkuId); +} + + + +UINT8 +EFIAPI +DxePcdGet8 ( + IN UINTN TokenNumber + ) +{ + return DxePcdGet8Ex (NULL, TokenNumber); +} + + + +UINT16 +EFIAPI +DxePcdGet16 ( + IN UINTN TokenNumber + ) +{ + return DxePcdGet16Ex (NULL, TokenNumber); +} + + + +UINT32 +EFIAPI +DxePcdGet32 ( + IN UINTN TokenNumber + ) +{ + return DxePcdGet32Ex (NULL, TokenNumber); +} + + + +UINT64 +EFIAPI +DxePcdGet64 ( + IN UINTN TokenNumber + ) +{ + return DxePcdGet32Ex (NULL, TokenNumber); +} + + + +VOID * +EFIAPI +DxePcdGetPtr ( + IN UINTN TokenNumber + ) +{ + return DxePcdGetPtrEx (NULL, TokenNumber); +} + + + +BOOLEAN +EFIAPI +DxePcdGetBool ( + IN UINTN TokenNumber + ) +{ + return DxePcdGetBoolEx (NULL, TokenNumber); +} + + + +UINTN +EFIAPI +DxePcdGetSize ( + IN UINTN TokenNumber + ) +{ + return DxePcdGetSizeEx (NULL, TokenNumber); +} + + + +UINT8 +EFIAPI +DxePcdGet8Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber + ) +{ + UINT8 Data; + + DxeGetPcdEntryWorker (TokenNumber, Guid, PcdByte8, &Data); + + return Data; +} + + + +UINT16 +EFIAPI +DxePcdGet16Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber + ) +{ + UINT16 Data; + + DxeGetPcdEntryWorker (TokenNumber, Guid, PcdByte16, &Data); + + return Data; +} + + + +UINT32 +EFIAPI +DxePcdGet32Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber + ) +{ + UINT32 Data; + + DxeGetPcdEntryWorker (TokenNumber, Guid, PcdByte32, &Data); + + return Data; +} + + + +UINT64 +EFIAPI +DxePcdGet64Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber + ) +{ + UINT64 Data; + + DxeGetPcdEntryWorker (TokenNumber, Guid, PcdByte64, &Data); + + return Data; +} + + + +VOID * +EFIAPI +DxePcdGetPtrEx ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber + ) +{ + VOID *Data; + + DxeGetPcdEntryWorker (TokenNumber, Guid, PcdPointer, &Data); + + return Data; +} + + + +BOOLEAN +EFIAPI +DxePcdGetBoolEx ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber + ) +{ + BOOLEAN Data; + DxeGetPcdEntryWorker (TokenNumber, Guid, PcdBoolean, &Data); + return Data; +} + + + +UINTN +EFIAPI +DxePcdGetSizeEx ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber + ) +{ + return DxeGetPcdEntrySizeWorker (TokenNumber, Guid); +} + + + +EFI_STATUS +EFIAPI +DxePcdSet8 ( + IN UINTN TokenNumber, + IN UINT8 Value + ) +{ + return DxePcdSet8Ex (NULL, TokenNumber, Value); +} + + + +EFI_STATUS +EFIAPI +DxePcdSet16 ( + IN UINTN TokenNumber, + IN UINT16 Value + ) +{ + return DxePcdSet16Ex (NULL, TokenNumber, Value); +} + + + +EFI_STATUS +EFIAPI +DxePcdSet32 ( + IN UINTN TokenNumber, + IN UINT32 Value + ) +{ + return DxePcdSet32Ex (NULL, TokenNumber, Value); +} + + + +EFI_STATUS +EFIAPI +DxePcdSet64 ( + IN UINTN TokenNumber, + IN UINT64 Value + ) +{ + return DxePcdSet64Ex (NULL, TokenNumber, Value); +} + + + +EFI_STATUS +EFIAPI +DxePcdSetPtr ( + IN UINTN TokenNumber, + IN CONST VOID *Value + ) +{ + return DxePcdSetPtrEx (NULL, TokenNumber, Value); +} + + + +EFI_STATUS +EFIAPI +DxePcdSetBool ( + IN UINTN TokenNumber, + IN BOOLEAN Value + ) +{ + return DxePcdSetBoolEx (NULL, TokenNumber, Value); +} + + + +EFI_STATUS +EFIAPI +DxePcdSet8Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN UINT8 Value + ) +{ + return DxeSetPcdEntryWorker (TokenNumber, Guid, PcdByte8, &Value); +} + + + +EFI_STATUS +EFIAPI +DxePcdSet16Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN UINT16 Value + ) +{ + return DxeSetPcdEntryWorker (TokenNumber, Guid, PcdByte16, &Value); +} + + + +EFI_STATUS +EFIAPI +DxePcdSet32Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN UINT32 Value + ) +{ + return DxeSetPcdEntryWorker (TokenNumber, Guid, PcdByte32, &Value); +} + + + +EFI_STATUS +EFIAPI +DxePcdSet64Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN UINT64 Value + ) +{ + return DxeSetPcdEntryWorker (TokenNumber, Guid, PcdByte64, &Value); +} + + + +EFI_STATUS +EFIAPI +DxePcdSetPtrEx ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN CONST VOID *Value + ) +{ + return DxeSetPcdEntryWorker (TokenNumber, Guid, PcdPointer, Value); +} + + + +EFI_STATUS +EFIAPI +DxePcdSetBoolEx ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN BOOLEAN Value + ) +{ + return DxeSetPcdEntryWorker (TokenNumber, Guid, PcdBoolean, &Value); + +} + + + + +EFI_STATUS +EFIAPI +PcdRegisterCallBackOnSet ( + IN UINTN TokenNumber, + IN CONST EFI_GUID *Guid, OPTIONAL + IN PCD_PROTOCOL_CALLBACK CallBackFunction + ) +{ + return DxeRegisterCallBackWorker (TokenNumber, Guid, CallBackFunction, TRUE); +} + + + +EFI_STATUS +EFIAPI +PcdUnRegisterCallBackOnSet ( + IN UINTN TokenNumber, + IN CONST EFI_GUID *Guid, OPTIONAL + IN PCD_PROTOCOL_CALLBACK CallBackFunction + ) +{ + return DxeRegisterCallBackWorker (TokenNumber, Guid, CallBackFunction, FALSE); +} + + + +EFI_STATUS +EFIAPI +DxePcdGetNextToken ( + IN CONST EFI_GUID *Guid, OPTIONAL + IN OUT UINTN *TokenNumber + ) +{ + return DxeGetNextTokenWorker (TokenNumber, Guid); +} + diff --git a/EdkModulePkg/Universal/PCD/Dxe/Service.c b/EdkModulePkg/Universal/PCD/Dxe/Service.c new file mode 100644 index 0000000000..280a45ea31 --- /dev/null +++ b/EdkModulePkg/Universal/PCD/Dxe/Service.c @@ -0,0 +1,491 @@ +/** @file +Private functions used by PCD DXE driver.s + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +Module Name: Service.c + +**/ +#include "../Common/PcdCommon.h" +#include "Service.h" + +static PCD_DATABASE *PrivatePcdDxeDatabase; +static LIST_ENTRY mPcdDatabaseListHead = INITIALIZE_LIST_HEAD_VARIABLE(mPcdDatabaseListHead); + +LIST_ENTRY * +GetPcdDatabaseListHead ( + VOID + ) +{ + return &mPcdDatabaseListHead; +} + +PCD_DATABASE * +GetPcdDxeDataBaseInstance ( + VOID +) +{ + return PrivatePcdDxeDatabase; +} + +PCD_DATABASE * +SetPcdDxeDataBaseInstance ( + PCD_DATABASE *PcdDatabase +) +{ + return PrivatePcdDxeDatabase = PcdDatabase; +} + + +VOID +DxeGetPcdEntryWorker ( + IN UINTN TokenNumber, + IN CONST GUID *Guid, OPTIONAL + IN PCD_DATA_TYPE Type, + OUT VOID *Data + ) +{ + PCD_DATABASE *Database; + Database = GetPcdDxeDataBaseInstance (); + + GetPcdEntryWorker ( &Database->Info, + TokenNumber, + Guid, + Type, + Data + ); + + + return; +} + + + +EFI_STATUS +DxeSetPcdEntryWorker ( + IN UINTN TokenNumber, + IN CONST GUID *Guid, OPTIONAL + IN PCD_DATA_TYPE Type, + IN CONST VOID *Data + ) +{ + PCD_DATABASE *Database; + PCD_INDEX *PcdIndex; + EFI_STATUS Status; + + Database = GetPcdDxeDataBaseInstance (); + + + ASSERT (Data != NULL); + + PcdIndex = FindPcdIndex (TokenNumber, Guid, &Database->Info, NULL); + + ASSERT (PcdIndex != NULL); + + ASSERT (PcdIndex->StateByte.DataType == Type); + + // + // Invoke the callback function. + // + + Status = SetPcdData (PcdIndex, &Database->Info, Data); + + return Status; + + +} + + + +UINTN +DxeGetPcdEntrySizeWorker ( + IN UINTN TokenNumber, + IN CONST GUID *Guid OPTIONAL + ) +{ + PCD_DATABASE *Database; + Database = GetPcdDxeDataBaseInstance (); + + return GetPcdEntrySizeWorker (&Database->Info, + TokenNumber, + Guid + ); +} + + + +LIST_ENTRY * +InsertToGuidSpaceListI ( + IN LIST_ENTRY *GuidSpaceListHead, + IN CONST EFI_GUID *Guid + ) +{ + PCD_GUID_SPACE *GuidSpaceEntry; + + GuidSpaceEntry = AllocatePool (sizeof (PCD_GUID_SPACE)); + ASSERT (GuidSpaceEntry != NULL); + + GuidSpaceEntry->GuidSpace= Guid; + InitializeListHead (&GuidSpaceEntry->TokenSpaceHead); + + InsertTailList (GuidSpaceListHead, &GuidSpaceEntry->ListNode); + + return &GuidSpaceEntry->TokenSpaceHead; +} + + + +LIST_ENTRY * +InsertToTokenSpaceListI ( + IN LIST_ENTRY *TokenSpaceListHead, + IN UINTN TokenNumber + ) +{ + PCD_TOKEN_SPACE *TokenSpaceEntry; + + TokenSpaceEntry = AllocatePool (sizeof (PCD_TOKEN_SPACE)); + ASSERT (TokenSpaceEntry != NULL); + + TokenSpaceEntry->TokeNumber = TokenNumber; + InitializeListHead (&TokenSpaceEntry->CallbackListHead); + + InsertTailList (TokenSpaceListHead, &TokenSpaceEntry->ListNode); + + return &TokenSpaceEntry->CallbackListHead; +} + + + +VOID +InsertToCallbackListI ( + IN LIST_ENTRY *CallbackListHead, + IN PCD_PROTOCOL_CALLBACK CallBackFunction + ) +{ + PCD_CALLBACK_ENTRY *CallbackEntry; + + CallbackEntry = AllocatePool (sizeof (PCD_CALLBACK_ENTRY)); + ASSERT (CallbackEntry != NULL); + CallbackEntry->CallbackFunction = CallBackFunction; + InsertTailList (CallbackListHead, &CallbackEntry->ListNode); + + return; +} + + + + +VOID +InsertToCallbackList ( + IN UINTN TokenNumber, + IN CONST EFI_GUID *Guid, + IN PCD_PROTOCOL_CALLBACK CallBackFunction + ) +{ + LIST_ENTRY *GuidListNode; + LIST_ENTRY *GuidListHead; + LIST_ENTRY *TokenListNode; + LIST_ENTRY *TokenListHead; + LIST_ENTRY *CallbackListHead; + PCD_GUID_SPACE *GuidSpaceEntry; + PCD_TOKEN_SPACE *TokenSpaceEntry; + + + GuidListHead = GetPcdDatabaseListHead (); + + GuidListNode = GetFirstNode (GuidListHead); + while (!IsNull (GuidListNode, GuidListHead)) { + GuidSpaceEntry = PCD_GUID_SPACE_FROM_LISTNODE(GuidListNode); + + if (CompareGuid (GuidSpaceEntry->GuidSpace, Guid)) { + TokenListHead = &GuidSpaceEntry->TokenSpaceHead; + TokenListNode = GetFirstNode (TokenListHead); + while (!IsNull (TokenListNode, TokenListHead)) { + TokenSpaceEntry = PCD_TOKEN_SPACE_FROM_LISTNODE(TokenListNode); + if (TokenSpaceEntry->TokeNumber == TokenNumber) { + InsertToCallbackListI (&TokenSpaceEntry->CallbackListHead , CallBackFunction); + } + } + + // + // No TokenNumber match input found in this GuidSpace + // + CallbackListHead = InsertToTokenSpaceListI (TokenListHead, TokenNumber); + InsertToCallbackListI (CallbackListHead , CallBackFunction); + } + + GuidListNode = GetNextNode (GuidListHead, GuidListNode); + } + + // + // No GuidSpace match the input Guid, so build the GuidSpace, TokenNumberSpace and Callback + // + TokenListHead = InsertToGuidSpaceListI (GuidListHead, Guid); + CallbackListHead = InsertToTokenSpaceListI (TokenListHead, TokenNumber); + InsertToCallbackListI (CallbackListHead , CallBackFunction); + + return; + +} + +EFI_STATUS +RemoveFromCallbackListI ( + IN LIST_ENTRY *CallbackListHead, + IN PCD_PROTOCOL_CALLBACK CallBackFunction + ) +{ + LIST_ENTRY *ListNode; + PCD_CALLBACK_ENTRY *CallbackEntry; + + ListNode = GetFirstNode (CallbackListHead); + + while (!IsNull(CallbackListHead, ListNode)) { + CallbackEntry = PCD_CALLBACK_ENTRY_FROM_LISTNODE(ListNode); + + if (CallbackEntry->CallbackFunction == CallBackFunction) { + RemoveEntryList (ListNode); + FreePool (CallbackEntry); + return EFI_SUCCESS; + } + ListNode = GetNextNode (CallbackListHead, ListNode); + } + + return EFI_NOT_FOUND; +} + + + +EFI_STATUS +RemoveFromCallbackList ( + IN UINTN TokenNumber, + IN CONST GUID *Guid, + IN PCD_PROTOCOL_CALLBACK CallBackFunction + ) +{ + LIST_ENTRY *GuidListNode; + LIST_ENTRY *GuidListHead; + LIST_ENTRY *TokenListNode; + LIST_ENTRY *TokenListHead; + PCD_GUID_SPACE *GuidSpaceEntry; + PCD_TOKEN_SPACE *TokenSpaceEntry; + + + GuidListHead = GetPcdDatabaseListHead (); + + GuidListNode = GetFirstNode (GuidListHead); + while (!IsNull (GuidListNode, GuidListHead)) { + + GuidSpaceEntry = PCD_GUID_SPACE_FROM_LISTNODE(GuidListNode); + if (CompareGuid (GuidSpaceEntry->GuidSpace, Guid)) { + + TokenListHead = &GuidSpaceEntry->TokenSpaceHead; + TokenListNode = GetFirstNode (TokenListHead); + while (!IsNull (TokenListNode, TokenListHead)) { + + TokenSpaceEntry = PCD_TOKEN_SPACE_FROM_LISTNODE(TokenListNode); + if (TokenSpaceEntry->TokeNumber == TokenNumber) { + return RemoveFromCallbackListI (&TokenSpaceEntry->CallbackListHead , CallBackFunction); + } + } + + // + // No TokenNumber match input found in this GuidSpace + // + return EFI_NOT_FOUND; + } + + GuidListNode = GetNextNode (GuidListHead, GuidListNode); + } + + + return EFI_NOT_FOUND; + +} + + + +EFI_STATUS +DxeRegisterCallBackWorker ( + IN UINTN TokenNumber, + IN CONST GUID *Guid, OPTIONAL + IN PCD_PROTOCOL_CALLBACK CallBackFunction, + IN BOOLEAN Register +) +{ + PCD_DATABASE *Database; + PCD_INDEX *PcdIndex; + + Database = GetPcdDxeDataBaseInstance (); + + PcdIndex = FindPcdIndex (TokenNumber, Guid, &Database->Info, NULL); + + if (PcdIndex == NULL) { + return EFI_NOT_FOUND; + } + + if (Register) { + InsertToCallbackList (TokenNumber, Guid, CallBackFunction); + return EFI_SUCCESS; + } else { + return RemoveFromCallbackList (TokenNumber, Guid, CallBackFunction); + } + + } + + + +EFI_STATUS +DxeSetSku ( + UINTN Id +) +{ + PCD_DATABASE * Database; + + Database = GetPcdDxeDataBaseInstance (); + + return Database->Info.SkuId = Id; + +} + + + +EFI_STATUS +DxeGetNextTokenWorker ( + IN OUT UINTN *TokenNumber, + IN CONST GUID *Guid OPTIONAL + ) +{ + PCD_DATABASE * Database; + + Database = GetPcdDxeDataBaseInstance (); + + return GetNextTokenWorker (&Database->Info, + TokenNumber, + Guid + ); +} + + + +VOID +InitPcdDxeDataBase ( + VOID +) +{ + PCD_DATABASE *PeiDatabase; + PCD_DATABASE *DxeDatabase; + EFI_HOB_GUID_TYPE *GuidHob; + + GuidHob = GetFirstGuidHob (&gPcdDataBaseHobGuid); + ASSERT (GuidHob != NULL); + + PeiDatabase = (PCD_DATABASE *) GET_GUID_HOB_DATA (GuidHob); + + DxeDatabase = AllocateCopyPool (PeiDatabase->Info.DatabaseLen, PeiDatabase); + + ASSERT (DxeDatabase != NULL); + + SetPcdDxeDataBaseInstance (DxeDatabase); + + return; +} + + + +EFI_STATUS +GetHiiVariable ( + IN EFI_GUID *VariableGuid, + IN UINT16 *VariableName, + OUT VOID ** VariableData, + OUT UINTN *VariableSize + ) +{ + UINTN Size; + EFI_STATUS Status; + VOID *Buffer; + + Status = EfiGetVariable ( + (UINT16 *)VariableName, + VariableGuid, + NULL, + &Size, + NULL + ); + ASSERT (Status == EFI_BUFFER_TOO_SMALL); + + Buffer = AllocatePool (Size); + + ASSERT (Buffer != NULL); + + Status = EfiGetVariable ( + VariableName, + VariableGuid, + NULL, + &Size, + Buffer + ); + + return Status; + +} + + + +EFI_STATUS +SetHiiVariable ( + IN EFI_GUID *VariableGuid, + IN UINT16 *VariableName, + IN CONST VOID *Data, + IN UINTN DataSize, + IN UINTN Offset + ) +{ + UINTN Size; + VOID *Buffer; + EFI_STATUS Status; + + Size = 0; + + Status = EfiGetVariable ( + (UINT16 *)VariableName, + VariableGuid, + NULL, + &Size, + NULL + ); + + ASSERT (Status == EFI_BUFFER_TOO_SMALL); + + Buffer = AllocatePool (Size); + + ASSERT (Buffer != NULL); + + Status = EfiGetVariable ( + VariableName, + VariableGuid, + NULL, + &Size, + Buffer + ); + + + CopyMem ((UINT8 *)Buffer + Offset, Data, DataSize); + + return EfiSetVariable ( + VariableName, + VariableGuid, + 0, + Size, + Buffer + ); + +} + diff --git a/EdkModulePkg/Universal/PCD/Dxe/Service.h b/EdkModulePkg/Universal/PCD/Dxe/Service.h new file mode 100644 index 0000000000..86e3dfdee3 --- /dev/null +++ b/EdkModulePkg/Universal/PCD/Dxe/Service.h @@ -0,0 +1,399 @@ +/** @file +Private functions used by PCD DXE driver. + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +Module Name: Service.h + +**/ + +#ifndef _SERVICE_H +#define _SERVICE_H + +VOID +DxeGetPcdEntryWorker ( + IN UINTN Token, + IN CONST EFI_GUID *Guid, OPTIONAL + IN PCD_DATA_TYPE Type, + OUT VOID *Data + ); + +EFI_STATUS +DxeSetPcdEntryWorker ( + IN UINTN Token, + IN CONST EFI_GUID *Guid, OPTIONAL + IN PCD_DATA_TYPE Type, + IN CONST VOID *Data + ); + +UINTN +DxeGetPcdEntrySizeWorker ( + IN UINTN Token, + IN CONST EFI_GUID *Guid OPTIONAL + ); + +EFI_STATUS +DxeRegisterCallBackWorker ( + IN UINTN TokenNumber, + IN CONST EFI_GUID *Guid, OPTIONAL + IN PCD_PROTOCOL_CALLBACK CallBackFunction, + IN BOOLEAN Reigster +); + +EFI_STATUS +DxeSetSku ( + UINTN Id +); + +EFI_STATUS +DxeGetNextTokenWorker ( + IN OUT UINTN *Token, + IN CONST EFI_GUID *Guid OPTIONAL + ); + +VOID +InitPcdDxeDataBase ( + VOID +); + +// +// Protocol Interface function declaration. +// +EFI_STATUS +EFIAPI +DxePcdSetSku ( + IN UINTN SkuId + ) +; + + +UINT8 +EFIAPI +DxePcdGet8 ( + IN UINTN TokenNumber + ) +; + + +UINT16 +EFIAPI +DxePcdGet16 ( + IN UINTN TokenNumber + ) +; + + +UINT32 +EFIAPI +DxePcdGet32 ( + IN UINTN TokenNumber + ) +; + + +UINT64 +EFIAPI +DxePcdGet64 ( + IN UINTN TokenNumber + ) +; + + +VOID * +EFIAPI +DxePcdGetPtr ( + IN UINTN TokenNumber + ) +; + + +BOOLEAN +EFIAPI +DxePcdGetBool ( + IN UINTN TokenNumber + ) +; + + +UINTN +EFIAPI +DxePcdGetSize ( + IN UINTN TokenNumber + ) +; + + +UINT8 +EFIAPI +DxePcdGet8Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber + ) +; + + +UINT16 +EFIAPI +DxePcdGet16Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber + ) +; + + +UINT32 +EFIAPI +DxePcdGet32Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber + ) +; + + + +UINT64 +EFIAPI +DxePcdGet64Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber + ) +; + + + +VOID * +EFIAPI +DxePcdGetPtrEx ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber + ) +; + + +BOOLEAN +EFIAPI +DxePcdGetBoolEx ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber + ) +; + + +UINTN +EFIAPI +DxePcdGetSizeEx ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber + ) +; + + +EFI_STATUS +EFIAPI +DxePcdSet8 ( + IN UINTN TokenNumber, + IN UINT8 Value + ) +; + + +EFI_STATUS +EFIAPI +DxePcdSet16 ( + IN UINTN TokenNumber, + IN UINT16 Value + ) +; + + +EFI_STATUS +EFIAPI +DxePcdSet32 ( + IN UINTN TokenNumber, + IN UINT32 Value + ) +; + + +EFI_STATUS +EFIAPI +DxePcdSet64 ( + IN UINTN TokenNumber, + IN UINT64 Value + ) +; + + +EFI_STATUS +EFIAPI +DxePcdSetPtr ( + IN UINTN TokenNumber, + IN CONST VOID *Value + ) +; + + +EFI_STATUS +EFIAPI +DxePcdSetBool ( + IN UINTN TokenNumber, + IN BOOLEAN Value + ) +; + + +EFI_STATUS +EFIAPI +DxePcdSet8Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN UINT8 Value + ) +; + + +EFI_STATUS +EFIAPI +DxePcdSet16Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN UINT16 Value + ) +; + + +EFI_STATUS +EFIAPI +DxePcdSet32Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN UINT32 Value + ) +; + + +EFI_STATUS +EFIAPI +DxePcdSet64Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN UINT64 Value + ) +; + + +EFI_STATUS +EFIAPI +DxePcdSetPtrEx ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN CONST VOID *Value + ) +; + + +EFI_STATUS +EFIAPI +DxePcdSetBoolEx ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN BOOLEAN Value + ) +; + + + +EFI_STATUS +EFIAPI +PcdRegisterCallBackOnSet ( + IN UINTN TokenNumber, + IN CONST EFI_GUID *Guid, OPTIONAL + IN PCD_PROTOCOL_CALLBACK CallBackFunction + ) +; + + +EFI_STATUS +EFIAPI +PcdUnRegisterCallBackOnSet ( + IN UINTN TokenNumber, + IN CONST EFI_GUID *Guid, OPTIONAL + IN PCD_PROTOCOL_CALLBACK CallBackFunction + ) +; + + +EFI_STATUS +EFIAPI +DxePcdGetNextToken ( + IN CONST EFI_GUID *Guid, OPTIONAL + IN OUT UINTN *TokenNumber + ) +; + + +/* + This DXE_PCD_DATABASE layout. The difference of DXE_PCD_DATABASE + and PEI_PCD_DATABASE is as follows: + + 1) No PCD_CALL_BACK_TABLE; DXE_PCD_DATABASE maintain a LinkList for the + callback function registered. + + --------------------------- + | LIST_ENTRY GuidSpaceHead| + --------------------------- + | PCD_DATABASE_HEADER | + --------------------------- + | GUID_TABLE | Aligned on GUID (128 bits) + --------------------------- + | PCD_INDEX_TABLE | Aligned on PCD_INDEX (see PCD_INDEX's declaration) + --------------------------- + | IMAGE_STRING_TABLE | Aligned on 16 Bits + --------------------------- + | IMAGE_PCD_INDEX | Unaligned + --------------------------- + | Data Defaults | Unaligned + --------------------------- + | Data Buffer | + | for entries without | + | defaults | + --------------------------- + +*/ + + +typedef struct { + LIST_ENTRY ListNode; + LIST_ENTRY TokenSpaceHead; + CONST EFI_GUID *GuidSpace; +} PCD_GUID_SPACE; + +typedef struct { + LIST_ENTRY ListNode; + LIST_ENTRY CallbackListHead; + UINTN TokeNumber; +} PCD_TOKEN_SPACE; + +typedef struct { + LIST_ENTRY ListNode; + PCD_PROTOCOL_CALLBACK CallbackFunction; +} PCD_CALLBACK_ENTRY; + +#define PCD_GUID_SPACE_FROM_LISTNODE(a) \ + _CR(a, PCD_GUID_SPACE, ListNode) + +#define PCD_TOKEN_SPACE_FROM_LISTNODE(a) \ + _CR(a, PCD_TOKEN_SPACE, ListNode) + +#define PCD_CALLBACK_ENTRY_FROM_LISTNODE(a) \ + _CR(a, PCD_CALLBACK_ENTRY, ListNode) + +#endif diff --git a/EdkModulePkg/Universal/PCD/Pei/Pcd.c b/EdkModulePkg/Universal/PCD/Pei/Pcd.c new file mode 100644 index 0000000000..3fb49dd54f --- /dev/null +++ b/EdkModulePkg/Universal/PCD/Pei/Pcd.c @@ -0,0 +1,486 @@ +/** @file +PCD PEIM + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +Module Name: Pcd.c + +**/ + +#include "../Common/PcdCommon.h" +#include "Service.h" + + +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, + + PcdRegisterCallBackOnSet, + PcdUnRegisterCallBackOnSet, + PeiPcdGetNextToken +}; + + + +STATIC EFI_PEI_PPI_DESCRIPTOR mPpiPCD = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gPcdPpiGuid, + &mPcdPpiInstance +}; + + + +EFI_STATUS +EFIAPI +PcdPeimInit ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + UINT8 *PcdImage; + + PcdImage = (UINT8 *) LocatePcdImage (); + + BuildPcdDatabase (PcdImage); + + Status = PeiCoreInstallPpi (&mPpiPCD); + + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + + + +EFI_STATUS +EFIAPI +PeiPcdSetSku ( + IN UINTN SkuId + ) +{ + PCD_DATABASE *Database; + EFI_HOB_GUID_TYPE *GuidHob; + + GuidHob = GetFirstGuidHob (&gPcdDataBaseHobGuid); + ASSERT (GuidHob != NULL); + + Database = (PCD_DATABASE *) GET_GUID_HOB_DATA (GuidHob); + + Database->Info.SkuId = SkuId; + + return SkuId; +} + + + +UINT8 +EFIAPI +PeiPcdGet8 ( + IN UINTN TokenNumber + ) +{ + return PeiPcdGet8Ex (NULL, TokenNumber); +} + + + +UINT16 +EFIAPI +PeiPcdGet16 ( + IN UINTN TokenNumber + ) +{ + return PeiPcdGet16Ex (NULL, TokenNumber); +} + + + +UINT32 +EFIAPI +PeiPcdGet32 ( + IN UINTN TokenNumber + ) +{ + return PeiPcdGet32Ex (NULL, TokenNumber); +} + + + +UINT64 +EFIAPI +PeiPcdGet64 ( + IN UINTN TokenNumber + ) +{ + return PeiPcdGet64Ex (NULL, TokenNumber); +} + + + +VOID * +EFIAPI +PeiPcdGetPtr ( + IN UINTN TokenNumber + ) +{ + return PeiPcdGetPtrEx (NULL, TokenNumber); +} + + + +BOOLEAN +EFIAPI +PeiPcdGetBool ( + IN UINTN TokenNumber + ) +{ + return PeiPcdGetBoolEx (NULL, TokenNumber); +} + + + +UINTN +EFIAPI +PeiPcdGetSize ( + IN UINTN TokenNumber + ) +{ + return PeiPcdGetSizeEx (NULL, TokenNumber); +} + + + +UINT8 +EFIAPI +PeiPcdGet8Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber + ) +{ + UINT8 Data; + + PeiGetPcdEntryWorker (TokenNumber, Guid, PcdByte8, &Data); + + return Data; +} + + + +UINT16 +EFIAPI +PeiPcdGet16Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber + ) +{ + UINT16 Data; + + PeiGetPcdEntryWorker (TokenNumber, Guid, PcdByte16, &Data); + + return Data; +} + + + +UINT32 +EFIAPI +PeiPcdGet32Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber + ) +{ + UINT32 Data; + + PeiGetPcdEntryWorker (TokenNumber, Guid, PcdByte32, &Data); + + return Data; +} + + + +UINT64 +EFIAPI +PeiPcdGet64Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber + ) +{ + UINT64 Data; + + PeiGetPcdEntryWorker (TokenNumber, Guid, PcdByte64, &Data); + + return Data; +} + + + +VOID * +EFIAPI +PeiPcdGetPtrEx ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber + ) +{ + VOID *Data; + + PeiGetPcdEntryWorker (TokenNumber, Guid, PcdPointer, &Data); + + return Data; +} + + + +BOOLEAN +EFIAPI +PeiPcdGetBoolEx ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber + ) +{ + BOOLEAN Data; + + PeiGetPcdEntryWorker (TokenNumber, Guid, PcdBoolean, &Data); + + return Data; +} + + + +UINTN +EFIAPI +PeiPcdGetSizeEx ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber + ) +{ + return PeiGetPcdEntrySizeWorker (TokenNumber, Guid); +} + + + +EFI_STATUS +EFIAPI +PeiPcdSet8 ( + IN UINTN TokenNumber, + IN UINT8 Value + ) +{ + return PeiPcdSet8Ex (NULL, TokenNumber, Value); +} + + + +EFI_STATUS +EFIAPI +PeiPcdSet16 ( + IN UINTN TokenNumber, + IN UINT16 Value + ) +{ + return PeiPcdSet16Ex (NULL, TokenNumber, Value); +} + + + +EFI_STATUS +EFIAPI +PeiPcdSet32 ( + IN UINTN TokenNumber, + IN UINT32 Value + ) +{ + return PeiPcdSet32Ex (NULL, TokenNumber, Value); +} + + + +EFI_STATUS +EFIAPI +PeiPcdSet64 ( + IN UINTN TokenNumber, + IN UINT64 Value + ) +{ + return PeiPcdSet64Ex (NULL, TokenNumber, Value); +} + + +EFI_STATUS +EFIAPI +PeiPcdSetPtr ( + IN UINTN TokenNumber, + IN CONST VOID *Value + ) +{ + return PeiPcdSetPtrEx (NULL, TokenNumber, Value); +} + + + +EFI_STATUS +EFIAPI +PeiPcdSetBool ( + IN UINTN TokenNumber, + IN BOOLEAN Value + ) +{ + return PeiPcdSetBoolEx (NULL, TokenNumber, Value); +} + + + +EFI_STATUS +EFIAPI +PeiPcdSet8Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN UINT8 Value + ) +{ + return PeiSetPcdEntryWorker (TokenNumber, Guid, PcdByte8, &Value); +} + + + +EFI_STATUS +EFIAPI +PeiPcdSet16Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN UINT16 Value + ) +{ + return PeiSetPcdEntryWorker (TokenNumber, Guid, PcdByte16, &Value); +} + + + +EFI_STATUS +EFIAPI +PeiPcdSet32Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN UINT32 Value + ) +{ + return PeiSetPcdEntryWorker (TokenNumber, Guid, PcdByte32, &Value); +} + + + +EFI_STATUS +EFIAPI +PeiPcdSet64Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN UINT64 Value + ) +{ + return PeiSetPcdEntryWorker (TokenNumber, Guid, PcdByte64, &Value); +} + + + +EFI_STATUS +EFIAPI +PeiPcdSetPtrEx ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN CONST VOID *Value + ) +{ + return PeiSetPcdEntryWorker (TokenNumber, Guid, PcdPointer, (VOID *)Value); +} + + + +EFI_STATUS +EFIAPI +PeiPcdSetBoolEx ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN BOOLEAN Value + ) +{ + return PeiSetPcdEntryWorker (TokenNumber, Guid, PcdBoolean, &Value); + +} + + + + +EFI_STATUS +EFIAPI +PcdRegisterCallBackOnSet ( + IN UINTN TokenNumber, + IN CONST EFI_GUID *Guid, OPTIONAL + IN PCD_PPI_CALLBACK CallBackFunction + ) +{ + return PeiRegisterCallBackWorker (TokenNumber, Guid, CallBackFunction, TRUE); +} + + + +EFI_STATUS +EFIAPI +PcdUnRegisterCallBackOnSet ( + IN UINTN TokenNumber, + IN CONST EFI_GUID *Guid, OPTIONAL + IN PCD_PPI_CALLBACK CallBackFunction + ) +{ + return PeiRegisterCallBackWorker (TokenNumber, Guid, CallBackFunction, FALSE); +} + + + +EFI_STATUS +EFIAPI +PeiPcdGetNextToken ( + IN CONST EFI_GUID *Guid, OPTIONAL + IN OUT UINTN *TokenNumber + ) +{ + return PeiGetNextTokenWorker (TokenNumber, Guid); +} + + diff --git a/EdkModulePkg/Universal/PCD/Pei/Service.c b/EdkModulePkg/Universal/PCD/Pei/Service.c new file mode 100644 index 0000000000..38293252bc --- /dev/null +++ b/EdkModulePkg/Universal/PCD/Pei/Service.c @@ -0,0 +1,812 @@ +/** @file +Private functions used by PCD PEIM. + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +Module Name: Service.c + +**/ +#include "../Common/PcdCommon.h" +#include "Service.h" + + + + +/** + This function expand the StateByte + + @param[out] StateByte The output StateByte information. + @param[in] Byte The StateByte. + + @retval VOID +--*/ +VOID +PcdImageExpandStateByte ( + OUT PCD_STATEBYTE *StateByte, + IN UINT8 Byte +) +{ + switch (Byte & PCD_STATEBYTE_DATUMTYPE) { + case PCD_BYTE8: + StateByte->DataType = PcdByte8; + break; + case PCD_BYTE16: + StateByte->DataType = PcdByte16; + break; + case PCD_BYTE32: + StateByte->DataType = PcdByte32; + break; + case PCD_BYTE64: + StateByte->DataType = PcdByte64; + break; + case PCD_POINTER: + StateByte->DataType = PcdPointer; + break; + case PCD_BOOLEAN: + StateByte->DataType = PcdBoolean; + break; + default: + ASSERT (FALSE); + } + + StateByte->ExtendedGuidPresent = (BOOLEAN) ((Byte & PCD_STATEBYTE_EXTENDEDGUIDPRESENT) != 0); + StateByte->HiiEnable = (BOOLEAN) ((Byte & PCD_STATEBYTE_HIIENABLE) != 0); + StateByte->SkuDataArrayEnable = (BOOLEAN) ((Byte & PCD_STATEBYTE_SKUDATAARRAYENABLE) != 0); + StateByte->SkuEnable = (BOOLEAN) ((Byte & PCD_STATEBYTE_SKUENABLE) != 0); + StateByte->VpdEnable = (BOOLEAN) ((Byte & PCD_STATEBYTE_VPDENABLE) != 0); + +} + + + +/** + This function locates the on the flash and + return a pointer to the Section Data on flash. + + @param[in] VOID + + @retval VOID +--*/ +UINT8 * +LocatePcdImage ( + VOID +) +{ + EFI_STATUS Status; + EFI_FIRMWARE_VOLUME_HEADER *FvHdr; + EFI_FFS_FILE_HEADER *FfsHdr; + VOID *SectionData; + + Status = PeiCoreFfsFindNextVolume (0, &FvHdr); + ASSERT_EFI_ERROR (Status); + + do { + FfsHdr = NULL; + Status = PeiCoreFfsFindNextFile (EFI_FV_FILETYPE_FREEFORM, FvHdr, &FfsHdr); + if (Status == EFI_SUCCESS) { + if (CompareGuid (&gPcdImageFileGuid, &FfsHdr->Name)) { + + Status = PeiCoreFfsFindSectionData (EFI_SECTION_RAW, FfsHdr, &SectionData); + ASSERT_EFI_ERROR (Status); + + return (UINT8 *)SectionData; + } + } + } while (Status == EFI_SUCCESS); + + ASSERT (FALSE); + + return NULL; +} + +/** + The function retrieves the PCD data value according to + TokenNumber and Guid space given. + + @param[in] TokenNumber The token number. + @param[in] Guid The Guid space. + @param[in] Type The storage type. + @param[out] Data The output data. + + + @retval EFI_SUCESS If data value is found according to SKU_ID. + @retval EFI_NOT_FOUND If not such a value is found. + +--*/ +VOID +PeiGetPcdEntryWorker ( + IN UINTN TokenNumber, + IN CONST EFI_GUID *Guid, OPTIONAL + IN PCD_DATA_TYPE Type, + OUT VOID *Data + ) +{ + PCD_DATABASE *Database; + EFI_HOB_GUID_TYPE *GuidHob; + + ASSERT (Data != NULL); + + GuidHob = GetFirstGuidHob (&gPcdDataBaseHobGuid); + ASSERT (GuidHob != NULL); + + Database = GET_GUID_HOB_DATA (GuidHob); + + GetPcdEntryWorker ( &Database->Info, + TokenNumber, + Guid, + Type, + Data + ); + + + return; +} + + +/** + The function set the PCD data value according to + TokenNumber and Guid space given. + + @param[in] Database The PCD Database Instance. + @param[in] TokenNumber The token number. + @param[in] Guid The Guid space. + @param[in] Type The storage type. + @param[in] Data The output data. + + + @retval EFI_SUCESS If data value is found according to SKU_ID. + @retval EFI_NOT_FOUND If not such a value is found. + +--*/ +EFI_STATUS +SetPcdEntryWorker ( + IN CONST PCD_DATABASE *Database, + IN UINTN TokenNumber, + IN CONST EFI_GUID *Guid, OPTIONAL + IN PCD_DATA_TYPE Type, + IN VOID *Data + ) +{ + PCD_INDEX *PcdIndex; + EFI_STATUS Status; + PCD_PPI_CALLBACK *CallbackTable; + UINTN Idx; + + ASSERT (Data != NULL); + + // + // Find the PCD entry in list in memory first + // + PcdIndex = FindPcdIndex (TokenNumber, Guid, &Database->Info, &Idx); + + ASSERT (PcdIndex != NULL); + + ASSERT (PcdIndex->StateByte.DataType == Type); + + // + // Invoke the callback function. + // + CallbackTable = (PCD_PPI_CALLBACK *) + GetAbsoluteAddress (Idx * Database->Info.MaxCallbackNum * sizeof(PCD_PPI_CALLBACK), + Database->Info.CallbackTableOffset, + &Database->Info + ); + + for (Idx = 0; Idx < Database->Info.MaxCallbackNum; Idx++) { + if (CallbackTable[Idx] != NULL) { + CallbackTable[Idx] (Guid, + PcdIndex->TokenNumber, + Data, + PcdIndex->DatumSize + ); + } + } + + Status = SetPcdData (PcdIndex, &Database->Info, Data); + + return Status; +} + + + +/** + (reviewed) The function set the PCD data value according to + TokenNumber and Guid space given. + + @param[in] TokenNumber The token number. + @param[in] Guid The Guid space. + @param[in] Type The storage type. + @param[in] Data The output data. + + + @retval EFI_SUCESS If data value is found according to SKU_ID. + @retval EFI_NOT_FOUND If not such a value is found. + +--*/ +EFI_STATUS +PeiSetPcdEntryWorker ( + IN UINTN TokenNumber, + IN CONST EFI_GUID *Guid, OPTIONAL + IN PCD_DATA_TYPE Type, + IN VOID *Data + ) +{ + PCD_DATABASE *Database; + EFI_HOB_GUID_TYPE *GuidHob; + + ASSERT (Data != NULL); + + GuidHob = GetFirstGuidHob (&gPcdDataBaseHobGuid); + ASSERT (GuidHob != NULL); + + Database = GET_GUID_HOB_DATA (GuidHob); + + SetPcdEntryWorker (Database, + TokenNumber, + Guid, + Type, + Data + ); + + return EFI_SUCCESS; +} + + + +UINTN +PeiGetPcdEntrySizeWorker ( + IN UINTN TokenNumber, + IN CONST EFI_GUID *Guid OPTIONAL + ) +{ + PCD_DATABASE *Database; + EFI_HOB_GUID_TYPE *GuidHob; + + GuidHob = GetFirstGuidHob (&gPcdDataBaseHobGuid); + ASSERT (GuidHob != NULL); + + Database = GET_GUID_HOB_DATA (GuidHob); + + return GetPcdEntrySizeWorker (&Database->Info, + TokenNumber, + Guid + ); + +} + + + +/** + The function registers the CallBackOnSet fucntion + according to TokenNumber and EFI_GUID space. + + @param[in] TokenNumber The token number. + @param[in] Guid The GUID space. + @param[in] CallBackFunction The Callback function to be registered. + + @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. +--*/ +EFI_STATUS +PeiRegisterCallBackWorker ( + IN UINTN TokenNumber, + IN CONST EFI_GUID *Guid, OPTIONAL + IN PCD_PPI_CALLBACK CallBackFunction, + IN BOOLEAN Register +) +{ + PCD_DATABASE *Database; + EFI_HOB_GUID_TYPE *GuidHob; + PCD_INDEX *PcdIndex; + UINTN Idx; + PCD_PPI_CALLBACK *CallbackTable; + PCD_PPI_CALLBACK Compare; + PCD_PPI_CALLBACK Assign; + + GuidHob = GetFirstGuidHob (&gPcdDataBaseHobGuid); + ASSERT (GuidHob != NULL); + + Database = GET_GUID_HOB_DATA (GuidHob); + + PcdIndex = FindPcdIndex (TokenNumber, Guid, &Database->Info, NULL); + + ASSERT (PcdIndex != NULL); + + if (PcdIndex->StateByte.VpdEnable) { + return EFI_INVALID_PARAMETER; + } + + Idx = ((UINTN) PcdIndex - Database->Info.CallbackTableOffset) / sizeof(PCD_INDEX); + + CallbackTable = (PCD_PPI_CALLBACK *) GetAbsoluteAddress ( + sizeof (PCD_PPI_CALLBACK) * Idx * Database->Info.MaxCallbackNum, + Database->Info.CallbackTableOffset, + &Database->Info + ); + + Compare = Register? NULL: CallBackFunction; + Assign = Register? CallBackFunction: NULL; + + for (Idx = 0; Idx < Database->Info.MaxCallbackNum; Idx++) { + if (CallbackTable[Idx] == Compare) { + CallbackTable[Idx] = Assign; + return EFI_SUCCESS; + } + } + + return Register? EFI_OUT_OF_RESOURCES : EFI_NOT_FOUND; + +} + + + +EFI_STATUS +PeiGetNextTokenWorker ( + IN OUT UINTN *TokenNumber, + IN CONST EFI_GUID *Guid OPTIONAL + ) +{ + PCD_DATABASE *Database; + EFI_HOB_GUID_TYPE *GuidHob; + + GuidHob = GetFirstGuidHob (&gPcdDataBaseHobGuid); + ASSERT (GuidHob != NULL); + + Database = GET_GUID_HOB_DATA (GuidHob); + + return GetNextTokenWorker (&Database->Info, + TokenNumber, + Guid + ); + +} + + + +VOID +GetPcdImageInfo ( + IN CONST UINT8 *PcdImageOnFlash, + OUT PCD_IMAGE_RECORD *ImageInfo +) +{ + PCD_FFS_ENCODING *PcdFfsHdr; + + PcdFfsHdr = (PCD_FFS_ENCODING *) PcdImageOnFlash; + + ZeroMem (ImageInfo, sizeof (*ImageInfo)); + + ImageInfo->ImageStart = PcdImageOnFlash; + + CopyMem (&ImageInfo->EntryCount, PcdFfsHdr->EntryCount, 3); + + CopyMem (&ImageInfo->GlobalDatumLength, PcdFfsHdr->GlobalDatumLength, 1); + ASSERT (ImageInfo->GlobalDatumLength <= 3); + + CopyMem (&ImageInfo->GlobalOffsetLength, PcdFfsHdr->GlobalOffsetLength, 1); + ASSERT (ImageInfo->GlobalOffsetLength <= 3); + + CopyMem (&ImageInfo->GlobalTokenLength, PcdFfsHdr->GlobalTokenLength, 1); + ASSERT (ImageInfo->GlobalTokenLength <= 4); + + CopyMem (&ImageInfo->GlobalGuidTabIdxLength, PcdFfsHdr->GuidLength, 1); + ASSERT (ImageInfo->GlobalGuidTabIdxLength <= 2); + + CopyMem (&ImageInfo->GlobalStrTabIdxLength, PcdFfsHdr->GlobalStrTabIdxLength, 1); + ASSERT (ImageInfo->GlobalStrTabIdxLength <= 2); + + CopyMem (&ImageInfo->ImageLength, PcdFfsHdr->ImageLength, 3); + CopyMem (&ImageInfo->IndexLength, PcdFfsHdr->PcdIndexLength, 3); + CopyMem (&ImageInfo->WholeDataDefaultLength, PcdFfsHdr->WholeDataBufferLength, 3); + CopyMem (&ImageInfo->DataDefaultLength, PcdFfsHdr->DataBufferLength, 3); + CopyMem (&ImageInfo->GuidTableLength, PcdFfsHdr->GuidTableLength, 3); + + ImageInfo->StringTableLength = ImageInfo->ImageLength + - sizeof (PCD_FFS_ENCODING) + - ImageInfo->DataDefaultLength + - ImageInfo->IndexLength + - ImageInfo->GuidTableLength; + + ImageInfo->DataDefaultStart = PcdImageOnFlash + sizeof (PCD_FFS_ENCODING); + ImageInfo->IndexStart = ImageInfo->DataDefaultStart + ImageInfo->DataDefaultLength; + ImageInfo->GuidTableStart = (CONST EFI_GUID *)(ImageInfo->IndexStart + ImageInfo->IndexLength); + ImageInfo->StringTableStart = (CONST UINT16 *) ((UINT8 *) ImageInfo->GuidTableStart + ImageInfo->GuidTableLength); + + return; +} + + + +/** + The function builds the PCD database based on the + PCD_IMAGE on the flash. + + The layout of the PCD_DATABASE is as follows: + + --------------------------- + | PCD_DATABASE_HEADER | + --------------------------- + | GUID_TABLE | Aligned on GUID (128 bits) + --------------------------- + | PCD_CALL_BACK_TABLE | Aligned on Pointer (32 bits or 64 bits) + --------------------------- + | PCD_INDEX_TABLE | Aligned on PCD_INDEX (see PCD_INDEX's declaration) + --------------------------- + | IMAGE_STRING_TABLE | Aligned on 16 Bits + --------------------------- + | IMAGE_PCD_INDEX | Unaligned + --------------------------- + | Data Defaults | Unaligned + --------------------------- + | Data Buffer | + | for entries without | + | defaults | + --------------------------- + + @param[in] PcdImageOnFlash The PCD image on flash. + + @retval VOID +--*/ +UINTN +GetPcdDatabaseLen ( + IN CONST UINT8 *PcdImageOnFlash, + OUT PCD_DATABASE_HEADER *Info, + OUT PCD_IMAGE_RECORD *ImageInfo + ) +{ + UINTN DatabaseLen; + UINTN DatabaseHeaderLength; + UINTN PcdIndexLength; + UINTN CallbackBufferLength; + + + GetPcdImageInfo (PcdImageOnFlash, ImageInfo); + + Info->MaxCallbackNum = FixedPcdGet32(PcdMaxPcdCallBackNumber) ; + + DatabaseHeaderLength = sizeof (PCD_DATABASE) - sizeof(UINT8); + + PcdIndexLength = sizeof (PCD_INDEX) * ImageInfo->EntryCount; + CallbackBufferLength = sizeof (PCD_PPI_CALLBACK) * Info->MaxCallbackNum * ImageInfo->EntryCount; + + Info->EntryCount = ImageInfo->EntryCount; + Info->GuidTableOffset = DatabaseHeaderLength; + Info->CallbackTableOffset = Info->GuidTableOffset + ImageInfo->GuidTableLength; + Info->PcdIndexOffset = Info->PcdIndexOffset + PcdIndexLength; + Info->ImageIndexOffset = Info->CallbackTableOffset + CallbackBufferLength; + Info->DataBufferOffset = Info->ImageIndexOffset + ImageInfo->DataDefaultLength; + + Info->HiiGuidOffsetLength = ImageInfo->GlobalGuidTabIdxLength; + Info->HiiVariableOffsetLength = ImageInfo->GlobalStrTabIdxLength; + Info->ExtendedOffsetLength = ImageInfo->GlobalOffsetLength; + + Info->SkuId = 0; + + DatabaseLen = DatabaseHeaderLength + + ImageInfo->GuidTableLength + + PcdIndexLength + + CallbackBufferLength + + ImageInfo->IndexLength + + ImageInfo->WholeDataDefaultLength; + + Info->DatabaseLen = DatabaseLen; + + return DatabaseLen; +} + + +/** + The function constructs a single PCD_INDEX according a index in + . + + @param[in] ImageIndex The starting address of a PCD index defined in PCD spec 0.51. + @param[in] Index The output PCD_INDEX. + @param[in] ImageInfo The attributes of the PCD_IMAGE as this binary stream is highly + optimized for size. + + @retval UINTN The length of the current PCD index. +**/ +UINTN +BuildPcdIndex ( + IN CONST UINT8 *ImageIndex, + OUT PCD_INDEX *Index, + IN CONST PCD_IMAGE_RECORD *ImageInfo +) +{ + UINTN SkuCount; + CONST UINT8 *ImageIndexBackUp; + + ImageIndexBackUp = ImageIndex; + + // + // Token Number + // + CopyMem (&Index->TokenNumber, + ImageIndex, + ImageInfo->GlobalTokenLength + ); + + ImageIndex += ImageInfo->GlobalTokenLength; + + // + // State Byte + // + PcdImageExpandStateByte (&Index->StateByte, + *ImageIndex + ); + + ImageIndex += 1; + + // + // Dataum Size + // + CopyMem (&Index->DatumSize, + ImageIndex, + ImageInfo->GlobalDatumLength + ); + + ImageIndex += ImageInfo->GlobalDatumLength; + + // + // SKU_DATA + // + if (Index->StateByte.SkuEnable) { + Index->SkuCount = *ImageIndex; + SkuCount = *ImageIndex; + ImageIndex++; + Index->SkuIdArray = (UINT32) ImageIndex - (UINT32) ImageInfo->IndexStart; + ImageIndex += Index->SkuCount; + } else { + // + // There is always a default SKU_ID of zero even + // if SKU is not enabled for this PCD entry. + // + // + SkuCount = 1; + } + + // + // Extended Offset + // + CopyMem (&Index->ExtendedDataOffset, + ImageIndex, + ImageInfo->GlobalOffsetLength + ); + + ImageIndex += ImageInfo->GlobalOffsetLength * SkuCount; + + // + // DynamicEX Guid Offset + // + if (Index->StateByte.ExtendedGuidPresent) { + CopyMem (&Index->DynamicExGuid, + ImageIndex, + ImageInfo->GlobalGuidTabIdxLength + ); + + ImageIndex += ImageInfo->GlobalGuidTabIdxLength; + } + + // + // HII_DATA + // + if (Index->StateByte.HiiEnable) { + Index->HiiData = (UINT32) ImageIndex - (UINT32) ImageInfo->IndexStart; + ImageIndex += ((ImageInfo->GlobalStrTabIdxLength + ImageInfo->GlobalGuidTabIdxLength) * SkuCount); + } + + return (UINTN) (ImageIndex - ImageIndexBackUp); +} + + + + +/** + The function builds the PCD database based on the + PCD_IMAGE on the flash. + + @param[in] Database The database instance. + @param[in] ImageIndex The starting address of a PCD index defined in PCD spec 0.51. + @param[in] ImageInfo The attributes of the PCD_IMAGE as this binary stream is highly + optimized for size. + + @retval VOID +**/ +VOID +BuildPcdDatabaseIndex ( + PCD_DATABASE *Database, + UINT8 *ImageIndex, + PCD_IMAGE_RECORD *ImageInfo + ) +{ + UINTN Idx; + UINTN Len; + PCD_INDEX *IndexTable; + + IndexTable = (PCD_INDEX *) GetAbsoluteAddress (0, Database->Info.PcdIndexOffset, Database); + + for (Idx = 0; Idx < Database->Info.EntryCount; Idx++) { + Len = BuildPcdIndex (ImageIndex, &IndexTable[Idx], ImageInfo); + ImageIndex += Len; + } + + return; +} + + +/** + The function builds the PCD database based on the + PCD_IMAGE on the flash. + + @param[in] PcdImageOnFlash The PCD image on flash. + + @retval VOID +--*/ +VOID +BuildPcdDatabase ( + UINT8 *PcdImageOnFlash + ) +{ + PCD_DATABASE *Database; + UINTN Len; + PCD_IMAGE_RECORD ImageInfo; + UINT8 *ImageIndex; + PCD_DATABASE_HEADER DatabaseHeader; + + Len = GetPcdDatabaseLen(PcdImageOnFlash, &DatabaseHeader, &ImageInfo); + + Database = BuildGuidHob (&gPcdDataBaseHobGuid, Len); + ASSERT (Database != NULL); + + ZeroMem (Database, Len); + + // + // Update Database header + // + CopyMem (&Database->Info, &DatabaseHeader, sizeof (DatabaseHeader)); + + // + // I need this to get the GuidTableOffset as we don't + // know if Database field of PCD_DATABASE starts from an aligned + // address. The compilor may add padding after PCD_DATABASE_HEADER field. + // + Database->Info.GuidTableOffset = ((UINTN) &Database->GuidTable) - (UINTN)Database; + + // + // Copy Guid Table from Flash + // + CopyMem ((UINT8 *) Database + Database->Info.GuidTableOffset, + ImageInfo.GuidTableStart, + ImageInfo.GuidTableLength + ); + + // + // Copy ImageIndex from Flash + // + CopyMem ((UINT8 *) Database + Database->Info.ImageIndexOffset, + ImageInfo.IndexStart, + ImageInfo.IndexLength + ); + + // + // Copy Default Value + // + CopyMem ((UINT8 *) Database + Database->Info.DataBufferOffset, + ImageInfo.DataDefaultStart, + ImageInfo.DataDefaultLength + ); + + // + // Copy String Table + // + CopyMem ((UINT8 *) Database + Database->Info.StringTableOffset, + ImageInfo.StringTableStart, + ImageInfo.StringTableLength + ); + + ImageIndex = GetAbsoluteAddress (0, Database->Info.ImageIndexOffset, Database); + + BuildPcdDatabaseIndex (Database, ImageIndex, &ImageInfo); + + return; +} + + + +/** + The function is provided by PCD PEIM and PCD DXE driver to + do the work of reading a HII variable from variable service. + + @param[in] VariableGuid The Variable GUID. + @param[in] VariableName The Variable Name. + @param[out] VariableData The output data. + @param[out] VariableSize The size of the variable. + + @retval EFI_SUCCESS Operation successful. + @retval EFI_SUCCESS Variablel not found. +--*/ +EFI_STATUS +GetHiiVariable ( + IN EFI_GUID *VariableGuid, + IN UINT16 *VariableName, + OUT VOID **VariableData, + OUT UINTN *VariableSize + ) +{ + UINTN Size; + EFI_STATUS Status; + VOID *Buffer; + EFI_PEI_READ_ONLY_VARIABLE_PPI *VariablePpi; + + Status = PeiCoreLocatePpi (&gEfiPeiReadOnlyVariablePpiGuid, 0, NULL, &VariablePpi); + ASSERT_EFI_ERROR (Status); + + Size = 0; + + Status = VariablePpi->PeiGetVariable ( + GetPeiServicesTablePointer (), + VariableName, + VariableGuid, + NULL, + &Size, + NULL + ); + ASSERT (Status == EFI_BUFFER_TOO_SMALL); + + Status = PeiCoreAllocatePool (Size, &Buffer); + ASSERT_EFI_ERROR (Status); + + // declare a local for STP. + // + Status = VariablePpi->PeiGetVariable ( + GetPeiServicesTablePointer (), + (UINT16 *) VariableName, + VariableGuid, + NULL, + &Size, + Buffer + ); + ASSERT_EFI_ERROR (Status); + + *VariableSize = Size; + *VariableData = Buffer; + + return EFI_SUCCESS; +} + + + +/** + The function is provided by PCD PEIM and PCD DXE driver to + do the work of reading a HII variable from variable service. + + @param[in] VariableGuid The Variable GUID. + @param[in] VariableName The Variable Name. + @param[in] Data The input data. + @param[out] VariableSize The size of the variable. + @param[in] Offset The offset of the variable data that a PCD entry will starts from. + + @retval EFI_SUCCESS Operation successful. + @retval EFI_SUCCESS Variablel not found. +--*/ +EFI_STATUS +SetHiiVariable ( + IN EFI_GUID *VariableGuid, + IN UINT16 *VariableName, + IN CONST VOID *Data, + IN UINTN VariableSize, + IN UINTN Offset + ) +{ + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; +} + + diff --git a/EdkModulePkg/Universal/PCD/Pei/Service.h b/EdkModulePkg/Universal/PCD/Pei/Service.h new file mode 100644 index 0000000000..d775a12a17 --- /dev/null +++ b/EdkModulePkg/Universal/PCD/Pei/Service.h @@ -0,0 +1,371 @@ +/** @file +Private functions used by PCD PEIM. + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +Module Name: Service.h + +**/ + +#ifndef _SERVICE_H +#define _SERVICE_H + +// +// Offset of StateByte +// +#define PCD_STATEBYTE_HIIENABLE 0x01 +#define PCD_STATEBYTE_SKUENABLE 0x02 +#define PCD_STATEBYTE_VPDENABLE 0x04 +#define PCD_STATEBYTE_SKUDATAARRAYENABLE 0x08 +#define PCD_STATEBYTE_DATUMTYPE 0x70 +#define PCD_STATEBYTE_EXTENDEDGUIDPRESENT 0x80 + +#define PCD_DATUMTYPE_OFFSET 4 + +// +// The definitions for interpreting DatumType +// +#define PCD_BYTE8 (0x00 << PCD_DATUMTYPE_OFFSET) +#define PCD_BYTE16 (0x01 << PCD_DATUMTYPE_OFFSET) +#define PCD_BYTE32 (0x02 << PCD_DATUMTYPE_OFFSET) +#define PCD_BYTE64 (0x03 << PCD_DATUMTYPE_OFFSET) +#define PCD_POINTER (0x04 << PCD_DATUMTYPE_OFFSET) +#define PCD_BOOLEAN (0x05 << PCD_DATUMTYPE_OFFSET) + +extern GUID gEfiPcdImageHobGuid; + +/* Internal Function definitions */ + +VOID +PeiGetPcdEntryWorker ( + IN UINTN Token, + IN CONST GUID *Guid, OPTIONAL + IN PCD_DATA_TYPE Type, + OUT VOID *Data + ); + +EFI_STATUS +PeiSetPcdEntryWorker ( + IN UINTN Token, + IN CONST GUID *Guid, OPTIONAL + IN PCD_DATA_TYPE Type, + IN VOID *Data + ); + +UINTN +PeiGetPcdEntrySizeWorker ( + IN UINTN Token, + IN CONST GUID *Guid OPTIONAL + ); + +EFI_STATUS +PeiRegisterCallBackWorker ( + IN UINTN TokenNumber, + IN CONST GUID *Guid, OPTIONAL + IN PCD_PPI_CALLBACK CallBackFunction, + IN BOOLEAN Register +); + +EFI_STATUS +PeiSetSku ( + UINTN Id +); + +EFI_STATUS +PeiGetNextTokenWorker ( + IN OUT UINTN *Token, + IN CONST GUID *Guid OPTIONAL + ); + +UINT8 * +LocatePcdImage ( + VOID +); + +VOID +BuildPcdDatabase ( + UINT8 *PcdImageOnFlash + ) +; + + +extern EFI_GUID gPcdImageFileGuid; + +// +// PPI Interface Implementation Declaration. +// +EFI_STATUS +EFIAPI +PeiPcdSetSku ( + IN UINTN SkuId + ) +; + + +UINT8 +EFIAPI +PeiPcdGet8 ( + IN UINTN TokenNumber + ) +; + + +UINT16 +EFIAPI +PeiPcdGet16 ( + IN UINTN TokenNumber + ) +; + + +UINT32 +EFIAPI +PeiPcdGet32 ( + IN UINTN TokenNumber + ) +; + + +UINT64 +EFIAPI +PeiPcdGet64 ( + IN UINTN TokenNumber + ) +; + + +VOID * +EFIAPI +PeiPcdGetPtr ( + IN UINTN TokenNumber + ) +; + + +BOOLEAN +EFIAPI +PeiPcdGetBool ( + IN UINTN TokenNumber + ) +; + + +UINTN +EFIAPI +PeiPcdGetSize ( + IN UINTN TokenNumber + ) +; + + +UINT8 +EFIAPI +PeiPcdGet8Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber + ) +; + + +UINT16 +EFIAPI +PeiPcdGet16Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber + ) +; + +UINT32 +EFIAPI +PeiPcdGet32Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber + ) +; + + +UINT64 +EFIAPI +PeiPcdGet64Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber + ) +; + + +VOID * +EFIAPI +PeiPcdGetPtrEx ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber + ) +; + + +BOOLEAN +EFIAPI +PeiPcdGetBoolEx ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber + ) +; + + +UINTN +EFIAPI +PeiPcdGetSizeEx ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber + ) +; + + +EFI_STATUS +EFIAPI +PeiPcdSet8 ( + IN UINTN TokenNumber, + IN UINT8 Value + ) +; + + +EFI_STATUS +EFIAPI +PeiPcdSet16 ( + IN UINTN TokenNumber, + IN UINT16 Value + ) +; + + +EFI_STATUS +EFIAPI +PeiPcdSet32 ( + IN UINTN TokenNumber, + IN UINT32 Value + ) +; + + +EFI_STATUS +EFIAPI +PeiPcdSet64 ( + IN UINTN TokenNumber, + IN UINT64 Value + ) +; + +EFI_STATUS +EFIAPI +PeiPcdSetPtr ( + IN UINTN TokenNumber, + IN CONST VOID *Value + ) +; + + +EFI_STATUS +EFIAPI +PeiPcdSetBool ( + IN UINTN TokenNumber, + IN BOOLEAN Value + ) +; + + +EFI_STATUS +EFIAPI +PeiPcdSet8Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN UINT8 Value + ) +; + +EFI_STATUS +EFIAPI +PeiPcdSet16Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN UINT16 Value + ) +; + + +EFI_STATUS +EFIAPI +PeiPcdSet32Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN UINT32 Value + ) +; + + +EFI_STATUS +EFIAPI +PeiPcdSet64Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN UINT64 Value + ) +; + + +EFI_STATUS +EFIAPI +PeiPcdSetPtrEx ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN CONST VOID *Value + ) +; + + +EFI_STATUS +EFIAPI +PeiPcdSetBoolEx ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN BOOLEAN Value + ) +; + + + +EFI_STATUS +EFIAPI +PcdRegisterCallBackOnSet ( + IN UINTN TokenNumber, + IN CONST EFI_GUID *Guid, OPTIONAL + IN PCD_PPI_CALLBACK CallBackFunction + ) +; + + +EFI_STATUS +EFIAPI +PcdUnRegisterCallBackOnSet ( + IN UINTN TokenNumber, + IN CONST EFI_GUID *Guid, OPTIONAL + IN PCD_PPI_CALLBACK CallBackFunction + ) +; + + +EFI_STATUS +EFIAPI +PeiPcdGetNextToken ( + IN CONST EFI_GUID *Guid, OPTIONAL + IN OUT UINTN *TokenNumber + ) +; +#endif diff --git a/EdkModulePkg/Universal/PCD/Test/PcdTest.c b/EdkModulePkg/Universal/PCD/Test/PcdTest.c new file mode 100644 index 0000000000..77e25ac2b6 --- /dev/null +++ b/EdkModulePkg/Universal/PCD/Test/PcdTest.c @@ -0,0 +1,110 @@ +/** @file +PCD TEST PEIM + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +Module Name: PcdTest.c + +**/ +#define GUID1 \ + {0xF9349C58, 0xB767, 0x42c8, 0xB3, 0x6B, 0x41, 0x25, 0xDE, 0x3A, 0xEF, 0xEB} + +CONST GUID Guid1 = GUID1; + + +EFI_STATUS +EFIAPI +OnsetCallback1 ( + IN UINT32 CallBackToken, + IN VOID *TokenData, + IN UINTN TokenDataSize + ) +{ + DebugPrint (0x80000000, "In CallbackOnSet %x %d\n", * ((UINT32 *)TokenData), TokenDataSize); + return EFI_SUCCESS; +} + + +VOID +DoTest( + VOID + ) +{ + PCD_TOKEN_NUMBER tn; + UINTN Size; + VOID * Ptr; + UINT32 Uint32; + UINT32 Uint32a; + UINT64 Uint64; + UINT64 Uint64a; + INTN i; + + tn = 0x00001000; + + Size = LibPcdGetSize (tn); + Ptr = LibPcdGetPtr (tn); /* a:RW;2880;512!e:RW;262144;512 */ + + tn = 0x00001001; + Size = LibPcdGetSize (tn); /* FW;40960;512 */ + + tn = 0x00001002; + Size = LibPcdGetSize (tn); /* FW;40960;512 */ + Ptr = LibPcdGetPtr (tn); + + LibPcdSetSku (0x0a); + tn = 0x2233; + Uint64 = LibPcdGet64 (tn); + + LibPcdSetSku (0x0b); + Uint64 = LibPcdGet64 (tn); + + LibPcdSetSku (0x0c); + Uint64a = LibPcdGet64 (tn); + + LibPcdSetSku (0); + tn = 0x2233; + Uint64 = LibPcdGet64 (tn); + + + tn = 0xfaceface; + Size = LibPcdGetExSize (&Guid1, tn); + Uint32 = LibPcdGetEx32 (&Guid1, tn); + + LibPcdCallBackOnSet (&Guid1, tn, OnsetCallback1); + + LibPcdCancelCallBackOnSet (&Guid1, tn, OnsetCallback1); + + for (i = 0; i < 2; i++) { + Uint32a = LibPcdSetEx32 (&Guid1, tn, Uint32 + i); + DebugPrint (0x80000000, "%x\n", Uint32a); + } + + + + Uint32 = LibPcdGet32 (tn); + + + return; +} + +EFI_STATUS +EFIAPI +PcdTestPeimInit ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices + ) +{ + + DoTest(); + + return EFI_SUCCESS; +} + diff --git a/EdkModulePkg/Universal/PCD/Test/PcdTest.dxs b/EdkModulePkg/Universal/PCD/Test/PcdTest.dxs new file mode 100644 index 0000000000..bf742966e1 --- /dev/null +++ b/EdkModulePkg/Universal/PCD/Test/PcdTest.dxs @@ -0,0 +1,28 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Variable.dxs + +Abstract: + + Dependency expression file for PcdTest PEIM. + +--*/ +#include +#include + +DEPENDENCY_START + PCD_PPI_GUID +DEPENDENCY_END + + diff --git a/EdkModulePkg/Universal/Runtime/RuntimeDxe/Crc32.c b/EdkModulePkg/Universal/Runtime/RuntimeDxe/Crc32.c new file mode 100644 index 0000000000..675a5503c3 --- /dev/null +++ b/EdkModulePkg/Universal/Runtime/RuntimeDxe/Crc32.c @@ -0,0 +1,124 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Crc32.c + +Abstract: + + CalculateCrc32 Boot Services as defined in DXE CIS. + + 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. + +Revision History: + +--*/ + +#include "Runtime.h" + +UINT32 mCrcTable[256]; + +EFI_STATUS +EFIAPI +RuntimeDriverCalculateCrc32 ( + IN VOID *Data, + IN UINTN DataSize, + OUT UINT32 *CrcOut + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + UINT32 Crc; + UINTN Index; + UINT8 *Ptr; + + if (Data == NULL || DataSize == 0 || CrcOut == NULL) { + return EFI_INVALID_PARAMETER; + } + + Crc = 0xffffffff; + for (Index = 0, Ptr = Data; Index < DataSize; Index++, Ptr++) { + Crc = (Crc >> 8) ^ mCrcTable[(UINT8) Crc ^ *Ptr]; + } + + *CrcOut = Crc ^ 0xffffffff; + return EFI_SUCCESS; +} + +UINT32 +ReverseBits ( + UINT32 Value + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + UINTN Index; + UINT32 NewValue; + + NewValue = 0; + for (Index = 0; Index < 32; Index++) { + if (Value & (1 << Index)) { + NewValue = NewValue | (1 << (31 - Index)); + } + } + + return NewValue; +} + +VOID +RuntimeDriverInitializeCrc32Table ( + VOID + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + UINTN TableEntry; + UINTN Index; + UINT32 Value; + + for (TableEntry = 0; TableEntry < 256; TableEntry++) { + Value = ReverseBits ((UINT32) TableEntry); + for (Index = 0; Index < 8; Index++) { + if (Value & 0x80000000) { + Value = (Value << 1) ^ 0x04c11db7; + } else { + Value = Value << 1; + } + } + + mCrcTable[TableEntry] = ReverseBits (Value); + } +} diff --git a/EdkModulePkg/Universal/Runtime/RuntimeDxe/Ia32/PeHotRelocateEx.c b/EdkModulePkg/Universal/Runtime/RuntimeDxe/Ia32/PeHotRelocateEx.c new file mode 100644 index 0000000000..82d464aebe --- /dev/null +++ b/EdkModulePkg/Universal/Runtime/RuntimeDxe/Ia32/PeHotRelocateEx.c @@ -0,0 +1,88 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PeHotRelocateEx.c + +Abstract: + + Stub to resolve the IPF hook that handles IPF specific relocation types + + +Revision History + +--*/ + +#include "Runtime.h" + +EFI_STATUS +PeHotRelocateImageEx ( + IN UINT16 *Reloc, + IN OUT CHAR8 *Fixup, + IN OUT CHAR8 **FixupData, + IN UINT64 Adjust + ) +/*++ + +Routine Description: + + Performs an Itanium-based platform specific relocation fixup + +Arguments: + + Reloc - Pointer to the relocation record + + Fixup - Pointer to the address to fix up + + FixupData - Pointer to a buffer to log the fixups + + Adjust - The offset to adjust the fixup + +Returns: + + EFI_SUCCESS + +--*/ +{ + return EFI_SUCCESS; + +} + +// +// Cache Flush Routine. +// +EFI_STATUS +FlushCpuCache ( + IN EFI_PHYSICAL_ADDRESS Start, + IN UINT64 Length + ) +/*++ + +Routine Description: + + Flush cache with specified range. + +Arguments: + + Start - Start address + Length - Length in bytes + +Returns: + + Status code + + EFI_SUCCESS - success + +--*/ +{ + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Universal/Runtime/RuntimeDxe/Ipf/PeHotRelocateEx.c b/EdkModulePkg/Universal/Runtime/RuntimeDxe/Ipf/PeHotRelocateEx.c new file mode 100644 index 0000000000..ffc0aaf4a4 --- /dev/null +++ b/EdkModulePkg/Universal/Runtime/RuntimeDxe/Ipf/PeHotRelocateEx.c @@ -0,0 +1,242 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PeHotRelocateEx.c + +Abstract: + + Fixes IPF specific relocation types + + +Revision History + +--*/ + +#include "Runtime.h" +#include "PeHotRelocateEx.h" + +EFI_STATUS +PeHotRelocateImageEx ( + IN UINT16 *Reloc, + IN OUT CHAR8 *Fixup, + IN OUT CHAR8 **FixupData, + IN UINT64 Adjust + ) +/*++ + +Routine Description: + + Performs an IPF specific relocation fixup + +Arguments: + + Reloc - Pointer to the relocation record + + Fixup - Pointer to the address to fix up + + FixupData - Pointer to a buffer to log the fixups + + Adjust - The offset to adjust the fixup + +Returns: + + None + +--*/ +{ + UINT64 *F64; + UINT64 FixupVal; + + switch ((*Reloc) >> 12) { + case EFI_IMAGE_REL_BASED_DIR64: + F64 = (UINT64 *) Fixup; + *FixupData = ALIGN_POINTER (*FixupData, sizeof (UINT64)); + if (*(UINT64 *) (*FixupData) == *F64) { + *F64 = *F64 + (UINT64) Adjust; + } + + *FixupData = *FixupData + sizeof (UINT64); + break; + + case EFI_IMAGE_REL_BASED_IA64_IMM64: + F64 = (UINT64 *) Fixup; + *FixupData = ALIGN_POINTER (*FixupData, sizeof (UINT64)); + if (*(UINT64 *) (*FixupData) == *F64) { + // + // Align it to bundle address before fixing up the + // 64-bit immediate value of the movl instruction. + // + // + Fixup = (CHAR8 *) ((UINT64) Fixup & (UINT64)~(15)); + FixupVal = (UINT64) 0; + + // + // Extract the lower 32 bits of IMM64 from bundle + // + EXT_IMM64 ( + FixupVal, + (UINT32 *) Fixup + IMM64_IMM7B_INST_WORD_X, + IMM64_IMM7B_SIZE_X, + IMM64_IMM7B_INST_WORD_POS_X, + IMM64_IMM7B_VAL_POS_X + ); + + EXT_IMM64 ( + FixupVal, + (UINT32 *) Fixup + IMM64_IMM9D_INST_WORD_X, + IMM64_IMM9D_SIZE_X, + IMM64_IMM9D_INST_WORD_POS_X, + IMM64_IMM9D_VAL_POS_X + ); + + EXT_IMM64 ( + FixupVal, + (UINT32 *) Fixup + IMM64_IMM5C_INST_WORD_X, + IMM64_IMM5C_SIZE_X, + IMM64_IMM5C_INST_WORD_POS_X, + IMM64_IMM5C_VAL_POS_X + ); + + EXT_IMM64 ( + FixupVal, + (UINT32 *) Fixup + IMM64_IC_INST_WORD_X, + IMM64_IC_SIZE_X, + IMM64_IC_INST_WORD_POS_X, + IMM64_IC_VAL_POS_X + ); + + EXT_IMM64 ( + FixupVal, + (UINT32 *) Fixup + IMM64_IMM41a_INST_WORD_X, + IMM64_IMM41a_SIZE_X, + IMM64_IMM41a_INST_WORD_POS_X, + IMM64_IMM41a_VAL_POS_X + ); + + // + // Update 64-bit address + // + FixupVal += Adjust; + + // + // Insert IMM64 into bundle + // + INS_IMM64 ( + FixupVal, + ((UINT32 *) Fixup + IMM64_IMM7B_INST_WORD_X), + IMM64_IMM7B_SIZE_X, + IMM64_IMM7B_INST_WORD_POS_X, + IMM64_IMM7B_VAL_POS_X + ); + + INS_IMM64 ( + FixupVal, + ((UINT32 *) Fixup + IMM64_IMM9D_INST_WORD_X), + IMM64_IMM9D_SIZE_X, + IMM64_IMM9D_INST_WORD_POS_X, + IMM64_IMM9D_VAL_POS_X + ); + + INS_IMM64 ( + FixupVal, + ((UINT32 *) Fixup + IMM64_IMM5C_INST_WORD_X), + IMM64_IMM5C_SIZE_X, + IMM64_IMM5C_INST_WORD_POS_X, + IMM64_IMM5C_VAL_POS_X + ); + + INS_IMM64 ( + FixupVal, + ((UINT32 *) Fixup + IMM64_IC_INST_WORD_X), + IMM64_IC_SIZE_X, + IMM64_IC_INST_WORD_POS_X, + IMM64_IC_VAL_POS_X + ); + + INS_IMM64 ( + FixupVal, + ((UINT32 *) Fixup + IMM64_IMM41a_INST_WORD_X), + IMM64_IMM41a_SIZE_X, + IMM64_IMM41a_INST_WORD_POS_X, + IMM64_IMM41a_VAL_POS_X + ); + + INS_IMM64 ( + FixupVal, + ((UINT32 *) Fixup + IMM64_IMM41b_INST_WORD_X), + IMM64_IMM41b_SIZE_X, + IMM64_IMM41b_INST_WORD_POS_X, + IMM64_IMM41b_VAL_POS_X + ); + + INS_IMM64 ( + FixupVal, + ((UINT32 *) Fixup + IMM64_IMM41c_INST_WORD_X), + IMM64_IMM41c_SIZE_X, + IMM64_IMM41c_INST_WORD_POS_X, + IMM64_IMM41c_VAL_POS_X + ); + + INS_IMM64 ( + FixupVal, + ((UINT32 *) Fixup + IMM64_SIGN_INST_WORD_X), + IMM64_SIGN_SIZE_X, + IMM64_SIGN_INST_WORD_POS_X, + IMM64_SIGN_VAL_POS_X + ); + + *(UINT64 *) (*FixupData) = *F64; + } + + *FixupData = *FixupData + sizeof (UINT64); + break; + + default: + DEBUG ((EFI_D_ERROR, "PeHotRelocateEx:unknown fixed type\n")); + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + + +// +// Cache Flush Routine. +// +EFI_STATUS +FlushCpuCache ( + IN EFI_PHYSICAL_ADDRESS Start, + IN UINT64 Length + ) +/*++ + +Routine Description: + + Flush cache with specified range. + +Arguments: + + Start - Start address + Length - Length in bytes + +Returns: + + Status code + + EFI_SUCCESS - success + +--*/ +{ + SalFlushCache (Start, Length); + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Universal/Runtime/RuntimeDxe/Ipf/PeHotRelocateEx.h b/EdkModulePkg/Universal/Runtime/RuntimeDxe/Ipf/PeHotRelocateEx.h new file mode 100644 index 0000000000..00c3c100cd --- /dev/null +++ b/EdkModulePkg/Universal/Runtime/RuntimeDxe/Ipf/PeHotRelocateEx.h @@ -0,0 +1,76 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PeHotRelocateEx.h + +Abstract: + + Fixes Intel Itanium(TM) specific relocation types + + +Revision History + +--*/ + +#ifndef _PEHOTRELOCATE_EX_H_ +#define _PEHOTRELOCATE_EX_H_ + +#define EXT_IMM64(Value, Address, Size, InstPos, ValPos) \ + Value |= (((UINT64) ((*(Address) >> InstPos) & (((UINT64) 1 << Size) - 1))) << ValPos) + +#define INS_IMM64(Value, Address, Size, InstPos, ValPos) \ + * (UINT32 *) Address = \ + (*(UINT32 *) Address &~(((1 << Size) - 1) << InstPos)) | \ + ((UINT32) ((((UINT64) Value >> ValPos) & (((UINT64) 1 << Size) - 1))) << InstPos) + +#define IMM64_IMM7B_INST_WORD_X 3 +#define IMM64_IMM7B_SIZE_X 7 +#define IMM64_IMM7B_INST_WORD_POS_X 4 +#define IMM64_IMM7B_VAL_POS_X 0 + +#define IMM64_IMM9D_INST_WORD_X 3 +#define IMM64_IMM9D_SIZE_X 9 +#define IMM64_IMM9D_INST_WORD_POS_X 18 +#define IMM64_IMM9D_VAL_POS_X 7 + +#define IMM64_IMM5C_INST_WORD_X 3 +#define IMM64_IMM5C_SIZE_X 5 +#define IMM64_IMM5C_INST_WORD_POS_X 13 +#define IMM64_IMM5C_VAL_POS_X 16 + +#define IMM64_IC_INST_WORD_X 3 +#define IMM64_IC_SIZE_X 1 +#define IMM64_IC_INST_WORD_POS_X 12 +#define IMM64_IC_VAL_POS_X 21 + +#define IMM64_IMM41a_INST_WORD_X 1 +#define IMM64_IMM41a_SIZE_X 10 +#define IMM64_IMM41a_INST_WORD_POS_X 14 +#define IMM64_IMM41a_VAL_POS_X 22 + +#define IMM64_IMM41b_INST_WORD_X 1 +#define IMM64_IMM41b_SIZE_X 8 +#define IMM64_IMM41b_INST_WORD_POS_X 24 +#define IMM64_IMM41b_VAL_POS_X 32 + +#define IMM64_IMM41c_INST_WORD_X 2 +#define IMM64_IMM41c_SIZE_X 23 +#define IMM64_IMM41c_INST_WORD_POS_X 0 +#define IMM64_IMM41c_VAL_POS_X 40 + +#define IMM64_SIGN_INST_WORD_X 3 +#define IMM64_SIGN_SIZE_X 1 +#define IMM64_SIGN_INST_WORD_POS_X 27 +#define IMM64_SIGN_VAL_POS_X 63 + +#endif diff --git a/EdkModulePkg/Universal/Runtime/RuntimeDxe/PeHotRelocate.c b/EdkModulePkg/Universal/Runtime/RuntimeDxe/PeHotRelocate.c new file mode 100644 index 0000000000..4c2aeff78e --- /dev/null +++ b/EdkModulePkg/Universal/Runtime/RuntimeDxe/PeHotRelocate.c @@ -0,0 +1,216 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PeHotRelocate.c + +Abstract: + + +--*/ + +#include "Runtime.h" + +STATIC +VOID * +RuntimePeImageAddress ( + IN RUNTIME_IMAGE_RELOCATION_DATA *Image, + IN UINTN Address + ) +/*++ + +Routine Description: + + Converts an image address to the loaded address + +Arguments: + + Image - The relocation data of the image being loaded + + Address - The address to be converted to the loaded address + +Returns: + + NULL if the address can not be converted, otherwise, the converted address + +--*/ +{ + if (Address >= (Image->ImageSize) << EFI_PAGE_SHIFT) { + return NULL; + } + + return (CHAR8 *) ((UINTN) Image->ImageBase + Address); +} + +VOID +RelocatePeImageForRuntime ( + RUNTIME_IMAGE_RELOCATION_DATA *Image + ) +{ + CHAR8 *OldBase; + CHAR8 *NewBase; + EFI_IMAGE_DOS_HEADER *DosHdr; + EFI_IMAGE_NT_HEADERS *PeHdr; + UINT32 NumberOfRvaAndSizes; + EFI_IMAGE_DATA_DIRECTORY *DataDirectory; + EFI_IMAGE_DATA_DIRECTORY *RelocDir; + EFI_IMAGE_BASE_RELOCATION *RelocBase; + EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd; + UINT16 *Reloc; + UINT16 *RelocEnd; + CHAR8 *Fixup; + CHAR8 *FixupBase; + UINT16 *F16; + UINT32 *F32; + CHAR8 *FixupData; + UINTN Adjust; + EFI_STATUS Status; + + OldBase = (CHAR8 *) ((UINTN) Image->ImageBase); + NewBase = (CHAR8 *) ((UINTN) Image->ImageBase); + + Status = RuntimeDriverConvertPointer (0, (VOID **) &NewBase); + ASSERT_EFI_ERROR (Status); + + Adjust = (UINTN) NewBase - (UINTN) OldBase; + + // + // Find the image's relocate dir info + // + DosHdr = (EFI_IMAGE_DOS_HEADER *) OldBase; + if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { + // + // Valid DOS header so get address of PE header + // + PeHdr = (EFI_IMAGE_NT_HEADERS *) (((CHAR8 *) DosHdr) + DosHdr->e_lfanew); + } else { + // + // No Dos header so assume image starts with PE header. + // + PeHdr = (EFI_IMAGE_NT_HEADERS *) OldBase; + } + + if (PeHdr->Signature != EFI_IMAGE_NT_SIGNATURE) { + // + // Not a valid PE image so Exit + // + return ; + } + // + // Get some data from the PE type dependent data + // + NumberOfRvaAndSizes = PeHdr->OptionalHeader.NumberOfRvaAndSizes; + DataDirectory = &PeHdr->OptionalHeader.DataDirectory[0]; + + // + // Find the relocation block + // + // Per the PE/COFF spec, you can't assume that a given data directory + // is present in the image. You have to check the NumberOfRvaAndSizes in + // the optional header to verify a desired directory entry is there. + // + if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) { + RelocDir = DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC; + RelocBase = RuntimePeImageAddress (Image, RelocDir->VirtualAddress); + RelocBaseEnd = RuntimePeImageAddress (Image, RelocDir->VirtualAddress + RelocDir->Size); + } else { + // + // Cannot find relocations, cannot continue + // + ASSERT (FALSE); + return ; + } + + ASSERT (RelocBase != NULL && RelocBaseEnd != NULL); + + // + // Run the whole relocation block. And re-fixup data that has not been + // modified. The FixupData is used to see if the image has been modified + // since it was relocated. This is so data sections that have been updated + // by code will not be fixed up, since that would set them back to + // defaults. + // + FixupData = Image->RelocationData; + while (RelocBase < RelocBaseEnd) { + + Reloc = (UINT16 *) ((UINT8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION)); + RelocEnd = (UINT16 *) ((UINT8 *) RelocBase + RelocBase->SizeOfBlock); + FixupBase = (CHAR8 *) ((UINTN) Image->ImageBase) + RelocBase->VirtualAddress; + + // + // Run this relocation record + // + while (Reloc < RelocEnd) { + + Fixup = FixupBase + (*Reloc & 0xFFF); + switch ((*Reloc) >> 12) { + + case EFI_IMAGE_REL_BASED_ABSOLUTE: + break; + + case EFI_IMAGE_REL_BASED_HIGH: + F16 = (UINT16 *) Fixup; + if (*(UINT16 *) FixupData == *F16) { + *F16 = (UINT16) ((*F16 << 16) + ((UINT16) Adjust & 0xffff)); + } + + FixupData = FixupData + sizeof (UINT16); + break; + + case EFI_IMAGE_REL_BASED_LOW: + F16 = (UINT16 *) Fixup; + if (*(UINT16 *) FixupData == *F16) { + *F16 = (UINT16) (*F16 + ((UINT16) Adjust & 0xffff)); + } + + FixupData = FixupData + sizeof (UINT16); + break; + + case EFI_IMAGE_REL_BASED_HIGHLOW: + F32 = (UINT32 *) Fixup; + FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32)); + if (*(UINT32 *) FixupData == *F32) { + *F32 = *F32 + (UINT32) Adjust; + } + + FixupData = FixupData + sizeof (UINT32); + break; + + case EFI_IMAGE_REL_BASED_HIGHADJ: + // + // Not implemented, but not used in EFI 1.0 + // + ASSERT (FALSE); + break; + + default: + // + // Only Itanium requires ConvertPeImage_Ex + // + Status = PeHotRelocateImageEx (Reloc, Fixup, &FixupData, Adjust); + if (EFI_ERROR (Status)) { + return ; + } + } + // + // Next relocation record + // + Reloc += 1; + } + // + // next reloc block + // + RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd; + } + + FlushCpuCache (Image->ImageBase, (UINT64) Image->ImageSize); +} diff --git a/EdkModulePkg/Universal/Runtime/RuntimeDxe/Runtime.c b/EdkModulePkg/Universal/Runtime/RuntimeDxe/Runtime.c new file mode 100644 index 0000000000..5a21d4961e --- /dev/null +++ b/EdkModulePkg/Universal/Runtime/RuntimeDxe/Runtime.c @@ -0,0 +1,574 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Runtime.c + +Abstract: + + Runtime Architectural Protocol as defined in the DXE CIS + + 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 fixup 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. + +--*/ + + +#include "Runtime.h" + +// +// This is a only short term solution. +// There is a change coming to the Runtime AP that +// will make it so the Runtime driver will not have to allocate any buffers. +// +#define MAX_RUNTIME_IMAGE_NUM (64) +#define MAX_RUNTIME_EVENT_NUM (64) +RUNTIME_IMAGE_RELOCATION_DATA mRuntimeImageBuffer[MAX_RUNTIME_IMAGE_NUM]; +RUNTIME_NOTIFY_EVENT_DATA mRuntimeEventBuffer[MAX_RUNTIME_EVENT_NUM]; +UINTN mRuntimeImageNumber; +UINTN mRuntimeEventNumber; + +// +// 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 = { + RuntimeDriverRegisterImage, + RuntimeDriverRegisterEvent +}; + +// +// Global Variables +// +LIST_ENTRY mRelocationList = INITIALIZE_LIST_HEAD_VARIABLE(mRelocationList); +LIST_ENTRY mEventList = INITIALIZE_LIST_HEAD_VARIABLE(mEventList); +BOOLEAN mEfiVirtualMode = FALSE; +EFI_GUID mLocalEfiUgaIoProtocolGuid = EFI_UGA_IO_PROTOCOL_GUID; +EFI_MEMORY_DESCRIPTOR *mVirtualMap = NULL; +UINTN mVirtualMapDescriptorSize; +UINTN mVirtualMapMaxIndex; + +EFI_LOADED_IMAGE_PROTOCOL *mMyLoadedImage; + +// +// Worker Functions +// +VOID +RuntimeDriverCalculateEfiHdrCrc ( + IN OUT EFI_TABLE_HEADER *Hdr + ) +/*++ + +Routine Description: + + Calcualte 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() + +Arguments: + + Hdr - Pointer to an EFI standard header + +Returns: + + None + +--*/ +{ + UINT32 Crc; + + Hdr->CRC32 = 0; + + Crc = 0; + RuntimeDriverCalculateCrc32 ((UINT8 *) Hdr, Hdr->HeaderSize, &Crc); + Hdr->CRC32 = Crc; +} + +EFI_STATUS +EFIAPI +RuntimeDriverRegisterImage ( + IN EFI_RUNTIME_ARCH_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS ImageBase, + IN UINTN ImageSize, + IN VOID *RelocationData + ) +/*++ + +Routine Description: + + When a SetVirtualAddressMap() is performed all the runtime images loaded by + DXE must be fixed up with the new virtual address map. To facilitate this the + Runtime Architectural Protocol needs to be informed of every runtime driver + that is registered. All the runtime images loaded by DXE should be registered + with this service by the DXE Core when ExitBootServices() is called. The + images that are registered with this service must have successfully been + loaded into memory with the Boot Service LoadImage(). As a result, no + parameter checking needs to be performed. + +Arguments: + + This - The EFI_RUNTIME_ARCH_PROTOCOL instance. + + ImageBase - Start of image that has been loaded in memory. It is either + a pointer to the DOS or PE header of the image. + + ImageSize - Size of the image in bytes. + + RelocationData - Information about the fixups that were performed on ImageBase + when it was loaded into memory. This information is needed + when the virtual mode fix-ups are reapplied so that data that + has been programmatically updated will not be fixed up. If + code updates a global variable the code is responsible for + fixing up the variable for virtual mode. + +Returns: + + EFI_SUCCESS - The ImageBase has been registered. + +--*/ +{ + RUNTIME_IMAGE_RELOCATION_DATA *RuntimeImage; + + if (mMyLoadedImage->ImageBase == (VOID *) (UINTN) ImageBase) { + // + // We don't want to relocate our selves, as we only run in physical mode. + // + return EFI_SUCCESS; + } + + RuntimeImage = &mRuntimeImageBuffer[mRuntimeImageNumber]; + mRuntimeImageNumber++; + ASSERT (mRuntimeImageNumber < MAX_RUNTIME_IMAGE_NUM); + + RuntimeImage->Valid = TRUE; + RuntimeImage->ImageBase = ImageBase; + RuntimeImage->ImageSize = ImageSize; + RuntimeImage->RelocationData = RelocationData; + + InsertTailList (&mRelocationList, &RuntimeImage->Link); + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +RuntimeDriverRegisterEvent ( + IN EFI_RUNTIME_ARCH_PROTOCOL *This, + IN UINT32 Type, + IN EFI_TPL NotifyTpl, + IN EFI_EVENT_NOTIFY NotifyFunction, + IN VOID *NotifyContext, + IN EFI_EVENT *Event + ) +/*++ + +Routine Description: + + This function is used to support the required runtime events. Currently only + runtime events of type EFI_EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE needs to be + registered with this service. All the runtime events that exist in the DXE + Core should be registered with this service when ExitBootServices() is called. + All the events that are registered with this service must have been created + with the Boot Service CreateEvent(). As a result, no parameter checking needs + to be performed. + +Arguments: + + This - The EFI_RUNTIME_ARCH_PROTOCOL instance. + + Type - The same as Type passed into CreateEvent(). + + NotifyTpl - The same as NotifyTpl passed into CreateEvent(). + + NotifyFunction - The same as NotifyFunction passed into CreateEvent(). + + NotifyContext - The same as NotifyContext passed into CreateEvent(). + + Event - The EFI_EVENT returned by CreateEvent(). Event must be in + runtime memory. + +Returns: + + EFI_SUCCESS - The Event has been registered. + +--*/ +{ + RUNTIME_NOTIFY_EVENT_DATA *RuntimeEvent; + + RuntimeEvent = &mRuntimeEventBuffer[mRuntimeEventNumber]; + mRuntimeEventNumber++; + ASSERT (mRuntimeEventNumber < MAX_RUNTIME_EVENT_NUM); + + RuntimeEvent->Type = Type; + RuntimeEvent->NotifyTpl = NotifyTpl; + RuntimeEvent->NotifyFunction = NotifyFunction; + RuntimeEvent->NotifyContext = NotifyContext; + RuntimeEvent->Event = Event; + + InsertTailList (&mEventList, &RuntimeEvent->Link); + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +RuntimeDriverConvertPointer ( + IN UINTN DebugDisposition, + IN OUT VOID **ConvertAddress + ) +{ + UINTN Address; + VOID *PlabelConvertAddress; + 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_POINTER) { + return EFI_SUCCESS; + } + + return EFI_INVALID_PARAMETER; + } + + PlabelConvertAddress = NULL; + 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 ((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; + } else if (Address < (VirtEndOfRange + 0x200000)) { + // + // On Itanium GP defines a window +/- 2 MB inside an image. + // The compiler may asign a GP value outside of the image. Thus + // it could fall out side of any of our valid regions + // + PlabelConvertAddress = (VOID *) (Address - (UINTN) VirtEntry->PhysicalStart + (UINTN) VirtEntry->VirtualStart); + } + } + } + + VirtEntry = NextMemoryDescriptor (VirtEntry, mVirtualMapDescriptorSize); + } + + if (DebugDisposition & EFI_IPF_GP_POINTER) { + // + // If it's an IPF GP and the GP was outside the image handle that case. + // + if (PlabelConvertAddress != NULL) { + *ConvertAddress = PlabelConvertAddress; + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +EFI_STATUS +RuntimeDriverConvertInternalPointer ( + IN OUT VOID **ConvertAddress + ) +{ + return RuntimeDriverConvertPointer (0x0, ConvertAddress); +} + +EFI_STATUS +EFIAPI +RuntimeDriverSetVirtualAddressMap ( + IN UINTN MemoryMapSize, + IN UINTN DescriptorSize, + IN UINT32 DescriptorVersion, + IN EFI_MEMORY_DESCRIPTOR *VirtualMap + ) +{ + RUNTIME_NOTIFY_EVENT_DATA *RuntimeEvent; + RUNTIME_IMAGE_RELOCATION_DATA *RuntimeImage; + LIST_ENTRY *Link; + UINTN Index; + UINTN Index1; + EFI_DRIVER_OS_HANDOFF_HEADER *DriverOsHandoffHeader; + EFI_DRIVER_OS_HANDOFF *DriverOsHandoff; + + // + // Can only switch to virtual addresses once the memory map is locked down, + // and can only set it once + // + if (!EfiAtRuntime () || mEfiVirtualMode) { + return EFI_UNSUPPORTED; + } + // + // Only understand the original descriptor format + // + if (DescriptorVersion != EFI_MEMORY_DESCRIPTOR_VERSION || DescriptorSize < sizeof (EFI_MEMORY_DESCRIPTOR)) { + return EFI_INVALID_PARAMETER; + } + // + // BugBug: Add code here to verify the memory map. We should + // cache a copy of the system memory map in the EFI System Table + // as a GUID pointer pair. + // + // + // Make sure all virtual translations are satisfied + // + mVirtualMapMaxIndex = MemoryMapSize / DescriptorSize; + + // + // BugBug :The following code does not work hence commented out. + // Need to be replaced by something that works. + // + // VirtEntry = VirtualMap; + // for (Index = 0; Index < mVirtualMapMaxIndex; Index++) { + // if (((VirtEntry->Attribute & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) && + // (VirtEntry->VirtualStart != 0) ) { + // return EFI_NO_MAPPING; + // } + // VirtEntry = NextMemoryDescriptor(VirtEntry, DescriptorSize); + // } + // + // We are now committed to go to virtual mode, so lets get to it! + // + mEfiVirtualMode = TRUE; + + // + // ConvertPointer() needs this mVirtualMap to do the conversion. So set up + // globals we need to parse the virtual address map. + // + mVirtualMapDescriptorSize = DescriptorSize; + mVirtualMap = VirtualMap; + + // + // Signal all the EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE events. + // The core call RuntimeDriverRegisterEvent() for + // every runtime event and we stored them in the mEventList + // + // + // Currently the bug in StatusCode/RuntimeLib has been fixed, it will + // check whether in Runtime or not (this is judged by looking at + // mEfiAtRuntime global So this ReportStatusCode will work + // + REPORT_STATUS_CODE ( + EFI_PROGRESS_CODE, + (EFI_SOFTWARE_EFI_BOOT_SERVICE | EFI_SW_RS_PC_SET_VIRTUAL_ADDRESS_MAP) + ); + + // + // BugBug - Commented out for now because the status code driver is not + // ready for runtime yet. The Status Code driver calls data hub with does + // a bunch of Boot Service things (locks, AllocatePool) and hangs somewhere + // on the way. + // + // ReportStatusCode ( + // EfiProgressCode, EfiMaxErrorSeverity, + // 0x03, 0x01, 12, // ReadyToBoot Progress code + // 0x00, 30, L"ConvertPointer" + // ); + // + for (Link = mEventList.ForwardLink; Link != &mEventList; Link = Link->ForwardLink) { + RuntimeEvent = _CR (Link, RUNTIME_NOTIFY_EVENT_DATA, Link); + if ((RuntimeEvent->Type & EFI_EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) == EFI_EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) { + RuntimeEvent->NotifyFunction ( + RuntimeEvent->Event, + RuntimeEvent->NotifyContext + ); + } + } + // + // Relocate runtime images. Runtime images loaded before the runtime AP was + // started will not be relocated, since they would not have gotten registered. + // This includes the code in this file. + // + for (Link = mRelocationList.ForwardLink; Link != &mRelocationList; Link = Link->ForwardLink) { + RuntimeImage = _CR (Link, RUNTIME_IMAGE_RELOCATION_DATA, Link); + if (RuntimeImage->Valid) { + RelocatePeImageForRuntime (RuntimeImage); + } + } + // + // 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); + RuntimeDriverCalculateEfiHdrCrc (&gRT->Hdr); + + // + // Convert the UGA OS Handoff Table if it is present in the Configuration Table + // + for (Index = 0; Index < gST->NumberOfTableEntries; Index++) { + if (CompareGuid (&mLocalEfiUgaIoProtocolGuid, &(gST->ConfigurationTable[Index].VendorGuid))) { + DriverOsHandoffHeader = gST->ConfigurationTable[Index].VendorTable; + for (Index1 = 0; Index1 < DriverOsHandoffHeader->NumberOfEntries; Index1++) { + DriverOsHandoff = (EFI_DRIVER_OS_HANDOFF *) + ( + (UINTN) DriverOsHandoffHeader + + DriverOsHandoffHeader->HeaderSize + + Index1 * + DriverOsHandoffHeader->SizeOfEntries + ); + RuntimeDriverConvertPointer (EFI_OPTIONAL_POINTER, (VOID **) &DriverOsHandoff->DevicePath); + RuntimeDriverConvertPointer (EFI_OPTIONAL_POINTER, (VOID **) &DriverOsHandoff->PciRomImage); + } + + RuntimeDriverConvertPointer (EFI_OPTIONAL_POINTER, (VOID **) &(gST->ConfigurationTable[Index].VendorTable)); + } + } + // + // 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; +} + +EFI_STATUS +EFIAPI +RuntimeDriverInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + Install Runtime AP. This code includes the EfiDriverLib, but it functions at + RT in physical mode. The only Lib services are gBS, gRT, and the DEBUG and + ASSERT macros (they do ReportStatusCode). + +Arguments: + (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT) + +Returns: + + EFI_SUCEESS - Runtime Driver Architectural Protocol Installed + + Other - Return value from gBS->InstallMultipleProtocolInterfaces + +--*/ +{ + EFI_STATUS Status; + + // + // This image needs to be exclued from relocation for virtual mode, so cache + // a copy of the Loaded Image protocol to test later. + // + Status = gBS->HandleProtocol ( + ImageHandle, + &gEfiLoadedImageProtocolGuid, + (VOID **) &mMyLoadedImage + ); + ASSERT_EFI_ERROR (Status); + + // + // Initialize the table used to compute 32-bit CRCs + // + RuntimeDriverInitializeCrc32Table (); + + // + // 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); + + mRuntimeImageNumber = 0; + mRuntimeEventNumber = 0; + + return Status; +} diff --git a/EdkModulePkg/Universal/Runtime/RuntimeDxe/Runtime.dxs b/EdkModulePkg/Universal/Runtime/RuntimeDxe/Runtime.dxs new file mode 100644 index 0000000000..42ca881f4b --- /dev/null +++ b/EdkModulePkg/Universal/Runtime/RuntimeDxe/Runtime.dxs @@ -0,0 +1,26 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Runtime.dxs + +Abstract: + + Dependency expression source file. + +--*/ +#include +#include + +DEPENDENCY_START + TRUE +DEPENDENCY_END diff --git a/EdkModulePkg/Universal/Runtime/RuntimeDxe/Runtime.h b/EdkModulePkg/Universal/Runtime/RuntimeDxe/Runtime.h new file mode 100644 index 0000000000..3803a9dadd --- /dev/null +++ b/EdkModulePkg/Universal/Runtime/RuntimeDxe/Runtime.h @@ -0,0 +1,129 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Runtime.h + +Abstract: + + Runtime Architectural Protocol as defined in the DXE CIS + + This code is used to produce the EFI runtime virtual switch over + +--*/ + +#ifndef _RUNTIME_H_ +#define _RUNTIME_H_ + +// +// Data structures +// +typedef struct { + LIST_ENTRY Link; + BOOLEAN Valid; + EFI_PHYSICAL_ADDRESS ImageBase; + UINTN ImageSize; // In no. of pages + VOID *RelocationData; +} RUNTIME_IMAGE_RELOCATION_DATA; + +typedef struct { + LIST_ENTRY Link; + IN UINT32 Type; + IN EFI_TPL NotifyTpl; + IN EFI_EVENT_NOTIFY NotifyFunction; + IN VOID *NotifyContext; + IN EFI_EVENT Event; +} RUNTIME_NOTIFY_EVENT_DATA; + +// +// Function Prototypes +// +VOID +RelocatePeImageForRuntime ( + RUNTIME_IMAGE_RELOCATION_DATA *Image + ) +; + +EFI_STATUS +PeHotRelocateImageEx ( + IN UINT16 *Reloc, + IN OUT CHAR8 *Fixup, + IN OUT CHAR8 **FixupData, + IN UINT64 Adjust + ) +; + +EFI_STATUS +EFIAPI +RuntimeDriverCalculateCrc32 ( + IN VOID *Data, + IN UINTN DataSize, + OUT UINT32 *CrcOut + ) +; + +EFI_STATUS +EFIAPI +RuntimeDriverRegisterImage ( + IN EFI_RUNTIME_ARCH_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS ImageBase, + IN UINTN ImageSize, + IN VOID *RelocationData + ) +; + +EFI_STATUS +EFIAPI +RuntimeDriverRegisterEvent ( + IN EFI_RUNTIME_ARCH_PROTOCOL *This, + IN UINT32 Type, + IN EFI_TPL NotifyTpl, + IN EFI_EVENT_NOTIFY NotifyFunction, + IN VOID *NotifyContext, + IN EFI_EVENT *Event + ) +; + +EFI_STATUS +EFIAPI +RuntimeDriverConvertPointer ( + IN UINTN DebugDisposition, + IN OUT VOID **ConvertAddress + ) +; + +VOID +RuntimeDriverInitializeCrc32Table ( + VOID + ) +; + +EFI_STATUS +EFIAPI +RuntimeDriverInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +; + + +// +// Cache Flush Routine. +// +EFI_STATUS +FlushCpuCache ( + IN EFI_PHYSICAL_ADDRESS Start, + IN UINT64 Length + ) +; + +#endif diff --git a/EdkModulePkg/Universal/Runtime/RuntimeDxe/Runtime.mbd b/EdkModulePkg/Universal/Runtime/RuntimeDxe/Runtime.mbd new file mode 100644 index 0000000000..19ac5953f9 --- /dev/null +++ b/EdkModulePkg/Universal/Runtime/RuntimeDxe/Runtime.mbd @@ -0,0 +1,46 @@ + + + + + Runtime + B601F8C4-43B7-4784-95B1-F4226CB40CEE + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + BaseLib + BaseMemoryLib + EdkDxeRuntimeDriverLib + UefiDriverEntryPoint + BaseDebugLibReportStatusCode + DxeReportStatusCodeLib + + EdkDxeSalLib + + + + _ModuleEntryPoint + + diff --git a/EdkModulePkg/Universal/Runtime/RuntimeDxe/Runtime.msa b/EdkModulePkg/Universal/Runtime/RuntimeDxe/Runtime.msa new file mode 100644 index 0000000000..8b918ab205 --- /dev/null +++ b/EdkModulePkg/Universal/Runtime/RuntimeDxe/Runtime.msa @@ -0,0 +1,80 @@ + + + + + Runtime + DXE_RUNTIME_DRIVER + RT_DRIVER + B601F8C4-43B7-4784-95B1-F4226CB40CEE + 0 + Component description file for DiskIo module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + BaseLib + DxeRuntimeDriverLib + UefiDriverEntryPoint + DebugLib + ReportStatusCodeLib + BaseMemoryLib + EdkDxeSalLib + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + + + Runtime.dxs + PeHotRelocate.c + Runtime.c + Runtime.h + Crc32.c + + Ia32\PeHotRelocateEx.c + + + x64\PeHotRelocateEx.c + x64\PeHotRelocateEx.h + + + Ipf\PeHotRelocateEx.c + Ipf\PeHotRelocateEx.h + + + + MdePkg + EdkModulePkg + + + LoadedImage + Runtime + + + + RuntimeDriverInitialize + + + + + + + diff --git a/EdkModulePkg/Universal/Runtime/RuntimeDxe/build.xml b/EdkModulePkg/Universal/Runtime/RuntimeDxe/build.xml new file mode 100644 index 0000000000..d11bd8deb4 --- /dev/null +++ b/EdkModulePkg/Universal/Runtime/RuntimeDxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Universal/Runtime/RuntimeDxe/x64/PeHotRelocateEx.c b/EdkModulePkg/Universal/Runtime/RuntimeDxe/x64/PeHotRelocateEx.c new file mode 100644 index 0000000000..82d464aebe --- /dev/null +++ b/EdkModulePkg/Universal/Runtime/RuntimeDxe/x64/PeHotRelocateEx.c @@ -0,0 +1,88 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PeHotRelocateEx.c + +Abstract: + + Stub to resolve the IPF hook that handles IPF specific relocation types + + +Revision History + +--*/ + +#include "Runtime.h" + +EFI_STATUS +PeHotRelocateImageEx ( + IN UINT16 *Reloc, + IN OUT CHAR8 *Fixup, + IN OUT CHAR8 **FixupData, + IN UINT64 Adjust + ) +/*++ + +Routine Description: + + Performs an Itanium-based platform specific relocation fixup + +Arguments: + + Reloc - Pointer to the relocation record + + Fixup - Pointer to the address to fix up + + FixupData - Pointer to a buffer to log the fixups + + Adjust - The offset to adjust the fixup + +Returns: + + EFI_SUCCESS + +--*/ +{ + return EFI_SUCCESS; + +} + +// +// Cache Flush Routine. +// +EFI_STATUS +FlushCpuCache ( + IN EFI_PHYSICAL_ADDRESS Start, + IN UINT64 Length + ) +/*++ + +Routine Description: + + Flush cache with specified range. + +Arguments: + + Start - Start address + Length - Length in bytes + +Returns: + + Status code + + EFI_SUCCESS - success + +--*/ +{ + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Universal/Security/SecurityStub/Dxe/SecurityStub.c b/EdkModulePkg/Universal/Security/SecurityStub/Dxe/SecurityStub.c new file mode 100644 index 0000000000..4b4581d4d8 --- /dev/null +++ b/EdkModulePkg/Universal/Security/SecurityStub/Dxe/SecurityStub.c @@ -0,0 +1,156 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + SecurityStub.c + +Abstract: + + This driver supports platform security service + +--*/ + +#include "SecurityStub.h" + +// +// Handle for the Security Architectural Protocol instance produced by this driver +// +EFI_HANDLE mSecurityArchProtocolHandle = NULL; + +// +// Security Architectural Protocol instance produced by this driver +// +EFI_SECURITY_ARCH_PROTOCOL mSecurityStub = { + SecurityStubAuthenticateState +}; + +// +// Worker functions +// +EFI_STATUS +EFIAPI +SecurityStubAuthenticateState ( + IN EFI_SECURITY_ARCH_PROTOCOL *This, + IN UINT32 AuthenticationStatus, + IN EFI_DEVICE_PATH_PROTOCOL *File + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + This - The EFI_SECURITY_ARCH_PROTOCOL instance. + + AuthenticationStatus - This is the authentication type returned from the Section + Extraction protocol. See the Section Extraction Protocol + Specification for details on this type. + + File - This is a pointer to the device path of the file that is + being dispatched. This will optionally be used for logging. + +Returns: + + EFI_SUCCESS - The file specified by File did authenticate, and the + platform policy dictates that the DXE Core may use File. + + EFI_INVALID_PARAMETER - File is NULL. + + 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. + + 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. + +--*/ +{ + if (File == NULL) { + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +SecurityStubInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Initialize the state information for the Security Architectural Protocol + +Arguments: + + ImageHandle of the loaded driver + Pointer to the System Table + +Returns: + + Status + + EFI_SUCCESS - successful installation of the service + EFI_OUT_OF_RESOURCES - cannot allocate protocol data structure + EFI_DEVICE_ERROR - cannot create the timer service + +--*/ +{ + EFI_STATUS Status; + + // + // Make sure the Security Architectural Protocol is not already installed in the system + // + ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiSecurityArchProtocolGuid); + + // + // Install the Security Architectural Protocol onto a new handle + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &mSecurityArchProtocolHandle, + &gEfiSecurityArchProtocolGuid, + &mSecurityStub, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/EdkModulePkg/Universal/Security/SecurityStub/Dxe/SecurityStub.dxs b/EdkModulePkg/Universal/Security/SecurityStub/Dxe/SecurityStub.dxs new file mode 100644 index 0000000000..bc3b419c92 --- /dev/null +++ b/EdkModulePkg/Universal/Security/SecurityStub/Dxe/SecurityStub.dxs @@ -0,0 +1,27 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + SecurityStub.dxs + +Abstract: + + Dependency expression source file. + +--*/ + +#include +#include + +DEPENDENCY_START + TRUE +DEPENDENCY_END diff --git a/EdkModulePkg/Universal/Security/SecurityStub/Dxe/SecurityStub.h b/EdkModulePkg/Universal/Security/SecurityStub/Dxe/SecurityStub.h new file mode 100644 index 0000000000..420afd1e05 --- /dev/null +++ b/EdkModulePkg/Universal/Security/SecurityStub/Dxe/SecurityStub.h @@ -0,0 +1,47 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + SecurityStub.h + +Abstract: + + Some definitions for Security Architectural Protocol stub driver + +--*/ + +#ifndef _SECURITY_STUB_ARCH_PROTOCOL_H +#define _SECURITY_STUB_ARCH_PROTOCOL_H + + + +// +// Function prototypes +// +EFI_STATUS +EFIAPI +SecurityStubAuthenticateState ( + IN EFI_SECURITY_ARCH_PROTOCOL *This, + IN UINT32 AuthenticationStatus, + IN EFI_DEVICE_PATH_PROTOCOL *File + ) +; + +EFI_STATUS +EFIAPI +SecurityStubInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +; + +#endif diff --git a/EdkModulePkg/Universal/Security/SecurityStub/Dxe/SecurityStub.mbd b/EdkModulePkg/Universal/Security/SecurityStub/Dxe/SecurityStub.mbd new file mode 100644 index 0000000000..2dc6fe738d --- /dev/null +++ b/EdkModulePkg/Universal/Security/SecurityStub/Dxe/SecurityStub.mbd @@ -0,0 +1,40 @@ + + + + + SecurityStub + F80697E9-7FD6-4665-8646-88E33EF71DFC + EDK_RELEASE_VERSION 0x00020000 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-22 19:19 + + + UefiBootServicesTableLib + BaseLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + EdkDxePrintLib + + diff --git a/EdkModulePkg/Universal/Security/SecurityStub/Dxe/SecurityStub.msa b/EdkModulePkg/Universal/Security/SecurityStub/Dxe/SecurityStub.msa new file mode 100644 index 0000000000..224fcec5a3 --- /dev/null +++ b/EdkModulePkg/Universal/Security/SecurityStub/Dxe/SecurityStub.msa @@ -0,0 +1,55 @@ + + + + + SecurityStub + DXE_DRIVER + BS_DRIVER + F80697E9-7FD6-4665-8646-88E33EF71DFC + EDK_RELEASE_VERSION 0x00020000 + Component description file for SecurityStub module + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + EFI_SPECIFICATION_VERSION 0x00000000 + 2006-03-12 17:09 + 2006-03-22 19:19 + + + DebugLib + UefiBootServicesTableLib + UefiDriverEntryPoint + + + SecurityStub.dxs + SecurityStub.h + SecurityStub.c + + + MdePkg + + + Security + + + + SecurityStubInitialize + + + diff --git a/EdkModulePkg/Universal/Security/SecurityStub/Dxe/build.xml b/EdkModulePkg/Universal/Security/SecurityStub/Dxe/build.xml new file mode 100644 index 0000000000..991db08208 --- /dev/null +++ b/EdkModulePkg/Universal/Security/SecurityStub/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Universal/StatusCode/RuntimeDxe/DebugAssert.c b/EdkModulePkg/Universal/StatusCode/RuntimeDxe/DebugAssert.c new file mode 100644 index 0000000000..75f0ed144d --- /dev/null +++ b/EdkModulePkg/Universal/StatusCode/RuntimeDxe/DebugAssert.c @@ -0,0 +1,231 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DebugAssert.c + +Abstract: + + Produce EfiDebugAssertProtocol to enable EfiUtilityLib to function. + The EfiUtilityLib is used by the EFI shell! + +--*/ + +#include "StatusCode.h" + +EFI_STATUS +EFIAPI +StatusCodeDebugAssert ( + IN EFI_DEBUG_ASSERT_PROTOCOL *This, + IN CHAR8 *FileName, + IN INTN LineNumber, + IN CHAR8 *Description + ); + +EFI_STATUS +EFIAPI +StatusCodeDebugPrint ( + IN EFI_DEBUG_ASSERT_PROTOCOL *This, + IN UINTN ErrorLevel, + IN CHAR8 *Format, + IN VA_LIST Marker + ); + +EFI_STATUS +EFIAPI +StatusCodePostCode ( + IN EFI_DEBUG_ASSERT_PROTOCOL * This, + IN UINT16 PostCode, + IN CHAR8 *PostCodeString OPTIONAL + ); + +EFI_STATUS +EFIAPI +StatusCodeGetErrorLevel ( + IN EFI_DEBUG_ASSERT_PROTOCOL *This, + IN UINTN *ErrorLevel + ); + +EFI_STATUS +EFIAPI +StatusCodeSetErrorLevel ( + IN EFI_DEBUG_ASSERT_PROTOCOL *This, + IN UINTN ErrorLevel + ); + +// +// Protocol instance, there can be only one. +// +EFI_HANDLE mHandle = NULL; +EFI_DEBUG_ASSERT_PROTOCOL mDebugAssertProtocol = { + StatusCodeDebugAssert, + StatusCodeDebugPrint, + StatusCodePostCode, + StatusCodeGetErrorLevel, + StatusCodeSetErrorLevel +}; + +// +// Function implementations +// +EFI_STATUS +EFIAPI +StatusCodeDebugAssert ( + IN EFI_DEBUG_ASSERT_PROTOCOL *This, + IN CHAR8 *FileName, + IN INTN LineNumber, + IN CHAR8 *Description + ) +/*++ + +Routine Description: + + Worker function for ASSERT (). If Error Logging hub is loaded log ASSERT + information. If Error Logging hub is not loaded CpuBreakpoint (). + +Arguments: + + This - Protocol instance. + FileName - File name of failing routine. + LineNumber - Line number of failing ASSERT(). + Description - Description, usually the assertion, + +Returns: + + EFI_SUCCESS The function always completes successfully. + +--*/ +{ + DebugAssert (FileName, LineNumber, Description); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +StatusCodeDebugPrint ( + IN EFI_DEBUG_ASSERT_PROTOCOL *This, + IN UINTN ErrorLevel, + IN CHAR8 *Format, + IN VA_LIST Marker + ) +/*++ + +Routine Description: + + Worker function for DEBUG (). If Error Logging hub is loaded log ASSERT + information. If Error Logging hub is not loaded do nothing. + +Arguments: + + This - Protocol Instance. + ErrorLevel - If error level is set do the debug print. + Format - String to use for the print, followed by Print arguments. + +Returns: + + EFI_SUCCESS The function always completes successfully. + +--*/ +{ + CHAR8 Buffer[EFI_STATUS_CODE_DATA_MAX_SIZE]; + + AsciiVSPrint (Buffer, EFI_STATUS_CODE_DATA_MAX_SIZE, Format, Marker); + DebugPrint (ErrorLevel, Buffer); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +StatusCodeGetErrorLevel ( + IN EFI_DEBUG_ASSERT_PROTOCOL *This, + IN UINTN *ErrorLevel + ) +{ + *ErrorLevel = PcdGet32(PcdDebugPrintErrorLevel); + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +StatusCodeSetErrorLevel ( + IN EFI_DEBUG_ASSERT_PROTOCOL *This, + IN UINTN ErrorLevel + ) +{ + return EFI_UNSUPPORTED; +} + +EFI_STATUS +EFIAPI +StatusCodePostCode ( + IN EFI_DEBUG_ASSERT_PROTOCOL * This, + IN UINT16 PostCode, + IN CHAR8 *PostCodeString OPTIONAL + ) +/*++ + +Routine Description: + + Write the code to IO ports 80 and 81. + +Arguments: + + This - Protocol Instance. + PostCode - Code to write + PostCodeString - String, currently ignored. + +Returns: + + EFI_SUCCESS The function always completes successfully. + +--*/ +{ + IoWrite8 (0x80, (UINT8) (PostCode & 0xff)); + IoWrite8 (0x81, (UINT8) (PostCode >> 8)); + + return EFI_SUCCESS; +} + +EFI_STATUS +InstallStatusCodeDebugAssert ( + VOID + ) +/*++ + +Routine Description: + + Install the status code debug assert protocol + +Arguments: + + None + +Returns: + + Results of call to InstallProtocolInterface. + +--*/ +{ + + DEBUG_CODE ( + gBS->InstallProtocolInterface ( + &mHandle, + &gEfiDebugAssertProtocolGuid, + EFI_NATIVE_INTERFACE, + &mDebugAssertProtocol + ); + ); + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Universal/StatusCode/RuntimeDxe/Ia32/Ia32StatusCode.c b/EdkModulePkg/Universal/StatusCode/RuntimeDxe/Ia32/Ia32StatusCode.c new file mode 100644 index 0000000000..d2e1009b7f --- /dev/null +++ b/EdkModulePkg/Universal/StatusCode/RuntimeDxe/Ia32/Ia32StatusCode.c @@ -0,0 +1,75 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Ia32StatusCode.c + +Abstract: + + Installs the ReportStatusCode runtime service. + +--*/ + +#include "StatusCode.h" + +// +// +// +EFI_HANDLE gStatusCodeHandle = NULL; + +const EFI_STATUS_CODE_PROTOCOL gStatusCodeInstance = { + StatusCodeReportStatusCode +}; + +// +// Define the driver entry point +// +EFI_STATUS +EFIAPI +InstallStatusCode ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Install the ReportStatusCode runtime service. + +Arguments: + + ImageHandle Image handle of the loaded driver + SystemTable Pointer to the System Table + +Returns: + + EFI_SUCCESS The function always returns success. + +--*/ +{ + EFI_STATUS Status; + + // + // Initialize RT status code + // + InitializeStatusCode (ImageHandle, SystemTable); + + Status = gBS->InstallMultipleProtocolInterfaces ( + &gStatusCodeHandle, + &gEfiStatusCodeRuntimeProtocolGuid, + &gStatusCodeInstance, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/EdkModulePkg/Universal/StatusCode/RuntimeDxe/Ia32/Ia32StatusCode.dxs b/EdkModulePkg/Universal/StatusCode/RuntimeDxe/Ia32/Ia32StatusCode.dxs new file mode 100644 index 0000000000..6371258e9a --- /dev/null +++ b/EdkModulePkg/Universal/StatusCode/RuntimeDxe/Ia32/Ia32StatusCode.dxs @@ -0,0 +1,26 @@ +#/*++ +# +# Copyright (c) 2006, Intel Corporation +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# Module Name: +# +# Ia32StatusCode.dxs +# +# Abstract: +# +# Dependency expression source file. +# +#--*/ +#include +#include + +DEPENDENCY_START + EFI_DATA_HUB_PROTOCOL_GUID AND EFI_CPU_IO_PROTOCOL_GUID +DEPENDENCY_END diff --git a/EdkModulePkg/Universal/StatusCode/RuntimeDxe/Ipf/IpfStatusCode.c b/EdkModulePkg/Universal/StatusCode/RuntimeDxe/Ipf/IpfStatusCode.c new file mode 100644 index 0000000000..62564c0cd8 --- /dev/null +++ b/EdkModulePkg/Universal/StatusCode/RuntimeDxe/Ipf/IpfStatusCode.c @@ -0,0 +1,126 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + IpfStatusCode.c + +Abstract: + + Contains the IPF installation function and an ESAL entry. + +--*/ + +#include "StatusCode.h" + +SAL_RETURN_REGS +ReportStatusCodeEsalServicesClassCommonEntry ( + IN UINT64 FunctionId, + IN UINT64 Arg2, + IN UINT64 Arg3, + IN UINT64 Arg4, + IN UINT64 Arg5, + IN UINT64 Arg6, + IN UINT64 Arg7, + IN UINT64 Arg8, + IN SAL_EXTENDED_SAL_PROC ExtendedSalProc, + IN BOOLEAN VirtualMode, + IN VOID *Global + ) +/*++ + +Routine Description: + + Main entry for Extended SAL ReportStatusCode Services + +Arguments: + + FunctionId Function Id which needed to be called + Arg2 Efi status code type + Arg3 Efi status code value + Arg4 Instance number + Arg5 Caller Id + Arg6 Efi status code data + Arg7 Not used + Arg8 Not used + ExtendedSalProc Esal Proc pointer + VirtualMode If this function is called in virtual mode + Global This module's global variable pointer + +Returns: + + SAL_RETURN_REGS + +--*/ +{ + SAL_RETURN_REGS ReturnVal; + + switch (FunctionId) { + + case ReportStatusCodeService: + ReturnVal.Status = StatusCodeReportStatusCode ( + (EFI_STATUS_CODE_TYPE) Arg2, + (EFI_STATUS_CODE_VALUE) Arg3, + (UINT32) Arg4, + (EFI_GUID *) Arg5, + (EFI_STATUS_CODE_DATA *) Arg6 + ); + break; + + default: + ReturnVal.Status = EFI_SAL_INVALID_ARGUMENT; + break; + } + + return ReturnVal; +} + +EFI_STATUS +EFIAPI +InstallStatusCode ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Install the ReportStatusCode runtime service. + +Arguments: + + ImageHandle Image handle of the loaded driver + SystemTable Pointer to the System Table + +Returns: + + EFI_SUCCESS The function always returns success. + +--*/ +{ + // + // Initialize RT status code + // + InitializeStatusCode (ImageHandle, SystemTable); + + // + // Initialize ESAL capabilities + // + RegisterEsalClass ( + &gEfiExtendedSalStatusCodeServicesProtocolGuid, + NULL, + ReportStatusCodeEsalServicesClassCommonEntry, + StatusCode, + NULL + ); + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Universal/StatusCode/RuntimeDxe/Ipf/IpfStatusCode.dxs b/EdkModulePkg/Universal/StatusCode/RuntimeDxe/Ipf/IpfStatusCode.dxs new file mode 100644 index 0000000000..aaa3efe3e1 --- /dev/null +++ b/EdkModulePkg/Universal/StatusCode/RuntimeDxe/Ipf/IpfStatusCode.dxs @@ -0,0 +1,27 @@ +#/*++ +# +# Copyright (c) 2006, Intel Corporation +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# Module Name: +# +# IpfStatusCode.dxs +# +# Abstract: +# +# Dependency expression source file. +# +#--*/ + +#include +#include + +DEPENDENCY_START + EFI_DATA_HUB_PROTOCOL_GUID AND EFI_EXTENDED_SAL_BASE_IO_SERVICES_PROTOCOL_GUID +DEPENDENCY_END diff --git a/EdkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCode.c b/EdkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCode.c new file mode 100644 index 0000000000..13b6426beb --- /dev/null +++ b/EdkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCode.c @@ -0,0 +1,172 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + StatusCode.c + +Abstract: + + Status Code Architectural Protocol implementation as defined in Tiano + Architecture Specification. + + This driver also depends on the DataHub, and will log all status code info + to the DataHub. Fatal Errors are Printed to Standard Error (StdErr) and not + logged to the data hub (If you crash what good is the data in the data hub). + + This driver has limited functionality at runtime and will not log to Data Hub + at runtime. + + Notes: + This driver assumes the following ReportStatusCode strategy: + PEI -> uses PeiReportStatusCode + DXE IPL -> uses PeiReportStatusCode + early DXE -> uses PeiReportStatusCode via HOB + DXE -> This driver + RT -> This driver + +--*/ + +#include "StatusCode.h" + +EFI_LOCK mStatusCodeLock; +BOOLEAN mStatusCodeFlag = FALSE; + +// +// Function implemenations +// + + +EFI_STATUS +EFIAPI +StatusCodeReportStatusCode ( + 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 + ) +/*++ + +Routine Description: + + Calls into the platform library which dispatches the platform specific + listeners. For NT environments we still call back into PEI because the + ReportStatusCode functionality requires Win32 services and is built into + the SecMain.exe utility. + +Arguments: + + (See Tiano Runtime Specification) + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + + // + // Acquire the lock required to update mStatusCodeFlag + // + Status = EfiAcquireLockOrFail (&mStatusCodeLock); + if (EFI_ERROR (Status)) { + // + // Check for reentrancy of the lock + // + return EFI_DEVICE_ERROR; + } + // + // Check to see if we are already in the middle of a ReportStatusCode() + // + if (mStatusCodeFlag) { + EfiReleaseLock (&mStatusCodeLock); + return EFI_DEVICE_ERROR; + } + // + // Set the flag to show we are in the middle of a ReportStatusCode() + // + mStatusCodeFlag = TRUE; + + // + // Release the lock for updating mStatusCodeFlag + // + EfiReleaseLock (&mStatusCodeLock); + + // + // Go do the work required to report a status code + // + RtPlatformReportStatusCode (CodeType, Value, Instance, CallerId, Data); + + // + // Acquire the lock required to update mStatusCodeFlag + // + Status = EfiAcquireLockOrFail (&mStatusCodeLock); + if (EFI_ERROR (Status)) { + // + // Check for reentrancy of the lock + // + return EFI_DEVICE_ERROR; + } + // + // Clear the flag to show we are no longer in the middle of a ReportStatusCode() + // + mStatusCodeFlag = FALSE; + + // + // Release the lock for updating mStatusCodeFlag + // + EfiReleaseLock (&mStatusCodeLock); + + return EFI_SUCCESS; +} +// +// Protocol instance, there can be only one. +// +EFI_STATUS +InitializeStatusCode ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Install Driver to produce Report Status Code Arch Protocol + +Arguments: + + (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT) + +Returns: + + EFI_SUCCESS - Logging Hub protocol installed + Other - No protocol installed, unload driver. + +--*/ +{ + + EfiInitializeLock (&mStatusCodeLock, EFI_TPL_HIGH_LEVEL); + + // + // Call the platform hook to initialize the different listeners. + // + RtPlatformStatusCodeInitialize (); + + // + // Register a protocol that EfiUtilityLib can use to implement DEBUG () and ASSERT () + // Macros. + // + InstallStatusCodeDebugAssert (); + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCode.h b/EdkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCode.h new file mode 100644 index 0000000000..cb4a4d9def --- /dev/null +++ b/EdkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCode.h @@ -0,0 +1,64 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + StatusCode.h + +Abstract: + + EFI DXE/RT Status Code include file. + +--*/ + +#ifndef _EFI_RUNTIME_STATUS_CODE_H_ +#define _EFI_RUNTIME_STATUS_CODE_H_ + +// +// Function prototypes +// + +EFI_STATUS +EFIAPI +StatusCodeReportStatusCode ( + 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 + ) +; + +EFI_STATUS +InitializeStatusCode ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +; + +EFI_STATUS +InstallStatusCodeDebugAssert ( + VOID + ) +; + +// +// Driver entry point +// +EFI_STATUS +EFIAPI +InstallStatusCode ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +; + +#endif diff --git a/EdkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCode.mbd b/EdkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCode.mbd new file mode 100644 index 0000000000..923914aee9 --- /dev/null +++ b/EdkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCode.mbd @@ -0,0 +1,55 @@ + + + + + StatusCode + 9F455D3B-2B8A-4c06-960B-A71B9714B9CD + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + + UefiBootServicesTableLib + BaseLib + EdkDxeRuntimeDriverLib + UefiDriverEntryPoint + UefiLib + BasePrintLib + BaseDebugLibReportStatusCode + EdkRtPlatformStatusCodeLib + DxeIoLibCpuIo + BaseMemoryLib + DxeReportStatusCodeLib + EdkRtMemoryStatusCodeLib + EdkBsDataHubStatusCodeLib + DxeHobLib + DxeMemoryAllocationLib + EdkMemoryStatusCodeLib + + + EdkDxeSalLib + + + + _ModuleEntryPoint + + diff --git a/EdkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCode.msa b/EdkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCode.msa new file mode 100644 index 0000000000..b0d888b963 --- /dev/null +++ b/EdkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCode.msa @@ -0,0 +1,77 @@ + + + + + StatusCode + DXE_RUNTIME_DRIVER + RT_DRIVER + 9F455D3B-2B8A-4c06-960B-A71B9714B9CD + 0 + Component description file for DiskIo module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + BaseLib + DxeRuntimeDriverLib + UefiDriverEntryPoint + UefiLib + DebugLib + PrintLib + IoLib + EdkRtPlatformStatusCodeLib + EdkDxeSalLib + UefiBootServicesTableLib + PcdLib + + + DebugAssert.c + StatusCode.c + StatusCode.h + + Ia32\Ia32StatusCode.c + Ia32\Ia32StatusCode.dxs + + + x64\x64StatusCode.c + x64\x64StatusCode.dxs + + + Ipf\IpfStatusCode.c + Ipf\IpfStatusCode.dxs + + + + MdePkg + EdkModulePkg + + + DebugAssert + ExtendedSalStatusCodeServices + + + + InstallStatusCode + + + diff --git a/EdkModulePkg/Universal/StatusCode/RuntimeDxe/build.xml b/EdkModulePkg/Universal/StatusCode/RuntimeDxe/build.xml new file mode 100644 index 0000000000..994d073598 --- /dev/null +++ b/EdkModulePkg/Universal/StatusCode/RuntimeDxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Universal/StatusCode/RuntimeDxe/x64/x64StatusCode.c b/EdkModulePkg/Universal/StatusCode/RuntimeDxe/x64/x64StatusCode.c new file mode 100644 index 0000000000..4c8ad0c81a --- /dev/null +++ b/EdkModulePkg/Universal/StatusCode/RuntimeDxe/x64/x64StatusCode.c @@ -0,0 +1,75 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + x64StatusCode.c + +Abstract: + + Installs the ReportStatusCode runtime service. + +--*/ + +#include "StatusCode.h" + +// +// +// +EFI_HANDLE gStatusCodeHandle = NULL; + +const EFI_STATUS_CODE_PROTOCOL gStatusCodeInstance = { + StatusCodeReportStatusCode +}; + +// +// Define the driver entry point +// +EFI_STATUS +EFIAPI +InstallStatusCode ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Install the ReportStatusCode runtime service. + +Arguments: + + ImageHandle Image handle of the loaded driver + SystemTable Pointer to the System Table + +Returns: + + EFI_SUCCESS The function always returns success. + +--*/ +{ + EFI_STATUS Status; + + // + // Initialize RT status code + // + InitializeStatusCode (ImageHandle, SystemTable); + + Status = gBS->InstallMultipleProtocolInterfaces ( + &gStatusCodeHandle, + &gEfiStatusCodeRuntimeProtocolGuid, + &gStatusCodeInstance, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/EdkModulePkg/Universal/StatusCode/RuntimeDxe/x64/x64StatusCode.dxs b/EdkModulePkg/Universal/StatusCode/RuntimeDxe/x64/x64StatusCode.dxs new file mode 100644 index 0000000000..74cf23eee3 --- /dev/null +++ b/EdkModulePkg/Universal/StatusCode/RuntimeDxe/x64/x64StatusCode.dxs @@ -0,0 +1,27 @@ +#/*++ +# +# Copyright (c) 2006, Intel Corporation +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# Module Name: +# +# x64StatusCode.dxs +# +# Abstract: +# +# Dependency expression source file. +# +#--*/ + +#include +#include + +DEPENDENCY_START + EFI_DATA_HUB_PROTOCOL_GUID AND EFI_CPU_IO_PROTOCOL_GUID +DEPENDENCY_END diff --git a/EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/Fonts.c b/EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/Fonts.c new file mode 100644 index 0000000000..52dc12e877 --- /dev/null +++ b/EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/Fonts.c @@ -0,0 +1,263 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Fonts.c + +Abstract: + + This file contains the Glyph/Font processing code to the HII database. + +--*/ + + +#include "HiiDatabase.h" + +// +// We only need to define a wide glyph, since we will seed the narrow glyph with EFI_NARROW_GLYPH size of +// this data structure +// +UINT8 mUnknownGlyph[38] = { + 0xaa, + 0x55, + 0xaa, + 0x55, + 0xaa, + 0x55, + 0xaa, + 0x55, + 0xaa, + 0x55, + 0xaa, + 0x55, + 0xaa, + 0x55, + 0xaa, + 0x55, + 0xaa, + 0x55, + 0xAA, + 0xaa, + 0x55, + 0xaa, + 0x55, + 0xaa, + 0x55, + 0xaa, + 0x55, + 0xaa, + 0x55, + 0xaa, + 0x55, + 0xaa, + 0x55, + 0xaa, + 0x55, + 0xaa, + 0x55, + 0xAA +}; + +EFI_STATUS +EFIAPI +HiiGetGlyph ( + IN EFI_HII_PROTOCOL *This, + IN CHAR16 *Source, + IN OUT UINT16 *Index, + OUT UINT8 **GlyphBuffer, + OUT UINT16 *BitWidth, + IN OUT UINT32 *InternalStatus + ) +/*++ + +Routine Description: + Translates a Unicode character into the corresponding font glyph. + If the Source was pointing to a non-spacing character, the next Source[*Index] + character will be parsed and OR'd to the GlyphBuffer until a spacing character + is found in the Source. Since non-spacing characters are considered to be the + same pixel width as a regular character their BitWidth will be reflected correctly + however due to their special attribute, they are considered to be zero advancing width. + This basically means that the cursor would not advance, thus the character that follows + it would overlay the non-spacing character. The Index is modified to reflect both the + incoming array entry into the Source string but also the outgoing array entry after having + parsed the equivalent of a single Glyph's worth of data. + +Arguments: + +Returns: + +--*/ +{ + EFI_HII_GLOBAL_DATA *GlobalData; + EFI_HII_DATA *HiiData; + UINTN Count; + BOOLEAN Narrow; + UINTN Location; + UINTN SearchLocation; + UINTN Value; + CHAR16 Character; + UINTN Attributes; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + HiiData = EFI_HII_DATA_FROM_THIS (This); + + GlobalData = HiiData->GlobalData; + Count = sizeof (GlobalData->NarrowGlyphs->GlyphCol1); + + Location = *Index; + SearchLocation = *Index; + Narrow = TRUE; + + if (Source[Location] == NARROW_CHAR || Source[Location] == WIDE_CHAR) { + *InternalStatus = 0; + } + // + // We don't know what glyph database to look in - let's figure it out + // + if (*InternalStatus == 0) { + // + // Determine if we are looking for narrow or wide glyph data + // + do { + if (Source[SearchLocation] == NARROW_CHAR || Source[SearchLocation] == WIDE_CHAR) { + // + // We found something that identifies what glyph database to look in + // + if (Source[SearchLocation] == WIDE_CHAR) { + Narrow = FALSE; + *BitWidth = WIDE_WIDTH; + *InternalStatus = WIDE_CHAR; + Location++; + break; + } else { + Narrow = TRUE; + *BitWidth = NARROW_WIDTH; + *InternalStatus = NARROW_CHAR; + Location++; + break; + } + } + } while (SearchLocation-- > 0); + } + + if (*InternalStatus == NARROW_CHAR) { + Narrow = TRUE; + *BitWidth = NARROW_WIDTH; + } else if (*InternalStatus == WIDE_CHAR) { + Narrow = FALSE; + *BitWidth = WIDE_WIDTH; + } else { + // + // Without otherwise knowing what the width is narrow (e.g. someone passed in a string with index of 0 + // we wouldn't be able to determine the width of the data.) + // BUGBUG - do we go to wide database and if exist, ignore narrow? Check Unicode spec.... + // + Narrow = TRUE; + *BitWidth = NARROW_WIDTH; + } + + Character = Source[Location]; + + if (Narrow) { + if (GlobalData->NarrowGlyphs[Character].UnicodeWeight != 0x0000) { + *GlyphBuffer = (UINT8 *) (&GlobalData->NarrowGlyphs[Character]); + Attributes = GlobalData->NarrowGlyphs[Character].Attributes & EFI_GLYPH_NON_SPACING; + } else { + // + // Glyph is uninitialized - return an error, but hand back the glyph + // + *GlyphBuffer = (UINT8 *) (&GlobalData->NarrowGlyphs[Character]); + *Index = (UINT16) (Location + 1); + return EFI_NOT_FOUND; + } + } else { + // + // Wide character + // + if (GlobalData->WideGlyphs[Character].UnicodeWeight != 0x0000) { + *GlyphBuffer = (UINT8 *) (&GlobalData->WideGlyphs[Character]); + Attributes = GlobalData->WideGlyphs[Character].Attributes & EFI_GLYPH_NON_SPACING; + } else { + // + // Glyph is uninitialized - return an error, but hand back the glyph + // + *GlyphBuffer = (UINT8 *) (&GlobalData->WideGlyphs[Character]); + *Index = (UINT16) (Location + 1); + return EFI_NOT_FOUND; + } + } + // + // This is a non-spacing character. It will be followed by either more non-spacing + // characters or a regular character. We need to OR together the data associated with each. + // + for (; Attributes != 0; Location++) { + // + // Character is the Unicode value which is the index into the Glyph array. + // + Character = Source[Location]; + + if (Narrow) { + for (Value = 0; Value != Count; Value++) { + *GlyphBuffer[Location + Value] |= GlobalData->NarrowGlyphs[Character].GlyphCol1[Value]; + } + + Attributes = GlobalData->NarrowGlyphs[Character].Attributes & EFI_GLYPH_NON_SPACING; + } else { + for (Value = 0; Value != Count; Value++) { + *GlyphBuffer[Location + Value] |= GlobalData->WideGlyphs[Character].GlyphCol1[Value]; + *GlyphBuffer[Location + Value + Count] |= GlobalData->WideGlyphs[Character].GlyphCol2[Value]; + } + + Attributes = GlobalData->WideGlyphs[Character].Attributes & EFI_GLYPH_NON_SPACING; + } + } + // + // Source[*Index] should point to the next character to process + // + *Index = (UINT16) (Location + 1); + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +HiiGlyphToBlt ( + IN EFI_HII_PROTOCOL *This, + IN UINT8 *GlyphBuffer, + IN EFI_UGA_PIXEL Foreground, + IN EFI_UGA_PIXEL Background, + IN UINTN Count, + IN UINTN Width, + IN UINTN Height, + IN OUT EFI_UGA_PIXEL *BltBuffer + ) +{ + UINTN X; + UINTN Y; + + // + // Convert Monochrome bitmap of the Glyph to BltBuffer structure + // + for (Y = 0; Y < Height; Y++) { + for (X = 0; X < Width; X++) { + if ((((EFI_NARROW_GLYPH *) GlyphBuffer)->GlyphCol1[Y] & (1 << X)) != 0) { + BltBuffer[Y * Width * Count + (Width - X - 1)] = Foreground; + } else { + BltBuffer[Y * Width * Count + (Width - X - 1)] = Background; + } + } + } + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/Forms.c b/EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/Forms.c new file mode 100644 index 0000000000..a0a9619197 --- /dev/null +++ b/EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/Forms.c @@ -0,0 +1,1564 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Forms.c + +Abstract: + + This file contains the form processing code to the HII database. + +--*/ + + +#include "HiiDatabase.h" + +CHAR16* +Ascii2Unicode ( + OUT CHAR16 *UnicodeStr, + IN CHAR8 *AsciiStr + ) +/*++ + + Routine Description: + + This function converts ASCII string to Unicode string. + + Arguments: + + UnicodeStr - NULL terminated Unicode output string. + AsciieStr - NULL terminated ASCII input string. + + Returns: + + Start of the Unicode ouput string. + +--*/ + +{ + CHAR16 *Str = UnicodeStr; + while (TRUE) { + *(UnicodeStr++) = (CHAR16) *AsciiStr; + if (*(AsciiStr++) == '\0') { + return Str; + } + } +} + +CHAR8* +Unicode2Ascii ( + OUT CHAR8 *AsciiStr, + IN CHAR16 *UnicodeStr + ) +/*++ + + Routine Description: + + This function converts Unicode string to ASCII string. + + Arguments: + + AsciieStr - NULL terminated ASCII output string. + UnicodeStr - NULL terminated Unicode input string. + + Returns: + + Start of the ASCII ouput string. + +--*/ + +{ + CHAR8 *Str = AsciiStr; + while (TRUE) { + *(AsciiStr++) = (CHAR8) *UnicodeStr; + if (*(UnicodeStr++) == '\0') { + return Str; + } + } +} + +VOID +ExtractDevicePathData ( + IN EFI_HII_DATA_TABLE *DataTable, + IN UINT8 *IfrData, + IN OUT UINT8 **ExportBufferPtr + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + UINT8 *ExportBuffer; + + ExportBuffer = *ExportBufferPtr; + + // + // BUGBUG - don't have devicepath data yet, setting dummy value + // + DataTable++; + ExportBuffer = (UINT8 *) DataTable; + ((EFI_HII_DEVICE_PATH_PACK *) ExportBuffer)->Header.Type = EFI_HII_DEVICE_PATH; + ((EFI_HII_DEVICE_PATH_PACK *) ExportBuffer)->Header.Length = (UINT32) (sizeof (EFI_HII_DEVICE_PATH_PACK) + sizeof (EFI_DEVICE_PATH_PROTOCOL)); + + // + // BUGBUG - part of hack - skip the Device Path Pack.....place some data + // + ExportBuffer = ExportBuffer + sizeof (EFI_HII_DEVICE_PATH_PACK); + + ((EFI_DEVICE_PATH_PROTOCOL *) ExportBuffer)->Type = EFI_END_ENTIRE_DEVICE_PATH; + ((EFI_DEVICE_PATH_PROTOCOL *) ExportBuffer)->SubType = EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; + + // + // BUGBUG - still part of hack.... + // + ExportBuffer = ExportBuffer + sizeof (EFI_DEVICE_PATH_PROTOCOL); + *ExportBufferPtr = ExportBuffer; +} + +VOID +ExtractVariableData ( + IN OUT EFI_HII_DATA_TABLE *DataTable, + IN UINT8 *IfrData, + IN OUT UINT8 **ExportBufferPtr + ) +/*++ + +Routine Description: + + This function extract the EFI_HII_VARIABLE_PACK portion from the + each of the EFI_HII_PACKAGE_INSTANCE in HII handle database. + +Arguments: + + DataTable ¨C On input, this parameter point to the EFI_HII_DATA_TABLE structure + of the final data buffer for the EFI_HII_EXPORT interface. This function + update the NumberOfVariableData attribute. + IfrData - It points to a staring address of a EFI_HII_IFR_PACK structure. + ExportBufferPtr ¨C On input, it points the starting address of the data buffer to + host the variable pack. On output, it is the starting address + of data buffer for the next extraction operation. +Returns: + + VOID + +--*/ +{ + EFI_HII_VARIABLE_PACK *VariableContents; + UINT8 *ExportBuffer; + UINTN Index; + UINTN Index2; + UINTN TempValue; + UINTN TempValue2; + EFI_FORM_CALLBACK_PROTOCOL *FormCallback; + EFI_PHYSICAL_ADDRESS CallbackHandle; + EFI_STATUS Status; + CHAR16 *String; + + FormCallback = NULL; + CallbackHandle = 0; + ExportBuffer = *ExportBufferPtr; + + for (Index = 0; IfrData[Index] != EFI_IFR_END_FORM_SET_OP;) { + VariableContents = (EFI_HII_VARIABLE_PACK *) ExportBuffer; + + switch (IfrData[Index]) { + case EFI_IFR_FORM_SET_OP: + TempValue = EFI_HII_VARIABLE; + CopyMem (&VariableContents->Header.Type, &TempValue, sizeof (UINT16)); + CopyMem (&TempValue, &((EFI_IFR_FORM_SET *) &IfrData[Index])->NvDataSize, sizeof (UINT16)); + + // + // If the variable has 0 size, do not process it + // + if (TempValue == 0) { + break; + } + // + // Add the size of the variable pack overhead. Later, will also add the size of the + // name of the variable. + // + TempValue = TempValue + sizeof (EFI_HII_VARIABLE_PACK); + + CopyMem (&VariableContents->Header.Length, &TempValue, sizeof (UINT32)); + CopyMem ( + &CallbackHandle, + &((EFI_IFR_FORM_SET *) &IfrData[Index])->CallbackHandle, + sizeof (EFI_PHYSICAL_ADDRESS) + ); + if (CallbackHandle != 0) { + Status = gBS->HandleProtocol ( + (EFI_HANDLE) (UINTN) CallbackHandle, + &gEfiFormCallbackProtocolGuid, + (VOID *) &FormCallback + ); + } + // + // Since we have a "Setup" variable that wasn't specified by a variable op-code + // it will have a VariableId of 0. All other variable op-codes will have a designation + // of VariableId 1+ + // + TempValue = 0; + CopyMem (&VariableContents->VariableId, &TempValue, sizeof (UINT16)); + CopyMem (&VariableContents->VariableGuid, &((EFI_IFR_FORM_SET *) &IfrData[Index])->Guid, sizeof (EFI_GUID)); + TempValue = sizeof (SETUP_MAP_NAME); + CopyMem (&VariableContents->VariableNameLength, &TempValue, sizeof (UINT32)); + + // + // Add the size of the name to the Header Length + // + TempValue2 = 0; + CopyMem (&TempValue2, &VariableContents->Header.Length, sizeof (UINT32)); + TempValue2 = TempValue + TempValue2; + CopyMem (&VariableContents->Header.Length, &TempValue2, sizeof (UINT32)); + + ExportBuffer = ExportBuffer + sizeof (EFI_HII_VARIABLE_PACK); + CopyMem (ExportBuffer, SETUP_MAP_NAME, sizeof (SETUP_MAP_NAME)); + ExportBuffer = ExportBuffer + sizeof (SETUP_MAP_NAME); + + CopyMem (&TempValue, &((EFI_IFR_FORM_SET *) &IfrData[Index])->NvDataSize, sizeof (UINT16)); + + if ((FormCallback != NULL) && (FormCallback->NvRead != NULL)) { + Status = FormCallback->NvRead ( + FormCallback, + (CHAR16 *) SETUP_MAP_NAME, + (EFI_GUID *)(UINTN)&VariableContents->VariableGuid, + NULL, + &TempValue, + ExportBuffer + ); + } else { + Status = gRT->GetVariable ( + (CHAR16 *) SETUP_MAP_NAME, + (EFI_GUID *)(UINTN)&VariableContents->VariableGuid, + NULL, + &TempValue, + ExportBuffer + ); + } + + ExportBuffer = (UINT8 *) (UINTN) (((UINTN) ExportBuffer) + TempValue); + DataTable->NumberOfVariableData++; + break; + + case EFI_IFR_VARSTORE_OP: + TempValue = EFI_HII_VARIABLE; + CopyMem (&VariableContents->Header.Type, &TempValue, sizeof (UINT16)); + CopyMem (&TempValue, &((EFI_IFR_VARSTORE *) &IfrData[Index])->Size, sizeof (UINT16)); + + // + // If the variable has 0 size, do not process it + // + if (TempValue == 0) { + break; + } + // + // Add the size of the variable pack overhead. Later, will also add the size of the + // name of the variable. + // + TempValue = TempValue + sizeof (EFI_HII_VARIABLE_PACK); + + CopyMem (&VariableContents->Header.Length, &TempValue, sizeof (UINT32)); + CopyMem (&VariableContents->VariableId, &((EFI_IFR_VARSTORE *) &IfrData[Index])->VarId, sizeof (UINT16)); + CopyMem (&VariableContents->VariableGuid, &((EFI_IFR_VARSTORE *) &IfrData[Index])->Guid, sizeof (EFI_GUID)); + TempValue = (UINTN) ((EFI_IFR_VARSTORE *) &IfrData[Index])->Header.Length - sizeof (EFI_IFR_VARSTORE); + TempValue = TempValue * 2; + CopyMem (&VariableContents->VariableNameLength, &TempValue, sizeof (UINT32)); + + // + // Add the size of the name to the Header Length + // + TempValue2 = 0; + CopyMem (&TempValue2, &VariableContents->Header.Length, sizeof (UINT32)); + TempValue2 = TempValue + TempValue2; + CopyMem (&VariableContents->Header.Length, &TempValue2, sizeof (UINT32)); + + ExportBuffer = ExportBuffer + sizeof (EFI_HII_VARIABLE_PACK); + String = (CHAR16 *) ExportBuffer; + for (Index2 = 0; Index2 < TempValue / 2; Index2++) { + ExportBuffer[Index2 * 2] = IfrData[Index + sizeof (EFI_IFR_VARSTORE) + Index2]; + ExportBuffer[Index2 * 2 + 1] = 0; + } + + ExportBuffer = ExportBuffer + TempValue; + + CopyMem (&TempValue, &((EFI_IFR_VARSTORE *) &IfrData[Index])->Size, sizeof (UINT16)); + + if ((FormCallback != NULL) && (FormCallback->NvRead != NULL)) { + Status = FormCallback->NvRead ( + FormCallback, + String, + (EFI_GUID *)(UINTN)&VariableContents->VariableGuid, + NULL, + &TempValue, + ExportBuffer + ); + } else { + Status = gRT->GetVariable ( + String, + (EFI_GUID *)(UINTN)&VariableContents->VariableGuid, + NULL, + &TempValue, + ExportBuffer + ); + } + + ExportBuffer = (UINT8 *) (UINTN) (((UINTN) ExportBuffer) + TempValue); + DataTable->NumberOfVariableData++; + break; + } + + Index = IfrData[Index + 1] + Index; + } + // + // If we have added a variable pack, add a dummy empty one to signify the end + // + if (ExportBuffer != *ExportBufferPtr) { + VariableContents = (EFI_HII_VARIABLE_PACK *) ExportBuffer; + TempValue = EFI_HII_VARIABLE; + CopyMem (&VariableContents->Header.Type, &TempValue, sizeof (UINT16)); + TempValue = sizeof (EFI_HII_VARIABLE_PACK); + CopyMem (&VariableContents->Header.Length, &TempValue, sizeof (UINT32)); + ExportBuffer = ExportBuffer + sizeof (EFI_HII_VARIABLE_PACK); + } + + *ExportBufferPtr = ExportBuffer; +} + +EFI_STATUS +EFIAPI +HiiExportDatabase ( + IN EFI_HII_PROTOCOL *This, + IN EFI_HII_HANDLE Handle, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + This function allows a program to extract a form or form package that has + previously been registered with the EFI HII database. + +Arguments: + +Returns: + +--*/ +{ + EFI_HII_PACKAGE_INSTANCE *PackageInstance; + EFI_HII_DATA *HiiData; + EFI_HII_HANDLE_DATABASE *HandleDatabase; + EFI_HII_IFR_PACK *FormPack; + UINT8 *RawData; + UINT8 *ExportBuffer; + EFI_HII_EXPORT_TABLE *ExportTable; + EFI_HII_DATA_TABLE *DataTable; + BOOLEAN InsufficientSize; + BOOLEAN VariableExist; + UINT16 NumberOfHiiDataTables; + UINTN SizeNeeded; + UINTN Index; + UINTN VariableSize; + UINTN TempValue; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + HiiData = EFI_HII_DATA_FROM_THIS (This); + + HandleDatabase = HiiData->DatabaseHead; + + FormPack = NULL; + RawData = NULL; + PackageInstance = NULL; + InsufficientSize = FALSE; + NumberOfHiiDataTables = 0; + VariableSize = 0; + TempValue = 0; + SizeNeeded = sizeof (EFI_HII_EXPORT_TABLE); + + // + // How many total tables are there? + // + for (; HandleDatabase != NULL; HandleDatabase = HandleDatabase->NextHandleDatabase) { + if ((Handle != 0) && (Handle != HandleDatabase->Handle)) { + continue; + } + + VariableExist = FALSE; + NumberOfHiiDataTables++; + PackageInstance = HandleDatabase->Buffer; + if (PackageInstance == NULL) { + continue; + } + // + // Extract Size of Export Package + // + SizeNeeded = SizeNeeded + PackageInstance->IfrSize + + PackageInstance->StringSize + + sizeof (EFI_HII_DATA_TABLE) + + sizeof (EFI_HII_DEVICE_PATH_PACK); + + // + // BUGBUG We aren't inserting Device path data yet + // + SizeNeeded = SizeNeeded + sizeof (EFI_DEVICE_PATH_PROTOCOL); + + // + // Extract Size of Variable Data + // + if (PackageInstance->IfrSize > 0) { + FormPack = (EFI_HII_IFR_PACK *) ((CHAR8 *) (&PackageInstance->IfrData) + sizeof (EFI_HII_PACK_HEADER)); + } else { + // + // No IFR? No variable information + // + continue; + } + + RawData = (UINT8 *) FormPack; + + for (Index = 0; RawData[Index] != EFI_IFR_END_FORM_SET_OP;) { + switch (RawData[Index]) { + case EFI_IFR_FORM_SET_OP: + CopyMem (&VariableSize, &((EFI_IFR_FORM_SET *) &RawData[Index])->NvDataSize, sizeof (UINT16)); + SizeNeeded = SizeNeeded + VariableSize + sizeof (SETUP_MAP_NAME) + sizeof (EFI_HII_VARIABLE_PACK); + VariableExist = TRUE; + break; + + case EFI_IFR_VARSTORE_OP: + CopyMem (&VariableSize, &((EFI_IFR_VARSTORE *) &RawData[Index])->Size, sizeof (UINT16)); + SizeNeeded = SizeNeeded + VariableSize + sizeof (EFI_HII_VARIABLE_PACK); + // + // We will be expanding the stored ASCII name to a Unicode string. This will cause some memory overhead + // Since the VARSTORE size already takes in consideration the ASCII size, we need to size it and add another + // instance of it. Essentially, 2 ASCII strings == 1 Unicode string in size. + // + TempValue = (UINTN) ((EFI_IFR_VARSTORE *) &RawData[Index])->Header.Length - sizeof (EFI_IFR_VARSTORE); + SizeNeeded = SizeNeeded + TempValue * 2; + VariableExist = TRUE; + break; + } + + Index = RawData[Index + 1] + Index; + } + // + // If a variable exists for this handle, add an additional variable pack overhead to + // indicate that we will have an extra null Variable Pack to signify the end of the Variable Packs + // + if (VariableExist) { + SizeNeeded = SizeNeeded + sizeof (EFI_HII_VARIABLE_PACK); + } + } + + if (SizeNeeded > *BufferSize) { + *BufferSize = SizeNeeded; + return EFI_BUFFER_TOO_SMALL; + } + // + // Zero out the incoming buffer + // + ZeroMem (Buffer, *BufferSize); + + // + // Cast the Buffer to EFI_HII_EXPORT_TABLE + // + ExportTable = (EFI_HII_EXPORT_TABLE *) Buffer; + + // + // Set the Revision for the Export Table + // + CopyMem (&ExportTable->Revision, &gEfiHiiProtocolGuid, sizeof (EFI_GUID)); + + ExportBuffer = (UINT8 *) (UINTN) (((UINT8 *) ExportTable) + sizeof (EFI_HII_EXPORT_TABLE)); + HandleDatabase = HiiData->DatabaseHead; + + // + // Check numeric value against the head of the database + // + for (; HandleDatabase != NULL; HandleDatabase = HandleDatabase->NextHandleDatabase) { + DataTable = (EFI_HII_DATA_TABLE *) ExportBuffer; + PackageInstance = HandleDatabase->Buffer; + // + // If not asking for a specific handle, export the entire database + // + if (Handle == 0) { + ExportTable->NumberOfHiiDataTables = NumberOfHiiDataTables; + CopyMem (&DataTable->PackageGuid, &PackageInstance->Guid, sizeof (EFI_GUID)); + DataTable->HiiHandle = PackageInstance->Handle; + DataTable->DevicePathOffset = (UINT32) (sizeof (EFI_HII_DATA_TABLE)); + + // + // Start Dumping DevicePath + // + ExtractDevicePathData (DataTable, RawData, &ExportBuffer); + + if (((UINTN) ExportBuffer) == ((UINTN) DataTable)) { + // + // If there is no DevicePath information - set offset to 0 to signify the absence of data to parse + // + DataTable->DevicePathOffset = 0; + } + + DataTable->VariableDataOffset = (UINT32) (((UINTN) ExportBuffer) - ((UINTN) DataTable)); + + if (PackageInstance->IfrSize > 0) { + FormPack = (EFI_HII_IFR_PACK *) ((CHAR8 *) (&PackageInstance->IfrData) + sizeof (EFI_HII_PACK_HEADER)); + + RawData = (UINT8 *) FormPack; + TempValue = 0; + + // + // Start dumping the Variable Data + // + ExtractVariableData (DataTable, RawData, &ExportBuffer); + DataTable->IfrDataOffset = (UINT32) (((UINTN) ExportBuffer) - ((UINTN) DataTable)); + + if (DataTable->VariableDataOffset == DataTable->IfrDataOffset) { + DataTable->VariableDataOffset = 0; + } + // + // Start dumping the IFR data (Note: It is in an IFR PACK) + // + CopyMem (ExportBuffer, &PackageInstance->IfrData, PackageInstance->IfrSize); + ExportBuffer = (UINT8 *) (UINTN) (((UINTN) ExportBuffer) + PackageInstance->IfrSize); + DataTable->StringDataOffset = (UINT32) (((UINTN) ExportBuffer) - ((UINTN) DataTable)); + + // + // Start dumping the String data (Note: It is in a String PACK) + // + if (PackageInstance->StringSize > 0) { + RawData = (UINT8 *) (((UINTN) &PackageInstance->IfrData) + PackageInstance->IfrSize); + CopyMem (ExportBuffer, RawData, PackageInstance->StringSize); + DataTable->DataTableSize = (UINT32) (DataTable->StringDataOffset + PackageInstance->StringSize); + + CopyMem (&TempValue, &((EFI_HII_STRING_PACK *) ExportBuffer)->Header.Length, sizeof (UINT32)); + for (; TempValue != 0;) { + DataTable->NumberOfLanguages++; + ExportBuffer = ExportBuffer + ((EFI_HII_STRING_PACK *) ExportBuffer)->Header.Length; + CopyMem (&TempValue, &((EFI_HII_STRING_PACK *) ExportBuffer)->Header.Length, sizeof (UINT32)); + } + + ExportBuffer = ExportBuffer + sizeof (EFI_HII_STRING_PACK); + } else { + DataTable->StringDataOffset = 0; + } + } else { + // + // No IFR? No variable information. If Offset is 0, means there is none. (Hmm - this might be prunable - no strings to export if no IFR - we always have a stub) + // + DataTable->VariableDataOffset = 0; + DataTable->IfrDataOffset = 0; + DataTable->StringDataOffset = (UINT32) (((UINTN) ExportBuffer) - ((UINTN) DataTable)); + + // + // Start dumping the String data - NOTE: It is in String Pack form + // + if (PackageInstance->StringSize > 0) { + RawData = (UINT8 *) (((UINTN) &PackageInstance->IfrData) + PackageInstance->IfrSize); + CopyMem (ExportBuffer, RawData, PackageInstance->StringSize); + DataTable->DataTableSize = (UINT32) (DataTable->StringDataOffset + PackageInstance->StringSize); + + CopyMem (&TempValue, &((EFI_HII_STRING_PACK *) ExportBuffer)->Header.Length, sizeof (UINT32)); + for (; TempValue != 0;) { + DataTable->NumberOfLanguages++; + ExportBuffer = ExportBuffer + ((EFI_HII_STRING_PACK *) ExportBuffer)->Header.Length; + CopyMem (&TempValue, &((EFI_HII_STRING_PACK *) ExportBuffer)->Header.Length, sizeof (UINT32)); + } + + ExportBuffer = ExportBuffer + sizeof (EFI_HII_STRING_PACK); + } else { + DataTable->StringDataOffset = 0; + } + } + } else { + // + // Match the numeric value with the database entry - if matched, extract PackageInstance + // + if (Handle == HandleDatabase->Handle) { + PackageInstance = HandleDatabase->Buffer; + ExportTable->NumberOfHiiDataTables = NumberOfHiiDataTables; + DataTable->HiiHandle = PackageInstance->Handle; + CopyMem (&DataTable->PackageGuid, &PackageInstance->Guid, sizeof (EFI_GUID)); + + // + // Start Dumping DevicePath + // + ExtractDevicePathData (DataTable, RawData, &ExportBuffer); + DataTable->VariableDataOffset = (UINT32) (((UINTN) ExportBuffer) - ((UINTN) DataTable)); + + if (PackageInstance->IfrSize > 0) { + FormPack = (EFI_HII_IFR_PACK *) ((CHAR8 *) (&PackageInstance->IfrData) + sizeof (EFI_HII_PACK_HEADER)); + + RawData = (UINT8 *) FormPack; + TempValue = 0; + + // + // Start dumping the Variable Data + // + ExtractVariableData (DataTable, RawData, &ExportBuffer); + DataTable->IfrDataOffset = (UINT32) (((UINTN) ExportBuffer) - ((UINTN) DataTable)); + + if (DataTable->VariableDataOffset == DataTable->IfrDataOffset) { + DataTable->VariableDataOffset = 0; + } + // + // Start dumping the IFR data + // + CopyMem (ExportBuffer, &PackageInstance->IfrData, PackageInstance->IfrSize); + ExportBuffer = (UINT8 *) (UINTN) (((UINTN) ExportBuffer) + PackageInstance->IfrSize); + DataTable->StringDataOffset = (UINT32) (((UINTN) ExportBuffer) - ((UINTN) DataTable)); + + // + // Start dumping the String data - NOTE: It is in String Pack form + // + if (PackageInstance->StringSize > 0) { + RawData = (UINT8 *) (((UINTN) &PackageInstance->IfrData) + PackageInstance->IfrSize); + CopyMem (ExportBuffer, RawData, PackageInstance->StringSize); + DataTable->DataTableSize = (UINT32) (DataTable->StringDataOffset + PackageInstance->StringSize); + + CopyMem (&TempValue, &((EFI_HII_STRING_PACK *) ExportBuffer)->Header.Length, sizeof (UINT32)); + for (; TempValue != 0;) { + DataTable->NumberOfLanguages++; + ExportBuffer = ExportBuffer + ((EFI_HII_STRING_PACK *) ExportBuffer)->Header.Length; + CopyMem (&TempValue, &((EFI_HII_STRING_PACK *) ExportBuffer)->Header.Length, sizeof (UINT32)); + } + + ExportBuffer = ExportBuffer + sizeof (EFI_HII_STRING_PACK); + } else { + DataTable->StringDataOffset = 0; + } + } else { + // + // No IFR? No variable information. If Offset is 0, means there is none. + // + DataTable->VariableDataOffset = 0; + DataTable->IfrDataOffset = 0; + DataTable->StringDataOffset = (UINT32) (((UINTN) ExportBuffer) - ((UINTN) DataTable)); + + // + // Start dumping the String data - Note: It is in String Pack form + // + if (PackageInstance->StringSize > 0) { + RawData = (UINT8 *) (((UINTN) &PackageInstance->IfrData) + PackageInstance->IfrSize); + CopyMem (ExportBuffer, RawData, PackageInstance->StringSize); + DataTable->DataTableSize = (UINT32) (DataTable->StringDataOffset + PackageInstance->StringSize); + + CopyMem (&TempValue, &((EFI_HII_STRING_PACK *) ExportBuffer)->Header.Length, sizeof (UINT32)); + for (; TempValue != 0;) { + DataTable->NumberOfLanguages++; + ExportBuffer = ExportBuffer + ((EFI_HII_STRING_PACK *) ExportBuffer)->Header.Length; + CopyMem (&TempValue, &((EFI_HII_STRING_PACK *) ExportBuffer)->Header.Length, sizeof (UINT32)); + } + + ExportBuffer = ExportBuffer + sizeof (EFI_HII_STRING_PACK); + } else { + DataTable->StringDataOffset = 0; + } + } + break; + } + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +HiiGetForms ( + IN EFI_HII_PROTOCOL *This, + IN EFI_HII_HANDLE Handle, + IN EFI_FORM_ID FormId, + IN OUT UINTN *BufferLengthTemp, + OUT UINT8 *Buffer + ) +/*++ + +Routine Description: + + This function allows a program to extract a form or form package that has + previously been registered with the EFI HII database. + +Arguments: + This - A pointer to the EFI_HII_PROTOCOL instance. + + Handle - Handle on which the form resides. Type EFI_HII_HANDLE is defined in + EFI_HII_PROTOCOL.NewPack() in the Packages section. + + FormId - The ID of the form to return. If the ID is zero, the entire form package is returned. + Type EFI_FORM_ID is defined in "Related Definitions" below. + + BufferLength - On input, the length of the Buffer. On output, the length of the returned buffer, if + the length was sufficient and, if it was not, the length that is required to fit the + requested form(s). + + Buffer - The buffer designed to receive the form(s). + +Returns: + + EFI_SUCCESS - Buffer filled with the requested forms. BufferLength + was updated. + + EFI_INVALID_PARAMETER - The handle is unknown. + + EFI_NOT_FOUND - A form on the requested handle cannot be found with the + requested FormId. + + EFI_BUFFER_TOO_SMALL - The buffer provided was not large enough to allow the form to be stored. + +--*/ +{ + EFI_HII_PACKAGE_INSTANCE *PackageInstance; + EFI_HII_DATA *HiiData; + EFI_HII_HANDLE_DATABASE *HandleDatabase; + EFI_HII_IFR_PACK *FormPack; + EFI_IFR_FORM *Form; + EFI_IFR_OP_HEADER *Location; + UINT16 *BufferLength = (UINT16 *) BufferLengthTemp; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + HiiData = EFI_HII_DATA_FROM_THIS (This); + + HandleDatabase = HiiData->DatabaseHead; + + PackageInstance = NULL; + + // + // Check numeric value against the head of the database + // + for (; HandleDatabase != NULL; HandleDatabase = HandleDatabase->NextHandleDatabase) { + // + // Match the numeric value with the database entry - if matched, extract PackageInstance + // + if (Handle == HandleDatabase->Handle) { + PackageInstance = HandleDatabase->Buffer; + break; + } + } + // + // No handle was found - error condition + // + if (PackageInstance == NULL) { + return EFI_NOT_FOUND; + } + // + // Based on if there is IFR data in this package instance, determine + // what the location is of the beginning of the string data. + // + if (PackageInstance->IfrSize > 0) { + FormPack = (EFI_HII_IFR_PACK *) (&PackageInstance->IfrData); + } else { + // + // If there is no IFR data return an error + // + return EFI_NOT_FOUND; + } + // + // If requesting the entire Form Package + // + if (FormId == 0) { + // + // Return an error if buffer is too small + // + if (PackageInstance->IfrSize > *BufferLength || Buffer == NULL) { + *BufferLength = (UINT16) PackageInstance->IfrSize; + return EFI_BUFFER_TOO_SMALL; + } + + CopyMem (Buffer, FormPack, PackageInstance->IfrSize); + return EFI_SUCCESS; + } else { + FormPack = (EFI_HII_IFR_PACK *) ((CHAR8 *) (&PackageInstance->IfrData) + sizeof (EFI_HII_PACK_HEADER)); + Location = (EFI_IFR_OP_HEADER *) FormPack; + + // + // Look for the FormId requested + // + for (; Location->OpCode != EFI_IFR_END_FORM_SET_OP;) { + switch (Location->OpCode) { + case EFI_IFR_FORM_OP: + Form = (EFI_IFR_FORM *) Location; + + // + // If we found a Form Op-code and it is of the correct Id, copy it and return + // + if (Form->FormId == FormId) { + if (Location->Length > *BufferLength || Buffer == NULL) { + *BufferLength = Location->Length; + return EFI_BUFFER_TOO_SMALL; + } else { + for (; Location->OpCode != EFI_IFR_END_FORM_OP;) { + CopyMem (Buffer, Location, Location->Length); + Buffer = Buffer + Location->Length; + Location = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (Location) + Location->Length); + } + + CopyMem (Buffer, Location, Location->Length); + return EFI_SUCCESS; + } + } + + default: + break; + } + // + // Go to the next Op-Code + // + Location = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (Location) + Location->Length); + } + } + + return EFI_SUCCESS; +} + +// +// Helper functions to HiiGetDefaultImage() +// + +STATIC +UINT8* +HiiGetDefaultImageInitPack ( + IN OUT EFI_HII_VARIABLE_PACK_LIST *VariablePackItem, + IN EFI_IFR_VARSTORE *VarStore + ) +/*++ + + Routine Description: + + Initialize the EFI_HII_VARIABLE_PACK_LIST structure and + prepare it ready to be used by HiiGetDefaultImagePopulateMap (). + + Arguments: + + VariablePackItem - Variable Package List. + VarStore - IFR variable storage. + + Returns: + + Return the pointer to the Map space. + +--*/ +{ + CHAR16 *Name16; + CHAR8 *Name8; + CHAR8 *Map; + EFI_HII_VARIABLE_PACK *VariablePack; + + // + // Set pointer the pack right after the node + // + VariablePackItem->VariablePack = (EFI_HII_VARIABLE_PACK *) (VariablePackItem + 1); + VariablePack = VariablePackItem->VariablePack; + + // + // Copy the var name to VariablePackItem from VarStore + // Needs ASCII->Unicode conversion. + // + ASSERT (VarStore->Header.Length > sizeof (*VarStore)); + Name8 = (CHAR8 *) (VarStore + 1); + Name16 = (CHAR16 *) (VariablePack + 1); + Ascii2Unicode (Name16, Name8); + + // + // Compute the other fields of the VariablePackItem + // + VariablePack->VariableId = VarStore->VarId; + CopyMem (&VariablePack->VariableGuid, &VarStore->Guid, sizeof (EFI_GUID)); + VariablePack->VariableNameLength = (UINT32) ((StrLen (Name16) + 1) * 2); + VariablePack->Header.Length = sizeof (*VariablePack) + + VariablePack->VariableNameLength + + VarStore->Size; + // + // Return the pointer to the Map space. + // + Map = (CHAR8 *) Name16 + VariablePack->VariableNameLength; + + return (UINT8 *)Map; +} + +STATIC +VOID +HiiGetDefaultImagePopulateMap ( + IN OUT UINT8 *Map, + IN EFI_IFR_OP_HEADER *FormSet, + IN EFI_IFR_VARSTORE *VarStore, + IN UINTN DefaultMask + ) +/*++ + + Routine Description: + + Fill the Map with all the default values either from NV or Hii database. + + Arguments: + + Map - Memory pointer to hold the default values. + FormSet - The starting EFI_IFR_OP_HEADER to begin retriving default values. + VarStore - IFR variable storage. + DefaultMask - The mask used to get the default variable. + + Returns: + + VOID + +--*/ +{ + EFI_STATUS Status; + EFI_IFR_OP_HEADER *IfrItem; + UINT16 VarId; + EFI_IFR_VARSTORE_SELECT *VarSelect; + EFI_IFR_ONE_OF_OPTION *OneOfOpt; + EFI_IFR_CHECKBOX *CheckBox; + EFI_IFR_NUMERIC *Numeric; + UINTN Size; + UINTN SizeTmp; + EFI_IFR_NV_DATA *IfrNvData; + EFI_GUID Guid; + CHAR16 *Name16; + CHAR8 *Name8; + EFI_HANDLE CallbackHandle; + EFI_FORM_CALLBACK_PROTOCOL *FormCallbackProt; + + // + // Get the Map's Name/Guid/Szie from the Varstore. + // VARSTORE contains the Name in ASCII format (@#$^&!), must convert it to Unicode. + // + ASSERT (VarStore->Header.Length >= sizeof (*VarStore)); + Name8 = (CHAR8 *) (VarStore + 1); + Name16 = AllocateZeroPool ((VarStore->Header.Length - sizeof (*VarStore)) * sizeof (CHAR16)); + Ascii2Unicode (Name16, Name8); + CopyMem (&Guid, &VarStore->Guid, sizeof(EFI_GUID)); + Size = VarStore->Size; + + // + // First, check if the map exists in the NV. If so, get it from NV and exit. + // + if (DefaultMask == EFI_IFR_FLAG_MANUFACTURING) { + // + // Check if Manufaturing Defaults exist in the NV. + // + Status = EfiLibHiiVariableOverrideBySuffix ( + HII_VARIABLE_SUFFIX_MANUFACTURING_OVERRIDE, + Name16, + &Guid, + Size, + Map + ); + } else { + // + // All other cases default to Defaults. Check if Defaults exist in the NV. + // + Status = EfiLibHiiVariableOverrideBySuffix ( + HII_VARIABLE_SUFFIX_DEFAULT_OVERRIDE, + Name16, + &Guid, + Size, + Map + ); + } + if (!EFI_ERROR (Status)) { + // + // Either Defaults/Manufacturing variable exists and appears to be valid. + // The map is read, exit w/ success now. + // + gBS->FreePool (Name16); + return; + } + + // + // First, prime the map with what already is in the NV. + // This is needed to cover a situation where the IFR does not contain all the + // defaults; either deliberately not having appropriate IFR, or in case of IFR_STRING, there is no default. + // Ignore status. Either it gets read or not. + // + FormCallbackProt = NULL; + CopyMem (&CallbackHandle, &((EFI_IFR_FORM_SET*) FormSet)->CallbackHandle, sizeof (CallbackHandle)); + if (CallbackHandle != NULL) { + Status = gBS->HandleProtocol ( + (EFI_HANDLE) (UINTN) CallbackHandle, + &gEfiFormCallbackProtocolGuid, + (VOID *) &FormCallbackProt + ); + } + if ((NULL != FormCallbackProt) && (NULL != FormCallbackProt->NvRead)) { + // + // Attempt to read using NvRead() callback. Probe first for existence and correct variable size. + // + SizeTmp = 0; + Status = FormCallbackProt->NvRead ( + FormCallbackProt, + Name16, + &Guid, + 0, + &SizeTmp, + NULL + ); + if ((EFI_BUFFER_TOO_SMALL == Status) && (SizeTmp == Size)) { + Status = FormCallbackProt->NvRead ( + FormCallbackProt, + Name16, + &Guid, + 0, + &SizeTmp, + Map + ); + ASSERT_EFI_ERROR (Status); + ASSERT (SizeTmp == Size); + } + } else { + // + // No callback available for this formset, read straight from NV. Deliberately ignore the Status. + // The buffer will only be written if variable exists nd has correct size. + // + Status = EfiLibHiiVariableRetrieveFromNv ( + Name16, + &Guid, + Size, + (VOID **) &Map + ); + } + + // + // Iterate all IFR statements and for applicable, retrieve the default into the Map. + // + for (IfrItem = FormSet, VarId = 0; + IfrItem->OpCode != EFI_IFR_END_FORM_SET_OP; + IfrItem = (EFI_IFR_OP_HEADER *) ((UINT8*) IfrItem + IfrItem->Length) + ) { + + // + // Observe VarStore switch. + // + if (EFI_IFR_VARSTORE_SELECT_OP == IfrItem->OpCode) { + VarSelect = (EFI_IFR_VARSTORE_SELECT *) IfrItem; + VarId = VarSelect->VarId; + continue; + } + + + // + // Skip opcodes that reference other VarStore than that specific to current map. + // + if (VarId != VarStore->VarId) { + continue; + } + + // + // Extract the default value from this opcode if applicable, and apply it to the map. + // + IfrNvData = (EFI_IFR_NV_DATA *) IfrItem; + switch (IfrItem->OpCode) { + + case EFI_IFR_ONE_OF_OP: + ASSERT (IfrNvData->QuestionId + IfrNvData->StorageWidth <= VarStore->Size); + // + // Get to the first EFI_IFR_ONE_OF_OPTION_OP + // + IfrItem = (EFI_IFR_OP_HEADER *) ((UINT8*) IfrItem + IfrItem->Length); + ASSERT (EFI_IFR_ONE_OF_OPTION_OP == IfrItem->OpCode); + + OneOfOpt = (EFI_IFR_ONE_OF_OPTION *)IfrItem; + // + // In the worst case, the first will be the default. + // + CopyMem (Map + IfrNvData->QuestionId, &OneOfOpt->Value, IfrNvData->StorageWidth); + + while (EFI_IFR_ONE_OF_OPTION_OP == IfrItem->OpCode) { + + OneOfOpt = (EFI_IFR_ONE_OF_OPTION *)IfrItem; + if (DefaultMask == EFI_IFR_FLAG_MANUFACTURING) { + if (0 != (OneOfOpt->Flags & EFI_IFR_FLAG_MANUFACTURING)) { + // + // In the worst case, the first will be the default. + // + CopyMem (Map + IfrNvData->QuestionId, &OneOfOpt->Value, IfrNvData->StorageWidth); + break; + } + } else { + if (OneOfOpt->Flags & EFI_IFR_FLAG_DEFAULT) { + // + // In the worst case, the first will be the default. + // + CopyMem (Map + IfrNvData->QuestionId, &OneOfOpt->Value, IfrNvData->StorageWidth); + break; + } + } + + IfrItem = (EFI_IFR_OP_HEADER *)((UINT8*)IfrItem + IfrItem->Length); + } + continue; + break; + + case EFI_IFR_CHECKBOX_OP: + ASSERT (IfrNvData->QuestionId + IfrNvData->StorageWidth <= VarStore->Size); + CheckBox = (EFI_IFR_CHECK_BOX *)IfrItem; + if (DefaultMask == EFI_IFR_FLAG_MANUFACTURING) { + if (0 != (CheckBox->Flags & EFI_IFR_FLAG_MANUFACTURING)) { + *(UINT8 *) (Map + IfrNvData->QuestionId) = TRUE; + } + } else { + if (CheckBox->Flags & EFI_IFR_FLAG_DEFAULT) { + *(UINT8 *) (Map + IfrNvData->QuestionId) = TRUE; + } + } + break; + + case EFI_IFR_NUMERIC_OP: + ASSERT (IfrNvData->QuestionId + IfrNvData->StorageWidth <= VarStore->Size); + Numeric = (EFI_IFR_NUMERIC *) IfrItem; + CopyMem (Map + IfrNvData->QuestionId, &Numeric->Default, IfrNvData->StorageWidth); + break; + + case EFI_IFR_ORDERED_LIST_OP: + case EFI_IFR_PASSWORD_OP: + case EFI_IFR_STRING_OP: + // + // No support for default value for these opcodes. + // + break; + } + } + + gBS->FreePool (Name16); + +} + + +EFI_STATUS +EFIAPI +HiiGetDefaultImage ( + IN EFI_HII_PROTOCOL *This, + IN EFI_HII_HANDLE Handle, + IN UINTN DefaultMask, + OUT EFI_HII_VARIABLE_PACK_LIST **VariablePackList + ) +/*++ + + Routine Description: + + This function allows a program to extract the NV Image + that represents the default storage image + + Arguments: + This - A pointer to the EFI_HII_PROTOCOL instance. + Handle - The HII handle from which will have default data retrieved. + UINTN - Mask used to retrieve the default image. + VariablePackList - Callee allocated, tightly-packed, link list data + structure that contain all default varaible packs + from the Hii Database. + + Returns: + EFI_NOT_FOUND - If Hii database does not contain any default images. + EFI_INVALID_PARAMETER - Invalid input parameter. + EFI_SUCCESS - Operation successful. + +--*/ +{ + EFI_HII_HANDLE_DATABASE *HandleDatabase; + EFI_HII_PACKAGE_INSTANCE *PackageInstance; + EFI_IFR_OP_HEADER *FormSet; + EFI_IFR_OP_HEADER *IfrItem; + EFI_IFR_VARSTORE *VarStore; + EFI_IFR_VARSTORE *VarStoreDefault; + UINTN SetupMapNameSize; + UINTN SizeOfMaps; + EFI_HII_VARIABLE_PACK_LIST *PackList; + EFI_HII_VARIABLE_PACK_LIST *PackListNext; + EFI_HII_VARIABLE_PACK_LIST *PackListLast; + UINT8 *Map; + + + // + // Find the IFR pack from the handle. Then get the formset from the pack. + // + PackageInstance = NULL; + HandleDatabase = (EFI_HII_DATA_FROM_THIS (This))->DatabaseHead; + for ( ; HandleDatabase != NULL; HandleDatabase = HandleDatabase->NextHandleDatabase) { + if (Handle == HandleDatabase->Handle) { + PackageInstance = HandleDatabase->Buffer; + break; + } + } + if (PackageInstance == NULL) { + return EFI_INVALID_PARAMETER; + } + FormSet = (EFI_IFR_OP_HEADER *) ((UINT8 *) &PackageInstance->IfrData + sizeof (EFI_HII_IFR_PACK)); + + // + // Get the sizes of all the VARSTOREs in this VFR. + // Then allocate enough space for all of them plus all maps + // + SizeOfMaps = 0; + IfrItem = FormSet; + while (EFI_IFR_END_FORM_SET_OP != IfrItem->OpCode) { + + if (EFI_IFR_VARSTORE_OP == IfrItem->OpCode) { + VarStore = (EFI_IFR_VARSTORE *) IfrItem; + // + // Size of the map + // + SizeOfMaps += VarStore->Size; + // + // add the size of the string, in Unicode + // + SizeOfMaps += (VarStore->Header.Length - sizeof (*VarStore)) * 2; + // + // Space for node + // + SizeOfMaps += sizeof (EFI_HII_VARIABLE_PACK); + // + // Space for linked list node + // + SizeOfMaps += sizeof (EFI_HII_VARIABLE_PACK_LIST); + } + + IfrItem = (EFI_IFR_OP_HEADER *) ((UINT8 *) IfrItem + IfrItem->Length); + } + + // + // If the FormSet OpCode has a non-zero NvDataSize. There is a default + // NvMap with ID=0, GUID that of the formset itself and "Setup" as name. + // + SetupMapNameSize = StrLen (SETUP_MAP_NAME) + 1; + VarStoreDefault = AllocateZeroPool (sizeof (*VarStoreDefault) + SetupMapNameSize); + + if (0 != ((EFI_IFR_FORM_SET*)FormSet)->NvDataSize) { + + VarStoreDefault->Header.OpCode = EFI_IFR_VARSTORE_OP; + VarStoreDefault->Header.Length = (UINT8) (sizeof (*VarStoreDefault) + SetupMapNameSize); + Unicode2Ascii ((CHAR8 *) (VarStoreDefault + 1), SETUP_MAP_NAME); + CopyMem (&VarStoreDefault->Guid, &((EFI_IFR_FORM_SET*) FormSet)->Guid, sizeof (EFI_GUID)); + VarStoreDefault->VarId = 0; + VarStoreDefault->Size = ((EFI_IFR_FORM_SET*) FormSet)->NvDataSize; + + // + // Size of the map + // + SizeOfMaps += VarStoreDefault->Size; + // + // add the size of the string + // + SizeOfMaps += sizeof (SETUP_MAP_NAME); + // + // Space for node + // + SizeOfMaps += sizeof (EFI_HII_VARIABLE_PACK); + // + // Space for linked list node + // + SizeOfMaps += sizeof (EFI_HII_VARIABLE_PACK_LIST); + } + + if (0 == SizeOfMaps) { + // + // The IFR does not have any explicit or default map(s). + // + return EFI_NOT_FOUND; + } + + // + // Allocate the return buffer + // + PackList = AllocateZeroPool (SizeOfMaps); + ASSERT (NULL != PackList); + + PackListNext = PackList; + PackListLast = PackList; + + // + // Handle the default map first, if any. + // + if (0 != VarStoreDefault->Size) { + + Map = HiiGetDefaultImageInitPack (PackListNext, VarStoreDefault); + + HiiGetDefaultImagePopulateMap (Map, FormSet, VarStoreDefault, DefaultMask); + + PackListNext->NextVariablePack = (EFI_HII_VARIABLE_PACK_LIST *) ((UINT8 *) PackListNext->VariablePack + PackListNext->VariablePack->Header.Length); + PackListLast = PackListNext; + PackListNext = PackListNext->NextVariablePack; + } + + + // + // Handle the explicit varstore(s) + // + IfrItem = FormSet; + while (EFI_IFR_END_FORM_SET_OP != IfrItem->OpCode) { + + if (EFI_IFR_VARSTORE_OP == IfrItem->OpCode) { + + Map = HiiGetDefaultImageInitPack (PackListNext, (EFI_IFR_VARSTORE *) IfrItem); + + HiiGetDefaultImagePopulateMap (Map, FormSet, (EFI_IFR_VARSTORE *) IfrItem, DefaultMask); + + PackListNext->NextVariablePack = (EFI_HII_VARIABLE_PACK_LIST *) ((UINT8 *) PackListNext->VariablePack + PackListNext->VariablePack->Header.Length); + PackListLast = PackListNext; + PackListNext = PackListNext->NextVariablePack; + } + + IfrItem = (EFI_IFR_OP_HEADER *) ((UINT8 *) IfrItem + IfrItem->Length); + } + + PackListLast->NextVariablePack = NULL; + *VariablePackList = PackList; + + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +HiiUpdateForm ( + IN EFI_HII_PROTOCOL *This, + IN EFI_HII_HANDLE Handle, + IN EFI_FORM_LABEL Label, + IN BOOLEAN AddData, + IN EFI_HII_UPDATE_DATA *Data + ) +/*++ + +Routine Description: + This function allows the caller to update a form that has + previously been registered with the EFI HII database. + +Arguments: + Handle - Hii Handle associated with the Formset to modify + Label - Update information starting immediately after this label in the IFR + AddData - If TRUE, add data. If FALSE, remove data + Data - If adding data, this is the pointer to the data to add + +Returns: + EFI_SUCCESS - Update success. + Other - Update fail. + +--*/ +{ + EFI_HII_PACKAGE_INSTANCE *PackageInstance; + EFI_HII_DATA *HiiData; + EFI_HII_HANDLE_DATABASE *HandleDatabase; + EFI_HII_IFR_PACK *FormPack; + EFI_IFR_OP_HEADER *Location; + EFI_IFR_OP_HEADER *DataLocation; + UINT8 *OtherBuffer; + UINT8 *TempBuffer; + UINT8 *OrigTempBuffer; + UINTN TempBufferSize; + UINTN Index; + + OtherBuffer = NULL; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + HiiData = EFI_HII_DATA_FROM_THIS (This); + + HandleDatabase = HiiData->DatabaseHead; + + PackageInstance = NULL; + + // + // Check numeric value against the head of the database + // + for (; HandleDatabase != NULL; HandleDatabase = HandleDatabase->NextHandleDatabase) { + // + // Match the numeric value with the database entry - if matched, extract PackageInstance + // + if (Handle == HandleDatabase->Handle) { + PackageInstance = HandleDatabase->Buffer; + break; + } + } + // + // No handle was found - error condition + // + if (PackageInstance == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Calculate and allocate space for retrieval of IFR data + // + DataLocation = (EFI_IFR_OP_HEADER *) &Data->Data; + TempBufferSize = (CHAR8 *) (&PackageInstance->IfrData) - (CHAR8 *) (PackageInstance); + + for (Index = 0; Index < Data->DataCount; Index++) { + TempBufferSize += DataLocation->Length; + DataLocation = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (DataLocation) + DataLocation->Length); + } + + TempBufferSize += PackageInstance->IfrSize + PackageInstance->StringSize; + + TempBuffer = AllocateZeroPool (TempBufferSize); + OrigTempBuffer = TempBuffer; + + // + // We update only packages with IFR information in it + // + if (PackageInstance->IfrSize == 0) { + return EFI_INVALID_PARAMETER; + } + + CopyMem ( + TempBuffer, + PackageInstance, + ((CHAR8 *) (&PackageInstance->IfrData) + sizeof (EFI_HII_PACK_HEADER) - (CHAR8 *) (PackageInstance)) + ); + + TempBuffer = TempBuffer + ((CHAR8 *) (&PackageInstance->IfrData) + sizeof (EFI_HII_PACK_HEADER) - (CHAR8 *) (PackageInstance)); + + // + // Based on if there is IFR data in this package instance, determine + // what the location is of the beginning of the string data. + // + FormPack = (EFI_HII_IFR_PACK *) ((CHAR8 *) (&PackageInstance->IfrData) + sizeof (EFI_HII_PACK_HEADER)); + Location = (EFI_IFR_OP_HEADER *) FormPack; + + // + // Look for the FormId requested + // + for (; Location->OpCode != EFI_IFR_END_FORM_SET_OP;) { + switch (Location->OpCode) { + case EFI_IFR_FORM_SET_OP: + // + // If the FormSet has an update pending, pay attention. + // + if (Data->FormSetUpdate) { + ((EFI_IFR_FORM_SET *) Location)->CallbackHandle = Data->FormCallbackHandle; + } + + CopyMem (TempBuffer, Location, Location->Length); + TempBuffer = TempBuffer + Location->Length; + break; + + case EFI_IFR_FORM_OP: + // + // If the Form has an update pending, pay attention. + // + if (Data->FormUpdate) { + ((EFI_IFR_FORM *) Location)->FormTitle = Data->FormTitle; + } + + CopyMem (TempBuffer, Location, Location->Length); + TempBuffer = TempBuffer + Location->Length; + break; + + case EFI_IFR_LABEL_OP: + // + // If the label does not match the requested update point, ignore it + // + if (((EFI_IFR_LABEL *) Location)->LabelId != Label) { + // + // Copy the label + // + CopyMem (TempBuffer, Location, Location->Length); + TempBuffer = TempBuffer + Location->Length; + + // + // Go to the next Op-Code + // + Location = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (Location) + Location->Length); + continue; + } + + if (AddData) { + // + // Copy the label + // + CopyMem (TempBuffer, Location, Location->Length); + TempBuffer = TempBuffer + Location->Length; + + // + // Add the DataCount amount of opcodes to TempBuffer + // + DataLocation = (EFI_IFR_OP_HEADER *) &Data->Data; + for (Index = 0; Index < Data->DataCount; Index++) { + CopyMem (TempBuffer, DataLocation, DataLocation->Length); + ((EFI_HII_PACKAGE_INSTANCE *) OrigTempBuffer)->IfrSize += DataLocation->Length; + OtherBuffer = ((UINT8 *) &((EFI_HII_PACKAGE_INSTANCE *) OrigTempBuffer)->StringSize + sizeof (UINTN)); + CopyMem (OtherBuffer, &((EFI_HII_PACKAGE_INSTANCE *) OrigTempBuffer)->IfrSize, 2); + TempBuffer = TempBuffer + DataLocation->Length; + DataLocation = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (DataLocation) + DataLocation->Length); + } + // + // Go to the next Op-Code + // + Location = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (Location) + Location->Length); + continue; + } else { + // + // Copy the label + // + CopyMem (TempBuffer, Location, Location->Length); + TempBuffer = TempBuffer + Location->Length; + Location = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (Location) + Location->Length); + + // + // Remove the DataCount amount of opcodes unless we run into an end of form or a label + // + for (Index = 0; Index < Data->DataCount; Index++) { + // + // If we are about to skip an end form - bail out, since that is illegal + // + if ((Location->OpCode == EFI_IFR_END_FORM_OP) || (Location->OpCode == EFI_IFR_LABEL_OP)) { + break; + } + // + // By skipping Location entries, we are in effect not copying what was previously there + // + ((EFI_HII_PACKAGE_INSTANCE *) OrigTempBuffer)->IfrSize -= Location->Length; + OtherBuffer = ((UINT8 *) &((EFI_HII_PACKAGE_INSTANCE *) OrigTempBuffer)->StringSize + sizeof (UINTN)); + CopyMem (OtherBuffer, &((EFI_HII_PACKAGE_INSTANCE *) OrigTempBuffer)->IfrSize, 2); + Location = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (Location) + Location->Length); + } + } + + default: + CopyMem (TempBuffer, Location, Location->Length); + TempBuffer = TempBuffer + Location->Length; + break; + } + // + // Go to the next Op-Code + // + Location = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (Location) + Location->Length); + } + // + // Copy the last op-code left behind from the for loop + // + CopyMem (TempBuffer, Location, Location->Length); + + // + // Advance to beginning of strings and copy them + // + TempBuffer = TempBuffer + Location->Length; + Location = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (Location) + Location->Length); + CopyMem (TempBuffer, Location, PackageInstance->StringSize); + + // + // Free the old buffer, and assign into our database the latest buffer + // + gBS->FreePool (HandleDatabase->Buffer); + HandleDatabase->Buffer = OrigTempBuffer; + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/HiiDatabase.c b/EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/HiiDatabase.c new file mode 100644 index 0000000000..ce34eff5bd --- /dev/null +++ b/EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/HiiDatabase.c @@ -0,0 +1,413 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + HiiDatabase.c + +Abstract: + + This file contains the entry code to the HII database. + +--*/ + +#include "HiiDatabase.h" + +EFI_STATUS +EFIAPI +InitializeHiiDatabase ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + Initialize HII Database + +Arguments: + (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT) + +Returns: + EFI_SUCCESS - Setup loaded. + other - Setup Error + +--*/ +{ + EFI_STATUS Status; + EFI_HII_DATA *HiiData; + EFI_HII_GLOBAL_DATA *GlobalData; + EFI_HANDLE *HandleBuffer; + EFI_HANDLE Handle; + UINTN HandleCount; + UINTN Index; + + // + // 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. + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiHiiProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + + // + // If there was no error, assume there is an installation and fail to load + // + if (!EFI_ERROR (Status)) { + if (HandleBuffer != NULL) { + gBS->FreePool (HandleBuffer); + } + + return EFI_DEVICE_ERROR; + } + + HiiData = AllocatePool (sizeof (EFI_HII_DATA)); + + ASSERT (HiiData); + + GlobalData = AllocateZeroPool (sizeof (EFI_HII_GLOBAL_DATA)); + + ASSERT (GlobalData); + + // + // Seed the Font Database with a known non-character glyph + // + for (Index = 0; Index <= MAX_GLYPH_COUNT; Index++) { + // + // Seeding the UnicodeWeight with 0 signifies that it is uninitialized + // + GlobalData->NarrowGlyphs[Index].UnicodeWeight = 0; + GlobalData->WideGlyphs[Index].UnicodeWeight = 0; + GlobalData->NarrowGlyphs[Index].Attributes = 0; + GlobalData->WideGlyphs[Index].Attributes = 0; + CopyMem (GlobalData->NarrowGlyphs[Index].GlyphCol1, &mUnknownGlyph, NARROW_GLYPH_ARRAY_SIZE); + CopyMem (GlobalData->WideGlyphs[Index].GlyphCol1, &mUnknownGlyph, WIDE_GLYPH_ARRAY_SIZE); + } + // + // Fill in HII data + // + HiiData->Signature = EFI_HII_DATA_SIGNATURE; + HiiData->GlobalData = GlobalData; + HiiData->GlobalData->SystemKeyboardUpdate = FALSE; + HiiData->DatabaseHead = NULL; + HiiData->Hii.NewPack = HiiNewPack; + HiiData->Hii.RemovePack = HiiRemovePack; + HiiData->Hii.FindHandles = HiiFindHandles; + HiiData->Hii.ExportDatabase = HiiExportDatabase; + HiiData->Hii.GetGlyph = HiiGetGlyph; + HiiData->Hii.GetPrimaryLanguages = HiiGetPrimaryLanguages; + HiiData->Hii.GetSecondaryLanguages = HiiGetSecondaryLanguages; + HiiData->Hii.NewString = HiiNewString; + HiiData->Hii.GetString = HiiGetString; + HiiData->Hii.ResetStrings = HiiResetStrings; + HiiData->Hii.TestString = HiiTestString; + HiiData->Hii.GetLine = HiiGetLine; + HiiData->Hii.GetForms = HiiGetForms; + HiiData->Hii.GetDefaultImage = HiiGetDefaultImage; + HiiData->Hii.UpdateForm = HiiUpdateForm; + HiiData->Hii.GetKeyboardLayout = HiiGetKeyboardLayout; + HiiData->Hii.GlyphToBlt = HiiGlyphToBlt; + + // + // Install protocol interface + // + Handle = NULL; + Status = gBS->InstallProtocolInterface ( + &Handle, + &gEfiHiiProtocolGuid, + EFI_NATIVE_INTERFACE, + &HiiData->Hii + ); + + ASSERT_EFI_ERROR (Status); + + return Status; +} + +EFI_STATUS +EFIAPI +HiiFindHandles ( + IN EFI_HII_PROTOCOL *This, + IN OUT UINT16 *HandleBufferLength, + OUT EFI_HII_HANDLE Handle[1] + ) +/*++ + +Routine Description: + Determines the handles that are currently active in the database. + +Arguments: + +Returns: + +--*/ +{ + EFI_HII_GLOBAL_DATA *GlobalData; + EFI_HII_HANDLE_DATABASE *Database; + EFI_HII_DATA *HiiData; + UINTN HandleCount; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + HiiData = EFI_HII_DATA_FROM_THIS (This); + + GlobalData = HiiData->GlobalData; + + Database = HiiData->DatabaseHead; + + if (Database == NULL) { + *HandleBufferLength = 0; + return EFI_NOT_FOUND; + } + + for (HandleCount = 0; Database != NULL; HandleCount++) { + Database = Database->NextHandleDatabase; + } + // + // Is there a sufficient buffer for the data being passed back? + // + if (*HandleBufferLength >= (sizeof (EFI_HII_HANDLE) * HandleCount)) { + Database = HiiData->DatabaseHead; + + // + // Copy the Head information + // + if (Database->Handle != 0) { + CopyMem (&Handle[0], &Database->Handle, sizeof (EFI_HII_HANDLE)); + Database = Database->NextHandleDatabase; + } + // + // Copy more data if appropriate + // + for (HandleCount = 1; Database != NULL; HandleCount++) { + CopyMem (&Handle[HandleCount], &Database->Handle, sizeof (EFI_HII_HANDLE)); + Database = Database->NextHandleDatabase; + } + + *HandleBufferLength = (UINT16) (sizeof (EFI_HII_HANDLE) * HandleCount); + return EFI_SUCCESS; + } else { + // + // Insufficient buffer length + // + *HandleBufferLength = (UINT16) (sizeof (EFI_HII_HANDLE) * HandleCount); + return EFI_BUFFER_TOO_SMALL; + } +} + +EFI_STATUS +EFIAPI +HiiGetPrimaryLanguages ( + IN EFI_HII_PROTOCOL *This, + IN EFI_HII_HANDLE Handle, + OUT EFI_STRING *LanguageString + ) +/*++ + +Routine Description: + + This function allows a program to determine what the primary languages that are supported on a given handle. + +Arguments: + +Returns: + +--*/ +{ + UINTN Count; + EFI_HII_PACKAGE_INSTANCE *PackageInstance; + EFI_HII_PACKAGE_INSTANCE *StringPackageInstance; + EFI_HII_DATA *HiiData; + EFI_HII_HANDLE_DATABASE *HandleDatabase; + EFI_HII_STRING_PACK *StringPack; + EFI_HII_STRING_PACK *Location; + UINT32 Length; + RELOFST Token; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + HiiData = EFI_HII_DATA_FROM_THIS (This); + + PackageInstance = NULL; + // + // Find matching handle in the handle database. Then get the package instance. + // + for (HandleDatabase = HiiData->DatabaseHead; + HandleDatabase != NULL; + HandleDatabase = HandleDatabase->NextHandleDatabase + ) { + if (Handle == HandleDatabase->Handle) { + PackageInstance = HandleDatabase->Buffer; + } + } + // + // No handle was found - error condition + // + if (PackageInstance == NULL) { + return EFI_INVALID_PARAMETER; + } + + ValidatePack (This, PackageInstance, &StringPackageInstance, NULL); + + // + // Based on if there is IFR data in this package instance, determine + // what the location is of the beginning of the string data. + // + if (StringPackageInstance->IfrSize > 0) { + StringPack = (EFI_HII_STRING_PACK *) ((CHAR8 *) (&StringPackageInstance->IfrData) + StringPackageInstance->IfrSize); + } else { + StringPack = (EFI_HII_STRING_PACK *) (&StringPackageInstance->IfrData); + } + + Location = StringPack; + // + // Remember that the string packages are formed into contiguous blocks of language data. + // + CopyMem (&Length, &StringPack->Header.Length, sizeof (UINT32)); + for (Count = 0; Length != 0; Count = Count + 3) { + StringPack = (EFI_HII_STRING_PACK *) ((CHAR8 *) (StringPack) + Length); + CopyMem (&Length, &StringPack->Header.Length, sizeof (UINT32)); + } + + *LanguageString = AllocateZeroPool (2 * (Count + 1)); + + ASSERT (*LanguageString); + + StringPack = (EFI_HII_STRING_PACK *) Location; + + // + // Copy the 6 bytes to LanguageString - keep concatenating it. Shouldn't we just store uint8's since the ISO + // standard defines the lettering as all US English characters anyway? Save a few bytes. + // + CopyMem (&Length, &StringPack->Header.Length, sizeof (UINT32)); + for (Count = 0; Length != 0; Count = Count + 3) { + CopyMem (&Token, &StringPack->LanguageNameString, sizeof (RELOFST)); + CopyMem (*LanguageString + Count, (VOID *) ((CHAR8 *) (StringPack) + Token), 6); + StringPack = (EFI_HII_STRING_PACK *) ((CHAR8 *) (StringPack) + Length); + CopyMem (&Length, &StringPack->Header.Length, sizeof (UINT32)); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +HiiGetSecondaryLanguages ( + IN EFI_HII_PROTOCOL *This, + IN EFI_HII_HANDLE Handle, + IN CHAR16 *PrimaryLanguage, + OUT EFI_STRING *LanguageString + ) +/*++ + +Routine Description: + + This function allows a program to determine which secondary languages are supported + on a given handle for a given primary language. + + Arguments: + +Returns: + +--*/ +{ + UINTN Count; + EFI_HII_PACKAGE_INSTANCE *PackageInstance; + EFI_HII_PACKAGE_INSTANCE *StringPackageInstance; + EFI_HII_DATA *HiiData; + EFI_HII_HANDLE_DATABASE *HandleDatabase; + EFI_HII_STRING_PACK *StringPack; + EFI_HII_STRING_PACK *Location; + RELOFST Token; + UINT32 Length; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + HiiData = EFI_HII_DATA_FROM_THIS (This); + // + // Check numeric value against the head of the database + // + PackageInstance = NULL; + for (HandleDatabase = HiiData->DatabaseHead; + HandleDatabase != NULL; + HandleDatabase = HandleDatabase->NextHandleDatabase + ) { + // + // Match the numeric value with the database entry - if matched, extract PackageInstance + // + if (Handle == HandleDatabase->Handle) { + PackageInstance = HandleDatabase->Buffer; + } + } + // + // No handle was found - error condition + // + if (PackageInstance == NULL) { + return EFI_INVALID_PARAMETER; + } + + ValidatePack (This, PackageInstance, &StringPackageInstance, NULL); + + // + // Based on if there is IFR data in this package instance, determine + // what the location is of the beginning of the string data. + // + if (StringPackageInstance->IfrSize > 0) { + StringPack = (EFI_HII_STRING_PACK *) ((CHAR8 *) (&StringPackageInstance->IfrData) + StringPackageInstance->IfrSize); + } else { + StringPack = (EFI_HII_STRING_PACK *) (&StringPackageInstance->IfrData); + } + + Location = StringPack; + + // + // Remember that the string packages are formed into contiguous blocks of language data. + // + for (; StringPack->Header.Length != 0;) { + // + // Find the PrimaryLanguage being requested + // + Token = StringPack->LanguageNameString; + if (CompareMem ((VOID *) ((CHAR8 *) (StringPack) + Token), PrimaryLanguage, 3) == 0) { + // + // Now that we found the primary, the secondary languages will follow immediately + // or the next character is a NULL if there are no secondary languages. We determine + // the number by getting the stringsize based on the StringPack origination + the LanguageNameString + // offset + 6 (which is the size of the first 3 letter ISO primary language name). If we get 2, there + // are no secondary languages (2 = null-terminator). + // + Count = StrSize ((VOID *) ((CHAR8 *) (StringPack) + Token + 6)); + + *LanguageString = AllocateZeroPool (2 * (Count + 1)); + + ASSERT (*LanguageString); + + CopyMem (*LanguageString, (VOID *) ((CHAR8 *) (StringPack) + Token + 6), Count); + break; + } + + CopyMem (&Length, &StringPack->Header.Length, sizeof (UINT32)); + StringPack = (EFI_HII_STRING_PACK *) ((CHAR8 *) (StringPack) + Length); + } + + return EFI_SUCCESS; +} + diff --git a/EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/HiiDatabase.dxs b/EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/HiiDatabase.dxs new file mode 100644 index 0000000000..86c8ac4ce2 --- /dev/null +++ b/EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/HiiDatabase.dxs @@ -0,0 +1,26 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + HiiDatabase.dxs + +Abstract: + + Dependency expression source file. + +--*/ +#include +#include + +DEPENDENCY_START + TRUE +DEPENDENCY_END \ No newline at end of file diff --git a/EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/HiiDatabase.h b/EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/HiiDatabase.h new file mode 100644 index 0000000000..c50cd958a0 --- /dev/null +++ b/EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/HiiDatabase.h @@ -0,0 +1,302 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + HiiDatabase.h + +Abstract: + + This file contains global defines and prototype definitions + for the HII database. + +--*/ + +#ifndef _HIIDATABASE_H +#define _HIIDATABASE_H + +// +// HII Database Global data +// +#define EFI_HII_DATA_SIGNATURE EFI_SIGNATURE_32 ('H', 'i', 'i', 'P') + +#define MAX_GLYPH_COUNT 65535 +#define NARROW_GLYPH_ARRAY_SIZE 19 +#define WIDE_GLYPH_ARRAY_SIZE 38 + +#define SETUP_MAP_NAME L"Setup" +#define HII_VARIABLE_SUFFIX_USER_DATA L"UserSavedData" +#define HII_VARIABLE_SUFFIX_DEFAULT_OVERRIDE L"DefaultOverride" +#define HII_VARIABLE_SUFFIX_MANUFACTURING_OVERRIDE L"ManufacturingOverride" + +typedef struct _EFI_HII_HANDLE_DATABASE { + VOID *Buffer; // Actual buffer pointer + EFI_HII_HANDLE Handle; // Monotonically increasing value to signify the value returned to caller + UINT32 NumberOfTokens; // The initial number of tokens when first registered + struct _EFI_HII_HANDLE_DATABASE *NextHandleDatabase; +} EFI_HII_HANDLE_DATABASE; + +typedef struct { + EFI_NARROW_GLYPH NarrowGlyphs[MAX_GLYPH_COUNT]; + EFI_WIDE_GLYPH WideGlyphs[MAX_GLYPH_COUNT]; + EFI_KEY_DESCRIPTOR SystemKeyboardLayout[106]; + EFI_KEY_DESCRIPTOR OverrideKeyboardLayout[106]; + BOOLEAN SystemKeyboardUpdate; // Has the SystemKeyboard been updated? +} EFI_HII_GLOBAL_DATA; + +typedef struct { + UINTN Signature; + + EFI_HII_GLOBAL_DATA *GlobalData; + EFI_HII_HANDLE_DATABASE *DatabaseHead; // Head of the Null-terminated singly-linked list of handles. + EFI_HII_PROTOCOL Hii; +} EFI_HII_DATA; + +typedef struct { + EFI_HII_HANDLE Handle; + EFI_GUID Guid; + EFI_HII_HANDLE_PACK HandlePack; + UINTN IfrSize; + UINTN StringSize; + EFI_HII_IFR_PACK *IfrData; // All the IFR data stored here + EFI_HII_STRING_PACK *StringData; // All the String data stored at &IfrData + IfrSize (StringData is just a label - never referenced) +} EFI_HII_PACKAGE_INSTANCE; + +typedef struct { + EFI_HII_PACK_HEADER Header; + EFI_IFR_FORM_SET FormSet; + EFI_IFR_END_FORM_SET EndFormSet; +} EFI_FORM_SET_STUB; + +#define EFI_HII_DATA_FROM_THIS(a) CR (a, EFI_HII_DATA, Hii, EFI_HII_DATA_SIGNATURE) + +#define NARROW_WIDTH 8 +#define WIDE_WIDTH 16 + +extern UINT8 mUnknownGlyph[38]; + +// +// Prototypes +// +EFI_STATUS +GetPackSize ( + IN VOID *Pack, + OUT UINTN *PackSize, + OUT UINT32 *NumberOfTokens + ) +; + +EFI_STATUS +ValidatePack ( + IN EFI_HII_PROTOCOL *This, + IN EFI_HII_PACKAGE_INSTANCE *PackageInstance, + OUT EFI_HII_PACKAGE_INSTANCE **StringPackageInstance, + OUT UINT32 *TotalStringCount + ) +; + +// +// Public Interface Prototypes +// +EFI_STATUS +EFIAPI +InitializeHiiDatabase ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +; + +EFI_STATUS +EFIAPI +HiiNewPack ( + IN EFI_HII_PROTOCOL *This, + IN EFI_HII_PACKAGES *PackageList, + OUT EFI_HII_HANDLE *Handle + ) +; + +EFI_STATUS +EFIAPI +HiiRemovePack ( + IN EFI_HII_PROTOCOL *This, + IN EFI_HII_HANDLE Handle + ) +; + +EFI_STATUS +EFIAPI +HiiFindHandles ( + IN EFI_HII_PROTOCOL *This, + IN OUT UINT16 *HandleBufferLength, + OUT EFI_HII_HANDLE *Handle + ) +; + +EFI_STATUS +EFIAPI +HiiExportDatabase ( + IN EFI_HII_PROTOCOL *This, + IN EFI_HII_HANDLE Handle, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +; + +EFI_STATUS +EFIAPI +HiiGetGlyph ( + IN EFI_HII_PROTOCOL *This, + IN CHAR16 *Source, + IN OUT UINT16 *Index, + OUT UINT8 **GlyphBuffer, + OUT UINT16 *BitWidth, + IN OUT UINT32 *InternalStatus + ) +; + +EFI_STATUS +EFIAPI +HiiGlyphToBlt ( + IN EFI_HII_PROTOCOL *This, + IN UINT8 *GlyphBuffer, + IN EFI_UGA_PIXEL Foreground, + IN EFI_UGA_PIXEL Background, + IN UINTN Count, + IN UINTN Width, + IN UINTN Height, + IN OUT EFI_UGA_PIXEL *BltBuffer + ) +; + +EFI_STATUS +EFIAPI +HiiNewString ( + IN EFI_HII_PROTOCOL *This, + IN CHAR16 *Language, + IN EFI_HII_HANDLE Handle, + IN OUT STRING_REF *Reference, + IN CHAR16 *NewString + ) +; + +EFI_STATUS +EFIAPI +HiiGetString ( + IN EFI_HII_PROTOCOL *This, + IN EFI_HII_HANDLE Handle, + IN STRING_REF Token, + IN BOOLEAN Raw, + IN CHAR16 *LanguageString, + IN OUT UINTN *BufferLength, + OUT EFI_STRING StringBuffer + ) +; + +EFI_STATUS +EFIAPI +HiiResetStrings ( + IN EFI_HII_PROTOCOL *This, + IN EFI_HII_HANDLE Handle + ) +; + +EFI_STATUS +EFIAPI +HiiTestString ( + IN EFI_HII_PROTOCOL *This, + IN CHAR16 *StringToTest, + IN OUT UINT32 *FirstMissing, + OUT UINT32 *GlyphBufferSize + ) +; + +EFI_STATUS +EFIAPI +HiiGetPrimaryLanguages ( + IN EFI_HII_PROTOCOL *This, + IN EFI_HII_HANDLE Handle, + OUT EFI_STRING *LanguageString + ) +; + +EFI_STATUS +EFIAPI +HiiGetSecondaryLanguages ( + IN EFI_HII_PROTOCOL *This, + IN EFI_HII_HANDLE Handle, + IN CHAR16 *PrimaryLanguage, + OUT EFI_STRING *LanguageString + ) +; + +EFI_STATUS +EFIAPI +HiiGetLine ( + IN EFI_HII_PROTOCOL *This, + IN EFI_HII_HANDLE Handle, + IN STRING_REF Token, + IN OUT UINT16 *Index, + IN UINT16 LineWidth, + IN CHAR16 *LanguageString, + IN OUT UINT16 *BufferLength, + OUT EFI_STRING StringBuffer + ) +; + +EFI_STATUS +EFIAPI +HiiGetForms ( + IN EFI_HII_PROTOCOL *This, + IN EFI_HII_HANDLE Handle, + IN EFI_FORM_ID FormId, + IN OUT UINTN *BufferLength, + OUT UINT8 *Buffer + ) +; + +EFI_STATUS +EFIAPI +HiiGetDefaultImage ( + IN EFI_HII_PROTOCOL *This, + IN EFI_HII_HANDLE Handle, + IN UINTN DefaultMask, + OUT EFI_HII_VARIABLE_PACK_LIST **VariablePackList + ) +; + +EFI_STATUS +EFIAPI +HiiUpdateForm ( + IN EFI_HII_PROTOCOL *This, + IN EFI_HII_HANDLE Handle, + IN EFI_FORM_LABEL Label, + IN BOOLEAN AddData, + IN EFI_HII_UPDATE_DATA *Data + ) +; + +EFI_STATUS +EFIAPI +HiiGetKeyboardLayout ( + IN EFI_HII_PROTOCOL *This, + OUT UINT16 *DescriptorCount, + OUT EFI_KEY_DESCRIPTOR *Descriptor + ) +; + +EFI_STATUS +HiiCompareLanguage ( + IN CHAR16 *LanguageStringLocation, + IN CHAR16 *Language + ) +; + +#endif diff --git a/EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/HiiDatabase.mbd b/EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/HiiDatabase.mbd new file mode 100644 index 0000000000..03f2ed9463 --- /dev/null +++ b/EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/HiiDatabase.mbd @@ -0,0 +1,44 @@ + + + + + HiiDatabase + FCD337AB-B1D3-4EF8-957C-8048606FF670 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + BaseLib + BaseMemoryLib + BaseDebugLibReportStatusCode + UefiDriverEntryPoint + DxeMemoryAllocationLib + DxeReportStatusCodeLib + EdkIfrSupportLib + + + _ModuleEntryPoint + + diff --git a/EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/HiiDatabase.msa b/EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/HiiDatabase.msa new file mode 100644 index 0000000000..3eb5332c81 --- /dev/null +++ b/EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/HiiDatabase.msa @@ -0,0 +1,80 @@ + + + + + HiiDatabase + DXE_DRIVER + BS_DRIVER + FCD337AB-B1D3-4EF8-957C-8048606FF670 + 0 + Component description file for DiskIo module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + BaseLib + DebugLib + UefiDriverEntryPoint + MemoryAllocationLib + BaseMemoryLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + EdkIfrSupportLib + + + HiiDatabase.c + HiiDatabase.h + Forms.c + Strings.c + Package.c + Fonts.c + Keyboard.c + HiiDatabase.dxs + + + MdePkg + EdkModulePkg + + + Hii + FormCallback + + + + L"Lang" + + 0x8BE4DF61, 0x93CA, 0x11d2, {0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C } + + + + + + GlobalVariable + + + + + InitializeHiiDatabase + + + diff --git a/EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/Keyboard.c b/EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/Keyboard.c new file mode 100644 index 0000000000..8e9417fc83 --- /dev/null +++ b/EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/Keyboard.c @@ -0,0 +1,43 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Keyboard.c + +Abstract: + + This file contains the keyboard processing code to the HII database. + +--*/ + + +#include "HiiDatabase.h" + +EFI_STATUS +EFIAPI +HiiGetKeyboardLayout ( + IN EFI_HII_PROTOCOL *This, + OUT UINT16 *DescriptorCount, + OUT EFI_KEY_DESCRIPTOR *Descriptor + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/Package.c b/EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/Package.c new file mode 100644 index 0000000000..3e9e5364e9 --- /dev/null +++ b/EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/Package.c @@ -0,0 +1,677 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Package.c + +Abstract: + + This file contains the package processing code to the HII database. + +--*/ + + +#include "HiiDatabase.h" + +EFI_STATUS +GetPackSize ( + IN VOID *Pack, + OUT UINTN *PackSize, + OUT UINT32 *NumberOfTokens + ) +/*++ + +Routine Description: + Determines the passed in Pack's size and returns the value. + +Arguments: + +Returns: + +--*/ +{ + EFI_HII_STRING_PACK *StringPack; + UINT16 Type; + UINT32 Length; + + *PackSize = 0; + + Type = EFI_HII_IFR; + if (!CompareMem (&((EFI_HII_PACK_HEADER *) Pack)->Type, &Type, sizeof (UINT16))) { + // + // The header contains the full IFR length + // + CopyMem (&Length, &((EFI_HII_PACK_HEADER *) Pack)->Length, sizeof (Length)); + *PackSize = (UINTN) Length; + return EFI_SUCCESS; + } + + Type = EFI_HII_STRING; + if (!CompareMem (&((EFI_HII_PACK_HEADER *) Pack)->Type, &Type, sizeof (UINT16))) { + // + // The header contains the STRING package length + // The assumption is that the strings for all languages + // are a contiguous block of data and there is a series of + // these package instances which will terminate with a NULL package + // instance. + // + StringPack = (EFI_HII_STRING_PACK *) Pack; + + // + // There may be multiple instances packed together of strings + // so we must walk the self describing structures until we encounter + // the NULL structure to determine the full size. + // + CopyMem (&Length, &StringPack->Header.Length, sizeof (Length)); + if (NumberOfTokens != NULL) { + CopyMem (NumberOfTokens, &StringPack->NumStringPointers, sizeof (UINT32)); + } + + while (Length != 0) { + *PackSize = *PackSize + Length; + StringPack = (EFI_HII_STRING_PACK *) ((CHAR8 *) StringPack + Length); + CopyMem (&Length, &StringPack->Header.Length, sizeof (Length)); + } + // + // Encountered a length of 0, so let's add the space for the NULL terminator + // pack's length and call it done. + // + *PackSize = *PackSize + sizeof (EFI_HII_STRING_PACK); + return EFI_SUCCESS; + } + // + // We only determine the size of the non-global Package types. + // If neither IFR or STRING data were found, return an error + // + return EFI_NOT_FOUND; +} + +EFI_STATUS +ValidatePack ( + IN EFI_HII_PROTOCOL *This, + IN EFI_HII_PACKAGE_INSTANCE *PackageInstance, + OUT EFI_HII_PACKAGE_INSTANCE **StringPackageInstance, + OUT UINT32 *TotalStringCount + ) +/*++ + +Routine Description: + Verifies that the package instance is using the correct handle for string operations. + +Arguments: + +Returns: + +--*/ +{ + EFI_HII_DATA *HiiData; + EFI_HII_HANDLE_DATABASE *HandleDatabase; + EFI_HII_PACKAGE_INSTANCE *HandlePackageInstance; + UINT8 *RawData; + EFI_GUID Guid; + EFI_HII_IFR_PACK *FormPack; + UINTN Index; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + HiiData = EFI_HII_DATA_FROM_THIS (This); + + HandleDatabase = HiiData->DatabaseHead; + ZeroMem (&Guid, sizeof (EFI_GUID)); + + *StringPackageInstance = PackageInstance; + + // + // Based on if there is IFR data in this package instance, determine + // what the location is of the beginning of the string data. + // + if (PackageInstance->IfrSize > 0) { + FormPack = (EFI_HII_IFR_PACK *) ((CHAR8 *) (&PackageInstance->IfrData) + sizeof (EFI_HII_PACK_HEADER)); + } else { + // + // If there is no IFR data assume the caller knows what they are doing. + // + return EFI_SUCCESS; + } + + RawData = (UINT8 *) FormPack; + + for (Index = 0; RawData[Index] != EFI_IFR_END_FORM_SET_OP;) { + if (RawData[Index] == EFI_IFR_FORM_SET_OP) { + // + // Cache the guid for this formset + // + CopyMem (&Guid, &((EFI_IFR_FORM_SET *) &RawData[Index])->Guid, sizeof (EFI_GUID)); + break; + } + + Index = RawData[Index + 1] + Index; + } + // + // If there is no string package, and the PackageInstance->IfrPack.Guid and PackageInstance->Guid are + // different, we should return the correct handle for the caller to use for strings. + // + if ((PackageInstance->StringSize == 0) && (!CompareGuid (&Guid, &PackageInstance->Guid))) { + // + // Search the database for a handle that matches the PackageInstance->Guid + // + for (; HandleDatabase != NULL; HandleDatabase = HandleDatabase->NextHandleDatabase) { + // + // Get Ifrdata and extract the Guid for it + // + HandlePackageInstance = HandleDatabase->Buffer; + + ASSERT (HandlePackageInstance->IfrSize != 0); + + FormPack = (EFI_HII_IFR_PACK *) ((CHAR8 *) (&HandlePackageInstance->IfrData) + sizeof (EFI_HII_PACK_HEADER)); + RawData = (UINT8 *) FormPack; + + for (Index = 0; RawData[Index] != EFI_IFR_END_FORM_SET_OP;) { + if (RawData[Index] == EFI_IFR_FORM_SET_OP) { + // + // Cache the guid for this formset + // + CopyMem (&Guid, &((EFI_IFR_FORM_SET *) &RawData[Index])->Guid, sizeof (EFI_GUID)); + break; + } + + Index = RawData[Index + 1] + Index; + } + // + // If the Guid from the new handle matches the original Guid referenced in the original package data + // return the appropriate package instance data to use. + // + if (CompareGuid (&Guid, &PackageInstance->Guid)) { + if (TotalStringCount != NULL) { + *TotalStringCount = HandleDatabase->NumberOfTokens; + } + + *StringPackageInstance = HandlePackageInstance; + } + } + // + // end for + // + } else { + return EFI_SUCCESS; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +HiiNewPack ( + IN EFI_HII_PROTOCOL *This, + IN EFI_HII_PACKAGES *Packages, + OUT EFI_HII_HANDLE *Handle + ) +/*++ + +Routine Description: + + Extracts the various packs from a package list. + +Arguments: + + This - Pointer of HII protocol. + Packages - Pointer of HII packages. + Handle - Handle value to be returned. + +Returns: + + EFI_SUCCESS - Pacakges has added to HII database successfully. + EFI_INVALID_PARAMETER - Invalid parameter. + +--*/ +{ + EFI_HII_PACKAGE_INSTANCE *PackageInstance; + EFI_HII_DATA *HiiData; + EFI_HII_HANDLE_DATABASE *HandleDatabase; + EFI_HII_HANDLE_DATABASE *Database; + EFI_HII_PACK_HEADER *PackageHeader; + EFI_HII_GLOBAL_DATA *GlobalData; + EFI_HII_IFR_PACK *IfrPack; + EFI_HII_STRING_PACK *StringPack; + EFI_HII_FONT_PACK *FontPack; + EFI_HII_KEYBOARD_PACK *KeyboardPack; + EFI_STATUS Status; + UINTN IfrSize; + UINTN StringSize; + UINTN TotalStringSize; + UINTN InstanceSize; + UINTN Count; + UINTN Index; + UINT16 Member; + EFI_GUID Guid; + EFI_FORM_SET_STUB FormSetStub; + UINT8 *Location; + UINT16 Unicode; + UINT16 NumWideGlyphs; + UINT16 NumNarrowGlyphs; + UINT32 NumberOfTokens; + UINT32 TotalTokenNumber; + UINT8 *Local; + EFI_NARROW_GLYPH *NarrowGlyph; + EFI_WIDE_GLYPH *WideGlyph; + + if (Packages->NumberOfPackages == 0 || This == NULL) { + return EFI_INVALID_PARAMETER; + } + + HiiData = EFI_HII_DATA_FROM_THIS (This); + + GlobalData = HiiData->GlobalData; + + Database = HiiData->DatabaseHead; + + PackageInstance = NULL; + IfrPack = NULL; + StringPack = NULL; + InstanceSize = 0; + IfrSize = 0; + StringSize = 0; + TotalStringSize = 0; + NumberOfTokens = 0; + TotalTokenNumber = 0; + + // + // Search through the passed in Packages for the IfrPack and any StringPack. + // + for (Index = 0; Index < Packages->NumberOfPackages; Index++) { + + PackageHeader = *(EFI_HII_PACK_HEADER **) (((UINT8 *) Packages) + sizeof (EFI_HII_PACKAGES) + Index * sizeof (VOID *)); + + switch (PackageHeader->Type) { + case EFI_HII_IFR: + // + // There shoule be only one Ifr package. + // + ASSERT (IfrPack == NULL); + IfrPack = (EFI_HII_IFR_PACK *) PackageHeader; + break; + + case EFI_HII_STRING: + StringPack = (EFI_HII_STRING_PACK *) PackageHeader; + // + // Sending me a String Package. Get its size. + // + Status = GetPackSize ((VOID *) StringPack, &StringSize, &NumberOfTokens); + ASSERT (!EFI_ERROR (Status)); + + // + // The size which GetPackSize() returns include the null terminator. So if multiple + // string packages are passed in, merge all these packages, and only pad one null terminator. + // + if (TotalStringSize > 0) { + TotalStringSize -= sizeof (EFI_HII_STRING_PACK); + } + + TotalStringSize += StringSize; + TotalTokenNumber += NumberOfTokens; + break; + } + } + // + // If sending a StringPack without an IfrPack, you must include a GuidId + // + if ((StringPack != NULL) && (IfrPack == NULL)) { + if (Packages->GuidId == NULL) { + return EFI_INVALID_PARAMETER; + } + } + // + // If passing in an IfrPack and a GuidId is provided, ensure they are the same value. + // + if ((IfrPack != NULL) && (Packages->GuidId != NULL)) { + Location = ((UINT8 *) IfrPack); + Location = (UINT8 *) (((UINTN) Location) + sizeof (EFI_HII_PACK_HEADER)); + + // + // Advance to the Form Set Op-code + // + for (Count = 0; ((EFI_IFR_OP_HEADER *) &Location[Count])->OpCode != EFI_IFR_FORM_SET_OP;) { + Count = Count + ((EFI_IFR_OP_HEADER *) &Location[Count])->Length; + } + // + // Copy to local variable + // + CopyMem (&Guid, &((EFI_IFR_FORM_SET *) &Location[Count])->Guid, sizeof (EFI_GUID)); + + // + // Check to see if IfrPack->Guid != GuidId + // + if (!CompareGuid (&Guid, Packages->GuidId)) { + // + // If a string package is present, the GUIDs should have agreed. Return an error + // + if (StringPack != NULL) { + return EFI_INVALID_PARAMETER; + } + } + } + // + // If someone is passing in a string only, create a dummy IfrPack with a Guid + // to enable future searching of this data. + // + if ((IfrPack == NULL) && (StringPack != NULL)) { + ZeroMem (&FormSetStub, sizeof (FormSetStub)); + + FormSetStub.Header.Type = EFI_HII_IFR; + FormSetStub.Header.Length = sizeof (EFI_FORM_SET_STUB); + + FormSetStub.FormSet.Header.OpCode = EFI_IFR_FORM_SET_OP; + FormSetStub.FormSet.Header.Length = (UINT8) sizeof (EFI_IFR_FORM_SET); + // + // Dummy string + // + FormSetStub.FormSet.FormSetTitle = 0x02; + CopyMem (&FormSetStub.FormSet.Guid, Packages->GuidId, sizeof (EFI_GUID)); + + FormSetStub.EndFormSet.Header.OpCode = EFI_IFR_END_FORM_SET_OP; + FormSetStub.EndFormSet.Header.Length = (UINT8) sizeof (EFI_IFR_END_FORM_SET); + IfrPack = (EFI_HII_IFR_PACK *) &FormSetStub; + } + + if (IfrPack != NULL) { + // + // Sending me an IFR Package. Get its size. + // + Status = GetPackSize ((VOID *) IfrPack, &IfrSize, NULL); + ASSERT (!EFI_ERROR (Status)); + } + // + // Prepare the internal package instace buffer to store package data. + // + InstanceSize = IfrSize + TotalStringSize; + + if (InstanceSize != 0) { + PackageInstance = AllocateZeroPool (InstanceSize + sizeof (EFI_HII_PACKAGE_INSTANCE)); + + ASSERT (PackageInstance); + + // + // If there is no DatabaseHead allocated - allocate one + // + if (HiiData->DatabaseHead == NULL) { + HiiData->DatabaseHead = AllocateZeroPool (sizeof (EFI_HII_HANDLE_DATABASE)); + ASSERT (HiiData->DatabaseHead); + } + // + // If the head is being used (Handle is non-zero), allocate next Database and + // add it to the linked-list + // + if (HiiData->DatabaseHead->Handle != 0) { + HandleDatabase = AllocateZeroPool (sizeof (EFI_HII_HANDLE_DATABASE)); + + ASSERT (HandleDatabase); + + for (; Database->NextHandleDatabase != NULL; Database = Database->NextHandleDatabase) + ; + + // + // We are sitting on the Database entry which contains the null Next pointer. Fix it. + // + Database->NextHandleDatabase = HandleDatabase; + + } + + Database = HiiData->DatabaseHead; + + // + // Initialize this instance data + // + for (*Handle = 1; Database->NextHandleDatabase != NULL; Database = Database->NextHandleDatabase) { + // + // Since the first Database instance will have a passed back handle of 1, we will continue + // down the linked list of entries until we encounter the end of the linked list. Each time + // we go down one level deeper, increment the handle value that will be passed back. + // + if (Database->Handle >= *Handle) { + *Handle = Database->Handle + 1; + } + } + + PackageInstance->Handle = *Handle; + PackageInstance->IfrSize = IfrSize; + PackageInstance->StringSize = TotalStringSize; + if (Packages->GuidId != NULL) { + CopyMem (&PackageInstance->Guid, Packages->GuidId, sizeof (EFI_GUID)); + } + + Database->Buffer = PackageInstance; + Database->Handle = PackageInstance->Handle; + Database->NumberOfTokens = TotalTokenNumber; + Database->NextHandleDatabase = NULL; + } + // + // Copy the Ifr package data into package instance. + // + if (IfrSize > 0) { + CopyMem (&PackageInstance->IfrData, IfrPack, IfrSize); + } + // + // Main loop to store package data into HII database. + // + StringSize = 0; + TotalStringSize = 0; + + for (Index = 0; Index < Packages->NumberOfPackages; Index++) { + + PackageHeader = *(EFI_HII_PACK_HEADER **) (((UINT8 *) Packages) + sizeof (EFI_HII_PACKAGES) + Index * sizeof (VOID *)); + + switch (PackageHeader->Type) { + case EFI_HII_STRING: + StringPack = (EFI_HII_STRING_PACK *) PackageHeader; + // + // The size which GetPackSize() returns include the null terminator. So if multiple + // string packages are passed in, merge all these packages, and only pad one null terminator. + // + if (TotalStringSize > 0) { + TotalStringSize -= sizeof (EFI_HII_STRING_PACK); + } + + GetPackSize ((VOID *) StringPack, &StringSize, &NumberOfTokens); + CopyMem ((CHAR8 *) (&PackageInstance->IfrData) + IfrSize + TotalStringSize, StringPack, StringSize); + + TotalStringSize += StringSize; + break; + + case EFI_HII_HANDLES: + CopyMem (&PackageInstance->HandlePack, PackageHeader, sizeof (EFI_HII_HANDLE_PACK)); + break; + + case EFI_HII_FONT: + FontPack = (EFI_HII_FONT_PACK *) PackageHeader; + // + // Add whatever narrow glyphs were passed to us if undefined + // + CopyMem (&NumNarrowGlyphs, &FontPack->NumberOfNarrowGlyphs, sizeof (UINT16)); + for (Count = 0; Count <= NumNarrowGlyphs; Count++) { + Local = (UINT8 *) (&FontPack->NumberOfWideGlyphs + sizeof (UINT8)) + (sizeof (EFI_NARROW_GLYPH)) * Count; + NarrowGlyph = (EFI_NARROW_GLYPH *) Local; + CopyMem (&Member, &NarrowGlyph->UnicodeWeight, sizeof (UINT16)); + // + // If the glyph is already defined, do not overwrite it. It is what it is. + // + CopyMem (&Unicode, &GlobalData->NarrowGlyphs[Member].UnicodeWeight, sizeof (UINT16)); + if (Unicode == 0) { + CopyMem (&GlobalData->NarrowGlyphs[Member], Local, sizeof (EFI_NARROW_GLYPH)); + } + } + // + // Add whatever wide glyphs were passed to us if undefined + // + CopyMem (&NumWideGlyphs, &FontPack->NumberOfWideGlyphs, sizeof (UINT16)); + for (Count = 0; Count <= NumWideGlyphs; Count++) { + Local = (UINT8 *) (&FontPack->NumberOfWideGlyphs + sizeof (UINT8)) + + (sizeof (EFI_NARROW_GLYPH)) * + NumNarrowGlyphs; + WideGlyph = (EFI_WIDE_GLYPH *) Local; + CopyMem ( + &Member, + (UINTN *) (Local + sizeof (EFI_WIDE_GLYPH) * Count), + sizeof (UINT16) + ); + // + // If the glyph is already defined, do not overwrite it. It is what it is. + // + CopyMem (&Unicode, &GlobalData->WideGlyphs[Member].UnicodeWeight, sizeof (UINT16)); + if (Unicode == 0) { + Local = (UINT8*)(&FontPack->NumberOfWideGlyphs + sizeof(UINT8)) + (sizeof(EFI_NARROW_GLYPH)) * NumNarrowGlyphs; + WideGlyph = (EFI_WIDE_GLYPH *) Local; + CopyMem ( + &GlobalData->WideGlyphs[Member], + (UINTN *) (Local + sizeof (EFI_WIDE_GLYPH) * Count), + sizeof (EFI_WIDE_GLYPH) + ); + } + } + break; + + case EFI_HII_KEYBOARD: + KeyboardPack = (EFI_HII_KEYBOARD_PACK *) PackageHeader; + // + // Sending me a Keyboard Package + // + if (KeyboardPack->DescriptorCount > 105) { + return EFI_INVALID_PARAMETER; + } + // + // If someone updates the Descriptors with a count of 0, blow aware the overrides. + // + if (KeyboardPack->DescriptorCount == 0) { + ZeroMem (GlobalData->OverrideKeyboardLayout, sizeof (EFI_KEY_DESCRIPTOR) * 106); + } + + if (KeyboardPack->DescriptorCount < 106 && KeyboardPack->DescriptorCount > 0) { + // + // If SystemKeyboard was updated already, then steer changes to the override database + // + if (GlobalData->SystemKeyboardUpdate) { + ZeroMem (GlobalData->OverrideKeyboardLayout, sizeof (EFI_KEY_DESCRIPTOR) * 106); + for (Count = 0; Count < KeyboardPack->DescriptorCount; Count++) { + CopyMem (&Member, &KeyboardPack->Descriptor[Count].Key, sizeof (UINT16)); + CopyMem ( + &GlobalData->OverrideKeyboardLayout[Member], + &KeyboardPack->Descriptor[Count], + sizeof (EFI_KEY_DESCRIPTOR) + ); + } + } else { + // + // SystemKeyboard was never updated, so this is likely the keyboard driver setting the System database. + // + ZeroMem (GlobalData->SystemKeyboardLayout, sizeof (EFI_KEY_DESCRIPTOR) * 106); + for (Count = 0; Count < KeyboardPack->DescriptorCount; Count++) { + CopyMem (&Member, &KeyboardPack->Descriptor->Key, sizeof (UINT16)); + CopyMem ( + &GlobalData->SystemKeyboardLayout[Member], + &KeyboardPack->Descriptor[Count], + sizeof (EFI_KEY_DESCRIPTOR) + ); + } + // + // Just updated the system keyboard database, reflect that in the global flag. + // + GlobalData->SystemKeyboardUpdate = TRUE; + } + } + break; + + default: + break; + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +HiiRemovePack ( + IN EFI_HII_PROTOCOL *This, + IN EFI_HII_HANDLE Handle + ) +/*++ + +Routine Description: + Removes the various packs from a Handle + +Arguments: + +Returns: + +--*/ +{ + EFI_HII_PACKAGE_INSTANCE *PackageInstance; + EFI_HII_DATA *HiiData; + EFI_HII_HANDLE_DATABASE *HandleDatabase; + EFI_HII_HANDLE_DATABASE *PreviousHandleDatabase; + UINTN Count; + + if (This == NULL || Handle == 0) { + return EFI_INVALID_PARAMETER; + } + + HiiData = EFI_HII_DATA_FROM_THIS (This); + + HandleDatabase = HiiData->DatabaseHead; + PackageInstance = NULL; + + // + // Initialize the Previous with the Head of the Database + // + PreviousHandleDatabase = HandleDatabase; + + for (Count = 0; HandleDatabase != NULL; HandleDatabase = HandleDatabase->NextHandleDatabase) { + // + // Match the numeric value with the database entry - if matched, + // free the package instance and apply fix-up to database linked list + // + if (Handle == HandleDatabase->Handle) { + PackageInstance = HandleDatabase->Buffer; + + // + // Free the Package Instance + // + gBS->FreePool (PackageInstance); + + // + // If this was the only Handle in the database + // + if (HiiData->DatabaseHead == HandleDatabase) { + HiiData->DatabaseHead = NULL; + } + // + // Make the parent->Next point to the current->Next + // + PreviousHandleDatabase->NextHandleDatabase = HandleDatabase->NextHandleDatabase; + gBS->FreePool (HandleDatabase); + return EFI_SUCCESS; + } + // + // If this was not the HandleDatabase entry we were looking for, cache it just in case the next one is + // + PreviousHandleDatabase = HandleDatabase; + } + // + // No handle was found - error condition + // + if (PackageInstance == NULL) { + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/Strings.c b/EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/Strings.c new file mode 100644 index 0000000000..742a01dc43 --- /dev/null +++ b/EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/Strings.c @@ -0,0 +1,1276 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Strings.c + +Abstract: + + This file contains the string processing code to the HII database. + +--*/ + + +#include "HiiDatabase.h" + +VOID +AsciiToUnicode ( + IN UINT8 *Lang, + IN UINT16 *Language + ) +{ + UINT8 Count; + + // + // Convert the ASCII Lang variable to a Unicode Language variable + // + for (Count = 0; Count < 3; Count++) { + Language[Count] = (CHAR16) Lang[Count]; + } +} + +EFI_STATUS +EFIAPI +HiiTestString ( + IN EFI_HII_PROTOCOL *This, + IN CHAR16 *StringToTest, + IN OUT UINT32 *FirstMissing, + OUT UINT32 *GlyphBufferSize + ) +/*++ + +Routine Description: + Test if all of the characters in a string have corresponding font characters. + +Arguments: + +Returns: + +--*/ +{ + EFI_HII_GLOBAL_DATA *GlobalData; + EFI_HII_DATA *HiiData; + UINTN Count; + BOOLEAN Narrow; + UINTN Location; + UINT8 GlyphCol1[19]; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + HiiData = EFI_HII_DATA_FROM_THIS (This); + + GlobalData = HiiData->GlobalData; + Count = 0; + Narrow = TRUE; + + ZeroMem (GlyphCol1, sizeof (GlyphCol1)); + + // + // Walk through the string until you hit the null terminator + // + for (; StringToTest[*FirstMissing] != 0x00; (*FirstMissing)++) { + Location = *FirstMissing; + // + // Rewind through the string looking for a glyph width identifier + // + for (; Location != 0; Location--) { + if (StringToTest[Location] == NARROW_CHAR || StringToTest[Location] == WIDE_CHAR) { + // + // We found something that identifies what glyph database to look in + // + if (StringToTest[Location] == WIDE_CHAR) { + Narrow = FALSE; + } else { + Narrow = TRUE; + } + } + } + + if (Narrow) { + if (CompareMem ( + GlobalData->NarrowGlyphs[StringToTest[*FirstMissing]].GlyphCol1, + &mUnknownGlyph, + NARROW_GLYPH_ARRAY_SIZE + ) == 0 + ) { + // + // Break since this glyph isn't defined + // + return EFI_NOT_FOUND; + } + } else { + // + // Can compare wide glyph against only GlyphCol1 since GlyphCol1 and GlyphCol2 are contiguous - just give correct size + // + if (CompareMem ( + GlobalData->WideGlyphs[StringToTest[*FirstMissing]].GlyphCol1, + &mUnknownGlyph, + WIDE_GLYPH_ARRAY_SIZE + ) == 0 + ) { + // + // Break since this glyph isn't defined + // + return EFI_NOT_FOUND; + } + } + + Count++; + } + + if (Narrow) { + *GlyphBufferSize = (UINT32) (Count * sizeof (EFI_NARROW_GLYPH)); + } else { + *GlyphBufferSize = (UINT32) (Count * sizeof (EFI_WIDE_GLYPH)); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +HiiNewString2 ( + IN EFI_HII_PROTOCOL *This, + IN CHAR16 *Language, + IN EFI_HII_HANDLE Handle, + IN OUT STRING_REF *Reference, + IN CHAR16 *NewString, + IN BOOLEAN ResetStrings + ) +/*++ + +Routine Description: + + This function allows a new String to be added to an already existing String Package. + We will make a buffer the size of the package + EfiStrSize of the new string. We will + copy the string package that first gets changed and the following language packages until + we encounter the NULL string package. All this time we will ensure that the offsets have + been adjusted. + +Arguments: + + This - Pointer to the HII protocol. + Language - Pointer to buffer which contains the language code of this NewString. + Handle - Handle of the package instance to be processed. + Reference - The token number for the string. If 0, new string token to be returned through this parameter. + NewString - Buffer pointer for the new string. + ResetStrings - Indicate if we are resetting a string. + +Returns: + + EFI_SUCCESS - The string has been added or reset to Hii database. + EFI_INVALID_PARAMETER - Some parameter passed in is invalid. + +--*/ +{ + EFI_HII_PACKAGE_INSTANCE *PackageInstance; + EFI_HII_PACKAGE_INSTANCE *StringPackageInstance; + EFI_HII_DATA *HiiData; + EFI_HII_STRING_PACK *StringPack; + EFI_HII_STRING_PACK *NewStringPack; + EFI_HII_HANDLE_DATABASE *HandleDatabase; + EFI_HII_PACKAGE_INSTANCE *NewBuffer; + UINT8 *Location; + UINT8 *StringLocation; + RELOFST *StringPointer; + UINTN Count; + UINTN Size; + UINTN Index; + UINTN SecondIndex; + BOOLEAN AddString; + EFI_STATUS Status; + UINTN Increment; + UINTN StringCount; + UINT32 TotalStringCount; + UINT32 OriginalStringCount; + RELOFST StringSize; + UINT32 Length; + RELOFST Offset; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + HiiData = EFI_HII_DATA_FROM_THIS (This); + + HandleDatabase = HiiData->DatabaseHead; + PackageInstance = NULL; + AddString = FALSE; + Increment = 0; + StringCount = 0; + TotalStringCount = 0; + OriginalStringCount = 0; + + // + // Check numeric value against the head of the database + // + for (; HandleDatabase != NULL; HandleDatabase = HandleDatabase->NextHandleDatabase) { + // + // Match the numeric value with the database entry - if matched, extract PackageInstance + // + if (Handle == HandleDatabase->Handle) { + PackageInstance = HandleDatabase->Buffer; + if (ResetStrings) { + TotalStringCount = HandleDatabase->NumberOfTokens; + } + break; + } + } + // + // No handle was found - error condition + // + if (PackageInstance == NULL) { + return EFI_INVALID_PARAMETER; + } + + Status = ValidatePack (This, PackageInstance, &StringPackageInstance, &TotalStringCount); + + // + // This sets Count to 0 or the size of the IfrData. We intend to use Count as an offset value + // + Count = StringPackageInstance->IfrSize; + + // + // This is the size of the complete series of string packs + // + Size = StringPackageInstance->StringSize; + + // + // Based on if there is IFR data in this package instance, determine + // what the location is of the beginning of the string data. + // + if (StringPackageInstance->IfrSize > 0) { + Location = (UINT8 *) (&StringPackageInstance->IfrData) + StringPackageInstance->IfrSize; + } else { + Location = (UINT8 *) (&StringPackageInstance->IfrData); + } + // + // We allocate a buffer which is big enough for both adding and resetting string. + // The size is slightly larger than the real size of the packages when we are resetting a string. + // + NewBuffer = AllocateZeroPool ( + sizeof (EFI_HII_PACKAGE_INSTANCE) - + 2 * sizeof (VOID *) + + StringPackageInstance->IfrSize + + StringPackageInstance->StringSize + + sizeof (RELOFST) + + StrSize (NewString) + ); + ASSERT (NewBuffer); + + // + // Copy data to new buffer + // + NewBuffer->Handle = StringPackageInstance->Handle; + NewBuffer->IfrSize = StringPackageInstance->IfrSize; + + // + // The worst case scenario for sizing is that we are adding a new string (not replacing one) and there was not a string + // package to begin with. + // + NewBuffer->StringSize = StringPackageInstance->StringSize + StrSize (NewString) + sizeof (EFI_HII_STRING_PACK); + + if (StringPackageInstance->IfrSize > 0) { + CopyMem (&NewBuffer->IfrData, &StringPackageInstance->IfrData, StringPackageInstance->IfrSize); + } + + StringPack = (EFI_HII_STRING_PACK *) Location; + + // + // There may be multiple instances packed together of strings + // so we must walk the self describing structures until we encounter + // what we are looking for. In the meantime, copy everything we encounter + // to the new buffer. + // + CopyMem (&Length, &StringPack->Header.Length, sizeof (UINT32)); + for (; Length != 0;) { + // + // If passed in Language ISO value is in this string pack's language string + // then we are dealing with the strings we want. + // + CopyMem (&Offset, &StringPack->LanguageNameString, sizeof (RELOFST)); + Status = HiiCompareLanguage ((CHAR16 *) ((CHAR8 *) (StringPack) + Offset), Language); + + if (!EFI_ERROR (Status)) { + break; + } + + CopyMem (((CHAR8 *) (&NewBuffer->IfrData) + Count), StringPack, Length); + + Count = Count + Length; + StringPack = (EFI_HII_STRING_PACK *) ((CHAR8 *) (StringPack) + Length); + CopyMem (&Length, &StringPack->Header.Length, sizeof (UINT32)); + } + // + // Found the language pack to update on a particular handle + // We need to Copy the Contents of this pack and adjust the offset values associated + // with adding/changing a string. This is a particular piece of code that screams for + // it being prone to programming error. + // + // + // Copy the string package up to the string data + // + StringPointer = (RELOFST *) (StringPack + 1); + CopyMem ( + ((CHAR8 *) (&NewBuffer->IfrData) + Count), + StringPack, + (UINTN) ((UINTN) (StringPointer) - (UINTN) (StringPack)) + ); + + // + // Determine the number of StringPointers + // + if (!ResetStrings) { + CopyMem (&TotalStringCount, &StringPack->NumStringPointers, sizeof (RELOFST)); + } else { + // + // If we are resetting the strings, use the original value when exported + // + CopyMem (&OriginalStringCount, &StringPack->NumStringPointers, sizeof (RELOFST)); + ((EFI_HII_STRING_PACK *) ((CHAR8 *) (&NewBuffer->IfrData) + Count))->LanguageNameString -= + ( + (RELOFST) (OriginalStringCount - TotalStringCount) * + sizeof (RELOFST) + ); + ((EFI_HII_STRING_PACK *) ((CHAR8 *) (&NewBuffer->IfrData) + Count))->PrintableLanguageName -= + ( + (RELOFST) (OriginalStringCount - TotalStringCount) * + sizeof (RELOFST) + ); + ((EFI_HII_STRING_PACK *) ((CHAR8 *) (&NewBuffer->IfrData) + Count))->NumStringPointers = TotalStringCount; + *Reference = (STRING_REF) (TotalStringCount); + } + // + // If the token value is not valid, error out + // + if ((*Reference >= TotalStringCount) && !ResetStrings) { + gBS->FreePool (NewBuffer); + return EFI_INVALID_PARAMETER; + } + // + // If Reference is 0, update it with what the new token reference will be and turn the AddString flag on + // + if (*Reference == 0) { + *Reference = (STRING_REF) (TotalStringCount); + AddString = TRUE; + } + + if (AddString) { + ((EFI_HII_STRING_PACK *) ((CHAR8 *) (&NewBuffer->IfrData) + Count))->LanguageNameString += sizeof (RELOFST); + ((EFI_HII_STRING_PACK *) ((CHAR8 *) (&NewBuffer->IfrData) + Count))->PrintableLanguageName += sizeof (RELOFST); + ((EFI_HII_STRING_PACK *) ((CHAR8 *) (&NewBuffer->IfrData) + Count))->NumStringPointers++; + } + // + // Increment offset by amount of copied data + // + Count = Count + ((UINTN) (StringPointer) - (UINTN) StringPack); + + for (Index = 0; Index < TotalStringCount; Index++) { + // + // If we are pointing to the size of the changing string value + // then cache the old string value so you know what the difference is + // + if (Index == *Reference) { + CopyMem (&Offset, &StringPointer[Index], sizeof (RELOFST)); + + StringLocation = ((UINT8 *) (StringPack) + Offset); + for (SecondIndex = 0; + (StringLocation[SecondIndex] != 0) || (StringLocation[SecondIndex + 1] != 0); + SecondIndex = SecondIndex + 2 + ) + ; + SecondIndex = SecondIndex + 2; + + Size = SecondIndex; + + // + // NewString is a passed in local string which is assumed to be aligned + // + Size = StrSize (NewString) - Size; + } + // + // If we are about to copy the offset of the string that follows the changed string make + // sure that the offsets are adjusted accordingly + // + if ((Index > *Reference) && !ResetStrings) { + CopyMem (&Offset, &StringPointer[Index], sizeof (RELOFST)); + Offset = (RELOFST) (Offset + Size); + CopyMem (&StringPointer[Index], &Offset, sizeof (RELOFST)); + } + // + // If we are adding a string that means we will have an extra string pointer that will affect all string offsets + // + if (AddString) { + CopyMem (&Offset, &StringPointer[Index], sizeof (RELOFST)); + Offset = (UINT32) (Offset + sizeof (RELOFST)); + CopyMem (&StringPointer[Index], &Offset, sizeof (RELOFST)); + } + // + // If resetting the strings, we need to reduce the offset by the difference in the strings + // + if (ResetStrings) { + CopyMem (&Length, &StringPointer[Index], sizeof (RELOFST)); + Length = Length - ((RELOFST) (OriginalStringCount - TotalStringCount) * sizeof (RELOFST)); + CopyMem (&StringPointer[Index], &Length, sizeof (RELOFST)); + } + // + // Notice that if the string was being added as a new token, we don't have to worry about the + // offsets changing in the other indexes + // + CopyMem (((CHAR8 *) (&NewBuffer->IfrData) + Count), &StringPointer[Index], sizeof (RELOFST)); + Count = Count + sizeof (RELOFST); + StringCount++; + } + // + // If we are adding a new string the above for loop did not copy the offset for us + // + if (AddString) { + // + // Since the Index is pointing to the beginning of the first string, we need to gather the size of the previous + // offset's string and create an offset to our new string. + // + CopyMem (&Offset, &StringPointer[Index - 1], sizeof (RELOFST)); + StringLocation = (UINT8 *) StringPack; + StringLocation = StringLocation + Offset - sizeof (RELOFST); + + // + // Since StringPack is a packed structure, we need to size it carefully (byte-wise) to avoid alignment issues + // + for (Length = 0; + (StringLocation[Length] != 0) || (StringLocation[Length + 1] != 0); + Length = (RELOFST) (Length + 2) + ) + ; + Length = (RELOFST) (Length + 2); + + StringSize = (RELOFST) (Offset + Length); + + // + // Copy the new string offset + // + CopyMem (((CHAR8 *) (&NewBuffer->IfrData) + Count), &StringSize, sizeof (RELOFST)); + Count = Count + sizeof (RELOFST); + + CopyMem (&Length, &StringPack->Header.Length, sizeof (UINT32)); + Length = Length + sizeof (RELOFST); + CopyMem (&StringPack->Header.Length, &Length, sizeof (UINT32)); + } + // + // Set Location to the First String + // + if (ResetStrings) { + Index = OriginalStringCount; + } + // + // Set Location to the First String + // + Location = (UINT8 *) &StringPointer[Index]; + Index = 0; + + // + // Keep copying strings until you run into two CHAR16's in a row that are NULL + // + do { + if ((*Reference == Increment) && !AddString) { + StringLocation = ((UINT8 *) (&NewBuffer->IfrData) + Count); + CopyMem (StringLocation, NewString, StrSize (NewString)); + + // + // Advance the destination location by Count number of bytes + // + Count = Count + StrSize (NewString); + + // + // Add the difference between the new string and the old string to the length + // + CopyMem (&Length, &StringPack->Header.Length, sizeof (UINT32)); + + // + // Since StringPack is a packed structure, we need to size it carefully (byte-wise) to avoid alignment issues + // + StringLocation = (UINT8 *) &Location[Index]; + for (Offset = 0; + (StringLocation[Offset] != 0) || (StringLocation[Offset + 1] != 0); + Offset = (RELOFST) (Offset + 2) + ) + ; + Offset = (RELOFST) (Offset + 2); + + Length = Length + (UINT32) StrSize (NewString) - Offset; + + CopyMem (&StringPack->Header.Length, &Length, sizeof (UINT32)); + } else { + StringLocation = (UINT8 *) &Location[Index]; + for (Offset = 0; + (StringLocation[Offset] != 0) || (StringLocation[Offset + 1] != 0); + Offset = (RELOFST) (Offset + 2) + ) + ; + Offset = (RELOFST) (Offset + 2); + + CopyMem (((CHAR8 *) (&NewBuffer->IfrData) + Count), StringLocation, Offset); + + // + // Advance the destination location by Count number of bytes + // + Count = Count + Offset; + } + // + // Retrieve the number of characters to advance the index - should land at beginning of next string + // + Index = Index + Offset; + Increment++; + StringCount--; + Offset = 0; + } while (StringCount > 0); + + // + // If we are adding a new string, then the above do/while will not suffice + // + if (AddString) { + Offset = (RELOFST) StrSize (NewString); + CopyMem (((CHAR8 *) (&NewBuffer->IfrData) + Count), NewString, Offset); + + Count = Count + StrSize (NewString); + CopyMem (&Length, &StringPack->Header.Length, sizeof (UINT32)); + Length = Length + (UINT32) StrSize (NewString); + CopyMem (&StringPack->Header.Length, &Length, sizeof (UINT32)); + } + + if (ResetStrings) { + // + // Skip the remainder of strings in the string package + // + StringCount = OriginalStringCount - TotalStringCount; + + while (StringCount > 0) { + StringLocation = (UINT8 *) &Location[Index]; + for (Offset = 0; + (StringLocation[Offset] != 0) || (StringLocation[Offset + 1] != 0); + Offset = (RELOFST) (Offset + 2) + ) + ; + Offset = (RELOFST) (Offset + 2); + Index = Index + Offset; + StringCount--; + + // + // Adjust the size of the string pack by the string size we just skipped. + // Also reduce the length by the size of a RelativeOffset value since we + // obviously would have skipped that as well. + // + CopyMem (&Length, &StringPack->Header.Length, sizeof (UINT32)); + Length = Length - Offset - sizeof (RELOFST); + CopyMem (&StringPack->Header.Length, &Length, sizeof (UINT32)); + } + } + + StringPack = (EFI_HII_STRING_PACK *) &Location[Index]; + + CopyMem (&Length, &StringPack->Header.Length, sizeof (UINT32)); + for (; Length != 0;) { + + CopyMem (((CHAR8 *) (&NewBuffer->IfrData) + Count), StringPack, Length); + + Count = Count + Length; + StringPack = (EFI_HII_STRING_PACK *) ((CHAR8 *) (StringPack) + Length); + CopyMem (&Length, &StringPack->Header.Length, sizeof (UINT32)); + } + // + // Copy the null terminator to the new buffer + // + CopyMem (((CHAR8 *) (&NewBuffer->IfrData) + Count), StringPack, sizeof (EFI_HII_STRING_PACK)); + + // + // Based on if there is IFR data in this package instance, determine + // what the location is of the beginning of the string data. + // + if (StringPackageInstance->IfrSize > 0) { + Location = (UINT8 *) (&StringPackageInstance->IfrData) + StringPackageInstance->IfrSize; + StringPack = (EFI_HII_STRING_PACK *) Location; + Location = (UINT8 *) (&NewBuffer->IfrData) + NewBuffer->IfrSize; + NewStringPack = (EFI_HII_STRING_PACK *) Location; + } else { + StringPack = (EFI_HII_STRING_PACK *) (&StringPackageInstance->IfrData); + NewStringPack = (EFI_HII_STRING_PACK *) (&NewBuffer->IfrData); + } + + CopyMem (&Length, &StringPack->Header.Length, sizeof (UINT32)); + for (; Length != 0;) { + // + // Since we updated the old version of the string data as we moved things over + // And we had a chicken-egg problem with the data we copied, let's post-fix the new + // buffer with accurate length data. + // + CopyMem (&Count, &NewStringPack->Header.Length, sizeof (UINT32)); + CopyMem (&NewStringPack->Header.Length, &StringPack->Header.Length, sizeof (UINT32)); + CopyMem (&StringPack->Header.Length, &Count, sizeof (UINT32)); + + CopyMem (&Count, &NewStringPack->Header.Length, sizeof (UINT32)); + NewStringPack = (EFI_HII_STRING_PACK *) ((CHAR8 *) (NewStringPack) + Count); + CopyMem (&Count, &StringPack->Header.Length, sizeof (UINT32)); + StringPack = (EFI_HII_STRING_PACK *) ((CHAR8 *) (StringPack) + Count); + CopyMem (&Length, &StringPack->Header.Length, sizeof (UINT32)); + } + + GetPackSize ((VOID *) ((CHAR8 *) (&NewBuffer->IfrData) + NewBuffer->IfrSize), &NewBuffer->StringSize, NULL); + + // + // Search through the handles until the requested handle is found. + // + for (HandleDatabase = HiiData->DatabaseHead; + HandleDatabase->Handle != 0; + HandleDatabase = HandleDatabase->NextHandleDatabase + ) { + if (HandleDatabase->Handle == StringPackageInstance->Handle) { + // + // Free the previous buffer associated with this handle, and assign the new buffer to the handle + // + gBS->FreePool (HandleDatabase->Buffer); + HandleDatabase->Buffer = NewBuffer; + break; + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +HiiNewString ( + IN EFI_HII_PROTOCOL *This, + IN CHAR16 *Language, + IN EFI_HII_HANDLE Handle, + IN OUT STRING_REF *Reference, + IN CHAR16 *NewString + ) +/*++ + +Routine Description: + This function allows a new String to be added to an already existing String Package. + We will make a buffer the size of the package + StrSize of the new string. We will + copy the string package that first gets changed and the following language packages until + we encounter the NULL string package. All this time we will ensure that the offsets have + been adjusted. + +Arguments: + +Returns: + +--*/ +{ + UINTN Index; + CHAR16 *LangCodes; + CHAR16 Lang[4]; + STRING_REF OriginalValue; + EFI_STATUS Status; + + // + // To avoid a warning 4 uninitialized variable warning + // + Status = EFI_SUCCESS; + + Status = HiiGetPrimaryLanguages ( + This, + Handle, + &LangCodes + ); + + if (!EFI_ERROR (Status)) { + OriginalValue = *Reference; + + if (Language == NULL) { + for (Index = 0; LangCodes[Index] != 0; Index += 3) { + *Reference = OriginalValue; + CopyMem (Lang, &LangCodes[Index], 6); + Lang[3] = 0; + Status = HiiNewString2 ( + This, + Lang, + Handle, + Reference, + NewString, + FALSE + ); + + } + } else { + Status = HiiNewString2 ( + This, + Language, + Handle, + Reference, + NewString, + FALSE + ); + } + + gBS->FreePool (LangCodes); + } + + return Status; +} + +EFI_STATUS +EFIAPI +HiiResetStrings ( + IN EFI_HII_PROTOCOL *This, + IN EFI_HII_HANDLE Handle + ) +/*++ + +Routine Description: + + This function removes any new strings that were added after the initial string export for this handle. + +Arguments: + +Returns: + +--*/ +{ + UINTN Index; + CHAR16 *LangCodes; + CHAR16 Lang[4]; + STRING_REF Reference; + CHAR16 NewString; + EFI_STATUS Status; + + Reference = 1; + NewString = 0; + + HiiGetPrimaryLanguages ( + This, + Handle, + &LangCodes + ); + + for (Index = 0; LangCodes[Index] != 0; Index += 3) { + CopyMem (Lang, &LangCodes[Index], 6); + Lang[3] = 0; + Status = HiiNewString2 ( + This, + Lang, + Handle, + &Reference, + &NewString, + TRUE + ); + + } + + gBS->FreePool (LangCodes); + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +HiiGetString ( + IN EFI_HII_PROTOCOL *This, + IN EFI_HII_HANDLE Handle, + IN STRING_REF Token, + IN BOOLEAN Raw, + IN CHAR16 *LanguageString, + IN OUT UINTN *BufferLengthTemp, + OUT EFI_STRING StringBuffer + ) +/*++ + +Routine Description: + + This function extracts a string from a package already registered with the EFI HII database. + +Arguments: + This - A pointer to the EFI_HII_PROTOCOL instance. + Handle - The HII handle on which the string resides. + Token - The string token assigned to the string. + Raw - If TRUE, the string is returned unedited in the internal storage format described + above. If false, the string returned is edited by replacing with + and by removing special characters such as the prefix. + LanguageString - Pointer to a NULL-terminated string containing a single ISO 639-2 language + identifier, indicating the language to print. If the LanguageString is empty (starts + with a NULL), the default system language will be used to determine the language. + BufferLength - Length of the StringBuffer. If the status reports that the buffer width is too + small, this parameter is filled with the length of the buffer needed. + StringBuffer - The buffer designed to receive the characters in the string. Type EFI_STRING is + defined in String. + +Returns: + EFI_INVALID_PARAMETER - If input parameter is invalid. + EFI_BUFFER_TOO_SMALL - If the *BufferLength is too small. + EFI_SUCCESS - Operation is successful. + +--*/ +{ + EFI_HII_PACKAGE_INSTANCE *PackageInstance; + EFI_HII_PACKAGE_INSTANCE *StringPackageInstance; + EFI_HII_DATA *HiiData; + EFI_HII_HANDLE_DATABASE *HandleDatabase; + EFI_HII_STRING_PACK *StringPack; + RELOFST *StringPointer; + EFI_STATUS Status; + UINTN DataSize; + CHAR8 Lang[3]; + CHAR16 Language[3]; + UINT32 Length; + UINTN Count; + RELOFST Offset; + UINT16 *Local; + UINT16 Zero; + UINT16 Narrow; + UINT16 Wide; + UINT16 NoBreak; + BOOLEAN LangFound; + UINT16 *BufferLength = (UINT16 *) BufferLengthTemp; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + LangFound = TRUE; + + DataSize = sizeof (Lang); + + HiiData = EFI_HII_DATA_FROM_THIS (This); + + PackageInstance = NULL; + Zero = 0; + Narrow = NARROW_CHAR; + Wide = WIDE_CHAR; + NoBreak = NON_BREAKING_CHAR; + + // + // Check numeric value against the head of the database + // + for (HandleDatabase = HiiData->DatabaseHead; + HandleDatabase != NULL; + HandleDatabase = HandleDatabase->NextHandleDatabase + ) { + // + // Match the numeric value with the database entry - if matched, extract PackageInstance + // + if (Handle == HandleDatabase->Handle) { + PackageInstance = HandleDatabase->Buffer; + break; + } + } + // + // No handle was found - error condition + // + if (PackageInstance == NULL) { + return EFI_INVALID_PARAMETER; + } + + Status = ValidatePack (This, PackageInstance, &StringPackageInstance, NULL); + + // + // If there is no specified language, assume the system default language + // + if (LanguageString == NULL) { + // + // Get system default language + // + Status = gRT->GetVariable ( + (CHAR16 *) L"Lang", + &gEfiGlobalVariableGuid, + NULL, + &DataSize, + Lang + ); + + if (EFI_ERROR (Status)) { + // + // If Lang doesn't exist, just use the first language you find + // + LangFound = FALSE; + goto LangNotFound; + } + // + // Convert the ASCII Lang variable to a Unicode Language variable + // + AsciiToUnicode ((UINT8 *)Lang, Language); + } else { + // + // Copy input ISO value to Language variable + // + CopyMem (Language, LanguageString, 6); + } + // + // Based on if there is IFR data in this package instance, determine + // what the location is of the beginning of the string data. + // +LangNotFound: + if (StringPackageInstance->IfrSize > 0) { + StringPack = (EFI_HII_STRING_PACK *) ((CHAR8 *) (&StringPackageInstance->IfrData) + StringPackageInstance->IfrSize); + } else { + StringPack = (EFI_HII_STRING_PACK *) (&StringPackageInstance->IfrData); + } + // + // If Token is 0, extract entire string package + // + if (Token == 0) { + // + // Compute the entire string pack length, including all languages' and the terminating pack's. + // + Length = 0; + while (0 != StringPack->Header.Length) { + Length += StringPack->Header.Length; + StringPack = (VOID*)(((UINT8*)StringPack) + StringPack->Header.Length); + } + // + // Back to the start of package. + // + StringPack = (VOID*)(((UINT8*)StringPack) - Length); + // + // Terminating zero sub-pack. + // + Length += sizeof (EFI_HII_STRING_PACK); + + // + // If trying to get the entire string package and have insufficient space. Return error. + // + if (Length > *BufferLength || StringBuffer == NULL) { + *BufferLength = (UINT16)Length; + return EFI_BUFFER_TOO_SMALL; + } + // + // Copy the Pack to the caller's buffer. + // + *BufferLength = (UINT16)Length; + CopyMem (StringBuffer, StringPack, Length); + + return EFI_SUCCESS; + } + // + // There may be multiple instances packed together of strings + // so we must walk the self describing structures until we encounter + // what we are looking for, and then extract the string we are looking for + // + CopyMem (&Length, &StringPack->Header.Length, sizeof (UINT32)); + for (; Length != 0;) { + // + // If passed in Language ISO value is in this string pack's language string + // then we are dealing with the strings we want. + // + CopyMem (&Offset, &StringPack->LanguageNameString, sizeof (RELOFST)); + Status = HiiCompareLanguage ((CHAR16 *) ((CHAR8 *) (StringPack) + Offset), Language); + + // + // If we cannot find the lang variable, we skip this check and use the first language available + // + if (LangFound) { + if (EFI_ERROR (Status)) { + StringPack = (EFI_HII_STRING_PACK *) ((CHAR8 *) (StringPack) + Length); + CopyMem (&Length, &StringPack->Header.Length, sizeof (UINT32)); + continue; + } + } + + StringPointer = (RELOFST *) (StringPack + 1); + + // + // We have the right string package - size it, and copy it to the StringBuffer + // + if (Token >= StringPack->NumStringPointers) { + return EFI_INVALID_PARAMETER; + } else { + CopyMem (&Offset, &StringPointer[Token], sizeof (RELOFST)); + } + // + // Since StringPack is a packed structure, we need to determine the string's + // size safely, thus byte-wise. Post-increment the size to include the null-terminator + // + Local = (UINT16 *) ((CHAR8 *) (StringPack) + Offset); + for (Count = 0; CompareMem (&Local[Count], &Zero, 2); Count++) + ; + Count++; + + Count = Count * sizeof (CHAR16);; + + if (*BufferLength >= Count && StringBuffer != NULL) { + // + // Copy the string to the user's buffer + // + if (Raw) { + CopyMem (StringBuffer, Local, Count); + } else { + for (Count = 0; CompareMem (Local, &Zero, 2); Local++) { + // + // Skip "Narraw, Wide, NoBreak" + // + if (CompareMem (Local, &Narrow, 2) && + CompareMem (Local, &Wide, 2) && + CompareMem (Local, &NoBreak, 2)) { + CopyMem (&StringBuffer[Count++], Local, 2); + } + } + // + // Add "NULL" at the end. + // + CopyMem (&StringBuffer[Count], &Zero, 2); + Count++; + Count *= sizeof (CHAR16); + } + + *BufferLength = (UINT16) Count; + return EFI_SUCCESS; + } else { + *BufferLength = (UINT16) Count; + return EFI_BUFFER_TOO_SMALL; + } + + } + + LangFound = FALSE; + goto LangNotFound; +} + +EFI_STATUS +EFIAPI +HiiGetLine ( + IN EFI_HII_PROTOCOL *This, + IN EFI_HII_HANDLE Handle, + IN STRING_REF Token, + IN OUT UINT16 *Index, + IN UINT16 LineWidth, + IN CHAR16 *LanguageString, + IN OUT UINT16 *BufferLength, + OUT EFI_STRING StringBuffer + ) +/*++ + +Routine Description: + + This function allows a program to extract a part of a string of not more than a given width. + With repeated calls, this allows a calling program to extract "lines" of text that fit inside + columns. The effort of measuring the fit of strings inside columns is localized to this call. + +Arguments: + +Returns: + +--*/ +{ + UINTN Count; + EFI_HII_PACKAGE_INSTANCE *PackageInstance; + EFI_HII_PACKAGE_INSTANCE *StringPackageInstance; + EFI_HII_DATA *HiiData; + EFI_HII_HANDLE_DATABASE *HandleDatabase; + EFI_HII_STRING_PACK *StringPack; + RELOFST *StringPointer; + CHAR16 *Location; + EFI_STATUS Status; + UINTN DataSize; + CHAR8 Lang[3]; + CHAR16 Language[3]; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + HiiData = EFI_HII_DATA_FROM_THIS (This); + + HandleDatabase = HiiData->DatabaseHead; + + PackageInstance = NULL; + DataSize = 4; + + // + // Check numeric value against the head of the database + // + for (; HandleDatabase != NULL; HandleDatabase = HandleDatabase->NextHandleDatabase) { + // + // Match the numeric value with the database entry - if matched, extract PackageInstance + // + if (Handle == HandleDatabase->Handle) { + PackageInstance = HandleDatabase->Buffer; + } + } + // + // No handle was found - error condition + // + if (PackageInstance == NULL) { + return EFI_INVALID_PARAMETER; + } + + Status = ValidatePack (This, PackageInstance, &StringPackageInstance, NULL); + + // + // If there is no specified language, assume the system default language + // + if (LanguageString == NULL) { + // + // Get system default language + // + Status = gRT->GetVariable ( + (CHAR16 *) L"Lang", + &gEfiGlobalVariableGuid, + NULL, + &DataSize, + Lang + ); + + if (EFI_ERROR (Status)) { + return Status; + } + // + // Convert the ASCII Lang variable to a Unicode Language variable + // + AsciiToUnicode ((UINT8 *)Lang, Language); + } else { + // + // Copy input ISO value to Language variable + // + CopyMem (Language, LanguageString, 6); + } + // + // Based on if there is IFR data in this package instance, determine + // what the location is of the beginning of the string data. + // + if (StringPackageInstance->IfrSize > 0) { + StringPack = (EFI_HII_STRING_PACK *) ((CHAR8 *) (&StringPackageInstance->IfrData) + StringPackageInstance->IfrSize); + } else { + StringPack = (EFI_HII_STRING_PACK *) (&StringPackageInstance->IfrData); + } + + StringPointer = (RELOFST *) (StringPack + 1); + + // + // There may be multiple instances packed together of strings + // so we must walk the self describing structures until we encounter + // what we are looking for, and then extract the string we are looking for + // + for (; StringPack->Header.Length != 0;) { + // + // If passed in Language ISO value is in this string pack's language string + // then we are dealing with the strings we want. + // + Status = HiiCompareLanguage ((CHAR16 *) ((CHAR8 *) (StringPack) + StringPack->LanguageNameString), Language); + + if (EFI_ERROR (Status)) { + StringPack = (EFI_HII_STRING_PACK *) ((CHAR8 *) (StringPack) + StringPack->Header.Length); + continue; + } + + Location = (CHAR16 *) ((CHAR8 *) (StringPack) + StringPointer[Token] +*Index * 2); + + // + // If the size of the remaining string is less than the LineWidth + // then copy the entire thing + // + if (StrSize (Location) <= LineWidth) { + if (*BufferLength >= StrSize (Location)) { + StrCpy (StringBuffer, Location); + return EFI_SUCCESS; + } else { + *BufferLength = (UINT16) StrSize (Location); + return EFI_BUFFER_TOO_SMALL; + } + } else { + // + // Rewind the string from the maximum size until we see a space the break the line + // + for (Count = LineWidth; Location[Count] != 0x0020; Count--) + ; + + // + // Put the index at the next character + // + *Index = (UINT16) (Count + 1); + + if (*BufferLength >= Count) { + StrnCpy (StringBuffer, Location, Count); + return EFI_SUCCESS; + } else { + *BufferLength = (UINT16) Count; + return EFI_BUFFER_TOO_SMALL; + } + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +HiiCompareLanguage ( + IN CHAR16 *LanguageStringLocation, + IN CHAR16 *Language + ) +{ + UINT8 *Local; + UINTN Index; + CHAR16 *InputString; + CHAR16 *OriginalInputString; + + // + // Allocate a temporary buffer for InputString + // + InputString = AllocateZeroPool (0x100); + + ASSERT (InputString); + + OriginalInputString = InputString; + + Local = (UINT8 *) LanguageStringLocation; + + // + // Determine the size of this packed string safely (e.g. access by byte), post-increment + // to include the null-terminator + // + for (Index = 0; Local[Index] != 0; Index = Index + 2) + ; + // + // MARMAR Index = Index + 2; + // + // This is a packed structure that this location comes from, so let's make sure + // the value is aligned by copying it to a local variable and working on it. + // + CopyMem (InputString, LanguageStringLocation, Index); + + for (Index = 0; Index < 3; Index++) { + InputString[Index] = (CHAR16) (InputString[Index] | 0x20); + Language[Index] = (CHAR16) (Language[Index] | 0x20); + } + // + // If the Language is the same return success + // + if (CompareMem (LanguageStringLocation, Language, 6) == 0) { + gBS->FreePool (InputString); + return EFI_SUCCESS; + } + // + // Skip the first three letters that comprised the primary language, + // see if what is being compared against is a secondary language + // + InputString = InputString + 3; + + // + // If the Language is not the same as the Primary language, see if there are any + // secondary languages, and if there are see if we have a match. If not, return an error. + // + for (Index = 0; InputString[Index] != 0; Index = Index + 3) { + // + // Getting in here means we have a secondary language + // + if (CompareMem (&InputString[Index], Language, 6) == 0) { + gBS->FreePool (InputString); + return EFI_SUCCESS; + } + } + // + // If nothing was found, return the error + // + gBS->FreePool (OriginalInputString); + return EFI_NOT_FOUND; + +} diff --git a/EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/build.xml b/EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/build.xml new file mode 100644 index 0000000000..7ffdb7c013 --- /dev/null +++ b/EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Boolean.c b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Boolean.c new file mode 100644 index 0000000000..c7bcb88fb2 --- /dev/null +++ b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Boolean.c @@ -0,0 +1,1360 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Boolean.c + +Abstract: + + This routine will evaluate the IFR inconsistency data to determine if + something is a valid entry for a particular expression + +--*/ + +#include "Setup.h" +#include "Ui.h" + +// +// Global stack used to evaluate boolean expresions +// +BOOLEAN *mBooleanEvaluationStack = (BOOLEAN) 0; +BOOLEAN *mBooleanEvaluationStackEnd = (BOOLEAN) 0; + +STATIC +VOID +GrowBooleanStack ( + IN OUT BOOLEAN **Stack, + IN UINTN StackSizeInBoolean + ) +/*++ + +Routine Description: + + Grow size of the boolean stack + +Arguments: + + Stack - Old stack on the way in and new stack on the way out + + StackSizeInBoolean - New size of the stack + +Returns: + + NONE + +--*/ +{ + BOOLEAN *NewStack; + + NewStack = AllocatePool (StackSizeInBoolean * sizeof (BOOLEAN)); + ASSERT (NewStack != NULL); + + if (*Stack != NULL) { + // + // Copy to Old Stack to the New Stack + // + CopyMem ( + NewStack, + mBooleanEvaluationStack, + (mBooleanEvaluationStackEnd - mBooleanEvaluationStack) * sizeof (BOOLEAN) + ); + + // + // Make the Stack pointer point to the old data in the new stack + // + *Stack = NewStack + (*Stack - mBooleanEvaluationStack); + + // + // Free The Old Stack + // + gBS->FreePool (mBooleanEvaluationStack); + } + + mBooleanEvaluationStack = NewStack; + mBooleanEvaluationStackEnd = NewStack + StackSizeInBoolean; +} + +VOID +InitializeBooleanEvaluator ( + VOID + ) +/*++ + +Routine Description: + + Allocate a global stack for boolean processing. + +Arguments: + + NONE + +Returns: + + NONE + +--*/ +{ + BOOLEAN *NullStack; + + NullStack = NULL; + GrowBooleanStack (&NullStack, 0x1000); +} + +STATIC +VOID +PushBool ( + IN OUT BOOLEAN **Stack, + IN BOOLEAN BoolResult + ) +/*++ + +Routine Description: + + Push an element onto the Boolean Stack + +Arguments: + + Stack - Current stack location. + BoolResult - BOOLEAN to push. + +Returns: + + None. + +--*/ +{ + CopyMem (*Stack, &BoolResult, sizeof (BOOLEAN)); + *Stack += 1; + + if (*Stack >= mBooleanEvaluationStackEnd) { + // + // If we run out of stack space make a new one that is 2X as big. Copy + // the old data into the new stack and update Stack to point to the old + // data in the new stack. + // + GrowBooleanStack ( + Stack, + (mBooleanEvaluationStackEnd - mBooleanEvaluationStack) * sizeof (BOOLEAN) * 2 + ); + } +} + +STATIC +BOOLEAN +PopBool ( + IN OUT BOOLEAN **Stack + ) +/*++ + +Routine Description: + + Pop an element from the Boolean stack. + +Arguments: + + Stack - Current stack location + +Returns: + + Top of the BOOLEAN stack. + +--*/ +{ + BOOLEAN ReturnValue; + + *Stack -= 1; + CopyMem (&ReturnValue, *Stack, sizeof (BOOLEAN)); + return ReturnValue; +} + +EFI_STATUS +GrowBooleanExpression ( + IN EFI_INCONSISTENCY_DATA *InconsistentTags, + OUT VOID **BooleanExpression, + IN OUT UINTN *BooleanExpressionLength + ) +{ + UINT8 *NewExpression; + + NewExpression = AllocatePool (*BooleanExpressionLength + sizeof (EFI_INCONSISTENCY_DATA)); + ASSERT (NewExpression != NULL); + + if (*BooleanExpression != NULL) { + // + // Copy Old buffer to the New buffer + // + CopyMem (NewExpression, *BooleanExpression, *BooleanExpressionLength); + + CopyMem (&NewExpression[*BooleanExpressionLength], InconsistentTags, sizeof (EFI_INCONSISTENCY_DATA)); + + // + // Free The Old buffer + // + gBS->FreePool (*BooleanExpression); + } else { + // + // Copy data into new buffer + // + CopyMem (NewExpression, InconsistentTags, sizeof (EFI_INCONSISTENCY_DATA)); + } + + *BooleanExpressionLength = *BooleanExpressionLength + sizeof (EFI_INCONSISTENCY_DATA); + *BooleanExpression = (VOID *) NewExpression; + return EFI_SUCCESS; +} + +VOID +CreateBooleanExpression ( + IN EFI_FILE_FORM_TAGS *FileFormTags, + IN UINT16 Value, + IN UINT16 Id, + IN BOOLEAN Complex, + OUT VOID **BooleanExpression, + OUT UINTN *BooleanExpressionLength + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + UINTN Count; + EFI_INCONSISTENCY_DATA *InconsistentTags; + EFI_INCONSISTENCY_DATA FakeInconsistentTags; + + InconsistentTags = FileFormTags->InconsistentTags; + + // + // Did we run into a question that contains the Id we are looking for? + // + for (Count = 0; InconsistentTags->Operand != 0xFF; Count++) { + + // + // Reserve INVALID_OFFSET_VALUE - 1 for TURE and FALSE, because we need to treat them as well + // as ideqid etc. but they have no coresponding id, so we reserve this value. + // + if (InconsistentTags->QuestionId1 == Id || + InconsistentTags->QuestionId1 == INVALID_OFFSET_VALUE - 1) { + // + // If !Complex - means evaluate a single if/endif expression + // + if (!Complex) { + // + // If the ConsistencyId does not match the expression we are looking for + // skip to the next consistency database entry + // + if (InconsistentTags->ConsistencyId != Value) { + goto NextEntry; + } + } + // + // We need to rewind to the beginning of the Inconsistent expression + // + for (; + (InconsistentTags->Operand != EFI_IFR_INCONSISTENT_IF_OP) && + (InconsistentTags->Operand != EFI_IFR_GRAYOUT_IF_OP) && + (InconsistentTags->Operand != EFI_IFR_SUPPRESS_IF_OP); + ) { + InconsistentTags = InconsistentTags->Previous; + } + // + // Store the consistency check expression, ensure the next for loop starts at the op-code afterwards + // + GrowBooleanExpression (InconsistentTags, BooleanExpression, BooleanExpressionLength); + InconsistentTags = InconsistentTags->Next; + + // + // Keep growing until we hit the End expression op-code or we hit the beginning of another + // consistency check like grayout/suppress + // + for (; + InconsistentTags->Operand != EFI_IFR_END_IF_OP && + InconsistentTags->Operand != EFI_IFR_GRAYOUT_IF_OP && + InconsistentTags->Operand != EFI_IFR_SUPPRESS_IF_OP; + ) { + GrowBooleanExpression (InconsistentTags, BooleanExpression, BooleanExpressionLength); + InconsistentTags = InconsistentTags->Next; + } + // + // Store the EndExpression Op-code + // + GrowBooleanExpression (InconsistentTags, BooleanExpression, BooleanExpressionLength); + } + +NextEntry: + if (InconsistentTags->Next != NULL) { + // + // Skip to next entry + // + InconsistentTags = InconsistentTags->Next; + } + } + + FakeInconsistentTags.Operand = 0; + + // + // Add one last expression which will signify we have definitely hit the end + // + GrowBooleanExpression (&FakeInconsistentTags, BooleanExpression, BooleanExpressionLength); +} + +EFI_STATUS +BooleanVariableWorker ( + IN CHAR16 *VariableName, + IN EFI_VARIABLE_DEFINITION *VariableDefinition, + IN BOOLEAN *StackPtr, + IN OUT UINTN *SizeOfVariable, + IN OUT VOID **VariableData + ) +/*++ + +Routine Description: + + +Arguments: + +Returns: + +--*/ +{ + EFI_STATUS Status; + + Status = gRT->GetVariable ( + VariableName, + &VariableDefinition->Guid, + NULL, + SizeOfVariable, + *VariableData + ); + + if (EFI_ERROR (Status)) { + + if (Status == EFI_BUFFER_TOO_SMALL) { + *VariableData = AllocatePool (*SizeOfVariable); + ASSERT (*VariableData != NULL); + + Status = gRT->GetVariable ( + VariableName, + &VariableDefinition->Guid, + NULL, + SizeOfVariable, + *VariableData + ); + } + + if (Status == EFI_NOT_FOUND) { + // + // This is a serious flaw, we must have some standard result if a variable + // is not found. Our default behavior must either be return a TRUE or FALSE + // since there is nothing else we can really do. Therefore, my crystal ball + // says I will return a FALSE + // + PushBool (&StackPtr, FALSE); + } + } + + return Status; +} + +UINT8 +PredicateIfrType ( + IN EFI_INCONSISTENCY_DATA *Iterator + ) +/*++ + +Routine Description: + This routine is for the purpose of predicate whether the Ifr is generated by a VfrCompiler greater than or equal to 1.88 or + less than 1.88 which is legacy. + +Arguments: + Iterator - The pointer to inconsistency tags + +Returns: + + 0x2 - If IFR is not legacy + + 0x1 - If IFR is legacy + +--*/ +{ + // + // legacy Ifr cover the states: + // Not ... + // Operand Opcode Operand + // + // while Operand means ideqval, TRUE, or other what can be evaluated to True or False, + // and Opcode means AND or OR. + // + if (Iterator->Operand == EFI_IFR_NOT_OP || + Iterator->Operand == 0) { + return 0x1; + } else if (Iterator->Operand == EFI_IFR_EQ_VAR_VAL_OP || + Iterator->Operand == EFI_IFR_EQ_ID_VAL_OP || + Iterator->Operand == EFI_IFR_EQ_ID_ID_OP || + Iterator->Operand == EFI_IFR_EQ_ID_LIST_OP) { + Iterator++; + if (Iterator->Operand == EFI_IFR_AND_OP || + Iterator->Operand == EFI_IFR_OR_OP) { + Iterator--; + return 0x1; + } + Iterator--; + } + return 0x2; +} + +VOID +PostOrderEvaluate ( + IN EFI_FILE_FORM_TAGS *FileFormTags, + IN UINT16 Width, + IN OUT EFI_INCONSISTENCY_DATA **PIterator, + IN OUT BOOLEAN **StackPtr + ) +/*++ + +Routine Description: + PostOrderEvaluate is used for Ifr generated by VfrCompiler greater than or equal to 1.88, + which generate Operand Operand Opcode type Ifr. + PostOrderEvaluete only evaluate boolean expression part, not suppressif/grayoutif. TRUE, + FALSE, >=, >, (, ) are supported. + +Arguments: + + FileFormTags - The pointer to the tags of the form + + Width - Width of Operand, recognized every iteration + + PIterator - The pointer to inconsistency tags + + StackPtr - The pointer to the evaluation stack + +Returns: + + TRUE - If value is valid + + FALSE - If value is not valid + +--*/ +{ + BOOLEAN Operator; + BOOLEAN Operator2; + UINT16 *MapBuffer; + UINT16 *MapBuffer2; + UINT16 MapValue; + UINT16 MapValue2; + UINTN SizeOfVariable; + CHAR16 VariableName[40]; + VOID *VariableData; + EFI_VARIABLE_DEFINITION *VariableDefinition; + EFI_STATUS Status; + UINTN Index; + BOOLEAN PushValue; + + Operator = FALSE; + Operator2 = FALSE; + MapBuffer = NULL; + MapBuffer2 = NULL; + MapValue = 0; + MapValue2 = 0; + VariableData = NULL; + + while (TRUE) { + if ((*PIterator)->Operand == 0) { + return; + } + + Width = (*PIterator)->Width; + + // + // Because INVALID_OFFSET_VALUE - 1 is reserved for TRUE or FALSE, omit them. + // + if ((*PIterator)->QuestionId1 != INVALID_OFFSET_VALUE && + (*PIterator)->QuestionId1 != INVALID_OFFSET_VALUE - 1) { + ExtractNvValue (FileFormTags, (*PIterator)->VariableNumber, Width, (*PIterator)->QuestionId1, (VOID **) &MapBuffer); + ExtractNvValue (FileFormTags, (*PIterator)->VariableNumber2, Width, (*PIterator)->QuestionId2, (VOID **) &MapBuffer2); + if (MapBuffer != NULL) { + if (Width == 2) { + MapValue = *MapBuffer; + } else { + MapValue = (UINT8) *MapBuffer; + } + + gBS->FreePool (MapBuffer); + } + + if (MapBuffer2 != NULL) { + if (Width == 2) { + MapValue2 = *MapBuffer2; + } else { + MapValue2 = (UINT8) *MapBuffer2; + } + + gBS->FreePool (MapBuffer2); + } + } + + switch ((*PIterator)->Operand) { + case EFI_IFR_EQ_VAR_VAL_OP: + UnicodeValueToString ( + VariableName, + FALSE, + (UINTN) (*PIterator)->QuestionId1, + (sizeof (VariableName) / sizeof (VariableName[0])) + ); + + SizeOfVariable = 0; + + ExtractRequestedNvMap (FileFormTags, (*PIterator)->VariableNumber, &VariableDefinition); + + Status = BooleanVariableWorker ( + VariableName, + VariableDefinition, + *StackPtr, + &SizeOfVariable, + &VariableData + ); + + if (!EFI_ERROR (Status)) { + if (SizeOfVariable == 1) { + CopyMem (&MapValue, VariableData, 1); + } else { + CopyMem (&MapValue, VariableData, 2); + } + + // + // Do operation after knowing the compare operator. + // + MapValue2 = (*PIterator)->Value; + (*PIterator)++; + if ((*PIterator)->Operand == EFI_IFR_GT_OP) { + PushValue = (BOOLEAN) (MapValue > MapValue2); + } else if ((*PIterator)->Operand == EFI_IFR_GE_OP) { + PushValue = (BOOLEAN) (MapValue >= MapValue2); + } else { + (*PIterator)--; + PushValue = (BOOLEAN) (MapValue == MapValue2); + } + PushBool (StackPtr, PushValue); + } + + break; + + case EFI_IFR_EQ_ID_VAL_OP: + // + // Do operation after knowing the compare operator. + // + MapValue2 = (*PIterator)->Value; + (*PIterator)++; + if ((*PIterator)->Operand == EFI_IFR_GT_OP) { + PushValue = (BOOLEAN) (MapValue > MapValue2); + } else if ((*PIterator)->Operand == EFI_IFR_GE_OP) { + PushValue = (BOOLEAN) (MapValue >= MapValue2); + } else { + (*PIterator)--; + PushValue = (BOOLEAN) (MapValue == MapValue2); + } + PushBool (StackPtr, PushValue); + break; + + case EFI_IFR_EQ_ID_ID_OP: + // + // Do operation after knowing the compare operator. + // + (*PIterator)++; + if ((*PIterator)->Operand == EFI_IFR_GT_OP) { + PushValue = (BOOLEAN) (MapValue > MapValue2); + } else if ((*PIterator)->Operand == EFI_IFR_GE_OP) { + PushValue = (BOOLEAN) (MapValue >= MapValue2); + } else { + (*PIterator)--; + PushValue = (BOOLEAN) (MapValue == MapValue2); + } + PushBool (StackPtr, PushValue); + break; + + case EFI_IFR_EQ_ID_LIST_OP: + for (Index = 0; Index < (*PIterator)->ListLength; Index++) { + Operator = (BOOLEAN) (MapValue == (*PIterator)->ValueList[Index]); + if (Operator) { + break; + } + } + + PushBool (StackPtr, Operator); + break; + + case EFI_IFR_TRUE_OP: + PushBool (StackPtr, TRUE); + break; + + case EFI_IFR_FALSE_OP: + PushBool (StackPtr, FALSE); + break; + + case EFI_IFR_AND_OP: + Operator = PopBool (StackPtr); + Operator2 = PopBool (StackPtr); + PushBool (StackPtr, (BOOLEAN) (Operator && Operator2)); + break; + case EFI_IFR_OR_OP: + Operator = PopBool (StackPtr); + Operator2 = PopBool (StackPtr); + PushBool (StackPtr, (BOOLEAN) (Operator || Operator2)); + break; + case EFI_IFR_NOT_OP: + Operator = PopBool (StackPtr); + PushBool (StackPtr, !Operator); + break; + + case EFI_IFR_SUPPRESS_IF_OP: + case EFI_IFR_GRAYOUT_IF_OP: + case EFI_IFR_INCONSISTENT_IF_OP: + default: + // + // Return to the previous tag if runs out of boolean expression. + // + (*PIterator)--; + return; + } + (*PIterator)++; + } +} + +BOOLEAN +ValueIsNotValid ( + IN BOOLEAN Complex, + IN UINT16 Value, + IN EFI_TAG *Tag, + IN EFI_FILE_FORM_TAGS *FileFormTags, + IN STRING_REF *PopUp + ) +/*++ + +Routine Description: + + +Arguments: + +Returns: + + TRUE - If value is valid + + FALSE - If value is not valid + +--*/ +{ + BOOLEAN *StackPtr; + EFI_INCONSISTENCY_DATA *Iterator; + BOOLEAN Operator; + BOOLEAN Operator2; + UINTN Index; + VOID *BooleanExpression; + UINTN BooleanExpressionLength; + BOOLEAN NotOperator; + BOOLEAN OrOperator; + BOOLEAN AndOperator; + BOOLEAN ArtificialEnd; + UINT16 *MapBuffer; + UINT16 *MapBuffer2; + UINT16 MapValue; + UINT16 MapValue2; + UINTN SizeOfVariable; + CHAR16 VariableName[40]; + VOID *VariableData; + EFI_STATUS Status; + UINT16 Id; + UINT16 Width; + EFI_VARIABLE_DEFINITION *VariableDefinition; + BOOLEAN CosmeticConsistency; + UINT8 IsLegacy; + + VariableData = NULL; + BooleanExpressionLength = 0; + BooleanExpression = NULL; + Operator = FALSE; + ArtificialEnd = FALSE; + CosmeticConsistency = TRUE; + IsLegacy = 0; + + Id = Tag->Id; + if (Tag->StorageWidth == 1) { + Width = 1; + } else { + Width = 2; + } + CreateBooleanExpression (FileFormTags, Value, Id, Complex, &BooleanExpression, &BooleanExpressionLength); + + if (mBooleanEvaluationStack == 0) { + InitializeBooleanEvaluator (); + } + + if (BooleanExpression == NULL) { + return FALSE; + } + + StackPtr = mBooleanEvaluationStack; + Iterator = BooleanExpression; + MapBuffer = NULL; + MapBuffer2 = NULL; + MapValue = 0; + MapValue2 = 0; + + while (TRUE) { + NotOperator = FALSE; + OrOperator = FALSE; + AndOperator = FALSE; + + if (Iterator->Operand == 0) { + return Operator; + } + + // + // Because INVALID_OFFSET_VALUE - 1 is reserved for TRUE or FALSE, omit them. + // + if (Iterator->QuestionId1 != INVALID_OFFSET_VALUE && + Iterator->QuestionId1 != INVALID_OFFSET_VALUE-1) { + ExtractNvValue (FileFormTags, Iterator->VariableNumber, Width, Iterator->QuestionId1, (VOID **) &MapBuffer); + ExtractNvValue (FileFormTags, Iterator->VariableNumber2, Width, Iterator->QuestionId2, (VOID **) &MapBuffer2); + if (MapBuffer != NULL) { + if (Width == 2) { + MapValue = *MapBuffer; + } else { + MapValue = (UINT8) *MapBuffer; + } + + gBS->FreePool (MapBuffer); + } + + if (MapBuffer2 != NULL) { + if (Width == 2) { + MapValue2 = *MapBuffer2; + } else { + MapValue2 = (UINT8) *MapBuffer2; + } + + gBS->FreePool (MapBuffer2); + } + } + + switch (Iterator->Operand) { + case EFI_IFR_SUPPRESS_IF_OP: + // + // Must have hit a suppress followed by a grayout or vice-versa + // + if (ArtificialEnd) { + ArtificialEnd = FALSE; + Operator = PopBool (&StackPtr); + if (Operator) { + Tag->Suppress = TRUE; + } + + return Operator; + } + + ArtificialEnd = TRUE; + *PopUp = Iterator->Popup; + break; + + case EFI_IFR_GRAYOUT_IF_OP: + // + // Must have hit a suppress followed by a grayout or vice-versa + // + if (ArtificialEnd) { + ArtificialEnd = FALSE; + Operator = PopBool (&StackPtr); + if (Operator) { + Tag->GrayOut = TRUE; + } + + return Operator; + } + + ArtificialEnd = TRUE; + *PopUp = Iterator->Popup; + break; + + case EFI_IFR_INCONSISTENT_IF_OP: + CosmeticConsistency = FALSE; + *PopUp = Iterator->Popup; + break; + + // + // In the case of external variable values, we must read the variable which is + // named by the human readable version of the OpCode->VariableId and the guid of the formset + // + case EFI_IFR_EQ_VAR_VAL_OP: + // + // To check whether Ifr is legacy. Once every boolean expression. + // + if (IsLegacy == 0) { + IsLegacy = PredicateIfrType (Iterator); + } + if (IsLegacy == 0x2) { + PostOrderEvaluate (FileFormTags, Width, &Iterator, &StackPtr); + break; + } + + UnicodeValueToString ( + VariableName, + FALSE, + (UINTN) Iterator->QuestionId1, + (sizeof (VariableName) / sizeof (VariableName[0])) + ); + + SizeOfVariable = 0; + + ExtractRequestedNvMap (FileFormTags, Iterator->VariableNumber, &VariableDefinition); + + Status = BooleanVariableWorker ( + VariableName, + VariableDefinition, + StackPtr, + &SizeOfVariable, + &VariableData + ); + + if (!EFI_ERROR (Status)) { + if (SizeOfVariable == 1) { + CopyMem (&MapValue, VariableData, 1); + } else { + CopyMem (&MapValue, VariableData, 2); + } + + PushBool (&StackPtr, (BOOLEAN) (MapValue == Iterator->Value)); + } + + break; + + case EFI_IFR_EQ_ID_VAL_OP: + // + // To check whether Ifr is legacy. Once every boolean expression. + // + if (IsLegacy == 0) { + IsLegacy = PredicateIfrType (Iterator); + } + if (IsLegacy == 0x2) { + PostOrderEvaluate (FileFormTags, Width, &Iterator, &StackPtr); + break; + } + + PushBool (&StackPtr, (BOOLEAN) (MapValue == Iterator->Value)); + break; + + case EFI_IFR_EQ_ID_ID_OP: + // + // To check whether Ifr is legacy. Once every boolean expression. + // + if (IsLegacy == 0) { + IsLegacy = PredicateIfrType (Iterator); + } + if (IsLegacy == 0x2) { + PostOrderEvaluate (FileFormTags, Width, &Iterator, &StackPtr); + break; + } + + PushBool (&StackPtr, (BOOLEAN) (MapValue == MapValue2)); + break; + + case EFI_IFR_EQ_ID_LIST_OP: + // + // To check whether Ifr is legacy. Once every boolean expression. + // + if (IsLegacy == 0) { + IsLegacy = PredicateIfrType (Iterator); + } + if (IsLegacy == 0x2) { + PostOrderEvaluate (FileFormTags, Width, &Iterator, &StackPtr); + break; + } + + for (Index = 0; Index < Iterator->ListLength; Index++) { + Operator = (BOOLEAN) (MapValue == Iterator->ValueList[Index]); + if (Operator) { + break; + } + } + + PushBool (&StackPtr, Operator); + break; + + case EFI_IFR_AND_OP: + Iterator++; + if (Iterator->Operand == EFI_IFR_NOT_OP) { + NotOperator = TRUE; + Iterator++; + } + + if (Iterator->QuestionId1 != INVALID_OFFSET_VALUE) { + ExtractNvValue (FileFormTags, Iterator->VariableNumber, Width, Iterator->QuestionId1, (VOID **) &MapBuffer); + ExtractNvValue (FileFormTags, Iterator->VariableNumber2, Width, Iterator->QuestionId2, (VOID **) &MapBuffer2); + if (MapBuffer != NULL) { + if (Width == 2) { + MapValue = *MapBuffer; + } else { + MapValue = (UINT8) *MapBuffer; + } + + gBS->FreePool (MapBuffer); + } + + if (MapBuffer2 != NULL) { + if (Width == 2) { + MapValue2 = *MapBuffer2; + } else { + MapValue2 = (UINT8) *MapBuffer2; + } + + gBS->FreePool (MapBuffer2); + } + } + + switch (Iterator->Operand) { + case EFI_IFR_EQ_ID_VAL_OP: + // + // If Not - flip the results + // + if (NotOperator) { + Operator = (BOOLEAN)!(MapValue == Iterator->Value); + } else { + Operator = (BOOLEAN) (MapValue == Iterator->Value); + } + + PushBool (&StackPtr, Operator); + break; + + // + // In the case of external variable values, we must read the variable which is + // named by the human readable version of the OpCode->VariableId and the guid of the formset + // + case EFI_IFR_EQ_VAR_VAL_OP: + UnicodeValueToString ( + VariableName, + FALSE, + (UINTN) Iterator->QuestionId1, + (sizeof (VariableName) / sizeof (VariableName[0])) + ); + + SizeOfVariable = 0; + + ExtractRequestedNvMap (FileFormTags, Iterator->VariableNumber, &VariableDefinition); + + Status = BooleanVariableWorker ( + VariableName, + VariableDefinition, + StackPtr, + &SizeOfVariable, + &VariableData + ); + + if (!EFI_ERROR (Status)) { + if (SizeOfVariable == 1) { + CopyMem (&MapValue, VariableData, 1); + } else { + CopyMem (&MapValue, VariableData, 2); + } + // + // If Not - flip the results + // + if (NotOperator) { + PushBool (&StackPtr, (BOOLEAN)!(MapValue == Iterator->Value)); + } else { + PushBool (&StackPtr, (BOOLEAN) (MapValue == Iterator->Value)); + } + } + break; + + case EFI_IFR_EQ_ID_ID_OP: + // + // If Not - flip the results + // + if (NotOperator) { + Operator = (BOOLEAN)!(MapValue == MapValue2); + } else { + Operator = (BOOLEAN) (MapValue == MapValue2); + } + + PushBool (&StackPtr, Operator); + break; + + case EFI_IFR_EQ_ID_LIST_OP: + for (Index = 0; Index < Iterator->ListLength; Index++) { + // + // If Not - flip the results + // + if (NotOperator) { + Operator = (BOOLEAN)!(MapValue == Iterator->ValueList[Index]); + } else { + Operator = (BOOLEAN) (MapValue == Iterator->ValueList[Index]); + } + // + // If We are trying to make sure that MapValue != Item[x], keep looking through + // the list to make sure we don't equal any other items + // + if (Operator && NotOperator) { + continue; + } + // + // If MapValue == Item, then we have succeeded (first found is good enough) + // + if (Operator) { + break; + } + } + + PushBool (&StackPtr, Operator); + break; + + default: + return FALSE; + } + + Operator = PopBool (&StackPtr); + Operator2 = PopBool (&StackPtr); + PushBool (&StackPtr, (BOOLEAN) (Operator && Operator2)); + break; + + case EFI_IFR_OR_OP: + Iterator++; + if (Iterator->Operand == EFI_IFR_NOT_OP) { + NotOperator = TRUE; + Iterator++; + } + + if (Iterator->QuestionId1 != INVALID_OFFSET_VALUE) { + ExtractNvValue (FileFormTags, Iterator->VariableNumber, Width, Iterator->QuestionId1, (VOID **) &MapBuffer); + ExtractNvValue (FileFormTags, Iterator->VariableNumber2, Width, Iterator->QuestionId2, (VOID **) &MapBuffer2); + if (MapBuffer != NULL) { + if (Width == 2) { + MapValue = *MapBuffer; + } else { + MapValue = (UINT8) *MapBuffer; + } + + gBS->FreePool (MapBuffer); + } + + if (MapBuffer2 != NULL) { + if (Width == 2) { + MapValue2 = *MapBuffer2; + } else { + MapValue2 = (UINT8) *MapBuffer2; + } + + gBS->FreePool (MapBuffer2); + } + } + + switch (Iterator->Operand) { + case EFI_IFR_EQ_ID_VAL_OP: + // + // If Not - flip the results + // + if (NotOperator) { + Operator = (BOOLEAN)!(MapValue == Iterator->Value); + } else { + Operator = (BOOLEAN) (MapValue == Iterator->Value); + } + + PushBool (&StackPtr, Operator); + break; + + // + // In the case of external variable values, we must read the variable which is + // named by the human readable version of the OpCode->VariableId and the guid of the formset + // + case EFI_IFR_EQ_VAR_VAL_OP: + UnicodeValueToString ( + VariableName, + FALSE, + (UINTN) Iterator->QuestionId1, + (sizeof (VariableName) / sizeof (VariableName[0])) + ); + + SizeOfVariable = 0; + + ExtractRequestedNvMap (FileFormTags, Iterator->VariableNumber, &VariableDefinition); + + Status = BooleanVariableWorker ( + VariableName, + VariableDefinition, + StackPtr, + &SizeOfVariable, + &VariableData + ); + + if (!EFI_ERROR (Status)) { + if (SizeOfVariable == 1) { + CopyMem (&MapValue, VariableData, 1); + } else { + CopyMem (&MapValue, VariableData, 2); + } + // + // If Not - flip the results + // + if (NotOperator) { + PushBool (&StackPtr, (BOOLEAN)!(MapValue == Iterator->Value)); + } else { + PushBool (&StackPtr, (BOOLEAN) (MapValue == Iterator->Value)); + } + } + break; + + case EFI_IFR_EQ_ID_ID_OP: + // + // If Not - flip the results + // + if (NotOperator) { + Operator = (BOOLEAN)!(MapValue == MapValue2); + } else { + Operator = (BOOLEAN) (MapValue == MapValue2); + } + + PushBool (&StackPtr, Operator); + break; + + case EFI_IFR_EQ_ID_LIST_OP: + for (Index = 0; Index < Iterator->ListLength; Index++) { + // + // If Not - flip the results + // + if (NotOperator) { + Operator = (BOOLEAN)!(MapValue == Iterator->ValueList[Index]); + } else { + Operator = (BOOLEAN) (MapValue == Iterator->ValueList[Index]); + } + // + // If We are trying to make sure that MapValue != Item[x], keep looking through + // the list to make sure we don't equal any other items + // + if (Operator && NotOperator) { + continue; + } + // + // If MapValue == Item, then we have succeeded (first found is good enough) + // + if (Operator) { + break; + } + } + + PushBool (&StackPtr, Operator); + break; + + default: + return FALSE; + } + + Operator = PopBool (&StackPtr); + Operator2 = PopBool (&StackPtr); + PushBool (&StackPtr, (BOOLEAN) (Operator || Operator2)); + break; + + case EFI_IFR_NOT_OP: + // + // To check whether Ifr is legacy. Once every boolean expression. + // + if (IsLegacy == 0) { + IsLegacy = PredicateIfrType (Iterator); + } + if (IsLegacy == 0x2) { + PostOrderEvaluate (FileFormTags, Width, &Iterator, &StackPtr); + break; + } + + // + // I don't need to set the NotOperator (I know that I have to NOT this in this case + // + Iterator++; + + if (Iterator->Operand == EFI_IFR_OR_OP) { + OrOperator = TRUE; + Iterator++; + } + + if (Iterator->Operand == EFI_IFR_AND_OP) { + AndOperator = TRUE; + Iterator++; + } + + if (Iterator->QuestionId1 != INVALID_OFFSET_VALUE) { + ExtractNvValue (FileFormTags, Iterator->VariableNumber, Width, Iterator->QuestionId1, (VOID **) &MapBuffer); + ExtractNvValue (FileFormTags, Iterator->VariableNumber2, Width, Iterator->QuestionId2, (VOID **) &MapBuffer2); + if (MapBuffer != NULL) { + if (Width == 2) { + MapValue = *MapBuffer; + } else { + MapValue = (UINT8) *MapBuffer; + } + + gBS->FreePool (MapBuffer); + } + + if (MapBuffer2 != NULL) { + if (Width == 2) { + MapValue2 = *MapBuffer2; + } else { + MapValue2 = (UINT8) *MapBuffer2; + } + + gBS->FreePool (MapBuffer2); + } + } + + switch (Iterator->Operand) { + case EFI_IFR_EQ_ID_VAL_OP: + Operator = (BOOLEAN)!(MapValue == Iterator->Value); + PushBool (&StackPtr, Operator); + break; + + // + // In the case of external variable values, we must read the variable which is + // named by the human readable version of the OpCode->VariableId and the guid of the formset + // + case EFI_IFR_EQ_VAR_VAL_OP: + UnicodeValueToString ( + VariableName, + FALSE, + (UINTN) Iterator->QuestionId1, + (sizeof (VariableName) / sizeof (VariableName[0])) + ); + + SizeOfVariable = 0; + + ExtractRequestedNvMap (FileFormTags, Iterator->VariableNumber, &VariableDefinition); + + Status = BooleanVariableWorker ( + VariableName, + VariableDefinition, + StackPtr, + &SizeOfVariable, + &VariableData + ); + + if (!EFI_ERROR (Status)) { + if (SizeOfVariable == 1) { + CopyMem (&MapValue, VariableData, 1); + } else { + CopyMem (&MapValue, VariableData, 2); + } + + PushBool (&StackPtr, (BOOLEAN)!(MapValue == Iterator->Value)); + } + break; + + case EFI_IFR_EQ_ID_ID_OP: + Operator = (BOOLEAN)!(MapValue == MapValue2); + PushBool (&StackPtr, Operator); + break; + + case EFI_IFR_EQ_ID_LIST_OP: + for (Index = 0; Index < Iterator->ListLength; Index++) { + Operator = (BOOLEAN)!(MapValue == Iterator->ValueList[Index]); + if (Operator) { + continue; + } + } + + PushBool (&StackPtr, Operator); + break; + + default: + return FALSE; + } + + Operator = PopBool (&StackPtr); + Operator2 = PopBool (&StackPtr); + + if (OrOperator) { + PushBool (&StackPtr, (BOOLEAN) (Operator || Operator2)); + } + + if (AndOperator) { + PushBool (&StackPtr, (BOOLEAN) (Operator && Operator2)); + } + + if (!OrOperator && !AndOperator) { + PushBool (&StackPtr, Operator); + } + break; + + case EFI_IFR_TRUE_OP: + // + // To check whether Ifr is legacy. Once every boolean expression. + // + if (IsLegacy == 0) { + IsLegacy = PredicateIfrType (Iterator); + } + if (IsLegacy == 0x2) { + PostOrderEvaluate (FileFormTags, Width, &Iterator, &StackPtr); + break; + } + break; + + case EFI_IFR_FALSE_OP: + // + // To check whether Ifr is legacy. Once every boolean expression. + // + if (IsLegacy == 0) { + IsLegacy = PredicateIfrType (Iterator); + } + if (IsLegacy == 0x2) { + PostOrderEvaluate (FileFormTags, Width, &Iterator, &StackPtr); + break; + } + break; + + case EFI_IFR_END_IF_OP: + Operator = PopBool (&StackPtr); + // + // If there is an error, return, otherwise keep looking - there might + // be another test that causes an error + // + if (Operator) { + if (Complex && CosmeticConsistency) { + return EFI_SUCCESS; + } else { + return Operator; + } + } else { + // + // If not doing a global consistency check, the endif is the REAL terminator of this operation + // This is used for grayout/suppress operations. InconsistentIf is a global operation so the EndIf is + // not the end-all be-all of terminators. + // + if (!Complex) { + return Operator; + } + break; + } + + default: + // + // Must have hit a non-consistency related op-code after a suppress/grayout + // + if (ArtificialEnd) { + ArtificialEnd = FALSE; + Operator = PopBool (&StackPtr); + return Operator; + } + + return FALSE; + } + + Iterator++; + } + + return FALSE; +} diff --git a/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Colors.h b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Colors.h new file mode 100644 index 0000000000..c1f5441432 --- /dev/null +++ b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Colors.h @@ -0,0 +1,54 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Colors.h + +Abstract: + + +Revision History + +--*/ + +#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_TEXT EFI_BLUE +#define SUBTITLE_BACKGROUND EFI_BACKGROUND_LIGHTGRAY +#define BANNER_TEXT EFI_BLUE +#define BANNER_BACKGROUND EFI_BACKGROUND_LIGHTGRAY +#define FIELD_TEXT EFI_BLACK +#define FIELD_TEXT_GRAYED EFI_DARKGRAY +#define FIELD_BACKGROUND EFI_BACKGROUND_LIGHTGRAY +#define FIELD_TEXT_HIGHLIGHT EFI_LIGHTGRAY +#define FIELD_BACKGROUND_HIGHLIGHT EFI_BACKGROUND_BLACK +#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/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/DriverSample.c b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/DriverSample.c new file mode 100644 index 0000000000..5f3823c612 --- /dev/null +++ b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/DriverSample.c @@ -0,0 +1,631 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + DriverSample.c + +Abstract: + + This is an example of how a driver might export data to the HII protocol to be + later utilized by the Setup Protocol + +--*/ + +#include "DriverSample.h" + +#define DISPLAY_ONLY_MY_ITEM 0x0001 + +#define STRING_PACK_GUID \ + { \ + 0x8160a85f, 0x934d, 0x468b, { 0xa2, 0x35, 0x72, 0x89, 0x59, 0x14, 0xf6, 0xfc } \ + } + +EFI_GUID mFormSetGuid = FORMSET_GUID; +EFI_GUID mStringPackGuid = STRING_PACK_GUID; + +EFI_STATUS +EFIAPI +DriverCallback ( + IN EFI_FORM_CALLBACK_PROTOCOL *This, + IN UINT16 KeyValue, + IN EFI_IFR_DATA_ARRAY *Data, + OUT EFI_HII_CALLBACK_PACKET **Packet + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + KeyValue - 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 op-code that geerated the callback. + + Data - A pointer to the data being sent to the original exporting driver. + +Returns: + +--*/ +{ + EFI_CALLBACK_INFO *Private; + EFI_HII_UPDATE_DATA *UpdateData; + EFI_STATUS Status; + UINT8 *Location; + EFI_HII_CALLBACK_PACKET *DataPacket; + UINT16 Value; + CHAR16 VariableName[40]; + STATIC UINT16 QuestionId = 0; + IFR_OPTION *OptionList; + UINTN Index; + MyIfrNVData NVStruc; + + Private = EFI_CALLBACK_INFO_FROM_THIS (This); + + // + // This should tell me the first offset AFTER the end of the compiled NV map + // If op-code results are not going to be saved to NV locations ensure the QuestionId + // is beyond the end of the NVRAM mapping. + // + if (QuestionId == 0) { + QuestionId = sizeof (MyIfrNVData); + } + + ZeroMem (VariableName, (sizeof (CHAR16) * 40)); + + switch (KeyValue) { + case 0x0001: + // + // Create a small boot order list + // + QuestionId = (UINT16) ((UINTN) (&NVStruc.BootOrder) - (UINTN) (&NVStruc)); + + // + // Need some memory for OptionList. Allow for up to 8 options. + // + OptionList = AllocateZeroPool (sizeof (IFR_OPTION) * 8); + + // + // Allocate space for creation of Buffer + // + UpdateData = AllocateZeroPool (0x1000); + + // + // Remove all the op-codes starting with Label 0x2222 to next Label (second label is for convenience + // so we don't have to keep track of how many op-codes we added or subtracted. The rules for removal + // of op-codes are simply that the removal will always stop as soon as a label or the end of a form is + // encountered. Therefore, giving a large obnoxious count such as below takes care of other complexities. + // + UpdateData->DataCount = 0xFF; + + // + // Delete set of op-codes + // + Private->Hii->UpdateForm ( + Private->Hii, + Private->RegisteredHandle, + (EFI_FORM_LABEL) 0x2222, + FALSE, // If we aren't adding, we are deleting + UpdateData + ); + + // + // Create 3 options + // + for (Index = 0; Index < 3; Index++) { + OptionList[Index].StringToken = (UINT16) (STR_BOOT_OPTION1 + Index); + OptionList[Index].Value = (UINT16) (Index + 1); + OptionList[Index].Flags = RESET_REQUIRED; + } + + CreateOrderedListOpCode ( + QuestionId, // Question ID + 8, // Max Entries + (UINT16) STRING_TOKEN (STR_BOOT_OPTIONS), // Token value for the Prompt + (UINT16) STRING_TOKEN (STR_NULL_STRING), // Token value for the Help + OptionList, + 3, + &UpdateData->Data // Buffer location to place op-codes + ); + + // + // For one-of/ordered lists commands, they really consist of 2 op-codes (a header and a footer) + // Each option within a one-of/ordered list is also an op-code + // So this example has 5 op-codes it is adding since we have a one-of header + 3 options + one-of footer + // + UpdateData->DataCount = 0x5; + + // + // Add one op-code + // + Private->Hii->UpdateForm ( + Private->Hii, + Private->RegisteredHandle, + (EFI_FORM_LABEL) 0x2222, + TRUE, + UpdateData + ); + + gBS->FreePool (UpdateData); + gBS->FreePool (OptionList); + break; + + case 0x0002: + // + // Create a large boot order list + // + QuestionId = (UINT16) ((UINTN) (&NVStruc.BootOrder) - (UINTN) (&NVStruc)); + + // + // Need some memory for OptionList. Allow for up to 8 options. + // + OptionList = AllocateZeroPool (sizeof (IFR_OPTION) * 8); + + // + // Allocate space for creation of Buffer + // + UpdateData = AllocateZeroPool (0x1000); + + // + // Remove all the op-codes starting with Label 0x2222 to next Label (second label is for convenience + // so we don't have to keep track of how many op-codes we added or subtracted + // + UpdateData->DataCount = 0xFF; + + // + // Delete one op-code + // + Private->Hii->UpdateForm ( + Private->Hii, + Private->RegisteredHandle, + (EFI_FORM_LABEL) 0x2222, + FALSE, + UpdateData + ); + + // + // Create 4 options + // + for (Index = 0; Index < 4; Index++) { + OptionList[Index].StringToken = (UINT16) (STR_BOOT_OPTION1 + Index); + OptionList[Index].Value = (UINT16) (Index + 1); + OptionList[Index].Flags = RESET_REQUIRED; + } + + CreateOrderedListOpCode ( + QuestionId, // Question ID + 8, // Max Entries + (UINT16) STRING_TOKEN (STR_BOOT_OPTIONS), // Token value for the Prompt + (UINT16) STRING_TOKEN (STR_NULL_STRING), // Token value for the Help + OptionList, + 4, + &UpdateData->Data // Buffer location to place op-codes + ); + + // + // For one-of commands, they really consist of 2 op-codes (a header and a footer) + // Each option within a one-of is also an op-code + // So this example has 6 op-codes it is adding since we have a one-of header + 4 options + one-of footer + // + UpdateData->DataCount = 0x6; + + // + // Add one op-code + // + Private->Hii->UpdateForm ( + Private->Hii, + Private->RegisteredHandle, + (EFI_FORM_LABEL) 0x2222, + TRUE, + UpdateData + ); + + gBS->FreePool (UpdateData); + gBS->FreePool (OptionList); + break; + + case 0x1234: + // + // Allocate space for creation of Buffer + // + QuestionId = (UINT16) ((UINTN) (&NVStruc.DynamicCheck)); + Status = gBS->AllocatePool ( + EfiBootServicesData, + 0x1000, + (VOID **) &UpdateData + ); + + ZeroMem (UpdateData, 0x1000); + + Location = (UINT8 *) &UpdateData->Data; + + UpdateData->FormSetUpdate = TRUE; + UpdateData->FormCallbackHandle = (EFI_PHYSICAL_ADDRESS) (UINTN) Private->CallbackHandle; + UpdateData->FormUpdate = FALSE; + UpdateData->FormTitle = 0; + UpdateData->DataCount = 2; + + CreateGotoOpCode ( + 1, + STR_GOTO_FORM1, // Token value for the Prompt + 0, // Goto Help + 0, // Flags + 0, // Key + &UpdateData->Data // Buffer location to place op-codes + ); + + Location = Location + ((EFI_IFR_OP_HEADER *) &UpdateData->Data)->Length; + + CreateCheckBoxOpCode ( + QuestionId, // Question ID + 1, // Data width (BOOLEAN = 1) + (UINT16) STRING_TOKEN (STR_CHECK_DYNAMIC_PROMPT), // Token value for the Prompt + (UINT16) STRING_TOKEN (STR_CHECK_DYNAMIC_HELP), // Token value for the Help + EFI_IFR_FLAG_INTERACTIVE, // Flags + 0x1236, // Key + Location // Buffer location to place op-codes + ); + + Private->Hii->UpdateForm ( + Private->Hii, + Private->RegisteredHandle, + (EFI_FORM_LABEL) 0x1234, + TRUE, + UpdateData + ); + + gBS->FreePool (UpdateData); + QuestionId++; + break; + + case 0x1235: + // + // Allocate space for creation of Buffer + // + Status = gBS->AllocatePool ( + EfiBootServicesData, + 0x1000, + (VOID **)&UpdateData + ); + + ZeroMem (UpdateData, 0x1000); + + // + // Initialize DataPacket with information intended to remove all + // previously created op-codes in the dynamic page + // + UpdateData->FormSetUpdate = FALSE; + UpdateData->FormCallbackHandle = 0; + UpdateData->FormUpdate = FALSE; + UpdateData->FormTitle = 0; + // + // Unlikely to be more than 0xff op-codes in the dynamic page to remove + // + UpdateData->DataCount = 0xff; + UpdateData->Data = NULL; + + // + // Remove all op-codes from dynamic page + // + Private->Hii->UpdateForm ( + Private->Hii, + Private->RegisteredHandle, + (EFI_FORM_LABEL) 0x1234, // Label 0x1234 + FALSE, // Remove Op-codes (will never remove form/endform) + UpdateData // Significant value is UpdateData->DataCount + ); + + UpdateData->FormSetUpdate = FALSE; + UpdateData->FormCallbackHandle = 0; + UpdateData->FormUpdate = FALSE; + UpdateData->FormTitle = 0; + UpdateData->DataCount = 1; + + CreateGotoOpCode ( + 1, + STR_GOTO_FORM1, // Token value for the Prompt + 0, // Goto Help + 0, // Flags + 0, // Key + &UpdateData->Data // Buffer location to place op-codes + ); + + Private->Hii->UpdateForm ( + Private->Hii, + Private->RegisteredHandle, + (EFI_FORM_LABEL) 0x1234, + TRUE, + UpdateData + ); + + gBS->FreePool (UpdateData); + break; + + case 0x1236: + // + // If I hit the checkbox, I enter this case statement... + // + // + // Since I am returning an error (for test purposes) I need to pass in the string for the error + // I will allocate space for the return value. If an error occurs (which is the case) I can simply return + // an error and fill in the string parameter, otherwise, I will return information in the DataArray structure. + // The browser will free this packet structure + // + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (EFI_HII_CALLBACK_PACKET) + sizeof (SAMPLE_STRING) + 2, + (VOID **) Packet + ); + + ZeroMem (*Packet, sizeof (EFI_HII_CALLBACK_PACKET) + sizeof (SAMPLE_STRING) + 2); + + // + // Assign the buffer address to DataPacket + // + DataPacket = *Packet; + + StrCpy (DataPacket->String, (CHAR16 *) SAMPLE_STRING); + return EFI_DEVICE_ERROR; + + case 0x1237: + + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (EFI_HII_CALLBACK_PACKET) + 2, + (VOID **) Packet + ); + + ZeroMem (*Packet, sizeof (EFI_HII_CALLBACK_PACKET) + 2); + + // + // Assign the buffer address to DataPacket + // + DataPacket = *Packet; + + DataPacket->DataArray.EntryCount = 1; + DataPacket->DataArray.NvRamMap = NULL; + ((EFI_IFR_DATA_ENTRY *) (&DataPacket->DataArray + 1))->Flags = EXIT_REQUIRED; + break; + + case 0x1555: + Value = 0x0001; + UnicodeSPrint (VariableName, 0x80, (CHAR16 *) L"%d", VAR_EQ_TEST_NAME); + + Status = gRT->SetVariable ( + VariableName, + &mFormSetGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + 2, + (VOID *) &Value + ); + break; + + case 0x1556: + Value = 0x1000; + UnicodeSPrint (VariableName, 0x80, (CHAR16 *) L"%d", VAR_EQ_TEST_NAME); + + Status = gRT->SetVariable ( + VariableName, + &mFormSetGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + 2, + (VOID *) &Value + ); + break; + + case 0x1557: + Value = 0x0000; + UnicodeSPrint (VariableName, 0x80, (CHAR16 *) L"%d", VAR_EQ_TEST_NAME); + + Status = gRT->SetVariable ( + VariableName, + &mFormSetGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + 2, + (VOID *) &Value + ); + break; + + default: + break; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +DriverSampleInit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HII_PROTOCOL *Hii; + // + // EFI_FORM_BROWSER_PROTOCOL *FormConfig; + // + EFI_HII_PACKAGES *PackageList; + EFI_HII_HANDLE HiiHandle; + STRING_REF TokenToUpdate; + STRING_REF TokenToUpdate2; + STRING_REF TokenToUpdate3; + CHAR16 *NewString; + EFI_HII_UPDATE_DATA *UpdateData; + EFI_CALLBACK_INFO *CallbackInfo; + EFI_HANDLE Handle; + EFI_SCREEN_DESCRIPTOR Screen; + + ZeroMem (&Screen, sizeof (EFI_SCREEN_DESCRIPTOR)); + + gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &Screen.RightColumn, &Screen.BottomRow); + + // + // Remove 3 characters from top and bottom + // + Screen.TopRow = 3; + Screen.BottomRow = Screen.BottomRow - 3; + + // + // There should only be one HII protocol + // + Status = gBS->LocateProtocol ( + &gEfiHiiProtocolGuid, + NULL, + (VOID **) &Hii + ); + if (EFI_ERROR (Status)) { + return Status;; + } + + /* + // + // There should only be one Form Configuration protocol + // + Status = gBS->LocateProtocol ( + &gEfiFormBrowserProtocolGuid, + NULL, + &FormConfig + ); + if (EFI_ERROR (Status)) { + return Status;; + } +*/ + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (EFI_CALLBACK_INFO), + (VOID **) &CallbackInfo + ); + if (EFI_ERROR (Status)) { + return Status; + } + + CallbackInfo->Signature = EFI_CALLBACK_INFO_SIGNATURE; + CallbackInfo->Hii = Hii; + + // + // This example does not implement worker functions for the NV accessor functions. Only a callback evaluator + // + CallbackInfo->DriverCallback.NvRead = NULL; + CallbackInfo->DriverCallback.NvWrite = NULL; + CallbackInfo->DriverCallback.Callback = DriverCallback; + + // + // Install protocol interface + // + Handle = NULL; + Status = gBS->InstallProtocolInterface ( + &Handle, + &gEfiFormCallbackProtocolGuid, + EFI_NATIVE_INTERFACE, + &CallbackInfo->DriverCallback + ); + + ASSERT_EFI_ERROR (Status); + + CallbackInfo->CallbackHandle = Handle; + + PackageList = PreparePackages (1, &mStringPackGuid, DriverSampleStrings); + Status = Hii->NewPack (Hii, PackageList, &HiiHandle); + gBS->FreePool (PackageList); + + PackageList = PreparePackages (1, &mStringPackGuid, InventoryBin); + Status = Hii->NewPack (Hii, PackageList, &HiiHandle); + gBS->FreePool (PackageList); + + PackageList = PreparePackages (1, &mStringPackGuid, VfrBin); + Status = Hii->NewPack (Hii, PackageList, &HiiHandle); + gBS->FreePool (PackageList); + + CallbackInfo->RegisteredHandle = HiiHandle; + + // + // Very simple example of how one would update a string that is already + // in the HII database + // + TokenToUpdate = (STRING_REF) STR_CPU_STRING2; + NewString = (CHAR16 *) L"700 Mhz"; + + Hii->NewString (Hii, NULL, HiiHandle, &TokenToUpdate, NewString); + + // + // Add a string - if 0 will be updated with new Token number + // + TokenToUpdate = (STRING_REF) 0; + + // + // Add a string - if 0 will be updated with new Token number + // + TokenToUpdate2 = (STRING_REF) 0; + + // + // Add a string - if 0 will be updated with new Token number + // + TokenToUpdate3 = (STRING_REF) 0; + + Hii->NewString (Hii, NULL, HiiHandle, &TokenToUpdate, (CHAR16 *) L"Desired Speed"); + Hii->NewString (Hii, NULL, HiiHandle, &TokenToUpdate2, (CHAR16 *) L"5 Thz"); + Hii->NewString (Hii, NULL, HiiHandle, &TokenToUpdate3, (CHAR16 *) L"This is next year's desired speed - right?"); + + // + // Allocate space for creation of Buffer + // + Status = gBS->AllocatePool ( + EfiBootServicesData, + 0x1000, + (VOID **) &UpdateData + ); + + ZeroMem (UpdateData, 0x1000); + + // + // Flag update pending in FormSet + // + UpdateData->FormSetUpdate = TRUE; + // + // Register CallbackHandle data for FormSet + // + UpdateData->FormCallbackHandle = (EFI_PHYSICAL_ADDRESS) (UINTN) CallbackInfo->CallbackHandle; + UpdateData->FormUpdate = FALSE; + UpdateData->FormTitle = 0; + UpdateData->DataCount = 1; + + CreateTextOpCode (TokenToUpdate, TokenToUpdate2, TokenToUpdate3, 0, 0, &UpdateData->Data); + + Hii->UpdateForm (Hii, HiiHandle, (EFI_FORM_LABEL) 100, TRUE, UpdateData); + + gBS->FreePool (UpdateData); + + // + // Example of how to display only the item we sent to HII + // + if (DISPLAY_ONLY_MY_ITEM == 0x0001) { + // + // Have the browser pull out our copy of the data, and only display our data + // + // Status = FormConfig->SendForm (FormConfig, TRUE, HiiHandle, NULL, NULL, NULL, &Screen, NULL); + // + } else { + // + // Have the browser pull out all the data in the HII Database and display it. + // + // Status = FormConfig->SendForm (FormConfig, TRUE, 0, NULL, NULL, NULL, NULL, NULL); + // + } + + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/DriverSample.h b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/DriverSample.h new file mode 100644 index 0000000000..b1534e8dc6 --- /dev/null +++ b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/DriverSample.h @@ -0,0 +1,60 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DriverSample.h + +Abstract: + + +Revision History + +--*/ + +#ifndef _DRIVER_SAMPLE_H +#define _DRIVER_SAMPLE_H + + +#include "NVDataStruc.h" + +// +// This is the generated header file which includes whatever needs to be exported (strings + IFR) +// +#include "DriverSampleStrDefs.h" + +extern UINT8 VfrBin[]; +// +// extern UINT8 VfrStringsStr[]; +// +extern UINT8 InventoryBin[]; +// +// extern UINT8 InventoryStringsStr[]; +// +extern UINT8 DriverSampleStrings[]; + +#define SAMPLE_STRING L"This is an error!" + +#define EFI_CALLBACK_INFO_SIGNATURE EFI_SIGNATURE_32 ('C', 'l', 'b', 'k') + +typedef struct { + UINTN Signature; + EFI_HANDLE CallbackHandle; + EFI_FORM_CALLBACK_PROTOCOL DriverCallback; + UINT16 *KeyList; + VOID *FormBuffer; + EFI_HII_HANDLE RegisteredHandle; + EFI_HII_PROTOCOL *Hii; +} EFI_CALLBACK_INFO; + +#define EFI_CALLBACK_INFO_FROM_THIS(a) CR (a, EFI_CALLBACK_INFO, DriverCallback, EFI_CALLBACK_INFO_SIGNATURE) + +#endif diff --git a/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/DriverSample.mbd b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/DriverSample.mbd new file mode 100644 index 0000000000..c77f09b976 --- /dev/null +++ b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/DriverSample.mbd @@ -0,0 +1,45 @@ + + + + + DriverSample + FE3542FE-C1D3-4EF8-657C-8048606FF670 + 0 + FIX ME! + Copyright (c) 2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + BaseLib + BaseMemoryLib + UefiLib + UefiDriverEntryPoint + DxeReportStatusCodeLib + BaseDebugLibNull + BasePrintLib + EdkGraphicsLib + EdkIfrSupportLib + DxeMemoryAllocationLib + HiiLib + + diff --git a/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/DriverSample.msa b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/DriverSample.msa new file mode 100644 index 0000000000..f77095e254 --- /dev/null +++ b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/DriverSample.msa @@ -0,0 +1,84 @@ + + + + + DriverSample + DXE_DRIVER + BS_DRIVER + FE3542FE-C1D3-4EF8-657C-8048606FF670 + 0 + Component description file for DiskIo module. + FIX ME! + Copyright (c) 2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + DebugLib + UefiDriverEntryPoint + UefiLib + BaseLib + PrintLib + EdkGraphicsLib + EdkIfrSupportLib + BaseMemoryLib + MemoryAllocationLib + HiiLib + + + InventoryStrings.uni + Inventory.vfr + VfrStrings.uni + Vfr.vfr + DriverSample.c + DriverSample.h + + + MdePkg + EdkModulePkg + + + Hii + UgaDraw + OEMBadging + FirmwareVolume + ConsoleControl + FormCallback + + + + L"256" + 0xA04A27f4, 0xDF00, 0x4D42, { 0xB5, 0x52, 0x39, 0x51, 0x13, 0x02, 0x11, 0x3D } + + + + + GlobalVariable + + + + + DriverSampleInit + + + diff --git a/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/NVDataStruc.h b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/NVDataStruc.h new file mode 100644 index 0000000000..01369ebbf0 --- /dev/null +++ b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/NVDataStruc.h @@ -0,0 +1,62 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + NVDataStruc.h + +Abstract: + + NVData structure used by the sample driver + +Revision History: + +--*/ + +#ifndef _NVDATASTRUC_H +#define _NVDATASTRUC_H + +#define FORMSET_GUID \ + { \ + 0xA04A27f4, 0xDF00, 0x4D42, { 0xB5, 0x52, 0x39, 0x51, 0x13, 0x02, 0x11, 0x3D } \ + } + +#define INVENTORY_GUID \ + { \ + 0xb3f56470, 0x6141, 0x4621, { 0x8f, 0x19, 0x70, 0x4e, 0x57, 0x7a, 0xa9, 0xe8 } \ + } + +#define VAR_EQ_TEST_NAME 0x100 + +#pragma pack(1) +typedef struct { + UINT16 WhatIsThePassword[20]; + UINT16 WhatIsThePassword2[20]; + UINT16 MyStringData[20]; + 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]; + UINT8 BootOrder[8]; + UINT8 BootOrderLarge; + UINT8 DynamicCheck; +} MyIfrNVData; +#pragma pack() + +#endif diff --git a/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/Vfr.vfr b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/Vfr.vfr new file mode 100644 index 0000000000..6509a66b76 --- /dev/null +++ b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/Vfr.vfr @@ -0,0 +1,622 @@ +// *++ +// +// Copyright (c) 2006, Intel Corporation +// All rights reserved. This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// Module Name: +// +// Vfr.vfr +// +// Abstract: +// +// Sample Setup formset +// +// Revision History: +// +// --*/ + + +#include "DriverSampleStrDefs.h" + +#include "NVDataStruc.h" + + +typedef struct { + UINT8 Field8; + UINT16 Field16; + UINT8 OrderedList[3]; +} MyIfrNVData2; + +typedef struct { + UINT8 Field8; + UINT16 Field16; + UINT8 OrderedList[3]; +} MyIfrNVData3; + +#define MY_TEXT_KEY 0x100 + +#define LABEL_1_VALUE 0x01 +#define LABEL_2_VALUE 0x1000 +#define LABEL_UPDATE_BBS 0x2222 +#define LABEL_END_UPDATE_BBS 0x2223 + +formset + guid = FORMSET_GUID, + title = STRING_TOKEN(STR_FORM_SET_TITLE), + help = STRING_TOKEN(STR_FORM_SET_TITLE_HELP), + class = 0x10, + subclass = 0, + + varstore MyIfrNVData2, key = 0x1234, name = MY_DATA2, guid = FORMSET_GUID; + + + varstore MyIfrNVData3, key = 0x4321, name = MY_DATA3, guid = FORMSET_GUID; + + form formid = 1, + title = STRING_TOKEN(STR_FORM1_TITLE); // note formid is a variable (for readability) (UINT16) - also added Form to the line to signify the Op-Code + + subtitle text = STRING_TOKEN(STR_SUBTITLE_TEXT); + + subtitle text = STRING_TOKEN(STR_SUBTITLE_TEXT2); + + banner + title = STRING_TOKEN(STR_BANNER_TITLE), + line 1, + align center; + + banner + title = STRING_TOKEN(STR_BANNER_TITLE), + line 2, + align left; + + banner + title = STRING_TOKEN(STR_BANNER_TITLE), + line 2, + align right; + + text + help = STRING_TOKEN(STR_TEXT_HELP), + text = STRING_TOKEN(STR_CPU_STRING), + text = STRING_TOKEN(STR_CPU_STRING2), + flags = 0, + key = 0; + + text + help = STRING_TOKEN(STR_EXIT_TEXT), + text = STRING_TOKEN(STR_EXIT_TEXT), + text = STRING_TOKEN(STR_EXIT_TEXT), + flags = INTERACTIVE, + key = 0x1237; + + oneof varid = MyIfrNVData.SuppressGrayOutSomething, + prompt = STRING_TOKEN(STR_ONE_OF_PROMPT), + help = STRING_TOKEN(STR_ONE_OF_HELP), + option text = STRING_TOKEN(STR_ONE_OF_TEXT4), value = 0x0, flags = 0; + option text = STRING_TOKEN(STR_ONE_OF_TEXT5), value = 0x1, flags = 0; + 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), + option text = STRING_TOKEN(STR_BOOT_ORDER1), value = 0x0, flags = INTERACTIVE, key = 1; + option text = STRING_TOKEN(STR_BOOT_ORDER2), value = 0x1, flags = INTERACTIVE | DEFAULT, key = 2; + endoneof; + + grayoutif ideqval MyIfrNVData.SuppressGrayOutSomething == 0x1; + suppressif ideqval MyIfrNVData.SuppressGrayOutSomething == 0x0; + label 0; + checkbox varid = MyIfrNVData.ChooseToActivateNuclearWeaponry, + prompt = STRING_TOKEN(STR_CHECK_BOX_PROMPT), + help = STRING_TOKEN(STR_CHECK_BOX_HELP), + flags = 1, // Flags behavior for checkbox is overloaded so that it equals a DEFAULT value. 1 = ON, 0 = off + key = 0, + endcheckbox; + 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 LABEL_UPDATE_BBS; + orderedlist + varid = MyIfrNVData.BootOrder, + prompt = STRING_TOKEN(STR_BOOT_OPTIONS), + help = STRING_TOKEN(STR_NULL_STRING), + option text = STRING_TOKEN(STR_BOOT_OPTION2), value = 2, flags = RESET_REQUIRED; + option text = STRING_TOKEN(STR_BOOT_OPTION1), value = 1, flags = RESET_REQUIRED; + option text = STRING_TOKEN(STR_BOOT_OPTION3), value = 3, flags = RESET_REQUIRED; + option text = STRING_TOKEN(STR_BOOT_OPTION4), value = 4, flags = RESET_REQUIRED; + endlist; + label LABEL_END_UPDATE_BBS; + endif; + + suppressif ideqval MyIfrNVData.SuppressGrayOutSomething == 0x2; + orderedlist + varid = MyIfrNVData.OrderedList, + prompt = STRING_TOKEN(STR_TEST_OPCODE), + help = STRING_TOKEN(STR_TEXT_HELP), + option text = STRING_TOKEN(STR_ONE_OF_TEXT1), value = 4, flags = RESET_REQUIRED; + option text = STRING_TOKEN(STR_ONE_OF_TEXT2), value = 3, flags = RESET_REQUIRED; + option text = STRING_TOKEN(STR_ONE_OF_TEXT3), value = 2, flags = RESET_REQUIRED; + option text = STRING_TOKEN(STR_TEXT_HELP), value = 1, flags = RESET_REQUIRED; + endlist; + endif; + + label 100; + + goto 0x1234, + prompt = STRING_TOKEN(STR_GOTO_DYNAMIC), + help = STRING_TOKEN(STR_GOTO_HELP), + flags = INTERACTIVE, + key = 0x1234; + + goto 0x1234, + prompt = STRING_TOKEN(STR_GOTO_DYNAMIC2), + help = STRING_TOKEN(STR_GOTO_HELP), + flags = INTERACTIVE, + key = 0x1235; + + // + // VARSTORE tests + // + // Till now, been using variable NvData (must be reserved) + // now we do a varselect for variable NvData3 + inconsistentif prompt = STRING_TOKEN(STR_ERROR_POPUP), + ideqid MyIfrNVData3.Field16 == MyIfrNVData3.Field16 + endif; + // now we do a varselect_pair for variable NvData2 and NvData3 + inconsistentif prompt = STRING_TOKEN(STR_ERROR_POPUP), + ideqid MyIfrNVData2.Field16 == MyIfrNVData3.Field16 + endif; + + + // now we do a varselect_pair for variable NvData and NvData2 +// inconsistentif prompt = STRING_TOKEN(STR_ERROR_POPUP), +// ideqid MyIfrNVData2.Field16 == MyIfrNVData.TestLateCheck +// endif; + + inconsistentif prompt = STRING_TOKEN(STR_ERROR_POPUP), + ideqid MyIfrNVData.TestLateCheck == MyIfrNVData.TestLateCheck2 + endif; + + oneof varid = MyIfrNVData.TestLateCheck, + prompt = STRING_TOKEN(STR_TEST_OPCODE), + help = STRING_TOKEN(STR_ONE_OF_HELP), + option text = STRING_TOKEN(STR_ONE_OF_TEXT1), value = 0, flags = LATE_CHECK | RESET_REQUIRED; + option text = STRING_TOKEN(STR_ONE_OF_TEXT2), value = 1, flags = LATE_CHECK | DEFAULT | RESET_REQUIRED; + endoneof; + + oneof varid = MyIfrNVData.TestLateCheck2, + prompt = STRING_TOKEN(STR_TEST_OPCODE2), + help = STRING_TOKEN(STR_ONE_OF_HELP), + option text = STRING_TOKEN(STR_ONE_OF_TEXT1), value = 0, flags = LATE_CHECK | DEFAULT | RESET_REQUIRED; + option text = STRING_TOKEN(STR_ONE_OF_TEXT2), value = 1, flags = LATE_CHECK | RESET_REQUIRED; + + endoneof; + + oneof varid = MyIfrNVData.QuestionAboutTreeHugging, + prompt = STRING_TOKEN(STR_ONE_OF_PROMPT), + help = STRING_TOKEN(STR_ONE_OF_HELP), + option text = STRING_TOKEN(STR_ONE_OF_TEXT1), value = 0, flags = RESET_REQUIRED; + option text = STRING_TOKEN(STR_ONE_OF_TEXT2), value = 1, flags = DEFAULT | RESET_REQUIRED; + option text = STRING_TOKEN(STR_ONE_OF_TEXT3), value = 0x03, flags = RESET_REQUIRED; + + endoneof; + + string varid = MyIfrNVData.MyStringData, + prompt = STRING_TOKEN(STR_MY_STRING_PROMPT2), + help = STRING_TOKEN(STR_MY_STRING_HELP2), + flags = INTERACTIVE, + key = 0x1234, + minsize = 6, + maxsize = 0x14, + endstring; + + text + help = STRING_TOKEN(STR_GRAYOUT_TEST), + text = STRING_TOKEN(STR_GRAYOUT_TEST), + text = STRING_TOKEN(STR_GRAYOUT_TEST), + flags = INTERACTIVE, + key = 0x1555; + + text + help = STRING_TOKEN(STR_SUPPRESS_TEST), + text = STRING_TOKEN(STR_SUPPRESS_TEST), + text = STRING_TOKEN(STR_SUPPRESS_TEST), + flags = INTERACTIVE, + key = 0x1556; + + text + help = STRING_TOKEN(STR_CLEAR_TEST), + text = STRING_TOKEN(STR_CLEAR_TEST), + text = STRING_TOKEN(STR_CLEAR_TEST), + flags = INTERACTIVE, + key = 0x1557; + + grayoutif vareqval var(VAR_EQ_TEST_NAME) == 0x1; + suppressif vareqval var(VAR_EQ_TEST_NAME) == 0x1000; + label 30; + checkbox varid = MyIfrNVData.ChooseToActivateNuclearWeaponry, + prompt = STRING_TOKEN(STR_CHECK_BOX_PROMPT), + help = STRING_TOKEN(STR_CHECK_BOX_HELP), + flags = 1, + key = 0, + endcheckbox; + endif; + + + numeric varid = MyIfrNVData.HowOldAreYouInYearsManual, + prompt = STRING_TOKEN(STR_NUMERIC_MANUAL_PROMPT), + help = STRING_TOKEN(STR_NUMERIC_HELP0), + minimum = 0, + maximum = 0xf0, // 0xf0 = 240 in decimal + step = 0, // Stepping of 0 equates to a manual entering + // of a value, otherwise it will auto-increment + // with a left/right arrow + default = 21, + + endnumeric; + + numeric varid = MyIfrNVData.HowTallAreYouManual, + prompt = STRING_TOKEN(STR_TALL_MANUAL_PROMPT), + help = STRING_TOKEN(STR_NUMERIC_HELP1), + minimum = 0, + maximum = 300, + step = 0, // Stepping of 0 equates to a manual entering + // of a value, otherwise it will auto-increment + // with a left/right arrow + default = 175, + + endnumeric; + + inventory + help = STRING_TOKEN(STR_INVENTORY_HELP), + text = STRING_TOKEN(STR_INVENTORY_TEXT1), + text = STRING_TOKEN(STR_INVENTORY_TEXT2); + + + restore defaults, + formid = 4, + prompt = STRING_TOKEN(STR_RESTORE_DEFAULTS_PROMPT), + help = STRING_TOKEN(STR_RESTORE_DEFAULTS_HELP), + flags = 0, + key = 0; + + save defaults, + formid = 4, + prompt = STRING_TOKEN(STR_SAVE_DEFAULTS_PROMPT), + help = STRING_TOKEN(STR_SAVE_DEFAULTS_HELP), + flags = 0, + key = 0; + + // + // Case with no flags or key + // + save defaults, + formid = 4, + prompt = STRING_TOKEN(STR_SAVE_DEFAULTS_PROMPT), + help = STRING_TOKEN(STR_SAVE_DEFAULTS_HELP); + // + // Case with no key + // + save defaults, + formid = 4, + prompt = STRING_TOKEN(STR_SAVE_DEFAULTS_PROMPT), + help = STRING_TOKEN(STR_SAVE_DEFAULTS_HELP), + flags = 0; + // + // Case with no flags + // + save defaults, + formid = 4, + prompt = STRING_TOKEN(STR_SAVE_DEFAULTS_PROMPT), + help = STRING_TOKEN(STR_SAVE_DEFAULTS_HELP), + key = 0; + + label LABEL_2_VALUE; + + grayoutif ideqval MyIfrNVData.HowOldAreYouInYearsManual == 23 AND ideqval MyIfrNVData.SuppressGrayOutSomething == 0x1; + numeric varid = MyIfrNVData.HowOldAreYouInYears, + prompt = STRING_TOKEN(STR_NUMERIC_PROMPT), + help = STRING_TOKEN(STR_NUMERIC_HELP2), + minimum = 0, + maximum = 243, + step = 3, + default = 18, + + endnumeric; + + label LABEL_1_VALUE; + + // + // Numeric with no step or default specified + // + numeric varid = MyIfrNVData.HowTallAreYou, + prompt = STRING_TOKEN(STR_NUMERIC_PROMPT1), + help = STRING_TOKEN(STR_NUMERIC_HELP3), + minimum = 0, + maximum = 190, + // step = 1, // Stepping of 1 if not specified + // default = minimum; // if not specified + endnumeric; + endif; + + string varid = MyIfrNVData.MyStringData, + prompt = STRING_TOKEN(STR_MY_STRING_PROMPT), + help = STRING_TOKEN(STR_MY_STRING_HELP), + minsize = 6, + maxsize = 0x14, + endstring; + + password varid = MyIfrNVData.WhatIsThePassword, + prompt = STRING_TOKEN(STR_PASSWORD_PROMPT), + help = STRING_TOKEN(STR_PASSWORD_HELP), + minsize = 6, + maxsize = 20, // new opcode + encoding = 1, + endpassword; + password varid = MyIfrNVData.WhatIsThePassword2, + prompt = STRING_TOKEN(STR_PASSWORD_PROMPT), + help = STRING_TOKEN(STR_PASSWORD_HELP), + minsize = 6, + maxsize = 20, // new opcode + encoding = 1, + endpassword; + // + // Test with flags and key fields + // + password varid = MyIfrNVData.WhatIsThePassword, + prompt = STRING_TOKEN(STR_PASSWORD_PROMPT), + help = STRING_TOKEN(STR_PASSWORD_HELP), + flags = INTERACTIVE, + key = 0x2000, + minsize = 6, + maxsize = 20, // new opcode + encoding = 1, + endpassword; + + 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); + + endform; + + 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 year varid = Date.Year, // Note that it is a member of NULL, so the RTC will be the system resource to retrieve and save from + prompt = STRING_TOKEN(STR_DATE_PROMPT), + help = STRING_TOKEN(STR_DATE_YEAR_HELP), + minimum = 1998, + maximum = 2099, + step = 1, + default = 2004, + + month varid = Date.Month, // Note that it is a member of NULL, so the RTC will be the system resource to retrieve and save from + prompt = STRING_TOKEN(STR_DATE_PROMPT), + help = STRING_TOKEN(STR_DATE_MONTH_HELP), + minimum = 1, + maximum = 12, + step = 1, + default = 1, + + day varid = Date.Day, // Note that it is a member of NULL, so the RTC will be the system resource to retrieve and save from + prompt = STRING_TOKEN(STR_DATE_PROMPT), + help = STRING_TOKEN(STR_DATE_DAY_HELP), + minimum = 1, + maximum = 31, + step = 0x1, + default = 1, + + enddate; + + time hour varid = Time.Hours, // Note that it is a member of NULL, so the RTC will be the system resource to retrieve and save from + prompt = STRING_TOKEN(STR_TIME_PROMPT), + help = STRING_TOKEN(STR_TIME_HOUR_HELP), + minimum = 0, + maximum = 23, + step = 1, + default = 0, + + minute varid = Time.Minutes, // Note that it is a member of NULL, so the RTC will be the system resource to retrieve and save from + prompt = STRING_TOKEN(STR_TIME_PROMPT), + help = STRING_TOKEN(STR_TIME_MINUTE_HELP), + minimum = 0, + maximum = 59, + step = 1, + default = 0, + + second varid = Time.Seconds, // Note that it is a member of NULL, so the RTC will be the system resource to retrieve and save from + prompt = STRING_TOKEN(STR_TIME_PROMPT), + help = STRING_TOKEN(STR_TIME_SECOND_HELP), + minimum = 0, + maximum = 59, + step = 1, + default = 0, + + endtime; + + date year varid = Date.Year, // Note that it is a member of NULL, so the RTC will be the system resource to retrieve and save from + prompt = STRING_TOKEN(STR_DATE_PROMPT), + help = STRING_TOKEN(STR_DATE_YEAR_HELP), + minimum = 1939, + maximum = 2101, + step = 1, + default = 1964, + + month varid = Date.Month, // Note that it is a member of NULL, so the RTC will be the system resource to retrieve and save from + prompt = STRING_TOKEN(STR_DATE_PROMPT), + help = STRING_TOKEN(STR_DATE_MONTH_HELP), + minimum = 1, + maximum = 12, + step = 1, + default = 1, + + day varid = Date.Day, // Note that it is a member of NULL, so the RTC will be the system resource to retrieve and save from + prompt = STRING_TOKEN(STR_DATE_PROMPT), + help = STRING_TOKEN(STR_DATE_DAY_HELP), + minimum = 1, + maximum = 31, + step = 0x1, + default = 1, + + enddate; + + time hour varid = Time.Hours, // Note that it is a member of NULL, so the RTC will be the system resource to retrieve and save from + prompt = STRING_TOKEN(STR_TIME_PROMPT), + help = STRING_TOKEN(STR_TIME_HOUR_HELP), + minimum = 0, + maximum = 23, + step = 1, + default = 0, + + minute varid = Time.Minutes, // Note that it is a member of NULL, so the RTC will be the system resource to retrieve and save from + prompt = STRING_TOKEN(STR_TIME_PROMPT), + help = STRING_TOKEN(STR_TIME_MINUTE_HELP), + minimum = 0, + maximum = 59, + step = 1, + default = 0, + + second varid = Time.Seconds, // Note that it is a member of NULL, so the RTC will be the system resource to retrieve and save from + prompt = STRING_TOKEN(STR_TIME_PROMPT), + help = STRING_TOKEN(STR_TIME_SECOND_HELP), + minimum = 0, + maximum = 59, + step = 1, + default = 0, + + endtime; + + grayoutif + ideqval Date.Day == 21 + AND + ideqval Date.Month == 8; + + hidden value = 32, key = 0x7777; + + endif; // grayoutif + + suppressif + ideqval Date.Day == 8 + AND + ideqval Date.Month == 21; + + hidden value = 32, key = 0x7777; + + endif; // suppressif + + + hidden value = 32, key = 0x1234; + + inconsistentif prompt = STRING_TOKEN(STR_ERROR_POPUP), + ideqval MyIfrNVData.HowOldAreYouInYearsManual == 4 + endif; + + inconsistentif prompt = STRING_TOKEN(STR_ERROR_POPUP), + ideqvallist MyIfrNVData.HowOldAreYouInYearsManual == 1 2 3 4 + endif; + + inconsistentif prompt = STRING_TOKEN(STR_ERROR_POPUP), + ideqid MyIfrNVData.HowOldAreYouInYearsManual == MyIfrNVData.MyFavoriteNumber + endif; + +// grayoutif +// +// If the day is 31 AND months is any of the following 2, 4, 6, 9, 11 +// + 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; + + checkbox varid = MyIfrNVData.ChooseToActivateNuclearWeaponry, + prompt = STRING_TOKEN(STR_CHECK_BOX_PROMPT), + help = STRING_TOKEN(STR_CHECK_BOX_HELP), + flags = 1, + key = 0, + 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), + flags = 0, + key = MY_TEXT_KEY; + + 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); + + endform; + + 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 + + grayoutif ideqval MyIfrNVData.SuppressGrayOutSomething == 0x1; + text + help = STRING_TOKEN(STR_TEXT_HELP), + text = STRING_TOKEN(STR_TEXT_TEXT_1); + + endif; //end grayoutif + + text + help = STRING_TOKEN(STR_TEXT_HELP), + text = STRING_TOKEN(STR_TEXT_TEXT_1); + + endform; + + form formid = 4, title = STRING_TOKEN(STR_FORM3_TITLE); + + 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 0x1234; + + endform; + +endformset; diff --git a/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/VfrStrings.uni b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/VfrStrings.uni new file mode 100644 index 0000000000000000000000000000000000000000..9e9dbf5454e0dd43e33f1d7272352bc06d9f0eba GIT binary patch literal 35590 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/inventory.vfr b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/inventory.vfr new file mode 100644 index 0000000000..ff8a6aacb1 --- /dev/null +++ b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/inventory.vfr @@ -0,0 +1,123 @@ +// *++ +// +// Copyright (c) 2006, Intel Corporation +// All rights reserved. This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// Module Name: +// +// Inventory.vfr +// +// Abstract: +// +// Sample Inventory Data. +// +// Revision History: +// +// --*/ + +#include "DriverSampleStrDefs.h" + +#define INVENTORY_GUID { 0xb3f56470, 0x6141, 0x4621, { 0x8f, 0x19, 0x70, 0x4e, 0x57, 0x7a, 0xa9, 0xe8 } } + +formset + guid = INVENTORY_GUID, + title = STRING_TOKEN(STR_INV_FORM_SET_TITLE), + help = STRING_TOKEN(STR_INV_FORM_SET_HELP), + class = 0x04, + subclass = 0x03, + + 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; + + subtitle text = STRING_TOKEN(STR_INV_EMPTY_STRING); + + subtitle text = STRING_TOKEN(STR_INV_VERSION_TEXT12); + + endform; + +endformset; diff --git a/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/inventorystrings.uni b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/inventorystrings.uni new file mode 100644 index 0000000000000000000000000000000000000000..4946b4ae6130097afb7319b344cf0220912db644 GIT binary patch literal 8302 zcmd^^-%cAx6voeWrM|-oZrZd!fIw-aUhu~xR$^ljLz=4!FeYvQN4A0RQhldBLSLZm z?>obK*WLx&8^Bc6%DXeOvuD2Z&G|Dk{^#!nTd>HU*$-Ub+Beh|`p?KVt!dA`hI6e_C3!fd(O3LKT}v> ztqbOkU2<>OJZ*J!Y|$ElzXR?Q*Wrx%0Xj5z_ULi!^&@y_+ZjFe?waq;=^xP|ttGcb z>C~l7u6u(107)A06nRIK&K6k6ZBc(afF-M4g8s@GJ>o9BgPgU%r!mB7U|pkksf)WqkjK`exe2o) zjheg(Gb%m4&}$gyAXi~duIY8?j5N_Iup&(Qdhkln%i?>?@Jsg#`9k1d-*J*KJptJ^ZsfH`umglc#;zIb$e|kSgP5s?bs{s>sFy&#s(v- zP|rH8W!tblN+q|i*l z(7#8L#@}&lk-bOWuIo^xz0CL;ZO3u$Qj?Zy6S_Km)kpY3uWkAY=Leo|cq1K!t8_C; z(6?m2_T?nf%dl3%V>RZMN4eXyNzf;y3ijP_f0O4`@s~4v;AKBYBt0cnc|g%r*+71A z4gTQGij7@Hm*2JeUq`9Zy8DZID^B!MW2Ad&l(fvqBVQAlk{id1F1_UCig{T~dZ!q9 z44wpkQrhLsB|WP%isd6&_7z9cSz5i0n6V4DQhCxg5<2j7wQO z8c=JkQ12q;Gnd#^uGXqWYXLDDygaOv#HCg@u^s1eRJ<*Z-Lx(I-`E{DIxLQe3t>j` z*iGB+WH!4$WV2h?Nsr$&Vnm1!HEgxzSx>P{KA4UMTA%!hpUP`ul%x3FClc%uc|(R* z>{aHjBRlUJ#c$R-v-vBqsJtDqXImmmJ-217F@<3=51vv-Y_Y;qTDSP;;!bl9(M6r?iOK9QAOM>Pldh7@fGFoMIrt+?_Bf9 z{vun1!v()Tr&eJ%v@oUh(AT0Z%I!)aZu4^HaNDwbxBOlwdu?B*YHz4$8+J6)h_=Hh z^XlUwFUtAq19JWb*>zv(>&)_u9H+CkZPq>7e?DEt$H85c@1Gu+Z>{}wO5E~2+JA-Z zyHOYAdhNluuCoiT5uf)sQPYlInNhrd!p<+S^spvuvJ-9-Um8!=){E&;bUuE5u=!YI z^|8jusO(*5Y{?l~UQ8|CmbVv6pCpVU`F5;DdDY4xJ8~Y@^u9d%MYcsN;yG3#A#&HS z`tp;t<=e3q=XLRccrCNr(|Opb{lN%pu)Ja~n8gz7zNeZOM`JF|bKZ__l>O>lM*kn` z+)@9WZ1U7OuFj^vxW&#-h0F1Ajp9qzP-6x4!O!W#e_d7n3CsGaT1N3T4Z8|s#{WwE E3ppGb!vFvP literal 0 HcmV?d00001 diff --git a/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/InputHandler.c b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/InputHandler.c new file mode 100644 index 0000000000..d84fcf02b1 --- /dev/null +++ b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/InputHandler.c @@ -0,0 +1,1580 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + InputHandler.C + +Abstract: + + Implementation for handling user input from the User Interface + +Revision History + +--*/ + +#include "Setup.h" +#include "Ui.h" +#include "Colors.h" + +#ifndef EFI_MAX +#define EFI_MAX(_a, _b) ((_a) > (_b) ? (_a) : (_b)) +#endif + +EFI_STATUS +ReadString ( + IN UI_MENU_OPTION *MenuOption, + OUT CHAR16 *StringPtr + ) +{ + EFI_STATUS Status; + EFI_INPUT_KEY Key; + CHAR16 NullCharacter; + UINTN ScreenSize; + EFI_TAG *Tag; + CHAR16 Space[2]; + CHAR16 KeyPad[2]; + BOOLEAN SelectionComplete; + CHAR16 *TempString; + CHAR16 *BufferedString; + UINTN Index; + UINTN Count; + UINTN Start; + UINTN Top; + CHAR16 *PromptForDataString; + UINTN DimensionsWidth; + UINTN DimensionsHeight; + BOOLEAN CursorVisible; + + DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn; + DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow; + + PromptForDataString = GetToken (STRING_TOKEN (PROMPT_FOR_DATA), gHiiHandle); + + NullCharacter = CHAR_NULL; + ScreenSize = GetStringWidth (PromptForDataString) / 2; + Tag = MenuOption->ThisTag; + Space[0] = L' '; + Space[1] = CHAR_NULL; + SelectionComplete = FALSE; + + TempString = AllocateZeroPool (MenuOption->ThisTag->Maximum * 2); + ASSERT (TempString); + + if (ScreenSize < (Tag->Maximum / (UINTN) 2)) { + ScreenSize = Tag->Maximum / 2; + } + + if ((ScreenSize + 2) > DimensionsWidth) { + ScreenSize = DimensionsWidth - 2; + } + + BufferedString = AllocateZeroPool (ScreenSize * 2); + ASSERT (BufferedString); + + Start = (DimensionsWidth - ScreenSize - 2) / 2 + gScreenDimensions.LeftColumn + 1; + Top = ((DimensionsHeight - 6) / 2) + gScreenDimensions.TopRow - 1; + + // + // Display prompt for string + // + CreatePopUp (ScreenSize, 4, &NullCharacter, PromptForDataString, Space, &NullCharacter); + + gBS->FreePool (PromptForDataString); + + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY)); + + CursorVisible = gST->ConOut->Mode->CursorVisible; + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + + do { + Status = WaitForKeyStroke (&Key); + + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY)); + switch (Key.UnicodeChar) { + case CHAR_NULL: + switch (Key.ScanCode) { + case SCAN_LEFT: + break; + + case SCAN_RIGHT: + break; + + case SCAN_ESC: + gBS->FreePool (TempString); + gBS->FreePool (BufferedString); + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->EnableCursor (gST->ConOut, CursorVisible); + return EFI_DEVICE_ERROR; + + default: + break; + } + + break; + + case CHAR_CARRIAGE_RETURN: + if (GetStringWidth (StringPtr) >= MenuOption->ThisTag->Minimum) { + SelectionComplete = TRUE; + gBS->FreePool (TempString); + gBS->FreePool (BufferedString); + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->EnableCursor (gST->ConOut, CursorVisible); + return EFI_SUCCESS; + } else { + ScreenSize = GetStringWidth (gMiniString) / 2; + CreatePopUp (ScreenSize, 4, &NullCharacter, gMiniString, gPressEnter, &NullCharacter); + // + // 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 { + Status = WaitForKeyStroke (&Key); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + gBS->FreePool (TempString); + gBS->FreePool (BufferedString); + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->EnableCursor (gST->ConOut, CursorVisible); + return EFI_DEVICE_ERROR; + } + + break; + + case CHAR_BACKSPACE: + if (StringPtr[0] != CHAR_NULL) { + for (Index = 0; StringPtr[Index] != CHAR_NULL; Index++) { + TempString[Index] = StringPtr[Index]; + } + // + // Effectively truncate string by 1 character + // + TempString[Index - 1] = CHAR_NULL; + StrCpy (StringPtr, TempString); + } + + 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)) { + StrnCpy (StringPtr, &Key.UnicodeChar, 1); + StrnCpy (TempString, &Key.UnicodeChar, 1); + } else if ((GetStringWidth (StringPtr) < MenuOption->ThisTag->Maximum) && (Key.UnicodeChar != CHAR_BACKSPACE)) { + KeyPad[0] = Key.UnicodeChar; + KeyPad[1] = CHAR_NULL; + StrCat (StringPtr, KeyPad); + StrCat (TempString, KeyPad); + } + // + // 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; + } + + for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) { + BufferedString[Count] = StringPtr[Index]; + } + + 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 + GetStringWidth (StringPtr) / 2, Top + 3); + } while (!SelectionComplete); + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->EnableCursor (gST->ConOut, CursorVisible); + return Status; +} + +EFI_STATUS +ReadPassword ( + IN UI_MENU_OPTION *MenuOption, + IN BOOLEAN PromptForPassword, + IN EFI_TAG *Tag, + IN EFI_IFR_DATA_ARRAY *PageData, + IN BOOLEAN SecondEntry, + IN EFI_FILE_FORM_TAGS *FileFormTags, + OUT CHAR16 *StringPtr + ) +{ + EFI_STATUS Status; + UINTN PasswordSize; + UINTN ScreenSize; + CHAR16 NullCharacter; + CHAR16 Space[2]; + EFI_INPUT_KEY Key; + CHAR16 KeyPad[2]; + UINTN Index; + UINTN Start; + UINTN Top; + CHAR16 *TempString; + CHAR16 *TempString2; + BOOLEAN Confirmation; + BOOLEAN ConfirmationComplete; + EFI_HII_CALLBACK_PACKET *Packet; + EFI_FORM_CALLBACK_PROTOCOL *FormCallback; + EFI_VARIABLE_DEFINITION *VariableDefinition; + UINTN DimensionsWidth; + UINTN DimensionsHeight; + EFI_IFR_DATA_ENTRY *DataEntry; + + DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn; + DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow; + + VariableDefinition = NULL; + PasswordSize = 0; + NullCharacter = CHAR_NULL; + Space[0] = L' '; + Space[1] = CHAR_NULL; + Confirmation = FALSE; + ConfirmationComplete = FALSE; + Status = EFI_SUCCESS; + FormCallback = NULL; + Packet = NULL; + + // + // Remember that dynamic pages in an environment where all pages are not + // dynamic require us to call back to the user to give them an opportunity + // to register fresh information in the HII database so that we can extract it. + // + Status = gBS->HandleProtocol ( + (VOID *) (UINTN) MenuOption->Tags[0].CallbackHandle, + &gEfiFormCallbackProtocolGuid, + (VOID **) &FormCallback + ); + + TempString = AllocateZeroPool (MenuOption->ThisTag->Maximum * 2); + TempString2 = AllocateZeroPool (MenuOption->ThisTag->Maximum * 2); + + ASSERT (TempString); + ASSERT (TempString2); + + if (Tag->Flags & EFI_IFR_FLAG_INTERACTIVE) { + // + // Password requires a callback to determine if a password exists + // + DataEntry = (EFI_IFR_DATA_ENTRY *) (PageData + 1); + DataEntry->OpCode = EFI_IFR_PASSWORD_OP; + DataEntry->Length = 3; + + ExtractRequestedNvMap (FileFormTags, Tag->VariableNumber, &VariableDefinition); + + // + // The user is about to be prompted with a password field, Data = 0 (Return Status determines the type of prompt) + // + DataEntry->Data = (VOID *) (UINTN) (UINT8) (0 + SecondEntry * 2); + PageData->NvRamMap = VariableDefinition->NvRamMap; + + if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) { + Status = FormCallback->Callback ( + FormCallback, + Tag->Key, + PageData, + &Packet + ); + } + // + // If error on return, continue with the reading of a typed in password to verify user knows password + // If no error, there is no password set, so prompt for new password + // if the previous callback was to verify the user knew password, and user typed it correctly - should return no error + // + if (!EFI_ERROR (Status)) { + PromptForPassword = FALSE; + + // + // Simulate this as the second entry into this routine for an interactive behavior + // + SecondEntry = TRUE; + } else if (Status == EFI_NOT_READY) { +Error: + if (Packet != NULL) { + // + // Upon error, we will likely receive a string to print out + // Display error popup + // + ScreenSize = EFI_MAX(GetStringWidth (Packet->String), GetStringWidth (gPressEnter)) / 2; + CreatePopUp (ScreenSize, 4, &NullCharacter, Packet->String, gPressEnter, &NullCharacter); + gBS->FreePool (Packet); + + do { + Status = WaitForKeyStroke (&Key); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + } + + gBS->FreePool (TempString); + gBS->FreePool (TempString2); + return EFI_NOT_READY; + } + } + + do { + // + // Display PopUp Screen + // + ScreenSize = GetStringWidth (gPromptForNewPassword) / 2; + if (GetStringWidth (gConfirmPassword) / 2 > ScreenSize) { + ScreenSize = GetStringWidth (gConfirmPassword) / 2; + } + + Start = (DimensionsWidth - ScreenSize - 4) / 2 + gScreenDimensions.LeftColumn + 2; + Top = ((DimensionsHeight - 6) / 2) + gScreenDimensions.TopRow - 1; + + if (!Confirmation) { + if (PromptForPassword) { + CreatePopUp (ScreenSize, 4, &NullCharacter, gPromptForPassword, Space, &NullCharacter); + } else { + CreatePopUp (ScreenSize, 4, &NullCharacter, gPromptForNewPassword, Space, &NullCharacter); + } + } else { + CreatePopUp (ScreenSize, 4, &NullCharacter, gConfirmPassword, Space, &NullCharacter); + StringPtr[0] = CHAR_NULL; + } + + do { + Status = WaitForKeyStroke (&Key); + + switch (Key.UnicodeChar) { + case CHAR_NULL: + if (Key.ScanCode == SCAN_ESC) { + return EFI_NOT_READY; + } + + ConfirmationComplete = FALSE; + break; + + case CHAR_CARRIAGE_RETURN: + if (Tag->Flags & EFI_IFR_FLAG_INTERACTIVE) { + // + // User just typed a string in + // + DataEntry = (EFI_IFR_DATA_ENTRY *) (PageData + 1); + DataEntry->OpCode = EFI_IFR_PASSWORD_OP; + + // + // If the user just typed in a password, Data = 1 + // If the user just typed in a password to confirm the previous password, Data = 2 + // + if (!Confirmation) { + DataEntry->Length = 3; + DataEntry->Data = (VOID *) (UINTN) (UINT8) (1 + SecondEntry * 2); + + if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) { + Status = FormCallback->Callback ( + FormCallback, + Tag->Key, + PageData, + &Packet + ); + } + + DataEntry->Length = sizeof (EFI_IFR_DATA_ENTRY); + DataEntry->Data = (VOID *) TempString; + } else { + DataEntry->Length = 3; + DataEntry->Data = (VOID *) (UINTN) (UINT8) (2 + SecondEntry * 2); + + if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) { + Status = FormCallback->Callback ( + FormCallback, + Tag->Key, + PageData, + &Packet + ); + } + + DataEntry->Length = sizeof (EFI_IFR_DATA_ENTRY); + DataEntry->Data = (VOID *) TempString2; + } + + if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) { + Status = FormCallback->Callback ( + FormCallback, + Tag->Key, + PageData, + &Packet + ); + } + // + // If this was the confirmation round of callbacks + // and an error comes back, display an error + // + if (Confirmation) { + if (EFI_ERROR (Status)) { + if (Packet->String == NULL) { + ScreenSize = EFI_MAX (GetStringWidth (gConfirmError), GetStringWidth (gPressEnter)) / 2; + CreatePopUp (ScreenSize, 4, &NullCharacter, gConfirmError, gPressEnter, &NullCharacter); + } else { + ScreenSize = EFI_MAX (GetStringWidth (Packet->String), GetStringWidth (gPressEnter)) / 2; + CreatePopUp (ScreenSize, 4, &NullCharacter, Packet->String, gPressEnter, &NullCharacter); + gBS->FreePool (Packet); + } + + StringPtr[0] = CHAR_NULL; + do { + Status = WaitForKeyStroke (&Key); + + if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) { + gBS->FreePool (TempString); + gBS->FreePool (TempString2); + return EFI_NOT_READY; + } + } while (1); + } else { + gBS->FreePool (TempString); + gBS->FreePool (TempString2); + return EFI_NOT_READY; + } + } else { + // + // User typed a string in and it wasn't valid somehow from the callback + // For instance, callback may have said that some invalid characters were contained in the string + // + if (Status == EFI_NOT_READY) { + goto Error; + } + + if (PromptForPassword && EFI_ERROR (Status)) { + gBS->FreePool (TempString); + gBS->FreePool (TempString2); + return EFI_DEVICE_ERROR; + } + } + } + + if (Confirmation) { + // + // Compare tempstring and tempstring2, if the same, return with StringPtr success + // Otherwise, kick and error box, and return an error + // + if (StrCmp (TempString, TempString2) == 0) { + gBS->FreePool (TempString); + gBS->FreePool (TempString2); + return EFI_SUCCESS; + } else { + ScreenSize = EFI_MAX (GetStringWidth (gConfirmError), GetStringWidth (gPressEnter)) / 2; + CreatePopUp (ScreenSize, 4, &NullCharacter, gConfirmError, gPressEnter, &NullCharacter); + StringPtr[0] = CHAR_NULL; + do { + Status = WaitForKeyStroke (&Key); + if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) { + gBS->FreePool (TempString); + gBS->FreePool (TempString2); + return EFI_DEVICE_ERROR; + } + } while (1); + } + } + + if (PromptForPassword) { + // + // I was asked for a password, return it back in StringPtr + // + gBS->FreePool (TempString); + gBS->FreePool (TempString2); + return EFI_SUCCESS; + } else { + // + // If the two passwords were not the same kick an error popup + // + Confirmation = TRUE; + ConfirmationComplete = TRUE; + break; + } + + case CHAR_BACKSPACE: + if (StringPtr[0] != CHAR_NULL) { + if (!Confirmation) { + for (Index = 0; StringPtr[Index] != CHAR_NULL; Index++) { + TempString[Index] = StringPtr[Index]; + } + // + // Effectively truncate string by 1 character + // + TempString[Index - 1] = CHAR_NULL; + StrCpy (StringPtr, TempString); + } else { + for (Index = 0; StringPtr[Index] != CHAR_NULL; Index++) { + TempString2[Index] = StringPtr[Index]; + } + // + // Effectively truncate string by 1 character + // + TempString2[Index - 1] = CHAR_NULL; + StrCpy (StringPtr, TempString2); + } + + ConfirmationComplete = FALSE; + } else { + ConfirmationComplete = FALSE; + } + + // + // Must be a character we are interested in! + // + default: + if ((StringPtr[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) { + if (!Confirmation) { + StrnCpy (StringPtr, &Key.UnicodeChar, 1); + StrnCpy (TempString, &Key.UnicodeChar, 1); + } else { + StrnCpy (StringPtr, &Key.UnicodeChar, 1); + StrnCpy (TempString2, &Key.UnicodeChar, 1); + ConfirmationComplete = FALSE; + } + } else if ((GetStringWidth (StringPtr) / 2 <= (UINTN) (MenuOption->ThisTag->Maximum - 1) / 2) && + (Key.UnicodeChar != CHAR_BACKSPACE) + ) { + KeyPad[0] = Key.UnicodeChar; + KeyPad[1] = CHAR_NULL; + if (!Confirmation) { + StrCat (StringPtr, KeyPad); + StrCat (TempString, KeyPad); + } else { + StrCat (StringPtr, KeyPad); + StrCat (TempString2, KeyPad); + } + } + + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY)); + for (Index = 1; Index < ScreenSize; Index++) { + PrintCharAt (Start + Index, Top + 3, L' '); + } + + gST->ConOut->SetCursorPosition ( + gST->ConOut, + (DimensionsWidth - GetStringWidth (StringPtr) / 2) / 2 + gScreenDimensions.LeftColumn, + Top + 3 + ); + for (Index = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++) { + PrintChar (L'*'); + } + + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + break; + } + // + // end switch + // + } while (!ConfirmationComplete); + + } while (1); + gBS->FreePool (TempString); + gBS->FreePool (TempString2); + return Status; +} + +VOID +EncodePassword ( + IN CHAR16 *Password, + IN UINT8 MaxSize + ) +{ + UINTN Index; + UINTN Loop; + CHAR16 *Buffer; + CHAR16 *Key; + + Key = (CHAR16 *) L"MAR10648567"; + Buffer = AllocateZeroPool (MaxSize); + + ASSERT (Buffer); + + for (Index = 0; Key[Index] != 0; Index++) { + for (Loop = 0; Loop < (UINT8) (MaxSize / 2); Loop++) { + Buffer[Loop] = (CHAR16) (Password[Loop] ^ Key[Index]); + } + } + + CopyMem (Password, Buffer, MaxSize); + + gBS->FreePool (Buffer); + return ; +} + +EFI_STATUS +GetNumericInput ( + IN UI_MENU_OPTION *MenuOption, + IN EFI_FILE_FORM_TAGS *FileFormTagsHead, + IN BOOLEAN ManualInput, + IN EFI_TAG *Tag, + IN UINTN NumericType, + OUT UINT16 *Value + ) +/*++ + +Routine Description: + + This routine reads a numeric value from the user input. + +Arguments: + + MenuOption - Pointer to the current input menu. + + FileFormTagsHead - Pointer to the root of formset. + + ManualInput - If the input is manual or not. + + Tag - Pointer to all the attributes and values associated with a tag. + + Value - Pointer to the numeric value that is going to be read. + +Returns: + + EFI_SUCCESS - If numerical input is read successfully + EFI_DEVICE_ERROR - If operation fails + +--*/ +{ + EFI_INPUT_KEY Key; + BOOLEAN SelectionComplete; + UINTN Column; + UINTN Row; + CHAR16 FormattedNumber[6]; + UINTN PreviousNumber[6]; + INTN Number; + UINTN Count; + UINT16 BackupValue; + STRING_REF PopUp; + CHAR16 NullCharacter; + CHAR16 *StringPtr; + EFI_FILE_FORM_TAGS *FileFormTags; + EFI_STATUS Status; + EFI_VARIABLE_DEFINITION *VariableDefinition; + UINTN Loop; + + NullCharacter = CHAR_NULL; + StringPtr = NULL; + Column = MenuOption->OptCol; + Row = MenuOption->Row; + Number = 0; + PreviousNumber[0] = 0; + Count = 0; + SelectionComplete = FALSE; + BackupValue = Tag->Value; + FileFormTags = FileFormTagsHead; + + if (ManualInput) { + PrintAt (Column, Row, (CHAR16 *) L"[ ]"); + Column++; + if (Tag->Operand != EFI_IFR_TIME_OP) { + *Value = BackupValue; + } + } + // + // 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; + } + + Status = WaitForKeyStroke (&Key); + +TheKey2: + switch (Key.UnicodeChar) { + case '+': + case '-': + if ((Tag->Operand == EFI_IFR_DATE_OP) || (Tag->Operand == EFI_IFR_TIME_OP)) { + Key.UnicodeChar = CHAR_NULL; + if (Key.UnicodeChar == '+') { + Key.ScanCode = SCAN_RIGHT; + } else { + Key.ScanCode = SCAN_LEFT; + } + + goto TheKey2; + } + break; + + case CHAR_NULL: + switch (Key.ScanCode) { + case SCAN_LEFT: + case SCAN_RIGHT: + if ((Tag->Operand == EFI_IFR_DATE_OP) || (Tag->Operand == EFI_IFR_TIME_OP)) { + // + // 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 (!ManualInput) { + Tag->Value = *Value; + if (Key.ScanCode == SCAN_LEFT) { + Number = *Value - Tag->Step; + if (Number < Tag->Minimum) { + Number = Tag->Minimum; + } + } else if (Key.ScanCode == SCAN_RIGHT) { + Number = *Value + Tag->Step; + if (Number > Tag->Maximum) { + Number = Tag->Maximum; + } + } + + Tag->Value = (UINT16) Number; + *Value = (UINT16) Number; + UnicodeValueToString ( + FormattedNumber, + FALSE, + (UINTN) Number, + (sizeof (FormattedNumber) / sizeof (FormattedNumber[0])) + ); + Number = (UINT16) GetStringWidth (FormattedNumber); + + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); + if ((Tag->Operand == EFI_IFR_DATE_OP) || (Tag->Operand == EFI_IFR_TIME_OP)) { + for (Loop = 0; Loop < (UINTN) ((Number >= 8) ? 4 : 2); Loop++) { + PrintAt (MenuOption->OptCol + Loop, MenuOption->Row, (CHAR16 *) L" "); + } + } else { + for (Loop = 0; Loop < gOptionBlockWidth; Loop++) { + PrintAt (MenuOption->OptCol + Loop, MenuOption->Row, (CHAR16 *) L" "); + } + } + + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT); + + if ((MenuOption->Col + gPromptBlockWidth + 1) == MenuOption->OptCol) { + PrintCharAt (MenuOption->OptCol, Row, LEFT_NUMERIC_DELIMITER); + Column = MenuOption->OptCol + 1; + } + // + // If Number looks like "3", convert it to "03/" + // + if (Number == 4 && (NumericType == DATE_NUMERIC)) { + FormattedNumber[3] = FormattedNumber[1]; + FormattedNumber[2] = DATE_SEPARATOR; + FormattedNumber[1] = FormattedNumber[0]; + FormattedNumber[0] = L'0'; + Number = 8; + } + // + // If Number looks like "13", convert it to "13/" + // + if (Number == 6 && (NumericType == DATE_NUMERIC)) { + FormattedNumber[3] = FormattedNumber[2]; + FormattedNumber[2] = DATE_SEPARATOR; + Number = 8; + } + + if (Number == 4 && + (NumericType == TIME_NUMERIC) && + (MenuOption->Col + gPromptBlockWidth + 8) != MenuOption->OptCol + ) { + FormattedNumber[3] = FormattedNumber[1]; + FormattedNumber[2] = TIME_SEPARATOR; + FormattedNumber[1] = FormattedNumber[0]; + FormattedNumber[0] = L'0'; + Number = 8; + } + + if (Number == 4 && + (NumericType == TIME_NUMERIC) && + (MenuOption->Col + gPromptBlockWidth + 8) == MenuOption->OptCol + ) { + FormattedNumber[3] = FormattedNumber[1]; + FormattedNumber[2] = RIGHT_NUMERIC_DELIMITER; + FormattedNumber[1] = FormattedNumber[0]; + FormattedNumber[0] = L'0'; + Number = 8; + } + + PrintStringAt (Column, Row, FormattedNumber); + if (Number == 10 && (NumericType == DATE_NUMERIC)) { + PrintChar (RIGHT_NUMERIC_DELIMITER); + } + + if (NumericType == REGULAR_NUMERIC) { + PrintChar (RIGHT_NUMERIC_DELIMITER); + } + } + break; + + case SCAN_UP: + case SCAN_DOWN: + goto EnterCarriageReturn; + + case SCAN_ESC: + return EFI_DEVICE_ERROR; + + default: + break; + } + + break; + +EnterCarriageReturn: + + case CHAR_CARRIAGE_RETURN: + // + // Check to see if the Value is something reasonable against consistency limitations. + // If not, let's kick the error specified. + // + // + // This gives us visibility to the FileFormTags->NvRamMap to check things + // ActiveIfr is a global maintained by the menuing code to ensure that we + // are pointing to the correct formset's file data. + // + for (Count = 0; Count < gActiveIfr; Count++) { + FileFormTags = FileFormTags->NextFile; + } + + ExtractRequestedNvMap (FileFormTags, Tag->VariableNumber, &VariableDefinition); + + CopyMem (&VariableDefinition->NvRamMap[Tag->StorageStart], &Tag->Value, Tag->StorageWidth); + + // + // Data associated with a NULL device (in the fake NV storage) + // + if (Tag->StorageWidth == (UINT16) 0) { + CopyMem (&VariableDefinition->FakeNvRamMap[Tag->StorageStart], &Tag->Value, 2); + } + // + // If a late check is required save off the information. This is used when consistency checks + // are required, but certain values might be bound by an impossible consistency check such as + // if two questions are bound by consistency checks and each only has two possible choices, there + // would be no way for a user to switch the values. Thus we require late checking. + // + if (Tag->Flags & EFI_IFR_FLAG_LATE_CHECK) { + CopyMem (&Tag->OldValue, &BackupValue, Tag->StorageWidth); + } else { + // + // In theory, passing the value and the Id are sufficient to determine what needs + // to be done. The Id is the key to look for the entry needed in the Inconsistency + // database. That will yields operand and ID data - and since the ID's correspond + // to the NV storage, we can determine the values for other IDs there. + // + if (ValueIsNotValid (TRUE, 0, Tag, FileFormTags, &PopUp)) { + if (PopUp == 0x0000) { + SelectionComplete = TRUE; + break; + } + + StringPtr = GetToken (PopUp, MenuOption->Handle); + + CreatePopUp (GetStringWidth (StringPtr) / 2, 3, &NullCharacter, StringPtr, &NullCharacter); + + do { + Status = WaitForKeyStroke (&Key); + + switch (Key.UnicodeChar) { + + case CHAR_CARRIAGE_RETURN: + SelectionComplete = TRUE; + gBS->FreePool (StringPtr); + break; + + default: + break; + } + } while (!SelectionComplete); + + Tag->Value = BackupValue; + *Value = BackupValue; + + CopyMem (&VariableDefinition->NvRamMap[Tag->StorageStart], &Tag->Value, Tag->StorageWidth); + + // + // Data associated with a NULL device (in the fake NV storage) + // + if (Tag->StorageWidth == (UINT16) 0) { + CopyMem (&VariableDefinition->FakeNvRamMap[Tag->StorageStart], &Tag->Value, 2); + } + + return EFI_DEVICE_ERROR; + } + } + + return EFI_SUCCESS; + break; + + case CHAR_BACKSPACE: + if (ManualInput) { + if (Count == 0) { + break; + } + // + // Remove a character + // + Number = PreviousNumber[Count - 1]; + *Value = (UINT16) Number; + UpdateStatusBar (INPUT_ERROR, Tag->Flags, FALSE); + Count--; + Column--; + PrintAt (Column, Row, (CHAR16 *) L" "); + } + break; + + default: + if (ManualInput) { + if (Key.UnicodeChar > L'9' || Key.UnicodeChar < L'0') { + UpdateStatusBar (INPUT_ERROR, Tag->Flags, TRUE); + break; + } + // + // If Count 0-4 is complete, there is no way more is valid + // + if (Count > 4) { + break; + } + // + // Someone typed something valid! + // + if (Count != 0) { + Number = Number * 10 + (Key.UnicodeChar - L'0'); + } else { + Number = Key.UnicodeChar - L'0'; + } + + if (Number > Tag->Maximum) { + UpdateStatusBar (INPUT_ERROR, Tag->Flags, TRUE); + Number = PreviousNumber[Count]; + break; + } else { + UpdateStatusBar (INPUT_ERROR, Tag->Flags, FALSE); + } + + Count++; + + PreviousNumber[Count] = Number; + *Value = (UINT16) Number; + Tag->Value = (UINT16) Number; + + PrintCharAt (Column, Row, Key.UnicodeChar); + Column++; + } + break; + } + } while (!SelectionComplete); + return EFI_SUCCESS; +} +// +// Notice that this is at least needed for the ordered list manipulation. +// Left/Right doesn't make sense for this op-code +// +EFI_STATUS +GetSelectionInputPopUp ( + IN UI_MENU_OPTION *MenuOption, + IN EFI_TAG *Tag, + IN UINTN ValueCount, + OUT UINT16 *Value, + OUT UINT16 *KeyValue + ) +{ + EFI_STATUS Status; + EFI_INPUT_KEY Key; + UINTN Index; + UINTN TempIndex; + CHAR16 *StringPtr; + CHAR16 *TempStringPtr; + UINT16 Token; + UINTN Index2; + UINTN TopOptionIndex; + UINTN HighlightPosition; + UINTN Start; + UINTN End; + UINTN Top; + UINTN Bottom; + UINT16 TempValue; + UINTN Count; + UINTN PopUpMenuLines; + UINTN MenuLinesInView; + UINTN PopUpWidth; + CHAR16 Character; + UINTN FirstOption; + BOOLEAN FirstOptionFoundFlag; + INT32 SavedAttribute; + EFI_TAG TagBackup; + UINT8 *ValueArray; + UINT8 *ValueArrayBackup; + UINT8 ValueBackup; + BOOLEAN Initialized; + BOOLEAN KeyInitialized; + BOOLEAN ShowDownArrow; + BOOLEAN ShowUpArrow; + UINTN DimensionsWidth; + UINTN DimensionsHeight; + + DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn; + DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow; + + TempValue = 0; + TempIndex = 0; + ValueArray = (UINT8 *) Value; + ValueArrayBackup = NULL; + Initialized = FALSE; + KeyInitialized = FALSE; + ShowDownArrow = FALSE; + ShowUpArrow = FALSE; + + if (Tag->Operand == EFI_IFR_ORDERED_LIST_OP) { + ValueArrayBackup = AllocateZeroPool (Tag->StorageWidth); + ASSERT (ValueArrayBackup != NULL); + CopyMem (ValueArrayBackup, ValueArray, ValueCount); + TempValue = *(UINT8 *) (ValueArray); + if (ValueArray[0] != 0x00) { + Initialized = TRUE; + } + + for (Index = 0; ValueArray[Index] != 0x00; Index++) + ; + ValueCount = Index; + } else { + TempValue = *Value; + } + + Count = 0; + PopUpWidth = 0; + + FirstOption = MenuOption->TagIndex; + FirstOptionFoundFlag = FALSE; + + StringPtr = AllocateZeroPool ((gOptionBlockWidth + 1) * 2); + ASSERT (StringPtr); + + // + // Initialization for "One of" pop-up menu + // + // + // Get the number of one of options present and its size + // + for (Index = MenuOption->TagIndex; MenuOption->Tags[Index].Operand != EFI_IFR_END_ONE_OF_OP; Index++) { + if (MenuOption->Tags[Index].Operand == EFI_IFR_ONE_OF_OPTION_OP && + !MenuOption->Tags[Index].Suppress) { + if (!FirstOptionFoundFlag) { + FirstOption = Index; + FirstOptionFoundFlag = TRUE; + } + + Count++; + Token = MenuOption->Tags[Index].Text; + + // + // If this is an ordered list that is initialized + // + if (Initialized) { + for (ValueBackup = (UINT8) MenuOption->TagIndex; + MenuOption->Tags[ValueBackup].Operand != EFI_IFR_END_OP; + ValueBackup++ + ) { + if (MenuOption->Tags[ValueBackup].Value == ((UINT8 *) ValueArrayBackup)[Index - MenuOption->TagIndex - 1]) { + StringPtr = GetToken (MenuOption->Tags[ValueBackup].Text, MenuOption->Handle); + break; + } + } + } else { + StringPtr = GetToken (Token, MenuOption->Handle); + } + + if (StrLen (StringPtr) > PopUpWidth) { + PopUpWidth = StrLen (StringPtr); + } + + gBS->FreePool (StringPtr); + } + } + // + // Perform popup menu initialization. + // + PopUpMenuLines = Count; + PopUpWidth = PopUpWidth + POPUP_PAD_SPACE_COUNT; + + SavedAttribute = gST->ConOut->Mode->Attribute; + gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND); + + if ((PopUpWidth + POPUP_FRAME_WIDTH) > DimensionsWidth) { + PopUpWidth = DimensionsWidth - POPUP_FRAME_WIDTH; + } + + Start = (DimensionsWidth - PopUpWidth - POPUP_FRAME_WIDTH) / 2 + gScreenDimensions.LeftColumn; + End = Start + PopUpWidth + POPUP_FRAME_WIDTH; + Top = gScreenDimensions.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT; + Bottom = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT; + + MenuLinesInView = Bottom - Top - 1; + if (MenuLinesInView >= PopUpMenuLines) { + Top = Top + (MenuLinesInView - PopUpMenuLines) / 2; + Bottom = Top + PopUpMenuLines + 1; + } else { + TempValue = MenuOption->Tags[MenuOption->TagIndex + 1].Value; + ShowDownArrow = TRUE; + } + + TopOptionIndex = 1; + HighlightPosition = 0; + do { + if (Initialized) { + for (Index = MenuOption->TagIndex, Index2 = 0; Index2 < ValueCount; Index++, Index2++) { + // + // Set the value for the item we are looking for + // + Count = ValueArrayBackup[Index2]; + + // + // If we hit the end of the Array, we are complete + // + if (Count == 0) { + break; + } + + if (MenuOption->Tags[Index].Operand == EFI_IFR_ONE_OF_OPTION_OP) { + for (ValueBackup = (UINT8) MenuOption->TagIndex; + MenuOption->Tags[ValueBackup].Operand != EFI_IFR_END_ONE_OF_OP; + ValueBackup++ + ) { + // + // We just found what we are looking for + // + if (MenuOption->Tags[ValueBackup].Value == Count) { + // + // As long as the two indexes aren't the same, we have + // two different op-codes we need to swap internally + // + if (Index != ValueBackup) { + // + // Backup destination tag, then copy source to destination, then copy backup to source location + // + CopyMem (&TagBackup, &MenuOption->Tags[Index], sizeof (EFI_TAG)); + CopyMem (&MenuOption->Tags[Index], &MenuOption->Tags[ValueBackup], sizeof (EFI_TAG)); + CopyMem (&MenuOption->Tags[ValueBackup], &TagBackup, sizeof (EFI_TAG)); + } else { + // + // If the indexes are the same, then the op-code is where he belongs + // + } + } + } + } else { + // + // Since this wasn't an option op-code (likely the ordered list op-code) decerement Index2 + // + Index2--; + } + } + } + // + // Clear that portion of the screen + // + ClearLines (Start, End, Top, Bottom, POPUP_TEXT | POPUP_BACKGROUND); + + // + // Draw "One of" pop-up menu + // + Character = (CHAR16) BOXDRAW_DOWN_RIGHT; + PrintCharAt (Start, Top, Character); + for (Index = Start; Index + 2 < End; Index++) { + if ((ShowUpArrow) && ((Index + 1) == (Start + End) / 2)) { + Character = (CHAR16) GEOMETRICSHAPE_UP_TRIANGLE; + } else { + Character = (CHAR16) BOXDRAW_HORIZONTAL; + } + + PrintChar (Character); + } + + Character = (CHAR16) BOXDRAW_DOWN_LEFT; + PrintChar (Character); + Character = (CHAR16) BOXDRAW_VERTICAL; + for (Index = Top + 1; Index < Bottom; Index++) { + PrintCharAt (Start, Index, Character); + PrintCharAt (End - 1, Index, Character); + } + // + // Display the One of options + // + Index2 = Top + 1; + for (Index = MenuOption->TagIndex + TopOptionIndex; + (MenuOption->Tags[Index].Operand != EFI_IFR_END_ONE_OF_OP) && (Index2 < Bottom); + Index++ + ) { + if (MenuOption->Tags[Index].Operand == EFI_IFR_ONE_OF_OPTION_OP) { + Token = MenuOption->Tags[Index].Text; + if (Initialized) { + for (ValueBackup = (UINT8) MenuOption->TagIndex; + MenuOption->Tags[ValueBackup].Operand != EFI_IFR_END_ONE_OF_OP; + ValueBackup++ + ) { + if (MenuOption->Tags[ValueBackup].Value == ((UINT8 *) ValueArrayBackup)[Index - MenuOption->TagIndex - 1]) { + StringPtr = GetToken (MenuOption->Tags[ValueBackup].Text, MenuOption->Handle); + break; + } + } + } else { + ValueBackup = (UINT8) Index; + StringPtr = GetToken (Token, MenuOption->Handle); + } + // + // 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)); + CopyMem (TempStringPtr, StringPtr, (sizeof (CHAR16) * (PopUpWidth - 5))); + gBS->FreePool (StringPtr); + StringPtr = TempStringPtr; + StrCat (StringPtr, (CHAR16 *) L"..."); + } + // + // Code to display the text should go here. Follwed by the [*] + // + if (MenuOption->Tags[ValueBackup].Suppress == TRUE) { + // + // Don't show the one, so decrease the Index2 for balance + // + Index2--; + } else if (MenuOption->Tags[ValueBackup].GrayOut == TRUE) { + // + // Gray Out the one + // + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | POPUP_BACKGROUND); + PrintStringAt (Start + 2, Index2, StringPtr); + gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND); + } else if (MenuOption->Tags[ValueBackup].Value == TempValue) { + // + // Highlight the selected one + // + gST->ConOut->SetAttribute (gST->ConOut, PICKLIST_HIGHLIGHT_TEXT | PICKLIST_HIGHLIGHT_BACKGROUND); + PrintStringAt (Start + 2, Index2, StringPtr); + gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND); + HighlightPosition = Index2; + } else { + gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND); + PrintStringAt (Start + 2, Index2, StringPtr); + } + + gBS->FreePool (StringPtr); + Index2 = Index2 + 1; + } + } + + Character = (CHAR16) BOXDRAW_UP_RIGHT; + PrintCharAt (Start, Bottom, Character); + for (Index = Start; Index + 2 < End; Index++) { + if ((ShowDownArrow) && ((Index + 1) == (Start + End) / 2)) { + Character = (CHAR16) GEOMETRICSHAPE_DOWN_TRIANGLE; + } else { + Character = (CHAR16) BOXDRAW_HORIZONTAL; + } + + PrintChar (Character); + } + + Character = (CHAR16) BOXDRAW_UP_LEFT; + PrintChar (Character); + // + // Get User selection and change TempValue if necessary + // + // + // Stop: One of pop-up menu + // + Key.UnicodeChar = CHAR_NULL; + if ((gDirection == SCAN_UP) || (gDirection == SCAN_DOWN)) { + Key.ScanCode = gDirection; + gDirection = 0; + goto TheKey; + } + + if (!KeyInitialized) { + if (MenuOption->ThisTag->Operand == EFI_IFR_ONE_OF_OP) { + *KeyValue = MenuOption->Tags[MenuOption->TagIndex + 1].Key; + } else { + *KeyValue = MenuOption->ThisTag->Key; + } + + KeyInitialized = TRUE; + } + + Status = WaitForKeyStroke (&Key); + +TheKey: + switch (Key.UnicodeChar) { + case '+': + case '-': + // + // If an ordered list op-code, we will allow for a popup of +/- keys + // to create an ordered list of items + // + if (Tag->Operand == EFI_IFR_ORDERED_LIST_OP) { + if (Key.UnicodeChar == '+') { + if ((TopOptionIndex > 1) && (HighlightPosition == (Top + 1))) { + // + // Highlight reaches the top of the popup window, scroll one menu item. + // + TopOptionIndex--; + ShowDownArrow = TRUE; + } + + if (TopOptionIndex == 1) { + ShowUpArrow = FALSE; + } + } else { + if (((TopOptionIndex + MenuLinesInView) <= PopUpMenuLines) && (HighlightPosition == (Bottom - 1))) { + // + // Highlight reaches the bottom of the popup window, scroll one menu item. + // + TopOptionIndex++; + ShowUpArrow = TRUE; + } + + if ((TopOptionIndex + MenuLinesInView) == (PopUpMenuLines + 1)) { + ShowDownArrow = FALSE; + } + } + + for (Index = MenuOption->TagIndex + TopOptionIndex; + MenuOption->Tags[Index].Operand != EFI_IFR_END_ONE_OF_OP; + Index++ + ) { + if (MenuOption->Tags[Index].Operand == EFI_IFR_ORDERED_LIST_OP) { + continue; + } + + if (Key.UnicodeChar == '+') { + TempIndex = Index - 1; + } else { + TempIndex = Index + 1; + } + // + // Is this the current tag we are on? + // + if (MenuOption->Tags[Index].Value == TempValue) { + // + // Is this prior tag a valid choice? If not, bail out + // + if (MenuOption->Tags[TempIndex].Operand == EFI_IFR_ONE_OF_OPTION_OP) { + // + // Copy the destination tag to the local variable + // + CopyMem (&TagBackup, &MenuOption->Tags[TempIndex], sizeof (EFI_TAG)); + // + // Copy the current tag to the tag location before us + // + CopyMem (&MenuOption->Tags[TempIndex], &MenuOption->Tags[Index], sizeof (EFI_TAG)); + // + // Copy the backed up tag to the current location + // + CopyMem (&MenuOption->Tags[Index], &TagBackup, sizeof (EFI_TAG)); + + // + // Adjust the array of values + // + for (Index = 0; Index < ValueCount; Index++) { + if (ValueArrayBackup[Index] == (UINT8) TempValue) { + if (Key.UnicodeChar == '+') { + if (Index == 0) { + // + // It is the top of the array already + // + break; + } + + TempIndex = Index - 1; + } else { + if ((Index + 1) == ValueCount) { + // + // It is the bottom of the array already + // + break; + } + + TempIndex = Index + 1; + } + + ValueBackup = ValueArrayBackup[TempIndex]; + ValueArrayBackup[TempIndex] = ValueArrayBackup[Index]; + ValueArrayBackup[Index] = ValueBackup; + Initialized = TRUE; + break; + } + } + break; + } else { + break; + } + } + } + } + break; + + case CHAR_NULL: + switch (Key.ScanCode) { + case SCAN_UP: + case SCAN_DOWN: + if (Key.ScanCode == SCAN_UP) { + if ((TopOptionIndex > 1) && (HighlightPosition == (Top + 1))) { + // + // Highlight reaches the top of the popup window, scroll one menu item. + // + TopOptionIndex--; + ShowDownArrow = TRUE; + } + + if (TopOptionIndex == 1) { + ShowUpArrow = FALSE; + } + } else { + if (((TopOptionIndex + MenuLinesInView) <= PopUpMenuLines) && (HighlightPosition == (Bottom - 1))) { + // + // Highlight reaches the bottom of the popup window, scroll one menu item. + // + TopOptionIndex++; + ShowUpArrow = TRUE; + } + + if ((TopOptionIndex + MenuLinesInView) == (PopUpMenuLines + 1)) { + ShowDownArrow = FALSE; + } + } + + for (Index = MenuOption->TagIndex + TopOptionIndex; + MenuOption->Tags[Index].Operand != EFI_IFR_END_ONE_OF_OP; + Index++ + ) { + if (MenuOption->Tags[Index].Operand == EFI_IFR_ONE_OF_OPTION_OP) { + if (Initialized) { + for (Index = 0; (ValueArrayBackup[Index] != TempValue) && (Index < ValueCount); Index++) + ; + + // + // Did we hit the end of the array? Either get the first TempValue or the next one + // + if (Key.ScanCode == SCAN_UP) { + if (Index == 0) { + TempValue = ValueArrayBackup[0]; + } else { + TempValue = ValueArrayBackup[Index - 1]; + } + } else { + if ((Index + 1) == ValueCount) { + TempValue = ValueArrayBackup[Index]; + } else { + TempValue = ValueArrayBackup[Index + 1]; + } + } + break; + } else { + if (Key.ScanCode == SCAN_UP) { + TempIndex = Index - 1; + + // + // Keep going until meets meaningful tag. + // + while ((MenuOption->Tags[TempIndex].Operand != EFI_IFR_ONE_OF_OPTION_OP && + MenuOption->Tags[TempIndex].Operand != EFI_IFR_ONE_OF_OP && + MenuOption->Tags[TempIndex].Operand != EFI_IFR_END_ONE_OF_OP) + || + (MenuOption->Tags[TempIndex].Operand == EFI_IFR_ONE_OF_OPTION_OP && + (MenuOption->Tags[TempIndex].Suppress || MenuOption->Tags[TempIndex].GrayOut))) { + TempIndex--; + } + } else { + TempIndex = Index + 1; + + // + // Keep going until meets meaningful tag. + // + while ((MenuOption->Tags[TempIndex].Operand != EFI_IFR_ONE_OF_OPTION_OP && + MenuOption->Tags[TempIndex].Operand != EFI_IFR_ONE_OF_OP && + MenuOption->Tags[TempIndex].Operand != EFI_IFR_END_ONE_OF_OP) + || + (MenuOption->Tags[TempIndex].Operand == EFI_IFR_ONE_OF_OPTION_OP && + (MenuOption->Tags[TempIndex].Suppress || MenuOption->Tags[TempIndex].GrayOut))) { + TempIndex++; + } + } + // + // The option value is the same as what is stored in NV store. This is where we take action + // + if (MenuOption->Tags[Index].Value == TempValue) { + // + // Only if the previous op-code is an option can we select it, otherwise we are at the left-most option + // + if (MenuOption->Tags[TempIndex].Operand == EFI_IFR_ONE_OF_OPTION_OP) { + TempValue = MenuOption->Tags[TempIndex].Value; + *KeyValue = MenuOption->Tags[TempIndex].Key; + } else { + TempValue = MenuOption->Tags[Index].Value; + *KeyValue = MenuOption->Tags[Index].Key; + } + break; + } + } + } + } + break; + + case SCAN_ESC: + gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute); + if (ValueArrayBackup != NULL) { + gBS->FreePool (ValueArrayBackup); + } + + return EFI_DEVICE_ERROR; + + default: + break; + } + + break; + + case CHAR_CARRIAGE_RETURN: + // + // return the current selection + // + if (Tag->Operand == EFI_IFR_ORDERED_LIST_OP) { + CopyMem (ValueArray, ValueArrayBackup, ValueCount); + gBS->FreePool (ValueArrayBackup); + } else { + *Value = TempValue; + } + + gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute); + return EFI_SUCCESS; + + default: + break; + } + } while (1); + + gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute); + return EFI_SUCCESS; +} + +EFI_STATUS +WaitForKeyStroke ( + OUT EFI_INPUT_KEY *Key + ) +{ + EFI_STATUS Status; + + do { + UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0); + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, Key); + } while (EFI_ERROR(Status)); + + return Status; +} diff --git a/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Presentation.c b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Presentation.c new file mode 100644 index 0000000000..cf3d0004d9 --- /dev/null +++ b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Presentation.c @@ -0,0 +1,1481 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + Presentation.c + +Abstract: + + Some presentation routines. + +Revision History: + +--*/ + +#include "Setup.h" +#include "Ui.h" +#include "Colors.h" + +VOID +ClearLines ( + UINTN LeftColumn, + UINTN RightColumn, + UINTN TopRow, + UINTN BottomRow, + 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 + // + SetUnicodeMem (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); + + gBS->FreePool (Buffer); + return ; +} + +VOID +NewStrCat ( + CHAR16 *Destination, + 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] = (CHAR16) NARROW_CHAR; + Length++; + + StrCpy (Destination + Length, Source); +} + +UINTN +GetStringWidth ( + CHAR16 *String + ) +{ + UINTN Index; + UINTN Count; + UINTN IncrementValue; + + 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); +} + +VOID +DisplayPageFrame ( + VOID + ) +{ + UINTN Index; + UINT8 Line; + UINT8 Alignment; + CHAR16 Character; + CHAR16 *Buffer; + CHAR16 *StrFrontPageBanner; + EFI_SCREEN_DESCRIPTOR LocalScreen; + UINTN Row; + + ZeroMem (&LocalScreen, sizeof (EFI_SCREEN_DESCRIPTOR)); + gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &LocalScreen.RightColumn, &LocalScreen.BottomRow); + ClearLines (0, LocalScreen.RightColumn, 0, LocalScreen.BottomRow, KEYHELP_BACKGROUND); + + CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); + + // + // For now, allocate an arbitrarily long buffer + // + Buffer = AllocateZeroPool (0x10000); + ASSERT (Buffer != NULL); + + Character = (CHAR16) BOXDRAW_HORIZONTAL; + + for (Index = 0; Index + 2 < (LocalScreen.RightColumn - LocalScreen.LeftColumn); Index++) { + Buffer[Index] = Character; + } + + if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) { + // + // ClearLines(0, LocalScreen.RightColumn, 0, BANNER_HEIGHT-1, BANNER_TEXT | BANNER_BACKGROUND); + // + ClearLines ( + LocalScreen.LeftColumn, + LocalScreen.RightColumn, + LocalScreen.TopRow, + FRONT_PAGE_HEADER_HEIGHT - 1 + LocalScreen.TopRow, + BANNER_TEXT | BANNER_BACKGROUND + ); + // + // for (Line = 0; Line < BANNER_HEIGHT; Line++) { + // + for (Line = (UINT8) LocalScreen.TopRow; Line < BANNER_HEIGHT + (UINT8) LocalScreen.TopRow; Line++) { + // + // for (Alignment = 0; Alignment < BANNER_COLUMNS; Alignment++) { + // + for (Alignment = (UINT8) LocalScreen.LeftColumn; + Alignment < BANNER_COLUMNS + (UINT8) LocalScreen.LeftColumn; + Alignment++ + ) { + if (BannerData->Banner[Line - (UINT8) LocalScreen.TopRow][Alignment - (UINT8) LocalScreen.LeftColumn] != 0x0000) { + StrFrontPageBanner = GetToken ( + BannerData->Banner[Line - (UINT8) LocalScreen.TopRow][Alignment - (UINT8) LocalScreen.LeftColumn], + FrontPageHandle + ); + } else { + continue; + } + + switch (Alignment - LocalScreen.LeftColumn) { + case 0: + // + // Handle left column + // + PrintStringAt (LocalScreen.LeftColumn, Line, StrFrontPageBanner); + break; + + case 1: + // + // Handle center column + // + PrintStringAt ( + LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3, + Line, + StrFrontPageBanner + ); + break; + + case 2: + // + // Handle right column + // + PrintStringAt ( + LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) * 2 / 3, + Line, + StrFrontPageBanner + ); + break; + } + + gBS->FreePool (StrFrontPageBanner); + } + } + } + + ClearLines ( + LocalScreen.LeftColumn, + LocalScreen.RightColumn, + LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT, + LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 1, + KEYHELP_TEXT | KEYHELP_BACKGROUND + ); + + if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) { + ClearLines ( + LocalScreen.LeftColumn, + LocalScreen.RightColumn, + LocalScreen.TopRow, + LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 1, + TITLE_TEXT | TITLE_BACKGROUND + ); + // + // Print Top border line + // +------------------------------------------------------------------------------+ + // ? ? + // +------------------------------------------------------------------------------+ + // + Character = (CHAR16) BOXDRAW_DOWN_RIGHT; + + PrintChar (Character); + PrintString (Buffer); + + Character = (CHAR16) BOXDRAW_DOWN_LEFT; + PrintChar (Character); + + Character = (CHAR16) BOXDRAW_VERTICAL; + for (Row = LocalScreen.TopRow + 1; Row <= LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 2; Row++) { + PrintCharAt (LocalScreen.LeftColumn, Row, Character); + PrintCharAt (LocalScreen.RightColumn - 1, Row, Character); + } + + Character = (CHAR16) BOXDRAW_UP_RIGHT; + PrintCharAt (LocalScreen.LeftColumn, LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 1, Character); + PrintString (Buffer); + + Character = (CHAR16) BOXDRAW_UP_LEFT; + PrintChar (Character); + + if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) { + // + // Print Bottom border line + // +------------------------------------------------------------------------------+ + // ? ? + // +------------------------------------------------------------------------------+ + // + Character = (CHAR16) BOXDRAW_DOWN_RIGHT; + PrintCharAt (LocalScreen.LeftColumn, LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT, Character); + + PrintString (Buffer); + + Character = (CHAR16) BOXDRAW_DOWN_LEFT; + PrintChar (Character); + Character = (CHAR16) BOXDRAW_VERTICAL; + for (Row = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT + 1; + Row <= LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 2; + Row++ + ) { + PrintCharAt (LocalScreen.LeftColumn, Row, Character); + PrintCharAt (LocalScreen.RightColumn - 1, Row, Character); + } + + Character = (CHAR16) BOXDRAW_UP_RIGHT; + PrintCharAt (LocalScreen.LeftColumn, LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 1, Character); + + PrintString (Buffer); + + Character = (CHAR16) BOXDRAW_UP_LEFT; + PrintChar (Character); + } + } + + gBS->FreePool (Buffer); + +} + +/* ++------------------------------------------------------------------------------+ +?F2=Previous Page Setup Page ? ++------------------------------------------------------------------------------+ + + + + + + + + + + + + + + + + + ++------------------------------------------------------------------------------+ +?F1=Scroll Help F9=Reset to Defaults F10=Save and Exit ? +| ^"=Move Highlight Toggles Checkbox Esc=Discard Changes | ++------------------------------------------------------------------------------+ +*/ +UI_MENU_OPTION * +DisplayForm ( + OUT UI_MENU_OPTION *Selection, + IN UINT16 FormHandle, + IN UINT16 TitleToken, + IN EFI_FORM_TAGS FormTags, + IN EFI_FILE_FORM_TAGS *FileFormTagsHead, + IN UINT8 *CallbackData + ) +{ + CHAR16 *StringPtr; + UINTN Index; + UINTN Count; + UINT16 MenuItemCount; + EFI_HII_HANDLE Handle; + UINT16 FormId; + STRING_REF String; + EFI_FILE_FORM_TAGS *FileFormTags; + BOOLEAN SuppressIf; + BOOLEAN Suppress; + BOOLEAN GrayOut; + BOOLEAN Conditional; + EFI_SCREEN_DESCRIPTOR LocalScreen; + UINT16 Width; + UINTN ArrayEntry; + CHAR16 *OutputString; + + Handle = Selection->Handle; + FormId = 0; + String = 0; + MenuItemCount = 0; + ArrayEntry = 0; + OutputString = NULL; + + CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); + + // + // If we hit a F2 (previous) we already nuked the menu and are simply carrying around what information we need + // + if (Selection->Previous) { + Selection->Previous = FALSE; + } else { + UiFreeMenu (); + UiInitMenu (); + } + + StringPtr = GetToken (TitleToken, Handle); + + if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) { + gST->ConOut->SetAttribute (gST->ConOut, TITLE_TEXT | TITLE_BACKGROUND); + PrintStringAt ( + (LocalScreen.RightColumn + LocalScreen.LeftColumn - GetStringWidth (StringPtr) / 2) / 2, + LocalScreen.TopRow + 1, + StringPtr + ); + } + + if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) { + gST->ConOut->SetAttribute (gST->ConOut, KEYHELP_TEXT | KEYHELP_BACKGROUND); + + // + // Display the infrastructure strings + // + if (!IsListEmpty (&gMenuList)) { + PrintStringAt (LocalScreen.LeftColumn + 2, LocalScreen.TopRow + 1, gFunctionTwoString); + } + + PrintStringAt (LocalScreen.LeftColumn + 2, LocalScreen.BottomRow - 4, gFunctionOneString); + PrintStringAt ( + LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3, + LocalScreen.BottomRow - 4, + gFunctionNineString + ); + PrintStringAt ( + LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) * 2 / 3, + LocalScreen.BottomRow - 4, + gFunctionTenString + ); + PrintAt (LocalScreen.LeftColumn + 2, LocalScreen.BottomRow - 3, (CHAR16 *) L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight); + PrintStringAt ( + LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3, + LocalScreen.BottomRow - 3, + gEscapeString + ); + } + // + // Remove Buffer allocated for StringPtr after it has been used. + // + gBS->FreePool (StringPtr); + + for (Index = 0; FormTags.Tags[Index].Operand != EFI_IFR_END_FORM_OP; Index++) { + GrayOut = FALSE; + Suppress = FALSE; + SuppressIf = FALSE; + Conditional = FALSE; + FileFormTags = FileFormTagsHead; + + if (FormTags.Tags[Index].Operand == EFI_IFR_FORM_OP) { + FormId = FormTags.Tags[Index].Id; + } + // + // This gives us visibility to the FileFormTags->NvRamMap to check things + // ActiveIfr is a global maintained by the menuing code to ensure that we + // are pointing to the correct formset's file data. + // + for (Count = 0; Count < gActiveIfr; Count++) { + FileFormTags = FileFormTags->NextFile; + } + // + // GrayoutIf [SuppressIf] + // + // OpCode(s) + // EndIf + // + // SuppressIf [GrayoutIf] + // + // OpCode(s) + // EndIf + // + Count = 0; + + do { + switch (FormTags.Tags[Index].Operand) { + case EFI_IFR_SUPPRESS_IF_OP: + SuppressIf = TRUE; + + case EFI_IFR_GRAYOUT_IF_OP: + + Conditional = TRUE; + + // + // Advance to the next op-code + // + Index++; + + // + // We are now pointing to the beginning of the consistency checking. Let's fast forward + // through the AND/OR/NOT data to come up with some meaningful ID data. + // + for (; + FormTags.Tags[Index].Operand == EFI_IFR_AND_OP || + FormTags.Tags[Index].Operand == EFI_IFR_OR_OP || + FormTags.Tags[Index].Operand == EFI_IFR_GT_OP || + FormTags.Tags[Index].Operand == EFI_IFR_GE_OP || + FormTags.Tags[Index].Operand == EFI_IFR_NOT_OP; + Index++ + ) + ; + + // + // We need to walk through the consistency checks until we hit the end of the consistency + // FALSE means evaluate this single expression + // The ConsistencyId refers to which expression in the Consistency database to use + // + if (SuppressIf) { + Suppress = ValueIsNotValid ( + FALSE, + FormTags.Tags[Index].ConsistencyId, + &FormTags.Tags[Index], + FileFormTags, + &String + ); + SuppressIf = FALSE; + } else { + GrayOut = ValueIsNotValid ( + FALSE, + FormTags.Tags[Index].ConsistencyId, + &FormTags.Tags[Index], + FileFormTags, + &String + ); + } + // + // Advance to the end of the expression (Will land us at a grayoutif/suppressif or the op-code being affected) + // + for (; + FormTags.Tags[Index].Operand == EFI_IFR_EQ_ID_VAL_OP || + FormTags.Tags[Index].Operand == EFI_IFR_EQ_VAR_VAL_OP || + FormTags.Tags[Index].Operand == EFI_IFR_EQ_ID_ID_OP || + FormTags.Tags[Index].Operand == EFI_IFR_EQ_ID_LIST_OP || + FormTags.Tags[Index].Operand == EFI_IFR_NOT_OP || + FormTags.Tags[Index].Operand == EFI_IFR_AND_OP || + FormTags.Tags[Index].Operand == EFI_IFR_OR_OP || + FormTags.Tags[Index].Operand == EFI_IFR_TRUE_OP || + FormTags.Tags[Index].Operand == EFI_IFR_FALSE_OP || + FormTags.Tags[Index].Operand == EFI_IFR_GT_OP || + FormTags.Tags[Index].Operand == EFI_IFR_GE_OP || + FormTags.Tags[Index].Operand == EFI_IFR_LABEL_OP; + Index++ + ) + ; + break; + + default: + goto GetOut; + } + // + // Do this two times (at most will see a suppress and grayout combination + // + Count++; + } while (Count < 2); + +GetOut: + do { + if (GrayOut) { + FormTags.Tags[Index].GrayOut = TRUE; + } else { + FormTags.Tags[Index].GrayOut = FALSE; + } + if (Suppress && FormTags.Tags[Index].Operand == EFI_IFR_ONE_OF_OPTION_OP) { + // + // Only need .Suppress field when the tag is a one_of_option. For other cases, omit them directly. + // + FormTags.Tags[Index].Suppress = TRUE; + } else { + FormTags.Tags[Index].Suppress = FALSE; + } + + if (( + FormTags.Tags[Index].NumberOfLines > 0 || + FormTags.Tags[Index].Operand == EFI_IFR_DATE_OP || + FormTags.Tags[Index].Operand == EFI_IFR_TIME_OP + ) && + !Suppress + ) { + + StringPtr = GetToken (FormTags.Tags[Index].Text, Handle); + + Width = GetWidth (&FormTags.Tags[Index], Handle); + + // + // This data can be retrieved over and over again. Therefore, reset to original values + // before processing otherwise things will start growing linearly + // + if (FormTags.Tags[Index].NumberOfLines > 1) { + FormTags.Tags[Index].NumberOfLines = 1; + } + + for (Count = 0; GetLineByWidth (StringPtr, Width, &ArrayEntry, &OutputString) != 0x0000;) { + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&StringPtr[ArrayEntry])) { + FormTags.Tags[Index].NumberOfLines++; + } + + gBS->FreePool (OutputString); + } + + ArrayEntry = 0; + + // + // We are NOT!! removing this StringPtr buffer via FreePool since it is being used in the menuoptions, we will do + // it in UiFreeMenu. + // + UiAddSubMenuOption (StringPtr, Handle, FormTags.Tags, Index, FormId, MenuItemCount); + MenuItemCount++; + } + // + // Keep processing menu entries based on the resultant suppress/grayout results until we hit an end-if + // + Index++; + } while (FormTags.Tags[Index].Operand != EFI_IFR_END_IF_OP && Conditional); + + // + // We advanced the index for the above conditional, rewind it to keep harmony with the for loop logic + // + Index--; + } + + Selection = UiDisplayMenu (TRUE, FileFormTagsHead, (EFI_IFR_DATA_ARRAY *) CallbackData); + + return Selection; +} + +VOID +InitializeBrowserStrings ( + VOID + ) +{ + gFunctionOneString = GetToken (STRING_TOKEN (FUNCTION_ONE_STRING), gHiiHandle); + gFunctionTwoString = GetToken (STRING_TOKEN (FUNCTION_TWO_STRING), gHiiHandle); + gFunctionNineString = GetToken (STRING_TOKEN (FUNCTION_NINE_STRING), gHiiHandle); + gFunctionTenString = GetToken (STRING_TOKEN (FUNCTION_TEN_STRING), gHiiHandle); + gEnterString = GetToken (STRING_TOKEN (ENTER_STRING), gHiiHandle); + gEnterCommitString = GetToken (STRING_TOKEN (ENTER_COMMIT_STRING), gHiiHandle); + gEscapeString = GetToken (STRING_TOKEN (ESCAPE_STRING), gHiiHandle); + gMoveHighlight = GetToken (STRING_TOKEN (MOVE_HIGHLIGHT), gHiiHandle); + gMakeSelection = GetToken (STRING_TOKEN (MAKE_SELECTION), gHiiHandle); + gNumericInput = GetToken (STRING_TOKEN (NUMERIC_INPUT), gHiiHandle); + gToggleCheckBox = GetToken (STRING_TOKEN (TOGGLE_CHECK_BOX), 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); + gPressEnter = GetToken (STRING_TOKEN (PRESS_ENTER), gHiiHandle); + gEmptyString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); + gAreYouSure = GetToken (STRING_TOKEN (ARE_YOU_SURE), gHiiHandle); + gYesResponse = GetToken (STRING_TOKEN (ARE_YOU_SURE_YES), gHiiHandle); + gNoResponse = GetToken (STRING_TOKEN (ARE_YOU_SURE_NO), gHiiHandle); + gMiniString = GetToken (STRING_TOKEN (MINI_STRING), gHiiHandle); + gPlusString = GetToken (STRING_TOKEN (PLUS_STRING), gHiiHandle); + gMinusString = GetToken (STRING_TOKEN (MINUS_STRING), gHiiHandle); + gAdjustNumber = GetToken (STRING_TOKEN (ADJUST_NUMBER), gHiiHandle); + return ; +} + +VOID +UpdateKeyHelp ( + IN UI_MENU_OPTION *Selection, + IN BOOLEAN Selected + ) +/*++ +Routine Description: + Update key's help imformation + +Arguments: + Selection C The form that current display + Selected C Whether or not a tag be selected + +Returns: + None +--*/ +{ + UINTN SecCol; + UINTN ThdCol; + UINTN LeftColumnOfHelp; + UINTN RightColumnOfHelp; + UINTN TopRowOfHelp; + UINTN BottomRowOfHelp; + UINTN StartColumnOfHelp; + EFI_SCREEN_DESCRIPTOR LocalScreen; + + CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); + + SecCol = LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3; + ThdCol = LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) * 2 / 3; + + StartColumnOfHelp = LocalScreen.LeftColumn + 2; + LeftColumnOfHelp = LocalScreen.LeftColumn + 1; + RightColumnOfHelp = LocalScreen.RightColumn - 2; + TopRowOfHelp = LocalScreen.BottomRow - 4; + BottomRowOfHelp = LocalScreen.BottomRow - 3; + + if (gClassOfVfr == EFI_GENERAL_APPLICATION_SUBCLASS) { + return ; + } + + gST->ConOut->SetAttribute (gST->ConOut, KEYHELP_TEXT | KEYHELP_BACKGROUND); + + switch (Selection->ThisTag->Operand) { + 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: + ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND); + + if (!Selected) { + if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) { + PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gFunctionOneString); + PrintStringAt (SecCol, TopRowOfHelp, gFunctionNineString); + PrintStringAt (ThdCol, TopRowOfHelp, gFunctionTenString); + PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); + + } + + if ((Selection->ThisTag->Operand == EFI_IFR_DATE_OP) || (Selection->ThisTag->Operand == EFI_IFR_TIME_OP)) { + PrintAt ( + StartColumnOfHelp, + BottomRowOfHelp, + (CHAR16 *) L"%c%c%c%c%s", + ARROW_UP, + ARROW_DOWN, + ARROW_RIGHT, + ARROW_LEFT, + gMoveHighlight + ); + PrintStringAt (SecCol, BottomRowOfHelp, gAdjustNumber); + } else { + PrintAt (StartColumnOfHelp, BottomRowOfHelp, (CHAR16 *) L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight); + PrintStringAt (SecCol, BottomRowOfHelp, gEnterString); + } + } else { + PrintStringAt (StartColumnOfHelp, BottomRowOfHelp, gEnterCommitString); + + // + // If it is a selected numeric with manual input, display different message + // + if ((Selection->ThisTag->Operand == EFI_IFR_NUMERIC_OP) && (Selection->ThisTag->Step == 0)) { + PrintStringAt (SecCol, TopRowOfHelp, gNumericInput); + } else if (Selection->ThisTag->Operand != EFI_IFR_ORDERED_LIST_OP) { + PrintAt (SecCol, BottomRowOfHelp, (CHAR16 *) L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight); + } + + if (Selection->ThisTag->Operand == EFI_IFR_ORDERED_LIST_OP) { + PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gPlusString); + PrintStringAt (ThdCol, TopRowOfHelp, gMinusString); + } + + PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); + } + break; + + case EFI_IFR_CHECKBOX_OP: + ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND); + + if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) { + PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gFunctionOneString); + PrintStringAt (SecCol, TopRowOfHelp, gFunctionNineString); + PrintStringAt (ThdCol, TopRowOfHelp, gFunctionTenString); + PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); + } + + PrintAt (StartColumnOfHelp, BottomRowOfHelp, (CHAR16 *) L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight); + PrintStringAt (SecCol, BottomRowOfHelp, gToggleCheckBox); + break; + + case EFI_IFR_REF_OP: + case EFI_IFR_PASSWORD_OP: + case EFI_IFR_STRING_OP: + ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND); + + if (!Selected) { + if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) { + PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gFunctionOneString); + PrintStringAt (SecCol, TopRowOfHelp, gFunctionNineString); + PrintStringAt (ThdCol, TopRowOfHelp, gFunctionTenString); + PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); + } + + PrintAt (StartColumnOfHelp, BottomRowOfHelp, (CHAR16 *) L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight); + PrintStringAt (SecCol, BottomRowOfHelp, gEnterString); + } else { + if (Selection->ThisTag->Operand != EFI_IFR_REF_OP) { + PrintStringAt ( + (LocalScreen.RightColumn - GetStringWidth (gEnterCommitString) / 2) / 2, + BottomRowOfHelp, + gEnterCommitString + ); + PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); + } + } + break; + } + +} + +VOID +ExtractFormHandle ( + IN UI_MENU_OPTION *Selection, + IN EFI_FILE_FORM_TAGS *FileFormTagsHead, + IN UINTN IdValue, + OUT UINT16 *FormHandle, + OUT UINT16 *TitleToken, + OUT EFI_FORM_TAGS *FormTags + ) +{ + UINTN Index; + EFI_FILE_FORM_TAGS *FileFormTags; + EFI_FORM_TAGS LocalTags; + + FileFormTags = FileFormTagsHead; + + // + // Advance FileFormTags to the correct file's tag information. + // For instance, if Selection->IfrNumber is 3, that means the 4th + // file (0-based) in the FileFormTags linked-list contains the tag + // information. + // + for (Index = 0; Index < Selection->IfrNumber; Index++) { + FileFormTags = FileFormTags->NextFile; + } + + LocalTags = FileFormTags->FormTags; + + if (IdValue == 0) { + // + // Advance Index to the first FormOp tag information + // + for (Index = 0; FileFormTags->FormTags.Tags[Index].Operand != EFI_IFR_FORM_OP; Index++) + ; + } else { + // + // Advance Index to the FormOp with the correct ID value + // + for (; LocalTags.Next != NULL; LocalTags = *LocalTags.Next) { + for (Index = 0; LocalTags.Tags[Index].Operand != EFI_IFR_FORM_OP; Index++) + ; + if (LocalTags.Tags[Index].Id == IdValue) { + break; + } + } + } + // + // return the Form Id, Text, and the File's FormTags structure + // + *FormHandle = LocalTags.Tags[Index].Id; + *TitleToken = LocalTags.Tags[Index].Text; + *FormTags = LocalTags; + return ; +} + +EFI_STATUS +UpdateNewTagData ( + IN UINT8 *FormData, + IN UINT16 ConsistencyId, + IN UINT16 CurrentVariable, + IN EFI_FORM_TAGS *FormTags, + OUT EFI_FILE_FORM_TAGS *FileFormTags + ) +{ + EFI_STATUS Status; + UINT16 Index; + UINT16 QuestionIndex; + UINT16 NumberOfTags; + INT16 CurrTag; + UINT8 TagLength; + UINTN Count; + BOOLEAN Finished; + + // + // Initialize some Index variable and Status + // + Count = 0; + QuestionIndex = 0; + NumberOfTags = 1; + Index = 0; + Status = EFI_SUCCESS; + Finished = FALSE; + + // + // Determine the number of tags for the first form + // + GetTagCount (&FormData[Index], &NumberOfTags); + + // + // Allocate memory for our tags on the first form + // + FormTags->Tags = AllocateZeroPool (NumberOfTags * sizeof (EFI_TAG)); + ASSERT (FormTags->Tags != NULL); + + for (CurrTag = 0; FormData[Index] != EFI_IFR_END_FORM_SET_OP; CurrTag++) { + // + // Operand = IFR OpCode + // + FormTags->Tags[CurrTag].Operand = FormData[Index]; + + // + // Assume for now 0 lines occupied by this OpCode + // + FormTags->Tags[CurrTag].NumberOfLines = 0; + + // + // Determine the length of the Tag so we can later skip to the next tag in the form + // + // + // get the length + // + TagLength = FormData[Index + 1]; + // + // Operate on the Found OpCode + // + switch (FormData[Index]) { + + case EFI_IFR_FORM_OP: + case EFI_IFR_SUBTITLE_OP: + case EFI_IFR_TEXT_OP: + case EFI_IFR_REF_OP: + IfrToFormTag (FormData[Index], &FormTags->Tags[CurrTag], (VOID *) &FormData[Index], NULL); + break; + + case EFI_IFR_VARSTORE_SELECT_OP: + IfrToFormTag (FormData[Index], &FormTags->Tags[CurrTag], (VOID *) &FormData[Index], NULL); + CopyMem (&CurrentVariable, &((EFI_IFR_VARSTORE_SELECT *) &FormData[Index])->VarId, sizeof (UINT16)); + break; + + case EFI_IFR_END_FORM_OP: + FormTags->Tags[CurrTag].Operand = FormData[Index]; + FormTags->Tags[CurrTag].NumberOfLines = 0; + + Finished = TRUE; + break; + + case EFI_IFR_ORDERED_LIST_OP: + case EFI_IFR_ONE_OF_OP: + GetQuestionHeader (&FormTags->Tags[CurrTag], FormData, Index, FileFormTags, CurrentVariable); + + // + // Store away the CurrTag since what follows will be the answer that we + // need to place into the appropriate location in the tag array + // + // + // record for setting default later + // + QuestionIndex = (UINT16) CurrTag; + break; + + case EFI_IFR_ONE_OF_OPTION_OP: + IfrToFormTag (FormData[Index], &FormTags->Tags[CurrTag], (VOID *) &FormData[Index], NULL); + FormTags->Tags[QuestionIndex].Key = ((EFI_IFR_ONE_OF_OPTION *) &FormData[Index])->Key; + FormTags->Tags[QuestionIndex].ResetRequired = (BOOLEAN) (FormTags->Tags[QuestionIndex].Flags & EFI_IFR_FLAG_RESET_REQUIRED); + break; + + case EFI_IFR_CHECKBOX_OP: + GetQuestionHeader (&FormTags->Tags[CurrTag], FormData, Index, FileFormTags, CurrentVariable); + IfrToFormTag (FormData[Index], &FormTags->Tags[CurrTag], (VOID *) &FormData[Index], NULL); + break; + + case EFI_IFR_NUMERIC_OP: + GetNumericHeader (&FormTags->Tags[CurrTag], FormData, Index, (UINT16) 1, FileFormTags, CurrentVariable); + IfrToFormTag (FormData[Index], &FormTags->Tags[CurrTag], (VOID *) &FormData[Index], NULL); + break; + + case EFI_IFR_DATE_OP: + // + // Date elements come in as a Year, Month, Day. We need to process them as a country-based + // Order. It is much easier to do it here than anywhere else. + // + // For US standards - we want Month/Day/Year, thus we advance "i" +1, +2, +0 while CurrTag is +0, +1, +2 + // + GetNumericHeader ( + &FormTags->Tags[CurrTag], + FormData, + (UINT16) (Index + TagLength), + (UINT16) 0, + FileFormTags, + CurrentVariable + ); + + // + // The current language selected + the Date operand + // + FormTags->Tags[CurrTag + 1].Operand = FormData[Index]; + GetNumericHeader ( + &FormTags->Tags[CurrTag + 1], + FormData, + (UINT16) (Index + TagLength + FormData[Index + TagLength + 1]), + (UINT16) 0, + FileFormTags, + CurrentVariable + ); + + // + // The current language selected + the Date operand + // + FormTags->Tags[CurrTag + 2].Operand = FormData[Index]; + GetNumericHeader (&FormTags->Tags[CurrTag + 2], FormData, Index, (UINT16) 1, FileFormTags, CurrentVariable); + + CurrTag = (INT16) (CurrTag + 2); + + Index = (UINT16) (Index + TagLength); + // + // get the length + // + TagLength = FormData[Index + 1]; + Index = (UINT16) (Index + TagLength); + // + // get the length + // + TagLength = FormData[Index + 1]; + break; + + case EFI_IFR_TIME_OP: + GetNumericHeader (&FormTags->Tags[CurrTag], FormData, Index, (UINT16) 0, FileFormTags, CurrentVariable); + + if (Count == 2) { + // + // Override the GetQuestionHeader information - date/time are treated very differently + // + FormTags->Tags[CurrTag].NumberOfLines = 1; + Count = 0; + } else { + // + // The premise is that every date/time op-code have 3 elements, the first 2 have 0 lines + // associated with them, and the third has 1 line to allow to space beyond the choice. + // + Count++; + } + break; + + case EFI_IFR_PASSWORD_OP: + case EFI_IFR_STRING_OP: + GetQuestionHeader (&FormTags->Tags[CurrTag], FormData, Index, FileFormTags, CurrentVariable); + IfrToFormTag (FormData[Index], &FormTags->Tags[CurrTag], (VOID *) &FormData[Index], NULL); + break; + + case EFI_IFR_INCONSISTENT_IF_OP: + case EFI_IFR_SUPPRESS_IF_OP: + case EFI_IFR_GRAYOUT_IF_OP: + ConsistencyId++; + break; + + case EFI_IFR_EQ_ID_VAL_OP: + IfrToFormTag (FormData[Index], &FormTags->Tags[CurrTag], (VOID *) &FormData[Index], NULL); + FormTags->Tags[CurrTag].ConsistencyId = ConsistencyId; + break; + + case EFI_IFR_EQ_VAR_VAL_OP: + IfrToFormTag (FormData[Index], &FormTags->Tags[CurrTag], (VOID *) &FormData[Index], NULL); + FormTags->Tags[CurrTag].ConsistencyId = ConsistencyId; + break; + + case EFI_IFR_EQ_ID_ID_OP: + IfrToFormTag (FormData[Index], &FormTags->Tags[CurrTag], (VOID *) &FormData[Index], NULL); + FormTags->Tags[CurrTag].ConsistencyId = ConsistencyId; + break; + + case EFI_IFR_AND_OP: + case EFI_IFR_OR_OP: + case EFI_IFR_NOT_OP: + case EFI_IFR_TRUE_OP: + case EFI_IFR_FALSE_OP: + case EFI_IFR_GT_OP: + case EFI_IFR_GE_OP: + FormTags->Tags[CurrTag].ConsistencyId = ConsistencyId; + break; + + case EFI_IFR_EQ_ID_LIST_OP: + IfrToFormTag (FormData[Index], &FormTags->Tags[CurrTag], (VOID *) &FormData[Index], NULL); + + FormTags->Tags[CurrTag].ConsistencyId = ConsistencyId; + break; + + default: + break; + } + // + // End of switch + // + if (Finished) { + break; + } + // + // Per spec., we ignore ops that we don't know how to deal with. Skip to next tag + // + Index = (UINT16) (Index + TagLength); + } + // + // End of Index + // + return Status; +} + +VOID +ExtractDynamicFormHandle ( + IN UI_MENU_OPTION *Selection, + IN UINT8 *CallbackData, + IN EFI_FILE_FORM_TAGS *FileFormTagsHead, + IN UINTN IdValue, + OUT UINT16 *FormHandle, + OUT UINT16 *TitleToken, + OUT EFI_FORM_TAGS *FormTags + ) +/*++ + +Routine Description: + + The function does the most of the works when the EFI_TAG that + user selects on is EFI_IFR_FLAG_INTERACTIVE or EFI_IFR_PASSWORD_OP: + invoke CallBack, update the new form data. + +Arguments: + + Selection - The current selection of the form. + CallbackData - The pointer to host the data passed back by the callback function. + FileFormTagsHead - Prompt string token of the one-of box + IdValue - The current page number. + FormHandle - Output the the handle of the form. + TitleToken - Output the TitleToken of the new page. + FormTags - Output the FormFags of the new page. + +Returns: + VOID + +--*/ +{ + UINTN Index; + UINTN BackupIndex; + EFI_FILE_FORM_TAGS *FileFormTags; + EFI_FORM_TAGS *LocalTags; + EFI_FORM_CALLBACK_PROTOCOL *FormCallback; + EFI_STATUS Status; + UINTN Length; + UINT8 *Buffer; + EFI_PHYSICAL_ADDRESS CallbackHandle; + EFI_GUID TagGuid; + UINT16 TargetPage; + EFI_HII_CALLBACK_PACKET *Packet; + UINTN ScreenSize; + CHAR16 NullCharacter; + EFI_INPUT_KEY Key; + UINT16 ConsistencyId; + UINT16 CurrentVariable; + EFI_VARIABLE_DEFINITION *VariableDefinition; + EFI_IFR_DATA_ENTRY *DataEntry; + + VariableDefinition = NULL; + NullCharacter = CHAR_NULL; + + CurrentVariable = 0; + FileFormTags = FileFormTagsHead; + Length = 0; + CallbackHandle = 0; + TargetPage = (UINT16) IdValue; + Packet = NULL; + ConsistencyId = 0; + + // + // Advance FileFormTags to the correct file's tag information. + // For instance, if Selection->IfrNumber is 3, that means the 4th + // file (0-based) in the FileFormTags linked-list contains the tag + // information. + // + for (Index = 0; Index < Selection->IfrNumber; Index++) { + FileFormTags = FileFormTags->NextFile; + } + + LocalTags = &FileFormTags->FormTags; + + // + // Advance Index to the FormOp with the correct ID value + // + for (; LocalTags->Next != NULL; LocalTags = LocalTags->Next) { + if ((LocalTags->Tags[0].CallbackHandle != 0) && (CallbackHandle == 0)) { + CallbackHandle = LocalTags->Tags[0].CallbackHandle; + CopyMem (&TagGuid, &LocalTags->Tags[0].GuidValue, sizeof (EFI_GUID)); + } + + for (Index = 0; LocalTags->Tags[Index].Operand != EFI_IFR_FORM_OP; Index++) + ; + if (LocalTags->Tags[Index].Id == IdValue) { + break; + } + } + // + // If we are going to callback on a non-goto opcode, make sure we don't change pages + // + if (Selection->ThisTag->Operand != EFI_IFR_REF_OP) { + TargetPage = Selection->FormId; + } + // + // The first tag below should be the form op-code. We need to store away the + // current variable setting to ensure if we have to reload the page, that we + // can correctly restore the values for the active variable + // + CurrentVariable = Selection->Tags[0].VariableNumber; + + // + // Remember that dynamic pages in an environment where all pages are not + // dynamic require us to call back to the user to give them an opportunity + // to register fresh information in the HII database so that we can extract it. + // + Status = gBS->HandleProtocol ( + (VOID *) (UINTN) CallbackHandle, + &gEfiFormCallbackProtocolGuid, + (VOID **) &FormCallback + ); + + if (EFI_ERROR (Status)) { + gBS->FreePool (LocalTags->Tags); + return ; + } + + ExtractRequestedNvMap (FileFormTags, CurrentVariable, &VariableDefinition); + + if (Selection->ThisTag->Flags & (EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_NV_ACCESS)) { + ((EFI_IFR_DATA_ARRAY *) CallbackData)->NvRamMap = VariableDefinition->NvRamMap; + } else { + ((EFI_IFR_DATA_ARRAY *) CallbackData)->NvRamMap = NULL; + } + + if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) { + Status = FormCallback->Callback ( + FormCallback, + Selection->ThisTag->Key, + (EFI_IFR_DATA_ARRAY *) CallbackData, + &Packet + ); + } + + if (EFI_ERROR (Status)) { + // + // Restore Previous Value + // + CopyMem ( + &VariableDefinition->NvRamMap[Selection->ThisTag->StorageStart], + gPreviousValue, + Selection->ThisTag->StorageWidth + ); + + if (Packet != NULL) { + // + // Upon error, we will likely receive a string to print out + // + ScreenSize = GetStringWidth (Packet->String) / 2; + + // + // Display error popup + // + CreatePopUp (ScreenSize, 3, &NullCharacter, Packet->String, &NullCharacter); + + do { + Status = WaitForKeyStroke (&Key); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + } else { + UpdateStatusBar (INPUT_ERROR, (UINT8) 0, TRUE); + } + + } else { + if (Packet != NULL) { + // + // We need to on a non-error, look in the outbound Packet for information and update the NVRAM + // location associated with the op-code specified there. This is used on single op-code instances + // and not for when a hyperlink sent us a whole page of data. + // + DataEntry = (EFI_IFR_DATA_ENTRY *) (&Packet->DataArray + 1); + if (Packet->DataArray.EntryCount == 1) { + switch (DataEntry->OpCode) { + case EFI_IFR_STRING_OP: + case EFI_IFR_NUMERIC_OP: + case EFI_IFR_ORDERED_LIST_OP: + case EFI_IFR_ONE_OF_OP: + case EFI_IFR_CHECKBOX_OP: + CopyMem ( + &VariableDefinition->NvRamMap[Selection->ThisTag->StorageStart], + &DataEntry->Data, + Selection->ThisTag->StorageWidth + ); + break; + + case EFI_IFR_NV_ACCESS_COMMAND: + CopyMem ( + &VariableDefinition->NvRamMap[((EFI_IFR_NV_DATA *) Packet)->QuestionId], + ((EFI_IFR_NV_DATA *) Packet) + 1, + ((EFI_IFR_NV_DATA *) Packet)->StorageWidth + ); + break; + + } + + if (DataEntry->Flags & RESET_REQUIRED) { + gResetRequired = TRUE; + } + + if (DataEntry->Flags & EXIT_REQUIRED) { + gExitRequired = TRUE; + } + + if (DataEntry->Flags & SAVE_REQUIRED) { + gSaveRequired = TRUE; + } + + if (DataEntry->Flags & NV_CHANGED) { + gNvUpdateRequired = TRUE; + } + + if (DataEntry->Flags & NV_NOT_CHANGED) { + gNvUpdateRequired = FALSE; + } + } + } + } + + if (Packet != NULL) { + gBS->FreePool (Packet); + } + + for (BackupIndex = 0; LocalTags->Tags[BackupIndex].Operand != EFI_IFR_END_FORM_OP; BackupIndex++) { + switch (LocalTags->Tags[BackupIndex].Operand) { + case EFI_IFR_EQ_VAR_VAL_OP: + case EFI_IFR_EQ_ID_VAL_OP: + case EFI_IFR_EQ_ID_ID_OP: + case EFI_IFR_AND_OP: + case EFI_IFR_OR_OP: + case EFI_IFR_NOT_OP: + case EFI_IFR_TRUE_OP: + case EFI_IFR_FALSE_OP: + case EFI_IFR_GT_OP: + case EFI_IFR_GE_OP: + case EFI_IFR_EQ_ID_LIST_OP: + // + // If we encountered a ConsistencyId value, on this page they will be incremental + // So register the first value we encounter. We will pass this in when we re-create this page + // + if ((LocalTags->Tags[BackupIndex].ConsistencyId != 0) && (ConsistencyId == 0)) { + ConsistencyId = (UINT16) (LocalTags->Tags[BackupIndex].ConsistencyId - 1); + } + break; + } + } + // + // Delete the buffer associated with previous dynamic page + // We will re-allocate a buffer.... + // + gBS->FreePool (LocalTags->Tags); + + Length = 0xF000; + Buffer = AllocateZeroPool (Length); + ASSERT (Buffer != NULL); + + // + // Get the form that was updated by the callback + // + Hii->GetForms ( + Hii, + Selection->Handle, + TargetPage, + &Length, + Buffer + ); + + // + // Ok, we have the new page.....now we must purge the old page and re-allocate + // the tag page with the new data + // + UpdateNewTagData ( + Buffer, + ConsistencyId, + CurrentVariable, + LocalTags, + FileFormTags + ); + + // + // return the Form Id, Text, and the File's FormTags structure + // + *FormHandle = LocalTags->Tags[0].Id; + *TitleToken = LocalTags->Tags[0].Text; + *FormTags = *LocalTags; + + FormTags->Tags[0].CallbackHandle = CallbackHandle; + CopyMem (&FormTags->Tags[0].GuidValue, &TagGuid, sizeof (EFI_GUID)); + + return ; +} + +UI_MENU_OPTION * +SetupBrowser ( + IN UI_MENU_OPTION *Selection, + IN BOOLEAN Callback, + IN EFI_FILE_FORM_TAGS *FileFormTagsHead, + IN UINT8 *CallbackData + ) +{ + UINT16 FormHandle; + UINT16 TitleToken; + EFI_FORM_TAGS FormTags; + + gEntryNumber = -1; + gLastOpr = FALSE; + // + // Displays the Header and Footer borders + // + DisplayPageFrame (); + + // + // Id of 0 yields the getting of the top form whatever the ID is. Usually the first form in the IFR + // + ExtractFormHandle (Selection, FileFormTagsHead, 0, &FormHandle, &TitleToken, &FormTags); + + Selection = DisplayForm (Selection, FormHandle, TitleToken, FormTags, FileFormTagsHead, CallbackData); + + // + // If selection is null use the former selection + // + if (Selection == NULL) { + return Selection; + } + + if (Callback) { + return Selection; + } + + while (Selection->Tags != NULL) { + if (Selection->Previous) { + ExtractFormHandle (Selection, FileFormTagsHead, Selection->FormId, &FormHandle, &TitleToken, &FormTags); + } else { + // + // True if a hyperlink/jump is selected + // + if (Selection->ThisTag->Operand == EFI_IFR_REF_OP && Selection->ThisTag->Id != 0x0000) { + if (Selection->ThisTag->Flags & EFI_IFR_FLAG_INTERACTIVE) { + ExtractDynamicFormHandle ( + Selection, + CallbackData, + FileFormTagsHead, + Selection->ThisTag->Id, + &FormHandle, + &TitleToken, + &FormTags + ); + goto DisplayPage; + } else { + ExtractFormHandle (Selection, FileFormTagsHead, Selection->ThisTag->Id, &FormHandle, &TitleToken, &FormTags); + goto DisplayPage; + } + } + + if ((Selection->ThisTag->Flags & EFI_IFR_FLAG_INTERACTIVE) && + (Selection->ThisTag->Operand != EFI_IFR_PASSWORD_OP) + ) { + ExtractDynamicFormHandle ( + Selection, + CallbackData, + FileFormTagsHead, + Selection->FormId, + &FormHandle, + &TitleToken, + &FormTags + ); + } else { + ExtractFormHandle (Selection, FileFormTagsHead, Selection->FormId, &FormHandle, &TitleToken, &FormTags); + } + } + +DisplayPage: + // + // Displays the Header and Footer borders + // + DisplayPageFrame (); + + Selection = DisplayForm (Selection, FormHandle, TitleToken, FormTags, FileFormTagsHead, CallbackData); + + if (Selection == NULL) { + break; + } + }; + + return Selection; +} diff --git a/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Print.c b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Print.c new file mode 100644 index 0000000000..ec7bb1e174 --- /dev/null +++ b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Print.c @@ -0,0 +1,338 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Print.c + +Abstract: + + Basic Ascii AvSPrintf() function named VSPrint(). VSPrint() enables very + simple implemenation of SPrint() and Print() to support debug. + + You can not Print more than EFI_DRIVER_LIB_MAX_PRINT_BUFFER characters at a + time. This makes the implementation very simple. + + VSPrint, Print, SPrint format specification has the follwoing form + + %type + + type: + 'S','s' - argument is an Unicode string + 'c' - argument is an ascii character + '%' - Print a % + +--*/ + +#include "print.h" + +STATIC +UINTN +_IPrint ( + IN UINTN Column, + IN UINTN Row, + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *Out, + IN CHAR16 *fmt, + IN VA_LIST args + ) +// +// Display string worker for: Print, PrintAt, IPrint, IPrintAt +// +{ + CHAR16 *Buffer; + CHAR16 *BackupBuffer; + UINTN Index; + UINTN PreviousIndex; + + // + // 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; + + do { + for (; (Buffer[Index] != NARROW_CHAR) && (Buffer[Index] != WIDE_CHAR) && (Buffer[Index] != 0); Index++) { + BackupBuffer[Index] = Buffer[Index]; + } + + if (Buffer[Index] == 0) { + break; + } + // + // Null-terminate the temporary string + // + BackupBuffer[Index] = 0; + + // + // Print this out, we are about to switch widths + // + Out->OutputString (Out, &BackupBuffer[PreviousIndex]); + + // + // 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); + } else { + // + // Must be wide, set bit 7 ON + // + Out->Mode->Attribute = Out->Mode->Attribute | EFI_WIDE_ATTRIBUTE; + Out->SetAttribute (Out, Out->Mode->Attribute); + } + + Index++; + + } while (Buffer[Index] != 0); + + // + // We hit the end of the string - print it + // + Out->OutputString (Out, &BackupBuffer[PreviousIndex]); + + gBS->FreePool (Buffer); + gBS->FreePool (BackupBuffer); + return EFI_SUCCESS; +} + +UINTN +Print ( + IN CHAR16 *fmt, + ... + ) +/*++ + +Routine Description: + + Prints a formatted unicode string to the default console + +Arguments: + + fmt - Format string + +Returns: + + Length of string printed to the console + +--*/ +{ + VA_LIST args; + + VA_START (args, fmt); + return _IPrint ((UINTN) -1, (UINTN) -1, gST->ConOut, fmt, args); +} + +UINTN +PrintString ( + CHAR16 *String + ) +/*++ + +Routine Description: + + Prints a unicode string to the default console, + using L"%s" format. + +Arguments: + + String - String pointer. + +Returns: + + Length of string printed to the console + +--*/ +{ + return Print ((CHAR16 *) L"%s", String); +} + +UINTN +PrintChar ( + CHAR16 Character + ) +/*++ + +Routine Description: + + Prints a chracter to the default console, + using L"%c" format. + +Arguments: + + Character - Character to print. + +Returns: + + Length of string printed to the console. + +--*/ +{ + return Print ((CHAR16 *) L"%c", Character); +} + +/* +UINTN +PrintToken ( + IN EFI_HII_HANDLE Handle, + IN UINT16 Token, + IN CHAR16 *Language, + ... + ) +{ + VA_LIST args; + UINTN NumberOfHiiHandles; + EFI_HANDLE *HandleBuffer; + EFI_HII_PROTOCOL *Hii; + + // + // There should only be one HII image + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiHiiProtocolGuid, + NULL, + &NumberOfHiiHandles, + &HandleBuffer + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Retrieve the Hii protocol interface + // + Status = gBS->HandleProtocol ( + HandleBuffer[0], + &gEfiHiiProtocolGuid, + &Hii + ); + + Hii->GetString (Hii, Handle, Token, FALSE, Language, + + VA_START (args, fmt); + return _IPrint ((UINTN) -1, (UINTN) -1, gST->ConOut, fmt, args); +} + +*/ +UINTN +PrintAt ( + IN UINTN Column, + IN UINTN Row, + IN CHAR16 *fmt, + ... + ) +/*++ + +Routine Description: + + Prints a formatted unicode string to the default console, at + the supplied cursor position + +Arguments: + + Column, Row - The cursor position to print the string at + + fmt - Format string + +Returns: + + Length of string printed to the console + +--*/ +{ + VA_LIST args; + + VA_START (args, fmt); + return _IPrint (Column, Row, gST->ConOut, fmt, args); +} + +UINTN +PrintStringAt ( + IN UINTN Column, + IN UINTN Row, + CHAR16 *String + ) +/*++ + +Routine Description: + + Prints a unicode string to the default console, at + the supplied cursor position, using L"%s" format. + +Arguments: + + Column, Row - The cursor position to print the string at + + String - String pointer. + +Returns: + + Length of string printed to the console + +--*/ +{ + return PrintAt (Column, Row, (CHAR16 *) L"%s", String); +} + +UINTN +PrintCharAt ( + IN UINTN Column, + IN UINTN Row, + CHAR16 Character + ) +/*++ + +Routine Description: + + Prints a chracter to the default console, at + the supplied cursor position, using L"%c" format. + +Arguments: + + Column, Row - The cursor position to print the string at + + Character - Character to print. + +Returns: + + Length of string printed to the console. + +--*/ +{ + return PrintAt (Column, Row, (CHAR16 *) L"%c", Character); +} + + diff --git a/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Print.h b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Print.h new file mode 100644 index 0000000000..86feb88bdf --- /dev/null +++ b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Print.h @@ -0,0 +1,37 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Print.h + +Abstract: + + Private data for Print.c + +--*/ + +#ifndef _PRINT_H_ +#define _PRINT_H_ + +#define LEFT_JUSTIFY 0x01 +#define PREFIX_SIGN 0x02 +#define PREFIX_BLANK 0x04 +#define COMMA_TYPE 0x08 +#define LONG_TYPE 0x10 +#define PREFIX_ZERO 0x20 + +// +// Largest number of characters that can be printed out. +// +#define EFI_DRIVER_LIB_MAX_PRINT_BUFFER (80 * 4) + +#endif diff --git a/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/ProcessOptions.c b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/ProcessOptions.c new file mode 100644 index 0000000000..8a878bcf71 --- /dev/null +++ b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/ProcessOptions.c @@ -0,0 +1,1677 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ProcessOptions.c + +Abstract: + + Implementation for handling the User Interface option processing. + +Revision History + +--*/ + +#include "Setup.h" +#include "Ui.h" + +EFI_STATUS +ExtractRequestedNvMap ( + IN EFI_FILE_FORM_TAGS *FileFormTags, + IN UINT16 VariableId, + OUT EFI_VARIABLE_DEFINITION **VariableDefinition + ) +{ + *VariableDefinition = FileFormTags->VariableDefinitions; + + // + // Extract the data from the NV variable - consumer will free the buffer. + // + for (; *VariableDefinition != NULL; *VariableDefinition = (*VariableDefinition)->Next) { + // + // If there is a variable with this ID return with EFI_SUCCESS + // + if (!CompareMem (&(*VariableDefinition)->VariableId, &VariableId, sizeof (UINT16))) { + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +EFI_STATUS +ExtractNvValue ( + IN EFI_FILE_FORM_TAGS *FileFormTags, + IN UINT16 VariableId, + IN UINT16 VariableSize, + IN UINT16 OffsetValue, + OUT VOID **Buffer + ) +{ + EFI_STATUS Status; + EFI_VARIABLE_DEFINITION *VariableDefinition; + + Status = ExtractRequestedNvMap (FileFormTags, VariableId, &VariableDefinition); + + if (!EFI_ERROR (Status)) { + // + // Allocate sufficient space for the data and copy it into the outgoing buffer + // + if (VariableSize != 0) { + *Buffer = AllocateZeroPool (VariableSize); + ASSERT (*Buffer != NULL); + CopyMem (*Buffer, &VariableDefinition->NvRamMap[OffsetValue], VariableSize); + } + return EFI_SUCCESS; + } + + return Status; +} + +VOID +AdjustNvMap ( + IN EFI_FILE_FORM_TAGS *FileFormTags, + IN UI_MENU_OPTION *MenuOption + ) +{ + CHAR8 *NvRamMap; + UINTN SizeRequired; + UINTN Index; + UINTN CachedStart; + EFI_VARIABLE_DEFINITION *VariableDefinition; + + CachedStart = 0; + + SizeRequired = MenuOption->ThisTag->StorageStart + MenuOption->ThisTag->StorageWidth; + + ExtractRequestedNvMap (FileFormTags, MenuOption->Tags->VariableNumber, &VariableDefinition); + + // + // We arrived here because the current NvRamMap is too small for the new op-code to store things and + // we need to adjust the buffer to support this. + // + NvRamMap = AllocateZeroPool (SizeRequired + 1); + ASSERT (NvRamMap != NULL); + + // + // Copy current NvRamMap to the new NvRamMap + // + CopyMem (NvRamMap, VariableDefinition->NvRamMap, VariableDefinition->VariableFakeSize); + + // + // Remember, the only time we come here is because we are in the NVPlus section of the NvRamMap + // + for (Index = MenuOption->TagIndex; + (MenuOption->Tags[Index].Operand != EFI_IFR_END_FORM_OP) && (MenuOption->Tags[Index].Operand != EFI_IFR_END_ONE_OF_OP); + Index++ + ) { + + switch (MenuOption->Tags[Index].Operand) { + case EFI_IFR_ORDERED_LIST_OP: + case EFI_IFR_ONE_OF_OP: + CachedStart = MenuOption->Tags[Index].StorageStart; + break; + + case EFI_IFR_ONE_OF_OPTION_OP: + if (MenuOption->Tags[Index].Flags & EFI_IFR_FLAG_DEFAULT) { + CopyMem (&NvRamMap[CachedStart], &MenuOption->Tags[Index].Value, 2); + } + break; + + case EFI_IFR_CHECKBOX_OP: + CopyMem (&NvRamMap[MenuOption->Tags[Index].StorageStart], &MenuOption->Tags[Index].Flags, 1); + break; + + case EFI_IFR_NUMERIC_OP: + case EFI_IFR_DATE_OP: + case EFI_IFR_TIME_OP: + case EFI_IFR_STRING_OP: + case EFI_IFR_PASSWORD_OP: + CopyMem ( + &NvRamMap[MenuOption->Tags[Index].StorageStart], + &MenuOption->Tags[Index].Value, + MenuOption->Tags[Index].StorageWidth + ); + break; + + } + } + + gBS->FreePool (VariableDefinition->NvRamMap); + VariableDefinition->NvRamMap = NvRamMap; + VariableDefinition->VariableFakeSize = (UINT16) SizeRequired; +} + +EFI_STATUS +ProcessOptions ( + IN UI_MENU_OPTION *MenuOption, + IN BOOLEAN Selected, + IN EFI_FILE_FORM_TAGS *FileFormTagsHead, + IN EFI_IFR_DATA_ARRAY *PageData, + OUT CHAR16 **OptionString + ) +{ + EFI_STATUS Status; + CHAR16 *StringPtr; + UINTN Index; + UINTN CachedIndex; + EFI_FILE_FORM_TAGS *FileFormTags; + EFI_TAG *Tag; + CHAR16 FormattedNumber[6]; + UINT16 Number; + UINT16 Value; + UINT16 *ValueArray; + UINT16 *NvRamMap; + CHAR8 *TmpNvRamMap; + UINTN Default; + UINTN StringCount; + CHAR16 Character[2]; + UINTN Count; + EFI_TIME Time; + EFI_FORM_CALLBACK_PROTOCOL *FormCallback; + STRING_REF PopUp; + CHAR16 NullCharacter; + EFI_INPUT_KEY Key; + EFI_VARIABLE_DEFINITION *VariableDefinition; + BOOLEAN OrderedList; + BOOLEAN Initialized; + UINT16 KeyValue; + BOOLEAN Skip; + + FileFormTags = FileFormTagsHead; + + for (Index = 0; Index < MenuOption->IfrNumber; Index++) { + FileFormTags = FileFormTags->NextFile; + } + + OrderedList = FALSE; + Initialized = FALSE; + ValueArray = NULL; + VariableDefinition = NULL; + Skip = FALSE; + + ZeroMem (&Time, sizeof (EFI_TIME)); + + StringPtr = (CHAR16 *) L"\0"; + Tag = MenuOption->ThisTag; + ExtractRequestedNvMap (FileFormTags, Tag->VariableNumber, &VariableDefinition); + + if (Tag->StorageStart > VariableDefinition->VariableSize) { + NvRamMap = (UINT16 *) &VariableDefinition->FakeNvRamMap[Tag->StorageStart]; + } else { + NvRamMap = (UINT16 *) &VariableDefinition->NvRamMap[Tag->StorageStart]; + } + + StringCount = 0; + Character[1] = 0; + Count = 0; + Default = 0; + NullCharacter = CHAR_NULL; + FormCallback = NULL; + + if (MenuOption->ThisTag->Operand == EFI_IFR_ORDERED_LIST_OP) { + OrderedList = TRUE; + if (((UINT8 *) NvRamMap)[0] != 0x00) { + Initialized = TRUE; + } + } + + ZeroMem (FormattedNumber, 12); + + Status = gBS->HandleProtocol ( + (VOID *) (UINTN) FileFormTags->FormTags.Tags[0].CallbackHandle, + &gEfiFormCallbackProtocolGuid, + (VOID **) &FormCallback + ); + + if (*OptionString != NULL) { + gBS->FreePool (*OptionString); + *OptionString = NULL; + } + + switch (Tag->Operand) { + + case EFI_IFR_ORDERED_LIST_OP: + case EFI_IFR_ONE_OF_OP: + // + // If the op-code we are looking at is larger than the latest created NvMap - we likely encountered a dynamically + // created entry which has an expanded NvMap requirement. We won't save this information - but we need to adjust + // the NvMap so that we can properly display the information + // + if ((UINTN) (Tag->StorageStart + Tag->StorageWidth) > VariableDefinition->VariableFakeSize) { + AdjustNvMap (FileFormTags, MenuOption); + NvRamMap = (UINT16 *) &VariableDefinition->NvRamMap[Tag->StorageStart]; + } + + CachedIndex = MenuOption->TagIndex; + + // + // search for EFI_IFR_ONE_OF_OPTION_OP until you hit the EFI_IFR_END_ONE_OF_OP, + // each of the .Text in the options are going to be what gets displayed. Break each into 26 char chunks + // when hit right/left arrow allows for selection - then repopulate Tag[TagIndex] with the choice + // + for (Index = MenuOption->TagIndex; MenuOption->Tags[Index].Operand != EFI_IFR_END_ONE_OF_OP; Index++) { + // + // We found an option - which assumedly has a string. We will eventually have to support + // wrapping of strings. For now, let's pretend they don't wrap and code that up. + // + // Count how many strings there are + // + if (MenuOption->Tags[Index].Operand == EFI_IFR_ONE_OF_OPTION_OP) { + // + // If one of the options for the one-of has an interactive flag, back-define the oneof to have one too + // + if (MenuOption->Tags[Index].Flags & EFI_IFR_FLAG_INTERACTIVE) { + MenuOption->Tags[CachedIndex].Flags = (UINT8) (MenuOption->Tags[CachedIndex].Flags | EFI_IFR_FLAG_INTERACTIVE); + } + + StringCount++; + } + } + // + // We now know how many strings we will have, so we can allocate the + // space required for the array or strings. + // + *OptionString = AllocateZeroPool (StringCount * (gOptionBlockWidth + 1) * 2 * gScreenDimensions.BottomRow); + ASSERT (*OptionString); + + // + // Add left delimeter to string + // + *OptionString[0] = LEFT_ONEOF_DELIMITER; + + // + // Retrieve the current OneOf value + // + if (Selected) { + // + // Auto selection from list + // + Value = 0; + // + // Copy current setting to the seed Value + // + if (Tag->Operand == EFI_IFR_ORDERED_LIST_OP) { + ValueArray = AllocateZeroPool (MenuOption->ThisTag->StorageWidth); + ASSERT (ValueArray != NULL); + CopyMem (ValueArray, NvRamMap, MenuOption->ThisTag->StorageWidth); + } else { + CopyMem (&Value, NvRamMap, MenuOption->ThisTag->StorageWidth); + CopyMem (gPreviousValue, NvRamMap, MenuOption->ThisTag->StorageWidth); + } + + Number = Value; + if (Tag->Operand == EFI_IFR_ORDERED_LIST_OP) { + Status = GetSelectionInputPopUp (MenuOption, Tag, MenuOption->ThisTag->StorageWidth, ValueArray, &KeyValue); + } else { + Status = GetSelectionInputPopUp (MenuOption, Tag, 1, &Value, &KeyValue); + } + + if (!EFI_ERROR (Status)) { + if (Tag->Operand == EFI_IFR_ORDERED_LIST_OP) { + CopyMem (NvRamMap, ValueArray, MenuOption->ThisTag->StorageWidth); + gBS->FreePool (ValueArray); + } else { + // + // Since the value can be one byte long or two bytes long, do a CopyMem based on StorageWidth + // + CopyMem (NvRamMap, &Value, Tag->StorageWidth); + MenuOption->ThisTag->Key = KeyValue; + } + // + // If a late check is required save off the information. This is used when consistency checks + // are required, but certain values might be bound by an impossible consistency check such as + // if two questions are bound by consistency checks and each only has two possible choices, there + // would be no way for a user to switch the values. Thus we require late checking. + // + if (Tag->Flags & EFI_IFR_FLAG_LATE_CHECK) { + CopyMem (&Tag->OldValue, &Value, Tag->StorageWidth); + } else { + // + // In theory, passing the value and the Id are sufficient to determine what needs + // to be done. The Id is the key to look for the entry needed in the Inconsistency + // database. That will yields operand and ID data - and since the ID's correspond + // to the NV storage, we can determine the values for other IDs there. + // + if (ValueIsNotValid (TRUE, 0, Tag, FileFormTags, &PopUp)) { + if (PopUp == 0x0000) { + // + // Restore Old Value + // + if (!Tag->Suppress && !Tag->GrayOut) { + CopyMem (NvRamMap, &Number, MenuOption->ThisTag->StorageWidth); + } + break; + } + + StringPtr = GetToken (PopUp, MenuOption->Handle); + + CreatePopUp (GetStringWidth (StringPtr) / 2, 3, &NullCharacter, StringPtr, &NullCharacter); + + do { + Status = WaitForKeyStroke (&Key); + + switch (Key.UnicodeChar) { + + case CHAR_CARRIAGE_RETURN: + // + // Since the value can be one byte long or two bytes long, do a CopyMem based on StorageWidth + // + CopyMem (NvRamMap, &Number, MenuOption->ThisTag->StorageWidth); + gBS->FreePool (StringPtr); + break; + + default: + break; + } + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + } + } + + UpdateStatusBar (NV_UPDATE_REQUIRED, Tag->Flags, TRUE); + } else { + if (Tag->Operand == EFI_IFR_ORDERED_LIST_OP) { + gBS->FreePool (ValueArray); + } + + return EFI_SUCCESS; + } + } else { + for (Index = MenuOption->TagIndex; MenuOption->Tags[Index].Operand != EFI_IFR_END_ONE_OF_OP; Index++) { + // + // We found an option - which assumedly has a string. We will eventually have to support + // wrapping of strings. For now, let's pretend they don't wrap and code that up. + // + if (MenuOption->Tags[Index].Operand == EFI_IFR_ONE_OF_OPTION_OP) { + if (OrderedList) { + if (!Initialized) { + // + // If the first entry is invalid, then the "default" settings are based on what is reflected + // in the order of the op-codes + // + ((UINT8 *) NvRamMap)[Index - MenuOption->TagIndex - 1] = (UINT8) MenuOption->Tags[Index].Value; + } + // + // Only display 3 lines of stuff at most + // + if ((Index - MenuOption->TagIndex) > ORDERED_LIST_SIZE) { + break; + } + + if (((Index - MenuOption->TagIndex) != 1) && !Skip) { + Character[0] = LEFT_ONEOF_DELIMITER; + NewStrCat (OptionString[0], Character); + } + + MenuOption->ThisTag->NumberOfLines = (UINT16) (Index - MenuOption->TagIndex); + if (!Initialized) { + StringPtr = GetToken (MenuOption->Tags[Index].Text, MenuOption->Handle); + } else { + for (Value = (UINT16) (MenuOption->TagIndex + 1); + MenuOption->Tags[Value].Operand != EFI_IFR_END_ONE_OF_OP; + Value++ + ) { + if (MenuOption->Tags[Value].Value == ((UINT8 *) NvRamMap)[Index - MenuOption->TagIndex - 1]) { + StringPtr = GetToken (MenuOption->Tags[Value].Text, MenuOption->Handle); + break; + } + } + + if (MenuOption->Tags[Value].Operand == EFI_IFR_END_ONE_OF_OP) { + Skip = TRUE; + continue; + } + } + + Skip = FALSE; + NewStrCat (OptionString[0], StringPtr); + Character[0] = RIGHT_ONEOF_DELIMITER; + NewStrCat (OptionString[0], Character); + Character[0] = CHAR_CARRIAGE_RETURN; + NewStrCat (OptionString[0], Character); + + // + // Remove Buffer allocated for StringPtr after it has been used. + // + gBS->FreePool (StringPtr); + } else { + // + // The option value is the same as what is stored in NV store. Print this. + // + if (!CompareMem (&(MenuOption->Tags[Index].Value), NvRamMap, MenuOption->ThisTag->StorageWidth)) { + StringPtr = GetToken (MenuOption->Tags[Index].Text, MenuOption->Handle); + NewStrCat (OptionString[0], StringPtr); + Character[0] = RIGHT_ONEOF_DELIMITER; + NewStrCat (OptionString[0], Character); + // + // Remove Buffer allocated for StringPtr after it has been used. + // + gBS->FreePool (StringPtr); + Default = 0; + break; + } + + if ((MenuOption->Tags[Index].Flags & EFI_IFR_FLAG_DEFAULT) == 1) { + Default = MenuOption->Tags[Index].Text; + Value = MenuOption->Tags[Index].Value; + }; + } + } + } + // + // We didn't find a value that matched a setting in the NVRAM Map - display default - set default + // + if (Default != 0) { + // + // Since the value can be one byte long or two bytes long, do a CopyMem based on StorageWidth + // + CopyMem (NvRamMap, &Value, MenuOption->ThisTag->StorageWidth); + + StringPtr = GetToken ((UINT16) Default, MenuOption->Handle); + NewStrCat (OptionString[0], StringPtr); + Character[0] = RIGHT_ONEOF_DELIMITER; + NewStrCat (OptionString[0], Character); + // + // Remove Buffer allocated for StringPtr after it has been used. + // + gBS->FreePool (StringPtr); + } + } + break; + + case EFI_IFR_CHECKBOX_OP: + // + // If the op-code we are looking at is larger than the latest created NvMap - we likely encountered a dynamically + // created entry which has an expanded NvMap requirement. We won't save this information - but we need to adjust + // the NvMap so that we can properly display the information + // + if ((UINTN) (Tag->StorageStart + Tag->StorageWidth) > VariableDefinition->VariableFakeSize) { + AdjustNvMap (FileFormTags, MenuOption); + NvRamMap = (UINT16 *) &VariableDefinition->NvRamMap[Tag->StorageStart]; + } + + Default = Tag->Flags & 1; + // + // If hit spacebar, set or unset Tag[TagIndex].Flags based on it's previous value - BOOLEAN + // + *OptionString = AllocateZeroPool ((gOptionBlockWidth + 1) * 2 * gScreenDimensions.BottomRow); + ASSERT (*OptionString); + + // + // Since Checkboxes are BOOLEAN values, bit 0 of the Flags bit defines the default option, therefore, if + // the default option (only one option for checkboxes) is on, then the default value is on. Tag.Default is not + // an active field for Checkboxes. + // + StrnCpy (OptionString[0], (CHAR16 *) LEFT_CHECKBOX_DELIMITER, 1); + + // + // Since this is a BOOLEAN operation, flip bit 0 upon selection + // + if (Selected) { + Tag->Value = (UINT16) (Tag->Value ^ 1); + *(UINT8 *) NvRamMap = (UINT8) (Tag->Value & 1); + UpdateStatusBar (NV_UPDATE_REQUIRED, Tag->Flags, TRUE); + } + + if ((*(UINT8 *) NvRamMap & 1) == 0x01) { + NewStrCat (OptionString[0], (CHAR16 *) CHECK_ON); + // + // If someone reset default variables - we may need to reload from our NvMapping.... + // + Tag->Value = *(UINT8 *) NvRamMap; + } else { + // + // If someone reset default variables - we may need to reload from our NvMapping.... + // + NewStrCat (OptionString[0], (CHAR16 *) CHECK_OFF); + Tag->Value = *(UINT8 *) NvRamMap; + } + + NewStrCat (OptionString[0], (CHAR16 *) RIGHT_CHECKBOX_DELIMITER); + NewStrCat (OptionString[0], StringPtr); + break; + + case EFI_IFR_NUMERIC_OP: + // + // If the op-code we are looking at is larger than the latest created NvMap - we likely encountered a dynamically + // created entry which has an expanded NvMap requirement. We won't save this information - but we need to adjust + // the NvMap so that we can properly display the information + // + if ((UINTN) (Tag->StorageStart + Tag->StorageWidth) > VariableDefinition->VariableFakeSize) { + AdjustNvMap (FileFormTags, MenuOption); + NvRamMap = (UINT16 *) &VariableDefinition->NvRamMap[Tag->StorageStart]; + } + + *OptionString = AllocateZeroPool ((gOptionBlockWidth + 1) * 2 * gScreenDimensions.BottomRow); + ASSERT (*OptionString); + + // + // Add left delimeter to string + // + *OptionString[0] = LEFT_NUMERIC_DELIMITER; + + // + // Retrieve the current numeric value + // + if (Selected) { + // + // Go ask for input + // + if (Tag->Step == 0) { + // + // Manual Input + // + Status = GetNumericInput (MenuOption, FileFormTagsHead, TRUE, Tag, REGULAR_NUMERIC, &Number); + if (!EFI_ERROR (Status)) { + CopyMem (gPreviousValue, NvRamMap, MenuOption->ThisTag->StorageWidth); + UpdateStatusBar (NV_UPDATE_REQUIRED, Tag->Flags, TRUE); + + // + // Since the value can be one byte long or two bytes long, do a CopyMem based on StorageWidth + // + CopyMem (NvRamMap, &Number, MenuOption->ThisTag->StorageWidth); + } else { + return EFI_SUCCESS; + } + } else { + // + // Auto selection from list + // + if ((((Tag->StorageWidth == 1) && (UINT8) (*NvRamMap) > Tag->Maximum) || ((UINT8) (*NvRamMap) < Tag->Minimum)) || + (((Tag->StorageWidth == 2) && *NvRamMap > Tag->Maximum) || (*NvRamMap < Tag->Minimum)) + ) { + // + // Seed Number with valid value if currently invalid + // + Number = Tag->Default; + } else { + if (Tag->StorageWidth == 1) { + Number = (UINT8) (*NvRamMap); + } else { + Number = *NvRamMap; + } + } + + Status = GetNumericInput (MenuOption, FileFormTagsHead, FALSE, Tag, REGULAR_NUMERIC, &Number); + if (!EFI_ERROR (Status)) { + CopyMem (gPreviousValue, NvRamMap, MenuOption->ThisTag->StorageWidth); + UpdateStatusBar (NV_UPDATE_REQUIRED, Tag->Flags, TRUE); + + // + // Since the value can be one byte long or two bytes long, do a CopyMem based on StorageWidth + // + CopyMem (NvRamMap, &Number, MenuOption->ThisTag->StorageWidth); + } else { + return EFI_SUCCESS; + } + } + } else { + if (((Tag->StorageWidth == 1) && (UINT8) (*NvRamMap) <= Tag->Maximum && (UINT8) (*NvRamMap) >= Tag->Minimum) || + ((Tag->StorageWidth == 2) && *NvRamMap <= Tag->Maximum && *NvRamMap >= Tag->Minimum) + ) { + if (Tag->StorageWidth == 1) { + Number = (UINT8) (*NvRamMap); + } else { + Number = *NvRamMap; + } + UnicodeValueToString ( + FormattedNumber, + FALSE, + (UINTN) Number, + (sizeof (FormattedNumber) / sizeof (FormattedNumber[0])) + ); + Number = (UINT16) GetStringWidth (FormattedNumber); + StrnCpy (OptionString[0] + 1, FormattedNumber, Number); + } else { + // + // If *NvRamMap isn't within parameters, set it to within parameters + // + // + // Since the value can be one byte long or two bytes long, do a CopyMem based on StorageWidth + // + CopyMem (NvRamMap, &Tag->Default, MenuOption->ThisTag->StorageWidth); + Number = Tag->Default; + + UnicodeValueToString ( + FormattedNumber, + FALSE, + (UINTN) Number, + (sizeof (FormattedNumber) / sizeof (FormattedNumber[0])) + ); + Number = (UINT16) GetStringWidth (FormattedNumber); + StrnCpy (OptionString[0] + 1, FormattedNumber, Number); + } + + *(OptionString[0] + Number / 2) = RIGHT_NUMERIC_DELIMITER; + NewStrCat (OptionString[0] + (Number / 2) + 1, StringPtr); + } + break; + + case EFI_IFR_DATE_OP: + // + // If the op-code we are looking at is larger than the latest created NvMap - we likely encountered a dynamically + // created entry which has an expanded NvMap requirement. We won't save this information - but we need to adjust + // the NvMap so that we can properly display the information + // + if ((UINTN) (Tag->StorageStart + Tag->StorageWidth) > VariableDefinition->VariableFakeSize) { + AdjustNvMap (FileFormTags, MenuOption); + NvRamMap = (UINT16 *) &VariableDefinition->NvRamMap[Tag->StorageStart]; + } + + Status = gRT->GetTime (&Time, NULL); + if (EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + // + // This for loop advances Index till it points immediately after a date entry. We can then + // subtract MenuOption->TagIndex from Index and find out relative to the start of the Date + // structure which field we were in. For instance, if TagIndex was 52, and we advanced Index + // to 53 and found it to no longer point to a date operand, we were pointing to the last of 3 + // date operands. + // + // + // This has BUGBUG potential....fix this - if someone wants to ask two DATE questions in a row.....code + // against such silliness. + // + // Also, we want to internationalize the order of the date information. We need to code for it as well. + // + for (Index = MenuOption->TagIndex; MenuOption->Tags[Index].Operand == EFI_IFR_DATE_OP; Index++) + ; + + // + // Count 0 = We entered on the first Date operand + // Count 1 = We entered on the second Date operand + // Count 2 = We entered on the third Date operand + // + Count = 3 - (Index - MenuOption->TagIndex); + if (Count > 2) { + return EFI_SUCCESS; + } + // + // This is similar to numerics, except for the following: + // We will under normal circumstances get 3 consecutive calls + // to process this opcodes data. + // + *OptionString = AllocateZeroPool ((gOptionBlockWidth + 1) * 2 * gScreenDimensions.BottomRow); + ASSERT (*OptionString); + + switch (Count) { + case 0: + if (Selected) { + Number = (UINT16) Time.Month; + + if (Tag->Step == 0) { + MenuOption->OptCol++; + Status = GetNumericInput (MenuOption, FileFormTagsHead, TRUE, Tag, DATE_NUMERIC, &Number); + } else { + // + // Seed value with current setting + // + Tag->Value = (UINT16) Time.Month; + Status = GetNumericInput (MenuOption, FileFormTagsHead, FALSE, Tag, DATE_NUMERIC, &Number); + } + + if (!EFI_ERROR (Status)) { + Time.Month = (UINT8) Number; + gRT->SetTime (&Time); + } + } + + VariableDefinition->FakeNvRamMap[Tag->Id] = Time.Month; + *OptionString[0] = LEFT_NUMERIC_DELIMITER; + + UnicodeValueToString ( + FormattedNumber, + FALSE, + (UINTN) Time.Month, + (sizeof (FormattedNumber) / sizeof (FormattedNumber[0])) + ); + Number = (UINT16) GetStringWidth (FormattedNumber); + + if (Number == 4) { + FormattedNumber[2] = FormattedNumber[1]; + FormattedNumber[1] = FormattedNumber[0]; + FormattedNumber[0] = L'0'; + Number = 6; + } + + StrnCpy (OptionString[0] + 1, FormattedNumber, Number); + *(OptionString[0] + Number / 2) = DATE_SEPARATOR; + StrCat (OptionString[0] + (Number / 2) + 1, StringPtr); + break; + + case 1: + if (Selected) { + Number = (UINT16) Time.Day; + + if (Tag->Step == 0) { + Status = GetNumericInput (MenuOption, FileFormTagsHead, TRUE, Tag, DATE_NUMERIC, &Number); + } else { + // + // Seed value with current setting + // + Tag->Value = (UINT16) Time.Day; + Status = GetNumericInput (MenuOption, FileFormTagsHead, FALSE, Tag, DATE_NUMERIC, &Number); + } + + if (!EFI_ERROR (Status)) { + Time.Day = (UINT8) Number; + gRT->SetTime (&Time); + } + } + + VariableDefinition->FakeNvRamMap[Tag->Id] = Time.Day; + SetUnicodeMem (OptionString[0], 4, L' '); + + UnicodeValueToString ( + FormattedNumber, + FALSE, + (UINTN) Time.Day, + (sizeof (FormattedNumber) / sizeof (FormattedNumber[0])) + ); + Number = (UINT16) GetStringWidth (FormattedNumber); + if (Number == 4) { + FormattedNumber[2] = FormattedNumber[1]; + FormattedNumber[1] = FormattedNumber[0]; + FormattedNumber[0] = L'0'; + Number = 6; + } + + StrnCpy (OptionString[0] + 4, FormattedNumber, Number); + *(OptionString[0] + Number / 2 + 3) = DATE_SEPARATOR; + StrCat (OptionString[0] + (Number / 2) + 4, StringPtr); + break; + + case 2: + if (Selected) { + Number = (UINT16) Time.Year; + + if (Tag->Step == 0) { + Status = GetNumericInput (MenuOption, FileFormTagsHead, TRUE, Tag, DATE_NUMERIC, &Number); + } else { + // + // Seed value with current setting + // + Status = GetNumericInput (MenuOption, FileFormTagsHead, FALSE, Tag, DATE_NUMERIC, &Number); + } + + if (!EFI_ERROR (Status)) { + Time.Year = (UINT16) Number; + gRT->SetTime (&Time); + } + } + + Tag->Value = (UINT16) Time.Year; + VariableDefinition->FakeNvRamMap[Tag->Id] = (UINT8) Tag->Value; + VariableDefinition->FakeNvRamMap[Tag->Id + 1] = (UINT8) (Tag->Value >> 8); + SetUnicodeMem (OptionString[0], 7, L' '); + UnicodeValueToString ( + FormattedNumber, + FALSE, + (UINTN) Time.Year, + (sizeof (FormattedNumber) / sizeof (FormattedNumber[0])) + ); + Number = (UINT16) GetStringWidth (FormattedNumber); + StrnCpy (OptionString[0] + 7, FormattedNumber, Number); + *(OptionString[0] + Number / 2 + 6) = RIGHT_NUMERIC_DELIMITER; + StrCat (OptionString[0] + (Number / 2) + 7, StringPtr); + break; + } + + break; + + // + // BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG + // We need to add code to support the NVRam storage version of Date - this is the 1% case where someone + // might want to set an alarm and actually preserve the data in NVRam so a driver can pick up the instruction + // BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG + // + case EFI_IFR_TIME_OP: + // + // If the op-code we are looking at is larger than the latest created NvMap - we likely encountered a dynamically + // created entry which has an expanded NvMap requirement. We won't save this information - but we need to adjust + // the NvMap so that we can properly display the information + // + if ((UINTN) (Tag->StorageStart + Tag->StorageWidth) > VariableDefinition->VariableFakeSize) { + AdjustNvMap (FileFormTags, MenuOption); + NvRamMap = (UINT16 *) &VariableDefinition->NvRamMap[Tag->StorageStart]; + } + + Status = gRT->GetTime (&Time, NULL); + if (EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + // + // This is similar to numerics, except for the following: + // We will under normal circumstances get 3 consecutive calls + // to process this opcodes data. + // + *OptionString = AllocateZeroPool ((gOptionBlockWidth + 1) * 2 * gScreenDimensions.BottomRow); + ASSERT (*OptionString); + + // + // This for loop advances Index till it points immediately after a date entry. We can then + // subtract MenuOption->TagIndex from Index and find out relative to the start of the Date + // structure which field we were in. For instance, if TagIndex was 52, and we advanced Index + // to 53 and found it to no longer point to a date operand, we were pointing to the last of 3 + // date operands. + // + for (Index = MenuOption->TagIndex; MenuOption->Tags[Index].Operand == EFI_IFR_TIME_OP; Index++) + ; + // + // Count 0 = We entered on the first Date operand + // Count 1 = We entered on the second Date operand + // Count 2 = We entered on the third Date operand + // + Count = 3 - (Index - MenuOption->TagIndex); + if (Count > 2) { + return EFI_SUCCESS; + } + + switch (Count) { + case 0: + Number = Time.Hour; + break; + + case 1: + Number = Time.Minute; + break; + + case 2: + Number = Time.Second; + } + // + // Retrieve the current numeric value + // + if (Selected) { + // + // Go ask for input + // + if (Tag->Step == 0) { + // + // Manual Input + // + Status = GetNumericInput (MenuOption, FileFormTagsHead, TRUE, Tag, TIME_NUMERIC, &Number); + if (!EFI_ERROR (Status)) { + *NvRamMap = Number; + Time.Nanosecond = 0; + gRT->SetTime (&Time); + } else { + return EFI_SUCCESS; + } + } else { + // + // Auto selection from list + // + Status = GetNumericInput (MenuOption, FileFormTagsHead, FALSE, Tag, TIME_NUMERIC, &Number); + if (!EFI_ERROR (Status)) { + *NvRamMap = Number; + } else { + return EFI_SUCCESS; + } + } + + switch (Count) { + case 0: + Time.Hour = (UINT8) Number; + break; + + case 1: + Time.Minute = (UINT8) Number; + break; + + case 2: + Time.Second = (UINT8) Number; + } + + Time.Nanosecond = 0; + gRT->SetTime (&Time); + } else { + switch (Count) { + case 0: + *OptionString[0] = LEFT_NUMERIC_DELIMITER; + UnicodeValueToString ( + FormattedNumber, + FALSE, + (UINTN) Time.Hour, + (sizeof (FormattedNumber) / sizeof (FormattedNumber[0])) + ); + Number = (UINT16) GetStringWidth (FormattedNumber); + if (Number == 4) { + FormattedNumber[2] = FormattedNumber[1]; + FormattedNumber[1] = FormattedNumber[0]; + FormattedNumber[0] = L'0'; + Number = 6; + } + + StrnCpy (OptionString[0] + 1, FormattedNumber, Number); + *(OptionString[0] + Number / 2) = TIME_SEPARATOR; + StrCat (OptionString[0] + (Number / 2) + 1, StringPtr); + break; + + case 1: + SetUnicodeMem (OptionString[0], 4, L' '); + UnicodeValueToString ( + FormattedNumber, + FALSE, + (UINTN) Time.Minute, + (sizeof (FormattedNumber) / sizeof (FormattedNumber[0])) + ); + Number = (UINT16) GetStringWidth (FormattedNumber); + if (Number == 4) { + FormattedNumber[2] = FormattedNumber[1]; + FormattedNumber[1] = FormattedNumber[0]; + FormattedNumber[0] = L'0'; + Number = 6; + } + + StrnCpy (OptionString[0] + 4, FormattedNumber, Number); + *(OptionString[0] + Number / 2 + 3) = TIME_SEPARATOR; + StrCat (OptionString[0] + (Number / 2) + 4, StringPtr); + break; + + case 2: + SetUnicodeMem (OptionString[0], 7, L' '); + UnicodeValueToString ( + FormattedNumber, + FALSE, + (UINTN) Time.Second, + (sizeof (FormattedNumber) / sizeof (FormattedNumber[0])) + ); + Number = (UINT16) GetStringWidth (FormattedNumber); + if (Number == 4) { + FormattedNumber[2] = FormattedNumber[1]; + FormattedNumber[1] = FormattedNumber[0]; + FormattedNumber[0] = L'0'; + Number = 6; + } + + StrnCpy (OptionString[0] + 7, FormattedNumber, Number); + *(OptionString[0] + Number / 2 + 6) = RIGHT_NUMERIC_DELIMITER; + StrCat (OptionString[0] + (Number / 2) + 7, StringPtr); + break; + } + // + // BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG + // We need to add code to support the NVRam storage version of Date - this is the 1% case where someone + // might want to set an alarm and actually preserve the data in NVRam so a driver can pick up the instruction + // BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG + // + } + break; + + case EFI_IFR_STRING_OP: + // + // If the op-code we are looking at is larger than the latest created NvMap - we likely encountered a dynamically + // created entry which has an expanded NvMap requirement. We won't save this information - but we need to adjust + // the NvMap so that we can properly display the information + // + if ((UINTN) (Tag->StorageStart + Tag->StorageWidth) > VariableDefinition->VariableFakeSize) { + AdjustNvMap (FileFormTags, MenuOption); + NvRamMap = (UINT16 *) &VariableDefinition->NvRamMap[Tag->StorageStart]; + } + + *OptionString = AllocateZeroPool ((gOptionBlockWidth + 1) * 2 * gScreenDimensions.BottomRow); + ASSERT (*OptionString); + + if (Selected) { + StringPtr = AllocateZeroPool (Tag->Maximum); + ASSERT (StringPtr); + + Status = ReadString (MenuOption, StringPtr); + + if (!EFI_ERROR (Status)) { + CopyMem (gPreviousValue, NvRamMap, MenuOption->ThisTag->StorageWidth); + CopyMem (&VariableDefinition->NvRamMap[Tag->StorageStart], StringPtr, Tag->StorageWidth); + + UpdateStatusBar (NV_UPDATE_REQUIRED, Tag->Flags, TRUE); + } + + gBS->FreePool (StringPtr); + return Status; + } else { + for (Index = 0; Index < gOptionBlockWidth; Index++) { + if (VariableDefinition->NvRamMap[Tag->StorageStart + (Index * 2)] != 0x0000) { + CopyMem (OptionString[0] + Index, &VariableDefinition->NvRamMap[Tag->StorageStart + (Index * 2)], 2); + } else { + if (Index == 0) { + *(OptionString[0] + Index) = '_'; + *(OptionString[0] + 1 + Index) = 0; + } + break; + } + } + + return Status; + } + + case EFI_IFR_PASSWORD_OP: + // + // If the op-code we are looking at is larger than the latest created NvMap - we likely encountered a dynamically + // created entry which has an expanded NvMap requirement. We won't save this information - but we need to adjust + // the NvMap so that we can properly display the information + // + if ((UINTN) (Tag->StorageStart + Tag->StorageWidth) > VariableDefinition->VariableFakeSize) { + AdjustNvMap (FileFormTags, MenuOption); + NvRamMap = (UINT16 *) &VariableDefinition->NvRamMap[Tag->StorageStart]; + } + + if (Selected) { + StringPtr = AllocateZeroPool (Tag->Maximum); + ASSERT (StringPtr); + + // + // If interactive, read the password and do the appropriate callbacks in that routine. + // Since interactive passwords assume to handle the password data in a separate variable + // storage, we don't need to do more than what is below for password callbacks + // + if (Tag->Flags & EFI_IFR_FLAG_INTERACTIVE) { + MenuOption->Tags[0].CallbackHandle = FileFormTags->FormTags.Tags[0].CallbackHandle; + Status = ReadPassword (MenuOption, TRUE, Tag, PageData, FALSE, FileFormTags, StringPtr); + ZeroMem (StringPtr, Tag->Maximum); + + if (EFI_ERROR (Status)) { + if (Status == EFI_NOT_READY) { + gBS->FreePool (StringPtr); + return EFI_SUCCESS; + } + } + + Status = ReadPassword (MenuOption, TRUE, Tag, PageData, TRUE, FileFormTags, StringPtr); + gBS->FreePool (StringPtr); + return EFI_SUCCESS; + } + + for (Index = 0; Index < Tag->Maximum; Index++) { + if (VariableDefinition->NvRamMap[Tag->StorageStart + Index] != 0x00) { + // + // There is something there! Prompt for password + // + Status = ReadPassword (MenuOption, TRUE, Tag, PageData, FALSE, FileFormTags, StringPtr); + if (EFI_ERROR (Status)) { + gBS->FreePool (StringPtr); + return EFI_SUCCESS; + } + + if (Tag->Encoding == 1) { + EncodePassword (StringPtr, (UINT8) Tag->Maximum); + Status = CompareMem (StringPtr, &VariableDefinition->NvRamMap[Tag->StorageStart], Tag->Maximum); + } else { + Status = CompareMem (StringPtr, &VariableDefinition->NvRamMap[Tag->StorageStart], Tag->Maximum); + } + + if (Status != 0) { + gBS->FreePool (StringPtr); + return EFI_SUCCESS; + } else { + break; + } + } + } + // + // Clean the string + // + ZeroMem (StringPtr, Tag->Maximum); + + // + // No password set! Go ahead and prompt the user for a password. + // + Status = ReadPassword (MenuOption, FALSE, Tag, PageData, FALSE, FileFormTags, StringPtr); + + if (EFI_ERROR (Status)) { + // + // User couldn't figure out how to type two identical passwords + // + gBS->FreePool (StringPtr); + return EFI_SUCCESS; + } + // + // Very simple example of how one MIGHT do password encoding + // + if (Tag->Encoding == 1) { + EncodePassword (StringPtr, (UINT8) Tag->Maximum); + } + + TmpNvRamMap = AllocatePool (VariableDefinition->VariableSize); + ASSERT (TmpNvRamMap != NULL); + + Count = VariableDefinition->VariableSize; + + if ((FormCallback != NULL) && (FormCallback->NvRead != NULL)) { + Status = FormCallback->NvRead ( + FormCallback, + VariableDefinition->VariableName, + &VariableDefinition->Guid, + NULL, + &Count, + (VOID *) TmpNvRamMap + ); + } else { + Status = gRT->GetVariable ( + VariableDefinition->VariableName, + &VariableDefinition->Guid, + NULL, + &Count, + (VOID *) TmpNvRamMap + ); + } + + CopyMem (&VariableDefinition->NvRamMap[Tag->StorageStart], StringPtr, Tag->StorageWidth); + CopyMem (&TmpNvRamMap[Tag->StorageStart], StringPtr, Tag->StorageWidth); + + if ((FormCallback != NULL) && (FormCallback->NvWrite != NULL)) { + Status = FormCallback->NvWrite ( + FormCallback, + VariableDefinition->VariableName, + &VariableDefinition->Guid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + VariableDefinition->VariableSize, + (VOID *) TmpNvRamMap, + &gResetRequired + ); + } else { + Status = gRT->SetVariable ( + VariableDefinition->VariableName, + &VariableDefinition->Guid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + VariableDefinition->VariableSize, + (VOID *) TmpNvRamMap + ); + } + + gBS->FreePool (TmpNvRamMap); + gBS->FreePool (StringPtr); + break; + } + + default: + break; + } + + return EFI_SUCCESS; +} + +VOID +ProcessHelpString ( + IN CHAR16 *StringPtr, + OUT CHAR16 **FormattedString, + IN UINTN RowCount + ) +{ + UINTN CurrIndex; + UINTN PrevIndex; + UINTN SearchIndex; + UINTN PrevSearchIndex; + UINTN StringCount; + UINTN PageCount; + + StringCount = 0; + PrevIndex = 0; + CurrIndex = gHelpBlockWidth - 1; + + if (*FormattedString != NULL) { + gBS->FreePool (*FormattedString); + *FormattedString = NULL; + } + + for (; CurrIndex > PrevIndex; CurrIndex--) { + // + // In the case where the string ended and a new one is immediately after it + // we need to check for the null-terminator and reset the CurrIndex + // + SearchIndex = CurrIndex; + PrevSearchIndex = PrevIndex; + + for (; SearchIndex > PrevSearchIndex; PrevSearchIndex++) { + if ((StringPtr[PrevSearchIndex] == CHAR_NULL) || (StringPtr[PrevSearchIndex] == CHAR_LINEFEED)) { + CurrIndex = PrevSearchIndex; + break; + } + + if (StringPtr[PrevSearchIndex] == CHAR_CARRIAGE_RETURN) { + if (StringPtr[PrevSearchIndex + 1] == CHAR_LINEFEED) { + // + // Found a "\n",advance to the next new line. + // + CurrIndex = PrevSearchIndex + 1; + break; + } else { + // + // Found a "\r",return to the start of the current line. + // + PrevIndex = PrevSearchIndex + 1; + CurrIndex = PrevSearchIndex + gHelpBlockWidth; + continue; + } + } + } + + // + // End of the string, thus stop counting. + // + if (StringPtr[CurrIndex] == CHAR_NULL) { + StringCount++; + break; + } + // + // The premise is that for every HELP_BLOCK_WIDTH we rewind + // until we find the first space. That is the delimiter for + // the string, and we will then advance our CurrIndex another + // HELP_BLOCK_WIDTH and continue the process breaking the larger + // string into chunks that fit within the HELP_BLOCK_WIDTH requirements. + // + if (StringPtr[CurrIndex] == CHAR_SPACE) { + // + // How many strings have been found? + // + StringCount++; + PrevIndex = CurrIndex + 1; + CurrIndex = CurrIndex + gHelpBlockWidth; + } + // + // Found a Linefeed, advance to the next line. + // + if (StringPtr[CurrIndex] == CHAR_LINEFEED) { + StringCount++; + PrevIndex = CurrIndex + 1; + CurrIndex = CurrIndex + gHelpBlockWidth; + } + } + // + // endfor + // + // Round the value up one (doesn't hurt) + // + StringCount++; + + // + // Determine the number of pages this help string occupies + // + PageCount = StringCount / RowCount; + if (StringCount % RowCount > 0) { + PageCount++; + } + // + // Convert the PageCount into lines so we can allocate the correct buffer size + // + StringCount = PageCount * RowCount; + + // + // We now know how many strings we will have, so we can allocate the + // space required for the array or strings. + // + *FormattedString = AllocateZeroPool ((StringCount) * (gHelpBlockWidth + 1) * 2); + ASSERT (*FormattedString); + + StringCount = 0; + PrevIndex = 0; + CurrIndex = gHelpBlockWidth - 1; + + for (; CurrIndex > PrevIndex; CurrIndex--) { + // + // In the case where the string ended and a new one is immediately after it + // we need to check for the null-terminator and reset the CurrIndex + // + SearchIndex = CurrIndex; + PrevSearchIndex = PrevIndex; + + for (; SearchIndex > PrevSearchIndex; PrevSearchIndex++) { + if ((StringPtr[PrevSearchIndex] == CHAR_NULL) || (StringPtr[PrevSearchIndex] == CHAR_LINEFEED)) { + CurrIndex = PrevSearchIndex; + break; + } + + if (StringPtr[PrevSearchIndex] == CHAR_CARRIAGE_RETURN) { + if (StringPtr[PrevSearchIndex + 1] == CHAR_LINEFEED) { + // + // Found a "\n",advance to the next new line. + // + CurrIndex = PrevSearchIndex + 1; + break; + } else { + // + // Found a "\r",return to the start of the current line. + // + PrevIndex = PrevSearchIndex + 1; + CurrIndex = PrevSearchIndex + gHelpBlockWidth; + continue; + } + } + } + + // + // End of the string, thus stop counting. + // + if (StringPtr[CurrIndex] == CHAR_NULL) { + // + // Copy the fragment to the FormattedString buffer + // + StrnCpy ((FormattedString[0] + StringCount * gHelpBlockWidth), &StringPtr[PrevIndex], CurrIndex - PrevIndex); + StringCount++; + break; + } + // + // The premise is that for every HELP_BLOCK_WIDTH we rewind + // until we find the first space. That is the delimiter for + // the string, and we will then advance our CurrIndex another + // HELP_BLOCK_WIDTH and continue the process breaking the larger + // string into chunks that fit within the HELP_BLOCK_WIDTH requirements. + // + if (StringPtr[CurrIndex] == CHAR_SPACE) { + // + // Copy the fragment to the FormattedString buffer + // + StrnCpy ((FormattedString[0] + StringCount * gHelpBlockWidth), &StringPtr[PrevIndex], CurrIndex - PrevIndex); + StringCount++; + PrevIndex = CurrIndex + 1; + CurrIndex = CurrIndex + gHelpBlockWidth; + } + // + // Found a LineFeed, advance to the next line. + // + if (StringPtr[CurrIndex] == CHAR_LINEFEED) { + StringPtr[CurrIndex] = CHAR_SPACE; + // + // "\n" is represented as CHAR_CARRIAGE_RETURN + CHAR_LINEFEED,check this. + // + if (StringPtr[CurrIndex - 1] == CHAR_CARRIAGE_RETURN) { + StringPtr[CurrIndex - 1] = CHAR_SPACE; + } + + StrnCpy ((FormattedString[0] + StringCount * gHelpBlockWidth), &StringPtr[PrevIndex], CurrIndex - PrevIndex); + StringCount++; + PrevIndex = CurrIndex + 1; + CurrIndex = CurrIndex + gHelpBlockWidth; + } + } + // + // endfor + // + return ; +} + +VOID +IfrToFormTag ( + IN UINT8 OpCode, + IN EFI_TAG *TargetTag, + IN VOID *FormData, + EFI_VARIABLE_DEFINITION *VariableDefinitionsHead + ) +{ + UINT16 TempValue; + CHAR16 *VariableName; + CHAR8 *AsciiString; + EFI_VARIABLE_DEFINITION *VariableDefinitions; + EFI_VARIABLE_DEFINITION *PreviousVariableDefinitions; + STATIC UINT16 VariableSize; + EFI_GUID Guid; + STATIC UINT16 CurrentVariable; + STATIC UINT16 CurrentVariable2; + UINTN Index; + + switch (OpCode) { + case EFI_IFR_FORM_OP: + CopyMem (&TargetTag->Id, &((EFI_IFR_FORM *) FormData)->FormId, sizeof (UINT16)); + CopyMem (&TargetTag->Text, &((EFI_IFR_FORM *) FormData)->FormTitle, sizeof (UINT16)); + TargetTag->VariableNumber = CurrentVariable; + if (VariableDefinitionsHead != NULL) { + VariableName = AllocateZeroPool (12); + ASSERT (VariableName != NULL); + CopyMem (VariableName, L"Setup", 12); + VariableDefinitionsHead->VariableName = VariableName; + VariableDefinitionsHead->VariableSize = VariableSize; + CopyMem (&VariableDefinitionsHead->Guid, &Guid, sizeof (EFI_GUID)); + } + break; + + case EFI_IFR_SUBTITLE_OP: + TargetTag->NumberOfLines = 1; + CopyMem (&TargetTag->Text, &((EFI_IFR_SUBTITLE *) FormData)->SubTitle, sizeof (UINT16)); + TargetTag->VariableNumber = CurrentVariable; + break; + + case EFI_IFR_TEXT_OP: + TargetTag->NumberOfLines = 1; + CopyMem (&TargetTag->Text, &((EFI_IFR_TEXT *) FormData)->Text, sizeof (UINT16)); + CopyMem (&TargetTag->Help, &((EFI_IFR_TEXT *) FormData)->Help, sizeof (UINT16)); + TargetTag->VariableNumber = CurrentVariable; + + // + // To optimize the encoding size, certain opcodes have optional fields such as those + // inside the if() statement. If the encoded length is the complete size, then we + // know we have valid data encoded that we want to integrate + // + if (((EFI_IFR_TEXT *) FormData)->Header.Length == sizeof (EFI_IFR_TEXT)) { + // + // Text has no help associated with it, but in case there is a second entry due to + // dynamic/interactive flags being active, bring this data over. + // + CopyMem (&TargetTag->TextTwo, &((EFI_IFR_TEXT *) FormData)->TextTwo, sizeof (UINT16)); + TargetTag->Flags = ((EFI_IFR_TEXT *) FormData)->Flags; + CopyMem (&TargetTag->Key, &((EFI_IFR_TEXT *) FormData)->Key, sizeof (UINT16)); + } + break; + + case EFI_IFR_ONE_OF_OPTION_OP: + CopyMem (&TargetTag->Text, &((EFI_IFR_ONE_OF_OPTION *) FormData)->Option, sizeof (UINT16)); + CopyMem (&TargetTag->Value, &((EFI_IFR_ONE_OF_OPTION *) FormData)->Value, sizeof (UINT16)); + TargetTag->Flags = ((EFI_IFR_ONE_OF_OPTION *) FormData)->Flags; + CopyMem (&TargetTag->Key, &((EFI_IFR_ONE_OF_OPTION *) FormData)->Key, sizeof (UINT16)); + TargetTag->VariableNumber = CurrentVariable; + break; + + case EFI_IFR_CHECKBOX_OP: + TargetTag->Flags = ((EFI_IFR_CHECKBOX *) FormData)->Flags; + TargetTag->ResetRequired = (BOOLEAN) (TargetTag->Flags & EFI_IFR_FLAG_RESET_REQUIRED); + CopyMem (&TargetTag->Key, &((EFI_IFR_CHECKBOX *) FormData)->Key, sizeof (UINT16)); + TargetTag->VariableNumber = CurrentVariable; + break; + + case EFI_IFR_NUMERIC_OP: + TargetTag->Flags = ((EFI_IFR_NUMERIC *) FormData)->Flags; + CopyMem (&TargetTag->Key, &((EFI_IFR_NUMERIC *) FormData)->Key, sizeof (UINT16)); + TargetTag->VariableNumber = CurrentVariable; + break; + + case EFI_IFR_STRING_OP: + TempValue = 0; + CopyMem (&TempValue, &((EFI_IFR_STRING *) FormData)->MinSize, sizeof (UINT8)); + TempValue = (UINT16) (TempValue * 2); + CopyMem (&TargetTag->Minimum, &TempValue, sizeof (UINT16)); + + CopyMem (&TempValue, &((EFI_IFR_STRING *) FormData)->MaxSize, sizeof (UINT8)); + TempValue = (UINT16) (TempValue * 2); + CopyMem (&TargetTag->Maximum, &TempValue, sizeof (UINT16)); + CopyMem (&TargetTag->StorageWidth, &TempValue, sizeof (UINT16)); + TargetTag->Flags = (UINT8) (((EFI_IFR_STRING *) FormData)->Flags); + TargetTag->ResetRequired = (BOOLEAN) (TargetTag->Flags & EFI_IFR_FLAG_RESET_REQUIRED); + CopyMem (&TargetTag->Key, &((EFI_IFR_STRING *) FormData)->Key, sizeof (UINT16)); + TargetTag->VariableNumber = CurrentVariable; + break; + + case EFI_IFR_PASSWORD_OP: + TempValue = 0; + CopyMem (&TempValue, &((EFI_IFR_PASSWORD *) FormData)->MinSize, sizeof (UINT8)); + TempValue = (UINT16) (TempValue * 2); + CopyMem (&TargetTag->Minimum, &TempValue, sizeof (UINT16)); + + CopyMem (&TempValue, &((EFI_IFR_PASSWORD *) FormData)->MaxSize, sizeof (UINT8)); + TempValue = (UINT16) (TempValue * 2); + CopyMem (&TargetTag->Maximum, &TempValue, sizeof (UINT16)); + CopyMem (&TargetTag->StorageWidth, &TempValue, sizeof (UINT16)); + TargetTag->Flags = ((EFI_IFR_PASSWORD *) FormData)->Flags; + TargetTag->ResetRequired = (BOOLEAN) (TargetTag->Flags & EFI_IFR_FLAG_RESET_REQUIRED); + CopyMem (&TargetTag->Key, &((EFI_IFR_PASSWORD *) FormData)->Key, sizeof (UINT16)); + CopyMem (&TargetTag->Encoding, &((EFI_IFR_PASSWORD *) FormData)->Encoding, sizeof (UINT16)); + TargetTag->VariableNumber = CurrentVariable; + break; + + case EFI_IFR_VARSTORE_OP: + // + // It should NEVER be NULL + // + if (VariableDefinitionsHead == NULL) { + break; + } + + VariableDefinitions = VariableDefinitionsHead; + + // + // Advance VariableDefinitions to the last entry + // + for (; VariableDefinitions != NULL; VariableDefinitions = VariableDefinitions->Next) { + PreviousVariableDefinitions = VariableDefinitions; + // + // If there is a variable with this GUID and ID already, we need to bail out + // + if (!CompareMem (&VariableDefinitions->Guid, &((EFI_IFR_VARSTORE *) FormData)->Guid, sizeof (EFI_GUID)) && + !CompareMem (&VariableDefinitions->VariableId, &((EFI_IFR_VARSTORE *) FormData)->VarId, sizeof (UINT16)) + ) { + return ; + } + + if (VariableDefinitions->Next == NULL) { + break; + } + } + // + // If the last entry has a variable in it already, allocate a new entry and use it + // + if (VariableDefinitions->VariableName != NULL) { + VariableDefinitions->Next = AllocateZeroPool (sizeof (EFI_VARIABLE_DEFINITION)); + ASSERT (VariableDefinitions->Next != NULL); + PreviousVariableDefinitions = VariableDefinitions; + VariableDefinitions = VariableDefinitions->Next; + VariableDefinitions->Previous = PreviousVariableDefinitions; + } + // + // Copy the Variable data to our linked list + // + CopyMem (&VariableDefinitions->VariableId, &((EFI_IFR_VARSTORE *) FormData)->VarId, sizeof (UINT16)); + CopyMem (&VariableDefinitions->VariableSize, &((EFI_IFR_VARSTORE *) FormData)->Size, sizeof (UINT16)); + CopyMem (&VariableDefinitions->Guid, &((EFI_IFR_VARSTORE *) FormData)->Guid, sizeof (EFI_GUID)); + + // + // The ASCII String which is immediately past the EFI_IFR_VARSTORE is inferred by the structure definition + // due to it being variable sized. There are rules preventing it from being > 40 characters long and should + // be enforced by the compiler. + // + AsciiString = (CHAR8 *) (&((EFI_IFR_VARSTORE *) FormData)->Size); + AsciiString = AsciiString + 2; + VariableDefinitions->VariableName = AllocateZeroPool ((AsciiStrLen (AsciiString) + 1) * 2); + ASSERT (VariableDefinitions->VariableName != NULL); + for (Index = 0; AsciiString[Index] != 0; Index++) { + VariableDefinitions->VariableName[Index] = (CHAR16) AsciiString[Index]; + } + + VariableDefinitions->VariableName[Index] = 0; + + // + // Propogate the tag information for this op-code + // + CopyMem (&TargetTag->VariableNumber, &((EFI_IFR_VARSTORE *) FormData)->VarId, sizeof (UINT16)); + CopyMem (&TargetTag->GuidValue, &((EFI_IFR_VARSTORE *) FormData)->Guid, sizeof (EFI_GUID)); + CopyMem (&TargetTag->StorageWidth, &((EFI_IFR_VARSTORE *) FormData)->Size, sizeof (UINT16)); + CopyMem (&TargetTag->Maximum, &((EFI_IFR_VARSTORE *) FormData)->Size, sizeof (UINT16)); + break; + + case EFI_IFR_VARSTORE_SELECT_OP: + CopyMem (&TargetTag->VariableNumber, &((EFI_IFR_VARSTORE_SELECT *) FormData)->VarId, sizeof (UINT16)); + CopyMem (&CurrentVariable, &((EFI_IFR_VARSTORE_SELECT *) FormData)->VarId, sizeof (UINT16)); + CurrentVariable2 = CurrentVariable; + break; + + case EFI_IFR_VARSTORE_SELECT_PAIR_OP: + CopyMem (&TargetTag->VariableNumber, &((EFI_IFR_VARSTORE_SELECT_PAIR *) FormData)->VarId, sizeof (UINT16)); + CopyMem ( + &TargetTag->VariableNumber2, + &((EFI_IFR_VARSTORE_SELECT_PAIR *) FormData)->SecondaryVarId, + sizeof (UINT16) + ); + CopyMem (&CurrentVariable, &((EFI_IFR_VARSTORE_SELECT_PAIR *) FormData)->VarId, sizeof (UINT16)); + CopyMem (&CurrentVariable2, &((EFI_IFR_VARSTORE_SELECT_PAIR *) FormData)->SecondaryVarId, sizeof (UINT16)); + break; + + case EFI_IFR_REF_OP: + TargetTag->NumberOfLines = 1; + CopyMem (&TargetTag->Id, &((EFI_IFR_REF *) FormData)->FormId, sizeof (UINT16)); + CopyMem (&TargetTag->Key, &((EFI_IFR_REF *) FormData)->Key, sizeof (UINT16)); + CopyMem (&TargetTag->Text, &((EFI_IFR_REF *) FormData)->Prompt, sizeof (UINT16)); + CopyMem (&TargetTag->Help, &((EFI_IFR_REF *) FormData)->Help, sizeof (UINT16)); + TargetTag->Flags = ((EFI_IFR_REF *) FormData)->Flags; + TargetTag->VariableNumber = CurrentVariable; + break; + + case EFI_IFR_EQ_ID_VAL_OP: + CopyMem (&TargetTag->Value, &((EFI_IFR_EQ_ID_VAL *) FormData)->Value, sizeof (UINT16)); + CopyMem (&TargetTag->Id, &((EFI_IFR_EQ_ID_VAL *) FormData)->QuestionId, sizeof (UINT16)); + TargetTag->StorageWidth = ((EFI_IFR_EQ_ID_VAL *) FormData)->Width; + TargetTag->VariableNumber = CurrentVariable; + break; + + case EFI_IFR_EQ_VAR_VAL_OP: + CopyMem (&TargetTag->Value, &((EFI_IFR_EQ_VAR_VAL *) FormData)->Value, sizeof (UINT16)); + CopyMem (&TargetTag->Id, &((EFI_IFR_EQ_VAR_VAL *) FormData)->VariableId, sizeof (UINT16)); + TargetTag->VariableNumber = CurrentVariable; + break; + + case EFI_IFR_EQ_ID_ID_OP: + CopyMem (&TargetTag->Id, &((EFI_IFR_EQ_ID_ID *) FormData)->QuestionId1, sizeof (UINT16)); + CopyMem (&TargetTag->Id2, &((EFI_IFR_EQ_ID_ID *) FormData)->QuestionId2, sizeof (UINT16)); + TargetTag->StorageWidth = ((EFI_IFR_EQ_ID_ID *) FormData)->Width; + TargetTag->VariableNumber = CurrentVariable; + TargetTag->VariableNumber = CurrentVariable2; + break; + + case EFI_IFR_EQ_ID_LIST_OP: + CopyMem (&TargetTag->Id, &((EFI_IFR_EQ_ID_LIST *) FormData)->QuestionId, sizeof (UINT16)); + CopyMem (&TargetTag->Id2, &((EFI_IFR_EQ_ID_LIST *) FormData)->ListLength, sizeof (UINT16)); + TargetTag->StorageWidth = ((EFI_IFR_EQ_ID_LIST *) FormData)->Width; + + TargetTag->IntList = AllocateZeroPool (TargetTag->Id2 * sizeof (UINT16)); + ASSERT (TargetTag->IntList); + + for (TempValue = 0; TempValue < TargetTag->Id2; TempValue++) { + CopyMem ( + &TargetTag->IntList[TempValue], + &((EFI_IFR_EQ_ID_LIST *) FormData)->ValueList[TempValue], + sizeof (UINT16) + ); + } + + TargetTag->VariableNumber = CurrentVariable; + break; + + case EFI_IFR_FORM_SET_OP: + CopyMem (&VariableSize, &((EFI_IFR_FORM_SET *) FormData)->NvDataSize, sizeof (UINT16)); + CopyMem (&Guid, &((EFI_IFR_FORM_SET *) FormData)->Guid, sizeof (EFI_GUID)); + // + // If there is a size specified in the formste, we will establish a "default" variable + // + if (VariableDefinitionsHead != NULL) { + VariableName = AllocateZeroPool (12); + ASSERT (VariableName != NULL); + CopyMem (VariableName, L"Setup", 12); + VariableDefinitionsHead->VariableName = VariableName; + VariableDefinitionsHead->VariableSize = VariableSize; + CopyMem (&VariableDefinitionsHead->Guid, &Guid, sizeof (EFI_GUID)); + } + break; + + case EFI_IFR_END_FORM_SET_OP: + CurrentVariable = 0; + CurrentVariable2 = 0; + break; + } + + return ; +} diff --git a/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Setup.c b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Setup.c new file mode 100644 index 0000000000..f62bc120f0 --- /dev/null +++ b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Setup.c @@ -0,0 +1,2217 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + Setup.c + +Abstract: + + Entry and initialization module for the browser + +Revision History: +--*/ + +#include "Setup.h" +#include "Ui.h" + +FUNCTIION_KEY_SETTING gFunctionKeySettingTable[] = { + // + // Boot Manager + // + { + { + 0x847bc3fe, + 0xb974, + 0x446d, + { + 0x94, + 0x49, + 0x5a, + 0xd5, + 0x41, + 0x2e, + 0x99, + 0x3b + } + }, + NONE_FUNCTION_KEY_SETTING + }, + // + // Device Manager + // + { + { + 0x3ebfa8e6, + 0x511d, + 0x4b5b, + { + 0xa9, + 0x5f, + 0xfb, + 0x38, + 0x26, + 0xf, + 0x1c, + 0x27 + } + }, + NONE_FUNCTION_KEY_SETTING + }, + // + // BMM Formset. + // + { + { + 0x642237c7, + 0x35d4, + 0x472d, + { + 0x83, + 0x65, + 0x12, + 0xe0, + 0xcc, + 0xf2, + 0x7a, + 0x22 + } + }, + NONE_FUNCTION_KEY_SETTING + }, + // + // BMM File Explorer Formset. + // + { + { + 0x1f2d63e1, + 0xfebd, + 0x4dc7, + { + 0x9c, + 0xc5, + 0xba, + 0x2b, + 0x1c, + 0xef, + 0x9c, + 0x5b + } + }, + NONE_FUNCTION_KEY_SETTING + }, +}; + +EFI_STATUS +InitializeBinaryStructures ( + IN EFI_HII_HANDLE *Handle, + IN BOOLEAN UseDatabase, + IN EFI_IFR_PACKET *Packet, + IN UINT8 *NvMapOverride, + IN UINTN NumberOfIfrImages, + EFI_FILE_FORM_TAGS **FileFormTagsHead + ); + +EFI_STATUS +InitializeTagStructures ( + IN EFI_IFR_BINARY *BinaryData, + OUT EFI_FILE_FORM_TAGS *FileFormTags + ); + +UI_MENU_OPTION * +DisplayHomePage ( + IN UINTN NumberOfIfrImages, + IN EFI_FILE_FORM_TAGS *FileFormTagsHead, + IN UINT8 *CallbackData + ); + +EFI_STATUS +GetIfrBinaryData ( + IN EFI_HII_PROTOCOL *Hii, + IN EFI_HII_HANDLE HiiHandle, + IN EFI_IFR_PACKET *Packet, + IN EFI_IFR_BINARY *BinaryData + ); + +EFI_STATUS +InstallPrint ( + VOID + ); + +EFI_STATUS +EFIAPI +SendForm ( + IN EFI_FORM_BROWSER_PROTOCOL * This, + IN BOOLEAN UseDatabase, + IN EFI_HII_HANDLE * Handle, + IN UINTN HandleCount, + IN EFI_IFR_PACKET * Packet, + IN EFI_HANDLE CallbackHandle, + IN UINT8 *NvMapOverride, + IN EFI_SCREEN_DESCRIPTOR *ScreenDimensions, OPTIONAL + OUT BOOLEAN *ResetRequired OPTIONAL + ) +/*++ + +Routine Description: + + This is the routine which an external caller uses to direct the browser + where to obtain it's information. + +Arguments: + + UseDatabase - If set to TRUE, then all information is retrieved from the HII database handle specified + If set to FALSE, then the passed in Packet and CallbackHandle is used and Handle is ignored + + Handle - A pointer to an array of Handles. If HandleCount > 1 we display a list of the formsets for the handles specified + + HandleCount - The number of Handles specified in Handle. + + Packet - Valid only if UseDatabase is FALSE. Packet defines the pages being passed into + the browser. This is composed of IFR data as well as String information. + + CallbackHandle - The handle which contains the calling driver's EFI_FORM_CALLBACK_PROTOCOL interface. + + 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. + + NvMapOverride - This buffer is used only when there is no NV variable to define the current settings and the caller + needs to provide to the browser the current settings for the "fake" NV variable. If used, no saving + of an NV variable will be possible. This parameter is also ignored if HandleCount > 1. + +Returns: + +--*/ +{ + EFI_FORM_CONFIGURATION_DATA *FormData; + EFI_FORM_CALLBACK_PROTOCOL *FormCallback; + EFI_FILE_FORM_TAGS *FileFormTagsHead; + UI_MENU_OPTION *Selection; + UI_MENU_OPTION *AltSelection; + EFI_STATUS Status; + BOOLEAN Callback; + VOID *CallbackData; + EFI_HII_HANDLE BackupHandle; + + ZeroMem (&gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); + + gPreviousValue = AllocatePool (0x1000); + CallbackData = AllocatePool (0x10000); + ASSERT (gPreviousValue != NULL); + ASSERT (CallbackData != NULL); + + do { + // + // Seed the dimensions in the global + // + gST->ConOut->QueryMode ( + gST->ConOut, + gST->ConOut->Mode->Mode, + &gScreenDimensions.RightColumn, + &gScreenDimensions.BottomRow + ); + + if (ScreenDimensions != NULL) { + // + // Check local dimension vs. global dimension. + // + if ((gScreenDimensions.RightColumn < ScreenDimensions->RightColumn) || + (gScreenDimensions.BottomRow < ScreenDimensions->BottomRow) + ) { + return EFI_INVALID_PARAMETER; + } else { + // + // Local dimension validation. + // + if ((ScreenDimensions->RightColumn > ScreenDimensions->LeftColumn) && + (ScreenDimensions->BottomRow > ScreenDimensions->TopRow) && + ((ScreenDimensions->RightColumn - ScreenDimensions->LeftColumn) > 2) && + ( + (ScreenDimensions->BottomRow - ScreenDimensions->TopRow) > STATUS_BAR_HEIGHT + + SCROLL_ARROW_HEIGHT * + 2 + + FRONT_PAGE_HEADER_HEIGHT + + FOOTER_HEIGHT + + 1 + ) + ) { + CopyMem (&gScreenDimensions, ScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); + } else { + return EFI_INVALID_PARAMETER; + } + } + } + + gOptionBlockWidth = (CHAR16) ((gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3); + gHelpBlockWidth = gOptionBlockWidth; + gPromptBlockWidth = gOptionBlockWidth; + + // + // Initialize the strings for the browser, upon exit of the browser, the strings will be freed + // + InitializeBrowserStrings (); + + gFunctionKeySetting = DEFAULT_FUNCTION_KEY_SETTING; + gClassOfVfr = EFI_SETUP_APPLICATION_SUBCLASS; + gResetRequired = FALSE; + gExitRequired = FALSE; + gSaveRequired = FALSE; + gNvUpdateRequired = FALSE; + gActiveIfr = 0; + gConsistencyId = 0; + gPriorMenuEntry = 0; + BackupHandle = *Handle; + gMenuRefreshHead = NULL; + ASSERT (CallbackData); + ZeroMem (CallbackData, 0x10000); + + // + // We can recurse through this and might need to re-allocate this particular buffer + // + if (gPreviousValue == NULL) { + gPreviousValue = AllocatePool (0x1000); + ASSERT (gPreviousValue != NULL); + } + + FormData = EFI_FORM_DATA_FROM_THIS (This); + Callback = FALSE; + FormCallback = NULL; + + if (CallbackHandle != NULL) { + // + // Retrieve the Callback protocol interface + // + Status = gBS->HandleProtocol ( + CallbackHandle, + &gEfiFormCallbackProtocolGuid, + (VOID **) &FormCallback + ); + + if (EFI_ERROR (Status)) { + gBS->FreePool (CallbackData); + return Status;; + } + + Callback = TRUE; + } + // + // Initializes all the internal state structures for all IFR images in system + // + Status = InitializeBinaryStructures (Handle, UseDatabase, Packet, NvMapOverride, HandleCount, &FileFormTagsHead); + + if (EFI_ERROR (Status)) { + gBS->FreePool (CallbackData); + return Status; + } + // + // Beginning of the Presentation of the Data + // + if (UseDatabase && (HandleCount > 1)) { + Selection = DisplayHomePage (HandleCount, FileFormTagsHead, CallbackData); + } else { + // + // If passing something specific, we know there is only one Ifr + // + Selection = AllocateZeroPool (sizeof (UI_MENU_OPTION)); + ASSERT (Selection != NULL); + Selection->IfrNumber = 0; + Selection->Handle = Handle[0]; + UiInitMenu (); + } + + UiInitMenuList (); + + if (UseDatabase && (HandleCount > 1)) { + if (Selection == NULL) { + gBS->FreePool (CallbackData); + return EFI_SUCCESS; + } + } + // + // Launch the setup browser with the user's selection information + // + AltSelection = SetupBrowser (Selection, Callback, FileFormTagsHead, CallbackData); + + // + // If the caller cares about Reset status, we can return to the caller if something happened that required a reset + // + if (ResetRequired != NULL) { + *ResetRequired = gResetRequired; + } + + if (Callback && (AltSelection != NULL)) { + if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) { + Status = FormCallback->Callback ( + FormCallback, + AltSelection->ThisTag->Key, + CallbackData, + (EFI_HII_CALLBACK_PACKET **) &Packet + ); + } + } + + *Handle = BackupHandle; + + if (EFI_ERROR (Status)) { + gBS->FreePool (CallbackData); + return Status; + } + + if (Callback && (AltSelection == NULL)) { + gBS->FreePool (CallbackData); + return Status; + } + + if (UseDatabase && (HandleCount > 1)) { + } else { + + if (gBinaryDataHead->UnRegisterOnExit) { + Hii->RemovePack (Hii, Handle[0]); + } + + if (Callback && + ((AltSelection->ThisTag->SubClass == EFI_FRONT_PAGE_SUBCLASS) || + (AltSelection->ThisTag->SubClass == EFI_SINGLE_USE_SUBCLASS))) { + // + // If this is the FrontPage, return after every selection + // + gBS->FreePool (Selection); + UiFreeMenu (); + + // + // Clean up the allocated data buffers + // + FreeData (FileFormTagsHead, NULL, NULL); + + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->ClearScreen (gST->ConOut); + + gBS->FreePool (CallbackData); + return EFI_SUCCESS; + } + + gBS->FreePool (Selection); + UiFreeMenu (); + + // + // Clean up the allocated data buffers + // + FreeData (FileFormTagsHead, NULL, NULL); + + gST->ConOut->ClearScreen (gST->ConOut); + + if (!Callback) { + gBS->FreePool (CallbackData); + return EFI_SUCCESS; + } + } + + } while (!EFI_ERROR (Status)); + + gBS->FreePool (CallbackData); + return Status; +} + +EFI_STATUS +EFIAPI +InitializeSetup ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + Initialize Setup + +Arguments: + (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT) + +Returns: + EFI_SUCCESS - Setup loaded. + other - Setup Error + +--*/ +{ + EFI_STATUS Status; + EFI_FORM_CONFIGURATION_DATA *FormData; + EFI_FORM_BROWSER_PROTOCOL *FormBrowser; + EFI_HANDLE Handle; + EFI_HII_PACKAGES *PackageList; + + // + // There will be only one FormConfig in the system + // If there is another out there, someone is trying to install us + // again. Fail that scenario. + // + Status = gBS->LocateProtocol ( + &gEfiFormBrowserProtocolGuid, + NULL, + (VOID **) &FormBrowser + ); + + gFirstIn = TRUE; + + // + // If there was no error, assume there is an installation and fail to load + // + if (!EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + FormData = AllocatePool (sizeof (EFI_FORM_CONFIGURATION_DATA)); + + if (FormData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Fill in HII data + // + FormData->Signature = EFI_FORM_DATA_SIGNATURE; + FormData->FormConfig.SendForm = SendForm; + FormData->FormConfig.CreatePopUp = CreateDialog; + + // + // There should only be one HII image + // + Status = gBS->LocateProtocol ( + &gEfiHiiProtocolGuid, + NULL, + (VOID **) &FormData->Hii + ); + + ASSERT_EFI_ERROR (Status); + + Hii = FormData->Hii; + + PackageList = PreparePackages (1, &gEfiFormBrowserProtocolGuid, SetupBrowserStrings); + + Status = Hii->NewPack (Hii, PackageList, &gHiiHandle); + + gBS->FreePool (PackageList); + + // + // Install protocol interface + // + Handle = NULL; + Status = gBS->InstallProtocolInterface ( + &Handle, + &gEfiFormBrowserProtocolGuid, + EFI_NATIVE_INTERFACE, + &FormData->FormConfig + ); + + ASSERT_EFI_ERROR (Status); + + BannerData = AllocateZeroPool (sizeof (BANNER_DATA)); + ASSERT (BannerData != NULL); + + Status = InstallPrint (); + return Status; +} + +VOID +GetQuestionHeader ( + IN EFI_TAG *Tag, + IN UINT8 *RawFormSet, + IN UINT16 Index, + IN EFI_FILE_FORM_TAGS *FileFormTags, + IN UINT16 CurrentVariable + ) +/*++ + +Routine Description: + Initialize question tag's members. + +Arguments: + Tag - Pointer of the current EFI_TAG structure. + RawFormSet - Pointer of the formset raw data. + Index - Offset of the current opcode in the Ifr raw data. + FileFormTags - Pointer of current EFI_FILE_FORM_TAGS structure. + CurrentVariable - Current variable number. + +Returns: + None. +--*/ +{ + EFI_VARIABLE_DEFINITION *VariableDefinition; + + Tag->NumberOfLines = 1; + Tag->VariableNumber = CurrentVariable; + CopyMem (&Tag->Id, &((EFI_IFR_ONE_OF *) &RawFormSet[Index])->QuestionId, sizeof (UINT16)); + CopyMem (&Tag->StorageStart, &((EFI_IFR_ONE_OF *) &RawFormSet[Index])->QuestionId, sizeof (UINT16)); + CopyMem (&Tag->StorageWidth, &((EFI_IFR_ONE_OF *) &RawFormSet[Index])->Width, sizeof (UINT8)); + CopyMem (&Tag->Text, &((EFI_IFR_ONE_OF *) &RawFormSet[Index])->Prompt, sizeof (UINT16)); + CopyMem (&Tag->Help, &((EFI_IFR_ONE_OF *) &RawFormSet[Index])->Help, sizeof (UINT16)); + + VariableDefinition = FileFormTags->VariableDefinitions; + + for (; VariableDefinition != NULL; VariableDefinition = VariableDefinition->Next) { + // + // Have we found the correct variable for the request? + // + if (CurrentVariable == VariableDefinition->VariableId) { + if (VariableDefinition->VariableSize < (UINTN) (Tag->StorageStart + Tag->StorageWidth)) { + VariableDefinition->VariableFakeSize = (UINT16) (VariableDefinition->VariableFakeSize + Tag->StorageWidth); + } + + if (VariableDefinition->NvRamMap != NULL) { + // + // If it is an 8bit or 16bit width, then move it to Tag->Value, otherwise + // we will never be looking for the data in Tag->Value (e.g. strings, password, etc) + // + if (Tag->StorageWidth == (UINT16) 1) { + CopyMem (&Tag->Value, &VariableDefinition->NvRamMap[Tag->StorageStart], sizeof (UINT16)); + } + + if (Tag->StorageWidth == (UINT16) 2) { + Index = (UINT16) + ( + VariableDefinition->NvRamMap[Tag->StorageStart] + + (VariableDefinition->NvRamMap[Tag->StorageStart + 1] * 0x100) + ); + CopyMem (&Tag->Value, &Index, sizeof (UINT16)); + } + } else { + Index = 0; + CopyMem (&Tag->Value, &Index, sizeof (UINT16)); + } + break; + } else { + continue; + } + } +} + +VOID +GetNumericHeader ( + IN EFI_TAG *Tag, + IN UINT8 *RawFormSet, + IN UINT16 Index, + IN UINT16 NumberOfLines, + IN EFI_FILE_FORM_TAGS *FileFormTags, + IN UINT16 CurrentVariable + ) +/*++ + +Routine Description: + Initialize numeric tag's members. + +Arguments: + Tag - Pointer of the current EFI_TAG structure. + RawFormSet - Pointer of the formset raw data. + Index - Offset of the current opcode in the Ifr raw data. + NumberOfLines - Number of lines this opcode occupied. + FileFormTags - Pointer of current EFI_FILE_FORM_TAGS structure. + CurrentVariable - Current variable number. + +Returns: + None. +--*/ +{ + EFI_VARIABLE_DEFINITION *VariableDefinition; + + Tag->NumberOfLines = NumberOfLines; + Tag->VariableNumber = CurrentVariable; + CopyMem (&Tag->Id, &((EFI_IFR_ONE_OF *) &RawFormSet[Index])->QuestionId, sizeof (UINT16)); + CopyMem (&Tag->StorageStart, &((EFI_IFR_ONE_OF *) &RawFormSet[Index])->QuestionId, sizeof (UINT16)); + CopyMem (&Tag->StorageWidth, &((EFI_IFR_ONE_OF *) &RawFormSet[Index])->Width, sizeof (UINT8)); + CopyMem (&Tag->Text, &((EFI_IFR_ONE_OF *) &RawFormSet[Index])->Prompt, sizeof (UINT16)); + CopyMem (&Tag->Help, &((EFI_IFR_ONE_OF *) &RawFormSet[Index])->Help, sizeof (UINT16)); + CopyMem (&Tag->Minimum, &((EFI_IFR_NUMERIC *) &RawFormSet[Index])->Minimum, sizeof (UINT16)); + CopyMem (&Tag->Maximum, &((EFI_IFR_NUMERIC *) &RawFormSet[Index])->Maximum, sizeof (UINT16)); + CopyMem (&Tag->Step, &((EFI_IFR_NUMERIC *) &RawFormSet[Index])->Step, sizeof (UINT16)); + CopyMem (&Tag->Default, &((EFI_IFR_NUMERIC *) &RawFormSet[Index])->Default, sizeof (UINT16)); + Tag->ResetRequired = (BOOLEAN) (((EFI_IFR_NUMERIC *) &RawFormSet[Index])->Flags & EFI_IFR_FLAG_RESET_REQUIRED); + + VariableDefinition = FileFormTags->VariableDefinitions; + + for (; VariableDefinition != NULL; VariableDefinition = VariableDefinition->Next) { + // + // Have we found the correct variable for the request? + // + if (CurrentVariable == VariableDefinition->VariableId) { + if (VariableDefinition->VariableSize <= (UINTN) (Tag->StorageStart + Tag->StorageWidth)) { + if (Tag->StorageWidth == 0) { + VariableDefinition->VariableFakeSize = (UINT16) (VariableDefinition->VariableFakeSize + 2); + } else { + VariableDefinition->VariableFakeSize = (UINT16) (VariableDefinition->VariableFakeSize + Tag->StorageWidth); + } + } + + if (VariableDefinition->NvRamMap != NULL) { + // + // If it is an 8bit or 16bit width, then move it to Tag->Value, otherwise + // we will never be looking for the data in Tag->Value (e.g. strings, password, etc) + // + if (Tag->StorageWidth == (UINT16) 1) { + CopyMem (&Tag->Value, &VariableDefinition->NvRamMap[Tag->StorageStart], sizeof (UINT16)); + } + + if (Tag->StorageWidth == (UINT16) 2) { + Index = (UINT16) + ( + VariableDefinition->NvRamMap[Tag->StorageStart] + + (VariableDefinition->NvRamMap[Tag->StorageStart + 1] * 0x100) + ); + CopyMem (&Tag->Value, &Index, sizeof (UINT16)); + } + } else { + CopyMem (&Tag->Value, &Tag->Default, sizeof (UINT16)); + } + break; + } else { + continue; + } + } +} + +VOID +GetTagCount ( + IN UINT8 *RawFormSet, + IN OUT UINT16 *NumberOfTags + ) +{ + UINT16 Index; + + // + // Assume on entry we are pointing to an OpCode - reasonably this should + // be a FormOp since the purpose is to count the tags in a particular Form. + // + for (Index = 0; RawFormSet[Index] != EFI_IFR_END_FORM_OP;) { + // + // If we encounter the end of a form set, bail out + // + if (RawFormSet[Index] == EFI_IFR_END_FORM_SET_OP) { + break; + } + // + // We treat date/time internally as three op-codes + // + if (RawFormSet[Index] == EFI_IFR_DATE_OP || RawFormSet[Index] == EFI_IFR_TIME_OP) { + *NumberOfTags = (UINT16) (*NumberOfTags + 3); + } else { + // + // Assume that we could have no more tags than op-codes + // + (*NumberOfTags)++; + } + + Index = (UINT16) (Index + RawFormSet[Index + 1]); + } + // + // Increase the tag count by one so it is inclusive of the end_form_op + // + (*NumberOfTags)++; +} + +VOID +AddNextInconsistentTag ( + IN OUT EFI_INCONSISTENCY_DATA **InconsistentTagsPtr + ) +/*++ + +Routine Description: + Initialize the next inconsistent tag data and add it to the inconsistent tag list. + +Arguments: + InconsistentTagsPtr - Pointer of the inconsistent tag's pointer. + +Returns: + None. + +--*/ +{ + EFI_INCONSISTENCY_DATA *PreviousInconsistentTags; + EFI_INCONSISTENCY_DATA *InconsistentTags; + + InconsistentTags = *InconsistentTagsPtr; + // + // We just hit the end of an inconsistent expression. Let's allocate the ->Next structure + // + InconsistentTags->Next = AllocatePool (sizeof (EFI_INCONSISTENCY_DATA)); + ASSERT (InconsistentTags->Next != NULL); + + // + // Preserve current Tag entry + // + PreviousInconsistentTags = InconsistentTags; + + InconsistentTags = InconsistentTags->Next; + + // + // This will zero on the entry including the ->Next so I don't have to do it + // + ZeroMem (InconsistentTags, sizeof (EFI_INCONSISTENCY_DATA)); + + // + // Point our Previous field to the previous entry + // + InconsistentTags->Previous = PreviousInconsistentTags; + + *InconsistentTagsPtr = InconsistentTags; + + return ; +} + +EFI_STATUS +InitializeTagStructures ( + IN EFI_IFR_BINARY *BinaryData, + OUT EFI_FILE_FORM_TAGS *FileFormTags + ) +{ + EFI_STATUS Status; + UINT8 *RawFormSet; + UINT16 Index; + UINT16 QuestionIndex; + UINT16 NumberOfTags; + INT16 CurrTag; + UINT8 TagLength; + EFI_FORM_TAGS *FormTags; + EFI_FORM_TAGS *SavedFormTags; + EFI_INCONSISTENCY_DATA *InconsistentTags; + EFI_VARIABLE_DEFINITION *VariableDefinitions; + UINTN Count; + UINT16 Class; + UINT16 SubClass; + UINT16 TempValue; + UINT16 CurrentVariable; + UINT16 CurrentVariable2; + + // + // Initialize some Index variable and Status + // + Count = 0; + Class = 0; + SubClass = 0; + CurrentVariable = 0; + CurrentVariable2 = 0; + QuestionIndex = 0; + NumberOfTags = 1; + Status = EFI_SUCCESS; + FormTags = &FileFormTags->FormTags; + FormTags->Next = NULL; + if (FileFormTags->InconsistentTags == NULL) { + InconsistentTags = NULL; + } else { + InconsistentTags = FileFormTags->InconsistentTags; + } + + if (FileFormTags->VariableDefinitions == NULL) { + VariableDefinitions = NULL; + } else { + VariableDefinitions = FileFormTags->VariableDefinitions; + } + // + // RawFormSet now points to the beginning of the forms portion of + // the specific IFR Binary. + // + RawFormSet = (UINT8 *) BinaryData->FormBinary; + + // + // Determine the number of tags for the first form + // + GetTagCount (&RawFormSet[0], &NumberOfTags); + + SavedFormTags = FormTags; + + if (FormTags->Tags != NULL) { + do { + // + // Advance FormTags to the last entry + // + for (; FormTags->Next != NULL; FormTags = FormTags->Next) + ; + + // + // Walk through each of the tags and free the IntList allocation + // + for (Index = 0; Index < NumberOfTags; Index++) { + if (FormTags->Tags[Index].IntList != NULL) { + gBS->FreePool (FormTags->Tags[Index].IntList); + } + } + + gBS->FreePool (FormTags->Tags); + gBS->FreePool (FormTags->Next); + FormTags->Next = NULL; + FormTags->Tags = NULL; + + FormTags = SavedFormTags; + + } while (FormTags->Next != NULL); + } + + Index = 0; + + // + // Test for an allocated buffer. If already allocated this is due to having called this routine + // once for sizing of the NV storage. We then loaded the NV variable and can correctly initialize + // the tag structure with current values from the NV + // + if (FormTags->Tags == NULL) { + // + // Allocate memory for our tags on the first form + // + FormTags->Tags = AllocateZeroPool (NumberOfTags * sizeof (EFI_TAG)); + ASSERT (FormTags->Tags); + } + // + // Test for an allocated buffer. If already allocated this is due to having called this routine + // once for sizing of the NV storage. We then loaded the NV variable and can correctly initialize + // the tag structure with current values from the NV + // + if (InconsistentTags == NULL) { + // + // We just hit the end of an inconsistent expression. Let's allocate the ->Next structure + // + InconsistentTags = AllocateZeroPool (sizeof (EFI_INCONSISTENCY_DATA)); + ASSERT (InconsistentTags != NULL); + + FileFormTags->InconsistentTags = InconsistentTags; + } + + ZeroMem (FormTags->Tags, NumberOfTags * sizeof (EFI_TAG)); + + for (CurrTag = 0; RawFormSet[Index] != EFI_IFR_END_FORM_SET_OP; CurrTag++) { + // + // Operand = IFR OpCode + // + FormTags->Tags[CurrTag].Operand = RawFormSet[Index]; + + // + // Assume for now 0 lines occupied by this OpCode + // + FormTags->Tags[CurrTag].NumberOfLines = 0; + + FormTags->Tags[CurrTag].Class = Class; + FormTags->Tags[CurrTag].SubClass = SubClass; + + // + // Determine the length of the Tag so we can later skip to the next tag in the form + // + TagLength = RawFormSet[Index + 1]; + // + // get the length + // + // Operate on the Found OpCode + // + switch (RawFormSet[Index]) { + + case EFI_IFR_FORM_OP: + // + // If there was no variable op-code defined, create a dummy entry for one + // + if (FileFormTags->VariableDefinitions == NULL) { + FileFormTags->VariableDefinitions = AllocateZeroPool (sizeof (EFI_VARIABLE_DEFINITION)); + ASSERT (FileFormTags->VariableDefinitions != NULL); + IfrToFormTag ( + RawFormSet[Index], + &FormTags->Tags[CurrTag], + (VOID *) &RawFormSet[Index], + FileFormTags->VariableDefinitions + ); + } else { + IfrToFormTag (RawFormSet[Index], &FormTags->Tags[CurrTag], (VOID *) &RawFormSet[Index], NULL); + } + break; + + case EFI_IFR_SUBTITLE_OP: + case EFI_IFR_TEXT_OP: + case EFI_IFR_REF_OP: + IfrToFormTag (RawFormSet[Index], &FormTags->Tags[CurrTag], (VOID *) &RawFormSet[Index], NULL); + break; + + case EFI_IFR_VARSTORE_OP: + if (FileFormTags->VariableDefinitions == NULL) { + VariableDefinitions = AllocateZeroPool (sizeof (EFI_VARIABLE_DEFINITION)); + ASSERT (VariableDefinitions != NULL); + FileFormTags->VariableDefinitions = VariableDefinitions; + } + + IfrToFormTag ( + RawFormSet[Index], + &FormTags->Tags[CurrTag], + (VOID *) &RawFormSet[Index], + FileFormTags->VariableDefinitions + ); + break; + + case EFI_IFR_VARSTORE_SELECT_OP: + IfrToFormTag (RawFormSet[Index], &FormTags->Tags[CurrTag], (VOID *) &RawFormSet[Index], NULL); + CopyMem (&CurrentVariable, &((EFI_IFR_VARSTORE_SELECT *) &RawFormSet[Index])->VarId, sizeof (UINT16)); + CurrentVariable2 = CurrentVariable; + break; + + case EFI_IFR_VARSTORE_SELECT_PAIR_OP: + IfrToFormTag (RawFormSet[Index], &FormTags->Tags[CurrTag], (VOID *) &RawFormSet[Index], NULL); + CopyMem(&CurrentVariable, &((EFI_IFR_VARSTORE_SELECT_PAIR *)&RawFormSet[Index])->VarId, sizeof (UINT16)); + CopyMem ( + &CurrentVariable2, + &((EFI_IFR_VARSTORE_SELECT_PAIR *) &RawFormSet[Index])->SecondaryVarId, + sizeof (UINT16) + ); + break; + + case EFI_IFR_END_FORM_OP: + // + // Test for an allocated buffer. If already allocated this is due to having called this routine + // once for sizing of the NV storage. We then loaded the NV variable and can correctly initialize + // the tag structure with current values from the NV + // + if (FormTags->Next == NULL) { + // + // We just hit the end of a form. Let's allocate the ->Next structure + // + FormTags->Next = AllocatePool (sizeof (EFI_FORM_TAGS)); + ASSERT (FormTags->Next); + } + + FormTags = FormTags->Next; + ZeroMem (FormTags, sizeof (EFI_FORM_TAGS)); + + // + // Reset the tag count to one + // + NumberOfTags = 1; + + // + // Reset the CurrTag value (it will be incremented, after this case statement + // so set to a negative one so that we get the desired effect.) Fish can beat me later. + // + CurrTag = -1; + + // + // Determine the number of tags after this form. If this is the last + // form, then we will count the endformset and preserve that information + // in the tag structure. + // + GetTagCount (&RawFormSet[Index + TagLength], &NumberOfTags); + + // + // Allocate memory for our tags + // + FormTags->Tags = AllocateZeroPool (NumberOfTags * sizeof (EFI_TAG)); + ASSERT (FormTags->Tags); + break; + + // + // Two types of tags constitute the One Of question: a one-of header and + // several one-of options. + // + case EFI_IFR_ONE_OF_OP: + case EFI_IFR_ORDERED_LIST_OP: + GetQuestionHeader (&FormTags->Tags[CurrTag], RawFormSet, Index, FileFormTags, CurrentVariable); + + // + // Store away the CurrTag since what follows will be the answer that we + // need to place into the appropriate location in the tag array + // + // + // record for setting default later + // + QuestionIndex = (UINT16) CurrTag; + break; + + case EFI_IFR_ONE_OF_OPTION_OP: + IfrToFormTag (RawFormSet[Index], &FormTags->Tags[CurrTag], (VOID *) &RawFormSet[Index], NULL); + FormTags->Tags[QuestionIndex].Flags = ((EFI_IFR_ONE_OF_OPTION *) &RawFormSet[Index])->Flags; + CopyMem ( + &FormTags->Tags[QuestionIndex].Key, + &((EFI_IFR_ONE_OF_OPTION *) &RawFormSet[Index])->Key, + sizeof (UINT16) + ); + FormTags->Tags[QuestionIndex].ResetRequired = (BOOLEAN) (FormTags->Tags[QuestionIndex].Flags & EFI_IFR_FLAG_RESET_REQUIRED); + break; + + case EFI_IFR_CHECKBOX_OP: + GetQuestionHeader (&FormTags->Tags[CurrTag], RawFormSet, Index, FileFormTags, CurrentVariable); + IfrToFormTag (RawFormSet[Index], &FormTags->Tags[CurrTag], (VOID *) &RawFormSet[Index], NULL); + break; + + case EFI_IFR_NUMERIC_OP: + GetNumericHeader (&FormTags->Tags[CurrTag], RawFormSet, Index, (UINT16) 1, FileFormTags, CurrentVariable); + IfrToFormTag (RawFormSet[Index], &FormTags->Tags[CurrTag], (VOID *) &RawFormSet[Index], NULL); + break; + + case EFI_IFR_DATE_OP: + // + // Date elements come in as a Year, Month, Day. We need to process them as a country-based + // Order. It is much easier to do it here than anywhere else. + // + // For US standards - we want Month/Day/Year, thus we advance "Index" +1, +2, +0 while CurrTag is +0, +1, +2 + // + GetNumericHeader ( + &FormTags->Tags[CurrTag], + RawFormSet, + (UINT16) (Index + TagLength), + (UINT16) 0, + FileFormTags, + CurrentVariable + ); + + // + // The current language selected + the Date operand + // + FormTags->Tags[CurrTag + 1].Operand = RawFormSet[Index]; + GetNumericHeader ( + &FormTags->Tags[CurrTag + 1], + RawFormSet, + (UINT16) (Index + TagLength + RawFormSet[Index + TagLength + 1]), + (UINT16) 0, + FileFormTags, + CurrentVariable + ); + + // + // The current language selected + the Date operand + // + FormTags->Tags[CurrTag + 2].Operand = RawFormSet[Index]; + GetNumericHeader (&FormTags->Tags[CurrTag + 2], RawFormSet, Index, (UINT16) 1, FileFormTags, CurrentVariable); + + CurrTag = (INT16) (CurrTag + 2); + + Index = (UINT16) (Index + TagLength); + // + // get the length + // + TagLength = RawFormSet[Index + 1]; + Index = (UINT16) (Index + TagLength); + // + // get the length + // + TagLength = RawFormSet[Index + 1]; + break; + + case EFI_IFR_TIME_OP: + GetNumericHeader (&FormTags->Tags[CurrTag], RawFormSet, Index, (UINT16) 0, FileFormTags, CurrentVariable); + + if (Count == 2) { + // + // Override the GetQuestionHeader information - date/time are treated very differently + // + FormTags->Tags[CurrTag].NumberOfLines = 1; + Count = 0; + } else { + // + // The premise is that every date/time op-code have 3 elements, the first 2 have 0 lines + // associated with them, and the third has 1 line to allow to space beyond the choice. + // + Count++; + } + break; + + case EFI_IFR_PASSWORD_OP: + case EFI_IFR_STRING_OP: + GetQuestionHeader (&FormTags->Tags[CurrTag], RawFormSet, Index, FileFormTags, CurrentVariable); + IfrToFormTag (RawFormSet[Index], &FormTags->Tags[CurrTag], (VOID *) &RawFormSet[Index], NULL); + break; + + case EFI_IFR_SUPPRESS_IF_OP: + case EFI_IFR_GRAYOUT_IF_OP: + InconsistentTags->Operand = ((EFI_IFR_INCONSISTENT *) &RawFormSet[Index])->Header.OpCode; + gConsistencyId++; + + // + // Since this op-code doesn't use the next field(s), initialize them with something invalid. + // Unfortunately 0 is a valid offset value for a QuestionId + // + InconsistentTags->QuestionId1 = INVALID_OFFSET_VALUE; + InconsistentTags->QuestionId2 = INVALID_OFFSET_VALUE; + + // + // Test for an allocated buffer. If already allocated this is due to having called this routine + // once for sizing of the NV storage. We then loaded the NV variable and can correctly initialize + // the tag structure with current values from the NV + // + if (InconsistentTags->Next == NULL) { + AddNextInconsistentTag (&InconsistentTags); + break; + } + + InconsistentTags = InconsistentTags->Next; + break; + + case EFI_IFR_FORM_SET_OP: + CopyMem ( + &FormTags->Tags[CurrTag].GuidValue, + &((EFI_IFR_FORM_SET *) &RawFormSet[Index])->Guid, + sizeof (EFI_GUID) + ); + CopyMem ( + &FormTags->Tags[CurrTag].CallbackHandle, + &((EFI_IFR_FORM_SET *) &RawFormSet[Index])->CallbackHandle, + sizeof (EFI_PHYSICAL_ADDRESS) + ); + CopyMem (&FormTags->Tags[CurrTag].Class, &((EFI_IFR_FORM_SET *) &RawFormSet[Index])->Class, sizeof (UINT8)); + CopyMem ( + &FormTags->Tags[CurrTag].SubClass, + &((EFI_IFR_FORM_SET *) &RawFormSet[Index])->SubClass, + sizeof (UINT8) + ); + CopyMem ( + &FormTags->Tags[CurrTag].NvDataSize, + &((EFI_IFR_FORM_SET *) &RawFormSet[Index])->NvDataSize, + sizeof (UINT16) + ); + Class = ((EFI_IFR_FORM_SET *) &RawFormSet[Index])->Class; + SubClass = ((EFI_IFR_FORM_SET *) &RawFormSet[Index])->SubClass; + // + // If the formset has a size value, that means someone must be using this, so create a variable + // We also shall reserve the formid of 0 for this specific purpose. + // + if ((FileFormTags->VariableDefinitions == NULL) && (FormTags->Tags[CurrTag].NvDataSize > 0)) { + FileFormTags->VariableDefinitions = AllocateZeroPool (sizeof (EFI_VARIABLE_DEFINITION)); + ASSERT (FileFormTags->VariableDefinitions != NULL); + IfrToFormTag ( + RawFormSet[Index], + &FormTags->Tags[CurrTag], + (VOID *) &RawFormSet[Index], + FileFormTags->VariableDefinitions + ); + } else { + IfrToFormTag (RawFormSet[Index], &FormTags->Tags[CurrTag], (VOID *) &RawFormSet[Index], NULL); + } + break; + + case EFI_IFR_BANNER_OP: + if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) { + TempValue = 0; + CopyMem (&TempValue, &((EFI_IFR_BANNER *) &RawFormSet[Index])->Alignment, sizeof (UINT8)); + // + // If this is the special timeout value, we will dynamically figure out where to put it + // Also the least significant byte refers to the TimeOut desired. + // + if (TempValue == EFI_IFR_BANNER_TIMEOUT) { + CopyMem (&FrontPageTimeOutTitle, &((EFI_IFR_BANNER *) &RawFormSet[Index])->Title, sizeof (UINT16)); + if (FrontPageTimeOutValue != (INT16) -1) { + CopyMem (&FrontPageTimeOutValue, &((EFI_IFR_BANNER *) &RawFormSet[Index])->LineNumber, sizeof (UINT16)); + } + break; + } + + CopyMem ( + &BannerData->Banner[((EFI_IFR_BANNER *) &RawFormSet[Index])->LineNumber][ + ((EFI_IFR_BANNER *) &RawFormSet[Index])->Alignment], + &((EFI_IFR_BANNER *) &RawFormSet[Index])->Title, + sizeof (STRING_REF) + ); + } + break; + + case EFI_IFR_INCONSISTENT_IF_OP: + CopyMem ( + &FormTags->Tags[CurrTag].Text, + &((EFI_IFR_INCONSISTENT *) &RawFormSet[Index])->Popup, + sizeof (UINT16) + ); + gConsistencyId++; + + InconsistentTags->Operand = ((EFI_IFR_INCONSISTENT *) &RawFormSet[Index])->Header.OpCode; + CopyMem (&InconsistentTags->Popup, &((EFI_IFR_INCONSISTENT *) &RawFormSet[Index])->Popup, sizeof (UINT16)); + + // + // Since this op-code doesn't use the next field(s), initialize them with something invalid. + // Unfortunately 0 is a valid offset value for a QuestionId + // + InconsistentTags->QuestionId1 = INVALID_OFFSET_VALUE; + InconsistentTags->QuestionId2 = INVALID_OFFSET_VALUE; + + InconsistentTags->VariableNumber = CurrentVariable; + + // + // Test for an allocated buffer. If already allocated this is due to having called this routine + // once for sizing of the NV storage. We then loaded the NV variable and can correctly initialize + // the tag structure with current values from the NV + // + if (InconsistentTags->Next == NULL) { + AddNextInconsistentTag (&InconsistentTags); + break; + } + + InconsistentTags = InconsistentTags->Next; + break; + + case EFI_IFR_EQ_ID_VAL_OP: + IfrToFormTag (RawFormSet[Index], &FormTags->Tags[CurrTag], (VOID *) &RawFormSet[Index], NULL); + + InconsistentTags->Operand = ((EFI_IFR_EQ_ID_VAL *) &RawFormSet[Index])->Header.OpCode; + CopyMem (&InconsistentTags->Value, &((EFI_IFR_EQ_ID_VAL *) &RawFormSet[Index])->Value, sizeof (UINT16)); + CopyMem ( + &InconsistentTags->QuestionId1, + &((EFI_IFR_EQ_ID_VAL *) &RawFormSet[Index])->QuestionId, + sizeof (UINT16) + ); + + // + // Since this op-code doesn't use the next field(s), initialize them with something invalid. + // Unfortunately 0 is a valid offset value for a QuestionId + // + InconsistentTags->Width = FormTags->Tags[CurrTag].StorageWidth; + InconsistentTags->QuestionId2 = INVALID_OFFSET_VALUE; + InconsistentTags->ConsistencyId = gConsistencyId; + FormTags->Tags[CurrTag].ConsistencyId = gConsistencyId; + + InconsistentTags->VariableNumber = CurrentVariable; + + // + // Test for an allocated buffer. If already allocated this is due to having called this routine + // once for sizing of the NV storage. We then loaded the NV variable and can correctly initialize + // the tag structure with current values from the NV + // + if (InconsistentTags->Next == NULL) { + AddNextInconsistentTag (&InconsistentTags); + break; + } + + InconsistentTags = InconsistentTags->Next; + break; + + case EFI_IFR_EQ_VAR_VAL_OP: + IfrToFormTag (RawFormSet[Index], &FormTags->Tags[CurrTag], (VOID *) &RawFormSet[Index], NULL); + + InconsistentTags->Operand = ((EFI_IFR_EQ_VAR_VAL *) &RawFormSet[Index])->Header.OpCode; + CopyMem (&InconsistentTags->Value, &((EFI_IFR_EQ_VAR_VAL *) &RawFormSet[Index])->Value, sizeof (UINT16)); + CopyMem ( + &InconsistentTags->QuestionId1, + &((EFI_IFR_EQ_VAR_VAL *) &RawFormSet[Index])->VariableId, + sizeof (UINT16) + ); + + // + // Since this op-code doesn't use the next field(s), initialize them with something invalid. + // Unfortunately 0 is a valid offset value for a QuestionId + // + InconsistentTags->QuestionId2 = INVALID_OFFSET_VALUE; + InconsistentTags->ConsistencyId = gConsistencyId; + FormTags->Tags[CurrTag].ConsistencyId = gConsistencyId; + + InconsistentTags->VariableNumber = CurrentVariable; + + // + // Test for an allocated buffer. If already allocated this is due to having called this routine + // once for sizing of the NV storage. We then loaded the NV variable and can correctly initialize + // the tag structure with current values from the NV + // + if (InconsistentTags->Next == NULL) { + AddNextInconsistentTag (&InconsistentTags); + break; + } + + InconsistentTags = InconsistentTags->Next; + break; + + case EFI_IFR_EQ_ID_ID_OP: + IfrToFormTag (RawFormSet[Index], &FormTags->Tags[CurrTag], (VOID *) &RawFormSet[Index], NULL); + + InconsistentTags->Operand = ((EFI_IFR_EQ_ID_ID *) &RawFormSet[Index])->Header.OpCode; + CopyMem ( + &InconsistentTags->QuestionId1, + &((EFI_IFR_EQ_ID_ID *) &RawFormSet[Index])->QuestionId1, + sizeof (UINT16) + ); + CopyMem ( + &InconsistentTags->QuestionId2, + &((EFI_IFR_EQ_ID_ID *) &RawFormSet[Index])->QuestionId2, + sizeof (UINT16) + ); + + InconsistentTags->Width = FormTags->Tags[CurrTag].StorageWidth; + InconsistentTags->ConsistencyId = gConsistencyId; + FormTags->Tags[CurrTag].ConsistencyId = gConsistencyId; + + InconsistentTags->VariableNumber = CurrentVariable; + InconsistentTags->VariableNumber2 = CurrentVariable2; + + // + // Test for an allocated buffer. If already allocated this is due to having called this routine + // once for sizing of the NV storage. We then loaded the NV variable and can correctly initialize + // the tag structure with current values from the NV + // + if (InconsistentTags->Next == NULL) { + AddNextInconsistentTag (&InconsistentTags); + break; + } + + InconsistentTags = InconsistentTags->Next; + break; + + case EFI_IFR_AND_OP: + case EFI_IFR_OR_OP: + case EFI_IFR_NOT_OP: + case EFI_IFR_GT_OP: + case EFI_IFR_GE_OP: + case EFI_IFR_TRUE_OP: + case EFI_IFR_FALSE_OP: + InconsistentTags->Operand = ((EFI_IFR_NOT *) &RawFormSet[Index])->Header.OpCode; + + // + // Since this op-code doesn't use the next field(s), initialize them with something invalid. + // Unfortunately 0 is a valid offset value for a QuestionId + // + + // + // Reserve INVALID_OFFSET_VALUE - 1 for TRUE or FALSE because they are inconsistency tags also, but + // have no coresponding id. The examination of id is needed by evaluating boolean expression. + // + if (RawFormSet[Index] == EFI_IFR_TRUE_OP || + RawFormSet[Index] == EFI_IFR_FALSE_OP) { + InconsistentTags->QuestionId1 = INVALID_OFFSET_VALUE - 1; + } else { + InconsistentTags->QuestionId1 = INVALID_OFFSET_VALUE; + } + InconsistentTags->QuestionId2 = INVALID_OFFSET_VALUE; + InconsistentTags->ConsistencyId = gConsistencyId; + FormTags->Tags[CurrTag].ConsistencyId = gConsistencyId; + + // + // Test for an allocated buffer. If already allocated this is due to having called this routine + // once for sizing of the NV storage. We then loaded the NV variable and can correctly initialize + // the tag structure with current values from the NV + // + if (InconsistentTags->Next == NULL) { + AddNextInconsistentTag (&InconsistentTags); + break; + } + + InconsistentTags = InconsistentTags->Next; + break; + + case EFI_IFR_EQ_ID_LIST_OP: + IfrToFormTag (RawFormSet[Index], &FormTags->Tags[CurrTag], (VOID *) &RawFormSet[Index], NULL); + + InconsistentTags->Operand = ((EFI_IFR_EQ_ID_LIST *) &RawFormSet[Index])->Header.OpCode; + CopyMem ( + &InconsistentTags->QuestionId1, + &((EFI_IFR_EQ_ID_LIST *) &RawFormSet[Index])->QuestionId, + sizeof (UINT16) + ); + CopyMem ( + &InconsistentTags->ListLength, + &((EFI_IFR_EQ_ID_LIST *) &RawFormSet[Index])->ListLength, + sizeof (UINT16) + ); + InconsistentTags->ValueList = FormTags->Tags[CurrTag].IntList; + + // + // Since this op-code doesn't use the next field(s), initialize them with something invalid. + // Unfortunately 0 is a valid offset value for a QuestionId + // + InconsistentTags->Width = FormTags->Tags[CurrTag].StorageWidth; + InconsistentTags->QuestionId2 = INVALID_OFFSET_VALUE; + InconsistentTags->ConsistencyId = gConsistencyId; + FormTags->Tags[CurrTag].ConsistencyId = gConsistencyId; + + // + // Test for an allocated buffer. If already allocated this is due to having called this routine + // once for sizing of the NV storage. We then loaded the NV variable and can correctly initialize + // the tag structure with current values from the NV + // + if (InconsistentTags->Next == NULL) { + AddNextInconsistentTag (&InconsistentTags); + break; + } + + InconsistentTags = InconsistentTags->Next; + break; + + case EFI_IFR_END_IF_OP: + InconsistentTags->Operand = ((EFI_IFR_END_EXPR *) &RawFormSet[Index])->Header.OpCode; + + // + // Since this op-code doesn't use the next field(s), initialize them with something invalid. + // Unfortunately 0 is a valid offset value for a QuestionId + // + InconsistentTags->QuestionId1 = INVALID_OFFSET_VALUE; + InconsistentTags->QuestionId2 = INVALID_OFFSET_VALUE; + + // + // Test for an allocated buffer. If already allocated this is due to having called this routine + // once for sizing of the NV storage. We then loaded the NV variable and can correctly initialize + // the tag structure with current values from the NV + // + if (InconsistentTags->Next == NULL) { + AddNextInconsistentTag (&InconsistentTags); + break; + } + + InconsistentTags = InconsistentTags->Next; + break; + + case EFI_IFR_END_ONE_OF_OP: + break; + + default: + break; + } + // + // End of switch + // + // Per spec., we ignore ops that we don't know how to deal with. Skip to next tag + // + Index = (UINT16) (Index + TagLength); + } + // + // End of Index + // + // When we eventually exit, make sure we mark the last tag with an op-code + // + FormTags->Tags[CurrTag].Operand = RawFormSet[Index]; + + IfrToFormTag (RawFormSet[Index], &FormTags->Tags[CurrTag], (VOID *) &RawFormSet[Index], NULL); + + // + // Place this as an end of the database marker + // + InconsistentTags->Operand = 0xFF; + + // + // This is the Head of the linked list of pages. Each page is an array of tags + // + FormTags = &FileFormTags->FormTags; + InconsistentTags = FileFormTags->InconsistentTags; + + for (; InconsistentTags->Operand != 0xFF;) { + if (InconsistentTags->QuestionId1 != INVALID_OFFSET_VALUE) { + // + // Search the tags for the tag which corresponds to this ID + // + for (CurrTag = 0; FormTags->Tags[0].Operand != EFI_IFR_END_FORM_SET_OP; CurrTag++) { + // + // If we hit the end of a form, go to the next set of Tags. + // Remember - EndFormSet op-codes sit on their own page after an end form. + // + if (FormTags->Tags[CurrTag].Operand == EFI_IFR_END_FORM_OP) { + // + // Reset the CurrTag value (it will be incremented, after this case statement + // so set to a negative one so that we get the desired effect.) Fish can beat me later. + // + CurrTag = -1; + FormTags = FormTags->Next; + continue; + } + + if (FormTags->Tags[CurrTag].Id == InconsistentTags->QuestionId1) { + FormTags->Tags[CurrTag].Consistency++; + } + } + } + + FormTags = &FileFormTags->FormTags; + + if (InconsistentTags->QuestionId2 != INVALID_OFFSET_VALUE) { + // + // Search the tags for the tag which corresponds to this ID + // + for (CurrTag = 0; FormTags->Tags[CurrTag].Operand != EFI_IFR_END_FORM_SET_OP; CurrTag++) { + // + // If we hit the end of a form, go to the next set of Tags. + // Remember - EndFormSet op-codes sit on their own page after an end form. + // + if (FormTags->Tags[CurrTag].Operand == EFI_IFR_END_FORM_OP) { + // + // Reset the CurrTag value (it will be incremented, after this case statement + // so set to a negative one so that we get the desired effect.) Fish can beat me later. + // + CurrTag = -1; + FormTags = FormTags->Next; + continue; + } + + if (FormTags->Tags[CurrTag].Id == InconsistentTags->QuestionId2) { + FormTags->Tags[CurrTag].Consistency++; + } + } + } + + InconsistentTags = InconsistentTags->Next; + } + + return Status; +} + +VOID +InitPage ( + VOID + ) +{ + CHAR16 *HomePageString; + CHAR16 *HomeEscapeString; + + // + // Displays the Header and Footer borders + // + DisplayPageFrame (); + + HomePageString = GetToken (STRING_TOKEN (HOME_PAGE_TITLE), gHiiHandle); + HomeEscapeString = GetToken (STRING_TOKEN (HOME_ESCAPE_STRING), gHiiHandle); + + gST->ConOut->SetAttribute (gST->ConOut, EFI_YELLOW | EFI_BRIGHT); + // + // PrintStringAt ((gScreenDimensions.RightColumn - GetStringWidth(HomePageString)/2)/2, 1, HomePageString); + // + PrintStringAt ( + (gScreenDimensions.RightColumn + gScreenDimensions.LeftColumn - GetStringWidth (HomePageString) / 2) / 2, + 1, + HomePageString + ); + PrintAt ( + gScreenDimensions.LeftColumn + 2, + gScreenDimensions.BottomRow - 3, + (CHAR16 *) L"%c%c%s", + ARROW_UP, + ARROW_DOWN, + gMoveHighlight + ); + PrintAt ( + gScreenDimensions.RightColumn - (GetStringWidth (HomeEscapeString) / 2) - 2, + gScreenDimensions.BottomRow - 3, + (CHAR16 *) L" %s", + HomeEscapeString + ); + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gBS->FreePool (HomeEscapeString); + gBS->FreePool (HomePageString); + + return ; +} + +CHAR16 * +GetToken ( + IN STRING_REF Token, + IN EFI_HII_HANDLE HiiHandle + ) +/*++ + +Routine Description: + + Get the string based on the TokenID and HII Handle. + +Arguments: + + Token - The Token ID. + HiiHandle - Handle of Ifr to be fetched. + +Returns: + + The output string. + +--*/ +{ + CHAR16 *Buffer; + UINTN BufferLength; + EFI_STATUS Status; + + // + // Set default string size assumption at no more than 256 bytes + // + BufferLength = 0x100; + + Buffer = AllocateZeroPool (BufferLength); + ASSERT (Buffer != NULL); + + Status = Hii->GetString (Hii, HiiHandle, Token, TRUE, NULL, &BufferLength, Buffer); + + if (EFI_ERROR (Status)) { + if (Status == EFI_BUFFER_TOO_SMALL) { + // + // Free the old pool + // + gBS->FreePool (Buffer); + + // + // Allocate new pool with correct value + // + Buffer = AllocatePool (BufferLength); + ASSERT (Buffer != NULL); + + Status = Hii->GetString (Hii, HiiHandle, Token, TRUE, NULL, &BufferLength, Buffer); + + if (!EFI_ERROR (Status)) { + return Buffer; + } + } + + ASSERT_EFI_ERROR (Status); + } + + return Buffer; +} + +EFI_STATUS +PopulateHomePage ( + IN UINTN NumberOfIfrImages, + IN EFI_FILE_FORM_TAGS *FileFormTagsHead + ) +{ + EFI_STATUS Status; + UINTN Index; + EFI_IFR_BINARY *IfrBinary; + CHAR16 *StringPtr; + EFI_FILE_FORM_TAGS *FileFormTags; + EFI_FORM_TAGS LocalTags; + + FileFormTags = FileFormTagsHead; + + UiInitMenu (); + + Status = EFI_SUCCESS; + + // + // If there are no images + // + if (NumberOfIfrImages == 0) { + Status = EFI_NO_MEDIA; + return Status; + } + // + // IfrBinary points to the beginning of the Binary data linked-list + // + IfrBinary = gBinaryDataHead; + + // + // Print the entries which were in the default language. + // + for (Index = 0; Index < NumberOfIfrImages; Index++) { + LocalTags = FileFormTags->FormTags; + + // + // Populate the Menu + // + StringPtr = GetToken (IfrBinary->TitleToken, IfrBinary->Handle); + + // + // If the default language doesn't exist, don't add a menu option yet + // + if (StringPtr[0] != CHAR_NULL) { + // + // We are NOT!! removing this StringPtr buffer via FreePool since it is being used in the menuoptions, we will do + // it in UiFreeMenu. + // + UiAddMenuOption (StringPtr, IfrBinary->Handle, LocalTags.Tags, IfrBinary->FormBinary, Index); + } + // + // Advance to the next HII handle + // + IfrBinary = IfrBinary->Next; + FileFormTags = FileFormTags->NextFile; + } + + return Status; +} + +UI_MENU_OPTION * +DisplayHomePage ( + IN UINTN NumberOfIfrImages, + IN EFI_FILE_FORM_TAGS *FileFormTagsHead, + IN UINT8 *CallbackData + ) +{ + EFI_STATUS Status; + UI_MENU_OPTION *Selection; + + // + // This prints the basic home page template which the user sees + // + InitPage (); + + Status = PopulateHomePage (NumberOfIfrImages, FileFormTagsHead); + + if (EFI_ERROR (Status)) { + Selection = NULL; + return Selection; + } + + Selection = UiDisplayMenu (FALSE, FileFormTagsHead, (EFI_IFR_DATA_ARRAY *) CallbackData); + + return Selection; +} + +EFI_STATUS +InitializeBinaryStructures ( + IN EFI_HII_HANDLE *Handle, + IN BOOLEAN UseDatabase, + IN EFI_IFR_PACKET *Packet, + IN UINT8 *NvMapOverride, + IN UINTN NumberOfIfrImages, + OUT EFI_FILE_FORM_TAGS **FileFormTagsHead + ) +{ + UINTN HandleIndex; + EFI_STATUS Status; + EFI_IFR_BINARY *BinaryData; + EFI_FILE_FORM_TAGS *FileFormTags; + UINTN SizeOfNvStore; + EFI_FORM_CALLBACK_PROTOCOL *FormCallback; + EFI_VARIABLE_DEFINITION *VariableDefinition; + EFI_VARIABLE_DEFINITION *OverrideDefinition; + VOID *NvMap; + UINTN NvMapSize; + EFI_HII_VARIABLE_PACK_LIST *NvMapListHead; + EFI_HII_VARIABLE_PACK_LIST *NvMapListNode; + + // + // Initialize some variables to avoid warnings + // + BinaryData = NULL; + *FileFormTagsHead = NULL; + FileFormTags = NULL; + gBinaryDataHead = NULL; + Status = EFI_SUCCESS; + FormCallback = NULL; + NvMap = NULL; + NvMapSize = 0; + + if (NumberOfIfrImages > 1) { + NvMapOverride = NULL; + } + + for (HandleIndex = 0; HandleIndex < NumberOfIfrImages; HandleIndex += 1) { + // + // If the buffers are uninitialized, allocate them, otherwise work on the ->Next members + // + if ((BinaryData == NULL) || (FileFormTags == NULL)) { + // + // Allocate memory for our Binary Data + // + BinaryData = AllocateZeroPool (sizeof (EFI_IFR_BINARY)); + ASSERT (BinaryData); + + // + // Preserve the Head of what will be a linked-list. + // + gBinaryDataHead = BinaryData; + gBinaryDataHead->Next = NULL; + + if (UseDatabase) { + Status = GetIfrBinaryData (Hii, Handle[HandleIndex], NULL, BinaryData); + } else { + Status = GetIfrBinaryData (Hii, Handle[HandleIndex], Packet, BinaryData); + } + // + // Allocate memory for our File Form Tags + // + FileFormTags = AllocateZeroPool (sizeof (EFI_FILE_FORM_TAGS)); + ASSERT (FileFormTags); + + // + // Preserve the Head of what will be a linked-list. + // + *FileFormTagsHead = FileFormTags; + (*FileFormTagsHead)->NextFile = NULL; + + } else { + // + // Allocate memory for our Binary Data linked-list + // Each handle represents a Binary and we will store that data away. + // + BinaryData->Next = AllocateZeroPool (sizeof (EFI_IFR_BINARY)); + ASSERT (BinaryData->Next); + + BinaryData = BinaryData->Next; + BinaryData->Next = NULL; + + if (UseDatabase) { + Status = GetIfrBinaryData (Hii, Handle[HandleIndex], NULL, BinaryData); + } else { + Status = GetIfrBinaryData (Hii, Handle[HandleIndex], Packet, BinaryData); + } + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + // + // Allocate memory for our FileFormTags linked-list + // Each allocation reserves handle represents a Binary and we will store that data away. + // + FileFormTags->NextFile = AllocateZeroPool (sizeof (EFI_FILE_FORM_TAGS)); + ASSERT (FileFormTags->NextFile); + + FileFormTags = FileFormTags->NextFile; + } + // + // endif + // + // Tag Structure Initialization + // + Status = InitializeTagStructures (BinaryData, FileFormTags); + + VariableDefinition = FileFormTags->VariableDefinitions; + + // + // Allocate memory for our NVRAM Maps for all of our variables + // + for (; VariableDefinition != NULL; VariableDefinition = VariableDefinition->Next) { + // + // Pad the fake variable size accordingly - this value should reflect the size of information that is not accounted by + // the mainstream NVRAM variable such as DATE/TIME information that the browser needs to track but is saved to an RTC + // + VariableDefinition->VariableFakeSize = (UINT16) (VariableDefinition->VariableSize + VariableDefinition->VariableFakeSize); + + // + // In the case where a file has no "real" NV data, we should pad the buffer accordingly + // + if (VariableDefinition->VariableSize == 0) { + if (VariableDefinition->VariableFakeSize != 0) { + VariableDefinition->NvRamMap = AllocateZeroPool (VariableDefinition->VariableFakeSize); + ASSERT (VariableDefinition->NvRamMap != NULL); + } + } else { + VariableDefinition->NvRamMap = AllocateZeroPool (VariableDefinition->VariableSize); + ASSERT (VariableDefinition->NvRamMap != NULL); + } + + if (VariableDefinition->VariableFakeSize != 0) { + VariableDefinition->FakeNvRamMap = AllocateZeroPool (VariableDefinition->VariableFakeSize); + ASSERT (VariableDefinition->FakeNvRamMap != NULL); + } + } + + Status = gBS->HandleProtocol ( + (VOID *) (UINTN) FileFormTags->FormTags.Tags[0].CallbackHandle, + &gEfiFormCallbackProtocolGuid, + (VOID **) &FormCallback + ); + + // + // Since we might have multiple variables, if there is an NvMapOverride we need to use the EFI_VARIABLE_DEFINITION + // information as the information that we pass back and forth. NOTE that callbacks that are initiated will only have the + // NVRAM data refreshed based on the op-code that initiated the callback. In other words, we will pass to the caller a single + // NVRAM map for a single variable based on the op-code that the user selected. + // + if (NvMapOverride != NULL) { + VariableDefinition = FileFormTags->VariableDefinitions; + OverrideDefinition = ((EFI_VARIABLE_DEFINITION *) NvMapOverride); + + // + // Search through the variable definitions. There should be sufficient passed in settings for the variable op-codes specified + // + for (; VariableDefinition != NULL; VariableDefinition = VariableDefinition->Next) { + if ((!CompareMem (VariableDefinition->VariableName, L"Setup", 10)) && (VariableDefinition->Next == NULL)) { + if (VariableDefinition->VariableSize != 0) { + CopyMem (VariableDefinition->NvRamMap, NvMapOverride, VariableDefinition->VariableSize); + } else { + CopyMem (VariableDefinition->NvRamMap, NvMapOverride, VariableDefinition->VariableFakeSize); + } + break; + } else { + VariableDefinition->NvRamMap = OverrideDefinition->NvRamMap; + } + // + // There should NEVER be a ->Next for VariableDefinition and a NULL ->Next for the OverrideDefinition + // + ASSERT (OverrideDefinition->Next); + OverrideDefinition = OverrideDefinition->Next; + } + } else { + VariableDefinition = FileFormTags->VariableDefinitions; + + // + // Search through the variable definitions. There should be sufficient passed in settings for the variable op-codes specified + // + for (; VariableDefinition != NULL; VariableDefinition = VariableDefinition->Next) { + SizeOfNvStore = VariableDefinition->VariableSize; + + // + // Getting the NvStore and placing it into our Global Data + // + if ((FormCallback != NULL) && (FormCallback->NvRead != NULL)) { + Status = FormCallback->NvRead ( + FormCallback, + VariableDefinition->VariableName, + &VariableDefinition->Guid, + NULL, + &SizeOfNvStore, + (VOID *) VariableDefinition->NvRamMap + ); + } else { + Status = gRT->GetVariable ( + VariableDefinition->VariableName, + &VariableDefinition->Guid, + NULL, + &SizeOfNvStore, + (VOID *) VariableDefinition->NvRamMap + ); + } + + if (EFI_ERROR (Status)) { + // + // If there is a variable that exists already and it is larger than what we calculated the + // storage needs to be, we must assume the variable size from GetVariable is correct and not + // allow the truncation of the variable. It is very possible that the user who created the IFR + // we are cracking is not referring to a variable that was in a previous map, however we cannot + // allow it's truncation. + // + if (Status == EFI_BUFFER_TOO_SMALL) { + // + // If the buffer was too small, we should have the expanded size requirement in SizeOfNvStore now. + // + VariableDefinition->VariableSize = (UINT16) SizeOfNvStore; + + // + // Free the buffer that was allocated that was too small + // + gBS->FreePool (VariableDefinition->NvRamMap); + gBS->FreePool (VariableDefinition->FakeNvRamMap); + + VariableDefinition->NvRamMap = AllocateZeroPool (SizeOfNvStore); + VariableDefinition->FakeNvRamMap = AllocateZeroPool (SizeOfNvStore + VariableDefinition->VariableFakeSize); + ASSERT (VariableDefinition->NvRamMap); + ASSERT (VariableDefinition->FakeNvRamMap); + + if ((FormCallback != NULL) && (FormCallback->NvRead != NULL)) { + Status = FormCallback->NvRead ( + FormCallback, + VariableDefinition->VariableName, + &VariableDefinition->Guid, + NULL, + &SizeOfNvStore, + (VOID *) VariableDefinition->NvRamMap + ); + } else { + Status = gRT->GetVariable ( + VariableDefinition->VariableName, + &VariableDefinition->Guid, + NULL, + &SizeOfNvStore, + (VOID *) VariableDefinition->NvRamMap + ); + } + } + // + // if the variable was not found, we will retrieve default values + // + if (Status == EFI_NOT_FOUND) { + + if (0 == CompareMem (VariableDefinition->VariableName, L"Setup", 10)) { + + NvMapListHead = NULL; + + Status = Hii->GetDefaultImage (Hii, Handle[HandleIndex], EFI_IFR_FLAG_DEFAULT, &NvMapListHead); + + if (!EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (NULL != NvMapListHead); + + NvMapListNode = NvMapListHead; + + while (NULL != NvMapListNode) { + if (VariableDefinition->VariableId == NvMapListNode->VariablePack->VariableId) { + NvMap = (VOID *) ((CHAR8 *) NvMapListNode->VariablePack + sizeof (EFI_HII_VARIABLE_PACK) + NvMapListNode->VariablePack->VariableNameLength); + NvMapSize = NvMapListNode->VariablePack->Header.Length - sizeof (EFI_HII_VARIABLE_PACK) - NvMapListNode->VariablePack->VariableNameLength; + break; + } + NvMapListNode = NvMapListNode->NextVariablePack; + } + + // + // Free the buffer that was allocated. + // + gBS->FreePool (VariableDefinition->NvRamMap); + gBS->FreePool (VariableDefinition->FakeNvRamMap); + + // + // Allocate, copy the NvRamMap. + // + VariableDefinition->VariableFakeSize = (UINT16) (VariableDefinition->VariableFakeSize - VariableDefinition->VariableSize); + VariableDefinition->VariableSize = (UINT16) NvMapSize; + VariableDefinition->VariableFakeSize = (UINT16) (VariableDefinition->VariableFakeSize + VariableDefinition->VariableSize); + + VariableDefinition->NvRamMap = AllocateZeroPool (VariableDefinition->VariableSize); + VariableDefinition->FakeNvRamMap = AllocateZeroPool (NvMapSize + VariableDefinition->VariableFakeSize); + + CopyMem (VariableDefinition->NvRamMap, NvMap, NvMapSize); + gBS->FreePool (NvMapListHead); + } + + } + Status = EFI_SUCCESS; + } + } + } + } + + InitializeTagStructures (BinaryData, FileFormTags); + } + // + // endfor + // + return Status; +} + +EFI_STATUS +GetIfrBinaryData ( + IN EFI_HII_PROTOCOL *Hii, + IN EFI_HII_HANDLE HiiHandle, + IN EFI_IFR_PACKET *Packet, + IN OUT EFI_IFR_BINARY *BinaryData + ) +/*++ + +Routine Description: + Fetch the Ifr binary data. + +Arguments: + Hii - Point to HII protocol. + HiiHandle - Handle of Ifr to be fetched. + Packet - Pointer to IFR packet. + BinaryData - Buffer to copy the string into + +Returns: + Returns the number of CHAR16 characters that were copied into the OutputString buffer. + + +--*/ +{ + EFI_STATUS Status; + EFI_HII_PACKAGES *PackageList; + UINTN BufferSize; + VOID *Buffer; + UINT8 *RawFormBinary; + EFI_IFR_FORM_SET *FormOp; + UINT16 Index; + UINT16 Index2; + UINT16 TitleToken; + + // + // Initialize the TitleToken to 0 just in case not found + // + TitleToken = 0; + + // + // Try for a 32K Buffer + // + BufferSize = 0x8000; + + // + // Allocate memory for our Form binary + // + Buffer = AllocateZeroPool (BufferSize); + ASSERT (Buffer); + + if (Packet == NULL) { + Status = Hii->GetForms (Hii, HiiHandle, 0, &BufferSize, Buffer); + + if (Status == EFI_BUFFER_TOO_SMALL) { + + gBS->FreePool (Buffer); + + // + // Allocate memory for our Form binary + // + Buffer = AllocatePool (BufferSize); + ASSERT (Buffer); + + Status = Hii->GetForms (Hii, HiiHandle, 0, &BufferSize, Buffer); + } + } else { + // + // Copies the data to local usable buffer + // + CopyMem (Buffer, Packet->IfrData, Packet->IfrData->Header.Length); + + // + // Register the string data with HII + // + PackageList = PreparePackages (2, NULL, Packet->IfrData, Packet->StringData); + + Status = Hii->NewPack (Hii, PackageList, &HiiHandle); + + gBS->FreePool (PackageList); + } + + if (EFI_ERROR (Status)) { + return Status; + } + // + // We now have the IFR binary in our Buffer + // + BinaryData->IfrPackage = Buffer; + RawFormBinary = (UINT8 *) ((CHAR8 *) (Buffer) + sizeof (EFI_HII_PACK_HEADER)); + BinaryData->FormBinary = (UINT8 *) ((CHAR8 *) (Buffer) + sizeof (EFI_HII_PACK_HEADER)); + BinaryData->Handle = HiiHandle; + + // + // If a packet was passed in, remove the string data when exiting. + // + if (Packet != NULL) { + BinaryData->UnRegisterOnExit = TRUE; + } else { + BinaryData->UnRegisterOnExit = FALSE; + } + // + // Walk through the FormSet Opcodes looking for the FormSet opcode + // If we hit EFI_IFR_END_SET_OP we know we hit the end of the FormSet. + // + for (Index = 0; RawFormBinary[Index] != EFI_IFR_END_FORM_SET_OP;) { + FormOp = (EFI_IFR_FORM_SET *) &RawFormBinary[Index]; + Index = (UINT16) (Index + FormOp->Header.Length); + + if (FormOp->Header.OpCode == EFI_IFR_FORM_SET_OP) { + TitleToken = FormOp->FormSetTitle; + // + // If displaying FrontPage - set the flag signifying it + // + switch (FormOp->SubClass) { + case EFI_FRONT_PAGE_SUBCLASS: + FrontPageHandle = HiiHandle; + + default: + gClassOfVfr = FormOp->SubClass; + } + // + // Match GUID to find out the function key setting. If match fail, use the default setting. + // + for (Index2 = 0; Index2 < sizeof (gFunctionKeySettingTable) / sizeof (FUNCTIION_KEY_SETTING); Index2++) { + if (CompareGuid ((EFI_GUID *)(UINTN)&FormOp->Guid, &(gFunctionKeySettingTable[Index2].FormSetGuid))) { + // + // Update the function key setting. + // + gFunctionKeySetting = gFunctionKeySettingTable[Index2].KeySetting; + // + // Function key prompt can not be displayed if the function key has been disabled. + // + if ((gFunctionKeySetting & FUNCTION_ONE) != FUNCTION_ONE) { + gFunctionOneString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); + } + + if ((gFunctionKeySetting & FUNCTION_TWO) != FUNCTION_TWO) { + gFunctionTwoString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); + } + + if ((gFunctionKeySetting & FUNCTION_NINE) != FUNCTION_NINE) { + gFunctionNineString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); + } + + if ((gFunctionKeySetting & FUNCTION_TEN) != FUNCTION_TEN) { + gFunctionTenString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); + } + } + } + } + } + + BinaryData->TitleToken = TitleToken; + + return Status; +} + +EFI_HANDLE PrintHandle = NULL; +EFI_PRINT_PROTOCOL mPrintProtocol = { UnicodeVSPrint }; + +EFI_STATUS +InstallPrint ( + VOID + ) +{ + return gBS->InstallProtocolInterface ( + &PrintHandle, + &gEfiPrintProtocolGuid, + EFI_NATIVE_INTERFACE, + &mPrintProtocol + ); +} diff --git a/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Setup.h b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Setup.h new file mode 100644 index 0000000000..6089d765ce --- /dev/null +++ b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Setup.h @@ -0,0 +1,504 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Setup.h + +Abstract: + + +Revision History + +--*/ + +#ifndef _SETUP_H +#define _SETUP_H + +// +// This is the generated header file which includes whatever needs to be exported (strings + IFR) +// +#include "SetupBrowserStrDefs.h" +extern UINT8 SetupBrowserStrings[]; + +// +// Screen definitions +// +#define BANNER_HEIGHT 4 +#define BANNER_COLUMNS 3 + +#define FRONT_PAGE_HEADER_HEIGHT 4 +#define NONE_FRONT_PAGE_HEADER_HEIGHT 3 +#define LEFT_SKIPPED_COLUMNS 4 +#define FOOTER_HEIGHT 4 +#define STATUS_BAR_HEIGHT 1 +#define SCROLL_ARROW_HEIGHT 1 +#define POPUP_PAD_SPACE_COUNT 5 +#define POPUP_FRAME_WIDTH 2 + + +#define EFI_SETUP_APPLICATION_SUBCLASS 0x00 +#define EFI_GENERAL_APPLICATION_SUBCLASS 0x01 +#define EFI_FRONT_PAGE_SUBCLASS 0x02 +#define EFI_SINGLE_USE_SUBCLASS 0x03 // Used to display a single entity and then exit +// +// Definition for function key setting +// +#define NONE_FUNCTION_KEY_SETTING 0 +#define DEFAULT_FUNCTION_KEY_SETTING (FUNCTION_ONE | FUNCTION_TWO | FUNCTION_NINE | FUNCTION_TEN) + +#define FUNCTION_ONE (1 << 0) +#define FUNCTION_TWO (1 << 1) +#define FUNCTION_NINE (1 << 2) +#define FUNCTION_TEN (1 << 3) + +typedef struct { + EFI_GUID FormSetGuid; + UINTN KeySetting; +} FUNCTIION_KEY_SETTING; + +// +// Character definitions +// +#define CHAR_SPACE 0x0020 +#define UPPER_LOWER_CASE_OFFSET 0x20 + +// +// Time definitions +// +#define ONE_SECOND 10000000 + +// +// Display definitions +// +#define LEFT_HYPER_DELIMITER L'<' +#define RIGHT_HYPER_DELIMITER L'>' + +#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 YES_ANSWER L'Y' +#define NO_ANSWER L'N' + +// +// Up to how many lines does the ordered list display +// +#define ORDERED_LIST_SIZE 4 + +// +// This is the Input Error Message +// +#define INPUT_ERROR 1 + +// +// This is the NV RAM update required Message +// +#define NV_UPDATE_REQUIRED 2 + +// +// Refresh the Status Bar with flags +// +#define REFRESH_STATUS_BAR 0xff + +// +// This width is basically the sum of the prompt and option widths +// +#define QUESTION_BLOCK_WIDTH 50 + +// +// Width of the Language Description (Using ISO-639-2 3 ASCII letter standard) +// +#define LANG_DESC_WIDTH 3 + +// +// Maximum Number of Binaries we can see +// +#define MAX_BINARIES 255 + +// +// Invalid Handle +// +#define EFI_HII_INVALID_HANDLE 0xFFFF + +// +// Invalid Offset Value +// +#define INVALID_OFFSET_VALUE 0xFFFF + +struct StringPart { + struct StringPart *Next; + CHAR8 String[QUESTION_BLOCK_WIDTH + 2]; +}; + +// +// The tag definition defines the data associated with a tag (an operation +// in the IFR lingo). The tag is thus a modified union of all the data +// required for tags. The user should be careful to only rely upon information +// relevant to that tag as the contents of other fields is undefined. +// +// The intent here is for this to be all of the data associated with a particular tag. +// Some of this data is extracted from the IFR and left alone. Other data will be derived +// when the page is selected (since that's the first time we really know what language the +// page is to be displayed in) and still other data will vary based on the selection. +// If you'd like to consider alternatives, let me know. This structure has grown somewhat organically. +// It gets a new item stuffed in it when a new item is needed. When I finally decided I needed the +// StringPart structure, items got added here, for example. +// +typedef struct { + UINT8 Operand; // The operand (first byte) of the variable length tag. + EFI_GUID GuidValue; // Primarily for FormSet data + EFI_PHYSICAL_ADDRESS CallbackHandle; + UINT16 Class; + UINT16 SubClass; + UINT16 NumberOfLines; // The number of lines the tag takes up on the page. Adjusted when we display the page as it can change from language to language. + UINT16 PageLine; + UINT16 PageColumn; + UINT16 OptionWidth; // The option can be wider than the column usually associated with options. This is the width on the last option line + STRING_REF Text; // Used for title, subtitle, prompt, etc. This is the string token associated with the string. This token is language independent. + STRING_REF TextTwo; // Used for title, subtitle, prompt, etc. This is the string token associated with the string. This token is language independent. + STRING_REF Help; // Null means no help Same as above but for languages. + UINT16 Consistency; // Do we need to check this opcode against consistency? If > 0, yes. + UINT16 Id; + UINT16 Id2; // The questions (mainly) have identifiers associated with them. These are filled in from the IFR tags and used by e.g. the RPN calculations. (com1 is set to, versus com2 is set to) + // + // These are the three values that are created to determine where in the variable the data is stored. This should, in general, + // be allocated by the build tool. The one major issue is, once storage is allocated for something, it can't be reallocated or we will get a mess. + // + UINT16 StorageStart; + // + // These are the three values that are created to determine where in the variable the data is stored. This should, in general, + // be allocated by the build tool. The one major issue is, once storage is allocated for something, it can't be reallocated or we will get a mess. + // + UINT8 StorageWidth; + // + // These are the three values that are created to determine where in the variable the data is stored. This should, in general, + // be allocated by the build tool. The one major issue is, once storage is allocated for something, it can't be reallocated or we will get a mess. + // + UINT16 Value; + // + // (Default or current) + // + UINT8 Flags; + UINT16 Key; + // + // Used to preserve a value during late consistency checking + // + UINT16 OldValue; + UINT16 Minimum; + UINT16 Maximum; + UINT16 Step; + UINT16 Default; + UINT16 NvDataSize; + UINT16 ConsistencyId; + BOOLEAN GrayOut; + BOOLEAN Suppress; + UINT16 Encoding; // Data from the tags. The first three are used by the numeric input. Encoding is used by the password stuff (a placeholder today - may go away). + UINT16 *IntList; // List of the values possible for a list question + // + // The string is obtained from the string list and formatted into lines and the lines are held in this linked list. + // If we have more than a screen's worth of items, we will end up with cases where we have to display the last couple + // lines of a tag's string above the currently selected one, or, display a few lines of a tag at the bottom of a screen. + // + struct StringPart *StringList; + BOOLEAN ResetRequired; // Primarily used to determine if a reset is required by changing this op-code. + UINT16 VariableNumber; // Used to define which variable the StorageStart will be pertinent for (0-based) For single variable VFR this will always be 0. + // + // Used to define which variable the StorageStart will be pertinent for (0-based) This is used for boolean check of ID versus ID + // so that a user can compare the value of one variable.field content versus another variable.field content. + // + UINT16 VariableNumber2; +} EFI_TAG; + +#define EFI_FORM_DATA_SIGNATURE EFI_SIGNATURE_32 ('F', 'o', 'r', 'm') + +typedef struct { + UINTN Signature; + + EFI_HII_PROTOCOL *Hii; + EFI_FORM_BROWSER_PROTOCOL FormConfig; +} EFI_FORM_CONFIGURATION_DATA; + +#define EFI_FORM_DATA_FROM_THIS(a) CR (a, EFI_FORM_CONFIGURATION_DATA, FormConfig, EFI_FORM_DATA_SIGNATURE) + +typedef struct _EFI_VARIABLE_DEFINITION { + CHAR8 *NvRamMap; + CHAR8 *FakeNvRamMap; // This is where the storage for NULL devices go (e.g. RTC) + EFI_GUID Guid; + UINT16 VariableId; + UINT16 VariableSize; + UINT16 VariableFakeSize; // For dynamically created and NULL device options, this is the latest size + CHAR16 *VariableName; + struct _EFI_VARIABLE_DEFINITION *Next; + struct _EFI_VARIABLE_DEFINITION *Previous; +} EFI_VARIABLE_DEFINITION; + +typedef struct { + UINT32 Length; // Length in bytes between beginning of struc and end of Strings + CHAR8 LanguageCode[4]; // ISO-639-2 language code with a null-terminator + RELOFST PrintableLanguageName; // Translated name of the Language, "English"/"Espanol" etc + UINT32 Attributes; // If on, the language is intended to be printed right to left. The default (off) is to print left to right. + RELOFST StringsPointers[1]; // Pointing to string offset from beginning of String Binary + EFI_STRING Strings[1]; // Array of String Entries. Note the number of entries for Strings and StringsPointers will be the same +} EFI_LANGUAGE_SET; + +// +// This encapsulates all the pointers associated with found IFR binaries +// +typedef struct _EFI_IFR_BINARY { + struct _EFI_IFR_BINARY *Next; + VOID *IfrPackage; // Handy for use in freeing the data later since this is the header of the buffer + VOID *FormBinary; + EFI_HII_HANDLE Handle; + STRING_REF TitleToken; + BOOLEAN UnRegisterOnExit; +} EFI_IFR_BINARY; + +// +// This encapsulates all the questions (tags) for a particular Form Set +// +typedef struct _EFI_FORM_TAGS { + struct _EFI_FORM_TAGS *Next; + EFI_TAG *Tags; +} EFI_FORM_TAGS; + +// +// This is the database of all inconsistency data. Each op-code associated +// with inconsistency will be tracked here. This optimizes the search requirement +// since we will back mark the main tag structure with the op-codes that have reference +// to inconsistency data. This way when parsing the main tag structure and encountering +// the inconsistency mark - we can search this database to know what the inconsistency +// parameters are for that entry. +// +typedef struct _EFI_INCONSISTENCY_DATA { + struct _EFI_INCONSISTENCY_DATA *Next; + struct _EFI_INCONSISTENCY_DATA *Previous; + UINT8 Operand; + STRING_REF Popup; + UINT16 QuestionId1; + UINT16 QuestionId2; + UINT16 Value; + UINT16 ListLength; + UINT16 ConsistencyId; + UINT16 *ValueList; + UINT16 VariableNumber; + UINT16 VariableNumber2; + UINT8 Width; +} EFI_INCONSISTENCY_DATA; + +// +// Encapsulating all found Tag information from all sources +// Each encapsulation also contains the NvRamMap buffer and the Size of the NV store +// +typedef struct _EFI_FILE_FORM_TAGS { + struct _EFI_FILE_FORM_TAGS *NextFile; + EFI_INCONSISTENCY_DATA *InconsistentTags; + EFI_VARIABLE_DEFINITION *VariableDefinitions; + EFI_FORM_TAGS FormTags; +} EFI_FILE_FORM_TAGS; + +typedef struct { + STRING_REF Banner[BANNER_HEIGHT][BANNER_COLUMNS]; +} BANNER_DATA; + +// +// Head of the Binary structures +// +EFI_IFR_BINARY *gBinaryDataHead; + +// +// The IFR binary that the user chose to run +// +UINTN gActiveIfr; + +EFI_HII_PROTOCOL *Hii; + +VOID *CachedNVEntry; +BANNER_DATA *BannerData; +EFI_HII_HANDLE FrontPageHandle; +STRING_REF FrontPageTimeOutTitle; +INT16 FrontPageTimeOutValue; +UINTN gClassOfVfr; +UINTN gFunctionKeySetting; +BOOLEAN gResetRequired; +BOOLEAN gExitRequired; +BOOLEAN gSaveRequired; +BOOLEAN gNvUpdateRequired; +UINT16 gConsistencyId; +UINTN gPriorMenuEntry; +EFI_HII_HANDLE gHiiHandle; +BOOLEAN gFirstIn; +VOID *gPreviousValue; +UINT16 gDirection; +EFI_SCREEN_DESCRIPTOR gScreenDimensions; +BOOLEAN gUpArrow; +BOOLEAN gDownArrow; +BOOLEAN gTimeOnScreen; +BOOLEAN gDateOnScreen; + +// +// Browser Global Strings +// +CHAR16 *gFunctionOneString; +CHAR16 *gFunctionTwoString; +CHAR16 *gFunctionNineString; +CHAR16 *gFunctionTenString; +CHAR16 *gEnterString; +CHAR16 *gEnterCommitString; +CHAR16 *gEscapeString; +CHAR16 *gMoveHighlight; +CHAR16 *gMakeSelection; +CHAR16 *gNumericInput; +CHAR16 *gToggleCheckBox; +CHAR16 *gPromptForPassword; +CHAR16 *gPromptForNewPassword; +CHAR16 *gConfirmPassword; +CHAR16 *gConfirmError; +CHAR16 *gPressEnter; +CHAR16 *gEmptyString; +CHAR16 *gAreYouSure; +CHAR16 *gYesResponse; +CHAR16 *gNoResponse; +CHAR16 *gMiniString; +CHAR16 *gPlusString; +CHAR16 *gMinusString; +CHAR16 *gAdjustNumber; + +CHAR16 gPromptBlockWidth; +CHAR16 gOptionBlockWidth; +CHAR16 gHelpBlockWidth; + +// +// Global Procedure Defines +// +VOID +InitializeBrowserStrings ( + VOID + ) +; + +UINTN +Print ( + IN CHAR16 *fmt, + ... + ) +; + +UINTN +PrintString ( + CHAR16 *String + ) +; + +UINTN +PrintChar ( + CHAR16 Character + ) +; + +UINTN +PrintAt ( + IN UINTN Column, + IN UINTN Row, + IN CHAR16 *fmt, + ... + ) +; + +UINTN +PrintStringAt ( + IN UINTN Column, + IN UINTN Row, + CHAR16 *String + ) +; + +UINTN +PrintCharAt ( + IN UINTN Column, + IN UINTN Row, + CHAR16 Character + ) +; + +VOID +DisplayPageFrame ( + VOID + ) +; + +CHAR16 * +GetToken ( + IN STRING_REF IfrBinaryTitle, + IN EFI_HII_HANDLE HiiHandle + ) +; + +VOID +GetTagCount ( + IN UINT8 *RawFormSet, + IN OUT UINT16 *NumberOfTags + ) +; + +VOID +GetNumericHeader ( + IN EFI_TAG *Tag, + IN UINT8 *RawFormSet, + IN UINT16 Index, + IN UINT16 NumberOfLines, + IN EFI_FILE_FORM_TAGS *FileFormTags, + IN UINT16 CurrentVariable + ) +; + +VOID +GetQuestionHeader ( + IN EFI_TAG *Tag, + IN UINT8 *RawFormSet, + IN UINT16 Index, + IN EFI_FILE_FORM_TAGS *FileFormTags, + IN UINT16 CurrentVariable + ) +; + +VOID +CreateSharedPopUp ( + IN UINTN RequestedWidth, + IN UINTN NumberOfLines, + IN CHAR16 **ArrayOfStrings + ) +; + +EFI_STATUS +CreateDialog ( + IN UINTN NumberOfLines, + IN BOOLEAN HotKey, + IN UINTN MaximumStringSize, + OUT CHAR16 *StringBuffer, + OUT EFI_INPUT_KEY *KeyValue, + IN CHAR16 *String, + ... + ) +; + +#endif diff --git a/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/SetupBrowser.mbd b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/SetupBrowser.mbd new file mode 100644 index 0000000000..6a3eec14b1 --- /dev/null +++ b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/SetupBrowser.mbd @@ -0,0 +1,43 @@ + + + + + SetupBrowser + EBf342FE-B1D3-4EF8-957C-8048606FF670 + 0 + FIX ME! + Copyright (c) 2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + BaseLib + BaseDebugLibNull + BaseMemoryLib + BasePrintLib + UefiDriverEntryPoint + DxeMemoryAllocationLib + EdkGraphicsLib + DxeReportStatusCodeLib + HiiLib + + diff --git a/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/SetupBrowser.msa b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/SetupBrowser.msa new file mode 100644 index 0000000000..c0e40a3993 --- /dev/null +++ b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/SetupBrowser.msa @@ -0,0 +1,82 @@ + + + + + SetupBrowser + DXE_DRIVER + BS_DRIVER + EBf342FE-B1D3-4EF8-957C-8048606FF670 + 0 + Component description file for DiskIo module. + FIX ME! + Copyright (c) 2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + BaseLib + DebugLib + BaseMemoryLib + MemoryAllocationLib + UefiDriverEntryPoint + EdkIfrSupportLib + PrintLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + HiiLib + EdkGraphicsLib + + + SetupBrowserStr.uni + Setup.c + Setup.h + Boolean.c + InputHandler.c + Print.c + Print.h + Presentation.c + ProcessOptions.c + Ui.c + Ui.h + + + MdePkg + EdkModulePkg + + + Hii + FormCallback + FormBrowser + Print + + + + + EFI_EVENT_TIMER + + + + + + InitializeSetup + + + diff --git a/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/SetupBrowserStr.uni b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/SetupBrowserStr.uni new file mode 100644 index 0000000000000000000000000000000000000000..1dfd9247a3639241e95223f221a3c46c1494ba10 GIT binary patch literal 11028 zcmdU#T~ix36oz%%&h$TQ$VKzfK$3nY6VfqYf}3DGV48Bp00!a~OvZLX@^5?B=B7WP z?fd9hXm_(_ZQ{u$vx9e~)k?2koi82n-@glP!6ojNyRGXh_oYe;7x%<1yEFIFy>)%p zb;s_78>;OMci?X7e&5~I^@ICH&kfhpyF+)PXTIs{D}MJ>+tpJ~^&k5Rvq@Y{xIh+X zG4Q2BHxTB&d#&G&n^#?1bL^@%5&ph#ANx6+s=TK;baWr8#i1`Bh=((Gs+PQatM7Vh zpQwge({EQ#C%(7o=N{4TsV7D}QGW+|>Uq>)378nMGeY%R&t0|MbNl+`yH_4Lcp`ek zcj~c)UYHGY>|U%HJe;|s)OSm6%dM#VEQ96!*+ul{p3wvSf;Y=qSNIqMPK|X&AE*p> z`$8V1hqbZQVMa%KV=Kx$-l$a`XO=5llecQM?-@DLtc(>f@pbl!=#luLR`{XU3v|Kw z=li~2jd}Ie*Sas{)@Puaea)rg?&RLgtCtu0%Z@p_Qba$yK0jVh5q;aOxw=?txlOm> zp6Ivc)>Upu1`|mk_qJ*qZpm%ysqQ6n+ckBss~&l=9-`DXWS#12vE_T-&=b~y-#Ojs zmtN;|U-D&2*tbcqi2k{HV*Cw{EpgA)-=?2KQ}qpv&uAMS=cY=`k~+|})s{BkvsSBW z3(g(gpXv>B1Xq1Dip{s~e!J)=_TCU{Eom%cu6QdqZZ;8pd|H=$cf7u#c}?ldsdV7s zg^!3W>2*u*hHCv%{9!-Or2$x;E!FllHd@!c_%=yB)x5UQ3M(;8jgW3-W0-v~Ym41G zQlIo2ti?b`&~YqY7RP*Q#EATkboAE9?@?=S7TtCKMCrP87(03F?JO1%JAk#H6RSL7 zaR$=sIseW3?T`G-Xus;8dhRdv$T#+djS_61^^NqbtN&fCUrido6LQhkYN8pJUlGGA zjdU!;5j8mCT1Eej-^SaRe=ua1k23AsB2|=ZRF7}G+MPs{7$YvCZ~z_PVQ+FT7slVB>BqoyRYIiWt5%h3bzw5e6X*AUGO#T5|( zo?*}XuA$yl!&e^LpB~w}5weJ@oHHVv=FDX4p7w5N-=5$7RKraXhCB}z4-wx?W_7YQ zy-ao4zG--zK8lF4SjJ=U*(-j152TfS`5kg8FZ4__ zh;^$%3Ij5t!r%R>+PdNu@kVKc>*vAmn z-uCPzT9q^J6>L8j>|w~`ZC4bZ1$49E5gUm7U5&{y9!(0%cw7<7=VHGKtqurh!{vr_ zj9tN+Sbd^jat++uUas;|m@SuaxtNm1HCacp(CoD>8(jr=?D__}%+|4cBDah^B+p2c zPChx$r8b7+9 z+ygNd^6zBUkv#k|`KFgz>FDdO&R5ZwWgHeGWk-+yHEF~-_tI@e ziBEJPmAhh@9O|;9byvQ6Lm9>*ys@qbdD_Q3l4NpXg8c1!ZXav)IB6k=h7KVcMBsnu z{n>>i#1UrkRD?1uqeUo}gqF+-XAj^cBM4e*DVqi0+zaU#s-CE=SpO}jO>u{rKVFjI(a`gr-54{$&IUP;^O%lp@(<4^V0~6>_k{dh*gs#^dwzxRZe&%a zT?KZZP04ygvb{b5?^)@eZWZh-lXHQ-_j*z0Kc`j5&caS`(^@dw^}wrg(l(pj7+K1+ zZNd8lPYQ0dH=L!D%_m-}BAR=qalvL5#e60fCTJn?@hzG z9y^Vg%gW03_)@vlGd?_%Y2oD1cGH#tHTfaK-;=&p#V=mcPL(Wb4oErgOyo~3W(gSk zQ+do4c}z}A$1`Ye%6Y`6mwU{P+Tf9@kksisrAac}hUl+25@~AhwyOxbrFa7_iTOBl zBo47N$IG}a}r?Iw~DnbmSg_A0@>Y>2ix{@-S#!v`HU--&9gR&J1vgD7x4c-hwf)to*No-K~i{jIJ>fah1&eRxZm{NEc841Y?_h@#wkKjJYIS? z)tqu3$;Et&7)sBCp6$O|@^i8LWaCOYTRx-g{?PJR7G3hpE{yCNzM0d9@EOV literal 0 HcmV?d00001 diff --git a/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Ui.c b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Ui.c new file mode 100644 index 0000000000..0d512fd34e --- /dev/null +++ b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Ui.c @@ -0,0 +1,3143 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Ui.c + +Abstract: + + Implementation for UI. + +Revision History + +--*/ + +#include "Setup.h" +#include "Ui.h" +#include "Colors.h" + +// +// Implementation +// +VOID +SetUnicodeMem ( + IN VOID *Buffer, + IN UINTN Size, + IN CHAR16 Value + ) +/*++ + +Routine Description: + + Set Buffer to Value for Size bytes. + +Arguments: + + Buffer - Memory to set. + + Size - Number of bytes to set + + Value - Value of the set operation. + +Returns: + + None + +--*/ +{ + CHAR16 *Ptr; + + Ptr = Buffer; + while (Size--) { + *(Ptr++) = Value; + } +} + +VOID +UiInitMenu ( + VOID + ) +/*++ + +Routine Description: + Initialize Menu option list. + +Arguments: + +Returns: + +--*/ +{ + InitializeListHead (&Menu); +} + +VOID +UiInitMenuList ( + VOID + ) +/*++ + +Routine Description: + Initialize Menu option list. + +Arguments: + +Returns: + +--*/ +{ + InitializeListHead (&gMenuList); +} + +VOID +UiRemoveMenuListEntry ( + IN UI_MENU_OPTION *Selection, + OUT UI_MENU_OPTION **PreviousSelection + ) +/*++ + +Routine Description: + Remove Menu option list. + +Arguments: + +Returns: + +--*/ +{ + UI_MENU_LIST *UiMenuList; + + *PreviousSelection = AllocateZeroPool (sizeof (UI_MENU_OPTION)); + ASSERT (*PreviousSelection != NULL); + + if (!IsListEmpty (&gMenuList)) { + UiMenuList = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE); + (*PreviousSelection)->IfrNumber = UiMenuList->Selection.IfrNumber; + (*PreviousSelection)->FormId = UiMenuList->Selection.FormId; + (*PreviousSelection)->Tags = UiMenuList->Selection.Tags; + (*PreviousSelection)->ThisTag = UiMenuList->Selection.ThisTag; + (*PreviousSelection)->Handle = UiMenuList->Selection.Handle; + gEntryNumber = UiMenuList->FormerEntryNumber; + RemoveEntryList (&UiMenuList->MenuLink); + gBS->FreePool (UiMenuList); + } +} + +VOID +UiFreeMenuList ( + VOID + ) +/*++ + +Routine Description: + Free Menu option linked list. + +Arguments: + +Returns: + +--*/ +{ + UI_MENU_LIST *UiMenuList; + + while (!IsListEmpty (&gMenuList)) { + UiMenuList = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE); + RemoveEntryList (&UiMenuList->MenuLink); + gBS->FreePool (UiMenuList); + } +} + +VOID +UiAddMenuListEntry ( + IN UI_MENU_OPTION *Selection + ) +/*++ + +Routine Description: + Add one menu entry to the linked lst + +Arguments: + +Returns: + +--*/ +{ + UI_MENU_LIST *UiMenuList; + + UiMenuList = AllocateZeroPool (sizeof (UI_MENU_LIST)); + ASSERT (UiMenuList != NULL); + + UiMenuList->Signature = UI_MENU_LIST_SIGNATURE; + CopyMem (&UiMenuList->Selection, Selection, sizeof (UI_MENU_OPTION)); + + InsertHeadList (&gMenuList, &UiMenuList->MenuLink); +} + +VOID +UiFreeMenu ( + VOID + ) +/*++ + +Routine Description: + Free Menu option linked list. + +Arguments: + +Returns: + +--*/ +{ + UI_MENU_OPTION *MenuOption; + + while (!IsListEmpty (&Menu)) { + MenuOption = CR (Menu.ForwardLink, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE); + RemoveEntryList (&MenuOption->Link); + + // + // We allocated space for this description when we did a GetToken, free it here + // + gBS->FreePool (MenuOption->Description); + gBS->FreePool (MenuOption); + } +} + +VOID +UpdateDateAndTime ( + VOID + ) +/*++ + +Routine Description: + Refresh screen with current date and/or time based on screen context + +Arguments: + +Returns: + +--*/ +{ + CHAR16 *OptionString; + MENU_REFRESH_ENTRY *MenuRefreshEntry; + UINTN Index; + UINTN Loop; + + OptionString = NULL; + + if (gMenuRefreshHead != NULL) { + + MenuRefreshEntry = gMenuRefreshHead; + + do { + gST->ConOut->SetAttribute (gST->ConOut, MenuRefreshEntry->CurrentAttribute); + ProcessOptions (MenuRefreshEntry->MenuOption, FALSE, MenuRefreshEntry->FileFormTagsHead, NULL, &OptionString); + + if (OptionString != NULL) { + // + // If leading spaces on OptionString - remove the spaces + // + for (Index = 0; OptionString[Index] == L' '; Index++) + ; + + for (Loop = 0; OptionString[Index] != CHAR_NULL; Index++) { + OptionString[Loop] = OptionString[Index]; + Loop++; + } + + OptionString[Loop] = CHAR_NULL; + + PrintStringAt (MenuRefreshEntry->CurrentColumn, MenuRefreshEntry->CurrentRow, OptionString); + } + + MenuRefreshEntry = MenuRefreshEntry->Next; + + } while (MenuRefreshEntry != NULL); + } + + if (OptionString != NULL) { + gBS->FreePool (OptionString); + } +} + +EFI_STATUS +UiWaitForSingleEvent ( + IN EFI_EVENT Event, + IN UINT64 Timeout OPTIONAL + ) +/*++ + +Routine Description: + Wait for a given event to fire, or for an optional timeout to expire. + +Arguments: + Event - The event to wait for + + Timeout - An optional timeout value in 100 ns units. + +Returns: + + EFI_SUCCESS - Event fired before Timeout expired. + EFI_TIME_OUT - Timout expired before Event fired. + +--*/ +{ + EFI_STATUS Status; + UINTN Index; + EFI_EVENT TimerEvent; + EFI_EVENT WaitList[2]; + + if (Timeout) { + // + // Create a timer event + // + Status = gBS->CreateEvent (EFI_EVENT_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 { + // + // Update screen every second + // + Timeout = ONE_SECOND; + + do { + Status = gBS->CreateEvent (EFI_EVENT_TIMER, 0, NULL, NULL, &TimerEvent); + + // + // 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); + + // + // If the timer expired, update anything that needs a refresh and keep waiting + // + if (!EFI_ERROR (Status) && Index == 1) { + Status = EFI_TIMEOUT; + UpdateDateAndTime (); + } + + gBS->CloseEvent (TimerEvent); + } while (Status == EFI_TIMEOUT); + } + + return Status; +} + +VOID +UiAddMenuOption ( + IN CHAR16 *String, + IN EFI_HII_HANDLE Handle, + IN EFI_TAG *Tags, + IN VOID *FormBinary, + IN UINTN IfrNumber + ) +/*++ + +Routine Description: + Add one menu option by specified description and context. + +Arguments: + String - String description for this option. + Context - Context data for entry. + +Returns: + +--*/ +{ + UI_MENU_OPTION *MenuOption; + + MenuOption = AllocateZeroPool (sizeof (UI_MENU_OPTION)); + ASSERT (MenuOption); + + MenuOption->Signature = UI_MENU_OPTION_SIGNATURE; + MenuOption->Description = String; + MenuOption->Handle = Handle; + MenuOption->FormBinary = FormBinary; + MenuOption->IfrNumber = IfrNumber; + MenuOption->Skip = 1; + MenuOption->Tags = Tags; + MenuOption->TagIndex = 0; + MenuOption->ThisTag = &(MenuOption->Tags[MenuOption->TagIndex]); + MenuOption->EntryNumber = (UINT16) IfrNumber; + + InsertTailList (&Menu, &MenuOption->Link); +} + +VOID +UiAddSubMenuOption ( + IN CHAR16 *String, + IN EFI_HII_HANDLE Handle, + IN EFI_TAG *Tags, + IN UINTN TagIndex, + IN UINT16 FormId, + IN UINT16 MenuItemCount + ) +/*++ + +Routine Description: + Add one menu option by specified description and context. + +Arguments: + String - String description for this option. + Context - Context data for entry. + +Returns: + +--*/ +{ + UI_MENU_OPTION *MenuOption; + + MenuOption = AllocateZeroPool (sizeof (UI_MENU_OPTION)); + ASSERT (MenuOption); + + MenuOption->Signature = UI_MENU_OPTION_SIGNATURE; + MenuOption->Description = String; + MenuOption->Handle = Handle; + MenuOption->Skip = Tags[TagIndex].NumberOfLines; + MenuOption->IfrNumber = gActiveIfr; + MenuOption->Tags = Tags; + MenuOption->TagIndex = TagIndex; + MenuOption->ThisTag = &(MenuOption->Tags[MenuOption->TagIndex]); + MenuOption->Consistency = Tags[TagIndex].Consistency; + MenuOption->FormId = FormId; + MenuOption->GrayOut = Tags[TagIndex].GrayOut; + MenuOption->EntryNumber = MenuItemCount; + + InsertTailList (&Menu, &MenuOption->Link); +} + +EFI_STATUS +CreateDialog ( + IN UINTN NumberOfLines, + IN BOOLEAN HotKey, + IN UINTN MaximumStringSize, + OUT CHAR16 *StringBuffer, + OUT EFI_INPUT_KEY *KeyValue, + IN CHAR16 *String, + ... + ) +/*++ + +Routine Description: + Routine used to abstract a generic dialog interface and return the selected key or string + +Arguments: + NumberOfLines - The number of lines for the dialog box + HotKey - Defines whether a single character is parsed (TRUE) and returned in KeyValue + or a string is returned in StringBuffer. Two special characters are considered when entering a string, a SCAN_ESC and + an CHAR_CARRIAGE_RETURN. SCAN_ESC terminates string input and returns + MaximumStringSize - The maximum size in bytes of a typed in string (each character is a CHAR16) and the minimum string returned is two bytes + StringBuffer - The passed in pointer to the buffer which will hold the typed in string if HotKey is FALSE + KeyValue - The EFI_KEY value returned if HotKey is TRUE.. + String - Pointer to the first string in the list + ... - A series of (quantity == NumberOfLines) text strings which will be used to construct the dialog box + +Returns: + EFI_SUCCESS - Displayed dialog and received user interaction + EFI_INVALID_PARAMETER - One of the parameters was invalid (e.g. (StringBuffer == NULL) && (HotKey == FALSE)) + EFI_DEVICE_ERROR - User typed in an ESC character to exit the routine + +--*/ +{ + VA_LIST Marker; + UINTN Count; + EFI_INPUT_KEY Key; + UINTN LargestString; + CHAR16 *TempString; + CHAR16 *BufferedString; + CHAR16 *StackString; + CHAR16 KeyPad[2]; + UINTN Start; + UINTN Top; + UINTN Index; + EFI_STATUS Status; + BOOLEAN SelectionComplete; + UINTN InputOffset; + UINTN CurrentAttribute; + UINTN DimensionsWidth; + UINTN DimensionsHeight; + + DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn; + DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow; + + SelectionComplete = FALSE; + InputOffset = 0; + TempString = AllocateZeroPool (MaximumStringSize * 2); + BufferedString = AllocateZeroPool (MaximumStringSize * 2); + CurrentAttribute = gST->ConOut->Mode->Attribute; + + ASSERT (TempString); + ASSERT (BufferedString); + + VA_START (Marker, String); + + // + // Zero the outgoing buffer + // + ZeroMem (StringBuffer, MaximumStringSize); + + if (HotKey) { + if (KeyValue == NULL) { + return EFI_INVALID_PARAMETER; + } + } else { + if (StringBuffer == NULL) { + return EFI_INVALID_PARAMETER; + } + } + // + // Disable cursor + // + gST->ConOut->EnableCursor (gST->ConOut, FALSE); + + LargestString = (GetStringWidth (String) / 2); + + if (LargestString == L' ') { + InputOffset = 1; + } + // + // Determine the largest string in the dialog box + // Notice we are starting with 1 since String is the first string + // + for (Count = 1; Count < NumberOfLines; Count++) { + StackString = VA_ARG (Marker, CHAR16 *); + + if (StackString[0] == L' ') { + InputOffset = Count + 1; + } + + if ((GetStringWidth (StackString) / 2) > LargestString) { + // + // Size of the string visually and subtract the width by one for the null-terminator + // + LargestString = (GetStringWidth (StackString) / 2); + } + } + + Start = (DimensionsWidth - LargestString - 2) / 2 + gScreenDimensions.LeftColumn + 1; + Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gScreenDimensions.TopRow - 1; + + Count = 0; + + // + // Display the Popup + // + CreateSharedPopUp (LargestString, NumberOfLines, &String); + + // + // Take the first key typed and report it back? + // + if (HotKey) { + Status = WaitForKeyStroke (&Key); + CopyMem (KeyValue, &Key, sizeof (EFI_INPUT_KEY)); + + } else { + do { + Status = WaitForKeyStroke (&Key); + + switch (Key.UnicodeChar) { + case CHAR_NULL: + switch (Key.ScanCode) { + case SCAN_ESC: + gBS->FreePool (TempString); + gBS->FreePool (BufferedString); + gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute); + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + return EFI_DEVICE_ERROR; + + default: + break; + } + + break; + + case CHAR_CARRIAGE_RETURN: + SelectionComplete = TRUE; + gBS->FreePool (TempString); + gBS->FreePool (BufferedString); + gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute); + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + return EFI_SUCCESS; + break; + + case CHAR_BACKSPACE: + if (StringBuffer[0] != CHAR_NULL) { + for (Index = 0; StringBuffer[Index] != CHAR_NULL; Index++) { + TempString[Index] = StringBuffer[Index]; + } + // + // Effectively truncate string by 1 character + // + TempString[Index - 1] = CHAR_NULL; + StrCpy (StringBuffer, TempString); + } + + default: + // + // If it is the beginning of the string, don't worry about checking maximum limits + // + if ((StringBuffer[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) { + StrnCpy (StringBuffer, &Key.UnicodeChar, 1); + StrnCpy (TempString, &Key.UnicodeChar, 1); + } else if ((GetStringWidth (StringBuffer) < MaximumStringSize) && (Key.UnicodeChar != CHAR_BACKSPACE)) { + KeyPad[0] = Key.UnicodeChar; + KeyPad[1] = CHAR_NULL; + StrCat (StringBuffer, KeyPad); + StrCat (TempString, KeyPad); + } + // + // 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, LargestString, L' '); + + PrintStringAt (Start + 1, Top + InputOffset, BufferedString); + + if ((GetStringWidth (StringBuffer) / 2) > (DimensionsWidth - 2)) { + Index = (GetStringWidth (StringBuffer) / 2) - DimensionsWidth + 2; + } else { + Index = 0; + } + + for (Count = 0; Index + 1 < GetStringWidth (StringBuffer) / 2; Index++, Count++) { + BufferedString[Count] = StringBuffer[Index]; + } + + PrintStringAt (Start + 1, Top + InputOffset, BufferedString); + break; + } + } while (!SelectionComplete); + } + + gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute); + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + return EFI_SUCCESS; +} + +VOID +CreateSharedPopUp ( + IN UINTN RequestedWidth, + IN UINTN NumberOfLines, + IN CHAR16 **ArrayOfStrings + ) +{ + UINTN Index; + UINTN Count; + CHAR16 Character; + UINTN Start; + UINTN End; + UINTN Top; + UINTN Bottom; + CHAR16 *String; + + UINTN DimensionsWidth; + UINTN DimensionsHeight; + + DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn; + DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow; + + Count = 0; + + gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND); + + 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 + gScreenDimensions.LeftColumn + 1; + End = Start + RequestedWidth + 1; + + Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gScreenDimensions.TopRow - 1; + Bottom = Top + NumberOfLines + 2; + + Character = (CHAR16) BOXDRAW_DOWN_RIGHT; + PrintCharAt (Start, Top, Character); + Character = (CHAR16) BOXDRAW_HORIZONTAL; + for (Index = Start; Index + 2 < End; Index++) { + PrintChar (Character); + } + + Character = (CHAR16) BOXDRAW_DOWN_LEFT; + PrintChar (Character); + Character = (CHAR16) BOXDRAW_VERTICAL; + for (Index = Top; Index + 2 < Bottom; Index++) { + String = ArrayOfStrings[Count]; + Count++; + + // + // 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, POPUP_TEXT | POPUP_BACKGROUND); + } + // + // 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, POPUP_INVERSE_TEXT | POPUP_INVERSE_BACKGROUND); + } + // + // Passing in a NULL results in a blank space + // + if (String[0] == CHAR_NULL) { + ClearLines (Start, End, Index + 1, Index + 1, POPUP_TEXT | POPUP_BACKGROUND); + } + + PrintStringAt ( + ((DimensionsWidth - GetStringWidth (String) / 2) / 2) + gScreenDimensions.LeftColumn + 1, + Index + 1, + String + ); + gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND); + PrintCharAt (Start, Index + 1, Character); + PrintCharAt (End - 1, Index + 1, Character); + } + + Character = (CHAR16) BOXDRAW_UP_RIGHT; + PrintCharAt (Start, Bottom - 1, Character); + Character = (CHAR16) BOXDRAW_HORIZONTAL; + for (Index = Start; Index + 2 < End; Index++) { + PrintChar (Character); + } + + Character = (CHAR16) BOXDRAW_UP_LEFT; + PrintChar (Character); +} + +VOID +CreatePopUp ( + IN UINTN RequestedWidth, + IN UINTN NumberOfLines, + IN CHAR16 *ArrayOfStrings, + ... + ) +{ + CreateSharedPopUp (RequestedWidth, NumberOfLines, &ArrayOfStrings); +} + +VOID +UpdateStatusBar ( + IN UINTN MessageType, + IN UINT8 Flags, + IN BOOLEAN State + ) +{ + UINTN Index; + STATIC BOOLEAN InputError; + CHAR16 *NvUpdateMessage; + CHAR16 *InputErrorMessage; + + NvUpdateMessage = GetToken (STRING_TOKEN (NV_UPDATE_MESSAGE), gHiiHandle); + InputErrorMessage = GetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE), gHiiHandle); + + switch (MessageType) { + case INPUT_ERROR: + if (State) { + gST->ConOut->SetAttribute (gST->ConOut, ERROR_TEXT); + PrintStringAt ( + gScreenDimensions.LeftColumn + gPromptBlockWidth, + gScreenDimensions.BottomRow - 1, + InputErrorMessage + ); + InputError = TRUE; + } else { + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT); + for (Index = 0; Index < (GetStringWidth (InputErrorMessage) - 2) / 2; Index++) { + PrintAt (gScreenDimensions.LeftColumn + gPromptBlockWidth + Index, gScreenDimensions.BottomRow - 1, (CHAR16 *) L" "); + } + + InputError = FALSE; + } + break; + + case NV_UPDATE_REQUIRED: + if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) { + if (State) { + gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT); + PrintStringAt ( + gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth, + gScreenDimensions.BottomRow - 1, + NvUpdateMessage + ); + gResetRequired = (BOOLEAN) (gResetRequired | (Flags & RESET_REQUIRED)); + + gNvUpdateRequired = TRUE; + } else { + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT); + for (Index = 0; Index < (GetStringWidth (NvUpdateMessage) - 2) / 2; Index++) { + PrintAt ( + (gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + Index), + gScreenDimensions.BottomRow - 1, + (CHAR16 *) L" " + ); + } + + gNvUpdateRequired = FALSE; + } + } + break; + + case REFRESH_STATUS_BAR: + if (InputError) { + UpdateStatusBar (INPUT_ERROR, Flags, TRUE); + } + + if (gNvUpdateRequired) { + UpdateStatusBar (NV_UPDATE_REQUIRED, Flags, TRUE); + } + break; + + default: + break; + } + + gBS->FreePool (InputErrorMessage); + gBS->FreePool (NvUpdateMessage); + return ; +} + +VOID +FreeData ( + IN EFI_FILE_FORM_TAGS *FileFormTagsHead, + IN CHAR16 *FormattedString, + IN CHAR16 *OptionString + ) +/*++ + +Routine Description: + + Used to remove the allocated data instances + +Arguments: + +Returns: + +--*/ +{ + EFI_FILE_FORM_TAGS *FileForm; + EFI_FILE_FORM_TAGS *PreviousFileForm; + EFI_FORM_TAGS *FormTags; + EFI_FORM_TAGS *PreviousFormTags; + EFI_IFR_BINARY *IfrBinary; + EFI_IFR_BINARY *PreviousIfrBinary; + EFI_INCONSISTENCY_DATA *Inconsistent; + EFI_VARIABLE_DEFINITION *VariableDefinition; + EFI_VARIABLE_DEFINITION *PreviousVariableDefinition; + VOID *Buffer; + UINTN Index; + + FileForm = FileFormTagsHead; + + if (FormattedString != NULL) { + gBS->FreePool (FormattedString); + } + + if (OptionString != NULL) { + gBS->FreePool (OptionString); + } + + for (; FileForm != NULL;) { + PreviousFileForm = NULL; + + // + // Advance FileForm to the last entry + // + for (; FileForm->NextFile != NULL; FileForm = FileForm->NextFile) { + PreviousFileForm = FileForm; + } + + FormTags = &FileForm->FormTags; + + for (; FormTags != NULL;) { + FormTags = &FileForm->FormTags; + PreviousFormTags = NULL; + + // + // Advance FormTags to the last entry + // + for (; FormTags->Next != NULL; FormTags = FormTags->Next) { + PreviousFormTags = FormTags; + } + // + // Walk through each of the tags and free the IntList allocation + // + for (Index = 0; FormTags->Tags[Index].Operand != EFI_IFR_END_FORM_OP; Index++) { + // + // It is more than likely that the very last page will contain an end formset + // + if (FormTags->Tags[Index].Operand == EFI_IFR_END_FORM_SET_OP) { + break; + } + + if (FormTags->Tags[Index].IntList != NULL) { + gBS->FreePool (FormTags->Tags[Index].IntList); + } + } + + if (PreviousFormTags != NULL) { + gBS->FreePool (FormTags->Tags); + FormTags = PreviousFormTags; + gBS->FreePool (FormTags->Next); + FormTags->Next = NULL; + } else { + gBS->FreePool (FormTags->Tags); + FormTags = NULL; + } + } + // + // Last FileForm entry's Inconsistent database + // + Inconsistent = FileForm->InconsistentTags; + + // + // Advance Inconsistent to the last entry + // + for (; Inconsistent->Next != NULL; Inconsistent = Inconsistent->Next) + ; + + for (; Inconsistent != NULL;) { + // + // Preserve the Previous pointer + // + Buffer = (VOID *) Inconsistent->Previous; + + // + // Free the current entry + // + gBS->FreePool (Inconsistent); + + // + // Restore the Previous pointer + // + Inconsistent = (EFI_INCONSISTENCY_DATA *) Buffer; + } + + VariableDefinition = FileForm->VariableDefinitions; + + for (; VariableDefinition != NULL;) { + VariableDefinition = FileForm->VariableDefinitions; + PreviousVariableDefinition = NULL; + + // + // Advance VariableDefinitions to the last entry + // + for (; VariableDefinition->Next != NULL; VariableDefinition = VariableDefinition->Next) { + PreviousVariableDefinition = VariableDefinition; + } + + gBS->FreePool (VariableDefinition->VariableName); + gBS->FreePool (VariableDefinition->NvRamMap); + gBS->FreePool (VariableDefinition->FakeNvRamMap); + + if (PreviousVariableDefinition != NULL) { + VariableDefinition = PreviousVariableDefinition; + gBS->FreePool (VariableDefinition->Next); + VariableDefinition->Next = NULL; + } else { + gBS->FreePool (VariableDefinition); + VariableDefinition = NULL; + } + } + + if (PreviousFileForm != NULL) { + FileForm = PreviousFileForm; + gBS->FreePool (FileForm->NextFile); + FileForm->NextFile = NULL; + } else { + gBS->FreePool (FileForm); + FileForm = NULL; + } + } + + IfrBinary = gBinaryDataHead; + + for (; IfrBinary != NULL;) { + IfrBinary = gBinaryDataHead; + PreviousIfrBinary = NULL; + + // + // Advance IfrBinary to the last entry + // + for (; IfrBinary->Next != NULL; IfrBinary = IfrBinary->Next) { + PreviousIfrBinary = IfrBinary; + } + + gBS->FreePool (IfrBinary->IfrPackage); + + if (PreviousIfrBinary != NULL) { + IfrBinary = PreviousIfrBinary; + gBS->FreePool (IfrBinary->Next); + IfrBinary->Next = NULL; + } else { + gBS->FreePool (IfrBinary); + IfrBinary = NULL; + } + } + + gBS->FreePool (gPreviousValue); + gPreviousValue = NULL; + + // + // Free Browser Strings + // + gBS->FreePool (gPressEnter); + gBS->FreePool (gConfirmError); + gBS->FreePool (gConfirmPassword); + gBS->FreePool (gPromptForNewPassword); + gBS->FreePool (gPromptForPassword); + gBS->FreePool (gToggleCheckBox); + gBS->FreePool (gNumericInput); + gBS->FreePool (gMakeSelection); + gBS->FreePool (gMoveHighlight); + gBS->FreePool (gEscapeString); + gBS->FreePool (gEnterCommitString); + gBS->FreePool (gEnterString); + gBS->FreePool (gFunctionOneString); + gBS->FreePool (gFunctionTwoString); + gBS->FreePool (gFunctionNineString); + gBS->FreePool (gFunctionTenString); + return ; +} + +BOOLEAN +SelectionsAreValid ( + IN UI_MENU_OPTION *MenuOption, + IN EFI_FILE_FORM_TAGS *FileFormTagsHead + ) +/*++ + +Routine Description: + Initiate late consistency checks against the current page. + +Arguments: + None + +Returns: + +--*/ +{ + LIST_ENTRY *Link; + EFI_TAG *Tag; + EFI_FILE_FORM_TAGS *FileFormTags; + CHAR16 *StringPtr; + CHAR16 NullCharacter; + EFI_STATUS Status; + UINTN Index; + UINT16 *NvRamMap; + STRING_REF PopUp; + EFI_INPUT_KEY Key; + EFI_VARIABLE_DEFINITION *VariableDefinition; + + StringPtr = (CHAR16 *) L"\0"; + NullCharacter = CHAR_NULL; + + FileFormTags = FileFormTagsHead; + + for (Index = 0; Index < MenuOption->IfrNumber; Index++) { + FileFormTags = FileFormTags->NextFile; + } + + for (Link = Menu.ForwardLink; Link != &Menu; Link = Link->ForwardLink) { + MenuOption = CR (Link, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE); + + Tag = MenuOption->ThisTag; + + ExtractRequestedNvMap (FileFormTags, Tag->VariableNumber, &VariableDefinition); + NvRamMap = (UINT16 *) &VariableDefinition->NvRamMap[Tag->StorageStart]; + + // + // If the op-code has a late check, ensure consistency checks are now applied + // + if (Tag->Flags & EFI_IFR_FLAG_LATE_CHECK) { + if (ValueIsNotValid (TRUE, 0, Tag, FileFormTags, &PopUp)) { + if (PopUp != 0x0000) { + StringPtr = GetToken (PopUp, MenuOption->Handle); + + CreatePopUp (GetStringWidth (StringPtr) / 2, 3, &NullCharacter, StringPtr, &NullCharacter); + + do { + Status = WaitForKeyStroke (&Key); + + switch (Key.UnicodeChar) { + + case CHAR_CARRIAGE_RETURN: + // + // Since the value can be one byte long or two bytes long, do a CopyMem based on StorageWidth + // + CopyMem (NvRamMap, &Tag->OldValue, Tag->StorageWidth); + gBS->FreePool (StringPtr); + break; + + default: + break; + } + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + } + + return FALSE; + } + } + } + + return TRUE; +} + +UINT16 +GetWidth ( + IN EFI_TAG *Tag, + IN EFI_HII_HANDLE Handle + ) +/*++ + +Routine Description: + Get the supported width for a particular op-code + +Arguments: + Tag - The Tag structure passed in. + Handle - The handle in the HII database being used + +Returns: + Returns the number of CHAR16 characters that is support. + + +--*/ +{ + CHAR16 *String; + UINTN Size; + + Size = 0x00; + + // + // See if the second text parameter is really NULL + // + if ((Tag->Operand == EFI_IFR_TEXT_OP) && (Tag->TextTwo != 0)) { + String = GetToken (Tag->TextTwo, Handle); + Size = StrLen (String); + gBS->FreePool (String); + } + + if ((Tag->Operand == EFI_IFR_SUBTITLE_OP) || + (Tag->Operand == EFI_IFR_REF_OP) || + (Tag->Operand == EFI_IFR_PASSWORD_OP) || + (Tag->Operand == EFI_IFR_STRING_OP) || + (Tag->Operand == EFI_IFR_INVENTORY_OP) || + // + // Allow a wide display if text op-code and no secondary text op-code + // + ((Tag->Operand == EFI_IFR_TEXT_OP) && (Size == 0x0000)) + ) { + return (UINT16) (gPromptBlockWidth + gOptionBlockWidth); + } else { + return (UINT16) gPromptBlockWidth; + } +} + +UINT16 +GetLineByWidth ( + IN CHAR16 *InputString, + IN UINT16 LineWidth, + IN OUT UINTN *Index, + OUT CHAR16 **OutputString + ) +/*++ + +Routine Description: + 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. + +Arguments: + InputString - String description for this option. + LineWidth - Width of the desired string to extract in CHAR16 characters + Index - Where in InputString to start the copy process + OutputString - Buffer to copy the string into + +Returns: + Returns the number of CHAR16 characters that were copied into the OutputString buffer. + + +--*/ +{ + static BOOLEAN Finished; + UINT16 Count; + UINT16 Count2; + + if (Finished) { + Finished = FALSE; + return (UINT16) 0; + } + + Count = LineWidth; + Count2 = 0; + + *OutputString = AllocateZeroPool (((UINTN) (LineWidth + 1) * 2)); + + // + // Ensure we have got a valid buffer + // + if (*OutputString != NULL) { + // + // Fast-forward the string and see if there is a carriage-return in the string + // + for (; (InputString[*Index + Count2] != CHAR_CARRIAGE_RETURN) && (Count2 != LineWidth); Count2++) + ; + + // + // Copy the desired LineWidth of data to the output buffer. + // Also make sure that we don't copy more than the string. + // Also make sure that if there are linefeeds, we account for them. + // + if ((StrSize (&InputString[*Index]) <= ((UINTN) (LineWidth + 1) * 2)) && + (StrSize (&InputString[*Index]) <= ((UINTN) (Count2 + 1) * 2)) + ) { + // + // Convert to CHAR16 value and show that we are done with this operation + // + LineWidth = (UINT16) ((StrSize (&InputString[*Index]) - 2) / 2); + if (LineWidth != 0) { + Finished = TRUE; + } + } else { + if (Count2 == LineWidth) { + // + // Rewind the string from the maximum size until we see a space to break the line + // + for (; (InputString[*Index + LineWidth] != CHAR_SPACE) && (LineWidth != 0); LineWidth--) + ; + if (LineWidth == 0) { + LineWidth = Count; + } + } else { + LineWidth = Count2; + } + } + + CopyMem (*OutputString, &InputString[*Index], LineWidth * 2); + + // + // If currently pointing to a space, increment the index to the first non-space character + // + for (; + (InputString[*Index + LineWidth] == CHAR_SPACE) || (InputString[*Index + LineWidth] == CHAR_CARRIAGE_RETURN); + (*Index)++ + ) + ; + *Index = (UINT16) (*Index + LineWidth); + return LineWidth; + } else { + return (UINT16) 0; + } +} + +VOID +UpdateOptionSkipLines ( + IN EFI_IFR_DATA_ARRAY *PageData, + IN UI_MENU_OPTION *MenuOption, + IN EFI_FILE_FORM_TAGS *FileFormTagsHead, + IN CHAR16 **OptionalString, + IN UINTN SkipValue + ) +{ + UINTN Index; + UINTN Loop; + UINT16 Width; + UINTN Row; + UINTN OriginalRow; + CHAR16 *OutputString; + CHAR16 *OptionString; + + Row = 0; + OptionString = *OptionalString; + OutputString = NULL; + + ProcessOptions (MenuOption, FALSE, FileFormTagsHead, PageData, &OptionString); + + if (OptionString != NULL) { + // + // If leading spaces on OptionString - remove the spaces + // + for (Index = 0; OptionString[Index] == L' '; Index++) + ; + + for (Loop = 0; OptionString[Index] != CHAR_NULL; Index++) { + OptionString[Loop] = OptionString[Index]; + Loop++; + } + + OptionString[Loop] = CHAR_NULL; + + Width = (UINT16) gOptionBlockWidth; + + OriginalRow = Row; + + for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) { + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&OptionString[Index])) { + if (SkipValue == 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 - OriginalRow) >= MenuOption->Skip) { + MenuOption->Skip++; + } + } + } + + gBS->FreePool (OutputString); + if (SkipValue != 0) { + SkipValue--; + } + } + + Row = OriginalRow; + } + + *OptionalString = OptionString; +} +// +// 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_F2, UiPrevious}, + { SCAN_LEFT, UiLeft }, + { SCAN_RIGHT, UiRight }, + { SCAN_F9, UiDefault}, + { SCAN_F10, UiSave } +}; + +SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag[] = { + { UiNoOperation, CfUiNoOperation }, + { UiDefault, CfUiDefault }, + { UiSelect, CfUiSelect }, + { UiUp, CfUiUp}, + { UiDown, CfUiDown }, + { UiLeft, CfUiLeft }, + { UiRight, CfUiRight }, + { UiReset, CfUiReset }, + { UiSave, CfUiSave }, + { UiPrevious, CfUiPrevious }, + { UiPageUp, CfUiPageUp }, + { UiPageDown, CfUiPageDown } +}; + +UI_MENU_OPTION * +UiDisplayMenu ( + IN BOOLEAN SubMenu, + IN EFI_FILE_FORM_TAGS *FileFormTagsHead, + OUT EFI_IFR_DATA_ARRAY *PageData + ) +/*++ + +Routine Description: + 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. + +Arguments: + SubMenu - Indicate is sub menu. + FileFormTagsHead - A pointer to the EFI_FILE_FORM_TAGS structure. + PageData - A pointer to the EFI_IFR_DATA_ARRAY. + +Returns: + Return the pointer of the menu which selected, + otherwise return NULL. + +--*/ +{ + INTN SkipValue; + INTN Difference; + INTN OldSkipValue; + UINTN Row; + UINTN Col; + UINTN Temp; + UINTN Temp2; + UINTN TopRow; + UINTN BottomRow; + UINTN OriginalRow; + UINTN Index; + UINTN DataAndTimeLineNumberPad; + UINT32 Count; + INT16 OriginalTimeOut; + UINT8 *Location; + UINT16 Width; + CHAR16 *StringPtr; + CHAR16 *OptionString; + CHAR16 *OutputString; + CHAR16 *FormattedString; + CHAR16 YesResponse; + CHAR16 NoResponse; + BOOLEAN NewLine; + BOOLEAN Repaint; + BOOLEAN SavedValue; + EFI_STATUS Status; + UI_MENU_LIST *UiMenuList; + EFI_INPUT_KEY Key; + LIST_ENTRY *Link; + LIST_ENTRY *NewPos; + LIST_ENTRY *TopOfScreen; + LIST_ENTRY *SavedListEntry; + UI_MENU_OPTION *Selection; + UI_MENU_OPTION *MenuOption; + UI_MENU_OPTION *NextMenuOption; + UI_MENU_OPTION *SavedMenuOption; + UI_MENU_OPTION *PreviousMenuOption; + EFI_IFR_BINARY *IfrBinary; + UI_CONTROL_FLAG ControlFlag; + EFI_SCREEN_DESCRIPTOR LocalScreen; + EFI_FILE_FORM_TAGS *FileFormTags; + MENU_REFRESH_ENTRY *MenuRefreshEntry; + MENU_REFRESH_ENTRY *OldMenuRefreshEntry; + UI_SCREEN_OPERATION ScreenOperation; + EFI_VARIABLE_DEFINITION *VariableDefinition; + EFI_FORM_CALLBACK_PROTOCOL *FormCallback; + EFI_HII_VARIABLE_PACK_LIST *NvMapListHead; + EFI_HII_VARIABLE_PACK_LIST *NvMapListNode; + VOID *NvMap; + UINTN NvMapSize; + + CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); + + VariableDefinition = NULL; + Status = EFI_SUCCESS; + FormattedString = NULL; + OptionString = NULL; + ScreenOperation = UiNoOperation; + NewLine = TRUE; + FormCallback = NULL; + FileFormTags = NULL; + OutputString = NULL; + gUpArrow = FALSE; + gDownArrow = FALSE; + SkipValue = 0; + OldSkipValue = 0; + MenuRefreshEntry = gMenuRefreshHead; + OldMenuRefreshEntry = gMenuRefreshHead; + NextMenuOption = NULL; + PreviousMenuOption = NULL; + SavedMenuOption = NULL; + IfrBinary = NULL; + NvMap = NULL; + NvMapSize = 0; + + ZeroMem (&Key, sizeof (EFI_INPUT_KEY)); + + if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) { + TopRow = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT; + Row = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT; + } else { + TopRow = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT; + Row = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT; + } + + if (SubMenu) { + Col = LocalScreen.LeftColumn; + } else { + Col = LocalScreen.LeftColumn + LEFT_SKIPPED_COLUMNS; + } + + BottomRow = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT - SCROLL_ARROW_HEIGHT - 1; + + TopOfScreen = Menu.ForwardLink; + Repaint = TRUE; + MenuOption = NULL; + + // + // Get user's selection + // + Selection = NULL; + NewPos = Menu.ForwardLink; + gST->ConOut->EnableCursor (gST->ConOut, FALSE); + + UpdateStatusBar (REFRESH_STATUS_BAR, (UINT8) 0, TRUE); + + ControlFlag = CfInitialization; + + while (TRUE) { + switch (ControlFlag) { + case CfInitialization: + ControlFlag = CfCheckSelection; + if (gExitRequired) { + ScreenOperation = UiReset; + ControlFlag = CfScreenOperation; + } else if (gSaveRequired) { + ScreenOperation = UiSave; + ControlFlag = CfScreenOperation; + } else if (IsListEmpty (&Menu)) { + ControlFlag = CfReadKey; + } + break; + + case CfCheckSelection: + if (Selection != NULL) { + ControlFlag = CfExit; + } else { + ControlFlag = CfRepaint; + } + + FileFormTags = FileFormTagsHead; + break; + + case CfRepaint: + ControlFlag = CfRefreshHighLight; + + if (Repaint) { + // + // Display menu + // + SavedMenuOption = MenuOption; + gDownArrow = FALSE; + gUpArrow = FALSE; + Row = TopRow; + + Temp = SkipValue; + Temp2 = SkipValue; + + ClearLines ( + LocalScreen.LeftColumn, + LocalScreen.RightColumn, + TopRow - SCROLL_ARROW_HEIGHT, + BottomRow + SCROLL_ARROW_HEIGHT, + FIELD_TEXT | FIELD_BACKGROUND + ); + + while (gMenuRefreshHead != NULL) { + OldMenuRefreshEntry = gMenuRefreshHead->Next; + + gBS->FreePool (gMenuRefreshHead); + + gMenuRefreshHead = OldMenuRefreshEntry; + } + + for (Link = TopOfScreen; Link != &Menu; Link = Link->ForwardLink) { + MenuOption = CR (Link, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE); + MenuOption->Row = Row; + OriginalRow = Row; + MenuOption->Col = Col; + MenuOption->OptCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn; + + if (SubMenu) { + if (MenuOption->ThisTag->GrayOut) { + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND); + } else { + if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) { + gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND); + } + } + + Width = GetWidth (MenuOption->ThisTag, MenuOption->Handle); + + OriginalRow = Row; + + for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) { + if ((Temp == 0) && (Row <= BottomRow)) { + PrintStringAt (Col, Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&MenuOption->Description[Index])) { + if (Temp == 0) { + Row++; + } + } + + gBS->FreePool (OutputString); + if (Temp != 0) { + Temp--; + } + } + + Temp = 0; + + Row = OriginalRow; + + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); + ProcessOptions (MenuOption, FALSE, FileFormTagsHead, PageData, &OptionString); + + if (OptionString != NULL) { + // + // If leading spaces on OptionString - remove the spaces + // + for (Index = 0; OptionString[Index] == L' '; Index++) { + MenuOption->OptCol++; + } + + for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) { + OptionString[Count] = OptionString[Index]; + Count++; + } + + OptionString[Count] = CHAR_NULL; + + // + // If this is a date or time op-code and is used to reflect an RTC, register the op-code + // + if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP || + MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP) && + (MenuOption->ThisTag->StorageStart >= FileFormTags->FormTags.Tags[0].NvDataSize)) { + + if (gMenuRefreshHead == NULL) { + MenuRefreshEntry = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY)); + ASSERT (MenuRefreshEntry != NULL); + MenuRefreshEntry->MenuOption = MenuOption; + MenuRefreshEntry->FileFormTagsHead = FileFormTagsHead; + MenuRefreshEntry->CurrentColumn = MenuOption->OptCol; + MenuRefreshEntry->CurrentRow = MenuOption->Row; + MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND; + gMenuRefreshHead = MenuRefreshEntry; + } else { + // + // Advance to the last entry + // + for (MenuRefreshEntry = gMenuRefreshHead; + MenuRefreshEntry->Next != NULL; + MenuRefreshEntry = MenuRefreshEntry->Next + ) + ; + MenuRefreshEntry->Next = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY)); + ASSERT (MenuRefreshEntry->Next != NULL); + MenuRefreshEntry = MenuRefreshEntry->Next; + MenuRefreshEntry->MenuOption = MenuOption; + MenuRefreshEntry->FileFormTagsHead = FileFormTagsHead; + MenuRefreshEntry->CurrentColumn = MenuOption->OptCol; + MenuRefreshEntry->CurrentRow = MenuOption->Row; + MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND; + } + } + + Width = (UINT16) gOptionBlockWidth; + + OriginalRow = Row; + + for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) { + if ((Temp2 == 0) && (Row <= BottomRow)) { + PrintStringAt (MenuOption->OptCol, Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&OptionString[Index])) { + 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 - OriginalRow) >= MenuOption->Skip) { + MenuOption->Skip++; + } + } + } + + gBS->FreePool (OutputString); + if (Temp2 != 0) { + Temp2--; + } + } + + Temp2 = 0; + Row = OriginalRow; + } + // + // If this is a text op with secondary text information + // + if ((MenuOption->ThisTag->Operand == EFI_IFR_TEXT_OP) && (MenuOption->ThisTag->TextTwo != 0)) { + StringPtr = GetToken (MenuOption->ThisTag->TextTwo, MenuOption->Handle); + + Width = (UINT16) gOptionBlockWidth; + + OriginalRow = Row; + + for (Index = 0; GetLineByWidth (StringPtr, Width, &Index, &OutputString) != 0x0000;) { + if ((Temp == 0) && (Row <= BottomRow)) { + PrintStringAt (MenuOption->OptCol, Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&StringPtr[Index])) { + 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 - OriginalRow) >= MenuOption->Skip) { + MenuOption->Skip++; + } + } + } + + gBS->FreePool (OutputString); + if (Temp2 != 0) { + Temp2--; + } + } + + Row = OriginalRow; + gBS->FreePool (StringPtr); + } + } else { + // + // For now, assume left-justified 72 width max setup entries + // + PrintStringAt (Col, Row, MenuOption->Description); + } + // + // Tracker 6210 - need to handle the bottom of the display + // + if (MenuOption->Skip > 1) { + Row += MenuOption->Skip - SkipValue; + SkipValue = 0; + } else { + Row += MenuOption->Skip; + } + + if (Row > BottomRow) { + if (!ValueIsScroll (FALSE, Link)) { + gDownArrow = TRUE; + } + + Row = BottomRow + 1; + break; + } + } + + if (!ValueIsScroll (TRUE, TopOfScreen)) { + gUpArrow = TRUE; + } + + if (gUpArrow) { + gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND); + PrintAt ( + LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1, + TopRow - SCROLL_ARROW_HEIGHT, + (CHAR16 *) L"%c", + ARROW_UP + ); + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); + } + + if (gDownArrow) { + gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND); + PrintAt ( + LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1, + BottomRow + SCROLL_ARROW_HEIGHT, + (CHAR16 *) L"%c", + ARROW_DOWN + ); + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); + } + + if (SavedMenuOption != NULL) { + MenuOption = SavedMenuOption; + } + } + break; + + case CfRefreshHighLight: + ControlFlag = CfUpdateHelpString; + // + // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily + // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing. + // + SavedValue = Repaint; + Repaint = FALSE; + + if (NewPos != NULL) { + gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row); + if (SubMenu) { + if (gLastOpr && (gEntryNumber != -1)) { + MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE); + if (gEntryNumber != MenuOption->EntryNumber) { + ScreenOperation = UiDown; + ControlFlag = CfScreenOperation; + break; + } else { + gLastOpr = FALSE; + } + } + + ProcessOptions (MenuOption, FALSE, FileFormTagsHead, PageData, &OptionString); + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); + if (OptionString != NULL) { + // + // If leading spaces on OptionString - remove the spaces + // + for (Index = 0; OptionString[Index] == L' '; Index++) + ; + + for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) { + OptionString[Count] = OptionString[Index]; + Count++; + } + + OptionString[Count] = CHAR_NULL; + + Width = (UINT16) gOptionBlockWidth; + + OriginalRow = MenuOption->Row; + + for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) { + if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) { + PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&OptionString[Index])) { + MenuOption->Row++; + } + + gBS->FreePool (OutputString); + } + + MenuOption->Row = OriginalRow; + } else { + if (NewLine) { + if (MenuOption->ThisTag->GrayOut) { + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND); + } else { + if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) { + gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND); + } + } + + OriginalRow = MenuOption->Row; + Width = GetWidth (MenuOption->ThisTag, MenuOption->Handle); + + for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) { + if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) { + PrintStringAt (Col, MenuOption->Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&MenuOption->Description[Index])) { + MenuOption->Row++; + } + + gBS->FreePool (OutputString); + } + + MenuOption->Row = OriginalRow; + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); + } + } + } else { + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); + gST->ConOut->OutputString (gST->ConOut, MenuOption->Description); + } + + MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE); + + if ((gPriorMenuEntry != 0) && (MenuOption->EntryNumber != gPriorMenuEntry) && (NewPos->ForwardLink != &Menu)) { + ScreenOperation = UiDown; + ControlFlag = CfScreenOperation; + break; + } else { + gPriorMenuEntry = 0; + } + // + // This is only possible if we entered this page and the first menu option is + // a "non-menu" item. In that case, force it UiDown + // + if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || MenuOption->ThisTag->GrayOut) { + // + // If we previously hit an UP command and we are still sitting on a text operation + // we must continue going up + // + if (ScreenOperation == UiUp) { + ControlFlag = CfScreenOperation; + break; + } else { + ScreenOperation = UiDown; + ControlFlag = CfScreenOperation; + break; + } + } + // + // Set reverse attribute + // + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT); + gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row); + + // + // Assuming that we have a refresh linked-list created, lets annotate the + // appropriate entry that we are highlighting with its new attribute. Just prior to this + // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh + // + if (gMenuRefreshHead != NULL) { + for (MenuRefreshEntry = gMenuRefreshHead; MenuRefreshEntry != NULL; MenuRefreshEntry = MenuRefreshEntry->Next) { + MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND; + if (MenuRefreshEntry->MenuOption == MenuOption) { + MenuRefreshEntry->CurrentAttribute = FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT; + } + } + } + + if (SubMenu) { + ProcessOptions (MenuOption, FALSE, FileFormTagsHead, PageData, &OptionString); + if (OptionString != NULL) { + // + // If leading spaces on OptionString - remove the spaces + // + for (Index = 0; OptionString[Index] == L' '; Index++) + ; + + for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) { + OptionString[Count] = OptionString[Index]; + Count++; + } + + OptionString[Count] = CHAR_NULL; + + Width = (UINT16) gOptionBlockWidth; + + OriginalRow = MenuOption->Row; + + for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) { + if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) { + PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&OptionString[Index])) { + MenuOption->Row++; + } + + gBS->FreePool (OutputString); + } + + MenuOption->Row = OriginalRow; + } else { + if (NewLine) { + OriginalRow = MenuOption->Row; + + Width = GetWidth (MenuOption->ThisTag, MenuOption->Handle); + + for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) { + if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) { + PrintStringAt (Col, MenuOption->Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&MenuOption->Description[Index])) { + MenuOption->Row++; + } + + gBS->FreePool (OutputString); + } + + MenuOption->Row = OriginalRow; + + } + } + + if (((NewPos->ForwardLink != &Menu) && (ScreenOperation == UiDown)) || + ((NewPos->BackLink != &Menu) && (ScreenOperation == UiUp)) || + (ScreenOperation == UiNoOperation) + ) { + UpdateKeyHelp (MenuOption, FALSE); + } + } else { + gST->ConOut->OutputString (gST->ConOut, MenuOption->Description); + } + // + // Clear reverse attribute + // + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); + } + // + // Repaint flag will be used when process CfUpdateHelpString, so restore its value + // if we didn't break halfway when process CfRefreshHighLight. + // + Repaint = SavedValue; + break; + + case CfUpdateHelpString: + ControlFlag = CfPrepareToReadKey; + + if (SubMenu && + (Repaint || NewLine || + (MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || + (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) && + !(gClassOfVfr == EFI_GENERAL_APPLICATION_SUBCLASS)) { + // + // Don't print anything if it is a NULL help token + // + if (MenuOption->ThisTag->Help == 0x00000000) { + StringPtr = (CHAR16 *) L"\0"; + } else { + StringPtr = GetToken (MenuOption->ThisTag->Help, MenuOption->Handle); + } + + ProcessHelpString (StringPtr, &FormattedString, BottomRow - TopRow); + + gST->ConOut->SetAttribute (gST->ConOut, HELP_TEXT | FIELD_BACKGROUND); + + for (Index = 0; Index < BottomRow - TopRow; Index++) { + // + // Pad String with spaces to simulate a clearing of the previous line + // + for (; GetStringWidth (&FormattedString[Index * gHelpBlockWidth]) / 2 < gHelpBlockWidth;) { + StrCat (&FormattedString[Index * gHelpBlockWidth], (CHAR16 *) L" "); + } + + PrintStringAt ( + LocalScreen.RightColumn - gHelpBlockWidth, + Index + TopRow, + &FormattedString[Index * gHelpBlockWidth] + ); + } + } + // + // Reset this flag every time we finish using it. + // + Repaint = FALSE; + NewLine = FALSE; + break; + + case CfPrepareToReadKey: + ControlFlag = CfReadKey; + + for (Index = 0; Index < MenuOption->IfrNumber; Index++) { + FileFormTags = FileFormTags->NextFile; + } + + ScreenOperation = UiNoOperation; + + Status = gBS->HandleProtocol ( + (VOID *) (UINTN) FileFormTags->FormTags.Tags[0].CallbackHandle, + &gEfiFormCallbackProtocolGuid, + (VOID **) &FormCallback + ); + + break; + + case CfReadKey: + ControlFlag = CfScreenOperation; + + OriginalTimeOut = FrontPageTimeOutValue; + do { + if (FrontPageTimeOutValue >= 0 && (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) && FrontPageTimeOutValue != (INT16) -1) { + // + // Remember that if set to 0, must immediately boot an option + // + if (FrontPageTimeOutValue == 0) { + FrontPageTimeOutValue = 0xFFFF; + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + if (EFI_ERROR (Status)) { + Status = EFI_TIMEOUT; + } + break; + } + + Status = UiWaitForSingleEvent (gST->ConIn->WaitForKey, ONE_SECOND); + if (Status == EFI_TIMEOUT) { + EFI_IFR_DATA_ENTRY *DataEntry; + + DataEntry = (EFI_IFR_DATA_ENTRY *) (PageData + 1); + + PageData->EntryCount = 1; + Count = (UINT32) ((OriginalTimeOut - FrontPageTimeOutValue) * 100 / OriginalTimeOut); + CopyMem (&DataEntry->Data, &Count, sizeof (UINT32)); + + if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) { + FormCallback->Callback ( + FormCallback, + 0xFFFF, + (EFI_IFR_DATA_ARRAY *) PageData, + NULL + ); + } + // + // Count down 1 second + // + FrontPageTimeOutValue--; + + } else { + ASSERT (!EFI_ERROR (Status)); + PageData->EntryCount = 0; + if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) { + FormCallback->Callback ( + FormCallback, + 0xFFFE, + (EFI_IFR_DATA_ARRAY *) PageData, + NULL + ); + } + + FrontPageTimeOutValue = 0xFFFF; + } + } else { + // + // Wait for user's selection, no auto boot + // + Status = UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0); + } + } while (Status == EFI_TIMEOUT); + + if (gFirstIn) { + gFirstIn = FALSE; + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + DisableQuietBoot (); + } + + if (Status == EFI_TIMEOUT) { + Key.UnicodeChar = CHAR_CARRIAGE_RETURN; + } else { + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + // + // if we encounter error, continue to read another key in. + // + if (EFI_ERROR (Status)) { + ControlFlag = CfReadKey; + continue; + } + } + + switch (Key.UnicodeChar) { + case CHAR_CARRIAGE_RETURN: + Selection = MenuOption; + ScreenOperation = UiSelect; + gDirection = 0; + break; + + // + // We will push the adjustment of these numeric values directly to the input handler + // + case '+': + case '-': + if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) { + + if (Key.UnicodeChar == '+') { + gDirection = SCAN_RIGHT; + } else { + gDirection = SCAN_LEFT; + } + + Status = ProcessOptions (MenuOption, TRUE, FileFormTagsHead, NULL, &OptionString); + } + break; + + case '^': + ScreenOperation = UiUp; + break; + + case 'V': + case 'v': + ScreenOperation = UiDown; + break; + + case ' ': + if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) { + if (SubMenu) { + if (MenuOption->ThisTag->Operand == EFI_IFR_CHECKBOX_OP && !(MenuOption->ThisTag->GrayOut)) { + gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row); + gST->ConOut->OutputString (gST->ConOut, MenuOption->Description); + Selection = MenuOption; + ScreenOperation = UiSelect; + } + } + } + break; + + case CHAR_NULL: + if (((Key.ScanCode == SCAN_F1) && ((gFunctionKeySetting & FUNCTION_ONE) != FUNCTION_ONE)) || + ((Key.ScanCode == SCAN_F2) && ((gFunctionKeySetting & FUNCTION_TWO) != FUNCTION_TWO)) || + ((Key.ScanCode == SCAN_F9) && ((gFunctionKeySetting & FUNCTION_NINE) != FUNCTION_NINE)) || + ((Key.ScanCode == SCAN_F10) && ((gFunctionKeySetting & FUNCTION_TEN) != FUNCTION_TEN)) + ) { + // + // If the function key has been disabled, just ignore the key. + // + } else { + for (Index = 0; Index < sizeof (gScanCodeToOperation) / sizeof (gScanCodeToOperation[0]); Index++) { + if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) { + if ((Key.ScanCode == SCAN_F9) || (Key.ScanCode == SCAN_F10)) { + if (SubMenu) { + ScreenOperation = gScanCodeToOperation[Index].ScreenOperation; + } + } else { + ScreenOperation = gScanCodeToOperation[Index].ScreenOperation; + } + } + } + } + break; + } + break; + + case CfScreenOperation: + IfrBinary = gBinaryDataHead; + + // + // Advance to the Ifr we are using + // + for (Index = 0; Index < gActiveIfr; Index++) { + IfrBinary = IfrBinary->Next; + } + + if (ScreenOperation != UiPrevious && ScreenOperation != UiReset) { + // + // If the screen has no menu items, and the user didn't select UiPrevious, or UiReset + // ignore the selection and go back to reading keys. + // + if (IsListEmpty (&Menu)) { + ControlFlag = CfReadKey; + break; + } + // + // if there is nothing logical to place a cursor on, just move on to wait for a key. + // + for (Link = Menu.ForwardLink; Link != &Menu; Link = Link->ForwardLink) { + NextMenuOption = CR (Link, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE); + if (!(NextMenuOption->ThisTag->GrayOut) && (NextMenuOption->ThisTag->Operand != EFI_IFR_SUBTITLE_OP)) { + break; + } + } + + if (Link == &Menu) { + ControlFlag = CfPrepareToReadKey; + break; + } + } + + for (Index = 0; + Index < sizeof (gScreenOperationToControlFlag) / sizeof (gScreenOperationToControlFlag[0]); + Index++ + ) { + if (ScreenOperation == gScreenOperationToControlFlag[Index].ScreenOperation) { + ControlFlag = gScreenOperationToControlFlag[Index].ControlFlag; + } + } + + break; + + case CfUiPrevious: + ControlFlag = CfCheckSelection; + // + // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data. + // + if (MenuOption != NULL) { + if (!SelectionsAreValid (MenuOption, FileFormTagsHead)) { + Selection = NULL; + Repaint = TRUE; + break; + } + } + + if (IsListEmpty (&gMenuList)) { + Selection = NULL; + if (IsListEmpty (&Menu)) { + ControlFlag = CfReadKey; + } + break; + } + + gLastOpr = TRUE; + + while (gMenuRefreshHead != NULL) { + OldMenuRefreshEntry = gMenuRefreshHead->Next; + + gBS->FreePool (gMenuRefreshHead); + + gMenuRefreshHead = OldMenuRefreshEntry; + } + // + // Remove the Cached page entry, free and init the menus, flag Selection as jumping to previous page and a valid Tag + // + if (SubMenu) { + UiRemoveMenuListEntry (MenuOption, &Selection); + Selection->Previous = TRUE; + UiFreeMenu (); + UiInitMenu (); + } + + gActiveIfr = Selection->IfrNumber; + return Selection; + + case CfUiSelect: + ControlFlag = CfCheckSelection; + + ExtractRequestedNvMap (FileFormTags, MenuOption->ThisTag->VariableNumber, &VariableDefinition); + + if (SubMenu) { + if ((MenuOption->ThisTag->Operand == EFI_IFR_TEXT_OP && + !(MenuOption->ThisTag->Flags & EFI_IFR_FLAG_INTERACTIVE)) || + (MenuOption->ThisTag->GrayOut) || + (MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || + (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) { + Selection = NULL; + break; + } + + NewLine = TRUE; + UpdateKeyHelp (MenuOption, TRUE); + Status = ProcessOptions (MenuOption, TRUE, FileFormTagsHead, PageData, &OptionString); + + if (EFI_ERROR (Status)) { + Selection = NULL; + Repaint = TRUE; + break; + } + + if (OptionString != NULL) { + PrintStringAt (LocalScreen.LeftColumn + gPromptBlockWidth + 1, MenuOption->Row, OptionString); + } + + if (MenuOption->ThisTag->Flags & EFI_IFR_FLAG_INTERACTIVE) { + Selection = MenuOption; + } + + if (Selection == NULL) { + break; + } + + Location = (UINT8 *) &PageData->EntryCount; + + // + // If not a goto, dump single piece of data, otherwise dump everything + // + if (Selection->ThisTag->Operand == EFI_IFR_REF_OP) { + // + // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data. + // + if (!SelectionsAreValid (MenuOption, FileFormTagsHead)) { + Selection = NULL; + Repaint = TRUE; + break; + } + + UiAddMenuListEntry (Selection); + gPriorMenuEntry = 0; + + // + // Now that we added a menu entry specific to a goto, we can always go back when someone hits the UiPrevious + // + UiMenuList = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE); + UiMenuList->FormerEntryNumber = MenuOption->EntryNumber; + + gLastOpr = FALSE; + + // + // Rewind to the beginning of the menu + // + for (; NewPos->BackLink != &Menu; NewPos = NewPos->BackLink) + ; + + // + // Get Total Count of Menu entries + // + for (Count = 1; NewPos->ForwardLink != &Menu; NewPos = NewPos->ForwardLink) { + Count++; + } + // + // Rewind to the beginning of the menu + // + for (; NewPos->BackLink != &Menu; NewPos = NewPos->BackLink) + ; + + // + // Copy the number of entries being described to the PageData location + // + CopyMem (&Location[0], &Count, sizeof (UINT32)); + + for (Index = 4; NewPos->ForwardLink != &Menu; Index = Index + MenuOption->ThisTag->StorageWidth + 2) { + + MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE); + Location[Index] = MenuOption->ThisTag->Operand; + Location[Index + 1] = (UINT8) (MenuOption->ThisTag->StorageWidth + 4); + CopyMem ( + &Location[Index + 4], + &VariableDefinition->NvRamMap[MenuOption->ThisTag->StorageStart], + MenuOption->ThisTag->StorageWidth + ); + NewPos = NewPos->ForwardLink; + } + } else { + + gPriorMenuEntry = MenuOption->EntryNumber; + + Count = 1; + + // + // Copy the number of entries being described to the PageData location + // + CopyMem (&Location[0], &Count, sizeof (UINT32)); + + // + // Start at PageData[4] since the EntryCount is a UINT32 + // + Index = 4; + + // + // Copy data to destination + // + Location[Index] = MenuOption->ThisTag->Operand; + Location[Index + 1] = (UINT8) (MenuOption->ThisTag->StorageWidth + 4); + CopyMem ( + &Location[Index + 4], + &VariableDefinition->NvRamMap[MenuOption->ThisTag->StorageStart], + MenuOption->ThisTag->StorageWidth + ); + } + } + break; + + case CfUiReset: + ControlFlag = CfCheckSelection; + gLastOpr = FALSE; + if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) { + break; + } + // + // If NV flag is up, prompt user + // + if (gNvUpdateRequired) { + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + + YesResponse = gYesResponse[0]; + NoResponse = gNoResponse[0]; + + do { + CreateDialog (3, TRUE, 0, NULL, &Key, gEmptyString, gAreYouSure, gEmptyString); + } 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 the user hits the YesResponse key + // + if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse | UPPER_LOWER_CASE_OFFSET)) { + } else { + Repaint = TRUE; + NewLine = TRUE; + break; + } + } + // + // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data. + // + if (MenuOption != NULL) { + if (!SelectionsAreValid (MenuOption, FileFormTagsHead)) { + Selection = NULL; + Repaint = TRUE; + NewLine = TRUE; + break; + } + } + + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + + if (SubMenu) { + UiFreeMenuList (); + gST->ConOut->ClearScreen (gST->ConOut); + return NULL; + } + + UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->Flags, FALSE); + UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->Flags, FALSE); + + if (IfrBinary->UnRegisterOnExit) { + Hii->RemovePack (Hii, MenuOption->Handle); + } + + UiFreeMenu (); + + // + // Clean up the allocated data buffers + // + FreeData (FileFormTagsHead, FormattedString, OptionString); + + gST->ConOut->ClearScreen (gST->ConOut); + return NULL; + + case CfUiLeft: + ControlFlag = CfCheckSelection; + if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) { + if (MenuOption->Skip == 1) { + // + // In the tail of the Date/Time op-code set, go left. + // + NewPos = NewPos->BackLink; + } else { + // + // In the middle of the Data/Time op-code set, go left. + // + NextMenuOption = CR (NewPos->ForwardLink, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE); + if (NextMenuOption->Skip == 1) { + NewPos = NewPos->BackLink; + } + } + } + break; + + case CfUiRight: + ControlFlag = CfCheckSelection; + if ((MenuOption->Skip == 0) && + ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) + ) { + // + // We are in the head or middle of the Date/Time op-code set, advance right. + // + NewPos = NewPos->ForwardLink; + } + break; + + case CfUiUp: + ControlFlag = CfCheckSelection; + + if (NewPos->BackLink != &Menu) { + NewLine = TRUE; + // + // Adjust Date/Time position before we advance forward. + // + AdjustDateAndTimePosition (TRUE, &NewPos); + + // + // Caution that we have already rewind to the top, don't go backward in this situation. + // + if (NewPos->BackLink != &Menu) { + NewPos = NewPos->BackLink; + } + + PreviousMenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE); + + // + // Since the behavior of hitting the up arrow on a Date/Time op-code is intended + // to be one that back to the previous set of op-codes, we need to advance to the sencond + // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate + // checking can be done. + // + DataAndTimeLineNumberPad = AdjustDateAndTimePosition (TRUE, &NewPos); + + if (SubMenu) { + // + // If the previous MenuOption contains a display-only op-code, skip to the next one + // + if (PreviousMenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || PreviousMenuOption->ThisTag->GrayOut) { + // + // This is ok as long as not at the end of the list + // + if (NewPos->BackLink == &Menu) { + // + // If we are at the start of the list, then this list must start with a display only + // piece of data, so do not allow the backward motion + // + ScreenOperation = UiDown; + + if (PreviousMenuOption->Row <= TopRow) { + if (TopOfScreen->BackLink != &Menu) { + TopOfScreen = TopOfScreen->BackLink; + Repaint = TRUE; + } + } + + UpdateStatusBar (INPUT_ERROR, PreviousMenuOption->ThisTag->Flags, FALSE); + break; + } + } + } + // + // Check the previous menu entry to see if it was a zero-length advance. If it was, + // don't worry about a redraw. + // + if ((MenuOption->Row - PreviousMenuOption->Skip - DataAndTimeLineNumberPad < TopRow) || + (PreviousMenuOption->Skip > MenuOption->Row) + ) { + do { + if (TopOfScreen->BackLink == &Menu) { + break; + } + + Repaint = TRUE; + + // + // Is the current top of screen a zero-advance op-code? + // If so, keep moving forward till we hit a >0 advance op-code + // + SavedMenuOption = CR (TopOfScreen->BackLink, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE); + TopOfScreen = TopOfScreen->BackLink; + } while (SavedMenuOption->Skip == 0); + // + // If we encounter a Date/Time op-code set, rewind to the first op-code of the set. + // + AdjustDateAndTimePosition (TRUE, &TopOfScreen); + } + + UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->Flags, FALSE); + } else { + if (SubMenu) { + SavedMenuOption = MenuOption; + MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE); + if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || MenuOption->ThisTag->GrayOut) { + // + // If we are at the end of the list and sitting on a text op, we need to more forward + // + ScreenOperation = UiDown; + ControlFlag = CfScreenOperation; + break; + } + + MenuOption = SavedMenuOption; + } + } + break; + + case CfUiPageUp: + ControlFlag = CfCheckSelection; + + SavedListEntry = NewPos; + Link = TopOfScreen; + for (Index = BottomRow; Index >= TopRow + 1; Index -= MenuOption->Skip) { + if (Link->BackLink == &Menu) { + TopOfScreen = Link; + Link = SavedListEntry; + MenuOption = CR (Link, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE); + break; + } + + NewLine = TRUE; + Repaint = TRUE; + Link = Link->BackLink; + MenuOption = CR (Link, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE); + TopOfScreen = Link; + SavedListEntry = Link; + } + + NewPos = Link; + + // + // 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. + // + if (Repaint) { + AdjustDateAndTimePosition (TRUE, &TopOfScreen); + AdjustDateAndTimePosition (TRUE, &NewPos); + MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE); + } + break; + + case CfUiPageDown: + ControlFlag = CfCheckSelection; + + SavedListEntry = NewPos; + Link = TopOfScreen; + NewPos = TopOfScreen; + for (Index = TopRow; Index <= BottomRow - 1; Index += MenuOption->Skip) { + if (NewPos->ForwardLink == &Menu) { + NewPos = SavedListEntry; + MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE); + Link = TopOfScreen; + NewLine = FALSE; + Repaint = FALSE; + break; + } + + NewLine = TRUE; + Repaint = TRUE; + MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE); + NewPos = NewPos->ForwardLink; + Link = NewPos; + } + + TopOfScreen = Link; + + // + // 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. + // + if (Repaint) { + AdjustDateAndTimePosition (TRUE, &TopOfScreen); + AdjustDateAndTimePosition (TRUE, &NewPos); + MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE); + } + break; + + case CfUiDown: + ControlFlag = CfCheckSelection; + // + // 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. + // + DataAndTimeLineNumberPad = AdjustDateAndTimePosition (FALSE, &NewPos); + + if (NewPos->ForwardLink != &Menu) { + NewLine = TRUE; + NewPos = NewPos->ForwardLink; + NextMenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE); + + if (SubMenu) { + // + // If the next MenuOption contains a display-only op-code, skip to the next one + // Also if the next MenuOption is date or time, + // + if (NextMenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || NextMenuOption->ThisTag->GrayOut) { + // + // This is ok as long as not at the end of the list + // + if (NewPos == &Menu) { + // + // If we are at the end of the list, then this list must end with a display only + // piece of data, so do not allow the forward motion + // + UpdateStatusBar (INPUT_ERROR, NextMenuOption->ThisTag->Flags, FALSE); + NewPos = NewPos->BackLink; + ScreenOperation = UiUp; + break; + } + } + } + // + // An option might be multi-line, so we need to reflect that data in the overall skip value + // + UpdateOptionSkipLines (PageData, NextMenuOption, FileFormTagsHead, &OptionString, SkipValue); + + if (NextMenuOption->Skip > 1) { + Temp = MenuOption->Row + MenuOption->Skip + NextMenuOption->Skip - 1; + } else { + Temp = MenuOption->Row + MenuOption->Skip + DataAndTimeLineNumberPad; + } + // + // If we are going to scroll + // + if (Temp > BottomRow) { + do { + // + // Is the current top of screen a zero-advance op-code? + // If so, keep moving forward till we hit a >0 advance op-code + // + SavedMenuOption = CR (TopOfScreen, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE); + + // + // If bottom op-code is more than one line or top op-code is more than one line + // + if ((NextMenuOption->Skip > 1) || (MenuOption->Skip > 1)) { + // + // Is the bottom op-code greater than or equal in size to the top op-code? + // + if ((Temp - BottomRow) >= (SavedMenuOption->Skip - OldSkipValue)) { + // + // Skip the top op-code + // + TopOfScreen = TopOfScreen->ForwardLink; + Difference = (Temp - BottomRow) - (SavedMenuOption->Skip - OldSkipValue); + + OldSkipValue = Difference; + + SavedMenuOption = CR (TopOfScreen, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE); + + // + // If we have a remainder, skip that many more op-codes until we drain the remainder + // + for (; + Difference >= (INTN) SavedMenuOption->Skip; + Difference = Difference - (INTN) SavedMenuOption->Skip + ) { + // + // Since the Difference is greater than or equal to this op-code's skip value, skip it + // + TopOfScreen = TopOfScreen->ForwardLink; + SavedMenuOption = CR (TopOfScreen, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE); + if (Difference < (INTN) SavedMenuOption->Skip) { + Difference = SavedMenuOption->Skip - Difference - 1; + break; + } else { + if (Difference == (INTN) SavedMenuOption->Skip) { + TopOfScreen = TopOfScreen->ForwardLink; + SavedMenuOption = CR (TopOfScreen, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE); + Difference = SavedMenuOption->Skip - Difference; + break; + } + } + } + // + // 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 = Difference - 1; + + } 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 = OldSkipValue + (Temp - BottomRow) - 1; + } + } else { + if ((OldSkipValue + 1) == (INTN) SavedMenuOption->Skip) { + TopOfScreen = TopOfScreen->ForwardLink; + break; + } else { + SkipValue = OldSkipValue; + } + } + // + // If the op-code at the top of the screen is more than one line, let's not skip it yet + // Let's set a skip flag to smoothly scroll the top of the screen. + // + if (SavedMenuOption->Skip > 1) { + if (SavedMenuOption == NextMenuOption) { + SkipValue = 0; + } else { + SkipValue++; + } + } else { + SkipValue = 0; + TopOfScreen = TopOfScreen->ForwardLink; + } + } while (SavedMenuOption->Skip == 0); + + Repaint = TRUE; + OldSkipValue = SkipValue; + } + + UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->Flags, FALSE); + + } else { + if (SubMenu) { + SavedMenuOption = MenuOption; + MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE); + if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || MenuOption->ThisTag->GrayOut) { + // + // If we are at the end of the list and sitting on a text op, we need to more forward + // + ScreenOperation = UiUp; + ControlFlag = CfScreenOperation; + break; + } + + MenuOption = SavedMenuOption; + // + // If we are at the end of the list and sitting on a Date/Time op, rewind to the head. + // + AdjustDateAndTimePosition (TRUE, &NewPos); + } + } + break; + + case CfUiSave: + ControlFlag = CfCheckSelection; + // + // Check for tags that might have LATE_CHECK enabled. If they do, we can't switch pages or save NV data. + // + if (MenuOption != NULL) { + if (!SelectionsAreValid (MenuOption, FileFormTagsHead)) { + Selection = NULL; + Repaint = TRUE; + break; + } + } + // + // If callbacks are active, and the callback has a Write method, try to use it + // + if (FileFormTags->VariableDefinitions->VariableName == NULL) { + if ((FormCallback != NULL) && (FormCallback->NvWrite != NULL)) { + Status = FormCallback->NvWrite ( + FormCallback, + (CHAR16 *) L"Setup", + &FileFormTags->FormTags.Tags[0].GuidValue, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + VariableDefinition->VariableSize, + (VOID *) VariableDefinition->NvRamMap, + &gResetRequired + ); + + } else { + Status = gRT->SetVariable ( + (CHAR16 *) L"Setup", + &FileFormTags->FormTags.Tags[0].GuidValue, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + VariableDefinition->VariableSize, + (VOID *) VariableDefinition->NvRamMap + ); + } + } else { + VariableDefinition = FileFormTags->VariableDefinitions; + + for (; VariableDefinition != NULL; VariableDefinition = VariableDefinition->Next) { + if ((FormCallback != NULL) && (FormCallback->NvWrite != NULL)) { + Status = FormCallback->NvWrite ( + FormCallback, + VariableDefinition->VariableName, + &VariableDefinition->Guid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + VariableDefinition->VariableSize, + (VOID *) VariableDefinition->NvRamMap, + &gResetRequired + ); + + } else { + Status = gRT->SetVariable ( + VariableDefinition->VariableName, + &VariableDefinition->Guid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + VariableDefinition->VariableSize, + (VOID *) VariableDefinition->NvRamMap + ); + } + } + } + + UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->Flags, FALSE); + UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->Flags, FALSE); + break; + + case CfUiDefault: + ControlFlag = CfCheckSelection; + + NvMapListHead = NULL; + + Status = Hii->GetDefaultImage (Hii, MenuOption->Handle, EFI_IFR_FLAG_DEFAULT, &NvMapListHead); + + if (!EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (NULL != NvMapListHead); + + NvMapListNode = NvMapListHead; + + while (NULL != NvMapListNode) { + if (FileFormTags->VariableDefinitions->VariableId == NvMapListNode->VariablePack->VariableId) { + NvMap = (VOID *) ((CHAR8 *) NvMapListNode->VariablePack + sizeof (EFI_HII_VARIABLE_PACK) + NvMapListNode->VariablePack->VariableNameLength); + NvMapSize = NvMapListNode->VariablePack->Header.Length - sizeof (EFI_HII_VARIABLE_PACK) - NvMapListNode->VariablePack->VariableNameLength; + break; + } + NvMapListNode = NvMapListNode->NextVariablePack; + } + + // + // Free the buffer that was allocated. + // + gBS->FreePool (FileFormTags->VariableDefinitions->NvRamMap); + gBS->FreePool (FileFormTags->VariableDefinitions->FakeNvRamMap); + + // + // Allocate, copy the NvRamMap. + // + FileFormTags->VariableDefinitions->VariableFakeSize = (UINT16) (FileFormTags->VariableDefinitions->VariableFakeSize - FileFormTags->VariableDefinitions->VariableSize); + FileFormTags->VariableDefinitions->VariableSize = (UINT16) NvMapSize; + FileFormTags->VariableDefinitions->VariableFakeSize = (UINT16) (FileFormTags->VariableDefinitions->VariableFakeSize + FileFormTags->VariableDefinitions->VariableSize); + + FileFormTags->VariableDefinitions->NvRamMap = AllocateZeroPool (FileFormTags->VariableDefinitions->VariableSize); + FileFormTags->VariableDefinitions->FakeNvRamMap = AllocateZeroPool (NvMapSize + FileFormTags->VariableDefinitions->VariableFakeSize); + + CopyMem (FileFormTags->VariableDefinitions->NvRamMap, NvMap, NvMapSize); + gBS->FreePool (NvMapListHead); + } + + UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->Flags, TRUE); + Repaint = TRUE; + // + // After the repaint operation, we should refresh the highlight. + // + NewLine = TRUE; + break; + + case CfUiNoOperation: + ControlFlag = CfCheckSelection; + break; + + case CfExit: + while (gMenuRefreshHead != NULL) { + OldMenuRefreshEntry = gMenuRefreshHead->Next; + + gBS->FreePool (gMenuRefreshHead); + + gMenuRefreshHead = OldMenuRefreshEntry; + } + + gST->ConOut->SetCursorPosition (gST->ConOut, 0, Row + 4); + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + gST->ConOut->OutputString (gST->ConOut, (CHAR16 *) L"\n"); + + gActiveIfr = MenuOption->IfrNumber; + return Selection; + + default: + break; + } + } +} + +BOOLEAN +ValueIsScroll ( + IN BOOLEAN Direction, + IN LIST_ENTRY *CurrentPos + ) +/*++ + +Routine Description: + Determine if the menu is the last menu that can be selected. + +Arguments: + Direction - the scroll direction. False is down. True is up. + +Returns: + FALSE -- the menu isn't the last menu that can be selected. + TRUE -- the menu is the last menu that can be selected. +--*/ +{ + LIST_ENTRY *Temp; + UI_MENU_OPTION *MenuOption; + MenuOption = NULL; + + Temp = Direction ? CurrentPos->BackLink : CurrentPos->ForwardLink; + + if (Temp == &Menu) { + return TRUE; + } + + for (; Temp != &Menu; Temp = Direction ? Temp->BackLink : Temp->ForwardLink) { + MenuOption = CR (Temp, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE); + if (!(MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || MenuOption->ThisTag->GrayOut)) { + return FALSE; + } + } + + return TRUE; +} + +UINTN +AdjustDateAndTimePosition ( + IN BOOLEAN DirectionUp, + IN LIST_ENTRY **CurrentPosition + ) +/*++ +Routine Description: + Adjust Data and Time tag position accordingly. + Data format : [01/02/2004] [11:22:33] + Line number : 0 0 1 0 0 1 + +Arguments: + Direction - the up or down direction. False is down. True is up. + CurrentPos - Current position. + +Returns: + Return line number to pad. It is possible that we stand on a zero-advance + data or time opcode, so pad one line when we judge if we are going to scroll outside. +--*/ +{ + UINTN Count; + LIST_ENTRY *NewPosition; + UI_MENU_OPTION *MenuOption; + UINTN PadLineNumber; + + PadLineNumber = 0; + NewPosition = *CurrentPosition; + MenuOption = CR (NewPosition, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE); + + if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) { + // + // Calculate the distance from current position to the last Date/Time op-code. + // + Count = 0; + while (MenuOption->ThisTag->NumberOfLines == 0) { + Count++; + NewPosition = NewPosition->ForwardLink; + MenuOption = CR (NewPosition, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE); + PadLineNumber = 1; + } + + NewPosition = *CurrentPosition; + if (DirectionUp) { + // + // Since the behavior of hitting the up arrow on a Date/Time op-code is intended + // to be one that back to the previous set of op-codes, we need to advance to the first + // Date/Time op-code 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 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 CfUiDown intact so the appropriate + // checking can be done. + // + while (Count-- > 0) { + NewPosition = NewPosition->ForwardLink; + } + } + + *CurrentPosition = NewPosition; + } + + return PadLineNumber; +} diff --git a/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Ui.h b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Ui.h new file mode 100644 index 0000000000..522f4ce5b8 --- /dev/null +++ b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Ui.h @@ -0,0 +1,435 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Ui.h + +Abstract: + + Head file UI + +Revision History + +--*/ + +#ifndef _UI_H +#define _UI_H + +// +// Globals +// +#define REGULAR_NUMERIC 0 +#define TIME_NUMERIC 1 +#define DATE_NUMERIC 2 + +typedef enum { + UiNoOperation, + UiDefault, + UiSelect, + UiUp, + UiDown, + UiLeft, + UiRight, + UiReset, + UiSave, + UiPrevious, + UiPageUp, + UiPageDown, + UiMaxOperation +} UI_SCREEN_OPERATION; + +typedef enum { + CfInitialization, + CfCheckSelection, + CfRepaint, + CfRefreshHighLight, + CfUpdateHelpString, + CfPrepareToReadKey, + CfReadKey, + CfScreenOperation, + CfUiPrevious, + CfUiSelect, + CfUiReset, + CfUiLeft, + CfUiRight, + CfUiUp, + CfUiPageUp, + CfUiPageDown, + CfUiDown, + CfUiSave, + CfUiDefault, + CfUiNoOperation, + CfExit, + CfMaxControlFlag +} UI_CONTROL_FLAG; + +#define UI_MENU_OPTION_SIGNATURE EFI_SIGNATURE_32 ('u', 'i', 'm', 'm') +#define UI_MENU_LIST_SIGNATURE EFI_SIGNATURE_32 ('u', 'i', 'm', 'l') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + UINTN Row; + UINTN Col; + UINTN OptCol; + CHAR16 *Description; + UINTN Skip; + + UINTN IfrNumber; + VOID *FormBinary; + EFI_HII_HANDLE Handle; + EFI_TAG *Tags; + UINTN TagIndex; + EFI_TAG *ThisTag; + UINT16 FormId; + BOOLEAN Previous; + UINT16 EntryNumber; + UINT16 Consistency; + BOOLEAN GrayOut; +} UI_MENU_OPTION; + +typedef struct { + UINTN Signature; + LIST_ENTRY MenuLink; + + UI_MENU_OPTION Selection; + UINTN FormerEntryNumber; +} UI_MENU_LIST; + +typedef struct _MENU_REFRESH_ENTRY { + struct _MENU_REFRESH_ENTRY *Next; + EFI_FILE_FORM_TAGS *FileFormTagsHead; + UINTN CurrentColumn; + UINTN CurrentRow; + UINTN CurrentAttribute; + UI_MENU_OPTION *MenuOption; // Describes the entry needing an update +} MENU_REFRESH_ENTRY; + +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; + +LIST_ENTRY Menu; +LIST_ENTRY gMenuList; +MENU_REFRESH_ENTRY *gMenuRefreshHead; + +INTN gEntryNumber; +BOOLEAN gLastOpr; +// +// Global Functions +// +VOID +UiInitMenu ( + VOID + ) +; + +VOID +UiInitMenuList ( + VOID + ) +; + +VOID +UiRemoveMenuListEntry ( + IN UI_MENU_OPTION *Selection, + OUT UI_MENU_OPTION **PreviousSelection + ) +; + +VOID +UiFreeMenuList ( + VOID + ) +; + +VOID +UiAddMenuListEntry ( + IN UI_MENU_OPTION *Selection + ) +; + +VOID +UiFreeMenu ( + VOID + ) +; + +VOID +UiAddMenuOption ( + IN CHAR16 *String, + IN EFI_HII_HANDLE Handle, + IN EFI_TAG *Tag, + IN VOID *FormBinary, + IN UINTN IfrNumber + ) +; + +VOID +UiAddSubMenuOption ( + IN CHAR16 *String, + IN EFI_HII_HANDLE Handle, + IN EFI_TAG *Tag, + IN UINTN TagIndex, + IN UINT16 FormId, + IN UINT16 MenuItemCount + ) +; + +UI_MENU_OPTION * +UiDisplayMenu ( + IN BOOLEAN SubMenu, + IN EFI_FILE_FORM_TAGS *FileFormTagsHead, + OUT EFI_IFR_DATA_ARRAY *PageData + ) +; + +VOID +InitPage ( + VOID + ) +; + +UI_MENU_OPTION * +SetupBrowser ( + IN UI_MENU_OPTION *Selection, + IN BOOLEAN Callback, + IN EFI_FILE_FORM_TAGS *FileFormTagsHead, + IN UINT8 *CallbackData + ) +; + + +VOID +SetUnicodeMem ( + IN VOID *Buffer, + IN UINTN Size, + IN CHAR16 Value + ) +; + +EFI_STATUS +UiWaitForSingleEvent ( + IN EFI_EVENT Event, + IN UINT64 Timeout OPTIONAL + ) +; + +VOID +CreatePopUp ( + IN UINTN ScreenWidth, + IN UINTN NumberOfLines, + IN CHAR16 *ArrayOfStrings, + ... + ) +; + +EFI_STATUS +ReadString ( + IN UI_MENU_OPTION *MenuOption, + OUT CHAR16 *StringPtr + ) +; + +EFI_STATUS +ReadPassword ( + IN UI_MENU_OPTION *MenuOption, + IN BOOLEAN PromptForPassword, + IN EFI_TAG *Tag, + IN EFI_IFR_DATA_ARRAY *PageData, + IN BOOLEAN SecondEntry, + IN EFI_FILE_FORM_TAGS *FileFormTags, + OUT CHAR16 *StringPtr + ) +; + +VOID +EncodePassword ( + IN CHAR16 *Password, + IN UINT8 MaxSize + ) +; + +EFI_STATUS +GetSelectionInputPopUp ( + IN UI_MENU_OPTION *MenuOption, + IN EFI_TAG *Tag, + IN UINTN ValueCount, + OUT UINT16 *Value, + OUT UINT16 *KeyValue + ) +; + +EFI_STATUS +GetSelectionInputLeftRight ( + IN UI_MENU_OPTION *MenuOption, + IN EFI_TAG *Tag, + IN UINTN ValueCount, + OUT UINT16 *Value + ) +; + +EFI_STATUS +GetNumericInput ( + IN UI_MENU_OPTION *MenuOption, + IN EFI_FILE_FORM_TAGS *FileFormTagsHead, + IN BOOLEAN ManualInput, + IN EFI_TAG *Tag, + IN UINTN NumericType, + OUT UINT16 *Value + ) +; + +VOID +UpdateStatusBar ( + IN UINTN MessageType, + IN UINT8 Flags, + IN BOOLEAN State + ) +; + +EFI_STATUS +ProcessOptions ( + IN UI_MENU_OPTION *MenuOption, + IN BOOLEAN Selected, + IN EFI_FILE_FORM_TAGS *FileFormTagsHead, + IN EFI_IFR_DATA_ARRAY *PageData, + OUT CHAR16 **OptionString + ) +; + +VOID +ProcessHelpString ( + IN CHAR16 *StringPtr, + OUT CHAR16 **FormattedString, + IN UINTN RowCount + ) +; + +VOID +UpdateKeyHelp ( + IN UI_MENU_OPTION *Selection, + IN BOOLEAN Selected + ) +; + +BOOLEAN +ValueIsNotValid ( + IN BOOLEAN Complex, + IN UINT16 Value, + IN EFI_TAG *Tag, + IN EFI_FILE_FORM_TAGS *FileFormTags, + IN STRING_REF *PopUp + ) +; + +VOID +FreeData ( + IN EFI_FILE_FORM_TAGS *FileFormTagsHead, + IN CHAR16 *FormattedString, + IN CHAR16 *OptionString + ) +; + +VOID +ClearLines ( + UINTN LeftColumn, + UINTN RightColumn, + UINTN TopRow, + UINTN BottomRow, + UINTN TextAttribute + ) +; + +UINTN +GetStringWidth ( + CHAR16 *String + ) +; + +UINT16 +GetLineByWidth ( + IN CHAR16 *InputString, + IN UINT16 LineWidth, + IN OUT UINTN *Index, + OUT CHAR16 **OutputString + ) +; + +UINT16 +GetWidth ( + IN EFI_TAG *Tag, + IN EFI_HII_HANDLE Handle + ) +; + +VOID +NewStrCat ( + CHAR16 *Destination, + CHAR16 *Source + ) +; + +VOID +IfrToFormTag ( + IN UINT8 OpCode, + IN EFI_TAG *TargetTag, + IN VOID *FormData, + EFI_VARIABLE_DEFINITION *VariableDefinitionsHead + ) +; + +EFI_STATUS +ExtractNvValue ( + IN EFI_FILE_FORM_TAGS *FileFormTags, + IN UINT16 VariableId, + IN UINT16 VariableSize, + IN UINT16 OffsetValue, + OUT VOID **Buffer + ) +; + +EFI_STATUS +ExtractRequestedNvMap ( + IN EFI_FILE_FORM_TAGS *FileFormTags, + IN UINT16 VariableId, + OUT EFI_VARIABLE_DEFINITION **VariableDefinition + ) +; + +BOOLEAN +ValueIsScroll ( + IN BOOLEAN Direction, + IN LIST_ENTRY *CurrentPos + ) +; + +UINTN +AdjustDateAndTimePosition ( + IN BOOLEAN DirectionUp, + IN LIST_ENTRY **CurrentPosition + ) +; + +EFI_STATUS +WaitForKeyStroke ( + OUT EFI_INPUT_KEY *Key + ) +; +#endif // _UI_H diff --git a/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/build.xml b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/build.xml new file mode 100644 index 0000000000..a94cdfa58c --- /dev/null +++ b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Universal/Variable/Pei/Ia32/VarMachine.h b/EdkModulePkg/Universal/Variable/Pei/Ia32/VarMachine.h new file mode 100644 index 0000000000..83031e9788 --- /dev/null +++ b/EdkModulePkg/Universal/Variable/Pei/Ia32/VarMachine.h @@ -0,0 +1,27 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + VarMachine.h + +Abstract: + + Variable Machine Type + +--*/ + +#ifndef _VAR_MACHINE_H +#define _VAR_MACHINE_H + +#define ALIGNMENT 1 + +#endif diff --git a/EdkModulePkg/Universal/Variable/Pei/Ipf/VarMachine.h b/EdkModulePkg/Universal/Variable/Pei/Ipf/VarMachine.h new file mode 100644 index 0000000000..c5b5753f9e --- /dev/null +++ b/EdkModulePkg/Universal/Variable/Pei/Ipf/VarMachine.h @@ -0,0 +1,27 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + VarMachine.h + +Abstract: + + Variable Machine Type + +--*/ + +#ifndef _VAR_MACHINE_H +#define _VAR_MACHINE_H + +#define ALIGNMENT 8 + +#endif diff --git a/EdkModulePkg/Universal/Variable/Pei/Variable.c b/EdkModulePkg/Universal/Variable/Pei/Variable.c new file mode 100644 index 0000000000..b2286c1860 --- /dev/null +++ b/EdkModulePkg/Universal/Variable/Pei/Variable.c @@ -0,0 +1,563 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Variable.c + +Abstract: + + Framework PEIM to provide the Variable functionality + +--*/ + + +#include +#include +#include + +// +// Module globals +// +static EFI_PEI_READ_ONLY_VARIABLE_PPI mVariablePpi = { + PeiGetVariable, + PeiGetNextVariableName +}; + +static EFI_PEI_PPI_DESCRIPTOR mPpiListVariable = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiPeiReadOnlyVariablePpiGuid, + &mVariablePpi +}; + +EFI_GUID gEfiVariableIndexTableGuid = EFI_VARIABLE_INDEX_TABLE_GUID; + +EFI_STATUS +EFIAPI +PeimInitializeVariableServices ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices + ) +/*++ + +Routine Description: + + Provide the functionality of the variable services. + +Arguments: + + FfsHeadher - The FFS file header + PeiServices - General purpose services available to every PEIM. + +Returns: + + Status - EFI_SUCCESS if the interface could be successfully + installed + +--*/ +{ + // + // Publish the variable capability to other modules + // + return (**PeiServices).InstallPpi (PeiServices, &mPpiListVariable); + +} + +VARIABLE_HEADER * +GetNextVariablePtr ( + IN VARIABLE_HEADER *Variable + ) +/*++ + +Routine Description: + + This code checks if variable header is valid or not. + +Arguments: + Variable Pointer to the Variable Header. + +Returns: + TRUE Variable header is valid. + FALSE Variable header is not valid. + +--*/ +{ + return (VARIABLE_HEADER *) ((UINTN) GET_VARIABLE_DATA_PTR (Variable) + Variable->DataSize + GET_PAD_SIZE (Variable->DataSize)); +} + +BOOLEAN +EFIAPI +IsValidVariableHeader ( + IN VARIABLE_HEADER *Variable + ) +/*++ + +Routine Description: + + This code checks if variable header is valid or not. + +Arguments: + Variable Pointer to the Variable Header. + +Returns: + TRUE Variable header is valid. + FALSE Variable header is not valid. + +--*/ +{ + if (Variable == NULL || + Variable->StartId != VARIABLE_DATA || + (sizeof (VARIABLE_HEADER) + Variable->DataSize + Variable->NameSize) > MAX_VARIABLE_SIZE + ) { + return FALSE; + } + + return TRUE; +} + +VARIABLE_STORE_STATUS +EFIAPI +GetVariableStoreStatus ( + IN VARIABLE_STORE_HEADER *VarStoreHeader + ) +/*++ + +Routine Description: + + This code gets the pointer to the variable name. + +Arguments: + + VarStoreHeader Pointer to the Variable Store Header. + +Returns: + + EfiRaw Variable store is raw + EfiValid Variable store is valid + EfiInvalid Variable store is invalid + +--*/ +{ + if (VarStoreHeader->Signature == VARIABLE_STORE_SIGNATURE && + VarStoreHeader->Format == VARIABLE_STORE_FORMATTED && + VarStoreHeader->State == VARIABLE_STORE_HEALTHY + ) { + + return EfiValid; + } + + if (VarStoreHeader->Signature == 0xffffffff && + VarStoreHeader->Size == 0xffffffff && + VarStoreHeader->Format == 0xff && + VarStoreHeader->State == 0xff + ) { + + return EfiRaw; + } else { + return EfiInvalid; + } +} + +EFI_STATUS +CompareWithValidVariable ( + IN VARIABLE_HEADER *Variable, + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT VARIABLE_POINTER_TRACK *PtrTrack + ) +/*++ + +Routine Description: + + This function compares a variable with variable entries in database + +Arguments: + + Variable - Pointer to the variable in our database + VariableName - Name of the variable to compare to 'Variable' + VendorGuid - GUID of the variable to compare to 'Variable' + PtrTrack - Variable Track Pointer structure that contains + Variable Information. + +Returns: + + EFI_SUCCESS - Found match variable + EFI_NOT_FOUND - Variable not found + +--*/ +{ + 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 *) &Variable->VendorGuid)[0]) && + (((INT32 *) VendorGuid)[1] == ((INT32 *) &Variable->VendorGuid)[1]) && + (((INT32 *) VendorGuid)[2] == ((INT32 *) &Variable->VendorGuid)[2]) && + (((INT32 *) VendorGuid)[3] == ((INT32 *) &Variable->VendorGuid)[3]) + ) { + if (!StrCmp (VariableName, GET_VARIABLE_NAME_PTR (Variable))) { + PtrTrack->CurrPtr = Variable; + return EFI_SUCCESS; + } + } + } + + return EFI_NOT_FOUND; +} + +EFI_STATUS +EFIAPI +FindVariable ( + IN EFI_PEI_SERVICES **PeiServices, + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT VARIABLE_POINTER_TRACK *PtrTrack + ) +/*++ + +Routine Description: + + This code finds variable in storage blocks (Non-Volatile) + +Arguments: + + PeiServices - General purpose services available to every PEIM. + VariableName - Name of the variable to be found + VendorGuid - Vendor GUID to be found. + PtrTrack - Variable Track Pointer structure that contains + Variable Information. + +Returns: + + EFI_SUCCESS - Variable found successfully + EFI_NOT_FOUND - Variable not found + EFI_INVALID_PARAMETER - Invalid variable name + +--*/ +{ + PEI_FLASH_MAP_PPI *FlashMapPpi; + EFI_FLASH_SUBAREA_ENTRY *VariableStoreEntry; + UINT32 NumEntries; + EFI_HOB_GUID_TYPE *GuidHob; + VARIABLE_STORE_HEADER *VariableStoreHeader; + VARIABLE_HEADER *Variable; + + EFI_STATUS Status; + + VARIABLE_HEADER *MaxIndex; + VARIABLE_INDEX_TABLE *IndexTable; + UINT32 Count; + + if (VariableName != 0 && VendorGuid == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // No Variable Address equals zero, so 0 as initial value is safe. + // + MaxIndex = 0; + + GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid); + if (GuidHob == NULL) { + IndexTable = BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE)); + IndexTable->Length = 0; + IndexTable->StartPtr = NULL; + IndexTable->EndPtr = NULL; + IndexTable->GoneThrough = 0; + } else { + IndexTable = GET_GUID_HOB_DATA (GuidHob); + for (Count = 0; Count < IndexTable->Length; Count++) + { +#if ALIGNMENT <= 1 + MaxIndex = (VARIABLE_HEADER *) (UINTN) (IndexTable->Index[Count] + ((UINTN) IndexTable->StartPtr & 0xFFFF0000)); +#else +#if ALIGNMENT >= 4 + MaxIndex = (VARIABLE_HEADER *) (UINTN) ((((UINT32)IndexTable->Index[Count]) << 2) + ((UINT32)(UINTN)IndexTable->StartPtr & 0xFFFC0000) ); +#endif +#endif + if (CompareWithValidVariable (MaxIndex, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) { + PtrTrack->StartPtr = IndexTable->StartPtr; + PtrTrack->EndPtr = IndexTable->EndPtr; + + return EFI_SUCCESS; + } + } + + if (IndexTable->GoneThrough) { + return EFI_NOT_FOUND; + } + } + // + // If not found in HOB, then let's start from the MaxIndex we've found. + // + if (MaxIndex != NULL) { + Variable = GetNextVariablePtr (MaxIndex); + } else { + if (IndexTable->StartPtr || IndexTable->EndPtr) { + Variable = IndexTable->StartPtr; + } else { + // + // Locate FlashMap PPI + // + Status = (**PeiServices).LocatePpi ( + PeiServices, + &gPeiFlashMapPpiGuid, + 0, + NULL, + (VOID **) &FlashMapPpi + ); + ASSERT_EFI_ERROR (Status); + + // + // Get flash area info for variables + // + Status = FlashMapPpi->GetAreaInfo ( + PeiServices, + FlashMapPpi, + EFI_FLASH_AREA_EFI_VARIABLES, + NULL, + &NumEntries, + &VariableStoreEntry + ); + + // + // Currently only one non-volatile variable store is supported + // + if (NumEntries != 1) { + return EFI_UNSUPPORTED; + } + + VariableStoreHeader = (VARIABLE_STORE_HEADER *) (UINTN) (VariableStoreEntry->Base); + + if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) { + return EFI_UNSUPPORTED; + } + + if (~VariableStoreHeader->Size == 0) { + return EFI_NOT_FOUND; + } + // + // Find the variable by walk through non-volatile variable store + // + IndexTable->StartPtr = (VARIABLE_HEADER *) (VariableStoreHeader + 1); + IndexTable->EndPtr = (VARIABLE_HEADER *) ((UINTN) VariableStoreHeader + VariableStoreHeader->Size); + + // + // Start Pointers for the variable. + // Actual Data Pointer where data can be written. + // + Variable = IndexTable->StartPtr; + } + } + // + // Find the variable by walk through non-volatile variable store + // + PtrTrack->StartPtr = IndexTable->StartPtr; + PtrTrack->EndPtr = IndexTable->EndPtr; + + while (IsValidVariableHeader (Variable) && (Variable <= IndexTable->EndPtr)) { + if (Variable->State == VAR_ADDED) { + // + // Record Variable in VariableIndex HOB + // + if (IndexTable->Length < VARIABLE_INDEX_TABLE_VOLUME) + { +#if ALIGNMENT <= 1 + IndexTable->Index[IndexTable->Length++] = (UINT16) (UINTN) Variable; +#else +#if ALIGNMENT >= 4 + IndexTable->Index[IndexTable->Length++] = (UINT16) (((UINT32)(UINTN) Variable) >> 2); +#endif +#endif + } + + if (CompareWithValidVariable (Variable, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) { + return EFI_SUCCESS; + } + } + + Variable = GetNextVariablePtr (Variable); + } + // + // If gone through the VariableStore, that means we never find in Firmware any more. + // + if (IndexTable->Length < VARIABLE_INDEX_TABLE_VOLUME) { + IndexTable->GoneThrough = 1; + } + + PtrTrack->CurrPtr = NULL; + + return EFI_NOT_FOUND; +} + +EFI_STATUS +EFIAPI +PeiGetVariable ( + IN EFI_PEI_SERVICES **PeiServices, + IN CHAR16 *VariableName, + IN EFI_GUID * VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, + OUT VOID *Data + ) +/*++ + +Routine Description: + + Provide the read variable functionality of the variable services. + +Arguments: + + PeiServices - General purpose services available to every PEIM. + + VariableName - The variable name + + VendorGuid - The vendor's GUID + + Attributes - Pointer to the attribute + + DataSize - Size of data + + Data - Pointer to data + +Returns: + + EFI_SUCCESS - The interface could be successfully installed + + EFI_NOT_FOUND - The variable could not be discovered + + EFI_BUFFER_TOO_SMALL - The caller buffer is not large enough + +--*/ +{ + VARIABLE_POINTER_TRACK Variable; + UINTN VarDataSize; + EFI_STATUS Status; + + if (VariableName == NULL || VendorGuid == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Find existing variable + // + Status = FindVariable (PeiServices, VariableName, VendorGuid, &Variable); + + if (Variable.CurrPtr == NULL || Status != EFI_SUCCESS) { + return Status; + } + // + // Get data size + // + VarDataSize = Variable.CurrPtr->DataSize; + if (*DataSize >= VarDataSize) { + (*PeiServices)->CopyMem (Data, GET_VARIABLE_DATA_PTR (Variable.CurrPtr), VarDataSize); + + if (Attributes != NULL) { + *Attributes = Variable.CurrPtr->Attributes; + } + + *DataSize = VarDataSize; + return EFI_SUCCESS; + } else { + *DataSize = VarDataSize; + return EFI_BUFFER_TOO_SMALL; + } +} + +EFI_STATUS +EFIAPI +PeiGetNextVariableName ( + IN EFI_PEI_SERVICES **PeiServices, + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VendorGuid + ) +/*++ + +Routine Description: + + Provide the get next variable functionality of the variable services. + +Arguments: + + PeiServices - General purpose services available to every PEIM. + VariabvleNameSize - The variable name's size. + VariableName - A pointer to the variable's name. + VendorGuid - A pointer to the EFI_GUID structure. + + VariableNameSize - Size of the variable name + + VariableName - The variable name + + VendorGuid - The vendor's GUID + +Returns: + + EFI_SUCCESS - The interface could be successfully installed + + EFI_NOT_FOUND - The variable could not be discovered + +--*/ +{ + VARIABLE_POINTER_TRACK Variable; + UINTN VarNameSize; + EFI_STATUS Status; + + if (VariableName == NULL) { + return EFI_INVALID_PARAMETER; + } + + Status = FindVariable (PeiServices, VariableName, VendorGuid, &Variable); + + if (Variable.CurrPtr == NULL || Status != EFI_SUCCESS) { + return Status; + } + + if (VariableName[0] != 0) { + // + // If variable name is not NULL, get next variable + // + Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); + } + + while (!(Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL)) { + if (IsValidVariableHeader (Variable.CurrPtr)) { + if (Variable.CurrPtr->State == VAR_ADDED) { + VarNameSize = (UINTN) Variable.CurrPtr->NameSize; + if (VarNameSize <= *VariableNameSize) { + (*PeiServices)->CopyMem (VariableName, GET_VARIABLE_NAME_PTR (Variable.CurrPtr), VarNameSize); + + (*PeiServices)->CopyMem (VendorGuid, &Variable.CurrPtr->VendorGuid, sizeof (EFI_GUID)); + + Status = EFI_SUCCESS; + } else { + Status = EFI_BUFFER_TOO_SMALL; + } + + *VariableNameSize = VarNameSize; + return Status; + // + // Variable is found + // + } else { + Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); + } + } else { + break; + } + } + + return EFI_NOT_FOUND; +} diff --git a/EdkModulePkg/Universal/Variable/Pei/Variable.dxs b/EdkModulePkg/Universal/Variable/Pei/Variable.dxs new file mode 100644 index 0000000000..d16ad10db2 --- /dev/null +++ b/EdkModulePkg/Universal/Variable/Pei/Variable.dxs @@ -0,0 +1,28 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Variable.dxs + +Abstract: + + Dependency expression file for Variable PEIM. + +--*/ +#include +#include + +DEPENDENCY_START + PEI_FLASH_MAP_PPI_GUID +DEPENDENCY_END + + diff --git a/EdkModulePkg/Universal/Variable/Pei/Variable.h b/EdkModulePkg/Universal/Variable/Pei/Variable.h new file mode 100644 index 0000000000..2a6f861def --- /dev/null +++ b/EdkModulePkg/Universal/Variable/Pei/Variable.h @@ -0,0 +1,154 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Variable.h + +Abstract: + + Tiano PEIM to provide the variable functionality + +--*/ + +#ifndef _PEI_VARIABLE_H +#define _PEI_VARIABLE_H + +// +// BugBug: We need relcate the head file. +// +#include + +#define ALIGNMENT 1 + +// +// Define GET_PAD_SIZE to optimize compiler +// +#if ((ALIGNMENT == 0) || (ALIGNMENT == 1)) +#define GET_PAD_SIZE(a) (0) +#else +#define GET_PAD_SIZE(a) (((~a) + 1) & (ALIGNMENT - 1)) +#endif + +#define GET_VARIABLE_NAME_PTR(a) (CHAR16 *) ((UINTN) (a) + sizeof (VARIABLE_HEADER)) + +#define GET_VARIABLE_DATA_PTR(a) \ + (UINT8 *) ((UINTN) GET_VARIABLE_NAME_PTR (a) + (a)->NameSize + GET_PAD_SIZE ((a)->NameSize)) + +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 } } + +typedef struct { + UINT16 Length; + UINT16 GoneThrough; + VARIABLE_HEADER *EndPtr; + VARIABLE_HEADER *StartPtr; + UINT16 Index[VARIABLE_INDEX_TABLE_VOLUME]; +} VARIABLE_INDEX_TABLE; + +extern EFI_GUID gEfiVariableIndexTableGuid; + +// +// Functions +// +EFI_STATUS +EFIAPI +PeimInitializeVariableServices ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + FfsHeader - TODO: add argument description + PeiServices - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +PeiGetVariable ( + IN EFI_PEI_SERVICES **PeiServices, + IN CHAR16 *VariableName, + IN EFI_GUID * VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, + OUT VOID *Data + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PeiServices - TODO: add argument description + VariableName - TODO: add argument description + VendorGuid - TODO: add argument description + Attributes - TODO: add argument description + DataSize - TODO: add argument description + Data - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +PeiGetNextVariableName ( + IN EFI_PEI_SERVICES **PeiServices, + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VendorGuid + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PeiServices - TODO: add argument description + VariableNameSize - TODO: add argument description + VariableName - TODO: add argument description + VendorGuid - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif // _PEI_VARIABLE_H diff --git a/EdkModulePkg/Universal/Variable/Pei/Variable.mbd b/EdkModulePkg/Universal/Variable/Pei/Variable.mbd new file mode 100644 index 0000000000..036758dc62 --- /dev/null +++ b/EdkModulePkg/Universal/Variable/Pei/Variable.mbd @@ -0,0 +1,43 @@ + + + + + PeiVariable + 34C8C28F-B61C-45a2-8F2E-89E46BECC63B + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + + PeiReportStatusCodeLib + BaseDebugLibReportStatusCode + BaseLib + PeiMemoryLib + PeiCoreLib + PeiServicesTablePointerLib + PeiHobLib + PeimEntryPoint + + + _ModuleEntryPoint + + diff --git a/EdkModulePkg/Universal/Variable/Pei/Variable.msa b/EdkModulePkg/Universal/Variable/Pei/Variable.msa new file mode 100644 index 0000000000..79c086bdb1 --- /dev/null +++ b/EdkModulePkg/Universal/Variable/Pei/Variable.msa @@ -0,0 +1,57 @@ + + + + + PeiVariable + PEIM + PE32_PEIM + 34C8C28F-B61C-45a2-8F2E-89E46BECC63B + 0 + Component description file for DiskIo module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + DebugLib + PeimEntryPoint + PeiCoreLib + HobLib + + + Variable.c + Variable.dxs + + + MdePkg + EdkModulePkg + + + FlashMap + ReadOnlyVariable + + + + PeimInitializeVariableServices + + + diff --git a/EdkModulePkg/Universal/Variable/Pei/build.xml b/EdkModulePkg/Universal/Variable/Pei/build.xml new file mode 100644 index 0000000000..c6b57f9f77 --- /dev/null +++ b/EdkModulePkg/Universal/Variable/Pei/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Universal/Variable/Pei/x64/VarMachine.h b/EdkModulePkg/Universal/Variable/Pei/x64/VarMachine.h new file mode 100644 index 0000000000..83031e9788 --- /dev/null +++ b/EdkModulePkg/Universal/Variable/Pei/x64/VarMachine.h @@ -0,0 +1,27 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + VarMachine.h + +Abstract: + + Variable Machine Type + +--*/ + +#ifndef _VAR_MACHINE_H +#define _VAR_MACHINE_H + +#define ALIGNMENT 1 + +#endif diff --git a/EdkModulePkg/Universal/Variable/RuntimeDxe/Emu/EmuVariable.c b/EdkModulePkg/Universal/Variable/RuntimeDxe/Emu/EmuVariable.c new file mode 100644 index 0000000000..beb404f42c --- /dev/null +++ b/EdkModulePkg/Universal/Variable/RuntimeDxe/Emu/EmuVariable.c @@ -0,0 +1,754 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + EmuVariable.c + +Abstract: + +Revision History + +--*/ + +#include "Variable.h" + +// +// Don't use module globals after the SetVirtualAddress map is signaled +// +ESAL_VARIABLE_GLOBAL *mVariableModuleGlobal; + +UINT32 +EFIAPI +ArrayLength ( + IN CHAR16 *String + ) +/*++ + +Routine Description: + + Determine the length of null terminated char16 array. + +Arguments: + + String Null-terminated CHAR16 array pointer. + +Returns: + + UINT32 Number of bytes in the string, including the double NULL at the end; + +--*/ +{ + UINT32 Count; + + if (NULL == String) { + return 0; + } + + Count = 0; + + while (0 != String[Count]) { + Count++; + } + + return (Count * 2) + 2; +} + +UINTN +EFIAPI +GetPadSize ( + IN UINTN Value + ) +/*++ + +Routine Description: + + This function return the pad size for alignment + +Arguments: + + Value The value need to align + +Returns: + + Pad size for value + +--*/ +{ + // + // If alignment is 0 or 1, means no alignment required + // + if (ALIGNMENT == 0 || ALIGNMENT == 1) { + return 0; + } + + return ALIGNMENT - (Value % ALIGNMENT); +} + +VARIABLE_STORE_STATUS +EFIAPI +GetVariableStoreStatus ( + IN VARIABLE_STORE_HEADER *VarStoreHeader + ) +/*++ + +Routine Description: + + This code gets the pointer to the variable name. + +Arguments: + + VarStoreHeader Pointer to the Variable Store Header. + +Returns: + + EfiHealthy Variable store is healthy + EfiRaw Variable store is raw + EfiInvalid Variable store is invalid + +--*/ +{ + if (VarStoreHeader->Signature == VARIABLE_STORE_SIGNATURE && + VarStoreHeader->Format == VARIABLE_STORE_FORMATTED && + VarStoreHeader->State == VARIABLE_STORE_HEALTHY + ) { + + return EfiValid; + } else if (VarStoreHeader->Signature == 0xffffffff && + VarStoreHeader->Size == 0xffffffff && + VarStoreHeader->Format == 0xff && + VarStoreHeader->State == 0xff + ) { + + return EfiRaw; + } else { + return EfiInvalid; + } +} + +UINT8 * +EFIAPI +GetVariableDataPtr ( + IN VARIABLE_HEADER *Variable + ) +/*++ + +Routine Description: + + This code gets the pointer to the variable data. + +Arguments: + + Variable Pointer to the Variable Header. + +Returns: + + UINT8* Pointer to Variable Data + +--*/ +{ + if (Variable->StartId != VARIABLE_DATA) { + return NULL; + } + // + // Be careful about pad size for alignment + // + return (UINT8 *) ((UINTN) GET_VARIABLE_NAME_PTR (Variable) + Variable->NameSize + GetPadSize (Variable->NameSize)); +} + +VARIABLE_HEADER * +EFIAPI +GetNextVariablePtr ( + IN VARIABLE_HEADER *Variable + ) +/*++ + +Routine Description: + + This code gets the pointer to the next variable header. + +Arguments: + + Variable Pointer to the Variable Header. + +Returns: + + VARIABLE_HEADER* Pointer to next variable header. + +--*/ +{ + VARIABLE_HEADER *VarHeader; + + if (Variable->StartId != VARIABLE_DATA) { + return NULL; + } + // + // Be careful about pad size for alignment + // + VarHeader = (VARIABLE_HEADER *) (GetVariableDataPtr (Variable) + Variable->DataSize + GET_PAD_SIZE (Variable->DataSize)); + + if (VarHeader->StartId != VARIABLE_DATA || + (sizeof (VARIABLE_HEADER) + VarHeader->DataSize + VarHeader->NameSize) > MAX_VARIABLE_SIZE + ) { + return NULL; + } + + return VarHeader; +} + +VARIABLE_HEADER * +EFIAPI +GetEndPointer ( + IN VARIABLE_STORE_HEADER *VolHeader + ) +/*++ + +Routine Description: + + This code gets the pointer to the last variable memory pointer byte + +Arguments: + + Variable Pointer to the Variable Header. + +Returns: + + VARIABLE_HEADER* Pointer to last unavailable Variable Header + +--*/ +{ + // + // The end of variable store + // + return (VARIABLE_HEADER *) ((UINTN) VolHeader + VolHeader->Size); +} + +EFI_STATUS +EFIAPI +FindVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT VARIABLE_POINTER_TRACK *PtrTrack, + IN VARIABLE_GLOBAL *Global + ) +/*++ + +Routine Description: + + This code finds variable in storage blocks (Volatile or Non-Volatile) + +Arguments: + + VariableName Name of the variable to be found + VendorGuid Vendor GUID to be found. + PtrTrack Variable Track Pointer structure that contains + Variable Information. + Contains the pointer of Variable header. + Global VARIABLE_GLOBAL pointer + +Returns: + + EFI STATUS + +--*/ +{ + VARIABLE_HEADER *Variable[2]; + VARIABLE_STORE_HEADER *VariableStoreHeader[2]; + UINTN Index; + + // + // 0: Non-Volatile, 1: Volatile + // + VariableStoreHeader[0] = (VARIABLE_STORE_HEADER *) ((UINTN) Global->NonVolatileVariableBase); + VariableStoreHeader[1] = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase); + + // + // Start Pointers for the variable. + // Actual Data Pointer where data can be written. + // + Variable[0] = (VARIABLE_HEADER *) (VariableStoreHeader[0] + 1); + Variable[1] = (VARIABLE_HEADER *) (VariableStoreHeader[1] + 1); + + if (VariableName[0] != 0 && VendorGuid == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Find the variable by walk through non-volatile and volatile variable store + // + for (Index = 0; Index < 2; Index++) { + PtrTrack->StartPtr = (VARIABLE_HEADER *) (VariableStoreHeader[Index] + 1); + PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index]); + + while ((Variable[Index] != NULL) && (Variable[Index] <= GetEndPointer (VariableStoreHeader[Index]))) { + if (Variable[Index]->StartId == VARIABLE_DATA && Variable[Index]->State == VAR_ADDED) { + if (!(EfiAtRuntime () && !(Variable[Index]->Attributes & EFI_VARIABLE_RUNTIME_ACCESS))) { + if (VariableName[0] == 0) { + PtrTrack->CurrPtr = Variable[Index]; + PtrTrack->Volatile = (BOOLEAN) Index; + return EFI_SUCCESS; + } else { + if (CompareGuid (VendorGuid, &Variable[Index]->VendorGuid)) { + if (!CompareMem (VariableName, GET_VARIABLE_NAME_PTR (Variable[Index]), ArrayLength (VariableName))) { + PtrTrack->CurrPtr = Variable[Index]; + PtrTrack->Volatile = (BOOLEAN) Index; + return EFI_SUCCESS; + } + } + } + } + } + + Variable[Index] = GetNextVariablePtr (Variable[Index]); + } + } + PtrTrack->CurrPtr = NULL; + return EFI_NOT_FOUND; +} + +EFI_STATUS +EFIAPI +GetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID * VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, + OUT VOID *Data, + IN VARIABLE_GLOBAL * Global, + IN UINT32 Instance + ) +/*++ + +Routine Description: + + This code finds variable in storage blocks (Volatile or Non-Volatile) + +Arguments: + + VariableName Name of Variable to be found + VendorGuid Variable vendor GUID + Attributes OPTIONAL Attribute value of the variable found + DataSize Size of Data found. If size is less than the + data, this value contains the required size. + Data Data pointer + Global Pointer to VARIABLE_GLOBAL structure + Instance Instance of the Firmware Volume. + +Returns: + + EFI STATUS + +--*/ +{ + VARIABLE_POINTER_TRACK Variable; + UINTN VarDataSize; + EFI_STATUS Status; + + if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Find existing variable + // + Status = FindVariable (VariableName, VendorGuid, &Variable, Global); + + if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) { + return Status; + } + // + // Get data size + // + VarDataSize = Variable.CurrPtr->DataSize; + if (*DataSize >= VarDataSize) { + CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize); + if (Attributes) { + *Attributes = Variable.CurrPtr->Attributes; + } + + *DataSize = VarDataSize; + return EFI_SUCCESS; + } else { + *DataSize = VarDataSize; + return EFI_BUFFER_TOO_SMALL; + } +} + +EFI_STATUS +EFIAPI +GetNextVariableName ( + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VendorGuid, + IN VARIABLE_GLOBAL *Global, + IN UINT32 Instance + ) +/*++ + +Routine Description: + + This code Finds the Next available variable + +Arguments: + + VariableNameSize Size of the variable + VariableName Pointer to variable name + VendorGuid Variable Vendor Guid + Global VARIABLE_GLOBAL structure pointer. + Instance FV instance + +Returns: + + EFI STATUS + +--*/ +{ + VARIABLE_POINTER_TRACK Variable; + UINTN VarNameSize; + EFI_STATUS Status; + + if (VariableNameSize == NULL || VendorGuid == NULL) { + return EFI_INVALID_PARAMETER; + } + + Status = FindVariable (VariableName, VendorGuid, &Variable, Global); + + if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) { + return Status; + } + + while (TRUE) { + if (VariableName[0] != 0) { + // + // If variable name is not NULL, get next variable + // + Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); + } + // + // If both volatile and non-volatile variable store are parsed, + // return not found + // + if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL) { + Variable.Volatile = (BOOLEAN) (Variable.Volatile ^ ((BOOLEAN) 0x1)); + if (Variable.Volatile) { + Variable.StartPtr = (VARIABLE_HEADER *) ((UINTN) (Global->VolatileVariableBase + sizeof (VARIABLE_STORE_HEADER))); + Variable.EndPtr = (VARIABLE_HEADER *) GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase)); + } else { + return EFI_NOT_FOUND; + } + + Variable.CurrPtr = Variable.StartPtr; + if (Variable.CurrPtr->StartId != VARIABLE_DATA) { + continue; + } + } + // + // Variable is found + // + if (Variable.CurrPtr->StartId == VARIABLE_DATA && Variable.CurrPtr->State == VAR_ADDED) { + if (!(EfiAtRuntime () && !(Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS))) { + VarNameSize = Variable.CurrPtr->NameSize; + if (VarNameSize <= *VariableNameSize) { + CopyMem ( + VariableName, + GET_VARIABLE_NAME_PTR (Variable.CurrPtr), + VarNameSize + ); + CopyMem ( + VendorGuid, + &Variable.CurrPtr->VendorGuid, + sizeof (EFI_GUID) + ); + Status = EFI_SUCCESS; + } else { + Status = EFI_BUFFER_TOO_SMALL; + } + + *VariableNameSize = VarNameSize; + return Status; + } + } + } + + return EFI_NOT_FOUND; +} + +EFI_STATUS +EFIAPI +SetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data, + IN VARIABLE_GLOBAL *Global, + IN UINTN *VolatileOffset, + IN UINTN *NonVolatileOffset, + IN UINT32 Instance + ) +/*++ + +Routine Description: + + This code sets variable in storage blocks (Volatile or Non-Volatile) + +Arguments: + + VariableName Name of Variable to be found + VendorGuid Variable vendor GUID + Attributes Attribute value of the variable found + DataSize Size of Data found. If size is less than the + data, this value contains the required size. + Data Data pointer + Global Pointer to VARIABLE_GLOBAL structure + VolatileOffset The offset of last volatile variable + NonVolatileOffset The offset of last non-volatile variable + Instance Instance of the Firmware Volume. + +Returns: + + EFI STATUS + +--*/ +{ + VARIABLE_POINTER_TRACK Variable; + EFI_STATUS Status; + VARIABLE_HEADER *NextVariable; + UINTN VarNameSize; + UINTN VarNameOffset; + UINTN VarDataOffset; + UINTN VarSize; + + if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) { + return EFI_INVALID_PARAMETER; + } + + Status = FindVariable (VariableName, VendorGuid, &Variable, Global); + + if (Status == EFI_INVALID_PARAMETER) { + return Status; + } + // + // The size of the VariableName, including the Unicode Null in bytes plus + // the DataSize is limited to maximum size of MAX_VARIABLE_SIZE (1024) bytes. + // + else if (sizeof (VARIABLE_HEADER) + (ArrayLength (VariableName) + DataSize) > MAX_VARIABLE_SIZE) { + return EFI_INVALID_PARAMETER; + } + // + // Make sure if runtime bit is set, boot service bit is set also + // + else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS + ) { + return EFI_INVALID_PARAMETER; + } + // + // Runtime but Attribute is not Runtime + // + else if (EfiAtRuntime () && Attributes && !(Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) { + return EFI_INVALID_PARAMETER; + } + // + // Cannot set volatile variable in Runtime + // + else if (EfiAtRuntime () && Attributes && !(Attributes & EFI_VARIABLE_NON_VOLATILE)) { + return EFI_INVALID_PARAMETER; + } + // + // Setting a data variable with no access, or zero DataSize attributes + // specified causes it to be deleted. + // + else if (DataSize == 0 || Attributes == 0) { + if (!EFI_ERROR (Status)) { + Variable.CurrPtr->State &= VAR_DELETED; + return EFI_SUCCESS; + } + + return EFI_NOT_FOUND; + } else { + if (!EFI_ERROR (Status)) { + // + // If the variable is marked valid and the same data has been passed in + // then return to the caller immediately. + // + if (Variable.CurrPtr->DataSize == DataSize && + !CompareMem (Data, GetVariableDataPtr (Variable.CurrPtr), DataSize) + ) { + return EFI_SUCCESS; + } else if (Variable.CurrPtr->State == VAR_ADDED) { + // + // Mark the old variable as in delete transition + // + Variable.CurrPtr->State &= VAR_IN_DELETED_TRANSITION; + } + } + // + // Create a new variable and copy the data. + // + VarNameOffset = sizeof (VARIABLE_HEADER); + VarNameSize = ArrayLength (VariableName); + VarDataOffset = VarNameOffset + VarNameSize + GetPadSize (VarNameSize); + VarSize = VarDataOffset + DataSize + GetPadSize (DataSize); + + if (Attributes & EFI_VARIABLE_NON_VOLATILE) { + if ((UINT32) (VarSize +*NonVolatileOffset) > + ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->NonVolatileVariableBase)))->Size + ) { + return EFI_OUT_OF_RESOURCES; + } + + NextVariable = (VARIABLE_HEADER *) (UINT8 *) (*NonVolatileOffset + (UINTN) Global->NonVolatileVariableBase); + *NonVolatileOffset = *NonVolatileOffset + VarSize; + } else { + if (EfiAtRuntime ()) { + return EFI_INVALID_PARAMETER; + } + + if ((UINT32) (VarSize +*VolatileOffset) > + ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->VolatileVariableBase)))->Size + ) { + return EFI_OUT_OF_RESOURCES; + } + + NextVariable = (VARIABLE_HEADER *) (UINT8 *) (*VolatileOffset + (UINTN) Global->VolatileVariableBase); + *VolatileOffset = *VolatileOffset + VarSize; + } + + NextVariable->StartId = VARIABLE_DATA; + NextVariable->Attributes = Attributes; + NextVariable->State = VAR_ADDED; + NextVariable->Reserved = 0; + + // + // There will be pad bytes after Data, the NextVariable->NameSize and + // NextVariable->NameSize should not include pad size so that variable + // service can get actual size in GetVariable + // + NextVariable->NameSize = (UINT32)VarNameSize; + NextVariable->DataSize = (UINT32)DataSize; + + CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID)); + CopyMem ( + (UINT8 *) ((UINTN) NextVariable + VarNameOffset), + VariableName, + VarNameSize + ); + CopyMem ( + (UINT8 *) ((UINTN) NextVariable + VarDataOffset), + Data, + DataSize + ); + + // + // Mark the old variable as deleted + // + if (!EFI_ERROR (Status)) { + Variable.CurrPtr->State &= VAR_DELETED; + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +InitializeVariableStore ( + OUT EFI_PHYSICAL_ADDRESS *VariableBase, + OUT UINTN *LastVariableOffset + ) +/*++ + +Routine Description: + This function initializes variable store + +Arguments: + +Returns: + +--*/ +{ + VARIABLE_STORE_HEADER *VariableStore; + + // + // Allocate memory for volatile variable store + // + VariableStore = (VARIABLE_STORE_HEADER *) AllocateRuntimePool ( + VARIABLE_STORE_SIZE + ); + if (NULL == VariableStore) { + return EFI_OUT_OF_RESOURCES; + } + + SetMem (VariableStore, VARIABLE_STORE_SIZE, 0xff); + + // + // Variable Specific Data + // + *VariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStore; + *LastVariableOffset = sizeof (VARIABLE_STORE_HEADER); + + VariableStore->Signature = VARIABLE_STORE_SIGNATURE; + VariableStore->Size = VARIABLE_STORE_SIZE; + VariableStore->Format = VARIABLE_STORE_FORMATTED; + VariableStore->State = VARIABLE_STORE_HEALTHY; + VariableStore->Reserved = 0; + VariableStore->Reserved1 = 0; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +VariableCommonInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + This function does common initialization for variable services + +Arguments: + +Returns: + +--*/ +{ + EFI_STATUS Status; + + // + // Allocate memory for mVariableModuleGlobal + // + mVariableModuleGlobal = (ESAL_VARIABLE_GLOBAL *) AllocateRuntimePool ( + sizeof (ESAL_VARIABLE_GLOBAL) + ); + if (NULL == mVariableModuleGlobal) { + return EFI_OUT_OF_RESOURCES; + } + // + // Intialize volatile variable store + // + Status = InitializeVariableStore ( + &mVariableModuleGlobal->VariableBase[Physical].VolatileVariableBase, + &mVariableModuleGlobal->VolatileLastVariableOffset + ); + + if (EFI_ERROR (Status)) { + return Status; + } + // + // Intialize non volatile variable store + // + Status = InitializeVariableStore ( + &mVariableModuleGlobal->VariableBase[Physical].NonVolatileVariableBase, + &mVariableModuleGlobal->NonVolatileLastVariableOffset + ); + + return Status; +} diff --git a/EdkModulePkg/Universal/Variable/RuntimeDxe/Emu/EmuVariable.dxs b/EdkModulePkg/Universal/Variable/RuntimeDxe/Emu/EmuVariable.dxs new file mode 100644 index 0000000000..51c93d7657 --- /dev/null +++ b/EdkModulePkg/Universal/Variable/RuntimeDxe/Emu/EmuVariable.dxs @@ -0,0 +1,25 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + EmuVariable.dxs + +Abstract: + + Dependency expression source file. + +--*/ +#include "DxeDepex.h" + +DEPENDENCY_START + TRUE +DEPENDENCY_END \ No newline at end of file diff --git a/EdkModulePkg/Universal/Variable/RuntimeDxe/Emu/EmuVariable.mbd b/EdkModulePkg/Universal/Variable/RuntimeDxe/Emu/EmuVariable.mbd new file mode 100644 index 0000000000..4cc2c2085d --- /dev/null +++ b/EdkModulePkg/Universal/Variable/RuntimeDxe/Emu/EmuVariable.mbd @@ -0,0 +1,45 @@ + + + + + EmuVariable + CBD2E4D5-7068-4FF5-B866-9822B4AD8D60 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-23 16:05 + + + UefiBootServicesTableLib + BaseMemoryLib + BaseDebugLibReportStatusCode + UefiDriverEntryPoint + EdkDxeRuntimeDriverLib + DxeMemoryAllocationLib + BaseLib + DxeReportStatusCodeLib + + EdkDxeSalLib + + + + _ModuleEntryPoint + + diff --git a/EdkModulePkg/Universal/Variable/RuntimeDxe/Emu/EmuVariable.msa b/EdkModulePkg/Universal/Variable/RuntimeDxe/Emu/EmuVariable.msa new file mode 100644 index 0000000000..5a7a5f8447 --- /dev/null +++ b/EdkModulePkg/Universal/Variable/RuntimeDxe/Emu/EmuVariable.msa @@ -0,0 +1,73 @@ + + + + + EmuVariable + DXE_RUNTIME_DRIVER + RT_DRIVER + CBD2E4D5-7068-4FF5-B866-9822B4AD8D60 + 0 + Component description file for DiskIo module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-23 16:05 + + + BaseLib + BaseMemoryLib + MemoryAllocationLib + DebugLib + DxeRuntimeDriverLib + UefiDriverEntryPoint + EdkDxeSalLib + UefiBootServicesTableLib + + + EmuVariable.c + EmuVariable.dxs + + ..\Ia32\Ia32Variable.c + + + ..\x64\x64Variable.c + + + ..\Ipf\IpfVariable.c + + + + MdePkg + EdkModulePkg + + + VariableWrite + Variable + VariableWrite + Variable + ExtendedSalVariableServices + ExtendedSalBootService + + + + VariableServiceInitialize + + + diff --git a/EdkModulePkg/Universal/Variable/RuntimeDxe/Emu/build.xml b/EdkModulePkg/Universal/Variable/RuntimeDxe/Emu/build.xml new file mode 100644 index 0000000000..0035ab957b --- /dev/null +++ b/EdkModulePkg/Universal/Variable/RuntimeDxe/Emu/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Universal/Variable/RuntimeDxe/Ia32Variable.dxs b/EdkModulePkg/Universal/Variable/RuntimeDxe/Ia32Variable.dxs new file mode 100644 index 0000000000..821e27df4a --- /dev/null +++ b/EdkModulePkg/Universal/Variable/RuntimeDxe/Ia32Variable.dxs @@ -0,0 +1,28 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Ia32Variable.dxs + +Abstract: + + Dependency expression source file. + +--*/ +#include +#include + +DEPENDENCY_START + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL_GUID AND + EFI_ALTERNATE_FV_BLOCK_GUID AND + EFI_FTW_LITE_PROTOCOL_GUID +DEPENDENCY_END \ No newline at end of file diff --git a/EdkModulePkg/Universal/Variable/RuntimeDxe/InitVariable.c b/EdkModulePkg/Universal/Variable/RuntimeDxe/InitVariable.c new file mode 100644 index 0000000000..0ad86642ea --- /dev/null +++ b/EdkModulePkg/Universal/Variable/RuntimeDxe/InitVariable.c @@ -0,0 +1,185 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + InitVariable.c + +Abstract: + +Revision History + +--*/ + +#include "Variable.h" + +// +// Don't use module globals after the SetVirtualAddress map is signaled +// +extern ESAL_VARIABLE_GLOBAL *mVariableModuleGlobal; + +EFI_STATUS +EFIAPI +RuntimeServiceGetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID * VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, + OUT VOID *Data + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + return GetVariable ( + VariableName, + VendorGuid, + Attributes OPTIONAL, + DataSize, + Data, + &mVariableModuleGlobal->VariableBase[Physical], + mVariableModuleGlobal->FvbInstance + ); +} + +EFI_STATUS +EFIAPI +RuntimeServiceGetNextVariableName ( + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VendorGuid + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + return GetNextVariableName ( + VariableNameSize, + VariableName, + VendorGuid, + &mVariableModuleGlobal->VariableBase[Physical], + mVariableModuleGlobal->FvbInstance + ); +} + +EFI_STATUS +EFIAPI +RuntimeServiceSetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + return SetVariable ( + VariableName, + VendorGuid, + Attributes, + DataSize, + Data, + &mVariableModuleGlobal->VariableBase[Physical], + &mVariableModuleGlobal->VolatileLastVariableOffset, + &mVariableModuleGlobal->NonVolatileLastVariableOffset, + mVariableModuleGlobal->FvbInstance + ); +} + +VOID +EFIAPI +VariableClassAddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + EfiConvertPointer ( + 0x0, + (VOID **) &mVariableModuleGlobal->VariableBase[Physical].NonVolatileVariableBase + ); + EfiConvertPointer ( + 0x0, + (VOID **) &mVariableModuleGlobal->VariableBase[Physical].VolatileVariableBase + ); + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal); +} + +EFI_STATUS +EFIAPI +VariableServiceInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + EFI_HANDLE NewHandle; + EFI_STATUS Status; + + Status = VariableCommonInitialize (ImageHandle, SystemTable); + ASSERT_EFI_ERROR (Status); + + SystemTable->RuntimeServices->GetVariable = RuntimeServiceGetVariable; + SystemTable->RuntimeServices->GetNextVariableName = RuntimeServiceGetNextVariableName; + SystemTable->RuntimeServices->SetVariable = RuntimeServiceSetVariable; + + // + // Now install the Variable Runtime Architectural Protocol on a new handle + // + NewHandle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &NewHandle, + &gEfiVariableArchProtocolGuid, + NULL, + &gEfiVariableWriteArchProtocolGuid, + NULL, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Universal/Variable/RuntimeDxe/Ipf/InitVariable.c b/EdkModulePkg/Universal/Variable/RuntimeDxe/Ipf/InitVariable.c new file mode 100644 index 0000000000..061e6db73d --- /dev/null +++ b/EdkModulePkg/Universal/Variable/RuntimeDxe/Ipf/InitVariable.c @@ -0,0 +1,167 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + IpfVariable.c + +Abstract: + +Revision History + +--*/ + +#include "Variable.h" + +// +// Don't use module globals after the SetVirtualAddress map is signaled +// +extern ESAL_VARIABLE_GLOBAL *mVariableModuleGlobal; + +SAL_RETURN_REGS +EsalVariableCommonEntry ( + IN UINT64 FunctionId, + IN UINT64 Arg2, + IN UINT64 Arg3, + IN UINT64 Arg4, + IN UINT64 Arg5, + IN UINT64 Arg6, + IN UINT64 Arg7, + IN UINT64 Arg8, + IN SAL_EXTENDED_SAL_PROC ExtendedSalProc, + IN BOOLEAN VirtualMode, + IN ESAL_VARIABLE_GLOBAL *Global + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + SAL_RETURN_REGS ReturnVal; + + switch (FunctionId) { + case EsalGetVariable: + ReturnVal.Status = GetVariable ( + (CHAR16 *) Arg2, + (EFI_GUID *) Arg3, + (UINT32 *) Arg4, + (UINTN *) Arg5, + (VOID *) Arg6, + &Global->VariableBase[VirtualMode], + Global->FvbInstance + ); + return ReturnVal; + + case EsalGetNextVariableName: + ReturnVal.Status = GetNextVariableName ( + (UINTN *) Arg2, + (CHAR16 *) Arg3, + (EFI_GUID *) Arg4, + &Global->VariableBase[VirtualMode], + Global->FvbInstance + ); + return ReturnVal; + + case EsalSetVariable: + ReturnVal.Status = SetVariable ( + (CHAR16 *) Arg2, + (EFI_GUID *) Arg3, + (UINT32) Arg4, + (UINTN) Arg5, + (VOID *) Arg6, + &Global->VariableBase[VirtualMode], + (UINTN *) &Global->VolatileLastVariableOffset, + (UINTN *) &Global->NonVolatileLastVariableOffset, + Global->FvbInstance + ); + return ReturnVal; + + default: + ReturnVal.Status = EFI_SAL_INVALID_ARGUMENT; + return ReturnVal; + } +} + + +VOID +VariableClassAddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + CopyMem ( + &mVariableModuleGlobal->VariableBase[Virtual], + &mVariableModuleGlobal->VariableBase[Physical], + sizeof (VARIABLE_GLOBAL) + ); + + EfiConvertPointer ( + 0x0, + (VOID **) &mVariableModuleGlobal->VariableBase[Virtual].NonVolatileVariableBase + ); + EfiConvertPointer ( + 0x0, + (VOID **) &mVariableModuleGlobal->VariableBase[Virtual].VolatileVariableBase + ); + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal); +} + +EFI_STATUS +VariableServiceInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + EFI_STATUS Status; + + Status = VariableCommonInitialize (ImageHandle, SystemTable); + ASSERT_EFI_ERROR (Status); + + // + // Register All the Functions with Extended Sal. + // + RegisterEsalClass ( + &gEfiExtendedSalVariableServicesProtocolGuid, + mVariableModuleGlobal, + EsalVariableCommonEntry, + EsalGetVariable, + EsalVariableCommonEntry, + EsalGetNextVariableName, + EsalVariableCommonEntry, + EsalSetVariable, + NULL + ); + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Universal/Variable/RuntimeDxe/IpfVariable.dxs b/EdkModulePkg/Universal/Variable/RuntimeDxe/IpfVariable.dxs new file mode 100644 index 0000000000..a11dae680c --- /dev/null +++ b/EdkModulePkg/Universal/Variable/RuntimeDxe/IpfVariable.dxs @@ -0,0 +1,28 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + IpfVariable.dxs + +Abstract: + + Dependency expression source file. + +--*/ +#include +#include + +DEPENDENCY_START + EXTENDED_SAL_BOOT_SERVICE_PROTOCOL_GUID AND + EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID AND + EFI_FTW_LITE_PROTOCOL_GUID +DEPENDENCY_END \ No newline at end of file diff --git a/EdkModulePkg/Universal/Variable/RuntimeDxe/Variable.c b/EdkModulePkg/Universal/Variable/RuntimeDxe/Variable.c new file mode 100644 index 0000000000..0d91520d97 --- /dev/null +++ b/EdkModulePkg/Universal/Variable/RuntimeDxe/Variable.c @@ -0,0 +1,1311 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Variable.c + +Abstract: + +Revision History + +--*/ + +#include "Variable.h" +#include "reclaim.h" + +// +// Don't use module globals after the SetVirtualAddress map is signaled +// +ESAL_VARIABLE_GLOBAL *mVariableModuleGlobal; + +UINT32 +EFIAPI +ArrayLength ( + IN CHAR16 *String + ) +/*++ + +Routine Description: + + Determine the length of null terminated char16 array. + +Arguments: + + String Null-terminated CHAR16 array pointer. + +Returns: + + UINT32 Number of bytes in the string, including the double NULL at the end; + +--*/ +{ + UINT32 Count; + + if (NULL == String) { + return 0; + } + + Count = 0; + + while (0 != String[Count]) { + Count++; + } + + return (Count * 2) + 2; +} + +BOOLEAN +EFIAPI +IsValidVariableHeader ( + IN VARIABLE_HEADER *Variable + ) +/*++ + +Routine Description: + + This code checks if variable header is valid or not. + +Arguments: + Variable Pointer to the Variable Header. + +Returns: + TRUE Variable header is valid. + FALSE Variable header is not valid. + +--*/ +{ + if (Variable == NULL || + Variable->StartId != VARIABLE_DATA || + (sizeof (VARIABLE_HEADER) + Variable->NameSize + Variable->DataSize) > MAX_VARIABLE_SIZE + ) { + return FALSE; + } + + return TRUE; +} + +EFI_STATUS +EFIAPI +UpdateVariableStore ( + IN VARIABLE_GLOBAL *Global, + IN BOOLEAN Volatile, + IN BOOLEAN SetByIndex, + IN UINTN Instance, + IN UINTN DataPtrIndex, + IN UINT32 DataSize, + IN UINT8 *Buffer + ) +/*++ + +Routine Description: + + This function writes data to the FWH at the correct LBA even if the LBAs + are fragmented. + +Arguments: + + Global Pointer to VARAIBLE_GLOBAL structure + Volatile If the Variable is Volatile or Non-Volatile + SetByIndex TRUE: Target pointer is given as index + FALSE: Target pointer is absolute + Instance Instance of FV Block services + DataPtrIndex Pointer to the Data from the end of VARIABLE_STORE_HEADER + structure + DataSize Size of data to be written. + Buffer Pointer to the buffer from which data is written + +Returns: + + EFI STATUS + +--*/ +{ + EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry; + UINTN BlockIndex2; + UINTN LinearOffset; + UINTN CurrWriteSize; + UINTN CurrWritePtr; + UINT8 *CurrBuffer; + EFI_LBA LbaNumber; + UINTN Size; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + VARIABLE_STORE_HEADER *VolatileBase; + EFI_PHYSICAL_ADDRESS FvVolHdr; + EFI_PHYSICAL_ADDRESS DataPtr; + EFI_STATUS Status; + + FwVolHeader = NULL; + DataPtr = DataPtrIndex; + + // + // Check if the Data is Volatile + // + if (!Volatile) { + EfiFvbGetPhysicalAddress (Instance, &FvVolHdr); + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr); + // + // Data Pointer should point to the actual Address where data is to be + // written + // + if (SetByIndex) { + DataPtr += Global->NonVolatileVariableBase; + } + + if ((DataPtr + DataSize) >= ((EFI_PHYSICAL_ADDRESS) (UINTN) ((UINT8 *) FwVolHeader + FwVolHeader->FvLength))) { + return EFI_INVALID_PARAMETER; + } + } else { + // + // Data Pointer should point to the actual Address where data is to be + // written + // + VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase); + if (SetByIndex) { + DataPtr += Global->VolatileVariableBase; + } + + if ((DataPtr + DataSize) >= ((UINTN) ((UINT8 *) VolatileBase + VolatileBase->Size))) { + return EFI_INVALID_PARAMETER; + } + } + // + // If Volatile Variable just do a simple mem copy. + // + if (Volatile) { + CopyMem ((UINT8 *) ((UINTN) DataPtr), Buffer, DataSize); + return EFI_SUCCESS; + } + // + // If we are here we are dealing with Non-Volatile Variables + // + LinearOffset = (UINTN) FwVolHeader; + CurrWritePtr = (UINTN) DataPtr; + CurrWriteSize = DataSize; + CurrBuffer = Buffer; + LbaNumber = 0; + + if (CurrWritePtr < LinearOffset) { + return EFI_INVALID_PARAMETER; + } + + for (PtrBlockMapEntry = FwVolHeader->FvBlockMap; 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->BlockLength)) { + if ((CurrWritePtr + CurrWriteSize) <= (LinearOffset + PtrBlockMapEntry->BlockLength)) { + Status = EfiFvbWriteBlock ( + Instance, + LbaNumber, + (UINTN) (CurrWritePtr - LinearOffset), + &CurrWriteSize, + CurrBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + } else { + Size = (UINT32) (LinearOffset + PtrBlockMapEntry->BlockLength - CurrWritePtr); + Status = EfiFvbWriteBlock ( + Instance, + LbaNumber, + (UINTN) (CurrWritePtr - LinearOffset), + &Size, + CurrBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + CurrWritePtr = LinearOffset + PtrBlockMapEntry->BlockLength; + CurrBuffer = CurrBuffer + Size; + CurrWriteSize = CurrWriteSize - Size; + } + } + + LinearOffset += PtrBlockMapEntry->BlockLength; + LbaNumber++; + } + } + + return EFI_SUCCESS; +} + +VARIABLE_STORE_STATUS +EFIAPI +GetVariableStoreStatus ( + IN VARIABLE_STORE_HEADER *VarStoreHeader + ) +/*++ + +Routine Description: + + This code gets the current status of Variable Store. + +Arguments: + + VarStoreHeader Pointer to the Variable Store Header. + +Returns: + + EfiRaw Variable store status is raw + EfiValid Variable store status is valid + EfiInvalid Variable store status is invalid + +--*/ +{ + if (VarStoreHeader->Signature == VARIABLE_STORE_SIGNATURE && + VarStoreHeader->Format == VARIABLE_STORE_FORMATTED && + VarStoreHeader->State == VARIABLE_STORE_HEALTHY + ) { + + return EfiValid; + } else if (VarStoreHeader->Signature == 0xffffffff && + VarStoreHeader->Size == 0xffffffff && + VarStoreHeader->Format == 0xff && + VarStoreHeader->State == 0xff + ) { + + return EfiRaw; + } else { + return EfiInvalid; + } +} + +UINT8 * +EFIAPI +GetVariableDataPtr ( + IN VARIABLE_HEADER *Variable + ) +/*++ + +Routine Description: + + This code gets the pointer to the variable data. + +Arguments: + + Variable Pointer to the Variable Header. + +Returns: + + UINT8* Pointer to Variable Data + +--*/ +{ + // + // Be careful about pad size for alignment + // + return (UINT8 *) ((UINTN) GET_VARIABLE_NAME_PTR (Variable) + Variable->NameSize + GET_PAD_SIZE (Variable->NameSize)); +} + +VARIABLE_HEADER * +EFIAPI +GetNextVariablePtr ( + IN VARIABLE_HEADER *Variable + ) +/*++ + +Routine Description: + + This code gets the pointer to the next variable header. + +Arguments: + + Variable Pointer to the Variable Header. + +Returns: + + VARIABLE_HEADER* Pointer to next variable header. + +--*/ +{ + if (!IsValidVariableHeader (Variable)) { + return NULL; + } + // + // Be careful about pad size for alignment + // + return (VARIABLE_HEADER *) ((UINTN) GetVariableDataPtr (Variable) + Variable->DataSize + GET_PAD_SIZE (Variable->DataSize)); +} + +VARIABLE_HEADER * +EFIAPI +GetEndPointer ( + IN VARIABLE_STORE_HEADER *VarStoreHeader + ) +/*++ + +Routine Description: + + This code gets the pointer to the last variable memory pointer byte + +Arguments: + + VarStoreHeader Pointer to the Variable Store Header. + +Returns: + + VARIABLE_HEADER* Pointer to last unavailable Variable Header + +--*/ +{ + // + // The end of variable store + // + return (VARIABLE_HEADER *) ((UINTN) VarStoreHeader + VarStoreHeader->Size); +} + +EFI_STATUS +EFIAPI +Reclaim ( + IN EFI_PHYSICAL_ADDRESS VariableBase, + OUT UINTN *LastVariableOffset, + IN BOOLEAN IsVolatile + ) +/*++ + +Routine Description: + + Variable store garbage collection and reclaim operation + +Arguments: + + VariableBase Base address of variable store + LastVariableOffset Offset of last variable + IsVolatile The variable store is volatile or not, + if it is non-volatile, need FTW + +Returns: + + EFI STATUS + +--*/ +{ + VARIABLE_HEADER *Variable; + VARIABLE_HEADER *NextVariable; + VARIABLE_STORE_HEADER *VariableStoreHeader; + UINT8 *ValidBuffer; + UINTN ValidBufferSize; + UINTN VariableSize; + UINT8 *CurrPtr; + EFI_STATUS Status; + + VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase); + + // + // Start Pointers for the variable. + // + Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1); + + ValidBufferSize = sizeof (VARIABLE_STORE_HEADER); + + while (IsValidVariableHeader (Variable)) { + NextVariable = GetNextVariablePtr (Variable); + if (Variable->State == VAR_ADDED) { + VariableSize = (UINTN) NextVariable - (UINTN) Variable; + ValidBufferSize += VariableSize; + } + + Variable = NextVariable; + } + + Status = gBS->AllocatePool ( + EfiBootServicesData, + ValidBufferSize, + (VOID **) &ValidBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + SetMem (ValidBuffer, ValidBufferSize, 0xff); + + CurrPtr = ValidBuffer; + + // + // Copy variable store header + // + CopyMem (CurrPtr, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER)); + CurrPtr += sizeof (VARIABLE_STORE_HEADER); + + // + // Start Pointers for the variable. + // + Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1); + + while (IsValidVariableHeader (Variable)) { + NextVariable = GetNextVariablePtr (Variable); + if (Variable->State == VAR_ADDED) { + VariableSize = (UINTN) NextVariable - (UINTN) Variable; + CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize); + CurrPtr += VariableSize; + } + + Variable = NextVariable; + } + + if (IsVolatile) { + // + // If volatile variable store, just copy valid buffer + // + SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader->Size, 0xff); + CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, ValidBufferSize); + *LastVariableOffset = ValidBufferSize; + Status = EFI_SUCCESS; + } else { + // + // If non-volatile variable store, perform FTW here. + // + Status = FtwVariableSpace ( + VariableBase, + ValidBuffer, + ValidBufferSize + ); + if (!EFI_ERROR (Status)) { + *LastVariableOffset = ValidBufferSize; + } + } + + gBS->FreePool (ValidBuffer); + + if (EFI_ERROR (Status)) { + *LastVariableOffset = 0; + } + + return Status; +} + +EFI_STATUS +EFIAPI +FindVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT VARIABLE_POINTER_TRACK *PtrTrack, + IN VARIABLE_GLOBAL *Global + ) +/*++ + +Routine Description: + + This code finds variable in storage blocks (Volatile or Non-Volatile) + +Arguments: + + VariableName Name of the variable to be found + VendorGuid Vendor GUID to be found. + PtrTrack Variable Track Pointer structure that contains + Variable Information. + Contains the pointer of Variable header. + Global VARIABLE_GLOBAL pointer + +Returns: + + EFI STATUS + +--*/ +{ + VARIABLE_HEADER *Variable[2]; + VARIABLE_STORE_HEADER *VariableStoreHeader[2]; + UINTN Index; + + // + // 0: Non-Volatile, 1: Volatile + // + VariableStoreHeader[0] = (VARIABLE_STORE_HEADER *) ((UINTN) Global->NonVolatileVariableBase); + VariableStoreHeader[1] = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase); + + // + // Start Pointers for the variable. + // Actual Data Pointer where data can be written. + // + Variable[0] = (VARIABLE_HEADER *) (VariableStoreHeader[0] + 1); + Variable[1] = (VARIABLE_HEADER *) (VariableStoreHeader[1] + 1); + + if (VariableName[0] != 0 && VendorGuid == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Find the variable by walk through non-volatile and volatile variable store + // + for (Index = 0; Index < 2; Index++) { + PtrTrack->StartPtr = (VARIABLE_HEADER *) (VariableStoreHeader[Index] + 1); + PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index]); + + while (IsValidVariableHeader (Variable[Index]) && (Variable[Index] <= GetEndPointer (VariableStoreHeader[Index]))) { + if (Variable[Index]->State == VAR_ADDED) { + if (!(EfiAtRuntime () && !(Variable[Index]->Attributes & EFI_VARIABLE_RUNTIME_ACCESS))) { + if (VariableName[0] == 0) { + PtrTrack->CurrPtr = Variable[Index]; + PtrTrack->Volatile = (BOOLEAN) Index; + return EFI_SUCCESS; + } else { + if (CompareGuid (VendorGuid, &Variable[Index]->VendorGuid)) { + if (!CompareMem (VariableName, GET_VARIABLE_NAME_PTR (Variable[Index]), ArrayLength (VariableName))) { + PtrTrack->CurrPtr = Variable[Index]; + PtrTrack->Volatile = (BOOLEAN) Index; + return EFI_SUCCESS; + } + } + } + } + } + + Variable[Index] = GetNextVariablePtr (Variable[Index]); + } + // + // While (...) + // + } + // + // for (...) + // + PtrTrack->CurrPtr = NULL; + return EFI_NOT_FOUND; +} + +EFI_STATUS +EFIAPI +GetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID * VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, + OUT VOID *Data, + IN VARIABLE_GLOBAL * Global, + IN UINT32 Instance + ) +/*++ + +Routine Description: + + This code finds variable in storage blocks (Volatile or Non-Volatile) + +Arguments: + + VariableName Name of Variable to be found + VendorGuid Variable vendor GUID + Attributes OPTIONAL Attribute value of the variable found + DataSize Size of Data found. If size is less than the + data, this value contains the required size. + Data Data pointer + Global Pointer to VARIABLE_GLOBAL structure + Instance Instance of the Firmware Volume. + +Returns: + + EFI STATUS + +--*/ +{ + VARIABLE_POINTER_TRACK Variable; + UINTN VarDataSize; + EFI_STATUS Status; + + if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Find existing variable + // + Status = FindVariable (VariableName, VendorGuid, &Variable, Global); + + if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) { + return Status; + } + // + // Get data size + // + VarDataSize = Variable.CurrPtr->DataSize; + if (*DataSize >= VarDataSize) { + if (Data == NULL) { + return EFI_INVALID_PARAMETER; + } + + CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize); + if (Attributes != NULL) { + *Attributes = Variable.CurrPtr->Attributes; + } + + *DataSize = VarDataSize; + return EFI_SUCCESS; + } else { + *DataSize = VarDataSize; + return EFI_BUFFER_TOO_SMALL; + } +} + +EFI_STATUS +EFIAPI +GetNextVariableName ( + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VendorGuid, + IN VARIABLE_GLOBAL *Global, + IN UINT32 Instance + ) +/*++ + +Routine Description: + + This code Finds the Next available variable + +Arguments: + + VariableNameSize Size of the variable + VariableName Pointer to variable name + VendorGuid Variable Vendor Guid + Global VARIABLE_GLOBAL structure pointer. + Instance FV instance + +Returns: + + EFI STATUS + +--*/ +{ + VARIABLE_POINTER_TRACK Variable; + UINTN VarNameSize; + EFI_STATUS Status; + + if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) { + return EFI_INVALID_PARAMETER; + } + + Status = FindVariable (VariableName, VendorGuid, &Variable, Global); + + if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) { + return Status; + } + + if (VariableName[0] != 0) { + // + // If variable name is not NULL, get next variable + // + Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); + } + + while (TRUE) { + // + // If both volatile and non-volatile variable store are parsed, + // return not found + // + if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL) { + Variable.Volatile = (BOOLEAN) (Variable.Volatile ^ ((BOOLEAN) 0x1)); + if (Variable.Volatile) { + Variable.StartPtr = (VARIABLE_HEADER *) ((UINTN) (Global->VolatileVariableBase + sizeof (VARIABLE_STORE_HEADER))); + Variable.EndPtr = (VARIABLE_HEADER *) GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase)); + } else { + return EFI_NOT_FOUND; + } + + Variable.CurrPtr = Variable.StartPtr; + if (!IsValidVariableHeader (Variable.CurrPtr)) { + continue; + } + } + // + // Variable is found + // + if (IsValidVariableHeader (Variable.CurrPtr) && Variable.CurrPtr->State == VAR_ADDED) { + if (!(EfiAtRuntime () && !(Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS))) { + VarNameSize = Variable.CurrPtr->NameSize; + if (VarNameSize <= *VariableNameSize) { + CopyMem ( + VariableName, + GET_VARIABLE_NAME_PTR (Variable.CurrPtr), + VarNameSize + ); + CopyMem ( + VendorGuid, + &Variable.CurrPtr->VendorGuid, + sizeof (EFI_GUID) + ); + Status = EFI_SUCCESS; + } else { + Status = EFI_BUFFER_TOO_SMALL; + } + + *VariableNameSize = VarNameSize; + return Status; + } + } + + Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); + } + + return EFI_NOT_FOUND; +} + +EFI_STATUS +EFIAPI +SetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data, + IN VARIABLE_GLOBAL *Global, + IN UINTN *VolatileOffset, + IN UINTN *NonVolatileOffset, + IN UINT32 Instance + ) +/*++ + +Routine Description: + + This code sets variable in storage blocks (Volatile or Non-Volatile) + +Arguments: + + VariableName Name of Variable to be found + VendorGuid Variable vendor GUID + Attributes Attribute value of the variable found + DataSize Size of Data found. If size is less than the + data, this value contains the required size. + Data Data pointer + Global Pointer to VARIABLE_GLOBAL structure + VolatileOffset The offset of last volatile variable + NonVolatileOffset The offset of last non-volatile variable + Instance Instance of the Firmware Volume. + +Returns: + + EFI STATUS + EFI_INVALID_PARAMETER - Invalid parameter + EFI_SUCCESS - Set successfully + EFI_OUT_OF_RESOURCES - Resource not enough to set variable + EFI_NOT_FOUND - Not found + +--*/ +{ + VARIABLE_POINTER_TRACK Variable; + EFI_STATUS Status; + VARIABLE_HEADER *NextVariable; + UINTN VarNameSize; + UINTN VarNameOffset; + UINTN VarDataOffset; + UINTN VarSize; + UINT8 State; + BOOLEAN Reclaimed; + + Reclaimed = FALSE; + + if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) { + return EFI_INVALID_PARAMETER; + } + + Status = FindVariable (VariableName, VendorGuid, &Variable, Global); + + if (Status == EFI_INVALID_PARAMETER) { + return Status; + } + // + // The size of the VariableName, including the Unicode Null in bytes plus + // the DataSize is limited to maximum size of MAX_VARIABLE_SIZE (1024) bytes. + // + else if (sizeof (VARIABLE_HEADER) + ArrayLength (VariableName) + DataSize > MAX_VARIABLE_SIZE) { + return EFI_INVALID_PARAMETER; + } + // + // Make sure if runtime bit is set, boot service bit is set also + // + else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS + ) { + return EFI_INVALID_PARAMETER; + } + // + // Runtime but Attribute is not Runtime + // + else if (EfiAtRuntime () && Attributes && !(Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) { + return EFI_INVALID_PARAMETER; + } + // + // Cannot set volatile variable in Runtime + // + else if (EfiAtRuntime () && Attributes && !(Attributes & EFI_VARIABLE_NON_VOLATILE)) { + return EFI_INVALID_PARAMETER; + } + // + // Setting a data variable with no access, or zero DataSize attributes + // specified causes it to be deleted. + // + else if (DataSize == 0 || Attributes == 0) { + if (!EFI_ERROR (Status)) { + State = Variable.CurrPtr->State; + State &= VAR_DELETED; + + Status = UpdateVariableStore ( + Global, + Variable.Volatile, + FALSE, + Instance, + (UINTN) &Variable.CurrPtr->State, + sizeof (UINT8), + &State + ); + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; + } + + return EFI_NOT_FOUND; + } else { + if (!EFI_ERROR (Status)) { + // + // If the variable is marked valid and the same data has been passed in + // then return to the caller immediately. + // + if (Variable.CurrPtr->DataSize == DataSize && + !CompareMem (Data, GetVariableDataPtr (Variable.CurrPtr), DataSize) + ) { + return EFI_SUCCESS; + } else if (Variable.CurrPtr->State == VAR_ADDED) { + // + // Mark the old variable as in delete transition + // + State = Variable.CurrPtr->State; + State &= VAR_IN_DELETED_TRANSITION; + + Status = UpdateVariableStore ( + Global, + Variable.Volatile, + FALSE, + Instance, + (UINTN) &Variable.CurrPtr->State, + sizeof (UINT8), + &State + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + } + // + // Create a new variable and copy the data. + // + // Tricky part: Use scratch data area at the end of volatile variable store + // as a temporary storage. + // + NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase)); + + SetMem (NextVariable, SCRATCH_SIZE, 0xff); + + NextVariable->StartId = VARIABLE_DATA; + NextVariable->Attributes = Attributes; + // + // NextVariable->State = VAR_ADDED; + // + NextVariable->Reserved = 0; + VarNameOffset = sizeof (VARIABLE_HEADER); + VarNameSize = ArrayLength (VariableName); + CopyMem ( + (UINT8 *) ((UINTN) NextVariable + VarNameOffset), + VariableName, + VarNameSize + ); + VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize); + CopyMem ( + (UINT8 *) ((UINTN) NextVariable + VarDataOffset), + Data, + DataSize + ); + CopyMem (&NextVariable->VendorGuid, 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 + // + NextVariable->NameSize = (UINT32)VarNameSize; + NextVariable->DataSize = (UINT32)DataSize; + + // + // 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) { + if ((UINT32) (VarSize +*NonVolatileOffset) > + ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->NonVolatileVariableBase)))->Size + ) { + if (EfiAtRuntime ()) { + return EFI_OUT_OF_RESOURCES; + } + // + // Perform garbage collection & reclaim operation + // + Status = Reclaim (Global->NonVolatileVariableBase, NonVolatileOffset, FALSE); + if (EFI_ERROR (Status)) { + return Status; + } + // + // If still no enough space, return out of resources + // + if ((UINT32) (VarSize +*NonVolatileOffset) > + ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->NonVolatileVariableBase)))->Size + ) { + return EFI_OUT_OF_RESOURCES; + } + + Reclaimed = TRUE; + } + // + // Three steps + // 1. Write variable header + // 2. Write variable data + // 3. Set variable state to valid + // + // + // Step 1: + // + Status = UpdateVariableStore ( + Global, + FALSE, + TRUE, + Instance, + *NonVolatileOffset, + sizeof (VARIABLE_HEADER), + (UINT8 *) NextVariable + ); + + if (EFI_ERROR (Status)) { + return Status; + } + // + // Step 2: + // + Status = UpdateVariableStore ( + Global, + FALSE, + TRUE, + Instance, + *NonVolatileOffset + sizeof (VARIABLE_HEADER), + (UINT32) VarSize - sizeof (VARIABLE_HEADER), + (UINT8 *) NextVariable + sizeof (VARIABLE_HEADER) + ); + + if (EFI_ERROR (Status)) { + return Status; + } + // + // Step 3: + // + NextVariable->State = VAR_ADDED; + Status = UpdateVariableStore ( + Global, + FALSE, + TRUE, + Instance, + *NonVolatileOffset, + sizeof (VARIABLE_HEADER), + (UINT8 *) NextVariable + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + *NonVolatileOffset = *NonVolatileOffset + VarSize; + + } else { + if (EfiAtRuntime ()) { + return EFI_INVALID_PARAMETER; + } + + if ((UINT32) (VarSize +*VolatileOffset) > + ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->VolatileVariableBase)))->Size + ) { + // + // Perform garbage collection & reclaim operation + // + Status = Reclaim (Global->VolatileVariableBase, VolatileOffset, TRUE); + if (EFI_ERROR (Status)) { + return Status; + } + // + // If still no enough space, return out of resources + // + if ((UINT32) (VarSize +*VolatileOffset) > + ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->VolatileVariableBase)))->Size + ) { + return EFI_OUT_OF_RESOURCES; + } + + Reclaimed = TRUE; + } + + NextVariable->State = VAR_ADDED; + Status = UpdateVariableStore ( + Global, + TRUE, + TRUE, + Instance, + *VolatileOffset, + (UINT32) VarSize, + (UINT8 *) NextVariable + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + *VolatileOffset = *VolatileOffset + VarSize; + } + // + // Mark the old variable as deleted + // + if (!Reclaimed && !EFI_ERROR (Status) && Variable.CurrPtr != NULL) { + State = Variable.CurrPtr->State; + State &= VAR_DELETED; + + Status = UpdateVariableStore ( + Global, + Variable.Volatile, + FALSE, + Instance, + (UINTN) &Variable.CurrPtr->State, + sizeof (UINT8), + &State + ); + + if (EFI_ERROR (Status)) { + return Status; + } + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +VariableCommonInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + This function does common initialization for variable services + +Arguments: + + ImageHandle - The firmware allocated handle for the EFI image. + SystemTable - A pointer to the EFI System Table. + +Returns: + + Status code. + + EFI_NOT_FOUND - Variable store area not found. + EFI_UNSUPPORTED - Currently only one non-volatile variable store is supported. + EFI_SUCCESS - Variable services successfully initialized. + +--*/ +{ + EFI_STATUS Status; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + CHAR8 *CurrPtr; + VARIABLE_STORE_HEADER *VolatileVariableStore; + VARIABLE_STORE_HEADER *VariableStoreHeader; + VARIABLE_HEADER *NextVariable; + UINT32 Instance; + EFI_PHYSICAL_ADDRESS FvVolHdr; + + EFI_FLASH_MAP_ENTRY_DATA *FlashMapEntryData; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor; + EFI_FLASH_SUBAREA_ENTRY VariableStoreEntry; + UINT64 BaseAddress; + UINT64 Length; + UINTN Index; + UINT8 Data; + EFI_PEI_HOB_POINTERS GuidHob; + + Status = gBS->AllocatePool ( + EfiRuntimeServicesData, + sizeof (ESAL_VARIABLE_GLOBAL), + (VOID **) &mVariableModuleGlobal + ); + + if (EFI_ERROR (Status)) { + return Status; + } + // + // Allocate memory for volatile variable store + // + Status = gBS->AllocatePool ( + EfiRuntimeServicesData, + VARIABLE_STORE_SIZE + SCRATCH_SIZE, + (VOID **) &VolatileVariableStore + ); + + if (EFI_ERROR (Status)) { + gBS->FreePool (mVariableModuleGlobal); + return Status; + } + + SetMem (VolatileVariableStore, VARIABLE_STORE_SIZE + SCRATCH_SIZE, 0xff); + + // + // Variable Specific Data + // + mVariableModuleGlobal->VariableBase[Physical].VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore; + mVariableModuleGlobal->VolatileLastVariableOffset = sizeof (VARIABLE_STORE_HEADER); + + VolatileVariableStore->Signature = VARIABLE_STORE_SIGNATURE; + VolatileVariableStore->Size = VARIABLE_STORE_SIZE; + VolatileVariableStore->Format = VARIABLE_STORE_FORMATTED; + VolatileVariableStore->State = VARIABLE_STORE_HEALTHY; + VolatileVariableStore->Reserved = 0; + VolatileVariableStore->Reserved1 = 0; + + // + // Get non volatile varaible store + // + + FlashMapEntryData = NULL; + + GuidHob.Raw = GetHobList (); + while (NULL != (GuidHob.Raw = GetNextGuidHob (&gEfiFlashMapHobGuid, GuidHob.Raw))) { + FlashMapEntryData = (EFI_FLASH_MAP_ENTRY_DATA *) GET_GUID_HOB_DATA (GuidHob.Guid); + + if (FlashMapEntryData->AreaType == EFI_FLASH_AREA_EFI_VARIABLES) { + break; + } + GuidHob.Raw = GET_NEXT_HOB (GuidHob); + } + + if (NULL == GuidHob.Raw || FlashMapEntryData == NULL) { + gBS->FreePool (mVariableModuleGlobal); + gBS->FreePool (VolatileVariableStore); + return EFI_NOT_FOUND; + } + + // + // Currently only one non-volatile variable store is supported + // + if (FlashMapEntryData->NumEntries != 1) { + gBS->FreePool (mVariableModuleGlobal); + gBS->FreePool (VolatileVariableStore); + return EFI_UNSUPPORTED; + } + + CopyMem (&VariableStoreEntry, &FlashMapEntryData->Entries[0], sizeof (VariableStoreEntry)); + + // + // Mark the variable storage region of the FLASH as RUNTIME + // + BaseAddress = VariableStoreEntry.Base & (~EFI_PAGE_MASK); + Length = VariableStoreEntry.Length + (VariableStoreEntry.Base - BaseAddress); + Length = (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK); + + Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor); + if (EFI_ERROR (Status)) { + gBS->FreePool (mVariableModuleGlobal); + gBS->FreePool (VolatileVariableStore); + return EFI_UNSUPPORTED; + } + + Status = gDS->SetMemorySpaceAttributes ( + BaseAddress, + Length, + GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (mVariableModuleGlobal); + gBS->FreePool (VolatileVariableStore); + return EFI_UNSUPPORTED; + } + // + // Get address of non volatile variable store base + // + mVariableModuleGlobal->VariableBase[Physical].NonVolatileVariableBase = VariableStoreEntry.Base; + + // + // Check Integrity + // + // + // Find the Correct Instance of the FV Block Service. + // + Instance = 0; + CurrPtr = (CHAR8 *) ((UINTN) mVariableModuleGlobal->VariableBase[Physical].NonVolatileVariableBase); + while (EfiFvbGetPhysicalAddress (Instance, &FvVolHdr) == EFI_SUCCESS) { + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr); + if (CurrPtr >= (CHAR8 *) FwVolHeader && CurrPtr < (((CHAR8 *) FwVolHeader) + FwVolHeader->FvLength)) { + mVariableModuleGlobal->FvbInstance = Instance; + break; + } + + Instance++; + } + + VariableStoreHeader = (VARIABLE_STORE_HEADER *) CurrPtr; + if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) { + if (~VariableStoreHeader->Size == 0) { + Status = UpdateVariableStore ( + &mVariableModuleGlobal->VariableBase[Physical], + FALSE, + FALSE, + mVariableModuleGlobal->FvbInstance, + (UINTN) &VariableStoreHeader->Size, + sizeof (UINT32), + (UINT8 *) &VariableStoreEntry.Length + ); + + if (EFI_ERROR (Status)) { + return Status; + } + } + + mVariableModuleGlobal->VariableBase[Physical].NonVolatileVariableBase = (EFI_PHYSICAL_ADDRESS) ((UINTN) CurrPtr); + // + // Parse non-volatile variable data and get last variable offset + // + NextVariable = (VARIABLE_HEADER *) (CurrPtr + sizeof (VARIABLE_STORE_HEADER)); + Status = EFI_SUCCESS; + + while (IsValidVariableHeader (NextVariable)) { + NextVariable = GetNextVariablePtr (NextVariable); + } + + mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) CurrPtr; + + // + // Check if the free area is really free. + // + for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreHeader->Size; Index++) { + Data = ((UINT8 *) (UINTN) mVariableModuleGlobal->VariableBase[Physical].NonVolatileVariableBase)[Index]; + if (Data != 0xff) { + // + // There must be something wrong in variable store, do reclaim operation. + // + Status = Reclaim ( + mVariableModuleGlobal->VariableBase[Physical].NonVolatileVariableBase, + &mVariableModuleGlobal->NonVolatileLastVariableOffset, + FALSE + ); + break; + } + } + } + + if (EFI_ERROR (Status)) { + gBS->FreePool (mVariableModuleGlobal); + gBS->FreePool (VolatileVariableStore); + } + + return Status; +} diff --git a/EdkModulePkg/Universal/Variable/RuntimeDxe/Variable.h b/EdkModulePkg/Universal/Variable/RuntimeDxe/Variable.h new file mode 100644 index 0000000000..d1fd5e271e --- /dev/null +++ b/EdkModulePkg/Universal/Variable/RuntimeDxe/Variable.h @@ -0,0 +1,143 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Variable.h + +Abstract: + +--*/ + +#ifndef _VARIABLE_H +#define _VARIABLE_H + +// +// Statements that include other header files +// + +// +// BugBug: We need relcate the head file. +// +#include + +#if defined (MDE_CPU_IPF) +#define ALIGNMENT 8 +#else +#define ALIGNMENT 1 +#endif + + +#define VARIABLE_STORE_SIZE (64 * 1024) +#define SCRATCH_SIZE (4 * 1024) + +// +// Define GET_PAD_SIZE to optimize compiler +// +#if ((ALIGNMENT == 0) || (ALIGNMENT == 1)) +#define GET_PAD_SIZE(a) (0) +#else +#define GET_PAD_SIZE(a) (((~a) + 1) & (ALIGNMENT - 1)) +#endif + +#define GET_VARIABLE_NAME_PTR(a) (CHAR16 *) ((UINTN) (a) + sizeof (VARIABLE_HEADER)) + +typedef enum { + Physical, + Virtual +} VARIABLE_POINTER_TYPE; + +typedef struct { + VARIABLE_HEADER *CurrPtr; + VARIABLE_HEADER *EndPtr; + VARIABLE_HEADER *StartPtr; + BOOLEAN Volatile; +} VARIABLE_POINTER_TRACK; + +typedef struct { + EFI_PHYSICAL_ADDRESS VolatileVariableBase; + EFI_PHYSICAL_ADDRESS NonVolatileVariableBase; +} VARIABLE_GLOBAL; + +typedef struct { + VARIABLE_GLOBAL VariableBase[2]; + UINTN VolatileLastVariableOffset; + UINTN NonVolatileLastVariableOffset; + UINT32 FvbInstance; +} ESAL_VARIABLE_GLOBAL; + +// +// Functions +// +EFI_STATUS +EFIAPI +VariableCommonInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +; + +EFI_STATUS +EFIAPI +VariableServiceInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +; + +VOID +EFIAPI +VariableClassAddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +; + +EFI_STATUS +EFIAPI +GetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID * VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, + OUT VOID *Data, + IN VARIABLE_GLOBAL * Global, + IN UINT32 Instance + ) +; + +EFI_STATUS +EFIAPI +GetNextVariableName ( + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VendorGuid, + IN VARIABLE_GLOBAL *Global, + IN UINT32 Instance + ) +; + +EFI_STATUS +EFIAPI +SetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data, + IN VARIABLE_GLOBAL *Global, + IN UINTN *VolatileOffset, + IN UINTN *NonVolatileOffset, + IN UINT32 Instance + ) +; + +#endif diff --git a/EdkModulePkg/Universal/Variable/RuntimeDxe/Variable.mbd b/EdkModulePkg/Universal/Variable/RuntimeDxe/Variable.mbd new file mode 100644 index 0000000000..6a5be9d885 --- /dev/null +++ b/EdkModulePkg/Universal/Variable/RuntimeDxe/Variable.mbd @@ -0,0 +1,51 @@ + + + + + Variable + CBD2E4D5-7068-4FF5-B462-9822B4AD8D60 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + + UefiBootServicesTableLib + BaseLib + BaseMemoryLib + UefiLib + UefiDriverEntryPoint + DxeReportStatusCodeLib + DxeServicesTableLib + BaseDebugLibNull + BasePrintLib + EdkDxeRuntimeDriverLib + DxeHobLib + DxeMemoryAllocationLib + EdkFvbServiceLib + + EdkDxeSalLib + + + + _ModuleEntryPoint + + diff --git a/EdkModulePkg/Universal/Variable/RuntimeDxe/Variable.msa b/EdkModulePkg/Universal/Variable/RuntimeDxe/Variable.msa new file mode 100644 index 0000000000..a4399bc0d2 --- /dev/null +++ b/EdkModulePkg/Universal/Variable/RuntimeDxe/Variable.msa @@ -0,0 +1,109 @@ + + + + + Variable + DXE_RUNTIME_DRIVER + RT_DRIVER + CBD2E4D5-7068-4FF5-B462-9822B4AD8D60 + 0 + Component description file for DiskIo module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + BaseLib + UefiLib + UefiDriverEntryPoint + DxeServicesTableLib + DxeRuntimeDriverLib + DebugLib + HobLib + BaseMemoryLib + EdkFvbServiceLib + EdkDxeSalLib + UefiBootServicesTableLib + + + Variable.c + Reclaim.c + + InitVariable.c + Ia32Variable.dxs + + + InitVariable.c + x64Variable.dxs + + + InitVariable.c + x64Variable.dxs + + + Ipf\InitVariable.c + IpfVariable.dxs + + + + MdePkg + EdkModulePkg + + + Variable + VariableWrite + FaultTolerantWriteLite + CpuIo + FvbExtension + FirmwareVolumeBlock + Variable + VariableWrite + FaultTolerantWriteLite + CpuIo + FvbExtension + FirmwareVolumeBlock + ExtendedSalBootService + ExtendedSalVariableServices + + + + FlashMapHob + + + Hob + + + SystemNvData + + + AlternateFvBlock + + + + + VariableServiceInitialize + + + VariableClassAddressChangeEvent + + + diff --git a/EdkModulePkg/Universal/Variable/RuntimeDxe/build.xml b/EdkModulePkg/Universal/Variable/RuntimeDxe/build.xml new file mode 100644 index 0000000000..4eba6a6933 --- /dev/null +++ b/EdkModulePkg/Universal/Variable/RuntimeDxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Universal/Variable/RuntimeDxe/reclaim.c b/EdkModulePkg/Universal/Variable/RuntimeDxe/reclaim.c new file mode 100644 index 0000000000..a4bcdd67ce --- /dev/null +++ b/EdkModulePkg/Universal/Variable/RuntimeDxe/reclaim.c @@ -0,0 +1,240 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + reclaim.c + +Abstract: + + Handles non-volatile variable store garbage collection, using FTW + (Fault Tolerant Write) protocol. + +Revision History + +--*/ + +#include "reclaim.h" +#include "Common/Variable.h" + +EFI_STATUS +GetFvbHandleByAddress ( + IN EFI_PHYSICAL_ADDRESS Address, + OUT EFI_HANDLE *FvbHandle + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN HandleCount; + UINTN Index; + EFI_PHYSICAL_ADDRESS FvbBaseAddress; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + + *FvbHandle = NULL; + // + // Locate all handles of Fvb protocol + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiFirmwareVolumeBlockProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + // + // Get the FVB to access variable store + // + for (Index = 0; Index < HandleCount; Index += 1) { + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiFirmwareVolumeBlockProtocolGuid, + (VOID **) &Fvb + ); + if (EFI_ERROR (Status)) { + Status = EFI_NOT_FOUND; + break; + } + // + // Compare the address and select the right one + // + Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress); + if (EFI_ERROR (Status)) { + continue; + } + + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress); + if ((Address >= FvbBaseAddress) && (Address <= (FvbBaseAddress + FwVolHeader->FvLength))) { + *FvbHandle = HandleBuffer[Index]; + Status = EFI_SUCCESS; + break; + } + } + + gBS->FreePool (HandleBuffer); + return Status; +} + +EFI_STATUS +GetLbaAndOffsetByAddress ( + IN EFI_PHYSICAL_ADDRESS Address, + OUT EFI_LBA *Lba, + OUT UINTN *Offset + ) +{ + EFI_STATUS Status; + EFI_HANDLE FvbHandle; + EFI_PHYSICAL_ADDRESS FvbBaseAddress; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_FV_BLOCK_MAP_ENTRY *FvbMapEntry; + UINT32 LbaIndex; + + *Lba = (EFI_LBA) (-1); + *Offset = 0; + + // + // Get the proper FVB + // + Status = GetFvbHandleByAddress (Address, &FvbHandle); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->HandleProtocol ( + FvbHandle, + &gEfiFirmwareVolumeBlockProtocolGuid, + (VOID **) &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 ((Address >= FvbBaseAddress) && (Address <= (FvbBaseAddress + FwVolHeader->FvLength))) { + if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) { + // + // BUGBUG: Assume one FV has one type of BlockLength + // + FvbMapEntry = &FwVolHeader->FvBlockMap[0]; + for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) { + if (Address < (FvbBaseAddress + FvbMapEntry->BlockLength * LbaIndex)) { + // + // Found the (Lba, Offset) + // + *Lba = LbaIndex - 1; + *Offset = (UINTN) (Address - (FvbBaseAddress + FvbMapEntry->BlockLength * (LbaIndex - 1))); + return EFI_SUCCESS; + } + } + } + } + + return EFI_ABORTED; +} + +EFI_STATUS +FtwVariableSpace ( + IN EFI_PHYSICAL_ADDRESS VariableBase, + IN UINT8 *Buffer, + IN UINTN BufferSize + ) +/*++ + +Routine Description: + Write a buffer to Variable space, in the working block. + +Arguments: + FvbHandle - Indicates a handle to FVB to access variable store + Buffer - Point to the input buffer + BufferSize - The number of bytes of the input Buffer + +Returns: + EFI_SUCCESS - The function completed successfully + EFI_ABORTED - The function could not complete successfully + EFI_NOT_FOUND - Locate FVB protocol by handle fails + +--*/ +{ + EFI_STATUS Status; + EFI_HANDLE FvbHandle; + EFI_FTW_LITE_PROTOCOL *FtwLiteProtocol; + EFI_LBA VarLba; + UINTN VarOffset; + UINT8 *FtwBuffer; + UINTN FtwBufferSize; + + // + // Locate fault tolerant write protocol + // + Status = gBS->LocateProtocol ( + &gEfiFaultTolerantWriteLiteProtocolGuid, + NULL, + (VOID **) &FtwLiteProtocol + ); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + // + // Locate Fvb handle by address + // + Status = GetFvbHandleByAddress (VariableBase, &FvbHandle); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Get LBA and Offset by address + // + Status = GetLbaAndOffsetByAddress (VariableBase, &VarLba, &VarOffset); + if (EFI_ERROR (Status)) { + return EFI_ABORTED; + } + // + // Prepare for the variable data + // + FtwBufferSize = ((VARIABLE_STORE_HEADER *) ((UINTN) VariableBase))->Size; + Status = gBS->AllocatePool (EfiRuntimeServicesData, FtwBufferSize, (VOID **) &FtwBuffer); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + SetMem (FtwBuffer, FtwBufferSize, (UINT8) 0xff); + CopyMem (FtwBuffer, Buffer, BufferSize); + + // + // FTW write record + // + Status = FtwLiteProtocol->Write ( + FtwLiteProtocol, + FvbHandle, + VarLba, // LBA + VarOffset, // Offset + &FtwBufferSize, // NumBytes, + FtwBuffer + ); + + gBS->FreePool (FtwBuffer); + return Status; +} diff --git a/EdkModulePkg/Universal/Variable/RuntimeDxe/reclaim.h b/EdkModulePkg/Universal/Variable/RuntimeDxe/reclaim.h new file mode 100644 index 0000000000..7bc1020ba3 --- /dev/null +++ b/EdkModulePkg/Universal/Variable/RuntimeDxe/reclaim.h @@ -0,0 +1,45 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + reclaim.h + +Abstract: + + Definitions for non-volatile variable store garbage collection + +Revision History + +--*/ + +#ifndef _VAR_RECLAIM_H +#define _VAR_RECLAIM_H + +// +// Functions +// +EFI_STATUS +GetFvbHandleByAddress ( + IN EFI_PHYSICAL_ADDRESS VariableStoreBase, + OUT EFI_HANDLE *FvbHandle + ) +; + +EFI_STATUS +FtwVariableSpace ( + IN EFI_PHYSICAL_ADDRESS VariableBaseAddress, + IN UINT8 *Buffer, + IN UINTN BufferSize + ) +; + +#endif diff --git a/EdkModulePkg/Universal/Variable/RuntimeDxe/x64Variable.dxs b/EdkModulePkg/Universal/Variable/RuntimeDxe/x64Variable.dxs new file mode 100644 index 0000000000..c9f2f694e7 --- /dev/null +++ b/EdkModulePkg/Universal/Variable/RuntimeDxe/x64Variable.dxs @@ -0,0 +1,26 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + x64Variable.dxs + +Abstract: + + Dependency expression source file. + +--*/ +#include +#include "DxeDepex.h" + +DEPENDENCY_START + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL_GUID AND EFI_ALTERNATE_FV_BLOCK_GUID +DEPENDENCY_END \ No newline at end of file diff --git a/EdkModulePkg/Universal/WatchdogTimer/Dxe/WatchDogTimer.c b/EdkModulePkg/Universal/WatchdogTimer/Dxe/WatchDogTimer.c new file mode 100644 index 0000000000..b54b25ee83 --- /dev/null +++ b/EdkModulePkg/Universal/WatchdogTimer/Dxe/WatchDogTimer.c @@ -0,0 +1,310 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + WatchDogTimer.c + +Abstract: + + Generic watchdog timer implemenetation using EFI APIs + +Revision History + +--*/ + +#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; + +// +// Worker Functions +// +VOID +EFIAPI +WatchdogTimerDriverExpires ( + IN EFI_EVENT Timer, + IN VOID *Context + ) +/*++ + + Routine Description: + + Notification function that is called if the watchdog timer is fired. 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. + + Arguments: + + Timer - The one-shot timer event that was signaled when the watchdog timer + expired. + + Context - The context that was registered when the event Timer was created. + + Returns: + + None. + +--*/ +{ + // + // Report error code before exiting + // + 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); + } + // + // Reset the platform + // + gRT->ResetSystem (EfiResetCold, EFI_TIMEOUT, 0, NULL); +} + +EFI_STATUS +EFIAPI +WatchdogTimerDriverRegisterHandler ( + IN EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This, + IN EFI_WATCHDOG_TIMER_NOTIFY NotifyFunction + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + This - The EFI_WATCHDOG_TIMER_ARCH_PROTOCOL instance. + + NotifyFunction - The function to call when the watchdog timer fires. If this + is NULL, then the handler will be unregistered. + +Returns: + + EFI_SUCCESS - The watchdog timer handler was registered or + unregistered. + + EFI_ALREADY_STARTED - NotifyFunction is not NULL, and a handler is already + registered. + + EFI_INVALID_PARAMETER - NotifyFunction is NULL, and a handler was not + previously registered. + +--*/ +{ + if (NotifyFunction == NULL && mWatchdogTimerNotifyFunction == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (NotifyFunction != NULL && mWatchdogTimerNotifyFunction != NULL) { + return EFI_ALREADY_STARTED; + } + + mWatchdogTimerNotifyFunction = NotifyFunction; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +WatchdogTimerDriverSetTimerPeriod ( + IN EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This, + IN UINT64 TimerPeriod + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + This - The EFI_WATCHDOG_TIMER_ARCH_PROTOCOL instance. + + 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. + +Returns: + + EFI_SUCCESS - The watchdog timer has been programmed to fire in Time + 100 nS units. + + EFI_DEVICE_ERROR - A watchdog timer could not be programmed due to a device + error. + +--*/ +{ + mWatchdogTimerPeriod = TimerPeriod; + + return gBS->SetTimer ( + mWatchdogTimerEvent, + (mWatchdogTimerPeriod == 0) ? TimerCancel : TimerRelative, + mWatchdogTimerPeriod + ); +} + +EFI_STATUS +EFIAPI +WatchdogTimerDriverGetTimerPeriod ( + IN EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This, + IN UINT64 *TimerPeriod + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + This - The EFI_WATCHDOG_TIMER_ARCH_PROTOCOL instance. + + 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. + +Returns: + + EFI_SUCCESS - The amount of time that the system will wait before + firing the watchdog timer was returned in TimerPeriod. + + EFI_INVALID_PARAMETER - TimerPeriod is NULL. + +--*/ +{ + if (TimerPeriod == NULL) { + return EFI_INVALID_PARAMETER; + } + + *TimerPeriod = mWatchdogTimerPeriod; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +WatchdogTimerDriverInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Initialize the Watchdog Timer Architectural Protocol driver + +Arguments: + + ImageHandle - ImageHandle of the loaded driver + + SystemTable - Pointer to the System Table + +Returns: + + EFI_SUCCESS - Timer Architectural Protocol created + + EFI_OUT_OF_RESOURCES - Not enough resources available to initialize driver. + + EFI_DEVICE_ERROR - A device error occured attempting to initialize the driver. + +--*/ +{ + EFI_STATUS Status; + + REPORT_STATUS_CODE ( + EFI_PROGRESS_CODE, + (EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_SW_PC_INIT_BEGIN) + ); + // + // Make sure the Watchdog Timer Architectural Protocol is not already installed in the system + // + ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiWatchdogTimerArchProtocolGuid); + + // + // Create the timer event used to implement a simple watchdog timer + // + Status = gBS->CreateEvent ( + EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL, + EFI_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); + + REPORT_STATUS_CODE ( + EFI_PROGRESS_CODE, + (EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_SW_PC_INIT_END) + ); + + return Status; +} diff --git a/EdkModulePkg/Universal/WatchdogTimer/Dxe/WatchDogTimer.dxs b/EdkModulePkg/Universal/WatchdogTimer/Dxe/WatchDogTimer.dxs new file mode 100644 index 0000000000..da8c297342 --- /dev/null +++ b/EdkModulePkg/Universal/WatchdogTimer/Dxe/WatchDogTimer.dxs @@ -0,0 +1,27 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + WatchDogTimer.dxs + +Abstract: + + Dependency expression source file. + +--*/ +#include +#include + +DEPENDENCY_START + EFI_TIMER_ARCH_PROTOCOL_GUID +DEPENDENCY_END + diff --git a/EdkModulePkg/Universal/WatchdogTimer/Dxe/WatchDogTimer.h b/EdkModulePkg/Universal/WatchdogTimer/Dxe/WatchDogTimer.h new file mode 100644 index 0000000000..bb1936b90e --- /dev/null +++ b/EdkModulePkg/Universal/WatchdogTimer/Dxe/WatchDogTimer.h @@ -0,0 +1,62 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + WatchDogTimer.h + +Abstract: + + Generic watchdog timer implemenetation using EFI APIs + +Revision History + +--*/ + +#ifndef _WATCHDOG_TIMER_H_ +#define _WATCHDOG_TIMER_H_ + +// +// Function Prototypes +// +EFI_STATUS +EFIAPI +WatchdogTimerDriverRegisterHandler ( + IN EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This, + IN EFI_WATCHDOG_TIMER_NOTIFY NotifyFunction + ) +; + +EFI_STATUS +EFIAPI +WatchdogTimerDriverSetTimerPeriod ( + IN EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This, + IN UINT64 TimerPeriod + ) +; + +EFI_STATUS +EFIAPI +WatchdogTimerDriverGetTimerPeriod ( + IN EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This, + IN UINT64 *TimerPeriod + ) +; + +EFI_STATUS +EFIAPI +WatchdogTimerDriverInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +; + +#endif diff --git a/EdkModulePkg/Universal/WatchdogTimer/Dxe/WatchDogTimer.mbd b/EdkModulePkg/Universal/WatchdogTimer/Dxe/WatchDogTimer.mbd new file mode 100644 index 0000000000..17bd6ea24f --- /dev/null +++ b/EdkModulePkg/Universal/WatchdogTimer/Dxe/WatchDogTimer.mbd @@ -0,0 +1,44 @@ + + + + + WatchDogTimer + F099D67F-71AE-4c36-B2A3-DCEB0EB2B7D8 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:19 + + + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + BaseLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + EdkDxePrintLib + + + _ModuleEntryPoint + + diff --git a/EdkModulePkg/Universal/WatchdogTimer/Dxe/WatchDogTimer.msa b/EdkModulePkg/Universal/WatchdogTimer/Dxe/WatchDogTimer.msa new file mode 100644 index 0000000000..4cccdc7ce5 --- /dev/null +++ b/EdkModulePkg/Universal/WatchdogTimer/Dxe/WatchDogTimer.msa @@ -0,0 +1,61 @@ + + + + + WatchDogTimer + DXE_DRIVER + BS_DRIVER + F099D67F-71AE-4c36-B2A3-DCEB0EB2B7D8 + 0 + Component description file for DiskIo module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:19 + + + DebugLib + UefiDriverEntryPoint + ReportStatusCodeLib + UefiLib + BaseLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + + + WatchDogTimer.c + WatchDogTimer.h + WatchDogTimer.dxs + + + MdePkg + EdkModulePkg + + + StatusCode + WatchdogTimer + + + + WatchdogTimerDriverInitialize + + + diff --git a/EdkModulePkg/Universal/WatchdogTimer/Dxe/build.xml b/EdkModulePkg/Universal/WatchdogTimer/Dxe/build.xml new file mode 100644 index 0000000000..76f67c162e --- /dev/null +++ b/EdkModulePkg/Universal/WatchdogTimer/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/build.xml b/EdkModulePkg/build.xml new file mode 100644 index 0000000000..41712df4e8 --- /dev/null +++ b/EdkModulePkg/build.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/EdkModulePkg/genbuildfile.xml b/EdkModulePkg/genbuildfile.xml new file mode 100644 index 0000000000..77702ef12d --- /dev/null +++ b/EdkModulePkg/genbuildfile.xml @@ -0,0 +1,19 @@ + + + + + + + + + + diff --git a/EdkNt32Pkg/Build/AprioriList.mbd b/EdkNt32Pkg/Build/AprioriList.mbd new file mode 100644 index 0000000000..36b39b164b --- /dev/null +++ b/EdkNt32Pkg/Build/AprioriList.mbd @@ -0,0 +1,32 @@ + + + + + + $(EFI_APRIORI_GUID) + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-14 17:04 + 2006-03-19 15:17 + + + + diff --git a/EdkNt32Pkg/Build/AprioriList.msa b/EdkNt32Pkg/Build/AprioriList.msa new file mode 100644 index 0000000000..94850edd8c --- /dev/null +++ b/EdkNt32Pkg/Build/AprioriList.msa @@ -0,0 +1,44 @@ + + + + + AprioriList + USER_DEFINED + APRIORI + 0xfc510ee7, 0xffdc, 0x11d4, 0xbd, 0x41, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 + 0 + Component description file for creating an Apriori file. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-14 17:04 + 2006-03-19 15:17 + + + $(BUILD_DIR)\Fv\$(FV).apr + + + + + + + + + diff --git a/EdkNt32Pkg/Build/Nt32Common.xml b/EdkNt32Pkg/Build/Nt32Common.xml new file mode 100644 index 0000000000..7d996fe5c9 --- /dev/null +++ b/EdkNt32Pkg/Build/Nt32Common.xml @@ -0,0 +1,183 @@ + + + + + + + + +

+
+
+ + + + + + + +
+ + + + + + +
+ + + + + + + +
+ + + + + + + +
+ + + + + + + +
+ + + + + + + + +
+ + + + + + + +
+
+
+
+ + + + + + +
+ + + + + + + +
+
+
+
+
+ + + + + + + + + +
+
+
+ + + + + + +
+
+
+
+ + + + + + +
+
+ + + + + + +
+ +
+
+
+ + + + + + + +
+
+
+
+
+ + + + + + +
+
+
+ + + + + + + +
+
+
+
+ + + + + + + + +
+ + + diff --git a/EdkNt32Pkg/Build/component.def b/EdkNt32Pkg/Build/component.def new file mode 100644 index 0000000000..1e8484653b --- /dev/null +++ b/EdkNt32Pkg/Build/component.def @@ -0,0 +1,12 @@ +; Copyright (c) 2006, Intel Corporation +; All rights reserved. This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php + +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +LIBRARY +EXPORTS + InitializeDriver=_ModuleEntryPoint diff --git a/EdkNt32Pkg/Dxe/ConPlatform/ComponentName.c b/EdkNt32Pkg/Dxe/ConPlatform/ComponentName.c new file mode 100644 index 0000000000..f854499937 --- /dev/null +++ b/EdkNt32Pkg/Dxe/ConPlatform/ComponentName.c @@ -0,0 +1,141 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ComponentName.c + +Abstract: + +--*/ + +#include "ConPlatform.h" +#include "ComponentName.h" + +// +// EFI Component Name Protocol +// +EFI_COMPONENT_NAME_PROTOCOL gConPlatformComponentName = { + ConPlatformComponentNameGetDriverName, + ConPlatformComponentNameGetControllerName, + "eng" +}; + +STATIC EFI_UNICODE_STRING_TABLE mConPlatformDriverNameTable[] = { + { + "eng", + L"Platform Console Management Driver" + }, + { + NULL, + NULL + } +}; + +EFI_STATUS +EFIAPI +ConPlatformComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gConPlatformComponentName.SupportedLanguages, + mConPlatformDriverNameTable, + DriverName + ); +} + +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 + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + 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. + 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. + + Returns: + 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. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return EFI_UNSUPPORTED; +} diff --git a/EdkNt32Pkg/Dxe/ConPlatform/ComponentName.h b/EdkNt32Pkg/Dxe/ConPlatform/ComponentName.h new file mode 100644 index 0000000000..3bada842d7 --- /dev/null +++ b/EdkNt32Pkg/Dxe/ConPlatform/ComponentName.h @@ -0,0 +1,44 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ComponentName.h + +Abstract: + +--*/ + +#ifndef CON_MANAGE_COMPONENT_NAME_H_ +#define CON_MANAGE_COMPONENT_NAME_H_ + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +ConPlatformComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +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 + ); + +#endif diff --git a/EdkNt32Pkg/Dxe/ConPlatform/ConPlatform.c b/EdkNt32Pkg/Dxe/ConPlatform/ConPlatform.c new file mode 100644 index 0000000000..4b7d2796d0 --- /dev/null +++ b/EdkNt32Pkg/Dxe/ConPlatform/ConPlatform.c @@ -0,0 +1,811 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ConPlatform.c + +Abstract: + +--*/ + +#include "ConPlatform.h" + +EFI_DRIVER_BINDING_PROTOCOL gConPlatformTextInDriverBinding = { + ConPlatformTextInDriverBindingSupported, + ConPlatformTextInDriverBindingStart, + ConPlatformDriverBindingStop, + 0x10, + NULL, + NULL +}; + +EFI_DRIVER_BINDING_PROTOCOL gConPlatformTextOutDriverBinding = { + ConPlatformTextOutDriverBindingSupported, + ConPlatformTextOutDriverBindingStart, + ConPlatformDriverBindingStop, + 0x10, + NULL, + NULL +}; + +STATIC +EFI_STATUS +EFIAPI +ConPlatformTextInDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + Supported + +Arguments: + (Standard DriverBinding Protocol Supported() function) + +Returns: + + None + +--*/ +{ + return ConPlatformDriverBindingSupported ( + This, + ControllerHandle, + RemainingDevicePath, + &gEfiSimpleTextInProtocolGuid + ); +} + +STATIC +EFI_STATUS +EFIAPI +ConPlatformTextOutDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + Supported + +Arguments: + (Standard DriverBinding Protocol Supported() function) + +Returns: + + None + +--*/ +{ + return ConPlatformDriverBindingSupported ( + This, + ControllerHandle, + RemainingDevicePath, + &gEfiSimpleTextOutProtocolGuid + ); +} + +EFI_STATUS +ConPlatformDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath, + IN EFI_GUID *ProtocolGuid + ) +/*++ + +Routine Description: + Supported + +Arguments: + (Standard DriverBinding Protocol Supported() function) + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + VOID *Interface; + + // + // Test to see if this is a physical device by checking to see 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 Simple Text Output 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; +} + +STATIC +EFI_STATUS +EFIAPI +ConPlatformTextInDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + +Arguments: + (Standard DriverBinding Protocol Start() function) + +Returns: + + +--*/ +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_SIMPLE_TEXT_IN_PROTOCOL *TextIn; + + // + // 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 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 the device handle, if it is a hot plug device, + // do not put the device path into ConInDev, and install + // gEfiConsoleInDeviceGuid to the device handle directly. + // The policy is, make hot plug device plug in and play immediately. + // + if (IsHotPlugDevice (This->DriverBindingHandle, ControllerHandle)) { + gBS->InstallMultipleProtocolInterfaces ( + &ControllerHandle, + &gEfiConsoleInDeviceGuid, + NULL, + NULL + ); + } else { + // + // Append the device path to the ConInDev environment variable + // + ConPlatformUpdateDeviceVariable ( + VarConsoleInpDev, + DevicePath, + APPEND + ); + + // + // If the device path is an instance in the ConIn environment variable, + // then install EfiConsoleInDeviceGuid onto ControllerHandle + // + Status = ConPlatformUpdateDeviceVariable ( + VarConsoleInp, + DevicePath, + CHECK + ); + + if (!EFI_ERROR (Status)) { + gBS->InstallMultipleProtocolInterfaces ( + &ControllerHandle, + &gEfiConsoleInDeviceGuid, + NULL, + NULL + ); + } else { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiSimpleTextInProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + } + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +ConPlatformTextOutDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + +Arguments: + (Standard DriverBinding Protocol Start() function) + +Returns: + + +--*/ +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_SIMPLE_TEXT_OUT_PROTOCOL *TextOut; + + BOOLEAN NeedClose; + + 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 the device handle, if it is a hot plug device, + // do not put the device path into ConOutDev and StdErrDev, + // and install gEfiConsoleOutDeviceGuid to the device handle directly. + // The policy is, make hot plug device plug in and play immediately. + // + if (IsHotPlugDevice (This->DriverBindingHandle, ControllerHandle)) { + gBS->InstallMultipleProtocolInterfaces ( + &ControllerHandle, + &gEfiConsoleOutDeviceGuid, + NULL, + NULL + ); + } else { + // + // Append the device path to the ConOutDev environment variable + // + ConPlatformUpdateDeviceVariable ( + VarConsoleOutDev, + DevicePath, + APPEND + ); + // + // Append the device path to the StdErrDev environment variable + // + ConPlatformUpdateDeviceVariable ( + VarErrorOutDev, + DevicePath, + APPEND + ); + + // + // If the device path is an instance in the ConOut environment variable, + // then install EfiConsoleOutDeviceGuid onto ControllerHandle + // + Status = ConPlatformUpdateDeviceVariable ( + VarConsoleOut, + DevicePath, + CHECK + ); + if (!EFI_ERROR (Status)) { + NeedClose = FALSE; + Status = gBS->InstallMultipleProtocolInterfaces ( + &ControllerHandle, + &gEfiConsoleOutDeviceGuid, + NULL, + NULL + ); + } + // + // If the device path is an instance in the StdErr environment variable, + // then install EfiStandardErrorDeviceGuid onto ControllerHandle + // + Status = ConPlatformUpdateDeviceVariable ( + VarErrorOut, + DevicePath, + CHECK + ); + if (!EFI_ERROR (Status)) { + NeedClose = FALSE; + gBS->InstallMultipleProtocolInterfaces ( + &ControllerHandle, + &gEfiStandardErrorDeviceGuid, + NULL, + NULL + ); + } + + if (NeedClose) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiSimpleTextOutProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + } + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +ConPlatformDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + +Routine Description: + +Arguments: + (Standard DriverBinding Protocol Stop() function) + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + // + // hot plug device is not included into the console associated variables, + // so no need to check variable for those hot plug devices. + // + if (!IsHotPlugDevice (This->DriverBindingHandle, ControllerHandle)) { + // + // 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)) { + // + // Remove DevicePath from ConInDev, ConOutDev, and StdErrDev + // + ConPlatformUpdateDeviceVariable ( + VarConsoleInpDev, + DevicePath, + DELETE + ); + ConPlatformUpdateDeviceVariable ( + VarConsoleOutDev, + DevicePath, + DELETE + ); + ConPlatformUpdateDeviceVariable ( + VarErrorOutDev, + DevicePath, + DELETE + ); + } + } + // + // Uninstall the Console Device GUIDs from Controller Handle + // + ConPlatformUnInstallProtocol ( + This, + ControllerHandle, + &gEfiConsoleInDeviceGuid + ); + + ConPlatformUnInstallProtocol ( + This, + ControllerHandle, + &gEfiConsoleOutDeviceGuid + ); + + ConPlatformUnInstallProtocol ( + This, + ControllerHandle, + &gEfiStandardErrorDeviceGuid + ); + + // + // Close the Simple Input and Simple Text Output Protocols + // + gBS->CloseProtocol ( + ControllerHandle, + &gEfiSimpleTextInProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + + gBS->CloseProtocol ( + ControllerHandle, + &gEfiSimpleTextOutProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + + return EFI_SUCCESS; +} + +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 ; +} + +VOID * +ConPlatformGetVariable ( + IN CHAR16 *Name + ) +/*++ + +Routine Description: + Read the EFI variable (Name) and return a dynamically allocated + buffer, and the size of the buffer. On failure return NULL. + +Arguments: + Name - String part of EFI variable name + +Returns: + Dynamically allocated memory that contains a copy of the EFI variable. + Caller is repsoncible freeing the buffer. + + NULL - Variable was not read + +--*/ +{ + EFI_STATUS Status; + VOID *Buffer; + UINTN BufferSize; + + BufferSize = 0; + Buffer = NULL; + + // + // Test to see if the variable exists. If it doesn't reuturn NULL + // + Status = gRT->GetVariable ( + Name, + &gEfiGlobalVariableGuid, + NULL, + &BufferSize, + Buffer + ); + + if (Status == EFI_BUFFER_TOO_SMALL) { + // + // Allocate the buffer to return + // + Status = gBS->AllocatePool (EfiBootServicesData, BufferSize, &Buffer); + if (EFI_ERROR (Status)) { + return NULL; + } + // + // Read variable into the allocated buffer. + // + Status = gRT->GetVariable ( + Name, + &gEfiGlobalVariableGuid, + NULL, + &BufferSize, + Buffer + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (Buffer); + Buffer = NULL; + } + } + + return Buffer; +} + +EFI_STATUS +ConPlatformMatchDevicePaths ( + IN EFI_DEVICE_PATH_PROTOCOL * Multi, + IN EFI_DEVICE_PATH_PROTOCOL * Single, + IN EFI_DEVICE_PATH_PROTOCOL **NewDevicePath OPTIONAL, + IN BOOLEAN Delete + ) +/*++ + +Routine Description: + Function compares a device path data structure to that of all the nodes of a + second device path instance. + +Arguments: + Multi - A pointer to a multi-instance device path data structure. + + Single - A pointer to a single-instance device path data structure. + + 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.) + + Delete - If TRUE, means removing Single from Multi. + If FALSE, the routine just check whether Single matches + with any instance in Multi. + +Returns: + + The function returns EFI_SUCCESS if the Single is contained within Multi. + Otherwise, EFI_NOT_FOUND is returned. + +--*/ +{ + 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) || (!Single)) { + return EFI_NOT_FOUND; + } + // + // if performing Delete operation, the NewDevicePath must not be NULL. + // + TempDevicePath1 = NULL; + + DevicePath = Multi; + DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size); + + // + // search for the match of 'Single' in 'Multi' + // + while (DevicePathInst) { + if (CompareMem (Single, DevicePathInst, Size) == 0) { + if (!Delete) { + gBS->FreePool (DevicePathInst); + return EFI_SUCCESS; + } + } else { + if (Delete) { + TempDevicePath2 = AppendDevicePathInstance ( + TempDevicePath1, + DevicePathInst + ); + gBS->FreePool (TempDevicePath1); + TempDevicePath1 = TempDevicePath2; + } + } + + gBS->FreePool (DevicePathInst); + DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size); + } + + if (Delete) { + *NewDevicePath = TempDevicePath1; + return EFI_SUCCESS; + } + + return EFI_NOT_FOUND; +} + +EFI_STATUS +ConPlatformUpdateDeviceVariable ( + IN CHAR16 *VariableName, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN CONPLATFORM_VAR_OPERATION Operation + ) +/*++ + +Routine Description: + + +Arguments: + +Returns: + + None + +--*/ +{ + 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) { + + Status = ConPlatformMatchDevicePaths ( + VariableDevicePath, + DevicePath, + NULL, + FALSE + ); + + if ((Operation == CHECK) || (!EFI_ERROR (Status))) { + // + // The device path is already in the variable + // + gBS->FreePool (VariableDevicePath); + + return Status; + } + // + // The device path is not in variable. Append DevicePath to the + // environment variable that is a multi-instance device path. + // + Status = EFI_SUCCESS; + NewVariableDevicePath = AppendDevicePathInstance ( + VariableDevicePath, + DevicePath + ); + if (NewVariableDevicePath == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } + + } else { + // + // Remove DevicePath from the environment variable that + // is a multi-instance device path. + // + Status = ConPlatformMatchDevicePaths ( + VariableDevicePath, + DevicePath, + &NewVariableDevicePath, + TRUE + ); + } + + gBS->FreePool (VariableDevicePath); + + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gRT->SetVariable ( + VariableName, + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + GetDevicePathSize (NewVariableDevicePath), + NewVariableDevicePath + ); + + gBS->FreePool (NewVariableDevicePath); + + return Status; +} + +BOOLEAN +IsHotPlugDevice ( + EFI_HANDLE DriverBindingHandle, + EFI_HANDLE ControllerHandle + ) +{ + EFI_STATUS Status; + + // + // HotPlugDeviceGuid indicates ControllerHandle stands for a hot plug device. + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiHotPlugDeviceGuid, + NULL, + DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return FALSE; + } + + return TRUE; +} diff --git a/EdkNt32Pkg/Dxe/ConPlatform/ConPlatform.h b/EdkNt32Pkg/Dxe/ConPlatform/ConPlatform.h new file mode 100644 index 0000000000..41b025625b --- /dev/null +++ b/EdkNt32Pkg/Dxe/ConPlatform/ConPlatform.h @@ -0,0 +1,126 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ConPlatform.h + +Abstract: + +--*/ + +#ifndef CON_MANAGE_H_ +#define CON_MANAGE_H_ + +// +// +// +#define VarConsoleInpDev L"ConInDev" +#define VarConsoleInp L"ConIn" +#define VarConsoleOutDev L"ConOutDev" +#define VarConsoleOut L"ConOut" +#define VarErrorOutDev L"ErrOutDev" +#define VarErrorOut L"ErrOut" + +typedef enum { + CHECK, + APPEND, + DELETE +} CONPLATFORM_VAR_OPERATION; + +EFI_STATUS +ConPlatformDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath, + IN EFI_GUID *ProtocolGuid + ); + +STATIC +EFI_STATUS +EFIAPI +ConPlatformTextInDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +STATIC +EFI_STATUS +EFIAPI +ConPlatformTextOutDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +STATIC +EFI_STATUS +EFIAPI +ConPlatformTextInDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +STATIC +EFI_STATUS +EFIAPI +ConPlatformTextOutDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +STATIC +EFI_STATUS +EFIAPI +ConPlatformDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +VOID +ConPlatformUnInstallProtocol ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN EFI_GUID *ProtocolGuid + ); + +VOID * +ConPlatformGetVariable ( + IN CHAR16 *Name + ); + +EFI_STATUS +ConPlatformMatchDevicePaths ( + IN EFI_DEVICE_PATH_PROTOCOL * Multi, + IN EFI_DEVICE_PATH_PROTOCOL * Single, + IN EFI_DEVICE_PATH_PROTOCOL **NewDevicePath OPTIONAL, + IN BOOLEAN Delete + ); + +EFI_STATUS +ConPlatformUpdateDeviceVariable ( + IN CHAR16 *VariableName, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN CONPLATFORM_VAR_OPERATION Operation + ); + +BOOLEAN +IsHotPlugDevice ( + EFI_HANDLE DriverBindingHandle, + EFI_HANDLE ControllerHandle + ); + +#endif diff --git a/EdkNt32Pkg/Dxe/ConPlatform/ConPlatform.mbd b/EdkNt32Pkg/Dxe/ConPlatform/ConPlatform.mbd new file mode 100644 index 0000000000..6aaa24512b --- /dev/null +++ b/EdkNt32Pkg/Dxe/ConPlatform/ConPlatform.mbd @@ -0,0 +1,44 @@ + + + + + ConPlatform + 51ccf399-4fdf-4e55-a45b-e123f84d456a + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-13 17:06 + 2006-03-19 15:17 + + + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + EdkDxePrintLib + BaseLib + DxeMemoryAllocationLib + UefiDevicePathLib + + diff --git a/EdkNt32Pkg/Dxe/ConPlatform/ConPlatform.msa b/EdkNt32Pkg/Dxe/ConPlatform/ConPlatform.msa new file mode 100644 index 0000000000..30bd63cbff --- /dev/null +++ b/EdkNt32Pkg/Dxe/ConPlatform/ConPlatform.msa @@ -0,0 +1,116 @@ + + + + + ConPlatform + UEFI_DRIVER + BS_DRIVER + 51ccf399-4fdf-4e55-a45b-e123f84d456a + 0 + Component description file for DiskIo module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-13 17:06 + 2006-03-19 15:17 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + UefiLib + BaseLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + DevicePathLib + + + ConPlatform.c + ConPlatform.h + ComponentName.c + + + MdePkg + EdkModulePkg + + + SimpleTextOut + SimpleTextIn + DevicePath + + + + ConInDev + 0x8BE4DF61, 0x93CA, 0x11d2, 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C + + + ConIn + 0x8BE4DF61, 0x93CA, 0x11d2, 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C + + + ConOutDev + 0x8BE4DF61, 0x93CA, 0x11d2, 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C + + + ConOut + 0x8BE4DF61, 0x93CA, 0x11d2, 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C + + + ErrOutDev + 0x8BE4DF61, 0x93CA, 0x11d2, 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C + + + ErrOut + 0x8BE4DF61, 0x93CA, 0x11d2, 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C + + + + + ConsoleInDevice + + + ConsoleOutDevice + + + StandardErrorDevice + + + HotPlugDevice + + + GlobalVariable + + + + + + + + gConPlatformTextInDriverBinding + gConPlatformComponentName + + + gConPlatformTextOutDriverBinding + gConPlatformComponentName + + + diff --git a/EdkNt32Pkg/Dxe/ConPlatform/build.xml b/EdkNt32Pkg/Dxe/ConPlatform/build.xml new file mode 100644 index 0000000000..52d84eb934 --- /dev/null +++ b/EdkNt32Pkg/Dxe/ConPlatform/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscBaseBoardManufacturer.uni b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscBaseBoardManufacturer.uni new file mode 100644 index 0000000000000000000000000000000000000000..14a68936efd1c0008d99482a861ebe7a4414d98c GIT binary patch literal 2896 zcmchZTW?Z95Xa})#P4v@#zdtWBKz8U_6GXF-ZMVh zJNT+i_%^T`c%4Z(rMbiI2yVjubC1lL#0uaNvS`K3R|A`YIkkJ{zUA0!V&jP21pFzu zuiS<)>kc;bp|?m3eBHwjQyU|xZ*$H~kWbi=)zUkHyK!y*Z+k@FL6dI0L0=DU;;4ls z!=xMg3sm>;BV;?)W!AYnM=m@OeZV(%Y?&5WBO6D{n8^=Q8?Kxy+PRfkpR8f|-MWbW z!9Chz7T$HAjlicnsJ_|2m&~G;-)liF^K0d}i!)v88YOkG|y4a?Nl3&Zk>N z^iQYr`7}lJO*^&8c>ui-YFvR~zX-Bx#;4OX&J zdqUSlRx-jDqz;i4&acqVe36a9Rax8;?5)_BrJkt0ir3DlSlwCnF84QUBKpYH$nU<_ zn=0>=dKps#2g^4iN=j?Z>$ivZI^_NUI)zKoP=ij;Glcf2DbE4lLZ_)9h&!~3iE7q*)-KTQ*7O$an1%01v*Ey|r zm%S=<{*aGtY*pTrti8yhigR_(fHHi|W7)DpXbIdckG(QB8@u!j`RfWlb(rOQbsoJh z%GJ!j%G1ol^8TNFyyJ*BMH}j`3`${blLM+lRc1CeLwknrLvAS_Vs34R_5x%LydSD3 zL%2#eLwn)bIwNoNN^XZyRj$5Opep6h7XB>yUWRisjOUIq{OgcE@2FM1cj^o~ NV<-D}5>Trn`~q?~g#!Qp literal 0 HcmV?d00001 diff --git a/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscBaseBoardManufacturerData.c b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscBaseBoardManufacturerData.c new file mode 100644 index 0000000000..9536c88aa4 --- /dev/null +++ b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscBaseBoardManufacturerData.c @@ -0,0 +1,57 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + MiscBaseBoardManufacturerData.c + +Abstract: + + This driver parses the mMiscSubclassDataTable structure and reports + any generated data to the DataHub. + +--*/ + +#include "MiscSubclassDriver.h" + +// +// Static (possibly build generated) Bios Vendor data. +// +MISC_SUBCLASS_TABLE_DATA(EFI_MISC_BASE_BOARD_MANUFACTURER_DATA, MiscBaseBoardManufacturer) = { + STRING_TOKEN(STR_MISC_BASE_BOARD_MANUFACTURER), + STRING_TOKEN(STR_MISC_BASE_BOARD_PRODUCT_NAME), + STRING_TOKEN(STR_MISC_BASE_BOARD_VERSION), + STRING_TOKEN(STR_MISC_BASE_BOARD_SERIAL_NUMBER), + STRING_TOKEN(STR_MISC_BASE_BOARD_ASSET_TAG), + STRING_TOKEN(STR_MISC_BASE_BOARD_CHASSIS_LOCATION), + { // BaseBoardFeatureFlags + 1, // Motherboard + 0, // RequiresDaughterCard + 0, // Removable + 1, // Replaceable, + 0, // HotSwappable + 0, // Reserved + }, + EfiBaseBoardTypeUnknown, // BaseBoardType + { // BaseBoardChassisLink + EFI_MISC_SUBCLASS_GUID, // ProducerName + 1, // Instance + 1, // SubInstance + }, + 0, // BaseBoardNumberLinks + { // LinkN + EFI_MISC_SUBCLASS_GUID, // ProducerName + 1, // Instance + 1, // SubInstance + }, +}; + +/* eof - MiscBaseBoardManufacturerData.c */ diff --git a/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscBiosLanguageData.c b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscBiosLanguageData.c new file mode 100644 index 0000000000..652acacb54 --- /dev/null +++ b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscBiosLanguageData.c @@ -0,0 +1,45 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + MiscBiosLanguageData.c + +Abstract: + + This driver parses the mMiscSubclassDataTable structure and reports + any generated data to the DataHub. + +--*/ + +#include "MiscSubclassDriver.h" + +// +// Static (possibly build generated) Bios Vendor data. +// +MISC_SUBCLASS_TABLE_DATA(EFI_MISC_NUMBER_OF_INSTALLABLE_LANGUAGES_DATA, NumberOfInstallableLangauges) = { + 1, // NumberOfInstallableLanguages + { // LanguageFlags + 0, // AbbreviatedLanguageFormat + 0 // Reserved + }, + 0 // CurrentLanguageNumber +}; + +// +// +// +MISC_SUBCLASS_TABLE_DATA(EFI_MISC_SYSTEM_LANGUAGE_STRING_DATA, SystemLanguageString) = { + 0, // LanguageId + STR_MISC_SYSTEM_LANGUAGE_STRING // SystemLanguageString +}; + +/* eof - MiscBiosLanguageData.c */ diff --git a/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscBiosVendor.uni b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscBiosVendor.uni new file mode 100644 index 0000000000000000000000000000000000000000..b1e7e520fc2ea6a7a327a1464bde11c94619cb68 GIT binary patch literal 2260 zcmchYT~AX%5QgX4#Q$(oVxlOm@xludFMuAUk+!51&@0k!PSOu^TG9S_^?7G|x-Ciq zk&w;Vo!K)x`_AY7{#CJxCAMp?8PDw*TxGo`c4RaAW=qR0vyolf0@;_=vsbL|>@DNH zy@9UTlz#&oL+eb=Da{>rGpH&1Pdy525<38wkVPxz&JAo1=G<cr)b9TDe(zm@^f68dN=G(sW@wkZo z@pL|&rii|6$Cl!yQ)^k%J~1Cy9lk~mCS;-3HoG-Dv~#G`GxOXUtSS4-m!KhLZH?}f zB5~%Ln^5WwnoF$GE3GBgL+8b*zuk94^p|MT{Y}S~*d_W}ZbO6p8u#nArsHhE$x7`B zT^m`+2w#x;h^%maW&O+_*(hA;>Xu+{YG2lRqV^hIJEdZEXVtshUDibOk*bs5eXloF zUW0m>Py_qxHzG<(Yu)R&hxgR==XT-s()SuE(`Sd&N<0y%1Fsd;y?VrALw~X%uNz)4 z+UT!t>_^;&#?uDfIY|c~{u03^}qZ z5Gh_~P!}G<>MFMX^7RfKL0xx*Upvh5ton*x4`pKEy=2ROB}em6BrPz7O!|K$IbH~U meK;0n_X(e>EX7Mz&vDgvG4AgbMOklK2R!m!6-qBbK=lWya3F>N literal 0 HcmV?d00001 diff --git a/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscBiosVendorData.c b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscBiosVendorData.c new file mode 100644 index 0000000000..3187aba2a0 --- /dev/null +++ b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscBiosVendorData.c @@ -0,0 +1,88 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + MiscBiosVendorData.c + +Abstract: + + This driver parses the mMiscSubclassDataTable structure and reports + any generated data to the DataHub. + +--*/ + +#include "MiscSubclassDriver.h" + +// +// Static (possibly build generated) Bios Vendor data. +// +MISC_SUBCLASS_TABLE_DATA(EFI_MISC_BIOS_VENDOR_DATA, MiscBiosVendor) = { + STRING_TOKEN(STR_MISC_BIOS_VENDOR), // BiosVendor + STRING_TOKEN(STR_MISC_BIOS_VERSION), // BiosVersion + STRING_TOKEN(STR_MISC_BIOS_RELEASE_DATE), // BiosReleaseDate + 0xBABE, // BiosStartingAddress + { // BiosPhysicalDeviceSize + 2, // Value + 3, // Exponent + }, + { // BiosCharacteristics1 + 0, // Reserved1 :2 + 0, // Unknown :1 + 1, // BiosCharacteristicsNotSupported :1 + 0, // IsaIsSupported :1 + 0, // McaIsSupported :1 + 0, // EisaIsSupported :1 + 0, // PciIsSupported :1 + 0, // PcmciaIsSupported :1 + 0, // PlugAndPlayIsSupported :1 + 0, // ApmIsSupported :1 + 0, // BiosIsUpgradable :1 + 0, // BiosShadowingAllowed :1 + 0, // VlVesaIsSupported :1 + 0, // EscdSupportIsAvailable :1 + 0, // BootFromCdIsSupported :1 + 0, // SelectableBootIsSupported :1 + 0, // RomBiosIsSocketed :1 + 0, // BootFromPcmciaIsSupported :1 + 0, // EDDSpecificationIsSupported :1 + 0, // JapaneseNecFloppyIsSupported :1 + 0, // JapaneseToshibaFloppyIsSupported :1 + 0, // Floppy525_360IsSupported :1 + 0, // Floppy525_12IsSupported :1 + 0, // Floppy35_720IsSupported :1 + 0, // Floppy35_288IsSupported :1 + 0, // PrintScreenIsSupported :1 + 0, // Keyboard8042IsSupported :1 + 0, // SerialIsSupported :1 + 0, // PrinterIsSupported :1 + 0, // CgaMonoIsSupported :1 + 0, // NecPc98 :1 + 0, // AcpiIsSupported :1 + 0, // UsbLegacyIsSupported :1 + 0, // AgpIsSupported :1 + 0, // I20BootIsSupported :1 + 0, // Ls120BootIsSupported :1 + 0, // AtapiZipDriveBootIsSupported :1 + 0, // Boot1394IsSupported :1 + 0, // SmartBatteryIsSupported :1 + 0, // BiosBootSpecIsSupported :1 + 0, // FunctionKeyNetworkBootIsSupported :1 + 0 // Reserved :22 + }, + { // BiosCharacteristics2 + 0, // BiosReserved :16 + 0, // SystemReserved :16 + 0 // Reserved :32 + }, +}; + +/* eof - MiscBiosVendorData.c */ diff --git a/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscBootInformationData.c b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscBootInformationData.c new file mode 100644 index 0000000000..1bf280b141 --- /dev/null +++ b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscBootInformationData.c @@ -0,0 +1,33 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + MiscBootInformationData.c + +Abstract: + + This driver parses the mMiscSubclassDataTable structure and reports + any generated data to the DataHub. + +--*/ + +#include "MiscSubclassDriver.h" + +// +// Static (possibly build generated) Bios Vendor data. +// +MISC_SUBCLASS_TABLE_DATA(EFI_MISC_BOOT_INFORMATION_STATUS_DATA, BootInformationStatus) = { + EfiBootInformationStatusNoError, // BootInformationStatus + 0 // BootInformationData +}; + +/* eof - MiscBootInformationData.c */ diff --git a/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscChassisManufacturer.uni b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscChassisManufacturer.uni new file mode 100644 index 0000000000000000000000000000000000000000..67bee85037c6b2ee749495a7b1156e2bc5298a18 GIT binary patch literal 2460 zcmchYT~8B16o${WiT`0!VxlOm@xludFIp(jXesFj=vC8C*n}3dEyezM^?A?GP8T(? zgpkSZ%$Ys&p7(ss{`y(6k|nllZy7J`1yX4}Cw5>r_T842S!$PdWpi|2+rZv1f3WwA zkM@pr&8B=C*)?mO$vCBVkKL5jl>O%(D{m4j!%NJf7c-YeHiL6!3*JL3ve(APl-&gW z8N4suhY4~IABN0xG)68Dh{KId(A2jj=cec z{^>BE4=J*5+lf_)(wQ}_VaL47R!6Q;g9%lrxy^3PD%N3D^~&tnDRY&5)k{E#Ra@hB zs-n?yj`#(wBXq^{8}nzr$Vc(2-dhR&R_*H=C!*Jg+8G@yn}>eO{mYxkKCbH2_t5)I zop(yVOz46A^*y0Mh~5VPN4!$ipd literal 0 HcmV?d00001 diff --git a/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscChassisManufacturerData.c b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscChassisManufacturerData.c new file mode 100644 index 0000000000..5c657eef15 --- /dev/null +++ b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscChassisManufacturerData.c @@ -0,0 +1,45 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + MiscChassisManufacturerData.c + +Abstract: + + This driver parses the mMiscSubclassDataTable structure and reports + any generated data to the DataHub. + +--*/ + +#include "MiscSubclassDriver.h" + +// +// Static (possibly build generated) Chassis Manufacturer data. +// +MISC_SUBCLASS_TABLE_DATA(EFI_MISC_CHASSIS_MANUFACTURER_DATA, MiscChassisManufacturer) = { + STRING_TOKEN(STR_MISC_CHASSIS_MANUFACTURER), // ChassisManufactrurer + STRING_TOKEN(STR_MISC_CHASSIS_VERSION), // ChassisVersion + STRING_TOKEN(STR_MISC_CHASSIS_SERIAL_NUMBER), // ChassisSerialNumber + STRING_TOKEN(STR_MISC_CHASSIS_ASSET_TAG), // ChassisAssetTag + { // ChassisTypeStatus + EfiMiscChassisTypeOther, // ChassisType + 0, // ChassisLockPresent + 0 // Reserved + }, + EfiChassisStateOther, // ChassisBootupState + EfiChassisStateOther, // ChassisPowerSupplyState + EfiChassisStateOther, // ChassisThermalState + EfiChassisSecurityStatusOther, // ChassisSecurityState + 0 // ChassisOemDefined +}; + +/* eof - MiscChassisManufacaturerData.c */ diff --git a/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscDevicePath.h b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscDevicePath.h new file mode 100644 index 0000000000..1568e27b32 --- /dev/null +++ b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscDevicePath.h @@ -0,0 +1,175 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + MiscDevicePath.h + +Abstract: + + Misc class required EFI Device Path definitions (Ports, slots & + onboard devices) + +--*/ + +#ifndef _MISC_DEVICE_PATH_H +#define _MISC_DEVICE_PATH_H + + +#pragma pack(1) +// +// USB +// + +/* For reference: +#define USB1_1_STR "ACPI(PNP0A03,0)/PCI(1D,0)." +#define USB1_2_STR "ACPI(PNP0A03,0)/PCI(1D,1)." +#define USB1_3_STR "ACPI(PNP0A03,0)/PCI(1D,2)." +#define USB2_1_STR "ACPI(PNP0A03,0)/PCI(1D,7)." +*/ + +// +// #define acpi { 0x02, 0x01, 0x00, 0x0C, 0x0a0341d0, 0x00000000 } +// #define pci( device,function) { 0x01, 0x01, 0x00, 0x06, device, function } +// #define end { 0xFF, 0xFF, 0x00, 0x04 } +// +#define ACPI \ + { \ + ACPI_DEVICE_PATH, ACPI_DP, (UINT8) (sizeof (ACPI_HID_DEVICE_PATH)), (UINT8) \ + ((sizeof (ACPI_HID_DEVICE_PATH)) >> 8), EISA_PNP_ID (0x0A03), 0 \ + } +#define PCI(device, function) \ + { \ + HARDWARE_DEVICE_PATH, HW_PCI_DP, (UINT8) (sizeof (PCI_DEVICE_PATH)), (UINT8) \ + ((sizeof (PCI_DEVICE_PATH)) >> 8), function, device \ + } +#define END \ + { \ + END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, END_DEVICE_PATH_LENGTH, 0 \ + } + +#define LPC(eisaid, function) \ + { \ + ACPI_DEVICE_PATH, ACPI_DP, (UINT8) (sizeof (ACPI_HID_DEVICE_PATH)), (UINT8) \ + ((sizeof (ACPI_HID_DEVICE_PATH)) >> 8), EISA_PNP_ID (eisaid), function \ + } + +// +// Shanmu >> moved to TianoDevicePath.h +// + +/* +typedef struct _USB_PORT_DEVICE_PATH +{ + ACPI_HID_DEVICE_PATH PciRootBridgeDevicePath; + PCI_DEVICE_PATH PciBusDevicePath; + EFI_DEVICE_PATH_PROTOCOL EndDevicePath; +} USB_PORT_DEVICE_PATH; + + +//IDE ??I am not sure. Should this be ATAPI_DEVICE_PATH +typedef struct _IDE_DEVICE_PATH +{ + ACPI_HID_DEVICE_PATH PciRootBridgeDevicePath; + PCI_DEVICE_PATH PciBusDevicePath; + EFI_DEVICE_PATH_PROTOCOL EndDevicePath; +} IDE_DEVICE_PATH; + +//RMC Connector +typedef struct _RMC_CONN_DEVICE_PATH +{ + ACPI_HID_DEVICE_PATH PciRootBridgeDevicePath; + PCI_DEVICE_PATH PciBridgeDevicePath; + PCI_DEVICE_PATH PciBusDevicePath; + EFI_DEVICE_PATH_PROTOCOL EndDevicePath; +} RMC_CONN_DEVICE_PATH; + +//static RMC_CONN_DEVICE_PATH mRmcConnDevicePath = { acpi, pci( 0x1E,0x00 ),pci( 0x0A,0x00 ), end }; + +//RIDE +typedef struct _RIDE_DEVICE_PATH +{ + ACPI_HID_DEVICE_PATH PciRootBridgeDevicePath; + PCI_DEVICE_PATH PciBridgeDevicePath; + PCI_DEVICE_PATH PciBusDevicePath; + EFI_DEVICE_PATH_PROTOCOL EndDevicePath; +} RIDE_DEVICE_PATH; + +//static RIDE_DEVICE_PATH mRideDevicePath = { acpi, pci( 0x1E,0x00 ),pci( 0x02,0x00 ), end }; + +//Gigabit NIC +//typedef struct _GB_NIC_DEVICE_PATH +//{ +// ACPI_HID_DEVICE_PATH PciRootBridgeDevicePath; +// PCI_DEVICE_PATH PciBridgeDevicePath; +// PCI_DEVICE_PATH PciXBridgeDevicePath; +// PCI_DEVICE_PATH PciXBusDevicePath; +// EFI_DEVICE_PATH_PROTOCOL EndDevicePath; +//} GB_NIC_DEVICE_PATH; + +//static GB_NIC_DEVICE_PATH mGbNicDevicePath = { acpi, pci( 0x03,0x00 ),pci( 0x1F,0x00 ),pci( 0x07,0x00 ), end }; + + +//P/S2 Connector +typedef struct _PS2_CONN_DEVICE_PATH +{ + ACPI_HID_DEVICE_PATH PciRootBridgeDevicePath; + PCI_DEVICE_PATH LpcBridgeDevicePath; + ACPI_HID_DEVICE_PATH LpcBusDevicePath; + EFI_DEVICE_PATH_PROTOCOL EndDevicePath; +} PS2_CONN_DEVICE_PATH; + +//static PS2_CONN_DEVICE_PATH mPs2KeyboardDevicePath = { acpi, pci( 0x1F,0x00 ),lpc( 0x0303,0 ), end }; +//static PS2_CONN_DEVICE_PATH mPs2MouseDevicePath = { acpi, pci( 0x1F,0x00 ),lpc( 0x0303,1 ), end }; + +//Serial Port Connector +typedef struct _SERIAL_CONN_DEVICE_PATH +{ + ACPI_HID_DEVICE_PATH PciRootBridgeDevicePath; + PCI_DEVICE_PATH LpcBridgeDevicePath; + ACPI_HID_DEVICE_PATH LpcBusDevicePath; + EFI_DEVICE_PATH_PROTOCOL EndDevicePath; +} SERIAL_CONN_DEVICE_PATH; + +//static SERIAL_CONN_DEVICE_PATH mCom1DevicePath = { acpi, pci( 0x1F,0x00 ),lpc( 0x0501,0 ), end }; +//static SERIAL_CONN_DEVICE_PATH mCom2DevicePath = { acpi, pci( 0x1F,0x00 ),lpc( 0x0501,1 ), end }; + +//Parallel Port Connector +typedef struct _PARALLEL_CONN_DEVICE_PATH +{ + ACPI_HID_DEVICE_PATH PciRootBridgeDevicePath; + PCI_DEVICE_PATH LpcBridgeDevicePath; + ACPI_HID_DEVICE_PATH LpcBusDevicePath; + EFI_DEVICE_PATH_PROTOCOL EndDevicePath; +} PARALLEL_CONN_DEVICE_PATH; + +//static PARALLEL_CONN_DEVICE_PATH mLpt1DevicePath = { acpi, pci( 0x1F,0x00 ),lpc( 0x0401,0 ), end }; + +//Floopy Connector +typedef struct _FLOOPY_CONN_DEVICE_PATH +{ + ACPI_HID_DEVICE_PATH PciRootBridgeDevicePath; + PCI_DEVICE_PATH LpcBridgeDevicePath; + ACPI_HID_DEVICE_PATH LpcBusDevicePath; + EFI_DEVICE_PATH_PROTOCOL EndDevicePath; +} FLOOPY_CONN_DEVICE_PATH; + +//static FLOOPY_CONN_DEVICE_PATH mFloopyADevicePath = { acpi, pci( 0x1F,0x00 ),lpc( 0x0604,0 ), end }; +//static FLOOPY_CONN_DEVICE_PATH mFloopyBDevicePath = { acpi, pci( 0x1F,0x00 ),lpc( 0x0604,1 ), end }; + +*/ + +// +// End Shanmu +// +#pragma pack() + +#endif diff --git a/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscNumberOfInstallableLanguagesData.c b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscNumberOfInstallableLanguagesData.c new file mode 100644 index 0000000000..008425987b --- /dev/null +++ b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscNumberOfInstallableLanguagesData.c @@ -0,0 +1,37 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + MiscNumberOfInstallableLanguagesData.c + +Abstract: + + This driver parses the mMiscSubclassDataTable structure and reports + any generated data to the DataHub. + +--*/ + +#include "MiscSubclassDriver.h" + +// +// Static (possibly build generated) Bios Vendor data. +// +MISC_SUBCLASS_TABLE_DATA(EFI_MISC_NUMBER_OF_INSTALLABLE_LANGUAGES_DATA, NumberOfInstallableLanguages) = { + 1, // NumberOfInstallableLanguages + { // LanguageFlags + 0, // AbbreviatedLanguageFormat + 0 // Reserved + }, + 0, // CurrentLanguageNumber +}; + +/* eof - MiscNumberOfInstallableLanguagesData.c */ diff --git a/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscOemString.uni b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscOemString.uni new file mode 100644 index 0000000000000000000000000000000000000000..fb79bdbde1e3f02b283f0b9e9a427560df4c15b4 GIT binary patch literal 1996 zcmchYO>YxH42FG1;yJn+1pW+xj| z38bnT?TkI+v0r;^@9$rAt6O3R_LA|`p1{@1HL(+0*f(2SVYyB1+E&Oux1qgYePgc~ zZ|xOyW^>NQb_1_7I{c$3&MxP&Zvv2<>1OE4F9%RI6gdtH3Y*-gM- zfP3mb%;5X@Fk)RHF?N1P92Pc1QfF)K&5=*ok=N3jL*2Nx|Mxwj@1sc;Z_qb{nmcM? z*7g-y2ZHLPQ&@SiGJ{`M}S z|KSlGG7E1tW;ys|Lop3em-QvQVmAQ!CVTWY;dSKEgp=^1^5Z8`yEv<{3U9JTYTyx> z;8lo6O+!)`s)q)ZhMfMD$l^lKqxrOY91LZTF$ceujNnYdOv~oV?VY z&~=fOjPM1i_s9z8SJsc5$VcHy@2muWQ~OftiP|%wc0t9;=BanN`@D(hBXv%GkG$Sg zc}?nNMhzU5|A;6lt><39L!zgyzr?D#%ar?l<}ubkQ@urbJK3U+yJzIi8{1N{ z@{G~N#_87Wh@*|2TgS2a^PD-i@=9IbqxXTfqK#^?A>5B8q# zqrGFD*_5-9U9;Amf?FDU?B=Yd>_7LnvL>+ua0ywoV&>GyW?(Mto^fbZ_PW@Zvzvgw z0QaTaFoEu2!;pCn$H?gcez>s-oH|=@Zwi0Hj;xm4oYl2U`+wUb`W}*`@fvvpR#QhU zEGtaXI9#H-XPv{_vp%El-8pjMiRc5qiDO$yku|b0FJmS@+}L>SUfoWt0sUT z^bhXQ0i*D4`YZ>ZbjYW{>(V}hmhbu?UuBPC6QU!F#+-zR%8s9KZR6bZRfx#~uD*L@ zj8(xa!lc`qUqr8rpA+GIuM5>e@W1XC9*rup3gTYdiqDLlKDG>PZ|kIrlq>#Coli$a z^iL=A`6Na3T|2TAFSV^>E&IZFV8_rIIhc@zn!D^~R<~1Dsb}V?HJMZPl`la;%-W3Z zl)`c1l3T3Q9W+*$C09}_%yp+lslWZ}7tx<1N%~ukEwOXtb=-y~`x*MBt>rj7P_j~c zLf3^?Ji-^aKEo@VKbXIAA{&J(U1|yTruMy*6QyT(txd&BXT!VPW7b6Uadk|7553-0 zc}?nNLJjPfZ$#vj)MKyT0s2%GbAJn_bd?dcGWR{b6so^s*(by6P_;95i&AQ`wmR@S zQcqC-n6K$x=aTkUd|e{fSi2qZbwF|N_*O5{(X!hJ&EgTcd(`jl@=cViAn%jy_)64H z*|9?Z4_SGEFO)rpcHwcXGb#fb(8|vw; eeLSi6L9an$X`kMRK+W)%I_WK53pQ6u)PDf<9s|Yz literal 0 HcmV?d00001 diff --git a/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscOnboardDeviceData.c b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscOnboardDeviceData.c new file mode 100644 index 0000000000..e7fa04a29b --- /dev/null +++ b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscOnboardDeviceData.c @@ -0,0 +1,36 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + MiscOnboardDeviceData.c + +Abstract: + + This driver parses the mMiscSubclassDataTable structure and reports + any generated data to the DataHub. + +--*/ + +#include "MiscSubclassDriver.h" + +// +// Static (possibly build generated) Bios Vendor data. +// +MISC_SUBCLASS_TABLE_DATA(EFI_MISC_ONBOARD_DEVICE_DATA, MiscOnboardDevice) = { + STRING_TOKEN(STR_MISC_ONBOARD_DEVICE_DESCRIPTION), // OnBoardDeviceDescription + { // OnBoardDeviceStatus + EfiOnBoardDeviceTypeOther, // DeviceType + 0, // DeviceEnabled + 0 // Reserved + }, + 0 // OnBoardDevicePath +}; diff --git a/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscOnboardDeviceFunction.c b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscOnboardDeviceFunction.c new file mode 100644 index 0000000000..d96b6cc2ad --- /dev/null +++ b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscOnboardDeviceFunction.c @@ -0,0 +1,164 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + MiscOnboardDeviceFunction.c + +Abstract: + + Onboard device information boot time changes. + Misc. subclass type 8. + SMBIOS type 10. + +--*/ + +#include "MiscSubclassDriver.h" +#include "winntio/winntio.h" +#include "winntthunk/winntthunk.h" + +#pragma pack(1) + +typedef struct _VENDOR_DEVICE { + EFI_DEVICE_PATH_PROTOCOL Platform; + EFI_GUID PlatformGuid; + EFI_DEVICE_PATH_PROTOCOL Device; + EFI_GUID DeviceGuid; + UINT8 DeviceData[4]; + EFI_DEVICE_PATH_PROTOCOL End; + +} VENDOR_DEVICE; +#pragma pack() + +MISC_SUBCLASS_TABLE_FUNCTION ( + MiscOnboardDeviceVideo + ) +/*++ +Description: + + This function makes boot time changes to the contents of the + MiscOnboardDevice structure. + +Parameters: + + RecordType + Type of record to be processed from the Data Table. + mMiscSubclassDataTable[].RecordType + + RecordLen + Size of static RecordData from the Data Table. + mMiscSubclassDataTable[].RecordLen + + RecordData + Pointer to copy of RecordData from the Data Table. Changes made + to this copy will be written to the Data Hub but will not alter + the contents of the static Data Table. + + LogRecordData + Set *LogRecordData to TRUE to log RecordData to Data Hub. + Set *LogRecordData to FALSE when there is no more data to log. + +Returns: + + EFI_SUCCESS + All parameters were valid and *RecordData and *LogRecordData have + been set. + + EFI_UNSUPPORTED + Unexpected RecordType value. + + EFI_INVALID_PARAMETER + One of the following parameter conditions was true: + RecordLen was zero. + RecordData was NULL. + LogRecordData was NULL. +--*/ +{ + STATIC VENDOR_DEVICE mVideoDevicePath = { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + 0x14 + }, + EFI_WIN_NT_THUNK_PROTOCOL_GUID, + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + 0x18 + }, + EFI_WIN_NT_UGA_GUID, + 0, + 0, + 0, + 0, + END + }; + + STATIC BOOLEAN Done = FALSE; + + // + // First check for invalid parameters. + // + if (RecordLen == 0 || RecordData == NULL || LogRecordData == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Then check for unsupported RecordType. + // + if (RecordType != EFI_MISC_ONBOARD_DEVICE_DATA_RECORD_NUMBER) { + return EFI_UNSUPPORTED; + } + // + // Is this the first time through this function? + // + if (!Done) { + // + // Yes, this is the first time. Inspect/Change the contents of the + // RecordData structure. + // + // + // Any time changes? + // + // %%TBD + // + // Set Done flag to TRUE for next pass through this function. + // Set *LogRecordData to TRUE so data will get logged to Data Hub. + // + switch (((EFI_MISC_ONBOARD_DEVICE_DATA *) RecordData)->OnBoardDeviceDescription) { + case STR_MISC_ONBOARD_DEVICE_VIDEO_DESCRIPTION: + { + CopyMem ( + &((EFI_MISC_ONBOARD_DEVICE_DATA *) RecordData)->OnBoardDevicePath, + &mVideoDevicePath, + GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) &mVideoDevicePath) + ); + *RecordLen = *RecordLen - sizeof (EFI_DEVICE_PATH_PROTOCOL) + GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) &mVideoDevicePath); + } + break; + } + + Done = TRUE; + *LogRecordData = TRUE; + } else { + // + // No, this is the second time. Reset the state of the Done flag + // to FALSE and tell the data logger that there is no more data + // to be logged for this record type. If any memory allocations + // were made by earlier passes, they must be released now. + // + Done = FALSE; + *LogRecordData = FALSE; + } + + return EFI_SUCCESS; +} + +/* eof - MiscOnboardDeviceFunction.c */ diff --git a/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscPortInternalConnectorDesignator.uni b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscPortInternalConnectorDesignator.uni new file mode 100644 index 0000000000000000000000000000000000000000..b6a617b75e642448050d86572f9207ae92b33785 GIT binary patch literal 9426 zcmc&)ZBH9V5T4JK`X5e?Dz#|?!67J#)DO0?!GJl-n38-##x}$f*wNXL`p>t0o*B+} z_LchfSW}(wzTEE4%rkGhd;I;^wroovujN-fKgthiZ7<3|YBG^;GM7k3awA`5hOs|O zUw%PZmbZBJdSM2e}lhB5`ukv!mc zAY16`LdFq#1MnY#?;Dlj4(%Rf7@(YC#8BIP;4qOpjO4pH=8Z8vKo6znx+BzXbv1X{ z6YhIhi4c+G~iLUX+ zG)g)C#Hdw1m$5RP%rWXp5xIs`h6;J&?Byrno)$lYhCiua&=(AU&W}_ZTUaZC-nUou zGeyr8WEsetl{Z^h{c{4Js6x?Ht{vZ`&i7~k?f3HKLR ziS$F|EszVW*HIZx(cc7pQVW&O4qB9wedMl-u^dDGY*Yhd$>$f8$9O{-$yfc6ipg7- z&x>`E)tf-A4UZ+weT{NYNt1A&)LO9bf%+Rg?-c%W2Os#f$Pvj%uG&)n?Sme@Vg{O) z7b295h0G0OJVW@-Ovmh_KEs{2SN7`)%Wd$0##Cz)e6n!l)peyUc$4@Ser}7>Iv?t%T~O%y8@QJ(3-a-2u|BTF)Zq zPW>3Vp2HI+(0v5|bmte;ho=p_NKUV7L6>n{TrYXqo9w%4*%e;{}82}5TXK_%UTViMAgY^D)Qc&$GB3r@jfD?tyFf56MnqKm9{^r zxf|(X|H|FSajwkhQ`@f8J930Q+Ai#k`~SI~*nH@o`?uOc^LgUKo;QnkrCmX8qvTH92M#<(P$#x~eOVk_X{T}EjRnsgn?NEy?hiKO3h;#yU0v_GN>!<5VlZV?4AQ@;55bC9o}{NjT=opzq#x!_kfC@oZ(7) z6_qx24O93#}(zF0q>f?et1LQ#tDY`o8NKL=NZ3NRRf)KAk|Q$@>o?g93s0jVE#nkYXrH2zS&%{&UV>tOhhBx)R z&3Cbr9dD7xojUKjnW=btx+zTT=DLAQcmQ0E;6?oEVBaOy$7NcLpFPiW_^_`N*RU7f zsxN=NK0*(__3}o=hYeML5WiuC&T;vJw{vAt9?~a?w8uRaqkZ6I_ZjXv%vW?SLf_^v z@~qEeJ}}}}!_R6@A?|DP`d-=F&bkPFo5TFRx%*1HGfz$%dA@Jhm=YqHznjbF@L_ZL qUpFPhao2B7+3aq%`3`HPpZ|{32_`#;U4F9sbNH~i<~c-!fByh;7-lm7 literal 0 HcmV?d00001 diff --git a/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscPortInternalConnectorDesignatorData.c b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscPortInternalConnectorDesignatorData.c new file mode 100644 index 0000000000..d886a9d8c4 --- /dev/null +++ b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscPortInternalConnectorDesignatorData.c @@ -0,0 +1,99 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + MiscPortInternalConnectorDesignatorData.c + +Abstract: + + This driver parses the mMiscSubclassDataTable structure and reports + any generated data to the DataHub. + +--*/ + +#include "MiscSubclassDriver.h" + +// +// Static (possibly build generated) Bios Vendor data. +// +MISC_SUBCLASS_TABLE_DATA(EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA, MiscPortInternalConnectorDesignator) = { + STRING_TOKEN(STR_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR), // PortInternalConnectorDesignator + STRING_TOKEN(STR_MISC_PORT_EXTERNAL_CONNECTOR_DESIGNATOR), // PortExternalConnectorDesignator + EfiPortConnectorTypeOther, // PortInternalConnectorType + EfiPortConnectorTypeOther, // PortExternalConnectorType + EfiPortTypeNone, // PortType + 0 // PortPath +}; + +// +// Static (possibly build generated) Bios Vendor data. +// +MISC_SUBCLASS_TABLE_DATA(EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA, MiscPortKeyboard) = { + STRING_TOKEN (STR_MISC_PORT_INTERNAL_KEYBOARD), // PortInternalConnectorDesignator + STRING_TOKEN (STR_MISC_PORT_EXTERNAL_KEYBOARD), // PortExternalConnectorDesignator + EfiPortConnectorTypeNone, // PortInternalConnectorType + EfiPortConnectorTypePS2, // PortExternalConnectorType + EfiPortTypeKeyboard, // PortType + // mPs2KbyboardDevicePath // PortPath + // + 0 +}; + +MISC_SUBCLASS_TABLE_DATA(EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA, MiscPortMouse) = { + STRING_TOKEN (STR_MISC_PORT_INTERNAL_MOUSE), // PortInternalConnectorDesignator + STRING_TOKEN (STR_MISC_PORT_EXTERNAL_MOUSE), // PortExternalConnectorDesignator + EfiPortConnectorTypeNone, // PortInternalConnectorType + EfiPortConnectorTypePS2, // PortExternalConnectorType + EfiPortTypeMouse, // PortType + // mPs2MouseDevicePath // PortPath + // + 0 +}; + + +MISC_SUBCLASS_TABLE_DATA(EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA, MiscPortCom1) = { + STRING_TOKEN(STR_MISC_PORT_INTERNAL_COM1), + STRING_TOKEN(STR_MISC_PORT_EXTERNAL_COM1), + EfiPortConnectorTypeNone, + EfiPortConnectorTypeDB9Female, + EfiPortTypeSerial16550ACompatible, + 0 +}; + +MISC_SUBCLASS_TABLE_DATA(EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA, MiscPortCom2) = { + STRING_TOKEN(STR_MISC_PORT_INTERNAL_COM2), + STRING_TOKEN(STR_MISC_PORT_EXTERNAL_COM2), + EfiPortConnectorTypeNone, + EfiPortConnectorTypeDB9Female, + EfiPortTypeSerial16550ACompatible, + 0 +}; + +MISC_SUBCLASS_TABLE_DATA(EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA, MiscPortExtensionPower) = { + STRING_TOKEN(STR_MISC_PORT_INTERNAL_EXTENSION_POWER), + STRING_TOKEN(STR_MISC_PORT_EXTERNAL_EXTENSION_POWER), + EfiPortConnectorTypeOther, + EfiPortConnectorTypeNone, + EfiPortTypeOther, + 0 +}; + +MISC_SUBCLASS_TABLE_DATA(EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA, MiscPortFloppy) = { + STRING_TOKEN(STR_MISC_PORT_INTERNAL_FLOPPY), + STRING_TOKEN(STR_MISC_PORT_EXTERNAL_FLOPPY), + EfiPortConnectorTypeOnboardFloppy, + EfiPortConnectorTypeNone, + EfiPortTypeOther, + 0 +}; + +/* eof - MiscPortInternalConnectorDesignatorData.c */ diff --git a/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscPortInternalConnectorDesignatorFunction.c b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscPortInternalConnectorDesignatorFunction.c new file mode 100644 index 0000000000..a57c18c69b --- /dev/null +++ b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscPortInternalConnectorDesignatorFunction.c @@ -0,0 +1,266 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + MiscPortInternalConnectorDesignatorFunction.c + +Abstract: + + This driver parses the mMiscSubclassDataTable structure and reports + any generated data to the DataHub. + +--*/ + +#include "MiscSubclassDriver.h" + +// +// +// +MISC_SUBCLASS_TABLE_FUNCTION ( + MiscPortInternalConnectorDesignator + ) +/*++ +Description: + + This function makes boot time changes to the contents of the + MiscPortConnectorInformation (Type 8). + +Parameters: + + RecordType + Type of record to be processed from the Data Table. + mMiscSubclassDataTable[].RecordType + + RecordLen + Size of static RecordData from the Data Table. + mMiscSubclassDataTable[].RecordLen + + RecordData + Pointer to copy of RecordData from the Data Table. Changes made + to this copy will be written to the Data Hub but will not alter + the contents of the static Data Table. + + LogRecordData + Set *LogRecordData to TRUE to log RecordData to Data Hub. + Set *LogRecordData to FALSE when there is no more data to log. + +Returns: + + EFI_SUCCESS + All parameters were valid and *RecordData and *LogRecordData have + been set. + + EFI_UNSUPPORTED + Unexpected RecordType value. + + EFI_INVALID_PARAMETER + One of the following parameter conditions was true: + RecordLen was zero. + RecordData was NULL. + LogRecordData was NULL. +--*/ +{ + STATIC BOOLEAN Done = FALSE; + STATIC PS2_CONN_DEVICE_PATH mPs2KeyboardDevicePath = { ACPI, PCI (0x1F, 0x00), LPC (0x0303, 0), END }; + STATIC PS2_CONN_DEVICE_PATH mPs2MouseDevicePath = { ACPI, PCI (0x1F, 0x00), LPC (0x0303, 1), END }; + STATIC SERIAL_CONN_DEVICE_PATH mCom1DevicePath = { ACPI, PCI (0x1F, 0x00), LPC (0x0501, 0), END }; + STATIC SERIAL_CONN_DEVICE_PATH mCom2DevicePath = { ACPI, PCI (0x1F, 0x00), LPC (0x0501, 1), END }; + STATIC PARALLEL_CONN_DEVICE_PATH mLpt1DevicePath = { ACPI, PCI (0x1F, 0x00), LPC (0x0401, 0), END }; + STATIC FLOOPY_CONN_DEVICE_PATH mFloopyADevicePath = { ACPI, PCI (0x1F, 0x00), LPC (0x0604, 0), END }; + STATIC FLOOPY_CONN_DEVICE_PATH mFloopyBDevicePath = { ACPI, PCI (0x1F, 0x00), LPC (0x0604, 1), END }; + STATIC USB_PORT_DEVICE_PATH mUsb0DevicePath = { ACPI, PCI (0x1d, 0x00), END }; + STATIC USB_PORT_DEVICE_PATH mUsb1DevicePath = { ACPI, PCI (0x1d, 0x01), END }; + STATIC USB_PORT_DEVICE_PATH mUsb2DevicePath = { ACPI, PCI (0x1d, 0x02), END }; + STATIC USB_PORT_DEVICE_PATH mUsb3DevicePath = { ACPI, PCI (0x1d, 0x07), END }; + STATIC IDE_DEVICE_PATH mIdeDevicePath = { ACPI, PCI (0x1F, 0x01), END }; + STATIC GB_NIC_DEVICE_PATH mGbNicDevicePath = { ACPI, PCI( 0x03,0x00 ),PCI( 0x1F,0x00 ),PCI( 0x07,0x00 ), END }; + EFI_DEVICE_PATH_PROTOCOL EndDevicePath = END; + + // + // First check for invalid parameters. + // + // Shanmu >> to fix the Device Path Issue... + // if (RecordLen == 0 || RecordData == NULL || LogRecordData == NULL) { + // + if (*RecordLen == 0 || RecordData == NULL || LogRecordData == NULL) { + // + // End Shanmu + // + return EFI_INVALID_PARAMETER; + } + // + // Then check for unsupported RecordType. + // + if (RecordType != EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_RECORD_NUMBER) { + return EFI_UNSUPPORTED; + } + // + // Is this the first time through this function? + // + if (!Done) { + // + // Yes, this is the first time. Inspect/Change the contents of the + // RecordData structure. + // + // + // Device path is only updated here as it was not taking that in static data + // + // Shanmu >> to fix the Device Path Issue... + // + + /* + switch (((EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA *)RecordData)->PortInternalConnectorDesignator) + { + case STR_MISC_PORT_INTERNAL_MOUSE: + { + (EFI_DEVICE_PATH_PROTOCOL)((EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA *)RecordData)->PortPath = *((EFI_DEVICE_PATH_PROTOCOL*)&mPs2MouseDevicePath); + }break; + case STR_MISC_PORT_INTERNAL_KEYBOARD: + { + (EFI_DEVICE_PATH_PROTOCOL)((EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA *)RecordData)->PortPath = *((EFI_DEVICE_PATH_PROTOCOL*)&mPs2KeyboardDevicePath); + }break; + case STR_MISC_PORT_INTERNAL_COM1: + { + (EFI_DEVICE_PATH_PROTOCOL)((EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA *)RecordData)->PortPath = *((EFI_DEVICE_PATH_PROTOCOL*)&mCom1DevicePath); + }break; + case STR_MISC_PORT_INTERNAL_COM2: + { + (EFI_DEVICE_PATH_PROTOCOL)((EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA *)RecordData)->PortPath = *((EFI_DEVICE_PATH_PROTOCOL*)&mCom2DevicePath); + }break; + case STR_MISC_PORT_INTERNAL_LPT1: + { + (EFI_DEVICE_PATH_PROTOCOL)((EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA *)RecordData)->PortPath = *((EFI_DEVICE_PATH_PROTOCOL*)&mLpt1DevicePath); + }break; + case STR_MISC_PORT_INTERNAL_USB1: + { + (EFI_DEVICE_PATH_PROTOCOL)((EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA *)RecordData)->PortPath = *((EFI_DEVICE_PATH_PROTOCOL*)&mUsb0DevicePath); + }break; + case STR_MISC_PORT_INTERNAL_USB2: + { + (EFI_DEVICE_PATH_PROTOCOL)((EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA *)RecordData)->PortPath = *((EFI_DEVICE_PATH_PROTOCOL*)&mUsb1DevicePath); + }break; + case STR_MISC_PORT_INTERNAL_USB3: + { + (EFI_DEVICE_PATH_PROTOCOL)((EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA *)RecordData)->PortPath = *((EFI_DEVICE_PATH_PROTOCOL*)&mUsb2DevicePath); + }break; + case STR_MISC_PORT_INTERNAL_NETWORK: + { + (EFI_DEVICE_PATH_PROTOCOL)((EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA *)RecordData)->PortPath = *((EFI_DEVICE_PATH_PROTOCOL*)&mGbNicDevicePath); + }break; + case STR_MISC_PORT_INTERNAL_FLOPPY: + { + (EFI_DEVICE_PATH_PROTOCOL)((EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA *)RecordData)->PortPath = *((EFI_DEVICE_PATH_PROTOCOL*)&mFloopyADevicePath); + }break; + case STR_MISC_PORT_INTERNAL_IDE1: + { + (EFI_DEVICE_PATH_PROTOCOL)((EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA *)RecordData)->PortPath = *((EFI_DEVICE_PATH_PROTOCOL*)&mIdeDevicePath); + }break; + case STR_MISC_PORT_INTERNAL_IDE2: + { + (EFI_DEVICE_PATH_PROTOCOL)((EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA *)RecordData)->PortPath = *((EFI_DEVICE_PATH_PROTOCOL*)&mIdeDevicePath); + }break; + default: + { + (EFI_DEVICE_PATH_PROTOCOL)((EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA *)RecordData)->PortPath = EndDevicePath; + }break; + } + */ + switch (((EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA *) RecordData)->PortInternalConnectorDesignator) { + case STR_MISC_PORT_INTERNAL_MOUSE: + { + CopyMem ( + &((EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA *) RecordData)->PortPath, + &mPs2MouseDevicePath, + GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) &mPs2MouseDevicePath) + ); + *RecordLen = *RecordLen - sizeof (EFI_MISC_PORT_DEVICE_PATH) + GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) &mPs2MouseDevicePath); + } + break; + + case STR_MISC_PORT_INTERNAL_KEYBOARD: + { + CopyMem ( + &((EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA *) RecordData)->PortPath, + &mPs2KeyboardDevicePath, + GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) &mPs2KeyboardDevicePath) + ); + *RecordLen = *RecordLen - sizeof (EFI_MISC_PORT_DEVICE_PATH) + GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) &mPs2KeyboardDevicePath); + } + break; + + case STR_MISC_PORT_INTERNAL_COM1: + { + CopyMem ( + &((EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA *) RecordData)->PortPath, + &mCom1DevicePath, + GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) &mCom1DevicePath) + ); + *RecordLen = *RecordLen - sizeof (EFI_MISC_PORT_DEVICE_PATH) + GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) &mCom1DevicePath); + } + break; + + case STR_MISC_PORT_INTERNAL_COM2: + { + CopyMem ( + &((EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA *) RecordData)->PortPath, + &mCom2DevicePath, + GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) &mCom2DevicePath) + ); + *RecordLen = *RecordLen - sizeof (EFI_MISC_PORT_DEVICE_PATH) + GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) &mCom2DevicePath); + } + break; + + case STR_MISC_PORT_INTERNAL_FLOPPY: + { + CopyMem ( + &((EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA *) RecordData)->PortPath, + &mFloopyADevicePath, + GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) &mFloopyADevicePath) + ); + *RecordLen = *RecordLen - sizeof (EFI_MISC_PORT_DEVICE_PATH) + GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) &mFloopyADevicePath); + } + break; + + default: + { + CopyMem ( + &((EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA *) RecordData)->PortPath, + &EndDevicePath, + GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) &EndDevicePath) + ); + *RecordLen = *RecordLen - sizeof (EFI_MISC_PORT_DEVICE_PATH) + GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) &EndDevicePath); + } + break; + } + // + // End Shanmu + // + // Set Done flag to TRUE for next pass through this function. + // Set *LogRecordData to TRUE so data will get logged to Data Hub. + // + Done = TRUE; + *LogRecordData = TRUE; + } else { + // + // No, this is the second time. Reset the state of the Done flag + // to FALSE and tell the data logger that there is no more data + // to be logged for this record type. If any memory allocations + // were made by earlier passes, they must be released now. + // + Done = FALSE; + *LogRecordData = FALSE; + } + + return EFI_SUCCESS; +} + +/* eof - MiscSystemManufacturerFunction.c */ diff --git a/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscResetCapabilitiesData.c b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscResetCapabilitiesData.c new file mode 100644 index 0000000000..6e0c1bb5ad --- /dev/null +++ b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscResetCapabilitiesData.c @@ -0,0 +1,42 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + MiscResetCapabilitiesData.c + +Abstract: + + This driver parses the mMiscSubclassDataTable structure and reports + any generated data to the DataHub. + +--*/ + +#include "MiscSubclassDriver.h" + +// +// Static (possibly build generated) Bios Vendor data. +// +MISC_SUBCLASS_TABLE_DATA(EFI_MISC_RESET_CAPABILITIES, MiscResetCapabilities) = { + { // ResetCapabilities + 0, // Status + 0, // BootOption + 0, // BootOptionOnLimit + 0, // WatchdogTimerPresent + 0 // Reserved + }, + 0, // ResetCount + 0, // ResetLimit + 0, // ResetTimerInterval + 0 // ResetTimeout +}; + +/* eof - MiscResetCapabilities.c */ diff --git a/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSubclassDriver.dxs b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSubclassDriver.dxs new file mode 100644 index 0000000000..8698317e55 --- /dev/null +++ b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSubclassDriver.dxs @@ -0,0 +1,27 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + MiscSubclassDriver.dxs + +Abstract: + + Dependency expression file for MiscSubclass Driver. + +--*/ + +#include +#include + +DEPENDENCY_START + EFI_DATA_HUB_PROTOCOL_GUID AND EFI_HII_PROTOCOL_GUID +DEPENDENCY_END diff --git a/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSubclassDriver.h b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSubclassDriver.h new file mode 100644 index 0000000000..32f591fdf1 --- /dev/null +++ b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSubclassDriver.h @@ -0,0 +1,104 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + MiscSubclassDriver.h + +Abstract: + + Header file for MiscSubclass Driver. + +--*/ + +#ifndef _MISC_SUBCLASS_DRIVER_H +#define _MISC_SUBCLASS_DRIVER_H + + +#include + +// +// Autogen string file +// +#include + +// +// Data table entry update function. +// +typedef +EFI_STATUS +(EFIAPI EFI_MISC_SUBCLASS_DATA_FUNCTION) ( + IN UINT16 RecordType, + IN UINT32 *RecordLen, + IN OUT EFI_MISC_SUBCLASS_RECORDS *RecordData, + OUT BOOLEAN *LogRecordData + ); + +// +// Data table entry definition. +// +typedef struct { + UINT16 RecordType; + UINT32 RecordLen; + VOID *RecordData; + EFI_MISC_SUBCLASS_DATA_FUNCTION *Function; +} EFI_MISC_SUBCLASS_DATA_TABLE; + +// +// Data Table extern definitions. +// +#define MISC_SUBCLASS_TABLE_EXTERNS(NAME1, NAME2) \ + extern NAME1 NAME2 ## Data; \ + extern EFI_MISC_SUBCLASS_DATA_FUNCTION NAME2 ## Function + +// +// Data Table entries +// +#define MISC_SUBCLASS_TABLE_ENTRY_DATA_ONLY(NAME1, NAME2) { \ + NAME1 ## _RECORD_NUMBER, sizeof (NAME1 ## _DATA), &NAME2 ## Data, NULL \ + } + +#define MISC_SUBCLASS_TABLE_ENTRY_FUNCTION_ONLY(NAME1, NAME2) \ + { \ + NAME1 ## _RECORD_NUMBER, 0, NULL, &NAME2 ## Function \ + } + +#define MISC_SUBCLASS_TABLE_ENTRY_DATA_AND_FUNCTION(NAME1, NAME2, NAME3) \ + { \ + NAME1 ## _RECORD_NUMBER, sizeof (NAME1 ## _DATA), &NAME2 ## Data, &NAME3 ## Function \ + } + +// +// Global definition macros. +// +#define MISC_SUBCLASS_TABLE_DATA(NAME1, NAME2) NAME1 NAME2 ## Data + +#define MISC_SUBCLASS_TABLE_FUNCTION(NAME2) \ + EFI_STATUS EFIAPI NAME2 ## Function ( \ + IN UINT16 RecordType, \ + IN UINT32 *RecordLen, \ + IN OUT EFI_MISC_SUBCLASS_RECORDS * RecordData, \ + OUT BOOLEAN *LogRecordData \ + ) + +// +// Data Table Array +// +extern EFI_MISC_SUBCLASS_DATA_TABLE mMiscSubclassDataTable[]; + +// +// Data Table Array Entries +// +extern UINTN mMiscSubclassDataTableEntries; + +#endif /* _MISC_SUBCLASS_DRIVER_H */ + +/* eof - MiscSubclassDriver.h */ diff --git a/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSubclassDriver.mbd b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSubclassDriver.mbd new file mode 100644 index 0000000000..921c5c5e41 --- /dev/null +++ b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSubclassDriver.mbd @@ -0,0 +1,45 @@ + + + + + MiscSubclass + 4A9B9DB8-EC62-4A92-818F-8AA0246D246E + 0 + FIX ME! + Copyright (c) 2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-13 17:07 + 2006-03-23 13:50 + + + UefiBootServicesTableLib + BaseLib + UefiLib + HiiLib + UefiMemoryLib + UefiDriverEntryPoint + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + DxeMemoryAllocationLib + UefiDevicePathLib + + + _ModuleEntryPoint + + diff --git a/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSubclassDriver.msa b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSubclassDriver.msa new file mode 100644 index 0000000000..fb5252f0c0 --- /dev/null +++ b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSubclassDriver.msa @@ -0,0 +1,114 @@ + + + + + MiscSubclass + DXE_DRIVER + BS_DRIVER + 4A9B9DB8-EC62-4A92-818F-8AA0246D246E + 0 + Component description file for MiscSubclass Driver module + FIX ME! + Copyright (c) 2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-13 17:07 + 2006-03-23 13:50 + + + BaseLib + DebugLib + HiiLib + UefiLib + UefiDriverEntryPoint + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + DevicePathLib + + + MiscSubclassDriver.uni + MiscSubclassDriver.h + MiscSubclassDriverEntryPoint.c + MiscSubclassDriverDataTable.c + MiscBaseBoardManufacturerData.c + MiscBiosVendorData.c + MiscBootInformationData.c + MiscChassisManufacturerData.c + MiscNumberOfInstallableLanguagesData.c + MiscOemStringData.c + MiscOnboardDeviceData.c + MiscPortInternalConnectorDesignatorData.c + MiscResetCapabilitiesData.c + MiscSystemLanguageStringData.c + MiscSystemManufacturerData.c + MiscSystemManufacturerFunction.c + MiscSystemOptionStringData.c + MiscSystemSlotDesignationData.c + MiscPortInternalConnectorDesignatorFunction.c + MiscSubclassDriver.dxs + + + MdePkg + EdkModulePkg + EdkNt32Pkg + + + DataHub + Hii + WinNtIo + + + MiscPortKeyboard + MiscPortMouse + MiscPortCom1 + MiscPortCom2 + MiscBiosVendor + MiscSystemManufacturer + MiscBaseBoardManufacturer + MiscChassisManufacturer + MiscSystemSlotDesignation + OemString + SystemOptionString + ProcessorSubClassData + MemorySubClassData + + + + MiscSubClass + + + ProcessorSubClass + + + MemoryProducer + + + MemorySubClass + + + WinNtMemory + + + + + MiscSubclassDriverEntryPoint + + + diff --git a/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSubclassDriver.uni b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSubclassDriver.uni new file mode 100644 index 0000000000000000000000000000000000000000..1d6899c81cfc33c9da425a1f597f4fe56849380f GIT binary patch literal 2846 zcmchZU2jrB5QgX4#Q$(YZ?sx!yzrul7cHPAw$K2zde!h%N>Zpf2deye^?7GG>;cn+ z+NL>ScXoGn=AF;w&+mQPx5Res4c|+9!D@dsCswgr`(X=9ZEPdEwi&#ytZ%QG-`hLB z5B3(iZd1;Nb_18b4wk6ypvUlbt;eW)b4M;b5q-cnacsF1StA?AtC-0Tw{}&ycVum=vOZbE@~?Ff z{ZIF3pHX<%eKrQ4bjYW{>(ZXFmhXBX&$CCd3DJ>7SDb{1%8p-fZQ@+_Rfx#~uAY13 z3af%wgh{v8zldHLKO@2iUKgr`;D6muJsM?XrNn)IBR&~BJ!~1+-o{B8DcAhgbw1rH zqJKJ>&nGFO@7S@`@Y0#JtZAPa5ABq7og7TaLd_j^>vm-4P&LoYb89fy*jK&;2{CKy zbf+2|ZI|4HQg_f;VwPM%G}y1BU)q|Ev&BkQ zYES4o@QO$H0@o*ah4VY}7fxiOaMhMtg1t5SwvrR2*YVmJ6)T-p?{fE96VXTNl>8oe zy{YmV)XRh#I9Rt}fMFZcc=gr+agEbs_!xXoM&C9$Oo4D)%@27wUgKQmW;@vk8$Y literal 0 HcmV?d00001 diff --git a/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSubclassDriverDataTable.c b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSubclassDriverDataTable.c new file mode 100644 index 0000000000..c2d149631a --- /dev/null +++ b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSubclassDriverDataTable.c @@ -0,0 +1,103 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + MiscSubclassDriverDataTable.c + +Abstract: + + This driver parses the mMiscSubclassDataTable structure and reports + any generated data to the DataHub. + +--*/ + +#include "MiscSubclassDriver.h" + +// +// External definitions referenced by Data Table entries. +// +MISC_SUBCLASS_TABLE_EXTERNS ( + EFI_MISC_CHASSIS_MANUFACTURER_DATA, + MiscChassisManufacturer + ); +MISC_SUBCLASS_TABLE_EXTERNS ( + EFI_MISC_BIOS_VENDOR_DATA, + MiscBiosVendor + ); +MISC_SUBCLASS_TABLE_EXTERNS ( + EFI_MISC_SYSTEM_MANUFACTURER_DATA, + MiscSystemManufacturer + ); +MISC_SUBCLASS_TABLE_EXTERNS ( + EFI_MISC_BASE_BOARD_MANUFACTURER_DATA, + MiscBaseBoardManufacturer + ); +MISC_SUBCLASS_TABLE_EXTERNS ( + EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA, + MiscPortInternalConnectorDesignator + ); +MISC_SUBCLASS_TABLE_EXTERNS ( + EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA, + MiscPortKeyboard + ); +MISC_SUBCLASS_TABLE_EXTERNS ( + EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA, + MiscPortMouse + ); +MISC_SUBCLASS_TABLE_EXTERNS ( + EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA, + MiscPortCom1 + ); +MISC_SUBCLASS_TABLE_EXTERNS ( + EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA, + MiscPortCom2 + ); +MISC_SUBCLASS_TABLE_EXTERNS ( + EFI_MISC_SYSTEM_SLOT_DESIGNATION_DATA, + MiscSystemSlotDesignation + ); +MISC_SUBCLASS_TABLE_EXTERNS ( + EFI_MISC_ONBOARD_DEVICE_DATA, + MiscOnboardDevice + ); +MISC_SUBCLASS_TABLE_EXTERNS ( + EFI_MISC_OEM_STRING_DATA, + OemString + ); +MISC_SUBCLASS_TABLE_EXTERNS ( + EFI_MISC_SYSTEM_OPTION_STRING_DATA, + SystemOptionString + ); + +// +// Data Table. +// +EFI_MISC_SUBCLASS_DATA_TABLE mMiscSubclassDataTable[] = { + MISC_SUBCLASS_TABLE_ENTRY_DATA_AND_FUNCTION(EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR, MiscPortKeyboard, MiscPortInternalConnectorDesignator), + MISC_SUBCLASS_TABLE_ENTRY_DATA_AND_FUNCTION(EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR, MiscPortMouse, MiscPortInternalConnectorDesignator), + MISC_SUBCLASS_TABLE_ENTRY_DATA_AND_FUNCTION(EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR, MiscPortCom1, MiscPortInternalConnectorDesignator), + MISC_SUBCLASS_TABLE_ENTRY_DATA_AND_FUNCTION(EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR, MiscPortCom2, MiscPortInternalConnectorDesignator), + MISC_SUBCLASS_TABLE_ENTRY_DATA_ONLY(EFI_MISC_BIOS_VENDOR, MiscBiosVendor), + MISC_SUBCLASS_TABLE_ENTRY_DATA_ONLY(EFI_MISC_SYSTEM_MANUFACTURER, MiscSystemManufacturer), + MISC_SUBCLASS_TABLE_ENTRY_DATA_ONLY(EFI_MISC_BASE_BOARD_MANUFACTURER, MiscBaseBoardManufacturer), + MISC_SUBCLASS_TABLE_ENTRY_DATA_ONLY(EFI_MISC_CHASSIS_MANUFACTURER, MiscChassisManufacturer), + MISC_SUBCLASS_TABLE_ENTRY_DATA_ONLY(EFI_MISC_SYSTEM_SLOT_DESIGNATION, MiscSystemSlotDesignation), + MISC_SUBCLASS_TABLE_ENTRY_DATA_ONLY(EFI_MISC_OEM_STRING, OemString), + MISC_SUBCLASS_TABLE_ENTRY_DATA_ONLY(EFI_MISC_SYSTEM_OPTION_STRING, SystemOptionString), +}; + +// +// Number of Data Table entries. +// +UINTN mMiscSubclassDataTableEntries = (sizeof mMiscSubclassDataTable) / sizeof (EFI_MISC_SUBCLASS_DATA_TABLE); + +/* eof - MiscSubclassDriverDataTable.c */ diff --git a/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSubclassDriverEntryPoint.c b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSubclassDriverEntryPoint.c new file mode 100644 index 0000000000..f0e09a6152 --- /dev/null +++ b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSubclassDriverEntryPoint.c @@ -0,0 +1,518 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + MiscSubclassDriverEntryPoint.c + +Abstract: + + This driver parses the mMiscSubclassDataTable structure and reports + any generated data to the DataHub. + +--*/ + +#include "MiscSubclassDriver.h" + + +extern UINT8 MiscSubclassStrings[]; + +VOID +EFIAPI +WinNtIoProtocolNotifyFunction ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +// +// +// +EFI_STATUS +LogRecordDataToDataHub ( + EFI_DATA_HUB_PROTOCOL *DataHub, + UINT32 RecordType, + UINT32 RecordLen, + VOID *RecordData + ) +/*++ +Description: + +Parameters: + + DataHub + %%TBD + + RecordType + %%TBD + + RecordLen + %%TBD + + RecordData + %%TBD + +Returns: + + EFI_INVALID_PARAMETER + + EFI_SUCCESS + + Other Data Hub errors + +--*/ +{ + EFI_MISC_SUBCLASS_DRIVER_DATA MiscSubclass; + EFI_STATUS EfiStatus; + + // + // Do nothing if data parameters are not valid. + // + if (RecordLen == 0 || RecordData == NULL) { + DEBUG ( + (EFI_D_ERROR, + "RecordLen == %d RecordData == %xh\n", + RecordLen, + RecordData) + ); + + return EFI_INVALID_PARAMETER; + } + // + // Assemble Data Hub record. + // + MiscSubclass.Header.Version = EFI_MISC_SUBCLASS_VERSION; + MiscSubclass.Header.HeaderSize = sizeof (EFI_SUBCLASS_TYPE1_HEADER); + MiscSubclass.Header.Instance = 1; + MiscSubclass.Header.SubInstance = 1; + MiscSubclass.Header.RecordType = RecordType; + + CopyMem ( + &MiscSubclass.Record, + RecordData, + RecordLen + ); + + // + // Log Data Hub record. + // + EfiStatus = DataHub->LogData ( + DataHub, + &gEfiMiscSubClassGuid, + &gEfiMiscSubClassGuid, + EFI_DATA_RECORD_CLASS_DATA, + &MiscSubclass, + sizeof (EFI_SUBCLASS_TYPE1_HEADER) + RecordLen + ); + + if (EFI_ERROR (EfiStatus)) { + DEBUG ( + (EFI_D_ERROR, + "LogData(%d bytes) == %r\n", + sizeof (EFI_SUBCLASS_TYPE1_HEADER) + RecordLen, + EfiStatus) + ); + } + + return EfiStatus; +} + + +EFI_STATUS +EFIAPI +MiscSubclassDriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ +Description: + + Standard EFI driver point. This driver parses the mMiscSubclassDataTable + structure and reports any generated data to the DataHub. + +Arguments: + + ImageHandle + Handle for the image of this driver + + SystemTable + Pointer to the EFI System Table + +Returns: + + EFI_SUCCESS + The data was successfully reported to the Data Hub. + +--*/ +{ + EFI_MISC_SUBCLASS_DRIVER_DATA RecordData; + EFI_DATA_HUB_PROTOCOL *DataHub; + EFI_HII_PROTOCOL *Hii; + EFI_HII_PACKAGES *PackageList; + EFI_HII_HANDLE HiiHandle; + EFI_STATUS EfiStatus; + UINTN Index; + BOOLEAN LogRecordData; + EFI_EVENT Event; + VOID *Registration; + + + // + // Initialize constant portion of subclass header. + // + RecordData.Header.Version = EFI_MISC_SUBCLASS_VERSION; + RecordData.Header.HeaderSize = sizeof (EFI_SUBCLASS_TYPE1_HEADER); + RecordData.Header.Instance = 1; + RecordData.Header.SubInstance = 1; + + // + // Locate data hub protocol. + // + EfiStatus = gBS->LocateProtocol (&gEfiDataHubProtocolGuid, NULL, &DataHub); + + if (EFI_ERROR (EfiStatus)) { + DEBUG ((EFI_D_ERROR, "Could not locate DataHub protocol. %r\n", EfiStatus)); + return EfiStatus; + } else if (DataHub == NULL) { + DEBUG ((EFI_D_ERROR, "LocateProtocol(DataHub) returned NULL pointer!\n")); + return EFI_DEVICE_ERROR; + } + // + // Locate hii protocol. + // + EfiStatus = gBS->LocateProtocol (&gEfiHiiProtocolGuid, NULL, &Hii); + + if (EFI_ERROR (EfiStatus)) { + DEBUG ((EFI_D_ERROR, "Could not locate Hii protocol. %r\n", EfiStatus)); + return EfiStatus; + } else if (Hii == NULL) { + DEBUG ((EFI_D_ERROR, "LocateProtocol(Hii) returned NULL pointer!\n")); + return EFI_DEVICE_ERROR; + } + // + // Add our default strings to the HII database. They will be modified later. + // + PackageList = PreparePackages (1, &gEfiMiscSubClassGuid, MiscSubclassStrings); + EfiStatus = Hii->NewPack (Hii, PackageList, &HiiHandle); + gBS->FreePool (PackageList); + + if (EFI_ERROR (EfiStatus)) { + DEBUG ((EFI_D_ERROR, "Could not log default strings to Hii. %r\n", EfiStatus)); + return EfiStatus; + } + // + // + // + for (Index = 0; Index < mMiscSubclassDataTableEntries; ++Index) { + // + // Stupidity check! Do nothing if RecordLen is zero. + // %%TBD - Should this be an error or a mechanism for ignoring + // records in the Data Table? + // + if (mMiscSubclassDataTable[Index].RecordLen == 0) { + DEBUG ( + (EFI_D_ERROR, + "mMiscSubclassDataTable[%d].RecordLen == 0\n", + Index) + ); + + continue; + } + // + // Initialize per-record portion of subclass header and + // copy static data into data portion of subclass record. + // + RecordData.Header.RecordType = mMiscSubclassDataTable[Index].RecordType; + + if (mMiscSubclassDataTable[Index].RecordData == NULL) { + ZeroMem ( + &RecordData.Record, + mMiscSubclassDataTable[Index].RecordLen + ); + } else { + CopyMem ( + &RecordData.Record, + mMiscSubclassDataTable[Index].RecordData, + mMiscSubclassDataTable[Index].RecordLen + ); + } + // + // If the entry does not have a function pointer, just log the data. + // + if (mMiscSubclassDataTable[Index].Function == NULL) { + // + // Log RecordData to Data Hub. + // + EfiStatus = DataHub->LogData ( + DataHub, + &gEfiMiscSubClassGuid, + &gEfiMiscSubClassGuid, + EFI_DATA_RECORD_CLASS_DATA, + &RecordData, + sizeof (EFI_SUBCLASS_TYPE1_HEADER) + mMiscSubclassDataTable[Index].RecordLen + ); + + if (EFI_ERROR (EfiStatus)) { + DEBUG ( + (EFI_D_ERROR, + "LogData(%d bytes) == %r\n", + sizeof (EFI_SUBCLASS_TYPE1_HEADER) + mMiscSubclassDataTable[Index].RecordLen, + EfiStatus) + ); + } + + continue; + } + // + // The entry has a valid function pointer. + // Keep calling the function and logging data until there + // is no more data to log. + // + for (;;) { + // + // + // + EfiStatus = (*mMiscSubclassDataTable[Index].Function) + ( + mMiscSubclassDataTable[Index].RecordType, &mMiscSubclassDataTable[Index].RecordLen, &RecordData.Record, & + LogRecordData + ); + + // + // + // + if (EFI_ERROR (EfiStatus)) { + break; + } + + if (!LogRecordData) { + break; + } + // + // + // + EfiStatus = DataHub->LogData ( + DataHub, + &gEfiMiscSubClassGuid, + &gEfiMiscSubClassGuid, + EFI_DATA_RECORD_CLASS_DATA, + &RecordData, + sizeof (EFI_SUBCLASS_TYPE1_HEADER) + mMiscSubclassDataTable[Index].RecordLen + ); + + if (EFI_ERROR (EfiStatus)) { + DEBUG ( + (EFI_D_ERROR, + "LogData(%d bytes) == %r\n", + sizeof (EFI_SUBCLASS_TYPE1_HEADER) + mMiscSubclassDataTable[Index].RecordLen, + EfiStatus) + ); + } + } + } + // + // Install notify function to fetch memory data through WinNtIo protocol and store to data hub. + // + EfiStatus = gBS->CreateEvent ( + EFI_EVENT_NOTIFY_SIGNAL, + EFI_TPL_CALLBACK, + WinNtIoProtocolNotifyFunction, + ImageHandle, + &Event + ); + ASSERT (!EFI_ERROR (EfiStatus)); + + EfiStatus = gBS->RegisterProtocolNotify ( + &gEfiWinNtIoProtocolGuid, + Event, + &Registration + ); + ASSERT (!EFI_ERROR (EfiStatus)); + + return EFI_SUCCESS; +} + +UINTN +Atoi ( + CHAR16 *String + ) +/*++ + +Routine Description: + Convert a unicode string to a UINTN + +Arguments: + String - Unicode string. + +Returns: + UINTN of the number represented by String. + +--*/ +{ + UINTN Number; + CHAR16 *Str; + + // + // skip preceeding white space + // + Str = String; + while ((*Str) && (*Str == ' ' || *Str == '"')) { + Str++; + } + // + // Convert ot a Number + // + Number = 0; + while (*Str != '\0') { + if ((*Str >= '0') && (*Str <= '9')) { + Number = (Number * 10) +*Str - '0'; + } else { + break; + } + + Str++; + } + + return Number; +} + +VOID +EFIAPI +WinNtIoProtocolNotifyFunction ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + This function will log memory size data to data hub. + +Arguments: +Event - Event whose notification function is being invoked. +Context - Pointer to the notification function's context. + +Returns: + EFI_STATUS. + +--*/ +{ + EFI_STATUS Status; + EFI_MEMORY_SUBCLASS_DRIVER_DATA MemorySubClassData; + EFI_DATA_RECORD_HEADER *Record; + EFI_SUBCLASS_TYPE1_HEADER *DataHeader; + UINTN HandleCount; + UINTN HandleIndex; + UINT64 MonotonicCount; + BOOLEAN RecordFound; + EFI_HANDLE *HandleBuffer; + EFI_WIN_NT_IO_PROTOCOL *WinNtIo; + EFI_DATA_HUB_PROTOCOL *DataHub; + UINT64 TotalMemorySize; + + DataHub = NULL; + MonotonicCount = 0; + RecordFound = FALSE; + + // + // Retrieve the list of all handles from the handle database. + // + Status = gBS->LocateHandleBuffer ( + AllHandles, + &gEfiWinNtIoProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return ; + } + // + // Locate DataHub protocol. + // + Status = gBS->LocateProtocol (&gEfiDataHubProtocolGuid, NULL, &DataHub); + if (EFI_ERROR (Status)) { + return ; + } + // + // Search the Handle array to find the meory size information. + // + for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) { + Status = gBS->OpenProtocol ( + HandleBuffer[HandleIndex], + &gEfiWinNtIoProtocolGuid, + &WinNtIo, + Context, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + continue; + } + + if ((WinNtIo->WinNtThunk->Signature == EFI_WIN_NT_THUNK_PROTOCOL_SIGNATURE) && + CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtMemoryGuid) + ) { + // + // Check if this record has been stored in data hub. + // + do { + Status = DataHub->GetNextRecord (DataHub, &MonotonicCount, NULL, &Record); + if (Record->DataRecordClass == EFI_DATA_RECORD_CLASS_DATA) { + DataHeader = (EFI_SUBCLASS_TYPE1_HEADER *) (Record + 1); + if (CompareGuid (&Record->DataRecordGuid, &gEfiProcessorSubClassGuid) && + (DataHeader->RecordType == EFI_MEMORY_ARRAY_START_ADDRESS_RECORD_NUMBER) + ) { + RecordFound = TRUE; + } + } + } while (MonotonicCount != 0); + + if (RecordFound) { + RecordFound = FALSE; + continue; + } + // + // Initialize data record. + // + MemorySubClassData.Header.Instance = 1; + MemorySubClassData.Header.SubInstance = EFI_SUBCLASS_INSTANCE_NON_APPLICABLE; + MemorySubClassData.Header.RecordType = EFI_MEMORY_ARRAY_START_ADDRESS_RECORD_NUMBER; + + TotalMemorySize = (UINT64) Atoi (WinNtIo->EnvString); + + MemorySubClassData.Record.ArrayStartAddress.MemoryArrayStartAddress = 0; + MemorySubClassData.Record.ArrayStartAddress.MemoryArrayEndAddress = LShiftU64 (TotalMemorySize, 20) - 1; + MemorySubClassData.Record.ArrayStartAddress.PhysicalMemoryArrayLink.ProducerName = gEfiMemoryProducerGuid; + MemorySubClassData.Record.ArrayStartAddress.PhysicalMemoryArrayLink.Instance = 1; + MemorySubClassData.Record.ArrayStartAddress.PhysicalMemoryArrayLink.SubInstance = EFI_SUBCLASS_INSTANCE_NON_APPLICABLE; + MemorySubClassData.Record.ArrayStartAddress.MemoryArrayPartitionWidth = 0; + + // + // Store memory size data record to data hub. + // + Status = DataHub->LogData ( + DataHub, + &gEfiMemorySubClassGuid, + &gEfiMemoryProducerGuid, + EFI_DATA_RECORD_CLASS_DATA, + &MemorySubClassData, + sizeof (EFI_SUBCLASS_TYPE1_HEADER) + sizeof (EFI_MEMORY_ARRAY_START_ADDRESS_DATA) + ); + } + + gBS->CloseProtocol ( + HandleBuffer[HandleIndex], + &gEfiWinNtIoProtocolGuid, + Context, + NULL + ); + } +} + diff --git a/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSystemLanguageString.uni b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSystemLanguageString.uni new file mode 100644 index 0000000000000000000000000000000000000000..36dacf066ac0b23d688bf2b17c0a5f966bee9807 GIT binary patch literal 2014 zcmchYTWcFJ5QXQt(EqR`6xy`0OCS0W=!27N6VuoZwnLhy;9HypUyALx@t<$|osqp- zy98PYL9C>aMrY29X0*S5m91=v9oT!?YkP%M&d0<~Y-&GjWi!icX!o{2_pSBp9pfka zNc(Ibm{)DW-oQr8b!NsX^&M6-W)s$5x^28ktO74Fi(brK8rU4pGh5R4t;AXzA2U`H z_|M=ybRWjZ9en6BF3=db+#?QC8>6Yc73U`CC#=Y8;bzQ6j`sh)NA?|%WN`#ukJ-do zi_3ga%RBcoXQhiTeLLLQDS>j&w{7$J zq{#mHFkcQSvTxhDr9|n{n%1y0`ij+%tK?up7HVv>TD4=lVwQSlURj+nWnK9a5MtI= zd7V-;T8`Xcrq@CJ9;0xDy2p6zvLwB4|Jow^Ymj8W;oK6t2CwNp)LE}$U)CDVvxy`x zwI+6LbfqJHLF+5J;(5dPjUD+YUg_FO@He&ZIZi~c617VzRyI%lm3zvY$Ue?$KbcE8u;xeV<9%&tIzW z?uTr=B?iix6T79q;ZtVTkS_cN&&Y=g*_`@*$lp400-j#&Vx$s(ZS+r3eimb@7kF2< J7}q^#`3E0P|CRs% literal 0 HcmV?d00001 diff --git a/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSystemLanguageStringData.c b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSystemLanguageStringData.c new file mode 100644 index 0000000000..ef52513d58 --- /dev/null +++ b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSystemLanguageStringData.c @@ -0,0 +1,33 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + MiscSystemLanguageStringData.c + +Abstract: + + This driver parses the mMiscSubclassDataTable structure and reports + any generated data to the DataHub. + +--*/ + +#include "MiscSubclassDriver.h" + +// +// Static (possibly build generated) Bios Vendor data. +// +MISC_SUBCLASS_TABLE_DATA(EFI_MISC_SYSTEM_LANGUAGE_STRING_DATA, SystemLanguageString) = { + 0, + STRING_TOKEN(STR_MISC_SYSTEM_LANGUAGE_STRING) +}; + +/* eof - MiscSystemLanguageStringData.c */ diff --git a/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSystemManufacturer.uni b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSystemManufacturer.uni new file mode 100644 index 0000000000000000000000000000000000000000..204588ef8c69d2ffdf8ad4e2e2dbaec223e9f688 GIT binary patch literal 2456 zcmchZU2jrB5QgX4#Q$(YW1`i9@xqHHUO=IiDA4fH+AG3mdy+!UfmZqR>hsP53)Lpl zG|dUSJ9}nl-+AZb@cUQ63YOTuz2$jnFOUlBIk6+VvG2C9%u>6wE1RSH+6MN9`GdXZ z`DpK0S8d9>kzKRanT%5!d+esHrtClWv+^dfBDjPsdNFfpWHT^lcE>ohJbP_?OxaDq zpMm?*eV8Ek@L|Y2M`Psj03L2^f~MXrI5$N?h-^8)4tjHVrn66_c9&T*Bajs-7DTXIHX%ClXv~`sQTg!`t@}8)xe75^pw)Lq z#&{K25hk79ej<8h{G13MdR?d%0{=Rnc{K9a%7}a6UVLWk^zmhA2lw9Ov2w+4`_8A6 zBKoJZ`Fxfl`nH`|1(r^&X$||#ShN~)l^jgSLd|Vg-p!U$-?JXA?W-cA8+lb4;tR(8;pHsA?Av*gc?T_m|&6*$VbP*`BW??XA01 z==mWNyZEY%IkGO}1wUnF4XNhQ>)0{#5xX6awsKU@9vwm)UBXR|QB14P=xd_P++SystemUuid = %%TBD + // + // Set power-on type. + // + // ((EFI_MISC_SYSTEM_MANUFACTURER_DATA *)RecordData)->SystemWakeupType = %%TBD + // + // Set Done flag to TRUE for next pass through this function. + // Set *LogRecordData to TRUE so data will get logged to Data Hub. + // + Done = TRUE; + *LogRecordData = TRUE; + } else { + // + // No, this is the second time. Reset the state of the Done flag + // to FALSE and tell the data logger that there is no more data + // to be logged for this record type. If any memory allocations + // were made by earlier passes, they must be released now. + // + Done = FALSE; + *LogRecordData = FALSE; + } + + return EFI_SUCCESS; +} + +/* eof - MiscSystemManufacturerFunction.c */ diff --git a/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSystemOptionString.uni b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSystemOptionString.uni new file mode 100644 index 0000000000000000000000000000000000000000..617578d6a3395e6f977900480b286f1c5330c45e GIT binary patch literal 2004 zcmchYU2jrB5QgX4#Q$&tG0|$lc;Q78FQA|$3N%1dd)4sWlki~xtNeNOd1pE70n+nTbldqrcev^pL%58Bvt{JkVP-n&W&vi=9S$ukF3OA4~T}1!G zBRXUj-ou!s;FAr-G(=t2*YJwn0OVQqC^sQH@@T?I$f*4IiPSO9!&rr!Y>^sxL?(C@ zq9RPXeK;a|Rs4nwpLt)X7ef4Xf92UIp=(9n%SZWHvopY#k)0l$l+bd=cWCqRxQPDo zbUvM?h`whRRwqiA*0HvIVy;*dzCjHpRH4=$yA7+_6;$0T^U7MRb@o*+K|`$C2Cq{c ziLPsIL+N$UTws-6X)Ul;ofoI~?O#Vke~l*DZ#%ZcuF=e24{mhAc6t4QtO7ORCU-x>V_6AYAq+?~X=C9mC-bD0~YEs`L?>BW` zi+-8Y184hxM3j`)ruXj<)LZZ4G16^nJ?rBxlzLk)WyyOm-D^s6RKH>%C*j{z4bdZMB72f<%iMRN# ziaEDi<{Lg$WfQJV2C|ImEYxj_s+JE$UI@LyQzFu5R;2aL=x?IR%tuo-6XTh179(14 Ge18D`YxH42FG1;y+N6Q}dEj|H$xc#K z38bnT?abKgv0r;^&+lI)D_LTP_LlL|UO<)dHL(+$+jm=AW~q(s&X&l&w!Xb#{b27I zAMG9cy3P1EvrG;1a0yxTV&T-#7GTb7#XPVgybeC5a1-!n z;2ygVQ|K-}3|N;)44v*1hq+CW)W0?7X2>US?W@5|9y|>yJ(Wd3Hti%W{z4| zwwPpbutBwApCa3}9<$EfJ96QP=mWl~W7}$xH}Wyf?@V!++i2%p#oAVdKHtOgw|5c! z507Y{S$OwjmV!?<6w?rOSzkaac0G`9vqyImZbu%C_!Dkae*8r0ANTJHGvZ9W|p z(LbHe=hGC?ckIk+MCsC6*0fXRvNfRVCfM3VHtTi2H3rb#! zCv+WTB_n)6>NB#!dBggJKk`wyY8xxT-3 zN9qacAIlxvyHc|LiqYZbsynA6z7{A}j&J)Soo%{}(5xTPdqn*nZr()c3i>|Tf$u~e zXJiZm_SX4r@B}b&H|st$i|nqkR$yA`)UF# literal 0 HcmV?d00001 diff --git a/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSystemSlotDesignationData.c b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSystemSlotDesignationData.c new file mode 100644 index 0000000000..d5e1474fe2 --- /dev/null +++ b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/MiscSystemSlotDesignationData.c @@ -0,0 +1,52 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + MiscSystemSlotDesignationData.c + +Abstract: + + This driver parses the mMiscSubclassDataTable structure and reports + any generated data to the DataHub. + +--*/ + +#include "MiscSubclassDriver.h" + +// +// Static (possibly build generated) Bios Vendor data. +// +MISC_SUBCLASS_TABLE_DATA(EFI_MISC_SYSTEM_SLOT_DESIGNATION_DATA, MiscSystemSlotDesignation) = { + STRING_TOKEN(STR_MISC_SYSTEM_SLOT_DESIGNATION), // SlotDesignation + EfiSlotTypeOther, // SlotType + EfiSlotDataBusWidthOther, // SlotDataBusWidth + EfiSlotUsageOther, // SlotUsage + EfiSlotLengthOther, // SlotLength + 0, // SlotId + { // SlotCharacteristics + 0, // CharacteristicsUnknown :1; + 0, // Provides50Volts :1; + 0, // Provides33Volts :1; + 0, // SharedSlot :1; + 0, // PcCard16Supported :1; + 0, // CardBusSupported :1; + 0, // ZoomVideoSupported :1; + 0, // ModemRingResumeSupported:1; + 0, // PmeSignalSupported :1; + 0, // HotPlugDevicesSupported :1; + 0, // SmbusSignalSupported :1; + 0 // Reserved :21; + }, + 0 // SlotDevicePath +}; + +/* eof - MiscSystemSlotsData.c */ diff --git a/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/build.xml b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/build.xml new file mode 100644 index 0000000000..7265194134 --- /dev/null +++ b/EdkNt32Pkg/Dxe/Nt32Platform/MiscSubclass/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkNt32Pkg/Dxe/PcdEmulator/PcdEmulator.c b/EdkNt32Pkg/Dxe/PcdEmulator/PcdEmulator.c new file mode 100644 index 0000000000..38863b8a02 --- /dev/null +++ b/EdkNt32Pkg/Dxe/PcdEmulator/PcdEmulator.c @@ -0,0 +1,557 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + PcdEmulator.c + +Abstract: + Platform Configuration Database (PCD) Protocol + +--*/ + +#include + +UINTN mSkuId = 0; + +STATIC UINTN +GetPcdDataEntryCount ( + VOID +) { + return gEmulatedPcdDatabaseEx->Count; +} + +EFI_STATUS +EFIAPI +PcdEmulatorSetSku ( + IN UINTN SkuId + ) +{ + mSkuId = SkuId; + return EFI_SUCCESS; +} + +UINT8 +EFIAPI +PcdEmulatorGet8 ( + IN UINTN TokenNumber + ) +{ + EMULATED_PCD_ENTRY_EX *Pcd; + + Pcd = GetPcdEntry (TokenNumber); + ASSERT (Pcd != NULL); + ASSERT (Pcd->DatumSize == 1); + + return (UINT8)Pcd->Datum; +} + +UINT16 +EFIAPI +PcdEmulatorGet16 ( + IN UINTN TokenNumber + ) +{ + EMULATED_PCD_ENTRY_EX *Pcd; + + Pcd = GetPcdEntry (TokenNumber); + ASSERT (Pcd != NULL); + ASSERT (Pcd->DatumSize == 2); + + return (UINT16)Pcd->Datum; +} + +UINT32 +EFIAPI +PcdEmulatorGet32 ( + IN UINTN TokenNumber + ) +{ + EMULATED_PCD_ENTRY_EX *Pcd; + + Pcd = GetPcdEntry (TokenNumber); + ASSERT (Pcd != NULL); + ASSERT (Pcd->DatumSize == 4); + + return (UINT32)Pcd->Datum; +} + +UINT64 +EFIAPI +PcdEmulatorGet64 ( + IN UINTN TokenNumber + ) +{ + EMULATED_PCD_ENTRY_EX *Pcd; + + Pcd = GetPcdEntry (TokenNumber); + ASSERT (Pcd != NULL); + ASSERT (Pcd->DatumSize == sizeof (UINT64)); + + return (UINT64)Pcd->Datum; +} + +VOID * +EFIAPI +PcdEmulatorGetPtr ( + IN UINTN TokenNumber + ) +{ + EMULATED_PCD_ENTRY_EX *Pcd; + + Pcd = GetPcdEntry (TokenNumber); + ASSERT (Pcd != NULL); + + return (VOID *)(UINTN)Pcd->ExtendedData; +} + +BOOLEAN +EFIAPI +PcdEmulatorGetBoolean ( + IN UINTN TokenNumber + ) +{ + EMULATED_PCD_ENTRY_EX *Pcd; + + Pcd = GetPcdEntry (TokenNumber); + ASSERT (Pcd != NULL); + ASSERT (Pcd->DatumSize == 1); + + return (BOOLEAN)Pcd->Datum; +} + +UINTN +EFIAPI +PcdEmulatorGetSize ( + IN UINTN TokenNumber + ) +{ + EMULATED_PCD_ENTRY_EX *Pcd; + + Pcd = GetPcdEntry (TokenNumber); + ASSERT (Pcd != NULL); + return Pcd->DatumSize; +} + +UINT8 +EFIAPI +PcdEmulatorGet8Ex ( + IN CONST EFI_GUID *PcdDataBaseName, + IN UINTN TokenNumber + ) +{ + ASSERT (FALSE); + return 0; +} + +UINT16 +EFIAPI +PcdEmulatorGet16Ex ( + IN CONST EFI_GUID *PcdDataBaseName, + IN UINTN TokenNumber + ) +{ + ASSERT (FALSE); + return 0; +} + +UINT32 +EFIAPI +PcdEmulatorGet32Ex ( + IN CONST EFI_GUID *PcdDataBaseName, + IN UINTN TokenNumber + ) +{ + ASSERT (FALSE); + return 0; +} + +UINT64 +EFIAPI +PcdEmulatorGet64Ex ( + IN CONST EFI_GUID *PcdDataBaseName, + IN UINTN TokenNumber + ) +{ + ASSERT (FALSE); + return 0; +} + +VOID * +EFIAPI +PcdEmulatorGetPtrEx ( + IN CONST EFI_GUID *PcdDataBaseName, + IN UINTN TokenNumber + ) +{ + ASSERT (FALSE); + return 0; +} + +BOOLEAN +EFIAPI +PcdEmulatorGetBooleanEx ( + IN CONST EFI_GUID *PcdDataBaseName, + IN UINTN TokenNumber + ) +{ + ASSERT (FALSE); + return 0; +} + +UINTN +EFIAPI +PcdEmulatorGetSizeEx ( + IN CONST EFI_GUID *PcdDataBaseName, + IN UINTN TokenNumber + ) +{ + EMULATED_PCD_ENTRY_EX *Pcd; + + Pcd = GetPcdEntry (TokenNumber); + ASSERT (Pcd != NULL); + return Pcd->DatumSize; +} + + +EFI_STATUS +EFIAPI +PcdEmulatorSet8 ( + IN UINTN TokenNumber, + IN UINT8 Value + ) +{ + + EMULATED_PCD_ENTRY_EX *Pcd; + + Pcd = GetPcdEntry (TokenNumber); + ASSERT (Pcd != NULL); + + ASSERT (Pcd->DatumSize == sizeof (UINT8)); + + Pcd->Datum = Value; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcdEmulatorSet16 ( + IN UINTN TokenNumber, + IN UINT16 Value + ) +{ + + ASSERT (FALSE); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcdEmulatorSet32 ( + IN UINTN TokenNumber, + IN UINT32 Value + ) +{ + + EMULATED_PCD_ENTRY_EX *Pcd; + + Pcd = GetPcdEntry (TokenNumber); + ASSERT (Pcd != NULL); + + ASSERT (Pcd->DatumSize == sizeof (UINT32)); + + Pcd->Datum = Value; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcdEmulatorSet64 ( + IN UINTN TokenNumber, + IN UINT64 Value + ) +{ + + ASSERT (FALSE); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcdEmulatorSetPtr ( + IN UINTN TokenNumber, + IN CONST VOID *Value + ) +{ + + ASSERT (FALSE); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcdEmulatorSetBoolean ( + IN UINTN TokenNumber, + IN BOOLEAN Value + ) +{ + + ASSERT (FALSE); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcdEmulatorSet8Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN UINT8 Value + ) +{ + + ASSERT (FALSE); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcdEmulatorSet16Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN UINT16 Value + ) +{ + + ASSERT (FALSE); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcdEmulatorSet32Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN UINT32 Value + ) +{ + + ASSERT (FALSE); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcdEmulatorSet64Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN UINT64 Value + ) +{ + + ASSERT (FALSE); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcdEmulatorSetPtrEx ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN CONST VOID *Value + ) +{ + + ASSERT (FALSE); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcdEmulatorSetBooleanEx ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN BOOLEAN Value + ) +{ + + ASSERT (FALSE); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcdEmulatorCallBackOnSet ( + IN UINTN TokenNumber, + IN CONST EFI_GUID *Guid, OPTIONAL + IN PCD_PROTOCOL_CALLBACK CallBackFunction + ) +{ + EMULATED_PCD_ENTRY_EX *Pcd; + + Pcd = GetPcdEntry (TokenNumber); + ASSERT (Pcd != NULL); + + if (Pcd->CallBackListSize == Pcd->CallBackEntries) { + return EFI_OUT_OF_RESOURCES; + } + + Pcd->CallBackList[Pcd->CallBackEntries++] = CallBackFunction; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcdEmulatorUnregisterCallBackOnSet ( + IN UINTN TokenNumber, + IN CONST EFI_GUID *Guid, OPTIONAL + IN PCD_PROTOCOL_CALLBACK CallBackfunction + ) +{ + EMULATED_PCD_ENTRY_EX *Pcd; + UINT32 Index; + + Pcd = GetPcdEntry (TokenNumber); + ASSERT (Pcd != NULL); + + for (Index = 0; Index < Pcd->CallBackListSize; Index++) { + if (Pcd->CallBackList[Index] == CallBackfunction) { + Pcd->CallBackList[Index] = NULL; + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +EFI_STATUS +EFIAPI +PcdEmulatorGetNextToken ( + IN CONST EFI_GUID *Guid, OPTIONAL + IN UINTN *Token + ) +{ + EMULATED_PCD_ENTRY_EX *Pcd; + EMULATED_PCD_ENTRY_EX *LastPcdEntry; + + if (*Token == PCD_INVALID_TOKEN) { + // + // BugBug: Due to variable size array, ensure we convert this to a reasonable database + // that can accomodate array references for simplicity's sake + *Token = gEmulatedPcdEntryEx[0].Token; + return EFI_SUCCESS; + } + + Pcd = GetPcdEntry (*Token); + if (Pcd == NULL) { + return EFI_NOT_FOUND; + } + + LastPcdEntry = gEmulatedPcdEntryEx + GetPcdDataEntryCount (); + if (++Pcd >= LastPcdEntry) { + return EFI_NOT_FOUND; + } + + *Token = Pcd->Token; + return EFI_SUCCESS; +} + +PCD_PROTOCOL mPcdProtocolInstance = { + PcdEmulatorSetSku, + + PcdEmulatorGet8, + PcdEmulatorGet16, + PcdEmulatorGet32, + PcdEmulatorGet64, + PcdEmulatorGetPtr, + PcdEmulatorGetBoolean, + PcdEmulatorGetSize, + + PcdEmulatorGet8Ex, + PcdEmulatorGet16Ex, + PcdEmulatorGet32Ex, + PcdEmulatorGet64Ex, + PcdEmulatorGetPtrEx, + PcdEmulatorGetBooleanEx, + PcdEmulatorGetSizeEx, + + PcdEmulatorSet8, + PcdEmulatorSet16, + PcdEmulatorSet32, + PcdEmulatorSet64, + PcdEmulatorSetPtr, + PcdEmulatorSetBoolean, + + PcdEmulatorSet8Ex, + PcdEmulatorSet16Ex, + PcdEmulatorSet32Ex, + PcdEmulatorSet64Ex, + PcdEmulatorSetPtrEx, + PcdEmulatorSetBooleanEx, + + PcdEmulatorCallBackOnSet, + PcdEmulatorUnregisterCallBackOnSet, + PcdEmulatorGetNextToken +}; + + +EFI_STATUS +EFIAPI +PcdEmulatorEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HOB_GUID_TYPE *GuidHob; + + GuidHob = GetFirstGuidHob (&gPcdHobGuid); + gEmulatedPcdDatabaseEx = (EMULATED_PCD_DATABASE_EX *) GET_GUID_HOB_DATA(GuidHob); + ASSERT (gEmulatedPcdDatabaseEx != NULL); + gEmulatedPcdEntryEx = gEmulatedPcdDatabaseEx->Entry; + + Status = gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gPcdProtocolGuid, &mPcdProtocolInstance, + NULL + ); + ASSERT_EFI_ERROR (Status); + return Status; +} + + +EMULATED_PCD_ENTRY_EX * +GetPcdEntry ( + IN UINTN TokenNumber + ) +{ + UINTN Index; + UINTN Count; + + Count = GetPcdDataEntryCount (); + for (Index = 0; Index < Count; Index++) { + if (gEmulatedPcdEntryEx[Index].Token == TokenNumber) { + return &gEmulatedPcdEntryEx[Index]; + } + } + return NULL; +} diff --git a/EdkNt32Pkg/Dxe/PcdEmulator/PcdEmulator.dxs b/EdkNt32Pkg/Dxe/PcdEmulator/PcdEmulator.dxs new file mode 100644 index 0000000000..9e814a6f85 --- /dev/null +++ b/EdkNt32Pkg/Dxe/PcdEmulator/PcdEmulator.dxs @@ -0,0 +1,27 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PcdEmulator.dxs + +Abstract: + + Dependency expression source file. + +--*/ + +#include +#include + +DEPENDENCY_START + TRUE +DEPENDENCY_END diff --git a/EdkNt32Pkg/Dxe/PcdEmulator/PcdEmulator.h b/EdkNt32Pkg/Dxe/PcdEmulator/PcdEmulator.h new file mode 100644 index 0000000000..b49afb188d --- /dev/null +++ b/EdkNt32Pkg/Dxe/PcdEmulator/PcdEmulator.h @@ -0,0 +1,43 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + PcdEmulator.h + +Abstract: + Platform Configuration Database (PCD) + +--*/ + +#ifndef __PCD_EMULATOR_H__ +#define __PCD_EMULATOR_H__ + + + +// +// BugBug: Not very sure, where to put this "extern" +// +extern GUID gPcdHobGuid; + +// +// BugBug: Hack max number of callbacks per token +// +#define MAX_PCD_CALLBACK 0x10 + +EMULATED_PCD_ENTRY_EX *gEmulatedPcdEntryEx; +EMULATED_PCD_DATABASE_EX *gEmulatedPcdDatabaseEx; + +EMULATED_PCD_ENTRY_EX * +GetPcdEntry ( + IN UINTN TokenNumber + ); + +#endif diff --git a/EdkNt32Pkg/Dxe/PcdEmulator/PcdEmulator.mbd b/EdkNt32Pkg/Dxe/PcdEmulator/PcdEmulator.mbd new file mode 100644 index 0000000000..93000692ef --- /dev/null +++ b/EdkNt32Pkg/Dxe/PcdEmulator/PcdEmulator.mbd @@ -0,0 +1,46 @@ + + + + + PcdEmulator + 80CF7257-87AB-47f9-A3FE-D50B76D89541 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-14 17:04 + 2006-03-19 15:17 + + + UefiBootServicesTableLib + BaseLib + DxeHobLib + UefiLib + HiiLib + DxeWinNtLib + UefiMemoryLib + UefiDriverEntryPoint + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + DxeMemoryAllocationLib + + + _ModuleEntryPoint + + diff --git a/EdkNt32Pkg/Dxe/PcdEmulator/PcdEmulator.msa b/EdkNt32Pkg/Dxe/PcdEmulator/PcdEmulator.msa new file mode 100644 index 0000000000..ec4a0c1d71 --- /dev/null +++ b/EdkNt32Pkg/Dxe/PcdEmulator/PcdEmulator.msa @@ -0,0 +1,75 @@ + + + + + PcdEmulator + DXE_DRIVER + BS_DRIVER + 80CF7257-87AB-47f9-A3FE-D50B76D89541 + 0 + Component description file for DxeIpl module + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-14 17:04 + 2006-03-19 15:17 + + + BaseLib + DebugLib + HiiLib + UefiLib + UefiDriverEntryPoint + PcdLib + WinNtLib + HobLib + MemoryAllocationLib + UefiBootServicesTableLib + + + PcdEmulator.c + PcdEmulator.dxs + + + MdePkg + EdkModulePkg + EdkNt32Pkg + + + Pcd + + + + PcdDataBase + gPcdHobGuid + 0x582e7ca1, 0x68cd, 0x4d44, 0xb4, 0x3b, 0xf2, 0x98, 0xed, 0x58, 0x7b, 0xa6 + + + + + PcdHob + + + + + PcdEmulatorEntry + + + diff --git a/EdkNt32Pkg/Dxe/PcdEmulator/build.xml b/EdkNt32Pkg/Dxe/PcdEmulator/build.xml new file mode 100644 index 0000000000..603876b2c3 --- /dev/null +++ b/EdkNt32Pkg/Dxe/PcdEmulator/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkNt32Pkg/Dxe/PlatformBds/BdsPlatform.c b/EdkNt32Pkg/Dxe/PlatformBds/BdsPlatform.c new file mode 100644 index 0000000000..d1edef3d7e --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/BdsPlatform.c @@ -0,0 +1,517 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + BdsPlatform.c + +Abstract: + + This file include all platform action which can be customized + by IBV/OEM. + +--*/ + +#include "Generic/Bds.h" +#include "BdsPlatform.h" +#include "Generic/String.h" +#include "Generic/Language.h" +#include "Generic/FrontPage.h" + +CHAR16 mFirmwareVendor[] = L"TianoCore.org"; + +// +// BDS Platform Functions +// +VOID +PlatformBdsInit ( + IN EFI_BDS_ARCH_PROTOCOL_INSTANCE *PrivateData + ) +/*++ + +Routine Description: + + Platform Bds init. Incude the platform firmware vendor, revision + and so crc check. + +Arguments: + + PrivateData - The EFI_BDS_ARCH_PROTOCOL_INSTANCE instance + +Returns: + + None. + +--*/ +{ + // + // set firmwarevendor, here can be IBV/OEM customize + // + gST->FirmwareVendor = AllocateRuntimeCopyPool ( + sizeof (mFirmwareVendor), + &mFirmwareVendor + ); + ASSERT (gST->FirmwareVendor != NULL); + + gST->FirmwareRevision = EFI_FIRMWARE_REVISION; + + // + // Fixup Tasble CRC after we updated Firmware Vendor and Revision + // + gBS->CalculateCrc32 ((VOID *) gST, sizeof (EFI_SYSTEM_TABLE), &gST->Hdr.CRC32); + + // + // Initialize the platform specific string and language + // + InitializeStringSupport (); + InitializeLanguage (TRUE); + InitializeFrontPage (FALSE); + +} + +EFI_STATUS +PlatformBdsConnectConsole ( + IN BDS_CONSOLE_CONNECT_ENTRY *PlatformConsole + ) +/*++ + +Routine Description: + + Connect the predefined platform default console device. Always try to find + and enable the vga device if have. + +Arguments: + + PlatformConsole - Predfined platform default console device array. + +Returns: + + EFI_SUCCESS - Success connect at least one ConIn and ConOut + device, there must have one ConOut device is + active vga device. + + EFI_STATUS - Return the status of + BdsLibConnectAllDefaultConsoles () + +--*/ +{ + EFI_STATUS Status; + UINTN Index; + + Index = 0; + Status = EFI_SUCCESS; + + // + // Have chance to connect the platform default console, + // the platform default console is the minimue device group + // the platform should support + // + while (PlatformConsole[Index].DevicePath != NULL) { + // + // Update the console variable with the connect type + // + if ((PlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) { + BdsLibUpdateConsoleVariable (L"ConIn", PlatformConsole[Index].DevicePath, NULL); + } + + if ((PlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) { + BdsLibUpdateConsoleVariable (L"ConOut", PlatformConsole[Index].DevicePath, NULL); + } + + if ((PlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) { + BdsLibUpdateConsoleVariable (L"ErrOut", PlatformConsole[Index].DevicePath, NULL); + } + + Index++; + } + // + // Connect the all the default console with current cosole variable + // + Status = BdsLibConnectAllDefaultConsoles (); + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} + +VOID +PlatformBdsConnectSequence ( + VOID + ) +/*++ + +Routine Description: + + Connect with predeined platform connect sequence, + the OEM/IBV can customize with their own connect sequence. + +Arguments: + + None. + +Returns: + + None. + +--*/ +{ + UINTN Index; + + Index = 0; + + // + // Here we can get the customized platform connect sequence + // Notes: we can connect with new variable which record the + // last time boots connect device path sequence + // + while (gPlatformConnectSequence[Index] != NULL) { + // + // Build the platform boot option + // + BdsLibConnectDevicePath (gPlatformConnectSequence[Index]); + Index++; + } + +} + +VOID +PlatformBdsGetDriverOption ( + IN OUT LIST_ENTRY *BdsDriverLists + ) +/*++ + +Routine Description: + + Load the predefined driver option, OEM/IBV can customize this + to load their own drivers + +Arguments: + + BdsDriverLists - The header of the driver option link list. + +Returns: + + None. + +--*/ +{ + UINTN Index; + + Index = 0; + + // + // Here we can get the customized platform driver option + // + while (gPlatformDriverOption[Index] != NULL) { + // + // Build the platform boot option + // + BdsLibRegisterNewOption (BdsDriverLists, gPlatformDriverOption[Index], NULL, L"DriverOrder"); + Index++; + } + +} + +VOID +PlatformBdsDiagnostics ( + IN EXTENDMEM_COVERAGE_LEVEL MemoryTestLevel, + IN BOOLEAN QuietBoot + ) +/*++ + +Routine Description: + + Perform the platform diagnostic, such like test memory. OEM/IBV also + can customize this fuction to support specific platform diagnostic. + +Arguments: + + MemoryTestLevel - The memory test intensive level + + QuietBoot - Indicate if need to enable the quiet boot + +Returns: + + None. + +--*/ +{ + EFI_STATUS Status; + + // + // Here we can decide if we need to show + // the diagnostics screen + // Notes: this quiet boot code should be remove + // from the graphic lib + // + if (QuietBoot) { + EnableQuietBoot (&gEfiUgaSplashProtocolGuid); + // + // Perform system diagnostic + // + Status = BdsMemoryTest (MemoryTestLevel); + if (EFI_ERROR (Status)) { + DisableQuietBoot (); + } + + return ; + } + // + // Perform system diagnostic + // + Status = BdsMemoryTest (MemoryTestLevel); +} + +VOID +PlatformBdsPolicyBehavior ( + IN EFI_BDS_ARCH_PROTOCOL_INSTANCE *PrivateData, + IN OUT LIST_ENTRY *DriverOptionList, + IN OUT LIST_ENTRY *BootOptionList + ) +/*++ + +Routine Description: + + The function will excute with as the platform policy, current policy + is driven by boot mode. IBV/OEM can customize this code for their specific + policy action. + +Arguments: + + PrivateData - The EFI_BDS_ARCH_PROTOCOL_INSTANCE instance + + DriverOptionList - The header of the driver option link list + + BootOptionList - The header of the boot option link list + +Returns: + + None. + +--*/ +{ + EFI_STATUS Status; + UINT16 Timeout; + + // + // Init the time out value + // + Timeout = BdsLibGetTimeout (); + + // + // Load the driver option as the driver option list + // + PlatformBdsGetDriverOption (DriverOptionList); + + // + // Get current Boot Mode + // + Status = BdsLibGetBootMode (&PrivateData->BootMode); + + // + // Go the different platform policy with different boot mode + // Notes: this part code can be change with the table policy + // + switch (PrivateData->BootMode) { + + case BOOT_ASSUMING_NO_CONFIGURATION_CHANGES: + case BOOT_WITH_MINIMAL_CONFIGURATION: + // + // In no-configuration boot mode, we can connect the + // console directly. + // + BdsLibConnectAllDefaultConsoles (); + PlatformBdsDiagnostics (IGNORE, TRUE); + + // + // Perform some platform specific connect sequence + // + PlatformBdsConnectSequence (); + + // + // Notes: current time out = 0 can not enter the + // front page + // + PlatformBdsEnterFrontPage (Timeout, FALSE); + + // + // Check the boot option with the boot option list + // + BdsLibBuildOptionFromVar (BootOptionList, L"BootOrder"); + break; + + case BOOT_ON_FLASH_UPDATE: + // + // Boot with the specific configuration + // + PlatformBdsConnectConsole (gPlatformConsole); + PlatformBdsDiagnostics (EXTENSIVE, FALSE); + BdsLibConnectAll (); + ProcessCapsules (BOOT_ON_FLASH_UPDATE); + break; + + case BOOT_IN_RECOVERY_MODE: + // + // In recovery mode, just connect platform console + // and show up the front page + // + PlatformBdsConnectConsole (gPlatformConsole); + PlatformBdsDiagnostics (EXTENSIVE, FALSE); + + // + // In recovery boot mode, we still enter to the + // frong page now + // + PlatformBdsEnterFrontPage (Timeout, FALSE); + break; + + case BOOT_WITH_FULL_CONFIGURATION: + case BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS: + case BOOT_WITH_DEFAULT_SETTINGS: + default: + // + // Connect platform console + // + Status = PlatformBdsConnectConsole (gPlatformConsole); + if (EFI_ERROR (Status)) { + // + // Here OEM/IBV can customize with defined action + // + PlatformBdsNoConsoleAction (); + } + + PlatformBdsDiagnostics (IGNORE, TRUE); + + // + // Perform some platform specific connect sequence + // + PlatformBdsConnectSequence (); + + // + // Give one chance to enter the setup if we + // have the time out + // + PlatformBdsEnterFrontPage (Timeout, FALSE); + + // + // Here we have enough time to do the enumeration of boot device + // + BdsLibEnumerateAllBootOption (BootOptionList); + break; + } + + return ; + +} + +VOID +PlatformBdsBootSuccess ( + IN BDS_COMMON_OPTION *Option + ) +/*++ + +Routine Description: + + Hook point after a boot attempt succeeds. We don't expect a boot option to + return, so the EFI 1.0 specification defines that you will default to an + interactive mode and stop processing the BootOrder list in this case. This + is alos a platform implementation and can be customized by IBV/OEM. + +Arguments: + + Option - Pointer to Boot Option that succeeded to boot. + +Returns: + + None. + +--*/ +{ + CHAR16 *TmpStr; + + // + // If Boot returned with EFI_SUCCESS and there is not in the boot device + // select loop then we need to pop up a UI and wait for user input. + // + TmpStr = GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED)); + if (TmpStr != NULL) { + BdsLibOutputStrings (gST->ConOut, TmpStr, Option->Description, L"\n\r", NULL); + gBS->FreePool (TmpStr); + } +} + +VOID +PlatformBdsBootFail ( + IN BDS_COMMON_OPTION *Option, + IN EFI_STATUS Status, + IN CHAR16 *ExitData, + IN UINTN ExitDataSize + ) +/*++ + +Routine Description: + + Hook point after a boot attempt fails. + +Arguments: + + Option - Pointer to Boot Option that failed to boot. + + Status - Status returned from failed boot. + + ExitData - Exit data returned from failed boot. + + ExitDataSize - Exit data size returned from failed boot. + +Returns: + + None. + +--*/ +{ + CHAR16 *TmpStr; + + // + // If Boot returned with failed status then we need to pop up a UI and wait + // for user input. + // + TmpStr = GetStringById (STRING_TOKEN (STR_BOOT_FAILED)); + if (TmpStr != NULL) { + BdsLibOutputStrings (gST->ConOut, TmpStr, Option->Description, L"\n\r", NULL); + gBS->FreePool (TmpStr); + } + +} + +EFI_STATUS +PlatformBdsNoConsoleAction ( + VOID + ) +/*++ + +Routine Description: + + This function is remained for IBV/OEM to do some platform action, + if there no console device can be connected. + +Arguments: + + None. + +Returns: + + EFI_SUCCESS - Direct return success now. + +--*/ +{ + return EFI_SUCCESS; +} diff --git a/EdkNt32Pkg/Dxe/PlatformBds/BdsPlatform.h b/EdkNt32Pkg/Dxe/PlatformBds/BdsPlatform.h new file mode 100644 index 0000000000..f3679fb88d --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/BdsPlatform.h @@ -0,0 +1,140 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + BdsPlatform.h + +Abstract: + + Head file for BDS Platform specific code + +--*/ + +#ifndef _BDS_PLATFORM_H +#define _BDS_PLATFORM_H + +#include "IndustryStandard/Pci22.h" + +extern BDS_CONSOLE_CONNECT_ENTRY gPlatformConsole[]; +extern EFI_DEVICE_PATH_PROTOCOL *gPlatformConnectSequence[]; +extern EFI_DEVICE_PATH_PROTOCOL *gPlatformDriverOption[]; + +#define gEndEntire \ + { \ + END_DEVICE_PATH_TYPE,\ + END_ENTIRE_DEVICE_PATH_SUBTYPE,\ + END_DEVICE_PATH_LENGTH,\ + 0\ + } + +typedef struct { + VENDOR_DEVICE_PATH VendorDevicePath; + UINT32 Instance; +} WIN_NT_VENDOR_DEVICE_PATH_NODE; + +// +// Below is the platform console device path +// +typedef struct { + VENDOR_DEVICE_PATH NtBus; + WIN_NT_VENDOR_DEVICE_PATH_NODE SerialDevice; + UART_DEVICE_PATH Uart; + VENDOR_DEVICE_PATH TerminalType; + EFI_DEVICE_PATH_PROTOCOL End; +} NT_ISA_SERIAL_DEVICE_PATH; + +typedef struct { + VENDOR_DEVICE_PATH NtBus; + WIN_NT_VENDOR_DEVICE_PATH_NODE NtUgaDevice; + EFI_DEVICE_PATH_PROTOCOL End; +} NT_PLATFORM_UGA_DEVICE_PATH; + +// +// Platform BDS Functions +// +VOID +PlatformBdsInit ( + IN EFI_BDS_ARCH_PROTOCOL_INSTANCE *PrivateData + ) +; + +VOID +PlatformBdsPolicyBehavior ( + IN EFI_BDS_ARCH_PROTOCOL_INSTANCE *PrivateData, + IN LIST_ENTRY *DriverOptionList, + IN LIST_ENTRY *BootOptionList + ) +; + +VOID +PlatformBdsGetDriverOption ( + IN LIST_ENTRY *BdsDriverLists + ) +; + +EFI_STATUS +BdsMemoryTest ( + EXTENDMEM_COVERAGE_LEVEL Level + ) +; + +EFI_STATUS +PlatformBdsShowProgress ( + EFI_UGA_PIXEL TitleForeground, + EFI_UGA_PIXEL TitleBackground, + CHAR16 *Title, + EFI_UGA_PIXEL ProgressColor, + UINTN Progress, + UINTN PreviousValue + ) +; + +VOID +PlatformBdsConnectSequence ( + VOID + ) +; + +VOID +PlatformBdsBootFail ( + IN BDS_COMMON_OPTION *Option, + IN EFI_STATUS Status, + IN CHAR16 *ExitData, + IN UINTN ExitDataSize + ) +; + +VOID +PlatformBdsBootSuccess ( + IN BDS_COMMON_OPTION *Option + ) +; + +EFI_STATUS +ProcessCapsules ( + EFI_BOOT_MODE BootMode + ) +; + +EFI_STATUS +PlatformBdsConnectConsole ( + IN BDS_CONSOLE_CONNECT_ENTRY *PlatformConsole + ) +; + +EFI_STATUS +PlatformBdsNoConsoleAction ( + VOID + ) +; + +#endif // _BDS_PLATFORM_H diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/Bds.dxs b/EdkNt32Pkg/Dxe/PlatformBds/Generic/Bds.dxs new file mode 100644 index 0000000000..6647561959 --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/Generic/Bds.dxs @@ -0,0 +1,27 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Bds.dxs + +Abstract: + + Dependency expression source file. This driver produces an arch protocol, so + must dipatch early. + +--*/ +#include +#include + +DEPENDENCY_START + EFI_HII_PROTOCOL_GUID +DEPENDENCY_END \ No newline at end of file diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/Bds.h b/EdkNt32Pkg/Dxe/PlatformBds/Generic/Bds.h new file mode 100644 index 0000000000..2d9d199610 --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/Generic/Bds.h @@ -0,0 +1,83 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Bds.h + +Abstract: + + Head file for BDS Architectural Protocol implementation + +Revision History + +--*/ + +#ifndef _BDS_H +#define _BDS_H + +// +// Bds AP Context data +// +#define EFI_BDS_ARCH_PROTOCOL_INSTANCE_SIGNATURE EFI_SIGNATURE_32 ('B', 'd', 's', 'A') +typedef struct { + UINTN Signature; + + EFI_HANDLE Handle; + + EFI_BDS_ARCH_PROTOCOL Bds; + + // + // Save the current boot mode + // + EFI_BOOT_MODE BootMode; + + // + // Set true if boot with default settings + // + BOOLEAN DefaultBoot; + + // + // The system default timeout for choose the boot option + // + UINT16 TimeoutDefault; + + // + // Memory Test Level + // + EXTENDMEM_COVERAGE_LEVEL MemoryTestLevel; + +} EFI_BDS_ARCH_PROTOCOL_INSTANCE; + +#define EFI_BDS_ARCH_PROTOCOL_INSTANCE_FROM_THIS(_this) \ + CR (_this, \ + EFI_BDS_ARCH_PROTOCOL_INSTANCE, \ + Bds, \ + EFI_BDS_ARCH_PROTOCOL_INSTANCE_SIGNATURE \ + ) + +// +// Prototypes +// +EFI_STATUS +EFIAPI +BdsInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +EFI_STATUS +EFIAPI +BdsEntry ( + IN EFI_BDS_ARCH_PROTOCOL *This + ); + +#endif diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/BdsEntry.c b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BdsEntry.c new file mode 100644 index 0000000000..ddd6b4f78e --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BdsEntry.c @@ -0,0 +1,356 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + BdsEntry.c + +Abstract: + + The entry of the bds + +--*/ + +#include "Bds.h" +#include "BdsPlatform.h" +#include "FrontPage.h" + +EFI_BDS_ARCH_PROTOCOL_INSTANCE gBdsInstanceTemplate = { + EFI_BDS_ARCH_PROTOCOL_INSTANCE_SIGNATURE, + NULL, + BdsEntry, + 0xFFFF, + TRUE, + EXTENSIVE +}; + +UINT16 *mBootNext = NULL; + +EFI_HANDLE mBdsImageHandle; + +EFI_STATUS +EFIAPI +BdsInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Install Boot Device Selection Protocol + +Arguments: + + (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT) + +Returns: + + EFI_SUCEESS - BDS has finished initializing. + Rerun the + dispatcher and recall BDS.Entry + + Other - Return value from EfiLibAllocatePool() + or gBS->InstallProtocolInterface + +--*/ +{ + EFI_STATUS Status; + + mBdsImageHandle = ImageHandle; + + // + // Install protocol interface + // + Status = gBS->InstallProtocolInterface ( + &gBdsInstanceTemplate.Handle, + &gEfiBdsArchProtocolGuid, + EFI_NATIVE_INTERFACE, + &gBdsInstanceTemplate.Bds + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +VOID +BdsBootDeviceSelect ( + VOID + ) +/*++ + +Routine Description: + + In the loop of attempt to boot for the boot order + +Arguments: + + None. + +Returns: + + None. + +--*/ +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + BDS_COMMON_OPTION *BootOption; + UINTN ExitDataSize; + CHAR16 *ExitData; + UINT16 Timeout; + LIST_ENTRY BootLists; + CHAR16 Buffer[20]; + BOOLEAN BootNextExist; + LIST_ENTRY *LinkBootNext; + + // + // Got the latest boot option + // + BootNextExist = FALSE; + LinkBootNext = NULL; + InitializeListHead (&BootLists); + + // + // First check the boot next option + // + ZeroMem (Buffer, sizeof (Buffer)); + + if (mBootNext != NULL) { + // + // Indicate we have the boot next variable, so this time + // boot will always have this boot option + // + BootNextExist = TRUE; + + // + // Clear the this variable so it's only exist in this time boot + // + gRT->SetVariable ( + L"BootNext", + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + 0, + mBootNext + ); + + // + // Add the boot next boot option + // + UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *mBootNext); + BootOption = BdsLibVariableToOption (&BootLists, Buffer); + } + // + // Parse the boot order to get boot option + // + BdsLibBuildOptionFromVar (&BootLists, L"BootOrder"); + Link = BootLists.ForwardLink; + + // + // Parameter check, make sure the loop will be valid + // + if (Link == NULL) { + return ; + } + // + // Here we make the boot in a loop, every boot success will + // return to the front page + // + for (;;) { + // + // Check the boot option list first + // + if (Link == &BootLists) { + // + // There are two ways to enter here: + // 1. There is no active boot option, give user chance to + // add new boot option + // 2. All the active boot option processed, and there is no + // one is success to boot, then we back here to allow user + // add new active boot option + // + Timeout = 0xffff; + PlatformBdsEnterFrontPage (Timeout, FALSE); + InitializeListHead (&BootLists); + BdsLibBuildOptionFromVar (&BootLists, L"BootOrder"); + Link = BootLists.ForwardLink; + continue; + } + // + // Get the boot option from the link list + // + BootOption = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE); + + // + // According to EFI Specification, if a load option is not marked + // as LOAD_OPTION_ACTIVE, the boot manager will not automatically + // load the option. + // + if (!IS_LOAD_OPTION_TYPE (BootOption->Attribute, LOAD_OPTION_ACTIVE)) { + // + // skip the header of the link list, becuase it has no boot option + // + Link = Link->ForwardLink; + continue; + } + // + // Make sure the boot option device path connected, + // but ignore the BBS device path + // + if (DevicePathType (BootOption->DevicePath) != BBS_DEVICE_PATH) { + // + // Notes: the internal shell can not been connected with device path + // so we do not check the status here + // + BdsLibConnectDevicePath (BootOption->DevicePath); + } + // + // All the driver options should have been processed since + // now boot will be performed. + // + PERF_END (0, BDS_TOK, NULL, 0); + Status = BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData); + if (EFI_ERROR (Status)) { + // + // Call platform action to indicate the boot fail + // + PlatformBdsBootFail (BootOption, Status, ExitData, ExitDataSize); + + // + // Check the next boot option + // + Link = Link->ForwardLink; + + } else { + // + // Call platform action to indicate the boot success + // + PlatformBdsBootSuccess (BootOption); + + // + // Boot success, then stop process the boot order, and + // present the boot manager menu, front page + // + Timeout = 0xffff; + PlatformBdsEnterFrontPage (Timeout, FALSE); + + // + // Rescan the boot option list, avoid pertential risk of the boot + // option change in front page + // + if (BootNextExist) { + LinkBootNext = BootLists.ForwardLink; + } + + InitializeListHead (&BootLists); + if (LinkBootNext != NULL) { + // + // Reserve the boot next option + // + InsertTailList (&BootLists, LinkBootNext); + } + + BdsLibBuildOptionFromVar (&BootLists, L"BootOrder"); + Link = BootLists.ForwardLink; + } + } + + return ; + +} + +EFI_STATUS +EFIAPI +BdsEntry ( + IN EFI_BDS_ARCH_PROTOCOL *This + ) +/*++ + +Routine Description: + + Service routine for BdsInstance->Entry(). Devices are connected, the + consoles are initialized, and the boot options are tried. + +Arguments: + + This - Protocol Instance structure. + +Returns: + + EFI_SUCEESS - BDS->Entry has finished executing. + +--*/ +{ + EFI_BDS_ARCH_PROTOCOL_INSTANCE *PrivateData; + LIST_ENTRY DriverOptionList; + LIST_ENTRY BootOptionList; + UINTN BootNextSize; + + // + // Insert the performance probe + // + PERF_END (0, DXE_TOK, NULL, 0); + PERF_START (0, BDS_TOK, NULL, 0); + + // + // Initialize the global system boot option and driver option + // + InitializeListHead (&DriverOptionList); + InitializeListHead (&BootOptionList); + + // + // Get the BDS private data + // + PrivateData = EFI_BDS_ARCH_PROTOCOL_INSTANCE_FROM_THIS (This); + + // + // Do the platform init, can be customized by OEM/IBV + // + PERF_START (0, "PlatformBds", "BDS", 0); + PlatformBdsInit (PrivateData); + + // + // Set up the device list based on EFI 1.1 variables + // process Driver#### and Load the driver's in the + // driver option list + // + BdsLibBuildOptionFromVar (&DriverOptionList, L"DriverOrder"); + if (!IsListEmpty (&DriverOptionList)) { + BdsLibLoadDrivers (&DriverOptionList); + } + // + // Check if we have the boot next option + // + mBootNext = BdsLibGetVariableAndSize ( + L"BootNext", + &gEfiGlobalVariableGuid, + &BootNextSize + ); + + // + // Setup some platform policy here + // + PlatformBdsPolicyBehavior (PrivateData, &DriverOptionList, &BootOptionList); + PERF_END (0, L"PlatformBds", L"BDS", 0); + + // + // BDS select the boot device to load OS + // + BdsBootDeviceSelect (); + + // + // Only assert here since this is the right behavior, we should never + // return back to DxeCore. + // + ASSERT (FALSE); + + return EFI_SUCCESS; +} diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/BBSsupport.c b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/BBSsupport.c new file mode 100644 index 0000000000..a33be4b046 --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/BBSsupport.c @@ -0,0 +1,1515 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + BBSsupport.c + +Abstract: + + This function deal with the legacy boot option, it create, delete + and manage the legacy boot option, all legacy boot option is getting from + the legacy BBS table. + +--*/ + +#include "BBSsupport.h" + +EFI_DEVICE_PATH_PROTOCOL EndDevicePath[] = { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + END_DEVICE_PATH_LENGTH, + 0 +}; + +VOID +AsciiToUnicodeSize ( + IN UINT8 *a, + IN UINTN Size, + OUT UINT16 *u + ) +{ + UINTN i; + + i = 0; + while (a[i] != 0) { + u[i] = (CHAR16) a[i]; + if (i == Size) { + u[i] = 0; + break; + } + + i++; + } +} + +VOID +BdsBuildLegacyDevNameString ( + IN BBS_TABLE *CurBBSEntry, + IN UINTN Index, + IN UINTN BufSize, + OUT CHAR16 *BootString + ) +{ + CHAR16 *Fmt; + CHAR16 *Type; + UINT8 *StringDesc; + CHAR16 temp[80]; + + switch (Index) { + // + // Primary Master + // + case 1: + Fmt = L"Primary Master %s"; + break; + + // + // Primary Slave + // + case 2: + Fmt = L"Primary Slave %s"; + break; + + // + // Secondary Master + // + case 3: + Fmt = L"Secondary Master %s"; + break; + + // + // Secondary Slave + // + case 4: + Fmt = L"Secondary Slave %s"; + break; + + default: + Fmt = L"%s"; + break; + } + + switch (CurBBSEntry->DeviceType) { + case BBS_FLOPPY: + Type = L"Floppy"; + break; + + case BBS_HARDDISK: + Type = L"Harddisk"; + break; + + case BBS_CDROM: + Type = L"CDROM"; + break; + + case BBS_PCMCIA: + Type = L"PCMCIAe"; + break; + + case BBS_USB: + Type = L"USB"; + break; + + case BBS_EMBED_NETWORK: + Type = L"Network"; + break; + + case BBS_BEV_DEVICE: + Type = L"BEVe"; + break; + + case BBS_UNKNOWN: + default: + Type = L"Unknown"; + break; + } + // + // If current BBS entry has its description then use it. + // + StringDesc = (UINT8 *) (UINTN) ((CurBBSEntry->DescStringSegment << 4) + CurBBSEntry->DescStringOffset); + if (NULL != StringDesc) { + // + // Only get fisrt 32 characters, this is suggested by BBS spec + // + AsciiToUnicodeSize (StringDesc, 32, temp); + Fmt = L"%s"; + Type = temp; + } + + UnicodeSPrint (BootString, BufSize, Fmt, Type); +} + +EFI_STATUS +BdsCreateLegacyBootOption ( + IN BBS_TABLE *CurrentBbsEntry, + IN EFI_DEVICE_PATH_PROTOCOL *CurrentBbsDevPath, + IN UINTN Index, + IN OUT UINT16 **BootOrderList, + IN OUT UINTN *BootOrderListSize + ) +{ + EFI_STATUS Status; + UINT16 CurrentBootOptionNo; + UINT16 BootString[10]; + UINT16 BootDesc[100]; + UINT16 *NewBootOrderList; + UINTN BufferSize; + VOID *Buffer; + UINT8 *Ptr; + UINT16 CurrentBbsDevPathSize; + UINTN BootOrderIndex; + UINTN BootOrderLastIndex; + UINTN ArrayIndex; + BOOLEAN IndexNotFound; + + if (NULL == (*BootOrderList)) { + CurrentBootOptionNo = 0; + } else { + for (ArrayIndex = 0; ArrayIndex < (UINTN) (*BootOrderListSize / sizeof (UINT16)); ArrayIndex++) { + IndexNotFound = TRUE; + for (BootOrderIndex = 0; BootOrderIndex < (UINTN) (*BootOrderListSize / sizeof (UINT16)); BootOrderIndex++) { + if ((*BootOrderList)[BootOrderIndex] == ArrayIndex) { + IndexNotFound = FALSE; + break; + } + } + + if (!IndexNotFound) { + continue; + } else { + break; + } + } + + CurrentBootOptionNo = (UINT16) ArrayIndex; + } + + UnicodeSPrint ( + BootString, + sizeof (BootString), + L"Boot%04x", + CurrentBootOptionNo + ); + + BdsBuildLegacyDevNameString (CurrentBbsEntry, Index, sizeof (BootDesc), BootDesc); + + CurrentBbsDevPathSize = (UINT16) (GetDevicePathSize (CurrentBbsDevPath)); + + BufferSize = sizeof (UINT32) + + sizeof (UINT16) + + StrSize (BootDesc) + + CurrentBbsDevPathSize + + sizeof (BBS_TABLE) + + sizeof (UINT16); + + Buffer = AllocateZeroPool (BufferSize); + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Ptr = (UINT8 *) Buffer; + + *((UINT32 *) Ptr) = LOAD_OPTION_ACTIVE; + Ptr += sizeof (UINT32); + + *((UINT16 *) Ptr) = CurrentBbsDevPathSize; + Ptr += sizeof (UINT16); + + CopyMem ( + Ptr, + BootDesc, + StrSize (BootDesc) + ); + Ptr += StrSize (BootDesc); + + CopyMem ( + Ptr, + CurrentBbsDevPath, + CurrentBbsDevPathSize + ); + Ptr += CurrentBbsDevPathSize; + + CopyMem ( + Ptr, + CurrentBbsEntry, + sizeof (BBS_TABLE) + ); + + Ptr += sizeof (BBS_TABLE); + *((UINT16 *) Ptr) = (UINT16) Index; + + Status = gRT->SetVariable ( + BootString, + &gEfiGlobalVariableGuid, + VAR_FLAG, + BufferSize, + Buffer + ); + + SafeFreePool (Buffer); + Buffer = NULL; + + NewBootOrderList = AllocateZeroPool (*BootOrderListSize + sizeof (UINT16)); + if (NULL == NewBootOrderList) { + return EFI_OUT_OF_RESOURCES; + } + + if (NULL != *BootOrderList) { + CopyMem (NewBootOrderList, *BootOrderList, *BootOrderListSize); + } + + BootOrderLastIndex = (UINTN) (*BootOrderListSize / sizeof (UINT16)); + NewBootOrderList[BootOrderLastIndex] = CurrentBootOptionNo; + *BootOrderListSize += sizeof (UINT16); + *BootOrderList = NewBootOrderList; + + return Status; +} + +BOOLEAN +BdsIsLegacyBootOption ( + IN UINT8 *BootOptionVar, + OUT BBS_TABLE **BbsEntry, + OUT UINT16 *BbsIndex + ) +{ + UINT8 *Ptr; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + BOOLEAN Ret; + UINT16 DevPathLen; + + Ptr = BootOptionVar; + Ptr += sizeof (UINT32); + DevPathLen = *(UINT16 *) Ptr; + Ptr += sizeof (UINT16); + Ptr += StrSize ((UINT16 *) Ptr); + DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr; + if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) { + Ptr += DevPathLen; + *BbsEntry = (BBS_TABLE *) Ptr; + Ptr += sizeof (BBS_TABLE); + *BbsIndex = *(UINT16 *) Ptr; + Ret = TRUE; + } else { + *BbsEntry = NULL; + Ret = FALSE; + } + + return Ret; +} + +EFI_STATUS +BdsDeleteBootOption ( + IN UINTN OptionNumber, + IN OUT UINT16 *BootOrder, + IN OUT UINTN *BootOrderSize + ) +{ + UINT16 BootOption[100]; + UINTN Index; + EFI_STATUS Status; + UINTN Index2Del; + + Status = EFI_SUCCESS; + Index2Del = 0; + + UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", OptionNumber); + Status = EfiLibDeleteVariable (BootOption, &gEfiGlobalVariableGuid); + // + // adjust boot order array + // + for (Index = 0; Index < *BootOrderSize / sizeof (UINT16); Index++) { + if (BootOrder[Index] == OptionNumber) { + Index2Del = Index; + break; + } + } + + if (Index != *BootOrderSize / sizeof (UINT16)) { + for (Index = 0; Index < *BootOrderSize / sizeof (UINT16) - 1; Index++) { + if (Index >= Index2Del) { + BootOrder[Index] = BootOrder[Index + 1]; + } + } + + *BootOrderSize -= sizeof (UINT16); + } + + return Status; + +} + +EFI_STATUS +BdsDeleteAllInvalidLegacyBootOptions ( + VOID + ) +{ + UINT16 *BootOrder; + UINT8 *BootOptionVar; + UINTN BootOrderSize; + UINTN BootOptionSize; + EFI_STATUS Status; + UINT16 HddCount; + UINT16 BbsCount; + HDD_INFO *LocalHddInfo; + BBS_TABLE *LocalBbsTable; + BBS_TABLE *BbsEntry; + UINT16 BbsIndex; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + UINTN Index; + UINT16 BootOption[10]; + + Status = EFI_SUCCESS; + BootOrder = NULL; + BootOrderSize = 0; + HddCount = 0; + BbsCount = 0; + LocalHddInfo = NULL; + LocalBbsTable = NULL; + BbsEntry = NULL; + + Status = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, &LegacyBios); + if (EFI_ERROR (Status)) { + return Status; + } + + LegacyBios->GetBbsInfo ( + LegacyBios, + &HddCount, + &LocalHddInfo, + &BbsCount, + &LocalBbsTable + ); + + BootOrder = BdsLibGetVariableAndSize ( + L"BootOrder", + &gEfiGlobalVariableGuid, + &BootOrderSize + ); + if (NULL == BootOrder) { + return EFI_NOT_FOUND; + } + + Index = 0; + while (Index < BootOrderSize / sizeof (UINT16)) { + UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]); + BootOptionVar = BdsLibGetVariableAndSize ( + BootOption, + &gEfiGlobalVariableGuid, + &BootOptionSize + ); + if (NULL == BootOptionVar) { + SafeFreePool (BootOrder); + return EFI_OUT_OF_RESOURCES; + } + + if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, &BbsIndex)) { + SafeFreePool (BootOptionVar); + Index++; + continue; + } + + if (!((LocalBbsTable[BbsIndex].BootPriority == BBS_IGNORE_ENTRY) || + (LocalBbsTable[BbsIndex].BootPriority == BBS_DO_NOT_BOOT_FROM) || + (LocalBbsTable[BbsIndex].BootPriority == BBS_LOWEST_PRIORITY)) && + LocalBbsTable[BbsIndex].DeviceType == BbsEntry->DeviceType) { + Index++; + continue; + } + + SafeFreePool (BootOptionVar); + // + // should delete + // + BdsDeleteBootOption ( + BootOrder[Index], + BootOrder, + &BootOrderSize + ); + } + + if (BootOrderSize) { + Status = gRT->SetVariable ( + L"BootOrder", + &gEfiGlobalVariableGuid, + VAR_FLAG, + BootOrderSize, + BootOrder + ); + } else { + EfiLibDeleteVariable (L"BootOrder", &gEfiGlobalVariableGuid); + } + + SafeFreePool (BootOrder); + + return Status; +} + +BOOLEAN +BdsFindLegacyBootOptionByDevType ( + IN UINT16 *BootOrder, + IN UINTN BootOptionNum, + IN UINT16 DevType, + OUT UINT32 *Attribute, + OUT UINT16 *BbsIndex, + OUT UINTN *OptionNumber + ) +{ + UINTN Index; + UINTN BootOrderIndex; + UINT16 BootOption[100]; + UINTN BootOptionSize; + UINT8 *BootOptionVar; + BBS_TABLE *BbsEntry; + BOOLEAN Found; + + BbsEntry = NULL; + Found = FALSE; + + if (NULL == BootOrder) { + return Found; + } + + for (BootOrderIndex = 0; BootOrderIndex < BootOptionNum; BootOrderIndex++) { + Index = (UINTN) BootOrder[BootOrderIndex]; + UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", Index); + BootOptionVar = BdsLibGetVariableAndSize ( + BootOption, + &gEfiGlobalVariableGuid, + &BootOptionSize + ); + if (NULL == BootOptionVar) { + continue; + } + + if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, BbsIndex)) { + SafeFreePool (BootOptionVar); + continue; + } + + if (BbsEntry->DeviceType != DevType) { + SafeFreePool (BootOptionVar); + continue; + } + + *Attribute = *(UINT32 *) BootOptionVar; + *OptionNumber = Index; + Found = TRUE; + SafeFreePool (BootOptionVar); + break; + } + + return Found; +} + +EFI_STATUS +BdsCreateOneLegacyBootOption ( + IN BBS_TABLE *BbsItem, + IN UINTN Index, + IN OUT UINT16 **BootOrderList, + IN OUT UINTN *BootOrderListSize + ) +{ + BBS_BBS_DEVICE_PATH BbsDevPathNode; + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *DevPath; + + DevPath = NULL; + + BbsDevPathNode.Header.Type = BBS_DEVICE_PATH; + BbsDevPathNode.Header.SubType = BBS_BBS_DP; + SetDevicePathNodeLength (&BbsDevPathNode.Header, sizeof (BBS_BBS_DEVICE_PATH)); + BbsDevPathNode.DeviceType = BbsItem->DeviceType; + CopyMem (&BbsDevPathNode.StatusFlag, &BbsItem->StatusFlags, sizeof (UINT16)); + + DevPath = AppendDevicePathNode ( + EndDevicePath, + (EFI_DEVICE_PATH_PROTOCOL *) &BbsDevPathNode + ); + if (NULL == DevPath) { + return EFI_OUT_OF_RESOURCES; + } + + Status = BdsCreateLegacyBootOption ( + BbsItem, + DevPath, + Index, + BootOrderList, + BootOrderListSize + ); + BbsItem->BootPriority = 0x00; + + gBS->FreePool (DevPath); + + return Status; +} + +EFI_STATUS +BdsAddNonExistingLegacyBootOptions ( + VOID + ) +/*++ + +Routine Description: + + Add the legacy boot options from BBS table if they do not exist. + +Arguments: + + None. + +Returns: + + EFI_SUCCESS - The boot options are added successfully or they are already in boot options. + others - An error occurred when creating legacy boot options. + +--*/ +{ + UINT16 *BootOrder; + UINTN BootOrderSize; + EFI_STATUS Status; + UINT16 HddCount; + UINT16 BbsCount; + HDD_INFO *LocalHddInfo; + BBS_TABLE *LocalBbsTable; + UINT16 BbsIndex; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + UINTN Index; + UINT32 Attribute; + UINTN OptionNumber; + BOOLEAN Ret; + + BootOrder = NULL; + HddCount = 0; + BbsCount = 0; + LocalHddInfo = NULL; + LocalBbsTable = NULL; + + Status = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, &LegacyBios); + if (EFI_ERROR (Status)) { + return Status; + } + + LegacyBios->GetBbsInfo ( + LegacyBios, + &HddCount, + &LocalHddInfo, + &BbsCount, + &LocalBbsTable + ); + + BootOrder = BdsLibGetVariableAndSize ( + L"BootOrder", + &gEfiGlobalVariableGuid, + &BootOrderSize + ); + if (NULL == BootOrder) { + BootOrderSize = 0; + } + + for (Index = 0; Index < BbsCount; Index++) { + if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) || + (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM) + ) { + continue; + } + + Ret = BdsFindLegacyBootOptionByDevType ( + BootOrder, + BootOrderSize / sizeof (UINT16), + LocalBbsTable[Index].DeviceType, + &Attribute, + &BbsIndex, + &OptionNumber + ); + if (Ret && (Attribute & LOAD_OPTION_ACTIVE) != 0) { + continue; + } + + if (Ret) { + if (Index != BbsIndex) { + BdsDeleteBootOption ( + OptionNumber, + BootOrder, + &BootOrderSize + ); + } else { + continue; + } + } + // + // Not found such type of legacy device in boot options or we found but it's disabled + // so we have to create one and put it to the tail of boot order list + // + Status = BdsCreateOneLegacyBootOption ( + &LocalBbsTable[Index], + Index, + &BootOrder, + &BootOrderSize + ); + if (EFI_ERROR (Status)) { + break; + } + } + + if (BootOrderSize > 0) { + Status = gRT->SetVariable ( + L"BootOrder", + &gEfiGlobalVariableGuid, + VAR_FLAG, + BootOrderSize, + BootOrder + ); + } else { + EfiLibDeleteVariable (L"BootOrder", &gEfiGlobalVariableGuid); + } + + if (BootOrder != NULL) { + SafeFreePool (BootOrder); + } + + return Status; +} + +UINT16 * +BdsFillDevOrderBuf ( + IN BBS_TABLE *BbsTable, + IN BBS_TYPE BbsType, + IN UINTN BbsCount, + IN UINT16 *Buf + ) +{ + UINTN Index; + + for (Index = 0; Index < BbsCount; Index++) { + if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) { + continue; + } + + if (BbsTable[Index].DeviceType != BbsType) { + continue; + } + + *Buf = (UINT16) (Index & 0xFF); + Buf++; + } + + return Buf; +} + +EFI_STATUS +BdsCreateDevOrder ( + IN BBS_TABLE *BbsTable, + IN UINT16 BbsCount + ) +{ + UINTN Index; + UINTN FDCount; + UINTN HDCount; + UINTN CDCount; + UINTN NETCount; + UINTN BEVCount; + UINTN TotalSize; + UINTN HeaderSize; + UINT8 *DevOrder; + UINT8 *Ptr; + EFI_STATUS Status; + + FDCount = 0; + HDCount = 0; + CDCount = 0; + NETCount = 0; + BEVCount = 0; + TotalSize = 0; + HeaderSize = sizeof (BBS_TYPE) + sizeof (UINT16); + DevOrder = NULL; + Ptr = NULL; + Status = EFI_SUCCESS; + + for (Index = 0; Index < BbsCount; Index++) { + if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) { + continue; + } + + switch (BbsTable[Index].DeviceType) { + case BBS_FLOPPY: + FDCount++; + break; + + case BBS_HARDDISK: + HDCount++; + break; + + case BBS_CDROM: + CDCount++; + break; + + case BBS_EMBED_NETWORK: + NETCount++; + break; + + case BBS_BEV_DEVICE: + BEVCount++; + break; + + default: + break; + } + } + + TotalSize += (HeaderSize + sizeof (UINT16) * FDCount); + TotalSize += (HeaderSize + sizeof (UINT16) * HDCount); + TotalSize += (HeaderSize + sizeof (UINT16) * CDCount); + TotalSize += (HeaderSize + sizeof (UINT16) * NETCount); + TotalSize += (HeaderSize + sizeof (UINT16) * BEVCount); + + DevOrder = AllocateZeroPool (TotalSize); + if (NULL == DevOrder) { + return EFI_OUT_OF_RESOURCES; + } + + Ptr = DevOrder; + + *((BBS_TYPE *) Ptr) = BBS_FLOPPY; + Ptr += sizeof (BBS_TYPE); + *((UINT16 *) Ptr) = (UINT16) (sizeof (UINT16) + FDCount * sizeof (UINT16)); + Ptr += sizeof (UINT16); + if (FDCount) { + Ptr = (UINT8 *) BdsFillDevOrderBuf (BbsTable, BBS_FLOPPY, BbsCount, (UINT16 *) Ptr); + } + + *((BBS_TYPE *) Ptr) = BBS_HARDDISK; + Ptr += sizeof (BBS_TYPE); + *((UINT16 *) Ptr) = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16)); + Ptr += sizeof (UINT16); + if (HDCount) { + Ptr = (UINT8 *) BdsFillDevOrderBuf (BbsTable, BBS_HARDDISK, BbsCount, (UINT16 *) Ptr); + } + + *((BBS_TYPE *) Ptr) = BBS_CDROM; + Ptr += sizeof (BBS_TYPE); + *((UINT16 *) Ptr) = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16)); + Ptr += sizeof (UINT16); + if (CDCount) { + Ptr = (UINT8 *) BdsFillDevOrderBuf (BbsTable, BBS_CDROM, BbsCount, (UINT16 *) Ptr); + } + + *((BBS_TYPE *) Ptr) = BBS_EMBED_NETWORK; + Ptr += sizeof (BBS_TYPE); + *((UINT16 *) Ptr) = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16)); + Ptr += sizeof (UINT16); + if (NETCount) { + Ptr = (UINT8 *) BdsFillDevOrderBuf (BbsTable, BBS_EMBED_NETWORK, BbsCount, (UINT16 *) Ptr); + } + + *((BBS_TYPE *) Ptr) = BBS_BEV_DEVICE; + Ptr += sizeof (BBS_TYPE); + *((UINT16 *) Ptr) = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16)); + Ptr += sizeof (UINT16); + if (BEVCount) { + Ptr = (UINT8 *) BdsFillDevOrderBuf (BbsTable, BBS_BEV_DEVICE, BbsCount, (UINT16 *) Ptr); + } + + Status = gRT->SetVariable ( + VarLegacyDevOrder, + &EfiLegacyDevOrderGuid, + VAR_FLAG, + TotalSize, + DevOrder + ); + SafeFreePool (DevOrder); + + return Status; +} + +EFI_STATUS +BdsUpdateLegacyDevOrder ( + VOID + ) +/*++ +Format of LegacyDevOrder variable: +|----------------------------------------------------------------------------------------------------------------- +| BBS_FLOPPY | Length | Index0 | Index1 | ... | BBS_HARDDISK | Length | Index0 | Index1 | ... | BBS_CDROM | Length | Index0 | ... +|----------------------------------------------------------------------------------------------------------------- + +Length is a 16 bit integer, it indicates how many Indexes follows, including the size of itself. +Index# is a 16 bit integer, the low byte of it stands for the index in BBS table + the high byte of it only have two value 0 and 0xFF, 0xFF means this device has been + disabled by user. +--*/ +{ + UINT8 *DevOrder; + UINT8 *NewDevOrder; + UINTN DevOrderSize; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + EFI_STATUS Status; + UINT16 HddCount; + UINT16 BbsCount; + HDD_INFO *LocalHddInfo; + BBS_TABLE *LocalBbsTable; + UINTN Index; + UINTN Index2; + UINTN *Idx; + UINTN FDCount; + UINTN HDCount; + UINTN CDCount; + UINTN NETCount; + UINTN BEVCount; + UINTN TotalSize; + UINTN HeaderSize; + UINT8 *Ptr; + UINT8 *NewPtr; + UINT16 *NewFDPtr; + UINT16 *NewHDPtr; + UINT16 *NewCDPtr; + UINT16 *NewNETPtr; + UINT16 *NewBEVPtr; + UINT16 *NewDevPtr; + UINT16 Length; + UINT16 tmp; + UINTN FDIndex; + UINTN HDIndex; + UINTN CDIndex; + UINTN NETIndex; + UINTN BEVIndex; + + LocalHddInfo = NULL; + LocalBbsTable = NULL; + Idx = NULL; + FDCount = 0; + HDCount = 0; + CDCount = 0; + NETCount = 0; + BEVCount = 0; + TotalSize = 0; + HeaderSize = sizeof (BBS_TYPE) + sizeof (UINT16); + FDIndex = 0; + HDIndex = 0; + CDIndex = 0; + NETIndex = 0; + BEVIndex = 0; + NewDevPtr = NULL; + + Status = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, &LegacyBios); + if (EFI_ERROR (Status)) { + return Status; + } + + LegacyBios->GetBbsInfo ( + LegacyBios, + &HddCount, + &LocalHddInfo, + &BbsCount, + &LocalBbsTable + ); + + DevOrder = (UINT8 *) BdsLibGetVariableAndSize ( + VarLegacyDevOrder, + &EfiLegacyDevOrderGuid, + &DevOrderSize + ); + if (NULL == DevOrder) { + return BdsCreateDevOrder (LocalBbsTable, BbsCount); + } + // + // First we figure out how many boot devices with same device type respectively + // + for (Index = 0; Index < BbsCount; Index++) { + if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) || + (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM) || + (LocalBbsTable[Index].BootPriority == BBS_LOWEST_PRIORITY) + ) { + continue; + } + + switch (LocalBbsTable[Index].DeviceType) { + case BBS_FLOPPY: + FDCount++; + break; + + case BBS_HARDDISK: + HDCount++; + break; + + case BBS_CDROM: + CDCount++; + break; + + case BBS_EMBED_NETWORK: + NETCount++; + break; + + case BBS_BEV_DEVICE: + BEVCount++; + break; + + default: + break; + } + } + + TotalSize += (HeaderSize + FDCount * sizeof (UINT16)); + TotalSize += (HeaderSize + HDCount * sizeof (UINT16)); + TotalSize += (HeaderSize + CDCount * sizeof (UINT16)); + TotalSize += (HeaderSize + NETCount * sizeof (UINT16)); + TotalSize += (HeaderSize + BEVCount * sizeof (UINT16)); + + NewDevOrder = AllocateZeroPool (TotalSize); + if (NULL == NewDevOrder) { + return EFI_OUT_OF_RESOURCES; + } + + NewFDPtr = (UINT16 *) (NewDevOrder + HeaderSize); + NewHDPtr = (UINT16 *) ((UINT8 *) NewFDPtr + FDCount * sizeof (UINT16) + HeaderSize); + NewCDPtr = (UINT16 *) ((UINT8 *) NewHDPtr + HDCount * sizeof (UINT16) + HeaderSize); + NewNETPtr = (UINT16 *) ((UINT8 *) NewCDPtr + CDCount * sizeof (UINT16) + HeaderSize); + NewBEVPtr = (UINT16 *) ((UINT8 *) NewNETPtr + NETCount * sizeof (UINT16) + HeaderSize); + + // + // copy FD + // + Ptr = DevOrder; + NewPtr = NewDevOrder; + *((BBS_TYPE *) NewPtr) = *((BBS_TYPE *) Ptr); + Ptr += sizeof (BBS_TYPE); + NewPtr += sizeof (BBS_TYPE); + Length = *((UINT16 *) Ptr); + *((UINT16 *) NewPtr) = (UINT16) (sizeof (UINT16) + FDCount * sizeof (UINT16)); + Ptr += sizeof (UINT16); + + for (Index = 0; Index < Length / sizeof (UINT16) - 1; Index++) { + if (LocalBbsTable[*Ptr].BootPriority == BBS_IGNORE_ENTRY || + LocalBbsTable[*Ptr].BootPriority == BBS_DO_NOT_BOOT_FROM || + LocalBbsTable[*Ptr].BootPriority == BBS_LOWEST_PRIORITY || + LocalBbsTable[*Ptr].DeviceType != BBS_FLOPPY + ) { + Ptr += sizeof (UINT16); + continue; + } + + NewFDPtr[FDIndex] = *(UINT16 *) Ptr; + FDIndex++; + Ptr += sizeof (UINT16); + } + // + // copy HD + // + NewPtr = (UINT8 *) NewHDPtr - HeaderSize; + *((BBS_TYPE *) NewPtr) = *((BBS_TYPE *) Ptr); + Ptr += sizeof (BBS_TYPE); + NewPtr += sizeof (BBS_TYPE); + Length = *((UINT16 *) Ptr); + *((UINT16 *) NewPtr) = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16)); + Ptr += sizeof (UINT16); + + for (Index = 0; Index < Length / sizeof (UINT16) - 1; Index++) { + if (LocalBbsTable[*Ptr].BootPriority == BBS_IGNORE_ENTRY || + LocalBbsTable[*Ptr].BootPriority == BBS_DO_NOT_BOOT_FROM || + LocalBbsTable[*Ptr].BootPriority == BBS_LOWEST_PRIORITY || + LocalBbsTable[*Ptr].DeviceType != BBS_HARDDISK + ) { + Ptr += sizeof (UINT16); + continue; + } + + NewHDPtr[HDIndex] = *(UINT16 *) Ptr; + HDIndex++; + Ptr += sizeof (UINT16); + } + // + // copy CD + // + NewPtr = (UINT8 *) NewCDPtr - HeaderSize; + *((BBS_TYPE *) NewPtr) = *((BBS_TYPE *) Ptr); + Ptr += sizeof (BBS_TYPE); + NewPtr += sizeof (BBS_TYPE); + Length = *((UINT16 *) Ptr); + *((UINT16 *) NewPtr) = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16)); + Ptr += sizeof (UINT16); + + for (Index = 0; Index < Length / sizeof (UINT16) - 1; Index++) { + if (LocalBbsTable[*Ptr].BootPriority == BBS_IGNORE_ENTRY || + LocalBbsTable[*Ptr].BootPriority == BBS_DO_NOT_BOOT_FROM || + LocalBbsTable[*Ptr].BootPriority == BBS_LOWEST_PRIORITY || + LocalBbsTable[*Ptr].DeviceType != BBS_CDROM + ) { + Ptr += sizeof (UINT16); + continue; + } + + NewCDPtr[CDIndex] = *(UINT16 *) Ptr; + CDIndex++; + Ptr += sizeof (UINT16); + } + // + // copy NET + // + NewPtr = (UINT8 *) NewNETPtr - HeaderSize; + *((BBS_TYPE *) NewPtr) = *((BBS_TYPE *) Ptr); + Ptr += sizeof (BBS_TYPE); + NewPtr += sizeof (BBS_TYPE); + Length = *((UINT16 *) Ptr); + *((UINT16 *) NewPtr) = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16)); + Ptr += sizeof (UINT16); + + for (Index = 0; Index < Length / sizeof (UINT16) - 1; Index++) { + if (LocalBbsTable[*Ptr].BootPriority == BBS_IGNORE_ENTRY || + LocalBbsTable[*Ptr].BootPriority == BBS_DO_NOT_BOOT_FROM || + LocalBbsTable[*Ptr].BootPriority == BBS_LOWEST_PRIORITY || + LocalBbsTable[*Ptr].DeviceType != BBS_EMBED_NETWORK + ) { + Ptr += sizeof (UINT16); + continue; + } + + NewNETPtr[NETIndex] = *(UINT16 *) Ptr; + NETIndex++; + Ptr += sizeof (UINT16); + } + // + // copy BEV + // + NewPtr = (UINT8 *) NewBEVPtr - HeaderSize; + *((BBS_TYPE *) NewPtr) = *((BBS_TYPE *) Ptr); + Ptr += sizeof (BBS_TYPE); + NewPtr += sizeof (BBS_TYPE); + Length = *((UINT16 *) Ptr); + *((UINT16 *) NewPtr) = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16)); + Ptr += sizeof (UINT16); + + for (Index = 0; Index < Length / sizeof (UINT16) - 1; Index++) { + if (LocalBbsTable[*Ptr].BootPriority == BBS_IGNORE_ENTRY || + LocalBbsTable[*Ptr].BootPriority == BBS_DO_NOT_BOOT_FROM || + LocalBbsTable[*Ptr].BootPriority == BBS_LOWEST_PRIORITY || + LocalBbsTable[*Ptr].DeviceType != BBS_BEV_DEVICE + ) { + Ptr += sizeof (UINT16); + continue; + } + + NewBEVPtr[BEVIndex] = *(UINT16 *) Ptr; + BEVIndex++; + Ptr += sizeof (UINT16); + } + + for (Index = 0; Index < BbsCount; Index++) { + if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) || + (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM) || + (LocalBbsTable[Index].BootPriority == BBS_LOWEST_PRIORITY) + ) { + continue; + } + + switch (LocalBbsTable[Index].DeviceType) { + case BBS_FLOPPY: + Idx = &FDIndex; + NewDevPtr = NewFDPtr; + break; + + case BBS_HARDDISK: + Idx = &HDIndex; + NewDevPtr = NewHDPtr; + break; + + case BBS_CDROM: + Idx = &CDIndex; + NewDevPtr = NewCDPtr; + break; + + case BBS_EMBED_NETWORK: + Idx = &NETIndex; + NewDevPtr = NewNETPtr; + break; + + case BBS_BEV_DEVICE: + Idx = &BEVIndex; + NewDevPtr = NewBEVPtr; + break; + + default: + Idx = NULL; + break; + } + // + // at this point we have copied those valid indexes to new buffer + // and we should check if there is any new appeared boot device + // + if (Idx) { + for (Index2 = 0; Index2 < *Idx; Index2++) { + if ((NewDevPtr[Index2] & 0xFF) == (UINT16) Index) { + break; + } + } + + if (Index2 == *Idx) { + // + // Index2 == *Idx means we didn't find Index + // so Index is a new appeared device's index in BBS table + // save it. + // + NewDevPtr[*Idx] = (UINT16) (Index & 0xFF); + (*Idx)++; + } + } + } + + if (FDCount) { + // + // Just to make sure that disabled indexes are all at the end of the array + // + for (Index = 0; Index < FDIndex - 1; Index++) { + if (0xFF00 != (NewFDPtr[Index] & 0xFF00)) { + continue; + } + + for (Index2 = Index + 1; Index2 < FDIndex; Index2++) { + if (0 == (NewFDPtr[Index2] & 0xFF00)) { + tmp = NewFDPtr[Index]; + NewFDPtr[Index] = NewFDPtr[Index2]; + NewFDPtr[Index2] = tmp; + break; + } + } + } + } + + if (HDCount) { + // + // Just to make sure that disabled indexes are all at the end of the array + // + for (Index = 0; Index < HDIndex - 1; Index++) { + if (0xFF00 != (NewHDPtr[Index] & 0xFF00)) { + continue; + } + + for (Index2 = Index + 1; Index2 < HDIndex; Index2++) { + if (0 == (NewHDPtr[Index2] & 0xFF00)) { + tmp = NewHDPtr[Index]; + NewHDPtr[Index] = NewHDPtr[Index2]; + NewHDPtr[Index2] = tmp; + break; + } + } + } + } + + if (CDCount) { + // + // Just to make sure that disabled indexes are all at the end of the array + // + for (Index = 0; Index < CDIndex - 1; Index++) { + if (0xFF00 != (NewCDPtr[Index] & 0xFF00)) { + continue; + } + + for (Index2 = Index + 1; Index2 < CDIndex; Index2++) { + if (0 == (NewCDPtr[Index2] & 0xFF00)) { + tmp = NewCDPtr[Index]; + NewCDPtr[Index] = NewCDPtr[Index2]; + NewCDPtr[Index2] = tmp; + break; + } + } + } + } + + if (NETCount) { + // + // Just to make sure that disabled indexes are all at the end of the array + // + for (Index = 0; Index < NETIndex - 1; Index++) { + if (0xFF00 != (NewNETPtr[Index] & 0xFF00)) { + continue; + } + + for (Index2 = Index + 1; Index2 < NETIndex; Index2++) { + if (0 == (NewNETPtr[Index2] & 0xFF00)) { + tmp = NewNETPtr[Index]; + NewNETPtr[Index] = NewNETPtr[Index2]; + NewNETPtr[Index2] = tmp; + break; + } + } + } + } + + if (BEVCount) { + // + // Just to make sure that disabled indexes are all at the end of the array + // + for (Index = 0; Index < BEVIndex - 1; Index++) { + if (0xFF00 != (NewBEVPtr[Index] & 0xFF00)) { + continue; + } + + for (Index2 = Index + 1; Index2 < BEVIndex; Index2++) { + if (0 == (NewBEVPtr[Index2] & 0xFF00)) { + tmp = NewBEVPtr[Index]; + NewBEVPtr[Index] = NewBEVPtr[Index2]; + NewBEVPtr[Index2] = tmp; + break; + } + } + } + } + + SafeFreePool (DevOrder); + + Status = gRT->SetVariable ( + VarLegacyDevOrder, + &EfiLegacyDevOrderGuid, + VAR_FLAG, + TotalSize, + NewDevOrder + ); + SafeFreePool (NewDevOrder); + + return Status; +} + +EFI_STATUS +BdsSetBootPriority4SameTypeDev ( + IN UINT16 DeviceType, + IN OUT BBS_TABLE *LocalBbsTable, + IN OUT UINT16 *Priority + ) +/*++ +DeviceType - BBS_FLOPPY, BBS_HARDDISK, BBS_CDROM and so on +LocalBbsTable - BBS table instance +Priority - As input arg, it is the start point of boot priority, as output arg, it is the start point of boot + priority can be used next time. +--*/ +{ + UINT8 *DevOrder; + + UINT8 *OrigBuffer; + UINT16 *DevIndex; + UINTN DevOrderSize; + UINTN DevCount; + UINTN Index; + + DevOrder = BdsLibGetVariableAndSize ( + VarLegacyDevOrder, + &EfiLegacyDevOrderGuid, + &DevOrderSize + ); + if (NULL == DevOrder) { + return EFI_OUT_OF_RESOURCES; + } + + OrigBuffer = DevOrder; + while (DevOrder < OrigBuffer + DevOrderSize) { + if (DeviceType == * (BBS_TYPE *) DevOrder) { + break; + } + + DevOrder += sizeof (BBS_TYPE); + DevOrder += *(UINT16 *) DevOrder; + } + + if (DevOrder >= OrigBuffer + DevOrderSize) { + SafeFreePool (OrigBuffer); + return EFI_NOT_FOUND; + } + + DevOrder += sizeof (BBS_TYPE); + DevCount = (*((UINT16 *) DevOrder) - sizeof (UINT16)) / sizeof (UINT16); + DevIndex = (UINT16 *) (DevOrder + sizeof (UINT16)); + // + // If the high byte of the DevIndex is 0xFF, it indicates that this device has been disabled. + // + for (Index = 0; Index < DevCount; Index++) { + if ((DevIndex[Index] & 0xFF00) == 0xFF00) { + // + // LocalBbsTable[DevIndex[Index] & 0xFF].BootPriority = BBS_DISABLED_ENTRY; + // + } else { + LocalBbsTable[DevIndex[Index] & 0xFF].BootPriority = *Priority; + (*Priority)++; + } + } + + SafeFreePool (OrigBuffer); + return EFI_SUCCESS; +} + +VOID +PrintBbsTable ( + IN BBS_TABLE *LocalBbsTable + ) +{ + UINT16 Idx; + + DEBUG ((EFI_D_ERROR, "\n")); + DEBUG ((EFI_D_ERROR, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs\n")); + DEBUG ((EFI_D_ERROR, "=============================================\n")); + for (Idx = 0; Idx < MAX_BBS_ENTRIES; Idx++) { + if ((LocalBbsTable[Idx].BootPriority == BBS_IGNORE_ENTRY) || + (LocalBbsTable[Idx].BootPriority == BBS_DO_NOT_BOOT_FROM) || + (LocalBbsTable[Idx].BootPriority == BBS_LOWEST_PRIORITY) + ) { + continue; + } + + DEBUG ( + (EFI_D_ERROR, + " %02x: %04x %02x/%02x/%02x %02x/02%x %04x %04x %04x:%04x\n", + (UINTN) Idx, + (UINTN) LocalBbsTable[Idx].BootPriority, + (UINTN) LocalBbsTable[Idx].Bus, + (UINTN) LocalBbsTable[Idx].Device, + (UINTN) LocalBbsTable[Idx].Function, + (UINTN) LocalBbsTable[Idx].Class, + (UINTN) LocalBbsTable[Idx].SubClass, + (UINTN) LocalBbsTable[Idx].DeviceType, + (UINTN) * (UINT16 *) &LocalBbsTable[Idx].StatusFlags, + (UINTN) LocalBbsTable[Idx].BootHandlerSegment, + (UINTN) LocalBbsTable[Idx].BootHandlerOffset, + (UINTN) ((LocalBbsTable[Idx].MfgStringSegment << 4) + LocalBbsTable[Idx].MfgStringOffset), + (UINTN) ((LocalBbsTable[Idx].DescStringSegment << 4) + LocalBbsTable[Idx].DescStringOffset)) + ); + } + + DEBUG ((EFI_D_ERROR, "\n")); +} + +EFI_STATUS +BdsRefreshBbsTableForBoot ( + IN BDS_COMMON_OPTION *Entry + ) +{ + EFI_STATUS Status; + UINT16 HddCount; + UINT16 BbsCount; + HDD_INFO *LocalHddInfo; + BBS_TABLE *LocalBbsTable; + UINT16 DevType; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + UINTN Index; + UINT16 Priority; + UINT16 *BootOrder; + UINTN BootOrderSize; + UINT8 *BootOptionVar; + UINTN BootOptionSize; + UINT16 BootOption[100]; + UINT8 *Ptr; + UINT16 DevPathLen; + EFI_DEVICE_PATH_PROTOCOL *DevPath; + + HddCount = 0; + BbsCount = 0; + LocalHddInfo = NULL; + LocalBbsTable = NULL; + DevType = BBS_UNKNOWN; + + Status = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, &LegacyBios); + if (EFI_ERROR (Status)) { + return Status; + } + + LegacyBios->GetBbsInfo ( + LegacyBios, + &HddCount, + &LocalHddInfo, + &BbsCount, + &LocalBbsTable + ); + // + // First, set all the present devices' boot priority to BBS_UNPRIORITIZED_ENTRY + // We will set them according to the settings setup by user + // + for (Index = 0; Index < BbsCount; Index++) { + if (!((BBS_IGNORE_ENTRY == LocalBbsTable[Index].BootPriority) || + (BBS_DO_NOT_BOOT_FROM == LocalBbsTable[Index].BootPriority) || + (BBS_LOWEST_PRIORITY == LocalBbsTable[Index].BootPriority))) { + LocalBbsTable[Index].BootPriority = BBS_UNPRIORITIZED_ENTRY; + } + } + // + // boot priority always starts at 0 + // + Priority = 0; + if (Entry->LoadOptionsSize == sizeof (BBS_TABLE) + sizeof (UINT16)) { + // + // If Entry stands for a legacy boot option, we prioritize the devices with the same type first. + // + DevType = ((BBS_TABLE *) Entry->LoadOptions)->DeviceType; + Status = BdsSetBootPriority4SameTypeDev ( + DevType, + LocalBbsTable, + &Priority + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + // + // we have to set the boot priority for other BBS entries with different device types + // + BootOrder = (UINT16 *) BdsLibGetVariableAndSize ( + L"BootOrder", + &gEfiGlobalVariableGuid, + &BootOrderSize + ); + for (Index = 0; BootOrder && Index < BootOrderSize / sizeof (UINT16); Index++) { + UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]); + BootOptionVar = BdsLibGetVariableAndSize ( + BootOption, + &gEfiGlobalVariableGuid, + &BootOptionSize + ); + if (NULL == BootOptionVar) { + continue; + } + + Ptr = BootOptionVar; + + Ptr += sizeof (UINT32); + DevPathLen = *(UINT16 *) Ptr; + Ptr += sizeof (UINT16); + Ptr += StrSize ((UINT16 *) Ptr); + DevPath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr; + if (BBS_DEVICE_PATH != DevPath->Type || BBS_BBS_DP != DevPath->SubType) { + SafeFreePool (BootOptionVar); + continue; + } + + Ptr += DevPathLen; + if (DevType == ((BBS_TABLE *) Ptr)->DeviceType) { + // + // We don't want to process twice for a device type + // + SafeFreePool (BootOptionVar); + continue; + } + + Status = BdsSetBootPriority4SameTypeDev ( + ((BBS_TABLE *) Ptr)->DeviceType, + LocalBbsTable, + &Priority + ); + SafeFreePool (BootOptionVar); + if (EFI_ERROR (Status)) { + break; + } + } + + if (BootOrder) { + SafeFreePool (BootOrder); + } + // + // For debug + // + PrintBbsTable (LocalBbsTable); + + return Status; +} diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/BBSsupport.h b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/BBSsupport.h new file mode 100644 index 0000000000..37778f4421 --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/BBSsupport.h @@ -0,0 +1,83 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + BBSsupport.h + +Abstract: + + declares interface functions + +Revision History + +--*/ + +#ifndef _EFI_BDS_BBS_SUPPORT_H +#define _EFI_BDS_BBS_SUPPORT_H + +#include "Generic/BootMaint/BootMaint.h" + +#ifdef EFI32 +#define REFRESH_LEGACY_BOOT_OPTIONS \ + BdsDeleteAllInvalidLegacyBootOptions ();\ + BdsAddNonExistingLegacyBootOptions (); \ + BdsUpdateLegacyDevOrder () +#else +#define REFRESH_LEGACY_BOOT_OPTIONS +#endif + +VOID +BdsBuildLegacyDevNameString ( + IN BBS_TABLE *CurBBSEntry, + IN UINTN Index, + IN UINTN BufSize, + OUT CHAR16 *BootString + ); + +EFI_STATUS +BdsDeleteAllInvalidLegacyBootOptions ( + VOID + ); + +EFI_STATUS +BdsAddNonExistingLegacyBootOptions ( + VOID + ) +/*++ + +Routine Description: + + Add the legacy boot options from BBS table if they do not exist. + +Arguments: + + None. + +Returns: + + EFI_SUCCESS - The boot options are added successfully or they are already in boot options. + others - An error occurred when creating legacy boot options. + +--*/ +; + +EFI_STATUS +BdsUpdateLegacyDevOrder ( + VOID + ); + +EFI_STATUS +BdsRefreshBbsTableForBoot ( + IN BDS_COMMON_OPTION *Entry + ); + +#endif diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/BmLib.c b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/BmLib.c new file mode 100644 index 0000000000..201339e896 --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/BmLib.c @@ -0,0 +1,626 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + bmlib.c + +AgBStract: + + Boot Maintainence Helper functions + +--*/ + +#include "bootmaint.h" + +EFI_STATUS +EfiLibLocateProtocol ( + IN EFI_GUID *ProtocolGuid, + OUT VOID **Interface + ) +/*++ + +Routine Description: + + Find the first instance of this Protocol + in the system and return it's interface + +Arguments: + + ProtocolGuid - Provides the protocol to search for + Interface - On return, a pointer to the first interface + that matches ProtocolGuid + +Returns: + + EFI_SUCCESS - A protocol instance matching ProtocolGuid was found + + EFI_NOT_FOUND - No protocol instances were found that match ProtocolGuid + +--*/ +{ + EFI_STATUS Status; + + Status = gBS->LocateProtocol ( + ProtocolGuid, + NULL, + Interface + ); + return Status; +} + +EFI_FILE_HANDLE +EfiLibOpenRoot ( + IN EFI_HANDLE DeviceHandle + ) +/*++ + +Routine Description: + + Function opens and returns a file handle to the root directory of a volume. + +Arguments: + + DeviceHandle - A handle for a device + +Returns: + + A valid file handle or NULL is returned + +--*/ +{ + 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; +} + +BOOLEAN +EfiGrowBuffer ( + IN OUT EFI_STATUS *Status, + IN OUT VOID **Buffer, + IN UINTN BufferSize + ) +/*++ + +Routine Description: + + Helper function called as part of the code needed + to allocate the proper sized buffer for various + EFI interfaces. + +Arguments: + + Status - Current status + + Buffer - Current allocated buffer, or NULL + + BufferSize - Current buffer size needed + +Returns: + + TRUE - if the buffer was reallocated and the caller + should try the API again. + +--*/ +{ + BOOLEAN TryAgain; + + // + // If this is an initial request, buffer will be null with a new buffer size + // + if (!*Buffer && BufferSize) { + *Status = EFI_BUFFER_TOO_SMALL; + } + // + // If the status code is "buffer too small", resize the buffer + // + TryAgain = FALSE; + if (*Status == EFI_BUFFER_TOO_SMALL) { + + SafeFreePool (*Buffer); + + *Buffer = AllocateZeroPool (BufferSize); + + if (*Buffer) { + TryAgain = TRUE; + } else { + *Status = EFI_OUT_OF_RESOURCES; + } + } + // + // If there's an error, free the buffer + // + if (!TryAgain && EFI_ERROR (*Status) && *Buffer) { + SafeFreePool (*Buffer); + *Buffer = NULL; + } + + return TryAgain; +} + +VOID * +EfiLibGetVariable ( + IN CHAR16 *Name, + IN EFI_GUID *VendorGuid + ) +/*++ + +Routine Description: + Function returns the value of the specified variable. + +Arguments: + Name - A Null-terminated Unicode string that is + the name of the vendor's variable. + + VendorGuid - A unique identifier for the vendor. + +Returns: + + None + +--*/ +{ + UINTN VarSize; + + return BdsLibGetVariableAndSize (Name, VendorGuid, &VarSize); +} + +EFI_STATUS +EfiLibDeleteVariable ( + IN CHAR16 *VarName, + IN EFI_GUID *VarGuid + ) +/*++ + +Routine Description: + Function deletes the variable specified by VarName and VarGuid. + +Arguments: + VarName - A Null-terminated Unicode string that is + the name of the vendor's variable. + + VendorGuid - A unique identifier for the vendor. + +Returns: + + EFI_SUCCESS - The variable was found and removed + + EFI_UNSUPPORTED - The variable store was inaccessible + + EFI_OUT_OF_RESOURCES - The temporary buffer was not available + + EFI_NOT_FOUND - The variable was not found + +--*/ +{ + VOID *VarBuf; + EFI_STATUS Status; + + VarBuf = EfiLibGetVariable (VarName, VarGuid); + Status = EFI_NOT_FOUND; + + if (VarBuf) { + // + // Delete variable from Storage + // + Status = gRT->SetVariable (VarName, VarGuid, VAR_FLAG, 0, NULL); + ASSERT (!EFI_ERROR (Status)); + SafeFreePool (VarBuf); + } + + return Status; +} + +EFI_FILE_SYSTEM_VOLUME_LABEL_INFO * +EfiLibFileSystemVolumeLabelInfo ( + IN EFI_FILE_HANDLE FHand + ) +/*++ + +Routine Description: + + Function gets the file system information from an open file descriptor, + and stores it in a buffer allocated from pool. + +Arguments: + + Fhand - A file handle + +Returns: + + A pointer to a buffer with file information or NULL is returned + +--*/ +{ + EFI_STATUS Status; + EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *Buffer; + UINTN BufferSize; + // + // Initialize for GrowBuffer loop + // + Buffer = NULL; + BufferSize = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO + 200; + + // + // Call the real function + // + while (EfiGrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) { + Status = FHand->GetInfo ( + FHand, + &gEfiFileSystemVolumeLabelInfoIdGuid, + &BufferSize, + Buffer + ); + } + + return Buffer; +} + +CHAR16 * +EfiStrDuplicate ( + IN CHAR16 *Src + ) +{ + CHAR16 *Dest; + UINTN Size; + + Size = StrSize (Src); + Dest = AllocateZeroPool (Size); + ASSERT (Dest != NULL); + if (Dest) { + CopyMem (Dest, Src, Size); + } + + return Dest; +} + +EFI_FILE_INFO * +EfiLibFileInfo ( + IN EFI_FILE_HANDLE FHand + ) +/*++ + +Routine Description: + + Function gets the file information from an open file descriptor, and stores it + in a buffer allocated from pool. + +Arguments: + + Fhand - A file handle + +Returns: + + A pointer to a buffer with file information or NULL is returned + +--*/ +{ + EFI_STATUS Status; + EFI_FILE_INFO *Buffer; + UINTN BufferSize; + + // + // Initialize for GrowBuffer loop + // + Buffer = NULL; + BufferSize = SIZE_OF_EFI_FILE_INFO + 200; + + // + // Call the real function + // + while (EfiGrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) { + Status = FHand->GetInfo ( + FHand, + &gEfiFileInfoGuid, + &BufferSize, + Buffer + ); + } + + return Buffer; +} + +UINTN +EfiDevicePathInstanceCount ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +/*++ + +Routine Description: + Function is used to determine the number of device path instances + that exist in a device path. + +Arguments: + DevicePath - A pointer to a device path data structure. + +Returns: + + This function counts and returns the number of device path instances + in DevicePath. + +--*/ +{ + UINTN Count; + UINTN Size; + + Count = 0; + while (GetNextDevicePathInstance (&DevicePath, &Size)) { + Count += 1; + } + + return Count; +} + +VOID * +EfiReallocatePool ( + IN VOID *OldPool, + IN UINTN OldSize, + IN UINTN NewSize + ) +/*++ + +Routine Description: + Adjusts the size of a previously allocated buffer. + +Arguments: + OldPool - A pointer to the buffer whose size is being adjusted. + OldSize - The size of the current buffer. + NewSize - The size of the new buffer. + +Returns: + + EFI_SUCEESS - The requested number of bytes were allocated. + + EFI_OUT_OF_RESOURCES - The pool requested could not be allocated. + + EFI_INVALID_PARAMETER - The buffer was invalid. + +--*/ +{ + VOID *NewPool; + + NewPool = NULL; + if (NewSize) { + NewPool = AllocateZeroPool (NewSize); + } + + if (OldPool) { + if (NewPool) { + CopyMem (NewPool, OldPool, OldSize < NewSize ? OldSize : NewSize); + } + + SafeFreePool (OldPool); + } + + return NewPool; +} + +EFI_STATUS +EfiLibGetStringFromToken ( + IN EFI_GUID *ProducerGuid, + IN STRING_REF Token, + OUT CHAR16 **String + ) +/*++ + +Routine Description: + + Acquire the string associated with the ProducerGuid and return it. + +Arguments: + + ProducerGuid - The Guid to search the HII database for + Token - The token value of the string to extract + String - The string that is extracted + +Returns: + + EFI_SUCCESS - Buffer filled with the requested forms. BufferLength + was updated. + EFI_BUFFER_TOO_SMALL - The buffer provided was not large enough to allow the form to be stored. + +--*/ +{ + EFI_STATUS Status; + UINT16 HandleBufferLength; + EFI_HII_HANDLE *HiiHandleBuffer; + UINTN StringBufferLength; + UINTN NumberOfHiiHandles; + UINTN Index; + UINT16 Length; + EFI_GUID HiiGuid; + EFI_HII_PROTOCOL *Hii; + + HandleBufferLength = 0x1000; + HiiHandleBuffer = NULL; + Status = gBS->LocateProtocol ( + &gEfiHiiProtocolGuid, + NULL, + &Hii + ); + if (EFI_ERROR (Status)) { + *String = NULL; + return Status; + } + // + // Get all the Hii handles + // + HiiHandleBuffer = AllocateZeroPool (HandleBufferLength); + ASSERT (HiiHandleBuffer != NULL); + + Status = Hii->FindHandles (Hii, &HandleBufferLength, HiiHandleBuffer); + ASSERT_EFI_ERROR (Status); + + // + // Get the Hii Handle that matches the StructureNode->ProducerName + // + NumberOfHiiHandles = HandleBufferLength / sizeof (EFI_HII_HANDLE); + for (Index = 0; Index < NumberOfHiiHandles; Index++) { + Length = 0; + Status = ExtractDataFromHiiHandle ( + HiiHandleBuffer[Index], + &Length, + NULL, + &HiiGuid + ); + if (CompareGuid (ProducerGuid, &HiiGuid)) { + break; + } + } + // + // Find the string based on the current language + // + StringBufferLength = 0x100; + *String = AllocateZeroPool (0x100); + ASSERT (*String != NULL); + + Status = Hii->GetString ( + Hii, + HiiHandleBuffer[Index], + Token, + FALSE, + NULL, + &StringBufferLength, + *String + ); + + gBS->FreePool (HiiHandleBuffer); + + return Status; +} + +BOOLEAN +TimeCompare ( + IN EFI_TIME *FirstTime, + IN EFI_TIME *SecondTime + ) +/*++ + +Routine Description: + Compare two EFI_TIME data. + +Arguments: + + FirstTime - A pointer to the first EFI_TIME data. + SecondTime - A pointer to the second EFI_TIME data. + +Returns: + TRUE The FirstTime is not later than the SecondTime. + FALSE The FirstTime is later than the 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 < FirstTime->Minute); + } else if (FirstTime->Second != SecondTime->Second) { + return (BOOLEAN) (FirstTime->Second < SecondTime->Second); + } + + return (BOOLEAN) (FirstTime->Nanosecond <= SecondTime->Nanosecond); +} + +UINT16 * +EfiLibStrFromDatahub ( + IN EFI_DEVICE_PATH_PROTOCOL *DevPath + ) +{ + EFI_STATUS Status; + UINT16 *Desc; + EFI_DATA_HUB_PROTOCOL *Datahub; + UINT64 Count; + EFI_DATA_RECORD_HEADER *Record; + EFI_SUBCLASS_TYPE1_HEADER *DataHdr; + EFI_GUID MiscGuid = EFI_MISC_SUBCLASS_GUID; + EFI_MISC_ONBOARD_DEVICE_DATA *ob; + EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA *Port; + EFI_TIME CurTime; + + Status = gBS->LocateProtocol ( + &gEfiDataHubProtocolGuid, + NULL, + &Datahub + ); + if (EFI_ERROR (Status)) { + return NULL; + } + + Status = gRT->GetTime (&CurTime, NULL); + if (EFI_ERROR (Status)) { + return NULL; + } + + Count = 0; + do { + Status = Datahub->GetNextRecord (Datahub, &Count, NULL, &Record); + + if (EFI_ERROR (Status)) { + break; + } + + if (Record->DataRecordClass == EFI_DATA_RECORD_CLASS_DATA && CompareGuid (&Record->DataRecordGuid, &MiscGuid)) { + // + // This record is what we need + // + DataHdr = (EFI_SUBCLASS_TYPE1_HEADER *) (Record + 1); + if (EFI_MISC_ONBOARD_DEVICE_RECORD_NUMBER == DataHdr->RecordType) { + ob = (EFI_MISC_ONBOARD_DEVICE_DATA *) (DataHdr + 1); + if (BdsLibMatchDevicePaths ((EFI_DEVICE_PATH_PROTOCOL *) &ob->OnBoardDevicePath, DevPath)) { + EfiLibGetStringFromToken (&Record->ProducerName, ob->OnBoardDeviceDescription, &Desc); + return Desc; + } + } + + if (EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_RECORD_NUMBER == DataHdr->RecordType) { + Port = (EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA *) (DataHdr + 1); + if (BdsLibMatchDevicePaths ((EFI_DEVICE_PATH_PROTOCOL *) &Port->PortPath, DevPath)) { + EfiLibGetStringFromToken (&Record->ProducerName, Port->PortExternalConnectorDesignator, &Desc); + return Desc; + } + } + } + + } while (TimeCompare (&Record->LogTime, &CurTime) && Count != 0); + + return NULL; +} diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/BootMaint.c b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/BootMaint.c new file mode 100644 index 0000000000..c4b3211dfd --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/BootMaint.c @@ -0,0 +1,1305 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + BootMaint.c + +Abstract: + + Boot Maintainence Main File + +--*/ + +#include "Generic/Bds.h" +#include "BootMaint.h" +#include "BdsStrDefs.h" +#include "formguid.h" + +// +// Form binary for Boot Maintenance +// +extern UINT8 bmBin[]; +extern UINT8 FEBin[]; +extern EFI_GUID gBdsStringPackGuid; +extern BOOLEAN gConnectAllHappened; + +EFI_GUID EfiLegacyDevOrderGuid = EFI_LEGACY_DEV_ORDER_VARIABLE_GUID; + +VOID +InitAllMenu ( + IN BMM_CALLBACK_DATA *CallbackData + ); + +VOID +FreeAllMenu ( + VOID + ); + +EFI_STATUS +CreateMenuStringToken ( + IN BMM_CALLBACK_DATA *CallbackData, + IN EFI_HII_HANDLE HiiHandle, + IN BM_MENU_OPTION *MenuOption + ) +/*++ +Routine Description: + + Create string tokens for a menu from its help strings and display strings + +Arguments: + + HiiHandle - Hii Handle of the package to be updated. + + MenuOption - The Menu whose string tokens need to be created + +Returns: + + EFI_SUCCESS - string tokens created successfully + + others - contain some errors + +--*/ +{ + BM_MENU_ENTRY *NewMenuEntry; + UINTN Index; + + for (Index = 0; Index < MenuOption->MenuNumber; Index++) { + NewMenuEntry = BOpt_GetMenuEntry (MenuOption, Index); + CallbackData->Hii->NewString ( + CallbackData->Hii, + NULL, + HiiHandle, + &NewMenuEntry->DisplayStringToken, + NewMenuEntry->DisplayString + ); + + if (NULL == NewMenuEntry->HelpString) { + NewMenuEntry->HelpStringToken = NewMenuEntry->DisplayStringToken; + } else { + CallbackData->Hii->NewString ( + CallbackData->Hii, + NULL, + HiiHandle, + &NewMenuEntry->HelpStringToken, + NewMenuEntry->HelpString + ); + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +DriverCallback ( + IN EFI_FORM_CALLBACK_PROTOCOL *This, + IN UINT16 KeyValue, + IN EFI_IFR_DATA_ARRAY *Data, + OUT EFI_HII_CALLBACK_PACKET **Packet + ) +/*++ +Routine Description: + + Callback Function for boot maintenance utility user interface interaction. + +Arguments: + + This - File explorer callback protocol pointer. + KeyValue - Key value to identify the type of data to expect. + Data - A pointer to the data being sent to the original exporting driver. + Packet - A pointer to a packet of information which a driver passes back to the browser. + +Returns: + + EFI_SUCCESS - Callback ended successfully. + Others - Contain some errors. + +--*/ +{ + BMM_CALLBACK_DATA *Private; + BM_MENU_ENTRY *NewMenuEntry; + BMM_FAKE_NV_DATA *CurrentFakeNVMap; + EFI_STATUS Status; + UINTN OldValue; + UINTN NewValue; + UINTN Number; + UINTN Pos; + UINTN Bit; + UINT16 NewValuePos; + UINT16 Index2; + UINT16 Index; + UINT8 *OldLegacyDev; + UINT8 *NewLegacyDev; + UINT8 *Location; + UINT8 *DisMap; + FORM_ID FormId; + + OldValue = 0; + NewValue = 0; + Number = 0; + OldLegacyDev = NULL; + NewLegacyDev = NULL; + NewValuePos = 0; + DisMap = NULL; + + Private = BMM_CALLBACK_DATA_FROM_THIS (This); + UpdateData->FormCallbackHandle = (EFI_PHYSICAL_ADDRESS) (UINTN) Private->BmmCallbackHandle; + CurrentFakeNVMap = (BMM_FAKE_NV_DATA *) Data->NvRamMap; + Private->BmmFakeNvData = CurrentFakeNVMap; + Location = (UINT8 *) &UpdateData->Data; + + UpdatePageId (Private, KeyValue); + + // + // need to be subtituded. + // + // Update Select FD/HD/CD/NET/BEV Order Form + // + if (FORM_SET_FD_ORDER_ID == Private->BmmPreviousPageId || + FORM_SET_HD_ORDER_ID == Private->BmmPreviousPageId || + FORM_SET_CD_ORDER_ID == Private->BmmPreviousPageId || + FORM_SET_NET_ORDER_ID == Private->BmmPreviousPageId || + FORM_SET_BEV_ORDER_ID == Private->BmmPreviousPageId || + ((FORM_BOOT_SETUP_ID == Private->BmmPreviousPageId) && + (KeyValue >= LEGACY_FD_QUESTION_ID) && + (KeyValue < (LEGACY_BEV_QUESTION_ID + 100)) ) + ) { + + DisMap = Private->BmmOldFakeNVData.DisableMap; + + FormId = Private->BmmPreviousPageId; + if (FormId == FORM_BOOT_SETUP_ID) { + FormId = Private->BmmCurrentPageId; + } + + switch (FormId) { + case FORM_SET_FD_ORDER_ID: + Number = (UINT16) LegacyFDMenu.MenuNumber; + OldLegacyDev = Private->BmmOldFakeNVData.LegacyFD; + NewLegacyDev = CurrentFakeNVMap->LegacyFD; + break; + + case FORM_SET_HD_ORDER_ID: + Number = (UINT16) LegacyHDMenu.MenuNumber; + OldLegacyDev = Private->BmmOldFakeNVData.LegacyHD; + NewLegacyDev = CurrentFakeNVMap->LegacyHD; + break; + + case FORM_SET_CD_ORDER_ID: + Number = (UINT16) LegacyCDMenu.MenuNumber; + OldLegacyDev = Private->BmmOldFakeNVData.LegacyCD; + NewLegacyDev = CurrentFakeNVMap->LegacyCD; + break; + + case FORM_SET_NET_ORDER_ID: + Number = (UINT16) LegacyNETMenu.MenuNumber; + OldLegacyDev = Private->BmmOldFakeNVData.LegacyNET; + NewLegacyDev = CurrentFakeNVMap->LegacyNET; + break; + + case FORM_SET_BEV_ORDER_ID: + Number = (UINT16) LegacyBEVMenu.MenuNumber; + OldLegacyDev = Private->BmmOldFakeNVData.LegacyBEV; + NewLegacyDev = CurrentFakeNVMap->LegacyBEV; + break; + + default: + break; + } + // + // First, find the different position + // if there is change, it should be only one + // + for (Index = 0; Index < Number; Index++) { + if (OldLegacyDev[Index] != NewLegacyDev[Index]) { + OldValue = OldLegacyDev[Index]; + NewValue = NewLegacyDev[Index]; + break; + } + } + + if (Index != Number) { + // + // there is change, now process + // + if (0xFF == NewValue) { + // + // This item will be disable + // Just move the items behind this forward to overlap it + // + Pos = OldValue / 8; + Bit = 7 - (OldValue % 8); + DisMap[Pos] |= (UINT8) (1 << Bit); + for (Index2 = Index; Index2 < Number - 1; Index2++) { + NewLegacyDev[Index2] = NewLegacyDev[Index2 + 1]; + } + + NewLegacyDev[Index2] = 0xFF; + } else { + for (Index2 = 0; Index2 < Number; Index2++) { + if (Index2 == Index) { + continue; + } + + if (OldLegacyDev[Index2] == NewValue) { + // + // If NewValue is in OldLegacyDev array + // remember its old position + // + NewValuePos = Index2; + break; + } + } + + if (Index2 != Number) { + // + // We will change current item to an existing item + // (It's hard to describe here, please read code, it's like a cycle-moving) + // + for (Index2 = NewValuePos; Index2 != Index;) { + if (NewValuePos < Index) { + NewLegacyDev[Index2] = OldLegacyDev[Index2 + 1]; + Index2++; + } else { + NewLegacyDev[Index2] = OldLegacyDev[Index2 - 1]; + Index2--; + } + } + } else { + // + // If NewValue is not in OldlegacyDev array, we are changing to a disabled item + // so we should modify DisMap to reflect the change + // + Pos = NewValue / 8; + Bit = 7 - (NewValue % 8); + DisMap[Pos] &= ~ (UINT8) (1 << Bit); + if (0xFF != OldValue) { + // + // Because NewValue is a item that was disabled before + // so after changing the OldValue should be disabled + // actually we are doing a swap of enable-disable states of two items + // + Pos = OldValue / 8; + Bit = 7 - (OldValue % 8); + DisMap[Pos] |= (UINT8) (1 << Bit); + } + } + } + // + // To prevent DISABLE appears in the middle of the list + // we should perform a re-ordering + // + Index = 0; + while (Index < Number) { + if (0xFF != NewLegacyDev[Index]) { + Index++; + continue; + } + + Index2 = Index; + Index2++; + while (Index2 < Number) { + if (0xFF != NewLegacyDev[Index2]) { + break; + } + + Index2++; + } + + if (Index2 < Number) { + NewLegacyDev[Index] = NewLegacyDev[Index2]; + NewLegacyDev[Index2] = 0xFF; + } + + Index++; + } + + CopyMem ( + OldLegacyDev, + NewLegacyDev, + Number + ); + } + } + + if (KeyValue < FILE_OPTION_OFFSET) { + if (KeyValue < NORMAL_GOTO_OFFSET) { + switch (KeyValue) { + case KEY_VALUE_BOOT_FROM_FILE: + Private->FeCurrentState = BOOT_FROM_FILE_STATE; + + // + // Exit Bmm main formset to send File Explorer formset. + // + CreateCallbackPacket (Packet, EXIT_REQUIRED); + + break; + + case FORM_BOOT_ADD_ID: + Private->FeCurrentState = ADD_BOOT_OPTION_STATE; + + // + // Exit Bmm main formset to send File Explorer formset. + // + CreateCallbackPacket (Packet, EXIT_REQUIRED); + break; + + case FORM_DRV_ADD_FILE_ID: + Private->FeCurrentState = ADD_DRIVER_OPTION_STATE; + + // + // Exit Bmm main formset to send File Explorer formset. + // + CreateCallbackPacket (Packet, EXIT_REQUIRED); + + 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 (KeyValue, Private); + break; + + case FORM_DRV_DEL_ID: + CleanUpPage (FORM_DRV_DEL_ID, Private); + UpdateDrvDelPage (Private); + break; + + case FORM_BOOT_NEXT_ID: + CleanUpPage (FORM_BOOT_NEXT_ID, Private); + UpdateBootNextPage (Private); + break; + + case FORM_TIME_OUT_ID: + CleanUpPage (FORM_TIME_OUT_ID, Private); + UpdateTimeOutPage (Private); + break; + + case FORM_RESET: + gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL); + return EFI_UNSUPPORTED; + + case FORM_CON_IN_ID: + case FORM_CON_OUT_ID: + case FORM_CON_ERR_ID: + UpdatePageBody (KeyValue, Private); + break; + + case FORM_CON_COM_ID: + CleanUpPage (FORM_CON_COM_ID, Private); + UpdateConCOMPage (Private); + break; + + case FORM_SET_FD_ORDER_ID: + case FORM_SET_HD_ORDER_ID: + case FORM_SET_CD_ORDER_ID: + case FORM_SET_NET_ORDER_ID: + case FORM_SET_BEV_ORDER_ID: + CleanUpPage (KeyValue, Private); + UpdateSetLegacyDeviceOrderPage (KeyValue, Private); + break; + + case KEY_VALUE_SAVE_AND_EXIT: + case KEY_VALUE_NO_SAVE_AND_EXIT: + + if (KeyValue == KEY_VALUE_SAVE_AND_EXIT) { + Status = ApplyChangeHandler (Private, CurrentFakeNVMap, Private->BmmPreviousPageId); + if (EFI_ERROR (Status)) { + return Status; + } + } else if (KeyValue == KEY_VALUE_NO_SAVE_AND_EXIT) { + DiscardChangeHandler (Private, CurrentFakeNVMap); + } + // + // Tell browser not to ask for confirmation of changes, + // since we have already applied or discarded. + // + CreateCallbackPacket (Packet, NV_NOT_CHANGED); + break; + + default: + break; + } + } else if ((KeyValue >= TERMINAL_OPTION_OFFSET) && (KeyValue < CONSOLE_OPTION_OFFSET)) { + Index2 = (UINT16) (KeyValue - TERMINAL_OPTION_OFFSET); + Private->CurrentTerminal = Index2; + + CleanUpPage (FORM_CON_COM_SETUP_ID, Private); + UpdateTerminalPage (Private); + + } else if (KeyValue >= HANDLE_OPTION_OFFSET) { + Index2 = (UINT16) (KeyValue - HANDLE_OPTION_OFFSET); + + NewMenuEntry = BOpt_GetMenuEntry (&DriverMenu, Index2); + 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); + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +ApplyChangeHandler ( + IN BMM_CALLBACK_DATA *Private, + IN BMM_FAKE_NV_DATA *CurrentFakeNVMap, + IN FORM_ID FormId + ) +/*++ + +Routine Description: + + Function handling request to apply changes for BMM pages. + +Arguments: + + Private - Pointer to callback data buffer. + CurrentFakeNVMap - Pointer to buffer holding data of various values used by BMM + FormId - ID of the form which has sent the request to apply change. + +Returns: + + EFI_SUCCESS - Change successfully applied. + Other - Error occurs while trying to apply changes. + +--*/ +{ + BM_CONSOLE_CONTEXT *NewConsoleContext; + BM_TERMINAL_CONTEXT *NewTerminalContext; + BM_LOAD_CONTEXT *NewLoadContext; + BM_MENU_ENTRY *NewMenuEntry; + EFI_STATUS Status; + UINT16 Index; + + Status = EFI_SUCCESS; + + switch (FormId) { + case FORM_SET_FD_ORDER_ID: + case FORM_SET_HD_ORDER_ID: + case FORM_SET_CD_ORDER_ID: + case FORM_SET_NET_ORDER_ID: + case FORM_SET_BEV_ORDER_ID: + Var_UpdateBBSOption (Private); + break; + + case FORM_BOOT_DEL_ID: + for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) { + NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index); + NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext; + NewLoadContext->Deleted = CurrentFakeNVMap->BootOptionDel[Index]; + } + + Var_DelBootOption (); + break; + + case FORM_DRV_DEL_ID: + for (Index = 0; Index < DriverOptionMenu.MenuNumber; Index++) { + NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, Index); + NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext; + NewLoadContext->Deleted = CurrentFakeNVMap->DriverOptionDel[Index]; + } + + Var_DelDriverOption (); + break; + + case FORM_BOOT_CHG_ID: + Status = Var_UpdateBootOrder (Private); + break; + + case FORM_DRV_CHG_ID: + Status = Var_UpdateDriverOrder (Private); + break; + + case FORM_TIME_OUT_ID: + Status = gRT->SetVariable ( + L"Timeout", + &gEfiGlobalVariableGuid, + VAR_FLAG, + sizeof (UINT16), + &(CurrentFakeNVMap->BootTimeOut) + ); + if (EFI_ERROR (Status)) { + goto Error; + } + + Private->BmmOldFakeNVData.BootTimeOut = CurrentFakeNVMap->BootTimeOut; + break; + + case FORM_BOOT_NEXT_ID: + Status = Var_UpdateBootNext (Private); + break; + + case FORM_CON_COM_ID: + NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Private->CurrentTerminal); + + NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext; + + NewTerminalContext->BaudRateIndex = CurrentFakeNVMap->COMBaudRate; + NewTerminalContext->BaudRate = BaudRateList[CurrentFakeNVMap->COMBaudRate].Value; + NewTerminalContext->DataBitsIndex = CurrentFakeNVMap->COMDataRate; + NewTerminalContext->DataBits = (UINT8) DataBitsList[CurrentFakeNVMap->COMDataRate].Value; + NewTerminalContext->StopBitsIndex = CurrentFakeNVMap->COMStopBits; + NewTerminalContext->StopBits = (UINT8) StopBitsList[CurrentFakeNVMap->COMStopBits].Value; + NewTerminalContext->ParityIndex = CurrentFakeNVMap->COMParity; + NewTerminalContext->Parity = (UINT8) ParityList[CurrentFakeNVMap->COMParity].Value; + NewTerminalContext->TerminalType = CurrentFakeNVMap->COMTerminalType; + + ChangeTerminalDevicePath ( + NewTerminalContext->DevicePath, + FALSE + ); + + Var_UpdateConsoleInpOption (); + Var_UpdateConsoleOutOption (); + Var_UpdateErrorOutOption (); + break; + + case FORM_CON_IN_ID: + for (Index = 0; Index < ConsoleInpMenu.MenuNumber; Index++) { + NewMenuEntry = BOpt_GetMenuEntry (&ConsoleInpMenu, Index); + NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext; + NewConsoleContext->IsActive = CurrentFakeNVMap->ConsoleCheck[Index]; + } + + for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) { + NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index); + NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext; + NewTerminalContext->IsConIn = CurrentFakeNVMap->ConsoleCheck[Index + ConsoleInpMenu.MenuNumber]; + } + + Var_UpdateConsoleInpOption (); + break; + + case FORM_CON_OUT_ID: + for (Index = 0; Index < ConsoleOutMenu.MenuNumber; Index++) { + NewMenuEntry = BOpt_GetMenuEntry (&ConsoleOutMenu, Index); + NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext; + NewConsoleContext->IsActive = CurrentFakeNVMap->ConsoleCheck[Index]; + } + + for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) { + NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index); + NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext; + NewTerminalContext->IsConOut = CurrentFakeNVMap->ConsoleCheck[Index + ConsoleOutMenu.MenuNumber]; + } + + Var_UpdateConsoleOutOption (); + break; + + case FORM_CON_ERR_ID: + for (Index = 0; Index < ConsoleErrMenu.MenuNumber; Index++) { + NewMenuEntry = BOpt_GetMenuEntry (&ConsoleErrMenu, Index); + NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext; + NewConsoleContext->IsActive = CurrentFakeNVMap->ConsoleCheck[Index]; + } + + for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) { + NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index); + NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext; + NewTerminalContext->IsStdErr = CurrentFakeNVMap->ConsoleCheck[Index + ConsoleErrMenu.MenuNumber]; + } + + Var_UpdateErrorOutOption (); + break; + + case FORM_DRV_ADD_HANDLE_DESC_ID: + Status = Var_UpdateDriverOption ( + Private, + Private->BmmHiiHandle, + CurrentFakeNVMap->DriverAddHandleDesc, + CurrentFakeNVMap->DriverAddHandleOptionalData, + CurrentFakeNVMap->DriverAddForceReconnect + ); + if (EFI_ERROR (Status)) { + goto Error; + } + + BOpt_GetDriverOptions (Private); + CreateMenuStringToken (Private, Private->BmmHiiHandle, &DriverOptionMenu); + break; + + default: + break; + } + +Error: + return Status; +} + +VOID +DiscardChangeHandler ( + IN BMM_CALLBACK_DATA *Private, + IN BMM_FAKE_NV_DATA *CurrentFakeNVMap + ) +{ + UINT16 Index; + + switch (Private->BmmPreviousPageId) { + case FORM_BOOT_CHG_ID: + case FORM_DRV_CHG_ID: + CopyMem (CurrentFakeNVMap->OptionOrder, Private->BmmOldFakeNVData.OptionOrder, 100); + break; + + case FORM_BOOT_DEL_ID: + for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) { + CurrentFakeNVMap->BootOptionDel[Index] = 0x00; + } + break; + + case FORM_DRV_DEL_ID: + for (Index = 0; Index < DriverOptionMenu.MenuNumber; Index++) { + CurrentFakeNVMap->DriverOptionDel[Index] = 0x00; + } + 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; + } +} + +EFI_STATUS +EFIAPI +NvWrite ( + IN EFI_FORM_CALLBACK_PROTOCOL *This, + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT UINT32 Attributes OPTIONAL, + IN OUT UINTN DataSize, + OUT VOID *Buffer, + OUT BOOLEAN *ResetRequired + ) +{ + // + // Do nothing here. Just to catch the F10, we use "Apply Changes" tag to save. + // + return EFI_SUCCESS; +} + +EFI_STATUS +InitializeBM ( + VOID + ) +/*++ +Routine Description: + + Initialize the Boot Maintenance Utitliy + +Arguments: + + ImageHandle - caller provided handle + + SystemTable - caller provided system tables + +Returns: + + EFI_SUCCESS - utility ended successfully + + others - contain some errors + +--*/ +{ + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + EFI_HII_PACKAGES *PackageList; + BMM_CALLBACK_DATA *BmmCallbackInfo; + EFI_HII_PROTOCOL *Hii; + EFI_HII_HANDLE HiiHandle; + EFI_STATUS Status; + EFI_HANDLE Handle; + UINT8 *Ptr; + UINT8 *Location; + + Status = EFI_SUCCESS; + UpdateData = NULL; + // + // Initialize EfiUtilityLib and EfiDriverLib + // Since many functions in UtilityLib must be used and + // SetupBrowser use DriverLib + // + // + // There should be only one EFI_HII_PROTOCOL Image + // + Status = EfiLibLocateProtocol (&gEfiHiiProtocolGuid, &Hii); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Create CallbackData structures for Driver Callback + // + BmmCallbackInfo = AllocateZeroPool (sizeof (BMM_CALLBACK_DATA)); + if (!BmmCallbackInfo) { + return EFI_OUT_OF_RESOURCES; + } + // + // Create LoadOption in BmmCallbackInfo for Driver Callback + // + Ptr = AllocateZeroPool (sizeof (BM_LOAD_CONTEXT) + sizeof (BM_FILE_CONTEXT) + sizeof (BM_HANDLE_CONTEXT) + sizeof (BM_MENU_ENTRY)); + if (!Ptr) { + SafeFreePool (BmmCallbackInfo); + return EFI_OUT_OF_RESOURCES; + } + // + // Initialize Bmm callback data. + // + BmmCallbackInfo->LoadContext = (BM_LOAD_CONTEXT *) Ptr; + Ptr += sizeof (BM_LOAD_CONTEXT); + + BmmCallbackInfo->FileContext = (BM_FILE_CONTEXT *) Ptr; + Ptr += sizeof (BM_FILE_CONTEXT); + + BmmCallbackInfo->HandleContext = (BM_HANDLE_CONTEXT *) Ptr; + Ptr += sizeof (BM_HANDLE_CONTEXT); + + BmmCallbackInfo->MenuEntry = (BM_MENU_ENTRY *) Ptr; + + BmmCallbackInfo->BmmFakeNvData = &BmmCallbackInfo->BmmOldFakeNVData; + + ZeroMem (BmmCallbackInfo->BmmFakeNvData, sizeof (BMM_FAKE_NV_DATA)); + + BmmCallbackInfo->Signature = BMM_CALLBACK_DATA_SIGNATURE; + BmmCallbackInfo->Hii = Hii; + BmmCallbackInfo->BmmDriverCallback.NvRead = NULL; + BmmCallbackInfo->BmmDriverCallback.NvWrite = NvWrite; + BmmCallbackInfo->BmmDriverCallback.Callback = DriverCallback; + BmmCallbackInfo->BmmPreviousPageId = FORM_MAIN_ID; + BmmCallbackInfo->BmmCurrentPageId = FORM_MAIN_ID; + BmmCallbackInfo->FeDriverCallback.NvRead = NULL; + BmmCallbackInfo->FeDriverCallback.NvWrite = NvWrite; + BmmCallbackInfo->FeDriverCallback.Callback = FileExplorerCallback; + BmmCallbackInfo->FeCurrentState = INACTIVE_STATE; + BmmCallbackInfo->FeDisplayContext = UNKNOWN_CONTEXT; + + // + // Install bmm callback protocol interface + // + Handle = NULL; + Status = gBS->InstallProtocolInterface ( + &Handle, + &gEfiFormCallbackProtocolGuid, + EFI_NATIVE_INTERFACE, + &BmmCallbackInfo->BmmDriverCallback + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + BmmCallbackInfo->BmmCallbackHandle = Handle; + + // + // Install file explorer callback protocol interface + // + Handle = NULL; + Status = gBS->InstallProtocolInterface ( + &Handle, + &gEfiFormCallbackProtocolGuid, + EFI_NATIVE_INTERFACE, + &BmmCallbackInfo->FeDriverCallback + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + BmmCallbackInfo->FeCallbackHandle = Handle; + + // + // Post our VFR to the HII database. + // + PackageList = PreparePackages (1, &gBdsStringPackGuid, bmBin); + Status = Hii->NewPack (Hii, PackageList, &HiiHandle); + gBS->FreePool (PackageList); + + BmmCallbackInfo->BmmHiiHandle = HiiHandle; + + PackageList = PreparePackages (1, &gBdsStringPackGuid, FEBin); + Status = Hii->NewPack (Hii, PackageList, &HiiHandle); + gBS->FreePool (PackageList); + + BmmCallbackInfo->FeHiiHandle = HiiHandle; + + // + // Allocate space for creation of Buffer + // + UpdateData = AllocateZeroPool (UPDATE_DATA_SIZE); + if (!UpdateData) { + SafeFreePool (BmmCallbackInfo->LoadContext); + SafeFreePool (BmmCallbackInfo); + return EFI_OUT_OF_RESOURCES; + } + // + // Initialize UpdateData structure + // + RefreshUpdateData (TRUE, (EFI_PHYSICAL_ADDRESS) (UINTN) BmmCallbackInfo->BmmCallbackHandle, FALSE, 0, 0); + + Location = (UINT8 *) &UpdateData->Data; + + InitializeStringDepository (); + + InitAllMenu (BmmCallbackInfo); + + CreateMenuStringToken (BmmCallbackInfo, BmmCallbackInfo->BmmHiiHandle, &ConsoleInpMenu); + CreateMenuStringToken (BmmCallbackInfo, BmmCallbackInfo->BmmHiiHandle, &ConsoleOutMenu); + CreateMenuStringToken (BmmCallbackInfo, BmmCallbackInfo->BmmHiiHandle, &ConsoleErrMenu); + CreateMenuStringToken (BmmCallbackInfo, BmmCallbackInfo->BmmHiiHandle, &BootOptionMenu); + CreateMenuStringToken (BmmCallbackInfo, BmmCallbackInfo->BmmHiiHandle, &DriverOptionMenu); + CreateMenuStringToken (BmmCallbackInfo, BmmCallbackInfo->BmmHiiHandle, &TerminalMenu); + CreateMenuStringToken (BmmCallbackInfo, BmmCallbackInfo->BmmHiiHandle, &DriverMenu); + + UpdateBootDelPage (BmmCallbackInfo); + UpdateDrvDelPage (BmmCallbackInfo); + + if (TerminalMenu.MenuNumber > 0) { + BmmCallbackInfo->CurrentTerminal = 0; + UpdateTerminalPage (BmmCallbackInfo); + } + + Location = (UINT8 *) &UpdateData->Data; + Status = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, &LegacyBios); + if (!EFI_ERROR (Status)) { + // + // If LegacyBios Protocol is installed, add 3 tags about legacy boot option + // in BootOption form: legacy FD/HD/CD/NET/BEV + // + UpdateData->DataCount = 5; + CreateGotoOpCode ( + FORM_SET_FD_ORDER_ID, + STRING_TOKEN (STR_FORM_SET_FD_ORDER_TITLE), + STRING_TOKEN (STR_FORM_SET_FD_ORDER_TITLE), + EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_NV_ACCESS, + FORM_SET_FD_ORDER_ID, + Location + ); + + Location = Location + ((EFI_IFR_OP_HEADER *) Location)->Length; + + CreateGotoOpCode ( + FORM_SET_HD_ORDER_ID, + STRING_TOKEN (STR_FORM_SET_HD_ORDER_TITLE), + STRING_TOKEN (STR_FORM_SET_HD_ORDER_TITLE), + EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_NV_ACCESS, + FORM_SET_HD_ORDER_ID, + Location + ); + + Location = Location + ((EFI_IFR_OP_HEADER *) Location)->Length; + + CreateGotoOpCode ( + FORM_SET_CD_ORDER_ID, + STRING_TOKEN (STR_FORM_SET_CD_ORDER_TITLE), + STRING_TOKEN (STR_FORM_SET_CD_ORDER_TITLE), + EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_NV_ACCESS, + FORM_SET_CD_ORDER_ID, + Location + ); + + Location = Location + ((EFI_IFR_OP_HEADER *) Location)->Length; + + CreateGotoOpCode ( + FORM_SET_NET_ORDER_ID, + STRING_TOKEN (STR_FORM_SET_NET_ORDER_TITLE), + STRING_TOKEN (STR_FORM_SET_NET_ORDER_TITLE), + EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_NV_ACCESS, + FORM_SET_NET_ORDER_ID, + Location + ); + + Location = Location + ((EFI_IFR_OP_HEADER *) Location)->Length; + + CreateGotoOpCode ( + FORM_SET_BEV_ORDER_ID, + STRING_TOKEN (STR_FORM_SET_BEV_ORDER_TITLE), + STRING_TOKEN (STR_FORM_SET_BEV_ORDER_TITLE), + EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_NV_ACCESS, + FORM_SET_BEV_ORDER_ID, + Location + ); + + Hii->UpdateForm ( + Hii, + BmmCallbackInfo->BmmHiiHandle, + (EFI_FORM_LABEL) FORM_BOOT_LEGACY_DEVICE_ID, + TRUE, + UpdateData + ); + } + // + // Dispatch BMM main formset and File Explorer formset. + // + FormSetDispatcher (BmmCallbackInfo); + + Hii->ResetStrings (Hii, HiiHandle); + + CleanUpStringDepository (); + + if (EFI_ERROR (Status)) { + return Status; + } + + FreeAllMenu (); + + SafeFreePool (BmmCallbackInfo->LoadContext); + BmmCallbackInfo->LoadContext = NULL; + SafeFreePool (BmmCallbackInfo); + BmmCallbackInfo = NULL; + SafeFreePool (UpdateData); + UpdateData = NULL; + + return Status; +} + +VOID +InitAllMenu ( + IN BMM_CALLBACK_DATA *CallbackData + ) +{ + InitializeListHead (&BootOptionMenu.Head); + InitializeListHead (&DriverOptionMenu.Head); + BOpt_GetBootOptions (CallbackData); + BOpt_GetDriverOptions (CallbackData); + BOpt_GetLegacyOptions (); + InitializeListHead (&FsOptionMenu.Head); + BOpt_FindDrivers (); + InitializeListHead (&DirectoryMenu.Head); + InitializeListHead (&ConsoleInpMenu.Head); + InitializeListHead (&ConsoleOutMenu.Head); + InitializeListHead (&ConsoleErrMenu.Head); + InitializeListHead (&TerminalMenu.Head); + LocateSerialIo (); + GetAllConsoles (); +} + +VOID +FreeAllMenu ( + VOID + ) +{ + BOpt_FreeMenu (&DirectoryMenu); + BOpt_FreeMenu (&FsOptionMenu); + BOpt_FreeMenu (&BootOptionMenu); + BOpt_FreeMenu (&DriverOptionMenu); + BOpt_FreeMenu (&DriverMenu); + BOpt_FreeLegacyOptions (); + FreeAllConsoles (); +} + +VOID +InitializeStringDepository ( + VOID + ) +/*++ +Routine Description: + Intialize all the string depositories. + +Arguments: + None. + +Returns: + None. +--*/ +{ + STRING_DEPOSITORY *StringDepository; + StringDepository = AllocateZeroPool (sizeof (STRING_DEPOSITORY) * STRING_DEPOSITORY_NUMBER); + FileOptionStrDepository = StringDepository++; + ConsoleOptionStrDepository = StringDepository++; + BootOptionStrDepository = StringDepository++; + BootOptionHelpStrDepository = StringDepository++; + DriverOptionStrDepository = StringDepository++; + DriverOptionHelpStrDepository = StringDepository++; + TerminalStrDepository = StringDepository; +} + +STRING_REF +GetStringTokenFromDepository ( + IN BMM_CALLBACK_DATA *CallbackData, + IN STRING_DEPOSITORY *StringDepository + ) +/*++ +Routine Description: + Fetch a usable string node from the string depository and return the string token. + +Arguments: + StringDepository - Pointer of the string depository. + +Returns: + STRING_REF - String token. +--*/ +{ + STRING_LIST_NODE *CurrentListNode; + STRING_LIST_NODE *NextListNode; + + CurrentListNode = StringDepository->CurrentNode; + + if ((NULL != CurrentListNode) && (NULL != CurrentListNode->Next)) { + // + // Fetch one reclaimed node from the list. + // + NextListNode = StringDepository->CurrentNode->Next; + } else { + // + // If there is no usable node in the list, update the list. + // + NextListNode = AllocateZeroPool (sizeof (STRING_LIST_NODE)); + + CallbackData->Hii->NewString ( + CallbackData->Hii, + NULL, + CallbackData->BmmHiiHandle, + &(NextListNode->StringToken), + L" " + ); + + ASSERT (NextListNode->StringToken != 0); + + StringDepository->TotalNodeNumber++; + + if (NULL == CurrentListNode) { + StringDepository->ListHead = NextListNode; + } else { + CurrentListNode->Next = NextListNode; + } + } + + StringDepository->CurrentNode = NextListNode; + + return StringDepository->CurrentNode->StringToken; +} + +VOID +ReclaimStringDepository ( + VOID + ) +/*++ +Routine Description: + Reclaim string depositories by moving the current node pointer to list head.. + +Arguments: + None. + +Returns: + None. +--*/ +{ + UINTN DepositoryIndex; + STRING_DEPOSITORY *StringDepository; + + StringDepository = FileOptionStrDepository; + for (DepositoryIndex = 0; DepositoryIndex < STRING_DEPOSITORY_NUMBER; DepositoryIndex++) { + StringDepository->CurrentNode = StringDepository->ListHead; + StringDepository++; + } +} + +VOID +CleanUpStringDepository ( + VOID + ) +/*++ +Routine Description: + Release resource for all the string depositories. + +Arguments: + None. + +Returns: + None. +--*/ +{ + UINTN NodeIndex; + UINTN DepositoryIndex; + STRING_LIST_NODE *CurrentListNode; + STRING_LIST_NODE *NextListNode; + STRING_DEPOSITORY *StringDepository; + + // + // Release string list nodes. + // + StringDepository = FileOptionStrDepository; + for (DepositoryIndex = 0; DepositoryIndex < STRING_DEPOSITORY_NUMBER; DepositoryIndex++) { + CurrentListNode = StringDepository->ListHead; + for (NodeIndex = 0; NodeIndex < StringDepository->TotalNodeNumber; NodeIndex++) { + NextListNode = CurrentListNode->Next; + SafeFreePool (CurrentListNode); + CurrentListNode = NextListNode; + } + + StringDepository++; + } + // + // Release string depository. + // + SafeFreePool (FileOptionStrDepository); +} + +EFI_STATUS +BdsStartBootMaint ( + VOID + ) +/*++ + +Routine Description: + Start boot maintenance manager + +Arguments: + +Returns: + +--*/ +{ + EFI_STATUS Status; + LIST_ENTRY BdsBootOptionList; + + InitializeListHead (&BdsBootOptionList); + + // + // Connect all prior to entering the platform setup menu. + // + if (!gConnectAllHappened) { + BdsLibConnectAllDriversToAllControllers (); + gConnectAllHappened = TRUE; + } + // + // Have chance to enumerate boot device + // + BdsLibEnumerateAllBootOption (&BdsBootOptionList); + + // + // Init the BMM + // + Status = InitializeBM (); + + return Status; +} + +EFI_STATUS +FormSetDispatcher ( + IN BMM_CALLBACK_DATA *CallbackData + ) +/*++ + +Routine Description: + Dispatch BMM formset and FileExplorer formset. + +Arguments: + +Returns: + +--*/ +{ + EFI_FORM_BROWSER_PROTOCOL *FormConfig; + UINT8 *Location; + EFI_STATUS Status; + UINTN Index; + BM_MENU_ENTRY *NewMenuEntry; + BM_FILE_CONTEXT *NewFileContext; + + Location = NULL; + Index = 0; + NewMenuEntry = NULL; + NewFileContext = NULL; + + // + // There should only be one Form Configuration protocol + // + Status = EfiLibLocateProtocol (&gEfiFormBrowserProtocolGuid, &FormConfig); + if (EFI_ERROR (Status)) { + return Status; + } + + while (1) { + UpdatePageId (CallbackData, FORM_MAIN_ID); + + Status = FormConfig->SendForm ( + FormConfig, + TRUE, + &(CallbackData->BmmHiiHandle), + 1, + NULL, + NULL, + (UINT8 *) CallbackData->BmmFakeNvData, + NULL, + NULL + ); + + ReclaimStringDepository (); + + // + // When this Formset returns, check if we are going to explore files. + // + if (INACTIVE_STATE != CallbackData->FeCurrentState) { + UpdateFileExplorer (CallbackData, 0); + + Status = FormConfig->SendForm ( + FormConfig, + TRUE, + &(CallbackData->FeHiiHandle), + 1, + NULL, + NULL, + NULL, + NULL, + NULL + ); + + CallbackData->FeCurrentState = INACTIVE_STATE; + CallbackData->FeDisplayContext = UNKNOWN_CONTEXT; + ReclaimStringDepository (); + } else { + break; + } + } + + return Status; +} + +VOID +CreateCallbackPacket ( + OUT EFI_HII_CALLBACK_PACKET **Packet, + IN UINT16 Flags + ) +{ + *Packet = (EFI_HII_CALLBACK_PACKET *) AllocateZeroPool (sizeof (EFI_HII_CALLBACK_PACKET) + 2); + ASSERT (*Packet != NULL); + + (*Packet)->DataArray.EntryCount = 1; + (*Packet)->DataArray.NvRamMap = NULL; + ((EFI_IFR_DATA_ENTRY *) (&((*Packet)->DataArray) + 1))->Flags = Flags; +} diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/BootMaint.h b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/BootMaint.h new file mode 100644 index 0000000000..1e0dc8de87 --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/BootMaint.h @@ -0,0 +1,1161 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + bootmaint.h + +Abstract: + +Revision History + +--*/ + +#ifndef _BOOT_MAINT_H +#define _BOOT_MAINT_H + +#include "BdsStrDefs.h" +#include "Generic/BootMaint/BBSsupport.h" + +// +// Constants which are variable names used to access variables +// +#define VarLegacyDevOrder L"LegacyDevOrder" + +// +// Guid of a NV Variable which store the information about the +// FD/HD/CD/NET/BEV order +// +#define EFI_LEGACY_DEV_ORDER_VARIABLE_GUID \ + { \ + 0xa56074db, 0x65fe, 0x45f7, {0xbd, 0x21, 0x2d, 0x2b, 0xdd, 0x8e, 0x96, 0x52 } \ + } + +// +// String Contant +// +#define StrFloppy L"Floppy Drive #%02x" +#define StrHardDisk L"HardDisk Drive #%02x" +#define StrCDROM L"ATAPI CDROM Drive #%02x" +#define StrNET L"NET Drive #%02x" +#define StrBEV L"BEV Drive #%02x" +#define StrFloppyHelp L"Select Floppy Drive #%02x" +#define StrHardDiskHelp L"Select HardDisk Drive #%02x" +#define StrCDROMHelp L"Select ATAPI CDROM Drive #%02x" +#define StrNETHelp L"NET Drive #%02x" +#define StrBEVHelp L"BEV Drive #%02x" + +// +// Constant will be used in display and file system navigation +// +#define UPDATE_DATA_SIZE 0x100000 +#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 0x0A00 +#define TERMINAL_OPTION_OFFSET 0x0700 +#define NORMAL_GOTO_OFFSET 0x0100 +#define MAX_STRING_TOKEN_COUNT 0x00FF +// +// Variable created with this flag will be "Efi:...." +// +#define VAR_FLAG EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE + +// +// Define Maxmim characters that will be accepted +// +#define MAX_CHAR 480 +#define MAX_CHAR_SIZE (MAX_CHAR * 2) + +// +// Check to see if current build support option active feature of +// some driver option +// +#ifndef LOAD_OPTION_ACTIVE +#define LOAD_OPTION_ACTIVE 0x00000001 +#endif +// +// Check to see if current build support force reconnect feature of +// some driver option +// +#ifndef LOAD_OPTION_FORCE_RECONNECT +#define LOAD_OPTION_FORCE_RECONNECT 0x00000002 +#endif +// +// Below are the form ids for display, form id is used as callback key value, +// some key value definitions are also defined here. By defining this enum type, +// We can easy know where we are. The int to UINT16 convertion should be ok because +// there is a MAXIMUM_FORM_ID which in within the range of UINT16. +// +typedef enum { + IplRelative, + BcvRelative +} BBS_TYPE; + +typedef enum { + FORM_RESERVED_ID = 0, + FORM_MAIN_ID, // 0x0001 + FORM_BOOT_ADD_ID, // 0x0002 + FORM_BOOT_DEL_ID, // 0x0003 + FORM_BOOT_CHG_ID, // 0x0004 + FORM_DRV_ADD_ID, // 0x0005 + FORM_DRV_DEL_ID, // 0x0006 + FORM_DRV_CHG_ID, // 0x0007 + FORM_CON_MAIN_ID, // 0x0008 + FORM_CON_IN_ID, // 0x0009 + FORM_CON_OUT_ID, // 0x000A + FORM_CON_ERR_ID, // 0x000B + FORM_FILE_SEEK_ID, // 0x000C + FORM_FILE_NEW_SEEK_ID, // 0x000D + FORM_DRV_ADD_FILE_ID, // 0x000E + FORM_DRV_ADD_HANDLE_ID, // 0x000F + FORM_DRV_ADD_HANDLE_DESC_ID, // 0x0010 + FORM_BOOT_NEXT_ID, // 0x0011 + FORM_TIME_OUT_ID, // 0x0012 + FORM_RESET, // 0x0013 + FORM_BOOT_SETUP_ID, // 0x0014 + FORM_DRIVER_SETUP_ID, // 0x0015 + FORM_BOOT_LEGACY_DEVICE_ID, // 0x0016 + FORM_CON_COM_ID, // 0x0017 + FORM_CON_COM_SETUP_ID, // 0x0018 + FORM_SET_FD_ORDER_ID, // 0x0019 + FORM_SET_HD_ORDER_ID, // 0x001A + FORM_SET_CD_ORDER_ID, // 0x001B + FORM_SET_NET_ORDER_ID, // 0x001C + FORM_SET_BEV_ORDER_ID, // 0x001D + FORM_FILE_EXPLORER_ID, // 0x001E + FORM_BOOT_ADD_DESCRIPTION_ID, // 0x001F + FORM_DRIVER_ADD_FILE_DESCRIPTION_ID, // 0x0020 +} FORM_ID; + +#define MAXIMUM_FORM_ID 0x007F + +#define KEY_VALUE_COM_SET_BAUD_RATE 0x0080 +#define KEY_VALUE_COM_SET_DATA_BITS 0x0081 +#define KEY_VALUE_COM_SET_STOP_BITS 0x0082 +#define KEY_VALUE_COM_SET_PARITY 0x0083 +#define KEY_VALUE_COM_SET_TERMI_TYPE 0x0084 +#define KEY_VALUE_MAIN_BOOT_NEXT 0x0085 +#define KEY_VALUE_BOOT_ADD_DESC_DATA 0x0086 +#define KEY_VALUE_BOOT_ADD_OPT_DATA 0x0087 +#define KEY_VALUE_DRIVER_ADD_DESC_DATA 0x0088 +#define KEY_VALUE_DRIVER_ADD_OPT_DATA 0x0089 +#define KEY_VALUE_SAVE_AND_EXIT 0x0090 +#define KEY_VALUE_NO_SAVE_AND_EXIT 0x0091 +#define KEY_VALUE_BOOT_FROM_FILE 0x0092 + +#define MAXIMUM_NORMAL_KEY_VALUE NORMAL_GOTO_OFFSET +// +// 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 EFI_SIGNATURE_32 ('C', 'b', 'c', 'k') +#define BMM_CALLBACK_DATA_FROM_THIS(a) CR (a, BMM_CALLBACK_DATA, BmmDriverCallback, BMM_CALLBACK_DATA_SIGNATURE) + +#define FE_CALLBACK_DATA_FROM_THIS(a) CR (a, BMM_CALLBACK_DATA, FeDriverCallback, BMM_CALLBACK_DATA_SIGNATURE) + +// +// Enumeration type definition +// +typedef enum { + PC_ANSI = 0, + VT_100, + VT_100_PLUS, + VT_UTF8 +} TYPE_OF_TERMINAL; + +typedef enum { + COM1 = 0, + COM2, + UNKNOW_COM +} TYPE_OF_COM; + +typedef enum { + CONIN = 0, + CONOUT, + CONERR, + UNKNOWN_CON +} TYPE_OF_CON; + +typedef enum { + BAUDRATE = 0, + DATABITS, + PARITY, + STOPBITS, + UNKNOW_ATTR +} TYPE_OF_ATTRIBUTE; + +typedef enum { + MANNER_GOTO = 0, + MANNER_CHECK, + MANNER_ONEOF, + MANNER_USER_DEFINE +} TYPE_OF_UPATE_MANNER; + +typedef enum { + INACTIVE_STATE = 0, + BOOT_FROM_FILE_STATE, + ADD_BOOT_OPTION_STATE, + ADD_DRIVER_OPTION_STATE, + UNKNOWN_STATE +} FILE_EXPLORER_STATE; + +typedef enum { + FILE_SYSTEM, + DIRECTORY, + UNKNOWN_CONTEXT +} FILE_EXPLORER_DISPLAY_CONTEXT; + +// +// All of the signatures that will be used in list structure +// +#define BM_MENU_OPTION_SIGNATURE 'menu' +#define BM_LOAD_OPTION_SIGNATURE 'load' +#define BM_CONSOLE_OPTION_SIGNATURE 'cnsl' +#define BM_FILE_OPTION_SIGNATURE 'file' +#define BM_HANDLE_OPTION_SIGNATURE 'hndl' +#define BM_TERMINAL_OPTION_SIGNATURE 'trml' +#define BM_MENU_ENTRY_SIGNATURE 'entr' + +#define BM_LOAD_CONTEXT_SELECT 0x0 +#define BM_CONSOLE_CONTEXT_SELECT 0x1 +#define BM_FILE_CONTEXT_SELECT 0x2 +#define BM_HANDLE_CONTEXT_SELECT 0x3 +#define BM_TERMINAL_CONTEXT_SELECT 0x5 + +#define BM_CONSOLE_IN_CONTEXT_SELECT 0x6 +#define BM_CONSOLE_OUT_CONTEXT_SELECT 0x7 +#define BM_CONSOLE_ERR_CONTEXT_SELECT 0x8 +#define BM_LEGACY_DEV_CONTEXT_SELECT 0x9 + +// +// Question Id that will be used to create question +// all these values are computed from the structure +// defined below +// +#define QUESTION_ID(Field) ((UINTN) &(((BMM_FAKE_NV_DATA *) 0)->Field)) + +#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_DEVICE_QUESTION_ID QUESTION_ID (ConsoleCheck) +#define OPTION_ORDER_QUESTION_ID QUESTION_ID (OptionOrder) +#define DRIVER_OPTION_ORDER_QUESTION_ID QUESTION_ID (DriverOptionToBeDeleted) +#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 LEGACY_FD_QUESTION_ID QUESTION_ID (LegacyFD) +#define LEGACY_HD_QUESTION_ID QUESTION_ID (LegacyHD) +#define LEGACY_CD_QUESTION_ID QUESTION_ID (LegacyCD) +#define LEGACY_NET_QUESTION_ID QUESTION_ID (LegacyNET) +#define LEGACY_BEV_QUESTION_ID QUESTION_ID (LegacyBEV) + +#define STRING_DEPOSITORY_NUMBER 8 + +// +// #pragma pack(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; + +// +// This is the structure that will be used to store the +// question's current value. Use it at initialize time to +// set default value for each question. When using at run +// time, this map is returned by the callback function, +// so dynamically changing the question's value will be +// possible through this mechanism +// +typedef struct { + // + // Three questions displayed at the main page + // for Timeout, BootNext Variables respectively + // + UINT16 BootTimeOut; + UINT16 BootNext; + + // + // This is the COM1 Attributes value storage + // + UINT8 COM1BaudRate; + UINT8 COM1DataRate; + UINT8 COM1StopBits; + UINT8 COM1Parity; + UINT8 COM1TerminalType; + + // + // This is the COM2 Attributes value storage + // + UINT8 COM2BaudRate; + UINT8 COM2DataRate; + UINT8 COM2StopBits; + UINT8 COM2Parity; + UINT8 COM2TerminalType; + + // + // Driver Option Add Handle page storage + // + UINT16 DriverAddHandleDesc[75]; + UINT16 DriverAddHandleOptionalData[75]; + 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[100]; + + // + // Boot or Driver Option Order storage + // + UINT8 OptionOrder[100]; + UINT8 DriverOptionToBeDeleted[100]; + + // + // Boot Option Delete storage + // + UINT8 BootOptionDel[100]; + UINT8 DriverOptionDel[100]; + + // + // This is the Terminal Attributes value storage + // + UINT8 COMBaudRate; + UINT8 COMDataRate; + UINT8 COMStopBits; + UINT8 COMParity; + UINT8 COMTerminalType; + + // + // Legacy Device Order Selection Storage + // + UINT8 LegacyFD[100]; + UINT8 LegacyHD[100]; + UINT8 LegacyCD[100]; + UINT8 LegacyNET[100]; + UINT8 LegacyBEV[100]; + + // + // 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]; + + // + // UINT16 PadArea[10]; + // +} BMM_FAKE_NV_DATA; + +typedef struct { + UINT16 DescriptionData[75]; + UINT16 OptionalData[127]; + UINT8 Active; + UINT8 ForceReconnect; +} FILE_EXPLORER_NV_DATA; + +typedef struct { + BBS_TYPE BbsType; + // + // Length = sizeof (UINT16) + SIZEOF (Data) + // + UINT16 Length; + UINT16 *Data; +} BM_LEGACY_DEV_ORDER_CONTEXT; + +typedef struct { + UINT64 BaudRate; + UINT8 DataBits; + UINT8 Parity; + UINT8 StopBits; + + UINT8 BaudRateIndex; + UINT8 DataBitsIndex; + UINT8 ParityIndex; + UINT8 StopBitsIndex; + + UINT8 IsConIn; + UINT8 IsConOut; + UINT8 IsStdErr; + UINT8 TerminalType; + + EFI_DEVICE_PATH_PROTOCOL *DevicePath; +} BM_TERMINAL_CONTEXT; + +typedef struct { + BOOLEAN IsBootNext; + BOOLEAN LoadOptionModified; + BOOLEAN Deleted; + + BOOLEAN IsLegacy; + BOOLEAN IsActive; + BOOLEAN ForceReconnect; + UINTN OptionalDataSize; + + UINTN LoadOptionSize; + UINT8 *LoadOption; + + UINT32 Attributes; + UINT16 FilePathListLength; + UINT16 *Description; + EFI_DEVICE_PATH_PROTOCOL *FilePathList; + UINT8 *OptionalData; + + UINT16 BbsIndex; +} BM_LOAD_CONTEXT; + +typedef struct { + BBS_TABLE *BbsTable; + UINTN Index; + UINTN BbsCount; + UINT16 *Description; +} BM_LEGACY_DEVICE_CONTEXT; + +typedef struct { + + BOOLEAN IsActive; + + BOOLEAN IsTerminal; + + EFI_DEVICE_PATH_PROTOCOL *DevicePath; +} BM_CONSOLE_CONTEXT; + +typedef struct { + EFI_HANDLE Handle; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_FILE_HANDLE FHandle; + UINT16 *FileName; + EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *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; + STRING_REF DisplayStringToken; + STRING_REF HelpStringToken; + UINTN ContextSelection; + VOID *VariableContext; +} BM_MENU_ENTRY; + +typedef struct { + // + // Shared callback data. + // + UINTN Signature; + EFI_HII_PROTOCOL *Hii; + BM_MENU_ENTRY *MenuEntry; + BM_HANDLE_CONTEXT *HandleContext; + BM_FILE_CONTEXT *FileContext; + BM_LOAD_CONTEXT *LoadContext; + BM_TERMINAL_CONTEXT *TerminalContext; + UINTN CurrentTerminal; + BBS_TYPE BbsType; + + // + // BMM main formset callback data. + // + EFI_HII_HANDLE BmmHiiHandle; + EFI_HANDLE BmmCallbackHandle; + EFI_FORM_CALLBACK_PROTOCOL BmmDriverCallback; + FORM_ID BmmCurrentPageId; + FORM_ID BmmPreviousPageId; + BOOLEAN BmmAskSaveOrNot; + BMM_FAKE_NV_DATA *BmmFakeNvData; + BMM_FAKE_NV_DATA BmmOldFakeNVData; + + // + // File explorer formset callback data. + // + EFI_HII_HANDLE FeHiiHandle; + EFI_HANDLE FeCallbackHandle; + EFI_FORM_CALLBACK_PROTOCOL FeDriverCallback; + FILE_EXPLORER_STATE FeCurrentState; + FILE_EXPLORER_DISPLAY_CONTEXT FeDisplayContext; +} BMM_CALLBACK_DATA; + +typedef struct _STRING_LIST_NODE { + STRING_REF StringToken; + struct _STRING_LIST_NODE *Next; +} STRING_LIST_NODE; + +typedef struct _STRING_DEPOSITORY { + UINTN TotalNodeNumber; + STRING_LIST_NODE *CurrentNode; + STRING_LIST_NODE *ListHead; +} STRING_DEPOSITORY; + +// +// #pragma pack() +// +// For initializing File System menu +// +EFI_STATUS +BOpt_FindFileSystem ( + IN BMM_CALLBACK_DATA *CallbackData + ) +; + +// +// For cleaning up File System menu +// +VOID +BOpt_FreeFileSystem ( + VOID + ) +; + +// +// For initializing File Navigation menu +// +EFI_STATUS +BOpt_FindFiles ( + IN BMM_CALLBACK_DATA *CallbackData, + IN BM_MENU_ENTRY *MenuEntry + ) +; + +// +// For cleaning up File Navigation menu +// +VOID +BOpt_FreeFiles ( + VOID + ) +; + +// +// For Initializing handle navigation menu +// +EFI_STATUS +BOpt_FindDrivers ( + VOID + ) +; + +// +// For Cleaning up handle navigation menu +// +VOID +BOpt_FreeDrivers(); + +// +// For initializing Boot Option menu +// +EFI_STATUS +BOpt_GetBootOptions ( + IN BMM_CALLBACK_DATA *CallbackData + ); + +// +// For Initializing Driver option menu +// +EFI_STATUS +BOpt_GetDriverOptions ( + IN BMM_CALLBACK_DATA *CallbackData + ); + +// +// For Cleaning up boot option menu +// +VOID +BOpt_FreeBootOptions (); + +// +// For cleaning up driver option menu +// +VOID +BOpt_FreeDriverOptions(); + +// +// For Initializing HD/FD/CD/NET/BEV option menu +// +EFI_STATUS +BOpt_GetLegacyOptions(); + +// +// For cleaning up driver option menu +// +VOID +BOpt_FreeLegacyOptions(); + +// +// this function is used to take place of all other free menu actions +// +VOID +BOpt_FreeMenu ( + BM_MENU_OPTION *FreeMenu + ); + + +// +// Following are the helper functions used +// +CHAR16 * +BOpt_AppendFileName ( + IN CHAR16 *Str1, + IN CHAR16 *Str2 + ); + +BOOLEAN +BOpt_IsEfiImageName ( + IN UINT16 *FileName + ); + +BOOLEAN +BOpt_IsEfiApp ( + IN EFI_FILE_HANDLE Dir, + IN UINT16 *FileName + ); + +// +// Get current unused boot option number +// +UINT16 +BOpt_GetBootOptionNumber (); + +// +// Get current unused driver option number +// +UINT16 +BOpt_GetDriverOptionNumber (); + +BM_MENU_ENTRY * +BOpt_CreateMenuEntry ( + UINTN MenuType + ); + +VOID +BOpt_DestroyMenuEntry ( + BM_MENU_ENTRY *MenuEntry + ); + +BM_MENU_ENTRY * +BOpt_GetMenuEntry ( + BM_MENU_OPTION *MenuOption, + UINTN MenuNumber + ); + +// +// a helper function used to free pool type memory +// +VOID +SafeFreePool ( + IN VOID *Buffer + ); + +// +// Locate all serial io devices for console +// +EFI_STATUS +LocateSerialIo (); + +// +// Initializing Console menu +// +EFI_STATUS +GetAllConsoles(); + +// +// Cleaning up console menu +// +EFI_STATUS +FreeAllConsoles(); + +VOID +ChangeVariableDevicePath ( + EFI_DEVICE_PATH_PROTOCOL *DevicePath +); + +EFI_STATUS +ChangeTerminalDevicePath ( + EFI_DEVICE_PATH_PROTOCOL *DevicePath, + BOOLEAN ChangeTerminal +); +// +// Variable operation by menu selection +// +EFI_STATUS +Var_UpdateBootOption ( + IN BMM_CALLBACK_DATA *CallbackData, + IN FILE_EXPLORER_NV_DATA *NvRamMap + ); + +EFI_STATUS +Var_DelBootOption (); + +EFI_STATUS +Var_ChangeBootOrder (); + +EFI_STATUS +Var_UpdateDriverOption ( + IN BMM_CALLBACK_DATA *CallbackData, + IN EFI_HII_HANDLE HiiHandle, + IN UINT16 *DescriptionData, + IN UINT16 *OptionalData, + IN UINT8 ForceReconnect + ); + +EFI_STATUS +Var_DelDriverOption (); + +EFI_STATUS +Var_ChangeDriverOrder (); + +EFI_STATUS +Var_UpdateConsoleInpOption (); + +EFI_STATUS +Var_UpdateConsoleOutOption (); + +EFI_STATUS +Var_UpdateErrorOutOption (); + +VOID +Var_UpdateAllConsoleOption (); + +EFI_STATUS +Var_UpdateBootNext ( + IN BMM_CALLBACK_DATA *CallbackData + ); + +EFI_STATUS +Var_UpdateBootOrder ( + IN BMM_CALLBACK_DATA *CallbackData + ); + +EFI_STATUS +Var_UpdateDriverOrder ( + IN BMM_CALLBACK_DATA *CallbackData + ); + +EFI_STATUS +Var_UpdateBBSOption ( + IN BMM_CALLBACK_DATA *CallbackData + ); + +// +// Following are page create and refresh functions +// +VOID +RefreshUpdateData ( + IN BOOLEAN FormSetUpdate, + IN EFI_PHYSICAL_ADDRESS FormCallbackHandle, + IN BOOLEAN FormUpdate, + IN STRING_REF FormTitle, + IN UINT16 DataCount + ); + +VOID +CleanUpPage ( + IN EFI_FORM_LABEL LabelId, + IN BMM_CALLBACK_DATA *CallbackData + ); + +EFI_STATUS +UpdatePage ( + IN BMM_CALLBACK_DATA *CallbackData, + IN BM_MENU_OPTION *UpdatingMenu, + IN UINT16 UpdatingPage, + IN UINT16 UpdatingManner, + IN UINT16 QuestionIdStart, + IN UINT16 GotoForm, + IN UINT16 GotoAlternateForm, + IN STRING_REF DisplayTokenStart, + IN STRING_REF HelpTokenStart, + IN UINT16 KeyValueStart + ); + +VOID +UpdateBootAddPage ( + IN BMM_CALLBACK_DATA *CallbackData + ); + +VOID +UpdateBootDelPage ( + IN BMM_CALLBACK_DATA *CallbackData + ); + +VOID +UpdateDrvAddFilePage ( + IN BMM_CALLBACK_DATA *CallbackData + ); + +VOID +UpdateDrvAddHandlePage ( + IN BMM_CALLBACK_DATA *CallbackData + ); + +VOID +UpdateDrvDelPage ( + IN BMM_CALLBACK_DATA *CallbackData + ); + +VOID +UpdateDriverAddHandleDescPage ( + IN BMM_CALLBACK_DATA *CallbackData + ); + +VOID +UpdateBootTimeOut ( + IN BMM_CALLBACK_DATA *CallbackData + ); + +VOID +UpdateConInPage ( + IN BMM_CALLBACK_DATA *CallbackData + ); + +VOID +UpdateConOutPage ( + IN BMM_CALLBACK_DATA *CallbackData + ); + +VOID +UpdateStdErrPage ( + IN BMM_CALLBACK_DATA *CallbackData + ); + +VOID +UpdatePageBody ( + IN UINT16 UpdatePageId, + IN BMM_CALLBACK_DATA *CallbackData + ); + +VOID +UpdateCOM1Page ( + IN BMM_CALLBACK_DATA *CallbackData + ); + +VOID +UpdateCOM2Page ( + IN BMM_CALLBACK_DATA *CallbackData + ); + +VOID +UpdateBootOrderPage ( + IN BMM_CALLBACK_DATA *CallbackData + ); + +VOID +UpdateDriverOrderPage ( + IN BMM_CALLBACK_DATA *CallbackData + ); + +VOID +UpdateBootNextPage ( + IN BMM_CALLBACK_DATA *CallbackData + ); + +VOID +UpdateTimeOutPage ( + IN BMM_CALLBACK_DATA *CallbackData + ); + +VOID +UpdateTerminalPage ( + IN BMM_CALLBACK_DATA *CallbackData + ); + +VOID +UpdateConCOMPage ( + IN BMM_CALLBACK_DATA *CallbackData + ); + +VOID +UpdateSetLegacyDeviceOrderPage ( + IN UINT16 UpdatePageId, + IN BMM_CALLBACK_DATA *CallbackData +); + +EFI_STATUS +BootLegacy ( + IN UINT16 BbsType, + IN UINT16 BbsFlag +); + +BM_MENU_ENTRY * +GetCurrentTerminal ( + UINTN TerminalNumber +); + +EFI_FILE_HANDLE +EfiLibOpenRoot ( + IN EFI_HANDLE DeviceHandle + ); + +EFI_FILE_SYSTEM_VOLUME_LABEL_INFO * +EfiLibFileSystemVolumeLabelInfo ( + IN EFI_FILE_HANDLE FHand + ); + +EFI_FILE_INFO * +EfiLibFileInfo ( + IN EFI_FILE_HANDLE FHand + ); + +CHAR16 * +DevicePathToStr ( + EFI_DEVICE_PATH_PROTOCOL *DevPath + ); + +EFI_STATUS +EfiLibLocateProtocol ( + IN EFI_GUID *ProtocolGuid, + OUT VOID **Interface + ); + +VOID * +EfiReallocatePool ( + IN VOID *OldPool, + IN UINTN OldSize, + IN UINTN NewSize + ); + +CHAR16 * +DevicePathToStr ( + EFI_DEVICE_PATH_PROTOCOL *DevPath + ); + +VOID * +BdsLibGetVariableAndSize ( + IN CHAR16 *Name, + IN EFI_GUID *VendorGuid, + OUT UINTN *VarSize + ); + +EFI_STATUS +EfiLibDeleteVariable ( + IN CHAR16 *VarName, + IN EFI_GUID *VarGuid + ); + +CHAR16 * +EfiStrDuplicate ( + IN CHAR16 *Src + ); + +BOOLEAN +EfiLibMatchDevicePaths ( + IN EFI_DEVICE_PATH_PROTOCOL *Multi, + IN EFI_DEVICE_PATH_PROTOCOL *Single + ); + +UINTN +EfiDevicePathInstanceCount ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ); + +EFI_STATUS +CreateMenuStringToken ( + IN BMM_CALLBACK_DATA *CallbackData, + IN EFI_HII_HANDLE HiiHandle, + IN BM_MENU_OPTION *MenuOption + ); + +UINT16 * +EfiLibStrFromDatahub ( + IN EFI_DEVICE_PATH_PROTOCOL *DevPath + ); + +VOID * +GetLegacyBootOptionVar ( + IN UINTN DeviceType, + OUT UINTN *OptionIndex, + OUT UINTN *OptionSize + ); + +EFI_STATUS +InitializeBM ( + VOID + ); + +EFI_STATUS +BdsStartBootMaint ( + VOID + ); + +VOID +InitializeStringDepository (); + +STRING_REF +GetStringTokenFromDepository ( + IN BMM_CALLBACK_DATA *CallbackData, + IN STRING_DEPOSITORY *StringDepository + ) ; + +VOID +ReclaimStringDepository ( + VOID + ); + +VOID +CleanUpStringDepository ( + VOID + ); + +EFI_STATUS +ApplyChangeHandler ( + IN BMM_CALLBACK_DATA *Private, + IN BMM_FAKE_NV_DATA *CurrentFakeNVMap, + IN FORM_ID FormId + ); + +VOID +DiscardChangeHandler ( + IN BMM_CALLBACK_DATA *Private, + IN BMM_FAKE_NV_DATA *CurrentFakeNVMap + ); + +VOID +UpdatePageId ( + BMM_CALLBACK_DATA *Private, + UINT16 NewPageId + ); + +EFI_STATUS +BootThisFile ( + IN BM_FILE_CONTEXT *FileContext + ); + +BOOLEAN +UpdateFileExplorer ( + IN BMM_CALLBACK_DATA *CallbackData, + IN UINT16 KeyValue + ); + +EFI_STATUS +EFIAPI +FileExplorerCallback ( + IN EFI_FORM_CALLBACK_PROTOCOL *This, + IN UINT16 KeyValue, + IN EFI_IFR_DATA_ARRAY *Data, + OUT EFI_HII_CALLBACK_PACKET **Packet + ); + +EFI_STATUS +FormSetDispatcher ( + IN BMM_CALLBACK_DATA *CallbackData + ); + +VOID CreateCallbackPacket ( + OUT EFI_HII_CALLBACK_PACKET **Packet, + IN UINT16 Flags + ); + +// +// Global variable in this program (defined in data.c) +// +extern BM_MENU_OPTION BootOptionMenu; +extern BM_MENU_OPTION DriverOptionMenu; +extern BM_MENU_OPTION FsOptionMenu; +extern BM_MENU_OPTION ConsoleInpMenu; +extern BM_MENU_OPTION ConsoleOutMenu; +extern BM_MENU_OPTION ConsoleErrMenu; +extern BM_MENU_OPTION DirectoryMenu; +extern BM_MENU_OPTION DriverMenu; +extern BM_MENU_OPTION TerminalMenu; +extern BM_MENU_OPTION LegacyFDMenu; +extern BM_MENU_OPTION LegacyHDMenu; +extern BM_MENU_OPTION LegacyCDMenu; +extern BM_MENU_OPTION LegacyNETMenu; +extern BM_MENU_OPTION LegacyBEVMenu; +extern UINT16 TerminalType[]; +extern COM_ATTR BaudRateList[19]; +extern COM_ATTR DataBitsList[4]; +extern COM_ATTR ParityList[5]; +extern COM_ATTR StopBitsList[3]; +extern EFI_GUID Guid[4]; +extern EFI_HII_UPDATE_DATA *UpdateData; +extern STRING_DEPOSITORY *FileOptionStrDepository; +extern STRING_DEPOSITORY *ConsoleOptionStrDepository; +extern STRING_DEPOSITORY *BootOptionStrDepository; +extern STRING_DEPOSITORY *BootOptionHelpStrDepository; +extern STRING_DEPOSITORY *DriverOptionStrDepository; +extern STRING_DEPOSITORY *DriverOptionHelpStrDepository; +extern STRING_DEPOSITORY *TerminalStrDepository; +extern EFI_DEVICE_PATH_PROTOCOL EndDevicePath[]; +extern EFI_GUID EfiLegacyDevOrderGuid; + +#endif diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/BootOption.c b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/BootOption.c new file mode 100644 index 0000000000..35187bf58f --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/BootOption.c @@ -0,0 +1,1657 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + bootoption.c + +Abstract: + + Provide boot option support for Application "BootMaint" + + Include file system navigation, system handle selection + + Boot option manipulation + +Revision History + +--*/ + +#include "bootmaint.h" +#include "BBSsupport.h" + +BM_MENU_ENTRY * +BOpt_CreateMenuEntry ( + UINTN MenuType + ) +/*++ + +Routine Description + Create Menu Entry for future use, make all types together + in order to reduce code size + +Arguments: + MenuType Use this parameter to identify current + Menu type + +Returns: + NULL Cannot allocate memory for current menu + entry + Others A valid pointer pointing to the allocated + memory pool for current menu entry + +--*/ +{ + BM_MENU_ENTRY *MenuEntry; + UINTN ContextSize; + + switch (MenuType) { + case BM_LOAD_CONTEXT_SELECT: + ContextSize = sizeof (BM_LOAD_CONTEXT); + break; + + case BM_FILE_CONTEXT_SELECT: + ContextSize = sizeof (BM_FILE_CONTEXT); + break; + + case BM_CONSOLE_CONTEXT_SELECT: + ContextSize = sizeof (BM_CONSOLE_CONTEXT); + break; + + case BM_TERMINAL_CONTEXT_SELECT: + ContextSize = sizeof (BM_TERMINAL_CONTEXT); + break; + + case BM_HANDLE_CONTEXT_SELECT: + ContextSize = sizeof (BM_HANDLE_CONTEXT); + break; + + case BM_LEGACY_DEV_CONTEXT_SELECT: + ContextSize = sizeof (BM_LEGACY_DEVICE_CONTEXT); + break; + + default: + ContextSize = 0; + break; + + } + + if (0 == ContextSize) { + return NULL; + } + + MenuEntry = AllocateZeroPool (sizeof (BM_MENU_ENTRY)); + if (NULL == MenuEntry) { + return MenuEntry; + } + + MenuEntry->VariableContext = AllocateZeroPool (ContextSize); + if (NULL == MenuEntry->VariableContext) { + SafeFreePool (MenuEntry); + MenuEntry = NULL; + return MenuEntry; + } + + MenuEntry->Signature = BM_MENU_ENTRY_SIGNATURE; + MenuEntry->ContextSelection = MenuType; + return MenuEntry; +} + +VOID +BOpt_DestroyMenuEntry ( + BM_MENU_ENTRY *MenuEntry + ) +/*++ + Routine Description : + Destroy the menu entry passed in + + Arguments : + The menu entry need to be destroyed + + Returns : + None + +--*/ +{ + BM_LOAD_CONTEXT *LoadContext; + BM_FILE_CONTEXT *FileContext; + BM_CONSOLE_CONTEXT *ConsoleContext; + BM_TERMINAL_CONTEXT *TerminalContext; + BM_HANDLE_CONTEXT *HandleContext; + BM_LEGACY_DEVICE_CONTEXT *LegacyDevContext; + + // + // Select by the type in Menu entry for current context type + // + switch (MenuEntry->ContextSelection) { + case BM_LOAD_CONTEXT_SELECT: + LoadContext = (BM_LOAD_CONTEXT *) MenuEntry->VariableContext; + SafeFreePool (LoadContext->FilePathList); + SafeFreePool (LoadContext->LoadOption); + SafeFreePool (LoadContext->OptionalData); + SafeFreePool (LoadContext); + break; + + case BM_FILE_CONTEXT_SELECT: + FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext; + + if (!FileContext->IsRoot) { + SafeFreePool (FileContext->DevicePath); + } else { + if (FileContext->FHandle != NULL) { + FileContext->FHandle->Close (FileContext->FHandle); + } + } + + SafeFreePool (FileContext->FileName); + SafeFreePool (FileContext->Info); + SafeFreePool (FileContext); + break; + + case BM_CONSOLE_CONTEXT_SELECT: + ConsoleContext = (BM_CONSOLE_CONTEXT *) MenuEntry->VariableContext; + SafeFreePool (ConsoleContext->DevicePath); + SafeFreePool (ConsoleContext); + break; + + case BM_TERMINAL_CONTEXT_SELECT: + TerminalContext = (BM_TERMINAL_CONTEXT *) MenuEntry->VariableContext; + SafeFreePool (TerminalContext->DevicePath); + SafeFreePool (TerminalContext); + break; + + case BM_HANDLE_CONTEXT_SELECT: + HandleContext = (BM_HANDLE_CONTEXT *) MenuEntry->VariableContext; + SafeFreePool (HandleContext); + break; + + case BM_LEGACY_DEV_CONTEXT_SELECT: + LegacyDevContext = (BM_LEGACY_DEVICE_CONTEXT *) MenuEntry->VariableContext; + SafeFreePool (LegacyDevContext); + + default: + break; + } + + SafeFreePool (MenuEntry->DisplayString); + if (NULL != MenuEntry->HelpString) { + SafeFreePool (MenuEntry->HelpString); + } + + SafeFreePool (MenuEntry); +} + +BM_MENU_ENTRY * +BOpt_GetMenuEntry ( + BM_MENU_OPTION *MenuOption, + UINTN MenuNumber + ) +/*++ + Rountine Description : + Use this routine to get one particular menu entry in specified + menu + + Arguments : + MenuOption The menu that we will search + + MenuNumber The menunubmer that we want + + Returns : + The desired menu entry + +--*/ +{ + BM_MENU_ENTRY *NewMenuEntry; + UINTN Index; + LIST_ENTRY *List; + + if (MenuNumber >= MenuOption->MenuNumber) { + return NULL; + } + + 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; +} + +EFI_STATUS +BOpt_FindFileSystem ( + IN BMM_CALLBACK_DATA *CallbackData + ) +/*++ + +Routine Description + Find file systems for current Extensible Firmware + Including Handles that support Simple File System + protocol, Load File protocol. + + Building up the FileSystem Menu for user selection + All file system will be stored in FsOptionMenu + for future use. + +Arguments: + CallbackData - BMM context data + +Returns: + EFI_SUCCESS - Success find the file system + EFI_OUT_OF_RESOURCES - Can not create menu entry + +--*/ +{ + UINTN NoSimpleFsHandles; + UINTN NoLoadFileHandles; + EFI_HANDLE *SimpleFsHandle; + EFI_HANDLE *LoadFileHandle; + UINT16 *VolumeLabel; + EFI_BLOCK_IO_PROTOCOL *BlkIo; + UINTN Index; + EFI_STATUS Status; + BM_MENU_ENTRY *MenuEntry; + BM_FILE_CONTEXT *FileContext; + UINT16 *TempStr; + UINTN OptionNumber; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + UINT16 DeviceType; + BBS_BBS_DEVICE_PATH BbsDevicePathNode; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + BOOLEAN RemovableMedia; + + + NoSimpleFsHandles = 0; + NoLoadFileHandles = 0; + OptionNumber = 0; + InitializeListHead (&FsOptionMenu.Head); + + // + // Locate Handles that support Simple File System protocol + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSimpleFileSystemProtocolGuid, + NULL, + &NoSimpleFsHandles, + &SimpleFsHandle + ); + if (!EFI_ERROR (Status)) { + // + // Find all the instances of the File System prototocol + // + for (Index = 0; Index < NoSimpleFsHandles; Index++) { + Status = gBS->HandleProtocol ( + SimpleFsHandle[Index], + &gEfiBlockIoProtocolGuid, + &BlkIo + ); + if (EFI_ERROR (Status)) { + // + // If no block IO exists assume it's NOT a removable media + // + RemovableMedia = FALSE; + } else { + // + // If block IO exists check to see if it's remobable media + // + RemovableMedia = BlkIo->Media->RemovableMedia; + } + + // + // Allocate pool for this load option + // + MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT); + if (NULL == MenuEntry) { + SafeFreePool (SimpleFsHandle); + return EFI_OUT_OF_RESOURCES; + } + + FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext; + + FileContext->Handle = SimpleFsHandle[Index]; + MenuEntry->OptionNumber = Index; + FileContext->FHandle = EfiLibOpenRoot (FileContext->Handle); + if (!FileContext->FHandle) { + BOpt_DestroyMenuEntry (MenuEntry); + continue; + } + + MenuEntry->HelpString = DevicePathToStr (DevicePathFromHandle (FileContext->Handle)); + FileContext->Info = EfiLibFileSystemVolumeLabelInfo (FileContext->FHandle); + FileContext->FileName = EfiStrDuplicate (L"\\"); + FileContext->DevicePath = FileDevicePath ( + FileContext->Handle, + FileContext->FileName + ); + FileContext->IsDir = TRUE; + FileContext->IsRoot = TRUE; + FileContext->IsRemovableMedia = FALSE; + FileContext->IsLoadFile = FALSE; + + // + // Get current file system's Volume Label + // + if (FileContext->Info == NULL) { + VolumeLabel = L"NO FILE SYSTEM INFO"; + } else { + if (FileContext->Info->VolumeLabel == NULL) { + VolumeLabel = L"NULL VOLUME LABEL"; + } else { + VolumeLabel = FileContext->Info->VolumeLabel; + if (*VolumeLabel == 0x0000) { + VolumeLabel = L"NO VOLUME LABEL"; + } + } + } + + TempStr = MenuEntry->HelpString; + MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR); + ASSERT (MenuEntry->DisplayString != NULL); + UnicodeSPrint ( + MenuEntry->DisplayString, + MAX_CHAR, + L"%s, [%s]", + VolumeLabel, + TempStr + ); + OptionNumber++; + InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link); + } + } + + if (NoSimpleFsHandles != 0) { + SafeFreePool (SimpleFsHandle); + } + // + // Searching for handles that support Load File protocol + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiLoadFileProtocolGuid, + NULL, + &NoLoadFileHandles, + &LoadFileHandle + ); + + if (!EFI_ERROR (Status)) { + for (Index = 0; Index < NoLoadFileHandles; Index++) { + MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT); + if (NULL == MenuEntry) { + SafeFreePool (LoadFileHandle); + return EFI_OUT_OF_RESOURCES; + } + + FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext; + FileContext->IsRemovableMedia = FALSE; + FileContext->IsLoadFile = TRUE; + FileContext->Handle = LoadFileHandle[Index]; + FileContext->IsRoot = TRUE; + + FileContext->DevicePath = DevicePathFromHandle (FileContext->Handle); + + MenuEntry->HelpString = DevicePathToStr (FileContext->DevicePath); + + TempStr = MenuEntry->HelpString; + MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR); + ASSERT (MenuEntry->DisplayString != NULL); + UnicodeSPrint ( + MenuEntry->DisplayString, + MAX_CHAR, + L"Load File [%s]", + TempStr + ); + + MenuEntry->OptionNumber = OptionNumber; + OptionNumber++; + InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link); + } + } + + if (NoLoadFileHandles != 0) { + SafeFreePool (LoadFileHandle); + } + + // + // Add Legacy Boot Option Support Here + // + Status = gBS->LocateProtocol ( + &gEfiLegacyBiosProtocolGuid, + NULL, + &LegacyBios + ); + if (!EFI_ERROR (Status)) { + + for (Index = BBS_TYPE_FLOPPY; Index <= BBS_TYPE_EMBEDDED_NETWORK; Index++) { + MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT); + if (NULL == MenuEntry) { + return EFI_OUT_OF_RESOURCES; + } + + FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext; + + FileContext->IsRemovableMedia = FALSE; + FileContext->IsLoadFile = TRUE; + FileContext->IsBootLegacy = TRUE; + DeviceType = (UINT16) Index; + BbsDevicePathNode.Header.Type = BBS_DEVICE_PATH; + BbsDevicePathNode.Header.SubType = BBS_BBS_DP; + SetDevicePathNodeLength ( + &BbsDevicePathNode.Header, + sizeof (BBS_BBS_DEVICE_PATH) + ); + BbsDevicePathNode.DeviceType = DeviceType; + BbsDevicePathNode.StatusFlag = 0; + BbsDevicePathNode.String[0] = 0; + DevicePath = AppendDevicePathNode ( + EndDevicePath, + (EFI_DEVICE_PATH_PROTOCOL *) &BbsDevicePathNode + ); + + FileContext->DevicePath = DevicePath; + MenuEntry->HelpString = DevicePathToStr (FileContext->DevicePath); + + TempStr = MenuEntry->HelpString; + MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR); + ASSERT (MenuEntry->DisplayString != NULL); + UnicodeSPrint ( + MenuEntry->DisplayString, + MAX_CHAR, + L"Boot Legacy [%s]", + TempStr + ); + MenuEntry->OptionNumber = OptionNumber; + OptionNumber++; + InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link); + } + } + // + // Remember how many file system options are here + // + FsOptionMenu.MenuNumber = OptionNumber; + return EFI_SUCCESS; +} + +VOID +BOpt_FreeMenu ( + BM_MENU_OPTION *FreeMenu + ) +/*++ + +Routine Description + Free resources allocated in Allocate Rountine + +Arguments: + FreeMenu Menu to be freed + +Returns: + VOID + +--*/ +{ + 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); + } +} + +EFI_STATUS +BOpt_FindFiles ( + IN BMM_CALLBACK_DATA *CallbackData, + IN BM_MENU_ENTRY *MenuEntry + ) +/*++ + +Routine Description + Find files under current directory + All files and sub-directories in current directory + will be stored in DirectoryMenu for future use. + +Arguments: + FileOption -- Pointer for Dir to explore + +Returns: + TRUE -- Get files from current dir successfully + FALSE -- Can't get files from current dir + +--*/ +{ + EFI_FILE_HANDLE NewDir; + EFI_FILE_HANDLE Dir; + EFI_FILE_INFO *DirInfo; + UINTN BufferSize; + UINTN DirBufferSize; + BM_MENU_ENTRY *NewMenuEntry; + BM_FILE_CONTEXT *FileContext; + BM_FILE_CONTEXT *NewFileContext; + UINTN Pass; + EFI_STATUS Status; + UINTN OptionNumber; + + FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext; + Dir = FileContext->FHandle; + OptionNumber = 0; + // + // Open current directory to get files from it + // + Status = Dir->Open ( + Dir, + &NewDir, + FileContext->FileName, + EFI_FILE_READ_ONLY, + 0 + ); + if (!FileContext->IsRoot) { + Dir->Close (Dir); + } + + if (EFI_ERROR (Status)) { + return Status; + } + + DirInfo = EfiLibFileInfo (NewDir); + if (!DirInfo) { + return EFI_NOT_FOUND; + } + + if (!(DirInfo->Attribute & EFI_FILE_DIRECTORY)) { + return EFI_INVALID_PARAMETER; + } + + FileContext->DevicePath = FileDevicePath ( + FileContext->Handle, + FileContext->FileName + ); + + DirBufferSize = sizeof (EFI_FILE_INFO) + 1024; + DirInfo = AllocateZeroPool (DirBufferSize); + if (!DirInfo) { + return EFI_OUT_OF_RESOURCES; + } + // + // Get all files in current directory + // Pass 1 to get Directories + // Pass 2 to get files that are EFI images + // + for (Pass = 1; Pass <= 2; Pass++) { + NewDir->SetPosition (NewDir, 0); + for (;;) { + BufferSize = DirBufferSize; + Status = NewDir->Read (NewDir, &BufferSize, DirInfo); + if (EFI_ERROR (Status) || BufferSize == 0) { + break; + } + + if ((DirInfo->Attribute & EFI_FILE_DIRECTORY && Pass == 2) || + (!(DirInfo->Attribute & EFI_FILE_DIRECTORY) && Pass == 1) + ) { + // + // Pass 1 is for Directories + // Pass 2 is for file names + // + continue; + } + + if (!(BOpt_IsEfiImageName (DirInfo->FileName) || DirInfo->Attribute & EFI_FILE_DIRECTORY)) { + // + // Slip file unless it is a directory entry or a .EFI file + // + continue; + } + + NewMenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT); + if (NULL == NewMenuEntry) { + return EFI_OUT_OF_RESOURCES; + } + + NewFileContext = (BM_FILE_CONTEXT *) NewMenuEntry->VariableContext; + NewFileContext->Handle = FileContext->Handle; + NewFileContext->FileName = BOpt_AppendFileName ( + FileContext->FileName, + DirInfo->FileName + ); + NewFileContext->FHandle = NewDir; + NewFileContext->DevicePath = FileDevicePath ( + NewFileContext->Handle, + NewFileContext->FileName + ); + NewMenuEntry->HelpString = NULL; + + MenuEntry->DisplayStringToken = GetStringTokenFromDepository ( + CallbackData, + FileOptionStrDepository + ); + + NewFileContext->IsDir = (BOOLEAN) ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY); + + if (NewFileContext->IsDir) { + BufferSize = StrLen (DirInfo->FileName) * 2 + 6; + NewMenuEntry->DisplayString = AllocateZeroPool (BufferSize); + + UnicodeSPrint ( + NewMenuEntry->DisplayString, + BufferSize, + L"<%s>", + DirInfo->FileName + ); + + } else { + NewMenuEntry->DisplayString = EfiStrDuplicate (DirInfo->FileName); + } + + NewFileContext->IsRoot = FALSE; + NewFileContext->IsLoadFile = FALSE; + NewFileContext->IsRemovableMedia = FALSE; + + NewMenuEntry->OptionNumber = OptionNumber; + OptionNumber++; + InsertTailList (&DirectoryMenu.Head, &NewMenuEntry->Link); + } + } + + DirectoryMenu.MenuNumber = OptionNumber; + SafeFreePool (DirInfo); + return TRUE; +} + +EFI_STATUS +BOpt_GetLegacyOptions ( + VOID + ) +/*++ +Routine Description: + + Build the LegacyFDMenu LegacyHDMenu LegacyCDMenu according to LegacyBios.GetBbsInfo(). + +Arguments: + None + +Returns: + The device info of legacy device. + +--*/ +{ + BM_MENU_ENTRY *NewMenuEntry; + BM_LEGACY_DEVICE_CONTEXT *NewLegacyDevContext; + EFI_STATUS Status; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + UINT16 HddCount; + HDD_INFO *HddInfo; + UINT16 BbsCount; + BBS_TABLE *BbsTable; + UINTN Index; + CHAR16 DescString[100]; + UINTN FDNum; + UINTN HDNum; + UINTN CDNum; + UINTN NETNum; + UINTN BEVNum; + + NewMenuEntry = NULL; + HddInfo = NULL; + BbsTable = NULL; + BbsCount = 0; + + // + // Initialize Bbs Table Context from BBS info data + // + InitializeListHead (&LegacyFDMenu.Head); + InitializeListHead (&LegacyHDMenu.Head); + InitializeListHead (&LegacyCDMenu.Head); + InitializeListHead (&LegacyNETMenu.Head); + InitializeListHead (&LegacyBEVMenu.Head); + + Status = gBS->LocateProtocol ( + &gEfiLegacyBiosProtocolGuid, + NULL, + &LegacyBios + ); + if (!EFI_ERROR (Status)) { + Status = LegacyBios->GetBbsInfo ( + LegacyBios, + &HddCount, + &HddInfo, + &BbsCount, + &BbsTable + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + + FDNum = 0; + HDNum = 0; + CDNum = 0; + NETNum = 0; + BEVNum = 0; + + for (Index = 0; Index < BbsCount; Index++) { + if ((BBS_IGNORE_ENTRY == BbsTable[Index].BootPriority) || + (BBS_DO_NOT_BOOT_FROM == BbsTable[Index].BootPriority) || + (BBS_LOWEST_PRIORITY == BbsTable[Index].BootPriority) + ) { + continue; + } + + NewMenuEntry = BOpt_CreateMenuEntry (BM_LEGACY_DEV_CONTEXT_SELECT); + if (NULL == NewMenuEntry) { + break; + } + + NewLegacyDevContext = (BM_LEGACY_DEVICE_CONTEXT *) NewMenuEntry->VariableContext; + NewLegacyDevContext->BbsTable = &BbsTable[Index]; + NewLegacyDevContext->Index = Index; + NewLegacyDevContext->BbsCount = BbsCount; + BdsBuildLegacyDevNameString ( + &BbsTable[Index], + Index, + sizeof (DescString), + DescString + ); + NewLegacyDevContext->Description = AllocateZeroPool (StrSize (DescString)); + if (NULL == NewLegacyDevContext->Description) { + break; + } + + CopyMem (NewLegacyDevContext->Description, DescString, StrSize (DescString)); + NewMenuEntry->DisplayString = NewLegacyDevContext->Description; + NewMenuEntry->HelpString = NULL; + + switch (BbsTable[Index].DeviceType) { + case BBS_FLOPPY: + InsertTailList (&LegacyFDMenu.Head, &NewMenuEntry->Link); + FDNum++; + break; + + case BBS_HARDDISK: + InsertTailList (&LegacyHDMenu.Head, &NewMenuEntry->Link); + HDNum++; + break; + + case BBS_CDROM: + InsertTailList (&LegacyCDMenu.Head, &NewMenuEntry->Link); + CDNum++; + break; + + case BBS_EMBED_NETWORK: + InsertTailList (&LegacyNETMenu.Head, &NewMenuEntry->Link); + NETNum++; + break; + + case BBS_BEV_DEVICE: + InsertTailList (&LegacyBEVMenu.Head, &NewMenuEntry->Link); + BEVNum++; + break; + } + } + + if (Index != BbsCount) { + BOpt_FreeLegacyOptions (); + return EFI_OUT_OF_RESOURCES; + } + + LegacyFDMenu.MenuNumber = FDNum; + LegacyHDMenu.MenuNumber = HDNum; + LegacyCDMenu.MenuNumber = CDNum; + LegacyNETMenu.MenuNumber = NETNum; + LegacyBEVMenu.MenuNumber = BEVNum; + return EFI_SUCCESS; +} + +VOID +BOpt_FreeLegacyOptions ( + VOID + ) +{ + BOpt_FreeMenu (&LegacyFDMenu); + BOpt_FreeMenu (&LegacyHDMenu); + BOpt_FreeMenu (&LegacyCDMenu); + BOpt_FreeMenu (&LegacyNETMenu); + BOpt_FreeMenu (&LegacyBEVMenu); +} + +EFI_STATUS +BOpt_GetBootOptions ( + IN BMM_CALLBACK_DATA *CallbackData + ) +/*++ + +Routine Description: + + Build the BootOptionMenu according to BootOrder Variable. + This Routine will access the Boot#### to get EFI_LOAD_OPTION + +Arguments: + None + +Returns: + The number of the Var Boot#### + +--*/ +{ + UINTN Index; + UINT16 BootString[10]; + UINT8 *LoadOptionFromVar; + UINT8 *LoadOption; + UINTN BootOptionSize; + BOOLEAN BootNextFlag; + UINT16 *BootOrderList; + UINTN BootOrderListSize; + UINT16 *BootNext; + UINTN BootNextSize; + BM_MENU_ENTRY *NewMenuEntry; + BM_LOAD_CONTEXT *NewLoadContext; + UINT8 *LoadOptionPtr; + UINTN StringSize; + UINTN OptionalDataSize; + UINT8 *LoadOptionEnd; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + UINTN MenuCount; + UINT8 *Ptr; + + MenuCount = 0; + BootOrderListSize = 0; + BootNextSize = 0; + BootOrderList = NULL; + BootNext = NULL; + LoadOptionFromVar = NULL; + BOpt_FreeMenu (&BootOptionMenu); + InitializeListHead (&BootOptionMenu.Head); + + // + // Get the BootOrder from the Var + // + BootOrderList = BdsLibGetVariableAndSize ( + L"BootOrder", + &gEfiGlobalVariableGuid, + &BootOrderListSize + ); + + // + // Get the BootNext from the Var + // + BootNext = BdsLibGetVariableAndSize ( + L"BootNext", + &gEfiGlobalVariableGuid, + &BootNextSize + ); + + if (BootNext) { + if (BootNextSize != sizeof (UINT16)) { + SafeFreePool (BootNext); + BootNext = NULL; + } + } + + for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) { + UnicodeSPrint (BootString, sizeof (BootString), L"Boot%04x", BootOrderList[Index]); + // + // Get all loadoptions from the VAR + // + LoadOptionFromVar = BdsLibGetVariableAndSize ( + BootString, + &gEfiGlobalVariableGuid, + &BootOptionSize + ); + if (!LoadOptionFromVar) { + continue; + } + + LoadOption = AllocateZeroPool (BootOptionSize); + if (!LoadOption) { + continue; + } + + CopyMem (LoadOption, LoadOptionFromVar, BootOptionSize); + SafeFreePool (LoadOptionFromVar); + + if (BootNext) { + BootNextFlag = (BOOLEAN) (*BootNext == BootOrderList[Index]); + } else { + BootNextFlag = FALSE; + } + + if (0 == (*((UINT32 *) LoadOption) & LOAD_OPTION_ACTIVE)) { + SafeFreePool (LoadOption); + continue; + } + // + // BUGBUG: could not return EFI_OUT_OF_RESOURCES here directly. + // the buffer allocated already should be freed before returning. + // + NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT); + if (NULL == NewMenuEntry) { + return EFI_OUT_OF_RESOURCES; + } + + NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext; + + LoadOptionPtr = LoadOption; + LoadOptionEnd = LoadOption + BootOptionSize; + + NewMenuEntry->OptionNumber = BootOrderList[Index]; + NewLoadContext->LoadOptionModified = FALSE; + NewLoadContext->Deleted = FALSE; + NewLoadContext->IsBootNext = BootNextFlag; + + // + // Is a Legacy Device? + // + Ptr = (UINT8 *) LoadOption; + + // + // Attribute = *(UINT32 *)Ptr; + // + Ptr += sizeof (UINT32); + + // + // FilePathSize = *(UINT16 *)Ptr; + // + Ptr += sizeof (UINT16); + + // + // Description = (CHAR16 *)Ptr; + // + Ptr += StrSize ((CHAR16 *) Ptr); + + // + // Now Ptr point to Device Path + // + DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr; + if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) { + NewLoadContext->IsLegacy = TRUE; + } else { + NewLoadContext->IsLegacy = FALSE; + } + // + // LoadOption is a pointer type of UINT8 + // for easy use with following LOAD_OPTION + // embedded in this struct + // + NewLoadContext->LoadOption = LoadOption; + NewLoadContext->LoadOptionSize = BootOptionSize; + + NewLoadContext->Attributes = *(UINT32 *) LoadOptionPtr; + NewLoadContext->IsActive = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_ACTIVE); + + NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT); + + LoadOptionPtr += sizeof (UINT32); + + NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr; + LoadOptionPtr += sizeof (UINT16); + + StringSize = StrSize ((UINT16 *) LoadOptionPtr); + NewLoadContext->Description = AllocateZeroPool (StringSize); + ASSERT (NewLoadContext->Description != NULL); + CopyMem ( + NewLoadContext->Description, + (UINT16 *) LoadOptionPtr, + StringSize + ); + NewMenuEntry->DisplayString = NewLoadContext->Description; + + LoadOptionPtr += StringSize; + + NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength); + ASSERT (NewLoadContext->FilePathList != NULL); + CopyMem ( + NewLoadContext->FilePathList, + (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr, + NewLoadContext->FilePathListLength + ); + + NewMenuEntry->HelpString = DevicePathToStr (NewLoadContext->FilePathList); + NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository ( + CallbackData, + BootOptionStrDepository + ); + NewMenuEntry->HelpStringToken = GetStringTokenFromDepository ( + CallbackData, + BootOptionHelpStrDepository + ); + LoadOptionPtr += NewLoadContext->FilePathListLength; + + if (LoadOptionPtr < LoadOptionEnd) { + OptionalDataSize = BootOptionSize - + sizeof (UINT32) - + sizeof (UINT16) - + StringSize - + NewLoadContext->FilePathListLength; + + NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize); + ASSERT (NewLoadContext->OptionalData != NULL); + CopyMem ( + NewLoadContext->OptionalData, + LoadOptionPtr, + OptionalDataSize + ); + + NewLoadContext->OptionalDataSize = OptionalDataSize; + } + + InsertTailList (&BootOptionMenu.Head, &NewMenuEntry->Link); + MenuCount++; + } + + SafeFreePool (BootNext); + SafeFreePool (BootOrderList); + BootOptionMenu.MenuNumber = MenuCount; + return MenuCount; +} + +CHAR16 * +BOpt_AppendFileName ( + IN CHAR16 *Str1, + IN CHAR16 *Str2 + ) +/*++ + +Routine Description + Append file name to existing file name. + +Arguments: + Str1 - existing file name + Str2 - file name to be appended + +Returns: + Allocate a new string to hold the appended result. + Caller is responsible to free the returned string. + +--*/ +{ + UINTN Size1; + UINTN Size2; + CHAR16 *Str; + CHAR16 *Ptr; + CHAR16 *LastSlash; + + Size1 = StrSize (Str1); + Size2 = StrSize (Str2); + Str = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16)); + ASSERT (Str != NULL); + + StrCat (Str, Str1); + if (!((*Str == '\\') && (*(Str + 1) == 0))) { + StrCat (Str, L"\\"); + } + + StrCat (Str, Str2); + + Ptr = Str; + LastSlash = Str; + while (*Ptr != 0) { + if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '.' && *(Ptr + 3) != 0) { + // + // Convert \Name\..\ to \ + // DO NOT convert the .. if it is at the end of the string. This will + // break the .. behavior in changing directories. + // + StrCpy (LastSlash, Ptr + 3); + Ptr = LastSlash; + } else if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '\\') { + // + // Convert a \.\ to a \ + // + StrCpy (Ptr, Ptr + 2); + Ptr = LastSlash; + } else if (*Ptr == '\\') { + LastSlash = Ptr; + } + + Ptr++; + } + + return Str; +} + +BOOLEAN +BOpt_IsEfiImageName ( + IN UINT16 *FileName + ) +/*++ + +Routine Description + Check whether current FileName point to a valid + Efi Image File. + +Arguments: + FileName - File need to be checked. + +Returns: + TRUE - Is Efi Image + FALSE - Not a valid Efi Image + +--*/ +{ + // + // Search for ".efi" extension + // + while (*FileName) { + if (FileName[0] == '.') { + if (FileName[1] == 'e' || FileName[1] == 'E') { + if (FileName[2] == 'f' || FileName[2] == 'F') { + if (FileName[3] == 'i' || FileName[3] == 'I') { + return TRUE; + } else if (FileName[3] == 0x0000) { + return FALSE; + } + } else if (FileName[2] == 0x0000) { + return FALSE; + } + } else if (FileName[1] == 0x0000) { + return FALSE; + } + } + + FileName += 1; + } + + return FALSE; +} + +BOOLEAN +BOpt_IsEfiApp ( + IN EFI_FILE_HANDLE Dir, + IN UINT16 *FileName + ) +/*++ + +Routine Description: + Check whether current FileName point to a valid Efi Application + +Arguments: + Dir - Pointer to current Directory + FileName - Pointer to current File name. + +Returns: + TRUE - Is a valid Efi Application + FALSE - not a valid Efi Application + +--*/ +{ + UINTN BufferSize; + EFI_IMAGE_DOS_HEADER DosHdr; + EFI_IMAGE_NT_HEADERS PeHdr; + EFI_IMAGE_OPTIONAL_HEADER32 *PeOpt32; + EFI_IMAGE_OPTIONAL_HEADER64 *PeOpt64; + UINT16 Subsystem; + EFI_FILE_HANDLE File; + EFI_STATUS Status; + + Status = Dir->Open (Dir, &File, FileName, EFI_FILE_MODE_READ, 0); + + if (EFI_ERROR (Status)) { + return FALSE; + } + + BufferSize = sizeof (EFI_IMAGE_DOS_HEADER); + File->Read (File, &BufferSize, &DosHdr); + if (DosHdr.e_magic != EFI_IMAGE_DOS_SIGNATURE) { + File->Close (File); + return FALSE; + } + + File->SetPosition (File, DosHdr.e_lfanew); + BufferSize = sizeof (EFI_IMAGE_NT_HEADERS); + File->Read (File, &BufferSize, &PeHdr); + if (PeHdr.Signature != EFI_IMAGE_NT_SIGNATURE) { + File->Close (File); + return FALSE; + } + // + // Determine PE type and read subsytem + // BugBug : We should be using EFI_IMAGE_MACHINE_TYPE_SUPPORTED (machine) + // macro to detect the machine type. + // We should not be using EFI_IMAGE_OPTIONAL_HEADER32 and + // EFI_IMAGE_OPTIONAL_HEADER64 + // + if (PeHdr.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + PeOpt32 = (EFI_IMAGE_OPTIONAL_HEADER32 *) &(PeHdr.OptionalHeader); + Subsystem = PeOpt32->Subsystem; + } else if (PeHdr.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + PeOpt64 = (EFI_IMAGE_OPTIONAL_HEADER64 *) &(PeHdr.OptionalHeader); + Subsystem = PeOpt64->Subsystem; + } else { + return FALSE; + } + + if (Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) { + File->Close (File); + return TRUE; + } else { + File->Close (File); + return FALSE; + } +} + +EFI_STATUS +BOpt_FindDrivers ( + VOID + ) +/*++ + +Routine Description + 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. + +Arguments: + None + +Returns: + EFI_SUCCESS + Others + +--*/ +{ + 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]; + + // + // Check whether this handle support + // driver binding + // + Status = gBS->HandleProtocol ( + CurHandle, + &gEfiSimpleFileSystemProtocolGuid, + &SimpleFs + ); + if (Status == EFI_SUCCESS) { + continue; + } + + Status = gBS->HandleProtocol ( + CurHandle, + &gEfiLoadFileProtocolGuid, + &LoadFile + ); + if (Status == EFI_SUCCESS) { + continue; + } + + NewMenuEntry = BOpt_CreateMenuEntry (BM_HANDLE_CONTEXT_SELECT); + if (NULL == NewMenuEntry) { + return EFI_OUT_OF_RESOURCES; + } + + NewHandleContext = (BM_HANDLE_CONTEXT *) NewMenuEntry->VariableContext; + NewHandleContext->Handle = CurHandle; + NewHandleContext->DevicePath = DevicePathFromHandle (CurHandle); + NewMenuEntry->DisplayString = DevicePathToStr (NewHandleContext->DevicePath); + NewMenuEntry->HelpString = NULL; + NewMenuEntry->OptionNumber = OptionNumber; + OptionNumber++; + InsertTailList (&DriverMenu.Head, &NewMenuEntry->Link); + + } + + DriverMenu.MenuNumber = OptionNumber; + return EFI_SUCCESS; +} + +UINT16 +BOpt_GetBootOptionNumber ( + VOID + ) +/*++ + +Routine Description: + Get the Option Number that does not used + +Arguments: + +Returns: + The Option Number + +--*/ +{ + BM_MENU_ENTRY *NewMenuEntry; + UINT16 *BootOrderList; + UINTN BootOrderListSize; + UINT16 Number; + UINTN Index; + UINTN Index2; + BOOLEAN Found; + + BootOrderListSize = 0; + BootOrderList = NULL; + + BootOrderList = BdsLibGetVariableAndSize ( + L"BootOrder", + &gEfiGlobalVariableGuid, + &BootOrderListSize + ); + if (BootOrderList) { + // + // already have Boot#### + // + // AlreadyBootNumbers = BootOrderListSize / sizeof(UINT16); + // + for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) { + Found = TRUE; + for (Index2 = 0; Index2 < BootOptionMenu.MenuNumber; Index2++) { + NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index2); + if (Index == NewMenuEntry->OptionNumber) { + Found = FALSE; + break; + } + } + + if (Found) { + break; + } + } + // + // end for Index + // + Number = (UINT16) Index; + } else { + // + // No Boot#### + // + Number = 0; + } + + return Number; +} + +UINT16 +BOpt_GetDriverOptionNumber ( + VOID + ) +/*++ + +Routine Description: + Get the Option Number that does not used + +Arguments: + +Returns: + The Option Number + +--*/ +{ + BM_MENU_ENTRY *NewMenuEntry; + UINT16 *DriverOrderList; + UINTN DriverOrderListSize; + UINT16 Number; + UINTN Index; + UINTN Index2; + BOOLEAN Found; + + DriverOrderListSize = 0; + DriverOrderList = NULL; + + DriverOrderList = BdsLibGetVariableAndSize ( + L"DriverOrder", + &gEfiGlobalVariableGuid, + &DriverOrderListSize + ); + if (DriverOrderList) { + // + // already have Driver#### + // + // AlreadyDriverNumbers = DriverOrderListSize / sizeof(UINT16); + // + for (Index = 0; Index < DriverOrderListSize / sizeof (UINT16); Index++) { + Found = TRUE; + for (Index2 = 0; Index2 < DriverOptionMenu.MenuNumber; Index2++) { + NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, Index2); + if (Index == NewMenuEntry->OptionNumber) { + Found = FALSE; + break; + } + } + + if (Found) { + break; + } + } + // + // end for Index + // + Number = (UINT16) Index; + } else { + // + // No Driver#### + // + Number = 0; + } + + return Number; +} + +EFI_STATUS +BOpt_GetDriverOptions ( + IN BMM_CALLBACK_DATA *CallbackData + ) +/*++ + +Routine Description: + Build up all DriverOptionMenu + +Arguments: + +Returns: + The Option Number + +--*/ +{ + UINTN Index; + UINT16 DriverString[12]; + UINT8 *LoadOptionFromVar; + UINT8 *LoadOption; + UINTN DriverOptionSize; + + UINT16 *DriverOrderList; + UINTN DriverOrderListSize; + BM_MENU_ENTRY *NewMenuEntry; + BM_LOAD_CONTEXT *NewLoadContext; + UINT8 *LoadOptionPtr; + UINTN StringSize; + UINTN OptionalDataSize; + UINT8 *LoadOptionEnd; + + DriverOrderListSize = 0; + DriverOrderList = NULL; + DriverOptionSize = 0; + LoadOptionFromVar = NULL; + BOpt_FreeMenu (&DriverOptionMenu); + InitializeListHead (&DriverOptionMenu.Head); + // + // Get the DriverOrder from the Var + // + DriverOrderList = BdsLibGetVariableAndSize ( + L"DriverOrder", + &gEfiGlobalVariableGuid, + &DriverOrderListSize + ); + + for (Index = 0; Index < DriverOrderListSize / sizeof (UINT16); Index++) { + UnicodeSPrint ( + DriverString, + sizeof (DriverString), + L"Driver%04x", + DriverOrderList[Index] + ); + // + // Get all loadoptions from the VAR + // + LoadOptionFromVar = BdsLibGetVariableAndSize ( + DriverString, + &gEfiGlobalVariableGuid, + &DriverOptionSize + ); + if (!LoadOptionFromVar) { + continue; + } + + LoadOption = AllocateZeroPool (DriverOptionSize); + if (!LoadOption) { + continue; + } + + CopyMem (LoadOption, LoadOptionFromVar, DriverOptionSize); + SafeFreePool (LoadOptionFromVar); + + NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT); + if (NULL == NewMenuEntry) { + return EFI_OUT_OF_RESOURCES; + } + + NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext; + LoadOptionPtr = LoadOption; + LoadOptionEnd = LoadOption + DriverOptionSize; + NewMenuEntry->OptionNumber = DriverOrderList[Index]; + NewLoadContext->LoadOptionModified = FALSE; + NewLoadContext->Deleted = FALSE; + NewLoadContext->IsLegacy = FALSE; + + // + // LoadOption is a pointer type of UINT8 + // for easy use with following LOAD_OPTION + // embedded in this struct + // + NewLoadContext->LoadOption = LoadOption; + NewLoadContext->LoadOptionSize = DriverOptionSize; + + NewLoadContext->Attributes = *(UINT32 *) LoadOptionPtr; + NewLoadContext->IsActive = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_ACTIVE); + + NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT); + + LoadOptionPtr += sizeof (UINT32); + + NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr; + LoadOptionPtr += sizeof (UINT16); + + StringSize = StrSize ((UINT16 *) LoadOptionPtr); + NewLoadContext->Description = AllocateZeroPool (StringSize); + ASSERT (NewLoadContext->Description != NULL); + CopyMem ( + NewLoadContext->Description, + (UINT16 *) LoadOptionPtr, + StringSize + ); + NewMenuEntry->DisplayString = NewLoadContext->Description; + + LoadOptionPtr += StringSize; + + NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength); + ASSERT (NewLoadContext->FilePathList != NULL); + CopyMem ( + NewLoadContext->FilePathList, + (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr, + NewLoadContext->FilePathListLength + ); + + NewMenuEntry->HelpString = DevicePathToStr (NewLoadContext->FilePathList); + NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository ( + CallbackData, + DriverOptionStrDepository + ); + NewMenuEntry->HelpStringToken = GetStringTokenFromDepository ( + CallbackData, + DriverOptionHelpStrDepository + ); + LoadOptionPtr += NewLoadContext->FilePathListLength; + + if (LoadOptionPtr < LoadOptionEnd) { + OptionalDataSize = DriverOptionSize - + sizeof (UINT32) - + sizeof (UINT16) - + StringSize - + NewLoadContext->FilePathListLength; + + NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize); + ASSERT (NewLoadContext->OptionalData != NULL); + CopyMem ( + NewLoadContext->OptionalData, + LoadOptionPtr, + OptionalDataSize + ); + + NewLoadContext->OptionalDataSize = OptionalDataSize; + } + + InsertTailList (&DriverOptionMenu.Head, &NewMenuEntry->Link); + + } + + SafeFreePool (DriverOrderList); + DriverOptionMenu.MenuNumber = Index; + return EFI_SUCCESS; + +} + +VOID +SafeFreePool ( + IN VOID *Buffer + ) +/*++ + +Routine Description: + Wrap original FreePool gBS call + in order to decrease code length + +Arguments: + +Returns: + +--*/ +{ + if (Buffer != NULL) { + gBS->FreePool (Buffer); + Buffer = NULL; + } +} diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/ConsoleOption.c b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/ConsoleOption.c new file mode 100644 index 0000000000..9deb5fa912 --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/ConsoleOption.c @@ -0,0 +1,840 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + consoleoption.c + +Abstract: + + handles console redirection from boot manager + + +Revision History + +--*/ + +#include "bootmaint.h" + +EFI_DEVICE_PATH_PROTOCOL * +DevicePathInstanceDup ( + IN EFI_DEVICE_PATH_PROTOCOL *DevPath + ); + +EFI_STATUS +UpdateComAttributeFromVariable ( + EFI_DEVICE_PATH_PROTOCOL *DevicePath + ); + +EFI_STATUS +ChangeTerminalDevicePath ( + EFI_DEVICE_PATH_PROTOCOL *DevicePath, + 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; + UINT32 Match; + BM_TERMINAL_CONTEXT *NewTerminalContext; + BM_MENU_ENTRY *NewMenuEntry; + + Match = EISA_PNP_ID (0x0501); + Node = DevicePath; + Node = NextDevicePathNode (Node); + Com = 0; + while (!IsDevicePathEnd (Node)) { + if ((DevicePathType (Node) == ACPI_DEVICE_PATH) && (DevicePathSubType (Node) == ACPI_DP)) { + Acpi = (ACPI_HID_DEVICE_PATH *) Node; + if (CompareMem (&Acpi->HID, &Match, sizeof (UINT32)) == 0) { + CopyMem (&Com, &Acpi->UID, sizeof (UINT32)); + } + } + + NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Com); + if (NULL == NewMenuEntry) { + return EFI_NOT_FOUND; + } + + 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; + +} + +VOID +ChangeVariableDevicePath ( + EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + EFI_DEVICE_PATH_PROTOCOL *Node; + ACPI_HID_DEVICE_PATH *Acpi; + UART_DEVICE_PATH *Uart; + UINTN Com; + UINT32 Match; + BM_TERMINAL_CONTEXT *NewTerminalContext; + BM_MENU_ENTRY *NewMenuEntry; + + Match = EISA_PNP_ID (0x0501); + Node = DevicePath; + Node = NextDevicePathNode (Node); + Com = 0; + while (!IsDevicePathEnd (Node)) { + if ((DevicePathType (Node) == ACPI_DEVICE_PATH) && (DevicePathSubType (Node) == ACPI_DP)) { + Acpi = (ACPI_HID_DEVICE_PATH *) Node; + if (CompareMem (&Acpi->HID, &Match, sizeof (UINT32)) == 0) { + CopyMem (&Com, &Acpi->UID, sizeof (UINT32)); + } + } + + if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) { + NewMenuEntry = BOpt_GetMenuEntry ( + &TerminalMenu, + Com + ); + 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); + } + + return ; +} + +BOOLEAN +IsTerminalDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + OUT TYPE_OF_TERMINAL *Termi, + OUT UINTN *Com + ); + +EFI_STATUS +LocateSerialIo ( + VOID + ) +/*++ + +Routine Description: + Build a list containing all serial devices + +Arguments: + +Returns: + +--*/ +{ + UINT8 *Ptr; + UINTN Index; + UINTN Index2; + UINTN NoHandles; + EFI_HANDLE *Handles; + EFI_STATUS Status; + ACPI_HID_DEVICE_PATH *Acpi; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + UINT32 Match; + EFI_SERIAL_IO_PROTOCOL *SerialIo; + 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; + } + + for (Index = 0; Index < NoHandles; Index++) { + // + // Check to see whether the handle has DevicePath Protocol installed + // + gBS->HandleProtocol ( + Handles[Index], + &gEfiDevicePathProtocolGuid, + &DevicePath + ); + Ptr = (UINT8 *) DevicePath; + while (*Ptr != END_DEVICE_PATH_TYPE) { + Ptr++; + } + + Ptr = Ptr - sizeof (UART_DEVICE_PATH) - sizeof (ACPI_HID_DEVICE_PATH); + Acpi = (ACPI_HID_DEVICE_PATH *) Ptr; + Match = EISA_PNP_ID (0x0501); + + if (CompareMem (&Acpi->HID, &Match, sizeof (UINT32)) == 0) { + NewMenuEntry = BOpt_CreateMenuEntry (BM_TERMINAL_CONTEXT_SELECT); + if (!NewMenuEntry) { + return EFI_OUT_OF_RESOURCES; + } + + NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext; + CopyMem (&NewMenuEntry->OptionNumber, &Acpi->UID, sizeof (UINT32)); + NewTerminalContext->DevicePath = DevicePathInstanceDup (DevicePath); + // + // BugBug: I have no choice, calling EfiLibStrFromDatahub will hang the system! + // coz' the misc data for each platform is not correct, actually it's the device path stored in + // datahub which is not completed, so a searching for end of device path will enter a + // dead-loop. + // + NewMenuEntry->DisplayString = EfiLibStrFromDatahub (DevicePath); + if (NULL == NewMenuEntry->DisplayString) { + NewMenuEntry->DisplayString = DevicePathToStr (DevicePath); + } + + NewMenuEntry->HelpString = NULL; + + gBS->HandleProtocol ( + Handles[Index], + &gEfiSerialIoProtocolGuid, + &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++; + } + } + // + // Get L"ConOut", L"ConIn" and L"ErrOut" from the Var + // + OutDevicePath = EfiLibGetVariable (L"ConOut", &gEfiGlobalVariableGuid); + InpDevicePath = EfiLibGetVariable (L"ConIn", &gEfiGlobalVariableGuid); + ErrDevicePath = EfiLibGetVariable (L"ErrOut", &gEfiGlobalVariableGuid); + if (OutDevicePath) { + UpdateComAttributeFromVariable (OutDevicePath); + } + + if (InpDevicePath) { + UpdateComAttributeFromVariable (InpDevicePath); + } + + if (ErrDevicePath) { + UpdateComAttributeFromVariable (ErrDevicePath); + } + + for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) { + NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index); + if (NULL == NewMenuEntry) { + return EFI_NOT_FOUND; + } + + NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext; + + NewTerminalContext->TerminalType = 0; + NewTerminalContext->IsConIn = FALSE; + NewTerminalContext->IsConOut = FALSE; + NewTerminalContext->IsStdErr = FALSE; + + Vendor.Header.Type = MESSAGING_DEVICE_PATH; + Vendor.Header.SubType = MSG_VENDOR_DP; + + for (Index2 = 0; Index2 < 4; Index2++) { + CopyMem (&Vendor.Guid, &Guid[Index2], sizeof (EFI_GUID)); + SetDevicePathNodeLength (&Vendor.Header, sizeof (VENDOR_DEVICE_PATH)); + NewDevicePath = AppendDevicePathNode ( + NewTerminalContext->DevicePath, + (EFI_DEVICE_PATH_PROTOCOL *) &Vendor + ); + SafeFreePool (NewMenuEntry->HelpString); + // + // NewMenuEntry->HelpString = DevicePathToStr (NewDevicePath); + // NewMenuEntry->DisplayString = NewMenuEntry->HelpString; + // + NewMenuEntry->HelpString = NULL; + + if (BdsLibMatchDevicePaths (OutDevicePath, NewDevicePath)) { + NewTerminalContext->IsConOut = TRUE; + NewTerminalContext->TerminalType = (UINT8) Index2; + } + + if (BdsLibMatchDevicePaths (InpDevicePath, NewDevicePath)) { + NewTerminalContext->IsConIn = TRUE; + NewTerminalContext->TerminalType = (UINT8) Index2; + } + + if (BdsLibMatchDevicePaths (ErrDevicePath, NewDevicePath)) { + NewTerminalContext->IsStdErr = TRUE; + NewTerminalContext->TerminalType = (UINT8) Index2; + } + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +UpdateComAttributeFromVariable ( + EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +/*++ + +Routine Description: + Update Com Ports attributes from DevicePath + +Arguments: + DevicePath - DevicePath that contains Com ports + +Returns: + +--*/ +{ + EFI_DEVICE_PATH_PROTOCOL *Node; + EFI_DEVICE_PATH_PROTOCOL *SerialNode; + ACPI_HID_DEVICE_PATH *Acpi; + UART_DEVICE_PATH *Uart; + UART_DEVICE_PATH *Uart1; + UINT32 Match; + UINTN TerminalNumber; + BM_MENU_ENTRY *NewMenuEntry; + BM_TERMINAL_CONTEXT *NewTerminalContext; + UINTN Index; + + Match = EISA_PNP_ID (0x0501); + Node = DevicePath; + Node = NextDevicePathNode (Node); + TerminalNumber = 0; + for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) { + while (!IsDevicePathEnd (Node)) { + if ((DevicePathType (Node) == ACPI_DEVICE_PATH) && (DevicePathSubType (Node) == ACPI_DP)) { + Acpi = (ACPI_HID_DEVICE_PATH *) Node; + if (CompareMem (&Acpi->HID, &Match, sizeof (UINT32)) == 0) { + 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; +} + +EFI_DEVICE_PATH_PROTOCOL * +DevicePathInstanceDup ( + IN EFI_DEVICE_PATH_PROTOCOL *DevPath + ) +/*++ + +Routine Description: + Function creates a device path data structure that identically matches the + device path passed in. + +Arguments: + DevPath - A pointer to a device path data structure. + +Returns: + + The new copy of DevPath is created to identically match the input. + Otherwise, NULL is returned. + +--*/ +{ + EFI_DEVICE_PATH_PROTOCOL *NewDevPath; + EFI_DEVICE_PATH_PROTOCOL *DevicePathInst; + EFI_DEVICE_PATH_PROTOCOL *Temp; + UINT8 *Ptr; + UINTN Size; + + // + // get the size of an instance from the input + // + Temp = DevPath; + DevicePathInst = GetNextDevicePathInstance (&Temp, &Size); + + // + // Make a copy and set proper end type + // + NewDevPath = NULL; + if (Size) { + NewDevPath = AllocateZeroPool (Size); + ASSERT (NewDevPath != NULL); + } + + if (NewDevPath) { + CopyMem (NewDevPath, DevicePathInst, Size); + Ptr = (UINT8 *) NewDevPath; + Ptr += Size - sizeof (EFI_DEVICE_PATH_PROTOCOL); + Temp = (EFI_DEVICE_PATH_PROTOCOL *) Ptr; + SetDevicePathEndNode (Temp); + } + + return NewDevPath; +} + +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; + BM_TERMINAL_CONTEXT *NewTerminalContext; + TYPE_OF_TERMINAL Terminal; + BM_MENU_ENTRY *NewTerminalMenuEntry; + UINTN Com; + BM_MENU_OPTION *ConsoleMenu; + + DevicePath = NULL; + AllDevicePath = NULL; + AllCount = 0; + switch (ConsoleMenuType) { + case BM_CONSOLE_IN_CONTEXT_SELECT: + ConsoleMenu = &ConsoleInpMenu; + DevicePath = EfiLibGetVariable ( + L"ConIn", + &gEfiGlobalVariableGuid + ); + + AllDevicePath = EfiLibGetVariable ( + L"ConInDev", + &gEfiGlobalVariableGuid + ); + break; + + case BM_CONSOLE_OUT_CONTEXT_SELECT: + ConsoleMenu = &ConsoleOutMenu; + DevicePath = EfiLibGetVariable ( + L"ConOut", + &gEfiGlobalVariableGuid + ); + + AllDevicePath = EfiLibGetVariable ( + L"ConOutDev", + &gEfiGlobalVariableGuid + ); + break; + + case BM_CONSOLE_ERR_CONTEXT_SELECT: + ConsoleMenu = &ConsoleErrMenu; + DevicePath = EfiLibGetVariable ( + L"ErrOut", + &gEfiGlobalVariableGuid + ); + + AllDevicePath = EfiLibGetVariable ( + L"ErrOutDev", + &gEfiGlobalVariableGuid + ); + break; + + default: + return EFI_UNSUPPORTED; + } + + if (NULL == AllDevicePath) { + return EFI_NOT_FOUND; + } + + InitializeListHead (&ConsoleMenu->Head); + + AllCount = EfiDevicePathInstanceCount (AllDevicePath); + ConsoleMenu->MenuNumber = 0; + // + // Following is menu building up for Console Out Devices + // + 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 = DevicePathInstanceDup (DevicePathInst); + NewMenuEntry->DisplayString = EfiLibStrFromDatahub (NewConsoleContext->DevicePath); + if (NULL == NewMenuEntry->DisplayString) { + NewMenuEntry->DisplayString = DevicePathToStr (NewConsoleContext->DevicePath); + } + + NewConsoleContext->IsTerminal = IsTerminalDevicePath ( + NewConsoleContext->DevicePath, + &Terminal, + &Com + ); + + NewConsoleContext->IsActive = BdsLibMatchDevicePaths ( + DevicePath, + NewConsoleContext->DevicePath + ); + NewTerminalMenuEntry = NULL; + NewTerminalContext = NULL; + + if (NewConsoleContext->IsTerminal) { + BOpt_DestroyMenuEntry (NewMenuEntry); + } else { + Index2++; + ConsoleMenu->MenuNumber++; + InsertTailList (&ConsoleMenu->Head, &NewMenuEntry->Link); + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +GetAllConsoles ( + VOID + ) +/*++ + +Routine Description: + Build up ConsoleOutMenu, ConsoleInpMenu and ConsoleErrMenu + +Arguments: + +Returns: + EFI_SUCCESS + Others + +--*/ +{ + GetConsoleMenu (BM_CONSOLE_IN_CONTEXT_SELECT); + GetConsoleMenu (BM_CONSOLE_OUT_CONTEXT_SELECT); + GetConsoleMenu (BM_CONSOLE_ERR_CONTEXT_SELECT); + return EFI_SUCCESS; +} + +EFI_STATUS +FreeAllConsoles ( + VOID + ) +/*++ + +Routine Description: + Free ConsoleOutMenu, ConsoleInpMenu and ConsoleErrMenu + +Arguments: + +Returns: + EFI_SUCCESS + Others + +--*/ +{ + BOpt_FreeMenu (&ConsoleOutMenu); + BOpt_FreeMenu (&ConsoleInpMenu); + BOpt_FreeMenu (&ConsoleErrMenu); + BOpt_FreeMenu (&TerminalMenu); + return EFI_SUCCESS; +} + +BOOLEAN +IsTerminalDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + OUT TYPE_OF_TERMINAL *Termi, + OUT UINTN *Com + ) +/*++ + +Routine Description: + Test whether DevicePath is a valid Terminal + +Arguments: + DevicePath - DevicePath to be checked + Termi - If is terminal, give its type + Com - If is Com Port, give its type + +Returns: + TRUE - If DevicePath point to a Terminal + FALSE + +--*/ +{ + UINT8 *Ptr; + BOOLEAN IsTerminal; + VENDOR_DEVICE_PATH *Vendor; + ACPI_HID_DEVICE_PATH *Acpi; + UINT32 Match; + EFI_GUID TempGuid; + + IsTerminal = FALSE; + + // + // Parse the Device Path, should be change later!!! + // + Ptr = (UINT8 *) DevicePath; + while (*Ptr != END_DEVICE_PATH_TYPE) { + Ptr++; + } + + Ptr = Ptr - sizeof (VENDOR_DEVICE_PATH); + Vendor = (VENDOR_DEVICE_PATH *) Ptr; + + // + // There are four kinds of Terminal types + // check to see whether this devicepath + // is one of that type + // + CopyMem (&TempGuid, &Vendor->Guid, sizeof (EFI_GUID)); + + if (CompareGuid (&TempGuid, &Guid[0])) { + *Termi = PC_ANSI; + IsTerminal = TRUE; + } else { + if (CompareGuid (&TempGuid, &Guid[1])) { + *Termi = VT_100; + IsTerminal = TRUE; + } else { + if (CompareGuid (&TempGuid, &Guid[2])) { + *Termi = VT_100_PLUS; + IsTerminal = TRUE; + } else { + if (CompareGuid (&TempGuid, &Guid[3])) { + *Termi = VT_UTF8; + IsTerminal = TRUE; + } else { + IsTerminal = FALSE; + } + } + } + } + + if (!IsTerminal) { + return FALSE; + } + + Ptr = Ptr - sizeof (UART_DEVICE_PATH) - sizeof (ACPI_HID_DEVICE_PATH); + Acpi = (ACPI_HID_DEVICE_PATH *) Ptr; + Match = EISA_PNP_ID (0x0501); + if (CompareMem (&Acpi->HID, &Match, sizeof (UINT32)) == 0) { + CopyMem (Com, &Acpi->UID, sizeof (UINT32)); + } else { + return FALSE; + } + + return TRUE; +} diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/Data.c b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/Data.c new file mode 100644 index 0000000000..3c0c1cc7e3 --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/Data.c @@ -0,0 +1,324 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + data.c + +Abstract: + + Define some data used for Boot Maint + +Revision History + +--*/ + +#include "bootmaint.h" + +EFI_HII_UPDATE_DATA *UpdateData; +STRING_DEPOSITORY *FileOptionStrDepository; +STRING_DEPOSITORY *ConsoleOptionStrDepository; +STRING_DEPOSITORY *BootOptionStrDepository; +STRING_DEPOSITORY *BootOptionHelpStrDepository; +STRING_DEPOSITORY *DriverOptionStrDepository; +STRING_DEPOSITORY *DriverOptionHelpStrDepository; +STRING_DEPOSITORY *TerminalStrDepository; + +// +// Terminal type string token storage +// +UINT16 TerminalType[] = { + STRING_TOKEN(STR_COM_TYPE_0), + STRING_TOKEN(STR_COM_TYPE_1), + STRING_TOKEN(STR_COM_TYPE_2), + STRING_TOKEN(STR_COM_TYPE_3), +}; + +// +// File system selection menu +// +BM_MENU_OPTION FsOptionMenu = { + BM_MENU_OPTION_SIGNATURE, + NULL, + 0 +}; + +// +// Console Input Device Selection Menu +// +BM_MENU_OPTION ConsoleInpMenu = { + BM_MENU_OPTION_SIGNATURE, + NULL, + 0 +}; + +// +// Console Output Device Selection Menu +// +BM_MENU_OPTION ConsoleOutMenu = { + BM_MENU_OPTION_SIGNATURE, + NULL, + 0 +}; + +// +// Error Output Device Selection Menu +// +BM_MENU_OPTION ConsoleErrMenu = { + BM_MENU_OPTION_SIGNATURE, + NULL, + 0 +}; + +// +// Boot Option from variable Menu +// +BM_MENU_OPTION BootOptionMenu = { + BM_MENU_OPTION_SIGNATURE, + NULL, + 0 +}; + +// +// Driver Option from variable menu +// +BM_MENU_OPTION DriverOptionMenu = { + BM_MENU_OPTION_SIGNATURE, + NULL, + 0 +}; + +// +// Legacy FD Info from LegacyBios.GetBbsInfo() +// +BM_MENU_OPTION LegacyFDMenu = { + BM_MENU_OPTION_SIGNATURE, + NULL, + 0 +}; + +// +// Legacy HD Info from LegacyBios.GetBbsInfo() +// +BM_MENU_OPTION LegacyHDMenu = { + BM_MENU_OPTION_SIGNATURE, + NULL, + 0 +}; + +// +// Legacy CD Info from LegacyBios.GetBbsInfo() +// +BM_MENU_OPTION LegacyCDMenu = { + BM_MENU_OPTION_SIGNATURE, + NULL, + 0 +}; + +// +// Legacy NET Info from LegacyBios.GetBbsInfo() +// +BM_MENU_OPTION LegacyNETMenu = { + BM_MENU_OPTION_SIGNATURE, + NULL, + 0 +}; + +// +// Legacy NET Info from LegacyBios.GetBbsInfo() +// +BM_MENU_OPTION LegacyBEVMenu = { + BM_MENU_OPTION_SIGNATURE, + NULL, + 0 +}; + +// +// Files and sub-directories in current directory menu +// +BM_MENU_OPTION DirectoryMenu = { + BM_MENU_OPTION_SIGNATURE, + NULL, + 0 +}; + +// +// Handles in current system selection menu +// +BM_MENU_OPTION DriverMenu = { + BM_MENU_OPTION_SIGNATURE, + NULL, + 0 +}; + +BM_MENU_OPTION TerminalMenu = { + BM_MENU_OPTION_SIGNATURE, + NULL, + 0 +}; + +// +// Value and string token correspondency for BaudRate +// +COM_ATTR BaudRateList[19] = { + { + 115200, + STRING_TOKEN(STR_COM_BAUD_RATE_0) + }, + { + 57600, + STRING_TOKEN(STR_COM_BAUD_RATE_1) + }, + { + 38400, + STRING_TOKEN(STR_COM_BAUD_RATE_2) + }, + { + 19200, + STRING_TOKEN(STR_COM_BAUD_RATE_3) + }, + { + 9600, + STRING_TOKEN(STR_COM_BAUD_RATE_4) + }, + { + 7200, + STRING_TOKEN(STR_COM_BAUD_RATE_5) + }, + { + 4800, + STRING_TOKEN(STR_COM_BAUD_RATE_6) + }, + { + 3600, + STRING_TOKEN(STR_COM_BAUD_RATE_7) + }, + { + 2400, + STRING_TOKEN(STR_COM_BAUD_RATE_8) + }, + { + 2000, + STRING_TOKEN(STR_COM_BAUD_RATE_9) + }, + { + 1800, + STRING_TOKEN(STR_COM_BAUD_RATE_10) + }, + { + 1200, + STRING_TOKEN(STR_COM_BAUD_RATE_11) + }, + { + 600, + STRING_TOKEN(STR_COM_BAUD_RATE_12) + }, + { + 300, + STRING_TOKEN(STR_COM_BAUD_RATE_13) + }, + { + 150, + STRING_TOKEN(STR_COM_BAUD_RATE_14) + }, + { + 134, + STRING_TOKEN(STR_COM_BAUD_RATE_15) + }, + { + 110, + STRING_TOKEN(STR_COM_BAUD_RATE_16) + }, + { + 75, + STRING_TOKEN(STR_COM_BAUD_RATE_17) + }, + { + 50, + STRING_TOKEN(STR_COM_BAUD_RATE_18) + } +}; + +// +// Value and string token correspondency for DataBits +// +COM_ATTR DataBitsList[4] = { + { + 5, + STRING_TOKEN(STR_COM_DATA_BITS_0) + }, + { + 6, + STRING_TOKEN(STR_COM_DATA_BITS_1) + }, + { + 7, + STRING_TOKEN(STR_COM_DATA_BITS_2) + }, + { + 8, + STRING_TOKEN(STR_COM_DATA_BITS_3) + } +}; + +// +// Value and string token correspondency for Parity +// +COM_ATTR ParityList[5] = { + { + NoParity, + STRING_TOKEN(STR_COM_PAR_0) + }, + { + EvenParity, + STRING_TOKEN(STR_COM_PAR_1) + }, + { + OddParity, + STRING_TOKEN(STR_COM_PAR_2) + }, + { + MarkParity, + STRING_TOKEN(STR_COM_PAR_3) + }, + { + SpaceParity, + STRING_TOKEN(STR_COM_PAR_4) + } +}; + +// +// Value and string token correspondency for Baudreate +// +COM_ATTR StopBitsList[3] = { + { + OneStopBit, + STRING_TOKEN(STR_COM_STOP_BITS_0) + }, + { + OneFiveStopBits, + STRING_TOKEN(STR_COM_STOP_BITS_1) + }, + { + TwoStopBits, + STRING_TOKEN(STR_COM_STOP_BITS_2) + } +}; + +// +// Guid for messaging path, used in Serial port setting. +// +EFI_GUID Guid[4] = { + DEVICE_PATH_MESSAGING_PC_ANSI, + DEVICE_PATH_MESSAGING_VT_100, + DEVICE_PATH_MESSAGING_VT_100_PLUS, + DEVICE_PATH_MESSAGING_VT_UTF8 +}; diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/FE.vfr b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/FE.vfr new file mode 100644 index 0000000000..998a4a68f5 --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/FE.vfr @@ -0,0 +1,138 @@ +// *++ +// +// Copyright (c) 2006, Intel Corporation +// All rights reserved. This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// Module Name: +// +// FE.vfr +// +// Abstract: +// +// File Explorer Formset +// +// Revision History: +// +// --*/ + +#include "BdsStrDefs.h" +#include "formguid.h" + +#pragma pack(1) +typedef struct { + UINT16 DescriptionData[75]; + UINT16 OptionalData[127]; + UINT8 Active; + UINT8 ForceReconnect; +} FILE_EXPLORER_NV_DATA; +#pragma pack() + +#define FORM_FILE_EXPLORER_ID 0x001E +#define FORM_BOOT_ADD_DESCRIPTION_ID 0x001F +#define FORM_DRIVER_ADD_FILE_DESCRIPTION_ID 0x0020 +#define KEY_VALUE_SAVE_AND_EXIT 0x0090 +#define KEY_VALUE_NO_SAVE_AND_EXIT 0x0091 + + + +formset + guid = FILE_EXPLORE_FORMSET_GUID, + title = STRING_TOKEN(STR_FILE_EXPLORER_TITLE), + help = STRING_TOKEN(STR_NULL_STRING), + class = 0, + subclass = 0, + + form formid = FORM_FILE_EXPLORER_ID, + title = STRING_TOKEN(STR_FILE_EXPLORER_TITLE); + + label FORM_FILE_EXPLORER_ID; + endform; + + form formid = FORM_BOOT_ADD_DESCRIPTION_ID, + title = STRING_TOKEN(STR_FORM_BOOT_ADD_DESC_TITLE); + + label FORM_BOOT_ADD_DESCRIPTION_ID; + + subtitle text = STRING_TOKEN(STR_NULL_STRING); + + string varid = FILE_EXPLORER_NV_DATA.DescriptionData, + prompt = STRING_TOKEN(STR_LOAD_OPTION_DESC), + help = STRING_TOKEN(STR_NULL_STRING), + minsize = 6, + maxsize = 75, + endstring; + + string varid = FILE_EXPLORER_NV_DATA.OptionalData, + prompt = STRING_TOKEN(STR_OPTIONAL_DATA), + help = STRING_TOKEN(STR_NULL_STRING), + minsize = 0, + maxsize = 120, + endstring; + + text + help = STRING_TOKEN(STR_SAVE_AND_EXIT), + text = STRING_TOKEN(STR_SAVE_AND_EXIT), + text = STRING_TOKEN(STR_NULL_STRING), + flags = INTERACTIVE | NV_ACCESS, + key = KEY_VALUE_SAVE_AND_EXIT; + + text + help = STRING_TOKEN(STR_NO_SAVE_AND_EXIT), + text = STRING_TOKEN(STR_NO_SAVE_AND_EXIT), + text = STRING_TOKEN(STR_NULL_STRING), + flags = INTERACTIVE | NV_ACCESS, + key = KEY_VALUE_NO_SAVE_AND_EXIT; + + endform; + + form formid = FORM_DRIVER_ADD_FILE_DESCRIPTION_ID, + title = STRING_TOKEN(STR_FORM_DRV_ADD_DESC_TITLE); + + label FORM_DRIVER_ADD_FILE_DESCRIPTION_ID; + + subtitle text = STRING_TOKEN(STR_NULL_STRING); + + string varid = FILE_EXPLORER_NV_DATA.DescriptionData, + prompt = STRING_TOKEN(STR_LOAD_OPTION_DESC), + help = STRING_TOKEN(STR_NULL_STRING), + minsize = 6, + maxsize = 75, + endstring; + + string varid = FILE_EXPLORER_NV_DATA.OptionalData, + prompt = STRING_TOKEN(STR_OPTIONAL_DATA), + help = STRING_TOKEN(STR_NULL_STRING), + minsize = 0, + maxsize = 120, + endstring; + + checkbox varid = FILE_EXPLORER_NV_DATA.ForceReconnect, + prompt = STRING_TOKEN(STR_LOAD_OPTION_FORCE_RECON), + help = STRING_TOKEN(STR_LOAD_OPTION_FORCE_RECON), + flags = 1, + key = 0, + endcheckbox; + + text + help = STRING_TOKEN(STR_SAVE_AND_EXIT), + text = STRING_TOKEN(STR_SAVE_AND_EXIT), + text = STRING_TOKEN(STR_NULL_STRING), + flags = INTERACTIVE | NV_ACCESS, + key = KEY_VALUE_SAVE_AND_EXIT; + + text + help = STRING_TOKEN(STR_NO_SAVE_AND_EXIT), + text = STRING_TOKEN(STR_NO_SAVE_AND_EXIT), + text = STRING_TOKEN(STR_NULL_STRING), + flags = INTERACTIVE | NV_ACCESS, + key = KEY_VALUE_NO_SAVE_AND_EXIT; + + endform; + +endformset; \ No newline at end of file diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/FileExplorer.c b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/FileExplorer.c new file mode 100644 index 0000000000..0c8c74c604 --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/FileExplorer.c @@ -0,0 +1,335 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FileExplorer.c + +AgBStract: + + File explorer related functions. + +--*/ + +#include "Generic/Bds.h" +#include "bootmaint.h" +#include "BdsPlatform.h" + +VOID +UpdateFileExplorePage ( + IN BMM_CALLBACK_DATA *CallbackData, + BM_MENU_OPTION *MenuOption + ) +/*++ +Routine Description: + Update the File Explore page. + +Arguments: + MenuOption - Pointer to menu options to display. + +Returns: + None. + +--*/ +{ + UINT8 *Location; + UINTN Index; + BM_MENU_ENTRY *NewMenuEntry; + BM_FILE_CONTEXT *NewFileContext; + FORM_ID FormId; + + NewMenuEntry = NULL; + NewFileContext = NULL; + FormId = 0; + + // + // Clean up file explore page. + // + RefreshUpdateData (FALSE, 0, FALSE, 0, 0xff); + + // + // Remove all op-codes from dynamic page + // + CallbackData->Hii->UpdateForm ( + CallbackData->Hii, + CallbackData->FeHiiHandle, + FORM_FILE_EXPLORER_ID, + FALSE, + UpdateData + ); + + RefreshUpdateData (TRUE, (EFI_PHYSICAL_ADDRESS) (UINTN) CallbackData->FeCallbackHandle, FALSE, 0, 0); + + Location = (UINT8 *) &UpdateData->Data; + + for (Index = 0; Index < MenuOption->MenuNumber; Index++) { + NewMenuEntry = BOpt_GetMenuEntry (MenuOption, Index); + NewFileContext = (BM_FILE_CONTEXT *) NewMenuEntry->VariableContext; + + if (NewFileContext->IsBootLegacy) { + continue; + } + + if ((NewFileContext->IsDir) || (BOOT_FROM_FILE_STATE == CallbackData->FeCurrentState)) { + // + // Create Text opcode for directory, also create Text opcode for file in BOOT_FROM_FILE_STATE. + // + CreateTextOpCode ( + NewMenuEntry->DisplayStringToken, + STR_NULL_STRING, + STR_NULL_STRING, + EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_NV_ACCESS, + (UINT16) (FILE_OPTION_OFFSET + Index), + Location + ); + } else { + // + // Create Goto opcode for file in ADD_BOOT_OPTION_STATE or ADD_DRIVER_OPTION_STATE. + // + if (ADD_BOOT_OPTION_STATE == CallbackData->FeCurrentState) { + FormId = FORM_BOOT_ADD_DESCRIPTION_ID; + } else if (ADD_DRIVER_OPTION_STATE == CallbackData->FeCurrentState) { + FormId = FORM_DRIVER_ADD_FILE_DESCRIPTION_ID; + } + + CreateGotoOpCode ( + FormId, + NewMenuEntry->DisplayStringToken, + STRING_TOKEN (STR_NULL_STRING), + EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_NV_ACCESS, + (UINT16) (FILE_OPTION_OFFSET + Index), + Location + ); + } + + UpdateData->DataCount++; + Location = Location + ((EFI_IFR_OP_HEADER *) Location)->Length; + } + + CallbackData->Hii->UpdateForm ( + CallbackData->Hii, + CallbackData->FeHiiHandle, + FORM_FILE_EXPLORER_ID, + TRUE, + UpdateData + ); +} + +BOOLEAN +UpdateFileExplorer ( + IN BMM_CALLBACK_DATA *CallbackData, + IN UINT16 KeyValue + ) +/*++ + +Routine Description: + Update the file explower page with the refershed file system. + +Arguments: + CallbackData - BMM context data + KeyValue - Key value to identify the type of data to expect. + +Returns: + TRUE - Inform the caller to create a callback packet to exit file explorer. + FALSE - Indicate that there is no need to exit file explorer. + +--*/ +{ + UINT16 FileOptionMask; + BM_MENU_ENTRY *NewMenuEntry; + BM_FILE_CONTEXT *NewFileContext; + FORM_ID FormId; + BOOLEAN ExitFileExplorer; + + NewMenuEntry = NULL; + NewFileContext = NULL; + ExitFileExplorer = FALSE; + + FileOptionMask = (UINT16) (FILE_OPTION_MASK & KeyValue); + + if (UNKNOWN_CONTEXT == CallbackData->FeDisplayContext) { + // + // First in, display file system. + // + BOpt_FreeMenu (&FsOptionMenu); + BOpt_FindFileSystem (CallbackData); + CreateMenuStringToken (CallbackData, CallbackData->FeHiiHandle, &FsOptionMenu); + + UpdateFileExplorePage (CallbackData, &FsOptionMenu); + + CallbackData->FeDisplayContext = FILE_SYSTEM; + } else { + if (FILE_SYSTEM == CallbackData->FeDisplayContext) { + NewMenuEntry = BOpt_GetMenuEntry (&FsOptionMenu, FileOptionMask); + } else if (DIRECTORY == CallbackData->FeDisplayContext) { + NewMenuEntry = BOpt_GetMenuEntry (&DirectoryMenu, FileOptionMask); + } + + CallbackData->FeDisplayContext = DIRECTORY; + + NewFileContext = (BM_FILE_CONTEXT *) NewMenuEntry->VariableContext; + + if (NewFileContext->IsDir ) { + RemoveEntryList (&NewMenuEntry->Link); + BOpt_FreeMenu (&DirectoryMenu); + BOpt_FindFiles (CallbackData, NewMenuEntry); + CreateMenuStringToken (CallbackData, CallbackData->FeHiiHandle, &DirectoryMenu); + BOpt_DestroyMenuEntry (NewMenuEntry); + + UpdateFileExplorePage (CallbackData, &DirectoryMenu); + + } else { + switch (CallbackData->FeCurrentState) { + case BOOT_FROM_FILE_STATE: + // + // Here boot from file + // + BootThisFile (NewFileContext); + ExitFileExplorer = TRUE; + break; + + case ADD_BOOT_OPTION_STATE: + case ADD_DRIVER_OPTION_STATE: + if (ADD_BOOT_OPTION_STATE == CallbackData->FeCurrentState) { + FormId = FORM_BOOT_ADD_DESCRIPTION_ID; + } else { + FormId = FORM_DRIVER_ADD_FILE_DESCRIPTION_ID; + } + + CallbackData->MenuEntry = NewMenuEntry; + CallbackData->LoadContext->FilePathList = ((BM_FILE_CONTEXT *) (CallbackData->MenuEntry->VariableContext))->DevicePath; + + // + // Clean up file explore page. + // + RefreshUpdateData (FALSE, 0, FALSE, 0, 1); + + // + // Remove the Subtitle op-code. + // + CallbackData->Hii->UpdateForm ( + CallbackData->Hii, + CallbackData->FeHiiHandle, + FormId, + FALSE, + UpdateData + ); + + // + // Create Subtitle op-code for the display string of the option. + // + RefreshUpdateData (TRUE, (EFI_PHYSICAL_ADDRESS) (UINTN) CallbackData->FeCallbackHandle, FALSE, 0, 1); + + CreateSubTitleOpCode ( + NewMenuEntry->DisplayStringToken, + &UpdateData->Data + ); + + CallbackData->Hii->UpdateForm ( + CallbackData->Hii, + CallbackData->FeHiiHandle, + FormId, + TRUE, + UpdateData + ); + break; + + default: + break; + } + } + } + + return ExitFileExplorer; +} + +EFI_STATUS +EFIAPI +FileExplorerCallback ( + IN EFI_FORM_CALLBACK_PROTOCOL *This, + IN UINT16 KeyValue, + IN EFI_IFR_DATA_ARRAY *Data, + OUT EFI_HII_CALLBACK_PACKET **Packet + ) +/*++ +Routine Description: + Callback Function for file exploration and file interaction. + +Arguments: + This - File explorer callback protocol pointer. + KeyValue - Key value to identify the type of data to expect. + Data - A pointer to the data being sent to the original exporting driver. + Packet - A pointer to a packet of information which a driver passes back to the browser. + +Returns: + EFI_SUCCESS - Callback ended successfully. + Others - Contain some errors. + +--*/ +{ + BMM_CALLBACK_DATA *Private; + FILE_EXPLORER_NV_DATA *NvRamMap; + EFI_STATUS Status; + + Status = EFI_SUCCESS; + Private = FE_CALLBACK_DATA_FROM_THIS (This); + UpdateData->FormCallbackHandle = (EFI_PHYSICAL_ADDRESS) (UINTN) Private->FeCallbackHandle; + NvRamMap = (FILE_EXPLORER_NV_DATA *) Data->NvRamMap; + + if (KEY_VALUE_SAVE_AND_EXIT == KeyValue) { + // + // Apply changes and exit formset. + // + if (ADD_BOOT_OPTION_STATE == Private->FeCurrentState) { + Status = Var_UpdateBootOption (Private, NvRamMap); + if (EFI_ERROR (Status)) { + return Status; + } + + BOpt_GetBootOptions (Private); + CreateMenuStringToken (Private, Private->FeHiiHandle, &BootOptionMenu); + } else if (ADD_DRIVER_OPTION_STATE == Private->FeCurrentState) { + Status = Var_UpdateDriverOption ( + Private, + Private->FeHiiHandle, + NvRamMap->DescriptionData, + NvRamMap->OptionalData, + NvRamMap->ForceReconnect + ); + if (EFI_ERROR (Status)) { + return Status; + } + + BOpt_GetDriverOptions (Private); + CreateMenuStringToken (Private, Private->FeHiiHandle, &DriverOptionMenu); + } + + CreateCallbackPacket (Packet, EXIT_REQUIRED | NV_NOT_CHANGED); + } else if (KEY_VALUE_NO_SAVE_AND_EXIT == KeyValue) { + // + // Discard changes and exit formset. + // + NvRamMap->OptionalData[0] = 0x0000; + NvRamMap->DescriptionData[0] = 0x0000; + CreateCallbackPacket (Packet, EXIT_REQUIRED | NV_NOT_CHANGED); + } else if (KeyValue < FILE_OPTION_OFFSET) { + // + // Exit File Explorer formset. + // + CreateCallbackPacket (Packet, EXIT_REQUIRED); + } else { + if (UpdateFileExplorer (Private, KeyValue)) { + CreateCallbackPacket (Packet, EXIT_REQUIRED); + } + } + + return Status; +} diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/FormGuid.h b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/FormGuid.h new file mode 100644 index 0000000000..3d4cd4a027 --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/FormGuid.h @@ -0,0 +1,32 @@ +// *++ +// +// Copyright (c) 2006, Intel Corporation +// All rights reserved. This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// Module Name: +// +// formguid.h +// +// Abstract: +// +// Formset guids for Boot Maintenance Manager +// +// Revision History: +// +// --*/ +// +#define MAIN_FORMSET_GUID \ + { \ + 0x642237c7, 0x35d4, 0x472d, { 0x83, 0x65, 0x12, 0xe0, 0xcc, 0xf2, 0x7a, 0x22 } \ + } + +#define FILE_EXPLORE_FORMSET_GUID \ + { \ + 0x1f2d63e1, 0xfebd, 0x4dc7, { 0x9c, 0xc5, 0xba, 0x2b, 0x1c, 0xef, 0x9c, 0x5b } \ + } diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/UpdatePage.c b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/UpdatePage.c new file mode 100644 index 0000000000..65ee289968 --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/UpdatePage.c @@ -0,0 +1,1275 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + UpdatePage.c + +AgBStract: + + Dynamically Update the pages + +--*/ + +#include "Generic/Bds.h" +#include "bootmaint.h" +#include "BdsPlatform.h" + +EFI_GUID gTerminalDriverGuid = { + 0x10634d8e, 0x1c05, 0x46cb, 0xbb, 0xc, 0x5a, 0xfd, 0xc8, 0x29, 0xa8, 0xc8 +}; + +VOID +RefreshUpdateData ( + IN BOOLEAN FormSetUpdate, + IN EFI_PHYSICAL_ADDRESS FormCallbackHandle, + IN BOOLEAN FormUpdate, + IN STRING_REF FormTitle, + IN UINT16 DataCount + ) +/*++ +Routine Description: + Refresh the global UpdateData structure. + +Arguments: + FormSetUpdate - If TRUE, next variable is significant + FormCallbackHandle - If not 0, will update FormSet with this info + FormUpdate - If TRUE, next variable is significant + FormTitle - If not 0, will update Form with this info + DataCount - The number of Data entries in this structure + +Returns: + None. +--*/ +{ + UpdateData->FormSetUpdate = FormSetUpdate; + if (FormSetUpdate) { + ASSERT (0 != FormCallbackHandle); + UpdateData->FormCallbackHandle = FormCallbackHandle; + } + + UpdateData->FormUpdate = FALSE; + UpdateData->FormTitle = FormTitle; + UpdateData->DataCount = DataCount; +} + +VOID +UpdatePageStart ( + IN BMM_CALLBACK_DATA *CallbackData, + IN OUT UINT8 **CurrentLocation + ) +{ + RefreshUpdateData (TRUE, (EFI_PHYSICAL_ADDRESS) (UINTN) CallbackData->BmmCallbackHandle, FALSE, 0, 0); + + 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. + // + CreateGotoOpCode ( + FORM_MAIN_ID, + STRING_TOKEN (STR_FORM_GOTO_MAIN), + STRING_TOKEN (STR_FORM_GOTO_MAIN), + EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_NV_ACCESS, + FORM_MAIN_ID, + *CurrentLocation + ); + + UpdateData->DataCount++; + + *CurrentLocation = *CurrentLocation + ((EFI_IFR_OP_HEADER *) (*CurrentLocation))->Length; + } + +} + +VOID +UpdatePageEnd ( + IN BMM_CALLBACK_DATA *CallbackData, + IN UINT8 *CurrentLocation + ) +{ + // + // Create the "Apply changes" and "Discard changes" tags. + // + if (CallbackData->BmmAskSaveOrNot) { + CreateGotoOpCode ( + FORM_MAIN_ID, + STRING_TOKEN (STR_SAVE_AND_EXIT), + STRING_TOKEN (STR_NULL_STRING), + EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_NV_ACCESS, + KEY_VALUE_SAVE_AND_EXIT, + CurrentLocation + ); + + UpdateData->DataCount++; + + CurrentLocation = CurrentLocation + ((EFI_IFR_OP_HEADER *) CurrentLocation)->Length; + + CreateGotoOpCode ( + FORM_MAIN_ID, + STRING_TOKEN (STR_NO_SAVE_AND_EXIT), + STRING_TOKEN (STR_NULL_STRING), + EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_NV_ACCESS, + KEY_VALUE_NO_SAVE_AND_EXIT, + CurrentLocation + ); + + UpdateData->DataCount++; + } + // + // Ensure user can return to the main page. + // + if (0 == UpdateData->DataCount) { + CreateGotoOpCode ( + FORM_MAIN_ID, + STRING_TOKEN (STR_NO_SAVE_AND_EXIT), + STRING_TOKEN (STR_NULL_STRING), + EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_NV_ACCESS, + KEY_VALUE_NO_SAVE_AND_EXIT, + CurrentLocation + ); + + UpdateData->DataCount++; + } + + CallbackData->Hii->UpdateForm ( + CallbackData->Hii, + CallbackData->BmmHiiHandle, + CallbackData->BmmCurrentPageId, + TRUE, + UpdateData + ); +} + +VOID +CleanUpPage ( + IN EFI_FORM_LABEL LabelId, + IN BMM_CALLBACK_DATA *CallbackData + ) +{ + RefreshUpdateData (FALSE, 0, FALSE, 0, 0xff); + + // + // Remove all op-codes from dynamic page + // + CallbackData->Hii->UpdateForm ( + CallbackData->Hii, + CallbackData->BmmHiiHandle, + LabelId, + FALSE, + UpdateData + ); +} + +EFI_STATUS +BootThisFile ( + IN BM_FILE_CONTEXT *FileContext + ) +{ + EFI_STATUS Status; + UINTN ExitDataSize; + CHAR16 *ExitData; + BDS_COMMON_OPTION *Option; + + Status = gBS->AllocatePool (EfiBootServicesData, sizeof (BDS_COMMON_OPTION), &Option); + Option->Description = FileContext->FileName; + Option->DevicePath = FileContext->DevicePath; + Option->LoadOptionsSize = 0; + Option->LoadOptions = NULL; + + // + // Since current no boot from removable media directly is allowed */ + // + gST->ConOut->ClearScreen (gST->ConOut); + + ExitDataSize = 0; + + Status = BdsLibBootViaBootOption (Option, Option->DevicePath, &ExitDataSize, &ExitData); + + return Status; + +} + +VOID +UpdateConCOMPage ( + IN BMM_CALLBACK_DATA *CallbackData + ) +{ + BM_MENU_ENTRY *NewMenuEntry; + UINT16 Index; + UINT8 *Location; + EFI_STATUS Status; + VOID *Interface; + + Location = (UINT8 *) &UpdateData->Data; + CallbackData->BmmAskSaveOrNot = FALSE; + + UpdatePageStart (CallbackData, &Location); + + Status = EfiLibLocateProtocol (&gTerminalDriverGuid, &Interface); + if (!EFI_ERROR (Status)) { + for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) { + NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index); + + CreateGotoOpCode ( + FORM_CON_COM_SETUP_ID, + NewMenuEntry->DisplayStringToken, + STRING_TOKEN (STR_NULL_STRING), + EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_NV_ACCESS, + (UINT16) (TERMINAL_OPTION_OFFSET + Index), + Location + ); + Location = Location + ((EFI_IFR_OP_HEADER *) Location)->Length; + UpdateData->DataCount++; + } + } + + UpdatePageEnd (CallbackData, Location); +} + +VOID +UpdateBootDelPage ( + IN BMM_CALLBACK_DATA *CallbackData + ) +{ + BM_MENU_ENTRY *NewMenuEntry; + BM_LOAD_CONTEXT *NewLoadContext; + UINT16 Index; + UINT8 *Location; + + Location = (UINT8 *) &UpdateData->Data; + CallbackData->BmmAskSaveOrNot = TRUE; + + UpdatePageStart (CallbackData, &Location); + CreateMenuStringToken (CallbackData, CallbackData->BmmHiiHandle, &BootOptionMenu); + + 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; + CallbackData->BmmFakeNvData->BootOptionDel[Index] = 0x00; + + CreateCheckBoxOpCode ( + (UINT16) (BOOT_OPTION_DEL_QUESTION_ID + Index), + (UINT8) 1, + NewMenuEntry->DisplayStringToken, + NewMenuEntry->HelpStringToken, + EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_NV_ACCESS, + (UINT16) BOOT_OPTION_DEL_QUESTION_ID, + Location + ); + + Location = Location + ((EFI_IFR_OP_HEADER *) Location)->Length; + UpdateData->DataCount++; + } + + UpdatePageEnd (CallbackData, Location); +} + +VOID +UpdateDrvAddHandlePage ( + IN BMM_CALLBACK_DATA *CallbackData + ) +{ + BM_MENU_ENTRY *NewMenuEntry; + UINT16 Index; + UINT8 *Location; + + Location = (UINT8 *) &UpdateData->Data; + CallbackData->BmmAskSaveOrNot = FALSE; + + UpdatePageStart (CallbackData, &Location); + + for (Index = 0; Index < DriverMenu.MenuNumber; Index++) { + NewMenuEntry = BOpt_GetMenuEntry (&DriverMenu, Index); + + CreateGotoOpCode ( + FORM_DRV_ADD_HANDLE_DESC_ID, + NewMenuEntry->DisplayStringToken, + STRING_TOKEN (STR_NULL_STRING), + EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_NV_ACCESS, + (UINT16) (HANDLE_OPTION_OFFSET + Index), + Location + ); + + Location = Location + ((EFI_IFR_OP_HEADER *) Location)->Length; + UpdateData->DataCount++; + } + + UpdatePageEnd (CallbackData, Location); +} + +VOID +UpdateDrvDelPage ( + IN BMM_CALLBACK_DATA *CallbackData + ) +{ + BM_MENU_ENTRY *NewMenuEntry; + BM_LOAD_CONTEXT *NewLoadContext; + UINT16 Index; + UINT8 *Location; + + Location = (UINT8 *) &UpdateData->Data; + CallbackData->BmmAskSaveOrNot = TRUE; + + UpdatePageStart (CallbackData, &Location); + + CreateMenuStringToken (CallbackData, CallbackData->BmmHiiHandle, &DriverOptionMenu); + + for (Index = 0; Index < DriverOptionMenu.MenuNumber; Index++) { + NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, Index); + + NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext; + NewLoadContext->Deleted = FALSE; + CallbackData->BmmFakeNvData->DriverOptionDel[Index] = 0x00; + + CreateCheckBoxOpCode ( + (UINT16) (DRIVER_OPTION_DEL_QUESTION_ID + Index), + (UINT8) 1, + NewMenuEntry->DisplayStringToken, + NewMenuEntry->HelpStringToken, + EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_NV_ACCESS, + (UINT16) DRIVER_OPTION_DEL_QUESTION_ID, + Location + ); + + Location = Location + ((EFI_IFR_OP_HEADER *) Location)->Length; + UpdateData->DataCount++; + } + + UpdatePageEnd (CallbackData, Location); +} + +VOID +UpdateDriverAddHandleDescPage ( + IN BMM_CALLBACK_DATA *CallbackData + ) +{ + BM_MENU_ENTRY *NewMenuEntry; + UINT8 *Location; + + Location = (UINT8 *) &UpdateData->Data; + CallbackData->BmmFakeNvData->DriverAddActive = 0x01; + CallbackData->BmmFakeNvData->DriverAddForceReconnect = 0x00; + CallbackData->BmmAskSaveOrNot = TRUE; + NewMenuEntry = CallbackData->MenuEntry; + + UpdatePageStart (CallbackData, &Location); + + UpdateData->DataCount += (UINT16) 4; + + CreateSubTitleOpCode ( + NewMenuEntry->DisplayStringToken, + Location + ); + + Location = Location + ((EFI_IFR_OP_HEADER *) Location)->Length; + + CreateStringOpCode ( + DRV_ADD_HANDLE_DESC_QUESTION_ID, + (UINT8) 150, + STRING_TOKEN (STR_LOAD_OPTION_DESC), + STRING_TOKEN (STR_NULL_STRING), + 6, + 75, + EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_NV_ACCESS, + KEY_VALUE_DRIVER_ADD_DESC_DATA, + Location + ); + + Location = Location + ((EFI_IFR_OP_HEADER *) Location)->Length; + + CreateCheckBoxOpCode ( + DRV_ADD_RECON_QUESTION_ID, + (UINT8) 1, + STRING_TOKEN (STR_LOAD_OPTION_FORCE_RECON), + STRING_TOKEN (STR_LOAD_OPTION_FORCE_RECON), + EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_NV_ACCESS, + DRV_ADD_RECON_QUESTION_ID, + Location + ); + Location = Location + ((EFI_IFR_OP_HEADER *) Location)->Length; + + CreateStringOpCode ( + DRIVER_ADD_OPTION_QUESTION_ID, + (UINT8) 150, + STRING_TOKEN (STR_OPTIONAL_DATA), + STRING_TOKEN (STR_NULL_STRING), + 6, + 75, + EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_NV_ACCESS, + KEY_VALUE_DRIVER_ADD_OPT_DATA, + Location + ); + + Location = Location + ((EFI_IFR_OP_HEADER *) Location)->Length; + UpdatePageEnd (CallbackData, Location); +} + +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 *Location; + UINT8 CheckFlags; + EFI_STATUS Status; + VOID *Interface; + + Location = (UINT8 *) &UpdateData->Data; + CallbackData->BmmAskSaveOrNot = TRUE; + + UpdatePageStart (CallbackData, &Location); + + for (Index = 0; Index < ConsoleMenu->MenuNumber; Index++) { + NewMenuEntry = BOpt_GetMenuEntry (ConsoleMenu, Index); + NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext; + CheckFlags = EFI_IFR_FLAG_INTERACTIVE; + if (NewConsoleContext->IsActive) { + CheckFlags |= EFI_IFR_FLAG_DEFAULT; + CallbackData->BmmFakeNvData->ConsoleCheck[Index] = TRUE; + } else { + CallbackData->BmmFakeNvData->ConsoleCheck[Index] = FALSE; + } + + CreateCheckBoxOpCode ( + (UINT16) (CON_DEVICE_QUESTION_ID + Index), + (UINT8) 1, + NewMenuEntry->DisplayStringToken, + NewMenuEntry->HelpStringToken, + CheckFlags, + (UINT16) (CONSOLE_OPTION_OFFSET + Index), + Location + ); + Location = Location + ((EFI_IFR_OP_HEADER *) Location)->Length; + UpdateData->DataCount++; + } + + Status = EfiLibLocateProtocol (&gTerminalDriverGuid, &Interface); + if (!EFI_ERROR (Status)) { + for (Index2 = 0; Index2 < TerminalMenu.MenuNumber; Index2++) { + CheckFlags = EFI_IFR_FLAG_INTERACTIVE; + NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index2); + NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext; + + if ((NewTerminalContext->IsConIn && (UpdatePageId == FORM_CON_IN_ID)) || + (NewTerminalContext->IsConOut && (UpdatePageId == FORM_CON_OUT_ID)) || + (NewTerminalContext->IsStdErr && (UpdatePageId == FORM_CON_ERR_ID)) + ) { + CheckFlags |= EFI_IFR_FLAG_DEFAULT; + CallbackData->BmmFakeNvData->ConsoleCheck[Index] = TRUE; + } else { + CallbackData->BmmFakeNvData->ConsoleCheck[Index] = FALSE; + } + + CreateCheckBoxOpCode ( + (UINT16) (CON_DEVICE_QUESTION_ID + Index), + (UINT8) 1, + NewMenuEntry->DisplayStringToken, + NewMenuEntry->HelpStringToken, + CheckFlags, + (UINT16) (CONSOLE_OPTION_OFFSET + Index), + Location + ); + Location = Location + ((EFI_IFR_OP_HEADER *) Location)->Length; + UpdateData->DataCount++; + Index++; + } + } + + UpdatePageEnd (CallbackData, Location); +} + +VOID +UpdateOrderPage ( + IN UINT16 UpdatePageId, + IN BM_MENU_OPTION *OptionMenu, + IN BMM_CALLBACK_DATA *CallbackData + ) +{ + BM_MENU_ENTRY *NewMenuEntry; + UINT16 Index; + UINT8 *Location; + IFR_OPTION *IfrOptionList; + + Location = (UINT8 *) &UpdateData->Data; + CallbackData->BmmAskSaveOrNot = TRUE; + + UpdatePageStart (CallbackData, &Location); + + CreateMenuStringToken (CallbackData, CallbackData->BmmHiiHandle, OptionMenu); + + ZeroMem (CallbackData->BmmFakeNvData->OptionOrder, 100); + + IfrOptionList = AllocateZeroPool (sizeof (IFR_OPTION) * OptionMenu->MenuNumber); + if (NULL == IfrOptionList) { + return ; + } + + for (Index = 0; Index < OptionMenu->MenuNumber; Index++) { + NewMenuEntry = BOpt_GetMenuEntry (OptionMenu, Index); + IfrOptionList[Index].StringToken = NewMenuEntry->DisplayStringToken; + IfrOptionList[Index].Value = (UINT16) (NewMenuEntry->OptionNumber + 1); + IfrOptionList[Index].OptionString = NULL; + CallbackData->BmmFakeNvData->OptionOrder[Index] = (UINT8) (IfrOptionList[Index].Value); + } + + if (OptionMenu->MenuNumber > 0) { + CreateOrderedListOpCode ( + (UINT16) OPTION_ORDER_QUESTION_ID, + (UINT8) 100, + STRING_TOKEN (STR_CHANGE_ORDER), + STRING_TOKEN (STR_CHANGE_ORDER), + IfrOptionList, + OptionMenu->MenuNumber, + Location + ); + + for (Index = 0; Index < OptionMenu->MenuNumber + 2; Index++) { + Location = Location + ((EFI_IFR_OP_HEADER *) Location)->Length; + } + + UpdateData->DataCount = (UINT16) (UpdateData->DataCount + OptionMenu->MenuNumber + 2); + } + + SafeFreePool (IfrOptionList); + + UpdatePageEnd (CallbackData, Location); + + CopyMem ( + CallbackData->BmmOldFakeNVData.OptionOrder, + CallbackData->BmmFakeNvData->OptionOrder, + 100 + ); +} + +VOID +UpdateBootNextPage ( + IN BMM_CALLBACK_DATA *CallbackData + ) +{ + UINT8 *Location; + BM_MENU_ENTRY *NewMenuEntry; + BM_LOAD_CONTEXT *NewLoadContext; + IFR_OPTION *IfrOptionList; + UINTN NumberOfOptions; + UINT16 Index; + + Location = (UINT8 *) &UpdateData->Data; + IfrOptionList = NULL; + NumberOfOptions = BootOptionMenu.MenuNumber; + CallbackData->BmmAskSaveOrNot = TRUE; + + UpdatePageStart (CallbackData, &Location); + CreateMenuStringToken (CallbackData, CallbackData->BmmHiiHandle, &BootOptionMenu); + + if (NumberOfOptions > 0) { + UpdateData->DataCount = (UINT8) (UpdateData->DataCount + NumberOfOptions); + IfrOptionList = AllocateZeroPool ((NumberOfOptions + 1) * sizeof (IFR_OPTION)); + + ASSERT (IfrOptionList); + + CallbackData->BmmFakeNvData->BootNext = (UINT16) (BootOptionMenu.MenuNumber); + + for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) { + NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index); + NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext; + if (NewLoadContext->IsBootNext) { + IfrOptionList[Index].Flags = EFI_IFR_FLAG_DEFAULT | EFI_IFR_FLAG_INTERACTIVE; + CallbackData->BmmFakeNvData->BootNext = Index; + } else { + IfrOptionList[Index].Flags = EFI_IFR_FLAG_INTERACTIVE; + } + + IfrOptionList[Index].Key = (UINT16) KEY_VALUE_MAIN_BOOT_NEXT; + IfrOptionList[Index].Value = Index; + IfrOptionList[Index].StringToken = NewMenuEntry->DisplayStringToken; + IfrOptionList[Index].OptionString = NULL; + } + + IfrOptionList[Index].Key = (UINT16) KEY_VALUE_MAIN_BOOT_NEXT; + IfrOptionList[Index].Value = Index; + IfrOptionList[Index].StringToken = STRING_TOKEN (STR_NONE); + IfrOptionList[Index].Flags = EFI_IFR_FLAG_INTERACTIVE; + if (CallbackData->BmmFakeNvData->BootNext == Index) { + IfrOptionList[Index].Flags |= EFI_IFR_FLAG_DEFAULT; + } + + IfrOptionList[Index].OptionString = NULL; + + CreateOneOfOpCode ( + (UINT16) BOOT_NEXT_QUESTION_ID, + (UINT8) 2, + STRING_TOKEN (STR_BOOT_NEXT), + STRING_TOKEN (STR_BOOT_NEXT_HELP), + IfrOptionList, + (UINTN) (NumberOfOptions + 1), + Location + ); + Location = Location + (NumberOfOptions + 2) * ((EFI_IFR_OP_HEADER *) Location)->Length; + Location = Location + ((EFI_IFR_OP_HEADER *) Location)->Length; + + UpdateData->DataCount += 3; + SafeFreePool (IfrOptionList); + IfrOptionList = NULL; + } + + UpdatePageEnd (CallbackData, Location); +} + +VOID +UpdateTimeOutPage ( + IN BMM_CALLBACK_DATA *CallbackData + ) +{ + UINT8 *Location; + UINT16 BootTimeOut; + + Location = (UINT8 *) &UpdateData->Data; + CallbackData->BmmAskSaveOrNot = TRUE; + + UpdatePageStart (CallbackData, &Location); + + BootTimeOut = BdsLibGetTimeout (); + + CreateNumericOpCode ( + (UINT16) BOOT_TIME_OUT_QUESTION_ID, + (UINT8) 2, + STRING_TOKEN (STR_NUM_AUTO_BOOT), + STRING_TOKEN (STR_HLP_AUTO_BOOT), + 0, + 65535, + 0, + 10, + 0, + 0, + Location + ); + + CallbackData->BmmFakeNvData->BootTimeOut = (UINT16) BootTimeOut; + UpdateData->DataCount++; + Location = Location + ((EFI_IFR_OP_HEADER *) Location)->Length; + + UpdatePageEnd (CallbackData, Location); +} + +VOID +UpdateTerminalPage ( + IN BMM_CALLBACK_DATA *CallbackData + ) +{ + UINT16 Index; + UINT8 *Location; + UINT8 CheckFlags; + IFR_OPTION *IfrOptionList; + BM_MENU_ENTRY *NewMenuEntry; + BM_TERMINAL_CONTEXT *NewTerminalContext; + + ZeroMem (UpdateData, UPDATE_DATA_SIZE); + Location = (UINT8 *) &UpdateData->Data; + UpdatePageStart (CallbackData, &Location); + + NewMenuEntry = BOpt_GetMenuEntry ( + &TerminalMenu, + CallbackData->CurrentTerminal + ); + + if (!NewMenuEntry) { + return ; + } + + NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext; + + IfrOptionList = AllocateZeroPool (sizeof (IFR_OPTION) * 19); + if (!IfrOptionList) { + return ; + } + + for (Index = 0; Index < 19; Index++) { + CheckFlags = EFI_IFR_FLAG_INTERACTIVE; + if (NewTerminalContext->BaudRate == (UINT64) (BaudRateList[Index].Value)) { + CheckFlags |= EFI_IFR_FLAG_DEFAULT; + NewTerminalContext->BaudRateIndex = (UINT8) Index; + CallbackData->BmmFakeNvData->COMBaudRate = NewTerminalContext->BaudRateIndex; + } + + IfrOptionList[Index].Flags = CheckFlags; + IfrOptionList[Index].Key = KEY_VALUE_COM_SET_BAUD_RATE; + IfrOptionList[Index].StringToken = BaudRateList[Index].StringToken; + IfrOptionList[Index].Value = Index; + } + + CreateOneOfOpCode ( + (UINT16) COM_BAUD_RATE_QUESTION_ID, + (UINT8) 1, + STRING_TOKEN (STR_COM_BAUD_RATE), + STRING_TOKEN (STR_COM_BAUD_RATE), + IfrOptionList, + 19, + Location + ); + + Location = Location + (Index + 1) * ((EFI_IFR_OP_HEADER *) Location)->Length; + Location = Location + ((EFI_IFR_OP_HEADER *) Location)->Length; + UpdateData->DataCount = (UINT8) (UpdateData->DataCount + Index); + UpdateData->DataCount += 2; + + SafeFreePool (IfrOptionList); + + IfrOptionList = AllocateZeroPool (sizeof (IFR_OPTION) * 4); + if (!IfrOptionList) { + return ; + } + + for (Index = 0; Index < 4; Index++) { + CheckFlags = EFI_IFR_FLAG_INTERACTIVE; + + if (NewTerminalContext->DataBits == DataBitsList[Index].Value) { + NewTerminalContext->DataBitsIndex = (UINT8) Index; + CallbackData->BmmFakeNvData->COMDataRate = NewTerminalContext->DataBitsIndex; + CheckFlags |= EFI_IFR_FLAG_DEFAULT; + } + + IfrOptionList[Index].Flags = CheckFlags; + IfrOptionList[Index].Key = KEY_VALUE_COM_SET_DATA_BITS; + IfrOptionList[Index].StringToken = DataBitsList[Index].StringToken; + IfrOptionList[Index].Value = Index; + } + + CreateOneOfOpCode ( + (UINT16) COM_DATA_RATE_QUESTION_ID, + (UINT8) 1, + STRING_TOKEN (STR_COM_DATA_BITS), + STRING_TOKEN (STR_COM_DATA_BITS), + IfrOptionList, + 4, + Location + ); + + Location = Location + (Index + 1) * ((EFI_IFR_OP_HEADER *) Location)->Length; + Location = Location + ((EFI_IFR_OP_HEADER *) Location)->Length; + UpdateData->DataCount = (UINT8) (UpdateData->DataCount + Index); + UpdateData->DataCount += 2; + + SafeFreePool (IfrOptionList); + + IfrOptionList = AllocateZeroPool (sizeof (IFR_OPTION) * 5); + if (!IfrOptionList) { + return ; + } + + for (Index = 0; Index < 5; Index++) { + CheckFlags = EFI_IFR_FLAG_INTERACTIVE; + if (NewTerminalContext->Parity == ParityList[Index].Value) { + CheckFlags |= EFI_IFR_FLAG_DEFAULT; + NewTerminalContext->ParityIndex = (UINT8) Index; + CallbackData->BmmFakeNvData->COMParity = NewTerminalContext->ParityIndex; + } + + IfrOptionList[Index].Flags = CheckFlags; + IfrOptionList[Index].Key = KEY_VALUE_COM_SET_PARITY; + IfrOptionList[Index].StringToken = ParityList[Index].StringToken; + IfrOptionList[Index].Value = Index; + } + + CreateOneOfOpCode ( + (UINT16) COM_PARITY_QUESTION_ID, + (UINT8) 1, + STRING_TOKEN (STR_COM_PARITY), + STRING_TOKEN (STR_COM_PARITY), + IfrOptionList, + 5, + Location + ); + + Location = Location + (Index + 1) * ((EFI_IFR_OP_HEADER *) Location)->Length; + Location = Location + ((EFI_IFR_OP_HEADER *) Location)->Length; + UpdateData->DataCount = (UINT8) (UpdateData->DataCount + Index); + UpdateData->DataCount += 2; + + SafeFreePool (IfrOptionList); + + IfrOptionList = AllocateZeroPool (sizeof (IFR_OPTION) * 3); + if (!IfrOptionList) { + return ; + } + + for (Index = 0; Index < 3; Index++) { + CheckFlags = EFI_IFR_FLAG_INTERACTIVE; + if (NewTerminalContext->StopBits == StopBitsList[Index].Value) { + CheckFlags |= EFI_IFR_FLAG_DEFAULT; + NewTerminalContext->StopBitsIndex = (UINT8) Index; + CallbackData->BmmFakeNvData->COMStopBits = NewTerminalContext->StopBitsIndex; + } + + IfrOptionList[Index].Flags = CheckFlags; + IfrOptionList[Index].Key = KEY_VALUE_COM_SET_STOP_BITS; + IfrOptionList[Index].StringToken = StopBitsList[Index].StringToken; + IfrOptionList[Index].Value = Index; + } + + CreateOneOfOpCode ( + (UINT16) COM_STOP_BITS_QUESTION_ID, + (UINT8) 1, + STRING_TOKEN (STR_COM_STOP_BITS), + STRING_TOKEN (STR_COM_STOP_BITS), + IfrOptionList, + 3, + Location + ); + + Location = Location + (Index + 1) * ((EFI_IFR_OP_HEADER *) Location)->Length; + Location = Location + ((EFI_IFR_OP_HEADER *) Location)->Length; + UpdateData->DataCount = (UINT8) (UpdateData->DataCount + Index); + UpdateData->DataCount += 2; + + SafeFreePool (IfrOptionList); + + IfrOptionList = AllocateZeroPool (sizeof (IFR_OPTION) * 4); + if (!IfrOptionList) { + return ; + } + + for (Index = 0; Index < 4; Index++) { + CheckFlags = EFI_IFR_FLAG_INTERACTIVE; + if (NewTerminalContext->TerminalType == Index) { + CheckFlags |= EFI_IFR_FLAG_DEFAULT; + CallbackData->BmmFakeNvData->COMTerminalType = NewTerminalContext->TerminalType; + } + + IfrOptionList[Index].Flags = CheckFlags; + IfrOptionList[Index].Key = KEY_VALUE_COM_SET_TERMI_TYPE; + IfrOptionList[Index].StringToken = (STRING_REF) TerminalType[Index]; + IfrOptionList[Index].Value = Index; + } + + CreateOneOfOpCode ( + (UINT16) COM_TERMINAL_QUESTION_ID, + (UINT8) 1, + STRING_TOKEN (STR_COM_TERMI_TYPE), + STRING_TOKEN (STR_COM_TERMI_TYPE), + IfrOptionList, + 4, + Location + ); + + Location = Location + (Index + 1) * ((EFI_IFR_OP_HEADER *) Location)->Length; + Location = Location + ((EFI_IFR_OP_HEADER *) Location)->Length; + UpdateData->DataCount = (UINT8) (UpdateData->DataCount + Index); + UpdateData->DataCount += 2; + + SafeFreePool (IfrOptionList); + + CreateGotoOpCode ( + FORM_MAIN_ID, + STRING_TOKEN (STR_SAVE_AND_EXIT), + STRING_TOKEN (STR_NULL_STRING), + EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_NV_ACCESS, + KEY_VALUE_SAVE_AND_EXIT, + Location + ); + + Location = Location + ((EFI_IFR_OP_HEADER *) Location)->Length; + UpdateData->DataCount++; + + CreateGotoOpCode ( + FORM_MAIN_ID, + STRING_TOKEN (STR_NO_SAVE_AND_EXIT), + STRING_TOKEN (STR_NULL_STRING), + EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_NV_ACCESS, + KEY_VALUE_NO_SAVE_AND_EXIT, + Location + ); + + UpdateData->DataCount++; + + CallbackData->Hii->UpdateForm ( + CallbackData->Hii, + CallbackData->BmmHiiHandle, + (EFI_FORM_LABEL) FORM_CON_COM_SETUP_ID, + TRUE, + UpdateData + ); + +} + +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; + } +} + +VOID * +GetLegacyBootOptionVar ( + IN UINTN DeviceType, + OUT UINTN *OptionIndex, + OUT UINTN *OptionSize + ) +{ + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + VOID *OptionBuffer; + UINTN OrderSize; + UINTN Index; + UINT32 Attribute; + UINT16 *OrderBuffer; + CHAR16 StrTemp[100]; + UINT16 FilePathSize; + CHAR16 *Description; + UINT8 *Ptr; + UINT8 *OptionalData; + + // + // Get Boot Option number from the size of BootOrder + // + OrderBuffer = BdsLibGetVariableAndSize ( + L"BootOrder", + &gEfiGlobalVariableGuid, + &OrderSize + ); + + for (Index = 0; Index < OrderSize / sizeof (UINT16); Index++) { + UnicodeSPrint (StrTemp, 100, L"Boot%04x", OrderBuffer[Index]); + OptionBuffer = BdsLibGetVariableAndSize ( + StrTemp, + &gEfiGlobalVariableGuid, + OptionSize + ); + if (NULL == OptionBuffer) { + continue; + } + + Ptr = (UINT8 *) OptionBuffer; + 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; + Ptr += FilePathSize; + + // + // Now Ptr point to Optional Data + // + OptionalData = Ptr; + + if ((DeviceType == ((BBS_TABLE *) OptionalData)->DeviceType) && + (BBS_DEVICE_PATH == DevicePath->Type) && + (BBS_BBS_DP == DevicePath->SubType) + ) { + *OptionIndex = OrderBuffer[Index]; + SafeFreePool (OrderBuffer); + return OptionBuffer; + } else { + SafeFreePool (OptionBuffer); + } + } + + SafeFreePool (OrderBuffer); + return NULL; +} + +VOID +UpdateSetLegacyDeviceOrderPage ( + IN UINT16 UpdatePageId, + IN BMM_CALLBACK_DATA *CallbackData + ) +{ + BM_LEGACY_DEV_ORDER_CONTEXT *DevOrder; + BM_MENU_OPTION *OptionMenu; + BM_MENU_ENTRY *NewMenuEntry; + IFR_OPTION *IfrOptionList; + STRING_REF StrRef; + STRING_REF StrRefHelp; + BBS_TYPE BbsType; + UINTN VarSize; + UINTN Pos; + UINTN Bit; + UINT16 Index; + UINT16 Index2; + UINT16 Key; + CHAR16 String[100]; + CHAR16 *TypeStr; + CHAR16 *TypeStrHelp; + UINT16 VarDevOrder; + UINT8 *Location; + UINT8 *VarData; + UINT8 *OriginalPtr; + UINT8 *LegacyOrder; + UINT8 *OldData; + UINT8 *DisMap; + + OptionMenu = NULL; + Key = 0; + StrRef = 0; + StrRefHelp = 0; + TypeStr = NULL; + TypeStrHelp = NULL; + BbsType = BBS_FLOPPY; + LegacyOrder = NULL; + OldData = NULL; + DisMap = NULL; + + Location = (UINT8 *) &UpdateData->Data; + CallbackData->BmmAskSaveOrNot = TRUE; + + UpdatePageStart (CallbackData, &Location); + + DisMap = CallbackData->BmmOldFakeNVData.DisableMap; + + SetMem (DisMap, 32, 0); + // + // Create oneof option list + // + switch (UpdatePageId) { + case FORM_SET_FD_ORDER_ID: + OptionMenu = (BM_MENU_OPTION *) &LegacyFDMenu; + Key = LEGACY_FD_QUESTION_ID; + TypeStr = StrFloppy; + TypeStrHelp = StrFloppyHelp; + BbsType = BBS_FLOPPY; + LegacyOrder = CallbackData->BmmFakeNvData->LegacyFD; + OldData = CallbackData->BmmOldFakeNVData.LegacyFD; + break; + + case FORM_SET_HD_ORDER_ID: + OptionMenu = (BM_MENU_OPTION *) &LegacyHDMenu; + Key = LEGACY_HD_QUESTION_ID; + TypeStr = StrHardDisk; + TypeStrHelp = StrHardDiskHelp; + BbsType = BBS_HARDDISK; + LegacyOrder = CallbackData->BmmFakeNvData->LegacyHD; + OldData = CallbackData->BmmOldFakeNVData.LegacyHD; + break; + + case FORM_SET_CD_ORDER_ID: + OptionMenu = (BM_MENU_OPTION *) &LegacyCDMenu; + Key = LEGACY_CD_QUESTION_ID; + TypeStr = StrCDROM; + TypeStrHelp = StrCDROMHelp; + BbsType = BBS_CDROM; + LegacyOrder = CallbackData->BmmFakeNvData->LegacyCD; + OldData = CallbackData->BmmOldFakeNVData.LegacyCD; + break; + + case FORM_SET_NET_ORDER_ID: + OptionMenu = (BM_MENU_OPTION *) &LegacyNETMenu; + Key = LEGACY_NET_QUESTION_ID; + TypeStr = StrNET; + TypeStrHelp = StrNETHelp; + BbsType = BBS_EMBED_NETWORK; + LegacyOrder = CallbackData->BmmFakeNvData->LegacyNET; + OldData = CallbackData->BmmOldFakeNVData.LegacyNET; + break; + + case FORM_SET_BEV_ORDER_ID: + OptionMenu = (BM_MENU_OPTION *) &LegacyBEVMenu; + Key = LEGACY_BEV_QUESTION_ID; + TypeStr = StrBEV; + TypeStrHelp = StrBEVHelp; + BbsType = BBS_BEV_DEVICE; + LegacyOrder = CallbackData->BmmFakeNvData->LegacyBEV; + OldData = CallbackData->BmmOldFakeNVData.LegacyBEV; + break; + + } + + CreateMenuStringToken (CallbackData, CallbackData->BmmHiiHandle, OptionMenu); + + IfrOptionList = AllocateZeroPool (sizeof (IFR_OPTION) * (OptionMenu->MenuNumber + 1)); + if (NULL == IfrOptionList) { + return ; + } + + for (Index = 0; Index < OptionMenu->MenuNumber; Index++) { + NewMenuEntry = BOpt_GetMenuEntry (OptionMenu, Index); + IfrOptionList[Index].Flags = EFI_IFR_FLAG_INTERACTIVE; + if (0 == Index) { + IfrOptionList[Index].Flags |= EFI_IFR_FLAG_DEFAULT; + } + + IfrOptionList[Index].Key = Key; + IfrOptionList[Index].StringToken = NewMenuEntry->DisplayStringToken; + IfrOptionList[Index].Value = (UINT16) ((BM_LEGACY_DEVICE_CONTEXT *) NewMenuEntry->VariableContext)->Index; + IfrOptionList[Index].OptionString = NULL; + } + // + // for item "Disabled" + // + IfrOptionList[Index].Flags = EFI_IFR_FLAG_INTERACTIVE; + IfrOptionList[Index].Key = Key; + IfrOptionList[Index].StringToken = STRING_TOKEN (STR_DISABLE_LEGACY_DEVICE); + IfrOptionList[Index].Value = 0xFF; + IfrOptionList[Index].OptionString = NULL; + + // + // Get Device Order from variable + // + VarData = BdsLibGetVariableAndSize ( + VarLegacyDevOrder, + &EfiLegacyDevOrderGuid, + &VarSize + ); + + if (NULL != VarData) { + OriginalPtr = VarData; + DevOrder = (BM_LEGACY_DEV_ORDER_CONTEXT *) VarData; + while (VarData < VarData + VarSize) { + if (DevOrder->BbsType == BbsType) { + break; + } + + VarData += sizeof (BBS_TYPE); + VarData += *(UINT16 *) VarData; + DevOrder = (BM_LEGACY_DEV_ORDER_CONTEXT *) VarData; + } + // + // Create oneof tag here for FD/HD/CD #1 #2 + // + for (Index = 0; Index < OptionMenu->MenuNumber; Index++) { + for (Index2 = 0; Index2 <= OptionMenu->MenuNumber; Index2++) { + IfrOptionList[Index2].Key = (UINT16) (Key + Index); + } + // + // Create the string for oneof tag + // + UnicodeSPrint (String, sizeof (String), TypeStr, Index); + StrRef = 0; + CallbackData->Hii->NewString ( + CallbackData->Hii, + NULL, + CallbackData->BmmHiiHandle, + &StrRef, + String + ); + + UnicodeSPrint (String, sizeof (String), TypeStrHelp, Index); + StrRefHelp = 0; + CallbackData->Hii->NewString ( + CallbackData->Hii, + NULL, + CallbackData->BmmHiiHandle, + &StrRefHelp, + String + ); + + CreateOneOfOpCode ( + (UINT16) (Key + Index), + (UINT8) 1, + StrRef, + StrRefHelp, + IfrOptionList, + OptionMenu->MenuNumber + 1, + Location + ); + + VarDevOrder = *(UINT16 *) ((UINT8 *) DevOrder + sizeof (BBS_TYPE) + sizeof (UINT16) + Index * sizeof (UINT16)); + + if (0xFF00 == (VarDevOrder & 0xFF00)) { + LegacyOrder[Index] = 0xFF; + Pos = (VarDevOrder & 0xFF) / 8; + Bit = 7 - ((VarDevOrder & 0xFF) % 8); + DisMap[Pos] |= (UINT8) (1 << Bit); + } else { + LegacyOrder[Index] = (UINT8) (VarDevOrder & 0xFF); + } + + Location = Location + (OptionMenu->MenuNumber + 2) * ((EFI_IFR_OP_HEADER *) Location)->Length; + Location = Location + ((EFI_IFR_OP_HEADER *) Location)->Length; + UpdateData->DataCount = (UINT16) (UpdateData->DataCount + (OptionMenu->MenuNumber + 3)); + } + } + + CopyMem ( + OldData, + LegacyOrder, + 100 + ); + + if (IfrOptionList != NULL) { + SafeFreePool (IfrOptionList); + IfrOptionList = NULL; + } + + UpdatePageEnd (CallbackData, Location); +} + +VOID +UpdatePageId ( + BMM_CALLBACK_DATA *Private, + UINT16 NewPageId + ) +{ + UINT16 FileOptionMask; + + FileOptionMask = (UINT16) (FILE_OPTION_MASK & 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; + } + + if ((NewPageId > 0) && (NewPageId < MAXIMUM_FORM_ID)) { + Private->BmmPreviousPageId = Private->BmmCurrentPageId; + Private->BmmCurrentPageId = NewPageId; + } +} diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/Variable.c b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/Variable.c new file mode 100644 index 0000000000..d0c5c9bafb --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/Variable.c @@ -0,0 +1,1279 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Variable.c + +Abstract: + + Variable operation that will be used by bootmaint + +--*/ + +#include "Generic/Bds.h" +#include "bootmaint.h" +#include "bdsplatform.h" + +EFI_STATUS +Var_DelBootOption ( + VOID + ) +/*++ + +Routine Description: + Delete Boot Option that represent a Deleted state in BootOptionMenu. + After deleting this boot option, call Var_ChangeBootOrder to + make sure BootOrder is in valid state. + +Arguments: + LoadOption -- Pointer to the boot option that to be deleted + +Returns: + EFI_SUCCESS + Others + +--*/ +{ + BM_MENU_ENTRY *NewMenuEntry; + BM_LOAD_CONTEXT *NewLoadContext; + + UINT16 BootString[10]; + EFI_STATUS Status; + UINTN Index; + UINTN Index2; + + Status = EFI_SUCCESS; + Index2 = 0; + for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) { + NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, (Index - Index2)); + if (NULL == NewMenuEntry) { + return EFI_NOT_FOUND; + } + + NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext; + if (!NewLoadContext->Deleted) { + continue; + } + + UnicodeSPrint ( + BootString, + sizeof (BootString), + L"Boot%04x", + NewMenuEntry->OptionNumber + ); + + EfiLibDeleteVariable (BootString, &gEfiGlobalVariableGuid); + Index2++; + // + // If current Load Option is the same as BootNext, + // must delete BootNext in order to make sure + // there will be no panic on next boot + // + if (NewLoadContext->IsBootNext) { + EfiLibDeleteVariable (L"BootNext", &gEfiGlobalVariableGuid); + } + + RemoveEntryList (&NewMenuEntry->Link); + BOpt_DestroyMenuEntry (NewMenuEntry); + NewMenuEntry = NULL; + } + + BootOptionMenu.MenuNumber -= Index2; + + Status = Var_ChangeBootOrder (); + return Status; +} + +EFI_STATUS +Var_ChangeBootOrder ( + VOID + ) +/*++ + +Routine Description: + After any operation on Boot####, there will be a discrepancy in BootOrder. + Since some are missing but in BootOrder, while some are present but are + not reflected by BootOrder. Then a function rebuild BootOrder from + scratch by content from BootOptionMenu is needed. + +Arguments: + +Returns: + EFI_SUCCESS + Others + +--*/ +{ + + EFI_STATUS Status; + BM_MENU_ENTRY *NewMenuEntry; + UINT16 *BootOrderList; + UINT16 *BootOrderListPtr; + UINTN BootOrderListSize; + UINTN Index; + + BootOrderList = NULL; + BootOrderListSize = 0; + + // + // First check whether BootOrder is present in current configuration + // + BootOrderList = BdsLibGetVariableAndSize ( + L"BootOrder", + &gEfiGlobalVariableGuid, + &BootOrderListSize + ); + + // + // If exists, delete it to hold new BootOrder + // + if (BootOrderList) { + EfiLibDeleteVariable (L"BootOrder", &gEfiGlobalVariableGuid); + SafeFreePool (BootOrderList); + BootOrderList = NULL; + } + // + // Maybe here should be some check method to ensure that + // no new added boot options will be added + // but the setup engine now will give only one callback + // that is to say, user are granted only one chance to + // decide whether the boot option will be added or not + // there should be no indictor to show whether this + // is a "new" boot option + // + BootOrderListSize = BootOptionMenu.MenuNumber; + + if (BootOrderListSize > 0) { + BootOrderList = AllocateZeroPool (BootOrderListSize * sizeof (UINT16)); + ASSERT (BootOrderList != NULL); + BootOrderListPtr = BootOrderList; + + // + // Get all current used Boot#### from BootOptionMenu. + // OptionNumber in each BM_LOAD_OPTION is really its + // #### value. + // + for (Index = 0; Index < BootOrderListSize; Index++) { + NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index); + *BootOrderList = (UINT16) NewMenuEntry->OptionNumber; + BootOrderList++; + } + + BootOrderList = BootOrderListPtr; + + // + // After building the BootOrderList, write it back + // + Status = gRT->SetVariable ( + L"BootOrder", + &gEfiGlobalVariableGuid, + VAR_FLAG, + BootOrderListSize * sizeof (UINT16), + BootOrderList + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + return EFI_SUCCESS; +} + +EFI_STATUS +Var_DelDriverOption ( + VOID + ) +/*++ + +Routine Description: + Delete Load Option that represent a Deleted state in BootOptionMenu. + After deleting this Driver option, call Var_ChangeDriverOrder to + make sure DriverOrder is in valid state. + +Arguments: + LoadOption -- Pointer to the Driver option that to be deleted + +Returns: + EFI_SUCCESS + Others + +--*/ +{ + BM_MENU_ENTRY *NewMenuEntry; + BM_LOAD_CONTEXT *NewLoadContext; + + UINT16 DriverString[12]; + EFI_STATUS Status; + UINTN Index; + UINTN Index2; + + Status = EFI_SUCCESS; + Index2 = 0; + for (Index = 0; Index < DriverOptionMenu.MenuNumber; Index++) { + NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, (Index - Index2)); + if (NULL == NewMenuEntry) { + return EFI_NOT_FOUND; + } + + NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext; + if (!NewLoadContext->Deleted) { + continue; + } + + UnicodeSPrint ( + DriverString, + sizeof (DriverString), + L"Driver%04x", + NewMenuEntry->OptionNumber + ); + + EfiLibDeleteVariable (DriverString, &gEfiGlobalVariableGuid); + Index2++; + + RemoveEntryList (&NewMenuEntry->Link); + BOpt_DestroyMenuEntry (NewMenuEntry); + NewMenuEntry = NULL; + } + + DriverOptionMenu.MenuNumber -= Index2; + + Status = Var_ChangeDriverOrder (); + return Status; +} + +EFI_STATUS +Var_ChangeDriverOrder ( + VOID + ) +/*++ + +Routine Description: + After any operation on Driver####, there will be a discrepancy in + DriverOrder. Since some are missing but in DriverOrder, while some + are present but are not reflected by DriverOrder. Then a function + rebuild DriverOrder from scratch by content from DriverOptionMenu is + needed. + +Arguments: + +Returns: + EFI_SUCCESS + Others + +--*/ +{ + EFI_STATUS Status; + BM_MENU_ENTRY *NewMenuEntry; + UINT16 *DriverOrderList; + UINT16 *DriverOrderListPtr; + UINTN DriverOrderListSize; + UINTN Index; + + DriverOrderList = NULL; + DriverOrderListSize = 0; + + // + // First check whether DriverOrder is present in current configuration + // + DriverOrderList = BdsLibGetVariableAndSize ( + L"DriverOrder", + &gEfiGlobalVariableGuid, + &DriverOrderListSize + ); + + // + // If exists, delete it to hold new DriverOrder + // + if (DriverOrderList) { + EfiLibDeleteVariable (L"DriverOrder", &gEfiGlobalVariableGuid); + SafeFreePool (DriverOrderList); + DriverOrderList = NULL; + } + + DriverOrderListSize = DriverOptionMenu.MenuNumber; + + if (DriverOrderListSize > 0) { + DriverOrderList = AllocateZeroPool (DriverOrderListSize * sizeof (UINT16)); + ASSERT (DriverOrderList != NULL); + DriverOrderListPtr = DriverOrderList; + + // + // Get all current used Driver#### from DriverOptionMenu. + // OptionNumber in each BM_LOAD_OPTION is really its + // #### value. + // + for (Index = 0; Index < DriverOrderListSize; Index++) { + NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, Index); + *DriverOrderList = (UINT16) NewMenuEntry->OptionNumber; + DriverOrderList++; + } + + DriverOrderList = DriverOrderListPtr; + + // + // After building the DriverOrderList, write it back + // + Status = gRT->SetVariable ( + L"DriverOrder", + &gEfiGlobalVariableGuid, + VAR_FLAG, + DriverOrderListSize * sizeof (UINT16), + DriverOrderList + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + return EFI_SUCCESS; +} + +VOID +Var_UpdateAllConsoleOption ( + VOID + ) +{ + EFI_DEVICE_PATH_PROTOCOL *OutDevicePath; + EFI_DEVICE_PATH_PROTOCOL *InpDevicePath; + EFI_DEVICE_PATH_PROTOCOL *ErrDevicePath; + EFI_STATUS Status; + + OutDevicePath = EfiLibGetVariable (L"ConOut", &gEfiGlobalVariableGuid); + InpDevicePath = EfiLibGetVariable (L"ConIn", &gEfiGlobalVariableGuid); + ErrDevicePath = EfiLibGetVariable (L"ErrOut", &gEfiGlobalVariableGuid); + if (OutDevicePath) { + ChangeVariableDevicePath (OutDevicePath); + Status = gRT->SetVariable ( + L"ConOut", + &gEfiGlobalVariableGuid, + VAR_FLAG, + GetDevicePathSize (OutDevicePath), + OutDevicePath + ); + ASSERT (!EFI_ERROR (Status)); + } + + if (InpDevicePath) { + ChangeVariableDevicePath (InpDevicePath); + Status = gRT->SetVariable ( + L"ConIn", + &gEfiGlobalVariableGuid, + VAR_FLAG, + GetDevicePathSize (InpDevicePath), + InpDevicePath + ); + ASSERT (!EFI_ERROR (Status)); + } + + if (ErrDevicePath) { + ChangeVariableDevicePath (ErrDevicePath); + Status = gRT->SetVariable ( + L"ErrOut", + &gEfiGlobalVariableGuid, + VAR_FLAG, + GetDevicePathSize (ErrDevicePath), + ErrDevicePath + ); + ASSERT (!EFI_ERROR (Status)); + } +} + +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; + UINT16 *Temp; + + ConDevicePath = EfiLibGetVariable (ConsoleName, &gEfiGlobalVariableGuid); + if (ConDevicePath != NULL) { + EfiLibDeleteVariable (ConsoleName, &gEfiGlobalVariableGuid); + SafeFreePool (ConDevicePath); + ConDevicePath = NULL; + }; + + // + // First add all console input device to it from console input menu + // + for (Index = 0; Index < ConsoleMenu->MenuNumber; Index++) { + NewMenuEntry = BOpt_GetMenuEntry (ConsoleMenu, Index); + if (NULL == NewMenuEntry) { + return EFI_NOT_FOUND; + } + + 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); + if (NULL == NewMenuEntry) { + return EFI_NOT_FOUND; + } + + NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext; + if ((NewTerminalContext->IsConIn && (UpdatePageId == FORM_CON_IN_ID)) || + (NewTerminalContext->IsConOut && (UpdatePageId == FORM_CON_OUT_ID)) || + (NewTerminalContext->IsStdErr && (UpdatePageId == FORM_CON_ERR_ID)) + ) { + Vendor.Header.Type = MESSAGING_DEVICE_PATH; + Vendor.Header.SubType = MSG_VENDOR_DP; + CopyMem ( + &Vendor.Guid, + &Guid[NewTerminalContext->TerminalType], + sizeof (EFI_GUID) + ); + SetDevicePathNodeLength (&Vendor.Header, sizeof (VENDOR_DEVICE_PATH)); + TerminalDevicePath = AppendDevicePathNode ( + NewTerminalContext->DevicePath, + (EFI_DEVICE_PATH_PROTOCOL *) &Vendor + ); + ChangeTerminalDevicePath (TerminalDevicePath, TRUE); + Temp = DevicePathToStr (TerminalDevicePath); + ConDevicePath = AppendDevicePathInstance ( + ConDevicePath, + TerminalDevicePath + ); + } + } + + if (ConDevicePath) { + Status = gRT->SetVariable ( + ConsoleName, + &gEfiGlobalVariableGuid, + VAR_FLAG, + GetDevicePathSize (ConDevicePath), + ConDevicePath + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + + return EFI_SUCCESS; + +} + +EFI_STATUS +Var_UpdateConsoleInpOption ( + VOID + ) +{ + return Var_UpdateConsoleOption (L"ConIn", &ConsoleInpMenu, FORM_CON_IN_ID); +} + +EFI_STATUS +Var_UpdateConsoleOutOption ( + VOID + ) +{ + return Var_UpdateConsoleOption (L"ConOut", &ConsoleOutMenu, FORM_CON_OUT_ID); +} + +EFI_STATUS +Var_UpdateErrorOutOption ( + VOID + ) +{ + return Var_UpdateConsoleOption (L"ErrOut", &ConsoleErrMenu, FORM_CON_ERR_ID); +} + +EFI_STATUS +Var_UpdateDriverOption ( + IN BMM_CALLBACK_DATA *CallbackData, + IN EFI_HII_HANDLE HiiHandle, + IN UINT16 *DescriptionData, + IN UINT16 *OptionalData, + IN UINT8 ForceReconnect + ) +{ + UINT16 Index; + UINT16 *DriverOrderList; + UINT16 *NewDriverOrderList; + UINT16 DriverString[12]; + UINTN DriverOrderListSize; + VOID *Buffer; + UINTN BufferSize; + UINT8 *Ptr; + BM_MENU_ENTRY *NewMenuEntry; + BM_LOAD_CONTEXT *NewLoadContext; + BOOLEAN OptionalDataExist; + EFI_STATUS Status; + + OptionalDataExist = FALSE; + + Index = BOpt_GetDriverOptionNumber (); + UnicodeSPrint ( + DriverString, + sizeof (DriverString), + L"Driver%04x", + Index + ); + + if (*DescriptionData == 0x0000) { + StrCpy (DescriptionData, DriverString); + } + + BufferSize = sizeof (UINT32) + sizeof (UINT16) + StrSize (DescriptionData) + GetDevicePathSize (CallbackData->LoadContext->FilePathList); + + if (*OptionalData != 0x0000) { + OptionalDataExist = TRUE; + BufferSize += StrSize (OptionalData); + } + + Buffer = AllocateZeroPool (BufferSize); + if (NULL == Buffer) { + return EFI_OUT_OF_RESOURCES; + } + + NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT); + if (NULL == NewMenuEntry) { + return EFI_OUT_OF_RESOURCES; + } + + NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext; + NewLoadContext->Deleted = FALSE; + NewLoadContext->LoadOptionSize = BufferSize; + Ptr = (UINT8 *) Buffer; + NewLoadContext->LoadOption = Ptr; + *((UINT32 *) Ptr) = LOAD_OPTION_ACTIVE | (ForceReconnect << 1); + NewLoadContext->Attributes = *((UINT32 *) Ptr); + NewLoadContext->IsActive = TRUE; + NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT); + + Ptr += sizeof (UINT32); + *((UINT16 *) Ptr) = (UINT16) GetDevicePathSize (CallbackData->LoadContext->FilePathList); + NewLoadContext->FilePathListLength = *((UINT16 *) Ptr); + + Ptr += sizeof (UINT16); + CopyMem ( + Ptr, + DescriptionData, + StrSize (DescriptionData) + ); + + NewLoadContext->Description = AllocateZeroPool (StrSize (DescriptionData)); + ASSERT (NewLoadContext->Description != NULL); + NewMenuEntry->DisplayString = NewLoadContext->Description; + CopyMem ( + NewLoadContext->Description, + (VOID *) Ptr, + StrSize (DescriptionData) + ); + + Ptr += StrSize (DescriptionData); + CopyMem ( + Ptr, + CallbackData->LoadContext->FilePathList, + GetDevicePathSize (CallbackData->LoadContext->FilePathList) + ); + + NewLoadContext->FilePathList = AllocateZeroPool (GetDevicePathSize (CallbackData->LoadContext->FilePathList)); + ASSERT (NewLoadContext->FilePathList != NULL); + + CopyMem ( + NewLoadContext->FilePathList, + (VOID *) Ptr, + GetDevicePathSize (CallbackData->LoadContext->FilePathList) + ); + + NewMenuEntry->HelpString = DevicePathToStr (NewLoadContext->FilePathList); + NewMenuEntry->OptionNumber = Index; + NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository ( + CallbackData, + DriverOptionStrDepository + ); + CallbackData->Hii->NewString ( + CallbackData->Hii, + NULL, + HiiHandle, + &NewMenuEntry->DisplayStringToken, + NewMenuEntry->DisplayString + ); + + NewMenuEntry->HelpStringToken = GetStringTokenFromDepository ( + CallbackData, + DriverOptionHelpStrDepository + ); + CallbackData->Hii->NewString ( + CallbackData->Hii, + NULL, + HiiHandle, + &NewMenuEntry->HelpStringToken, + NewMenuEntry->HelpString + ); + + if (OptionalDataExist) { + Ptr += (UINT8) GetDevicePathSize (CallbackData->LoadContext->FilePathList); + + CopyMem ( + Ptr, + OptionalData, + StrSize (OptionalData) + ); + } + + Status = gRT->SetVariable ( + DriverString, + &gEfiGlobalVariableGuid, + VAR_FLAG, + BufferSize, + Buffer + ); + DriverOrderList = BdsLibGetVariableAndSize ( + L"DriverOrder", + &gEfiGlobalVariableGuid, + &DriverOrderListSize + ); + NewDriverOrderList = AllocateZeroPool (DriverOrderListSize + sizeof (UINT16)); + ASSERT (NewDriverOrderList != NULL); + CopyMem (NewDriverOrderList, DriverOrderList, DriverOrderListSize); + NewDriverOrderList[DriverOrderListSize / sizeof (UINT16)] = Index; + if (DriverOrderList != NULL) { + EfiLibDeleteVariable (L"DriverOrder", &gEfiGlobalVariableGuid); + } + + Status = gRT->SetVariable ( + L"DriverOrder", + &gEfiGlobalVariableGuid, + VAR_FLAG, + DriverOrderListSize + sizeof (UINT16), + NewDriverOrderList + ); + SafeFreePool (DriverOrderList); + DriverOrderList = NULL; + SafeFreePool (NewDriverOrderList); + NewDriverOrderList = NULL; + InsertTailList (&DriverOptionMenu.Head, &NewMenuEntry->Link); + DriverOptionMenu.MenuNumber++; + + *DescriptionData = 0x0000; + *OptionalData = 0x0000; + return EFI_SUCCESS; +} + +EFI_STATUS +Var_UpdateBootOption ( + IN BMM_CALLBACK_DATA *CallbackData, + IN FILE_EXPLORER_NV_DATA *NvRamMap + ) +{ + UINT16 *BootOrderList; + UINT16 *NewBootOrderList; + UINTN BootOrderListSize; + UINT16 BootString[10]; + VOID *Buffer; + UINTN BufferSize; + UINT8 *Ptr; + UINT16 Index; + BM_MENU_ENTRY *NewMenuEntry; + BM_LOAD_CONTEXT *NewLoadContext; + BOOLEAN OptionalDataExist; + EFI_STATUS Status; + + OptionalDataExist = FALSE; + + Index = BOpt_GetBootOptionNumber (); + UnicodeSPrint (BootString, sizeof (BootString), L"Boot%04x", Index); + + if (NvRamMap->DescriptionData[0] == 0x0000) { + StrCpy (NvRamMap->DescriptionData, BootString); + } + + BufferSize = sizeof (UINT32) + sizeof (UINT16) + StrSize (NvRamMap->DescriptionData) + GetDevicePathSize (CallbackData->LoadContext->FilePathList); + + if (NvRamMap->OptionalData[0] != 0x0000) { + OptionalDataExist = TRUE; + BufferSize += StrSize (NvRamMap->OptionalData); + } + + Buffer = AllocateZeroPool (BufferSize); + if (NULL == Buffer) { + return EFI_OUT_OF_RESOURCES; + } + + NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT); + if (NULL == NewMenuEntry) { + return EFI_OUT_OF_RESOURCES; + } + + NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext; + NewLoadContext->Deleted = FALSE; + NewLoadContext->LoadOptionSize = BufferSize; + Ptr = (UINT8 *) Buffer; + NewLoadContext->LoadOption = Ptr; + *((UINT32 *) Ptr) = LOAD_OPTION_ACTIVE; + NewLoadContext->Attributes = *((UINT32 *) Ptr); + NewLoadContext->IsActive = TRUE; + NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT); + + Ptr += sizeof (UINT32); + *((UINT16 *) Ptr) = (UINT16) GetDevicePathSize (CallbackData->LoadContext->FilePathList); + NewLoadContext->FilePathListLength = *((UINT16 *) Ptr); + Ptr += sizeof (UINT16); + + CopyMem ( + Ptr, + NvRamMap->DescriptionData, + StrSize (NvRamMap->DescriptionData) + ); + + NewLoadContext->Description = AllocateZeroPool (StrSize (NvRamMap->DescriptionData)); + ASSERT (NewLoadContext->Description != NULL); + + NewMenuEntry->DisplayString = NewLoadContext->Description; + CopyMem ( + NewLoadContext->Description, + (VOID *) Ptr, + StrSize (NvRamMap->DescriptionData) + ); + + Ptr += StrSize (NvRamMap->DescriptionData); + CopyMem ( + Ptr, + CallbackData->LoadContext->FilePathList, + GetDevicePathSize (CallbackData->LoadContext->FilePathList) + ); + + NewLoadContext->FilePathList = AllocateZeroPool (GetDevicePathSize (CallbackData->LoadContext->FilePathList)); + ASSERT (NewLoadContext->FilePathList != NULL); + + CopyMem ( + NewLoadContext->FilePathList, + (VOID *) Ptr, + GetDevicePathSize (CallbackData->LoadContext->FilePathList) + ); + + NewMenuEntry->HelpString = DevicePathToStr (NewLoadContext->FilePathList); + NewMenuEntry->OptionNumber = Index; + NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository ( + CallbackData, + BootOptionStrDepository + ); + CallbackData->Hii->NewString ( + CallbackData->Hii, + NULL, + CallbackData->FeHiiHandle, + &NewMenuEntry->DisplayStringToken, + NewMenuEntry->DisplayString + ); + + NewMenuEntry->HelpStringToken = GetStringTokenFromDepository ( + CallbackData, + BootOptionHelpStrDepository + ); + + CallbackData->Hii->NewString ( + CallbackData->Hii, + NULL, + CallbackData->FeHiiHandle, + &NewMenuEntry->HelpStringToken, + NewMenuEntry->HelpString + ); + + if (OptionalDataExist) { + Ptr += (UINT8) GetDevicePathSize (CallbackData->LoadContext->FilePathList); + + CopyMem (Ptr, NvRamMap->OptionalData, StrSize (NvRamMap->OptionalData)); + } + + Status = gRT->SetVariable ( + BootString, + &gEfiGlobalVariableGuid, + VAR_FLAG, + BufferSize, + Buffer + ); + + BootOrderList = BdsLibGetVariableAndSize ( + L"BootOrder", + &gEfiGlobalVariableGuid, + &BootOrderListSize + ); + + NewBootOrderList = AllocateZeroPool (BootOrderListSize + sizeof (UINT16)); + ASSERT (NewBootOrderList != NULL); + CopyMem (NewBootOrderList, BootOrderList, BootOrderListSize); + NewBootOrderList[BootOrderListSize / sizeof (UINT16)] = Index; + + if (BootOrderList != NULL) { + EfiLibDeleteVariable (L"BootOrder", &gEfiGlobalVariableGuid); + } + + Status = gRT->SetVariable ( + L"BootOrder", + &gEfiGlobalVariableGuid, + VAR_FLAG, + BootOrderListSize + sizeof (UINT16), + NewBootOrderList + ); + + SafeFreePool (BootOrderList); + BootOrderList = NULL; + SafeFreePool (NewBootOrderList); + NewBootOrderList = NULL; + InsertTailList (&BootOptionMenu.Head, &NewMenuEntry->Link); + BootOptionMenu.MenuNumber++; + + NvRamMap->DescriptionData[0] = 0x0000; + NvRamMap->OptionalData[0] = 0x0000; + return EFI_SUCCESS; +} + +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); + if (NULL == NewMenuEntry) { + return EFI_NOT_FOUND; + } + + NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext; + NewLoadContext->IsBootNext = FALSE; + } + + if (CurrentFakeNVMap->BootNext == BootOptionMenu.MenuNumber) { + EfiLibDeleteVariable (L"BootNext", &gEfiGlobalVariableGuid); + return EFI_SUCCESS; + } + + NewMenuEntry = BOpt_GetMenuEntry ( + &BootOptionMenu, + CurrentFakeNVMap->BootNext + ); + if (NULL == NewMenuEntry) { + return EFI_NOT_FOUND; + } + + 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; +} + +EFI_STATUS +Var_UpdateBootOrder ( + IN BMM_CALLBACK_DATA *CallbackData + ) +{ + EFI_STATUS Status; + UINT16 Index; + UINT16 *BootOrderList; + UINT16 *NewBootOrderList; + UINTN BootOrderListSize; + UINT8 *Map; + + BootOrderList = NULL; + BootOrderListSize = 0; + + // + // First check whether BootOrder is present in current configuration + // + BootOrderList = BdsLibGetVariableAndSize ( + L"BootOrder", + &gEfiGlobalVariableGuid, + &BootOrderListSize + ); + + NewBootOrderList = AllocateZeroPool (BootOrderListSize); + if (!NewBootOrderList) { + return EFI_OUT_OF_RESOURCES; + } + + Map = AllocateZeroPool (BootOrderListSize / sizeof (UINT16)); + if (!Map) { + return EFI_OUT_OF_RESOURCES; + } + // + // If exists, delete it to hold new BootOrder + // + if (BootOrderList) { + EfiLibDeleteVariable (L"BootOrder", &gEfiGlobalVariableGuid); + } + + for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) { + NewBootOrderList[Index] = CallbackData->BmmFakeNvData->OptionOrder[Index] - 1; + } + + Status = gRT->SetVariable ( + L"BootOrder", + &gEfiGlobalVariableGuid, + VAR_FLAG, + BootOrderListSize, + NewBootOrderList + ); + SafeFreePool (BootOrderList); + SafeFreePool (NewBootOrderList); + SafeFreePool (Map); + if (EFI_ERROR (Status)) { + return Status; + } + + BOpt_FreeMenu (&BootOptionMenu); + BOpt_GetBootOptions (CallbackData); + + return EFI_SUCCESS; + +} + +EFI_STATUS +Var_UpdateDriverOrder ( + IN BMM_CALLBACK_DATA *CallbackData + ) +{ + EFI_STATUS Status; + UINT16 Index; + UINT16 *DriverOrderList; + UINT16 *NewDriverOrderList; + UINTN DriverOrderListSize; + + DriverOrderList = NULL; + DriverOrderListSize = 0; + + // + // First check whether DriverOrder is present in current configuration + // + DriverOrderList = BdsLibGetVariableAndSize ( + L"DriverOrder", + &gEfiGlobalVariableGuid, + &DriverOrderListSize + ); + + NewDriverOrderList = AllocateZeroPool (DriverOrderListSize); + + if (!NewDriverOrderList) { + return EFI_OUT_OF_RESOURCES; + } + // + // If exists, delete it to hold new DriverOrder + // + if (DriverOrderList) { + EfiLibDeleteVariable (L"DriverOrder", &gEfiGlobalVariableGuid); + } + + for (Index = 0; Index < DriverOrderListSize; Index++) { + NewDriverOrderList[Index] = CallbackData->BmmFakeNvData->OptionOrder[Index] - 1; + } + + Status = gRT->SetVariable ( + L"DriverOrder", + &gEfiGlobalVariableGuid, + VAR_FLAG, + DriverOrderListSize, + NewDriverOrderList + ); + if (EFI_ERROR (Status)) { + return Status; + } + + SafeFreePool (DriverOrderList); + + BOpt_FreeMenu (&DriverOptionMenu); + BOpt_GetDriverOptions (CallbackData); + return EFI_SUCCESS; +} + +EFI_STATUS +Var_UpdateBBSOption ( + IN BMM_CALLBACK_DATA *CallbackData + ) +{ + UINTN Index; + UINTN Index2; + VOID *BootOptionVar; + CHAR16 VarName[100]; + UINTN OptionSize; + UINT16 FilePathSize; + UINT8 *Ptr; + EFI_STATUS Status; + CHAR16 DescString[100]; + UINTN NewOptionSize; + UINT8 *NewOptionPtr; + UINT8 *TempPtr; + UINT32 *Attribute; + + BM_MENU_OPTION *OptionMenu; + BM_LEGACY_DEVICE_CONTEXT *LegacyDeviceContext; + UINT8 *LegacyDev; + UINT8 *VarData; + UINTN VarSize; + BM_MENU_ENTRY *NewMenuEntry; + BM_LEGACY_DEV_ORDER_CONTEXT *DevOrder; + UINT8 *OriginalPtr; + UINT8 *DisMap; + UINTN Pos; + UINTN Bit; + UINT16 *NewOrder; + UINT16 Tmp; + + LegacyDeviceContext = NULL; + DisMap = NULL; + NewOrder = NULL; + + if (FORM_SET_FD_ORDER_ID == CallbackData->BmmPreviousPageId) { + OptionMenu = (BM_MENU_OPTION *) &LegacyFDMenu; + LegacyDev = CallbackData->BmmFakeNvData->LegacyFD; + CallbackData->BbsType = BBS_FLOPPY; + } else { + if (FORM_SET_HD_ORDER_ID == CallbackData->BmmPreviousPageId) { + OptionMenu = (BM_MENU_OPTION *) &LegacyHDMenu; + LegacyDev = CallbackData->BmmFakeNvData->LegacyHD; + CallbackData->BbsType = BBS_HARDDISK; + } else { + if (FORM_SET_CD_ORDER_ID == CallbackData->BmmPreviousPageId) { + OptionMenu = (BM_MENU_OPTION *) &LegacyCDMenu; + LegacyDev = CallbackData->BmmFakeNvData->LegacyCD; + CallbackData->BbsType = BBS_CDROM; + } else { + if (FORM_SET_NET_ORDER_ID == CallbackData->BmmPreviousPageId) { + OptionMenu = (BM_MENU_OPTION *) &LegacyNETMenu; + LegacyDev = CallbackData->BmmFakeNvData->LegacyNET; + CallbackData->BbsType = BBS_EMBED_NETWORK; + } else { + OptionMenu = (BM_MENU_OPTION *) &LegacyBEVMenu; + LegacyDev = CallbackData->BmmFakeNvData->LegacyBEV; + CallbackData->BbsType = BBS_BEV_DEVICE; + } + } + } + } + + DisMap = CallbackData->BmmOldFakeNVData.DisableMap; + Status = EFI_SUCCESS; + + // + // Find the first device's context + // If all devices are disabled( 0xFF == LegacyDev[0]), LegacyDeviceContext can be set to any VariableContext + // because we just use it to fill the desc string, and user can not see the string in UI + // + for (Index = 0; Index < OptionMenu->MenuNumber; Index++) { + NewMenuEntry = BOpt_GetMenuEntry (OptionMenu, Index); + LegacyDeviceContext = (BM_LEGACY_DEVICE_CONTEXT *) NewMenuEntry->VariableContext; + if (0xFF != LegacyDev[0] && LegacyDev[0] == LegacyDeviceContext->Index) { + DEBUG ((EFI_D_ERROR, "DescStr: %s\n", LegacyDeviceContext->Description)); + break; + } + } + // + // Update the Variable "LegacyDevOrder" + // + VarData = (UINT8 *) BdsLibGetVariableAndSize ( + VarLegacyDevOrder, + &EfiLegacyDevOrderGuid, + &VarSize + ); + + if (NULL == VarData) { + return EFI_NOT_FOUND; + } + + OriginalPtr = VarData; + DevOrder = (BM_LEGACY_DEV_ORDER_CONTEXT *) VarData; + + while (VarData < VarData + VarSize) { + if (DevOrder->BbsType == CallbackData->BbsType) { + break; + } + + VarData += sizeof (BBS_TYPE); + VarData += *(UINT16 *) VarData; + DevOrder = (BM_LEGACY_DEV_ORDER_CONTEXT *) VarData; + } + + if (VarData >= VarData + VarSize) { + SafeFreePool (OriginalPtr); + return EFI_NOT_FOUND; + } + + NewOrder = (UINT16 *) AllocateZeroPool (DevOrder->Length - sizeof (UINT16)); + if (NULL == NewOrder) { + SafeFreePool (VarData); + return EFI_OUT_OF_RESOURCES; + } + + for (Index = 0; Index < OptionMenu->MenuNumber; Index++) { + if (0xFF == LegacyDev[Index]) { + break; + } + + NewOrder[Index] = LegacyDev[Index]; + } + // + // Only the enable/disable state of each boot device with same device type can be changed, + // so we can count on the index information in DevOrder. + // DisMap bit array is the only reliable source to check a device's en/dis state, + // so we use DisMap to set en/dis state of each item in NewOrder array + // + for (Index2 = 0; Index2 < OptionMenu->MenuNumber; Index2++) { + Tmp = *(UINT16 *) ((UINT8 *) DevOrder + sizeof (BBS_TYPE) + sizeof (UINT16) + Index2 * sizeof (UINT16)); + Tmp &= 0xFF; + Pos = Tmp / 8; + Bit = 7 - (Tmp % 8); + if (DisMap[Pos] & (1 << Bit)) { + NewOrder[Index] = (UINT16) (0xFF00 | Tmp); + Index++; + } + } + + CopyMem ( + (UINT8 *) DevOrder + sizeof (BBS_TYPE) + sizeof (UINT16), + NewOrder, + DevOrder->Length - sizeof (UINT16) + ); + SafeFreePool (NewOrder); + + Status = gRT->SetVariable ( + VarLegacyDevOrder, + &EfiLegacyDevOrderGuid, + VAR_FLAG, + VarSize, + OriginalPtr + ); + + SafeFreePool (OriginalPtr); + + // + // Update Optional Data of Boot#### + // + BootOptionVar = GetLegacyBootOptionVar (CallbackData->BbsType, &Index, &OptionSize); + + if (NULL != BootOptionVar) { + CopyMem ( + DescString, + LegacyDeviceContext->Description, + StrSize (LegacyDeviceContext->Description) + ); + + NewOptionSize = sizeof (UINT32) + sizeof (UINT16) + StrSize (DescString) + sizeof (BBS_TABLE) + sizeof (UINT16); + + UnicodeSPrint (VarName, 100, L"Boot%04x", Index); + + Ptr = BootOptionVar; + + Attribute = (UINT32 *) Ptr; + *Attribute |= LOAD_OPTION_ACTIVE; + if (0xFF == LegacyDev[0]) { + // + // Disable this legacy boot option + // + *Attribute &= ~LOAD_OPTION_ACTIVE; + } + + Ptr += sizeof (UINT32); + + FilePathSize = *(UINT16 *) Ptr; + Ptr += sizeof (UINT16); + + NewOptionSize += FilePathSize; + + NewOptionPtr = AllocateZeroPool (NewOptionSize); + if (NULL == NewOptionPtr) { + return EFI_OUT_OF_RESOURCES; + } + + TempPtr = NewOptionPtr; + + // + // Copy previous option data to new option except the description string + // + CopyMem ( + TempPtr, + BootOptionVar, + sizeof (UINT32) + sizeof (UINT16) + ); + + TempPtr += (sizeof (UINT32) + sizeof (UINT16)); + + CopyMem ( + TempPtr, + DescString, + StrSize (DescString) + ); + + TempPtr += StrSize (DescString); + + // + // Description = (CHAR16 *)Ptr; + // + Ptr += StrSize ((CHAR16 *) Ptr); + + CopyMem ( + TempPtr, + Ptr, + FilePathSize + ); + + TempPtr += FilePathSize; + + // + // DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)Ptr; + // + Ptr += FilePathSize; + + // + // Now Ptr point to optional data, i.e. Bbs Table + // + CopyMem ( + TempPtr, + LegacyDeviceContext->BbsTable, + sizeof (BBS_TABLE) + ); + + TempPtr += sizeof (BBS_TABLE); + *((UINT16 *) TempPtr) = (UINT16) LegacyDeviceContext->Index; + + Status = gRT->SetVariable ( + VarName, + &gEfiGlobalVariableGuid, + VAR_FLAG, + NewOptionSize, + NewOptionPtr + ); + + SafeFreePool (NewOptionPtr); + SafeFreePool (BootOptionVar); + } + + BOpt_GetBootOptions (CallbackData); + return Status; +} diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/bm.vfr b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/bm.vfr new file mode 100644 index 0000000000..e907e18d6c --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/bm.vfr @@ -0,0 +1,495 @@ +// *++ +// +// Copyright (c) 2006, Intel Corporation +// All rights reserved. This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// Module Name: +// +// bm.vfr +// +// Abstract: +// +// Boot Maintenance Utility Formset +// +// Revision History: +// +// --*/ + +#include "BdsStrDefs.h" +#include "formguid.h" + +#pragma pack(1) + +// +// This is the structure that will be used to store the +// question's current value. Use it at initialize time to +// set default value for each question. When using at run +// time, this map is returned by the callback function, +// so dynamically changing the question's value will be +// possible through this mechanism +// +typedef struct { + +// +// Three questions displayed at the main page +// for Timeout, BootNext Variables respectively +// + UINT16 BootTimeOut; + UINT16 BootNext; + +// +// This is the COM1 Attributes value storage +// + UINT8 COM1BaudRate; + UINT8 COM1DataRate; + UINT8 COM1StopBits; + UINT8 COM1Parity; + UINT8 COM1TerminalType; + +// +// This is the COM2 Attributes value storage +// + UINT8 COM2BaudRate; + UINT8 COM2DataRate; + UINT8 COM2StopBits; + UINT8 COM2Parity; + UINT8 COM2TerminalType; + +// +// Driver Option Add Handle page storage +// + UINT16 DriverAddHandleDesc[100]; + UINT16 DriverAddHandleOptionalData[100]; + 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[100]; + +// +// Boot or Driver Option Order storage +// + UINT8 OptionOrder[100]; + UINT8 DriverOptionToBeDeleted[100]; + +// +// Boot Option Delete storage +// + UINT8 BootOptionDel[100]; + UINT8 DriverOptionDel[100]; + +// +// This is the Terminal Attributes value storage +// + UINT8 COMBaudRate; + UINT8 COMDataRate; + UINT8 COMStopBits; + UINT8 COMParity; + UINT8 COMTerminalType; + +// +// Legacy Device Order Selection Storage +// + UINT8 LegacyFD[100]; + UINT8 LegacyHD[100]; + UINT8 LegacyCD[100]; + UINT8 LegacyNET[100]; + UINT8 LegacyBEV[100]; +} BMM_FAKE_NV_DATA; +#pragma pack() + + +#define FORM_MAIN_ID 0x0001 +#define FORM_BOOT_ADD_ID 0x0002 +#define FORM_BOOT_DEL_ID 0x0003 +#define FORM_BOOT_CHG_ID 0x0004 +#define FORM_DRV_ADD_ID 0x0005 +#define FORM_DRV_DEL_ID 0x0006 +#define FORM_DRV_CHG_ID 0x0007 +#define FORM_CON_MAIN_ID 0x0008 +#define FORM_CON_IN_ID 0x0009 +#define FORM_CON_OUT_ID 0x000A +#define FORM_CON_ERR_ID 0x000B +#define FORM_FILE_SEEK_ID 0x000C +#define FORM_FILE_NEW_SEEK_ID 0x000D +#define FORM_DRV_ADD_FILE_ID 0x000E +#define FORM_DRV_ADD_HANDLE_ID 0x000F +#define FORM_DRV_ADD_HANDLE_DESC_ID 0x0010 +#define FORM_BOOT_NEXT_ID 0x0011 +#define FORM_TIME_OUT_ID 0x0012 +#define FORM_RESET 0x0013 +#define FORM_BOOT_SETUP_ID 0x0014 +#define FORM_DRIVER_SETUP_ID 0x0015 +#define FORM_BOOT_LEGACY_DEVICE_ID 0x0016 +#define FORM_CON_COM_ID 0x0017 +#define FORM_CON_COM_SETUP_ID 0x0018 +#define FORM_SET_FD_ORDER_ID 0x0019 +#define FORM_SET_HD_ORDER_ID 0x001A +#define FORM_SET_CD_ORDER_ID 0x001B +#define FORM_SET_NET_ORDER_ID 0x001C +#define FORM_SET_BEV_ORDER_ID 0x001D + +#define KEY_VALUE_BOOT_FROM_FILE 0x0092 + +formset + guid = MAIN_FORMSET_GUID, + title = STRING_TOKEN(STR_FORM_MAIN_TITLE), // uint8 opcode, uint8 length, guid Handle, uint16 Title + help = STRING_TOKEN(STR_NULL_STRING), + class = 0, + subclass = 0, + + form formid = FORM_MAIN_ID, + title = STRING_TOKEN(STR_FORM_MAIN_TITLE); + + goto FORM_BOOT_SETUP_ID, + prompt = STRING_TOKEN(STR_FORM_BOOT_SETUP_TITLE), + help = STRING_TOKEN(STR_FORM_BOOT_SETUP_HELP), + flags = INTERACTIVE | NV_ACCESS, + key = FORM_BOOT_SETUP_ID; + + subtitle text = STRING_TOKEN(STR_NULL_STRING); + + goto FORM_DRIVER_SETUP_ID, + prompt = STRING_TOKEN(STR_FORM_DRIVER_SETUP_TITLE), + help = STRING_TOKEN(STR_FORM_DRIVER_SETUP_HELP), + flags = INTERACTIVE | NV_ACCESS, + key = FORM_DRIVER_SETUP_ID; + + subtitle text = STRING_TOKEN(STR_NULL_STRING); + + goto FORM_CON_MAIN_ID, + prompt = STRING_TOKEN(STR_FORM_CON_MAIN_TITLE), + help = STRING_TOKEN(STR_FORM_CON_MAIN_HELP), + flags = INTERACTIVE | NV_ACCESS, + key = FORM_CON_MAIN_ID; + + subtitle text = STRING_TOKEN(STR_NULL_STRING); + + text + help = STRING_TOKEN(STR_BOOT_FROM_FILE_HELP), + text = STRING_TOKEN(STR_BOOT_FROM_FILE), + text = STRING_TOKEN(STR_NULL_STRING), + flags = INTERACTIVE | NV_ACCESS, + key = KEY_VALUE_BOOT_FROM_FILE; + + subtitle text = STRING_TOKEN(STR_NULL_STRING); + +// label FORM_MAIN_ID; + + goto FORM_BOOT_NEXT_ID, + prompt = STRING_TOKEN(STR_FORM_BOOT_NEXT_TITLE), + help = STRING_TOKEN(STR_FORM_BOOT_NEXT_HELP), + flags = INTERACTIVE | NV_ACCESS, + key = FORM_BOOT_NEXT_ID; + + goto FORM_TIME_OUT_ID, + prompt = STRING_TOKEN(STR_FORM_TIME_OUT_TITLE), + help = STRING_TOKEN(STR_FORM_TIME_OUT_HELP), + flags = INTERACTIVE | NV_ACCESS, + key = FORM_TIME_OUT_ID; + + subtitle text = STRING_TOKEN(STR_NULL_STRING); + + goto FORM_MAIN_ID, + prompt = STRING_TOKEN(STR_RESET), + help = STRING_TOKEN(STR_RESET), + flags = INTERACTIVE | NV_ACCESS, + key = FORM_RESET; + + endform; + + form formid = FORM_BOOT_SETUP_ID, + title = STRING_TOKEN(STR_FORM_BOOT_SETUP_TITLE); + + goto FORM_MAIN_ID, + prompt = STRING_TOKEN(STR_FORM_GOTO_MAIN), + help = STRING_TOKEN(STR_FORM_GOTO_MAIN), + flags = INTERACTIVE | NV_ACCESS, + key = FORM_MAIN_ID; + + goto FORM_BOOT_ADD_ID, + prompt = STRING_TOKEN(STR_FORM_BOOT_ADD_TITLE), + help = STRING_TOKEN(STR_FORM_BOOT_ADD_HELP), + flags = INTERACTIVE | NV_ACCESS, + key = FORM_BOOT_ADD_ID; + + goto FORM_BOOT_DEL_ID, + prompt = STRING_TOKEN(STR_FORM_BOOT_DEL_TITLE), + help = STRING_TOKEN(STR_FORM_NEXT_BOOT_HELP), + flags = INTERACTIVE | NV_ACCESS, + key = FORM_BOOT_DEL_ID; + + goto FORM_BOOT_CHG_ID, + prompt = STRING_TOKEN(STR_FORM_BOOT_CHG_TITLE), + help = STRING_TOKEN(STR_FORM_NEXT_BOOT_HELP), + flags = INTERACTIVE | NV_ACCESS, + key = FORM_BOOT_CHG_ID; + + subtitle text = STRING_TOKEN(STR_NULL_STRING); + // + // We will add "Select Legacy Boot Floppy Drive" and "Select Legacy Boot Hard Drive" + // here dynamically + // + label FORM_BOOT_LEGACY_DEVICE_ID; + + 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), + flags = INTERACTIVE | NV_ACCESS, + 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 | NV_ACCESS, + 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 | NV_ACCESS, + 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 | NV_ACCESS, + key = FORM_DRV_CHG_ID; + endform; + + form formid = FORM_BOOT_ADD_ID, + title = STRING_TOKEN(STR_FORM_BOOT_ADD_TITLE); + + label FORM_BOOT_ADD_ID; + endform; + + form formid = FORM_BOOT_DEL_ID, + title = STRING_TOKEN(STR_FORM_BOOT_DEL_TITLE); + + label FORM_BOOT_DEL_ID; + endform; + + form formid = FORM_BOOT_CHG_ID, + title = STRING_TOKEN(STR_FORM_BOOT_CHG_TITLE); + + label FORM_BOOT_CHG_ID; + + // + // This tag is added for bypassing issue of setup browser + // setup browser could not support dynamic form very well. + // + checkbox varid = BMM_FAKE_NV_DATA.OptionOrder[0], + prompt = STRING_TOKEN(STR_FORM_BOOT_CHG_TITLE), + help = STRING_TOKEN(STR_FORM_BOOT_CHG_TITLE), + flags = 1, + key = 0, + endcheckbox; + + endform; + + form formid = FORM_BOOT_NEXT_ID, + title = STRING_TOKEN(STR_FORM_BOOT_NEXT_TITLE); + + label FORM_BOOT_NEXT_ID; + endform; + + form formid = FORM_TIME_OUT_ID, + title = STRING_TOKEN(STR_FORM_TIME_OUT_TITLE); + + label FORM_TIME_OUT_ID; + 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 | NV_ACCESS, + key = FORM_MAIN_ID; + + goto FORM_DRV_ADD_FILE_ID, + prompt = STRING_TOKEN(STR_FORM_DRV_ADD_FILE_TITLE), + help = STRING_TOKEN(STR_FORM_DRV_ADD_FILE_TITLE), + flags = INTERACTIVE | NV_ACCESS, + key = FORM_DRV_ADD_FILE_ID; + + endform; + + form formid = FORM_DRV_DEL_ID, + title = STRING_TOKEN(STR_FORM_DRV_DEL_TITLE); + + label FORM_DRV_DEL_ID; + + endform; + + form formid = FORM_DRV_CHG_ID, + title = STRING_TOKEN(STR_FORM_DRV_CHG_TITLE); + + label FORM_DRV_CHG_ID; + + // + // This tag is added for bypassing issue of setup browser + // setup browser could not support dynamic form very well. + // + checkbox varid = BMM_FAKE_NV_DATA.OptionOrder[0], + prompt = STRING_TOKEN(STR_FORM_DRV_CHG_TITLE), + help = STRING_TOKEN(STR_FORM_DRV_CHG_TITLE), + flags = 1, + key = 0, + endcheckbox; + + 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 | NV_ACCESS, + 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 | NV_ACCESS, + 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 | NV_ACCESS, + 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 | NV_ACCESS, + key = FORM_CON_ERR_ID; + + goto FORM_CON_COM_ID, + prompt = STRING_TOKEN(STR_FORM_COM_TITLE), + help = STRING_TOKEN(STR_FORM_COM_HELP), + flags = INTERACTIVE | NV_ACCESS, + key = FORM_CON_COM_ID; + endform; + + form formid = FORM_CON_COM_ID, + title = STRING_TOKEN(STR_FORM_COM_TITLE); + + label FORM_CON_COM_ID; + endform; + + form formid = FORM_CON_COM_SETUP_ID, + title = STRING_TOKEN(STR_CON_COM_SETUP); + + label FORM_CON_COM_SETUP_ID; + endform; + + form formid = FORM_FILE_SEEK_ID, + title = STRING_TOKEN(STR_FORM_BOOT_ADD_TITLE); + + label FORM_FILE_SEEK_ID; + endform; + + form formid = FORM_FILE_NEW_SEEK_ID, + title = STRING_TOKEN(STR_FORM_BOOT_ADD_TITLE); + + label FORM_FILE_NEW_SEEK_ID; + endform; + + form formid = FORM_DRV_ADD_FILE_ID, + title = STRING_TOKEN(STR_FORM_DRV_ADD_FILE_TITLE); + + label FORM_DRV_ADD_FILE_ID; + endform; + + form formid = FORM_DRV_ADD_HANDLE_ID, + title = STRING_TOKEN(STR_FORM_DRV_ADD_HANDLE_TITLE); + + label FORM_DRV_ADD_HANDLE_ID; + 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; + + endform; + + form formid = FORM_CON_IN_ID, + title = STRING_TOKEN(STR_FORM_CON_IN_TITLE); + + label FORM_CON_IN_ID; + + endform; + + form formid = FORM_CON_OUT_ID, + title = STRING_TOKEN(STR_FORM_CON_OUT_TITLE); + + label FORM_CON_OUT_ID; + + endform; + + form formid = FORM_CON_ERR_ID, + title = STRING_TOKEN(STR_FORM_STD_ERR_TITLE); + + label FORM_CON_ERR_ID; + + endform; + + form formid = FORM_SET_FD_ORDER_ID, + title = STRING_TOKEN(STR_FORM_SET_FD_ORDER_TITLE); + + label FORM_SET_FD_ORDER_ID; + endform; + + form formid = FORM_SET_HD_ORDER_ID, + title = STRING_TOKEN(STR_FORM_SET_HD_ORDER_TITLE); + + label FORM_SET_HD_ORDER_ID; + endform; + + form formid = FORM_SET_CD_ORDER_ID, + title = STRING_TOKEN(STR_FORM_SET_CD_ORDER_TITLE); + + label FORM_SET_CD_ORDER_ID; + endform; + + form formid = FORM_SET_NET_ORDER_ID, + title = STRING_TOKEN(STR_FORM_SET_NET_ORDER_TITLE); + + label FORM_SET_NET_ORDER_ID; + endform; + + form formid = FORM_SET_BEV_ORDER_ID, + title = STRING_TOKEN(STR_FORM_SET_BEV_ORDER_TITLE); + + label FORM_SET_BEV_ORDER_ID; + endform; + +endformset; diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/bmstring.uni b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMaint/bmstring.uni new file mode 100644 index 0000000000000000000000000000000000000000..f646d8b331af572316f51d994da5017f51f88b46 GIT binary patch literal 36240 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 z`4#=A`pW5telgptForwardLink; Link != mBootOptionsList; Link = Link->ForwardLink) { + Option = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE); + + KeyCount++; + + gOption = Option; + + // + // Is this device the one chosen? + // + if (KeyCount == KeyValue) { + // + // Assigning the returned Key to a global allows the original routine to know what was chosen + // + mKeyInput = KeyValue; + + *Packet = AllocateZeroPool (sizeof (EFI_HII_CALLBACK_PACKET) + 2); + ASSERT (*Packet != NULL); + + // + // Assign the buffer address to DataPacket + // + DataPacket = *Packet; + + DataPacket->DataArray.EntryCount = 1; + DataPacket->DataArray.NvRamMap = NULL; + ((EFI_IFR_DATA_ENTRY *) (((EFI_IFR_DATA_ARRAY *)DataPacket) + 1))->Flags = EXIT_REQUIRED | NV_NOT_CHANGED; + return EFI_SUCCESS; + } else { + continue; + } + } + + return EFI_SUCCESS; +} + +VOID +CallBootManager ( + VOID + ) +/*++ + +Routine Description: + Hook to enable UI timeout override behavior. + +Arguments: + BdsDeviceList - Device List that BDS needs to connect. + + Entry - Pointer to current Boot Entry. + +Returns: + NONE + +--*/ +{ + EFI_STATUS Status; + EFI_HII_PACKAGES *PackageList; + BDS_COMMON_OPTION *Option; + LIST_ENTRY *Link; + EFI_HII_UPDATE_DATA *UpdateData; + CHAR16 *ExitData; + UINTN ExitDataSize; + STRING_REF Token; + STRING_REF LastToken; + EFI_INPUT_KEY Key; + UINT8 *Location; + EFI_GUID BmGuid; + LIST_ENTRY BdsBootOptionList; + + gOption = NULL; + InitializeListHead (&BdsBootOptionList); + + // + // Connect all prior to entering the platform setup menu. + // + if (!gConnectAllHappened) { + BdsLibConnectAllDriversToAllControllers (); + gConnectAllHappened = TRUE; + } + // + // BugBug: Here we can not remove the legacy refresh macro, so we need + // get the boot order every time from "BootOrder" variable. + // Recreate the boot option list base on the BootOrder variable + // + BdsLibEnumerateAllBootOption (&BdsBootOptionList); + + // + // This GUID must be the same as what is defined in BootManagerVfr.vfr + // + BmGuid = gBmGuid; + + mBootOptionsList = &BdsBootOptionList; + + // + // Post our VFR to the HII database + // + PackageList = PreparePackages (2, &BmGuid, BootManagerVfrBin, BdsStrings); + Status = Hii->NewPack (Hii, PackageList, &gBootManagerHandle); + gBS->FreePool (PackageList); + + // + // This example does not implement worker functions + // for the NV accessor functions. Only a callback evaluator + // + BootManagerCallback.NvRead = NULL; + BootManagerCallback.NvWrite = NULL; + BootManagerCallback.Callback = BootManagerCallbackRoutine; + + // + // Install protocol interface + // + BootManagerCallbackHandle = NULL; + Status = gBS->InstallProtocolInterface ( + &BootManagerCallbackHandle, + &gEfiFormCallbackProtocolGuid, + EFI_NATIVE_INTERFACE, + &BootManagerCallback + ); + ASSERT_EFI_ERROR (Status); + + LastToken = 0; + Hii->NewString (Hii, NULL, gBootManagerHandle, &LastToken, L" "); + + // + // Allocate space for creation of UpdateData Buffer + // + UpdateData = AllocateZeroPool (0x1000); + ASSERT (UpdateData != NULL); + + // + // Flag update pending in FormSet + // + UpdateData->FormSetUpdate = TRUE; + // + // Register CallbackHandle data for FormSet + // + UpdateData->FormCallbackHandle = (EFI_PHYSICAL_ADDRESS) (UINTN) BootManagerCallbackHandle; + UpdateData->FormUpdate = FALSE; + UpdateData->FormTitle = 0; + UpdateData->DataCount = 1; + + // + // Create blank space. Since when we update the contents of IFR data at a label, it is + // inserted at the location of the label. So if you want to add a string with an empty + // space afterwards, you need to add the space first and then the string like below. + // + Status = CreateSubTitleOpCode ( + LastToken, // Token Value for the string + &UpdateData->Data // Buffer containing created op-code + ); + + Hii->UpdateForm (Hii, gBootManagerHandle, (EFI_FORM_LABEL) 0x0000, TRUE, UpdateData); + + // + // Create "Boot Option Menu" title + // + Status = CreateSubTitleOpCode ( + STRING_TOKEN (STR_BOOT_OPTION_BANNER), // Token Value for the string + &UpdateData->Data // Buffer containing created op-code + ); + + Hii->UpdateForm (Hii, gBootManagerHandle, (EFI_FORM_LABEL) 0x0000, TRUE, UpdateData); + + Token = LastToken; + mKeyInput = 0; + + UpdateData->DataCount = 0; + Location = (UINT8 *) &UpdateData->Data; + + for (Link = BdsBootOptionList.ForwardLink; Link != &BdsBootOptionList; Link = Link->ForwardLink) { + Option = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE); + + // + // At this stage we are creating a menu entry, thus the Keys are reproduceable + // + mKeyInput++; + Token++; + + Status = Hii->NewString (Hii, NULL, gBootManagerHandle, &Token, Option->Description); + + // + // If we got an error it is almost certainly due to the token value being invalid. + // Therefore we will set the Token to 0 to automatically add a token. + // + if (EFI_ERROR (Status)) { + Token = 0; + Status = Hii->NewString (Hii, NULL, gBootManagerHandle, &Token, Option->Description); + } + + Status = CreateGotoOpCode ( + 0x1000, // Form ID + Token, // Token Value for the string + 0, // Help String (none) + EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_NV_ACCESS, // The Op-Code flags + mKeyInput, // The Key to get a callback on + Location // Buffer containing created op-code + ); + + UpdateData->DataCount++; + Location = Location + ((EFI_IFR_OP_HEADER *) Location)->Length; + + } + + Hii->UpdateForm (Hii, gBootManagerHandle, (EFI_FORM_LABEL) 0x0001, TRUE, UpdateData); + + UpdateData->DataCount = 1; + + // + // Create "Boot Option Menu" title + // + Status = CreateSubTitleOpCode ( + STRING_TOKEN (STR_HELP_FOOTER), // Token Value for the string + &UpdateData->Data // Buffer containing created op-code + ); + + Hii->UpdateForm (Hii, gBootManagerHandle, (EFI_FORM_LABEL) 0x0002, TRUE, UpdateData); + + Status = CreateSubTitleOpCode ( + LastToken, // Token Value for the string + &UpdateData->Data // Buffer containing created op-code + ); + + Hii->UpdateForm (Hii, gBootManagerHandle, (EFI_FORM_LABEL) 0x0002, TRUE, UpdateData); + + gBS->FreePool (UpdateData); + + ASSERT (gBrowser); + + gBrowser->SendForm (gBrowser, TRUE, &gBootManagerHandle, 1, NULL, NULL, NULL, NULL, NULL); + + Hii->ResetStrings (Hii, gBootManagerHandle); + + if (gOption == NULL) { + return ; + } + // + // BugBug: This code looks repeated from the BDS. Need to save code space. + // + + // + // parse the selected option + // + Status = BdsLibBootViaBootOption (gOption, gOption->DevicePath, &ExitDataSize, &ExitData); + + if (!EFI_ERROR (Status)) { + PlatformBdsBootSuccess (gOption); + } else { + PlatformBdsBootFail (gOption, Status, ExitData, ExitDataSize); + gST->ConOut->OutputString ( + gST->ConOut, + GetStringById (STRING_TOKEN (STR_ANY_KEY_CONTINUE)) + ); + + // + // BdsLibUiWaitForSingleEvent (gST->ConIn->WaitForKey, 0); + // + + gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + } +} diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMngr/BootManager.h b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMngr/BootManager.h new file mode 100644 index 0000000000..3a90932695 --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMngr/BootManager.h @@ -0,0 +1,50 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + BootManager.h + +Abstract: + + The platform boot manager reference implement + +Revision History + +--*/ + +#ifndef _EFI_BOOT_MANAGER_H +#define _EFI_BOOT_MANAGER_H + +#include "Generic/Bds.h" +#include "BdsPlatform.h" +#include "Generic/String.h" + +EFI_STATUS +EFIAPI +BootManagerCallbackRoutine ( + IN EFI_FORM_CALLBACK_PROTOCOL *This, + IN UINT16 KeyValue, + IN EFI_IFR_DATA_ARRAY *DataArray, + OUT EFI_HII_CALLBACK_PACKET **Packet + ); + +VOID +CallBootManager ( + VOID +); + +#define BOOT_MANAGER_GUID \ + { \ + 0x847bc3fe, 0xb974, 0x446d, {0x94, 0x49, 0x5a, 0xd5, 0x41, 0x2e, 0x99, 0x3b } \ + } + +#endif diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMngr/BootManagerStrings.uni b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMngr/BootManagerStrings.uni new file mode 100644 index 0000000000000000000000000000000000000000..e875cfbee1c5c72580059ccf00ee85fe221cb10b GIT binary patch literal 3942 zcmc&%+iuf95S?cv{=uXVg#r!Yfrm;wB-Cvq+9XO+6`rD8TZ>$Z?FRB0h>zqifOBTz ztR0e?NL8a%?A`V3?3uH3+5Gukl%jZYATQCL$`g!=%eN;VWGc5Zmrw$^mK%v7`&@eR z0`Ir-2JM}^Lcbytd>hCJeXa?yiq8&a1N0`Cf9#f6<4Fm)h|F0L>1ZGkFo!b3voD93 zYr)0YbbLhV*qdh!{H_KT7eB6Va8tdFW!kFB3fjsdZo{gOjEgIsBoha@24yjd~ zS+49%=8)>LVLp_Z{=n8S}#g+4kFw=!CeR;j| z~{ zsA9f?{kdCBaW*ibm7F8G7GxpVR_eXr8jl|_Ib}@T>`LxvIv{%4d9TCet zk2T9}vc{ozy$kqvU*nCDS4F&x5d%ld8sQ|VwTWn9>@pKZ*lUJZ4VSWBs#ntJpfs~W zoYI(V5 znQy@O8WDc5sG6qhz3i!ej`kD@`Cx`-E@dMt9lQ&2qP>ay!kD?Qpexs}V(wvuDc~g8 zW0s4MOKgqpmSj(pv`tGxJL%o9 z&TK~izd!oTx7+aWI#{>Ll9vziEO*ggOL--80r|Pxi5J?9H$lK^u@9SF%vk+km0;fD z?eTu*tmd{+bA8m_He!u6nG9A@*Lgcx*YcRF!((~#jj-DOJ9zR1GrXZDxq^3b<_9u4 zK)qtyg@={E-YqcjuI>TNK6?DmV^PPsuZocOagJPM+W!e>LzuB*QgMln0L7de_t SpF;2bEsybCFlT!*F8=~a>-Hf4 literal 0 HcmV?d00001 diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMngr/BootManagerVfr.Vfr b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMngr/BootManagerVfr.Vfr new file mode 100644 index 0000000000..7fb193ac1b --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/Generic/BootMngr/BootManagerVfr.Vfr @@ -0,0 +1,55 @@ +// *++ +// +// Copyright (c) 2006, Intel Corporation +// All rights reserved. This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// Module Name: +// +// BootManager.vfr +// +// Abstract: +// +// Browser formset. +// +// Revision History: +// +// --*/ + +#include "BdsStrDefs.h" + +#define FORMSET_GUID { 0x847bc3fe, 0xb974, 0x446d, { 0x94, 0x49, 0x5a, 0xd5, 0x41, 0x2e, 0x99, 0x3b } } + +#define BOOT_MANAGER_HEADER 0x00 +#define BOOT_MANAGER_LABEL 0x01 +#define BOOT_MANAGER_TAIL 0x02 + + +#define BOOT_MANAGER_CLASS 0x00 +#define BOOT_MANAGER_SUBCLASS 0x01 + +formset + guid = FORMSET_GUID, + title = STRING_TOKEN(STR_BM_BANNER), + help = STRING_TOKEN(STR_LAST_STRING), + class = BOOT_MANAGER_CLASS, + subclass = BOOT_MANAGER_SUBCLASS, + + form formid = 0x1000, + title = STRING_TOKEN(STR_BM_BANNER); + + label BOOT_MANAGER_HEADER; + label BOOT_MANAGER_LABEL; + // + // This is where we will dynamically add choices for the Boot Manager + // + + label BOOT_MANAGER_TAIL; + endform; + +endformset; diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/Capsules.c b/EdkNt32Pkg/Dxe/PlatformBds/Generic/Capsules.c new file mode 100644 index 0000000000..b33af03bb7 --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/Generic/Capsules.c @@ -0,0 +1,213 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Capsules.c + +Abstract: + + BDS routines to handle capsules. + +--*/ + + +#include + +VOID +BdsLockFv ( + IN EFI_CPU_IO_PROTOCOL *CpuIo, + IN EFI_FLASH_SUBAREA_ENTRY *FlashEntry + ); + +VOID +BdsLockFv ( + IN EFI_CPU_IO_PROTOCOL *CpuIo, + IN EFI_FLASH_SUBAREA_ENTRY *FlashEntry + ) +{ + EFI_FV_BLOCK_MAP_ENTRY *BlockMap; + EFI_FIRMWARE_VOLUME_HEADER *FvHeader; + UINT64 BaseAddress; + UINT8 Data; + UINT32 BlockLength; + UINTN Index; + + BaseAddress = FlashEntry->Base - 0x400000 + 2; + FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) (FlashEntry->Base)); + BlockMap = &(FvHeader->FvBlockMap[0]); + + while ((BlockMap->NumBlocks != 0) && (BlockMap->BlockLength != 0)) { + BlockLength = BlockMap->BlockLength; + for (Index = 0; Index < BlockMap->NumBlocks; Index++) { + CpuIo->Mem.Read ( + CpuIo, + EfiCpuIoWidthUint8, + BaseAddress, + 1, + &Data + ); + Data = (UINT8) (Data | 0x3); + CpuIo->Mem.Write ( + CpuIo, + EfiCpuIoWidthUint8, + BaseAddress, + 1, + &Data + ); + BaseAddress += BlockLength; + } + + BlockMap++; + } +} + +VOID +BdsLockNonUpdatableFlash ( + VOID + ) +{ + EFI_FLASH_MAP_ENTRY_DATA *FlashMapEntryData; + EFI_PEI_HOB_POINTERS GuidHob; + EFI_STATUS Status; + EFI_CPU_IO_PROTOCOL *CpuIo; + + Status = gBS->LocateProtocol (&gEfiCpuIoProtocolGuid, NULL, &CpuIo); + ASSERT_EFI_ERROR (Status); + + GuidHob.Raw = GetHobList (); + while ((GuidHob.Raw = GetNextGuidHob (&gEfiFlashMapHobGuid, GuidHob.Raw)) != NULL) { + FlashMapEntryData = (EFI_FLASH_MAP_ENTRY_DATA *) GET_GUID_HOB_DATA (GuidHob.Guid); + + // + // Get the variable store area + // + if ((FlashMapEntryData->AreaType == EFI_FLASH_AREA_RECOVERY_BIOS) || + (FlashMapEntryData->AreaType == EFI_FLASH_AREA_MAIN_BIOS) + ) { + BdsLockFv (CpuIo, &(FlashMapEntryData->Entries[0])); + } + GuidHob.Raw = GET_NEXT_HOB (GuidHob); + } + + return ; +} + +EFI_STATUS +ProcessCapsules ( + EFI_BOOT_MODE BootMode + ) +/*++ + +Routine Description: + + This routine is called to see if there are any capsules we need to process. + If the boot mode is not UPDATE, then we do nothing. Otherwise find the + capsule HOBS and produce firmware volumes for them via the DXE service. + Then call the dispatcher to dispatch drivers from them. Finally, check + the status of the updates. + +Arguments: + + BootMode - the current boot mode + +Returns: + + EFI_INVALID_PARAMETER - boot mode is not correct for an update + +Note: + + This function should be called by BDS in case we need to do some + sort of processing even if there is no capsule to process. We + need to do this if an earlier update went awry and we need to + clear the capsule variable so on the next reset PEI does not see it and + think there is a capsule available. + +--*/ +{ + EFI_STATUS Status; + EFI_HOB_CAPSULE_VOLUME *CvHob; + EFI_PHYSICAL_ADDRESS BaseAddress; + UINT64 Length; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_HANDLE FvProtocolHandle; + + // + // We don't do anything else if the boot mode is not flash-update + // + if (BootMode != BOOT_ON_FLASH_UPDATE) { + return EFI_INVALID_PARAMETER; + } + // + // Only one capsule HOB allowed. + // + CvHob = GetFirstHob (EFI_HOB_TYPE_CV); + if (CvHob == NULL) { + // + // We didn't find a hob, so had no errors. + // + BdsLockNonUpdatableFlash (); + return EFI_SUCCESS; + } + + BaseAddress = CvHob->BaseAddress; + Length = CvHob->Length; + + Status = EFI_SUCCESS; + // + // Now walk the capsule and call the core to process each + // firmware volume in it. + // + while (Length != 0) { + // + // Point to the next firmware volume header, and then + // call the DXE service to process it. + // + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress; + if (FwVolHeader->FvLength > Length) { + // + // Notes: need to stuff this status somewhere so that the + // error can be detected at OS runtime + // + Status = EFI_VOLUME_CORRUPTED; + break; + } + + Status = gDS->ProcessFirmwareVolume ( + (VOID *) (UINTN) BaseAddress, + (UINTN) FwVolHeader->FvLength, + &FvProtocolHandle + ); + if (EFI_ERROR (Status)) { + break; + } + // + // Call the dispatcher to dispatch any drivers from the produced firmware volume + // + gDS->Dispatch (); + // + // On to the next FV in the capsule + // + Length -= FwVolHeader->FvLength; + BaseAddress = (EFI_PHYSICAL_ADDRESS) ((UINTN) BaseAddress + FwVolHeader->FvLength); + // + // Notes: when capsule spec is finalized, if the requirement is made to + // have each FV in a capsule aligned, then we will need to align the + // BaseAddress and Length here. + // + } + + + BdsLockNonUpdatableFlash (); + + return Status; +} + diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/DeviceMngr/DeviceManager.c b/EdkNt32Pkg/Dxe/PlatformBds/Generic/DeviceMngr/DeviceManager.c new file mode 100644 index 0000000000..0e73a4e3fe --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/Generic/DeviceMngr/DeviceManager.c @@ -0,0 +1,482 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DeviceManager.c + +Abstract: + + The platform device manager reference implement + +--*/ +#include "DeviceManager.h" + +STATIC UINT16 mTokenCount; +EFI_FRONTPAGE_CALLBACK_INFO FPCallbackInfo; +extern UINTN gCallbackKey; +extern EFI_FORM_BROWSER_PROTOCOL *gBrowser; +extern EFI_GUID gBdsStringPackGuid; +extern BOOLEAN gConnectAllHappened; + +STRING_REF gStringTokenTable[] = { + STR_VIDEO_DEVICE, + STR_NETWORK_DEVICE, + STR_INPUT_DEVICE, + STR_ON_BOARD_DEVICE, + STR_OTHER_DEVICE, + STR_EMPTY_STRING, + 0xFFFF +}; + +EFI_STATUS +EFIAPI +DeviceManagerCallbackRoutine ( + IN EFI_FORM_CALLBACK_PROTOCOL *This, + IN UINT16 KeyValue, + IN EFI_IFR_DATA_ARRAY *DataArray, + OUT EFI_HII_CALLBACK_PACKET **Packet + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + KeyValue - 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 op-code that geerated the callback. + + Data - A pointer to the data being sent to the original exporting driver. + +Returns: + +--*/ +{ + // + // The KeyValue corresponds in this case to the handle which was requested to be displayed + // + EFI_FRONTPAGE_CALLBACK_INFO *CallbackInfo; + + CallbackInfo = EFI_FP_CALLBACK_DATA_FROM_THIS (This); + switch (KeyValue) { + case 0x2000: + CallbackInfo->Data.VideoBIOS = (UINT8) (UINTN) (((EFI_IFR_DATA_ENTRY *)(DataArray + 1))->Data); + gRT->SetVariable ( + L"VBIOS", + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + sizeof (UINT8), + &CallbackInfo->Data.VideoBIOS + ); + break; + + default: + break; + } + + gCallbackKey = KeyValue; + return EFI_SUCCESS; +} + +EFI_STATUS +InitializeDeviceManager ( + VOID + ) +/*++ + +Routine Description: + + Initialize HII information for the FrontPage + +Arguments: + None + +Returns: + +--*/ +{ + EFI_STATUS Status; + EFI_HII_PACKAGES *PackageList; + EFI_HII_UPDATE_DATA *UpdateData; + + // + // Allocate space for creation of UpdateData Buffer + // + UpdateData = AllocateZeroPool (0x1000); + ASSERT (UpdateData != NULL); + + PackageList = PreparePackages (1, &gBdsStringPackGuid, DeviceManagerVfrBin); + Status = Hii->NewPack (Hii, PackageList, &FPCallbackInfo.DevMgrHiiHandle); + gBS->FreePool (PackageList); + + // + // This example does not implement worker functions for the NV accessor functions. Only a callback evaluator + // + FPCallbackInfo.Signature = EFI_FP_CALLBACK_DATA_SIGNATURE; + FPCallbackInfo.DevMgrCallback.NvRead = NULL; + FPCallbackInfo.DevMgrCallback.NvWrite = NULL; + FPCallbackInfo.DevMgrCallback.Callback = DeviceManagerCallbackRoutine; + + // + // Install protocol interface + // + FPCallbackInfo.CallbackHandle = NULL; + + Status = gBS->InstallProtocolInterface ( + &FPCallbackInfo.CallbackHandle, + &gEfiFormCallbackProtocolGuid, + EFI_NATIVE_INTERFACE, + &FPCallbackInfo.DevMgrCallback + ); + + ASSERT_EFI_ERROR (Status); + + // + // Flag update pending in FormSet + // + UpdateData->FormSetUpdate = TRUE; + // + // Register CallbackHandle data for FormSet + // + UpdateData->FormCallbackHandle = (EFI_PHYSICAL_ADDRESS) (UINTN) FPCallbackInfo.CallbackHandle; + // + // Simply registering the callback handle + // + Hii->UpdateForm (Hii, FPCallbackInfo.DevMgrHiiHandle, (EFI_FORM_LABEL) 0x0000, TRUE, UpdateData); + + gBS->FreePool (UpdateData); + return Status; +} + +EFI_STATUS +CallDeviceManager ( + VOID + ) +/*++ + +Routine Description: + + Call the browser and display the device manager + +Arguments: + + None + +Returns: + EFI_SUCCESS - Operation is successful. + EFI_INVALID_PARAMETER - If the inputs to SendForm function is not valid. + +--*/ +{ + EFI_STATUS Status; + UINTN BufferSize; + UINTN Count; + EFI_HII_HANDLE Index; + UINT8 *Buffer; + EFI_IFR_FORM_SET *FormSetData; + CHAR16 *String; + UINTN StringLength; + EFI_HII_UPDATE_DATA *UpdateData; + STRING_REF Token; + STRING_REF TokenHelp; + IFR_OPTION *IfrOptionList; + UINT8 *VideoOption; + UINTN VideoOptionSize; + EFI_HII_HANDLE *HiiHandles; + UINT16 HandleBufferLength; + + IfrOptionList = NULL; + VideoOption = NULL; + HandleBufferLength = 0; + + // + // Connect all prior to entering the platform setup menu. + // + if (!gConnectAllHappened) { + BdsLibConnectAllDriversToAllControllers (); + gConnectAllHappened = TRUE; + } + // + // Allocate space for creation of UpdateData Buffer + // + UpdateData = AllocateZeroPool (0x1000); + ASSERT (UpdateData != NULL); + + Status = EFI_SUCCESS; + Buffer = NULL; + FormSetData = NULL; + gCallbackKey = 0; + if (mTokenCount == 0) { + Hii->NewString (Hii, NULL, FPCallbackInfo.DevMgrHiiHandle, &mTokenCount, L" "); + } + + Token = mTokenCount; + TokenHelp = (UINT16) (Token + 1); + + // + // Reset the menu + // + for (Index = 0, Count = 1; Count < 0x10000; Count <<= 1, Index++) { + // + // We will strip off all previous menu entries + // + UpdateData->DataCount = 0xFF; + + // + // Erase entries on this label + // + Hii->UpdateForm (Hii, FPCallbackInfo.DevMgrHiiHandle, (EFI_FORM_LABEL) Count, FALSE, UpdateData); + + // + // Did we reach the end of the Token Table? + // + if (gStringTokenTable[Index] == 0xFFFF) { + break; + } + + CreateSubTitleOpCode (gStringTokenTable[Index], &UpdateData->Data); + // + // Add a single menu item - in this case a subtitle for the device type + // + UpdateData->DataCount = 1; + + // + // Add default title for this label + // + Hii->UpdateForm (Hii, FPCallbackInfo.DevMgrHiiHandle, (EFI_FORM_LABEL) Count, TRUE, UpdateData); + } + // + // Add a space and an exit string. Remember since we add things at the label and push other things beyond the + // label down, we add this in reverse order + // + CreateSubTitleOpCode (STRING_TOKEN (STR_EXIT_STRING), &UpdateData->Data); + Hii->UpdateForm (Hii, FPCallbackInfo.DevMgrHiiHandle, (EFI_FORM_LABEL) Count, TRUE, UpdateData); + CreateSubTitleOpCode (STR_EMPTY_STRING, &UpdateData->Data); + Hii->UpdateForm (Hii, FPCallbackInfo.DevMgrHiiHandle, (EFI_FORM_LABEL) Count, TRUE, UpdateData); + + HiiHandles = AllocateZeroPool (HandleBufferLength); + Hii->FindHandles (Hii, &HandleBufferLength, HiiHandles); + + for (Index = 1, BufferSize = 0; Index < HandleBufferLength; Index++) { + // + // Am not initializing Buffer since the first thing checked is the size + // this way I can get the real buffersize in the smallest code size + // + Status = Hii->GetForms (Hii, Index, 0, &BufferSize, Buffer); + + if (Status != EFI_NOT_FOUND) { + // + // BufferSize should have the real size of the forms now + // + Buffer = AllocateZeroPool (BufferSize); + ASSERT (Buffer != NULL); + + // + // Am not initializing Buffer since the first thing checked is the size + // this way I can get the real buffersize in the smallest code size + // + Status = Hii->GetForms (Hii, Index, 0, &BufferSize, Buffer); + + // + // Skip EFI_HII_PACK_HEADER, advance to EFI_IFR_FORM_SET data. + // + FormSetData = (EFI_IFR_FORM_SET *) (Buffer + sizeof (EFI_HII_PACK_HEADER)); + + // + // If this formset belongs in the device manager, add it to the menu + // + if (FormSetData->Class != EFI_NON_DEVICE_CLASS) { + + StringLength = 0x1000; + String = AllocateZeroPool (StringLength); + ASSERT (String != NULL); + + Status = Hii->GetString (Hii, Index, FormSetData->FormSetTitle, TRUE, NULL, &StringLength, String); + Status = Hii->NewString (Hii, NULL, FPCallbackInfo.DevMgrHiiHandle, &Token, String); + + // + // If token value exceeded real token value - we need to add a new token values + // + if (Status == EFI_INVALID_PARAMETER) { + Token = 0; + TokenHelp = 0; + Status = Hii->NewString (Hii, NULL, FPCallbackInfo.DevMgrHiiHandle, &Token, String); + } + + StringLength = 0x1000; + if (FormSetData->Help == 0) { + TokenHelp = 0; + } else { + Status = Hii->GetString (Hii, Index, FormSetData->Help, TRUE, NULL, &StringLength, String); + if (StringLength == 0x02) { + TokenHelp = 0; + } else { + Status = Hii->NewString (Hii, NULL, FPCallbackInfo.DevMgrHiiHandle, &TokenHelp, String); + if (Status == EFI_INVALID_PARAMETER) { + TokenHelp = 0; + Status = Hii->NewString (Hii, NULL, FPCallbackInfo.DevMgrHiiHandle, &TokenHelp, String); + } + } + } + + gBS->FreePool (String); + + CreateGotoOpCode ( + 0x1000, // Device Manager Page + Token, // Description String Token + TokenHelp, // Description Help String Token + EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_NV_ACCESS, // Flag designating callback is active + (UINT16) Index, // Callback key value + &UpdateData->Data // Buffer to fill with op-code + ); + + // + // In the off-chance that we have lots of extra tokens allocated to the DeviceManager + // this ensures we are fairly re-using the tokens instead of constantly growing the token + // storage for this one handle. If we incremented the token value beyond what it normally + // would use, we will fall back into the error path which seeds the token value with a 0 + // so that we can correctly add a token value. + // + if (TokenHelp == 0) { + // + // Since we didn't add help, only advance Token by 1 + // + Token++; + } else { + Token = (UINT16) (Token + 2); + TokenHelp = (UINT16) (TokenHelp + 2); + } + // + // This for loop basically will take the Class value which is a bitmask and + // update the form for every active bit. There will be a label at each bit + // location. So if someone had a device which a class of EFI_DISK_DEVICE_CLASS | + // EFI_ON_BOARD_DEVICE_CLASS, this routine will unwind that mask and drop the menu entry + // on each corresponding label. + // + for (Count = 1; Count < 0x10000; Count <<= 1) { + // + // This is an active bit, so update the form + // + if (FormSetData->Class & Count) { + Hii->UpdateForm ( + Hii, + FPCallbackInfo.DevMgrHiiHandle, + (EFI_FORM_LABEL) (FormSetData->Class & Count), + TRUE, + UpdateData + ); + } + } + } + + BufferSize = 0; + // + // Reset Buffer pointer to original location + // + gBS->FreePool (Buffer); + } + } + // + // Add oneof for video BIOS selection + // + VideoOption = BdsLibGetVariableAndSize ( + L"VBIOS", + &gEfiGlobalVariableGuid, + &VideoOptionSize + ); + if (NULL == VideoOption) { + FPCallbackInfo.Data.VideoBIOS = 0; + } else { + FPCallbackInfo.Data.VideoBIOS = VideoOption[0]; + gBS->FreePool (VideoOption); + } + + ASSERT (FPCallbackInfo.Data.VideoBIOS <= 1); + + Status = gBS->AllocatePool (EfiBootServicesData, 2 * sizeof (IFR_OPTION), &IfrOptionList); + if (IfrOptionList != NULL) { + IfrOptionList[0].Flags = EFI_IFR_FLAG_INTERACTIVE; + IfrOptionList[0].Key = SET_VIDEO_BIOS_TYPE_QUESTION_ID + 0x2000; + IfrOptionList[0].StringToken = STRING_TOKEN (STR_ONE_OF_PCI); + IfrOptionList[0].Value = 0; + IfrOptionList[0].OptionString = NULL; + IfrOptionList[1].Flags = EFI_IFR_FLAG_INTERACTIVE; + IfrOptionList[1].Key = SET_VIDEO_BIOS_TYPE_QUESTION_ID + 0x2000; + IfrOptionList[1].StringToken = STRING_TOKEN (STR_ONE_OF_AGP); + IfrOptionList[1].Value = 1; + IfrOptionList[1].OptionString = NULL; + IfrOptionList[FPCallbackInfo.Data.VideoBIOS].Flags |= EFI_IFR_FLAG_DEFAULT; + + CreateOneOfOpCode ( + SET_VIDEO_BIOS_TYPE_QUESTION_ID, + (UINT8) 1, + STRING_TOKEN (STR_ONE_OF_VBIOS), + STRING_TOKEN (STR_ONE_OF_VBIOS_HELP), + IfrOptionList, + 2, + &UpdateData->Data + ); + + UpdateData->DataCount = 4; + Hii->UpdateForm (Hii, FPCallbackInfo.DevMgrHiiHandle, (EFI_FORM_LABEL) EFI_VBIOS_CLASS, TRUE, UpdateData); + gBS->FreePool (IfrOptionList); + } + + Status = gBrowser->SendForm ( + gBrowser, + TRUE, // Use the database + &FPCallbackInfo.DevMgrHiiHandle, // The HII Handle + 1, + NULL, + FPCallbackInfo.CallbackHandle, + (UINT8 *) &FPCallbackInfo.Data, + NULL, + NULL + ); + + Hii->ResetStrings (Hii, FPCallbackInfo.DevMgrHiiHandle); + + // + // We will have returned from processing a callback - user either hit ESC to exit, or selected + // a target to display + // + if (gCallbackKey != 0 && gCallbackKey < 0x2000) { + Status = gBrowser->SendForm ( + gBrowser, + TRUE, // Use the database + (EFI_HII_HANDLE *) &gCallbackKey, // The HII Handle + 1, + NULL, + NULL, // This is the handle that the interface to the callback was installed on + NULL, + NULL, + NULL + ); + + // + // Force return to Device Manager + // + gCallbackKey = 4; + } + + if (gCallbackKey >= 0x2000) { + gCallbackKey = 4; + } + + gBS->FreePool (UpdateData); + + return Status; +} diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/DeviceMngr/DeviceManager.h b/EdkNt32Pkg/Dxe/PlatformBds/Generic/DeviceMngr/DeviceManager.h new file mode 100644 index 0000000000..dd6d935e45 --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/Generic/DeviceMngr/DeviceManager.h @@ -0,0 +1,59 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DeviceManager.c + +Abstract: + + The platform device manager reference implement + +Revision History + +--*/ + +#ifndef _DEVICE_MANAGER_H +#define _DEVICE_MANAGER_H + +#include "Generic/FrontPage.h" + +#define EFI_NON_DEVICE_CLASS 0x00 // Useful when you do not want something in the Device Manager +#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 + +EFI_STATUS +EFIAPI +DeviceManagerCallbackRoutine ( + IN EFI_FORM_CALLBACK_PROTOCOL *This, + IN UINT16 KeyValue, + IN EFI_IFR_DATA_ARRAY *DataArray, + OUT EFI_HII_CALLBACK_PACKET **Packet + ) +; + +EFI_STATUS +InitializeDeviceManager ( + VOID + ) +; + +EFI_STATUS +CallDeviceManager ( + VOID + ) +; + +#endif diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/DeviceMngr/DeviceManagerStrings.uni b/EdkNt32Pkg/Dxe/PlatformBds/Generic/DeviceMngr/DeviceManagerStrings.uni new file mode 100644 index 0000000000000000000000000000000000000000..f549ff28ac3a19c1dc6b3d0363a0f2624edf0262 GIT binary patch literal 4232 zcmchaT~8ZV5QgWrmHHo6aFeD5s$BFUQZFDljg??q#)0( zUDsf56h*7u^Reg5yfbIM&cFX0*nwsC+q&0UE2qnv-X({ z?PuB-_8ZUd_AC9SP55_dH}th<#x8v?m>tubF#o-uLYmAD!6jr#irhz+mVR0fea(sIV&!GJVXyuyJe;RJ+N=W`ivP#ExKcRH%_g->M=dM`CUG1sP~FoXv-ZLUe6{b+kqb{kANXz^TR}zANXGH<%%q2@U6uA7 z*{K~fepkWrf9VqX&#uuSU*WClYz#i}kWNGE;+`{>?gk()tVd@Prz453_!B28Ili!J z6=zjfaV8I}8n{NTkSeqyOxj(25_(zuoD+WOej#57{cHcsPh%fiGtT{B<$Q8x2FNn9 zy_G-vQ2D@H<@xPK3H`UD`TZy*^gVlH4Ybs;uC?t?zK3?gxQPvBSfSb;vrRj)_w*WW zneVMd+hAVy5)_ivHi=FRR-8KJHa$fLeRpU@S5$Xsk9@3=;@h@QLVpe=@ozh}%+8_L zbs1XBH{maCZO7SVBq=o~bUoH;jqt^)*Q^!JziHp{M=}amW5FflZP;H+I*ED{t#$BN z@jUh@_n0&Zed?WH-y`=od0q>Dxy1)wE^|a$DXPc(yI;hH6V^_6ubG=6M|ibjWDbgZ zym+>xl9hUg?l)Skcrh>WDz6f^GR@2*;1#?lyhYr|StV~T$G$Sg4BeDb?w4>R$+`=v zawtbGdqYogN|YZSLAZzKKVM|ip!J9CI(?0Hi3;L;y}%u3qUfR=vcp-ar#O}qEp|%# ziuf2S!w33q^Jko~?7NRtvX(=0AS?4;*WZjs`uK#3kpK*G1kwr$4M{RG_n~=4axay%%v{#Pl<7bfvTlo7ruPV=NLeoJns>&2Om5*N0 zD$Xe`e8J-9#O|j(U+1S7)V9}r&p1hCGUcPEo^5cAy|z}w&7hmSui)@?xcXityu$<5 z;oF4k)cr2*3uS!Df<<)r8hjlz-&~8RigFXapi@UP${Oo+QIB)b3C`79rE**D6|`y! zd1X}L=^mgcpKdG4l*)RUe~VlbcY<^DuPQ$7NO!C#GLdX`^&S^@Gu@+fGrPf(QkD-Z zAGxhpbFBV+gwF(e;{D0vLpW{9qL{h2nY0pQt_^+Uz%=Rx}_^dOT$IYlxm=;Q>wZs>Wzk1l|3rbYW(>D M9_43~eTIGf2iEsRVgLXD literal 0 HcmV?d00001 diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/DeviceMngr/DeviceManagerVfr.Vfr b/EdkNt32Pkg/Dxe/PlatformBds/Generic/DeviceMngr/DeviceManagerVfr.Vfr new file mode 100644 index 0000000000..5497c6df15 --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/Generic/DeviceMngr/DeviceManagerVfr.Vfr @@ -0,0 +1,75 @@ +// *++ +// +// Copyright (c) 2006, Intel Corporation +// All rights reserved. This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// Module Name: +// +// DeviceManagerVfr.vfr +// +// Abstract: +// +// Device Manager formset. +// +// Revision History: +// +// --*/ + +#include "BdsStrDefs.h" + +#define FORMSET_GUID { 0x3ebfa8e6, 0x511d, 0x4b5b, { 0xa9, 0x5f, 0xfb, 0x38, 0x26, 0xf, 0x1c, 0x27 } } + +#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 +#define EFI_VBIOS_CLASS 0x40 + +#define DEVICE_MANAGER_CLASS 0x0000 +#define FRONT_PAGE_SUBCLASS 0x0003 + +formset + guid = FORMSET_GUID, + title = STRING_TOKEN(STR_DEVICE_MANAGER_TITLE), + help = STRING_TOKEN(STR_EMPTY_STRING), + class = DEVICE_MANAGER_CLASS, + subclass = FRONT_PAGE_SUBCLASS, + + form formid = 0x1000, + title = STRING_TOKEN(STR_DEVICE_MANAGER_TITLE); + + // + // This is where devices get added to the device manager hierarchy + // + subtitle text = STRING_TOKEN(STR_DISK_DEVICE); + label EFI_DISK_DEVICE_CLASS; + + subtitle text = STRING_TOKEN(STR_VIDEO_DEVICE); + label EFI_VIDEO_DEVICE_CLASS; + + subtitle text = STRING_TOKEN(STR_NETWORK_DEVICE); + label EFI_NETWORK_DEVICE_CLASS; + + subtitle text = STRING_TOKEN(STR_INPUT_DEVICE); + label EFI_INPUT_DEVICE_CLASS; + + subtitle text = STRING_TOKEN(STR_ON_BOARD_DEVICE); + label EFI_ON_BOARD_DEVICE_CLASS; + + subtitle text = STRING_TOKEN(STR_OTHER_DEVICE); + label EFI_OTHER_DEVICE_CLASS; + + subtitle text = STRING_TOKEN(STR_EMPTY_STRING); + label EFI_VBIOS_CLASS; + + endform; +endformset; + diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/FrontPage.c b/EdkNt32Pkg/Dxe/PlatformBds/Generic/FrontPage.c new file mode 100644 index 0000000000..69b2fb5078 --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/Generic/FrontPage.c @@ -0,0 +1,888 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FrontPage.c + +Abstract: + + FrontPage routines to handle the callbacks and browser calls + +--*/ + +#include "Bds.h" +#include "BdsPlatform.h" +#include "FrontPage.h" +#include "String.h" + +EFI_GUID mProcessorSubClass = EFI_PROCESSOR_SUBCLASS_GUID; +EFI_GUID mMemorySubClass = EFI_MEMORY_SUBCLASS_GUID; +EFI_GUID mMiscSubClass = EFI_MISC_SUBCLASS_GUID; + +UINT16 mLastSelection; +EFI_HII_HANDLE gFrontPageHandle; +EFI_HANDLE FrontPageCallbackHandle; +EFI_FORM_CALLBACK_PROTOCOL FrontPageCallback; +EFI_FORM_BROWSER_PROTOCOL *gBrowser; +UINTN gCallbackKey; +BOOLEAN gConnectAllHappened = FALSE; + +extern EFI_HII_HANDLE gFrontPageHandle; +extern EFI_GUID gBdsStringPackGuid; + +EFI_STATUS +EFIAPI +FrontPageCallbackRoutine ( + IN EFI_FORM_CALLBACK_PROTOCOL *This, + IN UINT16 KeyValue, + IN EFI_IFR_DATA_ARRAY *DataArray, + OUT EFI_HII_CALLBACK_PACKET **Packet + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + KeyValue - 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 op-code that geerated the callback. + + Data - A pointer to the data being sent to the original exporting driver. + +Returns: + +--*/ +{ + CHAR16 *LanguageString; + UINTN Count; + CHAR16 UnicodeLang[3]; + CHAR8 Lang[3]; + EFI_STATUS Status; + UINTN Index; + CHAR16 *TmpStr; + EFI_UGA_PIXEL Foreground; + EFI_UGA_PIXEL Background; + EFI_UGA_PIXEL Color; + + SetMem (&Foreground, sizeof (EFI_UGA_PIXEL), 0xff); + SetMem (&Background, sizeof (EFI_UGA_PIXEL), 0x0); + SetMem (&Color, sizeof (EFI_UGA_PIXEL), 0xff); + + Count = 0; + + // + // The first 4 entries in the Front Page are to be GUARANTEED to remain constant so IHV's can + // describe to their customers in documentation how to find their setup information (namely + // under the device manager and specific buckets) + // + switch (KeyValue) { + case 0x0001: + // + // This is the continue - clear the screen and return an error to get out of FrontPage loop + // + gCallbackKey = 1; + break; + + case 0x1234: + // + // Collect the languages from what our current Language support is based on our VFR + // + Hii->GetPrimaryLanguages (Hii, gFrontPageHandle, &LanguageString); + + // + // Based on the DataArray->Data->Data value, we can determine + // which language was chosen by the user + // + for (Index = 0; Count != (UINTN) (((EFI_IFR_DATA_ENTRY *) (DataArray + 1))->Data); Index += 3) { + Count++; + } + // + // Preserve the choice the user made + // + mLastSelection = (UINT16) Count; + + // + // The Language (in Unicode format) the user chose + // + CopyMem (UnicodeLang, &LanguageString[Index], 6); + + // + // Convert Unicode to ASCII (Since the ISO standard assumes ASCII equivalent abbreviations + // we can be safe in converting this Unicode stream to ASCII without any loss in meaning. + // + for (Index = 0; Index < 3; Index++) { + Lang[Index] = (CHAR8) UnicodeLang[Index]; + } + + Status = gRT->SetVariable ( + L"Lang", + &gEfiGlobalVariableGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + 3, + Lang + ); + + gBS->FreePool (LanguageString); + gCallbackKey = 2; + break; + + case 0x1064: + // + // Boot Manager + // + gCallbackKey = 3; + break; + + case 0x8567: + // + // Device Manager + // + gCallbackKey = 4; + break; + + case 0x9876: + // + // Boot Maintenance Manager + // + gCallbackKey = 5; + break; + + case 0xFFFE: + + break; + + case 0xFFFF: + // + // FrontPage TimeOut Callback + // + TmpStr = GetStringById (STRING_TOKEN (STR_START_BOOT_OPTION)); + if (TmpStr != NULL) { + PlatformBdsShowProgress ( + Foreground, + Background, + TmpStr, + Color, + (UINTN) (((EFI_IFR_DATA_ENTRY *) (DataArray+1))->Data), + 0 + ); + gBS->FreePool (TmpStr); + } + break; + + default: + gCallbackKey = 0; + break; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +InitializeFrontPage ( + BOOLEAN ReInitializeStrings + ) +/*++ + +Routine Description: + + Initialize HII information for the FrontPage + +Arguments: + None + +Returns: + EFI_SUCCESS - The operation is successful. + EFI_DEVICE_ERROR - If the dynamic opcode creation failed. + +--*/ +{ + EFI_STATUS Status; + EFI_HII_PACKAGES *PackageList; + EFI_HII_UPDATE_DATA *UpdateData; + IFR_OPTION *OptionList; + CHAR16 *LanguageString; + UINTN OptionCount; + UINTN Index; + STRING_REF Token; + UINT16 Key; + CHAR8 AsciiLang[4]; + CHAR16 UnicodeLang[4]; + CHAR16 Lang[4]; + CHAR16 *StringBuffer; + UINTN BufferSize; + UINT8 *TempBuffer; + + UpdateData = NULL; + OptionList = NULL; + + if (ReInitializeStrings) { + // + // BugBug: Dont' use a goto + // + goto ReInitStrings; + } + // + // Go ahead and initialize the Device Manager + // + InitializeDeviceManager (); + + // + // BugBug: if FrontPageVfrBin is generated by a tool, why are we patching it here + // + TempBuffer = (UINT8 *) FrontPageVfrBin; + TempBuffer = TempBuffer + sizeof (EFI_HII_PACK_HEADER); + TempBuffer = (UINT8 *) &((EFI_IFR_FORM_SET *) TempBuffer)->NvDataSize; + *TempBuffer = 1; + + gCallbackKey = 0; + + PackageList = PreparePackages (1, &gBdsStringPackGuid, FrontPageVfrBin); + + Status = Hii->NewPack (Hii, PackageList, &gFrontPageHandle); + + gBS->FreePool (PackageList); + + // + // There will be only one FormConfig in the system + // If there is another out there, someone is trying to install us + // again. Fail that scenario. + // + Status = gBS->LocateProtocol ( + &gEfiFormBrowserProtocolGuid, + NULL, + &gBrowser + ); + + // + // This example does not implement worker functions + // for the NV accessor functions. Only a callback evaluator + // + FrontPageCallback.NvRead = NULL; + FrontPageCallback.NvWrite = NULL; + FrontPageCallback.Callback = FrontPageCallbackRoutine; + + // + // Install protocol interface + // + FrontPageCallbackHandle = NULL; + Status = gBS->InstallProtocolInterface ( + &FrontPageCallbackHandle, + &gEfiFormCallbackProtocolGuid, + EFI_NATIVE_INTERFACE, + &FrontPageCallback + ); + ASSERT_EFI_ERROR (Status); + +ReInitStrings: + // + // BugBug: This logic is in BdsInitLanguage. It should not be in two places! + // + BufferSize = 4; + Status = gRT->GetVariable ( + L"Lang", + &gEfiGlobalVariableGuid, + NULL, + &BufferSize, + AsciiLang + ); + + for (Index = 0; Index < 3; Index++) { + UnicodeLang[Index] = (CHAR16) AsciiLang[Index]; + } + + UnicodeLang[3] = 0; + + // + // Allocate space for creation of UpdateData Buffer + // + UpdateData = AllocateZeroPool (0x1000); + ASSERT (UpdateData != NULL); + + OptionList = AllocateZeroPool (0x1000); + ASSERT (OptionList != NULL); + + // + // Flag update pending in FormSet + // + UpdateData->FormSetUpdate = TRUE; + // + // Register CallbackHandle data for FormSet + // + UpdateData->FormCallbackHandle = (EFI_PHYSICAL_ADDRESS) (UINTN) FrontPageCallbackHandle; + UpdateData->FormUpdate = FALSE; + UpdateData->FormTitle = 0; + UpdateData->DataCount = 1; + + // + // Collect the languages from what our current Language support is based on our VFR + // + Hii->GetPrimaryLanguages (Hii, gFrontPageHandle, &LanguageString); + + OptionCount = 0; + + // + // Try for a 512 byte Buffer + // + BufferSize = 0x200; + + // + // Allocate memory for our Form binary + // + StringBuffer = AllocateZeroPool (BufferSize); + ASSERT (StringBuffer != NULL); + + for (Index = 0; LanguageString[Index] != 0; Index += 3) { + Token = 0; + CopyMem (Lang, &LanguageString[Index], 6); + Lang[3] = 0; + + if (!StrCmp (Lang, UnicodeLang)) { + mLastSelection = (UINT16) OptionCount; + } + + Status = Hii->GetString (Hii, gStringPackHandle, 1, TRUE, Lang, &BufferSize, StringBuffer); + Hii->NewString (Hii, NULL, gStringPackHandle, &Token, StringBuffer); + CopyMem (&OptionList[OptionCount].StringToken, &Token, sizeof (UINT16)); + CopyMem (&OptionList[OptionCount].Value, &OptionCount, sizeof (UINT16)); + Key = 0x1234; + CopyMem (&OptionList[OptionCount].Key, &Key, sizeof (UINT16)); + OptionList[OptionCount].Flags = EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_NV_ACCESS; + OptionCount++; + } + + gBS->FreePool (LanguageString); + + if (ReInitializeStrings) { + gBS->FreePool (StringBuffer); + gBS->FreePool (OptionList); + return EFI_SUCCESS; + } + + Status = CreateOneOfOpCode ( + FRONT_PAGE_QUESTION_ID, // Question ID + FRONT_PAGE_DATA_WIDTH, // Data Width + (STRING_REF) STRING_TOKEN (STR_LANGUAGE_SELECT), // Prompt Token + (STRING_REF) STRING_TOKEN (STR_LANGUAGE_SELECT_HELP), // Help Token + OptionList, // List of Options + OptionCount, // Number of Options + &UpdateData->Data // Data Buffer + ); + + // + // Assign the number of options and the oneof and endoneof op-codes to count + // + UpdateData->DataCount = (UINT8) (OptionCount + 2); + + Hii->UpdateForm (Hii, gFrontPageHandle, (EFI_FORM_LABEL) 0x0002, TRUE, UpdateData); + + gBS->FreePool (UpdateData); + // + // gBS->FreePool (OptionList); + // + gBS->FreePool (StringBuffer); + return Status; +} + +EFI_STATUS +CallFrontPage ( + VOID + ) +/*++ + +Routine Description: + + Call the browser and display the front page + +Arguments: + + None + +Returns: + +--*/ +{ + EFI_STATUS Status; + UINT8 FakeNvRamMap[1]; + + // + // Begin waiting for USER INPUT + // + REPORT_STATUS_CODE ( + EFI_PROGRESS_CODE, + (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_PC_INPUT_WAIT) + ); + + FakeNvRamMap[0] = (UINT8) mLastSelection; + Status = gBrowser->SendForm ( + gBrowser, + TRUE, // Use the database + &gFrontPageHandle, // The HII Handle + 1, + NULL, + FrontPageCallbackHandle, // This is the handle that the interface to the callback was installed on + FakeNvRamMap, + NULL, + NULL + ); + + Hii->ResetStrings (Hii, gFrontPageHandle); + + return Status; +} + +EFI_STATUS +GetStringFromToken ( + IN EFI_GUID *ProducerGuid, + IN STRING_REF Token, + OUT CHAR16 **String + ) +/*++ + +Routine Description: + + Acquire the string associated with the ProducerGuid and return it. + +Arguments: + + ProducerGuid - The Guid to search the HII database for + Token - The token value of the string to extract + String - The string that is extracted + +Returns: + + EFI_SUCCESS - The function returns EFI_SUCCESS always. + +--*/ +{ + EFI_STATUS Status; + UINT16 HandleBufferLength; + EFI_HII_HANDLE *HiiHandleBuffer; + UINTN StringBufferLength; + UINTN NumberOfHiiHandles; + UINTN Index; + UINT16 Length; + EFI_GUID HiiGuid; + + HandleBufferLength = 0x1000; + HiiHandleBuffer = NULL; + + // + // Get all the Hii handles + // + HiiHandleBuffer = AllocateZeroPool (HandleBufferLength); + + Status = Hii->FindHandles (Hii, &HandleBufferLength, HiiHandleBuffer); + ASSERT_EFI_ERROR (Status); + + // + // Get the Hii Handle that matches the StructureNode->ProducerName + // + NumberOfHiiHandles = HandleBufferLength / sizeof (EFI_HII_HANDLE); + for (Index = 0; Index < NumberOfHiiHandles; Index++) { + Length = 0; + Status = ExtractDataFromHiiHandle ( + HiiHandleBuffer[Index], + &Length, + NULL, + &HiiGuid + ); + if (CompareGuid (ProducerGuid, &HiiGuid)) { + break; + } + } + // + // Find the string based on the current language + // + StringBufferLength = 0x100; + *String = AllocateZeroPool (0x100); + Status = Hii->GetString ( + Hii, + HiiHandleBuffer[Index], + Token, + FALSE, + NULL, + &StringBufferLength, + *String + ); + + if (EFI_ERROR (Status)) { + gBS->FreePool (*String); + *String = GetStringById (STRING_TOKEN (STR_MISSING_STRING)); + } + + gBS->FreePool (HiiHandleBuffer); + return EFI_SUCCESS; +} + +VOID +ConvertProcessorToString ( + IN EFI_PROCESSOR_CORE_FREQUENCY_DATA *ProcessorFrequency, + OUT CHAR16 **String + ) +/*++ + +Routine Description: + + Convert Processor Frequency Data to a string + +Arguments: + + ProcessorFrequency - The frequency data to process + String - The string that is created + +Returns: + +--*/ +{ + CHAR16 *StringBuffer; + UINTN Index; + UINT32 FreqMhz; + + if (ProcessorFrequency->Exponent >= 6) { + FreqMhz = ProcessorFrequency->Value; + for (Index = 0; Index < (UINTN) (ProcessorFrequency->Exponent - 6); Index++) { + FreqMhz *= 10; + } + } else { + FreqMhz = 0; + } + + StringBuffer = AllocateZeroPool (0x20); + ASSERT (StringBuffer != NULL); + Index = UnicodeValueToString (StringBuffer, LEFT_JUSTIFY, FreqMhz / 1000, 3); + StrCat (StringBuffer, L"."); + UnicodeValueToString (StringBuffer + Index + 1, PREFIX_ZERO, (FreqMhz % 1000) / 10, 2); + StrCat (StringBuffer, L" GHz"); + + *String = (CHAR16 *) StringBuffer; + + return ; +} + +VOID +ConvertMemorySizeToString ( + IN UINT32 MemorySize, + OUT CHAR16 **String + ) +/*++ + +Routine Description: + + Convert Memory Size to a string + +Arguments: + + MemorySize - The size of the memory to process + String - The string that is created + +Returns: + +--*/ +{ + CHAR16 *StringBuffer; + + StringBuffer = AllocateZeroPool (0x20); + ASSERT (StringBuffer != NULL); + UnicodeValueToString (StringBuffer, LEFT_JUSTIFY, MemorySize, 6); + StrCat (StringBuffer, L" MB RAM"); + + *String = (CHAR16 *) StringBuffer; + + return ; +} + +VOID +UpdateFrontPageStrings ( + VOID + ) +/*++ + +Routine Description: + + Update the banner information for the Front Page based on DataHub information + +Arguments: + + None + +Returns: + +--*/ +{ + EFI_STATUS Status; + STRING_REF TokenToUpdate; + CHAR16 *NewString; + UINT64 MonotonicCount; + EFI_DATA_HUB_PROTOCOL *DataHub; + EFI_DATA_RECORD_HEADER *Record; + EFI_SUBCLASS_TYPE1_HEADER *DataHeader; + EFI_MISC_BIOS_VENDOR_DATA *BiosVendor; + EFI_MISC_SYSTEM_MANUFACTURER_DATA *SystemManufacturer; + EFI_PROCESSOR_VERSION_DATA *ProcessorVersion; + EFI_PROCESSOR_CORE_FREQUENCY_DATA *ProcessorFrequency; + EFI_MEMORY_ARRAY_START_ADDRESS_DATA *MemoryArray; + CHAR8 LangCode[3]; + CHAR16 Lang[3]; + UINTN Size; + UINTN Index; + BOOLEAN Find[5]; + + ZeroMem (Find, sizeof (Find)); + + // + // Update Front Page strings + // + Status = gBS->LocateProtocol ( + &gEfiDataHubProtocolGuid, + NULL, + &DataHub + ); + ASSERT_EFI_ERROR (Status); + + Size = 3; + + Status = gRT->GetVariable ( + L"Lang", + &gEfiGlobalVariableGuid, + NULL, + &Size, + LangCode + ); + + for (Index = 0; Index < 3; Index++) { + Lang[Index] = (CHAR16) LangCode[Index]; + } + + MonotonicCount = 0; + Record = NULL; + do { + Status = DataHub->GetNextRecord (DataHub, &MonotonicCount, NULL, &Record); + if (Record->DataRecordClass == EFI_DATA_RECORD_CLASS_DATA) { + DataHeader = (EFI_SUBCLASS_TYPE1_HEADER *) (Record + 1); + if (CompareGuid (&Record->DataRecordGuid, &mMiscSubClass) && + (DataHeader->RecordType == EFI_MISC_BIOS_VENDOR_RECORD_NUMBER) + ) { + BiosVendor = (EFI_MISC_BIOS_VENDOR_DATA *) (DataHeader + 1); + GetStringFromToken (&Record->ProducerName, BiosVendor->BiosVersion, &NewString); + TokenToUpdate = (STRING_REF) STR_FRONT_PAGE_BIOS_VERSION; + Hii->NewString (Hii, Lang, gFrontPageHandle, &TokenToUpdate, NewString); + gBS->FreePool (NewString); + Find[0] = TRUE; + } + + if (CompareGuid (&Record->DataRecordGuid, &mMiscSubClass) && + (DataHeader->RecordType == EFI_MISC_SYSTEM_MANUFACTURER_RECORD_NUMBER) + ) { + SystemManufacturer = (EFI_MISC_SYSTEM_MANUFACTURER_DATA *) (DataHeader + 1); + GetStringFromToken (&Record->ProducerName, SystemManufacturer->SystemProductName, &NewString); + TokenToUpdate = (STRING_REF) STR_FRONT_PAGE_COMPUTER_MODEL; + Hii->NewString (Hii, Lang, gFrontPageHandle, &TokenToUpdate, NewString); + gBS->FreePool (NewString); + Find[1] = TRUE; + } + + if (CompareGuid (&Record->DataRecordGuid, &mProcessorSubClass) && + (DataHeader->RecordType == ProcessorVersionRecordType) + ) { + ProcessorVersion = (EFI_PROCESSOR_VERSION_DATA *) (DataHeader + 1); + GetStringFromToken (&Record->ProducerName, *ProcessorVersion, &NewString); + TokenToUpdate = (STRING_REF) STR_FRONT_PAGE_CPU_MODEL; + Hii->NewString (Hii, Lang, gFrontPageHandle, &TokenToUpdate, NewString); + gBS->FreePool (NewString); + Find[2] = TRUE; + } + + if (CompareGuid (&Record->DataRecordGuid, &mProcessorSubClass) && + (DataHeader->RecordType == ProcessorCoreFrequencyRecordType) + ) { + ProcessorFrequency = (EFI_PROCESSOR_CORE_FREQUENCY_DATA *) (DataHeader + 1); + ConvertProcessorToString (ProcessorFrequency, &NewString); + TokenToUpdate = (STRING_REF) STR_FRONT_PAGE_CPU_SPEED; + Hii->NewString (Hii, Lang, gFrontPageHandle, &TokenToUpdate, NewString); + gBS->FreePool (NewString); + Find[3] = TRUE; + } + + if (CompareGuid (&Record->DataRecordGuid, &mMemorySubClass) && + (DataHeader->RecordType == EFI_MEMORY_ARRAY_START_ADDRESS_RECORD_NUMBER) + ) { + MemoryArray = (EFI_MEMORY_ARRAY_START_ADDRESS_DATA *) (DataHeader + 1); + ConvertMemorySizeToString((UINT32)(RShiftU64((MemoryArray->MemoryArrayEndAddress - + MemoryArray->MemoryArrayStartAddress + 1), 20)), + &NewString); + TokenToUpdate = (STRING_REF) STR_FRONT_PAGE_MEMORY_SIZE; + Hii->NewString (Hii, Lang, gFrontPageHandle, &TokenToUpdate, NewString); + gBS->FreePool (NewString); + Find[4] = TRUE; + } + } + } while (!EFI_ERROR (Status) && (MonotonicCount != 0) && !(Find[0] && Find[1] && Find[2] && Find[3] && Find[4])); + + return ; +} + +VOID +PlatformBdsEnterFrontPage ( + IN UINT16 TimeoutDefault, + IN BOOLEAN ConnectAllHappened + ) +/*++ + +Routine Description: + This function is the main entry of the platform setup entry. + The function will present the main menu of the system setup, + this is the platform reference part and can be customize. + +Arguments: + TimeoutDefault - The fault time out value before the system + continue to boot. + ConnectAllHappened - The indicater to check if the connect all have + already happended. + +Returns: + None + +--*/ +{ + EFI_STATUS Status; + EFI_HII_UPDATE_DATA *UpdateData; + EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl; + + // + // Indicate if we need connect all in the platform setup + // + if (ConnectAllHappened) { + gConnectAllHappened = TRUE; + } + // + // Allocate space for creation of Buffer + // + UpdateData = AllocateZeroPool (0x1000); + ASSERT (UpdateData != NULL); + + UpdateData->FormSetUpdate = FALSE; + UpdateData->FormCallbackHandle = 0; + UpdateData->FormUpdate = FALSE; + UpdateData->FormTitle = 0; + UpdateData->DataCount = 1; + + // + // Remove Banner Op-code if any at this label + // + Hii->UpdateForm (Hii, gFrontPageHandle, (EFI_FORM_LABEL) 0xFFFF, FALSE, UpdateData); + + // + // Create Banner Op-code which reflects correct timeout value + // + CreateBannerOpCode ( + STRING_TOKEN (STR_TIME_OUT_PROMPT), + TimeoutDefault, + (UINT8) EFI_IFR_BANNER_TIMEOUT, + &UpdateData->Data + ); + + // + // Add Banner Op-code at this label + // + Hii->UpdateForm (Hii, gFrontPageHandle, (EFI_FORM_LABEL) 0xFFFF, TRUE, UpdateData); + + do { + + InitializeFrontPage (TRUE); + + // + // Update Front Page strings + // + UpdateFrontPageStrings (); + + gCallbackKey = 0; + PERF_START (0, "BdsTimeOut", "BDS", 0); + Status = CallFrontPage (); + PERF_END (0, "BdsTimeOut", "BDS", 0); + + // + // If gCallbackKey is greater than 1 and less or equal to 5, + // it will lauch configuration utilities. + // 2 = set language + // 3 = boot manager + // 4 = device manager + // 5 = boot maintainenance manager + // + if ((gCallbackKey > 0x0001) && (gCallbackKey <= 0x0005)) { + REPORT_STATUS_CODE ( + EFI_PROGRESS_CODE, + (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_PC_USER_SETUP) + ); + } + // + // Based on the key that was set, we can determine what to do + // + switch (gCallbackKey) { + // + // The first 4 entries in the Front Page are to be GUARANTEED to remain constant so IHV's can + // describe to their customers in documentation how to find their setup information (namely + // under the device manager and specific buckets) + // + // These entries consist of the Continue, Select language, Boot Manager, and Device Manager + // + case 0x0001: + // + // User hit continue + // + break; + + case 0x0002: + // + // User made a language setting change - display front page again + // + break; + + case 0x0003: + // + // User chose to run the Boot Manager + // + CallBootManager (); + break; + + case 0x0004: + // + // Display the Device Manager + // + do { + CallDeviceManager(); + } while (gCallbackKey == 4); + break; + + case 0x0005: + // + // Display the Boot Maintenance Manager + // + BdsStartBootMaint (); + break; + } + + } while ((Status == EFI_SUCCESS) && (gCallbackKey != 1)); + + // + // Automatically load current entry + // Note: The following lines of code only execute when Auto boot + // takes affect + // + Status = gBS->LocateProtocol (&gEfiConsoleControlProtocolGuid, NULL, &ConsoleControl); + ConsoleControl->SetMode (ConsoleControl, EfiConsoleControlScreenText); + +} diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/FrontPage.h b/EdkNt32Pkg/Dxe/PlatformBds/Generic/FrontPage.h new file mode 100644 index 0000000000..82aa380b46 --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/Generic/FrontPage.h @@ -0,0 +1,100 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FrontPage.h + +Abstract: + + FrontPage routines to handle the callbacks and browser calls + +Revision History + +--*/ + +#ifndef _FRONT_PAGE_H +#define _FRONT_PAGE_H + +#include "Generic/DeviceMngr/DeviceManager.h" +#include "Generic/BootMaint/bootmaint.h" +#include "Generic/BootMngr/BootManager.h" + +// +// This is the VFR compiler generated header file which defines the +// string identifiers. +// +#include "BdsStrDefs.h" +#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 +#define EFI_VBIOS_CLASS 0x40 + +#define SET_VIDEO_BIOS_TYPE_QUESTION_ID 0x00 + +#pragma pack(1) +typedef struct { + UINT8 VideoBIOS; +} MyDevMgrIfrNVData; +#pragma pack() + +#define EFI_FP_CALLBACK_DATA_SIGNATURE EFI_SIGNATURE_32 ('F', 'P', 'C', 'B') +#define EFI_FP_CALLBACK_DATA_FROM_THIS(a) \ + CR (a, \ + EFI_FRONTPAGE_CALLBACK_INFO, \ + DevMgrCallback, \ + EFI_FP_CALLBACK_DATA_SIGNATURE \ + ) + +typedef struct { + UINTN Signature; + MyDevMgrIfrNVData Data; + EFI_HII_HANDLE DevMgrHiiHandle; + EFI_HANDLE CallbackHandle; + EFI_FORM_CALLBACK_PROTOCOL DevMgrCallback; +} EFI_FRONTPAGE_CALLBACK_INFO; + +// +// These are the VFR compiler generated data representing our VFR data. +// +// BugBug: we should put g in front of these tool generated globals. +// maybe even gVrf would be a better prefix +// +extern UINT8 FrontPageVfrBin[]; +extern UINT8 FrontPageStringsStr[]; +extern UINT8 DeviceManagerVfrBin[]; +extern UINT8 DeviceManagerStringsStr[]; + +#define FRONT_PAGE_QUESTION_ID 0x0000 +#define FRONT_PAGE_DATA_WIDTH 0x01 + +EFI_STATUS +InitializeFrontPage ( + IN BOOLEAN ReInitializeStrings + ); + +BOOLEAN +TimeCompare ( + IN EFI_TIME *FirstTime, + IN EFI_TIME *SecondTime + ); + +VOID +PlatformBdsEnterFrontPage ( + IN UINT16 TimeoutDefault, + IN BOOLEAN ConnectAllHappened + ); + +#endif // _FRONT_PAGE_H_ + diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/FrontPageStrings.uni b/EdkNt32Pkg/Dxe/PlatformBds/Generic/FrontPageStrings.uni new file mode 100644 index 0000000000000000000000000000000000000000..76dbdcfd4ff44a0354794969f2cc20be2dc13857 GIT binary patch literal 9938 zcmd6t-A)@v6vyYbmHG}VqAE?=Ktj^AiPQ@lOk&kG2$PTI#xmG|TQIHdkkW_BGxe_F zCEEUfa~NiAuRnnpt?CS76DbD_7CIpmF@gW{6%}6gm||QS~!#ss%dmyQDkw zGV7A=dEci8zD;{Y?%!x8*5CBJCGL&p+x9Y4G+xyDthVX-+*S`M8H2kW(Lw`%MztYY z`20oppY;S8;j3`5ipg7WZ!hPGvlpecEk!JAu6vXlB~9c$w#xGFhL1NQucCN4Rt!A9 z%n^~2S*wZ`VizRrYOPbnYUh$RNwso5I-mv>dZ`)HRD*LS9_RM`3jH`mOoMQFQFJ9Q z2-wr=jDp{x1>*O_S>!vmw)O1PBT&d$FMY4)XE__e;{!$b{fn$=bN%G*`1$GG@tmL! z5E?AyLMwIMm)wSLwcS7JgMCZ>&Fr_p9x}|5EJ+KL>k3Qk9a}A+r%_sj)U*mQglE;H zo1CJlpcX#1BhMhpvaZO*dvSLl{uBM#%z<}u1_-)!L1DaP%{Kp779T-_n-5Ea_}mFl<9AjTg%3X2mQ?(^#;nJiQ1k%zNLN2Z{P6el)Y!u1f1$vLE@NC2JhJ zj~aRF|C*kwu&ZJh)73?8?&^6*)NNf>H-wt}NAKC}$o^W0CP&MIm%_L05rZ^MA8m}= zUhJ)?Z0F0)3jf9Ld;ZP8MKvtnRXh}X&E}!2?uoeAQN=`FJQH8w3$>C}+KcesG*6-4 zH*E$EKZ(QUg+E+HU#m0wcTRf;vKU@n5b_jt4;dy=h5?(q@?o?2BllQU=J#HkAazsL zr}i`qd+eU+=`)?7EJDjSDaloA@_1&ORK3>ioQ2&9sKXw=qgowJzti8UEb&B^cx61vKB#?|yPmb?sBy;BdL zU-Uz4rRBCUviU2R3REISL^vr|ilnrFDWn3O@Odn}hw(S(>Ep64nf zSv;icl|ddl6Od(6kDz^XOL!x~@ZzvL_b7m9+g$L2(b9roH4A_0^Oa&z`d9dRIz zZBM=!s~k$7oIc=j=p4;Q&O)?~LX7cxs`+!f;i#EDPT(v?0Oz(bUhsT8gfsJBrA6u< zqqfMv2hcAx;j|z5(mD_4Ns(etGj()X)`9YIV{&BiHcyu6$wz+kesdL}Sxp17WhP^#xs!6)KF0a3BI=?9o&&^~rzNc|QR8tkh zH>B&?2S=emzgwcZ$>U|_`HV1!}6eu@%e)@iIOh9I@$jVRCJF2g=QOfWl2P?;`=M#9Ou#E qJZq-4I9|@OyszrNaUtJy(oT}HETqEM@Fpa$`pj*;MQC6$KmP;y^-p;K literal 0 HcmV?d00001 diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/FrontPageVfr.Vfr b/EdkNt32Pkg/Dxe/PlatformBds/Generic/FrontPageVfr.Vfr new file mode 100644 index 0000000000..77efd2d949 --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/Generic/FrontPageVfr.Vfr @@ -0,0 +1,159 @@ +// *++ +// +// Copyright (c) 2006, Intel Corporation +// All rights reserved. This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// Module Name: +// +// FrontPageVfr.vfr +// +// Abstract: +// +// Browser formset. +// +// Revision History: +// +// --*/ + +#include "BdsStrDefs.h" + +#define FORMSET_GUID { 0x9e0c30bc, 0x3f06, 0x4ba6, { 0x82, 0x88, 0x9, 0x17, 0x9b, 0x85, 0x5d, 0xbe } } + +#define FRONT_PAGE_ITEM_ONE 0x0001 +#define FRONT_PAGE_ITEM_TWO 0x0002 +#define FRONT_PAGE_ITEM_THREE 0x0003 +#define FRONT_PAGE_ITEM_FOUR 0x0004 +#define FRONT_PAGE_ITEM_FIVE 0x0005 + +#define FRONT_PAGE_TIMEOUT 0xFFFF +#define FRONT_PAGE_CLASS 0x0000 +#define FRONT_PAGE_SUBCLASS 0x0002 + +formset + guid = FORMSET_GUID, + title = STRING_TOKEN(STR_FRONT_PAGE_TITLE), + help = STRING_TOKEN(STR_NULL_STRING), + class = FRONT_PAGE_CLASS, + subclass = FRONT_PAGE_SUBCLASS, + + form formid = 0x1000, + title = STRING_TOKEN(STR_FRONT_PAGE_TITLE); + + banner + title = STRING_TOKEN(STR_FRONT_PAGE_COMPUTER_MODEL), + line 0, + align left; + + banner + title = STRING_TOKEN(STR_FRONT_PAGE_CPU_MODEL), + line 1, + align left; + + banner + title = STRING_TOKEN(STR_FRONT_PAGE_CPU_SPEED), + line 1, + align right; + + banner + title = STRING_TOKEN(STR_FRONT_PAGE_BIOS_VERSION), + line 2, + align left; + + banner + title = STRING_TOKEN(STR_FRONT_PAGE_MEMORY_SIZE), + line 2, + align right; + +// banner +// title = STRING_TOKEN(STR_FRONT_PAGE_BANNER_0_LEFT), +// line 0, +// align left; + +// banner +// title = STRING_TOKEN(STR_FRONT_PAGE_BANNER_0_RIGHT), +// line 0, +// align right; + +// banner +// title = STRING_TOKEN(STR_FRONT_PAGE_BANNER_1_LEFT), +// line 1, +// align left; + +// banner +// title = STRING_TOKEN(STR_FRONT_PAGE_BANNER_1_RIGHT), +// line 1, +// align right; + +// banner +// title = STRING_TOKEN(STR_FRONT_PAGE_BANNER_2_LEFT), +// line 2, +// align left; + +// banner +// title = STRING_TOKEN(STR_FRONT_PAGE_BANNER_3_LEFT), +// line 3, +// align left; + + goto FRONT_PAGE_ITEM_ONE, + prompt = STRING_TOKEN(STR_CONTINUE_PROMPT), + help = STRING_TOKEN(STR_CONTINUE_HELP), + flags = INTERACTIVE | NV_ACCESS, + key = 0x0001; + + label FRONT_PAGE_ITEM_TWO; + // + // This is where we will dynamically add a OneOf type op-code to select Languages from the + // currently available choices + // + + goto FRONT_PAGE_ITEM_THREE, + prompt = STRING_TOKEN(STR_BOOT_MANAGER), + help = STRING_TOKEN(STR_BOOT_MANAGER_HELP), + flags = INTERACTIVE | NV_ACCESS, + key = 0x1064; + + goto FRONT_PAGE_ITEM_FOUR, + prompt = STRING_TOKEN(STR_DEVICE_MANAGER), + help = STRING_TOKEN(STR_DEVICE_MANAGER_HELP), + flags = INTERACTIVE | NV_ACCESS, + key = 0x8567; + + goto FRONT_PAGE_ITEM_FIVE, + prompt = STRING_TOKEN(STR_BOOT_MAINT_MANAGER), + help = STRING_TOKEN(STR_BOOT_MAINT_MANAGER_HELP), + flags = INTERACTIVE | NV_ACCESS, + key = 0x9876; + + label FRONT_PAGE_TIMEOUT; +// If one wanted to hard-code a value one could do it below, but our implementation follows EFI architecture +// and honors the TimeOut NV variable +// +// banner +// title = STRING_TOKEN(STR_TIME_OUT_PROMPT), +// timeout = 0x000A; + + endform; + + form formid = FRONT_PAGE_ITEM_ONE, + title = STRING_TOKEN(STR_FRONT_PAGE_TITLE); + endform; + + form formid = FRONT_PAGE_ITEM_THREE, + title = STRING_TOKEN(STR_FRONT_PAGE_TITLE); + endform; + + form formid = FRONT_PAGE_ITEM_FOUR, + title = STRING_TOKEN(STR_FRONT_PAGE_TITLE); + endform; + + form formid = FRONT_PAGE_ITEM_FIVE, + title = STRING_TOKEN(STR_FRONT_PAGE_TITLE); + endform; + +endformset; diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/Language.c b/EdkNt32Pkg/Dxe/PlatformBds/Generic/Language.c new file mode 100644 index 0000000000..21d61f1135 --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/Generic/Language.c @@ -0,0 +1,431 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + language.c + +Abstract: + + Language settings + +Revision History + +--*/ + +#include "String.h" +#include "Language.h" + +#define NARROW_GLYPH_NUMBER 8 +#define WIDE_GLYPH_NUMBER 75 + +// +// Default language code, currently is English +// +CHAR8 *mDefaultLangCode = "eng"; + +typedef struct { + EFI_HII_FONT_PACK FixedLength; + EFI_NARROW_GLYPH NarrowArray[NARROW_GLYPH_NUMBER]; + EFI_WIDE_GLYPH WideArray[WIDE_GLYPH_NUMBER]; +} FONT_PACK; + +FONT_PACK mFontPack = { + sizeof (EFI_HII_FONT_PACK) + (NARROW_GLYPH_NUMBER * sizeof (EFI_NARROW_GLYPH)) + (WIDE_GLYPH_NUMBER * sizeof (EFI_WIDE_GLYPH)), + EFI_HII_FONT, + NARROW_GLYPH_NUMBER, + WIDE_GLYPH_NUMBER, + { // 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 + } + } + }, + { // Wide Glyphs + { + 0x0020, + 0x00, + { + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00 + }, + { + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00 + }, + { + 0x00, + 0x00, + 0x00 + } + }, // + } +}; + +VOID +ExportFonts ( + VOID + ) +/*++ + +Routine Description: + Routine to export glyphs to the HII database. This is in addition to whatever is defined in the Graphics Console driver. + +Arguments: + None + +Returns: + +--*/ +{ + EFI_HII_HANDLE HiiHandle; + EFI_HII_PACKAGES *PackageList; + + PackageList = PreparePackages (1, NULL, &mFontPack); + // + // Register our Fonts into the global database + // + HiiHandle = 0; + Hii->NewPack (Hii, PackageList, &HiiHandle); + + gBS->FreePool (PackageList); +} + +VOID +InitializeLanguage ( + BOOLEAN LangCodesSettingRequired + ) +/*++ + +Routine Description: + Determine the current language that will be used + based on language related EFI Variables + +Arguments: + LangCodesSettingRequired - If required to set LangCode variable + +Returns: + +--*/ +{ + EFI_STATUS Status; + UINTN Index; + UINTN Size; + CHAR8 LangCode[ISO_639_2_ENTRY_SIZE]; + CHAR8 *LangCodes; + CHAR16 *LanguageString; + + LanguageString = NULL; + LangCodes = NULL; + + ExportFonts (); + + // + // Collect the languages from what our current Language support is based on our VFR + // + Hii->GetPrimaryLanguages (Hii, gStringPackHandle, &LanguageString); + + LangCodes = AllocatePool (StrLen (LanguageString)); + ASSERT (LangCodes); + + // + // Convert LanguageString from Unicode to EFI defined ASCII LangCodes + // + for (Index = 0; LanguageString[Index] != 0x0000; Index++) { + LangCodes[Index] = (CHAR8) LanguageString[Index]; + } + + LangCodes[Index] = 0; + + if (LangCodesSettingRequired) { + Status = gRT->SetVariable ( + L"LangCodes", + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + AsciiStrLen (LangCodes), + LangCodes + ); + } + // + // Find current LangCode from Lang NV Variable + // + Size = ISO_639_2_ENTRY_SIZE; + Status = gRT->GetVariable ( + L"Lang", + &gEfiGlobalVariableGuid, + NULL, + &Size, + &LangCode + ); + + if (!EFI_ERROR (Status)) { + Status = EFI_NOT_FOUND; + for (Index = 0; LangCodes[Index] != 0; Index += ISO_639_2_ENTRY_SIZE) { + if (CompareMem (&LangCodes[Index], LangCode, ISO_639_2_ENTRY_SIZE) == 0) { + Status = EFI_SUCCESS; + break; + } + } + } + // + // If we cannot get language code from Lang variable, + // or LangCode cannot be found from language table, + // set the mDefaultLangCode to Lang variable. + // + if (EFI_ERROR (Status)) { + Status = gRT->SetVariable ( + L"Lang", + &gEfiGlobalVariableGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + ISO_639_2_ENTRY_SIZE, + mDefaultLangCode + ); + } + + if (LangCodes) { + gBS->FreePool (LangCodes); + } + + if (LanguageString != NULL) { + gBS->FreePool (LanguageString); + } + +} diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/Language.h b/EdkNt32Pkg/Dxe/PlatformBds/Generic/Language.h new file mode 100644 index 0000000000..6b6d887040 --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/Generic/Language.h @@ -0,0 +1,36 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Language.h + +Abstract: + + Language setting + +Revision History + +--*/ + +#ifndef _LANGUAGE_H +#define _LANGUAGE_H + +#ifndef ISO_639_2_ENTRY_SIZE +#define ISO_639_2_ENTRY_SIZE 3 +#endif + +VOID +InitializeLanguage ( + BOOLEAN LangCodesSettingRequired + ); + +#endif // _LANGUAGE_H_ diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/MemoryTest.c b/EdkNt32Pkg/Dxe/PlatformBds/Generic/MemoryTest.c new file mode 100644 index 0000000000..f1fedf391a --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/Generic/MemoryTest.c @@ -0,0 +1,386 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + MemoryTest.c + +Abstract: + + Perform the platform memory test + +--*/ + +#include "bds.h" +#include "BdsPlatform.h" +#include "String.h" + +// +// BDS Platform Functions +// +EFI_STATUS +PlatformBdsShowProgress ( + IN EFI_UGA_PIXEL TitleForeground, + IN EFI_UGA_PIXEL TitleBackground, + IN CHAR16 *Title, + IN EFI_UGA_PIXEL ProgressColor, + IN UINTN Progress, + IN UINTN PreviousValue + ) +/*++ + +Routine Description: + + Show progress bar with title above it. It only works in UGA mode. + +Arguments: + + TitleForeground - Foreground color for Title. + TitleBackground - Background color for Title. + Title - Title above progress bar. + ProgressColor - Progress bar color. + Progress - Progress (0-100) + +Returns: + + EFI_STATUS - Success update the progress bar + +--*/ +{ + EFI_STATUS Status; + EFI_UGA_DRAW_PROTOCOL *UgaDraw; + UINT32 SizeOfX; + UINT32 SizeOfY; + UINT32 ColorDepth; + UINT32 RefreshRate; + EFI_UGA_PIXEL Color; + UINTN BlockHeight; + UINTN BlockWidth; + UINTN BlockNum; + UINTN PosX; + UINTN PosY; + UINTN Index; + + if (Progress > 100) { + return EFI_INVALID_PARAMETER; + } + + Status = gBS->HandleProtocol ( + gST->ConsoleOutHandle, + &gEfiUgaDrawProtocolGuid, + &UgaDraw + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Status = UgaDraw->GetMode ( + UgaDraw, + &SizeOfX, + &SizeOfY, + &ColorDepth, + &RefreshRate + ); + if (EFI_ERROR (Status)) { + 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_UGA_PIXEL), 0x0); + + Status = UgaDraw->Blt ( + UgaDraw, + &Color, + EfiUgaVideoFill, + 0, + 0, + 0, + PosY - GLYPH_HEIGHT - 1, + SizeOfX, + SizeOfY - (PosY - GLYPH_HEIGHT - 1), + SizeOfX * sizeof (EFI_UGA_PIXEL) + ); + } + // + // Show progress by drawing blocks + // + for (Index = PreviousValue; Index < BlockNum; Index++) { + PosX = Index * BlockWidth; + Status = UgaDraw->Blt ( + UgaDraw, + &ProgressColor, + EfiUgaVideoFill, + 0, + 0, + PosX, + PosY, + BlockWidth - 1, + BlockHeight, + (BlockWidth) * sizeof (EFI_UGA_PIXEL) + ); + } + + PrintXY ( + (SizeOfX - StrLen (Title) * GLYPH_WIDTH) / 2, + PosY - GLYPH_HEIGHT - 1, + &TitleForeground, + &TitleBackground, + Title + ); + + return EFI_SUCCESS; +} + +EFI_STATUS +BdsMemoryTest ( + IN EXTENDMEM_COVERAGE_LEVEL Level + ) +/*++ + +Routine Description: + + Perform the memory test base on the memory test intensive level, + and update the memory resource. + +Arguments: + + Level - The memory test intensive level. + +Returns: + + EFI_STATUS - Success test all the system memory and update + the memory resource + +--*/ +{ + EFI_STATUS Status; + EFI_STATUS InitStatus; + EFI_STATUS KeyStatus; + EFI_STATUS ReturnStatus; + BOOLEAN RequireSoftECCInit; + EFI_GENERIC_MEMORY_TEST_PROTOCOL *GenMemoryTest; + UINT64 TestedMemorySize; + UINT64 TotalMemorySize; + UINTN TestPercent; + UINT64 PreviousValue; + BOOLEAN ErrorOut; + BOOLEAN TestAbort; + EFI_INPUT_KEY Key; + CHAR16 StrPercent[16]; + CHAR16 *StrTotalMemory; + CHAR16 *Pos; + CHAR16 *TmpStr; + EFI_UGA_PIXEL Foreground; + EFI_UGA_PIXEL Background; + EFI_UGA_PIXEL Color; + UINT8 Value; + UINTN DataSize; + UINT32 Attributes; + + ReturnStatus = EFI_SUCCESS; + ZeroMem (&Key, sizeof (EFI_INPUT_KEY)); + + Pos = AllocatePool (128); + + if (Pos == NULL) { + return ReturnStatus; + } + + StrTotalMemory = Pos; + + TestedMemorySize = 0; + TotalMemorySize = 0; + PreviousValue = 0; + ErrorOut = FALSE; + TestAbort = FALSE; + + SetMem (&Foreground, sizeof (EFI_UGA_PIXEL), 0xff); + SetMem (&Background, sizeof (EFI_UGA_PIXEL), 0x0); + SetMem (&Color, sizeof (EFI_UGA_PIXEL), 0xff); + + RequireSoftECCInit = FALSE; + + gST->ConOut->ClearScreen (gST->ConOut); + gST->ConOut->SetAttribute (gST->ConOut, EFI_YELLOW | EFI_BRIGHT); + gST->ConOut->EnableCursor (gST->ConOut, FALSE); + + Status = gBS->LocateProtocol ( + &gEfiGenericMemTestProtocolGuid, + NULL, + &GenMemoryTest + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (Pos); + return EFI_SUCCESS; + } + + InitStatus = GenMemoryTest->MemoryTestInit ( + GenMemoryTest, + Level, + &RequireSoftECCInit + ); + if (InitStatus == EFI_NO_MEDIA) { + // + // The PEI codes also have the relevant memory test code to check the memory, + // it can select to test some range of the memory or all of them. If PEI code + // checks all the memory, this BDS memory test will has no not-test memory to + // do the test, and then the status of EFI_NO_MEDIA will be returned by + // "MemoryTestInit". So it does not need to test memory again, just return. + // + gBS->FreePool (Pos); + return EFI_SUCCESS; + } + + gST->ConOut->SetCursorPosition (gST->ConOut, 0, 2); + TmpStr = GetStringById (STRING_TOKEN (STR_ESC_TO_SKIP_MEM_TEST)); + + if (TmpStr != NULL) { + gST->ConOut->OutputString (gST->ConOut, TmpStr); + gBS->FreePool (TmpStr); + } + + do { + Status = GenMemoryTest->PerformMemoryTest ( + GenMemoryTest, + &TestedMemorySize, + &TotalMemorySize, + &ErrorOut, + TestAbort + ); + if (ErrorOut && (Status == EFI_DEVICE_ERROR)) { + TmpStr = GetStringById (STRING_TOKEN (STR_SYSTEM_MEM_ERROR)); + if (TmpStr != NULL) { + PrintXY (10, 10, NULL, NULL, TmpStr); + gST->ConOut->SetCursorPosition (gST->ConOut, 0, 4); + gST->ConOut->OutputString (gST->ConOut, TmpStr); + gBS->FreePool (TmpStr); + } + + ASSERT (0); + } + + TestPercent = (UINTN) DivU64x32 ( + DivU64x32 (MultU64x32 (TestedMemorySize, 100), 16), + (UINTN)DivU64x32 (TotalMemorySize, 16) + ); + if (TestPercent != PreviousValue) { + UnicodeValueToString (StrPercent, 0, TestPercent, 0); + gST->ConOut->SetCursorPosition (gST->ConOut, 0, 0); + TmpStr = GetStringById (STRING_TOKEN (STR_MEMORY_TEST_PERCENT)); + if (TmpStr != NULL) { + BdsLibOutputStrings (gST->ConOut, StrPercent, TmpStr, NULL); + gBS->FreePool (TmpStr); + } + + TmpStr = GetStringById (STRING_TOKEN (STR_PERFORM_MEM_TEST)); + if (TmpStr != NULL) { + PlatformBdsShowProgress ( + Foreground, + Background, + TmpStr, + Color, + TestPercent, + (UINTN) PreviousValue + ); + gBS->FreePool (TmpStr); + } + } + + PreviousValue = TestPercent; + + KeyStatus = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + if (Key.ScanCode == SCAN_ESC) { + if (!RequireSoftECCInit) { + TmpStr = GetStringById (STRING_TOKEN (STR_PERFORM_MEM_TEST)); + if (TmpStr != NULL) { + PlatformBdsShowProgress ( + Foreground, + Background, + TmpStr, + Color, + 100, + (UINTN) PreviousValue + ); + gBS->FreePool (TmpStr); + } + + gST->ConOut->SetCursorPosition (gST->ConOut, 0, 0); + gST->ConOut->OutputString (gST->ConOut, L"100"); + Status = GenMemoryTest->Finished (GenMemoryTest); + goto Done; + } + + TestAbort = TRUE; + } + } while (Status != EFI_NOT_FOUND); + + Status = GenMemoryTest->Finished (GenMemoryTest); + +Done: + UnicodeValueToString (StrTotalMemory, COMMA_TYPE, (UINTN) TotalMemorySize, 0); + if (StrTotalMemory[0] == L',') { + StrTotalMemory++; + } + + TmpStr = GetStringById (STRING_TOKEN (STR_MEM_TEST_COMPLETED)); + if (TmpStr != NULL) { + StrCat (StrTotalMemory, TmpStr); + gBS->FreePool (TmpStr); + } + + gST->ConOut->ClearScreen (gST->ConOut); + gST->ConOut->SetAttribute (gST->ConOut, EFI_YELLOW | EFI_BRIGHT); + gST->ConOut->EnableCursor (gST->ConOut, FALSE); + gST->ConOut->OutputString (gST->ConOut, StrTotalMemory); + PlatformBdsShowProgress ( + Foreground, + Background, + StrTotalMemory, + Color, + 100, + (UINTN) PreviousValue + ); + + gBS->FreePool (Pos); + + DataSize = sizeof (Value); + Status = gRT->GetVariable ( + L"BootState", + &gEfiBootStateGuid, + &Attributes, + &DataSize, + &Value + ); + + if (EFI_ERROR (Status)) { + Value = 1; + gRT->SetVariable ( + L"BootState", + &gEfiBootStateGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof (Value), + &Value + ); + } + + return ReturnStatus; +} diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/String.c b/EdkNt32Pkg/Dxe/PlatformBds/Generic/String.c new file mode 100644 index 0000000000..412b7f8f17 --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/Generic/String.c @@ -0,0 +1,133 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + string.c + +Abstract: + + String support + +Revision History + +--*/ + +#include "Bds.h" +#include "String.h" +#include "Language.h" + +extern UINT8 BdsStrings[]; + +EFI_GUID gBdsStringPackGuid = { 0x7bac95d3, 0xddf, 0x42f3, 0x9e, 0x24, 0x7c, 0x64, 0x49, 0x40, 0x37, 0x9a }; + +EFI_STATUS +InitializeStringSupport ( + VOID + ) +/*++ + +Routine Description: + + Initialize HII global accessor for string support + +Arguments: + None + +Returns: + String from ID. + +--*/ +{ + EFI_STATUS Status; + EFI_HII_PACKAGES *PackageList; + // + // There should only ever be one HII protocol + // + Status = gBS->LocateProtocol ( + &gEfiHiiProtocolGuid, + NULL, + &Hii + ); + if (!EFI_ERROR (Status)) { + PackageList = PreparePackages (1, &gBdsStringPackGuid, BdsStrings); + Status = Hii->NewPack (Hii, PackageList, &gStringPackHandle); + gBS->FreePool (PackageList); + } + + return Status; +} + +CHAR16 * +GetStringById ( + IN STRING_REF Id + ) +/*++ + +Routine Description: + + Get string by string id from HII Interface + +Arguments: + + Id - String ID. + +Returns: + + CHAR16 * - String from ID. + NULL - If error occurs. + +--*/ +{ + CHAR16 *String; + UINTN StringLength; + EFI_STATUS Status; + + // + // Set default string size assumption at no more than 256 bytes + // + StringLength = 0x100; + + String = AllocateZeroPool (StringLength); + if (String == NULL) { + // + // If this happens, we are oh-so-dead, but return a NULL in any case. + // + return NULL; + } + // + // Get the current string for the current Language + // + Status = Hii->GetString (Hii, gStringPackHandle, Id, FALSE, NULL, &StringLength, String); + if (EFI_ERROR (Status)) { + if (Status == EFI_BUFFER_TOO_SMALL) { + // + // Free the old pool + // + gBS->FreePool (String); + + // + // Allocate new pool with correct value + // + String = AllocatePool (StringLength); + ASSERT (String != NULL); + + Status = Hii->GetString (Hii, gStringPackHandle, Id, FALSE, NULL, &StringLength, String); + if (!EFI_ERROR (Status)) { + return String; + } + } + + return NULL; + } + + return String; +} diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/String.h b/EdkNt32Pkg/Dxe/PlatformBds/Generic/String.h new file mode 100644 index 0000000000..0800febc5e --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/Generic/String.h @@ -0,0 +1,59 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + string.h + +Abstract: + + String support + +Revision History + +--*/ + +#ifndef _STRING_H_ +#define _STRING_H_ + +// +// This is the VFR compiler generated header file which defines the +// string identifiers. +// +#include "BdsStrDefs.h" + +// +// String Definition Guid for BDS Platform +// +#define EFI_BDS_PLATFORM_GUID \ + { \ + 0x7777E939, 0xD57E, 0x4DCB, {0xA0, 0x8E, 0x64, 0xD7, 0x98, 0x57, 0x1E, 0x0F } \ + } + +EFI_HII_HANDLE gStringPackHandle; +EFI_HII_PROTOCOL *Hii; + +CHAR16 * +GetStringById ( + IN STRING_REF Id + ); + +EFI_STATUS +InitializeStringSupport ( + VOID + ); + +EFI_STATUS +CallFrontPage ( + VOID + ); + +#endif // _STRING_H_ diff --git a/EdkNt32Pkg/Dxe/PlatformBds/Generic/Strings.uni b/EdkNt32Pkg/Dxe/PlatformBds/Generic/Strings.uni new file mode 100644 index 0000000000000000000000000000000000000000..41a6b9acde8918e541b99ad20398331ff92d4d3d GIT binary patch literal 7870 zcmd6s-%cAx6vpSeQs2QPs?wwlRK4g$q+S?o5~~;^3{9e{vH%0I0+@IWDNo$;5^cZV zISe!Fc)dl9;%epH+1c6I?|kR)jQ{>?Ev$t`cpARd@n!fzcWd|8M%W1Ba2amGB#gpo zcpIh~`%O3sPjvkue6Qoj@SWP7aG__%;Y@AbndmLf2kITEb)o*xeMD&*p($J-OHvee zcN_{~o`h?ihhbHHdy;Xa-iGi`g!|NFIM@AwWEko?)re!eKN1h)aITR&yU}|W8sAV4 zQZw&JtuveL;j$<62bzg5o@u@#wJr=bSRy9AIJ`r3t@cP`55l3&ymw{D!IRKCzH`GC zXF(cd9Np^-9>(D$dv87TLreEtB`hCHm(YJOMvrs`Z<(`^@bL{eb=LWMp?kPH6!K_2 z=*G2!L??RU8byxZHEI@TnJd@HjYb_BBPWu|SpgGomyd)Vi=Rrv&&@CJ1?QjlC#H>6 z%{7tU*JkunsOM0!48yaTC##y}t$yWie!9Da{?pC*`DRM!_rlB27E3!}H}t{_otvSn z`;Kg|AuHs%r`}Fj5BqAh%`*4HwytgUV=q2Kvf7TKQ(GhYHgiucq66m@U743zS9D#s zd+vyD|Mp1eUuh=3-!p8D@JjRTnhe|O@96t{t!FrQb%&Jnfo@M@83R5awW+b-e532n zdV-ALYTtduN$69nEBhXrzu|e?@|Sb@!1MbYkw!9W zU*3Z65(x`^>sr1#xgXoeT21o~MiUjL*^K$9**O~)=T7VkOSn^OSI@330>zy5((a}<%S{EwXY%l;cUjZt`YAlJ`MG;!NZ^AAO)TYr zl>=Q@!ltz@!XLUP_N~~P^WP%&kYQG&Nm@j?Lb1f(@vp_`=_B1k24*pM$gVWllr0R@ z-c;{E8pB7nbU3p7oKRc|-Kp?5^z)fP@vCO=yg$*ET!%$6FP1=_Buf8whcBP`zqjXM zi>x{}EWoRg_p)DdqUS@b)AQejN#vQ+aYw9=#A~u-q#@D_#8O+4sHrIOMtAG-(4L+Q z)U!yUd06Xs+!D4^NpPgf0;?YDAX7DEg%RbVZ$A9lJd|Zd!9?x{S)tY}lN-`G)rwn6 zj?!}o+M-ZJ`$ViF z*;x3gtnezgUiVe%yi`4HhF_MZgNIAjFxlK2sPW3);MSjOj`)s;5Noe=&ZVu=WAcPe zG2Ic9o{bk@7-s}k6- z`U7qj^D_@iZsCcUzH~%YeXIjrV!hAwTLwe96*UwuZ-ov288|C)b!{b=VdsTL;D0HiPk5u4~ zu`8D>$6v+xj%9<*JFW+oFS?dHs3`X;tg?>r9YY;gjO-pA>j&r5;^cmEJv*U%WyAW$ zIv3%ceECw<8JTu+DcG}RUkgddn7&Gi(p2ey z9NjeyuqI-a3G)MK8&B~4mX9@2r-QGBqP+K5h<$iR7gaj(Jl)eC$ucwmX6M-R^(@o= zEXwhx*%d2lYNP{6cWZiUNpGw$$-cXauXR}o3xxNc&VAb*+EL53lJt>BoJO`QF@I%` zr#dcH^lszt)Z_M_+j^BImcf5hzIQ3RWnUQ^c3Y14bDM_sI?q_l`z*f$)0gkGwap9I zC!am)te(2_#%!Dl&Fw$h%m3HzS!v^!Q*rJd@cHbYJj-s@Yl}HiD`W)U37*w}-`DA( zD``^1cV9?*{`{wMDNpzRd4}Pur9_+g9Fswb^|z)G{?EBGZy*;V!L>!1h`1`I_qD%8 z6eqH$SVBB!FFs#?<^0yM+Al?Ls$i;b{)zESgY}eiE!6|KC$g+%L=>-EBJLQmu?NQ< zYn-&EaKy)w3d}JdlrzEN$O7;DS3nL;y9fCmSk8HD*K^P6Vj`yVH8B5Z#nta}_My+x-vHpc$qB literal 0 HcmV?d00001 diff --git a/EdkNt32Pkg/Dxe/PlatformBds/PlatformBds.mbd b/EdkNt32Pkg/Dxe/PlatformBds/PlatformBds.mbd new file mode 100644 index 0000000000..cda7d5b774 --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/PlatformBds.mbd @@ -0,0 +1,54 @@ + + + + + Bds + A6F691AC-31C8-4444-854C-E2C1A6950F92 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-13 17:04 + 2006-03-23 14:14 + + + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + BaseLib + UefiLib + UefiMemoryLib + UefiDriverEntryPoint + DxeServicesTableLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + EdkGenericBdsLib + BasePrintLib + EdkGraphicsLib + EdkIfrSupportLib + HiiLib + DxeHobLib + DxeMemoryAllocationLib + UefiDevicePathLib + BasePerformanceLibNull + + + _ModuleEntryPoint + + + diff --git a/EdkNt32Pkg/Dxe/PlatformBds/PlatformBds.msa b/EdkNt32Pkg/Dxe/PlatformBds/PlatformBds.msa new file mode 100644 index 0000000000..c46396e95e --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/PlatformBds.msa @@ -0,0 +1,151 @@ + + + + + Bds + DXE_DRIVER + BS_DRIVER + A6F691AC-31C8-4444-854C-E2C1A6950F92 + 0 + Component description file for DxeIpl module + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-13 17:04 + 2006-03-23 14:14 + + + DebugLib + UefiLib + UefiDriverEntryPoint + PcdLib + BaseLib + EdkGraphicsLib + DxeServicesTableLib + PerformanceLib + PrintLib + EdkIfrSupportLib + ReportStatusCodeLib + HobLib + EdkGenericBdsLib + MemoryAllocationLib + BaseMemoryLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + DevicePathLib + HiiLib + + + PlatformData.c + BdsPlatform.c + Generic\BdsEntry.c + Generic\FrontPage.c + Generic\FrontPageStrings.uni + Generic\FrontPageVfr.vfr + Generic\Language.c + Generic\String.c + Generic\Strings.uni + Generic\Capsules.c + Generic\MemoryTest.c + Generic\BootMaint\BmString.uni + Generic\BootMaint\bm.vfr + Generic\BootMaint\BmLib.c + Generic\BootMaint\BootOption.c + Generic\BootMaint\ConsoleOption.c + Generic\BootMaint\Data.c + Generic\BootMaint\Variable.c + Generic\BootMaint\UpdatePage.c + Generic\BootMaint\BBSsupport.c + Generic\BootMaint\BootMaint.c + Generic\BootMaint\FileExplorer.c + Generic\BootMaint\FE.vfr + Generic\BootMngr\BootManager.c + Generic\BootMngr\BootManagerStrings.uni + Generic\BootMngr\BootManagerVfr.Vfr + Generic\DeviceMngr\DeviceManager.c + Generic\DeviceMngr\DeviceManagerStrings.uni + Generic\DeviceMngr\DeviceManagerVfr.Vfr + Generic\Bds.dxs + + + MdePkg + EdkModulePkg + EdkNt32Pkg + + + Bds + LegacyBios + UgaSplash + Hii + FormCallback + DataHub + FormBrowser + ConsoleControl + CpuIo + UgaDraw + LoadFile + SimpleFileSystem + DevicePath + BlockIo + SerialIo + GenericMemTest + Cpu + DriverBinding + + + + FlashMapEntryData + gEfiFlashMapHobGuid + 0xb091e7d2, 0x5a0, 0x4198, 0x94, 0xf0, 0x74, 0xb7, 0xb8, 0xc5, 0x54, 0x59 + + + + + BiosVendor + SystemManufacturer + ProcessorVersion + ProcessorFrequency + MemoryArray + SerialIoDevice + SerialIoPort + + + + BootState + + + GlobalVariable + + + FlashMapHob + + + FileSystemVolumeLabelInfoId + + + FileInfo + + + + + BdsInitialize + + + diff --git a/EdkNt32Pkg/Dxe/PlatformBds/PlatformData.c b/EdkNt32Pkg/Dxe/PlatformBds/PlatformData.c new file mode 100644 index 0000000000..e9885b7957 --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/PlatformData.c @@ -0,0 +1,182 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PlatformData.c + +Abstract: + + Defined the platform specific device path which will be used by + platform Bbd to perform the platform policy connect. + +--*/ + +#include "Generic/Bds.h" +#include "BdsPlatform.h" + +// +// Predefined platform default time out value +// +UINT16 gPlatformBootTimeOutDefault = 10; + +// +// Platform specific keyboard device path +// +NT_PLATFORM_UGA_DEVICE_PATH gUgaDevicePath0 = { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + (UINT8) (sizeof (VENDOR_DEVICE_PATH)), + (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8), + EFI_WIN_NT_THUNK_PROTOCOL_GUID + }, + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + (UINT8) (sizeof (WIN_NT_VENDOR_DEVICE_PATH_NODE)), + (UINT8) ((sizeof (WIN_NT_VENDOR_DEVICE_PATH_NODE)) >> 8), + EFI_WIN_NT_UGA_GUID, + 0 + }, + gEndEntire +}; + +NT_PLATFORM_UGA_DEVICE_PATH gUgaDevicePath1 = { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + (UINT8) (sizeof (VENDOR_DEVICE_PATH)), + (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8), + EFI_WIN_NT_THUNK_PROTOCOL_GUID + }, + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + (UINT8) (sizeof (WIN_NT_VENDOR_DEVICE_PATH_NODE)), + (UINT8) ((sizeof (WIN_NT_VENDOR_DEVICE_PATH_NODE)) >> 8), + EFI_WIN_NT_UGA_GUID, + 1 + }, + gEndEntire +}; + +// +// Platform specific serial device path +// +NT_ISA_SERIAL_DEVICE_PATH gNtSerialDevicePath0 = { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + (UINT8) (sizeof (VENDOR_DEVICE_PATH)), + (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8), + EFI_WIN_NT_THUNK_PROTOCOL_GUID + }, + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + (UINT8) (sizeof (WIN_NT_VENDOR_DEVICE_PATH_NODE)), + (UINT8) ((sizeof (WIN_NT_VENDOR_DEVICE_PATH_NODE)) >> 8), + EFI_WIN_NT_SERIAL_PORT_GUID + }, + { + MESSAGING_DEVICE_PATH, + MSG_UART_DP, + (UINT8) (sizeof (UART_DEVICE_PATH)), + (UINT8) ((sizeof (UART_DEVICE_PATH)) >> 8), + 0, + 115200, + 8, + 1, + 1 + }, + { + MESSAGING_DEVICE_PATH, + MSG_VENDOR_DP, + (UINT8) (sizeof (VENDOR_DEVICE_PATH)), + (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8), + DEVICE_PATH_MESSAGING_PC_ANSI + }, + gEndEntire +}; + +NT_ISA_SERIAL_DEVICE_PATH gNtSerialDevicePath1 = { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + (UINT8) (sizeof (VENDOR_DEVICE_PATH)), + (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8), + EFI_WIN_NT_THUNK_PROTOCOL_GUID + }, + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + (UINT8) (sizeof (WIN_NT_VENDOR_DEVICE_PATH_NODE)), + (UINT8) ((sizeof (WIN_NT_VENDOR_DEVICE_PATH_NODE)) >> 8), + EFI_WIN_NT_SERIAL_PORT_GUID, + 1 + }, + { + MESSAGING_DEVICE_PATH, + MSG_UART_DP, + (UINT8) (sizeof (UART_DEVICE_PATH)), + (UINT8) ((sizeof (UART_DEVICE_PATH)) >> 8), + 0, + 115200, + 8, + 1, + 1 + }, + { + MESSAGING_DEVICE_PATH, + MSG_VENDOR_DP, + (UINT8) (sizeof (VENDOR_DEVICE_PATH)), + (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8), + DEVICE_PATH_MESSAGING_PC_ANSI + }, + gEndEntire +}; + +// +// Predefined platform default console device path +// +BDS_CONSOLE_CONNECT_ENTRY gPlatformConsole[] = { + { + (EFI_DEVICE_PATH_PROTOCOL *) &gNtSerialDevicePath0, + (CONSOLE_OUT | CONSOLE_IN) + }, + { + (EFI_DEVICE_PATH_PROTOCOL *) &gNtSerialDevicePath1, + (CONSOLE_OUT | CONSOLE_IN) + }, + { + (EFI_DEVICE_PATH_PROTOCOL *) &gUgaDevicePath0, + (CONSOLE_OUT | CONSOLE_IN) + }, + { + (EFI_DEVICE_PATH_PROTOCOL *) &gUgaDevicePath1, + (CONSOLE_OUT | CONSOLE_IN) + }, + { + NULL, + 0 + } +}; + +// +// Predefined platform specific driver option +// +EFI_DEVICE_PATH_PROTOCOL *gPlatformDriverOption[] = { NULL }; + +// +// Predefined platform connect sequence +// +EFI_DEVICE_PATH_PROTOCOL *gPlatformConnectSequence[] = { NULL }; diff --git a/EdkNt32Pkg/Dxe/PlatformBds/build.xml b/EdkNt32Pkg/Dxe/PlatformBds/build.xml new file mode 100644 index 0000000000..d30fd98a89 --- /dev/null +++ b/EdkNt32Pkg/Dxe/PlatformBds/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/BlockIo/ComponentName.c b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/BlockIo/ComponentName.c new file mode 100644 index 0000000000..a24f6da602 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/BlockIo/ComponentName.c @@ -0,0 +1,187 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ComponentName.c + +Abstract: + +--*/ + +#include "WinNtBlockIo.h" + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +WinNtBlockIoComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +EFI_STATUS +EFIAPI +WinNtBlockIoComponentNameGetControllerName ( + 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 +// +EFI_COMPONENT_NAME_PROTOCOL gWinNtBlockIoComponentName = { + WinNtBlockIoComponentNameGetDriverName, + WinNtBlockIoComponentNameGetControllerName, + "eng" +}; + +static EFI_UNICODE_STRING_TABLE mWinNtBlockIoDriverNameTable[] = { + { "eng", L"Windows Block I/O Driver" }, + { NULL , NULL } +}; + +EFI_STATUS +EFIAPI +WinNtBlockIoComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gWinNtBlockIoComponentName.SupportedLanguages, + mWinNtBlockIoDriverNameTable, + DriverName + ); +} + +EFI_STATUS +EFIAPI +WinNtBlockIoComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + 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. + 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. + + Returns: + 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. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + EFI_STATUS Status; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + WIN_NT_BLOCK_IO_PRIVATE *Private; + + // + // This is a device driver, so ChildHandle must be NULL. + // + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + + // + // Get our context back + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiBlockIoProtocolGuid, + &BlockIo, + gWinNtBlockIoDriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Private = WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (BlockIo); + + return LookupUnicodeString ( + Language, + gWinNtBlockIoComponentName.SupportedLanguages, + Private->ControllerNameTable, + ControllerName + ); +} diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/BlockIo/DriverConfiguration.c b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/BlockIo/DriverConfiguration.c new file mode 100644 index 0000000000..672ea5ffd0 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/BlockIo/DriverConfiguration.c @@ -0,0 +1,338 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DriverConfiguration.c + +Abstract: + +--*/ + +#include "WinNtBlockIo.h" + +// +// EFI Driver Configuration Functions +// +EFI_STATUS +EFIAPI +WinNtBlockIoDriverConfigurationSetOptions ( + IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED *ActionRequired + ); + +EFI_STATUS +EFIAPI +WinNtBlockIoDriverConfigurationOptionsValid ( + IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL + ); + +EFI_STATUS +EFIAPI +WinNtBlockIoDriverConfigurationForceDefaults ( + IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN UINT32 DefaultType, + OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED *ActionRequired + ); + +// +// EFI Driver Configuration Protocol +// +EFI_DRIVER_CONFIGURATION_PROTOCOL gWinNtBlockIoDriverConfiguration = { + WinNtBlockIoDriverConfigurationSetOptions, + WinNtBlockIoDriverConfigurationOptionsValid, + WinNtBlockIoDriverConfigurationForceDefaults, + LANGUAGESUPPORTED +}; + +EFI_STATUS +EFIAPI +WinNtBlockIoDriverConfigurationSetOptions ( + IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED *ActionRequired + ) +/*++ + + Routine Description: + Allows the user to set controller specific options for a controller that a + driver is currently managing. + + Arguments: + This - A pointer to the EFI_DRIVER_CONFIGURATION_ PROTOCOL instance. + ControllerHandle - The handle of the controller to set options on. + ChildHandle - The handle of the child controller to set options on. This + is an optional parameter that may be NULL. It will be NULL + for device drivers, and for a bus drivers that wish to set + options for the bus controller. It will not be NULL for a + bus driver that wishes to set options for one of its child + controllers. + Language - A pointer to a three character ISO 639-2 language identifier. + This is the language of the user interface that should be + presented to the user, and it must match one of the languages + specified in SupportedLanguages. The number of languages + supported by a driver is up to the driver writer. + ActionRequired - A pointer to the action that the calling agent is required + to perform when this function returns. See "Related + Definitions" for a list of the actions that the calling + agent is required to perform prior to accessing + ControllerHandle again. + + Returns: + EFI_SUCCESS - The driver specified by This successfully set the + configuration options for the controller specified + by ControllerHandle.. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ActionRequired is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support setting + configuration options for the controller specified by + ControllerHandle and ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + EFI_DEVICE_ERROR - A device error occurred while attempt to set the + configuration options for the controller specified + by ControllerHandle and ChildHandle. + EFI_OUT_RESOURCES - There are not enough resources available to set the + configuration options for the controller specified + by ControllerHandle and ChildHandle. + +--*/ +{ + EFI_STATUS Status; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + CHAR8 *SupportedLanguage; + + SupportedLanguage = This->SupportedLanguages; + + Status = EFI_UNSUPPORTED; + while (*SupportedLanguage != 0) { + if (AsciiStrnCmp (Language, SupportedLanguage, 3) == 0) { + Status = EFI_SUCCESS; + } + + SupportedLanguage += 3; + } + + if (EFI_ERROR (Status)) { + return Status; + } + + if (ActionRequired == NULL || ControllerHandle == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + + // + // Validate controller handle + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiWinNtIoProtocolGuid, + &BlockIo, + gWinNtBlockIoDriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (!EFI_ERROR (Status)) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiWinNtIoProtocolGuid, + gWinNtBlockIoDriverBinding.DriverBindingHandle, + ControllerHandle + ); + + return EFI_UNSUPPORTED; + } + + if (Status == EFI_UNSUPPORTED) { + return Status; + } else if (Status != EFI_ALREADY_STARTED) { + return EFI_INVALID_PARAMETER; + } + + *ActionRequired = EfiDriverConfigurationActionNone; + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +WinNtBlockIoDriverConfigurationOptionsValid ( + IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL + ) +/*++ + + Routine Description: + Tests to see if a controller's current configuration options are valid. + + Arguments: + This - A pointer to the EFI_DRIVER_CONFIGURATION_PROTOCOL instance. + ControllerHandle - The handle of the controller to test if it's current + configuration options are valid. + ChildHandle - The handle of the child controller to test if it's current + configuration options are valid. This is an optional + parameter that may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers that wish + to test the configuration options for the bus controller. + It will not be NULL for a bus driver that wishes to test + configuration options for one of its child controllers. + + Returns: + EFI_SUCCESS - The controller specified by ControllerHandle and + ChildHandle that is being managed by the driver + specified by This has a valid set of configuration + options. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE. + EFI_UNSUPPORTED - The driver specified by This is not currently + managing the controller specified by ControllerHandle + and ChildHandle. + EFI_DEVICE_ERROR - The controller specified by ControllerHandle and + ChildHandle that is being managed by the driver + specified by This has an invalid set of configuration + options. + +--*/ +{ + EFI_STATUS Status; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + + if (ControllerHandle == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Validate controller handle + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiWinNtIoProtocolGuid, + &BlockIo, + gWinNtBlockIoDriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (!EFI_ERROR (Status)) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiWinNtIoProtocolGuid, + gWinNtBlockIoDriverBinding.DriverBindingHandle, + ControllerHandle + ); + + return EFI_UNSUPPORTED; + } + + if (Status == EFI_UNSUPPORTED) { + return Status; + } else if (Status != EFI_ALREADY_STARTED) { + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +WinNtBlockIoDriverConfigurationForceDefaults ( + IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN UINT32 DefaultType, + OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED *ActionRequired + ) +/*++ + + Routine Description: + Forces a driver to set the default configuration options for a controller. + + Arguments: + This - A pointer to the EFI_DRIVER_CONFIGURATION_ PROTOCOL instance. + ControllerHandle - The handle of the controller to force default configuration options on. + ChildHandle - The handle of the child controller to force default configuration options on This is an optional parameter that may be NULL. It will be NULL for device drivers. It will also be NULL for a bus drivers that wish to force default configuration options for the bus controller. It will not be NULL for a bus driver that wishes to force default configuration options for one of its child controllers. + DefaultType - The type of default configuration options to force on the controller specified by ControllerHandle and ChildHandle. See Table 9-1 for legal values. A DefaultType of 0x00000000 must be supported by this protocol. + ActionRequired - A pointer to the action that the calling agent is required to perform when this function returns. See "Related Definitions" in Section 9.1for a list of the actions that the calling agent is required to perform prior to accessing ControllerHandle again. + + Returns: + EFI_SUCCESS - The driver specified by This successfully forced the default configuration options on the controller specified by ControllerHandle and ChildHandle. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ActionRequired is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support forcing the default configuration options on the controller specified by ControllerHandle and ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the configuration type specified by DefaultType. + EFI_DEVICE_ERROR - A device error occurred while attempt to force the default configuration options on the controller specified by ControllerHandle and ChildHandle. + EFI_OUT_RESOURCES - There are not enough resources available to force the default configuration options on the controller specified by ControllerHandle and ChildHandle. + +--*/ +{ + EFI_STATUS Status; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + + if (ActionRequired == NULL || ControllerHandle == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Validate controller handle + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiWinNtIoProtocolGuid, + &BlockIo, + gWinNtBlockIoDriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (!EFI_ERROR (Status)) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiWinNtIoProtocolGuid, + gWinNtBlockIoDriverBinding.DriverBindingHandle, + ControllerHandle + ); + + return EFI_UNSUPPORTED; + } + + if (Status == EFI_UNSUPPORTED) { + return Status; + } else if (Status != EFI_ALREADY_STARTED) { + return EFI_INVALID_PARAMETER; + } + + *ActionRequired = EfiDriverConfigurationActionNone; + return EFI_SUCCESS; +} diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/BlockIo/DriverDiagnostics.c b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/BlockIo/DriverDiagnostics.c new file mode 100644 index 0000000000..dd815789c6 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/BlockIo/DriverDiagnostics.c @@ -0,0 +1,186 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DriverDiagnostics.c + +Abstract: + +--*/ + +#include "WinNtBlockIo.h" + +// +// EFI Driver Diagnostics Functions +// +EFI_STATUS +EFIAPI +WinNtBlockIoDriverDiagnosticsRunDiagnostics ( + IN EFI_DRIVER_DIAGNOSTICS_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN EFI_DRIVER_DIAGNOSTIC_TYPE DiagnosticType, + IN CHAR8 *Language, + OUT EFI_GUID **ErrorType, + OUT UINTN *BufferSize, + OUT CHAR16 **Buffer + ); + +// +// EFI Driver Diagnostics Protocol +// +EFI_DRIVER_DIAGNOSTICS_PROTOCOL gWinNtBlockIoDriverDiagnostics = { + WinNtBlockIoDriverDiagnosticsRunDiagnostics, + LANGUAGESUPPORTED +}; + +EFI_STATUS +EFIAPI +WinNtBlockIoDriverDiagnosticsRunDiagnostics ( + IN EFI_DRIVER_DIAGNOSTICS_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN EFI_DRIVER_DIAGNOSTIC_TYPE DiagnosticType, + IN CHAR8 *Language, + OUT EFI_GUID **ErrorType, + OUT UINTN *BufferSize, + OUT CHAR16 **Buffer + ) +/*++ + + Routine Description: + Runs diagnostics on a controller. + + Arguments: + This - A pointer to the EFI_DRIVER_DIAGNOSTICS_PROTOCOL instance. + ControllerHandle - The handle of the controller to run diagnostics on. + ChildHandle - The handle of the child controller to run diagnostics on + This is an optional parameter that may be NULL. It will + be NULL for device drivers. It will also be NULL for a + bus drivers that wish to run diagnostics on the bus + controller. It will not be NULL for a bus driver that + wishes to run diagnostics on one of its child controllers. + DiagnosticType - Indicates type of diagnostics to perform on the controller + specified by ControllerHandle and ChildHandle. See + "Related Definitions" for the list of supported types. + Language - A pointer to a three character ISO 639-2 language + identifier. This is the language in which the optional + error message should be returned in Buffer, and it must + match one of the languages specified in SupportedLanguages. + The number of languages supported by a driver is up to + the driver writer. + ErrorType - A GUID that defines the format of the data returned in + Buffer. + BufferSize - The size, in bytes, of the data returned in Buffer. + Buffer - A buffer that contains a Null-terminated Unicode string + plus some additional data whose format is defined by + ErrorType. Buffer is allocated by this function with + AllocatePool(), and it is the caller's responsibility + to free it with a call to FreePool(). + + Returns: + EFI_SUCCESS - The controller specified by ControllerHandle and + ChildHandle passed the diagnostic. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ErrorType is NULL. + EFI_INVALID_PARAMETER - BufferType is NULL. + EFI_INVALID_PARAMETER - Buffer is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support + running diagnostics for the controller specified + by ControllerHandle and ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + type of diagnostic specified by DiagnosticType. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + EFI_OUT_OF_RESOURCES - There are not enough resources available to complete + the diagnostics. + EFI_OUT_OF_RESOURCES - There are not enough resources available to return + the status information in ErrorType, BufferSize, + and Buffer. + EFI_DEVICE_ERROR - The controller specified by ControllerHandle and + ChildHandle did not pass the diagnostic. + +--*/ +{ + EFI_STATUS Status; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + CHAR8 *SupportedLanguage; + + if (Language == NULL || + ErrorType == NULL || + Buffer == NULL || + ControllerHandle == NULL || + BufferSize == NULL) { + + return EFI_INVALID_PARAMETER; + } + + SupportedLanguage = This->SupportedLanguages; + + Status = EFI_UNSUPPORTED; + while (*SupportedLanguage != 0) { + if (AsciiStrnCmp (Language, SupportedLanguage, 3) == 0) { + Status = EFI_SUCCESS; + break; + } + + SupportedLanguage += 3; + } + + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + *ErrorType = NULL; + *BufferSize = 0; + if (DiagnosticType != EfiDriverDiagnosticTypeStandard) { + *ErrorType = &gEfiBlockIoProtocolGuid; + *BufferSize = 0x60; + gBS->AllocatePool (EfiBootServicesData, (UINTN) (*BufferSize), Buffer); + CopyMem (*Buffer, L"Windows Block I/O Driver Diagnostics Failed\n", *BufferSize); + return EFI_DEVICE_ERROR; + } + + // + // Validate controller handle + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiWinNtIoProtocolGuid, + &BlockIo, + gWinNtBlockIoDriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (!EFI_ERROR (Status)) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiWinNtIoProtocolGuid, + gWinNtBlockIoDriverBinding.DriverBindingHandle, + ControllerHandle + ); + + return EFI_UNSUPPORTED; + } + + if (Status == EFI_UNSUPPORTED) { + return Status; + } else if (Status != EFI_ALREADY_STARTED) { + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/BlockIo/WinNtBlockIo.c b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/BlockIo/WinNtBlockIo.c new file mode 100644 index 0000000000..2f65092747 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/BlockIo/WinNtBlockIo.c @@ -0,0 +1,1085 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + WinNtBlockIo.c + +Abstract: + + Produce block IO abstractions for real devices on your PC using Win32 APIs. + The configuration of what devices to mount or emulate comes from NT + environment variables. The variables must be visible to the Microsoft* + Developer Studio for them to work. + + ixed - Fixed disk like a hard drive. + emovable - Removable media like a floppy or CD-ROM. + Read nly - Write protected device. + Read rite - Read write device. + - Decimal number of blocks a device supports. + - Decimal number of bytes per block. + + NT envirnonment variable contents. '<' and '>' are not part of the variable, + they are just used to make this help more readable. There should be no + spaces between the ';'. Extra spaces will break the variable. A '!' is + used to seperate multiple devices in a variable. + + EFI_WIN_NT_VIRTUAL_DISKS = + ;;[!...] + + EFI_WIN_NT_PHYSICAL_DISKS = + :;;[!...] + + Virtual Disks: These devices use a file to emulate a hard disk or removable + media device. + + Thus a 20 MB emulated hard drive would look like: + EFI_WIN_NT_VIRTUAL_DISKS=FW;40960;512 + + A 1.44MB emulated floppy with a block size of 1024 would look like: + EFI_WIN_NT_VIRTUAL_DISKS=RW;1440;1024 + + Physical Disks: These devices use NT to open a real device in your system + + Thus a 120 MB floppy would look like: + EFI_WIN_NT_PHYSICAL_DISKS=B:RW;245760;512 + + Thus a standard CD-ROM floppy would look like: + EFI_WIN_NT_PHYSICAL_DISKS=Z:RO;307200;2048 + + + * Other names and brands may be claimed as the property of others. + +--*/ + +#include "WinNtBlockIo.h" + +EFI_DRIVER_BINDING_PROTOCOL gWinNtBlockIoDriverBinding = { + WinNtBlockIoDriverBindingSupported, + WinNtBlockIoDriverBindingStart, + WinNtBlockIoDriverBindingStop, + 0x10, + NULL, + NULL +}; + + +EFI_STATUS +EFIAPI +WinNtBlockIoDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Handle - add argument and description to function comment +// TODO: RemainingDevicePath - add argument and description to function comment +{ + EFI_STATUS Status; + EFI_WIN_NT_IO_PROTOCOL *WinNtIo; + + // + // Open the IO Abstraction(s) needed to perform the supported test + // + Status = gBS->OpenProtocol ( + Handle, + &gEfiWinNtIoProtocolGuid, + &WinNtIo, + This->DriverBindingHandle, + Handle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Make sure the WinNtThunkProtocol is valid + // + Status = EFI_UNSUPPORTED; + if (WinNtIo->WinNtThunk->Signature == EFI_WIN_NT_THUNK_PROTOCOL_SIGNATURE) { + + // + // Check the GUID to see if this is a handle type the driver supports + // + if (CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtVirtualDisksGuid) || + CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtPhysicalDisksGuid) ) { + Status = EFI_SUCCESS; + } + } + + // + // Close the I/O Abstraction(s) used to perform the supported test + // + gBS->CloseProtocol ( + Handle, + &gEfiWinNtIoProtocolGuid, + This->DriverBindingHandle, + Handle + ); + + return Status; +} + +EFI_STATUS +EFIAPI +WinNtBlockIoDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Handle - add argument and description to function comment +// TODO: RemainingDevicePath - add argument and description to function comment +{ + EFI_STATUS Status; + EFI_WIN_NT_IO_PROTOCOL *WinNtIo; + WIN_NT_RAW_DISK_DEVICE_TYPE DiskType; + UINT16 Buffer[FILENAME_BUFFER_SIZE]; + CHAR16 *Str; + BOOLEAN RemovableMedia; + BOOLEAN WriteProtected; + UINTN NumberOfBlocks; + UINTN BlockSize; + + // + // Grab the protocols we need + // + Status = gBS->OpenProtocol ( + Handle, + &gEfiWinNtIoProtocolGuid, + &WinNtIo, + This->DriverBindingHandle, + Handle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Set DiskType + // + if (CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtVirtualDisksGuid)) { + DiskType = EfiWinNtVirtualDisks; + } else if (CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtPhysicalDisksGuid)) { + DiskType = EfiWinNtPhysicalDisks; + } else { + Status = EFI_UNSUPPORTED; + goto Done; + } + + Status = EFI_NOT_FOUND; + Str = WinNtIo->EnvString; + if (DiskType == EfiWinNtVirtualDisks) { + WinNtIo->WinNtThunk->SPrintf ( + Buffer, + L"Diskfile%d", + WinNtIo->InstanceNumber + ); + } else { + if (*Str >= 'A' && *Str <= 'Z' || *Str >= 'a' && *Str <= 'z') { + WinNtIo->WinNtThunk->SPrintf (Buffer, L"\\\\.\\%c:", *Str); + } else { + WinNtIo->WinNtThunk->SPrintf (Buffer, L"\\\\.\\PHYSICALDRIVE%c", *Str); + } + + Str++; + if (*Str != ':') { + Status = EFI_NOT_FOUND; + goto Done; + } + + Str++; + } + + if (*Str == 'R' || *Str == 'F') { + RemovableMedia = (BOOLEAN) (*Str == 'R'); + Str++; + if (*Str == 'O' || *Str == 'W') { + WriteProtected = (BOOLEAN) (*Str == 'O'); + Str = GetNextElementPastTerminator (Str, ';'); + + NumberOfBlocks = Atoi (Str); + if (NumberOfBlocks != 0) { + Str = GetNextElementPastTerminator (Str, ';'); + BlockSize = Atoi (Str); + if (BlockSize != 0) { + // + // If we get here the variable is valid so do the work. + // + Status = WinNtBlockIoCreateMapping ( + WinNtIo, + Handle, + Buffer, + WriteProtected, + RemovableMedia, + NumberOfBlocks, + BlockSize, + DiskType + ); + + } + } + } + } + +Done: + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + Handle, + &gEfiWinNtIoProtocolGuid, + This->DriverBindingHandle, + Handle + ); + } + + return Status; +} + +EFI_STATUS +EFIAPI +WinNtBlockIoDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Handle - TODO: add argument description + NumberOfChildren - TODO: add argument description + ChildHandleBuffer - TODO: add argument description + +Returns: + + EFI_UNSUPPORTED - TODO: Add description for return value + +--*/ +{ + EFI_BLOCK_IO_PROTOCOL *BlockIo; + EFI_STATUS Status; + WIN_NT_BLOCK_IO_PRIVATE *Private; + + // + // Get our context back + // + Status = gBS->OpenProtocol ( + Handle, + &gEfiBlockIoProtocolGuid, + &BlockIo, + This->DriverBindingHandle, + Handle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Private = WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (BlockIo); + + // + // BugBug: If we need to kick people off, we need to make Uninstall Close the handles. + // We could pass in our image handle or FLAG our open to be closed via + // Unistall (== to saying any CloseProtocol will close our open) + // + Status = gBS->UninstallMultipleProtocolInterfaces ( + Private->EfiHandle, + &gEfiBlockIoProtocolGuid, + &Private->BlockIo, + NULL + ); + if (!EFI_ERROR (Status)) { + + Status = gBS->CloseProtocol ( + Handle, + &gEfiWinNtIoProtocolGuid, + This->DriverBindingHandle, + Handle + ); + + // + // Shut down our device + // + Private->WinNtThunk->CloseHandle (Private->NtHandle); + + // + // Free our instance data + // + FreeUnicodeStringTable (Private->ControllerNameTable); + + gBS->FreePool (Private); + } + + return Status; +} + +STATIC +CHAR16 * +GetNextElementPastTerminator ( + IN CHAR16 *EnvironmentVariable, + IN CHAR16 Terminator + ) +/*++ + +Routine Description: + + Worker function to parse environment variables. + +Arguments: + EnvironmentVariable - Envirnment variable to parse. + + Terminator - Terminator to parse for. + +Returns: + + Pointer to next eliment past the first occurence of Terminator or the '\0' + at the end of the string. + +--*/ +{ + CHAR16 *Ptr; + + for (Ptr = EnvironmentVariable; *Ptr != '\0'; Ptr++) { + if (*Ptr == Terminator) { + Ptr++; + break; + } + } + + return Ptr; +} + +STATIC +EFI_STATUS +WinNtBlockIoCreateMapping ( + IN EFI_WIN_NT_IO_PROTOCOL *WinNtIo, + IN EFI_HANDLE EfiDeviceHandle, + IN CHAR16 *Filename, + IN BOOLEAN ReadOnly, + IN BOOLEAN RemovableMedia, + IN UINTN NumberOfBlocks, + IN UINTN BlockSize, + IN WIN_NT_RAW_DISK_DEVICE_TYPE DeviceType + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + WinNtIo - TODO: add argument description + EfiDeviceHandle - TODO: add argument description + Filename - TODO: add argument description + ReadOnly - TODO: add argument description + RemovableMedia - TODO: add argument description + NumberOfBlocks - TODO: add argument description + BlockSize - TODO: add argument description + DeviceType - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + EFI_STATUS Status; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + WIN_NT_BLOCK_IO_PRIVATE *Private; + UINTN Index; + + WinNtIo->WinNtThunk->SetErrorMode (SEM_FAILCRITICALERRORS); + + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (WIN_NT_BLOCK_IO_PRIVATE), + &Private + ); + ASSERT_EFI_ERROR (Status); + + EfiInitializeLock (&Private->Lock, EFI_TPL_NOTIFY); + + Private->WinNtThunk = WinNtIo->WinNtThunk; + + Private->Signature = WIN_NT_BLOCK_IO_PRIVATE_SIGNATURE; + Private->LastBlock = NumberOfBlocks - 1; + Private->BlockSize = BlockSize; + + for (Index = 0; Filename[Index] != 0; Index++) { + Private->Filename[Index] = Filename[Index]; + } + + Private->Filename[Index] = 0; + + Private->ReadMode = GENERIC_READ | (ReadOnly ? 0 : GENERIC_WRITE); + Private->ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; + + Private->NumberOfBlocks = NumberOfBlocks; + Private->DeviceType = DeviceType; + Private->NtHandle = INVALID_HANDLE_VALUE; + + Private->ControllerNameTable = NULL; + + AddUnicodeString ( + "eng", + gWinNtBlockIoComponentName.SupportedLanguages, + &Private->ControllerNameTable, + Private->Filename + ); + + BlockIo = &Private->BlockIo; + BlockIo->Revision = EFI_BLOCK_IO_PROTOCOL_REVISION; + BlockIo->Media = &Private->Media; + BlockIo->Media->BlockSize = Private->BlockSize; + BlockIo->Media->LastBlock = Private->NumberOfBlocks - 1; + BlockIo->Media->MediaId = 0;; + + BlockIo->Reset = WinNtBlockIoResetBlock; + BlockIo->ReadBlocks = WinNtBlockIoReadBlocks; + BlockIo->WriteBlocks = WinNtBlockIoWriteBlocks; + BlockIo->FlushBlocks = WinNtBlockIoFlushBlocks; + + BlockIo->Media->ReadOnly = ReadOnly; + BlockIo->Media->RemovableMedia = RemovableMedia; + BlockIo->Media->LogicalPartition = FALSE; + BlockIo->Media->MediaPresent = TRUE; + BlockIo->Media->WriteCaching = FALSE; + + if (DeviceType == EfiWinNtVirtualDisks) { + BlockIo->Media->IoAlign = 1; + + // + // Create a file to use for a virtual disk even if it does not exist. + // + Private->OpenMode = OPEN_ALWAYS; + } else if (DeviceType == EfiWinNtPhysicalDisks) { + // + // Physical disk and floppy devices require 4 byte alignment. + // + BlockIo->Media->IoAlign = 4; + + // + // You can only open a physical device if it exists. + // + Private->OpenMode = OPEN_EXISTING; + } else { + ASSERT (FALSE); + } + + Private->EfiHandle = EfiDeviceHandle; + Status = WinNtBlockIoOpenDevice (Private); + if (!EFI_ERROR (Status)) { + + Status = gBS->InstallMultipleProtocolInterfaces ( + &Private->EfiHandle, + &gEfiBlockIoProtocolGuid, + &Private->BlockIo, + NULL + ); + if (EFI_ERROR (Status)) { + FreeUnicodeStringTable (Private->ControllerNameTable); + gBS->FreePool (Private); + } + + DEBUG ((EFI_D_INIT, "BlockDevice added: %s\n", Filename)); + } + + return Status; +} + +STATIC +EFI_STATUS +WinNtBlockIoOpenDevice ( + WIN_NT_BLOCK_IO_PRIVATE *Private + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + EFI_STATUS Status; + UINT64 FileSize; + UINT64 EndOfFile; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + + BlockIo = &Private->BlockIo; + EfiAcquireLock (&Private->Lock); + + // + // If the device is already opened, close it + // + if (Private->NtHandle != INVALID_HANDLE_VALUE) { + BlockIo->Reset (BlockIo, FALSE); + } + + // + // Open the device + // + Private->NtHandle = Private->WinNtThunk->CreateFile ( + Private->Filename, + Private->ReadMode, + Private->ShareMode, + NULL, + Private->OpenMode, + 0, + NULL + ); + + Status = Private->WinNtThunk->GetLastError (); + + if (Private->NtHandle == INVALID_HANDLE_VALUE) { + DEBUG ((EFI_D_INFO, "PlOpenBlock: Could not open %s, %x\n", Private->Filename, Private->WinNtThunk->GetLastError ())); + BlockIo->Media->MediaPresent = FALSE; + Status = EFI_NO_MEDIA; + goto Done; + } + + if (!BlockIo->Media->MediaPresent) { + // + // BugBug: try to emulate if a CD appears - notify drivers to check it out + // + BlockIo->Media->MediaPresent = TRUE; + EfiReleaseLock (&Private->Lock); + EfiAcquireLock (&Private->Lock); + } + + // + // get the size of the file + // + Status = SetFilePointer64 (Private, 0, &FileSize, FILE_END); + + if (EFI_ERROR (Status)) { + FileSize = MultU64x32 (Private->NumberOfBlocks, Private->BlockSize); + if (Private->DeviceType == EfiWinNtVirtualDisks) { + DEBUG ((EFI_D_ERROR, "PlOpenBlock: Could not get filesize of %s\n", Private->Filename)); + Status = EFI_UNSUPPORTED; + goto Done; + } + } + + if (Private->NumberOfBlocks == 0) { + Private->NumberOfBlocks = DivU64x32 (FileSize, Private->BlockSize); + } + + EndOfFile = MultU64x32 (Private->NumberOfBlocks, Private->BlockSize); + + if (FileSize != EndOfFile) { + // + // file is not the proper size, change it + // + DEBUG ((EFI_D_INIT, "PlOpenBlock: Initializing block device: %hs\n", Private->Filename)); + + // + // first set it to 0 + // + SetFilePointer64 (Private, 0, NULL, FILE_BEGIN); + Private->WinNtThunk->SetEndOfFile (Private->NtHandle); + + // + // then set it to the needed file size (OS will zero fill it) + // + SetFilePointer64 (Private, EndOfFile, NULL, FILE_BEGIN); + Private->WinNtThunk->SetEndOfFile (Private->NtHandle); + } + + DEBUG ((EFI_D_INIT, "%HPlOpenBlock: opened %s%N\n", Private->Filename)); + Status = EFI_SUCCESS; + +Done: + if (EFI_ERROR (Status)) { + if (Private->NtHandle != INVALID_HANDLE_VALUE) { + BlockIo->Reset (BlockIo, FALSE); + } + } + + EfiReleaseLock (&Private->Lock); + return Status; +} + +STATIC +EFI_STATUS +WinNtBlockIoError ( + IN WIN_NT_BLOCK_IO_PRIVATE *Private + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + EFI_BLOCK_IO_PROTOCOL *BlockIo; + EFI_STATUS Status; + BOOLEAN ReinstallBlockIoFlag; + + BlockIo = &Private->BlockIo; + + switch (Private->WinNtThunk->GetLastError ()) { + + case ERROR_NOT_READY: + Status = EFI_NO_MEDIA; + BlockIo->Media->ReadOnly = FALSE; + BlockIo->Media->MediaPresent = FALSE; + ReinstallBlockIoFlag = FALSE; + break; + + case ERROR_WRONG_DISK: + BlockIo->Media->ReadOnly = FALSE; + BlockIo->Media->MediaPresent = TRUE; + BlockIo->Media->MediaId += 1; + ReinstallBlockIoFlag = TRUE; + Status = EFI_MEDIA_CHANGED; + break; + + case ERROR_WRITE_PROTECT: + BlockIo->Media->ReadOnly = TRUE; + ReinstallBlockIoFlag = FALSE; + Status = EFI_WRITE_PROTECTED; + break; + + default: + ReinstallBlockIoFlag = FALSE; + Status = EFI_DEVICE_ERROR; + break; + } + + if (ReinstallBlockIoFlag) { + BlockIo->Reset (BlockIo, FALSE); + + gBS->ReinstallProtocolInterface ( + Private->EfiHandle, + &gEfiBlockIoProtocolGuid, + BlockIo, + BlockIo + ); + } + + return Status; +} + +STATIC +EFI_STATUS +WinNtBlockIoReadWriteCommon ( + IN WIN_NT_BLOCK_IO_PRIVATE *Private, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + IN VOID *Buffer, + IN CHAR8 *CallerName + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + MediaId - TODO: add argument description + Lba - TODO: add argument description + BufferSize - TODO: add argument description + Buffer - TODO: add argument description + CallerName - TODO: add argument description + +Returns: + + EFI_NO_MEDIA - TODO: Add description for return value + EFI_MEDIA_CHANGED - TODO: Add description for return value + EFI_INVALID_PARAMETER - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + EFI_BAD_BUFFER_SIZE - TODO: Add description for return value + EFI_INVALID_PARAMETER - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + EFI_STATUS Status; + UINTN BlockSize; + UINT64 LastBlock; + INT64 DistanceToMove; + UINT64 DistanceMoved; + + if (Private->NtHandle == INVALID_HANDLE_VALUE) { + Status = WinNtBlockIoOpenDevice (Private); + if (EFI_ERROR (Status)) { + return Status; + } + } + + if (!Private->Media.MediaPresent) { + DEBUG ((EFI_D_INIT, "%s: No Media\n", CallerName)); + return EFI_NO_MEDIA; + } + + if (Private->Media.MediaId != MediaId) { + return EFI_MEDIA_CHANGED; + } + + if ((UINT32) Buffer % Private->Media.IoAlign != 0) { + return EFI_INVALID_PARAMETER; + } + + // + // Verify buffer size + // + BlockSize = Private->BlockSize; + if (BufferSize == 0) { + DEBUG ((EFI_D_INIT, "%s: Zero length read\n", CallerName)); + return EFI_SUCCESS; + } + + if ((BufferSize % BlockSize) != 0) { + DEBUG ((EFI_D_INIT, "%s: Invalid read size\n", CallerName)); + return EFI_BAD_BUFFER_SIZE; + } + + LastBlock = Lba + (BufferSize / BlockSize) - 1; + if (LastBlock > Private->LastBlock) { + DEBUG ((EFI_D_INIT, "ReadBlocks: Attempted to read off end of device\n")); + return EFI_INVALID_PARAMETER; + } + // + // Seek to End of File + // + DistanceToMove = MultU64x32 (Lba, BlockSize); + Status = SetFilePointer64 (Private, DistanceToMove, &DistanceMoved, FILE_BEGIN); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_INIT, "WriteBlocks: SetFilePointer failed\n")); + return WinNtBlockIoError (Private); + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +WinNtBlockIoReadBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +/*++ + + Routine Description: + Read BufferSize bytes from Lba into Buffer. + + Arguments: + This - Protocol instance pointer. + MediaId - Id of the media, changes every time the media is replaced. + Lba - The starting Logical Block Address to read from + BufferSize - Size of Buffer, must be a multiple of device block size. + Buffer - Buffer containing read data + + Returns: + EFI_SUCCESS - The data was read correctly from the device. + EFI_DEVICE_ERROR - The device reported an error while performing the read. + EFI_NO_MEDIA - There is no media in the device. + EFI_MEDIA_CHANGED - The MediaId does not matched the current device. + EFI_BAD_BUFFER_SIZE - The Buffer was not a multiple of the block size of the + device. + EFI_INVALID_PARAMETER - The read request contains device addresses that are not + valid for the device. + +--*/ +{ + WIN_NT_BLOCK_IO_PRIVATE *Private; + BOOL Flag; + EFI_STATUS Status; + DWORD BytesRead; + + Private = WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This); + + Status = WinNtBlockIoReadWriteCommon (Private, MediaId, Lba, BufferSize, Buffer, "WinNtReadBlocks"); + if (EFI_ERROR (Status)) { + return Status; + } + + Flag = Private->WinNtThunk->ReadFile (Private->NtHandle, Buffer, (DWORD) BufferSize, (LPDWORD) &BytesRead, NULL); + if (!Flag || (BytesRead != BufferSize)) { + DEBUG ((EFI_D_INIT, "ReadBlocks: ReadFile failed. (%d)\n", Private->WinNtThunk->GetLastError ())); + return WinNtBlockIoError (Private); + } + + // + // If we wrote then media is present. + // + This->Media->MediaPresent = TRUE; + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +WinNtBlockIoWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + IN VOID *Buffer + ) +/*++ + + Routine Description: + Write BufferSize bytes from Lba into Buffer. + + Arguments: + This - Protocol instance pointer. + MediaId - Id of the media, changes every time the media is replaced. + Lba - The starting Logical Block Address to read from + BufferSize - Size of Buffer, must be a multiple of device block size. + Buffer - Buffer containing read data + + Returns: + EFI_SUCCESS - The data was written correctly to the device. + EFI_WRITE_PROTECTED - The device can not be written to. + EFI_DEVICE_ERROR - The device reported an error while performing the write. + EFI_NO_MEDIA - There is no media in the device. + EFI_MEDIA_CHNAGED - The MediaId does not matched the current device. + EFI_BAD_BUFFER_SIZE - The Buffer was not a multiple of the block size of the + device. + EFI_INVALID_PARAMETER - The write request contains a LBA that is not + valid for the device. + +--*/ +{ + WIN_NT_BLOCK_IO_PRIVATE *Private; + UINTN BytesWritten; + BOOL Flag; + EFI_STATUS Status; + + Private = WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This); + + Status = WinNtBlockIoReadWriteCommon (Private, MediaId, Lba, BufferSize, Buffer, "WinNtWriteBlocks"); + if (EFI_ERROR (Status)) { + return Status; + } + + Flag = Private->WinNtThunk->WriteFile (Private->NtHandle, Buffer, (DWORD) BufferSize, (LPDWORD) &BytesWritten, NULL); + if (!Flag || (BytesWritten != BufferSize)) { + DEBUG ((EFI_D_INIT, "ReadBlocks: WriteFile failed. (%d)\n", Private->WinNtThunk->GetLastError ())); + return WinNtBlockIoError (Private); + } + + // + // If the write succeeded, we are not write protected and media is present. + // + This->Media->MediaPresent = TRUE; + This->Media->ReadOnly = FALSE; + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +WinNtBlockIoFlushBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This + ) +/*++ + + Routine Description: + Flush the Block Device. + + Arguments: + This - Protocol instance pointer. + + Returns: + EFI_SUCCESS - All outstanding data was written to the device + EFI_DEVICE_ERROR - The device reported an error while writting back the data + EFI_NO_MEDIA - There is no media in the device. + +--*/ +{ + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +WinNtBlockIoResetBlock ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + + Routine Description: + Reset the Block Device. + + Arguments: + This - Protocol instance pointer. + ExtendedVerification - Driver may perform diagnostics on reset. + + Returns: + EFI_SUCCESS - The device was reset. + EFI_DEVICE_ERROR - The device is not functioning properly and could + not be reset. + +--*/ +{ + WIN_NT_BLOCK_IO_PRIVATE *Private; + + Private = WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This); + + if (Private->NtHandle != INVALID_HANDLE_VALUE) { + Private->WinNtThunk->CloseHandle (Private->NtHandle); + Private->NtHandle = INVALID_HANDLE_VALUE; + } + + return EFI_SUCCESS; +} + +UINTN +Atoi ( + CHAR16 *String + ) +/*++ + +Routine Description: + + Convert a unicode string to a UINTN + +Arguments: + + String - Unicode string. + +Returns: + + UINTN of the number represented by String. + +--*/ +{ + UINTN Number; + CHAR16 *Str; + + // + // skip preceeding white space + // + Str = String; + while ((*Str) && (*Str == ' ')) { + Str++; + } + // + // Convert ot a Number + // + Number = 0; + while (*Str != '\0') { + if ((*Str >= '0') && (*Str <= '9')) { + Number = (Number * 10) +*Str - '0'; + } else { + break; + } + + Str++; + } + + return Number; +} + +EFI_STATUS +SetFilePointer64 ( + IN WIN_NT_BLOCK_IO_PRIVATE *Private, + IN INT64 DistanceToMove, + OUT UINT64 *NewFilePointer, + IN DWORD MoveMethod + ) +/*++ + +This function extends the capability of SetFilePointer to accept 64 bit parameters + +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: function comment is missing 'Returns:' +// TODO: Private - add argument and description to function comment +// TODO: DistanceToMove - add argument and description to function comment +// TODO: NewFilePointer - add argument and description to function comment +// TODO: MoveMethod - add argument and description to function comment +{ + EFI_STATUS Status; + LARGE_INTEGER LargeInt; + UINT32 ErrorCode; + + LargeInt.QuadPart = DistanceToMove; + Status = EFI_SUCCESS; + + LargeInt.LowPart = Private->WinNtThunk->SetFilePointer ( + Private->NtHandle, + LargeInt.LowPart, + &LargeInt.HighPart, + MoveMethod + ); + + if (LargeInt.LowPart == -1 && + (ErrorCode = Private->WinNtThunk->GetLastError ()) != NO_ERROR) { + Status = EFI_INVALID_PARAMETER; + } + + if (NewFilePointer != NULL) { + *NewFilePointer = LargeInt.QuadPart; + } + + return Status; +} diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/BlockIo/WinNtBlockIo.h b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/BlockIo/WinNtBlockIo.h new file mode 100644 index 0000000000..59d4b54f64 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/BlockIo/WinNtBlockIo.h @@ -0,0 +1,471 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + WinNtBlockIo.h + +Abstract: + + Produce block IO abstractions for real devices on your PC using Win32 APIs. + The configuration of what devices to mount or emulate comes from NT + environment variables. The variables must be visible to the Microsoft* + Developer Studio for them to work. + + * Other names and brands may be claimed as the property of others. + +--*/ + +#ifndef _WIN_NT_BLOCK_IO_H_ +#define _WIN_NT_BLOCK_IO_H_ + + + +#define FILENAME_BUFFER_SIZE 80 + +// +// Language supported for driverconfiguration protocol +// +#define LANGUAGESUPPORTED "eng" + +typedef enum { + EfiWinNtVirtualDisks, + EfiWinNtPhysicalDisks, + EifWinNtMaxTypeDisks +} WIN_NT_RAW_DISK_DEVICE_TYPE; + +#define WIN_NT_BLOCK_IO_PRIVATE_SIGNATURE EFI_SIGNATURE_32 ('N', 'T', 'b', 'k') +typedef struct { + UINTN Signature; + + EFI_LOCK Lock; + + CHAR16 Filename[FILENAME_BUFFER_SIZE]; + UINTN ReadMode; + UINTN ShareMode; + UINTN OpenMode; + + HANDLE NtHandle; + WIN_NT_RAW_DISK_DEVICE_TYPE DeviceType; + + UINT64 LastBlock; + UINTN BlockSize; + UINT64 NumberOfBlocks; + + EFI_HANDLE EfiHandle; + EFI_BLOCK_IO_PROTOCOL BlockIo; + EFI_BLOCK_IO_MEDIA Media; + + EFI_UNICODE_STRING_TABLE *ControllerNameTable; + + EFI_WIN_NT_THUNK_PROTOCOL *WinNtThunk; + +} WIN_NT_BLOCK_IO_PRIVATE; + +#define WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS(a) \ + CR(a, WIN_NT_BLOCK_IO_PRIVATE, BlockIo, WIN_NT_BLOCK_IO_PRIVATE_SIGNATURE) + +#define LIST_BUFFER_SIZE 512 + +// +// Block I/O Global Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gWinNtBlockIoDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gWinNtBlockIoComponentName; +extern EFI_DRIVER_CONFIGURATION_PROTOCOL gWinNtBlockIoDriverConfiguration; +extern EFI_DRIVER_DIAGNOSTICS_PROTOCOL gWinNtBlockIoDriverDiagnostics; + +// +// EFI Driver Binding Functions +// +EFI_STATUS +EFIAPI +WinNtBlockIoDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Handle - TODO: add argument description + RemainingDevicePath - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +WinNtBlockIoDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Handle - TODO: add argument description + RemainingDevicePath - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +WinNtBlockIoDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Handle - TODO: add argument description + NumberOfChildren - TODO: add argument description + ChildHandleBuffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +// +// Block IO protocol member functions +// +STATIC +EFI_STATUS +EFIAPI +WinNtBlockIoReadBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + MediaId - TODO: add argument description + Lba - TODO: add argument description + BufferSize - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +STATIC +EFI_STATUS +EFIAPI +WinNtBlockIoWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + MediaId - TODO: add argument description + Lba - TODO: add argument description + BufferSize - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +STATIC +EFI_STATUS +EFIAPI +WinNtBlockIoFlushBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +STATIC +EFI_STATUS +EFIAPI +WinNtBlockIoResetBlock ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + ExtendedVerification - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +// +// Private Worker functions +// +STATIC +EFI_STATUS +WinNtBlockIoCreateMapping ( + IN EFI_WIN_NT_IO_PROTOCOL *WinNtIo, + IN EFI_HANDLE EfiDeviceHandle, + IN CHAR16 *Filename, + IN BOOLEAN ReadOnly, + IN BOOLEAN RemovableMedia, + IN UINTN NumberOfBlocks, + IN UINTN BlockSize, + IN WIN_NT_RAW_DISK_DEVICE_TYPE DeviceType + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + WinNtIo - TODO: add argument description + EfiDeviceHandle - TODO: add argument description + Filename - TODO: add argument description + ReadOnly - TODO: add argument description + RemovableMedia - TODO: add argument description + NumberOfBlocks - TODO: add argument description + BlockSize - TODO: add argument description + DeviceType - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +STATIC +EFI_STATUS +WinNtBlockIoReadWriteCommon ( + IN WIN_NT_BLOCK_IO_PRIVATE *Private, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + IN VOID *Buffer, + IN CHAR8 *CallerName + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + MediaId - TODO: add argument description + Lba - TODO: add argument description + BufferSize - TODO: add argument description + Buffer - TODO: add argument description + CallerName - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +STATIC +EFI_STATUS +WinNtBlockIoError ( + IN WIN_NT_BLOCK_IO_PRIVATE *Private + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +STATIC +EFI_STATUS +WinNtBlockIoOpenDevice ( + WIN_NT_BLOCK_IO_PRIVATE *Private + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +STATIC +CHAR16 * +GetNextElementPastTerminator ( + IN CHAR16 *EnvironmentVariable, + IN CHAR16 Terminator + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + EnvironmentVariable - TODO: add argument description + Terminator - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + + + +EFI_STATUS +SetFilePointer64 ( + IN WIN_NT_BLOCK_IO_PRIVATE *Private, + IN INT64 DistanceToMove, + OUT UINT64 *NewFilePointer, + IN DWORD MoveMethod + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + DistanceToMove - TODO: add argument description + NewFilePointer - TODO: add argument description + MoveMethod - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +UINTN +Atoi ( + CHAR16 *String + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + String - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/BlockIo/WinNtBlockIo.mbd b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/BlockIo/WinNtBlockIo.mbd new file mode 100644 index 0000000000..078350addc --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/BlockIo/WinNtBlockIo.mbd @@ -0,0 +1,41 @@ + + + + + WinNtBlockIo + F479E147-A125-11d4-BCFC-0080C73C8881 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-14 17:04 + 2006-03-19 15:17 + + + UefiBootServicesTableLib + BaseLib + UefiLib + UefiMemoryLib + UefiDriverEntryPoint + UefiDriverModelLib + UefiDebugLibStdErr + BasePrintLib + DxeMemoryAllocationLib + + diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/BlockIo/WinNtBlockIo.msa b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/BlockIo/WinNtBlockIo.msa new file mode 100644 index 0000000000..c261d234cd --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/BlockIo/WinNtBlockIo.msa @@ -0,0 +1,78 @@ + + + + + WinNtBlockIo + UEFI_DRIVER + BS_DRIVER + F479E147-A125-11d4-BCFC-0080C73C8881 + 0 + Component description file for WinNtBlockIo module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-14 17:04 + 2006-03-19 15:17 + + + DebugLib + BaseLib + UefiDriverModelLib + UefiDriverEntryPoint + UefiLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + + + WinNtBlockIo.h + WinNtBlockIo.c + ComponentName.c + DriverConfiguration.c + DriverDiagnostics.c + + + MdePkg + EdkModulePkg + EdkNt32Pkg + + + WinNtIo + BlockIo + + + + WinNtVirtualDisks + + + WinNtPhysicalDisks + + + + + + + + gWinNtBlockIoDriverBinding + gWinNtBlockIoComponentName + gWinNtBlockIoDriverDiagnostics + + + diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/BlockIo/build.xml b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/BlockIo/build.xml new file mode 100644 index 0000000000..b03cad7e05 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/BlockIo/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Console/ComponentName.c b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Console/ComponentName.c new file mode 100644 index 0000000000..d10f9ab68e --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Console/ComponentName.c @@ -0,0 +1,187 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ComponentName.c + +Abstract: + +--*/ + +#include "Console.h" + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +WinNtConsoleComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +EFI_STATUS +EFIAPI +WinNtConsoleComponentNameGetControllerName ( + 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 +// +EFI_COMPONENT_NAME_PROTOCOL gWinNtConsoleComponentName = { + WinNtConsoleComponentNameGetDriverName, + WinNtConsoleComponentNameGetControllerName, + "eng" +}; + +static EFI_UNICODE_STRING_TABLE mWinNtConsoleDriverNameTable[] = { + { "eng", L"Windows Text Console Driver" }, + { NULL , NULL } +}; + +EFI_STATUS +EFIAPI +WinNtConsoleComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gWinNtConsoleComponentName.SupportedLanguages, + mWinNtConsoleDriverNameTable, + DriverName + ); +} + +EFI_STATUS +EFIAPI +WinNtConsoleComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + 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. + 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. + + Returns: + 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. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + EFI_STATUS Status; + EFI_SIMPLE_TEXT_OUT_PROTOCOL *SimpleTextOut; + WIN_NT_SIMPLE_TEXT_PRIVATE_DATA *Private; + + // + // This is a device driver, so ChildHandle must be NULL. + // + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + + // + // Get out context back + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiSimpleTextOutProtocolGuid, + &SimpleTextOut, + gWinNtConsoleDriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Private = WIN_NT_SIMPLE_TEXT_OUT_PRIVATE_DATA_FROM_THIS (SimpleTextOut); + + return LookupUnicodeString ( + Language, + gWinNtConsoleComponentName.SupportedLanguages, + Private->ControllerNameTable, + ControllerName + ); +} diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Console/Console.c b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Console/Console.c new file mode 100644 index 0000000000..0bc344c1ec --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Console/Console.c @@ -0,0 +1,307 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Console.c + +Abstract: + + Console based on Win32 APIs. + +--*/ + +#include "Console.h" + +EFI_STATUS +EFIAPI +WinNtConsoleDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +WinNtConsoleDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +WinNtConsoleDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +EFI_DRIVER_BINDING_PROTOCOL gWinNtConsoleDriverBinding = { + WinNtConsoleDriverBindingSupported, + WinNtConsoleDriverBindingStart, + WinNtConsoleDriverBindingStop, + 0x10, + NULL, + NULL +}; + + +EFI_STATUS +EFIAPI +WinNtConsoleDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Handle - add argument and description to function comment +// TODO: RemainingDevicePath - add argument and description to function comment +{ + EFI_STATUS Status; + EFI_WIN_NT_IO_PROTOCOL *WinNtIo; + + // + // Open the IO Abstraction(s) needed to perform the supported test + // + Status = gBS->OpenProtocol ( + Handle, + &gEfiWinNtIoProtocolGuid, + &WinNtIo, + This->DriverBindingHandle, + Handle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Make sure that the WinNt Thunk Protocol is valid + // + Status = EFI_UNSUPPORTED; + if (WinNtIo->WinNtThunk->Signature == EFI_WIN_NT_THUNK_PROTOCOL_SIGNATURE) { + + // + // Check the GUID to see if this is a handle type the driver supports + // + if (CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtConsoleGuid)) { + Status = EFI_SUCCESS; + } + } + + // + // Close the I/O Abstraction(s) used to perform the supported test + // + gBS->CloseProtocol ( + Handle, + &gEfiWinNtIoProtocolGuid, + This->DriverBindingHandle, + Handle + ); + + return Status; +} + +EFI_STATUS +EFIAPI +WinNtConsoleDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Handle - add argument and description to function comment +// TODO: RemainingDevicePath - add argument and description to function comment +{ + EFI_STATUS Status; + EFI_WIN_NT_IO_PROTOCOL *WinNtIo; + WIN_NT_SIMPLE_TEXT_PRIVATE_DATA *Private; + + // + // Grab the IO abstraction we need to get any work done + // + Status = gBS->OpenProtocol ( + Handle, + &gEfiWinNtIoProtocolGuid, + &WinNtIo, + This->DriverBindingHandle, + Handle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (WIN_NT_SIMPLE_TEXT_PRIVATE_DATA), + &Private + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + ZeroMem (Private, sizeof (WIN_NT_SIMPLE_TEXT_PRIVATE_DATA)); + + Private->Signature = WIN_NT_SIMPLE_TEXT_PRIVATE_DATA_SIGNATURE; + Private->Handle = Handle; + Private->WinNtIo = WinNtIo; + Private->WinNtThunk = WinNtIo->WinNtThunk; + + WinNtSimpleTextOutOpenWindow (Private); + WinNtSimpleTextInAttachToWindow (Private); + + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gEfiSimpleTextOutProtocolGuid, + &Private->SimpleTextOut, + &gEfiSimpleTextInProtocolGuid, + &Private->SimpleTextIn, + NULL + ); + if (!EFI_ERROR (Status)) { + return Status; + } + +Done: + gBS->CloseProtocol ( + Handle, + &gEfiWinNtIoProtocolGuid, + This->DriverBindingHandle, + Handle + ); + if (Private != NULL) { + + FreeUnicodeStringTable (Private->ControllerNameTable); + + if (Private->NtOutHandle != NULL) { + Private->WinNtThunk->CloseHandle (Private->NtOutHandle); + } + + if (Private->SimpleTextIn.WaitForKey != NULL) { + gBS->CloseEvent (Private->SimpleTextIn.WaitForKey); + } + + gBS->FreePool (Private); + } + + return Status; +} + +EFI_STATUS +EFIAPI +WinNtConsoleDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Handle - TODO: add argument description + NumberOfChildren - TODO: add argument description + ChildHandleBuffer - TODO: add argument description + +Returns: + + EFI_UNSUPPORTED - TODO: Add description for return value + +--*/ +{ + EFI_SIMPLE_TEXT_OUT_PROTOCOL *SimpleTextOut; + EFI_STATUS Status; + WIN_NT_SIMPLE_TEXT_PRIVATE_DATA *Private; + + // + // Kick people off our interface??? + // + Status = gBS->OpenProtocol ( + Handle, + &gEfiSimpleTextOutProtocolGuid, + &SimpleTextOut, + This->DriverBindingHandle, + Handle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Private = WIN_NT_SIMPLE_TEXT_OUT_PRIVATE_DATA_FROM_THIS (SimpleTextOut); + + ASSERT (Private->Handle == Handle); + + Status = gBS->UninstallMultipleProtocolInterfaces ( + Handle, + &gEfiSimpleTextOutProtocolGuid, + &Private->SimpleTextOut, + &gEfiSimpleTextInProtocolGuid, + &Private->SimpleTextIn, + NULL + ); + if (!EFI_ERROR (Status)) { + + // + // Shut down our device + // + Status = gBS->CloseProtocol ( + Handle, + &gEfiWinNtIoProtocolGuid, + This->DriverBindingHandle, + Handle + ); + + Status = gBS->CloseEvent (Private->SimpleTextIn.WaitForKey); + ASSERT_EFI_ERROR (Status); + + Private->WinNtThunk->CloseHandle (Private->NtOutHandle); + // + // DO NOT close Private->NtInHandle. It points to StdIn and not + // the Private->NtOutHandle is StdIn and should not be closed! + // + FreeUnicodeStringTable (Private->ControllerNameTable); + + gBS->FreePool (Private); + } + + return Status; +} diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Console/Console.h b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Console/Console.h new file mode 100644 index 0000000000..1c8a26bddc --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Console/Console.h @@ -0,0 +1,512 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Console.h + +Abstract: + + Console based on Win32 APIs. + + This file attaches a SimpleTextIn protocol to a previously open window. + + The constructor for this protocol depends on an open window. Currently + the SimpleTextOut protocol creates a window when it's constructor is called. + Thus this code must run after the constructor for the SimpleTextOut + protocol + +--*/ + +#ifndef _CONSOLE_H_ +#define _CONSOLE_H_ + + + +#define WIN_NT_SIMPLE_TEXT_PRIVATE_DATA_SIGNATURE \ + EFI_SIGNATURE_32('N','T','s','c') + +typedef struct { + UINT64 Signature; + + EFI_HANDLE Handle; + + EFI_SIMPLE_TEXT_OUT_PROTOCOL SimpleTextOut; + EFI_SIMPLE_TEXT_OUTPUT_MODE SimpleTextOutMode; + + EFI_WIN_NT_IO_PROTOCOL *WinNtIo; + EFI_WIN_NT_THUNK_PROTOCOL *WinNtThunk; + + // + // SimpleTextOut Private Data including Win32 types. + // + HANDLE NtOutHandle; + HANDLE NtInHandle; + + COORD MaxScreenSize; + COORD Possition; + WORD Attribute; + BOOLEAN CursorEnable; + + EFI_SIMPLE_TEXT_IN_PROTOCOL SimpleTextIn; + + EFI_UNICODE_STRING_TABLE *ControllerNameTable; + +} WIN_NT_SIMPLE_TEXT_PRIVATE_DATA; + +#define WIN_NT_SIMPLE_TEXT_OUT_PRIVATE_DATA_FROM_THIS(a) \ + CR(a, WIN_NT_SIMPLE_TEXT_PRIVATE_DATA, SimpleTextOut, WIN_NT_SIMPLE_TEXT_PRIVATE_DATA_SIGNATURE) + +#define WIN_NT_SIMPLE_TEXT_IN_PRIVATE_DATA_FROM_THIS(a) \ + CR(a, WIN_NT_SIMPLE_TEXT_PRIVATE_DATA, SimpleTextIn, WIN_NT_SIMPLE_TEXT_PRIVATE_DATA_SIGNATURE) + +// +// Console Globale Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gWinNtConsoleDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gWinNtConsoleComponentName; + +typedef struct { + UINTN ColumnsX; + UINTN RowsY; +} WIN_NT_SIMPLE_TEXT_OUT_MODE; + +// +// Simple Text Out protocol member functions +// + +STATIC +EFI_STATUS +EFIAPI +WinNtSimpleTextOutReset ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + ExtendedVerification - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +STATIC +EFI_STATUS +EFIAPI +WinNtSimpleTextOutOutputString ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN CHAR16 *String + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + String - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +STATIC +EFI_STATUS +EFIAPI +WinNtSimpleTextOutTestString ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN CHAR16 *String + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + String - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +STATIC +EFI_STATUS +EFIAPI +WinNtSimpleTextOutQueryMode ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN UINTN ModeNumber, + OUT UINTN *Columns, + OUT UINTN *Rows + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + ModeNumber - TODO: add argument description + Columns - TODO: add argument description + Rows - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +STATIC +EFI_STATUS +EFIAPI +WinNtSimpleTextOutSetMode ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN UINTN ModeNumber + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + ModeNumber - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +STATIC +EFI_STATUS +EFIAPI +WinNtSimpleTextOutSetAttribute ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN UINTN Attribute + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Attribute - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +STATIC +EFI_STATUS +EFIAPI +WinNtSimpleTextOutClearScreen ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +STATIC +EFI_STATUS +EFIAPI +WinNtSimpleTextOutSetCursorPosition ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN UINTN Column, + IN UINTN Row + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Column - TODO: add argument description + Row - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +STATIC +EFI_STATUS +EFIAPI +WinNtSimpleTextOutEnableCursor ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN BOOLEAN Enable + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Enable - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +// +// Simple Text Out constructor and destructor. +// +EFI_STATUS +WinNtSimpleTextOutOpenWindow ( + IN OUT WIN_NT_SIMPLE_TEXT_PRIVATE_DATA *Private + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +WinNtSimpleTextOutCloseWindow ( + IN OUT WIN_NT_SIMPLE_TEXT_PRIVATE_DATA *Console + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Console - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +// +// Simple Text In protocol member functions. +// +STATIC +EFI_STATUS +EFIAPI +WinNtSimpleTextInReset ( + IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + ExtendedVerification - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +STATIC +EFI_STATUS +EFIAPI +WinNtSimpleTextInReadKeyStroke ( + IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This, + OUT EFI_INPUT_KEY *Key + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Key - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +STATIC +VOID +EFIAPI +WinNtSimpleTextInWaitForKey ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Event - TODO: add argument description + Context - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +// +// Simple Text In constructor +// +EFI_STATUS +WinNtSimpleTextInAttachToWindow ( + IN WIN_NT_SIMPLE_TEXT_PRIVATE_DATA *Private + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +// +// Main Entry Point +// +EFI_STATUS +EFIAPI +InitializeWinNtConsole ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ImageHandle - TODO: add argument description + SystemTable - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AppendDevicePathInstanceToVar ( + IN CHAR16 *VariableName, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathInstance + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + VariableName - TODO: add argument description + DevicePathInstance - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Console/ConsoleIn.c b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Console/ConsoleIn.c new file mode 100644 index 0000000000..3af1ce6570 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Console/ConsoleIn.c @@ -0,0 +1,361 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ConsoleIn.c + +Abstract: + + Console based on Win32 APIs. + + This file attaches a SimpleTextIn protocol to a previously open window. + + The constructor for this protocol depends on an open window. Currently + the SimpleTextOut protocol creates a window when it's constructor is called. + Thus this code must run after the constructor for the SimpleTextOut + protocol + +--*/ + +#include "Console.h" + +// +// Private worker functions +// +STATIC +EFI_STATUS +WinNtSimpleTextInCheckKey ( + WIN_NT_SIMPLE_TEXT_PRIVATE_DATA *Private + ); + +EFI_STATUS +EFIAPI +WinNtSimpleTextInReset ( + IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + ExtendedVerification - TODO: add argument description + +Returns: + + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + WIN_NT_SIMPLE_TEXT_PRIVATE_DATA *Private; + + Private = WIN_NT_SIMPLE_TEXT_IN_PRIVATE_DATA_FROM_THIS (This); + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +WinNtConvertInputRecordToEfiKey ( + IN INPUT_RECORD *InputRecord, + OUT EFI_INPUT_KEY *Key + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + InputRecord - TODO: add argument description + Key - TODO: add argument description + +Returns: + + EFI_NOT_READY - TODO: Add description for return value + EFI_NOT_READY - TODO: Add description for return value + EFI_NOT_READY - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + // + // Make sure InputRecord is an event that represents a keypress + // + if (InputRecord->EventType == KEY_EVENT) { + if (!InputRecord->Event.KeyEvent.bKeyDown) { + return EFI_NOT_READY; + } + } else { + return EFI_NOT_READY; + } + + // + // Check to see if we should return a scan code in place of Unicode character. + // + Key->ScanCode = 0; + Key->UnicodeChar = 0; + if ((InputRecord->Event.KeyEvent.dwControlKeyState & (NUMLOCK_ON | ENHANCED_KEY)) != NUMLOCK_ON) { + // + // Only check these scan codes if num lock is off. + // + switch (InputRecord->Event.KeyEvent.wVirtualScanCode) { + case 0x48: Key->ScanCode = SCAN_UP; break; + case 0x50: Key->ScanCode = SCAN_DOWN; break; + case 0x4d: Key->ScanCode = SCAN_RIGHT; break; + case 0x4b: Key->ScanCode = SCAN_LEFT; break; + case 0x47: Key->ScanCode = SCAN_HOME; break; + case 0x4F: Key->ScanCode = SCAN_END; break; + case 0x52: Key->ScanCode = SCAN_INSERT; break; + case 0x53: Key->ScanCode = SCAN_DELETE; break; + case 0x49: Key->ScanCode = SCAN_PAGE_UP; break; + case 0x51: Key->ScanCode = SCAN_PAGE_DOWN; break; + } + } + + switch (InputRecord->Event.KeyEvent.wVirtualScanCode) { + case 0x3b: Key->ScanCode = SCAN_F1; break; + case 0x3c: Key->ScanCode = SCAN_F2; break; + case 0x3d: Key->ScanCode = SCAN_F3; break; + case 0x3e: Key->ScanCode = SCAN_F4; break; + case 0x3f: Key->ScanCode = SCAN_F5; break; + case 0x40: Key->ScanCode = SCAN_F6; break; + case 0x41: Key->ScanCode = SCAN_F7; break; + case 0x42: Key->ScanCode = SCAN_F8; break; + case 0x43: Key->ScanCode = SCAN_F9; break; + case 0x44: Key->ScanCode = SCAN_F10; break; + case 0x01: Key->ScanCode = SCAN_ESC; break; + } + + // + // If there's a scan code pass it, and don't pass the char code + // + if (Key->ScanCode == 0) { + Key->UnicodeChar = InputRecord->Event.KeyEvent.uChar.UnicodeChar; + if (Key->UnicodeChar == 0) { + return EFI_NOT_READY; + } + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +WinNtSimpleTextInReadKeyStroke ( + IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This, + OUT EFI_INPUT_KEY *Key + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Key - TODO: add argument description + +Returns: + + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_NOT_READY - TODO: Add description for return value + +--*/ +{ + EFI_STATUS Status; + WIN_NT_SIMPLE_TEXT_PRIVATE_DATA *Private; + INPUT_RECORD InputRecord; + DWORD NtEventCount; + + Private = WIN_NT_SIMPLE_TEXT_IN_PRIVATE_DATA_FROM_THIS (This); + + Status = WinNtSimpleTextInCheckKey (Private); + if (EFI_ERROR (Status)) { + return Status; + } + + do { + + if (!Private->WinNtThunk->ReadConsoleInput (Private->NtInHandle, &InputRecord, 1, &NtEventCount)) { + return EFI_DEVICE_ERROR; + } + + if (NtEventCount == 0) { + return EFI_NOT_READY; + } + + // + // Convert the Input Record to an EFI Keystroke. + // + Status = WinNtConvertInputRecordToEfiKey (&InputRecord, Key); + } while (EFI_ERROR (Status)); + + return Status; +} + +STATIC +VOID +EFIAPI +WinNtSimpleTextInWaitForKey ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Event - TODO: add argument description + Context - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + WIN_NT_SIMPLE_TEXT_PRIVATE_DATA *Private; + EFI_STATUS Status; + + Private = (WIN_NT_SIMPLE_TEXT_PRIVATE_DATA *) Context; + Status = WinNtSimpleTextInCheckKey (Private); + if (!EFI_ERROR (Status)) { + gBS->SignalEvent (Event); + } +} + +STATIC +EFI_STATUS +WinNtSimpleTextInCheckKey ( + WIN_NT_SIMPLE_TEXT_PRIVATE_DATA *Private + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + INPUT_RECORD *InputRecord; + DWORD NtEventCount; + DWORD ActualNtEventCount; + EFI_STATUS Status; + BOOLEAN Success; + UINTN Index; + EFI_INPUT_KEY Key; + + InputRecord = NULL; + NtEventCount = 0; + Private->WinNtThunk->GetNumberOfConsoleInputEvents (Private->NtInHandle, &NtEventCount); + if (NtEventCount == 0) { + Status = EFI_NOT_READY; + goto Done; + } + + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (INPUT_RECORD) * NtEventCount, + &InputRecord + ); + if (EFI_ERROR (Status)) { + Status = EFI_NOT_READY; + goto Done; + } + + Success = (BOOLEAN) Private->WinNtThunk->PeekConsoleInput ( + Private->NtInHandle, + InputRecord, + NtEventCount, + &ActualNtEventCount + ); + if (!Success) { + Status = EFI_NOT_READY; + goto Done; + } + + Status = EFI_NOT_READY; + for (Index = 0; Index < (UINTN) ActualNtEventCount; Index++) { + // + // Convert the Input Record to an EFI Keystroke. + // + Status = WinNtConvertInputRecordToEfiKey (&InputRecord[Index], &Key); + if (!EFI_ERROR (Status)) { + Status = EFI_SUCCESS; + goto Done; + } + } + +Done: + if (InputRecord != NULL) { + gBS->FreePool (InputRecord); + } + + return Status; +} + +EFI_STATUS +WinNtSimpleTextInAttachToWindow ( + IN WIN_NT_SIMPLE_TEXT_PRIVATE_DATA *Private + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + EFI_STATUS Status; + + Private->NtInHandle = Private->WinNtThunk->GetStdHandle (STD_INPUT_HANDLE); + + Private->SimpleTextIn.Reset = WinNtSimpleTextInReset; + Private->SimpleTextIn.ReadKeyStroke = WinNtSimpleTextInReadKeyStroke; + + Status = gBS->CreateEvent ( + EFI_EVENT_NOTIFY_WAIT, + EFI_TPL_NOTIFY, + WinNtSimpleTextInWaitForKey, + Private, + &Private->SimpleTextIn.WaitForKey + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Console/ConsoleOut.c b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Console/ConsoleOut.c new file mode 100644 index 0000000000..cab3768b1c --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Console/ConsoleOut.c @@ -0,0 +1,638 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ConsoleOut.c + +Abstract: + + Console based on Win32 APIs. + + This file creates an Win32 window and attaches a SimpleTextOut protocol. + +--*/ + +#include "Console.h" +// +// Private worker functions. +// + +STATIC +VOID +WinNtSimpleTextOutScrollScreen ( + IN OUT WIN_NT_SIMPLE_TEXT_PRIVATE_DATA *Console + ); + +STATIC +VOID +WinNtSimpleTextOutPutChar ( + IN OUT WIN_NT_SIMPLE_TEXT_PRIVATE_DATA *Console, + IN CHAR16 Char + ); + +// +// Modeule Global for Simple Text Out Mode. +// +#define MAX_SIMPLE_TEXT_OUT_MODE \ + (sizeof(mWinNtSimpleTextOutSupportedModes)/sizeof(WIN_NT_SIMPLE_TEXT_OUT_MODE)) + +STATIC WIN_NT_SIMPLE_TEXT_OUT_MODE mWinNtSimpleTextOutSupportedModes[] = { + { 80, 25 }, + { 80, 50 }, + { 80, 43 }, + { 100, 100 }, + { 100, 999 } +}; + +STATIC +EFI_STATUS +EFIAPI +WinNtSimpleTextOutReset ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + ExtendedVerification - TODO: add argument description + +Returns: + + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + WIN_NT_SIMPLE_TEXT_PRIVATE_DATA *Private; + + Private = WIN_NT_SIMPLE_TEXT_OUT_PRIVATE_DATA_FROM_THIS (This); + + WinNtSimpleTextOutSetAttribute (This, EFI_TEXT_ATTR (This->Mode->Attribute & 0x0F, EFI_BACKGROUND_BLACK)); + + WinNtSimpleTextOutSetMode (This, 0); + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +WinNtSimpleTextOutOutputString ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN CHAR16 *String + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + String - TODO: add argument description + +Returns: + + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + WIN_NT_SIMPLE_TEXT_PRIVATE_DATA *Private; + CHAR16 *Str; + + Private = WIN_NT_SIMPLE_TEXT_OUT_PRIVATE_DATA_FROM_THIS (This); + + for (Str = String; *Str != '\0'; Str++) { + switch (*Str) { + case '\n': + if (Private->Possition.Y == (Private->MaxScreenSize.Y - 1)) { + WinNtSimpleTextOutScrollScreen (Private); + } + + if (Private->Possition.Y < (Private->MaxScreenSize.Y - 1)) { + Private->Possition.Y++; + This->Mode->CursorRow++; + } + break; + + case '\r': + Private->Possition.X = 0; + This->Mode->CursorColumn = 0; + break; + + case '\b': + if (Private->Possition.X > 0) { + Private->Possition.X--; + This->Mode->CursorColumn--; + } + break; + + default: + WinNtSimpleTextOutPutChar (Private, *Str); + } + } + + return EFI_SUCCESS; +} + +STATIC +VOID +WinNtSimpleTextOutPutChar ( + IN OUT WIN_NT_SIMPLE_TEXT_PRIVATE_DATA *Console, + IN CHAR16 Char + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Console - TODO: add argument description + Char - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + SMALL_RECT Region; + COORD StrCoordinate; + COORD StrSize; + CHAR_INFO CharInfo; + BOOL Flag; + + CharInfo.Char.UnicodeChar = Char; + CharInfo.Attributes = Console->Attribute; + + StrSize.X = 1; + StrSize.Y = 1; + StrCoordinate.X = 0; + StrCoordinate.Y = 0; + + Region.Left = (INT16) Console->Possition.X; + Region.Top = (INT16) Console->Possition.Y; + Region.Right = (INT16) (Console->Possition.X + 1); + Region.Bottom = (INT16) Console->Possition.Y; + + Console->WinNtThunk->WriteConsoleOutput ( + Console->NtOutHandle, + &CharInfo, + StrSize, + StrCoordinate, + &Region + ); + + if (Console->Possition.X >= (Console->MaxScreenSize.X - 1)) { + // + // If you print off the end wrap around + // + Console->SimpleTextOut.OutputString (&Console->SimpleTextOut, L"\n\r"); + } else { + Console->Possition.X++; + Console->SimpleTextOut.Mode->CursorColumn++; + } + + Flag = Console->WinNtThunk->SetConsoleCursorPosition (Console->NtOutHandle, Console->Possition); +} + +STATIC +VOID +WinNtSimpleTextOutScrollScreen ( + IN OUT WIN_NT_SIMPLE_TEXT_PRIVATE_DATA *Console + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Console - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + SMALL_RECT Scroll; + CHAR_INFO CharInfo; + COORD Origin; + + CharInfo.Char.UnicodeChar = ' '; + CharInfo.Attributes = Console->Attribute; + + Origin.X = 0; + Origin.Y = 0; + + Scroll.Top = 1; + Scroll.Left = 0; + Scroll.Right = (INT16) Console->MaxScreenSize.X; + Scroll.Bottom = (INT16) Console->MaxScreenSize.Y; + + Console->WinNtThunk->ScrollConsoleScreenBuffer ( + Console->NtOutHandle, + &Scroll, + NULL, + Origin, + &CharInfo + ); +} + +STATIC +EFI_STATUS +EFIAPI +WinNtSimpleTextOutTestString ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN CHAR16 *String + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + String - TODO: add argument description + +Returns: + + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + WIN_NT_SIMPLE_TEXT_PRIVATE_DATA *Private; + + Private = WIN_NT_SIMPLE_TEXT_OUT_PRIVATE_DATA_FROM_THIS (This); + + // + // BugBug: The correct answer would be a function of what code pages + // are currently loaded? For now we will just return success. + // + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +WinNtSimpleTextOutQueryMode ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN UINTN ModeNumber, + OUT UINTN *Columns, + OUT UINTN *Rows + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + ModeNumber - TODO: add argument description + Columns - TODO: add argument description + Rows - TODO: add argument description + +Returns: + + EFI_INVALID_PARAMETER - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + WIN_NT_SIMPLE_TEXT_PRIVATE_DATA *Private; + + Private = WIN_NT_SIMPLE_TEXT_OUT_PRIVATE_DATA_FROM_THIS (This); + + if (ModeNumber > MAX_SIMPLE_TEXT_OUT_MODE) { + return EFI_INVALID_PARAMETER; + } + + *Columns = mWinNtSimpleTextOutSupportedModes[ModeNumber].ColumnsX; + *Rows = mWinNtSimpleTextOutSupportedModes[ModeNumber].RowsY; + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +WinNtSimpleTextOutSetMode ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN UINTN ModeNumber + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + ModeNumber - TODO: add argument description + +Returns: + + EFI_INVALID_PARAMETER - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + WIN_NT_SIMPLE_TEXT_PRIVATE_DATA *Private; + + Private = WIN_NT_SIMPLE_TEXT_OUT_PRIVATE_DATA_FROM_THIS (This); + + if (ModeNumber > MAX_SIMPLE_TEXT_OUT_MODE) { + return EFI_INVALID_PARAMETER; + } + + Private->MaxScreenSize.X = (WORD) mWinNtSimpleTextOutSupportedModes[ModeNumber].ColumnsX; + Private->MaxScreenSize.Y = (WORD) mWinNtSimpleTextOutSupportedModes[ModeNumber].RowsY; + + Private->WinNtThunk->SetConsoleScreenBufferSize (Private->NtOutHandle, Private->MaxScreenSize); + Private->WinNtThunk->SetConsoleActiveScreenBuffer (Private->NtOutHandle); + + This->Mode->Mode = (INT32) ModeNumber; + + This->EnableCursor (This, TRUE); + This->ClearScreen (This); + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +WinNtSimpleTextOutSetAttribute ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN UINTN Attribute + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Attribute - TODO: add argument description + +Returns: + + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + WIN_NT_SIMPLE_TEXT_PRIVATE_DATA *Private; + + Private = WIN_NT_SIMPLE_TEXT_OUT_PRIVATE_DATA_FROM_THIS (This); + + Private->Attribute = (WORD) Attribute; + This->Mode->Attribute = (INT32) Attribute; + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +WinNtSimpleTextOutClearScreen ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + +Returns: + + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + WIN_NT_SIMPLE_TEXT_PRIVATE_DATA *Private; + DWORD ConsoleWindow; + + Private = WIN_NT_SIMPLE_TEXT_OUT_PRIVATE_DATA_FROM_THIS (This); + + This->SetCursorPosition (This, 0, 0); + + Private->WinNtThunk->FillConsoleOutputCharacter ( + Private->NtOutHandle, + ' ', + Private->MaxScreenSize.X * Private->MaxScreenSize.Y, + Private->Possition, + &ConsoleWindow + ); + Private->WinNtThunk->FillConsoleOutputAttribute ( + Private->NtOutHandle, + Private->Attribute, + Private->MaxScreenSize.X * Private->MaxScreenSize.Y, + Private->Possition, + &ConsoleWindow + ); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +WinNtSimpleTextOutSetCursorPosition ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN UINTN Column, + IN UINTN Row + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Column - TODO: add argument description + Row - TODO: add argument description + +Returns: + + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + WIN_NT_SIMPLE_TEXT_PRIVATE_DATA *Private; + + Private = WIN_NT_SIMPLE_TEXT_OUT_PRIVATE_DATA_FROM_THIS (This); + + Private->Possition.X = (WORD) Column; + This->Mode->CursorColumn = (INT32) Column; + + Private->Possition.Y = (WORD) Row; + This->Mode->CursorRow = (INT32) Row; + Private->WinNtThunk->SetConsoleCursorPosition (Private->NtOutHandle, Private->Possition); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +WinNtSimpleTextOutEnableCursor ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This, + IN BOOLEAN Enable + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Enable - TODO: add argument description + +Returns: + + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + WIN_NT_SIMPLE_TEXT_PRIVATE_DATA *Private; + CONSOLE_CURSOR_INFO Info; + + Private = WIN_NT_SIMPLE_TEXT_OUT_PRIVATE_DATA_FROM_THIS (This); + Private->CursorEnable = Enable; + This->Mode->CursorVisible = Enable; + + Private->WinNtThunk->GetConsoleCursorInfo (Private->NtOutHandle, &Info); + Info.bVisible = Enable; + Private->WinNtThunk->SetConsoleCursorInfo (Private->NtOutHandle, &Info); + + return EFI_SUCCESS; +} + +EFI_STATUS +WinNtSimpleTextOutOpenWindow ( + IN OUT WIN_NT_SIMPLE_TEXT_PRIVATE_DATA *Private + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + EFI_SIMPLE_TEXT_OUT_PROTOCOL *SimpleTextOut; + CHAR16 *WindowName; + + WindowName = Private->WinNtIo->EnvString; + Private->Attribute = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY; + if (*WindowName == '?') { + Private->Attribute = BACKGROUND_RED | FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN; + WindowName = L"EFI Emulator Error Console"; + } + + AddUnicodeString ( + "eng", + gWinNtConsoleComponentName.SupportedLanguages, + &Private->ControllerNameTable, + WindowName + ); + + // + // Fill in protocol member functions + // + SimpleTextOut = &Private->SimpleTextOut; + SimpleTextOut->Reset = WinNtSimpleTextOutReset; + SimpleTextOut->OutputString = WinNtSimpleTextOutOutputString; + SimpleTextOut->TestString = WinNtSimpleTextOutTestString; + SimpleTextOut->QueryMode = WinNtSimpleTextOutQueryMode; + SimpleTextOut->SetMode = WinNtSimpleTextOutSetMode; + SimpleTextOut->SetAttribute = WinNtSimpleTextOutSetAttribute; + SimpleTextOut->ClearScreen = WinNtSimpleTextOutClearScreen; + SimpleTextOut->SetCursorPosition = WinNtSimpleTextOutSetCursorPosition; + SimpleTextOut->EnableCursor = WinNtSimpleTextOutEnableCursor; + + // + // Initialize SimpleTextOut protocol mode structure + // + SimpleTextOut->Mode = &Private->SimpleTextOutMode; + SimpleTextOut->Mode->MaxMode = MAX_SIMPLE_TEXT_OUT_MODE; + SimpleTextOut->Mode->Attribute = (INT32) Private->Attribute; + + // + // Open the window an initialize it! + // + Private->NtOutHandle = Private->WinNtThunk->CreateConsoleScreenBuffer ( + GENERIC_WRITE | GENERIC_READ, + FILE_SHARE_WRITE | FILE_SHARE_READ, + NULL, + CONSOLE_TEXTMODE_BUFFER, + NULL + ); + Private->WinNtThunk->SetConsoleTitle (WindowName); + + return SimpleTextOut->SetMode (SimpleTextOut, 0); +} + +EFI_STATUS +WinNtSimpleTextOutCloseWindow ( + IN OUT WIN_NT_SIMPLE_TEXT_PRIVATE_DATA *Console + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Console - TODO: add argument description + +Returns: + + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + Console->WinNtThunk->CloseHandle (Console->NtOutHandle); + return EFI_SUCCESS; +} diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Console/WinNtConsole.mbd b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Console/WinNtConsole.mbd new file mode 100644 index 0000000000..566a7481af --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Console/WinNtConsole.mbd @@ -0,0 +1,41 @@ + + + + + WinNtConsole + 263631d7-5836-4b74-be48-ee22e92ce5d3 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-14 17:04 + 2006-03-19 15:17 + + + UefiBootServicesTableLib + BaseLib + UefiLib + UefiMemoryLib + UefiDriverEntryPoint + UefiDriverModelLib + UefiDebugLibStdErr + BasePrintLib + DxeMemoryAllocationLib + + diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Console/WinNtConsole.msa b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Console/WinNtConsole.msa new file mode 100644 index 0000000000..95f7595961 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Console/WinNtConsole.msa @@ -0,0 +1,75 @@ + + + + + WinNtConsole + UEFI_DRIVER + BS_DRIVER + 263631d7-5836-4b74-be48-ee22e92ce5d3 + 0 + Component description file for WinNtConsole module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-14 17:04 + 2006-03-19 15:17 + + + DebugLib + BaseLib + UefiDriverModelLib + UefiDriverEntryPoint + UefiLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + + + Console.h + Console.c + ConsoleIn.c + ConsoleOut.c + ComponentName.c + + + MdePkg + EdkModulePkg + EdkNt32Pkg + + + WinNtIo + SimpleTextOut + SimpleTextIn + + + + WinNtConsole + + + + + + + + gWinNtConsoleDriverBinding + gWinNtConsoleComponentName + + + diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Console/build.xml b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Console/build.xml new file mode 100644 index 0000000000..9d227c7f0e --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Console/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SerialIo/ComponentName.c b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SerialIo/ComponentName.c new file mode 100644 index 0000000000..82057866c7 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SerialIo/ComponentName.c @@ -0,0 +1,187 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ComponentName.c + +Abstract: + +--*/ + +#include "WinNtSerialIo.h" + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +WinNtSerialIoComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +EFI_STATUS +EFIAPI +WinNtSerialIoComponentNameGetControllerName ( + 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 +// +EFI_COMPONENT_NAME_PROTOCOL gWinNtSerialIoComponentName = { + WinNtSerialIoComponentNameGetDriverName, + WinNtSerialIoComponentNameGetControllerName, + "eng" +}; + +static EFI_UNICODE_STRING_TABLE mWinNtSerialIoDriverNameTable[] = { + { "eng", L"Windows Serial I/O Driver" }, + { NULL , NULL } +}; + +EFI_STATUS +EFIAPI +WinNtSerialIoComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gWinNtSerialIoComponentName.SupportedLanguages, + mWinNtSerialIoDriverNameTable, + DriverName + ); +} + +EFI_STATUS +EFIAPI +WinNtSerialIoComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + 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. + 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. + + Returns: + 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. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + EFI_STATUS Status; + EFI_SERIAL_IO_PROTOCOL *SerialIo; + WIN_NT_SERIAL_IO_PRIVATE_DATA *Private; + + // + // This is a bus driver, so ChildHandle must not be NULL. + // + if (ChildHandle == NULL) { + return EFI_UNSUPPORTED; + } + + // + // Get our context back + // + Status = gBS->OpenProtocol ( + ChildHandle, + &gEfiSerialIoProtocolGuid, + &SerialIo, + gWinNtSerialIoDriverBinding.DriverBindingHandle, + ChildHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (SerialIo); + + return LookupUnicodeString ( + Language, + gWinNtSerialIoComponentName.SupportedLanguages, + Private->ControllerNameTable, + ControllerName + ); +} diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SerialIo/WinNtSerialIo.c b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SerialIo/WinNtSerialIo.c new file mode 100644 index 0000000000..38c03a8bbc --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SerialIo/WinNtSerialIo.c @@ -0,0 +1,1410 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + WinNtSerialIo.c + +Abstract: + + Our DriverBinding member functions operate on the handles + created by the NT Bus driver. + + Handle(1) - WinNtIo - DevicePath(1) + + If a serial port is added to the system this driver creates a new handle. + The new handle is required, since the serial device must add an UART device + pathnode. + + Handle(2) - SerialIo - DevicePath(1)\UART + + The driver then adds a gEfiWinNtSerialPortGuid as a protocol to Handle(1). + The instance data for this protocol is the private data used to create + Handle(2). + + Handle(1) - WinNtIo - DevicePath(1) - WinNtSerialPort + + If the driver is unloaded Handle(2) is removed from the system and + gEfiWinNtSerialPortGuid is removed from Handle(1). + + Note: Handle(1) is any handle created by the Win NT Bus driver that is passed + into the DriverBinding member functions of this driver. This driver requires + a Handle(1) to contain a WinNtIo protocol, a DevicePath protocol, and + the TypeGuid in the WinNtIo must be gEfiWinNtSerialPortGuid. + + If Handle(1) contains a gEfiWinNtSerialPortGuid protocol then the driver is + loaded on the device. + +--*/ + +#include "WinNtSerialIo.h" + +EFI_DRIVER_BINDING_PROTOCOL gWinNtSerialIoDriverBinding = { + WinNtSerialIoDriverBindingSupported, + WinNtSerialIoDriverBindingStart, + WinNtSerialIoDriverBindingStop, + 0x10, + NULL, + NULL +}; + +STATIC +EFI_STATUS +EFIAPI +WinNtSerialIoDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Handle - add argument and description to function comment +// TODO: RemainingDevicePath - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_WIN_NT_IO_PROTOCOL *WinNtIo; + UART_DEVICE_PATH *UartNode; + + // + // Open the IO Abstraction(s) needed to perform the supported test + // + Status = gBS->OpenProtocol ( + Handle, + &gEfiDevicePathProtocolGuid, + &ParentDevicePath, + This->DriverBindingHandle, + Handle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (Status == EFI_ALREADY_STARTED) { + return EFI_SUCCESS; + } + + if (EFI_ERROR (Status)) { + return Status; + } + + gBS->CloseProtocol ( + Handle, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Handle + ); + + Status = gBS->OpenProtocol ( + Handle, + &gEfiWinNtIoProtocolGuid, + &WinNtIo, + This->DriverBindingHandle, + Handle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (Status == EFI_ALREADY_STARTED) { + return EFI_SUCCESS; + } + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Make sure that the WinNt Thunk Protocol is valid + // + if (WinNtIo->WinNtThunk->Signature != EFI_WIN_NT_THUNK_PROTOCOL_SIGNATURE) { + Status = EFI_UNSUPPORTED; + goto Error; + } + + // + // Check the GUID to see if this is a handle type the driver supports + // + if (!CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtSerialPortGuid)) { + Status = EFI_UNSUPPORTED; + goto Error; + } + + if (RemainingDevicePath != NULL) { + Status = EFI_UNSUPPORTED; + UartNode = (UART_DEVICE_PATH *) RemainingDevicePath; + if (UartNode->Header.Type != MESSAGING_DEVICE_PATH || + UartNode->Header.SubType != MSG_UART_DP || + DevicePathNodeLength((EFI_DEVICE_PATH_PROTOCOL *)UartNode) != sizeof(UART_DEVICE_PATH)) { + goto Error; + } + if (UartNode->BaudRate < 0 || UartNode->BaudRate > SERIAL_PORT_MAX_BAUD_RATE) { + goto Error; + } + if (UartNode->Parity < NoParity || UartNode->Parity > SpaceParity) { + goto Error; + } + if (UartNode->DataBits < 5 || UartNode->DataBits > 8) { + goto Error; + } + if (UartNode->StopBits < OneStopBit || UartNode->StopBits > TwoStopBits) { + goto Error; + } + if ((UartNode->DataBits == 5) && (UartNode->StopBits == TwoStopBits)) { + goto Error; + } + if ((UartNode->DataBits >= 6) && (UartNode->DataBits <= 8) && (UartNode->StopBits == OneFiveStopBits)) { + goto Error; + } + Status = EFI_SUCCESS; + } + +Error: + // + // Close the I/O Abstraction(s) used to perform the supported test + // + gBS->CloseProtocol ( + Handle, + &gEfiWinNtIoProtocolGuid, + This->DriverBindingHandle, + Handle + ); + + return Status; +} + +STATIC +EFI_STATUS +EFIAPI +WinNtSerialIoDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Handle - add argument and description to function comment +// TODO: RemainingDevicePath - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + EFI_WIN_NT_IO_PROTOCOL *WinNtIo; + WIN_NT_SERIAL_IO_PRIVATE_DATA *Private; + HANDLE NtHandle; + UART_DEVICE_PATH Node; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer; + UINTN EntryCount; + UINTN Index; + EFI_SERIAL_IO_PROTOCOL *SerialIo; + + Private = NULL; + NtHandle = INVALID_HANDLE_VALUE; + + // + // Grab the protocols we need + // + Status = gBS->OpenProtocol ( + Handle, + &gEfiDevicePathProtocolGuid, + &ParentDevicePath, + This->DriverBindingHandle, + Handle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { + return Status; + } + + // + // Grab the IO abstraction we need to get any work done + // + Status = gBS->OpenProtocol ( + Handle, + &gEfiWinNtIoProtocolGuid, + &WinNtIo, + This->DriverBindingHandle, + Handle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { + gBS->CloseProtocol ( + Handle, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Handle + ); + return Status; + } + + if (Status == EFI_ALREADY_STARTED) { + + if (RemainingDevicePath == NULL) { + return EFI_SUCCESS; + } + + // + // Make sure a child handle does not already exist. This driver can only + // produce one child per serial port. + // + Status = gBS->OpenProtocolInformation ( + Handle, + &gEfiWinNtIoProtocolGuid, + &OpenInfoBuffer, + &EntryCount + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = EFI_ALREADY_STARTED; + for (Index = 0; Index < EntryCount; Index++) { + if (OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) { + Status = gBS->OpenProtocol ( + OpenInfoBuffer[Index].ControllerHandle, + &gEfiSerialIoProtocolGuid, + &SerialIo, + This->DriverBindingHandle, + Handle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + CopyMem (&Node, RemainingDevicePath, sizeof (UART_DEVICE_PATH)); + Status = SerialIo->SetAttributes ( + SerialIo, + Node.BaudRate, + SerialIo->Mode->ReceiveFifoDepth, + SerialIo->Mode->Timeout, + Node.Parity, + Node.DataBits, + Node.StopBits + ); + } + break; + } + } + + gBS->FreePool (OpenInfoBuffer); + return Status; + } + + // + // Check to see if we can access the hardware device. If it's Open in NT we + // will not get access. + // + NtHandle = WinNtIo->WinNtThunk->CreateFile ( + WinNtIo->EnvString, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + 0, + NULL + ); + if (NtHandle == INVALID_HANDLE_VALUE) { + Status = EFI_DEVICE_ERROR; + goto Error; + } + + // + // Construct Private data + // + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (WIN_NT_SERIAL_IO_PRIVATE_DATA), + &Private + ); + if (EFI_ERROR (Status)) { + goto Error; + } + + // + // This signature must be valid before any member function is called + // + Private->Signature = WIN_NT_SERIAL_IO_PRIVATE_DATA_SIGNATURE; + Private->NtHandle = NtHandle; + Private->ControllerHandle = Handle; + Private->Handle = NULL; + Private->WinNtThunk = WinNtIo->WinNtThunk; + Private->ParentDevicePath = ParentDevicePath; + Private->ControllerNameTable = NULL; + + Private->SoftwareLoopbackEnable = FALSE; + Private->HardwareLoopbackEnable = FALSE; + Private->HardwareFlowControl = FALSE; + Private->Fifo.First = 0; + Private->Fifo.Last = 0; + Private->Fifo.Surplus = SERIAL_MAX_BUFFER_SIZE; + + AddUnicodeString ( + "eng", + gWinNtSerialIoComponentName.SupportedLanguages, + &Private->ControllerNameTable, + WinNtIo->EnvString + ); + + Private->SerialIo.Revision = SERIAL_IO_INTERFACE_REVISION; + Private->SerialIo.Reset = WinNtSerialIoReset; + Private->SerialIo.SetAttributes = WinNtSerialIoSetAttributes; + Private->SerialIo.SetControl = WinNtSerialIoSetControl; + Private->SerialIo.GetControl = WinNtSerialIoGetControl; + Private->SerialIo.Write = WinNtSerialIoWrite; + Private->SerialIo.Read = WinNtSerialIoRead; + Private->SerialIo.Mode = &Private->SerialIoMode; + + if (RemainingDevicePath != NULL) { + // + // Match the configuration of the RemainingDevicePath. IsHandleSupported() + // already checked to make sure the RemainingDevicePath contains settings + // that we can support. + // + CopyMem (&Private->UartDevicePath, RemainingDevicePath, sizeof (UART_DEVICE_PATH)); + } else { + // + // Build the device path by appending the UART node to the ParentDevicePath + // from the WinNtIo handle. The Uart setings are zero here, since + // SetAttribute() will update them to match the default setings. + // + ZeroMem (&Private->UartDevicePath, sizeof (UART_DEVICE_PATH)); + Private->UartDevicePath.Header.Type = MESSAGING_DEVICE_PATH; + Private->UartDevicePath.Header.SubType = MSG_UART_DP; + SetDevicePathNodeLength ((EFI_DEVICE_PATH_PROTOCOL *) &Private->UartDevicePath, sizeof (UART_DEVICE_PATH)); + } + + // + // Build the device path by appending the UART node to the ParentDevicePath + // from the WinNtIo handle. The Uart setings are zero here, since + // SetAttribute() will update them to match the current setings. + // + Private->DevicePath = AppendDevicePathNode ( + ParentDevicePath, + (EFI_DEVICE_PATH_PROTOCOL *) &Private->UartDevicePath + ); + if (Private->DevicePath == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + + // + // Fill in Serial I/O Mode structure based on either the RemainingDevicePath or defaults. + // + Private->SerialIoMode.ControlMask = SERIAL_CONTROL_MASK; + Private->SerialIoMode.Timeout = SERIAL_TIMEOUT_DEFAULT; + Private->SerialIoMode.BaudRate = Private->UartDevicePath.BaudRate; + Private->SerialIoMode.ReceiveFifoDepth = SERIAL_FIFO_DEFAULT; + Private->SerialIoMode.DataBits = Private->UartDevicePath.DataBits; + Private->SerialIoMode.Parity = Private->UartDevicePath.Parity; + Private->SerialIoMode.StopBits = Private->UartDevicePath.StopBits; + + // + // Issue a reset to initialize the COM port + // + Status = Private->SerialIo.Reset (&Private->SerialIo); + if (EFI_ERROR (Status)) { + goto Error; + } + + // + // Create new child handle + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &Private->Handle, + &gEfiSerialIoProtocolGuid, + &Private->SerialIo, + &gEfiDevicePathProtocolGuid, + Private->DevicePath, + NULL + ); + if (EFI_ERROR (Status)) { + goto Error; + } + + // + // Open For Child Device + // + Status = gBS->OpenProtocol ( + Handle, + &gEfiWinNtIoProtocolGuid, + &WinNtIo, + This->DriverBindingHandle, + Private->Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + if (EFI_ERROR (Status)) { + goto Error; + } + + return EFI_SUCCESS; + +Error: + // + // Use the Stop() function to free all resources allocated in Start() + // + if (Private != NULL) { + if (Private->Handle != NULL) { + This->Stop (This, Handle, 1, &Private->Handle); + } else { + if (NtHandle != INVALID_HANDLE_VALUE) { + Private->WinNtThunk->CloseHandle (NtHandle); + } + + if (Private->DevicePath != NULL) { + gBS->FreePool (Private->DevicePath); + } + + FreeUnicodeStringTable (Private->ControllerNameTable); + + gBS->FreePool (Private); + } + } + + This->Stop (This, Handle, 0, NULL); + + return Status; +} + +STATIC +EFI_STATUS +EFIAPI +WinNtSerialIoDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Handle - TODO: add argument description + NumberOfChildren - TODO: add argument description + ChildHandleBuffer - TODO: add argument description + +Returns: + + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + EFI_STATUS Status; + UINTN Index; + BOOLEAN AllChildrenStopped; + EFI_SERIAL_IO_PROTOCOL *SerialIo; + WIN_NT_SERIAL_IO_PRIVATE_DATA *Private; + EFI_WIN_NT_IO_PROTOCOL *WinNtIo; + + // + // Complete all outstanding transactions to Controller. + // Don't allow any new transaction to Controller to be started. + // + + if (NumberOfChildren == 0) { + // + // Close the bus driver + // + Status = gBS->CloseProtocol ( + Handle, + &gEfiWinNtIoProtocolGuid, + This->DriverBindingHandle, + Handle + ); + Status = gBS->CloseProtocol ( + Handle, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Handle + ); + return Status; + } + + AllChildrenStopped = TRUE; + + for (Index = 0; Index < NumberOfChildren; Index++) { + Status = gBS->OpenProtocol ( + ChildHandleBuffer[Index], + &gEfiSerialIoProtocolGuid, + &SerialIo, + This->DriverBindingHandle, + Handle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (SerialIo); + + ASSERT (Private->Handle == ChildHandleBuffer[Index]); + + Status = gBS->CloseProtocol ( + Handle, + &gEfiWinNtIoProtocolGuid, + This->DriverBindingHandle, + ChildHandleBuffer[Index] + ); + + Status = gBS->UninstallMultipleProtocolInterfaces ( + ChildHandleBuffer[Index], + &gEfiSerialIoProtocolGuid, + &Private->SerialIo, + &gEfiDevicePathProtocolGuid, + Private->DevicePath, + NULL + ); + + if (EFI_ERROR (Status)) { + gBS->OpenProtocol ( + Handle, + &gEfiWinNtIoProtocolGuid, + (VOID **) &WinNtIo, + This->DriverBindingHandle, + ChildHandleBuffer[Index], + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + } else { + Private->WinNtThunk->CloseHandle (Private->NtHandle); + + gBS->FreePool (Private->DevicePath); + + FreeUnicodeStringTable (Private->ControllerNameTable); + + gBS->FreePool (Private); + } + } + + if (EFI_ERROR (Status)) { + AllChildrenStopped = FALSE; + } + } + + if (!AllChildrenStopped) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +// +// Serial IO Protocol member functions +// + +STATIC +EFI_STATUS +EFIAPI +WinNtSerialIoReset ( + IN EFI_SERIAL_IO_PROTOCOL *This + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + WIN_NT_SERIAL_IO_PRIVATE_DATA *Private; + EFI_TPL Tpl; + + Tpl = gBS->RaiseTPL (EFI_TPL_NOTIFY); + + Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This); + + Private->WinNtThunk->PurgeComm ( + Private->NtHandle, + PURGE_TXCLEAR | PURGE_RXCLEAR + ); + + gBS->RestoreTPL (Tpl); + + return This->SetAttributes ( + This, + This->Mode->BaudRate, + This->Mode->ReceiveFifoDepth, + This->Mode->Timeout, + This->Mode->Parity, + (UINT8) This->Mode->DataBits, + This->Mode->StopBits + ); +} + +STATIC +EFI_STATUS +EFIAPI +WinNtSerialIoSetAttributes ( + 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 + ) +/*++ + +Routine Description: + + This function is used to set the attributes. + +Arguments: + + This - A pointer to the EFI_SERIAL_IO_PROTOCOL structrue. + BaudRate - The Baud rate of the serial device. + ReceiveFifoDepth - The request depth of fifo on receive side. + Timeout - the request timeout for a single charact. + Parity - The type of parity used in serial device. + DataBits - Number of deata bits used in serial device. + StopBits - Number of stop bits used in serial device. + +Returns: + Status code + + None + +--*/ +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + WIN_NT_SERIAL_IO_PRIVATE_DATA *Private; + COMMTIMEOUTS PortTimeOuts; + DWORD ConvertedTime; + BOOL Result; + EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; + EFI_TPL Tpl; + + Tpl = gBS->RaiseTPL (EFI_TPL_NOTIFY); + + Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This); + + // + // Some of our arguments have defaults if a null value is passed in, and + // we must set the default values if a null argument is passed in. + // + if (BaudRate == 0) { + BaudRate = SERIAL_BAUD_DEFAULT; + } + + if (ReceiveFifoDepth == 0) { + ReceiveFifoDepth = SERIAL_FIFO_DEFAULT; + } + + if (Timeout == 0) { + Timeout = SERIAL_TIMEOUT_DEFAULT; + } + + if (Parity == DefaultParity) { + Parity = NoParity; + } + + if (DataBits == 0) { + DataBits = SERIAL_DATABITS_DEFAULT; + } + + if (StopBits == DefaultStopBits) { + StopBits = OneStopBit; + } + // + // See if the new attributes already match the current attributes + // + if (Private->UartDevicePath.BaudRate == BaudRate && + Private->UartDevicePath.DataBits == DataBits && + Private->UartDevicePath.Parity == Parity && + Private->UartDevicePath.StopBits == StopBits && + Private->SerialIoMode.ReceiveFifoDepth == ReceiveFifoDepth && + Private->SerialIoMode.Timeout == Timeout ) { + gBS->RestoreTPL(Tpl); + return EFI_SUCCESS; + } + + // + // Get current values from NT + // + ZeroMem (&Private->NtDCB, sizeof (DCB)); + Private->NtDCB.DCBlength = sizeof (DCB); + + if (!Private->WinNtThunk->GetCommState (Private->NtHandle, &Private->NtDCB)) { + Private->NtError = Private->WinNtThunk->GetLastError (); + DEBUG ((EFI_D_ERROR, "SerialSetAttributes: GetCommState %d\n", Private->NtError)); + gBS->RestoreTPL (Tpl); + return EFI_DEVICE_ERROR; + } + + // + // Map EFI com setting to NT + // + Private->NtDCB.BaudRate = ConvertBaud2Nt (BaudRate); + Private->NtDCB.ByteSize = ConvertData2Nt (DataBits); + Private->NtDCB.Parity = ConvertParity2Nt (Parity); + Private->NtDCB.StopBits = ConvertStop2Nt (StopBits); + + Private->NtDCB.fBinary = TRUE; + Private->NtDCB.fParity = Private->NtDCB.Parity == NOPARITY ? FALSE : TRUE; + Private->NtDCB.fOutxCtsFlow = FALSE; + Private->NtDCB.fOutxDsrFlow = FALSE; + Private->NtDCB.fDtrControl = DTR_CONTROL_ENABLE; + Private->NtDCB.fDsrSensitivity = FALSE; + Private->NtDCB.fOutX = FALSE; + Private->NtDCB.fInX = FALSE; + Private->NtDCB.fRtsControl = RTS_CONTROL_ENABLE; + Private->NtDCB.fNull = FALSE; + + // + // Set new values + // + Result = Private->WinNtThunk->SetCommState (Private->NtHandle, &Private->NtDCB); + if (!Result) { + Private->NtError = Private->WinNtThunk->GetLastError (); + DEBUG ((EFI_D_ERROR, "SerialSetAttributes: SetCommState %d\n", Private->NtError)); + gBS->RestoreTPL (Tpl); + return EFI_DEVICE_ERROR; + } + + // + // Set com port read/write timeout values + // + ConvertedTime = ConvertTime2Nt (Timeout); + PortTimeOuts.ReadIntervalTimeout = MAXDWORD; + PortTimeOuts.ReadTotalTimeoutMultiplier = 0; + PortTimeOuts.ReadTotalTimeoutConstant = ConvertedTime; + PortTimeOuts.WriteTotalTimeoutMultiplier = ConvertedTime == 0 ? 1 : ConvertedTime; + PortTimeOuts.WriteTotalTimeoutConstant = 0; + + if (!Private->WinNtThunk->SetCommTimeouts (Private->NtHandle, &PortTimeOuts)) { + Private->NtError = Private->WinNtThunk->GetLastError (); + DEBUG ((EFI_D_ERROR, "SerialSetAttributes: SetCommTimeouts %d\n", Private->NtError)); + gBS->RestoreTPL (Tpl); + return EFI_DEVICE_ERROR; + } + + // + // Update mode + // + Private->SerialIoMode.BaudRate = BaudRate; + Private->SerialIoMode.ReceiveFifoDepth = ReceiveFifoDepth; + Private->SerialIoMode.Timeout = Timeout; + Private->SerialIoMode.Parity = Parity; + Private->SerialIoMode.DataBits = DataBits; + Private->SerialIoMode.StopBits = StopBits; + + // + // See if Device Path Node has actually changed + // + if (Private->UartDevicePath.BaudRate == BaudRate && + Private->UartDevicePath.DataBits == DataBits && + Private->UartDevicePath.Parity == Parity && + Private->UartDevicePath.StopBits == StopBits ) { + gBS->RestoreTPL(Tpl); + return EFI_SUCCESS; + } + + // + // Update the device path + // + Private->UartDevicePath.BaudRate = BaudRate; + Private->UartDevicePath.DataBits = DataBits; + Private->UartDevicePath.Parity = (UINT8) Parity; + Private->UartDevicePath.StopBits = (UINT8) StopBits; + + NewDevicePath = AppendDevicePathNode ( + Private->ParentDevicePath, + (EFI_DEVICE_PATH_PROTOCOL *) &Private->UartDevicePath + ); + if (NewDevicePath == NULL) { + gBS->RestoreTPL (Tpl); + return EFI_DEVICE_ERROR; + } + + if (Private->Handle != NULL) { + Status = gBS->ReinstallProtocolInterface ( + Private->Handle, + &gEfiDevicePathProtocolGuid, + Private->DevicePath, + NewDevicePath + ); + if (EFI_ERROR (Status)) { + gBS->RestoreTPL (Tpl); + return Status; + } + } + + if (Private->DevicePath != NULL) { + gBS->FreePool (Private->DevicePath); + } + + Private->DevicePath = NewDevicePath; + + gBS->RestoreTPL (Tpl); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +WinNtSerialIoSetControl ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN UINT32 Control + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Control - TODO: add argument description + +Returns: + + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + WIN_NT_SERIAL_IO_PRIVATE_DATA *Private; + BOOL Result; + DCB Dcb; + EFI_TPL Tpl; + + Tpl = gBS->RaiseTPL (EFI_TPL_NOTIFY); + + Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This); + + Result = Private->WinNtThunk->GetCommState (Private->NtHandle, &Dcb); + + if (!Result) { + Private->NtError = Private->WinNtThunk->GetLastError (); + DEBUG ((EFI_D_ERROR, "SerialSetControl: GetCommState %d\n", Private->NtError)); + gBS->RestoreTPL (Tpl); + return EFI_DEVICE_ERROR; + } + + Dcb.fRtsControl = RTS_CONTROL_DISABLE; + Dcb.fDtrControl = DTR_CONTROL_DISABLE; + Private->HardwareFlowControl = FALSE; + Private->SoftwareLoopbackEnable = FALSE; + Private->HardwareLoopbackEnable = FALSE; + + if (Control & EFI_SERIAL_REQUEST_TO_SEND) { + Dcb.fRtsControl = RTS_CONTROL_ENABLE; + } + + if (Control & EFI_SERIAL_DATA_TERMINAL_READY) { + Dcb.fDtrControl = DTR_CONTROL_ENABLE; + } + + if (Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) { + Private->HardwareFlowControl = TRUE; + } + + if (Control & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) { + Private->SoftwareLoopbackEnable = TRUE; + } + + if (Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) { + Private->HardwareLoopbackEnable = TRUE; + } + + Result = Private->WinNtThunk->SetCommState ( + Private->NtHandle, + &Dcb + ); + + if (!Result) { + Private->NtError = Private->WinNtThunk->GetLastError (); + DEBUG ((EFI_D_ERROR, "SerialSetControl: SetCommState %d\n", Private->NtError)); + gBS->RestoreTPL (Tpl); + return EFI_DEVICE_ERROR; + } + + gBS->RestoreTPL (Tpl); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +WinNtSerialIoGetControl ( + IN EFI_SERIAL_IO_PROTOCOL *This, + OUT UINT32 *Control + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Control - TODO: add argument description + +Returns: + + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + WIN_NT_SERIAL_IO_PRIVATE_DATA *Private; + DWORD ModemStatus; + DWORD Errors; + UINT32 Bits; + DCB Dcb; + EFI_TPL Tpl; + + Tpl = gBS->RaiseTPL (EFI_TPL_NOTIFY); + + Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This); + + // + // Get modem status + // + if (!Private->WinNtThunk->GetCommModemStatus (Private->NtHandle, &ModemStatus)) { + Private->NtError = Private->WinNtThunk->GetLastError (); + gBS->RestoreTPL (Tpl); + return EFI_DEVICE_ERROR; + } + + Bits = 0; + if (ModemStatus & MS_CTS_ON) { + Bits |= EFI_SERIAL_CLEAR_TO_SEND; + } + + if (ModemStatus & MS_DSR_ON) { + Bits |= EFI_SERIAL_DATA_SET_READY; + } + + if (ModemStatus & MS_RING_ON) { + Bits |= EFI_SERIAL_RING_INDICATE; + } + + if (ModemStatus & MS_RLSD_ON) { + Bits |= EFI_SERIAL_CARRIER_DETECT; + } + + // + // Get ctrl status + // + if (!Private->WinNtThunk->GetCommState (Private->NtHandle, &Dcb)) { + Private->NtError = Private->WinNtThunk->GetLastError (); + DEBUG ((EFI_D_ERROR, "SerialGetControl: GetCommState %d\n", Private->NtError)); + gBS->RestoreTPL (Tpl); + return EFI_DEVICE_ERROR; + } + + if (Dcb.fDtrControl == DTR_CONTROL_ENABLE) { + Bits |= EFI_SERIAL_DATA_TERMINAL_READY; + } + + if (Dcb.fRtsControl == RTS_CONTROL_ENABLE) { + Bits |= EFI_SERIAL_REQUEST_TO_SEND; + } + + if (Private->HardwareFlowControl) { + Bits |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE; + } + + if (Private->SoftwareLoopbackEnable) { + Bits |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE; + } + + if (Private->HardwareLoopbackEnable) { + Bits |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE; + } + + // + // Get input buffer status + // + if (!Private->WinNtThunk->ClearCommError (Private->NtHandle, &Errors, &Private->NtComStatus)) { + Private->NtError = Private->WinNtThunk->GetLastError (); + DEBUG ((EFI_D_ERROR, "SerialGetControl: ClearCommError %d\n", Private->NtError)); + gBS->RestoreTPL (Tpl); + return EFI_DEVICE_ERROR; + } + + if (Private->NtComStatus.cbInQue == 0) { + Bits |= EFI_SERIAL_INPUT_BUFFER_EMPTY; + } + + *Control = Bits; + + gBS->RestoreTPL (Tpl); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +WinNtSerialIoWrite ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + BufferSize - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + WIN_NT_SERIAL_IO_PRIVATE_DATA *Private; + UINT8 *ByteBuffer; + UINTN TotalBytesWritten; + DWORD BytesToGo; + DWORD BytesWritten; + BOOL Result; + UINT32 Index; + UINT32 Control; + EFI_TPL Tpl; + + Tpl = gBS->RaiseTPL (EFI_TPL_NOTIFY); + + Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This); + + ByteBuffer = (UINT8 *) Buffer; + TotalBytesWritten = 0; + + if (Private->SoftwareLoopbackEnable || Private->HardwareLoopbackEnable) { + for (Index = 0; Index < *BufferSize; Index++) { + if (IsaSerialFifoAdd (&Private->Fifo, ByteBuffer[Index]) == EFI_SUCCESS) { + TotalBytesWritten++; + } else { + break; + } + } + } else { + BytesToGo = (DWORD) (*BufferSize); + + do { + if (Private->HardwareFlowControl) { + // + // Send RTS + // + WinNtSerialIoGetControl (&Private->SerialIo, &Control); + Control |= EFI_SERIAL_REQUEST_TO_SEND; + WinNtSerialIoSetControl (&Private->SerialIo, Control); + } + + // + // Do the write + // + Result = Private->WinNtThunk->WriteFile ( + Private->NtHandle, + &ByteBuffer[TotalBytesWritten], + BytesToGo, + &BytesWritten, + NULL + ); + + if (Private->HardwareFlowControl) { + // + // Assert RTS + // + WinNtSerialIoGetControl (&Private->SerialIo, &Control); + Control &= ~ (UINT32) EFI_SERIAL_REQUEST_TO_SEND; + WinNtSerialIoSetControl (&Private->SerialIo, Control); + } + + TotalBytesWritten += BytesWritten; + BytesToGo -= BytesWritten; + if (!Result) { + Private->NtError = Private->WinNtThunk->GetLastError (); + DEBUG ((EFI_D_ERROR, "SerialWrite: FileWrite %d\n", Private->NtError)); + *BufferSize = TotalBytesWritten; + gBS->RestoreTPL (Tpl); + return EFI_DEVICE_ERROR; + } + } while (BytesToGo > 0); + } + + *BufferSize = TotalBytesWritten; + + gBS->RestoreTPL (Tpl); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +WinNtSerialIoRead ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + BufferSize - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + EFI_DEVICE_ERROR - TODO: Add description for return value + +--*/ +{ + WIN_NT_SERIAL_IO_PRIVATE_DATA *Private; + BOOL Result; + DWORD BytesRead; + EFI_STATUS Status; + UINT32 Index; + UINT8 Data; + UINT32 Control; + EFI_TPL Tpl; + + Tpl = gBS->RaiseTPL (EFI_TPL_NOTIFY); + + Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This); + + // + // Do the read + // + if (Private->SoftwareLoopbackEnable || Private->HardwareLoopbackEnable) { + for (Index = 0, BytesRead = 0; Index < *BufferSize; Index++) { + if (IsaSerialFifoRemove (&Private->Fifo, &Data) == EFI_SUCCESS) { + ((UINT8 *) Buffer)[Index] = Data; + BytesRead++; + } else { + break; + } + } + } else { + if (Private->HardwareFlowControl) { + WinNtSerialIoGetControl (&Private->SerialIo, &Control); + Control |= EFI_SERIAL_DATA_TERMINAL_READY; + WinNtSerialIoSetControl (&Private->SerialIo, Control); + } + + Result = Private->WinNtThunk->ReadFile ( + Private->NtHandle, + Buffer, + (DWORD) *BufferSize, + &BytesRead, + NULL + ); + + if (Private->HardwareFlowControl) { + WinNtSerialIoGetControl (&Private->SerialIo, &Control); + Control &= ~ (UINT32) EFI_SERIAL_DATA_TERMINAL_READY; + WinNtSerialIoSetControl (&Private->SerialIo, Control); + } + + if (!Result) { + Private->NtError = Private->WinNtThunk->GetLastError (); + gBS->RestoreTPL (Tpl); + return EFI_DEVICE_ERROR; + } + } + + if (BytesRead != *BufferSize) { + Status = EFI_TIMEOUT; + } else { + Status = EFI_SUCCESS; + } + + *BufferSize = (UINTN) BytesRead; + + gBS->RestoreTPL (Tpl); + + return Status; +} + +BOOLEAN +IsaSerialFifoFull ( + IN SERIAL_DEV_FIFO *Fifo + ) +/*++ + + Routine Description: + Detect whether specific FIFO is full or not + + Arguments: + Fifo SERIAL_DEV_FIFO *: A pointer to the Data Structure SERIAL_DEV_FIFO + + Returns: + TRUE: the FIFO is full + FALSE: the FIFO is not full + +--*/ +{ + if (Fifo->Surplus == 0) { + return TRUE; + } + + return FALSE; +} + +BOOLEAN +IsaSerialFifoEmpty ( + IN SERIAL_DEV_FIFO *Fifo + ) +/*++ + + Routine Description: + Detect whether specific FIFO is empty or not + + Arguments: + Fifo SERIAL_DEV_FIFO *: A pointer to the Data Structure SERIAL_DEV_FIFO + + Returns: + TRUE: the FIFO is empty + FALSE: the FIFO is not empty + +--*/ +{ + if (Fifo->Surplus == SERIAL_MAX_BUFFER_SIZE) { + return TRUE; + } + + return FALSE; +} + +EFI_STATUS +IsaSerialFifoAdd ( + IN SERIAL_DEV_FIFO *Fifo, + IN UINT8 Data + ) +/*++ + + Routine Description: + Add data to specific FIFO + + Arguments: + Fifo SERIAL_DEV_FIFO *: A pointer to the Data Structure SERIAL_DEV_FIFO + Data UINT8: the data added to FIFO + + Returns: + EFI_SUCCESS: Add data to specific FIFO successfully + EFI_OUT_RESOURCE: Failed to add data because FIFO is already full + +--*/ +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +{ + // + // if FIFO full can not add data + // + if (IsaSerialFifoFull (Fifo)) { + return EFI_OUT_OF_RESOURCES; + } + + // + // FIFO is not full can add data + // + Fifo->Data[Fifo->Last] = Data; + Fifo->Surplus--; + Fifo->Last++; + if (Fifo->Last >= SERIAL_MAX_BUFFER_SIZE) { + Fifo->Last = 0; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +IsaSerialFifoRemove ( + IN SERIAL_DEV_FIFO *Fifo, + OUT UINT8 *Data + ) +/*++ + + Routine Description: + Remove data from specific FIFO + + Arguments: + Fifo SERIAL_DEV_FIFO *: A pointer to the Data Structure SERIAL_DEV_FIFO + Data UINT8*: the data removed from FIFO + + Returns: + EFI_SUCCESS: Remove data from specific FIFO successfully + EFI_OUT_RESOURCE: Failed to remove data because FIFO is empty + +--*/ +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +{ + // + // if FIFO is empty, no data can remove + // + if (IsaSerialFifoEmpty (Fifo)) { + return EFI_OUT_OF_RESOURCES; + } + + // + // FIFO is not empty, can remove data + // + *Data = Fifo->Data[Fifo->First]; + Fifo->Surplus++; + Fifo->First++; + if (Fifo->First >= SERIAL_MAX_BUFFER_SIZE) { + Fifo->First = 0; + } + + return EFI_SUCCESS; +} diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SerialIo/WinNtSerialIo.h b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SerialIo/WinNtSerialIo.h new file mode 100644 index 0000000000..79e905c5ad --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SerialIo/WinNtSerialIo.h @@ -0,0 +1,513 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + WinNtSerialIo.h + +Abstract: + + +--*/ + +#ifndef _WIN_NT_SERIAL_IO_ +#define _WIN_NT_SERIAL_IO_ + + + +#define SERIAL_MAX_BUFFER_SIZE 256 +#define TIMEOUT_STALL_INTERVAL 10 + +typedef struct { + UINT32 First; + UINT32 Last; + UINT32 Surplus; + UINT8 Data[SERIAL_MAX_BUFFER_SIZE]; +} SERIAL_DEV_FIFO; + +#define WIN_NT_SERIAL_IO_PRIVATE_DATA_SIGNATURE EFI_SIGNATURE_32 ('N', 'T', 's', 'i') +typedef struct { + UINT64 Signature; + + // + // Protocol data for the new handle we are going to add + // + EFI_HANDLE Handle; + EFI_SERIAL_IO_PROTOCOL SerialIo; + EFI_SERIAL_IO_MODE SerialIoMode; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + // + // Private Data + // + EFI_HANDLE ControllerHandle; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + UART_DEVICE_PATH UartDevicePath; + EFI_WIN_NT_THUNK_PROTOCOL *WinNtThunk; + + EFI_UNICODE_STRING_TABLE *ControllerNameTable; + + // + // Private NT type Data; + // + HANDLE NtHandle; + DCB NtDCB; + DWORD NtError; + COMSTAT NtComStatus; + + BOOLEAN SoftwareLoopbackEnable; + BOOLEAN HardwareFlowControl; + BOOLEAN HardwareLoopbackEnable; + + SERIAL_DEV_FIFO Fifo; + +} WIN_NT_SERIAL_IO_PRIVATE_DATA; + +#define WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS(a) \ + CR(a, WIN_NT_SERIAL_IO_PRIVATE_DATA, SerialIo, WIN_NT_SERIAL_IO_PRIVATE_DATA_SIGNATURE) + +// +// Global Protocol Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gWinNtSerialIoDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gWinNtSerialIoComponentName; + +// +// Macros to convert EFI serial types to NT serial types. +// + +// +// one second +// +#define SERIAL_TIMEOUT_DEFAULT (1000 * 1000) +#define SERIAL_BAUD_DEFAULT 115200 +#define SERIAL_FIFO_DEFAULT 14 +#define SERIAL_DATABITS_DEFAULT 8 +#define SERIAL_PARITY_DEFAULT DefaultParity +#define SERIAL_STOPBITS_DEFAULT DefaultStopBits + +#define SERIAL_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_INPUT_BUFFER_EMPTY) + +#define ConvertBaud2Nt(x) (DWORD) x +#define ConvertData2Nt(x) (BYTE) x + +#define ConvertParity2Nt(x) \ + (BYTE) ( \ + x == DefaultParity ? NOPARITY : \ + x == NoParity ? NOPARITY : \ + x == EvenParity ? EVENPARITY : \ + x == OddParity ? ODDPARITY : \ + x == MarkParity ? MARKPARITY : \ + x == SpaceParity ? SPACEPARITY : 0 \ + ) + +#define ConvertStop2Nt(x) \ + (BYTE) ( \ + x == DefaultParity ? ONESTOPBIT : \ + x == OneFiveStopBits ? ONE5STOPBITS : \ + x == TwoStopBits ? TWOSTOPBITS : 0 \ + ) + +#define ConvertTime2Nt(x) ((x) / 1000) + +// +// 115400 baud with rounding errors +// +#define SERIAL_PORT_MAX_BAUD_RATE 115400 + +// +// Function Prototypes +// +EFI_STATUS +EFIAPI +InitializeWinNtSerialIo ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ImageHandle - TODO: add argument description + SystemTable - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +STATIC +EFI_STATUS +EFIAPI +WinNtSerialIoDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Handle - TODO: add argument description + RemainingDevicePath - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +STATIC +EFI_STATUS +EFIAPI +WinNtSerialIoDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Handle - TODO: add argument description + RemainingDevicePath - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +STATIC +EFI_STATUS +EFIAPI +WinNtSerialIoDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Handle - TODO: add argument description + NumberOfChildren - TODO: add argument description + ChildHandleBuffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +STATIC +EFI_STATUS +EFIAPI +WinNtSerialIoReset ( + IN EFI_SERIAL_IO_PROTOCOL *This + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +STATIC +EFI_STATUS +EFIAPI +WinNtSerialIoSetAttributes ( + 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 + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + BaudRate - TODO: add argument description + ReceiveFifoDepth - TODO: add argument description + Timeout - TODO: add argument description + Parity - TODO: add argument description + DataBits - TODO: add argument description + StopBits - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +STATIC +EFI_STATUS +EFIAPI +WinNtSerialIoSetControl ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN UINT32 Control + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Control - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +STATIC +EFI_STATUS +EFIAPI +WinNtSerialIoGetControl ( + IN EFI_SERIAL_IO_PROTOCOL *This, + OUT UINT32 *Control + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Control - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +STATIC +EFI_STATUS +EFIAPI +WinNtSerialIoWrite ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + BufferSize - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +STATIC +EFI_STATUS +EFIAPI +WinNtSerialIoRead ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + BufferSize - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +IsaSerialFifoFull ( + IN SERIAL_DEV_FIFO *Fifo + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Fifo - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +IsaSerialFifoEmpty ( + IN SERIAL_DEV_FIFO *Fifo + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Fifo - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +IsaSerialFifoAdd ( + IN SERIAL_DEV_FIFO *Fifo, + IN UINT8 Data + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Fifo - TODO: add argument description + Data - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +IsaSerialFifoRemove ( + IN SERIAL_DEV_FIFO *Fifo, + OUT UINT8 *Data + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Fifo - TODO: add argument description + Data - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +IsaSerialReceiveTransmit ( + WIN_NT_SERIAL_IO_PRIVATE_DATA *Private + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SerialIo/WinNtSerialIo.mbd b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SerialIo/WinNtSerialIo.mbd new file mode 100644 index 0000000000..a5b19f99c4 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SerialIo/WinNtSerialIo.mbd @@ -0,0 +1,42 @@ + + + + + WinNtSerialIo + 6B41B553-A649-11d4-BD02-0080C73C8881 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-13 17:02 + 2006-03-19 15:17 + + + UefiBootServicesTableLib + BaseLib + UefiLib + UefiMemoryLib + UefiDriverEntryPoint + UefiDriverModelLib + UefiDebugLibStdErr + BasePrintLib + DxeMemoryAllocationLib + UefiDevicePathLib + + diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SerialIo/WinNtSerialIo.msa b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SerialIo/WinNtSerialIo.msa new file mode 100644 index 0000000000..cf987e2230 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SerialIo/WinNtSerialIo.msa @@ -0,0 +1,74 @@ + + + + + WinNtSerialIo + UEFI_DRIVER + BS_DRIVER + 6B41B553-A649-11d4-BD02-0080C73C8881 + 0 + Component description file for WinNtSerialIo module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-13 17:02 + 2006-03-19 15:17 + + + DebugLib + BaseLib + UefiDriverModelLib + UefiDriverEntryPoint + UefiLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + DevicePathLib + + + WinNtSerialIo.h + WinNtSerialIo.c + ComponentName.c + + + MdePkg + EdkModulePkg + EdkNt32Pkg + + + WinNtIo + DevicePath + SerialIo + + + + WinNtSerialPort + + + + + + + + gWinNtSerialIoDriverBinding + gWinNtSerialIoComponentName + + + diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SerialIo/build.xml b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SerialIo/build.xml new file mode 100644 index 0000000000..7114d3bae2 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SerialIo/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SimpleFileSystem/ComponentName.c b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SimpleFileSystem/ComponentName.c new file mode 100644 index 0000000000..de4abd73e7 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SimpleFileSystem/ComponentName.c @@ -0,0 +1,193 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ComponentName.c + +Abstract: + +--*/ + +#include "WinNtSimpleFileSystem.h" + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +WinNtSimpleFileSystemComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +EFI_STATUS +EFIAPI +WinNtSimpleFileSystemComponentNameGetControllerName ( + 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 +// +EFI_COMPONENT_NAME_PROTOCOL gWinNtSimpleFileSystemComponentName = { + WinNtSimpleFileSystemComponentNameGetDriverName, + WinNtSimpleFileSystemComponentNameGetControllerName, + "eng" +}; + +static EFI_UNICODE_STRING_TABLE mWinNtSimpleFileSystemDriverNameTable[] = { + { + "eng", + L"Windows Simple File System Driver" + }, + { + NULL, + NULL + } +}; + +EFI_STATUS +EFIAPI +WinNtSimpleFileSystemComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gWinNtSimpleFileSystemComponentName.SupportedLanguages, + mWinNtSimpleFileSystemDriverNameTable, + DriverName + ); +} + +EFI_STATUS +EFIAPI +WinNtSimpleFileSystemComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + 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. + 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. + + Returns: + 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. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + EFI_STATUS Status; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem; + WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *Private; + + // + // This is a device driver, so ChildHandle must be NULL. + // + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + + // + // Get our context back + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiSimpleFileSystemProtocolGuid, + &SimpleFileSystem, + gWinNtSimpleFileSystemDriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Private = WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (SimpleFileSystem); + + return LookupUnicodeString ( + Language, + gWinNtSimpleFileSystemComponentName.SupportedLanguages, + Private->ControllerNameTable, + ControllerName + ); +} diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SimpleFileSystem/WinNtSimpleFileSystem.c b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SimpleFileSystem/WinNtSimpleFileSystem.c new file mode 100644 index 0000000000..5552bc28be --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SimpleFileSystem/WinNtSimpleFileSystem.c @@ -0,0 +1,2615 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + WinNtSimpleFileSystem.c + +Abstract: + + Produce Simple File System abstractions for directories on your PC using Win32 APIs. + The configuration of what devices to mount or emulate comes from NT + environment variables. The variables must be visible to the Microsoft* + Developer Studio for them to work. + + * Other names and brands may be claimed as the property of others. + +--*/ + +#include "WinNtSimpleFileSystem.h" + +EFI_DRIVER_BINDING_PROTOCOL gWinNtSimpleFileSystemDriverBinding = { + WinNtSimpleFileSystemDriverBindingSupported, + WinNtSimpleFileSystemDriverBindingStart, + WinNtSimpleFileSystemDriverBindingStop, + 0x10, + NULL, + NULL +}; + + +CHAR16 * +EfiStrChr ( + IN CHAR16 *Str, + IN CHAR16 Chr + ) +/*++ + +Routine Description: + + Locate the first occurance of a character in a string. + +Arguments: + + Str - Pointer to NULL terminated unicode string. + Chr - Character to locate. + +Returns: + + If Str is NULL, then NULL is returned. + If Chr is not contained in Str, then NULL is returned. + If Chr is contained in Str, then a pointer to the first occurance of Chr in Str is returned. + +--*/ +{ + if (Str == NULL) { + return Str; + } + + while (*Str != '\0' && *Str != Chr) { + ++Str; + } + + return (*Str == Chr) ? Str : NULL; +} + +BOOLEAN +IsZero ( + IN VOID *Buffer, + IN UINTN Length + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Buffer - TODO: add argument description + Length - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + if (Buffer == NULL || Length == 0) { + return FALSE; + } + + if (*(UINT8 *) Buffer != 0) { + return FALSE; + } + + if (Length > 1) { + if (!CompareMem (Buffer, (UINT8 *) Buffer + 1, Length - 1)) { + return FALSE; + } + } + + return TRUE; +} + +VOID +CutPrefix ( + IN CHAR16 *Str, + IN UINTN Count + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Str - TODO: add argument description + Count - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + CHAR16 *Pointer; + + if (StrLen (Str) < Count) { + ASSERT (0); + } + + for (Pointer = Str; *(Pointer + Count); Pointer++) { + *Pointer = *(Pointer + Count); + } + + *Pointer = *(Pointer + Count); +} + + + +EFI_STATUS +EFIAPI +WinNtSimpleFileSystemDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + Check to see if the driver supports a given controller. + +Arguments: + + This - A pointer to an instance of the EFI_DRIVER_BINDING_PROTOCOL. + + ControllerHandle - EFI handle of the controller to test. + + RemainingDevicePath - Pointer to remaining portion of a device path. + +Returns: + + EFI_SUCCESS - The device specified by ControllerHandle and RemainingDevicePath is supported by the driver + specified by This. + + EFI_ALREADY_STARTED - The device specified by ControllerHandle and RemainingDevicePath is already being managed by + the driver specified by This. + + 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. + + EFI_UNSUPPORTED - The device specified by ControllerHandle and RemainingDevicePath is not supported by the + driver specified by This. + +--*/ +{ + EFI_STATUS Status; + EFI_WIN_NT_IO_PROTOCOL *WinNtIo; + + // + // Open the IO Abstraction(s) needed to perform the supported test + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiWinNtIoProtocolGuid, + &WinNtIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Make sure GUID is for a File System handle. + // + Status = EFI_UNSUPPORTED; + if (CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtFileSystemGuid)) { + Status = EFI_SUCCESS; + } + + // + // Close the I/O Abstraction(s) used to perform the supported test + // + gBS->CloseProtocol ( + ControllerHandle, + &gEfiWinNtIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + + return Status; +} + +EFI_STATUS +EFIAPI +WinNtSimpleFileSystemDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + Starts a device controller or a bus controller. + +Arguments: + + This - A pointer to an instance of the EFI_DRIVER_BINDING_PROTOCOL. + + ControllerHandle - EFI handle of the controller to start. + + RemainingDevicePath - Pointer to remaining portion of a device path. + +Returns: + + EFI_SUCCESS - The device or bus controller has been started. + + EFI_DEVICE_ERROR - The device could not be started due to a device failure. + + EFI_OUT_OF_RESOURCES - The request could not be completed due to lack of resources. + +--*/ +{ + EFI_STATUS Status; + EFI_WIN_NT_IO_PROTOCOL *WinNtIo; + WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *Private; + + Private = NULL; + + // + // Open the IO Abstraction(s) needed + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiWinNtIoProtocolGuid, + &WinNtIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Validate GUID + // + if (!CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtFileSystemGuid)) { + Status = EFI_UNSUPPORTED; + goto Done; + } + + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE), + &Private + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + Private->Signature = WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE; + Private->WinNtThunk = WinNtIo->WinNtThunk; + + Private->FilePath = WinNtIo->EnvString; + + Private->VolumeLabel = NULL; + Status = gBS->AllocatePool ( + EfiBootServicesData, + StrSize (L"EFI_EMULATED"), + &Private->VolumeLabel + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + + StrCpy (Private->VolumeLabel, L"EFI_EMULATED"); + + Private->SimpleFileSystem.Revision = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION; + Private->SimpleFileSystem.OpenVolume = WinNtSimpleFileSystemOpenVolume; + + Private->WinNtThunk->SetErrorMode (SEM_FAILCRITICALERRORS); + + Private->ControllerNameTable = NULL; + + AddUnicodeString ( + "eng", + gWinNtSimpleFileSystemComponentName.SupportedLanguages, + &Private->ControllerNameTable, + WinNtIo->EnvString + ); + + Status = gBS->InstallMultipleProtocolInterfaces ( + &ControllerHandle, + &gEfiSimpleFileSystemProtocolGuid, + &Private->SimpleFileSystem, + NULL + ); + +Done: + if (EFI_ERROR (Status)) { + + if (Private != NULL) { + + FreeUnicodeStringTable (Private->ControllerNameTable); + + gBS->FreePool (Private); + } + + gBS->CloseProtocol ( + ControllerHandle, + &gEfiWinNtIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + } + + return Status; +} + +EFI_STATUS +EFIAPI +WinNtSimpleFileSystemDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - A pointer to an instance of the EFI_DRIVER_BINDING_PROTOCOL. + + ControllerHandle - A handle to the device to be stopped. + + NumberOfChildren - The number of child device handles in ChildHandleBuffer. + + ChildHandleBuffer - An array of child device handles to be freed. + +Returns: + + EFI_SUCCESS - The device has been stopped. + + EFI_DEVICE_ERROR - The device could not be stopped due to a device failure. + +--*/ +// TODO: EFI_UNSUPPORTED - add return value to function comment +{ + EFI_STATUS Status; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem; + WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *Private; + + // + // Get our context back + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiSimpleFileSystemProtocolGuid, + &SimpleFileSystem, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Private = WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (SimpleFileSystem); + + // + // Uninstall the Simple File System Protocol from ControllerHandle + // + Status = gBS->UninstallMultipleProtocolInterfaces ( + ControllerHandle, + &gEfiSimpleFileSystemProtocolGuid, + &Private->SimpleFileSystem, + NULL + ); + if (!EFI_ERROR (Status)) { + Status = gBS->CloseProtocol ( + ControllerHandle, + &gEfiWinNtIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + } + + if (!EFI_ERROR (Status)) { + // + // Free our instance data + // + FreeUnicodeStringTable (Private->ControllerNameTable); + + gBS->FreePool (Private); + } + + return Status; +} + +EFI_STATUS +EFIAPI +WinNtSimpleFileSystemOpenVolume ( + IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This, + OUT EFI_FILE **Root + ) +/*++ + +Routine Description: + + Open the root directory on a volume. + +Arguments: + + This - A pointer to the volume to open. + + Root - A pointer to storage for the returned opened file handle of the root directory. + +Returns: + + EFI_SUCCESS - The volume was opened. + + EFI_UNSUPPORTED - The volume does not support the requested file system type. + + EFI_NO_MEDIA - The device has no media. + + EFI_DEVICE_ERROR - The device reported an error. + + EFI_VOLUME_CORRUPTED - The file system structures are corrupted. + + EFI_ACCESS_DENIED - The service denied access to the file. + + EFI_OUT_OF_RESOURCES - The file volume could not be opened due to lack of resources. + + EFI_MEDIA_CHANGED - The device has new media or the media is no longer supported. + +--*/ +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +{ + EFI_STATUS Status; + WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *Private; + WIN_NT_EFI_FILE_PRIVATE *PrivateFile; + + if (This == NULL || Root == NULL) { + return EFI_INVALID_PARAMETER; + } + + Private = WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (This); + + PrivateFile = NULL; + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (WIN_NT_EFI_FILE_PRIVATE), + &PrivateFile + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + PrivateFile->FileName = NULL; + Status = gBS->AllocatePool ( + EfiBootServicesData, + StrSize (Private->FilePath), + &PrivateFile->FileName + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + PrivateFile->FilePath = NULL; + Status = gBS->AllocatePool ( + EfiBootServicesData, + StrSize (Private->FilePath), + &PrivateFile->FilePath + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + StrCpy (PrivateFile->FilePath, Private->FilePath); + StrCpy (PrivateFile->FileName, PrivateFile->FilePath); + PrivateFile->Signature = WIN_NT_EFI_FILE_PRIVATE_SIGNATURE; + PrivateFile->WinNtThunk = Private->WinNtThunk; + PrivateFile->SimpleFileSystem = This; + PrivateFile->IsRootDirectory = TRUE; + PrivateFile->IsDirectoryPath = TRUE; + PrivateFile->IsOpenedByRead = TRUE; + PrivateFile->EfiFile.Revision = EFI_FILE_HANDLE_REVISION; + PrivateFile->EfiFile.Open = WinNtSimpleFileSystemOpen; + PrivateFile->EfiFile.Close = WinNtSimpleFileSystemClose; + PrivateFile->EfiFile.Delete = WinNtSimpleFileSystemDelete; + PrivateFile->EfiFile.Read = WinNtSimpleFileSystemRead; + PrivateFile->EfiFile.Write = WinNtSimpleFileSystemWrite; + PrivateFile->EfiFile.GetPosition = WinNtSimpleFileSystemGetPosition; + PrivateFile->EfiFile.SetPosition = WinNtSimpleFileSystemSetPosition; + PrivateFile->EfiFile.GetInfo = WinNtSimpleFileSystemGetInfo; + PrivateFile->EfiFile.SetInfo = WinNtSimpleFileSystemSetInfo; + PrivateFile->EfiFile.Flush = WinNtSimpleFileSystemFlush; + PrivateFile->LHandle = INVALID_HANDLE_VALUE; + PrivateFile->DirHandle = INVALID_HANDLE_VALUE; + PrivateFile->IsValidFindBuf = FALSE; + + *Root = &PrivateFile->EfiFile; + + Status = EFI_SUCCESS; + +Done: + if (EFI_ERROR (Status)) { + if (PrivateFile) { + if (PrivateFile->FileName) { + gBS->FreePool (PrivateFile->FileName); + } + + if (PrivateFile->FilePath) { + gBS->FreePool (PrivateFile->FilePath); + } + + gBS->FreePool (PrivateFile); + } + } + + return Status; +} + +EFI_STATUS +EFIAPI +WinNtSimpleFileSystemOpen ( + IN EFI_FILE *This, + OUT EFI_FILE **NewHandle, + IN CHAR16 *FileName, + IN UINT64 OpenMode, + IN UINT64 Attributes + ) +/*++ + +Routine Description: + + Open a file relative to the source file location. + +Arguments: + + This - A pointer to the source file location. + + NewHandle - Pointer to storage for the new file handle. + + FileName - Pointer to the file name to be opened. + + OpenMode - File open mode information. + + Attributes - File creation attributes. + +Returns: + + EFI_SUCCESS - The file was opened. + + EFI_NOT_FOUND - The file could not be found in the volume. + + EFI_NO_MEDIA - The device has no media. + + EFI_MEDIA_CHANGED - The device has new media or the media is no longer supported. + + EFI_DEVICE_ERROR - The device reported an error. + + EFI_VOLUME_CORRUPTED - The file system structures are corrupted. + + EFI_WRITE_PROTECTED - The volume or file is write protected. + + EFI_ACCESS_DENIED - The service denied access to the file. + + EFI_OUT_OF_RESOURCES - Not enough resources were available to open the file. + + EFI_VOLUME_FULL - There is not enough space left to create the new file. + +--*/ +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +{ + EFI_FILE *Root; + WIN_NT_EFI_FILE_PRIVATE *PrivateFile; + WIN_NT_EFI_FILE_PRIVATE *NewPrivateFile; + WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot; + EFI_STATUS Status; + CHAR16 *RealFileName; + CHAR16 *TempFileName; + CHAR16 *ParseFileName; + CHAR16 *GuardPointer; + CHAR16 TempChar; + DWORD LastError; + UINTN Count; + BOOLEAN TrailingDash; + BOOLEAN LoopFinish; + UINTN InfoSize; + EFI_FILE_INFO *Info; + + TrailingDash = FALSE; + + // + // Check for obvious invalid parameters. + // + if (This == NULL || NewHandle == NULL || FileName == NULL) { + return EFI_INVALID_PARAMETER; + } + + switch (OpenMode) { + case EFI_FILE_MODE_CREATE | EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE: + if (Attributes &~EFI_FILE_VALID_ATTR) { + return EFI_INVALID_PARAMETER; + } + + if (Attributes & EFI_FILE_READ_ONLY) { + return EFI_INVALID_PARAMETER; + } + + // + // fall through + // + case EFI_FILE_MODE_READ: + case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE: + break; + + default: + return EFI_INVALID_PARAMETER; + } + + // + // + // + PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); + PrivateRoot = WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem); + NewPrivateFile = NULL; + + // + // BUGBUG: assume an open of root + // if current location, return current data + // + if (StrCmp (FileName, L"\\") == 0 || (StrCmp (FileName, L".") == 0 && PrivateFile->IsRootDirectory)) { + // + // BUGBUG: assume an open root + // +OpenRoot: + Status = WinNtSimpleFileSystemOpenVolume (PrivateFile->SimpleFileSystem, &Root); + NewPrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (Root); + goto Done; + } + + if (FileName[StrLen (FileName) - 1] == L'\\') { + TrailingDash = TRUE; + FileName[StrLen (FileName) - 1] = 0; + } + + // + // Attempt to open the file + // + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (WIN_NT_EFI_FILE_PRIVATE), + &NewPrivateFile + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + + CopyMem (NewPrivateFile, PrivateFile, sizeof (WIN_NT_EFI_FILE_PRIVATE)); + + NewPrivateFile->FilePath = NULL; + + Status = gBS->AllocatePool ( + EfiBootServicesData, + StrSize (PrivateFile->FileName), + &NewPrivateFile->FilePath + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + + if (PrivateFile->IsDirectoryPath) { + StrCpy (NewPrivateFile->FilePath, PrivateFile->FileName); + } else { + StrCpy (NewPrivateFile->FilePath, PrivateFile->FilePath); + } + + NewPrivateFile->FileName = NULL; + Status = gBS->AllocatePool ( + EfiBootServicesData, + StrSize (NewPrivateFile->FilePath) + StrSize (L"\\") + StrSize (FileName), + &NewPrivateFile->FileName + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + + if (*FileName == L'\\') { + StrCpy (NewPrivateFile->FileName, PrivateRoot->FilePath); + StrCat (NewPrivateFile->FileName, L"\\"); + StrCat (NewPrivateFile->FileName, FileName + 1); + } else { + StrCpy (NewPrivateFile->FileName, NewPrivateFile->FilePath); + StrCat (NewPrivateFile->FileName, L"\\"); + StrCat (NewPrivateFile->FileName, FileName); + } + + // + // Get rid of . and .., except leading . or .. + // + + // + // GuardPointer protect simplefilesystem root path not be destroyed + // + GuardPointer = NewPrivateFile->FileName + StrLen (PrivateRoot->FilePath); + + LoopFinish = FALSE; + + while (!LoopFinish) { + + LoopFinish = TRUE; + + for (ParseFileName = GuardPointer; *ParseFileName; ParseFileName++) { + if (*ParseFileName == L'.' && + (*(ParseFileName + 1) == 0 || *(ParseFileName + 1) == L'\\') && + *(ParseFileName - 1) == L'\\' + ) { + + // + // cut \. + // + CutPrefix (ParseFileName - 1, 2); + LoopFinish = FALSE; + break; + } + + if (*ParseFileName == L'.' && + *(ParseFileName + 1) == L'.' && + (*(ParseFileName + 2) == 0 || *(ParseFileName + 2) == L'\\') && + *(ParseFileName - 1) == L'\\' + ) { + + ParseFileName--; + Count = 3; + + while (ParseFileName != GuardPointer) { + ParseFileName--; + Count++; + if (*ParseFileName == L'\\') { + break; + } + } + + // + // cut \.. and its left directory + // + CutPrefix (ParseFileName, Count); + LoopFinish = FALSE; + break; + } + } + } + + if (StrCmp (NewPrivateFile->FileName, PrivateRoot->FilePath) == 0) { + NewPrivateFile->IsRootDirectory = TRUE; + gBS->FreePool (NewPrivateFile->FilePath); + gBS->FreePool (NewPrivateFile->FileName); + gBS->FreePool (NewPrivateFile); + goto OpenRoot; + } + + RealFileName = NewPrivateFile->FileName; + while (EfiStrChr (RealFileName, L'\\') != NULL) { + RealFileName = EfiStrChr (RealFileName, L'\\') + 1; + } + + TempChar = *(RealFileName - 1); + *(RealFileName - 1) = 0; + + gBS->FreePool (NewPrivateFile->FilePath); + NewPrivateFile->FilePath = NULL; + Status = gBS->AllocatePool ( + EfiBootServicesData, + StrSize (NewPrivateFile->FileName), + &NewPrivateFile->FilePath + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + + StrCpy (NewPrivateFile->FilePath, NewPrivateFile->FileName); + + *(RealFileName - 1) = TempChar; + + NewPrivateFile->IsRootDirectory = FALSE; + + // + // Test whether file or directory + // + if (OpenMode & EFI_FILE_MODE_CREATE) { + if (Attributes & EFI_FILE_DIRECTORY) { + NewPrivateFile->IsDirectoryPath = TRUE; + } else { + NewPrivateFile->IsDirectoryPath = FALSE; + } + } else { + NewPrivateFile->LHandle = INVALID_HANDLE_VALUE; + NewPrivateFile->LHandle = NewPrivateFile->WinNtThunk->CreateFile ( + NewPrivateFile->FileName, + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL + ); + + if (NewPrivateFile->LHandle != INVALID_HANDLE_VALUE) { + NewPrivateFile->IsDirectoryPath = FALSE; + NewPrivateFile->WinNtThunk->CloseHandle (NewPrivateFile->LHandle); + } else { + NewPrivateFile->IsDirectoryPath = TRUE; + } + + NewPrivateFile->LHandle = INVALID_HANDLE_VALUE; + } + + if (OpenMode & EFI_FILE_MODE_WRITE) { + NewPrivateFile->IsOpenedByRead = FALSE; + } else { + NewPrivateFile->IsOpenedByRead = TRUE; + } + + Status = EFI_SUCCESS; + + // + // deal with directory + // + if (NewPrivateFile->IsDirectoryPath) { + + Status = gBS->AllocatePool ( + EfiBootServicesData, + StrSize (NewPrivateFile->FileName) + StrSize (L"\\*"), + &TempFileName + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + + StrCpy (TempFileName, NewPrivateFile->FileName); + + if ((OpenMode & EFI_FILE_MODE_CREATE)) { + // + // Create a directory + // + if (!NewPrivateFile->WinNtThunk->CreateDirectory (TempFileName, NULL)) { + + LastError = PrivateFile->WinNtThunk->GetLastError (); + if (LastError != ERROR_ALREADY_EXISTS) { + gBS->FreePool (TempFileName); + Status = EFI_ACCESS_DENIED; + goto Done; + } + } + } + + NewPrivateFile->DirHandle = NewPrivateFile->WinNtThunk->CreateFile ( + TempFileName, + NewPrivateFile->IsOpenedByRead ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE), + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL + ); + + if (NewPrivateFile->DirHandle == INVALID_HANDLE_VALUE) { + + NewPrivateFile->DirHandle = NewPrivateFile->WinNtThunk->CreateFile ( + TempFileName, + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL + ); + + if (NewPrivateFile->DirHandle != INVALID_HANDLE_VALUE) { + NewPrivateFile->WinNtThunk->CloseHandle (NewPrivateFile->DirHandle); + NewPrivateFile->DirHandle = INVALID_HANDLE_VALUE; + Status = EFI_ACCESS_DENIED; + } else { + Status = EFI_NOT_FOUND; + } + + goto Done; + } + + // + // Find the first file under it + // + StrCat (TempFileName, L"\\*"); + NewPrivateFile->LHandle = NewPrivateFile->WinNtThunk->FindFirstFile (TempFileName, &NewPrivateFile->FindBuf); + + if (NewPrivateFile->LHandle == INVALID_HANDLE_VALUE) { + NewPrivateFile->IsValidFindBuf = FALSE; + } else { + NewPrivateFile->IsValidFindBuf = TRUE; + } + } else { + // + // deal with file + // + if (!NewPrivateFile->IsOpenedByRead) { + NewPrivateFile->LHandle = NewPrivateFile->WinNtThunk->CreateFile ( + NewPrivateFile->FileName, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + (OpenMode & EFI_FILE_MODE_CREATE) ? OPEN_ALWAYS : OPEN_EXISTING, + 0, + NULL + ); + + if (NewPrivateFile->LHandle == INVALID_HANDLE_VALUE) { + NewPrivateFile->LHandle = NewPrivateFile->WinNtThunk->CreateFile ( + NewPrivateFile->FileName, + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL + ); + + if (NewPrivateFile->LHandle == INVALID_HANDLE_VALUE) { + Status = EFI_NOT_FOUND; + } else { + Status = EFI_ACCESS_DENIED; + NewPrivateFile->WinNtThunk->CloseHandle (NewPrivateFile->LHandle); + NewPrivateFile->LHandle = INVALID_HANDLE_VALUE; + } + } + } else { + NewPrivateFile->LHandle = NewPrivateFile->WinNtThunk->CreateFile ( + NewPrivateFile->FileName, + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL + ); + + if (NewPrivateFile->LHandle == INVALID_HANDLE_VALUE) { + Status = EFI_NOT_FOUND; + } + } + } + + if ((OpenMode & EFI_FILE_MODE_CREATE) && Status == EFI_SUCCESS) { + // + // Set the attribute + // + InfoSize = 0; + Info = NULL; + + Status = WinNtSimpleFileSystemGetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, &InfoSize, Info); + + if (Status != EFI_BUFFER_TOO_SMALL) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + + Status = gBS->AllocatePool ( + EfiBootServicesData, + InfoSize, + &Info + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = WinNtSimpleFileSystemGetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, &InfoSize, Info); + + if (EFI_ERROR (Status)) { + goto Done; + } + + Info->Attribute = Attributes; + + WinNtSimpleFileSystemSetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, InfoSize, Info); + } + +Done: ; + if (TrailingDash) { + FileName[StrLen (FileName) + 1] = 0; + FileName[StrLen (FileName)] = L'\\'; + } + + if (EFI_ERROR (Status)) { + if (NewPrivateFile) { + if (NewPrivateFile->FileName) { + gBS->FreePool (NewPrivateFile->FileName); + } + + if (NewPrivateFile->FilePath) { + gBS->FreePool (NewPrivateFile->FilePath); + } + + gBS->FreePool (NewPrivateFile); + } + } else { + *NewHandle = &NewPrivateFile->EfiFile; + } + + return Status; +} + +EFI_STATUS +EFIAPI +WinNtSimpleFileSystemClose ( + IN EFI_FILE *This + ) +/*++ + +Routine Description: + + Close the specified file handle. + +Arguments: + + This - Pointer to a returned opened file handle. + +Returns: + + EFI_SUCCESS - The file handle has been closed. + +--*/ +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +{ + WIN_NT_EFI_FILE_PRIVATE *PrivateFile; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); + + if (PrivateFile->LHandle != INVALID_HANDLE_VALUE) { + if (PrivateFile->IsDirectoryPath) { + PrivateFile->WinNtThunk->FindClose (PrivateFile->LHandle); + } else { + PrivateFile->WinNtThunk->CloseHandle (PrivateFile->LHandle); + } + + PrivateFile->LHandle = INVALID_HANDLE_VALUE; + } + + if (PrivateFile->IsDirectoryPath && PrivateFile->DirHandle != INVALID_HANDLE_VALUE) { + PrivateFile->WinNtThunk->CloseHandle (PrivateFile->DirHandle); + PrivateFile->DirHandle = INVALID_HANDLE_VALUE; + } + + if (PrivateFile->FileName) { + gBS->FreePool (PrivateFile->FileName); + } + + gBS->FreePool (PrivateFile); + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +WinNtSimpleFileSystemDelete ( + IN EFI_FILE *This + ) +/*++ + +Routine Description: + + Close and delete a file. + +Arguments: + + This - Pointer to a returned opened file handle. + +Returns: + + EFI_SUCCESS - The file handle was closed and deleted. + + EFI_WARN_DELETE_FAILURE - The handle was closed but could not be deleted. + +--*/ +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +{ + EFI_STATUS Status; + WIN_NT_EFI_FILE_PRIVATE *PrivateFile; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); + + Status = EFI_WARN_DELETE_FAILURE; + + if (PrivateFile->IsDirectoryPath) { + if (PrivateFile->LHandle != INVALID_HANDLE_VALUE) { + PrivateFile->WinNtThunk->FindClose (PrivateFile->LHandle); + } + + if (PrivateFile->DirHandle != INVALID_HANDLE_VALUE) { + PrivateFile->WinNtThunk->CloseHandle (PrivateFile->DirHandle); + PrivateFile->DirHandle = INVALID_HANDLE_VALUE; + } + + if (PrivateFile->WinNtThunk->RemoveDirectory (PrivateFile->FileName)) { + Status = EFI_SUCCESS; + } + } else { + PrivateFile->WinNtThunk->CloseHandle (PrivateFile->LHandle); + PrivateFile->LHandle = INVALID_HANDLE_VALUE; + + if (!PrivateFile->IsOpenedByRead) { + if (PrivateFile->WinNtThunk->DeleteFile (PrivateFile->FileName)) { + Status = EFI_SUCCESS; + } + } + } + + gBS->FreePool (PrivateFile->FileName); + gBS->FreePool (PrivateFile); + + return Status; +} + +STATIC +VOID +WinNtSystemTimeToEfiTime ( + IN SYSTEMTIME *SystemTime, + IN TIME_ZONE_INFORMATION *TimeZone, + OUT EFI_TIME *Time + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SystemTime - TODO: add argument description + TimeZone - TODO: add argument description + Time - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + Time->Year = (UINT16) SystemTime->wYear; + Time->Month = (UINT8) SystemTime->wMonth; + Time->Day = (UINT8) SystemTime->wDay; + Time->Hour = (UINT8) SystemTime->wHour; + Time->Minute = (UINT8) SystemTime->wMinute; + Time->Second = (UINT8) SystemTime->wSecond; + Time->Nanosecond = (UINT32) SystemTime->wMilliseconds * 1000000; + Time->TimeZone = (INT16) TimeZone->Bias; + + if (TimeZone->StandardDate.wMonth) { + Time->Daylight = EFI_TIME_ADJUST_DAYLIGHT; + } +} + +EFI_STATUS +EFIAPI +WinNtSimpleFileSystemRead ( + IN EFI_FILE *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Read data from a file. + +Arguments: + + This - Pointer to a returned open file handle. + + BufferSize - On input, the size of the Buffer. On output, the number of bytes stored in the Buffer. + + Buffer - Pointer to the first byte of the read Buffer. + +Returns: + + EFI_SUCCESS - The data was read. + + EFI_NO_MEDIA - The device has no media. + + EFI_DEVICE_ERROR - The device reported an error. + + EFI_VOLUME_CORRUPTED - The file system structures are corrupted. + + EFI_BUFFER_TOO_SMALL - The supplied buffer size was too small to store the current directory entry. + *BufferSize has been updated with the size needed to complete the request. + +--*/ +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +{ + WIN_NT_EFI_FILE_PRIVATE *PrivateFile; + EFI_STATUS Status; + UINTN Size; + UINTN NameSize; + UINTN ResultSize; + UINTN Index; + SYSTEMTIME SystemTime; + EFI_FILE_INFO *Info; + WCHAR *pw; + TIME_ZONE_INFORMATION TimeZone; + EFI_FILE_INFO *FileInfo; + UINT64 Pos; + UINT64 FileSize; + UINTN FileInfoSize; + + if (This == NULL || BufferSize == NULL || Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); + + if (PrivateFile->LHandle == INVALID_HANDLE_VALUE) { + return EFI_DEVICE_ERROR; + } + + if (!PrivateFile->IsDirectoryPath) { + + if (This->GetPosition (This, &Pos) != EFI_SUCCESS) { + return EFI_DEVICE_ERROR; + } + + FileInfoSize = SIZE_OF_EFI_FILE_SYSTEM_INFO; + gBS->AllocatePool ( + EfiBootServicesData, + FileInfoSize, + &FileInfo + ); + + Status = This->GetInfo ( + This, + &gEfiFileInfoGuid, + &FileInfoSize, + FileInfo + ); + + if (Status == EFI_BUFFER_TOO_SMALL) { + gBS->FreePool (FileInfo); + gBS->AllocatePool ( + EfiBootServicesData, + FileInfoSize, + &FileInfo + ); + Status = This->GetInfo ( + This, + &gEfiFileInfoGuid, + &FileInfoSize, + FileInfo + ); + } + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + FileSize = FileInfo->FileSize; + + gBS->FreePool (FileInfo); + + if (Pos >= FileSize) { + *BufferSize = 0; + if (Pos == FileSize) { + return EFI_SUCCESS; + } else { + return EFI_DEVICE_ERROR; + } + } + + return PrivateFile->WinNtThunk->ReadFile ( + PrivateFile->LHandle, + Buffer, + *BufferSize, + BufferSize, + NULL + ) ? EFI_SUCCESS : EFI_DEVICE_ERROR; + } + + // + // Read on a directory. Perform a find next + // + if (!PrivateFile->IsValidFindBuf) { + *BufferSize = 0; + return EFI_SUCCESS; + } + + Size = SIZE_OF_EFI_FILE_INFO; + + NameSize = StrSize (PrivateFile->FindBuf.cFileName); + + ResultSize = Size + NameSize; + + Status = EFI_BUFFER_TOO_SMALL; + + if (*BufferSize >= ResultSize) { + Status = EFI_SUCCESS; + + Info = Buffer; + ZeroMem (Info, ResultSize); + + Info->Size = ResultSize; + + PrivateFile->WinNtThunk->GetTimeZoneInformation (&TimeZone); + + PrivateFile->WinNtThunk->FileTimeToLocalFileTime ( + &PrivateFile->FindBuf.ftCreationTime, + &PrivateFile->FindBuf.ftCreationTime + ); + + PrivateFile->WinNtThunk->FileTimeToSystemTime (&PrivateFile->FindBuf.ftCreationTime, &SystemTime); + + WinNtSystemTimeToEfiTime (&SystemTime, &TimeZone, &Info->CreateTime); + + PrivateFile->WinNtThunk->FileTimeToLocalFileTime ( + &PrivateFile->FindBuf.ftLastWriteTime, + &PrivateFile->FindBuf.ftLastWriteTime + ); + + PrivateFile->WinNtThunk->FileTimeToSystemTime (&PrivateFile->FindBuf.ftLastWriteTime, &SystemTime); + + WinNtSystemTimeToEfiTime (&SystemTime, &TimeZone, &Info->ModificationTime); + + Info->FileSize = PrivateFile->FindBuf.nFileSizeLow; + + Info->PhysicalSize = PrivateFile->FindBuf.nFileSizeLow; + + if (PrivateFile->FindBuf.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) { + Info->Attribute |= EFI_FILE_ARCHIVE; + } + + if (PrivateFile->FindBuf.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) { + Info->Attribute |= EFI_FILE_HIDDEN; + } + + if (PrivateFile->FindBuf.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) { + Info->Attribute |= EFI_FILE_SYSTEM; + } + + if (PrivateFile->FindBuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { + Info->Attribute |= EFI_FILE_READ_ONLY; + } + + if (PrivateFile->FindBuf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + Info->Attribute |= EFI_FILE_DIRECTORY; + } + + NameSize = NameSize / sizeof (WCHAR); + + pw = (WCHAR *) (((CHAR8 *) Buffer) + Size); + + for (Index = 0; Index < NameSize; Index++) { + pw[Index] = PrivateFile->FindBuf.cFileName[Index]; + } + + if (PrivateFile->WinNtThunk->FindNextFile (PrivateFile->LHandle, &PrivateFile->FindBuf)) { + PrivateFile->IsValidFindBuf = TRUE; + } else { + PrivateFile->IsValidFindBuf = FALSE; + } + } + + *BufferSize = ResultSize; + + return Status; +} + +EFI_STATUS +EFIAPI +WinNtSimpleFileSystemWrite ( + IN EFI_FILE *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Write data to a file. + +Arguments: + + This - Pointer to an opened file handle. + + BufferSize - On input, the number of bytes in the Buffer to write to the file. On output, the number of bytes + of data written to the file. + + Buffer - Pointer to the first by of data in the buffer to write to the file. + +Returns: + + EFI_SUCCESS - The data was written to the file. + + EFI_UNSUPPORTED - Writes to an open directory are not supported. + + EFI_NO_MEDIA - The device has no media. + + EFI_DEVICE_ERROR - The device reported an error. + + EFI_VOLUME_CORRUPTED - The file system structures are corrupt. + + EFI_WRITE_PROTECTED - The file, directory, volume, or device is write protected. + + EFI_ACCESS_DENIED - The file was opened read-only. + + EFI_VOLUME_FULL - The volume is full. + +--*/ +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +{ + WIN_NT_EFI_FILE_PRIVATE *PrivateFile; + + if (This == NULL || BufferSize == NULL || Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); + + if (PrivateFile->LHandle == INVALID_HANDLE_VALUE) { + return EFI_DEVICE_ERROR; + } + + if (PrivateFile->IsDirectoryPath) { + return EFI_UNSUPPORTED; + } + + if (PrivateFile->IsOpenedByRead) { + return EFI_ACCESS_DENIED; + } + + return PrivateFile->WinNtThunk->WriteFile ( + PrivateFile->LHandle, + Buffer, + *BufferSize, + BufferSize, + NULL + ) ? EFI_SUCCESS : EFI_DEVICE_ERROR; + + // + // bugbug: need to access windows error reporting + // +} + +EFI_STATUS +EFIAPI +WinNtSimpleFileSystemSetPosition ( + IN EFI_FILE *This, + IN UINT64 Position + ) +/*++ + +Routine Description: + + Set a file's current position. + +Arguments: + + This - Pointer to an opened file handle. + + Position - The byte position from the start of the file to set. + +Returns: + + EFI_SUCCESS - The file position has been changed. + + EFI_UNSUPPORTED - The seek request for non-zero is not supported for directories. + +--*/ +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +{ + EFI_STATUS Status; + WIN_NT_EFI_FILE_PRIVATE *PrivateFile; + UINT32 PosLow; + UINT32 PosHigh; + CHAR16 *FileName; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); + + if (PrivateFile->IsDirectoryPath) { + if (Position != 0) { + return EFI_UNSUPPORTED; + } + + Status = gBS->AllocatePool ( + EfiBootServicesData, + StrSize (PrivateFile->FileName) + StrSize (L"\\*"), + &FileName + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + StrCpy (FileName, PrivateFile->FileName); + StrCat (FileName, L"\\*"); + + if (PrivateFile->LHandle != INVALID_HANDLE_VALUE) { + PrivateFile->WinNtThunk->FindClose (PrivateFile->LHandle); + } + + PrivateFile->LHandle = PrivateFile->WinNtThunk->FindFirstFile (FileName, &PrivateFile->FindBuf); + + if (PrivateFile->LHandle == INVALID_HANDLE_VALUE) { + PrivateFile->IsValidFindBuf = FALSE; + } else { + PrivateFile->IsValidFindBuf = TRUE; + } + + gBS->FreePool (FileName); + + Status = (PrivateFile->LHandle == INVALID_HANDLE_VALUE) ? EFI_DEVICE_ERROR : EFI_SUCCESS; + } else { + if (Position == (UINT64) -1) { + PosLow = PrivateFile->WinNtThunk->SetFilePointer (PrivateFile->LHandle, (ULONG) 0, NULL, FILE_END); + } else { + PosHigh = (UINT32) RShiftU64 (Position, 32); + + PosLow = PrivateFile->WinNtThunk->SetFilePointer (PrivateFile->LHandle, (ULONG) Position, &PosHigh, FILE_BEGIN); + } + + Status = (PosLow == 0xFFFFFFFF) ? EFI_DEVICE_ERROR : EFI_SUCCESS; + } + + return Status; +} + +EFI_STATUS +EFIAPI +WinNtSimpleFileSystemGetPosition ( + IN EFI_FILE *This, + OUT UINT64 *Position + ) +/*++ + +Routine Description: + + Get a file's current position. + +Arguments: + + This - Pointer to an opened file handle. + + Position - Pointer to storage for the current position. + +Returns: + + EFI_SUCCESS - The file position has been reported. + + EFI_UNSUPPORTED - Not valid for directories. + +--*/ +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +{ + EFI_STATUS Status; + WIN_NT_EFI_FILE_PRIVATE *PrivateFile; + INT32 PositionHigh; + UINT64 PosHigh64; + + if (This == NULL || Position == NULL) { + return EFI_INVALID_PARAMETER; + } + + PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); + + PositionHigh = 0; + PosHigh64 = 0; + + if (PrivateFile->IsDirectoryPath) { + + return EFI_UNSUPPORTED; + + } else { + + PositionHigh = 0; + *Position = PrivateFile->WinNtThunk->SetFilePointer ( + PrivateFile->LHandle, + 0, + &PositionHigh, + FILE_CURRENT + ); + + Status = *Position == 0xffffffff ? EFI_DEVICE_ERROR : EFI_SUCCESS; + if (EFI_ERROR (Status)) { + goto Done; + } + + PosHigh64 = PositionHigh; + *Position += LShiftU64 (PosHigh64, 32); + } + +Done: + return Status; +} + +STATIC +EFI_STATUS +WinNtSimpleFileSystemFileInfo ( + IN WIN_NT_EFI_FILE_PRIVATE *PrivateFile, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PrivateFile - TODO: add argument description + BufferSize - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + EFI_STATUS Status; + UINTN Size; + UINTN NameSize; + UINTN ResultSize; + EFI_FILE_INFO *Info; + BY_HANDLE_FILE_INFORMATION FileInfo; + SYSTEMTIME SystemTime; + CHAR16 *RealFileName; + CHAR16 *TempPointer; + + Size = SIZE_OF_EFI_FILE_INFO; + NameSize = StrSize (PrivateFile->FileName); + ResultSize = Size + NameSize; + + Status = EFI_BUFFER_TOO_SMALL; + if (*BufferSize >= ResultSize) { + Status = EFI_SUCCESS; + + Info = Buffer; + ZeroMem (Info, ResultSize); + + Info->Size = ResultSize; + PrivateFile->WinNtThunk->GetFileInformationByHandle ( + PrivateFile->IsDirectoryPath ? PrivateFile->DirHandle : PrivateFile->LHandle, + &FileInfo + ); + Info->FileSize = FileInfo.nFileSizeLow; + Info->PhysicalSize = Info->FileSize; + + PrivateFile->WinNtThunk->FileTimeToSystemTime (&FileInfo.ftCreationTime, &SystemTime); + Info->CreateTime.Year = SystemTime.wYear; + Info->CreateTime.Month = (UINT8) SystemTime.wMonth; + Info->CreateTime.Day = (UINT8) SystemTime.wDay; + Info->CreateTime.Hour = (UINT8) SystemTime.wHour; + Info->CreateTime.Minute = (UINT8) SystemTime.wMinute; + Info->CreateTime.Second = (UINT8) SystemTime.wSecond; + + PrivateFile->WinNtThunk->FileTimeToSystemTime (&FileInfo.ftLastAccessTime, &SystemTime); + Info->LastAccessTime.Year = SystemTime.wYear; + Info->LastAccessTime.Month = (UINT8) SystemTime.wMonth; + Info->LastAccessTime.Day = (UINT8) SystemTime.wDay; + Info->LastAccessTime.Hour = (UINT8) SystemTime.wHour; + Info->LastAccessTime.Minute = (UINT8) SystemTime.wMinute; + Info->LastAccessTime.Second = (UINT8) SystemTime.wSecond; + + PrivateFile->WinNtThunk->FileTimeToSystemTime (&FileInfo.ftLastWriteTime, &SystemTime); + Info->ModificationTime.Year = SystemTime.wYear; + Info->ModificationTime.Month = (UINT8) SystemTime.wMonth; + Info->ModificationTime.Day = (UINT8) SystemTime.wDay; + Info->ModificationTime.Hour = (UINT8) SystemTime.wHour; + Info->ModificationTime.Minute = (UINT8) SystemTime.wMinute; + Info->ModificationTime.Second = (UINT8) SystemTime.wSecond; + + if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) { + Info->Attribute |= EFI_FILE_ARCHIVE; + } + + if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) { + Info->Attribute |= EFI_FILE_HIDDEN; + } + + if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { + Info->Attribute |= EFI_FILE_READ_ONLY; + } + + if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) { + Info->Attribute |= EFI_FILE_SYSTEM; + } + + if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + Info->Attribute |= EFI_FILE_DIRECTORY; + } + + if (PrivateFile->IsDirectoryPath) { + Info->Attribute |= EFI_FILE_DIRECTORY; + } + + RealFileName = PrivateFile->FileName; + TempPointer = RealFileName; + + while (*TempPointer) { + if (*TempPointer == '\\') { + RealFileName = TempPointer + 1; + } + + TempPointer++; + } + + if (PrivateFile->IsRootDirectory) { + *((CHAR8 *) Buffer + Size) = 0; + } else { + CopyMem ((CHAR8 *) Buffer + Size, RealFileName, NameSize); + } + } + + *BufferSize = ResultSize; + return Status; +} + +EFI_STATUS +EFIAPI +WinNtSimpleFileSystemGetInfo ( + IN EFI_FILE *This, + IN EFI_GUID *InformationType, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Return information about a file or volume. + +Arguments: + + This - Pointer to an opened file handle. + + InformationType - GUID describing the type of information to be returned. + + BufferSize - On input, the size of the information buffer. On output, the number of bytes written to the + information buffer. + + Buffer - Pointer to the first byte of the information buffer. + +Returns: + + EFI_SUCCESS - The requested information has been written into the buffer. + + EFI_UNSUPPORTED - The InformationType is not known. + + EFI_NO_MEDIA - The device has no media. + + EFI_DEVICE_ERROR - The device reported an error. + + EFI_VOLUME_CORRUPTED - The file system structures are corrupt. + + EFI_BUFFER_TOO_SMALL - The buffer size was too small to contain the requested information. The buffer size has + been updated with the size needed to complete the requested operation. + +--*/ +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +{ + EFI_STATUS Status; + WIN_NT_EFI_FILE_PRIVATE *PrivateFile; + EFI_FILE_SYSTEM_INFO *FileSystemInfoBuffer; + UINT32 SectorsPerCluster; + UINT32 BytesPerSector; + UINT32 FreeClusters; + UINT32 TotalClusters; + UINT32 BytesPerCluster; + CHAR16 *DriveName; + BOOLEAN DriveNameFound; + BOOL NtStatus; + UINTN Index; + WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot; + + if (This == NULL || InformationType == NULL || BufferSize == NULL) { + return EFI_INVALID_PARAMETER; + } + + PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); + PrivateRoot = WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem); + + Status = EFI_UNSUPPORTED; + + if (CompareGuid (InformationType, &gEfiFileInfoGuid)) { + Status = WinNtSimpleFileSystemFileInfo (PrivateFile, BufferSize, Buffer); + } + + if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) { + if (*BufferSize < SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel)) { + *BufferSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel); + return EFI_BUFFER_TOO_SMALL; + } + + FileSystemInfoBuffer = (EFI_FILE_SYSTEM_INFO *) Buffer; + FileSystemInfoBuffer->Size = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel); + FileSystemInfoBuffer->ReadOnly = FALSE; + + // + // Try to get the drive name + // + DriveName = NULL; + DriveNameFound = FALSE; + Status = gBS->AllocatePool ( + EfiBootServicesData, + StrSize (PrivateFile->FilePath) + 1, + &DriveName + ); + if (EFI_ERROR (Status)) { + return Status; + } + + StrCpy (DriveName, PrivateFile->FilePath); + for (Index = 0; DriveName[Index] != 0 && DriveName[Index] != ':'; Index++) { + ; + } + + if (DriveName[Index] == ':') { + DriveName[Index + 1] = '\\'; + DriveName[Index + 2] = 0; + DriveNameFound = TRUE; + } else if (DriveName[0] == '\\' && DriveName[1] == '\\') { + for (Index = 2; DriveName[Index] != 0 && DriveName[Index] != '\\'; Index++) { + ; + } + + if (DriveName[Index] == '\\') { + DriveNameFound = TRUE; + for (Index++; DriveName[Index] != 0 && DriveName[Index] != '\\'; Index++) { + ; + } + + DriveName[Index] = '\\'; + DriveName[Index + 1] = 0; + } + } + + // + // Try GetDiskFreeSpace first + // + NtStatus = PrivateFile->WinNtThunk->GetDiskFreeSpace ( + DriveNameFound ? DriveName : NULL, + &SectorsPerCluster, + &BytesPerSector, + &FreeClusters, + &TotalClusters + ); + if (DriveName) { + gBS->FreePool (DriveName); + } + + if (NtStatus) { + // + // Succeeded + // + BytesPerCluster = BytesPerSector * SectorsPerCluster; + FileSystemInfoBuffer->VolumeSize = MultU64x32 (TotalClusters, BytesPerCluster); + FileSystemInfoBuffer->FreeSpace = MultU64x32 (FreeClusters, BytesPerCluster); + FileSystemInfoBuffer->BlockSize = BytesPerCluster; + + } else { + // + // try GetDiskFreeSpaceEx then + // + FileSystemInfoBuffer->BlockSize = 0; + NtStatus = PrivateFile->WinNtThunk->GetDiskFreeSpaceEx ( + PrivateFile->FilePath, + (PULARGE_INTEGER) (&FileSystemInfoBuffer->FreeSpace), + (PULARGE_INTEGER) (&FileSystemInfoBuffer->VolumeSize), + NULL + ); + if (!NtStatus) { + return EFI_DEVICE_ERROR; + } + } + + StrCpy ((CHAR16 *) FileSystemInfoBuffer->VolumeLabel, PrivateRoot->VolumeLabel); + *BufferSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel); + Status = EFI_SUCCESS; + } + + if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) { + if (*BufferSize < StrSize (PrivateRoot->VolumeLabel)) { + *BufferSize = StrSize (PrivateRoot->VolumeLabel); + return EFI_BUFFER_TOO_SMALL; + } + + StrCpy ((CHAR16 *) Buffer, PrivateRoot->VolumeLabel); + *BufferSize = StrSize (PrivateRoot->VolumeLabel); + Status = EFI_SUCCESS; + } + + return Status; +} + +EFI_STATUS +EFIAPI +WinNtSimpleFileSystemSetInfo ( + IN EFI_FILE *This, + IN EFI_GUID *InformationType, + IN UINTN BufferSize, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Set information about a file or volume. + +Arguments: + + This - Pointer to an opened file handle. + + InformationType - GUID identifying the type of information to set. + + BufferSize - Number of bytes of data in the information buffer. + + Buffer - Pointer to the first byte of data in the information buffer. + +Returns: + + EFI_SUCCESS - The file or volume information has been updated. + + EFI_UNSUPPORTED - The information identifier is not recognised. + + EFI_NO_MEDIA - The device has no media. + + EFI_DEVICE_ERROR - The device reported an error. + + EFI_VOLUME_CORRUPTED - The file system structures are corrupt. + + EFI_WRITE_PROTECTED - The file, directory, volume, or device is write protected. + + EFI_ACCESS_DENIED - The file was opened read-only. + + EFI_VOLUME_FULL - The volume is full. + + EFI_BAD_BUFFER_SIZE - The buffer size is smaller than the type indicated by InformationType. + +--*/ +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +{ + WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot; + WIN_NT_EFI_FILE_PRIVATE *PrivateFile; + EFI_FILE_INFO *OldFileInfo; + EFI_FILE_INFO *NewFileInfo; + EFI_STATUS Status; + UINTN OldInfoSize; + INTN NtStatus; + UINT32 NewAttr; + UINT32 OldAttr; + CHAR16 *OldFileName; + CHAR16 *NewFileName; + CHAR16 *TempFileName; + CHAR16 *CharPointer; + BOOLEAN AttrChangeFlag; + BOOLEAN NameChangeFlag; + BOOLEAN SizeChangeFlag; + BOOLEAN TimeChangeFlag; + UINT64 CurPos; + SYSTEMTIME NewCreationSystemTime; + SYSTEMTIME NewLastAccessSystemTime; + SYSTEMTIME NewLastWriteSystemTime; + FILETIME NewCreationFileTime; + FILETIME NewLastAccessFileTime; + FILETIME NewLastWriteFileTime; + WIN32_FIND_DATA FindBuf; + EFI_FILE_SYSTEM_INFO *NewFileSystemInfo; + + // + // Check for invalid parameters. + // + if (This == NULL || InformationType == NULL || BufferSize == 0 || Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Initialise locals. + // + PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); + PrivateRoot = WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem); + + Status = EFI_UNSUPPORTED; + OldFileInfo = NewFileInfo = NULL; + OldFileName = NewFileName = NULL; + AttrChangeFlag = NameChangeFlag = SizeChangeFlag = TimeChangeFlag = FALSE; + + // + // Set file system information. + // + if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) { + if (BufferSize < SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel)) { + return EFI_BAD_BUFFER_SIZE; + } + + NewFileSystemInfo = (EFI_FILE_SYSTEM_INFO *) Buffer; + + gBS->FreePool (PrivateRoot->VolumeLabel); + + PrivateRoot->VolumeLabel = NULL; + Status = gBS->AllocatePool ( + EfiBootServicesData, + StrSize (NewFileSystemInfo->VolumeLabel), + &PrivateRoot->VolumeLabel + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + + StrCpy (PrivateRoot->VolumeLabel, NewFileSystemInfo->VolumeLabel); + + return EFI_SUCCESS; + } + + // + // Set volume label information. + // + if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) { + if (BufferSize < StrSize (PrivateRoot->VolumeLabel)) { + return EFI_BAD_BUFFER_SIZE; + } + + StrCpy (PrivateRoot->VolumeLabel, (CHAR16 *) Buffer); + + return EFI_SUCCESS; + } + + if (!CompareGuid (InformationType, &gEfiFileInfoGuid)) { + return EFI_UNSUPPORTED; + } + + if (BufferSize < SIZE_OF_EFI_FILE_INFO) { + return EFI_BAD_BUFFER_SIZE; + } + + // + // Set file/directory information. + // + + // + // Check for invalid set file information parameters. + // + NewFileInfo = (EFI_FILE_INFO *) Buffer; + + if (NewFileInfo->Size <= sizeof (EFI_FILE_INFO) || + (NewFileInfo->Attribute &~(EFI_FILE_VALID_ATTR)) || + (sizeof (UINTN) == 4 && NewFileInfo->Size > 0xFFFFFFFF) + ) { + return EFI_INVALID_PARAMETER; + } + + // + // bugbug: - This is not safe. We need something like EfiStrMaxSize() + // that would have an additional parameter that would be the size + // of the string array just in case there are no NULL characters in + // the string array. + // + // + // Get current file information so we can determine what kind + // of change request this is. + // + OldInfoSize = 0; + Status = WinNtSimpleFileSystemFileInfo (PrivateFile, &OldInfoSize, NULL); + + if (Status != EFI_BUFFER_TOO_SMALL) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + + Status = gBS->AllocatePool (EfiBootServicesData, OldInfoSize, &OldFileInfo); + + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = WinNtSimpleFileSystemFileInfo (PrivateFile, &OldInfoSize, OldFileInfo); + + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = gBS->AllocatePool ( + EfiBootServicesData, + StrSize (PrivateFile->FileName), + &OldFileName + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + + StrCpy (OldFileName, PrivateFile->FileName); + + // + // Make full pathname from new filename and rootpath. + // + if (NewFileInfo->FileName[0] == '\\') { + Status = gBS->AllocatePool ( + EfiBootServicesData, + StrSize (PrivateRoot->FilePath) + StrSize (L"\\") + StrSize (NewFileInfo->FileName), + &NewFileName + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + + StrCpy (NewFileName, PrivateRoot->FilePath); + StrCat (NewFileName, L"\\"); + StrCat (NewFileName, NewFileInfo->FileName + 1); + } else { + Status = gBS->AllocatePool ( + EfiBootServicesData, + StrSize (PrivateFile->FilePath) + StrSize (L"\\") + StrSize (NewFileInfo->FileName), + &NewFileName + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + + StrCpy (NewFileName, PrivateFile->FilePath); + StrCat (NewFileName, L"\\"); + StrCat (NewFileName, NewFileInfo->FileName); + } + + // + // Is there an attribute change request? + // + if (NewFileInfo->Attribute != OldFileInfo->Attribute) { + if ((NewFileInfo->Attribute & EFI_FILE_DIRECTORY) != (OldFileInfo->Attribute & EFI_FILE_DIRECTORY)) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + AttrChangeFlag = TRUE; + } + + // + // Is there a name change request? + // bugbug: - Need EfiStrCaseCmp() + // + if (StrCmp (NewFileInfo->FileName, OldFileInfo->FileName)) { + NameChangeFlag = TRUE; + } + + // + // Is there a size change request? + // + if (NewFileInfo->FileSize != OldFileInfo->FileSize) { + SizeChangeFlag = TRUE; + } + + // + // Is there a time stamp change request? + // + if (!IsZero (&NewFileInfo->CreateTime, sizeof (EFI_TIME)) && + CompareMem (&NewFileInfo->CreateTime, &OldFileInfo->CreateTime, sizeof (EFI_TIME)) + ) { + TimeChangeFlag = TRUE; + } else if (!IsZero (&NewFileInfo->LastAccessTime, sizeof (EFI_TIME)) && + CompareMem (&NewFileInfo->LastAccessTime, &OldFileInfo->LastAccessTime, sizeof (EFI_TIME)) + ) { + TimeChangeFlag = TRUE; + } else if (!IsZero (&NewFileInfo->ModificationTime, sizeof (EFI_TIME)) && + CompareMem (&NewFileInfo->ModificationTime, &OldFileInfo->ModificationTime, sizeof (EFI_TIME)) + ) { + TimeChangeFlag = TRUE; + } + + // + // All done if there are no change requests being made. + // + if (!(AttrChangeFlag || NameChangeFlag || SizeChangeFlag || TimeChangeFlag)) { + Status = EFI_SUCCESS; + goto Done; + } + + // + // Set file or directory information. + // + OldAttr = PrivateFile->WinNtThunk->GetFileAttributes (OldFileName); + + // + // Name change. + // + if (NameChangeFlag) { + // + // Close the handles first + // + if (PrivateFile->IsOpenedByRead) { + Status = EFI_ACCESS_DENIED; + goto Done; + } + + for (CharPointer = NewFileName; *CharPointer != 0 && *CharPointer != L'/'; CharPointer++) { + } + + if (*CharPointer != 0) { + Status = EFI_ACCESS_DENIED; + goto Done; + } + + if (PrivateFile->LHandle != INVALID_HANDLE_VALUE) { + if (PrivateFile->IsDirectoryPath) { + PrivateFile->WinNtThunk->FindClose (PrivateFile->LHandle); + } else { + PrivateFile->WinNtThunk->CloseHandle (PrivateFile->LHandle); + PrivateFile->LHandle = INVALID_HANDLE_VALUE; + } + } + + if (PrivateFile->IsDirectoryPath && PrivateFile->DirHandle != INVALID_HANDLE_VALUE) { + PrivateFile->WinNtThunk->CloseHandle (PrivateFile->DirHandle); + PrivateFile->DirHandle = INVALID_HANDLE_VALUE; + } + + NtStatus = PrivateFile->WinNtThunk->MoveFile (OldFileName, NewFileName); + + if (NtStatus) { + // + // modify file name + // + gBS->FreePool (PrivateFile->FileName); + + Status = gBS->AllocatePool ( + EfiBootServicesData, + StrSize (NewFileName), + &PrivateFile->FileName + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + + StrCpy (PrivateFile->FileName, NewFileName); + + Status = gBS->AllocatePool ( + EfiBootServicesData, + StrSize (NewFileName) + StrSize (L"\\*"), + &TempFileName + ); + + StrCpy (TempFileName, NewFileName); + + if (!PrivateFile->IsDirectoryPath) { + PrivateFile->LHandle = PrivateFile->WinNtThunk->CreateFile ( + TempFileName, + PrivateFile->IsOpenedByRead ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL + ); + + gBS->FreePool (TempFileName); + + // + // Flush buffers just in case + // + if (PrivateFile->WinNtThunk->FlushFileBuffers (PrivateFile->LHandle) == 0) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + } else { + PrivateFile->DirHandle = PrivateFile->WinNtThunk->CreateFile ( + TempFileName, + PrivateFile->IsOpenedByRead ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL + ); + + StrCat (TempFileName, L"\\*"); + PrivateFile->LHandle = PrivateFile->WinNtThunk->FindFirstFile (TempFileName, &FindBuf); + + gBS->FreePool (TempFileName); + } + } else { +Reopen: ; + Status = EFI_DEVICE_ERROR; + + NtStatus = PrivateFile->WinNtThunk->SetFileAttributes (OldFileName, OldAttr); + + if (!NtStatus) { + goto Done; + } + + Status = gBS->AllocatePool ( + EfiBootServicesData, + StrSize (OldFileName) + StrSize (L"\\*"), + &TempFileName + ); + + StrCpy (TempFileName, OldFileName); + + if (!PrivateFile->IsDirectoryPath) { + PrivateFile->LHandle = PrivateFile->WinNtThunk->CreateFile ( + TempFileName, + PrivateFile->IsOpenedByRead ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL + ); + } else { + PrivateFile->DirHandle = PrivateFile->WinNtThunk->CreateFile ( + TempFileName, + PrivateFile->IsOpenedByRead ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL + ); + + StrCat (TempFileName, L"\\*"); + PrivateFile->LHandle = PrivateFile->WinNtThunk->FindFirstFile (TempFileName, &FindBuf); + } + + gBS->FreePool (TempFileName); + + goto Done; + + } + } + + // + // Size change + // + if (SizeChangeFlag) { + if (PrivateFile->IsDirectoryPath) { + Status = EFI_UNSUPPORTED; + goto Done; + } + + if (PrivateFile->IsOpenedByRead || OldFileInfo->Attribute & EFI_FILE_READ_ONLY) { + Status = EFI_ACCESS_DENIED; + goto Done; + } + + Status = This->GetPosition (This, &CurPos); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = This->SetPosition (This, NewFileInfo->FileSize); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (PrivateFile->WinNtThunk->SetEndOfFile (PrivateFile->LHandle) == 0) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + + Status = This->SetPosition (This, CurPos); + if (EFI_ERROR (Status)) { + goto Done; + } + } + + // + // Time change + // + if (TimeChangeFlag) { + + NewCreationSystemTime.wYear = NewFileInfo->CreateTime.Year; + NewCreationSystemTime.wMonth = NewFileInfo->CreateTime.Month; + NewCreationSystemTime.wDay = NewFileInfo->CreateTime.Day; + NewCreationSystemTime.wHour = NewFileInfo->CreateTime.Hour; + NewCreationSystemTime.wMinute = NewFileInfo->CreateTime.Minute; + NewCreationSystemTime.wSecond = NewFileInfo->CreateTime.Second; + NewCreationSystemTime.wMilliseconds = 0; + + if (!PrivateFile->WinNtThunk->SystemTimeToFileTime ( + &NewCreationSystemTime, + &NewCreationFileTime + )) { + goto Done; + } + + NewLastAccessSystemTime.wYear = NewFileInfo->LastAccessTime.Year; + NewLastAccessSystemTime.wMonth = NewFileInfo->LastAccessTime.Month; + NewLastAccessSystemTime.wDay = NewFileInfo->LastAccessTime.Day; + NewLastAccessSystemTime.wHour = NewFileInfo->LastAccessTime.Hour; + NewLastAccessSystemTime.wMinute = NewFileInfo->LastAccessTime.Minute; + NewLastAccessSystemTime.wSecond = NewFileInfo->LastAccessTime.Second; + NewLastAccessSystemTime.wMilliseconds = 0; + + if (!PrivateFile->WinNtThunk->SystemTimeToFileTime ( + &NewLastAccessSystemTime, + &NewLastAccessFileTime + )) { + goto Done; + } + + NewLastWriteSystemTime.wYear = NewFileInfo->ModificationTime.Year; + NewLastWriteSystemTime.wMonth = NewFileInfo->ModificationTime.Month; + NewLastWriteSystemTime.wDay = NewFileInfo->ModificationTime.Day; + NewLastWriteSystemTime.wHour = NewFileInfo->ModificationTime.Hour; + NewLastWriteSystemTime.wMinute = NewFileInfo->ModificationTime.Minute; + NewLastWriteSystemTime.wSecond = NewFileInfo->ModificationTime.Second; + NewLastWriteSystemTime.wMilliseconds = 0; + + if (!PrivateFile->WinNtThunk->SystemTimeToFileTime ( + &NewLastWriteSystemTime, + &NewLastWriteFileTime + )) { + goto Done; + } + + if (!PrivateFile->WinNtThunk->SetFileTime ( + PrivateFile->IsDirectoryPath ? PrivateFile->DirHandle : PrivateFile->LHandle, + &NewCreationFileTime, + &NewLastAccessFileTime, + &NewLastWriteFileTime + )) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + + } + + // + // No matter about AttrChangeFlag, Attribute must be set. + // Because operation before may cause attribute change. + // + NewAttr = OldAttr; + + if (NewFileInfo->Attribute & EFI_FILE_ARCHIVE) { + NewAttr |= FILE_ATTRIBUTE_ARCHIVE; + } else { + NewAttr &= ~FILE_ATTRIBUTE_ARCHIVE; + } + + if (NewFileInfo->Attribute & EFI_FILE_HIDDEN) { + NewAttr |= FILE_ATTRIBUTE_HIDDEN; + } else { + NewAttr &= ~FILE_ATTRIBUTE_HIDDEN; + } + + if (NewFileInfo->Attribute & EFI_FILE_SYSTEM) { + NewAttr |= FILE_ATTRIBUTE_SYSTEM; + } else { + NewAttr &= ~FILE_ATTRIBUTE_SYSTEM; + } + + if (NewFileInfo->Attribute & EFI_FILE_READ_ONLY) { + NewAttr |= FILE_ATTRIBUTE_READONLY; + } else { + NewAttr &= ~FILE_ATTRIBUTE_READONLY; + } + + NtStatus = PrivateFile->WinNtThunk->SetFileAttributes (NewFileName, NewAttr); + + if (!NtStatus) { + goto Reopen; + } + +Done: + if (OldFileInfo != NULL) { + gBS->FreePool (OldFileInfo); + } + + if (OldFileName != NULL) { + gBS->FreePool (OldFileName); + } + + if (NewFileName != NULL) { + gBS->FreePool (NewFileName); + } + + return Status; +} + +EFI_STATUS +EFIAPI +WinNtSimpleFileSystemFlush ( + IN EFI_FILE *This + ) +/*++ + +Routine Description: + + Flush all modified data to the media. + +Arguments: + + This - Pointer to an opened file handle. + +Returns: + + EFI_SUCCESS - The data has been flushed. + + EFI_NO_MEDIA - The device has no media. + + EFI_DEVICE_ERROR - The device reported an error. + + EFI_VOLUME_CORRUPTED - The file system structures have been corrupted. + + EFI_WRITE_PROTECTED - The file, directory, volume, or device is write protected. + + EFI_ACCESS_DENIED - The file was opened read-only. + + EFI_VOLUME_FULL - The volume is full. + +--*/ +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +{ + BY_HANDLE_FILE_INFORMATION FileInfo; + WIN_NT_EFI_FILE_PRIVATE *PrivateFile; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); + + if (PrivateFile->LHandle == INVALID_HANDLE_VALUE) { + return EFI_DEVICE_ERROR; + } + + if (PrivateFile->IsDirectoryPath) { + return EFI_SUCCESS; + } + + if (PrivateFile->IsOpenedByRead) { + return EFI_ACCESS_DENIED; + } + + PrivateFile->WinNtThunk->GetFileInformationByHandle (PrivateFile->LHandle, &FileInfo); + + if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { + return EFI_ACCESS_DENIED; + } + + return PrivateFile->WinNtThunk->FlushFileBuffers (PrivateFile->LHandle) ? EFI_SUCCESS : EFI_DEVICE_ERROR; + + // + // bugbug: - Use Windows error reporting. + // +} + diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SimpleFileSystem/WinNtSimpleFileSystem.h b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SimpleFileSystem/WinNtSimpleFileSystem.h new file mode 100644 index 0000000000..eeb373d7d5 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SimpleFileSystem/WinNtSimpleFileSystem.h @@ -0,0 +1,587 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + WinNtSimpleFileSystem.h + +Abstract: + + Produce Simple File System abstractions for a directory on your PC using Win32 APIs. + The configuration of what devices to mount or emulate comes from NT + environment variables. The variables must be visible to the Microsoft* + Developer Studio for them to work. + + * Other names and brands may be claimed as the property of others. + +--*/ + +#ifndef _WIN_NT_SIMPLE_FILE_SYSTEM_H_ +#define _WIN_NT_SIMPLE_FILE_SYSTEM_H_ + + + +#define WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE EFI_SIGNATURE_32 ('N', 'T', 'f', 's') + +typedef struct { + UINTN Signature; + EFI_WIN_NT_THUNK_PROTOCOL *WinNtThunk; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL SimpleFileSystem; + CHAR16 *FilePath; + CHAR16 *VolumeLabel; + EFI_UNICODE_STRING_TABLE *ControllerNameTable; +} WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE; + +#define WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS(a) \ + CR (a, \ + WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE, \ + SimpleFileSystem, \ + WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE \ + ) + +#define WIN_NT_EFI_FILE_PRIVATE_SIGNATURE EFI_SIGNATURE_32 ('l', 'o', 'f', 's') + +typedef struct { + UINTN Signature; + EFI_WIN_NT_THUNK_PROTOCOL *WinNtThunk; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem; + EFI_FILE EfiFile; + HANDLE LHandle; + HANDLE DirHandle; + BOOLEAN IsRootDirectory; + BOOLEAN IsDirectoryPath; + BOOLEAN IsOpenedByRead; + CHAR16 *FilePath; + WCHAR *FileName; + BOOLEAN IsValidFindBuf; + WIN32_FIND_DATA FindBuf; +} WIN_NT_EFI_FILE_PRIVATE; + +#define WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS(a) \ + CR (a, \ + WIN_NT_EFI_FILE_PRIVATE, \ + EfiFile, \ + WIN_NT_EFI_FILE_PRIVATE_SIGNATURE \ + ) + +// +// Global Protocol Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gWinNtSimpleFileSystemDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gWinNtSimpleFileSystemComponentName; + +// +// Driver Binding protocol member functions +// +EFI_STATUS +EFIAPI +WinNtSimpleFileSystemDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +/*++ + +Routine Description: + + Check to see if the driver supports a given controller. + +Arguments: + + This - A pointer to an instance of the EFI_DRIVER_BINDING_PROTOCOL. + + ControllerHandle - EFI handle of the controller to test. + + RemainingDevicePath - Pointer to remaining portion of a device path. + +Returns: + + EFI_SUCCESS - The device specified by ControllerHandle and RemainingDevicePath is supported by the driver + specified by This. + + EFI_ALREADY_STARTED - The device specified by ControllerHandle and RemainingDevicePath is already being managed by + the driver specified by This. + + 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. + + EFI_UNSUPPORTED - The device specified by ControllerHandle and RemainingDevicePath is not supported by the + driver specified by This. + +--*/ +; + +EFI_STATUS +EFIAPI +WinNtSimpleFileSystemDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +/*++ + +Routine Description: + + Starts a device controller or a bus controller. + +Arguments: + + This - A pointer to an instance of the EFI_DRIVER_BINDING_PROTOCOL. + + ControllerHandle - EFI handle of the controller to start. + + RemainingDevicePath - Pointer to remaining portion of a device path. + +Returns: + + EFI_SUCCESS - The device or bus controller has been started. + + EFI_DEVICE_ERROR - The device could not be started due to a device failure. + + EFI_OUT_OF_RESOURCES - The request could not be completed due to lack of resources. + +--*/ +; + +EFI_STATUS +EFIAPI +WinNtSimpleFileSystemDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer OPTIONAL + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - A pointer to an instance of the EFI_DRIVER_BINDING_PROTOCOL. + + ControllerHandle - A handle to the device to be stopped. + + NumberOfChildren - The number of child device handles in ChildHandleBuffer. + + ChildHandleBuffer - An array of child device handles to be freed. + +Returns: + + EFI_SUCCESS - The device has been stopped. + + EFI_DEVICE_ERROR - The device could not be stopped due to a device failure. + +--*/ +; + +// +// Simple File System protocol member functions +// +EFI_STATUS +EFIAPI +WinNtSimpleFileSystemOpenVolume ( + IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This, + OUT EFI_FILE **Root + ) +/*++ + +Routine Description: + + Open the root directory on a volume. + +Arguments: + + This - A pointer to the volume to open. + + Root - A pointer to storage for the returned opened file handle of the root directory. + +Returns: + + EFI_SUCCESS - The volume was opened. + + EFI_UNSUPPORTED - The volume does not support the requested file system type. + + EFI_NO_MEDIA - The device has no media. + + EFI_DEVICE_ERROR - The device reported an error. + + EFI_VOLUME_CORRUPTED - The file system structures are corrupted. + + EFI_ACCESS_DENIED - The service denied access to the file. + + EFI_OUT_OF_RESOURCES - The file volume could not be opened due to lack of resources. + + EFI_MEDIA_CHANGED - The device has new media or the media is no longer supported. + +--*/ +; + +EFI_STATUS +EFIAPI +WinNtSimpleFileSystemOpen ( + IN EFI_FILE *This, + OUT EFI_FILE **NewHandle, + IN CHAR16 *FileName, + IN UINT64 OpenMode, + IN UINT64 Attributes + ) +/*++ + +Routine Description: + + Open a file relative to the source file location. + +Arguments: + + This - A pointer to the source file location. + + NewHandle - Pointer to storage for the new file handle. + + FileName - Pointer to the file name to be opened. + + OpenMode - File open mode information. + + Attributes - File creation attributes. + +Returns: + + EFI_SUCCESS - The file was opened. + + EFI_NOT_FOUND - The file could not be found in the volume. + + EFI_NO_MEDIA - The device has no media. + + EFI_MEDIA_CHANGED - The device has new media or the media is no longer supported. + + EFI_DEVICE_ERROR - The device reported an error. + + EFI_VOLUME_CORRUPTED - The file system structures are corrupted. + + EFI_WRITE_PROTECTED - The volume or file is write protected. + + EFI_ACCESS_DENIED - The service denied access to the file. + + EFI_OUT_OF_RESOURCES - Not enough resources were available to open the file. + + EFI_VOLUME_FULL - There is not enough space left to create the new file. + +--*/ +; + +EFI_STATUS +EFIAPI +WinNtSimpleFileSystemClose ( + IN EFI_FILE *This + ) +/*++ + +Routine Description: + + Close the specified file handle. + +Arguments: + + This - Pointer to a returned opened file handle. + +Returns: + + EFI_SUCCESS - The file handle has been closed. + +--*/ +; + +EFI_STATUS +EFIAPI +WinNtSimpleFileSystemDelete ( + IN EFI_FILE *This + ) +/*++ + +Routine Description: + + Close and delete a file. + +Arguments: + + This - Pointer to a returned opened file handle. + +Returns: + + EFI_SUCCESS - The file handle was closed and deleted. + + EFI_WARN_DELETE_FAILURE - The handle was closed but could not be deleted. + +--*/ +; + +EFI_STATUS +EFIAPI +WinNtSimpleFileSystemRead ( + IN EFI_FILE *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Read data from a file. + +Arguments: + + This - Pointer to a returned open file handle. + + BufferSize - On input, the size of the Buffer. On output, the number of bytes stored in the Buffer. + + Buffer - Pointer to the first byte of the read Buffer. + +Returns: + + EFI_SUCCESS - The data was read. + + EFI_NO_MEDIA - The device has no media. + + EFI_DEVICE_ERROR - The device reported an error. + + EFI_VOLUME_CORRUPTED - The file system structures are corrupted. + + EFI_BUFFER_TOO_SMALL - The supplied buffer size was too small to store the current directory entry. + *BufferSize has been updated with the size needed to complete the request. + +--*/ +; + +EFI_STATUS +EFIAPI +WinNtSimpleFileSystemWrite ( + IN EFI_FILE *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Write data to a file. + +Arguments: + + This - Pointer to an opened file handle. + + BufferSize - On input, the number of bytes in the Buffer to write to the file. On output, the number of bytes + of data written to the file. + + Buffer - Pointer to the first by of data in the buffer to write to the file. + +Returns: + + EFI_SUCCESS - The data was written to the file. + + EFI_UNSUPPORTED - Writes to an open directory are not supported. + + EFI_NO_MEDIA - The device has no media. + + EFI_DEVICE_ERROR - The device reported an error. + + EFI_VOLUME_CORRUPTED - The file system structures are corrupt. + + EFI_WRITE_PROTECTED - The file, directory, volume, or device is write protected. + + EFI_ACCESS_DENIED - The file was opened read-only. + + EFI_VOLUME_FULL - The volume is full. + +--*/ +; + +EFI_STATUS +EFIAPI +WinNtSimpleFileSystemSetPosition ( + IN EFI_FILE *This, + IN UINT64 Position + ) +/*++ + +Routine Description: + + Set a file's current position. + +Arguments: + + This - Pointer to an opened file handle. + + Position - The byte position from the start of the file to set. + +Returns: + + EFI_SUCCESS - The file position has been changed. + + EFI_UNSUPPORTED - The seek request for non-zero is not supported for directories. + +--*/ +; + +EFI_STATUS +EFIAPI +WinNtSimpleFileSystemGetPosition ( + IN EFI_FILE *This, + OUT UINT64 *Position + ) +/*++ + +Routine Description: + + Get a file's current position. + +Arguments: + + This - Pointer to an opened file handle. + + Position - Pointer to storage for the current position. + +Returns: + + EFI_SUCCESS - The file position has been reported. + + EFI_UNSUPPORTED - Not valid for directories. + +--*/ +; + +EFI_STATUS +EFIAPI +WinNtSimpleFileSystemGetInfo ( + IN EFI_FILE *This, + IN EFI_GUID *InformationType, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Return information about a file or volume. + +Arguments: + + This - Pointer to an opened file handle. + + InformationType - GUID describing the type of information to be returned. + + BufferSize - On input, the size of the information buffer. On output, the number of bytes written to the + information buffer. + + Buffer - Pointer to the first byte of the information buffer. + +Returns: + + EFI_SUCCESS - The requested information has been written into the buffer. + + EFI_UNSUPPORTED - The InformationType is not known. + + EFI_NO_MEDIA - The device has no media. + + EFI_DEVICE_ERROR - The device reported an error. + + EFI_VOLUME_CORRUPTED - The file system structures are corrupt. + + EFI_BUFFER_TOO_SMALL - The buffer size was too small to contain the requested information. The buffer size has + been updated with the size needed to complete the requested operation. + +--*/ +; + +EFI_STATUS +EFIAPI +WinNtSimpleFileSystemSetInfo ( + IN EFI_FILE *This, + IN EFI_GUID *InformationType, + IN UINTN BufferSize, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Set information about a file or volume. + +Arguments: + + This - Pointer to an opened file handle. + + InformationType - GUID identifying the type of information to set. + + BufferSize - Number of bytes of data in the information buffer. + + Buffer - Pointer to the first byte of data in the information buffer. + +Returns: + + EFI_SUCCESS - The file or volume information has been updated. + + EFI_UNSUPPORTED - The information identifier is not recognised. + + EFI_NO_MEDIA - The device has no media. + + EFI_DEVICE_ERROR - The device reported an error. + + EFI_VOLUME_CORRUPTED - The file system structures are corrupt. + + EFI_WRITE_PROTECTED - The file, directory, volume, or device is write protected. + + EFI_ACCESS_DENIED - The file was opened read-only. + + EFI_VOLUME_FULL - The volume is full. + + EFI_BAD_BUFFER_SIZE - The buffer size is smaller than the type indicated by InformationType. + +--*/ +; + +EFI_STATUS +EFIAPI +WinNtSimpleFileSystemFlush ( + IN EFI_FILE *This + ) +/*++ + +Routine Description: + + Flush all modified data to the media. + +Arguments: + + This - Pointer to an opened file handle. + +Returns: + + EFI_SUCCESS - The data has been flushed. + + EFI_NO_MEDIA - The device has no media. + + EFI_DEVICE_ERROR - The device reported an error. + + EFI_VOLUME_CORRUPTED - The file system structures have been corrupted. + + EFI_WRITE_PROTECTED - The file, directory, volume, or device is write protected. + + EFI_ACCESS_DENIED - The file was opened read-only. + + EFI_VOLUME_FULL - The volume is full. + +--*/ +; + +#endif /* _WIN_NT_SIMPLE_FILE_SYSTEM_H_ */ + +/* eof - WinNtSimpleFileSystem.h */ diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SimpleFileSystem/WinNtSimpleFileSystem.mbd b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SimpleFileSystem/WinNtSimpleFileSystem.mbd new file mode 100644 index 0000000000..3a3e7845c6 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SimpleFileSystem/WinNtSimpleFileSystem.mbd @@ -0,0 +1,41 @@ + + + + + WinNtSimpleFileSystem + 9C25E18B-76BA-43da-A132-DBB0997CEFEF + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-14 17:04 + 2006-03-19 15:17 + + + UefiBootServicesTableLib + BaseLib + UefiLib + UefiMemoryLib + UefiDriverEntryPoint + UefiDriverModelLib + UefiDebugLibStdErr + BasePrintLib + DxeMemoryAllocationLib + + diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SimpleFileSystem/WinNtSimpleFileSystem.msa b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SimpleFileSystem/WinNtSimpleFileSystem.msa new file mode 100644 index 0000000000..654340e2f8 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SimpleFileSystem/WinNtSimpleFileSystem.msa @@ -0,0 +1,81 @@ + + + + + WinNtSimpleFileSystem + UEFI_DRIVER + BS_DRIVER + 9C25E18B-76BA-43da-A132-DBB0997CEFEF + 0 + Component description file for WinNtSimpleFileSystem module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-14 17:04 + 2006-03-19 15:17 + + + DebugLib + BaseLib + UefiDriverModelLib + UefiDriverEntryPoint + UefiLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + + + WinNtSimpleFileSystem.h + WinNtSimpleFileSystem.c + ComponentName.c + + + MdePkg + EdkModulePkg + EdkNt32Pkg + + + WinNtIo + SimpleFileSystem + + + + WinNtFileSystem + + + FileSystemInfo + + + FileInfo + + + FileSystemVolumeLabelInfoId + + + + + + + + gWinNtSimpleFileSystemDriverBinding + gWinNtSimpleFileSystemComponentName + + + diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SimpleFileSystem/build.xml b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SimpleFileSystem/build.xml new file mode 100644 index 0000000000..fc39519781 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/SimpleFileSystem/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/ComponentName.c b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/ComponentName.c new file mode 100644 index 0000000000..7b9c2972d0 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/ComponentName.c @@ -0,0 +1,187 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ComponentName.c + +Abstract: + +--*/ + +#include "WinNtUga.h" + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +WinNtUgaComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +EFI_STATUS +EFIAPI +WinNtUgaComponentNameGetControllerName ( + 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 +// +EFI_COMPONENT_NAME_PROTOCOL gWinNtUgaComponentName = { + WinNtUgaComponentNameGetDriverName, + WinNtUgaComponentNameGetControllerName, + "eng" +}; + +static EFI_UNICODE_STRING_TABLE mWinNtUgaDriverNameTable[] = { + { "eng", L"Windows Universal Graphics Adapter Driver" }, + { NULL , NULL } +}; + +EFI_STATUS +EFIAPI +WinNtUgaComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gWinNtUgaComponentName.SupportedLanguages, + mWinNtUgaDriverNameTable, + DriverName + ); +} + +EFI_STATUS +EFIAPI +WinNtUgaComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + 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. + 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. + + Returns: + 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. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + EFI_STATUS Status; + EFI_UGA_DRAW_PROTOCOL *UgaDraw; + UGA_PRIVATE_DATA *Private; + + // + // This is a device driver, so ChildHandle must be NULL. + // + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + + // + // Get our context back + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUgaDrawProtocolGuid, + &UgaDraw, + gWinNtUgaDriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Private = UGA_DRAW_PRIVATE_DATA_FROM_THIS (UgaDraw); + + return LookupUnicodeString ( + Language, + gWinNtUgaComponentName.SupportedLanguages, + Private->ControllerNameTable, + ControllerName + ); +} diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/WinNtUga.h b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/WinNtUga.h new file mode 100644 index 0000000000..defe3913fc --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/WinNtUga.h @@ -0,0 +1,363 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + WinNtUga.h + +Abstract: + + Private data for the Uga driver that is bound to the WinNt Thunk protocol + +--*/ + +#ifndef _WIN_NT_UGA_H_ +#define _WIN_NT_UGA_H_ + + + +#define MAX_Q 256 + +typedef struct { + UINTN Front; + UINTN Rear; + UINTN Count; + EFI_INPUT_KEY Q[MAX_Q]; +} UGA_QUEUE_FIXED; + +#define WIN_NT_UGA_CLASS_NAME L"WinNtUgaWindow" + +#define UGA_PRIVATE_DATA_SIGNATURE EFI_SIGNATURE_32 ('S', 'g', 'o', 'N') +typedef struct { + UINT64 Signature; + + EFI_HANDLE Handle; + EFI_UGA_DRAW_PROTOCOL UgaDraw; + EFI_SIMPLE_TEXT_IN_PROTOCOL SimpleTextIn; + + EFI_WIN_NT_THUNK_PROTOCOL *WinNtThunk; + + EFI_UNICODE_STRING_TABLE *ControllerNameTable; + + // + // UGA Private Data for GetMode () + // + UINT32 HorizontalResolution; + UINT32 VerticalResolution; + UINT32 ColorDepth; + UINT32 RefreshRate; + + // + // UGA Private Data knowing when to start hardware + // + BOOLEAN HardwareNeedsStarting; + + CHAR16 *WindowName; + CHAR16 Buffer[160]; + + HANDLE ThreadInited; // Semaphore + HANDLE ThreadHandle; // Thread + DWORD ThreadId; + + HWND WindowHandle; + WNDCLASSEX WindowsClass; + + // + // This screen is used to redraw the scree when windows events happen. It's + // updated in the main thread and displayed in the windows thread. + // + BITMAPV4HEADER *VirtualScreenInfo; + RGBQUAD *VirtualScreen; + + EFI_UGA_PIXEL *FillLine; + + // + // Keyboard Queue used by Simple Text In. WinProc thread adds, and main + // thread removes. + // + CRITICAL_SECTION QCriticalSection; + UGA_QUEUE_FIXED Queue; + +} UGA_PRIVATE_DATA; + +#define UGA_DRAW_PRIVATE_DATA_FROM_THIS(a) \ + CR(a, UGA_PRIVATE_DATA, UgaDraw, UGA_PRIVATE_DATA_SIGNATURE) + +#define UGA_PRIVATE_DATA_FROM_TEXT_IN_THIS(a) \ + CR(a, UGA_PRIVATE_DATA, SimpleTextIn, UGA_PRIVATE_DATA_SIGNATURE) + +// +// Global Protocol Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gWinNtUgaDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gWinNtUgaComponentName; + +// +// Uga Hardware abstraction internal worker functions +// +EFI_STATUS +WinNtUgaSupported ( + IN EFI_WIN_NT_IO_PROTOCOL *WinNtIo + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + WinNtIo - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +WinNtUgaConstructor ( + IN UGA_PRIVATE_DATA *Private + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +WinNtUgaDestructor ( + IN UGA_PRIVATE_DATA *Private + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +// +// EFI 1.1 driver model prototypes for Win NT UGA +// + +EFI_STATUS +EFIAPI +WinNtUgaInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ImageHandle - TODO: add argument description + SystemTable - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +WinNtUgaDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Handle - TODO: add argument description + RemainingDevicePath - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +WinNtUgaDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Handle - TODO: add argument description + RemainingDevicePath - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +WinNtUgaDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Handle - TODO: add argument description + NumberOfChildren - TODO: add argument description + ChildHandleBuffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +UgaPrivateAddQ ( + IN UGA_PRIVATE_DATA *Private, + IN EFI_INPUT_KEY Key + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + Key - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +WinNtUgaInitializeSimpleTextInForWindow ( + IN UGA_PRIVATE_DATA *Private + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +WinNtUgaDestroySimpleTextInForWindow ( + IN UGA_PRIVATE_DATA *Private + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +UINTN +Atoi ( + IN CHAR16 *String + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + String - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/WinNtUga.mbd b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/WinNtUga.mbd new file mode 100644 index 0000000000..18add2fe18 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/WinNtUga.mbd @@ -0,0 +1,41 @@ + + + + + WinNtUga + AB248E8D-ABE1-11d4-BD0D-0080C73C8881 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-14 17:04 + 2006-03-19 15:17 + + + UefiBootServicesTableLib + BaseLib + UefiLib + UefiMemoryLib + UefiDriverEntryPoint + UefiDriverModelLib + UefiDebugLibStdErr + BasePrintLib + DxeMemoryAllocationLib + + diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/WinNtUga.msa b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/WinNtUga.msa new file mode 100644 index 0000000000..f83a41dda3 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/WinNtUga.msa @@ -0,0 +1,83 @@ + + + + + WinNtUga + UEFI_DRIVER + BS_DRIVER + AB248E8D-ABE1-11d4-BD0D-0080C73C8881 + 0 + Component description file for UGA module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-14 17:04 + 2006-03-19 15:17 + + + DebugLib + BaseLib + UefiDriverModelLib + UefiDriverEntryPoint + UefiLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + + + WinNtUga.h + WinNtUgaInput.c + WinNtUgaDriver.c + WinNtUgaScreen.c + ComponentName.c + + + MdePkg + EdkModulePkg + EdkNt32Pkg + + + WinNtIo + UgaDraw + SimpleTextIn + + + + + gEfiEventExitBootServicesGuid + 0x27abf055, 0xb1b8, 0x4c26, 0x80, 0x48, 0x74, 0x8f, 0x37, 0xba, 0xa2, 0xdf + + + + + + WinNtUga + + + + + + + + gWinNtUgaDriverBinding + gWinNtUgaComponentName + + + diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/WinNtUgaDriver.c b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/WinNtUgaDriver.c new file mode 100644 index 0000000000..58908d9f07 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/WinNtUgaDriver.c @@ -0,0 +1,343 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + WinNtUgaDriver.c + +Abstract: + + This file implements the EFI 1.1 Device Driver model requirements for UGA + + UGA is short hand for Universal Graphics Abstraction protocol. + + This file is a verision of UgaIo the uses WinNtThunk system calls as an IO + abstraction. For a PCI device WinNtIo would be replaced with + a PCI IO abstraction that abstracted a specific PCI device. + +--*/ + +#include "WinNtUga.h" + +EFI_DRIVER_BINDING_PROTOCOL gWinNtUgaDriverBinding = { + WinNtUgaDriverBindingSupported, + WinNtUgaDriverBindingStart, + WinNtUgaDriverBindingStop, + 0x10, + NULL, + NULL +}; + + +EFI_STATUS +EFIAPI +WinNtUgaDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Handle - add argument and description to function comment +// TODO: RemainingDevicePath - add argument and description to function comment +{ + EFI_STATUS Status; + EFI_WIN_NT_IO_PROTOCOL *WinNtIo; + + // + // Open the IO Abstraction(s) needed to perform the supported test + // + Status = gBS->OpenProtocol ( + Handle, + &gEfiWinNtIoProtocolGuid, + &WinNtIo, + This->DriverBindingHandle, + Handle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = WinNtUgaSupported (WinNtIo); + + // + // Close the I/O Abstraction(s) used to perform the supported test + // + gBS->CloseProtocol ( + Handle, + &gEfiWinNtIoProtocolGuid, + This->DriverBindingHandle, + Handle + ); + + return Status; +} + +EFI_STATUS +EFIAPI +WinNtUgaDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Handle - add argument and description to function comment +// TODO: RemainingDevicePath - add argument and description to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +{ + EFI_WIN_NT_IO_PROTOCOL *WinNtIo; + EFI_STATUS Status; + UGA_PRIVATE_DATA *Private; + + // + // Grab the protocols we need + // + Status = gBS->OpenProtocol ( + Handle, + &gEfiWinNtIoProtocolGuid, + &WinNtIo, + This->DriverBindingHandle, + Handle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + // + // Allocate Private context data for SGO inteface. + // + Private = NULL; + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (UGA_PRIVATE_DATA), + &Private + ); + if (EFI_ERROR (Status)) { + goto Done; + } + // + // Set up context record + // + Private->Signature = UGA_PRIVATE_DATA_SIGNATURE; + Private->Handle = Handle; + Private->WinNtThunk = WinNtIo->WinNtThunk; + + Private->ControllerNameTable = NULL; + + AddUnicodeString ( + "eng", + gWinNtUgaComponentName.SupportedLanguages, + &Private->ControllerNameTable, + WinNtIo->EnvString + ); + + Private->WindowName = WinNtIo->EnvString; + + Status = WinNtUgaConstructor (Private); + if (EFI_ERROR (Status)) { + goto Done; + } + // + // Publish the Uga interface to the world + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &Private->Handle, + &gEfiUgaDrawProtocolGuid, + &Private->UgaDraw, + &gEfiSimpleTextInProtocolGuid, + &Private->SimpleTextIn, + NULL + ); + +Done: + if (EFI_ERROR (Status)) { + + gBS->CloseProtocol ( + Handle, + &gEfiWinNtIoProtocolGuid, + This->DriverBindingHandle, + Handle + ); + + if (Private != NULL) { + // + // On Error Free back private data + // + if (Private->ControllerNameTable != NULL) { + FreeUnicodeStringTable (Private->ControllerNameTable); + } + + gBS->FreePool (Private); + } + } + + return Status; +} + +EFI_STATUS +EFIAPI +WinNtUgaDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: Handle - add argument and description to function comment +// TODO: NumberOfChildren - add argument and description to function comment +// TODO: ChildHandleBuffer - add argument and description to function comment +// TODO: EFI_NOT_STARTED - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +{ + EFI_UGA_DRAW_PROTOCOL *UgaDraw; + EFI_STATUS Status; + UGA_PRIVATE_DATA *Private; + + Status = gBS->OpenProtocol ( + Handle, + &gEfiUgaDrawProtocolGuid, + &UgaDraw, + This->DriverBindingHandle, + Handle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + // + // If the UGA interface does not exist the driver is not started + // + return EFI_NOT_STARTED; + } + + // + // Get our private context information + // + Private = UGA_DRAW_PRIVATE_DATA_FROM_THIS (UgaDraw); + + // + // Remove the SGO interface from the system + // + Status = gBS->UninstallMultipleProtocolInterfaces ( + Private->Handle, + &gEfiUgaDrawProtocolGuid, + &Private->UgaDraw, + &gEfiSimpleTextInProtocolGuid, + &Private->SimpleTextIn, + NULL + ); + if (!EFI_ERROR (Status)) { + // + // Shutdown the hardware + // + Status = WinNtUgaDestructor (Private); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + gBS->CloseProtocol ( + Handle, + &gEfiWinNtIoProtocolGuid, + This->DriverBindingHandle, + Handle + ); + + // + // Free our instance data + // + FreeUnicodeStringTable (Private->ControllerNameTable); + + gBS->FreePool (Private); + + } + + return Status; +} + +UINTN +Atoi ( + CHAR16 *String + ) +/*++ + +Routine Description: + + Convert a unicode string to a UINTN + +Arguments: + + String - Unicode string. + +Returns: + + UINTN of the number represented by String. + +--*/ +{ + UINTN Number; + CHAR16 *Str; + + // + // skip preceeding white space + // + Str = String; + while ((*Str) && (*Str == ' ' || *Str == '"')) { + Str++; + } + + // + // Convert ot a Number + // + Number = 0; + while (*Str != '\0') { + if ((*Str >= '0') && (*Str <= '9')) { + Number = (Number * 10) +*Str - '0'; + } else { + break; + } + + Str++; + } + + return Number; +} diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/WinNtUgaInput.c b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/WinNtUgaInput.c new file mode 100644 index 0000000000..19bca36359 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/WinNtUgaInput.c @@ -0,0 +1,411 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + WinNtUgaInput.c + +Abstract: + + This file produces the Simple Text In for an Uga window. + + This stuff is linked at the hip to the Window, since the window + processing is done in a thread kicked off in WinNtUgaImplementation.c + + Since the window information is processed in an other thread we need + a keyboard Queue to pass data about. The Simple Text In code just + takes data off the Queue. The WinProc message loop takes keyboard input + and places it in the Queue. + +--*/ + +#include "WinNtUga.h" + +EFI_STATUS +UgaPrivateCreateQ ( + IN UGA_PRIVATE_DATA *Private + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + +Returns: + + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + Private->WinNtThunk->InitializeCriticalSection (&Private->QCriticalSection); + + Private->Queue.Front = 0; + Private->Queue.Rear = MAX_Q - 1; + Private->Queue.Count = 0; + return EFI_SUCCESS; +} + +EFI_STATUS +UgaPrivateDestroyQ ( + IN UGA_PRIVATE_DATA *Private + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + +Returns: + + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + Private->Queue.Count = 0; + Private->WinNtThunk->DeleteCriticalSection (&Private->QCriticalSection); + return EFI_SUCCESS; +} + +EFI_STATUS +UgaPrivateAddQ ( + IN UGA_PRIVATE_DATA *Private, + IN EFI_INPUT_KEY Key + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + Key - TODO: add argument description + +Returns: + + EFI_NOT_READY - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + Private->WinNtThunk->EnterCriticalSection (&Private->QCriticalSection); + + if (Private->Queue.Count == MAX_Q) { + Private->WinNtThunk->LeaveCriticalSection (&Private->QCriticalSection); + return EFI_NOT_READY; + } + + Private->Queue.Rear = (Private->Queue.Rear + 1) % MAX_Q; + Private->Queue.Q[Private->Queue.Rear] = Key; + Private->Queue.Count++; + + Private->WinNtThunk->LeaveCriticalSection (&Private->QCriticalSection); + return EFI_SUCCESS; +} + +EFI_STATUS +UgaPrivateDeleteQ ( + IN UGA_PRIVATE_DATA *Private, + OUT EFI_INPUT_KEY *Key + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + Key - TODO: add argument description + +Returns: + + EFI_NOT_READY - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + Private->WinNtThunk->EnterCriticalSection (&Private->QCriticalSection); + + if (Private->Queue.Count == 0) { + Private->WinNtThunk->LeaveCriticalSection (&Private->QCriticalSection); + return EFI_NOT_READY; + } + + *Key = Private->Queue.Q[Private->Queue.Front]; + Private->Queue.Front = (Private->Queue.Front + 1) % MAX_Q; + Private->Queue.Count--; + + Private->WinNtThunk->LeaveCriticalSection (&Private->QCriticalSection); + return EFI_SUCCESS; +} + +EFI_STATUS +UgaPrivateCheckQ ( + IN UGA_PRIVATE_DATA *Private + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + +Returns: + + EFI_NOT_READY - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + if (Private->Queue.Count == 0) { + return EFI_NOT_READY; + } + + return EFI_SUCCESS; +} + +// +// Simple Text In implementation. +// + +EFI_STATUS +EFIAPI +WinNtUgaSimpleTextInReset ( + IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + ExtendedVerification - TODO: add argument description + +Returns: + + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + UGA_PRIVATE_DATA *Private; + EFI_INPUT_KEY Key; + EFI_TPL OldTpl; + + Private = UGA_PRIVATE_DATA_FROM_TEXT_IN_THIS (This); + + // + // Enter critical section + // + OldTpl = gBS->RaiseTPL (EFI_TPL_NOTIFY); + + // + // A reset is draining the Queue + // + while (UgaPrivateDeleteQ (Private, &Key) == EFI_SUCCESS) + ; + + // + // Leave critical section and return + // + gBS->RestoreTPL (OldTpl); + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +WinNtUgaSimpleTextInReadKeyStroke ( + IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This, + OUT EFI_INPUT_KEY *Key + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Key - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + UGA_PRIVATE_DATA *Private; + EFI_STATUS Status; + EFI_TPL OldTpl; + + Private = UGA_PRIVATE_DATA_FROM_TEXT_IN_THIS (This); + + // + // Enter critical section + // + OldTpl = gBS->RaiseTPL (EFI_TPL_NOTIFY); + + Status = UgaPrivateCheckQ (Private); + if (!EFI_ERROR (Status)) { + // + // If a Key press exists try and read it. + // + Status = UgaPrivateDeleteQ (Private, Key); + } + + // + // Leave critical section and return + // + gBS->RestoreTPL (OldTpl); + + return Status; +} + +STATIC +VOID +EFIAPI +WinNtUgaSimpleTextInWaitForKey ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Event - TODO: add argument description + Context - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + UGA_PRIVATE_DATA *Private; + EFI_STATUS Status; + EFI_TPL OldTpl; + + Private = (UGA_PRIVATE_DATA *) Context; + + // + // Enter critical section + // + OldTpl = gBS->RaiseTPL (EFI_TPL_NOTIFY); + + Status = UgaPrivateCheckQ (Private); + if (!EFI_ERROR (Status)) { + // + // If a there is a key in the queue signal our event. + // + gBS->SignalEvent (Event); + } else { + // + // We need to sleep or NT will schedule this thread with such high + // priority that WinProc thread will never run and we will not see + // keyboard input. This Sleep makes the syste run 10x faster, so don't + // remove it. + // + Private->WinNtThunk->Sleep (1); + } + + // + // Leave critical section and return + // + gBS->RestoreTPL (OldTpl); +} + +EFI_STATUS +WinNtUgaInitializeSimpleTextInForWindow ( + IN UGA_PRIVATE_DATA *Private + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + EFI_STATUS Status; + + UgaPrivateCreateQ (Private); + + // + // Initialize Simple Text In protoocol + // + Private->SimpleTextIn.Reset = WinNtUgaSimpleTextInReset; + Private->SimpleTextIn.ReadKeyStroke = WinNtUgaSimpleTextInReadKeyStroke; + + Status = gBS->CreateEvent ( + EFI_EVENT_NOTIFY_WAIT, + EFI_TPL_NOTIFY, + WinNtUgaSimpleTextInWaitForKey, + Private, + &Private->SimpleTextIn.WaitForKey + ); + + return Status; +} + +EFI_STATUS +WinNtUgaDestroySimpleTextInForWindow ( + IN UGA_PRIVATE_DATA *Private + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + +Returns: + + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + UgaPrivateDestroyQ (Private); + return EFI_SUCCESS; +} diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/WinNtUgaScreen.c b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/WinNtUgaScreen.c new file mode 100644 index 0000000000..ed35a01c32 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/WinNtUgaScreen.c @@ -0,0 +1,992 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + WinNtUgaScreen.c + +Abstract: + + This file produces the graphics abstration of UGA. It is called by + WinNtUgaDriver.c file which deals with the EFI 1.1 driver model. + This file just does graphics. + +--*/ + +#include "WinNtUga.h" + +EFI_WIN_NT_THUNK_PROTOCOL *mWinNt; +DWORD mTlsIndex = TLS_OUT_OF_INDEXES; +DWORD mTlsIndexUseCount = 0; // lets us know when we can free mTlsIndex. +static EFI_EVENT mUgaScreenExitBootServicesEvent; + +EFI_STATUS +WinNtUgaStartWindow ( + IN UGA_PRIVATE_DATA *Private, + IN UINT32 HorizontalResolution, + IN UINT32 VerticalResolution, + IN UINT32 ColorDepth, + IN UINT32 RefreshRate + ); + +STATIC +VOID +EFIAPI +KillNtUgaThread ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +// +// UGA Protocol Member Functions +// + +EFI_STATUS +EFIAPI +WinNtUgaGetMode ( + EFI_UGA_DRAW_PROTOCOL *This, + UINT32 *HorizontalResolution, + UINT32 *VerticalResolution, + UINT32 *ColorDepth, + UINT32 *RefreshRate + ) +/*++ + + Routine Description: + Return the current video mode information. + + Arguments: + This - Protocol instance pointer. + HorizontalResolution - Current video horizontal resolution in pixels + VerticalResolution - Current video Vertical resolution in pixels + ColorDepth - Current video color depth in bits per pixel + RefreshRate - Current video refresh rate in Hz. + + Returns: + EFI_SUCCESS - Mode information returned. + EFI_NOT_STARTED - Video display is not initialized. Call SetMode () + EFI_INVALID_PARAMETER - One of the input args was NULL. + +--*/ +// TODO: ADD IN/OUT description here +{ + UGA_PRIVATE_DATA *Private; + + Private = UGA_DRAW_PRIVATE_DATA_FROM_THIS (This); + + if (Private->HardwareNeedsStarting) { + return EFI_NOT_STARTED; + } + + if ((HorizontalResolution == NULL) || + (VerticalResolution == NULL) || + (ColorDepth == NULL) || + (RefreshRate == NULL)) { + return EFI_INVALID_PARAMETER; + } + + *HorizontalResolution = Private->HorizontalResolution; + *VerticalResolution = Private->VerticalResolution; + *ColorDepth = Private->ColorDepth; + *RefreshRate = Private->RefreshRate; + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +WinNtUgaSetMode ( + EFI_UGA_DRAW_PROTOCOL *This, + UINT32 HorizontalResolution, + UINT32 VerticalResolution, + UINT32 ColorDepth, + UINT32 RefreshRate + ) +/*++ + + Routine Description: + Return the current video mode information. + + Arguments: + This - Protocol instance pointer. + HorizontalResolution - Current video horizontal resolution in pixels + VerticalResolution - Current video Vertical resolution in pixels + ColorDepth - Current video color depth in bits per pixel + RefreshRate - Current video refresh rate in Hz. + + Returns: + EFI_SUCCESS - Mode information returned. + EFI_NOT_STARTED - Video display is not initialized. Call SetMode () + EFI_INVALID_PARAMETER - One of the input args was NULL. + +--*/ +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: ADD IN/OUT description here +{ + EFI_STATUS Status; + UGA_PRIVATE_DATA *Private; + EFI_UGA_PIXEL Fill; + EFI_UGA_PIXEL *NewFillLine; + RECT Rect; + UINTN Size; + UINTN Width; + UINTN Height; + + Private = UGA_DRAW_PRIVATE_DATA_FROM_THIS (This); + + if (Private->HardwareNeedsStarting) { + Status = WinNtUgaStartWindow ( + Private, + HorizontalResolution, + VerticalResolution, + ColorDepth, + RefreshRate + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + Private->HardwareNeedsStarting = FALSE; + } else { + // + // Change the resolution and resize of the window + // + + // + // Free the old buffer. We do not save the content of the old buffer since the + // screen is to be cleared anyway. Clearing the screen is required by the EFI spec. + // See EFI spec chepter 10.5-EFI_UGA_DRAW_PROTOCOL.SetMode() + // + Private->WinNtThunk->HeapFree (Private->WinNtThunk->GetProcessHeap (), 0, Private->VirtualScreenInfo); + + // + // Allocate DIB frame buffer directly from NT for performance enhancement + // This buffer is the virtual screen/frame buffer. This buffer is not the + // same a a frame buffer. The first row of this buffer will be the bottom + // line of the image. This is an artifact of the way we draw to the screen. + // + Size = HorizontalResolution * VerticalResolution * sizeof (RGBQUAD) + sizeof (BITMAPV4HEADER); + Private->VirtualScreenInfo = Private->WinNtThunk->HeapAlloc ( + Private->WinNtThunk->GetProcessHeap (), + HEAP_ZERO_MEMORY, + Size + ); + + // + // Update the virtual screen info data structure + // + Private->VirtualScreenInfo->bV4Size = sizeof (BITMAPV4HEADER); + Private->VirtualScreenInfo->bV4Width = HorizontalResolution; + Private->VirtualScreenInfo->bV4Height = VerticalResolution; + Private->VirtualScreenInfo->bV4Planes = 1; + Private->VirtualScreenInfo->bV4BitCount = 32; + // + // uncompressed + // + Private->VirtualScreenInfo->bV4V4Compression = BI_RGB; + + // + // The rest of the allocated memory block is the virtual screen buffer + // + Private->VirtualScreen = (RGBQUAD *) (Private->VirtualScreenInfo + 1); + + // + // Use the AdjuctWindowRect fuction to calculate the real width and height + // of the new window including the border and caption + // + Rect.left = 0; + Rect.top = 0; + Rect.right = HorizontalResolution; + Rect.bottom = VerticalResolution; + + Private->WinNtThunk->AdjustWindowRect (&Rect, WS_OVERLAPPEDWINDOW, 0); + + Width = Rect.right - Rect.left; + Height = Rect.bottom - Rect.top; + + // + // Retrieve the original window position information + // + Private->WinNtThunk->GetWindowRect (Private->WindowHandle, &Rect); + + // + // Adjust the window size + // + Private->WinNtThunk->MoveWindow (Private->WindowHandle, Rect.left, Rect.top, Width, Height, TRUE); + + } + + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (EFI_UGA_PIXEL) * HorizontalResolution, + &NewFillLine + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + if (Private->FillLine != NULL) { + gBS->FreePool (Private->FillLine); + } + + Private->FillLine = NewFillLine; + + Private->HorizontalResolution = HorizontalResolution; + Private->VerticalResolution = VerticalResolution; + Private->ColorDepth = ColorDepth; + Private->RefreshRate = RefreshRate; + + Fill.Red = 0x00; + Fill.Green = 0x00; + Fill.Blue = 0x00; + This->Blt ( + This, + &Fill, + EfiUgaVideoFill, + 0, + 0, + 0, + 0, + HorizontalResolution, + VerticalResolution, + HorizontalResolution * sizeof (EFI_UGA_PIXEL) + ); + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +WinNtUgaBlt ( + 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 + ) +/*++ + + Routine Description: + Blt pixels from the rectangle (Width X Height) formed by the BltBuffer + onto the graphics screen starting a location (X, Y). (0, 0) is defined as + the upper left hand side of the screen. (X, Y) can be outside of the + current screen geometry and the BltBuffer will be cliped when it is + displayed. X and Y can be negative or positive. If Width or Height is + bigger than the current video screen the image will be clipped. + + Arguments: + This - Protocol instance pointer. + X - X location on graphics screen. + Y - Y location on the graphics screen. + Width - Width of BltBuffer. + Height - Hight of BltBuffer + BltOperation - Operation to perform on BltBuffer and video memory + BltBuffer - Buffer containing data to blt into video buffer. This + buffer has a size of Width*Height*sizeof(EFI_UGA_PIXEL) + SourceX - If the BltOperation is a EfiCopyBlt this is the source + of the copy. For other BLT operations this argument is not + used. + SourceX - If the BltOperation is a EfiCopyBlt this is the source + of the copy. For other BLT operations this argument is not + used. + + Returns: + EFI_SUCCESS - The palette is updated with PaletteArray. + EFI_INVALID_PARAMETER - BltOperation is not valid. + EFI_DEVICE_ERROR - A hardware error occured writting to the video + buffer. + +--*/ +// TODO: SourceY - add argument and description to function comment +// TODO: DestinationX - add argument and description to function comment +// TODO: DestinationY - add argument and description to function comment +// TODO: Delta - add argument and description to function comment +{ + UGA_PRIVATE_DATA *Private; + EFI_TPL OriginalTPL; + UINTN DstY; + UINTN SrcY; + RGBQUAD *VScreen; + RGBQUAD *VScreenSrc; + EFI_UGA_PIXEL *Blt; + UINTN Index; + RECT Rect; + EFI_UGA_PIXEL *FillPixel; + + Private = UGA_DRAW_PRIVATE_DATA_FROM_THIS (This); + + if ((BltOperation < 0) || (BltOperation >= EfiUgaBltMax)) { + return EFI_INVALID_PARAMETER; + } + + if (Width == 0 || Height == 0) { + return EFI_INVALID_PARAMETER; + } + // + // If Delta is zero, then the entire BltBuffer is being used, so Delta + // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size, + // the number of bytes in each row can be computed. + // + if (Delta == 0) { + Delta = Width * sizeof (EFI_UGA_PIXEL); + } + + // + // We need to fill the Virtual Screen buffer with the blt data. + // The virtual screen is upside down, as the first row is the bootom row of + // the image. + // + + if (BltOperation == EfiUgaVideoToBltBuffer) { + + // + // Video to BltBuffer: Source is Video, destination is BltBuffer + // + if (SourceY + Height > Private->VerticalResolution) { + return EFI_INVALID_PARAMETER; + } + + if (SourceX + Width > Private->HorizontalResolution) { + return EFI_INVALID_PARAMETER; + } + // + // We have to raise to TPL Notify, so we make an atomic write the frame buffer. + // We would not want a timer based event (Cursor, ...) to come in while we are + // doing this operation. + // + OriginalTPL = gBS->RaiseTPL (EFI_TPL_NOTIFY); + + for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY); SrcY++, DstY++) { + Blt = (EFI_UGA_PIXEL *) ((UINT8 *) BltBuffer + (DstY * Delta) + DestinationX * sizeof (EFI_UGA_PIXEL)); + VScreen = &Private->VirtualScreen[(Private->VerticalResolution - SrcY - 1) * Private->HorizontalResolution + SourceX]; + CopyMem (Blt, VScreen, sizeof (EFI_UGA_PIXEL) * Width); + } + } else { + // + // BltBuffer to Video: Source is BltBuffer, destination is Video + // + if (DestinationY + Height > Private->VerticalResolution) { + return EFI_INVALID_PARAMETER; + } + + if (DestinationX + Width > Private->HorizontalResolution) { + return EFI_INVALID_PARAMETER; + } + + // + // We have to raise to TPL Notify, so we make an atomic write the frame buffer. + // We would not want a timer based event (Cursor, ...) to come in while we are + // doing this operation. + // + OriginalTPL = gBS->RaiseTPL (EFI_TPL_NOTIFY); + + if (BltOperation == EfiUgaVideoFill) { + FillPixel = BltBuffer; + for (Index = 0; Index < Width; Index++) { + Private->FillLine[Index] = *FillPixel; + } + } + + for (Index = 0; Index < Height; Index++) { + if (DestinationY <= SourceY) { + SrcY = SourceY + Index; + DstY = DestinationY + Index; + } else { + SrcY = SourceY + Height - Index - 1; + DstY = DestinationY + Height - Index - 1; + } + + VScreen = &Private->VirtualScreen[(Private->VerticalResolution - DstY - 1) * Private->HorizontalResolution + DestinationX]; + switch (BltOperation) { + case EfiUgaBltBufferToVideo: + Blt = (EFI_UGA_PIXEL *) ((UINT8 *) BltBuffer + (SrcY * Delta) + SourceX * sizeof (EFI_UGA_PIXEL)); + CopyMem (VScreen, Blt, Width * sizeof (EFI_UGA_PIXEL)); + break; + + case EfiUgaVideoToVideo: + VScreenSrc = &Private->VirtualScreen[(Private->VerticalResolution - SrcY - 1) * Private->HorizontalResolution + SourceX]; + CopyMem (VScreen, VScreenSrc, Width * sizeof (EFI_UGA_PIXEL)); + break; + + case EfiUgaVideoFill: + CopyMem (VScreen, Private->FillLine, Width * sizeof (EFI_UGA_PIXEL)); + break; + } + } + } + + if (BltOperation != EfiUgaVideoToBltBuffer) { + // + // Mark the area we just blted as Invalid so WM_PAINT will update. + // + Rect.left = DestinationX; + Rect.top = DestinationY; + Rect.right = DestinationX + Width; + Rect.bottom = DestinationY + Height; + Private->WinNtThunk->InvalidateRect (Private->WindowHandle, &Rect, FALSE); + + // + // Send the WM_PAINT message to the thread that is drawing the window. We + // are in the main thread and the window drawing is in a child thread. + // There is a child thread per window. We have no CriticalSection or Mutex + // since we write the data and the other thread displays the data. While + // we may miss some data for a short period of time this is no different than + // a write combining on writes to a frame buffer. + // + + Private->WinNtThunk->UpdateWindow (Private->WindowHandle); + } + + gBS->RestoreTPL (OriginalTPL); + + return EFI_SUCCESS; +} + + +// +// Construction and Destruction functions +// + +EFI_STATUS +WinNtUgaSupported ( + IN EFI_WIN_NT_IO_PROTOCOL *WinNtIo + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: WinNtIo - add argument and description to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + // + // Check to see if the IO abstraction represents a device type we support. + // + // This would be replaced a check of PCI subsystem ID, etc. + // + if (!CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtUgaGuid)) { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +LRESULT +CALLBACK +WinNtUgaThreadWindowProc ( + IN HWND hwnd, + IN UINT iMsg, + IN WPARAM wParam, + IN LPARAM lParam + ) +/*++ + +Routine Description: + Win32 Windows event handler. + +Arguments: + See Win32 Book + +Returns: + See Win32 Book + +--*/ +// TODO: hwnd - add argument and description to function comment +// TODO: iMsg - add argument and description to function comment +// TODO: wParam - add argument and description to function comment +// TODO: lParam - add argument and description to function comment +{ + UGA_PRIVATE_DATA *Private; + UINTN Size; + HDC Handle; + PAINTSTRUCT PaintStruct; + LPARAM Index; + EFI_INPUT_KEY Key; + + // + // BugBug - if there are two instances of this DLL in memory (such as is + // the case for ERM), the correct instance of this function may not be called. + // This also means that the address of the mTlsIndex value will be wrong, and + // the value may be wrong too. + // + + + // + // Use mTlsIndex global to get a Thread Local Storage version of Private. + // This works since each Uga protocol has a unique Private data instance and + // a unique thread. + // + Private = mWinNt->TlsGetValue (mTlsIndex); + ASSERT (NULL != Private); + + switch (iMsg) { + case WM_CREATE: + Size = Private->HorizontalResolution * Private->VerticalResolution * sizeof (RGBQUAD); + + // + // Allocate DIB frame buffer directly from NT for performance enhancement + // This buffer is the virtual screen/frame buffer. This buffer is not the + // same a a frame buffer. The first fow of this buffer will be the bottom + // line of the image. This is an artifact of the way we draw to the screen. + // + Private->VirtualScreenInfo = Private->WinNtThunk->HeapAlloc ( + Private->WinNtThunk->GetProcessHeap (), + HEAP_ZERO_MEMORY, + Size + ); + + Private->VirtualScreenInfo->bV4Size = sizeof (BITMAPV4HEADER); + Private->VirtualScreenInfo->bV4Width = Private->HorizontalResolution; + Private->VirtualScreenInfo->bV4Height = Private->VerticalResolution; + Private->VirtualScreenInfo->bV4Planes = 1; + Private->VirtualScreenInfo->bV4BitCount = 32; + // + // uncompressed + // + Private->VirtualScreenInfo->bV4V4Compression = BI_RGB; + Private->VirtualScreen = (RGBQUAD *) (Private->VirtualScreenInfo + 1); + return 0; + + case WM_PAINT: + // + // I have not found a way to convert hwnd into a Private context. So for + // now we use this API to convert hwnd to Private data. + // + + Handle = mWinNt->BeginPaint (hwnd, &PaintStruct); + + mWinNt->SetDIBitsToDevice ( + Handle, // Destination Device Context + 0, // Destination X - 0 + 0, // Destination Y - 0 + Private->HorizontalResolution, // Width + Private->VerticalResolution, // Height + 0, // Source X + 0, // Source Y + 0, // DIB Start Scan Line + Private->VerticalResolution, // Number of scan lines + Private->VirtualScreen, // Address of array of DIB bits + (BITMAPINFO *) Private->VirtualScreenInfo, // Address of structure with bitmap info + DIB_RGB_COLORS // RGB or palette indexes + ); + + mWinNt->EndPaint (hwnd, &PaintStruct); + return 0; + + // + // F10 and the ALT key do not create a WM_KEYDOWN message, thus this special case + // + case WM_SYSKEYDOWN: + Key.ScanCode = 0; + switch (wParam) { + case VK_F10: + Key.ScanCode = SCAN_F10; + Key.UnicodeChar = 0; + UgaPrivateAddQ (Private, Key); + return 0; + } + break; + + case WM_KEYDOWN: + Key.ScanCode = 0; + switch (wParam) { + case VK_HOME: Key.ScanCode = SCAN_HOME; break; + case VK_END: Key.ScanCode = SCAN_END; break; + case VK_LEFT: Key.ScanCode = SCAN_LEFT; break; + case VK_RIGHT: Key.ScanCode = SCAN_RIGHT; break; + case VK_UP: Key.ScanCode = SCAN_UP; break; + case VK_DOWN: Key.ScanCode = SCAN_DOWN; break; + case VK_DELETE: Key.ScanCode = SCAN_DELETE; break; + case VK_INSERT: Key.ScanCode = SCAN_INSERT; break; + case VK_PRIOR: Key.ScanCode = SCAN_PAGE_UP; break; + case VK_NEXT: Key.ScanCode = SCAN_PAGE_DOWN; break; + case VK_ESCAPE: Key.ScanCode = SCAN_ESC; break; + + case VK_F1: Key.ScanCode = SCAN_F1; break; + case VK_F2: Key.ScanCode = SCAN_F2; break; + case VK_F3: Key.ScanCode = SCAN_F3; break; + case VK_F4: Key.ScanCode = SCAN_F4; break; + case VK_F5: Key.ScanCode = SCAN_F5; break; + case VK_F6: Key.ScanCode = SCAN_F6; break; + case VK_F7: Key.ScanCode = SCAN_F7; break; + case VK_F8: Key.ScanCode = SCAN_F8; break; + case VK_F9: Key.ScanCode = SCAN_F9; break; + } + + if (Key.ScanCode != 0) { + Key.UnicodeChar = 0; + UgaPrivateAddQ (Private, Key); + } + + return 0; + + case WM_CHAR: + // + // The ESC key also generate WM_CHAR. + // + if (wParam == 0x1B) { + return 0; + } + + for (Index = 0; Index < (lParam & 0xffff); Index++) { + if (wParam != 0) { + Key.UnicodeChar = (CHAR16) wParam; + Key.ScanCode = 0; + UgaPrivateAddQ (Private, Key); + } + } + + return 0; + + case WM_CLOSE: + // + // This close message is issued by user, core is not aware of this, + // so don't release the window display resource, just hide the window. + // + Private->WinNtThunk->ShowWindow (Private->WindowHandle, SW_HIDE); + return 0; + + case WM_DESTROY: + mWinNt->DestroyWindow (hwnd); + mWinNt->PostQuitMessage (0); + + mWinNt->HeapFree (Private->WinNtThunk->GetProcessHeap (), 0, Private->VirtualScreenInfo); + + mWinNt->ExitThread (0); + return 0; + + default: + break; + }; + + return mWinNt->DefWindowProc (hwnd, iMsg, wParam, lParam); +} + +DWORD +WINAPI +WinNtUgaThreadWinMain ( + LPVOID lpParameter + ) +/*++ + +Routine Description: + + This thread simulates the end of WinMain () aplication. Each Winow nededs + to process it's events. The messages are dispatched to + WinNtUgaThreadWindowProc (). + + Be very careful sine WinNtUgaThreadWinMain () and WinNtUgaThreadWindowProc () + are running in a seperate thread. We have to do this to process the events. + +Arguments: + + lpParameter - Handle of window to manage. + +Returns: + + if a WM_QUIT message is returned exit. + +--*/ +{ + MSG Message; + UGA_PRIVATE_DATA *Private; + ATOM Atom; + RECT Rect; + + Private = (UGA_PRIVATE_DATA *) lpParameter; + ASSERT (NULL != Private); + + // + // Since each thread has unique private data, save the private data in Thread + // Local Storage slot. Then the shared global mTlsIndex can be used to get + // thread specific context. + // + Private->WinNtThunk->TlsSetValue (mTlsIndex, Private); + + Private->ThreadId = Private->WinNtThunk->GetCurrentThreadId (); + + Private->WindowsClass.cbSize = sizeof (WNDCLASSEX); + Private->WindowsClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; + Private->WindowsClass.lpfnWndProc = WinNtUgaThreadWindowProc; + Private->WindowsClass.cbClsExtra = 0; + Private->WindowsClass.cbWndExtra = 0; + Private->WindowsClass.hInstance = NULL; + Private->WindowsClass.hIcon = Private->WinNtThunk->LoadIcon (NULL, IDI_APPLICATION); + Private->WindowsClass.hCursor = Private->WinNtThunk->LoadCursor (NULL, IDC_ARROW); + Private->WindowsClass.hbrBackground = (HBRUSH) COLOR_WINDOW; + Private->WindowsClass.lpszMenuName = NULL; + Private->WindowsClass.lpszClassName = WIN_NT_UGA_CLASS_NAME; + Private->WindowsClass.hIconSm = Private->WinNtThunk->LoadIcon (NULL, IDI_APPLICATION); + + // + // This call will fail after the first time, but thats O.K. since we only need + // WIN_NT_UGA_CLASS_NAME to exist to create the window. + // + // Note: Multiple instances of this DLL will use the same instance of this + // Class, including the callback function, unless the Class is unregistered and + // successfully registered again. + // + Atom = Private->WinNtThunk->RegisterClassEx (&Private->WindowsClass); + + // + // Setting Rect values to allow for the AdjustWindowRect to provide + // us the correct sizes for the client area when doing the CreateWindowEx + // + Rect.top = 0; + Rect.bottom = Private->VerticalResolution; + Rect.left = 0; + Rect.right = Private->HorizontalResolution; + + Private->WinNtThunk->AdjustWindowRect (&Rect, WS_OVERLAPPEDWINDOW, 0); + + Private->WindowHandle = Private->WinNtThunk->CreateWindowEx ( + 0, + WIN_NT_UGA_CLASS_NAME, + Private->WindowName, + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, + CW_USEDEFAULT, + Rect.right - Rect.left, + Rect.bottom - Rect.top, + NULL, + NULL, + NULL, + &Private + ); + + // + // The reset of this thread is the standard winows program. We need a sperate + // thread since we must process the message loop to make windows act like + // windows. + // + + Private->WinNtThunk->ShowWindow (Private->WindowHandle, SW_SHOW); + Private->WinNtThunk->UpdateWindow (Private->WindowHandle); + + // + // Let the main thread get some work done + // + Private->WinNtThunk->ReleaseSemaphore (Private->ThreadInited, 1, NULL); + + // + // This is the message loop that all Windows programs need. + // + while (Private->WinNtThunk->GetMessage (&Message, Private->WindowHandle, 0, 0)) { + Private->WinNtThunk->TranslateMessage (&Message); + Private->WinNtThunk->DispatchMessage (&Message); + } + + return Message.wParam; +} + +EFI_STATUS +WinNtUgaStartWindow ( + IN UGA_PRIVATE_DATA *Private, + IN UINT32 HorizontalResolution, + IN UINT32 VerticalResolution, + IN UINT32 ColorDepth, + IN UINT32 RefreshRate + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Private - TODO: add argument description + HorizontalResolution - TODO: add argument description + VerticalResolution - TODO: add argument description + ColorDepth - TODO: add argument description + RefreshRate - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + EFI_STATUS Status; + DWORD NewThreadId; + + + mWinNt = Private->WinNtThunk; + + // + // Initialize a Thread Local Storge variable slot. We use TLS to get the + // correct Private data instance into the windows thread. + // + if (mTlsIndex == TLS_OUT_OF_INDEXES) { + ASSERT (0 == mTlsIndexUseCount); + mTlsIndex = Private->WinNtThunk->TlsAlloc (); + } + + // + // always increase the use count! + // + mTlsIndexUseCount++; + + Private->HorizontalResolution = HorizontalResolution; + Private->VerticalResolution = VerticalResolution; + + // + // Register to be notified on exit boot services so we can destroy the window. + // + Status = gBS->CreateEvent ( + EFI_EVENT_SIGNAL_EXIT_BOOT_SERVICES, + EFI_TPL_CALLBACK, + KillNtUgaThread, + Private, + &mUgaScreenExitBootServicesEvent + ); + + Private->ThreadInited = Private->WinNtThunk->CreateSemaphore (NULL, 0, 1, NULL); + Private->ThreadHandle = Private->WinNtThunk->CreateThread ( + NULL, + 0, + WinNtUgaThreadWinMain, + (VOID *) Private, + 0, + &NewThreadId + ); + + // + // The other thread has entered the windows message loop so we can + // continue our initialization. + // + Private->WinNtThunk->WaitForSingleObject (Private->ThreadInited, INFINITE); + Private->WinNtThunk->CloseHandle (Private->ThreadInited); + + return Status; +} + +EFI_STATUS +WinNtUgaConstructor ( + UGA_PRIVATE_DATA *Private + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: Private - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + + Private->UgaDraw.GetMode = WinNtUgaGetMode; + Private->UgaDraw.SetMode = WinNtUgaSetMode; + Private->UgaDraw.Blt = WinNtUgaBlt; + + Private->HardwareNeedsStarting = TRUE; + Private->FillLine = NULL; + + WinNtUgaInitializeSimpleTextInForWindow (Private); + + return EFI_SUCCESS; +} + +EFI_STATUS +WinNtUgaDestructor ( + UGA_PRIVATE_DATA *Private + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: Private - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + UINT32 UnregisterReturn; + + if (!Private->HardwareNeedsStarting) { + // + // BugBug: Shutdown Uga Hardware and any child devices. + // + Private->WinNtThunk->SendMessage (Private->WindowHandle, WM_DESTROY, 0, 0); + Private->WinNtThunk->CloseHandle (Private->ThreadHandle); + + mTlsIndexUseCount--; + + // + // The callback function for another window could still be called, + // so we need to make sure there are no more users of mTlsIndex. + // + if (0 == mTlsIndexUseCount) { + ASSERT (TLS_OUT_OF_INDEXES != mTlsIndex); + + Private->WinNtThunk->TlsFree (mTlsIndex); + mTlsIndex = TLS_OUT_OF_INDEXES; + + UnregisterReturn = Private->WinNtThunk->UnregisterClass ( + Private->WindowsClass.lpszClassName, + Private->WindowsClass.hInstance + ); + } + + WinNtUgaDestroySimpleTextInForWindow (Private); + } + + return EFI_SUCCESS; +} + +STATIC +VOID +EFIAPI +KillNtUgaThread ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + + This is the UGA screen's callback notification function for exit-boot-services. + All we do here is call WinNtUgaDestructor(). + +Arguments: + + Event - not used + Context - pointer to the Private structure. + +Returns: + + None. + +--*/ +{ + EFI_STATUS Status; + Status = WinNtUgaDestructor (Context); +} diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/build.xml b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/build.xml new file mode 100644 index 0000000000..4d5022a84b --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/Uga/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/WinNtBusDriver/ComponentName.c b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/WinNtBusDriver/ComponentName.c new file mode 100644 index 0000000000..7dee4bd9a4 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/WinNtBusDriver/ComponentName.c @@ -0,0 +1,187 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ComponentName.c + +Abstract: + +--*/ + +#include "WinNtBusDriver.h" + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +WinNtBusDriverComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +EFI_STATUS +EFIAPI +WinNtBusDriverComponentNameGetControllerName ( + 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 +// +EFI_COMPONENT_NAME_PROTOCOL gWinNtBusDriverComponentName = { + WinNtBusDriverComponentNameGetDriverName, + WinNtBusDriverComponentNameGetControllerName, + "eng" +}; + +static EFI_UNICODE_STRING_TABLE mWinNtBusDriverNameTable[] = { + { "eng", L"Windows Bus Driver" }, + { NULL , NULL } +}; + +EFI_STATUS +EFIAPI +WinNtBusDriverComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gWinNtBusDriverComponentName.SupportedLanguages, + mWinNtBusDriverNameTable, + DriverName + ); +} + +EFI_STATUS +EFIAPI +WinNtBusDriverComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + 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. + 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. + 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. + 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. + + Returns: + 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. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + EFI_STATUS Status; + EFI_WIN_NT_IO_PROTOCOL *WinNtIo; + WIN_NT_IO_DEVICE *Private; + + // + // This is a bus driver, so ChildHandle can not be NULL. + // + if (ChildHandle == NULL) { + return EFI_UNSUPPORTED; + } + + // + // Get our context back + // + Status = gBS->OpenProtocol ( + ChildHandle, + &gEfiWinNtIoProtocolGuid, + &WinNtIo, + gWinNtBusDriverBinding.DriverBindingHandle, + ChildHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Private = WIN_NT_IO_DEVICE_FROM_THIS (WinNtIo); + + return LookupUnicodeString ( + Language, + gWinNtBusDriverComponentName.SupportedLanguages, + Private->ControllerNameTable, + ControllerName + ); +} diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/WinNtBusDriver/WinNtBusDriver.c b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/WinNtBusDriver/WinNtBusDriver.c new file mode 100644 index 0000000000..eb071575e0 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/WinNtBusDriver/WinNtBusDriver.c @@ -0,0 +1,744 @@ +/*+++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + WinNtBusDriver.c + +Abstract: + +This following section documents the envirnoment variables for the Win NT +build. These variables are used to define the (virtual) hardware +configuration of the NT environment + +A ! can be used to seperate multiple instances in a variable. Each +instance represents a seperate hardware device. + +EFI_WIN_NT_PHYSICAL_DISKS - maps to drives on your system +EFI_WIN_NT_VIRTUAL_DISKS - maps to a device emulated by a file +EFI_WIN_NT_FILE_SYSTEM - mouts a directory as a file system +EFI_WIN_NT_CONSOLE - make a logical comand line window (only one!) +EFI_WIN_NT_UGA - Builds UGA Windows of Width and Height +EFI_WIN_NT_SERIAL_PORT - maps physical serial ports + + ixed - Fixed disk like a hard drive. + emovable - Removable media like a floppy or CD-ROM. + Read nly - Write protected device. + Read rite - Read write device. + - Decimal number of blocks a device supports. + - Decimal number of bytes per block. + + NT envirnonment variable contents. '<' and '>' are not part of the variable, + they are just used to make this help more readable. There should be no + spaces between the ';'. Extra spaces will break the variable. A '!' is + used to seperate multiple devices in a variable. + + EFI_WIN_NT_VIRTUAL_DISKS = + ;;[!...] + + EFI_WIN_NT_PHYSICAL_DISKS = + :;;[!...] + + Virtual Disks: These devices use a file to emulate a hard disk or removable + media device. + + Thus a 20 MB emulated hard drive would look like: + EFI_WIN_NT_VIRTUAL_DISKS=FW;40960;512 + + A 1.44MB emulated floppy with a block size of 1024 would look like: + EFI_WIN_NT_VIRTUAL_DISKS=RW;1440;1024 + + Physical Disks: These devices use NT to open a real device in your system + + Thus a 120 MB floppy would look like: + EFI_WIN_NT_PHYSICAL_DISKS=B:RW;245760;512 + + Thus a standard CD-ROM floppy would look like: + EFI_WIN_NT_PHYSICAL_DISKS=Z:RO;307200;2048 + + EFI_WIN_NT_FILE_SYSTEM = + [!...] + + Mounting the two directories C:\FOO and C:\BAR would look like: + EFI_WIN_NT_FILE_SYSTEM=c:\foo!c:\bar + + EFI_WIN_NT_CONSOLE = + + + Declaring a text console window with the title "My EFI Console" woild look like: + EFI_WIN_NT_CONSOLE=My EFI Console + + EFI_WIN_NT_UGA = + [!...] + + Declaring a two UGA windows with resolutions of 800x600 and 1024x768 would look like: + Example : EFI_WIN_NT_UGA=800 600!1024 768 + + EFI_WIN_NT_SERIAL_PORT = + [!...] + + Declaring two serial ports on COM1 and COM2 would look like: + Example : EFI_WIN_NT_SERIAL_PORT=COM1!COM2 + + EFI_WIN_NT_PASS_THROUGH = + ;;; + + Declaring a base address of 0xE0000000 (used for PCI Express devices) + and having NT32 talk to a device located at bus 0, device 1, function 0: + Example : EFI_WIN_NT_PASS_THROUGH=E000000;0;1;0 + +---*/ + +#include "WinNtBusDriver.h" +//#include "PciHostBridge.h" + +// +// Define GUID for the WinNt Bus Driver +// +static EFI_GUID gWinNtBusDriverGuid = { + 0x419f582, 0x625, 0x4531, 0x8a, 0x33, 0x85, 0xa9, 0x96, 0x5c, 0x95, 0xbc +}; + +// +// DriverBinding protocol global +// +EFI_DRIVER_BINDING_PROTOCOL gWinNtBusDriverBinding = { + WinNtBusDriverBindingSupported, + WinNtBusDriverBindingStart, + WinNtBusDriverBindingStop, + 0x10, + NULL, + NULL +}; + +#define NT_PCD_ARRAY_SIZE (sizeof(mPcdEnvironment)/sizeof(NT_PCD_ENTRY)) + +// +// Table to map NT Environment variable to the GUID that should be in +// device path. +// +static NT_PCD_ENTRY mPcdEnvironment[] = { + PcdToken(PcdWinNtConsole), &gEfiWinNtConsoleGuid, + PcdToken(PcdWinNtUga), &gEfiWinNtUgaGuid, + PcdToken(PcdWinNtSerialPort), &gEfiWinNtSerialPortGuid, + PcdToken(PcdWinNtFileSystem), &gEfiWinNtFileSystemGuid, + PcdToken(PcdWinNtVirtualDisk), &gEfiWinNtVirtualDisksGuid, + PcdToken(PcdWinNtPhysicalDisk), &gEfiWinNtPhysicalDisksGuid, + PcdToken(PcdWinNtCpuModel), &gEfiWinNtCPUModelGuid, + PcdToken(PcdWinNtCpuSpeed), &gEfiWinNtCPUSpeedGuid, + PcdToken(PcdWinNtMemorySize), &gEfiWinNtMemoryGuid +}; + +VOID * +AllocateMemory ( + IN UINTN Size + ) +{ + EFI_STATUS Status; + VOID *Buffer; + + Status = gBS->AllocatePool ( + EfiBootServicesData, + Size, + (VOID *)&Buffer + ); + if (EFI_ERROR (Status)) { + ASSERT (FALSE); + return NULL; + } + return Buffer; +} + + +EFI_STATUS +EFIAPI +WinNtBusDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: ControllerHandle - add argument and description to function comment +// TODO: RemainingDevicePath - add argument and description to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_WIN_NT_THUNK_PROTOCOL *WinNtThunk; + UINTN Index; + + // + // Check the contents of the first Device Path Node of RemainingDevicePath to make sure + // it is a legal Device Path Node for this bus driver's children. + // + if (RemainingDevicePath != NULL) { + if (RemainingDevicePath->Type != HARDWARE_DEVICE_PATH || + RemainingDevicePath->SubType != HW_VENDOR_DP || + DevicePathNodeLength(RemainingDevicePath) != sizeof(WIN_NT_VENDOR_DEVICE_PATH_NODE)) { + return EFI_UNSUPPORTED; + } + + for (Index = 0; Index < NT_PCD_ARRAY_SIZE; Index++) { + if (CompareGuid (&((VENDOR_DEVICE_PATH *) RemainingDevicePath)->Guid, mPcdEnvironment[Index].DevicePathGuid)) { + break; + } + } + + if (Index >= NT_PCD_ARRAY_SIZE) { + return EFI_UNSUPPORTED; + } + } + + // + // Open the IO Abstraction(s) needed to perform the supported test + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + &ParentDevicePath, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (Status == EFI_ALREADY_STARTED) { + return EFI_SUCCESS; + } + + if (EFI_ERROR (Status)) { + return Status; + } + + gBS->CloseProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiWinNtThunkProtocolGuid, + &WinNtThunk, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (Status == EFI_ALREADY_STARTED) { + return EFI_SUCCESS; + } + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Since we call through WinNtThunk we need to make sure it's valid + // + Status = EFI_SUCCESS; + if (WinNtThunk->Signature != EFI_WIN_NT_THUNK_PROTOCOL_SIGNATURE) { + Status = EFI_UNSUPPORTED; + } + + // + // Close the I/O Abstraction(s) used to perform the supported test + // + gBS->CloseProtocol ( + ControllerHandle, + &gEfiWinNtThunkProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + + return Status; +} + +EFI_STATUS +EFIAPI +WinNtBusDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: ControllerHandle - add argument and description to function comment +// TODO: RemainingDevicePath - add argument and description to function comment +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + EFI_STATUS InstallStatus; + EFI_WIN_NT_THUNK_PROTOCOL *WinNtThunk; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + WIN_NT_BUS_DEVICE *WinNtBusDevice; + WIN_NT_IO_DEVICE *WinNtDevice; + UINTN Index; + CHAR16 *StartString; + CHAR16 *SubString; + UINT16 Count; + UINTN StringSize; + UINT16 ComponentName[MAX_NT_ENVIRNMENT_VARIABLE_LENGTH]; + WIN_NT_VENDOR_DEVICE_PATH_NODE *Node; + BOOLEAN CreateDevice; + CHAR16 *TempStr; + CHAR16 *PcdTempStr; + UINTN TempStrSize; + + // + // Test Feature Set and Binary Patchable Case + // + if (FeaturePcdGet (PcdWinNtFeatureFlag1)) { + TempStrSize = PatchPcdGet32(PcdWinNtBinaryPatch1) + PatchPcdGet32(PcdWinNtBinaryPatch2); + } + + if (0) { + // + // Test Dynamic and DynamicEx + // (Please add PcdWinNtConsole in "WinNtBusDriver.inf" before enable this code!!!) + // + PcdTempStr = PcdGetPtr (PcdWinNtConsole); + } + + // + // Test Dynamic Set and Dynamic Set Ex + // + PcdSet32 (PcdWinNtDynamicUINT32, 2006); + + Status = EFI_UNSUPPORTED; + + // + // Grab the protocols we need + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + &ParentDevicePath, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { + return Status; + } + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiWinNtThunkProtocolGuid, + &WinNtThunk, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { + return Status; + } + + if (Status != EFI_ALREADY_STARTED) { + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (WIN_NT_BUS_DEVICE), + (VOID *) &WinNtBusDevice + ); + if (EFI_ERROR (Status)) { + return Status; + } + + WinNtBusDevice->Signature = WIN_NT_BUS_DEVICE_SIGNATURE; + WinNtBusDevice->ControllerNameTable = NULL; + + AddUnicodeString ( + "eng", + gWinNtBusDriverComponentName.SupportedLanguages, + &WinNtBusDevice->ControllerNameTable, + L"Windows Bus Controller" + ); + + Status = gBS->InstallMultipleProtocolInterfaces ( + &ControllerHandle, + &gWinNtBusDriverGuid, + WinNtBusDevice, + NULL + ); + if (EFI_ERROR (Status)) { + FreeUnicodeStringTable (WinNtBusDevice->ControllerNameTable); + gBS->FreePool (WinNtBusDevice); + return Status; + } + } + + // + // Loop on the Variable list. Parse each variable to produce a set of handles that + // represent virtual hardware devices. + // + InstallStatus = EFI_NOT_FOUND; + for (Index = 0; Index < NT_PCD_ARRAY_SIZE; Index++) { + PcdTempStr = (VOID *)LibPcdGetPtr (mPcdEnvironment[Index].Token); + ASSERT (PcdTempStr != NULL); + + TempStrSize = StrLen (PcdTempStr); + TempStr = AllocateMemory ((TempStrSize * sizeof (CHAR16)) + 1); + StrCpy (TempStr, PcdTempStr); + + StartString = TempStr; + + // + // Parse the envirnment variable into sub strings using '!' as a delimator. + // Each substring needs it's own handle to be added to the system. This code + // does not understand the sub string. Thats the device drivers job. + // + Count = 0; + while (*StartString != '\0') { + + // + // Find the end of the sub string + // + SubString = StartString; + while (*SubString != '\0' && *SubString != '!') { + SubString++; + } + + if (*SubString == '!') { + // + // Replace token with '\0' to make sub strings. If this is the end + // of the string SubString will already point to NULL. + // + *SubString = '\0'; + SubString++; + } + + CreateDevice = TRUE; + if (RemainingDevicePath != NULL) { + CreateDevice = FALSE; + Node = (WIN_NT_VENDOR_DEVICE_PATH_NODE *) RemainingDevicePath; + if (Node->VendorDevicePath.Header.Type == HARDWARE_DEVICE_PATH && + Node->VendorDevicePath.Header.SubType == HW_VENDOR_DP && + DevicePathNodeLength (&Node->VendorDevicePath.Header) == sizeof (WIN_NT_VENDOR_DEVICE_PATH_NODE) + ) { + if (CompareGuid (&Node->VendorDevicePath.Guid, mPcdEnvironment[Index].DevicePathGuid) && + Node->Instance == Count + ) { + CreateDevice = TRUE; + } + } + } + + if (CreateDevice) { + + // + // Allocate instance structure, and fill in parent information. + // + WinNtDevice = AllocateMemory (sizeof (WIN_NT_IO_DEVICE)); + if (WinNtDevice == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + WinNtDevice->Handle = NULL; + WinNtDevice->ControllerHandle = ControllerHandle; + WinNtDevice->ParentDevicePath = ParentDevicePath; + + WinNtDevice->WinNtIo.WinNtThunk = WinNtThunk; + + // + // Plus 2 to account for the NULL at the end of the Unicode string + // + StringSize = (UINTN) ((UINT8 *) SubString - (UINT8 *) StartString) + sizeof (CHAR16); + WinNtDevice->WinNtIo.EnvString = AllocateMemory (StringSize); + if (WinNtDevice->WinNtIo.EnvString != NULL) { + CopyMem (WinNtDevice->WinNtIo.EnvString, StartString, StringSize); + } + + WinNtDevice->ControllerNameTable = NULL; + + WinNtThunk->SPrintf (ComponentName, L"%s", WinNtDevice->WinNtIo.EnvString); + + WinNtDevice->DevicePath = WinNtBusCreateDevicePath ( + ParentDevicePath, + mPcdEnvironment[Index].DevicePathGuid, + Count + ); + if (WinNtDevice->DevicePath == NULL) { + gBS->FreePool (WinNtDevice); + return EFI_OUT_OF_RESOURCES; + } + + AddUnicodeString ( + "eng", + gWinNtBusDriverComponentName.SupportedLanguages, + &WinNtDevice->ControllerNameTable, + ComponentName + ); + + WinNtDevice->WinNtIo.TypeGuid = mPcdEnvironment[Index].DevicePathGuid; + WinNtDevice->WinNtIo.InstanceNumber = Count; + + WinNtDevice->Signature = WIN_NT_IO_DEVICE_SIGNATURE; + + Status = gBS->InstallMultipleProtocolInterfaces ( + &WinNtDevice->Handle, + &gEfiDevicePathProtocolGuid, + WinNtDevice->DevicePath, + &gEfiWinNtIoProtocolGuid, + &WinNtDevice->WinNtIo, + NULL + ); + if (EFI_ERROR (Status)) { + FreeUnicodeStringTable (WinNtDevice->ControllerNameTable); + gBS->FreePool (WinNtDevice); + } else { + // + // Open For Child Device + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiWinNtThunkProtocolGuid, + &WinNtThunk, + This->DriverBindingHandle, + WinNtDevice->Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + if (!EFI_ERROR (Status)) { + InstallStatus = EFI_SUCCESS; + } + } + } + + // + // Parse Next sub string. This will point to '\0' if we are at the end. + // + Count++; + StartString = SubString; + } + + gBS->FreePool (TempStr); + } + + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +WinNtBusDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: ControllerHandle - add argument and description to function comment +// TODO: NumberOfChildren - add argument and description to function comment +// TODO: ChildHandleBuffer - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + UINTN Index; + BOOLEAN AllChildrenStopped; + EFI_WIN_NT_IO_PROTOCOL *WinNtIo; + WIN_NT_BUS_DEVICE *WinNtBusDevice; + WIN_NT_IO_DEVICE *WinNtDevice; + EFI_WIN_NT_THUNK_PROTOCOL *WinNtThunk; + + // + // 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 ( + ControllerHandle, + &gWinNtBusDriverGuid, + &WinNtBusDevice, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + gBS->UninstallMultipleProtocolInterfaces ( + ControllerHandle, + &gWinNtBusDriverGuid, + WinNtBusDevice, + NULL + ); + + FreeUnicodeStringTable (WinNtBusDevice->ControllerNameTable); + + gBS->FreePool (WinNtBusDevice); + + gBS->CloseProtocol ( + ControllerHandle, + &gEfiWinNtThunkProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + + gBS->CloseProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + return EFI_SUCCESS; + } + + AllChildrenStopped = TRUE; + + for (Index = 0; Index < NumberOfChildren; Index++) { + + Status = gBS->OpenProtocol ( + ChildHandleBuffer[Index], + &gEfiWinNtIoProtocolGuid, + &WinNtIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + + WinNtDevice = WIN_NT_IO_DEVICE_FROM_THIS (WinNtIo); + + Status = gBS->CloseProtocol ( + ControllerHandle, + &gEfiWinNtThunkProtocolGuid, + This->DriverBindingHandle, + WinNtDevice->Handle + ); + + Status = gBS->UninstallMultipleProtocolInterfaces ( + WinNtDevice->Handle, + &gEfiDevicePathProtocolGuid, + WinNtDevice->DevicePath, + &gEfiWinNtIoProtocolGuid, + &WinNtDevice->WinNtIo, + NULL + ); + + if (EFI_ERROR (Status)) { + gBS->OpenProtocol ( + ControllerHandle, + &gEfiWinNtThunkProtocolGuid, + (VOID **) &WinNtThunk, + This->DriverBindingHandle, + WinNtDevice->Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + } else { + // + // Close the child handle + // + FreeUnicodeStringTable (WinNtDevice->ControllerNameTable); + gBS->FreePool (WinNtDevice); + } + } + + if (EFI_ERROR (Status)) { + AllChildrenStopped = FALSE; + } + } + + if (!AllChildrenStopped) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_DEVICE_PATH_PROTOCOL * +WinNtBusCreateDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *RootDevicePath, + IN EFI_GUID *Guid, + IN UINT16 InstanceNumber + ) +/*++ + +Routine Description: + Create a device path node using Guid and InstanceNumber and append it to + the passed in RootDevicePath + +Arguments: + RootDevicePath - Root of the device path to return. + + Guid - GUID to use in vendor device path node. + + InstanceNumber - Instance number to use in the vendor device path. This + argument is needed to make sure each device path is unique. + +Returns: + + EFI_DEVICE_PATH_PROTOCOL + +--*/ +{ + WIN_NT_VENDOR_DEVICE_PATH_NODE DevicePath; + + DevicePath.VendorDevicePath.Header.Type = HARDWARE_DEVICE_PATH; + DevicePath.VendorDevicePath.Header.SubType = HW_VENDOR_DP; + SetDevicePathNodeLength (&DevicePath.VendorDevicePath.Header, sizeof (WIN_NT_VENDOR_DEVICE_PATH_NODE)); + + // + // The GUID defines the Class + // + CopyMem (&DevicePath.VendorDevicePath.Guid, Guid, sizeof (EFI_GUID)); + + // + // Add an instance number so we can make sure there are no Device Path + // duplication. + // + DevicePath.Instance = InstanceNumber; + + return AppendDevicePathNode ( + RootDevicePath, + (EFI_DEVICE_PATH_PROTOCOL *) &DevicePath + ); +} diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/WinNtBusDriver/WinNtBusDriver.h b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/WinNtBusDriver/WinNtBusDriver.h new file mode 100644 index 0000000000..414465b8b2 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/WinNtBusDriver/WinNtBusDriver.h @@ -0,0 +1,297 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + WinNtBusDriver.h + +Abstract: + +This following section documents the envirnoment variables for the Win NT +build. These variables are used to define the (virtual) hardware +configuration of the NT environment + +A ! can be used to seperate multiple instances in a variable. Each +instance represents a seperate hardware device. + +EFI_WIN_NT_PHYSICAL_DISKS - maps to drives on your system +EFI_WIN_NT_VIRTUAL_DISKS - maps to a device emulated by a file +EFI_WIN_NT_FILE_SYSTEM - mouts a directory as a file system +EFI_WIN_NT_CONSOLE - make a logical comand line window (only one!) +EFI_WIN_NT_UGA - Builds UGA Windows of Width and Height +EFI_WIN_NT_SERIAL_PORT - maps physical serial ports +EFI_WIN_NT_PASS_THRU - associates a device with our PCI support + + ixed - Fixed disk like a hard drive. + emovable - Removable media like a floppy or CD-ROM. + Read nly - Write protected device. + Read rite - Read write device. + - Decimal number of blocks a device supports. + - Decimal number of bytes per block. + + NT envirnonment variable contents. '<' and '>' are not part of the variable, + they are just used to make this help more readable. There should be no + spaces between the ';'. Extra spaces will break the variable. A '!' is + used to seperate multiple devices in a variable. + + EFI_WIN_NT_VIRTUAL_DISKS = + ;;[!...] + + EFI_WIN_NT_PHYSICAL_DISKS = + :;;[!...] + + Virtual Disks: These devices use a file to emulate a hard disk or removable + media device. + + Thus a 20 MB emulated hard drive would look like: + EFI_WIN_NT_VIRTUAL_DISKS=FW;40960;512 + + A 1.44MB emulated floppy with a block size of 1024 would look like: + EFI_WIN_NT_VIRTUAL_DISKS=RW;1440;1024 + + Physical Disks: These devices use NT to open a real device in your system + + Thus a 120 MB floppy would look like: + EFI_WIN_NT_PHYSICAL_DISKS=B:RW;245760;512 + + Thus a standard CD-ROM floppy would look like: + EFI_WIN_NT_PHYSICAL_DISKS=Z:RO;307200;2048 + + EFI_WIN_NT_FILE_SYSTEM = + [!...] + + Mounting the two directories C:\FOO and C:\BAR would look like: + EFI_WIN_NT_FILE_SYSTEM=c:\foo!c:\bar + + EFI_WIN_NT_CONSOLE = + + + Declaring a text console window with the title "My EFI Console" woild look like: + EFI_WIN_NT_CONSOLE=My EFI Console + + EFI_WIN_NT_UGA = + [!...] + + Declaring a two UGA windows with resolutions of 800x600 and 1024x768 would look like: + Example : EFI_WIN_NT_UGA=800 600!1024 768 + + EFI_WIN_NT_SERIAL_PORT = + [!...] + + Declaring two serial ports on COM1 and COM2 would look like: + Example : EFI_WIN_NT_SERIAL_PORT=COM1!COM2 + + EFI_WIN_NT_PASS_THROUGH = + ;;; + + Declaring a base address of 0xE0000000 (used for PCI Express devices) + and having NT32 talk to a device located at bus 0, device 1, function 0: + Example : EFI_WIN_NT_PASS_THROUGH=E000000;0;1;0 + +---*/ + +#ifndef __NT_BUS_DRIVER_H__ +#define __NT_BUS_DRIVER_H__ + + + +// +// WinNt Bus Driver Global Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gWinNtBusDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gWinNtBusDriverComponentName; + +// +// WinNt Bus Controller Structure +// +#define WIN_NT_BUS_DEVICE_SIGNATURE EFI_SIGNATURE_32 ('N', 'T', 'B', 'D') + +typedef struct { + UINT64 Signature; + EFI_UNICODE_STRING_TABLE *ControllerNameTable; +} WIN_NT_BUS_DEVICE; + +// +// WinNt Child Device Controller Structure +// +#define WIN_NT_IO_DEVICE_SIGNATURE EFI_SIGNATURE_32 ('N', 'T', 'V', 'D') + +typedef struct { + UINT64 Signature; + EFI_HANDLE Handle; + EFI_WIN_NT_IO_PROTOCOL WinNtIo; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + // + // Private data about the parent + // + EFI_HANDLE ControllerHandle; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + + EFI_UNICODE_STRING_TABLE *ControllerNameTable; + +} WIN_NT_IO_DEVICE; + +#define WIN_NT_IO_DEVICE_FROM_THIS(a) \ + CR(a, WIN_NT_IO_DEVICE, WinNtIo, WIN_NT_IO_DEVICE_SIGNATURE) + +// +// This is the largest env variable we can parse +// +#define MAX_NT_ENVIRNMENT_VARIABLE_LENGTH 512 + +typedef struct { + UINTN Token; + EFI_GUID *DevicePathGuid; +} NT_PCD_ENTRY; + +typedef struct { + VENDOR_DEVICE_PATH VendorDevicePath; + UINT32 Instance; +} WIN_NT_VENDOR_DEVICE_PATH_NODE; + +EFI_STATUS +EFIAPI +CpuIoInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ImageHandle - TODO: add argument description + SystemTable - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +// +// Driver Binding Protocol function prototypes +// +EFI_STATUS +EFIAPI +WinNtBusDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Handle - TODO: add argument description + RemainingDevicePath - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +WinNtBusDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ParentHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + ParentHandle - TODO: add argument description + RemainingDevicePath - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +WinNtBusDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Handle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Handle - TODO: add argument description + NumberOfChildren - TODO: add argument description + ChildHandleBuffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +// +// WinNt Bus Driver private worker functions +// +EFI_DEVICE_PATH_PROTOCOL * +WinNtBusCreateDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *RootDevicePath, + IN EFI_GUID *Guid, + IN UINT16 InstanceNumber + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + RootDevicePath - TODO: add argument description + Guid - TODO: add argument description + InstanceNumber - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + + +#endif diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/WinNtBusDriver/WinNtBusDriver.mbd b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/WinNtBusDriver/WinNtBusDriver.mbd new file mode 100644 index 0000000000..eb50771993 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/WinNtBusDriver/WinNtBusDriver.mbd @@ -0,0 +1,43 @@ + + + + + WinNtBusDriver + BD7E9A27-D6C5-416a-B245-5F507D95B2BD + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-13 17:02 + 2006-03-19 15:17 + + + UefiBootServicesTableLib + BaseLib + UefiLib + UefiMemoryLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + DxePcdLib + DxeMemoryAllocationLib + UefiDevicePathLib + + diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/WinNtBusDriver/WinNtBusDriver.msa b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/WinNtBusDriver/WinNtBusDriver.msa new file mode 100644 index 0000000000..56ce4337bb --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/WinNtBusDriver/WinNtBusDriver.msa @@ -0,0 +1,167 @@ + + + + + WinNtBusDriver + UEFI_DRIVER + BS_DRIVER + BD7E9A27-D6C5-416a-B245-5F507D95B2BD + 0 + Component description file for WinNtBusDriver module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-13 17:02 + 2006-03-19 15:17 + + + DebugLib + BaseLib + UefiDriverModelLib + UefiDriverEntryPoint + UefiLib + PcdLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + DevicePathLib + + + WinNtBusDriver.h + WinNtBusDriver.c + ComponentName.c + + + MdePkg + EdkModulePkg + EdkNt32Pkg + + + WinNtIo + WinNtThunk + DevicePath + Pcd + + + + WinNtVirtualDisks + + + WinNtPhysicalDisks + + + WinNtFileSystem + + + WinNtSerialPort + + + WinNtUga + + + WinNtConsole + + + WinNtMemory + + + WinNtCPUModel + + + WinNtCPUSpeed + + + + + + + + gWinNtBusDriverBinding + gWinNtBusDriverComponentName + + + + + PcdWinNtConsole + 0x0000100a + VOID* + + + PcdWinNtUga + 0x00001003 + VOID* + + + PcdWinNtSerialPort + 0x00001002 + VOID* + + + PcdWinNtFileSystem + 0x00001004 + VOID* + + + PcdWinNtVirtualDisk + 0x00001001 + VOID* + + + PcdWinNtPhysicalDisk + 0x00001000 + VOID* + + + PcdWinNtCpuModel + 0x00001007 + VOID* + + + PcdWinNtCpuSpeed + 0x00001008 + VOID* + + + PcdWinNtMemorySize + 0x00001005 + VOID* + + + PcdWinNtBinaryPatch1 + 0x0001000b + UINT32 + + + PcdWinNtBinaryPatch2 + 0x0001000c + UINT32 + + + PcdWinNtFeatureFlag1 + 0x0001000d + BOOLEAN + + + PcdWinNtDynamicUINT32 + 0x0001000e + UINT32 + + + diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Bus/WinNtBusDriver/build.xml b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/WinNtBusDriver/build.xml new file mode 100644 index 0000000000..93d853bfd1 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Bus/WinNtBusDriver/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Metronome/Metronome.c b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Metronome/Metronome.c new file mode 100644 index 0000000000..394ca6e717 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Metronome/Metronome.c @@ -0,0 +1,129 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Metronome.c + +Abstract: + + NT Emulation Metronome Architectural Protocol Driver as defined in DXE CIS + +--*/ + +#include "Metronome.h" + +// +// Global Variables +// +EFI_METRONOME_ARCH_PROTOCOL mMetronome = { + WinNtMetronomeDriverWaitForTick, + TICK_PERIOD +}; + +// +// Worker Functions +// + +EFI_STATUS +EFIAPI +WinNtMetronomeDriverWaitForTick ( + IN EFI_METRONOME_ARCH_PROTOCOL *This, + IN UINT32 TickNumber + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + This - The EFI_METRONOME_ARCH_PROTOCOL instance. + TickNumber - Number of ticks to wait. + +Returns: + + EFI_SUCCESS - The wait for the number of ticks specified by TickNumber + succeeded. + +--*/ +{ + UINT64 SleepTime; + + // + // Calculate the time to sleep. Win API smallest unit to sleep is 1 millisec + // Tick Period is in 100ns units, divide by 10000 to convert to ms + // + SleepTime = DivU64x32 (MultU64x32 ((UINT64) TickNumber, TICK_PERIOD) + 9999, 10000); + gWinNt->Sleep ((UINT32) SleepTime); + + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +WinNtMetronomeDriverInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Initialize the Metronome Architectural Protocol driver + +Arguments: + + ImageHandle - ImageHandle of the loaded driver + + + SystemTable - Pointer to the System Table + +Returns: + + EFI_SUCCESS - Metronome Architectural Protocol created + + EFI_OUT_OF_RESOURCES - Not enough resources available to initialize driver. + + EFI_DEVICE_ERROR - A device error occured attempting to initialize the driver. + +--*/ +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + + + // + // Install the Metronome Architectural Protocol onto a new handle + // + Handle = NULL; + Status = gBS->InstallProtocolInterface ( + &Handle, + &gEfiMetronomeArchProtocolGuid, + EFI_NATIVE_INTERFACE, + &mMetronome + ); + + return Status; +} diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Metronome/Metronome.dxs b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Metronome/Metronome.dxs new file mode 100644 index 0000000000..d11f48a5c9 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Metronome/Metronome.dxs @@ -0,0 +1,27 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Metronome.dxs + +Abstract: + + Dependency expression source file. + +--*/ + +#include +#include + +DEPENDENCY_START + TRUE +DEPENDENCY_END diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Metronome/Metronome.h b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Metronome/Metronome.h new file mode 100644 index 0000000000..d89a149a1c --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Metronome/Metronome.h @@ -0,0 +1,84 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Metronome.h + +Abstract: + + NT Emulation Metronome Architectural Protocol Driver as defined in DXE CIS + +--*/ + +#ifndef _NT_THUNK_METRONOME_H_ +#define _NT_THUNK_METRONOME_H_ + + + +// +// Period of on tick in 100 nanosecond units +// +#define TICK_PERIOD 2000 + +// +// Function Prototypes +// + +EFI_STATUS +EFIAPI +WinNtMetronomeDriverInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ImageHandle - TODO: add argument description + SystemTable - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +WinNtMetronomeDriverWaitForTick ( + IN EFI_METRONOME_ARCH_PROTOCOL *This, + IN UINT32 TickNumber + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + TickNumber - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Metronome/Metronome.mbd b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Metronome/Metronome.mbd new file mode 100644 index 0000000000..f510b4250d --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Metronome/Metronome.mbd @@ -0,0 +1,45 @@ + + + + + Metronome + 154CAB4A-52B5-46CD-99C3-4368ABBACFFD + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-14 17:04 + 2006-03-19 15:17 + + + UefiBootServicesTableLib + DxeHobLib + BaseLib + UefiLib + UefiMemoryLib + UefiDriverEntryPoint + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + DxeWinNtLib + DxeMemoryAllocationLib + + + _ModuleEntryPoint + + diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Metronome/Metronome.msa b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Metronome/Metronome.msa new file mode 100644 index 0000000000..0966e8294c --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Metronome/Metronome.msa @@ -0,0 +1,61 @@ + + + + + Metronome + DXE_DRIVER + BS_DRIVER + 154CAB4A-52B5-46CD-99C3-4368ABBACFFD + 0 + Component description file for Metronome module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-14 17:04 + 2006-03-19 15:17 + + + BaseLib + DebugLib + UefiLib + UefiDriverEntryPoint + WinNtLib + MemoryAllocationLib + UefiBootServicesTableLib + + + Metronome.c + Metronome.h + Metronome.dxs + + + MdePkg + EdkModulePkg + EdkNt32Pkg + + + Metronome + + + + WinNtMetronomeDriverInitialize + + + diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Metronome/build.xml b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Metronome/build.xml new file mode 100644 index 0000000000..5922fac8f1 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Metronome/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/RealTimeClock/RealTimeClock.c b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/RealTimeClock/RealTimeClock.c new file mode 100644 index 0000000000..b705ee6874 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/RealTimeClock/RealTimeClock.c @@ -0,0 +1,391 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + RealTimeClock.c + +Abstract: + + NT Emulation Architectural Protocol Driver as defined in Tiano + +--*/ + + + +BOOLEAN +DayValid ( + IN EFI_TIME *Time + ); + +BOOLEAN +IsLeapYear ( + IN EFI_TIME *Time + ); + +EFI_STATUS +RtcTimeFieldsValid ( + IN EFI_TIME *Time + ); + +EFI_STATUS +EFIAPI +InitializeRealTimeClock ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +STATIC +EFI_STATUS +EFIAPI +WinNtGetTime ( + OUT EFI_TIME *Time, + OUT EFI_TIME_CAPABILITIES *Capabilities OPTIONAL + ) +/*++ + +Routine Description: + Service routine for RealTimeClockInstance->GetTime + +Arguments: + + Time - A pointer to storage that will receive a snapshot of the current time. + + Capabilities - A pointer to storage that will receive the capabilities of the real time clock + in the platform. This includes the real time clock's resolution and accuracy. + All reported device capabilities are rounded up. This is an OPTIONAL argument. + +Returns: + + EFI_SUCEESS - The underlying GetSystemTime call occurred and returned + Note that in the NT32 emulation, the GetSystemTime call has no return value + thus you will always receive a EFI_SUCCESS on this. + +--*/ +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +{ + SYSTEMTIME SystemTime; + TIME_ZONE_INFORMATION TimeZone; + + // + // Check parameter for null pointer + // + if (Time == NULL) { + return EFI_INVALID_PARAMETER; + + } + + gWinNt->GetLocalTime (&SystemTime); + gWinNt->GetTimeZoneInformation (&TimeZone); + + Time->Year = (UINT16) SystemTime.wYear; + Time->Month = (UINT8) SystemTime.wMonth; + Time->Day = (UINT8) SystemTime.wDay; + Time->Hour = (UINT8) SystemTime.wHour; + Time->Minute = (UINT8) SystemTime.wMinute; + Time->Second = (UINT8) SystemTime.wSecond; + Time->Nanosecond = (UINT32) (SystemTime.wMilliseconds * 1000000); + Time->TimeZone = (INT16) TimeZone.Bias; + + if (Capabilities != NULL) { + Capabilities->Resolution = 1; + Capabilities->Accuracy = 50000000; + Capabilities->SetsToZero = FALSE; + } + + Time->Daylight = 0; + if (TimeZone.StandardDate.wMonth) { + Time->Daylight = EFI_TIME_ADJUST_DAYLIGHT; + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +WinNtSetTime ( + IN EFI_TIME *Time + ) +/*++ + +Routine Description: + Service routine for RealTimeClockInstance->SetTime + +Arguments: + + Time - A pointer to storage containing the time and date information to + program into the real time clock. + +Returns: + + EFI_SUCEESS - The operation completed successfully. + + EFI_INVALID_PARAMETER - One of the fields in Time is out of range. + + EFI_DEVICE_ERROR - The operation could not be complete due to a device error. + +--*/ +// TODO: EFI_SUCCESS - add return value to function comment +{ + TIME_ZONE_INFORMATION TimeZone; + EFI_STATUS Status; + SYSTEMTIME SystemTime; + BOOL Flag; + + if (Time == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Make sure that the time fields are valid + // + Status = RtcTimeFieldsValid (Time); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Set Daylight savings time information and Time Zone + // + gWinNt->GetTimeZoneInformation (&TimeZone); + TimeZone.StandardDate.wMonth = Time->Daylight; + TimeZone.Bias = Time->TimeZone; + gWinNt->SetTimeZoneInformation (&TimeZone); + + SystemTime.wYear = Time->Year; + SystemTime.wMonth = Time->Month; + SystemTime.wDay = Time->Day; + SystemTime.wHour = Time->Hour; + SystemTime.wMinute = Time->Minute; + SystemTime.wSecond = Time->Second; + SystemTime.wMilliseconds = (INT16) (Time->Nanosecond / 1000000); + + Flag = gWinNt->SetLocalTime (&SystemTime); + + if (!Flag) { + return EFI_DEVICE_ERROR; + } else { + return EFI_SUCCESS; + } +} + +STATIC +EFI_STATUS +EFIAPI +WinNtGetWakeupTime ( + OUT BOOLEAN *Enabled, + OUT BOOLEAN *Pending, + OUT EFI_TIME *Time + ) +/*++ + +Routine Description: + Service routine for RealTimeClockInstance->GetWakeupTime + +Arguments: + This - Indicates the protocol instance structure. + + Enabled - Indicates if the alarm is currently enabled or disabled. + + Pending - Indicates if the alarm signal is pending and requires + acknowledgement. + + Time - The current alarm setting. + +Returns: + + EFI_SUCEESS - The operation completed successfully. + + EFI_DEVICE_ERROR - The operation could not be complete due to a device error. + + EFI_UNSUPPORTED - The operation is not supported on this platform. + +--*/ +{ + return EFI_UNSUPPORTED; +} + +STATIC +EFI_STATUS +EFIAPI +WinNtSetWakeupTime ( + IN BOOLEAN Enable, + OUT EFI_TIME *Time + ) +/*++ + +Routine Description: + Service routine for RealTimeClockInstance->SetWakeupTime + +Arguments: + + Enabled - Enable or disable the wakeup alarm. + + Time - If enable is TRUE, the time to set the wakup alarm for. + If enable is FALSE, then this parameter is optional, and + may be NULL. + +Returns: + + EFI_SUCEESS - The operation completed successfully. + + EFI_DEVICE_ERROR - The operation could not be complete due to a device error. + + EFI_INVALID_PARAMETER - A field in Time is out of range. + + EFI_UNSUPPORTED - The operation is not supported on this platform. + +--*/ +{ + return EFI_UNSUPPORTED; +} + +EFI_STATUS +EFIAPI +InitializeRealTimeClock ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + Install Real Time Clock Protocol + +Arguments: + (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT) + +Returns: + + EFI_SUCEESS - Real Time Clock Services are installed into the Runtime Services Table + +--*/ +// TODO: ImageHandle - add argument and description to function comment +// TODO: SystemTable - add argument and description to function comment +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + + + SystemTable->RuntimeServices->GetTime = WinNtGetTime; + SystemTable->RuntimeServices->SetTime = WinNtSetTime; + SystemTable->RuntimeServices->GetWakeupTime = WinNtGetWakeupTime; + SystemTable->RuntimeServices->SetWakeupTime = WinNtSetWakeupTime; + + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gEfiRealTimeClockArchProtocolGuid, + NULL, + NULL + ); + return Status; +} + +EFI_STATUS +RtcTimeFieldsValid ( + IN EFI_TIME *Time + ) +/*++ + +Routine Description: + + Arguments: + + Returns: +--*/ +// TODO: Time - add argument and description to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + if (Time->Year < 1998 || + Time->Year > 2099 || + Time->Month < 1 || + Time->Month > 12 || + (!DayValid (Time)) || + Time->Hour > 23 || + Time->Minute > 59 || + Time->Second > 59 || + Time->Nanosecond > 999999999 || + (!(Time->TimeZone == EFI_UNSPECIFIED_TIMEZONE || (Time->TimeZone >= -1440 && Time->TimeZone <= 1440))) || + (Time->Daylight & (~(EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT))) + ) { + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + +BOOLEAN +DayValid ( + IN EFI_TIME *Time + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Time - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + + INTN DayOfMonth[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + + if (Time->Day < 1 || + Time->Day > DayOfMonth[Time->Month - 1] || + (Time->Month == 2 && (!IsLeapYear (Time) && Time->Day > 28)) + ) { + return FALSE; + } + + return TRUE; +} + +BOOLEAN +IsLeapYear ( + IN EFI_TIME *Time + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Time - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + if (Time->Year % 4 == 0) { + if (Time->Year % 100 == 0) { + if (Time->Year % 400 == 0) { + return TRUE; + } else { + return FALSE; + } + } else { + return TRUE; + } + } else { + return FALSE; + } +} diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/RealTimeClock/RealTimeClock.dxs b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/RealTimeClock/RealTimeClock.dxs new file mode 100644 index 0000000000..01f441c562 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/RealTimeClock/RealTimeClock.dxs @@ -0,0 +1,27 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + RealTimeClock.dxs + +Abstract: + + Dependency expression source file. + +--*/ + +#include +#include + +DEPENDENCY_START + TRUE +DEPENDENCY_END diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/RealTimeClock/RealTimeClock.mbd b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/RealTimeClock/RealTimeClock.mbd new file mode 100644 index 0000000000..2eeac01ee9 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/RealTimeClock/RealTimeClock.mbd @@ -0,0 +1,45 @@ + + + + + RealTimeClock + 27F05AF5-1644-4EF4-8944-48C4F75675A0 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-14 17:04 + 2006-03-19 15:17 + + + UefiBootServicesTableLib + DxeHobLib + DxeWinNtLib + BaseLib + UefiLib + UefiMemoryLib + UefiDriverEntryPoint + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + DxeMemoryAllocationLib + + + _ModuleEntryPoint + + diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/RealTimeClock/RealTimeClock.msa b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/RealTimeClock/RealTimeClock.msa new file mode 100644 index 0000000000..fd0761a7a0 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/RealTimeClock/RealTimeClock.msa @@ -0,0 +1,60 @@ + + + + + RealTimeClock + DXE_DRIVER + BS_DRIVER + 27F05AF5-1644-4EF4-8944-48C4F75675A0 + 0 + Component description file for RealTimeClock module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-14 17:04 + 2006-03-19 15:17 + + + BaseLib + DebugLib + UefiLib + UefiDriverEntryPoint + WinNtLib + MemoryAllocationLib + UefiBootServicesTableLib + + + RealTimeClock.c + RealTimeClock.dxs + + + MdePkg + EdkModulePkg + EdkNt32Pkg + + + RealTimeClock + + + + InitializeRealTimeClock + + + diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/RealTimeClock/build.xml b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/RealTimeClock/build.xml new file mode 100644 index 0000000000..b649e11eb5 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/RealTimeClock/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Reset/Reset.dxs b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Reset/Reset.dxs new file mode 100644 index 0000000000..5dfb191aef --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Reset/Reset.dxs @@ -0,0 +1,27 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Reset.dxs + +Abstract: + + Dependency expression source file. + +--*/ + +#include +#include + +DEPENDENCY_START + TRUE +DEPENDENCY_END diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Reset/Reset.mbd b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Reset/Reset.mbd new file mode 100644 index 0000000000..817bc4ed18 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Reset/Reset.mbd @@ -0,0 +1,45 @@ + + + + + Reset + BA929954-35B0-4dd3-90CD-9634BD7E1CF1 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-14 17:04 + 2006-03-19 15:17 + + + UefiBootServicesTableLib + DxeHobLib + BaseLib + UefiLib + UefiMemoryLib + UefiDriverEntryPoint + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + DxeWinNtLib + DxeMemoryAllocationLib + + + _ModuleEntryPoint + + diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Reset/Reset.msa b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Reset/Reset.msa new file mode 100644 index 0000000000..8887df13d9 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Reset/Reset.msa @@ -0,0 +1,60 @@ + + + + + Reset + DXE_DRIVER + BS_DRIVER + BA929954-35B0-4dd3-90CD-9634BD7E1CF1 + 0 + description of file contents + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-14 17:04 + 2006-03-19 15:17 + + + BaseLib + DebugLib + UefiLib + UefiDriverEntryPoint + WinNtLib + MemoryAllocationLib + UefiBootServicesTableLib + + + Reset.c + Reset.dxs + + + MdePkg + EdkModulePkg + EdkNt32Pkg + + + Reset + + + + InitializeNtReset + + + diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Reset/build.xml b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Reset/build.xml new file mode 100644 index 0000000000..f924c6b261 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Reset/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Reset/reset.c b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Reset/reset.c new file mode 100644 index 0000000000..d1b841de39 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Reset/reset.c @@ -0,0 +1,121 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Reset.c + +Abstract: + + Reset Architectural Protocol as defined in Tiano under NT Emulation + +--*/ + + + +EFI_STATUS +EFIAPI +InitializeNtReset ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +STATIC +EFI_STATUS +EFIAPI +WinNtResetSystem ( + IN EFI_RESET_TYPE ResetType, + IN EFI_STATUS ResetStatus, + IN UINTN DataSize, + IN CHAR16 *ResetData OPTIONAL + ); + + +EFI_STATUS +EFIAPI +InitializeNtReset ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + +Arguments: + + ImageHandle of the loaded driver + Pointer to the System Table + +Returns: + + Status +--*/ +// TODO: SystemTable - add argument and description to function comment +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + + SystemTable->RuntimeServices->ResetSystem = WinNtResetSystem; + + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gEfiResetArchProtocolGuid, + NULL, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +STATIC +EFI_STATUS +EFIAPI +WinNtResetSystem ( + IN EFI_RESET_TYPE ResetType, + IN EFI_STATUS ResetStatus, + IN UINTN DataSize, + IN CHAR16 *ResetData OPTIONAL + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ResetType - TODO: add argument description + ResetStatus - TODO: add argument description + DataSize - TODO: add argument description + ResetData - TODO: add argument description + +Returns: + + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + // + // BUGBUG Need to kill all console windows later + // + // + // Discard ResetType, always return 0 as exit code + // + gWinNt->ExitProcess (0); + + // + // Should never go here + // + return EFI_SUCCESS; +} diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Timer/Timer.c b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Timer/Timer.c new file mode 100644 index 0000000000..18779a6b5e --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Timer/Timer.c @@ -0,0 +1,597 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Timer.c + +Abstract: + + NT Emulation Timer Architectural Protocol Driver as defined in DXE CIS + + This Timer module uses an NT Thread to simulate the timer-tick driven + timer service. In the future, the Thread creation should possibly be + abstracted by the CPU architectural protocol + +--*/ + +#include "Timer.h" + +// +// Pointer to the CPU Architectural Protocol instance +// +EFI_CPU_ARCH_PROTOCOL *mCpu; + +// +// The Timer Architectural Protocol that this driver produces +// +EFI_TIMER_ARCH_PROTOCOL mTimer = { + WinNtTimerDriverRegisterHandler, + WinNtTimerDriverSetTimerPeriod, + WinNtTimerDriverGetTimerPeriod, + WinNtTimerDriverGenerateSoftInterrupt +}; + +// +// Define a global that we can use to shut down the NT timer thread when +// the timer is canceled. +// +BOOLEAN mCancelTimerThread = FALSE; + +// +// The notification function to call on every timer interrupt +// +EFI_TIMER_NOTIFY mTimerNotifyFunction = NULL; + +// +// The current period of the timer interrupt +// +UINT64 mTimerPeriod; + +// +// The thread handle for this driver +// +HANDLE mNtMainThreadHandle; + +// +// The timer value from the last timer interrupt +// +UINT32 mNtLastTick; + +// +// Critical section used to update varibles shared between the main thread and +// the timer interrupt thread. +// +CRITICAL_SECTION mNtCriticalSection; + +// +// Worker Functions +// +UINT mMMTimerThreadID = 0; + +VOID +CALLBACK +MMTimerThread ( + UINT wTimerID, + UINT msg, + DWORD dwUser, + DWORD dw1, + DWORD dw2 + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + wTimerID - TODO: add argument description + msg - TODO: add argument description + dwUser - TODO: add argument description + dw1 - TODO: add argument description + dw2 - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + EFI_TPL OriginalTPL; + UINT32 CurrentTick; + UINT32 Delta; + EFI_TIMER_NOTIFY CallbackFunction; + BOOLEAN InterruptState; + + if (!mCancelTimerThread) { + + // + // Suspend the main thread until we are done + // + + gWinNt->SuspendThread (mNtMainThreadHandle); + + // + // If the timer thread is being canceled, then bail immediately. + // We check again here because there's a small window of time from when + // this thread was kicked off and when we suspended the main thread above. + // + if (mCancelTimerThread) { + gWinNt->ResumeThread (mNtMainThreadHandle); + gWinNt->timeKillEvent (wTimerID); + mMMTimerThreadID = 0; + return ; + } + + mCpu->GetInterruptState (mCpu, &InterruptState); + while (!InterruptState) { + // + // Resume the main thread + // + gWinNt->ResumeThread (mNtMainThreadHandle); + + // + // Wait for interrupts to be enabled. + // + mCpu->GetInterruptState (mCpu, &InterruptState); + while (!InterruptState) { + gWinNt->Sleep (0); + mCpu->GetInterruptState (mCpu, &InterruptState); + } + + // + // Suspend the main thread until we are done + // + gWinNt->SuspendThread (mNtMainThreadHandle); + mCpu->GetInterruptState (mCpu, &InterruptState); + } + + // + // Get the current system tick + // + CurrentTick = gWinNt->GetTickCount (); + Delta = CurrentTick - mNtLastTick; + mNtLastTick = CurrentTick; + + // + // If delay was more then 1 second, ignore it (probably debugging case) + // + if (Delta < 1000) { + + OriginalTPL = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL); + + // + // Inform the firmware of an "timer interrupt". The time + // expired since the last call is 10,000 times the number + // of ms. (or 100ns units) + // + gWinNt->EnterCriticalSection (&mNtCriticalSection); + CallbackFunction = mTimerNotifyFunction; + gWinNt->LeaveCriticalSection (&mNtCriticalSection); + + // + // Only invoke the callback function if a Non-NULL handler has been + // registered. Assume all other handlers are legal. + // + if (CallbackFunction != NULL) { + CallbackFunction ((UINT64) (Delta * 10000)); + } + + gBS->RestoreTPL (OriginalTPL); + + } + + // + // Resume the main thread + // + gWinNt->ResumeThread (mNtMainThreadHandle); + } else { + gWinNt->timeKillEvent (wTimerID); + mMMTimerThreadID = 0; + } + +} + +UINT +CreateNtTimer ( + VOID + ) +/*++ + +Routine Description: + + It is used to emulate a platform + timer-driver interrupt handler. + +Returns: + + Timer ID + +--*/ +// TODO: function comment is missing 'Arguments:' +{ + UINT32 SleepCount; + + // + // Set our thread priority higher than the "main" thread. + // + gWinNt->SetThreadPriority ( + gWinNt->GetCurrentThread (), + THREAD_PRIORITY_HIGHEST + ); + + // + // Calc the appropriate interval + // + gWinNt->EnterCriticalSection (&mNtCriticalSection); + SleepCount = (UINT32) (mTimerPeriod + 5000) / 10000; + gWinNt->LeaveCriticalSection (&mNtCriticalSection); + + return gWinNt->timeSetEvent ( + SleepCount, + 0, + MMTimerThread, + (DWORD_PTR) NULL, + TIME_PERIODIC | TIME_KILL_SYNCHRONOUS | TIME_CALLBACK_FUNCTION + ); + +} + +EFI_STATUS +EFIAPI +WinNtTimerDriverRegisterHandler ( + IN EFI_TIMER_ARCH_PROTOCOL *This, + IN EFI_TIMER_NOTIFY NotifyFunction + ) +/*++ + +Routine Description: + + This function registers the handler NotifyFunction so it is called every time + the timer interrupt fires. It also passes the amount of time since the last + handler call to the NotifyFunction. If NotifyFunction is NULL, then the + handler is unregistered. If the handler is registered, then EFI_SUCCESS is + returned. If the CPU does not support registering a timer interrupt handler, + then EFI_UNSUPPORTED 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 unregister a handler when a handler is not registered, + then EFI_INVALID_PARAMETER is returned. If an error occurs attempting to + register the NotifyFunction with the timer interrupt, then EFI_DEVICE_ERROR + is returned. + +Arguments: + + This - The EFI_TIMER_ARCH_PROTOCOL instance. + + NotifyFunction - The function to call when a timer interrupt fires. This + function executes at TPL_HIGH_LEVEL. The DXE Core will + register a handler for the timer interrupt, so it can know + how much time has passed. This information is used to + signal timer based events. NULL will unregister the handler. + +Returns: + + EFI_SUCCESS - The timer handler was registered. + + EFI_UNSUPPORTED - The platform does not support timer interrupts. + + EFI_ALREADY_STARTED - NotifyFunction is not NULL, and a handler is already + registered. + + EFI_INVALID_PARAMETER - NotifyFunction is NULL, and a handler was not + previously registered. + + EFI_DEVICE_ERROR - The timer handler could not be registered. + +--*/ +{ + // + // Check for invalid parameters + // + if (NotifyFunction == NULL && mTimerNotifyFunction == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (NotifyFunction != NULL && mTimerNotifyFunction != NULL) { + return EFI_ALREADY_STARTED; + } + + // + // Use Critical Section to update the notification function that is + // used from the timer interrupt thread. + // + gWinNt->EnterCriticalSection (&mNtCriticalSection); + + mTimerNotifyFunction = NotifyFunction; + + gWinNt->LeaveCriticalSection (&mNtCriticalSection); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +WinNtTimerDriverSetTimerPeriod ( + IN EFI_TIMER_ARCH_PROTOCOL *This, + IN UINT64 TimerPeriod + ) +/*++ + +Routine Description: + + This function adjusts the period of timer interrupts to the value specified + by TimerPeriod. If the timer period is updated, then the selected timer + period is stored in EFI_TIMER.TimerPeriod, and EFI_SUCCESS is returned. If + the timer hardware is not programmable, then EFI_UNSUPPORTED is returned. + If an error occurs while attempting to update the timer period, then the + timer hardware will be put back in its state prior to this call, and + EFI_DEVICE_ERROR is returned. If TimerPeriod is 0, then the timer interrupt + is disabled. This is not the same as disabling the CPU's interrupts. + Instead, it must either turn off the timer hardware, or it must adjust the + interrupt controller so that a CPU interrupt is not generated when the timer + interrupt fires. + +Arguments: + + This - The EFI_TIMER_ARCH_PROTOCOL instance. + + TimerPeriod - The rate to program the timer interrupt in 100 nS units. If + the timer hardware is not programmable, then EFI_UNSUPPORTED is + returned. If the timer is programmable, then the timer period + will be rounded up to the nearest timer period that is supported + by the timer hardware. If TimerPeriod is set to 0, then the + timer interrupts will be disabled. + +Returns: + + EFI_SUCCESS - The timer period was changed. + + EFI_UNSUPPORTED - The platform cannot change the period of the timer interrupt. + + EFI_DEVICE_ERROR - The timer period could not be changed due to a device error. + +--*/ +{ + + // + // If TimerPeriod is 0, then the timer thread should be canceled + // + if (TimerPeriod == 0) { + // + // Cancel the timer thread + // + gWinNt->EnterCriticalSection (&mNtCriticalSection); + + mCancelTimerThread = TRUE; + + gWinNt->LeaveCriticalSection (&mNtCriticalSection); + + // + // Wait for the timer thread to exit + // + + if (mMMTimerThreadID) { + gWinNt->timeKillEvent (mMMTimerThreadID); + } + + mMMTimerThreadID = 0; + + // + // Update the timer period + // + gWinNt->EnterCriticalSection (&mNtCriticalSection); + + mTimerPeriod = TimerPeriod; + + gWinNt->LeaveCriticalSection (&mNtCriticalSection); + + // + // NULL out the thread handle so it will be re-created if the timer is enabled again + // + + } else if ((TimerPeriod > TIMER_MINIMUM_VALUE) && (TimerPeriod < TIMER_MAXIMUM_VALUE)) { + // + // If the TimerPeriod is valid, then create and/or adjust the period of the timer thread + // + gWinNt->EnterCriticalSection (&mNtCriticalSection); + + mTimerPeriod = TimerPeriod; + + mCancelTimerThread = FALSE; + + gWinNt->LeaveCriticalSection (&mNtCriticalSection); + + // + // Get the starting tick location if we are just starting the timer thread + // + mNtLastTick = gWinNt->GetTickCount (); + + if (mMMTimerThreadID) { + gWinNt->timeKillEvent (mMMTimerThreadID); + } + + mMMTimerThreadID = 0; + + mMMTimerThreadID = CreateNtTimer (); + + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +WinNtTimerDriverGetTimerPeriod ( + IN EFI_TIMER_ARCH_PROTOCOL *This, + OUT UINT64 *TimerPeriod + ) +/*++ + +Routine Description: + + This function retrieves the period of timer interrupts in 100 ns units, + returns that value in TimerPeriod, and returns EFI_SUCCESS. If TimerPeriod + is NULL, then EFI_INVALID_PARAMETER is returned. If a TimerPeriod of 0 is + returned, then the timer is currently disabled. + +Arguments: + + This - The EFI_TIMER_ARCH_PROTOCOL instance. + + TimerPeriod - A pointer to the timer period to retrieve in 100 ns units. If + 0 is returned, then the timer is currently disabled. + +Returns: + + EFI_SUCCESS - The timer period was returned in TimerPeriod. + + EFI_INVALID_PARAMETER - TimerPeriod is NULL. + +--*/ +{ + if (TimerPeriod == NULL) { + return EFI_INVALID_PARAMETER; + } + + *TimerPeriod = mTimerPeriod; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +WinNtTimerDriverGenerateSoftInterrupt ( + IN EFI_TIMER_ARCH_PROTOCOL *This + ) +/*++ + +Routine Description: + + This function generates a soft timer interrupt. If the platform does not support soft + timer interrupts, then EFI_UNSUPPORTED is returned. Otherwise, EFI_SUCCESS is returned. + If a handler has been registered through the EFI_TIMER_ARCH_PROTOCOL.RegisterHandler() + service, then a soft timer interrupt will be generated. If the timer interrupt is + enabled when this service is called, then the registered handler will be invoked. The + registered handler should not be able to distinguish a hardware-generated timer + interrupt from a software-generated timer interrupt. + +Arguments: + + This - The EFI_TIMER_ARCH_PROTOCOL instance. + +Returns: + + EFI_SUCCESS - The soft timer interrupt was generated. + + EFI_UNSUPPORTEDT - The platform does not support the generation of soft timer interrupts. + +--*/ +{ + return EFI_UNSUPPORTED; +} + + +EFI_STATUS +EFIAPI +WinNtTimerDriverInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Initialize the Timer Architectural Protocol driver + +Arguments: + + ImageHandle - ImageHandle of the loaded driver + + SystemTable - Pointer to the System Table + +Returns: + + EFI_SUCCESS - Timer Architectural Protocol created + + EFI_OUT_OF_RESOURCES - Not enough resources available to initialize driver. + + EFI_DEVICE_ERROR - A device error occured attempting to initialize the driver. + +--*/ +{ + EFI_STATUS Status; + UINTN Result; + EFI_HANDLE Handle; + + // + // Make sure the Timer Architectural Protocol is not already installed in the system + // + ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiTimerArchProtocolGuid); + + // + // Get the CPU Architectural Protocol instance + // + Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, &mCpu); + ASSERT_EFI_ERROR (Status); + + // + // Get our handle so the timer tick thread can suspend + // + Result = gWinNt->DuplicateHandle ( + gWinNt->GetCurrentProcess (), + gWinNt->GetCurrentThread (), + gWinNt->GetCurrentProcess (), + &mNtMainThreadHandle, + 0, + FALSE, + DUPLICATE_SAME_ACCESS + ); + if (Result == 0) { + return EFI_DEVICE_ERROR; + } + + // + // Initialize Critical Section used to update variables shared between the main + // thread and the timer interrupt thread. + // + gWinNt->InitializeCriticalSection (&mNtCriticalSection); + + // + // Start the timer thread at the default timer period + // + Status = mTimer.SetTimerPeriod (&mTimer, DEFAULT_TIMER_TICK_DURATION); + if (EFI_ERROR (Status)) { + gWinNt->DeleteCriticalSection (&mNtCriticalSection); + return Status; + } + + // + // Install the Timer Architectural Protocol onto a new handle + // + Handle = NULL; + Status = gBS->InstallProtocolInterface ( + &Handle, + &gEfiTimerArchProtocolGuid, + EFI_NATIVE_INTERFACE, + &mTimer + ); + if (EFI_ERROR (Status)) { + // + // Cancel the timer + // + mTimer.SetTimerPeriod (&mTimer, 0); + gWinNt->DeleteCriticalSection (&mNtCriticalSection); + return Status; + } + + return EFI_SUCCESS; +} diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Timer/Timer.dxs b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Timer/Timer.dxs new file mode 100644 index 0000000000..6e6638331b --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Timer/Timer.dxs @@ -0,0 +1,28 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Timer.dxs + +Abstract: + + Dependency expression source file. + +--*/ + + +#include +#include + +DEPENDENCY_START + EFI_CPU_ARCH_PROTOCOL_GUID +DEPENDENCY_END diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Timer/Timer.h b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Timer/Timer.h new file mode 100644 index 0000000000..218ece65a5 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Timer/Timer.h @@ -0,0 +1,162 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Timer.h + +Abstract: + + NT Emulation Architectural Protocol Driver as defined in Tiano. + This Timer module uses an NT Thread to simulate the timer-tick driven + timer service. + +--*/ + +#ifndef _TIMER_H_ +#define _TIMER_H_ + + + + +// +// Legal timer value range in 100 ns units +// +#define TIMER_MINIMUM_VALUE 0 +#define TIMER_MAXIMUM_VALUE (0x100000000 - 1) + +// +// Default timer value in 100 ns units (10 ms) +// +#define DEFAULT_TIMER_TICK_DURATION 100000 + +// +// Function Prototypes +// +EFI_STATUS +EFIAPI +WinNtTimerDriverInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ImageHandle - TODO: add argument description + SystemTable - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +WinNtTimerDriverRegisterHandler ( + IN EFI_TIMER_ARCH_PROTOCOL *This, + IN EFI_TIMER_NOTIFY NotifyFunction + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + NotifyFunction - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +WinNtTimerDriverSetTimerPeriod ( + IN EFI_TIMER_ARCH_PROTOCOL *This, + IN UINT64 TimerPeriod + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + TimerPeriod - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +WinNtTimerDriverGetTimerPeriod ( + IN EFI_TIMER_ARCH_PROTOCOL *This, + OUT UINT64 *TimerPeriod + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + TimerPeriod - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +WinNtTimerDriverGenerateSoftInterrupt ( + IN EFI_TIMER_ARCH_PROTOCOL *This + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Timer/Timer.mbd b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Timer/Timer.mbd new file mode 100644 index 0000000000..3b8602d4f2 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Timer/Timer.mbd @@ -0,0 +1,46 @@ + + + + + Timer + C3811036-710B-4E39-8CF1-0AF9BE3A8198 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-14 17:04 + 2006-03-19 15:17 + + + UefiBootServicesTableLib + BaseDebugLibReportStatusCode + DxeHobLib + BaseLib + UefiLib + HiiLib + UefiMemoryLib + UefiDriverEntryPoint + DxeReportStatusCodeLib + DxeWinNtLib + DxeMemoryAllocationLib + + + _ModuleEntryPoint + + diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Timer/Timer.msa b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Timer/Timer.msa new file mode 100644 index 0000000000..d89ddf7433 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Timer/Timer.msa @@ -0,0 +1,62 @@ + + + + + Timer + DXE_DRIVER + BS_DRIVER + C3811036-710B-4E39-8CF1-0AF9BE3A8198 + 0 + Component description file for Timer module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-14 17:04 + 2006-03-19 15:17 + + + BaseLib + DebugLib + UefiLib + UefiDriverEntryPoint + WinNtLib + MemoryAllocationLib + UefiBootServicesTableLib + + + Timer.h + Timer.c + Timer.dxs + + + MdePkg + EdkModulePkg + EdkNt32Pkg + + + Timer + Cpu + + + + WinNtTimerDriverInitialize + + + diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Timer/build.xml b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Timer/build.xml new file mode 100644 index 0000000000..fac1fa4061 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Chipset/Timer/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Cpu/Cpu.c b/EdkNt32Pkg/Dxe/WinNtThunk/Cpu/Cpu.c new file mode 100644 index 0000000000..8633327263 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Cpu/Cpu.c @@ -0,0 +1,736 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Cpu.c + +Abstract: + + NT Emulation Architectural Protocol Driver as defined in Tiano. + This CPU module abstracts the interrupt subsystem of a platform and + the CPU-specific setjump/long pair. Other services are not implemented + in this driver. + +--*/ + +#include "CpuDriver.h" + +// +// This is the VFR compiler generated header file which defines the +// string identifiers. +// +#include STRING_DEFINES_FILE + +#define EFI_CPU_DATA_MAXIMUM_LENGTH 0x100 + +EFI_STATUS +EFIAPI +InitializeCpu ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +VOID +EFIAPI +WinNtIoProtocolNotifyFunction ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +typedef union { + EFI_CPU_DATA_RECORD *DataRecord; + UINT8 *Raw; +} EFI_CPU_DATA_RECORD_BUFFER; + +EFI_SUBCLASS_TYPE1_HEADER mCpuDataRecordHeader = { + EFI_PROCESSOR_SUBCLASS_VERSION, // Version + sizeof (EFI_SUBCLASS_TYPE1_HEADER), // Header Size + 0, // Instance, Initialize later + EFI_SUBCLASS_INSTANCE_NON_APPLICABLE, // SubInstance + 0 // RecordType, Initialize later +}; + +// +// Service routines for the driver +// +STATIC +EFI_STATUS +EFIAPI +WinNtFlushCpuDataCache ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS Start, + IN UINT64 Length, + IN EFI_CPU_FLUSH_TYPE FlushType + ) +/*++ + +Routine Description: + + This routine would provide support for flushing the CPU data cache. + In the case of NT emulation environment, this flushing is not necessary and + is thus not implemented. + +Arguments: + + Pointer to CPU Architectural Protocol interface + Start adddress in memory to flush + Length of memory to flush + Flush type + +Returns: + + Status + EFI_SUCCESS + +--*/ +// TODO: This - add argument and description to function comment +// TODO: FlushType - add argument and description to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +{ + if (FlushType == EfiCpuFlushTypeWriteBackInvalidate) { + // + // Only WB flush is supported. We actually need do nothing on NT emulator + // environment. Classify this to follow EFI spec + // + return EFI_SUCCESS; + } + // + // Other flush types are not supported by NT emulator + // + return EFI_UNSUPPORTED; +} + +STATIC +EFI_STATUS +EFIAPI +WinNtEnableInterrupt ( + IN EFI_CPU_ARCH_PROTOCOL *This + ) +/*++ + +Routine Description: + + This routine provides support for emulation of the interrupt enable of the + the system. For our purposes, CPU enable is just a BOOLEAN that the Timer + Architectural Protocol observes in order to defer behaviour while in its + emulated interrupt, or timer tick. + +Arguments: + + Pointer to CPU Architectural Protocol interface + +Returns: + + Status + EFI_SUCCESS + +--*/ +// TODO: This - add argument and description to function comment +{ + CPU_ARCH_PROTOCOL_PRIVATE *Private; + + Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This); + Private->InterruptState = TRUE; + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +WinNtDisableInterrupt ( + IN EFI_CPU_ARCH_PROTOCOL *This + ) +/*++ + +Routine Description: + + This routine provides support for emulation of the interrupt disable of the + the system. For our purposes, CPU enable is just a BOOLEAN that the Timer + Architectural Protocol observes in order to defer behaviour while in its + emulated interrupt, or timer tick. + +Arguments: + + Pointer to CPU Architectural Protocol interface + +Returns: + + Status + EFI_SUCCESS + +--*/ +// TODO: This - add argument and description to function comment +{ + CPU_ARCH_PROTOCOL_PRIVATE *Private; + + Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This); + Private->InterruptState = FALSE; + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +WinNtGetInterruptState ( + IN EFI_CPU_ARCH_PROTOCOL *This, + OUT BOOLEAN *State + ) +/*++ + +Routine Description: + + This routine provides support for emulation of the interrupt disable of the + the system. For our purposes, CPU enable is just a BOOLEAN that the Timer + Architectural Protocol observes in order to defer behaviour while in its + emulated interrupt, or timer tick. + +Arguments: + + Pointer to CPU Architectural Protocol interface + +Returns: + + Status + EFI_SUCCESS + +--*/ +// TODO: This - add argument and description to function comment +// TODO: State - add argument and description to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +{ + CPU_ARCH_PROTOCOL_PRIVATE *Private; + + if (State == NULL) { + return EFI_INVALID_PARAMETER; + } + + Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This); + *State = Private->InterruptState; + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +WinNtInit ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_CPU_INIT_TYPE InitType + ) +/*++ + +Routine Description: + + This routine would support generation of a CPU INIT. At + present, this code does not provide emulation. + +Arguments: + + Pointer to CPU Architectural Protocol interface + INIT Type + +Returns: + + Status + EFI_UNSUPPORTED - not yet implemented + +--*/ +// TODO: This - add argument and description to function comment +// TODO: InitType - add argument and description to function comment +{ + CPU_ARCH_PROTOCOL_PRIVATE *Private; + + Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This); + return EFI_UNSUPPORTED; +} + +STATIC +EFI_STATUS +EFIAPI +WinNtRegisterInterruptHandler ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler + ) +/*++ + +Routine Description: + + This routine would support registration of an interrupt handler. At + present, this code does not provide emulation. + +Arguments: + + Pointer to CPU Architectural Protocol interface + Pointer to interrupt handlers + Interrupt type + +Returns: + + Status + EFI_UNSUPPORTED - not yet implemented + +--*/ +// TODO: This - add argument and description to function comment +// TODO: InterruptType - add argument and description to function comment +// TODO: InterruptHandler - add argument and description to function comment +{ + CPU_ARCH_PROTOCOL_PRIVATE *Private; + + // + // Do parameter checking for EFI spec conformance + // + if (InterruptType < 0 || InterruptType > 0xff) { + return EFI_UNSUPPORTED; + } + // + // Do nothing for Nt32 emulation + // + Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This); + return EFI_UNSUPPORTED; +} + +STATIC +EFI_STATUS +EFIAPI +WinNtGetTimerValue ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN UINT32 TimerIndex, + OUT UINT64 *TimerValue, + OUT UINT64 *TimerPeriod OPTIONAL + ) +/*++ + +Routine Description: + + This routine would support querying of an on-CPU timer. At present, + this code does not provide timer emulation. + +Arguments: + + This - Pointer to CPU Architectural Protocol interface + TimerIndex - Index of given CPU timer + TimerValue - Output of the timer + TimerPeriod - Output of the timer period + +Returns: + + EFI_UNSUPPORTED - not yet implemented + EFI_INVALID_PARAMETER - TimeValue is NULL + +--*/ +{ + if (TimerValue == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // No timer supported + // + return EFI_UNSUPPORTED; +} + +STATIC +EFI_STATUS +EFIAPI +WinNtSetMemoryAttributes ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Attributes + ) +/*++ + +Routine Description: + + This routine would support querying of an on-CPU timer. At present, + this code does not provide timer emulation. + +Arguments: + + Pointer to CPU Architectural Protocol interface + Start address of memory region + The size in bytes of the memory region + The bit mask of attributes to set for the memory region + +Returns: + + Status + EFI_UNSUPPORTED - not yet implemented + +--*/ +// TODO: This - add argument and description to function comment +// TODO: BaseAddress - add argument and description to function comment +// TODO: Length - add argument and description to function comment +// TODO: Attributes - add argument and description to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +{ + CPU_ARCH_PROTOCOL_PRIVATE *Private; + + // + // Check for invalid parameter for Spec conformance + // + if (Length == 0) { + return EFI_INVALID_PARAMETER; + } + + // + // Do nothing for Nt32 emulation + // + Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This); + return EFI_UNSUPPORTED; +} + + +EFI_STATUS +EFIAPI +InitializeCpu ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Initialize the state information for the CPU Architectural Protocol + +Arguments: + + ImageHandle of the loaded driver + Pointer to the System Table + +Returns: + + Status + + EFI_SUCCESS - protocol instance can be published + EFI_OUT_OF_RESOURCES - cannot allocate protocol data structure + EFI_DEVICE_ERROR - cannot create the thread + +--*/ +// TODO: SystemTable - add argument and description to function comment +{ + EFI_STATUS Status; + EFI_EVENT Event; + CPU_ARCH_PROTOCOL_PRIVATE *Private; + VOID *Registration; + + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (CPU_ARCH_PROTOCOL_PRIVATE), + &Private + ); + ASSERT_EFI_ERROR (Status); + + Private->Signature = CPU_ARCH_PROT_PRIVATE_SIGNATURE; + Private->Cpu.FlushDataCache = WinNtFlushCpuDataCache; + Private->Cpu.EnableInterrupt = WinNtEnableInterrupt; + Private->Cpu.DisableInterrupt = WinNtDisableInterrupt; + Private->Cpu.GetInterruptState = WinNtGetInterruptState; + Private->Cpu.Init = WinNtInit; + Private->Cpu.RegisterInterruptHandler = WinNtRegisterInterruptHandler; + Private->Cpu.GetTimerValue = WinNtGetTimerValue; + Private->Cpu.SetMemoryAttributes = WinNtSetMemoryAttributes; + + Private->Cpu.NumberOfTimers = 0; + Private->Cpu.DmaBufferAlignment = 4; + + Private->InterruptState = TRUE; + + Private->CpuIo.Mem.Read = CpuMemoryServiceRead; + Private->CpuIo.Mem.Write = CpuMemoryServiceWrite; + Private->CpuIo.Io.Read = CpuIoServiceRead; + Private->CpuIo.Io.Write = CpuIoServiceWrite; + + + Private->Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &Private->Handle, + &gEfiCpuArchProtocolGuid, &Private->Cpu, + &gEfiCpuIoProtocolGuid, &Private->CpuIo, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // + // Install notify function to store processor data to HII database and data hub. + // + Status = gBS->CreateEvent ( + EFI_EVENT_NOTIFY_SIGNAL, + EFI_TPL_CALLBACK, + WinNtIoProtocolNotifyFunction, + ImageHandle, + &Event + ); + ASSERT (!EFI_ERROR (Status)); + + Status = gBS->RegisterProtocolNotify ( + &gEfiWinNtIoProtocolGuid, + Event, + &Registration + ); + ASSERT (!EFI_ERROR (Status)); + + // + // Should be at EFI_D_INFO, but lets us now things are running + // + DEBUG ((EFI_D_ERROR, "CPU Architectural Protocol Loaded\n")); + + + + return Status; +} + +UINTN +Atoi ( + CHAR16 *String + ) +/*++ + +Routine Description: + Convert a unicode string to a UINTN + +Arguments: + String - Unicode string. + +Returns: + UINTN of the number represented by String. + +--*/ +{ + UINTN Number; + CHAR16 *Str; + + // + // skip preceeding white space + // + Str = String; + while ((*Str) && (*Str == ' ' || *Str == '"')) { + Str++; + } + // + // Convert ot a Number + // + Number = 0; + while (*Str != '\0') { + if ((*Str >= '0') && (*Str <= '9')) { + Number = (Number * 10) +*Str - '0'; + } else { + break; + } + + Str++; + } + + return Number; +} + +VOID +EFIAPI +WinNtIoProtocolNotifyFunction ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + This function will log processor version and frequency data to data hub. + +Arguments: + Event - Event whose notification function is being invoked. + Context - Pointer to the notification function's context. + +Returns: + None. + +--*/ +{ + EFI_STATUS Status; + EFI_CPU_DATA_RECORD_BUFFER RecordBuffer; + EFI_DATA_RECORD_HEADER *Record; + EFI_SUBCLASS_TYPE1_HEADER *DataHeader; + UINT32 HeaderSize; + UINT32 TotalSize; + UINTN HandleCount; + UINTN HandleIndex; + UINT64 MonotonicCount; + BOOLEAN RecordFound; + EFI_HANDLE *HandleBuffer; + EFI_WIN_NT_IO_PROTOCOL *WinNtIo; + EFI_DATA_HUB_PROTOCOL *DataHub; + EFI_HII_PROTOCOL *Hii; + EFI_HII_HANDLE StringHandle; + EFI_HII_PACKAGES *PackageList; + STRING_REF Token; + + DataHub = NULL; + Token = 0; + MonotonicCount = 0; + RecordFound = FALSE; + + // + // Retrieve the list of all handles from the handle database + // + Status = gBS->LocateHandleBuffer ( + AllHandles, + &gEfiWinNtIoProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return ; + } + // + // Locate HII protocol + // + Status = gBS->LocateProtocol (&gEfiHiiProtocolGuid, NULL, &Hii); + if (EFI_ERROR (Status)) { + return ; + } + // + // Locate DataHub protocol. + // + Status = gBS->LocateProtocol (&gEfiDataHubProtocolGuid, NULL, &DataHub); + if (EFI_ERROR (Status)) { + return ; + } + // + // Initialize data record header + // + mCpuDataRecordHeader.Instance = 1; + HeaderSize = sizeof (EFI_SUBCLASS_TYPE1_HEADER); + + RecordBuffer.Raw = AllocatePool (HeaderSize + EFI_CPU_DATA_MAXIMUM_LENGTH); + if (RecordBuffer.Raw == NULL) { + return ; + } + + CopyMem (RecordBuffer.Raw, &mCpuDataRecordHeader, HeaderSize); + + // + // Search the Handle array to find the CPU model and speed information + // + for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) { + Status = gBS->OpenProtocol ( + HandleBuffer[HandleIndex], + &gEfiWinNtIoProtocolGuid, + &WinNtIo, + Context, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + continue; + } + + if ((WinNtIo->WinNtThunk->Signature == EFI_WIN_NT_THUNK_PROTOCOL_SIGNATURE) && + CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtCPUModelGuid) + ) { + // + // Check if this record has been stored in data hub + // + do { + Status = DataHub->GetNextRecord (DataHub, &MonotonicCount, NULL, &Record); + if (Record->DataRecordClass == EFI_DATA_RECORD_CLASS_DATA) { + DataHeader = (EFI_SUBCLASS_TYPE1_HEADER *) (Record + 1); + if (CompareGuid (&Record->DataRecordGuid, &gEfiProcessorSubClassGuid) && + (DataHeader->RecordType == ProcessorVersionRecordType) + ) { + RecordFound = TRUE; + } + } + } while (MonotonicCount != 0); + + if (RecordFound) { + RecordFound = FALSE; + continue; + } + // + // Initialize strings to HII database + // + PackageList = PreparePackages (1, &gEfiProcessorProducerGuid, STRING_ARRAY_NAME); + + Status = Hii->NewPack (Hii, PackageList, &StringHandle); + ASSERT (!EFI_ERROR (Status)); + + gBS->FreePool (PackageList); + + // + // Store processor version data record to data hub + // + Status = Hii->NewString (Hii, NULL, StringHandle, &Token, WinNtIo->EnvString); + ASSERT (!EFI_ERROR (Status)); + + RecordBuffer.DataRecord->DataRecordHeader.RecordType = ProcessorVersionRecordType; + RecordBuffer.DataRecord->VariableRecord.ProcessorVersion = Token; + TotalSize = HeaderSize + sizeof (EFI_PROCESSOR_VERSION_DATA); + + Status = DataHub->LogData ( + DataHub, + &gEfiProcessorSubClassGuid, + &gEfiProcessorProducerGuid, + EFI_DATA_RECORD_CLASS_DATA, + RecordBuffer.Raw, + TotalSize + ); + } + + if ((WinNtIo->WinNtThunk->Signature == EFI_WIN_NT_THUNK_PROTOCOL_SIGNATURE) && + CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtCPUSpeedGuid) + ) { + // + // Check if this record has been stored in data hub + // + do { + Status = DataHub->GetNextRecord (DataHub, &MonotonicCount, NULL, &Record); + if (Record->DataRecordClass == EFI_DATA_RECORD_CLASS_DATA) { + DataHeader = (EFI_SUBCLASS_TYPE1_HEADER *) (Record + 1); + if (CompareGuid (&Record->DataRecordGuid, &gEfiProcessorSubClassGuid) && + (DataHeader->RecordType == ProcessorCoreFrequencyRecordType) + ) { + RecordFound = TRUE; + } + } + } while (MonotonicCount != 0); + + if (RecordFound) { + RecordFound = FALSE; + continue; + } + // + // Store CPU frequency data record to data hub + // + RecordBuffer.DataRecord->DataRecordHeader.RecordType = ProcessorCoreFrequencyRecordType; + RecordBuffer.DataRecord->VariableRecord.ProcessorCoreFrequency.Value = (UINT16) Atoi (WinNtIo->EnvString); + RecordBuffer.DataRecord->VariableRecord.ProcessorCoreFrequency.Exponent = 6; + TotalSize = HeaderSize + sizeof (EFI_PROCESSOR_CORE_FREQUENCY_DATA); + + Status = DataHub->LogData ( + DataHub, + &gEfiProcessorSubClassGuid, + &gEfiProcessorProducerGuid, + EFI_DATA_RECORD_CLASS_DATA, + RecordBuffer.Raw, + TotalSize + ); + + gBS->FreePool (RecordBuffer.Raw); + } + + gBS->CloseProtocol ( + HandleBuffer[HandleIndex], + &gEfiWinNtIoProtocolGuid, + Context, + NULL + ); + } +} diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Cpu/Cpu.dxs b/EdkNt32Pkg/Dxe/WinNtThunk/Cpu/Cpu.dxs new file mode 100644 index 0000000000..4f87af4ca9 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Cpu/Cpu.dxs @@ -0,0 +1,28 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Cpu.dxs + +Abstract: + + Dependency expression source file. + +--*/ + +#include +#include + +DEPENDENCY_START + EFI_DATA_HUB_PROTOCOL_GUID AND + EFI_HII_PROTOCOL_GUID +DEPENDENCY_END diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Cpu/Cpu.mbd b/EdkNt32Pkg/Dxe/WinNtThunk/Cpu/Cpu.mbd new file mode 100644 index 0000000000..f2d25fecb0 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Cpu/Cpu.mbd @@ -0,0 +1,46 @@ + + + + + Cpu + ee993080-5197-4d4e-b63c-f1f7413e33ce + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-14 17:04 + 2006-03-23 16:17 + + + UefiBootServicesTableLib + BaseLib + UefiLib + HiiLib + UefiMemoryLib + UefiDriverEntryPoint + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + DxeMemoryAllocationLib + + + _ModuleEntryPoint + + + + diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Cpu/Cpu.msa b/EdkNt32Pkg/Dxe/WinNtThunk/Cpu/Cpu.msa new file mode 100644 index 0000000000..36fbd12401 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Cpu/Cpu.msa @@ -0,0 +1,86 @@ + + + + + Cpu + DXE_DRIVER + BS_DRIVER + ee993080-5197-4d4e-b63c-f1f7413e33ce + 0 + Component description file for Cpu module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-14 17:04 + 2006-03-23 16:17 + + + BaseLib + DebugLib + HiiLib + UefiLib + UefiDriverEntryPoint + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + + + Strings.uni + CpuDriver.h + Cpu.c + CpuIo.c + Cpu.dxs + + + MdePkg + EdkModulePkg + EdkNt32Pkg + + + Cpu + CpuIo + Hii + DataHub + WinNtIo + + + ProcessorVersion + ProcessorCoreFrequency + + + + ProcessorProducer + + + ProcessorSubClass + + + WinNtCPUModel + + + WinNtCPUSpeed + + + + + InitializeCpu + + + diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Cpu/CpuDriver.h b/EdkNt32Pkg/Dxe/WinNtThunk/Cpu/CpuDriver.h new file mode 100644 index 0000000000..e5b952f938 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Cpu/CpuDriver.h @@ -0,0 +1,97 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + CpuDriver.h + +Abstract: + + NT Emulation Architectural Protocol Driver as defined in Tiano. + +--*/ + +#ifndef _CPU_ARCHITECTURAL_PROTOCOL_DRIVER_H_ +#define _CPU_ARCHITECTURAL_PROTOCOL_DRIVER_H_ + + + +extern UINT8 STRING_ARRAY_NAME[]; + +// +// Internal Data Structures +// +#define CPU_ARCH_PROT_PRIVATE_SIGNATURE EFI_SIGNATURE_32 ('c', 'a', 'p', 'd') + +typedef struct { + UINTN Signature; + EFI_HANDLE Handle; + + EFI_CPU_ARCH_PROTOCOL Cpu; + EFI_CPU_IO_PROTOCOL CpuIo; + + // + // Local Data for CPU interface goes here + // + CRITICAL_SECTION NtCriticalSection; + BOOLEAN InterruptState; + +} CPU_ARCH_PROTOCOL_PRIVATE; + +#define CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS(a) \ + CR (a, \ + CPU_ARCH_PROTOCOL_PRIVATE, \ + Cpu, \ + CPU_ARCH_PROT_PRIVATE_SIGNATURE \ + ) + +EFI_STATUS +EFIAPI +CpuMemoryServiceRead ( + IN EFI_CPU_IO_PROTOCOL *This, + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +CpuMemoryServiceWrite ( + IN EFI_CPU_IO_PROTOCOL *This, + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +CpuIoServiceRead ( + IN EFI_CPU_IO_PROTOCOL *This, + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ); + +EFI_STATUS +EFIAPI +CpuIoServiceWrite ( + IN EFI_CPU_IO_PROTOCOL *This, + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ); + + +#endif diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Cpu/CpuIo.c b/EdkNt32Pkg/Dxe/WinNtThunk/Cpu/CpuIo.c new file mode 100644 index 0000000000..4aaa431d54 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Cpu/CpuIo.c @@ -0,0 +1,335 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + CpuIo.c + +Abstract: + + This is the code that publishes the CPU I/O Protocol. + The intent herein is to have a single I/O service that can load + as early as possible, extend into runtime, and be layered upon by + the implementations of architectural protocols and the PCI Root + Bridge I/O Protocol. + +--*/ + +#include + +#define IA32_MAX_IO_ADDRESS 0xFFFF +#define IA32_MAX_MEM_ADDRESS 0xFFFFFFFF + +EFI_CPU_IO_PROTOCOL mCpuIoProtocol; + +EFI_STATUS +CpuIoCheckAddressRange ( + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer, + IN UINT64 Limit + ); + +EFI_STATUS +EFIAPI +CpuMemoryServiceRead ( + IN EFI_CPU_IO_PROTOCOL *This, + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Perform the Memory Access Read service for the CPU I/O Protocol + +Arguments: + + Pointer to an instance of the CPU I/O Protocol + Width of the Memory Access + Address of the Memory access + Count of the number of accesses to perform + Pointer to the buffer to read or write from memory + +Returns: + + Status + + EFI_SUCCESS - The data was read from or written to the EFI + System. + EFI_INVALID_PARAMETER - Width is invalid for this EFI System. + EFI_INVALID_PARAMETER - Buffer is NULL. + EFI_UNSUPPORTED - The Buffer is not aligned for the given Width. + EFI_UNSUPPORTED - The address range specified by Address, Width, + and Count is not valid for this EFI System. + +--*/ +// TODO: This - add argument and description to function comment +{ + EFI_STATUS Status; + + if (!Buffer) { + return EFI_INVALID_PARAMETER; + } + + Status = CpuIoCheckAddressRange (Width, Address, Count, Buffer, IA32_MAX_MEM_ADDRESS); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Do nothing for Nt32 version + // + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +CpuMemoryServiceWrite ( + IN EFI_CPU_IO_PROTOCOL *This, + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Perform the Memory Access Read service for the CPU I/O Protocol + +Arguments: + + Pointer to an instance of the CPU I/O Protocol + Width of the Memory Access + Address of the Memory access + Count of the number of accesses to perform + Pointer to the buffer to read or write from memory + +Returns: + + Status + + EFI_SUCCESS - The data was read from or written to the EFI System. + EFI_INVALID_PARAMETER - Width is invalid for this EFI System. + EFI_INVALID_PARAMETER - Buffer is NULL. + EFI_UNSUPPORTED - The Buffer is not aligned for the given Width. + EFI_UNSUPPORTED - The address range specified by Address, Width, and + Count is not valid for this EFI System. + +--*/ +// TODO: This - add argument and description to function comment +{ + EFI_STATUS Status; + + if (!Buffer) { + return EFI_INVALID_PARAMETER; + } + + Status = CpuIoCheckAddressRange (Width, Address, Count, Buffer, IA32_MAX_MEM_ADDRESS); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Do nothing for Nt32 version + // + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +CpuIoServiceRead ( + IN EFI_CPU_IO_PROTOCOL *This, + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ) +/*++ + +Routine Description: + + This is the service that implements the I/O read + +Arguments: + + Pointer to an instance of the CPU I/O Protocol + Width of the Memory Access + Address of the I/O access + Count of the number of accesses to perform + Pointer to the buffer to read or write from I/O space + +Returns: + + Status + EFI_SUCCESS - The data was read from or written to the EFI System. + EFI_INVALID_PARAMETER - Width is invalid for this EFI System. + EFI_INVALID_PARAMETER - Buffer is NULL. + EFI_UNSUPPORTED - The Buffer is not aligned for the given Width. + EFI_UNSUPPORTED - The address range specified by Address, Width, and + Count is not valid for this EFI System. +--*/ +// TODO: This - add argument and description to function comment +// TODO: UserAddress - add argument and description to function comment +// TODO: UserBuffer - add argument and description to function comment +{ + UINTN Address; + EFI_STATUS Status; + + if (!UserBuffer) { + return EFI_INVALID_PARAMETER; + } + + Address = (UINTN) UserAddress; + + if (Width >= EfiCpuIoWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + Status = CpuIoCheckAddressRange (Width, Address, Count, UserBuffer, IA32_MAX_IO_ADDRESS); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Do nothing for Nt32 version + // + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +CpuIoServiceWrite ( + IN EFI_CPU_IO_PROTOCOL *This, + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ) +/*++ + +Routine Description: + + + This is the service that implements the I/O Write + +Arguments: + + Pointer to an instance of the CPU I/O Protocol + Width of the Memory Access + Address of the I/O access + Count of the number of accesses to perform + Pointer to the buffer to read or write from I/O space + +Returns: + + Status + + Status + EFI_SUCCESS - The data was read from or written to the EFI System. + EFI_INVALID_PARAMETER - Width is invalid for this EFI System. + EFI_INVALID_PARAMETER - Buffer is NULL. + EFI_UNSUPPORTED - The Buffer is not aligned for the given Width. + EFI_UNSUPPORTED - The address range specified by Address, Width, and + Count is not valid for this EFI System. + +--*/ +// TODO: This - add argument and description to function comment +// TODO: UserAddress - add argument and description to function comment +// TODO: UserBuffer - add argument and description to function comment +{ + UINTN Address; + EFI_STATUS Status; + + if (!UserBuffer) { + return EFI_INVALID_PARAMETER; + } + + Address = (UINTN) UserAddress; + + if (Width >= EfiCpuIoWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + Status = CpuIoCheckAddressRange (Width, Address, Count, UserBuffer, IA32_MAX_IO_ADDRESS); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Do nothing for Nt32 version + // + return EFI_SUCCESS; +} + + +EFI_STATUS +CpuIoCheckAddressRange ( + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer, + IN UINT64 Limit + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Width - TODO: add argument description + Address - TODO: add argument description + Count - TODO: add argument description + Buffer - TODO: add argument description + Limit - TODO: add argument description + +Returns: + + EFI_UNSUPPORTED - TODO: Add description for return value + EFI_UNSUPPORTED - TODO: Add description for return value + EFI_UNSUPPORTED - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + UINTN AlignMask; + + if (Address > Limit) { + return EFI_UNSUPPORTED; + } + + // + // For FiFo type, the target address won't increase during the access, so treat count as 1 + // + if (Width >= EfiCpuIoWidthFifoUint8 && Width <= EfiCpuIoWidthFifoUint64) { + Count = 1; + } + + Width = Width & 0x03; + if (Address - 1 + (1 << Width) * Count > Limit) { + return EFI_UNSUPPORTED; + } + + AlignMask = (1 << Width) - 1; + if ((UINTN) Buffer & AlignMask) { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + + diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Cpu/Strings.uni b/EdkNt32Pkg/Dxe/WinNtThunk/Cpu/Strings.uni new file mode 100644 index 0000000000000000000000000000000000000000..fd70fb906819c800344ee31e9373ce50fdef24ae GIT binary patch literal 2036 zcmchYU2hUm5QgVg6aT{oZfdn)yzrul7huXqTUoA6;+TFakTpLY&$0MkU1 zrrGSCnRDjMyz{xgf0eCli5=S;o>%q~uDo3n`($(bVJll$W@EdxC9+4>x7V!i?H$ht zdkbB&8D~SAKw$bzJ<3hUjyxK15;7`39*{c3xgV>LlNC}ukH`qG zLR5rFxA&ijUKPJ2!>8UC>V*)0-CuY%O6XdU_wqr0a&~(7GO&|_lM-5PdG~ET9T(9* zozCae6w!C=!cwBtw3apOoNvXh;A_-iLKSN5uv@dLT|=c_nb%flP1#qy1P!rjYfPsU ziMDHQKxsPYTVR!5X)Ul;ofoJ1_ODMwe}g93Z#cHZZqV0qAL{JaurF&3$Jv6Dm)aA$ z4ziLFz997(S>gP~`h^quC|v2Y7*wyQkP|0*<^>Rcy~xzQ(?KIaaZcap2ozd+{pFEDHRd4 zKz7e*&Kv$Y7tSrcM^}&7IH5z2*MGgB>!TGNskkEDs|h(?+m@G_0h;s$A}UJLCa0$h zeya!_qoA0mO22#7RHc{D=d5)qLzztBLyfC8+dQEvLYAWaJ8+D#9qkK2{PP}RMgQd{ VF`fHt%0Z&(lu!Z6qW;eX`vbS=1cU$p literal 0 HcmV?d00001 diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/Cpu/build.xml b/EdkNt32Pkg/Dxe/WinNtThunk/Cpu/build.xml new file mode 100644 index 0000000000..91fe4e49ad --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/Cpu/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/WinNtThunk/WinNtThunk.c b/EdkNt32Pkg/Dxe/WinNtThunk/WinNtThunk/WinNtThunk.c new file mode 100644 index 0000000000..b1f139f4c2 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/WinNtThunk/WinNtThunk.c @@ -0,0 +1,87 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + WinNtThunk.c + +Abstract: + + Produce WinNtThunk protocol and it's associated device path and controller + state protocols. WinNtThunk is to the NT emulation environment as + PCI_ROOT_BRIGE is to real hardware. The WinNtBusDriver is the child of this + driver. + + Since we are a root hardware abstraction we do not install a Driver Binding + protocol on this handle. This driver can only support one one WinNtThunk protocol + in the system, since the device path is hard coded. + +--*/ + +#include "WinNtThunk.h" + +// +// WinNtThunk Device Path Protocol Instance +// +static WIN_NT_THUNK_DEVICE_PATH mWinNtThunkDevicePath = { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + (UINT8) (sizeof (VENDOR_DEVICE_PATH)), + (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8), + EFI_WIN_NT_THUNK_PROTOCOL_GUID, + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + END_DEVICE_PATH_LENGTH, + 0 + } +}; + + +EFI_STATUS +EFIAPI +InitializeWinNtThunk ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + Install WinNtThunk Protocol and it's associated Device Path protocol + +Arguments: + (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT) + +Returns: + EFI_SUCEESS - WinNtThunk protocol is added or error status from + gBS->InstallMultiProtocolInterfaces(). + +--*/ +// TODO: ImageHandle - add argument and description to function comment +// TODO: SystemTable - add argument and description to function comment +{ + EFI_STATUS Status; + EFI_HANDLE ControllerHandle; + + ControllerHandle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &ControllerHandle, + &gEfiWinNtThunkProtocolGuid, + gWinNt, + &gEfiDevicePathProtocolGuid, + &mWinNtThunkDevicePath, + NULL + ); + + return Status; +} diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/WinNtThunk/WinNtThunk.dxs b/EdkNt32Pkg/Dxe/WinNtThunk/WinNtThunk/WinNtThunk.dxs new file mode 100644 index 0000000000..8a59515da7 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/WinNtThunk/WinNtThunk.dxs @@ -0,0 +1,27 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + WinNtThunk.dxs + +Abstract: + + Dependency expression source file. + +--*/ + +#include +#include + +DEPENDENCY_START + TRUE +DEPENDENCY_END diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/WinNtThunk/WinNtThunk.h b/EdkNt32Pkg/Dxe/WinNtThunk/WinNtThunk/WinNtThunk.h new file mode 100644 index 0000000000..6f474b3d29 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/WinNtThunk/WinNtThunk.h @@ -0,0 +1,30 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + WinNtThunk.h + +Abstract: + +--*/ + +// TODO: add protective #ifndef + + +// +// WinNtThunk Device Path Protocol Instance Type +// +typedef struct { + VENDOR_DEVICE_PATH Vendor; + EFI_DEVICE_PATH_PROTOCOL EndDevicePath; +} WIN_NT_THUNK_DEVICE_PATH; + diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/WinNtThunk/WinNtThunk.mbd b/EdkNt32Pkg/Dxe/WinNtThunk/WinNtThunk/WinNtThunk.mbd new file mode 100644 index 0000000000..01f9f6ddf8 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/WinNtThunk/WinNtThunk.mbd @@ -0,0 +1,45 @@ + + + + + WinNtThunk + 0C95A916-A006-11d4-BCFA-0080C73C8881 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-14 17:04 + 2006-03-19 15:17 + + + UefiBootServicesTableLib + BaseLib + DxeHobLib + UefiLib + UefiMemoryLib + UefiDriverEntryPoint + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + DxeWinNtLib + DxeMemoryAllocationLib + + + _ModuleEntryPoint + + diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/WinNtThunk/WinNtThunk.msa b/EdkNt32Pkg/Dxe/WinNtThunk/WinNtThunk/WinNtThunk.msa new file mode 100644 index 0000000000..6dbdfaba23 --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/WinNtThunk/WinNtThunk.msa @@ -0,0 +1,61 @@ + + + + + WinNtThunk + DXE_DRIVER + BS_DRIVER + 0C95A916-A006-11d4-BCFA-0080C73C8881 + 0 + Component description file for WinNtThunk module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-14 17:04 + 2006-03-19 15:17 + + + DebugLib + UefiLib + UefiDriverEntryPoint + WinNtLib + MemoryAllocationLib + UefiBootServicesTableLib + + + WinNtThunk.h + WinNtThunk.c + WinNtThunk.dxs + + + MdePkg + EdkModulePkg + EdkNt32Pkg + + + WinNtThunk + DevicePath + + + + InitializeWinNtThunk + + + diff --git a/EdkNt32Pkg/Dxe/WinNtThunk/WinNtThunk/build.xml b/EdkNt32Pkg/Dxe/WinNtThunk/WinNtThunk/build.xml new file mode 100644 index 0000000000..938e55f47d --- /dev/null +++ b/EdkNt32Pkg/Dxe/WinNtThunk/WinNtThunk/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkNt32Pkg/EdkNt32Pkg.spd b/EdkNt32Pkg/EdkNt32Pkg.spd new file mode 100644 index 0000000000..1667af21f7 --- /dev/null +++ b/EdkNt32Pkg/EdkNt32Pkg.spd @@ -0,0 +1,383 @@ + + + + + EdkNt32Pkg + 0fb2aa2d-10d5-40a5-a9dc-060c12a4a3f3 + 0 + This is the NT32 Emulation Environment Platform + Reference platform implementation using an emulator. + Copyright (c) 2006, Intel Corporation. + + All rights reserved. + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License which accompanies this distribution. + The full text of the license may be found at http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES + OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-02-22 13:25 + 2006-03-22 16:18 + http://www.TianoCore.org + SOURCE + true + false + + + + EdkGenericBdsLib + Include/Library/EdkGenericBdsLib.h + + + WinNtLib + Include/Library/WinNtLib.h + + + + + + Dxe/ConPlatform/ConPlatform.msa + + + Dxe/Nt32Platform/MiscSubclass/MiscSubclassDriver.msa + + + Dxe/PcdEmulator/PcdEmulator.msa + + + Dxe/PlatformBds/PlatformBds.msa + + + Dxe/WinNtThunk/Bus/BlockIo/WinNtBlockIo.msa + + + Dxe/WinNtThunk/Bus/Console/WinNtConsole.msa + + + Dxe/WinNtThunk/Bus/SerialIo/WinNtSerialIo.msa + + + Dxe/WinNtThunk/Bus/SimpleFileSystem/WinNtSimpleFileSystem.msa + + + Dxe/WinNtThunk/Bus/Uga/WinNtUga.msa + + + Dxe/WinNtThunk/Bus/WinNtBusDriver/WinNtBusDriver.msa + + + Dxe/WinNtThunk/Chipset/Metronome/Metronome.msa + + + Dxe/WinNtThunk/Chipset/RealTimeClock/RealTimeClock.msa + + + Dxe/WinNtThunk/Chipset/Reset/Reset.msa + + + Dxe/WinNtThunk/Chipset/Timer/Timer.msa + + + Dxe/WinNtThunk/Cpu/Cpu.msa + + + Dxe/WinNtThunk/WinNtThunk/WinNtThunk.msa + + + Library/DxeWinNtLib/DxeWinNtLib.msa + + + Library/EdkGenericBdsLib/EdkGenericBdsLib.msa + + + Library/EdkNt32PeiPeCoffGetEntryPointLib/EdkNt32PeiPeCoffGetEntryPointLib.msa + + + Library/Nt32PeCoffLoaderLib/Nt32PeCoffLoaderLib.msa + + + Logo/Logo.msa + + + Pei/Autoscan/WinNtAutoScan.msa + + + Pei/BootMode/BootMode.msa + + + Pei/FirmwareVolume/WinNtFwh.msa + + + Pei/FlashMap/FlashMap.msa + + + Pei/MonoStatusCode/Nt32/MonoStatusCode.msa + + + Pei/PcdEmulator/PcdEmulator.msa + + + Pei/WinNtStuff/WinNtStuff.msa + + + RuntimeDxe/FvbServices/Nt32Fwh.msa + + + Sec/SecMain.msa + + + + Include/WinNtPeim.h + Include/WinNtPeim.h + Include/WinNtDxe.h + Include/WinNtDxe.h + Include/WinNtDxe.h + Include/WinNtDxe.h + Include/WinNtDxe.h + + + + gEfiWinNtVirtualDisksGuid + 0xc95a928, 0xa006, 0x11d4, 0xbc, 0xfa, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81 + + + gEfiWinNtPhysicalDisksGuid + 0xc95a92f, 0xa006, 0x11d4, 0xbc, 0xfa, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81 + + + gEfiWinNtFileSystemGuid + 0xc95a935, 0xa006, 0x11d4, 0xbc, 0xfa, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81 + + + gEfiWinNtSerialPortGuid + 0xc95a93d, 0xa006, 0x11d4, 0xbc, 0xfa, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81 + + + gEfiWinNtUgaGuid + 0xab248e99, 0xabe1, 0x11d4, 0xbd, 0x0d, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81 + + + gEfiWinNtConsoleGuid + 0xba73672c, 0xa5d3, 0x11d4, 0xbd, 0x00, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81 + + + gEfiWinNtMemoryGuid + 0x99042912, 0x122a, 0x11d4, 0xbd, 0x0d, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81 + + + gEfiWinNtCPUModelGuid + 0xbee9b6ce, 0x2f8a, 0x11d4, 0xbd, 0x0d, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81 + + + gEfiWinNtCPUSpeedGuid + 0xd4f29055, 0xe1fb, 0x11d4, 0xbd, 0x0d, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81 + + + gEfiWinNtPassThroughGuid + 0xcc664eb8, 0x3c24, 0x4086, 0xb6, 0xf6, 0x34, 0xe8, 0x56, 0xbc, 0xe3, 0x6e + + + gPcdHobGuid + 0x582e7ca1, 0x68cd, 0x4d44, 0xb4, 0x3b, 0xf2, 0x98, 0xed, 0x58, 0x7b, 0xa6 + + + + + gEfiWinNtIoProtocolGuid + 0x96eb4ad6, 0xa32a, 0x11d4, 0xbc, 0xfd, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81 + + + gEfiWinNtThunkProtocolGuid + 0x58c518b1, 0x76f3, 0x11d4, 0xbc, 0xea, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81 + + + + + gPeiNtAutoScanPpiGuid + 0xdce384d, 0x7c, 0x4ba5, 0x94, 0xbd, 0x0f, 0x6e, 0xb6, 0x4d, 0x2a, 0xa9 + + + gNtFwhPpiGuid + 0x4e76928f, 0x50ad, 0x4334, 0xb0, 0x6b, 0xa8, 0x42, 0x13, 0x10, 0x8a, 0x57 + + + gNtPeiLoadFilePpiGuid + 0xfd0c65eb, 0x405, 0x4cd2, 0x8a, 0xee, 0xf4, 0x00, 0xef, 0x13, 0xba, 0xc2 + + + gPeiNtThunkPpiGuid + 0x98c281e5, 0xf906, 0x43dd, 0xa9, 0x2b, 0xb0, 0x03, 0xbf, 0x27, 0x65, 0xda + + + + + PcdMaximumUnicodeStringLength + 0x00000001 + UINT32 + 1000000 + + + PcdMaximumAsciiStringLength + 0x00000002 + UINT32 + 1000000 + + + PcdMaximumLinkedListLength + 0x00000003 + UINT32 + 1000000 + + + PcdSpinLockTimeout + 0x00000004 + UINT32 + 10000000 + + + PcdDebugPropertyMask + 0x00000005 + UINT8 + 0x0f + + + PcdDebugPrintErrorLevel + 0x00000006 + UINT32 + 0x80000000 + + + PcdReportStatusCodePropertyMask + 0x00000007 + UINT8 + 0x07 + + + PcdDebugClearMemoryValue + 0x00000008 + UINT8 + 0xAF + + + PcdDebugClearMemoryValue + 0x00000008 + UINT8 + 0xAF + + + PcdPerformanceLibraryPropertyMask + 0x00000009 + UINT8 + 0 + + + PcdWinNtPhysicalDisk + 0x00001000 + VOID* + L"FW;40960;512" + + + PcdWinNtVirtualDisk + 0x00001001 + VOID* + L"FW;40960;512" + + + PcdWinNtSerialPort + 0x00001002 + VOID* + L"COM1!COM2" + + + PcdWinNtUga + 0x00001003 + VOID* + L"UGA Window 1!UGA Window 2" + + + PcdWinNtFileSystem + 0x00001004 + VOID* + L".!C:\\D\\work\\Remodel\\mdk\\EdkShellBinPkg\\bin\\ia32\\Apps" + + + PcdWinNtMemorySize + 0x00001005 + VOID* + L"64!64" + + + PcdWinNtBootMode + 0x00001006 + UINT32 + 1 + + + PcdWinNtCpuModel + 0x00001007 + VOID* + L"Intel(R) Processor Model" + + + PcdWinNtCpuSpeed + 0x00001008 + VOID* + L"3000" + + + PcdWinNtFirmwareVolume + 0x00001009 + VOID* + L"..\\..\\Fv\\Fv_Recovery.fd" + + + PcdWinNtConsole + 0x0000100a + VOID* + L"Bus Driver Console Window" + + + PcdRothmanTest + 0x0000100b + UINT32 + 0 + + + PcdWinNtBinaryPatch1 + 0x0001000b + UINT32 + 0x1234 + + + PcdWinNtBinaryPatch2 + 0x0001000c + UINT32 + 0x5678 + + + PcdWinNtFeatureFlag1 + 0x0001000d + BOOLEAN + 0x1 + + + PcdWinNtDynamicUINT32 + 0x0001000e + UINT32 + 0x0 + + + diff --git a/EdkNt32Pkg/Include/Common/WinNTInclude.h b/EdkNt32Pkg/Include/Common/WinNTInclude.h new file mode 100644 index 0000000000..a8d31c3518 --- /dev/null +++ b/EdkNt32Pkg/Include/Common/WinNTInclude.h @@ -0,0 +1,71 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + WinNtLib.h + +Abstract: + Public include file for the WinNt Library + +--*/ + +#ifndef __WIN_NT_INCLUDE_H__ +#define __WIN_NT_INCLUDE_H__ + +// +// Win32 include files do not compile clean with /W4, so we use the warning +// pragma to suppress the warnings for Win32 only. This way our code can stil +// compile at /W4 (highest warning level) with /WX (warnings cause build +// errors). +// +#pragma warning(disable : 4115) +#pragma warning(disable : 4201) +#pragma warning(disable : 4214) +#pragma warning(disable : 4028) +#pragma warning(disable : 4133) + +#define GUID _WINNT_DUP_GUID_____ +#define _LIST_ENTRY _WINNT_DUP_LIST_ENTRY_FORWARD +#define LIST_ENTRY _WINNT_DUP_LIST_ENTRY +#define InterlockedIncrement _WINNT_DUP_InterlockedIncrement +#define InterlockedDecrement _WINNT_DUP_InterlockedDecrement +#define InterlockedCompareExchange64 _WINNT_DUP_InterlockedCompareExchange64 +#undef UNALIGNED +#undef CONST +#undef VOID + +#include "windows.h" + +#undef GUID +#undef _LIST_ENTRY +#undef LIST_ENTRY +#undef InterlockedIncrement +#undef InterlockedDecrement +#undef InterlockedCompareExchange64 +#undef InterlockedCompareExchangePointer + +#define VOID void + +// +// Prevent collisions with Windows API name macros that deal with Unicode/Not issues +// +#undef LoadImage +#undef CreateEvent + +// +// Set the warnings back on as the EFI code must be /W4. +// +#pragma warning(default : 4115) +#pragma warning(default : 4201) +#pragma warning(default : 4214) + + +#endif diff --git a/EdkNt32Pkg/Include/FlashLayout.h b/EdkNt32Pkg/Include/FlashLayout.h new file mode 100644 index 0000000000..5a95961709 --- /dev/null +++ b/EdkNt32Pkg/Include/FlashLayout.h @@ -0,0 +1,64 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FlashLayout.h + +Abstract: + + Platform specific flash layout + + BugBug: We need a better way + +--*/ + +#ifndef __EFI_FLASH_LAYOUT__ +#define __EFI_FLASH_LAYOUT__ + +// +// Firmware Volume Information for Nt32 +// adding one working block before FFS FV, +// and another one for spare block behind FFS FV +// +// +// Note: When block number is changed in .dsc file, +// this value should be changed accordingly!!! +// +#define FIRMWARE_BLOCK_NUMBER 0x28 + +#define EFI_WINNT_FIRMWARE_OFFSET 0x0 +#define EFI_WINNT_FIRMWARE_LENGTH (0x10000 * FIRMWARE_BLOCK_NUMBER) + +#define EFI_WINNT_RUNTIME_UPDATABLE_OFFSET (EFI_WINNT_FIRMWARE_OFFSET + EFI_WINNT_FIRMWARE_LENGTH) + +#define EFI_WINNT_RUNTIME_UPDATABLE_LENGTH 0x10000 + +#define EFI_WINNT_FTW_SPARE_BLOCK_OFFSET (EFI_WINNT_RUNTIME_UPDATABLE_OFFSET + EFI_WINNT_RUNTIME_UPDATABLE_LENGTH) + +#define EFI_WINNT_FTW_SPARE_BLOCK_LENGTH 0x10000 + +#define EFI_WINNT_RUNTIME_UPDATABLE_FV_HEADER_LENGTH 0x48 + +#define EFI_VARIABLE_STORE_OFFSET (EFI_WINNT_RUNTIME_UPDATABLE_OFFSET + EFI_WINNT_RUNTIME_UPDATABLE_FV_HEADER_LENGTH) + +#define EFI_VARIABLE_STORE_LENGTH (0x00C000 - EFI_WINNT_RUNTIME_UPDATABLE_FV_HEADER_LENGTH) + +#define EFI_EVENT_LOG_OFFSET (EFI_VARIABLE_STORE_OFFSET + EFI_VARIABLE_STORE_LENGTH) + +#define EFI_EVENT_LOG_LENGTH 0x002000 + +#define EFI_FTW_WORKING_OFFSET (EFI_EVENT_LOG_OFFSET + EFI_EVENT_LOG_LENGTH) + +#define EFI_FTW_WORKING_LENGTH 0x002000 + +#endif + diff --git a/EdkNt32Pkg/Include/Ppi/NtAutoscan.h b/EdkNt32Pkg/Include/Ppi/NtAutoscan.h new file mode 100644 index 0000000000..6098819f3f --- /dev/null +++ b/EdkNt32Pkg/Include/Ppi/NtAutoscan.h @@ -0,0 +1,66 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + NtAutoscan.h + +Abstract: + +Nt Autoscan PPI + +--*/ + +#ifndef __NT_PEI_AUTOSCAN_H__ +#define __NT_PEI_AUTOSCAN_H__ + +#include + +#define PEI_NT_AUTOSCAN_PPI_GUID \ + { \ + 0xdce384d, 0x7c, 0x4ba5, {0x94, 0xbd, 0xf, 0x6e, 0xb6, 0x4d, 0x2a, 0xa9 } \ + } + +typedef +EFI_STATUS +(EFIAPI *PEI_NT_AUTOSCAN) ( + IN UINTN Index, + OUT EFI_PHYSICAL_ADDRESS * MemoryBase, + OUT UINT64 *MemorySize + ); + +/*++ + +Routine Description: + This service is called from Index == 0 until it returns EFI_UNSUPPORTED. + It allows discontiguous memory regions to be supported by the emulator. + It uses gSystemMemory[] and gSystemMemoryCount that were created by + parsing the Windows environment variable EFI_MEMORY_SIZE. + The size comes from the varaible and the address comes from the call to + WinNtOpenFile. + +Arguments: + Index - Which memory region to use + MemoryBase - Return Base address of memory region + MemorySize - Return size in bytes of the memory region + +Returns: + EFI_SUCCESS - If memory region was mapped + EFI_UNSUPPORTED - If Index is not supported + +--*/ +typedef struct { + PEI_NT_AUTOSCAN NtAutoScan; +} PEI_NT_AUTOSCAN_PPI; + +extern EFI_GUID gPeiNtAutoScanPpiGuid; + +#endif diff --git a/EdkNt32Pkg/Include/Ppi/NtFwh.h b/EdkNt32Pkg/Include/Ppi/NtFwh.h new file mode 100644 index 0000000000..90b41094cf --- /dev/null +++ b/EdkNt32Pkg/Include/Ppi/NtFwh.h @@ -0,0 +1,62 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + NtFwh.h + +Abstract: + + WinNt FWH PPI as defined in Tiano + +--*/ + +#ifndef __NT_PEI_FWH_H__ +#define __NT_PEI_FWH_H__ + +#include + +#define NT_FWH_PPI_GUID \ + { \ + 0x4e76928f, 0x50ad, 0x4334, {0xb0, 0x6b, 0xa8, 0x42, 0x13, 0x10, 0x8a, 0x57 } \ + } + +typedef +EFI_STATUS +(EFIAPI *NT_FWH_INFORMATION) ( + IN UINTN Index, + IN OUT EFI_PHYSICAL_ADDRESS * FdBase, + IN OUT UINT64 *FdSize + ); + +/*++ + +Routine Description: + Return the FD Size and base address. Since the FD is loaded from a + file into Windows memory only the SEC will know it's address. + +Arguments: + Index - Which FD, starts at zero. + FdSize - Size of the FD in bytes + FdBase - Start address of the FD. Assume it points to an FV Header + +Returns: + EFI_SUCCESS - Return the Base address and size of the FV + EFI_UNSUPPORTED - Index does nto map to an FD in the system + +--*/ +typedef struct { + NT_FWH_INFORMATION NtFwh; +} NT_FWH_PPI; + +extern EFI_GUID gNtFwhPpiGuid; + +#endif diff --git a/EdkNt32Pkg/Include/Ppi/NtPeiLoadFile.h b/EdkNt32Pkg/Include/Ppi/NtPeiLoadFile.h new file mode 100644 index 0000000000..622e01a145 --- /dev/null +++ b/EdkNt32Pkg/Include/Ppi/NtPeiLoadFile.h @@ -0,0 +1,65 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + NtPeiLoadFile.h + +Abstract: + + WinNt Load File PPI. + + When the PEI core is done it calls the DXE IPL via PPI + +--*/ + +#ifndef __NT_PEI_LOAD_FILE_H__ +#define __NT_PEI_LOAD_FILE_H__ + +#include + +#define NT_PEI_LOAD_FILE_GUID \ + { \ + 0xfd0c65eb, 0x405, 0x4cd2, {0x8a, 0xee, 0xf4, 0x0, 0xef, 0x13, 0xba, 0xc2 } \ + } + +typedef +EFI_STATUS +(EFIAPI *NT_PEI_LOAD_FILE) ( + VOID *Pe32Data, + EFI_PHYSICAL_ADDRESS *ImageAddress, + UINT64 *ImageSize, + EFI_PHYSICAL_ADDRESS *EntryPoint + ); + +/*++ + +Routine Description: + Loads and relocates a PE/COFF image into memory. + +Arguments: + Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated + ImageAddress - The base address of the relocated PE/COFF image + ImageSize - The size of the relocated PE/COFF image + EntryPoint - The entry point of the relocated PE/COFF image + +Returns: + EFI_SUCCESS - The file was loaded and relocated + EFI_OUT_OF_RESOURCES - There was not enough memory to load and relocate the PE/COFF file + +--*/ +typedef struct { + NT_PEI_LOAD_FILE PeiLoadFileService; +} NT_PEI_LOAD_FILE_PPI; + +extern EFI_GUID gNtPeiLoadFilePpiGuid; + +#endif diff --git a/EdkNt32Pkg/Include/Ppi/NtThunk.h b/EdkNt32Pkg/Include/Ppi/NtThunk.h new file mode 100644 index 0000000000..782c510a30 --- /dev/null +++ b/EdkNt32Pkg/Include/Ppi/NtThunk.h @@ -0,0 +1,56 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + NtThunk.h + +Abstract: + + WinNt Thunk interface PPI + +--*/ + +#ifndef __NT_PEI_WIN_NT_THUNK_H__ +#define __NT_PEI_WIN_NT_THUNK_H__ + +#include + +#define PEI_NT_THUNK_PPI_GUID \ + { \ + 0x98c281e5, 0xf906, 0x43dd, {0xa9, 0x2b, 0xb0, 0x3, 0xbf, 0x27, 0x65, 0xda } \ + } + +typedef +VOID * +(EFIAPI *PEI_NT_THUNK_INTERFACE) ( + VOID + ); + +/*++ + +Routine Description: + Export of EFI_WIN_NT_THUNK_PROTOCOL from the Windows SEC. + +Arguments: + InterfaceBase - Address of the EFI_WIN_NT_THUNK_PROTOCOL + +Returns: + EFI_SUCCESS - Data returned + +--*/ +typedef struct { + PEI_NT_THUNK_INTERFACE NtThunk; +} PEI_NT_THUNK_PPI; + +extern EFI_GUID gPeiNtThunkPpiGuid; + +#endif diff --git a/EdkNt32Pkg/Include/Protocol/WinNtIo.h b/EdkNt32Pkg/Include/Protocol/WinNtIo.h new file mode 100644 index 0000000000..85d99feac9 --- /dev/null +++ b/EdkNt32Pkg/Include/Protocol/WinNtIo.h @@ -0,0 +1,141 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + WinNtIo.h + +Abstract: + +--*/ + +#ifndef __WIN_NT_IO_H__ +#define __WIN_NT_IO_H__ + +#define EFI_WIN_NT_IO_PROTOCOL_GUID \ + { 0x96eb4ad6, 0xa32a, 0x11d4, { 0xbc, 0xfd, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } } + +typedef struct { + EFI_WIN_NT_THUNK_PROTOCOL *WinNtThunk; + EFI_GUID *TypeGuid; + CHAR16 *EnvString; + UINT16 InstanceNumber; +} EFI_WIN_NT_IO_PROTOCOL; + + +extern EFI_GUID gEfiWinNtIoProtocolGuid; + +// +// The following GUIDs are used in EFI_WIN_NT_IO_PROTOCOL_GUID +// Device paths. They map 1:1 with NT envirnment variables. The variables +// define what virtual hardware the emulator/WinNtBusDriver will produce. +// +// +// EFI_WIN_NT_VIRTUAL_DISKS +// +#define EFI_WIN_NT_VIRTUAL_DISKS_GUID \ + { \ + 0xc95a928, 0xa006, 0x11d4, {0xbc, 0xfa, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } \ + } + +extern EFI_GUID gEfiWinNtVirtualDisksGuid; + +// +// EFI_WIN_NT_PHYSICAL_DISKS +// +#define EFI_WIN_NT_PHYSICAL_DISKS_GUID \ + { \ + 0xc95a92f, 0xa006, 0x11d4, {0xbc, 0xfa, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } \ + } + +extern EFI_GUID gEfiWinNtPhysicalDisksGuid; + +// +// EFI_WIN_NT_FILE_SYSTEM +// +#define EFI_WIN_NT_FILE_SYSTEM_GUID \ + { \ + 0xc95a935, 0xa006, 0x11d4, {0xbc, 0xfa, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } \ + } + +extern EFI_GUID gEfiWinNtFileSystemGuid; + +// +// EFI_WIN_NT_SERIAL_PORT +// +#define EFI_WIN_NT_SERIAL_PORT_GUID \ + { \ + 0xc95a93d, 0xa006, 0x11d4, {0xbc, 0xfa, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } \ + } + +extern EFI_GUID gEfiWinNtSerialPortGuid; + +// +// EFI_WIN_NT_UGA +// +#define EFI_WIN_NT_UGA_GUID \ + { \ + 0xab248e99, 0xabe1, 0x11d4, {0xbd, 0xd, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } \ + } + +extern EFI_GUID gEfiWinNtUgaGuid; + +// +// EFI_WIN_NT_CONSOLE +// +#define EFI_WIN_NT_CONSOLE_GUID \ + { \ + 0xba73672c, 0xa5d3, 0x11d4, {0xbd, 0x0, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } \ + } + +extern EFI_GUID gEfiWinNtConsoleGuid; + +// +// EFI_WIN_NT_MEMORY +// +#define EFI_WIN_NT_MEMORY_GUID \ + { \ + 0x99042912, 0x122a, 0x11d4, {0xbd, 0xd, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } \ + } + +extern EFI_GUID gEfiWinNtMemoryGuid; + +// +// EFI_WIN_NT_CPU_MODEL +// +#define EFI_WIN_NT_CPU_MODEL_GUID \ + { \ + 0xbee9b6ce, 0x2f8a, 0x11d4, {0xbd, 0xd, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } \ + } + +extern EFI_GUID gEfiWinNtCPUModelGuid; + +// +// EFI_WIN_NT_CPU_SPEED +// +#define EFI_WIN_NT_CPU_SPEED_GUID \ + { \ + 0xd4f29055, 0xe1fb, 0x11d4, {0xbd, 0xd, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } \ + } + +extern EFI_GUID gEfiWinNtCPUSpeedGuid; + +// +// EFI_WIN_NT_PASS_THROUGH +// +#define EFI_WIN_NT_PASS_THROUGH_GUID \ + { \ + 0xcc664eb8, 0x3c24, 0x4086, {0xb6, 0xf6, 0x34, 0xe8, 0x56, 0xbc, 0xe3, 0x6e } \ + } + +extern EFI_GUID gEfiWinNtPassThroughGuid; + +#endif diff --git a/EdkNt32Pkg/Include/Protocol/WinNtThunk.h b/EdkNt32Pkg/Include/Protocol/WinNtThunk.h new file mode 100644 index 0000000000..6ebc93fb6f --- /dev/null +++ b/EdkNt32Pkg/Include/Protocol/WinNtThunk.h @@ -0,0 +1,1264 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + WinNtThunk.h + +Abstract: + + This protocol allows an EFI driver (DLL) in the NT emulation envirnment + to make Win32 API calls. + + NEVER make a Win32 call directly, always make the call via this protocol. + + There are no This pointers on the protocol member functions as they map + exactly into Win32 system calls. + + YOU MUST include EfiWinNT.h in place of Efi.h to make this file compile. + +--*/ + +#ifndef __WIN_NT_THUNK_H__ +#define __WIN_NT_THUNK_H__ + +#define EFI_WIN_NT_THUNK_PROTOCOL_GUID \ + { 0x58c518b1, 0x76f3, 0x11d4, { 0xbc, 0xea, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } } + +typedef +WINBASEAPI +VOID +(WINAPI *WinNtSleep) ( + DWORD Milliseconds + ); + +typedef +WINBASEAPI +DWORD +(WINAPI *WinNtSuspendThread) ( + HANDLE hThread + ); + +typedef +WINBASEAPI +HANDLE +(WINAPI *WinNtGetCurrentThread) ( + VOID + ); + +typedef +WINBASEAPI +DWORD +(WINAPI *WinNtGetCurrentThreadId) ( + VOID + ); + +typedef +WINBASEAPI +HANDLE +(WINAPI *WinNtGetCurrentProcess) ( + VOID + ); + +typedef +WINBASEAPI +HANDLE +(WINAPI *WinNtCreateThread) ( + LPSECURITY_ATTRIBUTES lpThreadAttributes, + DWORD dwStackSize, + LPTHREAD_START_ROUTINE lpStartAddress, + LPVOID lpParameter, + DWORD dwCreationFlags, + LPDWORD lpThreadId + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtTerminateThread) ( + HANDLE hThread, + DWORD dwExitCode + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtSendMessage) ( + HWND hWnd, + UINT Msg, + WPARAM wParam, + LPARAM lParam + ); + +typedef +WINBASEAPI +VOID +(WINAPI *WinNtExitThread) ( + DWORD dwExitCode + ); + +typedef +WINBASEAPI +DWORD +(WINAPI *WinNtResumeThread) ( + HANDLE hThread + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtSetThreadPriority) ( + HANDLE hThread, + INTN nPriority + ); + +typedef +WINBASEAPI +VOID +(WINAPI *WinNtInitializeCriticalSection) ( + LPCRITICAL_SECTION lpCriticalSection + ); + +typedef +WINBASEAPI +VOID +(WINAPI *WinNtDeleteCriticalSection) ( + LPCRITICAL_SECTION lpCriticalSection + ); + +typedef +WINBASEAPI +VOID +(WINAPI *WinNtEnterCriticalSection) ( + LPCRITICAL_SECTION lpCriticalSection + ); + +typedef +WINBASEAPI +VOID +(WINAPI *WinNtLeaveCriticalSection) ( + LPCRITICAL_SECTION lpCriticalSection + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtTlsAlloc) ( + VOID + ); + +typedef +WINBASEAPI +LPVOID +(WINAPI *WinNtTlsGetValue) ( + DWORD dwTlsIndex + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtTlsSetValue) ( + DWORD dwTlsIndex, + LPVOID lpTlsValue + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtTlsFree) ( + DWORD dwTlsIndex + ); + +typedef +WINBASEAPI +HANDLE +(WINAPI *WinNtCreateSemaphore) ( + LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, + LONG lInitialCount, + LONG lMaximumCount, + LPCWSTR lpName + ); + +typedef +WINBASEAPI +DWORD +(WINAPI *WinNtWaitForSingleObject) ( + HANDLE hHandle, + DWORD dwMilliseconds + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtReleaseSemaphore) ( + HANDLE hSemaphore, + LONG lReleaseCount, + LPLONG lpPreviousCount + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtDuplicateHandle) ( + HANDLE hSourceProcessHandle, + HANDLE hSourceHandle, + HANDLE hTargetProcessHandle, + LPHANDLE lpTargetHandle, + DWORD dwDesiredAccess, + BOOL bInheritHandle, + DWORD dwOptions + ); + +typedef +WINBASEAPI +HANDLE +(WINAPI *WinNtCreateConsoleScreenBuffer) ( + DWORD DesiredAccess, + DWORD ShareMode, + CONST SECURITY_ATTRIBUTES *SecurityAttributes, + DWORD Flags, + LPVOID ScreenBufferData + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtSetConsoleScreenBufferSize) ( + HANDLE ConsoleOutput, + COORD Size + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtSetConsoleActiveScreenBuffer) ( + HANDLE ConsoleOutput + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtFillConsoleOutputAttribute) ( + HANDLE ConsoleOutput, + WORD Attribute, + DWORD Length, + COORD WriteCoord, + LPDWORD NumberOfAttrsWritten + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtFillConsoleOutputCharacter) ( + HANDLE ConsoleOutput, + TCHAR Character, + DWORD Length, + COORD WriteCoord, + LPDWORD NumberOfCharsWritten + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtWriteConsoleOutput) ( + HANDLE ConsoleOutput, + CONST CHAR_INFO *Buffer, + COORD BufferSize, + COORD BufferCoord, + PSMALL_RECT WriteRegion + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtScrollConsoleScreenBuffer) ( + HANDLE ConsoleOutput, + CONST SMALL_RECT *ScrollRectangle, + CONST SMALL_RECT *ClipRectangle, + COORD DestinationOrigin, + CONST CHAR_INFO *Fill + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtSetConsoleTitleW) ( + LPCTSTR ConsoleTitle + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtGetConsoleCursorInfo) ( + HANDLE ConsoleOutput, + PCONSOLE_CURSOR_INFO ConsoleCursorInfo + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtSetConsoleCursorInfo) ( + HANDLE ConsoleOutput, + CONST CONSOLE_CURSOR_INFO *ConsoleCursorInfo + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtSetPriorityClass) ( + HANDLE Process, + DWORD PriorityClass + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtWriteConsoleInput) ( + HANDLE ConsoleInput, + CONST INPUT_RECORD *Buffer, + DWORD Legnth, + LPDWORD NumberOfEventsWritten + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtGetNumberOfConsoleInputEvents) ( + HANDLE ConsoleInput, + LPDWORD NumberOfEvents + ); + +typedef +WINBASEAPI +HANDLE +(WINAPI *WinNtGetStdHandle) ( + DWORD StdHandle + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtReadConsoleInput) ( + HANDLE ConsoleInput, + PINPUT_RECORD Buffer, + DWORD Length, + LPDWORD NumberOfEventsRead + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtPeekConsoleInput) ( + HANDLE ConsoleInput, + PINPUT_RECORD Buffer, + DWORD Length, + LPDWORD NumberOfEventsRead + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtSetConsoleCursorPosition) ( + HANDLE ConsoleInput, + COORD CursorPosition + ); + +typedef +WINBASEAPI +HANDLE +(WINAPI *WinNtCreateFile) ( + LPCWSTR FileName, + DWORD DesiredAccess, + DWORD SharedMode, + LPSECURITY_ATTRIBUTES SecurityAttributes, + DWORD CreationDisposition, + DWORD FlagsAndAttributes, + HANDLE TemplateFile + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtDeviceIoControl) ( + HANDLE DeviceHandle, + DWORD IoControlCode, + LPVOID InBuffer, + DWORD InBufferSize, + LPVOID OutBuffer, + DWORD OutBufferSize, + LPDWORD BytesReturned, + LPOVERLAPPED Overlapped + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtCreateDirectory) ( + LPCWSTR PathName, + LPSECURITY_ATTRIBUTES SecurityAttributes + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtRemoveDirectory) ( + LPCWSTR PathName + ); + +typedef +WINBASEAPI +DWORD +(WINAPI *WinNtGetFileAttributes) ( + LPCWSTR FileName + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtSetFileAttributes) ( + LPCWSTR FileName, + DWORD FileAttributes + ); + +typedef +WINBASEAPI +HANDLE +(WINAPI *WinNtCreateFileMapping) ( + HANDLE FileHandle, + LPSECURITY_ATTRIBUTES Attributes, + DWORD Protect, + DWORD MaximumSizeHigh, + DWORD MaximumSizeLow, + LPCTSTR Name + ); + +typedef +WINBASEAPI +LPVOID +(WINAPI *WinNtMapViewOfFileEx) ( + HANDLE FileHandle, + DWORD DesiredAccess, + DWORD FileOffsetHigh, + DWORD FileOffsetLow, + DWORD NumberOfBytesToMap, + LPVOID BaseAddress + ); + +typedef +WINBASEAPI +DWORD +(WINAPI *WinNtGetEnvironmentVariable) ( + LPCTSTR Name, + LPTSTR Buffer, + DWORD Size + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtCloseHandle) ( + HANDLE Object + ); + +typedef +WINBASEAPI +DWORD +(WINAPI *WinNtSetFilePointer) ( + HANDLE FileHandle, + LONG DistanceToMove, + PLONG DistanceToHoveHigh, + DWORD MoveMethod + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtSetEndOfFile) ( + HANDLE FileHandle + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtReadFile) ( + HANDLE FileHandle, + LPVOID Buffer, + DWORD NumberOfBytesToRead, + LPDWORD NumberOfBytesRead, + LPOVERLAPPED Overlapped + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtWriteFile) ( + HANDLE FileHandle, + LPCVOID Buffer, + DWORD NumberOfBytesToWrite, + LPDWORD NumberOfBytesWritten, + LPOVERLAPPED Overlapped + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtGetFileInformationByHandle) ( + HANDLE FileHandle, + BY_HANDLE_FILE_INFORMATION *FileInfo + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtGetDiskFreeSpace) ( + LPCTSTR RootPathName, + LPDWORD SectorsPerCluster, + LPDWORD BytesPerSector, + LPDWORD NumberOfFreeClusters, + LPDWORD TotalNumberOfClusters + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtGetDiskFreeSpaceEx) ( + LPCTSTR DirectoryName, + PULARGE_INTEGER FreeBytesAvailable, + PULARGE_INTEGER TotalNumberOfBytes, + PULARGE_INTEGER TotoalNumberOfFreeBytes + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtMoveFile) ( + LPCTSTR ExistingFileName, + LPCTSTR NewFileName + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtSetFileTime) ( + HANDLE FileHandle, + FILETIME *CreationTime, + FILETIME *LastAccessTime, + FILETIME *LastWriteTime + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtSystemTimeToFileTime) ( + SYSTEMTIME * SystemTime, + FILETIME * FileTime + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtDeleteFile) ( + LPCTSTR FileName + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtFlushFileBuffers) ( + HANDLE + ); + +typedef +WINBASEAPI +DWORD +(WINAPI *WinNtGetLastError) ( + VOID + ); + +typedef +WINBASEAPI +UINT +(WINAPI *WinNtSetErrorMode) ( + UINT Mode + ); + +typedef +WINBASEAPI +DWORD +(WINAPI *WinNtGetTickCount) ( + VOID + ); + +typedef +WINBASEAPI +HMODULE +(WINAPI *WinNtLoadLibraryEx) ( + LPCTSTR LibFileName, + HANDLE FileHandle, + DWORD Flags + ); + +typedef +WINBASEAPI +FARPROC +(WINAPI *WinNtGetProcAddress) ( + HMODULE Module, + LPCSTR ProcName + ); + +typedef +WINBASEAPI +DWORD +(WINAPI *WinNtGetTimeZoneInformation) ( + LPTIME_ZONE_INFORMATION timeZoneInformation + ); + +typedef +WINBASEAPI +MMRESULT +(WINAPI *WinNttimeSetEvent) ( + UINT uDelay, + UINT uResolution, + LPTIMECALLBACK lpTimeProc, + DWORD_PTR dwUser, + UINT fuEvent + ); + +typedef +WINBASEAPI +MMRESULT +(WINAPI *WinNttimeKillEvent) ( + UINT uTimerID + ); + +typedef +WINBASEAPI +DWORD +(WINAPI *WinNtSetTimeZoneInformation) ( + LPTIME_ZONE_INFORMATION timeZoneInformation + ); + +typedef +WINBASEAPI +VOID +(WINAPI *WinNtGetSystemTime) ( + LPSYSTEMTIME SystemTime + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtSetSystemTime) ( + CONST SYSTEMTIME *SystemTime + ); + +typedef +WINBASEAPI +VOID +(WINAPI *WinNtGetLocalTime) ( + LPSYSTEMTIME SystemTime + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtSetLocalTime) ( + CONST SYSTEMTIME *SystemTime + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtFileTimeToLocalFileTime) ( + CONST FILETIME *FileTime, + LPFILETIME LocalFileTime + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtFileTimeToSystemTime) ( + CONST FILETIME *FileTime, + LPSYSTEMTIME SystemTime + ); + +typedef +WINBASEAPI +HANDLE +(WINAPI *WinNtFindFirstFile) ( + LPCTSTR FileName, + LPWIN32_FIND_DATA FindFileData + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtFindNextFile) ( + HANDLE FindFile, + LPWIN32_FIND_DATA FindFileData + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtFindClose) ( + HANDLE FindFile + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtGetCommState) ( + HANDLE FileHandle, + LPDCB DCB + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtSetCommState) ( + HANDLE FileHandle, + LPDCB DCB + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtSetCommState) ( + HANDLE FileHandle, + LPDCB DCB + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtSetCommTimeouts) ( + HANDLE FileHandle, + LPCOMMTIMEOUTS CommTimeouts + ); + +typedef +WINBASEAPI +VOID +(WINAPI *WinNtExitProcess) ( + UINT uExitCode // exit code for all threads + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtPurgeComm) ( + HANDLE FileHandle, + DWORD Flags + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtEscapeCommFunction) ( + HANDLE FileHandle, + DWORD Func + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtGetCommModemStatus) ( + HANDLE FileHandle, + LPDWORD ModemStat + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtClearCommError) ( + HANDLE FileHandle, + LPDWORD Errors, + LPCOMSTAT Stat + ); + +typedef +WINUSERAPI +INT32 +(WINAPIV *WinNtSprintf) ( + LPWSTR Buffer, + LPCWSTR String, + ... + ); + +typedef +WINUSERAPI +HWND +(WINAPI *WinNtGetDesktopWindow) ( + VOID + ); + +typedef +WINUSERAPI +HWND +(WINAPI *WinNtGetForegroundWindow) ( + VOID + ); + +typedef +WINUSERAPI +HWND +(WINAPI *WinNtCreateWindowEx) ( + DWORD dwExStyle, + LPCTSTR lpClassName, + LPCTSTR lpWindowName, + DWORD dwStyle, + INT32 x, + INT32 y, + INT32 nWidth, + INT32 nHeight, + HWND hWndParent, + HMENU hMenu, + HINSTANCE hInstance, + LPVOID *lpParam + ); + +typedef +WINUSERAPI +BOOL +(WINAPI *WinNtUpdateWindow) ( + HWND hWnd + ); + +typedef +WINUSERAPI +BOOL +(WINAPI *WinNtShowWindow) ( + HWND hWnd, + INT32 nCmdShow + ); + +typedef +WINGDIAPI +BOOL +(WINAPI *WinNtDestroyWindow) ( + HWND hWnd + ); + +typedef +WINUSERAPI +HDC +(WINAPI *WinNtGetWindowDC) ( + HWND hWnd + ); + +typedef +WINUSERAPI +BOOL +(WINAPI *WinNtGetClientRect) ( + HWND hWnd, + LPRECT lpRect + ); + +typedef +WINUSERAPI +BOOL +(WINAPI *WinNtAdjustWindowRect) ( + LPRECT lpRect, + DWORD dwStyle, + BOOL bMenu + ); + +typedef +WINGDIAPI +INT32 +(WINAPI *WinNtSetDIBitsToDevice) ( + HDC, + INT32, + INT32, + DWORD, + DWORD, + INT32, + INT32, + UINT, + UINT, + CONST VOID *, + CONST BITMAPINFO *, + UINT + ); + +typedef +WINGDIAPI +BOOL +(WINAPI *WinNtBitBlt) ( + HDC, + INT32, + INT32, + INT32, + INT32, + HDC, + INT32, + INT32, + DWORD + ); + +typedef +WINUSERAPI +BOOL +(WINAPI *WinNtInvalidateRect) ( + HWND hWnd, + CONST RECT *lpRect, + BOOL bErase + ); + +typedef +WINUSERAPI +HDC +(WINAPI *WinNtGetDC) ( + HWND hWnd + ); + +typedef +WINUSERAPI +INT32 +(WINAPI *WinNtReleaseDC) ( + HWND hWnd, + HDC hDC + ); + +typedef +WINUSERAPI +ATOM +(WINAPI *WinNtRegisterClassEx) ( + CONST WNDCLASSEX * + ); + +typedef +WINUSERAPI +BOOL +(WINAPI *WinNtUnregisterClass) ( + LPCTSTR lpClassName, + HINSTANCE hInstance + ); + +typedef +WINUSERAPI +HDC +(WINAPI *WinNtBeginPaint) ( + HWND hWnd, + LPPAINTSTRUCT lpPaint + ); + +typedef +WINUSERAPI +BOOL +(WINAPI *WinNtEndPaint) ( + HWND hWnd, + CONST PAINTSTRUCT *lpPaint + ); + +typedef +WINUSERAPI +VOID +(WINAPI *WinNtPostQuitMessage) ( + INT32 nExitCode + ); + +typedef +WINUSERAPI +LRESULT +(WINAPI *WinNtDefWindowProc) ( + HWND hWnd, + UINT Msg, + WPARAM wParam, + LPARAM lParam + ); + +typedef +WINUSERAPI +HICON +(WINAPI *WinNtLoadIcon) ( + HINSTANCE hInstance, + LPCTSTR lpIconName + ); + +typedef +WINUSERAPI +HCURSOR +(WINAPI *WinNtLoadCursor) ( + HINSTANCE hInstance, + LPCTSTR lpCursorName + ); + +typedef +WINGDIAPI +HGDIOBJ +(WINAPI *WinNtGetStockObject) ( + INT32 + ); + +typedef +WINGDIAPI +BOOL +(WINAPI *WinNtSetViewportOrgEx) ( + HDC, + INT32, + INT32, + LPPOINT + ); + +typedef +WINGDIAPI +BOOL +(WINAPI *WinNtSetWindowOrgEx) ( + HDC, + INT32, + INT32, + LPPOINT + ); +typedef +WINGDIAPI +BOOL +(WINAPI *WinNtMoveWindow) ( + HWND, + INT32, + INT32, + INT32, + INT32, + BOOL + ); + +typedef +WINGDIAPI +BOOL +(WINAPI *WinNtGetWindowRect) ( + HWND, + LPRECT + ); + +typedef +WINUSERAPI +BOOL +(WINAPI *WinNtGetMessage) ( + LPMSG lpMsg, + HWND hWnd, + UINT wMsgFilterMin, + UINT wMsgFilterMax + ); + +typedef +WINUSERAPI +BOOL +(WINAPI *WinNtTranslateMessage) ( + CONST MSG *lpMsg + ); + +typedef +WINUSERAPI +BOOL +(WINAPI *WinNtDispatchMessage) ( + CONST MSG *lpMsg + ); + +typedef +WINUSERAPI +HANDLE +(WINAPI *WinNtGetProcessHeap) (); + +typedef +WINUSERAPI +LPVOID +(WINAPI *WinNtHeapAlloc) ( + HANDLE hHeap, + DWORD dwFlags, + SIZE_T dwBytes + ); + +typedef +WINUSERAPI +BOOL +(WINAPI *WinNtHeapFree) ( + HANDLE hHeap, + DWORD dwFlags, + LPVOID lpMem + ); + +typedef +WINBASEAPI +BOOL +(WINAPI *WinNtFreeLibrary) ( + HANDLE ModHandle + ); +// +// +// + +#define EFI_WIN_NT_THUNK_PROTOCOL_SIGNATURE EFI_SIGNATURE_32 ('N', 'T', 'T', 'T') + +typedef struct { + UINT64 Signature; + + // + // Win32 Process APIs + // + WinNtGetProcAddress GetProcAddress; + WinNtGetTickCount GetTickCount; + WinNtLoadLibraryEx LoadLibraryEx; + WinNtFreeLibrary FreeLibrary; + + WinNtSetPriorityClass SetPriorityClass; + WinNtSetThreadPriority SetThreadPriority; + WinNtSleep Sleep; + + WinNtSuspendThread SuspendThread; + WinNtGetCurrentThread GetCurrentThread; + WinNtGetCurrentThreadId GetCurrentThreadId; + WinNtGetCurrentProcess GetCurrentProcess; + WinNtCreateThread CreateThread; + WinNtTerminateThread TerminateThread; + WinNtSendMessage SendMessage; + WinNtExitThread ExitThread; + WinNtResumeThread ResumeThread; + WinNtDuplicateHandle DuplicateHandle; + + // + // Wint32 Mutex primitive + // + WinNtInitializeCriticalSection InitializeCriticalSection; + WinNtEnterCriticalSection EnterCriticalSection; + WinNtLeaveCriticalSection LeaveCriticalSection; + WinNtDeleteCriticalSection DeleteCriticalSection; + WinNtTlsAlloc TlsAlloc; + WinNtTlsFree TlsFree; + WinNtTlsSetValue TlsSetValue; + WinNtTlsGetValue TlsGetValue; + WinNtCreateSemaphore CreateSemaphore; + WinNtWaitForSingleObject WaitForSingleObject; + WinNtReleaseSemaphore ReleaseSemaphore; + + // + // Win32 Console APIs + // + WinNtCreateConsoleScreenBuffer CreateConsoleScreenBuffer; + WinNtFillConsoleOutputAttribute FillConsoleOutputAttribute; + WinNtFillConsoleOutputCharacter FillConsoleOutputCharacter; + WinNtGetConsoleCursorInfo GetConsoleCursorInfo; + WinNtGetNumberOfConsoleInputEvents GetNumberOfConsoleInputEvents; + WinNtPeekConsoleInput PeekConsoleInput; + WinNtScrollConsoleScreenBuffer ScrollConsoleScreenBuffer; + WinNtReadConsoleInput ReadConsoleInput; + + WinNtSetConsoleActiveScreenBuffer SetConsoleActiveScreenBuffer; + WinNtSetConsoleCursorInfo SetConsoleCursorInfo; + WinNtSetConsoleCursorPosition SetConsoleCursorPosition; + WinNtSetConsoleScreenBufferSize SetConsoleScreenBufferSize; + WinNtSetConsoleTitleW SetConsoleTitleW; + WinNtWriteConsoleInput WriteConsoleInput; + WinNtWriteConsoleOutput WriteConsoleOutput; + + // + // Win32 File APIs + // + WinNtCreateFile CreateFile; + WinNtDeviceIoControl DeviceIoControl; + WinNtCreateDirectory CreateDirectory; + WinNtRemoveDirectory RemoveDirectory; + WinNtGetFileAttributes GetFileAttributes; + WinNtSetFileAttributes SetFileAttributes; + WinNtCreateFileMapping CreateFileMapping; + WinNtCloseHandle CloseHandle; + WinNtDeleteFile DeleteFile; + WinNtFindFirstFile FindFirstFile; + WinNtFindNextFile FindNextFile; + WinNtFindClose FindClose; + WinNtFlushFileBuffers FlushFileBuffers; + WinNtGetEnvironmentVariable GetEnvironmentVariable; + WinNtGetLastError GetLastError; + WinNtSetErrorMode SetErrorMode; + WinNtGetStdHandle GetStdHandle; + WinNtMapViewOfFileEx MapViewOfFileEx; + WinNtReadFile ReadFile; + WinNtSetEndOfFile SetEndOfFile; + WinNtSetFilePointer SetFilePointer; + WinNtWriteFile WriteFile; + WinNtGetFileInformationByHandle GetFileInformationByHandle; + WinNtGetDiskFreeSpace GetDiskFreeSpace; + WinNtGetDiskFreeSpaceEx GetDiskFreeSpaceEx; + WinNtMoveFile MoveFile; + WinNtSetFileTime SetFileTime; + WinNtSystemTimeToFileTime SystemTimeToFileTime; + + // + // Win32 Time APIs + // + WinNtFileTimeToLocalFileTime FileTimeToLocalFileTime; + WinNtFileTimeToSystemTime FileTimeToSystemTime; + WinNtGetSystemTime GetSystemTime; + WinNtSetSystemTime SetSystemTime; + WinNtGetLocalTime GetLocalTime; + WinNtSetLocalTime SetLocalTime; + WinNtGetTimeZoneInformation GetTimeZoneInformation; + WinNtSetTimeZoneInformation SetTimeZoneInformation; + WinNttimeSetEvent timeSetEvent; + WinNttimeKillEvent timeKillEvent; + + // + // Win32 Serial APIs + // + WinNtClearCommError ClearCommError; + WinNtEscapeCommFunction EscapeCommFunction; + WinNtGetCommModemStatus GetCommModemStatus; + WinNtGetCommState GetCommState; + WinNtSetCommState SetCommState; + WinNtPurgeComm PurgeComm; + WinNtSetCommTimeouts SetCommTimeouts; + + WinNtExitProcess ExitProcess; + + WinNtSprintf SPrintf; + + WinNtGetDesktopWindow GetDesktopWindow; + WinNtGetForegroundWindow GetForegroundWindow; + WinNtCreateWindowEx CreateWindowEx; + WinNtShowWindow ShowWindow; + WinNtUpdateWindow UpdateWindow; + WinNtDestroyWindow DestroyWindow; + WinNtInvalidateRect InvalidateRect; + WinNtGetWindowDC GetWindowDC; + WinNtGetClientRect GetClientRect; + WinNtAdjustWindowRect AdjustWindowRect; + WinNtSetDIBitsToDevice SetDIBitsToDevice; + WinNtBitBlt BitBlt; + WinNtGetDC GetDC; + WinNtReleaseDC ReleaseDC; + WinNtRegisterClassEx RegisterClassEx; + WinNtUnregisterClass UnregisterClass; + + WinNtBeginPaint BeginPaint; + WinNtEndPaint EndPaint; + WinNtPostQuitMessage PostQuitMessage; + WinNtDefWindowProc DefWindowProc; + WinNtLoadIcon LoadIcon; + WinNtLoadCursor LoadCursor; + WinNtGetStockObject GetStockObject; + WinNtSetViewportOrgEx SetViewportOrgEx; + WinNtSetWindowOrgEx SetWindowOrgEx; + WinNtMoveWindow MoveWindow; + WinNtGetWindowRect GetWindowRect; + + WinNtGetMessage GetMessage; + WinNtTranslateMessage TranslateMessage; + WinNtDispatchMessage DispatchMessage; + + WinNtGetProcessHeap GetProcessHeap; + WinNtHeapAlloc HeapAlloc; + WinNtHeapFree HeapFree; + +} EFI_WIN_NT_THUNK_PROTOCOL; + +extern EFI_GUID gEfiWinNtThunkProtocolGuid; + +#endif diff --git a/EdkNt32Pkg/Include/WinNtDxe.h b/EdkNt32Pkg/Include/WinNtDxe.h new file mode 100644 index 0000000000..d82b2a2c45 --- /dev/null +++ b/EdkNt32Pkg/Include/WinNtDxe.h @@ -0,0 +1,38 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + WinNtLib.h + +Abstract: + Public include file for the WinNt Library + +--*/ + +#ifndef __WIN_NT_DXE_H__ +#define __WIN_NT_DXE_H__ + +#include +#include +#include +#include + +// +// This forces Windows.h WIN32 include file to be included +// it's needed for WinNtThunk.h +// WinNtIo.h depends on WinNtThunk.h +// +#include + +#include +#include + +#endif diff --git a/EdkNt32Pkg/Include/WinNtPeim.h b/EdkNt32Pkg/Include/WinNtPeim.h new file mode 100644 index 0000000000..0b2240b2f1 --- /dev/null +++ b/EdkNt32Pkg/Include/WinNtPeim.h @@ -0,0 +1,36 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + WinNtLib.h + +Abstract: + Public include file for the WinNt Library + +--*/ + +#ifndef __WIN_NT_PEIM_H__ +#define __WIN_NT_PEIM_H__ + +#include +#include +#include +#include + +// +// This forces Windows.h WIN32 include file to be included +// it's needed for WinNtThunk.h +// +#include + +#include + +#endif diff --git a/EdkNt32Pkg/Include/library/EdkGenericBdsLib.h b/EdkNt32Pkg/Include/library/EdkGenericBdsLib.h new file mode 100644 index 0000000000..3f01119041 --- /dev/null +++ b/EdkNt32Pkg/Include/library/EdkGenericBdsLib.h @@ -0,0 +1,332 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + BdsLib.h + +Abstract: + + BDS library definition, include the file and data structure + +--*/ + +#ifndef _BDS_LIB_H_ +#define _BDS_LIB_H_ + +extern EFI_HANDLE mBdsImageHandle; + +// +// Constants which are variable names used to access variables +// +#define VarLegacyDevOrder L"LegacyDevOrder" + +// +// Data structures and defines +// +#define FRONT_PAGE_QUESTION_ID 0x0000 +#define FRONT_PAGE_DATA_WIDTH 0x01 + +// +// ConnectType +// +#define CONSOLE_OUT 0x00000001 +#define STD_ERROR 0x00000002 +#define CONSOLE_IN 0x00000004 +#define CONSOLE_ALL (CONSOLE_OUT | CONSOLE_IN | STD_ERROR) + +// +// Load Option Attributes defined in EFI Specification +// +#define LOAD_OPTION_ACTIVE 0x00000001 +#define LOAD_OPTION_FORCE_RECONNECT 0x00000002 +#define IS_LOAD_OPTION_TYPE(_c, _Mask) (BOOLEAN) (((_c) & (_Mask)) != 0) + +// +// Define Maxmim characters that will be accepted +// +#define MAX_CHAR 480 +#define MAX_CHAR_SIZE (MAX_CHAR * 2) + +#define MIN_ALIGNMENT_SIZE 4 +#define ALIGN_SIZE(a) ((a % MIN_ALIGNMENT_SIZE) ? MIN_ALIGNMENT_SIZE - (a % MIN_ALIGNMENT_SIZE) : 0) + +// +// This data structure is the part of BDS_CONNECT_ENTRY that we can hard code. +// +#define BDS_LOAD_OPTION_SIGNATURE EFI_SIGNATURE_32 ('B', 'd', 'C', 'O') + +typedef struct { + + UINTN Signature; + LIST_ENTRY Link; + + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + CHAR16 *OptionName; + UINTN OptionNumber; + UINT16 BootCurrent; + UINT32 Attribute; + CHAR16 *Description; + VOID *LoadOptions; + UINT32 LoadOptionsSize; + +} BDS_COMMON_OPTION; + +typedef struct { + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + UINTN ConnectType; +} BDS_CONSOLE_CONNECT_ENTRY; + +// +// Lib Functions +// + +// +// Bds boot relate lib functions +// +EFI_STATUS +BdsLibUpdateBootOrderList ( + IN LIST_ENTRY *BdsOptionList, + IN CHAR16 *VariableName + ); + +VOID +BdsLibBootNext ( + VOID + ); + +EFI_STATUS +BdsLibBootViaBootOption ( + IN BDS_COMMON_OPTION * Option, + IN EFI_DEVICE_PATH_PROTOCOL * DevicePath, + OUT UINTN *ExitDataSize, + OUT CHAR16 **ExitData OPTIONAL + ); + +EFI_STATUS +BdsLibEnumerateAllBootOption ( + IN OUT LIST_ENTRY *BdsBootOptionList + ); + +VOID +BdsLibBuildOptionFromHandle ( + IN EFI_HANDLE Handle, + IN LIST_ENTRY *BdsBootOptionList + ); + +VOID +BdsLibBuildOptionFromShell ( + IN EFI_HANDLE Handle, + IN LIST_ENTRY *BdsBootOptionList + ); + +// +// Bds misc lib functions +// +UINT16 +BdsLibGetTimeout ( + VOID + ); + +EFI_STATUS +BdsLibGetBootMode ( + OUT EFI_BOOT_MODE *BootMode + ); + +VOID +BdsLibLoadDrivers ( + IN LIST_ENTRY *BdsDriverLists + ); + +EFI_STATUS +BdsLibBuildOptionFromVar ( + IN LIST_ENTRY *BdsCommonOptionList, + IN CHAR16 *VariableName + ); + +VOID * +BdsLibGetVariableAndSize ( + IN CHAR16 *Name, + IN EFI_GUID *VendorGuid, + OUT UINTN *VariableSize + ); + +EFI_STATUS +BdsLibOutputStrings ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *ConOut, + ... + ); + +BDS_COMMON_OPTION * +BdsLibVariableToOption ( + IN OUT LIST_ENTRY *BdsCommonOptionList, + IN CHAR16 *VariableName + ); + +EFI_STATUS +BdsLibRegisterNewOption ( + IN LIST_ENTRY *BdsOptionList, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN CHAR16 *String, + IN CHAR16 *VariableName + ); + +// +// Bds connect or disconnect driver lib funcion +// +VOID +BdsLibConnectAllDriversToAllControllers ( + VOID + ); + +VOID +BdsLibConnectAll ( + VOID + ); + +EFI_STATUS +BdsLibConnectDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathToConnect + ); + +EFI_STATUS +BdsLibConnectAllEfi ( + VOID + ); + +EFI_STATUS +BdsLibDisconnectAllEfi ( + VOID + ); + +// +// Bds console relate lib functions +// +VOID +BdsLibConnectAllConsoles ( + VOID + ); + +EFI_STATUS +BdsLibConnectAllDefaultConsoles ( + VOID + ); + +EFI_STATUS +BdsLibUpdateConsoleVariable ( + IN CHAR16 *ConVarName, + IN EFI_DEVICE_PATH_PROTOCOL *CustomizedConDevicePath, + IN EFI_DEVICE_PATH_PROTOCOL *ExclusiveDevicePath + ); + +EFI_STATUS +BdsLibConnectConsoleVariable ( + IN CHAR16 *ConVarName + ); + +// +// Bds device path relate lib functions +// +EFI_DEVICE_PATH_PROTOCOL * +BdsLibUnpackDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevPath + ); + +BOOLEAN +BdsLibMatchDevicePaths ( + IN EFI_DEVICE_PATH_PROTOCOL *Multi, + IN EFI_DEVICE_PATH_PROTOCOL *Single + ); + +CHAR16 * +DevicePathToStr ( + EFI_DEVICE_PATH_PROTOCOL *DevPath + ); + +VOID * +EfiLibGetVariable ( + IN CHAR16 *Name, + IN EFI_GUID *VendorGuid + ); + +// +// Internal definitions +// +typedef struct { + CHAR16 *str; + UINTN len; + UINTN maxlen; +} POOL_PRINT; + +typedef struct { + UINT8 Type; + UINT8 SubType; + VOID (*Function) (POOL_PRINT *, VOID *); +} DEVICE_PATH_STRING_TABLE; + +// +// Internal functions +// +EFI_STATUS +BdsBootByDiskSignatureAndPartition ( + IN BDS_COMMON_OPTION * Option, + IN HARDDRIVE_DEVICE_PATH * HardDriveDevicePath, + IN UINT32 LoadOptionsSize, + IN VOID *LoadOptions, + OUT UINTN *ExitDataSize, + OUT CHAR16 **ExitData OPTIONAL + ); + +// +// Notes: EFI 64 shadow all option rom +// +#ifdef EFI64 +#define EFI64_SHADOW_ALL_LEGACY_ROM() ShadowAllOptionRom (); +VOID +ShadowAllOptionRom(); +#else +#define EFI64_SHADOW_ALL_LEGACY_ROM() +#endif + +// +// BBS support macros and functions +// +#ifdef EFI32 +#define REFRESH_LEGACY_BOOT_OPTIONS \ + BdsDeleteAllInvalidLegacyBootOptions ();\ + BdsAddNonExistingLegacyBootOptions (); \ + BdsUpdateLegacyDevOrder () +#else +#define REFRESH_LEGACY_BOOT_OPTIONS +#endif + +EFI_STATUS +BdsDeleteAllInvalidLegacyBootOptions ( + VOID + ); + +EFI_STATUS +BdsAddNonExistingLegacyBootOptions ( + VOID + ); + +EFI_STATUS +BdsUpdateLegacyDevOrder ( + VOID + ); + +EFI_STATUS +BdsRefreshBbsTableForBoot ( + IN BDS_COMMON_OPTION *Entry + ); + +#endif // _BDS_LIB_H_ diff --git a/EdkNt32Pkg/Include/library/WinNtLib.h b/EdkNt32Pkg/Include/library/WinNtLib.h new file mode 100644 index 0000000000..b9bccfc008 --- /dev/null +++ b/EdkNt32Pkg/Include/library/WinNtLib.h @@ -0,0 +1,27 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + WinNtLib.h + +Abstract: + + Public include file for the WinNt Library + +--*/ + +#ifndef __WIN_NT_LIB_H__ +#define __WIN_NT_LIB_H__ + +extern EFI_WIN_NT_THUNK_PROTOCOL *gWinNt; + +#endif \ No newline at end of file diff --git a/EdkNt32Pkg/Library/DxeWinNtLib/DxeWinNtLib.mbd b/EdkNt32Pkg/Library/DxeWinNtLib/DxeWinNtLib.mbd new file mode 100644 index 0000000000..a054a89442 --- /dev/null +++ b/EdkNt32Pkg/Library/DxeWinNtLib/DxeWinNtLib.mbd @@ -0,0 +1,30 @@ + + + + + DxeWinNtLib + f6b5871d-5226-41b3-a569-3ff893fdc7bc + EDK_RELEASE_VERSION 0x00020000 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-14 17:04 + 2006-03-31 13:20 + + diff --git a/EdkNt32Pkg/Library/DxeWinNtLib/DxeWinNtLib.msa b/EdkNt32Pkg/Library/DxeWinNtLib/DxeWinNtLib.msa new file mode 100644 index 0000000000..d20cf4d350 --- /dev/null +++ b/EdkNt32Pkg/Library/DxeWinNtLib/DxeWinNtLib.msa @@ -0,0 +1,55 @@ + + + + + DxeWinNtLib + DXE_DRIVER + LIBRARY + f6b5871d-5226-41b3-a569-3ff893fdc7bc + EDK_RELEASE_VERSION 0x00020000 + Component description file for the entry point to a EFIDXE Drivers + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + EFI_SPECIFICATION_VERSION 0x00000000 + 2006-03-14 17:04 + 2006-03-31 13:20 + + + WinNtLib + DebugLib + HobLib + + + WinNtLib.c + + + MdePkg + EdkModulePkg + EdkNt32Pkg + + + WinNtThunk + + + + WinNtLibConstructor + + + diff --git a/EdkNt32Pkg/Library/DxeWinNtLib/WinNtLib.c b/EdkNt32Pkg/Library/DxeWinNtLib/WinNtLib.c new file mode 100644 index 0000000000..9010d8ae24 --- /dev/null +++ b/EdkNt32Pkg/Library/DxeWinNtLib/WinNtLib.c @@ -0,0 +1,48 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + WinNtLib.c + +Abstract: + + WinNt Library + +--*/ + + + +EFI_WIN_NT_THUNK_PROTOCOL *gWinNt; + +EFI_STATUS +WinNtLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + EFI_HOB_GUID_TYPE *GuidHob; + + GuidHob = GetFirstGuidHob (&gEfiWinNtThunkProtocolGuid); + ASSERT (GuidHob != NULL); + gWinNt = (EFI_WIN_NT_THUNK_PROTOCOL *)(*(UINTN *)(GET_GUID_HOB_DATA (GuidHob))); + ASSERT (gWinNt != NULL); + return EFI_SUCCESS; +} diff --git a/EdkNt32Pkg/Library/DxeWinNtLib/build.xml b/EdkNt32Pkg/Library/DxeWinNtLib/build.xml new file mode 100644 index 0000000000..5d4ab2c855 --- /dev/null +++ b/EdkNt32Pkg/Library/DxeWinNtLib/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkNt32Pkg/Library/EdkGenericBdsLib/BdsBoot.c b/EdkNt32Pkg/Library/EdkGenericBdsLib/BdsBoot.c new file mode 100644 index 0000000000..c9b1eede1c --- /dev/null +++ b/EdkNt32Pkg/Library/EdkGenericBdsLib/BdsBoot.c @@ -0,0 +1,795 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + BdsBoot.c + +Abstract: + + BDS Lib functions which relate with create or process the boot + option. + +--*/ +#include "Performance.h" + +BOOLEAN mEnumBootDevice = FALSE; + +EFI_STATUS +BdsLibDoLegacyBoot ( + IN BDS_COMMON_OPTION *Option + ) +/*++ + +Routine Description: + + Boot the legacy system with the boot option + +Arguments: + + Option - The legacy boot option which have BBS device path + +Returns: + + EFI_UNSUPPORTED - There is no legacybios protocol, do not support + legacy boot. + + EFI_STATUS - Return the status of LegacyBios->LegacyBoot (). + +--*/ +{ + EFI_STATUS Status; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + + Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, &LegacyBios); + if (EFI_ERROR (Status)) { + // + // If no LegacyBios protocol we do not support legacy boot + // + return EFI_UNSUPPORTED; + } + // + // Notes: if we seperate the int 19, then we don't need to refresh BBS + // + BdsRefreshBbsTableForBoot (Option); + + // + // Write boot to OS performance data to a file + // + PERF_CODE ( + WriteBootToOsPerformanceData (); + ); + + + DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Legacy Boot: %S\n", Option->Description)); + return LegacyBios->LegacyBoot ( + LegacyBios, + (BBS_BBS_DEVICE_PATH *) Option->DevicePath, + Option->LoadOptionsSize, + Option->LoadOptions + ); +} + +EFI_STATUS +BdsLibBootViaBootOption ( + IN BDS_COMMON_OPTION * Option, + IN EFI_DEVICE_PATH_PROTOCOL * DevicePath, + OUT UINTN *ExitDataSize, + OUT CHAR16 **ExitData OPTIONAL + ) +/*++ + +Routine Description: + + Process the boot option follow the EFI 1.1 specification and + special treat the legacy boot option with BBS_DEVICE_PATH. + +Arguments: + + Option - The boot option need to be processed + + DevicePath - The device path which describe where to load + the boot image or the legcy BBS device path + to boot the legacy OS + + ExitDataSize - Returned directly from gBS->StartImage () + + ExitData - Returned directly from gBS->StartImage () + +Returns: + + EFI_SUCCESS - Status from gBS->StartImage (), + or BdsBootByDiskSignatureAndPartition () + + EFI_NOT_FOUND - If the Device Path is not found in the system + +--*/ +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + EFI_HANDLE ImageHandle; + EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; + EFI_DEVICE_PATH_PROTOCOL *FilePath; + EFI_LOADED_IMAGE_PROTOCOL *ImageInfo; + EFI_ACPI_S3_SAVE_PROTOCOL *AcpiS3Save; + + *ExitDataSize = 0; + *ExitData = NULL; + + // + // Notes: put EFI64 ROM Shadow Solution + // + EFI64_SHADOW_ALL_LEGACY_ROM (); + + // + // Notes: this code can be remove after the s3 script table + // hook on the event EFI_EVENT_SIGNAL_READY_TO_BOOT or + // EFI_EVENT_SIGNAL_LEGACY_BOOT + // + Status = gBS->LocateProtocol (&gEfiAcpiS3SaveProtocolGuid, NULL, &AcpiS3Save); + if (!EFI_ERROR (Status)) { + AcpiS3Save->S3Save (AcpiS3Save, NULL); + } + // + // If it's Device Path that starts with a hard drive path, + // this routine will do the booting. + // + Status = BdsBootByDiskSignatureAndPartition ( + Option, + (HARDDRIVE_DEVICE_PATH *) DevicePath, + Option->LoadOptionsSize, + Option->LoadOptions, + ExitDataSize, + ExitData + ); + if (!EFI_ERROR (Status)) { + // + // If we found a disk signature and partition device path return success + // + return EFI_SUCCESS; + } + + EfiSignalEventReadyToBoot (); + + // + // Set Boot Current + // + gRT->SetVariable ( + L"BootCurrent", + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof (UINT16), + &Option->BootCurrent + ); + + if ((DevicePathType (Option->DevicePath) == BBS_DEVICE_PATH) && + (DevicePathSubType (Option->DevicePath) == BBS_BBS_DP) + ) { + // + // Check to see if we should legacy BOOT. If yes then do the legacy boot + // + return BdsLibDoLegacyBoot (Option); + } + + DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Booting EFI 1.1 way %S\n", Option->Description)); + + Status = gBS->LoadImage ( + TRUE, + mBdsImageHandle, + DevicePath, + NULL, + 0, + &ImageHandle + ); + + // + // If we didn't find an image, we may need to load the default + // boot behavior for the device. + // + if (EFI_ERROR (Status)) { + // + // Find a Simple File System protocol on the device path. If the remaining + // device path is set to end then no Files are being specified, so try + // the removable media file name. + // + TempDevicePath = DevicePath; + Status = gBS->LocateDevicePath ( + &gEfiSimpleFileSystemProtocolGuid, + &TempDevicePath, + &Handle + ); + if (!EFI_ERROR (Status) && IsDevicePathEnd (TempDevicePath)) { + FilePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME); + if (FilePath) { + Status = gBS->LoadImage ( + TRUE, + mBdsImageHandle, + FilePath, + NULL, + 0, + &ImageHandle + ); + if (EFI_ERROR (Status)) { + // + // The DevicePath failed, and it's not a valid + // removable media device. + // + goto Done; + } + } + } else { + Status = EFI_NOT_FOUND; + } + } + + if (EFI_ERROR (Status)) { + // + // It there is any error from the Boot attempt exit now. + // + goto Done; + } + // + // Provide the image with it's load options + // + Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, &ImageInfo); + ASSERT_EFI_ERROR (Status); + + if (Option->LoadOptionsSize != 0) { + ImageInfo->LoadOptionsSize = Option->LoadOptionsSize; + ImageInfo->LoadOptions = Option->LoadOptions; + } + // + // Before calling the image, enable the Watchdog Timer for + // the 5 Minute period + // + gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL); + + Status = gBS->StartImage (ImageHandle, ExitDataSize, ExitData); + DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Image Return Status = %r\n", Status)); + + // + // Clear the Watchdog Timer after the image returns + // + gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL); + +Done: + // + // Clear Boot Current + // + gRT->SetVariable ( + L"BootCurrent", + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + 0, + &Option->BootCurrent + ); + + return Status; +} + +EFI_STATUS +BdsBootByDiskSignatureAndPartition ( + IN BDS_COMMON_OPTION * Option, + IN HARDDRIVE_DEVICE_PATH * HardDriveDevicePath, + IN UINT32 LoadOptionsSize, + IN VOID *LoadOptions, + OUT UINTN *ExitDataSize, + OUT CHAR16 **ExitData OPTIONAL + ) +/*++ + +Routine Description: + + Check to see if a hard ware device path was passed in. If it was then search + all the block IO devices for the passed in hard drive device path. + +Arguments: + + Option - The current processing boot option. + + HardDriveDevicePath - EFI Device Path to boot, if it starts with a hard + drive device path. + + LoadOptionsSize - Passed into gBS->StartImage () + via the loaded image protocol. + + LoadOptions - Passed into gBS->StartImage () + via the loaded image protocol. + + ExitDataSize - returned directly from gBS->StartImage () + + ExitData - returned directly from gBS->StartImage () + +Returns: + + EFI_SUCCESS - Status from gBS->StartImage (), + or BootByDiskSignatureAndPartition () + + EFI_NOT_FOUND - If the Device Path is not found in the system + +--*/ +{ + EFI_STATUS Status; + UINTN BlockIoHandleCount; + EFI_HANDLE *BlockIoBuffer; + EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath; + EFI_DEVICE_PATH_PROTOCOL *BlockIoHdDevicePath; + HARDDRIVE_DEVICE_PATH *TmpHdPath; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; + UINTN Index; + BOOLEAN DevicePathMatch; + HARDDRIVE_DEVICE_PATH *TempPath; + + *ExitDataSize = 0; + *ExitData = NULL; + + if ( !((DevicePathType (&HardDriveDevicePath->Header) == MEDIA_DEVICE_PATH) && + (DevicePathSubType (&HardDriveDevicePath->Header) == MEDIA_HARDDRIVE_DP)) + ) { + // + // If the HardDriveDevicePath does not start with a Hard Drive Device Path + // exit. + // + return EFI_NOT_FOUND; + } + // + // The boot device have already been connected + // + Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer); + if (EFI_ERROR (Status) || BlockIoHandleCount == 0) { + // + // If there was an error or there are no device handles that support + // the BLOCK_IO Protocol, then return. + // + return EFI_NOT_FOUND; + } + // + // Loop through all the device handles that support the BLOCK_IO Protocol + // + for (Index = 0; Index < BlockIoHandleCount; Index++) { + + Status = gBS->HandleProtocol (BlockIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *) &BlockIoDevicePath); + if (EFI_ERROR (Status) || BlockIoDevicePath == NULL) { + continue; + } + // + // Make PreviousDevicePath == the device path node before the end node + // + DevicePath = BlockIoDevicePath; + BlockIoHdDevicePath = NULL; + + // + // find HardDriver device path node + // + while (!IsDevicePathEnd (DevicePath)) { + if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) && + (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP) + ) { + BlockIoHdDevicePath = DevicePath; + break; + } + + DevicePath = NextDevicePathNode (DevicePath); + } + + if (BlockIoHdDevicePath == NULL) { + continue; + } + // + // See if the harddrive device path in blockio matches the orig Hard Drive Node + // + DevicePathMatch = FALSE; + + TmpHdPath = (HARDDRIVE_DEVICE_PATH *) BlockIoHdDevicePath; + TempPath = (HARDDRIVE_DEVICE_PATH *) BdsLibUnpackDevicePath ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath); + + // + // Only several fields will be checked. NOT whole NODE + // + if ( TmpHdPath->PartitionNumber == TempPath->PartitionNumber && + TmpHdPath->MBRType == TempPath->MBRType && + TmpHdPath->SignatureType == TempPath->SignatureType && + CompareGuid ((EFI_GUID *) TmpHdPath->Signature, (EFI_GUID *) TempPath->Signature)) { + // + // Get the matched device path + // + DevicePathMatch = TRUE; + } + // + // Only do the boot, when devicepath match + // + if (DevicePathMatch) { + // + // Combine the Block IO and Hard Drive Device path together and try + // to boot from it. + // + DevicePath = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath); + NewDevicePath = AppendDevicePath (BlockIoDevicePath, DevicePath); + + // + // Recursive boot with new device path + // + Status = BdsLibBootViaBootOption (Option, NewDevicePath, ExitDataSize, ExitData); + if (!EFI_ERROR (Status)) { + break; + } + } + } + + gBS->FreePool (BlockIoBuffer); + return Status; +} + +EFI_STATUS +BdsLibEnumerateAllBootOption ( + IN OUT LIST_ENTRY *BdsBootOptionList + ) +/*++ + +Routine Description: + + This function will enumerate all possible boot device in the system, + it will only excute once of every boot. + +Arguments: + + BdsBootOptionList - The header of the link list which indexed all + current boot options + +Returns: + + EFI_SUCCESS - Finished all the boot device enumerate and create + the boot option base on that boot device + +--*/ +{ + EFI_STATUS Status; + UINT16 BootOptionNumber; + UINTN NumberFileSystemHandles; + EFI_HANDLE *FileSystemHandles; + UINTN NumberBlkIoHandles; + EFI_HANDLE *BlkIoHandles; + EFI_BLOCK_IO_PROTOCOL *BlkIo; + UINTN Index; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + UINTN NumberLoadFileHandles; + EFI_HANDLE *LoadFileHandles; + VOID *ProtocolInstance; + EFI_FIRMWARE_VOLUME_PROTOCOL *Fv; + UINTN FvHandleCount; + EFI_HANDLE *FvHandleBuffer; + EFI_FV_FILETYPE Type; + UINTN Size; + EFI_FV_FILE_ATTRIBUTES Attributes; + UINT32 AuthenticationStatus; + + BootOptionNumber = 0; + + // + // If the boot device enumerate happened, just get the boot + // device from the boot order variable + // + if (mEnumBootDevice) { + BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder"); + return EFI_SUCCESS; + } + // + // Notes: this dirty code is to get the legacy boot option from the + // BBS table and create to variable as the EFI boot option, it should + // be removed after the CSM can provide legacy boot option directly + // + REFRESH_LEGACY_BOOT_OPTIONS; + + // + // Check all the block IO to create boot option + // + gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiBlockIoProtocolGuid, + NULL, + &NumberBlkIoHandles, + &BlkIoHandles + ); + for (Index = 0; Index < NumberBlkIoHandles; Index++) { + Status = gBS->HandleProtocol ( + BlkIoHandles[Index], + &gEfiBlockIoProtocolGuid, + (VOID **) &BlkIo + ); + if (EFI_ERROR (Status)) { + continue; + } + + if (!BlkIo->Media->RemovableMedia) { + // + // Skip fixed Media device on first loop interration + // + continue; + } + + DevicePath = DevicePathFromHandle (BlkIoHandles[Index]); + if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) && + (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP) + ) { + // + // Build the boot option + // + BdsLibBuildOptionFromHandle (BlkIoHandles[Index], BdsBootOptionList); + BootOptionNumber++; + } + } + + if (NumberBlkIoHandles) { + gBS->FreePool (BlkIoHandles); + } + // + // Parse Fixed Disk Devices. + // + gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSimpleFileSystemProtocolGuid, + NULL, + &NumberFileSystemHandles, + &FileSystemHandles + ); + for (Index = 0; Index < NumberFileSystemHandles; Index++) { + Status = gBS->HandleProtocol ( + FileSystemHandles[Index], + &gEfiBlockIoProtocolGuid, + (VOID **) &BlkIo + ); + if (!EFI_ERROR (Status)) { + if (BlkIo->Media->RemovableMedia) { + // + // If the file system handle supports a BlkIo protocol, + // skip the removable media devices + // + continue; + } + } + + DevicePath = DevicePathFromHandle (FileSystemHandles[Index]); + if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) && + (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP) + ) { + // + // If the FileSystem protocol does not contain a BlkIo protocol, + // then build it + // + BdsLibBuildOptionFromHandle (FileSystemHandles[Index], BdsBootOptionList); + BootOptionNumber++; + } + } + + if (NumberFileSystemHandles) { + gBS->FreePool (FileSystemHandles); + } + // + // Parse Network Boot Device + // + gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSimpleNetworkProtocolGuid, + NULL, + &NumberLoadFileHandles, + &LoadFileHandles + ); + for (Index = 0; Index < NumberLoadFileHandles; Index++) { + Status = gBS->HandleProtocol ( + LoadFileHandles[Index], + &gEfiLoadFileProtocolGuid, + (VOID **) &ProtocolInstance + ); + if (EFI_ERROR (Status)) { + continue; + } + + BdsLibBuildOptionFromHandle (LoadFileHandles[Index], BdsBootOptionList); + BootOptionNumber++; + } + + if (NumberLoadFileHandles) { + gBS->FreePool (LoadFileHandles); + } + // + // Check if we have on flash shell + // + gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiFirmwareVolumeProtocolGuid, + NULL, + &FvHandleCount, + &FvHandleBuffer + ); + for (Index = 0; Index < FvHandleCount; Index++) { + gBS->HandleProtocol ( + FvHandleBuffer[Index], + &gEfiFirmwareVolumeProtocolGuid, + (VOID **) &Fv + ); + + Status = Fv->ReadFile ( + Fv, + &gEfiShellFileGuid, + NULL, + &Size, + &Type, + &Attributes, + &AuthenticationStatus + ); + if (EFI_ERROR (Status)) { + // + // Skip if no shell file in the FV + // + continue; + } + // + // Build the shell boot option + // + BdsLibBuildOptionFromShell (FvHandleBuffer[Index], BdsBootOptionList); + BootOptionNumber++; + } + + if (FvHandleCount) { + gBS->FreePool (FvHandleBuffer); + } + // + // Make sure every boot only have one time + // boot device enumerate + // + BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder"); + mEnumBootDevice = TRUE; + + return EFI_SUCCESS; +} + +VOID +BdsLibBuildOptionFromHandle ( + IN EFI_HANDLE Handle, + IN LIST_ENTRY *BdsBootOptionList + ) +/*++ + +Routine Description: + + Build the boot option with the handle parsed in + +Arguments: + + Handle - The handle which present the device path to create boot option + + BdsBootOptionList - The header of the link list which indexed all current + boot options + +Returns: + + VOID + +--*/ +{ + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + CHAR16 *TempString; + + DevicePath = DevicePathFromHandle (Handle); + TempString = DevicePathToStr (DevicePath); + + // + // Create and register new boot option + // + BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, TempString, L"BootOrder"); +} + +VOID +BdsLibBuildOptionFromShell ( + IN EFI_HANDLE Handle, + IN OUT LIST_ENTRY *BdsBootOptionList + ) +/*++ + +Routine Description: + + Build the on flash shell boot option with the handle parsed in + +Arguments: + + Handle - The handle which present the device path to create on flash shell + boot option + + BdsBootOptionList - The header of the link list which indexed all current + boot options + +Returns: + + None + +--*/ +{ + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + MEDIA_FW_VOL_FILEPATH_DEVICE_PATH ShellNode; + + DevicePath = DevicePathFromHandle (Handle); + + // + // Build the shell device path + // + EfiInitializeFwVolDevicepathNode (&ShellNode, &gEfiShellFileGuid); + DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &ShellNode); + + // + // Create and register the shell boot option + // + BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, L"Internal EFI Shell", L"BootOrder"); + +} + +VOID +BdsLibBootNext ( + VOID + ) +/*++ + +Routine Description: + + Boot from the EFI1.1 spec defined "BootNext" variable + +Arguments: + + None + +Returns: + + None + +--*/ +{ + UINT16 *BootNext; + UINTN BootNextSize; + CHAR16 Buffer[20]; + BDS_COMMON_OPTION *BootOption; + LIST_ENTRY TempList; + UINTN ExitDataSize; + CHAR16 *ExitData; + + // + // Init the boot option name buffer and temp link list + // + InitializeListHead (&TempList); + ZeroMem (Buffer, sizeof (Buffer)); + + BootNext = BdsLibGetVariableAndSize ( + L"BootNext", + &gEfiGlobalVariableGuid, + &BootNextSize + ); + + // + // Clear the boot next variable first + // + if (BootNext != NULL) { + gRT->SetVariable ( + L"BootNext", + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + 0, + BootNext + ); + + // + // Start to build the boot option and try to boot + // + UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *BootNext); + BootOption = BdsLibVariableToOption (&TempList, Buffer); + BdsLibConnectDevicePath (BootOption->DevicePath); + BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData); + } + +} diff --git a/EdkNt32Pkg/Library/EdkGenericBdsLib/BdsConnect.c b/EdkNt32Pkg/Library/EdkGenericBdsLib/BdsConnect.c new file mode 100644 index 0000000000..9c649f1f82 --- /dev/null +++ b/EdkNt32Pkg/Library/EdkGenericBdsLib/BdsConnect.c @@ -0,0 +1,357 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + BdsConnect.c + +Abstract: + + BDS Lib functions which relate with connect the device + +--*/ + +VOID +BdsLibConnectAll ( + VOID + ) +/*++ + +Routine Description: + + 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 avialbe and the platform default + console connected. + +Arguments: + + None + +Returns: + + None + +--*/ +{ + // + // Connect the platform console first + // + BdsLibConnectAllDefaultConsoles (); + + // + // Generic way to connect all the drivers + // + BdsLibConnectAllDriversToAllControllers (); + + // + // Here we have the assumption that we have already had + // platform default console + // + BdsLibConnectAllDefaultConsoles (); +} + +VOID +BdsLibGenericConnectAll ( + VOID + ) +/*++ + +Routine Description: + + This function will connect all the system drivers to all controllers + first, and then connect all the console devices the system current + have. After this we should get all the device work and console avariable + if the system have console device. + +Arguments: + + None + +Returns: + + None + +--*/ +{ + // + // Most generic way to connect all the drivers + // + BdsLibConnectAllDriversToAllControllers (); + BdsLibConnectAllConsoles (); +} + +EFI_STATUS +BdsLibConnectDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathToConnect + ) +/*++ + +Routine Description: + 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. + +Arguments: + + DevicePathToConnect - The device path which will be connected, it can + be a multi-instance device path + +Returns: + + EFI_SUCCESS - All handles associate with every device path + node have been created + + EFI_OUT_OF_RESOURCES - There is no resource to create new handles + + EFI_NOT_FOUND - Create the handle associate with one device + path node failed + +--*/ +{ + 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); + 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 fail, RemainingDevicepath and handle will not + // change, so next time will do the dispatch, then dispatch's status + // will take effect + // 2. If the connect success, the RemainingDevicepath and handle will + // change, then avoid the dispatch, we have chance to continue the + // next connection + // + gBS->ConnectController (Handle, NULL, RemainingDevicePath, FALSE); + } + } + // + // Loop until RemainingDevicePath is an empty device path + // + } while (!EFI_ERROR (Status) && !IsDevicePathEnd (RemainingDevicePath)); + + } while (DevicePath != NULL); + + if (CopyOfDevicePath != NULL) { + gBS->FreePool (CopyOfDevicePath); + } + // + // All handle with DevicePath exists in the handle database + // + return Status; +} + +EFI_STATUS +BdsLibConnectAllEfi ( + VOID + ) +/*++ + +Routine Description: + + This function will connect all current system handles recursively. The + connection will finish until every handle's child handle created if it have. + +Arguments: + + None + +Returns: + + EFI_SUCCESS - All handles and it's child handle have been connected + + EFI_STATUS - Return the status of gBS->LocateHandleBuffer(). + +--*/ +{ + EFI_STATUS Status; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + UINTN Index; + + Status = gBS->LocateHandleBuffer ( + AllHandles, + NULL, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE); + } + + gBS->FreePool (HandleBuffer); + + return EFI_SUCCESS; +} + +EFI_STATUS +BdsLibDisconnectAllEfi ( + VOID + ) +/*++ + +Routine Description: + + This function will disconnect all current system handles. The disconnection + will finish until every handle have been disconnected. + +Arguments: + + None + +Returns: + + EFI_SUCCESS - All handles have been disconnected + + EFI_STATUS - Return the status of gBS->LocateHandleBuffer(). + +--*/ +{ + EFI_STATUS Status; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + UINTN Index; + + // + // Disconnect all + // + Status = gBS->LocateHandleBuffer ( + AllHandles, + NULL, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->DisconnectController (HandleBuffer[Index], NULL, NULL); + } + + gBS->FreePool (HandleBuffer); + + return EFI_SUCCESS; +} + +VOID +BdsLibConnectAllDriversToAllControllers ( + VOID + ) +/*++ + +Routine Description: + + Connects all drivers to all controllers. + This function make sure all the current system driver will manage + the correspoinding controllers if have. And at the same time, make + sure all the system controllers have driver to manage it if have. + +Arguments: + + None + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + + do { + // + // Connect All EFI 1.10 drivers following EFI 1.10 algorithm + // + BdsLibConnectAllEfi (); + + // + // Check to see if it's possible to dispatch an more DXE drivers. + // The BdsLibConnectAllEfi () may have made new DXE drivers show up. + // If anything is Dispatched Status == EFI_SUCCESS and we will try + // the connect again. + // + Status = gDS->Dispatch (); + + } while (!EFI_ERROR (Status)); + +} diff --git a/EdkNt32Pkg/Library/EdkGenericBdsLib/BdsConsole.c b/EdkNt32Pkg/Library/EdkGenericBdsLib/BdsConsole.c new file mode 100644 index 0000000000..721d74363a --- /dev/null +++ b/EdkNt32Pkg/Library/EdkGenericBdsLib/BdsConsole.c @@ -0,0 +1,370 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + BdsConsole.c + +Abstract: + + BDS Lib functions which contain all the code to connect console device + +--*/ + +EFI_STATUS +BdsLibUpdateConsoleVariable ( + IN CHAR16 *ConVarName, + IN EFI_DEVICE_PATH_PROTOCOL *CustomizedConDevicePath, + IN EFI_DEVICE_PATH_PROTOCOL *ExclusiveDevicePath + ) +/*++ + +Routine Description: + + This function update console variable based on ConVarName, it can + add or remove one specific console device path from the variable + +Arguments: + + ConVarName - Console related variable name, ConIn, ConOut, ErrOut. + + CustomizedConDevicePath - The console device path which will be added to + the console variable ConVarName, this parameter + can not be multi-instance. + + ExclusiveDevicePath - The console device path which will be removed + from the console variable ConVarName, this + parameter can not be multi-instance. + +Returns: + + EFI_UNSUPPORTED - Add or remove the same device path. + + EFI_SUCCESS - Success add or remove the device path from + the console variable. + +--*/ +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *VarConsole; + UINTN DevicePathSize; + EFI_DEVICE_PATH_PROTOCOL *Instance; + EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; + + VarConsole = NULL; + DevicePathSize = 0; + NewDevicePath = NULL; + Status = EFI_UNSUPPORTED; + + // + // Notes: check the device path point, here should check + // with compare memory + // + if (CustomizedConDevicePath == ExclusiveDevicePath) { + return EFI_UNSUPPORTED; + } + // + // Delete the ExclusiveDevicePath from current default console + // + VarConsole = BdsLibGetVariableAndSize ( + ConVarName, + &gEfiGlobalVariableGuid, + &DevicePathSize + ); + + if (ExclusiveDevicePath != NULL && VarConsole != NULL) { + if (BdsLibMatchDevicePaths (VarConsole, ExclusiveDevicePath)) { + + Instance = GetNextDevicePathInstance (&VarConsole, &DevicePathSize); + + while (VarConsole != NULL) { + if (CompareMem ( + Instance, + ExclusiveDevicePath, + DevicePathSize - sizeof (EFI_DEVICE_PATH_PROTOCOL) + ) == 0) { + // + // Remove the match part + // + NewDevicePath = AppendDevicePathInstance (NewDevicePath, VarConsole); + break; + } else { + // + // Continue the next instance + // + NewDevicePath = AppendDevicePathInstance (NewDevicePath, Instance); + } + + Instance = GetNextDevicePathInstance (&VarConsole, &DevicePathSize); + } + // + // Reset the console variable with new device path + // + gRT->SetVariable ( + ConVarName, + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + GetDevicePathSize (NewDevicePath), + NewDevicePath + ); + } + } + // + // Try to append customized device path + // + VarConsole = BdsLibGetVariableAndSize ( + ConVarName, + &gEfiGlobalVariableGuid, + &DevicePathSize + ); + + if (CustomizedConDevicePath != NULL) { + if (!BdsLibMatchDevicePaths (VarConsole, CustomizedConDevicePath)) { + // + // In the first check, the default console variable will be null, + // just append current customized device path + // + VarConsole = AppendDevicePathInstance (VarConsole, CustomizedConDevicePath); + + // + // Update the variable of the default console + // + gRT->SetVariable ( + ConVarName, + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + GetDevicePathSize (VarConsole), + VarConsole + ); + } + } + + return EFI_SUCCESS; + +} + +EFI_STATUS +BdsLibConnectConsoleVariable ( + IN CHAR16 *ConVarName + ) +/*++ + +Routine Description: + + 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. + +Arguments: + + ConVarName - Console related variable name, ConIn, ConOut, ErrOut. + +Returns: + + EFI_NOT_FOUND - There is not any console devices connected success + + EFI_SUCCESS - Success connect any one instance of the console + device path base on the variable ConVarName. + +--*/ +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *StartDevicePath; + UINTN VariableSize; + EFI_DEVICE_PATH_PROTOCOL *Instance; + EFI_DEVICE_PATH_PROTOCOL *Next; + EFI_DEVICE_PATH_PROTOCOL *CopyOfDevicePath; + UINTN Size; + BOOLEAN DeviceExist; + + Status = EFI_SUCCESS; + DeviceExist = FALSE; + + // + // Check if the console variable exist + // + StartDevicePath = BdsLibGetVariableAndSize ( + ConVarName, + &gEfiGlobalVariableGuid, + &VariableSize + ); + if (StartDevicePath == NULL) { + return EFI_UNSUPPORTED; + } + + CopyOfDevicePath = DuplicateDevicePath (StartDevicePath); + do { + // + // Check every instance of the console variable + // + Instance = GetNextDevicePathInstance (&CopyOfDevicePath, &Size); + Next = Instance; + while (!IsDevicePathEndType (Next)) { + Next = NextDevicePathNode (Next); + } + + SetDevicePathEndNode (Next); + + // + // Connect the instance device path + // + Status = BdsLibConnectDevicePath (Instance); + if (EFI_ERROR (Status)) { + // + // Delete the instance from the console varialbe + // + BdsLibUpdateConsoleVariable (ConVarName, NULL, Instance); + } else { + DeviceExist = TRUE; + } + + } while (CopyOfDevicePath != NULL); + + gBS->FreePool (StartDevicePath); + + if (DeviceExist == FALSE) { + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} + +VOID +BdsLibConnectAllConsoles ( + VOID + ) +/*++ + +Routine Description: + + This function will search every simpletxt devive in current system, + and make every simpletxt device as pertantial console device. + +Arguments: + + None + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + UINTN Index; + EFI_DEVICE_PATH_PROTOCOL *ConDevicePath; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + + Index = 0; + HandleCount = 0; + HandleBuffer = NULL; + ConDevicePath = NULL; + + // + // Update all the console varables + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSimpleTextInProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiDevicePathProtocolGuid, + (VOID **) &ConDevicePath + ); + BdsLibUpdateConsoleVariable (L"ConIn", ConDevicePath, NULL); + } + + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSimpleTextOutProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiDevicePathProtocolGuid, + (VOID **) &ConDevicePath + ); + BdsLibUpdateConsoleVariable (L"ConOut", ConDevicePath, NULL); + BdsLibUpdateConsoleVariable (L"ErrOut", ConDevicePath, NULL); + } + // + // Connect all console variables + // + BdsLibConnectAllDefaultConsoles (); + +} + +EFI_STATUS +BdsLibConnectAllDefaultConsoles ( + VOID + ) +/*++ + +Routine Description: + + This function will connect console device base on the console + device variable ConIn, ConOut and ErrOut. + +Arguments: + + None + +Returns: + + EFI_SUCCESS - At least one of the ConIn and ConOut device have + been connected success. + + EFI_STATUS - Return the status of BdsLibConnectConsoleVariable (). + +--*/ +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *VarErrout; + UINTN DevicePathSize; + + // + // Connect all default console variables + // + Status = BdsLibConnectConsoleVariable (L"ConIn"); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = BdsLibConnectConsoleVariable (L"ConOut"); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Special treat the err out device, becaues the null + // err out var is legal. + // + VarErrout = BdsLibGetVariableAndSize ( + L"ErrOut", + &gEfiGlobalVariableGuid, + &DevicePathSize + ); + if (VarErrout != NULL) { + BdsLibConnectConsoleVariable (L"ErrOut"); + } + + return EFI_SUCCESS; + +} diff --git a/EdkNt32Pkg/Library/EdkGenericBdsLib/BdsMisc.c b/EdkNt32Pkg/Library/EdkGenericBdsLib/BdsMisc.c new file mode 100644 index 0000000000..576ae7237f --- /dev/null +++ b/EdkNt32Pkg/Library/EdkGenericBdsLib/BdsMisc.c @@ -0,0 +1,764 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + BdsMisc.c + +Abstract: + + Misc BDS library function + +--*/ + +extern UINT16 gPlatformBootTimeOutDefault; + +UINT16 +BdsLibGetTimeout ( + VOID + ) +/*++ + +Routine Description: + + Return the default value for system Timeout variable. + +Arguments: + + None + +Returns: + + Timeout value. + +--*/ +{ + UINT16 Timeout; + UINTN Size; + EFI_STATUS Status; + + // + // Return Timeout variable or 0xffff if no valid + // Timeout variable exists. + // + Size = sizeof (UINT16); + Status = gRT->GetVariable (L"Timeout", &gEfiGlobalVariableGuid, NULL, &Size, &Timeout); + if (!EFI_ERROR (Status)) { + return Timeout; + } + // + // To make the current EFI Automatic-Test activity possible, just add + // following code to make AutoBoot enabled when this variable is not + // present. + // This code should be removed later. + // + Timeout = gPlatformBootTimeOutDefault; + + // + // Notes: Platform should set default variable if non exists on all error cases!!! + // + Status = gRT->SetVariable ( + L"Timeout", + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + sizeof (UINT16), + &Timeout + ); + return Timeout; +} + +VOID +BdsLibLoadDrivers ( + IN LIST_ENTRY *BdsDriverLists + ) +/*++ + +Routine Description: + + The function will go through the driver optoin link list, load and start + every driver the driver optoin device path point to. + +Arguments: + + BdsDriverLists - The header of the current driver option link list + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + BDS_COMMON_OPTION *Option; + EFI_HANDLE ImageHandle; + EFI_LOADED_IMAGE_PROTOCOL *ImageInfo; + UINTN ExitDataSize; + CHAR16 *ExitData; + BOOLEAN ReconnectAll; + + ReconnectAll = FALSE; + + // + // Process the driver option + // + for (Link = BdsDriverLists->ForwardLink; Link != BdsDriverLists; Link = Link->ForwardLink) { + Option = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE); + // + // If a load option is not marked as LOAD_OPTION_ACTIVE, + // the boot manager will not automatically load the option. + // + if (!IS_LOAD_OPTION_TYPE (Option->Attribute, LOAD_OPTION_ACTIVE)) { + continue; + } + // + // If a driver load option is marked as LOAD_OPTION_FORCE_RECONNECT, + // then all of the EFI drivers in the system will be disconnected and + // reconnected after the last driver load option is processed. + // + if (IS_LOAD_OPTION_TYPE (Option->Attribute, LOAD_OPTION_FORCE_RECONNECT)) { + ReconnectAll = TRUE; + } + // + // Make sure the driver path is connected. + // + BdsLibConnectDevicePath (Option->DevicePath); + + // + // Load and start the image that Driver#### describes + // + Status = gBS->LoadImage ( + FALSE, + mBdsImageHandle, + Option->DevicePath, + NULL, + 0, + &ImageHandle + ); + + if (!EFI_ERROR (Status)) { + gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, &ImageInfo); + + // + // Verify whether this image is a driver, if not, + // exit it and continue to parse next load option + // + if (ImageInfo->ImageCodeType != EfiBootServicesCode && ImageInfo->ImageCodeType != EfiRuntimeServicesCode) { + gBS->Exit (ImageHandle, EFI_INVALID_PARAMETER, 0, NULL); + continue; + } + + if (Option->LoadOptionsSize != 0) { + ImageInfo->LoadOptionsSize = Option->LoadOptionsSize; + ImageInfo->LoadOptions = Option->LoadOptions; + } + // + // Before calling the image, enable the Watchdog Timer for + // the 5 Minute period + // + gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL); + + Status = gBS->StartImage (ImageHandle, &ExitDataSize, &ExitData); + DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Driver Return Status = %r\n", Status)); + + // + // Clear the Watchdog Timer after the image returns + // + gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL); + } + } + // + // Process the LOAD_OPTION_FORCE_RECONNECT driver option + // + if (ReconnectAll) { + BdsLibDisconnectAllEfi (); + BdsLibConnectAll (); + } + +} + +EFI_STATUS +BdsLibRegisterNewOption ( + IN LIST_ENTRY *BdsOptionList, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN CHAR16 *String, + IN CHAR16 *VariableName + ) +/*++ + +Routine Description: + + This function will register the new boot#### or driver#### option base on + the VariableName. The new registered boot#### or driver#### will be linked + to BdsOptionList and also update to the VariableName. After the boot#### or + driver#### updated, the BootOrder or DriverOrder will also be updated. + +Arguments: + + BdsOptionList - The header of the boot#### or driver#### link list + + DevicePath - The device path which the boot#### + or driver#### option present + + String - The description of the boot#### or driver#### + + VariableName - Indicate if the boot#### or driver#### option + +Returns: + + EFI_SUCCESS - The boot#### or driver#### have been success registered + + EFI_STATUS - Return the status of gRT->SetVariable (). + +--*/ +{ + EFI_STATUS Status; + UINTN Index; + UINT16 MaxOptionNumber; + UINT16 RegisterOptionNumber; + UINT16 *TempOptionPtr; + UINTN TempOptionSize; + UINT16 *OptionOrderPtr; + VOID *OptionPtr; + UINTN OptionSize; + UINT8 *TempPtr; + EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath; + CHAR16 *Description; + CHAR16 OptionName[10]; + BOOLEAN UpdateBootDevicePath; + + OptionPtr = NULL; + OptionSize = 0; + TempPtr = NULL; + OptionDevicePath = NULL; + Description = NULL; + MaxOptionNumber = 0; + OptionOrderPtr = NULL; + UpdateBootDevicePath = FALSE; + ZeroMem (OptionName, sizeof (OptionName)); + + TempOptionSize = 0; + TempOptionPtr = BdsLibGetVariableAndSize ( + VariableName, + &gEfiGlobalVariableGuid, + &TempOptionSize + ); + // + // Compare with current option variable + // + for (Index = 0; Index < TempOptionSize / sizeof (UINT16); Index++) { + // + // Got the max option#### number + // + if (MaxOptionNumber < TempOptionPtr[Index]) { + MaxOptionNumber = TempOptionPtr[Index]; + } + + if (*VariableName == 'B') { + UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", TempOptionPtr[Index]); + } else { + UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", TempOptionPtr[Index]); + } + + OptionPtr = BdsLibGetVariableAndSize ( + OptionName, + &gEfiGlobalVariableGuid, + &OptionSize + ); + TempPtr = OptionPtr; + TempPtr += sizeof (UINT32) + sizeof (UINT16); + Description = (CHAR16 *) TempPtr; + TempPtr += StrSize ((CHAR16 *) TempPtr); + OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr; + + // + // Notes: the description may will change base on the GetStringToken + // + if (CompareMem (Description, String, StrSize (Description)) == 0) { + if (CompareMem (OptionDevicePath, DevicePath, GetDevicePathSize (OptionDevicePath)) == 0) { + // + // Got the option, so just return + // + gBS->FreePool (OptionPtr); + gBS->FreePool (TempOptionPtr); + return EFI_SUCCESS; + } else { + // + // Boot device path changed, need update. + // + UpdateBootDevicePath = TRUE; + break; + } + } + + gBS->FreePool (OptionPtr); + } + + OptionSize = sizeof (UINT32) + sizeof (UINT16) + StrSize (String) + GetDevicePathSize (DevicePath); + OptionPtr = AllocateZeroPool (OptionSize); + TempPtr = OptionPtr; + *(UINT32 *) TempPtr = LOAD_OPTION_ACTIVE; + TempPtr += sizeof (UINT32); + *(UINT16 *) TempPtr = (UINT16) GetDevicePathSize (DevicePath); + TempPtr += sizeof (UINT16); + CopyMem (TempPtr, String, StrSize (String)); + TempPtr += StrSize (String); + CopyMem (TempPtr, DevicePath, GetDevicePathSize (DevicePath)); + + if (UpdateBootDevicePath) { + // + // The number in option#### to be updated + // + RegisterOptionNumber = TempOptionPtr[Index]; + } else { + // + // The new option#### number + // + RegisterOptionNumber = MaxOptionNumber + 1; + } + + if (*VariableName == 'B') { + UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", RegisterOptionNumber); + } else { + UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", RegisterOptionNumber); + } + + Status = gRT->SetVariable ( + OptionName, + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + OptionSize, + OptionPtr + ); + if (EFI_ERROR (Status) || UpdateBootDevicePath) { + gBS->FreePool (OptionPtr); + gBS->FreePool (TempOptionPtr); + return Status; + } + + gBS->FreePool (OptionPtr); + + // + // Update the option order variable + // + OptionOrderPtr = AllocateZeroPool ((Index + 1) * sizeof (UINT16)); + CopyMem (OptionOrderPtr, TempOptionPtr, Index * sizeof (UINT16)); + OptionOrderPtr[Index] = RegisterOptionNumber; + Status = gRT->SetVariable ( + VariableName, + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + (Index + 1) * sizeof (UINT16), + OptionOrderPtr + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (TempOptionPtr); + gBS->FreePool (OptionOrderPtr); + return Status; + } + + gBS->FreePool (TempOptionPtr); + gBS->FreePool (OptionOrderPtr); + + return EFI_SUCCESS; +} + +BDS_COMMON_OPTION * +BdsLibVariableToOption ( + IN OUT LIST_ENTRY *BdsCommonOptionList, + IN CHAR16 *VariableName + ) +/*++ + +Routine Description: + + Build the boot#### or driver#### option from the VariableName, the + build boot#### or driver#### will also be linked to BdsCommonOptionList + +Arguments: + + BdsCommonOptionList - The header of the boot#### or driver#### option link list + + VariableName - EFI Variable name indicate if it is boot#### or driver#### + +Returns: + + BDS_COMMON_OPTION - Get the option just been created + + NULL - Failed to get the new option + +--*/ +{ + UINT32 Attribute; + UINT16 FilePathSize; + UINT8 *Variable; + UINT8 *TempPtr; + UINTN VariableSize; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + BDS_COMMON_OPTION *Option; + VOID *LoadOptions; + UINT32 LoadOptionsSize; + CHAR16 *Description; + + // + // Read the variable. We will never free this data. + // + Variable = BdsLibGetVariableAndSize ( + VariableName, + &gEfiGlobalVariableGuid, + &VariableSize + ); + if (Variable == NULL) { + return NULL; + } + // + // Notes: careful defined the variable of Boot#### or + // Driver####, consider use some macro to abstract the code + // + // + // Get the option attribute + // + TempPtr = Variable; + Attribute = *(UINT32 *) Variable; + TempPtr += sizeof (UINT32); + + // + // Get the option's device path size + // + FilePathSize = *(UINT16 *) TempPtr; + TempPtr += sizeof (UINT16); + + // + // Get the option's description string + // + Description = (CHAR16 *) TempPtr; + + // + // Get the option's description string size + // + TempPtr += StrSize ((CHAR16 *) TempPtr); + + // + // Get the option's device path + // + DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr; + TempPtr += FilePathSize; + + LoadOptions = TempPtr; + LoadOptionsSize = (UINT32) (VariableSize - (UINTN) (TempPtr - Variable)); + + // + // The Console variables may have multiple device paths, so make + // an Entry for each one. + // + Option = AllocateZeroPool (sizeof (BDS_COMMON_OPTION)); + if (Option == NULL) { + return NULL; + } + + Option->Signature = BDS_LOAD_OPTION_SIGNATURE; + Option->DevicePath = AllocateZeroPool (GetDevicePathSize (DevicePath)); + CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath)); + Option->Attribute = Attribute; + Option->Description = AllocateZeroPool (StrSize (Description)); + CopyMem (Option->Description, Description, StrSize (Description)); + Option->LoadOptions = AllocateZeroPool (LoadOptionsSize); + CopyMem (Option->LoadOptions, LoadOptions, LoadOptionsSize); + Option->LoadOptionsSize = LoadOptionsSize; + + // + // Insert active entry to BdsDeviceList + // + if ((Option->Attribute & LOAD_OPTION_ACTIVE) == LOAD_OPTION_ACTIVE) { + InsertTailList (BdsCommonOptionList, &Option->Link); + gBS->FreePool (Variable); + return Option; + } + + gBS->FreePool (Variable); + gBS->FreePool (Option); + return NULL; + +} + +EFI_STATUS +BdsLibBuildOptionFromVar ( + IN LIST_ENTRY *BdsCommonOptionList, + IN CHAR16 *VariableName + ) +/*++ + +Routine Description: + + Process BootOrder, or DriverOrder variables, by calling + BdsLibVariableToOption () for each UINT16 in the variables. + +Arguments: + + BdsCommonOptionList - The header of the option list base on variable + VariableName + + VariableName - EFI Variable name indicate the BootOrder or DriverOrder + +Returns: + + EFI_SUCCESS - Success create the boot option or driver option list + + EFI_OUT_OF_RESOURCES - Failed to get the boot option or driver option list + +--*/ +{ + UINT16 *OptionOrder; + UINTN OptionOrderSize; + UINTN Index; + BDS_COMMON_OPTION *Option; + CHAR16 OptionName[20]; + + // + // Zero Buffer in order to get all BOOT#### variables + // + ZeroMem (OptionName, sizeof (OptionName)); + + // + // Read the BootOrder, or DriverOrder variable. + // + OptionOrder = BdsLibGetVariableAndSize ( + VariableName, + &gEfiGlobalVariableGuid, + &OptionOrderSize + ); + if (OptionOrder == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) { + if (*VariableName == 'B') { + UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", OptionOrder[Index]); + } else { + UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", OptionOrder[Index]); + } + Option = BdsLibVariableToOption (BdsCommonOptionList, OptionName); + Option->BootCurrent = OptionOrder[Index]; + + } + + gBS->FreePool (OptionOrder); + + return EFI_SUCCESS; +} + +EFI_STATUS +BdsLibGetBootMode ( + OUT EFI_BOOT_MODE *BootMode + ) +/*++ + +Routine Description: + + Get boot mode by looking up configuration table and parsing HOB list + +Arguments: + + BootMode - Boot mode from PEI handoff HOB. + +Returns: + + EFI_SUCCESS - Successfully get boot mode + + EFI_NOT_FOUND - Can not find the current system boot mode + +--*/ +{ + EFI_HOB_HANDOFF_INFO_TABLE *HobList; + + HobList = GetHobList (); + ASSERT (HobList->Header.HobType == EFI_HOB_TYPE_HANDOFF); + *BootMode = HobList->BootMode; + + return EFI_SUCCESS; +} + +VOID * +BdsLibGetVariableAndSize ( + IN CHAR16 *Name, + IN EFI_GUID *VendorGuid, + OUT UINTN *VariableSize + ) +/*++ + +Routine Description: + + Read the EFI variable (VendorGuid/Name) and return a dynamically allocated + buffer, and the size of the buffer. If failure return NULL. + +Arguments: + + Name - String part of EFI variable name + + VendorGuid - GUID part of EFI variable name + + VariableSize - Returns the size of the EFI variable that was read + +Returns: + + Dynamically allocated memory that contains a copy of the EFI variable. + Caller is responsible freeing the buffer. + + NULL - Variable was not read + +--*/ +{ + 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; +} + +BOOLEAN +BdsLibMatchDevicePaths ( + IN EFI_DEVICE_PATH_PROTOCOL *Multi, + IN EFI_DEVICE_PATH_PROTOCOL *Single + ) +/*++ + +Routine Description: + + Function compares a device path data structure to that of all the nodes of a + second device path instance. + +Arguments: + + Multi - A pointer to a multi-instance device path data structure. + + Single - A pointer to a single-instance device path data structure. + +Returns: + + TRUE - If the Single is contained within Multi + + FALSE - The Single is not match within Multi + + +--*/ +{ + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_DEVICE_PATH_PROTOCOL *DevicePathInst; + UINTN Size; + + if (!Multi || !Single) { + return FALSE; + } + + DevicePath = Multi; + DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size); + Size -= sizeof (EFI_DEVICE_PATH_PROTOCOL); + + // + // 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 (Size == 0) { + return FALSE; + } + + if (CompareMem (Single, DevicePathInst, Size) == 0) { + return TRUE; + } + + gBS->FreePool (DevicePathInst); + DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size); + Size -= sizeof (EFI_DEVICE_PATH_PROTOCOL); + } + + return FALSE; +} + +EFI_STATUS +BdsLibOutputStrings ( + IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *ConOut, + ... + ) +/*++ + +Routine Description: + + This function prints a series of strings. + +Arguments: + + ConOut - Pointer to EFI_SIMPLE_TEXT_OUT_PROTOCOL + + ... - A variable argument list containing series of strings, + the last string must be NULL. + +Returns: + + EFI_SUCCESS - Success print out the string using ConOut. + + EFI_STATUS - Return the status of the ConOut->OutputString (). + +--*/ +{ + VA_LIST args; + EFI_STATUS Status; + CHAR16 *String; + + Status = EFI_SUCCESS; + VA_START (args, ConOut); + + while (!EFI_ERROR (Status)) { + // + // If String is NULL, then it's the end of the list + // + String = VA_ARG (args, CHAR16 *); + if (!String) { + break; + } + + Status = ConOut->OutputString (ConOut, String); + + if (EFI_ERROR (Status)) { + break; + } + } + + return Status; +} diff --git a/EdkNt32Pkg/Library/EdkGenericBdsLib/DevicePath.c b/EdkNt32Pkg/Library/EdkGenericBdsLib/DevicePath.c new file mode 100644 index 0000000000..de854103cb --- /dev/null +++ b/EdkNt32Pkg/Library/EdkGenericBdsLib/DevicePath.c @@ -0,0 +1,988 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DevicePath.c + +Abstract: + + BDS internal function define the default device path string, it can be + replaced by platform device path. + +--*/ + + +#ifdef TIANO_EXTENSION_FLAG +EFI_GUID UnknownDeviceGuid = UNKNOWN_DEVICE_GUID; +#endif + +EFI_GUID mEfiWinNtThunkProtocolGuid = EFI_WIN_NT_THUNK_PROTOCOL_GUID; +EFI_GUID mEfiWinNtUgaGuid = EFI_WIN_NT_UGA_GUID; +EFI_GUID mEfiWinNtSerialPortGuid = EFI_WIN_NT_SERIAL_PORT_GUID; +EFI_GUID mEfiMsgPcAnsiGuid = DEVICE_PATH_MESSAGING_PC_ANSI; +EFI_GUID mEfiMsgVt100Guid = DEVICE_PATH_MESSAGING_VT_100; +EFI_GUID mEfiMsgVt100PlusGuid = DEVICE_PATH_MESSAGING_VT_100_PLUS; +EFI_GUID mEfiMsgVt100Utf8Guid = DEVICE_PATH_MESSAGING_VT_UTF8; + +VOID * +ReallocatePool ( + IN VOID *OldPool, + IN UINTN OldSize, + IN UINTN NewSize + ) +/*++ + +Routine Description: + + Adjusts the size of a previously allocated buffer. + +Arguments: + + OldPool - A pointer to the buffer whose size is being adjusted. + + OldSize - The size of the current buffer. + + NewSize - The size of the new buffer. + +Returns: + + EFI_SUCEESS - The requested number of bytes were allocated. + + EFI_OUT_OF_RESOURCES - The pool requested could not be allocated. + + EFI_INVALID_PARAMETER - The buffer was invalid. + +--*/ +{ + VOID *NewPool; + + NewPool = NULL; + if (NewSize) { + NewPool = AllocateZeroPool (NewSize); + } + + if (OldPool) { + if (NewPool) { + CopyMem (NewPool, OldPool, OldSize < NewSize ? OldSize : NewSize); + } + + gBS->FreePool (OldPool); + } + + return NewPool; +} + +CHAR16 * +CatPrint ( + IN OUT POOL_PRINT *Str, + IN CHAR16 *fmt, + ... + ) +/*++ + +Routine Description: + + Concatenates a formatted unicode string to allocated pool. + The caller must free the resulting buffer. + +Arguments: + + Str - Tracks the allocated pool, size in use, and + amount of pool allocated. + + fmt - The format string + +Returns: + + Allocated buffer with the formatted string printed in it. + The caller must free the allocated buffer. The buffer + allocation is not packed. + +--*/ +{ + UINT16 *AppendStr; + VA_LIST args; + UINTN strsize; + + AppendStr = AllocateZeroPool (0x1000); + if (AppendStr == NULL) { + return Str->str; + } + + VA_START (args, fmt); + UnicodeVSPrint (AppendStr, 0x1000, fmt, args); + VA_END (args); + if (NULL == Str->str) { + strsize = StrSize (AppendStr); + Str->str = AllocateZeroPool (strsize); + ASSERT (Str->str != NULL); + } else { + strsize = StrSize (AppendStr) + StrSize (Str->str) - sizeof (UINT16); + Str->str = ReallocatePool ( + Str->str, + StrSize (Str->str), + strsize + ); + ASSERT (Str->str != NULL); + } + + Str->maxlen = MAX_CHAR * sizeof (UINT16); + if (strsize < Str->maxlen) { + StrCat (Str->str, AppendStr); + Str->len = strsize - sizeof (UINT16); + } + + gBS->FreePool (AppendStr); + return Str->str; +} + +EFI_DEVICE_PATH_PROTOCOL * +BdsLibUnpackDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevPath + ) +/*++ + +Routine Description: + + Function unpacks a device path data structure so that all the nodes + of a device path are naturally aligned. + +Arguments: + + DevPath - A pointer to a device path data structure + +Returns: + + If the memory for the device path is successfully allocated, then a + pointer to the new device path is returned. Otherwise, NULL is returned. + +--*/ +{ + EFI_DEVICE_PATH_PROTOCOL *Src; + EFI_DEVICE_PATH_PROTOCOL *Dest; + EFI_DEVICE_PATH_PROTOCOL *NewPath; + UINTN Size; + + // + // Walk device path and round sizes to valid boundries + // + Src = DevPath; + Size = 0; + for (;;) { + Size += DevicePathNodeLength (Src); + Size += ALIGN_SIZE (Size); + + if (IsDevicePathEnd (Src)) { + break; + } + + Src = NextDevicePathNode (Src); + } + // + // Allocate space for the unpacked path + // + NewPath = AllocateZeroPool (Size); + if (NewPath) { + + ASSERT (((UINTN) NewPath) % MIN_ALIGNMENT_SIZE == 0); + + // + // Copy each node + // + Src = DevPath; + Dest = NewPath; + for (;;) { + Size = DevicePathNodeLength (Src); + CopyMem (Dest, Src, Size); + Size += ALIGN_SIZE (Size); + SetDevicePathNodeLength (Dest, Size); + Dest->Type |= EFI_DP_TYPE_UNPACKED; + Dest = (EFI_DEVICE_PATH_PROTOCOL *) (((UINT8 *) Dest) + Size); + + if (IsDevicePathEnd (Src)) { + break; + } + + Src = NextDevicePathNode (Src); + } + } + + return NewPath; +} + +VOID +DevPathPci ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + PCI_DEVICE_PATH *Pci; + + Pci = DevPath; + CatPrint (Str, L"Pci(%x|%x)", Pci->Device, Pci->Function); +} + +VOID +DevPathPccard ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + PCCARD_DEVICE_PATH *Pccard; + + Pccard = DevPath; + CatPrint (Str, L"Pcmcia(Function%x)", Pccard->FunctionNumber); +} + +VOID +DevPathMemMap ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + MEMMAP_DEVICE_PATH *MemMap; + + MemMap = DevPath; + CatPrint ( + Str, + L"MemMap(%d:%.lx-%.lx)", + MemMap->MemoryType, + MemMap->StartingAddress, + MemMap->EndingAddress + ); +} + +VOID +DevPathController ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + CONTROLLER_DEVICE_PATH *Controller; + + Controller = DevPath; + CatPrint (Str, L"Ctrl(%d)", Controller->ControllerNumber); +} + +VOID +DevPathVendor ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +/*++ + +Routine Description: + + Convert Vendor device path to device name + +Arguments: + + Str - The buffer store device name + DevPath - Pointer to vendor device path + +Returns: + + When it return, the device name have been stored in *Str. + +--*/ +{ + VENDOR_DEVICE_PATH *Vendor; + CHAR16 *Type; + INT32 *Temp; + + Vendor = DevPath; + Temp = (INT32 *) (&Vendor->Guid); + + switch (DevicePathType (&Vendor->Header)) { + case HARDWARE_DEVICE_PATH: + // + // If the device is a winntbus device, we will give it a readable device name. + // + if (CompareGuid (&Vendor->Guid, &mEfiWinNtThunkProtocolGuid)) { + CatPrint (Str, L"%s", L"WinNtBus"); + return ; + } else if (CompareGuid (&Vendor->Guid, &mEfiWinNtUgaGuid)) { + CatPrint (Str, L"%s", L"UGA"); + return ; + } else if (CompareGuid (&Vendor->Guid, &mEfiWinNtSerialPortGuid)) { + CatPrint (Str, L"%s", L"Serial"); + return ; + } else { + Type = L"Hw"; + break; + } + + case MESSAGING_DEVICE_PATH: + // + // If the device is a winntbus device, we will give it a readable device name. + // + if (CompareGuid (&Vendor->Guid, &mEfiMsgPcAnsiGuid)) { + CatPrint (Str, L"%s", L"PC-ANSI"); + return ; + } else if (CompareGuid (&Vendor->Guid, &mEfiMsgVt100Guid)) { + CatPrint (Str, L"%s", L"VT100"); + return ; + } else if (CompareGuid (&Vendor->Guid, &mEfiMsgVt100PlusGuid)) { + CatPrint (Str, L"%s", L"VT100+"); + return ; + } else if (CompareGuid (&Vendor->Guid, &mEfiMsgVt100Utf8Guid)) { + CatPrint (Str, L"%s", L"VT100-UTF8"); + return ; + } else { + Type = L"Msg"; + break; + } + + case MEDIA_DEVICE_PATH: + Type = L"Media"; + break; + + default: + Type = L"?"; + break; + } + + CatPrint (Str, L"Ven%s(%g)", Type, &Vendor->Guid); +} + +VOID +DevPathAcpi ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + ACPI_HID_DEVICE_PATH *Acpi; + + Acpi = DevPath; + if ((Acpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) { + CatPrint (Str, L"Acpi(PNP%04x,%x)", EISA_ID_TO_NUM (Acpi->HID), Acpi->UID); + } else { + CatPrint (Str, L"Acpi(%08x,%x)", Acpi->HID, Acpi->UID); + } +} + +VOID +DevPathAtapi ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + ATAPI_DEVICE_PATH *Atapi; + + Atapi = DevPath; + CatPrint ( + Str, + L"Ata(%s,%s)", + Atapi->PrimarySecondary ? L"Secondary" : L"Primary", + Atapi->SlaveMaster ? L"Slave" : L"Master" + ); +} + +VOID +DevPathScsi ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + SCSI_DEVICE_PATH *Scsi; + + Scsi = DevPath; + CatPrint (Str, L"Scsi(Pun%x,Lun%x)", Scsi->Pun, Scsi->Lun); +} + +VOID +DevPathFibre ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + FIBRECHANNEL_DEVICE_PATH *Fibre; + + Fibre = DevPath; + CatPrint (Str, L"Fibre(Wwn%lx,Lun%x)", Fibre->WWN, Fibre->Lun); +} + +VOID +DevPath1394 ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + F1394_DEVICE_PATH *F1394; + + F1394 = DevPath; + CatPrint (Str, L"1394(%g)", &F1394->Guid); +} + +VOID +DevPathUsb ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + USB_DEVICE_PATH *Usb; + + Usb = DevPath; + CatPrint (Str, L"Usb(%x, %x)", Usb->ParentPortNumber, Usb->InterfaceNumber); +} + +VOID +DevPathUsbClass ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + USB_CLASS_DEVICE_PATH *UsbClass; + + UsbClass = DevPath; + CatPrint ( + Str, + L"Usb Class(%x, %x, %x, %x, %x)", + UsbClass->VendorId, + UsbClass->ProductId, + UsbClass->DeviceClass, + UsbClass->DeviceSubClass, + UsbClass->DeviceProtocol + ); +} + +VOID +DevPathI2O ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + I2O_DEVICE_PATH *I2O; + + I2O = DevPath; + CatPrint (Str, L"I2O(%x)", I2O->Tid); +} + +VOID +DevPathMacAddr ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + MAC_ADDR_DEVICE_PATH *MAC; + UINTN HwAddressSize; + UINTN Index; + + MAC = DevPath; + + HwAddressSize = sizeof (EFI_MAC_ADDRESS); + if (MAC->IfType == 0x01 || MAC->IfType == 0x00) { + HwAddressSize = 6; + } + + CatPrint (Str, L"Mac("); + + for (Index = 0; Index < HwAddressSize; Index++) { + CatPrint (Str, L"%02x", MAC->MacAddress.Addr[Index]); + } + + CatPrint (Str, L")"); +} + +VOID +DevPathIPv4 ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + IPv4_DEVICE_PATH *IP; + + IP = DevPath; + CatPrint ( + Str, + L"IPv4(%d.%d.%d.%d:%d)", + IP->RemoteIpAddress.Addr[0], + IP->RemoteIpAddress.Addr[1], + IP->RemoteIpAddress.Addr[2], + IP->RemoteIpAddress.Addr[3], + IP->RemotePort + ); +} + +VOID +DevPathIPv6 ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + IPv6_DEVICE_PATH *IP; + + IP = DevPath; + CatPrint (Str, L"IP-v6(not-done)"); +} + +VOID +DevPathInfiniBand ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + INFINIBAND_DEVICE_PATH *InfiniBand; + + InfiniBand = DevPath; + CatPrint (Str, L"InfiniBand(not-done)"); +} + +VOID +DevPathUart ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + UART_DEVICE_PATH *Uart; + CHAR8 Parity; + + Uart = DevPath; + switch (Uart->Parity) { + case 0: + Parity = 'D'; + break; + + case 1: + Parity = 'N'; + break; + + case 2: + Parity = 'E'; + break; + + case 3: + Parity = 'O'; + break; + + case 4: + Parity = 'M'; + break; + + case 5: + Parity = 'S'; + break; + + default: + Parity = 'x'; + break; + } + + if (Uart->BaudRate == 0) { + CatPrint (Str, L"Uart(DEFAULT %c", Parity); + } else { + CatPrint (Str, L"Uart(%d %c", Uart->BaudRate, Parity); + } + + if (Uart->DataBits == 0) { + CatPrint (Str, L"D"); + } else { + CatPrint (Str, L"%d", Uart->DataBits); + } + + switch (Uart->StopBits) { + case 0: + CatPrint (Str, L"D)"); + break; + + case 1: + CatPrint (Str, L"1)"); + break; + + case 2: + CatPrint (Str, L"1.5)"); + break; + + case 3: + CatPrint (Str, L"2)"); + break; + + default: + CatPrint (Str, L"x)"); + break; + } +} + +VOID +DevPathHardDrive ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + HARDDRIVE_DEVICE_PATH *Hd; + + Hd = DevPath; + switch (Hd->SignatureType) { + case SIGNATURE_TYPE_MBR: + CatPrint ( + Str, + L"HD(Part%d,Sig%08x)", + Hd->PartitionNumber, + *((UINT32 *) (&(Hd->Signature[0]))) + ); + break; + + case SIGNATURE_TYPE_GUID: + CatPrint ( + Str, + L"HD(Part%d,Sig%g)", + Hd->PartitionNumber, + (EFI_GUID *) &(Hd->Signature[0]) + ); + break; + + default: + CatPrint ( + Str, + L"HD(Part%d,MBRType=%02x,SigType=%02x)", + Hd->PartitionNumber, + Hd->MBRType, + Hd->SignatureType + ); + break; + } +} + +VOID +DevPathCDROM ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + CDROM_DEVICE_PATH *Cd; + + Cd = DevPath; + CatPrint (Str, L"CDROM(Entry%x)", Cd->BootEntry); +} + +VOID +DevPathFilePath ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + FILEPATH_DEVICE_PATH *Fp; + + Fp = DevPath; + CatPrint (Str, L"%s", Fp->PathName); +} + +VOID +DevPathMediaProtocol ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + MEDIA_PROTOCOL_DEVICE_PATH *MediaProt; + + MediaProt = DevPath; + CatPrint (Str, L"%g", &MediaProt->Protocol); +} + +VOID +DevPathFvFilePath ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFilePath; + + FvFilePath = DevPath; + CatPrint (Str, L"%g", &FvFilePath->NameGuid); +} + +VOID +DevPathBssBss ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + BBS_BBS_DEVICE_PATH *Bbs; + CHAR16 *Type; + + Bbs = DevPath; + switch (Bbs->DeviceType) { + case BBS_TYPE_FLOPPY: + Type = L"Floppy"; + break; + + case BBS_TYPE_HARDDRIVE: + Type = L"Harddrive"; + break; + + case BBS_TYPE_CDROM: + Type = L"CDROM"; + break; + + case BBS_TYPE_PCMCIA: + Type = L"PCMCIA"; + break; + + case BBS_TYPE_USB: + Type = L"Usb"; + break; + + case BBS_TYPE_EMBEDDED_NETWORK: + Type = L"Net"; + break; + + default: + Type = L"?"; + break; + } + // + // Since current Print function hasn't implemented %a (for ansi string) + // we will only print Unicode strings. + // + CatPrint (Str, L"Legacy-%s", Type); +} + +VOID +DevPathEndInstance ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + CatPrint (Str, L","); +} + +VOID +DevPathNodeUnknown ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + CatPrint (Str, L"?"); +} + +DEVICE_PATH_STRING_TABLE DevPathTable[] = { + HARDWARE_DEVICE_PATH, + HW_PCI_DP, + DevPathPci, + HARDWARE_DEVICE_PATH, + HW_PCCARD_DP, + DevPathPccard, + HARDWARE_DEVICE_PATH, + HW_MEMMAP_DP, + DevPathMemMap, + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + DevPathVendor, + HARDWARE_DEVICE_PATH, + HW_CONTROLLER_DP, + DevPathController, + ACPI_DEVICE_PATH, + ACPI_DP, + DevPathAcpi, + MESSAGING_DEVICE_PATH, + MSG_ATAPI_DP, + DevPathAtapi, + MESSAGING_DEVICE_PATH, + MSG_SCSI_DP, + DevPathScsi, + MESSAGING_DEVICE_PATH, + MSG_FIBRECHANNEL_DP, + DevPathFibre, + MESSAGING_DEVICE_PATH, + MSG_1394_DP, + DevPath1394, + MESSAGING_DEVICE_PATH, + MSG_USB_DP, + DevPathUsb, + MESSAGING_DEVICE_PATH, + MSG_USB_CLASS_DP, + DevPathUsbClass, + MESSAGING_DEVICE_PATH, + MSG_I2O_DP, + DevPathI2O, + MESSAGING_DEVICE_PATH, + MSG_MAC_ADDR_DP, + DevPathMacAddr, + MESSAGING_DEVICE_PATH, + MSG_IPv4_DP, + DevPathIPv4, + MESSAGING_DEVICE_PATH, + MSG_IPv6_DP, + DevPathIPv6, + MESSAGING_DEVICE_PATH, + MSG_INFINIBAND_DP, + DevPathInfiniBand, + MESSAGING_DEVICE_PATH, + MSG_UART_DP, + DevPathUart, + MESSAGING_DEVICE_PATH, + MSG_VENDOR_DP, + DevPathVendor, + MEDIA_DEVICE_PATH, + MEDIA_HARDDRIVE_DP, + DevPathHardDrive, + MEDIA_DEVICE_PATH, + MEDIA_CDROM_DP, + DevPathCDROM, + MEDIA_DEVICE_PATH, + MEDIA_VENDOR_DP, + DevPathVendor, + MEDIA_DEVICE_PATH, + MEDIA_FILEPATH_DP, + DevPathFilePath, + MEDIA_DEVICE_PATH, + MEDIA_PROTOCOL_DP, + DevPathMediaProtocol, + +#if (EFI_SPECIFICATION_VERSION < 0x00020000) + MEDIA_DEVICE_PATH, + MEDIA_FV_FILEPATH_DP, + DevPathFvFilePath, +#endif + + BBS_DEVICE_PATH, + BBS_BBS_DP, + DevPathBssBss, + END_DEVICE_PATH_TYPE, + END_INSTANCE_DEVICE_PATH_SUBTYPE, + DevPathEndInstance, + 0, + 0, + NULL +}; + +CHAR16 * +DevicePathToStr ( + IN EFI_DEVICE_PATH_PROTOCOL *DevPath + ) +/*++ + + Turns the Device Path into a printable string. Allcoates + the string from pool. The caller must SafeFreePool the returned + string. + +--*/ +{ + POOL_PRINT Str; + EFI_DEVICE_PATH_PROTOCOL *DevPathNode; + VOID (*DumpNode) (POOL_PRINT *, VOID *); + + UINTN Index; + UINTN NewSize; + + ZeroMem (&Str, sizeof (Str)); + + if (DevPath == NULL) { + goto Done; + } + // + // Unpacked the device path + // + DevPath = BdsLibUnpackDevicePath (DevPath); + ASSERT (DevPath); + + // + // Process each device path node + // + DevPathNode = DevPath; + while (!IsDevicePathEnd (DevPathNode)) { + // + // Find the handler to dump this device path node + // + DumpNode = NULL; + for (Index = 0; DevPathTable[Index].Function; Index += 1) { + + if (DevicePathType (DevPathNode) == DevPathTable[Index].Type && + DevicePathSubType (DevPathNode) == DevPathTable[Index].SubType + ) { + DumpNode = DevPathTable[Index].Function; + break; + } + } + // + // If not found, use a generic function + // + if (!DumpNode) { + DumpNode = DevPathNodeUnknown; + } + // + // Put a path seperator in if needed + // + if (Str.len && DumpNode != DevPathEndInstance) { + CatPrint (&Str, L"/"); + } + // + // Print this node of the device path + // + DumpNode (&Str, DevPathNode); + + // + // Next device path node + // + DevPathNode = NextDevicePathNode (DevPathNode); + } + // + // Shrink pool used for string allocation + // + gBS->FreePool (DevPath); + +Done: + NewSize = (Str.len + 1) * sizeof (CHAR16); + Str.str = ReallocatePool (Str.str, NewSize, NewSize); + ASSERT (Str.str != NULL); + Str.str[Str.len] = 0; + return Str.str; +} + +EFI_DEVICE_PATH_PROTOCOL * +LibDuplicateDevicePathInstance ( + IN EFI_DEVICE_PATH_PROTOCOL *DevPath + ) +/*++ + +Routine Description: + + Function creates a device path data structure that identically matches the + device path passed in. + +Arguments: + + DevPath - A pointer to a device path data structure. + +Returns: + + The new copy of DevPath is created to identically match the input. + Otherwise, NULL is returned. + +--*/ +{ + EFI_DEVICE_PATH_PROTOCOL *NewDevPath; + EFI_DEVICE_PATH_PROTOCOL *DevicePathInst; + EFI_DEVICE_PATH_PROTOCOL *Temp; + UINTN Size; + + // + // get the size of an instance from the input + // + Temp = DevPath; + DevicePathInst = GetNextDevicePathInstance (&Temp, &Size); + + // + // Make a copy + // + NewDevPath = NULL; + if (Size) { + NewDevPath = AllocateZeroPool (Size); + ASSERT (NewDevPath != NULL); + } + + if (NewDevPath) { + CopyMem (NewDevPath, DevicePathInst, Size); + } + + return NewDevPath; +} diff --git a/EdkNt32Pkg/Library/EdkGenericBdsLib/EdkGenericBdsLib.mbd b/EdkNt32Pkg/Library/EdkGenericBdsLib/EdkGenericBdsLib.mbd new file mode 100644 index 0000000000..ca083fe61d --- /dev/null +++ b/EdkNt32Pkg/Library/EdkGenericBdsLib/EdkGenericBdsLib.mbd @@ -0,0 +1,30 @@ + + + + + EdkGenericBdsLib + 1ec995b2-d15b-44f6-abd2-050ea7dd37d2 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-13 17:00 + 2006-03-23 12:01 + + diff --git a/EdkNt32Pkg/Library/EdkGenericBdsLib/EdkGenericBdsLib.msa b/EdkNt32Pkg/Library/EdkGenericBdsLib/EdkGenericBdsLib.msa new file mode 100644 index 0000000000..e09537b723 --- /dev/null +++ b/EdkNt32Pkg/Library/EdkGenericBdsLib/EdkGenericBdsLib.msa @@ -0,0 +1,78 @@ + + + + + EdkGenericBdsLib + DXE_DRIVER + LIBRARY + 1ec995b2-d15b-44f6-abd2-050ea7dd37d2 + 0 + Component description file for the entry point to a EFIDXE Drivers + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-13 17:00 + 2006-03-23 12:01 + + + EdkGenericBdsLib + BaseLib + UefiLib + DxeServicesTableLib + DebugLib + PrintLib + HobLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + DevicePathLib + PerformanceLib + + + BdsBoot.c + BdsConsole.c + BdsConnect.c + DevicePath.c + Performance.c + BdsMisc.c + + Ipf\ShadowRom.c + + + + MdePkg + EdkModulePkg + EdkNt32Pkg + + + LoadedImage + FirmwareVolume + AcpiS3Save + SimpleTextOut + SimpleTextIn + SimpleNetwork + + + + ShellFile + + + diff --git a/EdkNt32Pkg/Library/EdkGenericBdsLib/Ipf/ShadowRom.c b/EdkNt32Pkg/Library/EdkGenericBdsLib/Ipf/ShadowRom.c new file mode 100644 index 0000000000..44a643d9b8 --- /dev/null +++ b/EdkNt32Pkg/Library/EdkGenericBdsLib/Ipf/ShadowRom.c @@ -0,0 +1,53 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ShadowRom.c + +Abstract: + + Shadow all option rom + +Revision History + +--*/ + +#include "Tiano.h" +#include "EfiDriverLib.h" + +#include EFI_PROTOCOL_DEFINITION (LegacyBios) + +UINT8 mShadowRomFlag = 0; + +VOID +ShadowAllOptionRom() +{ + EFI_STATUS Status; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + // + // Rom shadow only do once. + // + if (mShadowRomFlag == 0) { + Status = gBS->LocateProtocol ( + &gEfiLegacyBiosProtocolGuid, + NULL, + &LegacyBios + ); + if (!EFI_ERROR (Status)) { + LegacyBios->PrepareToBootEfi (LegacyBios, NULL, NULL); + } + + mShadowRomFlag = 1; + } + + return ; +} diff --git a/EdkNt32Pkg/Library/EdkGenericBdsLib/Performance.c b/EdkNt32Pkg/Library/EdkGenericBdsLib/Performance.c new file mode 100644 index 0000000000..320d6b7c44 --- /dev/null +++ b/EdkNt32Pkg/Library/EdkGenericBdsLib/Performance.c @@ -0,0 +1,426 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Performance.c + +Abstract: + + This file include the file which can help to get the system + performance, all the function will only include if the performance + switch is set. + +--*/ + +#include "Performance.h" + +VOID +ClearDebugRegisters ( + VOID + ) +{ + AsmWriteDr0 (0); + AsmWriteDr1 (0); +} + +STATIC +VOID +GetShortPdbFileName ( + CHAR8 *PdbFileName, + CHAR8 *GaugeString + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + UINTN Index; + UINTN Index1; + UINTN StartIndex; + UINTN EndIndex; + + if (PdbFileName == NULL) { + AsciiStrCpy (GaugeString, " "); + } else { + StartIndex = 0; + for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++) + ; + + for (Index = 0; PdbFileName[Index] != 0; Index++) { + if (PdbFileName[Index] == '\\') { + StartIndex = Index + 1; + } + + if (PdbFileName[Index] == '.') { + EndIndex = Index; + } + } + + Index1 = 0; + for (Index = StartIndex; Index < EndIndex; Index++) { + GaugeString[Index1] = PdbFileName[Index]; + Index1++; + if (Index1 == PERF_TOKEN_LENGTH - 1) { + break; + } + } + + GaugeString[Index1] = 0; + } + + return ; +} + +STATIC +CHAR8 * +GetPdbPath ( + VOID *ImageBase + ) +/*++ + +Routine Description: + + Located PDB path name in PE image + +Arguments: + + ImageBase - base of PE to search + +Returns: + + Pointer into image at offset of PDB file name if PDB file name is found, + Otherwise a pointer to an empty string. + +--*/ +{ + CHAR8 *PdbPath; + UINT32 DirCount; + EFI_IMAGE_DOS_HEADER *DosHdr; + EFI_IMAGE_NT_HEADERS *NtHdr; + EFI_IMAGE_OPTIONAL_HEADER *OptionalHdr; + EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry; + EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry; + VOID *CodeViewEntryPointer; + + CodeViewEntryPointer = NULL; + PdbPath = NULL; + DosHdr = ImageBase; + + if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { + NtHdr = (EFI_IMAGE_NT_HEADERS *) ((UINT8 *) DosHdr + DosHdr->e_lfanew); + OptionalHdr = (VOID *) &NtHdr->OptionalHeader; + DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionalHdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]); + if (DirectoryEntry->VirtualAddress != 0) { + 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) { + 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; + } + } + } + } + } + + return PdbPath; +} + +STATIC +VOID +GetNameFromHandle ( + IN EFI_HANDLE Handle, + OUT CHAR8 *GaugeString + ) +{ + EFI_STATUS Status; + EFI_LOADED_IMAGE_PROTOCOL *Image; + CHAR8 *PdbFileName; + EFI_DRIVER_BINDING_PROTOCOL *DriverBinding; + + AsciiStrCpy (GaugeString, " "); + + // + // Get handle name from image protocol + // + Status = gBS->HandleProtocol ( + Handle, + &gEfiLoadedImageProtocolGuid, + &Image + ); + + if (EFI_ERROR (Status)) { + Status = gBS->OpenProtocol ( + Handle, + &gEfiDriverBindingProtocolGuid, + (VOID **) &DriverBinding, + NULL, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return ; + } + // + // Get handle name from image protocol + // + Status = gBS->HandleProtocol ( + DriverBinding->ImageHandle, + &gEfiLoadedImageProtocolGuid, + &Image + ); + } + + PdbFileName = GetPdbPath (Image->ImageBase); + + if (PdbFileName != NULL) { + GetShortPdbFileName (PdbFileName, GaugeString); + } + + return ; +} + + + +VOID +WriteBootToOsPerformanceData ( + VOID + ) +/*++ + +Routine Description: + + Allocates a block of memory and writes performance data of booting to OS into it. + +Arguments: + + None + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + EFI_CPU_ARCH_PROTOCOL *Cpu; + EFI_PHYSICAL_ADDRESS mAcpiLowMemoryBase; + UINT32 mAcpiLowMemoryLength; + UINT32 LimitCount; + PERF_HEADER mPerfHeader; + PERF_DATA mPerfData; + EFI_HANDLE *Handles; + UINTN NoHandles; + CHAR8 GaugeString[PERF_TOKEN_LENGTH]; + UINT8 *Ptr; + UINT32 mIndex; + UINT64 Ticker; + UINT64 Freq; + UINT32 Duration; + UINT64 CurrentTicker; + UINT64 TimerPeriod; + UINTN LogEntryKey; + CONST VOID *Handle; + CONST CHAR8 *Token; + CONST CHAR8 *Module; + UINT64 StartTicker; + UINT64 EndTicker; + + // + // Retrive time stamp count as early as possilbe + // + Ticker = AsmReadTsc (); + + // + // Allocate a block of memory that contain performance data to OS + // + Status = gBS->AllocatePages ( + AllocateAnyPages, + EfiACPIReclaimMemory, + 4, + &mAcpiLowMemoryBase + ); + if (EFI_ERROR (Status)) { + return ; + } + + mAcpiLowMemoryLength = 0x1000; + + Ptr = (UINT8 *) ((UINT32) mAcpiLowMemoryBase + sizeof (PERF_HEADER)); + LimitCount = (mAcpiLowMemoryLength - sizeof (PERF_HEADER)) / sizeof (PERF_DATA); + + // + // Initialize performance data structure + // + ZeroMem (&mPerfHeader, sizeof (PERF_HEADER)); + + // + // Get CPU frequency + // + Status = gBS->LocateProtocol ( + &gEfiCpuArchProtocolGuid, + NULL, + &Cpu + ); + if (EFI_ERROR (Status)) { + gBS->FreePages (mAcpiLowMemoryBase, 1); + return ; + } + // + // Get Cpu Frequency + // + Status = Cpu->GetTimerValue (Cpu, 0, &(CurrentTicker), &TimerPeriod); + if (EFI_ERROR (Status)) { + gBS->FreePages (mAcpiLowMemoryBase, 1); + return ; + } + + Freq = DivU64x32 (1000000000000, (UINTN) TimerPeriod); + + mPerfHeader.CpuFreq = Freq; + + // + // Record BDS raw performance data + // + mPerfHeader.BDSRaw = Ticker; + + // + // Put Detailed performance data into memory + // + Handles = NULL; + Status = gBS->LocateHandleBuffer ( + AllHandles, + NULL, + NULL, + &NoHandles, + &Handles + ); + if (EFI_ERROR (Status)) { + gBS->FreePages (mAcpiLowMemoryBase, 1); + return ; + } + // + // Get DXE drivers performance + // + for (mIndex = 0; mIndex < NoHandles; mIndex++) { + Ticker = 0; + LogEntryKey = 0; + while ((LogEntryKey = GetPerformanceMeasurement ( + LogEntryKey, + &Handle, + &Token, + &Module, + &StartTicker, + &EndTicker)) != 0) { + if ((Handle == Handles[mIndex]) && (StartTicker < EndTicker)) { + Ticker += (EndTicker - StartTicker); + } + } + + Duration = (UINT32) DivU64x32 ( + Ticker, + (UINT32) Freq + ); + + if (Duration > 0) { + ZeroMem (&mPerfData, sizeof (PERF_DATA)); + + GetNameFromHandle (Handles[mIndex], GaugeString); + + AsciiStrCpy (mPerfData.Token, GaugeString); + mPerfData.Duration = Duration; + + CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA)); + Ptr += sizeof (PERF_DATA); + + mPerfHeader.Count++; + if (mPerfHeader.Count == LimitCount) { + goto Done; + } + } + } + + gBS->FreePool (Handles); + + // + // Get inserted performance data + // + LogEntryKey = 0; + while ((LogEntryKey = GetPerformanceMeasurement ( + LogEntryKey, + &Handle, + &Token, + &Module, + &StartTicker, + &EndTicker)) != 0) { + if ((Handle == NULL) && (StartTicker <= EndTicker)) { + + ZeroMem (&mPerfData, sizeof (PERF_DATA)); + + AsciiStrnCpy (mPerfData.Token, Token, DXE_PERFORMANCE_STRING_SIZE); + mPerfData.Duration = (UINT32) DivU64x32 ( + EndTicker - StartTicker, + (UINT32) Freq + ); + + CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA)); + Ptr += sizeof (PERF_DATA); + + mPerfHeader.Count++; + if (mPerfHeader.Count == LimitCount) { + goto Done; + } + } + } + +Done: + + ClearDebugRegisters (); + + mPerfHeader.Signiture = 0x66726550; + + // + // Put performance data to memory + // + CopyMem ( + (UINT32 *) (UINT32) mAcpiLowMemoryBase, + &mPerfHeader, + sizeof (PERF_HEADER) + ); + + gRT->SetVariable ( + L"PerfDataMemAddr", + &gEfiGlobalVariableGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof (UINT32), + (VOID *) &mAcpiLowMemoryBase + ); + + return ; +} diff --git a/EdkNt32Pkg/Library/EdkGenericBdsLib/Performance.h b/EdkNt32Pkg/Library/EdkGenericBdsLib/Performance.h new file mode 100644 index 0000000000..e7f80ab2c0 --- /dev/null +++ b/EdkNt32Pkg/Library/EdkGenericBdsLib/Performance.h @@ -0,0 +1,55 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Performance.h + +Abstract: + + This file included the performance relete function header and + definition. + +--*/ + +#ifndef _PERF_H_ +#define _PERF_H_ + +#define PERF_TOKEN_LENGTH 28 +#define PERF_PEI_ENTRY_MAX_NUM 50 + +typedef struct { + CHAR8 Token[PERF_TOKEN_LENGTH]; + UINT32 Duration; +} PERF_DATA; + +typedef struct { + UINT64 BootToOs; + UINT64 S3Resume; + UINT32 S3EntryNum; + PERF_DATA S3Entry[PERF_PEI_ENTRY_MAX_NUM]; + UINT64 CpuFreq; + UINT64 BDSRaw; + UINT32 Count; + UINT32 Signiture; +} PERF_HEADER; + +VOID +WriteBootToOsPerformanceData ( + VOID + ); + +VOID +ClearDebugRegisters ( + VOID + ); + +#endif diff --git a/EdkNt32Pkg/Library/EdkGenericBdsLib/build.xml b/EdkNt32Pkg/Library/EdkGenericBdsLib/build.xml new file mode 100644 index 0000000000..ad30c96192 --- /dev/null +++ b/EdkNt32Pkg/Library/EdkGenericBdsLib/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkNt32Pkg/Library/EdkNt32PeiPeCoffGetEntryPointLib/EdkNt32PeiPeCoffGetEntryPointLib.mbd b/EdkNt32Pkg/Library/EdkNt32PeiPeCoffGetEntryPointLib/EdkNt32PeiPeCoffGetEntryPointLib.mbd new file mode 100644 index 0000000000..8e23782db8 --- /dev/null +++ b/EdkNt32Pkg/Library/EdkNt32PeiPeCoffGetEntryPointLib/EdkNt32PeiPeCoffGetEntryPointLib.mbd @@ -0,0 +1,30 @@ + + + + + EdkNt32PeiPeCoffGetEntryPointLib + 434b164e-5fa6-4a3d-bc04-02da2a4eeb26 + 0 + FIX ME! + Copyright (c) 2004 - 2005, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-14 17:04 + 2006-03-19 15:17 + + diff --git a/EdkNt32Pkg/Library/EdkNt32PeiPeCoffGetEntryPointLib/EdkNt32PeiPeCoffGetEntryPointLib.msa b/EdkNt32Pkg/Library/EdkNt32PeiPeCoffGetEntryPointLib/EdkNt32PeiPeCoffGetEntryPointLib.msa new file mode 100644 index 0000000000..bbed045ba4 --- /dev/null +++ b/EdkNt32Pkg/Library/EdkNt32PeiPeCoffGetEntryPointLib/EdkNt32PeiPeCoffGetEntryPointLib.msa @@ -0,0 +1,48 @@ + + + + + EdkNt32PeiPeCoffGetEntryPointLib + PEIM + LIBRARY + 434b164e-5fa6-4a3d-bc04-02da2a4eeb26 + 0 + Component description file for the PEI library. + FIX ME! + Copyright (c) 2004 - 2005, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-14 17:04 + 2006-03-19 15:17 + + + PeCoffGetEntryPointLib + PeiCoreLib + + + PeCoffGetEntryPoint.c + + + MdePkg + EdkNt32Pkg + + + NtPeiLoadFile + + diff --git a/EdkNt32Pkg/Library/EdkNt32PeiPeCoffGetEntryPointLib/PeCoffGetEntryPoint.c b/EdkNt32Pkg/Library/EdkNt32PeiPeCoffGetEntryPointLib/PeCoffGetEntryPoint.c new file mode 100644 index 0000000000..ed64158df7 --- /dev/null +++ b/EdkNt32Pkg/Library/EdkNt32PeiPeCoffGetEntryPointLib/PeCoffGetEntryPoint.c @@ -0,0 +1,75 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PeCoffGetEntryPoint.c + +Abstract: + + Tiano PE/COFF loader + +Revision History + +--*/ + + +RETURN_STATUS +EFIAPI +PeCoffLoaderGetEntryPoint ( + IN VOID *Pe32Data, + IN OUT VOID **EntryPoint + ) +/*++ + +Routine Description: + + Loads a PE/COFF image into memory + +Arguments: + + Pe32Data - Pointer to a PE/COFF Image + + EntryPoint - Pointer to the entry point of the PE/COFF image + +Returns: + + EFI_SUCCESS if the EntryPoint was returned + EFI_INVALID_PARAMETER if the EntryPoint could not be found from Pe32Data + +--*/ +{ + EFI_STATUS Status; + EFI_PEI_PPI_DESCRIPTOR *PpiDescriptor; + NT_PEI_LOAD_FILE_PPI *PeiNtService; + EFI_PHYSICAL_ADDRESS ImageAddress; + UINT64 ImageSize; + EFI_PHYSICAL_ADDRESS ImageEntryPoint; + + Status = PeiCoreLocatePpi ( + &gNtPeiLoadFilePpiGuid, + 0, + &PpiDescriptor, + &PeiNtService + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = PeiNtService->PeiLoadFileService ( + Pe32Data, + &ImageAddress, + &ImageSize, + &ImageEntryPoint + ); + *EntryPoint = (VOID*)(UINTN)ImageEntryPoint; + return Status; +} \ No newline at end of file diff --git a/EdkNt32Pkg/Library/EdkNt32PeiPeCoffGetEntryPointLib/build.xml b/EdkNt32Pkg/Library/EdkNt32PeiPeCoffGetEntryPointLib/build.xml new file mode 100644 index 0000000000..c558a9b47f --- /dev/null +++ b/EdkNt32Pkg/Library/EdkNt32PeiPeCoffGetEntryPointLib/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkNt32Pkg/Library/Nt32PeCoffLoaderLib/Nt32PeCoffLoader.c b/EdkNt32Pkg/Library/Nt32PeCoffLoaderLib/Nt32PeCoffLoader.c new file mode 100644 index 0000000000..d06e57a6d7 --- /dev/null +++ b/EdkNt32Pkg/Library/Nt32PeCoffLoaderLib/Nt32PeCoffLoader.c @@ -0,0 +1,51 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + TianoPeCoffLoader.c + +Abstract: + + Wrap the Base PE/COFF loader with the PE COFF Protocol + + +--*/ + + + +EFI_PEI_PE_COFF_LOADER_PROTOCOL *mPeiEfiPeiPeCoffLoader; + +EFI_STATUS +PeCoffLoaderConstructor ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + + Status = (*PeiServices)->LocatePpi ( + PeiServices, + &gEfiPeiPeCoffLoaderGuid, + 0, + NULL, + &mPeiEfiPeiPeCoffLoader + ); + return Status; +} + +EFI_PEI_PE_COFF_LOADER_PROTOCOL * +EFIAPI +GetPeCoffLoaderProtocol ( + ) +{ + return mPeiEfiPeiPeCoffLoader; +} diff --git a/EdkNt32Pkg/Library/Nt32PeCoffLoaderLib/Nt32PeCoffLoaderLib.mbd b/EdkNt32Pkg/Library/Nt32PeCoffLoaderLib/Nt32PeCoffLoaderLib.mbd new file mode 100644 index 0000000000..233d7d3c59 --- /dev/null +++ b/EdkNt32Pkg/Library/Nt32PeCoffLoaderLib/Nt32PeCoffLoaderLib.mbd @@ -0,0 +1,30 @@ + + + + + Nt32PeCoffLoaderLib + 3c5702f2-9b17-4273-b60c-b96e6cd13066 + EDK_RELEASE_VERSION 0x00020000 + FIX ME! + Copyright (c) 2004 - 2005, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-14 17:04 + 2006-03-31 13:20 + + diff --git a/EdkNt32Pkg/Library/Nt32PeCoffLoaderLib/Nt32PeCoffLoaderLib.msa b/EdkNt32Pkg/Library/Nt32PeCoffLoaderLib/Nt32PeCoffLoaderLib.msa new file mode 100644 index 0000000000..68a5ca2a6b --- /dev/null +++ b/EdkNt32Pkg/Library/Nt32PeCoffLoaderLib/Nt32PeCoffLoaderLib.msa @@ -0,0 +1,53 @@ + + + + + Nt32PeCoffLoaderLib + PEIM + LIBRARY + 3c5702f2-9b17-4273-b60c-b96e6cd13066 + EDK_RELEASE_VERSION 0x00020000 + Component description file for the PEI library. + FIX ME! + Copyright (c) 2004 - 2005, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + EFI_SPECIFICATION_VERSION 0x00000000 + 2006-03-14 17:04 + 2006-03-31 13:20 + + + EdkPeCoffLoaderLib + + + Nt32PeCoffLoader.c + + + MdePkg + EdkModulePkg + EdkNt32Pkg + + + PeCoffLoader + + + + PeCoffLoaderConstructor + + + diff --git a/EdkNt32Pkg/Library/Nt32PeCoffLoaderLib/build.xml b/EdkNt32Pkg/Library/Nt32PeCoffLoaderLib/build.xml new file mode 100644 index 0000000000..1ca1244559 --- /dev/null +++ b/EdkNt32Pkg/Library/Nt32PeCoffLoaderLib/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkNt32Pkg/Logo/Logo.mbd b/EdkNt32Pkg/Logo/Logo.mbd new file mode 100644 index 0000000000..346ff12fb8 --- /dev/null +++ b/EdkNt32Pkg/Logo/Logo.mbd @@ -0,0 +1,30 @@ + + + + + Logo + 7BB28B99-61BB-11D5-9A5D-0090273FC14D + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-14 17:04 + 2006-03-19 15:17 + + diff --git a/EdkNt32Pkg/Logo/Logo.msa b/EdkNt32Pkg/Logo/Logo.msa new file mode 100644 index 0000000000..958dbbc36e --- /dev/null +++ b/EdkNt32Pkg/Logo/Logo.msa @@ -0,0 +1,48 @@ + + + + + Logo + BASE + LOGO + 7BB28B99-61BB-11D5-9A5D-0090273FC14D + 0 + Component description file for creating a Logo file. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-14 17:04 + 2006-03-19 15:17 + + + Logo.bmp + + + MdePkg + + + + + + + + + + diff --git a/EdkNt32Pkg/Logo/Logo_build.xml b/EdkNt32Pkg/Logo/Logo_build.xml new file mode 100644 index 0000000000..bbc8b000a4 --- /dev/null +++ b/EdkNt32Pkg/Logo/Logo_build.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/EdkNt32Pkg/Logo/build.xml b/EdkNt32Pkg/Logo/build.xml new file mode 100644 index 0000000000..f9828f3cfc --- /dev/null +++ b/EdkNt32Pkg/Logo/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkNt32Pkg/Logo/logo.bmp b/EdkNt32Pkg/Logo/logo.bmp new file mode 100644 index 0000000000000000000000000000000000000000..5acbc17c5c8c6da7502751c99d7c74b28df5794e GIT binary patch literal 33126 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 literal 0 HcmV?d00001 diff --git a/EdkNt32Pkg/Nt32.fpd b/EdkNt32Pkg/Nt32.fpd new file mode 100644 index 0000000000..38b2e48050 --- /dev/null +++ b/EdkNt32Pkg/Nt32.fpd @@ -0,0 +1,683 @@ + + + + + NT32 + EFI/Tiano Emulation Platform + The Emulation Platform can be used to debug individual modules, prior to creating a real platform. This also provides an example for how an FPD is created. + 2006-02-23 18:21 + lhauch + + + FlashMap.fdf + + + + + + + FV_RECOVERY + + NV_STORAGE + + + + FV_RECOVERY + NV_STORAGE + FV_FILE + + + EFI_READ_DISABLED_CAP + EFI_READ_ENABLED_CAP + EFI_READ_STATUS + EFI_WRITE_DISABLED_CAP + EFI_WRITE_ENABLED_CAP + EFI_WRITE_STATUS + EFI_LOCK_CAP + EFI_LOCK_STATUS + EFI_MEMORY_MAPPED + EFI_ALIGNMENT_CAP + EFI_ALIGNMENT_2 + EFI_ALIGNMENT_4 + EFI_ALIGNMENT_8 + EFI_ALIGNMENT_16 + EFI_ALIGNMENT_32 + EFI_ALIGNMENT_64 + EFI_ALIGNMENT_128 + EFI_ALIGNMENT_256 + EFI_ALIGNMENT_512 + EFI_ALIGNMENT_1K + EFI_ALIGNMENT_2K + EFI_ALIGNMENT_4K + EFI_ALIGNMENT_8K + EFI_ALIGNMENT_16K + EFI_ALIGNMENT_32K + EFI_ALIGNMENT_64K + EFI_STICKY_WRITE + + + + + NV_STORAGE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A + + + + + + + + + + + + + + + + + + EdkNt32Pkg + + + + + EdkNt32PeiPeCoffGetEntryPointLib + + + + + + + + + + + + + + + + + + Nt32PeCoffLoaderLib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PcdMaximumUnicodeStringLength + 0x00000001 + UINT32 + false + false + false + false + false + 0x00 + 0x00 + 4 + 0 + L"" + 0 + 0 + 1000000 + + + PcdMaximumAsciiStringLength + 0x00000002 + UINT32 + false + false + false + false + false + 0x00 + 0x00 + 4 + 0 + L"" + 0 + 0 + 1000000 + + + PcdMaximumLinkedListLength + 0x00000003 + UINT32 + false + false + false + false + false + 0x00 + 0x00 + 4 + 0 + L"" + 0 + 0 + 1000000 + + + PcdSpinLockTimeout + 0x00000004 + UINT32 + false + false + false + false + false + 0x00 + 0x00 + 4 + 0 + L"" + 0 + 0 + 10000000 + + + PcdDebugPropertyMask + 0x00000005 + UINT8 + false + false + false + false + false + 0x00 + 0x00 + 4 + 0 + L"" + 0 + 0 + 0x0f + + + PcdDebugPrintErrorLevel + 0x00000006 + UINT32 + false + false + false + false + false + 0x00 + 0x00 + 4 + 0 + L"" + 0 + 0 + 0x80000000 + + + PcdReportStatusCodePropertyMask + 0x00000007 + UINT8 + false + false + false + false + false + 0x00 + 0x00 + 1 + 0 + L"" + 0 + 0 + 0x07 + + + PcdDebugClearMemoryValue + 0x00000008 + UINT8 + false + false + false + false + false + 0 + 0 + 1 + 0 + L"" + 0 + 0 + 0xAF + + + PcdPerformanceLibraryPropertyMask + 0x00000009 + UINT8 + false + false + false + false + false + 0x00 + 0x00 + 1 + 0 + L"" + 0 + 0 + 0 + + + PcdWinNtPhysicalDisk + 0x00001000 + VOID* + false + false + false + false + false + 0x00 + 0x00 + 24 + 0 + L"" + 0 + 0 + L"FW;40960;512" + + + PcdWinNtVirtualDisk + 0x00001001 + VOID* + false + false + false + false + false + 0x00 + 0x00 + 24 + 0 + L"" + 0 + 0 + L"FW;40960;512" + + + PcdWinNtSerialPort + 0x00001002 + VOID* + false + false + false + false + false + 0x00 + 0x00 + 20 + 0 + L"" + 0 + 0 + L"COM1!COM2" + + + PcdWinNtUga + 0x00001003 + VOID* + false + false + false + false + false + 0x00 + 0x00 + 50 + 0 + L"" + 0 + 0 + L"UGA Window 1!UGA Window 2" + + + PcdWinNtFileSystem + 0x00001004 + VOID* + false + false + false + false + false + 0x00 + 0x00 + 120 + 0 + L"" + 0 + 0 + L".!C:\\D\\work\\Remodel\\mdk\\EdkShellBinPkg\\bin\\ia32\\Apps" + + + PcdWinNtMemorySize + 0x00001005 + VOID* + false + false + false + false + false + 0x00 + 0x00 + 10 + 0 + L"" + 0 + 0 + L"64!64" + + + PcdWinNtBootMode + 0x00001006 + UINT32 + false + false + false + false + false + 0x00 + 0x00 + 4 + 0 + L"" + 0 + 0 + 1 + + + PcdWinNtCpuModel + 0x00001007 + VOID* + false + false + false + false + false + 0x00 + 0x00 + 48 + 0 + L"" + 0 + 0 + L"Intel(R) Processor Model" + + + PcdWinNtCpuSpeed + 0x00001008 + VOID* + false + false + false + false + false + 0x00 + 0x00 + 8 + 0 + L"" + 0 + 0 + L"3000" + + + PcdWinNtFirmwareVolume + 0x00001009 + VOID* + false + false + false + false + false + 0x00 + 0x00 + 44 + 0 + L"" + 0 + 0 + L"..\\..\\Fv\\Fv_Recovery.fd" + + + PcdWinNtConsole + 0x0000100a + VOID* + false + false + false + false + false + 0x00 + 0x00 + 50 + 0 + L"" + 0 + 0 + L"Bus Driver Console Window" + + + PcdRothmanTest + 0x0000100b + UINT32 + true + false + false + false + false + 0x00 + 0x00 + 4 + 0B3ADA4F-AE56-4c24-8DEA-F03B7558AE50 + L"RothmanVariable" + 0 + 0 + 0 + + + PcdWinNtBinaryPatch1 + 0x0001000b + UINT32 + false + false + false + false + false + 0x00 + 0x00 + 4 + 0 + L"" + 0 + 0 + 0x1234 + + + PcdWinNtBinaryPatch2 + 0x0001000c + UINT32 + false + false + false + false + false + 0x00 + 0x00 + 4 + 0 + L"" + 0 + 0 + 0x5678 + + + PcdWinNtFeatureFlag1 + 0x0001000d + BOOLEAN + false + false + false + false + false + 0x00 + 0x00 + 1 + 0 + L"" + 0 + 0 + 0x1 + + + PcdWinNtDynamicUINT32 + 0x0001000e + UINT32 + false + false + false + false + false + 0x00 + 0x00 + 4 + 0 + L"" + 0 + 0 + 0x0 + + + + + + + + + + diff --git a/EdkNt32Pkg/Pei/Autoscan/WinNtAutoScan.mbd b/EdkNt32Pkg/Pei/Autoscan/WinNtAutoScan.mbd new file mode 100644 index 0000000000..c6a123ddf9 --- /dev/null +++ b/EdkNt32Pkg/Pei/Autoscan/WinNtAutoScan.mbd @@ -0,0 +1,43 @@ + + + + + WinNtAutoScan + BE0FEABA-3443-4919-9F3A-2D4216329EA9 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-14 17:04 + 2006-03-19 15:17 + + + PeimEntryPoint + PeiMemoryLib + PeiCoreLib + PeiServicesTablePointerLib + PeiHobLib + PeiReportStatusCodeLib + BaseDebugLibReportStatusCode + BaseLib + + + _ModuleEntryPoint + + diff --git a/EdkNt32Pkg/Pei/Autoscan/WinNtAutoScan.msa b/EdkNt32Pkg/Pei/Autoscan/WinNtAutoScan.msa new file mode 100644 index 0000000000..5141634516 --- /dev/null +++ b/EdkNt32Pkg/Pei/Autoscan/WinNtAutoScan.msa @@ -0,0 +1,68 @@ + + + + + WinNtAutoScan + PEIM + PE32_PEIM + BE0FEABA-3443-4919-9F3A-2D4216329EA9 + 0 + Component description file for WinNtAutoScan module + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-14 17:04 + 2006-03-19 15:17 + + + DebugLib + PeimEntryPoint + BaseLib + BaseMemoryLib + HobLib + PeiCoreLib + PeiServicesTablePointerLib + + + WinNtAutoScan.c + WinNtAutoscan.dxs + + + MdePkg + EdkModulePkg + EdkNt32Pkg + + + + EFI_RESOURCE_SYSTEM_MEMORY + + + + + NtAutoScan + BaseMemoryTest + MemoryDiscovered + + + + PeimInitializeWinNtAutoScan + + + diff --git a/EdkNt32Pkg/Pei/Autoscan/WinNtAutoscan.dxs b/EdkNt32Pkg/Pei/Autoscan/WinNtAutoscan.dxs new file mode 100644 index 0000000000..5b3af0e337 --- /dev/null +++ b/EdkNt32Pkg/Pei/Autoscan/WinNtAutoscan.dxs @@ -0,0 +1,29 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + WinNtAutoscan.dxs + +Abstract: + + Dependency expression file for WinNtAutoscan. + +--*/ + +#include +#include + +DEPENDENCY_START + PEI_NT_AUTOSCAN_PPI_GUID AND EFI_PEI_MASTER_BOOT_MODE_PEIM_PPI AND PEI_BASE_MEMORY_TEST_GUID +DEPENDENCY_END + + diff --git a/EdkNt32Pkg/Pei/Autoscan/WinntAutoscan.c b/EdkNt32Pkg/Pei/Autoscan/WinntAutoscan.c new file mode 100644 index 0000000000..c465ce68ca --- /dev/null +++ b/EdkNt32Pkg/Pei/Autoscan/WinntAutoscan.c @@ -0,0 +1,132 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + WinNtAutoscan.c + +Abstract: + Tiano PEIM to abstract memory auto-scan in a Windows NT environment. + +Revision History + +--*/ + +EFI_STATUS +EFIAPI +PeimInitializeWinNtAutoScan ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices + ) +/*++ + +Routine Description: + Perform a call-back into the SEC simulator to get a memory value + +Arguments: + FfsHeader - General purpose data available to every PEIM + PeiServices - General purpose services available to every PEIM. + +Returns: + None + +--*/ +{ + EFI_STATUS Status; + EFI_PEI_PPI_DESCRIPTOR *PpiDescriptor; + PEI_NT_AUTOSCAN_PPI *PeiNtService; + UINT64 MemorySize; + EFI_PHYSICAL_ADDRESS MemoryBase; + PEI_BASE_MEMORY_TEST_PPI *MemoryTestPpi; + EFI_PHYSICAL_ADDRESS ErrorAddress; + UINTN Index; + EFI_RESOURCE_ATTRIBUTE_TYPE Attributes; + + + DEBUG ((EFI_D_ERROR, "NT 32 Autoscan PEIM Loaded\n")); + + // + // Get the PEI NT Autoscan PPI + // + Status = (**PeiServices).LocatePpi ( + PeiServices, + &gPeiNtAutoScanPpiGuid, // GUID + 0, // INSTANCE + &PpiDescriptor, // EFI_PEI_PPI_DESCRIPTOR + &PeiNtService // PPI + ); + ASSERT_EFI_ERROR (Status); + + // + // Get the Memory Test PPI + // + Status = (**PeiServices).LocatePpi ( + PeiServices, + &gPeiBaseMemoryTestPpiGuid, + 0, + NULL, + &MemoryTestPpi + ); + ASSERT_EFI_ERROR (Status); + + Index = 0; + do { + Status = PeiNtService->NtAutoScan (Index, &MemoryBase, &MemorySize); + if (!EFI_ERROR (Status)) { + Attributes = + ( + 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 + ); + + if (Index == 0) { + // + // For the first area register it as PEI tested memory + // + Status = MemoryTestPpi->BaseMemoryTest ( + PeiServices, + MemoryTestPpi, + MemoryBase, + MemorySize, + Quick, + &ErrorAddress + ); + ASSERT_EFI_ERROR (Status); + + // + // Register the "tested" memory with the PEI Core + // + Status = (**PeiServices).InstallPeiMemory (PeiServices, MemoryBase, MemorySize); + ASSERT_EFI_ERROR (Status); + + Attributes |= EFI_RESOURCE_ATTRIBUTE_TESTED; + } + + BuildResourceDescriptorHob ( + EFI_RESOURCE_SYSTEM_MEMORY, + Attributes, + MemoryBase, + MemorySize + ); + } + Index++; + } while (!EFI_ERROR (Status)); + + // + // Build the CPU hob with 36-bit addressing and 16-bits of IO space. + // + BuildCpuHob (36, 16); + + return Status; +} diff --git a/EdkNt32Pkg/Pei/Autoscan/build.xml b/EdkNt32Pkg/Pei/Autoscan/build.xml new file mode 100644 index 0000000000..bdbd4c930e --- /dev/null +++ b/EdkNt32Pkg/Pei/Autoscan/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkNt32Pkg/Pei/BootMode/BootMode.c b/EdkNt32Pkg/Pei/BootMode/BootMode.c new file mode 100644 index 0000000000..955c7595dc --- /dev/null +++ b/EdkNt32Pkg/Pei/BootMode/BootMode.c @@ -0,0 +1,85 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + BootMode.c + +Abstract: + + Tiano PEIM to provide the platform support functionality within Windows + +--*/ + + + +// +// Module globals +// +EFI_PEI_PPI_DESCRIPTOR mPpiListBootMode = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiPeiMasterBootModePpiGuid, + NULL +}; + +EFI_PEI_PPI_DESCRIPTOR mPpiListRecoveryBootMode = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiPeiBootInRecoveryModePpiGuid, + NULL +}; + +EFI_STATUS +EFIAPI +InitializeBootMode ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices + ) +/*++ + +Routine Description: + + Peform the boot mode determination logic + +Arguments: + + PeiServices - General purpose services available to every PEIM. + +Returns: + + Status - EFI_SUCCESS if the boot mode could be set + +--*/ +// TODO: FfsHeader - add argument and description to function comment +{ + EFI_STATUS Status; + UINTN BootMode; + + DEBUG ((EFI_D_ERROR, "NT32 Boot Mode PEIM Loaded\n")); + + // + // Let's assume things are OK if not told otherwise + // Should we read an environment variable in order to easily change this? + // + BootMode = BOOT_WITH_FULL_CONFIGURATION; + + Status = (**PeiServices).SetBootMode (PeiServices, (UINT8) BootMode); + ASSERT_EFI_ERROR (Status); + + Status = (**PeiServices).InstallPpi (PeiServices, &mPpiListBootMode); + ASSERT_EFI_ERROR (Status); + + if (BootMode == BOOT_IN_RECOVERY_MODE) { + Status = (**PeiServices).InstallPpi (PeiServices, &mPpiListRecoveryBootMode); + ASSERT_EFI_ERROR (Status); + } + + return Status; +} diff --git a/EdkNt32Pkg/Pei/BootMode/BootMode.dxs b/EdkNt32Pkg/Pei/BootMode/BootMode.dxs new file mode 100644 index 0000000000..fd91a09892 --- /dev/null +++ b/EdkNt32Pkg/Pei/BootMode/BootMode.dxs @@ -0,0 +1,29 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + BootMode.dxs + +Abstract: + + Dependency expression file for BootMode. + +--*/ + +#include +#include + +DEPENDENCY_START + TRUE +DEPENDENCY_END + + diff --git a/EdkNt32Pkg/Pei/BootMode/BootMode.mbd b/EdkNt32Pkg/Pei/BootMode/BootMode.mbd new file mode 100644 index 0000000000..5dd1a6fe20 --- /dev/null +++ b/EdkNt32Pkg/Pei/BootMode/BootMode.mbd @@ -0,0 +1,42 @@ + + + + + BootMode + B7611005-1F26-45ba-A3DB-01F39DDB2785 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-14 17:04 + 2006-03-19 15:17 + + + PeimEntryPoint + PeiMemoryLib + PeiCoreLib + PeiServicesTablePointerLib + PeiReportStatusCodeLib + BaseDebugLibReportStatusCode + BaseLib + + + _ModuleEntryPoint + + diff --git a/EdkNt32Pkg/Pei/BootMode/BootMode.msa b/EdkNt32Pkg/Pei/BootMode/BootMode.msa new file mode 100644 index 0000000000..accb0b5ba3 --- /dev/null +++ b/EdkNt32Pkg/Pei/BootMode/BootMode.msa @@ -0,0 +1,59 @@ + + + + + BootMode + PEIM + PE32_PEIM + B7611005-1F26-45ba-A3DB-01F39DDB2785 + 0 + Component description file for Fwh module + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-14 17:04 + 2006-03-19 15:17 + + + DebugLib + PeimEntryPoint + BaseLib + PeiCoreLib + PeiServicesTablePointerLib + + + BootMode.c + BootMode.dxs + + + MdePkg + EdkModulePkg + EdkNt32Pkg + + + BootInRecoveryMode + MasterBootMode + + + + InitializeBootMode + + + diff --git a/EdkNt32Pkg/Pei/BootMode/build.xml b/EdkNt32Pkg/Pei/BootMode/build.xml new file mode 100644 index 0000000000..cd67235b3a --- /dev/null +++ b/EdkNt32Pkg/Pei/BootMode/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkNt32Pkg/Pei/FirmwareVolume/WinNtFwh.dxs b/EdkNt32Pkg/Pei/FirmwareVolume/WinNtFwh.dxs new file mode 100644 index 0000000000..6270ef0db7 --- /dev/null +++ b/EdkNt32Pkg/Pei/FirmwareVolume/WinNtFwh.dxs @@ -0,0 +1,29 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + WinNtFwh.dxs + +Abstract: + + Dependency expression file for WinNtFwh PEIM. + +--*/ + +#include +#include + +DEPENDENCY_START + NT_FWH_PPI_GUID AND EFI_PEI_PERMANENT_MEMORY_INSTALLED_PPI_GUID +DEPENDENCY_END + + diff --git a/EdkNt32Pkg/Pei/FirmwareVolume/WinNtFwh.mbd b/EdkNt32Pkg/Pei/FirmwareVolume/WinNtFwh.mbd new file mode 100644 index 0000000000..3c61664ecc --- /dev/null +++ b/EdkNt32Pkg/Pei/FirmwareVolume/WinNtFwh.mbd @@ -0,0 +1,43 @@ + + + + + WinNtFwh + F0384FFD-8633-452f-9010-F6B7D2EAE2F1 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-14 17:04 + 2006-03-23 10:33 + + + PeimEntryPoint + PeiMemoryLib + PeiCoreLib + PeiServicesTablePointerLib + PeiHobLib + PeiReportStatusCodeLib + BaseDebugLibReportStatusCode + BaseLib + + + _ModuleEntryPoint + + diff --git a/EdkNt32Pkg/Pei/FirmwareVolume/WinNtFwh.msa b/EdkNt32Pkg/Pei/FirmwareVolume/WinNtFwh.msa new file mode 100644 index 0000000000..3101d4866e --- /dev/null +++ b/EdkNt32Pkg/Pei/FirmwareVolume/WinNtFwh.msa @@ -0,0 +1,69 @@ + + + + + WinNtFwh + PEIM + PE32_PEIM + F0384FFD-8633-452f-9010-F6B7D2EAE2F1 + 0 + Component description file for WinNtFwh module + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-14 17:04 + 2006-03-23 10:33 + + + DebugLib + PeimEntryPoint + HobLib + PeiCoreLib + PeiServicesTablePointerLib + + + WinNtFwh.c + WinNtFwh.dxs + + + MdePkg + EdkModulePkg + EdkNt32Pkg + + + + FvRecovery.fv + + + EFI_RESOURCE_FIRMWARE_DEVICE + + + NVSTORAGE.fv + + + + NtFwh + + + + PeimInitializeWinNtFwh + + + diff --git a/EdkNt32Pkg/Pei/FirmwareVolume/WinntFwh.c b/EdkNt32Pkg/Pei/FirmwareVolume/WinntFwh.c new file mode 100644 index 0000000000..3764cb78ca --- /dev/null +++ b/EdkNt32Pkg/Pei/FirmwareVolume/WinntFwh.c @@ -0,0 +1,123 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + WinNtFwh.c + +Abstract: + PEIM to abstract construction of firmware volume in a Windows NT environment. + +Revision History + +--*/ + + +#include + + +EFI_STATUS +EFIAPI +PeimInitializeWinNtFwh ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices + ) +/*++ + +Routine Description: + Perform a call-back into the SEC simulator to get address of the Firmware Hub + +Arguments: + FfsHeader - Ffs Header availible to every PEIM + PeiServices - General purpose services available to every PEIM. + +Returns: + None + +--*/ +{ + EFI_STATUS Status; + EFI_PEI_PPI_DESCRIPTOR *PpiDescriptor; + NT_FWH_PPI *FwhPpi; + EFI_PHYSICAL_ADDRESS FdBase; + EFI_FIRMWARE_VOLUME_HEADER *FvHeader; + UINT64 FdSize; + UINTN Index; + + DEBUG ((EFI_D_ERROR, "NT 32 Firmware Volume PEIM Loaded\n")); + + // + // Get the Fwh Information PPI + // + Status = (**PeiServices).LocatePpi ( + PeiServices, + &gNtFwhPpiGuid, // GUID + 0, // INSTANCE + &PpiDescriptor, // EFI_PEI_PPI_DESCRIPTOR + &FwhPpi // PPI + ); + ASSERT_EFI_ERROR (Status); + + Index = 0; + do { + // + // Get information about all the FD's in the system + // + Status = FwhPpi->NtFwh (Index, &FdBase, &FdSize); + if (!EFI_ERROR (Status)) { + // + // Assume the FD starts with an FV header + // + FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) FdBase; + + // + // Make an FV Hob for the first FV in the FD + // + BuildFvHob (FdBase, FvHeader->FvLength); + + if (Index == 0) { + // + // Assume the first FD was produced by the NT32.DSC + // All these strange offests are needed to keep in + // sync with the FlashMap and NT32.dsc file + // + BuildResourceDescriptorHob ( + EFI_RESOURCE_FIRMWARE_DEVICE, + (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE), + FdBase, + (FvHeader->FvLength + EFI_WINNT_RUNTIME_UPDATABLE_LENGTH + EFI_WINNT_FTW_SPARE_BLOCK_LENGTH) + ); + + // + // Hard code the address of the spare block and variable services. + // Assume it's a hard coded offset from FV0 in FD0. + // + FdBase = FdBase + EFI_WINNT_RUNTIME_UPDATABLE_OFFSET; + FdSize = EFI_WINNT_RUNTIME_UPDATABLE_LENGTH + EFI_WINNT_FTW_SPARE_BLOCK_LENGTH; + + BuildFvHob (FdBase, FdSize); + } else { + // + // For other FD's just map them in. + // + BuildResourceDescriptorHob ( + EFI_RESOURCE_FIRMWARE_DEVICE, + (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE), + FdBase, + FdSize + ); + } + } + + Index++; + } while (!EFI_ERROR (Status)); + + return Status; +} diff --git a/EdkNt32Pkg/Pei/FirmwareVolume/build.xml b/EdkNt32Pkg/Pei/FirmwareVolume/build.xml new file mode 100644 index 0000000000..7aa147bb9e --- /dev/null +++ b/EdkNt32Pkg/Pei/FirmwareVolume/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkNt32Pkg/Pei/FlashMap/FlashMap.c b/EdkNt32Pkg/Pei/FlashMap/FlashMap.c new file mode 100644 index 0000000000..a8f7ba06ad --- /dev/null +++ b/EdkNt32Pkg/Pei/FlashMap/FlashMap.c @@ -0,0 +1,273 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FlashMap.c + +Abstract: + + PEIM to build GUIDed HOBs for platform specific flash map + +--*/ + + +#include + +EFI_STATUS +EFIAPI +GetAreaInfo ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_FLASH_MAP_PPI *This, + IN EFI_FLASH_AREA_TYPE AreaType, + IN EFI_GUID *AreaTypeGuid, + OUT UINT32 *NumEntries, + OUT EFI_FLASH_SUBAREA_ENTRY **Entries + ); + +EFI_STATUS +EFIAPI +MemoryDiscoveredPpiNotifyCallback ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ); + +// +// Module globals +// +static PEI_FLASH_MAP_PPI mFlashMapPpi = { GetAreaInfo }; + +static EFI_PEI_PPI_DESCRIPTOR mPpiListFlashMap = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gPeiFlashMapPpiGuid, + &mFlashMapPpi +}; + +static EFI_FLASH_AREA_DATA mFlashAreaData[] = { + // + // Variable area + // + { + EFI_VARIABLE_STORE_OFFSET, + EFI_VARIABLE_STORE_LENGTH, + EFI_FLASH_AREA_SUBFV | EFI_FLASH_AREA_MEMMAPPED_FV, + EFI_FLASH_AREA_EFI_VARIABLES + }, + // + // FTW spare (backup) block + // + { + EFI_WINNT_FTW_SPARE_BLOCK_OFFSET, + EFI_WINNT_FTW_SPARE_BLOCK_LENGTH, + EFI_FLASH_AREA_SUBFV | EFI_FLASH_AREA_MEMMAPPED_FV, + EFI_FLASH_AREA_FTW_BACKUP + }, + // + // FTW private working (state) area + // + { + EFI_FTW_WORKING_OFFSET, + EFI_FTW_WORKING_LENGTH, + EFI_FLASH_AREA_SUBFV | EFI_FLASH_AREA_MEMMAPPED_FV, + EFI_FLASH_AREA_FTW_STATE + }, + // + // Recovery FV + // + { + EFI_WINNT_FIRMWARE_OFFSET, + EFI_WINNT_FIRMWARE_LENGTH, + EFI_FLASH_AREA_FV | EFI_FLASH_AREA_MEMMAPPED_FV, + EFI_FLASH_AREA_RECOVERY_BIOS + }, + // + // System Non-Volatile Storage FV + // + { + EFI_WINNT_RUNTIME_UPDATABLE_OFFSET, + EFI_WINNT_RUNTIME_UPDATABLE_LENGTH + EFI_WINNT_FTW_SPARE_BLOCK_LENGTH, + EFI_FLASH_AREA_FV | EFI_FLASH_AREA_MEMMAPPED_FV, + EFI_FLASH_AREA_GUID_DEFINED + }, +}; + + +EFI_STATUS +EFIAPI +PeimInitializeFlashMap ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices + ) +/*++ + +Routine Description: + Build GUIDed HOBs for platform specific flash map + +Arguments: + FfsHeader - A pointer to the EFI_FFS_FILE_HEADER structure. + PeiServices - General purpose services available to every PEIM. + +Returns: + EFI_STATUS + +--*/ +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + NT_FWH_PPI *NtFwhPpi; + EFI_PEI_PPI_DESCRIPTOR *PpiDescriptor; + EFI_PHYSICAL_ADDRESS FdBase; + UINT64 FdSize; + UINTN NumOfHobData; + UINTN Index; + EFI_FLASH_AREA_HOB_DATA FlashHobData; + + DEBUG ((EFI_D_ERROR, "NT 32 Flash Map PEIM Loaded\n")); + + // + // Install FlashMap PPI + // + Status = PeiCoreInstallPpi (&mPpiListFlashMap); + ASSERT_EFI_ERROR (Status); + + + // + // Get the Fwh Information PPI + // + Status = PeiCoreLocatePpi ( + &gNtFwhPpiGuid, // GUID + 0, // INSTANCE + &PpiDescriptor, // EFI_PEI_PPI_DESCRIPTOR + &NtFwhPpi // PPI + ); + ASSERT_EFI_ERROR (Status); + + // + // Assume that FD0 contains the Flash map. + // + Status = NtFwhPpi->NtFwh (0, &FdBase, &FdSize); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get number of types + // + NumOfHobData = sizeof (mFlashAreaData) / sizeof (EFI_FLASH_AREA_DATA); + + // + // Build flash area entries as GUIDed HOBs. + // + for (Index = 0; Index < NumOfHobData; Index++) { + (*PeiServices)->SetMem (&FlashHobData, sizeof (EFI_FLASH_AREA_HOB_DATA), 0); + + FlashHobData.AreaType = mFlashAreaData[Index].AreaType; + FlashHobData.NumberOfEntries = 1; + FlashHobData.SubAreaData.Attributes = mFlashAreaData[Index].Attributes; + FlashHobData.SubAreaData.Base = FdBase + (EFI_PHYSICAL_ADDRESS) (UINTN) mFlashAreaData[Index].Base; + FlashHobData.SubAreaData.Length = (EFI_PHYSICAL_ADDRESS) (UINTN) mFlashAreaData[Index].Length; + + switch (FlashHobData.AreaType) { + case EFI_FLASH_AREA_RECOVERY_BIOS: + case EFI_FLASH_AREA_MAIN_BIOS: + (*PeiServices)->CopyMem ( + &FlashHobData.AreaTypeGuid, + &gEfiFirmwareFileSystemGuid, + sizeof (EFI_GUID) + ); + (*PeiServices)->CopyMem ( + &FlashHobData.SubAreaData.FileSystem, + &gEfiFirmwareVolumeBlockProtocolGuid, + sizeof (EFI_GUID) + ); + break; + + case EFI_FLASH_AREA_GUID_DEFINED: + (*PeiServices)->CopyMem ( + &FlashHobData.AreaTypeGuid, + &gEfiSystemNvDataHobGuid, + sizeof (EFI_GUID) + ); + (*PeiServices)->CopyMem ( + &FlashHobData.SubAreaData.FileSystem, + &gEfiFirmwareVolumeBlockProtocolGuid, + sizeof (EFI_GUID) + ); + break; + + default: + break; + } + + BuildGuidDataHob ( + &gEfiFlashMapHobGuid, + &FlashHobData, + sizeof (EFI_FLASH_AREA_HOB_DATA) + ); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +GetAreaInfo ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_FLASH_MAP_PPI *This, + IN EFI_FLASH_AREA_TYPE AreaType, + IN EFI_GUID *AreaTypeGuid, + OUT UINT32 *NumEntries, + OUT EFI_FLASH_SUBAREA_ENTRY **Entries + ) +/*++ + + Routine Description: + Implementation of Flash Map PPI + +--*/ +// TODO: function comment is missing 'Arguments:' +// TODO: function comment is missing 'Returns:' +// TODO: PeiServices - add argument and description to function comment +// TODO: This - add argument and description to function comment +// TODO: AreaType - add argument and description to function comment +// TODO: AreaTypeGuid - add argument and description to function comment +// TODO: NumEntries - add argument and description to function comment +// TODO: Entries - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +{ + EFI_STATUS Status; + EFI_PEI_HOB_POINTERS Hob; + EFI_HOB_FLASH_MAP_ENTRY_TYPE *FlashMapEntry; + + Status = PeiCoreGetHobList (&Hob.Raw); + while (!END_OF_HOB_LIST (Hob)) { + if (Hob.Header->HobType == EFI_HOB_TYPE_GUID_EXTENSION && CompareGuid (&Hob.Guid->Name, &gEfiFlashMapHobGuid)) { + FlashMapEntry = (EFI_HOB_FLASH_MAP_ENTRY_TYPE *) Hob.Raw; + if (AreaType == FlashMapEntry->AreaType) { + if (AreaType == EFI_FLASH_AREA_GUID_DEFINED) { + if (!CompareGuid (AreaTypeGuid, &FlashMapEntry->AreaTypeGuid)) { + continue; + } + } + + *NumEntries = FlashMapEntry->NumEntries; + *Entries = FlashMapEntry->Entries; + return EFI_SUCCESS; + } + } + + Hob.Raw = GET_NEXT_HOB (Hob); + } + + return EFI_NOT_FOUND; +} diff --git a/EdkNt32Pkg/Pei/FlashMap/FlashMap.dxs b/EdkNt32Pkg/Pei/FlashMap/FlashMap.dxs new file mode 100644 index 0000000000..0c197de817 --- /dev/null +++ b/EdkNt32Pkg/Pei/FlashMap/FlashMap.dxs @@ -0,0 +1,28 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FlashMap.dxs + +Abstract: + + Dependency expression file for FindFv. + +--*/ + +#include +#include + +DEPENDENCY_START + TRUE +DEPENDENCY_END + diff --git a/EdkNt32Pkg/Pei/FlashMap/FlashMap.mbd b/EdkNt32Pkg/Pei/FlashMap/FlashMap.mbd new file mode 100644 index 0000000000..8c38ee9f59 --- /dev/null +++ b/EdkNt32Pkg/Pei/FlashMap/FlashMap.mbd @@ -0,0 +1,43 @@ + + + + + PeiFlashMap + 681F3771-6F1D-42DE-9AA2-F82BBCDBC5F9 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-14 17:04 + 2006-03-23 10:43 + + + PeimEntryPoint + PeiMemoryLib + PeiCoreLib + PeiServicesTablePointerLib + PeiHobLib + PeiReportStatusCodeLib + BaseDebugLibReportStatusCode + BaseLib + + + _ModuleEntryPoint + + diff --git a/EdkNt32Pkg/Pei/FlashMap/FlashMap.msa b/EdkNt32Pkg/Pei/FlashMap/FlashMap.msa new file mode 100644 index 0000000000..c199978fb6 --- /dev/null +++ b/EdkNt32Pkg/Pei/FlashMap/FlashMap.msa @@ -0,0 +1,101 @@ + + + + + PeiFlashMap + PEIM + PE32_PEIM + 681F3771-6F1D-42DE-9AA2-F82BBCDBC5F9 + 0 + Component description file for FlashMap PEI module + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-14 17:04 + 2006-03-23 10:43 + + + DebugLib + PeimEntryPoint + HobLib + PeiCoreLib + PeiServicesTablePointerLib + BaseMemoryLib + + + FlashMap.c + FlashMap.dxs + + + MdePkg + EdkModulePkg + EdkNt32Pkg + + + FirmwareVolumeBlock + + + + VariableArea + gEfiFlashMapHobGuid + 0xb091e7d2, 0x5a0, 0x4198, 0x94, 0xf0, 0x74, 0xb7, 0xb8, 0xc5, 0x54, 0x59 + + + FtwBackupBlock + gEfiFlashMapHobGuid + 0xb091e7d2, 0x5a0, 0x4198, 0x94, 0xf0, 0x74, 0xb7, 0xb8, 0xc5, 0x54, 0x59 + + + FtwStateArea + gEfiFlashMapHobGuid + 0xb091e7d2, 0x5a0, 0x4198, 0x94, 0xf0, 0x74, 0xb7, 0xb8, 0xc5, 0x54, 0x59 + + + RecoveryBios + gEfiFlashMapHobGuid + 0xb091e7d2, 0x5a0, 0x4198, 0x94, 0xf0, 0x74, 0xb7, 0xb8, 0xc5, 0x54, 0x59 + + + SystemNvDataHob + gEfiFlashMapHobGuid + 0xb091e7d2, 0x5a0, 0x4198, 0x94, 0xf0, 0x74, 0xb7, 0xb8, 0xc5, 0x54, 0x59 + + + + FlashMap + NtFwh + + + + FlashMapHob + + + FirmwareFileSystem + + + SystemNvDataHob + + + + + PeimInitializeFlashMap + + + diff --git a/EdkNt32Pkg/Pei/FlashMap/build.xml b/EdkNt32Pkg/Pei/FlashMap/build.xml new file mode 100644 index 0000000000..b388551a3a --- /dev/null +++ b/EdkNt32Pkg/Pei/FlashMap/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkNt32Pkg/Pei/MonoStatusCode/MonoStatusCode.c b/EdkNt32Pkg/Pei/MonoStatusCode/MonoStatusCode.c new file mode 100644 index 0000000000..27c73f576e --- /dev/null +++ b/EdkNt32Pkg/Pei/MonoStatusCode/MonoStatusCode.c @@ -0,0 +1,150 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + MonoStatusCode.c + +Abstract: + + PEIM to provide the status code functionality, to aid in system debug. + It includes output to 0x80 port and/or to serial port. + This PEIM is monolithic. Different platform should provide different library. + +--*/ + +#include "MonoStatusCode.h" + +// +// Module globals +// +// +EFI_PEI_PROGRESS_CODE_PPI mStatusCodePpi = { PlatformReportStatusCode }; + +EFI_PEI_PPI_DESCRIPTOR mPpiListStatusCode = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiPeiStatusCodePpiGuid, + &mStatusCodePpi +}; + +// +// Function implemenations +// +EFI_STATUS +EFIAPI +TranslateDxeStatusCodeToPeiStatusCode ( + 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 + ) +/*++ + +Routine Description: + + Translate from a DXE status code interface into a PEI-callable + interface, making the PEI the least common denominator.. + +Arguments: + + Same as DXE ReportStatusCode RT service + +Returns: + + None + +--*/ +{ + return PlatformReportStatusCode (NULL, CodeType, Value, Instance, CallerId, Data); +} + +EFI_STATUS +EFIAPI +InitializeDxeReportStatusCode ( + IN EFI_PEI_SERVICES **PeiServices + ) +/*++ + +Routine Description: + + Build a hob describing the status code listener that has been installed. + This will be used by DXE code until a runtime status code listener is + installed. + +Arguments: + + PeiServices - General purpose services available to every PEIM. + +Returns: + + Status - EFI_SUCCESS if the interface could be successfully + installed + +--*/ +{ + VOID *Instance; + VOID *HobData; + + Instance = (VOID *) (UINTN) TranslateDxeStatusCodeToPeiStatusCode; + + HobData = BuildGuidDataHob ( + &gEfiStatusCodeRuntimeProtocolGuid, + &Instance, + sizeof (VOID *) + ); + + ASSERT (HobData != NULL); + return EFI_SUCCESS; +} + +VOID +EFIAPI +InitializeMonoStatusCode ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices + ) +/*++ + +Routine Description: + + Initialize the platform status codes and publish the platform status code + PPI. + +Arguments: + + FfsHeader - FV this PEIM was loaded from. + PeiServices - General purpose services available to every PEIM. + +Returns: + + Status - EFI_SUCCESS + +--*/ +{ + EFI_STATUS Status; + + // + // Initialize status code listeners. + // + PlatformInitializeStatusCode (FfsHeader, PeiServices); + + // + // Publish the status code capability to other modules + // + Status = (*PeiServices)->InstallPpi (PeiServices, &mPpiListStatusCode); + + ASSERT_EFI_ERROR (Status); + + DEBUG ((EFI_D_ERROR, "\nMono Status Code PEIM Loaded\n")); + + return ; +} diff --git a/EdkNt32Pkg/Pei/MonoStatusCode/MonoStatusCode.dxs b/EdkNt32Pkg/Pei/MonoStatusCode/MonoStatusCode.dxs new file mode 100644 index 0000000000..3c86da0c63 --- /dev/null +++ b/EdkNt32Pkg/Pei/MonoStatusCode/MonoStatusCode.dxs @@ -0,0 +1,28 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + MonoStatusCode.dxs + +Abstract: + + Dependency expression file for monolithic Status Code PEIM. + +--*/ +#include +#include + +DEPENDENCY_START + TRUE +DEPENDENCY_END + + diff --git a/EdkNt32Pkg/Pei/MonoStatusCode/MonoStatusCode.h b/EdkNt32Pkg/Pei/MonoStatusCode/MonoStatusCode.h new file mode 100644 index 0000000000..38a9022558 --- /dev/null +++ b/EdkNt32Pkg/Pei/MonoStatusCode/MonoStatusCode.h @@ -0,0 +1,111 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + MonoStatusCode.h + +Abstract: + + Monolithic single PEIM to provide the status code functionality. + The PEIM is a blend of libraries that correspond to the different status code + listeners that a platform installs. + +--*/ + +#ifndef _MONO_STATUS_CODE_H_ +#define _MONO_STATUS_CODE_H_ + +// +// Platform specific function Declarations. These must be implemented in a +// subdirectory named PlatformName in a file named PlatformStatusCode.c. +// See D845GRG\PlatformStatusCode.c for an example of a simple status code +// implementation. +// See Nt32\PlatformStatusCode.c for an example of a status code implementation +// that relocates itself into memory. +// +// +// This is the driver entry point and must be defined. +// +EFI_STATUS +EFIAPI +InstallMonoStatusCode ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices + ) +; + +// +// This is the platform function to initialize the listeners desired by the +// platform. +// +VOID +PlatformInitializeStatusCode ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices + ) +; + +// +// This is the platform function that calls all of the listeners desired by the +// platform. +// +EFI_STATUS +EFIAPI +PlatformReportStatusCode ( + IN EFI_PEI_SERVICES **PeiServices, + 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 + ) +; + +// +// Platform independent function Declarations +// +// +// Initialize the status code listeners and publish the status code PPI. +// +VOID +EFIAPI +InitializeMonoStatusCode ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices + ) +; + +// +// Convert a DXE status code call into a PEI status code call. +// +EFI_STATUS +EFIAPI +TranslateDxeStatusCodeToPeiStatusCode ( + 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 + ) +; + +// +// Publish a HOB that contains the listener to be used by DXE. +// +EFI_STATUS +EFIAPI +InitializeDxeReportStatusCode ( + IN EFI_PEI_SERVICES **PeiServices + ) +; + +#endif diff --git a/EdkNt32Pkg/Pei/MonoStatusCode/Nt32/MonoStatusCode.mbd b/EdkNt32Pkg/Pei/MonoStatusCode/Nt32/MonoStatusCode.mbd new file mode 100644 index 0000000000..f48b4c7f0e --- /dev/null +++ b/EdkNt32Pkg/Pei/MonoStatusCode/Nt32/MonoStatusCode.mbd @@ -0,0 +1,44 @@ + + + + + MonoStatusCode + 1501614E-0E6C-4ef4-8B8F-C276CDFB646F + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-14 17:04 + 2006-03-19 15:17 + + + PeiReportStatusCodeLib + BaseDebugLibReportStatusCode + BaseLib + PeiMemoryLib + PeiServicesTablePointerLib + PeiHobLib + PeimEntryPoint + EdkMemoryStatusCodeLib + PeiCoreLib + + + _ModuleEntryPoint + + diff --git a/EdkNt32Pkg/Pei/MonoStatusCode/Nt32/MonoStatusCode.msa b/EdkNt32Pkg/Pei/MonoStatusCode/Nt32/MonoStatusCode.msa new file mode 100644 index 0000000000..a1e96c7bf9 --- /dev/null +++ b/EdkNt32Pkg/Pei/MonoStatusCode/Nt32/MonoStatusCode.msa @@ -0,0 +1,70 @@ + + + + + MonoStatusCode + PEIM + PE32_PEIM + 1501614E-0E6C-4ef4-8B8F-C276CDFB646F + 0 + Component description file for DiskIo module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-14 17:04 + 2006-03-19 15:17 + + + DebugLib + PeimEntryPoint + EdkMemoryStatusCodeLib + HobLib + + + ..\MonoStatusCode.c + ..\MonoStatusCode.h + PlatformStatusCode.c + ..\MonoStatusCode.dxs + + + MdePkg + EdkModulePkg + EdkNt32Pkg + + + StatusCode + + + + TranslateDxeStatusCodeToPeiStatusCode + gEfiStatusCodeRuntimeProtocolGuid + 0xd2b2b828, 0x826, 0x48a7, 0xb3, 0xdf, 0x98, 0x3c, 0x0, 0x60, 0x24, 0xf0 + + + + StatusCode + FvFileLoader + + + + InstallMonoStatusCode + + + diff --git a/EdkNt32Pkg/Pei/MonoStatusCode/Nt32/PlatformStatusCode.c b/EdkNt32Pkg/Pei/MonoStatusCode/Nt32/PlatformStatusCode.c new file mode 100644 index 0000000000..9d1a57b2ee --- /dev/null +++ b/EdkNt32Pkg/Pei/MonoStatusCode/Nt32/PlatformStatusCode.c @@ -0,0 +1,162 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PlatformStatusCode.c + +Abstract: + + Contains NT32 specific implementations required to use status codes. + +--*/ + +#include "../MonoStatusCode.h" + + +BOOLEAN gRunningFromMemory = FALSE; +// +// Platform definitions +// +EFI_PEI_REPORT_STATUS_CODE mSecReportStatusCode = NULL; + +extern EFI_PEI_PROGRESS_CODE_PPI mStatusCodePpi; + +// +// Function implementations +// +EFI_STATUS +EFIAPI +PlatformReportStatusCode ( + IN EFI_PEI_SERVICES **PeiServices, + 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 + ) +/*++ + +Routine Description: + + Call all status code listeners in the MonoStatusCode. + +Arguments: + + Same as ReportStatusCode service + +Returns: + + EFI_SUCCESS Always returns success. + +--*/ +{ + mSecReportStatusCode (PeiServices, CodeType, Value, Instance, CallerId, Data); + MemoryReportStatusCode (CodeType, Value, Instance, CallerId, Data); + return EFI_SUCCESS; +} + +VOID +PlatformInitializeStatusCode ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices + ) +/*++ + +Routine Description: + + Initialize the status code listeners. This consists of locating the + listener produced by SecMain.exe. + +Arguments: + + FfsHeader - FV this PEIM was loaded from. + PeiServices - General purpose services available to every PEIM. + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + EFI_PEI_PROGRESS_CODE_PPI *ReportStatusCodePpi; + EFI_PEI_PPI_DESCRIPTOR *ReportStatusCodeDescriptor; + + // + // Cache the existing status code listener installed by the SEC core. + // We should actually do a heap allocate, install a PPI, etc, but since we + // know that we are running from a DLL, we can use global variables, and + // directly update the status code PPI descriptor + // + // + // Locate SEC status code PPI + // + Status = (*PeiServices)->LocatePpi ( + PeiServices, + &gEfiPeiStatusCodePpiGuid, + 0, + &ReportStatusCodeDescriptor, + &ReportStatusCodePpi + ); + if (EFI_ERROR (Status)) { + return ; + } + + mSecReportStatusCode = ReportStatusCodePpi->ReportStatusCode; + ReportStatusCodeDescriptor->Ppi = &mStatusCodePpi; + + // + // Always initialize memory status code listener. + // + MemoryStatusCodeInitialize (FfsHeader, PeiServices); + +} + +EFI_STATUS +EFIAPI +InstallMonoStatusCode ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices + ) +/*++ + +Routine Description: + + Install the PEIM. Publish the DXE callback as well. + +Arguments: + + FfsHeader - FV this PEIM was loaded from. + PeiServices - General purpose services available to every PEIM. + +Returns: + + EFI_SUCCESS The function always returns success. + +--*/ +{ + if (!gRunningFromMemory) { + // + // First pass, running from flash, initialize everything + // + InitializeMonoStatusCode (FfsHeader, PeiServices); + } else { + // + // Second pass, running from memory, initialize memory listener and + // publish the DXE listener in a HOB. + // + MemoryStatusCodeInitialize (FfsHeader, PeiServices); + InitializeDxeReportStatusCode (PeiServices); + } + + return EFI_SUCCESS; +} diff --git a/EdkNt32Pkg/Pei/MonoStatusCode/Nt32/build.xml b/EdkNt32Pkg/Pei/MonoStatusCode/Nt32/build.xml new file mode 100644 index 0000000000..e6c8551241 --- /dev/null +++ b/EdkNt32Pkg/Pei/MonoStatusCode/Nt32/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkNt32Pkg/Pei/PcdEmulator/PcdEmulator.c b/EdkNt32Pkg/Pei/PcdEmulator/PcdEmulator.c new file mode 100644 index 0000000000..69261b952b --- /dev/null +++ b/EdkNt32Pkg/Pei/PcdEmulator/PcdEmulator.c @@ -0,0 +1,657 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + PcdEmulator.c + +Abstract: + Platform Configuration Database (PCD) Service PEIM + +--*/ + +#include + +// +// BugBug: PEI early phase does not support global variable!!! +// This is only a temperary solution. +// + +UINTN mSkuId = 0; + + +STATIC EMULATED_PCD_DATABASE_EX * +GetPcdDataBaseEx ( + VOID +) { + EFI_HOB_GUID_TYPE *GuidHob; + EMULATED_PCD_DATABASE_EX *EmulatedPcdDatabaseEx; + + GuidHob = GetFirstGuidHob (&gPcdHobGuid); + EmulatedPcdDatabaseEx = (EMULATED_PCD_DATABASE_EX *) GET_GUID_HOB_DATA(GuidHob); + + return EmulatedPcdDatabaseEx; +} + +STATIC UINTN +GetPcdDataBaseExEntryCount ( + EMULATED_PCD_DATABASE_EX * Database +) { + return Database->Count; +} + +STATIC UINTN +GetPcdDataBaseExSize ( + EMULATED_PCD_DATABASE_EX * Database +) { + UINTN Size; + + Size = sizeof (Database->Count) + + (sizeof (Database->Entry[0]) * Database->Count); + + return Size; +} + +EFI_STATUS +EFIAPI +PcdEmulatorSetSku ( + IN UINTN SkuId + ) +{ + mSkuId = SkuId; + return EFI_SUCCESS; +} + +UINT8 +EFIAPI +PcdEmulatorGet8 ( + IN UINTN TokenNumber + ) +{ + EMULATED_PCD_ENTRY_EX *Pcd; + + Pcd = GetPcdEntry (TokenNumber); + ASSERT (Pcd != NULL); + ASSERT (Pcd->DatumSize == 1); + + return (UINT8)Pcd->Datum; +} + +UINT16 +EFIAPI +PcdEmulatorGet16 ( + IN UINTN TokenNumber + ) +{ + EMULATED_PCD_ENTRY_EX *Pcd; + + Pcd = GetPcdEntry (TokenNumber); + ASSERT (Pcd != NULL); + ASSERT (Pcd->DatumSize == 2); + + return (UINT16)Pcd->Datum; +} + +UINT32 +EFIAPI +PcdEmulatorGet32 ( + IN UINTN TokenNumber + ) +{ + EMULATED_PCD_ENTRY_EX *Pcd; + + Pcd = GetPcdEntry (TokenNumber); + ASSERT (Pcd != NULL); + ASSERT (Pcd->DatumSize == 4); + + return (UINT32)Pcd->Datum; +} + +UINT64 +EFIAPI +PcdEmulatorGet64 ( + IN UINTN TokenNumber + ) +{ + EMULATED_PCD_ENTRY_EX *Pcd; + + Pcd = GetPcdEntry (TokenNumber); + ASSERT (Pcd != NULL); + ASSERT (Pcd->DatumSize == sizeof (UINT64)); + + return (UINT64)Pcd->Datum; +} + +VOID * +EFIAPI +PcdEmulatorGetPtr ( + IN UINTN TokenNumber + ) +{ + EMULATED_PCD_ENTRY_EX *Pcd; + + Pcd = GetPcdEntry (TokenNumber); + ASSERT (Pcd != NULL); + + return (VOID *)(UINTN)Pcd->ExtendedData; +} + +BOOLEAN +EFIAPI +PcdEmulatorGetBoolean ( + IN UINTN TokenNumber + ) +{ + EMULATED_PCD_ENTRY_EX *Pcd; + + Pcd = GetPcdEntry (TokenNumber); + ASSERT (Pcd != NULL); + ASSERT (Pcd->DatumSize == 1); + + return (BOOLEAN)Pcd->Datum; +} + +UINTN +EFIAPI +PcdEmulatorGetSize ( + IN UINTN TokenNumber + ) +{ + EMULATED_PCD_ENTRY_EX *Pcd; + + Pcd = GetPcdEntry (TokenNumber); + ASSERT (Pcd != NULL); + return Pcd->DatumSize; +} + +UINT8 +EFIAPI +PcdEmulatorGet8Ex ( + IN CONST EFI_GUID *PcdDataBaseName, + IN UINTN TokenNumber + ) +{ + ASSERT (FALSE); + return 0; +} + +UINT16 +EFIAPI +PcdEmulatorGet16Ex ( + IN CONST EFI_GUID *PcdDataBaseName, + IN UINTN TokenNumber + ) +{ + ASSERT (FALSE); + return 0; +} + +UINT32 +EFIAPI +PcdEmulatorGet32Ex ( + IN CONST EFI_GUID *PcdDataBaseName, + IN UINTN TokenNumber + ) +{ + ASSERT (FALSE); + return 0; +} + +UINT64 +EFIAPI +PcdEmulatorGet64Ex ( + IN CONST EFI_GUID *PcdDataBaseName, + IN UINTN TokenNumber + ) +{ + ASSERT (FALSE); + return 0; +} + +VOID * +EFIAPI +PcdEmulatorGetPtrEx ( + IN CONST EFI_GUID *PcdDataBaseName, + IN UINTN TokenNumber + ) +{ + ASSERT (FALSE); + return 0; +} + +BOOLEAN +EFIAPI +PcdEmulatorGetBooleanEx ( + IN CONST EFI_GUID *PcdDataBaseName, + IN UINTN TokenNumber + ) +{ + ASSERT (FALSE); + return 0; +} + +UINTN +EFIAPI +PcdEmulatorGetSizeEx ( + IN CONST EFI_GUID *PcdDataBaseName, + IN UINTN TokenNumber + ) +{ + EMULATED_PCD_ENTRY_EX *Pcd; + + Pcd = GetPcdEntry (TokenNumber); + ASSERT (Pcd != NULL); + return Pcd->DatumSize; +} + + +EFI_STATUS +EFIAPI +PcdEmulatorSet8 ( + IN UINTN TokenNumber, + IN UINT8 Value + ) +{ + + EMULATED_PCD_ENTRY_EX *Pcd; + + Pcd = GetPcdEntry (TokenNumber); + ASSERT (Pcd != NULL); + + ASSERT (Pcd->DatumSize == sizeof (UINT8)); + + Pcd->Datum = Value; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcdEmulatorSet16 ( + IN UINTN TokenNumber, + IN UINT16 Value + ) +{ + + ASSERT (FALSE); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcdEmulatorSet32 ( + IN UINTN TokenNumber, + IN UINT32 Value + ) +{ + + EMULATED_PCD_ENTRY_EX *Pcd; + + Pcd = GetPcdEntry (TokenNumber); + ASSERT (Pcd != NULL); + + ASSERT (Pcd->DatumSize == sizeof (UINT32)); + + Pcd->Datum = Value; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcdEmulatorSet64 ( + IN UINTN TokenNumber, + IN UINT64 Value + ) +{ + + ASSERT (FALSE); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcdEmulatorSetPtr ( + IN UINTN TokenNumber, + IN CONST VOID *Value + ) +{ + + ASSERT (FALSE); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcdEmulatorSetBoolean ( + IN UINTN TokenNumber, + IN BOOLEAN Value + ) +{ + + ASSERT (FALSE); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcdEmulatorSet8Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN UINT8 Value + ) +{ + + ASSERT (FALSE); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcdEmulatorSet16Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN UINT16 Value + ) +{ + + ASSERT (FALSE); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcdEmulatorSet32Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN UINT32 Value + ) +{ + + ASSERT (FALSE); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcdEmulatorSet64Ex ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN UINT64 Value + ) +{ + + ASSERT (FALSE); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcdEmulatorSetPtrEx ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN CONST VOID *Value + ) +{ + + ASSERT (FALSE); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcdEmulatorSetBooleanEx ( + IN CONST EFI_GUID *Guid, + IN UINTN TokenNumber, + IN BOOLEAN Value + ) +{ + + ASSERT (FALSE); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcdEmulatorCallBackOnSet ( + IN UINTN TokenNumber, + IN CONST EFI_GUID *Guid, OPTIONAL + IN PCD_PPI_CALLBACK CallBackFunction + ) +{ + EMULATED_PCD_ENTRY_EX *Pcd; + + Pcd = GetPcdEntry (TokenNumber); + ASSERT (Pcd != NULL); + + if (Pcd->CallBackListSize == Pcd->CallBackEntries) { + return EFI_OUT_OF_RESOURCES; + } + + Pcd->CallBackList[Pcd->CallBackEntries++] = CallBackFunction; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcdEmulatorUnregisterCallBackOnSet ( + IN UINTN TokenNumber, + IN CONST EFI_GUID *Guid, OPTIONAL + IN PCD_PPI_CALLBACK CallBackfunction + ) +{ + EMULATED_PCD_ENTRY_EX *Pcd; + UINT32 Index; + + Pcd = GetPcdEntry (TokenNumber); + ASSERT (Pcd != NULL); + + for (Index = 0; Index < Pcd->CallBackListSize; Index++) { + if (Pcd->CallBackList[Index] == CallBackfunction) { + Pcd->CallBackList[Index] = NULL; + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +EFI_STATUS +EFIAPI +PcdEmulatorGetNextToken ( + IN CONST EFI_GUID *Guid, OPTIONAL + IN UINTN *Token + ) +{ + EMULATED_PCD_ENTRY_EX *Pcd; + EMULATED_PCD_ENTRY_EX *LastPcdEntry; + EMULATED_PCD_DATABASE_EX *PcdDatabase; + EMULATED_PCD_ENTRY_EX *PcdEntry; + + PcdDatabase = GetPcdDataBaseEx (); + PcdEntry = PcdDatabase->Entry; + + if (*Token == PCD_INVALID_TOKEN) { + // + // BugBug: Due to variable size array, ensure we convert this to a reasonable database + // that can accomodate array references for simplicity's sake + *Token = PcdEntry[0].Token; + return EFI_SUCCESS; + } + + Pcd = GetPcdEntry (*Token); + if (Pcd == NULL) { + return EFI_NOT_FOUND; + } + + LastPcdEntry = PcdEntry + GetPcdDataBaseExEntryCount (PcdDatabase); + if (++Pcd >= LastPcdEntry) { + return EFI_NOT_FOUND; + } + + *Token = Pcd->Token; + return EFI_SUCCESS; +} + +PCD_PPI mPcdPpiInstance = { + PcdEmulatorSetSku, + + PcdEmulatorGet8, + PcdEmulatorGet16, + PcdEmulatorGet32, + PcdEmulatorGet64, + PcdEmulatorGetPtr, + PcdEmulatorGetBoolean, + PcdEmulatorGetSize, + + PcdEmulatorGet8Ex, + PcdEmulatorGet16Ex, + PcdEmulatorGet32Ex, + PcdEmulatorGet64Ex, + PcdEmulatorGetPtrEx, + PcdEmulatorGetBooleanEx, + PcdEmulatorGetSizeEx, + + PcdEmulatorSet8, + PcdEmulatorSet16, + PcdEmulatorSet32, + PcdEmulatorSet64, + PcdEmulatorSetPtr, + PcdEmulatorSetBoolean, + + PcdEmulatorSet8Ex, + PcdEmulatorSet16Ex, + PcdEmulatorSet32Ex, + PcdEmulatorSet64Ex, + PcdEmulatorSetPtrEx, + PcdEmulatorSetBooleanEx, + + PcdEmulatorCallBackOnSet, + PcdEmulatorUnregisterCallBackOnSet, + PcdEmulatorGetNextToken +}; + +STATIC EFI_PEI_PPI_DESCRIPTOR mPpiPCD = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gPcdPpiGuid, + &mPcdPpiInstance +}; + +EFI_STATUS +EFIAPI +PeimPcdEmulatorEntry ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + UINTN Index; + UINTN Count; + UINTN Calculation; + UINT8 *AllocatedBuffer; + EMULATED_PCD_DATABASE_EX *EmulatedPcdDatabaseEx; + EMULATED_PCD_ENTRY_EX *EmulatedPcdEntryEx; + + // + // BugBug: Normally, we would read an FFS file for this data + // We need to remember, that when we read the FFS file, items such as the VariableName will not be encoded as a pointer + // but as an array of content. In this emulation, our init is encoding this data as a pointer. + // In the FFS version, we will depend on the proper Entry Count in the FFS data since the structures will + // now be variable length. + // + // + + // + // We should now read from the FFS file into the cache - for now, we fake this. + // + Count = GetPcdDataBaseSize () / sizeof (EMULATED_PCD_ENTRY); + + // + // Let's now determine how big of a buffer we need for our database + // For the FFS version, we need to calculate/consider the VariableName/ExtendedData size!!! + // + Calculation = sizeof (UINTN) + (Count * sizeof (EMULATED_PCD_ENTRY_EX)); + + EmulatedPcdDatabaseEx = (EMULATED_PCD_DATABASE_EX *) BuildGuidHob (&gPcdHobGuid, Calculation); + + EmulatedPcdDatabaseEx->Count = Count; + EmulatedPcdEntryEx = EmulatedPcdDatabaseEx->Entry; + + AllocatedBuffer = AllocatePool (Count * sizeof (PCD_PPI_CALLBACK) * MAX_PCD_CALLBACK); + ASSERT (AllocatedBuffer != NULL); + + for (Index = 0; Index < Count; Index++) { + // + // Copy from source to our own allocated buffer - normally an FFS read + // + (*PeiServices)->CopyMem ( + (VOID *) (EmulatedPcdEntryEx + Index), + (VOID *) (gEmulatedPcdEntry + Index), + sizeof (EMULATED_PCD_ENTRY) + ); + + // + // All the CallBackList worker functions refer to this CallBackList as CallBackList[CallbackEntry] + // so we seed the same buffer address here. + // + EmulatedPcdEntryEx[Index].CallBackList = (PCD_PPI_CALLBACK *)AllocatedBuffer; + AllocatedBuffer+= (sizeof (PCD_PPI_CALLBACK) * MAX_PCD_CALLBACK); + EmulatedPcdEntryEx[Index].CallBackEntries = 0; + EmulatedPcdEntryEx[Index].CallBackListSize = MAX_PCD_CALLBACK; + } + + // + // Install PCD service PPI + // + Status = PeiCoreInstallPpi (&mPpiPCD); + + ASSERT_EFI_ERROR (Status); + return Status; +} + + +EMULATED_PCD_ENTRY_EX * +GetPcdEntry ( + IN UINTN TokenNumber + ) +{ + UINTN Index; + UINTN Count; + EMULATED_PCD_DATABASE_EX *EmulatedPcdDatabaseEx; + EMULATED_PCD_ENTRY_EX *EmulatedPcdEntryEx; + + CpuBreakpoint (); + + EmulatedPcdDatabaseEx = GetPcdDataBaseEx (); + // + // BugBug: This Count will change when we flip over to FFS version + // + Count = EmulatedPcdDatabaseEx->Count; + EmulatedPcdEntryEx = EmulatedPcdDatabaseEx->Entry; + for (Index = 0; Index < Count; Index++) { + if (EmulatedPcdEntryEx[Index].Token == TokenNumber) { + return &EmulatedPcdEntryEx[Index]; + } + } + return NULL; +} + + diff --git a/EdkNt32Pkg/Pei/PcdEmulator/PcdEmulator.dxs b/EdkNt32Pkg/Pei/PcdEmulator/PcdEmulator.dxs new file mode 100644 index 0000000000..ea579976c8 --- /dev/null +++ b/EdkNt32Pkg/Pei/PcdEmulator/PcdEmulator.dxs @@ -0,0 +1,25 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PcdEmulator.dxs + +Abstract: + + Dependency expression source file. + +--*/ +#include + +DEPENDENCY_START + TRUE +DEPENDENCY_END diff --git a/EdkNt32Pkg/Pei/PcdEmulator/PcdEmulator.h b/EdkNt32Pkg/Pei/PcdEmulator/PcdEmulator.h new file mode 100644 index 0000000000..e97c2a1201 --- /dev/null +++ b/EdkNt32Pkg/Pei/PcdEmulator/PcdEmulator.h @@ -0,0 +1,53 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + PcdEmulator.h + +Abstract: + Platform Configuration Database (PCD) + +--*/ + +#ifndef __PCD_EMULATOR_H__ +#define __PCD_EMULATOR_H__ + + + +// +// BugBug: Not very sure, where to put this "extern" +// +extern GUID gPcdHobGuid; + +// +// BugBug: Hack max number of callbacks per token +// +#define MAX_PCD_CALLBACK 0x10 + +extern EMULATED_PCD_ENTRY gEmulatedPcdEntry[]; + +UINTN +GetPcdDataBaseSize ( + VOID + ); + +EMULATED_PCD_ENTRY_EX * +GetPcdEntry ( + IN UINTN TokenNumber + ); + +EFI_STATUS +InstallMyHob ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ); +#endif diff --git a/EdkNt32Pkg/Pei/PcdEmulator/PcdEmulator.mbd b/EdkNt32Pkg/Pei/PcdEmulator/PcdEmulator.mbd new file mode 100644 index 0000000000..816cf6f869 --- /dev/null +++ b/EdkNt32Pkg/Pei/PcdEmulator/PcdEmulator.mbd @@ -0,0 +1,41 @@ + + + + + PcdEmulatorPeim + 9B3ADA4F-AE56-4c24-8DEA-F03B7558AE50 + EDK_RELEASE_VERSION 0x00020000 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-14 17:04 + 2006-03-24 18:54 + + + PeimEntryPoint + BaseLib + PeiCoreLib + PeiServicesTablePointerLib + PeiHobLib + BaseDebugLibReportStatusCode + PeiMemoryLib + PeiReportStatusCodeLib + PeiMemoryAllocationLib + + diff --git a/EdkNt32Pkg/Pei/PcdEmulator/PcdEmulator.msa b/EdkNt32Pkg/Pei/PcdEmulator/PcdEmulator.msa new file mode 100644 index 0000000000..9a329a2b66 --- /dev/null +++ b/EdkNt32Pkg/Pei/PcdEmulator/PcdEmulator.msa @@ -0,0 +1,72 @@ + + + + + PcdEmulatorPeim + PEIM + PE32_PEIM + 9B3ADA4F-AE56-4c24-8DEA-F03B7558AE50 + EDK_RELEASE_VERSION 0x00020000 + Component description file for PcdEmulator PEIM module + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + EFI_SPECIFICATION_VERSION 0x00000000 + 2006-03-14 17:04 + 2006-03-24 18:54 + + + DebugLib + PeimEntryPoint + BaseLib + HobLib + PeiCoreLib + PcdLib + PeiServicesTablePointerLib + MemoryAllocationLib + + + PcdEmulator.dxs + PcdEmulator.c + + + MdePkg + EdkNt32Pkg + + + + PcdDataBase + gPcdHobGuid + 0x582e7ca1, 0x68cd, 0x4d44, 0xb4, 0x3b, 0xf2, 0x98, 0xed, 0x58, 0x7b, 0xa6 + + + + Pcd + + + + PcdHob + + + + + PeimPcdEmulatorEntry + + + diff --git a/EdkNt32Pkg/Pei/PcdEmulator/build.xml b/EdkNt32Pkg/Pei/PcdEmulator/build.xml new file mode 100644 index 0000000000..86e0d1fc8e --- /dev/null +++ b/EdkNt32Pkg/Pei/PcdEmulator/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkNt32Pkg/Pei/WinNtStuff/WinNtStuff.dxs b/EdkNt32Pkg/Pei/WinNtStuff/WinNtStuff.dxs new file mode 100644 index 0000000000..107ddee3e1 --- /dev/null +++ b/EdkNt32Pkg/Pei/WinNtStuff/WinNtStuff.dxs @@ -0,0 +1,29 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + WinNtStuff.dxs + +Abstract: + + Dependency expression file for WinNtStuff PEIM. + +--*/ + +#include +#include + +DEPENDENCY_START + PEI_NT_THUNK_PPI_GUID AND EFI_PEI_PERMANENT_MEMORY_INSTALLED_PPI_GUID +DEPENDENCY_END + + diff --git a/EdkNt32Pkg/Pei/WinNtStuff/WinNtStuff.mbd b/EdkNt32Pkg/Pei/WinNtStuff/WinNtStuff.mbd new file mode 100644 index 0000000000..ab862efcae --- /dev/null +++ b/EdkNt32Pkg/Pei/WinNtStuff/WinNtStuff.mbd @@ -0,0 +1,43 @@ + + + + + WinNtStuff + D3AAD8DC-3A48-46ac-B1C7-28A9D3CF6755 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-14 17:04 + 2006-03-19 15:17 + + + PeimEntryPoint + PeiMemoryLib + PeiCoreLib + PeiServicesTablePointerLib + PeiHobLib + PeiReportStatusCodeLib + BaseDebugLibReportStatusCode + BaseLib + + + _ModuleEntryPoint + + diff --git a/EdkNt32Pkg/Pei/WinNtStuff/WinNtStuff.msa b/EdkNt32Pkg/Pei/WinNtStuff/WinNtStuff.msa new file mode 100644 index 0000000000..11aa06a21b --- /dev/null +++ b/EdkNt32Pkg/Pei/WinNtStuff/WinNtStuff.msa @@ -0,0 +1,68 @@ + + + + + WinNtStuff + PEIM + PE32_PEIM + D3AAD8DC-3A48-46ac-B1C7-28A9D3CF6755 + 0 + Component description file for WinNtStuff module + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-14 17:04 + 2006-03-19 15:17 + + + DebugLib + PeimEntryPoint + HobLib + PeiCoreLib + PeiServicesTablePointerLib + + + WinNtStuff.c + WinNtStuff.dxs + + + MdePkg + EdkModulePkg + EdkNt32Pkg + + + WinNtThunk + + + + WinNtThunkProtocol + gEfiWinNtThunkProtocolGuid + 0x58c518b1, 0x76f3, 0x11d4, 0xbc, 0xea, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81 + + + + NtThunk + + + + PeimInitializeWinNtStuff + + + diff --git a/EdkNt32Pkg/Pei/WinNtStuff/build.xml b/EdkNt32Pkg/Pei/WinNtStuff/build.xml new file mode 100644 index 0000000000..885bacb1a2 --- /dev/null +++ b/EdkNt32Pkg/Pei/WinNtStuff/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkNt32Pkg/Pei/WinNtStuff/winntstuff.c b/EdkNt32Pkg/Pei/WinNtStuff/winntstuff.c new file mode 100644 index 0000000000..46859286ea --- /dev/null +++ b/EdkNt32Pkg/Pei/WinNtStuff/winntstuff.c @@ -0,0 +1,73 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + WinNtStuff.c + +Abstract: + + Tiano PEIM to abstract construction of firmware volume in a Windows NT environment. + +Revision History + +--*/ + + + +EFI_STATUS +EFIAPI +PeimInitializeWinNtStuff ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices + ) +/*++ + +Routine Description: + + Perform a call-back into the SEC simulator to get NT Stuff + +Arguments: + + PeiServices - General purpose services available to every PEIM. + +Returns: + + None + +--*/ +// TODO: FfsHeader - add argument and description to function comment +{ + EFI_STATUS Status; + EFI_PEI_PPI_DESCRIPTOR *PpiDescriptor; + PEI_NT_THUNK_PPI *PeiNtService; + VOID *Ptr; + + DEBUG ((EFI_D_ERROR, "NT 32 WinNT Stuff PEIM Loaded\n")); + + Status = (**PeiServices).LocatePpi ( + PeiServices, + &gPeiNtThunkPpiGuid, // GUID + 0, // INSTANCE + &PpiDescriptor, // EFI_PEI_PPI_DESCRIPTOR + &PeiNtService // PPI + ); + ASSERT_EFI_ERROR (Status); + + Ptr = PeiNtService->NtThunk (); + + BuildGuidDataHob ( + &gEfiWinNtThunkProtocolGuid, // Guid + &Ptr, // Buffer + sizeof (VOID *) // Sizeof Buffer + ); + return Status; +} diff --git a/EdkNt32Pkg/RuntimeDxe/FvbServices/Common/FWBlockService.c b/EdkNt32Pkg/RuntimeDxe/FvbServices/Common/FWBlockService.c new file mode 100644 index 0000000000..e22a3233c4 --- /dev/null +++ b/EdkNt32Pkg/RuntimeDxe/FvbServices/Common/FWBlockService.c @@ -0,0 +1,1939 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FWBlockService.c + +Abstract: + +Revision History + +--*/ + +#include "FWBlockService.h" +#include "EfiFlashMap.h" +#include EFI_GUID_DEFINITION (FlashMapHob) + +ESAL_FWB_GLOBAL *mFvbModuleGlobal; + +EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = { + FVB_DEVICE_SIGNATURE, + { + { + { + HARDWARE_DEVICE_PATH, + HW_MEMMAP_DP, + { + sizeof (MEMMAP_DEVICE_PATH), + 0 + } + }, + EfiMemoryMappedIO, + 0, + 0, + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + sizeof (EFI_DEVICE_PATH_PROTOCOL), + 0 + } + } + }, + 0, + { + FvbProtocolGetAttributes, + FvbProtocolSetAttributes, + FvbProtocolGetPhysicalAddress, + FvbProtocolGetBlockSize, + FvbProtocolRead, + FvbProtocolWrite, + FvbProtocolEraseBlocks, + NULL + }, + { + FvbExtendProtocolEraseCustomBlockRange + } +}; + +EFI_DRIVER_ENTRY_POINT (FvbInitialize) + + +VOID +EFIAPI +FvbVirtualddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + + Fixup internal data so that EFI and SAL can be call in virtual mode. + Call the passed in Child Notify event and convert the mFvbModuleGlobal + date items to there virtual address. + + mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance data + mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common + instance data. + +Arguments: + + (Standard EFI notify event - EFI_EVENT_NOTIFY) + +Returns: + + None + +--*/ +{ + EFI_FW_VOL_INSTANCE *FwhInstance; + UINTN Index; + + EfiConvertPointer (EFI_INTERNAL_POINTER, (VOID **) &mFvbModuleGlobal->FvInstance[FVB_VIRTUAL]); + + // + // Convert the base address of all the instances + // + Index = 0; + FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]; + while (Index < mFvbModuleGlobal->NumFv) { + EfiConvertPointer (EFI_INTERNAL_POINTER, (VOID **) &FwhInstance->FvBase[FVB_VIRTUAL]); + EfiConvertPointer (EFI_INTERNAL_POINTER, (VOID **) &FwhInstance->FvWriteBase[FVB_VIRTUAL]); + FwhInstance = (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhInstance) + FwhInstance->VolumeHeader.HeaderLength + + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))); + Index++; + } + + EfiConvertPointer (EFI_INTERNAL_POINTER, (VOID **) &mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL]); + EfiConvertPointer (EFI_INTERNAL_POINTER, (VOID **) &mFvbModuleGlobal); +} + +VOID +FvbMemWrite8 ( + IN UINT64 Dest, + IN UINT8 Byte + ) +{ + EfiMemWrite (EfiCpuIoWidthUint8, Dest, 1, &Byte); + + return ; +} + +EFI_STATUS +GetFvbInstance ( + IN UINTN Instance, + IN ESAL_FWB_GLOBAL *Global, + OUT EFI_FW_VOL_INSTANCE **FwhInstance, + IN BOOLEAN Virtual + ) +/*++ + +Routine Description: + Retrieves the physical address of a memory mapped FV + +Arguments: + Instance - The FV instance whose base address is going to be + returned + Global - Pointer to ESAL_FWB_GLOBAL that contains all + instance data + FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure + Virtual - Whether CPU is in virtual or physical mode + +Returns: + EFI_SUCCESS - Successfully returns + EFI_INVALID_PARAMETER - Instance not found + +--*/ +{ + EFI_FW_VOL_INSTANCE *FwhRecord; + + if (Instance >= Global->NumFv) { + return EFI_INVALID_PARAMETER; + } + // + // Find the right instance of the FVB private data + // + FwhRecord = Global->FvInstance[Virtual]; + while (Instance > 0) { + FwhRecord = (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhRecord) + FwhRecord->VolumeHeader.HeaderLength + + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))); + Instance--; + } + + *FwhInstance = FwhRecord; + + return EFI_SUCCESS; +} + +EFI_STATUS +FvbGetPhysicalAddress ( + IN UINTN Instance, + OUT EFI_PHYSICAL_ADDRESS *Address, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +/*++ + +Routine Description: + Retrieves the physical address of a memory mapped FV + +Arguments: + Instance - The FV instance whose base address is going to be + returned + Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS + that on successful return, contains the base address + of the firmware volume. + Global - Pointer to ESAL_FWB_GLOBAL that contains all + instance data + Virtual - Whether CPU is in virtual or physical mode + +Returns: + EFI_SUCCESS - Successfully returns + EFI_INVALID_PARAMETER - Instance not found + +--*/ +{ + EFI_FW_VOL_INSTANCE *FwhInstance; + EFI_STATUS Status; + + // + // Find the right instance of the FVB private data + // + Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual); + ASSERT_EFI_ERROR (Status); + *Address = FwhInstance->FvBase[Virtual]; + + return EFI_SUCCESS; +} + +EFI_STATUS +FvbGetVolumeAttributes ( + IN UINTN Instance, + OUT EFI_FVB_ATTRIBUTES *Attributes, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +/*++ + +Routine Description: + Retrieves attributes, insures positive polarity of attribute bits, returns + resulting attributes in output parameter + +Arguments: + Instance - The FV instance whose attributes is going to be + returned + Attributes - Output buffer which contains attributes + Global - Pointer to ESAL_FWB_GLOBAL that contains all + instance data + Virtual - Whether CPU is in virtual or physical mode + +Returns: + EFI_SUCCESS - Successfully returns + EFI_INVALID_PARAMETER - Instance not found + +--*/ +{ + EFI_FW_VOL_INSTANCE *FwhInstance; + EFI_STATUS Status; + + // + // Find the right instance of the FVB private data + // + Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual); + ASSERT_EFI_ERROR (Status); + *Attributes = FwhInstance->VolumeHeader.Attributes; + + return EFI_SUCCESS; +} + +EFI_STATUS +FvbGetLbaAddress ( + IN UINTN Instance, + IN EFI_LBA Lba, + OUT UINTN *LbaAddress, + OUT UINTN *LbaWriteAddress, + OUT UINTN *LbaLength, + OUT UINTN *NumOfBlocks, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +/*++ + +Routine Description: + Retrieves the starting address of an LBA in an FV + +Arguments: + Instance - The FV instance which the Lba belongs to + Lba - The logical block address + LbaAddress - On output, contains the physical starting address + of the Lba + LbaWriteAddress - On output, contains the physical starting address + of the Lba for writing + LbaLength - On output, contains the length of the block + NumOfBlocks - A 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 + Global - Pointer to ESAL_FWB_GLOBAL that contains all + instance data + Virtual - Whether CPU is in virtual or physical mode + +Returns: + EFI_SUCCESS - Successfully returns + EFI_INVALID_PARAMETER - Instance not found + +--*/ +{ + UINT32 NumBlocks; + UINT32 BlockLength; + UINTN Offset; + EFI_LBA StartLba; + EFI_LBA NextLba; + EFI_FW_VOL_INSTANCE *FwhInstance; + EFI_FV_BLOCK_MAP_ENTRY *BlockMap; + EFI_STATUS Status; + + // + // Find the right instance of the FVB private data + // + Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual); + ASSERT_EFI_ERROR (Status); + + StartLba = 0; + Offset = 0; + BlockMap = &(FwhInstance->VolumeHeader.FvBlockMap[0]); + + // + // Parse the blockmap of the FV to find which map entry the Lba belongs to + // + while (TRUE) { + NumBlocks = BlockMap->NumBlocks; + BlockLength = BlockMap->BlockLength; + + if (NumBlocks == 0 || BlockLength == 0) { + return EFI_INVALID_PARAMETER; + } + + NextLba = StartLba + NumBlocks; + + // + // The map entry found + // + if (Lba >= StartLba && Lba < NextLba) { + Offset = Offset + (UINTN) MultU64x32 ((Lba - StartLba), BlockLength); + if (LbaAddress) { + *LbaAddress = FwhInstance->FvBase[Virtual] + Offset; + } + + if (LbaWriteAddress) { + *LbaWriteAddress = FwhInstance->FvWriteBase[Virtual] + Offset; + } + + if (LbaLength) { + *LbaLength = BlockLength; + } + + if (NumOfBlocks) { + *NumOfBlocks = (UINTN) (NextLba - Lba); + } + + return EFI_SUCCESS; + } + + StartLba = NextLba; + Offset = Offset + NumBlocks * BlockLength; + BlockMap++; + } +} + +EFI_STATUS +FvbReadBlock ( + IN UINTN Instance, + IN EFI_LBA Lba, + IN UINTN BlockOffset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +/*++ + +Routine Description: + Reads specified number of bytes into a buffer from the specified block + +Arguments: + Instance - The FV instance to be read from + Lba - The logical block address to be read from + BlockOffset - Offset into the block at which to begin reading + NumBytes - Pointer that on input contains the total size of + the buffer. On output, it contains the total number + of bytes read + Buffer - Pointer to a caller allocated buffer that will be + used to hold the data read + Global - Pointer to ESAL_FWB_GLOBAL that contains all + instance data + Virtual - Whether CPU is in virtual or physical mode + +Returns: + EFI_SUCCESS - The firmware volume was read successfully and + contents are in Buffer + EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output, + NumBytes contains the total number of bytes returned + in Buffer + EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state + EFI_DEVICE_ERROR - The block device is not functioning correctly and + could not be read + EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL + +--*/ +{ + EFI_FVB_ATTRIBUTES Attributes; + UINTN LbaAddress; + UINTN LbaLength; + EFI_STATUS Status; + + // + // Check for invalid conditions + // + if ((NumBytes == NULL) || (Buffer == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (*NumBytes == 0) { + return EFI_INVALID_PARAMETER; + } + + Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, NULL, &LbaLength, NULL, Global, Virtual); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Check if the FV is read enabled + // + FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual); + + if ((Attributes & EFI_FVB_READ_STATUS) == 0) { + return EFI_ACCESS_DENIED; + } + // + // Perform boundary checks and adjust NumBytes + // + if (BlockOffset > LbaLength) { + return EFI_INVALID_PARAMETER; + } + + if (LbaLength < (*NumBytes + BlockOffset)) { + *NumBytes = (UINT32) (LbaLength - BlockOffset); + Status = EFI_BAD_BUFFER_SIZE; + } + + EfiMemRead (EfiCpuIoWidthUint8, LbaAddress + BlockOffset, (UINTN) *NumBytes, Buffer); + + return Status; +} + +EFI_STATUS +FlashFdWrite ( + IN UINTN WriteAddress, + IN UINTN Address, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer, + IN UINTN LbaLength + ) +/*++ + +Routine Description: + Writes specified number of bytes from the input buffer to the address + +Arguments: + +Returns: + +--*/ +{ + UINT8 *Src; + UINT8 *Dest; + UINTN Count; + EFI_STATUS Status; + UINT8 HubCommand; + UINT8 HubData; + UINTN RetryTimes; + + Status = EFI_SUCCESS; + + EnableFvbWrites (TRUE); + + // + // Grab the lock before entering critical code section + // + // bugbug + // Commented out since locking mechanisium is not correctly implemented + // on IA32 so that it will assert in runtime environment. + // + // EfiAcquireLock(&(FwhInstance->FvbDevLock)); + // + // Write data one byte at a time, don't write if the src and dest bytes match + // + Dest = (UINT8 *) WriteAddress; + Src = Buffer; + + for (Count = 0; Count < *NumBytes; Count++, Dest++, Src++) { + + HubCommand = FWH_WRITE_SETUP_COMMAND; + FvbMemWrite8 ((UINT64) ((UINTN) Dest), HubCommand); + FvbMemWrite8 ((UINT64) ((UINTN) Dest), *Src); + HubCommand = FWH_READ_STATUS_COMMAND; + FvbMemWrite8 ((UINT64) ((UINTN) Dest), HubCommand); + + // + // Device error if time out occurs + // + RetryTimes = 0; + while (RetryTimes < FVB_MAX_RETRY_TIMES) { + EfiMemRead (EfiCpuIoWidthUint8, (UINT64) ((UINTN) Dest), 0x1, &HubData); + if (HubData & FWH_WRITE_STATE_STATUS) { + break; + } + + RetryTimes++; + } + + if (RetryTimes >= FVB_MAX_RETRY_TIMES) { + *NumBytes = Count; + Status = EFI_DEVICE_ERROR; + break; + } + } + // + // Clear status register + // + HubCommand = FWH_CLEAR_STATUS_COMMAND; + FvbMemWrite8 ((UINT64) ((UINTN) Dest), HubCommand); + + // + // Issue read array command to return the FWH state machine to the + // normal operational state + // + HubCommand = FWH_READ_ARRAY_COMMAND; + FvbMemWrite8 ((UINT64) ((UINTN) WriteAddress), HubCommand); + // + // Flush the changed area to make the cache consistent + // + EfiCpuFlushCache (WriteAddress, *NumBytes); + + // + // End of critical code section, release lock. + // + // EfiReleaseLock(&(FwhInstance->FvbDevLock)); + // + EnableFvbWrites (FALSE); + + return Status; +} + +EFI_STATUS +FlashFdErase ( + IN UINTN WriteAddress, + IN UINTN Address, + IN UINTN LbaLength + ) +/*++ + +Routine Description: + Erase a certain block from address LbaWriteAddress + +Arguments: + +Returns: + +--*/ +{ + EFI_STATUS Status; + UINT8 HubCommand; + UINT8 HubData; + UINTN RetryTimes; + + Status = EFI_SUCCESS; + + EnableFvbWrites (TRUE); + + // + // Grab the lock before entering critical code section + // + // EfiAcquireLock(&(FwhInstance->FvbDevLock)); + // + // Send erase commands to FWH + // + HubCommand = FWH_BLOCK_ERASE_SETUP_COMMAND; + FvbMemWrite8 ((UINT64) WriteAddress, HubCommand); + HubCommand = FWH_BLOCK_ERASE_CONFIRM_COMMAND; + FvbMemWrite8 ((UINT64) WriteAddress, HubCommand); + HubCommand = FWH_READ_STATUS_COMMAND; + FvbMemWrite8 ((UINT64) WriteAddress, HubCommand); + + // + // Wait for completion. Indicated by FWH_WRITE_STATE_STATUS bit becoming 0 + // Device error if time out occurs + // + RetryTimes = 0; + while (RetryTimes < FVB_MAX_RETRY_TIMES) { + EfiMemRead (EfiCpuIoWidthUint8, (UINT64) WriteAddress, 0x1, &HubData); + if (HubData & FWH_WRITE_STATE_STATUS) { + break; + } + + RetryTimes++; + } + + if (RetryTimes >= FVB_MAX_RETRY_TIMES) { + Status = EFI_DEVICE_ERROR; + } + // + // Clear status register + // + HubCommand = FWH_CLEAR_STATUS_COMMAND; + FvbMemWrite8 ((UINT64) WriteAddress, HubCommand); + + // + // Issue read array command to return the FWH state machine to the normal op state + // + HubCommand = FWH_READ_ARRAY_COMMAND; + FvbMemWrite8 ((UINT64) ((UINTN) WriteAddress), HubCommand); + + EfiCpuFlushCache (Address, LbaLength); + + // + // End of critical code section, release lock. + // + // EfiReleaseLock(&(FwhInstance->FvbDevLock)); + // + EnableFvbWrites (FALSE); + + return Status; +} + +EFI_STATUS +FvbWriteBlock ( + IN UINTN Instance, + IN EFI_LBA Lba, + IN UINTN BlockOffset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +/*++ + +Routine Description: + Writes specified number of bytes from the input buffer to the block + +Arguments: + Instance - The FV instance to be written to + Lba - The starting logical block index to write to + BlockOffset - Offset into the block at which to begin writing + NumBytes - Pointer that on input contains the total size of + the buffer. On output, it contains the total number + of bytes actually written + Buffer - Pointer to a caller allocated buffer that contains + the source for the write + Global - Pointer to ESAL_FWB_GLOBAL that contains all + instance data + Virtual - Whether CPU is in virtual or physical mode + +Returns: + EFI_SUCCESS - The firmware volume was written successfully + EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output, + NumBytes contains the total number of bytes + actually written + EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state + EFI_DEVICE_ERROR - The block device is not functioning correctly and + could not be written + EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL + +--*/ +{ + EFI_FVB_ATTRIBUTES Attributes; + UINTN LbaAddress; + UINTN LbaWriteAddress; + UINTN LbaLength; + EFI_FW_VOL_INSTANCE *FwhInstance; + EFI_STATUS Status; + EFI_STATUS ReturnStatus; + + // + // Find the right instance of the FVB private data + // + Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual); + ASSERT_EFI_ERROR (Status); + + // + // Writes are enabled in the init routine itself + // + if (!FwhInstance->WriteEnabled) { + return EFI_ACCESS_DENIED; + } + // + // Check for invalid conditions + // + if ((NumBytes == NULL) || (Buffer == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (*NumBytes == 0) { + return EFI_INVALID_PARAMETER; + } + + Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaWriteAddress, &LbaLength, NULL, Global, Virtual); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Check if the FV is write enabled + // + FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual); + + if ((Attributes & EFI_FVB_WRITE_STATUS) == 0) { + return EFI_ACCESS_DENIED; + } + // + // Perform boundary checks and adjust NumBytes + // + if (BlockOffset > LbaLength) { + return EFI_INVALID_PARAMETER; + } + + if (LbaLength < (*NumBytes + BlockOffset)) { + *NumBytes = (UINT32) (LbaLength - BlockOffset); + Status = EFI_BAD_BUFFER_SIZE; + } + + ReturnStatus = FlashFdWrite ( + LbaWriteAddress + BlockOffset, + LbaAddress, + NumBytes, + Buffer, + LbaLength + ); + if (EFI_ERROR (ReturnStatus)) { + return ReturnStatus; + } + + return Status; +} + +EFI_STATUS +FvbEraseBlock ( + IN UINTN Instance, + IN EFI_LBA Lba, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +/*++ + +Routine Description: + Erases and initializes a firmware volume block + +Arguments: + Instance - The FV instance to be erased + Lba - The logical block index to be erased + Global - Pointer to ESAL_FWB_GLOBAL that contains all + instance data + Virtual - Whether CPU is in virtual or physical mode + +Returns: + EFI_SUCCESS - The erase request was successfully completed + EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state + EFI_DEVICE_ERROR - The block device is not functioning correctly and + could not be written. Firmware device may have been + partially erased + EFI_INVALID_PARAMETER - Instance not found + +--*/ +{ + + EFI_FVB_ATTRIBUTES Attributes; + UINTN LbaAddress; + UINTN LbaWriteAddress; + EFI_FW_VOL_INSTANCE *FwhInstance; + UINTN LbaLength; + EFI_STATUS Status; + + // + // Find the right instance of the FVB private data + // + Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual); + ASSERT_EFI_ERROR (Status); + + // + // Writes are enabled in the init routine itself + // + if (!FwhInstance->WriteEnabled) { + return EFI_ACCESS_DENIED; + } + // + // Check if the FV is write enabled + // + FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual); + + if ((Attributes & EFI_FVB_WRITE_STATUS) == 0) { + return EFI_ACCESS_DENIED; + } + // + // Get the starting address of the block for erase. For debug reasons, + // LbaWriteAddress may not be the same as LbaAddress. + // + Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaWriteAddress, &LbaLength, NULL, Global, Virtual); + if (EFI_ERROR (Status)) { + return Status; + } + + return FlashFdErase ( + LbaWriteAddress, + LbaAddress, + LbaLength + ); +} + +EFI_STATUS +FvbEraseCustomBlockRange ( + IN UINTN Instance, + IN EFI_LBA StartLba, + IN UINTN OffsetStartLba, + IN EFI_LBA LastLba, + IN UINTN OffsetLastLba, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +/*++ + +Routine Description: + Erases and initializes a specified range of a firmware volume + +Arguments: + Instance - The FV instance to be erased + StartLba - The starting logical block index to be erased + OffsetStartLba - Offset into the starting block at which to + begin erasing + LastLba - The last logical block index to be erased + OffsetStartLba - Offset into the last block at which to end erasing + Global - Pointer to ESAL_FWB_GLOBAL that contains all + instance data + Virtual - Whether CPU is in virtual or physical mode + +Returns: + EFI_SUCCESS - The firmware volume was erased successfully + EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state + EFI_DEVICE_ERROR - The block device is not functioning correctly and + could not be written. Firmware device may have been + partially erased + EFI_INVALID_PARAMETER - Instance not found + +--*/ +{ + EFI_LBA Index; + UINTN LbaSize; + UINTN ScratchLbaSizeData; + + // + // First LBA. + // + FvbGetLbaAddress (Instance, StartLba, NULL, NULL, &LbaSize, NULL, Global, Virtual); + + // + // Use the scratch space as the intermediate buffer to transfer data + // Back up the first LBA in scratch space. + // + FvbReadBlock (Instance, StartLba, 0, &LbaSize, Global->FvbScratchSpace[Virtual], Global, Virtual); + + // + // erase now + // + FvbEraseBlock (Instance, StartLba, Global, Virtual); + ScratchLbaSizeData = OffsetStartLba; + + // + // write the data back to the first block + // + if (ScratchLbaSizeData > 0) { + FvbWriteBlock (Instance, StartLba, 0, &ScratchLbaSizeData, Global->FvbScratchSpace[Virtual], Global, Virtual); + } + // + // Middle LBAs + // + if (LastLba > (StartLba + 1)) { + for (Index = (StartLba + 1); Index <= (LastLba - 1); Index++) { + FvbEraseBlock (Instance, Index, Global, Virtual); + } + } + // + // Last LBAs, the same as first LBAs + // + if (LastLba > StartLba) { + FvbGetLbaAddress (Instance, LastLba, NULL, NULL, &LbaSize, NULL, Global, Virtual); + FvbReadBlock (Instance, LastLba, 0, &LbaSize, Global->FvbScratchSpace[Virtual], Global, Virtual); + FvbEraseBlock (Instance, LastLba, Global, Virtual); + } + + ScratchLbaSizeData = LbaSize - (OffsetStartLba + 1); + + return FvbWriteBlock ( + Instance, + LastLba, + (OffsetLastLba + 1), + &ScratchLbaSizeData, + Global->FvbScratchSpace[Virtual], + Global, + Virtual + ); +} + +EFI_STATUS +FvbSetVolumeAttributes ( + IN UINTN Instance, + IN OUT EFI_FVB_ATTRIBUTES *Attributes, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +/*++ + +Routine Description: + Modifies the current settings of the firmware volume according to the + input parameter, and returns the new setting of the volume + +Arguments: + Instance - The FV instance whose attributes is going to be + modified + Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES + containing the desired firmware volume settings. + On successful return, it contains the new settings + of the firmware volume + Global - Pointer to ESAL_FWB_GLOBAL that contains all + instance data + Virtual - Whether CPU is in virtual or physical mode + +Returns: + EFI_SUCCESS - Successfully returns + EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified + EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are + in conflict with the capabilities as declared in the + firmware volume header + +--*/ +{ + EFI_FW_VOL_INSTANCE *FwhInstance; + EFI_FVB_ATTRIBUTES OldAttributes; + EFI_FVB_ATTRIBUTES *AttribPtr; + UINT32 Capabilities; + UINT32 OldStatus; + UINT32 NewStatus; + EFI_STATUS Status; + + // + // Find the right instance of the FVB private data + // + Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual); + ASSERT_EFI_ERROR (Status); + + AttribPtr = (EFI_FVB_ATTRIBUTES *) &(FwhInstance->VolumeHeader.Attributes); + OldAttributes = *AttribPtr; + Capabilities = OldAttributes & EFI_FVB_CAPABILITIES; + OldStatus = OldAttributes & EFI_FVB_STATUS; + NewStatus = *Attributes & EFI_FVB_STATUS; + + // + // If firmware volume is locked, no status bit can be updated + // + if (OldAttributes & EFI_FVB_LOCK_STATUS) { + if (OldStatus ^ NewStatus) { + return EFI_ACCESS_DENIED; + } + } + // + // Test read disable + // + if ((Capabilities & EFI_FVB_READ_DISABLED_CAP) == 0) { + if ((NewStatus & EFI_FVB_READ_STATUS) == 0) { + return EFI_INVALID_PARAMETER; + } + } + // + // Test read enable + // + if ((Capabilities & EFI_FVB_READ_ENABLED_CAP) == 0) { + if (NewStatus & EFI_FVB_READ_STATUS) { + return EFI_INVALID_PARAMETER; + } + } + // + // Test write disable + // + if ((Capabilities & EFI_FVB_WRITE_DISABLED_CAP) == 0) { + if ((NewStatus & EFI_FVB_WRITE_STATUS) == 0) { + return EFI_INVALID_PARAMETER; + } + } + // + // Test write enable + // + if ((Capabilities & EFI_FVB_WRITE_ENABLED_CAP) == 0) { + if (NewStatus & EFI_FVB_WRITE_STATUS) { + return EFI_INVALID_PARAMETER; + } + } + // + // Test lock + // + if ((Capabilities & EFI_FVB_LOCK_CAP) == 0) { + if (NewStatus & EFI_FVB_LOCK_STATUS) { + return EFI_INVALID_PARAMETER; + } + } + + *AttribPtr = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB_STATUS)); + *AttribPtr = (*AttribPtr) | NewStatus; + *Attributes = *AttribPtr; + + return EFI_SUCCESS; +} +// +// FVB protocol APIs +// +EFI_STATUS +EFIAPI +FvbProtocolGetPhysicalAddress ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_PHYSICAL_ADDRESS *Address + ) +/*++ + +Routine Description: + + Retrieves the physical address of the device. + +Arguments: + + This - Calling context + Address - Output buffer containing the address. + +Returns: + +Returns: + EFI_SUCCESS - Successfully returns + +--*/ +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + + return FvbGetPhysicalAddress (FvbDevice->Instance, Address, mFvbModuleGlobal, EfiGoneVirtual ()); +} + +EFI_STATUS +EFIAPI +FvbProtocolGetBlockSize ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + OUT UINTN *BlockSize, + OUT UINTN *NumOfBlocks + ) +/*++ + +Routine Description: + Retrieve the size of a logical block + +Arguments: + This - Calling context + Lba - Indicates which block to return the size for. + BlockSize - A pointer to a caller allocated UINTN in which + the size of the block is returned + NumOfBlocks - a 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 + +Returns: + EFI_SUCCESS - The firmware volume was read successfully and + contents are in Buffer + +--*/ +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + + return FvbGetLbaAddress ( + FvbDevice->Instance, + Lba, + NULL, + NULL, + BlockSize, + NumOfBlocks, + mFvbModuleGlobal, + EfiGoneVirtual () + ); +} + +EFI_STATUS +EFIAPI +FvbProtocolGetAttributes ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_FVB_ATTRIBUTES *Attributes + ) +/*++ + +Routine Description: + Retrieves Volume attributes. No polarity translations are done. + +Arguments: + This - Calling context + Attributes - output buffer which contains attributes + +Returns: + EFI_SUCCESS - Successfully returns + +--*/ +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + + return FvbGetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ()); +} + +EFI_STATUS +EFIAPI +FvbProtocolSetAttributes ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN OUT EFI_FVB_ATTRIBUTES *Attributes + ) +/*++ + +Routine Description: + Sets Volume attributes. No polarity translations are done. + +Arguments: + This - Calling context + Attributes - output buffer which contains attributes + +Returns: + EFI_SUCCESS - Successfully returns + +--*/ +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + + return FvbSetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ()); +} + +EFI_STATUS +EFIAPI +FvbProtocolEraseBlocks ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + ... + ) +/*++ + +Routine Description: + + 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. + +Arguments: + This - Calling context + ... - Starting LBA followed by Number of Lba to erase. + a -1 to terminate the list. + +Returns: + EFI_SUCCESS - The erase request was successfully completed + EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state + EFI_DEVICE_ERROR - The block device is not functioning correctly and + could not be written. Firmware device may have been + partially erased + +--*/ +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + EFI_FW_VOL_INSTANCE *FwhInstance; + UINTN NumOfBlocks; + VA_LIST args; + EFI_LBA StartingLba; + UINTN NumOfLba; + EFI_STATUS Status; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + + Status = GetFvbInstance (FvbDevice->Instance, mFvbModuleGlobal, &FwhInstance, EfiGoneVirtual ()); + ASSERT_EFI_ERROR (Status); + + NumOfBlocks = FwhInstance->NumOfBlocks; + + VA_START (args, This); + + do { + StartingLba = VA_ARG (args, EFI_LBA); + if (StartingLba == EFI_LBA_LIST_TERMINATOR) { + break; + } + + NumOfLba = VA_ARG (args, UINT32); + + // + // Check input parameters + // + if ((NumOfLba == 0) || ((StartingLba + NumOfLba) > NumOfBlocks)) { + VA_END (args); + return EFI_INVALID_PARAMETER; + } + } while (1); + + VA_END (args); + + VA_START (args, This); + do { + StartingLba = VA_ARG (args, EFI_LBA); + if (StartingLba == EFI_LBA_LIST_TERMINATOR) { + break; + } + + NumOfLba = VA_ARG (args, UINT32); + + while (NumOfLba > 0) { + Status = FvbEraseBlock (FvbDevice->Instance, StartingLba, mFvbModuleGlobal, EfiGoneVirtual ()); + if (EFI_ERROR (Status)) { + VA_END (args); + return Status; + } + + StartingLba++; + NumOfLba--; + } + + } while (1); + + VA_END (args); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +FvbProtocolWrite ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +/*++ + +Routine Description: + + Writes data beginning at Lba:Offset from FV. The write terminates either + when *NumBytes of data have been written, or when a block boundary is + reached. *NumBytes is updated to reflect the actual number of bytes + written. The write opertion does not include erase. This routine will + attempt to write only the specified bytes. If the writes do not stick, + it will return an error. + +Arguments: + This - Calling context + Lba - Block in which to begin write + Offset - Offset in the block at which to begin write + NumBytes - On input, indicates the requested write size. On + output, indicates the actual number of bytes written + Buffer - Buffer containing source data for the write. + +Returns: + EFI_SUCCESS - The firmware volume was written successfully + EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output, + NumBytes contains the total number of bytes + actually written + EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state + EFI_DEVICE_ERROR - The block device is not functioning correctly and + could not be written + EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL + +--*/ +{ + + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + + return FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ()); +} + +EFI_STATUS +EFIAPI +FvbProtocolRead ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +/*++ + +Routine Description: + + Reads data beginning at Lba:Offset from FV. The Read terminates either + when *NumBytes of data have been read, or when a block boundary is + reached. *NumBytes is updated to reflect the actual number of bytes + written. The write opertion does not include erase. This routine will + attempt to write only the specified bytes. If the writes do not stick, + it will return an error. + +Arguments: + This - Calling context + Lba - Block in which to begin Read + Offset - Offset in the block at which to begin Read + NumBytes - On input, indicates the requested write size. On + output, indicates the actual number of bytes Read + Buffer - Buffer containing source data for the Read. + +Returns: + EFI_SUCCESS - The firmware volume was read successfully and + contents are in Buffer + EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output, + NumBytes contains the total number of bytes returned + in Buffer + EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state + EFI_DEVICE_ERROR - The block device is not functioning correctly and + could not be read + EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL + +--*/ +{ + + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + + return FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ()); +} +// +// FVB Extension Protocols +// +EFI_STATUS +EFIAPI +FvbExtendProtocolEraseCustomBlockRange ( + IN EFI_FVB_EXTENSION_PROTOCOL *This, + IN EFI_LBA StartLba, + IN UINTN OffsetStartLba, + IN EFI_LBA LastLba, + IN UINTN OffsetLastLba + ) +/*++ + +Routine Description: + Erases and initializes a specified range of a firmware volume + +Arguments: + This - Calling context + StartLba - The starting logical block index to be erased + OffsetStartLba - Offset into the starting block at which to + begin erasing + LastLba - The last logical block index to be erased + OffsetStartLba - Offset into the last block at which to end erasing + +Returns: + EFI_SUCCESS - The firmware volume was erased successfully + EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state + EFI_DEVICE_ERROR - The block device is not functioning correctly and + could not be written. Firmware device may have been + partially erased + +--*/ +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + + FvbDevice = FVB_EXTEND_DEVICE_FROM_THIS (This); + + return FvbEraseCustomBlockRange ( + FvbDevice->Instance, + StartLba, + OffsetStartLba, + LastLba, + OffsetLastLba, + mFvbModuleGlobal, + EfiGoneVirtual () + ); +} + +STATIC +EFI_STATUS +ValidateFvHeader ( + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader + ) +/*++ + +Routine Description: + Check the integrity of firmware volume header + +Arguments: + FwVolHeader - A pointer to a firmware volume header + +Returns: + EFI_SUCCESS - The firmware volume is consistent + EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV + +--*/ +{ + UINT16 *Ptr; + UINT16 HeaderLength; + UINT16 Checksum; + + // + // Verify the header revision, header signature, length + // Length of FvBlock cannot be 2**64-1 + // HeaderLength cannot be an odd number + // + if ((FwVolHeader->Revision != EFI_FVH_REVISION) || + (FwVolHeader->Signature != EFI_FVH_SIGNATURE) || + (FwVolHeader->FvLength == ((UINTN) -1)) || + ((FwVolHeader->HeaderLength & 0x01) != 0) + ) { + return EFI_NOT_FOUND; + } + // + // Verify the header checksum + // + HeaderLength = (UINT16) (FwVolHeader->HeaderLength / 2); + Ptr = (UINT16 *) FwVolHeader; + Checksum = 0; + while (HeaderLength > 0) { + Checksum = *Ptr++; + HeaderLength--; + } + + if (Checksum != 0) { + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} + +BOOLEAN +FvbGetCfiSupported ( + IN UINTN LbaAddress + ) +/*++ + +Routine Description: + Check if the firmware volume is CFI typed flash + +Arguments: + LbaAddress - The physical address of the firmware volume + +Returns: + TRUE - CFI supported + FALSE - CFI un-supported + +--*/ +{ + UINT8 HubData[8]; + UINT8 HubCommand; + BOOLEAN Supported; + + Supported = TRUE; + + // + // Issue CFI Query (98h) to address 55h + // + HubCommand = CFI_QUERY; + FvbMemWrite8 ((LbaAddress + 0x55), HubCommand); + // + // x8 device in 8-bit mode? + // + EfiMemRead (EfiCpuIoWidthUint8, (LbaAddress + 0x10), 0x3, &HubData); + if (!EfiCompareMem (HubData, "QRY", 3)) { + goto Done; + } + // + // paired x8 devices? + // + EfiMemRead (EfiCpuIoWidthUint8, (LbaAddress + 0x20), 0x6, &HubData); + if (!EfiCompareMem (HubData, "QQRRYY", 6)) { + goto Done; + } + // + // x16 device in 16-bit mode? + // + EfiMemRead (EfiCpuIoWidthUint8, (LbaAddress + 0x20), 0x4, &HubData); + if ((!EfiCompareMem (&HubData[0], "R", 2)) && (!EfiCompareMem (&HubData[2], "Q", 2))) { + goto Done; + } + // + // x16 device in 8-bit mode? + // + EfiMemRead (EfiCpuIoWidthUint8, (LbaAddress + 0x20), 0x3, &HubData); + if (!EfiCompareMem (HubData, "QQR", 3)) { + goto Done; + } + // + // 2 x16 devices in 8-bit mode (paired chip configuration)? + // + EfiMemRead (EfiCpuIoWidthUint8, (LbaAddress + 0x40), 0x6, &HubData); + if (!EfiCompareMem (HubData, "QQQQRR", 6)) { + goto Done; + } + // + // x32 device in 8-bit mode + // + EfiMemRead (EfiCpuIoWidthUint8, (LbaAddress + 0x40), 0x5, &HubData); + if (!EfiCompareMem (HubData, "QQQQR", 5)) { + goto Done; + } + // + // x32 device in 32-bit mode + // + if ((!EfiCompareMem (&HubData[0], "R", 2)) && (((UINT16) HubData[2]) == 0) && (HubData[4] == 'Q')) { + goto Done; + } + // + // If it got to here, CFI is not supported + // + Supported = FALSE; + +Done: + // + // Bug Fix #4071: + // Issue command FWH_READ_ARRAY_COMMAND (0xff) at the end of this service to + // guarantee that the FWH is back in read mode again + // + HubCommand = FWH_READ_ARRAY_COMMAND; + FvbMemWrite8 (LbaAddress, HubCommand); + + return Supported; +} + +EFI_STATUS +GetFvbHeader ( + VOID **HobList, + EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader, + EFI_PHYSICAL_ADDRESS *BaseAddress, + BOOLEAN *WriteBack + ) +{ + EFI_STATUS Status; + VOID *Buffer; + EFI_FLASH_MAP_ENTRY_DATA *FlashMapEntry; + EFI_FLASH_SUBAREA_ENTRY *FlashMapSubEntry; + + Status = EFI_SUCCESS; + *FwVolHeader = NULL; + *WriteBack = FALSE; + + Status = GetNextGuidHob (HobList, &gEfiFlashMapHobGuid, &Buffer, NULL); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + FlashMapEntry = (EFI_FLASH_MAP_ENTRY_DATA *) Buffer; + FlashMapSubEntry = &FlashMapEntry->Entries[0]; + // + // Check if it is a "FVB" area + // + if (!EfiCompareGuid (&FlashMapSubEntry->FileSystem, &gEfiFirmwareVolumeBlockProtocolGuid)) { + return Status; + } + // + // Check if it is a "real" flash + // + if (FlashMapSubEntry->Attributes != (EFI_FLASH_AREA_FV | EFI_FLASH_AREA_MEMMAPPED_FV)) { + return Status; + } + + *BaseAddress = FlashMapSubEntry->Base; + DEBUG ((EFI_D_ERROR, "FlashMap HOB: BaseAddress = 0x%lx\n", *BaseAddress)); + + *FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (*BaseAddress); + Status = ValidateFvHeader (*FwVolHeader); + if (EFI_ERROR (Status)) { + // + // Get FvbInfo + // + *WriteBack = TRUE; + DEBUG ((EFI_D_ERROR, "BaseAddress = 0x%lx\n", BaseAddress)); + Status = GetFvbInfo (*BaseAddress, FwVolHeader); + DEBUG ((EFI_D_ERROR, "Fvb: FV header invalid, GetFvbInfo - %r\n", Status)); + ASSERT_EFI_ERROR (Status); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +FvbInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + This function does common initialization for FVB services + +Arguments: + +Returns: + +--*/ +{ + EFI_STATUS Status; + EFI_FW_VOL_INSTANCE *FwhInstance; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + VOID *HobList; + VOID *FirmwareVolumeHobList; + UINT32 BufferSize; + EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry; + UINTN LbaAddress; + UINT8 Data; + UINTN BlockIndex2; + BOOLEAN WriteEnabled; + BOOLEAN WriteLocked; + EFI_HANDLE FwbHandle; + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *OldFwbInterface; + EFI_DEVICE_PATH_PROTOCOL *TempFwbDevicePath; + FV_DEVICE_PATH TempFvbDevicePathData; + UINT32 MaxLbaSize; + BOOLEAN CfiEnabled; + EFI_PHYSICAL_ADDRESS BaseAddress; + BOOLEAN WriteBack; + UINTN NumOfBlocks; + UINTN HeaderLength; + + INITIALIZE_SCRIPT (ImageHandle, SystemTable); + + EfiInitializeRuntimeDriverLib (ImageHandle, SystemTable, FvbVirtualddressChangeEvent); + + Status = EfiGetSystemConfigurationTable (&gEfiHobListGuid, &HobList); + HeaderLength = 0; + // + // No FV HOBs found + // + ASSERT_EFI_ERROR (Status); + + // + // Allocate runtime services data for global variable, which contains + // the private data of all firmware volume block instances + // + Status = gBS->AllocatePool ( + EfiRuntimeServicesData, + sizeof (ESAL_FWB_GLOBAL), + &mFvbModuleGlobal + ); + ASSERT_EFI_ERROR (Status); + + EnablePlatformFvb (); + EnableFvbWrites (TRUE); + + // + // Calculate the total size for all firmware volume block instances + // + BufferSize = 0; + FirmwareVolumeHobList = HobList; + do { + Status = GetFvbHeader (&FirmwareVolumeHobList, &FwVolHeader, &BaseAddress, &WriteBack); + if (EFI_ERROR (Status)) { + break; + } + + if (FwVolHeader) { + BufferSize += (FwVolHeader->HeaderLength + sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)); + } + } while (TRUE); + + // + // Only need to allocate once. There is only one copy of physical memory for + // the private data of each FV instance. But in virtual mode or in physical + // mode, the address of the the physical memory may be different. + // + Status = gBS->AllocatePool ( + EfiRuntimeServicesData, + BufferSize, + &mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] + ); + ASSERT_EFI_ERROR (Status); + + // + // Make a virtual copy of the FvInstance pointer. + // + FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]; + mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] = FwhInstance; + + mFvbModuleGlobal->NumFv = 0; + FirmwareVolumeHobList = HobList; + + MaxLbaSize = 0; + + // + // Fill in the private data of each firmware volume block instance + // + do { + Status = GetFvbHeader (&FirmwareVolumeHobList, &FwVolHeader, &BaseAddress, &WriteBack); + if (EFI_ERROR (Status)) { + break; + } + + if (!FwVolHeader) { + continue; + } + + EfiCopyMem ((UINTN *) &(FwhInstance->VolumeHeader), (UINTN *) FwVolHeader, FwVolHeader->HeaderLength); + FwVolHeader = &(FwhInstance->VolumeHeader); + + FwhInstance->FvBase[FVB_PHYSICAL] = (UINTN) BaseAddress; + FwhInstance->FvBase[FVB_VIRTUAL] = (UINTN) BaseAddress; + + // + // FwhInstance->FvWriteBase may not be the same as FwhInstance->FvBase + // + PlatformGetFvbWriteBase ( + (UINTN) BaseAddress, + (UINTN *) &(FwhInstance->FvWriteBase[FVB_PHYSICAL]), + &WriteEnabled + ); + // + // Every pointer should have a virtual copy. + // + FwhInstance->FvWriteBase[FVB_VIRTUAL] = FwhInstance->FvWriteBase[FVB_PHYSICAL]; + + FwhInstance->WriteEnabled = WriteEnabled; + EfiInitializeLock (&(FwhInstance->FvbDevLock), EFI_TPL_HIGH_LEVEL); + + LbaAddress = (UINTN) FwhInstance->FvWriteBase[0]; + NumOfBlocks = 0; + WriteLocked = FALSE; + + if (WriteEnabled) { + CfiEnabled = FvbGetCfiSupported (LbaAddress); + for (PtrBlockMapEntry = FwVolHeader->FvBlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) { + + for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) { + + if (SetPlatformFvbLock (LbaAddress)) { + // + // Clear all write-lock and read-lock HW bits + // For sync3, the software will enforce the protection + // + if (CfiEnabled) { + Data = CFI_BLOCK_LOCK_UNLOCK; + FvbMemWrite8 (LbaAddress, Data); + Data = CFI_BLOCK_UNLOCK_CONFIRM; + FvbMemWrite8 (LbaAddress, Data); + while (TRUE) { + EfiMemRead (EfiCpuIoWidthUint8, (LbaAddress + 2), 1, &Data); + if (Data & 0x80) { + break; + } + } + + Data = FWH_READ_ARRAY_COMMAND; + FvbMemWrite8 (LbaAddress, Data); + } else { + EfiMemRead (EfiCpuIoWidthUint8, (LbaAddress - 0x400000 + 2), 0x1, &Data); + // + // bugbug: lock down is block based, not FV based. Here we assume that + // the FV is locked if one of its block is locked + // + if ((Data & FWH_WRITE_LOCK) && (Data & FWH_LOCK_DOWN)) { + // + // the flash is locked and locked down + // + WriteLocked = TRUE; + } else { + Data &= ~(FWH_WRITE_LOCK | FWH_READ_LOCK | FWH_LOCK_DOWN); + + // + // Save boot script for S3 resume + // + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint8, + (UINT64) (LbaAddress - 0x400000 + 2), + 1, + &Data + ); + + FvbMemWrite8 ((LbaAddress - 0x400000 + 2), Data); + } + } + } + + LbaAddress += PtrBlockMapEntry->BlockLength; + } + // + // Get the maximum size of a block. The size will be used to allocate + // buffer for Scratch space, the intermediate buffer for FVB extension + // protocol + // + if (MaxLbaSize < PtrBlockMapEntry->BlockLength) { + MaxLbaSize = PtrBlockMapEntry->BlockLength; + } + + NumOfBlocks = NumOfBlocks + PtrBlockMapEntry->NumBlocks; + } + // + // Write back a healthy FV header + // + if (WriteBack && (!WriteLocked)) { + Status = FlashFdErase ( + (UINTN) FwhInstance->FvWriteBase[0], + (UINTN) BaseAddress, + FwVolHeader->FvBlockMap->BlockLength + ); + + HeaderLength = (UINTN) FwVolHeader->HeaderLength; + Status = FlashFdWrite ( + (UINTN) FwhInstance->FvWriteBase[0], + (UINTN) BaseAddress, + (UINTN *) &HeaderLength, + (UINT8 *) FwVolHeader, + FwVolHeader->FvBlockMap->BlockLength + ); + + FwVolHeader->HeaderLength = (UINT16) HeaderLength; + DEBUG ((EFI_D_ERROR, "Fvb: FV header invalid, write back - %r\n", Status)); + } + } + // + // The total number of blocks in the FV. + // + FwhInstance->NumOfBlocks = NumOfBlocks; + + // + // If the FV is write locked, set the appropriate attributes + // + if (WriteLocked) { + // + // write disabled + // + FwhInstance->VolumeHeader.Attributes &= ~EFI_FVB_WRITE_STATUS; + // + // lock enabled + // + FwhInstance->VolumeHeader.Attributes |= EFI_FVB_LOCK_STATUS; + } + // + // Add a FVB Protocol Instance + // + Status = gBS->AllocatePool ( + EfiRuntimeServicesData, + sizeof (EFI_FW_VOL_BLOCK_DEVICE), + &FvbDevice + ); + ASSERT_EFI_ERROR (Status); + + EfiCopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE)); + + FvbDevice->Instance = mFvbModuleGlobal->NumFv; + mFvbModuleGlobal->NumFv++; + + // + // Set up the devicepath + // + FvbDevice->DevicePath.MemMapDevPath.StartingAddress = BaseAddress; + FvbDevice->DevicePath.MemMapDevPath.EndingAddress = BaseAddress + (FwVolHeader->FvLength - 1); + + // + // Find a handle with a matching device path that has supports FW Block protocol + // + TempFwbDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &TempFvbDevicePathData; + EfiCopyMem (TempFwbDevicePath, &FvbDevice->DevicePath, sizeof (FV_DEVICE_PATH)); + Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &TempFwbDevicePath, &FwbHandle); + if (EFI_ERROR (Status)) { + // + // LocateDevicePath fails so install a new interface and device path + // + FwbHandle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &FwbHandle, + &gEfiFirmwareVolumeBlockProtocolGuid, + &FvbDevice->FwVolBlockInstance, + &gEfiDevicePathProtocolGuid, + &FvbDevice->DevicePath, + NULL + ); + ASSERT_EFI_ERROR (Status); + } else if (EfiIsDevicePathEnd (TempFwbDevicePath)) { + // + // Device allready exists, so reinstall the FVB protocol + // + Status = gBS->HandleProtocol ( + FwbHandle, + &gEfiFirmwareVolumeBlockProtocolGuid, + &OldFwbInterface + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->ReinstallProtocolInterface ( + FwbHandle, + &gEfiFirmwareVolumeBlockProtocolGuid, + OldFwbInterface, + &FvbDevice->FwVolBlockInstance + ); + ASSERT_EFI_ERROR (Status); + + } else { + // + // There was a FVB protocol on an End Device Path node + // + ASSERT (FALSE); + } + // + // Install FVB Extension Protocol on the same handle + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &FwbHandle, + &gEfiFvbExtensionProtocolGuid, + &FvbDevice->FvbExtension, + &gEfiAlternateFvBlockGuid, + NULL, + NULL + ); + + ASSERT_EFI_ERROR (Status); + + FwhInstance = (EFI_FW_VOL_INSTANCE *) + ( + (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength + + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)) + ); + } while (TRUE); + + // + // Allocate for scratch space, an intermediate buffer for FVB extention + // + Status = gBS->AllocatePool ( + EfiRuntimeServicesData, + MaxLbaSize, + &mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL] + ); + ASSERT_EFI_ERROR (Status); + + mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL] = mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL]; + + FvbSpecificInitialize (mFvbModuleGlobal); + + return EnableFvbWrites (FALSE); +} diff --git a/EdkNt32Pkg/RuntimeDxe/FvbServices/Common/FwBlockService.h b/EdkNt32Pkg/RuntimeDxe/FvbServices/Common/FwBlockService.h new file mode 100644 index 0000000000..1fad9bd6ba --- /dev/null +++ b/EdkNt32Pkg/RuntimeDxe/FvbServices/Common/FwBlockService.h @@ -0,0 +1,324 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FwBlockService.h + +Abstract: + + Firmware volume block driver for Intel Firmware Hub (FWH) device + +--*/ + +#ifndef _FW_BLOCK_SERVICE_H +#define _FW_BLOCK_SERVICE_H + +// +// Statements that include other header files +// +#include "Tiano.h" +#include "EfiFirmwareVolumeHeader.h" +#include "EfiRuntimeLib.h" +#include "EfiHobLib.h" +#include "EfiScriptLib.h" + +#include EFI_PROTOCOL_PRODUCER (FirmwareVolumeBlock) +#include EFI_PROTOCOL_PRODUCER (FvbExtension) +#include EFI_GUID_DEFINITION (AlternateFvBlock) +#include EFI_GUID_DEFINITION (Hob) +#include EFI_GUID_DEFINITION (DxeServices) +#include EFI_PROTOCOL_CONSUMER (CpuIo) + +#define FVB_MAX_RETRY_TIMES 10000000 +#define FWH_BLOCK_ERASE_SETUP_COMMAND 0x20 +#define FWH_BLOCK_ERASE_CONFIRM_COMMAND 0xd0 +#define FWH_READ_STATUS_COMMAND 0x70 +#define FWH_CLEAR_STATUS_COMMAND 0x50 +#define FWH_READ_ARRAY_COMMAND 0xff +#define FWH_WRITE_SETUP_COMMAND 0x40 +#define FWH_OPEN_FEATURE_SPACE_COMMAND 0x91 +#define FWH_READ_LOCK (1 << 2) +#define FWH_WRITE_LOCK (1 << 1) +#define FWH_LOCK_DOWN 1 +#define FWH_WRITE_STATE_STATUS (1 << 7) +#define FWH_ERASE_STATUS (1 << 5) +#define FWH_PROGRAM_STATUS (1 << 4) +#define FWH_VPP_STATUS (1 << 3) +#define STALL_TIME 5 +#define FWH_ERASE_STATUS_BITS (FWH_ERASE_STATUS || FWH_VPP_STATUS) +#define FWH_WRITE_STATUS_BITS (FWH_WRITE_STATUS || FWH_VPP_STATUS) +#define CFI_BLOCK_LOCK_UNLOCK 0x60 +#define CFI_BLOCK_LOCK_CONFIRM 1 +#define CFI_BLOCK_UNLOCK_CONFIRM 0xD0 +#define CFI_QUERY 0x98 + +// +// BugBug: Add documentation here for data structure!!!! +// +#define FVB_PHYSICAL 0 +#define FVB_VIRTUAL 1 + +typedef struct { + EFI_LOCK FvbDevLock; + UINTN FvBase[2]; + UINTN FvWriteBase[2]; + UINTN NumOfBlocks; + BOOLEAN WriteEnabled; + EFI_FIRMWARE_VOLUME_HEADER VolumeHeader; +} EFI_FW_VOL_INSTANCE; + +typedef struct { + UINT32 NumFv; + EFI_FW_VOL_INSTANCE *FvInstance[2]; + UINT8 *FvbScratchSpace[2]; +} ESAL_FWB_GLOBAL; + +// +// Fvb Protocol instance data +// +#define FVB_DEVICE_FROM_THIS(a) CR (a, EFI_FW_VOL_BLOCK_DEVICE, FwVolBlockInstance, FVB_DEVICE_SIGNATURE) +#define FVB_EXTEND_DEVICE_FROM_THIS(a) CR (a, EFI_FW_VOL_BLOCK_DEVICE, FvbExtension, FVB_DEVICE_SIGNATURE) +#define FVB_DEVICE_SIGNATURE EFI_SIGNATURE_32 ('F', 'V', 'B', 'C') + +typedef struct { + MEMMAP_DEVICE_PATH MemMapDevPath; + EFI_DEVICE_PATH_PROTOCOL EndDevPath; +} FV_DEVICE_PATH; + +typedef struct { + UINTN Signature; + FV_DEVICE_PATH DevicePath; + UINTN Instance; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL FwVolBlockInstance; + EFI_FVB_EXTENSION_PROTOCOL FvbExtension; +} EFI_FW_VOL_BLOCK_DEVICE; + +EFI_STATUS +GetFvbInfo ( + IN EFI_PHYSICAL_ADDRESS FvBaseAddress, + OUT EFI_FIRMWARE_VOLUME_HEADER **FvbInfo + ) +; + +EFI_STATUS +EnableFvbWrites ( + IN BOOLEAN EnableWrites + ) +; + +EFI_STATUS +PlatformGetFvbWriteBase ( + IN UINTN CurrentBaseAddress, + IN UINTN *NewBaseAddress, + IN BOOLEAN *WriteEnabled + ) +; + +EFI_STATUS +EnablePlatformFvb ( + VOID + ) +; + +BOOLEAN +SetPlatformFvbLock ( + IN UINTN LbaAddress + ) +; + +EFI_STATUS +FvbReadBlock ( + IN UINTN Instance, + IN EFI_LBA Lba, + IN UINTN BlockOffset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +; + +EFI_STATUS +FvbWriteBlock ( + IN UINTN Instance, + IN EFI_LBA Lba, + IN UINTN BlockOffset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +; + +EFI_STATUS +FvbEraseBlock ( + IN UINTN Instance, + IN EFI_LBA Lba, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +; + +EFI_STATUS +FvbSetVolumeAttributes ( + IN UINTN Instance, + IN OUT EFI_FVB_ATTRIBUTES *Attributes, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +; + +EFI_STATUS +FvbGetVolumeAttributes ( + IN UINTN Instance, + OUT EFI_FVB_ATTRIBUTES *Attributes, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +; + +EFI_STATUS +FvbGetPhysicalAddress ( + IN UINTN Instance, + OUT EFI_PHYSICAL_ADDRESS *Address, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +; + +EFI_STATUS +EFIAPI +FvbInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +; + + +VOID +EFIAPI +FvbClassAddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +; + +EFI_STATUS +FvbSpecificInitialize ( + IN ESAL_FWB_GLOBAL *mFvbModuleGlobal + ) +; + +EFI_STATUS +FvbGetLbaAddress ( + IN UINTN Instance, + IN EFI_LBA Lba, + OUT UINTN *LbaAddress, + OUT UINTN *LbaWriteAddress, + OUT UINTN *LbaLength, + OUT UINTN *NumOfBlocks, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +; + +EFI_STATUS +FvbEraseCustomBlockRange ( + IN UINTN Instance, + IN EFI_LBA StartLba, + IN UINTN OffsetStartLba, + IN EFI_LBA LastLba, + IN UINTN OffsetLastLba, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +; + +// +// Protocol APIs +// +EFI_STATUS +EFIAPI +FvbProtocolGetAttributes ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_FVB_ATTRIBUTES *Attributes + ) +; + +EFI_STATUS +EFIAPI +FvbProtocolSetAttributes ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN OUT EFI_FVB_ATTRIBUTES *Attributes + ) +; + +EFI_STATUS +EFIAPI +FvbProtocolGetPhysicalAddress ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_PHYSICAL_ADDRESS *Address + ) +; + +EFI_STATUS +EFIAPI +FvbProtocolGetBlockSize ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + OUT UINTN *BlockSize, + OUT UINTN *NumOfBlocks + ) +; + +EFI_STATUS +EFIAPI +FvbProtocolRead ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +; + +EFI_STATUS +EFIAPI +FvbProtocolWrite ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +; + +EFI_STATUS +EFIAPI +FvbProtocolEraseBlocks ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + ... + ) +; + +EFI_STATUS +EFIAPI +FvbExtendProtocolEraseCustomBlockRange ( + IN EFI_FVB_EXTENSION_PROTOCOL *This, + IN EFI_LBA StartLba, + IN UINTN OffsetStartLba, + IN EFI_LBA LastLba, + IN UINTN OffsetLastLba + ) +; + +#endif diff --git a/EdkNt32Pkg/RuntimeDxe/FvbServices/Common/ia32/Ia32Fwh.c b/EdkNt32Pkg/RuntimeDxe/FvbServices/Common/ia32/Ia32Fwh.c new file mode 100644 index 0000000000..00998f8c67 --- /dev/null +++ b/EdkNt32Pkg/RuntimeDxe/FvbServices/Common/ia32/Ia32Fwh.c @@ -0,0 +1,42 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Ia32Fwh.c + +Abstract: + +Revision History + +--*/ + +#include "FWBlockService.h" + +EFI_STATUS +FvbSpecificInitialize ( + IN ESAL_FWB_GLOBAL *mFvbModuleGlobal + ) +/*++ + +Routine Description: + Additional initialize code for IA32 platform. + +Arguments: + ESAL_FWB_GLOBAL - Global pointer that points to the instance data + +Returns: + EFI_SUCCESS + +--*/ +{ + return EFI_SUCCESS; +} diff --git a/EdkNt32Pkg/RuntimeDxe/FvbServices/Nt32Fwh.dxs b/EdkNt32Pkg/RuntimeDxe/FvbServices/Nt32Fwh.dxs new file mode 100644 index 0000000000..3cb311228e --- /dev/null +++ b/EdkNt32Pkg/RuntimeDxe/FvbServices/Nt32Fwh.dxs @@ -0,0 +1,27 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Nt32Fwh.dxs + +Abstract: + + Dependency expression source file. + +--*/ +#include +#include + + +DEPENDENCY_START + TRUE +DEPENDENCY_END \ No newline at end of file diff --git a/EdkNt32Pkg/RuntimeDxe/FvbServices/Nt32Fwh.mbd b/EdkNt32Pkg/RuntimeDxe/FvbServices/Nt32Fwh.mbd new file mode 100644 index 0000000000..7f83760ff2 --- /dev/null +++ b/EdkNt32Pkg/RuntimeDxe/FvbServices/Nt32Fwh.mbd @@ -0,0 +1,47 @@ + + + + + FwBlockService + BDFE5FAA-2A35-44bb-B17A-8084D4E2B9E9 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-14 17:04 + 2006-03-19 15:17 + + + UefiBootServicesTableLib + BaseLib + BaseMemoryLib + UefiLib + UefiDriverEntryPoint + DxeReportStatusCodeLib + DxeServicesTableLib + BaseDebugLibNull + EdkDxePrintLib + EdkDxeRuntimeDriverLib + DxeHobLib + DxeMemoryAllocationLib + + + _ModuleEntryPoint + + diff --git a/EdkNt32Pkg/RuntimeDxe/FvbServices/Nt32Fwh.msa b/EdkNt32Pkg/RuntimeDxe/FvbServices/Nt32Fwh.msa new file mode 100644 index 0000000000..711e4e4874 --- /dev/null +++ b/EdkNt32Pkg/RuntimeDxe/FvbServices/Nt32Fwh.msa @@ -0,0 +1,89 @@ + + + + + FwBlockService + DXE_RUNTIME_DRIVER + RT_DRIVER + BDFE5FAA-2A35-44bb-B17A-8084D4E2B9E9 + 0 + Component description file for DiskIo module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-14 17:04 + 2006-03-19 15:17 + + + UefiLib + UefiDriverEntryPoint + BaseLib + DxeServicesTableLib + DxeRuntimeDriverLib + DebugLib + HobLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + + + Nt32Fwh.dxs + + nt32\FwBlockService.c + nt32\FwBlockService.h + nt32\FvbInfo.c + + + + MdePkg + EdkModulePkg + EdkNt32Pkg + + + DevicePath + FirmwareVolumeBlock + FvbExtension + + + + + gEfiEventVirtualAddressChangeGuid + 0x13fa7698, 0xc831, 0x49c7, 0x87, 0xea, 0x8f, 0x43, 0xfc, 0xc2, 0x51, 0x96 + + + + + + + + + AlternateFvBlock + + + + + FvbInitialize + + + + + + + diff --git a/EdkNt32Pkg/RuntimeDxe/FvbServices/build.xml b/EdkNt32Pkg/RuntimeDxe/FvbServices/build.xml new file mode 100644 index 0000000000..60d06c448b --- /dev/null +++ b/EdkNt32Pkg/RuntimeDxe/FvbServices/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkNt32Pkg/RuntimeDxe/FvbServices/nt32/FWBlockService.c b/EdkNt32Pkg/RuntimeDxe/FvbServices/nt32/FWBlockService.c new file mode 100644 index 0000000000..1f2f8fd2b4 --- /dev/null +++ b/EdkNt32Pkg/RuntimeDxe/FvbServices/nt32/FWBlockService.c @@ -0,0 +1,1493 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FWBlockService.c + +Abstract: + +Revision History + +--*/ + +#include "FWBlockService.h" + +ESAL_FWB_GLOBAL *mFvbModuleGlobal; + +EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = { + FVB_DEVICE_SIGNATURE, + { + { + { + HARDWARE_DEVICE_PATH, + HW_MEMMAP_DP, + { + sizeof (MEMMAP_DEVICE_PATH), + 0 + } + }, + EfiMemoryMappedIO, + 0, + 0, + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + sizeof (EFI_DEVICE_PATH_PROTOCOL), + 0 + } + } + }, + 0, + { + FvbProtocolGetAttributes, + FvbProtocolSetAttributes, + FvbProtocolGetPhysicalAddress, + FvbProtocolGetBlockSize, + FvbProtocolRead, + FvbProtocolWrite, + FvbProtocolEraseBlocks, + NULL + }, + { + FvbExtendProtocolEraseCustomBlockRange + } +}; + + + +VOID +EFIAPI +FvbVirtualddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + + Fixup internal data so that EFI and SAL can be call in virtual mode. + Call the passed in Child Notify event and convert the mFvbModuleGlobal + date items to there virtual address. + + mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance data + mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common + instance data. + +Arguments: + + (Standard EFI notify event - EFI_EVENT_NOTIFY) + +Returns: + + None + +--*/ +{ + EFI_FW_VOL_INSTANCE *FwhInstance; + UINTN Index; + + EfiConvertPointer (0x0, (VOID **) &mFvbModuleGlobal->FvInstance[FVB_VIRTUAL]); + + // + // Convert the base address of all the instances + // + Index = 0; + FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]; + while (Index < mFvbModuleGlobal->NumFv) { + EfiConvertPointer (0x0, (VOID **) &FwhInstance->FvBase[FVB_VIRTUAL]); + FwhInstance = (EFI_FW_VOL_INSTANCE *) + ( + (UINTN) ((UINT8 *) FwhInstance) + FwhInstance->VolumeHeader.HeaderLength + + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)) + ); + Index++; + } + + EfiConvertPointer (0x0, (VOID **) &mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL]); + EfiConvertPointer (0x0, (VOID **) &mFvbModuleGlobal); +} + +EFI_STATUS +GetFvbInstance ( + IN UINTN Instance, + IN ESAL_FWB_GLOBAL *Global, + OUT EFI_FW_VOL_INSTANCE **FwhInstance, + IN BOOLEAN Virtual + ) +/*++ + +Routine Description: + Retrieves the physical address of a memory mapped FV + +Arguments: + Instance - The FV instance whose base address is going to be + returned + Global - Pointer to ESAL_FWB_GLOBAL that contains all + instance data + FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure + Virtual - Whether CPU is in virtual or physical mode + +Returns: + EFI_SUCCESS - Successfully returns + EFI_INVALID_PARAMETER - Instance not found + +--*/ +{ + EFI_FW_VOL_INSTANCE *FwhRecord; + + if (Instance >= Global->NumFv) { + return EFI_INVALID_PARAMETER; + } + // + // Find the right instance of the FVB private data + // + FwhRecord = Global->FvInstance[Virtual]; + while (Instance > 0) { + FwhRecord = (EFI_FW_VOL_INSTANCE *) + ( + (UINTN) ((UINT8 *) FwhRecord) + FwhRecord->VolumeHeader.HeaderLength + + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)) + ); + Instance--; + } + + *FwhInstance = FwhRecord; + + return EFI_SUCCESS; +} + +EFI_STATUS +FvbGetPhysicalAddress ( + IN UINTN Instance, + OUT EFI_PHYSICAL_ADDRESS *Address, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +/*++ + +Routine Description: + Retrieves the physical address of a memory mapped FV + +Arguments: + Instance - The FV instance whose base address is going to be + returned + Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS + that on successful return, contains the base address + of the firmware volume. + Global - Pointer to ESAL_FWB_GLOBAL that contains all + instance data + Virtual - Whether CPU is in virtual or physical mode + +Returns: + EFI_SUCCESS - Successfully returns + EFI_INVALID_PARAMETER - Instance not found + +--*/ +{ + EFI_FW_VOL_INSTANCE *FwhInstance; + EFI_STATUS Status; + + // + // Find the right instance of the FVB private data + // + Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual); + ASSERT_EFI_ERROR (Status); + *Address = FwhInstance->FvBase[Virtual]; + + return EFI_SUCCESS; +} + +EFI_STATUS +FvbGetVolumeAttributes ( + IN UINTN Instance, + OUT EFI_FVB_ATTRIBUTES *Attributes, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +/*++ + +Routine Description: + Retrieves attributes, insures positive polarity of attribute bits, returns + resulting attributes in output parameter + +Arguments: + Instance - The FV instance whose attributes is going to be + returned + Attributes - Output buffer which contains attributes + Global - Pointer to ESAL_FWB_GLOBAL that contains all + instance data + Virtual - Whether CPU is in virtual or physical mode + +Returns: + EFI_SUCCESS - Successfully returns + EFI_INVALID_PARAMETER - Instance not found + +--*/ +{ + EFI_FW_VOL_INSTANCE *FwhInstance; + EFI_STATUS Status; + + // + // Find the right instance of the FVB private data + // + Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual); + ASSERT_EFI_ERROR (Status); + *Attributes = FwhInstance->VolumeHeader.Attributes; + + return EFI_SUCCESS; +} + +EFI_STATUS +FvbGetLbaAddress ( + IN UINTN Instance, + IN EFI_LBA Lba, + OUT UINTN *LbaAddress, + OUT UINTN *LbaLength, + OUT UINTN *NumOfBlocks, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +/*++ + +Routine Description: + Retrieves the starting address of an LBA in an FV + +Arguments: + Instance - The FV instance which the Lba belongs to + Lba - The logical block address + LbaAddress - On output, contains the physical starting address + of the Lba + LbaLength - On output, contains the length of the block + NumOfBlocks - A 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 + Global - Pointer to ESAL_FWB_GLOBAL that contains all + instance data + Virtual - Whether CPU is in virtual or physical mode + +Returns: + EFI_SUCCESS - Successfully returns + EFI_INVALID_PARAMETER - Instance not found + +--*/ +{ + UINT32 NumBlocks; + UINT32 BlockLength; + UINTN Offset; + EFI_LBA StartLba; + EFI_LBA NextLba; + EFI_FW_VOL_INSTANCE *FwhInstance; + EFI_FV_BLOCK_MAP_ENTRY *BlockMap; + EFI_STATUS Status; + + // + // Find the right instance of the FVB private data + // + Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual); + ASSERT_EFI_ERROR (Status); + + StartLba = 0; + Offset = 0; + BlockMap = &(FwhInstance->VolumeHeader.FvBlockMap[0]); + + // + // Parse the blockmap of the FV to find which map entry the Lba belongs to + // + while (TRUE) { + NumBlocks = BlockMap->NumBlocks; + BlockLength = BlockMap->BlockLength; + + if (NumBlocks == 0 || BlockLength == 0) { + return EFI_INVALID_PARAMETER; + } + + NextLba = StartLba + NumBlocks; + + // + // The map entry found + // + if (Lba >= StartLba && Lba < NextLba) { + Offset = Offset + (UINTN) MultU64x32 ((Lba - StartLba), BlockLength); + if (LbaAddress != NULL) { + *LbaAddress = FwhInstance->FvBase[Virtual] + Offset; + } + + if (LbaLength != NULL) { + *LbaLength = BlockLength; + } + + if (NumOfBlocks != NULL) { + *NumOfBlocks = (UINTN) (NextLba - Lba); + } + + return EFI_SUCCESS; + } + + StartLba = NextLba; + Offset = Offset + NumBlocks * BlockLength; + BlockMap++; + } +} + +EFI_STATUS +FvbReadBlock ( + IN UINTN Instance, + IN EFI_LBA Lba, + IN UINTN BlockOffset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +/*++ + +Routine Description: + Reads specified number of bytes into a buffer from the specified block + +Arguments: + Instance - The FV instance to be read from + Lba - The logical block address to be read from + BlockOffset - Offset into the block at which to begin reading + NumBytes - Pointer that on input contains the total size of + the buffer. On output, it contains the total number + of bytes read + Buffer - Pointer to a caller allocated buffer that will be + used to hold the data read + Global - Pointer to ESAL_FWB_GLOBAL that contains all + instance data + Virtual - Whether CPU is in virtual or physical mode + +Returns: + EFI_SUCCESS - The firmware volume was read successfully and + contents are in Buffer + EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output, + NumBytes contains the total number of bytes returned + in Buffer + EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state + EFI_DEVICE_ERROR - The block device is not functioning correctly and + could not be read + EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL + +--*/ +{ + EFI_FVB_ATTRIBUTES Attributes; + UINTN LbaAddress; + UINTN LbaLength; + EFI_STATUS Status; + + // + // Check for invalid conditions + // + if ((NumBytes == NULL) || (Buffer == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (*NumBytes == 0) { + return EFI_INVALID_PARAMETER; + } + + Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Check if the FV is read enabled + // + FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual); + + if ((Attributes & EFI_FVB_READ_STATUS) == 0) { + return EFI_ACCESS_DENIED; + } + // + // Perform boundary checks and adjust NumBytes + // + if (BlockOffset > LbaLength) { + return EFI_INVALID_PARAMETER; + } + + if (LbaLength < (*NumBytes + BlockOffset)) { + *NumBytes = (UINT32) (LbaLength - BlockOffset); + Status = EFI_BAD_BUFFER_SIZE; + } + + CopyMem (Buffer, (UINT8 *) (LbaAddress + BlockOffset), (UINTN) (*NumBytes)); + + return Status; +} + +EFI_STATUS +FvbWriteBlock ( + IN UINTN Instance, + IN EFI_LBA Lba, + IN UINTN BlockOffset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +/*++ + +Routine Description: + Writes specified number of bytes from the input buffer to the block + +Arguments: + Instance - The FV instance to be written to + Lba - The starting logical block index to write to + BlockOffset - Offset into the block at which to begin writing + NumBytes - Pointer that on input contains the total size of + the buffer. On output, it contains the total number + of bytes actually written + Buffer - Pointer to a caller allocated buffer that contains + the source for the write + Global - Pointer to ESAL_FWB_GLOBAL that contains all + instance data + Virtual - Whether CPU is in virtual or physical mode + +Returns: + EFI_SUCCESS - The firmware volume was written successfully + EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output, + NumBytes contains the total number of bytes + actually written + EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state + EFI_DEVICE_ERROR - The block device is not functioning correctly and + could not be written + EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL + +--*/ +{ + EFI_FVB_ATTRIBUTES Attributes; + UINTN LbaAddress; + UINTN LbaLength; + EFI_STATUS Status; + + // + // Check for invalid conditions + // + if ((NumBytes == NULL) || (Buffer == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (*NumBytes == 0) { + return EFI_INVALID_PARAMETER; + } + + Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Check if the FV is write enabled + // + FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual); + + if ((Attributes & EFI_FVB_WRITE_STATUS) == 0) { + return EFI_ACCESS_DENIED; + } + // + // Perform boundary checks and adjust NumBytes + // + if (BlockOffset > LbaLength) { + return EFI_INVALID_PARAMETER; + } + + if (LbaLength < (*NumBytes + BlockOffset)) { + *NumBytes = (UINT32) (LbaLength - BlockOffset); + Status = EFI_BAD_BUFFER_SIZE; + } + // + // Write data + // + CopyMem ((UINT8 *) (LbaAddress + BlockOffset), Buffer, (UINTN) (*NumBytes)); + + return Status; +} + +EFI_STATUS +FvbEraseBlock ( + IN UINTN Instance, + IN EFI_LBA Lba, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +/*++ + +Routine Description: + Erases and initializes a firmware volume block + +Arguments: + Instance - The FV instance to be erased + Lba - The logical block index to be erased + Global - Pointer to ESAL_FWB_GLOBAL that contains all + instance data + Virtual - Whether CPU is in virtual or physical mode + +Returns: + EFI_SUCCESS - The erase request was successfully completed + EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state + EFI_DEVICE_ERROR - The block device is not functioning correctly and + could not be written. Firmware device may have been + partially erased + EFI_INVALID_PARAMETER - Instance not found + +--*/ +{ + + EFI_FVB_ATTRIBUTES Attributes; + UINTN LbaAddress; + UINTN LbaLength; + EFI_STATUS Status; + UINT8 Data; + + // + // Check if the FV is write enabled + // + FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual); + + if ((Attributes & EFI_FVB_WRITE_STATUS) == 0) { + return EFI_ACCESS_DENIED; + } + // + // Get the starting address of the block for erase. + // + Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual); + + if (EFI_ERROR (Status)) { + return Status; + } + + if ((Attributes & EFI_FVB_ERASE_POLARITY) != 0) { + Data = 0xFF; + } else { + Data = 0x0; + } + + SetMem ((UINT8 *) LbaAddress, LbaLength, Data); + + return EFI_SUCCESS; +} + +EFI_STATUS +FvbEraseCustomBlockRange ( + IN UINTN Instance, + IN EFI_LBA StartLba, + IN UINTN OffsetStartLba, + IN EFI_LBA LastLba, + IN UINTN OffsetLastLba, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +/*++ + +Routine Description: + Erases and initializes a specified range of a firmware volume + +Arguments: + Instance - The FV instance to be erased + StartLba - The starting logical block index to be erased + OffsetStartLba - Offset into the starting block at which to + begin erasing + LastLba - The last logical block index to be erased + OffsetStartLba - Offset into the last block at which to end erasing + Global - Pointer to ESAL_FWB_GLOBAL that contains all + instance data + Virtual - Whether CPU is in virtual or physical mode + +Returns: + EFI_SUCCESS - The firmware volume was erased successfully + EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state + EFI_DEVICE_ERROR - The block device is not functioning correctly and + could not be written. Firmware device may have been + partially erased + EFI_INVALID_PARAMETER - Instance not found + +--*/ +{ + EFI_LBA Index; + UINTN LbaSize; + UINTN ScratchLbaSizeData; + + // + // First LBA + // + FvbGetLbaAddress (Instance, StartLba, NULL, &LbaSize, NULL, Global, Virtual); + + // + // Use the scratch space as the intermediate buffer to transfer data + // Back up the first LBA in scratch space. + // + FvbReadBlock (Instance, StartLba, 0, &LbaSize, Global->FvbScratchSpace[Virtual], Global, Virtual); + + // + // erase now + // + FvbEraseBlock (Instance, StartLba, Global, Virtual); + ScratchLbaSizeData = OffsetStartLba; + + // + // write the data back to the first block + // + if (ScratchLbaSizeData > 0) { + FvbWriteBlock (Instance, StartLba, 0, &ScratchLbaSizeData, Global->FvbScratchSpace[Virtual], Global, Virtual); + } + // + // Middle LBAs + // + if (LastLba > (StartLba + 1)) { + for (Index = (StartLba + 1); Index <= (LastLba - 1); Index++) { + FvbEraseBlock (Instance, Index, Global, Virtual); + } + } + // + // Last LBAs, the same as first LBAs + // + if (LastLba > StartLba) { + FvbGetLbaAddress (Instance, LastLba, NULL, &LbaSize, NULL, Global, Virtual); + FvbReadBlock (Instance, LastLba, 0, &LbaSize, Global->FvbScratchSpace[Virtual], Global, Virtual); + FvbEraseBlock (Instance, LastLba, Global, Virtual); + } + + ScratchLbaSizeData = LbaSize - (OffsetStartLba + 1); + + return FvbWriteBlock ( + Instance, + LastLba, + (OffsetLastLba + 1), + &ScratchLbaSizeData, + Global->FvbScratchSpace[Virtual], + Global, + Virtual + ); +} + +EFI_STATUS +FvbSetVolumeAttributes ( + IN UINTN Instance, + IN OUT EFI_FVB_ATTRIBUTES *Attributes, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +/*++ + +Routine Description: + Modifies the current settings of the firmware volume according to the + input parameter, and returns the new setting of the volume + +Arguments: + Instance - The FV instance whose attributes is going to be + modified + Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES + containing the desired firmware volume settings. + On successful return, it contains the new settings + of the firmware volume + Global - Pointer to ESAL_FWB_GLOBAL that contains all + instance data + Virtual - Whether CPU is in virtual or physical mode + +Returns: + EFI_SUCCESS - Successfully returns + EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified + EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are + in conflict with the capabilities as declared in the + firmware volume header + +--*/ +{ + EFI_FW_VOL_INSTANCE *FwhInstance; + EFI_FVB_ATTRIBUTES OldAttributes; + EFI_FVB_ATTRIBUTES *AttribPtr; + UINT32 Capabilities; + UINT32 OldStatus; + UINT32 NewStatus; + EFI_STATUS Status; + + // + // Find the right instance of the FVB private data + // + Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual); + ASSERT_EFI_ERROR (Status); + + AttribPtr = (EFI_FVB_ATTRIBUTES *) &(FwhInstance->VolumeHeader.Attributes); + OldAttributes = *AttribPtr; + Capabilities = OldAttributes & EFI_FVB_CAPABILITIES; + OldStatus = OldAttributes & EFI_FVB_STATUS; + NewStatus = *Attributes & EFI_FVB_STATUS; + + // + // If firmware volume is locked, no status bit can be updated + // + if (OldAttributes & EFI_FVB_LOCK_STATUS) { + if (OldStatus ^ NewStatus) { + return EFI_ACCESS_DENIED; + } + } + // + // Test read disable + // + if ((Capabilities & EFI_FVB_READ_DISABLED_CAP) == 0) { + if ((NewStatus & EFI_FVB_READ_STATUS) == 0) { + return EFI_INVALID_PARAMETER; + } + } + // + // Test read enable + // + if ((Capabilities & EFI_FVB_READ_ENABLED_CAP) == 0) { + if (NewStatus & EFI_FVB_READ_STATUS) { + return EFI_INVALID_PARAMETER; + } + } + // + // Test write disable + // + if ((Capabilities & EFI_FVB_WRITE_DISABLED_CAP) == 0) { + if ((NewStatus & EFI_FVB_WRITE_STATUS) == 0) { + return EFI_INVALID_PARAMETER; + } + } + // + // Test write enable + // + if ((Capabilities & EFI_FVB_WRITE_ENABLED_CAP) == 0) { + if (NewStatus & EFI_FVB_WRITE_STATUS) { + return EFI_INVALID_PARAMETER; + } + } + // + // Test lock + // + if ((Capabilities & EFI_FVB_LOCK_CAP) == 0) { + if (NewStatus & EFI_FVB_LOCK_STATUS) { + return EFI_INVALID_PARAMETER; + } + } + + *AttribPtr = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB_STATUS)); + *AttribPtr = (*AttribPtr) | NewStatus; + *Attributes = *AttribPtr; + + return EFI_SUCCESS; +} +// +// FVB protocol APIs +// +EFI_STATUS +EFIAPI +FvbProtocolGetPhysicalAddress ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_PHYSICAL_ADDRESS *Address + ) +/*++ + +Routine Description: + + Retrieves the physical address of the device. + +Arguments: + + This - Calling context + Address - Output buffer containing the address. + +Returns: + +Returns: + EFI_SUCCESS - Successfully returns + +--*/ +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + + return FvbGetPhysicalAddress (FvbDevice->Instance, Address, mFvbModuleGlobal, EfiGoneVirtual ()); +} + +EFI_STATUS +EFIAPI +FvbProtocolGetBlockSize ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + OUT UINTN *BlockSize, + OUT UINTN *NumOfBlocks + ) +/*++ + +Routine Description: + Retrieve the size of a logical block + +Arguments: + This - Calling context + Lba - Indicates which block to return the size for. + BlockSize - A pointer to a caller allocated UINTN in which + the size of the block is returned + NumOfBlocks - a 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 + +Returns: + EFI_SUCCESS - The firmware volume was read successfully and + contents are in Buffer + +--*/ +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + + return FvbGetLbaAddress ( + FvbDevice->Instance, + Lba, + NULL, + BlockSize, + NumOfBlocks, + mFvbModuleGlobal, + EfiGoneVirtual () + ); +} + +EFI_STATUS +EFIAPI +FvbProtocolGetAttributes ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_FVB_ATTRIBUTES *Attributes + ) +/*++ + +Routine Description: + Retrieves Volume attributes. No polarity translations are done. + +Arguments: + This - Calling context + Attributes - output buffer which contains attributes + +Returns: + EFI_SUCCESS - Successfully returns + +--*/ +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + + return FvbGetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ()); +} + +EFI_STATUS +EFIAPI +FvbProtocolSetAttributes ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN OUT EFI_FVB_ATTRIBUTES *Attributes + ) +/*++ + +Routine Description: + Sets Volume attributes. No polarity translations are done. + +Arguments: + This - Calling context + Attributes - output buffer which contains attributes + +Returns: + EFI_SUCCESS - Successfully returns + +--*/ +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + + return FvbSetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ()); +} + +EFI_STATUS +EFIAPI +FvbProtocolEraseBlocks ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + ... + ) +/*++ + +Routine Description: + + 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. + +Arguments: + This - Calling context + ... - Starting LBA followed by Number of Lba to erase. + a -1 to terminate the list. + +Returns: + EFI_SUCCESS - The erase request was successfully completed + EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state + EFI_DEVICE_ERROR - The block device is not functioning correctly and + could not be written. Firmware device may have been + partially erased + +--*/ +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + EFI_FW_VOL_INSTANCE *FwhInstance; + UINTN NumOfBlocks; + VA_LIST args; + EFI_LBA StartingLba; + UINTN NumOfLba; + EFI_STATUS Status; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + + Status = GetFvbInstance (FvbDevice->Instance, mFvbModuleGlobal, &FwhInstance, EfiGoneVirtual ()); + ASSERT_EFI_ERROR (Status); + + NumOfBlocks = FwhInstance->NumOfBlocks; + + VA_START (args, This); + + do { + StartingLba = VA_ARG (args, EFI_LBA); + if (StartingLba == EFI_LBA_LIST_TERMINATOR) { + break; + } + + NumOfLba = VA_ARG (args, UINT32); + + // + // Check input parameters + // + if (NumOfLba == 0) { + VA_END (args); + return EFI_INVALID_PARAMETER; + } + + if ((StartingLba + NumOfLba) > NumOfBlocks) { + return EFI_INVALID_PARAMETER; + } + } while (1); + + VA_END (args); + + VA_START (args, This); + do { + StartingLba = VA_ARG (args, EFI_LBA); + if (StartingLba == EFI_LBA_LIST_TERMINATOR) { + break; + } + + NumOfLba = VA_ARG (args, UINT32); + + while (NumOfLba > 0) { + Status = FvbEraseBlock (FvbDevice->Instance, StartingLba, mFvbModuleGlobal, EfiGoneVirtual ()); + if (EFI_ERROR (Status)) { + VA_END (args); + return Status; + } + + StartingLba++; + NumOfLba--; + } + + } while (1); + + VA_END (args); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +FvbProtocolWrite ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +/*++ + +Routine Description: + + Writes data beginning at Lba:Offset from FV. The write terminates either + when *NumBytes of data have been written, or when a block boundary is + reached. *NumBytes is updated to reflect the actual number of bytes + written. The write opertion does not include erase. This routine will + attempt to write only the specified bytes. If the writes do not stick, + it will return an error. + +Arguments: + This - Calling context + Lba - Block in which to begin write + Offset - Offset in the block at which to begin write + NumBytes - On input, indicates the requested write size. On + output, indicates the actual number of bytes written + Buffer - Buffer containing source data for the write. + +Returns: + EFI_SUCCESS - The firmware volume was written successfully + EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output, + NumBytes contains the total number of bytes + actually written + EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state + EFI_DEVICE_ERROR - The block device is not functioning correctly and + could not be written + EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL + +--*/ +{ + + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + + return FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ()); +} + +EFI_STATUS +EFIAPI +FvbProtocolRead ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +/*++ + +Routine Description: + + Reads data beginning at Lba:Offset from FV. The Read terminates either + when *NumBytes of data have been read, or when a block boundary is + reached. *NumBytes is updated to reflect the actual number of bytes + written. The write opertion does not include erase. This routine will + attempt to write only the specified bytes. If the writes do not stick, + it will return an error. + +Arguments: + This - Calling context + Lba - Block in which to begin Read + Offset - Offset in the block at which to begin Read + NumBytes - On input, indicates the requested write size. On + output, indicates the actual number of bytes Read + Buffer - Buffer containing source data for the Read. + +Returns: + EFI_SUCCESS - The firmware volume was read successfully and + contents are in Buffer + EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output, + NumBytes contains the total number of bytes returned + in Buffer + EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state + EFI_DEVICE_ERROR - The block device is not functioning correctly and + could not be read + EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL + +--*/ +{ + + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + + return FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ()); +} +// +// FVB Extension Protocols +// +EFI_STATUS +EFIAPI +FvbExtendProtocolEraseCustomBlockRange ( + IN EFI_FVB_EXTENSION_PROTOCOL *This, + IN EFI_LBA StartLba, + IN UINTN OffsetStartLba, + IN EFI_LBA LastLba, + IN UINTN OffsetLastLba + ) +/*++ + +Routine Description: + Erases and initializes a specified range of a firmware volume + +Arguments: + This - Calling context + StartLba - The starting logical block index to be erased + OffsetStartLba - Offset into the starting block at which to + begin erasing + LastLba - The last logical block index to be erased + OffsetStartLba - Offset into the last block at which to end erasing + +Returns: + EFI_SUCCESS - The firmware volume was erased successfully + EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state + EFI_DEVICE_ERROR - The block device is not functioning correctly and + could not be written. Firmware device may have been + partially erased + +--*/ +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + + FvbDevice = FVB_EXTEND_DEVICE_FROM_THIS (This); + + return FvbEraseCustomBlockRange ( + FvbDevice->Instance, + StartLba, + OffsetStartLba, + LastLba, + OffsetLastLba, + mFvbModuleGlobal, + EfiGoneVirtual () + ); +} + +STATIC +EFI_STATUS +ValidateFvHeader ( + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader + ) +/*++ + +Routine Description: + Check the integrity of firmware volume header + +Arguments: + FwVolHeader - A pointer to a firmware volume header + +Returns: + EFI_SUCCESS - The firmware volume is consistent + EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV + +--*/ +{ + UINT16 *Ptr; + UINT16 HeaderLength; + UINT16 Checksum; + + // + // Verify the header revision, header signature, length + // Length of FvBlock cannot be 2**64-1 + // HeaderLength cannot be an odd number + // + if ((FwVolHeader->Revision != EFI_FVH_REVISION) || + (FwVolHeader->Signature != EFI_FVH_SIGNATURE) || + (FwVolHeader->FvLength == ((UINTN) -1)) || + ((FwVolHeader->HeaderLength & 0x01) != 0) + ) { + return EFI_NOT_FOUND; + } + // + // Verify the header checksum + // + HeaderLength = (UINT16) (FwVolHeader->HeaderLength / 2); + Ptr = (UINT16 *) FwVolHeader; + Checksum = 0; + while (HeaderLength > 0) { + Checksum = *Ptr++; + HeaderLength--; + } + + if (Checksum != 0) { + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +FvbInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + This function does common initialization for FVB services + +Arguments: + +Returns: + +--*/ +{ + EFI_STATUS Status; + EFI_FW_VOL_INSTANCE *FwhInstance; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_DXE_SERVICES *DxeServices; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor; + UINT32 BufferSize; + EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry; + EFI_HANDLE FwbHandle; + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *OldFwbInterface; + EFI_DEVICE_PATH_PROTOCOL *TempFwbDevicePath; + FV_DEVICE_PATH TempFvbDevicePathData; + UINT32 MaxLbaSize; + EFI_PHYSICAL_ADDRESS BaseAddress; + UINT64 Length; + UINTN NumOfBlocks; + EFI_PEI_HOB_POINTERS FvHob; + + // + // Get the DXE services table + // + DxeServices = gDS; + + // + // Allocate runtime services data for global variable, which contains + // the private data of all firmware volume block instances + // + Status = gBS->AllocatePool ( + EfiRuntimeServicesData, + sizeof (ESAL_FWB_GLOBAL), + &mFvbModuleGlobal + ); + ASSERT_EFI_ERROR (Status); + + // + // Calculate the total size for all firmware volume block instances + // + BufferSize = 0; + + FvHob.Raw = GetHobList (); + while ((FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw)) != NULL) { + BaseAddress = FvHob.FirmwareVolume->BaseAddress; + Length = FvHob.FirmwareVolume->Length; + // + // Check if it is a "real" flash + // + Status = DxeServices->GetMemorySpaceDescriptor ( + BaseAddress, + &Descriptor + ); + if (EFI_ERROR (Status)) { + break; + } + + if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) { + FvHob.Raw = GET_NEXT_HOB (FvHob); + continue; + } + + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress; + Status = ValidateFvHeader (FwVolHeader); + if (EFI_ERROR (Status)) { + // + // Get FvbInfo + // + Status = GetFvbInfo (Length, &FwVolHeader); + if (EFI_ERROR (Status)) { + FvHob.Raw = GET_NEXT_HOB (FvHob); + continue; + } + } + + BufferSize += (sizeof (EFI_FW_VOL_INSTANCE) + FwVolHeader->HeaderLength - sizeof (EFI_FIRMWARE_VOLUME_HEADER)); + FvHob.Raw = GET_NEXT_HOB (FvHob); + } + + // + // Only need to allocate once. There is only one copy of physical memory for + // the private data of each FV instance. But in virtual mode or in physical + // mode, the address of the the physical memory may be different. + // + Status = gBS->AllocatePool ( + EfiRuntimeServicesData, + BufferSize, + &mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] + ); + ASSERT_EFI_ERROR (Status); + + // + // Make a virtual copy of the FvInstance pointer. + // + FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]; + mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] = FwhInstance; + + mFvbModuleGlobal->NumFv = 0; + MaxLbaSize = 0; + + FvHob.Raw = GetHobList (); + while (NULL != (FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw))) { + BaseAddress = FvHob.FirmwareVolume->BaseAddress; + Length = FvHob.FirmwareVolume->Length; + // + // Check if it is a "real" flash + // + Status = DxeServices->GetMemorySpaceDescriptor ( + BaseAddress, + &Descriptor + ); + if (EFI_ERROR (Status)) { + break; + } + + if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) { + FvHob.Raw = GET_NEXT_HOB (FvHob); + continue; + } + + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress; + Status = ValidateFvHeader (FwVolHeader); + if (EFI_ERROR (Status)) { + // + // Get FvbInfo to provide in FwhInstance. + // + Status = GetFvbInfo (Length, &FwVolHeader); + if (EFI_ERROR (Status)) { + FvHob.Raw = GET_NEXT_HOB (FvHob); + continue; + } + // + // Write healthy FV header back. + // + CopyMem ( + (VOID *) (UINTN) BaseAddress, + (VOID *) FwVolHeader, + FwVolHeader->HeaderLength + ); + } + + FwhInstance->FvBase[FVB_PHYSICAL] = (UINTN) BaseAddress; + FwhInstance->FvBase[FVB_VIRTUAL] = (UINTN) BaseAddress; + + CopyMem ((UINTN *) &(FwhInstance->VolumeHeader), (UINTN *) FwVolHeader, FwVolHeader->HeaderLength); + FwVolHeader = &(FwhInstance->VolumeHeader); + EfiInitializeLock (&(FwhInstance->FvbDevLock), EFI_TPL_HIGH_LEVEL); + + NumOfBlocks = 0; + + for (PtrBlockMapEntry = FwVolHeader->FvBlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) { + // + // Get the maximum size of a block. The size will be used to allocate + // buffer for Scratch space, the intermediate buffer for FVB extension + // protocol + // + if (MaxLbaSize < PtrBlockMapEntry->BlockLength) { + MaxLbaSize = PtrBlockMapEntry->BlockLength; + } + + NumOfBlocks = NumOfBlocks + PtrBlockMapEntry->NumBlocks; + } + // + // The total number of blocks in the FV. + // + FwhInstance->NumOfBlocks = NumOfBlocks; + + // + // Add a FVB Protocol Instance + // + Status = gBS->AllocatePool ( + EfiRuntimeServicesData, + sizeof (EFI_FW_VOL_BLOCK_DEVICE), + &FvbDevice + ); + ASSERT_EFI_ERROR (Status); + + CopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE)); + + FvbDevice->Instance = mFvbModuleGlobal->NumFv; + mFvbModuleGlobal->NumFv++; + + // + // Set up the devicepath + // + FvbDevice->DevicePath.MemMapDevPath.StartingAddress = BaseAddress; + FvbDevice->DevicePath.MemMapDevPath.EndingAddress = BaseAddress + (FwVolHeader->FvLength - 1); + + // + // Find a handle with a matching device path that has supports FW Block protocol + // + TempFwbDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &TempFvbDevicePathData; + CopyMem (TempFwbDevicePath, &FvbDevice->DevicePath, sizeof (FV_DEVICE_PATH)); + Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &TempFwbDevicePath, &FwbHandle); + if (EFI_ERROR (Status)) { + // + // LocateDevicePath fails so install a new interface and device path + // + FwbHandle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &FwbHandle, + &gEfiFirmwareVolumeBlockProtocolGuid, + &FvbDevice->FwVolBlockInstance, + &gEfiDevicePathProtocolGuid, + &FvbDevice->DevicePath, + NULL + ); + ASSERT_EFI_ERROR (Status); + } else if (EfiIsDevicePathEnd (TempFwbDevicePath)) { + // + // Device allready exists, so reinstall the FVB protocol + // + Status = gBS->HandleProtocol ( + FwbHandle, + &gEfiFirmwareVolumeBlockProtocolGuid, + &OldFwbInterface + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->ReinstallProtocolInterface ( + FwbHandle, + &gEfiFirmwareVolumeBlockProtocolGuid, + OldFwbInterface, + &FvbDevice->FwVolBlockInstance + ); + ASSERT_EFI_ERROR (Status); + + } else { + // + // There was a FVB protocol on an End Device Path node + // + ASSERT (FALSE); + } + // + // Install FVB Extension Protocol on the same handle + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &FwbHandle, + &gEfiFvbExtensionProtocolGuid, + &FvbDevice->FvbExtension, + &gEfiAlternateFvBlockGuid, + NULL, + NULL + ); + + ASSERT_EFI_ERROR (Status); + + FwhInstance = (EFI_FW_VOL_INSTANCE *) + ( + (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength + + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)) + ); + + FvHob.Raw = GET_NEXT_HOB (FvHob); + } + + // + // Allocate for scratch space, an intermediate buffer for FVB extention + // + Status = gBS->AllocatePool ( + EfiRuntimeServicesData, + MaxLbaSize, + &mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL] + ); + ASSERT_EFI_ERROR (Status); + + mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL] = mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL]; + + return EFI_SUCCESS; +} diff --git a/EdkNt32Pkg/RuntimeDxe/FvbServices/nt32/FvbInfo.c b/EdkNt32Pkg/RuntimeDxe/FvbServices/nt32/FvbInfo.c new file mode 100644 index 0000000000..d079423af8 --- /dev/null +++ b/EdkNt32Pkg/RuntimeDxe/FvbServices/nt32/FvbInfo.c @@ -0,0 +1,125 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FvbInfo.c + +Abstract: + + Defines data structure that is the volume header found.These data is intent + to decouple FVB driver with FV header. + +--*/ + +#include "FlashLayout.h" + +#define FIRMWARE_BLOCK_SIZE 0x10000 + +typedef struct { + UINT64 FvLength; + EFI_FIRMWARE_VOLUME_HEADER FvbInfo; + // + // EFI_FV_BLOCK_MAP_ENTRY ExtraBlockMap[n];//n=0 + // + EFI_FV_BLOCK_MAP_ENTRY End[1]; +} EFI_FVB_MEDIA_INFO; + +#define FVB_MEDIA_BLOCK_SIZE FIRMWARE_BLOCK_SIZE +#define RECOVERY_BOIS_BLOCK_NUM FIRMWARE_BLOCK_NUMBER +#define SYSTEM_NV_BLOCK_NUM 2 + +EFI_FVB_MEDIA_INFO mPlatformFvbMediaInfo[] = { + // + // Recovery BOIS FVB + // + { + EFI_WINNT_FIRMWARE_LENGTH, + { + { + 0, + }, // ZeroVector[16] + EFI_FIRMWARE_FILE_SYSTEM_GUID, + FVB_MEDIA_BLOCK_SIZE * RECOVERY_BOIS_BLOCK_NUM, + EFI_FVH_SIGNATURE, + EFI_FVB_READ_ENABLED_CAP | + EFI_FVB_READ_STATUS | + EFI_FVB_WRITE_ENABLED_CAP | + EFI_FVB_WRITE_STATUS | + EFI_FVB_ERASE_POLARITY, + sizeof (EFI_FIRMWARE_VOLUME_HEADER) + sizeof (EFI_FV_BLOCK_MAP_ENTRY), + 0, // CheckSum + { + 0, + }, // Reserved[3] + 1, // Revision + { + RECOVERY_BOIS_BLOCK_NUM, + FVB_MEDIA_BLOCK_SIZE, + } + }, + { + 0, + 0 + } + }, + // + // Systen NvStorage FVB + // + { + EFI_WINNT_RUNTIME_UPDATABLE_LENGTH + EFI_WINNT_FTW_SPARE_BLOCK_LENGTH, + { + { + 0, + }, // ZeroVector[16] + EFI_SYSTEM_NV_DATA_HOB_GUID, + FVB_MEDIA_BLOCK_SIZE * SYSTEM_NV_BLOCK_NUM, + EFI_FVH_SIGNATURE, + EFI_FVB_READ_ENABLED_CAP | + EFI_FVB_READ_STATUS | + EFI_FVB_WRITE_ENABLED_CAP | + EFI_FVB_WRITE_STATUS | + EFI_FVB_ERASE_POLARITY, + sizeof (EFI_FIRMWARE_VOLUME_HEADER) + sizeof (EFI_FV_BLOCK_MAP_ENTRY), + 0, // CheckSum + { + 0, + }, // Reserved[3] + 1, // Revision + { + SYSTEM_NV_BLOCK_NUM, + FVB_MEDIA_BLOCK_SIZE, + } + }, + { + 0, + 0 + } + } +}; + +EFI_STATUS +GetFvbInfo ( + IN UINT64 FvLength, + OUT EFI_FIRMWARE_VOLUME_HEADER **FvbInfo + ) +{ + UINTN Index; + + for (Index = 0; Index < sizeof (mPlatformFvbMediaInfo) / sizeof (EFI_FVB_MEDIA_INFO); Index += 1) { + if (mPlatformFvbMediaInfo[Index].FvLength == FvLength) { + *FvbInfo = &mPlatformFvbMediaInfo[Index].FvbInfo; + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} diff --git a/EdkNt32Pkg/RuntimeDxe/FvbServices/nt32/FwBlockService.h b/EdkNt32Pkg/RuntimeDxe/FvbServices/nt32/FwBlockService.h new file mode 100644 index 0000000000..6f949d37ec --- /dev/null +++ b/EdkNt32Pkg/RuntimeDxe/FvbServices/nt32/FwBlockService.h @@ -0,0 +1,238 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FwBlockService.h + +Abstract: + + Firmware volume block driver for Intel Firmware Hub (FWH) device + +--*/ + +#ifndef _FW_BLOCK_SERVICE_H +#define _FW_BLOCK_SERVICE_H + +// +// BugBug: Add documentation here for data structure!!!! +// +#define FVB_PHYSICAL 0 +#define FVB_VIRTUAL 1 + +typedef struct { + EFI_LOCK FvbDevLock; + UINTN FvBase[2]; + UINTN NumOfBlocks; + EFI_FIRMWARE_VOLUME_HEADER VolumeHeader; +} EFI_FW_VOL_INSTANCE; + +typedef struct { + UINT32 NumFv; + EFI_FW_VOL_INSTANCE *FvInstance[2]; + UINT8 *FvbScratchSpace[2]; +} ESAL_FWB_GLOBAL; + +// +// Fvb Protocol instance data +// +#define FVB_DEVICE_FROM_THIS(a) CR (a, EFI_FW_VOL_BLOCK_DEVICE, FwVolBlockInstance, FVB_DEVICE_SIGNATURE) +#define FVB_EXTEND_DEVICE_FROM_THIS(a) CR (a, EFI_FW_VOL_BLOCK_DEVICE, FvbExtension, FVB_DEVICE_SIGNATURE) +#define FVB_DEVICE_SIGNATURE EFI_SIGNATURE_32 ('F', 'V', 'B', 'N') + +typedef struct { + MEMMAP_DEVICE_PATH MemMapDevPath; + EFI_DEVICE_PATH_PROTOCOL EndDevPath; +} FV_DEVICE_PATH; + +typedef struct { + UINTN Signature; + FV_DEVICE_PATH DevicePath; + UINTN Instance; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL FwVolBlockInstance; + EFI_FVB_EXTENSION_PROTOCOL FvbExtension; +} EFI_FW_VOL_BLOCK_DEVICE; + +EFI_STATUS +GetFvbInfo ( + IN UINT64 FvLength, + OUT EFI_FIRMWARE_VOLUME_HEADER **FvbInfo + ) +; + +EFI_STATUS +FvbReadBlock ( + IN UINTN Instance, + IN EFI_LBA Lba, + IN UINTN BlockOffset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +; + +EFI_STATUS +FvbWriteBlock ( + IN UINTN Instance, + IN EFI_LBA Lba, + IN UINTN BlockOffset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +; + +EFI_STATUS +FvbEraseBlock ( + IN UINTN Instance, + IN EFI_LBA Lba, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +; + +EFI_STATUS +FvbSetVolumeAttributes ( + IN UINTN Instance, + IN OUT EFI_FVB_ATTRIBUTES *Attributes, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +; + +EFI_STATUS +FvbGetVolumeAttributes ( + IN UINTN Instance, + OUT EFI_FVB_ATTRIBUTES *Attributes, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +; + +EFI_STATUS +FvbGetPhysicalAddress ( + IN UINTN Instance, + OUT EFI_PHYSICAL_ADDRESS *Address, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +; + +EFI_STATUS +EFIAPI +FvbInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +; + + +VOID +EFIAPI +FvbClassAddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +; + +EFI_STATUS +FvbGetLbaAddress ( + IN UINTN Instance, + IN EFI_LBA Lba, + OUT UINTN *LbaAddress, + OUT UINTN *LbaLength, + OUT UINTN *NumOfBlocks, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +; + +// +// Protocol APIs +// +EFI_STATUS +EFIAPI +FvbProtocolGetAttributes ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_FVB_ATTRIBUTES *Attributes + ) +; + +EFI_STATUS +EFIAPI +FvbProtocolSetAttributes ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN OUT EFI_FVB_ATTRIBUTES *Attributes + ) +; + +EFI_STATUS +EFIAPI +FvbProtocolGetPhysicalAddress ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_PHYSICAL_ADDRESS *Address + ) +; + +EFI_STATUS +EFIAPI +FvbProtocolGetBlockSize ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + OUT UINTN *BlockSize, + OUT UINTN *NumOfBlocks + ) +; + +EFI_STATUS +EFIAPI +FvbProtocolRead ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +; + +EFI_STATUS +EFIAPI +FvbProtocolWrite ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +; + +EFI_STATUS +EFIAPI +FvbProtocolEraseBlocks ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + ... + ) +; + +EFI_STATUS +EFIAPI +FvbExtendProtocolEraseCustomBlockRange ( + IN EFI_FVB_EXTENSION_PROTOCOL *This, + IN EFI_LBA StartLba, + IN UINTN OffsetStartLba, + IN EFI_LBA LastLba, + IN UINTN OffsetLastLba + ) +; + +#endif diff --git a/EdkNt32Pkg/Sec/FwVol.c b/EdkNt32Pkg/Sec/FwVol.c new file mode 100644 index 0000000000..25ebe07c83 --- /dev/null +++ b/EdkNt32Pkg/Sec/FwVol.c @@ -0,0 +1,314 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + FwVol.c + +Abstract: + A simple FV stack so the SEC can extract the SEC Core from an + FV. + +--*/ + +#include "SecMain.h" + +#define GET_OCCUPIED_SIZE(ActualSize, Alignment) \ + (ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1)) + +EFI_FFS_FILE_STATE +GetFileState ( + IN UINT8 ErasePolarity, + IN EFI_FFS_FILE_HEADER *FfsHeader + ) +/*++ + +Routine Description: + Returns the highest bit set of the State field + +Arguments: + ErasePolarity - Erase Polarity as defined by EFI_FVB_ERASE_POLARITY + in the Attributes field. + FfsHeader - Pointer to FFS File Header. + +Returns: + Returns the highest bit in the State field + +--*/ +{ + EFI_FFS_FILE_STATE FileState; + EFI_FFS_FILE_STATE HighestBit; + + FileState = FfsHeader->State; + + if (ErasePolarity != 0) { + FileState = (EFI_FFS_FILE_STATE)~FileState; + } + + HighestBit = 0x80; + while (HighestBit != 0 && (HighestBit & FileState) == 0) { + HighestBit >>= 1; + } + + return HighestBit; +} + +UINT8 +CalculateHeaderChecksum ( + IN EFI_FFS_FILE_HEADER *FileHeader + ) +/*++ + +Routine Description: + Calculates the checksum of the header of a file. + +Arguments: + FileHeader - Pointer to FFS File Header. + +Returns: + Checksum of the header. + +--*/ +{ + UINT8 *ptr; + UINTN Index; + UINT8 Sum; + + Sum = 0; + ptr = (UINT8 *) FileHeader; + + for (Index = 0; Index < sizeof (EFI_FFS_FILE_HEADER) - 3; Index += 4) { + Sum = (UINT8) (Sum + ptr[Index]); + Sum = (UINT8) (Sum + ptr[Index + 1]); + Sum = (UINT8) (Sum + ptr[Index + 2]); + Sum = (UINT8) (Sum + ptr[Index + 3]); + } + + for (; Index < sizeof (EFI_FFS_FILE_HEADER); Index++) { + Sum = (UINT8) (Sum + ptr[Index]); + } + // + // State field (since this indicates the different state of file). + // + Sum = (UINT8) (Sum - FileHeader->State); + // + // Checksum field of the file is not part of the header checksum. + // + Sum = (UINT8) (Sum - FileHeader->IntegrityCheck.Checksum.File); + + return Sum; +} + +EFI_STATUS +SecFfsFindNextFile ( + IN EFI_FV_FILETYPE SearchType, + IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader, + IN OUT EFI_FFS_FILE_HEADER **FileHeader + ) +/*++ + +Routine Description: + 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. + +Arguments: + SearchType - Filter to find only files of this type. + Type EFI_FV_FILETYPE_ALL causes no filtering to be done. + FwVolHeader - Pointer to the FV header of the volume to search. + This parameter must point to a valid FFS volume. + FileHeader - Pointer to the current file from which to begin searching. + This pointer will be updated upon return to reflect the file + found. + +Returns: + EFI_NOT_FOUND - No files matching the search criteria were found + EFI_SUCCESS + +--*/ +{ + EFI_FFS_FILE_HEADER *FfsFileHeader; + UINT32 FileLength; + UINT32 FileOccupiedSize; + UINT32 FileOffset; + UINT64 FvLength; + UINT8 ErasePolarity; + UINT8 FileState; + + FvLength = FwVolHeader->FvLength; + if (FwVolHeader->Attributes & EFI_FVB_ERASE_POLARITY) { + ErasePolarity = 1; + } else { + ErasePolarity = 0; + } + // + // If FileHeader is not specified (NULL) start with the first file in the + // firmware volume. Otherwise, start from the FileHeader. + // + if (*FileHeader == NULL) { + FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FwVolHeader + FwVolHeader->HeaderLength); + } else { + // + // Length is 24 bits wide so mask upper 8 bits + // FileLength is adjusted to FileOccupiedSize as it is 8 byte aligned. + // + FileLength = *(UINT32 *) (*FileHeader)->Size & 0x00FFFFFF; + FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8); + FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) *FileHeader + FileOccupiedSize); + } + + FileOffset = (UINT32) ((UINT8 *) FfsFileHeader - (UINT8 *) FwVolHeader); + + 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_INVALID: + 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) { + FileLength = *(UINT32 *) (FfsFileHeader->Size) & 0x00FFFFFF; + FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8); + + if ((SearchType == FfsFileHeader->Type) || (SearchType == EFI_FV_FILETYPE_ALL)) { + + *FileHeader = FfsFileHeader; + + return EFI_SUCCESS; + } + + FileOffset += FileOccupiedSize; + FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsFileHeader + FileOccupiedSize); + } else { + return EFI_NOT_FOUND; + } + break; + + case EFI_FILE_DELETED: + FileLength = *(UINT32 *) (FfsFileHeader->Size) & 0x00FFFFFF; + FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8); + FileOffset += FileOccupiedSize; + FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsFileHeader + FileOccupiedSize); + break; + + default: + return EFI_NOT_FOUND; + + } + } + + return EFI_NOT_FOUND; +} + +EFI_STATUS +SecFfsFindSectionData ( + IN EFI_SECTION_TYPE SectionType, + IN EFI_FFS_FILE_HEADER *FfsFileHeader, + IN OUT VOID **SectionData + ) +/*++ + +Routine Description: + Given the input file pointer, search for the next matching section in the + FFS volume. + +Arguments: + SearchType - Filter to find only sections of this type. + FfsFileHeader - Pointer to the current file to search. + SectionData - Pointer to the Section matching SectionType in FfsFileHeader. + NULL if section not found + +Returns: + EFI_NOT_FOUND - No files matching the search criteria were found + EFI_SUCCESS + +--*/ +{ + UINT32 FileSize; + EFI_COMMON_SECTION_HEADER *Section; + UINT32 SectionLength; + UINT32 ParsedLength; + + // + // Size is 24 bits wide so mask upper 8 bits. + // Does not include FfsFileHeader header size + // FileSize is adjusted to FileOccupiedSize as it is 8 byte aligned. + // + Section = (EFI_COMMON_SECTION_HEADER *) (FfsFileHeader + 1); + FileSize = *(UINT32 *) (FfsFileHeader->Size) & 0x00FFFFFF; + FileSize -= sizeof (EFI_FFS_FILE_HEADER); + + *SectionData = NULL; + ParsedLength = 0; + while (ParsedLength < FileSize) { + if (Section->Type == SectionType) { + *SectionData = (VOID *) (Section + 1); + return EFI_SUCCESS; + } + // + // Size is 24 bits wide so mask upper 8 bits. + // SectionLength is adjusted it is 4 byte aligned. + // Go to the next section + // + SectionLength = *(UINT32 *) Section->Size & 0x00FFFFFF; + SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4); + + ParsedLength += SectionLength; + Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + SectionLength); + } + + return EFI_NOT_FOUND; +} + +EFI_STATUS +SecFfsFindPeiCore ( + IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader, + OUT VOID **Pe32Data + ) +/*++ + +Routine Description: + Given the pointer to the Firmware Volume Header find the SEC + core and return it's PE32 image. + +Arguments: + FwVolHeader - Pointer to memory mapped FV + Pe32Data - Pointer to SEC PE32 iamge. + +Returns: + EFI_SUCCESS - Pe32Data is valid + other - Failure + +--*/ +{ + EFI_STATUS Status; + EFI_FFS_FILE_HEADER *FileHeader; + EFI_FV_FILETYPE SearchType; + + SearchType = EFI_FV_FILETYPE_PEI_CORE; + FileHeader = NULL; + do { + Status = SecFfsFindNextFile (SearchType, FwVolHeader, &FileHeader); + if (!EFI_ERROR (Status)) { + Status = SecFfsFindSectionData (EFI_SECTION_PE32, FileHeader, Pe32Data); + return Status; + } + } while (!EFI_ERROR (Status)); + + return Status; +} diff --git a/EdkNt32Pkg/Sec/SecMain.c b/EdkNt32Pkg/Sec/SecMain.c new file mode 100644 index 0000000000..2c3d08e062 --- /dev/null +++ b/EdkNt32Pkg/Sec/SecMain.c @@ -0,0 +1,1163 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + SecMain.c + +Abstract: + WinNt emulator of SEC phase. It's really a Win32 application, but this is + Ok since all the other modules for NT32 are NOT Win32 applications. + + This program processes Windows environment variables and figures out + what the memory layout will be, how may FD's will be loaded and also + what the boot mode is. + + The SEC registers a set of services with the SEC core. gPrivateDispatchTable + is a list of PPI's produced by the SEC that are availble for usage in PEI. + + This code produces 128 K of temporary memory for the PEI stack by opening a + Windows file and mapping it directly to memory addresses. + + The system.cmd script is used to set windows environment variables that drive + the configuration opitons of the SEC. + +--*/ + +#include "SecMain.h" + +// +// Globals +// +EFI_PEI_PE_COFF_LOADER_PROTOCOL_INSTANCE mPeiEfiPeiPeCoffLoaderInstance = { + { + SecNt32PeCoffGetImageInfo, + SecNt32PeCoffLoadImage, + SecNt32PeCoffRelocateImage, + SecNt32PeCoffUnloadimage + }, + NULL +}; + + + +EFI_PEI_PE_COFF_LOADER_PROTOCOL *gPeiEfiPeiPeCoffLoader = &mPeiEfiPeiPeCoffLoaderInstance.PeCoff; + +NT_PEI_LOAD_FILE_PPI mSecNtLoadFilePpi = { SecWinNtPeiLoadFile }; + +PEI_NT_AUTOSCAN_PPI mSecNtAutoScanPpi = { SecWinNtPeiAutoScan }; + +PEI_NT_THUNK_PPI mSecWinNtThunkPpi = { SecWinNtWinNtThunkAddress }; + +EFI_PEI_PROGRESS_CODE_PPI mSecStatusCodePpi = { SecPeiReportStatusCode }; + +NT_FWH_PPI mSecFwhInformationPpi = { SecWinNtFdAddress }; + + +EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = { + { + EFI_PEI_PPI_DESCRIPTOR_PPI, + &gEfiPeiPeCoffLoaderGuid, + NULL + }, + { + EFI_PEI_PPI_DESCRIPTOR_PPI, + &gNtPeiLoadFilePpiGuid, + &mSecNtLoadFilePpi + }, + { + EFI_PEI_PPI_DESCRIPTOR_PPI, + &gPeiNtAutoScanPpiGuid, + &mSecNtAutoScanPpi + }, + { + EFI_PEI_PPI_DESCRIPTOR_PPI, + &gPeiNtThunkPpiGuid, + &mSecWinNtThunkPpi + }, + { + EFI_PEI_PPI_DESCRIPTOR_PPI, + &gEfiPeiStatusCodePpiGuid, + &mSecStatusCodePpi + }, + { + EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, + &gNtFwhPpiGuid, + &mSecFwhInformationPpi + } +}; + + +// +// Default information about where the FD is located. +// This array gets filled in with information from EFI_FIRMWARE_VOLUMES +// EFI_FIRMWARE_VOLUMES is a Windows environment variable set by system.cmd. +// The number of array elements is allocated base on parsing +// EFI_FIRMWARE_VOLUMES and the memory is never freed. +// +UINTN gFdInfoCount = 0; +NT_FD_INFO *gFdInfo; + +// +// Array that supports seperate memory rantes. +// The memory ranges are set in system.cmd via the EFI_MEMORY_SIZE variable. +// The number of array elements is allocated base on parsing +// EFI_MEMORY_SIZE and the memory is never freed. +// +UINTN gSystemMemoryCount = 0; +NT_SYSTEM_MEMORY *gSystemMemory; + + +UINTN mPdbNameModHandleArraySize = 0; +PDB_NAME_TO_MOD_HANDLE *mPdbNameModHandleArray = NULL; + + + + +INTN +EFIAPI +main ( + IN INTN Argc, + IN CHAR8 **Argv, + IN CHAR8 **Envp + ) +/*++ + +Routine Description: + Main entry point to SEC for WinNt. This is a Windows program + +Arguments: + Argc - Number of command line arguments + Argv - Array of command line argument strings + Envp - Array of environmemt variable strings + +Returns: + 0 - Normal exit + 1 - Abnormal exit + +--*/ +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS InitialStackMemory; + UINT64 InitialStackMemorySize; + UINTN Index; + UINTN Index1; + UINTN Index2; + UINTN PeiIndex; + CHAR16 *FileName; + CHAR16 *FileNamePtr; + BOOLEAN Done; + VOID *PeiCoreFile; + CHAR16 *MemorySizeStr; + CHAR16 *FirmwareVolumesStr; + + MemorySizeStr = (CHAR16 *)FixedPcdGetPtr (PcdWinNtMemorySize); + FirmwareVolumesStr = (CHAR16 *)FixedPcdGetPtr (PcdWinNtFirmwareVolume); + + printf ("\nEDK SEC Main NT Emulation Environment from www.TianoCore.org\n"); + + // + // Make some Windows calls to Set the process to the highest priority in the + // idle class. We need this to have good performance. + // + SetPriorityClass (GetCurrentProcess (), IDLE_PRIORITY_CLASS); + SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST); + + // + // Allocate space for gSystemMemory Array + // + gSystemMemoryCount = CountSeperatorsInString (MemorySizeStr, '!') + 1; + gSystemMemory = calloc (gSystemMemoryCount, sizeof (NT_SYSTEM_MEMORY)); + if (gSystemMemory == NULL) { + printf ("ERROR : Can not allocate memory for %s. Exiting.\n", MemorySizeStr); + exit (1); + } + // + // Allocate space for gSystemMemory Array + // + gFdInfoCount = CountSeperatorsInString (FirmwareVolumesStr, '!') + 1; + gFdInfo = calloc (gFdInfoCount, sizeof (NT_FD_INFO)); + if (gFdInfo == NULL) { + printf ("ERROR : Can not allocate memory for %s. Exiting.\n", FirmwareVolumesStr); + exit (1); + } + // + // Setup Boot Mode. If BootModeStr == "" then BootMode = 0 (BOOT_WITH_FULL_CONFIGURATION) + // + printf (" BootMode 0x%02x\n", FixedPcdGet32 (PcdWinNtBootMode)); + + // + // Open up a 128K file to emulate temp memory for PEI. + // on a real platform this would be SRAM, or using the cache as RAM. + // Set InitialStackMemory to zero so WinNtOpenFile will allocate a new mapping + // + InitialStackMemory = 0; + InitialStackMemorySize = 0x20000; + Status = WinNtOpenFile ( + L"SecStack", + (UINT32) InitialStackMemorySize, + OPEN_ALWAYS, + &InitialStackMemory, + &InitialStackMemorySize + ); + if (EFI_ERROR (Status)) { + printf ("ERROR : Can not open SecStack Exiting\n"); + exit (1); + } + + printf (" SEC passing in %d bytes of temp RAM to PEI\n", InitialStackMemorySize); + + // + // Open All the firmware volumes and remember the info in the gFdInfo global + // + FileNamePtr = (CHAR16 *)malloc (StrLen ((CHAR16 *)FirmwareVolumesStr) * sizeof(CHAR16)); + if (FileNamePtr == NULL) { + printf ("ERROR : Can not allocate memory for firmware volume string\n"); + exit (1); + } + + StrCpy (FileNamePtr, (CHAR16*)FirmwareVolumesStr); + + for (Done = FALSE, Index = 0, PeiIndex = 0, PeiCoreFile = NULL; !Done; Index++) { + FileName = FileNamePtr; + for (Index1 = 0; (FileNamePtr[Index1] != '!') && (FileNamePtr[Index1] != 0); Index1++) + ; + if (FileNamePtr[Index1] == 0) { + Done = TRUE; + } else { + FileNamePtr[Index1] = '\0'; + FileNamePtr = FileNamePtr + Index1 + 1; + } + + // + // Open the FD and remmeber where it got mapped into our processes address space + // + Status = WinNtOpenFile ( + FileName, + 0, + OPEN_EXISTING, + &gFdInfo[Index].Address, + &gFdInfo[Index].Size + ); + if (EFI_ERROR (Status)) { + printf ("ERROR : Can not open Firmware Device File %S (%r). Exiting.\n", FileName, Status); + exit (1); + } + + printf (" FD loaded from"); + // + // printf can't print filenames directly as the \ gets interperted as an + // escape character. + // + for (Index2 = 0; FileName[Index2] != '\0'; Index2++) { + printf ("%c", FileName[Index2]); + } + + if (PeiCoreFile == NULL) { + // + // Assume the beginning of the FD is an FV and look for the PEI Core. + // Load the first one we find. + // + Status = SecFfsFindPeiCore ((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) gFdInfo[Index].Address, &PeiCoreFile); + if (!EFI_ERROR (Status)) { + PeiIndex = Index; + printf (" contains SEC Core"); + } + } + + printf ("\n"); + } + // + // Calculate memory regions and store the information in the gSystemMemory + // global for later use. The autosizing code will use this data to + // map this memory into the SEC process memory space. + // + for (Index = 0, Done = FALSE; !Done; Index++) { + // + // Save the size of the memory and make a Unicode filename SystemMemory00, ... + // + gSystemMemory[Index].Size = _wtoi (MemorySizeStr) * 0x100000; + _snwprintf (gSystemMemory[Index].FileName, NT_SYSTEM_MEMORY_FILENAME_SIZE, L"SystemMemory%02d", Index); + + // + // Find the next region + // + for (Index1 = 0; MemorySizeStr[Index1] != '!' && MemorySizeStr[Index1] != 0; Index1++) + ; + if (MemorySizeStr[Index1] == 0) { + Done = TRUE; + } + + MemorySizeStr = MemorySizeStr + Index1 + 1; + } + + printf ("\n"); + + // + // Hand off to PEI Core + // + SecLoadFromCore ((UINTN) InitialStackMemory, (UINTN) InitialStackMemorySize, (UINTN) gFdInfo[0].Address, PeiCoreFile); + + // + // If we get here, then the PEI Core returned. This is an error as PEI should + // always hand off to DXE. + // + printf ("ERROR : PEI Core returned\n"); + exit (1); +} + +EFI_STATUS +WinNtOpenFile ( + IN CHAR16 *FileName, + IN UINT32 MapSize, + IN DWORD CreationDisposition, + IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress, + OUT UINT64 *Length + ) +/*++ + +Routine Description: + Opens and memory maps a file using WinNt services. If BaseAddress is non zero + the process will try and allocate the memory starting at BaseAddress. + +Arguments: + FileName - The name of the file to open and map + MapSize - The amount of the file to map in bytes + CreationDisposition - The flags to pass to CreateFile(). Use to create new files for + memory emulation, and exiting files for firmware volume emulation + BaseAddress - The base address of the mapped file in the user address space. + If passed in as NULL the a new memory region is used. + If passed in as non NULL the request memory region is used for + the mapping of the file into the process space. + Length - The size of the mapped region in bytes + +Returns: + EFI_SUCCESS - The file was opened and mapped. + EFI_NOT_FOUND - FileName was not found in the current directory + EFI_DEVICE_ERROR - An error occured attempting to map the opened file + +--*/ +{ + HANDLE NtFileHandle; + HANDLE NtMapHandle; + VOID *VirtualAddress; + UINTN FileSize; + + // + // Use Win API to open/create a file + // + NtFileHandle = CreateFile ( + FileName, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ, + NULL, + CreationDisposition, + FILE_ATTRIBUTE_NORMAL, + NULL + ); + if (NtFileHandle == INVALID_HANDLE_VALUE) { + return EFI_NOT_FOUND; + } + // + // Map the open file into a memory range + // + NtMapHandle = CreateFileMapping ( + NtFileHandle, + NULL, + PAGE_READWRITE, + 0, + MapSize, + NULL + ); + if (NtMapHandle == NULL) { + return EFI_DEVICE_ERROR; + } + // + // Get the virtual address (address in the emulator) of the mapped file + // + VirtualAddress = MapViewOfFileEx ( + NtMapHandle, + FILE_MAP_ALL_ACCESS, + 0, + 0, + MapSize, + (LPVOID) (UINTN) *BaseAddress + ); + if (VirtualAddress == NULL) { + return EFI_DEVICE_ERROR; + } + + if (MapSize == 0) { + // + // Seek to the end of the file to figure out the true file size. + // + FileSize = SetFilePointer ( + NtFileHandle, + 0, + NULL, + FILE_END + ); + if (FileSize == -1) { + return EFI_DEVICE_ERROR; + } + + *Length = (UINT64) FileSize; + } else { + *Length = (UINT64) MapSize; + } + + *BaseAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) VirtualAddress; + + return EFI_SUCCESS; +} + +#define BYTES_PER_RECORD 512 + +EFI_STATUS +EFIAPI +SecPeiReportStatusCode ( + IN EFI_PEI_SERVICES **PeiServices, + 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 + ) +/*++ + +Routine Description: + + This routine produces the ReportStatusCode PEI service. It's passed + up to the PEI Core via a PPI. T + + This code currently uses the NT clib printf. This does not work the same way + as the EFI Print (), as %t, %g, %s as Unicode are not supported. + +Arguments: + (see EFI_PEI_REPORT_STATUS_CODE) + +Returns: + EFI_SUCCESS - Always return success + +--*/ +// TODO: PeiServices - add argument and description to function comment +// TODO: CodeType - add argument and description to function comment +// TODO: Value - add argument and description to function comment +// TODO: Instance - add argument and description to function comment +// TODO: CallerId - add argument and description to function comment +// TODO: Data - add argument and description to function comment +{ + CHAR8 *Format; + EFI_DEBUG_INFO *DebugInfo; + VA_LIST Marker; + CHAR8 PrintBuffer[BYTES_PER_RECORD * 2]; + CHAR8 *Filename; + CHAR8 *Description; + UINT32 LineNumber; + + if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE) { + // + // This supports DEBUG () marcos + // Data format + // EFI_STATUS_CODE_DATA + // EFI_DEBUG_INFO + // + // The first 12 * UINT64 bytes of the string are really an + // arguement stack to support varargs on the Format string. + // + DebugInfo = (EFI_DEBUG_INFO *) (Data + 1); + Marker = (VA_LIST) (DebugInfo + 1); + Format = (CHAR8 *) (((UINT64 *) Marker) + 12); + + AsciiVSPrint (PrintBuffer, BYTES_PER_RECORD, Format, Marker); + printf (PrintBuffer); + } + + if (((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) && + ((CodeType & EFI_STATUS_CODE_SEVERITY_MASK) == EFI_ERROR_UNRECOVERED) + ) { + if (ReportStatusCodeExtractAssertInfo (CodeType, Value, Data, &Filename, &Description, &LineNumber)) { + // + // Support ASSERT () macro + // + printf ("ASSERT %s(%d): %s\n", Filename, LineNumber, Description); + CpuBreakpoint (); + } + } + + return EFI_SUCCESS; +} + + +VOID +SecLoadFromCore ( + IN UINTN LargestRegion, + IN UINTN LargestRegionSize, + IN UINTN BootFirmwareVolumeBase, + IN VOID *PeiCorePe32File + ) +/*++ + +Routine Description: + This is the service to load the PEI Core from the Firmware Volume + +Arguments: + LargestRegion - Memory to use for PEI. + LargestRegionSize - Size of Memory to use for PEI + BootFirmwareVolumeBase - Start of the Boot FV + PeiCorePe32File - PEI Core PE32 + +Returns: + Success means control is transfered and thus we should never return + +--*/ +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS TopOfMemory; + VOID *TopOfStack; + UINT64 PeiCoreSize; + EFI_PHYSICAL_ADDRESS PeiCoreEntryPoint; + EFI_PHYSICAL_ADDRESS PeiImageAddress; + EFI_PEI_STARTUP_DESCRIPTOR *PeiStartup; + + // + // Compute Top Of Memory for Stack and PEI Core Allocations + // + TopOfMemory = LargestRegion + ((LargestRegionSize) & (~15)); + + // + // Allocate 128KB for the Stack + // + TopOfStack = (VOID *) (UINTN) (TopOfMemory - sizeof (EFI_PEI_STARTUP_DESCRIPTOR)); + TopOfMemory = TopOfMemory - STACK_SIZE; + + // + // Patch value in dispatch table values + // + gPrivateDispatchTable[0].Ppi = gPeiEfiPeiPeCoffLoader; + + // + // Bind this information into the SEC hand-off state + // + PeiStartup = (EFI_PEI_STARTUP_DESCRIPTOR *) (UINTN) TopOfStack; + PeiStartup->DispatchTable = (EFI_PEI_PPI_DESCRIPTOR *) &gPrivateDispatchTable; + PeiStartup->SizeOfCacheAsRam = STACK_SIZE; + PeiStartup->BootFirmwareVolume = BootFirmwareVolumeBase; + + // + // Load the PEI Core from a Firmware Volume + // + Status = SecWinNtPeiLoadFile ( + PeiCorePe32File, + &PeiImageAddress, + &PeiCoreSize, + &PeiCoreEntryPoint + ); + if (EFI_ERROR (Status)) { + return ; + } + // + // Transfer control to the PEI Core + // + SwitchStack ( + (SWITCH_STACK_ENTRY_POINT) (UINTN) PeiCoreEntryPoint, + PeiStartup, + NULL, + TopOfStack + ); + // + // If we get here, then the PEI Core returned. This is an error + // + return ; +} + +EFI_STATUS +EFIAPI +SecWinNtPeiAutoScan ( + IN UINTN Index, + OUT EFI_PHYSICAL_ADDRESS *MemoryBase, + OUT UINT64 *MemorySize + ) +/*++ + +Routine Description: + This service is called from Index == 0 until it returns EFI_UNSUPPORTED. + It allows discontiguous memory regions to be supported by the emulator. + It uses gSystemMemory[] and gSystemMemoryCount that were created by + parsing the Windows environment variable EFI_MEMORY_SIZE. + The size comes from the varaible and the address comes from the call to + WinNtOpenFile. + +Arguments: + Index - Which memory region to use + MemoryBase - Return Base address of memory region + MemorySize - Return size in bytes of the memory region + +Returns: + EFI_SUCCESS - If memory region was mapped + EFI_UNSUPPORTED - If Index is not supported + +--*/ +{ + EFI_STATUS Status; + + if (Index >= gSystemMemoryCount) { + return EFI_UNSUPPORTED; + } + + *MemoryBase = 0; + Status = WinNtOpenFile ( + gSystemMemory[Index].FileName, + (UINT32) gSystemMemory[Index].Size, + OPEN_ALWAYS, + MemoryBase, + MemorySize + ); + + gSystemMemory[Index].Memory = *MemoryBase; + + return Status; +} + +VOID * +EFIAPI +SecWinNtWinNtThunkAddress ( + VOID + ) +/*++ + +Routine Description: + Since the SEC is the only Windows program in stack it must export + an interface to do Win API calls. That's what the WinNtThunk address + is for. gWinNt is initailized in WinNtThunk.c. + +Arguments: + InterfaceSize - sizeof (EFI_WIN_NT_THUNK_PROTOCOL); + InterfaceBase - Address of the gWinNt global + +Returns: + EFI_SUCCESS - Data returned + +--*/ +{ + return gWinNt; +} + + +EFI_STATUS +EFIAPI +SecWinNtPeiLoadFile ( + IN VOID *Pe32Data, + IN EFI_PHYSICAL_ADDRESS *ImageAddress, + IN UINT64 *ImageSize, + IN EFI_PHYSICAL_ADDRESS *EntryPoint + ) +/*++ + +Routine Description: + Loads and relocates a PE/COFF image into memory. + +Arguments: + Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated + ImageAddress - The base address of the relocated PE/COFF image + ImageSize - The size of the relocated PE/COFF image + EntryPoint - The entry point of the relocated PE/COFF image + +Returns: + EFI_SUCCESS - The file was loaded and relocated + EFI_OUT_OF_RESOURCES - There was not enough memory to load and relocate the PE/COFF file + +--*/ +{ + EFI_STATUS Status; + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + + ZeroMem (&ImageContext, sizeof (ImageContext)); + ImageContext.Handle = Pe32Data; + + ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) SecImageRead; + + Status = gPeiEfiPeiPeCoffLoader->GetImageInfo (gPeiEfiPeiPeCoffLoader, &ImageContext); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Allocate space in NT (not emulator) memory. Extra space is for alignment + // + ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) malloc ((UINTN) (ImageContext.ImageSize + (ImageContext.SectionAlignment * 2))); + if (ImageContext.ImageAddress == 0) { + return EFI_OUT_OF_RESOURCES; + } + // + // Align buffer on section boundry + // + ImageContext.ImageAddress += ImageContext.SectionAlignment; + ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1); + + Status = gPeiEfiPeiPeCoffLoader->LoadImage (gPeiEfiPeiPeCoffLoader, &ImageContext); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gPeiEfiPeiPeCoffLoader->RelocateImage (gPeiEfiPeiPeCoffLoader, &ImageContext); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // BugBug: Flush Instruction Cache Here when CPU Lib is ready + // + + *ImageAddress = ImageContext.ImageAddress; + *ImageSize = ImageContext.ImageSize; + *EntryPoint = ImageContext.EntryPoint; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +SecWinNtFdAddress ( + IN UINTN Index, + IN OUT EFI_PHYSICAL_ADDRESS *FdBase, + IN OUT UINT64 *FdSize + ) +/*++ + +Routine Description: + Return the FD Size and base address. Since the FD is loaded from a + file into Windows memory only the SEC will know it's address. + +Arguments: + Index - Which FD, starts at zero. + FdSize - Size of the FD in bytes + FdBase - Start address of the FD. Assume it points to an FV Header + +Returns: + EFI_SUCCESS - Return the Base address and size of the FV + EFI_UNSUPPORTED - Index does nto map to an FD in the system + +--*/ +{ + if (Index >= gFdInfoCount) { + return EFI_UNSUPPORTED; + } + + *FdBase = gFdInfo[Index].Address; + *FdSize = gFdInfo[Index].Size; + + if (*FdBase == 0 && *FdSize == 0) { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +SecImageRead ( + IN VOID *FileHandle, + IN UINTN FileOffset, + IN OUT UINTN *ReadSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file + +Arguments: + FileHandle - The handle to the PE/COFF file + FileOffset - The offset, in bytes, into the file to read + ReadSize - The number of bytes to read from the file starting at FileOffset + Buffer - A pointer to the buffer to read the data into. + +Returns: + EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset + +--*/ +{ + CHAR8 *Destination8; + CHAR8 *Source8; + UINTN Length; + + Destination8 = Buffer; + Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset); + Length = *ReadSize; + while (Length--) { + *(Destination8++) = *(Source8++); + } + + return EFI_SUCCESS; +} + +CHAR16 * +AsciiToUnicode ( + IN CHAR8 *Ascii, + IN UINTN *StrLen OPTIONAL + ) +/*++ + +Routine Description: + Convert the passed in Ascii string to Unicode. + Optionally return the length of the strings. + +Arguments: + Ascii - Ascii string to convert + StrLen - Length of string + +Returns: + Pointer to malloc'ed Unicode version of Ascii + +--*/ +{ + UINTN Index; + CHAR16 *Unicode; + + // + // Allocate a buffer for unicode string + // + for (Index = 0; Ascii[Index] != '\0'; Index++) + ; + Unicode = malloc ((Index + 1) * sizeof (CHAR16)); + if (Unicode == NULL) { + return NULL; + } + + for (Index = 0; Ascii[Index] != '\0'; Index++) { + Unicode[Index] = (CHAR16) Ascii[Index]; + } + + Unicode[Index] = '\0'; + + if (StrLen != NULL) { + *StrLen = Index; + } + + return Unicode; +} + +UINTN +CountSeperatorsInString ( + IN const CHAR16 *String, + IN CHAR16 Seperator + ) +/*++ + +Routine Description: + Count the number of seperators in String + +Arguments: + String - String to process + Seperator - Item to count + +Returns: + Number of Seperator in String + +--*/ +{ + UINTN Count; + + for (Count = 0; *String != '\0'; String++) { + if (*String == Seperator) { + Count++; + } + } + + return Count; +} + + +EFI_STATUS +AddModHandle ( + IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, + IN VOID *ModHandle + ) +/*++ + +Routine Description: + Store the ModHandle in an array indexed by the Pdb File name. + The ModHandle is needed to unload the image. + +Arguments: + ImageContext - Input data returned from PE Laoder Library. Used to find the + .PDB file name of the PE Image. + ModHandle - Returned from LoadLibraryEx() and stored for call to + FreeLibrary(). + +Returns: + EFI_SUCCESS - ModHandle was stored. + +--*/ +{ + UINTN Index; + PDB_NAME_TO_MOD_HANDLE *Array; + UINTN PreviousSize; + + + Array = mPdbNameModHandleArray; + for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) { + if (Array->PdbPointer == NULL) { + // + // Make a copy of the stirng and store the ModHandle + // + Array->PdbPointer = malloc (strlen (ImageContext->PdbPointer) + 1); + ASSERT (Array->PdbPointer != NULL); + + strcpy (Array->PdbPointer, ImageContext->PdbPointer); + Array->ModHandle = ModHandle; + return EFI_SUCCESS; + } + } + + // + // No free space in mPdbNameModHandleArray so grow it by + // MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE entires. realloc will + // copy the old values to the new locaiton. But it does + // not zero the new memory area. + // + PreviousSize = mPdbNameModHandleArraySize * sizeof (PDB_NAME_TO_MOD_HANDLE); + mPdbNameModHandleArraySize += MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE; + + mPdbNameModHandleArray = realloc (mPdbNameModHandleArray, mPdbNameModHandleArraySize * sizeof (PDB_NAME_TO_MOD_HANDLE)); + if (mPdbNameModHandleArray == NULL) { + ASSERT (FALSE); + return EFI_OUT_OF_RESOURCES; + } + + memset (mPdbNameModHandleArray + PreviousSize, 0, MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE * sizeof (PDB_NAME_TO_MOD_HANDLE)); + + return AddModHandle (ImageContext, ModHandle); +} + + +VOID * +RemoveModeHandle ( + IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +/*++ + +Routine Description: + Return the ModHandle and delete the entry in the array. + +Arguments: + ImageContext - Input data returned from PE Laoder Library. Used to find the + .PDB file name of the PE Image. + +Returns: + ModHandle - ModHandle assoicated with ImageContext is returned + NULL - No ModHandle associated with ImageContext + +--*/ +{ + UINTN Index; + PDB_NAME_TO_MOD_HANDLE *Array; + + if (ImageContext->PdbPointer == NULL) { + // + // If no PDB pointer there is no ModHandle so return NULL + // + return NULL; + } + + Array = mPdbNameModHandleArray; + for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) { + if ((Array->PdbPointer != NULL) && (strcmp(Array->PdbPointer, ImageContext->PdbPointer) == 0)) { + // + // If you find a match return it and delete the entry + // + free (Array->PdbPointer); + Array->PdbPointer = NULL; + return Array->ModHandle; + } + } + + return NULL; +} + + + +EFI_STATUS +EFIAPI +SecNt32PeCoffGetImageInfo ( + IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This, + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + EFI_STATUS Status; + + Status = PeCoffLoaderGetImageInfo (ImageContext); + if (EFI_ERROR (Status)) { + return Status; + } + + switch (ImageContext->ImageType) { + + case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION: + ImageContext->ImageCodeMemoryType = EfiLoaderCode; + ImageContext->ImageDataMemoryType = EfiLoaderData; + break; + + case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER: + ImageContext->ImageCodeMemoryType = EfiBootServicesCode; + ImageContext->ImageDataMemoryType = EfiBootServicesData; + break; + + case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER: + case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER: + ImageContext->ImageCodeMemoryType = EfiRuntimeServicesCode; + ImageContext->ImageDataMemoryType = EfiRuntimeServicesData; + break; + + default: + ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM; + return RETURN_UNSUPPORTED; + } + + return Status; +} + +EFI_STATUS +EFIAPI +SecNt32PeCoffLoadImage ( + IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This, + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + EFI_STATUS Status; + + Status = PeCoffLoaderLoadImage (ImageContext); + return Status; +} + +EFI_STATUS +EFIAPI +SecNt32PeCoffRelocateImage ( + IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This, + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + EFI_STATUS Status; + VOID *DllEntryPoint; + CHAR16 *DllFileName; + HMODULE Library; + UINTN Index; + + + Status = PeCoffLoaderRelocateImage (ImageContext); + if (EFI_ERROR (Status)) { + // + // We could not relocated the image in memory properly + // + return Status; + } + + // + // If we load our own PE COFF images the Windows debugger can not source + // level debug our code. If a valid PDB pointer exists usw it to load + // the *.dll file as a library using Windows* APIs. This allows + // source level debug. The image is still loaded and reloaced + // in the Framework memory space like on a real system (by the code above), + // but the entry point points into the DLL loaded by the code bellow. + // + + DllEntryPoint = NULL; + + // + // Load the DLL if it's not an EBC image. + // + if ((ImageContext->PdbPointer != NULL) && + (ImageContext->Machine != EFI_IMAGE_MACHINE_EBC)) { + // + // Convert filename from ASCII to Unicode + // + DllFileName = AsciiToUnicode (ImageContext->PdbPointer, &Index); + + // + // Check that we have a valid filename + // + if (Index < 5 || DllFileName[Index - 4] != '.') { + free (DllFileName); + + // + // Never return an error if PeCoffLoaderRelocateImage() succeeded. + // The image will run, but we just can't source level debug. If we + // return an error the image will not run. + // + return EFI_SUCCESS; + } + // + // Replace .PDB with .DLL on the filename + // + DllFileName[Index - 3] = 'D'; + DllFileName[Index - 2] = 'L'; + DllFileName[Index - 1] = 'L'; + + // + // Load the .DLL file into the user process's address space for source + // level debug + // + Library = LoadLibraryEx (DllFileName, NULL, DONT_RESOLVE_DLL_REFERENCES); + if (Library != NULL) { + // + // InitializeDriver is the entry point we put in all our EFI DLL's. The + // DONT_RESOLVE_DLL_REFERENCES argument to LoadLIbraryEx() supresses the + // normal DLL entry point of DllMain, and prevents other modules that are + // referenced in side the DllFileName from being loaded. There is no error + // checking as the we can point to the PE32 image loaded by Tiano. This + // step is only needed for source level debuging + // + DllEntryPoint = (VOID *) (UINTN) GetProcAddress (Library, "InitializeDriver"); + + } + + if ((Library != NULL) && (DllEntryPoint != NULL)) { + AddModHandle (ImageContext, Library); + ImageContext->EntryPoint = (EFI_PHYSICAL_ADDRESS) (UINTN) DllEntryPoint; + wprintf (L"LoadLibraryEx (%s,\n NULL, DONT_RESOLVE_DLL_REFERENCES)\n", DllFileName); + } else { + wprintf (L"WARNING: No source level debug %s. \n", DllFileName); + } + + free (DllFileName); + } + + // + // Never return an error if PeCoffLoaderRelocateImage() succeeded. + // The image will run, but we just can't source level debug. If we + // return an error the image will not run. + // + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +SecNt32PeCoffUnloadimage ( + IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This, + IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + VOID *ModHandle; + + ModHandle = RemoveModeHandle (ImageContext); + if (ModHandle != NULL) { + FreeLibrary (ModHandle); + } + return EFI_SUCCESS; +} + +VOID +_ModuleEntryPoint ( + VOID + ) +{ +} diff --git a/EdkNt32Pkg/Sec/SecMain.h b/EdkNt32Pkg/Sec/SecMain.h new file mode 100644 index 0000000000..7943b837c8 --- /dev/null +++ b/EdkNt32Pkg/Sec/SecMain.h @@ -0,0 +1,570 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +Module Name: + SecMain.h + +Abstract: + Include file for Windows API based SEC + +--*/ + +#include + + +#define STACK_SIZE 0x20000 + +typedef struct { + EFI_PHYSICAL_ADDRESS Address; + UINT64 Size; +} NT_FD_INFO; + +#define NT_SYSTEM_MEMORY_FILENAME_SIZE 40 + +typedef struct { + CHAR16 FileName[NT_SYSTEM_MEMORY_FILENAME_SIZE]; + EFI_PHYSICAL_ADDRESS Memory; + UINT64 Size; +} NT_SYSTEM_MEMORY; + + +#define MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE 0x100 + +typedef struct { + CHAR8 *PdbPointer; + VOID *ModHandle; +} PDB_NAME_TO_MOD_HANDLE; + + + + +EFI_STATUS +EFIAPI +SecWinNtPeiLoadFile ( + VOID *Pe32Data, // TODO: add IN/OUT modifier to Pe32Data + EFI_PHYSICAL_ADDRESS *ImageAddress, // TODO: add IN/OUT modifier to ImageAddress + UINT64 *ImageSize, // TODO: add IN/OUT modifier to ImageSize + EFI_PHYSICAL_ADDRESS *EntryPoint // TODO: add IN/OUT modifier to EntryPoint + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Pe32Data - TODO: add argument description + ImageAddress - TODO: add argument description + ImageSize - TODO: add argument description + EntryPoint - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +SecWinNtPeiAutoScan ( + IN UINTN Index, + OUT EFI_PHYSICAL_ADDRESS *MemoryBase, + OUT UINT64 *MemorySize + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Index - TODO: add argument description + MemoryBase - TODO: add argument description + MemorySize - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +VOID * +EFIAPI +SecWinNtWinNtThunkAddress ( + VOID + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + InterfaceSize - TODO: add argument description + InterfaceBase - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +SecWinNtWinNtFwhAddress ( + IN OUT UINT64 *FwhSize, + IN OUT EFI_PHYSICAL_ADDRESS *FwhBase + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + FwhSize - TODO: add argument description + FwhBase - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +SecPeiReportStatusCode ( + IN EFI_PEI_SERVICES **PeiServices, + 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 + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PeiServices - TODO: add argument description + CodeType - TODO: add argument description + Value - TODO: add argument description + Instance - TODO: add argument description + CallerId - TODO: add argument description + Data - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +INTN +EFIAPI +main ( + IN INTN Argc, + IN CHAR8 **Argv, + IN CHAR8 **Envp + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Argc - TODO: add argument description + Argv - TODO: add argument description + Envp - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +WinNtOpenFile ( + CHAR16 *FileName, + UINT32 MapSize, + DWORD CreationDispostion, + EFI_PHYSICAL_ADDRESS *BaseAddress, + UINT64 *Length + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + FileName - TODO: add argument description + MapSize - TODO: add argument description + CreationDispostion - TODO: add argument description + BaseAddress - TODO: add argument description + Length - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +VOID +SecLoadFromCore ( + IN UINTN LargestRegion, + IN UINTN LargestRegionSize, + IN UINTN BootFirmwareVolumeBase, + IN VOID *PeiCoreFile + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + LargestRegion - TODO: add argument description + LargestRegionSize - TODO: add argument description + BootFirmwareVolumeBase - TODO: add argument description + PeiCoreFile - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +SecLoadFile ( + IN VOID *Pe32Data, + IN EFI_PHYSICAL_ADDRESS *ImageAddress, + IN UINT64 *ImageSize, + IN EFI_PHYSICAL_ADDRESS *EntryPoint + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Pe32Data - TODO: add argument description + ImageAddress - TODO: add argument description + ImageSize - TODO: add argument description + EntryPoint - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +SecFfsFindPeiCore ( + IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader, + OUT VOID **Pe32Data + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + FwVolHeader - TODO: add argument description + Pe32Data - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +SecFfsFindNextFile ( + IN EFI_FV_FILETYPE SearchType, + IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader, + IN OUT EFI_FFS_FILE_HEADER **FileHeader + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SearchType - TODO: add argument description + FwVolHeader - TODO: add argument description + FileHeader - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +SecFfsFindSectionData ( + IN EFI_SECTION_TYPE SectionType, + IN EFI_FFS_FILE_HEADER *FfsFileHeader, + IN OUT VOID **SectionData + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SectionType - TODO: add argument description + FfsFileHeader - TODO: add argument description + SectionData - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +SecWinNtPeCoffLoaderLoadAsDll ( + IN CHAR8 *PdbFileName, + IN VOID **ImageEntryPoint, + OUT VOID **ModHandle + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PdbFileName - TODO: add argument description + ImageEntryPoint - TODO: add argument description + ModHandle - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +SecWinNtPeCoffLoaderFreeLibrary ( + OUT VOID *ModHandle + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ModHandle - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +SecWinNtFdAddress ( + IN UINTN Index, + IN OUT EFI_PHYSICAL_ADDRESS *FdBase, + IN OUT UINT64 *FdSize + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Index - TODO: add argument description + FdBase - TODO: add argument description + FdSize - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +GetImageReadFunction ( + IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, + IN EFI_PHYSICAL_ADDRESS *TopOfMemory + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ImageContext - TODO: add argument description + TopOfMemory - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +SecImageRead ( + IN VOID *FileHandle, + IN UINTN FileOffset, + IN OUT UINTN *ReadSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + FileHandle - TODO: add argument description + FileOffset - TODO: add argument description + ReadSize - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +CHAR16 * +AsciiToUnicode ( + IN CHAR8 *Ascii, + IN UINTN *StrLen OPTIONAL + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Ascii - TODO: add argument description + StrLen - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +UINTN +CountSeperatorsInString ( + IN const CHAR16 *String, + IN CHAR16 Seperator + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + String - TODO: add argument description + Seperator - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +SecNt32PeCoffGetImageInfo ( + IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This, + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ); + +EFI_STATUS +EFIAPI +SecNt32PeCoffLoadImage ( + IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This, + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ); + +EFI_STATUS +EFIAPI +SecNt32PeCoffRelocateImage ( + IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This, + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ); + +EFI_STATUS +EFIAPI +SecNt32PeCoffUnloadimage ( + IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This, + IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ); + + +typedef struct { + EFI_PEI_PE_COFF_LOADER_PROTOCOL PeCoff; + VOID *ModHandle; +} EFI_PEI_PE_COFF_LOADER_PROTOCOL_INSTANCE; + +extern EFI_WIN_NT_THUNK_PROTOCOL *gWinNt; diff --git a/EdkNt32Pkg/Sec/SecMain.mbd b/EdkNt32Pkg/Sec/SecMain.mbd new file mode 100644 index 0000000000..f310571a7c --- /dev/null +++ b/EdkNt32Pkg/Sec/SecMain.mbd @@ -0,0 +1,38 @@ + + + + + SecMain + 4b837b03-6587-4d19-b82b-edfad836c0a0 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-14 17:04 + 2006-03-19 15:17 + + + BaseLib + BaseMemoryLib + BasePeCoffLib + BasePrintLib + BaseReportStatusCodeLibNull + BaseDebugLibNull + + diff --git a/EdkNt32Pkg/Sec/SecMain.msa b/EdkNt32Pkg/Sec/SecMain.msa new file mode 100644 index 0000000000..fd46656138 --- /dev/null +++ b/EdkNt32Pkg/Sec/SecMain.msa @@ -0,0 +1,96 @@ + + + + + SecMain + SEC + SEC + 4b837b03-6587-4d19-b82b-edfad836c0a0 + 0 + Component description file for NT32 Sec.Warning the [sources.*] does not work like you think!If you add a file you need to update the makefile in the NT32 build tipSEC_OBJECTS needs to get the OBJ of the new C file added in.We keep [sources.*] synced up with SEC_OBJECTS so dependencies workproperly.Libraries.Common does not work you must update SEC_OBJECTS in the platformmakefile + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-14 17:04 + 2006-03-19 15:17 + + + PeCoffLib + BaseLib + BaseMemoryLib + PrintLib + ReportStatusCodeLib + PcdLib + DebugLib + + + SecMain.c + FwVol.c + WinNtThunk.c + SecMain.h + + + MdePkg + EdkModulePkg + EdkNt32Pkg + + + NtThunk + NtAutoScan + NtFwh + StatusCode + NtPeiLoadFile + + + + PeiPeCoffLoader + + + + + + + + + + PcdWinNtCpuSpeed + 0x00001008 + VOID* + + + PcdWinNtMemorySize + 0x00001005 + VOID* + + + PcdWinNtFirmwareVolume + 0x00001009 + VOID* + + + PcdWinNtBootMode + 0x00001006 + UINT32 + + + + + + diff --git a/EdkNt32Pkg/Sec/SecMain_build.xml b/EdkNt32Pkg/Sec/SecMain_build.xml new file mode 100644 index 0000000000..b0436d385b --- /dev/null +++ b/EdkNt32Pkg/Sec/SecMain_build.xml @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + "${LINK}" /LIBPATH:"${env.MSVCDir}\Lib" /LIBPATH:"${env.MSVCDir}\PlatformSdk\Lib" /NOLOGO /SUBSYSTEM:CONSOLE /NODEFAULTLIB /IGNORE:4086 /MAP /OPT:REF /DEBUG /MACHINE:I386 /LTCG Kernel32.lib MsvcRt.lib Gdi32.lib User32.lib Winmm.lib ${OBJECTS} ${LIBS} /base:0x10000000 /out:${BIN_DIR}\SecMain.exe /pdb:${DEST_DIR_DEBUG}\SecMain.pdb + + + + + + + + + diff --git a/EdkNt32Pkg/Sec/WinNtThunk.c b/EdkNt32Pkg/Sec/WinNtThunk.c new file mode 100644 index 0000000000..d064fae73d --- /dev/null +++ b/EdkNt32Pkg/Sec/WinNtThunk.c @@ -0,0 +1,178 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + WinNtThunk.c + +Abstract: + + Since the SEC is the only windows program in our emulation we + must use a Tiano mechanism to export Win32 APIs to other modules. + This is the role of the EFI_WIN_NT_THUNK_PROTOCOL. + + The mWinNtThunkTable exists so that a change to EFI_WIN_NT_THUNK_PROTOCOL + will cause an error in initializing the array if all the member functions + are not added. It looks like adding a element to end and not initializing + it may cause the table to be initaliized with the members at the end being + set to zero. This is bad as jumping to zero will case the NT32 to crash. + + All the member functions in mWinNtThunkTable are Win32 + API calls, so please reference Microsoft documentation. + + + gWinNt is a a public exported global that contains the initialized + data. + +--*/ + +#include "SecMain.h" + +// +// This pragma is needed for all the DLL entry points to be asigned to the array. +// if warning 4232 is not dissabled a warning will be generated as a DLL entry +// point could be modified dynamically. The SEC does not do that, so we must +// disable the warning so we can compile the SEC. The previous method was to +// asign each element in code. The disadvantage to that approach is it's harder +// to tell if all the elements have been initailized properly. +// +#pragma warning(disable : 4232) + +EFI_WIN_NT_THUNK_PROTOCOL mWinNtThunkTable = { + EFI_WIN_NT_THUNK_PROTOCOL_SIGNATURE, + GetProcAddress, + GetTickCount, + LoadLibraryEx, + FreeLibrary, + SetPriorityClass, + SetThreadPriority, + Sleep, + SuspendThread, + GetCurrentThread, + GetCurrentThreadId, + GetCurrentProcess, + CreateThread, + TerminateThread, + SendMessage, + ExitThread, + ResumeThread, + DuplicateHandle, + InitializeCriticalSection, + EnterCriticalSection, + LeaveCriticalSection, + DeleteCriticalSection, + TlsAlloc, + TlsFree, + TlsSetValue, + TlsGetValue, + CreateSemaphore, + WaitForSingleObject, + ReleaseSemaphore, + CreateConsoleScreenBuffer, + FillConsoleOutputAttribute, + FillConsoleOutputCharacter, + GetConsoleCursorInfo, + GetNumberOfConsoleInputEvents, + PeekConsoleInput, + ScrollConsoleScreenBuffer, + ReadConsoleInput, + SetConsoleActiveScreenBuffer, + SetConsoleCursorInfo, + SetConsoleCursorPosition, + SetConsoleScreenBufferSize, + SetConsoleTitleW, + WriteConsoleInput, + WriteConsoleOutput, + CreateFile, + DeviceIoControl, + CreateDirectory, + RemoveDirectory, + GetFileAttributes, + SetFileAttributes, + CreateFileMapping, + CloseHandle, + DeleteFile, + FindFirstFile, + FindNextFile, + FindClose, + FlushFileBuffers, + GetEnvironmentVariable, + GetLastError, + SetErrorMode, + GetStdHandle, + MapViewOfFileEx, + ReadFile, + SetEndOfFile, + SetFilePointer, + WriteFile, + GetFileInformationByHandle, + GetDiskFreeSpace, + GetDiskFreeSpaceEx, + MoveFile, + SetFileTime, + SystemTimeToFileTime, + FileTimeToLocalFileTime, + FileTimeToSystemTime, + GetSystemTime, + SetSystemTime, + GetLocalTime, + SetLocalTime, + GetTimeZoneInformation, + SetTimeZoneInformation, + timeSetEvent, + timeKillEvent, + ClearCommError, + EscapeCommFunction, + GetCommModemStatus, + GetCommState, + SetCommState, + PurgeComm, + SetCommTimeouts, + ExitProcess, + swprintf, + GetDesktopWindow, + GetForegroundWindow, + CreateWindowEx, + ShowWindow, + UpdateWindow, + DestroyWindow, + InvalidateRect, + GetWindowDC, + GetClientRect, + AdjustWindowRect, + SetDIBitsToDevice, + BitBlt, + GetDC, + ReleaseDC, + RegisterClassEx, + UnregisterClass, + BeginPaint, + EndPaint, + PostQuitMessage, + DefWindowProc, + LoadIcon, + LoadCursor, + GetStockObject, + SetViewportOrgEx, + SetWindowOrgEx, + MoveWindow, + GetWindowRect, + GetMessage, + TranslateMessage, + DispatchMessage, + GetProcessHeap, + HeapAlloc, + HeapFree +}; + +#pragma warning(default : 4232) + +EFI_WIN_NT_THUNK_PROTOCOL *gWinNt = &mWinNtThunkTable; diff --git a/EdkNt32Pkg/Sec/build.xml b/EdkNt32Pkg/Sec/build.xml new file mode 100644 index 0000000000..4140a8ab0f --- /dev/null +++ b/EdkNt32Pkg/Sec/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkNt32Pkg/build.xml b/EdkNt32Pkg/build.xml new file mode 100644 index 0000000000..d6ca4b81b5 --- /dev/null +++ b/EdkNt32Pkg/build.xml @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cd ${WORKSPACE_DIR}\EdkNt32Pkg\Build\DEBUG\IA32 + SecMain.exe + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/EdkNt32Pkg/genbuildfile.xml b/EdkNt32Pkg/genbuildfile.xml new file mode 100644 index 0000000000..77702ef12d --- /dev/null +++ b/EdkNt32Pkg/genbuildfile.xml @@ -0,0 +1,19 @@ + + + + + + + + + + diff --git a/EdkNt32Pkg/run.cmd b/EdkNt32Pkg/run.cmd new file mode 100644 index 0000000000..167cfc9685 --- /dev/null +++ b/EdkNt32Pkg/run.cmd @@ -0,0 +1,18 @@ +@REM +@REM Copyright (c) 2006, Intel Corporation +@REM All rights reserved. This program and the accompanying materials +@REM are licensed and made available under the terms and conditions of the BSD License +@REM which accompanies this distribution. The full text of the license may be found at +@REM http://opensource.org/licenses/bsd-license.php +@REM +@REM THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +@REM WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +@REM + +@echo off +pushd . +cd Build\DEBUG\IA32 +SecMain.exe +popd +@echo on + diff --git a/EdkShellBinPkg/EdkShellBinPkg.spd b/EdkShellBinPkg/EdkShellBinPkg.spd new file mode 100644 index 0000000000..439ecbc69a --- /dev/null +++ b/EdkShellBinPkg/EdkShellBinPkg.spd @@ -0,0 +1,40 @@ + + + + + EdkShellBinPkg + d4266a1b-1d38-4116-93ae-60dc3e2012a6 + 0 + Reference package showing multiple binaries + This package contains multiple binary drivers, using only one MSA, one MBD and a single SPD. + Copyright (c) 2006, Intel Corporation. + + All rights reserved. + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License which accompanies this distribution. + The full text of the license may be found at http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES + OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-05 10:13 + 2006-03-18 20:23 + http://www.TianoCore.org + BINARY + true + false + + + + bin/Shell.msa + + + diff --git a/EdkShellBinPkg/bin/Shell.mbd b/EdkShellBinPkg/bin/Shell.mbd new file mode 100644 index 0000000000..ad7211e6fc --- /dev/null +++ b/EdkShellBinPkg/bin/Shell.mbd @@ -0,0 +1,33 @@ + + + + + Shell + c57ad6b7-0515-40a8-9d21-551652854e37 + EDK_RELEASE_VERSION 0x00020000 + + This is a binary package containing multiple binary files, however there is + only a single MSA and MBD file. + + + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-17 20:56 + + diff --git a/EdkShellBinPkg/bin/Shell.msa b/EdkShellBinPkg/bin/Shell.msa new file mode 100644 index 0000000000..5fe1f2a527 --- /dev/null +++ b/EdkShellBinPkg/bin/Shell.msa @@ -0,0 +1,47 @@ + + + + + Shell + UEFI_APPLICATION + APPLICATION + c57ad6b7-0515-40a8-9d21-551652854e37 + 0x00090000 + Component description file for EFI Shell module. + + This is a binary package containing multiple binary files, however there is + only a single MSA and MBD file. + + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + EFI_SPECIFICATION_VERSION 0x00000000 + 2006-03-17 20:56 + + + Shell_Full.efi + + + Shell_Full.efi + + + diff --git a/EdkShellBinPkg/bin/build.xml b/EdkShellBinPkg/bin/build.xml new file mode 100644 index 0000000000..807380107d --- /dev/null +++ b/EdkShellBinPkg/bin/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkShellBinPkg/bin/ia32/Apps/Attrib.efi b/EdkShellBinPkg/bin/ia32/Apps/Attrib.efi new file mode 100644 index 0000000000000000000000000000000000000000..c3a45f28745773dc1a6da0d9f645d7d894bd9a12 GIT binary patch literal 45056 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 z%0A*pXv`{f?rX3X41^eLVCX`81bv)uYGb|;aM>+*y12pJSQ5U#wr~0hEW+5MoGpB! z0yx;{DfT(rzG<6S@p8xo!w#M96sIbe@|Z~W&{zcTS@cz3lspNG{i;pTj=;poxQyx- zZjsv90NGncnku1~@J$3hxOKrowcZ}laD8OAxFG@FVv@U-_dIXw9a#vyi7e?!_ zidrI@Y87rtsJWn6AF~!?GLI?RSUAcX5%UR$*&9h{cj#PpCn>6HaMzb$&%Ft=#u_=D z6P`n)(8=O_ccXp%MFPcq_?I8UT!zkW!`TcRyzffaRt%oc8PpnuS4G}q%L|C;;(U>v z0Vhplv2*}091`Wb{dw!@r~9-;asii!Cgo?_#~tl-F|KIhH{14^q3H3LK%4du10e>K z=Z9&*l#91Yn*&oR0=&Etg5u=XETtbXG-%o=RDQUpp3!0~2He;S>zUV%;{#0Yb&}`k zb_iSyZH0n8iv@cuG0dtsz0{PaDEfq-Xm39cy|$|L zGcZfAr^we^{1T;U)HRwB(`@GvLX-A2$#b6=K@%>DCH5u|!m4&Lyu7Q}cOz}n1mj8E zg#7iECzFaR?Iol-c7XS+->8YO~rFbIJ&A@834xE;Dz)md;oY->cV;nDn;HVFRvEXV{ z)Zd6~Ppyi!nR~(&B}P>3wKA;`s<^0?$df-=_r1M81e`J)S;E1Nt16@fwMVw|Cpi zwyhTkOai^pz){@2ifA+Cow;SU2fs;&%X`$e@8N%}#@@c@YqOAG*%1dGr(gzWf<;Kh z4(mYx6CsB(uo1q9A0t)rt5M8 zBU&#Ud>Uk65_hY<1f6A0@CiouC!Dy?+8y;A<}FlQZiRKn?c9SZa8psX_54X}(g${kwyYuvSOhOOP~akzVt_x+rMM3L9f&c`J%JX~ zC%z6pFd8_ZdJe$u?Dy{od?W{R{h5Q=2QEquX0T$cL_r*G6}pBca({sK8(KT@h!_Vq zX&ZH7{*~|)d$F{8y>Z#kvqpJ|EZ?t}cNyjLW%({y9@{87amhkeFI*`K9kOtPUI-76 z!{G*7>>9z962#zRF2O?wg7vYv0sz7%9e$+*hPvNvBE`$;LlPHuh;x zr!^>K1NQQB5xarzYfW02yxS=v=vV0P5PaPX+V(fg75l{%iaiI93D3EB-bYz2QeTx~ z_u#3(a}}Oj@m%dz?2n;ts8X?ii1g3MUx@M-k)A-=T%_Gdcj9>&^(&B0LcJH|tw@yu zd`tyd+2(>tXBi)s@iV!gz*0~!MZD*T?}CD<1y=p7VA|O>dv3uw=OUk1Fdg6Lou6ND zLBWNo_1_u{!V(Bh=`Iu9G;S*jX&T>`1`^k|@Xv7l-~=~mzmeM^84i-3dQs9j9D(0) zm`8~pV*xF}nvsaa&ktW3+{>{zg&OFkjrcg$5#fTF2DU*ZV^6>u(ya<#9y~x;>R1C6 zZ^Tbnb^02(YtiZJ@EyAe9?i#)`uk|}e&nKM_A!ChQEx~@KUmXKK6zAM)$yh}i?ICqK zF18#};K@j4p;%lILL|iUdOviYfesP%K&->Bt%dBkJ%!fcrg5C74)ERLJ$2|nh@qz* zULxM~!ws$LkJ4O@q6g|FG!Fgnnn^UkAQlWI2(xcz6jNM5O5pH6*(^B$(&&TEBIbc9 zkZ=d$8*bs=7@_6mrV)1_v0-s4D-NttmtdVB6B)Y**mBc#F**P(J1hvTVQAvRyaMfi zr+N&K83-6x$XoQoyB`DjgBpm*i^46&9Z+lz^9+An2v*1w4AIZYFfiwf9*C2NhVpdK z;=?7_r9udZ-N{HAZeb3^KBps(jiA9GF$IRXOJ;0RNC}9Hz38gP0=xgc_lvb>I{B+PT+5@uBfP7s*jvh{~@6-=DZ!sq#Z{Lr|A0nxy(AoIT4&~z8 z9LkFoKx;H~7P|m1Lwvzy=;1hDU`>Y2UnN=KGfy6e{Xq-!T$pYVG< zS#Lh5*?mEW(fv=~6+*)925L~BV(fAPP&(g|0O^BC{)+SElm<+Kk-;fLd>tB+5%JBU z2P%abGnoev59w9IyI3WT6NY`kJS47Gd``~>XQXfR%1c>bT%|4F+31HTfZVNf)jSpRc$_$f5) zkhoy{XgV8=ehNiDN!6x$PoUqO1gF5>(@5ZWd<}W=$hA;dT}HWzA|IMUQxVI6oQe?I zqvR0uRf0Q>;dhJv4BJg3l3aZgjHF>9AI=s;n0>(~*^0uvOJWgwJ@}l_(ao|Wp-H3o z4Z3;EPgR+!^CJh72YLS#y&M90!RW^>`WeTM;0Xed1Alr)%&PQ|FUAYTjr!Lntd9)h zOfV(UTsZjn+oVbN&I5Bsine*ZjIw;x5W5WDOJg(e?TMX-?;Bz)_cD0@(K6mu|7as{ z7biYLH13NnQyZ<}d;}UkY6=!TtmAmSz`+{36k(E&NHk(QKEUGQ070mD#R3FKkuh+A z!siBWGwQ68gxCdotv|TJsCw`BQvRaZIXJJvflv0m@Hht%5nBZ+f4;f zPldsWpFeoOz`y@@WQaXhEO|9sSFvKMm{>&m4YKwL$h+^-wk4HtbN9sv)c5H1D1 zT*Si(r2i!(q8reADSX|5Zh$_BKBvK-HPI>$Q_C9FM0Pr@<`4DbMHJk zM`;#-bMOh{S{)Kq>aUoxbRNMqWT8n%w(oQ`5G$P-Lv=$FPKID^wA%8RT z1~LL-^p``Kr-6 z&(35iO?dkp9%RJF$hRT)Ej+jhqxc}Ijd=cu=S|$a4B^`Hb9nmkT#W1EEqI>6vr1X3 z+zEJ(NY{XC?LtRp;=5g`fCR4rrfc!<9&oh~-|Ix1LPbIpf+u`muS`>N(9dVLTd9Nr zy%1^G5XktZQ6CJ z8U$a~DQhssCcW47=yfHyMD7p+juk?F71DHhkHw@FeXU92#$Lv9V6~`Kl>drR=Lw1_ z%Q|H_{xvC!lzQNJt3n&I8IoyMKCkE7MZP_m4~l#+nO`sR>-D@r_dLv}d3xDc$~TER z))E6gh5EnL=tc=s>d7*2D>Ou(*YUFZh& z?(Q=h$KcoBIu2=R!9UL3GoiqZv|8A4|&VT3zo8(N{A# z#CcMz+$&03Fq0^;79lgfv6hx*Js?*@zT|3)GJBLxjMpBHN}b@$8EaGicSog;ECnZ| zU8xv_3D<{0%oJK0TFQxZOxn&6Fe5h$ky1a~1(hq2Bj-pXYgljCl68VJl4Bg3dR>xM zzY_i3jeoR5Eu*lKG9Z^YO3HQ_J&&IUDSJ5)UWRNX)F)dmX+sPRC>zHcqaSi)qF%TH zoGEukQ(p)w$vtU<*TXJ{g{G|qH_5g1c`osjyh!Kw*dCj~J91B2Wy(d$cMZx?QZi^F zZ=@tX$*va)o#(jeavqP_XRnhfTkTOcV${0@o?MAi+Ic1LSuQXhtp_R0KTQjo(R%zW zOZ843wqiU7M!Zd_7PP0luk^aYQM^wdvjVf#(3SBm48El3phe;=F|;_{>P|fGMoTPR zQqnhA1@3WXtpz2;+yV{8x7 z&W7N7e{wsHU8pp|OG($9JA@S5F)lgM`kC#=j(nrQ{SM3;QqhQK4QAFn=m_=X)3F)P ziACt889r1PX*ws2eo~sv73*${NZm&a;FN*lNmuxCow+W^w$$-6<8C9c_$=vg-_WRx=6j*=rOA1@BDR7v^aiMX#w?Yqgt0ei z2Irbl$Cd65e3OfEPTYZ#mC9YPywc0y?BJ@&wUxaY(BwY-s(HX?sgQK~j)r!WwqLHb zT&39C=rx8?O>Yx`T<*ei560#y(<-o|r0A#2!Z_S#%^EjW1EeZf9ePHb3$%G>+WK03 z6j~!v%2~h_jC-uq`tw;hEJ8bSlr1^>SZY73{c^F!891bT6k~NaFXNbDzur3V(o$YJzMs5{V( zJ3mUr@K2~sa#m8hQo;{?>P~zObl@30ybs%CQk47f4B0aTP?2$8j@yuR) zqCM~EbttnJ|FlTO*qw7`FP_4K|Q-`-d9 zU^QBmA!g0b<=^kQ?#jc*bH8$vvg_s5>)p$)JJ|o@)5mkaVO4g{syXOgwc?-tdLU1i8M|S`jPV3nvP_&# zrpg(aVnj$ryskmYNOLN>#sSi!xDqP`t$5zbbT$4dpmHNh?m$n*`%2_+0|6yG@4Nya%9AIe#nE_1!A~m3J1?nw9mL0=?^?8zu}B5FostYsoH_gC39f{f+~A&)@mJ0y zquh%Td8W7;<-B{NK*wnz$PGz3%ZxFXfgV~HgQ_~vKpP|ZOi7KcXS6Z}zX;TL!R4_s zSPsjue1dXA9`}Gga&K(An*=tbRh~GEoy*su%_dMsyEhh=Tw+{aO8#2(MB7BU%6UH) zK3z}7LXU+#6FucTAywle|MKj?h#-^y%Yc(SL!+kB!?+RHk|U#S2QL1V)HSL!m-@Af>PvwWKQb(eQiaCS0+L zBh5l;->TU0({G*gk(!Y%K{^TP8l?Q)%$-OlBYg%b?(%hZBjt}y_anubMyGk3V#n|L zbrvH<7`w9;DMHwt%aI~{-MJ1ag5sT9k-~s=?m~)RKJDC(^c#LWxx$XOLxOW58Co$Z?|M+qHR=Y?PswuCov2KX z*Md8V^!2rH78^Zu>L*+v=CySIzxqZ2MgJv*$^Fws>uL z&6?S`$1C)RYa}xGa4q1>;8~alE7Ed&^Q>J)acD{Dg>fYa1Fi%$vvBIhc)NsPG>6u+ z0)5GIv+?On^ga{xUWt?+=J|PK?M+i^?uJiZE`9Rm|2U<-^62qgoSpSQkv-?3-K7P$ z-tjfm*T{M_>Ae5dZ5LGyr~LMkySKdiyPs#>@b!OrW9Mx@>b`_0vgrDw~ZpStvw&li2^qc?KDYLb0s|Nd}x@e3)x|JAx}Zv{SRzu}Rt zmdYKQzCXM57eBx74;%994{X_R|0Vx;U-YH2Cw9+FgTLpsnLp}#FNx1zA00ze?oZpk z_tUMQp;C_buw(GXC22HWcI(o|Z)r*K;EVqGKcD(T@)`%!C{_i*G|O==;zsX+bUh zDz2;41Zo7KC0x2aVJ|Jv1j>4iK5ONhguMpsdA=**WLYCl&H3>{C+I1$Kf`0=?QE{v z9IsuplD?ENw+tNE6MZ%MTgA}mrFb|GX;n(_X27LjSWD}Zs$B-WXnSc5XdSuJlUBg+ z6G%7hHSaIWc_a6HGG7PyW`QGbV-R0S-!kAupM!Xjhs34?7S(ts6!&j;hL5F9a zJXwi6Khnl+6z>w&2hK^HTExwY(chF8Z+7yt2z;0e=&RA!T48bLqK>>>B_Qa(amP*X zllvC(d}2thiPCE>hE3<$e;rDez=Dwjw7IEz@{?=6EN?&^G2*8o$ybRV?|ClJ%gXfB z;C&;YDMvXfdnm!mx*B?G=#%W@)8OvZ`+9HP0Aje2pCM8sOCgX?cO2 z2OQ%p+l1Bz-iE!MsqaOMly^vYLuj4QX#9pX z$H;gA=W9LwEfedt)V5}w-V)TY-ekhxj$8-74{pE;rf~RnGUdY8h!l=oFY;M{>qb7C z@QaWFekW7FcQYmYVx)j~Fok2ff+-x`Jxt-q_A`YeyY70VaAdogPC+?SIJ8g}do~wc zjAO<)onE9Er*J7!j3df1j*oea)6W$B+wt2SlK@|f^nRp6NC7QASK<4O|9RcNZ}}K& z$^yCemfU-v{jFd0<$mK@nZMzYt&<;r8~H^tKW9w+^QF7;ui1N{_t|dilq)WN>Wg~U znIyx338c*|E*>ZO8W< zryMbdsdRGbMWschwWZCa_mw_c`oq%KN`G1UUg;BMPnEq>_Q$fDowqx?od4|nuJfV! zkIv6qkiTHYg2Dww3yK%KxZt-7-d*tV)#in>7djVKEo@x4eBsK4cQ4$&@R^0rE&SfX zy$gS}FyHk#SDWiK*OcSNy!4NtcWM6%YtJU>d`7g^4RQ#c0R`s0ftE!#V3#;ALHPzQtUsrv7^$pd_ zs&A^kwfgqzmDP7v-&K82b$j)_)nBTVk5(M2ILF=SzSaG-`>^|z`?AVlrCRyVm4_;|%0E;pRp(Y+QB_{$ zt@2j|s&1+Jd{uMRs;bphcUOI}>ibo1RQ8g3W=Bb+J zYWCM0tLd%jt2t3~vZlXgxQ4>P`HkXq1RVD|b~ye8{8d&c3eH@V6^?a|PRCBiF2^26 zx1-n5?-+6@ol;lr&OB$nbB43fS>!BsmN*^G`A(O!(pl?la5g%ZIDO9L&YPXLIafGa zoI&Rr=Q?M|xzV}V+3DQs-0pnHxzqWW^9kpZ&Rx!DoXpI{%>^kP^ zbDeaZat*qMT?v=D+zO4JQC?JDQa-_Gk`8B zp#zoSHdVW}#n!g4>f3g8yKI*tZfP4ROVGs@FzvE#d`6qt%o16(w{bdY9ex4*|{zuig>{ zz_r!*B0@EKiNg34D$4RXO)J7HP;sURUw&LAdWpjL)F?{loQtC^ddwR0 zYSA`LX|t$at-l>`9o}Alhi@PdDg>xHN8 z)A5}h&WgKKUvD7fN2g|W3TJ3+F>Ak@D*D9>RE!$BM>I}iW1wZ6c2+iac{NPi-v93= zAh{eM9l?P{?UUnm8p75VrNyLq3dD0LL;w;!(*UsTcpQQYZ9s!IODLOfina}9Z7$$<#2MOZOxt~h(e=jA4pcVpBewpQY;C6KZq>1k zUz-})qS@rgXrc!7e*%PH4%4P-p)Ya>gB{u0yMhQ~jQ-yPy35>sd@+126G_vROawkXpf2E?FK`?h0#=R&$(04 z-tjSSQuQUHZ`;&h&yjb`6JHJNI|;(nhT?!aMcmaD5Bu|=Me$FnlSDp|CZXQJza#U-lX}=MQ zXx9E2S^yD>h{h z?xSrMB|N9YoA8IKA7YaQ^bu&d@gBj)AxK==YE``nwZR#i^wbIf1+9&$*W%a4&lbWL zW8AZS?g6yz!4+8)D#lo$5bm{UlLd_AXFzjOcE`*yuNb$@9zxc}uHBGPn^eM9HJEJF zV#NY9gTA6J?;vta?bPQESWk-*@?)ZwEUiPp<_Sz7^Ijz~uKz_0+T~5+TZvD=h|!}a zDG86a*B1Q}syloMSRl!!ga%aW6C;Qh*4vg9KO)G_mojbC*4qpsbh%)BxP{JaI0x0I zd3-~yvs<$1TA)tZ&`)jdEcUQMFjuL*L~IgS1!4ql~T`{i3 z;68lVQ2!1BT$3(SOB;ryA&9zLbEtxiTM(0Frj*_ zu`Ho85ZFG>1BGTWoGX<_og$C~=fw@QrdhQ#$0iX`A>`-ev_Qn5^rZMep98w^_K6`h z)3c(S%i)#qC!%xts6?)ZU*Tww99tw7!+tZ2i8_b>()M8ozJ8*sy_N*Ok6A+W)}cWN zgTmT(0#Cz!srP~nZP&n;l47w==EC(!Ar-y9CPDfum3th~^@s#R$(H2G6u_QchfzKSU@F0)4AI*vZU#~UVnHBR| zD<}tIzR6GEZu(UBm936rlfIqdHX1I)o1UjwTQc*y{pd3yW`$C*gB*(6vcc4 zUETyOn%*%Xydw-6`jPN7SZ&b*@U+4u6$?YBcZ|Mm3Ii`d$)~Ky70125GR4jKR(1z} zwJR969rVVb0TD98k@>qrH|$%|&(QNHMfg4S>XiYW+MI5dCnrZO0dYlfV&D zO{nH4!IJ3tS>cUvMA4&WeKmy!OrmqjjUKh4DjsjKYhRl#v<%fT6J!#tQX)Brz;UI& zU#yiN8$%}5ERJh^GS*<0Pw>cWutSKj5wI;*Ywg!Q9v(JaG#E4}7&Hh&InoRLu|}&+ zifzX#jvE|Agg_~6wOg|yvolG8-_RRXt39B-`+MPbYzI&6JQK-^e>XlWHJ+Mhf=NgW zNwiG5aB)qx2`~Q@jX1MF`^t zntRAm0~3j6wb7ZJ2b$yxRJ%R{!|>HKKrkjxHN~E|vIqs z^+5+=7En3L(GN!I5Yg%!C6aHRjqu0PSz)|FK;l8H>^Y;jtzW`z zHFts88DnIu@A0dEnK3(J3owgrS~|w8_&XV^fI*EO4`EhG5~96dQ|>`aESTV0mk{G6 zzUVl2pVL z34>G}1Q?3>l5vol6r=)`M(r9#bx<&$rDIv`$0^h_Fq)`&e3p#}JUF%OC7;!E1c<#Q zI{r`io^(g(TbML8ch%6{81W2P4%K12&SMk|b)o57w7z`4JW@U;f~r*-(wOTkA6itjq^eGf~{d$35U z9$XKsg0Ij$NGXvWxdu2ktGUf!51<4et>|I`R*9XjK-mpd7+==e9|r^WoBI1uuswQy zX2fqh7<>=zw82n@@U5v0$|fNIi|ybE$ZkA3zCZ>V3v2u}gN2$;0`{w7V2J+1J0iDW zEqf1Z*^Oe=g%(AK!5WTW=xhI7DMaqI?Yxo?0vX%RED0tQ#n%hH>(%?;DjE

^0k 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 LF%JAUbKpM#v2)sX literal 0 HcmV?d00001 diff --git a/EdkShellBinPkg/bin/ia32/Apps/Cp.efi b/EdkShellBinPkg/bin/ia32/Apps/Cp.efi new file mode 100644 index 0000000000000000000000000000000000000000..af8be91b1f2d6f80019789be8b9de6380afa023c GIT binary patch literal 69632 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%0D0T0W#j5X_K5j9rFRyIy3jbY+G^UKFa;e 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 literal 0 HcmV?d00001 diff --git a/EdkShellBinPkg/bin/ia32/Apps/Drvcfg.efi b/EdkShellBinPkg/bin/ia32/Apps/Drvcfg.efi new file mode 100644 index 0000000000000000000000000000000000000000..c3fba1f320b7e853f5972cb08cc124fabf0edb3c GIT binary patch literal 65536 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 RfdLE*U|;|P|4T9O{{h^|&&>b; literal 0 HcmV?d00001 diff --git a/EdkShellBinPkg/bin/ia32/Apps/Drvdiag.efi b/EdkShellBinPkg/bin/ia32/Apps/Drvdiag.efi new file mode 100644 index 0000000000000000000000000000000000000000..7ec7aeb9b626bbcd402e3604e73acda38f9bf609 GIT binary patch literal 53248 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 ZLlhXIzz_w7C@@5UAqosp;C~zi{vS;x&FugH literal 0 HcmV?d00001 diff --git a/EdkShellBinPkg/bin/ia32/Apps/Guid.efi b/EdkShellBinPkg/bin/ia32/Apps/Guid.efi new file mode 100644 index 0000000000000000000000000000000000000000..00ec9a077e080c4f6fb4b332bb7b14e53b7bab86 GIT binary patch literal 36864 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 DQN)YU literal 0 HcmV?d00001 diff --git a/EdkShellBinPkg/bin/ia32/Apps/IpConfig.efi b/EdkShellBinPkg/bin/ia32/Apps/IpConfig.efi new file mode 100644 index 0000000000000000000000000000000000000000..d121b0a028d30d7d2a902c6036254e291bcb9db2 GIT binary patch literal 34592 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 D<)CeA literal 0 HcmV?d00001 diff --git a/EdkShellBinPkg/bin/ia32/Apps/Load.efi b/EdkShellBinPkg/bin/ia32/Apps/Load.efi new file mode 100644 index 0000000000000000000000000000000000000000..0c1459fa96dab37f03c15ddfa919cc79209c4428 GIT binary patch literal 40960 zcmeHw4|r77nfIM!fB^<(qCume1`P!z(3vFU-vIeTMk8f(CNN5?wxSRRq<~}w(UO{U zpk)}-g4NdU+KLswwY#kK>sq8O?FLE-xM(A#Eh^mx8`~QvZPRU52A!Jk_j}L1nMnxR z?tb4s&-XkTo;&B>bI+gm|NEZzoC&^9X#eF;`+vFT|GkcWucj@rWDgmzOPf4>qGj9! z&5!D8|8X_G?!@IXN)+a&TGQI+Zd|o?{oR_DH3qeS zS;l0U@u}9d+Kk81+ffRPQeczOB1w6}bX zv(2mf^{YxXEqd4%_t^vSpshjw<9K=A*4{i}{}fGY={cUIX(22logtlHeV@~u`VJc# z*<;?5(dLs{vn}pD*|P`jp3?EQb+c`PX3?5vg+lBQ##du}68i<#*z}KH!>-N_@5yYA z{t5KbKQm3!+Jc=81Sm8M?c(glFJ8JDim$ zi+el$p_a@^#^^6yE&URg$1!T?VZMBd0QlF8)t^)E005?L>3Pip^d3ixHlH5Qr%z-@ z+qU+weT}xpqMvcdb7(gk1oZ}8GaERzegP~GJ&PCmXQpB;t_Ph)-^j)0Y*~7>%w|h0 zk2d#f_fL;D_hsEbmEVzhp%=_q{|Q+KnKhChI)KW?_!L6huqIpAq`%#OHj!hFJX!zk zbm`QS2Lz6I->`&^n#0|04i~oKg@&0eP1l4vGY7Wn{~+DXfqPB>nKo}%%-hxG>x%ih zN*|Gwqk_1_jJ789`l_}{3IUi ziUpGih(VpR51@x*-_dQy!sCG#g)FfcucL2UW5HD1n~H9BX_2eq zzEnIgt08ona2wnkr}yO(YiHup9lkdpu&IW)*XGy%5j0TpnD`Rl59r^*6w$+0VcD-l zSgra`#uC7j@we{y@$n%a(T7=W-fn-JuRj33p zfupD|2i* z|Ay${yckH1dflgnh&Fd?&DX?(_IT|q|Db`g>tDQ*)7tlAxR##pf>>?AWJ9R#Gq6h3 zgGn@T1A*meLJ4@#l^w1FoglMg!X8*r%B(4_EBatEt~dCi_;d)aLEXQ*L=3SZ!XM%H0LG z+}0ks_lVqCz^&M%UepOd^PeVLgoEX=DF<*LZMJFQxozI0U$Nh38{{3?AM^IpsBf_g zS|zbb%O8}XfF?}RSE2imX&GaA>w?XAcRQ}glF;53c*U0WVC}!;NShcmlY&_y(1X)5 zZnHD=FdIRF6#r41(!!8BXj@EiS0O3*6~Nrkqqcc_VP(3YR-txGv?fb$mbSS9$=GOf zmlhe*vloMQcvJWmOO_H#M%(N0b~&P7M0J}l8ITb$UmS`FV`U1iLSFdVoRv5z=;y)c z$AhOE^e4p&5{VA4Zj29sZqKFw`*e@5ziG~zY=#4l*riiCi6@^e}G^T4Hj8*&3hPj+(|;R&jgJ za~S%_7&f+qw&FX~2}0?g7b^@Sq^J)a=@*~2#;)I1Xs`g52nJ`I7@Wi!n#`ax762@% z4w_XBHPM5Hw}aZnvf`8(FzhML1LMJBAV&#Le2M@GA0ju9n#Q=TF*b>S3X}J!X#q%v zFvD{J-+;lqr(_7-^0br-IJ_4ANOS=owa67PYa9)n;~NFVfZr;%mfX&eA6Pd#Y=SMI zzYOg{i%>VZgr0{8l3B_D_!aAg49%B{z8jX-cu$)a>SD(®03MtW}XhIV4ur`Rsq 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 literal 0 HcmV?d00001 diff --git a/EdkShellBinPkg/bin/ia32/Apps/Mount.efi b/EdkShellBinPkg/bin/ia32/Apps/Mount.efi new file mode 100644 index 0000000000000000000000000000000000000000..43e4c22220e6ff5ad94bbec8f9b3addc61c0b823 GIT binary patch literal 40960 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 Bq)Pw* literal 0 HcmV?d00001 diff --git a/EdkShellBinPkg/bin/ia32/Apps/NShell.efi b/EdkShellBinPkg/bin/ia32/Apps/NShell.efi new file mode 100644 index 0000000000000000000000000000000000000000..9d1b2d12a87f3241a74bf55447113973c099112f GIT binary patch literal 45056 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 literal 0 HcmV?d00001 diff --git a/EdkShellBinPkg/bin/ia32/Apps/Resets.efi b/EdkShellBinPkg/bin/ia32/Apps/Resets.efi new file mode 100644 index 0000000000000000000000000000000000000000..ec6a92a449f2c0c3c14376bf5ab91c0b01834862 GIT binary patch literal 32768 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 literal 0 HcmV?d00001 diff --git a/EdkShellBinPkg/bin/ia32/Apps/Rm.efi b/EdkShellBinPkg/bin/ia32/Apps/Rm.efi new file mode 100644 index 0000000000000000000000000000000000000000..17fe4be8e866a3fb19a769c38e1f90d32b38c83f GIT binary patch literal 40960 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

6(TB_pUe{?cXyT3^XY!R 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 TlWc|U;~Iq@{r|83;|lx}46EmY literal 0 HcmV?d00001 diff --git a/EdkShellBinPkg/bin/ia32/Apps/TelnetMgmt.efi b/EdkShellBinPkg/bin/ia32/Apps/TelnetMgmt.efi new file mode 100644 index 0000000000000000000000000000000000000000..9183f3b931ea6f17c937914b90026f7b65dff0fa GIT binary patch literal 25216 zcmeHve|%KcnfIM!fFT)}i3AM>YtT?Yf=+%CG9)1(7b9hGCNPNNFXV?qL`5>A;F1Df zs0`QaV%NIZ(p^~Deyq}!*R?<`wt>YC*Bq7+^ z&-=&w$2)lMx%auxdCqg5^PJ~-&T~%m-J<->zt+FG=KsBlepOKx*wP0P>{7-~%CwEj z*jueAd-LR{IcbW*tE)!5y9wrH$HkvjZn;b15tfkx^ELT%C!hZEL+fpdvTHDVf4S0M zfpKkk)rK(ezJ@-sU+gQ(fxkROx%1kU%frh7Je@21-er~p@#ZK>>$U4wt-XJRqPze> zkmpvj9D-Ln@SV>=y+`X=*RJm2OS}3^yhd@is|Rf2?Vtp{DBq4aYWeM`d~228PRODo zM|?ZU9<-~cB(PH!XJm0!7G1J9CksOsJ+kPPMV~D8vd~qhU-vlzhBj7Fv=ff)t<4!n z#w*H}?lBmZ5Y)jP+KaYB2X9l{#%E3gdN?gMQxEQG2$hraJ`(mfrW=a|VRtN7_w5OU`~zFH8#Cp{7S-?@ znIlNwZhVNY903bky7O@lg;0Z>7|X$Cn(+)K2&CAq?q&P22}${kHCn_c2R?Cd z1fg3519qbp3{!3q=tpR`#qI&gUR2$$HSbp<*9@RlBWVdD<4q!;W-3Z?Yj+`NwD|T0 z^x%HI*6ugT@QzOIQ2T`p-owyCMq-Rz#w(~JCG|0R3dS26m5}ij#l7ztbf|yV0YC>R z#nn0pC)pTjyyOy}jYmL+{C^+lu0v|SzcEMm#lb?nzri`6{-r?juhvazjWQmV^?~O) zRO^VUyR_zA=?~qk`*!u`x41?QP%nqEP~bXZ3oOMLZFo)4tR%?{V~PozoMbc87-zz= ztg22!kszZ3h7L^W@80&4r$;F6!?<3>_20NoiuqmAuAT!9W@a3B6bTlXTI~v_66Tld zaMt$IVRQ{o4()tiBvTJMwBu>fpd;2Lq1#`Hj4p01KHYsCv;tonjJ!!=7@}&Qj{kg) zmc=!nMT0=^GKq}SgI%lJiLQ2OMp{(uioK)zx~BUaubsAWi#tL)a=)TTO-*L92@RY8e%v4XAR1{K4Pa-a}5J{!crmG3qw|Kyq zYr*5uU_uWX>A|?J_KZ^#(V!7kdvsrq*Oz!`+%3X452zGH-K^cra!@l}=iTaj$|V2*x}T z(_>-IvM@bEF-KB6V%gn)_gR0x9&~ctDfl=9NYy+ke$dCArb*Yw@8$e#sK?Bnircu7el~aU5#@?j1JZx9OUnWky9sM9) zt({f<&S=0+u^YW&GkC#@Lac%BV!UgyW71W)(w6|?x@RfW^i;Qej z|Hl@yGs6xhxhn$AXp~?9uHzwJt|w&IK@gq(Jxe=>bgUxbA!e0?Mm#|c7=yvqv$W$*fMT&mxAADcl(jDrwP8%O z3MG! z+fPT*V&9ETPtwz~ZBQ@CAv^6iMhjh`hab_ssULI6*L&=3a148R?&`V>M;I}L6kayv zoV_#Zru$R66T;9TG)X`}+AOfS8{i}-lFivxWlA1wQVvkix&a*04?y4bV76|HrX8WG zbnnF-dP~9UX|PzS(F+($CsO>J7P)$`Pp@_8KA|o4T~V8?eHS@P4O;iD=oZH9=T}{9 z+!z3uOvIzq6I1&7VjD&sM*OT2Zou6ZUXFVjB=tPIYNC-zpHsJkdvf{!x-xJyLYK>C zsSHoHWY>s>U=(8aS?mh}7>ym#v=}@&I_uQlx6OjtEw;ugrA?qNJ8jmg+hLE=)Wn60 zi^p=T?oV+7^&E5%(*i1|tL~^Df;2I-*%?YC$7&n#DOlec%{YR& zs>DWhmn8c8i(79WV8^7jHSL4bb!dbKwiY9_zD+#Y+D7aK0E6O;jyZrQs#oporx`I( zbb<2d_$TnJH9M5>wJq?Ip{a$T#*H#rJxnEFF?fJGfC)<)Y*VhiT)t6gDoT7W_QRGNKwU!XG=?&>jM1pr@$TC&afCUA z40;-jYx9I)p!e3$i~i?eyytWD;$_lxBE4Betwv?E$h-86RAYu#jd%2^%UMGQ#slgpkAkoMWDcm>kT^AgM&V=>WH{tqP#w5(CjZS{wfR$&6;Zevj>}(V@H>oXZmtP-4 zJnfh#U~CXtLi;>j#$4LNb8N0hGi{0@Vl8dM99zU~R@hjlxHOJ!OR%?r6Caa@jbZXA zB3{adct4jx%q6VVx3sHb9nXNgPX_x!-0`Ny0X<;Y(W_@~9U=fuT9eh|o(AJ^GVUr! zGW<}E#W0v3Z}qEASwGsE%W1Lgm>8Bn#cB~kz1$KhgMSBvBy3rLa+M^amcb~^*ce~vS49YWSPLe_L}fyk`J@t{jYU~zrEW4amACSHFB-Jo8@b;h)D z-O-XAXfQ4l4o(_ndpi7XFdm&Rz5~&3_XZqI z?+lEf(eEEf&|cgctBUbn-h!BvZ584s{0~jVsN- zW`Ny-d;%?qCDcS{-Ir054qU8!u|)A8(xp_fD6&~{74lr19N(79%<%;qeIin(q(qdG z9StHXc4I|>h(#=VPaQMtT9+%T9?*RUK6+hydz2nLfDk$J)u```t{y-Dt##n@S$sxB ztGzNd>g$py+N-0Z!E+W)2K=MeoUMczNk)A~Vi|4fK}7aB(clqXh2W3Ef%k{UO9|3@ zx-l&7{=h`&qR_c_gDeBqp3Bh5CFLEkUa`zu)piv0pYS#*-p>DVCoB zH!Y7|Ux#sU^f%0gD?pAx@S}Cx3Dj%dnt`NO;8Iie@KXdvYjUhnO7%#LS3UfFh`hCi zb2yrkiJCfZZGlkeXQ7^<4v56KO^heTP&jt1l18H+-8=bRao~HU_5F<2d`5{}3S|!% z9TF&UZwD^;X|Khk!jpPNYh}NpHS}YmAMWUUguG|A9{+3<5gbuJ)+vsb;Mr)P9nvitbE07~pU!|M{#fNSmb*2+puW5ufuid@$0_?8=wD;|GENGOEp9Qe-3Ij86rYi zi)C5&qd+D@9;JH|9>JB;-6S49v2{1%0hSI9qWca!a`3R!I8KF#`e9c2N~sHe!U5LZu)*n?|!w+WA>ueT9QmYu5~{b}?pl zxj-fiD_}W}h%EW4*C(RBbC8>jv26q~(YdMcYJ&Y2(JzTLY^7uck5xev6_D}56o>9R zwPWx+j_7>!jjt4zUXwsXs{0_e8j8)28%EC7eLWsrhk}WZ-pW0#y@Rz8j7^Ues1&*D zkS~E*d9}q6j0U=v>;|$}t-2p+v=gzs;ad+Rid&<>)~I?y_nm;cwPJ>z^BaZ2Z8*Ez zXeEXnnA${CJ*hRHRIp<984#BqJSpq05>v*}y;IcXCw2iw7rJjW80#+)6k$RA#%l8!T2?cWMt zxPF4`JGgprDKIvFny9$n$MqXrnRx&0<%+uw*Iv9oi}LAQ>;d5UZj?Jv{u;1#DCgkX zh-Wv-@8kLu&zGXUl8c`$H!a$7GjpBhQ|_3tE_YV$ zCFAg(ojV@)OE1gGosfIEa8mG3kdWWl7MDFo4>_cH(VBcnMB6w=VP=sT)|5}2gQ4d; zLdg2OLD^0bf2W+?I1c$hXO|Y+2utVG&Szk$gLXh zC)XdMYP|@_`r2#Zr#O+ZlBj7p#P{mCXg4kV|qaP5J0L_Pb_aFdz=3?lGM1kA8_n zs&-oW=&dM%dE`_D?Qk&@5sex62HnTL@=rvZ3H=}rTpHHQ9teL&28Ke2HXi#az)mO? zlrY{B?3jN1sUILBP(C{EI`s89aJ6)C@Y5%_J*ulGM6F&(9k||C!*y5;!|y{GkVy1_ zPg?={g=`l#`4Tc=hFWoff~9DDwd)Y(0-UlN*kVU55qm*)5ag|8n2?u~?sz$BBhkpE zDO3PYwRU72uo~~<21INMrZWb|u6^v>luP_|7Ct5r|T?R}(np?TN}QJ(t2O3^d0 zh5#oH5s~x=nAtu&(=U-&x(QDUgzC_LERi^HP6aR(7y7aI~8uI)R;yuz!n8j-J}HncQN&eOOIR3t|!r1y2xjNK2oUF#*3QBiKz@1&%s4X#L;C{` z{;b6x2s5|`Y9KP&Y&AAYKCrKS4yAiM2<+whFga@ntseu8=1B>E4&)D`wbSR=A=bK> z?N(xLBEuF)IqBbo1w_6oS86L%N}q3US!_cdhgu{IyW_znAhGqh0uPl0i!C=~wj8e` zNr@R5u!}4fa#sOkA=aQwCt;SRfe1GHA{g&@dyRB)$Pm>61KMdNQ(x}kTz8~82L2!? zF}t~SizlopU{SKX$HnHV>JWyR!G+K+Zmtf%ntuGkctcnuI`cegx#|=L31GM{*rxr3 zbQg*;fCl)n^4YOVz?s!LEGo`FAhSabq1I_Q88O7wTk(_DBjO1fENH{K>^>rsV4PkT zt^sa_<{DkZ@&ZbaCn~Aa`zm%Ce~l)E8$x0`9zh2<@#QQsZ8|_=rp9CM#EN8X*;Qc+ zcxD1!HBpjoErzbrg9uiTZ#yEXk9hri?`1jy?xsDWC5g`X_NWs#-?j=b^mbtc% z<%?j(wLMLu$xh=OPp}Itvi>yj0f!xW+SGn28|GR%k@FOC!L;jy=4t2CBjYFrz_AoV zT2g2zQik}7ZT{OL2yO&>PS8OX0%_tN%#0vDLos=gWI_9QS(rS~ zTXzSkb!rb%CNOWvOn$dxMDw=citUfy1{1zX@UC#jSP2e=+0yB{T@5z0-lE3YsQA ze3$Ep*y-4{K*r92_`rbiOZ0QT_|B{ya8}7xqjgx~^bnpUzak(*0!1Is0|r)1Qh-oF z$`qSA)>sd5qO!jEk&CpjODwncOP2*Hh_e8*nadAf19Rl{xtpjabg(0ViUzY<2U9GXaJ-y!QzA+;K_w@lf-~(!;KHxg>giP068(( z$I=iUz69LJl^HS&I58$1>mdX=2|%YGkKyc&xn4|8n%L1n`*&o|+W5roq+xwMf-2d2_)u#3xZBzgB`!W#1ZFhX9iY zE{vN+L?~4B!X8pSax}U5g%AMCUJ>${sw&3I+OJ3W%4Hy|6}IiUzY5_kllXF(fU|%E zb63rBiMlwq(%&HWT@$h6m~u)Ot7s@~U(~^LfZNKTU%0(b|Bvx=GV*i@b>Vr^cH0PS zlh8AP<*htmy(Lm5v5-#0aha?J<7qRL;adJ9Y0No(@PkgAM+?)h*=PtH?F#o?O!qd0 zcC$ihzS5+|pn}wb7Bw8vU@YnMWj(s1~(W4};jda>6kcRq2B zqc?VoIT^rA%BsQy^f7B>Mp|M9;3&OfT_ez8zcInHZlG1e@HB!4T*4dZ!6NawnxPNq+(9ChbW= zoBdkrjaYDp%W0qNZ}PCeMlOk;PVkeQpT@0k(?>aD_b}JNB!-KXkZTx= z>CYU*7^p4bloa8aCOpH0k2c{n7l;+>M+*31oMM+l8#4SNQ$ZW?hb}f&ZuNy?qyA~l zP9=glkXR5<+}+P2@Y>q!#H89HfVUF(4GF|u0>cDukw9dBBycx@_edZXP!f2MK!$&y zDHNFvog$FiE&xJhBxWCh1rmszJPC9(0C<@MVkstp`2;d@M0F~+;Iodv-+^raarj&U zLj<0YK+Jpze2l=KNFZ`W61bnhf0sb~;f4erA@C^)fhL^w+0zDFl0~r!nPaxO3=ux%>ypzC@63D~!f~744et>xk zOzh%H;4T6Yuo8$J6$yNXK+bUhb1YyhfiD0EO|S`qU4-nFkTd~tE(YZ9B_y3`w!~~e zVw+LLE?z@?T?eu_g0MwE_7HMAAUGx-cKqTup@&Ue`pIZX{n+5eZS_13o{bJz9C2I z%v9a3ZI7aVG-^!L;2aX(wpbRaWWc$a<*@FYUijk`7!)f!D3@m&#K9BL*U5)9NV}VXOjfu zh*8|J9|5H$cm@gHNy(@Spy9H&I2O2|hYV#8eA~cw~^lAfNY!eS4sIoGF#v2ht6#M_*9LeMDpp|>qXRyLkGtUw?A~yBELd%h23uW;M$a6 zJBdIGQ7aKF!HUsI#S10dbQlqdYv&LNKBXdHBMf zo_Q-}iw2FK>u_MC(67Vw_CTm!RE9vGxfuR1`Vv}ewX$B+8hV6hPSM z>~Vp9A-`G=;y>D1j7^@f65OTB*FLs|Gcgbtr+g%OIC2O*l#rYBsJAtOo@HwoJEx*M z?gV1t*_SRlVfTk7vK9w3Q*se|Jv7xK6hFg$NVOd-zr!M|qpD<@^2osC!Fyn|DJKj_ zfko$_pmQ;KgqB(?>=?Ga&<5*!Xz+Kew~{jmEoWha3La?0L)St${rTI+RP)r$Cv~x_ za9lx2s;2hI3YC|y$Bf=6RS-s^FzG^aoiS}pqZh#MR1M@$`9FZHo2c+g0ezRf>`l# z38J0&ZKdMw!SzR6aa^C_vR5hY1Gs*S>ol%+ahbNnoKGSjV%n3PfoVH}@h#19TiAhn zTKMW%Ejok)0a8@Zv}~*4eZLT9BX$FXs2$It!r*Vs0-@PNpaO3(5fBbglG98Tn@SZE zPUKFjTT29H_7GcV@|W^oqS67Y(j-yo;`0qz7A{b*k%FQ={n*=%%-6N|@pn|nWiz4Q zVBGiz_5fQxG6dpskS7qazy9X$gqCm%9|s8@dXI0&!ojVaw0ifiZweHF@Eu9$FY!!nx*L+-yaNUY)fV#1NAwTPKF5V&PVg~|t?;^i%=5_{s-}vE;E%)X}{^a@g%o$2p zV5Z8u%y+A-Hs56#R#qu%mHTiHEB7jQsPX%Z`g z$+$Nu6-u76Sh*kn^3d1iz}bkW<;r^0i2%adVc?D7{~ba})d>QA53c)_hj7O>F{HK} zb@G%MxTctxQ!c1i2de9UyGB_7d`e^G7pT1$Jd^)C)V?3wNsdWDLdj1UZ%v|=b$DB! zY-5e!GYkr=fDyslN<6I>d~Za3N+}Ogny1`=@8I zCdYY-AJ3EmvF`_^Jn@wv1iHT$W)hsH?N_#_>zZ&#GOe+=e+f7n;L)c{i}~P-8GIAyU?s1}#QAe`{+NjXbm@ z|4AOLH>p31#MrLDc&^5^3Nj`aa$bEtet9bQjxpi>J5f@ zE`meNAE=9iB{!JHaBqd5L-#@SU+U@?rCRh?Ql-tLHh)q2#h*i;GtAQV!E~W^_`#uE z@Z-S}TEZrwhqPR@W_bdS7HYX^Rp;WF_LaYZ@H$|Gaq(BHEK=?eR*INX<|+6}6Eg*G z0KdcGOZbKO%ZJe?(&ucYEK^#RM=-3^TxiG*XoEdm0f`TVFGMb6k>Hg0K49I8`*O^O z8(=LhIY_u)SlqDrh4_B7uwY0J2(QB)-L1I7xE{l`AJQklBCZl#3vjK( zwF%eW0_5wbDehL3yhzLX@eha7Y)<7=O*$R7vbo=`^Z>?kv(2tddZGRLYfhZb`um%d zy|1iU?|uBfn?_gPi}zXbeP3bjvb(;4_iFjR`L*p=RQ8?D`leIaHKqEP@1_Z5ul?xx z+iRa*ddJe}&p-RS<-a+nzxt1-vz{HJbnQ-`{@71HF8ukze~9{3uXv9=gg*mX zlcIlo$opQ;nI#W@^^L3_?v?HNfBN+K?{7}M&)W4;?+2mVYoFcx%V*E$KC*Ao^~bt? zbUww;syn~)n+Y$zk@d|PlE2P1rT4zOeeMnaKJWK;f9LJzZmEI{iWJ_dkJ6sp-u8f z@66f5nXJMm&{{X(nf_WvHH^3DNh82x+%W}F$CM<-DrEz{G9pk+AAVsu8Pq2u*0=^G ze|+b!7Hu#xxDhM41wFWrr&`0VY^+Z0ez?%a7VBc>P{iWX}RrXwk)YcCJm-y_S`Y_hn&N=!%hCX`N;Yf_NF7>UoKX%-9^yK6+%m-R$G3amW|rUnav-ygOMF|m(c>pdp$0$ zE@iwZb@0Mf8|@QkZXU`AX6I_u;3{SjC_OB+b1>Xm$u1JsgPO_TLU6)Jy8$&wZ6ja< zb$lqlH=zyAGR7p9<}w~2gjPh(My}yjn^c?d96>G47^$mE0Aa+&KIS2=pe)woohvFy zg>!Hq&OCgT9Ft$pGUCya@RxccwbY7${8;^)hk9~d%UC8gGI^r6v^271NuSba0zX{e z(rQUMY?txOI$+DZ0c{YiG5aBVPJXO57ok5KO{-U&v9#w>&K#+s-?`#V;opGX_#ow> zW56}o;$h&{c%)XhgLUmD!43N=*YiVHX4iv1t|;hZhT>8u=n3S=&jTfT29B$=gG2EL z>d8>-p}2pIo^qbhyW9)@q*t+4K})~^y=BVJaD~1?@J3B#&Sr`DI@BM{h1SmvB*-Y56WxMN4_yf zFd260TBQUQYdPMo!TWOD8Mw;vlUb%2LXVr!?-|eyxh@pMu;Dy3{-nQKgXnECtlTDX zm+>3n%%U&?nhIVyUpTX+WQi^DINz+;o>W$XPsUVhO-m}DB<@_)XC6u7NmxDdV*L3q zYK$mT^H))rY2=9B2Z~LimW(;Ac+uj4lsJz$7pGz_EW|~7Olw|%Ckroy!>_dZsjrK` z7uP}5V9sntT+}80qz-ZZbM3TV*hS7S8GFh18sIM%JT?icO{RPnfiLPK`JxQTO#vcn z>zTYWj=Brm11QUdPW&q&>&j4OF&4QS|YI}oOaNPsN^_X zI2S9~(hZ2*Z!~H0oibU0cm6D2$7hM_hvXzrGIuxl&hc7l@_z&5Fay|SpmiVgKa97P zC>iHTT8u7fmDUKKMwt(fNu8G#bt?3oImQ}57Kq48t|L<4DJyzM39l1x4!tO1F4OsyHa-0W|G`Q2tyl-_d1jpd<|Hwz`Q?|znc{J(`+j==vH z8D$#qwp1wYbmFrFzTb-y_*+;KpC#~nS-L=PHcIRZtYe8&V0&5O;Fky6b?H3o#d0*@ zEOE@Ml_iWP+qI*eIoM0Iqn$36Xh*=&j(ZN?(av6$pnnSG2;f5u?#(C!K+$IhcW!)P+UhrdcKPof%&9%P^})?o{?o(J9~AB0H+cZQdqw5g zbN3@Bu~qVW|Ia7?u=9gt4&u|HIg)=Il2iHmkoT;gG(P{6ZODntmi#^L=~=R1K+ff= zWecCYd1WeR@<5>EXPGbI{YHsDX~_4XIhCO~m!UbGp*f$&U)#|;Z!hTAO8VB=|G!pl z07L$wwM9FM`itzvql@PhUtfGr@i&Y279T2px!5QkUE(QGOBR&eUGh&Q|51`tdPQkP z>BFV}Qu>|JAC$gU`gUnwsjF;U*=1$9WiOX^mQSlHuBxc2tGcmjSyf|IxauFOo~wGk z>QL1WtGcSDRyS5ZT>Tq5Y|MmK6car8o*AAp&pgipPr&n}XOHJu&wqG+>^bW>=Xu}r zq32VNy)dKjrNSQ`xk_s)ED=HoL*mtR`GdDhovt*!WW#eY@)s`59L z|5N#1WvucKl^<4qRQX9|e`R{rsH)5=SJk+x%c^p#uB^JcYD(4gs_W3FnN{AZ>Z-X_ zf38X=|9Ogtyc|W2;^&HAEIwL%ytt$IqvHPJQ6=t@OG_q}JY1rc{AIAU(v_uJ=~Jc8m;SW$KOwW6vT0@4m)%@;SK05%KP>MBWzhA&uArFZ+36WqxV&g$ z@wDQ);ung4UHnH-o>)>?GOuJ=$-0v5CEqN0zT`y7FH3%3l3toqIs^1?DqUN;we-o- z=So{k-z#RS_iqEoDWK>*UF})&Cv9jV|#p@Lr-f`Z^-fO*H?>*jq-qYU9*^6dBGW+ywM`dp1 zib}omxypAcr&fKX>h7vXs-CI(UR7(=8&$upI$t%WI;(no^@QpxswY)XuAWvsqq?wq zef2+9zg+#tYGsZBf1@Z5cwX?l z@WsL>Dt1@wsn}bwzv7vS1K{b!iX#N(-*@SODA3K_1g2v=;X*jDja#S`eoe)Ql)aDM`vcUGLO fI9JhA(Ffk`UZ*$PJJFl(E%3r~{r}$=lED80l#7zT literal 0 HcmV?d00001 diff --git a/EdkShellBinPkg/bin/ia32/Apps/Time.efi b/EdkShellBinPkg/bin/ia32/Apps/Time.efi new file mode 100644 index 0000000000000000000000000000000000000000..2266815a0907b729536b521f7022258452667b14 GIT binary patch literal 32768 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 literal 0 HcmV?d00001 diff --git a/EdkShellBinPkg/bin/ia32/Apps/Type.efi b/EdkShellBinPkg/bin/ia32/Apps/Type.efi new file mode 100644 index 0000000000000000000000000000000000000000..1c7337725854ce6fde18ad424c4d047f06ee5a77 GIT binary patch literal 40960 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�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 literal 0 HcmV?d00001 diff --git a/EdkShellBinPkg/bin/ia32/Apps/Unload.efi b/EdkShellBinPkg/bin/ia32/Apps/Unload.efi new file mode 100644 index 0000000000000000000000000000000000000000..68173480d6e61250e486945ab588d79d9a735a0f GIT binary patch literal 49152 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

Jaq7a;0r|(eC>~Z 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 z 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 literal 0 HcmV?d00001 diff --git a/EdkShellBinPkg/bin/ia32/Apps/comp.efi b/EdkShellBinPkg/bin/ia32/Apps/comp.efi new file mode 100644 index 0000000000000000000000000000000000000000..a07d00942231d8dc427c50257dfdc224174771e0 GIT binary patch literal 45056 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 F_}}iFY~26= literal 0 HcmV?d00001 diff --git a/EdkShellBinPkg/bin/ia32/Apps/dmem.efi b/EdkShellBinPkg/bin/ia32/Apps/dmem.efi new file mode 100644 index 0000000000000000000000000000000000000000..21fd2bd98ab659e937764858db84416268996b15 GIT binary patch literal 65536 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 HWeWTssNuBf literal 0 HcmV?d00001 diff --git a/EdkShellBinPkg/bin/ia32/Apps/dmpstore.efi b/EdkShellBinPkg/bin/ia32/Apps/dmpstore.efi new file mode 100644 index 0000000000000000000000000000000000000000..ff5d478efbe37f5d08a84508473757af410af069 GIT binary patch literal 40960 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 QV2A@l92nxje=`UEA9*v0DgXcg literal 0 HcmV?d00001 diff --git a/EdkShellBinPkg/bin/ia32/Apps/edit.efi b/EdkShellBinPkg/bin/ia32/Apps/edit.efi new file mode 100644 index 0000000000000000000000000000000000000000..d3bc52aaad69e789df95f6fd61eb32954efe92f5 GIT binary patch literal 69632 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 literal 0 HcmV?d00001 diff --git a/EdkShellBinPkg/bin/ia32/Apps/eficompress.efi b/EdkShellBinPkg/bin/ia32/Apps/eficompress.efi new file mode 100644 index 0000000000000000000000000000000000000000..17dc9b38b68a324789cb97df974a1e1027ddbda0 GIT binary patch literal 47808 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 SBzn literal 0 HcmV?d00001 diff --git a/EdkShellBinPkg/bin/ia32/Apps/efidecompress.efi b/EdkShellBinPkg/bin/ia32/Apps/efidecompress.efi new file mode 100644 index 0000000000000000000000000000000000000000..8b5102190d531e7e7ccd0b96f430de214cec1ff3 GIT binary patch literal 29536 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 e+f4-7@r=A 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¬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 literal 0 HcmV?d00001 diff --git a/EdkShellBinPkg/bin/ia32/Apps/hexedit.efi b/EdkShellBinPkg/bin/ia32/Apps/hexedit.efi new file mode 100644 index 0000000000000000000000000000000000000000..ca7d54df6acd9019ae7785988809106a2bd97e63 GIT binary patch literal 73344 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 Gf&TzD5uwlk literal 0 HcmV?d00001 diff --git a/EdkShellBinPkg/bin/ia32/Apps/legacyboot.efi b/EdkShellBinPkg/bin/ia32/Apps/legacyboot.efi new file mode 100644 index 0000000000000000000000000000000000000000..98e49c3389b37c6bcdf63665548c45f6f782eaad GIT binary patch literal 25056 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 Bjb#7; literal 0 HcmV?d00001 diff --git a/EdkShellBinPkg/bin/ia32/Apps/loadfv.efi b/EdkShellBinPkg/bin/ia32/Apps/loadfv.efi new file mode 100644 index 0000000000000000000000000000000000000000..9c24b10347ffae2612eb9077cfe9d87f3da355f6 GIT binary patch literal 24928 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 literal 0 HcmV?d00001 diff --git a/EdkShellBinPkg/bin/ia32/Apps/mem.efi b/EdkShellBinPkg/bin/ia32/Apps/mem.efi new file mode 100644 index 0000000000000000000000000000000000000000..551ea79046440dc89246766c3b2504a776b1cdba GIT binary patch literal 65536 zcmeIb4}4VBwJ&~>3@{`EnP|`ms8NHW1UmUkLJ~qk1_NbeCNTd00}43cACOD{EfnZL z%P{5@Tia{Q8OpSRN1+ghZR_6CXuyr>bejh5DEX+3e$`{FaV4mvfz?|1EU=3fG6 zZ{O#~`@9LCGy9yq*WP>WwbovH?X}lAxNg+`?!S(|yXHTxqT8uy^E0xN8tl==UXqhB zDqCBO?43rD9VxHX@@$uTJX?%nGu5;V1&93Xc(DPc5;pUx|N4Pnyzx(6?M#5v{L9w+ z0d#l~eu&UwBSm8V6(V=q(k1>S$oS$K{H(^c*+`L?f3q~LW7?W!cdxob)7~6`T;MEi zGEMlKrD=@`kLlYq1=18qQy@)&GzHQWNK+t9fiwlu6i8DbO@aT5DBunCc|uN`JLIx@ z^dIMITHv5{TgS%iz2mS|?EM}_;wxOO*?p_;!_S6yG`l|UTmspG&S+p`RNFWrS2Rbs)L1;`fkPLaFH6B}T;1d)+CK=6EjWctTk|QYTI4DC)l31r$rw;-)t{$rM5Cde`TgT_bwb99Q5rrdwnAYgv&?!lk~8;@yiIp{m+Jl6ZSPX-4A8;>x<)f03b>Fq;C@4NWP-Q)du z+fjdk$-FW8HfhdU*3rAlXvTkD$aT!4+sW%p)sVOXJxi-mCg%* z)w|n{=5E~u{uq5A8;_$Ypn6W4E@k$hQv^@f}Yji&g*SRYDeW z;hzB?at^rlH)>=EL1$NBW0%%;neT+uF}feA2c?b;3>>W(7``{;?E;zum^GL^UcF@{ zS~`xW(Fdz+PKvZ>Jdg1k(C~^R2ju?_;^*MSsvcfLTXEx4RB{ z+97E^H-;!O?$&=%Cs=_WfsGxS|ACOJBk0;2*tj>te>HwH{YCiA@@Iw@g}et_e0?O2 zF{!ikd#;qq;i?c?_6;NwdxY*b3MW7k+`eccRV{j%D#S=QEqcF=U!Mg^hUn>Q)rhur z_-!%~UJw>peKrDc$le&h(!j<(ZQUh-je6#~3H)uV@Z}Q>Q&FF0g0&U;CL%L7Ei?6> zLh(RcjQ+z3vi>b8u^Ke)CEa{QW{bxaCcw-BdS`^ZCxTuPxZJG=L2;Q+i^;QQ3#L>% z7`YO<;)q*cc!Bg6bdntuv<=pft3Ssz&~`beh0j6s47!fe#|aKl8j3m_FzG_B?vTfZ z-oiTr8~15#3(a2kNiUdq``r3pL?bEXj4nn}MYmlMa_#f@suIUPO8==6Mze?U=pj6! zw-lNNYSEC|{uazb1E(B)i`2k0biK9haPHRcVz}+zV~~BBhL6cC+!>pNGMO+7XQ5l) zV(HtMQC5Ar>Kmfp`>zyJZ?r{USVj6kEgTALJfyW<>hmQKWTbA9DrA?Mgk4y3T!%1& zqQ*q*_h4QDosjd`pxc;)uKu9wP{?}-nH&;8GW7{X?8i=EPQHHRN72lo7QKZ0<0N#x zMZsh9`qXN{N`&%0bq}l)CZxgu$DP47vN5(_)SAjdyX?dciSzZFblNYtqX;V z)}X6DE4YA#Z=~ zo~_w0O8c>l2ebbj8T;S1=IjTV_P=8R1#|uc|$axVah5!o!83&LpEQ#s( zT)k)#2~p5n009h74S8(J|8 zu8((kKSt$zFxC#n8V$j+0c?H(=akJL{F{irg3d_D6_E=1bRZ~P>DbnhyY)Og#d+Y0 z2KHwJT~Req%w?bg9Ut1My{y@D95mI62uvD~hl5|U0RmGpT+lmG)I!9l zJNS@MGK88(j)0z6b+Vk+YNu_jrL-el9@uEp+IR;$#TIybl%Mw(fiZyxjDkGW2sPVk zTvn-(`E*9yq?7inp=Pqus?fKFJXT5vRIDcyAHq3$&!rsh#CT<}*sNdf3Ar7rRxxfT ztJ@;n7RHEhuKrzVp%BJ!$kWskYM6x)YBG-5dAdcK%x?#Sefd4K7eS3ew_*Hvt{2M( zW>%lJ0qgY%%?}EnXwiSzM3PwCCZEsOpSy%Pw&aG;p|YY*+0fFIh6?mG!!_hMV?z^C z8oEHgQZ+^(cGfVKuM719Mg<7CZx<`Puk2{E0;fr0?-%JijT%@ye2ZA)--gtPCL(pQeyfR; z-s0QL8tut7fRvtqRG~gqRfta{k(bGs5VGg6=058gzwKxnCVgL~hBW|_z7Mt{cQzTI zO70%(mXp1B_D_UBp`qsUwjGA4Pq`@yI*-Fr2hg*g z^Mc;vFkXYs6YAMkOmjV^RR5B5M$ep;(T%y;A#e+rLn%VX_t_b_HJS)+$EpXskn44%h z(D8Zq%AA?2d0{TTDvpi_LXzFfO|*zXa-x)qZBQN@V}rIrQ(P9^`fuw= zL94WJ{g%37l-Y5$&G!|dE#Gc%RKEEGzP$vxC?PkhabpWh z{|#{jS(MI`@fBfxguHET$G({RHf$-H(GjfmTLhDQ!3653M{66=%PmIS9`i;a%R#tl zoY5NiR097ErR~)5Yythz=(6oh8T<)qvW=PH{WAQ5pzCXZyTm!9BS7u>aflSA<;HJ>qi&?`4#+(DoDL96tG8X&rsPKW_TVObGQRdM5TJ%2% zxCKj-sqtg{%_h?#8Euz_#@KiZBU5hB+w#Y($XOoDg!|=37~Tsb2%O=w;MaFOhNtN8Yf7C@^S;ISst=34~`+C!sG$fEsf(;dG;90drX?p zGai?;j?HWS%L8?M)Y>k@d}V9k97_}ygKmow*Z9 zS!!$QR&uYrmgmE*z!77T#>&^jobWZVqJxuR$c&Mi8=Ss8-VFC*R=H#sWc5 zwyp7*OAJB0vEX2*Q;bIn=zusexe2LpMOu9cL*VA5KUMlu@c-{N6aV5k{_D<9z&$^P z`x@9GQDCoyGs9ouep(+RzA=ku3y;qN&GZSV0T5Fvz&}~WtXS^g z2*Dx-xq~{+t2qFdQ$ET99hpJce_SatgDzXRD-mkSfh23++<)Xg%k~NZ3CR%2%*K7- zKxR;Kq)A)&H$Zba_p=FY03TC6!{;RQ9^3U1L)b!@;dc^7q4tuA>m$H`0<_hiIJLZ1 zEQ;h+M7riq6GOx<50Z;J0DEmUFSccde~&I@<&1)tZ5RMb*&X&}zyRaNtc}PxBH?$! zrK+|XDl}ch9I62V45hy)hZ>ck0+km1d}^hG@CR7i7d3nmLrn*vi5fOyYcO%xb?&n+ zTg`qT_Lfxq16{_kiq+nTpJQ6yISa;VfiV|Pv8D{UMA7n4=5iT^(FsT!q1Tw} zLhiF*KxD~=d<-iRIJtaN4od^?6)p!2RH0+TXjNGK#dDnS;iV=zYCmf$bIzJpAY5VA+1;!_kr zbB2dsimeAO1=t&shQaHP>f5e>C*@t}YuS8o7Pb+C6>PzjyxwbLh}@LBZ7d(u;ls8} z1tt@XM?&5nqyCjrfNfjf3(i4B8&_Y@bqwpi&;@Glm`HF|+qooznA*o+od{+6aF`#}S3VM>qL7hVMg{^?JGTIQw7= zEbnw4r$fWTc}?1~}i_oq#?B z1>%$ix_JRPPR9nc9|s`9<3;dz$A{8a<2nYNkr{pz*u5F}XlmP?7*sFNzYP^wcpdu8 zY=iYnZ-4XOM62XJ+YkBdcI#E<^P!seHxwzDA~TOL$K86q`3#sZa_s-YWoaRtx;5To zt@T(H6^k%8$#oE27D{M1E|i8`QdA*sJ)+^DR|bSr1L2h!KtPcX) zfozLjWaf0#^vl9%u7|MV1Z#VEubPY=J@TQUtO?f}`!mSA^0R3}aGUlgR zdZBOOr~oE765g$960u-r_%{hPmC8C({YTGSKV`kefh<=0g!OjM8Q0q?L#7R*2nw=O z!zttD*z$3n(jkG9Tz+C|qQ}%MZKKON%8vHV=M?7p_~C~_K+I(bH5yT?;5-dx{@pWFT8nO^NHjF`*%=zj~ znc?5UO=@qO25{+O$p+x50GEFei=zT;Kpg{M4(dEESbr1q9sQW2!kB7+=T}x!4Zyw; z4U7{iv_5BLEd(3J84Ndn8P^V|E38t`QC&ISV}3=2IjFc2+X4eH#{}#NdQbFz8MAC< zoq2SkPcsV-1-(abV3OlHVzk071-DA-j75JQr}@$yTUiOU#zWD5_$SSLo{HgI8jcJ2 zu+Mc31aU^~IsqSMjdx((xocp@_0%}~TNR3r0}DB`?w9j7YaGZIl>%wla0zBTK;~>JkQ{ybx1{5Nb6*r^{Xp0Owb2c0gph2t+JtnZLXIR8!uh>l zfN6y3Mxmho1!l7I!Tj*Fi$!dNHDHTLN|*`&<$*pNYZ;E=fu&M=0NdaQHVD`)-=yGk z_uwqTe;M8L?I0>lZDY$5lI{Lri$iT5!UqByBbpzlfp!o%Xr*MtkcybS#>@?_|BU|# zRB3IwfsNRJ(WdImz*_*Dxza$aw#?u|+e`)J9}68pg>)|V_A~`?>Y!gO4jR~#wjkCu zTVRIf=Q@=^@wawr+;JMq)fJS}8QMnJbLR_s&H|^xQK@4S*A2waxmU_j&(}2H95yNrP*fW#CN3}zqzSVlT`vjpnqy# z+S$b&X%!}7$nrWLFm+&dtxz@vRx=m11K= z_tF?~FYS?o80O~~`PoMPXak-;1}qEBBPIXYMho*nc;Dh~>=(g)t6N_somC}r^>pKT z;&qPaDuwheJk&UCZ5Kefgz{fv8G1yczxdx&e%9~>;SLVhcTn|5y*Oy);Or^=1^Olf z)f}h2jaEE%84ilg^3Fy~h2AY-X1lXnS>(b!TaMT6pF#fjz)x)tybb8cj?Epv(d^r? z_lt=Bj6ef0u#0<^6YG`s}G%b3o7#xU=qH{c6j&maNWl^R* zm{*2~mhe-1xjm1ONaVLlJj>5+{{%{L%SrDK;2EaLvJpP77n~o!nI*HIQxzLGII|*{ z!#Lo*5#<;oPg&`|eOL}ou{e8^GUe1a4z)EyPJMfArazy%Y#ARNzl*e(daBS*@DnslBi2&*IISmlT9g77;yQU(*+=UWHmWVNr1 zq8gfuB^QxRCzLxc&C5t3$%O7 zdK?~EwN`TFT`&n&YS~f3&a#G97i@WfFM@?;O$>BtK^GUyVB4Xf6ARw48rP9EdF$Z5 z?yB(~TFdHBvO4$q5KJ8`b?G9|Izm&x(l4>ptCMz$7(5GyBEyijT=5$JNGn?z}iUzlnzNYmSyB;dVB?M$SO+B&YgSUV3A^|;0FnWBlb!1 zD0iz397Oka4wt?$``VFMnxLeIH5=fz%MH-=9`Zh!<&Eyh-0u7kZ1`~hNi1m5yN+h< z*di-k)41Kt4!oV4lKsQ7!|HlINWgAd*7px8(&N@Yt(#!GE?@MM}O`;WA8+zA8NE@ zVXA;^4c4_7DU7v9XdX;6FdgO5SKkpt01)CyL?mQw&-b+G|CC2epqOzsWyunsXKB!@aqN{RJ!2CY!RDva(x_=z9}KJoUl?mE=eIkb zMtl+2%AQ>LvXFqS5GaggF9as&LS)_3Eqe7x!X%zoAqJ6-dYREM^lh)c7kH1$wz2>8 z&8lUXVn3vg2MqQW{mWu9!r7a08Y1+={s8+hIYy%g9p@2puGd`bSvk0JP`}Y&iyDC7 zUl5BR=>yX>%#HzesJqo^(33?(7^9$PN830G$42l2(Xlq*(Ze!goCismL>mkLjgo`o zsdnu7cdd?3XRUHLRp(pCjbKJ_)h3?XlJw8mo3H zY!HSeTICik|8@BM9C_{%v0PVw73SCLPRNRI4ab?Dsm!% zVG1Sa1A5v)PoLXmoZ`r#1Pn<{yw{ZYP)3qGEQ-m)?_s=&JOB-7B|8L|UI3Rpfe+Z6Kd#?qeiA`J}ZZmhh4LnuCuVl0_~!()T4 z9t9G3aWpoGmC{(>AT(QFNQWLptxZUXPEgDtfX zOnMg(y;TtCMF1D$QS1TT;?^INlQhglm{ZIQHWZj#ijN5V6*P-vMoA9@E(|slp<>|v zSsKnt)H!yn&spe`Jz`2X7p8cy&>jxg*K?p961`!JsG+H*u^1NA{g^ejz{zZ!?(yiz z8k$#7(`;XJp`ZxwLGveAj{IX+jzLC?{v)+DRKw#8S{}r%M8>*56A;091@br%HlaLX zX$D@_kh`G9lTT9=9GEL&YEg*Fd}qf9^#Lo!NxxFXW69lPfuKk5dIagLhzg&2z6Yv^ zen^~yP)DH%y9zWBbn^hfv|JQTrF|$S;MlB8u+BycW*HU?I!Z;`=C@9vJ4j!xXpUz4 zL6v@ZpY!PDXtclv0Bo?q0+(;6%97<^AaH;FAWmthR3pJg9AaTkMQS|uwb*K-`AD$Y zjzTQ`7lHbS1{r|3#NB4FJ%B%|U|W{oYF}9>D&QYLo%#-e==$H(>=S*UYi-$bTHm{a<=CHS`tQwh zIJCMo8l1XE->znxg1r^65R%TuiHeKefey}+U;`*E0*p~W3ccN14t#?6SrH2`#@g;Z z9`rQhv2&K_o+M!hLe{$uXOnL2O?h3AB|67wZzc|fgj8paU4fI;Up!1E850UTv-I|&G0B66 zUhxr;BmluSHVOwR=$0W-d9VOatcMjR=s$D%O0f!?%?bgjpv#g3O@O0zSXR(hR7iLv zu|f@SuE0M7vNZs@*Nq==E~EEq+~9O9`r(@sjt1VrAv+ewK1EPPa#*WTsIJS*VNiPo z8)C!2B<={gquh*ef)CTXCtB7K^x_qvgM7;*JcZ3_>+&Qx+D6;$<@09#+54K5U>bdW}?7FC{6$m4C1{Y0hZ!0&kcu>g2pJ`d)gcH z?&FIXA=h4yibDsY-S4wAd+&v@&P-CIaukC@&~CT#!1ew`#7If)@I9iR6CT}a4Ca@F zr*KI8ut)ETs6l?;%r92@aIcZyZswP({9P(Pyj~iqQkfwm^A5>$sLZuSCM-a9hquXa z98Rhf!#NVJ5*j*i_{oqx0F)EpQURzU0K;HobFn@?7b%#A8M5>wakqr0^OZI1VDYXQ znrhLbax_Cd(>Y6&L>N{PG}SS|$U^yIZ?C}ah; z^73D$S6Zohsk~i)nT`|5%Z+;sv0);0`+H5AeVS9VkH?jV>oQy;ap7}B_QlPb-HU4; zu6kT|;hHl?vp<0{4fol&&$?Q(UxoWl-0QfnL)wLO7p^w|w;JgLK6tr63jGiD+;L^|Ed%u4s`I(H2oNaufKeOn9IstB9@@1C}tcE!tTJU zEzf#C!2(*0H6t2`oZohd?>PISupq+TX&rRaBz!?ku#Dbq5XtZ(ur6p;@l`y+QiR}z zby){Jgbj_m8|GSY+-m%WuY*PN3Ap}O)cI@Rq!kf2*J8Qh&Led^z~HZe$bEhWcmUMX zHrnVlJWAcjM#`%7jza^xXcER&@g(~b=QYwatbqv38QC)87#ZeS?pB__6JKYfrm-M5 zz_U4+DRRn}ox5!ZCmfHQ#cFK(B5K1*VY~|L9E8zOvCX3SFjN{mH|eu1)W)Ctmv-a_Ei%NR5hF)O0e*cPm~$C-w6 zLu2HbA&9&QjpJ|4I3Ip@JH0>J>;7%?9uRwxh|le_hss^R4!4~E6)OEWr1PW)0B zDP}5$)tHIR#uBtn3)j~-9M3=$9(nMGZSMT#Vt$xj>}X1%iOgD*A**DYZkg zh?(0-IUieTHzEiN#19A;i*>u~jbM42!G+j~iH9I&ubcjmr`|AB3LGDn_C*;gRu$er z7^>E_*P@9n2jE@S6tR#Ud%`D0ogcEn|y!az_Bk~YsnG6$v_CPP*qT;3tFRD;Xc39!M zMAvkr@LBm4!$-r@xcf$s0}Ci17jX;YitNbS4vhu3soEtN$423!DL5;9)d?(P5^WMv zH6OAz=q?5+!6tF*!hVv-MmC-}YE|DTlmk)(wc*I~3FrtV4HBDN%e^s<)(|b{vbTbU za7{+SBLOOMz;~*6pci%P&&h10>FCj40jnrC34I#;aqF`aIzZFsz%_&_piqlmWi*jc zZ8-iw#?*N!=)}nlS1}Bna?mbU&dPH4SZiKI1R^Hy9vF5}@Q2mkf@osVq{`Wd8BTL6py*6&HH}g z^!L?MO@Av-A!>o2(mt1?6srSjU;zO)81fpAE zu}3j?P%e9CgVF;y`)|bVkfwSVY{MS52#!wdcA!WkYQ#8jWD&fy&G`JmGuXvQ$a*o= z5S(AOoq@MA=v9e5Wikxyj~QXS$?`{Shxd=$yV7%LvjsNTZJBLT6NiL}Y7~ZSc8~sNl%D~`pfHT!TN7^mq{s?Rn*AesH$X%Yufqd3ymaC`aamKg)jz@P ziMl_Ozawbh3v{$ze%3-X4)kL*Pz^L6Aw^A06q>bWWm2B{1ayFCHzi<*Xk4fk5GFsA z5zO36QR&@FhkY8otVX$)_XIC1-|7P!C^!B zRw6?YBqBk|iAk+R8Q}Wyz{ca6zXiV;{w4U$1f_n=p&DRB66e7dU{6f%!%z~rQE*gE zO$x&|+w&V_v``BCu7g5f8UQ!8Bj)V}87vn{#5=c^nY@Zi6IxHI)wJCbq^dEOqyn=% zP82TJVNfy7*qo+pc$!aet@B_H4R@VA=msGTh(K+&26N7klYE&sTY}kpF<0?YU~f4l zKv~By$C>JUrhsddxcVOwxaBD{WC`*HYu zD2sl)NbedEb(~O~R68@{xFL7zn{1xpbkINW#BlLXMVa`D-7K#td-Q8%qlXC-$N7|F z&^ZP@HU_u}&{lMZb6|TTrDuOH_#53mk7vGEF}EDvEa*ge&>GEh4wwk#1>V^d_=rQ6 z5oT;T85^>UmD+|!koytna6r!0BF5JiV($WRiB#*4aUKMC3#|rFY=p;E(1VxeZT0w=-aPy=r^^DH3>hX!u3aP!vE;?sU-H1d=*BAebJ z_z7gO3AtsM?v(ri9U59f0n!O4DL9$R@Q-EWu|E&L7Jq(t0`{A;&{+5a+%)qBFS`u5 zc>@j&+${aTHen>xfXBC(&m_la=@+l=$hZYSe_pI^M(bRHUe%Ej1TNq0^RpU_ucLnw z>V)%rTg{gKO|q;B=0Gw(Fy1Zi41%v)KI&?KJQq=O$eZ=B11$S>yW6+jY`#_6vcp?M zBOy-M-2@{*W;nJ>2}jOz0*! z8TOcf55?Ey7tAkswM7*Iks`hujdxjag3w%qqY`oshiIBlH@o*pd&7L*19Olk6WACH zAcO#eu(*8#tVOY%ps)zP>eGI2@XM+i5=ly;H^$AdLyAg{L62sxdH7urX1BmYCnrF>vwzU<&ar<$LZ-a@$$8W1? zeF@yoAB%m%P|JB3=c5Fne0K{7kRoBQrEELb_l#M#Ps$MeXq0+7HnNI*$IXg$MpmBhgjw+_ zl|}A;`DV@jAg-_BdIZ;ZaXo=+{w-)Wd@xS(n+6d3ZObQ&}2WtR_d6@qPgN{25fXRv^R~jNV znIa}jLlq%OkL3cHpQ7uCVUoN`rLAVA5~+0R`36IPK|QctkQla0;63aU=#@j5Qj7j$ z96iYy`0k~W|_(ljw0(DdH zXY;<@W&`&b4J5h~lE*9X&zSHHr+_#0i>#l|dN4o?XFxXeY9h@7;)6x)#f$mwadaQr z3zy^O2ydp~riV9|;--%`SY4x0-VoUG7H*)LqBh(J*_4~YXXi8J_NhOR3}S4&a+_xF z#`QL?_i%lHD~c>SmS4rI=`l8q@UodQWpl{+zTRTs9zA9Xj_t4?jr9CAm zP5w`!1aldd8O%Z|gWNsVz}uSwCpYn%3V3SFs3Ump)?eWlnis!F#KXgwOvAB3!LEJ1 z9O!6%yfS38A`6G*bqBI*4z*2!4Gt-TK@M$Ud%lFZueLF23qj$m3d07+-cQksBuaiY z*nnV9%|Cw2#)uma{yd)@FKP3OEBY46OH3+Qd{@ z-xog~JVko@d=0OG8s;wF(Lk%$sgp47AG|tti3oafgI0Jhd?oyPM9tQKoyRwqp!$(Q19F!j=uo=K)$7b{WDa9`O2br)>@VtFC+X4^KQQm z(>FheV@iB25*zA#^L$hsZK9u`B#gNK7^~#%X7v(;dfUP3#!J%IfF9Dcifn=xraye+ zuzba9BaB)w&;qmQX-NGHfV8rKFRC3R`|y%JU*4(~YJ%2DhPff+N}tBiR6av^Gf&Ri zI3B7FyY$@eA9$??ZyK$!gt~BUiNFWdJAT29Pf`DeU9Y{T>L1`|6^E}c9UEvsqD`M2 zhB2%4!dI7BUqw_J`^85Q?Eg8T<4ULXGN=7Yda7c9Mi5~YodVB7OilzpuGcwEe8=i5 z5CSrR2S0dK9Z#FhuSk>&AEkf6pUrxSV>a{5 z^t0k%#cNub+8$s>&%|UImlk_|8PAy@%?w=Yas3KcA1?ln0c&yHjPt(#flJ3V8Dwm_ zT+<%F^&4Dkuh6tV;A%vpkKlR_R})?m{4TCTxc)b;iTL=|&A1-LbsX2kDR{>9D6ZqU zKEZW+G2n5XGgZ^J<9ZR-GVNZ_Rnwf3-VHjp%5HEHep|H}TA{W`xKIe1F9FQ`$XNn@ z+^Mw*7w!drTD39!9~HHD9WNm7!nI0UhhKymYImd7ow%Ed>k0$%iXruy(CTWyt^og+ zpyg%Y`lqiw$LOUMb?!jl_e#HP%a5FOXw{EVoe75pz=80qP`eN#U54?kLf#s*vup^) zbJ5FM;7Xi{YbtHd)Z2WtZH~1NV_$=3zvQh#n}z6cjpVJt{po492xBAn)Y$Ja_(hyl zF1f*RwF-?_<7o|^6@^y_mq?vufM~8(}9 zJPDfaDzv&DWxQwF2;4bBQ$GJOtuzTeDW#+h>21x+cEFeb79Kph~K?}Q!8+zl#n*$F(q*cEmRI3-DWF?Lr;uCIkQ1LL#EkNBX^ZfQL;tdP3k1m zn6f*RPRa65E)mZLv`Q%??~_|ehUX|02RUX+2sQMnv5aG;AWf`Spr+EorktvD334eX z%Zy$oqkYaIQ!B79wq)wIR#|O0*UYsnxs-JBgR|410g~rQsWI+kp4=n6B?Xdaeth1u zBzb11^7Yfqbhd74ElQK(Ln61zVtnDMPa2prgF25AFm#r(z7unH2{b6zBhpw&YX~Cs&H)sKFJO<4#_);xfG)Z8^}|&Du;rsWpfFnK&nFfrb=Wcc5yiWQ7aBb{u-h^3r%T_& z%*;{ug|Hpw!d{?tvrxMM*COyk{i9CgzpG+nPsFeUEfT{DXba-*#BU|$S0TpB`=Na? zXDVtbDiEdwJ*#n_3Z8ViN_er-z{bRG8g^*r{qPu;8W@%WuXy{!c6i)WzKLOzP`E@! z#Brax7BRd$hKq?4(=%aMW?iK*b$F7cUMCTbB#4=I6Q`IQDJyy8pQi0{XPqP;tVnI8JZ4{Vf9&$A+^id zO~b~s9>dvZJ%+R}&TcL{&w32!{GAvoeMntTT}sVeCi>^h`Y^6#R%4ej4Ykai;j~RP z$`zL@VRumjv#&~7m6bLgUhl>2!nk!-X^M$t1ooCdm(cyryJ4fXsGZU z9y`+>tPsk5dincoqfywovC}-2{GFP9$u{Aq?f1XJ;Z(lHpNFSm+%EiVv*ho$3*#7l z8oQ7-*V(<=RbyvEiJ^kAN}JCPT8JWBRQQT?GP{GWL~E}pHL?a>a0BVbb@C^%OPc}a2~`*75C9*$^pM%CvITp&97Eie1ryN6DX8kxtPZx!dJa#^DM$JjUQsI&u znV{q~8IoGyv!8k-+Ntq9uG)hVo8-O8sn0x2-5a-y6Gvj&beso;kY1i)G+{RIzA>eb zxTJmdJNk0t{}e9d!>5&=p=Z-WC5or6|9{C8BPd+>$63X3X~3mWOI*u1=UQU2H*^Jx z*K%VvsMrXeovKszNzluM#*Af5OsPc0#N#Mbq)e5OYsL`}l6mpA6EQm7>N*KHs5U9( zjKyIa9Me$D|7$tyDURPHe0y(_oP8#1%AqUgB%IzSuAb&tRs2Ens%e&){UqBHEHy`2 z2p*-bxn^yyEUA>`y4r#(PJgqH`QUd0;^V04l6zp}MRJZ8Ybno?1+E(@_L5|`w16VFC)mvL)%Nt;8**Mu?C8ep7(f~5Ur$|W&3 zPq$4vnJt?(hiR3V<-=JciDju)NW9E!S=lm-dQcG+ss}YwILdgGSSqAx|CqBX4yk&j zzb+o7XSSH!CS~MI)(>Y2{}FdnwoL4KQhp|z=k)c@Z0Vf7{+aEYPh0;~R?X?_pV^i< zef=|AFsH6h4KoKbhgLAPs?sBku&%h?6+&~X()ltQ8O_4=n{lr69xlOMvV}PpZ48B2 zfH`^(R)e8sN(#>0$3LPMwy{ih8??d_wbyzXYhr0DD8T*IY>b$?h;dPz_oR`AlzOpM z@)+~9G^u5!j6)~q zE8OFJjjwsb!7akbs5`0iRPW}BkchLUWuG<n=xrfv+)^sFzIubk` z37#6O_V+|`C+=?lp8Cm=mx-;VBf%5j21rMOtG7kck>Ke_aN1Y=mmCR9t0^4`&V8|Z z2Ou2@eg|xAdgoQle%wczjs!P-km*S9Panmcjs#EiwKHmkQE}-=@Z_kUbR>8@>g>}* z{P3jf?2ZzsI_o2Ts^FDA+i7^VNBmU5<9D{xFdYeQu0X@Z)0j4mnZ{3gRRn-~SMMJk z@uN=ahn_?ahvD!MKitX0F-%8-$ItW?4No13I~<3raVD(haXJz_E`#wk*_<6_Iy?>2 zk>Hd<(k~qeZt7g>xc|xBo@6)%t+J$JfTwR9vn;{i>osfZ^t=8E=pIucxcZ7VVInrnLEKeZ1@M}nJg zDyVZNWdSA9N!_O-!PAl8ri6UfG#v?^jszb*VmuuQUZ|xb!Q;{1j9yKCA1z*{qG-(s z^K>Nmso!}s_4DwN=;=uCbR;+>WVk5lbR;-q-<768@HD;%p8A)KjG=F9X`m**Cd~Mo zd!)*#-}lhY_$~<>nAfJv*p?jJnuqz zi}xCNK5je<68w2bmD}uyDa0SM<~KHI4NI4|lg_KJI(Rhi zzg?&8I=o^{&BCkq_x$SQ(Y$Zlw4GPf?{_U*{LgP)@XTv@-=361t;UHES{k=l@MM_Pci=Vjo5v>$0XQvRpIvyl2wz8L9xq&}ow zC|{4%9M?j;`4az{FlAZsKJl$E!jc+snJ)y@D3APhD|tm8Dw+@dKD&muj3`ZvKyQP@ zEEj0%U-jl4%M*2MANQA%D43R z-k@9ZdC#v9Fm_bKd!>or$yaasaF(d=m;^dOP)!RO^A!mG3g)^4;nB$v+_V}h9^BNL3!{{r{KE6R@!kcd>@w>&G z1)TeAhyAMWTCb2EkPR7EUn=JtwH!JB%sy#zs`qbI+kEelI!4i%oJuX{SB1^*?^8Br zqenOTP3FNOXof|@;0%a==bZ0RsqYj}A1E%&0~I-{ z_@D1p`9D=QuSW_?Ve?L;c=2oVGe|8+k02d^v=8Y>r1qnleH79nq*kP}kd8*W7%A+E z&0CS?Abk?44QU6`F-VUg9gDOdX)aRBYtX$&3z6m_twPHGjM0tsT%=2p<|EyJbR5!0 zk)DTiH`4Qw9ze>QsA#`MS20?_97jR^aRogNNulc_K8Rf zkzR@Ek=q&{v0KxW#tu>)2pf*8fP~-=Wsr$wNAZDNDGvIroN?YaE0VbnVR1u z@~}km8zD8fiG&eS?Q~e6@|PNr@%$Fdz~SIk{!sWO!^jicAG%8~WHxk^`fkW=z@Pe+ zvpG5c8c6j*!Ib&bf%h2tiC+#d>7ep?0#Ci7N(k>p5A#z-!2GV?U|qze{T95$<-pa9 zYca0%xOU=t5?2SVZe0Ditli*mhO%kRef3nlA?U!jD%Rt?JNb^^8(a|UjScci6RJ|lKF z34IY4zR63B_~z~;^ga!vu0kFoALxg=O1|MR`QEm>@4gaq0kdAMWq80Jb+-AoffFmo zBIx=S)Kzb&P~)j@v}n(NRPxF-2ae`#`v5lg%)>RGoBEyb_NlP3 z&r>$`b6;Hjx$*Ok<$b$KJAvmnpLi{A-=*5-&f4u;QlHiT zzr=4Etk*WkuSrK*TU>3Ig2uELxL%lF7a+8POPnWcg>O}pHvBFHrBU4}*x9JR1|)+X&1S`(x&YpK19DKjPxY>76=YH)5cB;XoclrPSfV%(W< zaTu2J>l^XXg|aeH=Me|~j|p6vm5rv>KS~bukox~+C}(Ofqn;Z8zeI54|DHg6)%X?y zFWUXYi!>xQ#n2SyJ)yWSxgG5-1Jrf$e>qJO`o-Z$P1PR1&RLC-ks4;M7d_lAIc%G= zMnS85T7+D6`34Sa#bHd?)RaBVg@i3I;Q36N+<|BQskzIyz%{{YF2=Ujz=`iWQ3?`& z$*-jb{)C+h=t{J8FJ_}3PfKN1E;HKVZjBbz3g{JDo|M1gAgQmEH8>f%il@*G$eE8B zPYO_%#LG!5TJ|cx31!5He@!vEn)IE9uidKqQX@5K-wbH-QT56eim_s>fK;0Dr0Sgx z?oOl4;b7F>&eXPb(kgYi*~`!p)!%I3)dFt0fSnVx;w-x#wN1QD{bbG`Gv)u}wFT4{W z;A15dZo2&&D6d!LsIqy}OWQ828;JW^itpL--k)C1T=1=*y|(k_=epKSZoO*%#gU_V zzxcdbBO3n0mHBSjYkA*Up;&y-!zH(U)KJz5BqU^k13+X$qt% zkfuPI0%;1QDUhZ>ngVGGq$!Z5!2in>fQR=W#($Y(vSX@auH!n#&5qk0UvP{nDJUr~ zSy*yo$<~q|lpHSUD!I7y(b8X)9xVM`X;109rTJwO%04WMmX(xGFL#wMDqmTCUwM1^ zkIG*!f3N)g@|=n*DuNYXt$45E{ff&fot5({msBpVyr=TpmAfjhp8oLk%~kWN-PQM1 zZ>#=J^*>kttom2guUCImoiStLjLI1YXN;_wR^zJKRr5^E{+iyJztv>dme$UxU0C~t z+HcnWYwh#3@6`UaHotCi-JH4`>(AG{ zPfLDTa;W53$sbGpQerJFDxF;Vxzh5|8%iH3eY5nv(gkI~vWLsQQ})kgd&>5e?Jp}T zpHg03-dMh%d_(!x@*U-0FaJ*Y6XicB|84p4@;{Z2sIXUztGKwLtfH#onu=R1R#bec z;(u1WR?%IdSA0+rsTf;1zH(CK&6Rgn-d*{f>c{!ou~rMbeqA!L?8>sHvY(Xom7OfJ zmS0*PEVountf;M+SRJX3%xJCIfl-dE_11l(?v=X7X8vyGf7WZW;GaQVi{nDabVq|@ zWXZWDE6UcEy;c6_@*@?0tC(J0Q(a#@yZY+t&sQ&~URZry^-a~cRo_v4XZ2mxtEyY8 z*HwR^dQ)|v`YY9;>aSLRz51W3|9kcKfYYcMr87Q1W6_M(8NnIfoAI+5&&?Q|VXe8K z=DC`KHAiZW)^yj5s?DuEzqYXU^4j9s9kpMt{YmX}wZE=CT>DDx6?N5hjdlGq|4P@r zThks!a)V=|<6*~B(_fojP}NxV)v8CT9;^C6)i0|4z3Tlci}3gd)jzF%zWU|r-&N<# zXqd5P##1vsm~m;%nwlrkXI5=dZBy-+Y7fI|U)Jrfd%o^)-Ai?^)}1r6Z00R9zcw?kzNP+4_5WUfwElPXC+h!F|JV9KI_DN^ z@QQ1i)luLmb~qg6jw(m3W0qr)!|%u{8DHWknOV|Oa$Cvr5_jqQI5zZ_uLF;NRt^WE zIKbSF#g5hBnbx6cICs>nGi@^qW=@S1Gn;$s*>80StU&+%_Z|o+$D=jt}nT{tSYLSTvc47m g|I!plQy@)&GzHQWNK+t9fiwlu6i8Fxtfs*K2N8Sfi~s-t literal 0 HcmV?d00001 diff --git a/EdkShellBinPkg/bin/ia32/Apps/memmap.efi b/EdkShellBinPkg/bin/ia32/Apps/memmap.efi new file mode 100644 index 0000000000000000000000000000000000000000..e7ac7d5c1627587f395e6d97aa3a82bc8e188033 GIT binary patch literal 36864 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 literal 0 HcmV?d00001 diff --git a/EdkShellBinPkg/bin/ia32/Apps/mm.efi b/EdkShellBinPkg/bin/ia32/Apps/mm.efi new file mode 100644 index 0000000000000000000000000000000000000000..564ed828ff4a87d8e8d05e4a3d38eae66c90e2d6 GIT binary patch literal 61440 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 B$vXf5 literal 0 HcmV?d00001 diff --git a/EdkShellBinPkg/bin/ia32/Apps/mode.efi b/EdkShellBinPkg/bin/ia32/Apps/mode.efi new file mode 100644 index 0000000000000000000000000000000000000000..004e0f47a121614b81e579560898e34450e56eea GIT binary patch literal 32768 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%0Dbv1SMbxn26b&Ko# zbxZ4Rue-BudEKhIP~F_iT?ozkgUE^+YFLp0=-w6#}>khlOy0^Q(?Eb3zDfhGPJeFX6UEC zaw(*FXXWzBRh6O2wUrwx!UVH7e*Iwt0?~}$Ue_Btu=IN{G_Zr5Ww2U}_?Z)s+ho+r9 z#8`^Ut=26MQXb9f+@tb1&s3*&YRpKJa=1RkaoH+nRd$}8AYYJXG`dbu<`iyEXuNkt zBkDc306(N_sg)wppIpPZYr=y0jq`Eg$Y%UB<9OLhk?7A1aB0G_dlxOa$1w6iv;mwI zOs0;{48y2$oSw;^;lLRVoZ-M34xHh@84jG`z!?sl;lLRVoZ-M34*U<|Kp@h&rgJ^k zd3(KWM0>B-WYXYi@$U1RKbT|~q1~>C&s`e{xa!OY#;fynt*eJ@ABpv3$M**tMiA>t zPjKHi@zb84<}nA4Vmql$*tZN%-+_xWpN zt^H>}i9ExT@G~pa4gRJzP7ZyanT*DvlF4kmHd-H9N6`M@(@s2|As#mh9?_W*X+8Kn zi@ZQg{lRBhqQok3X{3cfYJ)E+AR}3%F8EI@G9pGyI*C~XFFzLS-{Wx(oQoy zyzWW#71^1!E)Npc;%f!gU3D*PMz2L`#zkuLB2}6G$S`$YJ1%ykuhy-^auYcf3ABdZ z%M1rvBi`0fds^e*h_5x&krwu~?pYTC{ItE^ZkCGu;wYuGr2Xekg$IQBeS!;cS=I!&h z_;v%_;kuS}gzPuhDOeso2IE;X$b86x)rMZl+Uo6F*V;I!BMq?XBfi7+;gwl zik>=)34TyP=Amd?q^id5+Oy4ftJp$LgV7TBZk>5mo@x*M@?F&NeXBNW8|c%+&t<-< zN@quWn?gI&!@f#|{?)vZS3*?Ya4Kna;gX0B^(8lJV)_q{dmG~;4ZdUQ|+ zDeS1_&uILFzE6RXJ74`PF4o{jtAtlEMlf2^nl6s9W3V|@HP6urd1>x=M#^M76jKmG z%=6=mEJKk!>psVJ>i2p(mCTS64&i|miC_eKwE`@&*2Ptm&=~dpnh47$5QOh}2}(2HmKyDG6=_L(IjMEXoN- z5wj1!5$}Et_r4Zr6u=Gapjt2sG+Z?Z2zphP)u|9LfO~YjRWz8bTC%1#)lx=$OLwp( z!i549A{N9q_M>u(2pK_a%x#T>(D6&`mPYq$>A4wkG<9Pr#kX{8d`q{)T2jMLx1>&v zpKZ64*RQ2(;#=B)mZ;M(v9fz1;l9q=$TQTr&~v8W{4xs2grNH6ay=p-;GHo6A8NKu zR|IrSMRBXh&UY}5m3G;A#FO#5CEYvQT^aj|4~Bj1;lR+2fM4~qxBT}ow z3nPKevG&|%P_^gocpY8X(n2WVVTUmzSlXiB09NQ)C~#C$H(`(}4T-|uPJ3(*GlweR z`Fp)RV3yJH48emNJ$_94>E>UH6sf^+;H~-cG@fL(w6qi8_ejXtK#vqoHxEit=qQdP z=%|ZD&56>p0Gp#BR}g4LscAI272nTSW?QDREAAho8ZqZyPEp?+`R(mL+VA+l9t?Gk z-s62Awg5FGXEAS2s5LF@?TPq$%6#su(6>oQ;3yEwfwt>`Wf;la;5T_$&0lIlr`>0E z&=3l(K58_b15Jj3loLrWtEp+qEN+cH7V+goMu1(ODOEL%>Cug^f?fl3`C9_C_qs5t zbz@RHT4!!kkU^9{9t6nI8P>d&9?b>lZuCiZ+3Sy?8E+TPv&(j_Itx^!Mbo4It7B>( zrlPHZ_tzb4WXprLbFd5Lptm;Sb^Dds67jieBO__1_SN02Na+o&?lo4U!QNj#d_fRBVp(#dFb|m1g zXDL9d-)r=-?CrP*PHasN^{i|IxlS*;rP=bIJ+BE@}!=C8&;?^Yno5P#lo?ro`ZmJson8bRrwvn`+ zv4bf5whRw9uT@3ReJE0u&OXP?Gggfe+u+JFbFE^O7pTjpvX!JYWMD#Ojk9XapNvo< zLO@%qTms0I2*_jpqKw5nO7OB0(HUWGSGU~)C2LGGIF7*p{I}L-g^py!M)o=8XQd=f z6Vb&D=bDeGYc8qn798A(IAoi1V>o1Otr><%yC<}3*w~R|O{{^D=6I`=YJ51k7it}z zi1B&mSynMc_i({DJBHKw=I^GGU>EVU%-0ogjN zhgNr{HIBw_dgIm6vKYJz%x5ilGh*;AG(T-!8>cOaQRWis(gm@qqs?38+Fmb(8up-t z&qZdH+@PHWA_x1;HKP>L!4gVQ_Y|IF?(rUj;^;z62z+nYrv@w$HPadk@tfW_FS;@k z$Ofm>VB)eew98Xxa=oJTRu^P*Lruwg-?6AaS;1dv1?MPuWwL@thQ>k621NGxwyLv2 z?ViS*4ZdS&+{3X98OW|Rzk>y>61py@PE`63lITk8)QinRMY7u>8CE$c?IC3|zrdGW11tlGzgI1&Y}~(F1hd zbuUl=IlKg73l%TdRxlqiqC=~DjMX&qKBY9C@7TK6njmLZALg2mN(<3p!8W!rUD^P3 zk(%7lJ84b1sylKM#QaiomMZ9uUP0|rn+uFwq1N0)mRx3Dtja-AxFS`Y8(g8CIf+B- za)vHoB8HsXPXnG%?XKZUS)cmZC)d7UX#$~)#iK3$Kok& zRbr>)Ejx+4jWu_wf{?dAL(n=o(WH>K&Lr~oXOXu*+wwNfTq@q3;EGQ}7K+u$Ny%F& zG=q}2?$GM)IC=YXg1ilv79ejqA++(+iL98Z!B$x%g8gQgYs@B9F*~@OXqCp$f~IxZGg^Upz2E_mxHH&!r^I<@ zi1W^c&O1Y;*M}xhSZH>as4>ux)}Sndox^L*ZzJ@A%N9Lci_D*@Lat!VT44EkbwcK0 z)Z}6<45}gWZWzHs_l04G`Fhs8V|2lIrAbD!5o6Sy$g^Ve5owvVw^d!Xv)uz8Vdfl$ z74^_vwDPl7_p2BDmRzOl@2;SKyV}-V6)bJoo5#4thLYMEFMpIJG?Gf z=54j+3l}SSZNQ|_7CM6I_^`ju++U?G*4gG`h3S%&i=$W!jcI1IkQF>JsV_5ssjj#* z?$gbEasf;OYNKi0!Uh=)>vo)lX;)09rkek(3S$&mgw8O-Qr)7_#R<{6S7|Pmdk({^ z%Dlz8HVzDjnXbB^*Jkcavs9W0wsBZ~SU~*26*TFp5BoZ~I$U$47yf|yaKOZM8G_FZ z^?HT|;0#r3Rjh_7b(Y@<8s6!UPY5hs$l){3wr#%#ttGa{By)*5W&$JYrm~wfo_s@^N_O^wrTt)#Ban!~^~-2Oem#4=X0DD-ML( zyTaZB5#NDhZ^B;}_8o|#(+`A>^o9cmaQoN+wLoNnHSf@`gAyHoP_omCUx?6dCUpF| zu(E6QoA-`ZVggf<1VG#s9lowwAgETBai}UfuplJ%wyVuTRnZY>Ro*wt0T|B#_`kSZ zhLPB%#I!pc05x#Cb{%^Y9@=9EK~m@-aPESqHaa!p?FzN`Mtt32Z&%pYjatVJ!b=Mp zccq067_rJiDP6orth%ZCy3@(y_`Vh%XRYO^hgJ9sc)KdVMO)gc&DWKOpIVo?pbLC& zsUAY-iY3HebF-A_plEP3cB8Ai{AQ)NH5@~6mbqFL#nfRBnOSB~>IZYzL7vB|lT5(z zwW;O~XZSF-yU*PPA9twD@YkBA@>96u0Ox7ImMX{ybb*EE?hCz_7WyT0zMj-(nI9-; zggZJJf@4#0t$9SQTf-C`aG+&gT3>8r*O)t{KoWh*ArryUJ>W`E!n4gMR3&UkSo16v zp|h3wg5~2!Ga9ZlXDC?N!F=*5L!GGUIL>JJgn5DB37q1MhB;=R?2O4Bhtc3Of9t%H z!f3eO{GloZU1@dw4dyr16<2UOQCg}_ILI)wPZ&f0QR85Yt(wmmo+uo{-HVW+%Byx0np0q%By`n+qI6-H}Kz9k~>_mISZ@xE{ zs(_#)Rim+=vfle4M(l?ev1p*P&1#^t7a5F}50AY)>fo9qhSArzW*1crFuoj$?)8j1 z);jjfQLoV|!QGuy!GL=Cby#A+CkMhqJ4Yu@=Cx*n)jnB~hsk!m5A6p&gyuv0X71y{ zJF^-YjL;8{wT)_p3$3qjkZRrMy1X(!v@gS-h?{DixaHMxa}0=tb|qRMwdU`y7UGo& zmayOe!m!K63FF2kGOo`2w$!D@1ndcQ=B7*ngWnB(SOCWqmWZ&E(gC11)S7MqP#5Xv z=}m+<*Syoh23`hkgZX+xJ2Mj*HqV@*N?8jQ*fZdY8+vOD@l_tAerx4`IY{b6F9)t! z+vq~-XO!P)wkxl`GTOF5)p^*N$9`$+!kf$=s1okbYEODo9_Y+sx!lBZH=EB&x#(pn z%iLlvlQL35_D2!{ebV&B7vhjgEOe`xFNL(ha+`U+x`1tSG6cek(b8n00^vk2ITq!& zn;rS8+oDS}DlFf4sc>qHE^ZC^JIwD{#b@XOgnntPEkJKPSEF*L`Gi&4_JG}Gu8?cG zz6&%#sE@VT+IYS>PnDsPM0bs0G3`U0=BkIZ+i8J~$a)J4u zSCSL%=$L_u-D_@_VzENa{bALcUywpc{GU=U$!u|-d55Y*9f^($9Z93IIresJ4hotT zR?}92^n?Nn&C&4%G7}0km>*uDXw*%(5(?aJz8zn{lTcuh`D%QD+=K#)&5iK|W+W7N zz}A2ugRfzWC<)@D6mpT;JU z*DK7SPFP8Kz0!O)&mj}g7uLkx8?+{$-bQ4gvF!o+i1}|;9czG6WnjMQX|}5LJi#iy z9$R~U%51i(DCUbIN>pa6%v%!*Q9C5);nn6ODWp|a=$#pfWga!pi3g;FECJAC=I<{T z%2T5hWJUAGQZC;1i5J-5GuQjLU4%#kPt)iP-uF>ToUbV3H!lQOELgE` zGaMUD=Fa1;^}hF`A*cUt&W$&r)oe$r2g1HXjL&GmZrUNh!7VNEtn4KEjzUP4d-Zx5#DT&N*_mbaeK zw|pPeHX!avJmA64@!m>(kDIWFY>=5X_$2S$F8AQSuWQKF5TD|mnR2HgM+<}bj<^BV zd$%D(z}n6*_v?#W8{kHg?FDn2zW81A>^AOYZw+jfjcf#Ys9o&HAB+1MauGho!Eerz z3K?DJeh_YI4X@t4*Sp<-!5;B#uQh);ObJQYyFU`x4++|i$R>!?Zm3gP1#@E!+ml=v zTfqgZ&t*|F3m_m~+pz#@jur*GC~{@F>KdXRP-}awY9AZZ3$mq4SgmciDpK5f=N-Jy0-2JT>sy(4qX_*G1bcTZ+vE7vD|Izok`4_29&kVzf(tH1FJPoZH z;$jWD({!<($h!Y^)c|y`VIZ4{C#HMLn$>C>7)*@xC%)yFraU*_YfHl;pXL_WYM0SCp#?)Y=)RPqSO}bmUF~JG z1@wmbHMQ}WDFiC|@~~3om}`MrY+;0&5zGbB7-l|&Nw&h|tkCLq3h)*HO|i4no)w~c zYr(v(AfP=gZ6od{6No>`m+E%S9R zAK#E6^U~oAM(o@^gf+0dYdQymGCYi|0x`hBh@KtY)p0wd1N+a4^v*i-TdFvmBC$Qx zSpVM5PU}g-I%wDeX5mIu8MIda!d`qM)JYct^14^JiKzC($F8eFNReO=?%I`9`lArom0961*8A$j-82ZJiM- z=Oem^6w}1k_gBDb2|mw?+tG{tM~q_NDsQk9U|(Q4coF<&nd(v(Bw%c0n7X=hMq1Y6 zL#UTWs`E!?q%~zpg%#CCR_J{&y9IVt3pSx3>1+&=evfjq!2c~FH3)VDf-q^Fco0J{ zZ#a5TDG!N0>Q>HW_-nh%d_Bv94iXqx+m$H&3HXbA5dU#D{tut;z&$&L`!ZP2v>FXW z4Lwe4#QgQyO1e}O(1k!)?Z)>MAw;XsLkwYk7bWg-VUa%RzBugo@;V z(-Qp?sZ_!UCA>shi~bB(Lyu%aT2Kd(i=xZnlVMfATcp}=&ajHVsT&h}7~U?mJ)js3 z5K8Oy!ar(GSMxu4p(2_PumndB0uXznhqPr4d~c+*nQw`e5$R$FnLn1ZvaaQsMXk|t z;0Lz=oIVT)z)~4Cu%0V>6JcBkaDq1~Jq)_MZn&MoUU&3>DwTGu?ZVc-wcZgIkR%JW^&TbnVPWm9#JU4HL{wEl5p(k^3UTR%iw;{XuqZg98E1j090XWnKtn!y%4!gu z_6jtuQc2^~K&N(uSFaIxp_H7ZHz79cH)&CXtNg~;5ctjdKon+m6nvSdY7PgiNT3r@ zZJ~Bo(~N%CG9gRY8K?z`JrVb(=_~kPeAZeT)e1)j7ez9k0!u>2$2Kkl6`@@S7-uvH zC14np6LzuOxD<^xc+72?O3H8<_6#QfsYcU~?SlZVqa)o0*&D%<0qs2%u7Qu2XVAzs zv@+3&7$aa?xYFHWVkXxr8Vu@E4C=x_+1U>Hafiy&5bb;q;Rd>P9)W&zhgNyq=}qIE zBtdUjHzRI5Z1Fn;1uN^|079qJqhE`Tjlqj#r(se>$5=%B&0osQ3F#QrLF)knY3Dn@ z7<2K_%d3aD8WD{y%*!U9vp0l249GJ&dZ|;q2=n8Vi(t8|wHwJ%jftRHt}B!C)ZgF( z1hm?LA-Aj`?+6Ntq=nPBQ&c)O;TLjC#z$x^+r3w7=4*tTM!^RjseZS3g?{S;+T8o=-*1JA6oo`jm~vuqANDAE{cvdYVWY7QziEy0@tY1#{cn{F#qaIcs5)TqUYM?K*I z3zcEF7|1;vT*Au?5F50%DbaYw8#GOn=>5^0Q5O( zzm4Ow&MdV+II8LH5&wCv5=mdn--n{?`#2jXR4-6m>f2)+w+S&@)!Q9Ww-LQ)^P7$@7>8nG_ zG>)RX7{k|ys9p$Nci6=_&WbALpmBD!;-T>0jcKJROLaG%Msn>wWLlMm)LhA^8M(qBqACaVtO?7;cQjrpe$6J%c+mj|xB1}$o=*0G7+giUl8Zm+(? zf_ABYRyXO_MjNn=jj!HN`5QUs)8a1Wc+LD7PyE2P)?BD4rxgTs&s(E;OXSr& z4C52s8@)gJ9dH86=PXvjvYElXNL45>uT!FUeW-PP2*iWe2V2+a+k;V5bC$ZkP3@%q*u&_4jF}~>u~KKR4n)tm(WK{UK{_8NWnOpF1)P_%-{3v82%vA%{y{A91<_WL z8=P~AY7grGvrk!Zo`m*7o%uj@sMphU9%QF}Z(0H7T%=W)-8$BwGh4iEDi{nMhDDWo zXu#8mC<%9{J&Str9hC0b&|Gs-nrA&t5>af7^{~8OuS%Q{3_&Qw=nqf?4~f9pb7@R# z;!?egaTUOhVT|XRdT9ptO02vs_DY`0A+W_6hhad$W>Byji~00H15~`kDx1ZM3K%CWgVE3(+F1a? zF$rk>6a6tRb7~rmOL#bQ?5^kd0F`mx1-m?f!*AO-~BGGM!dU~*6LF1*avo0 zWA;~CuL~2U4}_h4?nu#HR z6;C$}?C6yu&Y7VP+^a^h{8C*$bbQzm zPf3S4mV{ZMwJaOhoDt~VkPaswJ&QY!(?-7kV8(_uN;0cQZsFz7J6Q>rzghem=EAeH zp4mA&^v)RVjF998r9BaaP+d+b;^@Dh9Rr3q}5Hpols=L~A^ zxDQ%Is_sEsytAizP&*dF?NInz$OwNhh&hH6X|N64Fn2054%QVA?+FJsqezCg2g3wH zIToh9&(rZ9)T(o|s`*IufD3X4R55c(+!+M5-?HoHGMo*=F{3&4%Q?^&Y8b#yv!+f! zk%e7)^ax0ZZ<`a2k|(sv{X5JDgF1ezcuyxQXA4Zl7*@0(uqeXpjj0?t6b`t{UdPJe z*Qlw6T`xM0;pVu@btF~-)~LrNCGtJdBhezMEu_-OQcf67DEjW04vnWe6D56jM$cr9UOPrP9XN5s^Wj>iBMI9y^M!@(dynAP=zsh zWmmEnBO~bzt9yaJeI862WHb1~DV3VnTng4e6Fa!C?qe^*73!G}vD$`^6eU)?V&+D% zKjV!rPIywjQkVZE#E|7%QOj=OP>_gyTR-{laNutcn9-HNXmz38Q$j3!Rq^^p+> zQp9|0t<+H^4OsP{XCarCD4bo?+7Sf%Ho36yTdl#zd5-?dwQ4=v(NC;Y9 zJ8q02a%JTCk{UXm z(R41^fa~GFA$Sawgmp%IxQk`}?M+br3OxkkBOaF~YiIPFNC3AX$aF09(S7tU&>1wC zMiPb42e&p7hp#|DI|7taZztRx(6ZR9z*CZVR~3>h{b%TB5)3#B(~9qpeXb&K?&#}6C0decmh-P@jP#vgOtuP-yz6+dh~f< z_cnYNP4|JQ4xoQ0D)8n_XfwSDo_jpjZ1Ry{*u`1fx*(rzezR1c?<@P`syr!^r?0Wh zVZWKJ&r#-4(*89JhUi?(4`qQv%csLcw&W5Rpx424TvDutBM0}CTvAjaZtZG>4&@ZY z$*?>6D$1654>i#jH4i;RvAlQ9IxlJt!dLWK<))uKr#IV-?d7Q4X^!0%CpFeT^ zn0+nt1tcb$71eiq{$?P#h%QyK7ld@0oc%xxv6`n)f&CHRzM;PT78GuYaI43P75>>d zR&#{H$nj!)5)vX|1pOzqrYe1$q`&nVLXllHIvq8%kL zGvIR1;3A=?tkU%mEJw_gJ(26MG!>V8@0&+3-_aWA!HWlY&()G$TW3E0d%|$@LQQ4{ z7fn6k>(qS|^k^RXM%w!nopk=$7n0B-TUam8zoW;I%?nmMkH1st<{8SgY-+WJb zt6*Vc$CfYjxruM7=>lEcK*H0RpHb5^jJbr}E@jWuwqRvPXua6jks}Yv?mS z2}xsoudLw|{yEn6BjS76p4ur!gC^ea!`;5^BUl4eaON{spN(xnZt6oOy3s$1VmPw! zZih~zi8p_Uo0tdjWC3DCu&sm{l}~XgW5fgzW?yZ7X!mFh@76V|yOc}hdR8(&P@RRj z0kzH5G3b1Efp}^N5JnB4(gkFq$IU*!6Cj@{pBCkBX$zK+>~DmRaFT~#Nxw=)@#1=5 zs-iL=NS%K3F=?8jpjWuy5BNzRc+e9>&;;#FwdsT{8ADm8ycS8*6%;?`#pL0Q_bhn; z8d&9FXMmi-Bo(R6#*+)syx2j3hgP23*lA{B5g+z$iTJkQ$&PoAw90&_VmDOcc z<6z^h#HewHjt{}^Ef;+NWzcx&f!VT%5=3MD2k$MqVx($URjEaoTP6g( zC#uk<{zOAC1F~zeB*BpD!3$idqo7*VhJq{X=K?8yQL5lWF`;UW68Y}ERotDx=%XR2 zv~BisY*%4$FBP5xEMF1P1-oJdXMw6rxLr^-T$u@zc&}Vi(?NG=Wp-Z^eILLkT!lp{ z##B#Pt>+=w4FHerH>@MO;Yzs}+`opmYvHNTW`%hAQKc8mS?<9jHDu3qiao9wU!?|TuXFel5_p266WqZ4#Zv!EC zVJ^lB=o-SVp>9gjp5UhX->P|7s~1`C*VrNk*HpZSQ2~D)>NL0yOgDf3F2?|Lj(YGP zyO{JHcWmH&13S9r8~Q#b{5FFQJhRqZVX8_}_70SVknF7*Exp)=huzU;xDuQeJ>a1f z2HMu_`WyDYL2%fQj&UKnGF)4O)4emK|H-*WWfg)RKLCRPo0nN@58*C!{ee)=n8wSY z(+_Y6*O{*<`<)H=^?HZ3qWfUFLTs?3s-~(It{J&->&e9$@`JQJ-Vc%X;y4Va)lr2q zkK@9KSXvmXBv9fZDpSzDjF zZ-L?I%X{Y7J&d0-)dt&9sKGH{5mM!$eH?{}P=V303Rz%fbSzhy57Rmtkikrj#b(Ey z$g=bBDzjZ2Yhk}zPAMAK^@d#?6)XV}gPBdnc1K+Izcz$?YpEV_fCGeM9`C1el0rrn ztb#|vcOZ0p%A>EbldJ)SKFgF1Y+l0(M*5NKG@M3i5TbSzd`naBhk-}!r~yZcLjM&p z^ix%eRdDGFAyvUtQxY@*mR_)|pslEoa7t!HDtoa)g7I3vw-Tj0{P;o7rFC4347>-u zj9d>L!P*0pW2Z1wSdNu^FH{#FT~QcOdtswplYv3p8u25ZZg-ReJW1=dy~V9~U0m3^ zTSsX|5OHg+QDX1z*dr@}Bpp+QsJ;E6)%y)BkbI`HxA$W(xZ)>iE49BazzVEux*HwWiA==KCy9Cg+RZJJ3VD;Oh8_zCKQ_Z?~?u=<6kN zeUn^|u24WquN~I*4R+BeWsSs;0|>i&&N-R87I_t7X~9$o(+a!XpphH+mB+n!lmf z|AIPy2_1LAqkbc%8?HPO=>Z0R3H3bKNM(znwM~PqR-qz2aN`UC z#XMEp5TTx7S!F|LeU~_Eegua>t%=B`S_8Z<{Xhn$TDANpER<8AGZN!zO zbqgyo!BL~V$CiCmW(h9msLm_JSVO< z+adFGj3_S&d?R?j#;*wsQ)dsRVr)YoY5}%e4;~o++u03xWI*L~z{c%=5OwLKXG3iN zh2f`tbu}1Mu~iZ9SHYNl{yFNJ&;#>`V67cQEImWVXRN-EVv3E>uk3oO9iGQ!nUMpS zr(x);ZU z&wq_-y$Vkbdp%b%GLt*lYGDnGWHp9JIwwD3v~!eed{ujRor8p9pkbQlU^PS~2aXa1 z_Uw|rkUbj2b>P)}Dr$ueA8~5gA@%Ya-(GCqdwcM-30L_r+wf*QEMBs;y=e0bs@RGH zi7{R|mLw=fqF-Eo1O;CYO{L;q#M6VQ)UN0!?R{Q*R}vvx-CV_4J8#lM{leZAlvUi= z*sY>y=z;T_7aSG|h6gdmwwOW$zYxD<`LD28$^`9*EW%cHu=z5jyX(xL5<=0Y{mTb8 zvK-e9GgLW8=SY9p@Zp51i&WD0(F+3%Sp*(2n^_lZ)j&Q}J|Q(pTm9**kCL6bdjK&f8&1}q$j-tEoa_Gwoka01C;OlM=GqA?H zMx6IyaY4ztX2+2Db|TDrnvU-yhClUfECzp zFQ^Lf;;H6`IO;9=2Y%JMVo+5~F8@QU@`Kqa=yApPcsg&>aB>x#m}sjp7>BPK2^(3Q z9rj1dm)T#wrN0m^j#W6d8oeBOp%2m;hho)=e#(Puhdl?UpAp=wn}0#U!;6cRZln^n zqs8b+L11S$LP!`G;}5>VTI|gG1&ipL!B!3EW&xxmDGqF3g6*DP(v_ykk$^i zuA@VCYd9VSryoCpT`WKjye|tWr-Da&LC+ZL{!f$M4|QfcdlZiv@Tr+W4`cJHyDx9u zMGwN%_kLI%y$rwCNAa%L553Xz@Owj)*L`%}emIx0@gJ_>bnfd?JI-B^>s&)?+)X)H zXnt51EY~=ELcE^QOR-G;P(~({^mU-~HWs1a<*On4&WFn{tHftpIsG_dub;0$##D4oX>(b=llN#VA>r!6u zd0nx^x-=sAlCJoOTw?G3Wr^YG#gV?$@VIac$B~U=2accOID+H9aKvU4J^#k|zoGW3 z^?{z|)jesAF8ro9ULLIiL2w>hO3WYJq8m{Kn-21hn=Vi|Vz>Q@XYiw7T3Nv6DJAJv^DIz* zNC7$#{sbRfqyg;wooXY#Qr!4d z+uFMd@S-KiJi*LZWHvE#88Ta#!R*?*gBcdy%?wmi?|x(y+qfIj>kl5_Ipy|4Wp68G zI~@(w;Hbs%NgVg!ScJnNZq(mFlXa;teyHl&#xM%vzUYIYUQgEA$Dt5ugmEFvXN}>U z)lW^9C_9V<8ms2Z28~-iq>kMZ6&vj@#nV|pQEfEBNbaH)34bUHSx;VKb&GjaI^PPY z#ygTT6->OIzBi3pxf@%`&Cv@O9Nhw>vDs`Djn!70jKJ;8=L`qVaNrCF&T!xi2hMQd z3t;DhLb8~9evpFrM-WYU-FTkAr4;rqu?fZ2!3bycdET&^N&1C{ykOL zr&5n2f@A3)=Sz%c8`l^&q~K0+p7p;6dDDp zUCHBbLhwm-eF(V3*)Z4e8Y?g}lB>({%{3Mv_Ym&fgESYv^KqA4UI;#uvX!{H9O*Kn z33nUu%eqt5%*ArL1ZEq{Fs1} z@l^7DC8%4JaGl&(g7$;Ja2fK<%?GZz#*N0csG&bI5GK&Rp6@WWKT=}6qKDKA9U`mo zt&45InwtTGaMF=P_xI5cQMnNk4PgKu&KVGUd|F!faYgNlX z^#!Fn{#-*yCYLg9q#ny9!#@=~jZr+lsoGACcPiM4xY{(FJe*{-oC=&1_YGHW{YP&i zZwV)PNpc|--{QGz_ffJIlfy~H2f2Roa0cc>YG{8iJ~;77Mnz(~src|w;W*3p?;Ype zWLQZbRa^678cuhFWp3kI{*aZ&;{ZmdmFJq?wL!`ZLO##RGsNO%E04!9j3=x-*ZjM! zJe~nD+O0gT*X)SE;j5HttUMmL!d|3Y$6IQQ=dC;fbd5t+9&ax++)qfEX5{Bs`8CMj zX5~MP{8}p?LVk;tUyFR3m1mHyt3}{^26?}g=kDl6E59E3b}Ju7-t$>0zXAE1t$YOe zO;-L1C=F5%yp$C&&1zg)u zic;UNgY84xAytVR95&P9n9V|)(P^`!YTYnaSu&9Z3Z6&42Q*P`);=XPQ*K_d@|2rH zR=yeeZYz&$>~lTzR-^H-YMpe?MD77xiMN&v*h1RYdqCAlMc+KszaJ%N3DPzayEZvJ zv%sh70k~Od%!9^E)e`$+F6v*OvV@b@g0)R&a*SeZF}8eO_?d=FhpasLY<$7ybFP&q zpJ!P4X5{a(^2o+M)k?CKLfYmlNlV3Nv5l`WN{xxI;7d}{Cgp@TixX^UHX2_)SqZ}^ zf7+(;HY*=P7@3=uC7+uA#V0A}GOBFa2jYD;@K}X|eBWf@M83CL`DWw~TX|&FhwB0# zRz!;+qqN5F#foVm_?!#;?Dd*~mB~W2mRf>4&XpX2RH8m>CA-JIA_toQUsgNwkaA_c z6ssPN7q0u_Av$GmaZ=pk%M*vC&)EI(gq0`lo2`5^@`tTFvayd3m@Eb!T!W+~b*WPp4FEGaMqGO~0ZZyw zuGlHF4*`-$5PO7@p+7YaJE7;FglGC5Q;i=}pQ5!tmDi)aDjZz1$8*O(4X#}mq`XhL znF;OxFv?N766-tr-g%E6ft45^nv!Y@_cY+Vz{;z6%gS@!ddbRDpSB^NyV3B_-l;~) zF|I;Ntvu}=yrNcJr@ix%m2XCVx0OdW?lTvh<~Ziam2t8d=S>*D>|5KLLOyZKC(eWP zM$AQB%GZ3=^U250wJ1Z`V7Yq$>t@Vj$-Ny0bo?Y}`HAqmq$(k0CZ0r@NheWe@=288 z+;Jj&rktRRW_;Uo(nsv~%r8ow{hn{-+3$0#Jo|mAm1n;{ZROeT+pRpZv5z0Uz%fMc zl#Ils=rwxQ49N3BaFiOI9yl3g>`|8H$BQ2Jqi+h~^Sar=d;0O{$0Cf`D8(;J6=6m# zQ8klYr?e9ndYtIj%LjxdD#uwUnUq{*!J6Y3-?#m<&7W0Pp8VNl<^P8Kb}MgHSBX9M zY5M68Jh7bmEM2o0P~v44YXi`;5-^rKcoXlZvn7{EoLqU4;*&2g5`FUJMY>sDf1Y^W zmcQq%Jmqh{l_!6Dtvuy#+?S-huFuq|43kfd5sFnR* z+Rl|Iqvt(jQH#4am9hFf&xhyuD#z7aj1P_uwns1bQYGcdB%Bao3;&DF|5a9A>3u6t z$MBO@J{S2-Rvy{dry4UGXSGzVB%`y~z#qWllZ;MYulcf#*8(d~ycSt`meHShu4@}p z{A|hEo@i-`RBi8ewB7D#+f34S9p;XiCrx{5daF0t^v<*Lr1v%}uW4nPNRzf>Xlpe> zANV0>P0)3zdc-+imd8mf?E%h;PKlM4Z)U&aNW*D9_^<*8@!O2F8wbZ}9&iof;5glA z;oXdUTM`;(LrTSBk6#6Fe0%~}tb`@A1S5vFPbxa9f$4oX*yE2V%&FN)!vh!-^w%v> zRuxBPD%qTiJDg9%9!Op8T9l$~Zfo%55aas>NZ?cQuhO?1Oa3JLEzbVn=+%5l-hu*Y zta!nemrYil{n2XW*&j!(Jp0299IA0NBOkQzK{ocO2CwdcXFz)dxJ%=-xL7crHtN&( zI@El2op`;htxfJq)uTU7RF~~}UKARek)L7Zd0l_}kPc!XyMMGSWIw7HnsgEhl~^hD zFm>WWNCW56N{kOm_q;uCq+YUP`e@3Hcfk-nR!5@$EVUjNh|85G zpj_obe(UgiPm+-WG;wcM%DYY-kf`7ExUy+U)dKv)|4aInJUwLP)!5l=kNI3HPn`5; zwk3C5UvVbXeJXZhYTnI;ohg>&GSD4FT}rPV4?+0!S+NiFF8wU6g{oQ(41_WVFz00UOpjS3&zZ%F^* z63{B+vs$$^UzOp{4&b8W7j|2D%Jl&&Pq{v9m$y`tYwe)6V-Lf^oh!n2TQ+h^KHA8Z^rd* zE6+0eqj}CX%ss|~7=zr+5&Mli%QZ+by+HTjO!R&H9IrW$TDGe(dyD+ji@E@9$Ot43 zPTHtDYGWYl-#%{T0^c)-eQx^(LFe2Rs`F_a5hmZ&kqd4yw!ROEs_+b_*K zv_Qqy74I&`mfimP^@b-uEP8hi(gN&xP(Ifp-H81R%4a815B$&6yK|7b;j5+ItwGv@ zgMONP`0Y&i-{_xP%C#@nv-Hp9!?t(9UL1`4ZAdr5M&y2EC(>20L%1Kg3F!>zf9^+a zLF$378ixE*qzf>fxgWU+>CG4?+>cy})WktumJfNz1>f-cQp1nbwFNIwLcRbg#~re< zPXHr<(LK~T*CVaQos+#bMsa*R_{*GpYVI?PbmLL5>oYjMXkFFk&*IuoaGVDguEp_l z94@f%W*k4k;Q|Y*alDQrA1r(wM;_RB8;&2~Xu~laEX>F8863NCWP*)X;J6OQ0vwOx z*o0#%jy*Wi!PV>H;?h+_wiZX8d7#d~n%g1ukI z@ivZW;N2k{JQtC4IA-9Ohob?G1IHh5u$?Kq}hj#Vd)KjHA_fj>B0V+`YN9Q`Bwr4 zj&>X$;DEVi%)rr%V>gcMtAG=Z@8C$k8k!l$CLCQj%EtnC9B<+RE9GBIjZ5;PvWZ#D-s7>!vGc|W^3>9lA(ezVQ#2>9{?qKN^5-p+S&>W0Wlr_#U z6%)u9#rS%2P)hvcoG~TNZ-LT#j8dc@h-)K>G#rCmDme5JGMbSZGZ$^J9{0Ve8EJb9 z6w#B^SpB0MKT2y{O_Eyby%j2_?M~X)nHO)xoZGD)jF&0KvE(bsxC$}Mgd}oJ zIg?iUOJ(vanBl-VJ97F&kl7p3BmAwi>e7}IJ1()lZdGGQ-kcnU+$o};cAlbCI3&~> zSnuliZfdM?3J;0tejtt?x;4RA#uxRa#D=r3+#x)!hp2bvSQeSsqx3E&yoV(yS>vx5UWF5otY<#~e#s&*}J!@z4{Z74=$0 zO3?0>8H)5LFQZ2WG11Z@82X`2X+=Btm~F16+QF6*lppGWWy;sHAl4h&4yJ5V4)iWd zB{;DFrCE!kkoD;YmYo;+itN6U7VLfzzb5w}@5Blq9*)gfmY=KSgEOzLO%0vw`HktZ z61KGHI{i~h7JWyJ7M(01-XhL~FgVn8d9r~T)*e-Lun-s{Lccdx<`R*=AVw`|6?*wQ z5QJ2`wE1RhlTvG}+R!;p*rQrQ(+4;gcyaX`FU_P)%cB#Hf%1&8;L`~9ESXAc*gVv* zl4&>%Gk!-SHOxdi<8?n9G%nnX?XfN zQ|=?_In{>ihg>`mlLn3&=Qk0a;K#U`2QU_{RqzJJ$O+Bv*W~!o+qeR7MeCgm+~oMB zlGK4mz2TtzA8*8y^L*YbcYrafIi`7jVy%#hQyP-fLWm!W#D_<|>#gZ>@PhPsSMqYW)tE>S{+C;i*y?0qtG zt+S0p*qSHOhRjg*S}cC1aKbs+yxm(TS0i!OkY_kG_f8H*|5BQ2Ef0oc-1ILkR}$+; z&-u`oI&SgQu}XxEl|1An*_@lJJk+ULjE7TzeL%4{lhK!|tkA{Zk2)u4h{-f#JXhnT zESXMEoGYC5Pre5~Js671G|( zbwySLdjDU&|EBL4#x2m3v@hgqx2>-vrWz-wm0-l`>(aEHi7U@j-?eFyoUGwBjQ*)z zO7PUSl3p>+h2G~ryZAo(TdvorIbkMjQ+hN`*5cJ8&erj|7vd%CL>it?)oNJ%X^W?& zf4RShhVPF>{1x5TdaN1!`Z>OQZcJiz4RR=XUw!mhgl#2aWWztTSwye)66tWB+mhnE z+CQH-i^xdq-;<<5Mr$GrO`Vpn#QXMnVoBjc>Urz$)gs$H8O`dnmo@HMMr^7QbIBl| ziXBcYKgya&W9ZaziMYwRK>c{DB1TeZZ-MN~F}id-G?eUU(J#QgO<5P_Di88~I1^6? z-3w&Lm=<+mCyDn zSi|C1O>GA(QWh<>Iz6B~TaMPWL`h#Qz?h=fSVNwO)+gcXgFpWfT(zOoBcVjgSQ|)(DJn5nl}bUWsrt&ke;1eWvM_ zzGPdxLp{n>4OdO^cX)R$B!W?9_8plCY>$`RVcC4dvKInR=PtNN)jaUUj$p5ZO~tj8 zEoB-*NmFrwk@8n5j~P8%5?w`^J$2{?Y75@QNg>Dg=c(h(c(ndpiH~tgEfxK_V&hH7 z?2&kmoDRqwCJ&XnX%CztZcn(?pqym;VA_qu>4G zd>;wNuk0{#&Zj@l_AMrk3a4CY4i+ehb*=yl-Mdj;?5?c0SS?q zYX2iSp*2P#zQRMznM55-iRJ9XI74bLde?Ozwl@0eU6s zicg+8-VZ%jhwtUcKdg307{S8*6QPP4ncB?O$jR~M%)v-w_Mp@EevQQg?#W3{@`>+- zps2rIc0!Jq6V4vg>>5+<5$O2Q)O^qq(w{2^un~@M=Fpm-au+}2>2uB}vUg4IJjeS4 z^%a>+#9MH$QaI{oCpog|*CihpC0U6HjDf~?D%~RfQpz@4V9zEWDNZbH`ejD4IqL-s zts|1d5pFtvosi@EjpLg;2wd}?3S_q8gl^-_@vWc4J{^$b@#ZK@HM`L!5UY1!{v^kn zBQTj?Q+pA#{g7(*Pvl5E-Y09n4aBkJcyk2C`-$~#)jg0Gd6vW8_e|uBz+A5Eq$-;fi<; zbj+WQ>R67o7Vk*w(t-BVDlz5wX#N}ttFDe z*>&K4bz;|_S|_~IN39L@<563OaW8RW{Vks4Qs<;LRbSL$v_Aw((yuJ1)NrIfQul?8 z-N{g?dsoAY?+cj&^t)APk0*tf{YQ|0g3>?cH%_yF!nyEAx`z1^{Rp(A#KRd<##2?SsB-%BbB!x8CKuwDdWJM|l}k!E zjs+(DBe@u_!b|#LmZ1#oHGe(oQ!!C9W3?xW0Xveomf(;MG`gl`1}!{-V#dn_^8KKdT!;d z5V~ygQLUwd?a;m;{N)M#Dg3%229a2>SI7(Uf06Q-e^hP^M2oHS8D+>(AaCtiZfObf z?rOBo_;Nl8MSS#(WRHWyesc1XbNQG9t~naXZ} ze)>6nl|rjUKTk!E0_8&H811>05~pK~3f)yFq?=>h*O?!8+*^7-N{`cb zEjlw^q9#I*mMGimROzPXUz<+u^J$tn zqie}Nkwr|;sB_2TRBa5}y__!-wFCE6C!eOibkgXwG5%-K$Ptoy9jDiCV*8xPGs(3m zy+vI8@)=0IVyEPDrRvnhye4Z`u8zf*SYWL!ldbf$rjT(Xzw~Die?7|e`d8M0_AD-? zwap`E@v<-1Z0{4#HB{!EU+xsjT1zBM)>o7`;z<3-(z$q#7JrNIJ01tehFsUbc1eAO zVz)~SQ{PQiOJhjCjm9W3O^zY) z5DY&`iysHWM7-?t4p( zWoQcWe1D&P#d-Hs`RG?tSo#rVagv2$a$cQY3~i}Po=Yx^lapY`xh)lLa{a%vm#GEW z%d$!?f<;QZjqA{XxJnEu36)4$k}HQ`lnS#k`kKPHCBIo}^!Cl3=b)91-C^qvL`#qN=RPU(-ETsd_NXPp2;S=r1=(2xVk zVe)==VyL4$HScsPJmlOQzk-$+Bt}AUOjCb|y{OkjCraaOQ-Q_^N5o-|2|nw(&b15!-?v z$4Gn}5IM=w#yOb!%sGlU!anZvVz!i03O>#=Vq$YU@jKbrUpoqodl{tG{@VDRj_0-F z`FCp1XldN+7=3vn>2y3v<;3swJUykQls>g&PadU;DUa_3O|w%=a$aSmwEYHEi9Cqk z&G14abH8_4LceN=Hhz>p&Nti`}znSMG5y$02bcGJ8>qoV1B0tFcLy+V2G` zfVHb3P}4Gkh4DG^ek4jirFoz?d(E`!Yx^Trn{s`i=fbNUkl1pnH+L0aRiSYvRPlka z=LUWUm-b>gy=6k-BGAZZcF4&Sc^L}W<4Cv;b3Uz;{M|be-5nn#rsIDZ z?LsOOpJkt``bnY;G|%ZrPxi(S=UcW2SN`)s*OHXcxQlVfyR~>tVmJQZ{gRKwgL8%R z%WK+N5ZvScgPprK{KmigLYK5tu8kAn@-BBJoYyrT|L-^` zhO>O=MOvdQ%R~G9wI?|7ePjIZCwnY8sb-!KQa@QwkAz*<<|}g=lJjcnr|F9lMzj-x zrb4t5W4I`ziEkDwj@jqV7P&?!RaDrqIrclhB>tT5Q7S$GB~F;hAnCUj@LwbQb3}8} z2dtg%3oA}SwX-EVPYCuIr9b`+VZ{zD?ks2LH4fxv>RpNduH6XkSx`GV-(E^TjmR5g z`{JX~w1+_WAiol)YtN9RRcrV&`xN9@;`%$@??s8S`8m)!KE9-`Wv}B?`@E9-LWl=v zTD$d=$$uOSwO^rsnjFJ3`xMT;v3t5d|MZpQd_1#Hp(Xp&dH6qVpQ2Lf9sWm=rrjw^ zcAn$;RQ4&f#3fIY%i)=Q3f&i44pZywGy4>pSGKIiU(q~FE`f42xg7rgW1m8H9tYk_ zJ#`-bXLtT%j#it26rU8F$5hd(crc_CE^fIsvQ-?#IFR9Px>tdRV`V zmz8+DD=p|(D(l$URyCmV$q+s-EbnaP(;g>Vo1PfHdrHR^CE_X1kSzNM5V0wnvE+5(yjkZQoM9rS=mo7$&)XP%O)pRs&yCnDgTSZ z=hk>nubsIXq2EOQRf#$BF?m_G9t3uL0*&G;ZytMtj?3}Mw}VSKgfT)T!OqjqomIaw8S?D;2&dfm+z|K zM|R$3tMbRN=EF8cw8w>a-HLYGA{1~;l3PKhxSvQgwNHaj=~qL z4Ai3cmFYr!4N$oPSMCNRoxcZX23C#tz)L5-6r5tuu@Sq0)c*YMr1-Jv+(BenzFpOi z^jiGRL*M)0`K!aZ9cf28gl8<@n4jiZKQhhJo15l&66sx+rFk|Y^&{Pa)O~51XFJjv zINy!50Ox)kZtNbf?r326{8w;)}CbO+M?z;hqc8MtpE^&{;zVUC|py%J|&*%T5IsbQvP~-o1h;8z}^Z2jAoB<^AnjDe;m!_`i zUxx9Lg0cAf=35LOHMLHf5)e{%V0;2^y$Ph0jiZw!W|5!zbtbXKx?IQDPs=gJzhQ>l^T}M-NcXOYf*>)2131;Se7zD?L=A_!6Z+Q^4U|-nTh3{a*|j& zvFypnDaVP-g7kY*3(Jm-{Of}~cai_}cHM*Cw%;dqBg&H_@j7xQq<&@smvrA%s!>Ue ztoMHCKNtN;zG+>~{djwZ=+8Hf0R2BQV5BBe%(cz#3)1+Xd(8z%-AHSY z;t$}OZ$mm9=?bLy^S9ninC( zpSm?ajTC?4*1Q=h{=ltyKT^^il^dR(^24ndpXu>wGs7^^n{ld_P*4 zlRyEl-+U3~Kpg9FY{Ib}#{nEB4&!3!}FI5N`2n$vGW9}g>C-Yu7y zOcMMvefSs38T;qyv4AQHWy_^3))1pQA zL!Nxq-<->Ef{*M_%6|`eF>}m=eNczG)Z+G&pw!rWs{}3cD`A&k87sjzNpb&YDqv~L zIx*#&tHuDYtC8{}Z?eL_IU=7s*YNmn!2f0<-GoCGuzohe*10snzJ9DP)A;cRg+IN1 z*TE6%{tTOY+G}OkjQ>(}{dm~e=ZTH|?~g9M=ECa^jrd}zoX`KyqmkFYaB#%ehZ*e~ zGsZsgLgA=e?|ue0`*g9{(OmOmZ>+nhqT9CH$1Ps--fw@Be#3L$ee22F{{6ti`OB}~ zc}dT~5#RfSv|0HFU;4YnZ;klULc_Ip&7Z$~>Fc-Wed@!vMtm+!U}pSocSime+wOm( za@{+DW6N*&e9MCJ4J*HMRsGL?a^deE%BkA1=Ap+f`KL$1uNG~5VT_~vlAn(G_d|b- z;q%uoJaE(C>5GB$6oLQwg!2(UYWUwjT8sPTa{sA<&Ku`AXuRy!>z}=4fnEQ>+LE6P z{T|M5kn)!%+~4(ZW9i<7cKMwN=T9ZH|I{1nyJl@d`6_{TNz<20OLNxG3_bbAnt9*9 zvWGUkejooTNWhAi{LvPYXQA>jKhZ|ApQo|QIrR(Qy|n-mN10k=jbh1(OwWWoa-}Kd z9phZKipzQ|E%hcbDG?eivYd|@#MEUs&$K?v@a*L01ffv`$ z#EU#6HshdSb)L9$g~#X2xWjsr@@PHN`dp2{k6cte>V6q z9;GJ%)&oidkHv_=^lB5xl~R+4(2z0n9r@=v~%xH1Qtk{qB8w(pZy zv;pLLwW48x!k_!l{4k13(g}#Impr3E`O&ydUL~V_?*6Vuw=yVpi!uQ%NRT7PV(N&a5 z6pp;p)`0A2*pzv$I~W;JsrVxD#dVF?zZ|bs%3|XDEz&mMq8EQ&tHyI$8Z!6eKc-<8 z6flJWco$PlItQ4-u-k+*9p#=}g#Vmo`Nc?4{w}5{|0GkEXG%lx0i-Zg3z*XIWeUUg zWu`D}XDmU=e>P@17}uG?z&*eehA`XBL_7Wmk)oY0rf5f9M?1O8aE^9fW(xT2NC%<3 zXSv~d3~4J;V4*(O;PGmvf5RLzQRcaE4?p60=VzGrX36;tpI>|Svqx|~Th7NO z-2X=5rkt6tTK(RYeo zEqbfytm5;EFDd@l;y)CRnmBgi>WSZ&c=aUTq^Bl*bJFi8bx*o!@*R_RPTn_pY-v&H z6Q#YSIa6+#^7xd&W#^XtwQOYhMdjt?)#dBTTgqQ5-%|eb^7qOISB$7AsF+-FW5pd6 zk5+uX;wKeHD*mft@U+XO&73xNdhztN)1RLH?diXp-orp?xFHSW{DO-MrWMR8SODB3 z1)neYcEPI!Z3XQGeFbL~jsf;_3g;CrFMOo%p9^0s>@LhKy0qxVqF~YEMV~GDR?*g? zH;UdadbjBPqQ0W@iVKRbD_&TDfvptPfPw#@?Rxm zCXSytXX4z6Kb_b<@lO+Po3wILWYY7KUYqo*NyjD)ojh)G`Q&>iZ=75^<%?5xOnG-o z?-cjc8B-gketPPQQ{SB0HZ{F0t88>xURg=mC(7MR;oJfZlO;?>1pD*kHmw~G%H|FZaK@!*mPC3Pha zmpoq*p7`a7|32~O6aP4I*rfbPGbi0S>5)m#O#1eu{gcc|nUgP`+&lRbrGe5rOY2MX zr`AlpZ)$kz7p8t`>gK7hO#RW+H>R3XGs|3{J-cj5*^097mAzheP5Hv|#`4wWpDBN~ z{Q2@1$}=m5R$NeVS;aLKw^b~tXsB3TvASYy#fFM)6+0?^T=CnAF33P%#ktdRrcIbO zZQATW3Lik_(`xI(_a z2^*wq2Y!dY;1Tu|dxrdTfgHq`&0J>Ki|ixv(D&>#|B!#n?{QzeBrb~y@s@a7yd&mB zQ!I&Pu_9K*nphV-V)HDie^Y)etvcPq(9Z!BpbS&cS9ew31y{M+9SrMeTULi=)`A$s zAqgqSKo;@%WHh7 zYN)9zHpCX`+9rSOiG5L*4cU@ynY2@O#?IP#8*F83yJRPvq?2|sE0XnFUifP17=qrepf%E_vwK42%`Tf_RW5 zC-sB7!BKD=3<4{Rh4C;Mrox4=9yY@k%}0k4mO8U+S(^GXMtw<8UuIyI*e?+KCd7$p zikN1JDG*alOiRSHMEoX*-x6Qut9*@j`3B$OJ-*F%_#WTqbI&Ejs88XaZmeLkbQQ{V{gk_w-3Ql2F&8V81 zQ+3s#-KMRE^Hp?9L~+VJbdTH<%H%OG<|VwOm-TZ*Q2N?0_;I3`B8n~D)*VWu6}_t0 zbysham+t6oy{q^1f$r-=eWXwHfbuG45+-TVCS!6YZ=_MCV2Wnkl+9$6VO2vX3Dz!+ zbPCf^y}77j8P!~fsveK(o{TD=#wyO>EY@%i7qE^EY+?)BxJdiS5-#HkuHqW5V;47Y z6SuHOd+Ijs;4bdrJ|18nhut6UrsH}-SM;==p(I$)4brq2DO!v4^ddF;k(T2~Nj%b# zjZ|o}8mtBDL6@?1GuR4xl(5^uPOwWUyFYxjC3A|-XvnMNx@GcR7mjJR$D+wjM?H~I sN5-RmOp~G-scDdsMN+Xs3c6H%59upL*NDJ~z=*(zz=*(z!2d|#Uq;v7r~m)} literal 0 HcmV?d00001 diff --git a/EdkShellBinPkg/bin/ia32/Apps/sermode.efi b/EdkShellBinPkg/bin/ia32/Apps/sermode.efi new file mode 100644 index 0000000000000000000000000000000000000000..a2f66b46c74dc271402d12baeaf03dc75829d00a GIT binary patch literal 30912 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 literal 0 HcmV?d00001 diff --git a/EdkShellBinPkg/bin/ia32/Apps/timezone.efi b/EdkShellBinPkg/bin/ia32/Apps/timezone.efi new file mode 100644 index 0000000000000000000000000000000000000000..625b4fc7f2aaa415220ab5b241f6c2ebf320ab00 GIT binary patch literal 33568 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.)&tP8(SmaxST2_<%0jtSPQXAzd|KQOZGD)$4m!&3;Es(!^D~tdu=SJ$A6%lYfbW9rJZG`q)zg}49kfB(1Z}3a z99sMjfbN|hHAEkdRpl{#8uZ-nb<1cQvNtEd!dSuVit*@+wflMVMd)q^L;B8C zNFW=m->mEWhCkIm9D2=Jhph-6ClKuTH%38}7}Ay1HhmVbqw8w(3WNu`W(H7qzU!A8GJ z`4WDMAC*M)4)uO;rH=t0S>Y>S+)S-2R?BCg)34UP*1iXwmBAdF3}0C(%&hj{zGIBX zj046`MlDkTOqsAz%z{_$J##8-6Kf$E9)LA5-d`T;qzPFh9joN~{(I~h_UE=g@FBSB zp}>!UHo?1svmjvspnNumNUk!4#-O{Q;I3nZ_k~^1e7wFESnn!}HAJ5n6tl2mY=!mW zlvq}30Ix-NX@oQtHjK?udwHZh7bEyN=2V9A9PD*Tm_cLUd--0i3`+Dv+q(-^?-wEg(||$um{}aPde#qD}m zQ05ptM}G=>|5C_hM2uvxGpB$}bYQPAj~ z489Uv9NZ0S9(@6D5X0?(pSuBUWnG0H!XDvENHu>z->HXjzTMZ=Hyk#-9N_0w-%{9T zkNRT8+G2{>8B)$vSTuHtF_3R=hO7_(o+e4FrJtpaa+drEY#WQ@C0MUc%O!!E|0+$? zht#>+26)wU1eWyYj#(xwWDEMc*)*mZw0)GfvW>)f&P$oX2B1zH82e}komCt=Rr#VY&eme z>~5umtKo^gSxCY9)(?KzIl?O83rIr0LW6DPYwx=U5YB{mW36wmueex7yj$!G32vVF zuBb~*;B|dC(LW@e#aylcOX4!@18A-Ef*m?ut)`}_)ggI{SPi;E!ErC?QWp?A}JLAqTDPx@Z0i@)hN8;a4{xCU|pPKK5A|-KL)jzx2}VA zeRyd0zHJ?bAH6)*!Dg_z+y^~k4{ULjv1YV|Uuv%XdEf)U>PdpEz=Qhu z7WmGIous=#y~D68;5n?~uSx6SH{J<)eR2Svn_K0s;8WW% zZ@&UvmxjN*iPB2B8@nAQfLE;sr}_n4s=V3|(tSTzoO9Ht)sNJ}kf2V18jH_7yl&~RC}oB`Z{vbluy~N~EhjiVI0I1R!fv_%l)5-Vg4u@A+zp*$KWr|=Jv#VS zO^l5!`=K$kkvq!W;9JX(N5CU62{ydx&>-evrY(o(e=|J)yWw*_C?Ane!pa@5Bq|l) z6|Si?fafh25G?>qiviV2=(`(WRpQX4>AfMdW$2mE5y$A`;QyHfDP{_|({z1?K1C)^a?tb~D;|;o^P%Td^2t8km+H&#Wx^*m z4|8IXZv(8*r+pQmAG8tEVVTVp*NA&z+387N?A2nTB41MSj=qd@+l&p3E73F|}7^b&CU#kFZJPkg^EcniI zwUy?YP@nU#V}|z22v#z@FlmsevarVGLc`6sh)TFjdm7Z9;OPcBNDwN4hjo#b9L9FN@viLw{GppslwPQnUT7gQ&J?sQOIGO*AxM15U=joxxPC@>Q= zI0l%>0v%?95_3R{GeC{GpvMKE$i=|eN>Jqn(B&3TW*%sBFQ_vg^mz!FJO&y)4J!30 z@d{zp3tFuNY9;$dT~Mq5n$@ALB`bAR9oldg_-n_&Q#k`vyb?QCPOE$24ew^B*}bvy zWx%qMW9I~>Ln4?3@5H>o0&tDRf#rdffi-~*fz7aLZVNc)B+Wg{X?)>Ddhs@Rx%UhC z@Sq+MjtM70IUZlUFA>sC1z%NPlCObJ@YR(BtaHf{!AuYnyaX-5N{|wq1SP>p5E6U@ z9l=JB5nKcn!PF9ZbVsEND5y82qfF4zIP8_l4%x+LDY@8Dwg~>7mDo9xqza%ae1i^e zaa~ zMmT>4-%oh3hb2`=gZ`N%e=+bc2L8pszZm!z1OH;+Ukv;oz`*|l^)Yx$ literal 0 HcmV?d00001 diff --git a/EdkShellBinPkg/bin/ia32/Shell_Full.efi b/EdkShellBinPkg/bin/ia32/Shell_Full.efi new file mode 100644 index 0000000000000000000000000000000000000000..b90893717ed010893b8d46dccffb47f22d29c7b5 GIT binary patch literal 1118208 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 z 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�L5RI!S?BIpT1qJ+%;a4^tAzaNp74}(l_E?z;)8tvX zKlY=?6iU41pp@X`)gs{_)SPddBgzpHAzF|J%MXl$^+$6kueh~MU5|&H?~gItHixAc z*)Pv))o$~$M!%I_FFB8wo)X&?AX|OHeEc8Adg34cCw!|Tju&nm>7XSjOiF(2)ISr1WI;SKhXzWWQqP|Xeg)jhk#0wzUQ06^DAKy)uB zcgk)BWnWN+KR12Gmd|GJ)F$@AZ<;re3h%8e^yqAk{MuUn!5zwykyiEl12+y9@3%pA zj?{>~NEA66pBJ0zbD_`-Ek>m_qY`zr6aM6m8Yf@OWX$Csfdpp( zo0*Ny$8A>z|DD!da4^aN8^L;FGN0=7VEx_ZB{Utp8z55{M_D`GN|Cww8p1C6IPT|F z!FssHx%QZs8SBkTzq2ukNhA5Phm1vOlJ%*#nO)0!%b|f#!01kl7_Ep#G{@u-QcCW~`i+%`OD)deNi8eUB*TSv;RpE7xc_M*13Jg})s zqQuLWd4!m_?#m*rv?VXR&HLtm8odwN{N)axY0YOx>$Nq1Y{y@1KIV&2*YD>lQ2MB$ zECUr`jfvqN66@&fohqWs6=B!67iD8|q;QjRPg`)rZ?p?B#Ysh>%nLS2Xuh@wQ=^y* zh-qRBZw%|FPxCi>Ed;h1*jabYHz}m!ZGZA~w4pMU+t34PRerk2HG1JlU4W2U0NBI)53vTdlP9{UjJJlYU!A3 zp!I>IkIpeJpIQx5)hNC|T%s2SSt6Ia^5X~efah8~sGqgVww~36=Fdvb8h@AA>eTi- zdeYypxdt_ZcX1ide$?~!>NZYyt+J> z6c)v4qON{N>mPmONs;Z5JzZgEq=PF5RW7l)O}J|k8O8n758{PBy>jAxoU+60%vJr1 z<$jBt9&2Y+ksK+{kzzX?Tn>BJEyRE#+J#O}C@`=Nwg>H7p!1Rf(Iyb{Ttvc&ilDS9 zY-XMHX+QqqSjYA+oiV`W$hz(YjgU@rUVU}%wj;P)5Mu<%VGoE1Qs*=k$9okemgjWN zo2o?mR1I?_+BR&;ZVw@~Kb|sMUA!I7#!N+{qe8+?YB%K;FhV}ydAyvHf)z8&d3%Fi;UR2SGmPt5H}`~BGYIkW)ePZoG*>eiq?~%~Y6hP#?~WVT zktUPo3+UCbAdJ7Bs?}k6o9-2KzH&4n!>L;dMZcP=k4JJ?PG3S{a36-X`GOdR) z3iGRE)R0+fcJ;>>rGp1-IAf?9)|ER=Yi}{|VT`j}DsJ^*v^C3*TO73~M|9<#v@D{2 zjWm6ZeR3w>p+YCaw3-XSSH2krMPk64j|}_Dx`IWR3(d|uWSV)v6s&ukQY;FGY?1G^ z^mkeH)QCzPxDmITUTaq{=)L~nv>aX7BXUb=A=jSR1ps18_c*;Ct@x2A*~4#tL@_W5 zGi=E0CURRov%B>3(nkzg)WTghrHuBsbn*gqvE5|!tJX2<>v$cGCv4(a`7J3EL&W4j z4DBv$uOx3?*X@o&Aam`A0*4TXZ&U(^r2rL=7kc9C+^#N`#>PbUbam-l z*z&uw*YlddI1G{0(iy=w&2mj-oZT1)S3|#|tb}B5x{qMIZ|+%|y;;R2h#Gl!RNPEC z-3C=|m$i5SmagpWVWsOMC@OuqTJct>^v)@jzJ0$+70oZ#yQ@l(6^Eg0@fF$2dUq&6 z-ak8ve;}b4@P&cwWi&4x2Ua7}*;ODMJZ0M!sBgv3_@cTI|GT<^mws-e_>2eG`^hJ_ zvxT0B-=gQtb~Z#zOW1B+7(1#6nyy{e?JftqR0@`}sY>+F-iu%R5MT!<%cU_-!>n9d zg3GM>HcXID>wMVP=p=2N;d^@zE)D~Ibl2n!cah4F^Uf~4bF%k9mFzB&#&N>o-x5hFfGFQp*u;|)!w z;<>GDr9()}CwJl}DY4){YJzXu>1%F*VO}TQEj9%cTsR;MTA=;Y&>k6qzvf(r74?-@ zUB=&?gNdD>UbVEjUwjj=u9U)=cmhs$+s?_2?83W_7=^IX37}$sW-FUY!>Q~7n&)^t z9lUh1_5rak+MZ$e)z%gF=X&q2?tTy7HQgukt;?J*WV1^He>V{UaRM*mm;LGkMEdjCB#SMICn*p&F-8)A(X}c$GBjL}_ zTMM&o0?^32DFXPU+FZf@6l0-?UwGhEYJnO1C2eN^I7fmL?&Cw8WmA}-+j zs)tl6?5Qrv_3pIGnnoKkV?Bhf+d;1g!;n#%gMTn2kQ|OeYZ!Kto{Plar7z}sHxiaP ztY%|a&Bkbjtu_~et-2hXiTTeH3WzVmmL37YNwF0>xmFkP9BW)0kp1Vg=48%|n zTn!z9Un7v=aP;*ja5!6gJ5BCqU(=67P9kb3ekmG?JB0*8@nWjZUTH1#JkSz+(TZXy z?kwVxihRZu^dDhhThrn3x?P7D)>cxbDfpn}QOCKlxU&SuZf7t}Fv#TSG>TAgd$haE zxk+OYdlAwou^kXK43L`OL~}CGShVpeQ@{kpY)=K-iJ@R)G5G}B9dQ*O+~LqN?!41E z?t^xDT!t288=vg`fpoCoF>8tsABrbZL!zZ=-NzwwuD1=vPNIu;>6}Bnd}MYxpu~bRz;L> z{fvi5*!*OyVKc4OjhPC3e&fs?O5M}kz$&8x_CE}^tzmP@17pj%_j<+dh7m2d5^iiB zwA`_V2k8V|kZ4ucY**@Va|5$L1?&R`+t%=4+5;N`)muomK7`lQ+;ldh=6?E7QLxQ| z;+D{|;=r)bd*9cUj0VRj;+}by^l^Gm`|)fse1i>CMwu47J*OC_l#-+LiHmA?049yA-3g9q+q=h8Efj#vk?9#K=;q=R*ufdF}; zQ6ZN3QWe>|mJFx^QdtF^4gSD9BLdmZiMny}pXvZ&fR@^dRgx68pP}rNU-EA%sA=mX zi0O_?5PD2?=@6>=QLYn(a(x%8K4b;;&5FW*X?0mIrF#2CdyD*!6&9RpZ~fr^sNVjAd)tq=&R%vUdmXDM zRRbf_5#?AUrZRbc{kZbX_j%ygY`5~9KQ#}gh4D%>E>otM&%_jxJ@Xne9lc+siAwA~ zp-hjNeH}F;Ks2kSJy>?9Vi#0kw?uhvb9pKUi18E4o_N!JokzK_-h>#NgY+?9)TaB= zN4aeRrgNx>M@47lApN9@?X+T%c=)%Tjx5Y=CaN?>lXz~+Md;BKp4;>{sih4O_h*&s z2+K9QG}izL((M4xVZygE-kMep-(7#N9K&Yfn=NGT?L1tfvFScWbX4q80sXrH!OQ^J zr~)Y6!f;ilBYdXja;D3b>2sE;&026GS>2G4*M+bD3PD}!iY^%j_jMjiVH44KHHdfk z$}#ZWmwvrfdSBj|DcM)Nq4{O*ZJ&2VfOEqv$qw`&>D7FuaYh4;3D@bK0Ug)x2MH*?>PDrqo7QQ ziiuX&U0=+6ssV9de6x>Ke^O?=dx1+WT(}vN^ri<)B4z77%<%la`=R^C50sN$Y2Ttz z_s_I%U+%@~o^lMSW9#9Xr!0R=o3-5>kscQZE3Q^L`#QbeYOmwjxaxY3t4rgY{#-NC zN2i5RxMm6ZE3PoAiZkYGN|)0=@!U(by;=Zr@VHr}R6C&3-=6V6&*RV`Mk(3VeD&X? zBQ{;Zs7dcwzn!~Dt=ElB42bM!$Iw0RF-MDL|1S8!b|VEP-CHSrjNVi6J5Koh*}xeQ zhF^WLK&{hIoFx=L?BGhDrr<|Gv28kv$pfQ!!#+@)ITght$|zD*Y|S1uwL1#a^?Kpu z>#JzOe)K(FaBrW2|NitnRmcxGJ77d#{L!Y;_XeBM_M`8PaghIixqJTrE30b%e}3u_ zW|%=|6a{NkEELp9QK5l^k+BJxJZEIg5=+atC;CM&185-7fn+>R;Z4nM-h$AwoA<`; z8d6aWUIp`7Az`6WjYRbv&s1YhI^bOA`+BeaJkR+tXN0Z5yyY3jej0|6wHOM@0&JZ^T+@G!y13HjtJrVw$rU1 z1AJ!)zLza~F#f~wH%su{=rWCrzi46jRvrPqnq2s5j~Tu*1>ZGCfp4DR+xfVmCxq{W zeEevLYEBMaHgD;W~Uv**lt{nuveP$9I z!uJfC2ZX|c;~NWD&qRSXJ`XekpyaTgn*^F{M380DXH%hA&vAgJNy&J}0Jz!^ zR6&N{WKBoO>$&{oY&H5-SKo;ESgc0J`i%zs?)ZFs6#aX_@ml;E;5=pq8zDX(H|6_L z@FD*QZ*(4LS@^)3H5y+j(3V+s8GKN%h~?kMN1p(=+}UUsz(=!R*1x;d-aU`zjyI;lS^cXnBFhJk-rhNC z?|ZJQ5&O4E?Y$|lz1;rIC??BG<{tdI{X19fU3rxD9#VVTcINg^q?MuP0kxMHvAtY+ zo~%ZH?&=FWnZJH-SEIB2Mn|OQ`hP1(&-+R!+;657AwB=KTUiU!b1r;S1m7h`f$uTF zx7q59g#3|$x$DcuuNQ=GK`Djj=fc-^%#(|x1%LH|Z<}j+#PRJHd}rjrcS=5d z)rH~PG?v2qEWlm}-!tD=SB?d~w+OzIj{;xO`)FdV)tQ+e$LGVh_^So+x93C(PtAqz z;$w#ILczDpH9aE!Dg@v2rjpLUSC$Xoo(BrTH~%CG-(@lTLj2wB)Y}E+hg|-0k>LBe zYkEZZ#tFXJM}x1vFnoIiUq9}`oGS(Um%n~*v~^`>Iu!S4@#+;{OsgdQD!V`RmUN zHM;Y=HvHlIA4b1hw-lt03F9c-ZV?Yd{C8Mg$1=Yz6@1%V(;-sw;cFIrXXL>*KA(Q8 z3&XeKbPDe?@7EB%XTCEsedOYAn&3P6DDce}d~2=F%={X*e^~sLg819|MhZ{Oh413m zfiI-r=>qMOuGJ8AvjX}2B$PGL_zi;W4`_iTo=;@H{v7eV4$PsQankv?H=e?AzGG_q9vyWo1U4<@g_gVMv7aG z;-V#|gbJLuDNCu#l3t7w@-0gATd?xKcYvg?2DU`cWgD7wiDosGIeElFp2WNxHaU85 z>KXj?QTwBZ-g7Zsnb_<2nXkGz+bYEK@TmHj%LLp)*M3M8`SWR=u=VsdM-_p*IVOb9 zZ?yZ%4!%5n(VA%#UT2{v!}+w{>N=MBZt(4LO^*oQM#1-%Jotw3qq@TIJv5!dhhE58 z4}SM;b>&##n`PsF6!`8Fe0N%%nfX2pzBOMeh`*I@rSP0w_?nIxzS)BB)2`_e@%NzM zd(kOPLw-JNe0%=2Abi^!D13h^2Y(M(UB`mIM#1-c*Yt?+JuLWQdGL+Rr@vW+;hQy+ z!ezPemA?*rA^*Bupk0{nBi*{eAgTWzCppa)2XjR_@vay z**|anLP7kkm_ytSeA}BSyzfvB ze9xGw`Ssw_!OGb^G_iA_ob@|g{O1bZ;{tdUM9ZDWaA-PU=P@lq1aK0(pK$7I@VQq? z(SeLU!Y!!Y4fi^HI&pxjQ4z=nqVaWCPgD93BU6M z^j94`BLY1|K#$D>dKi9-3IlzhnZl1*9K#Uk$4ymS0O%Ze^YGguP+xUQ<`F@iCQui; zOe5pB?Vf`8y;(4br}8r^{#@TZl6ct?^yi8kQBcA4P`9=>apSX zD&hC{RtNgP5hmRN0UdLhM#k@~!a(2GLgBJppvy-B`t|5HDo`7a0%}~Ke${E7Lr_PD ztk>rccYm%Reygvd@VkGLLkjP)x{iw9U_TZUkoUOuM_eD;1!Qpuq&tMF41o;JzyH|* znYW+W8l&*Tzs^}7zHO@P*IOR~_^uXwFFVcmi16JZ_-=HWK%#?hnEVti3}1gMg==!* zt377;<_o@SjsoAkf^Vl&KZo#9Fn4|3dS^lW-7ufR?Z3*wUx(FoEcj~^eA`^pBjWFV z!FNU;eCOuFS6vvs4GSo|??4WG&wR~I@6ZYWH#PxsLS5_U$5hbep2Y#WA6bdy6rAoQqrKE2T z=&Vd{KjXjsKv+$=UN84w&kO4~POoq9Utesp!NBU(85PFyN}uJYXDnADdVP+2Ej`dI zAbt;@Pw=^o&zJZFmdoxh{3U?!1QqUeI&Oa?%Tp*K^3kmCCu2!?xw*`%Gt>nRyOqtOtvuIeE3cbEMQ)cbKL0WBpqlqAT%-H5sD(fW6 zT46?|S^XQMw2Gh_-_ivZ9rn*R#(6^hYk$DzN_si8uvfHz@D=v0N;N&|=O9Rv?!qkY z$mo!&mHrh!y};;=Rr;s=^vvj;sMjBMuLFzNEcj1S@;sLu&b0P`mVMy&3HV3ucfh|( zoJzna4z9*<&Rq*wqiV{n8cg(BB5R*tBWz}%uT_RaeiflT&dGZF6ZbX%4iW;saK4?Q zEZ=ZhFx7GaNw5kmLoY_$rC6yHmRJRr$ZkndtKIvtA!y@N!6K_*f-6!Urk$#^cUl_W zGOF&lFzqy@U6`GAe3&*~X(wl=MZ&ZRN;_g&XTQ!9!nD(s_Ur7l(P7#fl=f(LT8ZDa zV%N2j3`M?CdGE2jazdxuRhh&(CEn~;6xb&Q19gTH7g(ZBCW*_MMPf#Rm$^g>%f!8` z#T{pbe8oucjV>Jn%U17dJiQQ$(gn!zOf~e9Q*LXj`kGK9#{=$lIO2?VqPJpE>Fp?O zz0X=yHUo|rLfGaXS9RN}V(F&)i2-)nFJYHH(Ve9xHoCg(5*;%+m49Q{+(c#hsLR4W zs_K!5>^Pm;_iUxbEUhASm0FOEt8N6AonnT7-lTlz`1#(fe6o%m-pp~Y)65H-HF>z! zcjOj!yDYX=1T745AA~&Kqu!|wD?pamS;iy?6BfIK)MuD)!;3xYQqxO^Cw(ob(RD^~ zerPBhYwPtz4yN=}o9{}t-1_^M~|+=)|<@D z1X=&U>Z*8;7~y}IhPh0k)=6qCS>H`AtCA8|k;_xA4Sufh3}LbwIOw#~skg}M!O9%Z zBv%W^G09b3IsA*i7U)s$Oa1p*Lo-D+-D@?~xkAN>fynam)GwKil)gO{+0gbX)h4eNV<{tNg~&74vj5-s8>zd#ztL-^p&sUM^oNfcmJ0hD9briS!Tv^r#hxuv#M%#HP;BVvz$o!2Sx=&ph z!QbcxinE9+yYFwb%ChJ98{I@EEmXt(jr^3HSph$SQ*&AO^rnhsWfyj*rzTca5Kxb& zbHzxXKfYbh1lFj~eMgo+NDVGuuV`rDjz-c-wibuWTj+lzr?HXzmmK`&zw~`mng7lH zORfgQ*Zyx{!8CoDT)7m)2Wdc|J!+_h0&0UR~zDG`&z=NB3VkGp{c5U;3k|pb-W${!4zxe@|4&wt5PYyL~Gnv(fg{FhuI^IzI!g$nvFx%SOF zX_Kou-+xIth>=`^WN@qB_;CLvSB?2Ez1z<<=2;tOEZ@hG14-hox3v5GJv8RN5A z2~qE#Z!v*COmSjFCVh!Zm%LV~5^%`Q+W9=>lra7pNm`E1$Y!Nyn5C0P7FEP=5`A} zg1>)|L7^lXxLI;^(yGVbRv~WsH!B-~i7dj?vh9NyzKoTqILmoaSZ|D z9xmEPOtsIl*BkR*TkQiR0T=C1mVkt~-_SC!v@TweUqz|BlpnTQD$+mYa=ijqz}K<- zXSds5s_0?`GU}4kVe_#r^iMq`NpN#B@F$U~KfA(k9AC`vczaD7O{_7cc9vMC#I!Jq zT0QiL-@nr2`Zc)og);81=YKqu6Fq&SahB@Umge~?{x^s7-n9p-kc~$_O|&P31>#~9 zfS22}!j6@;dM#%dM4Ju6UKvpY3KgW_xUW!C^c zxy{3sFJ8?6_yqKsiE2)9B}U7|%=^J*+-*w~hgaMcaz4Bh39tiwK5sKg;UzYM_@(X zjt0e(5^lI}UN~p4v&oq8aPN!#VZ3r_K!!2zf^~-SEdnAjQ{TfV&(YgSwghp%jr*BJG)6Cz{Od$~De-p{CkcKsQOO|mOu55b69y(ewPl_k25OAMU2tj5;VZQ(n` zwjq+m{u2dd%YGxI1EsoZL>zq?vUaa2Ac!Y;zbbw`^t3XWahr)3%^*MN}*D^gXilvPoF@6TbXM8mae@5|ZvyBnKEal}qHu1t} zn{0zLuRF5|>oZWabZorn15nj9=1Pn3lt!I}G^CPUWlviCIa`W$_r1ZE&s}S+~Q_r&K5|=DqAn6ArDcl;f`&B~Mtp5ca z@IH=D6&0*S5e!#1O1y`B$=Z1|Nx(aFx)%JVFY&_Voh(wT`Yx%u?OsX(Y}K|6Z+J;} zM|6$hkApJVsBN6%2Q#!tXZ_$%!B3f%ox%^qy)dODe4Z-R><^gzMw(fj?3Wkv@7E>C#1=AaCL3p1bd}5xT=IlqS}pQ6|21bcKluNk$6sQ4&|@EjMYI~yO4Pfv-MB4e z`sq&5NTpGcV$Xj5RO6ebFYEZ&{{y&=b8yA))5xdX$U_o80t}?4XPDWrz|vsw{{F%D z=S9@Jds=`9n|(L_Kj_nit_i#UNCKC*!<+lcs?Xr_wLh0tpU>Z-((qq#_*7aFK8}zc z2wVI$enWiYeoz(gw+#1zRb_J@Zf`4!cMHdlLu&{#zN$prr#E$_<32AGNUAsP^OCsF zOX5ENLu1~HxL{Gi+Eu+F_lXSSKCDTHjQdEChx^InThp( znq>1XRmZs4&0^TNjx7<#`Rz&KI4>E;;aeO>O1{)N;y5)ofs_9->U zc}jQwjJd%53#p5$z3ByjTTPOM?I29byS%p#2kyOO2tn}fSscJNsY?tmfX%D4nID7% zVjuQzigvd|J=hdqEWkc#j*Pj06$`M4x2ZtV?-~C9uy=d^VV73skkI2~$h7~z9}fUK zw~J_ynS}On8s}WV`in3v{R*IcNkI)wXtD^Bid?4%lHQl6`m^2<$8}=w|1ipHbd|gK z+Wvh1LVsEH=lGn>XA_?h=JVe=-zQ%4w@mnZHB9>;f&2;IC*m&l4i`vzh9qW7?u0MG zXDyG$|DAl{5@O=U0pfJpgg?N=wBdw5z=VI`h)wvr`STA%`*jx$pYW#umG_sbVH17` zx^xr1S2*c5AIMzNmCy_6{;ojMPLhHNf3^40ABQ1h6B)8r&DnOURkpr+8P};pgBe!v zNNpbRJ_ym?AFuu(Kus>tvM#p-sAz$tDOo^W=e>70P>OMw)$~Ij2`1EJy9zf0)S1J8 z($dI`+5~X-aWHw&k5Iy0^m6H=C;bE&Iq@u)r}c1?V+WFQ&(N|{;!_0v6!XjVFSta| zm*S@cd50-D$P{${c_+UmXClVqQI+j;g!m7gl@HZhOW~}v+eL04D63w_=VU&2^7%hZ zOIv@Z+2WO0QD0iM?mWY{TXkdSN&Ul0GoKYQzCwMRXO4W(T#tfdYklfTT|z4J@Dl}+ z#*^gJT-Cb0pws&#j%1WxyQ+sIC-c8to;AcoQ6>m85uOvN%ZWowOkyS>)}|N%?5o=L zsU^kb$o%Wy&!0eQum8WSy>QiMFYsre>r!pJPaQqW5v%%l4e)^kS^Dxv4i@~8Usek3 z*4zCW>Qf2c1VOMW8tM!gq4WE7kjxNr&gZ|+~Xd-j6!=^PJ@ z@8y92-MeSqz=I{d|9U^^CcpGk<|mko|81NwBmBQuAnA)Fc@ccivQW;I3;Scd)Zf z4H?wwPEPOmG1hj~wmr~SUHm2$`7cL3$X3Mf{3k;Zu>H~mx4*yv+^$Z$GOOZ#cjOLe zsAvD8+admfsBlRz7+6_E+`YUTRQWYol^C5%Q4loxda(@lZv2yAo2nqDgs-3pR-d~zXSbhUqSe}iP$a+ z?kOTPGU2v~i#)nzPdky!k$D;Emx|(BHBOJ4H(odm>a6-b?{oN3^;2E-n!cZ>a@f<} z{31f>zxqXl(&9{!n<%oY=|#kcrWe^yu0J5owG*48tZBsUNK~*OtAcJjGS!qK0(2+@ zqMLESg%jT8olS~b3`6_07+T8{glqhcF|@nC&L3KP34QI9c-cSE#jlvhEfIKW<>mKg zM*clvD?gwTpe#-|*sOWl&xEY#T^wfOf!Pi6zvU+jJ0}Op=~XEN(IH4V<`uh_|A2j} znoFE3kc~z(rKh^qZ8{upQy|z=o;=81seHcpYFYK^{QWx@v&W0dtG~+UBYd9c^LJLm zdKmMWNF7Q)9bDNKv~=!7lwp1fSArNjnmw+eq~qLxH&ytl6C38%EUSsvX%K(qh|YC* zdSd1Z6kAv#qm^l>)ie2;mG9fx`LH(`+|o|!uJSX`wdY(A`j3NevD%%P-R>ocnQFDD zeS*QKXB3EcDPOJ2hXT=n6X*qi3-E^szwVAtin{Ox#DJ z!(k-JoEh}Bp4p)@E7h{bMYoL%EFA@)?$RJrq^8E%wJFLoxmMu2%iAQrd7pcqv3-AI z9ULUxq+?pd!q&}}U7Fh$Ot!F25J*3EmkSCWhMyO3Ufsp%r}wl~3=cEqVmo4JZxKkTj)Rm3%zaiEdw?oJ3PTCH zt7!;U-RHlGj%yg(aiV@V*Ki3*;xL!KlA}0SuIrF=6;;|_J|}j~;RX|3^XPgl6}NY) z?LatFY8m1b$sbovJJiwQ^qAa^yNaDUn4Vj`yJnvk(x}OkHTnALULnFi_>50g2g}Ug zG3dNgAODF=Y!l8Ykn}T>d^xiH{obX|ixcPQjlV^PtZl;j8*H@MyIh#JcX>4;zQi)^ zRJvp1^99buW={&f(;s2CaJTmWGNJIKn~?^VjE%P|Q+1f>?JV(-pqUC|Pd0eb-tTCv zUwP4;qiP4B^8*HXp0UA-TqN!)Uz0zt1C^NJFJiO6kyq8alUYpS_X>cYnr9$LGwDP~ z8%&w5qS)&%ko0>%@^uwe>-O-&d+j&s*5KMzirD9b@1494BtBcJbYN#o)c_|5ELEJs zvQ+7==INK1Ows!Wjr_!UZ?Zm2|Ay!={ig+*M5yy6* zIzH}0ynbM*z22fciJAHycGBl6q`u8cj(TUl%hvR)vpVIl@#pdc|B$w7y~c;jn!!Uu zXoY($XKem;BR4IF0DEP!ocly!v!SofGMKx%cjCHHdaLrdeQZqZWp*dOYjCSp$_rzzYraN3sDJf_J zL`~CC*+~JkCoDfJJ0bKsFsQ$8#VgY9EC|MNtIqK;IxUHuflmkbaRsNfaRX#-(tx>H z!i6ruAvp_oCxGO6g5?uV*9($A=)*H3s9=V!vdx2s14@isgCNlc&zG%+;ItR&$!jL6 zW<~|g_>I(a^B6k!V%@{zm9$^Xw{GKU4DmKjU7cg4BI(J2Q^cuyd%piR<8ODGUZ3J# zXRq~Gk<7R8|CkXa^YV3!G`vrr793;4&ti)z;v2+3i^M>$Yf}Xk_G5(GnH=}mVq9*5 zbDq7$<}&KpQo~oWGQxLf0W-ZJ+@lXWhIcjTNR$J*eGf_Hgm3fz~hjb@fSbrUH z%dNMvr_ws=n=gGupxa{0mM@D$Zu#=dW>tv&TTs8MiFp^fp9S(KdL!5PWybhrumSWQb)6S3 z+6J5@-%qV0Wn0uhVy3=B@Y*siNI4e)3@jxW|DfxnHj5qHR#kHi*NM+g|6EI+_1>8~ znnAPr$jt&<)WPu5KqtD{xABizKL6-<#GzRtvqkTxsCDd+%B((_7VSdnv(LI|0h?Kq zO7pFY>7=oVuj6Vu@5y)Ci1~AARc-t}6}sOQ(z*6_iol*O+KX*bauyabd$`%Mv*{^x zW9Y;iViT6nSTdRm!nhNzp?Tc$3+P8_8^BAU_Krv=ckDG`aM#VfZONu58X6}onW(!y z`TbZ!Y#iqv-D+>D4HJQW22ERRnRfovl6{o^Mtw!{Cop1K1AS(eyN4cWfU4z`Is^IOe0wMQ0isxMU z^x^+iX%v^P`BUQ8szhye7oDT1-^DG5pp<_w!)>WSt#AXD*YKp)_(}mV$5i6dE=z?5 zY2B;0xBemv^Tu&yfERaf?Fz~rb1lc~a@=ICvD}h`H*Sm1aobK2$92nKO?-#iIx(v) zIIb>>{X00W&7ZnletVk6z~{HwQ;LX{-pWJ{#f{QrSd;RYab3(Hor}9!wC+luzzk+> zjr&rMYF=_DX(LxjLB=iBoh?1O4AZ-<#jn&YU%s)z=ae1%*{W6cCZC90eeiKqK|i#q zs{5VOA7TQ#`N32sDqJk;J^xfTjoSr|s>~*UpL?v$dsMnZF?JpBd3HY3`%kW32^}Nx z`G5t9-&e#R6u<9=@Vtt7)@blE&lE-lH-7(@iQJ*`gfm z?D!5Ds&8Vg^+E-r-jblavcxzqn3j^YbACv}}tqCuZt9Y<|vB z__;C{> zQ-wQz=4LQcU`^^pIB2qED^+oC&?)iAN67HS>W$6LyUd#Ah-YeN+g&V-i4{5*It#GS{n!RNb1oDd z^Kj!Z3LyPL__gDqp;mV;M0YtRVrO!wtL-jmo*!(vbu2Jpf%*%3ebBIQRy-=Ow(T`6 zfW4@9%NpU#@4{~)0^lw?7^+Uro|n+U(7Mj14at^uqgyt#Ul5P0{4&3M+tya^t*(5s z>8_|Z#u1q9B2u5rsw+5Tx_c!;b7#|F3q% zXR_(R)a?|sVe?P*>TShk+oLfl>A<|&fS@b8XVud!G#(J_83ynHJJ~IZ52((eJqC>G zyo5TLJY0${?6G|iqFmYir5&dvYc(&yMz6a_xHd0Z2BccVpLx4s8_NK@r1&g@CF;Xc^HE?~>R@rZv+4Nx?N4*%P3QCWza+L_C0R~PeEyBDQ>UGpy~BmD{=iSBUw0^Ne@r5$Dsp+nBaHNHk5p6Nhz z2z{5V7yM?<$uz@gj(5Kr`nb8wfoPoXF6&ez9raV%_x{At?9YEA zrj1c=Lz9n(O^H>TI5D@rm%4HW=Pw+hT-O&^u}uu}Mq^Yf_5)lvuSQb4xu1uPXjBO^l z_1m&tWl8e!aeBbjelgh}oaBmmlgEIpwv9}^O;PV-6I3tE>_Kbt%d@N*o8CxF52hAt z+Wmu-2ZW)lTK{##HeZ3zCuDV)niN0|U}cA$g$==)TMSbU?Z4ALf{l{*FHiZnI1u&z zbeTODl4kwWCHbZB5Al=@HrLV31v!&4zY+s)?HJ>Jc9qRVnohG7>a%m4zVwqOT34Yy zzUOA2LVD952`j$CDsE$T=~lTYXJuS!9sEihek=N1Zc)BNhjA_JGRtN!?3~lKBiV9? zReuM0-RV&Jd&#Cd7Ve&-tGK&bxR7~L*qSye?brJ)O8*x+=5dttpN?#&H}x&$o^(l$ z>K{Eq+xLunf#AckWCu@|ukgEYuajrz*w6IIMw2JI7Tvt~B-EH#b+1N2>+ca)(51bP zw62!>ApCn<<2Bl@j-RE9LgII2c4e25QmV^NPw#{3?z3f2BxhviM*5!Y{I7ynnCS)$ zo9r-Bvwg_-B)J<~yfxlW%hIHv6&Z?7wA;vi`N192_7Amkt9qHi|JLlfzpP4I_Q)Iv z^PtLj#mDGE^OHVB?TLE5jn-IBH6yE{&hci9lDzOxV%0-M9VZzspImM=7}cgPOg24a zd#Kk_L>aMv&K1iSQf+@U-xoo>JP~x3pnvPT)gB0ST-@Kh?1P!0SLkdz(A9JRx_0(B zh@hjb9kM@VjCIfAzdAcXDMyDj3l8JP`AqcdkpW&`rwV z%a+gpbMw*c#<~GbE1cHwRwr>u{V9Vvt@g- z?cvdF+mT#1s8c(3yG{v%Yh3wc%VRNb{;aIJUNK(i>M9QEdZ@EyYqIU3(QRAXPf0dC zmTYduE+QG7mw2wosfg0JV(T@(c#Y18pHc7C%dBEC1vp3``KcQw`8_4^Gh6b5PLQ@3 z{)6pSFy1Y&%N^K`78Kb8;Q-9+K|f4+#NeabjycS+XfyPm_Uk^Ry1%~5P~z(LEz@i> zflptb#&vg7xBdib3v{vR2oqR`a5`XYD3>~;{TyCNiQKXuC1Z5CnsQ87QE|$54>ODqWPjt2&@-^4^BmxhhV91Jd zUVlTS!Shxfa=tLmsnQZFfQNN|f70&0-Jj^jKTVciGiC@3?v&q;oKf0XBlF7t!cq(; z#%?1$;2MgJbF^nS&!77?1KjBFJQ1hmP)Hm|es`k@@HRou@S!&HydMPmJc^|w7O(g? znE#EbT;UZvl5IO$y}HM3Ad*cxqF(znd)DC+(tOs;9zRFTO9r{jr2AL@>@xb>d4lR> z5n3J|KfA<0cdWD4-#QpUbhwm2%N=Mx?0g(uhbR5VR@j4A(O~!r)ezEGC;@(Sse``q zVSdKE|8hUWjDD5IZ)^M_S2YX2CFgkPbBa{-xkI;|5C4R&d z(4MRvpsg@|#CL5Fs)aZ22LVyOPW*_e`Bhl_h<2;xDDfjQ?f&25M|i-mv(u|CF_g#q z86NMSTWxTYwMr#^g#Kj3kC-Q>QQ5Dwe|-E1*D>NpeAJv;$~N1Jqr{I8*@S1`p8-6t z%DO=O2qne5dYhZ9h{TUD@^JAZrZE6M0e!~COOxRoiy!f^w`)s_I3AiCL_<&Wp;j3l zWTH#>rU?_}jp;q`B_r!DsUw4^6M^xzWa00?4B?35pN;>bv`B@{%$VoNB_kaSQeR=wF8B5g5(45n7pP*j?zdL)x|JMf^(AeF zEljo%T%u++FB;0XQvtyx&PJy~g-*OinBDAG9M$q}Q7ex3KBvm zeY?v4m8P;{OJvRei`@K2#Sm{6cPpk@@U}&RnV6~XP}}G$JK+f`FDRqlr^51`mFiCz zPvRYy8ewlyw!}<*7pN!TSk#C8(17^WCUSZUF0p|P-rcKr&F)=%P}3#};laE8j^(o} zgHMH`-oXof{-%0k@u<4^2B%utq8zTM`lAf!e}nu=#Qxv?%x{4FoW~)2-A67)z8)z} zD7N?#MLZ;HRle2xnPEYsUKuarjklL|1;8nKfJsf!Yr>)(S7NVZwe0Pfm8tvUWaUb- zHdOB5yW`Et+BN!B+pS-xlI?CDsN)&E-Dws`3$)hO8q+X)n=D(R0pFI0)55_lTcUx` zmS{jnt!Dm%QF~wqG(_A81=5on-3X>Z$x34$snVGD#(IbHT4A(xb02_7&yuXQr^X4< z__bojet|N%?Dd+uhQm{3!EEwk?MLGq$risiC$D2Ei5Et-dfTl`b^7f1{mS+mPk;U}mF4DaP7a9GBWGDJ`%o!V^AD-`%w8J>@E&knqV@qVK_a*l;EbZIN zO=Q;(WfTQ9v4BH2MuslFMU+&FZ;`AO6bSS(Dkf3{vQ956tqW`+Z8w1}4q0Febk#Q) ztnmAO0$X6i9u0mIMYbP-?2sSWqW5TlEj+UVc=2MxmIb!JK-^CFe-*w%6{5fv2WlkQ zwj5B$JoeN4 zajbzE^5fRw5J^Ac^;cWl=FUCj+_`0Cm|Dz|8Q-MNT$tOL@yue!XP78gT&`-Zf4>4~ zoWJG_&s}L;iNFoxGP%D=Zf&fH+R*+{?}C?y_4PBPB`dA7ikvXh5de17GXo67yk^G& zs#Rk^VQ;?)vjMF56N3Lyr`BgoXR^NE4)?9KYO#9rKJ79F19h4>Q~>QFmuB0) zz(*v0VR`lY`CP*1<9z;p+g_vBsR6|CUP0=a8W~owKigq%9ZCpui<^F-o44k$XYP4& z*faM$IqaF|o*ecpNe+9Kbdz8D!_X7UqJMDj93~Y8nK9c~AjyKxe;$u`3Islq-0X<$ z#b3;lTrL4GNVOmzzTdc4S%~d=i^0n3J3ho{yyg>hvNY)Aq4cTYP{t=H$#ZICKUi6C zsJYG*7_h;2JErTRXVk?fs>tsgx!IQW>lav?02ZSN-gu0(4W{p^ci4EGbU)dydKU$A z_!7m!N5!LRKjT-clfu@p+9QZWssGV_K}It-DdWWf$W94%vH?=(O1N$Lw0le;mOkH&E>;z*Ts58N*oZm(!>wx8>S)*#D902B63c@`ifG*f z!OJ$w=nh+bC0e6i=_n@0*Y0JeA8-GGzIIQ%O#q{e>M{2!=WF-hldKnXKI*;My6hjR zKBV^ZeeL#`&+VSkE&FnO?G_8yUxymAD7enfac|11{)zV+3gv63SnF`xZTUr{+IWj! zL^|HPGess)B-_{S=WrnJ?iX`rfb+HMGsB)T=l|#`fang8KOku1&L}#cGVUx56Alb( z#L`-x5{I7VI5dBJU%PYSkEx3%yP0TIbbD4Sf4b2p?exv&Xg5t1=*9gUa+-T8%<(S6 z%RE0#Xx|#9HKg7EUpFtiFS?hO`J3|s%v!zGu51Axxygc<&;CoxtKZJw|0Dm41ar^U z&mVxFc#qKV!@v0O*sOB?C0{3%5j|8ONo&P-i}^yezS290;s>R4;9H`_d~wdW$ihA2 zShBnc9U)`#=yV&CZ}BJK%HHR%%!WgLAT?<80zVLYrgrBC@<|Zur#qSCK5Dv?&qw%d z;`8_8N)oWG7ZLdod9&Z^Lp6YKFh;_G`gpR58s+p&M@fU7l|_IWNJmyamYAt`MIB?~ z^-D7IiL#@;)8A)EgA@5i&aS=qd}XX>64=Dcl36xtIF9q$a+9q272f;)q}l|Y$u0u# z1Hll)yiZIvViq4JVQ$u{@p;EM89jf|z&$Zmtq@{^Ma##=7Ymq|UNT@PS=&&-CIO=LWq{ zV1lbj%XB2ZUCo|4OF3Zh&V0>3AUTJezI^H(j{qb27Ig#Xi#DueSEDwp<*Dbva=crW zJ>=Axq?!pfB645Udt{Qqp#JRDcoch&=Vxo_BR*Fq+c(JO!k@LhiqI7I9>!VUHEBa7 z@jmLk&lLd2w}vv9#Y3C`{}qQ%Sr6Ii zf#xIJKPGyo>}vXLQGCKunpgmd8cln$auAF0QlFJLG|5|AAgP@sZ-a%5@Yb&K3|AU= z9m;2D;`6S{P`1)$k(Nah&1$yX6u0>_p*v~}XV2vVcaylyPEz~yMQLF58*V#0r>2wo2ncu>U&$ZwMC-@-{)5kGgE!3dQYoYiDGbIo$721Sq zJ{P_O&;B&{DFRGoKtcmvr&t9sVQcQ_&Cf!Mn*J=ymiw75-ktayXCV|BfC^@0RZ#Dq8S)m&2jpNf0H-JW6W(km(ob8C zjq(1fZFg2R+FJAKY)zOygVEm>r!V!Niqhu=@4$3%`i(Xte>~B3QS!@9_e^uYhL@zG zEIbb1RqH+vyuq4!392&uo`tm^I*O)*gf24wiNU#;aYKr*-i(3$o8-ps9E85lZ%snR z)xoou5(AXR!H8mVI8HW!>I}>`Wr2BGrr;$Mj2E>7$?qV}VdK|#R%ZMT1Rt1aQGwA6O{<3%2`>^jxc<*%fUXzz! zglQ4uH{Xq4Gk-Kz=?T{PbNnhbMyCf=re~%;F3Et9lfH;jwf+aFnythuXJ$q^&dw}{}MEJFQ4!7$>x?>Of-DV zPDdWdCakgX8wBSRV#4TmT9b+u#Zt*|j4pzFgeD~}!#?#-D?P{Egr*?J( zb?QeK9YNm`-zfdujyDQ5SQyhx{9%1Pr3N3LX0Nv>PhzINhiUpke!p4C_0@@yLdp4yiaeRGzIZJ z_NMaZdgBztXTt~r1+nDKECq3vvuSqZ;lIV%^o_W+F^gOW<2@k8oJ}Ls1v7eI?Rpc_ zov-Q03T5wFm^eg#Gvg9$(gUB*A6xgG`)I%1M>)bKI;;sFav$x7mFKyS_J=_Z5NWd9 zM?d9PHBhs>QNm8VPXqasoi%Vg%})3RmxEPL+EA_(!e>=2)!@-MsLWrs%w>2qUgigE zb0EpTR2j#vIxPcIEMC+>nGd@L(!YpD^wXVp5Jbapb4ytfhOFb1aJgT1Wqg``PIW)C zX}v0btx`@4GcMN8(e9_K5QX|wJAv4sq&}xinFzxD;?bSFA(|8_r;y6fMM^y{fY$FTd6cEgcOA{Wt=w%5qnlH)W`h?Cpghyfs-H4jVt#0Yp38rx|xS>78<~<|)TI-3Sxwq+rMl zK$dqH;liE82-7UNF|theBUSMIy7wa~TmJn>Dpcrxq%kl;DfPVtsx@;z(oOud`;p>2 z$cH7_RznA?>Fgo-J39ih`;qQ21?)IjnZ*T`Ij|f>2Njs+PU2nb#9G>yZ} z7^H(k|6D^Rm{x)Nk^Gb_Y}$SmWD??u@*~}6uLp^kZ# zjLm6H&Ynf@c$~rGG`UABtAC%-8p}G)02}ABO$fVh_Zhv{a%A5);^-qZ92(Hl$bh&% z{qE18{#dW;U9Ts(%Im_)?LMPotNd@i&*+7dM6hq?@*9d>YXYV=jzufqtZ;1YXP6+_npc8i7bQY zYYr7j$xe-GAU1{&cr3^(LAhL z_bI)yTF0$De3&2YOI_pRX38kI{exkCP0{vi!o2^hpKlNHzNTN(!@NWKd9I%qSctY| za9~PGC#*w2a74MnPB0_}yBsgWmjqUl4SC~~v)ANiUW|xA6#MqLORw44Q!d?^RehqX z=(MVDKJA{WOP}t9~-! zI<6l%P*ve9h0c=+-;=4eN`~27S{AC_+UyXYqdkjf> z?bag4rbu-}=BN!)H97D|A1KvK7}O50rv!9N#>0J3!{>ctthMKBf2-C#WgXXa>jG9+Byxs${fXH8J#5@?yjTtQ**X?gy7ORU^rPH?+1V6HKSAlq+Le@9 zwQl^oboEKU38%Vq!UTy{CrG%XAxO$ZsbM7G%G(g$7z`m;#Fpel!&?>)T!9*(IUQnB*C6=qPbZ1Xw^b@5m15EYQ5)B|)I`3KQ z3mvudhpKhYsrohoF`$ru4#9@%%$e_k*W6pUiAcD*gpH1&BLnk@eel!=6KJgup7mky z_NM*~8t?v{Ddzj&hPn7VaG7{y?T^+NID;ET@xtz)aR3FBV{w;4%7N{06)NzmE`c4; z&H&?>x=>v%M2|>E8g%mOQat`Pm&fAwBH!6mA7|Qj$1olJX6KJ@RX*{6KGT2aTwf>t z0=@hB&3JycwoQY&wr4{V~K5HawO)gYoMLxv)$e}|vczeh>fVlr8y@gDt9Pd(G~7owL( zV#gVMJ)(Ok2COg$-9A$O0`wA}aEsr{r>xYt;r+?rFR@d$#44b1i&=qO^30`A=)c^j zf8bjX6dX4aeB>YH=RZNh2qSKYN8-uqXM0f3o{1uokhC@2x$WCb*sAOru+5fzIK12^ zXXDk+*wl$R*d^r?wRb?G$Fi+?B2uwN?l@B8-9hs)t1psKtpvI)=Af>&gmLt95j&kI zi^iW)DGla$2Sxhn`2L`xh^xpjpEEz{_ZS}^qkVjgV)9UB>;(Tk19Bj!r`weO!|)N0 zeA36jmn}miTOmz*@kv4Y>VoNQ+QU9^&AE}$#9AE3vCyk%3j-KlJ=0i!`V7hZ>a;0* z=F-o0Wf9@+w=4jqIm8~Y-#vp04tJx)-=+2T$mtP|^4S-nY*D^Q0Nv||+AMjsY8hY;(S6f<%B!dF zxscB^K5yeQhfgn`AwDMp#Myj|lHC{MgFSkP|J!5dY-k%;vx==;gzu8}v(k;m#Kt*P zL1~W#4gcpE!eliewjsb`{ z^lF6`1clyWg+`ultdQ(sBnW6L;{<;b|FmsLJX+G~efD_u07(LA#w3HpPA&?Qgj&l~ zL_k=?)&&*nFHX=e`M|~EE7iQH@pVB3pYSWlk~RzF zzaz*$dxZP}f3fxR5iXlE;mq7k+(eoM;N0W()b-^on1gpwUwSGJ_v>LY58L%{CJ&G4 zfz@?zpB|L?fF58?gNJx9v`MRsUdYpL(d{?hsIJ@M@o^eh!DlU>+xdKs&wYG?vGnl~ zFIwdf`^T;9Fn&=Mq+eAqJ<&U1QH7!tc^|h?ikS3To?_jFw*u0n;D#zBGsHqMgQ{(j z#Ph2YhgVDIz^}&QnaW2J7ADos_tx4c?M%k8ION7M&;h|Azns!Qjq*T2D0 z8mHCj;Shu>x>F0#F@M4hY#$vM^SLa&m7wG$H&nVO(BI#Dd41V$w<=em&LpX(T&)&v7LrlJ1wHW5QbFe>^6Q; zV(pD2*lO=E;`Yll>-6X(v%u08N^{e@-@3qtFGu?F_tUJu?1Y~W_63><5+%HE27nUk zyiY?cyN#-KU*idQcWM7PxNBB1cL0zdcTU83Z5xmfcY0ubaKr3UCoS2Lfc0JevYPd_ z?rLYu$OJMwMj)@>H7!meRw5=az$P^GIzzLle;*3{?W59|_pk$9>sZbhIexAEW0!x( zv)Oi!(YOt;?H*Thnm8yE6JvnE#siI=_@KXK#eTWX#f#C1721MwWLdpiNYmau1j5>v zyaQRg4gUb~wagBKSBN+vo~81`ip`=Qh{xJ)O=nZmt%x`|-un+~Hy#@H()G_!vo^3{ z6C;m#OM;)U@4<$)fn^r4u_%28%@9O)4vLPo#9|1e69x5K^Zjf23?>MZN^YT+u*XfnV+^XC2de? zrc~jFg6wy;;KtRC7$-f;?Gbj2G%a}a+mCR(H+?>t87oVWLYgfyun*imb_2uUpLQAn zQ{O;(ZywAJUMWPx8ZnlF)3o{|GsQ^8Ch;oq`24XB`9UCqCRV`+8CI+h?hlm@M$j`f zvrr1RR5Y|yF9nAc^jd~d)zFDi7)vJLM!oNua;U->^-pd1H48(i{qc!<_*BRi05n_G zC(0U&4oC$x&95S>SU5mg<3qa@wzC6I)rL;uthP@D8g`kq$(qpcbh}nH6cRR*$4-7U zeX=nCMVIE4c~%alcjTOB%f3hq0S5CQE|_7Kz)Slg-r#Vko-Smi8owgF>X8T|Ni-9l zXc`sk*oH?5GlI++Np$1a4)>`@?1Yh5r1xa!n*3-^ZGpVtS4eDP28aNadDWgiyxNeW z(mSn?ojyFGfdeAb_Sv#Oj3mPTRj`|ep7h6}lKHE+rBjFchZUP7OT4!hc0$_`WUfwo zV_mEuKqzrsb~8t_`sB(x?AH0@!A0X`jqIJBP;iAp=vXp#r0@v{J-wKpi#3>sqO%)A$=qm><>b0%# z<>_b1mNilig_KY9qWok1{e){wi=gJl`-7iM;Qk^Vo^j!mbc}NtaaMqx2a&+9f7PGm zeXIw&i|8j;WcQMxNR}|YHvf9rK{d4XuUdvjA)-)n{#x|K==%5pp~)j!Grj7OIkQWE zx<-Q5N@5VPO!OtoZfEq;KeJzCDZ`bF_dLy;TLPZO+UOv=sp8I>wHS4^F@O7Zmu(a% zshbTRUpnjsDwxnfL(AYQoDmGBtE_R*BrqI6WwY^QVf+y(#F5Ep%Smtg3>^`30x6;r ze@TO2`qr16bGu{Xz3I(>5%ab?q_`%mz+~NJ?G%xM3!`4DumLpuS6q#fhxewHHu~bm zD}X9V4AfD+C1Ru)N%y$7&?jcG8r#H?de!fbKI#65bEaoZDsgy)P9$7a*LE-@epSJ0 z(MBMql7%)y{1m3f0M35vJ_E9F>l{c7+_cm3r59=(T! z6G?j<@a6-RT4-1sye?d40tR6CW2e*ig)e+TJ0Ij|*gGB8EFA%h{(d2BNA&J6Ob`0u z64wJ{e`271>&Sp{QTV`<;On#nq5tQ;LQFHS~-p9*(@}^$XpbWDC$WI zX=6ni{MT#}p=wLLgj<+6vVYh{O-ddbG1Rqm+;_$g0Q4~FYfLS$%!*>od9ibx< z^|&m}87w`)s2)$jZ-@Z~D^mK$0Sdhqmob&JilNmbmvy`u%c4J^DYnCUq}fV*XbVUqX!UG{v1nSPu43JS;LLaNA?-NV7*{i_d$h; z!=)W32@Slr5JNas!}eh{q%wc6@2K&?tFU{CB=YpK5^|ZN7NQPrb{i^!l)i+zi|dCv zY6U{#$aU?4;Q<(Js!i;;sTa15Z#K?e3vpgs*xB+N0VkegF!uW*y;cd|Lt0w-rERdP zU2`fu&CPNe|sWQqvw!*>}Ic}t@ z{ps(Jx1niYN7;ql>G>9=QIcDRz8WADp8_0opT<%e$Z0ByL3t2d4X~}=#NbVLL!SwjfjlX}Pf%BilDs{MdWVIiW;c6Zp}02FsUt!@t>-XQLr0kNY8V9PxCFs^bznCWv{j z*>1feOOm9%SS}PS?b02%t%I1>HVK5UFMl%g5HgHaO?Jww=}py3PqUpLlv6g>EwKoB z2+S@7p&){%uf)Y1p3XK&gv&^bv5hB%+6ELZ=A!O~ror*uuk81i4D0_ie@-JcFbimx zjef1^3nUa!37a4-fr-NsA3`?StHjYQkJ0|@B#POB`lUpKB9}Z+ZMD9V6hA#r!(tlui8>_wvGW9Dfd1X9r`s$MO zFR*o}?%;@kSHOAWO5k)E7v73+<1)^sjGy5O%4{*H?}6XZPS7j*)Bv2fEfyP8TuIIJ z{Z{)Gi)Jvf!80=1L>5omE+b{YqxXz%+t==}a0LYyv4{0De(&Rc#vUS;r9KUM7tIXy z9ls6|pWymUqK=JjdCITFoI=nx`HGQ_Afsx*9}vwmToidZc#rxIT~iN+PH6Z}YC$~g zAsRG>he*oHPg=shs|Pt_sRMC~2Dya{Oz=Z?yaMh{hnwvWq_h2jbhh6~XAS}9x-7F- zo&nb*%N47~*&FZDFIdCXU2_U^gNP zQ6P}@hw~Hd^dVv{=P71kF@G1CULd*?neK7AHm9Wv$rP$)T{c>WOnZDX?J+X#5t;U6 z$W;3Dk|i^!&Cz7XTd0Opw35V;6$*dHb8|`J@U^TaR8gc>JCw&DOg!6{^g@Sf$dYMyOw>UTlVKtVvzAIK}HX0BA`Um zzM-<4A0$52*|rCV?$J$qaw##$nEr_0oN95Nsm3RN7QB}Q7HVZos+jyI;R#1j0C54< z?Lni&HVj}7APr&7f%A-A~Lx8v(Ssa%mi=!K*Ug=qTj$LH@d_g;j?%zCK9H zA$&VqAM_LF*X9?T-Zm(G5Q?T8eUR=83bwe+DbqGftIMGUQ(Ur5vIAkS;++dS0bJ@W zRMw>Ux@Z)Z8UbHW$w;oD{HOjU*X9O$vW!i=-Juz?{$_PKh z^|oL5zRLt^Bs7<7bvhB(QrMoIZ_^@^AA#wAaCUZjWp$^qtkm^yc4Qf6cJyKZyMf8g zL>_^u4L*GkLe=OHrj{jsAQ|bZiM4vK;CadL=tXl`sd5f<&b4$hM#~yvk)>=Ol&C68 z5ZRiMIS}WFm&@sov`(1(sMfKhHD=#oYy2jP)#*G7w%p>k)IvyA=)T%kefqMUzI3+i z=xW>A>YeINv7LZtk6!m2)HKt3nRHL8d@~uJtxNVSYX%V+SmCk$2&juOgQDF3UtP!chIVxd%431 zuR3ToJpHlxfIczwATgaA(s6$g0DIB+A#5hS4O7%2Sg<3dRnjT4Z`J-A>%h^5F~oUu ziZF%a4<%u64@?&_n(TSm;YPHTlyblW3Eog_l3k_k>bq|3sy@^}YdYSkLf*O73F)1% z1o-#g`_!Wa4r|wbGZ2=VBucHaUiDPzP&B(jZB^cu*7vk7U6Lcpq8!U5=LA8-Jj11w zX2JbrL_z+h>x)P!Q22-+1fx4>;{nGABkKkFjw@U}VX4fBy7HXLxbYAs1dXWNTVs3V zYThNoiDctBKcvU++ugwxEIoF{T+IZs#l9NTFFR=`V4osvnozOFd503tJK6HkD^Dk$ zKc0BXsPINVsi4744{>pF;)yEroPP*^tHh7S*abq$l6dk21m7UfDENM26%l=zGfaf- zGWlVyw~gy;+n#KiKs;TxghTCIkf0IJL6bCI_~uMtmf9TotACstpfN;91|OOXqHm`% zvf<$FQ|5U<+E&K!fl!AF*SJ7I@9;l&PDAq)xy{zz@Ezha+D;5f;L6b&(z5h>@UXpE z2|sFQ`(^h7OC!#;ADP&Q6IlanEE^{dX#p@c`7BWmU#_r9G%_(ewM{n9QBQ|jXOK&~ z55YsgB)v>Fa@vKBW9+w%OHs&PcFxY}i9>K*; z!4ii@bxc+}R5Ev5Lv!_#)2&r@Bh9Z7bG3cUA{6&5jQ`=(cMctz;R`!C=`-By#F`<} zId`1>oWQ2jeooL&8s(nvSj`ei@Z8t!y5;~4$Gd8qG%nJ}8tY~t2*p{Z-VuEcrnhe$uiV&@)W@)uA+RiofMA8RT9)X+c{R4BWbCBU# z%8HH7tZ@Rf5CM3cU*hMy&FWoqnXDMGL%`nZZin-z4S;797fC-yBi&86j1gfIcQhRu{IJJleLk;dG?&PZyeazJ9# zD#Z3DBOm?|Cn{}wxTkmzwA86N-|C%{-4!9yok8v4oaWXa+5C1BiZLrorKrr_q49L% zD7|j7u_D=wHP0dNR%~8@*iRg4MtnE$AAbEpVS#8+AYldA1+nD82{`&ka)eunA@Nhl zO3ofcql&U;;qKYwPDS}*o=Yi9P!B?Iezc+D^Lv|M5UWZVJay0*gur99372L#R zHF6BQ!6fcZM%lJMmaZ$@dTj8b?#{Mu?tjqL3EXqZ0*m$C&NpdMsz~i}nzI4})5wPH zDFx2gc_SM$^ixl{vbATcY$SENl~t0uz@o`@lnwz}S275Qu@l@53Rvo~m@h~Lje}o6 zF7D(;7~<(CTeioXhdY3J=5$+~Iz4PGKt=wD(m4XJc;<*4N&V5t$Wd(}x@(jii+P>1 zH;<&gulz#tB**vm*mXgX)C0l$DenDt|9w~ReyV%F$-Pgnuu7)6mr4KS2kd3Nd%4Vi ziG-@=2;-8LyJ<2u1?^;dn&GgX!=yCFie#9o3};$~Y07}MJ~J0D%gjX)rWDBVkeghj z$n>SU4-D^GF4Cf^R&UTE`H9c$o@GpeLrQU~eFl+ns?;yh;gdOW%fuq{YDFY;g?|_p zj(S_N3e>59YWb3Bv!Q(t``QD>Rqcf5tNt@xoIOFj{e?t%_4(_{t54%Imd{yyj^h*M zbHi=r)opy{^0|!9hxuHwzP$Q=(u#N<#dGPW%d5}jc{k4<&olYEhrgTnJWIaC{H-PZ zdfqSNZ_#-E6^}0|EgN5cT<}lt^zZob<0Iq8pJ30U?0fw9(c>%pr}33zs;bA1Kk+1f z*Nm^_`{Yx`jX!n#X&HI4B7Os$z(y@gtkbrqPOR}|#~@KI@t-f8xiI#>zRaeenRks4 z#vcCn8Vl$Y){Mc#z$qPP#2->yA{N2{G)0D@5+Qe)2v(e04@su)MY@n!#ifQ1E3Zgs zjtFlkro748k07pf)-L8d{VpV$*H{%^rp(KU!x1cKu3@>+&M3b>K=5*6;1lgS@F#1m zgR1}~_}Nu}dQe~cBSooND%hkK;VSNARejrf?${#I0D1-(gQS}(9f(z}lNL98zg-hfc};5UxRugKDY9Qc&cQ53j8)=DKID{PrG@{>B-YvLaF1%c zK<3|OAp(1hE&9tnt9&<9-o&?^S+hTPvW-Q{XfIFI0aNPFg2V?b(owZpbs@!V(O>SB zskGnNkJv-9RzDkR<9t`Ge>ms_D(g}7SU=6|C^1l3weB8Q@xo+`ZkZvWuidc|guHx?Pf>8?A`)Co8j6)W$JGqtF^fOQQK=V@km=*}#Pt5z%&s7;q=KxDFW((7}FP%KQ zXH$UX@mynRg6)!DM-2;|vYQelJ zbO6@$RA*DSv7(7=S_vknYt6da9&;0rT=H(zK_{Gt`^Tyis~#(Y!Mu}tv{N5v15-o% z-F-GJyPAGsERv0;UGmZWR-ZfWp$g% zBNh*Q{7@OUwY`M+RBtQ0uUnOcv2;xhZN1A_^5Jnc{7QDzEKJV72Bys&?WkdTdCgXN zue)3XJCGgfiEP)n59)yWkb18{B1!+@WYfb5uauj%6007rsk+T<`C1-E(*MRko1~xQ zk9jv-M9tI{prOT^+|v8>^9%y?U&9edN$^+^jd@?)YiLOQmDUWK?C*O`XUWZA`!RLz zCii2l-k(f#uSosaFx%VEDo8PzJ91 z5k`?}{f$w2RqptXFy@>ULZ(Q4cEc3{dvAIU{aGkOd7ti0(jB1pVS8=+CxbdrEpqoK zNxBlT{H0f(J?%%Y5sm33hVK^)UwLW?s7|cfF;ul~Do^o=Fl87GecB=Ffn?&3+48-g zE_Szie>83OI0bU@UbI;NgJkcD1Ndo7k(L2NxhIqh&#&$A`4G2SQzCU+95hp zi&U-C0)y1B7pbAr?KFAmaOls9(xwB2CPwg@xnWxz;wbcBzPDs7yIoE;b=E-8NVEzd zu)DP7Kts!8OJ*}tliRv66_CI96Ko`dF><^btZ{x?JiTc@ItxEq8}D2$hEM8%?owUM z2WEYjdFga}!A}j`L#OiEv+Uu}lUwRw zLWEZ!z}_-!7wVEN6No4W`>y(C6P7m>jU0F~W9v|A+AUX>mm`9h7>S>|HNFoDkSOT= znFyZpy=s~`S*dmhd&ACUXczKoVDc~Q)O{(U37>xpu;Buh@q7G4%Bv*~ba#Asmp!o_ zRCGECQ_((VY?0Fm?~<`;owdz8n-{?O7T2Immr1IXoVW%$Ixkv@ zpT9~YVt!oh*RGwZW3WEbJLbjb;AS2_z;EwzPCChBq8k1&Q*96-cB^+)b=*@Xyr;|RVvKs3R7Rx4I7;44Fyv~O=Nm=*DajI=sum13t8b5*SFQia2v$q@m z>cK{sJ4?^wu0NzH=0_=K72fGTwF%6?aQr*aSt(Tc#ysic(~qXEXCfN|rR$tse9W?= zEeTIp!tp&{gU02LXC^D_^(bLe545&$^AsM?HlP}lht95YWiF0S;@h3T9A~ku7z~Gf zs+(a`h>Ehzh4OKvo>252-)^`rmE+Tz{E`b zEb2I&XgjKnkyA>mK@n=V_yRa|x3C{W4; zPs(-6tYUT)_PAnBQB^{FjV^4MbkG2$t1&43Y9;_uCiBUTA;uYip_`CF*eVF2{4q=w z|L9Nz>Ibrf8%uv1&+3A9Vtx74p9lZ)vf9uL#pW};!@NE{`uP_G`SG{(moC4zKCX=k zO;c^&6~FK&)quH?>L~H;i~c|M&Iit_>bm!5hO3$2D5E8o7@AHM14bk$#2BEKe?!0m z4g(kxO(KFgDjLE+H6;l+n1VIGt<59WXD<%V z@+?*KQGMUvUT4kT=l&UnKenIt37_BGd(YWt@3q%jd+oK?{&U7)0cPdx&6^@KWJKN- z0S#Wm(V=>?nu3u*(6|K{2A2QK{c*@JVT_35AN4W%?a4tk=y&Dc@V=0ygN~%Yk9c1q zef#UOpFK$`@^7t?zwu|2>`7R!ne%Ij^DE`=^7_xO_UDuIH{Kg)Nkq~kzfJ3ErN5zm z`kOp`PVYDUce=iGknNyEzM5W;z;v{!;x*;t28b6A4LaGm!v6KwXLK~nz8tC!vV4JqlKa8UpJwt@74aT_fM> zVOBjb+rx|!aaNl?Z|r6TcEz2&3VM2L)401(n(C;Axhr(-z7K9XjWRfXS49NV75vA^mQ~P&bXMoe3X$;3IT#XmCu_P?YU|crvhYh-f5p!cS*bLu>8LisjiRqg= z7|k3M*56?>!oJ2YU-}FYmD6SACrXh z8I`HL5$0EIM9HY<*|Enio3DWq?f%&xmTpv<(2JfJXlJs2aJaRhbmQ2zrWMT^z|4Ji z{jqwNY>04?j#VbbbS+9p;3TBuRdP4fFML4Phaqlb+tV0wHNe3eFxAg)7`QHX`8M4y zf_mO0HQ^7oOrtf{Fc0WDB}Dt02pgUt zf4l8@mN3y9ZW!1wmL=iW9Z|SAr=h9qg_h-cO^E-LZajLmJhR9RVi2zr_W30ml@wE? zH?QmZ5w@mTOm5w9-1_EgV=*DersXFS0pzX0Jcj<#yGe)xZ|r&uQ7RjLXX^*93ktoG z2!oPHc&y=EL7?w>mRDhiH%xEgNR+1KbK=l59E-~GZQ7|upH0io${F^&PQ&KO)1Lc3*$qp4U8|N7u|oVMmOL(=B*MQ&1oo&oy+{ij*6>+N$rse4S;FU z41j6TWm@#;yxAJzfr{oeW1ElHB72oNqf86ydW=d1Z7ypcFDB85esRO({!LvwnwBpv zsES6Qi6$R<>4EM1vC?;LCG;pasl4k4!G!JnWd@322gl##7k)t4iEf8;B3g;=GwUjb zc9b8q+f+HfiugLpclg!ZpG2x|R$JZT?g&AwV6O+VMQorMU>*35(Vj8L(&xq|?|?Qk ze6kqGo_y&WrdeIZk>PEggXuXnX86((J0&!aGmu++x*jDV?Fz{xYMv=Tf%ST^%+=Q4=`OJp`0l_1}`V(&&VpniF ziYuDow}<>LJ5qyt!g5!K0KQG&B=W8yxfhqL%#ht@Lld!Ref&n#p zX-iFC$O!TmavAaDs}i0U7@HDraMUaUZYmo8Ph zF+B+URy?R@peMre5xj#gNM?ZJd21AKQzeeH=Me|jFa+d{+yD#tlE}USc=Kwv#s!ARF$mi6f@sD&}($n>$^6UNc>+j94 ztG%-Acj=Ih!?tyQBs-)JA- zC8{()9OOBSsvXtVqUD@AkY=RREMJ|t2K{FWGDsT%Bkks+=C&*!BYoMydj?v%eopGW z*RS6F)s~iZ*p&R(57uPoah&qbkA@buo)`nWt{)-^GnHc>TmCDw=@6<=;9=2#`*G8l zrD>u5VV%Uj?w`ULi{(X%>*z;5HN!&P@ylo#`!3%y(6$!zo50E)@oEwti47bW-o*Q? z0+Jl(G`6fi7I)-5-G8uIU33qRC~rgCu=eX`3_YG;i~f&=*z4Y+OI!2C+`D)afwugAiSd;69$}(TrYPUMgpDc<*!XGgBa`6M zvu*pPhOIo0dp@^t@iFz2G1c0JA9FzmRc}X(a+E3h{u`Pe*VUi59Q9-&?N375K}T)J zp;@CoDSt-W#Mkz>m6Rb9UAUpYx^5j<|1gxwZD+IT{Wl%EO;=xNIcjV2@D2Tc6w(el z>fsRJ2+0E_ErDQrUKeg^2?W2;bkt)xX`%4OK=6*1qqgN`S=vDG3xkw)-^S@pZ-;G2 zy9h9#G}DNpFdfcZxCTi05Mw6}Ub^fm_Gs~Y$JkkeRzv`i^=^X~#EhSTbnMqghtUHjE$KwLM!ugQ@eU*RR;dN>Uaf zj-B!N(qpf}quV}q?zWYB{7yYiLkeRCMCx7#aYaOWt?te(harzR+7d+iBSe~BG!FHo zDsZSQb*SP{lD3CK5-C1SRG%Qucwucr5T|KMIciD}r)f&h!)qIYICr2a)F`Gk~mR7u7b>-W(ae99QsZcNbD3@OF4iL?fldH5P@93SE&*i?OFGSZ$;1>4Ja_|=}7;3GSA9i$w^&fKyP7(xTi$HR=r#3VA z*`A8XZ_pM3I|8w^VsS`4wV~^cBUfBV?b)ZXv290tXXlM!{*6^hJ~uZnc*o{n5tP$b zuNQHj%ZgvI;8oFJ?9>kI;f}Z4S(?O9$(^y2^IC+Gb!sOBO!e1JP~@JSQ{_v_m-?$e z&V81OcyxFlvIpsI3pQ0z%rF*HtWsyq=N8)Rt74TlGrKq(A0h7~r0%~No3?tVrZH@l zLWtGzi&nuxFWfq9deW9S=Hh9s1hd2HnLTfJ*bX+m>^S&a)3kuJy?pl{<*pSo5M-gD zSw6*!x5`)xM%ha<)bzC{PIJ0iQMt$W#1#X#M!(W3Y49*V74}#tARnp_-n~4jXYi*b zVu4=X%mo|T%WwMFAtYaQeEGd>$H*UE)f7T^do%}N&Zd<|II!WWBX({IwgZRpnR{Ht zG!RpN8L}P_E;F!b4lBES|D?b0a&0L*&(SY?m(g?W9q>mpTKa_w@9TIQ-Y87>C63qf zvmBp>x0*6#QMP(G(zmtnmI$%jA1&YVhoXeAB*A``D(>lSwc%x$ZP3b*e(KCuTB@C0 z5~R+a2?X@yBIR-dz6=5RjBR%X0i<^VdT1|yzzN`-F74~>CO9QWQv{GIC*WW14rF#8 zvGbo`Kf)n}7#G&gwwG@QY7ARV20fmK4O)V{2C*MG%#{3| z=Goa0f$=I%nW`_(cOh9CE$?h*aoGF96BE$`yvlW9$*GPp%U}E0{Ub;YA&0f0+O)FW zuqyPAhlT3J<<+_gY3B%={mMV!FWz{E=me*oPNBNiSnkSuAKE^KOc@q4ZI3!O_MP@bS zqS&*3Djr~2RwobLgcX8gswst0(&d4Y*4*+&1)_f=y#1%t{de?(v&z2{^sW>nLL=cs zlnr);Fm#N6jYDORY8zO~pYMmoRhuXf5~MX zHH!nz5MbM>Tfg;ZSm*5ZHwN7Q^>rGjumy*4$|L_6{Ln{&OS2o{l9u7ZWP$}@xUidb z<>7S5;TUn0p2M7UzOk}WSz2IMZ$!Zuuwq1E_K?0|?|h!tfY2s^H6$!Cq}1ypn#s9) zC{~c+VX5oQ=2ah1`X!#8odT<9e!N;ovxv&%d)c@COo4;f-+(lh5^7RXSs#&Gh!B1t zvwr#YM&A0cK8zw|+&=!WY|9Wc1c5$06kPv1C8Ggrn?uXntEKnwhM+d<7_~7znN>@M z&Dh%kU2Bzg?w!0W;rhmPZLcGS*B^cZuWsMvPxZTgO&GaNe&5}?-1T#v+?`(j!%;uN z?Rd|CZ#+D$>*q&zJ=|*d*G+%lJqp8f!XgLZ>B(?#9`XG3b8nXvZy%vTwOIZ3b<>a7 zvGWq^^vRmD(C*fqM<*Y#gM~Re==JUvBY4@KtQ#Fj=W4i7Ub97f7!(L+m&2VT;UEl# zk(k<3wfC}R=gTs_ad3#q4E)mhR;{6U*haU=DEpJ;YyV#F)7D~x(!CAc)41BYl8JZ@ z7H-wJl$b5biz0^sqf9(&FEq42);cK`kvTWXX~YY!8gVL9Ny zFtHRT>CLqYQ|qe+S}00o?X^>6nb#b(MN0(-+_GirNj+|kbp~F)WIQ>@y5Ja}`u_h8 zJ(GRF(Q#){+ki4Rv4lqjD&}lzUV?{(+h^%0A1U3BCa9IB|#c-b?uF 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%0DH2MT1D9O4SXU1Udb?TvF=^IBl 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�E|B!89BD|hS4lJO3VwyebLVq^nfn|gmkD@5w( znctn_z6JKKQ)}HLo3~bSCTOrkE>uekYdKt~c^RLsoA`9o#HRxjpN{BL$Qm9xw@VZ2 zWF#UQ?EFAy6&@J(q*KfNpXhh+IzQQ&_aX0FKPJxS8kgtHbTA-SP_s_4ZZu*kWy8`z zgbXZO#cTRE9ZC+2;~>&@pR21r*{$umBX!)5G4x0?O6G!lPOCl_&nP7Rlsxwt?Hwx1$!;`2 zi6gYTXJS+Gnrj84;#QmcGwv@j4&>^c>MOs=Bk>cs;7`Pp{E58C_}2Rxu0t-1pT}+o z&toTo&&#!&9c5O?ii^)}E<#Jfed&0;rfh^H@TT3sMfRxoK4|gcI-@_nqhFlZh`)Ku zWbB|&nv)z@Uwq%DY4VY6o|$$mnstC3u>2f-XaVHcBZGt?HI`_0FK^PAm+#GnLZohT zxoB(RLE{fz`v1=Q|4UkPu>E#Rax;CK!OZ0R;<`W9En$as+mJD9IP1iHLd*=GZ0BYs zZfHa+#{09=Jpu5Sz2AIB(pNa``oVLwZhO?j9!a{^=k?u4E2E6Xhuy;|1kd~KbM(y4{+$kUpy_9X?P!Y&OApV=8o#M`%d-@=3d8%$Ik7@} zGvter=Sf7K_1rhr=Cf(bxb(nX^1s>`E*2i=#}AJou=Mkx+nQY{X)te6|9$UB+*y&Y z&#^l5K4AJ;>d8TTT2Pk{DjBiqb1Sf=?Ni2%5f1$kYp&lR7^`E*HJL!om9f2l8NH(Rv@)=KA_>ET3Q9ueQmANIWg? zij5J&9%3gw@_ew6eCGE(!i%=W&)+XR+q5zqu15o@aXjmw)==(Pwg2hJQu0umXVl^i znj^IpR<;_J7mq&pJsw z`^S0QX1B_@9`A(Rr@uyp51g!xmgV@y>nSUdElaG-vTiCt-&k$?zK>{LS&l3r&r>uF zBb_|8sKJ{R$wl*;g4Q}mP_|R%P_3_L6%yo|E?w6CdS24cQ^pZ8%{}aJh243iind*D z*pYSVsgH`K#8ewcj6+T{Z>~aCJW|B_Vob&+BnICB`@*-WhOdQ9Vr|a%^ey@ylGa@> z#-Xo%Gjq^u1~yDL{lRazU5=FLvD~KHO5>f6UTQ_mRQ@^D04I3P-)*1Cli&ekQ-s=fMgkEV`q zwN?SgE)%!gSb}FsauV;mK6!NWSq6qY54GI}bz+S2nv}#^Xs%xe+P8u`jyC-IJxEsa8~&J2VO969?Oj$y*e39Fa&67{#_AE?U^O0_y-s(Hg|@V$ z!$oI`vpYpz_A!-df5K}(Tk|IS_}^pf-9F;#-tUX3WGRDV>U+x8u5@F&cLn=OA!k9E zbXN*s?XG>|$Mv<|DC^~x*ob&XJjwf}rq%0TNg)`{QI9-=>%@1g_~uI5 zuG6HlZ|qEQSwC@QN6mY9M|7(!)z!BPYIzGrqZj$Uo;!m~Dd-ui$#z6{1I``kO6xJaBpADs~9b~$-MD9mLgw+eh_Q5R))t>rtE$B4OS`M9a3m1 z_o}>je4G-Frp!iZZck71kk~jQiVbDSE7t>7SAK|^;9>3&j~A+jBVCph=l}Q_r=f@A zHS;NMEQ7--dX7}?QJbtAyj3pNyI9|l|0b0&YV3_tn;k?X6N;l=vU$-TSg!6p~b+m@qIUW>bBHg41mx$Q2sSz2JE9u+v* zC;#i@yAD$>&L9kKlTxf`_5l`2-{CQGI%lNbU7f5pJ2pgP!tV8s3Uh04%@MVz5^vj?dNsam8s#U@caDyu2xW~zInmK4Vftm%R}@4i^Whkn^1OiL75&0{OeSET|UtR{czE1t4hv)|Th_UnLTLF1b$l7`yqsb1}@;9mxr?}!(TZ{W zrY~+aZc{tFEWNYE3uFa;OkZY}j^kWYzn|_xjUHAt(TE-5H)|B1r_#c*al0fm5bN=h zS`XPKLDyrwU?H%>wo2UR=BVI9+tLl4mUKUUCH55>s*RPLo>kfpUojNcGFsKfoLU`h zudyoFYvIj?;hltDy+{<9(h>1vo2-+5?cp1b?HQ)`R}Yrz5slwA;T&9Qqxij5rI2w) z!UmV$q_tp)bTGL}!`B*7bO`H+K3=8&p)0M5!{cGyyR;s~Vd)*My;q;}XZ`S7N#o|9 zZku&>#uqtm+T6+d2pa%zptJx=n=7p#>uV3fUXlG=-s^pyslzD zl3%w{7QxuKMbd7eSp%&wOpR@#fpy03(Ox902aBhTzwANuv%fAepC%Uu)!JCkpQ+Vp zm(Fu@Hj7s~GoIl$?-tL|_t=p8G!mw0jlRJ~hu(u(jW+(td$3b@W{L$(vaN@Eo28$+ z#^MUubzRT%c$j_1ToR){DQ4y}WMuk|n@W^)eY<>|cYWW!W8n8I#=jjA-w$a_uzhp7 z$Y3>Xn`@0a+W6kzjf%DrN$i@=Z&zvtIM1}i?YbM(t84XxZt42|eHur;yH5T>aA`#P zXuIgagY2raL-UlCBkxJn?V2gbJY(IKnZD6)$40_hDECix3#%o?o>{EWv2QgMJeI7P z;~8Glbhm|uEMrVvI>vjRp=nc`gSa4`X^clxH#v?NzCCMc*fhl9un*B1`0(te#p>4{ zCo)!v8)Mhme!r!t$<6EdcIT)s7ix}i=gN+8s>qz)p>GFUDcF(RU^+}myp&6aDrqZq zxmu5SZe$5{$7ADLR$JS*=4`C2SfjIp3B5Kun7H42W|+FhJKq@yxyYYk4I)qIIMx^> z&yfafu`xZx`e2WpXej)|*AD)gt5d@V$7T~BV>z4nkg~z}@ENXDsZsHY3>fcBv(_9E zpPWIMtjF%s=!-+G8sUwZuTgWI%0_f9;)?N|V_oT6Mu^zcl^QR`Gvz=g+Zv11`%`5* zZCrRv%$dkIB%(_;5^}L_LRun58Z=o$Y?KbcZefO!4PrZ)yUZd3*|LNtO7xqeWPkRp z2`b zGx5=t)|>uB%%!A`UA$xJKT<{16I(m7QerQ>q^#{3#JJKk^Ou|rbT~8CJ9y4-sWdva z-RV_$@}@1{0mA2R|(D=JoV(hn~u@Lw~-*mG-PS=^Af^h9g8{ zlds0!O{EcW8TxEaoICyrpMpsL+gsm+R7YLcY?hBwTQmxAF16$S2Q}A;e)Fu{_E9L!#F zVbJ}oPUyyb4q+X`)s!vTHJ?)t+AWwXeSK%lJz`z+DyO8J%|RFI+FH?lvnXVqlYbfV zQjU-U?;St2SP<@zW|`-PLYOTTPq#(RE|l)y}84*MsTXCx%OLpiAT z*f(i%1{G%~ZDV`)#r7=YklIK*F0uQq!`z_|`ZuV;!^G>^C_JW&ePyU*&jmTc_KsC7 z)-7x&>tfbRaA8x0t?V4V!MT&3e~G939kL(&zgcZGeT>vYxb2c<6g7{0p&jzff6vR@ z@?(TT%b-QkBS>cGH^(YdztINl+V84Mjnym90_|lXS&_eTmg-|0A$#^+%)dO_vCIaA zhsZiJgx%Q-YV7OP4mcyXbV-ZSuKd%z!a!upnLFq+#?Pk%q1?2brSJ2-duT3eLX*9; zBjfaJoup6Gq0c=H>urhpdtLPr(Pj$x2n^{Q3@a+N@GYE=!W=+OiGOxchn-_T^a9nR?ueiqYew*>+Pz-=@%am86|#h_ zb)BrGL;4%+&dMcDORF(jFH@3V^3tz$sGFZtY!L+2J!rW>qyxG{luK=!ig+5bu1h-ox!EEw0^K+kkRV=7SDyl znx~8m@)4YcGuAVnC%G=YwJytw=rt?X?afGfGarYMuz!lhjb`aOsWcUS91_*G-@!JR z6A?Ly`4d{26~tD6>8D3&1e$BZU_QcOWb3R(Khd2&jo;)px^{Se9~_rjW><>;c=YmI zeK@^Nyn#FR|F8(rAh9~EmPItGw!5VwA_BhSy^{4sJ{j?#{L>0O34FO+#9U)U)`(K_ zBZ$Fp-WjTyiT0qv*CoQh4q@_Dn8D?IjVKNpZ?JD(YPaw~SOJ((){BF*PgkGNQBaiP zGbP?(v8I)nl_QNIv)!H(R=v-#u?I7F#q6Tg)=AE5m%;*0)aM#9B4XiZ_tA(Y*^kAo zY|vPjXFrHEl&cF*(&_6wvo6Kzmxx+8!W{tYQE^{~a{xwF7wKm$uoN|87N%sK>W7UI za*73mRBmkPT(pAgT_Nhqtb<`_z>>8;hTcW5Tg`CMxEd`-=z z@GtGX1Xs$rwM@7o4lt9swN-pSTCc6KLUhsKjI1X2hppQ^o*Tsz*7T{jJ6z4~R+B_x zHF?L{+1i7%50FgDQyK?u8Cj)>`ifZ^iYZT;zv5#k?noZ~!Y%j0* z@eOf~v_~ILuhc9Yov7{c_6~@>qbP^0?h}t3{Y3WjZ%S<*-{dmwj5_z@iix_+*@Lna zoN126WSx#v$E+||F6lYz15wq;v5z>KM=fFkVb|Llh;=)@O_2`mJx!`J0Z0(GhBTxRkvN}f-~gJ^#kT<9BeHY4tbCW`nOd57*X za^MID)~8RIZLH~JY{&^o=O?1iNgl!$!*lS?2Ydc;CZNAOw8SZ#N)+Z+QJ7y633i)mi{(+;=_+8XxZu@4Gs{VT_ zxMp2Yvy0C-tsW?a1pGMAs&b6zhH7LhLXwj#zy~$GmF?zz zW^Ii~YT~13%phuV9P~Q>+qMX?Y3FK$4oA22Q_{pz#>yCr7~QzpAY`mP1|{XJ29(98 zMAFQ!a@631Z4AfLy?Y<)NYYHDM{Pcp?PIkfuhz!cU)UB+Z_##~XAV7YOY-D(%JrSK zw48e-U9?ixU_2(TQ}S}G?pumthQ;3OPuUXDYiu`W1MAdo$tuyX=DK)%uypaZTPx=r zL%*cHBf03QrUq=*fXl=VxqqG&iM6Q2lIt>L1*{Pr%uB9Ti)&Q7Etw@oINf(n8p-=j z&BNatjKI$3WCD`)saLef*y&Hvo%f=_I1#62ysbMA4n7Gq4IoYJf0t>opPfw4^AU#&hZ zQ3mh(i*mLgz4qe2;O`}@7goP9UfSye@dIMmhsMXw<6quDbER61eIew{5d`MM5#cAw zfR~Tvy-uS8-`9ytoL_=_?R5x#m@~P>>?eMcNf*|u)h;&HQOP`->izosF#*q;cc|vy z@!p42a@RPw+!|-k*zxnuZW?u{xV)!#e(#@0#@tH(TN_(SyA6nH^G6j?dUg}7hBr)XvB4$aX>Z^D^`xpG$eh@YOr4=n3w5( z{Zcm4+>E&pzmWw;85pmw`H}j(O7qvF8MWg#SYj1%?70gQ`9Ihrj#n}>x5)qD1gSFu zn0a|?7tL~OTa~*!rkTERK%2{ExlMYwU2Euw+U@S;@>y>@Uxdu^Q?6u7rQg#xT`L-Oxp~WVx7NEKj`zkoRF>#kzg)t3A7S65)v9l$ z;*DdLuP*7tu6O);vK!ibvp1{ig4z@H%xP*8w=|lqI6KBy99kmcgvI43J|0@cTNwi~ zQX?}Sk1F3u0dF5x_KfmdV$j`Q!MnA@U>f`A@a>PR2i}btjK%x2p~(+Oo3X}Y2@b9| zh(qY@_Da>{l=ogk+pwCHJ&Kjh*@UsSRkF5nEj4UCdIRKb?9eE#Q{2AHUCK#`w~K?R730lkbr+AqQY1f*5s&(P zT=VzC;m++DEONNOzUmF*IiOe=DdbZYY4mTY0qwWyky^X;Vt)z zhR4U5LF3E!Y=*CoN84)tahH}1yGIJIfY3#ac(Y2(cM2@j@<)mab71iQcNB`vA7D0z#6V#wVzlA{NWA@5;Lf*%{o z_Mxq@TtfN0yv{0f4_U1T#T~m^UtXW_ZF4AmMMoUFYlbXvvkbQ(G~?yN&kF9BF%QaF z0Y@UAYgD|BJ5zId{64yT^~BSL7e1NB-aAn)pNsSf7xMS9jU|&eXwzJy_LU1c@oLe>3CBh88a$?fJ$wacQUor0 z3S;6VGL&e&q1N9-BD^~szCRJ5F_k5@!~OtcaZsiB8;_f;So?&WQ{!&JLwXuxyRerB z-ETSVql@e#+C(nW%HlZ2(FwlA zU7P)NWIT-?UMKIrjGtUi(%edYDof`xc&x^cJwfK+KJm||UDB?rvxcC;rO2OgCJUKc z_MVU~<{c|H-!lGui%g!QPtZraGhxZw0^?D|d-D@GgRu}%Ko)H)MC1jHw@q}6=o>On z;(2Plzupd&HkYPXYn%E`R@qc*6Ithdi&LrBj8-=5vMa~#0Jp!rN5IUCUA4>f7ragU zi`thfURE`BBW&ZQvT0W?^v9UmnQm)=BcvU9VJ4;@>gHW1rR5#^WeR`#F^7vRHDiUB3Cm@sZ|J&!}6(CClnmv0^!O{XlJw6`koE$>0cM z)m5{6w!Ehd_?clL?IqpSxOKq%b##h|6gsnc%Flb_=s|n{tcoK7@_*wbWLOxMdw=iK zlBtaKflK)QPAq7@6&dfyQiXPj_04+58Kh9Qsn$Mx;@&stY2qY*GjOs(`29=l-ECBP zGOMsr=*6f$6WNcqkR-a6W;lrYdab&l(biIVX{oJ|8utT8tj*j!F*~ZGO4{JoPV{9Iuk-7(wp#-*OiOGA}Y>zWy(I;X} z`vllfrrrK3pUIfPj<~7*W}QkP6=+&K-l?~{B5QYKf*Z)=?gC#qM(#7YKa4Ik@B|5i zPvq!Af3uIv)fP7qQg(}I{%CD05#?qd-;&x@C-H^$SaFFfn>WN@7#(bKa;lt-Z+hON zZ?F&WO5qr9W}xl&=$Y@W?rW7C=V;ZlYKd@%te87ZO7odGQcI+ByMkBbn4otUE8+~E zp|;R?%N6SG|cu@B0z=X6hR}a*+SJypC*!;IKZx>ExJFPJHoPEw;q0icLXGBsFbE`>B zJ}!(0Rx36b7}0mk7_!pw8hD0uz%^R7{^TjLY~O*u-doepD#Yx@=V-Qy+=es|liMeZ z^xt~*3bhf|J@~c@_pSA}zB8Q>;I4G!kMFnWJGahWPFGtoN5(|W^`e|UHOrOrmL3y- zqo-h{oy~eiyXZLnhVl>V8K1}MQj8h1i6_5RbAc@7zSe@OE9y4jaFeE7hpnqu25Tnd z3<{Zvv=u88F}Q05!N<@i=xtx(J!YUno-2i44$n_KN{LGYUq;>|`MuD==4C(Es= z^eD2fQg2ixZ_sbvIDu3lY1SWjNn|4-A5G3cNpNPnzGsJztlzdAaRWmx+m!sUN}4vT z0rnuh+CT$zalXdXT~W7wL}hNOsdKNI)a3R6+Tn)kMgc9+Lq-nD_9-Hno^BX_2H*WH zWv^6wj3FiYdrWlj9x8D1_cncky6amU$!(Xd;<$T49agP)Ka~54-~VCt$A959I(kd# z->PeJGJ)}H_LNqF?<0~C{7@+56ScAI4r>hQXIU3JJBmcuCe(nJgdDi z5;5mJOx#{TsrQIKp_$xA&#Fmu2>F z(HCG$yx%OZ_^OEVuVO0#}gBY0MhpHO1> zzO!S}#0i&>La$A%%k(F;#JF|+Km&0g>i3UFC*<(&I-b8%k zEhp%6?*Rn|O3K+Q>iRMF&~qQHxe@P1cf8JRl<(7vyxOLWT~PCiR{JA*=Zgk(7}#0i zBf|>HJuBFOLNB46;xt|Kh&z7W`(|{aj1orqC~Y~*`H?)#e8z9AN6#J${B*`LlvzJw zGxT}B!P|s6w@;_y|F$vZ`j>St_kx?H2m8Y9()kKFTOM({m3%E9sprY;_{Hs(a!aS_ z`_7hk+-^0uFORp6+-|+JxJzF!`C^M2(G1oMRzy~D^j*KF+-`ALf4RG6vg&C2czMn3 zw)43@$aikn%;)k{J?Ih}T+e@gK7MpiU~Tn_;Z3(`%ExO&`uO}YG?lyx$tXx{PuiY-2YsBN_ad)>G6waRC-QCV$@4H#gCsx5UVE3{TIQon?&09ehSrUCpmK1{ykxQlay)s7!MO0V zpkm3yKG^Ve^OE61rTsL%jS@NU?6;ET!AgXm7QSEd75iczQ|0g82@2q9n^#zN$9tt4 z%>Up}H+_6tRo}XEel@px`fXM9oZ$ZdK#%k<{(f1{_Wq@+dP(rQ;FQy<>KlSBzfx77 z6nsPQqTu|~tLkHd#{_TtRmG45pAtMJc*_}8wN3CP!H)#z|K+N>QEA3l1%lOrI|R=O-u=H- z)fWYK37!$WB)IIcs`|L#JAzaGuG$bB6g((+T`=}|ReeVAO~Lv9yZSD;Pw=GR8Nt$T z>3hMq1tD)^q@Il*g!72m0<>jhsHJS8~sAE>hhf=2`={o|^-N^qaxgr~&^!Bc|o3-0(Q8dJgRf>qzIs?Q1T6uc_9 z_McYOj|GRHsj6oMSN${L6MXI2s``oGmj6p*CisTn6~XG~s_K~FbAr1C-xSRM=T-Gy z!5xC{3#uQeoZuG0$$Tkx=;dcLYQ2|g=$ zLU7W*6b}WT6Fee#MX>ZoRrLYEVZrAFcM2X7JRwg~nLjtcG+JSRBu zg{oR6__*Nff~N$h|EsFHKyZiPdxDdHEIAh3E_hb3;*Z21!QFxv1xsI)j0;{8yygE^ z9|YG6z94u=@T}nEm&7~4W&c`r1;+$m6g(%m{bhX?+$H$B;90@R|BuQFo)&!aC!$wy zm*76ZPXw3!zj`jXNAQ&3vR5Qmf`4-3wiGpG8D;Nf4MQ@!nNbE>y4m{aW+JoAn@)hmKa7SE~11osJE z7QAK2oN9;QPQinMR|P9Cm{Z*%__p9Df|D+sQ>_+!T<{ISD}o(M=Tu)7oO;om>RQ2F zg0BnaE}K(r6Wk$qT5#HOl@;72cv5h}3gHrbO7M{2gp21?mkW*wz9o1=uyUoo7kpDN z_nmX9Rf10lzA1QJu=Ao$Mc zoNE2poNCKebEa*ai4+*#6kl<0lf?ac}qk3qBzDgy2=d zOMiV%wd`wis@nwL7cBT2bE*#sPJTdb2<{V{^0&l0!50KC2(JHzPv!`1^d6FF%;Y__>SPDe=w(duizoU z3E$N?3vL(OBlxM{D?d;>f>ZuLeHE+~Y!Q4)aJ%3M!RbF1?SeZ6C;gFl@UJz81P=&a z5M1)|oa&Q*tTqI%3oiSqJ_}wKjQv~nRq&SA#c#nT!RG}}3(oy_YDci_Kb%|b72Gd) zMR56vbE{7Z9v8eO*njHW>OsM>U!Gh2c;Vb?#iF^@bAq$an_Jy0ctddV+PT#Z!JUGq z1TPAHB3Qj{ZgtAo-0C*LHw9;3Ik)<>;AO$sj=9xm1P=)2zHe@|NpPp&DZ!5g=kAIuP#*UhayAo#4{F~OO8=T?sh&fPb+x?S)C!LsZ1z2HZJQ*M}BtrF}J zd{ywg;Oraqx8SRS=LKhfcy6^`aIfH${d23U1WyXydSGs~P4KAT-3Qg@zc#m8bjRH4 z%Yuh~S2TY~Gz<0%UJ!iiF7e^_=2qJUcL*N*yQ(8N`ElVCd{*$d;0?h;|8Q<~>Qi&8 zLxS%L&i_ZEU+{?FWx=`MQysw_f;$CY7d$F>Lh!8MCxR3I@!aZdf)#=df-QnE!Bv6} z3HA#13l0m82|g}(Sn!76jHks%!To}h|H<6yvVS_a`jX%&!THaK7Qyp^)BoArYOUY_ z!Te{%OTl5m*9G4Zoc5f?NbsoOw12L41WyTG7cBdM@Cd#mnEwZoE5TO;j|tBF7ou12 z3BkRBX9XubKexI>aIN6;f(HdJ2;TZHMT6j=;4Z-vg84t1TdfrA5!^0#MDSz5>3=Ah z6C4$MMeu#WNiV2v!Ht5i2%Zp}`L877f+qw&6kPUW^-*xvA8DKfZ+TJp-jH1Ud$slF z=2h<&JS+IrN%N{@e|}zdRPdx=@yYY5+XX)oZ1|;l)z<{i2u^;>ylS=J7Qy|39|>L* zRDWS!b*f;oV6ET-f}?_u2|gpZTkv(k1A>PHj|d(YJRx{e@U-Ar!4CyL7Q8HYRq)nR z=2hnkRtdHU?i74eF#j*ktF95;EjaPCdDYp1rGjmOuL`~|IN?|3Rfh%N5iB}g^avgo zoc62ps{Mj5|C-to>^w_&1lY++t&utXW z_X@Y*HNgc}%&U$G?h*X-eethO|9W1vNAPLEy@JOD&k3q8&#T@hI9G73;0?hk|INH=yWoDoD}oJQQU3+c3Re8L zk_*B21ZUhOJ_}wJocnw8s!s?`x?AHd_=;e~f2Vqa#|3A6RXi1ZSup>vix$Bhg1ZFY z5IiAxR`9aml&{UJ76_IK_6j~F_=?~j!FL7U7wr8Tl3l?W_eiz`pAtMTxb45!bHNAh zRXhKKWK3}O*VP}v7X&W}-upiamtgLF^QsRC?h-sK_@3Y;!HNHq@CzOloO!=wL-3Sf z>EBd&!NY>n9*}$ro)nz_x5Q_`4+Zc3hU7%>y5QY^Tb~853AR5dehNJjl=@T_3V-_dyg8}&=D{x$VqaN-~9v*0m7^;5~+iSw(w1ti(fsO@f-ecaCU{ox z)>G$KTLkwCUKgDB%c?KfCb(1Zl;Fg-&95#O9249pcwTVkUs8VrpBFqKcv*1nY4fWO z2|g$Irr`U6>Q_`&@NU6&!5+bFg3k)>5OZ5e3yI)tboOZ503vL%YB6wbK>O$cX+#z^e@S0%5 zBHp@U-B>^F_blHo<*@lixAFx=ip%!9#*41uqCrUOc}#U$8-N zz2MV=djyXQekiDxh<2Cj^fRPF*GVb>S6UFZjIRLBXk) ziHCwW1XsOF&jsHRY`R?IA$a;XBxfVyx!|*cuM3_RtXeJHf~N)Z*NCTrZGzhbUlcqj zctvpjTGbbf362Tw6TBoid!3#Oz9@J~aLRg(x!}`+ZwtYm_J|(zE@Vww{+te??e!-^%_X?gD zobj8&BRD3wSMappgzchF@D;(21!s;*W(8jtEE>~X6ntAS|4Q*fa8U55;DjBLU%_pH zZwTHHEPJ2m5`0ncEx{XtwL3Lu1dj?%_$|#_!A`+3!6Sl~1gBm#zgjKWFSuRs1Hs8x ztKWhr1(#nVeh3~BJT2Jte$gaY`vLtH{6uic2c-)Hr+-K?B6ve^$u9Lxa8U4h!2^Qt z3Qo9IdQ|Y3;MCocIl&!*7X@eUQQtozoPxI<)|?SMA^85yYVQ`&CwNTonqcKegn|ALnV$Ntm#)iZ)?KCOC!?+eJw-=%OI zZ>?fy@(=Yt`DInM`_X?km%DDsJSFpMfol6^HF8PGFC||zZet+7k9_(3?GUa<77Mv) zj4#P7P+e-B{v!XHtX}TKxIkr(C~E^;i&cV=xmCaOv&m%8^UTE1AYI)xl#=~9A;#;OpJ5f zGeA}&{9sq#y@U_EeTqz6XNAU?H0$hDiI1x8W=COS?FZ@Ox7#15aKPZGVrz1yDT}5g)x1gag51Kvz&f}u<#~B-kD*unr{bG8VkEBi z(?ZrTInT%m5{Kp(OjY}Iepx>CIPt2<8=p1dBw+AA(LVF~j1W@qx#jhXbAe4NnzF`8 z0;DBIJl(oC8Be&eDBT*`Y-da}&$^SDneGK{YE<4<5~owhj7Dy)QJtyhTLO{Y!=jNh zLVSy^ij}ck4Ot-=Ti^b}Cop!GW!+)#pIv`SaUO+rikT2=HTh|rY%(X^%Vst`Z90n{ zUC&(SiFFy2!&^UhhB{|PSbu1x>}${oT|OhC9le^5k>hUMv)fv3TQFPOH;<&Od~RFW zSdD0P_j!vwI)Sl7HQrzU%}FWFt@yU_tMxo|YS$g2@I3!vPOYu`o%0Lr0Ty$O5r{gp z8=w6f41ULiS6xdrRA8IMS%4fzqBt;tV`QQ|W~O_T*Gm1$Yi+Gt*;kJ#6qj|WzeQ4k zB$Qbrz9okHx1z0us$0rtXm`sfbJns0Hcm^qy?i9gdFK%fYJIEN!fbqKk^F7&PPYxD zewQFW?~!JLafgKaOj_6yOKLq8)cJRuoVY+3IqAhsX`btgYdV`YU>XzV6(i1UhA*tW ze6qIUc9f8Wk}JN4CYSJToY<$#?p#|%zqUyJ;*Da~tobcD<}5X#fw^xSJU?3Z(5odn z2T3VU4w)~k#K^U6?a-3R3R_suN5<3ow|#e0+3OXxeVj{tx8$Lz%|X))58x_q`QW$L zFti6J=<@l;7G(~QNFN}OtQ1bZ$t<|>svAaBE#OjlXIRT^GWmV0V~4?H_xFjkLW zzLL;>scplf3MmUIpGnW4{MOp1v9*hL!>7C#)8k6?c393t`QQ$J=RYN#@G++~=uN!L z*ZMAAcCYm_cCCUQ!HE_(9w;bTycIFoCM!85z$(bQ%ZYYqAZ9|yk=+tzCVYm#FM z$bQfVhtN|=oXn^=~3e;4g1Z?W>>nIb?k1`Xn&%o6!#HtaVtEavIyVY(z;M?{Gv2P0MJ7 z1#Mm46|;#rLK90@JNXC)_PuJOw2~NO+wD_twa=DMBa+sl^v0j7MS;iRV`|&cqOj@O zHgl8>zGJH<{LS9vV_ssmZ}&cN8qddPNIYlCa$o=k+pR&>65X(g-H~iA&x7Q4>DZWs7!+9?=f+m~?{MOEcXT zUD?lM7b0n)NAl6IrJ1B4;UhBYce)=@|FC+SqY6#%#F`7M*p@E$5uh(4QkbYnJWR5Z zWU<>WO1iu3Tf&vk)9#s6>hiE15)F)`BURVdec;Xtp6#ugswR_NY~d11P?PMtHcegBAcwhymRq~IwSi0| z++8+moBN3-?%>8hzE)VupDvn0L!vJjKcY+_llHh0K4Mb-*19^PfRvB;NEwUcooLDH z*JQ|CnQZ@A0MQ)~S{Pc15hkl7w6+{*|K>b%SQdM40!? zO87$rBjN@@7jIok+OA)(CH;ZkYTt4K&FDEtI9!?$D`&b_R%B;#Jw>UYvead0t^RK< znXI_g(`q0HvSzTn<2GzC&o z-gg3TS-*&Fup?!C;x&T!gJT)|jWou7k$3-C#beenf}V45r)>`|Rv(Zzq=nY_JJ)85 zYkBmX$fLJ0hq`?>?;+)pM)r=^N{aIprdy{UulAGVk17H(Ca!TyPCH)9^AzoR|M;G9 zUI%Sc9zwRS5pN1+Fwu1RgOe6eS| zTj+I@NK|T{ccC*^59ld(24S)B7jlGWA6nn?9`wb{;(kv$G+38R#s~B8LX~Gdx=`G3 zJT`rTn#1A-@)MS7qBpH#*sdk*~?{KiPJGC#Sy#<9PgH+_|;H{6!m>Pkk|Ndfn~c!1uIjruY<6 zH>_?-D?HfB)i2~7?axZa2*XoiQ`>5J#R_!1WL0&|xTIZE+dP#2_4+$bzqh{&jZyXi zYbmWW!}p@8Z@T)COHZ`wNCCa*`XO3cN?nwK&VG(iugMiO;6>s?)NJ#nS)z|aX)iV` z@Yx(|uYN&gKH|ZvoR723=fIt$I=3li*55QDc-kS`N2Duu>u+nxXrFQJDxZH(8R!hY zI9_E4;iQ5OxGZx)_q}}2A+4dZheQ96S zSzERfb89*5wC*{4yznMZbFK0<>}MiL_-8~3ogtJ{9=Ep=vyDu@56U_qV>z;m;u9V# zk{;3ymrGnZ|MBg}R<*BW`*pI24!%dc$-!23jvud`2p##o*z-9ZdCTq3cqhK$8w`vV zk&*V>`0z1P_FZW^EfIg(n0eCdDKx_MoOaqwv8&*8%BgHy&*A??S&vGSCOm_#pC(Nq zk87nxQil9y(c~DmGxqGqC;z5BUd{IDXV*`&{l0h}-Y(zm6PEBaH`Y37f!;*QTN{_u z@5l=Y=H_X~r205Eyi^3vW}os1N8Yz)pPG9ReSIX(iWM_hx=jVtM--yez6fy2%&R$EklFyl03(}^pfOt5iHgKHA``2ac14$$D z9`f4mPd-9* zNAE15&Jm0~2g=Y3&n2QwZTi}MNV^3kWz6f1;)1DgG>O?8w6*!}8QzR{F^eLrw9I9* zG_mUe#m==L3S{YFzs&F8ZMWq4V4BdUXvB8UEHlGIxyqi~p4l&)IoIKA#PpiwW6y4~ zJLAi>qqNias5PvXv_lVnHjKB)xHBhgxi!a?Xc(gf4_Sv7Nn`G;J%=^*YIB|5uGOr= zy^agyL40(4ufU(zi|4fE_c7<+uhw(25Z3D3TP7lPi|V&i9MJ!GM2qB&K+8qiWxcq5 zy9jqt^9HoFdYj66{jAYD!p`fUhT9#>9;_25c6XHIX5L|`SfhM(C# zEU9>3tp&D7!p1Z{WEg+AgC_2t#R@=Ulx5qLvgi6vSyAg{N5L8MW{D`n*Bj9@D7-|l zM&*{*9J@q+U)0GrZjJ4uc(v#~Qmmcl)tpPKQtX9W(={ce+#g07lPBGr0img|I6`X= zvRKQxwLrZ+R=+=G@)^P%t~sUU4B^`al0(jYj)=z>*I1FcypA=`Msa7CW{uxh=4bi; z+vS6A7Pi>MF+co2Tn|Z#-|ZH_7Faf^oqQJ_Ji}wb`W~sVv1>v8gHO!)eF?S+OWx%@ zK|;2wwj+E&?^5xGH-lQ@{FEo_>yjfHM|N_WbzH8yue7jHGhnQ<){3Gf;50vB-_PjU(w)`Q?o``e^z}$M_)8_pGG8kqqR&Rw+qFQ-5P}(G~3MUrQ^6f>EsE>_5Yu7OiuH%dedLJC<*EnHgHrHtE50CJ|+Oqcv>YK)`rt;KeIb*ul zW8w?ecAUg6bw#OrVs&oD2*T=xXKRHcQ53zjv|Lo*FN}=144R32CDvVkZmzxP5IDSC z{AGQ(u%1i1^kh_e*w(Bwu6RcjYc!ey&$PYzU8FUMah+Q0i^tpDrgdtg+Fd#^(xYmh zC<4;Ky2+f`H2$gG`U*+m;MUnsi1`zpUNYy*_e2HQe>%>>| z98WIMC)Nb7rg)g6t=Z4b^V6lJufG>ckF2eEfkrs0-Y!S5<^ zqGebMd(a#<|FE-DhF56)=~&{^wK|Wd?Z-O;O1pA%ZP_u3cwFR{v~8-9RxR6DwnV39 zeXefdO7=Bg4R>F#`w1QBg{fP$)wr&UXcqd#vAI3MN~Vf)M994Jevj?suH3a@Ya&kbr3rcAQPluPZT@0!*>Cp^sK=(G1UVpf&ea}nE5ISb}c z;J_v!b{%>QEc7t2`EM+9vq!%1xx3*VyM&cU^d_~<8VknZBXH!M zHf1cQKIdFekKPYyiT(%ol64z;w8S3TEo9Hx^LZ=f?E~P)uHsA#J`6T(8IjAau%K{E zb~ZL|zIzjq>%2UXuKaYGb$s(wOITO-D!GveErd-)whC(94kUc8kr zxMYh7tHpMbEYWBT(}v^!;3UG-hkKE@=D5}{G@aKN4bRs^4U*Z_U-Vqs zALyfnwVLzI=teBza$lgMZ8O`;@yijwgJ8bf0GaK`t|(+Z`uT0#Q9=LXUI(prdi zC;Pou8jpwqcj^#{B$L0r@=bEZJk5Z*h7f4W`N9TG z%a{Z9^?cKT=_=RIzLqS}F<(9JLxyr0xb)4NN7J#ktOdwl-xyUI1>T9 z&2cmJeiJnJ%;lry-8;C?&QF{GqyLlhp-a<8CjG*3Ds1f`_w?O6BBr2wF9_O_uL~U^ zaphbIyAp22j#kXkD9OkVvL8LGj?{CIU1G9E%{x;KEo+4%=6ZbF)pqc7uc8T|M^-6o zj6DiQ_@ny2#KjsrqE_S15$9;4!HF>~)wh8&@cDO%C895Uw?niZ)Qa{|t!o!6y0S+9 zU!>ow^*`^an%+Lgg#})ALM|2F5&geR>+lkNB6_@1pUVA{_4;Pe{z>#M`b`g}$}xET zXN_N}ztiJa@H_bbr&qe@VbUe&Gxnv)X<|Ry>qT=;v!bwagcdGW`)27}`&gTlacgT6 z=qP7xQ$r^m7Nhc}9$|-yeb_hk2>N{X_3oQ`WLW7MtVjCiax?10jT!w~0-NKOdd;7S zuHekS4*>$hg#8NQ>2WiygVyItQJXHLPM47M!EZzf5(0g@$2=XXV8vT ziYVvtWAC+fw@DNnt&X=9p0r!;x4XJAZ5Jj^_Y);d)+D&L$TIG(vql!J@5XjyYON@7 zT=SZq8s)hD>9X8rTkhVJw|oxq`AvCCGGTrk4?WjC*Wc7`f3~z6Qjk1{GL{%CA`vj6 zbL^|2_ajm`Xob)3nv1p7<&o(8+v#}1L0Qa`Zdv}*v0C2HDidsT>R1DW690nA`gzsV8{JXH z!P*PYm=b6`PR|ezBr`GBe+#9(*hB2oA=nS+*WZ>aeCRD!L3WJaj5Yq^>{q zefhmFA^)uS&3qE9y4a5;>*dyt+v+0YZ~8dBC&_p?gX3!1AwHep?6>%<%v*pip9uGf z@t}hkk~1QGw^LM|AJlPwBCVt zj5F$zE8>i}5@%Dg_NackOQBqeN~v-NhGm=``PiLvHdGqRa&Io>CHe*#-z!~Wc7}s7 z2N!cak$BdozNvYddxL3Km-!fZTmYUSAMNpPw%3iV?9IiJugLsiZ179q4r6a#*@nP( z@d*>=3%O6;DTfkHjxy(*C8ZvJU$c#=eqPs zx-*(=$3)qAcEej!rv1lw;HKrikvF)Q0D4es9+Cp)`0rtmdO%iQ|)Vn>pb7 z<8sblBOD>oj8x**vD<#2DUXNc^O7l`(R z2kn{NEkUtA*w&X#E{Ensld)bUnJ#Uj9fE4!g=mWH+vFumTHCjo8AC{D{+oQpwc<|7 zv9iXA+nAVd++Z90Yx0*&$T;JbPLy=_E|=ZtOHPYFo1&Y>L7dZRxU0~>59 zC7Qcy=VR7iB1$F8daBy8y!k8XdDf9cqcsezwOhmvp=3l=619mJ@h0}w(vGtdTQqvtl*0@3aEys}3wAgO791rWL z>ouj`U2oo}@%od$V!ZT#R(w1)2QJVap-O-EV6MtB`fDIdiZP z@hpgbSziZ5xlfntn4P-eVQhlG{W^!zL9 z-!s3NKa5Y3)zBNv0_Jy$y5#*EZcI%}7Y)%$oaqFgt!XHUbD9worDb4{?YLDl*YEM$ zrQBD%RdzGj`DJE$&gZLM{?6>glkhfzi?+hzjfPF_0AA<~4&x7%^2fKtGV_?EXGrMK zn1Oi&gBm%vO-*SrG*8Mq>O2{xWU+Y0Ll?Hkg4#B{RlWn-j3~mwajg^k5$Rl?W9Y~a z8gY+K1Gf9yrn}ky)Z@g1&>}e(n)?IY{ii)NG*+CzFjn+ z{k5#9$BNC&E#G-#s<@}0dcKdIzd{%LtS4t$nU}*+bWzc6liop8RrQTgctoBZZJ*zo zDc0OLxq4&0f)O3DU4iuEyAya4?25$N{j+K(t=jLYSL>~!(7Ffz23g7FC4Cb*hTrJO zQArX8V(S|g@0@s8QTdWNUglIL&FI-Rp-%?L>&e!NxdDEjVJfman)7slqp*{(vVS!Pog z?W?8zrYY&8s6#x}Cd>f0%!2RVmJUSOa0+2Sz*)3Y3jQ^(#G z{=nLCc@2FK*t@BZZ_D4d+w9GDy~BjKP2xm8hB*gfR7>1lf935(Ezdvi2J;N=AwgIl zc`L*5nO5^wnzi!Q7~Rlh_6{QghyF>o&^yngJ*vU^!E%FTzC~0mlJuucIj`bZ*K>k- za!CGKd6!F*^5Z2}gQaTFDzjR2BNJ^~96e-9eP&j9aF$qSnPb6jmG=>vBbU#OG`FX& zvq#lJ*qg~-WHmrGuux(TkC9>>ac&G2kM&zn%s$i6@f9xC#WDw|v@k=TF_Y1n=3&B; z&kE17M2qXROCaaOi)|0$pW~rN3vt^<{%wxK(rUUw>SKPFw7*?g@s?-_-x7O=k@Ad+ zT=|H+;9ZpWa?sa(ddj{j_o!j7dnFFem(jGc^`NPngILwXA(jhP2rd?^6ueV#iQv*g z-vlmx=lHJG-yRXhhQD?T@T!;%c;C>EjeUdQMgbWt#L5l`ybDKMe?j#T0cUZL7&vsZ zfOnN}s|t7UaPI%MUYei_35y#!Vk~!!k7_=Cd0)Ef(F^KdJ4xN995nGZzwe?U=OrAp zXM%oYe3mz~VBSKK;XWyMJaf<({nV* z`YrC($}MxpRH%mrm?{Ol_m=oF+9CQf8&ug_NK{31yb4Dn*(19Oq>}tdeNi<`rFk+Y0I^I%1uRNwmLZX#b zp!D6u}s0G?3xJX%O&b7+v zZSNJcvUJ&Jp@W^N8tYl~yPKzdy?}zI#D{Hf$<6r~-ZHh&;^=&2kUqsT)@VPo{-YdP z*UzjOdBz&o}L-SV7d&+W0?w=FVZs7!0M@eST|61n6ReYN32BZVc3VDzfu$U; zG&X6x(%7W&N@J78D~(MWuQWDkywcdD@k(Qp#>-;^eQCUyBSCreKYG>82XqTuO8iUX z!gIK~ujb_8n)9rL+_q-T5Ti=`!?#f~`|NL~{X-~1V!R@wdC(_a^jx6l>r~Fs6f9x# zb-JV{>7!BY6|(m*rgEijN*cSnHRwut>*bs3yY)dIw}>BM?K>Z*sqJkgRJvmtjg0QK zj>0<5v)t0kkAL75mz9Uop}mMN-zq(Rlepx44KVsvz~kRS@-4SjBl7XtWA(k+9~s|! zg{QHaE~%~k_^bV!n8j!TT$e1k<=C;z;_d@Qw>_yglWNWK< zb-Z@dV!pAP#0u#>m*xoD{yIy1i#3>?sgDR^-h4!3k48m$!*0#@11teiI{a{?;AY9j zS?XtSqTBzE5hBNAy(n$2_W528t7OQkcP+y+wYTrHMV>?SpqziDMUZxku&I*wjvg?E zun~enBxb!Rz!&CzqJ*Jc2X2k3EOs;=@6yIiN~O>Ic9j`+w`_19b6U$bl26p8)_#dk z|3rK<<_B*eK}Y78LlfrD64w0b;8r8%kz|Bckp!>rWpps<*it4~JJIL4--qrSG~S8Y zu2Fu6W=m5F%B-sP_k(yiwbFg9cZ~%1XkI97a;g4D%6NxL&i_7KT_Z^CRkGg5*yb%N z!{A9h%S#_GZBmYCU*D!8b0OuaA0ZFKle~f+59ypG+L0ak{*vy#G9}v?^d-vv#1F*J$=0)DP6skgaQ&k%8)Q4flbiI}l#S>wdKC77ZRNCYYx|H$GI7F)|1Q!ezF}=UM?G;Q zjux&L=jbsU^m{`1%}97P_WgHQRm?3cEL-lB@5jm+5n>Tgjn!%^l@*h>)vc>{j7@pd z{#d0t9?@lL4V#OWJl6aV#+X(9y8kjPv>ejmI(Vxt*gP^65PBs=IeZsfc)72)RJ?i5{lgxLH}3gKANCRTk@w$hR1Ny*x0~=A{%@Mt$(xLCqtXJS z<5;$h*GjYmp2@Ia@A(~9Xcha6$USp^k@D%^SIf^iHP`85!aH~zE>bk*(mHywNbe9! zoY^;k@Ax;X$GL($(%xkBN1ZjIkVp`-anbnw+^lbmK5t0$oDHnZG2UW-b3G55CHf_! zoJszRx7nsSQ?`@FW3qm1ly$Q;>w7;9ys>CaT@rnDk({|}3dc9U_3AvqDYM%4t9PzJ@TX{X?B}(&qPj9W^bn7;8kNt%d>4Z8< zrDGWW-cR8px-Q`%g8DZOWUVEq&>mYHGnYIzWG!X|dAJOkVdYbYcb@uhv zVZ|UHE9ssEn$`HSKKE$dN2zFYoyw=5zMAXAd0Tv5?XlO&+k=~}#+vPRQVYDzA-$8; z*x-cu;Pw;6UJH?V+ib+{u2tI}ljuWf&G6msx=%zuJ;#s|kJPYPGZRd1AAH(1pV6aU#~3Y-na2cc zHNE)}?krLpT~8^Gd{=@zLPJ?D$%nQyQ1m>Jd8&sink;@bS9(moS8OY+^uOo4g!m z)GUpbtayufyNwtzZa8eW6ZOJ237-TS-M{X7!@qAlrxIH8H;p&H+pM{2{!Ve`qiLqK_D|?Gw-RN||M&|(C*c@WBjF#FZ0xJ|H<;TCs<(GaN^_h8H=5Qb zNIALUpCn(+TB9n_3@Bc&+01*7_#ASbdeZ*1Nm`d&1^U(Z z^B&QHrfAYi3-|~zs&E#IIq>i|@0PaKM(?%%wuK!vurns(wcBXY;`hv!V-vg!X{W7b zyf3hbe53E$jq@TKG}=V797$MJ$aPvtd8?LvjWX7dIG(uBHO5_-@*d`RrjCgj zd#&h8K62p8Io0G!7fo$DwI5T{YE1TZH8KCNB@fHTy1JfuaOVB`F4k9DUtv{X@3do& zc%VKdjdjNRDv0H!oJHHgoOVl)F-Ft=8vjELTqY-lI;=~KK2mpUP1hj()<;Lo7Bm&U zEN|nahmi#n6qYl9%yT3TyR6)!A)YvhjmdSm^2{vyc(qrCB|d9y(HmhGu19)XFuWuV0B1o-0V2bxufwCCp>b zXeJAoPf1#>P4j5W^eFhX37KIPL3?c#N1Q)Yp5U;&prM+(ozbgU>!6hWEs;dB$5#4X z_O!4{o1d^m!dmoq`IGpj@3&jsUG%3?+wp^DW2~9A%sAVY5fg|~a3HT$`T-Gph|=-f zT0gDB@w^$e8(e>bGP}7oWQ%;_%f*R2#$=4$eaQVh%DE3{MZ5}bAxXG+YVWLkMihF7 zJoPpDoxVx^aLbHz+geYh%!dutZwbrjEZ~6~UDT`<9eA_M8gwBmHF8$|OisrHvUHaaif>)DC zU>+xox2=_P%JaR8^1Lp-N0S5H^yjq(wTR9cW(JY%YfHXsHd%_g$Bw;P*BzevRHvWz z(2tW-&)BD%th;nqHxGxYH+kzxLYwbrM20LuT{>`>dXu+a_JPQU-yn}xPpx;yF3Y-I z`m#$era3ZP{mFFba9A!=>}*SQMZFS`2{33S=+nnBo2RRXqkf;p8>}~@c7N-`)$eOP zX|(W{(ny6QOfFB8Vd>IfYij#pe;qj)PJ0DqNe@h>J6P}XT@l+-5kd9Zz}~CrqqIw4 zE5Z3nz>hV7cg2Vedp9ed=B4mB!Rxt`W3KcxtdKTc3EmneSREx|n)@1vMSQo}b zpPKe#C3~s;)Nv(hah}k(9aMGJ2H0YUyQ}6@C^O{=-&E);>-N*QO)Di45c{MD#<@Ej z=gKz7C@pbSjU8_HooxNcAi?$~#_JQ~v3_>zJdajcBkB2&ZMU&QI2|3NZ+P?`i*C$Y zMR~-4LJHZ9z^|NYy>|JCVet)f$x`g7gQ;aMvvN3In`<4~$M$OLBXY*@EBB3Ss$Gik zGUJJ!lsrQ6J-S5Fi6PM5h-Pr~c|k3?KC!`=V&OX87Z~#~vtPeQ<fd#ulqzYeBp{De<+`pUwOTUc%)Rbo?eT9RdtU_io=5Ml9nrnE#iM(*A2es0M*#=V za_p-}0_T-#o9}-bIQ=~|NYN{^b?+1YrR5pfxvx5BS79(aF>}icV0L27kC`jiBl>L3 z6!Lf!R4Y z6#7gp2_7#Nq4KSA>`~mM`-xL;MHLD6?)tjls!!f+Z4IT;GWp(fv`PV=&sqiqv+r~C zt>S9F!)tl@dqEHQz8C+A+0Px%ys{i~ZzFvTDEa63+i(7`A`)4qte6{nED58xW=oKS zo8n1f>Ajj*W}?4MtA$<<0bi1?aT8v{t=fX)GV;0f|VIC z^)6`W%U%~CJ_|2Q&uY=yqSlJ1Yu&bgQ=HcJw7v(^1spZ{Wr~>kT2aBDVV;mrh!w{- z+}^YKg0)Fs9F4vknv1XIy-q$wD4!nZnp05}nyY$pO0Ur>P+jd=-WNpe2_unLj21za z_v6~>Rz*^34nqpqyYy|ygwE_CCS(R=C$)V4UGaMvFdsH7@e8z;Hs4{D=eWt2XJ3Lw zuq*yAtFP(aw6oyje8<~qsXxWi@bF@(lip1}rqJFG$s$@+Z1yN%^6WwkH(?c8NW|wADxRG{b=!vc0TId>TZ%H&P+H<9laNJJ0YINic~m6XVk<{txlFf zHa}+xbVeQ~Q8T|gPI?}hIbz@jEI_FbKKKk z|Fhk3F?hng{`Ne+>A5rX=q$&@faA}jcPyE>Y57-7*H?8D@$^ui>BgvTkbr*aVa z<-1SMz#k-rl!Z4R9T(mS{=s`}%(LT2qvAIj>GT>ACp32bu>4=&wZt9&?iG}j!LI@m za>eM-Y9jO>;y+IeK^8x4_E0mHtQ&KTb~jMjjUR-+$Jtgs!=a98Ng{fTQfhkpd6pP~ z75)G@m;Tfoojmr3rgw~#wa;8Xx)2$UC#6nYr@rOWGIZ`JJXM5!T8XLD6O}eg(7Bd{ z=w$*vDxX1)K`WP%&8hrOPgxZ9)+()cRgCI$iGbZ}+=zD1x6)1(=}!V@`69@f$1K~4 zhRMPrZOZdog7jYHnD!q3ljGP$^31G<$H^RzcdR?fdQrtJxkiWaA@Bku(@&e8bG=&S ztbaudbnbhll`yj%n9EH+A6yFP_Zvo78zkQ?`#z@}fe#7q}|ff^IN$q@yodNG`6%E(=mqht1$`BN+VH)|5U~!v+(!uXl|F+O3bY44f&GL z&L`6gfA|V_WMS#AawM&0KMRP<%oEVWGliw2*Kl7&U(kYn4B&h(=*t+$l&hyNUny9>x7H0u#I_WI%gprkbHq&ZVt#pWUhT z4xP^}&7?o-f(`<{{k!VtT!>$ZH?)_>r)E1=m|FnPZ}2y5h%I&YG2(A(fkwY<2j>0u zeD244tx4*1yvdKV8gG@fIgioH%7tEbrq4L-_ajXyW67k)tn27UeZ7o2=W={@_6QOu z%KxkL%rakd{&C-ZJHE+6j7F)s?~{)c^UTYKvEutlto2eKe;9xG>F))m z;0;bXnN&S_r?Vqpc@pXr zo~b*`<~X!am+}4e2^=8oGm%+mvMlzDV-SN;UI(f-^_Bxu!rEM&aCg# zJwcECP8RfSnpxtxAj;Cr^Cgdi&v`QVu8^<1G{{#^1X;WJcOAvmu&TRI$ncZXJx6;R zaxQ8XevA_%I4i!F#U*-*G(cRoh zXE>b~ytd<3F>qf=$+N*^7g~waFE1Z7ispCWI=Kp{x)(By_30%Oi^tqST%ZVdDV|`Z zk6H2CxN|xyzf9OU2jJ;&VkH$*nS(qC+?~C;7nnJBwJH0^Z&_hlTRHbQ?rUn;nq{U2~wzETldjkfW!>{ZD#Q$9@@N?ZAAQSE&S3wwrh zyJ250ErMFiXg%A zFvgbjLU5+i?Pcdbj1iJ^Ix4ImlX4t~%}zlZ=$YrVpt0NP(-o_2j*oIKTNBT0=Im5! zx7m1>zY?fCvBdy<${TOi-(u>k4@Q?d8_^t_F>);bW?scFZ4ZX|9p+^vf&9^w&HVWi_^Di1(KG%6;_KibQ<}JW9>bOzif}A z&VFAVVXr)~=Rl2QPOmw4(5du;=M=Owb60w&y>yIM%#zd9YMo}>Q=LPmt&u<1ShY@e zxac`6jw55liH52LfU3%X%U&s_Me?+gJRO%KI@S&x)1^KT4bDgFdJ*iJo(^F{ysPXmoZMZSwec$E#X1=(OFJ@A=w$^P~Qu;?$Sl3s0DynO&r_=VLZN zGxnm^_FnwLO4xVtSv$x+3|sSc{E=V5>M%pph zq^EN|Z&*xw#e3jf*Lrpz1T6cphY$7@b-ew%*u(fTU71j zDN}2D5u98-pSE_-%Xk7|^RM^93fe!)=Vl2z!Qa;YQM6~pfOS&W746b~KUN#H8&4EE z2#P&F;zGs$d^>rOy~lO##LLvG1+%iG773|m&my7FeqK+mvmD`8g_+nx0qXA6H!HoS zXKICdqYX9hQ=QI}99=cCGAbWq7)S(rr0kqWUM(@lv6y)jF_pt9uQ0 zYHuB}uwxIvGOecVdmN;NR3a#+_*LML>oAPn=RK|OVZXu1`udb9YD$lqrjr|Jz-hywUt}ws=W?*64aDF!oE_}_={isqO%utsua?( z4DEj0o#(%hHQ&^FlcX)<#XQlUiZjJjeiHgX56JsedxQC zpM8bmxFuXsN1e5&5DtT;=#6${Zo($Hy%~mVigD7q=X8uy2)*Por!p>`1v1BJ+Iq@s zEC{XhJP}C(PmZp#WA4am@&7?2BgQMga=O-}1?P|j+Bz@kGaVi5j zJ=4Fx z>4~oN+~3J}?-8bg6K_=!{a2B1@`zTCo!uw)3pZ0^%8Vuiy z?@teJxkazU; zm0HBYUk8_#?U5WI&O$kDl2i z*)=COuOt4wjbAb7Jbs3Y9)lL zY1z|2YlQCy)wDhfoYW8W0t*2L`9&PCO!PZU5{KHOx#}G~sb^E!nvcE0(U|Em_eZe9 zkQJ$)CS%HaGDYdOQIh9AQ=ThIrXZNA_8v(C!n9Ve+Pyi|syiD}g^APNnf-+(|XX^BES?(HK^)7FMZ99qnhS zYKtW87s99Z$S(vwhD(3FH1+VIVZC=Zs(#q)kbJpKe$Q(mGjGJbzuEhJ;Pb5O5v|i4 zK`e;9Vb;=W7McWYZ#6G~-O1P$@Wodh=R#$ zx)~Qq;v3B-lYe4##47dqzqVJKu{|HXPyfKc>m)>E%zD}_2mQ3x^Q6rJ%BXr)z(#Ju z1RIwXA==g1Q-B?uoFDs3^qThiR_xzBY`c7K$A~`O`(2FcKf_LP;=R7VXy0EPfB&j| z|LXYr^Y)!nbhzK+maWmXIq&@|oUfXby-UaSA31p()Y56N<_Xj#`wmAgv`_F!xjAO2 zId}S=Jg!}PsyhhQ^kaJM+7DyVsUPx6w~fbq*tH+Dk~mVn8lJ`WQJKrNFWCssaCN=u zwV3&osmF`rd4KTCH8$GytY>A*HubaVTzcpgnLu-B= zHL6(hrHPBNul9gg(d^G`c+s7}@+9D9wL_I;@c=6Iw#$&`awE&e9;dmF&${F~%hmhT zHLehC498Y<#K*PN=||5=IZ#hFc)D)AeBwu?_Y`72vlgpt?{XU9c}$XDtrkwlCA+Tp z1|C#C&-u1}o=jW4#<%X}AmwY56pU9Hd;h1e@u|>|m>1!TzO(nIpj#bbz3ZLO*0dJW z7H*Xu92Ng zgn@5{CkFneoxO-ptJmgHC}zQ$$~ypOXyLtWcn{nQ zwXorJL`WW)Iz2I&ieK8wGGpV3NS}w7{Y&+n)_Xtl#>mabp|i$oe(q%cCVAyQzRtst z8cs6bHd4!5ww`}_GvF95F}rBDrX{Bf*Ot_TtZB#IFt>X*_`zvt&sMd(T3YUhZ;Ax0 z>G4`=_b7TBoh&4r>i_Gd)r07ZJRnsMdY(?bbM*PG()wScr7OqR;LC{;yx{eFA@5&? zyc6vr(NwMjgFpMGy(ZWF*z&$c{v`SX?MHqe)&m`rM>h42p2S!(+FGl(WFCA9!KI^< z=jOE7Cef}AW?WFDM&r)x0(Fgdl;cPn+S?lM?HTo!ZMNaub0_C4o!-NVf#xSX&$(ec zezxtE3hVLWPU048(sn%Ad--$XnzkP4$^9l*x& z)9Xf){7jBbN1XT6G4Fbpv`ev=o*tt0vnk%agko8eC-XfX%+enRExwMd=VnOO{x<@i z#)`xxMdhn9Dqq_S&m6?p_E{*F8A+wSt%Wj=7mbJK3Q0NI|F^KZ^ZQTJlXAIBkP{Qn z3Ro+&%BRds`+gL(mHwM1Q+dIwWBp!nlt$xzrqFtsIBQO74@QkECbQy}>=-iaHdvl1c5dsejAl;iB#?Bi6XqOC zeD?G9SmQFDoJb{)*Dx-|z64e-Uc{9r?Kge$ss(qG!~XtA`=MFJ1B#sMcRc}EnHpkv z_#%IXd3oCUuLYK@*Z&<-4?X4mLZ_eNyCnFvz>zbX{(rkk?Y*8>_PX>;S$sJ(gpn#z13WJ^#VtBMpA=M;hHF9 zu9s(3(r9)uShz`r}_SY76L}Zu4&#@c$Rdk+s@N1~ ztv8ByltCNM%(m^=Am(ECs{Ld=FCDM?t}AVIQ8;WKEs%{nQhybal)w@^4;iB`MHR$Q>VKqFz09h9OS52F z_puFlEPJTkqX;3`*L&U~Fu|H+{ zGAI1CjR!Bm84PRw+`9GBpmVo1yZjW~|63c8bZ3g)JeOc<^y}7Rt3RI=Eq%T3GN;m1 z7F-9(ooh0Hw1*D(OISZsj`2x{`46u|={1&~k^3YYwUW;DenFoFbPmwg@}R*`Mgpk^ zH(-(T$dwff)qrobD!?})&!rqa@9)I7D>2q{d;dMWrTejdMw~x>U61>frO&mi zdgs~pfp*~&^{amL_j3Bt>2ag+Tn);ZW}Mmr&E9OfUhkfMrVjG;sQSAab&LFVKSncJ z{j2RfvXk}5nH;Z2uUF$Qdn7-zY5kQu-S69Fr0i>9q}Q5sR4kW1Q=!RkaE_e?m*UfO zopf7o*LRjh%gI#Yr&wMM%N zuawaewXYxTxMl5qZgaMeHl<>DtiGrAwLDVa{im=j*eYUe*9UE)=%#kH=lLl8YtB$a z!^FS#biV)tT2m)P)W$YcNM zT3mw<+;J~HV*x&o&)R{$ADXTmUbO~+HB460brJ}%uOQHC#@bjKTcCMVt$wgP&*MHU zmTZ$-7?ZhQozHXFYvcSmdz7X#T54Ml+n&IW!^8eI=t}+a8?jRKQ@s9s^q)KVGv~R} zpP8E<#Q2{zDmnj<<5tepYY5PXyi;vKrI>apku|{M0VZ*M?NfEt>XqLQqLs4^T?TBR z4z2$=uoWCA$tPdA*=S29;GY|GK5-A30$(Afl(oOqKHZFbfPUjsKL=<6 zCa$Jbj4|>a`P7Hg<>IC_?Uu=DOr5&l^Sbv=jD3~N>Qf*;aMtpJwD#T;x!t)X%G@wk zQR}fk9ZR_LzTmzFJ4u)P1AK)y_pZlZ#d*!Bn8O%L55Z7&8TR38C0>tVS+t#HCy`eCO!mgs!g zw%y>7zf+yp8VIgxnU5%UGpqmij_4x0q1C*)CZG&88c*z!&+^o`Y(MIbY4)mCsN;LE zQtD0mk~uK-r98i?4yX-geSkLD6|9cW5|t0YNqtx-;+3>5KHET58~7enYh;#ez6%wa z@TXZ1O4G{UM0t;`YI;fumf2Z4&QC~r>ghLb-P`EIR2U#R_WRUcawW)EXY5|}pOV|2 zNo}1*T%kfxYh_Pk)LK!>`J~b%DUzQ~S^<$|?BXFOO zr>C)I+z;bk&W>pP9H-hEj(s`t0yH;keXZ(Z z%44tBc(TOJ%*k4rMhd5TrD`f{pmeuloRne~#|xNq`_qIr3Kr=@XSQRp8L#GSe!4LcPUMn_R_hd;DGn181!Dd>zqu;{Vop`a*$tKiV<}R2b;1+tzuPb5HI@ z%!T*%X551veH<;bb{Be8n(czQ$FpsX&6u6#sO~i1Z_}u3pV#+38pkHe9z;v75!y1{im6AsE6sYajOTbxb6&^GDGbHsj9<81j zwxvI-g}IoPPvV_XR5<&g`J;U^_Ijrtw)v0FOki9@<>WC-mul>sPwCyOz=h3_$edDvJI%U&t zl%AICf218VDRG}6EK^|(Ps!zwp8*YAIQ{;NlVamlYkK!yie*^KvchSL zntL^yYL3bgjkEw+o@#@e1P=-qh7lXV^#toocP{KC^vRkLKuqXnPpwa<5q*h4|4>|;-LYLv-+`Msw9<%dMQ`$=yVt9{GGP_jD(KW*#^{r|Hsq_-jq~*v0s_;D|k1Vvi-t_Er29WA)E} zN#Ca-fkYJ4=K9lD$Df`be|j39&{gub@-+2~IAAO1Z@VC0^V`nn%3kN6;Hh3pHg<*6@)6p_a^Z4II3|6Tvd`#)-Cv7OB9{i-2!8`JE+b|tCTN=B6# z^Xk~N^OhsMyT-sCH8CU__Pc`NgIP%|5`XIkW4YUBT5Q?3N<$ihn3`&D~>8SDB< z?W6lyXH!&%e?8XYx7qxYRNah5w!X)I)Ztf4^UGULs+*Rrrz-z%M4p&hkv@M?$1(kU zme$jALPi5WpCy$o)ta=&c-Gd`XOjOsvn8|OGQT}W&ByEc&FaDKv!&;}rCDk!Q$Lt`K9Mf}Q|J(&^w9Yw@rnX^RBS7Vv$e`?XZN9TLDdu;vA>2anCU#!Yx z(k|=6l@HU1YqSj&^jrpV+C16x>my3Ls;AFNGj`ROj5F_J800s{9Gp{&ku2dd*S0r~ zEfP6ca_;h(ZTVRxCSF&@G_$bVM>;+;h%8mES?q^wAR+Rx@Ql6Aj(mOFp6y} z8>?NiZb!QAGu)Il1;0(zqldv=XsMGVbT;G|JL+1LAE%$OB#bInR9j))9F2P!o_1cV zB0%*qtUGar9?_*KMxDpkZ4_jYWmU#B?(tLgiYYL~%-N-BG}u?!%bE~=JC6;9+<8JDSBdtk(9*Vrbert)dZ zqa|K%A2po3(^0wZH_Ciy$^lx)h)w8ei5{QCR6(~pT(-o9fV#XvGtiI z*sPQ1C6r4$yM5B*SeGdN@?h^bGBJAXlHFSFk!oh*`CZN;nDSB8~r2Iop;qR*{r<*il_tQDd|8*HV#pc(K zR!?@(JonSfnRTtczZ|_AWnl2gUD3i?aeq2(u50~Av*mdE%-7W6GSd z2;hUfM)io-O;xu1U1PDS%4Cd@wIlJNu1dcB9J48m^;K$uZ)rN;^twOASh3{CAv4}z zL$wZ^yA^*t>9Mca;@Vigl6uvXp5lHQj53x_Sy~Tody(rx?@ zvP58_Q!I02$|A^L!K%9oP#HB&mhc1r z(|ImEHaZdX!yedD^g*+UF?c=*1jFqvOlZV+KB}979YK~>j)^w4bno>Gfa?G*qTC|xiUOQB-48HkHHF9Xij}i1)vv0#+-QH%2g4q0N zUr>kD&p(CaYF%K8!5aF_0F%FPfmo-{nMu&HL6d~y{dVt zy;xg^Gn?+ox#v;LK9A$?F#6=_COkdz<7T6n-;fV>Fu{rGoy?2lJ1gG=(Gu==Wb=c- z@Oki(nUu5mW%+*ync%x5QlseMap&~43=dzPRZvdj_#wtqVPT0q%7h54$K5aTB;}W| zrq3Dc+P$Y=qzT#s$uD^x3BB?6@Q9aHCv?)3eqrqL8Y(9lDb`FY%2+kLT6SVVRrX|j z5v_RsBwo;AjMQ}OWi+F*Xp)iw*!}L?>0xig;kjtfl#&$yaQgTL||3I$% zcK8pms^oM9C z%IdrC*4Z+CdKWS{r9kG!h+(z!wsKmuCNcs3bbMI{;rsgd8+k-aGdqhd&C^TpIqT{@ zJy(0I3I|b?O#8hUfzFd-yeF@S+71OwWErtjYcjWMaNB)dVhz+D*X=%|J$>i4kv+)> zn(hoc7Gjh$K7V}2e2(7>o#ly|hA4^g9yh9h&`o4;nVWs)Te66hkX1yMHn;BA9s0e| z$|&#Be!kwJ-N1|@*FdlwXf{?>^BR(aZIQ)U9_yn{$`svVt#wANS133)@r~%?&+Q3^ z%g}ntVHd%J8kWst{vh~;#Xv5I;oYxv8kx}gA(rvWBUmYOwwsl@2hlgYhZ<5$8DXlzW`Vzb{qy0X=8m`U#DxPc^gb zkh8S?d=~Q{)?W6Uxsq?zCuT@!CEr51NJfE`gR`=t$bkFx82vrp!RBtXfO}_|SD&x) zsZaVlXt?&ZLzx9Q`JUX7Kf)QH@*|MxlwwA^6d{;eV~#Jy3Vjw*8R$`;l`o>nR0oJi z`W12O9QaS;8Dr}#h^kzn-86rKB+CnlgqJR2H_N~^;v$CLP zpW##%Tl_KgrZR%v6_x5qcgP|5@EcZHb_K7IC&JDx%91td4%Ewk2&m2Y;V!FXO)4>-`dgURKshr{~LW=${NW znkD8HrnTjiZlmfm?{nY%UvT(8K09CMzur7L*_Qh_(^@-}n7>X^*Vbo~ z>PXJEpJ|4Op86Mi&+dkO!u#<2)!(6S+_!%J)3vx;(j%CbdSH>8zq2sIKmnRzB9xmx2oOXMn+h znw`#Zc^qqd@^c~n6cRwT4}U73o??Cq{@M5Xa^SCpni(H-;xsa#C$65I4EV`A%74F1 z8JOD6DUVIdC5>io82Pp7N%Rp0-s84-sCplcb~foe9?NJQgba1nr9Xx3R9r&@F{bLR zzzX^<#xu`= zWgaBkO;)8pV;B!maRJfJChFIIyCIovakuX>z{YJH3ButuCw zFO)qW-_@u7<4;gqM;yy}T&(D6Kcw|YD-ismtQzBXthU$uk(0LvCNkkZ#WQ>Z=#Jmd zY@fU0;Giqe<+n15!*~YC2jTrF`}OJGe}>2Kw|0`B@#GhOUe0VWGQXhJGHnbC+X7`c zO>95%46LcJ)}oaVtp)NFS+GpV)JXZYTR$H*nTIn_VtZeSC;ida!@vz|WNzjiS{=i- zCO^TOzj0jUQKhZ!TPI($7tw3YI5t_}-1iQrwRcxB|LAP6yD=s_aWpz@6l;Thn_f?O zF2%KubHAE=gQh)Ys3~IKSUyc!@%e?&F!zS{1_$$`deaejeIMi!zlwWDBUH`Om(ka= zS&TJ$I*My8YHx{Ey}G$qa=Fxgr~ZMrWZ?byv{nYT>C9UGqqRAXm&yMrclgfO^}_z} z%no9Xsb06!5Z~Lei3-|%e}lli$B_b8Gqo<@7y=dA7Hh?hp|m->bOQ*aGw4) z$D_)m`aUV{nn{E+V;IRU^h~=lj~s2opowx;8s+v1ri5z0h?%>NZfv3QZpCC%`*gK~ zAui?rdm$mzhsdtq4}NKOCEogd*K%9$iq!hvuf^$0bp#{plKqjh*6Hc`ztj?6M$fQ& zXYh$#5${H({;+vBPX>4B#E0q;y{xC(dA#T$8m-zFWW&Bpy`xqX*P4;d{!_ohtin5a zk16?w;jKJ4@|wO1Eq^Dp^4su}-ifiiIIbhAoZ>Fa*TwjRgn^@d31f()+hTU zpr1|abV(1d9C7~cv!I_wh{woC`Ty6rs&z*2lKx7*=F-($-@4vKiyWO+aJWAUQ*cSz+$IT3?46uKd7|c+dDXdenNxrK2j#%D;LtJXC(v^pBCe2pQ69 zlXZFdr1uIj`n*s?)S8g~?5 zRD5hZ{l3{p>LdF;;?c7P=1~NYZAF!Vah-$Kh&T6W8#=dc&;-hOZeGG>biR*A>vyj@ zd*_I3ERu~ihd+I_BG>Vm$y|_2!4~wVH&s1le_V~vH_=}hX-wbF{BYx|cg+lk#UhBy zo)MI_08>U_I&IQd&B;hiU%9azV@o6!A?-jfm8zFY4P7(8R663DyPwx~7>`Hpw(}XW zQcClpPZ~mtY)5_*w!BiJxBprlR<+Y8Vm+AYsIieHzLqH7V~jsTuKSDN@sxW@ zc#q)sd}Q^+Qdp&6FHYsC@}aTsMbBV+Ir0gw2Zx!Fb9TX#VP6)zKAf4RJ`fL)ntJ6R zx4{@a$yoj*wuy>ENoK`liU;(-2c%bG9PLA)4i(?sCty<9f`2J^%zL>O15MWP(Akoy z|6g@+lzCbQ-5j)}r>9imi^fD5$cNTx#Tm`n>Dhf0KGSEmH=oBV4})wF6A8sjkJ z`8&|=gq5ONey(Xf#0qs9Ndeha&I0*boSui6;HLJRhI0 zoDV%dxA(u|4{zXi@%PX1_i_9o74VxG`M<^AKgHjFk3Zz#_wn~e{Eg}i4cYICf}l&a z0k;0uNp_*ZkIkc!1RL_`U3J>7Zbl~i`E?$rl6ACRO|u|lnViNamH#80bPbExp9F)> zq)x7hwq*NUIgohw^4{B``Iu^^5ZroyUa;zzdKp`qE6ANa5A9RVZ$t;4&v`9!hBxB< zt$0yex$C^K1ebGIZ#MWmx3-77ZY~)?uGh$QUYS7NeTFez)Az2iZE`d%jQx(}l3{>d z*7Kp4;+;8)t;VKfcfJWr_DRS&d#d`{=$^ax!s@*jl^vgiy=LF@VYL4TUu~t9JqPn7 z`D))1Zw<@VYvo%0CfCRO?N^_BUcP#oio{-t*PEfKtRTF~nz|SAuN~VN$(;-D2>+W1 zSl;OQ;O(WDL;aN3Y(q_$J+WSH$Wl{Ll~9;tmmtw2d3$A&t3?`p79{UWQLlzc^p3=hY^S#Gr?pu4_RaBGoz^=|CurWs-2R>iM{i-`8H>zH}+w`=(I*%jU zEN{Yey&HW~%c(ONYJJW}Aw7?RM)=iu*w_c#2+@b@Nh$ozIi|>%_P&`??zzfjPd)c^ zI)9><@-aVb)5t!^C;9%EYrX$DwPHZ8)W}iosx>-+r(gFowB0r5enb$=d+!ag+g*$B zN-l-RW1hh8oFSIIx!tI*2!UCix`54`aC{$ z=>PGAo;547N!Ar(^*V=S3+^WYT`RHu94A{xbg6iFzH`j&Z|~5)j_ZRquFd`1;u3#c z3f}bVj!6zp zb@HDzxP8PWIG=db z@0sOw#h3CSm}`w07Gn-&?)@X>lAXF{gXOC0O~k$AJUO{abr1Sg-axL4X$~J{%sn!m zfkiIEUg*=Xb*lLxKCAu>K8!Q2nPKsm4oW-LsI<@Hn^-lQ`{O@X-_V}FgNPySN1R10 z@i@jrH1SQm|FOO1QH6f>45bRD`6#B8qTUb>pG>qzct83>?%xXSyBWQb`I_^t_sBGx zkl4(jShLHV7?nIZI!(QPWe|{k<^t^{Qm(@N|0<~J&;9#0T$pE^ zo!N|+u;?*!zEHJvL}+-LeTK1GB-Yz*9o4f>>D2FdvsLN)%c#-6BTcNiAye{`>+ZQt z{G+ZOdAbvnt624T<$8|lH(3=i^UKiYTJuEb*o<}R z!>~w5{gh+9&WxocufE&-n(x}&iYL)SLw>G>uCJ%j`+={Y9w8jYc7HPty;Q8Be8o#RR2af!e@Kn7 zCHWvEo6{6dM~x4{Yy8U*3~;y}uaRyblYcz=%USRb(N?RSKQvG4c1Q*O`fgGwC=Wv> zvc2W=dc?FNe8$|F;)B+4R?}`aCGnZt4(ee}j!)(Idc942YWt+nSck?|WJ)2{WAWjo z&1?0#VwCOOy4nQE)L6sja*bV{Vt6w7P7Kw)YN&9+PhLASO>xrc9A1IbJTRSi@WR=< zM@^z~9f{M25lMd9EZ|vY-=4UGSlz7fSLi`QplK8|XJuYwj=LRZLB z_$=bAbMNyDQ^?X1qP2Bdg}vxQF#aAnvc7LLm35GB;uqGv-fI}0i+5!rb^oVvbuaMz zxyC!srJXb*ERiZ|2Xeaf8n_t+jFEji{jx=sY=G{<>p7-|HaTV zf9~Ix@WM*qK`v)~;E!R6_WoAifv=3LRu;)?{d0<@{yeH?XK-Rz-v;MO)|0E3M}^ z)hp@~o1}FK+4ALFx@5Ayzsh;8ijDPP*E}^j3i0667%fyp_o_tf3K9Pfh{|C6t-)e1 zG#O*BJe;-MUKqe!-07 zRV_>4RA#AptI`KfUKQx&WLvMF23Ai?Yst2<*~??up3xr5B|32$jMOhUR|_cmEztlv z@#i|InsL=Seb3RHtwu7xMpN+0v1E9}s@=fu32W>}uh*(+((go-(!VLk>naQ0furAQ zW%4t>)2IE2FGHr-6@?e66;x&XKZ|Rhg|sQN_EWSFEx!njLf&o1t+8OmNryVuKy`}z zChRrd%x8}1cQU(hE^-q&tH@VQJ8ybSDelpWmLsZH9ZKr)DY-TFN%3aMMtW`EvxHh| zt!HfYuq00#Z_Eqwx@a%6!?Unq%JYt>x7OmlEP64zWty??1nH6;UY6j|$ac57ztk9) zy@!-T_^*AhI*+vK;z$}VG;O6`Yc%7ehAq>6u6y%y3!s>Ef>m>QZmPn-CSwJ`0Ogg~?7AeJ;N?; zjoa}s<1q)eSMPX*ZwY(bfjX0&WQ4{Dt0hl$laIT0tjyC-+Gq_wM_m13Fs^>0<;Iap zKcZcFCvH@A(OF_p{ToY-thMqQSZ39;REYvxN{4%ZQRg^mofg+>c-OO#a(JkM>bv-^S?V8uxYT>hnXRXruS=K|dN|x(owc6jiiCH)Mysevkd$g`rDbZ(q&vM=D zN$_a&Qof+pTr2wCZFP!~j$UKvKi8TZ7Gv}Rt4B>5vAT8aS#PdP4LLAH_xO%Pl-d*6 z=j`F=s2^<9+MZOIqMVJQzHv|Ao}edcaG-_8v?-%G>T_8>8Qo#av2ad_=%mV#f2@O4 zI&4~*In6rAtCNu%Yti=E-R*2o(W3NH_?4ND8Hg1PuLAsB`8a3c>{)=FG4A)LtRLy7 zc;fjfZIXR%M_tvAo1Pmr%6EBe;HdR}k34zua&fec+SNLp(YQ8cB+hDdo(Yz67--|BEWM?lneXSK$m#9Fc4=Os$J&hC zFGCmS;HVP57e2lATl!fhw<1EJ;?`@p^$8(7Nt2occ0Vd(f-l8viv&3Gm$dK{EbomR z_r$3PdA2E)cEBWx*E2MU3(iM>P-zT-+HiLId&RfMn-kX(zRphF^dyV3>_@(O|7-<4 zEqXi>Y8|y6jrAi+d|6{TNl&|uX4~^=_K#%FD=Fr^QZfWHcfecI~ekxgO8$qHx=n6by}MYDn52fx2M zlI_i~poF3EtR=KUe)Zn*^(&L>A2)4OoH54|Jww{aq-h@knyNbKy{M6Ao|(4Nb0Cx{ zU2fZRmJvJJqK$gvKfgG-{~8!@Q77{t z>OYlz`>bW$EPd3k`LoUegI~_$T#VX*{7jy-#-gGE``pQw@&wb*j?vbJeWs&jAEBgr}RW$%@+t#nRKRtc4KPBs4f zILW8prSsmlVGowtQ9gx-b)^5X^h)Q~S)R3z{A7#;-uY zrfi;hY?)4O@jc?q?3iZOmd)I;Os93GeVr#x${)_5@e`uXnm^lMpM3T`dwNz`M~->& z<=ije+F4QF@{Prlws=&?+iCP-GvrNLQ8BQ7NL!ZmvbG_j>tFa`*Tes^4!xZB-^MBI zzwIosv6sg;$9_!pG5%NEnFTKgb3y%W^w8tK#3ja4DeiHehD-a+D~4|xfB*mN#{Jun zbiMkqdJL!Il}2%;?V;!FN=9+@`2Sgsf+v9>Khx)ApL~8G+9jIT&f(mXG|w4u=79J4 zvkM&?Rqvn1afX_$^jvsF{h5tW-0#c<5~kV!cK_av-M~asoXYc7^!{UfWA8e5>-yX6 znqve!82bA<_Va)tExAKbbEFwjF2|4X?W35Zv{#aSakpbN*&1*$;@1A9K4|qp^X-TW zyc-8h@bumf?1dG(t{DsK&d;00H?E@*ChUrl&&|6R)X+&+#0RRcXQ#4yGUb*r@5iz0 zH+o9^$XF5mB2S0$%V$A9c*RJ`c6vwQ=W*A=xNZ+9d8HbY{#;_y#{Kjo?&SmCj$4l? z%Y64J{<44fA?ef3iM|I(dX-5|2B6v@$NO57J=0#N|L#REcY_MVkl;cLpsd7L(jSEk z6A6tq!FX2v8tDf19J#m^oRI$Ju8(u^bl+!9PSKnxmE{XOYx~l9!iazWP27u@@GRt6 z-b())ynY({NXYT@?ToWp=UGwr0~YZu|G~rA6ZeyMx<}nx?^LgxgPOS|L+oL?R>P4y zyuc24KPI&Bt8(7hV`I#j<(7glZl9-n*K>5LzHILQR?z>0;7hM#Zd2dK{bze-6K3C0 z-@qBSC)a`{TWXaUjN3nM)|9j9wn3S<$HM3=A+UQIf7p@Rfzj=FKNquyetoZLBM~~b zh*N8sH9u|7bF62T+z%M@JKhh8_%{Y z7eN7}ct1w0U448LjrQUlyGVWqIVXdGz`9 zg9ew(h_2D=6vw=~?_anlUp;3}+v~o==pEb1i9_n$GeX6AFMb<&A6)w`(S&6?B&nde`bjeLKolL`=5bp?<0O3SJ}bLc{3lEarkTzvazGnKr%;*MD;Ib z<2l_;*Ilx3>x=%YPK^LWA>QNM$_U`YD)>sg` zgY%CuH-p!Yk>#CY^hNaLjB~|qJwDkANu0haKK10?IYvF4?fpZOO_^XlKk&klL|q8X zq?68pqlZ{HGI4s&=Ie2fIR)Lm2ub9r59q%3cxZ1e^I>L}#WO4_oa(c#%$}Sb@GSar z-UjaqEd>I-S-1V&*5*RYyFa$sh@Jgl^Ot5vr#;JZ;3tDKcVee?T7bA-vG4KY$u{6e zKJ-GTZ)Zs_Ryn3vkLk4rAF2RZUDfOb1+mAp6g>z z#p{KN*3RDrCVemL0D!l8?v|xc(z7%sOC!I(XmXe^rVod=eYZ!O|NEOt@)7C1Sp=hN-D^%R4llzmVM98#~bz4JSVgg1CZN53`H9aNd zTztki@;9_Ey%l8uxa&zkNN>l{B){Z34XYZg=JwBE5$`hxjZUc=-dssuKtbdX&q?Fd zD&Sml=oyOxH0KO9(OZ4ZsV1uTIRxcu@erud$=pKnVrhN>8|T`0ALksq`M4#K+<7Og z7}7#LFS3_e!(4;t+e@c=ugB64555jd30)bT&SEEK)w2-NGs0>o$Ff)WT&rN8w!82g z4I8XI#*^Tv9Pb(oe{9*o-LMpNs>s&i$*jU@p4ki1E8lh(O#LKP`=M(nYFyQJ?K9Q1 zQ@`imFNHJn$DGdc`p`KnAhM0mARlHb%jv`C+_f~q)Z8hQoaM%CcjpFA0h*5NanV#| z?3CB7QOtJjys|<&>l~eu$xKkcy%{#T9~lzG3d5g*+R&YEI^~0Qsl``@5JlI(HRTanuMTF(DhEsONaV1gHVrJd$~CGfl$S2%z6a-;k~yXRViAUXpTnnU4h zt*tP8NUYoJmu-xU;_O4|7-1JV|u(8_rb@jt@o?#`uu*a z0PeT3fZ>CNv3wVKXylmnof?oahCFXOX?W0jyxq8o44(`6C3hwYAGE%1$2Vx0qtLHB zJqwN_$+w#f>z*6!%81KEAeHZ946g@VFyvW?<_k{<12;59pWkkH?l=5z2A&s#8r(0< zk__+^GWZULZ^tjGeYfH>7``2G<^LHt@uwG>^Ze-ZI}0@Ad3#{UbMnXsA#dtMW53d_ z>({Fd&o={ip321iZ$}HXn;q(+-i;+8}%?9mm!{1!~=m?ujVU>9z zAGExCbZv|w7$glPxmqiAUvTYm!%&!C4(yOa_^5l{Y#N|@B*~JB8;z2e8()%!!bg}I zw@cy2FKG(T>l21>Q`LT72(En@6ZA?MVc#J5S8v6aTeNMZ+E_VBo&MW4FBzz zUcxW+6+}o z-6jdQ8f}H)^Wf318xN?7gQoR0#t(>_ua-#SsPJI zdUVh%4_p$L@fxp$#Q{5B=bA>_+APtK84C>E3pVg}qm}3&nV0ouH3z=}ImFU?M0h7i z0uo|6BO!t#JrWHo#V+mrOT+cvF~(yW-Z{eXcB2Ef&a$-MI4ip$ny^xh&BSxKd&GA} ze`!Q8ene;r}iI}+^ySZZ2)57C)9ZoZ<-io3MQ)L0dlw$5uJB*_ z(qs7R;PHp?_o#8(n2u-&g@mE!3t(EJ;M(;@ThAR}&OCTAuAk$Ay>F#PAh zLb&{0tPO#Y@z>(r^S%Xopntf6Qh3 zhr&&|$u;v`kkuJFUB@oS8s{X_Zi zj^@NcdejyC8K?@*c#;?6J2bp;WOH;s8f_02dC;7qag8*^n8|~^y+A|zhqh)wo?5@O z-pplqGI$PPE6XXX=y_1jwc%GkmCD|iFtR25H2fN@-$JV;lVc3+A8O{3rB$SPEjSE5P*oa~ z@uuxzUcstMznF{PY*MOLZ$)d{!-ugN`CeFuN9_t%c|qGpktrKvX#eo7W>ww_YC%2d zCdlgdt%m1Yp`H9nobpz)=X^G9Zi`I1m7p<3A``>7{t z-D+9`hSYePuhVzDMPW$Z(ls!Ojw*WZiLXx$8-=R){L&P~yM^c zBkrBnAx*Q07mn6PYRyjOOyLriVqB{;tw(~&*alYgmTHmYZ~ZFn)Tq%}t$%E)LrOeq zC6a9M6gNCta*4`nO@HmHk(d{iQLf{6y;ZG6Qugy+jEov1VT~lvx>h4mF_5Q9vR6qp zM=#@v>sg}>KFE&O&c-|aT~$oAlb>qAo=;gLpV9*?uaj;&r{|=7LN)#l!ghQVGayE}d5tg40TQ{FehuIu(tjn!&%z!dzYp5(qCv-hKzzlDGO zU+a4MGrww;kJlAFj+C90I(TBpYoFwvt&y^mKFR%2t24{GMO7VBxtP!Nsn{9I<@f2+ z;m-o%=qd5r;QC2kb4=kIzI^JoWv%KnbsqKf$EwW-Mep&oS&3xzZrxMfj8UGI=qr9d zYYeeVyFW?(gJYRAUV5)`KazCSWl;U`eL#59sMAZ7X-VEMZDh3qswL^4w52C<_qeRX zsPeV%+dDkxvS59!SXE8t3nWOBkoUYFEh*Mb-STig0nVs?VEW2V|(dJrRcrpwdv`HyHqVBsdMT}=CI7`&zZOw6dh@)s+H$` zR8C@>BoDn$(%*x4>-oUo)iKz4Z%0rI39YFVoeTOvSNadSbKY;d6}olVb^z|0p&im4=6YkkDe7Hn-&a~!XwEzKl3VY{D%yiq z>GL44s?lywN6kpi!+6Ge5G~nRw|z#M+iEaeciK^JH>W$QfXseO?QM1hGQG=tM80qP zRz}s7tgs!1q)IBmj5>8$GFO}nXY4GN6@LegR$aIJ*Z0q2q&lZw5~?R;rN1s8RHx!l z-A;x!wUJN42`S)AAbMvm)>WVD2sL|35&LWRy0C##5R`r-yzq zcrWfJ^j;Ie^t*Uz7YTAg&-Y_&bq|N0`bsa1K(s}VIp0HPgQ3fR4GQW6J&l|@rCr;o zuPA|PPMs8|af%1p5nZ){{-4Cl*26n!)Ji?F>wdr4LQYVj9?2GY`yL|pYS2e-qr^$- z%_UJDo2@SO-o36P?^LCJ9>2({NVbS4;8{;&=CV1Rp2nTIgAgvkANFo*j|KFvoa*mq z6xzc;oZ^**Wh@gjtw9)T?d+Umr(H*!8>wDi3%$@8bvgqLiYTl5mm_|uD&9Lsr@wk< z#-*?Ty(F_XJfAl>9n$+`pt7Yi^&T1RHG9g}HJV;Cmh>n-RC-YDCcY3MKm%)rqwcwu z(thmaEqh4J6?LClKkMZDtjc@pq*Wa){h>!=-P?g%6KN-dUteUhS(9cpLzTwPuJ`ja zc4m4nQR}s~(xWw3eb!oz*6FXeU;UYimcHg#YtO7HP+85Yj8-D^KVIei@EP!a9`F5Y z{2c~I^uj9g%2l6=AuIo2c)jH~uD0k;>#wR*nD@mMR>8qUYkR6HRm3cX z>c0j^G!4qCCBu8>j*o^*R{6tzP&f-$2xvW<+jgg$)(sSE?nmS$Jk*N z;I6ra6SSR^br zwW@3EVOp8*BF?Bg%|_OSsySikdLLDL;WxO}eq<-pFQmdtc29M4)dtqj*h6vvL|cg? zpK@ow7(@GonqO6av~E5IbE=)}{cM_pJRkpiV3c!8#dM6FeL~f<))8;|?EL_$_|&f4 zHP}^rsEOozVmrprKA|vF&8X^tH}!a$880#F@g4isHzOuFnU=Vg6rWII*)$?^xW`E} z)U`4F><_9cZ@v6&;=gsK-h+mG5HWJ)Xpid>{d%9U!rb)vG#sAdmEXrSOuuksO-9rJ z^V9f+iP0Lr5TEO0GPsGtqj8poD=FJ(7bOX*Ln)$e#xyj=P0YP|bxP3E=ci{PP>@nc@$^tb(%6MsK4(ySBY zJ>=Yc5BSydS@C8Bhg}80@hBfnvipw%)Bc=PkHqi5;*b0kp0putKQYx1{BB6(p15X6 z+s{rl1iu4`@n4BpgXqDK@)Xp{J^VMn48iY$#NI|mID*8w1-{1=q9OF}?4Q#WmhAFW7RGCcXmY}b9q_}xGk?x^ec7!`UESrS!H)QbmWV`7a1es zsj7Bp4ODv{awRm^Ii@uy>YZF|4;u(c(_GP?uPODT=Nr0!6dO_^-pS_XOStSJKlAnJ ztg>~b25XAHoK#T@=2dn^MvVwh74_Kf z9G!2=4xWSPlf1O6LC(c)YHDkIGVL-npH#@Ys45~fs(FiwBP-2d%gU?H!}8Pf<`p+y zlYSWVc@(-uRmA zMEg3NDQ&jb+ALKNG7hNNS7E7!?bEpKGs0{uUUrQg;@Gl6HLIVYgS??SgmV`Y~k=R4xfQUURzos&DZ zaaY2kh|XYCN6BYK>V3Ls@mp=q>#va4^J*Zc4f&p{?K+-{_w2IHsBF3NbK3h$##twZ zW0QorDxCf!yc(I=hoU)4N{aw`1E{{4r;w3#n z;^lKH1EA0K|N1eG?)+_Fc`2}zhv?C7AMc&eufN9_y&GY9jMuhsR`ok|MEX3!_GH)6 z1J?MkP02A=XVqDP+Gp8zaN$LpoHge38Qnj>Ym!T=9W0mlCwEjz2J{EKCW4kdbzfBtvj}xP&|{Ml z*hGTFDAdNDJ?7*$^*n{Mhkf^m2e$)vKcRI*nK@@TX`XW(pe3<>N~)ptV^$d>Xyuaaj*AMm2-DZjlD5yR(!4JT%>BVg|sBcSM{0Ipqbzg%hmueSf! z+W+hA|6A?(=43l{H}+5!s?jrRW$ z?|hT)bFzu;!7>c!zx?Zmf!){f$4*1I)7zdqK|wMl&o@ATnv59Fo98PSyUg!6YF89a zPqYwD?vFe#nn8B;aq#|rtIL)J{4glR*&XkPM?(bm#nGsxb$r)evpxs1cRZG}hh1ZO z&M7zytUf-*Yo5zVj5T9u&yIJ6D`TDaVEL7CA~z;!GR2_U!}uL7$ecD%^>lMR!^7FG zgt;bv@-Sfja4etrMnA?MREB~T6UP}EjdofbhNdYG<#np*xL(8^l7Z>7JJH4Q6I+Nt zAH=$tGv}4^OHYXatA00waYsVHlD#LF;_u%heubje4?pYcZj)zhjii{9D>7H8=Z{*d z+3CS)8F~)TUz%m%ifNzPXXyJ)(%qhzOO{cYUghG>7oBsv-LWG7S9KG8a+WopY=(8z zstfi>oH)zzo&^3n%&|S}&LK|?m5@?ftYtcSZBz0IU%gv%DhKD9WV|0RIlY8^B9?9C z#_3rrrpn%re}5D>$}T#m&NBzk&!q13y-o2a`vqp$W<9BH4SoL5#;bXD7rO4Zei$qA zzrE!gJGgGW!2_6LUw^NbfIZC24`kfQwLgxRW(PyVU&f#CcWb>Y*z{gs^*i?3_RSEs z=fTmbN`2dKL+vs0RlnChb*G;YHo`zQdZ|Y|6I+pk;Lh|u_CEF}lca^7uIePDyD!yB z?hbvO%{YlQ+Qqt`1pYeA*W0a=*~O{8A+M>AsnN{h*xIM@PPUqSFn1!cqj_sAaog=f zO4`q5k+Mgg_KL=k)#9Y9+&ye>likd$EKGGtw2%*%P-L0Ml&DsXwct5SX659>)bimK zzk1ehi8fHeHty^#;HF-&g6!kdi5GWbrg+rWW{JFzT&gvGY@Z$;&&~W&eAM8efK)p@5Q*O`dSCucdvteH|E}TaJh3G%nt(J z_anMr2iJG6g?(%9-Qen4*t&ZiY~PYZ?}2Jx`~t*7e0Hcz0qf zYiX4CuZ5rXb&YjQdo1{5pE-?LezyHvoqL7Hp?nd3$BVdACvjLQWlF$q*nHc#WX5Lk$rNCuTG!gguC-?HUdY_OqK5U8Z4b0=h>7@3D|PlwqnVD zjvB7|;(Gng=age*AS-p0smNHsl|6|)^DXD45FO(Ss(02PbV>%-GAF3KC7zYfonf5h zOgHuVB7P?mGww@Kyl88Bs0Z_DTYu!!`V-Y^W$CzAo$iAi;Qw)gN5)D2N3npLM@A&4 zQ-9X>A_`7NdoO&K9~&q8v7U`AI?w8?Vm%F}`l9GN`gW&r6RCgiSe}&=m5!q?DM=p( z|Iv$j3Zn0;zu=DsGVNkLxk#B;@|$UIiN1QODLbvTCbSJpHJv9a zRIafbYmWUKuat@D$xk|2DJ_BPzd8SkR?5~ZyKmmrQ^b^w(T*COCFZIj_QP

sitJvGOK+vFHL4#528@k!}#ijBB6K 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