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