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 #include "ipl.h" 22 23 #define KERN_IMAGE_START 0x010000UL 24 #define KERN_PARM_AREA 0x010480UL 25 #define INITRD_START 0x800000UL 26 #define INITRD_PARM_START 0x010408UL 27 #define INITRD_PARM_SIZE 0x010410UL 28 #define PARMFILE_START 0x001000UL 29 #define ZIPL_IMAGE_START 0x009000UL 30 #define IPL_PSW_MASK (PSW_MASK_32 | PSW_MASK_64) 31 32 #define TYPE_S390_IPL "s390-ipl" 33 #define S390_IPL(obj) \ 34 OBJECT_CHECK(S390IPLState, (obj), TYPE_S390_IPL) 35 #if 0 36 #define S390_IPL_CLASS(klass) \ 37 OBJECT_CLASS_CHECK(S390IPLState, (klass), TYPE_S390_IPL) 38 #define S390_IPL_GET_CLASS(obj) \ 39 OBJECT_GET_CLASS(S390IPLState, (obj), TYPE_S390_IPL) 40 #endif 41 42 typedef struct S390IPLClass { 43 /*< private >*/ 44 SysBusDeviceClass parent_class; 45 /*< public >*/ 46 47 void (*parent_reset) (SysBusDevice *dev); 48 } S390IPLClass; 49 50 typedef struct S390IPLState { 51 /*< private >*/ 52 SysBusDevice parent_obj; 53 uint64_t start_addr; 54 uint64_t bios_start_addr; 55 bool enforce_bios; 56 IplParameterBlock iplb; 57 bool iplb_valid; 58 bool reipl_requested; 59 60 /*< public >*/ 61 char *kernel; 62 char *initrd; 63 char *cmdline; 64 char *firmware; 65 uint8_t cssid; 66 uint8_t ssid; 67 uint16_t devno; 68 } S390IPLState; 69 70 static const VMStateDescription vmstate_iplb = { 71 .name = "ipl/iplb", 72 .version_id = 0, 73 .minimum_version_id = 0, 74 .fields = (VMStateField[]) { 75 VMSTATE_UINT8_ARRAY(reserved1, IplParameterBlock, 110), 76 VMSTATE_UINT16(devno, IplParameterBlock), 77 VMSTATE_UINT8_ARRAY(reserved2, IplParameterBlock, 88), 78 VMSTATE_END_OF_LIST() 79 } 80 }; 81 82 static const VMStateDescription vmstate_ipl = { 83 .name = "ipl", 84 .version_id = 0, 85 .minimum_version_id = 0, 86 .fields = (VMStateField[]) { 87 VMSTATE_UINT64(start_addr, S390IPLState), 88 VMSTATE_UINT64(bios_start_addr, S390IPLState), 89 VMSTATE_STRUCT(iplb, S390IPLState, 0, vmstate_iplb, IplParameterBlock), 90 VMSTATE_BOOL(iplb_valid, S390IPLState), 91 VMSTATE_UINT8(cssid, S390IPLState), 92 VMSTATE_UINT8(ssid, S390IPLState), 93 VMSTATE_UINT16(devno, S390IPLState), 94 VMSTATE_END_OF_LIST() 95 } 96 }; 97 98 static int s390_ipl_init(SysBusDevice *dev) 99 { 100 S390IPLState *ipl = S390_IPL(dev); 101 uint64_t pentry = KERN_IMAGE_START; 102 int kernel_size; 103 104 int bios_size; 105 char *bios_filename; 106 107 /* 108 * Always load the bios if it was enforced, 109 * even if an external kernel has been defined. 110 */ 111 if (!ipl->kernel || ipl->enforce_bios) { 112 if (bios_name == NULL) { 113 bios_name = ipl->firmware; 114 } 115 116 bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); 117 if (bios_filename == NULL) { 118 hw_error("could not find stage1 bootloader\n"); 119 } 120 121 bios_size = load_elf(bios_filename, NULL, NULL, &ipl->bios_start_addr, 122 NULL, NULL, 1, ELF_MACHINE, 0); 123 if (bios_size < 0) { 124 bios_size = load_image_targphys(bios_filename, ZIPL_IMAGE_START, 125 4096); 126 ipl->bios_start_addr = ZIPL_IMAGE_START; 127 if (bios_size > 4096) { 128 hw_error("stage1 bootloader is > 4k\n"); 129 } 130 } 131 g_free(bios_filename); 132 133 if (bios_size == -1) { 134 hw_error("could not load bootloader '%s'\n", bios_name); 135 } 136 137 /* default boot target is the bios */ 138 ipl->start_addr = ipl->bios_start_addr; 139 } 140 141 if (ipl->kernel) { 142 kernel_size = load_elf(ipl->kernel, NULL, NULL, &pentry, NULL, 143 NULL, 1, ELF_MACHINE, 0); 144 if (kernel_size < 0) { 145 kernel_size = load_image_targphys(ipl->kernel, 0, ram_size); 146 } 147 if (kernel_size < 0) { 148 fprintf(stderr, "could not load kernel '%s'\n", ipl->kernel); 149 return -1; 150 } 151 /* 152 * Is it a Linux kernel (starting at 0x10000)? If yes, we fill in the 153 * kernel parameters here as well. Note: For old kernels (up to 3.2) 154 * we can not rely on the ELF entry point - it was 0x800 (the SALIPL 155 * loader) and it won't work. For this case we force it to 0x10000, too. 156 */ 157 if (pentry == KERN_IMAGE_START || pentry == 0x800) { 158 ipl->start_addr = KERN_IMAGE_START; 159 /* Overwrite parameters in the kernel image, which are "rom" */ 160 strcpy(rom_ptr(KERN_PARM_AREA), ipl->cmdline); 161 } else { 162 ipl->start_addr = pentry; 163 } 164 165 if (ipl->initrd) { 166 ram_addr_t initrd_offset; 167 int initrd_size; 168 169 initrd_offset = INITRD_START; 170 while (kernel_size + 0x100000 > initrd_offset) { 171 initrd_offset += 0x100000; 172 } 173 initrd_size = load_image_targphys(ipl->initrd, initrd_offset, 174 ram_size - initrd_offset); 175 if (initrd_size == -1) { 176 fprintf(stderr, "qemu: could not load initrd '%s'\n", 177 ipl->initrd); 178 exit(1); 179 } 180 181 /* 182 * we have to overwrite values in the kernel image, 183 * which are "rom" 184 */ 185 stq_p(rom_ptr(INITRD_PARM_START), initrd_offset); 186 stq_p(rom_ptr(INITRD_PARM_SIZE), initrd_size); 187 } 188 } 189 return 0; 190 } 191 192 static Property s390_ipl_properties[] = { 193 DEFINE_PROP_STRING("kernel", S390IPLState, kernel), 194 DEFINE_PROP_STRING("initrd", S390IPLState, initrd), 195 DEFINE_PROP_STRING("cmdline", S390IPLState, cmdline), 196 DEFINE_PROP_STRING("firmware", S390IPLState, firmware), 197 DEFINE_PROP_BOOL("enforce_bios", S390IPLState, enforce_bios, false), 198 DEFINE_PROP_END_OF_LIST(), 199 }; 200 201 /* 202 * In addition to updating the iplstate, this function returns: 203 * - 0 if system was ipled with external kernel 204 * - -1 if no valid boot device was found 205 * - ccw id of the boot device otherwise 206 */ 207 static uint64_t s390_update_iplstate(CPUS390XState *env, S390IPLState *ipl) 208 { 209 DeviceState *dev_st; 210 211 if (ipl->iplb_valid) { 212 ipl->cssid = 0; 213 ipl->ssid = 0; 214 ipl->devno = ipl->iplb.devno; 215 goto out; 216 } 217 218 if (ipl->kernel) { 219 return 0; 220 } 221 222 dev_st = get_boot_device(0); 223 if (dev_st) { 224 VirtioCcwDevice *ccw_dev = (VirtioCcwDevice *) object_dynamic_cast( 225 OBJECT(qdev_get_parent_bus(dev_st)->parent), 226 TYPE_VIRTIO_CCW_DEVICE); 227 if (ccw_dev) { 228 ipl->cssid = ccw_dev->sch->cssid; 229 ipl->ssid = ccw_dev->sch->ssid; 230 ipl->devno = ccw_dev->sch->devno; 231 goto out; 232 } 233 } 234 235 return -1; 236 out: 237 return ipl->cssid << 24 | ipl->ssid << 16 | ipl->devno; 238 } 239 240 int s390_ipl_update_diag308(IplParameterBlock *iplb) 241 { 242 S390IPLState *ipl; 243 244 ipl = S390_IPL(object_resolve_path(TYPE_S390_IPL, NULL)); 245 if (ipl) { 246 ipl->iplb = *iplb; 247 ipl->iplb_valid = true; 248 return 0; 249 } 250 return -1; 251 } 252 253 IplParameterBlock *s390_ipl_get_iplb(void) 254 { 255 S390IPLState *ipl; 256 257 ipl = S390_IPL(object_resolve_path(TYPE_S390_IPL, NULL)); 258 if (!ipl || !ipl->iplb_valid) { 259 return NULL; 260 } 261 return &ipl->iplb; 262 } 263 264 void s390_reipl_request(void) 265 { 266 S390IPLState *ipl; 267 268 ipl = S390_IPL(object_resolve_path(TYPE_S390_IPL, NULL)); 269 ipl->reipl_requested = true; 270 qemu_system_reset_request(); 271 } 272 273 static void s390_ipl_reset(DeviceState *dev) 274 { 275 S390IPLState *ipl = S390_IPL(dev); 276 S390CPU *cpu = S390_CPU(qemu_get_cpu(0)); 277 CPUS390XState *env = &cpu->env; 278 279 env->psw.addr = ipl->start_addr; 280 env->psw.mask = IPL_PSW_MASK; 281 282 if (!ipl->reipl_requested) { 283 ipl->iplb_valid = false; 284 } 285 ipl->reipl_requested = false; 286 287 if (!ipl->kernel || ipl->iplb_valid) { 288 env->psw.addr = ipl->bios_start_addr; 289 env->regs[7] = s390_update_iplstate(env, ipl); 290 } 291 292 s390_cpu_set_state(CPU_STATE_OPERATING, cpu); 293 } 294 295 static void s390_ipl_class_init(ObjectClass *klass, void *data) 296 { 297 DeviceClass *dc = DEVICE_CLASS(klass); 298 SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); 299 300 k->init = s390_ipl_init; 301 dc->props = s390_ipl_properties; 302 dc->reset = s390_ipl_reset; 303 dc->vmsd = &vmstate_ipl; 304 } 305 306 static const TypeInfo s390_ipl_info = { 307 .class_init = s390_ipl_class_init, 308 .parent = TYPE_SYS_BUS_DEVICE, 309 .name = "s390-ipl", 310 .instance_size = sizeof(S390IPLState), 311 }; 312 313 static void s390_ipl_register_types(void) 314 { 315 type_register_static(&s390_ipl_info); 316 } 317 318 type_init(s390_ipl_register_types) 319