summaryrefslogtreecommitdiffstats
path: root/bsps/x86_64/amd64/console/eficonsole.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--bsps/x86_64/amd64/console/eficonsole.c250
1 files changed, 250 insertions, 0 deletions
diff --git a/bsps/x86_64/amd64/console/eficonsole.c b/bsps/x86_64/amd64/console/eficonsole.c
new file mode 100644
index 0000000000..58bd2b660b
--- /dev/null
+++ b/bsps/x86_64/amd64/console/eficonsole.c
@@ -0,0 +1,250 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/*
+ * Copyright (C) 2023 Karel Gardas
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <bsp.h>
+
+#include <efi.h>
+
+#include <rtems/bspIo.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <efistop.h>
+#include <efigop.h>
+
+#include <multiboot2impl.h>
+
+#ifdef BSP_USE_EFI_BOOT_SERVICES
+
+extern EFI_HANDLE IH;
+extern EFI_SYSTEM_TABLE *ST;
+extern EFI_BOOT_SERVICES *BS;
+extern EFI_RUNTIME_SERVICES *RS;
+
+extern void uart0_output_char(char c);
+
+static bool is_efi_console_initialized = false;
+
+static char output_buffer[4096];
+static int output_buffer_index = 0;
+
+void
+efi_console_initialize(void);
+
+EFI_STATUS
+print_gop_info(EFI_GRAPHICS_OUTPUT *gop);
+
+EFI_STATUS
+check_gop(BOOLEAN verbose);
+
+static void
+both_output_char(char c);
+
+static void
+sync_output(void);
+
+void
+print_ccm_info(EFI_CONSOLE_CONTROL_SCREEN_MODE, BOOLEAN, BOOLEAN);
+
+void
+print_ccm_info(EFI_CONSOLE_CONTROL_SCREEN_MODE mode, BOOLEAN graphics, BOOLEAN locked)
+{
+ printf("RTEMS: EFI console default mode: ");
+ switch (mode) {
+ case EfiConsoleControlScreenText:
+ printf("text");
+ break;
+ case EfiConsoleControlScreenGraphics:
+ printf("graphics");
+ break;
+ case EfiConsoleControlScreenMaxValue:
+ printf("max value");
+ break;
+ }
+ if (graphics) {
+ printf(", graphics is available");
+ }
+ if (locked) {
+ printf(", stdin is locked");
+ }
+ printf("\n");
+}
+
+void
+efi_console_initialize( void )
+{
+ EFI_STATUS status;
+ EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
+ EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL;
+ EFI_HANDLE *HandleBuffer = NULL;
+ UINTN HandleCount = 0;
+ BOOLEAN graphics_exists;
+ BOOLEAN locked_stdin;
+ EFI_CONSOLE_CONTROL_SCREEN_MODE mode;
+ BOOLEAN use_text = false;
+ BOOLEAN use_graphic = false;
+ BOOLEAN use_auto = false;
+ int text_mode = -1;
+ int graphic_mode = -1;
+
+ if (is_efi_console_initialized)
+ return;
+ if (ST == NULL)
+ return;
+
+ /* try hard to obtain console control */
+ status = ST->BootServices->LocateProtocol(&ConsoleControlGUID, NULL,
+ (VOID **)&ConsoleControl);
+ if (EFI_ERROR(status)) {
+ status = ST->BootServices->HandleProtocol( ST->ConsoleOutHandle,
+ &ConsoleControlGUID,
+ (VOID **)&ConsoleControl);
+ if (EFI_ERROR(status)) {
+ status = ST->BootServices->LocateHandleBuffer( ByProtocol,
+ &ConsoleControlGUID,
+ NULL,
+ &HandleCount,
+ &HandleBuffer);
+ if (status == EFI_SUCCESS) {
+ for (int i = 0; i < HandleCount; i++) {
+ status = ST->BootServices->HandleProtocol( HandleBuffer[i],
+ &ConsoleControlGUID,
+ (VOID*)&ConsoleControl);
+ if (!EFI_ERROR (status)) {
+ break;
+ }
+ }
+ ST->BootServices->FreePool(HandleBuffer);
+ }
+ }
+ }
+ if (strcmp(BSP_EFI_CONSOLE_KIND, "TEXT") == 0) {
+ use_text = true;
+ }
+ if (strcmp(BSP_EFI_CONSOLE_KIND, "GRAPHIC") == 0) {
+ use_graphic = true;
+ }
+ if (strcmp(BSP_EFI_CONSOLE_KIND, "BOTH") == 0) {
+ use_text = true;
+ use_graphic = true;
+ }
+ if (strcmp(BSP_EFI_CONSOLE_KIND, "AUTO") == 0) {
+ use_auto = true;
+ }
+ if (ConsoleControl != NULL) {
+ status = ConsoleControl->GetMode(ConsoleControl, &mode, &graphics_exists, &locked_stdin);
+ if (!EFI_ERROR(status)) {
+ print_ccm_info(mode, graphics_exists, locked_stdin);
+ if (mode == EfiConsoleControlScreenText && use_auto) {
+ use_text = true;
+ }
+ if (mode == EfiConsoleControlScreenGraphics && use_auto) {
+ use_graphic = true;
+ }
+ }
+ else {
+ /* in case of error from console control, let's use both outputs */
+ use_text = true;
+ use_graphic = true;
+ }
+ }
+ else {
+ /* in case of missing console control, let's use both outputs */
+ use_text = true;
+ use_graphic = true;
+ }
+ if (get_boot_arg_int_value(boot_args(), "text_mode", &text_mode) == 0
+ || get_boot_arg_int_value(boot_args(), "graphic_mode", &graphic_mode) == 0) {
+ /* if there is any command-line arg passed to manage console, we give it max
+ priority which means we reset any value set so far. */
+ use_text = false;
+ use_graphic = false;
+ }
+ if (get_boot_arg_int_value(boot_args(), "text_mode", &text_mode) == 0) {
+ use_text = true;
+ }
+ if (get_boot_arg_int_value(boot_args(), "graphic_mode", &graphic_mode) == 0) {
+ use_graphic = true;
+ }
+ if (use_text)
+ efi_init_text_output(text_mode);
+ if (use_graphic) {
+ efi_init_graphic_output(graphic_mode);
+ }
+ if (use_text && use_graphic) {
+ BSP_output_char = both_output_char;
+ }
+ else if (use_text) {
+ BSP_output_char = efi_text_output_char;
+ }
+ else if (use_graphic) {
+ BSP_output_char = efi_graphic_output_char;
+ }
+ sync_output();
+ is_efi_console_initialized = true;
+}
+
+void
+buffered_output( char c );
+
+void
+buffered_output( char c )
+{
+ if (output_buffer_index < (4096 - 1)) {
+ output_buffer[output_buffer_index] = c;
+ output_buffer_index++;
+ }
+}
+
+static void
+both_output_char( char c )
+{
+ efi_text_output_char(c);
+ efi_graphic_output_char(c);
+}
+
+void
+sync_output()
+{
+ printf("EFI: console sync_output(): there are %d characters in the buffer.\n", output_buffer_index);
+ for (int i = 0; i < output_buffer_index; i++) {
+ BSP_output_char(output_buffer[i]);
+ }
+ printf("EFI: console sync_output() done.\n");
+}
+
+#if (BSP_EFI_EARLY_CONSOLE_KIND == BUFFER)
+BSP_output_char_function_type BSP_output_char = buffered_output;
+#elif (BSP_EFI_EARLY_CONSOLE_KIND == SERIAL)
+BSP_output_char_function_type BSP_output_char = uart0_output_char;
+#endif
+
+BSP_polling_getchar_function_type BSP_poll_char = NULL;
+
+#endif
+