* 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
@end deffn
+@node efitextmode
+@subsection efitextmode
+
+@deffn Command efitextmode [min | max | <mode_num> | <cols> <rows>]
+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 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
--- /dev/null
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ * Set/Get UEFI text output mode resolution.
+ */
+
+#include <grub/dl.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+#include <grub/efi/efi.h>
+#include <grub/efi/api.h>
+
+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 | <mode_num> | <cols> <rows>]"),
+ N_("Get or set EFI text mode."));
+}
+
+GRUB_MOD_FINI (efitextmode)
+{
+ grub_unregister_command (cmd);
+}