Skip to content

Commit 7d59b85

Browse files
committed
common/menu: add a hotkey for the UEFI Shell
1 parent fab259b commit 7d59b85

1 file changed

Lines changed: 167 additions & 14 deletions

File tree

common/menu.c

Lines changed: 167 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,75 @@ static void format_fg_rgb_escape(char *buf, uint32_t rgb) {
7474
*p = '\0';
7575
}
7676

77+
static size_t help_action_len(const char *label) {
78+
return 2 + strlen(label);
79+
}
80+
81+
static void add_help_action_len(size_t *len, size_t *count, const char *label) {
82+
*len += help_action_len(label);
83+
if ((*count)++ != 0) {
84+
*len += 4;
85+
}
86+
}
87+
88+
static void print_help_action(const char *key, const char *label, bool *need_separator) {
89+
if (*need_separator) {
90+
print(" ");
91+
}
92+
*need_separator = true;
93+
print("%s%s\e[0m %s", interface_help_colour, key, label);
94+
}
95+
96+
static void print_secondary_help(size_t row, bool firmware_setup, bool uefi_shell, bool blank_entry) {
97+
const char *firmware_setup_label = "Firmware Setup";
98+
const char *uefi_shell_label = "UEFI Shell";
99+
const char *blank_entry_label = "Blank Entry";
100+
101+
size_t len = 0;
102+
size_t count = 0;
103+
104+
if (firmware_setup) {
105+
add_help_action_len(&len, &count, firmware_setup_label);
106+
}
107+
if (uefi_shell) {
108+
add_help_action_len(&len, &count, uefi_shell_label);
109+
}
110+
if (blank_entry) {
111+
add_help_action_len(&len, &count, blank_entry_label);
112+
}
113+
114+
if (len > terms[0]->cols) {
115+
firmware_setup_label = "Setup";
116+
uefi_shell_label = "Shell";
117+
blank_entry_label = "Blank";
118+
119+
len = 0;
120+
count = 0;
121+
if (firmware_setup) {
122+
add_help_action_len(&len, &count, firmware_setup_label);
123+
}
124+
if (uefi_shell) {
125+
add_help_action_len(&len, &count, uefi_shell_label);
126+
}
127+
if (blank_entry) {
128+
add_help_action_len(&len, &count, blank_entry_label);
129+
}
130+
}
131+
132+
set_cursor_pos_helper((terms[0]->cols > len) ? (terms[0]->cols - len) / 2 : 0, row);
133+
134+
bool need_separator = false;
135+
if (firmware_setup) {
136+
print_help_action("S", firmware_setup_label, &need_separator);
137+
}
138+
if (uefi_shell) {
139+
print_help_action("U", uefi_shell_label, &need_separator);
140+
}
141+
if (blank_entry) {
142+
print_help_action("B", blank_entry_label, &need_separator);
143+
}
144+
}
145+
77146
static bool parse_rgb_colour_value(const char *str, uint32_t *out) {
78147
const char *end;
79148
uint32_t v = strtoui(str, &end, 16);
@@ -1034,6 +1103,87 @@ static void menu_init_term(void) {
10341103
}
10351104

10361105
#if defined(UEFI)
1106+
static struct volume *uefi_shell_volume = NULL;
1107+
1108+
static char *append_string(char *p, const char *s) {
1109+
while (*s != '\0') {
1110+
*p++ = *s++;
1111+
}
1112+
*p = '\0';
1113+
return p;
1114+
}
1115+
1116+
static char *append_uint_dec(char *p, uint64_t val) {
1117+
char buf[20];
1118+
size_t i = 0;
1119+
1120+
do {
1121+
buf[i++] = '0' + (val % 10);
1122+
val /= 10;
1123+
} while (val != 0);
1124+
1125+
while (i != 0) {
1126+
*p++ = buf[--i];
1127+
}
1128+
*p = '\0';
1129+
return p;
1130+
}
1131+
1132+
static const char *uefi_shell_filename(void) {
1133+
#if defined (__x86_64__)
1134+
return "shellx64.efi";
1135+
#elif defined (__i386__)
1136+
return "shellia32.efi";
1137+
#elif defined (__aarch64__)
1138+
return "shellaa64.efi";
1139+
#elif defined (__riscv)
1140+
return "shellriscv64.efi";
1141+
#elif defined (__loongarch64)
1142+
return "shellloongarch64.efi";
1143+
#else
1144+
#error Unknown UEFI architecture
1145+
#endif
1146+
}
1147+
1148+
static bool uefi_shell_available(void) {
1149+
if (uefi_shell_volume == NULL || uefi_shell_volume->pxe) {
1150+
return false;
1151+
}
1152+
1153+
bool old_cif = case_insensitive_fopen;
1154+
case_insensitive_fopen = true;
1155+
struct file_handle *f = fopen(uefi_shell_volume, uefi_shell_filename());
1156+
case_insensitive_fopen = old_cif;
1157+
1158+
if (f == NULL) {
1159+
return false;
1160+
}
1161+
1162+
fclose(f);
1163+
return true;
1164+
}
1165+
1166+
noreturn static void boot_uefi_shell(void) {
1167+
char shell_entry[160];
1168+
char *p = shell_entry;
1169+
1170+
p = append_string(p, "PROTOCOL: efi\nPATH: ");
1171+
p = append_string(p, uefi_shell_volume->is_optical ? "odd" : "hdd");
1172+
*p++ = '(';
1173+
p = append_uint_dec(p, uefi_shell_volume->index);
1174+
*p++ = ':';
1175+
p = append_uint_dec(p, uefi_shell_volume->partition);
1176+
p = append_string(p, "):/");
1177+
p = append_string(p, uefi_shell_filename());
1178+
*p++ = '\n';
1179+
*p = '\0';
1180+
1181+
if (!quiet) {
1182+
reset_term();
1183+
}
1184+
boot(shell_entry);
1185+
}
1186+
10371187
bool reboot_to_fw_ui_supported(void) {
10381188
uint64_t os_indications_supported;
10391189
UINTN size = sizeof(os_indications_supported);
@@ -1084,6 +1234,10 @@ noreturn void _menu(bool first_run) {
10841234
size_t bss_size = (uintptr_t)bss_end - (uintptr_t)bss_begin;
10851235
#endif
10861236

1237+
#if defined (UEFI)
1238+
uefi_shell_volume = boot_volume;
1239+
#endif
1240+
10871241
if (rewound_memmap != NULL) {
10881242
memcpy(data_begin, rewound_data, data_size);
10891243
#if defined (BIOS)
@@ -1434,6 +1588,7 @@ noreturn void _menu(bool first_run) {
14341588

14351589
#if defined(UEFI)
14361590
bool reboot_to_firmware_supported = reboot_to_fw_ui_supported();
1591+
bool uefi_shell_supported = uefi_shell_available();
14371592
#endif
14381593

14391594
if (!first_run) {
@@ -1467,7 +1622,7 @@ noreturn void _menu(bool first_run) {
14671622
size_t header_offset = (menu_branding[0] != '\0') ? 2 : 0;
14681623
bool has_secondary_help = editor_enabled;
14691624
#if defined(UEFI)
1470-
has_secondary_help = has_secondary_help || reboot_to_firmware_supported;
1625+
has_secondary_help = has_secondary_help || reboot_to_firmware_supported || uefi_shell_supported;
14711626
#endif
14721627
if (has_secondary_help) {
14731628
header_offset += 2;
@@ -1586,19 +1741,10 @@ noreturn void _menu(bool first_run) {
15861741
if (has_secondary_help) {
15871742
size_t secondary_row = 1 + header_offset;
15881743
#if defined(UEFI)
1589-
if (reboot_to_firmware_supported && editor_enabled) {
1590-
set_cursor_pos_helper((terms[0]->cols - 33) / 2, secondary_row);
1591-
print("%sS\e[0m Firmware Setup %sB\e[0m Blank Entry",
1592-
interface_help_colour, interface_help_colour);
1593-
} else if (reboot_to_firmware_supported) {
1594-
set_cursor_pos_helper((terms[0]->cols - 16) / 2, secondary_row);
1595-
print("%sS\e[0m Firmware Setup", interface_help_colour);
1596-
} else
1744+
print_secondary_help(secondary_row, reboot_to_firmware_supported, uefi_shell_supported, editor_enabled);
1745+
#else
1746+
print_secondary_help(secondary_row, false, false, editor_enabled);
15971747
#endif
1598-
if (editor_enabled) {
1599-
set_cursor_pos_helper((terms[0]->cols - 13) / 2, secondary_row);
1600-
print("%sB\e[0m Blank Entry", interface_help_colour);
1601-
}
16021748
}
16031749
}
16041750
set_cursor_pos_helper(x, y);
@@ -1664,7 +1810,7 @@ noreturn void _menu(bool first_run) {
16641810
timeout_aborted:
16651811
if (max_entries == 0) {
16661812
switch (c) {
1667-
case 'b': case 'B': case 's': case 'S':
1813+
case 'b': case 'B': case 's': case 'S': case 'u': case 'U':
16681814
break;
16691815
default:
16701816
continue;
@@ -1763,6 +1909,13 @@ noreturn void _menu(bool first_run) {
17631909
}
17641910
break;
17651911
}
1912+
case 'u':
1913+
case 'U': {
1914+
if (uefi_shell_supported) {
1915+
boot_uefi_shell();
1916+
}
1917+
break;
1918+
}
17661919
#endif
17671920
case 'b':
17681921
case 'B': {

0 commit comments

Comments
 (0)