cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

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
     31static uint8_t flag;
     32static uint64_t timeout;
     33
     34static 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
     46static 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
     58static inline void set_clock_comparator(uint64_t time)
     59{
     60    asm volatile("sckc %0" : : "Q" (time));
     61}
     62
     63static 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
     72static 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
    117static 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
    146static 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
    162static 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 */
    182static 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
    195int 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
    232int 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
    258void 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
    264bool menu_is_enabled_zipl(void)
    265{
    266    return flag & (QIPL_FLAG_BM_OPTS_CMD | QIPL_FLAG_BM_OPTS_ZIPL);
    267}
    268
    269bool menu_is_enabled_enum(void)
    270{
    271    return flag & QIPL_FLAG_BM_OPTS_CMD;
    272}