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