~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to hw/s390x/ipl.c

  • Committer: Phil Dennis-Jordan
  • Author(s): Michael Tokarev
  • Date: 2017-05-23 06:58:03 UTC
  • Revision ID: phil@philjordan.eu-20170523065803-3subwvf3y8kzkjry
Tags: upstream-2.8+dfsg
ImportĀ upstreamĀ versionĀ 2.8+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 "qemu/osdep.h"
 
15
#include "qapi/error.h"
 
16
#include "sysemu/sysemu.h"
 
17
#include "cpu.h"
 
18
#include "elf.h"
 
19
#include "hw/loader.h"
 
20
#include "hw/s390x/virtio-ccw.h"
 
21
#include "hw/s390x/css.h"
 
22
#include "ipl.h"
 
23
 
 
24
#define KERN_IMAGE_START                0x010000UL
 
25
#define KERN_PARM_AREA                  0x010480UL
 
26
#define INITRD_START                    0x800000UL
 
27
#define INITRD_PARM_START               0x010408UL
 
28
#define INITRD_PARM_SIZE                0x010410UL
 
29
#define PARMFILE_START                  0x001000UL
 
30
#define ZIPL_IMAGE_START                0x009000UL
 
31
#define IPL_PSW_MASK                    (PSW_MASK_32 | PSW_MASK_64)
 
32
 
 
33
static bool iplb_extended_needed(void *opaque)
 
34
{
 
35
    S390IPLState *ipl = S390_IPL(object_resolve_path(TYPE_S390_IPL, NULL));
 
36
 
 
37
    return ipl->iplbext_migration;
 
38
}
 
39
 
 
40
static const VMStateDescription vmstate_iplb_extended = {
 
41
    .name = "ipl/iplb_extended",
 
42
    .version_id = 0,
 
43
    .minimum_version_id = 0,
 
44
    .needed = iplb_extended_needed,
 
45
    .fields = (VMStateField[]) {
 
46
        VMSTATE_UINT8_ARRAY(reserved_ext, IplParameterBlock, 4096 - 200),
 
47
        VMSTATE_END_OF_LIST()
 
48
    }
 
49
};
 
50
 
 
51
static const VMStateDescription vmstate_iplb = {
 
52
    .name = "ipl/iplb",
 
53
    .version_id = 0,
 
54
    .minimum_version_id = 0,
 
55
    .fields = (VMStateField[]) {
 
56
        VMSTATE_UINT8_ARRAY(reserved1, IplParameterBlock, 110),
 
57
        VMSTATE_UINT16(devno, IplParameterBlock),
 
58
        VMSTATE_UINT8_ARRAY(reserved2, IplParameterBlock, 88),
 
59
        VMSTATE_END_OF_LIST()
 
60
    },
 
61
    .subsections = (const VMStateDescription*[]) {
 
62
        &vmstate_iplb_extended,
 
63
        NULL
 
64
    }
 
65
};
 
66
 
 
67
static const VMStateDescription vmstate_ipl = {
 
68
    .name = "ipl",
 
69
    .version_id = 0,
 
70
    .minimum_version_id = 0,
 
71
    .fields = (VMStateField[]) {
 
72
        VMSTATE_UINT64(compat_start_addr, S390IPLState),
 
73
        VMSTATE_UINT64(compat_bios_start_addr, S390IPLState),
 
74
        VMSTATE_STRUCT(iplb, S390IPLState, 0, vmstate_iplb, IplParameterBlock),
 
75
        VMSTATE_BOOL(iplb_valid, S390IPLState),
 
76
        VMSTATE_UINT8(cssid, S390IPLState),
 
77
        VMSTATE_UINT8(ssid, S390IPLState),
 
78
        VMSTATE_UINT16(devno, S390IPLState),
 
79
        VMSTATE_END_OF_LIST()
 
80
     }
 
81
};
 
82
 
 
83
static S390IPLState *get_ipl_device(void)
 
84
{
 
85
    return S390_IPL(object_resolve_path_type("", TYPE_S390_IPL, NULL));
 
86
}
 
87
 
 
88
static uint64_t bios_translate_addr(void *opaque, uint64_t srcaddr)
 
89
{
 
90
    uint64_t dstaddr = *(uint64_t *) opaque;
 
91
    /*
 
92
     * Assuming that our s390-ccw.img was linked for starting at address 0,
 
93
     * we can simply add the destination address for the final location
 
94
     */
 
95
    return srcaddr + dstaddr;
 
96
}
 
97
 
 
98
static void s390_ipl_realize(DeviceState *dev, Error **errp)
 
99
{
 
100
    S390IPLState *ipl = S390_IPL(dev);
 
101
    uint64_t pentry = KERN_IMAGE_START;
 
102
    int kernel_size;
 
103
    Error *err = NULL;
 
104
 
 
105
    int bios_size;
 
106
    char *bios_filename;
 
107
 
 
108
    /*
 
109
     * Always load the bios if it was enforced,
 
110
     * even if an external kernel has been defined.
 
111
     */
 
112
    if (!ipl->kernel || ipl->enforce_bios) {
 
113
        uint64_t fwbase = (MIN(ram_size, 0x80000000U) - 0x200000) & ~0xffffUL;
 
114
 
 
115
        if (bios_name == NULL) {
 
116
            bios_name = ipl->firmware;
 
117
        }
 
118
 
 
119
        bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
 
120
        if (bios_filename == NULL) {
 
121
            error_setg(&err, "could not find stage1 bootloader");
 
122
            goto error;
 
123
        }
 
124
 
 
125
        bios_size = load_elf(bios_filename, bios_translate_addr, &fwbase,
 
126
                             &ipl->bios_start_addr, NULL, NULL, 1,
 
127
                             EM_S390, 0, 0);
 
128
        if (bios_size > 0) {
 
129
            /* Adjust ELF start address to final location */
 
130
            ipl->bios_start_addr += fwbase;
 
131
        } else {
 
132
            /* Try to load non-ELF file */
 
133
            bios_size = load_image_targphys(bios_filename, ZIPL_IMAGE_START,
 
134
                                            4096);
 
135
            ipl->bios_start_addr = ZIPL_IMAGE_START;
 
136
        }
 
137
        g_free(bios_filename);
 
138
 
 
139
        if (bios_size == -1) {
 
140
            error_setg(&err, "could not load bootloader '%s'", bios_name);
 
141
            goto error;
 
142
        }
 
143
 
 
144
        /* default boot target is the bios */
 
145
        ipl->start_addr = ipl->bios_start_addr;
 
146
    }
 
147
 
 
148
    if (ipl->kernel) {
 
149
        kernel_size = load_elf(ipl->kernel, NULL, NULL, &pentry, NULL,
 
150
                               NULL, 1, EM_S390, 0, 0);
 
151
        if (kernel_size < 0) {
 
152
            kernel_size = load_image_targphys(ipl->kernel, 0, ram_size);
 
153
        }
 
154
        if (kernel_size < 0) {
 
155
            error_setg(&err, "could not load kernel '%s'", ipl->kernel);
 
156
            goto error;
 
157
        }
 
158
        /*
 
159
         * Is it a Linux kernel (starting at 0x10000)? If yes, we fill in the
 
160
         * kernel parameters here as well. Note: For old kernels (up to 3.2)
 
161
         * we can not rely on the ELF entry point - it was 0x800 (the SALIPL
 
162
         * loader) and it won't work. For this case we force it to 0x10000, too.
 
163
         */
 
164
        if (pentry == KERN_IMAGE_START || pentry == 0x800) {
 
165
            ipl->start_addr = KERN_IMAGE_START;
 
166
            /* Overwrite parameters in the kernel image, which are "rom" */
 
167
            strcpy(rom_ptr(KERN_PARM_AREA), ipl->cmdline);
 
168
        } else {
 
169
            ipl->start_addr = pentry;
 
170
        }
 
171
 
 
172
        if (ipl->initrd) {
 
173
            ram_addr_t initrd_offset;
 
174
            int initrd_size;
 
175
 
 
176
            initrd_offset = INITRD_START;
 
177
            while (kernel_size + 0x100000 > initrd_offset) {
 
178
                initrd_offset += 0x100000;
 
179
            }
 
180
            initrd_size = load_image_targphys(ipl->initrd, initrd_offset,
 
181
                                              ram_size - initrd_offset);
 
182
            if (initrd_size == -1) {
 
183
                error_setg(&err, "could not load initrd '%s'", ipl->initrd);
 
184
                goto error;
 
185
            }
 
186
 
 
187
            /*
 
188
             * we have to overwrite values in the kernel image,
 
189
             * which are "rom"
 
190
             */
 
191
            stq_p(rom_ptr(INITRD_PARM_START), initrd_offset);
 
192
            stq_p(rom_ptr(INITRD_PARM_SIZE), initrd_size);
 
193
        }
 
194
    }
 
195
    /*
 
196
     * Don't ever use the migrated values, they could come from a different
 
197
     * BIOS and therefore don't work. But still migrate the values, so
 
198
     * QEMUs relying on it don't break.
 
199
     */
 
200
    ipl->compat_start_addr = ipl->start_addr;
 
201
    ipl->compat_bios_start_addr = ipl->bios_start_addr;
 
202
    qemu_register_reset(qdev_reset_all_fn, dev);
 
203
error:
 
204
    error_propagate(errp, err);
 
205
}
 
206
 
 
207
static Property s390_ipl_properties[] = {
 
208
    DEFINE_PROP_STRING("kernel", S390IPLState, kernel),
 
209
    DEFINE_PROP_STRING("initrd", S390IPLState, initrd),
 
210
    DEFINE_PROP_STRING("cmdline", S390IPLState, cmdline),
 
211
    DEFINE_PROP_STRING("firmware", S390IPLState, firmware),
 
212
    DEFINE_PROP_BOOL("enforce_bios", S390IPLState, enforce_bios, false),
 
213
    DEFINE_PROP_BOOL("iplbext_migration", S390IPLState, iplbext_migration,
 
214
                     true),
 
215
    DEFINE_PROP_END_OF_LIST(),
 
216
};
 
217
 
 
218
static bool s390_gen_initial_iplb(S390IPLState *ipl)
 
219
{
 
220
    DeviceState *dev_st;
 
221
 
 
222
    dev_st = get_boot_device(0);
 
223
    if (dev_st) {
 
224
        VirtioCcwDevice *virtio_ccw_dev = (VirtioCcwDevice *)
 
225
            object_dynamic_cast(OBJECT(qdev_get_parent_bus(dev_st)->parent),
 
226
                TYPE_VIRTIO_CCW_DEVICE);
 
227
        SCSIDevice *sd = (SCSIDevice *) object_dynamic_cast(OBJECT(dev_st),
 
228
                                                            TYPE_SCSI_DEVICE);
 
229
        if (virtio_ccw_dev) {
 
230
            CcwDevice *ccw_dev = CCW_DEVICE(virtio_ccw_dev);
 
231
 
 
232
            ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_CCW_LEN);
 
233
            ipl->iplb.blk0_len =
 
234
                cpu_to_be32(S390_IPLB_MIN_CCW_LEN - S390_IPLB_HEADER_LEN);
 
235
            ipl->iplb.pbt = S390_IPL_TYPE_CCW;
 
236
            ipl->iplb.ccw.devno = cpu_to_be16(ccw_dev->sch->devno);
 
237
            ipl->iplb.ccw.ssid = ccw_dev->sch->ssid & 3;
 
238
            return true;
 
239
        } else if (sd) {
 
240
            SCSIBus *bus = scsi_bus_from_device(sd);
 
241
            VirtIOSCSI *vdev = container_of(bus, VirtIOSCSI, bus);
 
242
            VirtIOSCSICcw *scsi_ccw = container_of(vdev, VirtIOSCSICcw, vdev);
 
243
            CcwDevice *ccw_dev = CCW_DEVICE(scsi_ccw);
 
244
 
 
245
            ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN);
 
246
            ipl->iplb.blk0_len =
 
247
                cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN - S390_IPLB_HEADER_LEN);
 
248
            ipl->iplb.pbt = S390_IPL_TYPE_QEMU_SCSI;
 
249
            ipl->iplb.scsi.lun = cpu_to_be32(sd->lun);
 
250
            ipl->iplb.scsi.target = cpu_to_be16(sd->id);
 
251
            ipl->iplb.scsi.channel = cpu_to_be16(sd->channel);
 
252
            ipl->iplb.scsi.devno = cpu_to_be16(ccw_dev->sch->devno);
 
253
            ipl->iplb.scsi.ssid = ccw_dev->sch->ssid & 3;
 
254
            return true;
 
255
        }
 
256
    }
 
257
 
 
258
    return false;
 
259
}
 
260
 
 
261
void s390_ipl_update_diag308(IplParameterBlock *iplb)
 
262
{
 
263
    S390IPLState *ipl = get_ipl_device();
 
264
 
 
265
    ipl->iplb = *iplb;
 
266
    ipl->iplb_valid = true;
 
267
}
 
268
 
 
269
IplParameterBlock *s390_ipl_get_iplb(void)
 
270
{
 
271
    S390IPLState *ipl = get_ipl_device();
 
272
 
 
273
    if (!ipl->iplb_valid) {
 
274
        return NULL;
 
275
    }
 
276
    return &ipl->iplb;
 
277
}
 
278
 
 
279
void s390_reipl_request(void)
 
280
{
 
281
    S390IPLState *ipl = get_ipl_device();
 
282
 
 
283
    ipl->reipl_requested = true;
 
284
    qemu_system_reset_request();
 
285
}
 
286
 
 
287
void s390_ipl_prepare_cpu(S390CPU *cpu)
 
288
{
 
289
    S390IPLState *ipl = get_ipl_device();
 
290
 
 
291
    cpu->env.psw.addr = ipl->start_addr;
 
292
    cpu->env.psw.mask = IPL_PSW_MASK;
 
293
 
 
294
    if (!ipl->kernel || ipl->iplb_valid) {
 
295
        cpu->env.psw.addr = ipl->bios_start_addr;
 
296
        if (!ipl->iplb_valid) {
 
297
            ipl->iplb_valid = s390_gen_initial_iplb(ipl);
 
298
        }
 
299
    }
 
300
}
 
301
 
 
302
static void s390_ipl_reset(DeviceState *dev)
 
303
{
 
304
    S390IPLState *ipl = S390_IPL(dev);
 
305
 
 
306
    if (!ipl->reipl_requested) {
 
307
        ipl->iplb_valid = false;
 
308
        memset(&ipl->iplb, 0, sizeof(IplParameterBlock));
 
309
    }
 
310
    ipl->reipl_requested = false;
 
311
}
 
312
 
 
313
static void s390_ipl_class_init(ObjectClass *klass, void *data)
 
314
{
 
315
    DeviceClass *dc = DEVICE_CLASS(klass);
 
316
 
 
317
    dc->realize = s390_ipl_realize;
 
318
    dc->props = s390_ipl_properties;
 
319
    dc->reset = s390_ipl_reset;
 
320
    dc->vmsd = &vmstate_ipl;
 
321
    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
 
322
}
 
323
 
 
324
static const TypeInfo s390_ipl_info = {
 
325
    .class_init = s390_ipl_class_init,
 
326
    .parent = TYPE_DEVICE,
 
327
    .name  = TYPE_S390_IPL,
 
328
    .instance_size  = sizeof(S390IPLState),
 
329
};
 
330
 
 
331
static void s390_ipl_register_types(void)
 
332
{
 
333
    type_register_static(&s390_ipl_info);
 
334
}
 
335
 
 
336
type_init(s390_ipl_register_types)