summaryrefslogtreecommitdiffstats
path: root/EmbeddedPkg/Library/HalRuntimeServicesExampleLib
diff options
context:
space:
mode:
Diffstat (limited to 'EmbeddedPkg/Library/HalRuntimeServicesExampleLib')
-rw-r--r--EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Capsule.c288
-rw-r--r--EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Mtc.c226
-rw-r--r--EmbeddedPkg/Library/HalRuntimeServicesExampleLib/ReportStatusCode.c198
-rw-r--r--EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Reset.c63
-rw-r--r--EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Rtc.c861
-rw-r--r--EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Variable.c306
6 files changed, 1942 insertions, 0 deletions
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;
+}
+