]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/BdsDxe/BootMaint/ConsoleOption.c
Remove SafeFreePool from MemoryAllocationLib as this API's name is misleading. Its...
[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 FreePool (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 if (Handles != NULL) {
476 FreePool (Handles);
477 }
478
479 //
480 // Get L"ConOut", L"ConIn" and L"ErrOut" from the Var
481 //
482 OutDevicePath = EfiLibGetVariable (L"ConOut", &gEfiGlobalVariableGuid);
483 InpDevicePath = EfiLibGetVariable (L"ConIn", &gEfiGlobalVariableGuid);
484 ErrDevicePath = EfiLibGetVariable (L"ErrOut", &gEfiGlobalVariableGuid);
485 if (OutDevicePath != NULL) {
486 UpdateComAttributeFromVariable (OutDevicePath);
487 }
488
489 if (InpDevicePath != NULL) {
490 UpdateComAttributeFromVariable (InpDevicePath);
491 }
492
493 if (ErrDevicePath != NULL) {
494 UpdateComAttributeFromVariable (ErrDevicePath);
495 }
496
497 for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
498 NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index);
499 if (NULL == NewMenuEntry) {
500 return EFI_NOT_FOUND;
501 }
502
503 NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
504
505 NewTerminalContext->TerminalType = 0;
506 NewTerminalContext->IsConIn = FALSE;
507 NewTerminalContext->IsConOut = FALSE;
508 NewTerminalContext->IsStdErr = FALSE;
509
510 Vendor.Header.Type = MESSAGING_DEVICE_PATH;
511 Vendor.Header.SubType = MSG_VENDOR_DP;
512
513 for (Index2 = 0; Index2 < 4; Index2++) {
514 CopyMem (&Vendor.Guid, &TerminalTypeGuid[Index2], sizeof (EFI_GUID));
515 SetDevicePathNodeLength (&Vendor.Header, sizeof (VENDOR_DEVICE_PATH));
516 NewDevicePath = AppendDevicePathNode (
517 NewTerminalContext->DevicePath,
518 (EFI_DEVICE_PATH_PROTOCOL *) &Vendor
519 );
520 if (NewMenuEntry->HelpString != NULL) {
521 FreePool (NewMenuEntry->HelpString);
522 }
523 //
524 // NewMenuEntry->HelpString = DevicePathToStr (NewDevicePath);
525 // NewMenuEntry->DisplayString = NewMenuEntry->HelpString;
526 //
527 NewMenuEntry->HelpString = NULL;
528
529 if (BdsLibMatchDevicePaths (OutDevicePath, NewDevicePath)) {
530 NewTerminalContext->IsConOut = TRUE;
531 NewTerminalContext->TerminalType = (UINT8) Index2;
532 }
533
534 if (BdsLibMatchDevicePaths (InpDevicePath, NewDevicePath)) {
535 NewTerminalContext->IsConIn = TRUE;
536 NewTerminalContext->TerminalType = (UINT8) Index2;
537 }
538
539 if (BdsLibMatchDevicePaths (ErrDevicePath, NewDevicePath)) {
540 NewTerminalContext->IsStdErr = TRUE;
541 NewTerminalContext->TerminalType = (UINT8) Index2;
542 }
543 }
544 }
545
546 return EFI_SUCCESS;
547 }
548
549 /**
550 Update Com Ports attributes from DevicePath
551
552
553 @param DevicePath DevicePath that contains Com ports
554
555 @retval EFI_SUCCESS The update is successful.
556 @retval EFI_NOT_FOUND Can not find specific menu entry
557 **/
558 EFI_STATUS
559 UpdateComAttributeFromVariable (
560 EFI_DEVICE_PATH_PROTOCOL *DevicePath
561 )
562 {
563 EFI_DEVICE_PATH_PROTOCOL *Node;
564 EFI_DEVICE_PATH_PROTOCOL *SerialNode;
565 ACPI_HID_DEVICE_PATH *Acpi;
566 UART_DEVICE_PATH *Uart;
567 UART_DEVICE_PATH *Uart1;
568 UINT32 Match;
569 UINTN TerminalNumber;
570 BM_MENU_ENTRY *NewMenuEntry;
571 BM_TERMINAL_CONTEXT *NewTerminalContext;
572 UINTN Index;
573
574 Match = EISA_PNP_ID (0x0501);
575 Node = DevicePath;
576 Node = NextDevicePathNode (Node);
577 TerminalNumber = 0;
578 for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
579 while (!IsDevicePathEnd (Node)) {
580 if ((DevicePathType (Node) == ACPI_DEVICE_PATH) && (DevicePathSubType (Node) == ACPI_DP)) {
581 Acpi = (ACPI_HID_DEVICE_PATH *) Node;
582 if (CompareMem (&Acpi->HID, &Match, sizeof (UINT32)) == 0) {
583 CopyMem (&TerminalNumber, &Acpi->UID, sizeof (UINT32));
584 }
585 }
586
587 if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) {
588 Uart = (UART_DEVICE_PATH *) Node;
589 NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, TerminalNumber);
590 if (NULL == NewMenuEntry) {
591 return EFI_NOT_FOUND;
592 }
593
594 NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
595 CopyMem (
596 &NewTerminalContext->BaudRate,
597 &Uart->BaudRate,
598 sizeof (UINT64)
599 );
600
601 CopyMem (
602 &NewTerminalContext->DataBits,
603 &Uart->DataBits,
604 sizeof (UINT8)
605 );
606
607 CopyMem (
608 &NewTerminalContext->Parity,
609 &Uart->Parity,
610 sizeof (UINT8)
611 );
612
613 CopyMem (
614 &NewTerminalContext->StopBits,
615 &Uart->StopBits,
616 sizeof (UINT8)
617 );
618
619 SerialNode = NewTerminalContext->DevicePath;
620 SerialNode = NextDevicePathNode (SerialNode);
621 while (!IsDevicePathEnd (SerialNode)) {
622 if ((DevicePathType (SerialNode) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (SerialNode) == MSG_UART_DP)) {
623 //
624 // Update following device paths according to
625 // previous acquired uart attributes
626 //
627 Uart1 = (UART_DEVICE_PATH *) SerialNode;
628 CopyMem (
629 &Uart1->BaudRate,
630 &NewTerminalContext->BaudRate,
631 sizeof (UINT64)
632 );
633
634 CopyMem (
635 &Uart1->DataBits,
636 &NewTerminalContext->DataBits,
637 sizeof (UINT8)
638 );
639 CopyMem (
640 &Uart1->Parity,
641 &NewTerminalContext->Parity,
642 sizeof (UINT8)
643 );
644 CopyMem (
645 &Uart1->StopBits,
646 &NewTerminalContext->StopBits,
647 sizeof (UINT8)
648 );
649
650 break;
651 }
652
653 SerialNode = NextDevicePathNode (SerialNode);
654 }
655 //
656 // end while
657 //
658 }
659
660 Node = NextDevicePathNode (Node);
661 }
662 //
663 // end while
664 //
665 }
666
667 return EFI_SUCCESS;
668 }
669
670 /**
671 Function creates a device path data structure that identically matches the
672 device path passed in.
673
674
675 @param DevPath A pointer to a device path data structure.
676
677 @return The new copy of DevPath is created to identically match the input.
678 @retval NULL Otherwise, NULL is returned.
679
680 **/
681 EFI_DEVICE_PATH_PROTOCOL *
682 DevicePathInstanceDup (
683 IN EFI_DEVICE_PATH_PROTOCOL *DevPath
684 )
685 {
686 EFI_DEVICE_PATH_PROTOCOL *NewDevPath;
687 EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;
688 EFI_DEVICE_PATH_PROTOCOL *Temp;
689 UINT8 *Ptr;
690 UINTN Size;
691
692 //
693 // get the size of an instance from the input
694 //
695 Temp = DevPath;
696 DevicePathInst = GetNextDevicePathInstance (&Temp, &Size);
697
698 //
699 // Make a copy and set proper end type
700 //
701 NewDevPath = NULL;
702 if (Size != 0) {
703 NewDevPath = AllocateZeroPool (Size);
704 ASSERT (NewDevPath != NULL);
705 }
706
707 if (NewDevPath != NULL) {
708 CopyMem (NewDevPath, DevicePathInst, Size);
709 Ptr = (UINT8 *) NewDevPath;
710 Ptr += Size - sizeof (EFI_DEVICE_PATH_PROTOCOL);
711 Temp = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
712 SetDevicePathEndNode (Temp);
713 }
714
715 return NewDevPath;
716 }
717
718 /**
719 Build up Console Menu based on types passed in. The type can
720 be BM_CONSOLE_IN_CONTEXT_SELECT, BM_CONSOLE_OUT_CONTEXT_SELECT
721 and BM_CONSOLE_ERR_CONTEXT_SELECT.
722
723 @param ConsoleMenuType Can be BM_CONSOLE_IN_CONTEXT_SELECT, BM_CONSOLE_OUT_CONTEXT_SELECT
724 and BM_CONSOLE_ERR_CONTEXT_SELECT.
725
726 @retval EFI_UNSUPPORTED The type passed in is not in the 3 types defined.
727 @retval EFI_NOT_FOUND If the EFI Variable defined in UEFI spec with name "ConOutDev",
728 "ConInDev" or "ConErrDev" doesn't exists.
729 @retval EFI_OUT_OF_RESOURCES Not enough resource to complete the operations.
730 @retval EFI_SUCCESS Function completes successfully.
731
732 **/
733 EFI_STATUS
734 GetConsoleMenu (
735 IN UINTN ConsoleMenuType
736 )
737 {
738 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
739 EFI_DEVICE_PATH_PROTOCOL *AllDevicePath;
740 EFI_DEVICE_PATH_PROTOCOL *MultiDevicePath;
741 EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;
742 UINTN Size;
743 UINTN AllCount;
744 UINTN Index;
745 UINTN Index2;
746 BM_MENU_ENTRY *NewMenuEntry;
747 BM_CONSOLE_CONTEXT *NewConsoleContext;
748 TYPE_OF_TERMINAL Terminal;
749 UINTN Com;
750 BM_MENU_OPTION *ConsoleMenu;
751
752 DevicePath = NULL;
753 AllDevicePath = NULL;
754 AllCount = 0;
755 switch (ConsoleMenuType) {
756 case BM_CONSOLE_IN_CONTEXT_SELECT:
757 ConsoleMenu = &ConsoleInpMenu;
758 DevicePath = EfiLibGetVariable (
759 L"ConIn",
760 &gEfiGlobalVariableGuid
761 );
762
763 AllDevicePath = EfiLibGetVariable (
764 L"ConInDev",
765 &gEfiGlobalVariableGuid
766 );
767 break;
768
769 case BM_CONSOLE_OUT_CONTEXT_SELECT:
770 ConsoleMenu = &ConsoleOutMenu;
771 DevicePath = EfiLibGetVariable (
772 L"ConOut",
773 &gEfiGlobalVariableGuid
774 );
775
776 AllDevicePath = EfiLibGetVariable (
777 L"ConOutDev",
778 &gEfiGlobalVariableGuid
779 );
780 break;
781
782 case BM_CONSOLE_ERR_CONTEXT_SELECT:
783 ConsoleMenu = &ConsoleErrMenu;
784 DevicePath = EfiLibGetVariable (
785 L"ErrOut",
786 &gEfiGlobalVariableGuid
787 );
788
789 AllDevicePath = EfiLibGetVariable (
790 L"ErrOutDev",
791 &gEfiGlobalVariableGuid
792 );
793 break;
794
795 default:
796 return EFI_UNSUPPORTED;
797 }
798
799 if (NULL == AllDevicePath) {
800 return EFI_NOT_FOUND;
801 }
802
803 InitializeListHead (&ConsoleMenu->Head);
804
805 AllCount = EfiDevicePathInstanceCount (AllDevicePath);
806 ConsoleMenu->MenuNumber = 0;
807 //
808 // Following is menu building up for Console Devices selected.
809 //
810 MultiDevicePath = AllDevicePath;
811 Index2 = 0;
812 for (Index = 0; Index < AllCount; Index++) {
813 DevicePathInst = GetNextDevicePathInstance (&MultiDevicePath, &Size);
814
815 NewMenuEntry = BOpt_CreateMenuEntry (BM_CONSOLE_CONTEXT_SELECT);
816 if (NULL == NewMenuEntry) {
817 return EFI_OUT_OF_RESOURCES;
818 }
819
820 NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext;
821 NewMenuEntry->OptionNumber = Index2;
822
823 NewConsoleContext->DevicePath = DevicePathInstanceDup (DevicePathInst);
824 NewMenuEntry->DisplayString = EfiLibStrFromDatahub (NewConsoleContext->DevicePath);
825 if (NULL == NewMenuEntry->DisplayString) {
826 NewMenuEntry->DisplayString = DevicePathToStr (NewConsoleContext->DevicePath);
827 }
828
829 NewConsoleContext->IsTerminal = IsTerminalDevicePath (
830 NewConsoleContext->DevicePath,
831 &Terminal,
832 &Com
833 );
834
835 NewConsoleContext->IsActive = BdsLibMatchDevicePaths (
836 DevicePath,
837 NewConsoleContext->DevicePath
838 );
839
840 if (NewConsoleContext->IsTerminal) {
841 BOpt_DestroyMenuEntry (NewMenuEntry);
842 } else {
843 Index2++;
844 ConsoleMenu->MenuNumber++;
845 InsertTailList (&ConsoleMenu->Head, &NewMenuEntry->Link);
846 }
847 }
848
849 return EFI_SUCCESS;
850 }
851
852 /**
853 Build up ConsoleOutMenu, ConsoleInpMenu and ConsoleErrMenu
854
855 @retval EFI_SUCCESS The function always complete successfully.
856
857 **/
858 EFI_STATUS
859 GetAllConsoles (
860 VOID
861 )
862 {
863 GetConsoleMenu (BM_CONSOLE_IN_CONTEXT_SELECT);
864 GetConsoleMenu (BM_CONSOLE_OUT_CONTEXT_SELECT);
865 GetConsoleMenu (BM_CONSOLE_ERR_CONTEXT_SELECT);
866 return EFI_SUCCESS;
867 }
868
869 /**
870 Free ConsoleOutMenu, ConsoleInpMenu and ConsoleErrMenu
871
872 @retval EFI_SUCCESS The function always complete successfully.
873 **/
874 EFI_STATUS
875 FreeAllConsoles (
876 VOID
877 )
878 {
879 BOpt_FreeMenu (&ConsoleOutMenu);
880 BOpt_FreeMenu (&ConsoleInpMenu);
881 BOpt_FreeMenu (&ConsoleErrMenu);
882 BOpt_FreeMenu (&TerminalMenu);
883 return EFI_SUCCESS;
884 }
885
886 /**
887 Test whether DevicePath is a valid Terminal
888
889
890 @param DevicePath DevicePath to be checked
891 @param Termi If DevicePath is valid Terminal, terminal type is returned.
892 @param Com If DevicePath is valid Terminal, Com Port type is returned.
893
894 @retval TRUE If DevicePath point to a Terminal.
895 @retval FALSE If DevicePath does not point to a Terminal.
896
897 **/
898 BOOLEAN
899 IsTerminalDevicePath (
900 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
901 OUT TYPE_OF_TERMINAL *Termi,
902 OUT UINTN *Com
903 )
904 {
905 UINT8 *Ptr;
906 BOOLEAN IsTerminal;
907 VENDOR_DEVICE_PATH *Vendor;
908 ACPI_HID_DEVICE_PATH *Acpi;
909 UINT32 Match;
910 EFI_GUID TempGuid;
911
912 IsTerminal = FALSE;
913
914 //
915 // Parse the Device Path, should be change later!!!
916 //
917 Ptr = (UINT8 *) DevicePath;
918 while (*Ptr != END_DEVICE_PATH_TYPE) {
919 Ptr++;
920 }
921
922 Ptr = Ptr - sizeof (VENDOR_DEVICE_PATH);
923 Vendor = (VENDOR_DEVICE_PATH *) Ptr;
924
925 //
926 // There are four kinds of Terminal types
927 // check to see whether this devicepath
928 // is one of that type
929 //
930 CopyMem (&TempGuid, &Vendor->Guid, sizeof (EFI_GUID));
931
932 if (CompareGuid (&TempGuid, &TerminalTypeGuid[0])) {
933 *Termi = PC_ANSI;
934 IsTerminal = TRUE;
935 } else {
936 if (CompareGuid (&TempGuid, &TerminalTypeGuid[1])) {
937 *Termi = VT_100;
938 IsTerminal = TRUE;
939 } else {
940 if (CompareGuid (&TempGuid, &TerminalTypeGuid[2])) {
941 *Termi = VT_100_PLUS;
942 IsTerminal = TRUE;
943 } else {
944 if (CompareGuid (&TempGuid, &TerminalTypeGuid[3])) {
945 *Termi = VT_UTF8;
946 IsTerminal = TRUE;
947 } else {
948 IsTerminal = FALSE;
949 }
950 }
951 }
952 }
953
954 if (!IsTerminal) {
955 return FALSE;
956 }
957
958 Ptr = Ptr - sizeof (UART_DEVICE_PATH) - sizeof (ACPI_HID_DEVICE_PATH);
959 Acpi = (ACPI_HID_DEVICE_PATH *) Ptr;
960 Match = EISA_PNP_ID (0x0501);
961 if (CompareMem (&Acpi->HID, &Match, sizeof (UINT32)) == 0) {
962 CopyMem (Com, &Acpi->UID, sizeof (UINT32));
963 } else {
964 return FALSE;
965 }
966
967 return TRUE;
968 }
969
970 /**
971 Get mode number according to column and row
972
973 @param CallbackData The BMM context data.
974 **/
975 VOID
976 GetConsoleOutMode (
977 IN BMM_CALLBACK_DATA *CallbackData
978 )
979 {
980 UINTN Col;
981 UINTN Row;
982 UINTN CurrentCol;
983 UINTN CurrentRow;
984 UINTN Mode;
985 UINTN MaxMode;
986 EFI_STATUS Status;
987 CONSOLE_OUT_MODE *ModeInfo;
988 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
989
990 ConOut = gST->ConOut;
991 MaxMode = (UINTN) (ConOut->Mode->MaxMode);
992 ModeInfo = EfiLibGetVariable (VAR_CON_OUT_MODE, &gEfiGenericPlatformVariableGuid);
993
994 if (ModeInfo != NULL) {
995 CurrentCol = ModeInfo->Column;
996 CurrentRow = ModeInfo->Row;
997 for (Mode = 0; Mode < MaxMode; Mode++) {
998 Status = ConOut->QueryMode (ConOut, Mode, &Col, &Row);
999 if (!EFI_ERROR(Status)) {
1000 if (CurrentCol == Col && CurrentRow == Row) {
1001 CallbackData->BmmFakeNvData.ConsoleOutMode = (UINT16) Mode;
1002 break;
1003 }
1004 }
1005 }
1006 FreePool (ModeInfo);
1007 }
1008 }