]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupportUI.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Universal / EbcDxe / EbcDebugger / EdbSupportUI.c
1 /** @file
2
3 Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
4 SPDX-License-Identifier: BSD-2-Clause-Patent
5
6
7 **/
8
9 #include "Edb.h"
10
11 /**
12 Set the current coordinates of the cursor position.
13
14 @param ConOut Point to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.
15 @param Column The position to set the cursor to.
16 @param Row The position to set the cursor to.
17 @param LineLength Length of a line.
18 @param TotalRow Total row of a screen.
19 @param Str Point to the string.
20 @param StrPos The position of the string.
21 @param Len The length of the string.
22
23 **/
24 VOID
25 EFIAPI
26 SetCursorPosition (
27 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut,
28 IN UINTN Column,
29 IN INTN Row,
30 IN UINTN LineLength,
31 IN UINTN TotalRow,
32 IN CHAR16 *Str,
33 IN UINTN StrPos,
34 IN UINTN Len
35 );
36
37 /**
38
39 Function waits for a given event to fire, or for an optional timeout to expire.
40
41 @param Event - The event to wait for
42 @param Timeout - An optional timeout value in 100 ns units.
43
44 @retval EFI_SUCCESS - Event fired before Timeout expired.
45 @retval EFI_TIME_OUT - Timout expired before Event fired..
46
47 **/
48 EFI_STATUS
49 EFIAPI
50 WaitForSingleEvent (
51 IN EFI_EVENT Event,
52 IN UINT64 Timeout OPTIONAL
53 )
54 {
55 EFI_STATUS Status;
56 UINTN Index;
57 EFI_EVENT TimerEvent;
58 EFI_EVENT WaitList[2];
59
60 if (Timeout != 0) {
61 //
62 // Create a timer event
63 //
64 Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);
65 if (!EFI_ERROR (Status)) {
66 //
67 // Set the timer event
68 //
69 gBS->SetTimer (
70 TimerEvent,
71 TimerRelative,
72 Timeout
73 );
74
75 //
76 // Wait for the original event or the timer
77 //
78 WaitList[0] = Event;
79 WaitList[1] = TimerEvent;
80 Status = gBS->WaitForEvent (2, WaitList, &Index);
81 gBS->CloseEvent (TimerEvent);
82
83 //
84 // If the timer expired, change the return to timed out
85 //
86 if (!EFI_ERROR (Status) && (Index == 1)) {
87 Status = EFI_TIMEOUT;
88 }
89 }
90 } else {
91 //
92 // No timeout... just wait on the event
93 //
94 Status = gBS->WaitForEvent (1, &Event, &Index);
95 ASSERT (!EFI_ERROR (Status));
96 ASSERT (Index == 0);
97 }
98
99 return Status;
100 }
101
102 /**
103
104 Move the cursor position one character backward.
105
106 @param LineLength Length of a line. Get it by calling QueryMode
107 @param Column Current column of the cursor position
108 @param Row Current row of the cursor position
109
110 **/
111 VOID
112 EFIAPI
113 ConMoveCursorBackward (
114 IN UINTN LineLength,
115 IN OUT UINTN *Column,
116 IN OUT UINTN *Row
117 )
118 {
119 ASSERT (Column != NULL);
120 ASSERT (Row != NULL);
121 //
122 // If current column is 0, move to the last column of the previous line,
123 // otherwise, just decrement column.
124 //
125 if (*Column == 0) {
126 (*Column) = LineLength - 1;
127 //
128 // if (*Row > 0) {
129 //
130 (*Row)--;
131 //
132 // }
133 //
134 } else {
135 (*Column)--;
136 }
137 }
138
139 /**
140
141 Move the cursor position one character backward.
142
143 @param LineLength Length of a line. Get it by calling QueryMode
144 @param TotalRow Total row of a screen, get by calling QueryMode
145 @param Column Current column of the cursor position
146 @param Row Current row of the cursor position
147
148 **/
149 VOID
150 EFIAPI
151 ConMoveCursorForward (
152 IN UINTN LineLength,
153 IN UINTN TotalRow,
154 IN OUT UINTN *Column,
155 IN OUT UINTN *Row
156 )
157 {
158 ASSERT (Column != NULL);
159 ASSERT (Row != NULL);
160 //
161 // If current column is at line end, move to the first column of the nest
162 // line, otherwise, just increment column.
163 //
164 (*Column)++;
165 if (*Column >= LineLength) {
166 (*Column) = 0;
167 if ((*Row) < TotalRow - 1) {
168 (*Row)++;
169 }
170 }
171 }
172
173 CHAR16 mBackupSpace[EFI_DEBUG_INPUS_BUFFER_SIZE];
174 CHAR16 mInputBufferHistory[EFI_DEBUG_INPUS_BUFFER_SIZE];
175
176 /**
177
178 Get user input.
179
180 @param Prompt The prompt string.
181 @param InStr Point to the input string.
182 @param StrLength The max length of string user can input.
183
184 **/
185 VOID
186 EFIAPI
187 Input (
188 IN CHAR16 *Prompt OPTIONAL,
189 OUT CHAR16 *InStr,
190 IN UINTN StrLength
191 )
192 {
193 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
194 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn;
195 BOOLEAN Done;
196 UINTN Column;
197 UINTN Row;
198 UINTN StartColumn;
199 UINTN Update;
200 UINTN Delete;
201 UINTN Len;
202 UINTN StrPos;
203 UINTN Index;
204 UINTN LineLength;
205 UINTN TotalRow;
206 UINTN SkipLength;
207 UINTN OutputLength;
208 UINTN TailRow;
209 UINTN TailColumn;
210 EFI_INPUT_KEY Key;
211 BOOLEAN InsertMode;
212 BOOLEAN NeedAdjust;
213 UINTN SubIndex;
214 CHAR16 *CommandStr;
215
216 ConOut = gST->ConOut;
217 ConIn = gST->ConIn;
218
219 ASSERT (ConOut != NULL);
220 ASSERT (ConIn != NULL);
221 ASSERT (InStr != NULL);
222
223 if (Prompt != NULL) {
224 ConOut->OutputString (ConOut, Prompt);
225 }
226
227 //
228 // Read a line from the console
229 //
230 Len = 0;
231 StrPos = 0;
232 OutputLength = 0;
233 Update = 0;
234 Delete = 0;
235 InsertMode = TRUE;
236 NeedAdjust = FALSE;
237
238 //
239 // If buffer is not large enough to hold a CHAR16, do nothing.
240 //
241 if (StrLength < 1) {
242 return;
243 }
244
245 //
246 // Get the screen setting and the current cursor location
247 //
248 StartColumn = ConOut->Mode->CursorColumn;
249 Column = StartColumn;
250 Row = ConOut->Mode->CursorRow;
251 ConOut->QueryMode (ConOut, ConOut->Mode->Mode, &LineLength, &TotalRow);
252 if (LineLength == 0) {
253 return;
254 }
255
256 SetMem (InStr, StrLength * sizeof (CHAR16), 0);
257 Done = FALSE;
258 do {
259 //
260 // Read a key
261 //
262 WaitForSingleEvent (ConIn->WaitForKey, 0);
263 ConIn->ReadKeyStroke (ConIn, &Key);
264
265 switch (Key.UnicodeChar) {
266 case CHAR_CARRIAGE_RETURN:
267 //
268 // All done, print a newline at the end of the string
269 //
270 TailRow = Row + (Len - StrPos + Column) / LineLength;
271 TailColumn = (Len - StrPos + Column) % LineLength;
272 Done = TRUE;
273 break;
274
275 case CHAR_BACKSPACE:
276 if (StrPos != 0) {
277 //
278 // If not move back beyond string beginning, move all characters behind
279 // the current position one character forward
280 //
281 StrPos -= 1;
282 Update = StrPos;
283 Delete = 1;
284 CopyMem (InStr + StrPos, InStr + StrPos + 1, sizeof (CHAR16) * (Len - StrPos));
285
286 //
287 // Adjust the current column and row
288 //
289 ConMoveCursorBackward (LineLength, &Column, &Row);
290
291 NeedAdjust = TRUE;
292 }
293
294 break;
295
296 default:
297 if (Key.UnicodeChar >= ' ') {
298 //
299 // If we are at the buffer's end, drop the key
300 //
301 if ((Len == StrLength - 1) && (InsertMode || (StrPos == Len))) {
302 break;
303 }
304
305 //
306 // If in insert mode, move all characters behind the current position
307 // one character backward to make space for this character. Then store
308 // the character.
309 //
310 if (InsertMode) {
311 for (Index = Len; Index > StrPos; Index -= 1) {
312 InStr[Index] = InStr[Index - 1];
313 }
314 }
315
316 InStr[StrPos] = Key.UnicodeChar;
317 Update = StrPos;
318
319 StrPos += 1;
320 OutputLength = 1;
321 }
322
323 break;
324
325 case 0:
326 switch (Key.ScanCode) {
327 case SCAN_DELETE:
328 //
329 // Move characters behind current position one character forward
330 //
331 if (Len != 0) {
332 Update = StrPos;
333 Delete = 1;
334 CopyMem (InStr + StrPos, InStr + StrPos + 1, sizeof (CHAR16) * (Len - StrPos));
335
336 NeedAdjust = TRUE;
337 }
338
339 break;
340
341 case SCAN_LEFT:
342 //
343 // Adjust current cursor position
344 //
345 if (StrPos != 0) {
346 StrPos -= 1;
347 ConMoveCursorBackward (LineLength, &Column, &Row);
348 }
349
350 break;
351
352 case SCAN_RIGHT:
353 //
354 // Adjust current cursor position
355 //
356 if (StrPos < Len) {
357 StrPos += 1;
358 ConMoveCursorForward (LineLength, TotalRow, &Column, &Row);
359 }
360
361 break;
362
363 case SCAN_HOME:
364 //
365 // Move current cursor position to the beginning of the command line
366 //
367 Row -= (StrPos + StartColumn) / LineLength;
368 Column = StartColumn;
369 StrPos = 0;
370 break;
371
372 case SCAN_END:
373 //
374 // Move current cursor position to the end of the command line
375 //
376 TailRow = Row + (Len - StrPos + Column) / LineLength;
377 TailColumn = (Len - StrPos + Column) % LineLength;
378 Row = TailRow;
379 Column = TailColumn;
380 StrPos = Len;
381 break;
382
383 case SCAN_ESC:
384 //
385 // Prepare to clear the current command line
386 //
387 InStr[0] = 0;
388 Update = 0;
389 Delete = Len;
390 Row -= (StrPos + StartColumn) / LineLength;
391 Column = StartColumn;
392 OutputLength = 0;
393
394 NeedAdjust = TRUE;
395 break;
396
397 case SCAN_INSERT:
398 //
399 // Toggle the SEnvInsertMode flag
400 //
401 InsertMode = (BOOLEAN) !InsertMode;
402 break;
403
404 case SCAN_UP:
405 case SCAN_DOWN:
406 //
407 // show history
408 //
409 CopyMem (InStr, mInputBufferHistory, StrLength * sizeof (CHAR16));
410 StrPos = StrLen (mInputBufferHistory);
411 Update = 0;
412 Delete = 0;
413 OutputLength = 0;
414
415 TailRow = Row + (StrPos + StartColumn) / LineLength;
416 TailColumn = (StrPos + StartColumn) % LineLength;
417 Row = TailRow;
418 Column = TailColumn;
419 NeedAdjust = FALSE;
420
421 ConOut->SetCursorPosition (ConOut, StartColumn, Row);
422 for (SubIndex = 0; SubIndex < EFI_DEBUG_INPUS_BUFFER_SIZE - (StartColumn - EFI_DEBUG_PROMPT_COLUMN); SubIndex++) {
423 mBackupSpace[SubIndex] = L' ';
424 }
425
426 EDBPrint (mBackupSpace);
427 SetMem (mBackupSpace, (EFI_DEBUG_INPUS_BUFFER_SIZE - (StartColumn - EFI_DEBUG_PROMPT_COLUMN)) * sizeof (CHAR16), 0);
428
429 ConOut->SetCursorPosition (ConOut, StartColumn, Row);
430 Len = StrPos;
431
432 break;
433
434 case SCAN_F1:
435 case SCAN_F2:
436 case SCAN_F3:
437 case SCAN_F4:
438 case SCAN_F5:
439 case SCAN_F6:
440 case SCAN_F7:
441 case SCAN_F8:
442 case SCAN_F9:
443 case SCAN_F10:
444 case SCAN_F11:
445 case SCAN_F12:
446 CommandStr = GetCommandNameByKey (Key);
447 if (CommandStr != NULL) {
448 StrnCpyS (InStr, StrLength, CommandStr, StrLength - 1);
449 return;
450 }
451
452 break;
453 }
454 }
455
456 if (Done) {
457 break;
458 }
459
460 //
461 // If we need to update the output do so now
462 //
463 if (Update != -1) {
464 if (NeedAdjust) {
465 ConOut->SetCursorPosition (ConOut, Column, Row);
466 for (SubIndex = 0; SubIndex < EFI_DEBUG_INPUS_BUFFER_SIZE - (Column - EFI_DEBUG_PROMPT_COLUMN); SubIndex++) {
467 mBackupSpace[SubIndex] = L' ';
468 }
469
470 EDBPrint (mBackupSpace);
471 SetMem (mBackupSpace, (EFI_DEBUG_INPUS_BUFFER_SIZE - (Column - EFI_DEBUG_PROMPT_COLUMN)) * sizeof (CHAR16), 0);
472 ConOut->SetCursorPosition (ConOut, Column, Row);
473 NeedAdjust = FALSE;
474 }
475
476 EDBPrint (InStr + Update);
477 Len = StrLen (InStr);
478
479 if (Delete != 0) {
480 SetMem (InStr + Len, Delete * sizeof (CHAR16), 0x00);
481 }
482
483 if (StrPos > Len) {
484 StrPos = Len;
485 }
486
487 Update = (UINTN)-1;
488
489 //
490 // After using print to reflect newly updates, if we're not using
491 // BACKSPACE and DELETE, we need to move the cursor position forward,
492 // so adjust row and column here.
493 //
494 if ((Key.UnicodeChar != CHAR_BACKSPACE) && !((Key.UnicodeChar == 0) && (Key.ScanCode == SCAN_DELETE))) {
495 //
496 // Calulate row and column of the tail of current string
497 //
498 TailRow = Row + (Len - StrPos + Column + OutputLength) / LineLength;
499 TailColumn = (Len - StrPos + Column + OutputLength) % LineLength;
500
501 //
502 // If the tail of string reaches screen end, screen rolls up, so if
503 // Row does not equal TailRow, Row should be decremented
504 //
505 // (if we are recalling commands using UPPER and DOWN key, and if the
506 // old command is too long to fit the screen, TailColumn must be 79.
507 //
508 if ((TailColumn == 0) && (TailRow >= TotalRow) && ((UINTN)Row != TailRow)) {
509 Row--;
510 }
511
512 //
513 // Calculate the cursor position after current operation. If cursor
514 // reaches line end, update both row and column, otherwise, only
515 // column will be changed.
516 //
517 if (Column + OutputLength >= LineLength) {
518 SkipLength = OutputLength - (LineLength - Column);
519
520 Row += SkipLength / LineLength + 1;
521 if ((UINTN)Row > TotalRow - 1) {
522 Row = TotalRow - 1;
523 }
524
525 Column = SkipLength % LineLength;
526 } else {
527 Column += OutputLength;
528 }
529 }
530
531 Delete = 0;
532 }
533
534 //
535 // Set the cursor position for this key
536 //
537 SetCursorPosition (ConOut, Column, Row, LineLength, TotalRow, InStr, StrPos, Len);
538 } while (!Done);
539
540 CopyMem (mInputBufferHistory, InStr, StrLength * sizeof (CHAR16));
541
542 //
543 // Return the data to the caller
544 //
545 return;
546 }
547
548 /**
549 Set the current coordinates of the cursor position.
550
551 @param ConOut Point to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.
552 @param Column The position to set the cursor to.
553 @param Row The position to set the cursor to.
554 @param LineLength Length of a line.
555 @param TotalRow Total row of a screen.
556 @param Str Point to the string.
557 @param StrPos The position of the string.
558 @param Len The length of the string.
559
560 **/
561 VOID
562 EFIAPI
563 SetCursorPosition (
564 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut,
565 IN UINTN Column,
566 IN INTN Row,
567 IN UINTN LineLength,
568 IN UINTN TotalRow,
569 IN CHAR16 *Str,
570 IN UINTN StrPos,
571 IN UINTN Len
572 )
573 {
574 CHAR16 Backup;
575
576 ASSERT (ConOut != NULL);
577 ASSERT (Str != NULL);
578
579 Backup = 0;
580 if (Row >= 0) {
581 ConOut->SetCursorPosition (ConOut, Column, Row);
582 return;
583 }
584
585 if (Len - StrPos > Column * Row) {
586 Backup = *(Str + StrPos + Column * Row);
587 *(Str + StrPos + Column * Row) = 0;
588 }
589
590 EDBPrint (L"%s", Str + StrPos);
591 if (Len - StrPos > Column * Row) {
592 *(Str + StrPos + Column * Row) = Backup;
593 }
594
595 ConOut->SetCursorPosition (ConOut, 0, 0);
596 }
597
598 /**
599
600 SetPageBreak.
601
602 **/
603 BOOLEAN
604 EFIAPI
605 SetPageBreak (
606 VOID
607 )
608 {
609 EFI_INPUT_KEY Key;
610 CHAR16 Str[3];
611 BOOLEAN OmitPrint;
612
613 //
614 // Check
615 //
616 if (!mDebuggerPrivate.EnablePageBreak) {
617 return FALSE;
618 }
619
620 gST->ConOut->OutputString (gST->ConOut, L"Press ENTER to continue, 'q' to exit:");
621
622 OmitPrint = FALSE;
623 //
624 // Wait for user input
625 //
626 Str[0] = ' ';
627 Str[1] = 0;
628 Str[2] = 0;
629 for ( ; ;) {
630 WaitForSingleEvent (gST->ConIn->WaitForKey, 0);
631 gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
632
633 //
634 // handle control keys
635 //
636 if (Key.UnicodeChar == CHAR_NULL) {
637 if (Key.ScanCode == SCAN_ESC) {
638 gST->ConOut->OutputString (gST->ConOut, L"\r\n");
639 OmitPrint = TRUE;
640 break;
641 }
642
643 continue;
644 }
645
646 if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
647 gST->ConOut->OutputString (gST->ConOut, L"\r\n");
648 break;
649 }
650
651 //
652 // Echo input
653 //
654 Str[1] = Key.UnicodeChar;
655 if (Str[1] == CHAR_BACKSPACE) {
656 continue;
657 }
658
659 gST->ConOut->OutputString (gST->ConOut, Str);
660
661 if ((Str[1] == L'q') || (Str[1] == L'Q')) {
662 OmitPrint = TRUE;
663 } else {
664 OmitPrint = FALSE;
665 }
666
667 Str[0] = CHAR_BACKSPACE;
668 }
669
670 return OmitPrint;
671 }
672
673 /**
674 Print a Unicode string to the output device.
675
676 @param Format A Null-terminated Unicode format string.
677 @param ... The variable argument list that contains pointers to Null-
678 terminated Unicode strings to be printed
679
680 **/
681 UINTN
682 EFIAPI
683 EDBPrint (
684 IN CONST CHAR16 *Format,
685 ...
686 )
687 {
688 UINTN Return;
689 VA_LIST Marker;
690 CHAR16 Buffer[EFI_DEBUG_MAX_PRINT_BUFFER];
691
692 VA_START (Marker, Format);
693 Return = UnicodeVSPrint (Buffer, sizeof (Buffer), Format, Marker);
694 VA_END (Marker);
695
696 if (gST->ConOut != NULL) {
697 //
698 // To be extra safe make sure ConOut has been initialized
699 //
700 gST->ConOut->OutputString (gST->ConOut, Buffer);
701 }
702
703 return Return;
704 }
705
706 /**
707 Print a Unicode string to the output buffer.
708
709 @param Buffer A pointer to the output buffer for the produced Null-terminated
710 Unicode string.
711 @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
712 @param Format A Null-terminated Unicode format string.
713 @param ... The variable argument list that contains pointers to Null-
714 terminated Unicode strings to be printed
715
716 **/
717 UINTN
718 EFIAPI
719 EDBSPrint (
720 OUT CHAR16 *Buffer,
721 IN INTN BufferSize,
722 IN CONST CHAR16 *Format,
723 ...
724 )
725 {
726 UINTN Return;
727 VA_LIST Marker;
728
729 ASSERT (BufferSize > 0);
730
731 VA_START (Marker, Format);
732 Return = UnicodeVSPrint (Buffer, (UINTN)BufferSize, Format, Marker);
733 VA_END (Marker);
734
735 return Return;
736 }
737
738 /**
739 Print a Unicode string to the output buffer with specified offset..
740
741 @param Buffer A pointer to the output buffer for the produced Null-terminated
742 Unicode string.
743 @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
744 @param Offset The offset of the buffer.
745 @param Format A Null-terminated Unicode format string.
746 @param ... The variable argument list that contains pointers to Null-
747 terminated Unicode strings to be printed
748
749 **/
750 UINTN
751 EFIAPI
752 EDBSPrintWithOffset (
753 OUT CHAR16 *Buffer,
754 IN INTN BufferSize,
755 IN UINTN Offset,
756 IN CONST CHAR16 *Format,
757 ...
758 )
759 {
760 UINTN Return;
761 VA_LIST Marker;
762
763 ASSERT (BufferSize - (Offset * sizeof (CHAR16)) > 0);
764
765 VA_START (Marker, Format);
766 Return = UnicodeVSPrint (Buffer + Offset, (UINTN)(BufferSize - (Offset * sizeof (CHAR16))), Format, Marker);
767 VA_END (Marker);
768
769 return Return;
770 }