Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:09

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSBSPsX8664AMD64EFI
0007  *
0008  * @brief EFI console implementation
0009  */
0010 
0011 /*
0012  * Copyright (C) 2023 Karel Gardas
0013  *
0014  * Redistribution and use in source and binary forms, with or without
0015  * modification, are permitted provided that the following conditions
0016  * are met:
0017  * 1. Redistributions of source code must retain the above copyright
0018  *    notice, this list of conditions and the following disclaimer.
0019  * 2. Redistributions in binary form must reproduce the above copyright
0020  *    notice, this list of conditions and the following disclaimer in the
0021  *    documentation and/or other materials provided with the distribution.
0022  *
0023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0024  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0026  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0027  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0028  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0029  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0032  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0033  * POSSIBILITY OF SUCH DAMAGE.
0034  */
0035 
0036 #include <bsp.h>
0037 
0038 #include <efi.h>
0039 
0040 #include <rtems/bspIo.h>
0041 
0042 #include <stdio.h>
0043 #include <string.h>
0044 
0045 #include <efistop.h>
0046 #include <efigop.h>
0047 
0048 #include <multiboot2impl.h>
0049 
0050 #ifdef BSP_USE_EFI_BOOT_SERVICES
0051 
0052 extern EFI_HANDLE               IH;
0053 extern EFI_SYSTEM_TABLE         *ST;
0054 extern EFI_BOOT_SERVICES        *BS;
0055 extern EFI_RUNTIME_SERVICES     *RS;
0056 
0057 extern void uart0_output_char(char c);
0058 
0059 static bool is_efi_console_initialized = false;
0060 
0061 static char output_buffer[4096];
0062 static int output_buffer_index = 0;
0063 
0064 void
0065 efi_console_initialize(void);
0066 
0067 EFI_STATUS
0068 print_gop_info(EFI_GRAPHICS_OUTPUT *gop);
0069 
0070 EFI_STATUS
0071 check_gop(BOOLEAN verbose);
0072 
0073 static void
0074 both_output_char(char c);
0075 
0076 static void
0077 sync_output(void);
0078 
0079 void
0080 print_ccm_info(EFI_CONSOLE_CONTROL_SCREEN_MODE, BOOLEAN, BOOLEAN);
0081 
0082 void
0083 print_ccm_info(EFI_CONSOLE_CONTROL_SCREEN_MODE mode, BOOLEAN graphics, BOOLEAN locked)
0084 {
0085     printf("RTEMS: EFI console default mode: ");
0086     switch (mode) {
0087     case EfiConsoleControlScreenText:
0088         printf("text");
0089         break;
0090     case EfiConsoleControlScreenGraphics:
0091         printf("graphics");
0092         break;
0093     case EfiConsoleControlScreenMaxValue:
0094         printf("max value");
0095         break;
0096     }
0097     if (graphics) {
0098         printf(", graphics is available");
0099     }
0100     if (locked) {
0101         printf(", stdin is locked");
0102     }
0103     printf("\n");
0104 }
0105 
0106 void
0107 efi_console_initialize( void )
0108 {
0109     EFI_STATUS status;
0110     EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
0111     EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL;
0112     EFI_HANDLE *HandleBuffer = NULL;
0113     UINTN HandleCount = 0;
0114     BOOLEAN graphics_exists;
0115     BOOLEAN locked_stdin;
0116     EFI_CONSOLE_CONTROL_SCREEN_MODE mode;
0117     BOOLEAN use_text = false;
0118     BOOLEAN use_graphic = false;
0119     BOOLEAN use_auto = false;
0120     int text_mode = -1;
0121     int graphic_mode = -1;
0122 
0123     if (is_efi_console_initialized)
0124         return;
0125     if (ST == NULL)
0126         return;
0127 
0128     /* try hard to obtain console control */
0129     status = ST->BootServices->LocateProtocol(&ConsoleControlGUID, NULL,
0130                                               (VOID **)&ConsoleControl);
0131     if (EFI_ERROR(status)) {
0132         status = ST->BootServices->HandleProtocol( ST->ConsoleOutHandle,
0133                                                    &ConsoleControlGUID,
0134                                                    (VOID **)&ConsoleControl);
0135         if (EFI_ERROR(status)) {
0136             status = ST->BootServices->LocateHandleBuffer( ByProtocol,
0137                                                            &ConsoleControlGUID,
0138                                                            NULL,
0139                                                            &HandleCount,
0140                                                            &HandleBuffer);
0141             if (status == EFI_SUCCESS) {
0142                 for (int i = 0; i < HandleCount; i++) {
0143                     status = ST->BootServices->HandleProtocol( HandleBuffer[i],
0144                                                                &ConsoleControlGUID,
0145                                                                (VOID*)&ConsoleControl);
0146                     if (!EFI_ERROR (status)) {
0147                         break;
0148                     }
0149                 }
0150                 ST->BootServices->FreePool(HandleBuffer);
0151             }
0152         }
0153     }
0154     if (strcmp(BSP_EFI_CONSOLE_KIND, "TEXT") == 0) {
0155         use_text = true;
0156     }
0157     if (strcmp(BSP_EFI_CONSOLE_KIND, "GRAPHIC") == 0) {
0158         use_graphic = true;
0159     }
0160     if (strcmp(BSP_EFI_CONSOLE_KIND, "BOTH") == 0) {
0161         use_text = true;
0162         use_graphic = true;
0163     }
0164     if (strcmp(BSP_EFI_CONSOLE_KIND, "AUTO") == 0) {
0165         use_auto = true;
0166     }
0167     if (ConsoleControl != NULL) {
0168         status = ConsoleControl->GetMode(ConsoleControl, &mode, &graphics_exists, &locked_stdin);
0169         if (!EFI_ERROR(status)) {
0170             print_ccm_info(mode, graphics_exists, locked_stdin);
0171             if (mode == EfiConsoleControlScreenText && use_auto) {
0172                 use_text = true;
0173             }
0174             if (mode == EfiConsoleControlScreenGraphics && use_auto) {
0175                 use_graphic = true;
0176             }
0177         }
0178         else {
0179             /* in case of error from console control, let's use both outputs */
0180             use_text = true;
0181             use_graphic = true;
0182         }
0183     }
0184     else {
0185         /* in case of missing console control, let's use both outputs */
0186         use_text = true;
0187         use_graphic = true;
0188     }
0189     if (get_boot_arg_int_value(boot_args(), "text_mode", &text_mode) == 0
0190         || get_boot_arg_int_value(boot_args(), "graphic_mode", &graphic_mode) == 0) {
0191         /* if there is any command-line arg passed to manage console, we give it max
0192            priority which means we reset any value set so far. */
0193         use_text = false;
0194         use_graphic = false;
0195     }
0196     if (get_boot_arg_int_value(boot_args(), "text_mode", &text_mode) == 0) {
0197         use_text = true;
0198     }
0199     if (get_boot_arg_int_value(boot_args(), "graphic_mode", &graphic_mode) == 0) {
0200         use_graphic = true;
0201     }
0202     if (use_text)
0203         efi_init_text_output(text_mode);
0204     if (use_graphic) {
0205         efi_init_graphic_output(graphic_mode);
0206     }
0207     if (use_text && use_graphic) {
0208         BSP_output_char = both_output_char;
0209     }
0210     else if (use_text) {
0211         BSP_output_char = efi_text_output_char;
0212     }
0213     else if (use_graphic) {
0214         BSP_output_char = efi_graphic_output_char;
0215     }
0216     sync_output();
0217     is_efi_console_initialized = true;
0218 }
0219 
0220 void
0221 buffered_output( char c );
0222 
0223 void
0224 buffered_output( char c )
0225 {
0226     if (output_buffer_index < (4096 - 1)) {
0227         output_buffer[output_buffer_index] = c;
0228         output_buffer_index++;
0229     }
0230 }
0231 
0232 static void
0233 both_output_char( char c )
0234 {
0235     efi_text_output_char(c);
0236     efi_graphic_output_char(c);
0237 }
0238 
0239 void
0240 sync_output()
0241 {
0242     printf("EFI: console sync_output(): there are %d characters in the buffer.\n", output_buffer_index);
0243     for (int i = 0; i < output_buffer_index; i++) {
0244         BSP_output_char(output_buffer[i]);
0245     }
0246     printf("EFI: console sync_output() done.\n");
0247 }
0248 
0249 #if (BSP_EFI_EARLY_CONSOLE_KIND == BUFFER)
0250 BSP_output_char_function_type BSP_output_char   = buffered_output;
0251 #elif (BSP_EFI_EARLY_CONSOLE_KIND == SERIAL)
0252 BSP_output_char_function_type BSP_output_char   = uart0_output_char;
0253 #endif
0254 
0255 BSP_polling_getchar_function_type BSP_poll_char = NULL;
0256 
0257 #endif
0258