]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/BdsDxe/BootMaint/ConsoleOption.c
635dc34173c04033108293865ce0971c98478bbc
[mirror_edk2.git] / MdeModulePkg / Universal / BdsDxe / BootMaint / ConsoleOption.c
1 /** @file
2 handles console redirection from boot manager
3
4 Copyright (c) 2004 - 2008, Intel Corporation. <BR>
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "BootMaint.h"
16
17 /**
18 Function creates a device path data structure that identically matches the
19 device path passed in.
20
21
22 @param DevPath A pointer to a device path data structure.
23
24 @return The new copy of DevPath is created to identically match the input.
25 @retval NULL Otherwise, NULL is returned.
26
27 **/
28 EFI_DEVICE_PATH_PROTOCOL *
29 DevicePathInstanceDup (
30 IN EFI_DEVICE_PATH_PROTOCOL *DevPath
31 );
32
33 /**
34 Update Com Ports attributes from DevicePath
35
36
37 @param DevicePath DevicePath that contains Com ports
38
39 @retval EFI_SUCCESS The update is successful.
40
41 **/
42 EFI_STATUS
43 UpdateComAttributeFromVariable (
44 EFI_DEVICE_PATH_PROTOCOL *DevicePath
45 );
46
47 /**
48 Update the multi-instance device path of Terminal Device based on
49 the global TerminalMenu. If ChangeTernimal is TRUE, the terminal
50 device path in the Terminal Device in TerminalMenu is also updated.
51
52 @param DevicePath The multi-instance device path.
53 @param ChangeTerminal TRUE, then device path in the Terminal Device
54 in TerminalMenu is also updated; FALSE, no update.
55
56 @return EFI_SUCCESS The function completes successfully.
57
58 **/
59 EFI_STATUS
60 ChangeTerminalDevicePath (
61 IN OUT EFI_DEVICE_PATH_PROTOCOL *DevicePath,
62 IN BOOLEAN ChangeTerminal
63 )
64 {
65 EFI_DEVICE_PATH_PROTOCOL *Node;
66 EFI_DEVICE_PATH_PROTOCOL *Node1;
67 ACPI_HID_DEVICE_PATH *Acpi;
68 UART_DEVICE_PATH *Uart;
69 UART_DEVICE_PATH *Uart1;
70 UINTN Com;
71 UINT32 Match;
72 BM_TERMINAL_CONTEXT *NewTerminalContext;
73 BM_MENU_ENTRY *NewMenuEntry;
74
75 Match = EISA_PNP_ID (0x0501);
76 Node = DevicePath;
77 Node = NextDevicePathNode (Node);
78 Com = 0;
79 while (!IsDevicePathEnd (Node)) {
80 if ((DevicePathType (Node) == ACPI_DEVICE_PATH) && (DevicePathSubType (Node) == ACPI_DP)) {
81 Acpi = (ACPI_HID_DEVICE_PATH *) Node;
82 if (CompareMem (&Acpi->HID, &Match, sizeof (UINT32)) == 0) {
83 CopyMem (&Com, &Acpi->UID, sizeof (UINT32));
84 }
85 }
86
87 NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Com);
88
89 NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
90 if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) {
91 Uart = (UART_DEVICE_PATH *) Node;
92 CopyMem (
93 &Uart->BaudRate,
94 &NewTerminalContext->BaudRate,
95 sizeof (UINT64)
96 );
97
98 CopyMem (
99 &Uart->DataBits,
100 &NewTerminalContext->DataBits,
101 sizeof (UINT8)
102 );
103
104 CopyMem (
105 &Uart->Parity,
106 &NewTerminalContext->Parity,
107 sizeof (UINT8)
108 );
109
110 CopyMem (
111 &Uart->StopBits,
112 &NewTerminalContext->StopBits,
113 sizeof (UINT8)
114 );
115 //
116 // Change the device path in the ComPort
117 //
118 if (ChangeTerminal) {
119 Node1 = NewTerminalContext->DevicePath;
120 Node1 = NextDevicePathNode (Node1);
121 while (!IsDevicePathEnd (Node1)) {
122 if ((DevicePathType (Node1) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node1) == MSG_UART_DP)) {
123 Uart1 = (UART_DEVICE_PATH *) Node1;
124 CopyMem (
125 &Uart1->BaudRate,
126 &NewTerminalContext->BaudRate,
127 sizeof (UINT64)
128 );
129
130 CopyMem (
131 &Uart1->DataBits,
132 &NewTerminalContext->DataBits,
133 sizeof (UINT8)
134 );
135
136 CopyMem (
137 &Uart1->Parity,
138 &NewTerminalContext->Parity,
139 sizeof (UINT8)
140 );
141
142 CopyMem (
143 &Uart1->StopBits,
144 &NewTerminalContext->StopBits,
145 sizeof (UINT8)
146 );
147 break;
148 }
149 //
150 // end if
151 //
152 Node1 = NextDevicePathNode (Node1);
153 }
154 //
155 // end while
156 //
157 break;
158 }
159 }
160
161 Node = NextDevicePathNode (Node);
162 }
163
164 return EFI_SUCCESS;
165
166 }
167
168 /**
169 Update the device path that describing a terminal device
170 based on the new BaudRate, Data Bits, parity and Stop Bits
171 set.
172
173 @param DevicePath terminal device's path
174
175 **/
176 VOID
177 ChangeVariableDevicePath (
178 IN OUT EFI_DEVICE_PATH_PROTOCOL *DevicePath
179 )
180 {
181 EFI_DEVICE_PATH_PROTOCOL *Node;
182 ACPI_HID_DEVICE_PATH *Acpi;
183 UART_DEVICE_PATH *Uart;
184 UINTN Com;
185 UINT32 Match;
186 BM_TERMINAL_CONTEXT *NewTerminalContext;
187 BM_MENU_ENTRY *NewMenuEntry;
188
189 Match = EISA_PNP_ID (0x0501);
190 Node = DevicePath;
191 Node = NextDevicePathNode (Node);
192 Com = 0;
193 while (!IsDevicePathEnd (Node)) {
194 if ((DevicePathType (Node) == ACPI_DEVICE_PATH) && (DevicePathSubType (Node) == ACPI_DP)) {
195 Acpi = (ACPI_HID_DEVICE_PATH *) Node;
196 if (CompareMem (&Acpi->HID, &Match, sizeof (UINT32)) == 0) {
197 CopyMem (&Com, &Acpi->UID, sizeof (UINT32));
198 }
199 }
200
201 if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) {
202 NewMenuEntry = BOpt_GetMenuEntry (
203 &TerminalMenu,
204 Com
205 );
206 ASSERT (NewMenuEntry != NULL);
207 NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
208 Uart = (UART_DEVICE_PATH *) Node;
209 CopyMem (
210 &Uart->BaudRate,
211 &NewTerminalContext->BaudRate,
212 sizeof (UINT64)
213 );
214
215 CopyMem (
216 &Uart->DataBits,
217 &NewTerminalContext->DataBits,
218 sizeof (UINT8)
219 );
220
221 CopyMem (
222 &Uart->Parity,
223 &NewTerminalContext->Parity,
224 sizeof (UINT8)
225 );
226
227 CopyMem (
228 &Uart->StopBits,
229 &NewTerminalContext->StopBits,
230 sizeof (UINT8)
231 );
232 }
233
234 Node = NextDevicePathNode (Node);
235 }
236 }
237
238 /**
239 Retrieve ACPI UID of UART from device path
240
241 @param Handle The handle for the UART device.
242 @param AcpiUid The ACPI UID on output.
243
244 @retval TRUE Find valid UID from device path
245 @retval FALSE Can't find
246
247 **/
248 BOOLEAN
249 RetrieveUartUid (
250 IN EFI_HANDLE Handle,
251 IN OUT UINT32 *AcpiUid
252 )
253 {
254 UINT32 Match;
255 UINT8 *Ptr;
256 ACPI_HID_DEVICE_PATH *Acpi;
257 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
258
259 gBS->HandleProtocol (
260 Handle,
261 &gEfiDevicePathProtocolGuid,
262 (VOID **) &DevicePath
263 );
264 Ptr = (UINT8 *) DevicePath;
265
266 while (*Ptr != END_DEVICE_PATH_TYPE) {
267 Ptr++;
268 }
269
270 Ptr = Ptr - sizeof (UART_DEVICE_PATH) - sizeof (ACPI_HID_DEVICE_PATH);
271 Acpi = (ACPI_HID_DEVICE_PATH *) Ptr;
272 Match = EISA_PNP_ID (0x0501);
273
274 if (CompareMem (&Acpi->HID, &Match, sizeof (UINT32)) == 0) {
275 if (AcpiUid != NULL) {
276 *AcpiUid = Acpi->UID;
277 }
278 return TRUE;
279 } else {
280 return FALSE;
281 }
282 }
283
284 /**
285 Sort Uart handles array with Acpi->UID from low to high.
286
287 @param Handles EFI_SERIAL_IO_PROTOCOL handle buffer
288 @param NoHandles EFI_SERIAL_IO_PROTOCOL handle count
289 **/
290 VOID
291 SortedUartHandle (
292 IN EFI_HANDLE *Handles,
293 IN UINTN NoHandles
294 )
295 {
296 UINTN Index1;
297 UINTN Index2;
298 UINTN Position;
299 UINT32 AcpiUid1;
300 UINT32 AcpiUid2;
301 UINT32 TempAcpiUid;
302 EFI_HANDLE TempHandle;
303
304 for (Index1 = 0; Index1 < NoHandles-1; Index1++) {
305 if (!RetrieveUartUid (Handles[Index1], &AcpiUid1)) {
306 continue;
307 }
308 TempHandle = Handles[Index1];
309 Position = Index1;
310 TempAcpiUid = AcpiUid1;
311
312 for (Index2 = Index1+1; Index2 < NoHandles; Index2++) {
313 if (!RetrieveUartUid (Handles[Index2], &AcpiUid2)) {
314 continue;
315 }
316 if (AcpiUid2 < TempAcpiUid) {
317 TempAcpiUid = AcpiUid2;
318 TempHandle = Handles[Index2];
319 Position = Index2;
320 }
321 }
322 Handles[Position] = Handles[Index1];
323 Handles[Index1] = TempHandle;
324 }
325 }
326
327 /**
328 Test whether DevicePath is a valid Terminal
329
330
331 @param DevicePath DevicePath to be checked
332 @param Termi If DevicePath is valid Terminal, terminal type is returned.
333 @param Com If DevicePath is valid Terminal, Com Port type is returned.
334
335 @retval TRUE If DevicePath point to a Terminal.
336 @retval FALSE If DevicePath does not point to a Terminal.
337
338 **/
339 BOOLEAN
340 IsTerminalDevicePath (
341 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
342 OUT TYPE_OF_TERMINAL *Termi,
343 OUT UINTN *Com
344 );
345
346 /**
347 Build a list containing all serial devices.
348
349
350 @retval EFI_SUCCESS The function complete successfully.
351 @retval EFI_UNSUPPORTED No serial ports present.
352
353 **/
354 EFI_STATUS
355 LocateSerialIo (
356 VOID
357 )
358 {
359 UINT8 *Ptr;
360 UINTN Index;
361 UINTN Index2;
362 UINTN NoHandles;
363 EFI_HANDLE *Handles;
364 EFI_STATUS Status;
365 ACPI_HID_DEVICE_PATH *Acpi;
366 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
367 UINT32 Match;
368 EFI_SERIAL_IO_PROTOCOL *SerialIo;
369 EFI_DEVICE_PATH_PROTOCOL *OutDevicePath;
370 EFI_DEVICE_PATH_PROTOCOL *InpDevicePath;
371 EFI_DEVICE_PATH_PROTOCOL *ErrDevicePath;
372 BM_MENU_ENTRY *NewMenuEntry;
373 BM_TERMINAL_CONTEXT *NewTerminalContext;
374 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
375 VENDOR_DEVICE_PATH Vendor;
376 //
377 // Get all handles that have SerialIo protocol installed
378 //
379 InitializeListHead (&TerminalMenu.Head);
380 TerminalMenu.MenuNumber = 0;
381 Status = gBS->LocateHandleBuffer (
382 ByProtocol,
383 &gEfiSerialIoProtocolGuid,
384 NULL,
385 &NoHandles,
386 &Handles
387 );
388 if (EFI_ERROR (Status)) {
389 //
390 // No serial ports present
391 //
392 return EFI_UNSUPPORTED;
393 }
394
395 //
396 // Sort Uart handles array with Acpi->UID from low to high
397 // then Terminal menu can be built from low Acpi->UID to high Acpi->UID
398 //
399 SortedUartHandle (Handles, NoHandles);
400
401 for (Index = 0; Index < NoHandles; Index++) {
402 //
403 // Check to see whether the handle has DevicePath Protocol installed
404 //
405 gBS->HandleProtocol (
406 Handles[Index],
407 &gEfiDevicePathProtocolGuid,
408 (VOID **) &DevicePath
409 );
410 Ptr = (UINT8 *) DevicePath;
411 while (*Ptr != END_DEVICE_PATH_TYPE) {
412 Ptr++;
413 }
414
415 Ptr = Ptr - sizeof (UART_DEVICE_PATH) - sizeof (ACPI_HID_DEVICE_PATH);
416 Acpi = (ACPI_HID_DEVICE_PATH *) Ptr;
417 Match = EISA_PNP_ID (0x0501);
418
419 if (CompareMem (&Acpi->HID, &Match, sizeof (UINT32)) == 0) {
420 NewMenuEntry = BOpt_CreateMenuEntry (BM_TERMINAL_CONTEXT_SELECT);
421 if (NewMenuEntry == NULL) {
422 SafeFreePool (Handles);
423 return EFI_OUT_OF_RESOURCES;
424 }
425
426 NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
427 CopyMem (&NewMenuEntry->OptionNumber, &Acpi->UID, sizeof (UINT32));
428 NewTerminalContext->DevicePath = DevicePathInstanceDup (DevicePath);
429 //
430 // BugBug: I have no choice, calling EfiLibStrFromDatahub will hang the system!
431 // coz' the misc data for each platform is not correct, actually it's the device path stored in
432 // datahub which is not completed, so a searching for end of device path will enter a
433 // dead-loop.
434 //
435 NewMenuEntry->DisplayString = EfiLibStrFromDatahub (DevicePath);
436 if (NULL == NewMenuEntry->DisplayString) {
437 NewMenuEntry->DisplayString = DevicePathToStr (DevicePath);
438 }
439
440 NewMenuEntry->HelpString = NULL;
441
442 gBS->HandleProtocol (
443 Handles[Index],
444 &gEfiSerialIoProtocolGuid,
445 (VOID **) &SerialIo
446 );
447
448 CopyMem (
449 &NewTerminalContext->BaudRate,
450 &SerialIo->Mode->BaudRate,
451 sizeof (UINT64)
452 );
453
454 CopyMem (
455 &NewTerminalContext->DataBits,
456 &SerialIo->Mode->DataBits,
457 sizeof (UINT8)
458 );
459
460 CopyMem (
461 &NewTerminalContext->Parity,
462 &SerialIo->Mode->Parity,
463 sizeof (UINT8)
464 );
465
466 CopyMem (
467 &NewTerminalContext->StopBits,
468 &SerialIo->Mode->StopBits,
469 sizeof (UINT8)
470 );
471 InsertTailList (&TerminalMenu.Head, &NewMenuEntry->Link);
472 TerminalMenu.MenuNumber++;
473 }
474 }
475 SafeFreePool (Handles);
476
477 //
478 // Get L"ConOut", L"ConIn" and L"ErrOut" from the Var
479 //
480 OutDevicePath = EfiLibGetVariable (L"ConOut", &gEfiGlobalVariableGuid);
481 InpDevicePath = EfiLibGetVariable (L"ConIn", &gEfiGlobalVariableGuid);
482 ErrDevicePath = EfiLibGetVariable (L"ErrOut", &gEfiGlobalVariableGuid);
483 if (OutDevicePath != NULL) {
484 UpdateComAttributeFromVariable (OutDevicePath);
485 }
486
487 if (InpDevicePath != NULL) {
488 UpdateComAttributeFromVariable (InpDevicePath);
489 }
490
491 if (ErrDevicePath != NULL) {
492 UpdateComAttributeFromVariable (ErrDevicePath);
493 }
494
495 for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
496 NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index);
497 if (NULL == NewMenuEntry) {
498 return EFI_NOT_FOUND;
499 }
500
501 NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
502
503 NewTerminalContext->TerminalType = 0;
504 NewTerminalContext->IsConIn = FALSE;
505 NewTerminalContext->IsConOut = FALSE;
506 NewTerminalContext->IsStdErr = FALSE;
507
508 Vendor.Header.Type = MESSAGING_DEVICE_PATH;
509 Vendor.Header.SubType = MSG_VENDOR_DP;
510
511 for (Index2 = 0; Index2 < 4; Index2++) {
512 CopyMem (&Vendor.Guid, &TerminalTypeGuid[Index2], sizeof (EFI_GUID));
513 SetDevicePathNodeLength (&Vendor.Header, sizeof (VENDOR_DEVICE_PATH));
514 NewDevicePath = AppendDevicePathNode (
515 NewTerminalContext->DevicePath,
516 (EFI_DEVICE_PATH_PROTOCOL *) &Vendor
517 );
518 SafeFreePool (NewMenuEntry->HelpString);
519 //
520 // NewMenuEntry->HelpString = DevicePathToStr (NewDevicePath);
521 // NewMenuEntry->DisplayString = NewMenuEntry->HelpString;
522 //
523 NewMenuEntry->HelpString = NULL;
524
525 if (BdsLibMatchDevicePaths (OutDevicePath, NewDevicePath)) {
526 NewTerminalContext->IsConOut = TRUE;
527 NewTerminalContext->TerminalType = (UINT8) Index2;
528 }
529
530 if (BdsLibMatchDevicePaths (InpDevicePath, NewDevicePath)) {
531 NewTerminalContext->IsConIn = TRUE;
532 NewTerminalContext->TerminalType = (UINT8) Index2;
533 }
534
535 if (BdsLibMatchDevicePaths (ErrDevicePath, NewDevicePath)) {
536 NewTerminalContext->IsStdErr = TRUE;
537 NewTerminalContext->TerminalType = (UINT8) Index2;
538 }
539 }
540 }
541
542 return EFI_SUCCESS;
543 }
544
545 /**
546 Update Com Ports attributes from DevicePath
547
548
549 @param DevicePath DevicePath that contains Com ports
550
551 @retval EFI_SUCCESS The update is successful.
552 @retval EFI_NOT_FOUND Can not find specific menu entry
553 **/
554 EFI_STATUS
555 UpdateComAttributeFromVariable (
556 EFI_DEVICE_PATH_PROTOCOL *DevicePath
557 )
558 {
559 EFI_DEVICE_PATH_PROTOCOL *Node;
560 EFI_DEVICE_PATH_PROTOCOL *SerialNode;
561 ACPI_HID_DEVICE_PATH *Acpi;
562 UART_DEVICE_PATH *Uart;
563 UART_DEVICE_PATH *Uart1;
564 UINT32 Match;
565 UINTN TerminalNumber;
566 BM_MENU_ENTRY *NewMenuEntry;
567 BM_TERMINAL_CONTEXT *NewTerminalContext;
568 UINTN Index;
569
570 Match = EISA_PNP_ID (0x0501);
571 Node = DevicePath;
572 Node = NextDevicePathNode (Node);
573 TerminalNumber = 0;
574 for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
575 while (!IsDevicePathEnd (Node)) {
576 if ((DevicePathType (Node) == ACPI_DEVICE_PATH) && (DevicePathSubType (Node) == ACPI_DP)) {
577 Acpi = (ACPI_HID_DEVICE_PATH *) Node;
578 if (CompareMem (&Acpi->HID, &Match, sizeof (UINT32)) == 0) {
579 CopyMem (&TerminalNumber, &Acpi->UID, sizeof (UINT32));
580 }
581 }
582
583 if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) {
584 Uart = (UART_DEVICE_PATH *) Node;
585 NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, TerminalNumber);
586 if (NULL == NewMenuEntry) {
587 return EFI_NOT_FOUND;
588 }
589
590 NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
591 CopyMem (
592 &NewTerminalContext->BaudRate,
593 &Uart->BaudRate,
594 sizeof (UINT64)
595 );
596
597 CopyMem (
598 &NewTerminalContext->DataBits,
599 &Uart->DataBits,
600 sizeof (UINT8)
601 );
602
603 CopyMem (
604 &NewTerminalContext->Parity,
605 &Uart->Parity,
606 sizeof (UINT8)
607 );
608
609 CopyMem (
610 &NewTerminalContext->StopBits,
611 &Uart->StopBits,
612 sizeof (UINT8)
613 );
614
615 SerialNode = NewTerminalContext->DevicePath;
616 SerialNode = NextDevicePathNode (SerialNode);
617 while (!IsDevicePathEnd (SerialNode)) {
618 if ((DevicePathType (SerialNode) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (SerialNode) == MSG_UART_DP)) {
619 //
620 // Update following device paths according to
621 // previous acquired uart attributes
622 //
623 Uart1 = (UART_DEVICE_PATH *) SerialNode;
624 CopyMem (
625 &Uart1->BaudRate,
626 &NewTerminalContext->BaudRate,
627 sizeof (UINT64)
628 );
629
630 CopyMem (
631 &Uart1->DataBits,
632 &NewTerminalContext->DataBits,
633 sizeof (UINT8)
634 );
635 CopyMem (
636 &Uart1->Parity,
637 &NewTerminalContext->Parity,
638 sizeof (UINT8)
639 );
640 CopyMem (
641 &Uart1->StopBits,
642 &NewTerminalContext->StopBits,
643 sizeof (UINT8)
644 );
645
646 break;
647 }
648
649 SerialNode = NextDevicePathNode (SerialNode);
650 }
651 //
652 // end while
653 //
654 }
655
656 Node = NextDevicePathNode (Node);
657 }
658 //
659 // end while
660 //
661 }
662
663 return EFI_SUCCESS;
664 }
665
666 /**
667 Function creates a device path data structure that identically matches the
668 device path passed in.
669
670
671 @param DevPath A pointer to a device path data structure.
672
673 @return The new copy of DevPath is created to identically match the input.
674 @retval NULL Otherwise, NULL is returned.
675
676 **/
677 EFI_DEVICE_PATH_PROTOCOL *
678 DevicePathInstanceDup (
679 IN EFI_DEVICE_PATH_PROTOCOL *DevPath
680 )
681 {
682 EFI_DEVICE_PATH_PROTOCOL *NewDevPath;
683 EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;
684 EFI_DEVICE_PATH_PROTOCOL *Temp;
685 UINT8 *Ptr;
686 UINTN Size;
687
688 //
689 // get the size of an instance from the input
690 //
691 Temp = DevPath;
692 DevicePathInst = GetNextDevicePathInstance (&Temp, &Size);
693
694 //
695 // Make a copy and set proper end type
696 //
697 NewDevPath = NULL;
698 if (Size != 0) {
699 NewDevPath = AllocateZeroPool (Size);
700 ASSERT (NewDevPath != NULL);
701 }
702
703 if (NewDevPath != NULL) {
704 CopyMem (NewDevPath, DevicePathInst, Size);
705 Ptr = (UINT8 *) NewDevPath;
706 Ptr += Size - sizeof (EFI_DEVICE_PATH_PROTOCOL);
707 Temp = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
708 SetDevicePathEndNode (Temp);
709 }
710
711 return NewDevPath;
712 }
713
714 /**
715 Build up Console Menu based on types passed in. The type can
716 be BM_CONSOLE_IN_CONTEXT_SELECT, BM_CONSOLE_OUT_CONTEXT_SELECT
717 and BM_CONSOLE_ERR_CONTEXT_SELECT.
718
719 @param ConsoleMenuType Can be BM_CONSOLE_IN_CONTEXT_SELECT, BM_CONSOLE_OUT_CONTEXT_SELECT
720 and BM_CONSOLE_ERR_CONTEXT_SELECT.
721
722 @retval EFI_UNSUPPORTED The type passed in is not in the 3 types defined.
723 @retval EFI_NOT_FOUND If the EFI Variable defined in UEFI spec with name "ConOutDev",
724 "ConInDev" or "ConErrDev" doesn't exists.
725 @retval EFI_OUT_OF_RESOURCES Not enough resource to complete the operations.
726 @retval EFI_SUCCESS Function completes successfully.
727
728 **/
729 EFI_STATUS
730 GetConsoleMenu (
731 IN UINTN ConsoleMenuType
732 )
733 {
734 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
735 EFI_DEVICE_PATH_PROTOCOL *AllDevicePath;
736 EFI_DEVICE_PATH_PROTOCOL *MultiDevicePath;
737 EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;
738 UINTN Size;
739 UINTN AllCount;
740 UINTN Index;
741 UINTN Index2;
742 BM_MENU_ENTRY *NewMenuEntry;
743 BM_CONSOLE_CONTEXT *NewConsoleContext;
744 TYPE_OF_TERMINAL Terminal;
745 UINTN Com;
746 BM_MENU_OPTION *ConsoleMenu;
747
748 DevicePath = NULL;
749 AllDevicePath = NULL;
750 AllCount = 0;
751 switch (ConsoleMenuType) {
752 case BM_CONSOLE_IN_CONTEXT_SELECT:
753 ConsoleMenu = &ConsoleInpMenu;
754 DevicePath = EfiLibGetVariable (
755 L"ConIn",
756 &gEfiGlobalVariableGuid
757 );
758
759 AllDevicePath = EfiLibGetVariable (
760 L"ConInDev",
761 &gEfiGlobalVariableGuid
762 );
763 break;
764
765 case BM_CONSOLE_OUT_CONTEXT_SELECT:
766 ConsoleMenu = &ConsoleOutMenu;
767 DevicePath = EfiLibGetVariable (
768 L"ConOut",
769 &gEfiGlobalVariableGuid
770 );
771
772 AllDevicePath = EfiLibGetVariable (
773 L"ConOutDev",
774 &gEfiGlobalVariableGuid
775 );
776 break;
777
778 case BM_CONSOLE_ERR_CONTEXT_SELECT:
779 ConsoleMenu = &ConsoleErrMenu;
780 DevicePath = EfiLibGetVariable (
781 L"ErrOut",
782 &gEfiGlobalVariableGuid
783 );
784
785 AllDevicePath = EfiLibGetVariable (
786 L"ErrOutDev",
787 &gEfiGlobalVariableGuid
788 );
789 break;
790
791 default:
792 return EFI_UNSUPPORTED;
793 }
794
795 if (NULL == AllDevicePath) {
796 return EFI_NOT_FOUND;
797 }
798
799 InitializeListHead (&ConsoleMenu->Head);
800
801 AllCount = EfiDevicePathInstanceCount (AllDevicePath);
802 ConsoleMenu->MenuNumber = 0;
803 //
804 // Following is menu building up for Console Devices selected.
805 //
806 MultiDevicePath = AllDevicePath;
807 Index2 = 0;
808 for (Index = 0; Index < AllCount; Index++) {
809 DevicePathInst = GetNextDevicePathInstance (&MultiDevicePath, &Size);
810
811 NewMenuEntry = BOpt_CreateMenuEntry (BM_CONSOLE_CONTEXT_SELECT);
812 if (NULL == NewMenuEntry) {
813 return EFI_OUT_OF_RESOURCES;
814 }
815
816 NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext;
817 NewMenuEntry->OptionNumber = Index2;
818
819 NewConsoleContext->DevicePath = DevicePathInstanceDup (DevicePathInst);
820 NewMenuEntry->DisplayString = EfiLibStrFromDatahub (NewConsoleContext->DevicePath);
821 if (NULL == NewMenuEntry->DisplayString) {
822 NewMenuEntry->DisplayString = DevicePathToStr (NewConsoleContext->DevicePath);
823 }
824
825 NewConsoleContext->IsTerminal = IsTerminalDevicePath (
826 NewConsoleContext->DevicePath,
827 &Terminal,
828 &Com
829 );
830
831 NewConsoleContext->IsActive = BdsLibMatchDevicePaths (
832 DevicePath,
833 NewConsoleContext->DevicePath
834 );
835
836 if (NewConsoleContext->IsTerminal) {
837 BOpt_DestroyMenuEntry (NewMenuEntry);
838 } else {
839 Index2++;
840 ConsoleMenu->MenuNumber++;
841 InsertTailList (&ConsoleMenu->Head, &NewMenuEntry->Link);
842 }
843 }
844
845 return EFI_SUCCESS;
846 }
847
848 /**
849 Build up ConsoleOutMenu, ConsoleInpMenu and ConsoleErrMenu
850
851 @retval EFI_SUCCESS The function always complete successfully.
852
853 **/
854 EFI_STATUS
855 GetAllConsoles (
856 VOID
857 )
858 {
859 GetConsoleMenu (BM_CONSOLE_IN_CONTEXT_SELECT);
860 GetConsoleMenu (BM_CONSOLE_OUT_CONTEXT_SELECT);
861 GetConsoleMenu (BM_CONSOLE_ERR_CONTEXT_SELECT);
862 return EFI_SUCCESS;
863 }
864
865 /**
866 Free ConsoleOutMenu, ConsoleInpMenu and ConsoleErrMenu
867
868 @retval EFI_SUCCESS The function always complete successfully.
869 **/
870 EFI_STATUS
871 FreeAllConsoles (
872 VOID
873 )
874 {
875 BOpt_FreeMenu (&ConsoleOutMenu);
876 BOpt_FreeMenu (&ConsoleInpMenu);
877 BOpt_FreeMenu (&ConsoleErrMenu);
878 BOpt_FreeMenu (&TerminalMenu);
879 return EFI_SUCCESS;
880 }
881
882 /**
883 Test whether DevicePath is a valid Terminal
884
885
886 @param DevicePath DevicePath to be checked
887 @param Termi If DevicePath is valid Terminal, terminal type is returned.
888 @param Com If DevicePath is valid Terminal, Com Port type is returned.
889
890 @retval TRUE If DevicePath point to a Terminal.
891 @retval FALSE If DevicePath does not point to a Terminal.
892
893 **/
894 BOOLEAN
895 IsTerminalDevicePath (
896 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
897 OUT TYPE_OF_TERMINAL *Termi,
898 OUT UINTN *Com
899 )
900 {
901 UINT8 *Ptr;
902 BOOLEAN IsTerminal;
903 VENDOR_DEVICE_PATH *Vendor;
904 ACPI_HID_DEVICE_PATH *Acpi;
905 UINT32 Match;
906 EFI_GUID TempGuid;
907
908 IsTerminal = FALSE;
909
910 //
911 // Parse the Device Path, should be change later!!!
912 //
913 Ptr = (UINT8 *) DevicePath;
914 while (*Ptr != END_DEVICE_PATH_TYPE) {
915 Ptr++;
916 }
917
918 Ptr = Ptr - sizeof (VENDOR_DEVICE_PATH);
919 Vendor = (VENDOR_DEVICE_PATH *) Ptr;
920
921 //
922 // There are four kinds of Terminal types
923 // check to see whether this devicepath
924 // is one of that type
925 //
926 CopyMem (&TempGuid, &Vendor->Guid, sizeof (EFI_GUID));
927
928 if (CompareGuid (&TempGuid, &TerminalTypeGuid[0])) {
929 *Termi = PC_ANSI;
930 IsTerminal = TRUE;
931 } else {
932 if (CompareGuid (&TempGuid, &TerminalTypeGuid[1])) {
933 *Termi = VT_100;
934 IsTerminal = TRUE;
935 } else {
936 if (CompareGuid (&TempGuid, &TerminalTypeGuid[2])) {
937 *Termi = VT_100_PLUS;
938 IsTerminal = TRUE;
939 } else {
940 if (CompareGuid (&TempGuid, &TerminalTypeGuid[3])) {
941 *Termi = VT_UTF8;
942 IsTerminal = TRUE;
943 } else {
944 IsTerminal = FALSE;
945 }
946 }
947 }
948 }
949
950 if (!IsTerminal) {
951 return FALSE;
952 }
953
954 Ptr = Ptr - sizeof (UART_DEVICE_PATH) - sizeof (ACPI_HID_DEVICE_PATH);
955 Acpi = (ACPI_HID_DEVICE_PATH *) Ptr;
956 Match = EISA_PNP_ID (0x0501);
957 if (CompareMem (&Acpi->HID, &Match, sizeof (UINT32)) == 0) {
958 CopyMem (Com, &Acpi->UID, sizeof (UINT32));
959 } else {
960 return FALSE;
961 }
962
963 return TRUE;
964 }
965
966 /**
967 Get mode number according to column and row
968
969 @param CallbackData The BMM context data.
970 **/
971 VOID
972 GetConsoleOutMode (
973 IN BMM_CALLBACK_DATA *CallbackData
974 )
975 {
976 UINTN Col;
977 UINTN Row;
978 UINTN CurrentCol;
979 UINTN CurrentRow;
980 UINTN Mode;
981 UINTN MaxMode;
982 EFI_STATUS Status;
983 CONSOLE_OUT_MODE *ModeInfo;
984 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
985
986 ConOut = gST->ConOut;
987 MaxMode = (UINTN) (ConOut->Mode->MaxMode);
988 ModeInfo = EfiLibGetVariable (VAR_CON_OUT_MODE, &gEfiGenericPlatformVariableGuid);
989
990 if (ModeInfo != NULL) {
991 CurrentCol = ModeInfo->Column;
992 CurrentRow = ModeInfo->Row;
993 for (Mode = 0; Mode < MaxMode; Mode++) {
994 Status = ConOut->QueryMode (ConOut, Mode, &Col, &Row);
995 if (!EFI_ERROR(Status)) {
996 if (CurrentCol == Col && CurrentRow == Row) {
997 CallbackData->BmmFakeNvData.ConsoleOutMode = (UINT16) Mode;
998 break;
999 }
1000 }
1001 }
1002 }
1003 SafeFreePool (ModeInfo);
1004 }