diff options
author | AJFISH <AJFISH@6f19259b-4bc3-4df7-8a09-765794883524> | 2009-12-06 01:57:05 +0000 |
---|---|---|
committer | AJFISH <AJFISH@6f19259b-4bc3-4df7-8a09-765794883524> | 2009-12-06 01:57:05 +0000 |
commit | 2ef2b01e07c02db339f34004445734a2dbdd80e1 (patch) | |
tree | 19532a6be8d8bdb0aef04bd00c1efb582f6dc841 /EmbeddedPkg/Library | |
parent | f7753a96ba1653ddd31b01c198a352f6332ac404 (diff) | |
download | edk2-platforms-2ef2b01e07c02db339f34004445734a2dbdd80e1.tar.xz |
Adding support for BeagleBoard.
ArmPkg - Supoprt for ARM specific things that can change as the architecture changes. Plus semihosting JTAG drivers.
EmbeddedPkg - Generic support for an embeddded platform. Including a light weight command line shell.
BeagleBoardPkg - Platform specifics for BeagleBoard. SD Card works, but USB has issues. Looks like a bug in the open source USB stack (Our internal stack works fine).
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@9518 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'EmbeddedPkg/Library')
37 files changed, 8256 insertions, 0 deletions
diff --git a/EmbeddedPkg/Library/EblAddExternalCommandLib/EblAddExternalCommandLib.c b/EmbeddedPkg/Library/EblAddExternalCommandLib/EblAddExternalCommandLib.c new file mode 100644 index 0000000000..fcb533c8b7 --- /dev/null +++ b/EmbeddedPkg/Library/EblAddExternalCommandLib/EblAddExternalCommandLib.c @@ -0,0 +1,156 @@ +/** @file
+ Add external EblCmd Lib
+
+ Copyright (c) 2007, Intel Corporation<BR>
+ Portions copyright (c) 2008-2009, Apple Inc. All rights reserved.
+
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+
+#include <PiDxe.h>
+#include <Library/BaseLib.h>
+#include <Library/EblAddExternalCommandLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+
+STATIC BOOLEAN gInstalledCommand = FALSE;
+STATIC EFI_EVENT mEblCommandRegistration = NULL;
+
+STATIC const EBL_COMMAND_TABLE *mAddExternalCmdLibTemplate = NULL;
+STATIC UINTN mAddExternalCmdLibTemplateSize = 0;
+EBL_ADD_COMMAND_PROTOCOL *gEblExternalCommand = NULL;
+
+
+/**
+ Return a keypress or optionally timeout if a timeout value was passed in.
+ An optional callback funciton is called evey second when waiting for a
+ timeout.
+
+ @param Key EFI Key information returned
+ @param TimeoutInSec Number of seconds to wait to timeout
+ @param CallBack Callback called every second during the timeout wait
+
+ @return EFI_SUCCESS Key was returned
+ @return EFI_TIMEOUT If the TimoutInSec expired
+
+**/
+EFI_STATUS
+EFIAPI
+EblGetCharKey (
+ IN OUT EFI_INPUT_KEY *Key,
+ IN UINTN TimeoutInSec,
+ IN EBL_GET_CHAR_CALL_BACK CallBack OPTIONAL
+ )
+{
+ if (gEblExternalCommand != NULL) {
+ return gEblExternalCommand->EblGetCharKey (Key, TimeoutInSec, CallBack);
+ }
+ return EFI_TIMEOUT;
+}
+
+
+/**
+ This routine is used prevent command output data from scrolling off the end
+ of the screen. The global gPageBreak is used to turn on or off this feature.
+ If the CurrentRow is near the end of the screen pause and print out a prompt
+ If the use hits Q to quit return TRUE else for any other key return FALSE.
+ PrefixNewline is used to figure out if a newline is needed before the prompt
+ string. This depends on the last print done before calling this function.
+ CurrentRow is updated by one on a call or set back to zero if a prompt is
+ needed.
+
+ @param CurrentRow Used to figure out if its the end of the page and updated
+ @param PrefixNewline Did previous print issue a newline
+
+ @return TRUE if Q was hit to quit, FALSE in all other cases.
+
+**/
+BOOLEAN
+EFIAPI
+EblAnyKeyToContinueQtoQuit (
+ IN UINTN *CurrentRow,
+ IN BOOLEAN PrefixNewline
+ )
+{
+ if (gEblExternalCommand != NULL) {
+ return gEblExternalCommand->EblAnyKeyToContinueQtoQuit (CurrentRow, PrefixNewline);
+ }
+ return FALSE;
+}
+
+
+
+/**
+ Update mFvbEntry. Add new entry, or update existing entry if Fvb protocol is
+ reinstalled.
+
+ @param Event The Event that is being processed
+ @param Context Event Context
+
+**/
+VOID
+EFIAPI
+EblAddCommandNotificationEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+
+ if (!gInstalledCommand) {
+ Status = gBS->LocateProtocol (&gEfiEblAddCommandProtocolGuid, NULL, (VOID **)&gEblExternalCommand);
+ if (!EFI_ERROR (Status)) {
+ gEblExternalCommand->AddCommands (mAddExternalCmdLibTemplate, mAddExternalCmdLibTemplateSize);
+ gInstalledCommand = TRUE;
+ }
+ }
+}
+
+
+
+/**
+ The user Entry Point for the driver. The user code starts with this function
+ as the real entry point for the image goes into a library that calls this
+ function.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+EblAddExternalCommands (
+ IN const EBL_COMMAND_TABLE *EntryArray,
+ IN UINTN ArrayCount
+ )
+{
+ if (mAddExternalCmdLibTemplate != NULL) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ mAddExternalCmdLibTemplate = EntryArray;
+ mAddExternalCmdLibTemplateSize = ArrayCount;
+
+ EfiCreateProtocolNotifyEvent (
+ &gEfiEblAddCommandProtocolGuid,
+ TPL_CALLBACK,
+ EblAddCommandNotificationEvent,
+ NULL,
+ &mEblCommandRegistration
+ );
+
+ return EFI_SUCCESS;
+}
+
diff --git a/EmbeddedPkg/Library/EblAddExternalCommandLib/EblAddExternalCommandLib.inf b/EmbeddedPkg/Library/EblAddExternalCommandLib/EblAddExternalCommandLib.inf new file mode 100644 index 0000000000..5b0af6e75a --- /dev/null +++ b/EmbeddedPkg/Library/EblAddExternalCommandLib/EblAddExternalCommandLib.inf @@ -0,0 +1,47 @@ +#%HEADER%
+#/** @file
+# Component description file for the entry point to a EFIDXE Drivers
+#
+# Library to abstract Framework extensions that conflict with UEFI 2.0 Specification
+# Copyright (c) 2007 - 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.
+#
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = EblAddExternalCommandLib
+ FILE_GUID = 9195D970-C6F7-484E-8013-5B03C89C3B81
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = EblAddExternalCommandLib|DXE_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+ EblAddExternalCommandLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ UefiLib
+
+[Protocols]
+
+[Guids]
+
\ No newline at end of file diff --git a/EmbeddedPkg/Library/EblCmdLibNull/EblCmdLibNull.c b/EmbeddedPkg/Library/EblCmdLibNull/EblCmdLibNull.c new file mode 100644 index 0000000000..5cbdfdb15a --- /dev/null +++ b/EmbeddedPkg/Library/EblCmdLibNull/EblCmdLibNull.c @@ -0,0 +1,28 @@ +/** @file
+ Null EblCmdLib
+
+ Copyright (c) 2007, Intel Corporation<BR>
+ Portions copyright (c) 2008-2009, Apple Inc. All rights reserved.
+
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+
+#include <PiDxe.h>
+#include <Library/EblCmdLib.h>
+
+
+VOID
+EblInitializeExternalCmd (
+ VOID
+ )
+{
+ return;
+}
diff --git a/EmbeddedPkg/Library/EblCmdLibNull/EblCmdLibNull.inf b/EmbeddedPkg/Library/EblCmdLibNull/EblCmdLibNull.inf new file mode 100644 index 0000000000..b40935b838 --- /dev/null +++ b/EmbeddedPkg/Library/EblCmdLibNull/EblCmdLibNull.inf @@ -0,0 +1,45 @@ +#%HEADER%
+#/** @file
+# Component description file for the entry point to a EFIDXE Drivers
+#
+# Library to abstract Framework extensions that conflict with UEFI 2.0 Specification
+# Copyright (c) 2007 - 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.
+#
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = EblCmdLibNull
+ FILE_GUID = 3513C4E2-06D6-4921-9C2B-E938777BA79E
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = EfiCmdLib|DXE_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+ EblCmdLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+
+[LibraryClasses]
+
+[Protocols]
+
+[Guids]
+
\ No newline at end of file diff --git a/EmbeddedPkg/Library/EblNetworkLib/EblNetworkLib.c b/EmbeddedPkg/Library/EblNetworkLib/EblNetworkLib.c new file mode 100644 index 0000000000..13766c88b2 --- /dev/null +++ b/EmbeddedPkg/Library/EblNetworkLib/EblNetworkLib.c @@ -0,0 +1,173 @@ +/** @file + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include <Uefi.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/UefiRuntimeServicesTableLib.h> +#include <Library/UefiBootServicesTableLib.h> + +#include <Protocol/SimpleNetwork.h> +#include <Protocol/PxeBaseCode.h> + + +BOOLEAN gUseIpv6 = FALSE; + +EFI_STATUS +EFIAPI +EblGetCurrentIpAddress ( + IN OUT EFI_IP_ADDRESS *Ip + ) +{ + EFI_STATUS Status; + EFI_PXE_BASE_CODE_PROTOCOL *Pxe; + + Status = gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (VOID **)&Pxe); + if (EFI_ERROR(Status)) { + return Status; + } + + Status = Pxe->Start (Pxe, gUseIpv6); + if (EFI_ERROR(Status) && (Status != EFI_ALREADY_STARTED)) { + return Status; + } + + CopyMem (Ip, &Pxe->Mode->StationIp, sizeof (EFI_IP_ADDRESS)); + + return Status; +} + + +EFI_STATUS +EFIAPI +EblGetCurrentMacAddress ( + IN OUT EFI_MAC_ADDRESS *Mac + ) +{ + EFI_STATUS Status; + EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNet; + + Status = gBS->LocateProtocol (&gEfiSimpleNetworkProtocolGuid, NULL, (VOID **)&SimpleNet); + if (EFI_ERROR(Status)) { + return Status; + } + + CopyMem (SimpleNet->Mode->CurrentAddress.Addr, Mac, sizeof (EFI_MAC_ADDRESS)); + return Status; +} + + +CHAR8 * +EFIAPI +EblLoadFileBootTypeString ( + IN EFI_HANDLE Handle + ) +{ + EFI_STATUS Status; + VOID *NullPtr; + + Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, &NullPtr); + if (!EFI_ERROR (Status)) { + return "EFI PXE Network Boot"; + } + + return ""; +} + +EFI_STATUS +EFIAPI +EblPerformDHCP ( + IN BOOLEAN SortOffers + ) +{ + EFI_STATUS Status; + EFI_PXE_BASE_CODE_PROTOCOL *Pxe; + + Status = gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (VOID **)&Pxe); + if (EFI_ERROR(Status)) { + return Status; + } + + Status = Pxe->Start (Pxe, gUseIpv6); + if (EFI_ERROR(Status) && (Status != EFI_ALREADY_STARTED)) { + return Status; + } + + Status = Pxe->Dhcp(Pxe, TRUE); + return Status; +} + + +EFI_STATUS +EFIAPI +EblSetStationIp ( + IN EFI_IP_ADDRESS *NewStationIp, OPTIONAL + IN EFI_IP_ADDRESS *NewSubnetMask OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_PXE_BASE_CODE_PROTOCOL *Pxe; + + Status = gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (VOID **)&Pxe); + if (EFI_ERROR(Status)) { + return Status; + } + + Status = Pxe->Start (Pxe, gUseIpv6); + if (EFI_ERROR(Status) && (Status != EFI_ALREADY_STARTED)) { + return Status; + } + + Status = Pxe->SetStationIp (Pxe, NewStationIp, NewSubnetMask); + return Status; +} + + +EFI_STATUS +EFIAPI +EblMtftp ( + IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation, + IN OUT VOID *BufferPtr OPTIONAL, + IN BOOLEAN Overwrite, + IN OUT UINT64 *BufferSize, + IN UINTN *BlockSize OPTIONAL, + IN EFI_IP_ADDRESS *ServerIp, + IN UINT8 *Filename OPTIONAL, + IN EFI_PXE_BASE_CODE_MTFTP_INFO *Info OPTIONAL, + IN BOOLEAN DontUseBuffer + ) +{ + EFI_STATUS Status; + EFI_PXE_BASE_CODE_PROTOCOL *Pxe; + + Status = gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (VOID **)&Pxe); + if (EFI_ERROR(Status)) { + return Status; + } + + Status = Pxe->Mtftp ( + Pxe, + Operation, + BufferPtr, + Overwrite, + BufferSize, + BlockSize, + ServerIp, + Filename, + Info, + DontUseBuffer + ); + return Status; +} + diff --git a/EmbeddedPkg/Library/EblNetworkLib/EblNetworkLib.inf b/EmbeddedPkg/Library/EblNetworkLib/EblNetworkLib.inf new file mode 100644 index 0000000000..f46242fc62 --- /dev/null +++ b/EmbeddedPkg/Library/EblNetworkLib/EblNetworkLib.inf @@ -0,0 +1,28 @@ +#%HEADER%
+#
+# Copyright (c) 2005 - 2009 Apple Computer, Inc. All rights reserved.
+#
+#
+#
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = EblNetworkLib
+ FILE_GUID = D885869A-7869-47DB-9429-DE03C318BCFD
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = EblNetworkLib|DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+[sources.common]
+ EblNetworkLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+
+[Protocols]
+ gEfiSimpleNetworkProtocolGuid
+ gEfiPxeBaseCodeProtocolGuid
+
+[Depex]
+ TRUE
\ No newline at end of file diff --git a/EmbeddedPkg/Library/EfiFileLib/EfiFileLib.c b/EmbeddedPkg/Library/EfiFileLib/EfiFileLib.c new file mode 100644 index 0000000000..e98651b14d --- /dev/null +++ b/EmbeddedPkg/Library/EfiFileLib/EfiFileLib.c @@ -0,0 +1,1483 @@ +/** @file + File IO routines inspired by Streams with an EFI flavor + + Copyright (c) 2007, Intel Corporation<BR> + Portions copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + Basic support for opening files on different device types. The device string + is in the form of DevType:Path. Current DevType is required as there is no + current mounted device concept of current working directory concept implement + by this library. + + Device names are case insensative and only check the leading characters for + unique matches. Thus the following are all the same: + LoadFile0: + l0: + L0: + Lo0: + + Supported Device Names: + A0x1234:0x12 - A memory buffer starting at address 0x1234 for 0x12 bytes + l1: - EFI LoadFile device one. + B0: - EFI BlockIo zero. + fs3: - EFI Simple File System device 3 + Fv2: - EFI Firmware VOlume device 2 + 10.0.1.102: - TFTP service IP followed by the file name +**/ + +#include <PiDxe.h> +#include <Protocol/BlockIo.h> +#include <Protocol/DiskIo.h> +#include <Protocol/SimpleFileSystem.h> +#include <Protocol/FirmwareVolume2.h> +#include <Protocol/LoadFile.h> +#include <Protocol/FirmwareVolumeBlock.h> +#include <Guid/FileInfo.h> +#include <Library/BaseLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/DevicePathLib.h> +#include <Library/PrintLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/UefiLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiRuntimeServicesTableLib.h> +#include <Library/DebugLib.h> +#include <Library/EfiFileLib.h> +#include <Library/PcdLib.h> +#include <Library/EblNetworkLib.h> + + +#define EFI_OPEN_FILE_GUARD_HEADER 0x4B4D4641 +#define EFI_OPEN_FILE_GUARD_FOOTER 0x444D5A56 + +// Need to defend against this overflowing +#define MAX_CMD_LINE 0x200 + +typedef struct { + UINT32 Header; + EFI_OPEN_FILE File; + UINT32 Footer; +} EFI_OPEN_FILE_GUARD; + + +// globals to store current open device info +EFI_HANDLE *mBlkIo = NULL; +UINTN mBlkIoCount = 0; + +EFI_HANDLE *mFs = NULL; +UINTN mFsCount = 0; +// mFsInfo[] array entries must match mFs[] handles +EFI_FILE_SYSTEM_INFO **mFsInfo = NULL; + +EFI_HANDLE *mFv = NULL; +UINTN mFvCount = 0; +EFI_HANDLE *mLoadFile = NULL; +UINTN mLoadFileCount = 0; + + + +/** + Internal worker function to validate a File handle. + + @param File Open File Handle + + @return TRUE File is valid + @return FALSE File is not valid + + +**/ +BOOLEAN +FileHandleValid ( + IN EFI_OPEN_FILE *File + ) +{ + EFI_OPEN_FILE_GUARD *GuardFile; + + // Look right before and after file structure for the correct signatures + GuardFile = BASE_CR (File, EFI_OPEN_FILE_GUARD, File); + if ((GuardFile->Header != EFI_OPEN_FILE_GUARD_HEADER) || + (GuardFile->Footer != EFI_OPEN_FILE_GUARD_FOOTER) ) { + return FALSE; + } + + return TRUE; +} + +/** + Internal worker function. If Buffer is not NULL free it. + + @param Buffer Buffer to FreePool() + +**/ +VOID +EblFreePool ( + IN VOID *Buffer + ) +{ + if (Buffer != NULL) { + FreePool (Buffer); + } +} + +/** + Update Device List Global Variables + +**/ +VOID +EblUpdateDeviceLists ( + VOID + ) +{ + EFI_STATUS Status; + UINTN Size; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs; + EFI_FILE_HANDLE Root; + UINTN Index; + + if (mBlkIo != NULL) { + FreePool (mBlkIo); + } + gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &mBlkIoCount, &mBlkIo); + + if (mFv != NULL) { + FreePool (mFv); + } + gBS->LocateHandleBuffer (ByProtocol, &gEfiFirmwareVolume2ProtocolGuid, NULL, &mFvCount, &mFv); + + if (mLoadFile != NULL) { + FreePool (mLoadFile); + } + gBS->LocateHandleBuffer (ByProtocol, &gEfiLoadFileProtocolGuid, NULL, &mLoadFileCount, &mLoadFile); + + if (mFs != NULL) { + FreePool (mFs); + } + + if (&mFsInfo[0] != NULL) { + // Need to Free the mFsInfo prior to reclaculating mFsCount so don't move this code + for (Index = 0; Index < mFsCount; Index++) { + if (mFsInfo[Index] != NULL) { + FreePool (mFsInfo[Index]); + } + } + FreePool (mFsInfo); + } + + gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &mFsCount, &mFs); + + + mFsInfo = AllocateZeroPool (mFsCount * sizeof (EFI_FILE_SYSTEM_INFO *)); + if (mFsInfo == NULL) { + // If we can't do this then we can't support file system entries + mFsCount = 0; + } else { + // Loop through all the file system structures and cache the file system info data + for (Index =0; Index < mFsCount; Index++) { + Status = gBS->HandleProtocol (mFs[Index], &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs); + if (!EFI_ERROR (Status)) { + Status = Fs->OpenVolume (Fs, &Root); + if (!EFI_ERROR (Status)) { + // Get information about the volume + Size = 0; + Status = Root->GetInfo (Root, &gEfiFileSystemInfoGuid, &Size, mFsInfo[Index]); + if (Status == EFI_BUFFER_TOO_SMALL) { + mFsInfo[Index] = AllocatePool (Size); + Status = Root->GetInfo (Root, &gEfiFileSystemInfoGuid, &Size, mFsInfo[Index]); + } + + Root->Close (Root); + } + } + } + } +} + + +/** + PathName is in the form <device name>:<path> for example fs1:\ or ROOT:\. + Return TRUE if the <devce name> prefix of PathName matches a file system + Volume Name. MatchIndex is the array index in mFsInfo[] of the match, + and it can be used with mFs[] to find the handle that needs to be opened + + @param PathName PathName to check + @param FileStart Index of the first character of the <path> + @param MatchIndex Index in mFsInfo[] that matches + + @return TRUE PathName matches a Volume Label and MatchIndex is valid + @return FALSE PathName does not match a Volume Label MatchIndex undefined + +**/ +BOOLEAN +EblMatchVolumeName ( + IN CHAR8 *PathName, + IN UINTN FileStart, + OUT UINTN *MatchIndex + ) +{ + UINTN Index; + UINTN Compare; + UINTN VolStrLen; + BOOLEAN Match; + + for (Index =0; Index < mFsCount; Index++) { + if (mFsInfo[Index] == NULL) { + // FsInfo is not valid so skip it + continue; + } + VolStrLen = StrLen (mFsInfo[Index]->VolumeLabel); + for (Compare = 0, Match = TRUE; Compare < (FileStart - 1); Compare++) { + if (Compare > VolStrLen) { + Match = FALSE; + break; + } + if (PathName[Compare] != (CHAR8)mFsInfo[Index]->VolumeLabel[Compare]) { + // If the VolumeLabel has a space allow a _ to match with it in addition to ' ' + if (!((PathName[Compare] == '_') && (mFsInfo[Index]->VolumeLabel[Compare] == L' '))) { + Match = FALSE; + break; + } + } + } + if (Match) { + *MatchIndex = Index; + return TRUE; + } + } + + return FALSE; +} + + +/** + Return the number of devices of the current type active in the system + + @param Type Device type to check + + @return 0 Invalid type + +**/ +UINTN +EfiGetDeviceCounts ( + IN EFI_OPEN_FILE_TYPE DeviceType + ) +{ + switch (DeviceType) { + case EfiOpenLoadFile: + return mLoadFileCount; + case EfiOpenFirmwareVolume: + return mFvCount; + case EfiOpenFileSystem: + return mFsCount; + case EfiOpenBlockIo: + return mBlkIoCount; + default: + return 0; + } +} + +EFI_STATUS +ConvertIpStringToEfiIp ( + IN CHAR8 *PathName, + OUT EFI_IP_ADDRESS *ServerIp + ) +{ + CHAR8 *Str; + + Str = PathName; + ServerIp->v4.Addr[0] = (UINT8)AsciiStrDecimalToUintn (Str); + + Str = AsciiStrStr (Str, "."); + if (Str == NULL) { + return EFI_DEVICE_ERROR; + } + + ServerIp->v4.Addr[1] = (UINT8)AsciiStrDecimalToUintn (++Str); + + Str = AsciiStrStr (Str, "."); + if (Str == NULL) { + return EFI_DEVICE_ERROR; + } + + ServerIp->v4.Addr[2] = (UINT8)AsciiStrDecimalToUintn (++Str); + + Str = AsciiStrStr (Str, "."); + if (Str == NULL) { + return EFI_DEVICE_ERROR; + } + + ServerIp->v4.Addr[3] = (UINT8)AsciiStrDecimalToUintn (++Str); + + return EFI_SUCCESS; +} + + +/** + Internal work function to extract a device number from a string skipping + text. Easy way to extract numbers from strings like blk7:. + + @param Str String to extract device number form + + @return -1 Device string is not valid + @return Device # + +**/ +UINTN +EblConvertDevStringToNumber ( + IN CHAR8 *Str + ) +{ + UINTN Max; + UINTN Index; + + + // Find the first digit + Max = AsciiStrLen (Str); + for (Index = 0; !((*Str >= '0') && (*Str <= '9')) && (Index < Max); Index++) { + Str++; + } + if (Index == Max) { + return (UINTN)-1; + } + + return AsciiStrDecimalToUintn (Str); +} + + +/** + Internal work function to fill in EFI_OPEN_FILE information for the Fs and BlkIo + + @param File Open file handle + @param FileName Name of file after device stripped off + + +**/ +EFI_STATUS +EblFileDevicePath ( + IN OUT EFI_OPEN_FILE *File, + IN CHAR8 *FileName, + IN CONST UINT64 OpenMode + ) +{ + EFI_STATUS Status; + UINTN Size; + FILEPATH_DEVICE_PATH *FilePath; + EFI_DEVICE_PATH_PROTOCOL *FileDevicePath; + CHAR16 UnicodeFileName[MAX_PATHNAME]; + EFI_BLOCK_IO_PROTOCOL *BlkIo; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs; + EFI_FILE_HANDLE Root; + + + if ( *FileName != 0 ) { + AsciiStrToUnicodeStr (FileName, UnicodeFileName); + } else { + AsciiStrToUnicodeStr ("\\", UnicodeFileName); + } + + Size = StrSize (UnicodeFileName); + FileDevicePath = AllocatePool (Size + SIZE_OF_FILEPATH_DEVICE_PATH + sizeof (EFI_DEVICE_PATH_PROTOCOL)); + if (FileDevicePath != NULL) { + FilePath = (FILEPATH_DEVICE_PATH *) FileDevicePath; + FilePath->Header.Type = MEDIA_DEVICE_PATH; + FilePath->Header.SubType = MEDIA_FILEPATH_DP; + CopyMem (&FilePath->PathName, UnicodeFileName, Size); + SetDevicePathNodeLength (&FilePath->Header, Size + SIZE_OF_FILEPATH_DEVICE_PATH); + SetDevicePathEndNode (NextDevicePathNode (&FilePath->Header)); + + if (File->EfiHandle != NULL) { + File->DevicePath = DevicePathFromHandle (File->EfiHandle); + } + + File->DevicePath = AppendDevicePath (File->DevicePath, FileDevicePath); + FreePool (FileDevicePath); + } + + Status = gBS->HandleProtocol (File->EfiHandle, &gEfiBlockIoProtocolGuid, (VOID **)&BlkIo); + if (!EFI_ERROR (Status)) { + CopyMem (&File->FsBlockIoMedia, BlkIo->Media, sizeof (EFI_BLOCK_IO_MEDIA)); + + // If we are not opening the device this will get over written with file info + File->MaxPosition = MultU64x32 (BlkIo->Media->LastBlock + 1, BlkIo->Media->BlockSize); + } + + if (File->Type == EfiOpenFileSystem) { + Status = gBS->HandleProtocol (File->EfiHandle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs); + if (!EFI_ERROR (Status)) { + Status = Fs->OpenVolume (Fs, &Root); + if (!EFI_ERROR (Status)) { + // Get information about the volume + Size = 0; + Status = Root->GetInfo (Root, &gEfiFileSystemInfoGuid, &Size, File->FsInfo); + if (Status == EFI_BUFFER_TOO_SMALL) { + File->FsInfo = AllocatePool (Size); + Status = Root->GetInfo (Root, &gEfiFileSystemInfoGuid, &Size, File->FsInfo); + } + + // Get information about the file + Status = Root->Open (Root, &File->FsFileHandle, UnicodeFileName, OpenMode, 0); + if (!EFI_ERROR (Status)) { + Size = 0; + Status = File->FsFileHandle->GetInfo (File->FsFileHandle, &gEfiFileInfoGuid, &Size, NULL); + if (Status == EFI_BUFFER_TOO_SMALL) { + File->FsFileInfo = AllocatePool (Size); + Status = File->FsFileHandle->GetInfo (File->FsFileHandle, &gEfiFileInfoGuid, &Size, File->FsFileInfo); + if (!EFI_ERROR (Status)) { + File->Size = (UINTN)File->FsFileInfo->FileSize; + File->MaxPosition = (UINT64)File->Size; + } + } + } + + Root->Close (Root); + } + } + } else if (File->Type == EfiOpenBlockIo) { + File->Size = (UINTN)File->MaxPosition; + } + + return Status; +} + +#define ToUpper(a) ((((a) >= 'a') && ((a) <= 'z')) ? ((a) - 'a' + 'A') : (a)) + +EFI_STATUS +CompareGuidToString ( + IN EFI_GUID *Guid, + IN CHAR8 *String + ) +{ + CHAR8 AsciiGuid[64]; + CHAR8 *StringPtr; + CHAR8 *GuidPtr; + + AsciiSPrint (AsciiGuid, sizeof(AsciiGuid), "%g", Guid); + + StringPtr = String; + GuidPtr = AsciiGuid; + + while ((*StringPtr != '\0') && (*GuidPtr != '\0')) { + // Skip dashes + if (*StringPtr == '-') { + StringPtr++; + continue; + } + + if (*GuidPtr == '-') { + GuidPtr++; + continue; + } + + if (ToUpper(*StringPtr) != ToUpper(*GuidPtr)) { + return EFI_NOT_FOUND; + } + + StringPtr++; + GuidPtr++; + } + + return EFI_SUCCESS; +} + + +/** + Internal work function to fill in EFI_OPEN_FILE information for the FV + + @param File Open file handle + @param FileName Name of file after device stripped off + + +**/ +EFI_STATUS +EblFvFileDevicePath ( + IN OUT EFI_OPEN_FILE *File, + IN CHAR8 *FileName, + IN CONST UINT64 OpenMode + ) +{ + EFI_STATUS Status; + EFI_STATUS GetNextFileStatus; + MEDIA_FW_VOL_FILEPATH_DEVICE_PATH DevicePathNode; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + UINTN Key; + UINT32 AuthenticationStatus; + CHAR8 AsciiSection[MAX_PATHNAME]; + VOID *Section; + UINTN SectionSize; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; + EFI_LBA Lba; + UINTN BlockSize; + UINTN NumberOfBlocks; + + + Status = gBS->HandleProtocol (File->EfiHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&File->Fv); + if (EFI_ERROR (Status)) { + return Status; + } + + DevicePath = DevicePathFromHandle (File->EfiHandle); + + if (*FileName == '\0') { + File->DevicePath = DuplicateDevicePath (DevicePath); + } else { + Key = 0; + do { + File->FvType = EFI_FV_FILETYPE_ALL; + GetNextFileStatus = File->Fv->GetNextFile ( + File->Fv, + &Key, + &File->FvType, + &File->FvNameGuid, + &File->FvAttributes, + &File->Size + ); + if (!EFI_ERROR (GetNextFileStatus)) { + Section = NULL; + + // Compare GUID first + Status = CompareGuidToString (&File->FvNameGuid, FileName); + if (!EFI_ERROR(Status)) { + break; + } + + Status = File->Fv->ReadSection ( + File->Fv, + &File->FvNameGuid, + EFI_SECTION_USER_INTERFACE, + 0, + &Section, + &SectionSize, + &AuthenticationStatus + ); + if (!EFI_ERROR (Status)) { + UnicodeStrToAsciiStr (Section, AsciiSection); + if (AsciiStriCmp (FileName, AsciiSection) == 0) { + FreePool (Section); + break; + } + FreePool (Section); + } + } + } while (!EFI_ERROR (GetNextFileStatus)); + + if (EFI_ERROR (GetNextFileStatus)) { + return GetNextFileStatus; + } + + File->MaxPosition = File->Size; + EfiInitializeFwVolDevicepathNode (&DevicePathNode, &File->FvNameGuid); + File->DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&DevicePathNode); + } + + + // Get FVB Info about the handle + Status = gBS->HandleProtocol (File->EfiHandle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb); + if (!EFI_ERROR (Status)) { + Status = Fvb->GetPhysicalAddress (Fvb, &File->FvStart); + if (!EFI_ERROR (Status)) { + for (Lba = 0, File->FvSize = 0; ; File->FvSize += (BlockSize * NumberOfBlocks), Lba += NumberOfBlocks) { + Status = Fvb->GetBlockSize (Fvb, Lba, &BlockSize, &NumberOfBlocks); + if (EFI_ERROR (Status)) { + break; + } + } + } + } + + // FVB not required if FV was soft loaded... + return EFI_SUCCESS; +} + + + + +/** + Open a device named by PathName. The PathName includes a device name and + path seperated by a :. See file header for more details on the PathName + syntax. There is no checking to prevent a file from being opened more than + one type. + + SectionType is only used to open an FV. Each file in an FV contains multiple + secitons and only the SectionType section is opened. + + For any file that is opened with EfiOpen() must be closed with EfiClose(). + + @param PathName Path to parse to open + @param OpenMode Same as EFI_FILE.Open() + @param SectionType Section in FV to open. + + @return NULL Open failed + @return Valid EFI_OPEN_FILE handle + +**/ +EFI_OPEN_FILE * +EfiOpen ( + IN CHAR8 *PathName, + IN CONST UINT64 OpenMode, + IN CONST EFI_SECTION_TYPE SectionType + ) +{ + EFI_STATUS Status; + EFI_OPEN_FILE *File; + EFI_OPEN_FILE FileData; + UINTN StrLen; + UINTN FileStart; + UINTN DevNumber = 0; + EFI_OPEN_FILE_GUARD *GuardFile; + BOOLEAN VolumeNameMatch; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + UINTN Size; + EFI_IP_ADDRESS Ip; + + EblUpdateDeviceLists (); + + File = &FileData; + ZeroMem (File, sizeof (EFI_OPEN_FILE)); + File->FvSectionType = SectionType; + + StrLen = AsciiStrSize (PathName); + if (StrLen <= 2) { + // Smallest valid path is 1 char and a null + return NULL; + } + + for (FileStart = 0; FileStart < StrLen; FileStart++) { + if (PathName[FileStart] == ':') { + FileStart++; + break; + } + } + + if (FileStart == 0) { + // We could add a current working diretory concept + return NULL; + } + + // + // Matching volume name has precedence over handle based names + // + VolumeNameMatch = EblMatchVolumeName (PathName, FileStart, &DevNumber); + if (!VolumeNameMatch) { + DevNumber = EblConvertDevStringToNumber ((CHAR8 *)PathName); + } + + File->DeviceName = AllocatePool (StrLen); + AsciiStrCpy (File->DeviceName, PathName); + File->DeviceName[FileStart - 1] = '\0'; + File->FileName = &File->DeviceName[FileStart]; + + // + // Use best match algorithm on the dev names so we only need to look at the + // first few charters to match the full device name. Short name forms are + // legal from the caller. + // + Status = EFI_SUCCESS; + if (*PathName == 'f' || *PathName == 'F' || VolumeNameMatch) { + if (PathName[1] == 's' || PathName[1] == 'S' || VolumeNameMatch) { + if (DevNumber >= mFsCount) { + goto ErrorExit; + } + File->Type = EfiOpenFileSystem; + File->EfiHandle = mFs[DevNumber]; + Status = EblFileDevicePath (File, &PathName[FileStart], OpenMode); + + } else if (PathName[1] == 'v' || PathName[1] == 'V') { + if (DevNumber >= mFvCount) { + goto ErrorExit; + } + File->Type = EfiOpenFirmwareVolume; + File->EfiHandle = mFv[DevNumber]; + + if ((PathName[FileStart] == '/') || (PathName[FileStart] == '\\')) { + // Skip leading / as its not really needed for the FV since no directories are supported + FileStart++; + } + Status = EblFvFileDevicePath (File, &PathName[FileStart], OpenMode); + } + } else if ((*PathName == 'A') || (*PathName == 'a')) { + // Handle a:0x10000000:0x1234 address form a:ADDRESS:SIZE + File->Type = EfiOpenMemoryBuffer; + // 1st colon is at PathName[FileStart - 1] + File->Buffer = (VOID *)AsciiStrHexToUintn (&PathName[FileStart]); + + // Find 2nd colon + while ((PathName[FileStart] != ':') && (PathName[FileStart] != '\0')) { + FileStart++; + } + + // If we ran out of string, there's no extra data + if (PathName[FileStart] == '\0') { + File->Size = 0; + } else { + File->Size = AsciiStrHexToUintn (&PathName[FileStart + 1]); + } + + // if there's no number after the second colon, default + // the end of memory + if (File->Size == 0) { + File->Size = (UINTN)(0 - (UINTN)File->Buffer); + } + + File->MaxPosition = File->Size; + File->BaseOffset = (UINTN)File->Buffer; + + } else if (*PathName== 'l' || *PathName == 'L') { + if (DevNumber >= mLoadFileCount) { + goto ErrorExit; + } + File->Type = EfiOpenLoadFile; + File->EfiHandle = mLoadFile[DevNumber]; + + Status = gBS->HandleProtocol (File->EfiHandle, &gEfiLoadFileProtocolGuid, (VOID **)&File->LoadFile); + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + Status = gBS->HandleProtocol (File->EfiHandle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePath); + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + File->DevicePath = DuplicateDevicePath (DevicePath); + + } else if (*PathName == 'b' || *PathName == 'B') { + // Handle b#:0x10000000:0x1234 address form b#:ADDRESS:SIZE + if (DevNumber >= mBlkIoCount) { + goto ErrorExit; + } + File->Type = EfiOpenBlockIo; + File->EfiHandle = mBlkIo[DevNumber]; + EblFileDevicePath (File, "", OpenMode); + + // 1st colon is at PathName[FileStart - 1] + File->DiskOffset = AsciiStrHexToUintn (&PathName[FileStart]); + + // Find 2nd colon + while ((PathName[FileStart] != ':') && (PathName[FileStart] != '\0')) { + FileStart++; + } + + // If we ran out of string, there's no extra data + if (PathName[FileStart] == '\0') { + Size = 0; + } else { + Size = AsciiStrHexToUintn (&PathName[FileStart + 1]); + } + + // if a zero size is passed in (or the size is left out entirely), + // go to the end of the device. + if (Size == 0) { + File->Size = File->Size - File->DiskOffset; + } else { + File->Size = Size; + } + + File->MaxPosition = File->Size; + File->BaseOffset = File->DiskOffset; + } else if ((*PathName) >= '0' && (*PathName <= '9')) { + + // Get current IP address + Status = EblGetCurrentIpAddress (&Ip); + if (EFI_ERROR(Status)) { + AsciiPrint("Device IP Address is not configured.\n"); + goto ErrorExit; + } + + + // Parse X.X.X.X:Filename, only support IPv4 TFTP for now... + File->Type = EfiOpenTftp; + File->IsDirty = FALSE; + File->IsBufferValid = FALSE; + + Status = ConvertIpStringToEfiIp (PathName, &File->ServerIp); + } + + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + GuardFile = (EFI_OPEN_FILE_GUARD *)AllocateZeroPool (sizeof (EFI_OPEN_FILE_GUARD)); + if (GuardFile == NULL) { + goto ErrorExit; + } + + GuardFile->Header = EFI_OPEN_FILE_GUARD_HEADER; + CopyMem (&(GuardFile->File), &FileData, sizeof (EFI_OPEN_FILE)); + GuardFile->Footer = EFI_OPEN_FILE_GUARD_FOOTER; + + return &(GuardFile->File); + +ErrorExit: + FreePool (File->DeviceName); + return NULL; +} + +#define FILE_COPY_CHUNK 0x01000000 + +EFI_STATUS +EfiCopyFile ( + IN CHAR8 *DestinationFile, + IN CHAR8 *SourceFile + ) +{ + EFI_OPEN_FILE *Source = NULL; + EFI_OPEN_FILE *Destination = NULL; + EFI_STATUS Status = EFI_SUCCESS; + VOID *Buffer = NULL; + UINTN Size; + UINTN Offset; + UINTN Chunk = FILE_COPY_CHUNK; + + Source = EfiOpen(SourceFile, EFI_FILE_MODE_READ, 0); + if (Source == NULL) { + AsciiPrint("Source file open error.\n"); + Status = EFI_NOT_FOUND; + goto Exit; + } + + Destination = EfiOpen(DestinationFile, EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0); + if (Destination == NULL) { + AsciiPrint("Destination file open error.\n"); + Status = EFI_NOT_FOUND; + goto Exit; + } + + Buffer = AllocatePool(FILE_COPY_CHUNK); + if (Buffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Exit; + } + + Size = EfiTell(Source, NULL); + + for (Offset = 0; Offset + FILE_COPY_CHUNK <= Size; Offset += Chunk) { + Chunk = FILE_COPY_CHUNK; + + Status = EfiRead(Source, Buffer, &Chunk); + if (EFI_ERROR(Status)) { + AsciiPrint("Read file error\n"); + goto Exit; + } + + Status = EfiWrite(Destination, Buffer, &Chunk); + if (EFI_ERROR(Status)) { + AsciiPrint("Write file error\n"); + goto Exit; + } + } + + // Any left over? + if (Offset < Size) { + Chunk = Size - Offset; + + Status = EfiRead(Source, Buffer, &Chunk); + if (EFI_ERROR(Status)) { + AsciiPrint("Read file error\n"); + goto Exit; + } + + Status = EfiWrite(Destination, Buffer, &Chunk); + if (EFI_ERROR(Status)) { + AsciiPrint("Write file error\n"); + goto Exit; + } + } + +Exit: + if (Source != NULL) { + Status = EfiClose(Source); + if (EFI_ERROR(Status)) { + AsciiPrint("Source close error"); + } + } + + if (Destination != NULL) { + Status = EfiClose(Destination); + if (EFI_ERROR(Status)) { + AsciiPrint("Destination close error"); + } + } + + if (Buffer != NULL) { + FreePool(Buffer); + } + + return Status; +} + +/** + Use DeviceType and Index to form a valid PathName and try and open it. + + @param DeviceType Device type to open + @param Index Device Index to use. Zero relative. + + @return NULL Open failed + @return Valid EFI_OPEN_FILE handle + +**/ +EFI_OPEN_FILE * +EfiDeviceOpenByType ( + IN EFI_OPEN_FILE_TYPE DeviceType, + IN UINTN Index + ) +{ + CHAR8 *DevStr; + CHAR8 Path[MAX_CMD_LINE]; + + switch (DeviceType) { + case EfiOpenLoadFile: + DevStr = "loadfile%d:"; + break; + case EfiOpenFirmwareVolume: + DevStr = "fv%d:"; + break; + case EfiOpenFileSystem: + DevStr = "fs%d:"; + break; + case EfiOpenBlockIo: + DevStr = "blk%d:"; + break; + case EfiOpenMemoryBuffer: + DevStr = "a%d:"; + break; + default: + return NULL; + } + + AsciiSPrint (Path, MAX_PATHNAME, DevStr, Index); + + return EfiOpen (Path, EFI_FILE_MODE_READ, 0); +} + + +/** + Close a file handle opened by EfiOpen() and free all resources allocated by + EfiOpen(). + + @param Stream Open File Handle + + @return EFI_INVALID_PARAMETER Stream is not an Open File + @return EFI_SUCCESS Steam closed + +**/ +EFI_STATUS +EfiClose ( + IN EFI_OPEN_FILE *File + ) +{ + EFI_STATUS Status; + UINT64 TftpBufferSize; + + if (!FileHandleValid (File)) { + return EFI_INVALID_PARAMETER; + } + + //Write the buffer contents to TFTP file. + if ((File->Type == EfiOpenTftp) && (File->IsDirty)) { + + TftpBufferSize = File->Size; + Status = EblMtftp ( + EFI_PXE_BASE_CODE_TFTP_WRITE_FILE, + File->Buffer, + TRUE, + &TftpBufferSize, + NULL, + &File->ServerIp, + (UINT8 *)File->FileName, + NULL, + FALSE + ); + if (EFI_ERROR(Status)) { + AsciiPrint("TFTP error during APPLE_NSP_TFTP_WRITE_FILE: %r\n", Status); + return Status; + } + } + + if ((File->Type == EfiOpenLoadFile) || + ((File->Type == EfiOpenTftp) && (File->IsBufferValid == TRUE))) { + EblFreePool(File->Buffer); + } + + EblFreePool (File->DevicePath); + EblFreePool (File->DeviceName); + EblFreePool (File->FsFileInfo); + EblFreePool (File->FsInfo); + + if (File->FsFileHandle != NULL) { + File->FsFileHandle->Close (File->FsFileHandle); + } + + // Need to free File and it's Guard structures + EblFreePool (BASE_CR (File, EFI_OPEN_FILE_GUARD, File)); + return EFI_SUCCESS; +} + + +/** + Return the size of the file represented by Stream. Also return the current + Seek position. Opening a file will enable a valid file size to be returned. + LoadFile is an exception as a load file size is set to zero. + + @param Stream Open File Handle + + @return 0 Stream is not an Open File or a valid LoadFile handle + +**/ +UINTN +EfiTell ( + IN EFI_OPEN_FILE *File, + OUT EFI_LBA *CurrentPosition OPTIONAL + ) +{ + EFI_STATUS Status; + UINT64 BufferSize = 0; + + if (!FileHandleValid (File)) { + return 0; + } + + if (CurrentPosition != NULL) { + *CurrentPosition = File->CurrentPosition; + } + + if (File->Type == EfiOpenLoadFile) { + // Figure out the File->Size + File->Buffer = NULL; + File->Size = 0; + Status = File->LoadFile->LoadFile (File->LoadFile, File->DevicePath, FALSE, &File->Size, File->Buffer); + if (Status != EFI_BUFFER_TOO_SMALL) { + return 0; + } + + File->MaxPosition = (UINT64)File->Size; + } else if (File->Type == EfiOpenTftp) { + + Status = EblMtftp ( + EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, + NULL, + FALSE, + &BufferSize, + NULL, + &File->ServerIp, + (UINT8 *)File->FileName, + NULL, + TRUE + ); + if (EFI_ERROR(Status)) { + AsciiPrint("TFTP error during APPLE_NSP_TFTP_GET_FILE_SIZE: %r\n", Status); + return 0; + } + + File->Size = BufferSize; + File->MaxPosition = File->Size; + } + + return File->Size; +} + + +/** + Seek to the Offset locaiton in the file. LoadFile and FV device types do + not support EfiSeek(). It is not possible to grow the file size using + EfiSeek(). + + SeekType defines how use Offset to calculate the new file position: + EfiSeekStart : Position = Offset + EfiSeekCurrent: Position is Offset bytes from the current position + EfiSeekEnd : Only supported if Offset is zero to seek to end of file. + + @param Stream Open File Handle + @param Offset Offset to seek too. + @param SeekType Type of seek to perform + + + @return EFI_INVALID_PARAMETER Stream is not an Open File + @return EFI_UNSUPPORTED LoadFile and FV doe not support Seek + @return EFI_NOT_FOUND Seek past the end of the file. + @return EFI_SUCCESS Steam closed + +**/ +EFI_STATUS +EfiSeek ( + IN EFI_OPEN_FILE *File, + IN EFI_LBA Offset, + IN EFI_SEEK_TYPE SeekType + ) +{ + EFI_STATUS Status; + UINT64 CurrentPosition; + + if (!FileHandleValid (File)) { + return EFI_INVALID_PARAMETER; + } + + if (File->Type == EfiOpenLoadFile || File->Type == EfiOpenFirmwareVolume) { + // LoadFile and FV do not support Seek + return EFI_UNSUPPORTED; + } + + CurrentPosition = File->CurrentPosition; + switch (SeekType) { + case EfiSeekStart: + if (Offset > File->MaxPosition) { + return EFI_NOT_FOUND; + } + CurrentPosition = Offset; + break; + + case EfiSeekCurrent: + if ((File->CurrentPosition + Offset) > File->MaxPosition) { + return EFI_NOT_FOUND; + } + CurrentPosition += Offset; + break; + + case EfiSeekEnd: + if (Offset != 0) { + // We don't support growing file size via seeking past end of file + return EFI_UNSUPPORTED; + } + CurrentPosition = File->MaxPosition; + break; + + default: + return EFI_NOT_FOUND; + } + + Status = EFI_SUCCESS; + if (File->FsFileHandle != NULL) { + Status = File->FsFileHandle->SetPosition (File->FsFileHandle, CurrentPosition); + } + + if (!EFI_ERROR (Status)) { + File->CurrentPosition = CurrentPosition; + } + + return Status; +} + +EFI_STATUS +CacheTftpFile ( + IN OUT EFI_OPEN_FILE *File + ) +{ + EFI_STATUS Status; + UINT64 TftpBufferSize; + + if (File->IsBufferValid) { + return EFI_SUCCESS; + } + + // Make sure the file size is set. + EfiTell (File, NULL); + + //Allocate a buffer to hold the whole file. + File->Buffer = AllocatePool(File->Size); + if (File->Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + TftpBufferSize = File->Size; + + Status = EblMtftp ( + EFI_PXE_BASE_CODE_TFTP_READ_FILE, + File->Buffer, + FALSE, + &TftpBufferSize, + NULL, + &File->ServerIp, + (UINT8 *)File->FileName, + NULL, + FALSE); + if (EFI_ERROR(Status)) { + AsciiPrint("TFTP error during APPLE_NSP_TFTP_READ_FILE: %r\n", Status); + FreePool(File->Buffer); + return Status; + } + + // Set the buffer valid flag. + File->IsBufferValid = TRUE; + + return Status; +} + +/** + Read BufferSize bytes from the current locaiton in the file. For load file, + FV, and TFTP case you must read the entire file. + + @param Stream Open File Handle + @param Buffer Caller allocated buffer. + @param BufferSize Size of buffer in bytes. + + + @return EFI_SUCCESS Stream is not an Open File + @return EFI_END_OF_FILE Tried to read past the end of the file + @return EFI_INVALID_PARAMETER Stream is not an open file handle + @return EFI_BUFFER_TOO_SMALL Buffer is not big enough to do the read + @return "other" Error returned from device read + +**/ +EFI_STATUS +EfiRead ( + IN EFI_OPEN_FILE *File, + OUT VOID *Buffer, + OUT UINTN *BufferSize + ) +{ + EFI_STATUS Status; + UINT32 AuthenticationStatus; + EFI_DISK_IO_PROTOCOL *DiskIo; + + if (!FileHandleValid (File)) { + return EFI_INVALID_PARAMETER; + } + + // Don't read past the end of the file. + if ((File->CurrentPosition + *BufferSize) > File->MaxPosition) { + return EFI_END_OF_FILE; + } + + switch (File->Type) { + case EfiOpenMemoryBuffer: + CopyMem (Buffer, File->Buffer + File->CurrentPosition, *BufferSize); + File->CurrentPosition += *BufferSize; + Status = EFI_SUCCESS; + break; + + case EfiOpenLoadFile: + // Figure out the File->Size + EfiTell (File, NULL); + + Status = File->LoadFile->LoadFile (File->LoadFile, File->DevicePath, FALSE, BufferSize, Buffer); + break; + + case EfiOpenFirmwareVolume: + if (File->FvSectionType == EFI_SECTION_ALL) { + Status = File->Fv->ReadFile ( + File->Fv, + &File->FvNameGuid, + &Buffer, + BufferSize, + &File->FvType, + &File->FvAttributes, + &AuthenticationStatus + ); + } else { + Status = File->Fv->ReadSection ( + File->Fv, + &File->FvNameGuid, + File->FvSectionType, + 0, + &Buffer, + BufferSize, + &AuthenticationStatus + ); + } + break; + + case EfiOpenFileSystem: + Status = File->FsFileHandle->Read (File->FsFileHandle, BufferSize, Buffer); + File->CurrentPosition += *BufferSize; + break; + + case EfiOpenBlockIo: + Status = gBS->HandleProtocol(File->EfiHandle, &gEfiDiskIoProtocolGuid, (VOID **)&DiskIo); + if (!EFI_ERROR(Status)) { + Status = DiskIo->ReadDisk(DiskIo, File->FsBlockIoMedia.MediaId, File->DiskOffset + File->CurrentPosition, *BufferSize, Buffer); + } + File->CurrentPosition += *BufferSize; + break; + + case EfiOpenTftp: + // Cache the file if it hasn't been cached yet. + if (File->IsBufferValid == FALSE) { + Status = CacheTftpFile (File); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // Copy out the requested data + CopyMem (Buffer, File->Buffer + File->CurrentPosition, *BufferSize); + File->CurrentPosition += *BufferSize; + + Status = EFI_SUCCESS; + break; + + default: + return EFI_INVALID_PARAMETER; + }; + + return Status; +} + + +/** + Read the entire file into a buffer. This routine allocates the buffer and + returns it to the user full of the read data. + + This is very useful for load flie where it's hard to know how big the buffer + must be. + + @param Stream Open File Handle + @param Buffer Pointer to buffer to return. + @param BufferSize Pointer to Size of buffer return.. + + + @return EFI_SUCCESS Stream is not an Open File + @return EFI_END_OF_FILE Tried to read past the end of the file + @return EFI_INVALID_PARAMETER Stream is not an open file handle + @return EFI_BUFFER_TOO_SMALL Buffer is not big enough to do the read + @return "other" Error returned from device read + +**/ +EFI_STATUS +EfiReadAllocatePool ( + IN EFI_OPEN_FILE *File, + OUT VOID **Buffer, + OUT UINTN *BufferSize + ) +{ + if (!FileHandleValid (File)) { + return EFI_INVALID_PARAMETER; + } + + // Loadfile defers file size determination on Open so use tell to find it + EfiTell (File, NULL); + + *BufferSize = File->Size; + *Buffer = AllocatePool (*BufferSize); + if (*Buffer == NULL) { + return EFI_NOT_FOUND; + } + + return EfiRead (File, *Buffer, BufferSize); +} + + +/** + Write data back to the file. For TFTP case you must write the entire file. + + @param Stream Open File Handle + @param Buffer Pointer to buffer to return. + @param BufferSize Pointer to Size of buffer return.. + + + @return EFI_SUCCESS Stream is not an Open File + @return EFI_END_OF_FILE Tried to read past the end of the file + @return EFI_INVALID_PARAMETER Stream is not an open file handle + @return EFI_BUFFER_TOO_SMALL Buffer is not big enough to do the read + @return "other" Error returned from device write + +**/ +EFI_STATUS +EfiWrite ( + IN EFI_OPEN_FILE *File, + OUT VOID *Buffer, + OUT UINTN *BufferSize + ) +{ + EFI_STATUS Status; + EFI_FV_WRITE_FILE_DATA FileData; + EFI_DISK_IO_PROTOCOL *DiskIo; + + if (!FileHandleValid (File)) { + return EFI_INVALID_PARAMETER; + } + + switch (File->Type) { + case EfiOpenMemoryBuffer: + if ((File->CurrentPosition + *BufferSize) > File->MaxPosition) { + return EFI_END_OF_FILE; + } + + CopyMem (File->Buffer + File->CurrentPosition, Buffer, *BufferSize); + File->CurrentPosition += *BufferSize; + Status = EFI_SUCCESS; + + case EfiOpenLoadFile: + // LoadFile device is read only be definition + Status = EFI_UNSUPPORTED; + + case EfiOpenFirmwareVolume: + if (File->FvSectionType != EFI_SECTION_ALL) { + // Writes not support to a specific section. You have to update entire file + return EFI_UNSUPPORTED; + } + + FileData.NameGuid = &(File->FvNameGuid); + FileData.Type = File->FvType; + FileData.FileAttributes = File->FvAttributes; + FileData.Buffer = Buffer; + FileData.BufferSize = (UINT32)*BufferSize; + Status = File->Fv->WriteFile (File->Fv, 1, EFI_FV_UNRELIABLE_WRITE, &FileData); + break; + + case EfiOpenFileSystem: + Status = File->FsFileHandle->Write (File->FsFileHandle, BufferSize, Buffer); + File->CurrentPosition += *BufferSize; + break; + + case EfiOpenBlockIo: + if ((File->CurrentPosition + *BufferSize) > File->MaxPosition) { + return EFI_END_OF_FILE; + } + + Status = gBS->HandleProtocol (File->EfiHandle, &gEfiDiskIoProtocolGuid, (VOID **)&DiskIo); + if (!EFI_ERROR(Status)) { + Status = DiskIo->WriteDisk (DiskIo, File->FsBlockIoMedia.MediaId, File->DiskOffset + File->CurrentPosition, *BufferSize, Buffer); + } + File->CurrentPosition += *BufferSize; + break; + + case EfiOpenTftp: + // Cache the file if it hasn't been cached yet. + if (File->IsBufferValid == FALSE) { + Status = CacheTftpFile(File); + if (EFI_ERROR(Status)) { + return Status; + } + } + + // Don't overwrite the buffer + if ((File->CurrentPosition + *BufferSize) > File->MaxPosition) { + UINT8 *TempBuffer; + + TempBuffer = File->Buffer; + + File->Buffer = AllocatePool (File->CurrentPosition + *BufferSize); + if (File->Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CopyMem (File->Buffer, TempBuffer, File->Size); + + FreePool (TempBuffer); + + File->Size = File->CurrentPosition + *BufferSize; + File->MaxPosition = File->Size; + } + + // Copy in the requested data + CopyMem (File->Buffer + File->CurrentPosition, Buffer, *BufferSize); + File->CurrentPosition += *BufferSize; + + // Mark the file dirty + File->IsDirty = TRUE; + + Status = EFI_SUCCESS; + break; + + default: + Status = EFI_INVALID_PARAMETER; + }; + + return Status; +} + diff --git a/EmbeddedPkg/Library/EfiFileLib/EfiFileLib.inf b/EmbeddedPkg/Library/EfiFileLib/EfiFileLib.inf new file mode 100644 index 0000000000..a69fb0c423 --- /dev/null +++ b/EmbeddedPkg/Library/EfiFileLib/EfiFileLib.inf @@ -0,0 +1,64 @@ +#%HEADER%
+#/** @file
+# Component description file for the entry point to a EFIDXE Drivers
+#
+# Library to abstract Framework extensions that conflict with UEFI 2.0 Specification
+# Copyright (c) 2007 - 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.
+#
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = EfiFileLib
+ FILE_GUID = d8c640db-73ba-48f5-a7ed-8e93c6012491
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = EfiFileLib|DXE_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+ EfiFileLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ MemoryAllocationLib
+ DevicePathLib
+ PrintLib
+ BaseMemoryLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ DebugLib
+ EblNetworkLib
+
+[Protocols]
+ gEfiBlockIoProtocolGuid # PROTOCOL SOMETIMES_CONSUMED
+ gEfiDiskIoProtocolGuid # PROTOCOL SOMETIMES_CONSUMED
+ gEfiSimpleFileSystemProtocolGuid # PROTOCOL SOMETIMES_CONSUMED
+ gEfiFirmwareVolume2ProtocolGuid # PROTOCOL SOMETIMES_CONSUMED
+ gEfiLoadFileProtocolGuid # PROTOCOL SOMETIMES_CONSUMED
+ gEfiFirmwareVolumeBlockProtocolGuid # PROTOCOL SOMETIMES_CONSUMED
+
+[Guids]
+ gEfiFileInfoGuid
+ gEfiFileSystemInfoGuid
diff --git a/EmbeddedPkg/Library/GdbSerialDebugPortLib/GdbSerialDebugPortLib.c b/EmbeddedPkg/Library/GdbSerialDebugPortLib/GdbSerialDebugPortLib.c new file mode 100644 index 0000000000..ef5a2f2a7f --- /dev/null +++ b/EmbeddedPkg/Library/GdbSerialDebugPortLib/GdbSerialDebugPortLib.c @@ -0,0 +1,187 @@ +/** @file
+ Basic serial IO abstaction for GDB
+
+ Copyright (c) 2008-2009, Apple Inc. All rights reserved.
+
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Uefi.h>
+#include <Library/GdbSerialLib.h>
+#include <Library/PcdLib.h>
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include <Protocol/DebugPort.h>
+
+
+EFI_DEBUGPORT_PROTOCOL *gDebugPort = NULL;
+UINTN gTimeOut = 0;
+
+/**
+ The constructor function initializes the UART.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+RETURN_STATUS
+EFIAPI
+GdbSerialLibDebugPortConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->LocateProtocol (&gEfiDebugPortProtocolGuid, NULL, (VOID **)&gDebugPort);
+ if (!EFI_ERROR (Status)) {
+ gTimeOut = PcdGet32 (PcdGdbMaxPacketRetryCount);
+ gDebugPort->Reset (gDebugPort);
+ }
+
+ return Status;
+}
+
+
+
+/**
+ Sets the baud rate, receive FIFO depth, transmit/receice time out, parity,
+ data buts, and stop bits on a serial device. This call is optional as the serial
+ port will be set up with defaults base on PCD values.
+
+ @param BaudRate The requested baud rate. A BaudRate value of 0 will use the the
+ device's default interface speed.
+ @param Parity The type of parity to use on this serial device. A Parity value of
+ DefaultParity will use the device's default parity value.
+ @param DataBits The number of data bits to use on the serial device. A DataBits
+ vaule of 0 will use the device's default data bit setting.
+ @param StopBits The number of stop bits to use on this serial device. A StopBits
+ value of DefaultStopBits will use the device's default number of
+ stop bits.
+
+ @retval EFI_SUCCESS The device was configured.
+ @retval EFI_DEVICE_ERROR The serial device could not be coonfigured.
+
+**/
+RETURN_STATUS
+EFIAPI
+GdbSerialInit (
+ IN UINT64 BaudRate,
+ IN UINT8 Parity,
+ IN UINT8 DataBits,
+ IN UINT8 StopBits
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gDebugPort->Reset (gDebugPort);
+ return Status;
+}
+
+
+/**
+ Check to see if a character is available from GDB. Do not read the character as that is
+ done via GdbGetChar().
+
+ @return TRUE - Character availible
+ @return FALSE - Character not availible
+
+**/
+BOOLEAN
+EFIAPI
+GdbIsCharAvailable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gDebugPort->Poll (gDebugPort);
+
+ return (Status == EFI_SUCCESS ? TRUE : FALSE);
+}
+
+
+/**
+ Get a character from GDB. This function must be able to run in interrupt context.
+
+ @return A character from GDB
+
+**/
+CHAR8
+EFIAPI
+GdbGetChar (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ CHAR8 Char;
+ UINTN BufferSize;
+
+ do {
+ BufferSize = sizeof (Char);
+ Status = gDebugPort->Read (gDebugPort, gTimeOut, &BufferSize, &Char);
+ } while (EFI_ERROR (Status) || BufferSize != sizeof (Char));
+
+ return Char;
+}
+
+
+/**
+ Send a character to GDB. This function must be able to run in interrupt context.
+
+
+ @param Char Send a character to GDB
+
+**/
+
+VOID
+EFIAPI
+GdbPutChar (
+ IN CHAR8 Char
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+
+ do {
+ BufferSize = sizeof (Char);
+ Status = gDebugPort->Write (gDebugPort, gTimeOut, &BufferSize, &Char);
+ } while (EFI_ERROR (Status) || BufferSize != sizeof (Char));
+
+ return;
+}
+
+/**
+ Send an ASCII string to GDB. This function must be able to run in interrupt context.
+
+
+ @param String Send a string to GDB
+
+**/
+
+VOID
+GdbPutString (
+ IN CHAR8 *String
+ )
+{
+ // We could performance enhance this function by calling gDebugPort->Write ()
+ while (*String != '\0') {
+ GdbPutChar (*String);
+ String++;
+ }
+}
+
+
+
+
diff --git a/EmbeddedPkg/Library/GdbSerialDebugPortLib/GdbSerialDebugPortLib.inf b/EmbeddedPkg/Library/GdbSerialDebugPortLib/GdbSerialDebugPortLib.inf new file mode 100644 index 0000000000..42a7caaa91 --- /dev/null +++ b/EmbeddedPkg/Library/GdbSerialDebugPortLib/GdbSerialDebugPortLib.inf @@ -0,0 +1,50 @@ +#%HEADER%
+#/** @file
+# Component description file for Base PCI Cf8 Library.
+#
+# PCI CF8 Library that uses I/O ports 0xCF8 and 0xCFC to perform PCI Configuration cycles.
+# Layers on top of an I/O Library instance.
+# Copyright (c) 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.
+#
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = GdbSerialDebugPortLib
+ FILE_GUID = 42ABB10A-660A-4BEC-AEFA-CC94AB4D993D
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = GdbSerialLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+ CONSTRUCTOR = GdbSerialLibDebugPortConstructor
+
+
+[Sources.common]
+ GdbSerialDebugPortLib.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+
+[LibraryClasses]
+ DebugLib
+ IoLib
+
+[Protocols.common]
+ gEfiDebugPortProtocolGuid
+
+[FixedPcd.common]
+ gEmbeddedTokenSpaceGuid.PcdGdbBaudRate|115200
+ gEmbeddedTokenSpaceGuid.PcdGdbDataBits|8
+ gEmbeddedTokenSpaceGuid.PcdGdbParity|1
+ gEmbeddedTokenSpaceGuid.PcdGdbStopBits|1
+ gEmbeddedTokenSpaceGuid.PcdGdbMaxPacketRetryCount
diff --git a/EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.c b/EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.c new file mode 100644 index 0000000000..62d8636456 --- /dev/null +++ b/EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.c @@ -0,0 +1,262 @@ +/** @file
+ Basic serial IO abstaction for GDB
+
+ Copyright (c) 2008-2009, Apple Inc. All rights reserved.
+
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Uefi.h>
+#include <Library/GdbSerialLib.h>
+#include <Library/PcdLib.h>
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+
+
+//---------------------------------------------
+// UART Register Offsets
+//---------------------------------------------
+#define BAUD_LOW_OFFSET 0x00
+#define BAUD_HIGH_OFFSET 0x01
+#define IER_OFFSET 0x01
+#define LCR_SHADOW_OFFSET 0x01
+#define FCR_SHADOW_OFFSET 0x02
+#define IR_CONTROL_OFFSET 0x02
+#define FCR_OFFSET 0x02
+#define EIR_OFFSET 0x02
+#define BSR_OFFSET 0x03
+#define LCR_OFFSET 0x03
+#define MCR_OFFSET 0x04
+#define LSR_OFFSET 0x05
+#define MSR_OFFSET 0x06
+
+//---------------------------------------------
+// UART Register Bit Defines
+//---------------------------------------------
+#define LSR_TXRDY 0x20
+#define LSR_RXDA 0x01
+#define DLAB 0x01
+#define ENABLE_FIFO 0x01
+#define CLEAR_FIFOS 0x06
+
+
+
+// IO Port Base for the UART
+UINTN gPort;
+
+
+/**
+ The constructor function initializes the UART.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+RETURN_STATUS
+EFIAPI
+GdbSerialLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ UINT64 BaudRate;
+ UINT8 DataBits;
+ UINT8 Parity;
+ UINT8 StopBits;
+
+ gPort = (UINTN)PcdGet32 (PcdGdbUartPort);
+
+ BaudRate = PcdGet64 (PcdGdbBaudRate);
+ Parity = PcdGet8 (PcdGdbParity);
+ DataBits = PcdGet8 (PcdGdbDataBits);
+ StopBits = PcdGet8 (PcdGdbStopBits);
+
+ return GdbSerialInit (BaudRate, Parity, DataBits, StopBits);
+}
+
+
+
+/**
+ Sets the baud rate, receive FIFO depth, transmit/receice time out, parity,
+ data buts, and stop bits on a serial device. This call is optional as the serial
+ port will be set up with defaults base on PCD values.
+
+ @param BaudRate The requested baud rate. A BaudRate value of 0 will use the the
+ device's default interface speed.
+ @param Parity The type of parity to use on this serial device. A Parity value of
+ DefaultParity will use the device's default parity value.
+ @param DataBits The number of data bits to use on the serial device. A DataBits
+ vaule of 0 will use the device's default data bit setting.
+ @param StopBits The number of stop bits to use on this serial device. A StopBits
+ value of DefaultStopBits will use the device's default number of
+ stop bits.
+
+ @retval EFI_SUCCESS The device was configured.
+ @retval EFI_DEVICE_ERROR The serial device could not be coonfigured.
+
+**/
+RETURN_STATUS
+EFIAPI
+GdbSerialInit (
+ IN UINT64 BaudRate,
+ IN UINT8 Parity,
+ IN UINT8 DataBits,
+ IN UINT8 StopBits
+ )
+{
+ UINTN Divisor;
+ UINT8 OutputData;
+ UINT8 Data;
+ UINT8 BreakSet = 0;
+
+ //
+ // We assume the UART has been turned on to decode gPort address range
+ //
+
+ //
+ // Map 5..8 to 0..3
+ //
+ Data = (UINT8) (DataBits - (UINT8)5);
+
+ //
+ // Calculate divisor for baud generator
+ //
+ Divisor = 115200/(UINTN)BaudRate;
+
+ //
+ // Set communications format
+ //
+ OutputData = (UINT8)((DLAB << 7) | ((BreakSet << 6) | ((Parity << 3) | ((StopBits << 2) | Data))));
+ IoWrite8 (gPort + LCR_OFFSET, OutputData);
+
+ //
+ // Configure baud rate
+ //
+ IoWrite8 (gPort + BAUD_HIGH_OFFSET, (UINT8)(Divisor >> 8));
+ IoWrite8 (gPort + BAUD_LOW_OFFSET, (UINT8)(Divisor & 0xff));
+
+
+ //
+ // Switch back to bank 0
+ //
+ OutputData = (UINT8)((~DLAB<<7)|((BreakSet<<6)|((Parity<<3)|((StopBits<<2)| Data))));
+ IoWrite8 (gPort + LCR_OFFSET, OutputData);
+
+ // Not sure this is the right place to enable the FIFOs....
+ // We probably need the FIFO enabled to not drop input
+ IoWrite8 (gPort + FCR_SHADOW_OFFSET, ENABLE_FIFO);
+
+
+ // Configure the UART hardware here
+ return RETURN_SUCCESS;
+}
+
+
+/**
+ Check to see if a character is available from GDB. Do not read the character as that is
+ done via GdbGetChar().
+
+ @return TRUE - Character availible
+ @return FALSE - Character not availible
+
+**/
+BOOLEAN
+EFIAPI
+GdbIsCharAvailable (
+ VOID
+ )
+{
+ UINT8 Data;
+
+ Data = IoRead8 (gPort + LSR_OFFSET);
+
+ return ((Data & LSR_RXDA) == LSR_RXDA);
+}
+
+
+/**
+ Get a character from GDB. This function must be able to run in interrupt context.
+
+ @return A character from GDB
+
+**/
+CHAR8
+EFIAPI
+GdbGetChar (
+ VOID
+ )
+{
+ UINT8 Data;
+ CHAR8 Char;
+
+ // Wait for the serial port to be ready
+ do {
+ Data = IoRead8 (gPort + LSR_OFFSET);
+ } while ((Data & LSR_RXDA) == 0);
+
+ Char = IoRead8 (gPort);
+
+ // Make this an EFI_D_INFO after we get everything debugged.
+ DEBUG ((EFI_D_ERROR, "<%c<", Char));
+ return Char;
+}
+
+
+/**
+ Send a character to GDB. This function must be able to run in interrupt context.
+
+
+ @param Char Send a character to GDB
+
+**/
+
+VOID
+EFIAPI
+GdbPutChar (
+ IN CHAR8 Char
+ )
+{
+ UINT8 Data;
+
+ // Make this an EFI_D_INFO after we get everything debugged.
+ DEBUG ((EFI_D_ERROR, ">%c>", Char));
+
+ // Wait for the serial port to be ready
+ do {
+ Data = IoRead8 (gPort + LSR_OFFSET);
+ } while ((Data & LSR_TXRDY) == 0);
+
+ IoWrite8 (gPort, Char);
+}
+
+/**
+ Send an ASCII string to GDB. This function must be able to run in interrupt context.
+
+
+ @param String Send a string to GDB
+
+**/
+
+VOID
+GdbPutString (
+ IN CHAR8 *String
+ )
+{
+ while (*String != '\0') {
+ GdbPutChar (*String);
+ String++;
+ }
+}
+
+
+
+
diff --git a/EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.inf b/EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.inf new file mode 100644 index 0000000000..0c8d0e6a69 --- /dev/null +++ b/EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.inf @@ -0,0 +1,47 @@ +#%HEADER%
+#/** @file
+# Component description file for Base PCI Cf8 Library.
+#
+# PCI CF8 Library that uses I/O ports 0xCF8 and 0xCFC to perform PCI Configuration cycles.
+# Layers on top of an I/O Library instance.
+# Copyright (c) 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.
+#
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = GdbSerialLib
+ FILE_GUID = 9999B4EE-081F-4501-AEDC-137A534BAF69
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = GdbSerialLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+ CONSTRUCTOR = GdbSerialLibConstructor
+
+
+[Sources.common]
+ GdbSerialLib.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+
+[LibraryClasses]
+ DebugLib
+ IoLib
+
+[FixedPcd.common]
+ gEmbeddedTokenSpaceGuid.PcdGdbBaudRate|115200
+ gEmbeddedTokenSpaceGuid.PcdGdbDataBits|8
+ gEmbeddedTokenSpaceGuid.PcdGdbParity|1
+ gEmbeddedTokenSpaceGuid.PcdGdbStopBits|1
+ gEmbeddedTokenSpaceGuid.PcdGdbUartPort
diff --git a/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Capsule.c b/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Capsule.c new file mode 100644 index 0000000000..cbc48b2b0c --- /dev/null +++ b/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Capsule.c @@ -0,0 +1,288 @@ +/** @file
+ Generic Capsule services
+
+ Copyright (c) 2008-2009, Apple Inc. All rights reserved.
+
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Common/CapsuleName.h>
+
+
+//
+//Max size capsule services support are platform policy,to populate capsules we just need
+//memory to maintain them across reset,it is not a problem. And to special capsules ,for
+//example,update flash,it is mostly decided by the platform. Here is a sample size for
+//different type capsules.
+//
+#define MAX_SIZE_POPULATE (0)
+#define MAX_SIZE_NON_POPULATE (0)
+#define MAX_SUPPORT_CAPSULE_NUM 0x10
+
+
+BOOLEAN
+EFIAPI
+SupportUpdateCapsuleRest (
+ VOID
+ )
+{
+ //
+ //If the platform has a way to guarantee the memory integrity across a system reset, return
+ //TRUE, else FALSE.
+ //
+ return FALSE;
+}
+
+
+
+VOID
+EFIAPI
+SupportCapsuleSize (
+ IN OUT UINT32 *MaxSizePopulate,
+ IN OUT UINT32 *MaxSizeNonPopulate
+ )
+{
+ //
+ //Here is a sample size, different platforms have different sizes.
+ //
+ *MaxSizePopulate = MAX_SIZE_POPULATE;
+ *MaxSizeNonPopulate = MAX_SIZE_NON_POPULATE;
+ return;
+}
+
+
+
+
+EFI_STATUS
+LibUpdateCapsule (
+ IN UEFI_CAPSULE_HEADER **CapsuleHeaderArray,
+ IN UINTN CapsuleCount,
+ IN EFI_PHYSICAL_ADDRESS ScatterGatherList OPTIONAL
+ )
+/*++
+
+Routine Description:
+
+ This code finds if the capsule needs reset to update, if no, update immediately.
+
+Arguments:
+
+ CapsuleHeaderArray A array of pointers to capsule headers passed in
+ CapsuleCount The number of capsule
+ ScatterGatherList Physical address of datablock list points to capsule
+
+Returns:
+
+ EFI STATUS
+ EFI_SUCCESS Valid capsule was passed.If CAPSULE_FLAG_PERSIT_ACROSS_RESET is
+ not set, the capsule has been successfully processed by the firmware.
+ If it set, the ScattlerGatherList is successfully to be set.
+ EFI_INVALID_PARAMETER CapsuleCount is less than 1,CapsuleGuid is not supported.
+ EFI_DEVICE_ERROR Failed to SetVariable or AllocatePool or ProcessFirmwareVolume.
+
+--*/
+{
+ UINTN CapsuleSize;
+ UINTN ArrayNumber;
+ VOID *BufferPtr;
+ EFI_STATUS Status;
+ EFI_HANDLE FvHandle;
+ UEFI_CAPSULE_HEADER *CapsuleHeader;
+
+ if ((CapsuleCount < 1) || (CapsuleCount > MAX_SUPPORT_CAPSULE_NUM)){
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BufferPtr = NULL;
+ CapsuleHeader = NULL;
+
+ //
+ //Compare GUIDs with EFI_CAPSULE_GUID, if capsule header contains CAPSULE_FLAGS_PERSIST_ACROSS_RESET
+ //and CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE flags,whatever the GUID is ,the service supports.
+ //
+ for (ArrayNumber = 0; ArrayNumber < CapsuleCount; ArrayNumber++) {
+ CapsuleHeader = CapsuleHeaderArray[ArrayNumber];
+ if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (!CompareGuid (&CapsuleHeader->CapsuleGuid, &gEfiCapsuleGuid)) {
+ if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+ }
+
+ //
+ //Assume that capsules have the same flags on reseting or not.
+ //
+ CapsuleHeader = CapsuleHeaderArray[0];
+
+ if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {
+ //
+ //Check if the platform supports update capsule across a system reset
+ //
+ if (!SupportUpdateCapsuleRest()) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (ScatterGatherList == 0) {
+ return EFI_INVALID_PARAMETER;
+ } else {
+ Status = EfiSetVariable (
+ EFI_CAPSULE_VARIABLE_NAME,
+ &gEfiCapsuleVendorGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (UINTN),
+ (VOID *) &ScatterGatherList
+ );
+ if (Status != EFI_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ return EFI_SUCCESS;
+ }
+
+ //
+ //The rest occurs in the condition of non-reset mode
+ //
+ if (EfiAtRuntime ()) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ //Here should be in the boot-time
+ //
+ for (ArrayNumber = 0; ArrayNumber < CapsuleCount ; ArrayNumber++) {
+ CapsuleHeader = CapsuleHeaderArray[ArrayNumber];
+ CapsuleSize = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize;
+ Status = gBS->AllocatePool (EfiBootServicesData, CapsuleSize, &BufferPtr);
+ if (Status != EFI_SUCCESS) {
+ goto Done;
+ }
+ gBS->CopyMem (BufferPtr, (UINT8*)CapsuleHeader+ CapsuleHeader->HeaderSize, CapsuleSize);
+
+ //
+ //Call DXE service ProcessFirmwareVolume to process immediatelly
+ //
+ Status = gDS->ProcessFirmwareVolume (BufferPtr, CapsuleSize, &FvHandle);
+ if (Status != EFI_SUCCESS) {
+ gBS->FreePool (BufferPtr);
+ return EFI_DEVICE_ERROR;
+ }
+ gDS->Dispatch ();
+ gBS->FreePool (BufferPtr);
+ }
+ return EFI_SUCCESS;
+
+Done:
+ if (BufferPtr != NULL) {
+ gBS->FreePool (BufferPtr);
+ }
+ return EFI_DEVICE_ERROR;
+}
+
+
+EFI_STATUS
+QueryCapsuleCapabilities (
+ IN UEFI_CAPSULE_HEADER **CapsuleHeaderArray,
+ IN UINTN CapsuleCount,
+ OUT UINT64 *MaxiumCapsuleSize,
+ OUT EFI_RESET_TYPE *ResetType
+ )
+/*++
+
+Routine Description:
+
+ This code is query about capsule capability.
+
+Arguments:
+
+ CapsuleHeaderArray A array of pointers to capsule headers passed in
+ CapsuleCount The number of capsule
+ MaxiumCapsuleSize Max capsule size is supported
+ ResetType Reset type the capsule indicates, if reset is not needed,return EfiResetCold.
+ If reset is needed, return EfiResetWarm.
+
+Returns:
+
+ EFI STATUS
+ EFI_SUCCESS Valid answer returned
+ EFI_INVALID_PARAMETER MaxiumCapsuleSize is NULL,ResetType is NULL.CapsuleCount is less than 1,CapsuleGuid is not supported.
+ EFI_UNSUPPORTED The capsule type is not supported.
+
+--*/
+{
+ UINTN ArrayNumber;
+ UEFI_CAPSULE_HEADER *CapsuleHeader;
+ UINT32 MaxSizePopulate;
+ UINT32 MaxSizeNonPopulate;
+
+
+ if ((CapsuleCount < 1) || (CapsuleCount > MAX_SUPPORT_CAPSULE_NUM)){
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((MaxiumCapsuleSize == NULL) ||(ResetType == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CapsuleHeader = NULL;
+
+ //
+ //Compare GUIDs with EFI_CAPSULE_GUID, if capsule header contains CAPSULE_FLAGS_PERSIST_ACROSS_RESET
+ //and CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE flags,whatever the GUID is ,the service supports.
+ //
+ for (ArrayNumber = 0; ArrayNumber < CapsuleCount; ArrayNumber++) {
+ CapsuleHeader = CapsuleHeaderArray[ArrayNumber];
+ if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (!CompareGuid (&CapsuleHeader->CapsuleGuid, &gEfiCapsuleGuid)) {
+ if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+ }
+
+ SupportCapsuleSize(&MaxSizePopulate,&MaxSizeNonPopulate);
+ //
+ //Assume that capsules have the same flags on reseting or not.
+ //
+ CapsuleHeader = CapsuleHeaderArray[0];
+ if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {
+ //
+ //Check if the platform supports update capsule across a system reset
+ //
+ if (!SupportUpdateCapsuleRest()) {
+ return EFI_UNSUPPORTED;
+ }
+ *ResetType = EfiResetWarm;
+ *MaxiumCapsuleSize = MaxSizePopulate;
+ } else {
+ *ResetType = EfiResetCold;
+ *MaxiumCapsuleSize = MaxSizeNonPopulate;
+ }
+ return EFI_SUCCESS;
+}
+
+
+VOID
+LibCapsuleVirtualAddressChangeEvent (
+ VOID
+ )
+{
+}
+
+VOID
+LibCapsuleInitialize (
+ VOID
+ )
+{
+}
diff --git a/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Mtc.c b/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Mtc.c new file mode 100644 index 0000000000..8e8f2dbf24 --- /dev/null +++ b/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Mtc.c @@ -0,0 +1,226 @@ +/** @file
+ Generic Monotonic Counter services
+
+ Copyright (c) 2007, Intel Corporation<BR>
+ Portions copyright (c) 2008-2009, Apple Inc. All rights reserved.
+
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+
+
+//
+// The current Monotonic count value
+//
+UINT64 mEfiMtc = 0;
+
+
+//
+// Event to use to update the Mtc's high part when wrapping
+//
+EFI_EVENT mEfiMtcEvent;
+
+//
+// EfiMtcName - Variable name of the MTC value
+//
+CHAR16 *mEfiMtcName = L"MTC";
+
+//
+// EfiMtcGuid - Guid of the MTC value
+//
+EFI_GUID mEfiMtcGuid = { 0xeb704011, 0x1402, 0x11d3, { 0x8e, 0x77, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } };
+
+
+
+//
+// Worker functions
+//
+
+
+VOID
+EFIAPI
+EfiMtcEventHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+/*++
+
+Routine Description:
+
+ Monotonic count event handler. This handler updates the high monotonic count.
+
+Arguments:
+
+ Event The event to handle
+ Context The event context
+
+Returns:
+
+ EFI_SUCCESS The event has been handled properly
+ EFI_NOT_FOUND An error occurred updating the variable.
+
+--*/
+{
+ UINT32 HighCount;
+
+ EfiGetNextHighMonotonicCount (&HighCount);
+ return;
+}
+
+
+
+VOID
+LibMtcVirtualAddressChangeEvent (VOID)
+{
+}
+
+
+EFI_STATUS
+EFIAPI
+LibMtcGetNextHighMonotonicCount (
+ OUT UINT32 *HighCount
+ )
+{
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ //
+ // Check input parameters
+ //
+ if (HighCount == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+
+ if (!EfiAtRuntime ()) {
+ // Use a lock if called before ExitBootServices()
+ OldTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL);
+ }
+
+ *HighCount = (UINT32) RShiftU64 (mEfiMtc, 32) + 1;
+ mEfiMtc = LShiftU64 (*HighCount, 32);
+
+ if (!EfiAtRuntime ()) {
+ gBS->RestoreTPL (OldTpl);
+ }
+
+ //
+ // Update the NvRam store to match the new high part
+ //
+ Status = EfiSetVariable (
+ mEfiMtcName,
+ &mEfiMtcGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (UINT32),
+ HighCount
+ );
+
+ return Status;
+}
+
+
+EFI_STATUS
+LibMtcGetNextMonotonicCount (
+ OUT UINT64 *Count
+ )
+{
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+ UINT32 HighCount;
+ UINTN BufferSize;
+
+ //
+ // Can not be called after ExitBootServices()
+ //
+ if (EfiAtRuntime ()) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Check input parameters
+ //
+ if (Count == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (mEfiMtc == 0) {
+ //
+ // If the MTC has not been initialized read the variable
+ //
+
+ //
+ // Read the last high part
+ //
+ BufferSize = sizeof (UINT32);
+ Status = EfiGetVariable (
+ mEfiMtcName,
+ &mEfiMtcGuid,
+ NULL,
+ &BufferSize,
+ &HighCount
+ );
+ if (EFI_ERROR (Status)) {
+ HighCount = 0;
+ }
+
+ //
+ // Set the current value
+ //
+ mEfiMtc = LShiftU64 (HighCount, 32);
+ //
+ // Increment the upper 32 bits for this boot
+ // Continue even if it fails. It will only fail if the variable services are
+ // not functional.
+ //
+ Status = EfiGetNextHighMonotonicCount (&HighCount);
+ }
+
+
+ //
+ // Update the monotonic counter with a lock
+ //
+ OldTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL);
+ *Count = mEfiMtc;
+ mEfiMtc++;
+ gBS->RestoreTPL (OldTpl);
+
+ //
+ // If the MSB bit of the low part toggled, then signal that the high
+ // part needs updated now
+ //
+ if ((((UINT32) mEfiMtc) ^ ((UINT32) *Count)) & 0x80000000) {
+ gBS->SignalEvent (mEfiMtcEvent);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+
+VOID
+LibMtcInitialize (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Initialize event to handle overflows
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ EFI_TPL_CALLBACK,
+ EfiMtcEventHandler,
+ NULL,
+ &mEfiMtcEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
diff --git a/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/ReportStatusCode.c b/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/ReportStatusCode.c new file mode 100644 index 0000000000..f1953a89d8 --- /dev/null +++ b/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/ReportStatusCode.c @@ -0,0 +1,198 @@ +/** @file
+ Report status code lib on top of either SerialLib and/or EFI Serial Protocol.
+ Based on PcdStatusCodeUseEfiSerial & PcdStatusCodeUseHardSerial settings
+
+ There is just a single runtime memory buffer that contans all the data.
+
+ Copyright (c) 2007, Intel Corporation<BR>
+ Portions copyright (c) 2008-2009, Apple Inc. All rights reserved.
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+
+//////////#include "DxeStatusCode.h"
+
+
+EFI_SERIAL_IO_PROTOCOL *mSerialIoProtocol = NULL;
+
+
+EFI_STATUS
+LibReportStatusCode (
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN EFI_GUID *CallerId,
+ IN EFI_STATUS_CODE_DATA *Data OPTIONAL
+ )
+{
+ CHAR8 *Filename;
+ CHAR8 *Description;
+ CHAR8 *Format;
+ CHAR8 Buffer[EFI_STATUS_CODE_DATA_MAX_SIZE];
+ UINT32 ErrorLevel;
+ UINT32 LineNumber;
+ UINTN CharCount;
+ VA_LIST Marker;
+ EFI_DEBUG_INFO *DebugInfo;
+ EFI_TPL CurrentTpl;
+
+
+ if (FeaturePcdGet (PcdStatusCodeUseEfiSerial)) {
+ if (EfiAtRuntime ()) {
+ return EFI_DEVICE_ERROR;
+ }
+ CurrentTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL);
+ gBS->RestoreTPL (CurrentTpl);
+
+ if (CurrentTpl > EFI_TPL_CALLBACK ) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ Buffer[0] = '\0';
+
+ if (Data != NULL &&
+ ReportStatusCodeExtractAssertInfo (CodeType, Value, Data, &Filename, &Description, &LineNumber)) {
+ //
+ // Print ASSERT() information into output buffer.
+ //
+ CharCount = AsciiSPrint (
+ Buffer,
+ EFI_STATUS_CODE_DATA_MAX_SIZE,
+ "\n\rDXE_ASSERT!: %a (%d): %a\n\r",
+ Filename,
+ LineNumber,
+ Description
+ );
+ } else if (Data != NULL &&
+ ReportStatusCodeExtractDebugInfo (Data, &ErrorLevel, &Marker, &Format)) {
+ //
+ // Print DEBUG() information into output buffer.
+ //
+ CharCount = AsciiVSPrint (
+ Buffer,
+ EFI_STATUS_CODE_DATA_MAX_SIZE,
+ Format,
+ Marker
+ );
+ } else if (Data != NULL &&
+ CompareGuid (&Data->Type, &gEfiStatusCodeSpecificDataGuid) &&
+ (CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE) {
+ //
+ // Print specific data into output buffer.
+ //
+ DebugInfo = (EFI_DEBUG_INFO *) (Data + 1);
+ Marker = (VA_LIST) (DebugInfo + 1);
+ Format = (CHAR8 *) (((UINT64 *) (DebugInfo + 1)) + 12);
+
+ CharCount = AsciiVSPrint (Buffer, EFI_STATUS_CODE_DATA_MAX_SIZE, Format, Marker);
+ } else if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) {
+ //
+ // Print ERROR information into output buffer.
+ //
+ CharCount = AsciiSPrint (
+ Buffer,
+ EFI_STATUS_CODE_DATA_MAX_SIZE,
+ "ERROR: C%x:V%x I%x",
+ CodeType,
+ Value,
+ Instance
+ );
+
+ //
+ // Make sure we don't try to print values that weren't
+ // intended to be printed, especially NULL GUID pointers.
+ //
+
+ if (CallerId != NULL) {
+ CharCount += AsciiSPrint (
+ &Buffer[CharCount - 1],
+ (EFI_STATUS_CODE_DATA_MAX_SIZE - (sizeof (Buffer[0]) * CharCount)),
+ " %g",
+ CallerId
+ );
+ }
+
+ if (Data != NULL) {
+ CharCount += AsciiSPrint (
+ &Buffer[CharCount - 1],
+ (EFI_STATUS_CODE_DATA_MAX_SIZE - (sizeof (Buffer[0]) * CharCount)),
+ " %x",
+ Data
+ );
+ }
+
+ CharCount += AsciiSPrint (
+ &Buffer[CharCount - 1],
+ (EFI_STATUS_CODE_DATA_MAX_SIZE - (sizeof (Buffer[0]) * CharCount)),
+ "\n\r"
+ );
+ } else if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) {
+ CharCount = AsciiSPrint (
+ Buffer,
+ EFI_STATUS_CODE_DATA_MAX_SIZE,
+ "PROGRESS CODE: V%x I%x\n\r",
+ Value,
+ Instance
+ );
+ } else {
+ CharCount = AsciiSPrint (
+ Buffer,
+ EFI_STATUS_CODE_DATA_MAX_SIZE,
+ "Undefined: C%x:V%x I%x\n\r",
+ CodeType,
+ Value,
+ Instance
+ );
+ }
+
+
+ if (FeaturePcdGet (PcdStatusCodeUseHardSerial)) {
+ //
+ // Callout to SerialPort Lib function to do print.
+ //
+ SerialPortWrite ((UINT8 *) Buffer, CharCount);
+ }
+ if (FeaturePcdGet (PcdStatusCodeUseEfiSerial)) {
+ if (mSerialIoProtocol == NULL) {
+ gBS->LocateProtocol (&gEfiSerialIoProtocolGuid, NULL, (VOID **) &mSerialIoProtocol);
+ }
+
+ if (mSerialIoProtocol == NULL) {
+ mSerialIoProtocol->Write (
+ mSerialIoProtocol,
+ &CharCount,
+ Buffer
+ );
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+VOID
+LibReportStatusCodeVirtualAddressChangeEvent (
+ VOID
+ )
+{
+ return;
+}
+
+VOID
+LibReportStatusCodeInitialize (
+ VOID
+ )
+{
+ return;
+}
+
+
+
diff --git a/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Reset.c b/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Reset.c new file mode 100644 index 0000000000..8671971a22 --- /dev/null +++ b/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Reset.c @@ -0,0 +1,63 @@ +/** @file
+ Simple PC Port 0x92 reset driver
+
+ Copyright (c) 2007, Intel Corporation<BR>
+ Portions copyright (c) 2008-2009, Apple Inc. All rights reserved.
+
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+
+
+
+VOID
+LibResetInitializeReset (
+ VOID
+ )
+{
+}
+
+VOID
+LibResetVirtualAddressChangeEvent (
+ VOID
+ )
+{
+}
+
+
+VOID
+LibResetSystem (
+ IN EFI_RESET_TYPE ResetType,
+ IN EFI_STATUS ResetStatus,
+ IN UINTN DataSize,
+ IN CHAR16 *ResetData OPTIONAL
+ )
+{
+ UINT8 Data;
+
+ switch (ResetType) {
+ case EfiResetWarm:
+ case EfiResetCold:
+ case EfiResetShutdown:
+ Data = IoRead8 (0x92);
+ Data |= 1;
+ IoWrite8 (0x92, Data);
+ break;
+
+ default:
+ return ;
+ }
+
+ //
+ // Given we should have reset getting here would be bad
+ //
+ ASSERT (FALSE);
+}
+
diff --git a/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Rtc.c b/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Rtc.c new file mode 100644 index 0000000000..bb87ba82be --- /dev/null +++ b/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Rtc.c @@ -0,0 +1,861 @@ +/** @file
+ Simple PC RTC
+
+ Copyright (c) 2007, Intel Corporation<BR>
+ Portions copyright (c) 2008-2009, Apple Inc. All rights reserved.
+
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+
+
+
+typedef struct {
+ EFI_LOCK RtcLock;
+ UINT16 SavedTimeZone;
+ UINT8 Daylight;
+} PC_RTC_GLOBALS;
+
+#define PCAT_RTC_ADDRESS_REGISTER 0x70
+#define PCAT_RTC_DATA_REGISTER 0x71
+
+//
+// Dallas DS12C887 Real Time Clock
+//
+#define RTC_ADDRESS_SECONDS 0 // R/W Range 0..59
+#define RTC_ADDRESS_SECONDS_ALARM 1 // R/W Range 0..59
+#define RTC_ADDRESS_MINUTES 2 // R/W Range 0..59
+#define RTC_ADDRESS_MINUTES_ALARM 3 // R/W Range 0..59
+#define RTC_ADDRESS_HOURS 4 // R/W Range 1..12 or 0..23 Bit 7 is AM/PM
+#define RTC_ADDRESS_HOURS_ALARM 5 // R/W Range 1..12 or 0..23 Bit 7 is AM/PM
+#define RTC_ADDRESS_DAY_OF_THE_WEEK 6 // R/W Range 1..7
+#define RTC_ADDRESS_DAY_OF_THE_MONTH 7 // R/W Range 1..31
+#define RTC_ADDRESS_MONTH 8 // R/W Range 1..12
+#define RTC_ADDRESS_YEAR 9 // R/W Range 0..99
+#define RTC_ADDRESS_REGISTER_A 10 // R/W[0..6] R0[7]
+#define RTC_ADDRESS_REGISTER_B 11 // R/W
+#define RTC_ADDRESS_REGISTER_C 12 // RO
+#define RTC_ADDRESS_REGISTER_D 13 // RO
+#define RTC_ADDRESS_CENTURY 50 // R/W Range 19..20 Bit 8 is R/W
+//
+// Date and time initial values.
+// They are used if the RTC values are invalid during driver initialization
+//
+#define RTC_INIT_SECOND 0
+#define RTC_INIT_MINUTE 0
+#define RTC_INIT_HOUR 0
+#define RTC_INIT_DAY 1
+#define RTC_INIT_MONTH 1
+#define RTC_INIT_YEAR 2001
+
+//
+// Register initial values
+//
+#define RTC_INIT_REGISTER_A 0x26
+#define RTC_INIT_REGISTER_B 0x02
+#define RTC_INIT_REGISTER_D 0x0
+
+#pragma pack(1)
+//
+// Register A
+//
+typedef struct {
+ UINT8 RS : 4; // Rate Selection Bits
+ UINT8 DV : 3; // Divisor
+ UINT8 UIP : 1; // Update in progress
+} RTC_REGISTER_A_BITS;
+
+typedef union {
+ RTC_REGISTER_A_BITS Bits;
+ UINT8 Data;
+} RTC_REGISTER_A;
+
+//
+// Register B
+//
+typedef struct {
+ UINT8 DSE : 1; // 0 - Daylight saving disabled 1 - Daylight savings enabled
+ UINT8 MIL : 1; // 0 - 12 hour mode 1 - 24 hour mode
+ UINT8 DM : 1; // 0 - BCD Format 1 - Binary Format
+ UINT8 SQWE : 1; // 0 - Disable SQWE output 1 - Enable SQWE output
+ UINT8 UIE : 1; // 0 - Update INT disabled 1 - Update INT enabled
+ UINT8 AIE : 1; // 0 - Alarm INT disabled 1 - Alarm INT Enabled
+ UINT8 PIE : 1; // 0 - Periodic INT disabled 1 - Periodic INT Enabled
+ UINT8 SET : 1; // 0 - Normal operation. 1 - Updates inhibited
+} RTC_REGISTER_B_BITS;
+
+typedef union {
+ RTC_REGISTER_B_BITS Bits;
+ UINT8 Data;
+} RTC_REGISTER_B;
+
+//
+// Register C
+//
+typedef struct {
+ UINT8 Reserved : 4; // Read as zero. Can not be written.
+ UINT8 UF : 1; // Update End Interrupt Flag
+ UINT8 AF : 1; // Alarm Interrupt Flag
+ UINT8 PF : 1; // Periodic Interrupt Flag
+ UINT8 IRQF : 1; // Iterrupt Request Flag = PF & PIE | AF & AIE | UF & UIE
+} RTC_REGISTER_C_BITS;
+
+typedef union {
+ RTC_REGISTER_C_BITS Bits;
+ UINT8 Data;
+} RTC_REGISTER_C;
+
+//
+// Register D
+//
+typedef struct {
+ UINT8 Reserved : 7; // Read as zero. Can not be written.
+ UINT8 VRT : 1; // Valid RAM and Time
+} RTC_REGISTER_D_BITS;
+
+typedef union {
+ RTC_REGISTER_D_BITS Bits;
+ UINT8 Data;
+} RTC_REGISTER_D;
+
+#pragma pack()
+
+PC_RTC_GLOBALS mRtc;
+
+BOOLEAN
+IsLeapYear (
+ IN EFI_TIME *Time
+ )
+{
+ if (Time->Year % 4 == 0) {
+ if (Time->Year % 100 == 0) {
+ if (Time->Year % 400 == 0) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ } else {
+ return TRUE;
+ }
+ } else {
+ return FALSE;
+ }
+}
+
+
+const INTN mDayOfMonth[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+BOOLEAN
+DayValid (
+ IN EFI_TIME *Time
+ )
+{
+ if (Time->Day < 1 ||
+ Time->Day > mDayOfMonth[Time->Month - 1] ||
+ (Time->Month == 2 && (!IsLeapYear (Time) && Time->Day > 28))
+ ) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+UINT8
+DecimaltoBcd (
+ IN UINT8 DecValue
+ )
+{
+ UINTN High;
+ UINTN Low;
+
+ High = DecValue / 10;
+ Low = DecValue - (High * 10);
+
+ return (UINT8) (Low + (High << 4));
+}
+
+UINT8
+BcdToDecimal (
+ IN UINT8 BcdValue
+ )
+{
+ UINTN High;
+ UINTN Low;
+
+ High = BcdValue >> 4;
+ Low = BcdValue - (High << 4);
+
+ return (UINT8) (Low + (High * 10));
+}
+
+
+
+
+VOID
+ConvertEfiTimeToRtcTime (
+ IN EFI_TIME *Time,
+ IN RTC_REGISTER_B RegisterB,
+ IN UINT8 *Century
+ )
+{
+ BOOLEAN PM;
+
+ PM = TRUE;
+ //
+ // Adjust hour field if RTC in in 12 hour mode
+ //
+ if (RegisterB.Bits.MIL == 0) {
+ if (Time->Hour < 12) {
+ PM = FALSE;
+ }
+
+ if (Time->Hour >= 13) {
+ Time->Hour = (UINT8) (Time->Hour - 12);
+ } else if (Time->Hour == 0) {
+ Time->Hour = 12;
+ }
+ }
+ //
+ // Set the Time/Date/Daylight Savings values.
+ //
+ *Century = DecimaltoBcd ((UINT8) (Time->Year / 100));
+
+ Time->Year = (UINT16) (Time->Year % 100);
+
+ if (RegisterB.Bits.DM == 0) {
+ Time->Year = DecimaltoBcd ((UINT8) Time->Year);
+ Time->Month = DecimaltoBcd (Time->Month);
+ Time->Day = DecimaltoBcd (Time->Day);
+ Time->Hour = DecimaltoBcd (Time->Hour);
+ Time->Minute = DecimaltoBcd (Time->Minute);
+ Time->Second = DecimaltoBcd (Time->Second);
+ }
+ //
+ // If we are in 12 hour mode and PM is set, then set bit 7 of the Hour field.
+ //
+ if (RegisterB.Bits.MIL == 0 && PM) {
+ Time->Hour = (UINT8) (Time->Hour | 0x80);
+ }
+}
+
+EFI_STATUS
+RtcTimeFieldsValid (
+ IN EFI_TIME *Time
+ )
+/*++
+
+Routine Description:
+
+ Arguments:
+
+ Returns:
+--*/
+// TODO: Time - add argument and description to function comment
+// TODO: EFI_INVALID_PARAMETER - add return value to function comment
+// TODO: EFI_SUCCESS - add return value to function comment
+{
+ if (Time->Year < 1998 ||
+ Time->Year > 2099 ||
+ Time->Month < 1 ||
+ Time->Month > 12 ||
+ (!DayValid (Time)) ||
+ Time->Hour > 23 ||
+ Time->Minute > 59 ||
+ Time->Second > 59 ||
+ Time->Nanosecond > 999999999 ||
+ (!(Time->TimeZone == EFI_UNSPECIFIED_TIMEZONE || (Time->TimeZone >= -1440 && Time->TimeZone <= 1440))) ||
+ (Time->Daylight & (~(EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT)))
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+UINT8
+RtcRead (
+ IN UINT8 Address
+ )
+{
+ IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, (UINT8) (Address | (UINT8) (IoRead8 (PCAT_RTC_ADDRESS_REGISTER) & 0x80)));
+ return IoRead8 (PCAT_RTC_DATA_REGISTER);
+}
+
+VOID
+RtcWrite (
+ IN UINT8 Address,
+ IN UINT8 Data
+ )
+{
+ IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, (UINT8) (Address | (UINT8) (IoRead8 (PCAT_RTC_ADDRESS_REGISTER) & 0x80)));
+ IoWrite8 (PCAT_RTC_DATA_REGISTER, Data);
+}
+
+
+EFI_STATUS
+RtcTestCenturyRegister (
+ VOID
+ )
+{
+ UINT8 Century;
+ UINT8 Temp;
+
+ Century = RtcRead (RTC_ADDRESS_CENTURY);
+ //
+ // RtcWrite (RTC_ADDRESS_CENTURY, 0x00);
+ //
+ Temp = (UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f);
+ RtcWrite (RTC_ADDRESS_CENTURY, Century);
+ if (Temp == 0x19 || Temp == 0x20) {
+ return EFI_SUCCESS;
+ }
+
+ return EFI_DEVICE_ERROR;
+}
+
+VOID
+ConvertRtcTimeToEfiTime (
+ IN EFI_TIME *Time,
+ IN RTC_REGISTER_B RegisterB
+ )
+{
+ BOOLEAN PM;
+
+ if ((Time->Hour) & 0x80) {
+ PM = TRUE;
+ } else {
+ PM = FALSE;
+ }
+
+ Time->Hour = (UINT8) (Time->Hour & 0x7f);
+
+ if (RegisterB.Bits.DM == 0) {
+ Time->Year = BcdToDecimal ((UINT8) Time->Year);
+ Time->Month = BcdToDecimal (Time->Month);
+ Time->Day = BcdToDecimal (Time->Day);
+ Time->Hour = BcdToDecimal (Time->Hour);
+ Time->Minute = BcdToDecimal (Time->Minute);
+ Time->Second = BcdToDecimal (Time->Second);
+ }
+ //
+ // If time is in 12 hour format, convert it to 24 hour format
+ //
+ if (RegisterB.Bits.MIL == 0) {
+ if (PM && Time->Hour < 12) {
+ Time->Hour = (UINT8) (Time->Hour + 12);
+ }
+
+ if (!PM && Time->Hour == 12) {
+ Time->Hour = 0;
+ }
+ }
+
+ Time->Nanosecond = 0;
+ Time->TimeZone = EFI_UNSPECIFIED_TIMEZONE;
+ Time->Daylight = 0;
+}
+
+EFI_STATUS
+RtcWaitToUpdate (
+ UINTN Timeout
+ )
+{
+ RTC_REGISTER_A RegisterA;
+ RTC_REGISTER_D RegisterD;
+
+ //
+ // See if the RTC is functioning correctly
+ //
+ RegisterD.Data = RtcRead (RTC_ADDRESS_REGISTER_D);
+
+ if (RegisterD.Bits.VRT == 0) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Wait for up to 0.1 seconds for the RTC to be ready.
+ //
+ Timeout = (Timeout / 10) + 1;
+ RegisterA.Data = RtcRead (RTC_ADDRESS_REGISTER_A);
+ while (RegisterA.Bits.UIP == 1 && Timeout > 0) {
+ MicroSecondDelay (10);
+ RegisterA.Data = RtcRead (RTC_ADDRESS_REGISTER_A);
+ Timeout--;
+ }
+
+ RegisterD.Data = RtcRead (RTC_ADDRESS_REGISTER_D);
+ if (Timeout == 0 || RegisterD.Bits.VRT == 0) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+LibGetTime (
+ OUT EFI_TIME *Time,
+ OUT EFI_TIME_CAPABILITIES *Capabilities
+ )
+{
+ EFI_STATUS Status;
+ RTC_REGISTER_B RegisterB;
+ UINT8 Century;
+ UINTN BufferSize;
+
+ //
+ // Check parameters for null pointer
+ //
+ if (Time == NULL) {
+ return EFI_INVALID_PARAMETER;
+
+ }
+ //
+ // Acquire RTC Lock to make access to RTC atomic
+ //
+ EfiAcquireLock (&mRtc.RtcLock);
+
+ //
+ // Wait for up to 0.1 seconds for the RTC to be updated
+ //
+ Status = RtcWaitToUpdate (100000);
+ if (EFI_ERROR (Status)) {
+ EfiReleaseLock (&mRtc.RtcLock);
+ return Status;
+ }
+ //
+ // Read Register B
+ //
+ RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);
+
+ //
+ // Get the Time/Date/Daylight Savings values.
+ //
+ Time->Second = RtcRead (RTC_ADDRESS_SECONDS);
+ Time->Minute = RtcRead (RTC_ADDRESS_MINUTES);
+ Time->Hour = RtcRead (RTC_ADDRESS_HOURS);
+ Time->Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH);
+ Time->Month = RtcRead (RTC_ADDRESS_MONTH);
+ Time->Year = RtcRead (RTC_ADDRESS_YEAR);
+
+ ConvertRtcTimeToEfiTime (Time, RegisterB);
+
+ if (RtcTestCenturyRegister () == EFI_SUCCESS) {
+ Century = BcdToDecimal ((UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f));
+ } else {
+ Century = BcdToDecimal (RtcRead (RTC_ADDRESS_CENTURY));
+ }
+
+ Time->Year = (UINT16) (Century * 100 + Time->Year);
+
+ //
+ // Release RTC Lock.
+ //
+ EfiReleaseLock (&mRtc.RtcLock);
+
+ //
+ // Get the variable that containts the TimeZone and Daylight fields
+ //
+ Time->TimeZone = mRtc.SavedTimeZone;
+ Time->Daylight = mRtc.Daylight;
+
+ BufferSize = sizeof (INT16) + sizeof (UINT8);
+
+ //
+ // Make sure all field values are in correct range
+ //
+ Status = RtcTimeFieldsValid (Time);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Fill in Capabilities if it was passed in
+ //
+ if (Capabilities) {
+ Capabilities->Resolution = 1;
+ //
+ // 1 hertz
+ //
+ Capabilities->Accuracy = 50000000;
+ //
+ // 50 ppm
+ //
+ Capabilities->SetsToZero = FALSE;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+
+EFI_STATUS
+LibSetTime (
+ IN EFI_TIME *Time
+ )
+{
+ EFI_STATUS Status;
+ EFI_TIME RtcTime;
+ RTC_REGISTER_B RegisterB;
+ UINT8 Century;
+
+ if (Time == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Make sure that the time fields are valid
+ //
+ Status = RtcTimeFieldsValid (Time);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CopyMem (&RtcTime, Time, sizeof (EFI_TIME));
+
+ //
+ // Acquire RTC Lock to make access to RTC atomic
+ //
+ EfiAcquireLock (&mRtc.RtcLock);
+
+ //
+ // Wait for up to 0.1 seconds for the RTC to be updated
+ //
+ Status = RtcWaitToUpdate (100000);
+ if (EFI_ERROR (Status)) {
+ EfiReleaseLock (&mRtc.RtcLock);
+ return Status;
+ }
+ //
+ // Read Register B, and inhibit updates of the RTC
+ //
+ RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);
+ RegisterB.Bits.SET = 1;
+ RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);
+
+ ConvertEfiTimeToRtcTime (&RtcTime, RegisterB, &Century);
+
+ RtcWrite (RTC_ADDRESS_SECONDS, RtcTime.Second);
+ RtcWrite (RTC_ADDRESS_MINUTES, RtcTime.Minute);
+ RtcWrite (RTC_ADDRESS_HOURS, RtcTime.Hour);
+ RtcWrite (RTC_ADDRESS_DAY_OF_THE_MONTH, RtcTime.Day);
+ RtcWrite (RTC_ADDRESS_MONTH, RtcTime.Month);
+ RtcWrite (RTC_ADDRESS_YEAR, (UINT8) RtcTime.Year);
+ if (RtcTestCenturyRegister () == EFI_SUCCESS) {
+ Century = (UINT8) ((Century & 0x7f) | (RtcRead (RTC_ADDRESS_CENTURY) & 0x80));
+ }
+
+ RtcWrite (RTC_ADDRESS_CENTURY, Century);
+
+ //
+ // Allow updates of the RTC registers
+ //
+ RegisterB.Bits.SET = 0;
+ RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);
+
+ //
+ // Release RTC Lock.
+ //
+ EfiReleaseLock (&mRtc.RtcLock);
+
+ //
+ // Set the variable that containts the TimeZone and Daylight fields
+ //
+ mRtc.SavedTimeZone = Time->TimeZone;
+ mRtc.Daylight = Time->Daylight;
+ return Status;
+}
+
+EFI_STATUS
+libGetWakeupTime (
+ OUT BOOLEAN *Enabled,
+ OUT BOOLEAN *Pending,
+ OUT EFI_TIME *Time
+ )
+{
+ EFI_STATUS Status;
+ RTC_REGISTER_B RegisterB;
+ RTC_REGISTER_C RegisterC;
+ UINT8 Century;
+
+ //
+ // Check paramters for null pointers
+ //
+ if ((Enabled == NULL) || (Pending == NULL) || (Time == NULL)) {
+ return EFI_INVALID_PARAMETER;
+
+ }
+ //
+ // Acquire RTC Lock to make access to RTC atomic
+ //
+ EfiAcquireLock (&mRtc.RtcLock);
+
+ //
+ // Wait for up to 0.1 seconds for the RTC to be updated
+ //
+ Status = RtcWaitToUpdate (100000);
+ if (EFI_ERROR (Status)) {
+ EfiReleaseLock (&mRtc.RtcLock);
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Read Register B and Register C
+ //
+ RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);
+ RegisterC.Data = RtcRead (RTC_ADDRESS_REGISTER_C);
+
+ //
+ // Get the Time/Date/Daylight Savings values.
+ //
+ *Enabled = RegisterB.Bits.AIE;
+ if (*Enabled) {
+ Time->Second = RtcRead (RTC_ADDRESS_SECONDS_ALARM);
+ Time->Minute = RtcRead (RTC_ADDRESS_MINUTES_ALARM);
+ Time->Hour = RtcRead (RTC_ADDRESS_HOURS_ALARM);
+ Time->Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH);
+ Time->Month = RtcRead (RTC_ADDRESS_MONTH);
+ Time->Year = RtcRead (RTC_ADDRESS_YEAR);
+ } else {
+ Time->Second = 0;
+ Time->Minute = 0;
+ Time->Hour = 0;
+ Time->Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH);
+ Time->Month = RtcRead (RTC_ADDRESS_MONTH);
+ Time->Year = RtcRead (RTC_ADDRESS_YEAR);
+ }
+
+ ConvertRtcTimeToEfiTime (Time, RegisterB);
+
+ if (RtcTestCenturyRegister () == EFI_SUCCESS) {
+ Century = BcdToDecimal ((UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f));
+ } else {
+ Century = BcdToDecimal (RtcRead (RTC_ADDRESS_CENTURY));
+ }
+
+ Time->Year = (UINT16) (Century * 100 + Time->Year);
+
+ //
+ // Release RTC Lock.
+ //
+ EfiReleaseLock (&mRtc.RtcLock);
+
+ //
+ // Make sure all field values are in correct range
+ //
+ Status = RtcTimeFieldsValid (Time);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ *Pending = RegisterC.Bits.AF;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+LibSetWakeupTime (
+ IN BOOLEAN Enabled,
+ OUT EFI_TIME *Time
+ )
+{
+ EFI_STATUS Status;
+ EFI_TIME RtcTime;
+ RTC_REGISTER_B RegisterB;
+ UINT8 Century;
+ EFI_TIME_CAPABILITIES Capabilities;
+
+ if (Enabled) {
+
+ if (Time == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Make sure that the time fields are valid
+ //
+ Status = RtcTimeFieldsValid (Time);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Just support set alarm time within 24 hours
+ //
+ LibGetTime (&RtcTime, &Capabilities);
+ if (Time->Year != RtcTime.Year ||
+ Time->Month != RtcTime.Month ||
+ (Time->Day != RtcTime.Day && Time->Day != (RtcTime.Day + 1))
+ ) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Make a local copy of the time and date
+ //
+ CopyMem (&RtcTime, Time, sizeof (EFI_TIME));
+
+ }
+ //
+ // Acquire RTC Lock to make access to RTC atomic
+ //
+ EfiAcquireLock (&mRtc.RtcLock);
+
+ //
+ // Wait for up to 0.1 seconds for the RTC to be updated
+ //
+ Status = RtcWaitToUpdate (100000);
+ if (EFI_ERROR (Status)) {
+ EfiReleaseLock (&mRtc.RtcLock);
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Read Register B, and inhibit updates of the RTC
+ //
+ RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);
+
+ RegisterB.Bits.SET = 1;
+ RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);
+
+ if (Enabled) {
+ ConvertEfiTimeToRtcTime (&RtcTime, RegisterB, &Century);
+
+ //
+ // Set RTC alarm time
+ //
+ RtcWrite (RTC_ADDRESS_SECONDS_ALARM, RtcTime.Second);
+ RtcWrite (RTC_ADDRESS_MINUTES_ALARM, RtcTime.Minute);
+ RtcWrite (RTC_ADDRESS_HOURS_ALARM, RtcTime.Hour);
+
+ RegisterB.Bits.AIE = 1;
+
+ } else {
+ RegisterB.Bits.AIE = 0;
+ }
+ //
+ // Allow updates of the RTC registers
+ //
+ RegisterB.Bits.SET = 0;
+ RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);
+
+ //
+ // Release RTC Lock.
+ //
+ EfiReleaseLock (&mRtc.RtcLock);
+
+ return EFI_SUCCESS;
+}
+
+
+
+VOID
+LibRtcVirtualAddressChangeEvent (
+ VOID
+ )
+{
+}
+
+
+VOID
+LibRtcInitialize (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ RTC_REGISTER_A RegisterA;
+ RTC_REGISTER_B RegisterB;
+ RTC_REGISTER_C RegisterC;
+ RTC_REGISTER_D RegisterD;
+ UINT8 Century;
+ EFI_TIME Time;
+
+ //
+ // Acquire RTC Lock to make access to RTC atomic
+ //
+ EfiAcquireLock (&mRtc.RtcLock);
+
+ //
+ // Initialize RTC Register
+ //
+ // Make sure Division Chain is properly configured,
+ // or RTC clock won't "tick" -- time won't increment
+ //
+ RegisterA.Data = RTC_INIT_REGISTER_A;
+ RtcWrite (RTC_ADDRESS_REGISTER_A, RegisterA.Data);
+
+ //
+ // Read Register B
+ //
+ RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);
+
+ //
+ // Clear RTC flag register
+ //
+ RegisterC.Data = RtcRead (RTC_ADDRESS_REGISTER_C);
+
+ //
+ // Clear RTC register D
+ //
+ RegisterD.Data = RTC_INIT_REGISTER_D;
+ RtcWrite (RTC_ADDRESS_REGISTER_D, RegisterD.Data);
+
+ //
+ // Wait for up to 0.1 seconds for the RTC to be updated
+ //
+ Status = RtcWaitToUpdate (100000);
+ if (EFI_ERROR (Status)) {
+ EfiReleaseLock (&mRtc.RtcLock);
+ return;
+ }
+
+ //
+ // Get the Time/Date/Daylight Savings values.
+ //
+ Time.Second = RtcRead (RTC_ADDRESS_SECONDS);
+ Time.Minute = RtcRead (RTC_ADDRESS_MINUTES);
+ Time.Hour = RtcRead (RTC_ADDRESS_HOURS);
+ Time.Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH);
+ Time.Month = RtcRead (RTC_ADDRESS_MONTH);
+ Time.Year = RtcRead (RTC_ADDRESS_YEAR);
+
+ ConvertRtcTimeToEfiTime (&Time, RegisterB);
+
+ if (RtcTestCenturyRegister () == EFI_SUCCESS) {
+ Century = BcdToDecimal ((UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f));
+ } else {
+ Century = BcdToDecimal (RtcRead (RTC_ADDRESS_CENTURY));
+ }
+
+ Time.Year = (UINT16) (Century * 100 + Time.Year);
+
+ //
+ // Set RTC configuration after get original time
+ //
+ RtcWrite (RTC_ADDRESS_REGISTER_B, RTC_INIT_REGISTER_B);
+
+ //
+ // Release RTC Lock.
+ //
+ EfiReleaseLock (&mRtc.RtcLock);
+
+ //
+ // Validate time fields
+ //
+ Status = RtcTimeFieldsValid (&Time);
+ if (EFI_ERROR (Status)) {
+ Time.Second = RTC_INIT_SECOND;
+ Time.Minute = RTC_INIT_MINUTE;
+ Time.Hour = RTC_INIT_HOUR;
+ Time.Day = RTC_INIT_DAY;
+ Time.Month = RTC_INIT_MONTH;
+ Time.Year = RTC_INIT_YEAR;
+ }
+ //
+ // Reset time value according to new RTC configuration
+ //
+ LibSetTime (&Time);
+
+ return;
+}
+
+
diff --git a/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Variable.c b/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Variable.c new file mode 100644 index 0000000000..d96a44304a --- /dev/null +++ b/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Variable.c @@ -0,0 +1,306 @@ +/** @file
+ Variable services implemented from system memory
+
+ There is just a single runtime memory buffer that contans all the data.
+
+ Copyright (c) 2007, Intel Corporation<BR>
+ Portions copyright (c) 2008-2009, Apple Inc. All rights reserved.
+
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+
+
+UINT64 mMaximumVariableStorageSize;
+UINT64 mRemainingVariableStorageSize;
+UINT64 mMaximumVariableSize;
+
+typedef struct {
+ EFI_GUID VendorGuid;
+ UINT32 Attribute;
+ UINTN DataSize;
+} VARIABLE_ARRAY_ENTRY;
+// CHAR16 VariableName[]
+// UINT8 Data[]
+
+VARIABLE_ARRAY_ENTRY *mVariableArray = NULL;
+VARIABLE_ARRAY_ENTRY *mVariableArrayNextFree = NULL;
+VARIABLE_ARRAY_ENTRY *mVariableArrayEnd = NULL;
+
+
+VARIABLE_ARRAY_ENTRY *
+AddEntry (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ UINTN Size;
+ UINTN SizeOfString;
+ VARIABLE_ARRAY_ENTRY *Entry;
+ EFI_TPL CurrentTpl;
+
+
+ SizeOfString = StrSize (VariableName);
+ Size = SizeOfString + sizeof (VARIABLE_ARRAY_ENTRY) + DataSize;
+ if ((VARIABLE_ARRAY_ENTRY *)(((UINT8 *)mVariableArrayNextFree) + Size) > mVariableArrayEnd) {
+ // ran out of space
+ return NULL;
+ }
+
+ if (!EfiAtRuntime ()) {
+ // Enter critical section
+ CurrentTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL);
+ }
+
+ Entry = mVariableArrayNextFree;
+ CopyGuid (&Entry->VendorGuid, VendorGuid);
+ Entry->Attribute = Attributes;
+ Entry->DataSize = DataSize;
+ StrCpy ((CHAR16 *)++mVariableArrayNextFree, VariableName);
+ mVariableArrayNextFree = (VARIABLE_ARRAY_ENTRY *)(((UINT8 *)mVariableArrayNextFree) + SizeOfString);
+ CopyMem (mVariableArrayNextFree, Data, DataSize);
+ mVariableArrayNextFree = (VARIABLE_ARRAY_ENTRY *)(((UINT8 *)mVariableArrayNextFree) + DataSize);
+
+ if (!EfiAtRuntime ()) {
+ // Exit Critical section
+ gBS->RestoreTPL (CurrentTpl);
+ }
+
+ return Entry;
+}
+
+VOID
+DeleteEntry (
+ IN VARIABLE_ARRAY_ENTRY *Entry
+ )
+{
+ UINTN Size;
+ UINT8 *Data;
+ EFI_TPL CurrentTpl;
+
+ Size = StrSize ((CHAR16 *)(Entry + 1)) + sizeof (VARIABLE_ARRAY_ENTRY) + Entry->DataSize;
+ Data = ((UINT8 *)Entry) + Size;
+
+ CopyMem (Entry, Data, (UINTN)mVariableArrayNextFree - (UINTN)Data);
+
+ if (!EfiAtRuntime ()) {
+ // Enter critical section
+ CurrentTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL);
+ }
+
+ mVariableArrayNextFree = (VARIABLE_ARRAY_ENTRY *)(((UINT8 *)mVariableArrayNextFree) - Size);
+
+ if (!EfiAtRuntime ()) {
+ // Exit Critical section
+ gBS->RestoreTPL (CurrentTpl);
+ }
+}
+
+
+VARIABLE_ARRAY_ENTRY *
+GetVariableArrayEntry (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT VOID **Data OPTIONAL
+ )
+{
+ VARIABLE_ARRAY_ENTRY *Entry;
+ UINTN Size;
+
+ if (*VariableName == L'\0') {
+ // by definition first entry is null-terminated string
+ if (mVariableArray == mVariableArrayNextFree) {
+ return NULL;
+ }
+ return mVariableArray;
+ }
+
+ for (Entry = mVariableArray; Entry < mVariableArrayEnd;) {
+ if (CompareGuid (VendorGuid, &Entry->VendorGuid)) {
+ if (StrCmp (VariableName, (CHAR16 *)(Entry + 1))) {
+ Size = StrSize ((CHAR16 *)(Entry + 1));
+ if (Data != NULL) {
+ *Data = (VOID *)(((UINT8 *)Entry) + (Size + sizeof (VARIABLE_ARRAY_ENTRY)));
+ }
+ return Entry;
+ }
+ }
+
+ Size = StrSize ((CHAR16 *)(Entry + 1)) + sizeof (VARIABLE_ARRAY_ENTRY) + Entry->DataSize;
+ Entry = (VARIABLE_ARRAY_ENTRY *)(((UINT8 *)Entry) + Size);
+ }
+
+ return NULL;
+}
+
+
+EFI_STATUS
+LibGetVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINT32 *Attributes OPTIONAL,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data
+ )
+{
+ VARIABLE_ARRAY_ENTRY *Entry;
+ VOID *InternalData;
+
+ if (EfiAtRuntime () && (Attributes != NULL)) {
+ if ((*Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) {
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ Entry = GetVariableArrayEntry (VariableName, VendorGuid, &InternalData);
+ if (Entry == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (*DataSize < Entry->DataSize) {
+ *DataSize = Entry->DataSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *DataSize = Entry->DataSize;
+ if (Attributes != NULL) {
+ *Attributes = Entry->Attribute;
+ }
+
+ CopyMem (Data, InternalData, *DataSize);
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+LibGetNextVariableName (
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VendorGuid
+ )
+{
+ VARIABLE_ARRAY_ENTRY *Entry;
+ VOID *InternalData;
+ UINTN StringSize;
+ BOOLEAN Done;
+
+ for (Done = FALSE; !Done; ) {
+ Entry = GetVariableArrayEntry (VariableName, VendorGuid, &InternalData);
+ if (Entry == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ // If we are at runtime skip variables that do not have the Runitme attribute set.
+ Done = (EfiAtRuntime () && ((Entry->Attribute & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) ? FALSE : TRUE;
+ }
+
+ StringSize = StrSize ((CHAR16 *)(Entry + 1));
+ Entry = (VARIABLE_ARRAY_ENTRY *)(((UINT8 *)Entry) + (StringSize + sizeof (VARIABLE_ARRAY_ENTRY) + Entry->DataSize));
+ if (Entry >= mVariableArrayEnd) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (*VariableNameSize < StringSize) {
+ *VariableNameSize = StringSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *VariableNameSize = StringSize;
+ CopyMem (VariableName, (CHAR16 *)(Entry + 1), StringSize);
+ CopyMem (VendorGuid, &Entry->VendorGuid, sizeof (EFI_GUID));
+ return EFI_SUCCESS;
+}
+
+
+
+EFI_STATUS
+LibSetVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ VARIABLE_ARRAY_ENTRY *Entry;
+ VOID *InternalData;
+
+ if (EfiAtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Entry = GetVariableArrayEntry (VariableName, VendorGuid, &InternalData);
+ if (Entry == NULL) {
+ if (DataSize == 0) {
+ return EFI_NOT_FOUND;
+ }
+ Entry = AddEntry (VariableName, VendorGuid, Attributes, DataSize, Data);
+ return (Entry == NULL) ? EFI_OUT_OF_RESOURCES : EFI_SUCCESS;
+
+ } else if (DataSize == 0) {
+ // DataSize is zero so delete
+ DeleteEntry (Entry);
+ } else if (DataSize == Entry->DataSize) {
+ // No change is size so just update the store
+ Entry->Attribute |= Attributes;
+ CopyMem (InternalData, Data, DataSize);
+ } else {
+ // Grow the entry by deleting and adding back. Don't lose previous Attributes
+ Attributes |= Entry->Attribute;
+ DeleteEntry (Entry);
+ Entry = AddEntry (VariableName, VendorGuid, Attributes, DataSize, Data);
+ return (Entry == NULL) ? EFI_OUT_OF_RESOURCES : EFI_SUCCESS;
+ }
+}
+
+
+EFI_STATUS
+LibQueryVariableInfo (
+ IN UINT32 Attributes,
+ OUT UINT64 *MaximumVariableStorageSize,
+ OUT UINT64 *RemainingVariableStorageSize,
+ OUT UINT64 *MaximumVariableSize
+ )
+{
+ *MaximumVariableStorageSize = mMaximumVariableStorageSize;
+ *RemainingVariableStorageSize = mRemainingVariableStorageSize;
+ *MaximumVariableStorageSize = mRemainingVariableStorageSize;
+ return EFI_SUCCESS;
+}
+
+
+VOID
+LibVariableVirtualAddressChangeEvent (VOID)
+{
+ EfiConvertPointer (0, (VOID **)&mVariableArray);
+ EfiConvertPointer (0, (VOID **)&mVariableArrayNextFree);
+ EfiConvertPointer (0, (VOID **)&mVariableArrayEnd);
+}
+
+
+VOID
+LibVariableInitialize (VOID)
+{
+ UINTN Size;
+
+ Size = PcdGet32 (PcdEmbeddedMemVariableStoreSize);
+ mVariableArray = mVariableArrayNextFree = (VARIABLE_ARRAY_ENTRY *)AllocateRuntimePool (Size);
+ ASSERT (mVariableArray != NULL);
+
+ mVariableArrayEnd = (VARIABLE_ARRAY_ENTRY *)(((UINT8 *)mVariableArray) + Size);
+
+ mMaximumVariableStorageSize = Size - sizeof (VARIABLE_ARRAY_ENTRY);
+ mRemainingVariableStorageSize = mMaximumVariableStorageSize;
+ mMaximumVariableSize = mMaximumVariableStorageSize;
+}
+
diff --git a/EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.c b/EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.c new file mode 100644 index 0000000000..b635fa0d9e --- /dev/null +++ b/EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.c @@ -0,0 +1,247 @@ +/** @file
+
+ Copyright (c) 2008-2009, Apple Inc. All rights reserved.
+
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiPei.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/ExtractGuidedSectionLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PrePiLib.h>
+
+#define PRE_PI_EXTRACT_GUIDED_SECTION_DATA_GUID { 0x385A982C, 0x2F49, 0x4043, { 0xA5, 0x1E, 0x49, 0x01, 0x02, 0x5C, 0x8B, 0x6B }}
+
+typedef struct {
+ UINT32 NumberOfExtractHandler;
+ GUID *ExtractHandlerGuidTable;
+ EXTRACT_GUIDED_SECTION_DECODE_HANDLER *ExtractDecodeHandlerTable;
+ EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER *ExtractGetInfoHandlerTable;
+} PRE_PI_EXTRACT_GUIDED_SECTION_DATA;
+
+PRE_PI_EXTRACT_GUIDED_SECTION_DATA *
+GetSavedData (
+ VOID
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+ GUID SavedDataGuid = PRE_PI_EXTRACT_GUIDED_SECTION_DATA_GUID;
+
+ GuidHob = GetFirstGuidHob(&SavedDataGuid);
+ GuidHob++;
+
+ return (PRE_PI_EXTRACT_GUIDED_SECTION_DATA *)GuidHob;
+}
+
+RETURN_STATUS
+EFIAPI
+ExtractGuidedSectionRegisterHandlers (
+ IN CONST GUID *SectionGuid,
+ IN EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER GetInfoHandler,
+ IN EXTRACT_GUIDED_SECTION_DECODE_HANDLER DecodeHandler
+ )
+{
+ PRE_PI_EXTRACT_GUIDED_SECTION_DATA *SavedData;
+ UINT32 Index;
+ //
+ // Check input paramter.
+ //
+ if (SectionGuid == NULL) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ SavedData = GetSavedData();
+
+ //
+ // Search the match registered GetInfo handler for the input guided section.
+ //
+ for (Index = 0; Index < SavedData->NumberOfExtractHandler; Index ++) {
+ if (CompareGuid (&SavedData->ExtractHandlerGuidTable[Index], SectionGuid)) {
+ break;
+ }
+ }
+
+ //
+ // If the guided handler has been registered before, only update its handler.
+ //
+ if (Index < SavedData->NumberOfExtractHandler) {
+ SavedData->ExtractDecodeHandlerTable [Index] = DecodeHandler;
+ SavedData->ExtractGetInfoHandlerTable [Index] = GetInfoHandler;
+ return RETURN_SUCCESS;
+ }
+
+ //
+ // Check the global table is enough to contain new Handler.
+ //
+ if (SavedData->NumberOfExtractHandler >= PcdGet32 (PcdMaximumGuidedExtractHandler)) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Register new Handler and guid value.
+ //
+ CopyGuid (&SavedData->ExtractHandlerGuidTable [SavedData->NumberOfExtractHandler], SectionGuid);
+ SavedData->ExtractDecodeHandlerTable [SavedData->NumberOfExtractHandler] = DecodeHandler;
+ SavedData->ExtractGetInfoHandlerTable [SavedData->NumberOfExtractHandler++] = GetInfoHandler;
+
+ return RETURN_SUCCESS;
+}
+
+UINTN
+EFIAPI
+ExtractGuidedSectionGetGuidList (
+ IN OUT GUID **ExtractHandlerGuidTable
+ )
+{
+ PRE_PI_EXTRACT_GUIDED_SECTION_DATA *SavedData;
+
+ ASSERT(ExtractHandlerGuidTable != NULL);
+
+ SavedData = GetSavedData();
+
+ *ExtractHandlerGuidTable = SavedData->ExtractHandlerGuidTable;
+ return SavedData->NumberOfExtractHandler;
+}
+
+RETURN_STATUS
+EFIAPI
+ExtractGuidedSectionGetInfo (
+ IN CONST VOID *InputSection,
+ OUT UINT32 *OutputBufferSize,
+ OUT UINT32 *ScratchBufferSize,
+ OUT UINT16 *SectionAttribute
+ )
+{
+ PRE_PI_EXTRACT_GUIDED_SECTION_DATA *SavedData;
+ UINT32 Index;
+
+ if (InputSection == NULL) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ ASSERT (OutputBufferSize != NULL);
+ ASSERT (ScratchBufferSize != NULL);
+ ASSERT (SectionAttribute != NULL);
+
+ SavedData = GetSavedData();
+
+ //
+ // Search the match registered GetInfo handler for the input guided section.
+ //
+ for (Index = 0; Index < SavedData->NumberOfExtractHandler; Index ++) {
+ if (CompareGuid (&SavedData->ExtractHandlerGuidTable[Index], &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid))) {
+ break;
+ }
+ }
+
+ //
+ // Not found, the input guided section is not supported.
+ //
+ if (Index == SavedData->NumberOfExtractHandler) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ //
+ // Call the match handler to getinfo for the input section data.
+ //
+ return SavedData->ExtractGetInfoHandlerTable [Index] (
+ InputSection,
+ OutputBufferSize,
+ ScratchBufferSize,
+ SectionAttribute
+ );
+}
+
+RETURN_STATUS
+EFIAPI
+ExtractGuidedSectionDecode (
+ IN CONST VOID *InputSection,
+ OUT VOID **OutputBuffer,
+ OUT VOID *ScratchBuffer, OPTIONAL
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ PRE_PI_EXTRACT_GUIDED_SECTION_DATA *SavedData;
+ UINT32 Index;
+
+ if (InputSection == NULL) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ ASSERT (OutputBuffer != NULL);
+ ASSERT (AuthenticationStatus != NULL);
+
+ SavedData = GetSavedData();
+
+ //
+ // Search the match registered GetInfo handler for the input guided section.
+ //
+ for (Index = 0; Index < SavedData->NumberOfExtractHandler; Index ++) {
+ if (CompareGuid (&SavedData->ExtractHandlerGuidTable[Index], &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid))) {
+ break;
+ }
+ }
+
+ //
+ // Not found, the input guided section is not supported.
+ //
+ if (Index == SavedData->NumberOfExtractHandler) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ //
+ // Call the match handler to getinfo for the input section data.
+ //
+ return SavedData->ExtractDecodeHandlerTable [Index] (
+ InputSection,
+ OutputBuffer,
+ ScratchBuffer,
+ AuthenticationStatus
+ );
+}
+
+RETURN_STATUS
+EFIAPI
+ExtractGuidedSectionLibConstructor (
+ VOID
+ )
+{
+ PRE_PI_EXTRACT_GUIDED_SECTION_DATA SavedData;
+ GUID HobGuid = PRE_PI_EXTRACT_GUIDED_SECTION_DATA_GUID;
+
+ //
+ // Allocate global pool space to store the registered handler and its guid value.
+ //
+ SavedData.ExtractHandlerGuidTable = (GUID *)AllocatePool(PcdGet32(PcdMaximumGuidedExtractHandler) * sizeof(GUID));
+ if (SavedData.ExtractHandlerGuidTable == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+
+ SavedData.ExtractDecodeHandlerTable = (EXTRACT_GUIDED_SECTION_DECODE_HANDLER *)AllocatePool(PcdGet32(PcdMaximumGuidedExtractHandler) * sizeof(EXTRACT_GUIDED_SECTION_DECODE_HANDLER));
+ if (SavedData.ExtractDecodeHandlerTable == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+
+ SavedData.ExtractGetInfoHandlerTable = (EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER *)AllocatePool(PcdGet32(PcdMaximumGuidedExtractHandler) * sizeof(EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER));
+ if (SavedData.ExtractGetInfoHandlerTable == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+
+ //
+ // the initialized number is Zero.
+ //
+ SavedData.NumberOfExtractHandler = 0;
+
+ BuildGuidDataHob(&HobGuid, &SavedData, sizeof(SavedData));
+
+ return RETURN_SUCCESS;
+}
diff --git a/EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.inf b/EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.inf new file mode 100644 index 0000000000..bffe5b250a --- /dev/null +++ b/EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.inf @@ -0,0 +1,24 @@ +#%HEADER%
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PrePiExtractGuidedSectionLib
+ FILE_GUID = 36F6E94E-6E8E-488E-89A4-7AD911C5AFB1
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = ExtractGuidedSectionLib
+
+ CONSTRUCTOR = ExtractGuidedSectionLibConstructor
+
+[Sources.common]
+ PrePiExtractGuidedSectionLib.c
+
+[Packages]
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ DebugLib
+
+[FixedPcd.common]
+ gEfiMdePkgTokenSpaceGuid.PcdMaximumGuidedExtractHandler
diff --git a/EmbeddedPkg/Library/PrePiLib/FwVol.c b/EmbeddedPkg/Library/PrePiLib/FwVol.c new file mode 100644 index 0000000000..4a9e24683f --- /dev/null +++ b/EmbeddedPkg/Library/PrePiLib/FwVol.c @@ -0,0 +1,841 @@ +/** @file + Implementation of the 6 PEI Ffs (FV) APIs in library form. + + This code only knows about a FV if it has a EFI_HOB_TYPE_FV entry in the HOB list + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include <PrePi.h> +#include <Library/ExtractGuidedSectionLib.h> + + +#define GET_OCCUPIED_SIZE(ActualSize, Alignment) \ + (ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1)) + + +/** + Returns the highest bit set of the State field + + @param ErasePolarity Erase Polarity as defined by EFI_FVB2_ERASE_POLARITY + in the Attributes field. + @param FfsHeader Pointer to FFS File Header + + + @retval the highest bit in the State field + +**/ +STATIC +EFI_FFS_FILE_STATE +GetFileState( + IN UINT8 ErasePolarity, + IN EFI_FFS_FILE_HEADER *FfsHeader + ) +{ + EFI_FFS_FILE_STATE FileState; + EFI_FFS_FILE_STATE HighestBit; + + FileState = FfsHeader->State; + + if (ErasePolarity != 0) { + FileState = (EFI_FFS_FILE_STATE)~FileState; + } + + HighestBit = 0x80; + while (HighestBit != 0 && (HighestBit & FileState) == 0) { + HighestBit >>= 1; + } + + return HighestBit; +} + + +/** + Calculates the checksum of the header of a file. + The header is a zero byte checksum, so zero means header is good + + @param FfsHeader Pointer to FFS File Header + + @retval Checksum of the header + +**/ +STATIC +UINT8 +CalculateHeaderChecksum ( + IN EFI_FFS_FILE_HEADER *FileHeader + ) +{ + UINT8 *Ptr; + UINTN Index; + UINT8 Sum; + + Sum = 0; + Ptr = (UINT8 *)FileHeader; + + for (Index = 0; Index < sizeof(EFI_FFS_FILE_HEADER) - 3; Index += 4) { + Sum = (UINT8)(Sum + Ptr[Index]); + Sum = (UINT8)(Sum + Ptr[Index+1]); + Sum = (UINT8)(Sum + Ptr[Index+2]); + Sum = (UINT8)(Sum + Ptr[Index+3]); + } + + for (; Index < sizeof(EFI_FFS_FILE_HEADER); Index++) { + Sum = (UINT8)(Sum + Ptr[Index]); + } + + // + // State field (since this indicates the different state of file). + // + Sum = (UINT8)(Sum - FileHeader->State); + // + // Checksum field of the file is not part of the header checksum. + // + Sum = (UINT8)(Sum - FileHeader->IntegrityCheck.Checksum.File); + + return Sum; +} + + +/** + Given a FileHandle return the VolumeHandle + + @param FileHandle File handle to look up + @param VolumeHandle Match for FileHandle + + @retval TRUE VolumeHandle is valid + +**/ +STATIC +BOOLEAN +EFIAPI +FileHandleToVolume ( + IN EFI_PEI_FILE_HANDLE FileHandle, + OUT EFI_PEI_FV_HANDLE *VolumeHandle + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_PEI_HOB_POINTERS Hob; + + Hob.Raw = GetHobList (); + if (Hob.Raw == NULL) { + return FALSE; + } + + do { + Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw); + if (Hob.Raw != NULL) { + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(Hob.FirmwareVolume->BaseAddress); + if (((UINT64) (UINTN) FileHandle > (UINT64) (UINTN) FwVolHeader ) && \ + ((UINT64) (UINTN) FileHandle <= ((UINT64) (UINTN) FwVolHeader + FwVolHeader->FvLength - 1))) { + *VolumeHandle = (EFI_PEI_FV_HANDLE)FwVolHeader; + return TRUE; + } + + Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, GET_NEXT_HOB (Hob)); + } + } while (Hob.Raw != NULL); + + return FALSE; +} + + + +/** + Given the input file pointer, search for the next matching file in the + FFS volume as defined by SearchType. The search starts from FileHeader inside + the Firmware Volume defined by FwVolHeader. + + @param FileHandle File handle to look up + @param VolumeHandle Match for FileHandle + + +**/ +EFI_STATUS +FindFileEx ( + IN CONST EFI_PEI_FV_HANDLE FvHandle, + IN CONST EFI_GUID *FileName, OPTIONAL + IN EFI_FV_FILETYPE SearchType, + IN OUT EFI_PEI_FILE_HANDLE *FileHandle + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_FFS_FILE_HEADER **FileHeader; + EFI_FFS_FILE_HEADER *FfsFileHeader; + EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExHeaderInfo; + UINT32 FileLength; + UINT32 FileOccupiedSize; + UINT32 FileOffset; + UINT64 FvLength; + UINT8 ErasePolarity; + UINT8 FileState; + + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FvHandle; + FileHeader = (EFI_FFS_FILE_HEADER **)FileHandle; + + FvLength = FwVolHeader->FvLength; + if (FwVolHeader->Attributes & EFI_FVB2_ERASE_POLARITY) { + ErasePolarity = 1; + } else { + ErasePolarity = 0; + } + + // + // If FileHeader is not specified (NULL) or FileName is not NULL, + // start with the first file in the firmware volume. Otherwise, + // start from the FileHeader. + // + if ((*FileHeader == NULL) || (FileName != NULL)) { + FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FwVolHeader + FwVolHeader->HeaderLength); + if (FwVolHeader->ExtHeaderOffset != 0) { + FwVolExHeaderInfo = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)(((UINT8 *)FwVolHeader) + FwVolHeader->ExtHeaderOffset); + FfsFileHeader = (EFI_FFS_FILE_HEADER *)(((UINT8 *)FwVolExHeaderInfo) + FwVolExHeaderInfo->ExtHeaderSize); + } + } else { + // + // Length is 24 bits wide so mask upper 8 bits + // FileLength is adjusted to FileOccupiedSize as it is 8 byte aligned. + // + FileLength = *(UINT32 *)(*FileHeader)->Size & 0x00FFFFFF; + FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8); + FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)*FileHeader + FileOccupiedSize); + } + + FileOffset = (UINT32) ((UINT8 *)FfsFileHeader - (UINT8 *)FwVolHeader); + ASSERT (FileOffset <= 0xFFFFFFFF); + + while (FileOffset < (FvLength - sizeof (EFI_FFS_FILE_HEADER))) { + // + // Get FileState which is the highest bit of the State + // + FileState = GetFileState (ErasePolarity, FfsFileHeader); + + switch (FileState) { + + case EFI_FILE_HEADER_INVALID: + FileOffset += sizeof(EFI_FFS_FILE_HEADER); + FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + sizeof(EFI_FFS_FILE_HEADER)); + break; + + case EFI_FILE_DATA_VALID: + case EFI_FILE_MARKED_FOR_UPDATE: + if (CalculateHeaderChecksum (FfsFileHeader) != 0) { + ASSERT (FALSE); + *FileHeader = NULL; + return EFI_NOT_FOUND; + } + + FileLength = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF; + FileOccupiedSize = GET_OCCUPIED_SIZE(FileLength, 8); + + if (FileName != NULL) { + if (CompareGuid (&FfsFileHeader->Name, (EFI_GUID*)FileName)) { + *FileHeader = FfsFileHeader; + return EFI_SUCCESS; + } + } else if (((SearchType == FfsFileHeader->Type) || (SearchType == EFI_FV_FILETYPE_ALL)) && + (FfsFileHeader->Type != EFI_FV_FILETYPE_FFS_PAD)) { + *FileHeader = FfsFileHeader; + return EFI_SUCCESS; + } + + FileOffset += FileOccupiedSize; + FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize); + break; + + case EFI_FILE_DELETED: + FileLength = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF; + FileOccupiedSize = GET_OCCUPIED_SIZE(FileLength, 8); + FileOffset += FileOccupiedSize; + FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize); + break; + + default: + *FileHeader = NULL; + return EFI_NOT_FOUND; + } + } + + + *FileHeader = NULL; + return EFI_NOT_FOUND; +} + + +/** + Go through the file to search SectionType section, + when meeting an encapsuled section. + + @param SectionType - Filter to find only section of this type. + @param Section - From where to search. + @param SectionSize - The file size to search. + @param OutputBuffer - Pointer to the section to search. + + @retval EFI_SUCCESS +**/ +EFI_STATUS +FfsProcessSection ( + IN EFI_SECTION_TYPE SectionType, + IN EFI_COMMON_SECTION_HEADER *Section, + IN UINTN SectionSize, + OUT VOID **OutputBuffer + ) +{ + EFI_STATUS Status; + UINT32 SectionLength; + UINT32 ParsedLength; + EFI_COMPRESSION_SECTION *CompressionSection; + UINTN DstBufferSize; + VOID *ScratchBuffer; + UINT32 ScratchBufferSize; + VOID *DstBuffer; + UINT16 SectionAttribute; + UINT32 AuthenticationStatus; + + + *OutputBuffer = NULL; + ParsedLength = 0; + Status = EFI_NOT_FOUND; + while (ParsedLength < SectionSize) { + if (Section->Type == SectionType) { + *OutputBuffer = (VOID *)(Section + 1); + + return EFI_SUCCESS; + } else if ((Section->Type == EFI_SECTION_COMPRESSION) || (Section->Type == EFI_SECTION_GUID_DEFINED)) { + + if (Section->Type == EFI_SECTION_COMPRESSION) { + CompressionSection = (EFI_COMPRESSION_SECTION *) Section; + SectionLength = *(UINT32 *)Section->Size & 0x00FFFFFF; + + if (CompressionSection->CompressionType != EFI_STANDARD_COMPRESSION) { + return EFI_UNSUPPORTED; + } + + Status = UefiDecompressGetInfo ( + (UINT8 *) ((EFI_COMPRESSION_SECTION *) Section + 1), + (UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION), + (UINT32 *) &DstBufferSize, + &ScratchBufferSize + ); + } else if (Section->Type == EFI_SECTION_GUID_DEFINED) { + Status = ExtractGuidedSectionGetInfo ( + Section, + (UINT32 *) &DstBufferSize, + &ScratchBufferSize, + &SectionAttribute + ); + } + + if (EFI_ERROR (Status)) { + // + // GetInfo failed + // + DEBUG ((EFI_D_ERROR, "Decompress GetInfo Failed - %r\n", Status)); + return EFI_NOT_FOUND; + } + // + // Allocate scratch buffer + // + ScratchBuffer = (VOID *)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize)); + if (ScratchBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Allocate destination buffer, extra one page for adjustment + // + DstBuffer = (VOID *)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize) + 1); + if (DstBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // DstBuffer still is one section. Adjust DstBuffer offset, skip EFI section header + // to make section data at page alignment. + // + DstBuffer = (UINT8 *)DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER); + // + // Call decompress function + // + if (Section->Type == EFI_SECTION_COMPRESSION) { + Status = UefiDecompress ( + (CHAR8 *) ((EFI_COMPRESSION_SECTION *) Section + 1), + DstBuffer, + ScratchBuffer + ); + } else if (Section->Type == EFI_SECTION_GUID_DEFINED) { + Status = ExtractGuidedSectionDecode ( + Section, + &DstBuffer, + ScratchBuffer, + &AuthenticationStatus + ); + } + + if (EFI_ERROR (Status)) { + // + // Decompress failed + // + DEBUG ((EFI_D_ERROR, "Decompress Failed - %r\n", Status)); + return EFI_NOT_FOUND; + } else { + return FfsProcessSection ( + SectionType, + DstBuffer, + DstBufferSize, + OutputBuffer + ); + } + } + + // + // Size is 24 bits wide so mask upper 8 bits. + // SectionLength is adjusted it is 4 byte aligned. + // Go to the next section + // + SectionLength = *(UINT32 *)Section->Size & 0x00FFFFFF; + SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4); + ASSERT (SectionLength != 0); + ParsedLength += SectionLength; + Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength); + } + + return EFI_NOT_FOUND; +} + + + +/** + This service enables discovery sections of a given type within a valid FFS file. + + @param SearchType The value of the section type to find. + @param FfsFileHeader A pointer to the file header that contains the set of sections to + be searched. + @param SectionData A pointer to the discovered section, if successful. + + @retval EFI_SUCCESS The section was found. + @retval EFI_NOT_FOUND The section was not found. + +**/ +EFI_STATUS +EFIAPI +FfsFindSectionData ( + IN EFI_SECTION_TYPE SectionType, + IN EFI_PEI_FILE_HANDLE FileHandle, + OUT VOID **SectionData + ) +{ + EFI_FFS_FILE_HEADER *FfsFileHeader; + UINT32 FileSize; + EFI_COMMON_SECTION_HEADER *Section; + + FfsFileHeader = (EFI_FFS_FILE_HEADER *)(FileHandle); + + // + // Size is 24 bits wide so mask upper 8 bits. + // Does not include FfsFileHeader header size + // FileSize is adjusted to FileOccupiedSize as it is 8 byte aligned. + // + Section = (EFI_COMMON_SECTION_HEADER *)(FfsFileHeader + 1); + FileSize = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF; + FileSize -= sizeof (EFI_FFS_FILE_HEADER); + + return FfsProcessSection ( + SectionType, + Section, + FileSize, + SectionData + ); +} + + + + + + +/** + This service enables discovery of additional firmware files. + + @param SearchType A filter to find files only of this type. + @param FwVolHeader Pointer to the firmware volume header of the volume to search. + This parameter must point to a valid FFS volume. + @param FileHeader Pointer to the current file from which to begin searching. + + @retval EFI_SUCCESS The file was found. + @retval EFI_NOT_FOUND The file was not found. + @retval EFI_NOT_FOUND The header checksum was not zero. + +**/ +EFI_STATUS +EFIAPI +FfsFindNextFile ( + IN UINT8 SearchType, + IN EFI_PEI_FV_HANDLE VolumeHandle, + IN OUT EFI_PEI_FILE_HANDLE *FileHandle + ) +{ + return FindFileEx (VolumeHandle, NULL, SearchType, FileHandle); +} + + +/** + This service enables discovery of additional firmware volumes. + + @param Instance This instance of the firmware volume to find. The value 0 is the + Boot Firmware Volume (BFV). + @param FwVolHeader Pointer to the firmware volume header of the volume to return. + + @retval EFI_SUCCESS The volume was found. + @retval EFI_NOT_FOUND The volume was not found. + +**/ +EFI_STATUS +EFIAPI +FfsFindNextVolume ( + IN UINTN Instance, + IN OUT EFI_PEI_FV_HANDLE *VolumeHandle + ) +{ + EFI_PEI_HOB_POINTERS Hob; + + + Hob.Raw = GetHobList (); + if (Hob.Raw == NULL) { + return EFI_NOT_FOUND; + } + + do { + Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw); + if (Hob.Raw != NULL) { + if (Instance-- == 0) { + *VolumeHandle = (EFI_PEI_FV_HANDLE)(UINTN)(Hob.FirmwareVolume->BaseAddress); + return EFI_SUCCESS; + } + + Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, GET_NEXT_HOB (Hob)); + } + } while (Hob.Raw != NULL); + + return EFI_NOT_FOUND; + +} + + +/** + Find a file in the volume by name + + @param FileName A pointer to the name of the file to + find within the firmware volume. + + @param VolumeHandle The firmware volume to search FileHandle + Upon exit, points to the found file's + handle or NULL if it could not be found. + + @retval EFI_SUCCESS File was found. + + @retval EFI_NOT_FOUND File was not found. + + @retval EFI_INVALID_PARAMETER VolumeHandle or FileHandle or + FileName was NULL. + +**/ +EFI_STATUS +EFIAPI +FfsFindFileByName ( + IN CONST EFI_GUID *FileName, + IN EFI_PEI_FV_HANDLE VolumeHandle, + OUT EFI_PEI_FILE_HANDLE *FileHandle + ) +{ + EFI_STATUS Status; + if ((VolumeHandle == NULL) || (FileName == NULL) || (FileHandle == NULL)) { + return EFI_INVALID_PARAMETER; + } + Status = FindFileEx (VolumeHandle, FileName, 0, FileHandle); + if (Status == EFI_NOT_FOUND) { + *FileHandle = NULL; + } + return Status; +} + + + + +/** + Get information about the file by name. + + @param FileHandle Handle of the file. + + @param FileInfo Upon exit, points to the file's + information. + + @retval EFI_SUCCESS File information returned. + + @retval EFI_INVALID_PARAMETER If FileHandle does not + represent a valid file. + + @retval EFI_INVALID_PARAMETER If FileInfo is NULL. + +**/ +EFI_STATUS +EFIAPI +FfsGetFileInfo ( + IN EFI_PEI_FILE_HANDLE FileHandle, + OUT EFI_FV_FILE_INFO *FileInfo + ) +{ + UINT8 FileState; + UINT8 ErasePolarity; + EFI_FFS_FILE_HEADER *FileHeader; + EFI_PEI_FV_HANDLE VolumeHandle; + + if ((FileHandle == NULL) || (FileInfo == NULL)) { + return EFI_INVALID_PARAMETER; + } + + VolumeHandle = 0; + // + // Retrieve the FirmwareVolume which the file resides in. + // + if (!FileHandleToVolume(FileHandle, &VolumeHandle)) { + return EFI_INVALID_PARAMETER; + } + + if (((EFI_FIRMWARE_VOLUME_HEADER*)VolumeHandle)->Attributes & EFI_FVB2_ERASE_POLARITY) { + ErasePolarity = 1; + } else { + ErasePolarity = 0; + } + + // + // Get FileState which is the highest bit of the State + // + FileState = GetFileState (ErasePolarity, (EFI_FFS_FILE_HEADER*)FileHandle); + + switch (FileState) { + case EFI_FILE_DATA_VALID: + case EFI_FILE_MARKED_FOR_UPDATE: + break; + default: + return EFI_INVALID_PARAMETER; + } + + FileHeader = (EFI_FFS_FILE_HEADER *)FileHandle; + CopyMem (&FileInfo->FileName, &FileHeader->Name, sizeof(EFI_GUID)); + FileInfo->FileType = FileHeader->Type; + FileInfo->FileAttributes = FileHeader->Attributes; + FileInfo->BufferSize = ((*(UINT32 *)FileHeader->Size) & 0x00FFFFFF) - sizeof (EFI_FFS_FILE_HEADER); + FileInfo->Buffer = (FileHeader + 1); + return EFI_SUCCESS; +} + + +/** + Get Information about the volume by name + + @param VolumeHandle Handle of the volume. + + @param VolumeInfo Upon exit, points to the volume's + information. + + @retval EFI_SUCCESS File information returned. + + @retval EFI_INVALID_PARAMETER If FileHandle does not + represent a valid file. + + @retval EFI_INVALID_PARAMETER If FileInfo is NULL. + +**/ +EFI_STATUS +EFIAPI +FfsGetVolumeInfo ( + IN EFI_PEI_FV_HANDLE VolumeHandle, + OUT EFI_FV_INFO *VolumeInfo + ) +{ + EFI_FIRMWARE_VOLUME_HEADER FwVolHeader; + EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExHeaderInfo; + + if (VolumeInfo == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // VolumeHandle may not align at 8 byte, + // but FvLength is UINT64 type, which requires FvHeader align at least 8 byte. + // So, Copy FvHeader into the local FvHeader structure. + // + CopyMem (&FwVolHeader, VolumeHandle, sizeof (EFI_FIRMWARE_VOLUME_HEADER)); + // + // Check Fv Image Signature + // + if (FwVolHeader.Signature != EFI_FVH_SIGNATURE) { + return EFI_INVALID_PARAMETER; + } + VolumeInfo->FvAttributes = FwVolHeader.Attributes; + VolumeInfo->FvStart = (VOID *) VolumeHandle; + VolumeInfo->FvSize = FwVolHeader.FvLength; + CopyMem (&VolumeInfo->FvFormat, &FwVolHeader.FileSystemGuid, sizeof(EFI_GUID)); + + if (FwVolHeader.ExtHeaderOffset != 0) { + FwVolExHeaderInfo = (EFI_FIRMWARE_VOLUME_EXT_HEADER*)(((UINT8 *)VolumeHandle) + FwVolHeader.ExtHeaderOffset); + CopyMem (&VolumeInfo->FvName, &FwVolExHeaderInfo->FvName, sizeof(EFI_GUID)); + } + return EFI_SUCCESS; +} + + + +/** + Search through every FV until you find a file of type FileType + + @param FileType File handle of a Fv type file. + @param Volumehandle On succes Volume Handle of the match + @param FileHandle On success File Handle of the match + + @retval EFI_NOT_FOUND FV image can't be found. + @retval EFI_SUCCESS Successfully found FileType + +**/ +EFI_STATUS +EFIAPI +FfsAnyFvFindFirstFile ( + IN EFI_FV_FILETYPE FileType, + OUT EFI_PEI_FV_HANDLE *VolumeHandle, + OUT EFI_PEI_FILE_HANDLE *FileHandle + ) +{ + EFI_STATUS Status; + UINTN Instance; + + // + // Search every FV for the DXE Core + // + Instance = 0; + *FileHandle = NULL; + + while (1) + { + Status = FfsFindNextVolume (Instance++, VolumeHandle); + if (EFI_ERROR (Status)) + { + break; + } + + Status = FfsFindNextFile (FileType, *VolumeHandle, FileHandle); + if (!EFI_ERROR (Status)) + { + break; + } + } + + return Status; +} + + + +/** + Get Fv image from the FV type file, then add FV & FV2 Hob. + + @param FileHandle File handle of a Fv type file. + + + @retval EFI_NOT_FOUND FV image can't be found. + @retval EFI_SUCCESS Successfully to process it. + +**/ +EFI_STATUS +EFIAPI +FfsProcessFvFile ( + IN EFI_PEI_FILE_HANDLE FvFileHandle + ) +{ + EFI_STATUS Status; + EFI_PEI_FV_HANDLE FvImageHandle; + EFI_FV_INFO FvImageInfo; + UINT32 FvAlignment; + VOID *FvBuffer; + EFI_PEI_HOB_POINTERS HobFv2; + + FvBuffer = NULL; + + + // + // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already + // been extracted. + // + HobFv2.Raw = GetHobList (); + while ((HobFv2.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobFv2.Raw)) != NULL) { + if (CompareGuid (&(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name), &HobFv2.FirmwareVolume2->FileName)) { + // + // this FILE has been dispatched, it will not be dispatched again. + // + return EFI_SUCCESS; + } + HobFv2.Raw = GET_NEXT_HOB (HobFv2); + } + + // + // Find FvImage in FvFile + // + Status = FfsFindSectionData (EFI_SECTION_FIRMWARE_VOLUME_IMAGE, FvFileHandle, (VOID **)&FvImageHandle); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Collect FvImage Info. + // + Status = FfsGetVolumeInfo (FvImageHandle, &FvImageInfo); + ASSERT_EFI_ERROR (Status); + + // + // FvAlignment must be more than 8 bytes required by FvHeader structure. + // + FvAlignment = 1 << ((FvImageInfo.FvAttributes & EFI_FVB2_ALIGNMENT) >> 16); + if (FvAlignment < 8) { + FvAlignment = 8; + } + + // + // Check FvImage + // + if ((UINTN) FvImageInfo.FvStart % FvAlignment != 0) { + FvBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINT32) FvImageInfo.FvSize), FvAlignment); + if (FvBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + CopyMem (FvBuffer, FvImageInfo.FvStart, (UINTN) FvImageInfo.FvSize); + // + // Update FvImageInfo after reload FvImage to new aligned memory + // + FfsGetVolumeInfo ((EFI_PEI_FV_HANDLE) FvBuffer, &FvImageInfo); + } + + + // + // Inform HOB consumer phase, i.e. DXE core, the existance of this FV + // + BuildFvHob ((EFI_PHYSICAL_ADDRESS) (UINTN) FvImageInfo.FvStart, FvImageInfo.FvSize); + + // + // Makes the encapsulated volume show up in DXE phase to skip processing of + // encapsulated file again. + // + BuildFv2Hob ( + (EFI_PHYSICAL_ADDRESS) (UINTN) FvImageInfo.FvStart, + FvImageInfo.FvSize, + &FvImageInfo.FvName, + &(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name) + ); + + return EFI_SUCCESS; +} + + diff --git a/EmbeddedPkg/Library/PrePiLib/Hob.c b/EmbeddedPkg/Library/PrePiLib/Hob.c new file mode 100644 index 0000000000..3c6574282c --- /dev/null +++ b/EmbeddedPkg/Library/PrePiLib/Hob.c @@ -0,0 +1,808 @@ +/** @file + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include <PrePi.h> +#include <Guid/MemoryTypeInformation.h> + +// +// Have to use build system to set the original value in case we are running +// from FLASH and globals don't work. So if you do a GetHobList() and gHobList +// and gHobList is NULL the PCD default values are used. +// +VOID *gHobList = NULL; + + + + +// May want to put this into a library so you only need the PCD setings if you are using the feature? +VOID +BuildMemoryTypeInformationHob ( + VOID + ) +{ + EFI_MEMORY_TYPE_INFORMATION Info[10]; + + Info[0].Type = EfiACPIReclaimMemory; + Info[0].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiACPIReclaimMemory); + Info[1].Type = EfiACPIMemoryNVS; + Info[1].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiACPIMemoryNVS); + Info[2].Type = EfiReservedMemoryType; + Info[2].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiReservedMemoryType); + Info[3].Type = EfiRuntimeServicesData; + Info[3].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiRuntimeServicesData); + Info[4].Type = EfiRuntimeServicesCode; + Info[4].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiRuntimeServicesCode); + Info[5].Type = EfiBootServicesCode; + Info[5].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiBootServicesCode); + Info[6].Type = EfiBootServicesData; + Info[6].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiBootServicesData); + Info[7].Type = EfiLoaderCode; + Info[7].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiLoaderCode); + Info[8].Type = EfiLoaderData; + Info[8].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiLoaderData); + + // Terminator for the list + Info[9].Type = EfiMaxMemoryType; + Info[9].NumberOfPages = 0; + + + BuildGuidDataHob (&gEfiMemoryTypeInformationGuid, &Info, sizeof (Info)); +} + +/** + + +**/ +VOID +CreateHobList ( + IN VOID *MemoryBegin, + IN UINTN MemoryLength, + IN VOID *HobBase, + IN VOID *StackBase + ) +{ + EFI_HOB_HANDOFF_INFO_TABLE *Hob; + EFI_HOB_GENERIC_HEADER *HobEnd; + EFI_RESOURCE_ATTRIBUTE_TYPE Attributes; + + + Hob = HobBase; + HobEnd = (EFI_HOB_GENERIC_HEADER *)(Hob+1); + + Hob->Header.HobType = EFI_HOB_TYPE_HANDOFF; + Hob->Header.HobLength = sizeof(EFI_HOB_HANDOFF_INFO_TABLE); + Hob->Header.Reserved = 0; + + HobEnd->HobType = EFI_HOB_TYPE_END_OF_HOB_LIST; + HobEnd->HobLength = sizeof(EFI_HOB_GENERIC_HEADER); + HobEnd->Reserved = 0; + + Hob->Version = EFI_HOB_HANDOFF_TABLE_VERSION; + Hob->BootMode = BOOT_WITH_FULL_CONFIGURATION; + + Hob->EfiMemoryTop = (UINTN)MemoryBegin + MemoryLength; + Hob->EfiMemoryBottom = (UINTN)MemoryBegin; + Hob->EfiFreeMemoryTop = (UINTN)StackBase; + Hob->EfiFreeMemoryBottom = (EFI_PHYSICAL_ADDRESS)(UINTN)(HobEnd+1); + Hob->EfiEndOfHobList = (EFI_PHYSICAL_ADDRESS)(UINTN)HobEnd; + + SetHobList (Hob); + + BuildCpuHob (PcdGet8 (PcdPrePiCpuMemorySize), PcdGet8 (PcdPrePiCpuIoSize)); + + Attributes =( + EFI_RESOURCE_ATTRIBUTE_PRESENT | + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | + EFI_RESOURCE_ATTRIBUTE_TESTED | + EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE + ); + + BuildResourceDescriptorHob (EFI_RESOURCE_SYSTEM_MEMORY, Attributes, (UINTN)MemoryBegin, MemoryLength); + + + BuildStackHob ((UINTN)StackBase, Hob->EfiMemoryTop - (UINTN)StackBase); + + if (FeaturePcdGet (PcdPrePiProduceMemoryTypeInformationHob)) { + // Optional feature that helps prevent EFI memory map fragmentation. + BuildMemoryTypeInformationHob (); + } + +} + + +VOID +EFIAPI +BuildFvHobs ( + IN EFI_PHYSICAL_ADDRESS PhysicalStart, + IN UINT64 NumberOfBytes, + IN EFI_RESOURCE_ATTRIBUTE_TYPE *ResourceAttribute + ) +{ + + EFI_RESOURCE_ATTRIBUTE_TYPE Resource; + + BuildFvHob (PhysicalStart, NumberOfBytes); + + if (ResourceAttribute == NULL) { + Resource = (EFI_RESOURCE_ATTRIBUTE_PRESENT | + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | + EFI_RESOURCE_ATTRIBUTE_TESTED | + EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE); + } else { + Resource = *ResourceAttribute; + } + + BuildResourceDescriptorHob (EFI_RESOURCE_FIRMWARE_DEVICE, Resource, PhysicalStart, NumberOfBytes); +} + + + + + +/** + Returns the pointer to the HOB list. + + This function returns the pointer to first HOB in the list. + + @return The pointer to the HOB list. + +**/ +VOID * +EFIAPI +GetHobList ( + VOID + ) +{ + if (gHobList == NULL) { + return (VOID *)(UINTN)PcdGet32 (PcdPrePiHobBase); + } else { + return gHobList; + } +} + + + +/** + Updates the pointer to the HOB list. + + @param HobList Hob list pointer to store + +**/ +EFI_STATUS +EFIAPI +SetHobList ( + IN VOID *HobList + ) +{ + gHobList = HobList; + + // + // If this code is running from ROM this could fail + // + return (gHobList == HobList) ? EFI_SUCCESS: EFI_UNSUPPORTED; +} + + + +VOID * +CreateHob ( + IN UINT16 HobType, + IN UINT16 HobLength + ) +{ + EFI_HOB_HANDOFF_INFO_TABLE *HandOffHob; + EFI_HOB_GENERIC_HEADER *HobEnd; + EFI_PHYSICAL_ADDRESS FreeMemory; + VOID *Hob; + + HandOffHob = GetHobList (); + + HobLength = (UINT16)((HobLength + 0x7) & (~0x7)); + + FreeMemory = HandOffHob->EfiFreeMemoryTop - HandOffHob->EfiFreeMemoryBottom; + + if (FreeMemory < HobLength) { + return NULL; + } + + Hob = (VOID*) (UINTN) HandOffHob->EfiEndOfHobList; + ((EFI_HOB_GENERIC_HEADER*) Hob)->HobType = HobType; + ((EFI_HOB_GENERIC_HEADER*) Hob)->HobLength = HobLength; + ((EFI_HOB_GENERIC_HEADER*) Hob)->Reserved = 0; + + HobEnd = (EFI_HOB_GENERIC_HEADER*) ((UINTN)Hob + HobLength); + HandOffHob->EfiEndOfHobList = (EFI_PHYSICAL_ADDRESS) (UINTN) HobEnd; + + HobEnd->HobType = EFI_HOB_TYPE_END_OF_HOB_LIST; + HobEnd->HobLength = sizeof(EFI_HOB_GENERIC_HEADER); + HobEnd->Reserved = 0; + HobEnd++; + HandOffHob->EfiFreeMemoryBottom = (EFI_PHYSICAL_ADDRESS) (UINTN) HobEnd; + + return Hob; +} + + +/** + Returns the next instance of a HOB type from the starting HOB. + + This function searches the first instance of a HOB type from the starting HOB pointer. + If there does not exist such HOB type from the starting HOB pointer, it will return NULL. + In contrast with macro GET_NEXT_HOB(), this function does not skip the starting HOB pointer + unconditionally: it returns HobStart back if HobStart itself meets the requirement; + caller is required to use GET_NEXT_HOB() if it wishes to skip current HobStart. + If HobStart is NULL, then ASSERT(). + + @param Type The HOB type to return. + @param HobStart The starting HOB pointer to search from. + + @return The next instance of a HOB type from the starting HOB. + +**/ +VOID * +EFIAPI +GetNextHob ( + IN UINT16 Type, + IN CONST VOID *HobStart + ) +{ + EFI_PEI_HOB_POINTERS Hob; + + ASSERT (HobStart != NULL); + + Hob.Raw = (UINT8 *) HobStart; + // + // Parse the HOB list until end of list or matching type is found. + // + while (!END_OF_HOB_LIST (Hob)) { + if (Hob.Header->HobType == Type) { + return Hob.Raw; + } + Hob.Raw = GET_NEXT_HOB (Hob); + } + return NULL; +} + + + +/** + Returns the first instance of a HOB type among the whole HOB list. + + This function searches the first instance of a HOB type among the whole HOB list. + If there does not exist such HOB type in the HOB list, it will return NULL. + + @param Type The HOB type to return. + + @return The next instance of a HOB type from the starting HOB. + +**/ +VOID * +EFIAPI +GetFirstHob ( + IN UINT16 Type + ) +{ + VOID *HobList; + + HobList = GetHobList (); + return GetNextHob (Type, HobList); +} + + +/** + This function searches the first instance of a HOB from the starting HOB pointer. + Such HOB should satisfy two conditions: + its HOB type is EFI_HOB_TYPE_GUID_EXTENSION and its GUID Name equals to the input Guid. + If there does not exist such HOB from the starting HOB pointer, it will return NULL. + Caller is required to apply GET_GUID_HOB_DATA () and GET_GUID_HOB_DATA_SIZE () + to extract the data section and its size info respectively. + In contrast with macro GET_NEXT_HOB(), this function does not skip the starting HOB pointer + unconditionally: it returns HobStart back if HobStart itself meets the requirement; + caller is required to use GET_NEXT_HOB() if it wishes to skip current HobStart. + If Guid is NULL, then ASSERT(). + If HobStart is NULL, then ASSERT(). + + @param Guid The GUID to match with in the HOB list. + @param HobStart A pointer to a Guid. + + @return The next instance of the matched GUID HOB from the starting HOB. + +**/ +VOID * +EFIAPI +GetNextGuidHob ( + IN CONST EFI_GUID *Guid, + IN CONST VOID *HobStart + ){ + EFI_PEI_HOB_POINTERS GuidHob; + + GuidHob.Raw = (UINT8 *) HobStart; + while ((GuidHob.Raw = GetNextHob (EFI_HOB_TYPE_GUID_EXTENSION, GuidHob.Raw)) != NULL) { + if (CompareGuid (Guid, &GuidHob.Guid->Name)) { + break; + } + GuidHob.Raw = GET_NEXT_HOB (GuidHob); + } + return GuidHob.Raw; +} + + +/** + This function searches the first instance of a HOB among the whole HOB list. + Such HOB should satisfy two conditions: + its HOB type is EFI_HOB_TYPE_GUID_EXTENSION and its GUID Name equals to the input Guid. + If there does not exist such HOB from the starting HOB pointer, it will return NULL. + Caller is required to apply GET_GUID_HOB_DATA () and GET_GUID_HOB_DATA_SIZE () + to extract the data section and its size info respectively. + If Guid is NULL, then ASSERT(). + + @param Guid The GUID to match with in the HOB list. + + @return The first instance of the matched GUID HOB among the whole HOB list. + +**/ +VOID * +EFIAPI +GetFirstGuidHob ( + IN CONST EFI_GUID *Guid + ) +{ + VOID *HobList; + + HobList = GetHobList (); + return GetNextGuidHob (Guid, HobList); +} + + +/** + Get the Boot Mode from the HOB list. + + This function returns the system boot mode information from the + PHIT HOB in HOB list. + + @param VOID + + @return The Boot Mode. + +**/ +EFI_BOOT_MODE +EFIAPI +GetBootMode ( + VOID + ) +{ + EFI_PEI_HOB_POINTERS Hob; + + Hob.Raw = GetHobList (); + return Hob.HandoffInformationTable->BootMode; +} + + +/** + Get the Boot Mode from the HOB list. + + This function returns the system boot mode information from the + PHIT HOB in HOB list. + + @param VOID + + @return The Boot Mode. + +**/ +EFI_STATUS +EFIAPI +SetBootMode ( + IN EFI_BOOT_MODE BootMode + ) +{ + EFI_PEI_HOB_POINTERS Hob; + + Hob.Raw = GetHobList (); + Hob.HandoffInformationTable->BootMode = BootMode; + return BootMode; +} + +/** + Builds a HOB for a loaded PE32 module. + + This function builds a HOB for a loaded PE32 module. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If ModuleName is NULL, then ASSERT(). + If there is no additional space for HOB creation, then ASSERT(). + + @param ModuleName The GUID File Name of the module. + @param MemoryAllocationModule The 64 bit physical address of the module. + @param ModuleLength The length of the module in bytes. + @param EntryPoint The 64 bit physical address of the module entry point. + +**/ +VOID +EFIAPI +BuildModuleHob ( + IN CONST EFI_GUID *ModuleName, + IN EFI_PHYSICAL_ADDRESS MemoryAllocationModule, + IN UINT64 ModuleLength, + IN EFI_PHYSICAL_ADDRESS EntryPoint + ) +{ + EFI_HOB_MEMORY_ALLOCATION_MODULE *Hob; + + ASSERT (((MemoryAllocationModule & (EFI_PAGE_SIZE - 1)) == 0) && + ((ModuleLength & (EFI_PAGE_SIZE - 1)) == 0)); + + Hob = CreateHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, sizeof (EFI_HOB_MEMORY_ALLOCATION_MODULE)); + + CopyGuid (&(Hob->MemoryAllocationHeader.Name), &gEfiHobMemoryAllocModuleGuid); + Hob->MemoryAllocationHeader.MemoryBaseAddress = MemoryAllocationModule; + Hob->MemoryAllocationHeader.MemoryLength = ModuleLength; + Hob->MemoryAllocationHeader.MemoryType = EfiBootServicesCode; + + // + // Zero the reserved space to match HOB spec + // + ZeroMem (Hob->MemoryAllocationHeader.Reserved, sizeof (Hob->MemoryAllocationHeader.Reserved)); + + CopyGuid (&Hob->ModuleName, ModuleName); + Hob->EntryPoint = EntryPoint; +} + + +/** + Builds a HOB that describes a chunk of system memory. + + This function builds a HOB that describes a chunk of system memory. + If there is no additional space for HOB creation, then ASSERT(). + + @param ResourceType The type of resource described by this HOB. + @param ResourceAttribute The resource attributes of the memory described by this HOB. + @param PhysicalStart The 64 bit physical address of memory described by this HOB. + @param NumberOfBytes The length of the memory described by this HOB in bytes. + +**/ +VOID +EFIAPI +BuildResourceDescriptorHob ( + IN EFI_RESOURCE_TYPE ResourceType, + IN EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute, + IN EFI_PHYSICAL_ADDRESS PhysicalStart, + IN UINT64 NumberOfBytes + ) +{ + EFI_HOB_RESOURCE_DESCRIPTOR *Hob; + + Hob = CreateHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, sizeof (EFI_HOB_RESOURCE_DESCRIPTOR)); + + Hob->ResourceType = ResourceType; + Hob->ResourceAttribute = ResourceAttribute; + Hob->PhysicalStart = PhysicalStart; + Hob->ResourceLength = NumberOfBytes; +} + + +/** + Builds a GUID HOB with a certain data length. + + This function builds a customized HOB tagged with a GUID for identification + and returns the start address of GUID HOB data so that caller can fill the customized data. + The HOB Header and Name field is already stripped. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If Guid is NULL, then ASSERT(). + If there is no additional space for HOB creation, then ASSERT(). + If DataLength >= (0x10000 - sizeof (EFI_HOB_GUID_TYPE)), then ASSERT(). + + @param Guid The GUID to tag the customized HOB. + @param DataLength The size of the data payload for the GUID HOB. + + @return The start address of GUID HOB data. + +**/ +VOID * +EFIAPI +BuildGuidHob ( + IN CONST EFI_GUID *Guid, + IN UINTN DataLength + ) +{ + EFI_HOB_GUID_TYPE *Hob; + + // + // Make sure that data length is not too long. + // + ASSERT (DataLength <= (0xffff - sizeof (EFI_HOB_GUID_TYPE))); + + Hob = CreateHob (EFI_HOB_TYPE_GUID_EXTENSION, (UINT16) (sizeof (EFI_HOB_GUID_TYPE) + DataLength)); + CopyGuid (&Hob->Name, Guid); + return Hob + 1; +} + + +/** + Copies a data buffer to a newly-built HOB. + + This function builds a customized HOB tagged with a GUID for identification, + copies the input data to the HOB data field and returns the start address of the GUID HOB data. + The HOB Header and Name field is already stripped. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If Guid is NULL, then ASSERT(). + If Data is NULL and DataLength > 0, then ASSERT(). + If there is no additional space for HOB creation, then ASSERT(). + If DataLength >= (0x10000 - sizeof (EFI_HOB_GUID_TYPE)), then ASSERT(). + + @param Guid The GUID to tag the customized HOB. + @param Data The data to be copied into the data field of the GUID HOB. + @param DataLength The size of the data payload for the GUID HOB. + + @return The start address of GUID HOB data. + +**/ +VOID * +EFIAPI +BuildGuidDataHob ( + IN CONST EFI_GUID *Guid, + IN VOID *Data, + IN UINTN DataLength + ) +{ + VOID *HobData; + + ASSERT (Data != NULL || DataLength == 0); + + HobData = BuildGuidHob (Guid, DataLength); + + return CopyMem (HobData, Data, DataLength); +} + + +/** + Builds a Firmware Volume HOB. + + This function builds a Firmware Volume HOB. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The base address of the Firmware Volume. + @param Length The size of the Firmware Volume in bytes. + +**/ +VOID +EFIAPI +BuildFvHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + EFI_HOB_FIRMWARE_VOLUME *Hob; + + Hob = CreateHob (EFI_HOB_TYPE_FV, sizeof (EFI_HOB_FIRMWARE_VOLUME)); + + Hob->BaseAddress = BaseAddress; + Hob->Length = Length; +} + + +/** + Builds a EFI_HOB_TYPE_FV2 HOB. + + This function builds a EFI_HOB_TYPE_FV2 HOB. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The base address of the Firmware Volume. + @param Length The size of the Firmware Volume in bytes. + @param FvName The name of the Firmware Volume. + @param FileName The name of the file. + +**/ +VOID +EFIAPI +BuildFv2Hob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN CONST EFI_GUID *FvName, + IN CONST EFI_GUID *FileName + ) +{ + EFI_HOB_FIRMWARE_VOLUME2 *Hob; + + Hob = CreateHob (EFI_HOB_TYPE_FV2, sizeof (EFI_HOB_FIRMWARE_VOLUME2)); + + Hob->BaseAddress = BaseAddress; + Hob->Length = Length; + CopyGuid (&Hob->FvName, FvName); + CopyGuid (&Hob->FileName, FileName); +} + + + +/** + Builds a Capsule Volume HOB. + + This function builds a Capsule Volume HOB. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The base address of the Capsule Volume. + @param Length The size of the Capsule Volume in bytes. + +**/ +VOID +EFIAPI +BuildCvHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + ASSERT (FALSE); +} + + +/** + Builds a HOB for the CPU. + + This function builds a HOB for the CPU. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If there is no additional space for HOB creation, then ASSERT(). + + @param SizeOfMemorySpace The maximum physical memory addressability of the processor. + @param SizeOfIoSpace The maximum physical I/O addressability of the processor. + +**/ +VOID +EFIAPI +BuildCpuHob ( + IN UINT8 SizeOfMemorySpace, + IN UINT8 SizeOfIoSpace + ) +{ + EFI_HOB_CPU *Hob; + + Hob = CreateHob (EFI_HOB_TYPE_CPU, sizeof (EFI_HOB_CPU)); + + Hob->SizeOfMemorySpace = SizeOfMemorySpace; + Hob->SizeOfIoSpace = SizeOfIoSpace; + + // + // Zero the reserved space to match HOB spec + // + ZeroMem (Hob->Reserved, sizeof (Hob->Reserved)); +} + + +/** + Builds a HOB for the Stack. + + This function builds a HOB for the stack. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The 64 bit physical address of the Stack. + @param Length The length of the stack in bytes. + +**/ +VOID +EFIAPI +BuildStackHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + EFI_HOB_MEMORY_ALLOCATION_STACK *Hob; + + ASSERT (((BaseAddress & (EFI_PAGE_SIZE - 1)) == 0) && + ((Length & (EFI_PAGE_SIZE - 1)) == 0)); + + Hob = CreateHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, sizeof (EFI_HOB_MEMORY_ALLOCATION_STACK)); + + CopyGuid (&(Hob->AllocDescriptor.Name), &gEfiHobMemoryAllocStackGuid); + Hob->AllocDescriptor.MemoryBaseAddress = BaseAddress; + Hob->AllocDescriptor.MemoryLength = Length; + Hob->AllocDescriptor.MemoryType = EfiBootServicesData; + + // + // Zero the reserved space to match HOB spec + // + ZeroMem (Hob->AllocDescriptor.Reserved, sizeof (Hob->AllocDescriptor.Reserved)); +} + + +/** + Update the Stack Hob if the stack has been moved + + @param BaseAddress The 64 bit physical address of the Stack. + @param Length The length of the stack in bytes. + +**/ +VOID +UpdateStackHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + EFI_PEI_HOB_POINTERS Hob; + + Hob.Raw = GetHobList (); + while ((Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw)) != NULL) { + if (CompareGuid (&gEfiHobMemoryAllocStackGuid, &(Hob.MemoryAllocationStack->AllocDescriptor.Name))) { + // + // Build a new memory allocation HOB with old stack info with EfiConventionalMemory type + // to be reclaimed by DXE core. + // + BuildMemoryAllocationHob ( + Hob.MemoryAllocationStack->AllocDescriptor.MemoryBaseAddress, + Hob.MemoryAllocationStack->AllocDescriptor.MemoryLength, + EfiConventionalMemory + ); + // + // Update the BSP Stack Hob to reflect the new stack info. + // + Hob.MemoryAllocationStack->AllocDescriptor.MemoryBaseAddress = BaseAddress; + Hob.MemoryAllocationStack->AllocDescriptor.MemoryLength = Length; + break; + } + Hob.Raw = GET_NEXT_HOB (Hob); + } +} + + + +/** + Builds a HOB for the memory allocation. + + This function builds a HOB for the memory allocation. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The 64 bit physical address of the memory. + @param Length The length of the memory allocation in bytes. + @param MemoryType Type of memory allocated by this HOB. + +**/ +VOID +EFIAPI +BuildMemoryAllocationHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN EFI_MEMORY_TYPE MemoryType + ) +{ + EFI_HOB_MEMORY_ALLOCATION *Hob; + + ASSERT (((BaseAddress & (EFI_PAGE_SIZE - 1)) == 0) && + ((Length & (EFI_PAGE_SIZE - 1)) == 0)); + + Hob = CreateHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, sizeof (EFI_HOB_MEMORY_ALLOCATION)); + + ZeroMem (&(Hob->AllocDescriptor.Name), sizeof (EFI_GUID)); + Hob->AllocDescriptor.MemoryBaseAddress = BaseAddress; + Hob->AllocDescriptor.MemoryLength = Length; + Hob->AllocDescriptor.MemoryType = MemoryType; + // + // Zero the reserved space to match HOB spec + // + ZeroMem (Hob->AllocDescriptor.Reserved, sizeof (Hob->AllocDescriptor.Reserved)); +} + + diff --git a/EmbeddedPkg/Library/PrePiLib/Memory.c b/EmbeddedPkg/Library/PrePiLib/Memory.c new file mode 100644 index 0000000000..209c71b42f --- /dev/null +++ b/EmbeddedPkg/Library/PrePiLib/Memory.c @@ -0,0 +1,160 @@ +/** @file + Implementation of the 6 PEI Ffs (FV) APIs in library form. + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include <PrePi.h> + + + +/** + Allocates one or more 4KB pages of type EfiBootServicesData. + + Allocates the number of 4KB pages of MemoryType and returns a pointer to the + allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL + is returned. If there is not enough memory remaining to satisfy the request, then NULL is + returned. + + @param Pages The number of 4 KB pages to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocatePages ( + IN UINTN Pages + ) +{ + EFI_PEI_HOB_POINTERS Hob; + EFI_PHYSICAL_ADDRESS Offset; + + Hob.Raw = GetHobList (); + + // Check to see if on 4k boundary + Offset = Hob.HandoffInformationTable->EfiFreeMemoryTop & 0xFFF; + if (Offset != 0) { + // If not aligned, make the allocation aligned. + Hob.HandoffInformationTable->EfiFreeMemoryTop -= Offset; + } + + // + // Verify that there is sufficient memory to satisfy the allocation + // + if (Hob.HandoffInformationTable->EfiFreeMemoryTop - ((Pages * EFI_PAGE_SIZE) + sizeof (EFI_HOB_MEMORY_ALLOCATION)) < Hob.HandoffInformationTable->EfiFreeMemoryBottom) { + return 0; + } else { + // + // Update the PHIT to reflect the memory usage + // + Hob.HandoffInformationTable->EfiFreeMemoryTop -= Pages * EFI_PAGE_SIZE; + + // This routine used to create a memory allocation HOB a la PEI, but that's not + // necessary for us. + + return (VOID *)(UINTN)Hob.HandoffInformationTable->EfiFreeMemoryTop; + } +} + + +/** + Allocates one or more 4KB pages of type EfiBootServicesData at a specified alignment. + + Allocates the number of 4KB pages specified by Pages of type EfiBootServicesData with an + alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is + returned. If there is not enough memory at the specified alignment remaining to satisfy the + request, then NULL is returned. + If Alignment is not a power of two and Alignment is not zero, then ASSERT(). + + @param Pages The number of 4 KB pages to allocate. + @param Alignment The requested alignment of the allocation. Must be a power of two. + If Alignment is zero, then byte alignment is used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateAlignedPages ( + IN UINTN Pages, + IN UINTN Alignment + ) +{ + VOID *Memory; + UINTN AlignmentMask; + + // + // Alignment must be a power of two or zero. + // + ASSERT ((Alignment & (Alignment - 1)) == 0); + + if (Pages == 0) { + return NULL; + } + // + // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow. + // + ASSERT (Pages <= (MAX_ADDRESS - EFI_SIZE_TO_PAGES (Alignment))); + // + // We would rather waste some memory to save PEI code size. + // + Memory = (VOID *)(UINTN)AllocatePages (Pages + EFI_SIZE_TO_PAGES (Alignment)); + if (Alignment == 0) { + AlignmentMask = Alignment; + } else { + AlignmentMask = Alignment - 1; + } + return (VOID *) (UINTN) (((UINTN) Memory + AlignmentMask) & ~AlignmentMask); +} + + + + +/** + Allocates a buffer of type EfiBootServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiBootServicesData and returns a + pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is + returned. If there is not enough memory remaining to satisfy the request, then NULL is returned. + + @param AllocationSize The number of bytes to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocatePool ( + IN UINTN AllocationSize + ) +{ + EFI_HOB_MEMORY_POOL *Hob; + + Hob = GetHobList (); + + + // + // Verify that there is sufficient memory to satisfy the allocation + // + if (AllocationSize > 0x10000) { + // Please call AllcoatePages for big allocations + return 0; + } else { + + Hob = (EFI_HOB_MEMORY_POOL *)CreateHob (EFI_HOB_TYPE_MEMORY_POOL, (UINT16)(sizeof (EFI_HOB_TYPE_MEMORY_POOL) + AllocationSize)); + return (VOID *)(Hob + 1); + } +} + + + diff --git a/EmbeddedPkg/Library/PrePiLib/PrePi.h b/EmbeddedPkg/Library/PrePiLib/PrePi.h new file mode 100644 index 0000000000..dc3ef48614 --- /dev/null +++ b/EmbeddedPkg/Library/PrePiLib/PrePi.h @@ -0,0 +1,44 @@ +/** @file + Library that helps implement monolithic PEI (i.e. PEI part of SEC) + + Copyright (c) 2008-2009 Apple Inc. All rights reserved.<BR> + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _PI_PEI_H_ +#define _PI_PEI_H_ + +#include <PiPei.h> + +#include <Library/BaseLib.h> +#include <Library/PrePiLib.h> +#include <Library/PcdLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/UefiDecompressLib.h> +#include <Library/PeCoffLib.h> +#include <Library/CacheMaintenanceLib.h> + +#include <Guid/MemoryAllocationHob.h> + + +#define GET_HOB_TYPE(Hob) ((Hob).Header->HobType) +#define GET_HOB_LENGTH(Hob) ((Hob).Header->HobLength) +#define GET_NEXT_HOB(Hob) ((Hob).Raw + GET_HOB_LENGTH (Hob)) +#define END_OF_HOB_LIST(Hob) (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_END_OF_HOB_LIST) + +// +// Get the data and data size field of GUID +// +#define GET_GUID_HOB_DATA(GuidHob) ((VOID *) (((UINT8 *) &((GuidHob)->Name)) + sizeof (EFI_GUID))) +#define GET_GUID_HOB_DATA_SIZE(GuidHob) (((GuidHob)->Header).HobLength - sizeof (EFI_HOB_GUID_TYPE)) + +#endif diff --git a/EmbeddedPkg/Library/PrePiLib/PrePiLib.c b/EmbeddedPkg/Library/PrePiLib/PrePiLib.c new file mode 100644 index 0000000000..f92be0fea3 --- /dev/null +++ b/EmbeddedPkg/Library/PrePiLib/PrePiLib.c @@ -0,0 +1,231 @@ +/** @file + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include <PrePi.h> + +// +// Hack to work in NT32 +// +EFI_STATUS + +EFIAPI + +SecWinNtPeiLoadFile ( + + IN VOID *Pe32Data, + + IN EFI_PHYSICAL_ADDRESS *ImageAddress, + + IN UINT64 *ImageSize, + + IN EFI_PHYSICAL_ADDRESS *EntryPoint + + ); + + +EFI_STATUS +EFIAPI +LoadPeCoffImage ( + IN VOID *PeCoffImage, + OUT EFI_PHYSICAL_ADDRESS *ImageAddress, + OUT UINT64 *ImageSize, + OUT EFI_PHYSICAL_ADDRESS *EntryPoint + ) +{ + RETURN_STATUS Status; + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + VOID *Buffer; + + ZeroMem (&ImageContext, sizeof (ImageContext)); + + ImageContext.Handle = PeCoffImage; + ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; + + Status = PeCoffLoaderGetImageInfo (&ImageContext); + ASSERT_EFI_ERROR (Status); + + + // + // Allocate Memory for the image + // + Buffer = AllocatePages (EFI_SIZE_TO_PAGES((UINT32)ImageContext.ImageSize)); + ASSERT (Buffer != 0); + + + ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer; + + // + // Load the image to our new buffer + // + Status = PeCoffLoaderLoadImage (&ImageContext); + ASSERT_EFI_ERROR (Status); + + // + // Relocate the image in our new buffer + // + Status = PeCoffLoaderRelocateImage (&ImageContext); + ASSERT_EFI_ERROR (Status); + + + *ImageAddress = ImageContext.ImageAddress; + *ImageSize = ImageContext.ImageSize; + *EntryPoint = ImageContext.EntryPoint; + + // + // Flush not needed for all architectures. We could have a processor specific + // function in this library that does the no-op if needed. + // + InvalidateInstructionCacheRange ((VOID *)(UINTN)*ImageAddress, (UINTN)*ImageSize); + + return Status; +} + + + +typedef +VOID +(EFIAPI *DXE_CORE_ENTRY_POINT) ( + IN VOID *HobStart + ); + +EFI_STATUS +EFIAPI +LoadDxeCoreFromFfsFile ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN UINTN StackSize + ) +{ + EFI_STATUS Status; + VOID *PeCoffImage; + EFI_PHYSICAL_ADDRESS ImageAddress; + UINT64 ImageSize; + EFI_PHYSICAL_ADDRESS EntryPoint; + VOID *BaseOfStack; + VOID *TopOfStack; + VOID *Hob; + EFI_FV_FILE_INFO FvFileInfo; + + + Status = FfsFindSectionData (EFI_SECTION_PE32, FileHandle, &PeCoffImage); + if (EFI_ERROR (Status)) { + return Status; + } + + + Status = LoadPeCoffImage (PeCoffImage, &ImageAddress, &ImageSize, &EntryPoint); +// For NT32 Debug Status = SecWinNtPeiLoadFile (PeCoffImage, &ImageAddress, &ImageSize, &EntryPoint); + ASSERT_EFI_ERROR (Status); + + // + // Extract the DxeCore GUID file name. + // + Status = FfsGetFileInfo (FileHandle, &FvFileInfo); + ASSERT_EFI_ERROR (Status); + + BuildModuleHob (&FvFileInfo.FileName, (EFI_PHYSICAL_ADDRESS)(UINTN)ImageAddress, EFI_SIZE_TO_PAGES ((UINT32) ImageSize) * EFI_PAGE_SIZE, EntryPoint); + + DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading DxeCore at 0x%10p EntryPoint=0x%10p\n", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)EntryPoint)); + + Hob = GetHobList (); + if (StackSize == 0) { + // User the current stack + ((DXE_CORE_ENTRY_POINT)(UINTN)EntryPoint) (Hob); + } else { + + // + // Allocate 128KB for the Stack + // + BaseOfStack = AllocatePages (EFI_SIZE_TO_PAGES (StackSize)); + ASSERT (BaseOfStack != NULL); + + // + // Compute the top of the stack we were allocated. Pre-allocate a UINTN + // for safety. + // + TopOfStack = (VOID *) ((UINTN) BaseOfStack + EFI_SIZE_TO_PAGES (StackSize) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT); + TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT); + + // + // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore. + // + UpdateStackHob ((EFI_PHYSICAL_ADDRESS)(UINTN) BaseOfStack, StackSize); + + SwitchStack ( + (SWITCH_STACK_ENTRY_POINT)(UINTN)EntryPoint, + Hob, + NULL, + TopOfStack + ); + + } + + // Should never get here as DXE Core does not return + DEBUG ((EFI_D_ERROR, "DxeCore returned\n")); + ASSERT (FALSE); + + return EFI_DEVICE_ERROR; +} + + + +EFI_STATUS +EFIAPI +LoadDxeCoreFromFv ( + IN UINTN *FvInstance, OPTIONAL + IN UINTN StackSize + ) +{ + EFI_STATUS Status; + EFI_PEI_FV_HANDLE VolumeHandle; + EFI_PEI_FILE_HANDLE FileHandle = NULL; + + if (FvInstance != NULL) { + // + // Caller passed in a specific FV to try, so only try that one + // + Status = FfsFindNextVolume (*FvInstance, &VolumeHandle); + if (!EFI_ERROR (Status)) { + Status = FfsFindNextFile (EFI_FV_FILETYPE_DXE_CORE, VolumeHandle, &FileHandle); + } + } else { + Status = FfsAnyFvFindFirstFile (EFI_FV_FILETYPE_DXE_CORE, &VolumeHandle, &FileHandle); + } + + if (!EFI_ERROR (Status)) { + return LoadDxeCoreFromFfsFile (FileHandle, StackSize); + } + + return Status; +} + + +EFI_STATUS +EFIAPI +DecompressFirstFv ( + VOID + ) +{ + EFI_STATUS Status; + EFI_PEI_FV_HANDLE VolumeHandle; + EFI_PEI_FILE_HANDLE FileHandle; + + Status = FfsAnyFvFindFirstFile (EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, &VolumeHandle, &FileHandle); + if (!EFI_ERROR (Status)) { + Status = FfsProcessFvFile (FileHandle); + } + + return Status; +} + + diff --git a/EmbeddedPkg/Library/PrePiLib/PrePiLib.inf b/EmbeddedPkg/Library/PrePiLib/PrePiLib.inf new file mode 100644 index 0000000000..278ee44722 --- /dev/null +++ b/EmbeddedPkg/Library/PrePiLib/PrePiLib.inf @@ -0,0 +1,90 @@ +#%HEADER%
+#/** @file
+# Component description file for Apple Pre PI Library
+#
+# LIbrary helps you build a platform that skips PEI and loads DXE Core
+# directly. Helps building HOBs, reading data from the FV, and doing
+# decompression.
+#
+# Copyright (c) 2008, Apple, Inc.
+#
+# All rights reserved. This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PrePiLib
+ FILE_GUID = 1F3A3278-82EB-4C0D-86F1-5BCDA5846CB2
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PrePiLib
+
+
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+ FwVol.c
+ Hob.c
+ Memory.c
+ PrePiLib.c
+ ReportStatusCode.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec # needed to support StatusCodes
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec # needed to support StatusCodes
+
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ BaseMemoryLib
+ UefiDecompressLib
+ PeCoffLib
+ CacheMaintenanceLib
+ PrintLib
+ SerialPortLib
+ ExtractGuidedSectionLib
+
+[Guids]
+ gEfiHobMemoryAllocModuleGuid
+ gEfiHobMemoryAllocStackGuid
+ gEfiStatusCodeSpecificDataGuid
+ gEfiMemoryTypeInformationGuid
+ gEfiStatusCodeDataTypeDebugGuid
+
+[Protocols]
+ gEfiStatusCodeRuntimeProtocolGuid
+
+
+[FixedPcd.common]
+ gEmbeddedTokenSpaceGuid.PcdPrePiHobBase
+ gEmbeddedTokenSpaceGuid.PcdPrePiTempMemorySize
+ gEmbeddedTokenSpaceGuid.PcdPrePiBfvBaseAddress
+ gEmbeddedTokenSpaceGuid.PcdPrePiBfvSize
+ gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize
+ gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize
+
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIReclaimMemory
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIMemoryNVS
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiReservedMemoryType
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesData
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesCode
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesCode
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesData
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiLoaderCode
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiLoaderData
+
+[FeaturePcd]
+ gEmbeddedTokenSpaceGuid.PcdPrePiProduceMemoryTypeInformationHob
diff --git a/EmbeddedPkg/Library/PrePiLib/ReportStatusCode.c b/EmbeddedPkg/Library/PrePiLib/ReportStatusCode.c new file mode 100644 index 0000000000..8833567fe5 --- /dev/null +++ b/EmbeddedPkg/Library/PrePiLib/ReportStatusCode.c @@ -0,0 +1,327 @@ +/** @file + Library that helps implement monolithic PEI + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include <PrePi.h> +#include <Library/ReportStatusCodeLib.h> +#include <Library/SerialPortLib.h> +#include <Library/PrintLib.h> + +#include <Protocol/StatusCode.h> +#include <Guid/StatusCodeDataTypeId.h> +#include <Guid/StatusCodeDataTypeDebug.h> +#include <FrameworkPei.h> + +#define EFI_STATUS_CODE_DATA_MAX_SIZE 200 + +EFI_STATUS +EFIAPI +SerialReportStatusCode ( + IN EFI_STATUS_CODE_TYPE CodeType, + IN EFI_STATUS_CODE_VALUE Value, + IN UINT32 Instance, + IN CONST EFI_GUID *CallerId, + IN CONST EFI_STATUS_CODE_DATA *Data OPTIONAL + ); + + +EFI_STATUS_CODE_PROTOCOL gStatusCode = { + (EFI_REPORT_STATUS_CODE)SerialReportStatusCode +}; + +/** + Extracts ASSERT() information from a status code structure. + + Converts the status code specified by CodeType, Value, and Data to the ASSERT() + arguments specified by Filename, Description, and LineNumber. If CodeType is + an EFI_ERROR_CODE, and CodeType has a severity of EFI_ERROR_UNRECOVERED, and + Value has an operation mask of EFI_SW_EC_ILLEGAL_SOFTWARE_STATE, extract + Filename, Description, and LineNumber from the optional data area of the + status code buffer specified by Data. The optional data area of Data contains + a Null-terminated ASCII string for the FileName, followed by a Null-terminated + ASCII string for the Description, followed by a 32-bit LineNumber. If the + ASSERT() information could be extracted from Data, then return TRUE. + Otherwise, FALSE is returned. + + If Data is NULL, then ASSERT(). + If Filename is NULL, then ASSERT(). + If Description is NULL, then ASSERT(). + If LineNumber is NULL, then ASSERT(). + + @param CodeType The type of status code being converted. + @param Value The status code value being converted. + @param Data Pointer to status code data buffer. + @param Filename Pointer to the source file name that generated the ASSERT(). + @param Description Pointer to the description of the ASSERT(). + @param LineNumber Pointer to source line number that generated the ASSERT(). + + @retval TRUE The status code specified by CodeType, Value, and Data was + converted ASSERT() arguments specified by Filename, Description, + and LineNumber. + @retval FALSE The status code specified by CodeType, Value, and Data could + not be converted to ASSERT() arguments. + +**/ +BOOLEAN +EFIAPI +ReportStatusCodeExtractAssertInfo ( + IN EFI_STATUS_CODE_TYPE CodeType, + IN EFI_STATUS_CODE_VALUE Value, + IN CONST EFI_STATUS_CODE_DATA *Data, + OUT CHAR8 **Filename, + OUT CHAR8 **Description, + OUT UINT32 *LineNumber + ) +{ + EFI_DEBUG_ASSERT_DATA *AssertData; + + ASSERT (Data != NULL); + ASSERT (Filename != NULL); + ASSERT (Description != NULL); + ASSERT (LineNumber != NULL); + + if (((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) && + ((CodeType & EFI_STATUS_CODE_SEVERITY_MASK) == EFI_ERROR_UNRECOVERED) && + ((Value & EFI_STATUS_CODE_OPERATION_MASK) == EFI_SW_EC_ILLEGAL_SOFTWARE_STATE)) { + AssertData = (EFI_DEBUG_ASSERT_DATA *)(Data + 1); + *Filename = (CHAR8 *)(AssertData + 1); + *Description = *Filename + AsciiStrLen (*Filename) + 1; + *LineNumber = AssertData->LineNumber; + return TRUE; + } + return FALSE; +} + + +/** + Extracts DEBUG() information from a status code structure. + + Converts the status code specified by Data to the DEBUG() arguments specified + by ErrorLevel, Marker, and Format. If type GUID in Data is + EFI_STATUS_CODE_DATA_TYPE_DEBUG_GUID, then extract ErrorLevel, Marker, and + Format from the optional data area of the status code buffer specified by Data. + The optional data area of Data contains a 32-bit ErrorLevel followed by Marker + which is 12 UINTN parameters, followed by a Null-terminated ASCII string for + the Format. If the DEBUG() information could be extracted from Data, then + return TRUE. Otherwise, FALSE is returned. + + If Data is NULL, then ASSERT(). + If ErrorLevel is NULL, then ASSERT(). + If Marker is NULL, then ASSERT(). + If Format is NULL, then ASSERT(). + + @param Data Pointer to status code data buffer. + @param ErrorLevel Pointer to error level mask for a debug message. + @param Marker Pointer to the variable argument list associated with Format. + @param Format Pointer to a Null-terminated ASCII format string of a + debug message. + + @retval TRUE The status code specified by Data was converted DEBUG() arguments + specified by ErrorLevel, Marker, and Format. + @retval FALSE The status code specified by Data could not be converted to + DEBUG() arguments. + +**/ +BOOLEAN +EFIAPI +ReportStatusCodeExtractDebugInfo ( + IN CONST EFI_STATUS_CODE_DATA *Data, + OUT UINT32 *ErrorLevel, + OUT BASE_LIST *Marker, + OUT CHAR8 **Format + ) +{ + EFI_DEBUG_INFO *DebugInfo; + + ASSERT (Data != NULL); + ASSERT (ErrorLevel != NULL); + ASSERT (Marker != NULL); + ASSERT (Format != NULL); + + // + // If the GUID type is not EFI_STATUS_CODE_DATA_TYPE_DEBUG_GUID then return FALSE + // + if (!CompareGuid (&Data->Type, &gEfiStatusCodeDataTypeDebugGuid)) { + return FALSE; + } + + // + // Retrieve the debug information from the status code record + // + DebugInfo = (EFI_DEBUG_INFO *)(Data + 1); + + *ErrorLevel = DebugInfo->ErrorLevel; + + // + // The first 12 * UINTN bytes of the string are really an + // argument stack to support varargs on the Format string. + // + *Marker = (BASE_LIST) (DebugInfo + 1); + *Format = (CHAR8 *)(((UINT64 *)*Marker) + 12); + + return TRUE; +} + + + + +EFI_STATUS +EFIAPI +SerialReportStatusCode ( + IN EFI_STATUS_CODE_TYPE CodeType, + IN EFI_STATUS_CODE_VALUE Value, + IN UINT32 Instance, + IN CONST EFI_GUID *CallerId, + IN CONST EFI_STATUS_CODE_DATA *Data OPTIONAL + ) +{ + CHAR8 *Filename; + CHAR8 *Description; + CHAR8 *Format; + CHAR8 Buffer[EFI_STATUS_CODE_DATA_MAX_SIZE]; + UINT32 ErrorLevel; + UINT32 LineNumber; + UINTN CharCount; + BASE_LIST Marker; + EFI_DEBUG_INFO *DebugInfo; + + Buffer[0] = '\0'; + + + if (Data != NULL && + ReportStatusCodeExtractAssertInfo (CodeType, Value, Data, &Filename, &Description, &LineNumber)) { + + // + // Print ASSERT() information into output buffer. + // + CharCount = AsciiSPrint ( + Buffer, + EFI_STATUS_CODE_DATA_MAX_SIZE, + "\n\rASSERT!: %a (%d): %a\n\r", + Filename, + LineNumber, + Description + ); + + + // + // Callout to standard output. + // + SerialPortWrite ((UINT8 *)Buffer, CharCount); + return EFI_SUCCESS; + + } else if (Data != NULL && + ReportStatusCodeExtractDebugInfo (Data, &ErrorLevel, &Marker, &Format)) { + + // + // Print DEBUG() information into output buffer. + // + CharCount = AsciiBSPrint ( + Buffer, + EFI_STATUS_CODE_DATA_MAX_SIZE, + Format, + Marker + ); + + } else if (Data != NULL && + CompareGuid (&Data->Type, &gEfiStatusCodeSpecificDataGuid) && + (CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE) { + + // + // Print specific data into output buffer. + // + DebugInfo = (EFI_DEBUG_INFO *) (Data + 1); + Marker = (BASE_LIST) (DebugInfo + 1); + Format = (CHAR8 *) (((UINT64 *) (DebugInfo + 1)) + 12); + + CharCount = AsciiBSPrint (Buffer, EFI_STATUS_CODE_DATA_MAX_SIZE, Format, Marker); + + } else if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) { + // + // Print ERROR information into output buffer. + // + + CharCount = AsciiSPrint ( + Buffer, + EFI_STATUS_CODE_DATA_MAX_SIZE, + "ERROR: C%x:V%x I%x", + CodeType, + Value, + Instance + ); + + // + // Make sure we don't try to print values that weren't intended to be printed, especially NULL GUID pointers. + // + if (CallerId != NULL) { + CharCount += AsciiSPrint ( + &Buffer[CharCount - 1], + (EFI_STATUS_CODE_DATA_MAX_SIZE - (sizeof (Buffer[0]) * CharCount)), + " %g", + CallerId + ); + } + + if (Data != NULL) { + CharCount += AsciiSPrint ( + &Buffer[CharCount - 1], + (EFI_STATUS_CODE_DATA_MAX_SIZE - (sizeof (Buffer[0]) * CharCount)), + " %x", + Data + ); + + } + + + CharCount += AsciiSPrint ( + &Buffer[CharCount - 1], + (EFI_STATUS_CODE_DATA_MAX_SIZE - (sizeof (Buffer[0]) * CharCount)), + "\n\r" + ); + + } else if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) { + CharCount = AsciiSPrint ( + Buffer, + EFI_STATUS_CODE_DATA_MAX_SIZE, + "PROGRESS CODE: V%x I%x\n\r", + Value, + Instance + ); + } else { + CharCount = AsciiSPrint ( + Buffer, + EFI_STATUS_CODE_DATA_MAX_SIZE, + "Undefined: C%x:V%x I%x\n\r", + CodeType, + Value, + Instance + ); + + } + + SerialPortWrite ((UINT8 *)Buffer, CharCount); + return EFI_SUCCESS; + +} + + +VOID +EFIAPI +AddDxeCoreReportStatusCodeCallback ( + VOID + ) +{ + BuildGuidDataHob (&gEfiStatusCodeRuntimeProtocolGuid, &gStatusCode, sizeof(VOID *)); +} + diff --git a/EmbeddedPkg/Library/SemiHostingDebugLib/DebugLib.c b/EmbeddedPkg/Library/SemiHostingDebugLib/DebugLib.c new file mode 100644 index 0000000000..61e3aac3c2 --- /dev/null +++ b/EmbeddedPkg/Library/SemiHostingDebugLib/DebugLib.c @@ -0,0 +1,258 @@ +/** @file
+
+ Copyright (c) 2008-2009, Apple Inc. All rights reserved.
+
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+/** @file
+ UEFI Debug Library that uses PrintLib to send messages to STDERR.
+
+ Copyright (c) 2006 - 2007, Intel Corporation<BR>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#include <Uefi.h>
+#include <Library/DebugLib.h>
+#include <Library/PrintLib.h>
+#include <Library/PcdLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/SemihostLib.h>
+
+//
+// Define the maximum debug and assert message length that this library supports
+//
+#define MAX_DEBUG_MESSAGE_LENGTH 0x100
+
+/**
+
+ Prints a debug message to the debug output device if the specified error level is enabled.
+
+ If any bit in ErrorLevel is also set in PcdDebugPrintErrorLevel, then print
+ the message specified by Format and the associated variable argument list to
+ the debug output device.
+
+ If Format is NULL, then ASSERT().
+
+ @param ErrorLevel The error level of the debug message.
+ @param Format Format string for the debug message to print.
+
+**/
+VOID
+EFIAPI
+DebugPrint (
+ IN UINTN ErrorLevel,
+ IN CONST CHAR8 *Format,
+ ...
+ )
+{
+ CHAR8 AsciiBuffer[MAX_DEBUG_MESSAGE_LENGTH];
+ VA_LIST Marker;
+
+ //
+ // If Format is NULL, then ASSERT().
+ //
+ ASSERT (Format != NULL);
+
+ //
+ // Check driver debug mask value and global mask
+ //
+ if ((ErrorLevel & PcdGet32(PcdDebugPrintErrorLevel)) == 0) {
+ return;
+ }
+
+ //
+ // Convert the DEBUG() message to a Unicode String
+ //
+ VA_START (Marker, Format);
+ AsciiVSPrint (AsciiBuffer, sizeof (AsciiBuffer), Format, Marker);
+ VA_END (Marker);
+
+ SemihostWriteString (AsciiBuffer);
+}
+
+
+/**
+
+ Prints an assert message containing a filename, line number, and description.
+ This may be followed by a breakpoint or a dead loop.
+
+ Print a message of the form "ASSERT <FileName>(<LineNumber>): <Description>\n"
+ to the debug output device. If DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED bit of
+ PcdDebugProperyMask is set then CpuBreakpoint() is called. Otherwise, if
+ DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED bit of PcdDebugProperyMask is set then
+ CpuDeadLoop() is called. If neither of these bits are set, then this function
+ returns immediately after the message is printed to the debug output device.
+ DebugAssert() must actively prevent recusrsion. If DebugAssert() is called while
+ processing another DebugAssert(), then DebugAssert() must return immediately.
+
+ If FileName is NULL, then a <FileName> string of "(NULL) Filename" is printed.
+
+ If Description is NULL, then a <Description> string of "(NULL) Description" is printed.
+
+ @param FileName Pointer to the name of the source file that generated the assert condition.
+ @param LineNumber The line number in the source file that generated the assert condition
+ @param Description Pointer to the description of the assert condition.
+
+**/
+VOID
+EFIAPI
+DebugAssert (
+ IN CONST CHAR8 *FileName,
+ IN UINTN LineNumber,
+ IN CONST CHAR8 *Description
+ )
+{
+ CHAR8 AsciiBuffer[MAX_DEBUG_MESSAGE_LENGTH];
+
+ //
+ // Generate the ASSERT() message in Unicode format
+ //
+ AsciiSPrint (AsciiBuffer, sizeof (AsciiBuffer), "ASSERT %a(%d): %a\n", FileName, LineNumber, Description);
+
+ SemihostWriteString (AsciiBuffer);
+
+ //
+ // Generate a Breakpoint, DeadLoop, or NOP based on PCD settings
+ //
+ if ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED) != 0) {
+ CpuBreakpoint ();
+ } else if ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED) != 0) {
+ CpuDeadLoop ();
+ }
+}
+
+
+/**
+
+ Fills a target buffer with PcdDebugClearMemoryValue, and returns the target buffer.
+
+ This function fills Length bytes of Buffer with the value specified by
+ PcdDebugClearMemoryValue, and returns Buffer.
+
+ If Buffer is NULL, then ASSERT().
+
+ If Length is greater than (MAX_ADDRESS ? Buffer + 1), then ASSERT().
+
+ @param Buffer Pointer to the target buffer to fill with PcdDebugClearMemoryValue.
+ @param Length Number of bytes in Buffer to fill with zeros PcdDebugClearMemoryValue.
+
+ @return Buffer
+
+**/
+VOID *
+EFIAPI
+DebugClearMemory (
+ OUT VOID *Buffer,
+ IN UINTN Length
+ )
+{
+ //
+ // If Buffer is NULL, then ASSERT().
+ //
+ ASSERT (Buffer != NULL);
+
+ //
+ // SetMem() checks for the the ASSERT() condition on Length and returns Buffer
+ //
+ return SetMem (Buffer, Length, PcdGet8(PcdDebugClearMemoryValue));
+}
+
+
+/**
+
+ Returns TRUE if ASSERT() macros are enabled.
+
+ This function returns TRUE if the DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of
+ PcdDebugProperyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of PcdDebugProperyMask is set.
+ @retval FALSE The DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of PcdDebugProperyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+DebugAssertEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED) != 0);
+}
+
+
+/**
+
+ Returns TRUE if DEBUG()macros are enabled.
+
+ This function returns TRUE if the DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of
+ PcdDebugProperyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugProperyMask is set.
+ @retval FALSE The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugProperyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+DebugPrintEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_PRINT_ENABLED) != 0);
+}
+
+
+/**
+
+ Returns TRUE if DEBUG_CODE()macros are enabled.
+
+ This function returns TRUE if the DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of
+ PcdDebugProperyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of PcdDebugProperyMask is set.
+ @retval FALSE The DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of PcdDebugProperyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+DebugCodeEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_CODE_ENABLED) != 0);
+}
+
+
+/**
+
+ Returns TRUE if DEBUG_CLEAR_MEMORY()macro is enabled.
+
+ This function returns TRUE if the DEBUG_PROPERTY_DEBUG_CLEAR_MEMORY_ENABLED bit of
+ PcdDebugProperyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The DEBUG_PROPERTY_DEBUG_CLEAR_MEMORY_ENABLED bit of PcdDebugProperyMask is set.
+ @retval FALSE The DEBUG_PROPERTY_DEBUG_CLEAR_MEMORY_ENABLED bit of PcdDebugProperyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+DebugClearMemoryEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED) != 0);
+}
diff --git a/EmbeddedPkg/Library/SemiHostingDebugLib/SemiHostingDebugLib.inf b/EmbeddedPkg/Library/SemiHostingDebugLib/SemiHostingDebugLib.inf new file mode 100644 index 0000000000..683f03f2f3 --- /dev/null +++ b/EmbeddedPkg/Library/SemiHostingDebugLib/SemiHostingDebugLib.inf @@ -0,0 +1,46 @@ +#%HEADER%
+#/** @file
+# Debug Library for UEFI drivers
+#
+# Library to abstract Framework extensions that conflict with UEFI 2.0 Specification
+# Copyright (c) 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.
+#
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SemiHostingDebugLib
+ FILE_GUID = 2A8D3FC4-8DB1-4D27-A3F3-780AF03CF848
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = DebugLib|BASE SEC DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+
+[Sources.common]
+ DebugLib.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ ArmPkg/ArmPkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ BaseLib
+ PcdLib
+ PrintLib
+ SemihostLib
+
+[Pcd.common]
+ gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel
+ gEfiMdePkgTokenSpaceGuid.PcdDebugClearMemoryValue
+ gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask
+
diff --git a/EmbeddedPkg/Library/SemiHostingSerialPortLib/SemiHostingSerialPortLib.inf b/EmbeddedPkg/Library/SemiHostingSerialPortLib/SemiHostingSerialPortLib.inf new file mode 100644 index 0000000000..c0a540342a --- /dev/null +++ b/EmbeddedPkg/Library/SemiHostingSerialPortLib/SemiHostingSerialPortLib.inf @@ -0,0 +1,35 @@ +#%HEADER%
+#/** @file
+# Semihosting serail port lib
+#
+# Copyright (c) 2008, Apple Inc.
+#
+# All rights reserved. This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SemiHostingSerialPortLib
+ FILE_GUID = E9FB2D1E-05D9-421C-8C35-6100BB0093B7
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = SerialPortLib
+
+
+[Sources.common]
+ SerialPortLib.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ ArmPkg/ArmPkg.dec
+
+[LibraryClasses]
+ SemihostLib
diff --git a/EmbeddedPkg/Library/SemiHostingSerialPortLib/SerialPortLib.c b/EmbeddedPkg/Library/SemiHostingSerialPortLib/SerialPortLib.c new file mode 100644 index 0000000000..cadeb73731 --- /dev/null +++ b/EmbeddedPkg/Library/SemiHostingSerialPortLib/SerialPortLib.c @@ -0,0 +1,145 @@ +/** @file
+ Serial I/O Port library functions with no library constructor/destructor
+
+
+ Copyright (c) 2008-2009, Apple Inc. All rights reserved.
+
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Uefi.h>
+#include <Library/DebugLib.h>
+#include <Library/SemihostLib.h>
+#include <Library/SerialPortLib.h>
+
+
+/*
+
+ Programmed hardware of Serial port.
+
+ @return Always return EFI_UNSUPPORTED.
+
+**/
+RETURN_STATUS
+EFIAPI
+SerialPortInitialize (
+ VOID
+ )
+{
+ if (SemihostConnectionSupported ()) {
+ return RETURN_SUCCESS;
+ } else {
+ return RETURN_UNSUPPORTED;
+ }
+}
+
+/**
+ Write data to serial device.
+
+ @param Buffer Point of data buffer which need to be writed.
+ @param NumberOfBytes Number of output bytes which are cached in Buffer.
+
+ @retval 0 Write data failed.
+ @retval !0 Actual number of bytes writed to serial device.
+
+**/
+
+#define PRINT_BUFFER_SIZE 512
+#define PRINT_BUFFER_THRESHOLD (PRINT_BUFFER_SIZE - 4)
+
+UINTN
+EFIAPI
+SerialPortWrite (
+ IN UINT8 *Buffer,
+ IN UINTN NumberOfBytes
+)
+{
+ UINT8 PrintBuffer[PRINT_BUFFER_SIZE];
+ UINTN SourceIndex = 0;
+ UINTN DestinationIndex = 0;
+ UINT8 CurrentCharacter;
+
+ while (SourceIndex < NumberOfBytes)
+ {
+ CurrentCharacter = Buffer[SourceIndex++];
+
+ switch (CurrentCharacter)
+ {
+ case '\r':
+ continue;
+
+ case '\n':
+ PrintBuffer[DestinationIndex++] = ' ';
+ // fall through
+
+ default:
+ PrintBuffer[DestinationIndex++] = CurrentCharacter;
+ break;
+ }
+
+ if (DestinationIndex > PRINT_BUFFER_THRESHOLD)
+ {
+ PrintBuffer[DestinationIndex] = '\0';
+ SemihostWriteString ((CHAR8 *) PrintBuffer);
+
+ DestinationIndex = 0;
+ }
+ }
+
+ if (DestinationIndex > 0)
+ {
+ PrintBuffer[DestinationIndex] = '\0';
+ SemihostWriteString ((CHAR8 *) PrintBuffer);
+ }
+
+ return 0;
+}
+
+
+/**
+ Read data from serial device and save the datas in buffer.
+
+ @param Buffer Point of data buffer which need to be writed.
+ @param NumberOfBytes Number of output bytes which are cached in Buffer.
+
+ @retval 0 Read data failed.
+ @retval !0 Aactual number of bytes read from serial device.
+
+**/
+UINTN
+EFIAPI
+SerialPortRead (
+ OUT UINT8 *Buffer,
+ IN UINTN NumberOfBytes
+)
+{
+ *Buffer = SemihostReadCharacter ();
+ return 1;
+}
+
+
+
+/**
+ Check to see if any data is avaiable to be read from the debug device.
+
+ @retval TRUE At least one byte of data is avaiable to be read
+ @retval FALS No data is avaiable to be read
+
+**/
+BOOLEAN
+EFIAPI
+SerialPortPoll (
+ VOID
+ )
+{
+ // Since SemiHosting read character is blocking always say we have a char ready?
+ return SemihostConnectionSupported ();
+}
+
diff --git a/EmbeddedPkg/Library/TemplateRealTimeClockLib/RealTimeClockLib.c b/EmbeddedPkg/Library/TemplateRealTimeClockLib/RealTimeClockLib.c new file mode 100644 index 0000000000..6a5acad376 --- /dev/null +++ b/EmbeddedPkg/Library/TemplateRealTimeClockLib/RealTimeClockLib.c @@ -0,0 +1,175 @@ +/** @file
+ Implement EFI RealTimeClock runtime services via RTC Lib.
+
+ Currently this driver does not support runtime virtual calling.
+
+ Copyright (c) 2008-2009, Apple Inc. All rights reserved.
+
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/RealTimeClockLib.h>
+
+
+/**
+ Returns the current time and date information, and the time-keeping capabilities
+ of the hardware platform.
+
+ @param Time A pointer to storage to receive a snapshot of the current time.
+ @param Capabilities An optional pointer to a buffer to receive the real time clock
+ device's capabilities.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_INVALID_PARAMETER Time is NULL.
+ @retval EFI_DEVICE_ERROR The time could not be retrieved due to hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+LibGetTime (
+ OUT EFI_TIME *Time,
+ OUT EFI_TIME_CAPABILITIES *Capabilities
+ )
+{
+ //
+ // Fill in Time and Capabilities via data from you RTC
+ //
+ return EFI_DEVICE_ERROR;
+}
+
+
+/**
+ Sets the current local time and date information.
+
+ @param Time A pointer to the current time.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_INVALID_PARAMETER A time field is out of range.
+ @retval EFI_DEVICE_ERROR The time could not be set due due to hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+LibSetTime (
+ IN EFI_TIME *Time
+ )
+{
+ //
+ // Use Time, to set the time in your RTC hardware
+ //
+ return EFI_DEVICE_ERROR;
+}
+
+
+/**
+ Returns the current wakeup alarm clock setting.
+
+ @param Enabled Indicates if the alarm is currently enabled or disabled.
+ @param Pending Indicates if the alarm signal is pending and requires acknowledgement.
+ @param Time The current alarm setting.
+
+ @retval EFI_SUCCESS The alarm settings were returned.
+ @retval EFI_INVALID_PARAMETER Any parameter is NULL.
+ @retval EFI_DEVICE_ERROR The wakeup time could not be retrieved due to a hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+LibGetWakeupTime (
+ OUT BOOLEAN *Enabled,
+ OUT BOOLEAN *Pending,
+ OUT EFI_TIME *Time
+ )
+{
+ // Not a required feature
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Sets the system wakeup alarm clock time.
+
+ @param Enabled Enable or disable the wakeup alarm.
+ @param Time If Enable is TRUE, the time to set the wakeup alarm for.
+
+ @retval EFI_SUCCESS If Enable is TRUE, then the wakeup alarm was enabled. If
+ Enable is FALSE, then the wakeup alarm was disabled.
+ @retval EFI_INVALID_PARAMETER A time field is out of range.
+ @retval EFI_DEVICE_ERROR The wakeup time could not be set due to a hardware error.
+ @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform.
+
+**/
+EFI_STATUS
+EFIAPI
+LibSetWakeupTime (
+ IN BOOLEAN Enabled,
+ OUT EFI_TIME *Time
+ )
+{
+ // Not a required feature
+ return EFI_UNSUPPORTED;
+}
+
+
+
+/**
+ This is the declaration of an EFI image entry point. This can be the entry point to an application
+ written to this specification, an EFI boot service driver, or an EFI runtime driver.
+
+ @param ImageHandle Handle that identifies the loaded image.
+ @param SystemTable System Table for this image.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+LibRtcInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ //
+ // Do some initialization if reqruied to turn on the RTC
+ //
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Fixup internal data so that EFI can be call in virtual mode.
+ Call the passed in Child Notify event and convert any pointers in
+ lib to virtual mode.
+
+ @param[in] Event The Event that is being processed
+ @param[in] Context Event Context
+**/
+VOID
+EFIAPI
+LibRtcVirtualNotifyEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // Only needed if you are going to support the OS calling RTC functions in virtual mode.
+ // You will need to call EfiConvertPointer (). To convert any stored physical addresses
+ // to virtual address. After the OS transistions to calling in virtual mode, all future
+ // runtime calls will be made in virtual mode.
+ //
+ return;
+}
+
+
+
diff --git a/EmbeddedPkg/Library/TemplateRealTimeClockLib/TemplateRealTimeClockLib.inf b/EmbeddedPkg/Library/TemplateRealTimeClockLib/TemplateRealTimeClockLib.inf new file mode 100644 index 0000000000..b9f39dd380 --- /dev/null +++ b/EmbeddedPkg/Library/TemplateRealTimeClockLib/TemplateRealTimeClockLib.inf @@ -0,0 +1,38 @@ +#%HEADER%
+#/** @file
+# Memory Status Code Library for UEFI drivers
+#
+# Lib to provide memory journal status code reporting Routines
+# Copyright (c) 2006, Intel Corporation.
+#
+# All rights reserved. This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TemplateRealTimeClockLib
+ FILE_GUID = B661E02D-A90B-42AB-A5F9-CF841AAA43D9
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = RealTimeClockLib
+
+
+[Sources.common]
+ RealTimeClockLib.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+
+[LibraryClasses]
+ IoLib
+ DebugLib
+
\ No newline at end of file diff --git a/EmbeddedPkg/Library/TemplateResetSystemLib/ResetSystemLib.c b/EmbeddedPkg/Library/TemplateResetSystemLib/ResetSystemLib.c new file mode 100644 index 0000000000..fe02f9863f --- /dev/null +++ b/EmbeddedPkg/Library/TemplateResetSystemLib/ResetSystemLib.c @@ -0,0 +1,103 @@ +/** @file
+ Template library implementation to support ResetSystem Runtime call.
+
+ Fill in the templates with what ever makes you system reset.
+
+
+ Copyright (c) 2008-2009, Apple Inc. All rights reserved.
+
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#include <PiDxe.h>
+
+#include <Library/BaseLib.h>
+#include <Library/IoLib.h>
+#include <Library/EfiResetSystemLib.h>
+
+
+/**
+ Resets the entire platform.
+
+ @param ResetType The type of reset to perform.
+ @param ResetStatus The status code for the reset.
+ @param DataSize The size, in bytes, of WatchdogData.
+ @param ResetData For a ResetType of EfiResetCold, EfiResetWarm, or
+ EfiResetShutdown the data buffer starts with a Null-terminated
+ Unicode string, optionally followed by additional binary data.
+
+**/
+EFI_STATUS
+EFIAPI
+LibResetSystem (
+ IN EFI_RESET_TYPE ResetType,
+ IN EFI_STATUS ResetStatus,
+ IN UINTN DataSize,
+ IN CHAR16 *ResetData OPTIONAL
+ )
+{
+ UINTN Address;
+ UINT8 Data;
+
+
+ switch (ResetType) {
+ case EfiResetCold:
+ // system power cycle
+
+ // Example using IoLib functions to do IO.
+ Address = 0x12345678;
+ Data = MmioRead8 (Address);
+ MmioWrite8 (Address, Data | 0x01);
+
+ // Note this is a bad example asa MmioOr8 (Address, 0x01) does the same thing
+ break;
+
+ case EfiResetWarm:
+ // not a full power cycle, maybe memory stays around.
+ // if not support do the same thing as EfiResetCold.
+ break;
+
+ case EfiResetShutdown:
+ // turn off the system.
+ // if not support do the same thing as EfiResetCold.
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If we reset, we would not have returned...
+ //
+ return EFI_DEVICE_ERROR;
+}
+
+
+
+/**
+ Initialize any infrastructure required for LibResetSystem () to function.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+LibInitializeResetSystem (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return EFI_SUCCESS;
+}
+
diff --git a/EmbeddedPkg/Library/TemplateResetSystemLib/TemplateResetSystemLib.inf b/EmbeddedPkg/Library/TemplateResetSystemLib/TemplateResetSystemLib.inf new file mode 100644 index 0000000000..4b6fa5bb1a --- /dev/null +++ b/EmbeddedPkg/Library/TemplateResetSystemLib/TemplateResetSystemLib.inf @@ -0,0 +1,36 @@ +#%HEADER%
+#/** @file
+# Memory Status Code Library for UEFI drivers
+#
+# Lib to provide memory journal status code reporting Routines
+# Copyright (c) 2006, Intel Corporation.
+#
+# All rights reserved. This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TemplateResetSystemLib
+ FILE_GUID = 40BAFDE5-4CC8-4FBE-A8BA-071890076E50
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = EfiResetSystemLib
+
+
+[Sources.common]
+ ResetSystemLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+
+[LibraryClasses]
+ IoLib
+ DebugLib
\ No newline at end of file diff --git a/EmbeddedPkg/Library/TemplateSerialPortLib/TemplateSerialPortLib.c b/EmbeddedPkg/Library/TemplateSerialPortLib/TemplateSerialPortLib.c new file mode 100644 index 0000000000..98087f9dc0 --- /dev/null +++ b/EmbeddedPkg/Library/TemplateSerialPortLib/TemplateSerialPortLib.c @@ -0,0 +1,99 @@ +/** @file
+ Serial I/O Port library functions with no library constructor/destructor
+
+ Copyright (c) 2008-2009, Apple Inc. All rights reserved.
+
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Base.h>
+
+
+#include <Library/SerialPortLib.h>
+
+/*
+
+ Programmed hardware of Serial port.
+
+ @return Always return EFI_UNSUPPORTED.
+
+**/
+RETURN_STATUS
+EFIAPI
+SerialPortInitialize (
+ VOID
+ )
+{
+ return RETURN_UNSUPPORTED;
+}
+
+/**
+ Write data to serial device.
+
+ @param Buffer Point of data buffer which need to be writed.
+ @param NumberOfBytes Number of output bytes which are cached in Buffer.
+
+ @retval 0 Write data failed.
+ @retval !0 Actual number of bytes writed to serial device.
+
+**/
+UINTN
+EFIAPI
+SerialPortWrite (
+ IN UINT8 *Buffer,
+ IN UINTN NumberOfBytes
+)
+{
+ return 0;
+}
+
+
+/**
+ Read data from serial device and save the datas in buffer.
+
+ @param Buffer Point of data buffer which need to be writed.
+ @param NumberOfBytes Number of output bytes which are cached in Buffer.
+
+ @retval 0 Read data failed.
+ @retval !0 Aactual number of bytes read from serial device.
+
+**/
+UINTN
+EFIAPI
+SerialPortRead (
+ OUT UINT8 *Buffer,
+ IN UINTN NumberOfBytes
+)
+{
+ return 0;
+}
+
+
+
+/**
+ Poll the serial device to see if there is any data waiting.
+
+ If there is data waiting to be read from the serial port, then return
+ TRUE. If there is no data waiting to be read from the serial port, then
+ return FALSE.
+
+ @retval TRUE Data is waiting to be read.
+ @retval FALSE There is no data waiting to be read.
+
+**/
+BOOLEAN
+EFIAPI
+SerialPortPoll (
+ VOID
+ )
+{
+ return 0;
+}
+
diff --git a/EmbeddedPkg/Library/TemplateSerialPortLib/TemplateSerialPortLib.inf b/EmbeddedPkg/Library/TemplateSerialPortLib/TemplateSerialPortLib.inf new file mode 100644 index 0000000000..e2a994b63e --- /dev/null +++ b/EmbeddedPkg/Library/TemplateSerialPortLib/TemplateSerialPortLib.inf @@ -0,0 +1,37 @@ +#%HEADER%
+#/** @file
+# Memory Status Code Library for UEFI drivers
+#
+# Lib to provide memory journal status code reporting Routines
+# Copyright (c) 2006, Intel Corporation.
+#
+# All rights reserved. This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TemplateSerialPortLib
+ FILE_GUID = A9133571-AD4B-4457-94A8-A9CC2CE7574F
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = SerialPortLib
+
+
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+ TemplateSerialPortLib.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+
|