qemu/hw/s390x/ipl.c
<<
>>
Prefs
   1/*
   2 * bootloader support
   3 *
   4 * Copyright IBM, Corp. 2012
   5 *
   6 * Authors:
   7 *  Christian Borntraeger <borntraeger@de.ibm.com>
   8 *
   9 * This work is licensed under the terms of the GNU GPL, version 2 or (at your
  10 * option) any later version.  See the COPYING file in the top-level directory.
  11 *
  12 */
  13
  14#include "sysemu/sysemu.h"
  15#include "cpu.h"
  16#include "elf.h"
  17#include "hw/loader.h"
  18#include "hw/sysbus.h"
  19#include "hw/s390x/virtio-ccw.h"
  20#include "hw/s390x/css.h"
  21
  22#define KERN_IMAGE_START                0x010000UL
  23#define KERN_PARM_AREA                  0x010480UL
  24#define INITRD_START                    0x800000UL
  25#define INITRD_PARM_START               0x010408UL
  26#define INITRD_PARM_SIZE                0x010410UL
  27#define PARMFILE_START                  0x001000UL
  28#define ZIPL_IMAGE_START                0x009000UL
  29#define IPL_PSW_MASK                    (PSW_MASK_32 | PSW_MASK_64)
  30
  31#define TYPE_S390_IPL "s390-ipl"
  32#define S390_IPL(obj) \
  33    OBJECT_CHECK(S390IPLState, (obj), TYPE_S390_IPL)
  34#if 0
  35#define S390_IPL_CLASS(klass) \
  36    OBJECT_CLASS_CHECK(S390IPLState, (klass), TYPE_S390_IPL)
  37#define S390_IPL_GET_CLASS(obj) \
  38    OBJECT_GET_CLASS(S390IPLState, (obj), TYPE_S390_IPL)
  39#endif
  40
  41typedef struct S390IPLClass {
  42    /*< private >*/
  43    SysBusDeviceClass parent_class;
  44    /*< public >*/
  45
  46    void (*parent_reset) (SysBusDevice *dev);
  47} S390IPLClass;
  48
  49typedef struct S390IPLState {
  50    /*< private >*/
  51    SysBusDevice parent_obj;
  52    uint64_t start_addr;
  53
  54    /*< public >*/
  55    char *kernel;
  56    char *initrd;
  57    char *cmdline;
  58    char *firmware;
  59} S390IPLState;
  60
  61
  62static int s390_ipl_init(SysBusDevice *dev)
  63{
  64    S390IPLState *ipl = S390_IPL(dev);
  65    ram_addr_t kernel_size = 0;
  66
  67    if (!ipl->kernel) {
  68        ram_addr_t bios_size = 0;
  69        char *bios_filename;
  70
  71        /* Load zipl bootloader */
  72        if (bios_name == NULL) {
  73            bios_name = ipl->firmware;
  74        }
  75
  76        bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
  77        if (bios_filename == NULL) {
  78            hw_error("could not find stage1 bootloader\n");
  79        }
  80
  81        bios_size = load_elf(bios_filename, NULL, NULL, &ipl->start_addr, NULL,
  82                             NULL, 1, ELF_MACHINE, 0);
  83        if (bios_size == -1UL) {
  84            bios_size = load_image_targphys(bios_filename, ZIPL_IMAGE_START,
  85                                            4096);
  86            ipl->start_addr = ZIPL_IMAGE_START;
  87            if (bios_size > 4096) {
  88                hw_error("stage1 bootloader is > 4k\n");
  89            }
  90        }
  91        g_free(bios_filename);
  92
  93        if ((long)bios_size < 0) {
  94            hw_error("could not load bootloader '%s'\n", bios_name);
  95        }
  96        return 0;
  97    } else {
  98        kernel_size = load_elf(ipl->kernel, NULL, NULL, NULL, NULL,
  99                               NULL, 1, ELF_MACHINE, 0);
 100        if (kernel_size == -1UL) {
 101            kernel_size = load_image_targphys(ipl->kernel, 0, ram_size);
 102        }
 103        if (kernel_size == -1UL) {
 104            fprintf(stderr, "could not load kernel '%s'\n", ipl->kernel);
 105            return -1;
 106        }
 107        /* we have to overwrite values in the kernel image, which are "rom" */
 108        strcpy(rom_ptr(KERN_PARM_AREA), ipl->cmdline);
 109
 110        /*
 111         * we can not rely on the ELF entry point, since up to 3.2 this
 112         * value was 0x800 (the SALIPL loader) and it wont work. For
 113         * all (Linux) cases 0x10000 (KERN_IMAGE_START) should be fine.
 114         */
 115        ipl->start_addr = KERN_IMAGE_START;
 116    }
 117    if (ipl->initrd) {
 118        ram_addr_t initrd_offset, initrd_size;
 119
 120        initrd_offset = INITRD_START;
 121        while (kernel_size + 0x100000 > initrd_offset) {
 122            initrd_offset += 0x100000;
 123        }
 124        initrd_size = load_image_targphys(ipl->initrd, initrd_offset,
 125                                          ram_size - initrd_offset);
 126        if (initrd_size == -1UL) {
 127            fprintf(stderr, "qemu: could not load initrd '%s'\n", ipl->initrd);
 128            exit(1);
 129        }
 130
 131        /* we have to overwrite values in the kernel image, which are "rom" */
 132        stq_p(rom_ptr(INITRD_PARM_START), initrd_offset);
 133        stq_p(rom_ptr(INITRD_PARM_SIZE), initrd_size);
 134    }
 135
 136    return 0;
 137}
 138
 139static Property s390_ipl_properties[] = {
 140    DEFINE_PROP_STRING("kernel", S390IPLState, kernel),
 141    DEFINE_PROP_STRING("initrd", S390IPLState, initrd),
 142    DEFINE_PROP_STRING("cmdline", S390IPLState, cmdline),
 143    DEFINE_PROP_STRING("firmware", S390IPLState, firmware),
 144    DEFINE_PROP_END_OF_LIST(),
 145};
 146
 147static void s390_ipl_reset(DeviceState *dev)
 148{
 149    S390IPLState *ipl = S390_IPL(dev);
 150    S390CPU *cpu = S390_CPU(qemu_get_cpu(0));
 151    CPUS390XState *env = &cpu->env;
 152
 153    env->psw.addr = ipl->start_addr;
 154    env->psw.mask = IPL_PSW_MASK;
 155
 156    if (!ipl->kernel) {
 157        /* Tell firmware, if there is a preferred boot device */
 158        env->regs[7] = -1;
 159        DeviceState *dev_st = get_boot_device(0);
 160        if (dev_st) {
 161            VirtioCcwDevice *ccw_dev = (VirtioCcwDevice *) object_dynamic_cast(
 162                OBJECT(qdev_get_parent_bus(dev_st)->parent),
 163                TYPE_VIRTIO_CCW_DEVICE);
 164
 165            if (ccw_dev) {
 166                env->regs[7] = ccw_dev->sch->cssid << 24 |
 167                               ccw_dev->sch->ssid << 16 |
 168                               ccw_dev->sch->devno;
 169            }
 170        }
 171    }
 172
 173    s390_add_running_cpu(cpu);
 174}
 175
 176static void s390_ipl_class_init(ObjectClass *klass, void *data)
 177{
 178    DeviceClass *dc = DEVICE_CLASS(klass);
 179    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 180
 181    k->init = s390_ipl_init;
 182    dc->props = s390_ipl_properties;
 183    dc->reset = s390_ipl_reset;
 184    dc->no_user = 1;
 185}
 186
 187static const TypeInfo s390_ipl_info = {
 188    .class_init = s390_ipl_class_init,
 189    .parent = TYPE_SYS_BUS_DEVICE,
 190    .name  = "s390-ipl",
 191    .instance_size  = sizeof(S390IPLState),
 192};
 193
 194static void s390_ipl_register_types(void)
 195{
 196    type_register_static(&s390_ipl_info);
 197}
 198
 199type_init(s390_ipl_register_types)
 200