2 * QEMU S390 Interactive Boot Menu
4 * Copyright 2018 IBM Corp.
5 * Author: Collin L. Walling <walling@linux.vnet.ibm.com>
7 * This work is licensed under the terms of the GNU GPL, version 2 or (at
8 * your option) any later version. See the COPYING file in the top-level
15 #include "s390-time.h"
17 #define KEYCODE_NO_INP '\0'
18 #define KEYCODE_ESCAPE '\033'
19 #define KEYCODE_BACKSP '\177'
20 #define KEYCODE_ENTER '\r'
22 /* Offsets from zipl fields to zipl banner start */
23 #define ZIPL_TIMEOUT_OFFSET 138
24 #define ZIPL_FLAG_OFFSET 140
26 #define TOD_CLOCK_MILLISECOND 0x3e8000
28 #define LOW_CORE_EXTERNAL_INT_ADDR 0x86
29 #define CLOCK_COMPARATOR_INT 0X1004
32 static uint64_t timeout
;
34 static inline void enable_clock_int(void)
42 : : "Q" (tmp
) : "memory"
46 static inline void disable_clock_int(void)
54 : : "Q" (tmp
) : "memory"
58 static inline void set_clock_comparator(uint64_t time
)
60 asm volatile("sckc %0" : : "Q" (time
));
63 static inline bool check_clock_int(void)
65 uint16_t *code
= (uint16_t *)LOW_CORE_EXTERNAL_INT_ADDR
;
69 return *code
== CLOCK_COMPARATOR_INT
;
72 static int read_prompt(char *buf
, size_t len
)
79 time
= get_clock() + timeout
* TOD_CLOCK_MILLISECOND
;
80 set_clock_comparator(time
);
85 while (!check_clock_int()) {
87 sclp_read(inp
, 1); /* Process only one character at a time */
103 /* Echo input and add to buffer */
117 static int get_index(void)
123 memset(buf
, 0, sizeof(buf
));
125 sclp_set_write_mask(SCLP_EVENT_MASK_MSG_ASCII
, SCLP_EVENT_MASK_MSG_ASCII
);
127 len
= read_prompt(buf
, sizeof(buf
) - 1);
129 sclp_set_write_mask(0, SCLP_EVENT_MASK_MSG_ASCII
);
131 /* If no input, boot default */
136 /* Check for erroneous input */
137 for (i
= 0; i
< len
; i
++) {
138 if (!isdigit((unsigned char)buf
[i
])) {
146 static void boot_menu_prompt(bool retry
)
151 sclp_print("\nError: undefined configuration"
152 "\nPlease choose:\n");
153 } else if (timeout
> 0) {
154 sclp_print("Please choose (default will boot in ");
155 sclp_print(uitoa(timeout
/ 1000, tmp
, sizeof(tmp
)));
156 sclp_print(" seconds):\n");
158 sclp_print("Please choose:\n");
162 static int get_boot_index(bool *valid_entries
)
169 boot_menu_prompt(retry
);
170 boot_index
= get_index();
172 } while (boot_index
< 0 || boot_index
>= MAX_BOOT_ENTRIES
||
173 !valid_entries
[boot_index
]);
175 sclp_print("\nBooting entry #");
176 sclp_print(uitoa(boot_index
, tmp
, sizeof(tmp
)));
181 /* Returns the entry number that was printed */
182 static int zipl_print_entry(const char *data
, size_t len
)
186 ebcdic_to_ascii(data
, buf
, len
);
192 return buf
[0] == ' ' ? atoui(buf
+ 1) : atoui(buf
);
195 int menu_get_zipl_boot_index(const char *menu_data
)
199 bool valid_entries
[MAX_BOOT_ENTRIES
] = {false};
200 uint16_t zipl_flag
= *(uint16_t *)(menu_data
- ZIPL_FLAG_OFFSET
);
201 uint16_t zipl_timeout
= *(uint16_t *)(menu_data
- ZIPL_TIMEOUT_OFFSET
);
203 if (flag
== QIPL_FLAG_BM_OPTS_ZIPL
) {
205 return 0; /* Boot default */
207 /* zipl stores timeout as seconds */
208 timeout
= zipl_timeout
* 1000;
212 sclp_print("s390-ccw zIPL Boot Menu\n\n");
213 menu_data
+= strlen(menu_data
) + 1;
217 len
= strlen(menu_data
);
218 entry
= zipl_print_entry(menu_data
, len
);
219 menu_data
+= len
+ 1;
221 valid_entries
[entry
] = true;
229 return get_boot_index(valid_entries
);
232 int menu_get_enum_boot_index(bool *valid_entries
)
237 sclp_print("s390-ccw Enumerated Boot Menu.\n\n");
239 for (i
= 0; i
< MAX_BOOT_ENTRIES
; i
++) {
240 if (valid_entries
[i
]) {
245 sclp_print(uitoa(i
, tmp
, sizeof(tmp
)));
248 sclp_print(" default\n");
255 return get_boot_index(valid_entries
);
258 void menu_set_parms(uint8_t boot_menu_flag
, uint32_t boot_menu_timeout
)
260 flag
= boot_menu_flag
;
261 timeout
= boot_menu_timeout
;
264 bool menu_is_enabled_zipl(void)
266 return flag
& (QIPL_FLAG_BM_OPTS_CMD
| QIPL_FLAG_BM_OPTS_ZIPL
);
269 bool menu_is_enabled_enum(void)
271 return flag
& QIPL_FLAG_BM_OPTS_CMD
;