@@ -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+
77146static 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+
10371187bool 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) {
16641810timeout_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