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-ccw.h"
  13#include "virtio.h"
  14
  15char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
  16static SubChannelId blk_schid = { .one = 1 };
  17IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
  18static char loadparm[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
  19
  20/*
  21 * Priniciples of Operations (SA22-7832-09) chapter 17 requires that
  22 * a subsystem-identification is at 184-187 and bytes 188-191 are zero
  23 * after list-directed-IPL and ccw-IPL.
  24 */
  25void write_subsystem_identification(void)
  26{
  27    SubChannelId *schid = (SubChannelId *) 184;
  28    uint32_t *zeroes = (uint32_t *) 188;
  29
  30    *schid = blk_schid;
  31    *zeroes = 0;
  32}
  33
  34void panic(const char *string)
  35{
  36    sclp_print(string);
  37    disabled_wait();
  38    while (1) { }
  39}
  40
  41unsigned int get_loadparm_index(void)
  42{
  43    const char *lp = loadparm;
  44    int i;
  45    unsigned int idx = 0;
  46
  47    for (i = 0; i < 8; i++) {
  48        char c = lp[i];
  49
  50        if (c < '0' || c > '9') {
  51            break;
  52        }
  53
  54        idx *= 10;
  55        idx += c - '0';
  56    }
  57
  58    return idx;
  59}
  60
  61static bool find_dev(Schib *schib, int dev_no)
  62{
  63    int i, r;
  64
  65    for (i = 0; i < 0x10000; i++) {
  66        blk_schid.sch_no = i;
  67        r = stsch_err(blk_schid, schib);
  68        if ((r == 3) || (r == -EIO)) {
  69            break;
  70        }
  71        if (!schib->pmcw.dnv) {
  72            continue;
  73        }
  74        if (!virtio_is_supported(blk_schid)) {
  75            continue;
  76        }
  77        /* Skip net devices since no IPLB is created and therefore no
  78         * no network bootloader has been loaded
  79         */
  80        if (virtio_get_device_type() == VIRTIO_ID_NET && dev_no < 0) {
  81            continue;
  82        }
  83        if ((dev_no < 0) || (schib->pmcw.dev == dev_no)) {
  84            return true;
  85        }
  86    }
  87
  88    return false;
  89}
  90
  91static void virtio_setup(void)
  92{
  93    Schib schib;
  94    int ssid;
  95    bool found = false;
  96    uint16_t dev_no;
  97    char ldp[] = "LOADPARM=[________]\n";
  98    VDev *vdev = virtio_get_device();
  99
 100    /*
 101     * We unconditionally enable mss support. In every sane configuration,
 102     * this will succeed; and even if it doesn't, stsch_err() can deal
 103     * with the consequences.
 104     */
 105    enable_mss_facility();
 106
 107    sclp_get_loadparm_ascii(loadparm);
 108    memcpy(ldp + 10, loadparm, 8);
 109    sclp_print(ldp);
 110
 111    if (store_iplb(&iplb)) {
 112        switch (iplb.pbt) {
 113        case S390_IPL_TYPE_CCW:
 114            dev_no = iplb.ccw.devno;
 115            debug_print_int("device no. ", dev_no);
 116            blk_schid.ssid = iplb.ccw.ssid & 0x3;
 117            debug_print_int("ssid ", blk_schid.ssid);
 118            found = find_dev(&schib, dev_no);
 119            break;
 120        case S390_IPL_TYPE_QEMU_SCSI:
 121            vdev->scsi_device_selected = true;
 122            vdev->selected_scsi_device.channel = iplb.scsi.channel;
 123            vdev->selected_scsi_device.target = iplb.scsi.target;
 124            vdev->selected_scsi_device.lun = iplb.scsi.lun;
 125            blk_schid.ssid = iplb.scsi.ssid & 0x3;
 126            found = find_dev(&schib, iplb.scsi.devno);
 127            break;
 128        default:
 129            panic("List-directed IPL not supported yet!\n");
 130        }
 131    } else {
 132        for (ssid = 0; ssid < 0x3; ssid++) {
 133            blk_schid.ssid = ssid;
 134            found = find_dev(&schib, -1);
 135            if (found) {
 136                break;
 137            }
 138        }
 139    }
 140
 141    IPL_assert(found, "No virtio device found");
 142
 143    if (virtio_get_device_type() == VIRTIO_ID_NET) {
 144        sclp_print("Network boot device detected\n");
 145        vdev->netboot_start_addr = iplb.ccw.netboot_start_addr;
 146    } else {
 147        virtio_blk_setup_device(blk_schid);
 148
 149        IPL_assert(virtio_ipl_disk_is_valid(), "No valid IPL device detected");
 150    }
 151}
 152
 153int main(void)
 154{
 155    sclp_setup();
 156    virtio_setup();
 157
 158    zipl_load(); /* no return */
 159
 160    panic("Failed to load OS from hard disk\n");
 161    return 0; /* make compiler happy */
 162}
 163