OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
BuiltinPicker.c
Go to the documentation of this file.
1
10
11#include <Guid/AppleFile.h>
12#include <Guid/AppleVariable.h>
13#include <Guid/OcVariable.h>
14
16
20#include <Protocol/LoadedImage.h>
21#include <Protocol/OcAudio.h>
22#include <Protocol/SimpleTextOut.h>
23
24#include <Library/BaseLib.h>
25#include <Library/BaseMemoryLib.h>
26#include <Library/BaseOverflowLib.h>
28#include <Library/OcCryptoLib.h>
30#include <Library/DevicePathLib.h>
31#include <Library/OcTimerLib.h>
32#include <Library/OcTypingLib.h>
33#include <Library/MemoryAllocationLib.h>
37#include <Library/OcFileLib.h>
38#include <Library/OcMiscLib.h>
39#include <Library/OcRtcLib.h>
40#include <Library/OcStringLib.h>
41#include <Library/PrintLib.h>
42#include <Library/UefiBootServicesTableLib.h>
43#include <Library/UefiRuntimeServicesTableLib.h>
44#include <Library/UefiLib.h>
45#include <Library/ResetSystemLib.h>
46
47STATIC INT32 mStatusRow;
48STATIC INT32 mStatusColumn;
49
50STATIC INT32 mRunningColumn;
51
52STATIC UINT64 mPreviousTick;
53
54STATIC UINT64 mLoopDelayStart;
55STATIC UINT64 mLoopDelayEnd;
56
57typedef enum {
61 #if defined (BUILTIN_DEMONSTRATE_TYPING)
62 TAB_TYPING_DEMO,
63 #endif
66
68
73 #if defined (BUILTIN_DEMONSTRATE_TYPING)
74 TAB_TYPING_DEMO
75 #endif
76};
77
82 #if defined (BUILTIN_DEMONSTRATE_TYPING)
83 TAB_TYPING_DEMO
84 #endif
85};
86
89 #if defined (BUILTIN_DEMONSTRATE_TYPING)
90 TAB_TYPING_DEMO
91 #endif
92};
93
94#define MENU_PREFIX_LENGTH (5)
95
96#define OC_KB_DBG_MAX_COLUMN 80
97#define OC_KB_DBG_DELTA_SAMPLE_COLUMN 0 // 40
98
99#if defined (BUILTIN_DEMONSTRATE_TYPING)
100#define OC_KB_DBG_PRINT_ROW 4
101#else
102#define OC_KB_DBG_PRINT_ROW 2
103#endif
104
105#define OC_KB_DBG_DOWN_ROW (OC_KB_DBG_PRINT_ROW + 4)
106#define OC_KB_DBG_X_ROW (OC_KB_DBG_PRINT_ROW + 5)
107#define OC_KB_DBG_MODIFIERS_ROW (OC_KB_DBG_PRINT_ROW + 6)
108
109STATIC
110VOID
112 VOID
113 )
114{
115 mRunningColumn = 0;
116
117 mLoopDelayStart = 0;
118 mLoopDelayEnd = 0;
119}
120
121STATIC
122VOID
123EFIAPI
125 UINT64 LoopDelayStart,
126 UINT64 LoopDelayEnd
127 )
128{
129 mLoopDelayStart = LoopDelayStart;
130 mLoopDelayEnd = LoopDelayEnd;
131}
132
133STATIC
134VOID
135EFIAPI
137 UINTN NumKeysDown,
138 UINTN NumKeysHeld,
139 APPLE_MODIFIER_MAP Modifiers
140 )
141{
142 CONST CHAR16 *ClearSpace = L" ";
143
144 UINT64 CurrentTick;
145
146 CHAR16 Code[3]; // includes flush-ahead space, to make progress visible
147
148 Code[1] = L' ';
149 Code[2] = L'\0';
150
151 CurrentTick = AsmReadTsc ();
152
154 gST->ConOut->SetCursorPosition (gST->ConOut, 0, mStatusRow + OC_KB_DBG_PRINT_ROW + 1);
155
156 Print (
157 L"Called delta = %,Lu%s\n",
158 CurrentTick - mPreviousTick,
159 ClearSpace
160 );
161
162 Print (
163 L"Loop delta = %,Lu (@ -%,Lu)%s%s\n",
165 mLoopDelayEnd == 0 ? 0 : CurrentTick - mLoopDelayEnd,
166 ClearSpace,
167 ClearSpace
168 );
169 }
170
171 mPreviousTick = CurrentTick;
172
173 //
174 // Show Apple Event keys
175 //
176 gST->ConOut->SetCursorPosition (gST->ConOut, mRunningColumn, mStatusRow + OC_KB_DBG_DOWN_ROW);
177 if (NumKeysDown > 0) {
178 Code[0] = L'D';
179 } else {
180 Code[0] = L' ';
181 }
182
183 gST->ConOut->OutputString (gST->ConOut, Code);
184
185 //
186 // Show AKMA key held info
187 //
188 gST->ConOut->SetCursorPosition (gST->ConOut, mRunningColumn, mStatusRow + OC_KB_DBG_X_ROW);
189 if (NumKeysHeld > 0) {
190 Code[0] = L'X';
191 } else {
192 Code[0] = L'.';
193 }
194
195 gST->ConOut->OutputString (gST->ConOut, Code);
196
197 //
198 // Modifiers info
199 //
200 gST->ConOut->SetCursorPosition (gST->ConOut, mRunningColumn, mStatusRow + OC_KB_DBG_MODIFIERS_ROW);
201 if (Modifiers == 0) {
202 Code[0] = L' ';
203 gST->ConOut->OutputString (gST->ConOut, Code);
204 } else {
205 Print (L"%X", Modifiers);
206 }
207
209 mRunningColumn = 0;
210 }
211
212 gST->ConOut->SetCursorPosition (gST->ConOut, mStatusColumn, mStatusRow);
213}
214
219
220STATIC
221VOID
223 VOID
224 )
225{
226 UINT64 CurrentMillis;
227
228 CurrentMillis = DivU64x64Remainder (GetTimeInNanoSecond (GetPerformanceCounter ()), 1000000ULL, NULL);
229 Print (L"%,Lu]", CurrentMillis);
230}
231
232STATIC
233CHAR16
235 IN OC_BOOT_CONTEXT *BootContext,
236 IN UINT32 TimeOutSeconds,
237 IN INTN ChosenEntry,
238 IN UINTN Index,
239 IN OC_MODIFIER_MAP OcModifiers
240 )
241{
242 if ((TimeOutSeconds > 0) && (BootContext->DefaultEntry->EntryIndex - 1 == Index)) {
243 return L'*';
244 }
245
246 if ((ChosenEntry >= 0) && ((UINTN)ChosenEntry == Index)) {
247 return ((OcModifiers & OC_MODIFIERS_SET_DEFAULT) != 0) ? L'+' : L'>';
248 }
249
250 return L' ';
251}
252
253VOID
255 IN BOOLEAN IsEntering,
256 IN OC_BOOT_CONTEXT *BootContext,
257 IN OC_BOOT_ENTRY **BootEntries,
258 IN TAB_FOCUS TabFocus,
259 IN INTN ChosenEntry,
260 IN CHAR16 OldEntryCursor,
261#if defined (BUILTIN_DEMONSTRATE_TYPING)
262 IN INT32 TypingRow,
263 IN INT32 TypingColumn,
264#endif
265 IN INT32 FirstIndexRow,
266 IN INT32 ShutdownRestartRow,
267 IN INT32 ShutdownColumn,
268 IN INT32 RestartColumn
269 )
270{
271 CHAR16 Code[2];
272
273 Code[1] = L'\0';
274
275 if (TabFocus == TAB_PICKER) {
276 if (ChosenEntry >= 0) {
277 gST->ConOut->SetCursorPosition (gST->ConOut, 0, FirstIndexRow + ChosenEntry);
278 Code[0] = IsEntering ? OldEntryCursor : L' ';
279 gST->ConOut->OutputString (gST->ConOut, Code);
280 }
281
282 if (IsEntering) {
283 if (ChosenEntry >= 0) {
285 OcPlayAudioEntry (BootContext->PickerContext, BootEntries[ChosenEntry]);
286 } else {
287 //
288 // TODO: Sound for tabbing back to picker if no entry selected (cannot currently happen)
289 //
290 }
291 }
292 } else if ((TabFocus == TAB_SHUTDOWN) || (TabFocus == TAB_RESTART)) {
293 if (TabFocus == TAB_SHUTDOWN) {
294 gST->ConOut->SetCursorPosition (gST->ConOut, ShutdownColumn, ShutdownRestartRow);
295 } else {
296 gST->ConOut->SetCursorPosition (gST->ConOut, RestartColumn, ShutdownRestartRow);
297 }
298
299 Code[0] = IsEntering ? L'[' : '|';
300 gST->ConOut->OutputString (gST->ConOut, Code);
301 if (TabFocus == TAB_SHUTDOWN) {
302 gST->ConOut->OutputString (gST->ConOut, L"Shutdown");
303 } else {
304 gST->ConOut->OutputString (gST->ConOut, L"Restart");
305 }
306
307 Code[0] = IsEntering ? L']' : '|';
308 gST->ConOut->OutputString (gST->ConOut, Code);
309
310 if (IsEntering) {
311 if (TabFocus == TAB_SHUTDOWN) {
314 } else {
317 }
318 }
319 }
320
321 #if defined (BUILTIN_DEMONSTRATE_TYPING)
322 else if (TabFocus == TAB_TYPING_DEMO) {
323 gST->ConOut->SetCursorPosition (gST->ConOut, TypingColumn, TypingRow);
324 Code[0] = IsEntering ? L'_' : ' ';
325 gST->ConOut->OutputString (gST->ConOut, Code);
326 }
327 #endif
328}
329
330EFI_STATUS
331EFIAPI
333 IN OC_BOOT_CONTEXT *BootContext,
334 IN OC_BOOT_ENTRY **BootEntries,
335 OUT OC_BOOT_ENTRY **ChosenBootEntry
336 )
337{
339 UINTN Index;
340 UINTN Length;
341 OC_PICKER_KEY_INFO PickerKeyInfo;
342 INTN ChosenEntry;
343 INTN OldChosenEntry;
344 INT32 FirstIndexRow;
345 INT32 MillisColumn;
346 CHAR16 EntryCursor;
347 CHAR16 OldEntryCursor;
348 CHAR16 Code[2];
349 UINT32 TimeOutSeconds;
350 UINT32 Count;
351 UINT64 KeyEndTime;
352 BOOLEAN PlayedOnce;
353 BOOLEAN PlayChosen;
354 BOOLEAN ModifiersChanged;
355 UINTN Columns;
356 UINTN Rows;
357 UINTN SafeEntryLength;
358 UINTN SuffixLength;
359
360 #if defined (BUILTIN_DEMONSTRATE_TYPING)
361 INT32 TypingRow;
362 INT32 TypingColumn;
363 INT32 TypingStartColumn;
364 #endif
365 INT32 ShutdownRestartRow;
366 INT32 ShutdownColumn;
367 INT32 RestartColumn;
368 UINTN FocusState;
369 TAB_FOCUS *FocusList;
370 UINTN NumFocusList;
371
372 Code[1] = L'\0';
373
374 TimeOutSeconds = BootContext->PickerContext->TimeoutSeconds;
375 KeyEndTime = 0;
376
377 ASSERT (BootContext->DefaultEntry != NULL);
378 ChosenEntry = (INTN)(BootContext->DefaultEntry->EntryIndex - 1);
379 OldChosenEntry = ChosenEntry;
380
381 EntryCursor = L'\0';
382 OldEntryCursor = L'\0';
383
384 FirstIndexRow = -1;
385
386 FocusState = 0;
387 if ((BootContext->PickerContext->PickerAttributes & OC_ATTR_USE_MINIMAL_UI) == 0) {
388 STATIC_ASSERT (ARRAY_SIZE (mFocusList) == ARRAY_SIZE (mFocusListReversed), "Mismatched focus list sizes");
389 FocusList = ((BootContext->PickerContext->PickerAttributes & OC_ATTR_USE_REVERSED_UI) == 0)
390 ? mFocusList
392 NumFocusList = ARRAY_SIZE (mFocusList);
393 } else {
394 FocusList = mFocusListMinimal;
395 NumFocusList = ARRAY_SIZE (mFocusListMinimal);
396 }
397
398 //
399 //  Used to detect changes.
400 //
401 PickerKeyInfo.OcModifiers = OC_MODIFIERS_NONE;
402
403 PlayedOnce = FALSE;
404 PlayChosen = FALSE;
405
406 DEBUG_CODE_BEGIN ();
407 if ((BootContext->PickerContext->PickerAttributes & OC_ATTR_SHOW_DEBUG_DISPLAY) != 0) {
408 DEBUG ((DEBUG_INFO, "OCB: Init builtin picker debug\n"));
410 BootContext->PickerContext->KbDebug = &mSimplePickerKbDebug;
411 }
412
413 DEBUG_CODE_END ();
414
415 KeyMap = OcAppleKeyMapInstallProtocols (FALSE);
416 if (KeyMap == NULL) {
417 DEBUG ((DEBUG_ERROR, "OCB: Missing AppleKeyMapAggregator\n"));
418 return EFI_UNSUPPORTED;
419 }
420
421 Count = (UINT32)BootContext->BootEntryCount;
422
423 if (Count != MIN (Count, OC_INPUT_MAX)) {
424 DEBUG ((DEBUG_WARN, "OCB: Cannot display all entries in the menu!\n"));
425 }
426
427 //
428 // Fix overlong menu entries. For very small screens, below a minimum width we
429 // overflow anyway, but other parts of menu will also have overflowed before this.
430 //
431 gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &Columns, &Rows);
432 for (Index = 0; Index < Count; Index++) {
433 SuffixLength = 0;
434 if (BootEntries[Index]->IsExternal) {
435 SuffixLength += L_STR_LEN (OC_MENU_EXTERNAL);
436 }
437
438 if (BootEntries[Index]->IsFolder) {
439 SuffixLength += L_STR_LEN (OC_MENU_DISK_IMAGE);
440 }
441
442 if (Columns > MENU_PREFIX_LENGTH + SuffixLength + L_STR_LEN (L"...") + 1) {
443 SafeEntryLength = Columns - MENU_PREFIX_LENGTH - SuffixLength;
444 } else {
445 SafeEntryLength = L_STR_LEN (L"...") + 1;
446 }
447
448 if (StrLen (BootEntries[Index]->Name) > SafeEntryLength) {
449 StrCpyS (&BootEntries[Index]->Name[SafeEntryLength - L_STR_LEN (L"...")], L_STR_SIZE (L"..."), L"...");
450 }
451 }
452
454 gST->ConOut->EnableCursor (gST->ConOut, FALSE);
455
456 if (BootContext->PickerContext->ConsoleAttributes != 0) {
457 gST->ConOut->SetAttribute (gST->ConOut, BootContext->PickerContext->ConsoleAttributes & 0x7FU);
458 }
459
460 gST->ConOut->ClearScreen (gST->ConOut);
461
462 while (TRUE) {
463 if (FirstIndexRow != -1) {
464 //
465 // Incrementally update menu
466 //
467 if ((OldChosenEntry >= 0) && (OldChosenEntry != ChosenEntry)) {
468 gST->ConOut->SetCursorPosition (gST->ConOut, 0, FirstIndexRow + OldChosenEntry);
469 gST->ConOut->OutputString (gST->ConOut, L" ");
470 }
471
472 if (ChosenEntry >= 0) {
473 EntryCursor = GetPickerEntryCursor (BootContext, TimeOutSeconds, ChosenEntry, ChosenEntry, PickerKeyInfo.OcModifiers);
474 } else {
475 EntryCursor = L'\0';
476 }
477
478 if ((OldChosenEntry != ChosenEntry) || (OldEntryCursor != EntryCursor)) {
479 if (ChosenEntry >= 0) {
480 gST->ConOut->SetCursorPosition (gST->ConOut, 0, FirstIndexRow + ChosenEntry);
481 Code[0] = EntryCursor;
482 gST->ConOut->OutputString (gST->ConOut, Code);
483 }
484
485 OldChosenEntry = ChosenEntry;
486 OldEntryCursor = EntryCursor;
487
488 gST->ConOut->SetCursorPosition (gST->ConOut, mStatusColumn, mStatusRow);
489 }
490
491 DEBUG_CODE_BEGIN ();
492 if ((BootContext->PickerContext->PickerAttributes & OC_ATTR_SHOW_DEBUG_DISPLAY) != 0) {
493 //
494 // Varying part of milliseconds display
495 //
496 gST->ConOut->SetCursorPosition (gST->ConOut, MillisColumn, 0);
498 gST->ConOut->SetCursorPosition (gST->ConOut, mStatusColumn, mStatusRow);
499 }
500
501 DEBUG_CODE_END ();
502 } else {
503 //
504 // Render initial menu
505 //
506 gST->ConOut->ClearScreen (gST->ConOut);
507 gST->ConOut->OutputString (gST->ConOut, OC_MENU_BOOT_MENU);
508
509 if (BootContext->PickerContext->TitleSuffix != NULL) {
510 Length = AsciiStrLen (BootContext->PickerContext->TitleSuffix);
511 gST->ConOut->OutputString (gST->ConOut, L" (");
512 for (Index = 0; Index < Length; ++Index) {
513 Code[0] = BootContext->PickerContext->TitleSuffix[Index];
514 gST->ConOut->OutputString (gST->ConOut, Code);
515 }
516
517 gST->ConOut->OutputString (gST->ConOut, L")");
518 }
519
520 DEBUG_CODE_BEGIN ();
521 if ((BootContext->PickerContext->PickerAttributes & OC_ATTR_SHOW_DEBUG_DISPLAY) != 0) {
522 //
523 // Fixed part of milliseconds display
524 //
525 gST->ConOut->OutputString (gST->ConOut, L" [System uptime: ");
526 MillisColumn = gST->ConOut->Mode->CursorColumn;
528 }
529
530 DEBUG_CODE_END ();
531
532 gST->ConOut->OutputString (gST->ConOut, L"\r\n\r\n");
533
534 FirstIndexRow = gST->ConOut->Mode->CursorRow;
535
536 for (Index = 0; Index < MIN (Count, OC_INPUT_MAX); ++Index) {
537 EntryCursor = GetPickerEntryCursor (BootContext, TimeOutSeconds, ChosenEntry, Index, PickerKeyInfo.OcModifiers);
538
539 if ((ChosenEntry >= 0) && ((UINTN)ChosenEntry == Index)) {
540 OldEntryCursor = EntryCursor;
541 }
542
543 Code[0] = EntryCursor;
544 gST->ConOut->OutputString (gST->ConOut, Code);
545 gST->ConOut->OutputString (gST->ConOut, L" ");
546
547 Code[0] = OC_INPUT_STR[Index];
548 gST->ConOut->OutputString (gST->ConOut, Code);
549 gST->ConOut->OutputString (gST->ConOut, L". ");
550 gST->ConOut->OutputString (gST->ConOut, BootEntries[Index]->Name);
551 if (BootEntries[Index]->IsExternal) {
552 gST->ConOut->OutputString (gST->ConOut, OC_MENU_EXTERNAL);
553 }
554
555 if (BootEntries[Index]->IsFolder) {
556 gST->ConOut->OutputString (gST->ConOut, OC_MENU_DISK_IMAGE);
557 }
558
559 //
560 // Forcing cursor each row instead of using CRLF gives correct entry positioning
561 // when we overflow horizontally (in very small modes) and enables writing entry
562 // text (clipped or otherwise) up to the last column.
563 //
564 gST->ConOut->SetCursorPosition (gST->ConOut, 0, MIN (FirstIndexRow + Index + 1, Rows - 1));
565 }
566
567 if ((BootContext->PickerContext->PickerAttributes & OC_ATTR_USE_MINIMAL_UI) == 0) {
568 gST->ConOut->OutputString (gST->ConOut, L"\r\n");
569
570 ShutdownRestartRow = gST->ConOut->Mode->CursorRow;
571 gST->ConOut->OutputString (gST->ConOut, L" ");
572
573 if ((BootContext->PickerContext->PickerAttributes & OC_ATTR_USE_REVERSED_UI) == 0) {
574 ShutdownColumn = gST->ConOut->Mode->CursorColumn;
575 gST->ConOut->OutputString (gST->ConOut, L"|Shutdown|");
576 gST->ConOut->OutputString (gST->ConOut, L" ");
577 RestartColumn = gST->ConOut->Mode->CursorColumn;
578 gST->ConOut->OutputString (gST->ConOut, L"|Restart|");
579 } else {
580 RestartColumn = gST->ConOut->Mode->CursorColumn;
581 gST->ConOut->OutputString (gST->ConOut, L"|Restart|");
582 gST->ConOut->OutputString (gST->ConOut, L" ");
583 ShutdownColumn = gST->ConOut->Mode->CursorColumn;
584 gST->ConOut->OutputString (gST->ConOut, L"|Shutdown|");
585 }
586
587 gST->ConOut->OutputString (gST->ConOut, L"\r\n");
588 } else {
589 //
590 // prevent uninitialized err
591 //
592 ShutdownRestartRow = 0;
593 RestartColumn = 0;
594 ShutdownColumn = 0;
595 }
596
597 gST->ConOut->OutputString (gST->ConOut, L"\r\n");
598 gST->ConOut->OutputString (gST->ConOut, OC_MENU_CHOOSE_OS);
599
600 mStatusRow = gST->ConOut->Mode->CursorRow;
601 mStatusColumn = gST->ConOut->Mode->CursorColumn;
602
603 #if defined (BUILTIN_DEMONSTRATE_TYPING)
604 gST->ConOut->OutputString (gST->ConOut, L"\r\n\r\n");
605 gST->ConOut->OutputString (gST->ConOut, L"Typing: ");
606 TypingRow = gST->ConOut->Mode->CursorRow;
607 TypingColumn = gST->ConOut->Mode->CursorColumn;
608 TypingStartColumn = TypingColumn;
609 #endif
610
611 DEBUG_CODE_BEGIN ();
612 if ((BootContext->PickerContext->PickerAttributes & OC_ATTR_SHOW_DEBUG_DISPLAY) != 0) {
613 //
614 // Parts of main debug display which do not need to reprint every frame
615 // TODO: Could do more here
616 //
617 gST->ConOut->OutputString (gST->ConOut, L"\r\n\r\n");
618 Print (
619 L"mTscFrequency = %,Lu\n",
621 );
622 gST->ConOut->SetCursorPosition (gST->ConOut, mStatusColumn, mStatusRow);
623 }
624
625 DEBUG_CODE_END ();
626 }
627
628 if (!PlayedOnce && BootContext->PickerContext->PickerAudioAssist) {
630 for (Index = 0; Index < Count; ++Index) {
631 OcPlayAudioEntry (BootContext->PickerContext, BootEntries[Index]);
632 if ((TimeOutSeconds > 0) && (BootContext->DefaultEntry->EntryIndex - 1 == Index)) {
634 }
635 }
636
638 BootContext->PickerContext,
642 );
643 PlayedOnce = TRUE;
644
645 //
646 // Avoid responding to possibly multiple keys pressed before menu is fully read out.
647 //
648 BootContext->PickerContext->HotKeyContext->FlushTypingBuffer (BootContext->PickerContext);
649 }
650
651 while (TRUE) {
652 if (PlayChosen) {
653 //
654 // Pronounce entry name only after N ms of idleness.
655 //
656 KeyEndTime = BootContext->PickerContext->HotKeyContext->GetKeyWaitEndTime (OC_VOICE_OVER_IDLE_TIMEOUT_MS);
657 } else if (TimeOutSeconds != 0) {
658 if (KeyEndTime == 0) {
659 KeyEndTime = BootContext->PickerContext->HotKeyContext->GetKeyWaitEndTime (TimeOutSeconds * 1000);
660 }
661 } else {
662 KeyEndTime = 0;
663 }
664
665 ModifiersChanged = BootContext->PickerContext->HotKeyContext->WaitForKeyInfo (
666 BootContext->PickerContext,
667 KeyEndTime,
668 (FocusList[FocusState] != TAB_PICKER)
671 &PickerKeyInfo
672 );
673
674 if ((NumFocusList > 1) && (PickerKeyInfo.OcKeyCode == OC_INPUT_SWITCH_FOCUS)) {
676 FALSE,
677 BootContext,
678 BootEntries,
679 FocusList[FocusState],
680 ChosenEntry,
681 OldEntryCursor,
682 #if defined (BUILTIN_DEMONSTRATE_TYPING)
683 TypingRow,
684 TypingColumn,
685 #endif
686 FirstIndexRow,
687 ShutdownRestartRow,
688 ShutdownColumn,
689 RestartColumn
690 );
691
692 //
693 // On leaving picker the first time, any timeout gets cancelled (correctly), therefore text
694 // cursor changes, therefore text cursor gets redrawn - unless we do this.
695 //
696 if ((FocusList[FocusState] == TAB_PICKER) && (TimeOutSeconds > 0)) {
697 OldEntryCursor = GetPickerEntryCursor (BootContext, 0, ChosenEntry, ChosenEntry, PickerKeyInfo.OcModifiers);
698 }
699
700 if ((PickerKeyInfo.OcModifiers & OC_MODIFIERS_REVERSE_SWITCH_FOCUS) != 0) {
701 if (FocusState == 0) {
702 FocusState = NumFocusList;
703 }
704
705 FocusState--;
706 } else {
707 FocusState++;
708 if (FocusState == NumFocusList) {
709 FocusState = 0;
710 }
711 }
712
714 TRUE,
715 BootContext,
716 BootEntries,
717 FocusList[FocusState],
718 ChosenEntry,
719 OldEntryCursor,
720 #if defined (BUILTIN_DEMONSTRATE_TYPING)
721 TypingRow,
722 TypingColumn,
723 #endif
724 FirstIndexRow,
725 ShutdownRestartRow,
726 ShutdownColumn,
727 RestartColumn
728 );
729
730 gST->ConOut->SetCursorPosition (gST->ConOut, mStatusColumn, mStatusRow);
731 }
732
733 if (FocusList[FocusState] == TAB_RESTART) {
734 if (PickerKeyInfo.OcKeyCode == OC_INPUT_TYPING_CONFIRM) {
735 gST->ConOut->OutputString (gST->ConOut, OC_MENU_RESTART);
736 gST->ConOut->OutputString (gST->ConOut, L"\r\n");
738 ResetWarm ();
739 return EFI_SUCCESS;
740 }
741 } else if (FocusList[FocusState] == TAB_SHUTDOWN) {
742 if (PickerKeyInfo.OcKeyCode == OC_INPUT_TYPING_CONFIRM) {
743 gST->ConOut->OutputString (gST->ConOut, OC_MENU_SHUTDOWN);
744 gST->ConOut->OutputString (gST->ConOut, L"\r\n");
746 ResetShutdown ();
747 return EFI_SUCCESS;
748 }
749 }
750
751 #if defined (BUILTIN_DEMONSTRATE_TYPING)
752 else if (FocusList[FocusState] == TAB_TYPING_DEMO) {
753 if ((PickerKeyInfo.OcKeyCode == OC_INPUT_TYPING_BACKSPACE) && (TypingColumn > TypingStartColumn)) {
754 //
755 // Backspace and move cursor.
756 //
757 TypingColumn--;
758 gST->ConOut->SetCursorPosition (gST->ConOut, TypingColumn, TypingRow);
759 Code[0] = L'_';
760 gST->ConOut->OutputString (gST->ConOut, Code);
761 Code[0] = L' ';
762 gST->ConOut->OutputString (gST->ConOut, Code);
763 gST->ConOut->SetCursorPosition (gST->ConOut, mStatusColumn, mStatusRow);
764 } else if ((PickerKeyInfo.UnicodeChar >= 32) && (PickerKeyInfo.UnicodeChar < 128)) {
765 //
766 // Type and move cursor.
767 //
768 gST->ConOut->SetCursorPosition (gST->ConOut, TypingColumn, TypingRow);
769 Code[0] = PickerKeyInfo.UnicodeChar;
770 gST->ConOut->OutputString (gST->ConOut, Code);
771 Code[0] = L'_';
772 gST->ConOut->OutputString (gST->ConOut, Code);
773 gST->ConOut->SetCursorPosition (gST->ConOut, mStatusColumn, mStatusRow);
774 TypingColumn++;
775 }
776 }
777 #endif
778
779 if (PlayChosen && (PickerKeyInfo.OcKeyCode == OC_INPUT_TIMEOUT)) {
781 OcPlayAudioEntry (BootContext->PickerContext, BootEntries[ChosenEntry]);
782 PlayChosen = FALSE;
783 continue;
784 } else if (PickerKeyInfo.OcKeyCode == OC_INPUT_TIMEOUT) {
785 *ChosenBootEntry = BootEntries[BootContext->DefaultEntry->EntryIndex - 1];
786 gST->ConOut->OutputString (gST->ConOut, OC_MENU_TIMEOUT);
787 gST->ConOut->OutputString (gST->ConOut, L"\r\n");
789 return EFI_SUCCESS;
790 } else if (PickerKeyInfo.OcKeyCode == OC_INPUT_CONTINUE) {
791 if (ChosenEntry >= 0) {
792 *ChosenBootEntry = BootEntries[(UINTN)ChosenEntry];
793 } else {
794 *ChosenBootEntry = BootContext->DefaultEntry;
795 }
796
797 (*ChosenBootEntry)->SetDefault = ((PickerKeyInfo.OcModifiers & OC_MODIFIERS_SET_DEFAULT) != 0);
798 gST->ConOut->OutputString (gST->ConOut, OC_MENU_OK);
799 gST->ConOut->OutputString (gST->ConOut, L"\r\n");
800 return EFI_SUCCESS;
801 } else if (PickerKeyInfo.OcKeyCode == OC_INPUT_ABORTED) {
802 gST->ConOut->OutputString (gST->ConOut, OC_MENU_RELOADING);
803 gST->ConOut->OutputString (gST->ConOut, L"\r\n");
805 return EFI_ABORTED;
806 } else if ((PickerKeyInfo.OcKeyCode == OC_INPUT_MORE) && BootContext->PickerContext->HideAuxiliary) {
807 gST->ConOut->OutputString (gST->ConOut, OC_MENU_SHOW_AUXILIARY);
808 gST->ConOut->OutputString (gST->ConOut, L"\r\n");
810 BootContext->PickerContext->HideAuxiliary = FALSE;
811 return EFI_ABORTED;
812 } else if (PickerKeyInfo.OcKeyCode == OC_INPUT_UP) {
813 if (ChosenEntry < 0) {
814 ChosenEntry = 0;
815 } else if (ChosenEntry == 0) {
816 ChosenEntry = (INTN)(MIN (Count, OC_INPUT_MAX) - 1);
817 } else {
818 --ChosenEntry;
819 }
820
821 TimeOutSeconds = 0;
822 if (BootContext->PickerContext->PickerAudioAssist) {
823 PlayChosen = TRUE;
824 }
825
826 break;
827 } else if (PickerKeyInfo.OcKeyCode == OC_INPUT_DOWN) {
828 if (ChosenEntry < 0) {
829 ChosenEntry = 0;
830 } else if (ChosenEntry == (INTN)(MIN (Count, OC_INPUT_MAX) - 1)) {
831 ChosenEntry = 0;
832 } else {
833 ++ChosenEntry;
834 }
835
836 TimeOutSeconds = 0;
837 if (BootContext->PickerContext->PickerAudioAssist) {
838 PlayChosen = TRUE;
839 }
840
841 break;
842 } else if ((PickerKeyInfo.OcKeyCode == OC_INPUT_TOP) || (PickerKeyInfo.OcKeyCode == OC_INPUT_LEFT)) {
843 ChosenEntry = 0;
844 TimeOutSeconds = 0;
845 if (BootContext->PickerContext->PickerAudioAssist) {
846 PlayChosen = TRUE;
847 }
848
849 break;
850 } else if ((PickerKeyInfo.OcKeyCode == OC_INPUT_BOTTOM) || (PickerKeyInfo.OcKeyCode == OC_INPUT_RIGHT)) {
851 ChosenEntry = (INTN)(MIN (Count, OC_INPUT_MAX) - 1);
852 TimeOutSeconds = 0;
853 if (BootContext->PickerContext->PickerAudioAssist) {
854 PlayChosen = TRUE;
855 }
856
857 break;
858 } else if (PickerKeyInfo.OcKeyCode == OC_INPUT_VOICE_OVER) {
859 OcToggleVoiceOver (BootContext->PickerContext, NULL, NULL);
860 break;
861 } else if ((PickerKeyInfo.OcKeyCode != OC_INPUT_NO_ACTION) && (PickerKeyInfo.OcKeyCode >= 0) && ((UINTN)PickerKeyInfo.OcKeyCode < Count)) {
862 *ChosenBootEntry = BootEntries[PickerKeyInfo.OcKeyCode];
863 (*ChosenBootEntry)->SetDefault = ((PickerKeyInfo.OcModifiers & OC_MODIFIERS_SET_DEFAULT) != 0);
864 Code[0] = OC_INPUT_STR[PickerKeyInfo.OcKeyCode];
865 gST->ConOut->OutputString (gST->ConOut, Code);
866 gST->ConOut->OutputString (gST->ConOut, L"\r\n");
867 return EFI_SUCCESS;
868 }
869
870 if ((ModifiersChanged || (PickerKeyInfo.OcKeyCode != OC_INPUT_NO_ACTION)) && (TimeOutSeconds > 0)) {
872 TimeOutSeconds = 0;
873 break;
874 }
875
876 if (ModifiersChanged || (PickerKeyInfo.UnicodeChar != CHAR_NULL)) {
877 break;
878 }
879 }
880 }
881
882 ASSERT (FALSE);
883}
884
885EFI_STATUS
886EFIAPI
888 IN OC_PICKER_CONTEXT *Context,
889 IN OC_PRIVILEGE_LEVEL Level
890 )
891{
892 BOOLEAN Result;
893
894 UINT8 Password[OC_PASSWORD_MAX_LEN];
895 UINT32 PwIndex;
896
897 UINT8 Index;
898 OC_PICKER_KEY_INFO PickerKeyInfo;
899 UINT8 SpaceIndex;
900
902 gST->ConOut->EnableCursor (gST->ConOut, FALSE);
903 gST->ConOut->ClearScreen (gST->ConOut);
904
905 for (Index = 0; Index < OC_PASSWORD_MAX_RETRIES; ++Index) {
906 PwIndex = 0;
907
908 Context->HotKeyContext->FlushTypingBuffer (Context);
909
910 gST->ConOut->OutputString (gST->ConOut, OC_MENU_PASSWORD_REQUEST);
912
913 while (TRUE) {
914 Context->HotKeyContext->WaitForKeyInfo (
915 Context,
916 0,
918 &PickerKeyInfo
919 );
920
921 if (PickerKeyInfo.OcKeyCode == OC_INPUT_VOICE_OVER) {
923 continue;
924 }
925
926 if (PickerKeyInfo.UnicodeChar == CHAR_CARRIAGE_RETURN) {
927 //
928 // RETURN finalizes the input.
929 //
930 break;
931 }
932
933 if (PickerKeyInfo.UnicodeChar == CHAR_BACKSPACE) {
934 //
935 // Delete the last entered character, if such exists.
936 //
937 if (PwIndex > 0) {
938 --PwIndex;
939 Password[PwIndex] = 0;
940 //
941 // Overwrite current character with a space.
942 //
943 gST->ConOut->SetCursorPosition (
944 gST->ConOut,
945 gST->ConOut->Mode->CursorColumn - 1,
946 gST->ConOut->Mode->CursorRow
947 );
948 gST->ConOut->OutputString (gST->ConOut, L" ");
949 gST->ConOut->SetCursorPosition (
950 gST->ConOut,
951 gST->ConOut->Mode->CursorColumn - 1,
952 gST->ConOut->Mode->CursorRow
953 );
954 }
955
957 continue;
958 }
959
960 if ( (PickerKeyInfo.UnicodeChar != CHAR_NULL)
961 && (PickerKeyInfo.UnicodeChar == (CHAR8)PickerKeyInfo.UnicodeChar)
962 && (PwIndex < ARRAY_SIZE (Password)))
963 {
964 gST->ConOut->OutputString (gST->ConOut, L"*");
965 Password[PwIndex] = (UINT8)PickerKeyInfo.UnicodeChar;
967 ++PwIndex;
968 continue;
969 }
970
971 //
972 // Only ASCII characters are supported.
973 //
975 Context,
979 );
980 }
981
982 //
983 // Output password processing status.
984 //
985 gST->ConOut->SetCursorPosition (
986 gST->ConOut,
987 0,
988 gST->ConOut->Mode->CursorRow
989 );
990 gST->ConOut->OutputString (gST->ConOut, OC_MENU_PASSWORD_PROCESSING);
991 //
992 // Clear remaining password prompt status.
993 //
994 for (
996 SpaceIndex < L_STR_LEN (OC_MENU_PASSWORD_REQUEST) + PwIndex;
997 ++SpaceIndex
998 )
999 {
1000 gST->ConOut->OutputString (gST->ConOut, L" ");
1001 }
1002
1003 Result = Context->VerifyPassword (
1004 Password,
1005 PwIndex,
1006 Context->PrivilegeContext
1007 );
1008
1009 SecureZeroMem (Password, PwIndex);
1010 //
1011 // Clear password processing status.
1012 //
1013 gST->ConOut->SetCursorPosition (
1014 gST->ConOut,
1015 0,
1016 gST->ConOut->Mode->CursorRow
1017 );
1018 for (SpaceIndex = 0; SpaceIndex < L_STR_LEN (OC_MENU_PASSWORD_PROCESSING); ++SpaceIndex) {
1019 gST->ConOut->OutputString (gST->ConOut, L" ");
1020 }
1021
1022 gST->ConOut->SetCursorPosition (
1023 gST->ConOut,
1024 0,
1025 gST->ConOut->Mode->CursorRow
1026 );
1027
1028 if (Result) {
1030 return EFI_SUCCESS;
1031 }
1032
1034 }
1035
1036 gST->ConOut->OutputString (gST->ConOut, OC_MENU_PASSWORD_RETRY_LIMIT L"\r\n");
1038 DEBUG ((DEBUG_WARN, "OCB: User failed to verify password %d times running\n", OC_PASSWORD_MAX_RETRIES));
1039
1040 gBS->Stall (SECONDS_TO_MICROSECONDS (5));
1041 ResetWarm ();
1042
1043 return EFI_ACCESS_DENIED;
1044}
UINT16 APPLE_MODIFIER_MAP
Definition AppleHid.h:102
#define ARRAY_SIZE(Array)
Definition AppleMacEfi.h:34
UINT64 Length
#define APPLE_VOICE_OVER_AUDIO_FILE_BEEP
#define OC_KB_DBG_DOWN_ROW
#define OC_KB_DBG_DELTA_SAMPLE_COLUMN
STATIC TAB_FOCUS mFocusList[]
#define MENU_PREFIX_LENGTH
EFI_STATUS EFIAPI OcShowSimplePasswordRequest(IN OC_PICKER_CONTEXT *Context, IN OC_PRIVILEGE_LEVEL Level)
#define OC_KB_DBG_X_ROW
_TAB_FOCUS
@ TAB_MAX
@ TAB_RESTART
@ TAB_PICKER
@ TAB_SHUTDOWN
STATIC OC_KB_DEBUG_CALLBACKS mSimplePickerKbDebug
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, IN INT32 FirstIndexRow, IN INT32 ShutdownRestartRow, IN INT32 ShutdownColumn, IN INT32 RestartColumn)
STATIC INT32 mStatusColumn
STATIC VOID EFIAPI InstrumentLoopDelay(UINT64 LoopDelayStart, UINT64 LoopDelayEnd)
STATIC UINT64 mLoopDelayEnd
STATIC INT32 mStatusRow
STATIC CHAR16 GetPickerEntryCursor(IN OC_BOOT_CONTEXT *BootContext, IN UINT32 TimeOutSeconds, IN INTN ChosenEntry, IN UINTN Index, IN OC_MODIFIER_MAP OcModifiers)
STATIC VOID DisplaySystemMs(VOID)
EFI_STATUS EFIAPI OcShowSimpleBootMenu(IN OC_BOOT_CONTEXT *BootContext, IN OC_BOOT_ENTRY **BootEntries, OUT OC_BOOT_ENTRY **ChosenBootEntry)
#define OC_KB_DBG_MODIFIERS_ROW
STATIC UINT64 mLoopDelayStart
STATIC VOID InitKbDebugDisplay(VOID)
STATIC UINT64 mPreviousTick
#define OC_KB_DBG_MAX_COLUMN
STATIC INT32 mRunningColumn
STATIC TAB_FOCUS mFocusListMinimal[]
STATIC TAB_FOCUS mFocusListReversed[]
_TAB_FOCUS TAB_FOCUS
STATIC VOID EFIAPI ShowKbDebugDisplay(UINTN NumKeysDown, UINTN NumKeysHeld, APPLE_MODIFIER_MAP Modifiers)
#define OC_KB_DBG_PRINT_ROW
@ EfiConsoleControlScreenText
APPLE_KEY_MAP_AGGREGATOR_PROTOCOL * OcAppleKeyMapInstallProtocols(IN BOOLEAN Reinstall)
#define OC_VOICE_OVER_AUDIO_FILE_TIMEOUT
Definition OcAudio.h:72
#define OC_VOICE_OVER_AUDIO_FILE_SELECTED
Definition OcAudio.h:67
#define OC_VOICE_OVER_AUDIO_FILE_PASSWORD_RETRY_LIMIT
Definition OcAudio.h:63
#define OC_VOICE_OVER_AUDIO_FILE_PASSWORD_INCORRECT
Definition OcAudio.h:62
#define OC_VOICE_OVER_AUDIO_FILE_DEFAULT
Definition OcAudio.h:45
#define OC_VOICE_OVER_AUDIO_FILE_ABORT_TIMEOUT
Definition OcAudio.h:43
#define OC_VOICE_OVER_AUDIO_FILE_ENTER_PASSWORD
Definition OcAudio.h:47
#define OC_VOICE_OVER_AUDIO_FILE_RESTART
Definition OcAudio.h:66
#define OC_VOICE_OVER_AUDIO_FILE_PASSWORD_ACCEPTED
Definition OcAudio.h:61
#define OC_VOICE_OVER_AUDIO_FILE_RELOADING
Definition OcAudio.h:64
#define OC_VOICE_OVER_AUDIO_BASE_TYPE_APPLE
Definition OcAudio.h:37
#define OC_VOICE_OVER_AUDIO_FILE_SHOW_AUXILIARY
Definition OcAudio.h:68
#define OC_VOICE_OVER_AUDIO_FILE_SHUT_DOWN
Definition OcAudio.h:69
#define OC_VOICE_OVER_AUDIO_FILE_CHOOSE_OS
Definition OcAudio.h:44
#define OC_VOICE_OVER_AUDIO_BASE_TYPE_OPEN_CORE
Definition OcAudio.h:38
STATIC_ASSERT(BYTES_PER_PIXEL==sizeof(UINT32), "Non 4-byte pixels are unsupported!")
#define OC_PICKER_KEYS_FOR_TYPING
#define OC_MENU_OK
#define OC_MENU_BOOT_MENU
#define OC_PICKER_KEYS_FOR_PICKER
#define OC_ATTR_SHOW_DEBUG_DISPLAY
#define OC_INPUT_TYPING_BACKSPACE
Clear last typed character while typing (press backspace)
#define OC_MODIFIERS_NONE
#define OC_ATTR_USE_REVERSED_UI
#define OC_INPUT_TYPING_CONFIRM
Confirm input while typing (press enter)
#define OC_INPUT_DOWN
Move down.
#define OC_INPUT_NO_ACTION
Some other key.
#define OC_MENU_SHUTDOWN
#define OC_INPUT_TIMEOUT
Timeout.
#define OC_MODIFIERS_SET_DEFAULT
#define OC_MENU_PASSWORD_PROCESSING
VOID EFIAPI OcToggleVoiceOver(IN OC_PICKER_CONTEXT *Context, IN CONST CHAR8 *BasePath OPTIONAL, IN CONST CHAR8 *BaseType OPTIONAL)
Definition BootAudio.c:255
#define OC_INPUT_LEFT
Move left.
#define OC_VOICE_OVER_SILENCE_NORMAL_MS
From boot.efi, constant.
#define OC_MODIFIERS_REVERSE_SWITCH_FOCUS
#define OC_VOICE_OVER_SILENCE_ERROR_MS
#define OC_INPUT_MAX
#define OC_VOICE_OVER_SIGNAL_NORMAL_MS
From boot.efi, constant.
#define OC_MENU_RELOADING
#define OC_VOICE_OVER_IDLE_TIMEOUT_MS
Experimental, less is problematic.
EFI_STATUS EFIAPI OcPlayAudioFile(IN OC_PICKER_CONTEXT *Context, IN CONST CHAR8 *BasePath, IN CONST CHAR8 *BaseType, IN BOOLEAN Fallback)
Definition BootAudio.c:77
#define OC_VOICE_OVER_SIGNAL_ERROR_MS
#define OC_INPUT_CONTINUE
Continue (press enter)
#define OC_MENU_RESTART
#define OC_INPUT_ABORTED
Esc or 0.
#define OC_MENU_SHOW_AUXILIARY
#define OC_ATTR_USE_MINIMAL_UI
#define OC_INPUT_BOTTOM
Move to bottom.
#define OC_INPUT_STR
#define OC_INPUT_MORE
Show more entries (press space)
#define OC_INPUT_SWITCH_FOCUS
Switch UI focus (tab and shift+tab)
#define OC_INPUT_RIGHT
Move right.
EFI_STATUS EFIAPI OcPlayAudioBeep(IN OC_PICKER_CONTEXT *Context, IN UINT32 ToneCount, IN UINT32 ToneLength, IN UINT32 SilenceLength)
Definition BootAudio.c:155
#define OC_MENU_PASSWORD_RETRY_LIMIT
#define OC_INPUT_UP
Move up.
#define OC_INPUT_TOP
Move to top.
#define OC_VOICE_OVER_SIGNALS_ERROR
Password verification error or boot failure.
#define OC_MENU_CHOOSE_OS
#define OC_INPUT_VOICE_OVER
Toggle VoiceOver (press CMD+F5)
#define OC_MENU_TIMEOUT
OC_PRIVILEGE_LEVEL
#define OC_MENU_EXTERNAL
#define OC_MENU_PASSWORD_REQUEST
EFI_STATUS EFIAPI OcPlayAudioEntry(IN OC_PICKER_CONTEXT *Context, IN OC_BOOT_ENTRY *Entry)
Definition BootAudio.c:188
#define OC_MENU_DISK_IMAGE
UINT16 OC_MODIFIER_MAP
#define OC_VOICE_OVER_SIGNALS_NORMAL
Username prompt or any input for boot.efi.
EFI_SYSTEM_TABLE * gST
EFI_BOOT_SERVICES * gBS
EFI_CONSOLE_CONTROL_SCREEN_MODE OcConsoleControlSetMode(IN EFI_CONSOLE_CONTROL_SCREEN_MODE Mode)
#define OC_PASSWORD_MAX_LEN
Definition OcCryptoLib.h:89
#define OC_PASSWORD_MAX_RETRIES
Definition OcCryptoLib.h:94
VOID * SecureZeroMem(OUT VOID *Buffer, IN UINTN Length)
Definition SecureMem.c:73
#define SECONDS_TO_MICROSECONDS(x)
Definition OcMiscLib.h:30
VOID EFIAPI ResetWarm(VOID)
VOID EFIAPI ResetShutdown(VOID)
#define L_STR_LEN(String)
Definition OcStringLib.h:26
#define L_STR_SIZE(String)
Definition OcStringLib.h:35
UINT64 EFIAPI GetTscFrequency(VOID)
Definition OcTimerLib.c:243
UINT64 EFIAPI DivU64x64Remainder(IN UINT64 Dividend, IN UINT64 Divisor, OUT UINT64 *Remainder OPTIONAL)
Definition UserMath.c:59
UINT64 EFIAPI AsmReadTsc(VOID)
Definition UserMisc.c:232
UINT64 EFIAPI GetTimeInNanoSecond(IN UINT64 Ticks)
UINT64 EFIAPI GetPerformanceCounter(VOID)
#define ASSERT(x)
Definition coder.h:55
#define MIN(a, b)
Definition deflate.c:1673
#define Code
Definition deflate.h:80
OC_MODIFIER_MAP OcModifiers