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