alder_lake_bios/Insyde/InsydeSetupPkg/Library/H2ODisplayEngineLib/H2ODisplayEngineLib.c

1560 lines
44 KiB
C

/** @file
Implement H2O display engine related functions.
;******************************************************************************
;* Copyright (c) 2015 - 2020, Insyde Software Corp. All Rights Reserved.
;*
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
;* transmit, broadcast, present, recite, release, license or otherwise exploit
;* any part of this publication in any form, by any means, without the prior
;* written permission of Insyde Software Corporation.
;*
;******************************************************************************
*/
#include "H2ODisplayEngineLibInternal.h"
#include <Library/DxeOemSvcKernelLib.h>
#include <Guid/ZeroGuid.h>
/**
Check if the input character is a decimal character
@param[in] UnicodeChar Unicode character
@retval TRUE The input character is a decimal character
@retval FALSE The input character is not a decimal character
**/
BOOLEAN
IsDecChar (
IN CHAR16 UnicodeChar
)
{
return (BOOLEAN) (UnicodeChar >= '0' && UnicodeChar <= '9');
}
/**
Check if the input character is a hexadecimal character
@param[in] UnicodeChar Unicode character
@retval TRUE The input character is a hexadecimal character
@retval FALSE The input character is not a hexadecimal character
**/
BOOLEAN
IsHexChar (
IN CHAR16 UnicodeChar
)
{
if ((UnicodeChar >= '0' && UnicodeChar <= '9') ||
(UnicodeChar >= 'a' && UnicodeChar <= 'f') ||
(UnicodeChar >= 'A' && UnicodeChar <= 'F')) {
return TRUE;
}
return FALSE;
}
/**
Check if the input character is a visible character
@param[in] UnicodeChar Unicode character
@retval TRUE The input character is a visible character
@retval FALSE The input character is not a visible character
**/
BOOLEAN
IsVisibleChar (
IN CHAR16 UnicodeChar
)
{
return (BOOLEAN) (UnicodeChar >= ' ' && UnicodeChar <= '~');
}
/**
Check if the input string is a hexadecimal string
@param[in] Str Unicode string
@retval TRUE The input string is a hexadecimal string
@retval FALSE The input string is not a hexadecimal string
**/
BOOLEAN
IsHexString (
IN CHAR16 *Str
)
{
//
// skip preceeding white space
//
while ((*Str != 0) && *Str == L' ') {
Str++;
}
//
// skip preceeding zeros
//
while ((*Str != 0) && *Str == L'0') {
Str++;
}
return (BOOLEAN) (*Str == L'x' || *Str == L'X');
}
/**
Check if the input year value is leap year
@param[in] Year Year value
@retval TRUE The input year value is leap year
@retval FALSE The input year value is not leap year
**/
BOOLEAN
IsLeapYear (
IN UINT16 Year
)
{
return (BOOLEAN) ((Year%4 == 0) && ((Year%100 != 0) || (Year%400 == 0)));
}
/**
Check if the input time is valid
@param[in] EfiTime Pointer to EFI time
@retval TRUE The input time is valid
@retval FALSE The input time is not valid
**/
BOOLEAN
IsTimeValid (
IN EFI_TIME *EfiTime
)
{
if (EfiTime == NULL || (EfiTime->Hour > 23) || (EfiTime->Minute > 59) || (EfiTime->Second > 59)) {
return FALSE;
}
return TRUE;
}
/**
Check if the input day is valid
@param[in] EfiTime Pointer to EFI time
@retval TRUE The input day is valid
@retval FALSE The input day is not valid
**/
BOOLEAN
IsDayValid (
IN EFI_TIME *EfiTime
)
{
UINT8 DayOfMonth[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if (EfiTime == NULL ||
(EfiTime->Day < 1) ||
(EfiTime->Month < 1) ||
(EfiTime->Month > 12) ||
(EfiTime->Day > DayOfMonth[EfiTime->Month - 1]) ||
(EfiTime->Month == 2 && (!IsLeapYear (EfiTime->Year) && EfiTime->Day > 28)) ||
(EfiTime->Year < PcdGet16 (PcdRealTimeClockYearMin) || EfiTime->Year > PcdGet16 (PcdRealTimeClockYearMax))) {
return FALSE;
}
return TRUE;
}
/**
Check if current page is root page
@retval TRUE The current page is root page
@retval FALSE The current page is not root page, fail to locate protocol, current page pointer is NULL or
fail to get setup menu.
**/
BOOLEAN
IsRootPage (
VOID
)
{
EFI_STATUS Status;
H2O_FORM_BROWSER_PROTOCOL *FBProtocol;
SETUP_MENU_INFO CurrentSetupMenuInfo;
Status = gBS->LocateProtocol (&gH2OFormBrowserProtocolGuid, NULL, (VOID **) &FBProtocol);
if (EFI_ERROR (Status) || FBProtocol->CurrentP == NULL) {
return FALSE;
}
Status = GetSetupMenuInfoByPage (FBProtocol->CurrentP, &CurrentSetupMenuInfo);
if (EFI_ERROR (Status)) {
return FALSE;
}
return (BOOLEAN) (CurrentSetupMenuInfo.PageId == FBProtocol->CurrentP->PageId);
}
/**
Check if the edit value is valid or not.
The valid condition is that the edit value or possible range overlap on [MinValue, MaxValue].
@param[in] EditValue Edit value
@param[in] MinValue Minimum value
@param[in] MaxValue Maximum value
@param[in] IsHex Flag to determine that the edit value is hex
@retval TRUE The edit value is valid
@retval FALSE The edit value is not valid
**/
BOOLEAN
IsEditValueValid (
IN UINT64 EditValue,
IN UINT64 MinValue,
IN UINT64 MaxValue,
IN BOOLEAN IsHex
)
{
UINT32 Base;
UINT64 PossibleRangeMin;
UINT64 PossibleRangeMax;
UINT64 Limit;
//
// First, check if the edit value overlap on [MinValue, MaxValue]
//
if (EditValue == 0 || IN_RANGE (EditValue, MinValue, MaxValue)) {
return TRUE;
}
//
// Second, check if the passible range of edit value overlap on [MinValue, MaxValue]
// Keep possible range be multiplied by base until min value of possible range exceed MaxValue.
// For example: If [MinValue, MaxValue] is [2, 200], possible range will be [10, 19] and [100, 199] when edit value is 1.
//
if (EditValue > MaxValue) {
return FALSE;
}
Base = IsHex ? 16 : 10;
Limit = DivU64x32 ((UINT64) -1, Base);
PossibleRangeMin = EditValue;
PossibleRangeMax = EditValue;
while (PossibleRangeMin <= Limit) {
PossibleRangeMin = MultU64x32 (PossibleRangeMin, Base);
PossibleRangeMax = MultU64x32 (PossibleRangeMax, Base) + (Base - 1);
if (PossibleRangeMin > MaxValue) {
return FALSE;
}
if (IS_OVERLAP (PossibleRangeMin, PossibleRangeMax, MinValue, MaxValue)) {
return TRUE;
}
}
return FALSE;
}
/**
Check if the value string is valid or not.
@param[in] ValueStr Input value string for being checked
@param[in] IsHex Is hex number or not
@retval TRUE The value string is valid
@retval FALSE The value string is invalid
**/
STATIC
BOOLEAN
IsValidValueStr (
IN CHAR16 *ValueStr,
IN BOOLEAN IsHex
)
{
if (ValueStr == NULL) {
return FALSE;
}
while (*ValueStr != CHAR_NULL) {
if ((IsHex && !IsHexChar (*ValueStr)) ||
(!IsHex && !IsDecChar (*ValueStr))) {
return FALSE;
}
ValueStr++;
}
return TRUE;
}
/**
Convert question HII value to INT64 value based on numeric buffer size determined by opcode flag.
@param[in] NumericFlags Numeric opcode flag
@param[in] Value Question HII value
@return Numeric value in INT64 format
**/
STATIC
INT64
IfrNumericConvertValueToInt64 (
IN UINT8 NumericFlags,
IN UINT64 Value
)
{
switch (NumericFlags & EFI_IFR_NUMERIC_SIZE) {
case EFI_IFR_NUMERIC_SIZE_1:
return (INT64) ((INT8) ((UINT8) Value));
case EFI_IFR_NUMERIC_SIZE_2:
return (INT64) ((INT16) ((UINT16) Value));
case EFI_IFR_NUMERIC_SIZE_4:
return (INT64) ((INT32) ((UINT32) Value));
case EFI_IFR_NUMERIC_SIZE_8:
default:
return (INT64) Value;
}
}
/**
Convert INT64 value to question HII value based on numeric buffer size determined by opcode flag.
@param[in] NumericFlags Numeric opcode flag
@param[in] Int64Value Numeric value in INT64 format
@return Question HII value
**/
STATIC
UINT64
IfrNumericConvertInt64ToValue (
IN UINT8 NumericFlags,
IN INT64 Int64Value
)
{
switch (NumericFlags & EFI_IFR_NUMERIC_SIZE) {
case EFI_IFR_NUMERIC_SIZE_1:
return (UINT64) ((UINT8) ((INT8) Int64Value));
case EFI_IFR_NUMERIC_SIZE_2:
return (UINT64) ((UINT16) ((INT16) Int64Value));
case EFI_IFR_NUMERIC_SIZE_4:
return (UINT64) ((UINT32) ((INT32) Int64Value));
case EFI_IFR_NUMERIC_SIZE_8:
default:
return (UINT64) Int64Value;
}
}
/**
Convert the numeric string to question HII value.
@param[in] NumericFlags Numeric opcode flags
@param[in] NumericStr Pointer to numeric string
@retval Question HII value in UINT64 format or 0 if input string pointer is NULL.
**/
UINT64
IfrNumericConvertStrToValue (
IN UINT8 NumericFlags,
IN CHAR16 *NumericStr
)
{
UINT64 Value;
if (NumericStr == NULL) {
return 0;
}
while (*NumericStr != CHAR_NULL && *NumericStr == ' ') {
NumericStr++;
}
Value = 0;
switch (NumericFlags & EFI_IFR_DISPLAY) {
case EFI_IFR_DISPLAY_INT_DEC:
if (*NumericStr == '-') {
Value = StrDecimalToUint64 (NumericStr + 1);
switch (NumericFlags & EFI_IFR_NUMERIC_SIZE) {
case EFI_IFR_NUMERIC_SIZE_1:
Value = (UINT8) -((INT8) Value);
break;
case EFI_IFR_NUMERIC_SIZE_2:
Value = (UINT16) -((INT16) Value);
break;
case EFI_IFR_NUMERIC_SIZE_4:
Value = (UINT32) -((INT32) Value);
break;
case EFI_IFR_NUMERIC_SIZE_8:
Value = (UINT64) -((INT64) Value);
break;
}
} else {
Value = StrDecimalToUint64 (NumericStr);
}
return Value;
case EFI_IFR_DISPLAY_UINT_DEC:
return StrDecimalToUint64 (NumericStr);
case EFI_IFR_DISPLAY_UINT_HEX:
return StrHexToUint64 (NumericStr);
}
return Value;
}
/**
Get numeric value size from numeric question flags.
@param[in] NumericFlags Numeric opcode flags
@return Numeric value size
**/
UINTN
IfrNumericGetValueSize (
IN UINT8 NumericFlags
)
{
switch (NumericFlags & EFI_IFR_NUMERIC_SIZE) {
case EFI_IFR_NUMERIC_SIZE_1:
return 1;
case EFI_IFR_NUMERIC_SIZE_2:
return 2;
case EFI_IFR_NUMERIC_SIZE_4:
return 4;
case EFI_IFR_NUMERIC_SIZE_8:
default:
return 8;
}
}
/**
Check if the question HII value is in range [Minimum, Maximum] or not.
@param[in] NumericFlags Numeric opcode flags
@param[in] Value Question HII value
@param[in] Minimum Minimum value
@param[in] Maximum Maximum value
@retval TRUE The value is in range
@retval FALSE The value is not in range
**/
BOOLEAN
IfrNumericIsValueInRange (
IN UINT8 NumericFlags,
IN UINT64 Value,
IN UINT64 Minimum,
IN UINT64 Maximum
)
{
if ((NumericFlags & EFI_IFR_DISPLAY) == EFI_IFR_DISPLAY_INT_DEC) {
return IN_RANGE (IfrNumericConvertValueToInt64 (NumericFlags, Value),
IfrNumericConvertValueToInt64 (NumericFlags, Minimum),
IfrNumericConvertValueToInt64 (NumericFlags, Maximum));
} else {
return IN_RANGE (Value, Minimum, Maximum);
}
}
/**
Check if the editing signed decimal string in is valid or not.
@param[in] EditStr Pointer to editing signed decimal string
@param[in] Minimum Minimum value
@param[in] Maximum Maximum value
@retval TRUE The editing string is in valid
@retval FALSE The editing string is not valid
**/
STATIC
BOOLEAN
IfrNumericIsEditSignedDecStrValid (
IN CHAR16 *EditStr,
IN INT64 Minimum,
IN INT64 Maximum
)
{
UINTN ValueStrLen;
CHAR16 ValueStr[22];
BOOLEAN IsNegative;
CHAR16 LastChar;
UINT64 Value;
UINT64 Min;
UINT64 Max;
if (EditStr == NULL) {
return FALSE;
}
//
// Copy string without prefix space, minus char, prefix '0' and suffix space characters.
//
while (*EditStr == ' ') {
EditStr++;
}
if (*EditStr == '-') {
IsNegative = TRUE;
EditStr++;
} else {
IsNegative = FALSE;
}
while (*EditStr == '0') {
EditStr++;
}
for (ValueStrLen = StrLen (EditStr); ValueStrLen > 0 && EditStr[ValueStrLen - 1] == ' '; ValueStrLen--) {
}
if (ValueStrLen > 19) {
return FALSE;
}
StrnCpyS (ValueStr, ARRAY_SIZE(ValueStr), EditStr, ValueStrLen);
if (!IsValidValueStr (ValueStr, FALSE)) {
return FALSE;
}
if (ValueStrLen == 19) {
//
// Because 19 digits value maybe make INT64 overlap
// use 18 digits to check the value whether overlap
//
LastChar = ValueStr[18];
ValueStr[18] = '\0';
Value = StrDecimalToUint64 (ValueStr);
ValueStr[18] = LastChar;
//
// INT64 maximum (minimum) value is 9223372036854775807 (-9223372036854775808).
// If 18 digits is larger than 9223372036854775801ull, user can not input any key.
// If 18 digits is equal to 9223372036854775801ull, user can not input larger than '7' and '8' for positive and negative value
//
if (Value > 922337203685477580ull) {
return FALSE;
}
if ((Value == 922337203685477580ull) &&
((!IsNegative && LastChar > '7') || (IsNegative && LastChar > '8'))) {
return FALSE;
}
}
Value = StrDecimalToUint64 (ValueStr);
if (IsNegative) {
if (Minimum > 0) {
return FALSE;
}
Max = (UINT64) (-Minimum);
Min = (UINT64) ((Maximum > 0) ? 0 : -Maximum);
} else {
if (Maximum < 0) {
return FALSE;
}
Max = (UINT64) (Maximum);
Min = (UINT64) ((Minimum < 0) ? 0 : Minimum);
}
return IsEditValueValid (Value, Min, Max, FALSE);
}
/**
Check if the editing unsigned decimal string in is valid or not.
@param[in] EditStr Pointer to editing unsigned decimal string
@param[in] Minimum Minimum value
@param[in] Maximum Maximum value
@retval TRUE The editing string is in valid
@retval FALSE The editing string is not valid
**/
STATIC
BOOLEAN
IfrNumericIsEditDecStrValid (
IN CHAR16 *EditStr,
IN UINT64 Minimum,
IN UINT64 Maximum
)
{
UINTN ValueStrLen;
CHAR16 ValueStr[22];
CHAR16 LastChar;
UINT64 Value;
if (EditStr == NULL) {
return FALSE;
}
//
// Copy string without prefix space, prefix '0' and suffix space characters.
//
while (*EditStr == ' ' || *EditStr == '0') {
EditStr++;
}
for (ValueStrLen = StrLen (EditStr); ValueStrLen > 0 && EditStr[ValueStrLen - 1] == ' '; ValueStrLen--) {
}
if (ValueStrLen > 20) {
return FALSE;
}
StrnCpyS (ValueStr, ARRAY_SIZE(ValueStr), EditStr, ValueStrLen);
if (!IsValidValueStr (ValueStr, FALSE)) {
return FALSE;
}
if (ValueStrLen == 20) {
//
// Because 20 digits value maybe make UINT64 overlap
// use 19 digits to check the value whether overlap
//
LastChar = ValueStr[19];
ValueStr[19] = '\0';
Value = StrDecimalToUint64 (ValueStr);
ValueStr[19] = LastChar;
//
// UINT64 maximum value is 18446744073709551615.
// If 19 digits is larger than 1844674407370955161ull,
// use can not input any key.
//
if (Value > 1844674407370955161ull) {
return FALSE;
}
//
// UINT64 maximum value is 18446744073709551615.
// If 19 digits is equal to 1844674407370955161ull,
// use can not input larger than '5' key
//
if ((Value == 1844674407370955161ull) && (LastChar > '5')) {
return FALSE;
}
}
Value = StrDecimalToUint64 (ValueStr);
return IsEditValueValid (Value, Minimum, Maximum, FALSE);
}
/**
Check if the editing hex string in is valid or not.
@param[in] EditStr Pointer to editing hex string
@param[in] Minimum Minimum value
@param[in] Maximum Maximum value
@retval TRUE The editing string is in valid
@retval FALSE The editing string is not valid
**/
STATIC
BOOLEAN
IfrNumericIsEditHexStrValid (
IN CHAR16 *EditStr,
IN UINT64 Minimum,
IN UINT64 Maximum
)
{
UINTN ValueStrLen;
CHAR16 ValueStr[22];
UINT64 Value;
if (EditStr == NULL) {
return FALSE;
}
//
// Copy string without prefix space, prefix '0', prefix '0x' and suffix space characters.
//
while (*EditStr == ' ') {
EditStr++;
}
while (EditStr[0] == '0' && EditStr[1] == '0') {
EditStr++;
}
if (EditStr[0] == '0' && (EditStr[1] == 'x' || EditStr[1] == 'X')) {
EditStr += 2;
}
while (*EditStr == '0') {
EditStr++;
}
for (ValueStrLen = StrLen (EditStr); ValueStrLen > 0 && EditStr[ValueStrLen - 1] == ' '; ValueStrLen--) {
}
if (ValueStrLen > 16) {
return FALSE;
}
StrnCpyS (ValueStr, ARRAY_SIZE(ValueStr), EditStr, ValueStrLen);
if (!IsValidValueStr (ValueStr, TRUE)) {
return FALSE;
}
Value = StrHexToUint64 (ValueStr);
return IsEditValueValid (Value, Minimum, Maximum, TRUE);
}
/**
Check if the editing numeric string is valid or not.
@param[in] NumericFlags Numeric opcode flags
@param[in] EditStr Pointer to editing numeric string
@param[in] Minimum Minimum value
@param[in] Maximum Maximum value
@retval TRUE The editing string is in valid
@retval FALSE The editing string is not valid
**/
BOOLEAN
IfrNumericIsEditStrValid (
IN UINT8 NumericFlags,
IN CHAR16 *EditStr,
IN UINT64 Minimum,
IN UINT64 Maximum
)
{
switch (NumericFlags & EFI_IFR_DISPLAY) {
case EFI_IFR_DISPLAY_INT_DEC:
return IfrNumericIsEditSignedDecStrValid (
EditStr,
IfrNumericConvertValueToInt64(NumericFlags, Minimum),
IfrNumericConvertValueToInt64(NumericFlags, Maximum)
);
case EFI_IFR_DISPLAY_UINT_DEC:
return IfrNumericIsEditDecStrValid (EditStr, Minimum, Maximum);
case EFI_IFR_DISPLAY_UINT_HEX:
default:
return IfrNumericIsEditHexStrValid (EditStr, Minimum, Maximum);
}
}
/**
Check if the numeric value string is empty without any value char or not.
@param[in] NumericFlags Numeric opcode flags
@param[in] ValueStr Pointer to numeric value string
@retval TRUE The value string is empty
@retval FALSE The value string is not empty
**/
BOOLEAN
IfrNumericIsEmptyStr (
IN UINT8 NumericFlags,
IN CHAR16 *ValueStr
)
{
CHAR16 *StrPtr;
if (ValueStr == NULL || *ValueStr == CHAR_NULL) {
return TRUE;
}
while (*ValueStr == ' ') {
ValueStr++;
}
switch (NumericFlags & EFI_IFR_DISPLAY) {
case EFI_IFR_DISPLAY_INT_DEC:
if (*ValueStr == '-') {
ValueStr++;
}
break;
case EFI_IFR_DISPLAY_UINT_DEC:
break;
case EFI_IFR_DISPLAY_UINT_HEX:
default:
StrPtr = ValueStr;
while (StrPtr[0] == '0' && StrPtr[1] == '0') {
StrPtr++;
}
if (StrPtr[0] == '0' && (StrPtr[1] == 'x' || StrPtr[1] == 'X')) {
ValueStr = StrPtr + 2;
}
break;
}
return (BOOLEAN) (*ValueStr == CHAR_NULL);
}
/**
Get formatted number string.
@param[in] Question Pointer to H2O form browser question
@retval Formatted number string or NULL if input question pointer is NULL.
**/
CHAR16 *
IfrNumericPrintFormattedNumber (
IN H2O_FORM_BROWSER_Q *Question
)
{
INT64 Value;
if (Question == NULL) {
return NULL;
}
switch (Question->Flags & EFI_IFR_DISPLAY) {
case EFI_IFR_DISPLAY_INT_DEC:
Value = IfrNumericConvertValueToInt64 (Question->Flags, Question->HiiValue.Value.u64);
if (Value < 0) {
Value = -Value;
return CatSPrint (NULL, L"-%lu", Value);
} else {
return CatSPrint (NULL, L"%lu", Value);
}
case EFI_IFR_DISPLAY_UINT_DEC:
return CatSPrint (NULL, L"%lu", Question->HiiValue.Value.u64);
case EFI_IFR_DISPLAY_UINT_HEX:
default:
return CatSPrint (NULL, L"0x%lx", Question->HiiValue.Value.u64);
}
}
/**
Transfer EFI time to EFI HII value
@param[in] IsDate If true, transfer to HII value with date type. Otherwise, transfer to HII value with time type.
@param[in] EfiTime Pointer to EFI time
@param[out] HiiValue Pointer to EFI HII value
@retval EFI_SUCCESS Transfer EFI time to EFI HII value successfully
@retval EFI_INVALID_PARAMETER EfiTime or HiiValue is NULL
**/
EFI_STATUS
TransferEfiTimeToHiiValue (
IN BOOLEAN IsDate,
IN EFI_TIME *EfiTime,
OUT EFI_HII_VALUE *HiiValue
)
{
if (EfiTime == NULL || HiiValue == NULL) {
return EFI_INVALID_PARAMETER;
}
ZeroMem (HiiValue, sizeof(EFI_HII_VALUE));
if (IsDate) {
HiiValue->Type = EFI_IFR_TYPE_DATE;
HiiValue->Value.date.Year = EfiTime->Year;
HiiValue->Value.date.Month = EfiTime->Month;
HiiValue->Value.date.Day = EfiTime->Day;
} else {
HiiValue->Type = EFI_IFR_TYPE_TIME;
HiiValue->Value.time.Hour = EfiTime->Hour;
HiiValue->Value.time.Minute = EfiTime->Minute;
HiiValue->Value.time.Second = EfiTime->Second;
}
return EFI_SUCCESS;
}
/**
Transfer EFI HII value to EFI time
@param[in] HiiValue Pointer to EFI HII value
@param[out] EfiTime Pointer to EFI time
@retval EFI_SUCCESS Transfer EFI HII value to EFI time successfully
@retval EFI_INVALID_PARAMETER EfiTime or HiiValue is NULL or EFI HII value type is not date or time
**/
EFI_STATUS
TransferHiiValueToEfiTime (
IN EFI_HII_VALUE *HiiValue,
OUT EFI_TIME *EfiTime
)
{
if (EfiTime == NULL || HiiValue == NULL || (HiiValue->Type != EFI_IFR_TYPE_DATE && HiiValue->Type != EFI_IFR_TYPE_TIME)) {
return EFI_INVALID_PARAMETER;
}
if (HiiValue->Type == EFI_IFR_TYPE_DATE) {
EfiTime->Year = HiiValue->Value.date.Year;
EfiTime->Month = HiiValue->Value.date.Month;
EfiTime->Day = HiiValue->Value.date.Day;
} else {
EfiTime->Hour = HiiValue->Value.time.Hour;
EfiTime->Minute = HiiValue->Value.time.Minute;
EfiTime->Second = HiiValue->Value.time.Second;
}
return EFI_SUCCESS;
}
/**
Get next date or time value
@param[in] DateTimeItem Date time item
@param[in] Increasement If true, get next value. Otherwise, get previous value
@param[in, out] EfiTime Pointer to EFI time
@retval EFI_SUCCESS Get next date or time value successfully
@retval EFI_INVALID_PARAMETER EfiTime is NULL or DateTimeItem is invalid
@retval EFI_ABORTED Fail to get next date value
**/
EFI_STATUS
GetNextDateTimeValue (
IN H2O_DATE_TIME_ITEM DateTimeItem,
IN BOOLEAN Increasement,
IN OUT EFI_TIME *EfiTime
)
{
UINT8 DayOfMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
UINT8 MonthIndex;
EFI_TIME EfiTimeValue;
if (EfiTime == NULL) {
return EFI_INVALID_PARAMETER;
}
CopyMem (&EfiTimeValue, EfiTime, sizeof(EFI_TIME));
switch (DateTimeItem) {
case YearItem:
if (Increasement) {
EfiTimeValue.Year = (EfiTimeValue.Year == PcdGet16 (PcdRealTimeClockYearMax)) ? PcdGet16 (PcdRealTimeClockYearMin) : (EfiTimeValue.Year + 1);
} else {
EfiTimeValue.Year = (EfiTimeValue.Year == PcdGet16 (PcdRealTimeClockYearMin)) ? PcdGet16 (PcdRealTimeClockYearMax) : (EfiTimeValue.Year - 1);
}
break;
case MonthItem:
if (Increasement) {
EfiTimeValue.Month = (EfiTimeValue.Month == 12) ? 1 : (EfiTimeValue.Month + 1);
} else {
EfiTimeValue.Month = (EfiTimeValue.Month == 1) ? 12 : (EfiTimeValue.Month - 1);
}
break;
case DayItem:
MonthIndex = EfiTimeValue.Month - 1;
if (Increasement) {
if (EfiTimeValue.Month == 2 && IsLeapYear (EfiTimeValue.Year)) {
EfiTimeValue.Day = (EfiTimeValue.Day == 29) ? 1 : (EfiTimeValue.Day + 1);
} else {
EfiTimeValue.Day = (EfiTimeValue.Day == DayOfMonth[MonthIndex]) ? 1 : (EfiTimeValue.Day + 1);
}
} else {
if (EfiTimeValue.Month == 2 && IsLeapYear (EfiTimeValue.Year)) {
EfiTimeValue.Day = (EfiTimeValue.Day == 1) ? 29 : (EfiTimeValue.Day - 1);
} else {
EfiTimeValue.Day = (EfiTimeValue.Day == 1) ? DayOfMonth[MonthIndex] : (EfiTimeValue.Day - 1);
}
}
break;
case HourItem:
if (Increasement) {
EfiTimeValue.Hour = (EfiTimeValue.Hour == 23) ? 0 : (EfiTimeValue.Hour + 1);
} else {
EfiTimeValue.Hour = (EfiTimeValue.Hour == 0 ) ? 23 : (EfiTimeValue.Hour - 1);
}
break;
case MinuteItem:
if (Increasement) {
EfiTimeValue.Minute = (EfiTimeValue.Minute == 59) ? 0 : (EfiTimeValue.Minute + 1);
} else {
EfiTimeValue.Minute = (EfiTimeValue.Minute == 0) ? 59 : (EfiTimeValue.Minute - 1);
}
break;
case SecondItem:
if (Increasement) {
EfiTimeValue.Second = (EfiTimeValue.Second == 59) ? 0 : (EfiTimeValue.Second + 1);
} else {
EfiTimeValue.Second = (EfiTimeValue.Second == 0) ? 59 : (EfiTimeValue.Second - 1);
}
break;
default:
return EFI_INVALID_PARAMETER;
}
if (DateTimeItem == YearItem || DateTimeItem == MonthItem || DateTimeItem == DayItem) {
while (!IsDayValid (&EfiTimeValue)) {
EfiTimeValue.Day--;
if (EfiTimeValue.Day == 0) {
ASSERT(FALSE);
return EFI_ABORTED;
}
}
}
CopyMem (EfiTime, &EfiTimeValue, sizeof(EFI_TIME));
return EFI_SUCCESS;
}
/**
Get next question value
@param[in] Question Pointer to form browser question
@param[in] GoDown If true, get next value. Otherwise, get previous value
@param[out] ResultHiiValue Pointer to EFI HII value
@retval EFI_SUCCESS Get next question value successfully
@retval EFI_NOT_FOUND Step value is zero if question is numeric opcode or option list is empty if question is oneof opcode
@retval EFI_UNSUPPORTED Question operand is not numeric or oneof opcode
**/
EFI_STATUS
GetNextQuestionValue (
IN H2O_FORM_BROWSER_Q *Question,
IN BOOLEAN GoDown,
OUT EFI_HII_VALUE *ResultHiiValue
)
{
EFI_STATUS Status;
UINT64 Step;
UINT64 Minimum;
UINT64 Maximum;
UINT64 EditValue;
UINT64 CurrentValue;
UINT32 Index;
UINT32 OptionCount;
H2O_FORM_BROWSER_O *OptionList;
H2O_FORM_BROWSER_O *TargetOption;
Status = EFI_NOT_FOUND;
switch (Question->Operand) {
case EFI_IFR_NUMERIC_OP:
if (Question->Step == 0) {
break;
}
Step = Question->Step;
Minimum = Question->Minimum;
Maximum = Question->Maximum == 0 ? ((UINT64) -1) : Question->Maximum;
EditValue = Question->HiiValue.Value.u64;
if ((Question->Flags & EFI_IFR_DISPLAY) == EFI_IFR_DISPLAY_INT_DEC) {
EditValue = (UINT64) IfrNumericConvertValueToInt64 (Question->Flags, EditValue);
Minimum = (UINT64) IfrNumericConvertValueToInt64 (Question->Flags, Minimum);
Maximum = (UINT64) IfrNumericConvertValueToInt64 (Question->Flags, Maximum);
if (GoDown) {
if ((INT64) EditValue + (INT64) Step <= (INT64) Maximum) {
EditValue = (UINT64) ((INT64) EditValue + (INT64) Step);
} else if ((INT64) EditValue < (INT64) Maximum) {
EditValue = Maximum;
} else {
EditValue = Minimum;
}
} else {
if ((INT64) EditValue >= (INT64) Minimum + (INT64) Step) {
EditValue = (UINT64) ((INT64) EditValue - (INT64) Step);
} else if ((INT64) EditValue > (INT64) Minimum){
EditValue = Minimum;
} else {
EditValue = Maximum;
}
}
EditValue = IfrNumericConvertInt64ToValue (Question->Flags, (INT64) EditValue);
} else {
if (GoDown) {
if (EditValue + Step <= Maximum) {
EditValue = EditValue + Step;
} else if (EditValue < Maximum) {
EditValue = Maximum;
} else {
EditValue = Minimum;
}
} else {
if (EditValue >= Minimum + Step) {
EditValue = EditValue - Step;
} else if (EditValue > Minimum){
EditValue = Minimum;
} else {
EditValue = Maximum;
}
}
}
CopyMem (ResultHiiValue, &Question->HiiValue, sizeof (EFI_HII_VALUE));
ResultHiiValue->Value.u64 = EditValue;
Status = EFI_SUCCESS;
break;
case EFI_IFR_ONE_OF_OP:
if (Question->NumberOfOptions == 0 || Question->Options == NULL) {
break;
}
CurrentValue = Question->HiiValue.Value.u64;
OptionList = Question->Options;
OptionCount = (UINT32) Question->NumberOfOptions;
for (Index = 0; Index < OptionCount; Index++) {
if (OptionList[Index].HiiValue.Value.u64 == CurrentValue) {
break;
}
}
if (Index == OptionCount) {
break;
}
TargetOption = &OptionList[Index];
if (GoDown) {
if (Index != OptionCount - 1) {
TargetOption = &OptionList[Index + 1];
} else {
TargetOption = &OptionList[0];
}
} else {
if (Index != 0) {
TargetOption = &OptionList[Index - 1];
} else {
TargetOption = &OptionList[OptionCount - 1];
}
}
if (TargetOption == &OptionList[Index]) {
break;
}
CopyMem (ResultHiiValue, &Question->HiiValue, sizeof (EFI_HII_VALUE));
ResultHiiValue->Value.u64 = TargetOption->HiiValue.Value.u64;
Status = EFI_SUCCESS;
break;
case EFI_IFR_CHECKBOX_OP:
CopyMem (ResultHiiValue, &Question->HiiValue, sizeof (EFI_HII_VALUE));
ResultHiiValue->Value.b = (BOOLEAN) (Question->HiiValue.Value.b ? FALSE : TRUE);
Status = EFI_SUCCESS;
break;
default:
Status = EFI_UNSUPPORTED;
break;
}
return Status;
}
/**
Get opcode value by dialog type
@param[in] DialogType Dialog type
@return opcode value or zero if dialog type is not recognized
**/
UINT8
GetOpCodeByDialogType (
IN UINT32 DialogType
)
{
switch ((DialogType & H2O_FORM_BROWSER_D_TYPE_QUESTIONS) >> 16) {
case H2O_FORM_BROWSER_D_TYPE_ONE_OF:
return EFI_IFR_ONE_OF_OP;
case H2O_FORM_BROWSER_D_TYPE_ORDERED_LIST:
return EFI_IFR_ORDERED_LIST_OP;
case H2O_FORM_BROWSER_D_TYPE_NUMERIC:
return EFI_IFR_NUMERIC_OP;
case H2O_FORM_BROWSER_D_TYPE_STRING:
return EFI_IFR_STRING_OP;
case H2O_FORM_BROWSER_D_TYPE_DATE:
return EFI_IFR_DATE_OP;
case H2O_FORM_BROWSER_D_TYPE_TIME:
return EFI_IFR_TIME_OP;
case H2O_FORM_BROWSER_D_TYPE_PASSWORD:
return EFI_IFR_PASSWORD_OP;
default:
break;
}
return 0;
}
/**
Get HII buffer value by buffer type and index
@param[in] Buffer Pointer to buffer
@param[in] Type Buffer type
@param[in] Index Buffer index
@return buffer value or zero if Buffer is NULL or Type is not recognized
**/
UINT64
GetHiiBufferValue (
IN UINT8 *Buffer,
IN UINT8 Type,
IN UINT32 Index
)
{
UINT64 Data;
ASSERT (Buffer != NULL);
if (Buffer == NULL) {
return 0;
}
Data = 0;
switch (Type) {
case EFI_IFR_TYPE_NUM_SIZE_8:
Data = (UINT64) *(((UINT8 *) Buffer) + Index);
break;
case EFI_IFR_TYPE_NUM_SIZE_16:
Data = (UINT64) *(((UINT16 *) Buffer) + Index);
break;
case EFI_IFR_TYPE_NUM_SIZE_32:
Data = (UINT64) *(((UINT32 *) Buffer) + Index);
break;
case EFI_IFR_TYPE_NUM_SIZE_64:
Data = (UINT64) *(((UINT64 *) Buffer) + Index);
break;
default:
break;
}
return Data;
}
/**
Set HII buffer value by buffer type and index
@param[in] Buffer Pointer to buffer
@param[in] Type Buffer type
@param[in] Index Buffer index
@param[in] Value The value to be set
**/
VOID
SetHiiBufferValue (
IN UINT8 *Buffer,
IN UINT8 Type,
IN UINT32 Index,
IN UINT64 Value
)
{
ASSERT (Buffer != NULL);
if (Buffer == NULL) {
return;
}
switch (Type) {
case EFI_IFR_TYPE_NUM_SIZE_8:
*(((UINT8 *) Buffer) + Index) = (UINT8) Value;
break;
case EFI_IFR_TYPE_NUM_SIZE_16:
*(((UINT16 *) Buffer) + Index) = (UINT16) Value;
break;
case EFI_IFR_TYPE_NUM_SIZE_32:
*(((UINT32 *) Buffer) + Index) = (UINT32) Value;
break;
case EFI_IFR_TYPE_NUM_SIZE_64:
*(((UINT64 *) Buffer) + Index) = (UINT64) Value;
break;
default:
break;
}
}
EFI_STATUS
GetSetupMenuInfoByPage (
IN H2O_FORM_BROWSER_P *Page,
OUT SETUP_MENU_INFO *SetupMenuInfo
)
{
EFI_STATUS Status;
H2O_FORM_BROWSER_PROTOCOL *FBProtocol;
H2O_FORM_BROWSER_SM *SetupMenuData;
UINT32 HiiHandleIndex;
UINT32 Index;
SETUP_MENU_INFO *RootSetupMenuInfo;
if (Page == NULL || SetupMenuInfo == NULL) {
return EFI_INVALID_PARAMETER;
}
Status = gBS->LocateProtocol (&gH2OFormBrowserProtocolGuid, NULL, (VOID **) &FBProtocol);
if (EFI_ERROR (Status)) {
return Status;
}
Status = FBProtocol->GetSMInfo (FBProtocol, &SetupMenuData);
if (EFI_ERROR (Status)) {
return Status;
}
RootSetupMenuInfo = NULL;
do {
HiiHandleIndex = Page->PageId >> 16;
for (Index = 0; Index < SetupMenuData->NumberOfSetupMenus; Index++) {
if ((SetupMenuData->SetupMenuInfoList[Index].PageId >> 16) == HiiHandleIndex) {
RootSetupMenuInfo = &SetupMenuData->SetupMenuInfoList[Index];
break;
}
}
Page = Page->ParentPage;
} while (Page != NULL);
if (RootSetupMenuInfo != NULL) {
CopyMem (SetupMenuInfo, RootSetupMenuInfo, sizeof (SETUP_MENU_INFO));
}
FreeSetupMenuData (SetupMenuData);
return (RootSetupMenuInfo != NULL) ? EFI_SUCCESS : EFI_NOT_FOUND;
}
/**
Free form browser setup menu data
@param[in] SetupMenuData Pointer to form browser setup menu data
**/
VOID
FreeSetupMenuData (
IN H2O_FORM_BROWSER_SM *SetupMenuData
)
{
if (SetupMenuData == NULL) {
return;
}
if (SetupMenuData->TitleString != NULL) {
FreePool (SetupMenuData->TitleString);
}
if (SetupMenuData->CoreVersionString != NULL) {
FreePool (SetupMenuData->CoreVersionString);
}
if (SetupMenuData->SetupMenuInfoList != NULL) {
FreePool (SetupMenuData->SetupMenuInfoList);
}
FreePool (SetupMenuData);
}
/**
Get display engine resolution by Pcd
@param[in] DisplayEngineGuid Display engine guid
@param[in] HorizontalResolution Pointer to horizontal resolution
@param[in] VerticalResolution Pointer to vertical resolution
**/
VOID
EFIAPI
GetDisplayEngineResolutionByPcd (
IN EFI_GUID *DisplayEngineGuid,
IN UINT32 *HorizontalResolution,
IN UINT32 *VerticalResolution
)
{
UINT32 Horizontal;
UINT32 Vertical;
OEM_LOGO_RESOLUTION_DEFINITION TempLogoResolution;
OEM_LOGO_RESOLUTION_DEFINITION *LogoResolution;
H2O_DISPLAY_ENGINE_RESOLUTION *DisplayEngineResolution;
UINTN Count;
EFI_STATUS OemSvcStatus;
LogoResolution = (OEM_LOGO_RESOLUTION_DEFINITION *) PcdGetPtr (PcdDefaultLogoResolution);
CopyMem (&TempLogoResolution, LogoResolution, sizeof (OEM_LOGO_RESOLUTION_DEFINITION));
LogoResolution = &TempLogoResolution;
Horizontal = LogoResolution->ScuResolutionX;
Vertical = LogoResolution->ScuResolutionY;
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices Call: OemSvcLogoResolution \n"));
OemSvcStatus = OemSvcLogoResolution (&LogoResolution);
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices OemSvcLogoResolution Status: %r\n", OemSvcStatus));
if (Horizontal == 0xFFFF && Vertical == 0xFFFF) {
DisplayEngineResolution = (H2O_DISPLAY_ENGINE_RESOLUTION *)(LogoResolution + 1);
Count = 5;
while (Count--) {
if (CompareGuid (&DisplayEngineResolution->DisplayEngineGuid, DisplayEngineGuid)) {
Horizontal = DisplayEngineResolution->HorizontalResolution;
Vertical = DisplayEngineResolution->VerticalResolution;
break;
}
if (CompareGuid (&DisplayEngineResolution->DisplayEngineGuid, &gZeroGuid)) {
break;
}
DisplayEngineResolution++;
}
} else {
Horizontal = LogoResolution->ScuResolutionX;
Vertical = LogoResolution->ScuResolutionY;
}
*HorizontalResolution = Horizontal;
*VerticalResolution = Vertical;
}
/**
Check if user input key data match key data of hot key.
@param[in] HotKeyKeyData Pointer to input key data
@param[in] UserInputKeyData Pointer to key data of hot key
@retval TRUE User input key data match key data of hot key
@retval FALSE User input key data does not match key data of hot key
**/
STATIC
BOOLEAN
IsHotKeyPressed (
IN EFI_KEY_DATA *HotKeyKeyData,
IN EFI_KEY_DATA *UserInputKeyData
)
{
UINT32 HotKeyState;
UINT32 UserInputState;
BOOLEAN IsMatch;
BOOLEAN CheckCharCase;
ASSERT (HotKeyKeyData != NULL);
ASSERT (UserInputKeyData != NULL);
if (HotKeyKeyData == NULL || UserInputKeyData == NULL) {
return FALSE;
}
CheckCharCase = TRUE;
if (((HotKeyKeyData->KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) == EFI_SHIFT_STATE_VALID) &&
((UserInputKeyData->KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) == EFI_SHIFT_STATE_VALID)) {
HotKeyState = (HotKeyKeyData->KeyState.KeyShiftState & (EFI_RIGHT_SHIFT_PRESSED | EFI_LEFT_SHIFT_PRESSED));
UserInputState = (UserInputKeyData->KeyState.KeyShiftState & (EFI_RIGHT_SHIFT_PRESSED | EFI_LEFT_SHIFT_PRESSED));
IsMatch = (BOOLEAN) ((HotKeyState == 0 && UserInputState == 0) ||
((HotKeyState == (EFI_RIGHT_SHIFT_PRESSED | EFI_LEFT_SHIFT_PRESSED)) && (UserInputState != 0)) ||
((HotKeyState != (EFI_RIGHT_SHIFT_PRESSED | EFI_LEFT_SHIFT_PRESSED)) && (UserInputState == HotKeyState)));
if (!IsMatch) {
return FALSE;
}
HotKeyState = (HotKeyKeyData->KeyState.KeyShiftState & (EFI_RIGHT_CONTROL_PRESSED | EFI_LEFT_CONTROL_PRESSED));
UserInputState = (UserInputKeyData->KeyState.KeyShiftState & (EFI_RIGHT_CONTROL_PRESSED | EFI_LEFT_CONTROL_PRESSED));
IsMatch = (BOOLEAN) ((HotKeyState == 0 && UserInputState == 0) ||
((HotKeyState == (EFI_RIGHT_CONTROL_PRESSED | EFI_LEFT_CONTROL_PRESSED)) && (UserInputState != 0)) ||
((HotKeyState != (EFI_RIGHT_CONTROL_PRESSED | EFI_LEFT_CONTROL_PRESSED)) && (UserInputState == HotKeyState)));
if (!IsMatch) {
return FALSE;
}
if (HotKeyState != 0) {
CheckCharCase = FALSE;
}
HotKeyState = (HotKeyKeyData->KeyState.KeyShiftState & (EFI_RIGHT_ALT_PRESSED | EFI_LEFT_ALT_PRESSED));
UserInputState = (UserInputKeyData->KeyState.KeyShiftState & (EFI_RIGHT_ALT_PRESSED | EFI_LEFT_ALT_PRESSED));
IsMatch = (BOOLEAN) ((HotKeyState == 0 && UserInputState == 0) ||
((HotKeyState == (EFI_RIGHT_ALT_PRESSED | EFI_LEFT_ALT_PRESSED)) && (UserInputState != 0)) ||
((HotKeyState != (EFI_RIGHT_ALT_PRESSED | EFI_LEFT_ALT_PRESSED)) && (UserInputState == HotKeyState)));
if (!IsMatch) {
return FALSE;
}
if (HotKeyState != 0) {
CheckCharCase = FALSE;
}
HotKeyState = (HotKeyKeyData->KeyState.KeyShiftState & (EFI_RIGHT_LOGO_PRESSED | EFI_LEFT_LOGO_PRESSED));
UserInputState = (UserInputKeyData->KeyState.KeyShiftState & (EFI_RIGHT_LOGO_PRESSED | EFI_LEFT_LOGO_PRESSED));
IsMatch = (BOOLEAN) ((HotKeyState == 0 && UserInputState == 0) ||
((HotKeyState == (EFI_RIGHT_LOGO_PRESSED | EFI_LEFT_LOGO_PRESSED)) && (UserInputState != 0)) ||
((HotKeyState != (EFI_RIGHT_LOGO_PRESSED | EFI_LEFT_LOGO_PRESSED)) && (UserInputState == HotKeyState)));
if (!IsMatch) {
return FALSE;
}
if (HotKeyState != 0) {
CheckCharCase = FALSE;
}
HotKeyState = (HotKeyKeyData->KeyState.KeyShiftState & EFI_MENU_KEY_PRESSED);
UserInputState = (UserInputKeyData->KeyState.KeyShiftState & EFI_MENU_KEY_PRESSED);
if (HotKeyState != UserInputState) {
return FALSE;
}
if (HotKeyState != 0) {
CheckCharCase = FALSE;
}
HotKeyState = (HotKeyKeyData->KeyState.KeyShiftState & EFI_SYS_REQ_PRESSED);
UserInputState = (UserInputKeyData->KeyState.KeyShiftState & EFI_SYS_REQ_PRESSED);
if (HotKeyState != UserInputState) {
return FALSE;
}
if (HotKeyState != 0) {
CheckCharCase = FALSE;
}
}
if (HotKeyKeyData->Key.ScanCode != UserInputKeyData->Key.ScanCode ||
((CheckCharCase && HotKeyKeyData->Key.UnicodeChar != UserInputKeyData->Key.UnicodeChar) ||
(!CheckCharCase && TO_LOWER_UNICODE_CHAR (HotKeyKeyData->Key.UnicodeChar) != TO_LOWER_UNICODE_CHAR (UserInputKeyData->Key.UnicodeChar)))) {
return FALSE;
}
return TRUE;
}
/**
Get selected hot key info if input key data match one of input hot key info list.
@param[in] KeyData Pointer to input key data
@param[in] HotKeyInfoList Pointer to hot key info list
@param[out] SelectedHotKeyInfo Pointer to selected hot key info
@retval EFI_SUCCESS Get selected hot key info successfully
@retval EFI_NOT_FOUND Input key does not match one of input hot key info list.
@retval EFI_INVALID_PARAMETER KeyData, HotKeyInfoList or SelectedHotKeyInfo is NULL
**/
EFI_STATUS
GetSelectedHotKeyInfoByKeyData (
IN EFI_KEY_DATA *KeyData,
IN HOT_KEY_INFO *HotKeyInfoList,
OUT HOT_KEY_INFO *SelectedHotKeyInfo
)
{
if (KeyData == NULL || HotKeyInfoList == NULL || SelectedHotKeyInfo == NULL) {
return EFI_INVALID_PARAMETER;
}
while (!IS_END_OF_HOT_KEY_INFO (HotKeyInfoList)) {
if (IsHotKeyPressed (&HotKeyInfoList->KeyData, KeyData)) {
CopyMem (SelectedHotKeyInfo, HotKeyInfoList, sizeof (HOT_KEY_INFO));
return EFI_SUCCESS;
}
HotKeyInfoList++;
}
return EFI_NOT_FOUND;
}