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