qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

menu.c (6085B)


      1 /*
      2  * QEMU S390 Interactive Boot Menu
      3  *
      4  * Copyright 2018 IBM Corp.
      5  * Author: Collin L. Walling <walling@linux.vnet.ibm.com>
      6  *
      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
      9  * directory.
     10  */
     11 
     12 #include "libc.h"
     13 #include "s390-ccw.h"
     14 #include "sclp.h"
     15 #include "s390-time.h"
     16 
     17 #define KEYCODE_NO_INP '\0'
     18 #define KEYCODE_ESCAPE '\033'
     19 #define KEYCODE_BACKSP '\177'
     20 #define KEYCODE_ENTER  '\r'
     21 
     22 /* Offsets from zipl fields to zipl banner start */
     23 #define ZIPL_TIMEOUT_OFFSET 138
     24 #define ZIPL_FLAG_OFFSET    140
     25 
     26 #define TOD_CLOCK_MILLISECOND   0x3e8000
     27 
     28 #define LOW_CORE_EXTERNAL_INT_ADDR   0x86
     29 #define CLOCK_COMPARATOR_INT         0X1004
     30 
     31 static uint8_t flag;
     32 static uint64_t timeout;
     33 
     34 static inline void enable_clock_int(void)
     35 {
     36     uint64_t tmp = 0;
     37 
     38     asm volatile(
     39         "stctg      %%c0,%%c0,%0\n"
     40         "oi         6+%0, 0x8\n"
     41         "lctlg      %%c0,%%c0,%0"
     42         : : "Q" (tmp) : "memory"
     43     );
     44 }
     45 
     46 static inline void disable_clock_int(void)
     47 {
     48     uint64_t tmp = 0;
     49 
     50     asm volatile(
     51         "stctg      %%c0,%%c0,%0\n"
     52         "ni         6+%0, 0xf7\n"
     53         "lctlg      %%c0,%%c0,%0"
     54         : : "Q" (tmp) : "memory"
     55     );
     56 }
     57 
     58 static inline void set_clock_comparator(uint64_t time)
     59 {
     60     asm volatile("sckc %0" : : "Q" (time));
     61 }
     62 
     63 static inline bool check_clock_int(void)
     64 {
     65     uint16_t *code = (uint16_t *)LOW_CORE_EXTERNAL_INT_ADDR;
     66 
     67     consume_sclp_int();
     68 
     69     return *code == CLOCK_COMPARATOR_INT;
     70 }
     71 
     72 static int read_prompt(char *buf, size_t len)
     73 {
     74     char inp[2] = {};
     75     uint8_t idx = 0;
     76     uint64_t time;
     77 
     78     if (timeout) {
     79         time = get_clock() + timeout * TOD_CLOCK_MILLISECOND;
     80         set_clock_comparator(time);
     81         enable_clock_int();
     82         timeout = 0;
     83     }
     84 
     85     while (!check_clock_int()) {
     86 
     87         sclp_read(inp, 1); /* Process only one character at a time */
     88 
     89         switch (inp[0]) {
     90         case KEYCODE_NO_INP:
     91         case KEYCODE_ESCAPE:
     92             continue;
     93         case KEYCODE_BACKSP:
     94             if (idx > 0) {
     95                 buf[--idx] = 0;
     96                 sclp_print("\b \b");
     97             }
     98             continue;
     99         case KEYCODE_ENTER:
    100             disable_clock_int();
    101             return idx;
    102         default:
    103             /* Echo input and add to buffer */
    104             if (idx < len) {
    105                 buf[idx++] = inp[0];
    106                 sclp_print(inp);
    107             }
    108         }
    109     }
    110 
    111     disable_clock_int();
    112     *buf = 0;
    113 
    114     return 0;
    115 }
    116 
    117 static int get_index(void)
    118 {
    119     char buf[11];
    120     int len;
    121     int i;
    122 
    123     memset(buf, 0, sizeof(buf));
    124 
    125     sclp_set_write_mask(SCLP_EVENT_MASK_MSG_ASCII, SCLP_EVENT_MASK_MSG_ASCII);
    126 
    127     len = read_prompt(buf, sizeof(buf) - 1);
    128 
    129     sclp_set_write_mask(0, SCLP_EVENT_MASK_MSG_ASCII);
    130 
    131     /* If no input, boot default */
    132     if (len == 0) {
    133         return 0;
    134     }
    135 
    136     /* Check for erroneous input */
    137     for (i = 0; i < len; i++) {
    138         if (!isdigit((unsigned char)buf[i])) {
    139             return -1;
    140         }
    141     }
    142 
    143     return atoui(buf);
    144 }
    145 
    146 static void boot_menu_prompt(bool retry)
    147 {
    148     char tmp[11];
    149 
    150     if (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");
    157     } else {
    158         sclp_print("Please choose:\n");
    159     }
    160 }
    161 
    162 static int get_boot_index(bool *valid_entries)
    163 {
    164     int boot_index;
    165     bool retry = false;
    166     char tmp[5];
    167 
    168     do {
    169         boot_menu_prompt(retry);
    170         boot_index = get_index();
    171         retry = true;
    172     } while (boot_index < 0 || boot_index >= MAX_BOOT_ENTRIES ||
    173              !valid_entries[boot_index]);
    174 
    175     sclp_print("\nBooting entry #");
    176     sclp_print(uitoa(boot_index, tmp, sizeof(tmp)));
    177 
    178     return boot_index;
    179 }
    180 
    181 /* Returns the entry number that was printed */
    182 static int zipl_print_entry(const char *data, size_t len)
    183 {
    184     char buf[len + 2];
    185 
    186     ebcdic_to_ascii(data, buf, len);
    187     buf[len] = '\n';
    188     buf[len + 1] = '\0';
    189 
    190     sclp_print(buf);
    191 
    192     return buf[0] == ' ' ? atoui(buf + 1) : atoui(buf);
    193 }
    194 
    195 int menu_get_zipl_boot_index(const char *menu_data)
    196 {
    197     size_t len;
    198     int entry;
    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);
    202 
    203     if (flag == QIPL_FLAG_BM_OPTS_ZIPL) {
    204         if (!zipl_flag) {
    205             return 0; /* Boot default */
    206         }
    207         /* zipl stores timeout as seconds */
    208         timeout = zipl_timeout * 1000;
    209     }
    210 
    211     /* Print banner */
    212     sclp_print("s390-ccw zIPL Boot Menu\n\n");
    213     menu_data += strlen(menu_data) + 1;
    214 
    215     /* Print entries */
    216     while (*menu_data) {
    217         len = strlen(menu_data);
    218         entry = zipl_print_entry(menu_data, len);
    219         menu_data += len + 1;
    220 
    221         valid_entries[entry] = true;
    222 
    223         if (entry == 0) {
    224             sclp_print("\n");
    225         }
    226     }
    227 
    228     sclp_print("\n");
    229     return get_boot_index(valid_entries);
    230 }
    231 
    232 int menu_get_enum_boot_index(bool *valid_entries)
    233 {
    234     char tmp[3];
    235     int i;
    236 
    237     sclp_print("s390-ccw Enumerated Boot Menu.\n\n");
    238 
    239     for (i = 0; i < MAX_BOOT_ENTRIES; i++) {
    240         if (valid_entries[i]) {
    241             if (i < 10) {
    242                 sclp_print(" ");
    243             }
    244             sclp_print("[");
    245             sclp_print(uitoa(i, tmp, sizeof(tmp)));
    246             sclp_print("]");
    247             if (i == 0) {
    248                 sclp_print(" default\n");
    249             }
    250             sclp_print("\n");
    251         }
    252     }
    253 
    254     sclp_print("\n");
    255     return get_boot_index(valid_entries);
    256 }
    257 
    258 void menu_set_parms(uint8_t boot_menu_flag, uint32_t boot_menu_timeout)
    259 {
    260     flag = boot_menu_flag;
    261     timeout = boot_menu_timeout;
    262 }
    263 
    264 bool menu_is_enabled_zipl(void)
    265 {
    266     return flag & (QIPL_FLAG_BM_OPTS_CMD | QIPL_FLAG_BM_OPTS_ZIPL);
    267 }
    268 
    269 bool menu_is_enabled_enum(void)
    270 {
    271     return flag & QIPL_FLAG_BM_OPTS_CMD;
    272 }