From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from list by lists.gnu.org with archive (Exim 4.90_1) id 1oEmuW-0002yW-4I for mharc-grub-devel@gnu.org; Fri, 22 Jul 2022 03:17:22 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:50198) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1oEmuT-0002xG-PD for grub-devel@gnu.org; Fri, 22 Jul 2022 03:17:17 -0400 Received: from mail-qk1-x72f.google.com ([2607:f8b0:4864:20::72f]:34710) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1oEmuQ-0004yj-M5 for grub-devel@gnu.org; Fri, 22 Jul 2022 03:17:17 -0400 Received: by mail-qk1-x72f.google.com with SMTP id c3so3057618qko.1 for ; Fri, 22 Jul 2022 00:17:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=efficientek-com.20210112.gappssmtp.com; s=20210112; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=aGlqm56YEPzwFEm/b82ul7jG3fvL0Lgvv8EZLe6PUmc=; b=TZMAJvzVWlvgvoq8yztfvyhWa3Jb5E0U4LvWRygYqwkcn1l+DqyLD/KL6vuydywbR7 lyhe46CkD4v/j3cTd50PVj2eg5X+n8REkBnxEWnbHrbtgSUmdVwVVGJ1LeeYJCJJRjH0 R0LjVXR3D6h+1x+aZpLBwbTwY01gxb3N0jKuGZEqiI9FYo7z2LC1vMXzYEfnLv71mF2D R0FJOgOV+naddZHGC4vbidfLXR3pJ+uTysHfoD18Qqb4Tguvemi9BMUPhrRIZZrttDrQ 8nZJo11vE/2S5yRNZmFK6bwbg+Ly6vy9mdd7brWeXOee8JCawO6rVuGXLTklQvcVEPoN ASbQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=aGlqm56YEPzwFEm/b82ul7jG3fvL0Lgvv8EZLe6PUmc=; b=N8OztueXKs1jNiVN9mwgRe3K/v6hFf6UfDFM+Cs+TjrbE8p5vIOcVSMzH7gENZsWGk wxm6j2xACzhoBxJIxQq6gYdSsJoBmS8pq41DXgvGnob2/Ndq6YmiHJXfxOMyE5tjwS9U uk3jpBZu8IaceKkxKNHkzxkj/o2PP1bfsNxn6h/xX192LrNrWPB0QXWLhp3kwlyihF8s dtm1nQB3DX+djRwJ8ay0AQ+cIFGn8ygWcCaqs6e4UYNiMbBgJ8RIXWmt9fYqm/f9NLp5 gnip4b8x6pb/HfOrfCbnTpbfbbQH9m14kld9f6oI78K467EtkDWJv8CtObXgT7X4e8f5 FNYQ== X-Gm-Message-State: AJIora/CSiUYHgRQQgYOa0eAOWfbE0ZgvQ0uPiGz8iBV/GRDHun9YyJj 4lddokZrD5dubzQxbQVxQ2NuuUftyRwF8Q== X-Google-Smtp-Source: AGRyM1vBWWciNZphMEXzpFaoMj6fj+Tti3N9awWoT6DmlN2Et68jQHkovOlZoGfYEsajCZENPxGE/Q== X-Received: by 2002:a05:620a:4306:b0:6a9:7122:edb2 with SMTP id u6-20020a05620a430600b006a97122edb2mr1555129qko.502.1658474233188; Fri, 22 Jul 2022 00:17:13 -0700 (PDT) Received: from localhost.localdomain ([37.218.244.251]) by smtp.gmail.com with ESMTPSA id f8-20020a05620a280800b006a6ce613c7csm3156292qkp.89.2022.07.22.00.17.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 22 Jul 2022 00:17:12 -0700 (PDT) From: Glenn Washburn To: grub-devel@gnu.org, Daniel Kiper Cc: Paul Menzel , Gerd Hoffmann , Glenn Washburn Subject: [PATCH v3] efi: Add efitextmode command for getting/setting the text mode resolution Date: Fri, 22 Jul 2022 02:16:33 -0500 Message-Id: <20220722071633.1287796-1-development@efficientek.com> X-Mailer: git-send-email 2.34.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Received-SPF: pass client-ip=2607:f8b0:4864:20::72f; envelope-from=development@efficientek.com; helo=mail-qk1-x72f.google.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: The development of GNU GRUB List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 22 Jul 2022 07:17:18 -0000 This command is meant to behave similarly to the 'mode' command of the EFI Shell application. In addition to allowing mode selection by giving the number of columns and rows as arguments, the command allows specifying the mode number to select the mode. Also supported are the arguments "min" and "max", which set the mode to the minimum and maximum mode respectively as calculated by the columns * rows of that mode. Signed-off-by: Glenn Washburn --- Updates since v2: * Merge docs patch with this patch * Allow specifying cols and rows to select mode * Refactor * Other changes suggested by Daniel Glenn --- docs/grub.texi | 42 ++++++++ grub-core/Makefile.core.def | 6 ++ grub-core/commands/efi/efitextmode.c | 156 +++++++++++++++++++++++++++ include/grub/efi/api.h | 6 ++ include/grub/err.h | 3 +- 5 files changed, 212 insertions(+), 1 deletion(-) create mode 100644 grub-core/commands/efi/efitextmode.c diff --git a/docs/grub.texi b/docs/grub.texi index af119dea3..31194a0c7 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -4238,6 +4238,7 @@ you forget a command, you can run the command @command{help} * distrust:: Remove a pubkey from trusted keys * drivemap:: Map a drive to another * echo:: Display a line of text +* efitextmode:: Set/Get text output mode resolution * eval:: Evaluate agruments as GRUB commands * export:: Export an environment variable * false:: Do nothing, unsuccessfully @@ -4685,6 +4686,47 @@ character will print that character. @end deffn +@node efitextmode +@subsection efitextmode + +@deffn Command efitextmode [min | max | | ] +When used with no arguments displays all available text output modes. The +set mode determines the columns and rows of the text display when in +text mode. An asterisk, @samp{*}, will be at the end of the line of the +currently set mode. + +If given a single parameter, it must be @samp{min}, @samp{max}, or a mode +number given by the listing when run with no arguments. These arguments set +the mode to the minimum, maximum, and particular mode respectively. + +Otherwise, the command must be given two numerical arguments specifying the +columns and rows of the desired mode. Specifying a columns and rows +combination that corresponds to no supported mode, will return error, but +otherwise have no effect. + +By default GRUB will start in whatever mode the EFI firmware defaults to. +There are firmwares known to set up the default mode such that output +behaves strangely, for example the cursor in the grub shell never reaches +the bottom of the screen or, when typing characters at the prompt, +characters from previous command output are overwritten. Setting the mode +may fix this. + +The EFI specification says that mode 0 is must be available and have +columns and rows of 80 and 25 respectively. Mode 1 may be defined and if +so must have columns and rows of 80 and 50 respectively. Any other modes +may have columns and rows arbitrarily defined by the firmware. This means +that a mode with columns and rows of 100 and 31 on one firmware may be a +different mode number on a different firmware or not exist at all. +Likewise, mode number 2 on one firmware may have a different number of +columns and rows than mode 2 on a different firmware. So one should not +rely on a particular mode number or a mode of a certain number of columns +and rows existing on all firmwares, except for mode 0. + +Note: This command is only available on EFI platforms and is similar to +EFI shell "mode" command. +@end deffn + + @node eval @subsection eval diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 715994872..5212dfab1 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -813,6 +813,12 @@ module = { enable = efi; }; +module = { + name = efitextmode; + efi = commands/efi/efitextmode.c; + enable = efi; +}; + module = { name = blocklist; common = commands/blocklist.c; diff --git a/grub-core/commands/efi/efitextmode.c b/grub-core/commands/efi/efitextmode.c new file mode 100644 index 000000000..71d0fe625 --- /dev/null +++ b/grub-core/commands/efi/efitextmode.c @@ -0,0 +1,156 @@ +/* efitextmode.c - command to get/set text mode resolution */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2022 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + * + * Set/Get UEFI text output mode resolution + */ + +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +static grub_err_t +grub_efi_set_mode (grub_efi_simple_text_output_interface_t *o, + grub_efi_int32_t mode) +{ + grub_efi_status_t status; + + if (mode != o->mode->mode) + { + status = efi_call_2 (o->set_mode, o, mode); + if (status == GRUB_EFI_SUCCESS) + ; + else if (status == GRUB_EFI_DEVICE_ERROR) + return grub_error (GRUB_ERR_BAD_DEVICE, + N_("device error: could not set requested mode")); + else if (status == GRUB_EFI_UNSUPPORTED) + return grub_error (GRUB_ERR_OUT_OF_RANGE, + N_("invalid mode: number not valid")); + else + return grub_error (GRUB_ERR_BAD_FIRMWARE, + N_("unexpected EFI error number: `%u'"), + (unsigned) status); + } + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_efitextmode (grub_command_t cmd __attribute__ ((unused)), + int argc, char **args) +{ + grub_efi_simple_text_output_interface_t *o = grub_efi_system_table->con_out; + unsigned long mode; + const char *p = NULL; + grub_err_t err; + grub_efi_uintn_t columns, rows; + grub_efi_int32_t i; + + if (o == NULL) + return grub_error (GRUB_ERR_BAD_DEVICE, N_("no UEFI output console interface")); + + if (o->mode == NULL) + return grub_error (GRUB_ERR_BUG, N_("no mode struct for UEFI output console")); + + if (argc > 2) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("at most two arguments expected")); + + if (argc == 0) + { + grub_printf_ (N_("Available modes for console output device.\n")); + + for (i = 0; i < o->mode->max_mode; i++) + if (GRUB_EFI_SUCCESS == efi_call_4 (o->query_mode, o, i, + &columns, &rows)) + grub_printf_ (N_(" [%" PRIuGRUB_EFI_UINT32_T "] Col %5" + PRIuGRUB_EFI_UINTN_T " Row %5" PRIuGRUB_EFI_UINTN_T + " %c\n"), + i, columns, rows, (i == o->mode->mode) ? '*' : ' '); + } + else if (argc == 1) + { + if (grub_strcmp (args[0], "min") == 0) + mode = 0; + else if (grub_strcmp (args[0], "max") == 0) + mode = o->mode->max_mode - 1; + else + { + mode = grub_strtoul (args[0], &p, 0); + + if (*args[0] == '\0' || *p != '\0') + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("non-numeric or invalid mode `%s'"), args[0]); + } + + if (mode < (unsigned long) o->mode->max_mode) + { + err = grub_efi_set_mode (o, (grub_efi_int32_t) mode); + if (err != GRUB_ERR_NONE) + return err; + } + else + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("invalid mode: `%lu' is greater than maximum mode `%lu'"), + mode, (unsigned long) o->mode->max_mode); + } + else if (argc == 2) + { + grub_efi_uintn_t u_columns, u_rows; + + u_columns = (grub_efi_uintn_t) grub_strtoul (args[0], &p, 0); + + if (*args[0] == '\0' || *p != '\0') + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("non-numeric or invalid columns number `%s'"), args[0]); + + u_rows = (grub_efi_uintn_t) grub_strtoul (args[1], &p, 0); + + if (*args[1] == '\0' || *p != '\0') + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("non-numeric or invalid rows number `%s'"), args[1]); + + for (i = 0; i < o->mode->max_mode; i++) + if (GRUB_EFI_SUCCESS == efi_call_4 (o->query_mode, o, i, + &columns, &rows)) + if (u_columns == columns && u_rows == rows) + return grub_efi_set_mode (o, (grub_efi_int32_t) i); + + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("no mode found with requested columns and rows")); + } + + return GRUB_ERR_NONE; +} + +static grub_command_t cmd; +GRUB_MOD_INIT (efitextmode) +{ + cmd = grub_register_command ("efitextmode", grub_cmd_efitextmode, + N_("[min | max | | ]"), + N_("Get or set EFI text mode.")); +} + +GRUB_MOD_FINI (efitextmode) +{ + grub_unregister_command (cmd); +} diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h index d4cadd8b5..b1cd036f4 100644 --- a/include/grub/efi/api.h +++ b/include/grub/efi/api.h @@ -536,9 +536,13 @@ typedef char grub_efi_boolean_t; #if GRUB_CPU_SIZEOF_VOID_P == 8 typedef grub_int64_t grub_efi_intn_t; typedef grub_uint64_t grub_efi_uintn_t; +#define PRIxGRUB_EFI_UINTN_T "lx" +#define PRIuGRUB_EFI_UINTN_T "lu" #else typedef grub_int32_t grub_efi_intn_t; typedef grub_uint32_t grub_efi_uintn_t; +#define PRIxGRUB_EFI_UINTN_T "x" +#define PRIuGRUB_EFI_UINTN_T "u" #endif typedef grub_int8_t grub_efi_int8_t; typedef grub_uint8_t grub_efi_uint8_t; @@ -546,6 +550,8 @@ typedef grub_int16_t grub_efi_int16_t; typedef grub_uint16_t grub_efi_uint16_t; typedef grub_int32_t grub_efi_int32_t; typedef grub_uint32_t grub_efi_uint32_t; +#define PRIxGRUB_EFI_UINT32_T "x" +#define PRIuGRUB_EFI_UINT32_T "u" typedef grub_int64_t grub_efi_int64_t; typedef grub_uint64_t grub_efi_uint64_t; typedef grub_uint8_t grub_efi_char8_t; diff --git a/include/grub/err.h b/include/grub/err.h index b08d5d0de..1c07034cd 100644 --- a/include/grub/err.h +++ b/include/grub/err.h @@ -72,7 +72,8 @@ typedef enum GRUB_ERR_NET_PACKET_TOO_BIG, GRUB_ERR_NET_NO_DOMAIN, GRUB_ERR_EOF, - GRUB_ERR_BAD_SIGNATURE + GRUB_ERR_BAD_SIGNATURE, + GRUB_ERR_BAD_FIRMWARE } grub_err_t; -- 2.34.1