Statistics
| Branch: | Revision:

root / hw / s390x / ipl.c @ d0249ce5

History | View | Annotate | Download (5.2 kB)

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

    
20
#define KERN_IMAGE_START                0x010000UL
21
#define KERN_PARM_AREA                  0x010480UL
22
#define INITRD_START                    0x800000UL
23
#define INITRD_PARM_START               0x010408UL
24
#define INITRD_PARM_SIZE                0x010410UL
25
#define PARMFILE_START                  0x001000UL
26
#define ZIPL_IMAGE_START                0x009000UL
27
#define IPL_PSW_MASK                    (PSW_MASK_32 | PSW_MASK_64)
28

    
29
#define TYPE_S390_IPL "s390-ipl"
30
#define S390_IPL(obj) \
31
    OBJECT_CHECK(S390IPLState, (obj), TYPE_S390_IPL)
32
#if 0
33
#define S390_IPL_CLASS(klass) \
34
    OBJECT_CLASS_CHECK(S390IPLState, (klass), TYPE_S390_IPL)
35
#define S390_IPL_GET_CLASS(obj) \
36
    OBJECT_GET_CLASS(S390IPLState, (obj), TYPE_S390_IPL)
37
#endif
38

    
39
typedef struct S390IPLClass {
40
    /*< private >*/
41
    SysBusDeviceClass parent_class;
42
    /*< public >*/
43

    
44
    void (*parent_reset) (SysBusDevice *dev);
45
} S390IPLClass;
46

    
47
typedef struct S390IPLState {
48
    /*< private >*/
49
    SysBusDevice parent_obj;
50
    uint64_t start_addr;
51

    
52
    /*< public >*/
53
    char *kernel;
54
    char *initrd;
55
    char *cmdline;
56
    char *firmware;
57
} S390IPLState;
58

    
59

    
60
static void s390_ipl_cpu(uint64_t pswaddr)
61
{
62
    S390CPU *cpu = S390_CPU(qemu_get_cpu(0));
63
    CPUS390XState *env = &cpu->env;
64

    
65
    env->psw.addr = pswaddr;
66
    env->psw.mask = IPL_PSW_MASK;
67
    s390_add_running_cpu(cpu);
68
}
69

    
70
static int s390_ipl_init(SysBusDevice *dev)
71
{
72
    S390IPLState *ipl = S390_IPL(dev);
73
    ram_addr_t kernel_size = 0;
74

    
75
    if (!ipl->kernel) {
76
        ram_addr_t bios_size = 0;
77
        char *bios_filename;
78

    
79
        /* Load zipl bootloader */
80
        if (bios_name == NULL) {
81
            bios_name = ipl->firmware;
82
        }
83

    
84
        bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
85
        bios_size = load_elf(bios_filename, NULL, NULL, &ipl->start_addr, NULL,
86
                             NULL, 1, ELF_MACHINE, 0);
87
        if (bios_size == -1UL) {
88
            bios_size = load_image_targphys(bios_filename, ZIPL_IMAGE_START,
89
                                            4096);
90
            ipl->start_addr = ZIPL_IMAGE_START;
91
            if (bios_size > 4096) {
92
                hw_error("stage1 bootloader is > 4k\n");
93
            }
94
        }
95
        g_free(bios_filename);
96

    
97
        if ((long)bios_size < 0) {
98
            hw_error("could not load bootloader '%s'\n", bios_name);
99
        }
100
        return 0;
101
    } else {
102
        kernel_size = load_elf(ipl->kernel, NULL, NULL, NULL, NULL,
103
                               NULL, 1, ELF_MACHINE, 0);
104
        if (kernel_size == -1UL) {
105
            kernel_size = load_image_targphys(ipl->kernel, 0, ram_size);
106
        }
107
        if (kernel_size == -1UL) {
108
            fprintf(stderr, "could not load kernel '%s'\n", ipl->kernel);
109
            return -1;
110
        }
111
        /* we have to overwrite values in the kernel image, which are "rom" */
112
        strcpy(rom_ptr(KERN_PARM_AREA), ipl->cmdline);
113

    
114
        /*
115
         * we can not rely on the ELF entry point, since up to 3.2 this
116
         * value was 0x800 (the SALIPL loader) and it wont work. For
117
         * all (Linux) cases 0x10000 (KERN_IMAGE_START) should be fine.
118
         */
119
        ipl->start_addr = KERN_IMAGE_START;
120
    }
121
    if (ipl->initrd) {
122
        ram_addr_t initrd_offset, initrd_size;
123

    
124
        initrd_offset = INITRD_START;
125
        while (kernel_size + 0x100000 > initrd_offset) {
126
            initrd_offset += 0x100000;
127
        }
128
        initrd_size = load_image_targphys(ipl->initrd, initrd_offset,
129
                                          ram_size - initrd_offset);
130
        if (initrd_size == -1UL) {
131
            fprintf(stderr, "qemu: could not load initrd '%s'\n", ipl->initrd);
132
            exit(1);
133
        }
134

    
135
        /* we have to overwrite values in the kernel image, which are "rom" */
136
        stq_p(rom_ptr(INITRD_PARM_START), initrd_offset);
137
        stq_p(rom_ptr(INITRD_PARM_SIZE), initrd_size);
138
    }
139

    
140
    return 0;
141
}
142

    
143
static Property s390_ipl_properties[] = {
144
    DEFINE_PROP_STRING("kernel", S390IPLState, kernel),
145
    DEFINE_PROP_STRING("initrd", S390IPLState, initrd),
146
    DEFINE_PROP_STRING("cmdline", S390IPLState, cmdline),
147
    DEFINE_PROP_STRING("firmware", S390IPLState, firmware),
148
    DEFINE_PROP_END_OF_LIST(),
149
};
150

    
151
static void s390_ipl_reset(DeviceState *dev)
152
{
153
    S390IPLState *ipl = S390_IPL(dev);
154

    
155
    s390_ipl_cpu(ipl->start_addr);
156
}
157

    
158
static void s390_ipl_class_init(ObjectClass *klass, void *data)
159
{
160
    DeviceClass *dc = DEVICE_CLASS(klass);
161
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
162

    
163
    k->init = s390_ipl_init;
164
    dc->props = s390_ipl_properties;
165
    dc->reset = s390_ipl_reset;
166
    dc->no_user = 1;
167
}
168

    
169
static const TypeInfo s390_ipl_info = {
170
    .class_init = s390_ipl_class_init,
171
    .parent = TYPE_SYS_BUS_DEVICE,
172
    .name  = "s390-ipl",
173
    .instance_size  = sizeof(S390IPLState),
174
};
175

    
176
static void s390_ipl_register_types(void)
177
{
178
    type_register_static(&s390_ipl_info);
179
}
180

    
181
type_init(s390_ipl_register_types)