mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-09 10:34:58 -06:00
* Allow multiple boot devices (via bootindex properties) on s390x
* Avoid TEXTREL relocations in the s390-ccw.img firmware -----BEGIN PGP SIGNATURE----- iQJFBAABCAAvFiEEJ7iIR+7gJQEY8+q5LtnXdP5wLbUFAmcY9vsRHHRodXRoQHJl ZGhhdC5jb20ACgkQLtnXdP5wLbWnBQ//eM0RPHgp3OCbCy42HYp569RdHvXE69BS 7iO8uu7MGRKIAHJqqmDwFDfhfMtoJkfjq9bQpb+pmIUe50r2NAC9na9+bjIc2bK+ sxHvS5PTZiQcPOiGwAmp3lEheFPWi6sugYVruO+6syGLJdoa39Vnj71pF86lJ6dk HFltOqa0lG3YWzueKXInLQnpRaIvPzjJVEUuNRk5H6ai0woItWvrPK82HMcKXSu5 mwJiGP2dmwvZw3nC8GsNKbxxZNc2gEM6tFFozbsaE/Yfzmg/S4kHexzjSGd7svT7 kex65F9aqiK3x1WrWwuCCU6D8qEkNqzXezNlmedvgcMokkdd8Xwlqvw2Ng3sbF7i 466jEdq0CuAiEhO6AvSYrEDpI8trWxj4EtxcjfqltUVR/SYFcW9hRdx99VwrRCo2 woazKmHz7Hu6uS5+JPtfD+KxalIDXNXevY6uGyaWJp8TahDkUCim/gJ+Zb7Mx1iq Vrx/rCm1oV8v1xrn8NWTGewA8emVjbLI3PuDtPh9FWRpER7ekn+dDUinzeUl2wWK +USqIE2ougo1etRm7FAkyWEv9F/GjGTd8OegIGD6etWBNBq/YVMNwX1gjw4Q0qhM +7KmXLBKkuEBYSo4scSGt6DcasIUL93sc6rnWgiH3S/qMAYyKempKPkoROYQI8yA 0EI+x1fxW1w= =mWW5 -----END PGP SIGNATURE----- Merge tag 'pull-request-2024-10-23' of https://gitlab.com/thuth/qemu into staging * Allow multiple boot devices (via bootindex properties) on s390x * Avoid TEXTREL relocations in the s390-ccw.img firmware # -----BEGIN PGP SIGNATURE----- # # iQJFBAABCAAvFiEEJ7iIR+7gJQEY8+q5LtnXdP5wLbUFAmcY9vsRHHRodXRoQHJl # ZGhhdC5jb20ACgkQLtnXdP5wLbWnBQ//eM0RPHgp3OCbCy42HYp569RdHvXE69BS # 7iO8uu7MGRKIAHJqqmDwFDfhfMtoJkfjq9bQpb+pmIUe50r2NAC9na9+bjIc2bK+ # sxHvS5PTZiQcPOiGwAmp3lEheFPWi6sugYVruO+6syGLJdoa39Vnj71pF86lJ6dk # HFltOqa0lG3YWzueKXInLQnpRaIvPzjJVEUuNRk5H6ai0woItWvrPK82HMcKXSu5 # mwJiGP2dmwvZw3nC8GsNKbxxZNc2gEM6tFFozbsaE/Yfzmg/S4kHexzjSGd7svT7 # kex65F9aqiK3x1WrWwuCCU6D8qEkNqzXezNlmedvgcMokkdd8Xwlqvw2Ng3sbF7i # 466jEdq0CuAiEhO6AvSYrEDpI8trWxj4EtxcjfqltUVR/SYFcW9hRdx99VwrRCo2 # woazKmHz7Hu6uS5+JPtfD+KxalIDXNXevY6uGyaWJp8TahDkUCim/gJ+Zb7Mx1iq # Vrx/rCm1oV8v1xrn8NWTGewA8emVjbLI3PuDtPh9FWRpER7ekn+dDUinzeUl2wWK # +USqIE2ougo1etRm7FAkyWEv9F/GjGTd8OegIGD6etWBNBq/YVMNwX1gjw4Q0qhM # +7KmXLBKkuEBYSo4scSGt6DcasIUL93sc6rnWgiH3S/qMAYyKempKPkoROYQI8yA # 0EI+x1fxW1w= # =mWW5 # -----END PGP SIGNATURE----- # gpg: Signature made Wed 23 Oct 2024 14:15:39 BST # gpg: using RSA key 27B88847EEE0250118F3EAB92ED9D774FE702DB5 # gpg: issuer "thuth@redhat.com" # gpg: Good signature from "Thomas Huth <th.huth@gmx.de>" [full] # gpg: aka "Thomas Huth <thuth@redhat.com>" [full] # gpg: aka "Thomas Huth <huth@tuxfamily.org>" [full] # gpg: aka "Thomas Huth <th.huth@posteo.de>" [unknown] # Primary key fingerprint: 27B8 8847 EEE0 2501 18F3 EAB9 2ED9 D774 FE70 2DB5 * tag 'pull-request-2024-10-23' of https://gitlab.com/thuth/qemu: (23 commits) pc-bios/s390-ccw: Update s390-ccw.img with the full boot order support feature pc-bios/s390-ccw: Introduce `EXTRA_LDFLAGS` pc-bios/s390-ccw: Don't generate TEXTRELs pc-bios/s390-ccw: Clarify alignment is in bytes tests/qtest: Add s390x boot order tests to cdrom-test.c docs/system: Update documentation for s390x IPL pc-bios/s390x: Enable multi-device boot loop s390x: Rebuild IPLB for SCSI device directly from DIAG308 hw/s390x: Build an IPLB for each boot device s390x: Add individual loadparm assignment to CCW device include/hw/s390x: Add include files for common IPL structs pc-bios/s390-ccw: Enable failed IPL to return after error pc-bios/s390-ccw: Remove panics from Netboot IPL path pc-bios/s390-ccw: Remove panics from DASD IPL path pc-bios/s390-ccw: Remove panics from SCSI IPL path pc-bios/s390-ccw: Remove panics from ECKD IPL path pc-bios/s390-ccw: Remove panics from ISO IPL path docs/system/s390x/bootdevices: Update the documentation about network booting pc-bios/s390-ccw: Merge netboot.mak into the main Makefile hw/s390x: Remove the possibility to load the s390-netboot.img binary ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
e17e57e862
39 changed files with 1179 additions and 1090 deletions
|
@ -13,6 +13,10 @@
|
|||
#include "ccw-device.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "qemu/module.h"
|
||||
#include "ipl.h"
|
||||
#include "qapi/visitor.h"
|
||||
#include "qemu/ctype.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
static void ccw_device_refill_ids(CcwDevice *dev)
|
||||
{
|
||||
|
@ -37,10 +41,52 @@ static bool ccw_device_realize(CcwDevice *dev, Error **errp)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void ccw_device_get_loadparm(Object *obj, Visitor *v,
|
||||
const char *name, void *opaque,
|
||||
Error **errp)
|
||||
{
|
||||
CcwDevice *dev = CCW_DEVICE(obj);
|
||||
char *str = g_strndup((char *) dev->loadparm, sizeof(dev->loadparm));
|
||||
|
||||
visit_type_str(v, name, &str, errp);
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
static void ccw_device_set_loadparm(Object *obj, Visitor *v,
|
||||
const char *name, void *opaque,
|
||||
Error **errp)
|
||||
{
|
||||
CcwDevice *dev = CCW_DEVICE(obj);
|
||||
char *val;
|
||||
int index;
|
||||
|
||||
index = object_property_get_int(obj, "bootindex", NULL);
|
||||
|
||||
if (index < 0) {
|
||||
error_setg(errp, "LOADPARM is only valid for boot devices!");
|
||||
}
|
||||
|
||||
if (!visit_type_str(v, name, &val, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
s390_ipl_fmt_loadparm(dev->loadparm, val, errp);
|
||||
}
|
||||
|
||||
static const PropertyInfo ccw_loadparm = {
|
||||
.name = "ccw_loadparm",
|
||||
.description = "Up to 8 chars in set of [A-Za-z0-9. ] to pass"
|
||||
" to the guest loader/kernel",
|
||||
.get = ccw_device_get_loadparm,
|
||||
.set = ccw_device_set_loadparm,
|
||||
};
|
||||
|
||||
static Property ccw_device_properties[] = {
|
||||
DEFINE_PROP_CSS_DEV_ID("devno", CcwDevice, devno),
|
||||
DEFINE_PROP_CSS_DEV_ID_RO("dev_id", CcwDevice, dev_id),
|
||||
DEFINE_PROP_CSS_DEV_ID_RO("subch_id", CcwDevice, subch_id),
|
||||
DEFINE_PROP("loadparm", CcwDevice, loadparm, ccw_loadparm,
|
||||
typeof(uint8_t[8])),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
|
|
@ -26,6 +26,8 @@ struct CcwDevice {
|
|||
CssDevId dev_id;
|
||||
/* The actual busid of the virtual subchannel. */
|
||||
CssDevId subch_id;
|
||||
/* If set, use this loadparm value when device is boot target */
|
||||
uint8_t loadparm[8];
|
||||
};
|
||||
typedef struct CcwDevice CcwDevice;
|
||||
|
||||
|
|
296
hw/s390x/ipl.c
296
hw/s390x/ipl.c
|
@ -34,6 +34,7 @@
|
|||
#include "qemu/config-file.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/ctype.h"
|
||||
#include "standard-headers/linux/virtio_ids.h"
|
||||
|
||||
#define KERN_IMAGE_START 0x010000UL
|
||||
|
@ -45,6 +46,7 @@
|
|||
#define INITRD_PARM_START 0x010408UL
|
||||
#define PARMFILE_START 0x001000UL
|
||||
#define ZIPL_IMAGE_START 0x009000UL
|
||||
#define BIOS_MAX_SIZE 0x300000UL
|
||||
#define IPL_PSW_MASK (PSW_MASK_32 | PSW_MASK_64)
|
||||
|
||||
static bool iplb_extended_needed(void *opaque)
|
||||
|
@ -54,6 +56,13 @@ static bool iplb_extended_needed(void *opaque)
|
|||
return ipl->iplbext_migration;
|
||||
}
|
||||
|
||||
/* Place the IPLB chain immediately before the BIOS in memory */
|
||||
static uint64_t find_iplb_chain_addr(uint64_t bios_addr, uint16_t count)
|
||||
{
|
||||
return (bios_addr & TARGET_PAGE_MASK)
|
||||
- (count * sizeof(IplParameterBlock));
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_iplb_extended = {
|
||||
.name = "ipl/iplb_extended",
|
||||
.version_id = 0,
|
||||
|
@ -144,7 +153,14 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
|
|||
* even if an external kernel has been defined.
|
||||
*/
|
||||
if (!ipl->kernel || ipl->enforce_bios) {
|
||||
uint64_t fwbase = (MIN(ms->ram_size, 0x80000000U) - 0x200000) & ~0xffffUL;
|
||||
uint64_t fwbase;
|
||||
|
||||
if (ms->ram_size < BIOS_MAX_SIZE) {
|
||||
error_setg(errp, "not enough RAM to load the BIOS file");
|
||||
return;
|
||||
}
|
||||
|
||||
fwbase = (MIN(ms->ram_size, 0x80000000U) - BIOS_MAX_SIZE) & ~0xffffUL;
|
||||
|
||||
bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, ipl->firmware);
|
||||
if (bios_filename == NULL) {
|
||||
|
@ -280,7 +296,6 @@ static Property s390_ipl_properties[] = {
|
|||
DEFINE_PROP_STRING("initrd", S390IPLState, initrd),
|
||||
DEFINE_PROP_STRING("cmdline", S390IPLState, cmdline),
|
||||
DEFINE_PROP_STRING("firmware", S390IPLState, firmware),
|
||||
DEFINE_PROP_STRING("netboot_fw", S390IPLState, netboot_fw),
|
||||
DEFINE_PROP_BOOL("enforce_bios", S390IPLState, enforce_bios, false),
|
||||
DEFINE_PROP_BOOL("iplbext_migration", S390IPLState, iplbext_migration,
|
||||
true),
|
||||
|
@ -390,174 +405,169 @@ static CcwDevice *s390_get_ccw_device(DeviceState *dev_st, int *devtype)
|
|||
return ccw_dev;
|
||||
}
|
||||
|
||||
static bool s390_gen_initial_iplb(S390IPLState *ipl)
|
||||
static uint64_t s390_ipl_map_iplb_chain(IplParameterBlock *iplb_chain)
|
||||
{
|
||||
S390IPLState *ipl = get_ipl_device();
|
||||
uint16_t count = be16_to_cpu(ipl->qipl.chain_len);
|
||||
uint64_t len = sizeof(IplParameterBlock) * count;
|
||||
uint64_t chain_addr = find_iplb_chain_addr(ipl->bios_start_addr, count);
|
||||
|
||||
cpu_physical_memory_write(chain_addr, iplb_chain, len);
|
||||
return chain_addr;
|
||||
}
|
||||
|
||||
void s390_ipl_fmt_loadparm(uint8_t *loadparm, char *str, Error **errp)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Initialize the loadparm with spaces */
|
||||
memset(loadparm, ' ', LOADPARM_LEN);
|
||||
for (i = 0; i < LOADPARM_LEN && str[i]; i++) {
|
||||
uint8_t c = qemu_toupper(str[i]); /* mimic HMC */
|
||||
|
||||
if (qemu_isalnum(c) || c == '.' || c == ' ') {
|
||||
loadparm[i] = c;
|
||||
} else {
|
||||
error_setg(errp, "LOADPARM: invalid character '%c' (ASCII 0x%02x)",
|
||||
c, c);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void s390_ipl_convert_loadparm(char *ascii_lp, uint8_t *ebcdic_lp)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Initialize the loadparm with EBCDIC spaces (0x40) */
|
||||
memset(ebcdic_lp, '@', LOADPARM_LEN);
|
||||
for (i = 0; i < LOADPARM_LEN && ascii_lp[i]; i++) {
|
||||
ebcdic_lp[i] = ascii2ebcdic[(uint8_t) ascii_lp[i]];
|
||||
}
|
||||
}
|
||||
|
||||
static bool s390_build_iplb(DeviceState *dev_st, IplParameterBlock *iplb)
|
||||
{
|
||||
DeviceState *dev_st;
|
||||
CcwDevice *ccw_dev = NULL;
|
||||
SCSIDevice *sd;
|
||||
int devtype;
|
||||
|
||||
dev_st = get_boot_device(0);
|
||||
if (dev_st) {
|
||||
ccw_dev = s390_get_ccw_device(dev_st, &devtype);
|
||||
}
|
||||
uint8_t *lp;
|
||||
|
||||
/*
|
||||
* Currently allow IPL only from CCW devices.
|
||||
*/
|
||||
ccw_dev = s390_get_ccw_device(dev_st, &devtype);
|
||||
if (ccw_dev) {
|
||||
lp = ccw_dev->loadparm;
|
||||
|
||||
switch (devtype) {
|
||||
case CCW_DEVTYPE_SCSI:
|
||||
sd = SCSI_DEVICE(dev_st);
|
||||
ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN);
|
||||
ipl->iplb.blk0_len =
|
||||
iplb->len = cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN);
|
||||
iplb->blk0_len =
|
||||
cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN - S390_IPLB_HEADER_LEN);
|
||||
ipl->iplb.pbt = S390_IPL_TYPE_QEMU_SCSI;
|
||||
ipl->iplb.scsi.lun = cpu_to_be32(sd->lun);
|
||||
ipl->iplb.scsi.target = cpu_to_be16(sd->id);
|
||||
ipl->iplb.scsi.channel = cpu_to_be16(sd->channel);
|
||||
ipl->iplb.scsi.devno = cpu_to_be16(ccw_dev->sch->devno);
|
||||
ipl->iplb.scsi.ssid = ccw_dev->sch->ssid & 3;
|
||||
iplb->pbt = S390_IPL_TYPE_QEMU_SCSI;
|
||||
iplb->scsi.lun = cpu_to_be32(sd->lun);
|
||||
iplb->scsi.target = cpu_to_be16(sd->id);
|
||||
iplb->scsi.channel = cpu_to_be16(sd->channel);
|
||||
iplb->scsi.devno = cpu_to_be16(ccw_dev->sch->devno);
|
||||
iplb->scsi.ssid = ccw_dev->sch->ssid & 3;
|
||||
break;
|
||||
case CCW_DEVTYPE_VFIO:
|
||||
ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_CCW_LEN);
|
||||
ipl->iplb.pbt = S390_IPL_TYPE_CCW;
|
||||
ipl->iplb.ccw.devno = cpu_to_be16(ccw_dev->sch->devno);
|
||||
ipl->iplb.ccw.ssid = ccw_dev->sch->ssid & 3;
|
||||
iplb->len = cpu_to_be32(S390_IPLB_MIN_CCW_LEN);
|
||||
iplb->pbt = S390_IPL_TYPE_CCW;
|
||||
iplb->ccw.devno = cpu_to_be16(ccw_dev->sch->devno);
|
||||
iplb->ccw.ssid = ccw_dev->sch->ssid & 3;
|
||||
break;
|
||||
case CCW_DEVTYPE_VIRTIO_NET:
|
||||
ipl->netboot = true;
|
||||
/* Fall through to CCW_DEVTYPE_VIRTIO case */
|
||||
case CCW_DEVTYPE_VIRTIO:
|
||||
ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_CCW_LEN);
|
||||
ipl->iplb.blk0_len =
|
||||
iplb->len = cpu_to_be32(S390_IPLB_MIN_CCW_LEN);
|
||||
iplb->blk0_len =
|
||||
cpu_to_be32(S390_IPLB_MIN_CCW_LEN - S390_IPLB_HEADER_LEN);
|
||||
ipl->iplb.pbt = S390_IPL_TYPE_CCW;
|
||||
ipl->iplb.ccw.devno = cpu_to_be16(ccw_dev->sch->devno);
|
||||
ipl->iplb.ccw.ssid = ccw_dev->sch->ssid & 3;
|
||||
iplb->pbt = S390_IPL_TYPE_CCW;
|
||||
iplb->ccw.devno = cpu_to_be16(ccw_dev->sch->devno);
|
||||
iplb->ccw.ssid = ccw_dev->sch->ssid & 3;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!s390_ipl_set_loadparm(ipl->iplb.loadparm)) {
|
||||
ipl->iplb.flags |= DIAG308_FLAGS_LP_VALID;
|
||||
/* If the device loadparm is empty use the global machine loadparm */
|
||||
if (memcmp(lp, NO_LOADPARM, 8) == 0) {
|
||||
lp = S390_CCW_MACHINE(qdev_get_machine())->loadparm;
|
||||
}
|
||||
|
||||
s390_ipl_convert_loadparm((char *)lp, iplb->loadparm);
|
||||
iplb->flags |= DIAG308_FLAGS_LP_VALID;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int s390_ipl_set_loadparm(uint8_t *loadparm)
|
||||
void s390_rebuild_iplb(uint16_t dev_index, IplParameterBlock *iplb)
|
||||
{
|
||||
MachineState *machine = MACHINE(qdev_get_machine());
|
||||
char *lp = object_property_get_str(OBJECT(machine), "loadparm", NULL);
|
||||
|
||||
if (lp) {
|
||||
int i;
|
||||
|
||||
/* lp is an uppercase string without leading/embedded spaces */
|
||||
for (i = 0; i < 8 && lp[i]; i++) {
|
||||
loadparm[i] = ascii2ebcdic[(uint8_t) lp[i]];
|
||||
}
|
||||
|
||||
if (i < 8) {
|
||||
memset(loadparm + i, 0x40, 8 - i); /* fill with EBCDIC spaces */
|
||||
}
|
||||
|
||||
g_free(lp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int load_netboot_image(Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(qdev_get_machine());
|
||||
S390IPLState *ipl = get_ipl_device();
|
||||
char *netboot_filename;
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
MemoryRegion *mr = NULL;
|
||||
void *ram_ptr = NULL;
|
||||
int img_size = -1;
|
||||
uint16_t index;
|
||||
index = ipl->rebuilt_iplb ? ipl->iplb_index : dev_index;
|
||||
|
||||
mr = memory_region_find(sysmem, 0, 1).mr;
|
||||
if (!mr) {
|
||||
error_setg(errp, "Failed to find memory region at address 0");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ram_ptr = memory_region_get_ram_ptr(mr);
|
||||
if (!ram_ptr) {
|
||||
error_setg(errp, "No RAM found");
|
||||
goto unref_mr;
|
||||
}
|
||||
|
||||
netboot_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, ipl->netboot_fw);
|
||||
if (netboot_filename == NULL) {
|
||||
error_setg(errp, "Could not find network bootloader '%s'",
|
||||
ipl->netboot_fw);
|
||||
goto unref_mr;
|
||||
}
|
||||
|
||||
img_size = load_elf_ram(netboot_filename, NULL, NULL, NULL,
|
||||
&ipl->start_addr,
|
||||
NULL, NULL, NULL, 1, EM_S390, 0, 0, NULL,
|
||||
false);
|
||||
|
||||
if (img_size < 0) {
|
||||
img_size = load_image_size(netboot_filename, ram_ptr, ms->ram_size);
|
||||
ipl->start_addr = KERN_IMAGE_START;
|
||||
}
|
||||
|
||||
if (img_size < 0) {
|
||||
error_setg(errp, "Failed to load network bootloader");
|
||||
}
|
||||
|
||||
g_free(netboot_filename);
|
||||
|
||||
unref_mr:
|
||||
memory_region_unref(mr);
|
||||
return img_size;
|
||||
ipl->rebuilt_iplb = s390_build_iplb(get_boot_device(index), iplb);
|
||||
ipl->iplb_index = index;
|
||||
}
|
||||
|
||||
static bool is_virtio_ccw_device_of_type(IplParameterBlock *iplb,
|
||||
int virtio_id)
|
||||
static bool s390_init_all_iplbs(S390IPLState *ipl)
|
||||
{
|
||||
uint8_t cssid;
|
||||
uint8_t ssid;
|
||||
uint16_t devno;
|
||||
uint16_t schid;
|
||||
SubchDev *sch = NULL;
|
||||
int iplb_num = 0;
|
||||
IplParameterBlock iplb_chain[7];
|
||||
DeviceState *dev_st = get_boot_device(0);
|
||||
Object *machine = qdev_get_machine();
|
||||
|
||||
if (iplb->pbt != S390_IPL_TYPE_CCW) {
|
||||
/*
|
||||
* Parse the boot devices. Generate an IPLB for only the first boot device
|
||||
* which will later be set with DIAG308.
|
||||
*/
|
||||
if (!dev_st) {
|
||||
ipl->qipl.chain_len = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
devno = be16_to_cpu(iplb->ccw.devno);
|
||||
ssid = iplb->ccw.ssid & 3;
|
||||
|
||||
for (schid = 0; schid < MAX_SCHID; schid++) {
|
||||
for (cssid = 0; cssid < MAX_CSSID; cssid++) {
|
||||
sch = css_find_subch(1, cssid, ssid, schid);
|
||||
|
||||
if (sch && sch->devno == devno) {
|
||||
return sch->id.cu_model == virtio_id;
|
||||
}
|
||||
}
|
||||
/* If no machine loadparm was defined fill it with spaces */
|
||||
if (memcmp(S390_CCW_MACHINE(machine)->loadparm, NO_LOADPARM, 8) == 0) {
|
||||
object_property_set_str(machine, "loadparm", " ", NULL);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool is_virtio_net_device(IplParameterBlock *iplb)
|
||||
{
|
||||
return is_virtio_ccw_device_of_type(iplb, VIRTIO_ID_NET);
|
||||
}
|
||||
iplb_num = 1;
|
||||
s390_build_iplb(dev_st, &ipl->iplb);
|
||||
|
||||
static bool is_virtio_scsi_device(IplParameterBlock *iplb)
|
||||
{
|
||||
return is_virtio_ccw_device_of_type(iplb, VIRTIO_ID_SCSI);
|
||||
/* Index any fallback boot devices */
|
||||
while (get_boot_device(iplb_num)) {
|
||||
iplb_num++;
|
||||
}
|
||||
|
||||
if (iplb_num > MAX_BOOT_DEVS) {
|
||||
warn_report("Excess boot devices defined! %d boot devices found, "
|
||||
"but only the first %d will be considered.",
|
||||
iplb_num, MAX_BOOT_DEVS);
|
||||
|
||||
iplb_num = MAX_BOOT_DEVS;
|
||||
}
|
||||
|
||||
ipl->qipl.chain_len = cpu_to_be16(iplb_num - 1);
|
||||
|
||||
/*
|
||||
* Build fallback IPLBs for any boot devices above index 0, up to a
|
||||
* maximum amount as defined in ipl.h
|
||||
*/
|
||||
if (iplb_num > 1) {
|
||||
/* Start at 1 because the IPLB for boot index 0 is not chained */
|
||||
for (int i = 1; i < iplb_num; i++) {
|
||||
dev_st = get_boot_device(i);
|
||||
s390_build_iplb(dev_st, &iplb_chain[i - 1]);
|
||||
}
|
||||
|
||||
ipl->qipl.next_iplb = cpu_to_be64(s390_ipl_map_iplb_chain(iplb_chain));
|
||||
}
|
||||
|
||||
return iplb_num;
|
||||
}
|
||||
|
||||
static void update_machine_ipl_properties(IplParameterBlock *iplb)
|
||||
|
@ -577,7 +587,7 @@ static void update_machine_ipl_properties(IplParameterBlock *iplb)
|
|||
ascii_loadparm[i] = 0;
|
||||
object_property_set_str(machine, "loadparm", ascii_loadparm, &err);
|
||||
} else {
|
||||
object_property_set_str(machine, "loadparm", "", &err);
|
||||
object_property_set_str(machine, "loadparm", " ", &err);
|
||||
}
|
||||
if (err) {
|
||||
warn_report_err(err);
|
||||
|
@ -599,7 +609,7 @@ void s390_ipl_update_diag308(IplParameterBlock *iplb)
|
|||
ipl->iplb = *iplb;
|
||||
ipl->iplb_valid = true;
|
||||
}
|
||||
ipl->netboot = is_virtio_net_device(iplb);
|
||||
|
||||
update_machine_ipl_properties(iplb);
|
||||
}
|
||||
|
||||
|
@ -626,32 +636,14 @@ IplParameterBlock *s390_ipl_get_iplb(void)
|
|||
void s390_ipl_reset_request(CPUState *cs, enum s390_reset reset_type)
|
||||
{
|
||||
S390IPLState *ipl = get_ipl_device();
|
||||
|
||||
if (reset_type == S390_RESET_EXTERNAL || reset_type == S390_RESET_REIPL) {
|
||||
/* use CPU 0 for full resets */
|
||||
ipl->reset_cpu_index = 0;
|
||||
} else {
|
||||
ipl->reset_cpu_index = cs->cpu_index;
|
||||
}
|
||||
|
||||
ipl->reset_type = reset_type;
|
||||
|
||||
if (reset_type == S390_RESET_REIPL &&
|
||||
ipl->iplb_valid &&
|
||||
!ipl->netboot &&
|
||||
ipl->iplb.pbt == S390_IPL_TYPE_CCW &&
|
||||
is_virtio_scsi_device(&ipl->iplb)) {
|
||||
CcwDevice *ccw_dev = s390_get_ccw_device(get_boot_device(0), NULL);
|
||||
|
||||
if (ccw_dev &&
|
||||
cpu_to_be16(ccw_dev->sch->devno) == ipl->iplb.ccw.devno &&
|
||||
(ccw_dev->sch->ssid & 3) == ipl->iplb.ccw.ssid) {
|
||||
/*
|
||||
* this is the original boot device's SCSI
|
||||
* so restore IPL parameter info from it
|
||||
*/
|
||||
ipl->iplb_valid = s390_gen_initial_iplb(ipl);
|
||||
}
|
||||
}
|
||||
if (reset_type == S390_RESET_MODIFIED_CLEAR ||
|
||||
reset_type == S390_RESET_LOAD_NORMAL ||
|
||||
reset_type == S390_RESET_PV) {
|
||||
|
@ -743,13 +735,11 @@ void s390_ipl_prepare_cpu(S390CPU *cpu)
|
|||
if (!ipl->kernel || ipl->iplb_valid) {
|
||||
cpu->env.psw.addr = ipl->bios_start_addr;
|
||||
if (!ipl->iplb_valid) {
|
||||
ipl->iplb_valid = s390_gen_initial_iplb(ipl);
|
||||
ipl->iplb_valid = s390_init_all_iplbs(ipl);
|
||||
} else {
|
||||
ipl->qipl.chain_len = 0;
|
||||
}
|
||||
}
|
||||
if (ipl->netboot) {
|
||||
load_netboot_image(&error_fatal);
|
||||
ipl->qipl.netboot_start_addr = cpu_to_be64(ipl->start_addr);
|
||||
}
|
||||
s390_ipl_set_boot_menu(ipl);
|
||||
s390_ipl_prepare_qipl(cpu);
|
||||
}
|
||||
|
|
123
hw/s390x/ipl.h
123
hw/s390x/ipl.h
|
@ -16,96 +16,15 @@
|
|||
#include "cpu.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/qdev-core.h"
|
||||
#include "hw/s390x/ipl/qipl.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
struct IPLBlockPVComp {
|
||||
uint64_t tweak_pref;
|
||||
uint64_t addr;
|
||||
uint64_t size;
|
||||
} QEMU_PACKED;
|
||||
typedef struct IPLBlockPVComp IPLBlockPVComp;
|
||||
|
||||
struct IPLBlockPV {
|
||||
uint8_t reserved18[87]; /* 0x18 */
|
||||
uint8_t version; /* 0x6f */
|
||||
uint32_t reserved70; /* 0x70 */
|
||||
uint32_t num_comp; /* 0x74 */
|
||||
uint64_t pv_header_addr; /* 0x78 */
|
||||
uint64_t pv_header_len; /* 0x80 */
|
||||
struct IPLBlockPVComp components[0];
|
||||
} QEMU_PACKED;
|
||||
typedef struct IPLBlockPV IPLBlockPV;
|
||||
|
||||
struct IplBlockCcw {
|
||||
uint8_t reserved0[85];
|
||||
uint8_t ssid;
|
||||
uint16_t devno;
|
||||
uint8_t vm_flags;
|
||||
uint8_t reserved3[3];
|
||||
uint32_t vm_parm_len;
|
||||
uint8_t nss_name[8];
|
||||
uint8_t vm_parm[64];
|
||||
uint8_t reserved4[8];
|
||||
} QEMU_PACKED;
|
||||
typedef struct IplBlockCcw IplBlockCcw;
|
||||
|
||||
struct IplBlockFcp {
|
||||
uint8_t reserved1[305 - 1];
|
||||
uint8_t opt;
|
||||
uint8_t reserved2[3];
|
||||
uint16_t reserved3;
|
||||
uint16_t devno;
|
||||
uint8_t reserved4[4];
|
||||
uint64_t wwpn;
|
||||
uint64_t lun;
|
||||
uint32_t bootprog;
|
||||
uint8_t reserved5[12];
|
||||
uint64_t br_lba;
|
||||
uint32_t scp_data_len;
|
||||
uint8_t reserved6[260];
|
||||
uint8_t scp_data[0];
|
||||
} QEMU_PACKED;
|
||||
typedef struct IplBlockFcp IplBlockFcp;
|
||||
|
||||
struct IplBlockQemuScsi {
|
||||
uint32_t lun;
|
||||
uint16_t target;
|
||||
uint16_t channel;
|
||||
uint8_t reserved0[77];
|
||||
uint8_t ssid;
|
||||
uint16_t devno;
|
||||
} QEMU_PACKED;
|
||||
typedef struct IplBlockQemuScsi IplBlockQemuScsi;
|
||||
|
||||
#define DIAG308_FLAGS_LP_VALID 0x80
|
||||
#define MAX_BOOT_DEVS 8 /* Max number of devices that may have a bootindex */
|
||||
|
||||
union IplParameterBlock {
|
||||
struct {
|
||||
uint32_t len;
|
||||
uint8_t reserved0[3];
|
||||
uint8_t version;
|
||||
uint32_t blk0_len;
|
||||
uint8_t pbt;
|
||||
uint8_t flags;
|
||||
uint16_t reserved01;
|
||||
uint8_t loadparm[8];
|
||||
union {
|
||||
IplBlockCcw ccw;
|
||||
IplBlockFcp fcp;
|
||||
IPLBlockPV pv;
|
||||
IplBlockQemuScsi scsi;
|
||||
};
|
||||
} QEMU_PACKED;
|
||||
struct {
|
||||
uint8_t reserved1[110];
|
||||
uint16_t devno;
|
||||
uint8_t reserved2[88];
|
||||
uint8_t reserved_ext[4096 - 200];
|
||||
} QEMU_PACKED;
|
||||
} QEMU_PACKED;
|
||||
typedef union IplParameterBlock IplParameterBlock;
|
||||
|
||||
int s390_ipl_set_loadparm(uint8_t *loadparm);
|
||||
void s390_ipl_convert_loadparm(char *ascii_lp, uint8_t *ebcdic_lp);
|
||||
void s390_ipl_fmt_loadparm(uint8_t *loadparm, char *str, Error **errp);
|
||||
void s390_rebuild_iplb(uint16_t index, IplParameterBlock *iplb);
|
||||
void s390_ipl_update_diag308(IplParameterBlock *iplb);
|
||||
int s390_ipl_prepare_pv_header(Error **errp);
|
||||
int s390_ipl_pv_unpack(void);
|
||||
|
@ -131,27 +50,6 @@ void s390_ipl_clear_reset_request(void);
|
|||
#define QIPL_FLAG_BM_OPTS_CMD 0x80
|
||||
#define QIPL_FLAG_BM_OPTS_ZIPL 0x40
|
||||
|
||||
/*
|
||||
* The QEMU IPL Parameters will be stored at absolute address
|
||||
* 204 (0xcc) which means it is 32-bit word aligned but not
|
||||
* double-word aligned.
|
||||
* Placement of data fields in this area must account for
|
||||
* their alignment needs. E.g., netboot_start_address must
|
||||
* have an offset of 4 + n * 8 bytes within the struct in order
|
||||
* to keep it double-word aligned.
|
||||
* The total size of the struct must never exceed 28 bytes.
|
||||
* This definition must be kept in sync with the definition
|
||||
* in pc-bios/s390-ccw/iplb.h.
|
||||
*/
|
||||
struct QemuIplParameters {
|
||||
uint8_t qipl_flags;
|
||||
uint8_t reserved1[3];
|
||||
uint64_t netboot_start_addr;
|
||||
uint32_t boot_menu_timeout;
|
||||
uint8_t reserved2[12];
|
||||
} QEMU_PACKED;
|
||||
typedef struct QemuIplParameters QemuIplParameters;
|
||||
|
||||
#define TYPE_S390_IPL "s390-ipl"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(S390IPLState, S390_IPL)
|
||||
|
||||
|
@ -168,7 +66,8 @@ struct S390IPLState {
|
|||
bool enforce_bios;
|
||||
bool iplb_valid;
|
||||
bool iplb_valid_pv;
|
||||
bool netboot;
|
||||
bool rebuilt_iplb;
|
||||
uint16_t iplb_index;
|
||||
/* reset related properties don't have to be migrated or reset */
|
||||
enum s390_reset reset_type;
|
||||
int reset_cpu_index;
|
||||
|
@ -178,7 +77,6 @@ struct S390IPLState {
|
|||
char *initrd;
|
||||
char *cmdline;
|
||||
char *firmware;
|
||||
char *netboot_fw;
|
||||
uint8_t cssid;
|
||||
uint8_t ssid;
|
||||
uint16_t devno;
|
||||
|
@ -276,11 +174,14 @@ static inline bool iplb_valid_pv(IplParameterBlock *iplb)
|
|||
|
||||
static inline bool iplb_valid(IplParameterBlock *iplb)
|
||||
{
|
||||
uint32_t len = be32_to_cpu(iplb->len);
|
||||
|
||||
switch (iplb->pbt) {
|
||||
case S390_IPL_TYPE_FCP:
|
||||
return be32_to_cpu(iplb->len) >= S390_IPLB_MIN_FCP_LEN;
|
||||
return len >= S390_IPLB_MIN_FCP_LEN;
|
||||
case S390_IPL_TYPE_CCW:
|
||||
return be32_to_cpu(iplb->len) >= S390_IPLB_MIN_CCW_LEN;
|
||||
return len >= S390_IPLB_MIN_CCW_LEN;
|
||||
case S390_IPL_TYPE_QEMU_SCSI:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -197,11 +197,10 @@ static void s390_memory_init(MemoryRegion *ram)
|
|||
static void s390_init_ipl_dev(const char *kernel_filename,
|
||||
const char *kernel_cmdline,
|
||||
const char *initrd_filename, const char *firmware,
|
||||
const char *netboot_fw, bool enforce_bios)
|
||||
bool enforce_bios)
|
||||
{
|
||||
Object *new = object_new(TYPE_S390_IPL);
|
||||
DeviceState *dev = DEVICE(new);
|
||||
char *netboot_fw_prop;
|
||||
|
||||
if (kernel_filename) {
|
||||
qdev_prop_set_string(dev, "kernel", kernel_filename);
|
||||
|
@ -212,11 +211,6 @@ static void s390_init_ipl_dev(const char *kernel_filename,
|
|||
qdev_prop_set_string(dev, "cmdline", kernel_cmdline);
|
||||
qdev_prop_set_string(dev, "firmware", firmware);
|
||||
qdev_prop_set_bit(dev, "enforce_bios", enforce_bios);
|
||||
netboot_fw_prop = object_property_get_str(new, "netboot_fw", &error_abort);
|
||||
if (!strlen(netboot_fw_prop)) {
|
||||
qdev_prop_set_string(dev, "netboot_fw", netboot_fw);
|
||||
}
|
||||
g_free(netboot_fw_prop);
|
||||
object_property_add_child(qdev_get_machine(), TYPE_S390_IPL,
|
||||
new);
|
||||
object_unref(new);
|
||||
|
@ -284,7 +278,7 @@ static void ccw_init(MachineState *machine)
|
|||
s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline,
|
||||
machine->initrd_filename,
|
||||
machine->firmware ?: "s390-ccw.img",
|
||||
"s390-netboot.img", true);
|
||||
true);
|
||||
|
||||
dev = qdev_new(TYPE_S390_PCI_HOST_BRIDGE);
|
||||
object_property_add_child(qdev_get_machine(), TYPE_S390_PCI_HOST_BRIDGE,
|
||||
|
@ -728,28 +722,12 @@ static void machine_set_loadparm(Object *obj, Visitor *v,
|
|||
{
|
||||
S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
|
||||
char *val;
|
||||
int i;
|
||||
|
||||
if (!visit_type_str(v, name, &val, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof(ms->loadparm) && val[i]; i++) {
|
||||
uint8_t c = qemu_toupper(val[i]); /* mimic HMC */
|
||||
|
||||
if (('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || (c == '.') ||
|
||||
(c == ' ')) {
|
||||
ms->loadparm[i] = c;
|
||||
} else {
|
||||
error_setg(errp, "LOADPARM: invalid character '%c' (ASCII 0x%02x)",
|
||||
c, c);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (; i < sizeof(ms->loadparm); i++) {
|
||||
ms->loadparm[i] = ' '; /* pad right with spaces */
|
||||
}
|
||||
s390_ipl_fmt_loadparm(ms->loadparm, val, errp);
|
||||
}
|
||||
|
||||
static void ccw_machine_class_init(ObjectClass *oc, void *data)
|
||||
|
|
|
@ -110,7 +110,6 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
|
|||
MachineState *machine = MACHINE(qdev_get_machine());
|
||||
int cpu_count;
|
||||
int rnsize, rnmax;
|
||||
IplParameterBlock *ipib = s390_ipl_get_iplb();
|
||||
int required_len = SCCB_REQ_LEN(ReadInfo, machine->possible_cpus->len);
|
||||
int offset_cpu = s390_has_feat(S390_FEAT_EXTENDED_LENGTH_SCCB) ?
|
||||
offsetof(ReadInfo, entries) :
|
||||
|
@ -171,12 +170,8 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
|
|||
read_info->rnmax2 = cpu_to_be64(rnmax);
|
||||
}
|
||||
|
||||
if (ipib && ipib->flags & DIAG308_FLAGS_LP_VALID) {
|
||||
memcpy(&read_info->loadparm, &ipib->loadparm,
|
||||
sizeof(read_info->loadparm));
|
||||
} else {
|
||||
s390_ipl_set_loadparm(read_info->loadparm);
|
||||
}
|
||||
s390_ipl_convert_loadparm((char *)S390_CCW_MACHINE(machine)->loadparm,
|
||||
read_info->loadparm);
|
||||
|
||||
sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue