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
16 #define KEYCODE_NO_INP '\0'
17 #define KEYCODE_ESCAPE '\033'
18 #define KEYCODE_BACKSP '\177'
19 #define KEYCODE_ENTER '\r'
21 /* Offsets from zipl fields to zipl banner start */
22 #define ZIPL_TIMEOUT_OFFSET 138
23 #define ZIPL_FLAG_OFFSET 140
25 #define TOD_CLOCK_MILLISECOND 0x3e8000
27 #define LOW_CORE_EXTERNAL_INT_ADDR 0x86
28 #define CLOCK_COMPARATOR_INT 0X1004
31 static uint64_t timeout
;
33 static inline void enable_clock_int(void)
41 : : "Q" (tmp
) : "memory"
45 static inline void disable_clock_int(void)
53 : : "Q" (tmp
) : "memory"
57 static inline void set_clock_comparator(uint64_t time
)
59 asm volatile("sckc %0" : : "Q" (time
));
62 static inline bool check_clock_int(void)
64 uint16_t *code
= (uint16_t *)LOW_CORE_EXTERNAL_INT_ADDR
;
68 return *code
== CLOCK_COMPARATOR_INT
;
71 static int read_prompt(char *buf
, size_t len
)
78 time
= get_clock() + timeout
* TOD_CLOCK_MILLISECOND
;
79 set_clock_comparator(time
);
84 while (!check_clock_int()) {
86 sclp_read(inp
, 1); /* Process only one character at a time */
102 /* Echo input and add to buffer */
116 static int get_index(void)
122 memset(buf
, 0, sizeof(buf
));
124 sclp_set_write_mask(SCLP_EVENT_MASK_MSG_ASCII
, SCLP_EVENT_MASK_MSG_ASCII
);
126 len
= read_prompt(buf
, sizeof(buf
) - 1);
128 sclp_set_write_mask(0, SCLP_EVENT_MASK_MSG_ASCII
);
130 /* If no input, boot default */
135 /* Check for erroneous input */
136 for (i
= 0; i
< len
; i
++) {
137 if (!isdigit((unsigned char)buf
[i
])) {
145 static void boot_menu_prompt(bool retry
)
150 sclp_print("\nError: undefined configuration"
151 "\nPlease choose:\n");
152 } else if (timeout
> 0) {
153 sclp_print("Please choose (default will boot in ");
154 sclp_print(uitoa(timeout
/ 1000, tmp
, sizeof(tmp
)));
155 sclp_print(" seconds):\n");
157 sclp_print("Please choose:\n");
161 static int get_boot_index(bool *valid_entries
)
168 boot_menu_prompt(retry
);
169 boot_index
= get_index();
171 } while (boot_index
< 0 || boot_index
>= MAX_BOOT_ENTRIES
||
172 !valid_entries
[boot_index
]);
174 sclp_print("\nBooting entry #");
175 sclp_print(uitoa(boot_index
, tmp
, sizeof(tmp
)));
180 /* Returns the entry number that was printed */
181 static int zipl_print_entry(const char *data
, size_t len
)
185 ebcdic_to_ascii(data
, buf
, len
);
191 return buf
[0] == ' ' ? atoui(buf
+ 1) : atoui(buf
);
194 int menu_get_zipl_boot_index(const char *menu_data
)
198 bool valid_entries
[MAX_BOOT_ENTRIES
] = {false};
199 uint16_t zipl_flag
= *(uint16_t *)(menu_data
- ZIPL_FLAG_OFFSET
);
200 uint16_t zipl_timeout
= *(uint16_t *)(menu_data
- ZIPL_TIMEOUT_OFFSET
);
202 if (flag
== QIPL_FLAG_BM_OPTS_ZIPL
) {
204 return 0; /* Boot default */
206 /* zipl stores timeout as seconds */
207 timeout
= zipl_timeout
* 1000;
211 sclp_print("s390-ccw zIPL Boot Menu\n\n");
212 menu_data
+= strlen(menu_data
) + 1;
216 len
= strlen(menu_data
);
217 entry
= zipl_print_entry(menu_data
, len
);
218 menu_data
+= len
+ 1;
220 valid_entries
[entry
] = true;
228 return get_boot_index(valid_entries
);
231 int menu_get_enum_boot_index(bool *valid_entries
)
236 sclp_print("s390-ccw Enumerated Boot Menu.\n\n");
238 for (i
= 0; i
< MAX_BOOT_ENTRIES
; i
++) {
239 if (valid_entries
[i
]) {
244 sclp_print(uitoa(i
, tmp
, sizeof(tmp
)));
247 sclp_print(" default\n");
254 return get_boot_index(valid_entries
);
257 void menu_set_parms(uint8_t boot_menu_flag
, uint32_t boot_menu_timeout
)
259 flag
= boot_menu_flag
;
260 timeout
= boot_menu_timeout
;
263 bool menu_is_enabled_zipl(void)
265 return flag
& (QIPL_FLAG_BM_OPTS_CMD
| QIPL_FLAG_BM_OPTS_ZIPL
);
268 bool menu_is_enabled_enum(void)
270 return flag
& QIPL_FLAG_BM_OPTS_CMD
;