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