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