From b7c51c9cf4864df6aabb99a1ae843becd577237c Mon Sep 17 00:00:00 2001 From: raywu Date: Fri, 15 Jun 2018 00:00:50 +0800 Subject: init. 1AQQW051 --- .../Core/Dxe/ArchProtocol/ArchProtocolLib.cif | 38 + .../Core/Dxe/ArchProtocol/ArchProtocolLib.inf | 65 + .../Core/Dxe/ArchProtocol/ArchProtocolLib.mak | 69 + .../Core/Dxe/ArchProtocol/ArchProtocolLib.sdl | 26 + EDK/Foundation/Core/Dxe/ArchProtocol/Bds/Bds.c | 27 + EDK/Foundation/Core/Dxe/ArchProtocol/Bds/Bds.h | 100 + .../Core/Dxe/ArchProtocol/Capsule/Capsule.c | 27 + .../Core/Dxe/ArchProtocol/Capsule/Capsule.h | 33 + EDK/Foundation/Core/Dxe/ArchProtocol/Cpu/Cpu.c | 28 + EDK/Foundation/Core/Dxe/ArchProtocol/Cpu/Cpu.h | 361 +++ .../Core/Dxe/ArchProtocol/Metronome/Metronome.c | 27 + .../Core/Dxe/ArchProtocol/Metronome/Metronome.h | 109 + .../MonotonicCounter/MonotonicCounter.c | 27 + .../MonotonicCounter/MonotonicCounter.h | 35 + .../Dxe/ArchProtocol/RealTimeClock/RealTimeClock.c | 27 + .../Dxe/ArchProtocol/RealTimeClock/RealTimeClock.h | 43 + EDK/Foundation/Core/Dxe/ArchProtocol/Reset/Reset.c | 27 + EDK/Foundation/Core/Dxe/ArchProtocol/Reset/Reset.h | 40 + .../Core/Dxe/ArchProtocol/Runtime/Runtime.c | 29 + .../Core/Dxe/ArchProtocol/Runtime/Runtime.h | 114 + .../Core/Dxe/ArchProtocol/Security/Security.c | 28 + .../Core/Dxe/ArchProtocol/Security/Security.h | 146 ++ .../Core/Dxe/ArchProtocol/StatusCode/StatusCode.c | 29 + .../Core/Dxe/ArchProtocol/StatusCode/StatusCode.h | 100 + EDK/Foundation/Core/Dxe/ArchProtocol/Timer/Timer.c | 27 + EDK/Foundation/Core/Dxe/ArchProtocol/Timer/Timer.h | 260 ++ .../Core/Dxe/ArchProtocol/Variable/Variable.c | 29 + .../Core/Dxe/ArchProtocol/Variable/Variable.h | 41 + .../Dxe/ArchProtocol/VariableWrite/VariableWrite.c | 30 + .../Dxe/ArchProtocol/VariableWrite/VariableWrite.h | 41 + .../Dxe/ArchProtocol/WatchdogTimer/WatchdogTimer.c | 27 + .../Dxe/ArchProtocol/WatchdogTimer/WatchdogTimer.h | 206 ++ EDK/Foundation/Core/Dxe/Dispatcher/Dispatcher.c | 1203 ++++++++++ EDK/Foundation/Core/Dxe/Dispatcher/dependency.c | 451 ++++ EDK/Foundation/Core/Dxe/DxeMain.cif | 53 + EDK/Foundation/Core/Dxe/DxeMain.inf | 111 + EDK/Foundation/Core/Dxe/DxeMain/DxeMain.c | 1010 ++++++++ .../Core/Dxe/DxeMain/DxeProtocolNotify.c | 319 +++ EDK/Foundation/Core/Dxe/Event/event.c | 845 +++++++ EDK/Foundation/Core/Dxe/Event/exec.h | 209 ++ EDK/Foundation/Core/Dxe/Event/execdata.c | 50 + EDK/Foundation/Core/Dxe/Event/timer.c | 386 +++ EDK/Foundation/Core/Dxe/Event/tpl.c | 198 ++ EDK/Foundation/Core/Dxe/FwVol/Ffs.c | 266 ++ EDK/Foundation/Core/Dxe/FwVol/FwVol.c | 556 +++++ EDK/Foundation/Core/Dxe/FwVol/FwVolAttrib.c | 99 + EDK/Foundation/Core/Dxe/FwVol/FwVolDriver.h | 487 ++++ EDK/Foundation/Core/Dxe/FwVol/FwVolRead.c | 520 ++++ EDK/Foundation/Core/Dxe/FwVol/FwVolWrite.c | 60 + EDK/Foundation/Core/Dxe/FwVolBlock/FwVolBlock.c | 621 +++++ EDK/Foundation/Core/Dxe/FwVolBlock/FwVolBlock.h | 334 +++ EDK/Foundation/Core/Dxe/Gcd/gcd.c | 2509 +++++++++++++++++++ EDK/Foundation/Core/Dxe/Gcd/gcd.h | 54 + EDK/Foundation/Core/Dxe/Hand/DriverSupport.c | 860 +++++++ EDK/Foundation/Core/Dxe/Hand/Notify.c | 335 +++ EDK/Foundation/Core/Dxe/Hand/hand.h | 339 +++ EDK/Foundation/Core/Dxe/Hand/handle.c | 1716 +++++++++++++ EDK/Foundation/Core/Dxe/Hand/locate.c | 743 ++++++ EDK/Foundation/Core/Dxe/Ia32/Processor.h | 27 + EDK/Foundation/Core/Dxe/Image/Image.c | 1626 +++++++++++++ EDK/Foundation/Core/Dxe/Image/Image.h | 399 +++ EDK/Foundation/Core/Dxe/Image/ImageFile.c | 646 +++++ EDK/Foundation/Core/Dxe/Include/DxeCore.h | 2535 ++++++++++++++++++++ EDK/Foundation/Core/Dxe/Include/Library.h | 531 ++++ EDK/Foundation/Core/Dxe/Ipf/Processor.h | 27 + EDK/Foundation/Core/Dxe/Library/Library.c | 878 +++++++ EDK/Foundation/Core/Dxe/Mem/Page.c | 1648 +++++++++++++ EDK/Foundation/Core/Dxe/Mem/imem.h | 214 ++ EDK/Foundation/Core/Dxe/Mem/memdata.c | 41 + EDK/Foundation/Core/Dxe/Mem/pool.c | 613 +++++ EDK/Foundation/Core/Dxe/Misc/DebugImageInfo.c | 262 ++ EDK/Foundation/Core/Dxe/Misc/DebugImageInfo.h | 129 + EDK/Foundation/Core/Dxe/Misc/DebugMask.c | 400 +++ EDK/Foundation/Core/Dxe/Misc/DebugMask.h | 122 + .../Core/Dxe/Misc/InstallConfigurationTable.c | 230 ++ EDK/Foundation/Core/Dxe/Misc/SetWatchdogTimer.c | 84 + EDK/Foundation/Core/Dxe/Misc/Stall.c | 79 + .../Dxe/SectionExtraction/CoreSectionExtraction.c | 1387 +++++++++++ EDK/Foundation/Core/Dxe/x64/Processor.h | 27 + 79 files changed, 28455 insertions(+) create mode 100644 EDK/Foundation/Core/Dxe/ArchProtocol/ArchProtocolLib.cif create mode 100644 EDK/Foundation/Core/Dxe/ArchProtocol/ArchProtocolLib.inf create mode 100644 EDK/Foundation/Core/Dxe/ArchProtocol/ArchProtocolLib.mak create mode 100644 EDK/Foundation/Core/Dxe/ArchProtocol/ArchProtocolLib.sdl create mode 100644 EDK/Foundation/Core/Dxe/ArchProtocol/Bds/Bds.c create mode 100644 EDK/Foundation/Core/Dxe/ArchProtocol/Bds/Bds.h create mode 100644 EDK/Foundation/Core/Dxe/ArchProtocol/Capsule/Capsule.c create mode 100644 EDK/Foundation/Core/Dxe/ArchProtocol/Capsule/Capsule.h create mode 100644 EDK/Foundation/Core/Dxe/ArchProtocol/Cpu/Cpu.c create mode 100644 EDK/Foundation/Core/Dxe/ArchProtocol/Cpu/Cpu.h create mode 100644 EDK/Foundation/Core/Dxe/ArchProtocol/Metronome/Metronome.c create mode 100644 EDK/Foundation/Core/Dxe/ArchProtocol/Metronome/Metronome.h create mode 100644 EDK/Foundation/Core/Dxe/ArchProtocol/MonotonicCounter/MonotonicCounter.c create mode 100644 EDK/Foundation/Core/Dxe/ArchProtocol/MonotonicCounter/MonotonicCounter.h create mode 100644 EDK/Foundation/Core/Dxe/ArchProtocol/RealTimeClock/RealTimeClock.c create mode 100644 EDK/Foundation/Core/Dxe/ArchProtocol/RealTimeClock/RealTimeClock.h create mode 100644 EDK/Foundation/Core/Dxe/ArchProtocol/Reset/Reset.c create mode 100644 EDK/Foundation/Core/Dxe/ArchProtocol/Reset/Reset.h create mode 100644 EDK/Foundation/Core/Dxe/ArchProtocol/Runtime/Runtime.c create mode 100644 EDK/Foundation/Core/Dxe/ArchProtocol/Runtime/Runtime.h create mode 100644 EDK/Foundation/Core/Dxe/ArchProtocol/Security/Security.c create mode 100644 EDK/Foundation/Core/Dxe/ArchProtocol/Security/Security.h create mode 100644 EDK/Foundation/Core/Dxe/ArchProtocol/StatusCode/StatusCode.c create mode 100644 EDK/Foundation/Core/Dxe/ArchProtocol/StatusCode/StatusCode.h create mode 100644 EDK/Foundation/Core/Dxe/ArchProtocol/Timer/Timer.c create mode 100644 EDK/Foundation/Core/Dxe/ArchProtocol/Timer/Timer.h create mode 100644 EDK/Foundation/Core/Dxe/ArchProtocol/Variable/Variable.c create mode 100644 EDK/Foundation/Core/Dxe/ArchProtocol/Variable/Variable.h create mode 100644 EDK/Foundation/Core/Dxe/ArchProtocol/VariableWrite/VariableWrite.c create mode 100644 EDK/Foundation/Core/Dxe/ArchProtocol/VariableWrite/VariableWrite.h create mode 100644 EDK/Foundation/Core/Dxe/ArchProtocol/WatchdogTimer/WatchdogTimer.c create mode 100644 EDK/Foundation/Core/Dxe/ArchProtocol/WatchdogTimer/WatchdogTimer.h create mode 100644 EDK/Foundation/Core/Dxe/Dispatcher/Dispatcher.c create mode 100644 EDK/Foundation/Core/Dxe/Dispatcher/dependency.c create mode 100644 EDK/Foundation/Core/Dxe/DxeMain.cif create mode 100644 EDK/Foundation/Core/Dxe/DxeMain.inf create mode 100644 EDK/Foundation/Core/Dxe/DxeMain/DxeMain.c create mode 100644 EDK/Foundation/Core/Dxe/DxeMain/DxeProtocolNotify.c create mode 100644 EDK/Foundation/Core/Dxe/Event/event.c create mode 100644 EDK/Foundation/Core/Dxe/Event/exec.h create mode 100644 EDK/Foundation/Core/Dxe/Event/execdata.c create mode 100644 EDK/Foundation/Core/Dxe/Event/timer.c create mode 100644 EDK/Foundation/Core/Dxe/Event/tpl.c create mode 100644 EDK/Foundation/Core/Dxe/FwVol/Ffs.c create mode 100644 EDK/Foundation/Core/Dxe/FwVol/FwVol.c create mode 100644 EDK/Foundation/Core/Dxe/FwVol/FwVolAttrib.c create mode 100644 EDK/Foundation/Core/Dxe/FwVol/FwVolDriver.h create mode 100644 EDK/Foundation/Core/Dxe/FwVol/FwVolRead.c create mode 100644 EDK/Foundation/Core/Dxe/FwVol/FwVolWrite.c create mode 100644 EDK/Foundation/Core/Dxe/FwVolBlock/FwVolBlock.c create mode 100644 EDK/Foundation/Core/Dxe/FwVolBlock/FwVolBlock.h create mode 100644 EDK/Foundation/Core/Dxe/Gcd/gcd.c create mode 100644 EDK/Foundation/Core/Dxe/Gcd/gcd.h create mode 100644 EDK/Foundation/Core/Dxe/Hand/DriverSupport.c create mode 100644 EDK/Foundation/Core/Dxe/Hand/Notify.c create mode 100644 EDK/Foundation/Core/Dxe/Hand/hand.h create mode 100644 EDK/Foundation/Core/Dxe/Hand/handle.c create mode 100644 EDK/Foundation/Core/Dxe/Hand/locate.c create mode 100644 EDK/Foundation/Core/Dxe/Ia32/Processor.h create mode 100644 EDK/Foundation/Core/Dxe/Image/Image.c create mode 100644 EDK/Foundation/Core/Dxe/Image/Image.h create mode 100644 EDK/Foundation/Core/Dxe/Image/ImageFile.c create mode 100644 EDK/Foundation/Core/Dxe/Include/DxeCore.h create mode 100644 EDK/Foundation/Core/Dxe/Include/Library.h create mode 100644 EDK/Foundation/Core/Dxe/Ipf/Processor.h create mode 100644 EDK/Foundation/Core/Dxe/Library/Library.c create mode 100644 EDK/Foundation/Core/Dxe/Mem/Page.c create mode 100644 EDK/Foundation/Core/Dxe/Mem/imem.h create mode 100644 EDK/Foundation/Core/Dxe/Mem/memdata.c create mode 100644 EDK/Foundation/Core/Dxe/Mem/pool.c create mode 100644 EDK/Foundation/Core/Dxe/Misc/DebugImageInfo.c create mode 100644 EDK/Foundation/Core/Dxe/Misc/DebugImageInfo.h create mode 100644 EDK/Foundation/Core/Dxe/Misc/DebugMask.c create mode 100644 EDK/Foundation/Core/Dxe/Misc/DebugMask.h create mode 100644 EDK/Foundation/Core/Dxe/Misc/InstallConfigurationTable.c create mode 100644 EDK/Foundation/Core/Dxe/Misc/SetWatchdogTimer.c create mode 100644 EDK/Foundation/Core/Dxe/Misc/Stall.c create mode 100644 EDK/Foundation/Core/Dxe/SectionExtraction/CoreSectionExtraction.c create mode 100644 EDK/Foundation/Core/Dxe/x64/Processor.h (limited to 'EDK/Foundation/Core/Dxe') diff --git a/EDK/Foundation/Core/Dxe/ArchProtocol/ArchProtocolLib.cif b/EDK/Foundation/Core/Dxe/ArchProtocol/ArchProtocolLib.cif new file mode 100644 index 0000000..de96301 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/ArchProtocol/ArchProtocolLib.cif @@ -0,0 +1,38 @@ + + name = "ArchProtocolLib" + category = ModulePart + LocalRoot = "EDK\Foundation\Core\Dxe\ArchProtocol" + RefName = "ArchProtocolLib" +[files] +"ArchProtocolLib.sdl" +"ArchProtocolLib.mak" +"Bds\Bds.c" +"Bds\Bds.h" +"Capsule\Capsule.c" +"Capsule\Capsule.h" +"Cpu\Cpu.c" +"Cpu\Cpu.h" +"Metronome\Metronome.c" +"Metronome\Metronome.h" +"MonotonicCounter\MonotonicCounter.c" +"MonotonicCounter\MonotonicCounter.h" +"RealTimeClock\RealTimeClock.c" +"RealTimeClock\RealTimeClock.h" +"Reset\Reset.c" +"Reset\Reset.h" +"Runtime\Runtime.c" +"Runtime\Runtime.h" +"Security\Security.c" +"Security\Security.h" +"StatusCode\StatusCode.c" +"StatusCode\StatusCode.h" +"Timer\Timer.c" +"Timer\Timer.h" +"Variable\Variable.c" +"Variable\Variable.h" +"VariableWrite\VariableWrite.c" +"VariableWrite\VariableWrite.h" +"WatchdogTimer\WatchdogTimer.c" +"WatchdogTimer\WatchdogTimer.h" +"ArchProtocolLib.inf" + diff --git a/EDK/Foundation/Core/Dxe/ArchProtocol/ArchProtocolLib.inf b/EDK/Foundation/Core/Dxe/ArchProtocol/ArchProtocolLib.inf new file mode 100644 index 0000000..705c606 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/ArchProtocol/ArchProtocolLib.inf @@ -0,0 +1,65 @@ +#/*++ +# +# Copyright (c) 2004 - 2006, Intel Corporation +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# Module Name: +# +# ArchProtocolLib.inf +# +# Abstract: +# +# Component description file for the Architectural Protocol Library. +# +#--*/ + +[defines] +BASE_NAME = ArchProtocolLib +COMPONENT_TYPE = LIBRARY + +[sources.common] + Bds\Bds.c + Bds\Bds.h + Capsule\Capsule.c + Capsule\Capsule.h + Cpu\Cpu.c + Cpu\Cpu.h + Metronome\Metronome.c + Metronome\Metronome.h + MonotonicCounter\MonotonicCounter.c + MonotonicCounter\MonotonicCounter.h + RealTimeClock\RealTimeClock.c + RealTimeClock\RealTimeClock.h + Reset\Reset.c + Reset\Reset.h + Runtime\Runtime.c + Runtime\Runtime.h + Security\Security.c + Security\Security.h + StatusCode\StatusCode.c + StatusCode\StatusCode.h + Timer\Timer.c + Timer\Timer.h + Variable\Variable.c + Variable\Variable.h + VariableWrite\VariableWrite.c + VariableWrite\VariableWrite.h + WatchdogTimer\WatchdogTimer.c + WatchdogTimer\WatchdogTimer.h + +[includes.common] + $(EDK_SOURCE)\Foundation\Efi + $(EDK_SOURCE)\Foundation\Include + $(EDK_SOURCE)\Foundation\Efi\Include + $(EDK_SOURCE)\Foundation\Framework\Include + $(EDK_SOURCE)\Foundation\Include\IndustryStandard + $(EDK_SOURCE)\Foundation\Core\Dxe + $(EDK_SOURCE)\Foundation\Library\Dxe\Include + +[nmake.common] diff --git a/EDK/Foundation/Core/Dxe/ArchProtocol/ArchProtocolLib.mak b/EDK/Foundation/Core/Dxe/ArchProtocol/ArchProtocolLib.mak new file mode 100644 index 0000000..5a37110 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/ArchProtocol/ArchProtocolLib.mak @@ -0,0 +1,69 @@ +#********************************************************************** +#********************************************************************** +#** ** +#** (C)Copyright 1985-2009, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#********************************************************************** +#********************************************************************** + +#********************************************************************** +# $Header: /Alaska/SOURCE/Modules/SharkBayRefCodes/IntelEDK/ArchProtocolLib/ArchProtocolLib.mak 1 1/20/12 4:12a Jeffch $ +# +# $Revision: 1 $ +# +# $Date: 1/20/12 4:12a $ +#********************************************************************** +# Revision History +# ---------------- +# $Log: /Alaska/SOURCE/Modules/SharkBayRefCodes/IntelEDK/ArchProtocolLib/ArchProtocolLib.mak $ +# +# 1 1/20/12 4:12a Jeffch +# Create Intel EDK 1117 Patch 7. +# +# 1 9/27/11 6:34a Wesleychen +# Intel EDK initially releases. +# +# 2 9/02/09 3:06a Iminglin +# EIP24919 +# +#********************************************************************** +# +# +# Name: ArchProtocolLib.mak +# +# Description: +# +# +#********************************************************************** +$(ARCHPROTOCOLLIB) : ArchProtocolLib + +$(BUILD_DIR)\ArchProtocolLib.lib : ArchProtocolLib + +ArchProtocolLib : $(BUILD_DIR)\ArchProtocolLib.mak ArchProtocolLibBin + +$(BUILD_DIR)\ArchProtocolLib.mak : $(ArchProtocolLib_DIR)\$(@B).cif $(ArchProtocolLib_DIR)\$(@B).mak $(BUILD_RULES) + $(CIF2MAK) $(ArchProtocolLib_DIR)\$(@B).cif $(CIF2MAK_DEFAULTS) + +ArchProtocolLibBin : + $(MAKE) /$(MAKEFLAGS) $(EDK_DEFAULTS)\ + /f $(BUILD_DIR)\ArchProtocolLib.mak all\ + TYPE=LIBRARY \ +#********************************************************************** +#********************************************************************** +#** ** +#** (C)Copyright 1985-2009, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#********************************************************************** +#********************************************************************** \ No newline at end of file diff --git a/EDK/Foundation/Core/Dxe/ArchProtocol/ArchProtocolLib.sdl b/EDK/Foundation/Core/Dxe/ArchProtocol/ArchProtocolLib.sdl new file mode 100644 index 0000000..f758364 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/ArchProtocol/ArchProtocolLib.sdl @@ -0,0 +1,26 @@ +TOKEN + Name = "ArchProtocolLib_SUPPORT" + Value = "1" + Help = "Main switch to enable ArchProtocolLib support in Project" + TokenType = Boolean + TargetEQU = Yes + TargetMAK = Yes + Master = Yes +End + +TOKEN + Name = "ARCHPROTOCOLLIB" + Value = "$(BUILD_DIR)\ArchProtocolLib.lib" + TokenType = Expression + TargetMAK = Yes +End + +PATH + Name = "ArchProtocolLib_DIR" +End + +MODULE + Help = "Includes ArchProtocolLib.mak to Project" + File = "ArchProtocolLib.mak" +End + diff --git a/EDK/Foundation/Core/Dxe/ArchProtocol/Bds/Bds.c b/EDK/Foundation/Core/Dxe/ArchProtocol/Bds/Bds.c new file mode 100644 index 0000000..5bd71bf --- /dev/null +++ b/EDK/Foundation/Core/Dxe/ArchProtocol/Bds/Bds.c @@ -0,0 +1,27 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Bds.c + +Abstract: + + Boot Device Selection Architectural Protocol GUID as defined in Tiano + +--*/ + +#include "Tiano.h" +#include EFI_ARCH_PROTOCOL_DEFINITION (Bds) + +EFI_GUID gEfiBdsArchProtocolGuid = EFI_BDS_ARCH_PROTOCOL_GUID; + +EFI_GUID_STRING(&gEfiBdsArchProtocolGuid, "BDS", "BDS Arch Protocol"); diff --git a/EDK/Foundation/Core/Dxe/ArchProtocol/Bds/Bds.h b/EDK/Foundation/Core/Dxe/ArchProtocol/Bds/Bds.h new file mode 100644 index 0000000..a1282df --- /dev/null +++ b/EDK/Foundation/Core/Dxe/ArchProtocol/Bds/Bds.h @@ -0,0 +1,100 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Bds.h + +Abstract: + + Boot Device Selection Architectural Protocol as defined in Tiano + + When the DXE core is done it calls the BDS via this protocol. + +--*/ + +#ifndef _ARCH_PROTOCOL_BDS_H_ +#define _ARCH_PROTOCOL_BDS_H_ + +// +// Global ID for the BDS Architectural Protocol +// +#define EFI_BDS_ARCH_PROTOCOL_GUID \ + { 0x665E3FF6, 0x46CC, 0x11d4, 0x9A, 0x38, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D } + +// +// Declare forward reference for the BDS Architectural Protocol +// +EFI_FORWARD_DECLARATION (EFI_BDS_ARCH_PROTOCOL); + +typedef +VOID +(EFIAPI *EFI_BDS_ENTRY) ( + IN EFI_BDS_ARCH_PROTOCOL * This + ); +/*++ + +Routine Description: + + This function uses policy data from the platform to determine what operating + system or system utility should be loaded and invoked. This function call + also optionally make the use of user input to determine the operating system + or system utility to be loaded and invoked. When the DXE Core has dispatched + all the drivers on the dispatch queue, this function is called. This + function will attempt to connect the boot devices required to load and invoke + the selected operating system or system utility. During this process, + additional firmware volumes may be discovered that may contain addition DXE + drivers that can be dispatched by the DXE Core. If a boot device cannot be + fully connected, this function calls the DXE Service Dispatch() to allow the + DXE drivers from any newly discovered firmware volumes to be dispatched. + Then the boot device connection can be attempted again. If the same boot + device connection operation fails twice in a row, then that boot device has + failed, and should be skipped. This function should never return. + +Arguments: + + This - The EFI_BDS_ARCH_PROTOCOL instance. + +Returns: + + None. + +--*/ + +// +// Interface stucture for the BDS Architectural Protocol +// +typedef struct _EFI_BDS_ARCH_PROTOCOL { + EFI_BDS_ENTRY Entry; +} EFI_BDS_ARCH_PROTOCOL; + +/*++ + + Protocol Description: + The EFI_BDS_ARCH_PROTOCOL transfers control from DXE to an operating + system or a system utility. If there are not enough drivers initialized + when this protocol is used to access the required boot device(s), then + this protocol should add drivers to the dispatch queue and return control + back to the dispatcher. Once the required boot devices are available, then + the boot device can be used to load and invoke an OS or a system utility. + + Parameters: + + Entry - The entry point to BDS. This call does not take any parameters, + and the return value can be ignored. If it returns, then the + dispatcher must be invoked again, if it never returns, then an + operating system or a system utility have been invoked. + +--*/ + +extern EFI_GUID gEfiBdsArchProtocolGuid; + +#endif diff --git a/EDK/Foundation/Core/Dxe/ArchProtocol/Capsule/Capsule.c b/EDK/Foundation/Core/Dxe/ArchProtocol/Capsule/Capsule.c new file mode 100644 index 0000000..42673a2 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/ArchProtocol/Capsule/Capsule.c @@ -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: + + Capsule.c + +Abstract: + + Capsule Architectural Protocol is used to produce the UEFI 2.0 capsule runtime services + +--*/ + +#include "Tiano.h" +#include EFI_ARCH_PROTOCOL_DEFINITION (Capsule) + +EFI_GUID gEfiCapsuleArchProtocolGuid = EFI_CAPSULE_ARCH_PROTOCOL_GUID; + +EFI_GUID_STRING(&gEfiCapsuleArchProtocolGuid, "Capsule", "Capsule Arch Protocol"); diff --git a/EDK/Foundation/Core/Dxe/ArchProtocol/Capsule/Capsule.h b/EDK/Foundation/Core/Dxe/ArchProtocol/Capsule/Capsule.h new file mode 100644 index 0000000..2e11f83 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/ArchProtocol/Capsule/Capsule.h @@ -0,0 +1,33 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Capsule.h + +Abstract: + + Capsule Architectural Protocol is newly added to produce UEFI2.0 capsule runtime services. + +--*/ + +#ifndef _ARCH_PROTOCOL_CAPSULE_ARCH_H_ +#define _ARCH_PROTOCOL_CAPSULE_ARCH_H_ + +// +// Global ID for the Capsule Architectural Protocol +// +#define EFI_CAPSULE_ARCH_PROTOCOL_GUID \ + { 0x5053697e, 0x2cbc, 0x4819, 0x90, 0xd9, 0x5, 0x80, 0xde, 0xee, 0x57, 0x54 } + +extern EFI_GUID gEfiCapsuleArchProtocolGuid; + +#endif diff --git a/EDK/Foundation/Core/Dxe/ArchProtocol/Cpu/Cpu.c b/EDK/Foundation/Core/Dxe/ArchProtocol/Cpu/Cpu.c new file mode 100644 index 0000000..40dbb06 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/ArchProtocol/Cpu/Cpu.c @@ -0,0 +1,28 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Cpu.c + +Abstract: + + CPU Architectural Protocol GUID as defined in Tiano + + +--*/ + +#include "Tiano.h" +#include EFI_ARCH_PROTOCOL_DEFINITION (Cpu) + +EFI_GUID gEfiCpuArchProtocolGuid = EFI_CPU_ARCH_PROTOCOL_GUID; + +EFI_GUID_STRING(&gEfiCpuArchProtocolGuid, "CPU", "CPU Arch Protocol"); diff --git a/EDK/Foundation/Core/Dxe/ArchProtocol/Cpu/Cpu.h b/EDK/Foundation/Core/Dxe/ArchProtocol/Cpu/Cpu.h new file mode 100644 index 0000000..fdc426b --- /dev/null +++ b/EDK/Foundation/Core/Dxe/ArchProtocol/Cpu/Cpu.h @@ -0,0 +1,361 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Cpu.h + +Abstract: + + CPU Architectural Protocol as defined in Tiano + + This code abstracts the DXE core from processor implementation details. + +--*/ + +#ifndef _ARCH_PROTOCOL_CPU_H_ +#define _ARCH_PROTOCOL_CPU_H_ + +#include EFI_PROTOCOL_DEFINITION (DebugSupport) + +#define EFI_CPU_ARCH_PROTOCOL_GUID \ + { 0x26baccb1, 0x6f42, 0x11d4, 0xbc, 0xe7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } + +EFI_FORWARD_DECLARATION (EFI_CPU_ARCH_PROTOCOL); + +typedef enum { + EfiCpuFlushTypeWriteBackInvalidate, + EfiCpuFlushTypeWriteBack, + EfiCpuFlushTypeInvalidate, + EfiCpuMaxFlushType +} EFI_CPU_FLUSH_TYPE; + +typedef enum { + EfiCpuInit, + EfiCpuMaxInitType +} EFI_CPU_INIT_TYPE; + +typedef +VOID +(*EFI_CPU_INTERRUPT_HANDLER) ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_SYSTEM_CONTEXT SystemContext + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_CPU_FLUSH_DATA_CACHE) ( + IN EFI_CPU_ARCH_PROTOCOL * This, + IN EFI_PHYSICAL_ADDRESS Start, + IN UINT64 Length, + IN EFI_CPU_FLUSH_TYPE FlushType + ); + +/*++ + +Routine Description: + + This function flushes the range of addresses from Start to Start+Length + from the processor's data cache. If Start is not aligned to a cache line + boundary, then the bytes before Start to the preceding cache line boundary + are also flushed. If Start+Length is not aligned to a cache line boundary, + then the bytes past Start+Length to the end of the next cache line boundary + are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate must be + supported. If the data cache is fully coherent with all DMA operations, then + this function can just return EFI_SUCCESS. If the processor does not support + flushing a range of the data cache, then the entire data cache can be flushed. + +Arguments: + + This - The EFI_CPU_ARCH_PROTOCOL instance. + Start - The beginning physical address to flush from the processor's data + cache. + Length - The number of bytes to flush from the processor's data cache. This + function may flush more bytes than Length specifies depending upon + the granularity of the flush operation that the processor supports. + FlushType - Specifies the type of flush operation to perform. + +Returns: + + EFI_SUCCESS - The address range from Start to Start+Length was flushed from + the processor's data cache. + EFI_UNSUPPORTEDT - The processor does not support the cache flush type specified + by FlushType. + EFI_DEVICE_ERROR - The address range from Start to Start+Length could not be flushed + from the processor's data cache. + +--*/ + +typedef +EFI_STATUS +(EFIAPI *EFI_CPU_ENABLE_INTERRUPT) ( + IN EFI_CPU_ARCH_PROTOCOL * This + ); + +/*++ + +Routine Description: + + This function enables interrupt processing by the processor. + +Arguments: + + This - The EFI_CPU_ARCH_PROTOCOL instance. + +Returns: + + EFI_SUCCESS - Interrupts are enabled on the processor. + EFI_DEVICE_ERROR - Interrupts could not be enabled on the processor. + +--*/ + +typedef +EFI_STATUS +(EFIAPI *EFI_CPU_DISABLE_INTERRUPT) ( + IN EFI_CPU_ARCH_PROTOCOL * This + ); + +/*++ + +Routine Description: + + This function disables interrupt processing by the processor. + +Arguments: + + This - The EFI_CPU_ARCH_PROTOCOL instance. + +Returns: + + EFI_SUCCESS - Interrupts are disabled on the processor. + EFI_DEVICE_ERROR - Interrupts could not be disabled on the processor. + +--*/ + +typedef +EFI_STATUS +(EFIAPI *EFI_CPU_GET_INTERRUPT_STATE) ( + IN EFI_CPU_ARCH_PROTOCOL * This, + OUT BOOLEAN *State + ); + +/*++ + +Routine Description: + + This function retrieves the processor's current interrupt state a returns it in + State. If interrupts are currently enabled, then TRUE is returned. If interrupts + are currently disabled, then FALSE is returned. + +Arguments: + + This - The EFI_CPU_ARCH_PROTOCOL instance. + State - A pointer to the processor's current interrupt state. Set to TRUE if + interrupts are enabled and FALSE if interrupts are disabled. +Returns: + + EFI_SUCCESS - The processor's current interrupt state was returned in State. + EFI_INVALID_PARAMETER - State is NULL. + +--*/ + +typedef +EFI_STATUS +(EFIAPI *EFI_CPU_INIT) ( + IN EFI_CPU_ARCH_PROTOCOL * This, + IN EFI_CPU_INIT_TYPE InitType + ); + +/*++ + +Routine Description: + + This function generates an INIT on the processor. If this function succeeds, then the + processor will be reset, and control will not be returned to the caller. If InitType is + not supported by this processor, or the processor cannot programmatically generate an + INIT without help from external hardware, then EFI_UNSUPPORTED is returned. If an error + occurs attempting to generate an INIT, then EFI_DEVICE_ERROR is returned. + +Arguments: + + This - The EFI_CPU_ARCH_PROTOCOL instance. + InitType - The type of processor INIT to perform. + +Returns: + + EFI_SUCCESS - The processor INIT was performed. This return code should never be seen. + EFI_UNSUPPORTED - The processor INIT operation specified by InitType is not supported + by this processor. + EFI_DEVICE_ERROR - The processor INIT failed. + +--*/ + +typedef +EFI_STATUS +(EFIAPI *EFI_CPU_REGISTER_INTERRUPT_HANDLER) ( + IN EFI_CPU_ARCH_PROTOCOL * This, + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler + ); + +/*++ + +Routine Description: + + This function registers and enables the handler specified by InterruptHandler for a processor + interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the + handler for the processor interrupt or exception type specified by InterruptType is uninstalled. + The installed handler is called once for each processor interrupt or exception. + +Arguments: + + This - The EFI_CPU_ARCH_PROTOCOL instance. + InterruptType - A pointer to the processor's current interrupt state. Set to TRUE if interrupts + are enabled and FALSE if interrupts are disabled. + InterruptHandler - A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called + when a processor interrupt occurs. If this parameter is NULL, then the handler + will be uninstalled. +Returns: + + EFI_SUCCESS - The handler for the processor interrupt was successfully installed or uninstalled. + EFI_ALREADY_STARTED - InterruptHandler is not NULL, and a handler for InterruptType was + previously installed. + EFI_INVALID_PARAMETER - InterruptHandler is NULL, and a handler for InterruptType was not + previously installed. + EFI_UNSUPPORTED - The interrupt specified by InterruptType is not supported. + +--*/ + +typedef +EFI_STATUS +(EFIAPI *EFI_CPU_GET_TIMER_VALUE) ( + IN EFI_CPU_ARCH_PROTOCOL * This, + IN UINT32 TimerIndex, + OUT UINT64 *TimerValue, + OUT UINT64 *TimerPeriod OPTIONAL + ); + +/*++ + +Routine Description: + + This function reads the processor timer specified by TimerIndex and returns it in TimerValue. + +Arguments: + + This - The EFI_CPU_ARCH_PROTOCOL instance. + TimerIndex - Specifies which processor timer is to be returned in TimerValue. This parameter + must be between 0 and NumberOfTimers-1. + TimerValue - Pointer to the returned timer value. + TimerPeriod - A pointer to the amount of time that passes in femtoseconds for each increment + of TimerValue. +Returns: + + EFI_SUCCESS - The processor timer value specified by TimerIndex was returned in TimerValue. + EFI_DEVICE_ERROR - An error occurred attempting to read one of the processor's timers. + EFI_INVALID_PARAMETER - TimerValue is NULL or TimerIndex is not valid. + EFI_UNSUPPORTED - The processor does not have any readable timers. + +--*/ + +typedef +EFI_STATUS +(EFIAPI *EFI_CPU_SET_MEMORY_ATTRIBUTES) ( + IN EFI_CPU_ARCH_PROTOCOL * This, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Attributes + ); + +/*++ + +Routine Description: + + This function modifies the attributes for the memory region specified by BaseAddress and + Length from their current attributes to the attributes specified by Attributes. + +Arguments: + + This - The EFI_CPU_ARCH_PROTOCOL instance. + BaseAddress - The physical address that is the start address of a memory region. + Length - The size in bytes of the memory region. + Attributes - The bit mask of attributes to set for the memory region. + +Returns: + + EFI_SUCCESS - The attributes were set for the memory region. + EFI_ACCESS_DENIED - The attributes for the memory resource range specified by + BaseAddress and Length cannot be modified. + EFI_INVALID_PARAMETER - Length is zero. + EFI_OUT_OF_RESOURCES - There are not enough system resources to modify the attributes of + the memory resource range. + EFI_UNSUPPORTED - The processor does not support one or more bytes of the memory + resource range specified by BaseAddress and Length. + The bit mask of attributes is not support for the memory resource + range specified by BaseAddress and Length. + +--*/ + +typedef struct _EFI_CPU_ARCH_PROTOCOL { + EFI_CPU_FLUSH_DATA_CACHE FlushDataCache; + EFI_CPU_ENABLE_INTERRUPT EnableInterrupt; + EFI_CPU_DISABLE_INTERRUPT DisableInterrupt; + EFI_CPU_GET_INTERRUPT_STATE GetInterruptState; + EFI_CPU_INIT Init; + EFI_CPU_REGISTER_INTERRUPT_HANDLER RegisterInterruptHandler; + EFI_CPU_GET_TIMER_VALUE GetTimerValue; + EFI_CPU_SET_MEMORY_ATTRIBUTES SetMemoryAttributes; + UINT32 NumberOfTimers; + UINT32 DmaBufferAlignment; +} EFI_CPU_ARCH_PROTOCOL; + +/*++ + +Protocol Description: + + The EFI_CPU_ARCH_PROTOCOL is used to abstract processor-specific functions from the DXE + Foundation. This includes flushing caches, enabling and disabling interrupts, hooking interrupt + vectors and exception vectors, reading internal processor timers, resetting the processor, and + determining the processor frequency. + +Parameters: + + FlushDataCache - Flushes a range of the processor's data cache. If the processor does + not contain a data cache, or the data cache is fully coherent, then this + function can just return EFI_SUCCESS. If the processor does not support + flushing a range of addresses from the data cache, then the entire data + cache must be flushed. + EnableInterrupt - Enables interrupt processing by the processor. + DisableInterrupt - Disables interrupt processing by the processor. + GetInterruptState - Retrieves the processor's current interrupt state. + Init - Generates an INIT on the processor. If a processor cannot programmatically + generate an INIT without help from external hardware, then this function + returns EFI_UNSUPPORTED. + RegisterInterruptHandler - Associates an interrupt service routine with one of the processor's interrupt + vectors. This function is typically used by the EFI_TIMER_ARCH_PROTOCOL to + hook the timer interrupt in a system. It can also be used by the debugger to + hook exception vectors. + GetTimerValue - Returns the value of one of the processor's internal timers. + SetMemoryAttributes - Attempts to set the attributes of a memory region. + NumberOfTimers - The number of timers that are available in a processor. The value in this + field is a constant that must not be modified after the CPU Architectural + Protocol is installed. All consumers must treat this as a read-only field. + DmaBufferAlignment - The size, in bytes, of the alignment required for DMA buffer allocations. + This is typically the size of the largest data cache line in the platform. + The value in this field is a constant that must not be modified after the + CPU Architectural Protocol is installed. All consumers must treat this as + a read-only field. + +--*/ + +extern EFI_GUID gEfiCpuArchProtocolGuid; + +#endif diff --git a/EDK/Foundation/Core/Dxe/ArchProtocol/Metronome/Metronome.c b/EDK/Foundation/Core/Dxe/ArchProtocol/Metronome/Metronome.c new file mode 100644 index 0000000..a09a0d5 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/ArchProtocol/Metronome/Metronome.c @@ -0,0 +1,27 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Metronome.c + +Abstract: + + Metronome Architectural Protocol as defined in Tiano + +--*/ + +#include "Tiano.h" +#include EFI_ARCH_PROTOCOL_DEFINITION (Metronome) + +EFI_GUID gEfiMetronomeArchProtocolGuid = EFI_METRONOME_ARCH_PROTOCOL_GUID; + +EFI_GUID_STRING(&gEfiMetronomeArchProtocolGuid, "Metronome", "Metronome Arch Protocol"); diff --git a/EDK/Foundation/Core/Dxe/ArchProtocol/Metronome/Metronome.h b/EDK/Foundation/Core/Dxe/ArchProtocol/Metronome/Metronome.h new file mode 100644 index 0000000..c254d9b --- /dev/null +++ b/EDK/Foundation/Core/Dxe/ArchProtocol/Metronome/Metronome.h @@ -0,0 +1,109 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Metronome.h + +Abstract: + + Metronome Architectural Protocol as defined in DXE CIS + + This code abstracts the DXE core to provide delay services. + +--*/ + +#ifndef _ARCH_PROTOCOL_METRONOME_H_ +#define _ARCH_PROTOCOL_METRONOME_H_ + +// +// Global ID for the Metronome Architectural Protocol +// +#define EFI_METRONOME_ARCH_PROTOCOL_GUID \ + { 0x26baccb2, 0x6f42, 0x11d4, 0xbc, 0xe7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } + +// +// Declare forward reference for the Metronome Architectural Protocol +// +EFI_FORWARD_DECLARATION (EFI_METRONOME_ARCH_PROTOCOL); + +typedef +EFI_STATUS +(EFIAPI *EFI_METRONOME_WAIT_FOR_TICK) ( + IN EFI_METRONOME_ARCH_PROTOCOL *This, + IN UINT32 TickNumber + ); +/*++ + +Routine Description: + + The WaitForTick() function waits for the number of ticks specified by + TickNumber from a known time source in the platform. If TickNumber of + ticks are detected, then EFI_SUCCESS is returned. The actual time passed + between entry of this function and the first tick is between 0 and + TickPeriod 100 nS units. If you want to guarantee that at least TickPeriod + time has elapsed, wait for two ticks. This function waits for a hardware + event to determine when a tick occurs. It is possible for interrupt + processing, or exception processing to interrupt the execution of the + WaitForTick() function. Depending on the hardware source for the ticks, it + is possible for a tick to be missed. This function cannot guarantee that + ticks will not be missed. If a timeout occurs waiting for the specified + number of ticks, then EFI_TIMEOUT is returned. + +Arguments: + + This - The EFI_METRONOME_ARCH_PROTOCOL instance. + + TickNumber - Number of ticks to wait. + +Returns: + + EFI_SUCCESS - The wait for the number of ticks specified by TickNumber + succeeded. + + EFI_TIMEOUT - A timeout occurred waiting for the specified number of ticks. + +--*/ + +// +// Interface stucture for the Metronome Architectural Protocol +// +typedef struct _EFI_METRONOME_ARCH_PROTOCOL { + EFI_METRONOME_WAIT_FOR_TICK WaitForTick; + UINT32 TickPeriod; +} EFI_METRONOME_ARCH_PROTOCOL; + +/*++ + + Protocol Description: + This protocol provides access to a known time source in the platform to the + core. The core uses this known time source to produce core services that + require calibrated delays. + + Parameters: + + WaitForTick - Waits for a specified number of ticks from a known time source + in the platform. The actual time passed between entry of this + function and the first tick is between 0 and TickPeriod 100 nS + units. If you want to guarantee that at least TickPeriod time + has elapsed, wait for two ticks. + + TickPeriod - The period of platform's known time source in 100 nS units. + This value on any platform must be at least 10 uS, and must not + exceed 200 uS. The value in this field is a constant that must + not be modified after the Metronome architectural protocol is + installed. All consumers must treat this as a read-only field. + +--*/ + +extern EFI_GUID gEfiMetronomeArchProtocolGuid; + +#endif diff --git a/EDK/Foundation/Core/Dxe/ArchProtocol/MonotonicCounter/MonotonicCounter.c b/EDK/Foundation/Core/Dxe/ArchProtocol/MonotonicCounter/MonotonicCounter.c new file mode 100644 index 0000000..54d9ca4 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/ArchProtocol/MonotonicCounter/MonotonicCounter.c @@ -0,0 +1,27 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + MonotonicCounter.c + +Abstract: + + Monotonic Counter Architectural Protocol GUID as defined in the DXE CIS + +--*/ + +#include "Tiano.h" +#include EFI_ARCH_PROTOCOL_DEFINITION(MonotonicCounter) + +EFI_GUID gEfiMonotonicCounterArchProtocolGuid = EFI_MONTONIC_COUNTER_ARCH_PROTOCOL_GUID; + +EFI_GUID_STRING(&gEfiMonotonicCounterArchProtocolGuid, "Monotonic Counter", "Monotonic Counter Arch Protocol"); diff --git a/EDK/Foundation/Core/Dxe/ArchProtocol/MonotonicCounter/MonotonicCounter.h b/EDK/Foundation/Core/Dxe/ArchProtocol/MonotonicCounter/MonotonicCounter.h new file mode 100644 index 0000000..39e68aa --- /dev/null +++ b/EDK/Foundation/Core/Dxe/ArchProtocol/MonotonicCounter/MonotonicCounter.h @@ -0,0 +1,35 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + MonotonicCounter.h + +Abstract: + + Monotonic Counter Architectural Protocol as defined in DXE CIS + + This code provides the services required to access the systems monotonic counter + +--*/ + +#ifndef _ARCH_PROTOCOL_MONTONIC_COUNTER_H_ +#define _ARCH_PROTOCOL_MONTONIC_COUNTER_H_ + +// +// Global ID for the Monotonic Counter Architectural Protocol +// +#define EFI_MONTONIC_COUNTER_ARCH_PROTOCOL_GUID \ + {0x1da97072, 0xbddc, 0x4b30, 0x99, 0xf1, 0x72, 0xa0, 0xb5, 0x6f, 0xff, 0x2a} + +extern EFI_GUID gEfiMonotonicCounterArchProtocolGuid; + +#endif diff --git a/EDK/Foundation/Core/Dxe/ArchProtocol/RealTimeClock/RealTimeClock.c b/EDK/Foundation/Core/Dxe/ArchProtocol/RealTimeClock/RealTimeClock.c new file mode 100644 index 0000000..1109957 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/ArchProtocol/RealTimeClock/RealTimeClock.c @@ -0,0 +1,27 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + RealTimeClock.c + +Abstract: + + Real Time clock Architectural Protocol GUID as defined in Tiano + +--*/ + +#include "Tiano.h" +#include EFI_ARCH_PROTOCOL_DEFINITION (RealTimeClock) + +EFI_GUID gEfiRealTimeClockArchProtocolGuid = EFI_REAL_TIME_CLOCK_ARCH_PROTOCOL_GUID; + +EFI_GUID_STRING(&gEfiRealTimeClockArchProtocolGuid, "RTC", "Real Time Clock Arch Protocol"); diff --git a/EDK/Foundation/Core/Dxe/ArchProtocol/RealTimeClock/RealTimeClock.h b/EDK/Foundation/Core/Dxe/ArchProtocol/RealTimeClock/RealTimeClock.h new file mode 100644 index 0000000..9b98c15 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/ArchProtocol/RealTimeClock/RealTimeClock.h @@ -0,0 +1,43 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + RealTimeClock.h + +Abstract: + + Real Time clock Architectural Protocol as defined in Tiano + + This code abstracts time and data functions. Used to provide + Time and date related EFI runtime services. + + The GetTime (), SetTime (), GetWakeupTime (), and SetWakeupTime () EFI 1.0 + services are added to the EFI system table and the + EFI_REAL_TIME_CLOCK_ARCH_PROTOCOL_GUID protocol is registered with a NULL + pointer. + + No CRC of the EFI system table is required, as it is done in the DXE core. + +--*/ + +#ifndef _ARCH_PROTOCOL_REAL_TIME_CLOCK_H_ +#define _ARCH_PROTOCOL_REAL_TIME_CLOCK_H_ + +// +// Global ID for the Real Time Clock Architectural Protocol +// +#define EFI_REAL_TIME_CLOCK_ARCH_PROTOCOL_GUID \ + { 0x27CFAC87, 0x46CC, 0x11d4, 0x9A, 0x38, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D } + +extern EFI_GUID gEfiRealTimeClockArchProtocolGuid; + +#endif diff --git a/EDK/Foundation/Core/Dxe/ArchProtocol/Reset/Reset.c b/EDK/Foundation/Core/Dxe/ArchProtocol/Reset/Reset.c new file mode 100644 index 0000000..13896f6 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/ArchProtocol/Reset/Reset.c @@ -0,0 +1,27 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Reset.c + +Abstract: + + Reset Architectural Protocol GUID as defined in Tiano + +--*/ + +#include "Tiano.h" +#include EFI_ARCH_PROTOCOL_DEFINITION (Reset) + +EFI_GUID gEfiResetArchProtocolGuid = EFI_RESET_ARCH_PROTOCOL_GUID; + +EFI_GUID_STRING(&gEfiResetArchProtocolGuid, "Reset", "Reset Arch Protocol"); diff --git a/EDK/Foundation/Core/Dxe/ArchProtocol/Reset/Reset.h b/EDK/Foundation/Core/Dxe/ArchProtocol/Reset/Reset.h new file mode 100644 index 0000000..d26b661 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/ArchProtocol/Reset/Reset.h @@ -0,0 +1,40 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Reset.h + +Abstract: + + Reset Architectural Protocol as defined in the DXE CIS + + Used to provide ResetSystem runtime services + + The ResetSystem () EFI 1.0 service is added to the EFI system table and the + EFI_RESET_ARCH_PROTOCOL_GUID protocol is registered with a NULL pointer. + + No CRC of the EFI system table is required, as it is done in the DXE core. + +--*/ + +#ifndef _ARCH_PROTOCOL_RESET_H_ +#define _ARCH_PROTOCOL_RESET_H_ + +// +// Global ID for the Reset Architectural Protocol +// +#define EFI_RESET_ARCH_PROTOCOL_GUID \ + { 0x27CFAC88, 0x46CC, 0x11d4, 0x9A, 0x38, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D } + +extern EFI_GUID gEfiResetArchProtocolGuid; + +#endif diff --git a/EDK/Foundation/Core/Dxe/ArchProtocol/Runtime/Runtime.c b/EDK/Foundation/Core/Dxe/ArchProtocol/Runtime/Runtime.c new file mode 100644 index 0000000..4f58708 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/ArchProtocol/Runtime/Runtime.c @@ -0,0 +1,29 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Runtime.c + +Abstract: + + Runtime Architectural Protocol as defined in Tiano + + This code is used to produce the EFI 1.0 runtime virtual switch over + +--*/ + +#include "Tiano.h" +#include EFI_ARCH_PROTOCOL_DEFINITION (Runtime) + +EFI_GUID gEfiRuntimeArchProtocolGuid = EFI_RUNTIME_ARCH_PROTOCOL_GUID; + +EFI_GUID_STRING(&gEfiRuntimeArchProtocolGuid, "Runtime", "Runtime Arch Protocol"); diff --git a/EDK/Foundation/Core/Dxe/ArchProtocol/Runtime/Runtime.h b/EDK/Foundation/Core/Dxe/ArchProtocol/Runtime/Runtime.h new file mode 100644 index 0000000..28f0b41 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/ArchProtocol/Runtime/Runtime.h @@ -0,0 +1,114 @@ +/*++ + +Copyright (c) 2004 - 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Runtime.h + +Abstract: + + Runtime Architectural Protocol as defined in DXE CIS. + + + This code is used to produce the EFI runtime services that are callable + only in physical mode. + + This driver must add SetVirtualAddressMap () and ConvertPointer () to + the EFI system table. This driver is not responcible for CRCing the + EFI system table. + + This driver will add EFI_RUNTIME_ARCH_PROTOCOL_GUID protocol with a + pointer to the Runtime Arch Protocol instance structure. The protocol + member functions are used by the DXE core to export information needed + by this driver to produce the runtime transition of runtime drivers from + physical mode calling to virtual mode calling. + +--*/ + +#ifndef _ARCH_PROTOCOL_RUNTIME_H_ +#define _ARCH_PROTOCOL_RUNTIME_H_ + +#include "LinkedList.h" + +// +// Global ID for the Runtime Architectural Protocol +// +#define EFI_RUNTIME_ARCH_PROTOCOL_GUID \ + { 0xb7dfb4e1, 0x52f, 0x449f, 0x87, 0xbe, 0x98, 0x18, 0xfc, 0x91, 0xb7, 0x33 } + +EFI_FORWARD_DECLARATION (EFI_RUNTIME_ARCH_PROTOCOL); + +typedef struct _EFI_RUNTIME_IMAGE_ENTRY { + VOID *ImageBase; + UINT64 ImageSize; + VOID *RelocationData; + EFI_HANDLE Handle; + EFI_LIST_ENTRY Link; +} EFI_RUNTIME_IMAGE_ENTRY; + +typedef struct _EFI_RUNTIME_EVENT_ENTRY { + UINT32 Type; + EFI_TPL NotifyTpl; + EFI_EVENT_NOTIFY NotifyFunction; + VOID *NotifyContext; + EFI_EVENT *Event; + EFI_LIST_ENTRY Link; +} EFI_RUNTIME_EVENT_ENTRY; + +// +// Interface stucture for the Runtime Architectural Protocol +// +typedef struct _EFI_RUNTIME_ARCH_PROTOCOL { + EFI_LIST_ENTRY ImageHead; + EFI_LIST_ENTRY EventHead; + UINTN MemoryDescriptorSize; + UINT32 MemoryDesciptorVersion; + UINTN MemoryMapSize; + EFI_MEMORY_DESCRIPTOR *MemoryMapPhysical; + EFI_MEMORY_DESCRIPTOR *MemoryMapVirtual; + BOOLEAN VirtualMode; + BOOLEAN AtRuntime; +} EFI_RUNTIME_ARCH_PROTOCOL; +/*++ + +Protocol Description: + + Allows the runtime functionality of the DXE Foundation to be contained in a + separate driver. It also provides hooks for the DXE Foundation to export + information that is needed at runtime. As such, this protocol allows the DXE + Foundation to manage runtime drivers and events. This protocol also implies + that the runtime services required to transition to virtual mode, + SetVirtualAddressMap() and ConvertPointer(), have been registered into the + EFI Runtime Table in the EFI System Partition. This protocol must be produced + by a runtime DXE driver and may only be consumed by the DXE Foundation. + +Parameters: + + ImageHead - A list of type EFI_RUNTIME_IMAGE_ENTRY. + EventHead - A list of type EFI_RUNTIME_EVENT_ENTRY. + MemoryDescriptorSize - Size of a memory descriptor that is return by + GetMemoryMap(). + MemoryDescriptorVersion - Version of a memory descriptor that is return by + GetMemoryMap(). + MemoryMapSize - Size of the memory map in bytes contained in + MemoryMapPhysical and MemoryMapVirtual. + MemoryMapPhysical - Pointer to a runtime buffer that contains a copy of the + memory map returned via GetMemoryMap(). + MemoryMapVirtual - Pointer to MemoryMapPhysical that is updated to virtual mode + after SetVirtualAddressMap(). + VirtualMode - Boolean that is TRUE if SetVirtualAddressMap() has been called. + AtRuntime - Boolean that is TRUE if ExitBootServices () has been called. + +--*/ + +extern EFI_GUID gEfiRuntimeArchProtocolGuid; + +#endif \ No newline at end of file diff --git a/EDK/Foundation/Core/Dxe/ArchProtocol/Security/Security.c b/EDK/Foundation/Core/Dxe/ArchProtocol/Security/Security.c new file mode 100644 index 0000000..0b84bd5 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/ArchProtocol/Security/Security.c @@ -0,0 +1,28 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Security.c + +Abstract: + + Security Architectural Protocol GUID as defined in DXE CIS + +--*/ + +#include "Tiano.h" +#include EFI_ARCH_PROTOCOL_DEFINITION(Security) + +EFI_GUID gEfiSecurityArchProtocolGuid = EFI_SECURITY_ARCH_PROTOCOL_GUID; + +EFI_GUID_STRING(&gEfiSecurityArchProtocolGuid, "Security", "Security Arch Protocol"); + diff --git a/EDK/Foundation/Core/Dxe/ArchProtocol/Security/Security.h b/EDK/Foundation/Core/Dxe/ArchProtocol/Security/Security.h new file mode 100644 index 0000000..96ced0a --- /dev/null +++ b/EDK/Foundation/Core/Dxe/ArchProtocol/Security/Security.h @@ -0,0 +1,146 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Security.h + +Abstract: + + Security Architectural Protocol as defined in the DXE CIS + + Used to provide Security services. Specifically, dependening upon the + authentication state of a discovered driver in a Firmware Volume, the + portable DXE Core Dispatcher will call into the Security Architectural + Protocol (SAP) with the authentication state of the driver. + + This call-out allows for OEM-specific policy decisions to be made, such + as event logging for attested boots, locking flash in response to discovering + an unsigned driver or failed signature check, or other exception response. + + The SAP can also change system behavior by having the DXE core put a driver + in the Schedule-On-Request (SOR) state. This will allow for later disposition + of the driver by platform agent, such as Platform BDS. + +--*/ + +#ifndef _ARCH_PROTOCOL_SECURITY_H_ +#define _ARCH_PROTOCOL_SECURITY_H_ + +// +// Global ID for the Security Code Architectural Protocol +// +#define EFI_SECURITY_ARCH_PROTOCOL_GUID \ + { 0xA46423E3, 0x4617, 0x49f1, 0xB9, 0xFF, 0xD1, 0xBF, 0xA9, 0x11, 0x58, 0x39 } + +EFI_FORWARD_DECLARATION (EFI_SECURITY_ARCH_PROTOCOL); + +typedef +EFI_STATUS +(EFIAPI *EFI_SECURITY_FILE_AUTHENTICATION_STATE) ( + 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 - Driver 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. + +--*/ +; + +// +// Interface stucture for the Timer Architectural Protocol +// +typedef struct _EFI_SECURITY_ARCH_PROTOCOL { + EFI_SECURITY_FILE_AUTHENTICATION_STATE FileAuthenticationState; +} EFI_SECURITY_ARCH_PROTOCOL; +/*++ + + Protocol Description: + + The EFI_SECURITY_ARCH_PROTOCOL is used to abstract platform-specific policy + from the DXE core. This includes locking flash upon failure to authenticate, + attestation logging, and other exception operations. + + The driver that produces the EFI_SECURITY_ARCH_PROTOCOL may also optionally + install the EFI_SECURITY_POLICY_PROTOCOL_GUID onto a new handle with a NULL + interface. The existence of this GUID in the protocol database means that + the GUIDed Section Extraction Protocol should authenticate the contents of + an Authentication Section. The expectation is that the GUIDed Section + Extraction protocol will look for the existence of the EFI_SECURITY_POLICY_ + PROTOCOL_GUID in the protocol database. If it exists, then the publication + thereof is taken as an injunction to attempt an authentication of any section + wrapped in an Authentication Section. See the Firmware File System + Specification for details on the GUIDed Section Extraction Protocol and + Authentication Sections. + + Parameters: + + FileAuthenticationState - This service is called upon fault with respect to + the authentication of a section of a file. + +--*/ + +extern EFI_GUID gEfiSecurityArchProtocolGuid; + +#endif diff --git a/EDK/Foundation/Core/Dxe/ArchProtocol/StatusCode/StatusCode.c b/EDK/Foundation/Core/Dxe/ArchProtocol/StatusCode/StatusCode.c new file mode 100644 index 0000000..1c0890c --- /dev/null +++ b/EDK/Foundation/Core/Dxe/ArchProtocol/StatusCode/StatusCode.c @@ -0,0 +1,29 @@ +/*++ + +Copyright (c) 2004 - 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + StatusCode.c + +Abstract: + + Status code Architectural Protocol as defined in Tiano + + This code abstracts Status Code reporting. + +--*/ + +#include "Tiano.h" +#include EFI_ARCH_PROTOCOL_DEFINITION (StatusCode) + +EFI_GUID gEfiStatusCodeRuntimeProtocolGuid = EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID; + +EFI_GUID_STRING(&gEfiStatusCodeRuntimeProtocolGuid, "Status Code", "Status Code Arch Protocol"); \ No newline at end of file diff --git a/EDK/Foundation/Core/Dxe/ArchProtocol/StatusCode/StatusCode.h b/EDK/Foundation/Core/Dxe/ArchProtocol/StatusCode/StatusCode.h new file mode 100644 index 0000000..3346d87 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/ArchProtocol/StatusCode/StatusCode.h @@ -0,0 +1,100 @@ +/*++ + +Copyright (c) 2004 - 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + StatusCode.h + +Abstract: + + Status code Architectural Protocol as defined in the DXE CIS + + This code abstracts Status Code reporting. + + The StatusCode () Tiano service is added to the EFI system table and the + EFI_STATUS_CODE_ARCH_PROTOCOL_GUID protocol is registered with a NULL + pointer. + + No CRC of the EFI system table is required, as it is done in the DXE core. + +--*/ + +#ifndef __STATUS_CODE_RUNTIME_PROTOCOL_H__ +#define __STATUS_CODE_RUNTIME_PROTOCOL_H__ + +#define EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID \ + { 0xd2b2b828, 0x826, 0x48a7, 0xb3, 0xdf, 0x98, 0x3c, 0x0, 0x60, 0x24, 0xf0} + +#if (EFI_SPECIFICATION_VERSION >= 0x00020000) +typedef +EFI_STATUS +(EFIAPI *EFI_REPORT_STATUS_CODE) ( + IN EFI_STATUS_CODE_TYPE Type, + IN EFI_STATUS_CODE_VALUE Value, + IN UINT32 Instance, + IN EFI_GUID *CallerId OPTIONAL, + IN EFI_STATUS_CODE_DATA *Data OPTIONAL + ) +/*++ +Routine Description: + + Provides an interface that a software module can call to report a status code. + +Arguments: + + Type - Indicates the type of status code being reported. + + Value - Describes the current status of a hardware or software entity. + This included information about the class and subclass that is + used to classify the entity as well as an operation. + + Instance - The enumeration of a hardware or software entity within + the system. Valid instance numbers start with 1. + + CallerId - This optional parameter may be used to identify the caller. + This parameter allows the status code driver to apply different + rules to different callers. + + Data - This optional parameter may be used to pass additional data. + +Returns: + + EFI_SUCCESS - The function completed successfully + + EFI_DEVICE_ERROR - The function should not be completed due to a device error. + +--*/ +; +#endif + +// +// Interface stucture for the STATUS CODE Architectural Protocol +// +typedef struct _EFI_STATUS_CODE_PROTOCOL { + EFI_REPORT_STATUS_CODE ReportStatusCode; +} EFI_STATUS_CODE_PROTOCOL; + +/*++ +// Protocol Description: +// +// Provides the service required to report a status code to the platform firmware. +// This protocol must be produced by a runtime DXE driver and may be consumed +// only by the DXE Foundation. +// +// Parameter: +// +// ReportStatusCode - Emit a status code. +--*/ + + +extern EFI_GUID gEfiStatusCodeRuntimeProtocolGuid; + +#endif diff --git a/EDK/Foundation/Core/Dxe/ArchProtocol/Timer/Timer.c b/EDK/Foundation/Core/Dxe/ArchProtocol/Timer/Timer.c new file mode 100644 index 0000000..b2946f8 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/ArchProtocol/Timer/Timer.c @@ -0,0 +1,27 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Timer.c + +Abstract: + + Timer Architectural Protocol GUID as defined in Tiano + +--*/ + +#include "Tiano.h" +#include EFI_ARCH_PROTOCOL_DEFINITION (Timer) + +EFI_GUID gEfiTimerArchProtocolGuid = EFI_TIMER_ARCH_PROTOCOL_GUID; + +EFI_GUID_STRING(&gEfiTimerArchProtocolGuid, "Timer", "Timer Arch Protocol"); diff --git a/EDK/Foundation/Core/Dxe/ArchProtocol/Timer/Timer.h b/EDK/Foundation/Core/Dxe/ArchProtocol/Timer/Timer.h new file mode 100644 index 0000000..2e5c80d --- /dev/null +++ b/EDK/Foundation/Core/Dxe/ArchProtocol/Timer/Timer.h @@ -0,0 +1,260 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Timer.h + +Abstract: + + Timer Architectural Protocol as defined in the DXE CIS + + This code is used to provide the timer tick for the DXE core. + +--*/ + +#ifndef _ARCH_PROTOCOL_TIMER_H_ +#define _ARCH_PROTOCOL_TIMER_H_ + +// +// Global ID for the Timer Architectural Protocol +// +#define EFI_TIMER_ARCH_PROTOCOL_GUID \ + { 0x26baccb3, 0x6f42, 0x11d4, 0xbc, 0xe7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } + +// +// Declare forward reference for the Timer Architectural Protocol +// +EFI_FORWARD_DECLARATION (EFI_TIMER_ARCH_PROTOCOL); + +typedef +VOID +(EFIAPI *EFI_TIMER_NOTIFY) ( + IN UINT64 Time + ); +/*++ + +Routine Description: + + This function of this type is called when a timer interrupt fires. This + function executes at TPL_HIGH_LEVEL. The DXE Core will register a funtion + of tyis type to be called for the timer interrupt, so it can know how much + time has passed. This information is used to signal timer based events. + +Arguments: + + Time - Time since the last timer interrupt in 100 ns units. This will + typically be TimerPeriod, but if a timer interrupt is missed, and the + EFI_TIMER_ARCH_PROTOCOL driver can detect missed interrupts, then Time + will contain the actual amount of time since the last interrupt. + +Returns: + + None. + +--*/ + +typedef +EFI_STATUS +(EFIAPI *EFI_TIMER_REGISTER_HANDLER) ( + IN EFI_TIMER_ARCH_PROTOCOL *This, + IN EFI_TIMER_NOTIFY NotifyFunction +); +/*++ + +Routine Description: + + This function registers the handler NotifyFunction so it is called every time + the timer interrupt fires. It also passes the amount of time since the last + handler call to the NotifyFunction. If NotifyFunction is NULL, then the + handler is unregistered. If the handler is registered, then EFI_SUCCESS is + returned. If the CPU does not support registering a timer interrupt handler, + then EFI_UNSUPPORTED is returned. If an attempt is made to register a handler + when a handler is already registered, then EFI_ALREADY_STARTED is returned. + If an attempt is made to unregister a handler when a handler is not registered, + then EFI_INVALID_PARAMETER is returned. If an error occurs attempting to + register the NotifyFunction with the timer interrupt, then EFI_DEVICE_ERROR + is returned. + +Arguments: + + This - The EFI_TIMER_ARCH_PROTOCOL instance. + + NotifyFunction - The function to call when a timer interrupt fires. This + function executes at TPL_HIGH_LEVEL. The DXE Core will + register a handler for the timer interrupt, so it can know + how much time has passed. This information is used to + signal timer based events. NULL will unregister the handler. + +Returns: + + EFI_SUCCESS - The timer handler was registered. + + EFI_UNSUPPORTED - The platform does not support timer interrupts. + + EFI_ALREADY_STARTED - NotifyFunction is not NULL, and a handler is already + registered. + + EFI_INVALID_PARAMETER - NotifyFunction is NULL, and a handler was not + previously registered. + + EFI_DEVICE_ERROR - The timer handler could not be registered. + +--*/ + +typedef +EFI_STATUS +(EFIAPI *EFI_TIMER_SET_TIMER_PERIOD) ( + IN EFI_TIMER_ARCH_PROTOCOL *This, + IN UINT64 TimerPeriod + ); +/*++ + +Routine Description: + + This function adjusts the period of timer interrupts to the value specified + by TimerPeriod. If the timer period is updated, then the selected timer + period is stored in EFI_TIMER.TimerPeriod, and EFI_SUCCESS is returned. If + the timer hardware is not programmable, then EFI_UNSUPPORTED is returned. + If an error occurs while attempting to update the timer period, then the + timer hardware will be put back in its state prior to this call, and + EFI_DEVICE_ERROR is returned. If TimerPeriod is 0, then the timer interrupt + is disabled. This is not the same as disabling the CPU's interrupts. + Instead, it must either turn off the timer hardware, or it must adjust the + interrupt controller so that a CPU interrupt is not generated when the timer + interrupt fires. + +Arguments: + + This - The EFI_TIMER_ARCH_PROTOCOL instance. + + TimerPeriod - The rate to program the timer interrupt in 100 nS units. If + the timer hardware is not programmable, then EFI_UNSUPPORTED is + returned. If the timer is programmable, then the timer period + will be rounded up to the nearest timer period that is supported + by the timer hardware. If TimerPeriod is set to 0, then the + timer interrupts will be disabled. + +Returns: + + EFI_SUCCESS - The timer period was changed. + + EFI_UNSUPPORTED - The platform cannot change the period of the timer interrupt. + + EFI_DEVICE_ERROR - The timer period could not be changed due to a device error. + +--*/ + +typedef +EFI_STATUS +(EFIAPI *EFI_TIMER_GET_TIMER_PERIOD) ( + IN EFI_TIMER_ARCH_PROTOCOL *This, + OUT UINT64 *TimerPeriod + ); +/*++ + +Routine Description: + + This function retrieves the period of timer interrupts in 100 ns units, + returns that value in TimerPeriod, and returns EFI_SUCCESS. If TimerPeriod + is NULL, then EFI_INVALID_PARAMETER is returned. If a TimerPeriod of 0 is + returned, then the timer is currently disabled. + +Arguments: + + This - The EFI_TIMER_ARCH_PROTOCOL instance. + + TimerPeriod - A pointer to the timer period to retrieve in 100 ns units. If + 0 is returned, then the timer is currently disabled. + +Returns: + + EFI_SUCCESS - The timer period was returned in TimerPeriod. + + EFI_INVALID_PARAMETER - TimerPeriod is NULL. + +--*/ + +typedef +EFI_STATUS +(EFIAPI *EFI_TIMER_GENERATE_SOFT_INTERRUPT) ( + IN EFI_TIMER_ARCH_PROTOCOL *This + ); +/*++ + +Routine Description: + + This function generates a soft timer interrupt. If the platform does not support soft + timer interrupts, then EFI_UNSUPPORTED is returned. Otherwise, EFI_SUCCESS is returned. + If a handler has been registered through the EFI_TIMER_ARCH_PROTOCOL.RegisterHandler() + service, then a soft timer interrupt will be generated. If the timer interrupt is + enabled when this service is called, then the registered handler will be invoked. The + registered handler should not be able to distinguish a hardware-generated timer + interrupt from a software-generated timer interrupt. + +Arguments: + + This - The EFI_TIMER_ARCH_PROTOCOL instance. + +Returns: + + EFI_SUCCESS - The soft timer interrupt was generated. + + EFI_UNSUPPORTEDT - The platform does not support the generation of soft timer interrupts. + +--*/ + +// +// Interface stucture for the Timer Architectural Protocol +// +typedef struct _EFI_TIMER_ARCH_PROTOCOL { + EFI_TIMER_REGISTER_HANDLER RegisterHandler; + EFI_TIMER_SET_TIMER_PERIOD SetTimerPeriod; + EFI_TIMER_GET_TIMER_PERIOD GetTimerPeriod; + EFI_TIMER_GENERATE_SOFT_INTERRUPT GenerateSoftInterrupt; +} EFI_TIMER_ARCH_PROTOCOL; + +/*++ + + Protocol Description: + This protocol provides the services to initialize a periodic timer + interrupt, and to register a handler that is called each time the timer + interrupt fires. It may also provide a service to adjust the rate of the + periodic timer interrupt. When a timer interrupt occurs, the handler is + passed the amount of time that has passed since the previous timer + interrupt. + + Parameters: + + RegisterHandler - Registers a handler that will be called each time the + timer interrupt fires. TimerPeriod defines the minimum + time between timer interrupts, so TimerPeriod will also + be the minimum time between calls to the registered + handler. + + SetTimerPeriod - Sets the period of the timer interrupt in 100 nS units. + This function is optional, and may return EFI_UNSUPPORTED. + If this function is supported, then the timer period will + be rounded up to the nearest supported timer period. + + GetTimerPeriod - Retrieves the period of the timer interrupt in 100 nS units. + + GenerateSoftInterrupt - + Generates a soft timer interrupt that simulates the firing of + the timer interrupt. This service can be used to invoke the + registered handler if the timer interrupt has been masked for + a period of time. + +--*/ + +extern EFI_GUID gEfiTimerArchProtocolGuid; + +#endif diff --git a/EDK/Foundation/Core/Dxe/ArchProtocol/Variable/Variable.c b/EDK/Foundation/Core/Dxe/ArchProtocol/Variable/Variable.c new file mode 100644 index 0000000..5ff0e9b --- /dev/null +++ b/EDK/Foundation/Core/Dxe/ArchProtocol/Variable/Variable.c @@ -0,0 +1,29 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Variable.c + +Abstract: + + Variable Architectural Protocol as defined in Tiano + + This code is used to produce the EFI 1.0 runtime variable services + +--*/ + +#include "Tiano.h" +#include EFI_ARCH_PROTOCOL_DEFINITION (Variable) + +EFI_GUID gEfiVariableArchProtocolGuid = EFI_VARIABLE_ARCH_PROTOCOL_GUID; + +EFI_GUID_STRING(&gEfiVariableArchProtocolGuid, "Variable", "Variable Arch Protocol"); diff --git a/EDK/Foundation/Core/Dxe/ArchProtocol/Variable/Variable.h b/EDK/Foundation/Core/Dxe/ArchProtocol/Variable/Variable.h new file mode 100644 index 0000000..8d9d4df --- /dev/null +++ b/EDK/Foundation/Core/Dxe/ArchProtocol/Variable/Variable.h @@ -0,0 +1,41 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Variable.h + +Abstract: + + Variable Architectural Protocol as defined in the DXE CIS + + This code is used to produce the EFI 1.0 runtime variable services + + The GetVariable (), GetNextVariableName (), and SetVariable () EFI 1.0 + services are added to the EFI system table and the + EFI_VARIABLE_ARCH_PROTOCOL_GUID protocol is registered with a NULL pointer. + + No CRC of the EFI system table is required, as it is done in the DXE core. + +--*/ + +#ifndef _ARCH_PROTOCOL_VARIABLE_ARCH_H_ +#define _ARCH_PROTOCOL_VARIABLE_ARCH_H_ + +// +// Global ID for the Variable Architectural Protocol +// +#define EFI_VARIABLE_ARCH_PROTOCOL_GUID \ + { 0x1e5668e2, 0x8481, 0x11d4, 0xbc, 0xf1, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } + +extern EFI_GUID gEfiVariableArchProtocolGuid; + +#endif diff --git a/EDK/Foundation/Core/Dxe/ArchProtocol/VariableWrite/VariableWrite.c b/EDK/Foundation/Core/Dxe/ArchProtocol/VariableWrite/VariableWrite.c new file mode 100644 index 0000000..7daf743 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/ArchProtocol/VariableWrite/VariableWrite.c @@ -0,0 +1,30 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + VariableWrite.c + +Abstract: + + Variable Write Architectural Protocol as defined in DXE CIS + + This code is used to indicate the EFI 1.0 runtime variable services + support writting to variables. + +--*/ + +#include "Tiano.h" +#include EFI_ARCH_PROTOCOL_DEFINITION (VariableWrite) + +EFI_GUID gEfiVariableWriteArchProtocolGuid = EFI_VARIABLE_WRITE_ARCH_PROTOCOL_GUID; + +EFI_GUID_STRING(&gEfiVariableWriteArchProtocolGuid, "VariableWrite", "Variable Write Arch Protocol"); diff --git a/EDK/Foundation/Core/Dxe/ArchProtocol/VariableWrite/VariableWrite.h b/EDK/Foundation/Core/Dxe/ArchProtocol/VariableWrite/VariableWrite.h new file mode 100644 index 0000000..7629b09 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/ArchProtocol/VariableWrite/VariableWrite.h @@ -0,0 +1,41 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + VariableWrite.h + +Abstract: + + Variable Write Architectural Protocol as defined in the DXE CIS + + This code is used to produce the EFI 1.0 runtime variable services + + The GetVariable (), GetNextVariableName (), and SetVariable () EFI 1.0 + services are added to the EFI system table and the + EFI_VARIABLE_WRITE_ARCH_PROTOCOL_GUID protocol is registered with a NULL pointer. + + No CRC of the EFI system table is required, as it is done in the DXE core. + +--*/ + +#ifndef _ARCH_PROTOCOL_VARIABLE_WRITE_ARCH_H_ +#define _ARCH_PROTOCOL_VARIABLE_WRITE_ARCH_H_ + +// +// Global ID for the Variable Write Architectural Protocol +// +#define EFI_VARIABLE_WRITE_ARCH_PROTOCOL_GUID \ + { 0x6441f818, 0x6362, 0x4e44, 0xb5, 0x70, 0x7d, 0xba, 0x31, 0xdd, 0x24, 0x53 } + +extern EFI_GUID gEfiVariableWriteArchProtocolGuid; + +#endif diff --git a/EDK/Foundation/Core/Dxe/ArchProtocol/WatchdogTimer/WatchdogTimer.c b/EDK/Foundation/Core/Dxe/ArchProtocol/WatchdogTimer/WatchdogTimer.c new file mode 100644 index 0000000..d6ee113 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/ArchProtocol/WatchdogTimer/WatchdogTimer.c @@ -0,0 +1,27 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + WatchdogTimer.c + +Abstract: + + Watchdog Timer Architectural Protocol GUID as defined in Tiano + +--*/ + +#include "Tiano.h" +#include EFI_ARCH_PROTOCOL_DEFINITION (WatchdogTimer) + +EFI_GUID gEfiWatchdogTimerArchProtocolGuid = EFI_WATCHDOG_TIMER_ARCH_PROTOCOL_GUID; + +EFI_GUID_STRING(&gEfiWatchdogTimerArchProtocolGuid, "Watchdog Timer", "Watchdog Timer Arch Protocol"); diff --git a/EDK/Foundation/Core/Dxe/ArchProtocol/WatchdogTimer/WatchdogTimer.h b/EDK/Foundation/Core/Dxe/ArchProtocol/WatchdogTimer/WatchdogTimer.h new file mode 100644 index 0000000..6586594 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/ArchProtocol/WatchdogTimer/WatchdogTimer.h @@ -0,0 +1,206 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + WatchdogTimer.h + +Abstract: + + Watchdog Timer Architectural Protocol as defined in the DXE CIS + + Used to provide system watchdog timer services + +--*/ + +#ifndef _ARCH_PROTOCOL_WATCHDOG_TIMER_H_ +#define _ARCH_PROTOCOL_WATCHDOG_TIMER_H_ + +// +// Global ID for the Watchdog Timer Architectural Protocol +// +#define EFI_WATCHDOG_TIMER_ARCH_PROTOCOL_GUID \ + { 0x665E3FF5, 0x46CC, 0x11d4, 0x9A, 0x38, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D } + +// +// Declare forward reference for the Timer Architectural Protocol +// +EFI_FORWARD_DECLARATION (EFI_WATCHDOG_TIMER_ARCH_PROTOCOL); + +typedef +VOID +(EFIAPI *EFI_WATCHDOG_TIMER_NOTIFY) ( + IN UINT64 Time + ); +/*++ + +Routine Description: + + A function of this type is called when the watchdog timer fires if a + handler has been registered. + +Arguments: + + Time - The time in 100 ns units that has passed since the watchdog + timer was armed. For the notify function to be called, this + must be greater than TimerPeriod. + +Returns: + + None. + +--*/ + +typedef +EFI_STATUS +(EFIAPI *EFI_WATCHDOG_TIMER_REGISTER_HANDLER) ( + 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. + +--*/ + +typedef +EFI_STATUS +(EFIAPI *EFI_WATCHDOG_TIMER_SET_TIMER_PERIOD) ( + 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. + +--*/ + +typedef +EFI_STATUS +(EFIAPI *EFI_WATCHDOG_TIMER_GET_TIMER_PERIOD) ( + IN EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This, + OUT 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. + +--*/ + +// +// Interface stucture for the Watchdog Timer Architectural Protocol +// +typedef struct _EFI_WATCHDOG_TIMER_ARCH_PROTOCOL { + EFI_WATCHDOG_TIMER_REGISTER_HANDLER RegisterHandler; + EFI_WATCHDOG_TIMER_SET_TIMER_PERIOD SetTimerPeriod; + EFI_WATCHDOG_TIMER_GET_TIMER_PERIOD GetTimerPeriod; +} EFI_WATCHDOG_TIMER_ARCH_PROTOCOL; + +/*++ + + Protocol Description: + This protocol provides the services required to implement the Boot Service + SetWatchdogTimer(). It provides a service to set the amount of time to wait + before firing the watchdog timer, and it also provides a service to register + a handler that is invoked when the watchdog timer fires. This protocol can + implement the watchdog timer by using the event and timer Boot Services, or + it can make use of custom hardware. When the watchdog timer fires, control + will be passed to a handler if one has been registered. If no handler has + been registered, or the registered handler returns, then the system will be + reset by calling the Runtime Service ResetSystem(). + + Parameters: + + RegisterHandler - Registers a handler that is invoked when the watchdog + timer fires. + + SetTimerPeriod - Sets the amount of time in 100 ns units to wait before the + watchdog timer is fired. If this function is supported, + then the watchdog timer period will be rounded up to the + nearest supported watchdog timer period. + + GetTimerPeriod - Retrieves the amount of time in 100 ns units that the + system will wait before the watchdog timer is fired. + +--*/ + +extern EFI_GUID gEfiWatchdogTimerArchProtocolGuid; + +#endif + diff --git a/EDK/Foundation/Core/Dxe/Dispatcher/Dispatcher.c b/EDK/Foundation/Core/Dxe/Dispatcher/Dispatcher.c new file mode 100644 index 0000000..fa23df7 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/Dispatcher/Dispatcher.c @@ -0,0 +1,1203 @@ +/*++ + +Copyright (c) 2004 - 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Dispatcher.c + +Abstract: + + Tiano DXE Dispatcher. + + Step #1 - When a FV protocol is added to the system every driver in the FV + is added to the mDiscoveredList. The SOR, Before, and After Depex are + pre-processed as drivers are added to the mDiscoveredList. If an Apriori + file exists in the FV those drivers are addeded to the + mScheduledQueue. The mFvHandleList is used to make sure a + FV is only processed once. + + Step #2 - Dispatch. Remove driver from the mScheduledQueue and load and + start it. After mScheduledQueue is drained check the + mDiscoveredList to see if any item has a Depex that is ready to + be placed on the mScheduledQueue. + + Step #3 - Adding to the mScheduledQueue requires that you process Before + and After dependencies. This is done recursively as the call to add + to the mScheduledQueue checks for Before and recursively adds + all Befores. It then addes the item that was passed in and then + processess the After dependecies by recursively calling the routine. + + Dispatcher Rules: + The rules for the dispatcher are in chapter 10 of the DXE CIS. Figure 10-3 + is the state diagram for the DXE dispatcher + + Depex - Dependency Expresion. + SOR - Schedule On Request - Don't schedule if this bit is set. + +--*/ + +#include "Tiano.h" +#include "DxeCore.h" +#include "FwVolBlock.h" +#include EFI_GUID_DEFINITION (Apriori) + +// +// The Driver List contains one copy of every driver that has been discovered. +// Items are never removed from the driver list. List of EFI_CORE_DRIVER_ENTRY +// +EFI_LIST_ENTRY mDiscoveredList = INITIALIZE_LIST_HEAD_VARIABLE (mDiscoveredList); + +// +// Queue of drivers that are ready to dispatch. This queue is a subset of the +// mDiscoveredList.list of EFI_CORE_DRIVER_ENTRY. +// +EFI_LIST_ENTRY mScheduledQueue = INITIALIZE_LIST_HEAD_VARIABLE (mScheduledQueue); + +// +// List of handles who's Fv's have been parsed and added to the mFwDriverList. +// +EFI_LIST_ENTRY mFvHandleList = INITIALIZE_LIST_HEAD_VARIABLE (mFvHandleList); // list of KNOWN_HANDLE + +// +// Lock for mDiscoveredList, mScheduledQueue, mDispatcherRunning. +// +EFI_LOCK mDispatcherLock = EFI_INITIALIZE_LOCK_VARIABLE (EFI_TPL_HIGH_LEVEL); + + +// +// Flag for the DXE Dispacher. TRUE if dispatcher is execuing. +// +BOOLEAN mDispatcherRunning = FALSE; + +// +// Module globals to manage the FwVol registration notification event +// +EFI_EVENT mFwVolEvent; +VOID *mFwVolEventRegistration; + +// +// List of file types supported by dispatcher +// +static EFI_FV_FILETYPE mDxeFileTypes[] = { + EFI_FV_FILETYPE_DRIVER, + EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER, + EFI_FV_FILETYPE_DXE_CORE, + EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE +}; + +typedef struct { + MEDIA_FW_VOL_FILEPATH_DEVICE_PATH File; + EFI_DEVICE_PATH_PROTOCOL End; +} FV_FILEPATH_DEVICE_PATH; + +FV_FILEPATH_DEVICE_PATH mFvDevicePath; +// +// Function Prototypes +// +VOID +CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter ( + IN EFI_CORE_DRIVER_ENTRY *InsertedDriverEntry + ); + +VOID +EFIAPI +CoreFwVolEventProtocolNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +EFI_DEVICE_PATH_PROTOCOL * +CoreFvToDevicePath ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *Fv, + IN EFI_HANDLE FvHandle, + IN EFI_GUID *DriverName + ); + +STATIC +EFI_STATUS +CoreAddToDriverList ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *Fv, + IN EFI_HANDLE FvHandle, + IN EFI_GUID *DriverName + ); + +STATIC +EFI_STATUS +CoreProcessFvImageFile ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *Fv, + IN EFI_HANDLE FvHandle, + IN EFI_GUID *DriverName + ); + + +VOID +CoreAcquireDispatcherLock ( + VOID + ) +/*++ + +Routine Description: + + Enter critical section by gaining lock on mDispatcherLock + +Arguments: + + None + +Returns: + + None + +--*/ + +{ + CoreAcquireLock (&mDispatcherLock); +} + +VOID +CoreReleaseDispatcherLock ( + VOID + ) +/*++ + +Routine Description: + + Exit critical section by releasing lock on mDispatcherLock + +Arguments: + + None + +Returns: + + None + +--*/ +{ + CoreReleaseLock (&mDispatcherLock); +} + + +EFI_STATUS +CoreGetDepexSectionAndPreProccess ( + IN EFI_CORE_DRIVER_ENTRY *DriverEntry + ) +/*++ + +Routine Description: + + Read Depex and pre-process the Depex for Before and After. If Section Extraction + protocol returns an error via ReadSection defer the reading of the Depex. + +Arguments: + + DriverEntry - Driver to work on. + +Returns: + + EFI_SUCCESS - Depex read and preprossesed + + EFI_PROTOCOL_ERROR - The section extraction protocol returned an error and + Depex reading needs to be retried. + + Other Error - DEPEX not found. + +--*/ +{ + EFI_STATUS Status; + EFI_SECTION_TYPE SectionType; + UINT32 AuthenticationStatus; + EFI_FIRMWARE_VOLUME_PROTOCOL *Fv; + + + Fv = DriverEntry->Fv; + + // + // Grab Depex info, it will never be free'ed. + // + SectionType = EFI_SECTION_DXE_DEPEX; + Status = Fv->ReadSection ( + DriverEntry->Fv, + &DriverEntry->FileName, + SectionType, + 0, + &DriverEntry->Depex, + (UINTN *)&DriverEntry->DepexSize, + &AuthenticationStatus + ); + if (EFI_ERROR (Status)) { + if (Status == EFI_PROTOCOL_ERROR) { + // + // The section extraction protocol failed so set protocol error flag + // + DriverEntry->DepexProtocolError = TRUE; + } else { + // + // If no Depex assume EFI 1.1 driver model + // + DriverEntry->Depex = NULL; + DriverEntry->Dependent = TRUE; + DriverEntry->DepexProtocolError = FALSE; + } + } else { + // + // Set Before, After, and Unrequested state information based on Depex + // Driver will be put in Dependent or Unrequested state + // + CorePreProcessDepex (DriverEntry); + DriverEntry->DepexProtocolError = FALSE; + } + + return Status; +} + +EFI_DXESERVICE +EFI_STATUS +EFIAPI +CoreSchedule ( + IN EFI_HANDLE FirmwareVolumeHandle, + IN EFI_GUID *DriverName + ) +/*++ + +Routine Description: + + Check every driver and locate a matching one. If the driver is found, the Unrequested + state flag is cleared. + +Arguments: + + FirmwareVolumeHandle - The handle of the Firmware Volume that contains the firmware + file specified by DriverName. + + DriverName - The Driver name to put in the Dependent state. + +Returns: + + EFI_SUCCESS - The DriverName was found and it's SOR bit was cleared + + EFI_NOT_FOUND - The DriverName does not exist or it's SOR bit was not set. + +--*/ +{ + EFI_LIST_ENTRY *Link; + EFI_CORE_DRIVER_ENTRY *DriverEntry; + + // + // Check every driver + // + for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) { + DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE); + if (DriverEntry->FvHandle == FirmwareVolumeHandle && + DriverEntry->Unrequested && + EfiCompareGuid (DriverName, &DriverEntry->FileName)) { + // + // Move the driver from the Unrequested to the Dependent state + // + CoreAcquireDispatcherLock (); + DriverEntry->Unrequested = FALSE; + DriverEntry->Dependent = TRUE; + CoreReleaseDispatcherLock (); + + return EFI_SUCCESS; + } + } + return EFI_NOT_FOUND; +} + + +EFI_DXESERVICE +EFI_STATUS +EFIAPI +CoreTrust ( + IN EFI_HANDLE FirmwareVolumeHandle, + IN EFI_GUID *DriverName + ) +/*++ + +Routine Description: + + Convert a driver from the Untrused back to the Scheduled state + +Arguments: + + FirmwareVolumeHandle - The handle of the Firmware Volume that contains the firmware + file specified by DriverName. + + DriverName - The Driver name to put in the Scheduled state + +Returns: + + EFI_SUCCESS - The file was found in the untrusted state, and it was promoted + to the trusted state. + + EFI_NOT_FOUND - The file was not found in the untrusted state. + +--*/ +{ + EFI_LIST_ENTRY *Link; + EFI_CORE_DRIVER_ENTRY *DriverEntry; + + // + // Check every driver + // + for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) { + DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE); + if (DriverEntry->FvHandle == FirmwareVolumeHandle && + DriverEntry->Untrusted && + EfiCompareGuid (DriverName, &DriverEntry->FileName)) { + // + // Transition driver from Untrusted to Scheduled state. + // + CoreAcquireDispatcherLock (); + DriverEntry->Untrusted = FALSE; + DriverEntry->Scheduled = TRUE; + InsertTailList (&mScheduledQueue, &DriverEntry->ScheduledLink); + CoreReleaseDispatcherLock (); + + return EFI_SUCCESS; + } + } + return EFI_NOT_FOUND; +} + + +EFI_DXESERVICE +EFI_STATUS +EFIAPI +CoreDispatcher ( + VOID + ) +/*++ + +Routine Description: + + This is the main Dispatcher for DXE and it exits when there are no more + drivers to run. Drain the mScheduledQueue and load and start a PE + image for each driver. Search the mDiscoveredList to see if any driver can + be placed on the mScheduledQueue. If no drivers are placed on the + mScheduledQueue exit the function. On exit it is assumed the Bds() + will be called, and when the Bds() exits the Dispatcher will be called + again. + +Arguments: + + NONE + +Returns: + + EFI_ALREADY_STARTED - The DXE Dispatcher is already running + + EFI_NOT_FOUND - No DXE Drivers were dispatched + + EFI_SUCCESS - One or more DXE Drivers were dispatched + +--*/ +{ + EFI_STATUS Status; + EFI_STATUS ReturnStatus; + EFI_LIST_ENTRY *Link; + EFI_CORE_DRIVER_ENTRY *DriverEntry; + BOOLEAN ReadyToRun; + UINT8 Buffer[EFI_STATUS_CODE_DATA_MAX_SIZE]; + EFI_STATUS_CODE_DATA *StatusCodeData; + EFI_DEVICE_HANDLE_EXTENDED_DATA *DeviceHandleExtData; + + DeviceHandleExtData = (EFI_DEVICE_HANDLE_EXTENDED_DATA *) Buffer; + StatusCodeData = (EFI_STATUS_CODE_DATA *) Buffer; + DeviceHandleExtData->DataHeader.HeaderSize = sizeof (EFI_STATUS_CODE_DATA); + DeviceHandleExtData->DataHeader.Size = + sizeof (EFI_DEVICE_HANDLE_EXTENDED_DATA) - + sizeof (EFI_STATUS_CODE_DATA); + + EfiCommonLibCopyMem ( + &DeviceHandleExtData->DataHeader.Type, + &gEfiStatusCodeSpecificDataGuid, + sizeof (EFI_GUID) + ); + + if (mDispatcherRunning) { + // + // If the dispatcher is running don't let it be restarted. + // + return EFI_ALREADY_STARTED; + } + + mDispatcherRunning = TRUE; + + + ReturnStatus = EFI_NOT_FOUND; + do { + // + // Drain the Scheduled Queue + // + while (!IsListEmpty (&mScheduledQueue)) { + DriverEntry = CR ( + mScheduledQueue.ForwardLink, + EFI_CORE_DRIVER_ENTRY, + ScheduledLink, + EFI_CORE_DRIVER_ENTRY_SIGNATURE + ); + + // + // Load the DXE Driver image into memory. If the Driver was transitioned from + // Untrused to Scheduled it would have already been loaded so we may need to + // skip the LoadImage + // + if (DriverEntry->ImageHandle == NULL) { + Status = CoreLoadImage ( + FALSE, + gDxeCoreImageHandle, + DriverEntry->FvFileDevicePath, + NULL, + 0, + &DriverEntry->ImageHandle + ); + + // + // Update the driver state to reflect that it's been loaded + // + if (EFI_ERROR (Status)) { + CoreAcquireDispatcherLock (); + + if (Status == EFI_SECURITY_VIOLATION) { + // + // Take driver from Scheduled to Untrused state + // + DriverEntry->Untrusted = TRUE; + } else { + // + // The DXE Driver could not be loaded, and do not attempt to load or start it again. + // Take driver from Scheduled to Initialized. + // + // This case include the Never Trusted state if EFI_ACCESS_DENIED is returned + // + DriverEntry->Initialized = TRUE; + } + + DriverEntry->Scheduled = FALSE; + RemoveEntryList (&DriverEntry->ScheduledLink); + + CoreReleaseDispatcherLock (); + + // + // If it's an error don't try the StartImage + // + continue; + } + } + + CoreAcquireDispatcherLock (); + + DriverEntry->Scheduled = FALSE; + DriverEntry->Initialized = TRUE; + RemoveEntryList (&DriverEntry->ScheduledLink); + + CoreReleaseDispatcherLock (); + + // + // Report Status Code here to notify drivers has + // been initialized (INIT_BEGIN) + // + EfiCommonLibCopyMem ( + &DeviceHandleExtData->Handle, + &DriverEntry->ImageHandle, + sizeof (EFI_HANDLE) + ); + + CoreReportProgressCodeSpecific (EFI_SOFTWARE_DXE_CORE | EFI_SW_PC_INIT_BEGIN, DriverEntry->ImageHandle); + + Status = CoreStartImage (DriverEntry->ImageHandle, NULL, NULL); + + CoreReportProgressCodeSpecific (EFI_SOFTWARE_DXE_CORE | EFI_SW_PC_INIT_END, DriverEntry->ImageHandle); + + ReturnStatus = EFI_SUCCESS; + } + + // + // Search DriverList for items to place on Scheduled Queue + // + ReadyToRun = FALSE; + for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) { + DriverEntry = CR (Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE); + + if (DriverEntry->DepexProtocolError){ + // + // If Section Extraction Protocol did not let the Depex be read before retry the read + // + Status = CoreGetDepexSectionAndPreProccess (DriverEntry); + } + + if (DriverEntry->Dependent) { + if (CoreIsSchedulable (DriverEntry)) { + CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry); + ReadyToRun = TRUE; + } + } + } + } while (ReadyToRun); + + mDispatcherRunning = FALSE; + + return ReturnStatus; +} + + +VOID +CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter ( + IN EFI_CORE_DRIVER_ENTRY *InsertedDriverEntry + ) +/*++ + +Routine Description: + + Insert InsertedDriverEntry onto the mScheduledQueue. To do this you + must add any driver with a before dependency on InsertedDriverEntry first. + You do this by recursively calling this routine. After all the Befores are + processed you can add InsertedDriverEntry to the mScheduledQueue. + Then you can add any driver with an After dependency on InsertedDriverEntry + by recursively calling this routine. + +Arguments: + + InsertedDriverEntry - The driver to insert on the ScheduledLink Queue + +Returns: + + NONE + +--*/ +{ + EFI_LIST_ENTRY *Link; + EFI_CORE_DRIVER_ENTRY *DriverEntry; + + // + // Process Before Dependency + // + for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) { + DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE); + if (DriverEntry->Before && DriverEntry->Dependent) { + if (EfiCompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) { + // + // Recursively process BEFORE + // + CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry); + } + } + } + + // + // Convert driver from Dependent to Scheduled state + // + CoreAcquireDispatcherLock (); + + InsertedDriverEntry->Dependent = FALSE; + InsertedDriverEntry->Scheduled = TRUE; + InsertTailList (&mScheduledQueue, &InsertedDriverEntry->ScheduledLink); + + CoreReleaseDispatcherLock (); + + // + // Process After Dependency + // + for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) { + DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE); + if (DriverEntry->After && DriverEntry->Dependent) { + if (EfiCompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) { + // + // Recursively process AFTER + // + CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry); + } + } + } +} + + +BOOLEAN +FvHasBeenProcessed ( + IN EFI_HANDLE FvHandle + ) +/*++ + +Routine Description: + + Return TRUE if the Fv has been processed, FALSE if not. + +Arguments: + + FvHandle - The handle of a FV that's being tested + +Returns: + + TRUE - Fv protocol on FvHandle has been processed + + FALSE - Fv protocol on FvHandle has not yet been processed + +--*/ +{ + EFI_LIST_ENTRY *Link; + KNOWN_HANDLE *KnownHandle; + + for (Link = mFvHandleList.ForwardLink; Link != &mFvHandleList; Link = Link->ForwardLink) { + KnownHandle = CR(Link, KNOWN_HANDLE, Link, KNOWN_HANDLE_SIGNATURE); + if (KnownHandle->Handle == FvHandle) { + return TRUE; + } + } + return FALSE; +} + + +VOID +FvIsBeingProcesssed ( + IN EFI_HANDLE FvHandle + ) +/*++ + +Routine Description: + + Remember that Fv protocol on FvHandle has had it's drivers placed on the + mDiscoveredList. This fucntion adds entries on the mFvHandleList. Items are + never removed/freed from the mFvHandleList. + +Arguments: + + FvHandle - The handle of a FV that has been processed + +Returns: + + None + +--*/ +{ + KNOWN_HANDLE *KnownHandle; + + KnownHandle = CoreAllocateBootServicesPool (sizeof (KNOWN_HANDLE)); + ASSERT (KnownHandle != NULL); + if (KnownHandle == NULL) { + // + // Failed to allocate memory, no recovery path implemented as this is not expected to occur + // + EFI_DEADLOOP (); + } + + KnownHandle->Signature = KNOWN_HANDLE_SIGNATURE; + KnownHandle->Handle = FvHandle; + InsertTailList (&mFvHandleList, &KnownHandle->Link); +} + + + + +EFI_DEVICE_PATH_PROTOCOL * +CoreFvToDevicePath ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *Fv, + IN EFI_HANDLE FvHandle, + IN EFI_GUID *DriverName + ) +/*++ + +Routine Description: + + Convert FvHandle and DriverName into an EFI device path + +Arguments: + + Fv - Fv protocol, needed to read Depex info out of FLASH. + + FvHandle - Handle for Fv, needed in the EFI_CORE_DRIVER_ENTRY so that the + PE image can be read out of the FV at a later time. + + DriverName - Name of driver to add to mDiscoveredList. + +Returns: + + Pointer to device path constructed from FvHandle and DriverName + +--*/ +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *FvDevicePath; + EFI_DEVICE_PATH_PROTOCOL *FileNameDevicePath; + + // + // Remember the device path of the FV + // + Status = CoreHandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, &FvDevicePath); + if (EFI_ERROR (Status)) { + FileNameDevicePath = NULL; + } else { + // + // Build a device path to the file in the FV to pass into gBS->LoadImage + // + CoreInitializeFwVolDevicepathNode (&mFvDevicePath.File, DriverName); + mFvDevicePath.End.Type = EFI_END_ENTIRE_DEVICE_PATH; + mFvDevicePath.End.SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; + SetDevicePathNodeLength (&mFvDevicePath.End, sizeof (EFI_DEVICE_PATH_PROTOCOL)); + FileNameDevicePath = CoreAppendDevicePath ( + FvDevicePath, + (EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath + ); + } + + return FileNameDevicePath; +} + + + +EFI_STATUS +CoreAddToDriverList ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *Fv, + IN EFI_HANDLE FvHandle, + IN EFI_GUID *DriverName + ) +/*++ + +Routine Description: + + Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry, + and initilize any state variables. Read the Depex from the FV and store it + in DriverEntry. Pre-process the Depex to set the SOR, Before and After state. + The Discovered list is never free'ed and contains booleans that represent the + other possible DXE driver states. + +Arguments: + + Fv - Fv protocol, needed to read Depex info out of FLASH. + + FvHandle - Handle for Fv, needed in the EFI_CORE_DRIVER_ENTRY so that the + PE image can be read out of the FV at a later time. + + DriverName - Name of driver to add to mDiscoveredList. + +Returns: + + EFI_SUCCESS - If driver was added to the mDiscoveredList. + + EFI_ALREADY_STARTED - The driver has already been started. Only one DriverName + may be active in the system at any one time. + +--*/ +{ + EFI_CORE_DRIVER_ENTRY *DriverEntry; + + + // + // Create the Driver Entry for the list. ZeroPool initializes lots of variables to + // NULL or FALSE. + // + DriverEntry = CoreAllocateZeroBootServicesPool (sizeof (EFI_CORE_DRIVER_ENTRY)); + ASSERT (DriverEntry != NULL); + if (DriverEntry == NULL) { + // + // Failed to allocate memory, no recovery path implemented as this is not expected to occur + // + EFI_DEADLOOP (); + } + + DriverEntry->Signature = EFI_CORE_DRIVER_ENTRY_SIGNATURE; + EfiCommonLibCopyMem (&DriverEntry->FileName, DriverName, sizeof (EFI_GUID)); + DriverEntry->FvHandle = FvHandle; + DriverEntry->Fv = Fv; + DriverEntry->FvFileDevicePath = CoreFvToDevicePath (Fv, FvHandle, DriverName); + + CoreGetDepexSectionAndPreProccess (DriverEntry); + + CoreAcquireDispatcherLock (); + + InsertTailList (&mDiscoveredList, &DriverEntry->Link); + + CoreReleaseDispatcherLock (); + + return EFI_SUCCESS; +} + + + +EFI_STATUS +CoreProcessFvImageFile ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *Fv, + IN EFI_HANDLE FvHandle, + IN EFI_GUID *DriverName + ) +/*++ + +Routine Description: + + Get the driver from the FV through driver name, and produce a FVB protocol on FvHandle. + +Arguments: + + Fv - The FIRMWARE_VOLUME protocol installed on the FV. + FvHandle - The handle which FVB protocol installed on. + DriverName - The driver guid specified. + +Returns: + + EFI_OUT_OF_RESOURCES - No enough memory or other resource. + + EFI_VOLUME_CORRUPTED - Corrupted volume. + + EFI_SUCCESS - Function successfully returned. + + +--*/ +{ + EFI_STATUS Status; + EFI_SECTION_TYPE SectionType; + UINT32 AuthenticationStatus; + VOID *Buffer; + UINTN BufferSize; + + // + // Read the first (and only the first) firmware volume section + // + SectionType = EFI_SECTION_FIRMWARE_VOLUME_IMAGE; + Buffer = NULL; + BufferSize = 0; + Status = Fv->ReadSection ( + Fv, + DriverName, + SectionType, + 0, + &Buffer, + &BufferSize, + &AuthenticationStatus + ); + if (!EFI_ERROR (Status)) { + // + // Produce a FVB protocol for the file + // + Status = ProduceFVBProtocolOnBuffer ( + (EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, + (UINT64)BufferSize, + FvHandle, + NULL + ); + } + + if (EFI_ERROR (Status) && (Buffer != NULL)) { + // + // ReadSection or Produce FVB failed, Free data buffer + // + gBS->FreePool (Buffer); + + } + + return Status; +} + + +VOID +EFIAPI +CoreFwVolEventProtocolNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + + Event notification that is fired every time a FV dispatch protocol is added. + More than one protocol may have been added when this event is fired, so you + must loop on CoreLocateHandle () to see how many protocols were added and + do the following to each FV: + + If the Fv has already been processed, skip it. If the Fv has not been + processed then mark it as being processed, as we are about to process it. + + Read the Fv and add any driver in the Fv to the mDiscoveredList.The + mDiscoveredList is never free'ed and contains variables that define + the other states the DXE driver transitions to.. + + While you are at it read the A Priori file into memory. + Place drivers in the A Priori list onto the mScheduledQueue. + +Arguments: + + Event - The Event that is being processed, not used. + + Context - Event Context, not used. + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + EFI_STATUS GetNextFileStatus; + EFI_STATUS SecurityStatus; + EFI_FIRMWARE_VOLUME_PROTOCOL *Fv; + EFI_DEVICE_PATH_PROTOCOL *FvDevicePath; + EFI_HANDLE FvHandle; + UINTN BufferSize; + EFI_GUID NameGuid; + UINTN Key; + EFI_FV_FILETYPE Type; + EFI_FV_FILE_ATTRIBUTES Attributes; + UINTN Size; + EFI_CORE_DRIVER_ENTRY *DriverEntry; + EFI_GUID *AprioriFile; + UINTN AprioriEntryCount; + UINTN Index; + EFI_LIST_ENTRY *Link; + UINT32 AuthenticationStatus; + UINTN SizeOfBuffer; + + + while (TRUE) { + BufferSize = sizeof (EFI_HANDLE); + Status = CoreLocateHandle ( + ByRegisterNotify, + NULL, + mFwVolEventRegistration, + &BufferSize, + &FvHandle + ); + if (EFI_ERROR (Status)) { + // + // If no more notification events exit + // + return; + } + + if (FvHasBeenProcessed (FvHandle)) { + // + // This Fv has already been processed so lets skip it! + // + continue; + } + + Status = CoreHandleProtocol (FvHandle, &gEfiFirmwareVolumeDispatchProtocolGuid, &Fv); + if (EFI_ERROR (Status)) { + // + // If no dispatch protocol then skip, but do not marked as being processed as it + // may show up later. + // + continue; + } + + // + // Since we are about to process this Fv mark it as processed. + // + FvIsBeingProcesssed (FvHandle); + + + Status = CoreHandleProtocol (FvHandle, &gEfiFirmwareVolumeProtocolGuid, &Fv); + if (EFI_ERROR (Status) || (Fv == NULL)) { + // + // The Handle has a FirmwareVolumeDispatch protocol and should also contiain + // a FirmwareVolume protocol thus we should never get here. + // + ASSERT (FALSE); + continue; + } + + Status = CoreHandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, &FvDevicePath); + if (EFI_ERROR (Status)) { + // + // The Firmware volume doesn't have device path, can't be dispatched. + // + continue; + } + + // + // Evaluate the authentication status of the Firmware Volume through + // Security Architectural Protocol + // + if (gSecurity != NULL) { + SecurityStatus = gSecurity->FileAuthenticationState ( + gSecurity, + 0, + FvDevicePath + ); + if (SecurityStatus != EFI_SUCCESS) { + // + // Security check failed. The firmware volume should not be used for any purpose. + // + continue; + } + } + + // + // Discover Drivers in FV and add them to the Discovered Driver List. + // Process EFI_FV_FILETYPE_DRIVER type and then EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER + // EFI_FV_FILETYPE_DXE_CORE is processed to produce a Loaded Image protocol for the core + // EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE is processed to create a Fvb + // + for (Index = 0; Index < sizeof (mDxeFileTypes)/sizeof (EFI_FV_FILETYPE); Index++) { + // + // Initialize the search key + // + Key = 0; + do { + Type = mDxeFileTypes[Index]; + GetNextFileStatus = Fv->GetNextFile ( + Fv, + &Key, + &Type, + &NameGuid, + &Attributes, + &Size + ); + if (!EFI_ERROR (GetNextFileStatus)) { + if (Type == EFI_FV_FILETYPE_DXE_CORE) { + // + // If this is the DXE core fill in it's DevicePath & DeviceHandle + // + if (gDxeCoreLoadedImage->FilePath == NULL) { + if (EfiCompareGuid (&NameGuid, gDxeCoreFileName)) { + CoreInitializeFwVolDevicepathNode (&mFvDevicePath.File, &NameGuid); + mFvDevicePath.End.Type = EFI_END_ENTIRE_DEVICE_PATH; + mFvDevicePath.End.SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; + SetDevicePathNodeLength (&mFvDevicePath.End, sizeof (EFI_DEVICE_PATH_PROTOCOL)); + + gDxeCoreLoadedImage->FilePath = CoreDuplicateDevicePath ( + (EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath + ); + gDxeCoreLoadedImage->DeviceHandle = FvHandle; + } + } + } else if (Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) { + // + // Found a firmware volume image. Produce a firmware volume block + // protocol for it so it gets dispatched from. This is usually a + // capsule. + // + CoreProcessFvImageFile (Fv, FvHandle, &NameGuid); + } else { + // + // Transition driver from Undiscovered to Discovered state + // + CoreAddToDriverList (Fv, FvHandle, &NameGuid); + } + } + } while (!EFI_ERROR (GetNextFileStatus)); + } + + // + // Read the array of GUIDs from the Apriori file if it is present in the firmware volume + // + AprioriFile = NULL; + Status = Fv->ReadSection ( + Fv, + &gAprioriGuid, + EFI_SECTION_RAW, + 0, + &AprioriFile, + &SizeOfBuffer, + &AuthenticationStatus + ); + if (!EFI_ERROR (Status)) { + AprioriEntryCount = SizeOfBuffer / sizeof (EFI_GUID); + } else { + AprioriEntryCount = 0; + } + + // + // Put drivers on Apriori List on the Scheduled queue. The Discovered List includes + // drivers not in the current FV and these must be skipped since the a priori list + // is only valid for the FV that it resided in. + // + CoreAcquireDispatcherLock (); + + for (Index = 0; Index < AprioriEntryCount; Index++) { + for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) { + DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE); + if (EfiCompareGuid (&DriverEntry->FileName, &AprioriFile[Index]) && + (FvHandle == DriverEntry->FvHandle)) { + DriverEntry->Dependent = FALSE; + DriverEntry->Scheduled = TRUE; + InsertTailList (&mScheduledQueue, &DriverEntry->ScheduledLink); + break; + } + } + } + + CoreReleaseDispatcherLock (); + + // + // Free data allocated by Fv->ReadSection () + // + gBS->FreePool (AprioriFile); + } +} + + +VOID +CoreInitializeDispatcher ( + VOID + ) +/*++ + +Routine Description: + + Initialize the dispatcher. Initialize the notification function that runs when + a FV protocol is added to the system. + +Arguments: + + NONE + +Returns: + + NONE + +--*/ +{ + mFwVolEvent = CoreCreateProtocolNotifyEvent ( + &gEfiFirmwareVolumeProtocolGuid, + EFI_TPL_CALLBACK, + CoreFwVolEventProtocolNotify, + NULL, + &mFwVolEventRegistration, + TRUE + ); +} + +// +// Function only used in debug buils +// +DEBUG_CODE ( +VOID +CoreDisplayDiscoveredNotDispatched ( + VOID + ) +/*++ + +Routine Description: + + Traverse the discovered list for any drivers that were discovered but not loaded + because the dependency experessions evaluated to false + +Arguments: + + NONE + +Returns: + + NONE + +--*/ +{ + EFI_LIST_ENTRY *Link; + EFI_CORE_DRIVER_ENTRY *DriverEntry; + + for (Link = mDiscoveredList.ForwardLink;Link !=&mDiscoveredList; Link = Link->ForwardLink) { + DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE); + if (DriverEntry->Dependent) { + DEBUG ((EFI_D_LOAD, "Driver %g was discovered but not loaded!!\n", &DriverEntry->FileName)); + } + } +} +) diff --git a/EDK/Foundation/Core/Dxe/Dispatcher/dependency.c b/EDK/Foundation/Core/Dxe/Dispatcher/dependency.c new file mode 100644 index 0000000..b08c5bf --- /dev/null +++ b/EDK/Foundation/Core/Dxe/Dispatcher/dependency.c @@ -0,0 +1,451 @@ +/*++ + +Copyright (c) 2004 - 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + dependency.c + +Abstract: + + DXE Dispatcher Dependency Evaluator + + This routine evaluates a dependency expression (DEPENDENCY_EXPRESSION) to determine + if a driver can be scheduled for execution. The criteria for + schedulability is that the dependency expression is satisfied. + +--*/ + +#include "Tiano.h" +#include "DxeCore.h" +#include "EfiDependency.h" + +// +// Global stack used to evaluate dependency expressions +// +BOOLEAN *mDepexEvaluationStack = NULL; +BOOLEAN *mDepexEvaluationStackEnd = NULL; +BOOLEAN *mDepexEvaluationStackPointer = NULL; + +// +// Worker functions +// + +STATIC +EFI_STATUS +GrowDepexStack ( + VOID + ) +/*++ + +Routine Description: + + Grow size of the Depex stack + +Arguments: + + Stack - Old stack on the way in and new stack on the way out + + StackSize - New size of the stack + +Returns: + + EFI_SUCCESS - Stack successfully growed. + + EFI_OUT_OF_RESOURCES - There is not enough system memory to grow the stack. + + + +--*/ +{ + BOOLEAN *NewStack; + UINTN Size; + + Size = DEPEX_STACK_SIZE_INCREMENT; + if (mDepexEvaluationStack != NULL) { + Size = Size + (mDepexEvaluationStackEnd - mDepexEvaluationStack); + } + + NewStack = CoreAllocateBootServicesPool (Size * sizeof (BOOLEAN)); + if (NewStack == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if (mDepexEvaluationStack != NULL) { + // + // Copy to Old Stack to the New Stack + // + EfiCommonLibCopyMem ( + NewStack, + mDepexEvaluationStack, + (mDepexEvaluationStackEnd - mDepexEvaluationStack) * sizeof (BOOLEAN) + ); + + // + // Free The Old Stack + // + CoreFreePool (mDepexEvaluationStack); + } + + // + // Make the Stack pointer point to the old data in the new stack + // + mDepexEvaluationStackPointer = NewStack + (mDepexEvaluationStackPointer - mDepexEvaluationStack); + mDepexEvaluationStack = NewStack; + mDepexEvaluationStackEnd = NewStack + Size; + + return EFI_SUCCESS; +} + + +STATIC +EFI_STATUS +PushBool ( + IN BOOLEAN Value + ) +/*++ + +Routine Description: + + Push an element onto the Boolean Stack + +Arguments: + + Value - BOOLEAN to push. + +Returns: + + EFI_SUCCESS - The value was pushed onto the stack. + + EFI_OUT_OF_RESOURCES - There is not enough system memory to grow the stack. + +--*/ +{ + EFI_STATUS Status; + + // + // Check for a stack overflow condition + // + if (mDepexEvaluationStackPointer == mDepexEvaluationStackEnd) { + // + // Grow the stack + // + Status = GrowDepexStack (); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Push the item onto the stack + // + *mDepexEvaluationStackPointer = Value; + mDepexEvaluationStackPointer++; + + return EFI_SUCCESS; +} + + +STATIC +EFI_STATUS +PopBool ( + OUT BOOLEAN *Value + ) +/*++ + +Routine Description: + + Pop an element from the Boolean stack. + +Arguments: + + Value - BOOLEAN to pop. + +Returns: + + EFI_SUCCESS - The value was popped onto the stack. + + EFI_ACCESS_DENIED - The pop operation underflowed the stack + +--*/ +{ + // + // Check for a stack underflow condition + // + if (mDepexEvaluationStackPointer == mDepexEvaluationStack) { + return EFI_ACCESS_DENIED; + } + + // + // Pop the item off the stack + // + mDepexEvaluationStackPointer--; + *Value = *mDepexEvaluationStackPointer; + return EFI_SUCCESS; +} + + +EFI_STATUS +CorePreProcessDepex ( + IN EFI_CORE_DRIVER_ENTRY *DriverEntry + ) +/*++ + +Routine Description: + + Preprocess dependency expression and update DriverEntry to reflect the + state of Before, After, and SOR dependencies. If DriverEntry->Before + or DriverEntry->After is set it will never be cleared. If SOR is set + it will be cleared by CoreSchedule(), and then the driver can be + dispatched. + +Arguments: + + DriverEntry - DriverEntry element to update + +Returns: + + EFI_SUCCESS - It always works. + +--*/ +{ + UINT8 *Iterator; + + Iterator = DriverEntry->Depex; + if (*Iterator == EFI_DEP_SOR) { + DriverEntry->Unrequested = TRUE; + } else { + DriverEntry->Dependent = TRUE; + } + + if (*Iterator == EFI_DEP_BEFORE) { + DriverEntry->Before = TRUE; + } else if (*Iterator == EFI_DEP_AFTER) { + DriverEntry->After = TRUE; + } + + if (DriverEntry->Before || DriverEntry->After) { + EfiCommonLibCopyMem (&DriverEntry->BeforeAfterGuid, Iterator + 1, sizeof (EFI_GUID)); + } + + return EFI_SUCCESS; +} + + +BOOLEAN +CoreIsSchedulable ( + IN EFI_CORE_DRIVER_ENTRY *DriverEntry + ) +/*++ + +Routine Description: + + This is the POSTFIX version of the dependency evaluator. This code does + not need to handle Before or After, as it is not valid to call this + routine in this case. The SOR is just ignored and is a nop in the grammer. + + POSTFIX means all the math is done on top of the stack. + +Arguments: + + DriverEntry - DriverEntry element to update + +Returns: + + TRUE - If driver is ready to run. + FALSE - If driver is not ready to run or some fatal error was found. + +--*/ +{ + EFI_STATUS Status; + UINT8 *Iterator; + BOOLEAN Operator; + BOOLEAN Operator2; + EFI_GUID DriverGuid; + VOID *Interface; + + if (DriverEntry->After || DriverEntry->Before) { + // + // If Before or After Depex skip as CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter () + // processes them. + // + return FALSE; + } + + if (DriverEntry->Depex == NULL) { + // + // A NULL Depex means treat the driver like an EFI 1.0 thing. + // + Status = CoreAllEfiServicesAvailable (); + if (EFI_ERROR (Status)) { + return FALSE; + } + return TRUE; + } + + // + // Clean out memory leaks in Depex Boolean stack. Leaks are only caused by + // incorrectly formed DEPEX expressions + // + mDepexEvaluationStackPointer = mDepexEvaluationStack; + + + Iterator = DriverEntry->Depex; + + while (TRUE) { + // + // Check to see if we are attempting to fetch dependency expression instructions + // past the end of the dependency expression. + // + if (((UINTN) Iterator - (UINTN) DriverEntry->Depex) >= DriverEntry->DepexSize) { + return FALSE; + } + + // + // Look at the opcode of the dependency expression instruction. + // + switch (*Iterator) { + case EFI_DEP_BEFORE: + case EFI_DEP_AFTER: + // + // For a well-formed Dependency Expression, the code should never get here. + // The BEFORE and AFTER are processed prior to this routine's invocation. + // If the code flow arrives at this point, there was a BEFORE or AFTER + // that were not the first opcodes. + // + ASSERT (FALSE); + case EFI_DEP_SOR: + // + // These opcodes can only appear once as the first opcode. If it is found + // at any other location, then the dependency expression evaluates to FALSE + // + if (Iterator != DriverEntry->Depex) { + return FALSE; + } + // + // Otherwise, it is the first opcode and should be treated as a NOP. + // + break; + + case EFI_DEP_PUSH: + // + // Push operator is followed by a GUID. Test to see if the GUID protocol + // is installed and push the boolean result on the stack. + // + EfiCommonLibCopyMem (&DriverGuid, Iterator + 1, sizeof (EFI_GUID)); + + Status = CoreLocateProtocol (&DriverGuid, NULL, &Interface); + + if (EFI_ERROR (Status)) { + Status = PushBool (FALSE); + } else { + *Iterator = EFI_DEP_REPLACE_TRUE; + Status = PushBool (TRUE); + } + if (EFI_ERROR (Status)) { + return FALSE; + } + + Iterator += sizeof (EFI_GUID); + break; + + case EFI_DEP_AND: + Status = PopBool (&Operator); + if (EFI_ERROR (Status)) { + return FALSE; + } + + Status = PopBool (&Operator2); + if (EFI_ERROR (Status)) { + return FALSE; + } + + Status = PushBool ((BOOLEAN) (Operator && Operator2)); + if (EFI_ERROR (Status)) { + return FALSE; + } + break; + + case EFI_DEP_OR: + Status = PopBool (&Operator); + if (EFI_ERROR (Status)) { + return FALSE; + } + + Status = PopBool (&Operator2); + if (EFI_ERROR (Status)) { + return FALSE; + } + + Status = PushBool ((BOOLEAN) (Operator || Operator2)); + if (EFI_ERROR (Status)) { + return FALSE; + } + break; + + case EFI_DEP_NOT: + Status = PopBool (&Operator); + if (EFI_ERROR (Status)) { + return FALSE; + } + + Status = PushBool ((BOOLEAN) (!Operator)); + if (EFI_ERROR (Status)) { + return FALSE; + } + break; + + case EFI_DEP_TRUE: + Status = PushBool (TRUE); + if (EFI_ERROR (Status)) { + return FALSE; + } + break; + + case EFI_DEP_FALSE: + Status = PushBool (FALSE); + if (EFI_ERROR (Status)) { + return FALSE; + } + break; + + case EFI_DEP_END: + Status = PopBool (&Operator); + if (EFI_ERROR (Status)) { + return FALSE; + } + return Operator; + + case EFI_DEP_REPLACE_TRUE: + Status = PushBool (TRUE); + if (EFI_ERROR (Status)) { + return FALSE; + } + + Iterator += sizeof (EFI_GUID); + break; + + default: + return FALSE; + } + + // + // Skip over the Dependency Op Code we just processed in the switch. + // The math is done out of order, but it should not matter. That is + // we may add in the sizeof (EFI_GUID) before we account for the OP Code. + // This is not an issue, since we just need the correct end result. You + // need to be careful using Iterator in the loop as it's intermediate value + // may be strange. + // + Iterator++; + } + return FALSE; +} + diff --git a/EDK/Foundation/Core/Dxe/DxeMain.cif b/EDK/Foundation/Core/Dxe/DxeMain.cif new file mode 100644 index 0000000..cd1fa6c --- /dev/null +++ b/EDK/Foundation/Core/Dxe/DxeMain.cif @@ -0,0 +1,53 @@ + + name = "DxeMain" + category = ModulePart + LocalRoot = "EDK\Foundation\Core\Dxe\" + RefName = "DxeMain" +[files] +"DxeMain.inf" +"Dispatcher\dependency.c" +"Dispatcher\Dispatcher.c" +"DxeMain\DxeMain.c" +"DxeMain\DxeProtocolNotify.c" +"Event\event.c" +"Event\exec.h" +"Event\execdata.c" +"Event\timer.c" +"Event\tpl.c" +"FwVol\Ffs.c" +"FwVol\FwVol.c" +"FwVol\FwVolAttrib.c" +"FwVol\FwVolDriver.h" +"FwVol\FwVolRead.c" +"FwVol\FwVolWrite.c" +"FwVolBlock\FwVolBlock.c" +"FwVolBlock\FwVolBlock.h" +"Gcd\gcd.c" +"Gcd\gcd.h" +"Hand\DriverSupport.c" +"Hand\hand.h" +"Hand\handle.c" +"Hand\locate.c" +"Hand\Notify.c" +"Ia32\Processor.h" +"Image\Image.c" +"Image\Image.h" +"Image\ImageFile.c" +"Include\DxeCore.h" +"Include\Library.h" +"Ipf\Processor.h" +"Library\Library.c" +"Mem\imem.h" +"Mem\memdata.c" +"Mem\Page.c" +"Mem\pool.c" +"Misc\DebugImageInfo.c" +"Misc\DebugImageInfo.h" +"Misc\DebugMask.c" +"Misc\DebugMask.h" +"Misc\InstallConfigurationTable.c" +"Misc\SetWatchdogTimer.c" +"Misc\Stall.c" +"SectionExtraction\CoreSectionExtraction.c" +"x64\Processor.h" + diff --git a/EDK/Foundation/Core/Dxe/DxeMain.inf b/EDK/Foundation/Core/Dxe/DxeMain.inf new file mode 100644 index 0000000..5f6a047 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/DxeMain.inf @@ -0,0 +1,111 @@ +#/*++ +# +# Copyright (c) 2004 - 2005, Intel Corporation +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# Module Name: +# +# DxeMain.inf +# +# Abstract: +# +# Component description file for DxeMain. +# +--*/ + +[defines] +BASE_NAME = DxeMain +FILE_GUID = 35B898CA-B6A9-49CE-8C72-904735CC49B7 +COMPONENT_TYPE = BS_DRIVER + +[sources.common] + DxeMain\DxeMain.c + DxeMain\DxeProtocolNotify.c + Dispatcher\Dispatcher.c + Dispatcher\Dependency.c + Event\ExecData.c + Event\Event.c + Event\Exec.h + Event\Timer.c + Event\Tpl.c + FwVol\FwVolDriver.h + FwVol\FwVol.c + FwVol\Ffs.c + FwVol\FwVolAttrib.c + FwVol\FwVolRead.c + FwVol\FwVolWrite.c + FwVolBlock\FwVolBlock.c + FwVolBlock\FwVolBlock.h + Mem\Imem.h + Mem\MemData.c + Mem\Page.c + Mem\Pool.c + Gcd\Gcd.h + Gcd\Gcd.c + Hand\Hand.h + Hand\Handle.c + Hand\Locate.c + Hand\Notify.c + Hand\DriverSupport.c + Library\Library.c + Misc\InstallConfigurationTable.c + Misc\SetWatchdogTimer.c + Misc\Stall.c + Misc\DebugImageInfo.h + Misc\DebugImageInfo.c + Misc\DebugMask.h + Misc\DebugMask.c + Image\Image.h + Image\Image.c + Image\ImageFile.c + SectionExtraction\CoreSectionExtraction.c + +[sources.Ia32] + Ia32\Processor.h + +[sources.Ipf] + Ipf\Processor.h + +[sources.x64] + x64\Processor.h + +[includes.common] + $(EDK_SOURCE)\Foundation\Framework + $(EDK_SOURCE)\Foundation\Efi + $(EDK_SOURCE)\Foundation + . + $(EDK_SOURCE)\Foundation\Include + $(EDK_SOURCE)\Foundation\Efi\Include + $(EDK_SOURCE)\Foundation\Framework\Include + $(EDK_SOURCE)\Foundation\Include\IndustryStandard + $(EDK_SOURCE)\Foundation\Core\Dxe + $(EDK_SOURCE)\Foundation\Core\Dxe\Hand + $(EDK_SOURCE)\Foundation\Core\Dxe\Include + $(EDK_SOURCE)\Foundation\Core\Dxe\Misc + $(EDK_SOURCE)\Foundation\Core\Dxe\FwVolBlock + $(EDK_SOURCE)\Foundation\Library\Dxe\Include + $(EDK_SOURCE)\Foundation\Include\Pei + $(EDK_SOURCE)\Foundation\Library\Pei\Include + +[libraries.common] + EdkGuidLib + EdkFrameworkGuidLib + EfiGuidLib + EdkProtocolLib + EdkFrameworkProtocolLib + EfiProtocolLib + EfiCommonLib + HobLib + ArchProtocolLib + EfiDriverLib + +[nmake.common] + IMAGE_ENTRY_POINT=DxeMain + C_PROJ_FLAGS = $(C_PROJ_FLAGS) /Ob0 + diff --git a/EDK/Foundation/Core/Dxe/DxeMain/DxeMain.c b/EDK/Foundation/Core/Dxe/DxeMain/DxeMain.c new file mode 100644 index 0000000..4dc53be --- /dev/null +++ b/EDK/Foundation/Core/Dxe/DxeMain/DxeMain.c @@ -0,0 +1,1010 @@ +/*++ + +Copyright (c) 2004 - 2011, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DxeMain.c + +Abstract: + + DXE Core Main Entry Point + +--*/ + +#include "Tiano.h" +#include "DxeCore.h" +#include "EfiHobLib.h" +#include "EfiPerf.h" +#include "FwVolBlock.h" + + +VOID +EFIAPI +DxeMain ( + IN VOID *HobStart + ); + +EFI_STATUS +EFIAPI +CoreEfiNotAvailableYetArg0 ( + VOID + ); + +EFI_STATUS +EFIAPI +CoreEfiNotAvailableYetArg1 ( + UINTN Arg1 + ); + +EFI_STATUS +EFIAPI +CoreEfiNotAvailableYetArg2 ( + UINTN Arg1, + UINTN Arg2 + ); + +EFI_STATUS +EFIAPI +CoreEfiNotAvailableYetArg3 ( + UINTN Arg1, + UINTN Arg2, + UINTN Arg3 + ); + +EFI_STATUS +EFIAPI +CoreEfiNotAvailableYetArg4 ( + UINTN Arg1, + UINTN Arg2, + UINTN Arg3, + UINTN Arg4 + ); + +EFI_STATUS +EFIAPI +CoreEfiNotAvailableYetArg5 ( + UINTN Arg1, + UINTN Arg2, + UINTN Arg3, + UINTN Arg4, + UINTN Arg5 + ); + +EFI_STATUS +CoreGetPeiProtocol ( + IN EFI_GUID *ProtocolGuid, + IN VOID **Interface + ); + +PERF_CODE ( + EFI_STATUS + GetTimerValue ( + OUT UINT64 *TimerValue + ); +) + +// +// DXE Core Global Variables for Protocols from PEI +// +EFI_DECOMPRESS_PROTOCOL *gEfiDecompress = NULL; +EFI_TIANO_DECOMPRESS_PROTOCOL *gEfiTianoDecompress = NULL; +EFI_CUSTOMIZED_DECOMPRESS_PROTOCOL *gEfiCustomizedDecompress = NULL; +EFI_PEI_FLUSH_INSTRUCTION_CACHE_PROTOCOL *gEfiPeiFlushInstructionCache = NULL; +EFI_PEI_PE_COFF_LOADER_PROTOCOL *gEfiPeiPeCoffLoader = NULL; +EFI_PEI_TRANSFER_CONTROL_PROTOCOL *gEfiPeiTransferControl = NULL; + +// +// DXE Core globals for Architecture Protocols +// +EFI_SECURITY_ARCH_PROTOCOL *gSecurity = NULL; +EFI_CPU_ARCH_PROTOCOL *gCpu = NULL; +EFI_METRONOME_ARCH_PROTOCOL *gMetronome = NULL; +EFI_TIMER_ARCH_PROTOCOL *gTimer = NULL; +EFI_BDS_ARCH_PROTOCOL *gBds = NULL; +EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *gWatchdogTimer = NULL; + +// +// DXE Core Global used to update core loaded image protocol handle +// +EFI_GUID *gDxeCoreFileName; +EFI_LOADED_IMAGE_PROTOCOL *gDxeCoreLoadedImage; + +// +// BugBug: I'n not runtime, but is the PPI? +// +EFI_STATUS_CODE_PROTOCOL gStatusCodeInstance = { + NULL +}; + +EFI_STATUS_CODE_PROTOCOL *gStatusCode = &gStatusCodeInstance; + +// +// DXE Core Module Variables +// + +EFI_BOOT_SERVICES mBootServices = { + { + EFI_BOOT_SERVICES_SIGNATURE, // Signature + EFI_BOOT_SERVICES_REVISION, // Revision + sizeof (EFI_BOOT_SERVICES), // HeaderSize + 0, // CRC32 + 0 // Reserved + }, + (EFI_RAISE_TPL) CoreRaiseTpl, // RaiseTPL + (EFI_RESTORE_TPL) CoreRestoreTpl, // RestoreTPL + (EFI_ALLOCATE_PAGES) CoreAllocatePages, // AllocatePages + (EFI_FREE_PAGES) CoreFreePages, // FreePages + (EFI_GET_MEMORY_MAP) CoreGetMemoryMap, // GetMemoryMap + (EFI_ALLOCATE_POOL) CoreAllocatePool, // AllocatePool + (EFI_FREE_POOL) CoreFreePool, // FreePool + (EFI_CREATE_EVENT) CoreCreateEvent, // CreateEvent + (EFI_SET_TIMER) CoreSetTimer, // SetTimer + (EFI_WAIT_FOR_EVENT) CoreWaitForEvent, // WaitForEvent + (EFI_SIGNAL_EVENT) CoreSignalEvent, // SignalEvent + (EFI_CLOSE_EVENT) CoreCloseEvent, // CloseEvent + (EFI_CHECK_EVENT) CoreCheckEvent, // CheckEvent + (EFI_INSTALL_PROTOCOL_INTERFACE) CoreInstallProtocolInterface, // InstallProtocolInterface + (EFI_REINSTALL_PROTOCOL_INTERFACE) CoreReinstallProtocolInterface, // ReinstallProtocolInterface + (EFI_UNINSTALL_PROTOCOL_INTERFACE) CoreUninstallProtocolInterface, // UninstallProtocolInterface + (EFI_HANDLE_PROTOCOL) CoreHandleProtocol, // HandleProtocol + (VOID *) NULL, // Reserved + (EFI_REGISTER_PROTOCOL_NOTIFY) CoreRegisterProtocolNotify, // RegisterProtocolNotify + (EFI_LOCATE_HANDLE) CoreLocateHandle, // LocateHandle + (EFI_LOCATE_DEVICE_PATH) CoreLocateDevicePath, // LocateDevicePath + (EFI_INSTALL_CONFIGURATION_TABLE) CoreInstallConfigurationTable, // InstallConfigurationTable + (EFI_IMAGE_LOAD) CoreLoadImage, // LoadImage + (EFI_IMAGE_START) CoreStartImage, // StartImage + (EFI_EXIT) CoreExit, // Exit + (EFI_IMAGE_UNLOAD) CoreUnloadImage, // UnloadImage + (EFI_EXIT_BOOT_SERVICES) CoreExitBootServices, // ExitBootServices + (EFI_GET_NEXT_MONOTONIC_COUNT) CoreEfiNotAvailableYetArg1, // GetNextMonotonicCount + (EFI_STALL) CoreStall, // Stall + (EFI_SET_WATCHDOG_TIMER) CoreSetWatchdogTimer, // SetWatchdogTimer + (EFI_CONNECT_CONTROLLER) CoreConnectController, // ConnectController + (EFI_DISCONNECT_CONTROLLER) CoreDisconnectController, // DisconnectController + (EFI_OPEN_PROTOCOL) CoreOpenProtocol, // OpenProtocol + (EFI_CLOSE_PROTOCOL) CoreCloseProtocol, // CloseProtocol + (EFI_OPEN_PROTOCOL_INFORMATION) CoreOpenProtocolInformation, // OpenProtocolInformation + (EFI_PROTOCOLS_PER_HANDLE) CoreProtocolsPerHandle, // ProtocolsPerHandle + (EFI_LOCATE_HANDLE_BUFFER) CoreLocateHandleBuffer, // LocateHandleBuffer + (EFI_LOCATE_PROTOCOL) CoreLocateProtocol, // LocateProtocol + (EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES) CoreInstallMultipleProtocolInterfaces, // InstallMultipleProtocolInterfaces + (EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES) CoreUninstallMultipleProtocolInterfaces, // UninstallMultipleProtocolInterfaces + (EFI_CALCULATE_CRC32) CoreEfiNotAvailableYetArg3, // CalculateCrc32 + (EFI_COPY_MEM) EfiCommonLibCopyMem, // CopyMem + (EFI_SET_MEM) EfiCommonLibSetMem // SetMem +#if (EFI_SPECIFICATION_VERSION >= 0x00020000) + , + // + // UEFI 2.0 Extension to the table + // + (EFI_CREATE_EVENT_EX) CoreCreateEventEx +#endif +}; + +EFI_DXE_SERVICES mDxeServices = { + { + EFI_DXE_SERVICES_SIGNATURE, // Signature + EFI_DXE_SERVICES_REVISION, // Revision + sizeof (EFI_DXE_SERVICES), // HeaderSize + 0, // CRC32 + 0 // Reserved + }, + (EFI_ADD_MEMORY_SPACE) CoreAddMemorySpace, // AddMemorySpace + (EFI_ALLOCATE_MEMORY_SPACE) CoreAllocateMemorySpace, // AllocateMemorySpace + (EFI_FREE_MEMORY_SPACE) CoreFreeMemorySpace, // FreeMemorySpace + (EFI_REMOVE_MEMORY_SPACE) CoreRemoveMemorySpace, // RemoveMemorySpace + (EFI_GET_MEMORY_SPACE_DESCRIPTOR) CoreGetMemorySpaceDescriptor, // GetMemorySpaceDescriptor + (EFI_SET_MEMORY_SPACE_ATTRIBUTES) CoreSetMemorySpaceAttributes, // SetMemorySpaceAttributes + (EFI_GET_MEMORY_SPACE_MAP) CoreGetMemorySpaceMap, // GetMemorySpaceMap + (EFI_ADD_IO_SPACE) CoreAddIoSpace, // AddIoSpace + (EFI_ALLOCATE_IO_SPACE) CoreAllocateIoSpace, // AllocateIoSpace + (EFI_FREE_IO_SPACE) CoreFreeIoSpace, // FreeIoSpace + (EFI_REMOVE_IO_SPACE) CoreRemoveIoSpace, // RemoveIoSpace + (EFI_GET_IO_SPACE_DESCRIPTOR) CoreGetIoSpaceDescriptor, // GetIoSpaceDescriptor + (EFI_GET_IO_SPACE_MAP) CoreGetIoSpaceMap, // GetIoSpaceMap + (EFI_DISPATCH) CoreDispatcher, // Dispatch + (EFI_SCHEDULE) CoreSchedule, // Schedule + (EFI_TRUST) CoreTrust, // Trust + (EFI_PROCESS_FIRMWARE_VOLUME) CoreProcessFirmwareVolume, // ProcessFirmwareVolume +}; + +EFI_SYSTEM_TABLE mEfiSystemTableTemplate = { + { + EFI_SYSTEM_TABLE_SIGNATURE, // Signature + EFI_SYSTEM_TABLE_REVISION, // Revision + sizeof (EFI_SYSTEM_TABLE), // HeaderSize + 0, // CRC32 + 0 // Reserved + }, + NULL, // FirmwareVendor + 0, // FirmwareRevision + NULL, // ConsoleInHandle + NULL, // ConIn + NULL, // ConsoleOutHandle + NULL, // ConOut + NULL, // StandardErrorHandle + NULL, // StdErr + NULL, // RuntimeServices + &mBootServices, // BootServices + 0, // NumberOfConfigurationTableEntries + NULL // ConfigurationTable +}; + +EFI_RUNTIME_SERVICES mEfiRuntimeServicesTableTemplate = { + { + EFI_RUNTIME_SERVICES_SIGNATURE, // Signature + EFI_RUNTIME_SERVICES_REVISION, // Revision + sizeof (EFI_RUNTIME_SERVICES), // HeaderSize + 0, // CRC32 + 0 // Reserved + }, + (EFI_GET_TIME) CoreEfiNotAvailableYetArg2, // GetTime + (EFI_SET_TIME) CoreEfiNotAvailableYetArg1, // SetTime + (EFI_GET_WAKEUP_TIME) CoreEfiNotAvailableYetArg3, // GetWakeupTime + (EFI_SET_WAKEUP_TIME) CoreEfiNotAvailableYetArg2, // SetWakeupTime + (EFI_SET_VIRTUAL_ADDRESS_MAP) CoreEfiNotAvailableYetArg4, // SetVirtualAddressMap + (EFI_CONVERT_POINTER) CoreEfiNotAvailableYetArg2, // ConvertPointer + (EFI_GET_VARIABLE) CoreEfiNotAvailableYetArg5, // GetVariable + (EFI_GET_NEXT_VARIABLE_NAME) CoreEfiNotAvailableYetArg3, // GetNextVariableName + (EFI_SET_VARIABLE) CoreEfiNotAvailableYetArg5, // SetVariable + (EFI_GET_NEXT_HIGH_MONO_COUNT) CoreEfiNotAvailableYetArg1, // GetNextHighMonotonicCount + (EFI_RESET_SYSTEM) CoreEfiNotAvailableYetArg4, // ResetSystem +#if (EFI_SPECIFICATION_VERSION >= 0x00020000) + (EFI_UPDATE_CAPSULE) CoreEfiNotAvailableYetArg3, // UpdateCapsule + (EFI_QUERY_CAPSULE_CAPABILITIES) CoreEfiNotAvailableYetArg4, // QueryCapsuleCapabilities + (EFI_QUERY_VARIABLE_INFO) CoreEfiNotAvailableYetArg4 // QueryVariableInfo +#elif (TIANO_RELEASE_VERSION != 0) + (EFI_REPORT_STATUS_CODE) CoreEfiNotAvailableYetArg5 // ReportStatusCode +#endif +}; + +EFI_RUNTIME_ARCH_PROTOCOL gRuntimeTemplate = { + INITIALIZE_LIST_HEAD_VARIABLE (gRuntimeTemplate.ImageHead), + INITIALIZE_LIST_HEAD_VARIABLE (gRuntimeTemplate.EventHead), + + // + // Make sure Size != sizeof (EFI_MEMORY_DESCRIPTOR). This will + // prevent people from having pointer math bugs in their code. + // now you have to use *DescriptorSize to make things work. + // + sizeof (EFI_MEMORY_DESCRIPTOR) + sizeof (UINT64) - (sizeof (EFI_MEMORY_DESCRIPTOR) % sizeof (UINT64)), + EFI_MEMORY_DESCRIPTOR_VERSION, + 0, + NULL, + NULL, + FALSE, + FALSE +}; + +EFI_RUNTIME_ARCH_PROTOCOL *gRuntime = &gRuntimeTemplate; + +// +// DXE Core Global Variables for the EFI System Table, Boot Services Table, +// DXE Services Table, and Runtime Services Table +// +EFI_BOOT_SERVICES *gBS = &mBootServices; +EFI_DXE_SERVICES *gDS = &mDxeServices; +EFI_SYSTEM_TABLE *gST = NULL; + +// +// For debug initialize gRT to template. gRT must be allocated from RT memory +// but gRT is used for ASSERT () and DEBUG () type macros so lets give it +// a value that will not cause debug infrastructure to crash early on. +// +EFI_RUNTIME_SERVICES *gRT = &mEfiRuntimeServicesTableTemplate; +EFI_HANDLE gDxeCoreImageHandle; + +VOID *mHobStart; + +// +// Main entry point to the DXE Core +// +EFI_DXE_ENTRY_POINT (DxeMain) + +VOID +EFIAPI +DxeMain ( + IN VOID *HobStart + ) +/*++ + +Routine Description: + + Main entry point to DXE Core. + +Arguments: + + HobStart - Pointer to the beginning of the HOB List from PEI + +Returns: + + This function should never return + +--*/ +{ + EFI_STATUS Status; + EFI_HANDLE DecompressHandle; + EFI_PHYSICAL_ADDRESS MemoryBaseAddress; + UINT64 MemoryLength; + +#ifdef FIRMWARE_PERFORMANCE + UINT64 Tick; + + GetTimerValue (&Tick); +#endif + + + mHobStart = HobStart; + + // + // Initialize Memory Services + // + CoreInitializeMemoryServices (&HobStart, &MemoryBaseAddress, &MemoryLength); + + // + // Allocate the EFI System Table and EFI Runtime Service Table from EfiRuntimeServicesData + // Use the templates to initialize the contents of the EFI System Table and EFI Runtime Services Table + // + gST = CoreAllocateRuntimeCopyPool (sizeof (EFI_SYSTEM_TABLE), &mEfiSystemTableTemplate); + ASSERT (gST != NULL); + if (gST == NULL) { + // + // Failed to allocate memory for EFI System Table. No recovery path implemented as this is not expected to occur. + // + EFI_DEADLOOP (); + } + + gRT = CoreAllocateRuntimeCopyPool (sizeof (EFI_RUNTIME_SERVICES), &mEfiRuntimeServicesTableTemplate); + ASSERT (gRT != NULL); + + gST->RuntimeServices = gRT; + + // + // Start the Image Services. + // + Status = CoreInitializeImageServices (HobStart); + ASSERT_EFI_ERROR (Status); + + // + // Initialize the Global Coherency Domain Services + // + Status = CoreInitializeGcdServices (&HobStart, MemoryBaseAddress, MemoryLength); + ASSERT_EFI_ERROR (Status); + + // + // The HobStart is relocated in gcd service init. Sync mHobStart variable. + // + mHobStart = HobStart; + + // + // Install the DXE Services Table into the EFI System Tables's Configuration Table + // + Status = CoreInstallConfigurationTable (&gEfiDxeServicesTableGuid, gDS); + ASSERT_EFI_ERROR (Status); + + // + // Install the HOB List into the EFI System Tables's Configuration Table + // + Status = CoreInstallConfigurationTable (&gEfiHobListGuid, HobStart); + ASSERT_EFI_ERROR (Status); + + // + // Install Memory Type Information Table into the EFI System Tables's Configuration Table + // + Status = CoreInstallConfigurationTable (&gEfiMemoryTypeInformationGuid, &gMemoryTypeInformation); + ASSERT_EFI_ERROR (Status); + + // + // Initialize the ReportStatusCode with PEI version, if availible + // + CoreGetPeiProtocol (&gEfiStatusCodeRuntimeProtocolGuid, (VOID **)&gStatusCode->ReportStatusCode); +#if ((TIANO_RELEASE_VERSION != 0) && (EFI_SPECIFICATION_VERSION < 0x00020000)) + if (gStatusCode->ReportStatusCode != NULL) { + gRT->ReportStatusCode = gStatusCode->ReportStatusCode; + } +#endif + + // + // Report Status Code here for DXE_ENTRY_POINT once it is available + // + CoreReportProgressCode ((EFI_SOFTWARE_DXE_CORE | EFI_SW_DXE_CORE_PC_ENTRY_POINT)); + + // + // Create the aligned system table pointer structure that is used by external + // debuggers to locate the system table... Also, install debug image info + // configuration table. + // + CoreInitializeDebugImageInfoTable (); + CoreNewDebugImageInfoEntry ( + EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL, + gDxeCoreLoadedImage, + gDxeCoreImageHandle + ); + + DEBUG_CODE ( + DEBUG ((EFI_D_INFO | EFI_D_LOAD, "HOBLIST address in DXE = 0x%x\n", HobStart)); + ) + // + // Initialize the Event Services + // + Status = CoreInitializeEventServices (); + ASSERT_EFI_ERROR (Status); + + + // + // Get the Protocols that were passed in from PEI to DXE through GUIDed HOBs + // + // These Protocols are not architectural. This implementation is sharing code between + // PEI and DXE in order to save FLASH space. These Protocols could also be implemented + // as part of the DXE Core. However, that would also require the DXE Core to be ported + // each time a different CPU is used, a different Decompression algorithm is used, or a + // different Image type is used. By placing these Protocols in PEI, the DXE Core remains + // generic, and only PEI and the Arch Protocols need to be ported from Platform to Platform, + // and from CPU to CPU. + // + + Status = CoreGetPeiProtocol (&gEfiDecompressProtocolGuid, &gEfiDecompress); + if (!EFI_ERROR (Status)) { + + // + // Publish the EFI Decompress protocol for use by other DXE components + // + + DecompressHandle = NULL; + Status = CoreInstallProtocolInterface ( + &DecompressHandle, + &gEfiDecompressProtocolGuid, + EFI_NATIVE_INTERFACE, + gEfiDecompress + ); + ASSERT_EFI_ERROR (Status); + } + + Status = CoreGetPeiProtocol (&gEfiTianoDecompressProtocolGuid, &gEfiTianoDecompress); + if (!EFI_ERROR (Status)) { + + // + // Publish the Tiano Decompress protocol for use by other DXE components + // + + DecompressHandle = NULL; + Status = CoreInstallProtocolInterface ( + &DecompressHandle, + &gEfiTianoDecompressProtocolGuid, + EFI_NATIVE_INTERFACE, + gEfiTianoDecompress + ); + ASSERT_EFI_ERROR (Status); + } + + Status = CoreGetPeiProtocol (&gEfiCustomizedDecompressProtocolGuid, &gEfiCustomizedDecompress); + if (!EFI_ERROR (Status)) { + + // + // Publish the Tiano Decompress protocol for use by other DXE components + // + DecompressHandle = NULL; + Status = CoreInstallProtocolInterface ( + &DecompressHandle, + &gEfiCustomizedDecompressProtocolGuid, + EFI_NATIVE_INTERFACE, + gEfiCustomizedDecompress + ); + ASSERT_EFI_ERROR (Status); + } + + CoreGetPeiProtocol (&gEfiPeiFlushInstructionCacheGuid, &gEfiPeiFlushInstructionCache); + + CoreGetPeiProtocol (&gEfiPeiPeCoffLoaderGuid, &gEfiPeiPeCoffLoader); + + CoreGetPeiProtocol (&gEfiPeiTransferControlGuid, &gEfiPeiTransferControl); + + + // + // Register for the GUIDs of the Architectural Protocols, so the rest of the + // EFI Boot Services and EFI Runtime Services tables can be filled in. + // + CoreNotifyOnArchProtocolInstallation (); + + // + // Produce Firmware Volume Protocols, one for each FV in the HOB list. + // + Status = FwVolBlockDriverInit (gDxeCoreImageHandle, gST); + ASSERT_EFI_ERROR (Status); + + Status = FwVolDriverInit (gDxeCoreImageHandle, gST); + ASSERT_EFI_ERROR (Status); + + // + // Produce the Section Extraction Protocol + // + Status = InitializeSectionExtraction (gDxeCoreImageHandle, gST); + ASSERT_EFI_ERROR (Status); + + + // + // Initialize Performance monitoring if enabled in build + // + PERF_ENABLE (0, gST, Tick); + + PERF_START (0,DXE_TOK, NULL, Tick) ; + + // + // Initialize the DXE Dispatcher + // + PERF_START (0,L"CoreInitializeDispatcher", L"DxeMain", 0) ; + CoreInitializeDispatcher (); + PERF_END (0,L"CoreInitializeDispatcher", L"DxeMain", 0) ; + + // + // Invoke the DXE Dispatcher + // + PERF_START (0, L"CoreDispatcher", L"DxeMain", 0); + CoreDispatcher (); + PERF_END (0, L"CoreDispatcher", L"DxeMain", 0); + + // + // Display Architectural protocols that were not loaded if this is DEBUG build + // + DEBUG_CODE ( + CoreDisplayMissingArchProtocols (); + ) + + // + // Assert if the Architectural Protocols are not present. + // + ASSERT_EFI_ERROR (CoreAllEfiServicesAvailable ()); + + // + // Report Status code before transfer control to BDS + // + CoreReportProgressCode ((EFI_SOFTWARE_DXE_CORE | EFI_SW_DXE_CORE_PC_HANDOFF_TO_NEXT)); + + // + // Display any drivers that were not dispatched because dependency expression + // evaluated to false if this is a debug build + // + DEBUG_CODE ( + CoreDisplayDiscoveredNotDispatched (); + ) + + // + // Transfer control to the BDS Architectural Protocol + // + gBds->Entry (gBds); + + // + // BDS should never return + // + ASSERT (FALSE); + EFI_DEADLOOP (); +} + + +EFI_STATUS +EFIAPI +CoreEfiNotAvailableYetArg0 ( + VOID + ) +/*++ + +Routine Description: + + Place holder function until all the Boot Services and Runtime Services are available + +Arguments: + + None + +Returns: + + EFI_NOT_AVAILABLE_YET + +--*/ +{ + // + // This function should never be executed. If it does, then the architectural protocols + // have not been designed correctly. The EFI_BREAKPOINT() is commented out for now until the + // DXE Core and all the Architectural Protocols are complete. + // + + return EFI_NOT_AVAILABLE_YET; +} + +EFI_STATUS +EFIAPI +CoreEfiNotAvailableYetArg1 ( + UINTN Arg1 + ) +/*++ + +Routine Description: + + Place holder function until all the Boot Services and Runtime Services are available + +Arguments: + + Arg1 - Undefined + +Returns: + + EFI_NOT_AVAILABLE_YET + +--*/ +{ + // + // This function should never be executed. If it does, then the architectural protocols + // have not been designed correctly. The EFI_BREAKPOINT() is commented out for now until the + // DXE Core and all the Architectural Protocols are complete. + // + + return EFI_NOT_AVAILABLE_YET; +} + +EFI_STATUS +EFIAPI +CoreEfiNotAvailableYetArg2 ( + UINTN Arg1, + UINTN Arg2 + ) +/*++ + +Routine Description: + + Place holder function until all the Boot Services and Runtime Services are available + +Arguments: + + Arg1 - Undefined + + Arg2 - Undefined + +Returns: + + EFI_NOT_AVAILABLE_YET + +--*/ +{ + // + // This function should never be executed. If it does, then the architectural protocols + // have not been designed correctly. The EFI_BREAKPOINT() is commented out for now until the + // DXE Core and all the Architectural Protocols are complete. + // + + return EFI_NOT_AVAILABLE_YET; +} + +EFI_STATUS +EFIAPI +CoreEfiNotAvailableYetArg3 ( + UINTN Arg1, + UINTN Arg2, + UINTN Arg3 + ) +/*++ + +Routine Description: + + Place holder function until all the Boot Services and Runtime Services are available + +Arguments: + + Arg1 - Undefined + + Arg2 - Undefined + + Arg3 - Undefined + +Returns: + + EFI_NOT_AVAILABLE_YET + +--*/ +{ + // + // This function should never be executed. If it does, then the architectural protocols + // have not been designed correctly. The EFI_BREAKPOINT() is commented out for now until the + // DXE Core and all the Architectural Protocols are complete. + // + + return EFI_NOT_AVAILABLE_YET; +} + +EFI_STATUS +EFIAPI +CoreEfiNotAvailableYetArg4 ( + UINTN Arg1, + UINTN Arg2, + UINTN Arg3, + UINTN Arg4 + ) +/*++ + +Routine Description: + + Place holder function until all the Boot Services and Runtime Services are available + +Arguments: + + Arg1 - Undefined + + Arg2 - Undefined + + Arg3 - Undefined + + Arg4 - Undefined + +Returns: + + EFI_NOT_AVAILABLE_YET + +--*/ +{ + // + // This function should never be executed. If it does, then the architectural protocols + // have not been designed correctly. The EFI_BREAKPOINT() is commented out for now until the + // DXE Core and all the Architectural Protocols are complete. + // + + return EFI_NOT_AVAILABLE_YET; +} + +EFI_STATUS +EFIAPI +CoreEfiNotAvailableYetArg5 ( + UINTN Arg1, + UINTN Arg2, + UINTN Arg3, + UINTN Arg4, + UINTN Arg5 + ) +/*++ + +Routine Description: + + Place holder function until all the Boot Services and Runtime Services are available + +Arguments: + + Arg1 - Undefined + + Arg2 - Undefined + + Arg3 - Undefined + + Arg4 - Undefined + + Arg5 - Undefined + +Returns: + + EFI_NOT_AVAILABLE_YET + +--*/ +{ + // + // This function should never be executed. If it does, then the architectural protocols + // have not been designed correctly. The EFI_BREAKPOINT() is commented out for now until the + // DXE Core and all the Architectural Protocols are complete. + // + + return EFI_NOT_AVAILABLE_YET; +} + + +EFI_STATUS +CoreGetPeiProtocol ( + IN EFI_GUID *ProtocolGuid, + IN VOID **Interface + ) +/*++ + +Routine Description: + + Searches for a Protocol Interface passed from PEI through a HOB + +Arguments: + + ProtocolGuid - The Protocol GUID to search for in the HOB List + + Interface - A pointer to the interface for the Protocol GUID + +Returns: + + EFI_SUCCESS - The Protocol GUID was found and its interface is returned in Interface + + EFI_NOT_FOUND - The Protocol GUID was not found in the HOB List + +--*/ +{ + EFI_STATUS Status; + VOID *HobList; + VOID *Buffer; + + // + // Initialize 'Buffer' to NULL before usage. + // + Buffer = NULL; + + HobList = mHobStart; + Status = GetNextGuidHob (&HobList, ProtocolGuid, &Buffer, NULL); + if (EFI_ERROR (Status) || (Buffer == NULL)) { + // + // Failed to find a HOB containing the desired protocol + // + return Status; + } + + ASSERT (Buffer != NULL); + + *Interface = (VOID *)(*(UINTN *)(Buffer)); + + return Status; +} + + +VOID +CalculateEfiHdrCrc ( + IN OUT EFI_TABLE_HEADER *Hdr + ) +/*++ + +Routine Description: + + Calcualte the 32-bit CRC in a EFI table using the service provided by the + gRuntime service. + +Arguments: + + Hdr - Pointer to an EFI standard header + +Returns: + + None + +--*/ +{ + UINT32 Crc; + + Hdr->CRC32 = 0; + + // + // If gBS->CalculateCrce32 () == CoreEfiNotAvailableYet () then + // Crc will come back as zero if we set it to zero here + // + Crc = 0; + gBS->CalculateCrc32 ((UINT8 *)Hdr, Hdr->HeaderSize, &Crc); + Hdr->CRC32 = Crc; +} + + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreExitBootServices ( + IN EFI_HANDLE ImageHandle, + IN UINTN MapKey + ) +/*++ + +Routine Description: + + Terminates all boot services. + +Arguments: + + ImageHandle - Handle that identifies the exiting image. + MapKey - Key to the latest memory map. + +Returns: + + EFI_SUCCESS - Boot services have been terminated. + EFI_INVALID_PARAMETER - MapKey is incorrect. + +--*/ +{ + EFI_STATUS Status, Status2; + EFI_TCG_PLATFORM_PROTOCOL *TcgPlatformProtocol; + + // + // Measure invocation of ExitBootServices, + // which is defined by TCG_EFI_Platform_1_20_Final Specification + // + TcgPlatformProtocol = NULL; + Status = CoreLocateProtocol ( + &gEfiTcgPlatformProtocolGuid, + NULL, + &TcgPlatformProtocol + ); + if (!EFI_ERROR (Status) && (TcgPlatformProtocol != NULL)) { + Status = TcgPlatformProtocol->MeasureAction (EFI_EXIT_BOOT_SERVICES_INVOCATION); + ASSERT_EFI_ERROR (Status); + } + + // + // Terminate memory services if the MapKey matches + // + Status = CoreTerminateMemoryMap (MapKey); + if (EFI_ERROR (Status)) { + // + // Measure failure of ExitBootServices + // + if (TcgPlatformProtocol != NULL) { + Status2 = TcgPlatformProtocol->MeasureAction (EFI_EXIT_BOOT_SERVICES_FAILED); + ASSERT_EFI_ERROR (Status2); + } + + return Status; + } + + // + // Disable Timer + // + gTimer->SetTimerPeriod (gTimer, 0); + + + // + // Notify other drivers that we are exiting boot services. + // + CoreNotifySignalList (&gEfiEventExitBootServicesGuid); + + + + // + // Disable CPU Interrupts + // + gCpu->DisableInterrupt (gCpu); + + // + // Report that ExitBootServices() has been called + // + // We are using gEfiDxeServicesTableGuid as the caller ID for Dxe Core + // + CoreReportProgressCode ((EFI_SOFTWARE_EFI_BOOT_SERVICE | EFI_SW_BS_PC_EXIT_BOOT_SERVICES)); + + // + // Clear the non-runtime values of the EFI System Table + // + gST->BootServices = NULL; + gST->ConIn = NULL; + gST->ConsoleInHandle = NULL; + gST->ConOut = NULL; + gST->ConsoleOutHandle = NULL; + gST->StdErr = NULL; + gST->StandardErrorHandle = NULL; + + // + // Recompute the 32-bit CRC of the EFI System Table + // + CalculateEfiHdrCrc (&gST->Hdr); + + // + // Update the AtRuntime field in Runtiem AP. + // + gRuntime->AtRuntime = TRUE; + + // + // Measure success of ExitBootServices + // + if (TcgPlatformProtocol != NULL) { + Status2 = TcgPlatformProtocol->MeasureAction (EFI_EXIT_BOOT_SERVICES_SUCCEEDED); + ASSERT_EFI_ERROR (Status2); + } + + // + // Zero out the Boot Service Table + // + EfiCommonLibSetMem (gBS, sizeof (EFI_BOOT_SERVICES), 0); + gBS = NULL; + + return Status; +} diff --git a/EDK/Foundation/Core/Dxe/DxeMain/DxeProtocolNotify.c b/EDK/Foundation/Core/Dxe/DxeMain/DxeProtocolNotify.c new file mode 100644 index 0000000..15886f9 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/DxeMain/DxeProtocolNotify.c @@ -0,0 +1,319 @@ +/*++ + +Copyright (c) 2004 - 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DxeProtocolNotify.c + +Abstract: + + This file deals with Architecture Protocol (AP) registration in + the Dxe Core. The mArchProtocols[] array represents a list of + events that represent the Architectural Protocols. + +--*/ + +#include "Tiano.h" +#include "DxeCore.h" + + +// +// DXE Core Global Variables for all of the Architectural Protocols. +// If a protocol is installed mArchProtocols[].Present will be TRUE. +// +// CoreNotifyOnArchProtocolInstallation () fills in mArchProtocols[].Event +// and mArchProtocols[].Registration as it creates events for every array +// entry. +// + +ARCHITECTURAL_PROTOCOL_ENTRY mArchProtocols[] = { + { &gEfiSecurityArchProtocolGuid, &gSecurity, NULL, NULL, FALSE}, + { &gEfiCpuArchProtocolGuid, &gCpu, NULL, NULL, FALSE}, + { &gEfiMetronomeArchProtocolGuid, &gMetronome, NULL, NULL, FALSE}, + { &gEfiTimerArchProtocolGuid, &gTimer, NULL, NULL, FALSE}, + { &gEfiBdsArchProtocolGuid, &gBds, NULL, NULL, FALSE}, + { &gEfiWatchdogTimerArchProtocolGuid, &gWatchdogTimer, NULL, NULL, FALSE}, + { &gEfiRuntimeArchProtocolGuid, &gRuntime, NULL, NULL, FALSE}, + { &gEfiVariableArchProtocolGuid, NULL, NULL, NULL, FALSE}, + { &gEfiVariableWriteArchProtocolGuid, NULL, NULL, NULL, FALSE}, + #if (EFI_SPECIFICATION_VERSION >= 0x00020000) + { &gEfiCapsuleArchProtocolGuid, NULL, NULL, NULL, FALSE}, + #endif + { &gEfiMonotonicCounterArchProtocolGuid, NULL, NULL, NULL, FALSE}, + { &gEfiResetArchProtocolGuid, NULL, NULL, NULL, FALSE}, + { &gEfiStatusCodeRuntimeProtocolGuid, NULL, NULL, NULL, FALSE}, + { &gEfiRealTimeClockArchProtocolGuid, NULL, NULL, NULL, FALSE}, + NULL +}; + + +EFI_STATUS +CoreAllEfiServicesAvailable ( + VOID + ) +/*++ + +Routine Description: + Return TRUE if all AP services are availible. + +Arguments: + NONE + +Returns: + EFI_SUCCESS - All AP services are available + EFI_NOT_FOUND - At least one AP service is not available + +--*/ +{ + ARCHITECTURAL_PROTOCOL_ENTRY *Entry; + + for (Entry = mArchProtocols; Entry->ProtocolGuid != NULL; Entry++) { + if (!Entry->Present) { + return EFI_NOT_FOUND; + } + } + + return EFI_SUCCESS; +} + + +VOID +EFIAPI +GenericArchProtocolNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + Notification event handler registered by CoreNotifyOnArchProtocolInstallation (). + This notify function is registered for every architectural protocol. This handler + updates mArchProtocol[] array entry with protocol instance data and sets it's + present flag to TRUE. If any constructor is required it is executed. The EFI + System Table headers are updated. + +Arguments: + + Event - The Event that is being processed, not used. + + Context - Event Context, not used. + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + ARCHITECTURAL_PROTOCOL_ENTRY *Entry; + VOID *Protocol; + BOOLEAN Found; + EFI_LIST_ENTRY *Link; + EFI_LIST_ENTRY TempLinkNode; + + Found = FALSE; + for (Entry = mArchProtocols; Entry->ProtocolGuid != NULL; Entry++) { + + Status = CoreLocateProtocol (Entry->ProtocolGuid, Entry->Registration, &Protocol); + if (EFI_ERROR (Status)) { + continue; + } + + Found = TRUE; + Entry->Present = TRUE; + + // + // Update protocol global variable if one exists. Entry->Protocol points to a global variable + // if one exists in the DXE core for this Architectural Protocol + // + if (Entry->Protocol != NULL) { + *(Entry->Protocol) = Protocol; + } + + if (EfiCompareGuid (Entry->ProtocolGuid, &gEfiTimerArchProtocolGuid)) { + // + // Register the Core timer tick handler with the Timer AP + // + gTimer->RegisterHandler (gTimer, CoreTimerTick); + } + + if (EfiCompareGuid (Entry->ProtocolGuid, &gEfiRuntimeArchProtocolGuid)) { + // + // When runtime architectural protocol is available, updates CRC32 in the Debug Table + // + CoreUpdateDebugTableCrc32 (); + + // + // Update the Runtime Architectural protocol with the template that the core was + // using so there would not need to be a dependency on the Runtime AP + // + + // + // Copy all the registered Image to new gRuntime protocol + // + for (Link = gRuntimeTemplate.ImageHead.ForwardLink; Link != &gRuntimeTemplate.ImageHead; Link = TempLinkNode.ForwardLink) { + EfiCommonLibCopyMem (&TempLinkNode, Link, sizeof(EFI_LIST_ENTRY)); + InsertTailList (&gRuntime->ImageHead, Link); + } + // + // Copy all the registered Event to new gRuntime protocol + // + for (Link = gRuntimeTemplate.EventHead.ForwardLink; Link != &gRuntimeTemplate.EventHead; Link = TempLinkNode.ForwardLink) { + EfiCommonLibCopyMem (&TempLinkNode, Link, sizeof(EFI_LIST_ENTRY)); + InsertTailList (&gRuntime->EventHead, Link); + } + + // + // Clean up gRuntimeTemplate + // + gRuntimeTemplate.ImageHead.ForwardLink = &gRuntimeTemplate.ImageHead; + gRuntimeTemplate.ImageHead.BackLink = &gRuntimeTemplate.ImageHead; + gRuntimeTemplate.EventHead.ForwardLink = &gRuntimeTemplate.EventHead; + gRuntimeTemplate.EventHead.BackLink = &gRuntimeTemplate.EventHead; + } + + if (EfiCompareGuid (Entry->ProtocolGuid, &gEfiStatusCodeRuntimeProtocolGuid)) { + // + // Update StatusCode instance used by DXE core + // + gStatusCode = (EFI_STATUS_CODE_PROTOCOL *) Protocol; + } + } + + // + // It's over kill to do them all every time, but it saves a lot of code. + // + if (Found) { + CalculateEfiHdrCrc (&gRT->Hdr); + CalculateEfiHdrCrc (&gBS->Hdr); + CalculateEfiHdrCrc (&gST->Hdr); + CalculateEfiHdrCrc (&gDS->Hdr); + } +} + + + +VOID +CoreNotifyOnArchProtocolInstallation ( + VOID + ) +/*++ + +Routine Description: + Creates an event that is fired everytime a Protocol of a specific type is installed + +Arguments: + NONE + +Returns: + NONE + +--*/ +{ + EFI_STATUS Status; + ARCHITECTURAL_PROTOCOL_ENTRY *Entry; + + for (Entry = mArchProtocols; Entry->ProtocolGuid != NULL; Entry++) { + + // + // Create the event + // + Status = CoreCreateEvent ( + EFI_EVENT_NOTIFY_SIGNAL, + EFI_TPL_CALLBACK, + GenericArchProtocolNotify, + NULL, + &Entry->Event + ); + ASSERT_EFI_ERROR(Status); + + // + // Register for protocol notifactions on this event + // + Status = CoreRegisterProtocolNotify ( + Entry->ProtocolGuid, + Entry->Event, + &Entry->Registration + ); + ASSERT_EFI_ERROR(Status); + + } +} + +#ifdef EFI_DEBUG +// +// Following is needed to display missing architectural protocols in debug builds +// +typedef struct { + EFI_GUID *ProtocolGuid; + CHAR16 *GuidString; +} GUID_TO_STRING_PROTOCOL_ENTRY; + +GUID_TO_STRING_PROTOCOL_ENTRY MissingProtocols[] = { + { &gEfiSecurityArchProtocolGuid, L"Security" }, + { &gEfiCpuArchProtocolGuid, L"CPU" }, + { &gEfiMetronomeArchProtocolGuid, L"Metronome" }, + { &gEfiTimerArchProtocolGuid, L"Timer" }, + { &gEfiBdsArchProtocolGuid, L"Bds" }, + { &gEfiWatchdogTimerArchProtocolGuid, L"Watchdog Timer" }, + { &gEfiRuntimeArchProtocolGuid, L"Runtime" }, + { &gEfiVariableArchProtocolGuid, L"Variable" }, + { &gEfiVariableWriteArchProtocolGuid, L"Variable Write" }, + #if (EFI_SPECIFICATION_VERSION >= 0x00020000) + { &gEfiCapsuleArchProtocolGuid, L"Capsule" }, + #endif + { &gEfiMonotonicCounterArchProtocolGuid, L"Monotonic Counter" }, + { &gEfiResetArchProtocolGuid, L"Reset" }, + { &gEfiStatusCodeRuntimeProtocolGuid, L"Status Code" }, + { &gEfiRealTimeClockArchProtocolGuid, L"Real Time Clock" } +}; +#endif + +DEBUG_CODE ( +VOID +CoreDisplayMissingArchProtocols ( + VOID + ) +/*++ + +Routine Description: + Displays Architectural protocols that were not loaded and are required for DXE core to function + Only used in Debug Builds + +Arguments: + NONE + +Returns: + NONE + +--*/ +{ + + + GUID_TO_STRING_PROTOCOL_ENTRY *MissingEntry; + + ARCHITECTURAL_PROTOCOL_ENTRY *Entry; + + + for (Entry = mArchProtocols; Entry->ProtocolGuid != NULL; Entry++) { + if (!Entry->Present) { + MissingEntry = MissingProtocols; + for (MissingEntry = MissingProtocols; TRUE ; MissingEntry++) { + if (EfiCompareGuid (Entry->ProtocolGuid, MissingEntry->ProtocolGuid)) { + DEBUG ((EFI_D_ERROR, "\n%s Arch Protocol not present!!\n", MissingEntry->GuidString)); + break; + } + } + } + + } +} +) diff --git a/EDK/Foundation/Core/Dxe/Event/event.c b/EDK/Foundation/Core/Dxe/Event/event.c new file mode 100644 index 0000000..ee2eefa --- /dev/null +++ b/EDK/Foundation/Core/Dxe/Event/event.c @@ -0,0 +1,845 @@ +/*++ + +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + event.c + +Abstract: + + EFI Event support. + +--*/ + +#include "exec.h" +#include "hand.h" + +// +// Enumerate the valid types +// +UINT32 mEventTable[] = { + // + // 0x80000200 Timer event with a notification function that is + // queue when the event is signaled with SignalEvent() + // + EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL, + // + // 0x80000000 Timer event without a notification function. It can be + // signaled with SignalEvent() and checked with CheckEvent() or WaitForEvent(). + // + EFI_EVENT_TIMER, + // + // 0x00000100 Generic event with a notification function that + // can be waited on with CheckEvent() or WaitForEvent() + // + EFI_EVENT_NOTIFY_WAIT, + // + // 0x00000200 Generic event with a notification function that + // is queue when the event is signaled with SignalEvent() + // + EFI_EVENT_NOTIFY_SIGNAL, + // + // 0x00000201 ExitBootServicesEvent. + // + EFI_EVENT_SIGNAL_EXIT_BOOT_SERVICES, + // + // 0x60000202 SetVirtualAddressMapEvent. + // + EFI_EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE, +#if (EFI_SPECIFICATION_VERSION < 0x00020000) + // + // 0x00000203 ReadyToBootEvent. + // + EFI_EVENT_SIGNAL_READY_TO_BOOT, + // + // 0x00000204 LegacyBootEvent. + // + EFI_EVENT_SIGNAL_LEGACY_BOOT, + // + // 0x00000603 Signal all ReadyToBootEvents. + // + EFI_EVENT_NOTIFY_SIGNAL_ALL | EFI_EVENT_SIGNAL_READY_TO_BOOT, + // + // 0x00000604 Signal all LegacyBootEvents. + // + EFI_EVENT_NOTIFY_SIGNAL_ALL | EFI_EVENT_SIGNAL_LEGACY_BOOT, +#endif + // + // 0x00000000 Generic event without a notification function. + // It can be signaled with SignalEvent() and checked with CheckEvent() + // or WaitForEvent(). + // + 0x00000000, + // + // 0x80000100 Timer event with a notification function that can be + // waited on with CheckEvent() or WaitForEvent() + // + EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_WAIT, +}; + + +VOID +CoreAcquireEventLock ( + VOID + ) +/*++ + +Routine Description: + + Enter critical section by acquiring the lock on gEventQueueLock. + +Arguments: + + None + +Returns: + + None + +--*/ +{ + CoreAcquireLock (&gEventQueueLock); +} + + +VOID +CoreReleaseEventLock ( + VOID + ) +/*++ + +Routine Description: + + Exit critical section by releasing the lock on gEventQueueLock. + +Arguments: + + None + +Returns: + + None + +--*/ +{ + CoreReleaseLock (&gEventQueueLock); +} + + +EFI_STATUS +CoreInitializeEventServices ( + VOID + ) +/*++ + +Routine Description: + + Initializes "event" support and populates parts of the System and Runtime Table. + +Arguments: + + None + +Returns: + + EFI_SUCCESS - Always return success + +--*/ +{ + UINTN Index; + + for (Index=0; Index <= EFI_TPL_HIGH_LEVEL; Index ++) { + InitializeListHead (&gEventQueue[Index]); + } + + CoreInitializeTimer (); + + return EFI_SUCCESS; +} + + +VOID +CoreDispatchEventNotifies ( + IN EFI_TPL Priority + ) +/*++ + +Routine Description: + + Dispatches all pending events. + +Arguments: + + Priority - The task priority level of event notifications to dispatch + +Returns: + + None + +--*/ +{ + IEVENT *Event; + EFI_LIST_ENTRY *Head; + + CoreAcquireEventLock (); + ASSERT (gEventQueueLock.OwnerTpl == Priority); + Head = &gEventQueue[Priority]; + + // + // Dispatch all the pending notifications + // + while (!IsListEmpty (Head)) { + + Event = CR (Head->ForwardLink, IEVENT, NotifyLink, EVENT_SIGNATURE); + RemoveEntryList (&Event->NotifyLink); + + Event->NotifyLink.ForwardLink = NULL; + + // + // Only clear the SIGNAL status if it is a SIGNAL type event. + // WAIT type events are only cleared in CheckEvent() + // + if (Event->Type & EFI_EVENT_NOTIFY_SIGNAL) { + Event->SignalCount = 0; + } + + CoreReleaseEventLock (); + + // + // Notify this event + // + Event->NotifyFunction (Event, Event->NotifyContext); + + // + // Check for next pending event + // + CoreAcquireEventLock (); + } + + gEventPending &= ~(1 << Priority); + CoreReleaseEventLock (); +} + + +VOID +STATIC +CoreNotifyEvent ( + IN IEVENT *Event + ) +/*++ + +Routine Description: + + Queues the event's notification function to fire + +Arguments: + + Event - The Event to notify + +Returns: + + None + +--*/ +{ + + // + // Event database must be locked + // + ASSERT_LOCKED (&gEventQueueLock); + + // + // If the event is queued somewhere, remove it + // + + if (Event->NotifyLink.ForwardLink != NULL) { + RemoveEntryList (&Event->NotifyLink); + Event->NotifyLink.ForwardLink = NULL; + } + + // + // Queue the event to the pending notification list + // + + InsertTailList (&gEventQueue[Event->NotifyTpl], &Event->NotifyLink); + gEventPending |= (UINTN)1 << Event->NotifyTpl; +} + + + +VOID +CoreNotifySignalList ( + IN EFI_GUID *EventGroup + ) +/*++ + +Routine Description: + + Signals all events on the requested list + +Arguments: + + SignalType - The list to signal + +Returns: + + None + +--*/ +{ + EFI_LIST_ENTRY *Link; + EFI_LIST_ENTRY *Head; + IEVENT *Event; + + CoreAcquireEventLock (); + + Head = &gEventSignalQueue; + for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) { + Event = CR (Link, IEVENT, SignalLink, EVENT_SIGNATURE); + if ((Event->ExFlag) && EfiCompareGuid (&Event->EventGroup, EventGroup)) { + CoreNotifyEvent (Event); + } + } + + CoreReleaseEventLock (); +} + +#if (EFI_SPECIFICATION_VERSION < 0x00020000) + +static +VOID +EFIAPI +EventNotifySignalAllNullEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + // + // This null event is a size efficent way to enusre that + // EFI_EVENT_NOTIFY_SIGNAL_ALL is error checked correctly. + // EFI_EVENT_NOTIFY_SIGNAL_ALL is now mapped into + // CreateEventEx() and this function is used to make the + // old error checking in CreateEvent() for Tiano extensions + // function. + // + return; +} + +#endif + + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreCreateEvent ( + IN UINT32 Type, + IN EFI_TPL NotifyTpl, + IN EFI_EVENT_NOTIFY NotifyFunction, + IN VOID *NotifyContext, + OUT EFI_EVENT *Event + ) +/*++ + +Routine Description: + + Creates a general-purpose event structure + +Arguments: + + Type - The type of event to create and its mode and attributes + NotifyTpl - The task priority level of event notifications + NotifyFunction - Pointer to the events notification function + NotifyContext - Pointer to the notification functions context; corresponds to + parameter "Context" in the notification function + Event - Pointer to the newly created event if the call succeeds; undefined otherwise + +Returns: + + EFI_SUCCESS - The event structure was created + EFI_INVALID_PARAMETER - One of the parameters has an invalid value + EFI_OUT_OF_RESOURCES - The event could not be allocated + +--*/ +{ + EFI_GUID *GuidPtr; + EFI_EVENT_NOTIFY Function; + + GuidPtr = NULL; + Function = NotifyFunction; + +#if (EFI_SPECIFICATION_VERSION < 0x00020000) + // + // Clear EFI_EVENT_NOFITY_SIGNAL_ALL (Tiano extension) as all events in the + // EventGroup now have this property. So we need to filter it out. + // + if (Type & EFI_EVENT_NOTIFY_SIGNAL_ALL) { + Type &= ~EFI_EVENT_NOTIFY_SIGNAL_ALL; + Function = EventNotifySignalAllNullEvent; + } + + // + // Map the Tiano extensions Events to CreateEventEx form + // + if (Type == EFI_EVENT_SIGNAL_READY_TO_BOOT) { + GuidPtr = &gEfiEventReadyToBootGuid; + } else if (Type == EFI_EVENT_SIGNAL_LEGACY_BOOT) { + GuidPtr = &gEfiEventLegacyBootGuid; + } +#endif + + // + // Convert EFI 1.10 Events to thier UEFI 2.0 CreateEventEx mapping + // + if (Type == EFI_EVENT_SIGNAL_EXIT_BOOT_SERVICES) { + Type = 0; + GuidPtr = &gEfiEventExitBootServicesGuid; + } else if (Type == EFI_EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) { + Type = 0; + GuidPtr = &gEfiEventVirtualAddressChangeGuid; + } + + return CoreCreateEventEx (Type, NotifyTpl, Function, NotifyContext, GuidPtr, Event); +} + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreCreateEventEx ( + IN UINT32 Type, + IN EFI_TPL NotifyTpl, + IN EFI_EVENT_NOTIFY NotifyFunction, + IN VOID *NotifyContext, + IN CONST EFI_GUID *EventGroup, OPTIONAL + OUT EFI_EVENT *Event + ) +/*++ + +Routine Description: + Creates a general-purpose event structure + +Arguments: + Type - The type of event to create and its mode and attributes + NotifyTpl - The task priority level of event notifications + NotifyFunction - Pointer to the events notification function + NotifyContext - Pointer to the notification functions context; corresponds to + parameter "Context" in the notification function + EventGroup - GUID for EventGroup if NULL act the same as gBS->CreateEvent(). + Event - Pointer to the newly created event if the call succeeds; undefined otherwise + +Returns: + EFI_SUCCESS - The event structure was created + EFI_INVALID_PARAMETER - One of the parameters has an invalid value + EFI_OUT_OF_RESOURCES - The event could not be allocated + +--*/ +{ + EFI_STATUS Status; + IEVENT *IEvent; + INTN Index; + + + if ((Event == NULL) || (NotifyTpl == EFI_TPL_APPLICATION)) { + return EFI_INVALID_PARAMETER; + } + + // + // For event group, type EFI_EVENT_SIGNAL_EXIT_BOOT_SERVICES and EFI_EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE + // are not valid + // + if (EventGroup != NULL) { + if ((Type == EFI_EVENT_SIGNAL_EXIT_BOOT_SERVICES) || (Type == EFI_EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE)) { + return EFI_INVALID_PARAMETER; + } + } + + // + // Check to make sure no reserved flags are set + // + Status = EFI_INVALID_PARAMETER; + for (Index = 0; Index < (sizeof (mEventTable) / sizeof (UINT32)); Index++) { + if (Type == mEventTable[Index]) { + Status = EFI_SUCCESS; + break; + } + } + if(EFI_ERROR (Status)) { + return EFI_INVALID_PARAMETER; + } + + // + // Convert Event type for pre-defined Event groups + // + if (EventGroup != NULL) { + if (EfiCompareGuid ((VOID *) EventGroup, &gEfiEventExitBootServicesGuid)) { + Type = EFI_EVENT_SIGNAL_EXIT_BOOT_SERVICES; + } else if (EfiCompareGuid ((VOID *) EventGroup, &gEfiEventVirtualAddressChangeGuid)) { + Type = EFI_EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE; + } + } + + // + // If it's a notify type of event, check its parameters + // + if ((Type & (EFI_EVENT_NOTIFY_WAIT | EFI_EVENT_NOTIFY_SIGNAL))) { + // + // Check for an invalid NotifyFunction or NotifyTpl + // + if ((NotifyFunction == NULL) || + (NotifyTpl < EFI_TPL_APPLICATION) || + (NotifyTpl >= EFI_TPL_HIGH_LEVEL)) { + return EFI_INVALID_PARAMETER; + } + + } else { + // + // No notification needed, zero ignored values + // + NotifyTpl = 0; + NotifyFunction = NULL; + NotifyContext = NULL; + } + + // + // Allcoate and initialize a new event structure. + // + Status = CoreAllocatePool ( + (Type & EFI_EVENT_RUNTIME) ? EfiRuntimeServicesData: EfiBootServicesData, + sizeof (IEVENT), + (VOID **)&IEvent + ); + if (EFI_ERROR (Status) || (IEvent == NULL)) { + return EFI_OUT_OF_RESOURCES; + } + + EfiCommonLibSetMem (IEvent, sizeof (IEVENT), 0); + + IEvent->Signature = EVENT_SIGNATURE; + IEvent->Type = Type; + IEvent->NotifyTpl = NotifyTpl; + IEvent->NotifyFunction = NotifyFunction; + IEvent->NotifyContext = (VOID *)NotifyContext; + if (EventGroup != NULL) { + EfiCommonLibCopyMem (&IEvent->EventGroup, (VOID*)EventGroup, sizeof (EFI_GUID)); + IEvent->ExFlag = TRUE; + } + + *Event = IEvent; + + if (Type & EFI_EVENT_RUNTIME) { + // + // Keep a list of all RT events so we can tell the RT AP. + // + IEvent->RuntimeData.Type = Type; + IEvent->RuntimeData.NotifyTpl = NotifyTpl; + IEvent->RuntimeData.NotifyFunction = NotifyFunction; + IEvent->RuntimeData.NotifyContext = NotifyContext; + IEvent->RuntimeData.Event = (EFI_EVENT *) IEvent; + InsertTailList (&gRuntime->EventHead, &IEvent->RuntimeData.Link); + } + + CoreAcquireEventLock (); + + if ((Type & EFI_EVENT_NOTIFY_SIGNAL) != 0x00000000) { + // + // The Event's NotifyFunction must be queued whenever the event is signaled + // + InsertHeadList (&gEventSignalQueue, &IEvent->SignalLink); + } + + CoreReleaseEventLock (); + + // + // Done + // + return EFI_SUCCESS; +} + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreSignalEvent ( + IN EFI_EVENT UserEvent + ) +/*++ + +Routine Description: + + Signals the event. Queues the event to be notified if needed + +Arguments: + + UserEvent - The event to signal + +Returns: + + EFI_INVALID_PARAMETER - Parameters are not valid. + + EFI_SUCCESS - The event was signaled. + +--*/ +{ + IEVENT *Event; + + Event = UserEvent; + + if (Event == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Event->Signature != EVENT_SIGNATURE) { + return EFI_INVALID_PARAMETER; + } + + CoreAcquireEventLock (); + + // + // If the event is not already signalled, do so + // + + if (Event->SignalCount == 0x00000000) { + Event->SignalCount ++; + + // + // If signalling type is a notify function, queue it + // + if (Event->Type & EFI_EVENT_NOTIFY_SIGNAL) { + if (Event->ExFlag) { + // + // The CreateEventEx() style requires all members of the Event Group + // to be signaled. + // + CoreReleaseEventLock (); + CoreNotifySignalList (&Event->EventGroup); + CoreAcquireEventLock (); + } else { + CoreNotifyEvent (Event); + } + } + } + + CoreReleaseEventLock (); + return EFI_SUCCESS; +} + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreCheckEvent ( + IN EFI_EVENT UserEvent + ) +/*++ + +Routine Description: + + Check the status of an event + +Arguments: + + UserEvent - The event to check + +Returns: + + EFI_SUCCESS - The event is in the signaled state + EFI_NOT_READY - The event is not in the signaled state + EFI_INVALID_PARAMETER - Event is of type EVT_NOTIFY_SIGNAL + +--*/ + +{ + IEVENT *Event; + EFI_STATUS Status; + + Event = UserEvent; + + if (Event == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Event->Signature != EVENT_SIGNATURE) { + return EFI_INVALID_PARAMETER; + } + + if (Event->Type & EFI_EVENT_NOTIFY_SIGNAL) { + return EFI_INVALID_PARAMETER; + } + + Status = EFI_NOT_READY; + + if (!Event->SignalCount && (Event->Type & EFI_EVENT_NOTIFY_WAIT)) { + + // + // Queue the wait notify function + // + + CoreAcquireEventLock (); + if (!Event->SignalCount) { + CoreNotifyEvent (Event); + } + CoreReleaseEventLock (); + } + + // + // If the even looks signalled, get the lock and clear it + // + + if (Event->SignalCount) { + CoreAcquireEventLock (); + + if (Event->SignalCount) { + Event->SignalCount = 0; + Status = EFI_SUCCESS; + } + + CoreReleaseEventLock (); + } + + return Status; +} + + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreWaitForEvent ( + IN UINTN NumberOfEvents, + IN EFI_EVENT *UserEvents, + OUT UINTN *UserIndex + ) +/*++ + +Routine Description: + + Stops execution until an event is signaled. + +Arguments: + + NumberOfEvents - The number of events in the UserEvents array + UserEvents - An array of EFI_EVENT + UserIndex - Pointer to the index of the event which satisfied the wait condition + +Returns: + + EFI_SUCCESS - The event indicated by Index was signaled. + EFI_INVALID_PARAMETER - The event indicated by Index has a notification function or + Event was not a valid type + EFI_UNSUPPORTED - The current TPL is not TPL_APPLICATION + +--*/ + +{ + EFI_STATUS Status; + UINTN Index; + + // + // Can only WaitForEvent at TPL_APPLICATION + // + if (gEfiCurrentTpl != EFI_TPL_APPLICATION) { + return EFI_UNSUPPORTED; + } + + for(;;) { + + for(Index = 0; Index < NumberOfEvents; Index++) { + + Status = CoreCheckEvent (UserEvents[Index]); + + // + // provide index of event that caused problem + // + if (Status != EFI_NOT_READY) { + *UserIndex = Index; + return Status; + } + } + + // + // This was the location of the Idle loop callback in EFI 1.x reference + // code. We don't have that concept in this base at this point. + // + } +} + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreCloseEvent ( + IN EFI_EVENT UserEvent + ) +/*++ + +Routine Description: + + Closes an event and frees the event structure. + +Arguments: + + UserEvent - Event to close + +Returns: + + EFI_INVALID_PARAMETER - Parameters are not valid. + + EFI_SUCCESS - The event has been closed + +--*/ + +{ + EFI_STATUS Status; + IEVENT *Event; + + Event = UserEvent; + + if (Event == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Event->Signature != EVENT_SIGNATURE) { + return EFI_INVALID_PARAMETER; + } + + // + // If it's a timer event, make sure it's not pending + // + if (Event->Type & EFI_EVENT_TIMER) { + CoreSetTimer (Event, TimerCancel, 0); + } + + CoreAcquireEventLock (); + + // + // If the event is queued somewhere, remove it + // + + if (Event->RuntimeData.Link.ForwardLink != NULL) { + RemoveEntryList (&Event->RuntimeData.Link); + } + + if (Event->NotifyLink.ForwardLink != NULL) { + RemoveEntryList (&Event->NotifyLink); + } + + if (Event->SignalLink.ForwardLink != NULL) { + RemoveEntryList (&Event->SignalLink); + } + + CoreReleaseEventLock (); + + // + // If the event is registered on a protocol notify, + // then remove it from the protocol database + // + CoreUnregisterProtocolNotify (Event); + + Status = CoreFreePool (Event); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/EDK/Foundation/Core/Dxe/Event/exec.h b/EDK/Foundation/Core/Dxe/Event/exec.h new file mode 100644 index 0000000..2abdc90 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/Event/exec.h @@ -0,0 +1,209 @@ +/*++ + +Copyright (c) 2004 - 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + exec.h + +Abstract: + + EFI Event support + +--*/ + +#ifndef _EXEC_H_ +#define _EXEC_H_ + +#include "Tiano.h" +#include "DxeCore.h" + +#define VALID_TPL(a) ((a) <= EFI_TPL_HIGH_LEVEL) + +// +// EFI_EVENT +// + +#define EVENT_SIGNATURE EFI_SIGNATURE_32('e','v','n','t') +typedef struct { + UINTN Signature; + UINT32 Type; + UINT32 SignalCount; + + // + // Entry if the event is registered to be signalled + // + + EFI_LIST_ENTRY SignalLink; + + // + // Notification information for this event + // + + EFI_TPL NotifyTpl; + EFI_EVENT_NOTIFY NotifyFunction; + VOID *NotifyContext; + EFI_GUID EventGroup; + EFI_LIST_ENTRY NotifyLink; + BOOLEAN ExFlag; + + // + // A list of all runtime events + // + EFI_RUNTIME_EVENT_ENTRY RuntimeData; + + // + // Information by event type + // + + union { + // + // For timer events + // + struct { + EFI_LIST_ENTRY Link; + UINT64 TriggerTime; + UINT64 Period; + } Timer; + } u; + +} IEVENT; + +// +// Internal prototypes +// + +VOID +CoreDispatchEventNotifies ( + IN EFI_TPL Priority + ) +/*++ + +Routine Description: + + Dispatches all pending events. + +Arguments: + + Priority - The task priority level of event notifications to dispatch + +Returns: + + None + +--*/ +; + + +UINTN +CoreHighestSetBit ( + IN UINTN Number + ) +/*++ + +Routine Description: + + Return the highest set bit + +Arguments: + + Number - The value to check + +Returns: + + Bit position of the highest set bit + +--*/ +; + + +BOOLEAN +GetInterruptState ( + VOID + ) +/*++ + +Routine Description: + + Disables CPU interrupts. + +Arguments: + + This - Protocol instance structure + + State - Pointer to the CPU's current interrupt state + +Returns: + + EFI_SUCCESS - If interrupts were disabled in the CPU. + + EFI_INVALID_PARAMETER - State is NULL. + +--*/ +; + +// +// Exported functions +// + +VOID +CoreEventVirtualAddressFixup ( + VOID + ) +/*++ + +Routine Description: + + A function out of date, should be removed. + +Arguments: + + None + +Returns: + + None + +--*/ +; + + +VOID +CoreInitializeTimer ( + VOID + ) +/*++ + +Routine Description: + + Initializes timer support + +Arguments: + + None + +Returns: + + None + +--*/ +; + +// +// extern data declarations +// + +extern EFI_LOCK gEventQueueLock; +extern UINTN gEventPending; +extern EFI_LIST_ENTRY gEventQueue[]; +extern EFI_LIST_ENTRY gEventSignalQueue; +extern UINT8 gHSB[]; + +#endif diff --git a/EDK/Foundation/Core/Dxe/Event/execdata.c b/EDK/Foundation/Core/Dxe/Event/execdata.c new file mode 100644 index 0000000..284b89b --- /dev/null +++ b/EDK/Foundation/Core/Dxe/Event/execdata.c @@ -0,0 +1,50 @@ +/*++ + +Copyright (c) 2004 - 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + execdata.c + +Abstract: + + + + +Revision History + +--*/ + +#include "exec.h" + + +// +// gTpl - Task priority level +// +EFI_TPL gEfiCurrentTpl = EFI_TPL_DRIVER; + + +// +// gEventQueueLock - Protects the event queus +// +EFI_LOCK gEventQueueLock = EFI_INITIALIZE_LOCK_VARIABLE (EFI_TPL_HIGH_LEVEL); + +// +// gEventQueue - A list of event's to notify for each priority level +// gEventPending - A bitmask of the EventQueues that are pending +// +EFI_LIST_ENTRY gEventQueue[EFI_TPL_HIGH_LEVEL + 1]; +UINTN gEventPending = 0; + +// +// gEventSignalQueue - A list of events to signal when the EFI operation occurs +// +EFI_LIST_ENTRY gEventSignalQueue = INITIALIZE_LIST_HEAD_VARIABLE (gEventSignalQueue); + diff --git a/EDK/Foundation/Core/Dxe/Event/timer.c b/EDK/Foundation/Core/Dxe/Event/timer.c new file mode 100644 index 0000000..28ce124 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/Event/timer.c @@ -0,0 +1,386 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + timer.c + +Abstract: + + EFI Event support + +Revision History + +--*/ + + +#include "exec.h" + +// +// Internal prototypes +// +STATIC +UINT64 +CoreCurrentSystemTime ( + VOID + ); + +VOID +EFIAPI +CoreCheckTimers ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +STATIC +VOID +CoreInsertEventTimer ( + IN IEVENT *Event + ); + +// +// Internal data +// + +static EFI_LIST_ENTRY mEfiTimerList = INITIALIZE_LIST_HEAD_VARIABLE (mEfiTimerList); +static EFI_LOCK mEfiTimerLock = EFI_INITIALIZE_LOCK_VARIABLE (EFI_TPL_HIGH_LEVEL - 1); +static EFI_EVENT mEfiCheckTimerEvent; + +static EFI_LOCK mEfiSystemTimeLock = EFI_INITIALIZE_LOCK_VARIABLE (EFI_TPL_HIGH_LEVEL); +static UINT64 mEfiSystemTime = 0; + +// +// Timer functions +// + +VOID +CoreInitializeTimer ( + VOID + ) +/*++ + +Routine Description: + + Initializes timer support + +Arguments: + + None + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + + Status = CoreCreateEvent ( + EFI_EVENT_NOTIFY_SIGNAL, + EFI_TPL_HIGH_LEVEL - 1, + CoreCheckTimers, + NULL, + &mEfiCheckTimerEvent + ); + ASSERT_EFI_ERROR (Status); +} + +STATIC +UINT64 +CoreCurrentSystemTime ( + VOID + ) +/*++ + +Routine Description: + + Returns the current system time + +Arguments: + + None + +Returns: + + Returns the current system time + +--*/ +{ + UINT64 SystemTime; + + CoreAcquireLock (&mEfiSystemTimeLock); + SystemTime = mEfiSystemTime; + CoreReleaseLock (&mEfiSystemTimeLock); + return SystemTime; +} + +VOID +EFIAPI +CoreTimerTick ( + IN UINT64 Duration + ) +/*++ + +Routine Description: + + Called by the platform code to process a tick. + +Arguments: + + Duration - The number of 100ns elasped since the last call to TimerTick + +Returns: + + None + +--*/ +{ + IEVENT *Event; + + // + // Check runtiem flag in case there are ticks while exiting boot services + // + + CoreAcquireLock (&mEfiSystemTimeLock); + + // + // Update the system time + // + + mEfiSystemTime += Duration; + + // + // If the head of the list is expired, fire the timer event + // to process it + // + + if (!IsListEmpty (&mEfiTimerList)) { + Event = CR (mEfiTimerList.ForwardLink, IEVENT, u.Timer.Link, EVENT_SIGNATURE); + + if (Event->u.Timer.TriggerTime <= mEfiSystemTime) { + CoreSignalEvent (mEfiCheckTimerEvent); + } + } + + CoreReleaseLock (&mEfiSystemTimeLock); +} + +VOID +EFIAPI +CoreCheckTimers ( + IN EFI_EVENT CheckEvent, + IN VOID *Context + ) +/*++ + +Routine Description: + + Checks the sorted timer list against the current system time. + Signals any expired event timer. + +Arguments: + + CheckEvent - Not used + + Context - Not used + +Returns: + + None + +--*/ +{ + UINT64 SystemTime; + IEVENT *Event; + + // + // Check the timer database for expired timers + // + + CoreAcquireLock (&mEfiTimerLock); + SystemTime = CoreCurrentSystemTime (); + + while (!IsListEmpty (&mEfiTimerList)) { + Event = CR (mEfiTimerList.ForwardLink, IEVENT, u.Timer.Link, EVENT_SIGNATURE); + + // + // If this timer is not expired, then we're done + // + + if (Event->u.Timer.TriggerTime > SystemTime) { + break; + } + + // + // Remove this timer from the timer queue + // + + RemoveEntryList (&Event->u.Timer.Link); + Event->u.Timer.Link.ForwardLink = NULL; + + // + // Signal it + // + CoreSignalEvent (Event); + + // + // If this is a periodic timer, set it + // + if (Event->u.Timer.Period) { + + // + // Compute the timers new trigger time + // + + Event->u.Timer.TriggerTime = Event->u.Timer.TriggerTime + Event->u.Timer.Period; + + // + // If that's before now, then reset the timer to start from now + // + if (Event->u.Timer.TriggerTime <= SystemTime) { + Event->u.Timer.TriggerTime = SystemTime; + CoreSignalEvent (mEfiCheckTimerEvent); + } + + // + // Add the timer + // + + CoreInsertEventTimer (Event); + } + } + + CoreReleaseLock (&mEfiTimerLock); +} + +STATIC +VOID +CoreInsertEventTimer ( + IN IEVENT *Event + ) +/*++ + +Routine Description: + + Inserts the timer event + +Arguments: + + Event - Points to the internal structure of timer event to be installed + +Returns: + + None + +--*/ +{ + UINT64 TriggerTime; + EFI_LIST_ENTRY *Link; + IEVENT *Event2; + + ASSERT_LOCKED (&mEfiTimerLock); + + // + // Get the timer's trigger time + // + + TriggerTime = Event->u.Timer.TriggerTime; + + // + // Insert the timer into the timer database in assending sorted order + // + + for (Link = mEfiTimerList.ForwardLink; Link != &mEfiTimerList; Link = Link->ForwardLink) { + Event2 = CR (Link, IEVENT, u.Timer.Link, EVENT_SIGNATURE); + + if (Event2->u.Timer.TriggerTime > TriggerTime) { + break; + } + } + + InsertTailList (Link, &Event->u.Timer.Link); +} + + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreSetTimer ( + IN EFI_EVENT UserEvent, + IN EFI_TIMER_DELAY Type, + IN UINT64 TriggerTime + ) +/*++ + +Routine Description: + + Sets the type of timer and the trigger time for a timer event. + +Arguments: + + UserEvent - The timer event that is to be signaled at the specified time + Type - The type of time that is specified in TriggerTime + TriggerTime - The number of 100ns units until the timer expires + +Returns: + + EFI_SUCCESS - The event has been set to be signaled at the requested time + EFI_INVALID_PARAMETER - Event or Type is not valid + +--*/ +{ + IEVENT *Event; + + Event = UserEvent; + + if (Event == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Event->Signature != EVENT_SIGNATURE) { + return EFI_INVALID_PARAMETER; + } + + if (Type < 0 || Type >= TimerTypeMax || !(Event->Type & EFI_EVENT_TIMER)) { + return EFI_INVALID_PARAMETER; + } + + CoreAcquireLock (&mEfiTimerLock); + + // + // If the timer is queued to the timer database, remove it + // + + if (Event->u.Timer.Link.ForwardLink != NULL) { + RemoveEntryList (&Event->u.Timer.Link); + Event->u.Timer.Link.ForwardLink = NULL; + } + + Event->u.Timer.TriggerTime = 0; + Event->u.Timer.Period = 0; + + if (Type != TimerCancel) { + + if (Type == TimerPeriodic) { + Event->u.Timer.Period = TriggerTime; + } + + Event->u.Timer.TriggerTime = CoreCurrentSystemTime () + TriggerTime; + CoreInsertEventTimer (Event); + + if (TriggerTime == 0) { + CoreSignalEvent (mEfiCheckTimerEvent); + } + } + + CoreReleaseLock (&mEfiTimerLock); + return EFI_SUCCESS; +} diff --git a/EDK/Foundation/Core/Dxe/Event/tpl.c b/EDK/Foundation/Core/Dxe/Event/tpl.c new file mode 100644 index 0000000..3ac99fc --- /dev/null +++ b/EDK/Foundation/Core/Dxe/Event/tpl.c @@ -0,0 +1,198 @@ +/*++ + +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + tpl.c + +Abstract: + + Task priority function + +--*/ + +#include "exec.h" + +STATIC +VOID +CoreSetInterruptState ( + IN BOOLEAN Enable + ) +/*++ + +Routine Description: + + Set Interrupt State + +Arguments: + + Enable - The state of enable or disable interrupt + +Returns: + + None + +--*/ + +{ + if (gCpu != NULL) { + if (Enable) { + gCpu->EnableInterrupt(gCpu); + } else { + gCpu->DisableInterrupt(gCpu); + } + } +} + +// +// Return the highest set bit +// +UINTN +CoreHighestSetBit ( + IN UINTN Number + ) +/*++ + +Routine Description: + + Return the highest set bit + +Arguments: + + Number - The value to check + +Returns: + + Bit position of the highest set bit + +--*/ +{ + UINTN msb; + + msb = 31; + while ((msb > 0) && ((Number & ((UINTN)1 << msb)) == 0)) { + msb--; + } + + return msb; +} + + +EFI_BOOTSERVICE +EFI_TPL +EFIAPI +CoreRaiseTpl ( + IN EFI_TPL NewTpl + ) +/*++ + +Routine Description: + + Raise the task priority level to the new level. + High level is implemented by disabling processor interrupts. + +Arguments: + + NewTpl - New task priority level + +Returns: + + The previous task priority level + +--*/ +{ + EFI_TPL OldTpl; + + OldTpl = gEfiCurrentTpl; + ASSERT (OldTpl <= NewTpl); + ASSERT (VALID_TPL (NewTpl)); + + // + // If raising to high level, disable interrupts + // + if (NewTpl >= EFI_TPL_HIGH_LEVEL && OldTpl < EFI_TPL_HIGH_LEVEL) { + CoreSetInterruptState (FALSE); + } + + // + // Set the new value + // + gEfiCurrentTpl = NewTpl; + + return OldTpl; +} + + +EFI_BOOTSERVICE +VOID +EFIAPI +CoreRestoreTpl ( + IN EFI_TPL NewTpl + ) +/*++ + +Routine Description: + + Lowers the task priority to the previous value. If the new + priority unmasks events at a higher priority, they are dispatched. + +Arguments: + + NewTpl - New, lower, task priority + +Returns: + + None + +--*/ +{ + EFI_TPL OldTpl; + + OldTpl = gEfiCurrentTpl; + ASSERT (NewTpl <= OldTpl); + ASSERT (VALID_TPL (NewTpl)); + + // + // If lowering below HIGH_LEVEL, make sure + // interrupts are enabled + // + + if (OldTpl >= EFI_TPL_HIGH_LEVEL && NewTpl < EFI_TPL_HIGH_LEVEL) { + gEfiCurrentTpl = EFI_TPL_HIGH_LEVEL; + } + + // + // Dispatch any pending events + // + + while ((-2 << NewTpl) & gEventPending) { + gEfiCurrentTpl = CoreHighestSetBit (gEventPending); + if (gEfiCurrentTpl < EFI_TPL_HIGH_LEVEL) { + CoreSetInterruptState (TRUE); + } + CoreDispatchEventNotifies (gEfiCurrentTpl); + } + + // + // Set the new value + // + + gEfiCurrentTpl = NewTpl; + + // + // If lowering below HIGH_LEVEL, make sure + // interrupts are enabled + // + if (gEfiCurrentTpl < EFI_TPL_HIGH_LEVEL) { + CoreSetInterruptState (TRUE); + } + +} diff --git a/EDK/Foundation/Core/Dxe/FwVol/Ffs.c b/EDK/Foundation/Core/Dxe/FwVol/Ffs.c new file mode 100644 index 0000000..3361ce2 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/FwVol/Ffs.c @@ -0,0 +1,266 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Ffs.c + +Abstract: + + FFS file access utilities. + +--*/ + + +#include "FwVolDriver.h" + +#define PHYSICAL_ADDRESS_TO_POINTER(Address) ((VOID *)((UINTN)(Address))) + + +EFI_FFS_FILE_STATE +GetFileState ( + IN UINT8 ErasePolarity, + IN EFI_FFS_FILE_HEADER *FfsHeader + ) +/*++ + +Routine Description: + Get the FFS file state by checking the highest bit set in the header's state field + +Arguments: + ErasePolarity - Erase polarity attribute of the firmware volume + FfsHeader - Points to the FFS file header + +Returns: + FFS File state + +--*/ +{ + EFI_FFS_FILE_STATE FileState; + UINT8 HighestBit; + + FileState = FfsHeader->State; + + if (ErasePolarity != 0) { + FileState = (EFI_FFS_FILE_STATE)~FileState; + } + + HighestBit = 0x80; + while (HighestBit != 0 && ((HighestBit & FileState) == 0)) { + HighestBit >>= 1; + } + + return (EFI_FFS_FILE_STATE)HighestBit; +} + + +BOOLEAN +IsBufferErased ( + IN UINT8 ErasePolarity, + IN VOID *InBuffer, + IN UINTN BufferSize + ) +/*++ + +Routine Description: + Check if a block of buffer is erased + +Arguments: + ErasePolarity - Erase polarity attribute of the firmware volume + InBuffer - The buffer to be checked + BufferSize - Size of the buffer in bytes + +Returns: + TRUE - The block of buffer is erased + FALSE - The block of buffer is not erased + +--*/ +{ + UINTN Count; + UINT8 EraseByte; + UINT8 *Buffer; + + if(ErasePolarity == 1) { + EraseByte = 0xFF; + } else { + EraseByte = 0; + } + + Buffer = InBuffer; + for (Count = 0; Count < BufferSize; Count++) { + if (Buffer[Count] != EraseByte) { + return FALSE; + } + } + + return TRUE; +} + + +BOOLEAN +VerifyFvHeaderChecksum ( + IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader + ) +/*++ + +Routine Description: + Verify checksum of the firmware volume header + +Arguments: + FvHeader - Points to the firmware volume header to be checked + +Returns: + TRUE - Checksum verification passed + FALSE - Checksum verification failed + +--*/ +{ + UINT32 Index; + UINT32 HeaderLength; + UINT16 Checksum; + UINT16 *ptr; + + HeaderLength = FvHeader->HeaderLength; + ptr = (UINT16 *)FvHeader; + Checksum = 0; + + for (Index = 0; Index < HeaderLength / sizeof (UINT16); Index++) { + Checksum = (UINT16)(Checksum + ptr[Index]); + } + + if (Checksum == 0) { + return TRUE; + } else { + return FALSE; + } +} + + +BOOLEAN +VerifyHeaderChecksum ( + IN EFI_FFS_FILE_HEADER *FfsHeader + ) +/*++ + +Routine Description: + Verify checksum of the FFS file header + +Arguments: + FfsHeader - Points to the FFS file header to be checked + +Returns: + TRUE - Checksum verification passed + FALSE - Checksum verification failed + +--*/ +{ + UINT32 Index; + UINT8 *ptr; + UINT8 HeaderChecksum; + + ptr = (UINT8 *)FfsHeader; + HeaderChecksum = 0; + for (Index = 0; Index < sizeof(EFI_FFS_FILE_HEADER); Index++) { + HeaderChecksum = (UINT8)(HeaderChecksum + ptr[Index]); + } + + HeaderChecksum = HeaderChecksum - FfsHeader->State - FfsHeader->IntegrityCheck.Checksum.File; + + if (HeaderChecksum == 0) { + return TRUE; + } else { + return FALSE; + } +} + + +BOOLEAN +IsValidFfsHeader ( + IN UINT8 ErasePolarity, + IN EFI_FFS_FILE_HEADER *FfsHeader, + OUT EFI_FFS_FILE_STATE *FileState + ) +/*++ + +Routine Description: + Check if it's a valid FFS file header + +Arguments: + ErasePolarity - Erase polarity attribute of the firmware volume + FfsHeader - Points to the FFS file header to be checked + FileState - FFS file state to be returned + +Returns: + TRUE - Valid FFS file header + FALSE - Invalid FFS file header + +--*/ +{ + *FileState = GetFileState (ErasePolarity, FfsHeader); + + switch (*FileState) { + case EFI_FILE_HEADER_VALID: + case EFI_FILE_DATA_VALID: + case EFI_FILE_MARKED_FOR_UPDATE: + case EFI_FILE_DELETED: + // + // Here we need to verify header checksum + // + return VerifyHeaderChecksum (FfsHeader); + + case EFI_FILE_HEADER_CONSTRUCTION: + case EFI_FILE_HEADER_INVALID: + default: + return FALSE; + } +} + + +BOOLEAN +IsValidFfsFile ( + IN UINT8 ErasePolarity, + IN EFI_FFS_FILE_HEADER *FfsHeader + ) +/*++ + +Routine Description: + Check if it's a valid FFS file. + Here we are sure that it has a valid FFS file header since we must call IsValidFfsHeader() first. + +Arguments: + ErasePolarity - Erase polarity attribute of the firmware volume + FfsHeader - Points to the FFS file to be checked + +Returns: + TRUE - Valid FFS file + FALSE - Invalid FFS file + +--*/ +{ + EFI_FFS_FILE_STATE FileState; + + FileState = GetFileState (ErasePolarity, FfsHeader); + switch (FileState) { + + case EFI_FILE_DELETED: + case EFI_FILE_DATA_VALID: + case EFI_FILE_MARKED_FOR_UPDATE: + // + // Some other vliadation like file content checksum might be done here. + // For performance issue, Tiano only do FileState check. + // + return TRUE; + + default: + return FALSE; + } +} + diff --git a/EDK/Foundation/Core/Dxe/FwVol/FwVol.c b/EDK/Foundation/Core/Dxe/FwVol/FwVol.c new file mode 100644 index 0000000..eb0117c --- /dev/null +++ b/EDK/Foundation/Core/Dxe/FwVol/FwVol.c @@ -0,0 +1,556 @@ +/*++ + +Copyright (c) 2004 - 2005, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FwVol.c + +Abstract: + + Firmware File System driver that produce Firmware Volume protocol. + Layers on top of Firmware Block protocol to produce a file abstraction + of FV based files. + +--*/ + +#include "FwVolDriver.h" +#include "DxeCore.h" + +#define KEYSIZE sizeof (UINTN) + +// +// Protocol notify related globals +// +VOID *gEfiFwVolBlockNotifyReg; +EFI_EVENT gEfiFwVolBlockEvent; + +FV_DEVICE mFvDevice = { + FV_DEVICE_SIGNATURE, + NULL, + NULL, + { + FvGetVolumeAttributes, + FvSetVolumeAttributes, + FvReadFile, + FvReadFileSection, + FvWriteFile, + FvGetNextFile, + KEYSIZE + }, + NULL, + NULL, + NULL, + NULL, + { NULL, NULL }, + 0 +}; + + +// +// FFS helper functions +// + +EFI_STATUS +GetFwVolHeader ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb, + OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader + ) +/*++ + +Routine Description: + given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and + copy the volume header into it. + +Arguments: + Fvb - The FW_VOL_BLOCK_PROTOCOL instance from which to read the volume + header + FwVolHeader - Pointer to pointer to allocated buffer in which the volume + header is returned. + +Returns: + EFI_OUT_OF_RESOURCES - No enough buffer could be allocated. + EFI_SUCCESS - Successfully read volume header to the allocated buffer. + +--*/ + +{ + EFI_STATUS Status; + EFI_FIRMWARE_VOLUME_HEADER TempFvh; + UINTN FvhLength; + UINT8 *Buffer; + + + // + //Determine the real length of FV header + // + FvhLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER); + Status = Fvb->Read (Fvb, 0, 0, &FvhLength, (UINT8 *)&TempFvh); + + // + // Allocate a buffer for the caller + // + *FwVolHeader = CoreAllocateBootServicesPool (TempFvh.HeaderLength); + if (*FwVolHeader == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Copy the standard header into the buffer + // + EfiCommonLibCopyMem (*FwVolHeader, &TempFvh, sizeof (EFI_FIRMWARE_VOLUME_HEADER)); + + // + // Read the rest of the header + // + FvhLength = TempFvh.HeaderLength - sizeof (EFI_FIRMWARE_VOLUME_HEADER); + Buffer = (UINT8 *)*FwVolHeader + sizeof (EFI_FIRMWARE_VOLUME_HEADER); + Status = Fvb->Read (Fvb, 0, sizeof (EFI_FIRMWARE_VOLUME_HEADER), &FvhLength, Buffer); + if (EFI_ERROR (Status)) { + // + // Read failed so free buffer + // + CoreFreePool (*FwVolHeader); + } + + return Status; +} + + +STATIC +VOID +FreeFvDeviceResource ( + IN FV_DEVICE *FvDevice + ) +/*++ + +Routine Description: + Free FvDevice resource when error happens + +Arguments: + FvDevice - pointer to the FvDevice to be freed. + +Returns: + None. + +--*/ +{ + FFS_FILE_LIST_ENTRY *FfsFileEntry; + EFI_LIST_ENTRY *NextEntry; + + // + // Free File List Entry + // + FfsFileEntry = (FFS_FILE_LIST_ENTRY *)FvDevice->FfsFileListHeader.ForwardLink; + while (&FfsFileEntry->Link != &FvDevice->FfsFileListHeader) { + NextEntry = (&FfsFileEntry->Link)->ForwardLink; + + if (FfsFileEntry->StreamHandle != 0) { + // + // Close stream and free resources from SEP + // + FfsFileEntry->Sep->CloseSectionStream (FfsFileEntry->Sep, FfsFileEntry->StreamHandle); + } + + CoreFreePool (FfsFileEntry); + + FfsFileEntry = (FFS_FILE_LIST_ENTRY *)NextEntry; + } + + + // + // Free the cache + // + CoreFreePool (FvDevice->CachedFv); + + // + // Free Volume Header + // + CoreFreePool (FvDevice->FwVolHeader); + + return; +} + + +EFI_STATUS +FvCheck ( + IN OUT FV_DEVICE *FvDevice + ) +/*++ + +Routine Description: + Check if a FV is consistent and allocate cache + +Arguments: + FvDevice - pointer to the FvDevice to be checked. + +Returns: + EFI_OUT_OF_RESOURCES - No enough buffer could be allocated. + EFI_SUCCESS - FV is consistent and cache is allocated. + EFI_VOLUME_CORRUPTED - File system is corrupted. + +--*/ +{ + EFI_STATUS Status; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_FVB_ATTRIBUTES FvbAttributes; + EFI_FV_BLOCK_MAP_ENTRY *BlockMap; + FFS_FILE_LIST_ENTRY *FfsFileEntry; + EFI_FFS_FILE_HEADER *FfsHeader; + UINT8 *CacheLocation; + UINTN LbaOffset; + UINTN Index; + EFI_LBA LbaIndex; + UINTN Size; + UINTN FileLength; + EFI_FFS_FILE_STATE FileState; + UINT8 *TopFvAddress; + UINTN TestLength; + + + Fvb = FvDevice->Fvb; + FwVolHeader = FvDevice->FwVolHeader; + + Status = Fvb->GetVolumeAttributes (Fvb, &FvbAttributes); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Size is the size of the FV minus the head. We have already allocated + // the header to check to make sure the volume is valid + // + Size = (UINTN)(FwVolHeader->FvLength - FwVolHeader->HeaderLength); + FvDevice->CachedFv = CoreAllocateZeroBootServicesPool (Size); + if (FvDevice->CachedFv == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Remember a pointer to the end fo the CachedFv + // + FvDevice->EndOfCachedFv = FvDevice->CachedFv + Size; + + // + // Copy FV minus header into memory using the block map we have all ready + // read into memory. + // + BlockMap = FwVolHeader->FvBlockMap; + CacheLocation = FvDevice->CachedFv; + LbaIndex = 0; + LbaOffset = FwVolHeader->HeaderLength; + while ((BlockMap->NumBlocks != 0) || (BlockMap->BlockLength != 0)) { + + for (Index = 0; Index < BlockMap->NumBlocks; Index ++) { + + Size = BlockMap->BlockLength; + if (Index == 0) { + // + // Cache does not include FV Header + // + Size -= LbaOffset; + } + Status = Fvb->Read (Fvb, + LbaIndex, + LbaOffset, + &Size, + CacheLocation + ); + // + // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->BlockLength + // + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // After we skip Fv Header always read from start of block + // + LbaOffset = 0; + + LbaIndex++; + CacheLocation += Size; + } + BlockMap++; + } + + // + // Scan to check the free space & File list + // + if (FvbAttributes & EFI_FVB_ERASE_POLARITY) { + FvDevice->ErasePolarity = 1; + } else { + FvDevice->ErasePolarity = 0; + } + + + // + // go through the whole FV cache, check the consistence of the FV. + // Make a linked list off all the Ffs file headers + // + Status = EFI_SUCCESS; + InitializeListHead (&FvDevice->FfsFileListHeader); + + // + // Build FFS list + // + FfsHeader = (EFI_FFS_FILE_HEADER *)FvDevice->CachedFv; + TopFvAddress = FvDevice->EndOfCachedFv; + while ((UINT8 *)FfsHeader < TopFvAddress) { + + TestLength = TopFvAddress - ((UINT8 *)FfsHeader); + if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) { + TestLength = sizeof (EFI_FFS_FILE_HEADER); + } + + if (IsBufferErased (FvDevice->ErasePolarity, FfsHeader, TestLength)) { + // + // We have found the free space so we are done! + // + goto Done; + } + + if (!IsValidFfsHeader (FvDevice->ErasePolarity, FfsHeader, &FileState)) { + if ((FileState == EFI_FILE_HEADER_INVALID) || + (FileState == EFI_FILE_HEADER_CONSTRUCTION)) { + FfsHeader++; + + continue; + + } else { + // + // File system is corrputed + // + Status = EFI_VOLUME_CORRUPTED; + goto Done; + } + } + + if (!IsValidFfsFile (FvDevice->ErasePolarity, FfsHeader)) { + // + // File system is corrupted + // + Status = EFI_VOLUME_CORRUPTED; + goto Done; + } + + // + // Size[3] is a three byte array, read 4 bytes and throw one away + // + FileLength = *(UINT32 *)&FfsHeader->Size[0] & 0x00FFFFFF; + + FileState = GetFileState (FvDevice->ErasePolarity, FfsHeader); + + // + // check for non-deleted file + // + if (FileState != EFI_FILE_DELETED) { + // + // Create a FFS list entry for each non-deleted file + // + FfsFileEntry = CoreAllocateZeroBootServicesPool (sizeof (FFS_FILE_LIST_ENTRY)); + if (FfsFileEntry == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + FfsFileEntry->FfsHeader = FfsHeader; + InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link); + } + + FfsHeader = (EFI_FFS_FILE_HEADER *)(((UINT8 *)FfsHeader) + FileLength); + + // + // Adjust pointer to the next 8-byte aligned boundry. + // + FfsHeader = (EFI_FFS_FILE_HEADER *)(((UINTN)FfsHeader + 7) & ~0x07); + + } + +Done: + if (EFI_ERROR (Status)) { + FreeFvDeviceResource (FvDevice); + } + + return Status; +} + + +STATIC +VOID +EFIAPI +NotifyFwVolBlock ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + This notification function is invoked when an instance of the + EFI_FW_VOLUME_BLOCK_PROTOCOL is produced. It layers an instance of the + EFI_FIRMWARE_VOLUME_PROTOCOL on the same handle. This is the function where + the actual initialization of the EFI_FIRMWARE_VOLUME_PROTOCOL is done. + +Arguments: + Event - The event that occured + Context - For EFI compatiblity. Not used. + +Returns: + + None. + +--*/ +{ + EFI_HANDLE Handle; + EFI_STATUS Status; + UINTN BufferSize; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; + EFI_FIRMWARE_VOLUME_PROTOCOL *Fv; + FV_DEVICE *FvDevice; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + // + // Examine all new handles + // + for (;;) { + // + // Get the next handle + // + BufferSize = sizeof (Handle); + Status = CoreLocateHandle ( + ByRegisterNotify, + NULL, + gEfiFwVolBlockNotifyReg, + &BufferSize, + &Handle + ); + + // + // If not found, we're done + // + if (EFI_NOT_FOUND == Status) { + break; + } + + if (EFI_ERROR (Status)) { + continue; + } + + // + // Get the FirmwareVolumeBlock protocol on that handle + // + Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolumeBlockProtocolGuid, &Fvb); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status) || (Fvb == NULL)) { + return; + } + + // + // Make sure the Fv Header is O.K. + // + Status = GetFwVolHeader (Fvb, &FwVolHeader); + if (EFI_ERROR (Status) || (FwVolHeader == NULL)) { + return; + } + + if (!VerifyFvHeaderChecksum (FwVolHeader)) { + CoreFreePool (FwVolHeader); + continue; + } + + + // + // Check to see that the file system is indeed formatted in a way we can + // understand it... + // + if (!EfiCompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystemGuid)) { + continue; + } + + // + // Check if there is an FV protocol already installed in that handle + // + Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolumeProtocolGuid, &Fv); + if (!EFI_ERROR (Status)) { + // + // Update Fv to use a new Fvb + // + FvDevice = _CR (Fv, FV_DEVICE, Fv); + if (FvDevice->Signature == FV_DEVICE_SIGNATURE) { + // + // Only write into our device structure if it's our device structure + // + FvDevice->Fvb = Fvb; + } + + } else { + // + // No FwVol protocol on the handle so create a new one + // + FvDevice = CoreAllocateCopyPool (sizeof (FV_DEVICE), &mFvDevice); + if (FvDevice == NULL) { + return; + } + + FvDevice->Fvb = Fvb; + FvDevice->Handle = Handle; + FvDevice->FwVolHeader = FwVolHeader; + FvDevice->Fv.ParentHandle = Fvb->ParentHandle; + + // + // Install an New FV protocol on the existing handle + // + Status = CoreInstallProtocolInterface ( + &Handle, + &gEfiFirmwareVolumeProtocolGuid, + EFI_NATIVE_INTERFACE, + &FvDevice->Fv + ); + ASSERT_EFI_ERROR (Status); + } + } + + return; +} + + +EFI_STATUS +EFIAPI +FwVolDriverInit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + This routine is the driver initialization entry point. It initializes the + libraries, and registers two notification functions. These notification + functions are responsible for building the FV stack dynamically. + +Arguments: + ImageHandle - The image handle. + SystemTable - The system table. + +Returns: + EFI_SUCCESS - Function successfully returned. + +--*/ +{ + gEfiFwVolBlockEvent = CoreCreateProtocolNotifyEvent ( + &gEfiFirmwareVolumeBlockProtocolGuid, + EFI_TPL_CALLBACK, + NotifyFwVolBlock, + NULL, + &gEfiFwVolBlockNotifyReg, + TRUE + ); + return EFI_SUCCESS; +} + diff --git a/EDK/Foundation/Core/Dxe/FwVol/FwVolAttrib.c b/EDK/Foundation/Core/Dxe/FwVol/FwVolAttrib.c new file mode 100644 index 0000000..690d919 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/FwVol/FwVolAttrib.c @@ -0,0 +1,99 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FwVolAttrib.c + +Abstract: + + Implements get/set firmware volume attributes + +--*/ + +#include "FwVolDriver.h" + +EFI_STATUS +EFIAPI +FvGetVolumeAttributes ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, + OUT EFI_FV_ATTRIBUTES *Attributes + ) +/*++ + +Routine Description: + Retrieves attributes, insures positive polarity of attribute bits, returns + resulting attributes in output parameter + +Arguments: + This - Calling context + Attributes - output buffer which contains attributes + +Returns: + EFI_SUCCESS - Successfully got volume attributes + +--*/ +{ + EFI_STATUS Status; + FV_DEVICE *FvDevice; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; + EFI_FVB_ATTRIBUTES FvbAttributes; + + FvDevice = FV_DEVICE_FROM_THIS (This); + Fvb = FvDevice->Fvb; + + if (FvDevice->CachedFv == NULL) { + Status = FvCheck (FvDevice); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // First get the Firmware Volume Block Attributes + // + Status = Fvb->GetVolumeAttributes (Fvb, &FvbAttributes); + + // + // Mask out Fvb bits that are not defined in FV + // + FvbAttributes &= 0xfffff0ff; + + *Attributes = (EFI_FV_ATTRIBUTES)FvbAttributes; + + return Status; +} + + +EFI_STATUS +EFIAPI +FvSetVolumeAttributes ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, + IN OUT EFI_FV_ATTRIBUTES *Attributes + ) +/*++ + +Routine Description: + Sets current attributes for volume + +Arguments: + This - Calling context + Attributes - At input, contains attributes to be set. At output contains + new value of FV + +Returns: + EFI_UNSUPPORTED - Could not be set. + +--*/ +{ + return EFI_UNSUPPORTED; +} + diff --git a/EDK/Foundation/Core/Dxe/FwVol/FwVolDriver.h b/EDK/Foundation/Core/Dxe/FwVol/FwVolDriver.h new file mode 100644 index 0000000..4bd336d --- /dev/null +++ b/EDK/Foundation/Core/Dxe/FwVol/FwVolDriver.h @@ -0,0 +1,487 @@ +/*++ + +Copyright (c) 2004 - 2005, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FwVolDriver.h + +Abstract: + + Firmware File System protocol. Layers on top of Firmware + Block protocol to produce a file abstraction of FV based files. + +--*/ + +#ifndef __FWVOL_H +#define __FWVOL_H + +#include "Tiano.h" +#include "DxeCore.h" +#include "EfiFirmwareFileSystem.h" +#include "EfiFirmwareVolumeHeader.h" + +// +// Consumed protocol +// +#include EFI_PROTOCOL_DEFINITION (FirmwareVolumeBlock) +#include EFI_PROTOCOL_DEFINITION (SectionExtraction) + +// +// Consumed GUID +// +#include EFI_GUID_DEFINITION (FirmwareFileSystem) + +// +// Produced protocol +// +#include EFI_PROTOCOL_DEFINITION (FirmwareVolume) + + +// +// Used to track all non-deleted files +// +typedef struct { + EFI_LIST_ENTRY Link; + EFI_FFS_FILE_HEADER *FfsHeader; + UINTN StreamHandle; + EFI_SECTION_EXTRACTION_PROTOCOL *Sep; +} FFS_FILE_LIST_ENTRY; + +typedef struct { + UINTN Signature; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; + EFI_HANDLE Handle; + EFI_FIRMWARE_VOLUME_PROTOCOL Fv; + + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + UINT8 *CachedFv; + UINT8 *EndOfCachedFv; + + FFS_FILE_LIST_ENTRY *LastKey; + + EFI_LIST_ENTRY FfsFileListHeader; + + UINT8 ErasePolarity; +} FV_DEVICE; + +#define FV_DEVICE_FROM_THIS(a) CR(a, FV_DEVICE, Fv, FV_DEVICE_SIGNATURE) + + +EFI_STATUS +EFIAPI +FvGetVolumeAttributes ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, + OUT EFI_FV_ATTRIBUTES *Attributes + ) +/*++ + +Routine Description: + Retrieves attributes, insures positive polarity of attribute bits, returns + resulting attributes in output parameter + +Arguments: + This - Calling context + Attributes - output buffer which contains attributes + +Returns: + EFI_SUCCESS - Successfully got volume attributes + +--*/ +; + +EFI_STATUS +EFIAPI +FvSetVolumeAttributes ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, + IN OUT EFI_FV_ATTRIBUTES *Attributes + ) +/*++ + +Routine Description: + Sets current attributes for volume + +Arguments: + This - Calling context + Attributes - At input, contains attributes to be set. At output contains + new value of FV + +Returns: + EFI_UNSUPPORTED - Could not be set. +--*/ +; + +EFI_STATUS +EFIAPI +FvGetNextFile ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, + IN OUT VOID *Key, + IN OUT EFI_FV_FILETYPE *FileType, + OUT EFI_GUID *NameGuid, + OUT EFI_FV_FILE_ATTRIBUTES *Attributes, + OUT UINTN *Size + ) +/*++ + +Routine Description: + Given the input key, search for the next matching file in the volume. + +Arguments: + This - Indicates the calling context. + FileType - FileType is a pointer to a caller allocated + EFI_FV_FILETYPE. The GetNextFile() API can filter it's + search for files based on the value of *FileType input. + A *FileType input of 0 causes GetNextFile() to search for + files of all types. If a file is found, the file's type + is returned in *FileType. *FileType is not modified if + no file is found. + Key - Key is a pointer to a caller allocated buffer that + contains implementation specific data that is used to + track where to begin the search for the next file. + The size of the buffer must be at least This->KeySize + bytes long. To reinitialize the search and begin from + the beginning of the firmware volume, the entire buffer + must be cleared to zero. Other than clearing the buffer + to initiate a new search, the caller must not modify the + data in the buffer between calls to GetNextFile(). + NameGuid - NameGuid is a pointer to a caller allocated EFI_GUID. + If a file is found, the file's name is returned in + *NameGuid. *NameGuid is not modified if no file is + found. + Attributes - Attributes is a pointer to a caller allocated + EFI_FV_FILE_ATTRIBUTES. If a file is found, the file's + attributes are returned in *Attributes. *Attributes is + not modified if no file is found. + Size - Size is a pointer to a caller allocated UINTN. + If a file is found, the file's size is returned in *Size. + *Size is not modified if no file is found. + +Returns: + EFI_SUCCESS - Successfully find the file. + EFI_DEVICE_ERROR - Device error. + EFI_ACCESS_DENIED - Fv could not read. + EFI_NOT_FOUND - No matching file found. + EFI_INVALID_PARAMETER - Invalid parameter + +--*/ +; + + +EFI_STATUS +EFIAPI +FvReadFile ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, + IN EFI_GUID *NameGuid, + IN OUT VOID **Buffer, + IN OUT UINTN *BufferSize, + OUT EFI_FV_FILETYPE *FoundType, + OUT EFI_FV_FILE_ATTRIBUTES *FileAttributes, + OUT UINT32 *AuthenticationStatus + ) +/*++ + +Routine Description: + Locates a file in the firmware volume and + copies it to the supplied buffer. + +Arguments: + This - Indicates the calling context. + NameGuid - Pointer to an EFI_GUID, which is the filename. + Buffer - Buffer is a pointer to pointer to a buffer in + which the file or section contents or are returned. + BufferSize - BufferSize is a pointer to caller allocated + UINTN. On input *BufferSize indicates the size + in bytes of the memory region pointed to by + Buffer. On output, *BufferSize contains the number + of bytes required to read the file. + FoundType - FoundType is a pointer to a caller allocated + EFI_FV_FILETYPE that on successful return from Read() + contains the type of file read. This output reflects + the file type irrespective of the value of the + SectionType input. + FileAttributes - FileAttributes is a pointer to a caller allocated + EFI_FV_FILE_ATTRIBUTES. On successful return from + Read(), *FileAttributes contains the attributes of + the file read. + AuthenticationStatus - AuthenticationStatus is a pointer to a caller + allocated UINTN in which the authentication status + is returned. +Returns: + EFI_SUCCESS - Successfully read to memory buffer. + EFI_WARN_BUFFER_TOO_SMALL - Buffer too small. + EFI_NOT_FOUND - Not found. + EFI_DEVICE_ERROR - Device error. + EFI_ACCESS_DENIED - Could not read. + EFI_INVALID_PARAMETER - Invalid parameter. + EFI_OUT_OF_RESOURCES - Not enough buffer to be allocated. + +--*/ +; + +EFI_STATUS +EFIAPI +FvReadFileSection ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, + IN EFI_GUID *NameGuid, + IN EFI_SECTION_TYPE SectionType, + IN UINTN SectionInstance, + IN OUT VOID **Buffer, + IN OUT UINTN *BufferSize, + OUT UINT32 *AuthenticationStatus + ) +/*++ + + Routine Description: + Locates a section in a given FFS File and + copies it to the supplied buffer (not including section header). + + Arguments: + This - Indicates the calling context. + NameGuid - Pointer to an EFI_GUID, which is the filename. + SectionType - Indicates the section type to return. + SectionInstance - Indicates which instance of sections with a type of + SectionType to return. + Buffer - Buffer is a pointer to pointer to a buffer in which + the file or section contents or are returned. + BufferSize - BufferSize is a pointer to caller allocated UINTN. + AuthenticationStatus -AuthenticationStatus is a pointer to a caller + allocated UINT32 in which the authentication status + is returned. + + Returns: + EFI_SUCCESS - Successfully read the file section into buffer. + EFI_WARN_BUFFER_TOO_SMALL - Buffer too small. + EFI_NOT_FOUND - Section not found. + EFI_DEVICE_ERROR - Device error. + EFI_ACCESS_DENIED - Could not read. + EFI_INVALID_PARAMETER - Invalid parameter. + +--*/ +; + +EFI_STATUS +EFIAPI +FvWriteFile ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, + IN UINT32 NumberOfFiles, + IN EFI_FV_WRITE_POLICY WritePolicy, + IN EFI_FV_WRITE_FILE_DATA *FileData + ) +/*++ + + Routine Description: + Writes one or more files to the firmware volume. + + Arguments: + This - Indicates the calling context. + WritePolicy - WritePolicy indicates the level of reliability for + the write in the event of a power failure or other + system failure during the write operation. + FileData - FileData is an pointer to an array of EFI_FV_WRITE_DATA. + Each element of FileData[] represents a file to be written. + + Returns: + EFI_SUCCESS - Files successfully written to firmware volume + EFI_OUT_OF_RESOURCES - Not enough buffer to be allocated. + EFI_DEVICE_ERROR - Device error. + EFI_WRITE_PROTECTED - Write protected. + EFI_NOT_FOUND - Not found. + EFI_INVALID_PARAMETER - Invalid parameter. + EFI_UNSUPPORTED - This function not supported. + +--*/ +; + + + +// +//Internal functions +// +typedef enum { + EfiCheckSumUint8 = 0, + EfiCheckSumUint16 = 1, + EfiCheckSumUint32 = 2, + EfiCheckSumUint64 = 3, + EfiCheckSumMaximum = 4 +} EFI_CHECKSUM_TYPE; + + +BOOLEAN +IsBufferErased ( + IN UINT8 ErasePolarity, + IN VOID *Buffer, + IN UINTN BufferSize + ) +/*++ + +Routine Description: + Check if a block of buffer is erased + +Arguments: + ErasePolarity - Erase polarity attribute of the firmware volume + Buffer - The buffer to be checked + BufferSize - Size of the buffer in bytes + +Returns: + TRUE - The block of buffer is erased + FALSE - The block of buffer is not erased + +--*/ +; + +EFI_FFS_FILE_STATE +GetFileState ( + IN UINT8 ErasePolarity, + IN EFI_FFS_FILE_HEADER *FfsHeader + ) +/*++ + +Routine Description: + Get the FFS file state by checking the highest bit set in the header's state field + +Arguments: + ErasePolarity - Erase polarity attribute of the firmware volume + FfsHeader - Points to the FFS file header + +Returns: + FFS File state + +--*/ +; + +VOID +SetFileState ( + IN UINT8 State, + IN EFI_FFS_FILE_HEADER *FfsHeader + ) +/*++ + +Routine Description: + Set the FFS file state. + +Arguments: + State - The state to be set. + FfsHeader - Points to the FFS file header + +Returns: + None. + +--*/ +; + +BOOLEAN +VerifyFvHeaderChecksum ( + IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader + ) +/*++ + +Routine Description: + Verify checksum of the firmware volume header + +Arguments: + FvHeader - Points to the firmware volume header to be checked + +Returns: + TRUE - Checksum verification passed + FALSE - Checksum verification failed + +--*/ +; + +BOOLEAN +IsValidFfsHeader ( + IN UINT8 ErasePolarity, + IN EFI_FFS_FILE_HEADER *FfsHeader, + OUT EFI_FFS_FILE_STATE *FileState + ) +/*++ + +Routine Description: + Check if it's a valid FFS file header + +Arguments: + ErasePolarity - Erase polarity attribute of the firmware volume + FfsHeader - Points to the FFS file header to be checked + FileState - FFS file state to be returned + +Returns: + TRUE - Valid FFS file header + FALSE - Invalid FFS file header + +--*/ +; + +BOOLEAN +IsValidFfsFile ( + IN UINT8 ErasePolarity, + IN EFI_FFS_FILE_HEADER *FfsHeader + ) +/*++ + +Routine Description: + Check if it's a valid FFS file. + Here we are sure that it has a valid FFS file header since we must call IsValidFfsHeader() first. + +Arguments: + ErasePolarity - Erase polarity attribute of the firmware volume + FfsHeader - Points to the FFS file to be checked + +Returns: + TRUE - Valid FFS file + FALSE - Invalid FFS file + +--*/ +; + +EFI_STATUS +GetFwVolHeader ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb, + OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader + ) +/*++ + +Routine Description: + given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and + copy the volume header into it. + +Arguments: + Fvb - The FW_VOL_BLOCK_PROTOCOL instance from which to read the volume + header + FwVolHeader - Pointer to pointer to allocated buffer in which the volume + header is returned. + +Returns: + Status code. + +--*/ +; + + +EFI_STATUS +FvCheck ( + IN OUT FV_DEVICE *FvDevice + ) +/*++ + +Routine Description: + Check if a FV is consistent and allocate cache + +Arguments: + FvDevice - pointer to the FvDevice to be checked. + +Returns: + EFI_OUT_OF_RESOURCES - Not enough buffer to be allocated. + EFI_SUCCESS - FV is consistent and cache is allocated. + EFI_VOLUME_CORRUPTED - File system is corrupted. + +--*/ +; + +#endif \ No newline at end of file diff --git a/EDK/Foundation/Core/Dxe/FwVol/FwVolRead.c b/EDK/Foundation/Core/Dxe/FwVol/FwVolRead.c new file mode 100644 index 0000000..acaffa8 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/FwVol/FwVolRead.c @@ -0,0 +1,520 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FwVolRead.c + +Abstract: + + Implements read firmware file + +--*/ + +#include "FwVolDriver.h" +#include "DxeCore.h" + +/*++ + +Required Alignment Alignment Value in FFS Alignment Value in +(bytes) Attributes Field Firmware Volume Interfaces +1 0 0 +2 0 1 +4 0 2 +8 0 3 +16 1 4 +128 2 7 +512 3 9 +1 KB 4 10 +4 KB 5 12 +32 KB 6 15 +64 KB 7 16 + +--*/ + +UINT8 mFvAttributes[] = {0, 4, 7, 9, 10, 12, 15, 16}; + + +STATIC +EFI_FV_FILE_ATTRIBUTES +FfsAttributes2FvFileAttributes ( + IN EFI_FFS_FILE_ATTRIBUTES FfsAttributes + ) +/*++ + + Routine Description: + Convert the FFS File Attributes to FV File Attributes + + Arguments: + FfsAttributes - The attributes of UINT8 type. + + Returns: + The attributes of EFI_FV_FILE_ATTRIBUTES + +--*/ +{ + FfsAttributes = (EFI_FFS_FILE_ATTRIBUTES)((FfsAttributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3); + ASSERT (FfsAttributes < 8); + + return (EFI_FV_FILE_ATTRIBUTES) mFvAttributes[FfsAttributes]; +} + + +EFI_STATUS +EFIAPI +FvGetNextFile ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, + IN OUT VOID *Key, + IN OUT EFI_FV_FILETYPE *FileType, + OUT EFI_GUID *NameGuid, + OUT EFI_FV_FILE_ATTRIBUTES *Attributes, + OUT UINTN *Size + ) +/*++ + +Routine Description: + Given the input key, search for the next matching file in the volume. + +Arguments: + This - Indicates the calling context. + FileType - FileType is a pointer to a caller allocated + EFI_FV_FILETYPE. The GetNextFile() API can filter it's + search for files based on the value of *FileType input. + A *FileType input of 0 causes GetNextFile() to search for + files of all types. If a file is found, the file's type + is returned in *FileType. *FileType is not modified if + no file is found. + Key - Key is a pointer to a caller allocated buffer that + contains implementation specific data that is used to + track where to begin the search for the next file. + The size of the buffer must be at least This->KeySize + bytes long. To reinitialize the search and begin from + the beginning of the firmware volume, the entire buffer + must be cleared to zero. Other than clearing the buffer + to initiate a new search, the caller must not modify the + data in the buffer between calls to GetNextFile(). + NameGuid - NameGuid is a pointer to a caller allocated EFI_GUID. + If a file is found, the file's name is returned in + *NameGuid. *NameGuid is not modified if no file is + found. + Attributes - Attributes is a pointer to a caller allocated + EFI_FV_FILE_ATTRIBUTES. If a file is found, the file's + attributes are returned in *Attributes. *Attributes is + not modified if no file is found. + Size - Size is a pointer to a caller allocated UINTN. + If a file is found, the file's size is returned in *Size. + *Size is not modified if no file is found. + +Returns: + EFI_SUCCESS - Successfully find the file. + EFI_DEVICE_ERROR - Device error. + EFI_ACCESS_DENIED - Fv could not read. + EFI_NOT_FOUND - No matching file found. + EFI_INVALID_PARAMETER - Invalid parameter + +--*/ +{ + EFI_STATUS Status; + FV_DEVICE *FvDevice; + EFI_FV_ATTRIBUTES FvAttributes; + EFI_FFS_FILE_HEADER *FfsFileHeader; + UINTN *KeyValue; + EFI_LIST_ENTRY *Link; + FFS_FILE_LIST_ENTRY *FfsFileEntry; + UINTN FileLength; + + FvDevice = FV_DEVICE_FROM_THIS (This); + + Status = FvGetVolumeAttributes (This, &FvAttributes); + if (EFI_ERROR (Status)){ + return Status; + } + + // + // Check if read operation is enabled + // + if ((FvAttributes & EFI_FV_READ_STATUS) == 0) { + return EFI_ACCESS_DENIED; + } + + if (*FileType > EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) { + // + // File type needs to be in 0 - 0x0B + // + return EFI_INVALID_PARAMETER; + } + + KeyValue = (UINTN *)Key; + for (;;) { + if (*KeyValue == 0) { + // + // Search for 1st matching file + // + Link = &FvDevice->FfsFileListHeader; + } else { + // + // Key is pointer to FFsFileEntry, so get next one + // + Link = (EFI_LIST_ENTRY *)(*KeyValue); + } + + if (Link->ForwardLink == &FvDevice->FfsFileListHeader) { + // + // Next is end of list so we did not find data + // + return EFI_NOT_FOUND; + } + + FfsFileEntry = (FFS_FILE_LIST_ENTRY *)Link->ForwardLink; + FfsFileHeader = (EFI_FFS_FILE_HEADER *)FfsFileEntry->FfsHeader; + + // + // remember the key + // + *KeyValue = (UINTN)FfsFileEntry; + + if (FfsFileHeader->Type == EFI_FV_FILETYPE_FFS_PAD) { + // + // we ignore pad files + // + continue; + } + + if (*FileType == 0) { + // + // Process all file types so we have a match + // + break; + } + + if (*FileType == FfsFileHeader->Type) { + // + // Found a matching file type + // + break; + } + + } + + // + // Return FileType, NameGuid, and Attributes + // + *FileType = FfsFileHeader->Type; + EfiCommonLibCopyMem (NameGuid, &FfsFileHeader->Name, sizeof (EFI_GUID)); + *Attributes = FfsAttributes2FvFileAttributes (FfsFileHeader->Attributes); + + // + // Read four bytes out of the 3 byte array and throw out extra data + // + FileLength = *(UINT32 *)&FfsFileHeader->Size[0] & 0x00FFFFFF; + + // + // we need to substract the header size + // + *Size = FileLength - sizeof(EFI_FFS_FILE_HEADER); + + if (FfsFileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT) { + // + // If tail is present substract it's size; + // + *Size -= sizeof(EFI_FFS_FILE_TAIL); + } + + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +FvReadFile ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, + IN EFI_GUID *NameGuid, + IN OUT VOID **Buffer, + IN OUT UINTN *BufferSize, + OUT EFI_FV_FILETYPE *FoundType, + OUT EFI_FV_FILE_ATTRIBUTES *FileAttributes, + OUT UINT32 *AuthenticationStatus + ) +/*++ + +Routine Description: + Locates a file in the firmware volume and + copies it to the supplied buffer. + +Arguments: + This - Indicates the calling context. + NameGuid - Pointer to an EFI_GUID, which is the filename. + Buffer - Buffer is a pointer to pointer to a buffer in + which the file or section contents or are returned. + BufferSize - BufferSize is a pointer to caller allocated + UINTN. On input *BufferSize indicates the size + in bytes of the memory region pointed to by + Buffer. On output, *BufferSize contains the number + of bytes required to read the file. + FoundType - FoundType is a pointer to a caller allocated + EFI_FV_FILETYPE that on successful return from Read() + contains the type of file read. This output reflects + the file type irrespective of the value of the + SectionType input. + FileAttributes - FileAttributes is a pointer to a caller allocated + EFI_FV_FILE_ATTRIBUTES. On successful return from + Read(), *FileAttributes contains the attributes of + the file read. + AuthenticationStatus - AuthenticationStatus is a pointer to a caller + allocated UINTN in which the authentication status + is returned. +Returns: + EFI_SUCCESS - Successfully read to memory buffer. + EFI_WARN_BUFFER_TOO_SMALL - Buffer too small. + EFI_NOT_FOUND - Not found. + EFI_DEVICE_ERROR - Device error. + EFI_ACCESS_DENIED - Could not read. + EFI_INVALID_PARAMETER - Invalid parameter. + EFI_OUT_OF_RESOURCES - Not enough buffer to be allocated. + +--*/ +{ + EFI_STATUS Status; + FV_DEVICE *FvDevice; + EFI_GUID SearchNameGuid; + EFI_FV_FILETYPE LocalFoundType; + EFI_FV_FILE_ATTRIBUTES LocalAttributes; + UINTN FileSize; + UINT8 *SrcPtr; + EFI_FFS_FILE_HEADER *FfsHeader; + UINTN InputBufferSize; + + if (NULL == NameGuid) { + return EFI_INVALID_PARAMETER; + } + + FvDevice = FV_DEVICE_FROM_THIS (This); + + + // + // Keep looking until we find the matching NameGuid. + // The Key is really an FfsFileEntry + // + FvDevice->LastKey = 0; + do { + LocalFoundType = 0; + Status = FvGetNextFile ( + This, + &FvDevice->LastKey, + &LocalFoundType, + &SearchNameGuid, + &LocalAttributes, + &FileSize + ); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + } while (!EfiCompareGuid (&SearchNameGuid, NameGuid)); + + // + // Get a pointer to the header + // + FfsHeader = FvDevice->LastKey->FfsHeader; + + // + // Remember callers buffer size + // + InputBufferSize = *BufferSize; + + // + // Calculate return values + // + *FoundType = FfsHeader->Type; + *FileAttributes = FfsAttributes2FvFileAttributes (FfsHeader->Attributes); + *AuthenticationStatus = 0; + *BufferSize = FileSize; + + if (Buffer == NULL) { + // + // If Buffer is NULL, we only want to get the information colected so far + // + return EFI_SUCCESS; + } + + // + // Skip over file header + // + SrcPtr = ((UINT8 *)FfsHeader) + sizeof (EFI_FFS_FILE_HEADER); + + Status = EFI_SUCCESS; + if (*Buffer == NULL) { + // + // Caller passed in a pointer so allocate buffer for them + // + *Buffer = CoreAllocateBootServicesPool (FileSize); + if (*Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } else if (FileSize > InputBufferSize) { + // + // Callers buffer was not big enough + // + Status = EFI_WARN_BUFFER_TOO_SMALL; + FileSize = InputBufferSize; + } + + // + // Copy data into callers buffer + // + EfiCommonLibCopyMem (*Buffer, SrcPtr, FileSize); + + return Status; +} + + +EFI_STATUS +EFIAPI +FvReadFileSection ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, + IN EFI_GUID *NameGuid, + IN EFI_SECTION_TYPE SectionType, + IN UINTN SectionInstance, + IN OUT VOID **Buffer, + IN OUT UINTN *BufferSize, + OUT UINT32 *AuthenticationStatus + ) +/*++ + + Routine Description: + Locates a section in a given FFS File and + copies it to the supplied buffer (not including section header). + + Arguments: + This - Indicates the calling context. + NameGuid - Pointer to an EFI_GUID, which is the filename. + SectionType - Indicates the section type to return. + SectionInstance - Indicates which instance of sections with a type of + SectionType to return. + Buffer - Buffer is a pointer to pointer to a buffer in which + the file or section contents or are returned. + BufferSize - BufferSize is a pointer to caller allocated UINTN. + AuthenticationStatus -AuthenticationStatus is a pointer to a caller + allocated UINT32 in which the authentication status + is returned. + + Returns: + EFI_SUCCESS - Successfully read the file section into buffer. + EFI_WARN_BUFFER_TOO_SMALL - Buffer too small. + EFI_NOT_FOUND - Section not found. + EFI_DEVICE_ERROR - Device error. + EFI_ACCESS_DENIED - Could not read. + EFI_INVALID_PARAMETER - Invalid parameter. + +--*/ +{ + EFI_STATUS Status; + FV_DEVICE *FvDevice; + EFI_FV_FILETYPE FileType; + EFI_FV_FILE_ATTRIBUTES FileAttributes; + UINTN FileSize; + UINT8 *FileBuffer; + EFI_SECTION_EXTRACTION_PROTOCOL *Sep; + FFS_FILE_LIST_ENTRY *FfsEntry; + + if (NULL == NameGuid || Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + FvDevice = FV_DEVICE_FROM_THIS (This); + + // + // Read the whole file into buffer + // + FileBuffer = NULL; + Status = FvReadFile ( + This, + NameGuid, + &FileBuffer, + &FileSize, + &FileType, + &FileAttributes, + AuthenticationStatus + ); + // + // Get the last key used by our call to FvReadFile as it is the FfsEntry for this file. + // + FfsEntry = (FFS_FILE_LIST_ENTRY *)FvDevice->LastKey; + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Check to see that the file actually HAS sections before we go any further. + // + if (FileType == EFI_FV_FILETYPE_RAW) { + Status = EFI_NOT_FOUND; + goto Done; + } + + // + // Use FfsEntry to cache Section Extraction Protocol Inforomation + // + if (FfsEntry->StreamHandle == 0) { + // + // Located the protocol + // + Status = CoreLocateProtocol (&gEfiSectionExtractionProtocolGuid, NULL, &Sep); + // + // Section Extraction Protocol is part of Dxe Core so this should never fail + // + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status) || (Sep == NULL)) { + goto Done; + } + + Status = Sep->OpenSectionStream ( + Sep, + FileSize, + FileBuffer, + &FfsEntry->StreamHandle + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + FfsEntry->Sep = Sep; + } else { + // + // Get cached copy of Sep + // + Sep = FfsEntry->Sep; + } + + // + // If SectionType == 0 We need the whole section stream + // + Status = Sep->GetSection ( + Sep, + FfsEntry->StreamHandle, + (SectionType == 0) ? NULL : &SectionType, + NULL, + (SectionType == 0) ? 0 : SectionInstance, + Buffer, + BufferSize, + AuthenticationStatus + ); + + // + // Close of stream defered to close of FfsHeader list to allow SEP to cache data + // + +Done: + CoreFreePool (FileBuffer); + + return Status; +} + diff --git a/EDK/Foundation/Core/Dxe/FwVol/FwVolWrite.c b/EDK/Foundation/Core/Dxe/FwVol/FwVolWrite.c new file mode 100644 index 0000000..1db7305 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/FwVol/FwVolWrite.c @@ -0,0 +1,60 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FwVolWrite.c + +Abstract: + + Implements write firmware file + +--*/ + +#include "FwVolDriver.h" + + +EFI_STATUS +EFIAPI +FvWriteFile ( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, + IN UINT32 NumberOfFiles, + IN EFI_FV_WRITE_POLICY WritePolicy, + IN EFI_FV_WRITE_FILE_DATA *FileData + ) +/*++ + + Routine Description: + Writes one or more files to the firmware volume. + + Arguments: + This - Indicates the calling context. + NumberOfFiles - Number of files. + WritePolicy - WritePolicy indicates the level of reliability for + the write in the event of a power failure or other + system failure during the write operation. + FileData - FileData is an pointer to an array of EFI_FV_WRITE_DATA. + Each element of FileData[] represents a file to be written. + + Returns: + EFI_SUCCESS - Files successfully written to firmware volume + EFI_OUT_OF_RESOURCES - Not enough buffer to be allocated. + EFI_DEVICE_ERROR - Device error. + EFI_WRITE_PROTECTED - Write protected. + EFI_NOT_FOUND - Not found. + EFI_INVALID_PARAMETER - Invalid parameter. + EFI_UNSUPPORTED - This function not supported. + +--*/ +{ + return EFI_UNSUPPORTED; +} + diff --git a/EDK/Foundation/Core/Dxe/FwVolBlock/FwVolBlock.c b/EDK/Foundation/Core/Dxe/FwVolBlock/FwVolBlock.c new file mode 100644 index 0000000..ebe3964 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/FwVolBlock/FwVolBlock.c @@ -0,0 +1,621 @@ +/*++ + +Copyright (c) 2004 - 2005, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FwVolBlock.c + +Abstract: + + Firmware Volume Block protocol.. Consumes FV hobs and creates + appropriate block protocols. + + Also consumes NT_NON_MM_FV envinronment variable and produces appropriate + block protocols fro them also... (this is TBD) + +--*/ + +#include "Tiano.h" +#include "FwVolBlock.h" + + +EFI_FW_VOL_BLOCK_DEVICE mFwVolBlock = { + FVB_DEVICE_SIGNATURE, + NULL, + { + { + HARDWARE_DEVICE_PATH, + HW_MEMMAP_DP, + (UINT8)(sizeof (MEMMAP_DEVICE_PATH)), + (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8), + EfiMemoryMappedIO, + (EFI_PHYSICAL_ADDRESS)0, + (EFI_PHYSICAL_ADDRESS)0, + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + END_DEVICE_PATH_LENGTH, + 0 + }, + }, + { + FwVolBlockGetAttributes, + (EFI_FVB_SET_ATTRIBUTES)FwVolBlockSetAttributes, + FwVolBlockGetPhysicalAddress, + FwVolBlockGetBlockSize, + FwVolBlockReadBlock, + (EFI_FVB_WRITE)FwVolBlockWriteBlock, + (EFI_FVB_ERASE_BLOCKS)FwVolBlockEraseBlock, + NULL + }, + 0, + NULL, + 0, + 0 +}; + + + + +EFI_STATUS +EFIAPI +FwVolBlockGetAttributes ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_FVB_ATTRIBUTES *Attributes + ) +/*++ + +Routine Description: + Retrieves Volume attributes. No polarity translations are done. + +Arguments: + This - Calling context + Attributes - output buffer which contains attributes + +Returns: + EFI_SUCCESS - The firmware volume attributes were returned. + +--*/ +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + + // + // Since we are read only, it's safe to get attributes data from our in-memory copy. + // + *Attributes = FvbDevice->FvbAttributes; + + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +FwVolBlockSetAttributes ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_FVB_ATTRIBUTES *Attributes + ) +/*++ + +Routine Description: + Modifies the current settings of the firmware volume according to the input parameter. + +Arguments: + This - Calling context + Attributes - input buffer which contains attributes + +Returns: + EFI_SUCCESS - The firmware volume attributes were returned. + EFI_INVALID_PARAMETER - The attributes requested are in conflict with the capabilities as + declared in the firmware volume header. + EFI_UNSUPPORTED - Not supported. +--*/ +{ + return EFI_UNSUPPORTED; +} + + +EFI_STATUS +EFIAPI +FwVolBlockEraseBlock ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + ... + ) +/*++ + +Routine Description: + The EraseBlock() function erases one or more blocks as denoted by the +variable argument list. The entire parameter list of blocks must be verified +prior to erasing any blocks. If a block is requested that does not exist +within the associated firmware volume (it has a larger index than the last +block of the firmware volume), the EraseBlock() function must return +EFI_INVALID_PARAMETER without modifying the contents of the firmware volume. + +Arguments: + This - Calling context + ... - Starting LBA followed by Number of Lba to erase. a -1 to terminate + the list. + +Returns: + EFI_SUCCESS - The erase request was successfully completed. + EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state. + EFI_DEVICE_ERROR - The block device is not functioning correctly and could not be + written. The firmware device may have been partially erased. + EFI_INVALID_PARAMETER - One or more of the LBAs listed in the variable argument list do + EFI_UNSUPPORTED - Not supported. + +--*/ +{ + return EFI_UNSUPPORTED; +} + + +EFI_STATUS +EFIAPI +FwVolBlockReadBlock ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +/*++ + +Routine Description: + Read the specified number of bytes from the block to the input buffer. + +Arguments: + This - Indicates the calling context. + Lba - The starting logical block index to read. + Offset - Offset into the block at which to begin reading. + NumBytes - Pointer to a UINT32. At entry, *NumBytes contains the + total size of the buffer. At exit, *NumBytes contains the + total number of bytes actually read. + Buffer - Pinter to a caller-allocated buffer that contains the destine + for the read. + +Returns: + EFI_SUCCESS - The firmware volume was read successfully. + EFI_BAD_BUFFER_SIZE - The read was attempted across an LBA boundary. + EFI_ACCESS_DENIED - Access denied. + EFI_DEVICE_ERROR - The block device is malfunctioning and could not be read. +--*/ +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + UINT8 *LbaOffset; + UINTN LbaStart; + UINTN NumOfBytesRead; + UINTN LbaIndex; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + + // + // Check if This FW can be read + // + if ((FvbDevice->FvbAttributes & EFI_FVB_READ_STATUS) == 0) { + return EFI_ACCESS_DENIED; + } + + LbaIndex = (UINTN)Lba; + if (LbaIndex >= FvbDevice->NumBlocks) { + // + // Invalid Lba, read nothing. + // + *NumBytes = 0; + return EFI_BAD_BUFFER_SIZE; + } + + if (Offset > FvbDevice->LbaCache[LbaIndex].Length) { + // + // all exceed boundry, read nothing. + // + *NumBytes = 0; + return EFI_BAD_BUFFER_SIZE; + } + + NumOfBytesRead = *NumBytes; + if (Offset + NumOfBytesRead > FvbDevice->LbaCache[LbaIndex].Length) { + // + // partial exceed boundry, read data from current postion to end. + // + NumOfBytesRead = FvbDevice->LbaCache[LbaIndex].Length - Offset; + } + + LbaStart = FvbDevice->LbaCache[LbaIndex].Base; + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)FvbDevice->BaseAddress); + LbaOffset = (UINT8 *)FwVolHeader + LbaStart + Offset; + + // + // Perform read operation + // + EfiCommonLibCopyMem (Buffer, LbaOffset, NumOfBytesRead); + + if (NumOfBytesRead == *NumBytes) { + return EFI_SUCCESS; + } + + *NumBytes = NumOfBytesRead; + return EFI_BAD_BUFFER_SIZE; +} + + +EFI_STATUS +EFIAPI +FwVolBlockWriteBlock ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +/*++ + +Routine Description: + Writes the specified number of bytes from the input buffer to the block. + +Arguments: + This - Indicates the calling context. + Lba - The starting logical block index to write to. + Offset - Offset into the block at which to begin writing. + NumBytes - Pointer to a UINT32. At entry, *NumBytes contains the + total size of the buffer. At exit, *NumBytes contains the + total number of bytes actually written. + Buffer - Pinter to a caller-allocated buffer that contains the source + for the write. + +Returns: + EFI_SUCCESS - The firmware volume was written successfully. + EFI_BAD_BUFFER_SIZE - The write was attempted across an LBA boundary. On output, + NumBytes contains the total number of bytes actually written. + EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state. + EFI_DEVICE_ERROR - The block device is malfunctioning and could not be written. + EFI_UNSUPPORTED - Not supported. +--*/ +{ + return EFI_UNSUPPORTED; +} + + +EFI_STATUS +EFIAPI +FwVolBlockGetPhysicalAddress ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_PHYSICAL_ADDRESS *Address + ) +/*++ + +Routine Description: + Get Fvb's base address. + +Arguments: + This - Indicates the calling context. + Address - Fvb device base address. + +Returns: + EFI_SUCCESS - Successfully got Fvb's base address. + EFI_UNSUPPORTED - Not supported. +--*/ +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + + if (FvbDevice->FvbAttributes & EFI_FVB_MEMORY_MAPPED) { + *Address = FvbDevice->BaseAddress; + return EFI_SUCCESS; + } + + return EFI_UNSUPPORTED; +} + + +EFI_STATUS +EFIAPI +FwVolBlockGetBlockSize ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + OUT UINTN *BlockSize, + OUT UINTN *NumberOfBlocks + ) +/*++ + +Routine Description: + Retrieves the size in bytes of a specific block within a firmware volume. + +Arguments: + This - Indicates the calling context. + Lba - Indicates the block for which to return the size. + BlockSize - Pointer to a caller-allocated UINTN in which the size of the + block is returned. + NumberOfBlocks - Pointer to a caller-allocated UINTN in which the number of + consecutive blocks starting with Lba is returned. All blocks + in this range have a size of BlockSize. +Returns: + EFI_SUCCESS - The firmware volume base address is returned. + EFI_INVALID_PARAMETER - The requested LBA is out of range. +--*/ +{ + UINTN TotalBlocks; + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + + // + // Do parameter checking + // + if (Lba >= FvbDevice->NumBlocks) { + return EFI_INVALID_PARAMETER; + } + + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)FvbDevice->BaseAddress); + + PtrBlockMapEntry = FwVolHeader->FvBlockMap; + + // + // Search the block map for the given block + // + TotalBlocks = 0; + while ((PtrBlockMapEntry->NumBlocks != 0) || (PtrBlockMapEntry->BlockLength !=0 )) { + TotalBlocks += PtrBlockMapEntry->NumBlocks; + if (Lba < TotalBlocks) { + // + // We find the range + // + break; + } + + PtrBlockMapEntry++; + } + + *BlockSize = PtrBlockMapEntry->BlockLength; + *NumberOfBlocks = TotalBlocks - (UINTN)Lba; + + return EFI_SUCCESS; +} + + +EFI_STATUS +ProduceFVBProtocolOnBuffer ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN EFI_HANDLE ParentHandle, + OUT EFI_HANDLE *FvProtocol OPTIONAL + ) +/*++ + +Routine Description: + This routine produces a firmware volume block protocol on a given + buffer. + +Arguments: + BaseAddress - base address of the firmware volume image + Length - length of the firmware volume image + ParentHandle - handle of parent firmware volume, if this + image came from an FV image file in another + firmware volume (ala capsules) + FvProtocol - Firmware volume block protocol produced. + +Returns: + EFI_VOLUME_CORRUPTED - Volume corrupted. + EFI_OUT_OF_RESOURCES - No enough buffer to be allocated. + EFI_SUCCESS - Successfully produced a FVB protocol on given buffer. + +--*/ +{ + EFI_STATUS Status; + EFI_FW_VOL_BLOCK_DEVICE *FvbDev; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + UINTN BlockIndex; + UINTN BlockIndex2; + UINTN LinearOffset; + EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry; + + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)BaseAddress; + // + // Validate FV Header, if not as expected, return + // + if (FwVolHeader->Signature != EFI_FVH_SIGNATURE) { + return EFI_VOLUME_CORRUPTED; + } + // + // Allocate EFI_FW_VOL_BLOCK_DEVICE + // + FvbDev = CoreAllocateCopyPool (sizeof (EFI_FW_VOL_BLOCK_DEVICE), &mFwVolBlock); + if (FvbDev == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + FvbDev->BaseAddress = BaseAddress; + FvbDev->FvbAttributes = FwVolHeader->Attributes; + FvbDev->FwVolBlockInstance.ParentHandle = ParentHandle; + + // + // Init the block caching fields of the device + // First, count the number of blocks + // + FvbDev->NumBlocks = 0; + for (PtrBlockMapEntry = FwVolHeader->FvBlockMap; + PtrBlockMapEntry->NumBlocks != 0; + PtrBlockMapEntry++) { + FvbDev->NumBlocks += PtrBlockMapEntry->NumBlocks; + } + // + // Second, allocate the cache + // + FvbDev->LbaCache = CoreAllocateBootServicesPool (FvbDev->NumBlocks * sizeof (LBA_CACHE)); + if (FvbDev->LbaCache == NULL) { + CoreFreePool (FvbDev); + return EFI_OUT_OF_RESOURCES; + } + // + // Last, fill in the cache with the linear address of the blocks + // + BlockIndex = 0; + LinearOffset = 0; + for (PtrBlockMapEntry = FwVolHeader->FvBlockMap; + PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) { + for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) { + FvbDev->LbaCache[BlockIndex].Base = LinearOffset; + FvbDev->LbaCache[BlockIndex].Length = PtrBlockMapEntry->BlockLength; + LinearOffset += PtrBlockMapEntry->BlockLength; + BlockIndex++; + } + } + + // + // Set up the devicepath + // + FvbDev->DevicePath.MemMapDevPath.StartingAddress = BaseAddress; + FvbDev->DevicePath.MemMapDevPath.EndingAddress = BaseAddress + FwVolHeader->FvLength - 1; + + // + // + // Attach FvVolBlock Protocol to new handle + // + Status = CoreInstallMultipleProtocolInterfaces ( + &FvbDev->Handle, + &gEfiFirmwareVolumeBlockProtocolGuid, &FvbDev->FwVolBlockInstance, + &gEfiDevicePathProtocolGuid, &FvbDev->DevicePath, + &gEfiFirmwareVolumeDispatchProtocolGuid, NULL, + NULL + ); + + // + // If they want the handle back, set it. + // + if (FvProtocol != NULL) { + *FvProtocol = FvbDev->Handle; + } + + return Status; +} + + +EFI_STATUS +EFIAPI +FwVolBlockDriverInit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + This routine is the driver initialization entry point. It initializes the + libraries, consumes FV hobs and NT_NON_MM_FV environment variable and + produces instances of FW_VOL_BLOCK_PROTOCOL as appropriate. +Arguments: + ImageHandle - The image handle. + SystemTable - The system table. +Returns: + EFI_SUCCESS - Successfully initialized firmware volume block driver. +--*/ +{ + EFI_STATUS Status; + VOID *HobList; + EFI_PHYSICAL_ADDRESS BaseAddress; + UINT64 Length; + EFI_STATUS HobStatus; + + // + // First walk hobs and create appropriate FVs. + // + Status = CoreGetConfigTable (&gEfiHobListGuid, &HobList); + // + // Core Needs Firmware Volumes to function + // + ASSERT_EFI_ERROR (Status); + + BaseAddress = 0; + Length = 0; + HobStatus = GetNextFirmwareVolumeHob ( + &HobList, + &BaseAddress, + &Length + ); + while (!EFI_ERROR (HobStatus)) { + // + // Produce an FVB protocol for it + // + ProduceFVBProtocolOnBuffer (BaseAddress, Length, NULL, NULL); + HobStatus = GetNextFirmwareVolumeHob ( + &HobList, + &BaseAddress, + &Length + ); + } + + return EFI_SUCCESS; +} + + +EFI_STATUS +CoreProcessFirmwareVolume ( + IN VOID *FvHeader, + IN UINTN Size, + OUT EFI_HANDLE *FVProtocolHandle + ) +/*++ + +Routine Description: + This DXE service routine is used to process a firmware volume. In + particular, it can be called by BDS to process a single firmware + volume found in a capsule. + +Arguments: + FvHeader - pointer to a firmware volume header + Size - the size of the buffer pointed to by FvHeader + FVProtocolHandle - the handle on which a firmware volume protocol + was produced for the firmware volume passed in. + +Returns: + EFI_OUT_OF_RESOURCES - if an FVB could not be produced due to lack of + system resources + EFI_VOLUME_CORRUPTED - if the volume was corrupted + EFI_SUCCESS - a firmware volume protocol was produced for the + firmware volume + +--*/ +{ + VOID *Ptr; + EFI_STATUS Status; + + *FVProtocolHandle = NULL; + Status = ProduceFVBProtocolOnBuffer ( + (EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader, + (UINT64)Size, + NULL, + FVProtocolHandle + ); + // + // Since in our implementation we use register-protocol-notify to put a + // FV protocol on the FVB protocol handle, we can't directly verify that + // the FV protocol was produced. Therefore here we will check the handle + // and make sure an FV protocol is on it. This indicates that all went + // well. Otherwise we have to assume that the volume was corrupted + // somehow. + // + if (!EFI_ERROR(Status)) { + Ptr = NULL; + Status = CoreHandleProtocol (*FVProtocolHandle, &gEfiFirmwareVolumeProtocolGuid, &Ptr); + if (EFI_ERROR(Status) || (Ptr == NULL)) { + return EFI_VOLUME_CORRUPTED; + } + return EFI_SUCCESS; + } + return Status; +} + + diff --git a/EDK/Foundation/Core/Dxe/FwVolBlock/FwVolBlock.h b/EDK/Foundation/Core/Dxe/FwVolBlock/FwVolBlock.h new file mode 100644 index 0000000..cbf9ffc --- /dev/null +++ b/EDK/Foundation/Core/Dxe/FwVolBlock/FwVolBlock.h @@ -0,0 +1,334 @@ +/*++ + +Copyright (c) 2004 - 2005, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FwVolBlock.h + +Abstract: + + Firmware Volume Block protocol.. Consumes FV hobs and creates + appropriate block protocols. + + Also consumes NT_NON_MM_FV envinronment variable and produces appropriate + block protocols fro them also... (this is TBD) + +--*/ + +#ifndef _FWVOL_BLOCK_H_ +#define _FWVOL_BLOCK_H_ + +#include EFI_PROTOCOL_DEFINITION (FirmwareVolumeBlock) +#include EFI_PROTOCOL_DEFINITION (DevicePath) +#include "Peihob.h" +#include "EfiHobLib.h" +#include "DxeCore.h" + +#include EFI_GUID_DEFINITION (Hob) + + + +#define FVB_DEVICE_SIGNATURE EFI_SIGNATURE_32('_','F','V','B') + +typedef struct { + UINTN Base; + UINTN Length; +} LBA_CACHE; + +typedef struct { + MEMMAP_DEVICE_PATH MemMapDevPath; + EFI_DEVICE_PATH_PROTOCOL EndDevPath; +} FV_DEVICE_PATH; + + +typedef struct { + UINTN Signature; + EFI_HANDLE Handle; + FV_DEVICE_PATH DevicePath; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL FwVolBlockInstance; + UINTN NumBlocks; + LBA_CACHE *LbaCache; + UINT32 FvbAttributes; + EFI_PHYSICAL_ADDRESS BaseAddress; +} EFI_FW_VOL_BLOCK_DEVICE; + +#define FVB_DEVICE_FROM_THIS(a) \ + CR(a, EFI_FW_VOL_BLOCK_DEVICE, FwVolBlockInstance, FVB_DEVICE_SIGNATURE) + + + +EFI_STATUS +EFIAPI +FwVolBlockDriverInit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + This routine is the driver initialization entry point. It initializes the + libraries, consumes FV hobs and NT_NON_MM_FV environment variable and + produces instances of FW_VOL_BLOCK_PROTOCOL as appropriate. +Arguments: + ImageHandle - The image handle. + SystemTable - The system table. +Returns: + EFI_SUCCESS - Successfully initialized firmware volume block driver. +--*/ +; + + +EFI_STATUS +EFIAPI +FwVolBlockGetAttributes ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_FVB_ATTRIBUTES *Attributes + ) +/*++ + +Routine Description: + Retrieves Volume attributes. No polarity translations are done. + +Arguments: + This - Calling context + Attributes - output buffer which contains attributes + +Returns: + EFI_SUCCESS - The firmware volume attributes were returned. + +--*/ +; + + +EFI_STATUS +EFIAPI +FwVolBlockSetAttributes ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_FVB_ATTRIBUTES *Attributes + ) +/*++ + +Routine Description: + Modifies the current settings of the firmware volume according to the input parameter. + +Arguments: + This - Calling context + Attributes - input buffer which contains attributes + +Returns: + EFI_SUCCESS - The firmware volume attributes were returned. + EFI_INVALID_PARAMETER - The attributes requested are in conflict with the capabilities as + declared in the firmware volume header. + EFI_UNSUPPORTED - Not supported. +--*/ +; + + +EFI_STATUS +EFIAPI +FwVolBlockEraseBlock ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + ... + ) +/*++ + +Routine Description: + The EraseBlock() function erases one or more blocks as denoted by the +variable argument list. The entire parameter list of blocks must be verified +prior to erasing any blocks. If a block is requested that does not exist +within the associated firmware volume (it has a larger index than the last +block of the firmware volume), the EraseBlock() function must return +EFI_INVALID_PARAMETER without modifying the contents of the firmware volume. + +Arguments: + This - Calling context + ... - Starting LBA followed by Number of Lba to erase. a -1 to terminate + the list. + +Returns: + EFI_SUCCESS - The erase request was successfully completed. + EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state. + EFI_DEVICE_ERROR - The block device is not functioning correctly and could not be + written. The firmware device may have been partially erased. + EFI_INVALID_PARAMETER - One or more of the LBAs listed in the variable argument list do + EFI_UNSUPPORTED - Not supported. + +--*/ +; + + +EFI_STATUS +EFIAPI +FwVolBlockReadBlock ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +/*++ + +Routine Description: + Read the specified number of bytes from the block to the input buffer. + +Arguments: + This - Indicates the calling context. + Lba - The starting logical block index to read. + Offset - Offset into the block at which to begin reading. + NumBytes - Pointer to a UINT32. At entry, *NumBytes contains the + total size of the buffer. At exit, *NumBytes contains the + total number of bytes actually read. + Buffer - Pinter to a caller-allocated buffer that contains the destine + for the read. + +Returns: + EFI_SUCCESS - The firmware volume was read successfully. + EFI_BAD_BUFFER_SIZE - The read was attempted across an LBA boundary. + EFI_ACCESS_DENIED - Access denied. + EFI_DEVICE_ERROR - The block device is malfunctioning and could not be read. +--*/ +; + + +EFI_STATUS +EFIAPI +FwVolBlockWriteBlock ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +/*++ + +Routine Description: + Writes the specified number of bytes from the input buffer to the block. + +Arguments: + This - Indicates the calling context. + Lba - The starting logical block index to write to. + Offset - Offset into the block at which to begin writing. + NumBytes - Pointer to a UINT32. At entry, *NumBytes contains the + total size of the buffer. At exit, *NumBytes contains the + total number of bytes actually written. + Buffer - Pinter to a caller-allocated buffer that contains the source + for the write. + +Returns: + EFI_SUCCESS - The firmware volume was written successfully. + EFI_BAD_BUFFER_SIZE - The write was attempted across an LBA boundary. On output, + NumBytes contains the total number of bytes actually written. + EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state. + EFI_DEVICE_ERROR - The block device is malfunctioning and could not be written. + EFI_UNSUPPORTED - Not supported. +--*/ +; + + +EFI_STATUS +EFIAPI +FwVolBlockGetPhysicalAddress ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_PHYSICAL_ADDRESS *Address + ) +/*++ + +Routine Description: + Get Fvb's base address. + +Arguments: + This - Indicates the calling context. + Address - Fvb device base address. + +Returns: + EFI_SUCCESS - Successfully got Fvb's base address. + EFI_UNSUPPORTED - Not supported. +--*/ +; + + +EFI_STATUS +EFIAPI +FwVolBlockGetBlockSize ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + OUT UINTN *BlockSize, + OUT UINTN *NumberOfBlocks + ) +/*++ + +Routine Description: + Retrieves the size in bytes of a specific block within a firmware volume. + +Arguments: + This - Indicates the calling context. + Lba - Indicates the block for which to return the size. + BlockSize - Pointer to a caller-allocated UINTN in which the size of the + block is returned. + NumberOfBlocks - Pointer to a caller-allocated UINTN in which the number of + consecutive blocks starting with Lba is returned. All blocks + in this range have a size of BlockSize. +Returns: + EFI_SUCCESS - The firmware volume base address is returned. + EFI_INVALID_PARAMETER - The requested LBA is out of range. +--*/ +; + +EFI_STATUS +FwVolBlockDriverInit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + This routine is the driver initialization entry point. It initializes the + libraries, consumes FV hobs and NT_NON_MM_FV environment variable and + produces instances of FW_VOL_BLOCK_PROTOCOL as appropriate. +Arguments: + ImageHandle - The image handle. + SystemTable - The system table. +Returns: + Status code + +--*/ +; + +EFI_STATUS +ProduceFVBProtocolOnBuffer ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN EFI_HANDLE ParentHandle, + OUT EFI_HANDLE *FvProtocolHandle OPTIONAL + ) +/*++ + +Routine Description: + This routine produces a firmware volume block protocol on a given + buffer. + +Arguments: + BaseAddress - base address of the firmware volume image + Length - length of the firmware volume image + ParentHandle - handle of parent firmware volume, if this + image came from an FV image file in another + firmware volume (ala capsules) + FvProtocolHandle - Firmware volume block protocol produced. + +Returns: + EFI_VOLUME_CORRUPTED - Volume corrupted. + EFI_OUT_OF_RESOURCES - No enough buffer to be allocated. + EFI_SUCCESS - Successfully produced a FVB protocol on given buffer. + +--*/ +; + +#endif diff --git a/EDK/Foundation/Core/Dxe/Gcd/gcd.c b/EDK/Foundation/Core/Dxe/Gcd/gcd.c new file mode 100644 index 0000000..586826b --- /dev/null +++ b/EDK/Foundation/Core/Dxe/Gcd/gcd.c @@ -0,0 +1,2509 @@ +/*++ + +Copyright (c) 2004 - 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + gcd.c + +Abstract: + + The file contains the GCD related services in the EFI Boot Services Table. + The GCD services are used to manage the memory and I/O regions that + are accessible to the CPU that is executing the DXE core. + +--*/ + +#include "gcd.h" + +#define MINIMUM_INITIAL_MEMORY_SIZE 0x10000 + +#define MEMORY_ATTRIBUTE_MASK (EFI_RESOURCE_ATTRIBUTE_PRESENT | \ + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \ + EFI_RESOURCE_ATTRIBUTE_TESTED | \ + EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED | \ + EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED | \ + EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED | \ + EFI_RESOURCE_ATTRIBUTE_16_BIT_IO | \ + EFI_RESOURCE_ATTRIBUTE_32_BIT_IO | \ + EFI_RESOURCE_ATTRIBUTE_64_BIT_IO ) + +#define TESTED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | \ + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \ + EFI_RESOURCE_ATTRIBUTE_TESTED ) + +#define INITIALIZED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | \ + EFI_RESOURCE_ATTRIBUTE_INITIALIZED ) + +#define PRESENT_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT) + +#define INVALID_CPU_ARCH_ATTRIBUTES 0xffffffff + +// +// Module Variables +// +EFI_LOCK mGcdMemorySpaceLock = EFI_INITIALIZE_LOCK_VARIABLE (EFI_TPL_NOTIFY); +EFI_LOCK mGcdIoSpaceLock = EFI_INITIALIZE_LOCK_VARIABLE (EFI_TPL_NOTIFY); +EFI_LIST_ENTRY mGcdMemorySpaceMap = INITIALIZE_LIST_HEAD_VARIABLE (mGcdMemorySpaceMap); +EFI_LIST_ENTRY mGcdIoSpaceMap = INITIALIZE_LIST_HEAD_VARIABLE (mGcdIoSpaceMap); + +EFI_GCD_MAP_ENTRY mGcdMemorySpaceMapEntryTemplate = { + EFI_GCD_MAP_SIGNATURE, + { NULL, NULL }, + 0, + 0, + 0, + 0, + EfiGcdMemoryTypeNonExistent, + 0, + NULL, + NULL +}; + +EFI_GCD_MAP_ENTRY mGcdIoSpaceMapEntryTemplate = { + EFI_GCD_MAP_SIGNATURE, + { NULL, NULL }, + 0, + 0, + 0, + 0, + 0, + EfiGcdIoTypeNonExistent, + NULL, + NULL +}; + +GCD_ATTRIBUTE_CONVERSION_ENTRY mAttributeConversionTable[] = { + { EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE, EFI_MEMORY_UC, TRUE }, + { EFI_RESOURCE_ATTRIBUTE_UNCACHED_EXPORTED, EFI_MEMORY_UCE, TRUE }, + { EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE, EFI_MEMORY_WC, TRUE }, + { EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE, EFI_MEMORY_WT, TRUE }, + { EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE, EFI_MEMORY_WB, TRUE }, + { EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED, EFI_MEMORY_RP, TRUE }, + { EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED, EFI_MEMORY_WP, TRUE }, + { EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED, EFI_MEMORY_XP, TRUE }, + { EFI_RESOURCE_ATTRIBUTE_PRESENT, EFI_MEMORY_PRESENT, FALSE }, + { EFI_RESOURCE_ATTRIBUTE_INITIALIZED, EFI_MEMORY_INITIALIZED, FALSE }, + { EFI_RESOURCE_ATTRIBUTE_TESTED, EFI_MEMORY_TESTED, FALSE }, + { 0, 0, FALSE } +}; + +VOID +CoreAcquireGcdMemoryLock ( + VOID + ) +/*++ + +Routine Description: + Acquire memory lock on mGcdMemorySpaceLock + +Arguments: + None + +Returns: + None + +--*/ +{ + CoreAcquireLock (&mGcdMemorySpaceLock); +} + + +VOID +CoreReleaseGcdMemoryLock ( + VOID + ) +/*++ + +Routine Description: + Release memory lock on mGcdMemorySpaceLock + +Arguments: + None + +Returns: + None + +--*/ +{ + CoreReleaseLock (&mGcdMemorySpaceLock); +} + + + +VOID +CoreAcquireGcdIoLock ( + VOID + ) +/*++ + +Routine Description: + Acquire memory lock on mGcdIoSpaceLock + +Arguments: + None + +Returns: + None + +--*/ +{ + CoreAcquireLock (&mGcdIoSpaceLock); +} + + +VOID +CoreReleaseGcdIoLock ( + VOID + ) +/*++ + +Routine Description: + Release memory lock on mGcdIoSpaceLock + +Arguments: + None + +Returns: + None + +--*/ +{ + CoreReleaseLock (&mGcdIoSpaceLock); +} + + + +// +// GCD Initialization Worker Functions +// +UINT64 +AlignValue ( + IN UINT64 Value, + IN UINTN Alignment, + IN BOOLEAN RoundUp + ) +/*++ + +Routine Description: + + Aligns a value to the specified boundary. + +Arguments: + + Value - 64 bit value to align + Alignment - Log base 2 of the boundary to align Value to + RoundUp - TRUE if Value is to be rounded up to the nearest aligned boundary. + FALSE is Value is to be rounded down to the nearest aligned boundary. + +Returns: + + A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment. + +--*/ +{ + UINT64 AlignmentMask; + + AlignmentMask = LShiftU64 (1, Alignment) - 1; + if (RoundUp) { + Value += AlignmentMask; + } + return Value & (~AlignmentMask); +} + +UINT64 +PageAlignAddress ( + IN UINT64 Value + ) +/*++ + +Routine Description: + + Aligns address to the page boundary. + +Arguments: + + Value - 64 bit address to align + +Returns: + + A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment. + +--*/ +{ + return AlignValue (Value, EFI_PAGE_SHIFT, TRUE); +} + +UINT64 +PageAlignLength ( + IN UINT64 Value + ) +/*++ + +Routine Description: + + Aligns length to the page boundary. + +Arguments: + + Value - 64 bit length to align + +Returns: + + A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment. + +--*/ +{ + return AlignValue (Value, EFI_PAGE_SHIFT, FALSE); +} + +// +// GCD Memory Space Worker Functions +// +EFI_STATUS +CoreAllocateGcdMapEntry ( + IN OUT EFI_GCD_MAP_ENTRY **TopEntry, + IN OUT EFI_GCD_MAP_ENTRY **BottomEntry + ) +/*++ + +Routine Description: + + Allocate pool for two entries. + +Arguments: + + TopEntry - An entry of GCD map + BottomEntry - An entry of GCD map + +Returns: + + EFI_OUT_OF_RESOURCES - No enough buffer to be allocated. + EFI_SUCCESS - Both entries successfully allocated. + +--*/ +{ + *TopEntry = CoreAllocateZeroBootServicesPool (sizeof (EFI_GCD_MAP_ENTRY)); + if (*TopEntry == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + *BottomEntry = CoreAllocateZeroBootServicesPool (sizeof (EFI_GCD_MAP_ENTRY)); + if (*BottomEntry == NULL) { + CoreFreePool (*TopEntry); + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +CoreInsertGcdMapEntry ( + IN EFI_LIST_ENTRY *Link, + IN EFI_GCD_MAP_ENTRY *Entry, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN EFI_GCD_MAP_ENTRY *TopEntry, + IN EFI_GCD_MAP_ENTRY *BottomEntry + ) +/*++ + +Routine Description: + + Internal function. Inserts a new descriptor into a sorted list + +Arguments: + + Link - The linked list to insert the range BaseAddress and Length into + + Entry - A pointer to the entry that is inserted + + BaseAddress - The base address of the new range + + Length - The length of the new range in bytes + + TopEntry - Top pad entry to insert if needed. + + BottomEntry - Bottom pad entry to insert if needed. + +Returns: + + EFI_SUCCESS - The new range was inserted into the linked list + +--*/ +{ + ASSERT (Length != 0); + ASSERT (TopEntry->Signature == 0); + ASSERT (BottomEntry->Signature == 0); + + if (BaseAddress > Entry->BaseAddress) { + EfiCommonLibCopyMem (BottomEntry, Entry, sizeof (EFI_GCD_MAP_ENTRY)); + Entry->BaseAddress = BaseAddress; + BottomEntry->EndAddress = BaseAddress - 1; + InsertTailList (Link, &BottomEntry->Link); + } + + if ((BaseAddress + Length - 1) < Entry->EndAddress) { + EfiCommonLibCopyMem (TopEntry, Entry, sizeof (EFI_GCD_MAP_ENTRY)); + TopEntry->BaseAddress = BaseAddress + Length; + Entry->EndAddress = BaseAddress + Length - 1; + InsertHeadList (Link, &TopEntry->Link); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +CoreMergeGcdMapEntry ( + IN EFI_LIST_ENTRY *Link, + IN BOOLEAN Forward, + IN EFI_LIST_ENTRY *Map + ) +/*++ + +Routine Description: + + Merge the Gcd region specified by Link and its adjacent entry + +Arguments: + + Link - Specify the entry to be merged (with its adjacent entry). + + Forward - Direction (forward or backward). + + Map - Boundary. + +Returns: + + EFI_SUCCESS - Successfully returned. + + EFI_UNSUPPORTED - These adjacent regions could not merge. + +--*/ +{ + EFI_LIST_ENTRY *AdjacentLink; + EFI_GCD_MAP_ENTRY *Entry; + EFI_GCD_MAP_ENTRY *AdjacentEntry; + + // + // Get adjacent entry + // + if (Forward) { + AdjacentLink = Link->ForwardLink; + } else { + AdjacentLink = Link->BackLink; + } + + // + // If AdjacentLink is the head of the list, then no merge can be performed + // + if (AdjacentLink == Map) { + return EFI_SUCCESS; + } + + Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE); + AdjacentEntry = CR (AdjacentLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE); + + if (Entry->Capabilities != AdjacentEntry->Capabilities) { + return EFI_UNSUPPORTED; + } + if (Entry->Attributes != AdjacentEntry->Attributes) { + return EFI_UNSUPPORTED; + } + if (Entry->GcdMemoryType != AdjacentEntry->GcdMemoryType) { + return EFI_UNSUPPORTED; + } + if (Entry->GcdIoType != AdjacentEntry->GcdIoType) { + return EFI_UNSUPPORTED; + } + if (Entry->ImageHandle != AdjacentEntry->ImageHandle) { + return EFI_UNSUPPORTED; + } + if (Entry->DeviceHandle != AdjacentEntry->DeviceHandle) { + return EFI_UNSUPPORTED; + } + + if (Forward) { + Entry->EndAddress = AdjacentEntry->EndAddress; + } else { + Entry->BaseAddress = AdjacentEntry->BaseAddress; + } + RemoveEntryList (AdjacentLink); + CoreFreePool (AdjacentEntry); + + return EFI_SUCCESS; +} + +EFI_STATUS +CoreCleanupGcdMapEntry ( + IN EFI_GCD_MAP_ENTRY *TopEntry, + IN EFI_GCD_MAP_ENTRY *BottomEntry, + IN EFI_LIST_ENTRY *StartLink, + IN EFI_LIST_ENTRY *EndLink, + IN EFI_LIST_ENTRY *Map + ) +/*++ + +Routine Description: + + Merge adjacent entries on total chain. + +Arguments: + + TopEntry - Top entry of GCD map. + + BottomEntry - Bottom entry of GCD map. + + StartLink - Start link of the list for this loop. + + EndLink - End link of the list for this loop. + + Map - Boundary. + +Returns: + + EFI_SUCCESS - GCD map successfully cleaned up. + +--*/ +{ + EFI_LIST_ENTRY *Link; + + if (TopEntry->Signature == 0) { + CoreFreePool (TopEntry); + } + if (BottomEntry->Signature == 0) { + CoreFreePool (BottomEntry); + } + + Link = StartLink; + while (Link != EndLink->ForwardLink) { + CoreMergeGcdMapEntry (Link, FALSE, Map); + Link = Link->ForwardLink; + } + CoreMergeGcdMapEntry (EndLink, TRUE, Map); + + return EFI_SUCCESS; +} + +EFI_STATUS +CoreSearchGcdMapEntry ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + OUT EFI_LIST_ENTRY **StartLink, + OUT EFI_LIST_ENTRY **EndLink, + IN EFI_LIST_ENTRY *Map + ) +/*++ + +Routine Description: + + Search a segment of memory space in GCD map. The result is a range of GCD entry list. + +Arguments: + + BaseAddress - The start address of the segment. + + Length - The length of the segment. + + StartLink - The first GCD entry involves this segment of memory space. + + EndLink - The first GCD entry involves this segment of memory space. + + Map - Points to the start entry to search. + +Returns: + + EFI_SUCCESS - Successfully found the entry. + + EFI_NOT_FOUND - Not found. + +--*/ +{ + EFI_LIST_ENTRY *Link; + EFI_GCD_MAP_ENTRY *Entry; + + ASSERT (Length != 0); + + *StartLink = NULL; + *EndLink = NULL; + + Link = Map->ForwardLink; + while (Link != Map) { + Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE); + if (BaseAddress >= Entry->BaseAddress && BaseAddress <= Entry->EndAddress) { + *StartLink = Link; + } + if (*StartLink != NULL) { + if ((BaseAddress + Length - 1) >= Entry->BaseAddress && + (BaseAddress + Length - 1) <= Entry->EndAddress ) { + *EndLink = Link; + return EFI_SUCCESS; + } + } + Link = Link->ForwardLink; + } + return EFI_NOT_FOUND; +} + +UINTN +CoreCountGcdMapEntry ( + IN EFI_LIST_ENTRY *Map + ) +/*++ + +Routine Description: + + Count the amount of GCD map entries. + +Arguments: + + Map - Points to the start entry to do the count loop. + +Returns: + + The count. + +--*/ +{ + UINTN Count; + EFI_LIST_ENTRY *Link; + + Count = 0; + Link = Map->ForwardLink; + while (Link != Map) { + Count++; + Link = Link->ForwardLink; + } + return Count; +} + + + +UINT64 +ConverToCpuArchAttributes ( + UINT64 Attributes + ) +/*++ + +Routine Description: + + Return the memory attribute specified by Attributes + +Arguments: + + Attributes - A num with some attribute bits on. + +Returns: + + The enum value of memory attribute. + +--*/ +{ + if ( (Attributes & EFI_MEMORY_UC) == EFI_MEMORY_UC) { + return EFI_MEMORY_UC; + } + + if ( (Attributes & EFI_MEMORY_WC ) == EFI_MEMORY_WC) { + return EFI_MEMORY_WC; + } + + if ( (Attributes & EFI_MEMORY_WT ) == EFI_MEMORY_WT) { + return EFI_MEMORY_WT; + } + + if ( (Attributes & EFI_MEMORY_WB) == EFI_MEMORY_WB) { + return EFI_MEMORY_WB; + } + + if ( (Attributes & EFI_MEMORY_WP) == EFI_MEMORY_WP) { + return EFI_MEMORY_WP; + } + + return INVALID_CPU_ARCH_ATTRIBUTES; + +} + + +EFI_STATUS +CoreConvertSpace ( + IN UINTN Operation, + IN EFI_GCD_MEMORY_TYPE GcdMemoryType, + IN EFI_GCD_IO_TYPE GcdIoType, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Capabilities, + IN UINT64 Attributes + ) +/*++ + +Routine Description: + + Do operation on a segment of memory space specified (add, free, remove, change attribute ...). + +Arguments: + + Operation - The type of the operation + + GcdMemoryType - Additional information for the operation + + GcdIoType - Additional information for the operation + + BaseAddress - Start address of the segment + + Length - length of the segment + + Capabilities - The alterable attributes of a newly added entry + + Attributes - The attributes needs to be set + +Returns: + + EFI_INVALID_PARAMETER - Length is 0 or address (length) not aligned when setting attribute. + + EFI_SUCCESS - Action successfully done. + + EFI_UNSUPPORTED - Could not find the proper descriptor on this segment or + set an upsupported attribute. + + EFI_ACCESS_DENIED - Operate on an space non-exist or is used for an image. + + EFI_NOT_FOUND - Free a non-using space or remove a non-exist space, and so on. + + EFI_OUT_OF_RESOURCES - No buffer could be allocated. + +Returns: + +--*/ +{ + EFI_STATUS Status; + EFI_LIST_ENTRY *Map; + EFI_LIST_ENTRY *Link; + EFI_GCD_MAP_ENTRY *Entry; + EFI_GCD_MAP_ENTRY *TopEntry; + EFI_GCD_MAP_ENTRY *BottomEntry; + EFI_LIST_ENTRY *StartLink; + EFI_LIST_ENTRY *EndLink; + + EFI_CPU_ARCH_PROTOCOL *CpuArch; + UINT64 CpuArchAttributes; + + if (Length == 0) { + return EFI_INVALID_PARAMETER; + } + + Map = NULL; + if (Operation & GCD_MEMORY_SPACE_OPERATION) { + CoreAcquireGcdMemoryLock (); + Map = &mGcdMemorySpaceMap; + } + if (Operation & GCD_IO_SPACE_OPERATION) { + CoreAcquireGcdIoLock (); + Map = &mGcdIoSpaceMap; + } + + if (Map == NULL) { + // + // Fail if 'Map' doesn't point to a valid address + // + Status = EFI_UNSUPPORTED; + + goto Done; + } + + // + // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length + // + Status = CoreSearchGcdMapEntry (BaseAddress, Length, &StartLink, &EndLink, Map); + if (EFI_ERROR (Status) || (StartLink == NULL) || (EndLink == NULL)) { + Status = EFI_UNSUPPORTED; + + goto Done; + } + + // + // Verify that the list of descriptors are unallocated non-existent memory. + // + Link = StartLink; + while (Link != EndLink->ForwardLink) { + Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE); + switch (Operation) { + // + // Add operations + // + case GCD_ADD_MEMORY_OPERATION: + if (Entry->GcdMemoryType != EfiGcdMemoryTypeNonExistent || + Entry->ImageHandle != NULL ) { + Status = EFI_ACCESS_DENIED; + goto Done; + } + break; + case GCD_ADD_IO_OPERATION: + if (Entry->GcdIoType != EfiGcdIoTypeNonExistent || + Entry->ImageHandle != NULL ) { + Status = EFI_ACCESS_DENIED; + goto Done; + } + break; + // + // Free operations + // + case GCD_FREE_MEMORY_OPERATION: + case GCD_FREE_IO_OPERATION: + if (Entry->ImageHandle == NULL) { + Status = EFI_NOT_FOUND; + goto Done; + } + break; + // + // Remove operations + // + case GCD_REMOVE_MEMORY_OPERATION: + if (Entry->GcdMemoryType == EfiGcdMemoryTypeNonExistent) { + Status = EFI_NOT_FOUND; + goto Done; + } + if (Entry->ImageHandle != NULL) { + Status = EFI_ACCESS_DENIED; + goto Done; + } + break; + case GCD_REMOVE_IO_OPERATION: + if (Entry->GcdIoType == EfiGcdIoTypeNonExistent) { + Status = EFI_NOT_FOUND; + goto Done; + } + if (Entry->ImageHandle != NULL) { + Status = EFI_ACCESS_DENIED; + goto Done; + } + break; + // + // Set attribute operations + // + case GCD_SET_ATTRIBUTES_MEMORY_OPERATION: + if (Attributes & EFI_MEMORY_RUNTIME) { + if ((BaseAddress & EFI_PAGE_MASK) != 0 || (Length & EFI_PAGE_MASK) != 0) { + Status = EFI_INVALID_PARAMETER; + + goto Done; + } + } + if ((Entry->Capabilities & Attributes) != Attributes) { + Status = EFI_UNSUPPORTED; + goto Done; + } + break; + } + Link = Link->ForwardLink; + } + + // + // Allocate work space to perform this operation + // + Status = CoreAllocateGcdMapEntry (&TopEntry, &BottomEntry); + if (EFI_ERROR (Status) || (TopEntry == NULL) || (BottomEntry == NULL)) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + // + // + // + if (Operation == GCD_SET_ATTRIBUTES_MEMORY_OPERATION) { + // + // Call CPU Arch Protocol to attempt to set attributes on the range + // + CpuArchAttributes = ConverToCpuArchAttributes (Attributes); + if ( CpuArchAttributes != INVALID_CPU_ARCH_ATTRIBUTES ) { + Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, &CpuArch); + if (EFI_ERROR (Status)) { + Status = EFI_ACCESS_DENIED; + goto Done; + } + + Status = CpuArch->SetMemoryAttributes ( + CpuArch, + BaseAddress, + Length, + CpuArchAttributes + ); + if (EFI_ERROR (Status)) { + goto Done; + } + } + + } + + // + // Convert/Insert the list of descriptors from StartLink to EndLink + // + Link = StartLink; + while (Link != EndLink->ForwardLink) { + Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE); + CoreInsertGcdMapEntry (Link, Entry, BaseAddress, Length, TopEntry, BottomEntry); + switch (Operation) { + // + // Add operations + // + case GCD_ADD_MEMORY_OPERATION: + Entry->GcdMemoryType = GcdMemoryType; + if (GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) { + Entry->Capabilities = Capabilities | EFI_MEMORY_RUNTIME | EFI_MEMORY_PORT_IO; + } else { + Entry->Capabilities = Capabilities | EFI_MEMORY_RUNTIME; + } + break; + case GCD_ADD_IO_OPERATION: + Entry->GcdIoType = GcdIoType; + break; + // + // Free operations + // + case GCD_FREE_MEMORY_OPERATION: + case GCD_FREE_IO_OPERATION: + Entry->ImageHandle = NULL; + Entry->DeviceHandle = NULL; + break; + // + // Remove operations + // + case GCD_REMOVE_MEMORY_OPERATION: + Entry->GcdMemoryType = EfiGcdMemoryTypeNonExistent; + Entry->Capabilities = 0; + break; + case GCD_REMOVE_IO_OPERATION: + Entry->GcdIoType = EfiGcdIoTypeNonExistent; + break; + // + // Set attribute operations + // + case GCD_SET_ATTRIBUTES_MEMORY_OPERATION: + Entry->Attributes = Attributes; + break; + } + Link = Link->ForwardLink; + } + + // + // Cleanup + // + Status = CoreCleanupGcdMapEntry (TopEntry, BottomEntry, StartLink, EndLink, Map); + +Done: + if (Operation & GCD_MEMORY_SPACE_OPERATION) { + CoreReleaseGcdMemoryLock (); + } + if (Operation & GCD_IO_SPACE_OPERATION) { + CoreReleaseGcdIoLock (); + } + + return Status; +} + +EFI_STATUS +CoreAllocateSpaceCheckEntry ( + IN UINTN Operation, + IN EFI_GCD_MAP_ENTRY *Entry, + IN EFI_GCD_MEMORY_TYPE GcdMemoryType, + IN EFI_GCD_IO_TYPE GcdIoType + ) +/*++ + +Routine Description: + + Check whether an entry could be used to allocate space. + +Arguments: + + Operation - Allocate memory or IO + + Entry - The entry to be tested + + GcdMemoryType - The desired memory type + + GcdIoType - The desired IO type + +Returns: + + EFI_NOT_FOUND - The memory type does not match or there's an image handle on the entry. + + EFI_UNSUPPORTED - The operation unsupported. + + EFI_SUCCESS - It's ok for this entry to be used to allocate space. + +--*/ +{ + if (Entry->ImageHandle != NULL) { + return EFI_NOT_FOUND; + } + switch (Operation) { + case GCD_ALLOCATE_MEMORY_OPERATION: + if (Entry->GcdMemoryType != GcdMemoryType) { + return EFI_NOT_FOUND; + } + break; + case GCD_ALLOCATE_IO_OPERATION: + if (Entry->GcdIoType != GcdIoType) { + return EFI_NOT_FOUND; + } + break; + default: + return EFI_UNSUPPORTED; + } + return EFI_SUCCESS; +} + +EFI_STATUS +CoreAllocateSpace ( + IN UINTN Operation, + IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType, + IN EFI_GCD_MEMORY_TYPE GcdMemoryType, + IN EFI_GCD_IO_TYPE GcdIoType, + IN UINTN Alignment, + IN UINT64 Length, + IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress, + IN EFI_HANDLE ImageHandle, + IN EFI_HANDLE DeviceHandle OPTIONAL + ) +/*++ + +Routine Description: + + Allocate space on specified address and length. + +Arguments: + + Operation - The type of operation (memory or IO) + GcdAllocateType - The type of allocate operation + GcdMemoryType - The desired memory type + GcdIoType - The desired IO type + Alignment - Align with 2^Alignment + Length - Length to allocate + BaseAddress - Base address to allocate + ImageHandle - The image handle consume the allocated space. + DeviceHandle - The device handle consume the allocated space. + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter. + EFI_NOT_FOUND - No descriptor for the desired space exists. + EFI_SUCCESS - Space successfully allocated. + +--*/ +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS AlignmentMask; + EFI_PHYSICAL_ADDRESS MaxAddress; + EFI_LIST_ENTRY *Map; + EFI_LIST_ENTRY *Link; + EFI_LIST_ENTRY *SubLink; + EFI_GCD_MAP_ENTRY *Entry; + EFI_GCD_MAP_ENTRY *TopEntry; + EFI_GCD_MAP_ENTRY *BottomEntry; + EFI_LIST_ENTRY *StartLink; + EFI_LIST_ENTRY *EndLink; + BOOLEAN Found; + + // + // Make sure parameters are valid + // + if (GcdAllocateType < 0 || GcdAllocateType >= EfiGcdMaxAllocateType) { + return EFI_INVALID_PARAMETER; + } + if (GcdMemoryType < 0 || GcdMemoryType >= EfiGcdMemoryTypeMaximum) { + return EFI_INVALID_PARAMETER; + } + if (GcdIoType < 0 || GcdIoType >= EfiGcdIoTypeMaximum) { + return EFI_INVALID_PARAMETER; + } + if (BaseAddress == NULL) { + return EFI_INVALID_PARAMETER; + } + if (ImageHandle == NULL) { + return EFI_INVALID_PARAMETER; + } + if (Alignment >= 64) { + return EFI_NOT_FOUND; + } + if (Length == 0) { + return EFI_INVALID_PARAMETER; + } + + Map = NULL; + if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) { + CoreAcquireGcdMemoryLock (); + Map = &mGcdMemorySpaceMap; + } + if ((Operation & GCD_IO_SPACE_OPERATION) != 0) { + CoreAcquireGcdIoLock (); + Map = &mGcdIoSpaceMap; + } + + if (Map == NULL) { + // + // Fail if 'Map' doesn't point to a valid address + // + Status = EFI_UNSUPPORTED; + goto Done; + } + + Found = FALSE; + StartLink = NULL; + EndLink = NULL; + // + // Compute alignment bit mask + // + AlignmentMask = LShiftU64 (1, Alignment) - 1; + + if (GcdAllocateType == EfiGcdAllocateAddress) { + // + // Verify that the BaseAddress passed in is aligned correctly + // + if ((*BaseAddress & AlignmentMask) != 0) { + Status = EFI_NOT_FOUND; + goto Done; + } + + // + // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length + // + Status = CoreSearchGcdMapEntry (*BaseAddress, Length, &StartLink, &EndLink, Map); + if (EFI_ERROR (Status) || (StartLink == NULL) || (EndLink == NULL)) { + Status = EFI_NOT_FOUND; + goto Done; + } + + // + // Verify that the list of descriptors are unallocated memory matching GcdMemoryType. + // + Link = StartLink; + while (Link != EndLink->ForwardLink) { + Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE); + Link = Link->ForwardLink; + Status = CoreAllocateSpaceCheckEntry (Operation, Entry, GcdMemoryType, GcdIoType); + if (EFI_ERROR (Status)) { + goto Done; + } + } + Found = TRUE; + } else { + + Entry = CR (Map->BackLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE); + + // + // Compute the maximum address to use in the search algorithm + // + if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchBottomUp || + GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown) { + MaxAddress = *BaseAddress; + } else { + MaxAddress = Entry->EndAddress; + } + + // + // Verify that the list of descriptors are unallocated memory matching GcdMemoryType. + // + if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown || + GcdAllocateType == EfiGcdAllocateAnySearchTopDown) { + Link = Map->BackLink; + } else { + Link = Map->ForwardLink; + } + while (Link != Map) { + Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE); + + if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown || + GcdAllocateType == EfiGcdAllocateAnySearchTopDown) { + Link = Link->BackLink; + } else { + Link = Link->ForwardLink; + } + + Status = CoreAllocateSpaceCheckEntry (Operation, Entry, GcdMemoryType, GcdIoType); + if (EFI_ERROR (Status)) { + continue; + } + + if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown || + GcdAllocateType == EfiGcdAllocateAnySearchTopDown) { + if (Entry->BaseAddress > MaxAddress) { + continue; + } + if (Length > (Entry->EndAddress + 1)) { + Status = EFI_NOT_FOUND; + goto Done; + } + if (Entry->EndAddress > MaxAddress) { + *BaseAddress = MaxAddress; + } else { + *BaseAddress = Entry->EndAddress; + } + *BaseAddress = (*BaseAddress + 1 - Length) & (~AlignmentMask); + } else { + *BaseAddress = (Entry->BaseAddress + AlignmentMask) & (~AlignmentMask); + if ((*BaseAddress + Length - 1) > MaxAddress) { + Status = EFI_NOT_FOUND; + goto Done; + } + } + + // + // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length + // + Status = CoreSearchGcdMapEntry (*BaseAddress, Length, &StartLink, &EndLink, Map); + if (EFI_ERROR (Status) || (StartLink == NULL) || (EndLink == NULL)) { + Status = EFI_NOT_FOUND; + goto Done; + } + + Link = StartLink; + // + // Verify that the list of descriptors are unallocated memory matching GcdMemoryType. + // + Found = TRUE; + SubLink = StartLink; + while (SubLink != EndLink->ForwardLink) { + Entry = CR (SubLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE); + Status = CoreAllocateSpaceCheckEntry (Operation, Entry, GcdMemoryType, GcdIoType); + if (EFI_ERROR (Status)) { + Link = SubLink; + Found = FALSE; + break; + } + SubLink = SubLink->ForwardLink; + } + if (Found) { + break; + } + } + } + if (!Found) { + Status = EFI_NOT_FOUND; + goto Done; + } + + // + // Allocate work space to perform this operation + // + Status = CoreAllocateGcdMapEntry (&TopEntry, &BottomEntry); + if (EFI_ERROR (Status) || (TopEntry == NULL) || (BottomEntry == NULL)) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + // + // Convert/Insert the list of descriptors from StartLink to EndLink + // + Link = StartLink; + while (Link != EndLink->ForwardLink) { + Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE); + CoreInsertGcdMapEntry (Link, Entry, *BaseAddress, Length, TopEntry, BottomEntry); + Entry->ImageHandle = ImageHandle; + Entry->DeviceHandle = DeviceHandle; + Link = Link->ForwardLink; + } + + // + // Cleanup + // + Status = CoreCleanupGcdMapEntry (TopEntry, BottomEntry, StartLink, EndLink, Map); + +Done: + if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) { + CoreReleaseGcdMemoryLock (); + } + if ((Operation & GCD_IO_SPACE_OPERATION) != 0) { + CoreReleaseGcdIoLock (); + } + + return Status; +} + + +EFI_STATUS +CoreInternalAddMemorySpace ( + IN EFI_GCD_MEMORY_TYPE GcdMemoryType, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Capabilities + ) +/*++ + +Routine Description: + + Add a segment of memory to GCD map. + +Arguments: + + GcdMemoryType - Memory type of the segment. + + BaseAddress - Base address of the segment. + + Length - Length of the segment. + + Capabilities - alterable attributes of the segment. + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameters. + + EFI_SUCCESS - Successfully add a segment of memory space. + +--*/ +{ + // + // Make sure parameters are valid + // + if (GcdMemoryType <= EfiGcdMemoryTypeNonExistent || GcdMemoryType >= EfiGcdMemoryTypeMaximum) { + return EFI_INVALID_PARAMETER; + } + + return CoreConvertSpace (GCD_ADD_MEMORY_OPERATION, GcdMemoryType, 0, BaseAddress, Length, Capabilities, 0); +} + +// +// GCD Core Services +// +EFI_STATUS +CoreAllocateMemorySpace ( + IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType, + IN EFI_GCD_MEMORY_TYPE GcdMemoryType, + IN UINTN Alignment, + IN UINT64 Length, + IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress, + IN EFI_HANDLE ImageHandle, + IN EFI_HANDLE DeviceHandle OPTIONAL + ) +/*++ + +Routine Description: + + Allocates nonexistent memory, reserved memory, system memory, or memorymapped +I/O resources from the global coherency domain of the processor. + +Arguments: + + GcdAllocateType - The type of allocate operation + + GcdMemoryType - The desired memory type + + Alignment - Align with 2^Alignment + + Length - Length to allocate + + BaseAddress - Base address to allocate + + ImageHandle - The image handle consume the allocated space. + + DeviceHandle - The device handle consume the allocated space. + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter. + + EFI_NOT_FOUND - No descriptor contains the desired space. + + EFI_SUCCESS - Memory space successfully allocated. + +--*/ +{ + return CoreAllocateSpace ( + GCD_ALLOCATE_MEMORY_OPERATION, + GcdAllocateType, + GcdMemoryType, + 0, + Alignment, + Length, + BaseAddress, + ImageHandle, + DeviceHandle + ); +} + +EFI_STATUS +CoreAddMemorySpace ( + IN EFI_GCD_MEMORY_TYPE GcdMemoryType, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Capabilities + ) +/*++ + +Routine Description: + + Adds reserved memory, system memory, or memory-mapped I/O resources to the +global coherency domain of the processor. + +Arguments: + + GcdMemoryType - Memory type of the memory space. + + BaseAddress - Base address of the memory space. + + Length - Length of the memory space. + + Capabilities - alterable attributes of the memory space. + +Returns: + + EFI_SUCCESS - Merged this memory space into GCD map. + +--*/ +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS PageBaseAddress; + UINT64 PageLength; + + Status = CoreInternalAddMemorySpace (GcdMemoryType, BaseAddress, Length, Capabilities); + + if (!EFI_ERROR (Status) && GcdMemoryType == EfiGcdMemoryTypeSystemMemory) { + + PageBaseAddress = PageAlignLength (BaseAddress); + PageLength = PageAlignLength (BaseAddress + Length - PageBaseAddress); + + Status = CoreAllocateMemorySpace ( + EfiGcdAllocateAddress, + GcdMemoryType, + EFI_PAGE_SHIFT, + PageLength, + &PageBaseAddress, + gDxeCoreImageHandle, + NULL + ); + + if (!EFI_ERROR (Status)) { + CoreAddMemoryDescriptor ( + EfiConventionalMemory, + PageBaseAddress, + RShiftU64 (PageLength, EFI_PAGE_SHIFT), + Capabilities + ); + } else { + for (; PageLength != 0; PageLength -= EFI_PAGE_SIZE, PageBaseAddress += EFI_PAGE_SIZE) { + Status = CoreAllocateMemorySpace ( + EfiGcdAllocateAddress, + GcdMemoryType, + EFI_PAGE_SHIFT, + EFI_PAGE_SIZE, + &PageBaseAddress, + gDxeCoreImageHandle, + NULL + ); + + if (!EFI_ERROR (Status)) { + CoreAddMemoryDescriptor ( + EfiConventionalMemory, + PageBaseAddress, + 1, + Capabilities + ); + } + } + } + } + return Status; +} + +EFI_STATUS +CoreFreeMemorySpace ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +/*++ + +Routine Description: + + Frees nonexistent memory, reserved memory, system memory, or memory-mapped +I/O resources from the global coherency domain of the processor. + +Arguments: + + BaseAddress - Base address of the memory space. + + Length - Length of the memory space. + +Returns: + + EFI_SUCCESS - Space successfully freed. + +--*/ +{ + return CoreConvertSpace (GCD_FREE_MEMORY_OPERATION, 0, 0, BaseAddress, Length, 0, 0); +} + +EFI_STATUS +CoreRemoveMemorySpace ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +/*++ + +Routine Description: + + Removes reserved memory, system memory, or memory-mapped I/O resources from +the global coherency domain of the processor. + +Arguments: + + BaseAddress - Base address of the memory space. + + Length - Length of the memory space. + +Returns: + + EFI_SUCCESS - Successfully remove a segment of memory space. + +--*/ +{ + return CoreConvertSpace (GCD_REMOVE_MEMORY_OPERATION, 0, 0, BaseAddress, Length, 0, 0); +} + +VOID +BuildMemoryDescriptor ( + IN OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor, + IN EFI_GCD_MAP_ENTRY *Entry + ) +/*++ + +Routine Description: + + Build a memory descriptor according to an entry. + +Arguments: + + Descriptor - The descriptor to be built + + Entry - According to this entry + +Returns: + + None + +--*/ +{ + Descriptor->BaseAddress = Entry->BaseAddress; + Descriptor->Length = Entry->EndAddress - Entry->BaseAddress + 1; + Descriptor->Capabilities = Entry->Capabilities; + Descriptor->Attributes = Entry->Attributes; + Descriptor->GcdMemoryType = Entry->GcdMemoryType; + Descriptor->ImageHandle = Entry->ImageHandle; + Descriptor->DeviceHandle = Entry->DeviceHandle; +} + +EFI_STATUS +CoreGetMemorySpaceDescriptor ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor + ) +/*++ + +Routine Description: + + Retrieves the descriptor for a memory region containing a specified address. + +Arguments: + + BaseAddress - Specified start address + + Descriptor - Specified length + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_SUCCESS - Successfully get memory space descriptor. + +--*/ +{ + EFI_STATUS Status; + EFI_LIST_ENTRY *StartLink; + EFI_LIST_ENTRY *EndLink; + EFI_GCD_MAP_ENTRY *Entry; + + // + // Make sure parameters are valid + // + if (Descriptor == NULL) { + return EFI_INVALID_PARAMETER; + } + + CoreAcquireGcdMemoryLock (); + + // + // Search for the list of descriptors that contain BaseAddress + // + Status = CoreSearchGcdMapEntry (BaseAddress, 1, &StartLink, &EndLink, &mGcdMemorySpaceMap); + if (EFI_ERROR (Status) || (StartLink == NULL) || (EndLink == NULL)) { + Status = EFI_NOT_FOUND; + } else { + // + // Copy the contents of the found descriptor into Descriptor + // + Entry = CR (StartLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE); + BuildMemoryDescriptor (Descriptor, Entry); + } + + CoreReleaseGcdMemoryLock (); + + return Status; +} + +EFI_STATUS +CoreSetMemorySpaceAttributes ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Attributes + ) +/*++ + +Routine Description: + + Modifies the attributes for a memory region in the global coherency domain of the +processor. + +Arguments: + + BaseAddress - Specified start address + + Length - Specified length + + Attributes - Specified attributes + +Returns: + + EFI_SUCCESS - Successfully set attribute of a segment of memory space. + +--*/ +{ + return CoreConvertSpace (GCD_SET_ATTRIBUTES_MEMORY_OPERATION, 0, 0, BaseAddress, Length, 0, Attributes); +} + +EFI_STATUS +CoreGetMemorySpaceMap ( + OUT UINTN *NumberOfDescriptors, + OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR **MemorySpaceMap + ) +/*++ + +Routine Description: + + Returns a map of the memory resources in the global coherency domain of the +processor. + +Arguments: + + NumberOfDescriptors - Number of descriptors. + + MemorySpaceMap - Descriptor array + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_OUT_OF_RESOURCES - No enough buffer to allocate + + EFI_SUCCESS - Successfully get memory space map. + +--*/ +{ + EFI_STATUS Status; + EFI_LIST_ENTRY *Link; + EFI_GCD_MAP_ENTRY *Entry; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor; + + // + // Make sure parameters are valid + // + if (NumberOfDescriptors == NULL) { + return EFI_INVALID_PARAMETER; + } + if (MemorySpaceMap == NULL) { + return EFI_INVALID_PARAMETER; + } + + CoreAcquireGcdMemoryLock (); + + // + // Count the number of descriptors + // + *NumberOfDescriptors = CoreCountGcdMapEntry (&mGcdMemorySpaceMap); + + // + // Allocate the MemorySpaceMap + // + *MemorySpaceMap = CoreAllocateBootServicesPool (*NumberOfDescriptors * sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR)); + if (*MemorySpaceMap == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + // + // Fill in the MemorySpaceMap + // + Descriptor = *MemorySpaceMap; + Link = mGcdMemorySpaceMap.ForwardLink; + while (Link != &mGcdMemorySpaceMap) { + Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE); + BuildMemoryDescriptor (Descriptor, Entry); + Descriptor++; + Link = Link->ForwardLink; + } + Status = EFI_SUCCESS; + +Done: + CoreReleaseGcdMemoryLock (); + return Status; +} + +EFI_STATUS +CoreAddIoSpace ( + IN EFI_GCD_IO_TYPE GcdIoType, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +/*++ + +Routine Description: + + Adds reserved I/O or I/O resources to the global coherency domain of the processor. + +Arguments: + + GcdIoType - IO type of the segment. + + BaseAddress - Base address of the segment. + + Length - Length of the segment. + +Returns: + + EFI_SUCCESS - Merged this segment into GCD map. + EFI_INVALID_PARAMETER - Parameter not valid + +--*/ +{ + // + // Make sure parameters are valid + // + if (GcdIoType <= EfiGcdIoTypeNonExistent || GcdIoType >= EfiGcdIoTypeMaximum) { + return EFI_INVALID_PARAMETER; + } + return CoreConvertSpace (GCD_ADD_IO_OPERATION, 0, GcdIoType, BaseAddress, Length, 0, 0); +} + +EFI_STATUS +CoreAllocateIoSpace ( + IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType, + IN EFI_GCD_IO_TYPE GcdIoType, + IN UINTN Alignment, + IN UINT64 Length, + IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress, + IN EFI_HANDLE ImageHandle, + IN EFI_HANDLE DeviceHandle OPTIONAL + ) +/*++ + +Routine Description: + + Allocates nonexistent I/O, reserved I/O, or I/O resources from the global coherency +domain of the processor. + +Arguments: + + GcdAllocateType - The type of allocate operation + + GcdIoType - The desired IO type + + Alignment - Align with 2^Alignment + + Length - Length to allocate + + BaseAddress - Base address to allocate + + ImageHandle - The image handle consume the allocated space. + + DeviceHandle - The device handle consume the allocated space. + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter. + + EFI_NOT_FOUND - No descriptor contains the desired space. + + EFI_SUCCESS - IO space successfully allocated. + +--*/ +{ + return CoreAllocateSpace ( + GCD_ALLOCATE_IO_OPERATION, + GcdAllocateType, + 0, + GcdIoType, + Alignment, + Length, + BaseAddress, + ImageHandle, + DeviceHandle + ); +} + +EFI_STATUS +CoreFreeIoSpace ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +/*++ + +Routine Description: + + Frees nonexistent I/O, reserved I/O, or I/O resources from the global coherency +domain of the processor. + +Arguments: + + BaseAddress - Base address of the segment. + + Length - Length of the segment. + +Returns: + + EFI_SUCCESS - Space successfully freed. + +--*/ +{ + return CoreConvertSpace (GCD_FREE_IO_OPERATION, 0, 0, BaseAddress, Length, 0, 0); +} + +EFI_STATUS +CoreRemoveIoSpace ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +/*++ + +Routine Description: + + Removes reserved I/O or I/O resources from the global coherency domain of the +processor. + +Arguments: + + BaseAddress - Base address of the segment. + + Length - Length of the segment. + +Returns: + + EFI_SUCCESS - Successfully removed a segment of IO space. + +--*/ +{ + return CoreConvertSpace (GCD_REMOVE_IO_OPERATION, 0, 0, BaseAddress, Length, 0, 0); +} + +VOID +BuildIoDescriptor ( + IN EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor, + IN EFI_GCD_MAP_ENTRY *Entry + ) +/*++ + +Routine Description: + + Build a IO descriptor according to an entry. + +Arguments: + + Descriptor - The descriptor to be built + + Entry - According to this entry + +Returns: + + None + +--*/ +{ + Descriptor->BaseAddress = Entry->BaseAddress; + Descriptor->Length = Entry->EndAddress - Entry->BaseAddress + 1; + Descriptor->GcdIoType = Entry->GcdIoType; + Descriptor->ImageHandle = Entry->ImageHandle; + Descriptor->DeviceHandle = Entry->DeviceHandle; +} + +EFI_STATUS +CoreGetIoSpaceDescriptor ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + OUT EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor + ) +/*++ + +Routine Description: + + Retrieves the descriptor for an I/O region containing a specified address. + +Arguments: + + BaseAddress - Specified start address + + Descriptor - Specified length + +Returns: + + EFI_INVALID_PARAMETER - Descriptor is NULL. + + EFI_SUCCESS - Successfully get the IO space descriptor. + +--*/ +{ + EFI_STATUS Status; + EFI_LIST_ENTRY *StartLink; + EFI_LIST_ENTRY *EndLink; + EFI_GCD_MAP_ENTRY *Entry; + + // + // Make sure parameters are valid + // + if (Descriptor == NULL) { + return EFI_INVALID_PARAMETER; + } + + CoreAcquireGcdIoLock (); + + // + // Search for the list of descriptors that contain BaseAddress + // + Status = CoreSearchGcdMapEntry (BaseAddress, 1, &StartLink, &EndLink, &mGcdIoSpaceMap); + if (EFI_ERROR (Status) || (StartLink == NULL) || (EndLink == NULL)) { + Status = EFI_NOT_FOUND; + } else { + // + // Copy the contents of the found descriptor into Descriptor + // + Entry = CR (StartLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE); + BuildIoDescriptor (Descriptor, Entry); + } + + CoreReleaseGcdIoLock (); + + return Status; +} + +EFI_STATUS +CoreGetIoSpaceMap ( + OUT UINTN *NumberOfDescriptors, + OUT EFI_GCD_IO_SPACE_DESCRIPTOR **IoSpaceMap + ) +/*++ + +Routine Description: + + Returns a map of the I/O resources in the global coherency domain of the processor. + +Arguments: + + NumberOfDescriptors - Number of descriptors. + + IoSpaceMap - Descriptor array + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_OUT_OF_RESOURCES - No enough buffer to allocate + + EFI_SUCCESS - Successfully get IO space map. + +--*/ +{ + EFI_STATUS Status; + EFI_LIST_ENTRY *Link; + EFI_GCD_MAP_ENTRY *Entry; + EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor; + + // + // Make sure parameters are valid + // + if (NumberOfDescriptors == NULL) { + return EFI_INVALID_PARAMETER; + } + if (IoSpaceMap == NULL) { + return EFI_INVALID_PARAMETER; + } + + CoreAcquireGcdIoLock (); + + // + // Count the number of descriptors + // + *NumberOfDescriptors = CoreCountGcdMapEntry (&mGcdIoSpaceMap); + + // + // Allocate the IoSpaceMap + // + *IoSpaceMap = CoreAllocateBootServicesPool (*NumberOfDescriptors * sizeof (EFI_GCD_IO_SPACE_DESCRIPTOR)); + if (*IoSpaceMap == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + // + // Fill in the IoSpaceMap + // + Descriptor = *IoSpaceMap; + Link = mGcdIoSpaceMap.ForwardLink; + while (Link != &mGcdIoSpaceMap) { + Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE); + BuildIoDescriptor (Descriptor, Entry); + Descriptor++; + Link = Link->ForwardLink; + } + Status = EFI_SUCCESS; + +Done: + CoreReleaseGcdIoLock (); + return Status; +} + +UINT64 +CoreConvertResourceDescriptorHobAttributesToCapabilities ( + EFI_GCD_MEMORY_TYPE GcdMemoryType, + UINT64 Attributes + ) +/*++ + +Routine Description: + + Converts a Resource Descriptor HOB attributes mask to an EFI Memory Descriptor + capabilities mask + +Arguments: + + GcdMemoryType - Type of resource in the GCD memory map. + Attributes - The attribute mask in the Resource Descriptor HOB. + +Returns: + + The capabilities mask for an EFI Memory Descriptor. + +--*/ +{ + UINT64 Capabilities; + GCD_ATTRIBUTE_CONVERSION_ENTRY *Conversion; + + // + // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask + // + for (Capabilities = 0, Conversion = mAttributeConversionTable; Conversion->Attribute != 0; Conversion++) { + if (Conversion->Memory || (GcdMemoryType != EfiGcdMemoryTypeSystemMemory)) { + if (Attributes & Conversion->Attribute) { + Capabilities |= Conversion->Capability; + } + } + } + + return Capabilities; +} + +EFI_STATUS +CoreInitializeMemoryServices ( + IN VOID **HobStart, + OUT EFI_PHYSICAL_ADDRESS *MemoryBaseAddress, + OUT UINT64 *MemoryLength + ) +/*++ + +Routine Description: + + External function. Initializes the GCD and memory services based on the memory + descriptor HOBs. This function is responsible for priming the GCD map and the + memory map, so memory allocations and resource allocations can be made. The first + part of this function can not depend on any memory services until at least one + memory descriptor is provided to the memory services. Then the memory services + can be used to intialize the GCD map. + +Arguments: + + HobStart - The start address of the HOB. + MemoryBaseAddress - Start address of memory region found to init DXE core. + MemoryLength - Length of memory region found to init DXE core. + +Returns: + + EFI_SUCCESS - Memory services successfully initialized. + +--*/ +{ + EFI_STATUS Status; + EFI_PEI_HOB_POINTERS Hob; + EFI_MEMORY_TYPE_INFORMATION *EfiMemoryTypeInformation; + UINTN DataSize; + BOOLEAN Found; + EFI_HOB_HANDOFF_INFO_TABLE *PhitHob; + EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob; + EFI_HOB_RESOURCE_DESCRIPTOR *PhitResourceHob; + EFI_PHYSICAL_ADDRESS BaseAddress; + UINT64 Length; + UINT64 Attributes; + UINT64 Capabilities; + EFI_PHYSICAL_ADDRESS MaxMemoryBaseAddress; + UINT64 MaxMemoryLength; + UINT64 MaxMemoryAttributes; + EFI_PHYSICAL_ADDRESS MaxAddress; + EFI_PHYSICAL_ADDRESS HighAddress; + EFI_HOB_RESOURCE_DESCRIPTOR *MaxResourceHob; + + // + // Point at the first HOB. This must be the PHIT HOB. + // + Hob.Raw = *HobStart; + ASSERT (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_HANDOFF); + + // + // Initialize the spin locks and maps in the memory services. + // Also fill in the memory services into the EFI Boot Services Table + // + CoreInitializePool (); + + // + // Initialize Local Variables + // + PhitResourceHob = NULL; + MaxResourceHob = NULL; + ResourceHob = NULL; + BaseAddress = 0; + Length = 0; + Attributes = 0; + MaxMemoryBaseAddress = 0; + MaxMemoryLength = 0; + MaxMemoryAttributes = 0; + + // + // Cache the PHIT HOB for later use + // + PhitHob = Hob.HandoffInformationTable; + + // + // See if a Memory Type Information HOB is available + // + Status = GetNextGuidHob (&Hob.Raw, &gEfiMemoryTypeInformationGuid, &EfiMemoryTypeInformation, &DataSize); + if (!EFI_ERROR (Status) && + EfiMemoryTypeInformation != NULL && + DataSize > 0 && + DataSize < EfiMaxMemoryType * sizeof (EFI_MEMORY_TYPE_INFORMATION)) { + gBS->CopyMem (&gMemoryTypeInformation, EfiMemoryTypeInformation, DataSize); + } + + // + // Find the Resource Descriptor HOB that contains range FreeMemoryBaseAddress..FreeMemoryLength + // + Length = 0; + Found = FALSE; + for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) { + + if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { + + ResourceHob = Hob.ResourceDescriptor; + + if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY && + (ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == TESTED_MEMORY_ATTRIBUTES ) { + + if (PhitHob->EfiFreeMemoryBottom >= ResourceHob->PhysicalStart && + PhitHob->EfiFreeMemoryTop <= (ResourceHob->PhysicalStart + ResourceHob->ResourceLength) ) { + + // + // Cache the resource descriptor HOB for the memory region described by the PHIT HOB + // + PhitResourceHob = ResourceHob; + Found = TRUE; + + Attributes = PhitResourceHob->ResourceAttribute; + BaseAddress = PageAlignAddress (PhitHob->EfiMemoryTop); + Length = PageAlignLength (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - BaseAddress); + if (Length < MINIMUM_INITIAL_MEMORY_SIZE) { + BaseAddress = PageAlignAddress (PhitHob->EfiFreeMemoryBottom); + Length = PageAlignLength (PhitHob->EfiFreeMemoryTop - BaseAddress); + if (Length < MINIMUM_INITIAL_MEMORY_SIZE) { + BaseAddress = PageAlignAddress (ResourceHob->PhysicalStart); + Length = PageAlignLength ((UINT64)*HobStart - BaseAddress); + } + } + break; + } + } + } + } + + // + // Assert if a resource descriptor HOB for the memory region described by the PHIT was not found + // + ASSERT (Found); + + // + // Search all the resource descriptor HOBs from the highest possible addresses down for a memory + // region that is big enough to initialize the DXE core. Always skip the PHIT Resource HOB. + // The max address must be within the physically addressible range for the processor. + // + MaxMemoryLength = 0; + MaxAddress = EFI_MAX_ADDRESS; + do { + HighAddress = 0; + Found = FALSE; + // + // Search for a tested memory region that is below MaxAddress + // + for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) { + + // + // See if this is a resource descriptor HOB that does not contain the PHIT. + // + if (Hob.ResourceDescriptor != PhitResourceHob && GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { + + ResourceHob = Hob.ResourceDescriptor; + // + // See if this resource descrior HOB describes tested system memory below MaxAddress + // + if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY && + (ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == TESTED_MEMORY_ATTRIBUTES && + ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MaxAddress ) { + + // + // See if this is the highest tested system memory region below MaxAddress + // + if (ResourceHob->PhysicalStart > HighAddress) { + + MaxResourceHob = ResourceHob; + HighAddress = MaxResourceHob->PhysicalStart; + Found = TRUE; + } + } + } + } + if (Found) { + // + // Compute the size of the tested memory region below MaxAddrees + // + MaxMemoryBaseAddress = PageAlignAddress (MaxResourceHob->PhysicalStart); + MaxMemoryLength = PageAlignLength (MaxResourceHob->PhysicalStart + MaxResourceHob->ResourceLength - MaxMemoryBaseAddress); + MaxMemoryAttributes = MaxResourceHob->ResourceAttribute; + } + if (ResourceHob != NULL) { + MaxAddress = ResourceHob->PhysicalStart; + } + } while (Found && MaxMemoryLength < MINIMUM_INITIAL_MEMORY_SIZE); + + // + // + // + if ((Length < MINIMUM_INITIAL_MEMORY_SIZE) || + (MaxMemoryBaseAddress > BaseAddress && MaxMemoryLength >= MINIMUM_INITIAL_MEMORY_SIZE) ) { + BaseAddress = MaxMemoryBaseAddress; + Length = MaxMemoryLength; + Attributes = MaxMemoryAttributes; + } + + // + // If no memory regions are found that are big enough to initialize the DXE core, then ASSERT(). + // + ASSERT (Length >= MINIMUM_INITIAL_MEMORY_SIZE); + + // + // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask + // + Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (EfiGcdMemoryTypeSystemMemory, Attributes); + + // + // Declare the very first memory region, so the EFI Memory Services are available. + // + CoreAddMemoryDescriptor ( + EfiConventionalMemory, + BaseAddress, + RShiftU64 (Length, EFI_PAGE_SHIFT), + Capabilities + ); + + *MemoryBaseAddress = BaseAddress; + *MemoryLength = Length; + + return EFI_SUCCESS; +} + +EFI_STATUS +CoreInitializeGcdServices ( + IN VOID **HobStart, + IN EFI_PHYSICAL_ADDRESS MemoryBaseAddress, + IN UINT64 MemoryLength + ) +/*++ + +Routine Description: + + External function. Initializes the GCD and memory services based on the memory + descriptor HOBs. This function is responsible for priming the GCD map and the + memory map, so memory allocations and resource allocations can be made. The first + part of this function can not depend on any memory services until at least one + memory descriptor is provided to the memory services. Then the memory services + can be used to intialize the GCD map. + +Arguments: + + HobStart - The start address of the HOB + + MemoryBaseAddress - Start address of memory region found to init DXE core. + + MemoryLength - Length of memory region found to init DXE core. + + +Returns: + + EFI_SUCCESS - GCD services successfully initialized. + +--*/ +{ + EFI_PEI_HOB_POINTERS Hob; + VOID *NewHobList; + EFI_HOB_HANDOFF_INFO_TABLE *PhitHob; + UINT8 SizeOfMemorySpace; + UINT8 SizeOfIoSpace; + EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob; + EFI_PHYSICAL_ADDRESS BaseAddress; + UINT64 Length; + EFI_STATUS Status; + EFI_GCD_MAP_ENTRY *Entry; + EFI_GCD_MEMORY_TYPE GcdMemoryType; + EFI_GCD_IO_TYPE GcdIoType; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor; + EFI_HOB_MEMORY_ALLOCATION *MemoryHob; + EFI_HOB_FIRMWARE_VOLUME *FirmwareVolumeHob; + UINTN NumberOfDescriptors; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap; + UINTN Index; + UINT64 Capabilities; + + // + // Cache the PHIT HOB for later use + // + PhitHob = (EFI_HOB_HANDOFF_INFO_TABLE *)(*HobStart); + + // + // Get the number of address lines in the I/O and Memory space for the CPU + // + Status = GetCpuHobInfo (*HobStart, &SizeOfMemorySpace, &SizeOfIoSpace); + ASSERT_EFI_ERROR (Status); + + // + // Initialize the GCD Memory Space Map + // + Entry = CoreAllocateCopyPool (sizeof (EFI_GCD_MAP_ENTRY), &mGcdMemorySpaceMapEntryTemplate); + ASSERT (Entry != NULL); + if (Entry == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Entry->EndAddress = LShiftU64 (1, SizeOfMemorySpace) - 1; + + InsertHeadList (&mGcdMemorySpaceMap, &Entry->Link); + + // + // Initialize the GCD I/O Space Map + // + Entry = CoreAllocateCopyPool (sizeof (EFI_GCD_MAP_ENTRY), &mGcdIoSpaceMapEntryTemplate); + ASSERT (Entry != NULL); + if (Entry == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Entry->EndAddress = LShiftU64 (1, SizeOfIoSpace) - 1; + + InsertHeadList (&mGcdIoSpaceMap, &Entry->Link); + + // + // Walk the HOB list and add all resource descriptors to the GCD + // + for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) { + + GcdMemoryType = EfiGcdMemoryTypeNonExistent; + GcdIoType = EfiGcdIoTypeNonExistent; + + if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { + + ResourceHob = Hob.ResourceDescriptor; + + switch (ResourceHob->ResourceType) { + case EFI_RESOURCE_SYSTEM_MEMORY: + if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == TESTED_MEMORY_ATTRIBUTES) { + GcdMemoryType = EfiGcdMemoryTypeSystemMemory; + } + if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == INITIALIZED_MEMORY_ATTRIBUTES) { + GcdMemoryType = EfiGcdMemoryTypeReserved; + } + if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == PRESENT_MEMORY_ATTRIBUTES) { + GcdMemoryType = EfiGcdMemoryTypeReserved; + } + break; + case EFI_RESOURCE_MEMORY_MAPPED_IO: + case EFI_RESOURCE_FIRMWARE_DEVICE: + GcdMemoryType = EfiGcdMemoryTypeMemoryMappedIo; + break; + case EFI_RESOURCE_MEMORY_MAPPED_IO_PORT: + case EFI_RESOURCE_MEMORY_RESERVED: + GcdMemoryType = EfiGcdMemoryTypeReserved; + break; + case EFI_RESOURCE_IO: + GcdIoType = EfiGcdIoTypeIo; + break; + case EFI_RESOURCE_IO_RESERVED: + GcdIoType = EfiGcdIoTypeReserved; + break; + } + + if (GcdMemoryType != EfiGcdMemoryTypeNonExistent) { + + // + // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask + // + Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities ( + GcdMemoryType, + ResourceHob->ResourceAttribute + ); + + Status = CoreInternalAddMemorySpace ( + GcdMemoryType, + ResourceHob->PhysicalStart, + ResourceHob->ResourceLength, + Capabilities + ); + } + + if (GcdIoType != EfiGcdIoTypeNonExistent) { + Status = CoreAddIoSpace ( + GcdIoType, + ResourceHob->PhysicalStart, + ResourceHob->ResourceLength + ); + } + } + } + + // + // Allocate first memory region from the GCD by the DXE core + // + Status = CoreAllocateMemorySpace ( + EfiGcdAllocateAddress, + EfiGcdMemoryTypeSystemMemory, + 0, + MemoryLength, + &MemoryBaseAddress, + gDxeCoreImageHandle, + NULL + ); + + // + // Walk the HOB list and allocate all memory space that is consumed by memory allocation HOBs, + // and Firmware Volume HOBs. Also update the EFI Memory Map with the memory allocation HOBs. + // + for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) { + if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) { + MemoryHob = Hob.MemoryAllocation; + BaseAddress = MemoryHob->AllocDescriptor.MemoryBaseAddress; + Status = CoreAllocateMemorySpace ( + EfiGcdAllocateAddress, + EfiGcdMemoryTypeSystemMemory, + 0, + MemoryHob->AllocDescriptor.MemoryLength, + &BaseAddress, + gDxeCoreImageHandle, + NULL + ); + if (!EFI_ERROR (Status)) { + Status = CoreGetMemorySpaceDescriptor (MemoryHob->AllocDescriptor.MemoryBaseAddress, &Descriptor); + if (!EFI_ERROR (Status)) { + CoreAddMemoryDescriptor ( + MemoryHob->AllocDescriptor.MemoryType, + MemoryHob->AllocDescriptor.MemoryBaseAddress, + RShiftU64 (MemoryHob->AllocDescriptor.MemoryLength, EFI_PAGE_SHIFT), + Descriptor.Capabilities & (~EFI_MEMORY_RUNTIME) + ); + } + } + } + + if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV) { + FirmwareVolumeHob = Hob.FirmwareVolume; + BaseAddress = FirmwareVolumeHob->BaseAddress; + Status = CoreAllocateMemorySpace ( + EfiGcdAllocateAddress, + EfiGcdMemoryTypeMemoryMappedIo, + 0, + FirmwareVolumeHob->Length, + &BaseAddress, + gDxeCoreImageHandle, + NULL + ); + } + } + + // + // Relocate HOB List to an allocated pool buffer. + // + NewHobList = CoreAllocateCopyPool ( + (UINTN)PhitHob->EfiFreeMemoryBottom - (UINTN)(*HobStart), + *HobStart + ); + ASSERT (NewHobList != NULL); + + *HobStart = NewHobList; + + // + // Add and allocate the remaining unallocated system memory to the memory services. + // + Status = CoreGetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap); + if (EFI_ERROR (Status) || (MemorySpaceMap == NULL)) { + return Status; + } + for (Index = 0; Index < NumberOfDescriptors; Index++) { + if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeSystemMemory) { + if (MemorySpaceMap[Index].ImageHandle == NULL) { + BaseAddress = PageAlignAddress (MemorySpaceMap[Index].BaseAddress); + Length = PageAlignLength (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - BaseAddress); +// +// EDK Defect Start: EDK836 +// +// BUG FIX: +// Skip zero length descriptors +// + if (Length == 0) { + continue; + } +// +// EDK Defect End: EDK836 +// + CoreAddMemoryDescriptor ( + EfiConventionalMemory, + BaseAddress, + RShiftU64 (Length, EFI_PAGE_SHIFT), + MemorySpaceMap[Index].Capabilities & (~EFI_MEMORY_RUNTIME) + ); + Status = CoreAllocateMemorySpace ( + EfiGcdAllocateAddress, + EfiGcdMemoryTypeSystemMemory, + 0, + Length, + &BaseAddress, + gDxeCoreImageHandle, + NULL + ); + } + } + } + CoreFreePool (MemorySpaceMap); + + return EFI_SUCCESS; +} diff --git a/EDK/Foundation/Core/Dxe/Gcd/gcd.h b/EDK/Foundation/Core/Dxe/Gcd/gcd.h new file mode 100644 index 0000000..13d448d --- /dev/null +++ b/EDK/Foundation/Core/Dxe/Gcd/gcd.h @@ -0,0 +1,54 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + gcd.h + +Abstract: + +Revision History + +--*/ + +#ifndef _GCD_H +#define _GCD_H + +#include "Tiano.h" +#include "DxeCore.h" + +// +// GCD Operations +// +#define GCD_MEMORY_SPACE_OPERATION 0x20 +#define GCD_IO_SPACE_OPERATION 0x40 + +#define GCD_ADD_MEMORY_OPERATION (GCD_MEMORY_SPACE_OPERATION | 0) +#define GCD_ALLOCATE_MEMORY_OPERATION (GCD_MEMORY_SPACE_OPERATION | 1) +#define GCD_FREE_MEMORY_OPERATION (GCD_MEMORY_SPACE_OPERATION | 2) +#define GCD_REMOVE_MEMORY_OPERATION (GCD_MEMORY_SPACE_OPERATION | 3) +#define GCD_SET_ATTRIBUTES_MEMORY_OPERATION (GCD_MEMORY_SPACE_OPERATION | 4) + +#define GCD_ADD_IO_OPERATION (GCD_IO_SPACE_OPERATION | 0) +#define GCD_ALLOCATE_IO_OPERATION (GCD_IO_SPACE_OPERATION | 1) +#define GCD_FREE_IO_OPERATION (GCD_IO_SPACE_OPERATION | 2) +#define GCD_REMOVE_IO_OPERATION (GCD_IO_SPACE_OPERATION | 3) + +// +// The data structure used to convert from GCD attributes to EFI Memory Map attributes +// +typedef struct { + UINT64 Attribute; + UINT64 Capability; + BOOLEAN Memory; +} GCD_ATTRIBUTE_CONVERSION_ENTRY; + +#endif diff --git a/EDK/Foundation/Core/Dxe/Hand/DriverSupport.c b/EDK/Foundation/Core/Dxe/Hand/DriverSupport.c new file mode 100644 index 0000000..0597475 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/Hand/DriverSupport.c @@ -0,0 +1,860 @@ +/*++ + +Copyright (c) 2004 - 2011, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DriverSupport.c + +Abstract: + + EFI Driver Support Protocol + +Revision History + +--*/ + +#include "Tiano.h" +#include "hand.h" +#include "EfiPerf.h" + + +// +// Driver Consumed Protocol Prototypes +// +#include EFI_PROTOCOL_DEFINITION(DriverBinding) +#include EFI_PROTOCOL_DEFINITION(PlatformDriverOverride) +#include EFI_PROTOCOL_DEFINITION(BusSpecificDriverOverride) + + + +#ifdef FIRMWARE_PERFORMANCE +STATIC +EFI_STATUS +GetHandleFromDriverBinding ( + IN EFI_DRIVER_BINDING_PROTOCOL *DriverBindingNeed, + OUT EFI_HANDLE *Handle + ); +#endif + +// +// Driver Support Function Prototypes +// +STATIC +EFI_STATUS +CoreConnectSingleController ( + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE *DriverImageHandle OPTIONAL, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +// +// Driver Support Functions +// + +EFI_BOOTSERVICE11 +EFI_STATUS +EFIAPI +CoreConnectController ( + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE *DriverImageHandle OPTIONAL, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL, + IN BOOLEAN Recursive + ) +/*++ + +Routine Description: + + Connects one or more drivers to a controller. + +Arguments: + + ControllerHandle - Handle of the controller to be connected. + + DriverImageHandle - DriverImageHandle A pointer to an ordered list of driver image handles. + + RemainingDevicePath - RemainingDevicePath A pointer to the device path that specifies a child of the + controller specified by ControllerHandle. + + Recursive - Whether the function would be called recursively or not. + +Returns: + + Status code. + +--*/ +{ + EFI_STATUS Status; + EFI_STATUS ReturnStatus; + IHANDLE *Handle; + PROTOCOL_INTERFACE *Prot; + EFI_LIST_ENTRY *Link; + EFI_LIST_ENTRY *ProtLink; + OPEN_PROTOCOL_DATA *OpenData; + EFI_DEVICE_PATH_PROTOCOL *AlignedRemainingDevicePath; + + // + // Make sure ControllerHandle is valid + // + Status = CoreValidateHandle (ControllerHandle); + if (EFI_ERROR (Status)) { + return Status; + } + + Handle = ControllerHandle; + + // + // Connect all drivers to ControllerHandle + // + AlignedRemainingDevicePath = NULL; + if (RemainingDevicePath != NULL) { + AlignedRemainingDevicePath = CoreDuplicateDevicePath (RemainingDevicePath); + } + ReturnStatus = CoreConnectSingleController ( + ControllerHandle, + DriverImageHandle, + AlignedRemainingDevicePath + ); + if (AlignedRemainingDevicePath != NULL) { + CoreFreePool (AlignedRemainingDevicePath); + } + + // + // If not recursive, then just return after connecting drivers to ControllerHandle + // + if (!Recursive) { + return ReturnStatus; + } + + // + // If recursive, then connect all drivers to all of ControllerHandle's children + // + CoreAcquireProtocolLock (); + for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) { + Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE); + for (ProtLink = Prot->OpenList.ForwardLink; + ProtLink != &Prot->OpenList; + ProtLink = ProtLink->ForwardLink) { + OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE); + if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) { + CoreReleaseProtocolLock (); + Status = CoreConnectController ( + OpenData->ControllerHandle, + NULL, + NULL, + TRUE + ); + CoreAcquireProtocolLock (); + } + } + } + CoreReleaseProtocolLock (); + + return ReturnStatus; +} + +VOID +AddSortedDriverBindingProtocol ( + IN EFI_HANDLE DriverBindingHandle, + IN OUT UINTN *NumberOfSortedDriverBindingProtocols, + IN OUT EFI_DRIVER_BINDING_PROTOCOL **SortedDriverBindingProtocols, + IN UINTN DriverBindingHandleCount, + IN OUT EFI_HANDLE *DriverBindingHandleBuffer + ) +/*++ + +Routine Description: + + Add Driver Binding Protocols from Context Driver Image Handles to sorted + Driver Binding Protocol list. + +Arguments: + + DriverBindingHandle - Handle of the driver binding protocol. + + NumberOfSortedDriverBindingProtocols - Number Of sorted driver binding protocols + + SortedDriverBindingProtocols - The sorted protocol list. + + DriverBindingHandleCount - Driver Binding Handle Count. + + DriverBindingHandleBuffer - The buffer of driver binding protocol to be modified. + +Returns: + + None. + +--*/ +{ + EFI_STATUS Status; + EFI_DRIVER_BINDING_PROTOCOL *DriverBinding; + UINTN Index; + + // + // Make sure the DriverBindingHandle is valid + // + Status = CoreValidateHandle (DriverBindingHandle); + if (EFI_ERROR (Status)) { + return; + } + + // + // Retrieve the Driver Binding Protocol from DriverBindingHandle + // + Status = CoreHandleProtocol( + DriverBindingHandle, + &gEfiDriverBindingProtocolGuid, + &DriverBinding + ); + // + // If DriverBindingHandle does not support the Driver Binding Protocol then return + // + if (EFI_ERROR (Status) || DriverBinding == NULL) { + return; + } + + // + // See if DriverBinding is already in the sorted list + // + for (Index = 0; Index < *NumberOfSortedDriverBindingProtocols; Index++) { + if (DriverBinding == SortedDriverBindingProtocols[Index]) { + return; + } + } + + // + // Add DriverBinding to the end of the list + // + SortedDriverBindingProtocols[*NumberOfSortedDriverBindingProtocols] = DriverBinding; + *NumberOfSortedDriverBindingProtocols = *NumberOfSortedDriverBindingProtocols + 1; + + // + // Mark the cooresponding handle in DriverBindingHandleBuffer as used + // + for (Index = 0; Index < DriverBindingHandleCount; Index++) { + if (DriverBindingHandleBuffer[Index] == DriverBindingHandle) { + DriverBindingHandleBuffer[Index] = NULL; + } + } +} + +STATIC +EFI_STATUS +CoreConnectSingleController ( + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE *ContextDriverImageHandles OPTIONAL, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +/*++ + +Routine Description: + + Connects a controller to a driver. + +Arguments: + + ControllerHandle - Handle of the controller to be connected. + ContextDriverImageHandles - DriverImageHandle A pointer to an ordered list of driver image handles. + RemainingDevicePath - RemainingDevicePath A pointer to the device path that specifies a child + of the controller specified by ControllerHandle. + +Returns: + + EFI_SUCCESS - One or more drivers were connected to ControllerHandle. + EFI_OUT_OF_RESOURCES - No enough system resources to complete the request. + EFI_NOT_FOUND - No drivers were connected to ControllerHandle. + +--*/ +{ + EFI_STATUS Status; + UINTN Index; + EFI_HANDLE DriverImageHandle; + UINTN PlatformDriverOverrideHandleCount; + EFI_HANDLE *PlatformDriverOverrideHandleBuffer; + EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL *PlatformDriverOverride; + EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL *BusSpecificDriverOverride; + UINTN DriverBindingHandleCount; + EFI_HANDLE *DriverBindingHandleBuffer; + EFI_DRIVER_BINDING_PROTOCOL *DriverBinding; + UINTN NumberOfSortedDriverBindingProtocols; + EFI_DRIVER_BINDING_PROTOCOL **SortedDriverBindingProtocols; + UINT32 HighestVersion; + UINTN HighestIndex; + UINTN SortIndex; + BOOLEAN OneStarted; + BOOLEAN DriverFound; + +#ifdef FIRMWARE_PERFORMANCE + EFI_HANDLE DriverBindingHandle; +#endif + + // + // Initialize local variables + // + DriverBindingHandleCount = 0; + DriverBindingHandleBuffer = NULL; + PlatformDriverOverrideHandleCount = 0; + PlatformDriverOverrideHandleBuffer = NULL; + NumberOfSortedDriverBindingProtocols = 0; + SortedDriverBindingProtocols = NULL; + + // + // Get list of all Driver Binding Protocol Instances + // + Status = CoreLocateHandleBuffer ( + ByProtocol, + &gEfiDriverBindingProtocolGuid, + NULL, + &DriverBindingHandleCount, + &DriverBindingHandleBuffer + ); + if (EFI_ERROR (Status) || (DriverBindingHandleCount == 0)) { + return EFI_NOT_FOUND; + } + + // + // Allocate a duplicate array for the sorted Driver Binding Protocol Instances + // + SortedDriverBindingProtocols = CoreAllocateBootServicesPool (sizeof (VOID *) * DriverBindingHandleCount); + if (SortedDriverBindingProtocols == NULL) { + CoreFreePool (DriverBindingHandleBuffer); + return EFI_OUT_OF_RESOURCES; + } + + // + // Add Driver Binding Protocols from Context Driver Image Handles first + // + if (ContextDriverImageHandles != NULL) { + for (Index = 0; ContextDriverImageHandles[Index] != NULL; Index++) { + AddSortedDriverBindingProtocol ( + ContextDriverImageHandles[Index], + &NumberOfSortedDriverBindingProtocols, + SortedDriverBindingProtocols, + DriverBindingHandleCount, + DriverBindingHandleBuffer + ); + } + } + + // + // Add the Platform Driver Override Protocol drivers for ControllerHandle next + // + Status = CoreLocateProtocol ( + &gEfiPlatformDriverOverrideProtocolGuid, + NULL, + &PlatformDriverOverride + ); + if (!EFI_ERROR (Status) && (PlatformDriverOverride != NULL)) { + DriverImageHandle = NULL; + do { + Status = PlatformDriverOverride->GetDriver ( + PlatformDriverOverride, + ControllerHandle, + &DriverImageHandle + ); + if (!EFI_ERROR (Status)) { + AddSortedDriverBindingProtocol ( + DriverImageHandle, + &NumberOfSortedDriverBindingProtocols, + SortedDriverBindingProtocols, + DriverBindingHandleCount, + DriverBindingHandleBuffer + ); + } + } while (!EFI_ERROR (Status)); + } + + // + // Get the Bus Specific Driver Override Protocol instance on the Controller Handle + // + Status = CoreHandleProtocol( + ControllerHandle, + &gEfiBusSpecificDriverOverrideProtocolGuid, + &BusSpecificDriverOverride + ); + if (!EFI_ERROR (Status) && (BusSpecificDriverOverride != NULL)) { + DriverImageHandle = NULL; + do { + Status = BusSpecificDriverOverride->GetDriver ( + BusSpecificDriverOverride, + &DriverImageHandle + ); + if (!EFI_ERROR (Status)) { + AddSortedDriverBindingProtocol ( + DriverImageHandle, + &NumberOfSortedDriverBindingProtocols, + SortedDriverBindingProtocols, + DriverBindingHandleCount, + DriverBindingHandleBuffer + ); + } + } while (!EFI_ERROR (Status)); + } + + // + // Then add all the remaining Driver Binding Protocols + // + SortIndex = NumberOfSortedDriverBindingProtocols; + for (Index = 0; Index < DriverBindingHandleCount; Index++) { + AddSortedDriverBindingProtocol ( + DriverBindingHandleBuffer[Index], + &NumberOfSortedDriverBindingProtocols, + SortedDriverBindingProtocols, + DriverBindingHandleCount, + DriverBindingHandleBuffer + ); + } + + // + // Free the Driver Binding Handle Buffer + // + CoreFreePool (DriverBindingHandleBuffer); + + // + // Sort the remaining DriverBinding Protocol based on their Version field from + // highest to lowest. + // + for ( ; SortIndex < DriverBindingHandleCount; SortIndex++) { + HighestVersion = SortedDriverBindingProtocols[SortIndex]->Version; + HighestIndex = SortIndex; + for (Index = SortIndex + 1; Index < DriverBindingHandleCount; Index++) { + if (SortedDriverBindingProtocols[Index]->Version > HighestVersion) { + HighestVersion = SortedDriverBindingProtocols[Index]->Version; + HighestIndex = Index; + } + } + if (SortIndex != HighestIndex) { + DriverBinding = SortedDriverBindingProtocols[SortIndex]; + SortedDriverBindingProtocols[SortIndex] = SortedDriverBindingProtocols[HighestIndex]; + SortedDriverBindingProtocols[HighestIndex] = DriverBinding; + } + } + + // + // Loop until no more drivers can be started on ControllerHandle + // + OneStarted = FALSE; + do { + + // + // Loop through the sorted Driver Binding Protocol Instances in order, and see if + // any of the Driver Binding Protocols support the controller specified by + // ControllerHandle. + // + DriverBinding = NULL; + DriverFound = FALSE; + for (Index = 0; (Index < NumberOfSortedDriverBindingProtocols) && !DriverFound; Index++) { + if (SortedDriverBindingProtocols[Index] != NULL) { + DriverBinding = SortedDriverBindingProtocols[Index]; + Status = DriverBinding->Supported( + DriverBinding, + ControllerHandle, + RemainingDevicePath + ); + if (!EFI_ERROR (Status)) { + SortedDriverBindingProtocols[Index] = NULL; + DriverFound = TRUE; + + // + // A driver was found that supports ControllerHandle, so attempt to start the driver + // on ControllerHandle. + // + +#ifdef FIRMWARE_PERFORMANCE + GetHandleFromDriverBinding (DriverBinding, &DriverBindingHandle); +#endif + + PERF_START (DriverBindingHandle, DRIVERBINDING_START_TOK, NULL, 0); + Status = DriverBinding->Start ( + DriverBinding, + ControllerHandle, + RemainingDevicePath + ); + PERF_END (DriverBindingHandle, DRIVERBINDING_START_TOK, NULL, 0); + + if (!EFI_ERROR (Status)) { + // + // The driver was successfully started on ControllerHandle, so set a flag + // + OneStarted = TRUE; + } + } + } + } + } while (DriverFound); + + // + // Free any buffers that were allocated with AllocatePool() + // + CoreFreePool (SortedDriverBindingProtocols); + + // + // If at least one driver was started on ControllerHandle, then return EFI_SUCCESS. + // + if (OneStarted) { + return EFI_SUCCESS; + } + + // + // If no drivers started and RemainingDevicePath is an End Device Path Node, then return EFI_SUCCESS + // + if (RemainingDevicePath != NULL) { + if (IsDevicePathEnd (RemainingDevicePath)) { + return EFI_SUCCESS; + } + } + + // + // Otherwise, no drivers were started on ControllerHandle, so return EFI_NOT_FOUND + // + return EFI_NOT_FOUND; +} + +EFI_BOOTSERVICE11 +EFI_STATUS +EFIAPI +CoreDisconnectController ( + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE DriverImageHandle OPTIONAL, + IN EFI_HANDLE ChildHandle OPTIONAL + ) +/*++ + +Routine Description: + + Disonnects a controller from a driver + +Arguments: + + ControllerHandle - ControllerHandle The handle of the controller from which driver(s) + are to be disconnected. + DriverImageHandle - DriverImageHandle The driver to disconnect from ControllerHandle. + ChildHandle - ChildHandle The handle of the child to destroy. + +Returns: + + EFI_SUCCESS - One or more drivers were disconnected from the controller. + EFI_SUCCESS - On entry, no drivers are managing ControllerHandle. + EFI_SUCCESS - DriverImageHandle is not NULL, and on entry DriverImageHandle is not managing ControllerHandle. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - DriverImageHandle is not NULL, and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL, and it is not a valid EFI_HANDLE. + EFI_OUT_OF_RESOURCES - There are not enough resources available to disconnect any drivers from ControllerHandle. + EFI_DEVICE_ERROR - The controller could not be disconnected because of a device error. + +--*/ +{ + EFI_STATUS Status; + IHANDLE *Handle; + EFI_HANDLE *DriverImageHandleBuffer; + EFI_HANDLE *ChildBuffer; + UINTN Index; + UINTN HandleIndex; + UINTN DriverImageHandleCount; + UINTN ChildrenToStop; + UINTN ChildBufferCount; + UINTN StopCount; + BOOLEAN Duplicate; + BOOLEAN ChildHandleValid; + BOOLEAN DriverImageHandleValid; + EFI_LIST_ENTRY *Link; + EFI_LIST_ENTRY *ProtLink; + OPEN_PROTOCOL_DATA *OpenData; + PROTOCOL_INTERFACE *Prot; + EFI_DRIVER_BINDING_PROTOCOL *DriverBinding; + + // + // Make sure ControllerHandle is valid + // + Status = CoreValidateHandle (ControllerHandle); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Make sure ChildHandle is valid if it is not NULL + // + if (ChildHandle != NULL) { + Status = CoreValidateHandle (ChildHandle); + if (EFI_ERROR (Status)) { + return Status; + } + } + + Handle = ControllerHandle; + + // + // Get list of drivers that are currently managing ControllerHandle + // + DriverImageHandleBuffer = NULL; + DriverImageHandleCount = 1; + + if (DriverImageHandle == NULL) { + // + // Look at each protocol interface for a match + // + DriverImageHandleCount = 0; + + CoreAcquireProtocolLock (); + for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) { + Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE); + for (ProtLink = Prot->OpenList.ForwardLink; + ProtLink != &Prot->OpenList; + ProtLink = ProtLink->ForwardLink) { + OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE); + if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) { + DriverImageHandleCount++; + } + } + } + CoreReleaseProtocolLock (); + + // + // If there are no drivers managing this controller, then return EFI_SUCCESS + // + if (DriverImageHandleCount == 0) { + Status = EFI_SUCCESS; + goto Done; + } + + DriverImageHandleBuffer = CoreAllocateBootServicesPool (sizeof (EFI_HANDLE) * DriverImageHandleCount); + if (DriverImageHandleBuffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + DriverImageHandleCount = 0; + + CoreAcquireProtocolLock (); + for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) { + Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE); + for (ProtLink = Prot->OpenList.ForwardLink; + ProtLink != &Prot->OpenList; + ProtLink = ProtLink->ForwardLink) { + OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE); + if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) { + Duplicate = FALSE; + for (Index = 0; Index< DriverImageHandleCount; Index++) { + if (DriverImageHandleBuffer[Index] == OpenData->AgentHandle) { + Duplicate = TRUE; + break; + } + } + if (!Duplicate) { + DriverImageHandleBuffer[DriverImageHandleCount] = OpenData->AgentHandle; + DriverImageHandleCount++; + } + } + } + } + CoreReleaseProtocolLock (); + } + + StopCount = 0; + for (HandleIndex = 0; HandleIndex < DriverImageHandleCount; HandleIndex++) { + + if (DriverImageHandleBuffer != NULL) { + DriverImageHandle = DriverImageHandleBuffer[HandleIndex]; + } + + // + // Get the Driver Binding Protocol of the driver that is managing this controller + // + Status = CoreHandleProtocol ( + DriverImageHandle, + &gEfiDriverBindingProtocolGuid, + &DriverBinding + ); + if (EFI_ERROR (Status) || (DriverBinding == NULL)) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + // + // Look at each protocol interface for a match + // + DriverImageHandleValid = FALSE; + ChildBufferCount = 0; + + CoreAcquireProtocolLock (); + for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) { + Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE); + for (ProtLink = Prot->OpenList.ForwardLink; + ProtLink != &Prot->OpenList; + ProtLink = ProtLink->ForwardLink) { + OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE); + if (OpenData->AgentHandle == DriverImageHandle) { + if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) { + ChildBufferCount++; + } + if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) { + DriverImageHandleValid = TRUE; + } + } + } + } + CoreReleaseProtocolLock (); + + if (DriverImageHandleValid) { + ChildHandleValid = FALSE; + ChildBuffer = NULL; + if (ChildBufferCount != 0) { + ChildBuffer = CoreAllocateBootServicesPool (sizeof (EFI_HANDLE) * ChildBufferCount); + if (ChildBuffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + ChildBufferCount = 0; + + CoreAcquireProtocolLock (); + for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) { + Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE); + for (ProtLink = Prot->OpenList.ForwardLink; + ProtLink != &Prot->OpenList; + ProtLink = ProtLink->ForwardLink) { + OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE); + if ((OpenData->AgentHandle == DriverImageHandle) && + ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0)) { + Duplicate = FALSE; + for (Index = 0; Index < ChildBufferCount; Index++) { + if (ChildBuffer[Index] == OpenData->ControllerHandle) { + Duplicate = TRUE; + break; + } + } + if (!Duplicate) { + ChildBuffer[ChildBufferCount] = OpenData->ControllerHandle; + if (ChildHandle == ChildBuffer[ChildBufferCount]) { + ChildHandleValid = TRUE; + } + ChildBufferCount++; + } + } + } + } + CoreReleaseProtocolLock (); + } + + if (ChildHandle == NULL || ChildHandleValid) { + ChildrenToStop = 0; + Status = EFI_SUCCESS; + if (ChildBufferCount > 0) { + if (ChildHandle != NULL) { + ChildrenToStop = 1; + Status = DriverBinding->Stop (DriverBinding, ControllerHandle, ChildrenToStop, &ChildHandle); + } else { + ChildrenToStop = ChildBufferCount; + Status = DriverBinding->Stop (DriverBinding, ControllerHandle, ChildrenToStop, ChildBuffer); + } + } + if (!EFI_ERROR (Status) && ((ChildHandle == NULL) || (ChildBufferCount == ChildrenToStop))) { + Status = DriverBinding->Stop (DriverBinding, ControllerHandle, 0, NULL); + } + if (!EFI_ERROR (Status)) { + StopCount++; + } + } + + if (ChildBuffer != NULL) { + CoreFreePool (ChildBuffer); + } + } + } + + if (StopCount > 0) { + Status = EFI_SUCCESS; + } else { + Status = EFI_NOT_FOUND; + } + +Done: + + if (DriverImageHandleBuffer != NULL) { + CoreFreePool (DriverImageHandleBuffer); + } + + return Status; +} + + + +#ifdef FIRMWARE_PERFORMANCE +STATIC +EFI_STATUS +GetHandleFromDriverBinding ( + IN EFI_DRIVER_BINDING_PROTOCOL *DriverBindingNeed, + OUT EFI_HANDLE *Handle + ) +/*++ + +Routine Description: + + Locate the driver binding handle which a specified driver binding protocol installed on. + +Arguments: + + DriverBindingNeed - The specified driver binding protocol. + + Handle - The driver binding handle which the protocol installed on. + + +Returns: + + EFI_NOT_FOUND - Could not find the handle. + + EFI_SUCCESS - Successfully find the associated driver binding handle. + +--*/ + { + EFI_STATUS Status ; + EFI_DRIVER_BINDING_PROTOCOL *DriverBinding; + UINTN DriverBindingHandleCount; + EFI_HANDLE *DriverBindingHandleBuffer; + UINTN Index; + + DriverBindingHandleCount = 0; + DriverBindingHandleBuffer = NULL; + *Handle = NULL_HANDLE; + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiDriverBindingProtocolGuid, + NULL, + &DriverBindingHandleCount, + &DriverBindingHandleBuffer + ); + if (EFI_ERROR (Status) || DriverBindingHandleCount == 0) { + return EFI_NOT_FOUND; + } + + for (Index = 0 ; Index < DriverBindingHandleCount; Index++ ) { + Status = gBS->OpenProtocol( + DriverBindingHandleBuffer[Index], + &gEfiDriverBindingProtocolGuid, + &DriverBinding, + gDxeCoreImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (!EFI_ERROR (Status) && DriverBinding != NULL) { + + if ( DriverBinding == DriverBindingNeed ) { + *Handle = DriverBindingHandleBuffer[Index]; + CoreFreePool (DriverBindingHandleBuffer); + return EFI_SUCCESS ; + } + } + } + + CoreFreePool (DriverBindingHandleBuffer); + return EFI_NOT_FOUND ; +} +#endif \ No newline at end of file diff --git a/EDK/Foundation/Core/Dxe/Hand/Notify.c b/EDK/Foundation/Core/Dxe/Hand/Notify.c new file mode 100644 index 0000000..8b12657 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/Hand/Notify.c @@ -0,0 +1,335 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + notify.c + +Abstract: + + EFI notify infrastructure + + + +Revision History + +--*/ + +#include "hand.h" + + + +VOID +CoreNotifyProtocolEntry ( + IN PROTOCOL_ENTRY *ProtEntry + ) +/*++ + +Routine Description: + + Signal event for every protocol in protocol entry. + +Arguments: + + ProtEntry - Protocol entry + +Returns: + +--*/ +{ + PROTOCOL_NOTIFY *ProtNotify; + EFI_LIST_ENTRY *Link; + + ASSERT_LOCKED (&gProtocolDatabaseLock); + + for (Link=ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) { + ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE); + CoreSignalEvent (ProtNotify->Event); + } +} + + +PROTOCOL_INTERFACE * +CoreRemoveInterfaceFromProtocol ( + IN IHANDLE *Handle, + IN EFI_GUID *Protocol, + IN VOID *Interface + ) +/*++ + +Routine Description: + + Removes Protocol from the protocol list (but not the handle list). + +Arguments: + + Handle - The handle to remove protocol on. + + Protocol - GUID of the protocol to be moved + + Interface - The interface of the protocol + +Returns: + + Protocol Entry + +--*/ +{ + PROTOCOL_INTERFACE *Prot; + PROTOCOL_NOTIFY *ProtNotify; + PROTOCOL_ENTRY *ProtEntry; + EFI_LIST_ENTRY *Link; + + ASSERT_LOCKED (&gProtocolDatabaseLock); + + Prot = CoreFindProtocolInterface (Handle, Protocol, Interface); + if (Prot != NULL) { + + ProtEntry = Prot->Protocol; + + // + // If there's a protocol notify location pointing to this entry, back it up one + // + + for(Link = ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) { + ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE); + + if (ProtNotify->Position == &Prot->ByProtocol) { + ProtNotify->Position = Prot->ByProtocol.BackLink; + } + } + + // + // Remove the protocol interface entry + // + + RemoveEntryList (&Prot->ByProtocol); + } + + return Prot; +} + + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreRegisterProtocolNotify ( + IN EFI_GUID *Protocol, + IN EFI_EVENT Event, + OUT VOID **Registration + ) +/*++ + +Routine Description: + + Add a new protocol notification record for the request protocol. + +Arguments: + + Protocol - The requested protocol to add the notify registration + + Event - The event to signal + + Registration - Returns the registration record + + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_SUCCESS - Successfully returned the registration record that has been added + +--*/ +{ + PROTOCOL_ENTRY *ProtEntry; + PROTOCOL_NOTIFY *ProtNotify; + EFI_STATUS Status; + + if ((Protocol == NULL) || (Event == NULL) || (Registration == NULL)) { + return EFI_INVALID_PARAMETER; + } + + CoreAcquireProtocolLock (); + + ProtNotify = NULL; + + // + // Get the protocol entry to add the notification too + // + + ProtEntry = CoreFindProtocolEntry (Protocol, TRUE); + if (ProtEntry != NULL) { + + // + // Allocate a new notification record + // + + ProtNotify = CoreAllocateBootServicesPool (sizeof(PROTOCOL_NOTIFY)); + + if (ProtNotify != NULL) { + + ProtNotify->Signature = PROTOCOL_NOTIFY_SIGNATURE; + ProtNotify->Protocol = ProtEntry; + ProtNotify->Event = Event; + // + // start at the begining + // + ProtNotify->Position = &ProtEntry->Protocols; + + InsertTailList (&ProtEntry->Notify, &ProtNotify->Link); + } + } + + CoreReleaseProtocolLock (); + + // + // Done. If we have a protocol notify entry, then return it. + // Otherwise, we must have run out of resources trying to add one + // + + Status = EFI_OUT_OF_RESOURCES; + if (ProtNotify != NULL) { + *Registration = ProtNotify; + Status = EFI_SUCCESS; + } + + return Status; +} + + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreReinstallProtocolInterface ( + IN EFI_HANDLE UserHandle, + IN EFI_GUID *Protocol, + IN VOID *OldInterface, + IN VOID *NewInterface + ) +/*++ + +Routine Description: + + Reinstall a protocol interface on a device handle. The OldInterface for Protocol is replaced by the NewInterface. + +Arguments: + + UserHandle - Handle on which the interface is to be reinstalled + Protocol - The numeric ID of the interface + OldInterface - A pointer to the old interface + NewInterface - A pointer to the new interface + + +Returns: + + Status code. + + On EFI_SUCCESS The protocol interface was installed + On EFI_NOT_FOUND The OldInterface on the handle was not found + On EFI_INVALID_PARAMETER One of the parameters has an invalid value + +--*/ +{ + EFI_STATUS Status; + IHANDLE *Handle; + PROTOCOL_INTERFACE *Prot; + PROTOCOL_ENTRY *ProtEntry; + + Status = CoreValidateHandle (UserHandle); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Protocol == NULL) { + return EFI_INVALID_PARAMETER; + } + + Handle = (IHANDLE *) UserHandle; + + // + // Lock the protocol database + // + CoreAcquireProtocolLock (); + + // + // Check that Protocol exists on UserHandle, and Interface matches the interface in the database + // + Prot = CoreFindProtocolInterface (UserHandle, Protocol, OldInterface); + if (Prot == NULL) { + CoreReleaseProtocolLock (); + return EFI_NOT_FOUND; + } + + // + // Attempt to disconnect all drivers that are using the protocol interface that is about to be reinstalled + // + Status = CoreDisconnectControllersUsingProtocolInterface ( + UserHandle, + Prot + ); + if (EFI_ERROR (Status)) { + // + // One or more drivers refused to release, so return the error + // + CoreReleaseProtocolLock (); + return Status; + } + + // + // Remove the protocol interface from the protocol + // + Prot = CoreRemoveInterfaceFromProtocol (Handle, Protocol, OldInterface); + + if (Prot == NULL) { + CoreReleaseProtocolLock (); + return EFI_NOT_FOUND; + } + + ProtEntry = Prot->Protocol; + + // + // Update the interface on the protocol + // + Prot->Interface = NewInterface; + + // + // Add this protocol interface to the tail of the + // protocol entry + // + InsertTailList (&ProtEntry->Protocols, &Prot->ByProtocol); + + // + // Update the Key to show that the handle has been created/modified + // + gHandleDatabaseKey++; + Handle->Key = gHandleDatabaseKey; + + // + // Release the lock and connect all drivers to UserHandle + // + CoreReleaseProtocolLock (); + Status = CoreConnectController ( + UserHandle, + NULL, + NULL, + TRUE + ); + CoreAcquireProtocolLock (); + + // + // Notify the notification list for this protocol + // + CoreNotifyProtocolEntry (ProtEntry); + + CoreReleaseProtocolLock (); + + return EFI_SUCCESS; +} diff --git a/EDK/Foundation/Core/Dxe/Hand/hand.h b/EDK/Foundation/Core/Dxe/Hand/hand.h new file mode 100644 index 0000000..d048073 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/Hand/hand.h @@ -0,0 +1,339 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + hand.h + +Abstract: + + EFI internal protocol definitions + + + +Revision History + +--*/ + +#ifndef _HAND_H_ +#define _HAND_H_ + +#include "Tiano.h" +#include "DxeCore.h" + +// +// IHANDLE - contains a list of protocol handles +// + +#define EFI_HANDLE_SIGNATURE EFI_SIGNATURE_32('h','n','d','l') +typedef struct { + UINTN Signature; + EFI_LIST_ENTRY AllHandles; // All handles list of IHANDLE + EFI_LIST_ENTRY Protocols; // List of PROTOCOL_INTERFACE's for this handle + UINTN LocateRequest; // + UINT64 Key; // The Handle Database Key value when this handle was last created or modified +} IHANDLE; + +#define ASSERT_IS_HANDLE(a) ASSERT((a)->Signature == EFI_HANDLE_SIGNATURE) + + +// +// PROTOCOL_ENTRY - each different protocol has 1 entry in the protocol +// database. Each handler that supports this protocol is listed, along +// with a list of registered notifies. +// + +#define PROTOCOL_ENTRY_SIGNATURE EFI_SIGNATURE_32('p','r','t','e') +typedef struct { + UINTN Signature; + EFI_LIST_ENTRY AllEntries; // All entries + EFI_GUID ProtocolID; // ID of the protocol + EFI_LIST_ENTRY Protocols; // All protocol interfaces + EFI_LIST_ENTRY Notify; // Registerd notification handlers +} PROTOCOL_ENTRY; + +// +// PROTOCOL_INTERFACE - each protocol installed on a handle is tracked +// with a protocol interface structure +// + +#define PROTOCOL_INTERFACE_SIGNATURE EFI_SIGNATURE_32('p','i','f','c') +typedef struct { + UINTN Signature; + EFI_HANDLE Handle; // Back pointer + EFI_LIST_ENTRY Link; // Link on IHANDLE.Protocols + EFI_LIST_ENTRY ByProtocol; // Link on PROTOCOL_ENTRY.Protocols + PROTOCOL_ENTRY *Protocol; // The protocol ID + VOID *Interface; // The interface value + + EFI_LIST_ENTRY OpenList; // OPEN_PROTOCOL_DATA list. + UINTN OpenListCount; + + EFI_HANDLE ControllerHandle; + +} PROTOCOL_INTERFACE; + +#define OPEN_PROTOCOL_DATA_SIGNATURE EFI_SIGNATURE_32('p','o','d','l') + +typedef struct { + UINTN Signature; + EFI_LIST_ENTRY Link; + + EFI_HANDLE AgentHandle; + EFI_HANDLE ControllerHandle; + UINT32 Attributes; + UINT32 OpenCount; +} OPEN_PROTOCOL_DATA; + + +// +// PROTOCOL_NOTIFY - used for each register notification for a protocol +// + +#define PROTOCOL_NOTIFY_SIGNATURE EFI_SIGNATURE_32('p','r','t','n') +typedef struct { + UINTN Signature; + PROTOCOL_ENTRY *Protocol; + EFI_LIST_ENTRY Link; // All notifications for this protocol + EFI_EVENT Event; // Event to notify + EFI_LIST_ENTRY *Position; // Last position notified +} PROTOCOL_NOTIFY; + +// +// Internal prototypes +// + + +PROTOCOL_ENTRY * +CoreFindProtocolEntry ( + IN EFI_GUID *Protocol, + IN BOOLEAN Create + ) +/*++ + +Routine Description: + + Finds the protocol entry for the requested protocol. + + N.B. The gProtocolDatabaseLock must be owned + +Arguments: + + Protocol - The ID of the protocol + + Create - Create a new entry if not found + +Returns: + + Protocol entry + +--*/ +; + +VOID +CoreNotifyProtocolEntry ( + IN PROTOCOL_ENTRY *ProtEntry + ) +/*++ + +Routine Description: + + Signal event for every protocol in protocol entry. + +Arguments: + + ProtEntry - Protocol entry + +Returns: + +--*/ +; + +PROTOCOL_INTERFACE * +CoreFindProtocolInterface ( + IN IHANDLE *Handle, + IN EFI_GUID *Protocol, + IN VOID *Interface + ) +/*++ + +Routine Description: + + Finds the protocol instance for the requested handle and protocol. + + Note: This function doesn't do parameters checking, it's caller's responsibility + to pass in valid parameters. + +Arguments: + + Handle - The handle to search the protocol on + + Protocol - GUID of the protocol + + Interface - The interface for the protocol being searched + +Returns: + + Protocol instance (NULL: Not found) + +--*/ +; + +PROTOCOL_INTERFACE * +CoreRemoveInterfaceFromProtocol ( + IN IHANDLE *Handle, + IN EFI_GUID *Protocol, + IN VOID *Interface + ) +/*++ + +Routine Description: + + Removes Protocol from the protocol list (but not the handle list). + +Arguments: + + Handle - The handle to remove protocol on. + + Protocol - GUID of the protocol to be moved + + Interface - The interface of the protocol + +Returns: + + Protocol Entry + +--*/ +; + +EFI_STATUS +CoreUnregisterProtocolNotify ( + IN EFI_EVENT Event + ) +/*++ + +Routine Description: + + Removes all the events in the protocol database that match Event. + +Arguments: + + Event - The event to search for in the protocol database. + +Returns: + + EFI_SUCCESS when done searching the entire database. + +--*/ +; + +EFI_STATUS +CoreDisconnectControllersUsingProtocolInterface ( + IN EFI_HANDLE UserHandle, + IN PROTOCOL_INTERFACE *Prot + ) +/*++ + +Routine Description: + + Attempts to disconnect all drivers that are using the protocol interface being queried. + If failed, reconnect all drivers disconnected. + + Note: This function doesn't do parameters checking, it's caller's responsibility + to pass in valid parameters. + +Arguments: + + UserHandle - The handle on which the protocol is installed + Prot - The protocol to disconnect drivers from + +Returns: + + EFI_SUCCESS - Drivers using the protocol interface are all disconnected + EFI_ACCESS_DENIED - Failed to disconnect one or all of the drivers + +--*/ +; + +VOID +CoreAcquireProtocolLock ( + VOID + ) +/*++ + +Routine Description: + + Acquire lock on gProtocolDatabaseLock. + +Arguments: + + None + +Returns: + + None + +--*/ +; + +VOID +CoreReleaseProtocolLock ( + VOID + ) +/*++ + +Routine Description: + + Release lock on gProtocolDatabaseLock. + +Arguments: + + None + +Returns: + + None + +--*/ +; + +EFI_STATUS +CoreValidateHandle ( + IN EFI_HANDLE UserHandle + ) +/*++ + +Routine Description: + + Check whether a handle is a valid EFI_HANDLE + +Arguments: + + UserHandle - The handle to check + +Returns: + + EFI_INVALID_PARAMETER - The handle is NULL or not a valid EFI_HANDLE. + + EFI_SUCCESS - The handle is valid EFI_HANDLE. + +--*/ +; + +// +// Externs +// + +extern EFI_LOCK gProtocolDatabaseLock; +extern EFI_LIST_ENTRY gHandleList; +extern UINT64 gHandleDatabaseKey; + +#endif diff --git a/EDK/Foundation/Core/Dxe/Hand/handle.c b/EDK/Foundation/Core/Dxe/Hand/handle.c new file mode 100644 index 0000000..45874b4 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/Hand/handle.c @@ -0,0 +1,1716 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + handle.c + +Abstract: + + EFI handle & protocol handling + + + +Revision History + +--*/ + +#include "hand.h" +#include EFI_PROTOCOL_DEFINITION (DevicePath) +#include EFI_PROTOCOL_DEFINITION (LoadedImage) +#include EFI_PROTOCOL_DEFINITION (DebugMask) + +// +// mProtocolDatabase - A list of all protocols in the system. (simple list for now) +// gHandleList - A list of all the handles in the system +// gProtocolDatabaseLock - Lock to protect the mProtocolDatabase +// gHandleDatabaseKey - The Key to show that the handle has been created/modified +// +static EFI_LIST_ENTRY mProtocolDatabase = INITIALIZE_LIST_HEAD_VARIABLE (mProtocolDatabase); +EFI_LIST_ENTRY gHandleList = INITIALIZE_LIST_HEAD_VARIABLE (gHandleList); +EFI_LOCK gProtocolDatabaseLock = EFI_INITIALIZE_LOCK_VARIABLE (EFI_TPL_NOTIFY); +UINT64 gHandleDatabaseKey = 0; + + +VOID +CoreAcquireProtocolLock ( + VOID + ) +/*++ + +Routine Description: + + Acquire lock on gProtocolDatabaseLock. + +Arguments: + + None + +Returns: + + None + +--*/ +{ + CoreAcquireLock (&gProtocolDatabaseLock); +} + + +VOID +CoreReleaseProtocolLock ( + VOID + ) +/*++ + +Routine Description: + + Release lock on gProtocolDatabaseLock. + +Arguments: + + None + +Returns: + + None + +--*/ +{ + CoreReleaseLock (&gProtocolDatabaseLock); +} + + +EFI_STATUS +CoreValidateHandle ( + IN EFI_HANDLE UserHandle + ) +/*++ + +Routine Description: + + Check whether a handle is a valid EFI_HANDLE + +Arguments: + + UserHandle - The handle to check + +Returns: + + EFI_INVALID_PARAMETER - The handle is NULL or not a valid EFI_HANDLE. + + EFI_SUCCESS - The handle is valid EFI_HANDLE. + +--*/ +{ + IHANDLE *Handle; + + Handle = (IHANDLE *)UserHandle; + if (Handle == NULL) { + return EFI_INVALID_PARAMETER; + } + if (Handle->Signature != EFI_HANDLE_SIGNATURE) { + return EFI_INVALID_PARAMETER; + } + return EFI_SUCCESS; +} + + +PROTOCOL_ENTRY * +CoreFindProtocolEntry ( + IN EFI_GUID *Protocol, + IN BOOLEAN Create + ) +/*++ + +Routine Description: + + Finds the protocol entry for the requested protocol. + + N.B. The gProtocolDatabaseLock must be owned + +Arguments: + + Protocol - The ID of the protocol + + Create - Create a new entry if not found + +Returns: + + Protocol entry + +--*/ +{ + EFI_LIST_ENTRY *Link; + PROTOCOL_ENTRY *Item; + PROTOCOL_ENTRY *ProtEntry; + + ASSERT_LOCKED(&gProtocolDatabaseLock); + + // + // Search the database for the matching GUID + // + + ProtEntry = NULL; + for (Link = mProtocolDatabase.ForwardLink; + Link != &mProtocolDatabase; + Link = Link->ForwardLink) { + + Item = CR(Link, PROTOCOL_ENTRY, AllEntries, PROTOCOL_ENTRY_SIGNATURE); + if (EfiCompareGuid (&Item->ProtocolID, Protocol)) { + + // + // This is the protocol entry + // + + ProtEntry = Item; + break; + } + } + + // + // If the protocol entry was not found and Create is TRUE, then + // allocate a new entry + // + if ((ProtEntry == NULL) && Create) { + ProtEntry = CoreAllocateBootServicesPool (sizeof(PROTOCOL_ENTRY)); + + if (ProtEntry != NULL) { + // + // Initialize new protocol entry structure + // + ProtEntry->Signature = PROTOCOL_ENTRY_SIGNATURE; + ProtEntry->ProtocolID = *Protocol; + InitializeListHead (&ProtEntry->Protocols); + InitializeListHead (&ProtEntry->Notify); + + // + // Add it to protocol database + // + InsertTailList (&mProtocolDatabase, &ProtEntry->AllEntries); + } + } + + return ProtEntry; +} + + +PROTOCOL_INTERFACE * +CoreFindProtocolInterface ( + IN IHANDLE *Handle, + IN EFI_GUID *Protocol, + IN VOID *Interface + ) +/*++ + +Routine Description: + + Finds the protocol instance for the requested handle and protocol. + + Note: This function doesn't do parameters checking, it's caller's responsibility + to pass in valid parameters. + +Arguments: + + Handle - The handle to search the protocol on + + Protocol - GUID of the protocol + + Interface - The interface for the protocol being searched + +Returns: + + Protocol instance (NULL: Not found) + +--*/ +{ + PROTOCOL_INTERFACE *Prot; + PROTOCOL_ENTRY *ProtEntry; + EFI_LIST_ENTRY *Link; + + ASSERT_LOCKED(&gProtocolDatabaseLock); + Prot = NULL; + + // + // Lookup the protocol entry for this protocol ID + // + + ProtEntry = CoreFindProtocolEntry (Protocol, FALSE); + if (ProtEntry != NULL) { + + // + // Look at each protocol interface for any matches + // + for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link=Link->ForwardLink) { + + // + // If this protocol interface matches, remove it + // + Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE); + if (Prot->Interface == Interface && Prot->Protocol == ProtEntry) { + break; + } + + Prot = NULL; + } + } + + return Prot; +} + +STATIC +EFI_STATUS +CoreUnregisterProtocolNotifyEvent ( + IN EFI_EVENT Event + ) +/*++ + +Routine Description: + + Removes an event from a register protocol notify list on a protocol. + +Arguments: + + Event - The event to search for in the protocol database. + +Returns: + + EFI_SUCCESS if the event was found and removed. + EFI_NOT_FOUND if the event was not found in the protocl database. + +--*/ +{ + EFI_LIST_ENTRY *Link; + PROTOCOL_ENTRY *ProtEntry; + EFI_LIST_ENTRY *NotifyLink; + PROTOCOL_NOTIFY *ProtNotify; + + CoreAcquireProtocolLock (); + + for ( Link = mProtocolDatabase.ForwardLink; + Link != &mProtocolDatabase; + Link = Link->ForwardLink) { + + ProtEntry = CR(Link, PROTOCOL_ENTRY, AllEntries, PROTOCOL_ENTRY_SIGNATURE); + + for ( NotifyLink = ProtEntry->Notify.ForwardLink; + NotifyLink != &ProtEntry->Notify; + NotifyLink = NotifyLink->ForwardLink) { + + ProtNotify = CR(NotifyLink, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE); + + if (ProtNotify->Event == Event) { + RemoveEntryList(&ProtNotify->Link); + CoreFreePool(ProtNotify); + CoreReleaseProtocolLock (); + return EFI_SUCCESS; + } + } + } + + CoreReleaseProtocolLock (); + return EFI_NOT_FOUND; +} + + +EFI_STATUS +CoreUnregisterProtocolNotify ( + IN EFI_EVENT Event + ) +/*++ + +Routine Description: + + Removes all the events in the protocol database that match Event. + +Arguments: + + Event - The event to search for in the protocol database. + +Returns: + + EFI_SUCCESS when done searching the entire database. + +--*/ +{ + EFI_STATUS Status; + + do { + Status = CoreUnregisterProtocolNotifyEvent (Event); + } while (!EFI_ERROR (Status)); + + return EFI_SUCCESS; +} + + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreInstallProtocolInterface ( + IN OUT EFI_HANDLE *UserHandle, + IN EFI_GUID *Protocol, + IN EFI_INTERFACE_TYPE InterfaceType, + IN VOID *Interface + ) +/*++ + +Routine Description: + + Wrapper function to CoreInstallProtocolInterfaceNotify. This is the public API which + Calls the private one which contains a BOOLEAN parameter for notifications + +Arguments: + + UserHandle - The handle to install the protocol handler on, + or NULL if a new handle is to be allocated + + Protocol - The protocol to add to the handle + + InterfaceType - Indicates whether Interface is supplied in native form. + + Interface - The interface for the protocol being added + +Returns: + + Status code + +--*/ +{ + return CoreInstallProtocolInterfaceNotify ( + UserHandle, + Protocol, + InterfaceType, + Interface, + TRUE + ); +} + +EFI_STATUS +CoreInstallProtocolInterfaceNotify ( + IN OUT EFI_HANDLE *UserHandle, + IN EFI_GUID *Protocol, + IN EFI_INTERFACE_TYPE InterfaceType, + IN VOID *Interface, + IN BOOLEAN Notify + ) +/*++ + +Routine Description: + + Installs a protocol interface into the boot services environment. + +Arguments: + + UserHandle - The handle to install the protocol handler on, + or NULL if a new handle is to be allocated + + Protocol - The protocol to add to the handle + + InterfaceType - Indicates whether Interface is supplied in native form. + + Interface - The interface for the protocol being added + + Notify - indicates whether notify the notification list + for this protocol + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_OUT_OF_RESOURCES - No enough buffer to allocate + + EFI_SUCCESS - Protocol interface successfully installed + +--*/ +{ + PROTOCOL_INTERFACE *Prot; + PROTOCOL_ENTRY *ProtEntry; + IHANDLE *Handle; + EFI_STATUS Status; + VOID *ExistingInterface; + + DEBUG_CODE ( + UINTN ErrorLevel; + ) + + // + // returns EFI_INVALID_PARAMETER if InterfaceType is invalid. + // Also added check for invalid UserHandle and Protocol pointers. + // + if (UserHandle == NULL || Protocol == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (InterfaceType != EFI_NATIVE_INTERFACE) { + return EFI_INVALID_PARAMETER; + } + + // + // Print debug message + // + DEBUG_CODE ( + if (EfiCompareGuid (Protocol, &gEfiLoadedImageProtocolGuid) || + EfiCompareGuid (Protocol, &gEfiDebugMaskProtocolGuid)) { + // + // Print these protocols only at EFI_D_INFO level, for cleaner log. + // They are installed for every DXE driver. + // + ErrorLevel = EFI_D_INFO; + } else { + ErrorLevel = EFI_D_ERROR; + } + DEBUG ((ErrorLevel, "InstallProtocolInterface: %g %x\n", Protocol, Interface)); + ) + Status = EFI_OUT_OF_RESOURCES; + Prot = NULL; + Handle = NULL; + + ASSERT (NULL != gBS); + + if (*UserHandle != NULL_HANDLE) { + Status = CoreHandleProtocol (*UserHandle, Protocol, (VOID **)&ExistingInterface); + if (!EFI_ERROR (Status)) { + return EFI_INVALID_PARAMETER; + } + } + + // + // Lock the protocol database + // + CoreAcquireProtocolLock (); + + // + // Lookup the Protocol Entry for the requested protocol + // + ProtEntry = CoreFindProtocolEntry (Protocol, TRUE); + if (ProtEntry == NULL) { + goto Done; + } + + // + // Allocate a new protocol interface structure + // + Prot = CoreAllocateZeroBootServicesPool (sizeof(PROTOCOL_INTERFACE)); + if (Prot == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + // + // If caller didn't supply a handle, allocate a new one + // + Handle = (IHANDLE *)*UserHandle; + if (Handle == NULL) { + Handle = CoreAllocateZeroBootServicesPool (sizeof(IHANDLE)); + if (Handle == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + // + // Initialize new handler structure + // + Handle->Signature = EFI_HANDLE_SIGNATURE; + InitializeListHead (&Handle->Protocols); + + // + // Initialize the Key to show that the handle has been created/modified + // + gHandleDatabaseKey++; + Handle->Key = gHandleDatabaseKey; + + // + // Add this handle to the list global list of all handles + // in the system + // + InsertTailList (&gHandleList, &Handle->AllHandles); + } + + Status = CoreValidateHandle (Handle); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Each interface that is added must be unique + // + ASSERT (CoreFindProtocolInterface (Handle, Protocol, Interface) == NULL); + + // + // Initialize the protocol interface structure + // + Prot->Signature = PROTOCOL_INTERFACE_SIGNATURE; + Prot->Handle = Handle; + Prot->Protocol = ProtEntry; + Prot->Interface = Interface; + + // + // Initalize OpenProtocol Data base + // + InitializeListHead (&Prot->OpenList); + Prot->OpenListCount = 0; + + // + // Add this protocol interface to the head of the supported + // protocol list for this handle + // + InsertHeadList (&Handle->Protocols, &Prot->Link); + + // + // Add this protocol interface to the tail of the + // protocol entry + // + InsertTailList (&ProtEntry->Protocols, &Prot->ByProtocol); + + // + // Notify the notification list for this protocol + // + if (Notify) { + CoreNotifyProtocolEntry (ProtEntry); + } + Status = EFI_SUCCESS; + +Done: + // + // Done, unlock the database and return + // + CoreReleaseProtocolLock (); + if (!EFI_ERROR (Status)) { + // + // Return the new handle back to the caller + // + *UserHandle = Handle; + } else { + // + // There was an error, clean up + // + if (Prot != NULL) { + CoreFreePool (Prot); + } + } + + return Status; +} + + +EFI_BOOTSERVICE11 +EFI_STATUS +EFIAPI +CoreInstallMultipleProtocolInterfaces ( + IN OUT EFI_HANDLE *Handle, + ... + ) +/*++ + +Routine Description: + + Installs a list of protocol interface into the boot services environment. + This function calls InstallProtocolInterface() in a loop. If any error + occures all the protocols added by this function are removed. This is + basically a lib function to save space. + +Arguments: + + Handle - The handle to install the protocol handlers on, + or NULL if a new handle is to be allocated + ... - EFI_GUID followed by protocol instance. A NULL terminates the + list. The pairs are the arguments to InstallProtocolInterface(). + All the protocols are added to Handle. + +Returns: + + EFI_INVALID_PARAMETER - Handle is NULL. + + EFI_SUCCESS - Protocol interfaces successfully installed. + +--*/ +{ + VA_LIST args; + EFI_STATUS Status; + EFI_GUID *Protocol; + VOID *Interface; + EFI_TPL OldTpl; + UINTN Index; + EFI_HANDLE OldHandle; + EFI_HANDLE DeviceHandle; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + if (Handle == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Syncronize with notifcations. + // + OldTpl = CoreRaiseTpl (EFI_TPL_NOTIFY); + OldHandle = *Handle; + + // + // Check for duplicate device path and install the protocol interfaces + // + VA_START (args, Handle); + for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) { + // + // If protocol is NULL, then it's the end of the list + // + Protocol = VA_ARG (args, EFI_GUID *); + if (Protocol == NULL) { + break; + } + + Interface = VA_ARG (args, VOID *); + + // + // Make sure you are installing on top a device path that has already been added. + // + if (EfiCompareGuid (Protocol, &gEfiDevicePathProtocolGuid)) { + DeviceHandle = NULL; + DevicePath = Interface; + Status = CoreLocateDevicePath (&gEfiDevicePathProtocolGuid, &DevicePath, &DeviceHandle); + if (!EFI_ERROR (Status) && (DeviceHandle != NULL_HANDLE) && IsDevicePathEnd(DevicePath)) { + Status = EFI_ALREADY_STARTED; + continue; + } + } + + // + // Install it + // + Status = CoreInstallProtocolInterface (Handle, Protocol, EFI_NATIVE_INTERFACE, Interface); + } + + // + // If there was an error, remove all the interfaces that were installed without any errors + // + if (EFI_ERROR (Status)) { + // + // Reset the va_arg back to the first argument. + // + VA_START (args, Handle); + for (; Index > 1; Index--) { + Protocol = VA_ARG (args, EFI_GUID *); + Interface = VA_ARG (args, VOID *); + CoreUninstallProtocolInterface (*Handle, Protocol, Interface); + } + *Handle = OldHandle; + } + + // + // Done + // + CoreRestoreTpl (OldTpl); + return Status; +} + +EFI_STATUS +CoreDisconnectControllersUsingProtocolInterface ( + IN EFI_HANDLE UserHandle, + IN PROTOCOL_INTERFACE *Prot + ) +/*++ + +Routine Description: + + Attempts to disconnect all drivers that are using the protocol interface being queried. + If failed, reconnect all drivers disconnected. + + Note: This function doesn't do parameters checking, it's caller's responsibility + to pass in valid parameters. + +Arguments: + + UserHandle - The handle on which the protocol is installed + Prot - The protocol to disconnect drivers from + +Returns: + + EFI_SUCCESS - Drivers using the protocol interface are all disconnected + EFI_ACCESS_DENIED - Failed to disconnect one or all of the drivers + +--*/ +{ + EFI_STATUS Status; + BOOLEAN ItemFound; + EFI_LIST_ENTRY *Link; + OPEN_PROTOCOL_DATA *OpenData; + + Status = EFI_SUCCESS; + + // + // Attempt to disconnect all drivers from this protocol interface + // + do { + ItemFound = FALSE; + for ( Link = Prot->OpenList.ForwardLink; + (Link != &Prot->OpenList) && !ItemFound; + Link = Link->ForwardLink ) { + OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE); + if (OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) { + ItemFound = TRUE; + CoreReleaseProtocolLock (); + Status = CoreDisconnectController (UserHandle, OpenData->AgentHandle, NULL); + CoreAcquireProtocolLock (); + if (EFI_ERROR (Status)) { + ItemFound = FALSE; + break; + } + } + } + } while (ItemFound); + + if (!EFI_ERROR (Status)) { + // + // Attempt to remove BY_HANDLE_PROTOOCL and GET_PROTOCOL and TEST_PROTOCOL Open List items + // + do { + ItemFound = FALSE; + for ( Link = Prot->OpenList.ForwardLink; + (Link != &Prot->OpenList) && !ItemFound; + Link = Link->ForwardLink ) { + OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE); + if (OpenData->Attributes & + (EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL | EFI_OPEN_PROTOCOL_GET_PROTOCOL | EFI_OPEN_PROTOCOL_TEST_PROTOCOL)) { + ItemFound = TRUE; + RemoveEntryList (&OpenData->Link); + Prot->OpenListCount--; + CoreFreePool (OpenData); + } + } + } while (ItemFound); + } + + // + // If there are errors or still has open items in the list, then reconnect all the drivers and return an error + // + if (EFI_ERROR (Status) || (Prot->OpenListCount > 0)) { + CoreReleaseProtocolLock (); + CoreConnectController (UserHandle, NULL, NULL, TRUE); + CoreAcquireProtocolLock (); + Status = EFI_ACCESS_DENIED; + } + + return Status; +} + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreUninstallProtocolInterface ( + IN EFI_HANDLE UserHandle, + IN EFI_GUID *Protocol, + IN VOID *Interface + ) +/*++ + +Routine Description: + + Uninstalls all instances of a protocol:interfacer from a handle. + If the last protocol interface is remove from the handle, the + handle is freed. + +Arguments: + + UserHandle - The handle to remove the protocol handler from + + Protocol - The protocol, of protocol:interface, to remove + + Interface - The interface, of protocol:interface, to remove + +Returns: + + EFI_INVALID_PARAMETER - Protocol is NULL. + + EFI_SUCCESS - Protocol interface successfully uninstalled. + +--*/ +{ + EFI_STATUS Status; + IHANDLE *Handle; + PROTOCOL_INTERFACE *Prot; + + // + // Check that Protocol is valid + // + if (Protocol == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Check that UserHandle is a valid handle + // + Status = CoreValidateHandle (UserHandle); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Lock the protocol database + // + CoreAcquireProtocolLock (); + + // + // Check that Protocol exists on UserHandle, and Interface matches the interface in the database + // + Prot = CoreFindProtocolInterface (UserHandle, Protocol, Interface); + if (Prot == NULL) { + Status = EFI_NOT_FOUND; + goto Done; + } + + // + // Attempt to disconnect all drivers that are using the protocol interface that is about to be removed + // + Status = CoreDisconnectControllersUsingProtocolInterface ( + UserHandle, + Prot + ); + if (EFI_ERROR (Status)) { + // + // One or more drivers refused to release, so return the error + // + goto Done; + } + + // + // Remove the protocol interface from the protocol + // + Status = EFI_NOT_FOUND; + Handle = (IHANDLE *)UserHandle; + Prot = CoreRemoveInterfaceFromProtocol (Handle, Protocol, Interface); + + if (Prot != NULL) { + // + // Update the Key to show that the handle has been created/modified + // + gHandleDatabaseKey++; + Handle->Key = gHandleDatabaseKey; + + // + // Remove the protocol interface from the handle + // + RemoveEntryList (&Prot->Link); + + // + // Free the memory + // + Prot->Signature = 0; + CoreFreePool (Prot); + Status = EFI_SUCCESS; + } + + // + // If there are no more handlers for the handle, free the handle + // + if (IsListEmpty (&Handle->Protocols)) { + Handle->Signature = 0; + RemoveEntryList (&Handle->AllHandles); + CoreFreePool (Handle); + } + +Done: + // + // Done, unlock the database and return + // + CoreReleaseProtocolLock (); + return Status; +} + + +EFI_BOOTSERVICE11 +EFI_STATUS +EFIAPI +CoreUninstallMultipleProtocolInterfaces ( + IN EFI_HANDLE Handle, + ... + ) +/*++ + +Routine Description: + + Uninstalls a list of protocol interface in the boot services environment. + This function calls UnisatllProtocolInterface() in a loop. This is + basically a lib function to save space. + +Arguments: + + Handle - The handle to uninstall the protocol + + ... - EFI_GUID followed by protocol instance. A NULL terminates the + list. The pairs are the arguments to UninstallProtocolInterface(). + All the protocols are added to Handle. + +Returns: + + Status code + +--*/ +{ + EFI_STATUS Status; + VA_LIST args; + EFI_GUID *Protocol; + VOID *Interface; + UINTN Index; + + VA_START (args, Handle); + for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) { + // + // If protocol is NULL, then it's the end of the list + // + Protocol = VA_ARG (args, EFI_GUID *); + if (Protocol == NULL) { + break; + } + + Interface = VA_ARG (args, VOID *); + + // + // Uninstall it + // + Status = CoreUninstallProtocolInterface (Handle, Protocol, Interface); + } + + // + // If there was an error, add all the interfaces that were + // uninstalled without any errors + // + if (EFI_ERROR (Status)) { + // + // Reset the va_arg back to the first argument. + // + VA_START (args, Handle); + for (; Index > 1; Index--) { + Protocol = VA_ARG(args, EFI_GUID *); + Interface = VA_ARG(args, VOID *); + CoreInstallProtocolInterface (&Handle, Protocol, EFI_NATIVE_INTERFACE, Interface); + } + } + + return Status; +} + +PROTOCOL_INTERFACE * +CoreGetProtocolInterface ( + IN EFI_HANDLE UserHandle, + IN EFI_GUID *Protocol + ) +/*++ + +Routine Description: + + Locate a certain GUID protocol interface in a Handle's protocols. + +Arguments: + + UserHandle - The handle to obtain the protocol interface on + + Protocol - The GUID of the protocol + +Returns: + + The requested protocol interface for the handle + +--*/ +{ + EFI_STATUS Status; + PROTOCOL_ENTRY *ProtEntry; + PROTOCOL_INTERFACE *Prot; + IHANDLE *Handle; + EFI_LIST_ENTRY *Link; + + Status = CoreValidateHandle (UserHandle); + if (EFI_ERROR (Status)) { + return NULL; + } + + Handle = (IHANDLE *)UserHandle; + + // + // Look at each protocol interface for a match + // + for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) { + Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE); + ProtEntry = Prot->Protocol; + if (EfiCompareGuid (&ProtEntry->ProtocolID, Protocol)) { + return Prot; + } + } + return NULL; +} + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreHandleProtocol ( + IN EFI_HANDLE UserHandle, + IN EFI_GUID *Protocol, + OUT VOID **Interface + ) +/*++ + +Routine Description: + + Queries a handle to determine if it supports a specified protocol. + +Arguments: + + UserHandle - The handle being queried. + + Protocol - The published unique identifier of the protocol. + + Interface - Supplies the address where a pointer to the corresponding Protocol + Interface is returned. + +Returns: + + The requested protocol interface for the handle + +--*/ +{ + return CoreOpenProtocol ( + UserHandle, + Protocol, + Interface, + gDxeCoreImageHandle, + NULL, + EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL + ); +} + +EFI_BOOTSERVICE11 +EFI_STATUS +EFIAPI +CoreOpenProtocol ( + IN EFI_HANDLE UserHandle, + IN EFI_GUID *Protocol, + OUT VOID **Interface OPTIONAL, + IN EFI_HANDLE ImageHandle, + IN EFI_HANDLE ControllerHandle, + IN UINT32 Attributes + ) +/*++ + +Routine Description: + + Locates the installed protocol handler for the handle, and + invokes it to obtain the protocol interface. Usage information + is registered in the protocol data base. + +Arguments: + + UserHandle - The handle to obtain the protocol interface on + + Protocol - The ID of the protocol + + Interface - The location to return the protocol interface + + ImageHandle - The handle of the Image that is opening the protocol interface + specified by Protocol and Interface. + + ControllerHandle - The controller handle that is requiring this interface. + + Attributes - The open mode of the protocol interface specified by Handle + and Protocol. + +Returns: + + EFI_INVALID_PARAMETER - Protocol is NULL. + + EFI_SUCCESS - Get the protocol interface. + +--*/ +{ + EFI_STATUS Status; + PROTOCOL_INTERFACE *Prot; + EFI_LIST_ENTRY *Link; + OPEN_PROTOCOL_DATA *OpenData; + BOOLEAN ByDriver; + BOOLEAN Exclusive; + BOOLEAN Disconnect; + BOOLEAN ExactMatch; + + // + // Check for invalid Protocol + // + if (Protocol == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Check for invalid Interface + // + if (Attributes != EFI_OPEN_PROTOCOL_TEST_PROTOCOL) { + if (Interface == NULL) { + return EFI_INVALID_PARAMETER; + } else { + *Interface = NULL; + } + } + + // + // Check for invalid UserHandle + // + Status = CoreValidateHandle (UserHandle); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Check for invalid Attributes + // + switch (Attributes) { + case EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER : + Status = CoreValidateHandle (ImageHandle); + if (EFI_ERROR (Status)) { + return Status; + } + Status = CoreValidateHandle (ControllerHandle); + if (EFI_ERROR (Status)) { + return Status; + } + if (UserHandle == ControllerHandle) { + return EFI_INVALID_PARAMETER; + } + break; + case EFI_OPEN_PROTOCOL_BY_DRIVER : + case EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE : + Status = CoreValidateHandle (ImageHandle); + if (EFI_ERROR (Status)) { + return Status; + } + Status = CoreValidateHandle (ControllerHandle); + if (EFI_ERROR (Status)) { + return Status; + } + break; + case EFI_OPEN_PROTOCOL_EXCLUSIVE : + Status = CoreValidateHandle (ImageHandle); + if (EFI_ERROR (Status)) { + return Status; + } + break; + case EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL : + case EFI_OPEN_PROTOCOL_GET_PROTOCOL : + case EFI_OPEN_PROTOCOL_TEST_PROTOCOL : + break; + default: + return EFI_INVALID_PARAMETER; + } + + // + // Lock the protocol database + // + CoreAcquireProtocolLock (); + + // + // Look at each protocol interface for a match + // + Prot = CoreGetProtocolInterface (UserHandle, Protocol); + if (Prot == NULL) { + Status = EFI_UNSUPPORTED; + goto Done; + } + + // + // This is the protocol interface entry for this protocol + // + if (Attributes != EFI_OPEN_PROTOCOL_TEST_PROTOCOL) { + *Interface = Prot->Interface; + } + Status = EFI_SUCCESS; + + ByDriver = FALSE; + Exclusive = FALSE; + for ( Link = Prot->OpenList.ForwardLink; Link != &Prot->OpenList; Link = Link->ForwardLink) { + OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE); + ExactMatch = (BOOLEAN)((OpenData->AgentHandle == ImageHandle) && + (OpenData->Attributes == Attributes) && + (OpenData->ControllerHandle == ControllerHandle)); + if (OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) { + ByDriver = TRUE; + if (ExactMatch) { + Status = EFI_ALREADY_STARTED; + goto Done; + } + } + if (OpenData->Attributes & EFI_OPEN_PROTOCOL_EXCLUSIVE) { + Exclusive = TRUE; + } else if (ExactMatch) { + OpenData->OpenCount++; + Status = EFI_SUCCESS; + goto Done; + } + } + + // + // ByDriver TRUE -> A driver is managing (UserHandle, Protocol) + // ByDriver FALSE -> There are no drivers managing (UserHandle, Protocol) + // Exclusive TRUE -> Something has exclusive access to (UserHandle, Protocol) + // Exclusive FALSE -> Nothing has exclusive access to (UserHandle, Protocol) + // + + switch (Attributes) { + case EFI_OPEN_PROTOCOL_BY_DRIVER : + if (Exclusive || ByDriver) { + Status = EFI_ACCESS_DENIED; + goto Done; + } + break; + case EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE : + case EFI_OPEN_PROTOCOL_EXCLUSIVE : + if (Exclusive) { + Status = EFI_ACCESS_DENIED; + goto Done; + } + if (ByDriver) { + do { + Disconnect = FALSE; + for ( Link = Prot->OpenList.ForwardLink; (Link != &Prot->OpenList) && (!Disconnect); Link = Link->ForwardLink) { + OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE); + if (OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) { + Disconnect = TRUE; + CoreReleaseProtocolLock (); + Status = CoreDisconnectController (UserHandle, OpenData->AgentHandle, NULL); + CoreAcquireProtocolLock (); + if (EFI_ERROR (Status)) { + Status = EFI_ACCESS_DENIED; + goto Done; + } + } + } + } while (Disconnect); + } + break; + case EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER : + case EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL : + case EFI_OPEN_PROTOCOL_GET_PROTOCOL : + case EFI_OPEN_PROTOCOL_TEST_PROTOCOL : + break; + } + + if (ImageHandle == NULL) { + Status = EFI_SUCCESS; + goto Done; + } + // + // Create new entry + // + OpenData = CoreAllocateBootServicesPool (sizeof(OPEN_PROTOCOL_DATA)); + if (OpenData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } else { + OpenData->Signature = OPEN_PROTOCOL_DATA_SIGNATURE; + OpenData->AgentHandle = ImageHandle; + OpenData->ControllerHandle = ControllerHandle; + OpenData->Attributes = Attributes; + OpenData->OpenCount = 1; + InsertTailList (&Prot->OpenList, &OpenData->Link); + Prot->OpenListCount++; + Status = EFI_SUCCESS; + } + +Done: + // + // Done. Release the database lock are return + // + CoreReleaseProtocolLock (); + return Status; +} + +EFI_BOOTSERVICE11 +EFI_STATUS +EFIAPI +CoreCloseProtocol ( + IN EFI_HANDLE UserHandle, + IN EFI_GUID *Protocol, + IN EFI_HANDLE AgentHandle, + IN EFI_HANDLE ControllerHandle + ) +/*++ + +Routine Description: + + Closes a protocol on a handle that was opened using OpenProtocol(). + +Arguments: + + UserHandle - The handle for the protocol interface that was previously opened + with OpenProtocol(), and is now being closed. + Protocol - The published unique identifier of the protocol. It is the caller¡¯s + responsibility to pass in a valid GUID. + AgentHandle - The handle of the agent that is closing the protocol interface. + ControllerHandle - If the agent that opened a protocol is a driver that follows the + EFI Driver Model, then this parameter is the controller handle + that required the protocol interface. If the agent does not follow + the EFI Driver Model, then this parameter is optional and may be NULL. + +Returns: + + EFI_SUCCESS - The protocol instance was closed. + EFI_INVALID_PARAMETER - Handle, AgentHandle or ControllerHandle is not a valid EFI_HANDLE. + EFI_NOT_FOUND - Can not find the specified protocol or AgentHandle. + +--*/ +{ + EFI_STATUS Status; + PROTOCOL_INTERFACE *ProtocolInterface; + EFI_LIST_ENTRY *Link; + OPEN_PROTOCOL_DATA *OpenData; + + // + // Check for invalid parameters + // + Status = CoreValidateHandle (UserHandle); + if (EFI_ERROR (Status)) { + return Status; + } + Status = CoreValidateHandle (AgentHandle); + if (EFI_ERROR (Status)) { + return Status; + } + if (ControllerHandle != NULL_HANDLE) { + Status = CoreValidateHandle (ControllerHandle); + if (EFI_ERROR (Status)) { + return Status; + } + } + if (Protocol == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Lock the protocol database + // + CoreAcquireProtocolLock (); + + // + // Look at each protocol interface for a match + // + Status = EFI_NOT_FOUND; + ProtocolInterface = CoreGetProtocolInterface (UserHandle, Protocol); + if (ProtocolInterface == NULL) { + goto Done; + } + + // + // Walk the Open data base looking for AgentHandle + // + Link = ProtocolInterface->OpenList.ForwardLink; + while (Link != &ProtocolInterface->OpenList) { + OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE); + Link = Link->ForwardLink; + if ((OpenData->AgentHandle == AgentHandle) && (OpenData->ControllerHandle == ControllerHandle)) { + RemoveEntryList (&OpenData->Link); + ProtocolInterface->OpenListCount--; + CoreFreePool (OpenData); + Status = EFI_SUCCESS; + } + } + +Done: + // + // Done. Release the database lock and return. + // + CoreReleaseProtocolLock (); + return Status; +} + + +EFI_BOOTSERVICE11 +EFI_STATUS +EFIAPI +CoreOpenProtocolInformation ( + IN EFI_HANDLE UserHandle, + IN EFI_GUID *Protocol, + OUT EFI_OPEN_PROTOCOL_INFORMATION_ENTRY **EntryBuffer, + OUT UINTN *EntryCount + ) +/*++ + +Routine Description: + + Return information about Opened protocols in the system + +Arguments: + + UserHandle - The handle to close the protocol interface on + + Protocol - The ID of the protocol + + EntryBuffer - A pointer to a buffer of open protocol information in the form of + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY structures. + + EntryCount - Number of EntryBuffer entries + +Returns: + + +--*/ +{ + EFI_STATUS Status; + PROTOCOL_INTERFACE *ProtocolInterface; + EFI_LIST_ENTRY *Link; + OPEN_PROTOCOL_DATA *OpenData; + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *Buffer; + UINTN Count; + UINTN Size; + + *EntryBuffer = NULL; + *EntryCount = 0; + + // + // Lock the protocol database + // + CoreAcquireProtocolLock (); + + // + // Look at each protocol interface for a match + // + Status = EFI_NOT_FOUND; + ProtocolInterface = CoreGetProtocolInterface (UserHandle, Protocol); + if (ProtocolInterface == NULL) { + goto Done; + } + + // + // Count the number of Open Entries + // + for ( Link = ProtocolInterface->OpenList.ForwardLink, Count = 0; + (Link != &ProtocolInterface->OpenList) ; + Link = Link->ForwardLink ) { + Count++; + } + + ASSERT (Count == ProtocolInterface->OpenListCount); + + if (Count == 0) { + Size = sizeof(EFI_OPEN_PROTOCOL_INFORMATION_ENTRY); + } else { + Size = Count * sizeof(EFI_OPEN_PROTOCOL_INFORMATION_ENTRY); + } + + Buffer = CoreAllocateBootServicesPool (Size); + if (Buffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + Status = EFI_SUCCESS; + for ( Link = ProtocolInterface->OpenList.ForwardLink, Count = 0; + (Link != &ProtocolInterface->OpenList); + Link = Link->ForwardLink, Count++ ) { + OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE); + + Buffer[Count].AgentHandle = OpenData->AgentHandle; + Buffer[Count].ControllerHandle = OpenData->ControllerHandle; + Buffer[Count].Attributes = OpenData->Attributes; + Buffer[Count].OpenCount = OpenData->OpenCount; + } + + *EntryBuffer = Buffer; + *EntryCount = Count; + +Done: + // + // Done. Release the database lock are return + // + CoreReleaseProtocolLock (); + return Status; +} + + +EFI_BOOTSERVICE11 +EFI_STATUS +EFIAPI +CoreProtocolsPerHandle ( + IN EFI_HANDLE UserHandle, + OUT EFI_GUID ***ProtocolBuffer, + OUT UINTN *ProtocolBufferCount + ) +/*++ + +Routine Description: + + Retrieves the list of protocol interface GUIDs that are installed on a handle in a buffer allocated + from pool. + +Arguments: + + UserHandle - The handle from which to retrieve the list of protocol interface + GUIDs. + + ProtocolBuffer - A pointer to the list of protocol interface GUID pointers that are + installed on Handle. + + ProtocolBufferCount - A pointer to the number of GUID pointers present in + ProtocolBuffer. + +Returns: + EFI_SUCCESS - The list of protocol interface GUIDs installed on Handle was returned in + ProtocolBuffer. The number of protocol interface GUIDs was + returned in ProtocolBufferCount. + EFI_INVALID_PARAMETER - Handle is NULL. + EFI_INVALID_PARAMETER - Handle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ProtocolBuffer is NULL. + EFI_INVALID_PARAMETER - ProtocolBufferCount is NULL. + EFI_OUT_OF_RESOURCES - There is not enough pool memory to store the results. + +--*/ +{ + EFI_STATUS Status; + IHANDLE *Handle; + PROTOCOL_INTERFACE *Prot; + EFI_LIST_ENTRY *Link; + UINTN ProtocolCount; + EFI_GUID **Buffer; + + Status = CoreValidateHandle (UserHandle); + if (EFI_ERROR (Status)) { + return Status; + } + + Handle = (IHANDLE *)UserHandle; + + if (ProtocolBuffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (ProtocolBufferCount == NULL) { + return EFI_INVALID_PARAMETER; + } + + *ProtocolBufferCount = 0; + + ProtocolCount = 0; + + CoreAcquireProtocolLock (); + + for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) { + ProtocolCount++; + } + + // + // If there are no protocol interfaces installed on Handle, then Handle is not a valid EFI_HANDLE + // + if (ProtocolCount == 0) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + Buffer = CoreAllocateBootServicesPool (sizeof (EFI_GUID *) * ProtocolCount); + if (Buffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + *ProtocolBuffer = Buffer; + *ProtocolBufferCount = ProtocolCount; + + for ( Link = Handle->Protocols.ForwardLink, ProtocolCount = 0; + Link != &Handle->Protocols; + Link = Link->ForwardLink, ProtocolCount++) { + Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE); + Buffer[ProtocolCount] = &(Prot->Protocol->ProtocolID); + } + Status = EFI_SUCCESS; + +Done: + CoreReleaseProtocolLock (); + return Status; +} + + +UINT64 +CoreGetHandleDatabaseKey ( + VOID + ) +/*++ + +Routine Description: + + return handle database key. + +Arguments: + + None + +Returns: + + Handle database key. + +--*/ +{ + return gHandleDatabaseKey; +} + + +VOID +CoreConnectHandlesByKey ( + UINT64 Key + ) +/*++ + +Routine Description: + + Go connect any handles that were created or modified while a image executed. + +Arguments: + + Key - The Key to show that the handle has been created/modified + +Returns: + + None +--*/ +{ + UINTN Count; + EFI_LIST_ENTRY *Link; + EFI_HANDLE *HandleBuffer; + IHANDLE *Handle; + UINTN Index; + + // + // Lock the protocol database + // + CoreAcquireProtocolLock (); + + for (Link = gHandleList.ForwardLink, Count = 0; Link != &gHandleList; Link = Link->ForwardLink) { + Handle = CR (Link, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE); + if (Handle->Key > Key) { + Count++; + } + } + + HandleBuffer = CoreAllocateBootServicesPool (Count * sizeof (EFI_HANDLE)); + if (HandleBuffer == NULL) { + CoreReleaseProtocolLock (); + return; + } + + for (Link = gHandleList.ForwardLink, Count = 0; Link != &gHandleList; Link = Link->ForwardLink) { + Handle = CR (Link, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE); + if (Handle->Key > Key) { + HandleBuffer[Count++] = Handle; + } + } + + // + // Unlock the protocol database + // + CoreReleaseProtocolLock (); + + // + // Connect all handles whose Key value is greater than Key + // + for (Index = 0; Index < Count; Index++) { + CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE); + } + + CoreFreePool(HandleBuffer); +} diff --git a/EDK/Foundation/Core/Dxe/Hand/locate.c b/EDK/Foundation/Core/Dxe/Hand/locate.c new file mode 100644 index 0000000..4cd41e4 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/Hand/locate.c @@ -0,0 +1,743 @@ +/*++ + +Copyright (c) 2004 - 2011, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + locate.c + +Abstract: + + Locate handle functions + +Revision History + +--*/ + +#include "hand.h" + +// +// ProtocolRequest - Last LocateHandle request ID +// +UINTN mEfiLocateHandleRequest = 0; + +// +// Internal prototypes +// + +typedef struct { + EFI_GUID *Protocol; + VOID *SearchKey; + EFI_LIST_ENTRY *Position; + PROTOCOL_ENTRY *ProtEntry; +} LOCATE_POSITION; + +typedef +IHANDLE * +(* CORE_GET_NEXT) ( + IN OUT LOCATE_POSITION *Position, + OUT VOID **Interface + ); + +STATIC +IHANDLE * +CoreGetNextLocateAllHandles ( + IN OUT LOCATE_POSITION *Position, + OUT VOID **Interface + ); + +STATIC +IHANDLE * +CoreGetNextLocateByRegisterNotify ( + IN OUT LOCATE_POSITION *Position, + OUT VOID **Interface + ); + +STATIC +IHANDLE * +CoreGetNextLocateByProtocol ( + IN OUT LOCATE_POSITION *Position, + OUT VOID **Interface + ); + +// +// +// + + + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreLocateHandle ( + IN EFI_LOCATE_SEARCH_TYPE SearchType, + IN EFI_GUID *Protocol OPTIONAL, + IN VOID *SearchKey OPTIONAL, + IN OUT UINTN *BufferSize, + OUT EFI_HANDLE *Buffer + ) +/*++ + +Routine Description: + + Locates the requested handle(s) and returns them in Buffer. + +Arguments: + + SearchType - The type of search to perform to locate the handles + + Protocol - The protocol to search for + + SearchKey - Dependant on SearchType + + BufferSize - On input the size of Buffer. On output the + size of data returned. + + Buffer - The buffer to return the results in + + +Returns: + + EFI_BUFFER_TOO_SMALL - Buffer too small, required buffer size is returned in BufferSize. + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_SUCCESS - Successfully found the requested handle(s) and returns them in Buffer. + +--*/ +{ + EFI_STATUS Status; + LOCATE_POSITION Position; + PROTOCOL_NOTIFY *ProtNotify; + CORE_GET_NEXT GetNext; + UINTN ResultSize; + IHANDLE *Handle; + IHANDLE **ResultBuffer; + VOID *Interface; + + if (BufferSize == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((*BufferSize > 0) && (Buffer == NULL)) { + return EFI_INVALID_PARAMETER; + } + + GetNext = NULL; + // + // Set initial position + // + + Position.Protocol = Protocol; + Position.SearchKey = SearchKey; + Position.Position = &gHandleList; + + ResultSize = 0; + ResultBuffer = (IHANDLE **) Buffer; + Status = EFI_SUCCESS; + + // + // Lock the protocol database + // + + CoreAcquireProtocolLock (); + + // + // Get the search function based on type + // + switch (SearchType) { + case AllHandles: + GetNext = CoreGetNextLocateAllHandles; + break; + + case ByRegisterNotify: + // + // Must have SearchKey for locate ByRegisterNotify + // + if (SearchKey == NULL) { + Status = EFI_INVALID_PARAMETER; + break; + } + GetNext = CoreGetNextLocateByRegisterNotify; + break; + + case ByProtocol: + GetNext = CoreGetNextLocateByProtocol; + if (Protocol == NULL) { + Status = EFI_INVALID_PARAMETER; + break; + } + // + // Look up the protocol entry and set the head pointer + // + Position.ProtEntry = CoreFindProtocolEntry (Protocol, FALSE); + if (Position.ProtEntry == NULL) { + Status = EFI_NOT_FOUND; + break; + } + Position.Position = &Position.ProtEntry->Protocols; + break; + + default: + Status = EFI_INVALID_PARAMETER; + break; + } + + if (EFI_ERROR(Status) || (GetNext == NULL)) { + CoreReleaseProtocolLock (); + return Status; + } + + // + // Enumerate out the matching handles + // + mEfiLocateHandleRequest += 1; + for (; ;) { + // + // Get the next handle. If no more handles, stop + // + Handle = GetNext (&Position, &Interface); + if (NULL == Handle) { + break; + } + + // + // Increase the resulting buffer size, and if this handle + // fits return it + // + ResultSize += sizeof(Handle); + if (ResultSize <= *BufferSize) { + *ResultBuffer = Handle; + ResultBuffer += 1; + } + } + + // + // If the result is a zero length buffer, then there were no + // matching handles + // + if (ResultSize == 0) { + Status = EFI_NOT_FOUND; + } else { + // + // Return the resulting buffer size. If it's larger than what + // was passed, then set the error code + // + if (ResultSize > *BufferSize) { + Status = EFI_BUFFER_TOO_SMALL; + } + + *BufferSize = ResultSize; + + if (SearchType == ByRegisterNotify && !EFI_ERROR(Status)) { + // + // If this is a search by register notify and a handle was + // returned, update the register notification position + // + ProtNotify = SearchKey; + ProtNotify->Position = ProtNotify->Position->ForwardLink; + } + } + + CoreReleaseProtocolLock (); + return Status; +} + + +STATIC +IHANDLE * +CoreGetNextLocateAllHandles ( + IN OUT LOCATE_POSITION *Position, + OUT VOID **Interface + ) +/*++ + +Routine Description: + + Routine to get the next Handle, when you are searching for all handles. + +Arguments: + + Position - Information about which Handle to seach for. + + Interface - Return the interface structure for the matching protocol. + +Returns: + IHANDLE - An IHANDLE is returned if the next Position is not the end of the + list. A NULL_HANDLE is returned if it's the end of the list. + +--*/ +{ + IHANDLE *Handle; + + // + // Next handle + // + Position->Position = Position->Position->ForwardLink; + + // + // If not at the end of the list, get the handle + // + Handle = NULL_HANDLE; + *Interface = NULL; + if (Position->Position != &gHandleList) { + Handle = CR (Position->Position, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE); + } + + return Handle; +} + + +STATIC +IHANDLE * +CoreGetNextLocateByRegisterNotify ( + IN OUT LOCATE_POSITION *Position, + OUT VOID **Interface + ) +/*++ + +Routine Description: + + Routine to get the next Handle, when you are searching for register protocol + notifies. + +Arguments: + + Position - Information about which Handle to seach for. + + Interface - Return the interface structure for the matching protocol. + +Returns: + IHANDLE - An IHANDLE is returned if the next Position is not the end of the + list. A NULL_HANDLE is returned if it's the end of the list. + +--*/ +{ + IHANDLE *Handle; + PROTOCOL_NOTIFY *ProtNotify; + PROTOCOL_INTERFACE *Prot; + EFI_LIST_ENTRY *Link; + + Handle = NULL_HANDLE; + *Interface = NULL; + ProtNotify = Position->SearchKey; + + // + // If this is the first request, get the next handle + // + if (ProtNotify != NULL) { + ASSERT(ProtNotify->Signature == PROTOCOL_NOTIFY_SIGNATURE); + Position->SearchKey = NULL; + + // + // If not at the end of the list, get the next handle + // + Link = ProtNotify->Position->ForwardLink; + if (Link != &ProtNotify->Protocol->Protocols) { + Prot = CR (Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE); + Handle = (IHANDLE *) Prot->Handle; + *Interface = Prot->Interface; + } + } + + return Handle; +} + + +STATIC +IHANDLE * +CoreGetNextLocateByProtocol ( + IN OUT LOCATE_POSITION *Position, + OUT VOID **Interface + ) +/*++ + +Routine Description: + + Routine to get the next Handle, when you are searching for a given protocol. + +Arguments: + + Position - Information about which Handle to seach for. + + Interface - Return the interface structure for the matching protocol. + +Returns: + IHANDLE - An IHANDLE is returned if the next Position is not the end of the + list. A NULL_HANDLE is returned if it's the end of the list. + +--*/ +{ + IHANDLE *Handle; + EFI_LIST_ENTRY *Link; + PROTOCOL_INTERFACE *Prot; + + Handle = NULL_HANDLE; + *Interface = NULL; + for (; ;) { + // + // Next entry + // + Link = Position->Position->ForwardLink; + Position->Position = Link; + + // + // If not at the end, return the handle + // + if (Link == &Position->ProtEntry->Protocols) { + Handle = NULL_HANDLE; + break; + } + + // + // Get the handle + // + Prot = CR(Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE); + Handle = (IHANDLE *) Prot->Handle; + *Interface = Prot->Interface; + + // + // If this handle has not been returned this request, then + // return it now + // + if (Handle->LocateRequest != mEfiLocateHandleRequest) { + Handle->LocateRequest = mEfiLocateHandleRequest; + break; + } + } + + return Handle; +} + + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreLocateDevicePath ( + IN EFI_GUID *Protocol, + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath, + OUT EFI_HANDLE *Device + ) +/*++ + +Routine Description: + + Locates the handle to a device on the device path that best matches the specified protocol. + +Arguments: + + Protocol - The protocol to search for. + DevicePath - On input, a pointer to a pointer to the device path. On output, the device + path pointer is modified to point to the remaining part of the devicepath. + Device - A pointer to the returned device handle. + +Returns: + + EFI_SUCCESS - The resulting handle was returned. + EFI_NOT_FOUND - No handles matched the search. + EFI_INVALID_PARAMETER - One of the parameters has an invalid value. + +--*/ +{ + INTN SourceSize; + INTN Size; + INTN BestMatch; + UINTN HandleCount; + UINTN Index; + EFI_STATUS Status; + EFI_HANDLE *Handles; + EFI_HANDLE Handle; + EFI_HANDLE BestDevice; + EFI_DEVICE_PATH_PROTOCOL *SourcePath; + EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath; + + if (Protocol == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((DevicePath == NULL) || (*DevicePath == NULL)) { + return EFI_INVALID_PARAMETER; + } + + BestDevice = NULL; + SourcePath = *DevicePath; + TmpDevicePath = SourcePath; + while (!IsDevicePathEnd (TmpDevicePath)) { + if (EfiIsDevicePathEndInstance (TmpDevicePath)) { + // + // If DevicePath is a multi-instance device path, + // the function will operate on the first instance + // + break; + } + TmpDevicePath = NextDevicePathNode (TmpDevicePath); + } + + SourceSize = (UINTN) TmpDevicePath - (UINTN) SourcePath; + + // + // Get a list of all handles that support the requested protocol + // + Status = CoreLocateHandleBuffer (ByProtocol, Protocol, NULL, &HandleCount, &Handles); + if (EFI_ERROR (Status) || HandleCount == 0) { + return EFI_NOT_FOUND; + } + + BestMatch = -1; + for(Index = 0; Index < HandleCount; Index += 1) { + Handle = Handles[Index]; + Status = CoreHandleProtocol (Handle, &gEfiDevicePathProtocolGuid, &TmpDevicePath); + if (EFI_ERROR (Status)) { + // + // If this handle doesn't support device path, then skip it + // + continue; + } + + // + // Check if DevicePath is first part of SourcePath + // + Size = CoreDevicePathSize (TmpDevicePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL); + if ((Size <= SourceSize) && EfiCompareMem (SourcePath, TmpDevicePath, Size) == 0) { + // + // If the size is equal to the best match, then we + // have a duplice device path for 2 different device + // handles + // + ASSERT (Size != BestMatch); + + // + // We've got a match, see if it's the best match so far + // + if (Size > BestMatch) { + BestMatch = Size; + BestDevice = Handle; + } + } + } + + CoreFreePool (Handles); + + // + // If there wasn't any match, then no parts of the device path was found. + // Which is strange since there is likely a "root level" device path in the system. + // + if (BestMatch == -1) { + return EFI_NOT_FOUND; + } + + if (Device == NULL) { + return EFI_INVALID_PARAMETER; + } + *Device = BestDevice; + + // + // Return the remaining part of the device path + // + *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) (((UINT8 *) SourcePath) + BestMatch); + return EFI_SUCCESS; +} + + +EFI_BOOTSERVICE11 +EFI_STATUS +EFIAPI +CoreLocateProtocol ( + IN EFI_GUID *Protocol, + IN VOID *Registration OPTIONAL, + OUT VOID **Interface + ) +/*++ + +Routine Description: + + Return the first Protocol Interface that matches the Protocol GUID. If + Registration is pasased in return a Protocol Instance that was just add + to the system. If Retistration is NULL return the first Protocol Interface + you find. + +Arguments: + + Protocol - The protocol to search for + + Registration - Optional Registration Key returned from RegisterProtocolNotify() + + Interface - Return the Protocol interface (instance). + +Returns: + + EFI_SUCCESS - If a valid Interface is returned + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_NOT_FOUND - Protocol interface not found + +--*/ +{ + EFI_STATUS Status; + LOCATE_POSITION Position; + PROTOCOL_NOTIFY *ProtNotify; + IHANDLE *Handle; + + if (Interface == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Protocol == NULL) { + return EFI_NOT_FOUND; + } + + *Interface = NULL; + Status = EFI_SUCCESS; + + // + // Set initial position + // + Position.Protocol = Protocol; + Position.SearchKey = Registration; + Position.Position = &gHandleList; + + // + // Lock the protocol database + // + CoreAcquireProtocolLock (); + + mEfiLocateHandleRequest += 1; + + if (NULL == Registration) { + // + // Look up the protocol entry and set the head pointer + // + Position.ProtEntry = CoreFindProtocolEntry (Protocol, FALSE); + if (Position.ProtEntry == NULL) { + Status = EFI_NOT_FOUND; + goto Done; + } + Position.Position = &Position.ProtEntry->Protocols; + + Handle = CoreGetNextLocateByProtocol (&Position, Interface); + } else { + Handle = CoreGetNextLocateByRegisterNotify (&Position, Interface); + } + + if (NULL == Handle) { + Status = EFI_NOT_FOUND; + } else if (NULL != Registration) { + // + // If this is a search by register notify and a handle was + // returned, update the register notification position + // + ProtNotify = Registration; + ProtNotify->Position = ProtNotify->Position->ForwardLink; + } + +Done: + CoreReleaseProtocolLock (); + return Status; +} + + +EFI_BOOTSERVICE11 +EFI_STATUS +EFIAPI +CoreLocateHandleBuffer ( + IN EFI_LOCATE_SEARCH_TYPE SearchType, + IN EFI_GUID *Protocol OPTIONAL, + IN VOID *SearchKey OPTIONAL, + IN OUT UINTN *NumberHandles, + OUT EFI_HANDLE **Buffer + ) +/*++ + +Routine Description: + + Function returns an array of handles that support the requested protocol + in a buffer allocated from pool. This is a version of CoreLocateHandle() + that allocates a buffer for the caller. + +Arguments: + + SearchType - Specifies which handle(s) are to be returned. + Protocol - Provides the protocol to search by. + This parameter is only valid for SearchType ByProtocol. + SearchKey - Supplies the search key depending on the SearchType. + NumberHandles - The number of handles returned in Buffer. + Buffer - A pointer to the buffer to return the requested array of + handles that support Protocol. + +Returns: + + EFI_SUCCESS - The result array of handles was returned. + EFI_NOT_FOUND - No handles match the search. + EFI_OUT_OF_RESOURCES - There is not enough pool memory to store the matching results. + EFI_INVALID_PARAMETER - Invalid parameter + +--*/ +{ + EFI_STATUS Status; + UINTN BufferSize; + + if (NumberHandles == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + BufferSize = 0; + *NumberHandles = 0; + *Buffer = NULL; + Status = CoreLocateHandle ( + SearchType, + Protocol, + SearchKey, + &BufferSize, + *Buffer + ); + // + // LocateHandleBuffer() returns incorrect status code if SearchType is + // invalid. + // + // Add code to correctly handle expected errors from CoreLocateHandle(). + // + if (EFI_ERROR(Status)) { + switch (Status) { + case EFI_BUFFER_TOO_SMALL: + break; + case EFI_INVALID_PARAMETER: + return Status; + default: + return EFI_NOT_FOUND; + } + } + + *Buffer = CoreAllocateBootServicesPool (BufferSize); + if (*Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = CoreLocateHandle ( + SearchType, + Protocol, + SearchKey, + &BufferSize, + *Buffer + ); + + *NumberHandles = BufferSize/sizeof(EFI_HANDLE); + if (EFI_ERROR(Status)) { + *NumberHandles = 0; + } + + return Status; +} + + diff --git a/EDK/Foundation/Core/Dxe/Ia32/Processor.h b/EDK/Foundation/Core/Dxe/Ia32/Processor.h new file mode 100644 index 0000000..0084d4a --- /dev/null +++ b/EDK/Foundation/Core/Dxe/Ia32/Processor.h @@ -0,0 +1,27 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + Processor.h + +Abstract: + This file contains the IA-32 processor specific definitions + +--*/ + +#ifndef _PROCESSOR_H_ +#define _PROCESSOR_H_ + +#define EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT (EFI_PAGE_SIZE) + +#define DEFAULT_PAGE_ALLOCATION (EFI_PAGE_SIZE) + +#endif \ No newline at end of file diff --git a/EDK/Foundation/Core/Dxe/Image/Image.c b/EDK/Foundation/Core/Dxe/Image/Image.c new file mode 100644 index 0000000..bdf1783 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/Image/Image.c @@ -0,0 +1,1626 @@ +/*++ + +Copyright (c) 2004 - 2012, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Image.c + +Abstract: + + Core image handling services + +--*/ + +#include "Image.h" +#include "EfiHobLib.h" +#include "EfiPerf.h" + +// +// Module Globals +// + +LOADED_IMAGE_PRIVATE_DATA *mCurrentImage = NULL; + +LOAD_PE32_IMAGE_PRIVATE_DATA mLoadPe32PrivateData = { + LOAD_PE32_IMAGE_PRIVATE_DATA_SIGNATURE, + NULL, + CoreLoadImageEx, + CoreUnloadImageEx +}; + + +// +// This code is needed to build the Image handle for the DXE Core +// +LOADED_IMAGE_PRIVATE_DATA mCorePrivateImage = { + LOADED_IMAGE_PRIVATE_DATA_SIGNATURE, // Signature + NULL, // Image handle + EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER, // Image type + TRUE, // If entrypoint has been called + NULL, // EntryPoint + { + EFI_LOADED_IMAGE_INFORMATION_REVISION, // Revision + NULL, // Parent handle + NULL, // System handle + + NULL, // Device handle + NULL, // File path + NULL, // Reserved + + 0, // LoadOptionsSize + NULL, // LoadOptions + + NULL, // ImageBase + 0, // ImageSize + EfiBootServicesCode, // ImageCodeType + EfiBootServicesData // ImageDataType + }, +#if (EFI_SPECIFICATION_VERSION >= 0x0002000A) + NULL, // Loaded Image Device Path +#endif + (EFI_PHYSICAL_ADDRESS)0, // ImageBasePage + 0, // NumberOfPages + NULL, // FixupData + 0, // Tpl + EFI_SUCCESS, // Status + 0, // ExitDataSize + NULL, // ExitData + NULL, // JumpContext + 0, // Machine + NULL, // Ebc + NULL, // RuntimeData +}; + + +STATIC +EFI_STATUS +EFIAPI +CoreFlushICache ( + IN EFI_PHYSICAL_ADDRESS Start, + IN UINT64 Length + ); + +EFI_STATUS +GetTimerValue ( + OUT UINT64 *TimerValue + ); + +EFI_STATUS +CoreInitializeImageServices ( + IN VOID *HobStart + ) +/*++ + +Routine Description: + + Add the Image Services to EFI Boot Services Table and install the protocol + interfaces for this image. + +Arguments: + + HobStart - The HOB to initialize + +Returns: + + Status code. + +--*/ +{ + EFI_STATUS Status; + LOADED_IMAGE_PRIVATE_DATA *Image; + EFI_PHYSICAL_ADDRESS DxeCoreImageBaseAddress; + UINT64 DxeCoreImageLength; + VOID *DxeCoreEntryPoint; + + + // + // Searching for image hob + // + Status = GetDxeCoreHobInfo ( + HobStart, + &DxeCoreImageBaseAddress, + &DxeCoreImageLength, + &DxeCoreEntryPoint, + &gDxeCoreFileName + ); + ASSERT_EFI_ERROR (Status); + + // + // Initialize the fields for an internal driver + // + Image = &mCorePrivateImage; + + Image->EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)DxeCoreEntryPoint; + Image->ImageBasePage = DxeCoreImageBaseAddress; + Image->NumberOfPages = (UINTN)(EFI_SIZE_TO_PAGES((UINTN)(DxeCoreImageLength))); + Image->Tpl = gEfiCurrentTpl; + Image->Info.SystemTable = gST; + Image->Info.ImageBase = (VOID *)(UINTN)DxeCoreImageBaseAddress; + Image->Info.ImageSize = DxeCoreImageLength; + + // + // Install the protocol interfaces for this image + // + Status = CoreInstallProtocolInterface ( + &Image->Handle, + &gEfiLoadedImageProtocolGuid, + EFI_NATIVE_INTERFACE, + &Image->Info + ); + ASSERT_EFI_ERROR (Status); + + // + // Install Debug Mask Protocol + // + DEBUG_CODE ( + if (!EFI_ERROR (Status)) { + Status = InstallCoreDebugMaskProtocol(Image->Handle); + ASSERT_EFI_ERROR (Status); + } + ) + + mCurrentImage = Image; + + // + // Fill in DXE globals + // + gDxeCoreImageHandle = Image->Handle; + gDxeCoreLoadedImage = &Image->Info; + + // + // Export DXE Core PE Loader functionality + // + return CoreInstallProtocolInterface ( + &mLoadPe32PrivateData.Handle, + &gEfiLoadPeImageGuid, + EFI_NATIVE_INTERFACE, + &mLoadPe32PrivateData.Pe32Image + ); +} + + +STATIC +EFI_STATUS +CoreLoadPeImage ( + IN BOOLEAN BootPolicy, + IN VOID *Pe32Handle, + IN LOADED_IMAGE_PRIVATE_DATA *Image, + IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL, + OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL, + IN UINT32 Attribute, + IN BOOLEAN CrossLoad + ) +/*++ + +Routine Description: + + Loads, relocates, and invokes a PE/COFF image. + +Arguments: + + Pe32Handle - The handle of PE32 image. + Image - PE image to be loaded. + DstBuffer - The buffer to store the image. + EntryPoint - A pointer to the entry point. + Attribute - The bit mask of attributes to set for the load PE image. + CrossLoad - Whether expect to support cross architecture loading. + +Returns: + + EFI_SUCCESS - The file was loaded, relocated, and invoked. + EFI_OUT_OF_RESOURCES - There was not enough memory to load and relocate the PE/COFF file. + EFI_INVALID_PARAMETER - Invalid parameter. + EFI_BUFFER_TOO_SMALL - Buffer for image is too small. + +--*/ +{ + EFI_STATUS Status; + BOOLEAN DstBufAlocated; + UINTN Size; + EFI_IMAGE_NT_HEADERS64 *PeHdr; + EFI_TCG_PLATFORM_PROTOCOL *TcgPlatformProtocol; + IMAGE_FILE_HANDLE *FHandle; + BOOLEAN NeedAllocateAddress; +#ifdef EFI_LOAD_DRIVER_AT_FIXED_OFFSET + BOOLEAN OffsetMode; + STATIC BOOLEAN PrintTopAddress = TRUE; +#endif + + DEBUG_CODE ( + UINTN Index; + UINTN StartIndex; + CHAR8 EfiFileName[256]; + ) + + EfiCommonLibZeroMem (&(Image->ImageContext), sizeof (Image->ImageContext)); + + Image->ImageContext.Handle = Pe32Handle; + Image->ImageContext.ImageRead = (EFI_PEI_PE_COFF_LOADER_READ_FILE) CoreReadImageFile; + + // + // Get information about the image being loaded. + // + Status = gEfiPeiPeCoffLoader->GetImageInfo (gEfiPeiPeCoffLoader, &(Image->ImageContext)); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Check the processor architecture of the image + // + if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->ImageContext.Machine)) { + if (CrossLoad) { + if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Image->ImageContext.Machine)) { + return EFI_UNSUPPORTED; + } + } else { + return EFI_UNSUPPORTED; + } + } + + // + // Allocate memory of the correct memory type aligned on the required image boundary. + // + DstBufAlocated = FALSE; + if (DstBuffer == 0) { + // + // Allocate Destination Buffer as caller did not pass it in. + // + + if (Image->ImageContext.SectionAlignment > EFI_PAGE_SIZE) { + Size = (UINTN) Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment; + } else { + Size = (UINTN) Image->ImageContext.ImageSize; + } + + Image->NumberOfPages = EFI_SIZE_TO_PAGES (Size); + // + // Following code is to support load a PE image at fixed offset relative to TOLM + // +#ifdef EFI_LOAD_DRIVER_AT_FIXED_OFFSET + { + typedef struct { + EFI_PHYSICAL_ADDRESS BaseAddress; + EFI_PHYSICAL_ADDRESS MaximumAddress; + UINT64 CurrentNumberOfPages; + UINT64 NumberOfPages; + UINTN InformationIndex; + BOOLEAN Special; + BOOLEAN Runtime; + } EFI_MEMORY_TYPE_STAISTICS; + + + extern EFI_MEMORY_TYPE_STAISTICS mMemoryTypeStatistics[EfiMaxMemoryType + 1]; + INT32 Offset; + UINTN ReadSize = sizeof (UINT32); + + if (PrintTopAddress) { + DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Runtime code top address: %lX\n", mMemoryTypeStatistics[EfiRuntimeServicesCode].MaximumAddress + 1)); + DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Boot time code top address: %lX\n", mMemoryTypeStatistics[EfiBootServicesCode].MaximumAddress + 1)); + PrintTopAddress = FALSE; + } + OffsetMode = FALSE; + Status = Image->ImageContext.ImageRead ( + Image->ImageContext.Handle, + Image->ImageContext.PeCoffHeaderOffset + 12, + &ReadSize, + &Offset + ); + if (!EFI_ERROR (Status) && Offset != 0 && + Image->ImageContext.ImageCodeMemoryType != EfiLoaderCode) { + OffsetMode = TRUE; + Image->ImageContext.ImageAddress = mMemoryTypeStatistics[Image->ImageContext.ImageCodeMemoryType].MaximumAddress + 1 - Offset; + } + } +#endif + + // + // If the image relocations are stripped, or fixed address/offset feature is valid, + // try to load the image to the specified address first. + // Otherwise try to load the image at any page if image relocations are available. + // + NeedAllocateAddress = FALSE; + if (Image->ImageContext.RelocationsStripped) { + NeedAllocateAddress = TRUE; + } +#ifdef EFI_LOAD_DRIVER_AT_FIXED_ADDRESS + NeedAllocateAddress = TRUE; +#endif +#ifdef EFI_LOAD_DRIVER_AT_FIXED_OFFSET + if (OffsetMode) { + NeedAllocateAddress = TRUE; + } +#endif + Status = EFI_OUT_OF_RESOURCES; + if (NeedAllocateAddress) { + Status = CoreAllocatePages ( + AllocateAddress, + Image->ImageContext.ImageCodeMemoryType, + Image->NumberOfPages, + &Image->ImageContext.ImageAddress + ); +#ifdef EFI_LOAD_DRIVER_AT_FIXED_OFFSET + if (EFI_ERROR (Status) && OffsetMode) { + DEBUG((EFI_D_ERROR, "\nOffset mode load failure!")); + } +#endif + } + if (EFI_ERROR (Status) && !Image->ImageContext.RelocationsStripped) { + Status = CoreAllocatePages ( + AllocateAnyPages, + Image->ImageContext.ImageCodeMemoryType, + Image->NumberOfPages, + &Image->ImageContext.ImageAddress + ); + } + if (EFI_ERROR (Status)) { + return Status; + } + DstBufAlocated = TRUE; + } else { + // + // Caller provided the destination buffer. + // + + if (Image->ImageContext.RelocationsStripped && (Image->ImageContext.ImageAddress != DstBuffer)) { + // + // If the image relocations were stripped, and the caller provided a + // destination buffer address that does not match the address that the + // image is linked at, then the image cannot be loaded. + // + return EFI_INVALID_PARAMETER; + } + + Size = EFI_SIZE_TO_PAGES ((UINTN) Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment); + + if ((Image->NumberOfPages != 0) && (Image->NumberOfPages < Size)) { + Image->NumberOfPages = Size; + return EFI_BUFFER_TOO_SMALL; + } + + Image->NumberOfPages = Size; + Image->ImageContext.ImageAddress = DstBuffer; + } + + Image->ImageBasePage = Image->ImageContext.ImageAddress; + Image->ImageContext.ImageAddress = + (Image->ImageContext.ImageAddress + Image->ImageContext.SectionAlignment - 1) & + ~((UINTN) Image->ImageContext.SectionAlignment - 1); + + // + // Load the image from the file into the allocated memory + // + Status = gEfiPeiPeCoffLoader->LoadImage (gEfiPeiPeCoffLoader, &(Image->ImageContext)); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // If this is a Runtime Driver, then allocate memory for the FixupData that + // is used to relocate the image when SetVirtualAddressMap() is called. The + // relocation is done by the Runtime AP. + // + if (Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION) { + if (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER && + EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->ImageContext.Machine)) { + Image->ImageContext.FixupData = CoreAllocateRuntimePool ((UINTN)(Image->ImageContext.FixupDataSize)); + if (Image->ImageContext.FixupData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + } + } + + // + // Measure the image before applying fixup + // + Status = CoreLocateProtocol ( + &gEfiTcgPlatformProtocolGuid, + NULL, + &TcgPlatformProtocol + ); + if (!EFI_ERROR (Status) && (TcgPlatformProtocol != NULL)) { + PeHdr = (EFI_IMAGE_NT_HEADERS64 *)(UINTN) ( + Image->ImageContext.ImageAddress + + Image->ImageContext.PeCoffHeaderOffset + ); + FHandle = (IMAGE_FILE_HANDLE *)Image->ImageContext.Handle; + + Status = TcgPlatformProtocol->MeasurePeImage ( + BootPolicy, + (EFI_PHYSICAL_ADDRESS)FHandle->Source, + FHandle->SourceSize, + (UINTN) PeHdr->OptionalHeader.ImageBase, + Image->ImageContext.ImageType, + Image->Info.DeviceHandle, + Image->Info.FilePath + ); + + ASSERT_EFI_ERROR (Status); + } + + // + // Relocate the image in memory + // + Status = gEfiPeiPeCoffLoader->RelocateImage (gEfiPeiPeCoffLoader, &(Image->ImageContext)); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Flush the Instruction Cache + // + Status = CoreFlushICache (Image->ImageContext.ImageAddress, Image->ImageContext.ImageSize); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Get the image entry point. If it's an EBC image, then call into the + // interpreter to create a thunk for the entry point and use the returned + // value for the entry point. + // + Image->EntryPoint = (EFI_IMAGE_ENTRY_POINT) (UINTN) Image->ImageContext.EntryPoint; + + // + // Copy the machine type from the context to the image private data. This + // is needed during image unload to know if we should call an EBC protocol + // to unload the image. + // + Image->Machine = Image->ImageContext.Machine; + if (Image->ImageContext.Machine == EFI_IMAGE_MACHINE_EBC) { + // + // Locate the EBC interpreter protocol + // + Status = CoreLocateProtocol (&gEfiEbcProtocolGuid, NULL, &Image->Ebc); + if (EFI_ERROR (Status) || (Image->Ebc == NULL)) { + goto Done; + } + + // + // Register a callback for flushing the instruction cache so that created + // thunks can be flushed. + // + Status = Image->Ebc->RegisterICacheFlush (Image->Ebc, CoreFlushICache); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Create a thunk for the image's entry point. This will be the new + // entry point for the image. + // + Status = Image->Ebc->CreateThunk ( + Image->Ebc, + Image->Handle, + (VOID *)(UINTN)Image->ImageContext.EntryPoint, + (VOID **)&Image->EntryPoint + ); + if (EFI_ERROR (Status)) { + goto Done; + } + } + + // + // Fill in the image information for the Loaded Image Protocol + // + Image->Type = Image->ImageContext.ImageType; + Image->Info.ImageBase = (VOID *) (UINTN) Image->ImageContext.ImageAddress; + Image->Info.ImageSize = Image->ImageContext.ImageSize; + Image->Info.ImageCodeType = Image->ImageContext.ImageCodeMemoryType; + Image->Info.ImageDataType = Image->ImageContext.ImageDataMemoryType; + + if (Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION) { + if (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) { + // + // Make a list off all the RT images so we can let the RT AP know about them. + // + Image->RuntimeData = CoreAllocateRuntimePool (sizeof(EFI_RUNTIME_IMAGE_ENTRY)); + if (Image->RuntimeData == NULL) { + goto Done; + } + Image->RuntimeData->ImageBase = Image->Info.ImageBase; + Image->RuntimeData->ImageSize = (UINT64) (Image->Info.ImageSize); + Image->RuntimeData->RelocationData = Image->ImageContext.FixupData; + Image->RuntimeData->Handle = Image->Handle; + InsertTailList (&gRuntime->ImageHead, &Image->RuntimeData->Link); + } + } + + // + // Fill in the entry point of the image if it is available + // + if (EntryPoint != NULL) { + *EntryPoint = Image->ImageContext.EntryPoint; + } + + // + // Print the load address and the PDB file name if it is available + // + + DEBUG_CODE ( + { + DEBUG (( + EFI_D_INFO | EFI_D_LOAD, + "Loading driver at 0x%x EntryPoint=0x%x ", + (UINTN) Image->ImageContext.ImageAddress, + (UINTN) Image->ImageContext.EntryPoint + )); + if (Image->ImageContext.PdbPointer != NULL) { + StartIndex = 0; + for (Index = 0; Image->ImageContext.PdbPointer[Index] != 0; Index++) { + if (Image->ImageContext.PdbPointer[Index] == '\\') { + StartIndex = Index + 1; + } + } + // + // Copy the PDB file name to our temporary string, and replace .pdb with .efi + // + for (Index = 0; Index < sizeof (EfiFileName); Index++) { + EfiFileName[Index] = Image->ImageContext.PdbPointer[Index + StartIndex]; + if (EfiFileName[Index] == 0) { + EfiFileName[Index] = '.'; + } + if (EfiFileName[Index] == '.') { + EfiFileName[Index + 1] = 'e'; + EfiFileName[Index + 2] = 'f'; + EfiFileName[Index + 3] = 'i'; + EfiFileName[Index + 4] = 0; + break; + } + } + DEBUG ((EFI_D_INFO | EFI_D_LOAD, "%a", EfiFileName)); + } + DEBUG ((EFI_D_INFO | EFI_D_LOAD, "\n")); + } + ); + + return EFI_SUCCESS; + +Done: + + // + // Free memory. + // + + if (DstBufAlocated) { + CoreFreePages (Image->ImageContext.ImageAddress, Image->NumberOfPages); + } + + if (Image->ImageContext.FixupData != NULL) { + CoreFreePool (Image->ImageContext.FixupData); + } + + return Status; +} + + +LOADED_IMAGE_PRIVATE_DATA * +CoreLoadedImageInfo ( + IN EFI_HANDLE ImageHandle + ) +/*++ + +Routine Description: + + Get the image's private data from its handle. + +Arguments: + + ImageHandle - The image handle + +Returns: + + Return the image private data associated with ImageHandle. + +--*/ +{ + EFI_STATUS Status; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + LOADED_IMAGE_PRIVATE_DATA *Image; + + Status = CoreHandleProtocol ( + ImageHandle, + &gEfiLoadedImageProtocolGuid, + &LoadedImage + ); + if (!EFI_ERROR (Status)) { + Image = LOADED_IMAGE_PRIVATE_DATA_FROM_THIS (LoadedImage); + } else { + DEBUG ((EFI_D_LOAD, "CoreLoadedImageInfo: Not an ImageHandle %x\n", ImageHandle)); + Image = NULL; + } + + return Image; +} + + +EFI_STATUS +CoreLoadImageCommon ( + IN BOOLEAN BootPolicy, + IN EFI_HANDLE ParentImageHandle, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + IN VOID *SourceBuffer OPTIONAL, + IN UINTN SourceSize, + IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL, + IN OUT UINTN *NumberOfPages OPTIONAL, + OUT EFI_HANDLE *ImageHandle, + OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL, + IN UINT32 Attribute, + IN BOOLEAN CrossLoad + ) +/*++ + +Routine Description: + + Loads an EFI image into memory and returns a handle to the image. + +Arguments: + + BootPolicy - If TRUE, indicates that the request originates from the boot manager, + and that the boot manager is attempting to load FilePath as a boot selection. + ParentImageHandle - The caller's image handle. + FilePath - The specific file path from which the image is loaded. + SourceBuffer - If not NULL, a pointer to the memory location containing a copy of + the image to be loaded. + SourceSize - The size in bytes of SourceBuffer. + DstBuffer - The buffer to store the image + NumberOfPages - If not NULL, on input a pointer to the page number of DstBuffer and on + output a pointer to the page number of the image. If this number of DstBuffer + is not enough, return EFI_BUFFER_TOO_SMALL and this parameter contain + the required number. + ImageHandle - Pointer to the returned image handle that is created when the image + is successfully loaded. + EntryPoint - A pointer to the entry point + Attribute - The bit mask of attributes to set for the load PE image + CrossLoad - Whether expect to support cross architecture loading + +Returns: + + EFI_SUCCESS - The image was loaded into memory. + EFI_NOT_FOUND - The FilePath was not found. + EFI_INVALID_PARAMETER - One of the parameters has an invalid value. + EFI_BUFFER_TOO_SMALL - The buffer is too small + EFI_UNSUPPORTED - The image type is not supported, or the device path cannot be + parsed to locate the proper protocol for loading the file. + EFI_OUT_OF_RESOURCES - Image was not loaded due to insufficient resources. +--*/ +{ + LOADED_IMAGE_PRIVATE_DATA *Image; + LOADED_IMAGE_PRIVATE_DATA *ParentImage; + IMAGE_FILE_HANDLE FHand; + EFI_STATUS Status; + EFI_STATUS SecurityStatus; + EFI_HANDLE DeviceHandle; + UINT32 AuthenticationStatus; + EFI_DEVICE_PATH_PROTOCOL *OriginalFilePath; + EFI_DEVICE_PATH_PROTOCOL *HandleFilePath; + UINTN FilePathSize; + + SecurityStatus = EFI_SUCCESS; + + ASSERT (gEfiCurrentTpl < EFI_TPL_NOTIFY); + ParentImage = NULL; + + // + // The caller must pass in a valid ParentImageHandle + // + if (ImageHandle == NULL || ParentImageHandle == NULL) { + return EFI_INVALID_PARAMETER; + } + + ParentImage = CoreLoadedImageInfo (ParentImageHandle); + if (ParentImage == NULL) { + DEBUG((EFI_D_LOAD|EFI_D_ERROR, "LoadImageEx: Parent handle not an image handle\n")); + return EFI_INVALID_PARAMETER; + } + + // + // Get simple read access to the source file + // + OriginalFilePath = FilePath; + Status = CoreOpenImageFile ( + BootPolicy, + SourceBuffer, + SourceSize, + &FilePath, + &DeviceHandle, + &FHand, + &AuthenticationStatus + ); + if (Status == EFI_ALREADY_STARTED) { + Image = NULL; + goto Done; + } else if (EFI_ERROR (Status)) { + return Status; + } + + // + // Verify the Authentication Status through the Security Architectural Protocol + // + if ((gSecurity != NULL) && (OriginalFilePath != NULL)) { + SecurityStatus = gSecurity->FileAuthenticationState ( + gSecurity, + AuthenticationStatus, + OriginalFilePath + ); + if (EFI_ERROR (SecurityStatus) && SecurityStatus != EFI_SECURITY_VIOLATION) { + Status = SecurityStatus; + Image = NULL; + goto Done; + } + } + + + // + // Allocate a new image structure + // + Image = CoreAllocateZeroBootServicesPool (sizeof(LOADED_IMAGE_PRIVATE_DATA)); + if (Image == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Pull out just the file portion of the DevicePath for the LoadedImage FilePath + // + FilePath = OriginalFilePath; + Status = CoreHandleProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid, &HandleFilePath); + if (!EFI_ERROR (Status)) { + FilePathSize = CoreDevicePathSize (HandleFilePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL); + FilePath = (EFI_DEVICE_PATH_PROTOCOL *) ( ((UINT8 *)FilePath) + FilePathSize ); + } + + // + // Initialize the fields for an internal driver + // + Image->Signature = LOADED_IMAGE_PRIVATE_DATA_SIGNATURE; + Image->Info.SystemTable = gST; + Image->Info.DeviceHandle = DeviceHandle; + Image->Info.Revision = EFI_LOADED_IMAGE_INFORMATION_REVISION; + Image->Info.FilePath = CoreDuplicateDevicePath (FilePath); + Image->Info.ParentHandle = ParentImageHandle; + + if (NumberOfPages != NULL) { + Image->NumberOfPages = *NumberOfPages ; + } else { + Image->NumberOfPages = 0 ; + } + + // + // Install the protocol interfaces for this image + // don't fire notifications yet + // + Status = CoreInstallProtocolInterfaceNotify ( + &Image->Handle, + &gEfiLoadedImageProtocolGuid, + EFI_NATIVE_INTERFACE, + &Image->Info, + FALSE + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Install Debug Mask Protocol + // + DEBUG_CODE ( + Status = InstallDebugMaskProtocol(Image->Handle); + ASSERT_EFI_ERROR (Status); + ) + + // + // Load the image. If EntryPoint is Null, it will not be set. + // + Status = CoreLoadPeImage (BootPolicy, &FHand, Image, DstBuffer, EntryPoint, Attribute, CrossLoad); + if (EFI_ERROR (Status)) { + if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_OUT_OF_RESOURCES)) { + if (NumberOfPages != NULL) { + *NumberOfPages = Image->NumberOfPages; + } + } + goto Done; + } + if (NumberOfPages != NULL) { + *NumberOfPages = Image->NumberOfPages; + } + + // + // Register the image in the Debug Image Info Table if the attribute is set + // + if (Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION) { + CoreNewDebugImageInfoEntry (EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL, &Image->Info, Image->Handle); + } + + // + //Reinstall loaded image protocol to fire any notifications + // + Status = CoreReinstallProtocolInterface ( + Image->Handle, + &gEfiLoadedImageProtocolGuid, + &Image->Info, + &Image->Info + ); + if (EFI_ERROR (Status)) { + goto Done; + } + +#if (EFI_SPECIFICATION_VERSION >= 0x0002000A) + // + // If DevicePath parameter to the LoadImage() is not NULL, then make a copy of DevicePath, + // otherwise Loaded Image Device Path Protocol is installed with a NULL interface pointer. + // + if (OriginalFilePath != NULL) { + Image->LoadedImageDevicePath = CoreDuplicateDevicePath (OriginalFilePath); + } + + // + // Install Loaded Image Device Path Protocol onto the image handle of a PE/COFE image + // + Status = CoreInstallProtocolInterface ( + &Image->Handle, + &gEfiLoadedImageDevicePathProtocolGuid, + EFI_NATIVE_INTERFACE, + Image->LoadedImageDevicePath + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Install HII Package List Protocol onto the image handle + // + if (Image->ImageContext.HiiResourceData != 0) { + Status = CoreInstallProtocolInterface ( + &Image->Handle, + &gEfiHiiPackageListProtocolGuid, + EFI_NATIVE_INTERFACE, + (VOID *) (UINTN) Image->ImageContext.HiiResourceData + ); + if (EFI_ERROR (Status)) { + goto Done; + } + } +#endif + + // + // Success. Return the image handle + // + *ImageHandle = Image->Handle; + +Done: + // + // All done accessing the source file + // If we allocated the Source buffer, free it + // + if (FHand.FreeBuffer) { + CoreFreePool (FHand.Source); + } + + // + // There was an error. If there's an Image structure, free it + // + if (EFI_ERROR (Status)) { + if (Image != NULL) { + CoreUnloadAndCloseImage (Image, (BOOLEAN)(DstBuffer == 0)); + *ImageHandle = NULL; + } + } else if (EFI_ERROR (SecurityStatus)) { + Status = SecurityStatus; + } + + return Status; +} + + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreLoadImage ( + IN BOOLEAN BootPolicy, + IN EFI_HANDLE ParentImageHandle, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + IN VOID *SourceBuffer OPTIONAL, + IN UINTN SourceSize, + OUT EFI_HANDLE *ImageHandle + ) +/*++ + +Routine Description: + + Loads an EFI image into memory and returns a handle to the image. + +Arguments: + + BootPolicy - If TRUE, indicates that the request originates from the boot manager, + and that the boot manager is attempting to load FilePath as a boot selection. + ParentImageHandle - The caller's image handle. + FilePath - The specific file path from which the image is loaded. + SourceBuffer - If not NULL, a pointer to the memory location containing a copy of + the image to be loaded. + SourceSize - The size in bytes of SourceBuffer. + ImageHandle - Pointer to the returned image handle that is created when the image + is successfully loaded. + +Returns: + + EFI_SUCCESS - The image was loaded into memory. + EFI_NOT_FOUND - The FilePath was not found. + EFI_INVALID_PARAMETER - One of the parameters has an invalid value. + EFI_UNSUPPORTED - The image type is not supported, or the device path cannot be + parsed to locate the proper protocol for loading the file. + EFI_OUT_OF_RESOURCES - Image was not loaded due to insufficient resources. +--*/ +{ + EFI_STATUS Status; + UINT64 Ticker; + + GetTimerValue (&Ticker); + + Status = CoreLoadImageCommon ( + BootPolicy, + ParentImageHandle, + FilePath, + SourceBuffer, + SourceSize, + (EFI_PHYSICAL_ADDRESS)NULL, + NULL, + ImageHandle, + NULL, + EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION | EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION, + FALSE + ); + + if (!EFI_ERROR (Status)) { + PERF_START (0, L"LoadImage", NULL, Ticker); + PERF_END (*ImageHandle, L"LoadImage", NULL, 0); + } else { + PERF_START (0, L"Load Failed", L"CoreLoadImage", Ticker); + PERF_END (0, L"Load Failed", L"CoreLoadImage", 0); + } + + return Status; +} + + +EFI_STATUS +EFIAPI +CoreLoadImageEx ( + IN EFI_PE32_IMAGE_PROTOCOL *This, + IN EFI_HANDLE ParentImageHandle, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + IN VOID *SourceBuffer OPTIONAL, + IN UINTN SourceSize, + IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL, + OUT UINTN *NumberOfPages OPTIONAL, + OUT EFI_HANDLE *ImageHandle, + OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL, + IN UINT32 Attribute + ) +/*++ + +Routine Description: + + Loads an EFI image into memory and returns a handle to the image with extended parameters. + +Arguments: + + This - Calling context + ParentImageHandle - The caller's image handle. + FilePath - The specific file path from which the image is loaded. + SourceBuffer - If not NULL, a pointer to the memory location containing a copy of + the image to be loaded. + SourceSize - The size in bytes of SourceBuffer. + DstBuffer - The buffer to store the image. + NumberOfPages - For input, specifies the space size of the image by caller if not NULL. + For output, specifies the actual space size needed. + ImageHandle - Image handle for output. + EntryPoint - Image entry point for output. + Attribute - The bit mask of attributes to set for the load PE image. + +Returns: + + EFI_SUCCESS - The image was loaded into memory. + EFI_NOT_FOUND - The FilePath was not found. + EFI_INVALID_PARAMETER - One of the parameters has an invalid value. + EFI_UNSUPPORTED - The image type is not supported, or the device path cannot be + parsed to locate the proper protocol for loading the file. + EFI_OUT_OF_RESOURCES - Image was not loaded due to insufficient resources. +--*/ +{ + return CoreLoadImageCommon ( + FALSE, + ParentImageHandle, + FilePath, + SourceBuffer, + SourceSize, + DstBuffer, + NumberOfPages, + ImageHandle, + EntryPoint, + Attribute, + TRUE + ); +} + + + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreStartImage ( + IN EFI_HANDLE ImageHandle, + OUT UINTN *ExitDataSize, + OUT CHAR16 **ExitData OPTIONAL + ) +/*++ + +Routine Description: + + Transfer control to a loaded image's entry point. + +Arguments: + + ImageHandle - Handle of image to be started. + + ExitDataSize - Pointer of the size to ExitData + + ExitData - Pointer to a pointer to a data buffer that includes a Null-terminated + Unicode string, optionally followed by additional binary data. The string + is a description that the caller may use to further indicate the reason for + the image¡¯s exit. + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_OUT_OF_RESOURCES - No enough buffer to allocate + + EFI_SUCCESS - Successfully transfer control to the image's entry point. + +--*/ +{ + EFI_STATUS Status; + LOADED_IMAGE_PRIVATE_DATA *Image; + LOADED_IMAGE_PRIVATE_DATA *LastImage; + UINT64 HandleDatabaseKey; + + Image = CoreLoadedImageInfo (ImageHandle); + if (Image == NULL_HANDLE || Image->Started) { + return EFI_INVALID_PARAMETER; + } + + // + // Cannot start image of an unsupported processor architecture + // + if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->ImageContext.Machine)) { + return EFI_UNSUPPORTED; + } + + // + // Don't profile Objects or invalid start requests + // + PERF_START (ImageHandle, START_IMAGE_TOK, NULL, 0); + + // + // Push the current start image context, and + // link the current image to the head. This is the + // only image that can call Exit() + // + HandleDatabaseKey = CoreGetHandleDatabaseKey(); + LastImage = mCurrentImage; + mCurrentImage = Image; + Image->Tpl = gEfiCurrentTpl; + + // + // Set long jump for Exit() support + // + Image->JumpContext = CoreAllocateBootServicesPool (gEfiPeiTransferControl->JumpContextSize); + if (Image->JumpContext == NULL) { + PERF_END (ImageHandle, START_IMAGE_TOK, NULL, 0); + return EFI_OUT_OF_RESOURCES; + } + + Status = gEfiPeiTransferControl->SetJump (gEfiPeiTransferControl, Image->JumpContext); + // + // The SetJump returns EFI_SUCCESS when LongJump Buffer has been armed + // SetJump returns EFI_WARN_RETURN_FROM_LONG_JUMP as a result of the LongJump + // All other return values for SetJump are undefined. + // + if (Status == EFI_SUCCESS) { + + // + // Call the image's entry point + // + Image->Started = TRUE; + Image->Status = Image->EntryPoint (ImageHandle, Image->Info.SystemTable); + + // + // Add some debug information if the image returned with error. + // This make the user aware and check if the driver image have already released + // all the resource in this situation. + // + DEBUG_CODE ( + if (EFI_ERROR (Image->Status)) { + DEBUG ((EFI_D_ERROR, "Error: Image at %08X start failed: %x\n", Image->Info.ImageBase, Image->Status)); + } + ) + + // + // If the image returns, exit it through Exit() + // + CoreExit (ImageHandle, Image->Status, 0, NULL); + } + + // + // Image has completed. Verify the tpl is the same + // + ASSERT (Image->Tpl == gEfiCurrentTpl); + CoreRestoreTpl (Image->Tpl); + + CoreFreePool (Image->JumpContext); + + // + // Pop the current start image context + // + mCurrentImage = LastImage; + + // + // Go connect any handles that were created or modified while the image executed. + // + CoreConnectHandlesByKey (HandleDatabaseKey); + + // + // Handle the image's returned ExitData + // + DEBUG_CODE ( + if (Image->ExitDataSize != 0 || Image->ExitData != NULL) { + + DEBUG ( + (EFI_D_LOAD, + "StartImage: ExitDataSize %d, ExitData %x", + Image->ExitDataSize, + Image->ExitData) + ); + if (Image->ExitData != NULL) { + DEBUG ((EFI_D_LOAD, " (%hs)", Image->ExitData)); + } + DEBUG ((EFI_D_LOAD, "\n")); + } + ) + + // + // Return the exit data to the caller + // + if (ExitData != NULL && ExitDataSize != NULL) { + *ExitDataSize = Image->ExitDataSize; + *ExitData = Image->ExitData; + } else { + // + // Caller doesn't want the exit data, free it + // + CoreFreePool (Image->ExitData); + Image->ExitData = NULL; + } + + // + // Save the Status because Image will get destroyed if it is unloaded. + // + Status = Image->Status; + + // + // If the image returned an error, or if the image is an application + // unload it + // + if (EFI_ERROR (Image->Status) || Image->Type == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) { + CoreUnloadAndCloseImage (Image, TRUE); + } + + // + // Done + // + PERF_END (ImageHandle, START_IMAGE_TOK, NULL, 0); + return Status; +} + + +VOID +CoreUnloadAndCloseImage ( + IN LOADED_IMAGE_PRIVATE_DATA *Image, + IN BOOLEAN FreePage + ) +/*++ + +Routine Description: + + Unloads EFI image from memory. + +Arguments: + + Image - EFI image + FreePage - Free allocated pages + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + UINTN HandleIndex; + EFI_GUID **ProtocolGuidArray; + UINTN ArrayCount; + UINTN ProtocolIndex; + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfo; + UINTN OpenInfoCount; + UINTN OpenInfoIndex; + + if (Image->Ebc != NULL) { + // + // If EBC protocol exists we must perform cleanups for this image. + // + Image->Ebc->UnloadImage (Image->Ebc, Image->Handle); + } + + // + // Unload image, free Image->ImageContext->ModHandle + // + gEfiPeiPeCoffLoader->UnloadImage (&Image->ImageContext); + + // + // Free our references to the image handle + // + if (Image->Handle != NULL_HANDLE) { + + Status = CoreLocateHandleBuffer ( + AllHandles, + NULL, + NULL, + &HandleCount, + &HandleBuffer + ); + if (!EFI_ERROR (Status)) { + for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) { + Status = CoreProtocolsPerHandle ( + HandleBuffer[HandleIndex], + &ProtocolGuidArray, + &ArrayCount + ); + if (!EFI_ERROR (Status)) { + for (ProtocolIndex = 0; ProtocolIndex < ArrayCount; ProtocolIndex++) { + Status = CoreOpenProtocolInformation ( + HandleBuffer[HandleIndex], + ProtocolGuidArray[ProtocolIndex], + &OpenInfo, + &OpenInfoCount + ); + if (!EFI_ERROR (Status)) { + for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) { + if (OpenInfo[OpenInfoIndex].AgentHandle == Image->Handle) { + Status = CoreCloseProtocol ( + HandleBuffer[HandleIndex], + ProtocolGuidArray[ProtocolIndex], + Image->Handle, + OpenInfo[OpenInfoIndex].ControllerHandle + ); + } + } + if (OpenInfo != NULL) { + CoreFreePool(OpenInfo); + } + } + } + if (ProtocolGuidArray != NULL) { + CoreFreePool(ProtocolGuidArray); + } + } + } + if (HandleBuffer != NULL) { + CoreFreePool (HandleBuffer); + } + } + + CoreRemoveDebugImageInfoEntry (Image->Handle); + + Status = CoreUninstallProtocolInterface ( + Image->Handle, + &gEfiLoadedImageProtocolGuid, + &Image->Info + ); + +#if (EFI_SPECIFICATION_VERSION >= 0x0002000A) + Status = CoreUninstallProtocolInterface ( + Image->Handle, + &gEfiLoadedImageDevicePathProtocolGuid, + Image->LoadedImageDevicePath + ); + + if (Image->LoadedImageDevicePath != NULL) { + CoreFreePool (Image->LoadedImageDevicePath); + } + + if (Image->ImageContext.HiiResourceData != 0) { + Status = CoreUninstallProtocolInterface ( + Image->Handle, + &gEfiHiiPackageListProtocolGuid, + (VOID *) (UINTN) Image->ImageContext.HiiResourceData + ); + } +#endif + + // + // Uninstall Debug Mask Protocol + // + DEBUG_CODE ( + Status = UninstallDebugMaskProtocol(Image->Handle); + ASSERT_EFI_ERROR (Status); + ) + + } + + if (Image->RuntimeData != NULL) { + if (Image->RuntimeData->Link.ForwardLink != NULL) { + // + // Remove the Image from the Runtime Image list as we are about to Free it! + // + RemoveEntryList (&Image->RuntimeData->Link); + } + CoreFreePool (Image->RuntimeData); + } + + // + // Free the Image from memory + // + if ((Image->ImageBasePage != 0) && FreePage) { + CoreFreePages (Image->ImageBasePage, Image->NumberOfPages); + } + + // + // Done with the Image structure + // + if (Image->Info.FilePath != NULL) { + CoreFreePool (Image->Info.FilePath); + } + + if (Image->FixupData != NULL) { + CoreFreePool (Image->FixupData); + } + + CoreFreePool (Image); +} + + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreExit ( + IN EFI_HANDLE ImageHandle, + IN EFI_STATUS Status, + IN UINTN ExitDataSize, + IN CHAR16 *ExitData OPTIONAL + ) +/*++ + +Routine Description: + + Terminates the currently loaded EFI image and returns control to boot services. + +Arguments: + + ImageHandle - Handle that identifies the image. This parameter is passed to the image + on entry. + Status - The image¡¯s exit code. + ExitDataSize - The size, in bytes, of ExitData. Ignored if ExitStatus is + EFI_SUCCESS. + ExitData - Pointer to a data buffer that includes a Null-terminated Unicode string, + optionally followed by additional binary data. The string is a + description that the caller may use to further indicate the reason for + the image¡¯s exit. + +Returns: + + EFI_INVALID_PARAMETER - Image handle is NULL or it is not current image. + + EFI_SUCCESS - Successfully terminates the currently loaded EFI image. + + EFI_ACCESS_DENIED - Should never reach there. + + EFI_OUT_OF_RESOURCES - Could not allocate pool + +--*/ +{ + LOADED_IMAGE_PRIVATE_DATA *Image; + + Image = CoreLoadedImageInfo (ImageHandle); + if (Image == NULL_HANDLE) { + return EFI_INVALID_PARAMETER; + } + + if (!Image->Started) { + // + // The image has not been started so just free its resources + // + CoreUnloadAndCloseImage (Image, TRUE); + return EFI_SUCCESS; + } + + // + // Image has been started, verify this image can exit + // + if (Image != mCurrentImage) { + DEBUG ((EFI_D_LOAD|EFI_D_ERROR, "Exit: Image is not exitable image\n")); + return EFI_INVALID_PARAMETER; + } + + // + // Set status + // + Image->Status = Status; + + // + // If there's ExitData info, move it + // + if (ExitData != NULL) { + Image->ExitDataSize = ExitDataSize; + Image->ExitData = CoreAllocateBootServicesPool (Image->ExitDataSize); + if (Image->ExitData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + EfiCommonLibCopyMem (Image->ExitData, ExitData, Image->ExitDataSize); + } + + // + // return to StartImage + // + Status = gEfiPeiTransferControl->LongJump (gEfiPeiTransferControl, Image->JumpContext); + + // + // If we return from LongJump, then it is an error + // + ASSERT (FALSE); + return EFI_ACCESS_DENIED; +} + + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreUnloadImage ( + IN EFI_HANDLE ImageHandle + ) +/*++ + +Routine Description: + + Unloads an image. + +Arguments: + + ImageHandle - Handle that identifies the image to be unloaded. + +Returns: + + EFI_SUCCESS - The image has been unloaded. + EFI_UNSUPPORTED - The image has been sarted, and does not support unload. + EFI_INVALID_PARAMPETER - ImageHandle is not a valid image handle. + +--*/ +{ + EFI_STATUS Status; + LOADED_IMAGE_PRIVATE_DATA *Image; + + Image = CoreLoadedImageInfo (ImageHandle); + if (Image == NULL ) { + // + // The image handle is not valid + // + return EFI_INVALID_PARAMETER; + } + + if (Image->Started) { + // + // The image has been started, request it to unload. + // + Status = EFI_UNSUPPORTED; + if (Image->Info.Unload != NULL) { + Status = Image->Info.Unload (ImageHandle); + } + + } else { + // + // This Image hasn't been started, thus it can be unloaded + // + Status = EFI_SUCCESS; + } + + + if (!EFI_ERROR (Status)) { + // + // if the Image was not started or Unloaded O.K. then clean up + // + CoreUnloadAndCloseImage (Image, TRUE); + } + + return Status; +} + + +EFI_STATUS +EFIAPI +CoreUnloadImageEx ( + IN EFI_PE32_IMAGE_PROTOCOL *This, + IN EFI_HANDLE ImageHandle + ) +/*++ + +Routine Description: + + Unload the specified image. + +Arguments: + + This - Indicates the calling context. + + ImageHandle - The specified image handle. + +Returns: + + EFI_INVALID_PARAMETER - Image handle is NULL. + + EFI_UNSUPPORTED - Attempt to unload an unsupported image. + + EFI_SUCCESS - Image successfully unloaded. + +--*/ +{ + return CoreUnloadImage (ImageHandle); +} + + + +// +// This callback function is used by the EBC interpreter driver to flush the +// processor instruction cache after creating thunks. We're simply hiding +// the "this" pointer that must be passed into the real flush function. +// +STATIC +EFI_STATUS +EFIAPI +CoreFlushICache ( + IN EFI_PHYSICAL_ADDRESS Start, + IN UINT64 Length + ) +/*++ + +Routine Description: + + flush the processor instruction cache. + +Arguments: + + Start - Start adddress in memory to flush. + + Length - Length of memory to flush. + +Returns: + +--*/ +{ + return gEfiPeiFlushInstructionCache->Flush ( + gEfiPeiFlushInstructionCache, + Start, + Length + ); +} + + diff --git a/EDK/Foundation/Core/Dxe/Image/Image.h b/EDK/Foundation/Core/Dxe/Image/Image.h new file mode 100644 index 0000000..6cee212 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/Image/Image.h @@ -0,0 +1,399 @@ +/*++ + +Copyright (c) 2004 - 2008, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Image.h + +Abstract: + + EFI image loader + +--*/ + + +#ifndef _IMAGE_H_ +#define _IMAGE_H_ + + +#include "Tiano.h" +#include "LinkedList.h" +#include "DxeCore.h" + +#include EFI_PROTOCOL_PRODUCER (LoadedImage) +#include EFI_PROTOCOL_PRODUCER (LoadPe32Image) +#if (EFI_SPECIFICATION_VERSION >= 0x0002000A) +#include EFI_PROTOCOL_PRODUCER (LoadedImageDevicePath) +#include EFI_PROTOCOL_CONSUMER (LoadFile2) +#include EFI_PROTOCOL_PRODUCER (HiiPackageList) +#endif + +#include EFI_PROTOCOL_CONSUMER (Ebc) +#include EFI_PROTOCOL_CONSUMER (SimpleFileSystem) +#include EFI_PROTOCOL_CONSUMER (FileInfo) +#include EFI_PROTOCOL_CONSUMER (LoadFile) +#include EFI_PROTOCOL_CONSUMER (FirmwareVolume) + +#define LOADED_IMAGE_PRIVATE_DATA_SIGNATURE EFI_SIGNATURE_32('l','d','r','i') + +typedef struct { + UINTN Signature; // Data Signature + EFI_HANDLE Handle; // Image handle + UINTN Type; // Image type + + BOOLEAN Started; // If entrypoint has been called + + EFI_IMAGE_ENTRY_POINT EntryPoint; // The image's entry point + EFI_LOADED_IMAGE_PROTOCOL Info; // loaded image protocol + +#if (EFI_SPECIFICATION_VERSION >= 0x0002000A) + EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath; // Loaded Image Device Path Protocl pointer +#endif + + EFI_PHYSICAL_ADDRESS ImageBasePage; // Location in memory + UINTN NumberOfPages; // Number of pages + + CHAR8 *FixupData; // Original fixup data + + EFI_TPL Tpl; // Tpl of started image + EFI_STATUS Status; // Status returned by started image + + UINTN ExitDataSize; // Size of ExitData from started image + VOID *ExitData; // Pointer to exit data from started image + VOID *JumpContext; // Pointer to buffer for context save/retore + UINT16 Machine; // Machine type from PE image + + EFI_EBC_PROTOCOL *Ebc; // EBC Protocol pointer + + EFI_RUNTIME_IMAGE_ENTRY *RuntimeData; // Runtime image list + + EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; // PeCoffLoader ImageContext +} LOADED_IMAGE_PRIVATE_DATA; + +#define LOADED_IMAGE_PRIVATE_DATA_FROM_THIS(a) \ + CR(a, LOADED_IMAGE_PRIVATE_DATA, Info, LOADED_IMAGE_PRIVATE_DATA_SIGNATURE) + + +#define LOAD_PE32_IMAGE_PRIVATE_DATA_SIGNATURE EFI_SIGNATURE_32('l','p','e','i') + +typedef struct { + UINTN Signature; + EFI_HANDLE Handle; + EFI_PE32_IMAGE_PROTOCOL Pe32Image; +} LOAD_PE32_IMAGE_PRIVATE_DATA; + +#define LOAD_PE32_IMAGE_PRIVATE_DATA_FROM_THIS(a) \ + CR(a, LOAD_PE32_IMAGE_PRIVATE_DATA, Pe32Image, LOAD_PE32_IMAGE_PRIVATE_DATA_SIGNATURE) + +// +// Private Data Types +// +#define IMAGE_FILE_HANDLE_SIGNATURE EFI_SIGNATURE_32('i','m','g','f') +typedef struct { + UINTN Signature; + BOOLEAN FreeBuffer; + VOID *Source; + UINTN SourceSize; +} IMAGE_FILE_HANDLE; + + +// +// Abstractions for reading image contents +// + +EFI_STATUS +CoreOpenImageFile ( + IN BOOLEAN BootPolicy, + IN VOID *SourceBuffer OPTIONAL, + IN UINTN SourceSize, + IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath, + OUT EFI_HANDLE *DeviceHandle, + IN IMAGE_FILE_HANDLE *ImageFileHandle, + OUT UINT32 *AuthenticationStatus + ) +/*++ + +Routine Description: + + Opens a file for (simple) reading. The simple read abstraction + will access the file either from a memory copy, from a file + system interface, or from the load file interface. + +Arguments: + + BootPolicy - Policy for Open Image File. + SourceBuffer - Pointer to the memory location containing copy + of the image to be loaded. + SourceSize - The size in bytes of SourceBuffer. + FilePath - The specific file path from which the image is loaded + DeviceHandle - Pointer to the return device handle. + ImageFileHandle - Pointer to the image file handle. + AuthenticationStatus - Pointer to a caller-allocated UINT32 in which the authentication status is returned. + +Returns: + + A handle to access the file + +--*/ +; + + +EFI_STATUS +EFIAPI +CoreReadImageFile ( + IN VOID *UserHandle, + IN UINTN Offset, + IN OUT UINTN *ReadSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Read image file (specified by UserHandle) into user specified buffer with specified offset + and length. + +Arguments: + + UserHandle - Image file handle + + Offset - Offset to the source file + + ReadSize - For input, pointer of size to read; + For output, pointer of size actually read. + + Buffer - Buffer to write into + +Returns: + + EFI_SUCCESS - Successfully read the specified part of file into buffer. + +--*/ +; + +VOID +EFIAPI +CoreCloseImageFile ( + IN IMAGE_FILE_HANDLE *ImageFileHandle + ) +/*++ + +Routine Description: + + A function out of date, should be removed. + +Arguments: + + ImageFileHandle - Handle of the file to close + +Returns: + + None + +--*/ +; + +// +// Image processing worker functions +// +EFI_STATUS +CoreDevicePathToInterface ( + IN EFI_GUID *Protocol, + IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath, + OUT VOID **Interface, + OUT EFI_HANDLE *Handle + ) +/*++ + +Routine Description: + + Search a handle to a device on a specified device path that supports a specified protocol, + interface of that protocol on that handle is another output. + +Arguments: + + Protocol - The protocol to search for + + FilePath - The specified device path + + Interface - Interface of the protocol on the handle + + Handle - The handle to the device on the specified device path that supports the protocol. + +Returns: + + Status code. + +--*/ +; + +STATIC +EFI_STATUS +CoreLoadPeImage ( + IN BOOLEAN BootPolicy, + IN VOID *Pe32Handle, + IN LOADED_IMAGE_PRIVATE_DATA *Image, + IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL, + OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL, + IN UINT32 Attribute, + IN BOOLEAN CrossLoad + ) +/*++ + +Routine Description: + + Loads, relocates, and invokes a PE/COFF image + +Arguments: + + Pe32Handle - The handle of PE32 image + Image - PE image to be loaded + DstBuffer - The buffer to store the image + EntryPoint - A pointer to the entry point + Attribute - The bit mask of attributes to set for the load PE image + CrossLoad - Whether expect to support cross architecture loading + +Returns: + + EFI_SUCCESS - The file was loaded, relocated, and invoked + + EFI_OUT_OF_RESOURCES - There was not enough memory to load and relocate the PE/COFF file + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_BUFFER_TOO_SMALL - Buffer for image is too small + +--*/ +; + +LOADED_IMAGE_PRIVATE_DATA * +CoreLoadedImageInfo ( + IN EFI_HANDLE ImageHandle + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ImageHandle - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +VOID +CoreUnloadAndCloseImage ( + IN LOADED_IMAGE_PRIVATE_DATA *Image, + IN BOOLEAN FreePage + ) +/*++ + +Routine Description: + + Unloads EFI image from memory. + +Arguments: + + Image - EFI image + FreePage - Free allocated pages + +Returns: + + None + +--*/ +; + + +// +// Exported Image functions +// + +EFI_STATUS +EFIAPI +CoreLoadImageEx ( + IN EFI_PE32_IMAGE_PROTOCOL *This, + IN EFI_HANDLE ParentImageHandle, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + IN VOID *SourceBuffer OPTIONAL, + IN UINTN SourceSize, + IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL, + OUT UINTN *NumberOfPages OPTIONAL, + OUT EFI_HANDLE *ImageHandle, + OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL, + IN UINT32 Attribute + ) +/*++ + +Routine Description: + + Loads an EFI image into memory and returns a handle to the image with extended parameters. + +Arguments: + + ParentImageHandle - The caller's image handle. + FilePath - The specific file path from which the image is loaded. + SourceBuffer - If not NULL, a pointer to the memory location containing a copy of + the image to be loaded. + SourceSize - The size in bytes of SourceBuffer. + DstBuffer - The buffer to store the image. + NumberOfPages - For input, specifies the space size of the image by caller if not NULL. + For output, specifies the actual space size needed. + ImageHandle - Image handle for output. + EntryPoint - Image entry point for output. + Attribute - The bit mask of attributes to set for the load PE image. + +Returns: + + EFI_SUCCESS - The image was loaded into memory. + EFI_NOT_FOUND - The FilePath was not found. + EFI_INVALID_PARAMETER - One of the parameters has an invalid value. + EFI_UNSUPPORTED - The image type is not supported, or the device path cannot be + parsed to locate the proper protocol for loading the file. + EFI_OUT_OF_RESOURCES - Image was not loaded due to insufficient resources. +--*/ +; + +EFI_STATUS +EFIAPI +CoreUnloadImageEx ( + IN EFI_PE32_IMAGE_PROTOCOL *This, + IN EFI_HANDLE ImageHandle + ) +/*++ + +Routine Description: + + Unload the specified image. + +Arguments: + + This - Indicates the calling context. + + ImageHandle - The specified image handle. + +Returns: + + EFI_INVALID_PARAMETER - Image handle is NULL. + + EFI_UNSUPPORTED - Attempt to unload an unsupported image. + + EFI_SUCCESS - Image successfully unloaded. + +--*/ +; +#endif diff --git a/EDK/Foundation/Core/Dxe/Image/ImageFile.c b/EDK/Foundation/Core/Dxe/Image/ImageFile.c new file mode 100644 index 0000000..462446f --- /dev/null +++ b/EDK/Foundation/Core/Dxe/Image/ImageFile.c @@ -0,0 +1,646 @@ +/*++ + +Copyright (c) 2004 - 2011, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ImageFile.c + + +Abstract: + + + + +Revision History + +--*/ + +#include "Image.h" +#include "DxeCore.h" + + +VOID +CoreDevicePathToFileName ( + IN FILEPATH_DEVICE_PATH *FilePath, + OUT CHAR16 **String + ); + + + +EFI_STATUS +CoreOpenImageFile ( + IN BOOLEAN BootPolicy, + IN VOID *SourceBuffer OPTIONAL, + IN UINTN SourceSize, + IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath, + OUT EFI_HANDLE *DeviceHandle, + IN IMAGE_FILE_HANDLE *ImageFileHandle, + OUT UINT32 *AuthenticationStatus + ) +/*++ + +Routine Description: + + Opens a file for (simple) reading. The simple read abstraction + will access the file either from a memory copy, from a file + system interface, or from the load file interface. + +Arguments: + + BootPolicy - Policy for Open Image File. + SourceBuffer - Pointer to the memory location containing copy + of the image to be loaded. + SourceSize - The size in bytes of SourceBuffer. + FilePath - The specific file path from which the image is loaded + DeviceHandle - Pointer to the return device handle. + ImageFileHandle - Pointer to the image file handle. + AuthenticationStatus - Pointer to a caller-allocated UINT32 in which the authentication status is returned. + +Returns: + + EFI_SUCCESS - Image file successfully opened. + + EFI_LOAD_ERROR - If the caller passed a copy of the file, and SourceSize is 0. + + EFI_INVALID_PARAMETER - File path is not valid. + + EFI_NOT_FOUND - File not found. + +--*/ +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *TempFilePath; + FILEPATH_DEVICE_PATH *FilePathNode; + MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FwVolFilePathNode; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume; + EFI_FILE_HANDLE FileHandle; + EFI_FILE_HANDLE LastHandle; + EFI_LOAD_FILE_PROTOCOL *LoadFile; +#if (EFI_SPECIFICATION_VERSION >= 0x0002000A) + EFI_LOAD_FILE2_PROTOCOL *LoadFile2; +#endif + EFI_SECTION_TYPE SectionType; + UINT8 *Pe32Buffer; + UINTN Pe32BufferSize; + EFI_FV_FILETYPE Type; + EFI_FV_FILE_ATTRIBUTES Attrib; + EFI_FILE_INFO *FileInfo; + UINTN FileInfoSize; + EFI_GUID *NameGuid; + FILEPATH_DEVICE_PATH *OriginalFilePathNode; +#if (PI_SPECIFICATION_VERSION < 0x00010000) + EFI_FIRMWARE_VOLUME_PROTOCOL *FwVol; +#else + EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol; +#endif + + *AuthenticationStatus = 0; + EfiCommonLibZeroMem (ImageFileHandle, sizeof (IMAGE_FILE_HANDLE)); + ImageFileHandle->Signature = IMAGE_FILE_HANDLE_SIGNATURE; + + // + // If the caller passed a copy of the file, then just use it + // + if (SourceBuffer != NULL) { + ImageFileHandle->Source = SourceBuffer; + ImageFileHandle->SourceSize = SourceSize; + *DeviceHandle = NULL; + CoreLocateDevicePath (&gEfiDevicePathProtocolGuid, FilePath, DeviceHandle); + if (SourceSize > 0) { + Status = EFI_SUCCESS; + } else { + Status = EFI_LOAD_ERROR; + } + goto Done; + } + + // + // Make sure FilePath is valid + // + if (*FilePath == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Check to see if it's in a Firmware Volume + // + FwVolFilePathNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) *FilePath; + Status = CoreDevicePathToInterface ( + #if (PI_SPECIFICATION_VERSION < 0x00010000) + &gEfiFirmwareVolumeProtocolGuid, + #else + &gEfiFirmwareVolume2ProtocolGuid, + #endif + (EFI_DEVICE_PATH_PROTOCOL **)&FwVolFilePathNode, + (VOID*)&FwVol, + DeviceHandle + ); + if (!EFI_ERROR (Status) && (FwVol != NULL)) { + // + // For FwVol File system there is only a single file name that is a GUID. + // + NameGuid = CoreGetNameGuidFromFwVolDevicePathNode (FwVolFilePathNode); + if (NameGuid != NULL) { + + SectionType = EFI_SECTION_PE32; + Pe32Buffer = NULL; + Status = FwVol->ReadSection ( + FwVol, + &FwVolFilePathNode->NameGuid, + SectionType, + 0, + &Pe32Buffer, + &Pe32BufferSize, + AuthenticationStatus + ); + if (EFI_ERROR (Status)) { + // + // Try a raw file, since a PE32 SECTION does not exist + // + if (Pe32Buffer != NULL) { + CoreFreePool (Pe32Buffer); + *AuthenticationStatus = 0; + } + Pe32Buffer = NULL; + Status = FwVol->ReadFile ( + FwVol, + &FwVolFilePathNode->NameGuid, + &Pe32Buffer, + &Pe32BufferSize, + &Type, + &Attrib, + AuthenticationStatus + ); + } + + if (!EFI_ERROR (Status)) { + // + // One of the reads passed so we are done + // + ImageFileHandle->Source = Pe32Buffer; + ImageFileHandle->SourceSize = Pe32BufferSize; + ImageFileHandle->FreeBuffer = TRUE; + goto Done; + } + } + } + + // + // Attempt to access the file via a file system interface + // + FilePathNode = (FILEPATH_DEVICE_PATH *) *FilePath; + Status = CoreDevicePathToInterface ( + &gEfiSimpleFileSystemProtocolGuid, + (EFI_DEVICE_PATH_PROTOCOL **)&FilePathNode, + (VOID*)&Volume, + DeviceHandle + ); + if (!EFI_ERROR (Status) && (Volume != NULL)) { + // + // Open the Volume to get the File System handle + // + Status = Volume->OpenVolume (Volume, &FileHandle); + if (!EFI_ERROR (Status)) { + // + // Duplicate the device path to avoid the access to unaligned device path node. + // Because the device path consists of one or more FILE PATH MEDIA DEVICE PATH + // nodes, It assures the fields in device path nodes are 2 byte aligned. + // + FilePathNode = (FILEPATH_DEVICE_PATH *) CoreDuplicateDevicePath( + (EFI_DEVICE_PATH_PROTOCOL *)(UINTN)FilePathNode + ); + if (FilePathNode == NULL) { + FileHandle->Close (FileHandle); + FileHandle = NULL; + Status = EFI_OUT_OF_RESOURCES; + } else { + OriginalFilePathNode = FilePathNode; + // + // Parse each MEDIA_FILEPATH_DP node. There may be more than one, since the + // directory information and filename can be seperate. The goal is to inch + // our way down each device path node and close the previous node + // + while (!IsDevicePathEnd (&FilePathNode->Header)) { + if (DevicePathType (&FilePathNode->Header) != MEDIA_DEVICE_PATH || + DevicePathSubType (&FilePathNode->Header) != MEDIA_FILEPATH_DP) { + Status = EFI_UNSUPPORTED; + } + + if (EFI_ERROR (Status)) { + // + // Exit loop on Error + // + break; + } + + LastHandle = FileHandle; + FileHandle = NULL; + Status = LastHandle->Open ( + LastHandle, + &FileHandle, + FilePathNode->PathName, + EFI_FILE_MODE_READ, + 0 + ); + + // + // Close the previous node + // + LastHandle->Close (LastHandle); + + FilePathNode = (FILEPATH_DEVICE_PATH *) NextDevicePathNode (&FilePathNode->Header); + } + // + // Free the allocated memory pool + // + CoreFreePool (OriginalFilePathNode); + } + + if (!EFI_ERROR (Status)) { + // + // We have found the file. Now we need to read it. Before we can read the file we need to + // figure out how big the file is. + // + FileInfo = NULL; + FileInfoSize = sizeof (EFI_FILE_INFO); + while (CoreGrowBuffer (&Status, &FileInfo, FileInfoSize)) { + // + // Automatically allocate buffer of the correct size and make the call + // + Status = FileHandle->GetInfo ( + FileHandle, + &gEfiFileInfoGuid, + &FileInfoSize, + FileInfo + ); + } + if (!EFI_ERROR (Status) && (FileInfo != NULL)) { + // + // Allocate space for the file + // + ImageFileHandle->Source = CoreAllocateBootServicesPool ((UINTN)FileInfo->FileSize); + if (ImageFileHandle->Source != NULL) { + // + // Read the file into the buffer we allocated + // + ImageFileHandle->SourceSize = (UINTN)FileInfo->FileSize; + ImageFileHandle->FreeBuffer = TRUE; + Status = FileHandle->Read (FileHandle, &ImageFileHandle->SourceSize, ImageFileHandle->Source); + } else { + Status = EFI_OUT_OF_RESOURCES; + } + // + // Close the file since we are done + // + FileHandle->Close (FileHandle); + CoreFreePool (FileInfo); + goto Done; + } + + if (FileInfo != NULL) { + CoreFreePool (FileInfo); + } + } + if (FileHandle != NULL) { + FileHandle->Close (FileHandle); + } + } + } + + +#if (EFI_SPECIFICATION_VERSION >= 0x0002000A) + // + // Try LoadFile2 style + // + if (!BootPolicy) { + TempFilePath = *FilePath; + Status = CoreDevicePathToInterface ( + &gEfiLoadFile2ProtocolGuid, + &TempFilePath, + (VOID*)&LoadFile2, + DeviceHandle + ); + if (!EFI_ERROR (Status) && (LoadFile2 != NULL)) { + // + // Call LoadFile2 with the correct buffer size + // + while (CoreGrowBuffer (&Status, &ImageFileHandle->Source, ImageFileHandle->SourceSize)) { + Status = LoadFile2->LoadFile ( + LoadFile2, + TempFilePath, + BootPolicy, + &ImageFileHandle->SourceSize, + ImageFileHandle->Source + ); + // + // If success or other error happens, stop loop + // + if (Status != EFI_BUFFER_TOO_SMALL) { + break; + } + } + + if (!EFI_ERROR (Status)) { + ImageFileHandle->FreeBuffer = TRUE; + goto Done; + } + } + } +#endif + + // + // Try LoadFile style + // + TempFilePath = *FilePath; + Status = CoreDevicePathToInterface ( + &gEfiLoadFileProtocolGuid, + &TempFilePath, + (VOID*)&LoadFile, + DeviceHandle + ); + if (!EFI_ERROR (Status) && (LoadFile != NULL)) { + // + // Call LoadFile with the correct buffer size + // + while (CoreGrowBuffer (&Status, &ImageFileHandle->Source, ImageFileHandle->SourceSize)) { + Status = LoadFile->LoadFile ( + LoadFile, + TempFilePath, + BootPolicy, + &ImageFileHandle->SourceSize, + ImageFileHandle->Source + ); + // + // If success or other error happens, stop loop + // + if (Status != EFI_BUFFER_TOO_SMALL) { + break; + } + } + + if (!EFI_ERROR (Status) || Status == EFI_ALREADY_STARTED) { + ImageFileHandle->FreeBuffer = TRUE; + goto Done; + } + } + + // + // Nothing else to try + // + DEBUG ((EFI_D_LOAD|EFI_D_WARN, "CoreOpenImageFile: Device did not support a known load protocol\n")); + Status = EFI_NOT_FOUND; + +Done: + + // + // If the file was not accessed, clean up + // + if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) { + if (ImageFileHandle->FreeBuffer) { + // + // Free the source buffer if we allocated it + // + CoreFreePool (ImageFileHandle->Source); + } + } + + return Status; +} + + + +EFI_STATUS +EFIAPI +CoreReadImageFile ( + IN VOID *UserHandle, + IN UINTN Offset, + IN OUT UINTN *ReadSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Read image file (specified by UserHandle) into user specified buffer with specified offset + and length. + +Arguments: + + UserHandle - Image file handle + + Offset - Offset to the source file + + ReadSize - For input, pointer of size to read; + For output, pointer of size actually read. + + Buffer - Buffer to write into + +Returns: + + EFI_SUCCESS - Successfully read the specified part of file into buffer. + +--*/ +{ + UINTN EndPosition; + IMAGE_FILE_HANDLE *FHand; + + FHand = (IMAGE_FILE_HANDLE *)UserHandle; + ASSERT (FHand->Signature == IMAGE_FILE_HANDLE_SIGNATURE); + + // + // Move data from our local copy of the file + // + EndPosition = Offset + *ReadSize; + if (EndPosition > FHand->SourceSize) { + *ReadSize = (UINT32)(FHand->SourceSize - Offset); + } + if (Offset >= FHand->SourceSize) { + *ReadSize = 0; + } + + EfiCommonLibCopyMem (Buffer, (CHAR8 *)FHand->Source + Offset, *ReadSize); + return EFI_SUCCESS; +} + +EFI_STATUS +CoreDevicePathToInterface ( + IN EFI_GUID *Protocol, + IN EFI_DEVICE_PATH_PROTOCOL **FilePath, + OUT VOID **Interface, + OUT EFI_HANDLE *Handle + ) +/*++ + +Routine Description: + + Search a handle to a device on a specified device path that supports a specified protocol, + interface of that protocol on that handle is another output. + +Arguments: + + Protocol - The protocol to search for + + FilePath - The specified device path + + Interface - Interface of the protocol on the handle + + Handle - The handle to the device on the specified device path that supports the protocol. + +Returns: + + Status code. + +--*/ +{ + EFI_STATUS Status; + + Status = CoreLocateDevicePath (Protocol, FilePath, Handle); + if (!EFI_ERROR (Status)) { + Status = CoreHandleProtocol (*Handle, Protocol, Interface); + } + return Status; +} + + +VOID +CoreDevicePathToFileName ( + IN FILEPATH_DEVICE_PATH *FilePath, + OUT CHAR16 **String + ) +/*++ + +Routine Description: + + Transfer a device's full path a string. + +Arguments: + + FilePath - Device path + + String - The string represent the device's full path + +Returns: + + None + +--*/ +{ + UINTN StringSize; + FILEPATH_DEVICE_PATH *FilePathNode; + CHAR16 *Str; + + *String = NULL; + StringSize = 0; + FilePathNode = FilePath; + while (!IsDevicePathEnd (&FilePathNode->Header)) { + + // + // For filesystem access each node should be a filepath component + // + if (DevicePathType (&FilePathNode->Header) != MEDIA_DEVICE_PATH || + DevicePathSubType (&FilePathNode->Header) != MEDIA_FILEPATH_DP) { + + return; + } + + StringSize += EfiStrLen (FilePathNode->PathName); + + FilePathNode = (FILEPATH_DEVICE_PATH *) NextDevicePathNode (&FilePathNode->Header); + } + + *String = CoreAllocateBootServicesPool (StringSize); + if (*String == NULL) { + return; + } + + FilePathNode = FilePath; + Str = *String; + while (!IsDevicePathEnd (&FilePathNode->Header)) { + EfiStrCat (Str, FilePathNode->PathName); + FilePathNode = (FILEPATH_DEVICE_PATH *) NextDevicePathNode (&FilePathNode->Header); + } +} + + +BOOLEAN +CoreGrowBuffer ( + IN OUT EFI_STATUS *Status, + IN OUT VOID **Buffer, + IN UINTN BufferSize + ) +/*++ + +Routine Description: + + Helper function called as part of the code needed + to allocate the proper sized buffer for various + EFI interfaces. + +Arguments: + + Status - Current status + + Buffer - Current allocated buffer, or NULL + + BufferSize - Current buffer size needed + +Returns: + + TRUE - if the buffer was reallocated and the caller + should try the API again. + + FALSE - buffer could not be allocated and the caller + should not try the API again. + +--*/ +{ + BOOLEAN TryAgain; + + TryAgain = FALSE; + // + // If this is an initial request, buffer will be null with a new buffer size + // + if (*Buffer == NULL) { + *Status = EFI_BUFFER_TOO_SMALL; + } + + if (BufferSize == 0) { + return TRUE; + } + + // + // If the status code is "buffer too small", resize the buffer + // + + if (*Status == EFI_BUFFER_TOO_SMALL) { + if (*Buffer != NULL) { + CoreFreePool (*Buffer); + } + + *Buffer = CoreAllocateBootServicesPool (BufferSize); + if (*Buffer != NULL) { + TryAgain = TRUE; + } else { + *Status = EFI_OUT_OF_RESOURCES; + } + } + + // + // If there's an error, free the buffer + // + if ((!TryAgain) && (EFI_ERROR (*Status)) && (*Buffer)) { + CoreFreePool (*Buffer); + *Buffer = NULL; + } + + return TryAgain; +} + diff --git a/EDK/Foundation/Core/Dxe/Include/DxeCore.h b/EDK/Foundation/Core/Dxe/Include/DxeCore.h new file mode 100644 index 0000000..2587d7c --- /dev/null +++ b/EDK/Foundation/Core/Dxe/Include/DxeCore.h @@ -0,0 +1,2535 @@ +/*++ + +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DxeCore.h + +Abstract: + +Revision History + +--*/ + +#ifndef _DXECORE_H_ +#define _DXECORE_H_ + +#include EFI_GUID_DEFINITION (PeiFlushInstructionCache) +#include EFI_GUID_DEFINITION (PeiPeCoffLoader) +#include EFI_GUID_DEFINITION (PeiTransferControl) +#include EFI_GUID_DEFINITION (Hob) +#include EFI_GUID_DEFINITION (StatusCodeDataTypeId) +#include EFI_GUID_DEFINITION (DxeServices) +#include EFI_GUID_DEFINITION (MemoryTypeInformation) +#include EFI_GUID_DEFINITION (StatusCodeCallerId) +#include EFI_GUID_DEFINITION (EventGroup) +#include EFI_GUID_DEFINITION (EventLegacyBios) +#include EFI_GUID_DEFINITION (FrameworkDevicePath) +#include EFI_ARCH_PROTOCOL_DEFINITION (Cpu) +#include EFI_ARCH_PROTOCOL_DEFINITION (Metronome) +#include EFI_ARCH_PROTOCOL_DEFINITION (MonotonicCounter) +#include EFI_ARCH_PROTOCOL_DEFINITION (Timer) +#include EFI_ARCH_PROTOCOL_DEFINITION (Bds) +#include EFI_ARCH_PROTOCOL_DEFINITION (Reset) +#include EFI_ARCH_PROTOCOL_DEFINITION (RealTimeClock) +#include EFI_ARCH_PROTOCOL_DEFINITION (Variable) +#include EFI_ARCH_PROTOCOL_DEFINITION (VariableWrite) +#include EFI_ARCH_PROTOCOL_DEFINITION (Capsule) +#include EFI_ARCH_PROTOCOL_DEFINITION (WatchdogTimer) +#include EFI_ARCH_PROTOCOL_DEFINITION (Runtime) +#include EFI_ARCH_PROTOCOL_DEFINITION (StatusCode) +#include EFI_ARCH_PROTOCOL_DEFINITION (Security) +#include EFI_PROTOCOL_DEFINITION (Decompress) +#include EFI_PROTOCOL_DEFINITION (TianoDecompress) +#include EFI_PROTOCOL_DEFINITION (CustomizedDecompress) +#include EFI_PROTOCOL_DEFINITION (FirmwareVolume) +#include EFI_PROTOCOL_DEFINITION (FirmwareVolumeDispatch) +#include EFI_PROTOCOL_DEFINITION (LoadedImage) +#include EFI_PROTOCOL_DEFINITION (TcgService) +#include "LinkedList.h" +#include "DebugImageInfo.h" +#include "EfiCommonLib.h" +#include "Library.h" +#include "Peihob.h" +#include "EfiHobLib.h" +#include "DebugMask.h" + + +typedef struct { + EFI_GUID *ProtocolGuid; + VOID **Protocol; + EFI_EVENT Event; + VOID *Registration; + BOOLEAN Present; +} ARCHITECTURAL_PROTOCOL_ENTRY; + + +// +// DXE Dispatcher Data structures +// + +#define KNOWN_HANDLE_SIGNATURE EFI_SIGNATURE_32('k','n','o','w') +typedef struct { + UINTN Signature; + EFI_LIST_ENTRY Link; // mFvHandleList + EFI_HANDLE Handle; +} KNOWN_HANDLE; + + +#define EFI_CORE_DRIVER_ENTRY_SIGNATURE EFI_SIGNATURE_32('d','r','v','r') +typedef struct { + UINTN Signature; + EFI_LIST_ENTRY Link; // mDriverList + + EFI_LIST_ENTRY ScheduledLink; // mScheduledQueue + + EFI_HANDLE FvHandle; + EFI_GUID FileName; + EFI_DEVICE_PATH_PROTOCOL *FvFileDevicePath; +#if (PI_SPECIFICATION_VERSION < 0x00010000) + EFI_FIRMWARE_VOLUME_PROTOCOL *Fv; +#else + EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv; +#endif + VOID *Depex; + UINTN DepexSize; + + BOOLEAN Before; + BOOLEAN After; + EFI_GUID BeforeAfterGuid; + + BOOLEAN Dependent; + BOOLEAN Unrequested; + BOOLEAN Scheduled; + BOOLEAN Untrusted; + BOOLEAN Initialized; + BOOLEAN DepexProtocolError; + + EFI_HANDLE ImageHandle; + +} EFI_CORE_DRIVER_ENTRY; + +// +//The data structure of GCD memory map entry +// +#define EFI_GCD_MAP_SIGNATURE EFI_SIGNATURE_32('g','c','d','m') +typedef struct { + UINTN Signature; + EFI_LIST_ENTRY Link; + EFI_PHYSICAL_ADDRESS BaseAddress; + UINT64 EndAddress; + UINT64 Capabilities; + UINT64 Attributes; + EFI_GCD_MEMORY_TYPE GcdMemoryType; + EFI_GCD_IO_TYPE GcdIoType; + EFI_HANDLE ImageHandle; + EFI_HANDLE DeviceHandle; +} EFI_GCD_MAP_ENTRY; + +// +// DXE Core Global Variables +// +extern EFI_SYSTEM_TABLE *gST; +extern EFI_BOOT_SERVICES *gBS; +extern EFI_RUNTIME_SERVICES *gRT; +extern EFI_DXE_SERVICES *gDS; +extern EFI_HANDLE gDxeCoreImageHandle; + +extern EFI_DECOMPRESS_PROTOCOL *gEfiDecompress; +extern EFI_PEI_FLUSH_INSTRUCTION_CACHE_PROTOCOL *gEfiPeiFlushInstructionCache; +extern EFI_PEI_PE_COFF_LOADER_PROTOCOL *gEfiPeiPeCoffLoader; +extern EFI_PEI_TRANSFER_CONTROL_PROTOCOL *gEfiPeiTransferControl; + +extern EFI_RUNTIME_ARCH_PROTOCOL *gRuntime; +extern EFI_CPU_ARCH_PROTOCOL *gCpu; +extern EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *gWatchdogTimer; +extern EFI_METRONOME_ARCH_PROTOCOL *gMetronome; +extern EFI_TIMER_ARCH_PROTOCOL *gTimer; +extern EFI_SECURITY_ARCH_PROTOCOL *gSecurity; +extern EFI_BDS_ARCH_PROTOCOL *gBds; +extern EFI_STATUS_CODE_PROTOCOL *gStatusCode; + +extern EFI_TPL gEfiCurrentTpl; + +extern EFI_GUID *gDxeCoreFileName; +extern EFI_LOADED_IMAGE_PROTOCOL *gDxeCoreLoadedImage; + +extern EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1]; + +extern EFI_RUNTIME_ARCH_PROTOCOL gRuntimeTemplate; + +// +// Service Initialization Functions +// + + +VOID +CoreInitializePool ( + VOID + ) +/*++ + +Routine Description: + + Called to initialize the pool. + +Arguments: + + None + +Returns: + + None + +--*/ +; + +VOID +CoreAddMemoryDescriptor ( + IN EFI_MEMORY_TYPE Type, + IN EFI_PHYSICAL_ADDRESS Start, + IN UINT64 NumberOfPages, + IN UINT64 Attribute + ) +/*++ + +Routine Description: + + Called to initialize the memory map and add descriptors to + the current descriptor list. + + N.B. The first descriptor that is added must be general usable + memory as the addition allocates heap. + +Arguments: + + Type - The type of memory to add + + Start - The starting address in the memory range + Must be page aligned + + NumberOfPages - The number of pages in the range + + Attribute - Attributes of the memory to add + +Returns: + + None. The range is added to the memory map + +--*/ +; + +VOID +CoreReleaseGcdMemoryLock ( + VOID + ) +/*++ + +Routine Description: + Release memory lock on mGcdMemorySpaceLock + +Arguments: + None + +Returns: + None + +--*/ +; + +VOID +CoreAcquireGcdMemoryLock ( + VOID + ) +/*++ + +Routine Description: + Acquire memory lock on mGcdMemorySpaceLock + +Arguments: + None + +Returns: + None + +--*/ +; + +EFI_STATUS +CoreInitializeMemoryServices ( + IN VOID **HobStart, + IN EFI_PHYSICAL_ADDRESS *MemoryBaseAddress, + IN UINT64 *MemoryLength + ) +/*++ + +Routine Description: + + External function. Initializes the GCD and memory services based on the memory + descriptor HOBs. This function is responsible for priming the GCD map and the + memory map, so memory allocations and resource allocations can be made. The first + part of this function can not depend on any memory services until at least one + memory descriptor is provided to the memory services. Then the memory services + can be used to intialize the GCD map. + +Arguments: + + HobStart - The start address of the HOB. + + MemoryBaseAddress - Start address of memory region found to init DXE core. + + MemoryLength - Length of memory region found to init DXE core. + +Returns: + + EFI_SUCCESS - Memory services successfully initialized. + +--*/ +; + + +EFI_STATUS +CoreInitializeGcdServices ( + IN OUT VOID **HobStart, + IN EFI_PHYSICAL_ADDRESS MemoryBaseAddress, + IN UINT64 MemoryLength + ) +/*++ + +Routine Description: + + External function. Initializes the GCD and memory services based on the memory + descriptor HOBs. This function is responsible for priming the GCD map and the + memory map, so memory allocations and resource allocations can be made. The first + part of this function can not depend on any memory services until at least one + memory descriptor is provided to the memory services. Then the memory services + can be used to intialize the GCD map. The HobStart will be relocated to a pool + buffer. + +Arguments: + + HobStart - The start address of the HOB + + MemoryBaseAddress - Start address of memory region found to init DXE core. + + MemoryLength - Length of memory region found to init DXE core. + + +Returns: + + EFI_SUCCESS - GCD services successfully initialized. + +--*/ +; + +EFI_STATUS +CoreInitializeEventServices ( + VOID + ) +/*++ + +Routine Description: + + Initializes "event" support and populates parts of the System and Runtime Table. + +Arguments: + + None + +Returns: + + EFI_SUCCESS - Always return success + +--*/ +; + +EFI_STATUS +CoreInitializeImageServices ( + IN VOID *HobStart + ) +/*++ + +Routine Description: + + Add the Image Services to EFI Boot Services Table and install the protocol + interfaces for this image. + +Arguments: + + HobStart - The HOB to initialize + +Returns: + + Status code. + +--*/ +; + +VOID +CoreNotifyOnArchProtocolInstallation ( + VOID + ) +/*++ + +Routine Description: + Creates an event that is fired everytime a Protocol of a specific type is installed + +Arguments: + NONE + +Returns: + NONE + +--*/ +; + +EFI_STATUS +CoreAllEfiServicesAvailable ( + VOID + ) +/*++ + +Routine Description: + Return TRUE if all AP services are availible. + +Arguments: + NONE + +Returns: + EFI_SUCCESS - All AP services are available + EFI_NOT_FOUND - At least one AP service is not available + +--*/ +; + +VOID +CalculateEfiHdrCrc ( + IN OUT EFI_TABLE_HEADER *Hdr + ) +/*++ + +Routine Description: + + Calcualte the 32-bit CRC in a EFI table using the service provided by the + gRuntime service. + +Arguments: + + Hdr - Pointer to an EFI standard header + +Returns: + + None + +--*/ +; + +VOID +EFIAPI +CoreTimerTick ( + IN UINT64 Duration + ) +/*++ + +Routine Description: + + Called by the platform code to process a tick. + +Arguments: + + Duration - The number of 100ns elasped since the last call to TimerTick + +Returns: + + None + +--*/ +; + +VOID +CoreInitializeDispatcher ( + VOID + ) +/*++ + +Routine Description: + + Initialize the dispatcher. Initialize the notification function that runs when + a FV protocol is added to the system. + +Arguments: + + NONE + +Returns: + + NONE + +--*/ +; + +BOOLEAN +CoreIsSchedulable ( + IN EFI_CORE_DRIVER_ENTRY *DriverEntry + ) +/*++ + +Routine Description: + + This is the POSTFIX version of the dependency evaluator. This code does + not need to handle Before or After, as it is not valid to call this + routine in this case. The SOR is just ignored and is a nop in the grammer. + + POSTFIX means all the math is done on top of the stack. + +Arguments: + + DriverEntry - DriverEntry element to update + +Returns: + + TRUE - If driver is ready to run. + + FALSE - If driver is not ready to run or some fatal error was found. + +--*/ +; + +EFI_STATUS +CorePreProcessDepex ( + IN EFI_CORE_DRIVER_ENTRY *DriverEntry + ) +/*++ + +Routine Description: + + Preprocess dependency expression and update DriverEntry to reflect the + state of Before, After, and SOR dependencies. If DriverEntry->Before + or DriverEntry->After is set it will never be cleared. If SOR is set + it will be cleared by CoreSchedule(), and then the driver can be + dispatched. + +Arguments: + + DriverEntry - DriverEntry element to update + +Returns: + + EFI_SUCCESS - It always works. + +--*/ +; + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreExitBootServices ( + IN EFI_HANDLE ImageHandle, + IN UINTN MapKey + ) +/*++ + +Routine Description: + + EFI 1.0 API to terminate Boot Services + +Arguments: + + ImageHandle - Handle that represents the identity of the calling image + + MapKey -Key to the latest memory map. + +Returns: + + EFI_SUCCESS - Boot Services terminated + EFI_INVALID_PARAMETER - MapKey is incorrect. + +--*/ +; + +EFI_STATUS +CoreTerminateMemoryMap ( + IN UINTN MapKey + ) +/*++ + +Routine Description: + + Make sure the memory map is following all the construction rules, + it is the last time to check memory map error before exit boot services. + +Arguments: + + MapKey - Memory map key + +Returns: + + EFI_INVALID_PARAMETER - Memory map not consistent with construction rules. + + EFI_SUCCESS - Valid memory map. + +--*/ +; + +VOID +CoreNotifySignalList ( + IN EFI_GUID *EventGroup + ) +/*++ + +Routine Description: + + Signals all events on the requested list + +Arguments: + + SignalType - The list to signal + +Returns: + + None + +--*/ +; + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreInstallConfigurationTable ( + IN EFI_GUID *Guid, + IN VOID *Table + ) +/*++ + +Routine Description: + + Boot Service called to add, modify, or remove a system configuration table from + the EFI System Table. + +Arguments: + + Guid: Pointer to the GUID for the entry to add, update, or remove + Table: Pointer to the configuration table for the entry to add, update, or + remove, may be NULL. + +Returns: + + EFI_SUCCESS Guid, Table pair added, updated, or removed. + EFI_INVALID_PARAMETER Input GUID not valid. + EFI_NOT_FOUND Attempted to delete non-existant entry + EFI_OUT_OF_RESOURCES Not enough memory available + +--*/ +; + +EFI_BOOTSERVICE +EFI_TPL +EFIAPI +CoreRaiseTpl ( + IN EFI_TPL NewTpl + ) +/*++ + +Routine Description: + + Raise the task priority level to the new level. + High level is implemented by disabling processor interrupts. + +Arguments: + + NewTpl - New task priority level + +Returns: + + The previous task priority level + +--*/ +; + +EFI_BOOTSERVICE +VOID +EFIAPI +CoreRestoreTpl ( + IN EFI_TPL NewTpl + ) +/*++ + +Routine Description: + + Lowers the task priority to the previous value. If the new + priority unmasks events at a higher priority, they are dispatched. + +Arguments: + + NewTpl - New, lower, task priority + +Returns: + + None + +--*/ +; + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreStall ( + IN UINTN Microseconds + ) +/*++ + +Routine Description: + + Introduces a fine-grained stall. + +Arguments: + + Microseconds The number of microseconds to stall execution + +Returns: + + EFI_SUCCESS - Execution was stalled for at least the requested amount + of microseconds. + + EFI_NOT_AVAILABLE_YET - gMetronome is not available yet + +--*/ +; + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreSetWatchdogTimer ( + IN UINTN Timeout, + IN UINT64 WatchdogCode, + IN UINTN DataSize, + IN CHAR16 *WatchdogData OPTIONAL + ) +/*++ + +Routine Description: + + Sets the system's watchdog timer. + +Arguments: + + Timeout The number of seconds. Zero disables the timer. + + ///////following three parameters are left for platform specific using + + WatchdogCode The numberic code to log. 0x0 to 0xffff are firmware + DataSize Size of the optional data + WatchdogData Optional Null terminated unicode string followed by binary + data. + +Returns: + + EFI_SUCCESS Timeout has been set + EFI_NOT_AVAILABLE_YET WatchdogTimer is not available yet + EFI_UNSUPPORTED System does not have a timer (currently not used) + EFI_DEVICE_ERROR Could not complete due to hardware error + +--*/ +; + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreInstallProtocolInterface ( + IN OUT EFI_HANDLE *UserHandle, + IN EFI_GUID *Protocol, + IN EFI_INTERFACE_TYPE InterfaceType, + IN VOID *Interface + ) +/*++ + +Routine Description: + + Wrapper function to CoreInstallProtocolInterfaceNotify. This is the public API which + Calls the private one which contains a BOOLEAN parameter for notifications + +Arguments: + + UserHandle - The handle to install the protocol handler on, + or NULL if a new handle is to be allocated + + Protocol - The protocol to add to the handle + + InterfaceType - Indicates whether Interface is supplied in native form. + + Interface - The interface for the protocol being added + +Returns: + + Status code + +--*/ +; + +EFI_STATUS +CoreInstallProtocolInterfaceNotify ( + IN OUT EFI_HANDLE *UserHandle, + IN EFI_GUID *Protocol, + IN EFI_INTERFACE_TYPE InterfaceType, + IN VOID *Interface, + IN BOOLEAN Notify + ) +/*++ + +Routine Description: + + Installs a protocol interface into the boot services environment. + +Arguments: + + UserHandle - The handle to install the protocol handler on, + or NULL if a new handle is to be allocated + + Protocol - The protocol to add to the handle + + InterfaceType - Indicates whether Interface is supplied in native form. + + Interface - The interface for the protocol being added + + Notify - Whether to notify the notification list for this protocol + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_OUT_OF_RESOURCES - No enough buffer to allocate + + EFI_SUCCESS - Protocol interface successfully installed + +--*/ +; + +EFI_BOOTSERVICE11 +EFI_STATUS +EFIAPI +CoreInstallMultipleProtocolInterfaces ( + IN OUT EFI_HANDLE *Handle, + ... + ) +/*++ + +Routine Description: + + Installs a list of protocol interface into the boot services environment. + This function calls InstallProtocolInterface() in a loop. If any error + occures all the protocols added by this function are removed. This is + basically a lib function to save space. + +Arguments: + + Handle - The handle to install the protocol handlers on, + or NULL if a new handle is to be allocated + ... - EFI_GUID followed by protocol instance. A NULL terminates the + list. The pairs are the arguments to InstallProtocolInterface(). + All the protocols are added to Handle. + +Returns: + + EFI_INVALID_PARAMETER - Handle is NULL. + + EFI_SUCCESS - Protocol interfaces successfully installed. + +--*/ +; + +EFI_BOOTSERVICE11 +EFI_STATUS +EFIAPI +CoreUninstallMultipleProtocolInterfaces ( + IN EFI_HANDLE Handle, + ... + ) +/*++ + +Routine Description: + + Uninstalls a list of protocol interface in the boot services environment. + This function calls UnisatllProtocolInterface() in a loop. This is + basically a lib function to save space. + +Arguments: + + Handle - The handle to uninstall the protocol + + ... - EFI_GUID followed by protocol instance. A NULL terminates the + list. The pairs are the arguments to UninstallProtocolInterface(). + All the protocols are added to Handle. + +Returns: + + Status code + +--*/ +; + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreReinstallProtocolInterface ( + IN EFI_HANDLE UserHandle, + IN EFI_GUID *Protocol, + IN VOID *OldInterface, + IN VOID *NewInterface + ) +/*++ + +Routine Description: + + Reinstall a protocol interface on a device handle. The OldInterface for Protocol is replaced by the NewInterface. + +Arguments: + + UserHandle - Handle on which the interface is to be reinstalled + Protocol - The numeric ID of the interface + OldInterface - A pointer to the old interface + NewInterface - A pointer to the new interface + + +Returns: + + Status code. + + On EFI_SUCCESS The protocol interface was installed + On EFI_NOT_FOUND The OldInterface on the handle was not found + On EFI_INVALID_PARAMETER One of the parameters has an invalid value + +--*/ +; + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreUninstallProtocolInterface ( + IN EFI_HANDLE UserHandle, + IN EFI_GUID *Protocol, + IN VOID *Interface + ) +/*++ + +Routine Description: + + Uninstalls all instances of a protocol:interfacer from a handle. + If the last protocol interface is remove from the handle, the + handle is freed. + +Arguments: + + UserHandle - The handle to remove the protocol handler from + + Protocol - The protocol, of protocol:interface, to remove + + Interface - The interface, of protocol:interface, to remove + +Returns: + + EFI_INVALID_PARAMETER - Protocol is NULL. + + EFI_SUCCESS - Protocol interface successfully uninstalled. + +--*/ +; + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreHandleProtocol ( + IN EFI_HANDLE UserHandle, + IN EFI_GUID *Protocol, + OUT VOID **Interface + ) +/*++ + +Routine Description: + + Queries a handle to determine if it supports a specified protocol. + +Arguments: + + UserHandle - The handle being queried. + + Protocol - The published unique identifier of the protocol. + + Interface - Supplies the address where a pointer to the corresponding Protocol + Interface is returned. + +Returns: + + The requested protocol interface for the handle + +--*/ +; + +EFI_BOOTSERVICE11 +EFI_STATUS +EFIAPI +CoreOpenProtocol ( + IN EFI_HANDLE UserHandle, + IN EFI_GUID *Protocol, + OUT VOID **Interface OPTIONAL, + IN EFI_HANDLE ImageHandle, + IN EFI_HANDLE ControllerHandle, + IN UINT32 Attributes + ) +/*++ + +Routine Description: + + Locates the installed protocol handler for the handle, and + invokes it to obtain the protocol interface. Usage information + is registered in the protocol data base. + +Arguments: + + UserHandle - The handle to obtain the protocol interface on + + Protocol - The ID of the protocol + + Interface - The location to return the protocol interface + + ImageHandle - The handle of the Image that is opening the protocol interface + specified by Protocol and Interface. + + ControllerHandle - The controller handle that is requiring this interface. + + Attributes - The open mode of the protocol interface specified by Handle + and Protocol. + +Returns: + + EFI_INVALID_PARAMETER - Protocol is NULL. + + EFI_SUCCESS - Get the protocol interface. + +--*/ +; + +EFI_BOOTSERVICE11 +EFI_STATUS +EFIAPI +CoreOpenProtocolInformation ( + IN EFI_HANDLE UserHandle, + IN EFI_GUID *Protocol, + OUT EFI_OPEN_PROTOCOL_INFORMATION_ENTRY **EntryBuffer, + OUT UINTN *EntryCount + ) +/*++ + +Routine Description: + + Return information about Opened protocols in the system + +Arguments: + + UserHandle - The handle to close the protocol interface on + + Protocol - The ID of the protocol + + EntryBuffer - A pointer to a buffer of open protocol information in the form of + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY structures. + + EntryCount - Number of EntryBuffer entries + +Returns: + + +--*/ +; + +EFI_BOOTSERVICE11 +EFI_STATUS +EFIAPI +CoreCloseProtocol ( + IN EFI_HANDLE UserHandle, + IN EFI_GUID *Protocol, + IN EFI_HANDLE ImageHandle, + IN EFI_HANDLE ControllerHandle + ) +/*++ + +Routine Description: + + Close Protocol + +Arguments: + + UserHandle - The handle to close the protocol interface on + + Protocol - The ID of the protocol + + ImageHandle - The user of the protocol to close + + ControllerHandle - The user of the protocol to close + +Returns: + + EFI_INVALID_PARAMETER - Protocol is NULL. + +--*/ +; + +EFI_BOOTSERVICE11 +EFI_STATUS +EFIAPI +CoreProtocolsPerHandle ( + IN EFI_HANDLE UserHandle, + OUT EFI_GUID ***ProtocolBuffer, + OUT UINTN *ProtocolBufferCount + ) +/*++ + +Routine Description: + + Retrieves the list of protocol interface GUIDs that are installed on a handle in a buffer allocated + from pool. + +Arguments: + + UserHandle - The handle from which to retrieve the list of protocol interface + GUIDs. + + ProtocolBuffer - A pointer to the list of protocol interface GUID pointers that are + installed on Handle. + + ProtocolBufferCount - A pointer to the number of GUID pointers present in + ProtocolBuffer. + +Returns: + EFI_SUCCESS - The list of protocol interface GUIDs installed on Handle was returned in + ProtocolBuffer. The number of protocol interface GUIDs was + returned in ProtocolBufferCount. + EFI_INVALID_PARAMETER - Handle is NULL. + EFI_INVALID_PARAMETER - Handle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ProtocolBuffer is NULL. + EFI_INVALID_PARAMETER - ProtocolBufferCount is NULL. + EFI_OUT_OF_RESOURCES - There is not enough pool memory to store the results. + +--*/ +; + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreRegisterProtocolNotify ( + IN EFI_GUID *Protocol, + IN EFI_EVENT Event, + OUT VOID **Registration + ) +/*++ + +Routine Description: + + Add a new protocol notification record for the request protocol. + +Arguments: + + Protocol - The requested protocol to add the notify registration + + Event - The event to signal + + Registration - Returns the registration record + + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_SUCCESS - Successfully returned the registration record that has been added + +--*/ +; + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreLocateHandle ( + IN EFI_LOCATE_SEARCH_TYPE SearchType, + IN EFI_GUID *Protocol OPTIONAL, + IN VOID *SearchKey OPTIONAL, + IN OUT UINTN *BufferSize, + OUT EFI_HANDLE *Buffer + ) +/*++ + +Routine Description: + + Locates the requested handle(s) and returns them in Buffer. + +Arguments: + + SearchType - The type of search to perform to locate the handles + + Protocol - The protocol to search for + + SearchKey - Dependant on SearchType + + BufferSize - On input the size of Buffer. On output the + size of data returned. + + Buffer - The buffer to return the results in + + +Returns: + + EFI_BUFFER_TOO_SMALL - Buffer too small, required buffer size is returned in BufferSize. + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_SUCCESS - Successfully found the requested handle(s) and returns them in Buffer. + +--*/ +; + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreLocateDevicePath ( + IN EFI_GUID *Protocol, + IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath, + OUT EFI_HANDLE *Device + ) +/*++ + +Routine Description: + + Locates the handle to a device on the device path that supports the specified protocol. + +Arguments: + + Protocol - The protocol to search for. + FilePath - On input, a pointer to a pointer to the device path. On output, the device + path pointer is modified to point to the remaining part of the devicepath. + Device - A pointer to the returned device handle. + +Returns: + + EFI_SUCCESS - The resulting handle was returned. + EFI_NOT_FOUND - No handles matched the search. + EFI_INVALID_PARAMETER - One of the parameters has an invalid value. + +--*/ +; + +EFI_BOOTSERVICE11 +EFI_STATUS +EFIAPI +CoreLocateHandleBuffer ( + IN EFI_LOCATE_SEARCH_TYPE SearchType, + IN EFI_GUID *Protocol OPTIONAL, + IN VOID *SearchKey OPTIONAL, + IN OUT UINTN *NumberHandles, + OUT EFI_HANDLE **Buffer + ) +/*++ + +Routine Description: + + Function returns an array of handles that support the requested protocol + in a buffer allocated from pool. This is a version of CoreLocateHandle() + that allocates a buffer for the caller. + +Arguments: + + SearchType - Specifies which handle(s) are to be returned. + Protocol - Provides the protocol to search by. + This parameter is only valid for SearchType ByProtocol. + SearchKey - Supplies the search key depending on the SearchType. + NumberHandles - The number of handles returned in Buffer. + Buffer - A pointer to the buffer to return the requested array of + handles that support Protocol. + +Returns: + + EFI_SUCCESS - The result array of handles was returned. + EFI_NOT_FOUND - No handles match the search. + EFI_OUT_OF_RESOURCES - There is not enough pool memory to store the matching results. + EFI_INVALID_PARAMETER - Invalid parameter + +--*/ +; + +EFI_BOOTSERVICE11 +EFI_STATUS +EFIAPI +CoreLocateProtocol ( + IN EFI_GUID *Protocol, + IN VOID *Registration OPTIONAL, + OUT VOID **Interface + ) +/*++ + +Routine Description: + + Return the first Protocol Interface that matches the Protocol GUID. If + Registration is pasased in return a Protocol Instance that was just add + to the system. If Retistration is NULL return the first Protocol Interface + you find. + +Arguments: + + Protocol - The protocol to search for + + Registration - Optional Registration Key returned from RegisterProtocolNotify() + + Interface - Return the Protocol interface (instance). + +Returns: + + EFI_SUCCESS - If a valid Interface is returned + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_NOT_FOUND - Protocol interface not found + +--*/ +; + +UINT64 +CoreGetHandleDatabaseKey ( + VOID + ) +/*++ + +Routine Description: + + return handle database key. + +Arguments: + + None + +Returns: + + Handle database key. + +--*/ +; + +VOID +CoreConnectHandlesByKey ( + UINT64 Key + ) +/*++ + +Routine Description: + + Go connect any handles that were created or modified while a image executed. + +Arguments: + + Key - The Key to show that the handle has been created/modified + +Returns: + + None +--*/ +; + +EFI_BOOTSERVICE11 +EFI_STATUS +EFIAPI +CoreConnectController ( + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE *DriverImageHandle OPTIONAL, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL, + IN BOOLEAN Recursive + ) +/*++ + +Routine Description: + + Connects one or more drivers to a controller. + +Arguments: + + ControllerHandle - Handle of the controller to be connected. + + DriverImageHandle - DriverImageHandle A pointer to an ordered list of driver image handles. + + RemainingDevicePath - RemainingDevicePath A pointer to the device path that specifies a child of the + controller specified by ControllerHandle. + + Recursive - - Whether the function would be called recursively or not. + +Returns: + + Status code. + +--*/ +; + +EFI_BOOTSERVICE11 +EFI_STATUS +EFIAPI +CoreDisconnectController ( + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE DriverImageHandle OPTIONAL, + IN EFI_HANDLE ChildHandle OPTIONAL + ) +/*++ + +Routine Description: + + Disonnects a controller from a driver + +Arguments: + + ControllerHandle - ControllerHandle The handle of the controller from which driver(s) + are to be disconnected. + DriverImageHandle - DriverImageHandle The driver to disconnect from ControllerHandle. + ChildHandle - ChildHandle The handle of the child to destroy. + +Returns: + + EFI_SUCCESS - One or more drivers were disconnected from the controller. + EFI_SUCCESS - On entry, no drivers are managing ControllerHandle. + EFI_SUCCESS - DriverImageHandle is not NULL, and on entry DriverImageHandle is not managing ControllerHandle. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - DriverImageHandle is not NULL, and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL, and it is not a valid EFI_HANDLE. + EFI_OUT_OF_RESOURCES - There are not enough resources available to disconnect any drivers from ControllerHandle. + EFI_DEVICE_ERROR - The controller could not be disconnected because of a device error. + +--*/ +; + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreAllocatePages ( + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN NumberOfPages, + IN OUT EFI_PHYSICAL_ADDRESS *Memory + ) +/*++ + +Routine Description: + + Allocates pages from the memory map. + +Arguments: + + Type - The type of allocation to perform + + MemoryType - The type of memory to turn the allocated pages into + + NumberOfPages - The number of pages to allocate + + Memory - A pointer to receive the base allocated memory address + +Returns: + + Status. On success, Memory is filled in with the base address allocated + + EFI_INVALID_PARAMETER - Parameters violate checking rules defined in spec. + + EFI_NOT_FOUND - Could not allocate pages match the requirement. + + EFI_OUT_OF_RESOURCES - No enough pages to allocate. + + EFI_SUCCESS - Pages successfully allocated. + +--*/ +; + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreFreePages ( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN NumberOfPages + ) +/*++ + +Routine Description: + + Frees previous allocated pages. + +Arguments: + + Memory - Base address of memory being freed + + NumberOfPages - The number of pages to free + +Returns: + + EFI_NOT_FOUND - Could not find the entry that covers the range + + EFI_INVALID_PARAMETER - Address not aligned + + EFI_SUCCESS -Pages successfully freed. + +--*/ +; + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreGetMemoryMap ( + IN OUT UINTN *MemoryMapSize, + IN OUT EFI_MEMORY_DESCRIPTOR *Desc, + OUT UINTN *MapKey, + OUT UINTN *DescriptorSize, + OUT UINT32 *DescriptorVersion + ) +/*++ + +Routine Description: + + Returns the current memory map. + +Arguments: + + MemoryMapSize - On input the buffer size of MemoryMap allocated by caller + On output the required buffer size to contain the memory map + + Desc - The buffer to return the current memory map + + MapKey - The address to return the current map key + + DescriptorSize - The size in bytes for an individual EFI_MEMORY_DESCRIPTOR + + DescriptorVersion - The version number associated with the EFI_MEMORY_DESCRIPTOR + +Returns: + + EFI_SUCCESS The current memory map was returned successfully + + EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small + + EFI_INVALID_PARAMETER One of the parameters has an invalid value + +--*/ +; + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreAllocatePool ( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN Size, + OUT VOID **Buffer + ) +/*++ + +Routine Description: + + Allocate pool of a particular type. + +Arguments: + + PoolType - Type of pool to allocate + + Size - The amount of pool to allocate + + Buffer - The address to return a pointer to the allocated pool + +Returns: + + EFI_INVALID_PARAMETER - PoolType not valid + + EFI_OUT_OF_RESOURCES - Size exceeds max pool size or allocation failed. + + EFI_SUCCESS - Pool successfully allocated. + +--*/ +; + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreFreePool ( + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Frees pool. + +Arguments: + + Buffer - The allocated pool entry to free + +Returns: + + EFI_INVALID_PARAMETER - Buffer is not a valid value. + + EFI_SUCCESS - Pool successfully freed. + +--*/ +; + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreLoadImage ( + IN BOOLEAN BootPolicy, + IN EFI_HANDLE ParentImageHandle, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + IN VOID *SourceBuffer OPTIONAL, + IN UINTN SourceSize, + OUT EFI_HANDLE *ImageHandle + ) +/*++ + +Routine Description: + + Loads an EFI image into memory and returns a handle to the image. + +Arguments: + + BootPolicy - If TRUE, indicates that the request originates from the boot manager, + and that the boot manager is attempting to load FilePath as a boot selection. + ParentImageHandle - The caller's image handle. + FilePath - The specific file path from which the image is loaded. + SourceBuffer - If not NULL, a pointer to the memory location containing a copy of + the image to be loaded. + SourceSize - The size in bytes of SourceBuffer. + ImageHandle - Pointer to the returned image handle that is created when the image + is successfully loaded. + +Returns: + + EFI_SUCCESS - The image was loaded into memory. + EFI_NOT_FOUND - The FilePath was not found. + EFI_INVALID_PARAMETER - One of the parameters has an invalid value. + EFI_UNSUPPORTED - The image type is not supported, or the device path cannot be + parsed to locate the proper protocol for loading the file. + EFI_OUT_OF_RESOURCES - Image was not loaded due to insufficient resources. +--*/ +; + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreUnloadImage ( + IN EFI_HANDLE ImageHandle + ) +/*++ + +Routine Description: + + Unload the specified image. + +Arguments: + + ImageHandle - The specified image handle. + +Returns: + + EFI_INVALID_PARAMETER - Image handle is NULL. + + EFI_UNSUPPORTED - Attempt to unload an unsupported image. + + EFI_SUCCESS - Image successfully unloaded. + +--*/ +; + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreStartImage ( + IN EFI_HANDLE ImageHandle, + OUT UINTN *ExitDataSize, + OUT CHAR16 **ExitData OPTIONAL + ) +/*++ + +Routine Description: + + Transfer control to a loaded image's entry point. + +Arguments: + + ImageHandle - Handle of image to be started. + + ExitDataSize - Pointer of the size to ExitData + + ExitData - Pointer to a pointer to a data buffer that includes a Null-terminated + Unicode string, optionally followed by additional binary data. The string + is a description that the caller may use to further indicate the reason for + the image¡¯s exit. + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_OUT_OF_RESOURCES - No enough buffer to allocate + + EFI_SUCCESS - Successfully transfer control to the image's entry point. + +--*/ +; + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreExit ( + IN EFI_HANDLE ImageHandle, + IN EFI_STATUS Status, + IN UINTN ExitDataSize, + IN CHAR16 *ExitData OPTIONAL + ) +/*++ + +Routine Description: + + Terminates the currently loaded EFI image and returns control to boot services. + +Arguments: + + ImageHandle - Handle that identifies the image. This parameter is passed to the image + on entry. + Status - The image¡¯s exit code. + ExitDataSize - The size, in bytes, of ExitData. Ignored if ExitStatus is + EFI_SUCCESS. + ExitData - Pointer to a data buffer that includes a Null-terminated Unicode string, + optionally followed by additional binary data. The string is a + description that the caller may use to further indicate the reason for + the image¡¯s exit. + +Returns: + + EFI_INVALID_PARAMETER - Image handle is NULL or it is not current image. + + EFI_SUCCESS - Successfully terminates the currently loaded EFI image. + + EFI_ACCESS_DENIED - Should never reach there. + +--*/ +; + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreCreateEvent ( + IN UINT32 Type, + IN EFI_TPL NotifyTpl, + IN EFI_EVENT_NOTIFY NotifyFunction, + IN VOID *NotifyContext, + OUT EFI_EVENT *pEvent + ) +/*++ + +Routine Description: + + Creates a general-purpose event structure + +Arguments: + + Type - The type of event to create and its mode and attributes + NotifyTpl - The task priority level of event notifications + NotifyFunction - Pointer to the event’s notification function + NotifyContext - Pointer to the notification function’s context; corresponds to + parameter "Context" in the notification function + pEvent - Pointer to the newly created event if the call succeeds; undefined otherwise + +Returns: + + EFI_SUCCESS - The event structure was created + EFI_INVALID_PARAMETER - One of the parameters has an invalid value + EFI_OUT_OF_RESOURCES - The event could not be allocated + +--*/ +; + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreCreateEventEx ( + IN UINT32 Type, + IN EFI_TPL NotifyTpl, + IN EFI_EVENT_NOTIFY NotifyFunction, + IN VOID *NotifyContext, + IN CONST EFI_GUID *EventGroup, OPTIONAL + OUT EFI_EVENT *Event + ) +/*++ + +Routine Description: + Creates a general-purpose event structure + +Arguments: + Type - The type of event to create and its mode and attributes + NotifyTpl - The task priority level of event notifications + NotifyFunction - Pointer to the events notification function + NotifyContext - Pointer to the notification functions context; corresponds to + parameter "Context" in the notification function + EventGrout - GUID for EventGroup if NULL act the same as gBS->CreateEvent(). + Event - Pointer to the newly created event if the call succeeds; undefined otherwise + +Returns: + EFI_SUCCESS - The event structure was created + EFI_INVALID_PARAMETER - One of the parameters has an invalid value + EFI_OUT_OF_RESOURCES - The event could not be allocated + +--*/ +; + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreSetTimer ( + IN EFI_EVENT Event, + IN EFI_TIMER_DELAY Type, + IN UINT64 TriggerTime + ) +/*++ + +Routine Description: + + Sets the type of timer and the trigger time for a timer event. + +Arguments: + + UserEvent - The timer event that is to be signaled at the specified time + Type - The type of time that is specified in TriggerTime + TriggerTime - The number of 100ns units until the timer expires + +Returns: + + EFI_SUCCESS - The event has been set to be signaled at the requested time + EFI_INVALID_PARAMETER - Event or Type is not valid + +--*/ +; + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreSignalEvent ( + IN EFI_EVENT Event + ) +/*++ + +Routine Description: + + Signals the event. Queues the event to be notified if needed + +Arguments: + + Event - The event to signal + +Returns: + + EFI_INVALID_PARAMETER - Parameters are not valid. + + EFI_SUCCESS - The event was signaled. + +--*/ +; + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreWaitForEvent ( + IN UINTN NumberOfEvents, + IN EFI_EVENT *UserEvents, + OUT UINTN *UserIndex + ) +/*++ + +Routine Description: + + Stops execution until an event is signaled. + +Arguments: + + NumberOfEvents - The number of events in the UserEvents array + UserEvents - An array of EFI_EVENT + UserIndex - Pointer to the index of the event which satisfied the wait condition + +Returns: + + EFI_SUCCESS - The event indicated by Index was signaled. + EFI_INVALID_PARAMETER - The event indicated by Index has a notification function or + Event was not a valid type + EFI_UNSUPPORTED - The current TPL is not TPL_APPLICATION + +--*/ +; + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreCloseEvent ( + IN EFI_EVENT Event + ) +/*++ + +Routine Description: + + Closes an event and frees the event structure. + +Arguments: + + UserEvent - Event to close + +Returns: + + EFI_INVALID_PARAMETER - Parameters are not valid. + + EFI_SUCCESS - The event has been closed + +--*/ +; + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreCheckEvent ( + IN EFI_EVENT Event + ) +/*++ + +Routine Description: + + Check the status of an event + +Arguments: + + UserEvent - The event to check + +Returns: + + EFI_SUCCESS - The event is in the signaled state + EFI_NOT_READY - The event is not in the signaled state + EFI_INVALID_PARAMETER - Event is of type EVT_NOTIFY_SIGNAL + +--*/ +; + +EFI_STATUS +CoreAddMemorySpace ( + IN EFI_GCD_MEMORY_TYPE GcdMemoryType, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Capabilities + ) +/*++ + +Routine Description: + + Add a segment of memory space to GCD map and add all available pages in this segment + as memory descriptors. + +Arguments: + + GcdMemoryType - Memory type of the segment. + + BaseAddress - Base address of the segment. + + Length - Length of the segment. + + Capabilities - alterable attributes of the segment. + +Returns: + + EFI_SUCCESS - Merged this segment into GCD map. + +--*/ +; + +EFI_STATUS +CoreAllocateMemorySpace ( + IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType, + IN EFI_GCD_MEMORY_TYPE GcdMemoryType, + IN UINTN Alignment, + IN UINT64 Length, + IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress, + IN EFI_HANDLE ImageHandle, + IN EFI_HANDLE DeviceHandle OPTIONAL + ) +/*++ + +Routine Description: + + Allocate memory space on GCD map. + +Arguments: + + GcdAllocateType - The type of allocate operation + + GcdMemoryType - The desired memory type + + Alignment - Align with 2^Alignment + + Length - Length to allocate + + BaseAddress - Base address to allocate + + ImageHandle - The image handle consume the allocated space. + + DeviceHandle - The device handle consume the allocated space. + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter. + + EFI_NOT_FOUND - No descriptor contains the desired space. + + EFI_SUCCESS - Memory space successfully allocated. + +--*/ +; + +EFI_STATUS +CoreFreeMemorySpace ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +/*++ + +Routine Description:Routine Description: + + Free a segment of memory space in GCD map. + +Arguments: + + BaseAddress - Base address of the segment. + + Length - Length of the segment. + +Returns: + + EFI_SUCCESS - Space successfully freed. + +--*/ +; + +EFI_STATUS +CoreRemoveMemorySpace ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +/*++ + +Routine Description:Routine Description: + + Remove a segment of memory space in GCD map. + +Arguments: + + BaseAddress - Base address of the segment. + + Length - Length of the segment. + +Returns: + + EFI_SUCCESS - Successfully a segment of memory space. + +--*/ +; + +EFI_STATUS +CoreGetMemorySpaceDescriptor ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor + ) +/*++ + +Routine Description: + + Search all entries in GCD map which contains specified segment and build it to a descriptor. + +Arguments: + + BaseAddress - Specified start address + + Descriptor - Specified length + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_SUCCESS - Successfully get memory space descriptor. + +--*/ +; + +EFI_STATUS +CoreSetMemorySpaceAttributes ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Attributes + ) +/*++ + +Routine Description: + + Set memory space with specified attributes. + +Arguments: + + BaseAddress - Specified start address + + Length - Specified length + + Attributes - Specified attributes + +Returns: + + EFI_SUCCESS - Successfully set attribute of a segment of memory space. + +--*/ +; + +EFI_STATUS +CoreGetMemorySpaceMap ( + OUT UINTN *NumberOfDescriptors, + OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR **MemorySpaceMap + ) +/*++ + +Routine Description: + + Transer all entries of GCD memory map into memory descriptors and pass to caller. + +Arguments: + + NumberOfDescriptors - Number of descriptors. + + MemorySpaceMap - Descriptor array + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_OUT_OF_RESOURCES - No enough buffer to allocate + + EFI_SUCCESS - Successfully get memory space map. + +--*/ +; + +EFI_STATUS +CoreAddIoSpace ( + IN EFI_GCD_IO_TYPE GcdIoType, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +/*++ + +Routine Description: + + Add a segment of IO space to GCD map. + +Arguments: + + GcdIoType - IO type of the segment. + + BaseAddress - Base address of the segment. + + Length - Length of the segment. + +Returns: + + EFI_SUCCESS - Merged this segment into GCD map. + +--*/ +; + +EFI_STATUS +CoreAllocateIoSpace ( + IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType, + IN EFI_GCD_IO_TYPE GcdIoType, + IN UINTN Alignment, + IN UINT64 Length, + IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress, + IN EFI_HANDLE ImageHandle, + IN EFI_HANDLE DeviceHandle OPTIONAL + ) +/*++ + +Routine Description: + + Allocate IO space on GCD map. + +Arguments: + + GcdAllocateType - The type of allocate operation + + GcdIoType - The desired IO type + + Alignment - Align with 2^Alignment + + Length - Length to allocate + + BaseAddress - Base address to allocate + + ImageHandle - The image handle consume the allocated space. + + DeviceHandle - The device handle consume the allocated space. + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter. + + EFI_NOT_FOUND - No descriptor contains the desired space. + + EFI_SUCCESS - IO space successfully allocated. + +--*/ +; + +EFI_STATUS +CoreFreeIoSpace ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +/*++ + +Routine Description:Routine Description: + + Free a segment of IO space in GCD map. + +Arguments: + + BaseAddress - Base address of the segment. + + Length - Length of the segment. + +Returns: + + EFI_SUCCESS - Space successfully freed. + +--*/ +; + +EFI_STATUS +CoreRemoveIoSpace ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +/*++ + +Routine Description:Routine Description: + + Remove a segment of IO space in GCD map. + +Arguments: + + BaseAddress - Base address of the segment. + + Length - Length of the segment. + +Returns: + + EFI_SUCCESS - Successfully removed a segment of IO space. + +--*/ +; + +EFI_STATUS +CoreGetIoSpaceDescriptor ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + OUT EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor + ) +/*++ + +Routine Description: + + Search all entries in GCD map which contains specified segment and build it to a descriptor. + +Arguments: + + BaseAddress - Specified start address + + Descriptor - Specified length + +Returns: + + EFI_INVALID_PARAMETER - Descriptor is NULL. + + EFI_SUCCESS - Successfully get the IO space descriptor. + +--*/ +; + +EFI_STATUS +CoreGetIoSpaceMap ( + OUT UINTN *NumberOfDescriptors, + OUT EFI_GCD_IO_SPACE_DESCRIPTOR **IoSpaceMap + ) +/*++ + +Routine Description: + + Transer all entries of GCD IO map into IO descriptors and pass to caller. + +Arguments: + + NumberOfDescriptors - Number of descriptors. + + IoSpaceMap - Descriptor array + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_OUT_OF_RESOURCES - No enough buffer to allocate + + EFI_SUCCESS - Successfully get IO space map. + +--*/ +; + +EFI_DXESERVICE +EFI_STATUS +EFIAPI +CoreDispatcher ( + VOID + ) +/*++ + +Routine Description: + + This is the main Dispatcher for DXE and it exits when there are no more + drivers to run. Drain the mScheduledQueue and load and start a PE + image for each driver. Search the mDiscoveredList to see if any driver can + be placed on the mScheduledQueue. If no drivers are placed on the + mScheduledQueue exit the function. On exit it is assumed the Bds() + will be called, and when the Bds() exits the Dispatcher will be called + again. + +Arguments: + + NONE + +Returns: + + EFI_ALREADY_STARTED - The DXE Dispatcher is already running + + EFI_NOT_FOUND - No DXE Drivers were dispatched + + EFI_SUCCESS - One or more DXE Drivers were dispatched + +--*/ +; +EFI_DXESERVICE +EFI_STATUS +EFIAPI +CoreSchedule ( + IN EFI_HANDLE FirmwareVolumeHandle, + IN EFI_GUID *DriverName + ) +/*++ + +Routine Description: + + Check every driver and locate a matching one. If the driver is found, the Unrequested + state flag is cleared. + +Arguments: + + FirmwareVolumeHandle - The handle of the Firmware Volume that contains the firmware + file specified by DriverName. + + DriverName - The Driver name to put in the Dependent state. + +Returns: + + EFI_SUCCESS - The DriverName was found and it's SOR bit was cleared + + EFI_NOT_FOUND - The DriverName does not exist or it's SOR bit was not set. + +--*/ +; + +EFI_DXESERVICE +EFI_STATUS +EFIAPI +CoreTrust ( + IN EFI_HANDLE FirmwareVolumeHandle, + IN EFI_GUID *DriverName + ) +/*++ + +Routine Description: + + Convert a driver from the Untrused back to the Scheduled state + +Arguments: + + FirmwareVolumeHandle - The handle of the Firmware Volume that contains the firmware + file specified by DriverName. + + DriverName - The Driver name to put in the Scheduled state + +Returns: + + EFI_SUCCESS - The file was found in the untrusted state, and it was promoted + to the trusted state. + + EFI_NOT_FOUND - The file was not found in the untrusted state. + +--*/ +; + +BOOLEAN +CoreGrowBuffer ( + IN OUT EFI_STATUS *Status, + IN OUT VOID **Buffer, + IN UINTN BufferSize + ) +/*++ + +Routine Description: + + Helper function called as part of the code needed + to allocate the proper sized buffer for various + EFI interfaces. + +Arguments: + + Status - Current status + + Buffer - Current allocated buffer, or NULL + + BufferSize - Current buffer size needed + +Returns: + + TRUE - if the buffer was reallocated and the caller + should try the API again. + + FALSE - buffer could not be allocated and the caller + should not try the API again. + +--*/ +; + +EFI_STATUS +EFIAPI +FwVolDriverInit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + This routine is the driver initialization entry point. It initializes the + libraries, and registers two notification functions. These notification + functions are responsible for building the FV stack dynamically. + +Arguments: + ImageHandle - The image handle. + SystemTable - The system table. + +Returns: + EFI_SUCCESS - Function successfully returned. + +--*/ +; + +EFI_STATUS +EFIAPI +InitializeSectionExtraction ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + Entry point of the section extraction code. Initializes an instance of the + section extraction interface and installs it on a new handle. + +Arguments: + ImageHandle EFI_HANDLE: A handle for the image that is initializing this driver + SystemTable EFI_SYSTEM_TABLE: A pointer to the EFI system table + +Returns: + EFI_SUCCESS: Driver initialized successfully + EFI_OUT_OF_RESOURCES: Could not allocate needed resources + +--*/ +; + +EFI_STATUS +CoreProcessFirmwareVolume ( + IN VOID *FvHeader, + IN UINTN Size, + OUT EFI_HANDLE *FVProtocolHandle + ) +/*++ + +Routine Description: + This DXE service routine is used to process a firmware volume. In + particular, it can be called by BDS to process a single firmware + volume found in a capsule. + +Arguments: + FvHeader - pointer to a firmware volume header + Size - the size of the buffer pointed to by FvHeader + FVProtocolHandle - the handle on which a firmware volume protocol + was produced for the firmware volume passed in. + +Returns: + EFI_OUT_OF_RESOURCES - if an FVB could not be produced due to lack of + system resources + EFI_VOLUME_CORRUPTED - if the volume was corrupted + EFI_SUCCESS - a firmware volume protocol was produced for the + firmware volume + +--*/ +; + +// +//Functions used during debug buils +// +DEBUG_CODE ( + VOID + CoreDisplayMissingArchProtocols ( + VOID + ) + /*++ + + Routine Description: + Displays Architectural protocols that were not loaded and are required for DXE core to function + Only used in Debug Builds + + Arguments: + NONE + + Returns: + NONE + + --*/; + + VOID + CoreDisplayDiscoveredNotDispatched ( + VOID + ) + /*++ + + Routine Description: + + Traverse the discovered list for any drivers that were discovered but not loaded + because the dependency experessions evaluated to false + + Arguments: + + NONE + + Returns: + + NONE + + --*/; +) +#endif diff --git a/EDK/Foundation/Core/Dxe/Include/Library.h b/EDK/Foundation/Core/Dxe/Include/Library.h new file mode 100644 index 0000000..9cd4da2 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/Include/Library.h @@ -0,0 +1,531 @@ +/*++ + +Copyright (c) 2004 - 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Library.h + +Abstract: + +Revision History + +--*/ + +#ifndef _DXE_LIBRARY_H_ +#define _DXE_LIBRARY_H_ + +typedef struct { + EFI_TPL Tpl; + EFI_TPL OwnerTpl; + UINTN Lock; +} EFI_LOCK; + + +// +// Macro to initialize the state of a lock when a lock variable is declared +// +#define EFI_INITIALIZE_LOCK_VARIABLE(Tpl) {Tpl,0,0} + +VOID +CoreReportProgressCode ( + IN EFI_STATUS_CODE_VALUE Value + ) +/*++ + +Routine Description: + + Report status code of type EFI_PROGRESS_CODE by caller ID gEfiDxeServicesTableGuid. + +Arguments: + + Value - Describes the class/subclass/operation of the hardware or software entity + that the Status Code relates to. + +Returns: + + None + +--*/ +; + +VOID +CoreReportProgressCodeSpecific ( + IN EFI_STATUS_CODE_VALUE Value, + IN EFI_HANDLE Handle + ) +/*++ + +Routine Description: + + Report status code of type EFI_PROGRESS_CODE by caller ID gEfiDxeServicesTableGuid, + with a handle as additional information. + +Arguments: + + Value - Describes the class/subclass/operation of the hardware or software entity + that the Status Code relates to. + + Handle - Additional information. + +Returns: + + None + +--*/ +; + +VOID +CoreAcquireLock ( + IN EFI_LOCK *Lock + ) +/*++ + +Routine Description: + + Raising to the task priority level of the mutual exclusion + lock, and then acquires ownership of the lock. + +Arguments: + + Lock - The lock to acquire + +Returns: + + Lock owned + +--*/ +; + +EFI_STATUS +CoreAcquireLockOrFail ( + IN EFI_LOCK *Lock + ) +/*++ + +Routine Description: + + Initialize a basic mutual exclusion lock. Each lock + provides mutual exclusion access at it's task priority + level. Since there is no-premption (at any TPL) or + multiprocessor support, acquiring the lock only consists + of raising to the locks TPL. + +Arguments: + + Lock - The EFI_LOCK structure to initialize + +Returns: + + EFI_SUCCESS - Lock Owned. + EFI_ACCESS_DENIED - Reentrant Lock Acquisition, Lock not Owned. + +--*/ +; + +VOID +CoreReleaseLock ( + IN EFI_LOCK *Lock + ) +/*++ + +Routine Description: + + Releases ownership of the mutual exclusion lock, and + restores the previous task priority level. + +Arguments: + + Lock - The lock to release + +Returns: + + Lock unowned + +--*/ +; + +// +// Device Path functions +// + +UINTN +CoreDevicePathSize ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +/*++ + +Routine Description: + + Calculate the size of a whole device path. + +Arguments: + + DevicePath - The pointer to the device path data. + +Returns: + + Size of device path data structure.. + +--*/ +; + +BOOLEAN +CoreIsDevicePathMultiInstance ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +/*++ + +Routine Description: + Return TRUE is this is a multi instance device path. + +Arguments: + DevicePath - A pointer to a device path data structure. + + +Returns: + TRUE - If DevicePath is multi instance. FALSE - If DevicePath is not multi + instance. + +--*/ +; + + +EFI_DEVICE_PATH_PROTOCOL * +CoreDuplicateDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +/*++ + +Routine Description: + Duplicate a new device path data structure from the old one. + +Arguments: + DevicePath - A pointer to a device path data structure. + +Returns: + A pointer to the new allocated device path data. + Caller must free the memory used by DevicePath if it is no longer needed. + +--*/ +; + +EFI_DEVICE_PATH_PROTOCOL * +CoreAppendDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *Src1, + IN EFI_DEVICE_PATH_PROTOCOL *Node + ) +/*++ + +Routine Description: + Function is used to append a Src1 and Src2 together. + +Arguments: + Src1 - A pointer to a device path data structure. + + Node - A pointer to a device path data structure. + +Returns: + + A pointer to the new device path is returned. + NULL is returned if space for the new device path could not be allocated from pool. + It is up to the caller to free the memory used by Src1 and Src2 if they are no longer needed. + +--*/ +; + +VOID * +CoreAllocateBootServicesPool ( + IN UINTN AllocationSize + ) +/*++ + +Routine Description: + + Allocate pool of type EfiBootServicesData, the size is specified with AllocationSize. + +Arguments: + + AllocationSize - Size to allocate. + +Returns: + + Pointer of the allocated pool. + +--*/ +; + +VOID * +CoreAllocateZeroBootServicesPool ( + IN UINTN AllocationSize + ) +/*++ + +Routine Description: + + Allocate pool of type EfiBootServicesData and zero it, the size is specified with AllocationSize. + +Arguments: + + AllocationSize - Size to allocate. + +Returns: + + Pointer of the allocated pool. + +--*/ +; + +EFI_STATUS +CoreGetConfigTable ( + IN EFI_GUID *Guid, + IN OUT VOID **Table + ) +/*++ + +Routine Description: + + Find a config table by name in system table's ConfigurationTable. + +Arguments: + + Guid - The table name to look for + + Table - Pointer of the config table + +Returns: + + EFI_NOT_FOUND - Could not find the table in system table's ConfigurationTable. + + EFI_SUCCESS - Table successfully found. + +--*/ +; + +VOID * +CoreAllocateRuntimeCopyPool ( + IN UINTN AllocationSize, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Allocate pool of specified size with EfiRuntimeServicesData type, and copy specified buffer to this pool. + +Arguments: + + AllocationSize - Size to allocate. + + Buffer - Specified buffer that will be copy to the allocated pool + +Returns: + + Pointer of the allocated pool. + +--*/ +; + +VOID * +CoreAllocateRuntimePool ( + IN UINTN AllocationSize + ) +/*++ + +Routine Description: + + Allocate pool of type EfiRuntimeServicesData, the size is specified with AllocationSize. + +Arguments: + + AllocationSize - Size to allocate. + +Returns: + + Pointer of the allocated pool. + +--*/ +; + +VOID * +CoreAllocateCopyPool ( + IN UINTN AllocationSize, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Allocate pool of specified size with EfiBootServicesData type, and copy specified buffer to this pool. + +Arguments: + + AllocationSize - Size to allocate. + + Buffer - Specified buffer that will be copy to the allocated pool + +Returns: + + Pointer of the allocated pool. + +--*/ +; + +VOID +EfiDebugAssert ( + IN CHAR8 *FileName, + IN INTN LineNumber, + IN CHAR8 *Description + ) +/*++ + +Routine Description: + + Worker function for ASSERT(). If Error Logging hub is loaded, log DEBUG + information; If not, do BREAKPOINT(). + +Arguments: + + FileName - File name of failing routine. + + LineNumber - Line number of failing ASSERT(). + + Description - Descritption, usally the assertion string. + +Returns: + + None + +--*/ +; + +VOID +EfiDebugPrint ( + IN UINTN ErrorLevel, + IN CHAR8 *Format, + ... + ) +/*++ + +Routine Description: + + Wrapper for EfiDebugVPrint () + +Arguments: + + ErrorLevel - If error level is set do the debug print. + + Format - String to use for the print, followed by Print arguments. + + ... - Print arguments. + +Returns: + + None + +--*/ +; + +EFI_EVENT +CoreCreateProtocolNotifyEvent ( + IN EFI_GUID *ProtocolGuid, + IN EFI_TPL NotifyTpl, + IN EFI_EVENT_NOTIFY NotifyFunction, + IN VOID *NotifyContext, + OUT VOID **Registration, + IN BOOLEAN SignalFlag + ) +/*++ + +Routine Description: + + Create a protocol notification event and return it. + +Arguments: + + ProtocolGuid - Protocol to register notification event on. + + NotifyTpl - Maximum TPL to signal the NotifyFunction. + + NotifyFuncition - EFI notification routine. + + NotifyContext - Context passed into Event when it is created. + + Registration - Registration key returned from RegisterProtocolNotify(). + + SignalFlag - Boolean value to decide whether kick the event after register or not. + +Returns: + + The EFI_EVENT that has been registered to be signaled when a ProtocolGuid + is added to the system. + +--*/ +; + +VOID +EFIAPI +CoreInitializeFwVolDevicepathNode ( + IN MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvDevicePathNode, + IN EFI_GUID *NameGuid + ) +/*++ + +Routine Description: + + Initialize a Firmware Volume (FV) Media Device Path node. + + Tiano extended the EFI 1.10 device path nodes. Tiano does not own this enum + so as we move to UEFI 2.0 support we must use a mechanism that conforms with + the UEFI 2.0 specification to define the FV device path. An UEFI GUIDed + device path is defined for PIWG extensions of device path. If the code + is compiled to conform with the UEFI 2.0 specification use the new device path + else use the old form for backwards compatability. + +Arguments: + + FvDevicePathNode - Pointer to a FV device path node to initialize + NameGuid - FV file name to use in FvDevicePathNode + +--*/ +; + +EFI_GUID * +EFIAPI +CoreGetNameGuidFromFwVolDevicePathNode ( + IN MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvDevicePathNode + ) +/*++ + +Routine Description: + + Check to see if the Firmware Volume (FV) Media Device Path is valid. + + Tiano extended the EFI 1.10 device path nodes. Tiano does not own this enum + so as we move to UEFI 2.0 support we must use a mechanism that conforms with + the UEFI 2.0 specification to define the FV device path. An UEFI GUIDed + device path is defined for PIWG extensions of device path. If the code + is compiled to conform with the UEFI 2.0 specification use the new device path + else use the old form for backwards compatability. The return value to this + function points to a location in FvDevicePathNode and it does not allocate + new memory for the GUID pointer that is returned. + +Arguments: + + FvDevicePathNode Pointer to FV device path to check + +Returns: + + NULL - FvDevicePathNode is not valid. + Other - FvDevicePathNode is valid and pointer to NameGuid was returned. + +--*/ +; +#endif diff --git a/EDK/Foundation/Core/Dxe/Ipf/Processor.h b/EDK/Foundation/Core/Dxe/Ipf/Processor.h new file mode 100644 index 0000000..8e49d37 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/Ipf/Processor.h @@ -0,0 +1,27 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + Processor.h + +Abstract: + This file contains the Ipf processor specific definitions + +--*/ + +#ifndef _PROCESSOR_H_ +#define _PROCESSOR_H_ + +#define EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT (EFI_PAGE_SIZE * 2) + +#define DEFAULT_PAGE_ALLOCATION (EFI_PAGE_SIZE * 2) + +#endif \ No newline at end of file diff --git a/EDK/Foundation/Core/Dxe/Library/Library.c b/EDK/Foundation/Core/Dxe/Library/Library.c new file mode 100644 index 0000000..6014656 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/Library/Library.c @@ -0,0 +1,878 @@ +/*++ + +Copyright (c) 2004 - 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Library.c + +Abstract: + + DXE Core library services. + +--*/ + +#include "Tiano.h" +#include "DxeCore.h" +#include "EfiCommonLib.h" + +DEBUG_CODE ( + UINTN mErrorLevel = EFI_DBUG_MASK | EFI_D_LOAD; +) + +EFI_DEVICE_HANDLE_EXTENDED_DATA mStatusCodeData = { + sizeof (EFI_STATUS_CODE_DATA), + sizeof (EFI_DEVICE_HANDLE_EXTENDED_DATA) - sizeof (EFI_STATUS_CODE_DATA), + EFI_STATUS_CODE_SPECIFIC_DATA_GUID, + NULL +}; + +VOID +CoreReportProgressCodeSpecific ( + IN EFI_STATUS_CODE_VALUE Value, + IN EFI_HANDLE Handle + ) +/*++ + +Routine Description: + + Report status code of type EFI_PROGRESS_CODE by caller ID gEfiDxeServicesTableGuid, + with a handle as additional information. + +Arguments: + + Value - Describes the class/subclass/operation of the hardware or software entity + that the Status Code relates to. + + Handle - Additional information. + +Returns: + + None + +--*/ +{ + mStatusCodeData.DataHeader.Size = sizeof (EFI_DEVICE_HANDLE_EXTENDED_DATA) - sizeof (EFI_STATUS_CODE_DATA); + mStatusCodeData.Handle = Handle; + + if ((gStatusCode != NULL) && (gStatusCode->ReportStatusCode != NULL) ) { + gStatusCode->ReportStatusCode ( + EFI_PROGRESS_CODE, + Value, + 0, + &gEfiDxeServicesTableGuid, + (EFI_STATUS_CODE_DATA *) &mStatusCodeData + ); + } +} + +VOID +CoreReportProgressCode ( + IN EFI_STATUS_CODE_VALUE Value + ) +/*++ + +Routine Description: + + Report status code of type EFI_PROGRESS_CODE by caller ID gEfiDxeServicesTableGuid. + +Arguments: + + Value - Describes the class/subclass/operation of the hardware or software entity + that the Status Code relates to. + +Returns: + + None + +--*/ +{ + if ((gStatusCode != NULL) && (gStatusCode->ReportStatusCode != NULL) ) { + gStatusCode->ReportStatusCode ( + EFI_PROGRESS_CODE, + Value, + 0, + &gEfiDxeServicesTableGuid, + NULL + ); + } +} + + +VOID * +CoreAllocateBootServicesPool ( + IN UINTN AllocationSize + ) +/*++ + +Routine Description: + + Allocate pool of type EfiBootServicesData, the size is specified with AllocationSize. + +Arguments: + + AllocationSize - Size to allocate. + +Returns: + + Pointer of the allocated pool. + +--*/ +{ + VOID *Memory; + + CoreAllocatePool (EfiBootServicesData, AllocationSize, &Memory); + return Memory; +} + + +VOID * +CoreAllocateZeroBootServicesPool ( + IN UINTN AllocationSize + ) +/*++ + +Routine Description: + + Allocate pool of type EfiBootServicesData and zero it, the size is specified with AllocationSize. + +Arguments: + + AllocationSize - Size to allocate. + +Returns: + + Pointer of the allocated pool. + +--*/ +{ + VOID *Memory; + + Memory = CoreAllocateBootServicesPool (AllocationSize); + EfiCommonLibSetMem (Memory, (Memory == NULL) ? 0 : AllocationSize, 0); + return Memory; +} + + +VOID * +CoreAllocateCopyPool ( + IN UINTN AllocationSize, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Allocate pool of specified size with EfiBootServicesData type, and copy specified buffer to this pool. + +Arguments: + + AllocationSize - Size to allocate. + + Buffer - Specified buffer that will be copy to the allocated pool + +Returns: + + Pointer of the allocated pool. + +--*/ +{ + VOID *Memory; + + Memory = CoreAllocateBootServicesPool (AllocationSize); + EfiCommonLibCopyMem (Memory, Buffer, (Memory == NULL) ? 0 : AllocationSize); + + return Memory; +} + + + +VOID * +CoreAllocateRuntimePool ( + IN UINTN AllocationSize + ) +/*++ + +Routine Description: + + Allocate pool of type EfiRuntimeServicesData, the size is specified with AllocationSize. + +Arguments: + + AllocationSize - Size to allocate. + +Returns: + + Pointer of the allocated pool. + +--*/ +{ + VOID *Memory; + + CoreAllocatePool (EfiRuntimeServicesData, AllocationSize, &Memory); + return Memory; +} + +VOID * +CoreAllocateRuntimeCopyPool ( + IN UINTN AllocationSize, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Allocate pool of specified size with EfiRuntimeServicesData type, and copy specified buffer to this pool. + +Arguments: + + AllocationSize - Size to allocate. + + Buffer - Specified buffer that will be copy to the allocated pool + +Returns: + + Pointer of the allocated pool. + +--*/ + +{ + VOID *Memory; + + Memory = CoreAllocateRuntimePool (AllocationSize); + EfiCommonLibCopyMem (Memory, Buffer, (Memory == NULL) ? 0 : AllocationSize); + + return Memory; +} + + + +// +// Lock Stuff +// + + + +EFI_STATUS +CoreAcquireLockOrFail ( + IN EFI_LOCK *Lock + ) +/*++ + +Routine Description: + + Initialize a basic mutual exclusion lock. Each lock + provides mutual exclusion access at it's task priority + level. Since there is no-premption (at any TPL) or + multiprocessor support, acquiring the lock only consists + of raising to the locks TPL. + +Arguments: + + Lock - The EFI_LOCK structure to initialize + +Returns: + + EFI_SUCCESS - Lock Owned. + EFI_ACCESS_DENIED - Reentrant Lock Acquisition, Lock not Owned. + +--*/ +{ + if (Lock->Lock != 0) { + // + // Lock is already owned, so bail out + // + return EFI_ACCESS_DENIED; + } + + Lock->OwnerTpl = CoreRaiseTpl (Lock->Tpl); + Lock->Lock += 1; + + return EFI_SUCCESS; +} + + +VOID +CoreAcquireLock ( + IN EFI_LOCK *Lock + ) +/*++ + +Routine Description: + + Raising to the task priority level of the mutual exclusion + lock, and then acquires ownership of the lock. + +Arguments: + + Lock - The lock to acquire + +Returns: + + Lock owned + +--*/ +{ + EFI_STATUS Status; + + Status = CoreAcquireLockOrFail (Lock); + + // + // Lock was already locked. + // + ASSERT_EFI_ERROR (Status); +} + + +VOID +CoreReleaseLock ( + IN EFI_LOCK *Lock + ) +/*++ + +Routine Description: + + Releases ownership of the mutual exclusion lock, and + restores the previous task priority level. + +Arguments: + + Lock - The lock to release + +Returns: + + Lock unowned + +--*/ +{ + EFI_TPL Tpl; + + Tpl = Lock->OwnerTpl; + + ASSERT (Lock->Lock == 1); + Lock->Lock -= 1; + + CoreRestoreTpl (Tpl); +} + + +UINTN +CoreDevicePathSize ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +/*++ + +Routine Description: + + Calculate the size of a whole device path. + +Arguments: + + DevicePath - The pointer to the device path data. + +Returns: + + Size of device path data structure.. + +--*/ +{ + EFI_DEVICE_PATH_PROTOCOL *Start; + + if (DevicePath == NULL) { + return 0; + } + + // + // Search for the end of the device path structure + // + Start = DevicePath; + while (!EfiIsDevicePathEnd (DevicePath)) { + DevicePath = EfiNextDevicePathNode (DevicePath); + } + + // + // Compute the size and add back in the size of the end device path structure + // + return ((UINTN)DevicePath - (UINTN)Start) + sizeof(EFI_DEVICE_PATH_PROTOCOL); +} + + +BOOLEAN +CoreIsDevicePathMultiInstance ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +/*++ + +Routine Description: + Return TRUE is this is a multi instance device path. + +Arguments: + DevicePath - A pointer to a device path data structure. + + +Returns: + TRUE - If DevicePath is multi instance. FALSE - If DevicePath is not multi + instance. + +--*/ +{ + EFI_DEVICE_PATH_PROTOCOL *Node; + + if (DevicePath == NULL) { + return FALSE; + } + + Node = DevicePath; + while (!EfiIsDevicePathEnd (Node)) { + if (EfiIsDevicePathEndInstance (Node)) { + return TRUE; + } + Node = EfiNextDevicePathNode (Node); + } + return FALSE; +} + + + +EFI_DEVICE_PATH_PROTOCOL * +CoreDuplicateDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +/*++ + +Routine Description: + Duplicate a new device path data structure from the old one. + +Arguments: + DevicePath - A pointer to a device path data structure. + +Returns: + A pointer to the new allocated device path data. + Caller must free the memory used by DevicePath if it is no longer needed. + +--*/ +{ + EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; + UINTN Size; + + if (DevicePath == NULL) { + return NULL; + } + + // + // Compute the size + // + Size = CoreDevicePathSize (DevicePath); + + // + // Allocate space for duplicate device path + // + NewDevicePath = CoreAllocateCopyPool (Size, DevicePath); + + return NewDevicePath; +} + + + +EFI_DEVICE_PATH_PROTOCOL * +CoreAppendDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *Src1, + IN EFI_DEVICE_PATH_PROTOCOL *Src2 + ) +/*++ + +Routine Description: + Function is used to append a Src1 and Src2 together. + +Arguments: + Src1 - A pointer to a device path data structure. + + Src2 - A pointer to a device path data structure. + +Returns: + + A pointer to the new device path is returned. + NULL is returned if space for the new device path could not be allocated from pool. + It is up to the caller to free the memory used by Src1 and Src2 if they are no longer needed. + +--*/ +{ + UINTN Size; + UINTN Size1; + UINTN Size2; + EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; + EFI_DEVICE_PATH_PROTOCOL *SecondDevicePath; + + if (Src1 == NULL && Src2 == NULL) { + return NULL; + } + + // + // Allocate space for the combined device path. It only has one end node of + // length EFI_DEVICE_PATH_PROTOCOL + // + Size1 = CoreDevicePathSize (Src1); + Size2 = CoreDevicePathSize (Src2); + Size = Size1 + Size2 - sizeof(EFI_DEVICE_PATH_PROTOCOL); + + NewDevicePath = CoreAllocateCopyPool (Size, Src1); + if (NewDevicePath != NULL) { + + // + // Over write Src1 EndNode and do the copy + // + SecondDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)((CHAR8 *)NewDevicePath + (Size1 - sizeof(EFI_DEVICE_PATH_PROTOCOL))); + EfiCommonLibCopyMem (SecondDevicePath, Src2, Size2); + } + + return NewDevicePath; +} + + + +EFI_EVENT +CoreCreateProtocolNotifyEvent ( + IN EFI_GUID *ProtocolGuid, + IN EFI_TPL NotifyTpl, + IN EFI_EVENT_NOTIFY NotifyFunction, + IN VOID *NotifyContext, + OUT VOID **Registration, + IN BOOLEAN SignalFlag + ) +/*++ + +Routine Description: + + Create a protocol notification event and return it. + +Arguments: + + ProtocolGuid - Protocol to register notification event on. + + NotifyTpl - Maximum TPL to signal the NotifyFunction. + + NotifyFuncition - EFI notification routine. + + NotifyContext - Context passed into Event when it is created. + + Registration - Registration key returned from RegisterProtocolNotify(). + + SignalFlag - Boolean value to decide whether kick the event after register or not. + +Returns: + + The EFI_EVENT that has been registered to be signaled when a ProtocolGuid + is added to the system. + +--*/ +{ + EFI_STATUS Status; + EFI_EVENT Event; + + // + // Create the event + // + + Status = CoreCreateEvent ( + EFI_EVENT_NOTIFY_SIGNAL, + NotifyTpl, + NotifyFunction, + NotifyContext, + &Event + ); + ASSERT_EFI_ERROR (Status); + + // + // Register for protocol notifactions on this event + // + + Status = CoreRegisterProtocolNotify ( + ProtocolGuid, + Event, + Registration + ); + ASSERT_EFI_ERROR (Status); + + if (SignalFlag) { + // + // Kick the event so we will perform an initial pass of + // current installed drivers + // + CoreSignalEvent (Event); + } + + return Event; +} + +/*++ +Routine Description: + + Initialize a Firmware Volume (FV) Media Device Path node. + + Tiano extended the EFI 1.10 device path nodes. Tiano does not own this enum + so as we move to UEFI 2.0 support we must use a mechanism that conforms with + the UEFI 2.0 specification to define the FV device path. An UEFI GUIDed + device path is defined for PIWG extensions of device path. If the code + is compiled to conform with the UEFI 2.0 specification use the new device path + else use the old form for backwards compatability. + +Arguments: + + FvDevicePathNode - Pointer to a FV device path node to initialize + NameGuid - FV file name to use in FvDevicePathNode + +--*/ +VOID +EFIAPI +CoreInitializeFwVolDevicepathNode ( + IN MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvDevicePathNode, + IN EFI_GUID *NameGuid + ) +{ +// +// EDK Defect Start: EDK848 +// +#if 1 +//#if (EFI_SPECIFICATION_VERSION < 0x00020000) +// +// EDK Defect End: EDK848 +// + // + // Use old Device Path that conflicts with UEFI + // + FvDevicePathNode->Header.Type = MEDIA_DEVICE_PATH; + FvDevicePathNode->Header.SubType = MEDIA_FV_FILEPATH_DP; + SetDevicePathNodeLength (&FvDevicePathNode->Header, sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH)); + +#else + // + // Use the new Device path that does not conflict with the UEFI + // + FvDevicePathNode->Piwg.Header.Type = MEDIA_DEVICE_PATH; + FvDevicePathNode->Piwg.Header.SubType = MEDIA_VENDOR_DP; + SetDevicePathNodeLength (&FvDevicePathNode->Piwg.Header, sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH)); + + // + // Add the GUID for generic PIWG device paths + // + EfiCommonLibCopyMem (&FvDevicePathNode->Piwg.PiwgSpecificDevicePath, &gEfiFrameworkDevicePathGuid, sizeof(EFI_GUID)); + + // + // Add in the FW Vol File Path PIWG defined inforation + // + FvDevicePathNode->Piwg.Type = PIWG_MEDIA_FW_VOL_FILEPATH_DEVICE_PATH_TYPE; + +#endif + EfiCommonLibCopyMem (&FvDevicePathNode->NameGuid, NameGuid, sizeof(EFI_GUID)); +} + +/*++ + +Routine Description: + + Check to see if the Firmware Volume (FV) Media Device Path is valid. + + Tiano extended the EFI 1.10 device path nodes. Tiano does not own this enum + so as we move to UEFI 2.0 support we must use a mechanism that conforms with + the UEFI 2.0 specification to define the FV device path. An UEFI GUIDed + device path is defined for PIWG extensions of device path. If the code + is compiled to conform with the UEFI 2.0 specification use the new device path + else use the old form for backwards compatability. The return value to this + function points to a location in FvDevicePathNode and it does not allocate + new memory for the GUID pointer that is returned. + +Arguments: + + @param FvDevicePathNode Pointer to FV device path to check + +Returns: + + NULL - FvDevicePathNode is not valid. + Other - FvDevicePathNode is valid and pointer to NameGuid was returned. + +--*/ +EFI_GUID * +EFIAPI +CoreGetNameGuidFromFwVolDevicePathNode ( + IN MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvDevicePathNode + ) +{ +// +// EDK Defect Start: EDK848 +// +#if 1 +//#if (EFI_SPECIFICATION_VERSION < 0x00020000) +// +// EDK Defect End: EDK848 +// + // + // Use old Device Path that conflicts with UEFI + // + if (DevicePathType (&FvDevicePathNode->Header) == MEDIA_DEVICE_PATH && + DevicePathSubType (&FvDevicePathNode->Header) == MEDIA_FV_FILEPATH_DP) { + return &FvDevicePathNode->NameGuid; + } + +#else + // + // Use the new Device path that does not conflict with the UEFI + // + if (DevicePathType (&FvDevicePathNode->Piwg.Header) == MEDIA_DEVICE_PATH && + DevicePathSubType (&FvDevicePathNode->Piwg.Header) == MEDIA_VENDOR_DP) { + if (EfiCompareGuid (&gEfiFrameworkDevicePathGuid, &FvDevicePathNode->Piwg.PiwgSpecificDevicePath)) { + if (FvDevicePathNode->Piwg.Type == PIWG_MEDIA_FW_VOL_FILEPATH_DEVICE_PATH_TYPE) { + return &FvDevicePathNode->NameGuid; + } + } + } +#endif + return NULL; +} + +DEBUG_CODE ( + +VOID +EfiDebugAssert ( + IN CHAR8 *FileName, + IN INTN LineNumber, + IN CHAR8 *Description + ) +/*++ + +Routine Description: + + Worker function for ASSERT(). If Error Logging hub is loaded, log DEBUG + information; If not, do BREAKPOINT(). + + We use UINT64 buffers due to IPF alignment concerns. + +Arguments: + + FileName - File name of failing routine. + + LineNumber - Line number of failing ASSERT(). + + Description - Descritption, usally the assertion string. + +Returns: + + None + +--*/ +{ + UINT64 Buffer[EFI_STATUS_CODE_DATA_MAX_SIZE]; + + EfiDebugAssertWorker (FileName, LineNumber,Description, sizeof (Buffer), Buffer); + + // + // Check if our pointers are valid. Can't assert because that would recurse. + // + if ((gStatusCode != NULL) && (gStatusCode->ReportStatusCode != NULL) ) { + gStatusCode->ReportStatusCode ( + (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED), + (EFI_SOFTWARE_DXE_CORE | EFI_SW_EC_ILLEGAL_SOFTWARE_STATE), + 0, + &gEfiDxeServicesTableGuid, + (EFI_STATUS_CODE_DATA *)Buffer + ); + } + + // + // Put break point in module that contained the error. + // + EFI_BREAKPOINT (); +} + + +VOID +EfiDebugVPrint ( + IN UINTN ErrorLevel, + IN CHAR8 *Format, + IN VA_LIST Marker + ) +/*++ + +Routine Description: + + Worker function for DEBUG(). If Error Logging hub is loaded, DEBUG + information will be logged. If Error Logging hub is not loaded, do nothing. + + We use UINT64 buffers due to IPF alignment concerns. + +Arguments: + + ErrorLevel - If error level is set do the debug print. + + Format - String to use for the print, followed by Print arguments. + + Marker - VarArgs + +Returns: + + None + +--*/ +{ + UINT64 Buffer[EFI_STATUS_CODE_DATA_MAX_SIZE]; + + if (!(mErrorLevel & ErrorLevel)) { + return; + } + + EfiDebugVPrintWorker (ErrorLevel, Format, Marker, sizeof (Buffer), Buffer); + + // + // Check if our pointers are valid. Can't assert because that would recurse. + // + if ((gStatusCode != NULL) && (gStatusCode->ReportStatusCode != NULL) ) { + gStatusCode->ReportStatusCode ( + EFI_DEBUG_CODE, + (EFI_SOFTWARE_DXE_CORE | EFI_DC_UNSPECIFIED), + 0, + &gEfiDxeServicesTableGuid, + (EFI_STATUS_CODE_DATA *)Buffer + ); + } +} + + +VOID +EfiDebugPrint ( + IN UINTN ErrorLevel, + IN CHAR8 *Format, + ... + ) +/*++ + +Routine Description: + + Wrapper for EfiDebugVPrint () + +Arguments: + + ErrorLevel - If error level is set do the debug print. + + Format - String to use for the print, followed by Print arguments. + + ... - Print arguments. + +Returns: + + None + +--*/ +{ + VA_LIST Marker; + + VA_START (Marker, Format); + EfiDebugVPrint (ErrorLevel, Format, Marker); + VA_END (Marker); +} +) diff --git a/EDK/Foundation/Core/Dxe/Mem/Page.c b/EDK/Foundation/Core/Dxe/Mem/Page.c new file mode 100644 index 0000000..0f79cb3 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/Mem/Page.c @@ -0,0 +1,1648 @@ +/*++ + +Copyright (c) 2007 - 2011, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + page.c + +Abstract: + + EFI Memory page management + + +Revision History + +--*/ + +#include "imem.h" + +#define EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT (EFI_PAGE_SIZE) + +// +// Entry for tracking the memory regions for each memory type to help coalesce like memory types +// +typedef struct { + EFI_PHYSICAL_ADDRESS BaseAddress; // Base address of the coalesce bin if NumberOfPages is not 0, or 0 otherwise + EFI_PHYSICAL_ADDRESS MaximumAddress; // Top address of the coalesce bin if NumberOfPages is not 0, or the top address below all bin ranges + UINT64 CurrentNumberOfPages; // CurrentNumberOfPages allocated for this memory type + UINT64 NumberOfPages; // Number of pages specified in gMemoryTypeInformation + UINTN InformationIndex; // Index into gMemoryTypeInformation + BOOLEAN Special; // If this type of coalesce bin needs to be filled in memory map + BOOLEAN Runtime; // If this type is runtime available +} EFI_MEMORY_TYPE_STAISTICS; + +// +// MemoryMap - The current memory map +// +UINTN mMemoryMapKey = 0; + +// +// mMapStack - space to use as temp storage to build new map descriptors +// mMapDepth - depth of new descriptor stack +// + +#define MAX_MAP_DEPTH 6 +UINTN mMapDepth = 0; +MEMORY_MAP mMapStack[MAX_MAP_DEPTH]; +UINTN mFreeMapStack = 0; +// +// This list maintain the free memory map list +// +EFI_LIST_ENTRY mFreeMemoryMapEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList); +BOOLEAN mMemoryTypeInformationInitialized = FALSE; + +EFI_MEMORY_TYPE_STAISTICS mMemoryTypeStatistics[EfiMaxMemoryType + 1] = { + { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiReservedMemoryType + { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiLoaderCode + { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiLoaderData + { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiBootServicesCode + { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiBootServicesData + { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiRuntimeServicesCode + { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiRuntimeServicesData + { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiConventionalMemory + { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiUnusableMemory + { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiACPIReclaimMemory + { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiACPIMemoryNVS + { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiMemoryMappedIO + { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiMemoryMappedIOPortSpace + { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiPalCode + { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE } // EfiMaxMemoryType +}; + +EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress = EFI_MAX_ADDRESS; + +EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1] = { + { EfiReservedMemoryType, 0 }, + { EfiLoaderCode, 0 }, + { EfiLoaderData, 0 }, + { EfiBootServicesCode, 0 }, + { EfiBootServicesData, 0 }, + { EfiRuntimeServicesCode, 0 }, + { EfiRuntimeServicesData, 0 }, + { EfiConventionalMemory, 0 }, + { EfiUnusableMemory, 0 }, + { EfiACPIReclaimMemory, 0 }, + { EfiACPIMemoryNVS, 0 }, + { EfiMemoryMappedIO, 0 }, + { EfiMemoryMappedIOPortSpace, 0 }, + { EfiPalCode, 0 }, + { EfiMaxMemoryType, 0 } +}; + +// +// Internal prototypes +// +VOID +PromoteMemoryResource ( + VOID +); + +STATIC +VOID +CoreAddRange ( + IN EFI_MEMORY_TYPE Type, + IN EFI_PHYSICAL_ADDRESS Start, + IN EFI_PHYSICAL_ADDRESS End, + IN UINT64 Attribute + ); + +STATIC +VOID +CoreFreeMemoryMapStack ( + VOID + ); + +STATIC +EFI_STATUS +CoreConvertPages ( + IN UINT64 Start, + IN UINT64 NumberOfPages, + IN EFI_MEMORY_TYPE NewType + ); + +STATIC +VOID +RemoveMemoryMapEntry ( + MEMORY_MAP *Entry + ); + + +MEMORY_MAP * +AllocateMemoryMapEntry ( + ); + +VOID +CoreAcquireMemoryLock ( + VOID + ) +/*++ + +Routine Description: + + Enter critical section by gaining lock on gMemoryLock + +Arguments: + + None + +Returns: + + None + +--*/ +{ + CoreAcquireLock (&gMemoryLock); +} + + +VOID +CoreReleaseMemoryLock ( + VOID + ) +/*++ + +Routine Description: + + Exit critical section by releasing lock on gMemoryLock + +Arguments: + + None + +Returns: + + None + +--*/ +{ + CoreReleaseLock (&gMemoryLock); +} + +VOID +PromoteMemoryResource ( + VOID + ) +/*++ + +Routine Description: + + Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable. + +Arguments: + + None + +Returns: + + None + +--*/ +{ + EFI_LIST_ENTRY *Link; + EFI_GCD_MAP_ENTRY *Entry; + + DEBUG ((EFI_D_ERROR | EFI_D_PAGE, "Promote the memory resource\n")); + + CoreAcquireGcdMemoryLock (); + + Link = mGcdMemorySpaceMap.ForwardLink; + while (Link != &mGcdMemorySpaceMap) { + + Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE); + + if (Entry->GcdMemoryType == EfiGcdMemoryTypeReserved && + Entry->EndAddress < EFI_MAX_ADDRESS && + (Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) == + (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)) { + // + // Update the GCD map + // + Entry->GcdMemoryType = EfiGcdMemoryTypeSystemMemory; + Entry->Capabilities |= EFI_MEMORY_TESTED; + Entry->ImageHandle = gDxeCoreImageHandle; + Entry->DeviceHandle = NULL; + + // + // Add to allocable system memory resource + // + + CoreAddRange ( + EfiConventionalMemory, + Entry->BaseAddress, + Entry->EndAddress, + Entry->Capabilities & ~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME) + ); + mMemoryTypeStatistics[EfiConventionalMemory].CurrentNumberOfPages += RShiftU64 ((Entry->EndAddress - Entry->BaseAddress + 1), EFI_PAGE_SHIFT); + CoreFreeMemoryMapStack (); + + } + + Link = Link->ForwardLink; + } + + CoreReleaseGcdMemoryLock (); + + return; +} + +VOID +CoreAddMemoryDescriptor ( + IN EFI_MEMORY_TYPE Type, + IN EFI_PHYSICAL_ADDRESS Start, + IN UINT64 NumberOfPages, + IN UINT64 Attribute + ) +/*++ + +Routine Description: + + Called to initialize the memory map and add descriptors to + the current descriptor list. + + N.B. The first descriptor that is added must be general usable + memory as the addition allocates heap. + +Arguments: + + Type - The type of memory to add + + Start - The starting address in the memory range + Must be page aligned + + NumberOfPages - The number of pages in the range + + Attribute - Attributes of the memory to add + +Returns: + + None. The range is added to the memory map + +--*/ +{ + EFI_PHYSICAL_ADDRESS End; + EFI_STATUS Status; + UINTN Index; + UINTN FreeIndex; + + if ((Start & EFI_PAGE_MASK) != 0) { + return; + } + + if (Type >= EfiMaxMemoryType && Type <= 0x7fffffff) { + return; + } + + CoreAcquireMemoryLock (); + End = Start + LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT) - 1; + CoreAddRange (Type, Start, End, Attribute); + mMemoryTypeStatistics[Type].CurrentNumberOfPages += NumberOfPages; + CoreFreeMemoryMapStack (); + CoreReleaseMemoryLock (); + + // + // Check to see if the statistics for the different memory types have already been established + // + if (mMemoryTypeInformationInitialized) { + return; + } + + // + // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array + // + for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) { + // + // Make sure the memory type in the gMemoryTypeInformation[] array is valid + // + Type = gMemoryTypeInformation[Index].Type; + if (Type < 0 || Type > EfiMaxMemoryType) { + continue; + } + + if (gMemoryTypeInformation[Index].NumberOfPages != 0) { + // + // Allocate pages for the current memory type from the top of available memory + // + Status = CoreAllocatePages ( + AllocateAnyPages, + Type, + gMemoryTypeInformation[Index].NumberOfPages, + &mMemoryTypeStatistics[Type].BaseAddress + ); + if (EFI_ERROR (Status)) { + // + // If an error occurs allocating the pages for the current memory type, then + // free all the pages allocates for the previous memory types and return. This + // operation with be retied when/if more memory is added to the system + // + for (FreeIndex = 0; FreeIndex < Index; FreeIndex++) { + // + // Make sure the memory type in the gMemoryTypeInformation[] array is valid + // + Type = gMemoryTypeInformation[FreeIndex].Type; + if (Type < 0 || Type > EfiMaxMemoryType) { + continue; + } + + if (gMemoryTypeInformation[FreeIndex].NumberOfPages != 0) { + CoreFreePages ( + mMemoryTypeStatistics[Type].BaseAddress, + gMemoryTypeInformation[FreeIndex].NumberOfPages + ); + mMemoryTypeStatistics[Type].BaseAddress = 0; + mMemoryTypeStatistics[Type].MaximumAddress = EFI_MAX_ADDRESS; + } + } + return; + } + + // + // Compute the address at the top of the current statistics + // + mMemoryTypeStatistics[Type].MaximumAddress = + mMemoryTypeStatistics[Type].BaseAddress + + LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT) - 1; + + // + // If the current base address is the lowest address so far, then update the default + // maximum address + // + if (mMemoryTypeStatistics[Type].BaseAddress < mDefaultMaximumAddress) { + mDefaultMaximumAddress = mMemoryTypeStatistics[Type].BaseAddress - 1; + } + } + } + + // + // There was enough system memory for all the the memory types were allocated. So, + // those memory areas can be freed for future allocations, and all future memory + // allocations can occur within their respective bins + // + for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) { + // + // Make sure the memory type in the gMemoryTypeInformation[] array is valid + // + Type = gMemoryTypeInformation[Index].Type; + if (Type < 0 || Type > EfiMaxMemoryType) { + continue; + } + + if (gMemoryTypeInformation[Index].NumberOfPages != 0) { + CoreFreePages ( + mMemoryTypeStatistics[Type].BaseAddress, + gMemoryTypeInformation[Index].NumberOfPages + ); + mMemoryTypeStatistics[Type].NumberOfPages = gMemoryTypeInformation[Index].NumberOfPages; + gMemoryTypeInformation[Index].NumberOfPages = 0; + } + } + + // + // If the number of pages reserved for a memory type is 0, then all allocations for that type + // should be in the default range. + // + for (Type = 0; Type < EfiMaxMemoryType; Type++) { + for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) { + if (Type == (EFI_MEMORY_TYPE)gMemoryTypeInformation[Index].Type) { + mMemoryTypeStatistics[Type].InformationIndex = Index; + } + } + if (mMemoryTypeStatistics[Type].MaximumAddress == EFI_MAX_ADDRESS) { + mMemoryTypeStatistics[Type].MaximumAddress = mDefaultMaximumAddress; + } + } + + mMemoryTypeInformationInitialized = TRUE; +} + + +STATIC +VOID +CoreAddRange ( + IN EFI_MEMORY_TYPE Type, + IN EFI_PHYSICAL_ADDRESS Start, + IN EFI_PHYSICAL_ADDRESS End, + IN UINT64 Attribute + ) +/*++ + +Routine Description: + + Internal function. Adds a ranges to the memory map. + The range must not already exist in the map. + +Arguments: + + Type - The type of memory range to add + + Start - The starting address in the memory range + Must be paged aligned + + End - The last address in the range + Must be the last byte of a page + + Attribute - The attributes of the memory range to add + +Returns: + + None. The range is added to the memory map + +--*/ +{ + EFI_LIST_ENTRY *Link; + MEMORY_MAP *Entry; + + ASSERT ((Start & EFI_PAGE_MASK) == 0); + ASSERT (End > Start) ; + + ASSERT_LOCKED (&gMemoryLock); + + DEBUG ((EFI_D_PAGE, "AddRange: %lx-%lx to %d\n", Start, End, (UINTN)Type)); + + // + // Memory map being altered + // + + mMemoryMapKey += 1; + + // + // Look for adjoining memory descriptor + // + + // Two memory descriptors can only be merged if they have the same Type + // and the same Attribute + // + + Link = gMemoryMap.ForwardLink; + while (Link != &gMemoryMap) { + Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE); + Link = Link->ForwardLink; + + if (Entry->Type != Type) { + continue; + } + + if (Entry->Attribute != Attribute) { + continue; + } + + if (Entry->End + 1 == Start) { + + Start = Entry->Start; + RemoveMemoryMapEntry (Entry); + + } else if (Entry->Start == End + 1) { + + End = Entry->End; + RemoveMemoryMapEntry (Entry); + } + } + + // + // Add descriptor + // + + mMapStack[mMapDepth].Signature = MEMORY_MAP_SIGNATURE; + mMapStack[mMapDepth].FromPages = FALSE; + mMapStack[mMapDepth].Type = Type; + mMapStack[mMapDepth].Start = Start; + mMapStack[mMapDepth].End = End; + mMapStack[mMapDepth].VirtualStart = 0; + mMapStack[mMapDepth].Attribute = Attribute; + InsertTailList (&gMemoryMap, &mMapStack[mMapDepth].Link); + + mMapDepth += 1; + ASSERT (mMapDepth < MAX_MAP_DEPTH); + return ; +} + +STATIC +VOID +CoreFreeMemoryMapStack ( + VOID + ) +/*++ + +Routine Description: + + Internal function. Moves any memory descriptors that are on the + temporary descriptor stack to heap. + +Arguments: + + None + +Returns: + + None + +--*/ +{ + MEMORY_MAP *Entry; + MEMORY_MAP *Entry2; + EFI_LIST_ENTRY *Link2; + + ASSERT_LOCKED (&gMemoryLock); + + // + // If already freeing the map stack, then return + // + if (mFreeMapStack) { + return ; + } + + // + // Move the temporary memory descriptor stack into pool + // + mFreeMapStack += 1; + + while (mMapDepth) { + // + // Deque an memory map entry from mFreeMemoryMapEntryList + // + Entry = AllocateMemoryMapEntry (); + + ASSERT (Entry); + + // + // Update to proper entry + // + mMapDepth -= 1; + + if (mMapStack[mMapDepth].Link.ForwardLink != NULL) { + + // + // Move this entry to general memory + // + RemoveEntryList (&mMapStack[mMapDepth].Link); + mMapStack[mMapDepth].Link.ForwardLink = NULL; + + *Entry = mMapStack[mMapDepth]; + Entry->FromPages = TRUE; + + // + // Find insertion location + // + for (Link2 = gMemoryMap.ForwardLink; Link2 != &gMemoryMap; Link2 = Link2->ForwardLink) { + Entry2 = CR (Link2, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE); + if (Entry2->FromPages && Entry2->Start > Entry->Start) { + break; + } + } + + InsertTailList (Link2, &Entry->Link); + + } else { + // + // This item of mMapStack[mMapDepth] has already been dequeued from gMemoryMap list, + // so here no need to move it to memory. + // + InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link); + } + } + + mFreeMapStack -= 1; +} + +STATIC +VOID +RemoveMemoryMapEntry ( + MEMORY_MAP *Entry + ) +/*++ + +Routine Description: + + Internal function. Removes a descriptor entry. + +Arguments: + + Entry - The entry to remove + +Returns: + + None + +--*/ +{ + RemoveEntryList (&Entry->Link); + Entry->Link.ForwardLink = NULL; + + if (Entry->FromPages) { + // + // Insert the free memory map descriptor to the end of mFreeMemoryMapEntryList + // + InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link); + } +} + +MEMORY_MAP * +AllocateMemoryMapEntry ( + ) +/*++ + +Routine Description: + + Internal function. Deque a descriptor entry from the mFreeMemoryMapEntryList. + If the list is emtry, then allocate a new page to refuel the list. + Please Note this algorithm to allocate the memory map descriptor has a property + that the memory allocated for memory entries always grows, and will never really be freed + For example, if the current boot uses 2000 memory map entries at the maximum point, but + ends up with only 50 at the time the OS is booted, then the memory associated with the 1950 + memory map entries is still allocated from EfiBootServicesMemory. + +Arguments: + + NONE + +Returns: + + The Memory map descriptor dequed from the mFreeMemoryMapEntryList + +--*/ +{ + MEMORY_MAP* FreeDescriptorEntries; + MEMORY_MAP* Entry; + UINTN Index; + + if (IsListEmpty (&mFreeMemoryMapEntryList)) { + // + // The list is empty, to allocate one page to refuel the list + // + FreeDescriptorEntries = CoreAllocatePoolPages (EfiBootServicesData, EFI_SIZE_TO_PAGES(DEFAULT_PAGE_ALLOCATION), DEFAULT_PAGE_ALLOCATION); + if(FreeDescriptorEntries != NULL) { + // + // Enque the free memmory map entries into the list + // + for (Index = 0; Index< DEFAULT_PAGE_ALLOCATION / sizeof(MEMORY_MAP); Index++) { + FreeDescriptorEntries[Index].Signature = MEMORY_MAP_SIGNATURE; + InsertTailList (&mFreeMemoryMapEntryList, &FreeDescriptorEntries[Index].Link); + } + } else { + return NULL; + } + } + // + // dequeue the first descriptor from the list + // + Entry = CR (mFreeMemoryMapEntryList.ForwardLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE); + RemoveEntryList (&Entry->Link); + + return Entry; +} + +STATIC +EFI_STATUS +CoreConvertPages ( + IN UINT64 Start, + IN UINT64 NumberOfPages, + IN EFI_MEMORY_TYPE NewType + ) +/*++ + +Routine Description: + + Internal function. Converts a memory range to the specified type. + The range must exist in the memory map. + +Arguments: + + Start - The first address of the range + Must be page aligned + + NumberOfPages - The number of pages to convert + + NewType - The new type for the memory range + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter + + EFI_NOT_FOUND - Could not find a descriptor cover the specified range + or convertion not allowed. + + EFI_SUCCESS - Successfully converts the memory range to the specified type. + +--*/ +{ + + UINT64 NumberOfBytes; + UINT64 End; + UINT64 RangeEnd; + UINT64 Attribute; + EFI_LIST_ENTRY *Link; + MEMORY_MAP *Entry; + UINT64 NumberOfRangePages; + + Entry = NULL; + NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT); + End = Start + NumberOfBytes - 1; + + ASSERT (NumberOfPages); + ASSERT ((Start & EFI_PAGE_MASK) == 0); + ASSERT (End > Start) ; + ASSERT_LOCKED (&gMemoryLock); + + if (NumberOfPages == 0 || (Start & EFI_PAGE_MASK ) || (Start > (Start + NumberOfBytes))) { + return EFI_INVALID_PARAMETER; + } + + // + // Convert the entire range + // + + while (Start < End) { + + // + // Find the entry that the covers the range + // + for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) { + Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE); + + if (Entry->Start <= Start && Entry->End > Start) { + break; + } + } + + if ((Link == &gMemoryMap) || (Entry == NULL)) { + DEBUG ((EFI_D_ERROR | EFI_D_PAGE, "ConvertPages: failed to find range %lx - %lx\n", Start, End)); + return EFI_NOT_FOUND; + } + + // + // Convert range to the end, or to the end of the descriptor + // if that's all we've got + // + RangeEnd = End; + if (Entry->End < End) { + RangeEnd = Entry->End; + } + + DEBUG ((EFI_D_PAGE, "ConvertRange: %lx-%lx to %d\n", Start, RangeEnd, (UINTN)NewType)); + + // + // Debug code - verify conversion is allowed + // + if (!(NewType == EfiConventionalMemory ? 1 : 0) ^ (Entry->Type == EfiConventionalMemory ? 1 : 0)) { + DEBUG ((EFI_D_ERROR , "ConvertPages: Incompatible memory types\n")); + return EFI_NOT_FOUND; + } + + // + // Update counters for the number of pages allocated to each memory type + // + NumberOfRangePages = RShiftU64 (RangeEnd - Start + 1, EFI_PAGE_SHIFT); + if (Entry->Type >= 0 && Entry->Type < EfiMaxMemoryType) { + ASSERT (NumberOfRangePages <= mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages); + mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages -= NumberOfRangePages; + gMemoryTypeInformation[mMemoryTypeStatistics[Entry->Type].InformationIndex].NumberOfPages = (UINT32)mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages; + } + + if (NewType >= 0 && NewType < EfiMaxMemoryType) { + mMemoryTypeStatistics[NewType].CurrentNumberOfPages += NumberOfRangePages; + gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages = (UINT32)mMemoryTypeStatistics[NewType].CurrentNumberOfPages; + } + + // + // Pull range out of descriptor + // + if (Entry->Start == Start) { + + // + // Clip start + // + Entry->Start = RangeEnd + 1; + + } else if (Entry->End == RangeEnd) { + + // + // Clip end + // + Entry->End = Start - 1; + + } else { + + // + // Pull it out of the center, clip current + // + + // + // Add a new one + // + mMapStack[mMapDepth].Signature = MEMORY_MAP_SIGNATURE; + mMapStack[mMapDepth].FromPages = FALSE; + mMapStack[mMapDepth].Type = Entry->Type; + mMapStack[mMapDepth].Start = RangeEnd+1; + mMapStack[mMapDepth].End = Entry->End; + + // + // Inherit Attribute from the Memory Descriptor that is being clipped + // + mMapStack[mMapDepth].Attribute = Entry->Attribute; + + Entry->End = Start - 1; + ASSERT (Entry->Start < Entry->End); + + Entry = &mMapStack[mMapDepth]; + InsertTailList (&gMemoryMap, &Entry->Link); + + mMapDepth += 1; + ASSERT (mMapDepth < MAX_MAP_DEPTH); + } + + // + // The new range inherits the same Attribute as the Entry + //it is being cut out of + // + Attribute = Entry->Attribute; + + // + // If the descriptor is empty, then remove it from the map + // + if (Entry->Start == Entry->End + 1) { + RemoveMemoryMapEntry (Entry); + Entry = NULL; + } + + // + // Add our new range in + // + CoreAddRange (NewType, Start, RangeEnd, Attribute); + + // + // Move any map descriptor stack to general pool + // + CoreFreeMemoryMapStack (); + + // + // Bump the starting address, and convert the next range + // + Start = RangeEnd + 1; + } + + // + // Converted the whole range, done + // + + return EFI_SUCCESS; +} + + +STATIC +UINT64 +CoreFindFreePagesI ( + IN UINT64 MaxAddress, + IN UINT64 NumberOfPages, + IN EFI_MEMORY_TYPE NewType, + IN UINTN Alignment + ) +/*++ + +Routine Description: + + Internal function. Finds a consecutive free page range below + the requested address. + +Arguments: + + MaxAddress - The address that the range must be below + + NumberOfPages - Number of pages needed + + NewType - The type of memory the range is going to be turned into + + Alignment - Bits to align with + +Returns: + + The base address of the range, or 0 if the range was not found + +--*/ +{ + UINT64 NumberOfBytes; + UINT64 Target; + UINT64 DescStart; + UINT64 DescEnd; + UINT64 DescNumberOfBytes; + EFI_LIST_ENTRY *Link; + MEMORY_MAP *Entry; + + if ((MaxAddress < EFI_PAGE_MASK) ||(NumberOfPages == 0)) { + return 0; + } + + if ((MaxAddress & EFI_PAGE_MASK) != EFI_PAGE_MASK) { + + // + // If MaxAddress is not aligned to the end of a page + // + + // + // Change MaxAddress to be 1 page lower + // + MaxAddress -= (EFI_PAGE_MASK + 1); + + // + // Set MaxAddress to a page boundary + // + MaxAddress &= ~EFI_PAGE_MASK; + + // + // Set MaxAddress to end of the page + // + MaxAddress |= EFI_PAGE_MASK; + } + + NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT); + Target = 0; + + for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) { + Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE); + + // + // If it's not a free entry, don't bother with it + // + if (Entry->Type != EfiConventionalMemory) { + continue; + } + + DescStart = Entry->Start; + DescEnd = Entry->End; + + // + // If desc is past max allowed address, skip it + // + if (DescStart >= MaxAddress) { + continue; + } + + // + // If desc ends past max allowed address, clip the end + // + if (DescEnd >= MaxAddress) { + DescEnd = MaxAddress; + } + + DescEnd = ((DescEnd + 1) & (~(Alignment - 1))) - 1; + + // + // Compute the number of bytes we can used from this + // descriptor, and see it's enough to satisfy the request + // + DescNumberOfBytes = DescEnd - DescStart + 1; + + if (DescNumberOfBytes >= NumberOfBytes) { + + // + // If this is the best match so far remember it + // + if (DescEnd > Target) { + Target = DescEnd; + } + } + } + + // + // If this is a grow down, adjust target to be the allocation base + // + Target -= NumberOfBytes - 1; + + // + // If we didn't find a match, return 0 + // + if ((Target & EFI_PAGE_MASK) != 0) { + return 0; + } + + return Target; +} + +STATIC +UINT64 +FindFreePages ( + IN UINT64 MaxAddress, + IN UINT64 NoPages, + IN EFI_MEMORY_TYPE NewType, + IN UINTN Alignment + ) +/*++ + +Routine Description: + + Internal function. Finds a consecutive free page range below + the requested address + +Arguments: + + MaxAddress - The address that the range must be below + + NoPages - Number of pages needed + + NewType - The type of memory the range is going to be turned into + + Alignment - Bits to align with + +Returns: + + The base address of the range, or 0 if the range was not found. + +--*/ +{ + UINT64 NewMaxAddress; + UINT64 Start; + + NewMaxAddress = MaxAddress; + + if (NewType >= 0 && NewType < EfiMaxMemoryType && NewMaxAddress >= mMemoryTypeStatistics[NewType].MaximumAddress) { + NewMaxAddress = mMemoryTypeStatistics[NewType].MaximumAddress; + } else { + if (NewMaxAddress > mDefaultMaximumAddress) { + NewMaxAddress = mDefaultMaximumAddress; + } + } + + Start = CoreFindFreePagesI (NewMaxAddress, NoPages, NewType, Alignment); + if (!Start) { + Start = CoreFindFreePagesI (MaxAddress, NoPages, NewType, Alignment); + if (!Start) { + // + // Here means there may be no enough memory to use, so try to go through + // all the memory descript to promote the untested memory directly + // + PromoteMemoryResource (); + + // + // Allocate memory again after the memory resource re-arranged + // + Start = CoreFindFreePagesI (MaxAddress, NoPages, NewType, Alignment); + } + } + + return Start; +} + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreAllocatePages ( + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN NumberOfPages, + IN OUT EFI_PHYSICAL_ADDRESS *Memory + ) +/*++ + +Routine Description: + + Allocates pages from the memory map. + +Arguments: + + Type - The type of allocation to perform + + MemoryType - The type of memory to turn the allocated pages into + + NumberOfPages - The number of pages to allocate + + Memory - A pointer to receive the base allocated memory address + +Returns: + + Status. On success, Memory is filled in with the base address allocated + + EFI_INVALID_PARAMETER - Parameters violate checking rules defined in spec. + + EFI_NOT_FOUND - Could not allocate pages match the requirement. + + EFI_OUT_OF_RESOURCES - No enough pages to allocate. + + EFI_SUCCESS - Pages successfully allocated. + +--*/ +{ + EFI_STATUS Status; + UINT64 Start; + UINT64 MaxAddress; + UINTN Alignment; + + if (Type < AllocateAnyPages || Type >= (UINTN) MaxAllocateType) { + return EFI_INVALID_PARAMETER; + } + + if ((MemoryType >= EfiMaxMemoryType && MemoryType <= 0x7fffffff) || + MemoryType == EfiConventionalMemory) { + return EFI_INVALID_PARAMETER; + } + + Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT; + + if (MemoryType == EfiACPIReclaimMemory || + MemoryType == EfiACPIMemoryNVS || + MemoryType == EfiRuntimeServicesCode || + MemoryType == EfiRuntimeServicesData) { + + Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT; + } + + if (Type == AllocateAddress) { + if ((*Memory & (Alignment - 1)) != 0) { + return EFI_NOT_FOUND; + } + } + + NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1; + NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1); + + // + // If this is for below a particular address, then + // + Start = *Memory; + + // + // The max address is the max natively addressable address for the processor + // + MaxAddress = EFI_MAX_ADDRESS; + + if (Type == AllocateMaxAddress) { + MaxAddress = Start; + } + + CoreAcquireMemoryLock (); + + // + // If not a specific address, then find an address to allocate + // + if (Type != AllocateAddress) { + Start = FindFreePages (MaxAddress, NumberOfPages, MemoryType, Alignment); + if (Start == 0) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + } + + // + // Convert pages from FreeMemory to the requested type + // + Status = CoreConvertPages (Start, NumberOfPages, MemoryType); + +Done: + CoreReleaseMemoryLock (); + + if (!EFI_ERROR (Status)) { + *Memory = Start; + } + + return Status; +} + + + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreFreePages ( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN NumberOfPages + ) +/*++ + +Routine Description: + + Frees previous allocated pages. + +Arguments: + + Memory - Base address of memory being freed + + NumberOfPages - The number of pages to free + +Returns: + + EFI_NOT_FOUND - Could not find the entry that covers the range + + EFI_INVALID_PARAMETER - Address not aligned + + EFI_SUCCESS -Pages successfully freed. + +--*/ +{ + EFI_STATUS Status; + EFI_LIST_ENTRY *Link; + MEMORY_MAP *Entry; + UINTN Alignment; + + // + // Free the range + // + CoreAcquireMemoryLock (); + + // + // Find the entry that the covers the range + // + Entry = NULL; + for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) { + Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE); + if (Entry->Start <= Memory && Entry->End > Memory) { + break; + } + } + if ((Link == &gMemoryMap) || (Entry == NULL)) { + Status = EFI_NOT_FOUND; + goto Done; + } + + Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT; + + if (Entry->Type == EfiACPIReclaimMemory || + Entry->Type == EfiACPIMemoryNVS || + Entry->Type == EfiRuntimeServicesCode || + Entry->Type == EfiRuntimeServicesData) { + + Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT; + + } + + if ((Memory & (Alignment - 1)) != 0) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1; + NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1); + + Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory); + + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Destroy the contents + // + if (Memory < EFI_MAX_ADDRESS) { + DEBUG_SET_MEMORY ((VOID *)(UINTN)Memory, NumberOfPages << EFI_PAGE_SHIFT); + } + + Done: + CoreReleaseMemoryLock (); + + return Status; +} + + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreGetMemoryMap ( + IN OUT UINTN *MemoryMapSize, + IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, + OUT UINTN *MapKey, + OUT UINTN *DescriptorSize, + OUT UINT32 *DescriptorVersion + ) +/*++ + +Routine Description: + + This function returns a copy of the current memory map. The map is an array of + memory descriptors, each of which describes a contiguous block of memory. + +Arguments: + + MemoryMapSize - A pointer to the size, in bytes, of the MemoryMap buffer. On + input, this is the size of the buffer allocated by the caller. + On output, it is the size of the buffer returned by the firmware + if the buffer was large enough, or the size of the buffer needed + to contain the map if the buffer was too small. + MemoryMap - A pointer to the buffer in which firmware places the current memory map. + MapKey - A pointer to the location in which firmware returns the key for the + current memory map. + DescriptorSize - A pointer to the location in which firmware returns the size, in + bytes, of an individual EFI_MEMORY_DESCRIPTOR. + DescriptorVersion - A pointer to the location in which firmware returns the version + number associated with the EFI_MEMORY_DESCRIPTOR. + +Returns: + + EFI_SUCCESS - The memory map was returned in the MemoryMap buffer. + EFI_BUFFER_TOO_SMALL - The MemoryMap buffer was too small. The current buffer size + needed to hold the memory map is returned in MemoryMapSize. + EFI_INVALID_PARAMETER - One of the parameters has an invalid value. + +--*/ +{ + EFI_STATUS Status; + UINTN Size; + UINTN BufferSize; + UINTN NumberOfRuntimeEntries; + EFI_LIST_ENTRY *Link; + MEMORY_MAP *Entry; + EFI_GCD_MAP_ENTRY *GcdMapEntry; + EFI_MEMORY_TYPE Type; + + // + // Make sure the parameters are valid + // + if (MemoryMapSize == NULL) { + return EFI_INVALID_PARAMETER; + } + + CoreAcquireGcdMemoryLock (); + + // + // Count the number of Reserved and MMIO entries that are marked for runtime use + // + NumberOfRuntimeEntries = 0; + for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) { + GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE); + if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) || + ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) && ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) { + NumberOfRuntimeEntries++; + } + } + + Size = sizeof (EFI_MEMORY_DESCRIPTOR); + + // + // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will + // prevent people from having pointer math bugs in their code. + // now you have to use *DescriptorSize to make things work. + // + Size += sizeof(UINT64) - (Size % sizeof (UINT64)); + + if (DescriptorSize != NULL) { + *DescriptorSize = Size; + } + + if (DescriptorVersion != NULL) { + *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION; + } + + CoreAcquireMemoryLock (); + + // + // Compute the buffer size needed to fit the entire map + // + BufferSize = Size * NumberOfRuntimeEntries; + for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) { + BufferSize += Size; + } + + if (*MemoryMapSize < BufferSize) { + Status = EFI_BUFFER_TOO_SMALL; + goto Done; + } + + if (MemoryMap == NULL) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + // + // Build the map + // + EfiCommonLibZeroMem (MemoryMap, BufferSize); + for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) { + Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE); + ASSERT (Entry->VirtualStart == 0); + + // + // Convert internal map into an EFI_MEMORY_DESCRIPTOR + // + MemoryMap->Type = Entry->Type; + MemoryMap->PhysicalStart = Entry->Start; + MemoryMap->VirtualStart = Entry->VirtualStart; + MemoryMap->NumberOfPages = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT); + // + // If the memory type is EfiConventionalMemory, then determine if the range is part of a + // memory type bin and needs to be converted to the same memory type as the rest of the + // memory type bin in order to minimize EFI Memory Map changes across reboots. This + // improves the chances for a successful S4 resume in the presence of minor page allocation + // differences across reboots. + // + if (MemoryMap->Type == EfiConventionalMemory) { + for (Type = (EFI_MEMORY_TYPE) 0; Type < EfiMaxMemoryType; Type++) { + if (mMemoryTypeStatistics[Type].Special && + mMemoryTypeStatistics[Type].NumberOfPages > 0 && + Entry->Start >= mMemoryTypeStatistics[Type].BaseAddress && + Entry->End <= mMemoryTypeStatistics[Type].MaximumAddress ) { + MemoryMap->Type = Type; + } + } + } + MemoryMap->Attribute = Entry->Attribute; + if (mMemoryTypeStatistics[MemoryMap->Type].Runtime) { + MemoryMap->Attribute |= EFI_MEMORY_RUNTIME; + } + + MemoryMap = NextMemoryDescriptor (MemoryMap, Size); + } + + for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) { + GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE); + if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) || + ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) && ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) { + + MemoryMap->PhysicalStart = GcdMapEntry->BaseAddress; + MemoryMap->VirtualStart = 0; + MemoryMap->NumberOfPages = RShiftU64 ((GcdMapEntry->EndAddress - GcdMapEntry->BaseAddress + 1), EFI_PAGE_SHIFT); + MemoryMap->Attribute = GcdMapEntry->Attributes & ~EFI_MEMORY_PORT_IO; + + if (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) { + MemoryMap->Type = EfiReservedMemoryType; + } else if (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) { + if ((GcdMapEntry->Attributes & EFI_MEMORY_PORT_IO) == EFI_MEMORY_PORT_IO) { + MemoryMap->Type = EfiMemoryMappedIOPortSpace; + } else { + MemoryMap->Type = EfiMemoryMappedIO; + } + } + + MemoryMap = NextMemoryDescriptor (MemoryMap, Size); + } + } + + Status = EFI_SUCCESS; + +Done: + + CoreReleaseMemoryLock (); + + CoreReleaseGcdMemoryLock (); + + // + // Update the map key finally + // + if (MapKey != NULL) { + *MapKey = mMemoryMapKey; + } + + *MemoryMapSize = BufferSize; + + return Status; +} + +VOID * +CoreAllocatePoolPages ( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN NumberOfPages, + IN UINTN Alignment + ) +/*++ + +Routine Description: + + Internal function. Used by the pool functions to allocate pages + to back pool allocation requests. + +Arguments: + + PoolType - The type of memory for the new pool pages + + NumberOfPages - No of pages to allocate + + Alignment - Bits to align. + +Returns: + + The allocated memory, or NULL + +--*/ +{ + EFI_STATUS Status; + UINT64 Start; + + // + // Find the pages to convert + // + Start = FindFreePages (EFI_MAX_ADDRESS, NumberOfPages, PoolType, Alignment); + + // + // Convert it to boot services data + // + if (Start == 0) { + DEBUG ((EFI_D_ERROR | EFI_D_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", NumberOfPages)); + } else { + Status = CoreConvertPages (Start, NumberOfPages, PoolType); + } + + return (VOID *)(UINTN)Start; +} + +VOID +CoreFreePoolPages ( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN NumberOfPages + ) +/*++ + +Routine Description: + + Internal function. Frees pool pages allocated via AllocatePoolPages () + +Arguments: + + Memory - The base address to free + + NumberOfPages - The number of pages to free + +Returns: + + None + +--*/ +{ + CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory); +} + + +EFI_STATUS +CoreTerminateMemoryMap ( + IN UINTN MapKey + ) +/*++ + +Routine Description: + + Make sure the memory map is following all the construction rules, + it is the last time to check memory map error before exit boot services. + +Arguments: + + MapKey - Memory map key + +Returns: + + EFI_INVALID_PARAMETER - Memory map not consistent with construction rules. + + EFI_SUCCESS - Valid memory map. + +--*/ +{ + EFI_STATUS Status; + EFI_LIST_ENTRY *Link; + MEMORY_MAP *Entry; + + Status = EFI_SUCCESS; + + CoreAcquireMemoryLock (); + + if (MapKey == mMemoryMapKey) { + + // + // Make sure the memory map is following all the construction rules + // This is the last chance we will be able to display any messages on + // the console devices. + // + + for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) { + Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE); + if (Entry->Attribute & EFI_MEMORY_RUNTIME) { + if (Entry->Type == EfiACPIReclaimMemory || Entry->Type == EfiACPIMemoryNVS) { + DEBUG((EFI_D_ERROR, "ExitBootServices: ACPI memory entry has RUNTIME attribute set.\n")); + CoreReleaseMemoryLock (); + return EFI_INVALID_PARAMETER; + } + if (Entry->Start & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) { + DEBUG((EFI_D_ERROR, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n")); + CoreReleaseMemoryLock (); + return EFI_INVALID_PARAMETER; + } + if ((Entry->End + 1) & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) { + DEBUG((EFI_D_ERROR, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n")); + CoreReleaseMemoryLock (); + return EFI_INVALID_PARAMETER; + } + } + } + + // + // The map key they gave us matches what we expect. Fall through and + // return success. In an ideal world we would clear out all of + // EfiBootServicesCode and EfiBootServicesData. However this function + // is not the last one called by ExitBootServices(), so we have to + // preserve the memory contents. + // + } else { + Status = EFI_INVALID_PARAMETER; + } + + CoreReleaseMemoryLock (); + + return Status; +} + + + + + + + + diff --git a/EDK/Foundation/Core/Dxe/Mem/imem.h b/EDK/Foundation/Core/Dxe/Mem/imem.h new file mode 100644 index 0000000..d9029c5 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/Mem/imem.h @@ -0,0 +1,214 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + imem.h + +Abstract: + + Head file to imem.h + + +Revision History + +--*/ + +#ifndef _IMEM_H_ +#define _IMEM_H_ + +#include "Tiano.h" +#include "DxeCore.h" +#include "Processor.h" + +// +// MEMORY_MAP_ENTRY +// + +#define MEMORY_MAP_SIGNATURE EFI_SIGNATURE_32('m','m','a','p') +typedef struct { + UINTN Signature; + EFI_LIST_ENTRY Link; + BOOLEAN FromPages; + + EFI_MEMORY_TYPE Type; + UINT64 Start; + UINT64 End; + + UINT64 VirtualStart; + UINT64 Attribute; +} MEMORY_MAP; + +// +// Internal prototypes +// + +VOID * +CoreAllocatePoolPages ( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN NumberOfPages, + IN UINTN Alignment + ) +/*++ + +Routine Description: + + Internal function. Used by the pool functions to allocate pages + to back pool allocation requests. + +Arguments: + + PoolType - The type of memory for the new pool pages + + NumberOfPages - No of pages to allocate + + Alignment - Bits to align. + +Returns: + + The allocated memory, or NULL + +--*/ +; + + +VOID +CoreFreePoolPages ( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN NumberOfPages + ) +/*++ + +Routine Description: + + Internal function. Frees pool pages allocated via AllocatePoolPages () + +Arguments: + + Memory - The base address to free + + NumberOfPages - The number of pages to free + +Returns: + + None + +--*/ +; + + +VOID * +CoreAllocatePoolI ( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN Size + ) +/*++ + +Routine Description: + + Internal function to allocate pool of a particular type. + + N.B. Caller must have the memory lock held + + +Arguments: + + PoolType - Type of pool to allocate + + Size - The amount of pool to allocate + +Returns: + + The allocate pool, or NULL + +--*/ +; + + +EFI_STATUS +CoreFreePoolI ( + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Internal function to free a pool entry. + + N.B. Caller must have the memory lock held + + +Arguments: + + Buffer - The allocated pool entry to free + +Returns: + + EFI_INVALID_PARAMETER - Buffer not valid + + EFI_SUCCESS - Buffer successfully freed. + +--*/ +; + + +VOID +CoreAcquireMemoryLock ( + VOID + ) +/*++ + +Routine Description: + + Enter critical section by gaining lock on gMemoryLock + +Arguments: + + None + +Returns: + + None + +--*/ +; + +VOID +CoreReleaseMemoryLock ( + VOID + ) +/*++ + +Routine Description: + + Exit critical section by releasing lock on gMemoryLock + +Arguments: + + None + +Returns: + + None + +--*/ +; + + +// +// Internal Global data +// + +extern EFI_LOCK gMemoryLock; +extern EFI_LIST_ENTRY gMemoryMap; +extern MEMORY_MAP *gMemoryLastConvert; +extern EFI_LIST_ENTRY mGcdMemorySpaceMap; +#endif diff --git a/EDK/Foundation/Core/Dxe/Mem/memdata.c b/EDK/Foundation/Core/Dxe/Mem/memdata.c new file mode 100644 index 0000000..580b0bd --- /dev/null +++ b/EDK/Foundation/Core/Dxe/Mem/memdata.c @@ -0,0 +1,41 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + memdata.c + +Abstract: + + Global data used in memory service + + +Revision History + +--*/ + +#include "imem.h" + + +// +// MemoryLock - synchronizes access to the memory map and pool lists +// +EFI_LOCK gMemoryLock = EFI_INITIALIZE_LOCK_VARIABLE (EFI_TPL_NOTIFY); + +// +// MemoryMap - the current memory map +// +EFI_LIST_ENTRY gMemoryMap = INITIALIZE_LIST_HEAD_VARIABLE (gMemoryMap); + +// +// MemoryLastConvert - the last memory descriptor used for a conversion request +// +MEMORY_MAP *gMemoryLastConvert; diff --git a/EDK/Foundation/Core/Dxe/Mem/pool.c b/EDK/Foundation/Core/Dxe/Mem/pool.c new file mode 100644 index 0000000..a13d94d --- /dev/null +++ b/EDK/Foundation/Core/Dxe/Mem/pool.c @@ -0,0 +1,613 @@ +/*++ + +Copyright (c) 2004 - 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + pool.c + +Abstract: + + EFI Memory pool management + +Revision History + +--*/ + +#include "imem.h" + +#define POOL_FREE_SIGNATURE EFI_SIGNATURE_32('p','f','r','0') +typedef struct { + UINT32 Signature; + UINT32 Index; + EFI_LIST_ENTRY Link; +} POOL_FREE; + + +#define POOL_HEAD_SIGNATURE EFI_SIGNATURE_32('p','h','d','0') +typedef struct { + UINT32 Signature; + UINT32 Size; + EFI_MEMORY_TYPE Type; + UINTN Reserved; + CHAR8 Data[1]; +} POOL_HEAD; + +#define SIZE_OF_POOL_HEAD EFI_FIELD_OFFSET(POOL_HEAD,Data) + +#define POOL_TAIL_SIGNATURE EFI_SIGNATURE_32('p','t','a','l') +typedef struct { + UINT32 Signature; + UINT32 Size; +} POOL_TAIL; + + +#define POOL_SHIFT 7 + +#define POOL_OVERHEAD (SIZE_OF_POOL_HEAD + sizeof(POOL_TAIL)) + +#define HEAD_TO_TAIL(a) \ + ((POOL_TAIL *) (((CHAR8 *) (a)) + (a)->Size - sizeof(POOL_TAIL))); + + +#define SIZE_TO_LIST(a) ((a) >> POOL_SHIFT) +#define LIST_TO_SIZE(a) ((a+1) << POOL_SHIFT) + +#define MAX_POOL_LIST SIZE_TO_LIST(DEFAULT_PAGE_ALLOCATION) +#define MAX_POOL_SIZE (EFI_MAX_ADDRESS - POOL_OVERHEAD) + +// +// Globals +// + +#define POOL_SIGNATURE EFI_SIGNATURE_32('p','l','s','t') +typedef struct { + INTN Signature; + UINTN Used; + EFI_MEMORY_TYPE MemoryType; + EFI_LIST_ENTRY FreeList[MAX_POOL_LIST]; + EFI_LIST_ENTRY Link; +} POOL; + + +POOL PoolHead[EfiMaxMemoryType]; +EFI_LIST_ENTRY PoolHeadList; + +// +// +// + +VOID +CoreInitializePool ( + VOID + ) +/*++ + +Routine Description: + + Called to initialize the pool. + +Arguments: + + None + +Returns: + + None + +--*/ +{ + UINTN Type; + UINTN Index; + + for (Type=0; Type < EfiMaxMemoryType; Type++) { + PoolHead[Type].Signature = 0; + PoolHead[Type].Used = 0; + PoolHead[Type].MemoryType = Type; + for (Index=0; Index < MAX_POOL_LIST; Index++) { + InitializeListHead (&PoolHead[Type].FreeList[Index]); + } + } + InitializeListHead (&PoolHeadList); +} + + +POOL * +LookupPoolHead ( + IN EFI_MEMORY_TYPE MemoryType + ) +/*++ + +Routine Description: + + Look up pool head for specified memory type. + +Arguments: + + MemoryType - Memory type of which pool head is looked for + +Returns: + + Pointer of Corresponding pool head. + +--*/ +{ + EFI_LIST_ENTRY *Link; + POOL *Pool; + UINTN Index; + + if (MemoryType >= 0 && MemoryType < EfiMaxMemoryType) { + return &PoolHead[MemoryType]; + } + + if (MemoryType < 0) { + + for (Link = PoolHeadList.ForwardLink; Link != &PoolHeadList; Link = Link->ForwardLink) { + Pool = CR(Link, POOL, Link, POOL_SIGNATURE); + if (Pool->MemoryType == MemoryType) { + return Pool; + } + } + + Pool = CoreAllocatePoolI (EfiBootServicesData, sizeof (POOL)); + if (Pool == NULL) { + return NULL; + } + + Pool->Signature = POOL_SIGNATURE; + Pool->Used = 0; + Pool->MemoryType = MemoryType; + for (Index=0; Index < MAX_POOL_LIST; Index++) { + InitializeListHead (&Pool->FreeList[Index]); + } + + InsertHeadList (&PoolHeadList, &Pool->Link); + + return Pool; + } + + return NULL; +} + + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreAllocatePool ( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN Size, + OUT VOID **Buffer + ) +/*++ + +Routine Description: + + Allocate pool of a particular type. + +Arguments: + + PoolType - Type of pool to allocate + + Size - The amount of pool to allocate + + Buffer - The address to return a pointer to the allocated pool + +Returns: + + EFI_INVALID_PARAMETER - PoolType not valid + + EFI_OUT_OF_RESOURCES - Size exceeds max pool size or allocation failed. + + EFI_SUCCESS - Pool successfully allocated. + +--*/ +{ + EFI_STATUS Status; + + // + // If it's not a valid type, fail it + // + if ((PoolType >= EfiMaxMemoryType && PoolType <= 0x7fffffff) || + PoolType == EfiConventionalMemory) { + return EFI_INVALID_PARAMETER; + } + + *Buffer = NULL; + // + // As we need to reserve memory for other resources, we can't expect to allocate + // all memory( EFI_MAX_ADDRESS - POOL_OVERHEAD + 1) using this function, + // the following check operation is only used to make sure the allocated pool size will + // not rool over from a very large number to a very small number. + // + if (Size > MAX_POOL_SIZE) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Acquire the memory lock and make the allocation + // + Status = CoreAcquireLockOrFail (&gMemoryLock); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + *Buffer = CoreAllocatePoolI (PoolType, Size); + CoreReleaseMemoryLock (); + return (*Buffer != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES; +} + + +VOID * +CoreAllocatePoolI ( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN Size + ) +/*++ + +Routine Description: + + Internal function to allocate pool of a particular type. + + N.B. Caller must have the memory lock held + + +Arguments: + + PoolType - Type of pool to allocate + + Size - The amount of pool to allocate + +Returns: + + The allocate pool, or NULL + +--*/ +{ + POOL *Pool; + POOL_FREE *Free; + POOL_HEAD *Head; + POOL_TAIL *Tail; + CHAR8 *NewPage; + VOID *Buffer; + UINTN Index; + UINTN FSize; + UINTN offset; + UINTN Adjustment; + UINTN NoPages; + + ASSERT_LOCKED (&gMemoryLock); + + // + // Adjust the size by the pool header & tail overhead + // + + // + // Adjusting the Size to be of proper alignment so that + // we don't get an unaligned access fault later when + // pool_Tail is being initialized + // + ALIGN_VARIABLE (Size, Adjustment); + + Size += POOL_OVERHEAD; + Index = SIZE_TO_LIST(Size); + Pool = LookupPoolHead (PoolType); + if (Pool== NULL) { + return NULL; + } + Head = NULL; + + // + // If allocation is over max size, just allocate pages for the request + // (slow) + // + if (Index >= MAX_POOL_LIST) { + NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1; + NoPages &= ~(EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1); + Head = CoreAllocatePoolPages (PoolType, NoPages, DEFAULT_PAGE_ALLOCATION); + goto Done; + } + + // + // If there's no free pool in the proper list size, go get some more pages + // + if (IsListEmpty (&Pool->FreeList[Index])) { + + // + // Get another page + // + NewPage = CoreAllocatePoolPages(PoolType, EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION), DEFAULT_PAGE_ALLOCATION); + if (NewPage == NULL) { + goto Done; + } + + // + // Carve up new page into free pool blocks + // + offset = 0; + while (offset < DEFAULT_PAGE_ALLOCATION) { + ASSERT (Index < MAX_POOL_LIST); + FSize = LIST_TO_SIZE(Index); + + while (offset + FSize <= DEFAULT_PAGE_ALLOCATION) { + Free = (POOL_FREE *) &NewPage[offset]; + Free->Signature = POOL_FREE_SIGNATURE; + Free->Index = (UINT32)Index; + InsertHeadList (&Pool->FreeList[Index], &Free->Link); + offset += FSize; + } + + Index -= 1; + } + + ASSERT (offset == DEFAULT_PAGE_ALLOCATION); + Index = SIZE_TO_LIST(Size); + } + + // + // Remove entry from free pool list + // + Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE); + RemoveEntryList (&Free->Link); + + Head = (POOL_HEAD *) Free; + +Done: + Buffer = NULL; + + if (Head != NULL) { + + // + // If we have a pool buffer, fill in the header & tail info + // + Head->Signature = POOL_HEAD_SIGNATURE; + Head->Size = (UINT32) Size; + Head->Type = (EFI_MEMORY_TYPE) PoolType; + Tail = HEAD_TO_TAIL (Head); + Tail->Signature = POOL_TAIL_SIGNATURE; + Tail->Size = (UINT32) Size; + Buffer = Head->Data; + DEBUG_SET_MEMORY (Buffer, Size - POOL_OVERHEAD); + + DEBUG ( + (EFI_D_POOL, + "AllcocatePoolI: Type %x, Addr %x (len %x) %,d\n", + (UINTN)PoolType, + Buffer, + Size - POOL_OVERHEAD, + Pool->Used) + ); + + // + // Account the allocation + // + Pool->Used += Size; + + } else { + DEBUG ((EFI_D_ERROR | EFI_D_POOL, "AllocatePool: failed to allocate %d bytes\n", Size)); + } + + return Buffer; +} + + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreFreePool ( + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Frees pool. + +Arguments: + + Buffer - The allocated pool entry to free + +Returns: + + EFI_INVALID_PARAMETER - Buffer is not a valid value. + + EFI_SUCCESS - Pool successfully freed. + +--*/ +{ + EFI_STATUS Status; + + if (NULL == Buffer) { + return EFI_INVALID_PARAMETER; + } + + CoreAcquireMemoryLock (); + Status = CoreFreePoolI (Buffer); + CoreReleaseMemoryLock (); + return Status; +} + + +EFI_STATUS +CoreFreePoolI ( + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Internal function to free a pool entry. + + N.B. Caller must have the memory lock held + + +Arguments: + + Buffer - The allocated pool entry to free + +Returns: + + EFI_INVALID_PARAMETER - Buffer not valid + + EFI_SUCCESS - Buffer successfully freed. + +--*/ +{ + POOL *Pool; + POOL_HEAD *Head; + POOL_TAIL *Tail; + POOL_FREE *Free; + UINTN Index; + UINTN NoPages; + UINTN Size; + CHAR8 *NewPage; + UINTN FSize; + UINTN offset; + BOOLEAN AllFree; + + ASSERT(NULL != Buffer); + // + // Get the head & tail of the pool entry + // + Head = CR (Buffer, POOL_HEAD, Data, POOL_HEAD_SIGNATURE); + ASSERT(NULL != Head); + + if (Head->Signature != POOL_HEAD_SIGNATURE) { + return EFI_INVALID_PARAMETER; + } + + Tail = HEAD_TO_TAIL (Head); + ASSERT(NULL != Tail); + + // + // Debug + // + ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE); + ASSERT (Head->Size == Tail->Size); + ASSERT_LOCKED (&gMemoryLock); + + if (Tail->Signature != POOL_TAIL_SIGNATURE) { + return EFI_INVALID_PARAMETER; + } + + if (Head->Size != Tail->Size) { + return EFI_INVALID_PARAMETER; + } + + // + // Determine the pool type and account for it + // + Size = Head->Size; + Pool = LookupPoolHead (Head->Type); + if (Pool == NULL) { + return EFI_INVALID_PARAMETER; + } + Pool->Used -= Size; + DEBUG ((EFI_D_POOL, "FreePool: %x (len %x) %,d\n", Head->Data, (UINTN)Head->Size - POOL_OVERHEAD, Pool->Used)); + + // + // Determine the pool list + // + Index = SIZE_TO_LIST(Size); + DEBUG_SET_MEMORY (Head, Size); + + // + // If it's not on the list, it must be pool pages + // + if (Index >= MAX_POOL_LIST) { + + // + // Return the memory pages back to free memory + // + NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1; + NoPages &= ~(EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1); + CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN) Head, NoPages); + + } else { + + // + // Put the pool entry onto the free pool list + // + Free = (POOL_FREE *) Head; + ASSERT(NULL != Free); + Free->Signature = POOL_FREE_SIGNATURE; + Free->Index = (UINT32)Index; + InsertHeadList (&Pool->FreeList[Index], &Free->Link); + + // + // See if all the pool entries in the same page as Free are freed pool + // entries + // + NewPage = (CHAR8 *)((UINTN)Free & ~((DEFAULT_PAGE_ALLOCATION) -1)); + Free = (POOL_FREE *) &NewPage[0]; + ASSERT(NULL != Free); + + if (Free->Signature == POOL_FREE_SIGNATURE) { + + Index = Free->Index; + + AllFree = TRUE; + offset = 0; + + while ((offset < DEFAULT_PAGE_ALLOCATION) && (AllFree)) { + FSize = LIST_TO_SIZE(Index); + while (offset + FSize <= DEFAULT_PAGE_ALLOCATION) { + Free = (POOL_FREE *) &NewPage[offset]; + ASSERT(NULL != Free); + if (Free->Signature != POOL_FREE_SIGNATURE) { + AllFree = FALSE; + } + offset += FSize; + } + Index -= 1; + } + + if (AllFree) { + + // + // All of the pool entries in the same page as Free are free pool + // entries + // Remove all of these pool entries from the free loop lists. + // + Free = (POOL_FREE *) &NewPage[0]; + ASSERT(NULL != Free); + Index = Free->Index; + offset = 0; + + while (offset < DEFAULT_PAGE_ALLOCATION) { + FSize = LIST_TO_SIZE(Index); + while (offset + FSize <= DEFAULT_PAGE_ALLOCATION) { + Free = (POOL_FREE *) &NewPage[offset]; + ASSERT(NULL != Free); + RemoveEntryList (&Free->Link); + offset += FSize; + } + Index -= 1; + } + + // + // Free the page + // + CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN)NewPage, EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION)); + } + } + } + + // + // If this is an OS specific memory type, then check to see if the last + // portion of that memory type has been freed. If it has, then free the + // list entry for that memory type + // + if (Pool->MemoryType < 0 && Pool->Used == 0) { + RemoveEntryList (&Pool->Link); + CoreFreePoolI (Pool); + } + + return EFI_SUCCESS; +} diff --git a/EDK/Foundation/Core/Dxe/Misc/DebugImageInfo.c b/EDK/Foundation/Core/Dxe/Misc/DebugImageInfo.c new file mode 100644 index 0000000..c1a81a3 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/Misc/DebugImageInfo.c @@ -0,0 +1,262 @@ +/*++ + +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DebugImageInfo.c + +Abstract: + + Support functions for managing debug image info table when loading and unloading + images. + +--*/ + +#include "Tiano.h" +#include "DxeCore.h" +#include "DebugImageInfo.h" + + +static EFI_DEBUG_IMAGE_INFO_TABLE_HEADER mDebugInfoTableHeader = { + 0, // volatile UINT32 UpdateStatus; + 0, // UINT32 TableSize; + NULL // EFI_DEBUG_IMAGE_INFO *EfiDebugImageInfoTable; +}; + +static EFI_SYSTEM_TABLE_POINTER *mDebugTable = NULL; + + +VOID +CoreInitializeDebugImageInfoTable ( + VOID + ) +/*++ + +Routine Description: + + Creates and initializes the DebugImageInfo Table. Also creates the configuration + table and registers it into the system table. + +Arguments: + None + +Returns: + NA + +Notes: + This function allocates memory, frees it, and then allocates memory at an + address within the initial allocation. Since this function is called early + in DXE core initialization (before drivers are dispatched), this should not + be a problem. + +--*/ +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS Mem; + UINTN NumberOfPages; + + // + // Allocate boot services memory for the structure. It's required to be aligned on + // a 4M boundary, so allocate a 4M block (plus what we require), free it up, calculate + // a 4M aligned address within the memory we just freed, and then allocate memory at that + // address for our initial structure. + // + NumberOfPages = FOUR_MEG_PAGES + EFI_SIZE_TO_PAGES(sizeof (EFI_SYSTEM_TABLE_POINTER)); + + Status = CoreAllocatePages (AllocateAnyPages, EfiBootServicesData, NumberOfPages , &Mem); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR(Status)) { + return; + } + Status = CoreFreePages (Mem, NumberOfPages); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR(Status)) { + return; + } + // + // Now get a 4M aligned address within the memory range we were given. + // Then allocate memory at that address + // + Mem = (Mem + FOUR_MEG_MASK) & (~FOUR_MEG_MASK); + + Status = CoreAllocatePages (AllocateAddress, EfiBootServicesData, NumberOfPages - FOUR_MEG_PAGES, &Mem); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR(Status)) { + return; + } + // + // We now have a 4M aligned page allocated, so fill in the data structure. + // Ideally we would update the CRC now as well, but the service may not yet be available. + // See comments in the CoreUpdateDebugTableCrc32() function below for details. + // + mDebugTable = (EFI_SYSTEM_TABLE_POINTER *)(UINTN)Mem; + mDebugTable->Signature = EFI_SYSTEM_TABLE_SIGNATURE; + mDebugTable->EfiSystemTableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) gST; + mDebugTable->Crc32 = 0; + Status = CoreInstallConfigurationTable (&gEfiDebugImageInfoTableGuid, &mDebugInfoTableHeader); + ASSERT_EFI_ERROR (Status); +} + +VOID +CoreUpdateDebugTableCrc32 ( + VOID + ) +/*++ + +Routine Description: + + Update the CRC32 in the Debug Table. + Since the CRC32 service is made available by the Runtime driver, we have to + wait for the Runtime Driver to be installed before the CRC32 can be computed. + This function is called elsewhere by the core when the runtime architectural + protocol is produced. + +Arguments: + None + +Returns: + NA + +--*/ +{ + ASSERT(mDebugTable != NULL); + mDebugTable->Crc32 = 0; + gBS->CalculateCrc32 ((VOID *)mDebugTable, sizeof (EFI_SYSTEM_TABLE_POINTER), &mDebugTable->Crc32); +} + +VOID +CoreNewDebugImageInfoEntry ( + IN UINT32 ImageInfoType, + IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage, + IN EFI_HANDLE ImageHandle + ) +/*++ + +Routine Description: + + Adds a new DebugImageInfo structure to the DebugImageInfo Table. Re-Allocates + the table if it's not large enough to accomidate another entry. + +Arguments: + + ImageInfoType - type of debug image information + LoadedImage - pointer to the loaded image protocol for the image being loaded + ImageHandle - image handle for the image being loaded + +Returns: + NA + +--*/ +{ + EFI_DEBUG_IMAGE_INFO *Table; + EFI_DEBUG_IMAGE_INFO *NewTable; + UINTN Index; + UINTN MaxTableIndex; + UINTN TableSize; + + // + // Set the flag indicating that we're in the process of updating the table. + // + mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS; + + Table = mDebugInfoTableHeader.EfiDebugImageInfoTable; + MaxTableIndex = mDebugInfoTableHeader.TableSize; + + for (Index = 0; Index < MaxTableIndex; Index++) { + if (Table[Index].NormalImage == NULL) { + // + // We have found a free entry so exit the loop + // + break; + } + } + if (Index == MaxTableIndex) { + // + // Table is full, so re-allocate another page for a larger table... + // + TableSize = MaxTableIndex * EFI_DEBUG_TABLE_ENTRY_SIZE; + NewTable = CoreAllocateZeroBootServicesPool (TableSize + EFI_PAGE_SIZE); + if (NewTable == NULL) { + mDebugInfoTableHeader.UpdateStatus &= ~EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS; + return; + } + // + // Copy the old table into the new one + // + EfiCommonLibCopyMem (NewTable, Table, TableSize); + // + // Free the old table + // + CoreFreePool (Table); + // + // Update the table header + // + Table = NewTable; + mDebugInfoTableHeader.EfiDebugImageInfoTable = NewTable; + mDebugInfoTableHeader.TableSize += EFI_PAGE_SIZE / EFI_DEBUG_TABLE_ENTRY_SIZE; + } + // + // Allocate data for new entry + // + Table[Index].NormalImage = CoreAllocateZeroBootServicesPool (sizeof (EFI_DEBUG_IMAGE_INFO_NORMAL)); + if (Table[Index].NormalImage != NULL) { + // + // Update the entry + // + Table[Index].NormalImage->ImageInfoType = ImageInfoType; + Table[Index].NormalImage->LoadedImageProtocolInstance = LoadedImage; + Table[Index].NormalImage->ImageHandle = ImageHandle; + } + mDebugInfoTableHeader.UpdateStatus &= ~EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS; +} + + +VOID +CoreRemoveDebugImageInfoEntry ( + EFI_HANDLE ImageHandle + ) +/*++ + +Routine Description: + + Removes and frees an entry from the DebugImageInfo Table. + +Arguments: + + ImageHandle - image handle for the image being unloaded + +Returns: + + NA + +--*/ +{ + EFI_DEBUG_IMAGE_INFO *Table; + UINTN Index; + + mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS; + + Table = mDebugInfoTableHeader.EfiDebugImageInfoTable; + + for (Index = 0; Index < mDebugInfoTableHeader.TableSize; Index++) { + if (Table[Index].NormalImage != NULL && Table[Index].NormalImage->ImageHandle == ImageHandle) { + // + // Found a match. Free up the record, then NULL the pointer to indicate the slot + // is free. + // + CoreFreePool (Table[Index].NormalImage); + Table[Index].NormalImage = NULL; + break; + } + } + mDebugInfoTableHeader.UpdateStatus &= ~EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS; +} + diff --git a/EDK/Foundation/Core/Dxe/Misc/DebugImageInfo.h b/EDK/Foundation/Core/Dxe/Misc/DebugImageInfo.h new file mode 100644 index 0000000..a4e86e7 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/Misc/DebugImageInfo.h @@ -0,0 +1,129 @@ +/*++ + +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DebugImageInfo.h + +Abstract: + + Support functions for managing debug image info table when loading and unloading + images. + +--*/ + +#ifndef __DEBUG_IMAGE_INFO_H__ +#define __DEBUG_IMAGE_INFO_H__ + +#include EFI_PROTOCOL_DEFINITION(LoadedImage) +#include EFI_GUID_DEFINITION(DebugImageInfoTable) + +#define FOUR_MEG_PAGES 0x400 +#define FOUR_MEG_MASK ((FOUR_MEG_PAGES * EFI_PAGE_SIZE) - 1) + +#define EFI_DEBUG_TABLE_ENTRY_SIZE (sizeof (VOID *)) + +VOID +CoreInitializeDebugImageInfoTable ( + VOID + ) +/*++ + +Routine Description: + + Creates and initializes the DebugImageInfo Table. Also creates the configuration + table and registers it into the system table. + +Arguments: + None + +Returns: + NA + +Notes: + This function allocates memory, frees it, and then allocates memory at an + address within the initial allocation. Since this function is called early + in DXE core initialization (before drivers are dispatched), this should not + be a problem. + +--*/ +; + +VOID +CoreUpdateDebugTableCrc32 ( + VOID + ) +/*++ + +Routine Description: + + Update the CRC32 in the Debug Table. + Since the CRC32 service is made available by the Runtime driver, we have to + wait for the Runtime Driver to be installed before the CRC32 can be computed. + This function is called elsewhere by the core when the runtime architectural + protocol is produced. + +Arguments: + None + +Returns: + NA + +--*/ +; + +VOID +CoreNewDebugImageInfoEntry ( + UINT32 ImageInfoType, + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage, + EFI_HANDLE ImageHandle + ) +/*++ + +Routine Description: + + Adds a new DebugImageInfo structure to the DebugImageInfo Table. Re-Allocates + the table if it's not large enough to accomidate another entry. + +Arguments: + + ImageInfoType - type of debug image information + LoadedImage - pointer to the loaded image protocol for the image being loaded + ImageHandle - image handle for the image being loaded + +Returns: + NA + +--*/ +; + +VOID +CoreRemoveDebugImageInfoEntry ( + EFI_HANDLE ImageHandle + ) +/*++ + +Routine Description: + + Removes and frees an entry from the DebugImageInfo Table. + +Arguments: + + ImageHandle - image handle for the image being unloaded + +Returns: + + NA + +--*/ +; + +#endif diff --git a/EDK/Foundation/Core/Dxe/Misc/DebugMask.c b/EDK/Foundation/Core/Dxe/Misc/DebugMask.c new file mode 100644 index 0000000..c2dee47 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/Misc/DebugMask.c @@ -0,0 +1,400 @@ +/*++ + +Copyright (c) 2004 - 2005, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DebugMask.c + +Abstract: + + +--*/ + +#include "Tiano.h" +#include "DxeCore.h" +#include "DebugMask.h" +#include EFI_GUID_DEFINITION (GlobalVariable) + +extern UINTN mErrorLevel; +static VOID *mVariableReadyNotify; + +VOID +UpdateDebugMask ( + EFI_EVENT Event, + VOID *Context + ); + +EFI_STATUS +EFIAPI +GetDebugMask ( + IN EFI_DEBUG_MASK_PROTOCOL *This, // Calling context + IN OUT UINTN *CurrentDebugMask // Ptr to store current debug mask + ) +/*++ + +Routine Description: + DebugMask protocol member function. + Gets the current debug mask for an image, on which this protocol has been installed. + +Arguments: + + This - Indicates calling context + CurrentDebugMask - Ptr to store current debug mask + +Returns: + EFI_SUCCESS - Debug mask is retrieved successfully + EFI_INVALID_PARAMETER - CurrentDebugMask is NULL. + EFI_UNSUPPORTED - The handle on which this protocol is installed is not an image handle. + +--*/ +{ + DEBUG_MASK_PRIVATE_DATA *Private; + // + // Check Parameter + // + if (CurrentDebugMask == NULL){ + return EFI_INVALID_PARAMETER; + } + + // + // Get Private Data + // + Private = DEBUG_MASK_PRIVATE_DATA_FROM_THIS(This); + *CurrentDebugMask = Private->ImageDebugMask; + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +SetDebugMask ( + IN EFI_DEBUG_MASK_PROTOCOL *This, // Calling context + IN UINTN NewDebugMask // New Debug Mask value to set + ) +/*++ + +Routine Description: + DebugMask protocol member function. + Updates the current debug mask for an image, on which this protocol has been installed. + +Arguments: + + This - Calling context + NewDebugMask - New Debug Mask value to set + +Returns: + EFI_SUCCESS - Debug mask is updated with the new value successfully + EFI_UNSUPPORTED - The handle on which this protocol is installed is not an image handle. + +--*/ +{ + DEBUG_MASK_PRIVATE_DATA *Private; + // + // Set Private Data + // + Private = DEBUG_MASK_PRIVATE_DATA_FROM_THIS(This); + Private->ImageDebugMask = NewDebugMask; + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +SetCoreDebugMask ( + IN EFI_DEBUG_MASK_PROTOCOL *This, // Calling context + IN UINTN NewDebugMask // New Debug Mask value to set + ) +/*++ + +Routine Description: + DebugMask protocol member function. + Updates the current debug mask for core. + +Arguments: + + This - Calling context + NewDebugMask - New Debug Mask value to set + +Returns: + EFI_SUCCESS - Debug mask is updated with the new value successfully + EFI_UNSUPPORTED - The handle on which this protocol is installed is not an image handle. + +--*/ +{ + mErrorLevel = NewDebugMask; + return SetDebugMask(This, NewDebugMask); +} + +EFI_STATUS +InstallDebugMaskProtocol( + IN EFI_HANDLE ImageHandle + ) +/*++ + +Routine Description: + + Install debug mask protocol on an image handle. + +Arguments: + + ImageHandle - Image handle which debug mask protocol will install on + +Returns: + + EFI_INVALID_PARAMETER - Invalid image handle + + EFI_OUT_OF_RESOURCES - No enough buffer could be allocated + + EFI_SUCCESS - Debug mask protocol successfully installed + +--*/ +{ + EFI_STATUS Status; + EFI_LOADED_IMAGE_PROTOCOL *LoadImageInterface; + DEBUG_MASK_PRIVATE_DATA *DebugMaskPrivate; + + if (ImageHandle == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Check Image Handle + // + Status = CoreHandleProtocol ( + ImageHandle, + &gEfiLoadedImageProtocolGuid, + (VOID*)&LoadImageInterface + ); + + if (EFI_ERROR (Status)) { + return EFI_INVALID_PARAMETER; + } + // + // Create Pool for Private Data + // + DebugMaskPrivate = CoreAllocateZeroBootServicesPool (sizeof (DEBUG_MASK_PRIVATE_DATA)); + + if (DebugMaskPrivate == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Fill in private data structure + // + DebugMaskPrivate->Signature = DEBUGMASK_PRIVATE_DATA_SIGNATURE; + DebugMaskPrivate->ImageDebugMask = mErrorLevel; + DebugMaskPrivate->DebugMaskInterface.Revision = EFI_DEBUG_MASK_REVISION; + DebugMaskPrivate->DebugMaskInterface.GetDebugMask = GetDebugMask; + DebugMaskPrivate->DebugMaskInterface.SetDebugMask = SetDebugMask; + // + // Install Debug Mask Protocol in Image Handle + // + Status = CoreInstallProtocolInterface ( + &ImageHandle, + &gEfiDebugMaskProtocolGuid, + EFI_NATIVE_INTERFACE, + &(DebugMaskPrivate->DebugMaskInterface) + ); + + return Status; +} + +EFI_STATUS +UninstallDebugMaskProtocol( + IN EFI_HANDLE ImageHandle + ) +/*++ + +Routine Description: + + Uninstall debug mask protocol on an image handle. + +Arguments: + + ImageHandle - Image handle which debug mask protocol will uninstall on + +Returns: + + EFI_INVALID_PARAMETER - Invalid image handle + + EFI_SUCCESS - Debug mask protocol successfully uninstalled + +--*/ +{ + EFI_STATUS Status; + EFI_DEBUG_MASK_PROTOCOL *DebugMaskInterface; + DEBUG_MASK_PRIVATE_DATA *DebugMaskPrivate; + + if (ImageHandle == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Get Protocol from ImageHandle + // + Status = CoreHandleProtocol ( + ImageHandle, + &gEfiDebugMaskProtocolGuid, + (VOID*)&DebugMaskInterface + ); + if (EFI_ERROR (Status)) { + return Status; + } + + DebugMaskPrivate = DEBUG_MASK_PRIVATE_DATA_FROM_THIS(DebugMaskInterface); + // + // Remove Protocol from ImageHandle + // + Status = CoreUninstallProtocolInterface ( + ImageHandle, + &gEfiDebugMaskProtocolGuid, + (VOID*)DebugMaskInterface + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Free Private Data Pool + // + Status = CoreFreePool(DebugMaskPrivate); + return Status; +} + +EFI_STATUS +InstallCoreDebugMaskProtocol( + IN EFI_HANDLE ImageHandle + ) +/*++ + +Routine Description: + + Install debug mask protocol on core. + +Arguments: + + ImageHandle - Core handle + +Returns: + + EFI_INVALID_PARAMETER - Invalid image handle + + EFI_OUT_OF_RESOURCES - No enough buffer could be allocated + + EFI_SUCCESS - Debug mask protocol successfully installed + +--*/ +{ + EFI_DEBUG_MASK_PROTOCOL *DebugMaskInterface; + EFI_STATUS Status; + EFI_EVENT Event; + + if (ImageHandle == NULL) { + return EFI_INVALID_PARAMETER; + } + + Status = InstallDebugMaskProtocol(ImageHandle); + if (EFI_ERROR(Status)) { + return Status; + } + + // + // Check Image Handle + // + Status = CoreHandleProtocol ( + ImageHandle, + &gEfiDebugMaskProtocolGuid, + (VOID*)&DebugMaskInterface + ); + if (EFI_ERROR(Status) || (DebugMaskInterface == NULL)) { + return Status; + } + DebugMaskInterface->SetDebugMask = SetCoreDebugMask; + + Status = CoreCreateEvent ( + EFI_EVENT_NOTIFY_SIGNAL, + EFI_TPL_CALLBACK, + UpdateDebugMask, + mVariableReadyNotify, + &Event + ); + + if (!EFI_ERROR (Status)) { + Status = CoreRegisterProtocolNotify ( + &gEfiVariableArchProtocolGuid, + Event, + &mVariableReadyNotify + ); + } + + return Status; +} + +VOID +UpdateDebugMask ( + EFI_EVENT Event, + VOID *Context + ) +/*++ + +Routine Description: + + Event callback function to update the debug mask when the variable service is ready. + +Arguments: + + Event - The Event + Context - The event's context + +Returns: + + None + +--*/ +{ + UINTN NoHandles; + EFI_STATUS Status; + UINTN DebugMask; + UINTN Index; + UINTN DataSize; + EFI_HANDLE *Buffer; + EFI_DEBUG_MASK_PROTOCOL *DebugMaskProtocol; + + DataSize = sizeof(UINT32); + Status = gRT->GetVariable( + L"EFIDebug", + &gEfiGlobalVariableGuid, + NULL, + &DataSize, + &DebugMask + ); + if (EFI_ERROR(Status)) { + return; + } + + Status = CoreLocateHandleBuffer ( + AllHandles, + &gEfiDebugMaskProtocolGuid, + NULL, + &NoHandles, + &Buffer + ); + if (EFI_ERROR(Status)) { + return; + } + for (Index = 0; Index < NoHandles; Index ++) { + Status = CoreHandleProtocol ( + Buffer[Index], + &gEfiDebugMaskProtocolGuid, + &DebugMaskProtocol + ); + if (EFI_ERROR(Status) || (DebugMaskProtocol == NULL)) { + continue; + } + DebugMaskProtocol->SetDebugMask(DebugMaskProtocol, DebugMask); + } + CoreFreePool(Buffer); +} diff --git a/EDK/Foundation/Core/Dxe/Misc/DebugMask.h b/EDK/Foundation/Core/Dxe/Misc/DebugMask.h new file mode 100644 index 0000000..18dbef5 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/Misc/DebugMask.h @@ -0,0 +1,122 @@ +/*++ + +Copyright (c) 2004 - 2005, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DebugMask.h + +Abstract: + + +--*/ + +#ifndef __DEBUG_MASK_INFO_H__ +#define __DEBUG_MASK_INFO_H__ + +#include EFI_PROTOCOL_CONSUMER (DebugMask) + +// +// local type definitions +// +#define DEBUGMASK_PRIVATE_DATA_SIGNATURE EFI_SIGNATURE_32('D','M','S','K') + +// +// Private structure used by driver +// +typedef struct { + UINT32 Signature; + UINTN ImageDebugMask; + EFI_DEBUG_MASK_PROTOCOL DebugMaskInterface; +}DEBUG_MASK_PRIVATE_DATA; + +#define DEBUG_MASK_PRIVATE_DATA_FROM_THIS(a) \ + CR(a, DEBUG_MASK_PRIVATE_DATA, DebugMaskInterface, DEBUGMASK_PRIVATE_DATA_SIGNATURE) + +// +// Internal DebugMask Procotol Install/Uninstall Function +// +EFI_STATUS +InstallDebugMaskProtocol ( + IN EFI_HANDLE ImageHandle + ) +/*++ + +Routine Description: + + Install debug mask protocol on an image handle. + +Arguments: + + ImageHandle - Image handle which debug mask protocol will install on + +Returns: + + EFI_INVALID_PARAMETER - Invalid image handle + + EFI_OUT_OF_RESOURCES - No enough buffer could be allocated + + EFI_SUCCESS - Debug mask protocol successfully installed + +--*/ +; + +// +// Internal DebugMask Procotol Install/Uninstall Function +// +EFI_STATUS +InstallCoreDebugMaskProtocol ( + IN EFI_HANDLE ImageHandle + ) +/*++ + +Routine Description: + + Install debug mask protocol on Dxe Core. + +Arguments: + + ImageHandle - Image handle which debug mask protocol will install on + +Returns: + + EFI_INVALID_PARAMETER - Invalid image handle + + EFI_OUT_OF_RESOURCES - No enough buffer could be allocated + + EFI_SUCCESS - Debug mask protocol successfully installed + +--*/ +; + +EFI_STATUS +UninstallDebugMaskProtocol ( + IN EFI_HANDLE ImageHandle + ) +/*++ + +Routine Description: + + Uninstall debug mask protocol on an image handle. + +Arguments: + + ImageHandle - Image handle which debug mask protocol will uninstall on + +Returns: + + EFI_INVALID_PARAMETER - Invalid image handle + + EFI_SUCCESS - Debug mask protocol successfully uninstalled + +--*/ +; + +#endif diff --git a/EDK/Foundation/Core/Dxe/Misc/InstallConfigurationTable.c b/EDK/Foundation/Core/Dxe/Misc/InstallConfigurationTable.c new file mode 100644 index 0000000..8aea9bc --- /dev/null +++ b/EDK/Foundation/Core/Dxe/Misc/InstallConfigurationTable.c @@ -0,0 +1,230 @@ +/*++ + +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + InstallConfigurationTable.c + + +Abstract: + + Tiano Miscellaneous Services InstallConfigurationTable service + +--*/ + +#include "Tiano.h" +#include "DxeCore.h" + +#define CONFIG_TABLE_SIZE_INCREASED 0x10 + +UINTN mSystemTableAllocateSize = 0; + + +EFI_STATUS +CoreGetConfigTable ( + IN EFI_GUID *Guid, + OUT VOID **Table + ) +/*++ + +Routine Description: + + Find a config table by name in system table's ConfigurationTable. + +Arguments: + + Guid - The table name to look for + + Table - Pointer of the config table + +Returns: + + EFI_NOT_FOUND - Could not find the table in system table's ConfigurationTable. + + EFI_SUCCESS - Table successfully found. + +--*/ +{ + UINTN Index; + + for (Index = 0; Index < gST->NumberOfTableEntries; Index++) { + if (EfiCompareGuid (Guid, &(gST->ConfigurationTable[Index].VendorGuid))) { + *Table = gST->ConfigurationTable[Index].VendorTable; + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreInstallConfigurationTable ( + IN EFI_GUID *Guid, + IN VOID *Table + ) +/*++ + +Routine Description: + + Boot Service called to add, modify, or remove a system configuration table from + the EFI System Table. + +Arguments: + + Guid - Pointer to the GUID for the entry to add, update, or remove + Table - Pointer to the configuration table for the entry to add, update, or + remove, may be NULL. + +Returns: + + EFI_SUCCESS Guid, Table pair added, updated, or removed. + EFI_INVALID_PARAMETER Input GUID not valid. + EFI_NOT_FOUND Attempted to delete non-existant entry + EFI_OUT_OF_RESOURCES Not enough memory available + +--*/ +{ + UINTN Index; + EFI_CONFIGURATION_TABLE *EfiConfigurationTable; + + // + // If Guid is NULL, then this operation cannot be performed + // + if (Guid == NULL) { + return EFI_INVALID_PARAMETER; + } + + EfiConfigurationTable = gST->ConfigurationTable; + + // + // Search all the table for an entry that matches Guid + // + for (Index = 0; Index < gST->NumberOfTableEntries; Index++) { + if (EfiCompareGuid (Guid, &(gST->ConfigurationTable[Index].VendorGuid))) { + break; + } + } + + if (Index < gST->NumberOfTableEntries) { + // + // A match was found, so this is either a modify or a delete operation + // + if (Table != NULL) { + // + // If Table is not NULL, then this is a modify operation. + // Modify the table enty and return. + // + gST->ConfigurationTable[Index].VendorTable = Table; + +#if (EFI_SPECIFICATION_VERSION >= 0x0002000A) + // + // Signal Configuration Table change + // + CoreNotifySignalList (Guid); +#endif + + return EFI_SUCCESS; + } + + // + // A match was found and Table is NULL, so this is a delete operation. + // + gST->NumberOfTableEntries--; + + // + // Copy over deleted entry + // + EfiCommonLibCopyMem ( + &(EfiConfigurationTable[Index]), + &(gST->ConfigurationTable[Index + 1]), + (gST->NumberOfTableEntries - Index) * sizeof (EFI_CONFIGURATION_TABLE) + ); + + } else { + + // + // No matching GUIDs were found, so this is an add operation. + // + + if (Table == NULL) { + // + // If Table is NULL on an add operation, then return an error. + // + return EFI_NOT_FOUND; + } + + // + // Assume that Index == gST->NumberOfTableEntries + // + if ((Index * sizeof (EFI_CONFIGURATION_TABLE)) >= mSystemTableAllocateSize) { + // + // Allocate a table with one additional entry. + // + mSystemTableAllocateSize += (CONFIG_TABLE_SIZE_INCREASED * sizeof (EFI_CONFIGURATION_TABLE)); + EfiConfigurationTable = CoreAllocateRuntimePool (mSystemTableAllocateSize); + if (EfiConfigurationTable == NULL) { + // + // If a new table could not be allocated, then return an error. + // + return EFI_OUT_OF_RESOURCES; + } + + if (gST->ConfigurationTable != NULL) { + // + // Copy the old table to the new table. + // + EfiCommonLibCopyMem ( + EfiConfigurationTable, + gST->ConfigurationTable, + Index * sizeof (EFI_CONFIGURATION_TABLE) + ); + + // + // Free Old Table + // + CoreFreePool (gST->ConfigurationTable); + } + + // + // Update System Table + // + gST->ConfigurationTable = EfiConfigurationTable; + } + + // + // Fill in the new entry + // + EfiConfigurationTable[Index].VendorGuid = *Guid; + EfiConfigurationTable[Index].VendorTable = Table; + + // + // This is an add operation, so increment the number of table entries + // + gST->NumberOfTableEntries++; + } + + // + // Fix up the CRC-32 in the EFI System Table + // + CalculateEfiHdrCrc (&gST->Hdr); + +#if (EFI_SPECIFICATION_VERSION >= 0x0002000A) + // + // Signal Configuration Table change + // + CoreNotifySignalList (Guid); +#endif + + return EFI_SUCCESS; +} diff --git a/EDK/Foundation/Core/Dxe/Misc/SetWatchdogTimer.c b/EDK/Foundation/Core/Dxe/Misc/SetWatchdogTimer.c new file mode 100644 index 0000000..2146137 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/Misc/SetWatchdogTimer.c @@ -0,0 +1,84 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + SetWatchdogTimer.c + +Abstract: + + Tiano Miscellaneous Services SetWatchdogTimer service implementation + +--*/ + +#include "Tiano.h" +#include "DxeCore.h" + +#define WATCHDOG_TIMER_CALIBRATE_PER_SECOND 10000000 + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreSetWatchdogTimer ( + IN UINTN Timeout, + IN UINT64 WatchdogCode, + IN UINTN DataSize, + IN CHAR16 *WatchdogData OPTIONAL + ) +/*++ + +Routine Description: + + Sets the system's watchdog timer. + +Arguments: + + Timeout The number of seconds. Zero disables the timer. + + ///////following three parameters are left for platform specific using + + WatchdogCode The numberic code to log. 0x0 to 0xffff are firmware + DataSize Size of the optional data + WatchdogData Optional Null terminated unicode string followed by binary + data. + +Returns: + + EFI_SUCCESS Timeout has been set + EFI_NOT_AVAILABLE_YET WatchdogTimer is not available yet + EFI_UNSUPPORTED System does not have a timer (currently not used) + EFI_DEVICE_ERROR Could not complete due to hardware error + +--*/ +{ + EFI_STATUS Status; + + // + // Check our architectural protocol + // + if (gWatchdogTimer == NULL) { + return EFI_NOT_AVAILABLE_YET; + } + + // + // Attempt to set the timeout + // + Status = gWatchdogTimer->SetTimerPeriod (gWatchdogTimer, MultU64x32 (Timeout, WATCHDOG_TIMER_CALIBRATE_PER_SECOND)); + + // + // Check for errors + // + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} diff --git a/EDK/Foundation/Core/Dxe/Misc/Stall.c b/EDK/Foundation/Core/Dxe/Misc/Stall.c new file mode 100644 index 0000000..a87f894 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/Misc/Stall.c @@ -0,0 +1,79 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Stall.c + +Abstract: + + Tiano Miscellaneous Services Stall service implementation + +--*/ + +// +// Include statements +// + +#include "Tiano.h" +#include "DxeCore.h" + +EFI_BOOTSERVICE +EFI_STATUS +EFIAPI +CoreStall ( + IN UINTN Microseconds + ) +/*++ + +Routine Description: + + Introduces a fine-grained stall. + +Arguments: + + Microseconds The number of microseconds to stall execution + +Returns: + + EFI_SUCCESS - Execution was stalled for at least the requested amount + of microseconds. + + EFI_NOT_AVAILABLE_YET - gMetronome is not available yet + +--*/ +{ + UINT32 Counter; + UINTN Remainder; + + if (gMetronome == NULL) { + return EFI_NOT_AVAILABLE_YET; + } + + // + // Calculate the number of ticks by dividing the number of microseconds by + // the TickPeriod. + // Calcullation is based on 100ns unit. + // + Counter = (UINT32) DivU64x32 ((Microseconds * 10), (UINTN) gMetronome->TickPeriod, &Remainder); + + // + // Call WaitForTick for Counter + 1 ticks to try to guarantee Counter tick + // periods, thus attempting to ensure Microseconds of stall time. + // + if (Remainder != 0) { + Counter++; + } + + gMetronome->WaitForTick (gMetronome, Counter); + + return EFI_SUCCESS; +} diff --git a/EDK/Foundation/Core/Dxe/SectionExtraction/CoreSectionExtraction.c b/EDK/Foundation/Core/Dxe/SectionExtraction/CoreSectionExtraction.c new file mode 100644 index 0000000..f4e7727 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/SectionExtraction/CoreSectionExtraction.c @@ -0,0 +1,1387 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + CoreSectionExtraction.c + +Abstract: + + Section Extraction Protocol implementation. + + Stream database is implemented as a linked list of section streams, + where each stream contains a linked list of children, which may be leaves or + encapsulations. + + Children that are encapsulations generate new stream entries + when they are created. Streams can also be created by calls to + SEP->OpenSectionStream(). + + The database is only created far enough to return the requested data from + any given stream, or to determine that the requested data is not found. + + If a GUIDed encapsulation is encountered, there are three possiblilites. + + 1) A support protocol is found, in which the stream is simply processed with + the support protocol. + + 2) A support protocol is not found, but the data is available to be read + without processing. In this case, the database is built up through the + recursions to return the data, and a RPN event is set that will enable + the stream in question to be refreshed if and when the required section + extraction protocol is published.This insures the AuthenticationStatus + does not become stale in the cache. + + 3) A support protocol is not found, and the data is not available to be read + without it. This results in EFI_PROTOCOL_ERROR. + +--*/ + +#include "Tiano.h" +#include "DxeCore.h" +#include "EfiFirmwareFileSystem.h" + +// +// Comsumed protocol +// +#include EFI_PROTOCOL_DEFINITION (TianoDecompress) +#include EFI_PROTOCOL_DEFINITION (GuidedSectionExtraction) + +// +// Produced protocol +// +#include EFI_PROTOCOL_DEFINITION (SectionExtraction) + +// +// Local defines and typedefs +// +#define CORE_SECTION_CHILD_SIGNATURE EFI_SIGNATURE_32('S','X','C','S') +#define CHILD_SECTION_NODE_FROM_LINK(Node) \ + CR (Node, CORE_SECTION_CHILD_NODE, Link, CORE_SECTION_CHILD_SIGNATURE) + +typedef struct { + UINT32 Signature; + EFI_LIST_ENTRY Link; + UINT32 Type; + UINT32 Size; + // + // StreamBase + OffsetInStream == pointer to section header in stream. The + // stream base is always known when walking the sections within. + // + UINT32 OffsetInStream; + // + // Then EncapsulatedStreamHandle below is always 0 if the section is NOT an + // encapsulating section. Otherwise, it contains the stream handle + // of the encapsulated stream. This handle is ALWAYS produced any time an + // encapsulating child is encountered, irrespective of whether the + // encapsulated stream is processed further. + // + UINTN EncapsulatedStreamHandle; + EFI_GUID *EncapsulationGuid; +} CORE_SECTION_CHILD_NODE; + +#define CORE_SECTION_STREAM_SIGNATURE EFI_SIGNATURE_32('S','X','S','S') +#define STREAM_NODE_FROM_LINK(Node) \ + CR (Node, CORE_SECTION_STREAM_NODE, Link, CORE_SECTION_STREAM_SIGNATURE) + +typedef struct { + UINT32 Signature; + EFI_LIST_ENTRY Link; + UINTN StreamHandle; + UINT8 *StreamBuffer; + UINTN StreamLength; + EFI_LIST Children; + // + // Authentication status is from GUIDed encapsulations. + // + UINT32 AuthenticationStatus; +} CORE_SECTION_STREAM_NODE; + +#define NULL_STREAM_HANDLE 0 + +typedef struct { + CORE_SECTION_CHILD_NODE *ChildNode; + CORE_SECTION_STREAM_NODE *ParentStream; + VOID *Registration; + EFI_EVENT Event; +} RPN_EVENT_CONTEXT; + + + +// +// Local prototypes +// + +STATIC +BOOLEAN +ChildIsType ( + IN CORE_SECTION_STREAM_NODE *Stream, + IN CORE_SECTION_CHILD_NODE *Child, + IN EFI_SECTION_TYPE SearchType, + IN EFI_GUID *SectionDefinitionGuid + ); + +STATIC +VOID +EFIAPI +NotifyGuidedExtraction ( + IN EFI_EVENT Event, + IN VOID *RpnContext + ); + +STATIC +EFI_STATUS +EFIAPI +CreateGuidedExtractionRpnEvent ( + IN CORE_SECTION_STREAM_NODE *ParentStream, + IN CORE_SECTION_CHILD_NODE *ChildNode + ); + +EFI_STATUS +EFIAPI +OpenSectionStream ( + IN EFI_SECTION_EXTRACTION_PROTOCOL *This, + IN UINTN SectionStreamLength, + IN VOID *SectionStream, + OUT UINTN *SectionStreamHandle + ); + +EFI_STATUS +EFIAPI +GetSection ( + IN EFI_SECTION_EXTRACTION_PROTOCOL *This, + IN UINTN SectionStreamHandle, + IN EFI_SECTION_TYPE *SectionType, + IN EFI_GUID *SectionDefinitionGuid, + IN UINTN SectionInstance, + IN VOID **Buffer, + IN OUT UINTN *BufferSize, + OUT UINT32 *AuthenticationStatus + ); + +EFI_STATUS +EFIAPI +CloseSectionStream ( + IN EFI_SECTION_EXTRACTION_PROTOCOL *This, + IN UINTN StreamHandleToClose + ); + +STATIC +EFI_STATUS +FindStreamNode ( + IN UINTN SearchHandle, + OUT CORE_SECTION_STREAM_NODE **FoundStream + ); + +STATIC +EFI_STATUS +FindChildNode ( + IN CORE_SECTION_STREAM_NODE *SourceStream, + IN EFI_SECTION_TYPE SearchType, + IN UINTN *SectionInstance, + IN EFI_GUID *SectionDefinitionGuid, + OUT CORE_SECTION_CHILD_NODE **FoundChild, + OUT CORE_SECTION_STREAM_NODE **FoundStream, + OUT UINT32 *AuthenticationStatus + ); + +STATIC +EFI_STATUS +CreateChildNode ( + IN CORE_SECTION_STREAM_NODE *Stream, + IN UINT32 ChildOffset, + OUT CORE_SECTION_CHILD_NODE **ChildNode + ); + +STATIC +VOID +FreeChildNode ( + IN CORE_SECTION_CHILD_NODE *ChildNode + ); + +STATIC +EFI_STATUS +OpenSectionStreamEx ( + IN UINTN SectionStreamLength, + IN VOID *SectionStream, + IN BOOLEAN AllocateBuffer, + IN UINT32 AuthenticationStatus, + OUT UINTN *SectionStreamHandle + ); + +STATIC +BOOLEAN +IsValidSectionStream ( + IN VOID *SectionStream, + IN UINTN SectionStreamLength + ); + +// +// Module globals +// +EFI_LIST mStreamRoot = INITIALIZE_LIST_HEAD_VARIABLE (mStreamRoot); + +EFI_HANDLE mSectionExtractionHandle = NULL; + +EFI_SECTION_EXTRACTION_PROTOCOL mSectionExtraction = { + OpenSectionStream, + GetSection, + CloseSectionStream +}; + + +EFI_STATUS +EFIAPI +InitializeSectionExtraction ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + Entry point of the section extraction code. Initializes an instance of the + section extraction interface and installs it on a new handle. + +Arguments: + ImageHandle EFI_HANDLE: A handle for the image that is initializing this driver + SystemTable EFI_SYSTEM_TABLE: A pointer to the EFI system table + +Returns: + EFI_SUCCESS: Driver initialized successfully + EFI_OUT_OF_RESOURCES: Could not allocate needed resources + +--*/ +{ + EFI_STATUS Status; + + // + // Install SEP to a new handle + // + Status = CoreInstallProtocolInterface ( + &mSectionExtractionHandle, + &gEfiSectionExtractionProtocolGuid, + EFI_NATIVE_INTERFACE, + &mSectionExtraction + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + + +EFI_STATUS +EFIAPI +OpenSectionStream ( + IN EFI_SECTION_EXTRACTION_PROTOCOL *This, + IN UINTN SectionStreamLength, + IN VOID *SectionStream, + OUT UINTN *SectionStreamHandle + ) +/*++ + +Routine Description: + SEP member function. This function creates and returns a new section stream + handle to represent the new section stream. + +Arguments: + This - Indicates the calling context. + SectionStreamLength - Size in bytes of the section stream. + SectionStream - Buffer containing the new section stream. + SectionStreamHandle - A pointer to a caller allocated UINTN that on output + contains the new section stream handle. + +Returns: + EFI_SUCCESS + EFI_OUT_OF_RESOURCES - memory allocation failed. + EFI_INVALID_PARAMETER - section stream does not end concident with end of + last section. + +--*/ +{ + // + // Check to see section stream looks good... + // + if (!IsValidSectionStream (SectionStream, SectionStreamLength)) { + return EFI_INVALID_PARAMETER; + } + + return OpenSectionStreamEx ( + SectionStreamLength, + SectionStream, + TRUE, + 0, + SectionStreamHandle + ); +} + + +EFI_STATUS +EFIAPI +GetSection ( + IN EFI_SECTION_EXTRACTION_PROTOCOL *This, + IN UINTN SectionStreamHandle, + IN EFI_SECTION_TYPE *SectionType, + IN EFI_GUID *SectionDefinitionGuid, + IN UINTN SectionInstance, + IN VOID **Buffer, + IN OUT UINTN *BufferSize, + OUT UINT32 *AuthenticationStatus + ) +/*++ + +Routine Description: + SEP member function. Retrieves requested section from section stream. + +Arguments: + This: Pointer to SEP instance. + SectionStreamHandle: The section stream from which to extract the requested + section. + SectionType: A pointer to the type of section to search for. + SectionDefinitionGuid: If the section type is EFI_SECTION_GUID_DEFINED, then + SectionDefinitionGuid indicates which of these types + of sections to search for. + SectionInstance: Indicates which instance of the requested section to + return. + Buffer: Double indirection to buffer. If *Buffer is non-null on + input, then the buffer is caller allocated. If + *Buffer is NULL, then the buffer is callee allocated. + In either case, the requried buffer size is returned + in *BufferSize. + BufferSize: On input, indicates the size of *Buffer if *Buffer is + non-null on input. On output, indicates the required + size (allocated size if callee allocated) of *Buffer. + AuthenticationStatus: Indicates the authentication status of the retrieved + section. + +Returns: + EFI_SUCCESS: Section was retrieved successfully + EFI_PROTOCOL_ERROR: A GUID defined section was encountered in the section + stream with its EFI_GUIDED_SECTION_PROCESSING_REQUIRED + bit set, but there was no corresponding GUIDed Section + Extraction Protocol in the handle database. *Buffer is + unmodified. + EFI_NOT_FOUND: An error was encountered when parsing the SectionStream. + This indicates the SectionStream is not correctly + formatted. + EFI_NOT_FOUND: The requested section does not exist. + EFI_OUT_OF_RESOURCES: The system has insufficient resources to process the + request. + EFI_INVALID_PARAMETER: The SectionStreamHandle does not exist. + EFI_WARN_TOO_SMALL: The size of the caller allocated input buffer is + insufficient to contain the requested section. The + input buffer is filled and contents are section contents + are truncated. + +--*/ +{ + CORE_SECTION_STREAM_NODE *StreamNode; + EFI_TPL OldTpl; + EFI_STATUS Status; + CORE_SECTION_CHILD_NODE *ChildNode; + CORE_SECTION_STREAM_NODE *ChildStreamNode; + UINTN CopySize; + UINT32 ExtractedAuthenticationStatus; + UINTN Instance; + UINT8 *CopyBuffer; + UINTN SectionSize; + + + OldTpl = CoreRaiseTpl (EFI_TPL_NOTIFY); + Instance = SectionInstance + 1; + + // + // Locate target stream + // + Status = FindStreamNode (SectionStreamHandle, &StreamNode); + if (EFI_ERROR (Status)) { + Status = EFI_INVALID_PARAMETER; + goto GetSection_Done; + } + + // + // Found the stream, now locate and return the appropriate section + // + if (SectionType == NULL) { + // + // SectionType == NULL means return the WHOLE section stream... + // + CopySize = StreamNode->StreamLength; + CopyBuffer = StreamNode->StreamBuffer; + *AuthenticationStatus = StreamNode->AuthenticationStatus; + } else { + // + // There's a requested section type, so go find it and return it... + // + Status = FindChildNode ( + StreamNode, + *SectionType, + &Instance, + SectionDefinitionGuid, + &ChildNode, + &ChildStreamNode, + &ExtractedAuthenticationStatus + ); + if (EFI_ERROR (Status) || (ChildNode == NULL)) { + goto GetSection_Done; + } + CopySize = ChildNode->Size - sizeof (EFI_COMMON_SECTION_HEADER); + CopyBuffer = ChildStreamNode->StreamBuffer + ChildNode->OffsetInStream + sizeof (EFI_COMMON_SECTION_HEADER); + *AuthenticationStatus = ExtractedAuthenticationStatus; + } + + SectionSize = CopySize; + if (*Buffer != NULL) { + // + // Caller allocated buffer. Fill to size and return required size... + // + if (*BufferSize < CopySize) { + Status = EFI_WARN_BUFFER_TOO_SMALL; + CopySize = *BufferSize; + } + } else { + // + // Callee allocated buffer. Allocate buffer and return size. + // + *Buffer = CoreAllocateBootServicesPool (CopySize); + if (*Buffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto GetSection_Done; + } + } + EfiCommonLibCopyMem (*Buffer, CopyBuffer, CopySize); + *BufferSize = SectionSize; + +GetSection_Done: + CoreRestoreTpl (OldTpl); + return Status; +} + + + +EFI_STATUS +EFIAPI +CloseSectionStream ( + IN EFI_SECTION_EXTRACTION_PROTOCOL *This, + IN UINTN StreamHandleToClose + ) +/*++ + +Routine Description: + SEP member function. Deletes an existing section stream + +Arguments: + This - Indicates the calling context. + StreamHandleToClose - Indicates the stream to close + +Returns: + EFI_SUCCESS + EFI_OUT_OF_RESOURCES - memory allocation failed. + EFI_INVALID_PARAMETER - section stream does not end concident with end of + last section. + +--*/ +{ + CORE_SECTION_STREAM_NODE *StreamNode; + EFI_TPL OldTpl; + EFI_STATUS Status; + EFI_LIST *Link; + CORE_SECTION_CHILD_NODE *ChildNode; + + OldTpl = CoreRaiseTpl (EFI_TPL_NOTIFY); + + // + // Locate target stream + // + Status = FindStreamNode (StreamHandleToClose, &StreamNode); + if (!EFI_ERROR (Status)) { + // + // Found the stream, so close it + // + RemoveEntryList (&StreamNode->Link); + while (!IsListEmpty (&StreamNode->Children)) { + Link = GetFirstNode (&StreamNode->Children); + ChildNode = CHILD_SECTION_NODE_FROM_LINK (Link); + FreeChildNode (ChildNode); + } + CoreFreePool (StreamNode->StreamBuffer); + CoreFreePool (StreamNode); + Status = EFI_SUCCESS; + } else { + Status = EFI_INVALID_PARAMETER; + } + + CoreRestoreTpl (OldTpl); + return Status; +} + + +STATIC +BOOLEAN +ChildIsType ( + IN CORE_SECTION_STREAM_NODE *Stream, + IN CORE_SECTION_CHILD_NODE *Child, + IN EFI_SECTION_TYPE SearchType, + IN EFI_GUID *SectionDefinitionGuid + ) +/*++ + +Routine Description: + Worker function. Determine if the input stream:child matches the input type. + +Arguments: + Stream - Indicates the section stream associated with the child + Child - Indicates the child to check + SearchType - Indicates the type of section to check against for + SectionDefinitionGuid - Indicates the GUID to check against if the type is + EFI_SECTION_GUID_DEFINED +Returns: + TRUE - The child matches + FALSE - The child doesn't match + +--*/ +{ + EFI_GUID_DEFINED_SECTION *GuidedSection; + + if (SearchType == EFI_SECTION_ALL) { + return TRUE; + } + if (Child->Type != SearchType) { + return FALSE; + } + + // + // ReadSection function of the FV protocol (FvReadFileSection) doesn't work for GUID defined sections + // (always returns EFI_NOT_FOUND). When this function is called from FvReadFileSection, SectionDefinitionGuid + // is always NULL. If SectionDefinitionGuid is NULL, return TRUE (the section type matches). + // + if (SearchType != EFI_SECTION_GUID_DEFINED || SectionDefinitionGuid == NULL) { + return TRUE; + } + GuidedSection = (EFI_GUID_DEFINED_SECTION * )(Stream->StreamBuffer + Child->OffsetInStream); + return EfiCompareGuid (&GuidedSection->SectionDefinitionGuid, SectionDefinitionGuid); +} + + +STATIC +EFI_STATUS +FindChildNode ( + IN CORE_SECTION_STREAM_NODE *SourceStream, + IN EFI_SECTION_TYPE SearchType, + IN OUT UINTN *SectionInstance, + IN EFI_GUID *SectionDefinitionGuid, + OUT CORE_SECTION_CHILD_NODE **FoundChild, + OUT CORE_SECTION_STREAM_NODE **FoundStream, + OUT UINT32 *AuthenticationStatus + ) +/*++ + +Routine Description: + Worker function Recursively searches / builds section stream database + looking for requested section. + +Arguments: + SourceStream - Indicates the section stream in which to do the search. + SearchType - Indicates the type of section to search for. + SectionInstance - Indicates which instance of section to find. This is + an in/out parameter to deal with recursions. + SectionDefinitionGuid - Guid of section definition + FoundChild - Output indicating the child node that is found. + FoundStream - Output indicating which section stream the child was + found in. If this stream was generated as a result of + an encapsulation section, the streamhandle is visible + within the SEP driver only. + AuthenticationStatus- Indicates the authentication status of the found section. + +Returns: + EFI_SUCCESS - Child node was found and returned. + EFI_OUT_OF_RESOURCES- Memory allocation failed. + EFI_NOT_FOUND - Requested child node does not exist. + EFI_PROTOCOL_ERROR - a required GUIDED section extraction protocol does not + exist + +--*/ +{ + CORE_SECTION_CHILD_NODE *CurrentChildNode; + CORE_SECTION_CHILD_NODE *RecursedChildNode; + CORE_SECTION_STREAM_NODE *RecursedFoundStream; + UINT32 NextChildOffset; + EFI_STATUS ErrorStatus; + EFI_STATUS Status; + + CurrentChildNode = NULL; + ErrorStatus = EFI_NOT_FOUND; + + if (SourceStream->StreamLength == 0) { + return EFI_NOT_FOUND; + } + + if (IsListEmpty (&SourceStream->Children) && + SourceStream->StreamLength > sizeof (EFI_COMMON_SECTION_HEADER)) { + // + // This occurs when a section stream exists, but no child sections + // have been parsed out yet. Therefore, extract the first child and add it + // to the list of children so we can get started. + // + Status = CreateChildNode (SourceStream, 0, &CurrentChildNode); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // At least one child has been parsed out of the section stream. So, walk + // through the sections that have already been parsed out looking for the + // requested section, if necessary, continue parsing section stream and + // adding children until either the requested section is found, or we run + // out of data + // + CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetFirstNode(&SourceStream->Children)); + + for (;;) { + if (ChildIsType (SourceStream, CurrentChildNode, SearchType, SectionDefinitionGuid)) { + // + // The type matches, so check the instance count to see if it's the one we want + // + (*SectionInstance)--; + if (*SectionInstance == 0) { + // + // Got it! + // + *FoundChild = CurrentChildNode; + *FoundStream = SourceStream; + *AuthenticationStatus = SourceStream->AuthenticationStatus; + return EFI_SUCCESS; + } + } + + if (CurrentChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) { + // + // If the current node is an encapsulating node, recurse into it... + // + Status = FindChildNode ( + (CORE_SECTION_STREAM_NODE *)CurrentChildNode->EncapsulatedStreamHandle, + SearchType, + SectionInstance, + SectionDefinitionGuid, + &RecursedChildNode, + &RecursedFoundStream, + AuthenticationStatus + ); + // + // If the status is not EFI_SUCCESS, just save the error code and continue + // to find the request child node in the rest stream. + // + if (*SectionInstance == 0) { + ASSERT_EFI_ERROR (Status); + *FoundChild = RecursedChildNode; + *FoundStream = RecursedFoundStream; + return EFI_SUCCESS; + } else { + ErrorStatus = Status; + } + } + + if (!IsNodeAtEnd (&SourceStream->Children, &CurrentChildNode->Link)) { + // + // We haven't found the child node we're interested in yet, but there's + // still more nodes that have already been parsed so get the next one + // and continue searching.. + // + CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetNextNode (&SourceStream->Children, &CurrentChildNode->Link)); + } else { + // + // We've exhausted children that have already been parsed, so see if + // there's any more data and continue parsing out more children if there + // is. + // + NextChildOffset = CurrentChildNode->OffsetInStream + CurrentChildNode->Size; + // + // Round up to 4 byte boundary + // + NextChildOffset += 3; + NextChildOffset &= ~(UINTN)3; + if (NextChildOffset <= SourceStream->StreamLength - sizeof (EFI_COMMON_SECTION_HEADER)) { + // + // There's an unparsed child remaining in the stream, so create a new child node + // + Status = CreateChildNode (SourceStream, NextChildOffset, &CurrentChildNode); + if (EFI_ERROR (Status) || (CurrentChildNode == NULL)) { + return Status; + } + } else { + ASSERT (EFI_ERROR (ErrorStatus)); + return ErrorStatus; + } + } + } +} + + +STATIC +EFI_STATUS +CreateChildNode ( + IN CORE_SECTION_STREAM_NODE *Stream, + IN UINT32 ChildOffset, + OUT CORE_SECTION_CHILD_NODE **ChildNode + ) +/*++ + +Routine Description: + Worker function. Constructor for new child nodes. + +Arguments: + Stream - Indicates the section stream in which to add the child. + ChildOffset - Indicates the offset in Stream that is the beginning + of the child section. + ChildNode - Indicates the Callee allocated and initialized child. + +Returns: + EFI_SUCCESS - Child node was found and returned. + EFI_OUT_OF_RESOURCES- Memory allocation failed. + EFI_PROTOCOL_ERROR - Encapsulation sections produce new stream handles when + the child node is created. If the section type is GUID + defined, and the extraction GUID does not exist, and + producing the stream requires the GUID, then a protocol + error is generated and no child is produced. + Values returned by OpenSectionStreamEx. + +--*/ +{ + EFI_STATUS Status; + EFI_COMMON_SECTION_HEADER *SectionHeader; + EFI_COMPRESSION_SECTION *CompressionHeader; + EFI_GUID_DEFINED_SECTION *GuidedHeader; + EFI_TIANO_DECOMPRESS_PROTOCOL *Decompress; + EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *GuidedExtraction; + VOID *NewStreamBuffer; + VOID *ScratchBuffer; + UINT32 ScratchSize; + UINTN NewStreamBufferSize; + UINT32 AuthenticationStatus; + UINT32 SectionLength; + + CORE_SECTION_CHILD_NODE *Node; + + SectionHeader = (EFI_COMMON_SECTION_HEADER *) (Stream->StreamBuffer + ChildOffset); + + // + // Allocate a new node + // + *ChildNode = CoreAllocateBootServicesPool (sizeof (CORE_SECTION_CHILD_NODE)); + Node = *ChildNode; + if (Node == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Now initialize it + // + Node->Signature = CORE_SECTION_CHILD_SIGNATURE; + Node->Type = SectionHeader->Type; + Node->Size = SECTION_SIZE (SectionHeader); + Node->OffsetInStream = ChildOffset; + Node->EncapsulatedStreamHandle = NULL_STREAM_HANDLE; + Node->EncapsulationGuid = NULL; + + // + // If it's an encapsulating section, then create the new section stream also + // + switch (Node->Type) { + case EFI_SECTION_COMPRESSION: + // + // Get the CompressionSectionHeader + // + ASSERT (Node->Size >= sizeof (EFI_COMPRESSION_SECTION)); + + CompressionHeader = (EFI_COMPRESSION_SECTION *) SectionHeader; + + // + // Allocate space for the new stream + // + if (CompressionHeader->UncompressedLength > 0) { + NewStreamBufferSize = CompressionHeader->UncompressedLength; + NewStreamBuffer = CoreAllocateBootServicesPool (NewStreamBufferSize); + if (NewStreamBuffer == NULL) { + CoreFreePool (Node); + return EFI_OUT_OF_RESOURCES; + } + + if (CompressionHeader->CompressionType == EFI_NOT_COMPRESSED) { + // + // stream is not actually compressed, just encapsulated. So just copy it. + // + EfiCommonLibCopyMem (NewStreamBuffer, CompressionHeader + 1, NewStreamBufferSize); + } else if (CompressionHeader->CompressionType == EFI_STANDARD_COMPRESSION || + CompressionHeader->CompressionType == EFI_CUSTOMIZED_COMPRESSION) { + // + // Decompress the stream + // + if (CompressionHeader->CompressionType == EFI_STANDARD_COMPRESSION) { + Status = CoreLocateProtocol (&gEfiTianoDecompressProtocolGuid, NULL, &Decompress); + } else { + Status = CoreLocateProtocol (&gEfiCustomizedDecompressProtocolGuid, NULL, &Decompress); + } + + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status) || (Decompress == NULL)) { + // + // Failed to locate protocol 'Decompress' + // + CoreFreePool (Node); + CoreFreePool (NewStreamBuffer); + return Status; + } + + Status = Decompress->GetInfo ( + Decompress, + CompressionHeader + 1, + Node->Size - sizeof (EFI_COMPRESSION_SECTION), + (UINT32 *)&NewStreamBufferSize, + &ScratchSize + ); + ASSERT_EFI_ERROR (Status); + ASSERT (NewStreamBufferSize == CompressionHeader->UncompressedLength); + + ScratchBuffer = CoreAllocateBootServicesPool (ScratchSize); + if (ScratchBuffer == NULL) { + CoreFreePool (Node); + CoreFreePool (NewStreamBuffer); + return EFI_OUT_OF_RESOURCES; + } + + Status = Decompress->Decompress ( + Decompress, + CompressionHeader + 1, + Node->Size - sizeof (EFI_COMPRESSION_SECTION), + NewStreamBuffer, + (UINT32)NewStreamBufferSize, + ScratchBuffer, + ScratchSize + ); + ASSERT_EFI_ERROR (Status); + CoreFreePool (ScratchBuffer); + } + } else { + NewStreamBuffer = NULL; + NewStreamBufferSize = 0; + } + + Status = OpenSectionStreamEx ( + NewStreamBufferSize, + NewStreamBuffer, + FALSE, + Stream->AuthenticationStatus, + &Node->EncapsulatedStreamHandle + ); + if (EFI_ERROR (Status)) { + CoreFreePool (Node); + CoreFreePool (NewStreamBuffer); + return Status; + } + break; + + case EFI_SECTION_GUID_DEFINED: + GuidedHeader = (EFI_GUID_DEFINED_SECTION *) SectionHeader; + Node->EncapsulationGuid = &GuidedHeader->SectionDefinitionGuid; + Status = CoreLocateProtocol (Node->EncapsulationGuid, NULL, &GuidedExtraction); + if (!EFI_ERROR (Status) && (GuidedExtraction != NULL)) { + // + // NewStreamBuffer is always allocated by ExtractSection... No caller + // allocation here. + // + Status = GuidedExtraction->ExtractSection ( + GuidedExtraction, + GuidedHeader, + &NewStreamBuffer, + &NewStreamBufferSize, + &AuthenticationStatus + ); + if (EFI_ERROR (Status)) { + CoreFreePool (*ChildNode); + return EFI_PROTOCOL_ERROR; + } + + // + // Make sure we initialize the new stream with the correct + // authentication status for both aggregate and local status fields. + // + if (GuidedHeader->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) { + // + // OR in the parent stream's aggregate status. + // + AuthenticationStatus |= Stream->AuthenticationStatus & EFI_AGGREGATE_AUTH_STATUS_ALL; + } else { + // + // since there's no authentication data contributed by the section, + // just inherit the full value from our immediate parent. + // + AuthenticationStatus = Stream->AuthenticationStatus; + } + + Status = OpenSectionStreamEx ( + NewStreamBufferSize, + NewStreamBuffer, + FALSE, + AuthenticationStatus, + &Node->EncapsulatedStreamHandle + ); + if (EFI_ERROR (Status)) { + CoreFreePool (*ChildNode); + CoreFreePool (NewStreamBuffer); + return Status; + } + } else { + // + // There's no GUIDed section extraction protocol available. + // + if (GuidedHeader->Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) { + // + // If the section REQUIRES an extraction protocol, then we're toast + // + CoreFreePool (*ChildNode); + return EFI_PROTOCOL_ERROR; + } + + // + // Figure out the proper authentication status + // + AuthenticationStatus = Stream->AuthenticationStatus; + if (GuidedHeader->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) { + // + // The local status of the new stream is contained in + // AuthenticaionStatus. This value needs to be ORed into the + // Aggregate bits also... + // + + // + // Clear out and initialize the local status + // + AuthenticationStatus &= ~EFI_LOCAL_AUTH_STATUS_ALL; + AuthenticationStatus |= EFI_LOCAL_AUTH_STATUS_IMAGE_SIGNED | EFI_LOCAL_AUTH_STATUS_NOT_TESTED; + // + // OR local status into aggregate status + // + AuthenticationStatus |= AuthenticationStatus >> 16; + } + + SectionLength = SECTION_SIZE (GuidedHeader); + Status = OpenSectionStreamEx ( + SectionLength - GuidedHeader->DataOffset, + (UINT8 *) GuidedHeader + GuidedHeader->DataOffset, + TRUE, + AuthenticationStatus, + &Node->EncapsulatedStreamHandle + ); + if (EFI_ERROR (Status)) { + CoreFreePool (Node); + return Status; + } + } + + if ((AuthenticationStatus & EFI_LOCAL_AUTH_STATUS_ALL) == + (EFI_LOCAL_AUTH_STATUS_IMAGE_SIGNED | EFI_LOCAL_AUTH_STATUS_NOT_TESTED)) { + // + // Need to register for RPN for when the required GUIDed extraction + // protocol becomes available. This will enable us to refresh the + // AuthenticationStatus cached in the Stream if it's ever requested + // again. + // + Status = CreateGuidedExtractionRpnEvent (Stream, Node); + if (EFI_ERROR (Status)) { + CoreFreePool (Node); + return Status; + } + } + + break; + + default: + + // + // Nothing to do if it's a leaf + // + break; + } + + // + // Last, add the new child node to the stream + // + InsertTailList (&Stream->Children, &Node->Link); + + return EFI_SUCCESS; +} + + +STATIC +EFI_STATUS +EFIAPI +CreateGuidedExtractionRpnEvent ( + IN CORE_SECTION_STREAM_NODE *ParentStream, + IN CORE_SECTION_CHILD_NODE *ChildNode + ) +/*++ + +Routine Description: + Worker function. Constructor for RPN event if needed to keep AuthenticationStatus + cache correct when a missing GUIDED_SECTION_EXTRACTION_PROTOCOL appears... + +Arguments: + ParentStream - Indicates the parent of the ecnapsulation section (child) + ChildNode - Indicates the child node that is the encapsulation section. + +Returns: + EFI_SUCCESS: Event created successfully + EFI_OUT_OF_RESOURCES: Could not allocate needed resources + +--*/ +{ + RPN_EVENT_CONTEXT *Context; + + // + // Allocate new event structure and context + // + Context = CoreAllocateBootServicesPool (sizeof (RPN_EVENT_CONTEXT)); + ASSERT (Context != NULL); + if (Context == NULL) { + // + // Failed to allocate memory for 'Context' + // + return EFI_OUT_OF_RESOURCES; + } + + Context->ChildNode = ChildNode; + Context->ParentStream = ParentStream; + + Context->Event = CoreCreateProtocolNotifyEvent ( + Context->ChildNode->EncapsulationGuid, + EFI_TPL_NOTIFY, + NotifyGuidedExtraction, + Context, + &Context->Registration, + FALSE + ); + return EFI_SUCCESS; +} + + +STATIC +VOID +EFIAPI +NotifyGuidedExtraction ( + IN EFI_EVENT Event, + IN VOID *RpnContext + ) +/*++ + +Routine Description: + RPN callback function. Removes a stale section stream and re-initializes it + with an updated AuthenticationStatus. + +Arguments: + Event - The event that fired + RpnContext - A pointer to the context that allows us to identify + the relevent encapsulation... + +Returns: + None + +--*/ +{ + EFI_STATUS Status; + EFI_GUID_DEFINED_SECTION *GuidedHeader; + EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *GuidedExtraction; + VOID *NewStreamBuffer; + UINTN NewStreamBufferSize; + UINT32 AuthenticationStatus; + RPN_EVENT_CONTEXT *Context; + + Context = RpnContext; + + Status = CloseSectionStream (&mSectionExtraction, Context->ChildNode->EncapsulatedStreamHandle); + if (!EFI_ERROR (Status)) { + // + // The stream closed successfully, so re-open the stream with correct AuthenticationStatus + // + + GuidedHeader = (EFI_GUID_DEFINED_SECTION *) + (Context->ParentStream->StreamBuffer + Context->ChildNode->OffsetInStream); + ASSERT (GuidedHeader->CommonHeader.Type == EFI_SECTION_GUID_DEFINED); + + Status = CoreLocateProtocol (Context->ChildNode->EncapsulationGuid, NULL, &GuidedExtraction); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status) || (GuidedExtraction == NULL)) { + // + // Failed to locate protocol 'GuidedExtraction' + // + CoreCloseEvent (Event); + CoreFreePool (Context); + return; + } + + Status = GuidedExtraction->ExtractSection ( + GuidedExtraction, + GuidedHeader, + &NewStreamBuffer, + &NewStreamBufferSize, + &AuthenticationStatus + ); + ASSERT_EFI_ERROR (Status); + // + // OR in the parent stream's aggregagate status. + // + AuthenticationStatus |= Context->ParentStream->AuthenticationStatus & EFI_AGGREGATE_AUTH_STATUS_ALL; + Status = OpenSectionStreamEx ( + NewStreamBufferSize, + NewStreamBuffer, + FALSE, + AuthenticationStatus, + &Context->ChildNode->EncapsulatedStreamHandle + ); + ASSERT_EFI_ERROR (Status); + } + + // + // If above, the stream did not close successfully, it indicates it's + // alread been closed by someone, so just destroy the event and be done with + // it. + // + + CoreCloseEvent (Event); + CoreFreePool (Context); +} + + +STATIC +VOID +FreeChildNode ( + IN CORE_SECTION_CHILD_NODE *ChildNode + ) +/*++ + +Routine Description: + Worker function. Destructor for child nodes. + +Arguments: + ChildNode - Indicates the node to destroy + +Returns: + none + +--*/ +{ + ASSERT (ChildNode->Signature == CORE_SECTION_CHILD_SIGNATURE); + // + // Remove the child from it's list + // + RemoveEntryList (&ChildNode->Link); + + if (ChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) { + // + // If it's an encapsulating section, we close the resulting section stream. + // CloseSectionStream will free all memory associated with the stream. + // + CloseSectionStream (&mSectionExtraction, ChildNode->EncapsulatedStreamHandle); + } + // + // Last, free the child node itself + // + CoreFreePool (ChildNode); +} + + +STATIC +EFI_STATUS +OpenSectionStreamEx ( + IN UINTN SectionStreamLength, + IN VOID *SectionStream, + IN BOOLEAN AllocateBuffer, + IN UINT32 AuthenticationStatus, + OUT UINTN *SectionStreamHandle + ) +/*++ + + Routine Description: + Worker function. Constructor for section streams. + + Arguments: + SectionStreamLength - Size in bytes of the section stream. + SectionStream - Buffer containing the new section stream. + AllocateBuffer - Indicates whether the stream buffer is to be copied + or the input buffer is to be used in place. + AuthenticationStatus- Indicates the default authentication status for the + new stream. + SectionStreamHandle - A pointer to a caller allocated section stream handle. + + Returns: + EFI_SUCCESS - Stream was added to stream database. + EFI_OUT_OF_RESOURCES - memory allocation failed. + +--*/ +{ + CORE_SECTION_STREAM_NODE *NewStream; + EFI_TPL OldTpl; + + // + // Allocate a new stream + // + NewStream = CoreAllocateBootServicesPool (sizeof (CORE_SECTION_STREAM_NODE)); + if (NewStream == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if (AllocateBuffer) { + // + // if we're here, we're double buffering, allocate the buffer and copy the + // data in + // + if (SectionStreamLength > 0) { + NewStream->StreamBuffer = CoreAllocateBootServicesPool (SectionStreamLength); + if (NewStream->StreamBuffer == NULL) { + CoreFreePool (NewStream); + return EFI_OUT_OF_RESOURCES; + } + // + // Copy in stream data + // + EfiCommonLibCopyMem (NewStream->StreamBuffer, SectionStream, SectionStreamLength); + } else { + // + // It's possible to have a zero length section stream. + // + NewStream->StreamBuffer = NULL; + } + } else { + // + // If were here, the caller has supplied the buffer (it's an internal call) + // so just assign the buffer. This happens when we open section streams + // as a result of expanding an encapsulating section. + // + NewStream->StreamBuffer = SectionStream; + } + + // + // Initialize the rest of the section stream + // + NewStream->Signature = CORE_SECTION_STREAM_SIGNATURE; + NewStream->StreamHandle = (UINTN) NewStream; + NewStream->StreamLength = SectionStreamLength; + InitializeListHead (&NewStream->Children); + NewStream->AuthenticationStatus = AuthenticationStatus; + + // + // Add new stream to stream list + // + OldTpl = CoreRaiseTpl (EFI_TPL_NOTIFY); + InsertTailList (&mStreamRoot, &NewStream->Link); + CoreRestoreTpl (OldTpl); + + *SectionStreamHandle = NewStream->StreamHandle; + + return EFI_SUCCESS; +} + + +STATIC +EFI_STATUS +FindStreamNode ( + IN UINTN SearchHandle, + OUT CORE_SECTION_STREAM_NODE **FoundStream + ) +/*++ + + Routine Description: + Worker function. Search stream database for requested stream handle. + + Arguments: + SearchHandle - Indicates which stream to look for. + FoundStream - Output pointer to the found stream. + + Returns: + EFI_SUCCESS - StreamHandle was found and *FoundStream contains + the stream node. + EFI_NOT_FOUND - SearchHandle was not found in the stream database. + +--*/ +{ + CORE_SECTION_STREAM_NODE *StreamNode; + + if (!IsListEmpty (&mStreamRoot)) { + StreamNode = STREAM_NODE_FROM_LINK (GetFirstNode (&mStreamRoot)); + for (;;) { + if (StreamNode->StreamHandle == SearchHandle) { + *FoundStream = StreamNode; + return EFI_SUCCESS; + } else if (IsNodeAtEnd (&mStreamRoot, &StreamNode->Link)) { + break; + } else { + StreamNode = STREAM_NODE_FROM_LINK (GetNextNode (&mStreamRoot, &StreamNode->Link)); + } + } + } + + return EFI_NOT_FOUND; +} + + +STATIC +BOOLEAN +IsValidSectionStream ( + IN VOID *SectionStream, + IN UINTN SectionStreamLength + ) +/*++ + +Routine Description: + Check if a stream is valid. + +Arguments: + SectionStream - The section stream to be checked + SectionStreamLength - The length of section stream + +Returns: + TRUE + FALSE + +--*/ +{ + UINTN TotalLength; + UINTN SectionLength; + EFI_COMMON_SECTION_HEADER *SectionHeader; + EFI_COMMON_SECTION_HEADER *NextSectionHeader; + + TotalLength = 0; + SectionHeader = (EFI_COMMON_SECTION_HEADER *)SectionStream; + + while (TotalLength < SectionStreamLength) { + SectionLength = SECTION_SIZE (SectionHeader); + TotalLength += SectionLength; + + if (TotalLength == SectionStreamLength) { + return TRUE; + } + + // + // Move to the next byte following the section... + // + SectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) SectionHeader + SectionLength); + + // + // Figure out where the next section begins + // + NextSectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINTN) SectionHeader + 3); + NextSectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINTN) NextSectionHeader & ~(UINTN)3); + TotalLength += (UINTN) NextSectionHeader - (UINTN) SectionHeader; + SectionHeader = NextSectionHeader; + } + + ASSERT (FALSE); + return FALSE; +} diff --git a/EDK/Foundation/Core/Dxe/x64/Processor.h b/EDK/Foundation/Core/Dxe/x64/Processor.h new file mode 100644 index 0000000..cdf2992 --- /dev/null +++ b/EDK/Foundation/Core/Dxe/x64/Processor.h @@ -0,0 +1,27 @@ +/*++ + +Copyright (c) 2005, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + Processor.h + +Abstract: + This file contains the x64 processor specific definitions + +--*/ + +#ifndef _PROCESSOR_H_ +#define _PROCESSOR_H_ + +#define EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT (EFI_PAGE_SIZE) + +#define DEFAULT_PAGE_ALLOCATION (EFI_PAGE_SIZE) + +#endif -- cgit v1.2.3