summaryrefslogtreecommitdiffstats
path: root/EdkModulePkg/Universal
diff options
context:
space:
mode:
authorbbahnsen <bbahnsen@6f19259b-4bc3-4df7-8a09-765794883524>2006-04-21 22:54:32 +0000
committerbbahnsen <bbahnsen@6f19259b-4bc3-4df7-8a09-765794883524>2006-04-21 22:54:32 +0000
commit878ddf1fc3540a715f63594ed22b6929e881afb4 (patch)
treec56c44dac138137b510e1fba7c3efe5e4d84bea2 /EdkModulePkg/Universal
downloadedk2-878ddf1fc3540a715f63594ed22b6929e881afb4.tar.gz
edk2-878ddf1fc3540a715f63594ed22b6929e881afb4.tar.bz2
edk2-878ddf1fc3540a715f63594ed22b6929e881afb4.zip
Initial import.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'EdkModulePkg/Universal')
-rw-r--r--EdkModulePkg/Universal/Console/ConSplitter/Dxe/ComponentName.c531
-rw-r--r--EdkModulePkg/Universal/Console/ConSplitter/Dxe/ConSplitter.c3193
-rw-r--r--EdkModulePkg/Universal/Console/ConSplitter/Dxe/ConSplitter.h623
-rw-r--r--EdkModulePkg/Universal/Console/ConSplitter/Dxe/ConSplitter.mbd41
-rw-r--r--EdkModulePkg/Universal/Console/ConSplitter/Dxe/ConSplitter.msa102
-rw-r--r--EdkModulePkg/Universal/Console/ConSplitter/Dxe/ConSplitterGraphics.c1076
-rw-r--r--EdkModulePkg/Universal/Console/ConSplitter/Dxe/build.xml74
-rw-r--r--EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/ComponentName.c139
-rw-r--r--EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/ComponentName.h51
-rw-r--r--EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/GraphicsConsole.c1566
-rw-r--r--EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/GraphicsConsole.h160
-rw-r--r--EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/GraphicsConsole.mbd42
-rw-r--r--EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/GraphicsConsole.msa69
-rw-r--r--EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/LaffStd.c290
-rw-r--r--EdkModulePkg/Universal/Console/GraphicsConsole/Dxe/build.xml47
-rw-r--r--EdkModulePkg/Universal/Console/Terminal/Dxe/ComponentName.c194
-rw-r--r--EdkModulePkg/Universal/Console/Terminal/Dxe/Terminal.c1214
-rw-r--r--EdkModulePkg/Universal/Console/Terminal/Dxe/Terminal.h506
-rw-r--r--EdkModulePkg/Universal/Console/Terminal/Dxe/Terminal.mbd44
-rw-r--r--EdkModulePkg/Universal/Console/Terminal/Dxe/Terminal.msa108
-rw-r--r--EdkModulePkg/Universal/Console/Terminal/Dxe/TerminalConIn.c1185
-rw-r--r--EdkModulePkg/Universal/Console/Terminal/Dxe/TerminalConOut.c997
-rw-r--r--EdkModulePkg/Universal/Console/Terminal/Dxe/ansi.c68
-rw-r--r--EdkModulePkg/Universal/Console/Terminal/Dxe/build.xml47
-rw-r--r--EdkModulePkg/Universal/Console/Terminal/Dxe/vtutf8.c270
-rw-r--r--EdkModulePkg/Universal/DataHub/DataHub/Dxe/DataHub.c655
-rw-r--r--EdkModulePkg/Universal/DataHub/DataHub/Dxe/DataHub.dxs26
-rw-r--r--EdkModulePkg/Universal/DataHub/DataHub/Dxe/DataHub.h122
-rw-r--r--EdkModulePkg/Universal/DataHub/DataHub/Dxe/DataHub.mbd44
-rw-r--r--EdkModulePkg/Universal/DataHub/DataHub/Dxe/DataHub.msa61
-rw-r--r--EdkModulePkg/Universal/DataHub/DataHub/Dxe/build.xml47
-rw-r--r--EdkModulePkg/Universal/DataHub/DataHubStdErr/Dxe/DataHubStdErr.c163
-rw-r--r--EdkModulePkg/Universal/DataHub/DataHubStdErr/Dxe/DataHubStdErr.dxs27
-rw-r--r--EdkModulePkg/Universal/DataHub/DataHubStdErr/Dxe/DataHubStdErr.mbd41
-rw-r--r--EdkModulePkg/Universal/DataHub/DataHubStdErr/Dxe/DataHubStdErr.msa64
-rw-r--r--EdkModulePkg/Universal/DataHub/DataHubStdErr/Dxe/build.xml47
-rw-r--r--EdkModulePkg/Universal/DebugSupport/Dxe/DebugSupport.c151
-rw-r--r--EdkModulePkg/Universal/DebugSupport/Dxe/DebugSupport.dxs26
-rw-r--r--EdkModulePkg/Universal/DebugSupport/Dxe/DebugSupport.mbd42
-rw-r--r--EdkModulePkg/Universal/DebugSupport/Dxe/DebugSupport.msa68
-rw-r--r--EdkModulePkg/Universal/DebugSupport/Dxe/build.xml47
-rw-r--r--EdkModulePkg/Universal/DebugSupport/Dxe/ia32/AsmFuncs.asm547
-rw-r--r--EdkModulePkg/Universal/DebugSupport/Dxe/ia32/plDebugSupport.c440
-rw-r--r--EdkModulePkg/Universal/DebugSupport/Dxe/ia32/plDebugSupport.h312
-rw-r--r--EdkModulePkg/Universal/DebugSupport/Dxe/ipf/AsmFuncs.s1389
-rw-r--r--EdkModulePkg/Universal/DebugSupport/Dxe/ipf/Ds64Macros.i85
-rw-r--r--EdkModulePkg/Universal/DebugSupport/Dxe/ipf/common.i34
-rw-r--r--EdkModulePkg/Universal/DebugSupport/Dxe/ipf/plDebugSupport.c625
-rw-r--r--EdkModulePkg/Universal/Debugger/Debugport/Dxe/ComponentName.c108
-rw-r--r--EdkModulePkg/Universal/Debugger/Debugport/Dxe/DebugPort.c833
-rw-r--r--EdkModulePkg/Universal/Debugger/Debugport/Dxe/DebugPort.dxs26
-rw-r--r--EdkModulePkg/Universal/Debugger/Debugport/Dxe/DebugPort.h172
-rw-r--r--EdkModulePkg/Universal/Debugger/Debugport/Dxe/DebugPort.mbd46
-rw-r--r--EdkModulePkg/Universal/Debugger/Debugport/Dxe/DebugPort.msa77
-rw-r--r--EdkModulePkg/Universal/Debugger/Debugport/Dxe/build.xml47
-rw-r--r--EdkModulePkg/Universal/Disk/DiskIo/Dxe/ComponentName.c160
-rw-r--r--EdkModulePkg/Universal/Disk/DiskIo/Dxe/DiskIo.mbd41
-rw-r--r--EdkModulePkg/Universal/Disk/DiskIo/Dxe/DiskIo.msa65
-rw-r--r--EdkModulePkg/Universal/Disk/DiskIo/Dxe/build.xml47
-rw-r--r--EdkModulePkg/Universal/Disk/DiskIo/Dxe/diskio.c876
-rw-r--r--EdkModulePkg/Universal/Disk/DiskIo/Dxe/diskio.h44
-rw-r--r--EdkModulePkg/Universal/Disk/DiskIoPartition/dxe/DiskIoPartition.mbd42
-rw-r--r--EdkModulePkg/Universal/Disk/DiskIoPartition/dxe/DiskIoPartition.msa88
-rw-r--r--EdkModulePkg/Universal/Disk/DiskIoPartition/dxe/build.xml47
-rw-r--r--EdkModulePkg/Universal/Disk/Partition/Dxe/ComponentName.c160
-rw-r--r--EdkModulePkg/Universal/Disk/Partition/Dxe/ElTorito.c277
-rw-r--r--EdkModulePkg/Universal/Disk/Partition/Dxe/ElTorito.h130
-rw-r--r--EdkModulePkg/Universal/Disk/Partition/Dxe/Gpt.c768
-rw-r--r--EdkModulePkg/Universal/Disk/Partition/Dxe/Gpt.h76
-rw-r--r--EdkModulePkg/Universal/Disk/Partition/Dxe/Mbr.c317
-rw-r--r--EdkModulePkg/Universal/Disk/Partition/Dxe/Mbr.h68
-rw-r--r--EdkModulePkg/Universal/Disk/Partition/Dxe/Partition.c735
-rw-r--r--EdkModulePkg/Universal/Disk/Partition/Dxe/Partition.h123
-rw-r--r--EdkModulePkg/Universal/Disk/Partition/Dxe/Partition.mbd42
-rw-r--r--EdkModulePkg/Universal/Disk/Partition/Dxe/Partition.msa81
-rw-r--r--EdkModulePkg/Universal/Disk/Partition/Dxe/build.xml47
-rw-r--r--EdkModulePkg/Universal/Disk/UnicodeCollation/English/Dxe/English.mbd38
-rw-r--r--EdkModulePkg/Universal/Disk/UnicodeCollation/English/Dxe/English.msa53
-rw-r--r--EdkModulePkg/Universal/Disk/UnicodeCollation/English/Dxe/UnicodeCollationEng.c478
-rw-r--r--EdkModulePkg/Universal/Disk/UnicodeCollation/English/Dxe/UnicodeCollationEng.h102
-rw-r--r--EdkModulePkg/Universal/Disk/UnicodeCollation/English/Dxe/build.xml47
-rw-r--r--EdkModulePkg/Universal/Ebc/Dxe/Ebc.dxs26
-rw-r--r--EdkModulePkg/Universal/Ebc/Dxe/Ebc.mbd43
-rw-r--r--EdkModulePkg/Universal/Ebc/Dxe/Ebc.msa80
-rw-r--r--EdkModulePkg/Universal/Ebc/Dxe/EbcExecute.c4603
-rw-r--r--EdkModulePkg/Universal/Ebc/Dxe/EbcExecute.h383
-rw-r--r--EdkModulePkg/Universal/Ebc/Dxe/EbcInt.c932
-rw-r--r--EdkModulePkg/Universal/Ebc/Dxe/EbcInt.h231
-rw-r--r--EdkModulePkg/Universal/Ebc/Dxe/Ia32/EbcLowLevel.asm148
-rw-r--r--EdkModulePkg/Universal/Ebc/Dxe/Ia32/EbcSupport.c482
-rw-r--r--EdkModulePkg/Universal/Ebc/Dxe/Ia32/Ia32Math.asm622
-rw-r--r--EdkModulePkg/Universal/Ebc/Dxe/Ipf/EbcLowLevel.s167
-rw-r--r--EdkModulePkg/Universal/Ebc/Dxe/Ipf/EbcSupport.c906
-rw-r--r--EdkModulePkg/Universal/Ebc/Dxe/Ipf/IpfMath.c375
-rw-r--r--EdkModulePkg/Universal/Ebc/Dxe/Ipf/IpfMul.s144
-rw-r--r--EdkModulePkg/Universal/Ebc/Dxe/build.xml47
-rw-r--r--EdkModulePkg/Universal/Ebc/Dxe/x64/EbcLowLevel.asm145
-rw-r--r--EdkModulePkg/Universal/Ebc/Dxe/x64/EbcSupport.c579
-rw-r--r--EdkModulePkg/Universal/Ebc/Dxe/x64/x64Math.c451
-rw-r--r--EdkModulePkg/Universal/EmuVariable/RuntimeDxe/EmuVariable.c754
-rw-r--r--EdkModulePkg/Universal/EmuVariable/RuntimeDxe/EmuVariable.dxs25
-rw-r--r--EdkModulePkg/Universal/EmuVariable/RuntimeDxe/EmuVariable.mbd45
-rw-r--r--EdkModulePkg/Universal/EmuVariable/RuntimeDxe/EmuVariable.msa76
-rw-r--r--EdkModulePkg/Universal/EmuVariable/RuntimeDxe/InitVariable.c185
-rw-r--r--EdkModulePkg/Universal/EmuVariable/RuntimeDxe/Ipf/InitVariable.c167
-rw-r--r--EdkModulePkg/Universal/EmuVariable/RuntimeDxe/Variable.h143
-rw-r--r--EdkModulePkg/Universal/EmuVariable/RuntimeDxe/build.xml47
-rw-r--r--EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwLite.c951
-rw-r--r--EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwLite.dxs28
-rw-r--r--EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwLite.h675
-rw-r--r--EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwLite.mbd44
-rw-r--r--EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwLite.msa90
-rw-r--r--EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwMisc.c530
-rw-r--r--EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwWorkSpace.c567
-rw-r--r--EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/Ia32/Ia32FtwMisc.c399
-rw-r--r--EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/Ipf/IpfFtwMisc.c143
-rw-r--r--EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/build.xml47
-rw-r--r--EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/x64/x64FtwMisc.c140
-rw-r--r--EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/Crc32SectionExtract.c234
-rw-r--r--EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/Crc32SectionExtract.dxs28
-rw-r--r--EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/Crc32SectionExtract.h65
-rw-r--r--EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/Crc32SectionExtract.mbd40
-rw-r--r--EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/Crc32SectionExtract.msa61
-rw-r--r--EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/GuidedSection.c75
-rw-r--r--EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/GuidedSection.h53
-rw-r--r--EdkModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/build.xml47
-rw-r--r--EdkModulePkg/Universal/GenericMemoryTest/Dxe/Common.h59
-rw-r--r--EdkModulePkg/Universal/GenericMemoryTest/Dxe/NullMemoryTest.c214
-rw-r--r--EdkModulePkg/Universal/GenericMemoryTest/Dxe/NullMemoryTest.dxs26
-rw-r--r--EdkModulePkg/Universal/GenericMemoryTest/Dxe/NullMemoryTest.h65
-rw-r--r--EdkModulePkg/Universal/GenericMemoryTest/Dxe/NullMemoryTest.mbd44
-rw-r--r--EdkModulePkg/Universal/GenericMemoryTest/Dxe/NullMemoryTest.msa60
-rw-r--r--EdkModulePkg/Universal/GenericMemoryTest/Dxe/build.xml47
-rw-r--r--EdkModulePkg/Universal/GenericMemoryTest/Pei/BaseMemoryTest.c154
-rw-r--r--EdkModulePkg/Universal/GenericMemoryTest/Pei/BaseMemoryTest.h89
-rw-r--r--EdkModulePkg/Universal/GenericMemoryTest/Pei/BaseMemoryTest.mbd39
-rw-r--r--EdkModulePkg/Universal/GenericMemoryTest/Pei/BaseMemoryTest.msa54
-rw-r--r--EdkModulePkg/Universal/GenericMemoryTest/Pei/build.xml47
-rw-r--r--EdkModulePkg/Universal/MonotonicCounter/RuntimeDxe/MonotonicCounter.c266
-rw-r--r--EdkModulePkg/Universal/MonotonicCounter/RuntimeDxe/MonotonicCounter.dxs27
-rw-r--r--EdkModulePkg/Universal/MonotonicCounter/RuntimeDxe/MonotonicCounter.h36
-rw-r--r--EdkModulePkg/Universal/MonotonicCounter/RuntimeDxe/MonotonicCounter.mbd47
-rw-r--r--EdkModulePkg/Universal/MonotonicCounter/RuntimeDxe/MonotonicCounter.msa70
-rw-r--r--EdkModulePkg/Universal/MonotonicCounter/RuntimeDxe/build.xml47
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/BC.mbd42
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/BC.msa94
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/ComponentName.c160
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/Print.c81
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/bc.c2510
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/bc.h499
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/build.xml47
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/dhcp.h627
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/hton.h42
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/ip.h741
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_arp.c617
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_dhcp.c3332
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_igmp.c476
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_ip.c861
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_mtftp.c2391
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_udp.c577
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_loadfile.c1697
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/tftp.h153
-rw-r--r--EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/ComponentName.c169
-rw-r--r--EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/Dhcp4.mbd41
-rw-r--r--EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/Dhcp4.msa74
-rw-r--r--EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4.c342
-rw-r--r--EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4.h307
-rw-r--r--EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4InitSelect.c786
-rw-r--r--EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4Release.c246
-rw-r--r--EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4RenewRebind.c408
-rw-r--r--EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4Run.c196
-rw-r--r--EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4Setup.c268
-rw-r--r--EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/build.xml47
-rw-r--r--EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/support.c1126
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/ComponentName.c160
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/SNP.mbd41
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/SNP.msa85
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/WaitForPacket.c100
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/build.xml47
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/callback.c613
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/get_status.c193
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/initialize.c244
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/mcast_ip_to_mac.c167
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/nvdata.c183
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/receive.c255
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/receive_filters.c411
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/reset.c129
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/shutdown.c152
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/snp.c1315
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/snp.h410
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/start.c191
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/station_address.c248
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/statistics.c193
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/stop.c120
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/transmit.c396
-rw-r--r--EdkModulePkg/Universal/PCD/Common/PcdCommon.c592
-rw-r--r--EdkModulePkg/Universal/PCD/Common/PcdCommon.h386
-rw-r--r--EdkModulePkg/Universal/PCD/Dxe/Pcd.c472
-rw-r--r--EdkModulePkg/Universal/PCD/Dxe/Service.c491
-rw-r--r--EdkModulePkg/Universal/PCD/Dxe/Service.h399
-rw-r--r--EdkModulePkg/Universal/PCD/Pei/Pcd.c486
-rw-r--r--EdkModulePkg/Universal/PCD/Pei/Service.c812
-rw-r--r--EdkModulePkg/Universal/PCD/Pei/Service.h371
-rw-r--r--EdkModulePkg/Universal/PCD/Test/PcdTest.c110
-rw-r--r--EdkModulePkg/Universal/PCD/Test/PcdTest.dxs28
-rw-r--r--EdkModulePkg/Universal/Runtime/RuntimeDxe/Crc32.c124
-rw-r--r--EdkModulePkg/Universal/Runtime/RuntimeDxe/Ia32/PeHotRelocateEx.c88
-rw-r--r--EdkModulePkg/Universal/Runtime/RuntimeDxe/Ipf/PeHotRelocateEx.c242
-rw-r--r--EdkModulePkg/Universal/Runtime/RuntimeDxe/Ipf/PeHotRelocateEx.h76
-rw-r--r--EdkModulePkg/Universal/Runtime/RuntimeDxe/PeHotRelocate.c216
-rw-r--r--EdkModulePkg/Universal/Runtime/RuntimeDxe/Runtime.c574
-rw-r--r--EdkModulePkg/Universal/Runtime/RuntimeDxe/Runtime.dxs26
-rw-r--r--EdkModulePkg/Universal/Runtime/RuntimeDxe/Runtime.h129
-rw-r--r--EdkModulePkg/Universal/Runtime/RuntimeDxe/Runtime.mbd46
-rw-r--r--EdkModulePkg/Universal/Runtime/RuntimeDxe/Runtime.msa80
-rw-r--r--EdkModulePkg/Universal/Runtime/RuntimeDxe/build.xml47
-rw-r--r--EdkModulePkg/Universal/Runtime/RuntimeDxe/x64/PeHotRelocateEx.c88
-rw-r--r--EdkModulePkg/Universal/Security/SecurityStub/Dxe/SecurityStub.c156
-rw-r--r--EdkModulePkg/Universal/Security/SecurityStub/Dxe/SecurityStub.dxs27
-rw-r--r--EdkModulePkg/Universal/Security/SecurityStub/Dxe/SecurityStub.h47
-rw-r--r--EdkModulePkg/Universal/Security/SecurityStub/Dxe/SecurityStub.mbd40
-rw-r--r--EdkModulePkg/Universal/Security/SecurityStub/Dxe/SecurityStub.msa55
-rw-r--r--EdkModulePkg/Universal/Security/SecurityStub/Dxe/build.xml47
-rw-r--r--EdkModulePkg/Universal/StatusCode/RuntimeDxe/DebugAssert.c231
-rw-r--r--EdkModulePkg/Universal/StatusCode/RuntimeDxe/Ia32/Ia32StatusCode.c75
-rw-r--r--EdkModulePkg/Universal/StatusCode/RuntimeDxe/Ia32/Ia32StatusCode.dxs26
-rw-r--r--EdkModulePkg/Universal/StatusCode/RuntimeDxe/Ipf/IpfStatusCode.c126
-rw-r--r--EdkModulePkg/Universal/StatusCode/RuntimeDxe/Ipf/IpfStatusCode.dxs27
-rw-r--r--EdkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCode.c172
-rw-r--r--EdkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCode.h64
-rw-r--r--EdkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCode.mbd55
-rw-r--r--EdkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCode.msa77
-rw-r--r--EdkModulePkg/Universal/StatusCode/RuntimeDxe/build.xml47
-rw-r--r--EdkModulePkg/Universal/StatusCode/RuntimeDxe/x64/x64StatusCode.c75
-rw-r--r--EdkModulePkg/Universal/StatusCode/RuntimeDxe/x64/x64StatusCode.dxs27
-rw-r--r--EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/Fonts.c263
-rw-r--r--EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/Forms.c1564
-rw-r--r--EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/HiiDatabase.c413
-rw-r--r--EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/HiiDatabase.dxs26
-rw-r--r--EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/HiiDatabase.h302
-rw-r--r--EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/HiiDatabase.mbd44
-rw-r--r--EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/HiiDatabase.msa80
-rw-r--r--EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/Keyboard.c43
-rw-r--r--EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/Package.c677
-rw-r--r--EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/Strings.c1276
-rw-r--r--EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/build.xml47
-rw-r--r--EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Boolean.c1360
-rw-r--r--EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Colors.h54
-rw-r--r--EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/DriverSample.c631
-rw-r--r--EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/DriverSample.h60
-rw-r--r--EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/DriverSample.mbd45
-rw-r--r--EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/DriverSample.msa84
-rw-r--r--EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/NVDataStruc.h62
-rw-r--r--EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/Vfr.vfr622
-rw-r--r--EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/VfrStrings.unibin0 -> 35590 bytes
-rw-r--r--EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/build.xml47
-rw-r--r--EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/inventory.vfr123
-rw-r--r--EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/inventorystrings.unibin0 -> 8302 bytes
-rw-r--r--EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/InputHandler.c1580
-rw-r--r--EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Presentation.c1481
-rw-r--r--EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Print.c338
-rw-r--r--EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Print.h37
-rw-r--r--EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/ProcessOptions.c1677
-rw-r--r--EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Setup.c2217
-rw-r--r--EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Setup.h504
-rw-r--r--EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/SetupBrowser.mbd43
-rw-r--r--EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/SetupBrowser.msa82
-rw-r--r--EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/SetupBrowserStr.unibin0 -> 11028 bytes
-rw-r--r--EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Ui.c3143
-rw-r--r--EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Ui.h435
-rw-r--r--EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/build.xml47
-rw-r--r--EdkModulePkg/Universal/Variable/Pei/Ia32/VarMachine.h27
-rw-r--r--EdkModulePkg/Universal/Variable/Pei/Ipf/VarMachine.h27
-rw-r--r--EdkModulePkg/Universal/Variable/Pei/Variable.c563
-rw-r--r--EdkModulePkg/Universal/Variable/Pei/Variable.dxs28
-rw-r--r--EdkModulePkg/Universal/Variable/Pei/Variable.h154
-rw-r--r--EdkModulePkg/Universal/Variable/Pei/Variable.mbd43
-rw-r--r--EdkModulePkg/Universal/Variable/Pei/Variable.msa57
-rw-r--r--EdkModulePkg/Universal/Variable/Pei/build.xml47
-rw-r--r--EdkModulePkg/Universal/Variable/Pei/x64/VarMachine.h27
-rw-r--r--EdkModulePkg/Universal/Variable/RuntimeDxe/Emu/EmuVariable.c754
-rw-r--r--EdkModulePkg/Universal/Variable/RuntimeDxe/Emu/EmuVariable.dxs25
-rw-r--r--EdkModulePkg/Universal/Variable/RuntimeDxe/Emu/EmuVariable.mbd45
-rw-r--r--EdkModulePkg/Universal/Variable/RuntimeDxe/Emu/EmuVariable.msa73
-rw-r--r--EdkModulePkg/Universal/Variable/RuntimeDxe/Emu/build.xml47
-rw-r--r--EdkModulePkg/Universal/Variable/RuntimeDxe/Ia32Variable.dxs28
-rw-r--r--EdkModulePkg/Universal/Variable/RuntimeDxe/InitVariable.c185
-rw-r--r--EdkModulePkg/Universal/Variable/RuntimeDxe/Ipf/InitVariable.c167
-rw-r--r--EdkModulePkg/Universal/Variable/RuntimeDxe/IpfVariable.dxs28
-rw-r--r--EdkModulePkg/Universal/Variable/RuntimeDxe/Variable.c1311
-rw-r--r--EdkModulePkg/Universal/Variable/RuntimeDxe/Variable.h143
-rw-r--r--EdkModulePkg/Universal/Variable/RuntimeDxe/Variable.mbd51
-rw-r--r--EdkModulePkg/Universal/Variable/RuntimeDxe/Variable.msa109
-rw-r--r--EdkModulePkg/Universal/Variable/RuntimeDxe/build.xml47
-rw-r--r--EdkModulePkg/Universal/Variable/RuntimeDxe/reclaim.c240
-rw-r--r--EdkModulePkg/Universal/Variable/RuntimeDxe/reclaim.h45
-rw-r--r--EdkModulePkg/Universal/Variable/RuntimeDxe/x64Variable.dxs26
-rw-r--r--EdkModulePkg/Universal/WatchdogTimer/Dxe/WatchDogTimer.c310
-rw-r--r--EdkModulePkg/Universal/WatchdogTimer/Dxe/WatchDogTimer.dxs27
-rw-r--r--EdkModulePkg/Universal/WatchdogTimer/Dxe/WatchDogTimer.h62
-rw-r--r--EdkModulePkg/Universal/WatchdogTimer/Dxe/WatchDogTimer.mbd44
-rw-r--r--EdkModulePkg/Universal/WatchdogTimer/Dxe/WatchDogTimer.msa61
-rw-r--r--EdkModulePkg/Universal/WatchdogTimer/Dxe/build.xml47
303 files changed, 97497 insertions, 0 deletions
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>ConSplitter</BaseName>
+ <Guid>408edcec-cf6d-477c-a5a8-b4844e3de281</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Created>2006-03-12 17:09</Created>
+ <Modified>2006-03-19 15:19</Modified>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>UefiMemoryLib</Library>
+ <Library>UefiLib</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>UefiDriverModelLib</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Library>BaseDebugLibReportStatusCode</Library>
+ <Library>BaseLib</Library>
+ <Library>DxeMemoryAllocationLib</Library>
+ </Libraries>
+</ModuleBuildDescription>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>ConSplitter</BaseName>
+ <ModuleType>DXE_DRIVER</ModuleType>
+ <ComponentType>BS_DRIVER</ComponentType>
+ <Guid>408edcec-cf6d-477c-a5a8-b4844e3de281</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for DiskIo module.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Specification>0</Specification>
+ <Created>2006-03-12 17:09</Created>
+ <Updated>2006-03-19 15:19</Updated>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverModelLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseMemoryLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">MemoryAllocationLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>ConSplitter.c</Filename>
+ <Filename>ConSplitter.h</Filename>
+ <Filename>ComponentName.c</Filename>
+ <Filename>ConSplitterGraphics.c</Filename>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ <PackageName>EdkModulePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="ALWAYS_CONSUMED">UgaDraw</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">SimpleTextOut</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">SimpleTextIn</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">SimplePointer</Protocol>
+ <Protocol Usage="ALWAYS_PRODUCED">ConsoleControl</Protocol>
+ </Protocols>
+ <Guids>
+ <GuidEntry Usage="ALWAYS_PRODUCED">
+ <C_Name>PrimaryStandardErrorDevice</C_Name>
+ </GuidEntry>
+ <GuidEntry Usage="ALWAYS_PRODUCED">
+ <C_Name>PrimaryConsoleInDevice</C_Name>
+ </GuidEntry>
+ <GuidEntry Usage="ALWAYS_PRODUCED">
+ <C_Name>PrimaryConsoleOutDevice</C_Name>
+ </GuidEntry>
+ <GuidEntry Usage="ALWAYS_CONSUMED">
+ <C_Name>ConsoleOutDevice</C_Name>
+ </GuidEntry>
+ <GuidEntry Usage="ALWAYS_CONSUMED">
+ <C_Name>StandardErrorDevice</C_Name>
+ </GuidEntry>
+ <GuidEntry Usage="ALWAYS_CONSUMED">
+ <C_Name>ConsoleInDevice</C_Name>
+ </GuidEntry>
+ </Guids>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint>ConSplitterDriverEntry</ModuleEntryPoint>
+ </Extern>
+ <Extern>
+ <DriverBinding>gConSplitterConInDriverBinding</DriverBinding>
+ <ComponentName>gConSplitterConInComponentName</ComponentName>
+ </Extern>
+ <Extern>
+ <DriverBinding>gConSplitterSimplePointerDriverBinding</DriverBinding>
+ <ComponentName>gConSplitterSimplePointerComponentName</ComponentName>
+ </Extern>
+ <Extern>
+ <DriverBinding>gConSplitterConOutDriverBinding</DriverBinding>
+ <ComponentName>gConSplitterConOutComponentName</ComponentName>
+ </Extern>
+ <Extern>
+ <DriverBinding>gConSplitterStdErrDriverBinding</DriverBinding>
+ <ComponentName>gConSplitterStdErrComponentName</ComponentName>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
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 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="ConSplitter"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\Console\ConSplitter\Dxe"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="ConSplitter">
+ <GenBuild baseName="ConSplitter" mbdFilename="${MODULE_DIR}\ConSplitter.mbd" msaFilename="${MODULE_DIR}\ConSplitter.msa"/>
+ </target>
+ <target name="ConSplitterLite">
+ <GenBuild baseName="ConSplitterLite" mbdFilename="${MODULE_DIR}\ConSplitterLite.mbd" msaFilename="${MODULE_DIR}\ConSplitterLite.msa"/>
+ </target>
+ <target depends="ConSplitter_clean" name="clean"/>
+ <target depends="ConSplitter_cleanall" name="cleanall"/>
+ <target name="ConSplitter_clean">
+ <OutputDirSetup baseName="ConSplitter" mbdFilename="${MODULE_DIR}\ConSplitter.mbd" msaFilename="${MODULE_DIR}\ConSplitter.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\ConSplitter_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\ConSplitter_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="ConSplitterLite_clean">
+ <OutputDirSetup baseName="ConSplitterLite" mbdFilename="${MODULE_DIR}\ConSplitterLite.mbd" msaFilename="${MODULE_DIR}\ConSplitterLite.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\ConSplitterLite_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\ConSplitterLite_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="ConSplitter_cleanall">
+ <OutputDirSetup baseName="ConSplitter" mbdFilename="${MODULE_DIR}\ConSplitter.mbd" msaFilename="${MODULE_DIR}\ConSplitter.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\ConSplitter_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\ConSplitter_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**ConSplitter*"/>
+ </delete>
+ </target>
+ <target name="ConSplitterLite_cleanall">
+ <OutputDirSetup baseName="ConSplitterLite" mbdFilename="${MODULE_DIR}\ConSplitterLite.mbd" msaFilename="${MODULE_DIR}\ConSplitterLite.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\ConSplitterLite_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\ConSplitterLite_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**ConSplitterLite*"/>
+ </delete>
+ </target>
+</project> \ 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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>GraphicsConsole</BaseName>
+ <Guid>CCCB0C28-4B24-11d5-9A5A-0090273FC14D</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Created>2006-03-12 17:09</Created>
+ <Modified>2006-03-19 15:19</Modified>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>UefiLib</Library>
+ <Library>UefiMemoryLib</Library>
+ <Library>HiiLib</Library>
+ <Library>UefiDriverModelLib</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Library>BaseDebugLibReportStatusCode</Library>
+ <Library>BaseLib</Library>
+ <Library>DxeMemoryAllocationLib</Library>
+ </Libraries>
+</ModuleBuildDescription>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>GraphicsConsole</BaseName>
+ <ModuleType>DXE_DRIVER</ModuleType>
+ <ComponentType>BS_DRIVER</ComponentType>
+ <Guid>CCCB0C28-4B24-11d5-9A5A-0090273FC14D</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for GraphicsConsole module</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Specification>0</Specification>
+ <Created>2006-03-12 17:09</Created>
+ <Updated>2006-03-19 15:19</Updated>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverModelLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">HiiLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseMemoryLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">MemoryAllocationLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>GraphicsConsole.h</Filename>
+ <Filename>GraphicsConsole.c</Filename>
+ <Filename>LaffStd.c</Filename>
+ <Filename>ComponentName.c</Filename>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="TO_START">UgaDraw</Protocol>
+ <Protocol Usage="TO_START">Hii</Protocol>
+ <Protocol Usage="BY_START">SimpleTextOut</Protocol>
+ <Protocol Usage="TO_START">DevicePath</Protocol>
+ </Protocols>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint></ModuleEntryPoint>
+ </Extern>
+ <Extern>
+ <DriverBinding>gGraphicsConsoleDriverBinding</DriverBinding>
+ <ComponentName>gGraphicsConsoleComponentName</ComponentName>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
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 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="GraphicsConsole"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\Console\GraphicsConsole\Dxe"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="GraphicsConsole">
+ <GenBuild baseName="GraphicsConsole" mbdFilename="${MODULE_DIR}\GraphicsConsole.mbd" msaFilename="${MODULE_DIR}\GraphicsConsole.msa"/>
+ </target>
+ <target depends="GraphicsConsole_clean" name="clean"/>
+ <target depends="GraphicsConsole_cleanall" name="cleanall"/>
+ <target name="GraphicsConsole_clean">
+ <OutputDirSetup baseName="GraphicsConsole" mbdFilename="${MODULE_DIR}\GraphicsConsole.mbd" msaFilename="${MODULE_DIR}\GraphicsConsole.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\GraphicsConsole_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\GraphicsConsole_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="GraphicsConsole_cleanall">
+ <OutputDirSetup baseName="GraphicsConsole" mbdFilename="${MODULE_DIR}\GraphicsConsole.mbd" msaFilename="${MODULE_DIR}\GraphicsConsole.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\GraphicsConsole_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\GraphicsConsole_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**GraphicsConsole*"/>
+ </delete>
+ </target>
+</project> \ 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 <Common/StatusCode.h>
+
+//
+// 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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>Terminal</BaseName>
+ <Guid>9E863906-A40F-4875-977F-5B93FF237FC6</Guid>
+ <Version>EDK_RELEASE_VERSION 0x00020000</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Created>2006-03-12 17:09</Created>
+ <Modified>2006-03-22 19:05</Modified>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>UefiRuntimeServicesTableLib</Library>
+ <Library>UefiMemoryLib</Library>
+ <Library>UefiLib</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>UefiDriverModelLib</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Library>BaseDebugLibReportStatusCode</Library>
+ <Library>EdkDxePrintLib</Library>
+ <Library>BaseLib</Library>
+ <Library>DxeMemoryAllocationLib</Library>
+ <Library>UefiDevicePathLib</Library>
+ </Libraries>
+</ModuleBuildDescription>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>Terminal</BaseName>
+ <ModuleType>DXE_DRIVER</ModuleType>
+ <ComponentType>BS_DRIVER</ComponentType>
+ <Guid>9E863906-A40F-4875-977F-5B93FF237FC6</Guid>
+ <Version>EDK_RELEASE_VERSION 0x00020000</Version>
+ <Abstract>Component description file for DiskIo module.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Specification>EFI_SPECIFICATION_VERSION 0x00000000</Specification>
+ <Created>2006-03-12 17:09</Created>
+ <Updated>2006-03-22 19:05</Updated>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverModelLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">ReportStatusCodeLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseMemoryLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">MemoryAllocationLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiRuntimeServicesTableLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DevicePathLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>Terminal.h</Filename>
+ <Filename>Terminal.c</Filename>
+ <Filename>TerminalConIn.c</Filename>
+ <Filename>TerminalConOut.c</Filename>
+ <Filename>ansi.c</Filename>
+ <Filename>vtutf8.c</Filename>
+ <Filename>ComponentName.c</Filename>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ <PackageName>EdkModulePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="BY_START">SimpleTextOut</Protocol>
+ <Protocol Usage="BY_START">SimpleTextIn</Protocol>
+ <Protocol Usage="TO_START">DevicePath</Protocol>
+ <Protocol Usage="TO_START">SerialIo</Protocol>
+ </Protocols>
+ <Variables>
+ <Variable Usage="SOMETIMES_CONSUMED">
+ <String>ConInDev</String>
+ <Guid>0x8BE4DF61, 0x93CA, 0x11d2, 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C</Guid>
+ </Variable>
+ <Variable Usage="SOMETIMES_CONSUMED">
+ <String>ConOutDev</String>
+ <Guid>0x8BE4DF61, 0x93CA, 0x11d2, 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C</Guid>
+ </Variable>
+ <Variable Usage="SOMETIMES_CONSUMED">
+ <String>ErrOutDev</String>
+ <Guid>0x8BE4DF61, 0x93CA, 0x11d2, 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C</Guid>
+ </Variable>
+ </Variables>
+ <Guids>
+ <GuidEntry Usage="SOMETIMES_CONSUMED">
+ <C_Name>HotPlugDevice</C_Name>
+ </GuidEntry>
+ <GuidEntry Usage="SOMETIMES_CONSUMED">
+ <C_Name>GlobalVariable</C_Name>
+ </GuidEntry>
+ <GuidEntry Usage="SOMETIMES_CONSUMED">
+ <C_Name>PcAnsi</C_Name>
+ </GuidEntry>
+ <GuidEntry Usage="SOMETIMES_CONSUMED">
+ <C_Name>VT100Plus</C_Name>
+ </GuidEntry>
+ <GuidEntry Usage="SOMETIMES_CONSUMED">
+ <C_Name>VT100</C_Name>
+ </GuidEntry>
+ <GuidEntry Usage="SOMETIMES_CONSUMED">
+ <C_Name>VTUTF8</C_Name>
+ </GuidEntry>
+ </Guids>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint></ModuleEntryPoint>
+ </Extern>
+ <Extern>
+ <DriverBinding>gTerminalDriverBinding</DriverBinding>
+ <ComponentName>gTerminalComponentName</ComponentName>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
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 <Common/StatusCode.h>
+#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 <Common/StatusCode.h>
+
+//
+// This list is used to define the valid extend chars.
+// It also provides a mapping from Unicode to PCANSI or
+// ASCII. The ASCII mapping we just made up.
+//
+//
+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 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="Terminal"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\Console\Terminal\Dxe"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="Terminal">
+ <GenBuild baseName="Terminal" mbdFilename="${MODULE_DIR}\Terminal.mbd" msaFilename="${MODULE_DIR}\Terminal.msa"/>
+ </target>
+ <target depends="Terminal_clean" name="clean"/>
+ <target depends="Terminal_cleanall" name="cleanall"/>
+ <target name="Terminal_clean">
+ <OutputDirSetup baseName="Terminal" mbdFilename="${MODULE_DIR}\Terminal.mbd" msaFilename="${MODULE_DIR}\Terminal.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\Terminal_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\Terminal_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="Terminal_cleanall">
+ <OutputDirSetup baseName="Terminal" mbdFilename="${MODULE_DIR}\Terminal.mbd" msaFilename="${MODULE_DIR}\Terminal.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\Terminal_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\Terminal_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**Terminal*"/>
+ </delete>
+ </target>
+</project> \ 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 <AutoGen.h>
+#include <DxeDepex.h>
+
+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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>DataHub</BaseName>
+ <Guid>53BCC14F-C24F-434C-B294-8ED2D4CC1860</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Created>2006-03-12 17:09</Created>
+ <Modified>2006-03-19 15:19</Modified>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>UefiRuntimeServicesTableLib</Library>
+ <Library>UefiMemoryLib</Library>
+ <Library>UefiLib</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Library>BaseDebugLibReportStatusCode</Library>
+ <Library>BaseLib</Library>
+ <Library>DxeMemoryAllocationLib</Library>
+ </Libraries>
+ <BuildOptions ToolChain="MSFT">
+ <ImageEntryPoint>_ModuleEntryPoint</ImageEntryPoint>
+ </BuildOptions>
+</ModuleBuildDescription>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>DataHub</BaseName>
+ <ModuleType>DXE_DRIVER</ModuleType>
+ <ComponentType>BS_DRIVER</ComponentType>
+ <Guid>53BCC14F-C24F-434C-B294-8ED2D4CC1860</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for DiskIo module.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Specification>0</Specification>
+ <Created>2006-03-12 17:09</Created>
+ <Updated>2006-03-19 15:19</Updated>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseMemoryLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">MemoryAllocationLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiRuntimeServicesTableLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>DataHub.c</Filename>
+ <Filename>DataHub.h</Filename>
+ <Filename>DataHub.dxs</Filename>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ <PackageName>EdkModulePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="ALWAYS_PRODUCED">DataHub</Protocol>
+ </Protocols>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint>DataHubInstall</ModuleEntryPoint>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
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 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="DataHub"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\DataHub\DataHub\Dxe"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="DataHub">
+ <GenBuild baseName="DataHub" mbdFilename="${MODULE_DIR}\DataHub.mbd" msaFilename="${MODULE_DIR}\DataHub.msa"/>
+ </target>
+ <target depends="DataHub_clean" name="clean"/>
+ <target depends="DataHub_cleanall" name="cleanall"/>
+ <target name="DataHub_clean">
+ <OutputDirSetup baseName="DataHub" mbdFilename="${MODULE_DIR}\DataHub.mbd" msaFilename="${MODULE_DIR}\DataHub.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\DataHub_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\DataHub_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="DataHub_cleanall">
+ <OutputDirSetup baseName="DataHub" mbdFilename="${MODULE_DIR}\DataHub.mbd" msaFilename="${MODULE_DIR}\DataHub.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\DataHub_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\DataHub_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**DataHub*"/>
+ </delete>
+ </target>
+</project> \ 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 <AutoGen.h>
+#include <DxeDepex.h>
+
+
+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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>DataHubStdErr</BaseName>
+ <Guid>CA515306-00CE-4032-874E-11B755FF6866</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Created>2006-03-12 17:09</Created>
+ <Modified>2006-03-19 15:19</Modified>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>UefiMemoryLib</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Library>BaseDebugLibReportStatusCode</Library>
+ <Library>BaseLib</Library>
+ </Libraries>
+ <BuildOptions ToolChain="MSFT">
+ <ImageEntryPoint>_ModuleEntryPoint</ImageEntryPoint>
+ </BuildOptions>
+</ModuleBuildDescription>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>DataHubStdErr</BaseName>
+ <ModuleType>DXE_DRIVER</ModuleType>
+ <ComponentType>BS_DRIVER</ComponentType>
+ <Guid>CA515306-00CE-4032-874E-11B755FF6866</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for DiskIo module.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Specification>0</Specification>
+ <Created>2006-03-12 17:09</Created>
+ <Updated>2006-03-19 15:19</Updated>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseMemoryLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>DataHubStdErr.c</Filename>
+ <Filename>DataHubStdErr.dxs</Filename>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ <PackageName>EdkModulePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="ALWAYS_CONSUMED">DataHub</Protocol>
+ </Protocols>
+ <Guids>
+ <GuidEntry Usage="SOMETIMES_CONSUMED">
+ <C_Name>StatusCode</C_Name>
+ </GuidEntry>
+ <GuidEntry Usage="SOMETIMES_CONSUMED">
+ <C_Name>StatusCodeDataTypeDebug</C_Name>
+ </GuidEntry>
+ </Guids>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint>DataHubStdErrInitialize</ModuleEntryPoint>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
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 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="DataHubStdErr"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\DataHub\DataHubStdErr\Dxe"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="DataHubStdErr">
+ <GenBuild baseName="DataHubStdErr" mbdFilename="${MODULE_DIR}\DataHubStdErr.mbd" msaFilename="${MODULE_DIR}\DataHubStdErr.msa"/>
+ </target>
+ <target depends="DataHubStdErr_clean" name="clean"/>
+ <target depends="DataHubStdErr_cleanall" name="cleanall"/>
+ <target name="DataHubStdErr_clean">
+ <OutputDirSetup baseName="DataHubStdErr" mbdFilename="${MODULE_DIR}\DataHubStdErr.mbd" msaFilename="${MODULE_DIR}\DataHubStdErr.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\DataHubStdErr_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\DataHubStdErr_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="DataHubStdErr_cleanall">
+ <OutputDirSetup baseName="DataHubStdErr" mbdFilename="${MODULE_DIR}\DataHubStdErr.mbd" msaFilename="${MODULE_DIR}\DataHubStdErr.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\DataHubStdErr_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\DataHubStdErr_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**DataHubStdErr*"/>
+ </delete>
+ </target>
+</project> \ 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 <AutoGen.h>
+#include <DxeDepex.h>
+
+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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>DebugSupport</BaseName>
+ <Guid>911D584C-35F7-4955-BEF9-B452769DDC3A</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Created>2006-03-12 17:09</Created>
+ <Modified>2006-03-19 15:19</Modified>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>BaseLib</Library>
+ <Library>UefiMemoryLib</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Library>BaseDebugLibReportStatusCode</Library>
+ <Library>DxeMemoryAllocationLib</Library>
+ </Libraries>
+ <BuildOptions ToolChain="MSFT">
+ <ImageEntryPoint>_ModuleEntryPoint</ImageEntryPoint>
+ </BuildOptions>
+</ModuleBuildDescription>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>DebugSupport</BaseName>
+ <ModuleType>DXE_DRIVER</ModuleType>
+ <ComponentType>BS_DRIVER</ComponentType>
+ <Guid>911D584C-35F7-4955-BEF9-B452769DDC3A</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for DiskIo module.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Specification>0</Specification>
+ <Created>2006-03-12 17:09</Created>
+ <Updated>2006-03-19 15:19</Updated>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseMemoryLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">MemoryAllocationLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>DebugSupport.c</Filename>
+ <Filename>DebugSupport.dxs</Filename>
+ <Arch ArchType="IA32">
+ <Filename>ia32\AsmFuncs.asm</Filename>
+ <Filename>ia32\plDebugSupport.c</Filename>
+ </Arch>
+ <Arch ArchType="IPF">
+ <Filename>ipf\AsmFuncs.s</Filename>
+ <Filename>ipf\common.i</Filename>
+ <Filename>ipf\ds64macros.i</Filename>
+ <Filename>ipf\plDebugSupport.c</Filename>
+ </Arch>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ <PackageName>EdkModulePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="SOMETIMES_PRODUCED">DebugSupport</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">LoadedImage</Protocol>
+ </Protocols>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint>InitializeDebugSupportDriver</ModuleEntryPoint>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
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 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="DebugSupport"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\DebugSupport\Dxe"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="DebugSupport">
+ <GenBuild baseName="DebugSupport" mbdFilename="${MODULE_DIR}\DebugSupport.mbd" msaFilename="${MODULE_DIR}\DebugSupport.msa"/>
+ </target>
+ <target depends="DebugSupport_clean" name="clean"/>
+ <target depends="DebugSupport_cleanall" name="cleanall"/>
+ <target name="DebugSupport_clean">
+ <OutputDirSetup baseName="DebugSupport" mbdFilename="${MODULE_DIR}\DebugSupport.mbd" msaFilename="${MODULE_DIR}\DebugSupport.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\DebugSupport_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\DebugSupport_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="DebugSupport_cleanall">
+ <OutputDirSetup baseName="DebugSupport" mbdFilename="${MODULE_DIR}\DebugSupport.mbd" msaFilename="${MODULE_DIR}\DebugSupport.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\DebugSupport_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\DebugSupport_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**DebugSupport*"/>
+ </delete>
+ </target>
+</project> \ 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 <AutoGen.h>
+#include <DxeDepex.h>
+
+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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>DebugPort</BaseName>
+ <Guid>73E9457A-CEA1-4917-9A9C-9F1F0F0FD322</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Created>2006-03-12 17:09</Created>
+ <Modified>2006-03-19 15:19</Modified>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>UefiRuntimeServicesTableLib</Library>
+ <Library>UefiMemoryLib</Library>
+ <Library>UefiLib</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>UefiDriverModelLib</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Library>BaseDebugLibReportStatusCode</Library>
+ <Library>BaseLib</Library>
+ <Library>DxeMemoryAllocationLib</Library>
+ <Library>UefiDevicePathLib</Library>
+ </Libraries>
+ <BuildOptions ToolChain="MSFT">
+ <ImageEntryPoint>_ModuleEntryPoint</ImageEntryPoint>
+ </BuildOptions>
+</ModuleBuildDescription>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>DebugPort</BaseName>
+ <ModuleType>UEFI_DRIVER</ModuleType>
+ <ComponentType>BS_DRIVER</ComponentType>
+ <Guid>73E9457A-CEA1-4917-9A9C-9F1F0F0FD322</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for DiskIo module.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Specification>0</Specification>
+ <Created>2006-03-12 17:09</Created>
+ <Updated>2006-03-19 15:19</Updated>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverModelLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseMemoryLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">MemoryAllocationLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiRuntimeServicesTableLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DevicePathLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>DebugPort.h</Filename>
+ <Filename>DebugPort.c</Filename>
+ <Filename>ComponentName.c</Filename>
+ <Filename>DebugPort.dxs</Filename>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ <PackageName>EdkModulePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="BY_START">DebugPort</Protocol>
+ <Protocol Usage="BY_START">DevicePath</Protocol>
+ <Protocol Usage="TO_START">SerialIo</Protocol>
+ </Protocols>
+ <Variables>
+ <Variable Usage="SOMETIMES_CONSUMED">
+ <String>DEBUGPORT</String>
+ <Guid>0xEBA4E8D2, 0x3858, 0x41EC, 0xA2, 0x81, 0x26, 0x47, 0xBA, 0x96, 0x60, 0xD0</Guid>
+ </Variable>
+ </Variables>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint>InitializeDebugPortDriver</ModuleEntryPoint>
+ <ModuleUnloadImage>ImageUnloadHandler</ModuleUnloadImage>
+ </Extern>
+ <Extern>
+ <DriverBinding>gDebugPortDriverBinding</DriverBinding>
+ <ComponentName>gDebugPortComponentName</ComponentName>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
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 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="DebugPort"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\Debugger\Debugport\Dxe"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="DebugPort">
+ <GenBuild baseName="DebugPort" mbdFilename="${MODULE_DIR}\DebugPort.mbd" msaFilename="${MODULE_DIR}\DebugPort.msa"/>
+ </target>
+ <target depends="DebugPort_clean" name="clean"/>
+ <target depends="DebugPort_cleanall" name="cleanall"/>
+ <target name="DebugPort_clean">
+ <OutputDirSetup baseName="DebugPort" mbdFilename="${MODULE_DIR}\DebugPort.mbd" msaFilename="${MODULE_DIR}\DebugPort.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\DebugPort_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\DebugPort_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="DebugPort_cleanall">
+ <OutputDirSetup baseName="DebugPort" mbdFilename="${MODULE_DIR}\DebugPort.mbd" msaFilename="${MODULE_DIR}\DebugPort.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\DebugPort_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\DebugPort_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**DebugPort*"/>
+ </delete>
+ </target>
+</project> \ 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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>DiskIo</BaseName>
+ <Guid>6B38F7B4-AD98-40e9-9093-ACA2B5A253C4</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Created>2006-03-12 17:09</Created>
+ <Modified>2006-03-19 15:19</Modified>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>UefiMemoryLib</Library>
+ <Library>UefiLib</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>UefiDriverModelLib</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Library>BaseDebugLibReportStatusCode</Library>
+ <Library>BaseLib</Library>
+ <Library>DxeMemoryAllocationLib</Library>
+ </Libraries>
+</ModuleBuildDescription>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>DiskIo</BaseName>
+ <ModuleType>UEFI_DRIVER</ModuleType>
+ <ComponentType>BS_DRIVER</ComponentType>
+ <Guid>6B38F7B4-AD98-40e9-9093-ACA2B5A253C4</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for DiskIo module.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Specification>0</Specification>
+ <Created>2006-03-12 17:09</Created>
+ <Updated>2006-03-19 15:19</Updated>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverModelLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseMemoryLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">MemoryAllocationLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>diskio.c</Filename>
+ <Filename>diskio.h</Filename>
+ <Filename>ComponentName.c</Filename>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="TO_START">BlockIo</Protocol>
+ <Protocol Usage="BY_START">DiskIo</Protocol>
+ </Protocols>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint></ModuleEntryPoint>
+ </Extern>
+ <Extern>
+ <DriverBinding>gDiskIoDriverBinding</DriverBinding>
+ <ComponentName>gDiskIoComponentName</ComponentName>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
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 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="DiskIo"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\Disk\DiskIo\Dxe"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="DiskIo">
+ <GenBuild baseName="DiskIo" mbdFilename="${MODULE_DIR}\DiskIo.mbd" msaFilename="${MODULE_DIR}\DiskIo.msa"/>
+ </target>
+ <target depends="DiskIo_clean" name="clean"/>
+ <target depends="DiskIo_cleanall" name="cleanall"/>
+ <target name="DiskIo_clean">
+ <OutputDirSetup baseName="DiskIo" mbdFilename="${MODULE_DIR}\DiskIo.mbd" msaFilename="${MODULE_DIR}\DiskIo.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\DiskIo_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\DiskIo_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="DiskIo_cleanall">
+ <OutputDirSetup baseName="DiskIo" mbdFilename="${MODULE_DIR}\DiskIo.mbd" msaFilename="${MODULE_DIR}\DiskIo.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\DiskIo_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\DiskIo_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**DiskIo*"/>
+ </delete>
+ </target>
+</project> \ 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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>DiskIoPartition</BaseName>
+ <Guid>854E153A-8AC8-40f4-A5A9-4C51F18CFB1B</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Created>2006-03-12 17:09</Created>
+ <Modified>2006-03-19 15:19</Modified>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>BaseLib</Library>
+ <Library>UefiMemoryLib</Library>
+ <Library>UefiLib</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>UefiDriverModelLib</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Library>BaseDebugLibReportStatusCode</Library>
+ <Library>DxeMemoryAllocationLib</Library>
+ <Library>UefiDevicePathLib</Library>
+ </Libraries>
+</ModuleBuildDescription>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>DiskIoPartition</BaseName>
+ <ModuleType>UEFI_DRIVER</ModuleType>
+ <ComponentType>BS_DRIVER</ComponentType>
+ <Guid>854E153A-8AC8-40f4-A5A9-4C51F18CFB1B</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for DiskIo module.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Specification>0</Specification>
+ <Created>2006-03-12 17:09</Created>
+ <Updated>2006-03-19 15:19</Updated>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverModelLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseMemoryLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">MemoryAllocationLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DevicePathLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>..\..\DiskIo\Dxe\diskio.c</Filename>
+ <Filename>..\..\DiskIo\Dxe\diskio.h</Filename>
+ <Filename>..\..\DiskIo\Dxe\ComponentName.c</Filename>
+ <Filename>..\..\Partition\Dxe\Partition.h</Filename>
+ <Filename>..\..\Partition\Dxe\ElTorito.h</Filename>
+ <Filename>..\..\Partition\Dxe\Gpt.h</Filename>
+ <Filename>..\..\Partition\Dxe\Mbr.h</Filename>
+ <Filename>..\..\Partition\Dxe\Partition.c</Filename>
+ <Filename>..\..\Partition\Dxe\Eltorito.c</Filename>
+ <Filename>..\..\Partition\Dxe\Gpt.c</Filename>
+ <Filename>..\..\Partition\Dxe\Mbr.c</Filename>
+ <Filename>..\..\Partition\Dxe\ComponentName.c</Filename>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="TO_START">BlockIo</Protocol>
+ <Protocol Usage="TO_START">DiskIo</Protocol>
+ <Protocol Usage="TO_START">DevicePath</Protocol>
+ </Protocols>
+ <Guids>
+ <GuidEntry Usage="SOMETIMES_CONSUMED">
+ <C_Name>PartTypeSystemPart</C_Name>
+ </GuidEntry>
+ <GuidEntry Usage="ALWAYS_CONSUMED">
+ <C_Name>PartTypeUnused</C_Name>
+ </GuidEntry>
+ </Guids>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint></ModuleEntryPoint>
+ </Extern>
+ <Extern>
+ <DriverBinding>gPartitionDriverBinding</DriverBinding>
+ <ComponentName>gPartitionComponentName</ComponentName>
+ </Extern>
+ <Extern>
+ <DriverBinding>gDiskIoDriverBinding</DriverBinding>
+ <ComponentName>gDiskIoComponentName</ComponentName>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
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 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="DiskIoPartition"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\Disk\DiskIoPartition\dxe"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="DiskIoPartition">
+ <GenBuild baseName="DiskIoPartition" mbdFilename="${MODULE_DIR}\DiskIoPartition.mbd" msaFilename="${MODULE_DIR}\DiskIoPartition.msa"/>
+ </target>
+ <target depends="DiskIoPartition_clean" name="clean"/>
+ <target depends="DiskIoPartition_cleanall" name="cleanall"/>
+ <target name="DiskIoPartition_clean">
+ <OutputDirSetup baseName="DiskIoPartition" mbdFilename="${MODULE_DIR}\DiskIoPartition.mbd" msaFilename="${MODULE_DIR}\DiskIoPartition.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\DiskIoPartition_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\DiskIoPartition_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="DiskIoPartition_cleanall">
+ <OutputDirSetup baseName="DiskIoPartition" mbdFilename="${MODULE_DIR}\DiskIoPartition.mbd" msaFilename="${MODULE_DIR}\DiskIoPartition.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\DiskIoPartition_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\DiskIoPartition_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**DiskIoPartition*"/>
+ </delete>
+ </target>
+</project> \ 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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>Partition</BaseName>
+ <Guid>1FA1F39E-FEFF-4aae-BD7B-38A070A3B609</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Created>2006-03-12 17:09</Created>
+ <Modified>2006-03-19 15:19</Modified>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>BaseLib</Library>
+ <Library>UefiMemoryLib</Library>
+ <Library>UefiLib</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>UefiDriverModelLib</Library>
+ <Library>DxeMemoryAllocationLib</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Library>BaseDebugLibReportStatusCode</Library>
+ <Library>UefiDevicePathLib</Library>
+ </Libraries>
+</ModuleBuildDescription>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>Partition</BaseName>
+ <ModuleType>UEFI_DRIVER</ModuleType>
+ <ComponentType>BS_DRIVER</ComponentType>
+ <Guid>1FA1F39E-FEFF-4aae-BD7B-38A070A3B609</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for Partition module.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Specification>0</Specification>
+ <Created>2006-03-12 17:09</Created>
+ <Updated>2006-03-19 15:19</Updated>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverModelLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseMemoryLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">MemoryAllocationLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DevicePathLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>Partition.h</Filename>
+ <Filename>ElTorito.h</Filename>
+ <Filename>Gpt.h</Filename>
+ <Filename>Mbr.h</Filename>
+ <Filename>Partition.c</Filename>
+ <Filename>Eltorito.c</Filename>
+ <Filename>Gpt.c</Filename>
+ <Filename>Mbr.c</Filename>
+ <Filename>ComponentName.c</Filename>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="TO_START">BlockIo</Protocol>
+ <Protocol Usage="TO_START">DiskIo</Protocol>
+ <Protocol Usage="TO_START">DevicePath</Protocol>
+ </Protocols>
+ <Guids>
+ <GuidEntry Usage="SOMETIMES_CONSUMED">
+ <C_Name>PartTypeSystemPart</C_Name>
+ </GuidEntry>
+ <GuidEntry Usage="ALWAYS_CONSUMED">
+ <C_Name>PartTypeUnused</C_Name>
+ </GuidEntry>
+ </Guids>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint></ModuleEntryPoint>
+ </Extern>
+ <Extern>
+ <DriverBinding>gPartitionDriverBinding</DriverBinding>
+ <ComponentName>gPartitionComponentName</ComponentName>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
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 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="Partition"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\Disk\Partition\Dxe"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="Partition">
+ <GenBuild baseName="Partition" mbdFilename="${MODULE_DIR}\Partition.mbd" msaFilename="${MODULE_DIR}\Partition.msa"/>
+ </target>
+ <target depends="Partition_clean" name="clean"/>
+ <target depends="Partition_cleanall" name="cleanall"/>
+ <target name="Partition_clean">
+ <OutputDirSetup baseName="Partition" mbdFilename="${MODULE_DIR}\Partition.mbd" msaFilename="${MODULE_DIR}\Partition.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\Partition_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\Partition_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="Partition_cleanall">
+ <OutputDirSetup baseName="Partition" mbdFilename="${MODULE_DIR}\Partition.mbd" msaFilename="${MODULE_DIR}\Partition.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\Partition_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\Partition_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**Partition*"/>
+ </delete>
+ </target>
+</project> \ 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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>English</BaseName>
+ <Guid>CD3BAFB6-50FB-4fe8-8E4E-AB74D2C1A600</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Created>2006-03-12 17:09</Created>
+ <Modified>2006-03-19 15:19</Modified>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>BaseLib</Library>
+ <Library>UefiMemoryLib</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Library>BaseDebugLibReportStatusCode</Library>
+ </Libraries>
+</ModuleBuildDescription>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>English</BaseName>
+ <ModuleType>UEFI_DRIVER</ModuleType>
+ <ComponentType>BS_DRIVER</ComponentType>
+ <Guid>CD3BAFB6-50FB-4fe8-8E4E-AB74D2C1A600</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for English module for unicode collation.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Specification>0</Specification>
+ <Created>2006-03-12 17:09</Created>
+ <Updated>2006-03-19 15:19</Updated>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>UnicodeCollationEng.c</Filename>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="ALWAYS_PRODUCED">UnicodeCollation</Protocol>
+ </Protocols>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint>InitializeUnicodeCollationEng</ModuleEntryPoint>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
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 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="English"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\Disk\UnicodeCollation\English\Dxe"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="English">
+ <GenBuild baseName="English" mbdFilename="${MODULE_DIR}\English.mbd" msaFilename="${MODULE_DIR}\English.msa"/>
+ </target>
+ <target depends="English_clean" name="clean"/>
+ <target depends="English_cleanall" name="cleanall"/>
+ <target name="English_clean">
+ <OutputDirSetup baseName="English" mbdFilename="${MODULE_DIR}\English.mbd" msaFilename="${MODULE_DIR}\English.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\English_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\English_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="English_cleanall">
+ <OutputDirSetup baseName="English" mbdFilename="${MODULE_DIR}\English.mbd" msaFilename="${MODULE_DIR}\English.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\English_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\English_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**English*"/>
+ </delete>
+ </target>
+</project> \ 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 <AutoGen.h>
+#include <DxeDepex.h>
+
+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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>Ebc</BaseName>
+ <Guid>13AC6DD0-73D0-11D4-B06B-00AA00BD6DE7</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Created>2006-03-22 14:03</Created>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>BaseLib</Library>
+ <Library>UefiMemoryLib</Library>
+ <Library>UefiLib</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Library>BaseDebugLibReportStatusCode</Library>
+ <Library>EdkDxePrintLib</Library>
+ <Library>DxeMemoryAllocationLib</Library>
+ </Libraries>
+ <BuildOptions ToolChain="MSFT">
+ <ImageEntryPoint>_ModuleEntryPoint</ImageEntryPoint>
+ </BuildOptions>
+</ModuleBuildDescription>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>Ebc</BaseName>
+ <ModuleType>DXE_DRIVER</ModuleType>
+ <ComponentType>BS_DRIVER</ComponentType>
+ <Guid>13AC6DD0-73D0-11D4-B06B-00AA00BD6DE7</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for DiskIo module.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Specification>0</Specification>
+ <Created>2006-03-12 17:09</Created>
+ <Updated>2006-03-22 15:19</Updated>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">ReportStatusCodeLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseMemoryLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">MemoryAllocationLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>EbcInt.c</Filename>
+ <Filename>EbcInt.h</Filename>
+ <Filename>EbcExecute.c</Filename>
+ <Filename>EbcExecute.h</Filename>
+ <Filename>Ebc.dxs</Filename>
+ <Arch ArchType="IA32">
+ <Filename>Ia32\EbcLowLevel.asm</Filename>
+ <Filename>Ia32\Ia32Math.asm</Filename>
+ <Filename>Ia32\EbcSupport.c</Filename>
+ </Arch>
+ <Arch ArchType="X64">
+ <Filename>x64\EbcLowLevel.asm</Filename>
+ <Filename>x64\x64Math.c</Filename>
+ <Filename>x64\EbcSupport.c</Filename>
+ </Arch>
+ <Arch ArchType="IPF">
+ <Filename>Ipf\EbcLowLevel.s</Filename>
+ <Filename>Ipf\IpfMath.c</Filename>
+ <Filename>Ipf\IpfMul.s</Filename>
+ <Filename>Ipf\EbcSupport.c</Filename>
+ </Arch>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ <PackageName>EdkModulePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="ALWAYS_PRODUCED">Ebc</Protocol>
+ <Protocol Usage="ALWAYS_PRODUCED">DebugSupport</Protocol>
+ </Protocols>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint>InitializeEbcDriver</ModuleEntryPoint>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
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 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="Ebc"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\Ebc\Dxe"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="Ebc">
+ <GenBuild baseName="Ebc" mbdFilename="${MODULE_DIR}\Ebc.mbd" msaFilename="${MODULE_DIR}\Ebc.msa"/>
+ </target>
+ <target depends="Ebc_clean" name="clean"/>
+ <target depends="Ebc_cleanall" name="cleanall"/>
+ <target name="Ebc_clean">
+ <OutputDirSetup baseName="Ebc" mbdFilename="${MODULE_DIR}\Ebc.mbd" msaFilename="${MODULE_DIR}\Ebc.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\Ebc_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\Ebc_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="Ebc_cleanall">
+ <OutputDirSetup baseName="Ebc" mbdFilename="${MODULE_DIR}\Ebc.mbd" msaFilename="${MODULE_DIR}\Ebc.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\Ebc_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\Ebc_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**Ebc*"/>
+ </delete>
+ </target>
+</project> \ 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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>EmuVariable</BaseName>
+ <Guid>CBD2E4D5-7068-4FF5-B866-9822B4AD8D60</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Created>2006-03-23 16:05</Created>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>BaseMemoryLib</Library>
+ <Library>BaseDebugLibReportStatusCode</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>EdkDxeRuntimeDriverLib</Library>
+ <Library>DxeMemoryAllocationLib</Library>
+ <Library>BaseLib</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Arch ArchType="IPF">
+ <Library>EdkDxeSalLib</Library>
+ </Arch>
+ </Libraries>
+ <BuildOptions ToolChain="MSFT">
+ <ImageEntryPoint>_ModuleEntryPoint</ImageEntryPoint>
+ </BuildOptions>
+</ModuleBuildDescription>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>EmuVariable</BaseName>
+ <ModuleType>DXE_RUNTIME_DRIVER</ModuleType>
+ <ComponentType>RT_DRIVER</ComponentType>
+ <Guid>CBD2E4D5-7068-4FF5-B866-9822B4AD8D60</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for DiskIo module.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Specification>0</Specification>
+ <Created>2006-03-23 16:05</Created>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseMemoryLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">MemoryAllocationLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DxeRuntimeDriverLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">EdkDxeSalLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>EmuVariable.c</Filename>
+ <Filename>EmuVariable.dxs</Filename>
+ <Arch ArchType="IA32">
+ <Filename>InitVariable.c</Filename>
+ </Arch>
+ <Arch ArchType="X64">
+ <Filename>InitVariable.c</Filename>
+ </Arch>
+ <Arch ArchType="EBC">
+ <Filename>InitVariable.c</Filename>
+ </Arch>
+ <Arch ArchType="IPF">
+ <Filename>Ipf\InitVariable.c</Filename>
+ </Arch>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ <PackageName>EdkModulePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="ALWAYS_CONSUMED">VariableWrite</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">Variable</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">VariableWrite</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">Variable</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">ExtendedSalVariableServices</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">ExtendedSalBootService</Protocol>
+ </Protocols>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint>VariableServiceInitialize</ModuleEntryPoint>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
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 <Common/Variable.h>
+
+#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 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="EmuVariable"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\EmuVariable\RuntimeDxe"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="EmuVariable">
+ <GenBuild baseName="EmuVariable" mbdFilename="${MODULE_DIR}\EmuVariable.mbd" msaFilename="${MODULE_DIR}\EmuVariable.msa"/>
+ </target>
+ <target depends="EmuVariable_clean" name="clean"/>
+ <target depends="EmuVariable_cleanall" name="cleanall"/>
+ <target name="EmuVariable_clean">
+ <OutputDirSetup baseName="EmuVariable" mbdFilename="${MODULE_DIR}\EmuVariable.mbd" msaFilename="${MODULE_DIR}\EmuVariable.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\EmuVariable_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\EmuVariable_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="EmuVariable_cleanall">
+ <OutputDirSetup baseName="EmuVariable" mbdFilename="${MODULE_DIR}\EmuVariable.mbd" msaFilename="${MODULE_DIR}\EmuVariable.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\EmuVariable_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\EmuVariable_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**EmuVariable*"/>
+ </delete>
+ </target>
+</project> \ 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 <FtwLite.h>
+
+//
+// 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 <AutoGen.h>
+#include <DxeDepex.h>
+
+
+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 <Common/FlashMap.h>
+#include <Common/WorkingBlockHeader.h>
+
+#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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>FtwLite</BaseName>
+ <Guid>4C862FC6-0E54-4e36-8C8F-FF6F3167951F</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Created>2006-03-22 14:11</Created>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>BaseLib</Library>
+ <Library>UefiMemoryLib</Library>
+ <Library>DxeHobLib</Library>
+ <Library>UefiLib</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Library>BaseDebugLibReportStatusCode</Library>
+ <Library>EdkDxePrintLib</Library>
+ <Library>DxeMemoryAllocationLib</Library>
+ </Libraries>
+ <BuildOptions ToolChain="MSFT">
+ <ImageEntryPoint>_ModuleEntryPoint</ImageEntryPoint>
+ </BuildOptions>
+</ModuleBuildDescription>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>FtwLite</BaseName>
+ <ModuleType>DXE_DRIVER</ModuleType>
+ <ComponentType>BS_DRIVER</ComponentType>
+ <Guid>4C862FC6-0E54-4e36-8C8F-FF6F3167951F</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for DiskIo module.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Specification>0</Specification>
+ <Created>2006-03-22 14:11</Created>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">HobLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseMemoryLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">MemoryAllocationLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>FtwLite.c</Filename>
+ <Filename>FtwMisc.c</Filename>
+ <Filename>FtwWorkSpace.c</Filename>
+ <Filename>FtwLite.dxs</Filename>
+ <Arch ArchType="IA32">
+ <Filename>ia32\Ia32FtwMisc.c</Filename>
+ </Arch>
+ <Arch ArchType="X64">
+ <Filename>x64\x64FtwMisc.c</Filename>
+ </Arch>
+ <Arch ArchType="IPF">
+ <Filename>Ipf\IpfFtwMisc.c</Filename>
+ </Arch>
+ <Arch ArchType="EBC">
+ <Filename>ia32\Ia32FtwMisc.c</Filename>
+ </Arch>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ <PackageName>EdkModulePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="ALWAYS_PRODUCED">FaultTolerantWriteLite</Protocol>
+ <Protocol Usage="SOMETIMES_CONSUMED">PciRootBridgeIo</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">FirmwareVolumeBlock</Protocol>
+ </Protocols>
+ <Hobs>
+ <Hob Usage="ALWAYS_CONSUMED" HobType="GUID_EXTENSION">
+ <Name>FlashMapHob</Name>
+ <C_Name>gEfiFlashMapHobGuid</C_Name>
+ <Guid>0xb091e7d2, 0x5a0, 0x4198, 0x94, 0xf0, 0x74, 0xb7, 0xb8, 0xc5, 0x54, 0x59</Guid>
+ </Hob>
+ </Hobs>
+ <Guids>
+ <GuidEntry Usage="ALWAYS_CONSUMED">
+ <C_Name>FlashMapHob</C_Name>
+ </GuidEntry>
+ <GuidEntry Usage="ALWAYS_CONSUMED">
+ <C_Name>SystemNvDataFv</C_Name>
+ </GuidEntry>
+ </Guids>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint>InitializeFtwLite</ModuleEntryPoint>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
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 <FtwLite.h>
+
+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 <FtwLite.h>
+
+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 <FtwLite.h>
+
+//
+// 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 <FtwLite.h>
+
+//
+// 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 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="FtwLite"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\FirmwareVolume\FaultTolerantWriteLite\Dxe"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="FtwLite">
+ <GenBuild baseName="FtwLite" mbdFilename="${MODULE_DIR}\FtwLite.mbd" msaFilename="${MODULE_DIR}\FtwLite.msa"/>
+ </target>
+ <target depends="FtwLite_clean" name="clean"/>
+ <target depends="FtwLite_cleanall" name="cleanall"/>
+ <target name="FtwLite_clean">
+ <OutputDirSetup baseName="FtwLite" mbdFilename="${MODULE_DIR}\FtwLite.mbd" msaFilename="${MODULE_DIR}\FtwLite.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\FtwLite_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\FtwLite_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="FtwLite_cleanall">
+ <OutputDirSetup baseName="FtwLite" mbdFilename="${MODULE_DIR}\FtwLite.mbd" msaFilename="${MODULE_DIR}\FtwLite.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\FtwLite_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\FtwLite_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**FtwLite*"/>
+ </delete>
+ </target>
+</project> \ 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 <FtwLite.h>
+
+//
+// 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 <GuidedSection.h>
+#include <Crc32SectionExtract.h>
+
+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 <AutoGen.h>
+#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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>Crc32SectionExtract</BaseName>
+ <Guid>51C9F40C-5243-4473-B265-B3C8FFAFF9FA</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Created>2006-03-12 17:09</Created>
+ <Modified>2006-03-19 15:19</Modified>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>UefiMemoryLib</Library>
+ <Library>UefiLib</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Library>BaseDebugLibReportStatusCode</Library>
+ <Library>EdkDxePrintLib</Library>
+ <Library>BaseLib</Library>
+ </Libraries>
+</ModuleBuildDescription>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>Crc32SectionExtract</BaseName>
+ <ModuleType>DXE_DRIVER</ModuleType>
+ <ComponentType>BS_DRIVER</ComponentType>
+ <Guid>51C9F40C-5243-4473-B265-B3C8FFAFF9FA</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for DiskIo module.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Specification>0</Specification>
+ <Created>2006-03-12 17:09</Created>
+ <Updated>2006-03-19 15:19</Updated>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseMemoryLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>Crc32SectionExtract.c</Filename>
+ <Filename>Crc32SectionExtract.h</Filename>
+ <Filename>GuidedSection.c</Filename>
+ <Filename>GuidedSection.h</Filename>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ <PackageName>EdkModulePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="ALWAYS_CONSUMED">SecurityPolicy</Protocol>
+ <Protocol Usage="ALWAYS_PRODUCED">Crc32GuidedSectionExtraction</Protocol>
+ </Protocols>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint>InitializeCrc32GuidedSectionExtractionProtocol</ModuleEntryPoint>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
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 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="Crc32SectionExtract"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\FirmwareVolume\GuidedSectionExtraction\Crc32SectionExtract\Dxe"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="Crc32SectionExtract">
+ <GenBuild baseName="Crc32SectionExtract" mbdFilename="${MODULE_DIR}\Crc32SectionExtract.mbd" msaFilename="${MODULE_DIR}\Crc32SectionExtract.msa"/>
+ </target>
+ <target depends="Crc32SectionExtract_clean" name="clean"/>
+ <target depends="Crc32SectionExtract_cleanall" name="cleanall"/>
+ <target name="Crc32SectionExtract_clean">
+ <OutputDirSetup baseName="Crc32SectionExtract" mbdFilename="${MODULE_DIR}\Crc32SectionExtract.mbd" msaFilename="${MODULE_DIR}\Crc32SectionExtract.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\Crc32SectionExtract_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\Crc32SectionExtract_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="Crc32SectionExtract_cleanall">
+ <OutputDirSetup baseName="Crc32SectionExtract" mbdFilename="${MODULE_DIR}\Crc32SectionExtract.mbd" msaFilename="${MODULE_DIR}\Crc32SectionExtract.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\Crc32SectionExtract_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\Crc32SectionExtract_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**Crc32SectionExtract*"/>
+ </delete>
+ </target>
+</project> \ 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 <AutoGen.h>
+#include <DxeDepex.h>
+
+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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>NullMemoryTest</BaseName>
+ <Guid>96B5C032-DF4C-4b6e-8232-438DCF448D0E</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Created>2006-03-12 17:09</Created>
+ <Modified>2006-03-19 15:19</Modified>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>BaseLib</Library>
+ <Library>UefiMemoryLib</Library>
+ <Library>UefiLib</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>DxeServicesTableLib</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Library>BaseDebugLibReportStatusCode</Library>
+ <Library>DxeMemoryAllocationLib</Library>
+ </Libraries>
+ <BuildOptions ToolChain="MSFT">
+ <ImageEntryPoint>_ModuleEntryPoint</ImageEntryPoint>
+ </BuildOptions>
+</ModuleBuildDescription>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>NullMemoryTest</BaseName>
+ <ModuleType>DXE_DRIVER</ModuleType>
+ <ComponentType>BS_DRIVER</ComponentType>
+ <Guid>96B5C032-DF4C-4b6e-8232-438DCF448D0E</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for DiskIo module.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Specification>0</Specification>
+ <Created>2006-03-12 17:09</Created>
+ <Updated>2006-03-19 15:19</Updated>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DxeServicesTableLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">MemoryAllocationLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>Common.h</Filename>
+ <Filename>NullMemoryTest.c</Filename>
+ <Filename>NullMemoryTest.h</Filename>
+ <Filename>NullMemoryTest.dxs</Filename>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ <PackageName>EdkModulePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="ALWAYS_PRODUCED">GenericMemTest</Protocol>
+ </Protocols>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint>GenericMemoryTestEntryPoint</ModuleEntryPoint>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
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 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="NullMemoryTest"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\GenericMemoryTest\Dxe"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="NullMemoryTest">
+ <GenBuild baseName="NullMemoryTest" mbdFilename="${MODULE_DIR}\NullMemoryTest.mbd" msaFilename="${MODULE_DIR}\NullMemoryTest.msa"/>
+ </target>
+ <target depends="NullMemoryTest_clean" name="clean"/>
+ <target depends="NullMemoryTest_cleanall" name="cleanall"/>
+ <target name="NullMemoryTest_clean">
+ <OutputDirSetup baseName="NullMemoryTest" mbdFilename="${MODULE_DIR}\NullMemoryTest.mbd" msaFilename="${MODULE_DIR}\NullMemoryTest.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\NullMemoryTest_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\NullMemoryTest_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="NullMemoryTest_cleanall">
+ <OutputDirSetup baseName="NullMemoryTest" mbdFilename="${MODULE_DIR}\NullMemoryTest.mbd" msaFilename="${MODULE_DIR}\NullMemoryTest.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\NullMemoryTest_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\NullMemoryTest_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**NullMemoryTest*"/>
+ </delete>
+ </target>
+</project> \ 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 <BaseMemoryTest.h>
+#include <Library/ReportStatusCodeLib.h>
+
+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 <EdkPeim.h>
+
+//
+// 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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>PeiBaseMemoryTestInit</BaseName>
+ <Guid>736EB068-8C01-47c5-964B-1C57BD5D4D64</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Created>2006-03-12 17:09</Created>
+ <Modified>2006-03-19 15:19</Modified>
+ </MbdHeader>
+ <Libraries>
+ <Library>PeimEntryPoint</Library>
+ <Library>PeiReportStatusCodeLib</Library>
+ <Library>BaseDebugLibReportStatusCode</Library>
+ <Library>PeiServicesTablePointerLib</Library>
+ <Library>PeiMemoryLib</Library>
+ <Library>PeiCoreLib</Library>
+ <Library>BaseLib</Library>
+ </Libraries>
+</ModuleBuildDescription>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>PeiBaseMemoryTestInit</BaseName>
+ <ModuleType>PEIM</ModuleType>
+ <ComponentType>PE32_PEIM</ComponentType>
+ <Guid>736EB068-8C01-47c5-964B-1C57BD5D4D64</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for DiskIo module.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Specification>0</Specification>
+ <Created>2006-03-12 17:09</Created>
+ <Updated>2006-03-19 15:19</Updated>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">PeimEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">PeiCoreLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>BaseMemoryTest.c</Filename>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ <PackageName>EdkModulePkg</PackageName>
+ </Includes>
+ <PPIs>
+ <Ppi Usage="ALWAYS_PRODUCED">BaseMemoryTest</Ppi>
+ </PPIs>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint>PeiBaseMemoryTestInit</ModuleEntryPoint>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
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 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="PeiBaseMemoryTestInit"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\GenericMemoryTest\Pei"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="PeiBaseMemoryTestInit">
+ <GenBuild baseName="PeiBaseMemoryTestInit" mbdFilename="${MODULE_DIR}\BaseMemoryTest.mbd" msaFilename="${MODULE_DIR}\BaseMemoryTest.msa"/>
+ </target>
+ <target depends="PeiBaseMemoryTestInit_clean" name="clean"/>
+ <target depends="PeiBaseMemoryTestInit_cleanall" name="cleanall"/>
+ <target name="PeiBaseMemoryTestInit_clean">
+ <OutputDirSetup baseName="PeiBaseMemoryTestInit" mbdFilename="${MODULE_DIR}\BaseMemoryTest.mbd" msaFilename="${MODULE_DIR}\BaseMemoryTest.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\PeiBaseMemoryTestInit_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\PeiBaseMemoryTestInit_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="PeiBaseMemoryTestInit_cleanall">
+ <OutputDirSetup baseName="PeiBaseMemoryTestInit" mbdFilename="${MODULE_DIR}\BaseMemoryTest.mbd" msaFilename="${MODULE_DIR}\BaseMemoryTest.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\PeiBaseMemoryTestInit_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\PeiBaseMemoryTestInit_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**PeiBaseMemoryTestInit*"/>
+ </delete>
+ </target>
+</project> \ 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 <AutoGen.h>
+#include <DxeDepex.h>
+
+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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>MonotonicCounter</BaseName>
+ <Guid>AD608272-D07F-4964-801E-7BD3B7888652</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Created>2006-03-22 14:36</Created>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>UefiRuntimeServicesTableLib</Library>
+ <Library>BaseLib</Library>
+ <Library>BaseMemoryLib</Library>
+ <Library>UefiLib</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Library>BaseDebugLibReportStatusCode</Library>
+ <Library>DxeMemoryAllocationLib</Library>
+ <Library>EdkDxeRuntimeDriverLib</Library>
+ <Arch ArchType="IPF">
+ <Library>EdkDxeSalLib</Library>
+ </Arch>
+ </Libraries>
+ <BuildOptions ToolChain="MSFT">
+ <ImageEntryPoint>_ModuleEntryPoint</ImageEntryPoint>
+ </BuildOptions>
+</ModuleBuildDescription>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>MonotonicCounter</BaseName>
+ <ModuleType>DXE_RUNTIME_DRIVER</ModuleType>
+ <ComponentType>RT_DRIVER</ComponentType>
+ <Guid>AD608272-D07F-4964-801E-7BD3B7888652</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for DiskIo module.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Specification>0</Specification>
+ <Created>2006-03-22 14:36</Created>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DxeRuntimeDriverLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">MemoryAllocationLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiRuntimeServicesTableLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>MonotonicCounter.c</Filename>
+ <Filename>MonotonicCounter.h</Filename>
+ <Filename>MonotonicCounter.dxs</Filename>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ <PackageName>EdkModulePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="ALWAYS_PRODUCED">MonotonicCounter</Protocol>
+ </Protocols>
+ <Variables>
+ <Variable Usage="PRIVATE">
+ <String>MTC</String>
+ <Guid>0xeb704011, 0x1402, 0x11d3, 0x8e, 0x77, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b</Guid>
+ </Variable>
+ </Variables>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint>MonotonicCounterDriverInitialize</ModuleEntryPoint>
+ </Extern>
+ <Extern>
+ <SetVirtualAddressMapCallBack></SetVirtualAddressMapCallBack>
+ <ExitBootServicesCallBack></ExitBootServicesCallBack>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
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 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="MonotonicCounter"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\MonotonicCounter\RuntimeDxe"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="MonotonicCounter">
+ <GenBuild baseName="MonotonicCounter" mbdFilename="${MODULE_DIR}\MonotonicCounter.mbd" msaFilename="${MODULE_DIR}\MonotonicCounter.msa"/>
+ </target>
+ <target depends="MonotonicCounter_clean" name="clean"/>
+ <target depends="MonotonicCounter_cleanall" name="cleanall"/>
+ <target name="MonotonicCounter_clean">
+ <OutputDirSetup baseName="MonotonicCounter" mbdFilename="${MODULE_DIR}\MonotonicCounter.mbd" msaFilename="${MODULE_DIR}\MonotonicCounter.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\MonotonicCounter_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\MonotonicCounter_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="MonotonicCounter_cleanall">
+ <OutputDirSetup baseName="MonotonicCounter" mbdFilename="${MODULE_DIR}\MonotonicCounter.mbd" msaFilename="${MODULE_DIR}\MonotonicCounter.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\MonotonicCounter_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\MonotonicCounter_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**MonotonicCounter*"/>
+ </delete>
+ </target>
+</project> \ 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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>BC</BaseName>
+ <Guid>A3f436EA-A127-4EF8-957C-8048606FF670</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Created>2006-03-12 17:09</Created>
+ <Modified>2006-03-19 15:19</Modified>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>UefiMemoryLib</Library>
+ <Library>UefiLib</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>UefiDriverModelLib</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Library>BaseDebugLibReportStatusCode</Library>
+ <Library>EdkDxePrintLib</Library>
+ <Library>BaseLib</Library>
+ <Library>DxeMemoryAllocationLib</Library>
+ </Libraries>
+</ModuleBuildDescription>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>BC</BaseName>
+ <ModuleType>UEFI_DRIVER</ModuleType>
+ <ComponentType>BS_DRIVER</ComponentType>
+ <Guid>A3f436EA-A127-4EF8-957C-8048606FF670</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for DiskIo module.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Specification>0</Specification>
+ <Created>2006-03-12 17:09</Created>
+ <Updated>2006-03-19 15:19</Updated>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverModelLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">PrintLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseMemoryLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">MemoryAllocationLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>bc.c</Filename>
+ <Filename>pxe_bc_arp.c</Filename>
+ <Filename>pxe_bc_dhcp.c</Filename>
+ <Filename>pxe_bc_igmp.c</Filename>
+ <Filename>pxe_bc_ip.c</Filename>
+ <Filename>pxe_bc_mtftp.c</Filename>
+ <Filename>pxe_bc_udp.c</Filename>
+ <Filename>pxe_loadfile.c</Filename>
+ <Filename>dhcp.h</Filename>
+ <Filename>bc.h</Filename>
+ <Filename>ip.h</Filename>
+ <Filename>ComponentName.c</Filename>
+ <Filename>Print.c</Filename>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ <PackageName>EdkModulePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="TO_START">Bis</Protocol>
+ <Protocol Usage="BY_START">LoadFile</Protocol>
+ <Protocol Usage="SOMETIMES_PRODUCED">PxeBaseCodeCallBack</Protocol>
+ <Protocol Usage="TO_START">SimpleNetwork</Protocol>
+ <Protocol Usage="TO_START">DevicePath</Protocol>
+ <Protocol Usage="SOMETIMES_CONSUMED">NetworkInterfaceIdentifier</Protocol>
+ <Protocol Usage="SOMETIMES_CONSUMED">NetworkInterfaceIdentifier2</Protocol>
+ <Protocol Usage="BY_START">PxeBaseCode</Protocol>
+ </Protocols>
+ <SystemTables>
+ <SystemTable Usage="SOMETIMES_CONSUMED">
+ <Entry>gEfiSmbiosTableGuid</Entry>
+ </SystemTable>
+ </SystemTables>
+ <Guids>
+ <GuidEntry Usage="ALWAYS_CONSUMED">
+ <C_Name>SmbiosTable</C_Name>
+ </GuidEntry>
+ </Guids>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint>InitializeBCDriver</ModuleEntryPoint>
+ <ModuleUnloadImage></ModuleUnloadImage>
+ </Extern>
+ <Extern>
+ <DriverBinding>gPxeBcDriverBinding</DriverBinding>
+ <ComponentName>gPxeBcComponentName</ComponentName>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
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 <Bc.h>
+
+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 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="BC"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\Network\PxeBc\Dxe"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="BC">
+ <GenBuild baseName="BC" mbdFilename="${MODULE_DIR}\BC.mbd" msaFilename="${MODULE_DIR}\BC.msa"/>
+ </target>
+ <target depends="BC_clean" name="clean"/>
+ <target depends="BC_cleanall" name="cleanall"/>
+ <target name="BC_clean">
+ <OutputDirSetup baseName="BC" mbdFilename="${MODULE_DIR}\BC.mbd" msaFilename="${MODULE_DIR}\BC.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\BC_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\BC_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="BC_cleanall">
+ <OutputDirSetup baseName="BC" mbdFilename="${MODULE_DIR}\BC.mbd" msaFilename="${MODULE_DIR}\BC.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\BC_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\BC_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**BC*"/>
+ </delete>
+ </target>
+</project> \ 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<<VEND_PXE_MTFTP_IP_IX) | \
+ (1<<VEND_PXE_MTFTP_CPORT_IX) | \
+ (1<<VEND_PXE_MTFTP_SPORT_IX) | \
+ (1<<VEND_PXE_MTFTP_TMOUT_IX) | \
+ (1<<VEND_PXE_MTFTP_DELAY_IX))
+
+#define DISCOVER_OPTS ((1<<VEND_PXE_DISCOVERY_CONTROL_IX) | \
+ (1<<VEND_PXE_DISCOVERY_MCAST_ADDR_IX) | \
+ (1<<VEND_PXE_BOOT_SERVERS_IX) | \
+ (1<<VEND_PXE_BOOT_MENU_IX) | \
+ (1<<VEND_PXE_BOOT_PROMPT_IX) | \
+ (1<<VEND_PXE_BOOT_ITEM_IX))
+
+#define CREDENTIALS_OPT (1 << VEND_PXE_CREDENTIAL_TYPES_IX)
+
+//
+// definitions of indices to populate option interest array
+//
+#define OP_SUBNET_MASK_IX 1
+#define OP_TIME_OFFSET_IX 0 // not used by PXE client
+#define OP_ROUTER_LIST_IX 2
+#define OP_TIME_SERVERS_IX 0 // not used by PXE client
+#define OP_NAME_SERVERS_IX 0 // not used by PXE client
+#define OP_DNS_SERVERS_IX 0 // not used by PXE client
+#define OP_LOG_SERVERS_IX 0 // not used by PXE client
+#define OP_COOKIE_SERVERS_IX 0 // not used by PXE client
+#define OP_LPR_SREVERS_IX 0 // not used by PXE client
+#define OP_IMPRESS_SERVERS_IX 0 // not used by PXE client
+#define OP_RES_LOC_SERVERS_IX 0 // not used by PXE client
+#define OP_HOST_NAME_IX 0 // not used by PXE client
+#define OP_BOOT_FILE_SZ_IX 9
+#define OP_DUMP_FILE_IX 0 // not used by PXE client
+#define OP_DOMAIN_NAME_IX 0 // not used by PXE client
+#define OP_SWAP_SERVER_IX 0 // not used by PXE client
+#define OP_ROOT_PATH_IX 0 // not used by PXE client
+#define OP_EXTENSION_PATH_IX 0 // not used by PXE client
+#define OP_IP_FORWARDING_IX 0 // not used by PXE client
+#define OP_NON_LOCAL_SRC_RTE_IX 0 // not used by PXE client
+#define OP_POLICY_FILTER_IX 0 // not used by PXE client
+#define OP_MAX_DATAGRAM_SZ_IX 0 // not used by PXE client
+#define OP_DEFAULT_TTL_IX 0 // not used by PXE client
+#define OP_MTU_AGING_TIMEOUT_IX 0 // not used by PXE client
+#define OP_MTU_SIZES_IX 0 // not used by PXE client
+#define OP_MTU_TO_USE_IX 0 // not used by PXE client
+#define OP_ALL_SUBNETS_LOCAL_IX 0 // not used by PXE client
+#define OP_BROADCAST_ADD_IX 0 // not used by PXE client
+#define OP_PERFORM_MASK_DISCOVERY_IX 0 // not used by PXE client
+#define OP_RESPOND_TO_MASK_REQ_IX 0 // not used by PXE client
+#define OP_PERFORM_ROUTER_DISCOVERY_IX 0 // not used by PXE client
+#define OP_ROUTER_SOLICIT_ADDRESS_IX 0 // not used by PXE client
+#define OP_STATIC_ROUTER_LIST_IX 0 // not used by PXE client
+#define OP_USE_ARP_TRAILERS_IX 0 // not used by PXE client
+#define OP_ARP_CACHE_TIMEOUT_IX 0 // not used by PXE client
+#define OP_ETHERNET_ENCAPSULATION_IX 0 // not used by PXE client
+#define OP_TCP_DEFAULT_TTL_IX 0 // not used by PXE client
+#define OP_TCP_KEEP_ALIVE_INT_IX 0 // not used by PXE client
+#define OP_KEEP_ALIVE_GARBAGE_IX 0 // not used by PXE client
+#define OP_NIS_DOMAIN_NAME_IX 0 // not used by PXE client
+#define OP_NIS_SERVERS_IX 0 // not used by PXE client
+#define OP_NTP_SERVERS_IX 0 // not used by PXE client
+#define OP_VENDOR_SPECIFIC_IX 3
+#define OP_NBNS_SERVERS_IX 0 // not used by PXE client
+#define OP_NBDD_SERVERS_IX 0 // not used by PXE client
+#define OP_NETBIOS_NODE_TYPE_IX 0 // not used by PXE client
+#define OP_NETBIOS_SCOPE_IX 0 // not used by PXE client
+#define OP_XWINDOW_SYSTEM_FONT_SERVERS_IX 0 // not used by PXE client
+#define OP_XWINDOW_SYSTEM_DISPLAY_MANAGERS_IX 0 // not used by PXE client
+// DHCP option indices
+//
+#define OP_DHCP_REQ_IP_ADD_IX 0 // not used by PXE client
+#define OP_DHCP_LEASE_TIME_IX 0 // not used by PXE client
+#define OP_DHCP_OPTION_OVERLOAD_IX 4
+#define OP_DHCP_MESSAGE_TYPE_IX 5
+#define OP_DHCP_SERVER_IP_IX 6
+#define OP_DHCP_PARM_REQ_LIST_IX 0 // not used by PXE client
+#define OP_DHCP_ERROR_MESSAGE_IX 0 // not used by PXE client
+#define OP_DHCP_MAX_MESSAGE_SZ_IX 0 // not used by PXE client
+#define OP_DHCP_RENEWAL_TIME_IX 0 // not used by PXE client
+#define OP_DHCP_REBINDING_TIME_IX 0 // not used by PXE client
+#define OP_DHCP_CLASS_IDENTIFIER_IX 7
+#define OP_DHCP_CLIENT_IDENTIFIER_IX 0 // not used by PXE client
+#define OP_RESERVED62_IX 0 // not used by PXE client
+#define OP_RESERVED63_IX 0 // not used by PXE client
+#define OP_NISPLUS_DOMAIN_NAME_IX 0 // not used by PXE client
+#define OP_NISPLUS_SERVERS_IX 0 // not used by PXE client
+#define OP_DHCP_TFTP_SERVER_NAME_IX 0 // not used by PXE client
+#define OP_DHCP_BOOTFILE_IX 8
+
+#define MAX_OUR_OPT OP_DHCP_BOOTFILE // largest option in which we are interested
+#define MAX_OUR_IX OP_BOOT_FILE_SZ_IX
+
+typedef struct {
+ DHCPV4_OP_STRUCT *PktOptAdds[MAX_OUR_IX];
+ DHCPV4_OP_STRUCT *PxeOptAdds[MAX_OUR_PXE_IX];
+ UINT8 Status;
+} OPTION_POINTERS;
+
+typedef struct DhcpReceiveBufferStruct {
+ union {
+ UINT8 ReceiveBuffer[MAX_DHCP_MSG_SZ];
+ DHCPV4_STRUCT Dhcpv4;
+ } u;
+
+ OPTION_POINTERS OpAdds;
+} DHCP_RECEIVE_BUFFER;
+
+#define PXE_TYPE (1 << 0)
+#define WfM11a_TYPE (1 << 1)
+#define DISCOVER_TYPE (1 << 2)
+#define CREDENTIALS_TYPE (1 << 3)
+#define USE_THREE_BYTE (1 << 4)
+
+#endif // _DHCP_H
+
+/* EOF - dhcp.h */
diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/hton.h b/EdkModulePkg/Universal/Network/PxeBc/Dxe/hton.h
new file mode 100644
index 0000000000..b9000c1a88
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/hton.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:
+ hton.h
+
+Abstract:
+ Byte swapping macros.
+
+--*/
+
+#ifndef _HTON_H_
+#define _HTON_H_
+
+//
+// Only Intel order functions are defined at this time.
+//
+#define HTONS(v) (UINT16) ((((v) << 8) & 0xff00) + (((v) >> 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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>Dhcp4</BaseName>
+ <Guid>a46c3330-be36-4977-9d24-a7cf92eef0fe</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Created>2006-03-12 17:09</Created>
+ <Modified>2006-03-19 15:19</Modified>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>UefiMemoryLib</Library>
+ <Library>UefiLib</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>UefiDriverModelLib</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Library>BaseDebugLibReportStatusCode</Library>
+ <Library>BaseLib</Library>
+ <Library>DxeMemoryAllocationLib</Library>
+ </Libraries>
+</ModuleBuildDescription>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>Dhcp4</BaseName>
+ <ModuleType>UEFI_DRIVER</ModuleType>
+ <ComponentType>BS_DRIVER</ComponentType>
+ <Guid>a46c3330-be36-4977-9d24-a7cf92eef0fe</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for DiskIo module.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Specification>0</Specification>
+ <Created>2006-03-12 17:09</Created>
+ <Updated>2006-03-19 15:19</Updated>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverModelLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseMemoryLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">MemoryAllocationLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>ComponentName.c</Filename>
+ <Filename>PxeDhcp4.c</Filename>
+ <Filename>PxeDhcp4.h</Filename>
+ <Filename>PxeDhcp4InitSelect.c</Filename>
+ <Filename>PxeDhcp4Release.c</Filename>
+ <Filename>PxeDhcp4RenewRebind.c</Filename>
+ <Filename>PxeDhcp4Run.c</Filename>
+ <Filename>PxeDhcp4Setup.c</Filename>
+ <Filename>support.c</Filename>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ <PackageName>EdkModulePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="ALWAYS_CONSUMED">PxeDhcp4Callback</Protocol>
+ <Protocol Usage="BY_START">PxeDhcp4</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">SimpleNetwork</Protocol>
+ <Protocol Usage="TO_START">PxeBaseCode</Protocol>
+ </Protocols>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint></ModuleEntryPoint>
+ <ModuleUnloadImage></ModuleUnloadImage>
+ </Extern>
+ <Extern>
+ <DriverBinding>gPxeDhcp4DriverBinding</DriverBinding>
+ <ComponentName>gPxeDhcp4ComponentName</ComponentName>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
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 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="Dhcp4"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\Network\PxeDhcp4\Dxe"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="Dhcp4">
+ <GenBuild baseName="Dhcp4" mbdFilename="${MODULE_DIR}\Dhcp4.mbd" msaFilename="${MODULE_DIR}\Dhcp4.msa"/>
+ </target>
+ <target depends="Dhcp4_clean" name="clean"/>
+ <target depends="Dhcp4_cleanall" name="cleanall"/>
+ <target name="Dhcp4_clean">
+ <OutputDirSetup baseName="Dhcp4" mbdFilename="${MODULE_DIR}\Dhcp4.mbd" msaFilename="${MODULE_DIR}\Dhcp4.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\Dhcp4_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\Dhcp4_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="Dhcp4_cleanall">
+ <OutputDirSetup baseName="Dhcp4" mbdFilename="${MODULE_DIR}\Dhcp4.mbd" msaFilename="${MODULE_DIR}\Dhcp4.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\Dhcp4_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\Dhcp4_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**Dhcp4*"/>
+ </delete>
+ </target>
+</project> \ 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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>SNP</BaseName>
+ <Guid>A2f436EA-A127-4EF8-957C-8048606FF670</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Created>2006-03-12 17:09</Created>
+ <Modified>2006-03-19 15:19</Modified>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>BaseMemoryLib</Library>
+ <Library>UefiLib</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>UefiDriverModelLib</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Library>BaseDebugLibReportStatusCode</Library>
+ <Library>BaseLib</Library>
+ <Library>DxeMemoryAllocationLib</Library>
+ </Libraries>
+</ModuleBuildDescription>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>SNP</BaseName>
+ <ModuleType>UEFI_DRIVER</ModuleType>
+ <ComponentType>BS_DRIVER</ComponentType>
+ <Guid>A2f436EA-A127-4EF8-957C-8048606FF670</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for DiskIo module.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Specification>0</Specification>
+ <Created>2006-03-12 17:09</Created>
+ <Updated>2006-03-19 15:19</Updated>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverModelLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseMemoryLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">MemoryAllocationLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>callback.c</Filename>
+ <Filename>get_status.c</Filename>
+ <Filename>initialize.c</Filename>
+ <Filename>mcast_ip_to_mac.c</Filename>
+ <Filename>nvdata.c</Filename>
+ <Filename>receive.c</Filename>
+ <Filename>receive_filters.c</Filename>
+ <Filename>reset.c</Filename>
+ <Filename>shutdown.c</Filename>
+ <Filename>snp.c</Filename>
+ <Filename>snp.h</Filename>
+ <Filename>start.c</Filename>
+ <Filename>station_address.c</Filename>
+ <Filename>statistics.c</Filename>
+ <Filename>stop.c</Filename>
+ <Filename>transmit.c</Filename>
+ <Filename>WaitForPacket.c</Filename>
+ <Filename>ComponentName.c</Filename>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ <PackageName>EdkModulePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="BY_START">SimpleNetwork</Protocol>
+ <Protocol Usage="TO_START">PciIo</Protocol>
+ <Protocol Usage="TO_START">DevicePath</Protocol>
+ <Protocol Usage="SOMETIMES_CONSUMED">NetworkInterfaceIdentifier</Protocol>
+ <Protocol Usage="TO_START">NetworkInterfaceIdentifier2</Protocol>
+ </Protocols>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint></ModuleEntryPoint>
+ <ModuleUnloadImage></ModuleUnloadImage>
+ </Extern>
+ <Extern>
+ <DriverBinding>mSimpleNetworkDriverBinding</DriverBinding>
+ <ComponentName>gSimpleNetworkComponentName</ComponentName>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
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 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="SNP"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\Network\Snp32_64\Dxe"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="SNP">
+ <GenBuild baseName="SNP" mbdFilename="${MODULE_DIR}\SNP.mbd" msaFilename="${MODULE_DIR}\SNP.msa"/>
+ </target>
+ <target depends="SNP_clean" name="clean"/>
+ <target depends="SNP_cleanall" name="cleanall"/>
+ <target name="SNP_clean">
+ <OutputDirSetup baseName="SNP" mbdFilename="${MODULE_DIR}\SNP.mbd" msaFilename="${MODULE_DIR}\SNP.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\SNP_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\SNP_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="SNP_cleanall">
+ <OutputDirSetup baseName="SNP" mbdFilename="${MODULE_DIR}\SNP.mbd" msaFilename="${MODULE_DIR}\SNP.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\SNP_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\SNP_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**SNP*"/>
+ </delete>
+ </target>
+</project> \ 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 <PCD_IMAGE> 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 <PCD_IMAGE> 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 <PCD_IMAGE> 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
+ <PCD_IMAGE>.
+
+ @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 <AutoGen.h>
+#include <PeimDepex.h>
+
+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 <AutoGen.h>
+#include <DxeDepex.h>
+
+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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>Runtime</BaseName>
+ <Guid>B601F8C4-43B7-4784-95B1-F4226CB40CEE</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Created>2006-03-12 17:09</Created>
+ <Modified>2006-03-19 15:19</Modified>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiRuntimeServicesTableLib</Library>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>BaseLib</Library>
+ <Library>BaseMemoryLib</Library>
+ <Library>EdkDxeRuntimeDriverLib</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>BaseDebugLibReportStatusCode</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Arch ArchType="IPF">
+ <Library>EdkDxeSalLib</Library>
+ </Arch>
+ </Libraries>
+ <BuildOptions ToolChain="MSFT">
+ <ImageEntryPoint>_ModuleEntryPoint</ImageEntryPoint>
+ </BuildOptions>
+</ModuleBuildDescription>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>Runtime</BaseName>
+ <ModuleType>DXE_RUNTIME_DRIVER</ModuleType>
+ <ComponentType>RT_DRIVER</ComponentType>
+ <Guid>B601F8C4-43B7-4784-95B1-F4226CB40CEE</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for DiskIo module.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Specification>0</Specification>
+ <Created>2006-03-12 17:09</Created>
+ <Updated>2006-03-19 15:19</Updated>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DxeRuntimeDriverLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">ReportStatusCodeLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseMemoryLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">EdkDxeSalLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiRuntimeServicesTableLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>Runtime.dxs</Filename>
+ <Filename>PeHotRelocate.c</Filename>
+ <Filename>Runtime.c</Filename>
+ <Filename>Runtime.h</Filename>
+ <Filename>Crc32.c</Filename>
+ <Arch ArchType="IA32">
+ <Filename>Ia32\PeHotRelocateEx.c</Filename>
+ </Arch>
+ <Arch ArchType="X64">
+ <Filename>x64\PeHotRelocateEx.c</Filename>
+ <Filename>x64\PeHotRelocateEx.h</Filename>
+ </Arch>
+ <Arch ArchType="IPF">
+ <Filename>Ipf\PeHotRelocateEx.c</Filename>
+ <Filename>Ipf\PeHotRelocateEx.h</Filename>
+ </Arch>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ <PackageName>EdkModulePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="ALWAYS_CONSUMED">LoadedImage</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">Runtime</Protocol>
+ </Protocols>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint>RuntimeDriverInitialize</ModuleEntryPoint>
+ </Extern>
+ <Extern>
+ <SetVirtualAddressMapCallBack></SetVirtualAddressMapCallBack>
+ <ExitBootServicesCallBack></ExitBootServicesCallBack>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
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 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="Runtime"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\Runtime\RuntimeDxe"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="Runtime">
+ <GenBuild baseName="Runtime" mbdFilename="${MODULE_DIR}\Runtime.mbd" msaFilename="${MODULE_DIR}\Runtime.msa"/>
+ </target>
+ <target depends="Runtime_clean" name="clean"/>
+ <target depends="Runtime_cleanall" name="cleanall"/>
+ <target name="Runtime_clean">
+ <OutputDirSetup baseName="Runtime" mbdFilename="${MODULE_DIR}\Runtime.mbd" msaFilename="${MODULE_DIR}\Runtime.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\Runtime_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\Runtime_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="Runtime_cleanall">
+ <OutputDirSetup baseName="Runtime" mbdFilename="${MODULE_DIR}\Runtime.mbd" msaFilename="${MODULE_DIR}\Runtime.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\Runtime_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\Runtime_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**Runtime*"/>
+ </delete>
+ </target>
+</project> \ 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 <AutoGen.h>
+#include <DxeDepex.h>
+
+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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>SecurityStub</BaseName>
+ <Guid>F80697E9-7FD6-4665-8646-88E33EF71DFC</Guid>
+ <Version>EDK_RELEASE_VERSION 0x00020000</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Created>2006-03-12 17:09</Created>
+ <Modified>2006-03-22 19:19</Modified>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>BaseLib</Library>
+ <Library>UefiMemoryLib</Library>
+ <Library>UefiLib</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Library>BaseDebugLibReportStatusCode</Library>
+ <Library>EdkDxePrintLib</Library>
+ </Libraries>
+</ModuleBuildDescription>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>SecurityStub</BaseName>
+ <ModuleType>DXE_DRIVER</ModuleType>
+ <ComponentType>BS_DRIVER</ComponentType>
+ <Guid>F80697E9-7FD6-4665-8646-88E33EF71DFC</Guid>
+ <Version>EDK_RELEASE_VERSION 0x00020000</Version>
+ <Abstract>Component description file for SecurityStub module</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Specification>EFI_SPECIFICATION_VERSION 0x00000000</Specification>
+ <Created>2006-03-12 17:09</Created>
+ <Updated>2006-03-22 19:19</Updated>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>SecurityStub.dxs</Filename>
+ <Filename>SecurityStub.h</Filename>
+ <Filename>SecurityStub.c</Filename>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="ALWAYS_PRODUCED">Security</Protocol>
+ </Protocols>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint>SecurityStubInitialize</ModuleEntryPoint>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
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 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="SecurityStub"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\Security\SecurityStub\Dxe"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="SecurityStub">
+ <GenBuild baseName="SecurityStub" mbdFilename="${MODULE_DIR}\SecurityStub.mbd" msaFilename="${MODULE_DIR}\SecurityStub.msa"/>
+ </target>
+ <target depends="SecurityStub_clean" name="clean"/>
+ <target depends="SecurityStub_cleanall" name="cleanall"/>
+ <target name="SecurityStub_clean">
+ <OutputDirSetup baseName="SecurityStub" mbdFilename="${MODULE_DIR}\SecurityStub.mbd" msaFilename="${MODULE_DIR}\SecurityStub.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\SecurityStub_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\SecurityStub_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="SecurityStub_cleanall">
+ <OutputDirSetup baseName="SecurityStub" mbdFilename="${MODULE_DIR}\SecurityStub.mbd" msaFilename="${MODULE_DIR}\SecurityStub.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\SecurityStub_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\SecurityStub_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**SecurityStub*"/>
+ </delete>
+ </target>
+</project> \ 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 <AutoGen.h>
+#include <DxeDepex.h>
+
+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 <AutoGen.h>
+#include <DxeDepex.h>
+
+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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>StatusCode</BaseName>
+ <Guid>9F455D3B-2B8A-4c06-960B-A71B9714B9CD</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Created>2006-03-12 17:09</Created>
+ <Modified>2006-03-19 15:19</Modified>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>BaseLib</Library>
+ <Library>EdkDxeRuntimeDriverLib</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>UefiLib</Library>
+ <Library>BasePrintLib</Library>
+ <Library>BaseDebugLibReportStatusCode</Library>
+ <Library>EdkRtPlatformStatusCodeLib</Library>
+ <Library>DxeIoLibCpuIo</Library>
+ <Library>BaseMemoryLib</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Library>EdkRtMemoryStatusCodeLib</Library>
+ <Library>EdkBsDataHubStatusCodeLib</Library>
+ <Library>DxeHobLib</Library>
+ <Library>DxeMemoryAllocationLib</Library>
+ <Library>EdkMemoryStatusCodeLib</Library>
+
+ <Arch ArchType="IPF">
+ <Library>EdkDxeSalLib</Library>
+ </Arch>
+ </Libraries>
+ <BuildOptions ToolChain="MSFT">
+ <ImageEntryPoint>_ModuleEntryPoint</ImageEntryPoint>
+ </BuildOptions>
+</ModuleBuildDescription>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>StatusCode</BaseName>
+ <ModuleType>DXE_RUNTIME_DRIVER</ModuleType>
+ <ComponentType>RT_DRIVER</ComponentType>
+ <Guid>9F455D3B-2B8A-4c06-960B-A71B9714B9CD</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for DiskIo module.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Specification>0</Specification>
+ <Created>2006-03-12 17:09</Created>
+ <Updated>2006-03-19 15:19</Updated>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DxeRuntimeDriverLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">PrintLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">IoLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">EdkRtPlatformStatusCodeLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">EdkDxeSalLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">PcdLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>DebugAssert.c</Filename>
+ <Filename>StatusCode.c</Filename>
+ <Filename>StatusCode.h</Filename>
+ <Arch ArchType="IA32">
+ <Filename>Ia32\Ia32StatusCode.c</Filename>
+ <Filename>Ia32\Ia32StatusCode.dxs</Filename>
+ </Arch>
+ <Arch ArchType="X64">
+ <Filename>x64\x64StatusCode.c</Filename>
+ <Filename>x64\x64StatusCode.dxs</Filename>
+ </Arch>
+ <Arch ArchType="IPF">
+ <Filename>Ipf\IpfStatusCode.c</Filename>
+ <Filename>Ipf\IpfStatusCode.dxs</Filename>
+ </Arch>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ <PackageName>EdkModulePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="ALWAYS_CONSUMED">DebugAssert</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">ExtendedSalStatusCodeServices</Protocol>
+ </Protocols>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint>InstallStatusCode</ModuleEntryPoint>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
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 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="StatusCode"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\StatusCode\RuntimeDxe"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="StatusCode">
+ <GenBuild baseName="StatusCode" mbdFilename="${MODULE_DIR}\StatusCode.mbd" msaFilename="${MODULE_DIR}\StatusCode.msa"/>
+ </target>
+ <target depends="StatusCode_clean" name="clean"/>
+ <target depends="StatusCode_cleanall" name="cleanall"/>
+ <target name="StatusCode_clean">
+ <OutputDirSetup baseName="StatusCode" mbdFilename="${MODULE_DIR}\StatusCode.mbd" msaFilename="${MODULE_DIR}\StatusCode.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\StatusCode_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\StatusCode_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="StatusCode_cleanall">
+ <OutputDirSetup baseName="StatusCode" mbdFilename="${MODULE_DIR}\StatusCode.mbd" msaFilename="${MODULE_DIR}\StatusCode.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\StatusCode_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\StatusCode_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**StatusCode*"/>
+ </delete>
+ </target>
+</project> \ 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 <AutoGen.h>
+#include <DxeDepex.h>
+
+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 <AutoGen.h>
+#include <DxeDepex.h>
+
+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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>HiiDatabase</BaseName>
+ <Guid>FCD337AB-B1D3-4EF8-957C-8048606FF670</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Created>2006-03-12 17:09</Created>
+ <Modified>2006-03-19 15:19</Modified>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>UefiRuntimeServicesTableLib</Library>
+ <Library>BaseLib</Library>
+ <Library>BaseMemoryLib</Library>
+ <Library>BaseDebugLibReportStatusCode</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>DxeMemoryAllocationLib</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Library>EdkIfrSupportLib</Library>
+ </Libraries>
+ <BuildOptions ToolChain="MSFT">
+ <ImageEntryPoint>_ModuleEntryPoint</ImageEntryPoint>
+ </BuildOptions>
+</ModuleBuildDescription>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>HiiDatabase</BaseName>
+ <ModuleType>DXE_DRIVER</ModuleType>
+ <ComponentType>BS_DRIVER</ComponentType>
+ <Guid>FCD337AB-B1D3-4EF8-957C-8048606FF670</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for DiskIo module.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Specification>0</Specification>
+ <Created>2006-03-12 17:09</Created>
+ <Updated>2006-03-19 15:19</Updated>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">MemoryAllocationLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseMemoryLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiRuntimeServicesTableLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">EdkIfrSupportLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>HiiDatabase.c</Filename>
+ <Filename>HiiDatabase.h</Filename>
+ <Filename>Forms.c</Filename>
+ <Filename>Strings.c</Filename>
+ <Filename>Package.c</Filename>
+ <Filename>Fonts.c</Filename>
+ <Filename>Keyboard.c</Filename>
+ <Filename>HiiDatabase.dxs</Filename>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ <PackageName>EdkModulePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="ALWAYS_CONSUMED">Hii</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">FormCallback</Protocol>
+ </Protocols>
+ <Variables>
+ <Variable Usage="ALWAYS_CONSUMED">
+ <String>L"Lang"</String>
+ <Guid Usage="ALWAYS_CONSUMED">
+ 0x8BE4DF61, 0x93CA, 0x11d2, {0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C }
+ </Guid>
+ </Variable>
+ </Variables>
+ <Guids>
+ <GuidEntry Usage="ALWAYS_CONSUMED">
+ <C_Name>GlobalVariable</C_Name>
+ </GuidEntry>
+ </Guids>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint>InitializeHiiDatabase</ModuleEntryPoint>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
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 <cr> with <space>
+ and by removing special characters such as the <wide> 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 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="HiiDatabase"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\UserInterface\HiiDataBase\Dxe"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="HiiDatabase">
+ <GenBuild baseName="HiiDatabase" mbdFilename="${MODULE_DIR}\HiiDatabase.mbd" msaFilename="${MODULE_DIR}\HiiDatabase.msa"/>
+ </target>
+ <target depends="HiiDatabase_clean" name="clean"/>
+ <target depends="HiiDatabase_cleanall" name="cleanall"/>
+ <target name="HiiDatabase_clean">
+ <OutputDirSetup baseName="HiiDatabase" mbdFilename="${MODULE_DIR}\HiiDatabase.mbd" msaFilename="${MODULE_DIR}\HiiDatabase.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\HiiDatabase_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\HiiDatabase_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="HiiDatabase_cleanall">
+ <OutputDirSetup baseName="HiiDatabase" mbdFilename="${MODULE_DIR}\HiiDatabase.mbd" msaFilename="${MODULE_DIR}\HiiDatabase.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\HiiDatabase_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\HiiDatabase_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**HiiDatabase*"/>
+ </delete>
+ </target>
+</project> \ 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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>DriverSample</BaseName>
+ <Guid>FE3542FE-C1D3-4EF8-657C-8048606FF670</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Created>2006-03-12 17:09</Created>
+ <Modified>2006-03-19 15:19</Modified>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>UefiRuntimeServicesTableLib</Library>
+ <Library>BaseLib</Library>
+ <Library>BaseMemoryLib</Library>
+ <Library>UefiLib</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Library>BaseDebugLibNull</Library>
+ <Library>BasePrintLib</Library>
+ <Library>EdkGraphicsLib</Library>
+ <Library>EdkIfrSupportLib</Library>
+ <Library>DxeMemoryAllocationLib</Library>
+ <Library>HiiLib</Library>
+ </Libraries>
+</ModuleBuildDescription>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>DriverSample</BaseName>
+ <ModuleType>DXE_DRIVER</ModuleType>
+ <ComponentType>BS_DRIVER</ComponentType>
+ <Guid>FE3542FE-C1D3-4EF8-657C-8048606FF670</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for DiskIo module.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Specification>0</Specification>
+ <Created>2006-03-12 17:09</Created>
+ <Updated>2006-03-19 15:19</Updated>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiRuntimeServicesTableLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">PrintLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">EdkGraphicsLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">EdkIfrSupportLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseMemoryLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">MemoryAllocationLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">HiiLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>InventoryStrings.uni</Filename>
+ <Filename>Inventory.vfr</Filename>
+ <Filename>VfrStrings.uni</Filename>
+ <Filename>Vfr.vfr</Filename>
+ <Filename>DriverSample.c</Filename>
+ <Filename>DriverSample.h</Filename>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ <PackageName>EdkModulePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="ALWAYS_CONSUMED">Hii</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">UgaDraw</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">OEMBadging</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">FirmwareVolume</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">ConsoleControl</Protocol>
+ <Protocol Usage="ALWAYS_PRODUCED">FormCallback</Protocol>
+ </Protocols>
+ <Variables>
+ <Variable Usage="ALWAYS_PRODUCED">
+ <String>L"256"</String>
+ <Guid>0xA04A27f4, 0xDF00, 0x4D42, { 0xB5, 0x52, 0x39, 0x51, 0x13, 0x02, 0x11, 0x3D }</Guid>
+ </Variable>
+ </Variables>
+ <Guids>
+ <GuidEntry Usage="ALWAYS_CONSUMED">
+ <C_Name>GlobalVariable</C_Name>
+ </GuidEntry>
+ </Guids>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint>DriverSampleInit</ModuleEntryPoint>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
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 0000000000..9e9dbf5454
--- /dev/null
+++ b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/VfrStrings.uni
Binary files differ
diff --git a/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/build.xml b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/build.xml
new file mode 100644
index 0000000000..1263279552
--- /dev/null
+++ b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/build.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="DriverSample"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\UserInterface\SetupBrowser\Dxe\DriverSample"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="DriverSample">
+ <GenBuild baseName="DriverSample" mbdFilename="${MODULE_DIR}\DriverSample.mbd" msaFilename="${MODULE_DIR}\DriverSample.msa"/>
+ </target>
+ <target depends="DriverSample_clean" name="clean"/>
+ <target depends="DriverSample_cleanall" name="cleanall"/>
+ <target name="DriverSample_clean">
+ <OutputDirSetup baseName="DriverSample" mbdFilename="${MODULE_DIR}\DriverSample.mbd" msaFilename="${MODULE_DIR}\DriverSample.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\DriverSample_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\DriverSample_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="DriverSample_cleanall">
+ <OutputDirSetup baseName="DriverSample" mbdFilename="${MODULE_DIR}\DriverSample.mbd" msaFilename="${MODULE_DIR}\DriverSample.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\DriverSample_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\DriverSample_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**DriverSample*"/>
+ </delete>
+ </target>
+</project> \ 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 0000000000..4946b4ae61
--- /dev/null
+++ b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/DriverSample/inventorystrings.uni
Binary files differ
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 <Spacebar> 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]
+ // <BOOLEANS>
+ // OpCode(s)
+ // EndIf
+ //
+ // SuppressIf [GrayoutIf]
+ // <BOOLEANS>
+ // 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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>SetupBrowser</BaseName>
+ <Guid>EBf342FE-B1D3-4EF8-957C-8048606FF670</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Created>2006-03-12 17:09</Created>
+ <Modified>2006-03-19 15:19</Modified>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>UefiRuntimeServicesTableLib</Library>
+ <Library>BaseLib</Library>
+ <Library>BaseDebugLibNull</Library>
+ <Library>BaseMemoryLib</Library>
+ <Library>BasePrintLib</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>DxeMemoryAllocationLib</Library>
+ <Library>EdkGraphicsLib</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Library>HiiLib</Library>
+ </Libraries>
+</ModuleBuildDescription>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>SetupBrowser</BaseName>
+ <ModuleType>DXE_DRIVER</ModuleType>
+ <ComponentType>BS_DRIVER</ComponentType>
+ <Guid>EBf342FE-B1D3-4EF8-957C-8048606FF670</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for DiskIo module.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Specification>0</Specification>
+ <Created>2006-03-12 17:09</Created>
+ <Updated>2006-03-19 15:19</Updated>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseMemoryLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">MemoryAllocationLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">EdkIfrSupportLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">PrintLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiRuntimeServicesTableLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">HiiLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">EdkGraphicsLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>SetupBrowserStr.uni</Filename>
+ <Filename>Setup.c</Filename>
+ <Filename>Setup.h</Filename>
+ <Filename>Boolean.c</Filename>
+ <Filename>InputHandler.c</Filename>
+ <Filename>Print.c</Filename>
+ <Filename>Print.h</Filename>
+ <Filename>Presentation.c</Filename>
+ <Filename>ProcessOptions.c</Filename>
+ <Filename>Ui.c</Filename>
+ <Filename>Ui.h</Filename>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ <PackageName>EdkModulePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="ALWAYS_CONSUMED">Hii</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">FormCallback</Protocol>
+ <Protocol Usage="ALWAYS_PRODUCED">FormBrowser</Protocol>
+ <Protocol Usage="ALWAYS_PRODUCED">Print</Protocol>
+ </Protocols>
+ <Events>
+ <CreateEvents>
+ <Event>
+ <C_Name>EFI_EVENT_TIMER</C_Name>
+ </Event>
+ </CreateEvents>
+ </Events>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint>InitializeSetup</ModuleEntryPoint>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
diff --git a/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/SetupBrowserStr.uni b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/SetupBrowserStr.uni
new file mode 100644
index 0000000000..1dfd9247a3
--- /dev/null
+++ b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/SetupBrowserStr.uni
Binary files differ
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 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="SetupBrowser"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\UserInterface\SetupBrowser\Dxe"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="SetupBrowser">
+ <GenBuild baseName="SetupBrowser" mbdFilename="${MODULE_DIR}\SetupBrowser.mbd" msaFilename="${MODULE_DIR}\SetupBrowser.msa"/>
+ </target>
+ <target depends="SetupBrowser_clean" name="clean"/>
+ <target depends="SetupBrowser_cleanall" name="cleanall"/>
+ <target name="SetupBrowser_clean">
+ <OutputDirSetup baseName="SetupBrowser" mbdFilename="${MODULE_DIR}\SetupBrowser.mbd" msaFilename="${MODULE_DIR}\SetupBrowser.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\SetupBrowser_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\SetupBrowser_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="SetupBrowser_cleanall">
+ <OutputDirSetup baseName="SetupBrowser" mbdFilename="${MODULE_DIR}\SetupBrowser.mbd" msaFilename="${MODULE_DIR}\SetupBrowser.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\SetupBrowser_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\SetupBrowser_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**SetupBrowser*"/>
+ </delete>
+ </target>
+</project> \ 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 <Ppi/ReadOnlyVariable.h>
+#include <Variable.h>
+#include <Library/BaseLib.h>
+
+//
+// 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 <AutoGen.h>
+#include <PeimDepex.h>
+
+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 <Common/Variable.h>
+
+#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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>PeiVariable</BaseName>
+ <Guid>34C8C28F-B61C-45a2-8F2E-89E46BECC63B</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Created>2006-03-12 17:09</Created>
+ <Modified>2006-03-19 15:19</Modified>
+ </MbdHeader>
+ <Libraries>
+ <Library>PeiReportStatusCodeLib</Library>
+ <Library>BaseDebugLibReportStatusCode</Library>
+ <Library>BaseLib</Library>
+ <Library>PeiMemoryLib</Library>
+ <Library>PeiCoreLib</Library>
+ <Library>PeiServicesTablePointerLib</Library>
+ <Library>PeiHobLib</Library>
+ <Library>PeimEntryPoint</Library>
+ </Libraries>
+ <BuildOptions ToolChain="MSFT">
+ <ImageEntryPoint>_ModuleEntryPoint</ImageEntryPoint>
+ </BuildOptions>
+</ModuleBuildDescription>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>PeiVariable</BaseName>
+ <ModuleType>PEIM</ModuleType>
+ <ComponentType>PE32_PEIM</ComponentType>
+ <Guid>34C8C28F-B61C-45a2-8F2E-89E46BECC63B</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for DiskIo module.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Specification>0</Specification>
+ <Created>2006-03-12 17:09</Created>
+ <Updated>2006-03-19 15:19</Updated>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">PeimEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">PeiCoreLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">HobLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>Variable.c</Filename>
+ <Filename>Variable.dxs</Filename>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ <PackageName>EdkModulePkg</PackageName>
+ </Includes>
+ <PPIs>
+ <Ppi Usage="ALWAYS_CONSUMED">FlashMap</Ppi>
+ <Ppi Usage="ALWAYS_CONSUMED">ReadOnlyVariable</Ppi>
+ </PPIs>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint>PeimInitializeVariableServices</ModuleEntryPoint>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
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 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="PeiVariable"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\Variable\Pei"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="PeiVariable">
+ <GenBuild baseName="PeiVariable" mbdFilename="${MODULE_DIR}\Variable.mbd" msaFilename="${MODULE_DIR}\Variable.msa"/>
+ </target>
+ <target depends="PeiVariable_clean" name="clean"/>
+ <target depends="PeiVariable_cleanall" name="cleanall"/>
+ <target name="PeiVariable_clean">
+ <OutputDirSetup baseName="PeiVariable" mbdFilename="${MODULE_DIR}\Variable.mbd" msaFilename="${MODULE_DIR}\Variable.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\PeiVariable_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\PeiVariable_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="PeiVariable_cleanall">
+ <OutputDirSetup baseName="PeiVariable" mbdFilename="${MODULE_DIR}\Variable.mbd" msaFilename="${MODULE_DIR}\Variable.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\PeiVariable_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\PeiVariable_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**PeiVariable*"/>
+ </delete>
+ </target>
+</project> \ 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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>EmuVariable</BaseName>
+ <Guid>CBD2E4D5-7068-4FF5-B866-9822B4AD8D60</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Created>2006-03-23 16:05</Created>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>BaseMemoryLib</Library>
+ <Library>BaseDebugLibReportStatusCode</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>EdkDxeRuntimeDriverLib</Library>
+ <Library>DxeMemoryAllocationLib</Library>
+ <Library>BaseLib</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Arch ArchType="IPF">
+ <Library>EdkDxeSalLib</Library>
+ </Arch>
+ </Libraries>
+ <BuildOptions ToolChain="MSFT">
+ <ImageEntryPoint>_ModuleEntryPoint</ImageEntryPoint>
+ </BuildOptions>
+</ModuleBuildDescription>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>EmuVariable</BaseName>
+ <ModuleType>DXE_RUNTIME_DRIVER</ModuleType>
+ <ComponentType>RT_DRIVER</ComponentType>
+ <Guid>CBD2E4D5-7068-4FF5-B866-9822B4AD8D60</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for DiskIo module.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Specification>0</Specification>
+ <Created>2006-03-23 16:05</Created>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseMemoryLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">MemoryAllocationLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DxeRuntimeDriverLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">EdkDxeSalLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>EmuVariable.c</Filename>
+ <Filename>EmuVariable.dxs</Filename>
+ <Arch ArchType="IA32">
+ <Filename>..\Ia32\Ia32Variable.c</Filename>
+ </Arch>
+ <Arch ArchType="X64">
+ <Filename>..\x64\x64Variable.c</Filename>
+ </Arch>
+ <Arch ArchType="IPF">
+ <Filename>..\Ipf\IpfVariable.c</Filename>
+ </Arch>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ <PackageName>EdkModulePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="ALWAYS_CONSUMED">VariableWrite</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">Variable</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">VariableWrite</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">Variable</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">ExtendedSalVariableServices</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">ExtendedSalBootService</Protocol>
+ </Protocols>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint>VariableServiceInitialize</ModuleEntryPoint>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
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 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="EmuVariable"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\Variable\RuntimeDxe\Emu"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="EmuVariable">
+ <GenBuild baseName="EmuVariable" mbdFilename="${MODULE_DIR}\EmuVariable.mbd" msaFilename="${MODULE_DIR}\EmuVariable.msa"/>
+ </target>
+ <target depends="EmuVariable_clean" name="clean"/>
+ <target depends="EmuVariable_cleanall" name="cleanall"/>
+ <target name="EmuVariable_clean">
+ <OutputDirSetup baseName="EmuVariable" mbdFilename="${MODULE_DIR}\EmuVariable.mbd" msaFilename="${MODULE_DIR}\EmuVariable.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\EmuVariable_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\EmuVariable_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="EmuVariable_cleanall">
+ <OutputDirSetup baseName="EmuVariable" mbdFilename="${MODULE_DIR}\EmuVariable.mbd" msaFilename="${MODULE_DIR}\EmuVariable.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\EmuVariable_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\EmuVariable_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**EmuVariable*"/>
+ </delete>
+ </target>
+</project> \ 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 <AutoGen.h>
+#include <DxeDepex.h>
+
+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 <AutoGen.h>
+#include <DxeDepex.h>
+
+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 <Common/Variable.h>
+
+#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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>Variable</BaseName>
+ <Guid>CBD2E4D5-7068-4FF5-B462-9822B4AD8D60</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Created>2006-03-12 17:09</Created>
+ <Modified>2006-03-19 15:19</Modified>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>BaseLib</Library>
+ <Library>BaseMemoryLib</Library>
+ <Library>UefiLib</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Library>DxeServicesTableLib</Library>
+ <Library>BaseDebugLibNull</Library>
+ <Library>BasePrintLib</Library>
+ <Library>EdkDxeRuntimeDriverLib</Library>
+ <Library>DxeHobLib</Library>
+ <Library>DxeMemoryAllocationLib</Library>
+ <Library>EdkFvbServiceLib</Library>
+ <Arch ArchType="IPF">
+ <Library>EdkDxeSalLib</Library>
+ </Arch>
+ </Libraries>
+ <BuildOptions ToolChain="MSFT">
+ <ImageEntryPoint>_ModuleEntryPoint</ImageEntryPoint>
+ </BuildOptions>
+</ModuleBuildDescription>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>Variable</BaseName>
+ <ModuleType>DXE_RUNTIME_DRIVER</ModuleType>
+ <ComponentType>RT_DRIVER</ComponentType>
+ <Guid>CBD2E4D5-7068-4FF5-B462-9822B4AD8D60</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for DiskIo module.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Specification>0</Specification>
+ <Created>2006-03-12 17:09</Created>
+ <Updated>2006-03-19 15:19</Updated>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DxeServicesTableLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DxeRuntimeDriverLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">HobLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseMemoryLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">EdkFvbServiceLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">EdkDxeSalLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>Variable.c</Filename>
+ <Filename>Reclaim.c</Filename>
+ <Arch ArchType="IA32">
+ <Filename>InitVariable.c</Filename>
+ <Filename>Ia32Variable.dxs</Filename>
+ </Arch>
+ <Arch ArchType="X64">
+ <Filename>InitVariable.c</Filename>
+ <Filename>x64Variable.dxs</Filename>
+ </Arch>
+ <Arch ArchType="EBC">
+ <Filename>InitVariable.c</Filename>
+ <Filename>x64Variable.dxs</Filename>
+ </Arch>
+ <Arch ArchType="IPF">
+ <Filename>Ipf\InitVariable.c</Filename>
+ <Filename>IpfVariable.dxs</Filename>
+ </Arch>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ <PackageName>EdkModulePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="ALWAYS_CONSUMED">Variable</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">VariableWrite</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">FaultTolerantWriteLite</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">CpuIo</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">FvbExtension</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">FirmwareVolumeBlock</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">Variable</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">VariableWrite</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">FaultTolerantWriteLite</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">CpuIo</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">FvbExtension</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">FirmwareVolumeBlock</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">ExtendedSalBootService</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">ExtendedSalVariableServices</Protocol>
+ </Protocols>
+ <Guids>
+ <GuidEntry Usage="ALWAYS_CONSUMED">
+ <C_Name>FlashMapHob</C_Name>
+ </GuidEntry>
+ <GuidEntry Usage="ALWAYS_CONSUMED">
+ <C_Name>Hob</C_Name>
+ </GuidEntry>
+ <GuidEntry Usage="ALWAYS_CONSUMED">
+ <C_Name>SystemNvData</C_Name>
+ </GuidEntry>
+ <GuidEntry Usage="ALWAYS_CONSUMED">
+ <C_Name>AlternateFvBlock</C_Name>
+ </GuidEntry>
+ </Guids>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint>VariableServiceInitialize</ModuleEntryPoint>
+ </Extern>
+ <Extern>
+ <SetVirtualAddressMapCallBack>VariableClassAddressChangeEvent</SetVirtualAddressMapCallBack>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
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 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="Variable"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\Variable\RuntimeDxe"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="Variable">
+ <GenBuild baseName="Variable" mbdFilename="${MODULE_DIR}\Variable.mbd" msaFilename="${MODULE_DIR}\Variable.msa"/>
+ </target>
+ <target depends="Variable_clean" name="clean"/>
+ <target depends="Variable_cleanall" name="cleanall"/>
+ <target name="Variable_clean">
+ <OutputDirSetup baseName="Variable" mbdFilename="${MODULE_DIR}\Variable.mbd" msaFilename="${MODULE_DIR}\Variable.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\Variable_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\Variable_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="Variable_cleanall">
+ <OutputDirSetup baseName="Variable" mbdFilename="${MODULE_DIR}\Variable.mbd" msaFilename="${MODULE_DIR}\Variable.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\Variable_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\Variable_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**Variable*"/>
+ </delete>
+ </target>
+</project> \ 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 <AutoGen.h>
+#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 <AutoGen.h>
+#include <DxeDepex.h>
+
+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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>WatchDogTimer</BaseName>
+ <Guid>F099D67F-71AE-4c36-B2A3-DCEB0EB2B7D8</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Created>2006-03-12 17:09</Created>
+ <Modified>2006-03-19 15:19</Modified>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>UefiRuntimeServicesTableLib</Library>
+ <Library>BaseLib</Library>
+ <Library>UefiMemoryLib</Library>
+ <Library>UefiLib</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Library>BaseDebugLibReportStatusCode</Library>
+ <Library>EdkDxePrintLib</Library>
+ </Libraries>
+ <BuildOptions ToolChain="MSFT">
+ <ImageEntryPoint>_ModuleEntryPoint</ImageEntryPoint>
+ </BuildOptions>
+</ModuleBuildDescription>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>WatchDogTimer</BaseName>
+ <ModuleType>DXE_DRIVER</ModuleType>
+ <ComponentType>BS_DRIVER</ComponentType>
+ <Guid>F099D67F-71AE-4c36-B2A3-DCEB0EB2B7D8</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for DiskIo module.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ </License>
+ <Specification>0</Specification>
+ <Created>2006-03-12 17:09</Created>
+ <Updated>2006-03-19 15:19</Updated>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">ReportStatusCodeLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiRuntimeServicesTableLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>WatchDogTimer.c</Filename>
+ <Filename>WatchDogTimer.h</Filename>
+ <Filename>WatchDogTimer.dxs</Filename>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ <PackageName>EdkModulePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="ALWAYS_CONSUMED">StatusCode</Protocol>
+ <Protocol Usage="ALWAYS_PRODUCED">WatchdogTimer</Protocol>
+ </Protocols>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint>WatchdogTimerDriverInitialize</ModuleEntryPoint>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
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 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="WatchDogTimer"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\WatchdogTimer\Dxe"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="WatchDogTimer">
+ <GenBuild baseName="WatchDogTimer" mbdFilename="${MODULE_DIR}\WatchDogTimer.mbd" msaFilename="${MODULE_DIR}\WatchDogTimer.msa"/>
+ </target>
+ <target depends="WatchDogTimer_clean" name="clean"/>
+ <target depends="WatchDogTimer_cleanall" name="cleanall"/>
+ <target name="WatchDogTimer_clean">
+ <OutputDirSetup baseName="WatchDogTimer" mbdFilename="${MODULE_DIR}\WatchDogTimer.mbd" msaFilename="${MODULE_DIR}\WatchDogTimer.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\WatchDogTimer_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\WatchDogTimer_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="WatchDogTimer_cleanall">
+ <OutputDirSetup baseName="WatchDogTimer" mbdFilename="${MODULE_DIR}\WatchDogTimer.mbd" msaFilename="${MODULE_DIR}\WatchDogTimer.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\WatchDogTimer_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\WatchDogTimer_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**WatchDogTimer*"/>
+ </delete>
+ </target>
+</project> \ No newline at end of file