Mike Beaton c8b93357b8 OcConsoleLib: Simplify use of builtin renderer uncontrolled mode
The renderer already (esp. since recent changes incl. reset to controlled on cls)
manages its own transitions to controlled, so we just need to indicate uncontrolled
in cases where something else has been rendering graphics
2023-05-04 09:59:22 +01:00

998 lines
32 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/** @file
Builtin picker and password handler.
Copyright (C) 2019, vit9696. All rights reserved.<BR>
Copyright (C) 2021, Mike Beaton. All rights reserved.<BR>
SPDX-License-Identifier: BSD-3-Clause
**/
#include "BootManagementInternal.h"
#include <Guid/AppleFile.h>
#include <Guid/AppleVariable.h>
#include <Guid/OcVariable.h>
#include <IndustryStandard/AppleCsrConfig.h>
#include <Protocol/AppleBootPolicy.h>
#include <Protocol/AppleKeyMapAggregator.h>
#include <Protocol/AppleBeepGen.h>
#include <Protocol/LoadedImage.h>
#include <Protocol/OcAudio.h>
#include <Protocol/SimpleTextOut.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/BaseOverflowLib.h>
#include <Library/OcConsoleLib.h>
#include <Library/OcCryptoLib.h>
#include <Library/OcDebugLogLib.h>
#include <Library/DevicePathLib.h>
#include <Library/OcTimerLib.h>
#include <Library/OcTypingLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/OcAppleKeyMapLib.h>
#include <Library/OcBootManagementLib.h>
#include <Library/OcDevicePathLib.h>
#include <Library/OcFileLib.h>
#include <Library/OcMiscLib.h>
#include <Library/OcRtcLib.h>
#include <Library/OcStringLib.h>
#include <Library/PrintLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/UefiLib.h>
#include <Library/ResetSystemLib.h>
STATIC INT32 mStatusRow;
STATIC INT32 mStatusColumn;
STATIC INT32 mRunningColumn;
STATIC UINT64 mPreviousTick;
STATIC UINT64 mLoopDelayStart;
STATIC UINT64 mLoopDelayEnd;
typedef enum {
TAB_PICKER,
TAB_RESTART,
TAB_SHUTDOWN,
#if defined (BUILTIN_DEMONSTRATE_TYPING)
TAB_TYPING_DEMO,
#endif
TAB_MAX
} _TAB_FOCUS;
typedef _TAB_FOCUS TAB_FOCUS;
STATIC TAB_FOCUS mFocusList[] = {
TAB_PICKER,
TAB_RESTART,
TAB_SHUTDOWN,
#if defined (BUILTIN_DEMONSTRATE_TYPING)
TAB_TYPING_DEMO
#endif
};
STATIC TAB_FOCUS mFocusListMinimal[] = {
TAB_PICKER,
#if defined (BUILTIN_DEMONSTRATE_TYPING)
TAB_TYPING_DEMO
#endif
};
//
// Clamp menu entries for 80 column screen using ellipses to avoid wrapping to next line.
// TODO: (?) Update to actual text mode width, 80 is the guaranteed minimum.
//
#define MENU_PREFIX_LENGTH (5)
#define SAFE_ENTRY_LENGTH (80 - MENU_PREFIX_LENGTH - 1)
#define OC_KB_DBG_MAX_COLUMN 80
#define OC_KB_DBG_DELTA_SAMPLE_COLUMN 0 // 40
#if defined (BUILTIN_DEMONSTRATE_TYPING)
#define OC_KB_DBG_PRINT_ROW 4
#else
#define OC_KB_DBG_PRINT_ROW 2
#endif
#define OC_KB_DBG_DOWN_ROW (OC_KB_DBG_PRINT_ROW + 4)
#define OC_KB_DBG_X_ROW (OC_KB_DBG_PRINT_ROW + 5)
#define OC_KB_DBG_MODIFIERS_ROW (OC_KB_DBG_PRINT_ROW + 6)
STATIC
VOID
InitKbDebugDisplay (
VOID
)
{
mRunningColumn = 0;
mLoopDelayStart = 0;
mLoopDelayEnd = 0;
}
STATIC
VOID
EFIAPI
InstrumentLoopDelay (
UINT64 LoopDelayStart,
UINT64 LoopDelayEnd
)
{
mLoopDelayStart = LoopDelayStart;
mLoopDelayEnd = LoopDelayEnd;
}
STATIC
VOID
EFIAPI
ShowKbDebugDisplay (
UINTN NumKeysDown,
UINTN NumKeysHeld,
APPLE_MODIFIER_MAP Modifiers
)
{
CONST CHAR16 *ClearSpace = L" ";
UINT64 CurrentTick;
CHAR16 Code[3]; // includes flush-ahead space, to make progress visible
Code[1] = L' ';
Code[2] = L'\0';
CurrentTick = AsmReadTsc ();
if (mRunningColumn == OC_KB_DBG_DELTA_SAMPLE_COLUMN) {
gST->ConOut->SetCursorPosition (gST->ConOut, 0, mStatusRow + OC_KB_DBG_PRINT_ROW + 1);
Print (
L"Called delta = %,Lu%s\n",
CurrentTick - mPreviousTick,
ClearSpace
);
Print (
L"Loop delta = %,Lu (@ -%,Lu)%s%s\n",
mLoopDelayEnd == 0 ? 0 : mLoopDelayEnd - mLoopDelayStart,
mLoopDelayEnd == 0 ? 0 : CurrentTick - mLoopDelayEnd,
ClearSpace,
ClearSpace
);
}
mPreviousTick = CurrentTick;
//
// Show Apple Event keys
//
gST->ConOut->SetCursorPosition (gST->ConOut, mRunningColumn, mStatusRow + OC_KB_DBG_DOWN_ROW);
if (NumKeysDown > 0) {
Code[0] = L'D';
} else {
Code[0] = L' ';
}
gST->ConOut->OutputString (gST->ConOut, Code);
//
// Show AKMA key held info
//
gST->ConOut->SetCursorPosition (gST->ConOut, mRunningColumn, mStatusRow + OC_KB_DBG_X_ROW);
if (NumKeysHeld > 0) {
Code[0] = L'X';
} else {
Code[0] = L'.';
}
gST->ConOut->OutputString (gST->ConOut, Code);
//
// Modifiers info
//
gST->ConOut->SetCursorPosition (gST->ConOut, mRunningColumn, mStatusRow + OC_KB_DBG_MODIFIERS_ROW);
if (Modifiers == 0) {
Code[0] = L' ';
gST->ConOut->OutputString (gST->ConOut, Code);
} else {
Print (L"%X", Modifiers);
}
if (++mRunningColumn >= OC_KB_DBG_MAX_COLUMN) {
mRunningColumn = 0;
}
gST->ConOut->SetCursorPosition (gST->ConOut, mStatusColumn, mStatusRow);
}
STATIC OC_KB_DEBUG_CALLBACKS mSimplePickerKbDebug = {
InstrumentLoopDelay,
ShowKbDebugDisplay
};
STATIC
VOID
DisplaySystemMs (
VOID
)
{
UINT64 CurrentMillis;
CurrentMillis = DivU64x64Remainder (GetTimeInNanoSecond (GetPerformanceCounter ()), 1000000ULL, NULL);
Print (L"%,Lu]", CurrentMillis);
}
STATIC
CHAR16
GetPickerEntryCursor (
IN OC_BOOT_CONTEXT *BootContext,
IN UINT32 TimeOutSeconds,
IN INTN ChosenEntry,
IN UINTN Index,
IN OC_MODIFIER_MAP OcModifiers
)
{
if ((TimeOutSeconds > 0) && (BootContext->DefaultEntry->EntryIndex - 1 == Index)) {
return L'*';
}
if ((ChosenEntry >= 0) && ((UINTN)ChosenEntry == Index)) {
return ((OcModifiers & OC_MODIFIERS_SET_DEFAULT) != 0) ? L'+' : L'>';
}
return L' ';
}
VOID
UpdateTabContext (
IN BOOLEAN IsEntering,
IN OC_BOOT_CONTEXT *BootContext,
IN OC_BOOT_ENTRY **BootEntries,
IN TAB_FOCUS TabFocus,
IN INTN ChosenEntry,
IN CHAR16 OldEntryCursor,
#if defined (BUILTIN_DEMONSTRATE_TYPING)
IN INT32 TypingRow,
IN INT32 TypingColumn,
#endif
IN INT32 FirstIndexRow,
IN INT32 ShutdownRestartRow,
IN INT32 ShutdownColumn,
IN INT32 RestartColumn
)
{
CHAR16 Code[2];
Code[1] = L'\0';
if (TabFocus == TAB_PICKER) {
if (ChosenEntry >= 0) {
gST->ConOut->SetCursorPosition (gST->ConOut, 0, FirstIndexRow + ChosenEntry);
Code[0] = IsEntering ? OldEntryCursor : L' ';
gST->ConOut->OutputString (gST->ConOut, Code);
}
if (IsEntering) {
if (ChosenEntry >= 0) {
OcPlayAudioFile (BootContext->PickerContext, OC_VOICE_OVER_AUDIO_FILE_SELECTED, OC_VOICE_OVER_AUDIO_BASE_TYPE_OPEN_CORE, FALSE);
OcPlayAudioEntry (BootContext->PickerContext, BootEntries[ChosenEntry]);
} else {
//
// TODO: Sound for tabbing back to picker if no entry selected (cannot currently happen)
//
}
}
} else if ((TabFocus == TAB_SHUTDOWN) || (TabFocus == TAB_RESTART)) {
if (TabFocus == TAB_SHUTDOWN) {
gST->ConOut->SetCursorPosition (gST->ConOut, ShutdownColumn, ShutdownRestartRow);
} else {
gST->ConOut->SetCursorPosition (gST->ConOut, RestartColumn, ShutdownRestartRow);
}
Code[0] = IsEntering ? L'[' : '|';
gST->ConOut->OutputString (gST->ConOut, Code);
if (TabFocus == TAB_SHUTDOWN) {
gST->ConOut->OutputString (gST->ConOut, L"Shutdown");
} else {
gST->ConOut->OutputString (gST->ConOut, L"Restart");
}
Code[0] = IsEntering ? L']' : '|';
gST->ConOut->OutputString (gST->ConOut, Code);
if (IsEntering) {
if (TabFocus == TAB_SHUTDOWN) {
OcPlayAudioFile (BootContext->PickerContext, OC_VOICE_OVER_AUDIO_FILE_SELECTED, OC_VOICE_OVER_AUDIO_BASE_TYPE_OPEN_CORE, FALSE);
OcPlayAudioFile (BootContext->PickerContext, OC_VOICE_OVER_AUDIO_FILE_SHUT_DOWN, OC_VOICE_OVER_AUDIO_BASE_TYPE_OPEN_CORE, FALSE);
} else {
OcPlayAudioFile (BootContext->PickerContext, OC_VOICE_OVER_AUDIO_FILE_SELECTED, OC_VOICE_OVER_AUDIO_BASE_TYPE_OPEN_CORE, FALSE);
OcPlayAudioFile (BootContext->PickerContext, OC_VOICE_OVER_AUDIO_FILE_RESTART, OC_VOICE_OVER_AUDIO_BASE_TYPE_OPEN_CORE, FALSE);
}
}
}
#if defined (BUILTIN_DEMONSTRATE_TYPING)
else if (TabFocus == TAB_TYPING_DEMO) {
gST->ConOut->SetCursorPosition (gST->ConOut, TypingColumn, TypingRow);
Code[0] = IsEntering ? L'_' : ' ';
gST->ConOut->OutputString (gST->ConOut, Code);
}
#endif
}
EFI_STATUS
EFIAPI
OcShowSimpleBootMenu (
IN OC_BOOT_CONTEXT *BootContext,
IN OC_BOOT_ENTRY **BootEntries,
OUT OC_BOOT_ENTRY **ChosenBootEntry
)
{
APPLE_KEY_MAP_AGGREGATOR_PROTOCOL *KeyMap;
UINTN Index;
UINTN Length;
OC_PICKER_KEY_INFO PickerKeyInfo;
INTN ChosenEntry;
INTN OldChosenEntry;
INT32 FirstIndexRow;
INT32 MillisColumn;
CHAR16 EntryCursor;
CHAR16 OldEntryCursor;
CHAR16 Code[2];
UINT32 TimeOutSeconds;
UINT32 Count;
UINT64 KeyEndTime;
BOOLEAN PlayedOnce;
BOOLEAN PlayChosen;
BOOLEAN ModifiersChanged;
#if defined (BUILTIN_DEMONSTRATE_TYPING)
INT32 TypingRow;
INT32 TypingColumn;
INT32 TypingStartColumn;
#endif
INT32 ShutdownRestartRow;
INT32 ShutdownColumn;
INT32 RestartColumn;
UINTN FocusState;
TAB_FOCUS *FocusList;
UINTN NumFocusList;
Code[1] = L'\0';
TimeOutSeconds = BootContext->PickerContext->TimeoutSeconds;
KeyEndTime = 0;
ASSERT (BootContext->DefaultEntry != NULL);
ChosenEntry = (INTN)(BootContext->DefaultEntry->EntryIndex - 1);
OldChosenEntry = ChosenEntry;
EntryCursor = L'\0';
OldEntryCursor = L'\0';
FirstIndexRow = -1;
FocusState = 0;
if ((BootContext->PickerContext->PickerAttributes & OC_ATTR_USE_MINIMAL_UI) == 0) {
FocusList = mFocusList;
NumFocusList = ARRAY_SIZE (mFocusList);
} else {
FocusList = mFocusListMinimal;
NumFocusList = ARRAY_SIZE (mFocusListMinimal);
}
//
//  Used to detect changes.
//
PickerKeyInfo.OcModifiers = OC_MODIFIERS_NONE;
PlayedOnce = FALSE;
PlayChosen = FALSE;
DEBUG_CODE_BEGIN ();
if ((BootContext->PickerContext->PickerAttributes & OC_ATTR_SHOW_DEBUG_DISPLAY) != 0) {
DEBUG ((DEBUG_INFO, "OCB: Init builtin picker debug\n"));
InitKbDebugDisplay ();
BootContext->PickerContext->KbDebug = &mSimplePickerKbDebug;
}
DEBUG_CODE_END ();
KeyMap = OcAppleKeyMapInstallProtocols (FALSE);
if (KeyMap == NULL) {
DEBUG ((DEBUG_ERROR, "OCB: Missing AppleKeyMapAggregator\n"));
return EFI_UNSUPPORTED;
}
Count = (UINT32)BootContext->BootEntryCount;
if (Count != MIN (Count, OC_INPUT_MAX)) {
DEBUG ((DEBUG_WARN, "OCB: Cannot display all entries in the menu!\n"));
}
//
// Fix overlong menu entries.
//
for (Index = 0; Index < Count; Index++) {
if (StrLen (BootEntries[Index]->Name) > SAFE_ENTRY_LENGTH) {
StrCpyS (&BootEntries[Index]->Name[SAFE_ENTRY_LENGTH - L_STR_LEN (L"...")], L_STR_SIZE (L"..."), L"...");
}
}
OcConsoleControlSetMode (EfiConsoleControlScreenText);
gST->ConOut->EnableCursor (gST->ConOut, FALSE);
if (BootContext->PickerContext->ConsoleAttributes != 0) {
gST->ConOut->SetAttribute (gST->ConOut, BootContext->PickerContext->ConsoleAttributes & 0x7FU);
}
gST->ConOut->ClearScreen (gST->ConOut);
while (TRUE) {
if (FirstIndexRow != -1) {
//
// Incrementally update menu
//
if ((OldChosenEntry >= 0) && (OldChosenEntry != ChosenEntry)) {
gST->ConOut->SetCursorPosition (gST->ConOut, 0, FirstIndexRow + OldChosenEntry);
gST->ConOut->OutputString (gST->ConOut, L" ");
}
if (ChosenEntry >= 0) {
EntryCursor = GetPickerEntryCursor (BootContext, TimeOutSeconds, ChosenEntry, ChosenEntry, PickerKeyInfo.OcModifiers);
} else {
EntryCursor = L'\0';
}
if ((OldChosenEntry != ChosenEntry) || (OldEntryCursor != EntryCursor)) {
if (ChosenEntry >= 0) {
gST->ConOut->SetCursorPosition (gST->ConOut, 0, FirstIndexRow + ChosenEntry);
Code[0] = EntryCursor;
gST->ConOut->OutputString (gST->ConOut, Code);
}
OldChosenEntry = ChosenEntry;
OldEntryCursor = EntryCursor;
gST->ConOut->SetCursorPosition (gST->ConOut, mStatusColumn, mStatusRow);
}
DEBUG_CODE_BEGIN ();
if ((BootContext->PickerContext->PickerAttributes & OC_ATTR_SHOW_DEBUG_DISPLAY) != 0) {
//
// Varying part of milliseconds display
//
gST->ConOut->SetCursorPosition (gST->ConOut, MillisColumn, 0);
DisplaySystemMs ();
gST->ConOut->SetCursorPosition (gST->ConOut, mStatusColumn, mStatusRow);
}
DEBUG_CODE_END ();
} else {
//
// Render initial menu
//
gST->ConOut->ClearScreen (gST->ConOut);
gST->ConOut->OutputString (gST->ConOut, OC_MENU_BOOT_MENU);
if (BootContext->PickerContext->TitleSuffix != NULL) {
Length = AsciiStrLen (BootContext->PickerContext->TitleSuffix);
gST->ConOut->OutputString (gST->ConOut, L" (");
for (Index = 0; Index < Length; ++Index) {
Code[0] = BootContext->PickerContext->TitleSuffix[Index];
gST->ConOut->OutputString (gST->ConOut, Code);
}
gST->ConOut->OutputString (gST->ConOut, L")");
}
DEBUG_CODE_BEGIN ();
if ((BootContext->PickerContext->PickerAttributes & OC_ATTR_SHOW_DEBUG_DISPLAY) != 0) {
//
// Fixed part of milliseconds display
//
gST->ConOut->OutputString (gST->ConOut, L" [System uptime: ");
MillisColumn = gST->ConOut->Mode->CursorColumn;
DisplaySystemMs ();
}
DEBUG_CODE_END ();
gST->ConOut->OutputString (gST->ConOut, L"\r\n\r\n");
FirstIndexRow = gST->ConOut->Mode->CursorRow;
for (Index = 0; Index < MIN (Count, OC_INPUT_MAX); ++Index) {
EntryCursor = GetPickerEntryCursor (BootContext, TimeOutSeconds, ChosenEntry, Index, PickerKeyInfo.OcModifiers);
if ((ChosenEntry >= 0) && ((UINTN)ChosenEntry == Index)) {
OldEntryCursor = EntryCursor;
}
Code[0] = EntryCursor;
gST->ConOut->OutputString (gST->ConOut, Code);
gST->ConOut->OutputString (gST->ConOut, L" ");
Code[0] = OC_INPUT_STR[Index];
gST->ConOut->OutputString (gST->ConOut, Code);
gST->ConOut->OutputString (gST->ConOut, L". ");
gST->ConOut->OutputString (gST->ConOut, BootEntries[Index]->Name);
if (BootEntries[Index]->IsExternal) {
gST->ConOut->OutputString (gST->ConOut, OC_MENU_EXTERNAL);
}
if (BootEntries[Index]->IsFolder) {
gST->ConOut->OutputString (gST->ConOut, OC_MENU_DISK_IMAGE);
}
gST->ConOut->OutputString (gST->ConOut, L"\r\n");
}
if ((BootContext->PickerContext->PickerAttributes & OC_ATTR_USE_MINIMAL_UI) == 0) {
gST->ConOut->OutputString (gST->ConOut, L"\r\n");
ShutdownRestartRow = gST->ConOut->Mode->CursorRow;
gST->ConOut->OutputString (gST->ConOut, L" ");
RestartColumn = gST->ConOut->Mode->CursorColumn;
gST->ConOut->OutputString (gST->ConOut, L"|Restart|");
gST->ConOut->OutputString (gST->ConOut, L" ");
ShutdownColumn = gST->ConOut->Mode->CursorColumn;
gST->ConOut->OutputString (gST->ConOut, L"|Shutdown|");
gST->ConOut->OutputString (gST->ConOut, L"\r\n");
} else {
//
// prevent uninitialized err
//
ShutdownRestartRow = 0;
RestartColumn = 0;
ShutdownColumn = 0;
}
gST->ConOut->OutputString (gST->ConOut, L"\r\n");
gST->ConOut->OutputString (gST->ConOut, OC_MENU_CHOOSE_OS);
mStatusRow = gST->ConOut->Mode->CursorRow;
mStatusColumn = gST->ConOut->Mode->CursorColumn;
#if defined (BUILTIN_DEMONSTRATE_TYPING)
gST->ConOut->OutputString (gST->ConOut, L"\r\n\r\n");
gST->ConOut->OutputString (gST->ConOut, L"Typing: ");
TypingRow = gST->ConOut->Mode->CursorRow;
TypingColumn = gST->ConOut->Mode->CursorColumn;
TypingStartColumn = TypingColumn;
#endif
DEBUG_CODE_BEGIN ();
if ((BootContext->PickerContext->PickerAttributes & OC_ATTR_SHOW_DEBUG_DISPLAY) != 0) {
//
// Parts of main debug display which do not need to reprint every frame
// TODO: Could do more here
//
gST->ConOut->OutputString (gST->ConOut, L"\r\n\r\n");
Print (
L"mTscFrequency = %,Lu\n",
GetTscFrequency ()
);
gST->ConOut->SetCursorPosition (gST->ConOut, mStatusColumn, mStatusRow);
}
DEBUG_CODE_END ();
}
if (!PlayedOnce && BootContext->PickerContext->PickerAudioAssist) {
OcPlayAudioFile (BootContext->PickerContext, OC_VOICE_OVER_AUDIO_FILE_CHOOSE_OS, OC_VOICE_OVER_AUDIO_BASE_TYPE_OPEN_CORE, FALSE);
for (Index = 0; Index < Count; ++Index) {
OcPlayAudioEntry (BootContext->PickerContext, BootEntries[Index]);
if ((TimeOutSeconds > 0) && (BootContext->DefaultEntry->EntryIndex - 1 == Index)) {
OcPlayAudioFile (BootContext->PickerContext, OC_VOICE_OVER_AUDIO_FILE_DEFAULT, OC_VOICE_OVER_AUDIO_BASE_TYPE_OPEN_CORE, FALSE);
}
}
OcPlayAudioBeep (
BootContext->PickerContext,
OC_VOICE_OVER_SIGNALS_NORMAL,
OC_VOICE_OVER_SIGNAL_NORMAL_MS,
OC_VOICE_OVER_SILENCE_NORMAL_MS
);
PlayedOnce = TRUE;
}
while (TRUE) {
if (PlayChosen) {
//
// Pronounce entry name only after N ms of idleness.
//
KeyEndTime = BootContext->PickerContext->HotKeyContext->GetKeyWaitEndTime (OC_VOICE_OVER_IDLE_TIMEOUT_MS);
} else if (TimeOutSeconds != 0) {
if (KeyEndTime == 0) {
KeyEndTime = BootContext->PickerContext->HotKeyContext->GetKeyWaitEndTime (TimeOutSeconds * 1000);
}
} else {
KeyEndTime = 0;
}
ModifiersChanged = BootContext->PickerContext->HotKeyContext->WaitForKeyInfo (
BootContext->PickerContext,
KeyEndTime,
(FocusList[FocusState] != TAB_PICKER)
? OC_PICKER_KEYS_FOR_TYPING
: OC_PICKER_KEYS_FOR_PICKER,
&PickerKeyInfo
);
if ((NumFocusList > 1) && (PickerKeyInfo.OcKeyCode == OC_INPUT_SWITCH_FOCUS)) {
UpdateTabContext (
FALSE,
BootContext,
BootEntries,
FocusList[FocusState],
ChosenEntry,
OldEntryCursor,
#if defined (BUILTIN_DEMONSTRATE_TYPING)
TypingRow,
TypingColumn,
#endif
FirstIndexRow,
ShutdownRestartRow,
ShutdownColumn,
RestartColumn
);
//
// On leaving picker the first time, any timeout gets cancelled (correctly), therefore text
// cursor changes, therefore text cursor gets redrawn - unless we do this.
//
if ((FocusList[FocusState] == TAB_PICKER) && (TimeOutSeconds > 0)) {
OldEntryCursor = GetPickerEntryCursor (BootContext, 0, ChosenEntry, ChosenEntry, PickerKeyInfo.OcModifiers);
}
if ((PickerKeyInfo.OcModifiers & OC_MODIFIERS_REVERSE_SWITCH_FOCUS) != 0) {
if (FocusState == 0) {
FocusState = NumFocusList;
}
FocusState--;
} else {
FocusState++;
if (FocusState == NumFocusList) {
FocusState = 0;
}
}
UpdateTabContext (
TRUE,
BootContext,
BootEntries,
FocusList[FocusState],
ChosenEntry,
OldEntryCursor,
#if defined (BUILTIN_DEMONSTRATE_TYPING)
TypingRow,
TypingColumn,
#endif
FirstIndexRow,
ShutdownRestartRow,
ShutdownColumn,
RestartColumn
);
gST->ConOut->SetCursorPosition (gST->ConOut, mStatusColumn, mStatusRow);
}
if (FocusList[FocusState] == TAB_RESTART) {
if (PickerKeyInfo.OcKeyCode == OC_INPUT_TYPING_CONFIRM) {
gST->ConOut->OutputString (gST->ConOut, OC_MENU_RESTART);
gST->ConOut->OutputString (gST->ConOut, L"\r\n");
OcPlayAudioFile (BootContext->PickerContext, APPLE_VOICE_OVER_AUDIO_FILE_BEEP, OC_VOICE_OVER_AUDIO_BASE_TYPE_APPLE, FALSE);
ResetWarm ();
return EFI_SUCCESS;
}
} else if (FocusList[FocusState] == TAB_SHUTDOWN) {
if (PickerKeyInfo.OcKeyCode == OC_INPUT_TYPING_CONFIRM) {
gST->ConOut->OutputString (gST->ConOut, OC_MENU_SHUTDOWN);
gST->ConOut->OutputString (gST->ConOut, L"\r\n");
OcPlayAudioFile (BootContext->PickerContext, APPLE_VOICE_OVER_AUDIO_FILE_BEEP, OC_VOICE_OVER_AUDIO_BASE_TYPE_APPLE, FALSE);
ResetShutdown ();
return EFI_SUCCESS;
}
}
#if defined (BUILTIN_DEMONSTRATE_TYPING)
else if (FocusList[FocusState] == TAB_TYPING_DEMO) {
if ((PickerKeyInfo.OcKeyCode == OC_INPUT_TYPING_BACKSPACE) && (TypingColumn > TypingStartColumn)) {
//
// Backspace and move cursor.
//
TypingColumn--;
gST->ConOut->SetCursorPosition (gST->ConOut, TypingColumn, TypingRow);
Code[0] = L'_';
gST->ConOut->OutputString (gST->ConOut, Code);
Code[0] = L' ';
gST->ConOut->OutputString (gST->ConOut, Code);
gST->ConOut->SetCursorPosition (gST->ConOut, mStatusColumn, mStatusRow);
} else if ((PickerKeyInfo.UnicodeChar >= 32) && (PickerKeyInfo.UnicodeChar < 128)) {
//
// Type and move cursor.
//
gST->ConOut->SetCursorPosition (gST->ConOut, TypingColumn, TypingRow);
Code[0] = PickerKeyInfo.UnicodeChar;
gST->ConOut->OutputString (gST->ConOut, Code);
Code[0] = L'_';
gST->ConOut->OutputString (gST->ConOut, Code);
gST->ConOut->SetCursorPosition (gST->ConOut, mStatusColumn, mStatusRow);
TypingColumn++;
}
}
#endif
if (PlayChosen && (PickerKeyInfo.OcKeyCode == OC_INPUT_TIMEOUT)) {
OcPlayAudioFile (BootContext->PickerContext, OC_VOICE_OVER_AUDIO_FILE_SELECTED, OC_VOICE_OVER_AUDIO_BASE_TYPE_OPEN_CORE, FALSE);
OcPlayAudioEntry (BootContext->PickerContext, BootEntries[ChosenEntry]);
PlayChosen = FALSE;
continue;
} else if (PickerKeyInfo.OcKeyCode == OC_INPUT_TIMEOUT) {
*ChosenBootEntry = BootEntries[BootContext->DefaultEntry->EntryIndex - 1];
gST->ConOut->OutputString (gST->ConOut, OC_MENU_TIMEOUT);
gST->ConOut->OutputString (gST->ConOut, L"\r\n");
OcPlayAudioFile (BootContext->PickerContext, OC_VOICE_OVER_AUDIO_FILE_TIMEOUT, OC_VOICE_OVER_AUDIO_BASE_TYPE_OPEN_CORE, FALSE);
return EFI_SUCCESS;
} else if (PickerKeyInfo.OcKeyCode == OC_INPUT_CONTINUE) {
if (ChosenEntry >= 0) {
*ChosenBootEntry = BootEntries[(UINTN)ChosenEntry];
} else {
*ChosenBootEntry = BootContext->DefaultEntry;
}
(*ChosenBootEntry)->SetDefault = ((PickerKeyInfo.OcModifiers & OC_MODIFIERS_SET_DEFAULT) != 0);
gST->ConOut->OutputString (gST->ConOut, OC_MENU_OK);
gST->ConOut->OutputString (gST->ConOut, L"\r\n");
return EFI_SUCCESS;
} else if (PickerKeyInfo.OcKeyCode == OC_INPUT_ABORTED) {
gST->ConOut->OutputString (gST->ConOut, OC_MENU_RELOADING);
gST->ConOut->OutputString (gST->ConOut, L"\r\n");
OcPlayAudioFile (BootContext->PickerContext, OC_VOICE_OVER_AUDIO_FILE_RELOADING, OC_VOICE_OVER_AUDIO_BASE_TYPE_OPEN_CORE, FALSE);
return EFI_ABORTED;
} else if ((PickerKeyInfo.OcKeyCode == OC_INPUT_MORE) && BootContext->PickerContext->HideAuxiliary) {
gST->ConOut->OutputString (gST->ConOut, OC_MENU_SHOW_AUXILIARY);
gST->ConOut->OutputString (gST->ConOut, L"\r\n");
OcPlayAudioFile (BootContext->PickerContext, OC_VOICE_OVER_AUDIO_FILE_SHOW_AUXILIARY, OC_VOICE_OVER_AUDIO_BASE_TYPE_OPEN_CORE, FALSE);
BootContext->PickerContext->HideAuxiliary = FALSE;
return EFI_ABORTED;
} else if (PickerKeyInfo.OcKeyCode == OC_INPUT_UP) {
if (ChosenEntry < 0) {
ChosenEntry = 0;
} else if (ChosenEntry == 0) {
ChosenEntry = (INTN)(MIN (Count, OC_INPUT_MAX) - 1);
} else {
--ChosenEntry;
}
TimeOutSeconds = 0;
if (BootContext->PickerContext->PickerAudioAssist) {
PlayChosen = TRUE;
}
break;
} else if (PickerKeyInfo.OcKeyCode == OC_INPUT_DOWN) {
if (ChosenEntry < 0) {
ChosenEntry = 0;
} else if (ChosenEntry == (INTN)(MIN (Count, OC_INPUT_MAX) - 1)) {
ChosenEntry = 0;
} else {
++ChosenEntry;
}
TimeOutSeconds = 0;
if (BootContext->PickerContext->PickerAudioAssist) {
PlayChosen = TRUE;
}
break;
} else if ((PickerKeyInfo.OcKeyCode == OC_INPUT_TOP) || (PickerKeyInfo.OcKeyCode == OC_INPUT_LEFT)) {
ChosenEntry = 0;
TimeOutSeconds = 0;
if (BootContext->PickerContext->PickerAudioAssist) {
PlayChosen = TRUE;
}
break;
} else if ((PickerKeyInfo.OcKeyCode == OC_INPUT_BOTTOM) || (PickerKeyInfo.OcKeyCode == OC_INPUT_RIGHT)) {
ChosenEntry = (INTN)(MIN (Count, OC_INPUT_MAX) - 1);
TimeOutSeconds = 0;
if (BootContext->PickerContext->PickerAudioAssist) {
PlayChosen = TRUE;
}
break;
} else if (PickerKeyInfo.OcKeyCode == OC_INPUT_VOICE_OVER) {
OcToggleVoiceOver (BootContext->PickerContext, NULL, NULL);
break;
} else if ((PickerKeyInfo.OcKeyCode != OC_INPUT_NO_ACTION) && (PickerKeyInfo.OcKeyCode >= 0) && ((UINTN)PickerKeyInfo.OcKeyCode < Count)) {
*ChosenBootEntry = BootEntries[PickerKeyInfo.OcKeyCode];
(*ChosenBootEntry)->SetDefault = ((PickerKeyInfo.OcModifiers & OC_MODIFIERS_SET_DEFAULT) != 0);
Code[0] = OC_INPUT_STR[PickerKeyInfo.OcKeyCode];
gST->ConOut->OutputString (gST->ConOut, Code);
gST->ConOut->OutputString (gST->ConOut, L"\r\n");
return EFI_SUCCESS;
}
if ((ModifiersChanged || (PickerKeyInfo.OcKeyCode != OC_INPUT_NO_ACTION)) && (TimeOutSeconds > 0)) {
OcPlayAudioFile (BootContext->PickerContext, OC_VOICE_OVER_AUDIO_FILE_ABORT_TIMEOUT, OC_VOICE_OVER_AUDIO_BASE_TYPE_OPEN_CORE, FALSE);
TimeOutSeconds = 0;
break;
}
if (ModifiersChanged || (PickerKeyInfo.UnicodeChar != CHAR_NULL)) {
break;
}
}
}
ASSERT (FALSE);
}
EFI_STATUS
EFIAPI
OcShowSimplePasswordRequest (
IN OC_PICKER_CONTEXT *Context,
IN OC_PRIVILEGE_LEVEL Level
)
{
BOOLEAN Result;
UINT8 Password[OC_PASSWORD_MAX_LEN];
UINT32 PwIndex;
UINT8 Index;
OC_PICKER_KEY_INFO PickerKeyInfo;
UINT8 SpaceIndex;
OcConsoleControlSetMode (EfiConsoleControlScreenText);
gST->ConOut->EnableCursor (gST->ConOut, FALSE);
gST->ConOut->ClearScreen (gST->ConOut);
for (Index = 0; Index < OC_PASSWORD_MAX_RETRIES; ++Index) {
PwIndex = 0;
Context->HotKeyContext->FlushTypingBuffer (Context);
gST->ConOut->OutputString (gST->ConOut, OC_MENU_PASSWORD_REQUEST);
OcPlayAudioFile (Context, OC_VOICE_OVER_AUDIO_FILE_ENTER_PASSWORD, OC_VOICE_OVER_AUDIO_BASE_TYPE_OPEN_CORE, TRUE);
while (TRUE) {
Context->HotKeyContext->WaitForKeyInfo (
Context,
0,
OC_PICKER_KEYS_FOR_TYPING,
&PickerKeyInfo
);
if (PickerKeyInfo.OcKeyCode == OC_INPUT_VOICE_OVER) {
OcToggleVoiceOver (Context, OC_VOICE_OVER_AUDIO_FILE_ENTER_PASSWORD, OC_VOICE_OVER_AUDIO_BASE_TYPE_OPEN_CORE);
continue;
}
if (PickerKeyInfo.UnicodeChar == CHAR_CARRIAGE_RETURN) {
//
// RETURN finalizes the input.
//
break;
}
if (PickerKeyInfo.UnicodeChar == CHAR_BACKSPACE) {
//
// Delete the last entered character, if such exists.
//
if (PwIndex > 0) {
--PwIndex;
Password[PwIndex] = 0;
//
// Overwrite current character with a space.
//
gST->ConOut->SetCursorPosition (
gST->ConOut,
gST->ConOut->Mode->CursorColumn - 1,
gST->ConOut->Mode->CursorRow
);
gST->ConOut->OutputString (gST->ConOut, L" ");
gST->ConOut->SetCursorPosition (
gST->ConOut,
gST->ConOut->Mode->CursorColumn - 1,
gST->ConOut->Mode->CursorRow
);
}
OcPlayAudioFile (Context, APPLE_VOICE_OVER_AUDIO_FILE_BEEP, OC_VOICE_OVER_AUDIO_BASE_TYPE_APPLE, TRUE);
continue;
}
if ( (PickerKeyInfo.UnicodeChar != CHAR_NULL)
&& (PickerKeyInfo.UnicodeChar == (CHAR8)PickerKeyInfo.UnicodeChar)
&& (PwIndex < ARRAY_SIZE (Password)))
{
gST->ConOut->OutputString (gST->ConOut, L"*");
Password[PwIndex] = (UINT8)PickerKeyInfo.UnicodeChar;
OcPlayAudioFile (Context, APPLE_VOICE_OVER_AUDIO_FILE_BEEP, OC_VOICE_OVER_AUDIO_BASE_TYPE_APPLE, TRUE);
++PwIndex;
continue;
}
//
// Only ASCII characters are supported.
//
OcPlayAudioBeep (
Context,
OC_VOICE_OVER_SIGNALS_ERROR,
OC_VOICE_OVER_SIGNAL_ERROR_MS,
OC_VOICE_OVER_SILENCE_ERROR_MS
);
}
//
// Output password processing status.
//
gST->ConOut->SetCursorPosition (
gST->ConOut,
0,
gST->ConOut->Mode->CursorRow
);
gST->ConOut->OutputString (gST->ConOut, OC_MENU_PASSWORD_PROCESSING);
//
// Clear remaining password prompt status.
//
for (
SpaceIndex = L_STR_LEN (OC_MENU_PASSWORD_PROCESSING);
SpaceIndex < L_STR_LEN (OC_MENU_PASSWORD_REQUEST) + PwIndex;
++SpaceIndex
)
{
gST->ConOut->OutputString (gST->ConOut, L" ");
}
Result = Context->VerifyPassword (
Password,
PwIndex,
Context->PrivilegeContext
);
SecureZeroMem (Password, PwIndex);
//
// Clear password processing status.
//
gST->ConOut->SetCursorPosition (
gST->ConOut,
0,
gST->ConOut->Mode->CursorRow
);
for (SpaceIndex = 0; SpaceIndex < L_STR_LEN (OC_MENU_PASSWORD_PROCESSING); ++SpaceIndex) {
gST->ConOut->OutputString (gST->ConOut, L" ");
}
gST->ConOut->SetCursorPosition (
gST->ConOut,
0,
gST->ConOut->Mode->CursorRow
);
if (Result) {
OcPlayAudioFile (Context, OC_VOICE_OVER_AUDIO_FILE_PASSWORD_ACCEPTED, OC_VOICE_OVER_AUDIO_BASE_TYPE_OPEN_CORE, TRUE);
return EFI_SUCCESS;
}
OcPlayAudioFile (Context, OC_VOICE_OVER_AUDIO_FILE_PASSWORD_INCORRECT, OC_VOICE_OVER_AUDIO_BASE_TYPE_OPEN_CORE, TRUE);
}
gST->ConOut->OutputString (gST->ConOut, OC_MENU_PASSWORD_RETRY_LIMIT L"\r\n");
OcPlayAudioFile (Context, OC_VOICE_OVER_AUDIO_FILE_PASSWORD_RETRY_LIMIT, OC_VOICE_OVER_AUDIO_BASE_TYPE_OPEN_CORE, TRUE);
DEBUG ((DEBUG_WARN, "OCB: User failed to verify password %d times running\n", OC_PASSWORD_MAX_RETRIES));
gBS->Stall (SECONDS_TO_MICROSECONDS (5));
ResetWarm ();
return EFI_ACCESS_DENIED;
}