From 2ef2b01e07c02db339f34004445734a2dbdd80e1 Mon Sep 17 00:00:00 2001 From: AJFISH Date: Sun, 6 Dec 2009 01:57:05 +0000 Subject: 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 --- .../Library/HalRuntimeServicesExampleLib/Capsule.c | 288 +++++++ .../Library/HalRuntimeServicesExampleLib/Mtc.c | 226 ++++++ .../ReportStatusCode.c | 198 +++++ .../Library/HalRuntimeServicesExampleLib/Reset.c | 63 ++ .../Library/HalRuntimeServicesExampleLib/Rtc.c | 861 +++++++++++++++++++++ .../HalRuntimeServicesExampleLib/Variable.c | 306 ++++++++ 6 files changed, 1942 insertions(+) create mode 100644 EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Capsule.c create mode 100644 EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Mtc.c create mode 100644 EmbeddedPkg/Library/HalRuntimeServicesExampleLib/ReportStatusCode.c create mode 100644 EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Reset.c create mode 100644 EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Rtc.c create mode 100644 EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Variable.c (limited to 'EmbeddedPkg/Library/HalRuntimeServicesExampleLib') 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 + + +// +//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
+ 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
+ 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
+ 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
+ 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
+ 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; +} + -- cgit v1.2.3