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

main.c (7860B)


      1/*
      2 * S390 virtio-ccw loading program
      3 *
      4 * Copyright (c) 2013 Alexander Graf <agraf@suse.de>
      5 *
      6 * This work is licensed under the terms of the GNU GPL, version 2 or (at
      7 * your option) any later version. See the COPYING file in the top-level
      8 * directory.
      9 */
     10
     11#include "libc.h"
     12#include "helper.h"
     13#include "s390-arch.h"
     14#include "s390-ccw.h"
     15#include "cio.h"
     16#include "virtio.h"
     17#include "dasd-ipl.h"
     18
     19char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
     20static SubChannelId blk_schid = { .one = 1 };
     21static char loadparm_str[LOADPARM_LEN + 1];
     22QemuIplParameters qipl;
     23IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
     24static bool have_iplb;
     25static uint16_t cutype;
     26LowCore *lowcore; /* Yes, this *is* a pointer to address 0 */
     27
     28#define LOADPARM_PROMPT "PROMPT  "
     29#define LOADPARM_EMPTY  "        "
     30#define BOOT_MENU_FLAG_MASK (QIPL_FLAG_BM_OPTS_CMD | QIPL_FLAG_BM_OPTS_ZIPL)
     31
     32/*
     33 * Principles of Operations (SA22-7832-09) chapter 17 requires that
     34 * a subsystem-identification is at 184-187 and bytes 188-191 are zero
     35 * after list-directed-IPL and ccw-IPL.
     36 */
     37void write_subsystem_identification(void)
     38{
     39    lowcore->subchannel_id = blk_schid.sch_id;
     40    lowcore->subchannel_nr = blk_schid.sch_no;
     41    lowcore->io_int_parm = 0;
     42}
     43
     44void write_iplb_location(void)
     45{
     46    if (cutype == CU_TYPE_VIRTIO && virtio_get_device_type() != VIRTIO_ID_NET) {
     47        lowcore->ptr_iplb = ptr2u32(&iplb);
     48    }
     49}
     50
     51unsigned int get_loadparm_index(void)
     52{
     53    return atoui(loadparm_str);
     54}
     55
     56static int is_dev_possibly_bootable(int dev_no, int sch_no)
     57{
     58    bool is_virtio;
     59    Schib schib;
     60    int r;
     61
     62    blk_schid.sch_no = sch_no;
     63    r = stsch_err(blk_schid, &schib);
     64    if (r == 3 || r == -EIO) {
     65        return -ENODEV;
     66    }
     67    if (!schib.pmcw.dnv) {
     68        return false;
     69    }
     70
     71    enable_subchannel(blk_schid);
     72    cutype = cu_type(blk_schid);
     73
     74    /*
     75     * Note: we always have to run virtio_is_supported() here to make
     76     * sure that the vdev.senseid data gets pre-initialized correctly
     77     */
     78    is_virtio = virtio_is_supported(blk_schid);
     79
     80    /* No specific devno given, just return whether the device is possibly bootable */
     81    if (dev_no < 0) {
     82        switch (cutype) {
     83        case CU_TYPE_VIRTIO:
     84            if (is_virtio) {
     85                /*
     86                 * Skip net devices since no IPLB is created and therefore
     87                 * no network bootloader has been loaded
     88                 */
     89                if (virtio_get_device_type() != VIRTIO_ID_NET) {
     90                    return true;
     91                }
     92            }
     93            return false;
     94        case CU_TYPE_DASD_3990:
     95        case CU_TYPE_DASD_2107:
     96            return true;
     97        default:
     98            return false;
     99        }
    100    }
    101
    102    /* Caller asked for a specific devno */
    103    if (schib.pmcw.dev == dev_no) {
    104        return true;
    105    }
    106
    107    return false;
    108}
    109
    110/*
    111 * Find the subchannel connected to the given device (dev_no) and fill in the
    112 * subchannel information block (schib) with the connected subchannel's info.
    113 * NOTE: The global variable blk_schid is updated to contain the subchannel
    114 * information.
    115 *
    116 * If the caller gives dev_no=-1 then the user did not specify a boot device.
    117 * In this case we'll just use the first potentially bootable device we find.
    118 */
    119static bool find_subch(int dev_no)
    120{
    121    int i, r;
    122
    123    for (i = 0; i < 0x10000; i++) {
    124        r = is_dev_possibly_bootable(dev_no, i);
    125        if (r < 0) {
    126            break;
    127        }
    128        if (r == true) {
    129            return true;
    130        }
    131    }
    132
    133    return false;
    134}
    135
    136static void menu_setup(void)
    137{
    138    if (memcmp(loadparm_str, LOADPARM_PROMPT, LOADPARM_LEN) == 0) {
    139        menu_set_parms(QIPL_FLAG_BM_OPTS_CMD, 0);
    140        return;
    141    }
    142
    143    /* If loadparm was set to any other value, then do not enable menu */
    144    if (memcmp(loadparm_str, LOADPARM_EMPTY, LOADPARM_LEN) != 0) {
    145        return;
    146    }
    147
    148    switch (iplb.pbt) {
    149    case S390_IPL_TYPE_CCW:
    150    case S390_IPL_TYPE_QEMU_SCSI:
    151        menu_set_parms(qipl.qipl_flags & BOOT_MENU_FLAG_MASK,
    152                       qipl.boot_menu_timeout);
    153        return;
    154    }
    155}
    156
    157/*
    158 * Initialize the channel I/O subsystem so we can talk to our ipl/boot device.
    159 */
    160static void css_setup(void)
    161{
    162    /*
    163     * Unconditionally enable mss support. In every sane configuration this
    164     * will succeed; and even if it doesn't, stsch_err() can handle it.
    165     */
    166    enable_mss_facility();
    167}
    168
    169/*
    170 * Collect various pieces of information from the hypervisor/hardware that
    171 * we'll use to determine exactly how we'll boot.
    172 */
    173static void boot_setup(void)
    174{
    175    char lpmsg[] = "LOADPARM=[________]\n";
    176
    177    sclp_get_loadparm_ascii(loadparm_str);
    178    memcpy(lpmsg + 10, loadparm_str, 8);
    179    sclp_print(lpmsg);
    180
    181    /*
    182     * Clear out any potential S390EP magic (see jump_to_low_kernel()),
    183     * so we don't taint our decision-making process during a reboot.
    184     */
    185    memset((char *)S390EP, 0, 6);
    186
    187    have_iplb = store_iplb(&iplb);
    188}
    189
    190static void find_boot_device(void)
    191{
    192    VDev *vdev = virtio_get_device();
    193    bool found;
    194
    195    switch (iplb.pbt) {
    196    case S390_IPL_TYPE_CCW:
    197        debug_print_int("device no. ", iplb.ccw.devno);
    198        blk_schid.ssid = iplb.ccw.ssid & 0x3;
    199        debug_print_int("ssid ", blk_schid.ssid);
    200        found = find_subch(iplb.ccw.devno);
    201        break;
    202    case S390_IPL_TYPE_QEMU_SCSI:
    203        vdev->scsi_device_selected = true;
    204        vdev->selected_scsi_device.channel = iplb.scsi.channel;
    205        vdev->selected_scsi_device.target = iplb.scsi.target;
    206        vdev->selected_scsi_device.lun = iplb.scsi.lun;
    207        blk_schid.ssid = iplb.scsi.ssid & 0x3;
    208        found = find_subch(iplb.scsi.devno);
    209        break;
    210    default:
    211        panic("List-directed IPL not supported yet!\n");
    212    }
    213
    214    IPL_assert(found, "Boot device not found\n");
    215}
    216
    217static int virtio_setup(void)
    218{
    219    VDev *vdev = virtio_get_device();
    220    QemuIplParameters *early_qipl = (QemuIplParameters *)QIPL_ADDRESS;
    221
    222    memcpy(&qipl, early_qipl, sizeof(QemuIplParameters));
    223
    224    if (have_iplb) {
    225        menu_setup();
    226    }
    227
    228    if (virtio_get_device_type() == VIRTIO_ID_NET) {
    229        sclp_print("Network boot device detected\n");
    230        vdev->netboot_start_addr = qipl.netboot_start_addr;
    231    } else {
    232        int ret = virtio_blk_setup_device(blk_schid);
    233        if (ret) {
    234            return ret;
    235        }
    236        IPL_assert(virtio_ipl_disk_is_valid(), "No valid IPL device detected");
    237    }
    238
    239    return 0;
    240}
    241
    242static void ipl_boot_device(void)
    243{
    244    switch (cutype) {
    245    case CU_TYPE_DASD_3990:
    246    case CU_TYPE_DASD_2107:
    247        dasd_ipl(blk_schid, cutype); /* no return */
    248        break;
    249    case CU_TYPE_VIRTIO:
    250        if (virtio_setup() == 0) {
    251            zipl_load();             /* Only returns in case of errors */
    252        }
    253        break;
    254    default:
    255        print_int("Attempting to boot from unexpected device type", cutype);
    256        panic("\nBoot failed.\n");
    257    }
    258}
    259
    260/*
    261 * No boot device has been specified, so we have to scan through the
    262 * channels to find one.
    263 */
    264static void probe_boot_device(void)
    265{
    266    int ssid, sch_no, ret;
    267
    268    for (ssid = 0; ssid < 0x3; ssid++) {
    269        blk_schid.ssid = ssid;
    270        for (sch_no = 0; sch_no < 0x10000; sch_no++) {
    271            ret = is_dev_possibly_bootable(-1, sch_no);
    272            if (ret < 0) {
    273                break;
    274            }
    275            if (ret == true) {
    276                ipl_boot_device();      /* Only returns if unsuccessful */
    277            }
    278        }
    279    }
    280
    281    sclp_print("Could not find a suitable boot device (none specified)\n");
    282}
    283
    284int main(void)
    285{
    286    sclp_setup();
    287    css_setup();
    288    boot_setup();
    289    if (have_iplb) {
    290        find_boot_device();
    291        ipl_boot_device();
    292    } else {
    293        probe_boot_device();
    294    }
    295
    296    panic("Failed to load OS from hard disk\n");
    297    return 0; /* make compiler happy */
    298}