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(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(int entries
)
168 boot_menu_prompt(retry
);
169 boot_index
= get_index();
171 } while (boot_index
< 0 || boot_index
>= entries
);
173 sclp_print("\nBooting entry #");
174 sclp_print(uitoa(boot_index
, tmp
, sizeof(tmp
)));
179 static void zipl_println(const char *data
, size_t len
)
183 ebcdic_to_ascii(data
, buf
, len
);
190 int menu_get_zipl_boot_index(const char *menu_data
)
194 uint16_t zipl_flag
= *(uint16_t *)(menu_data
- ZIPL_FLAG_OFFSET
);
195 uint16_t zipl_timeout
= *(uint16_t *)(menu_data
- ZIPL_TIMEOUT_OFFSET
);
197 if (flag
== QIPL_FLAG_BM_OPTS_ZIPL
) {
199 return 0; /* Boot default */
201 /* zipl stores timeout as seconds */
202 timeout
= zipl_timeout
* 1000;
205 /* Print and count all menu items, including the banner */
206 for (entries
= 0; *menu_data
; entries
++) {
207 len
= strlen(menu_data
);
208 zipl_println(menu_data
, len
);
209 menu_data
+= len
+ 1;
217 return get_boot_index(entries
- 1); /* subtract 1 to exclude banner */
221 int menu_get_enum_boot_index(int entries
)
225 sclp_print("s390x Enumerated Boot Menu.\n\n");
227 sclp_print(uitoa(entries
, tmp
, sizeof(tmp
)));
228 sclp_print(" entries detected. Select from boot index 0 to ");
229 sclp_print(uitoa(entries
- 1, tmp
, sizeof(tmp
)));
232 return get_boot_index(entries
);
235 void menu_set_parms(uint8_t boot_menu_flag
, uint32_t boot_menu_timeout
)
237 flag
= boot_menu_flag
;
238 timeout
= boot_menu_timeout
;
241 bool menu_is_enabled_zipl(void)
243 return flag
& (QIPL_FLAG_BM_OPTS_CMD
| QIPL_FLAG_BM_OPTS_ZIPL
);
246 bool menu_is_enabled_enum(void)
248 return flag
& QIPL_FLAG_BM_OPTS_CMD
;