Hopefully last big batch of s390x patches, including:
- bugfixes for LE host and for pci translation - MAINTAINERS update - hugetlbfs enablement (kernel patches pending) - boot from El Torito iso images on virtio-blk (boot from scsi pending) - cleanup in the ipl device code There's also a helper function for resetting busless devices in the qdev core in there. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJWQ3/GAAoJEN7Pa5PG8C+vPd0P/0eBJgcmg0fH7clB092Jk9BO lnhccPHcFR7gsl6BYZIvmYCnHLLZVC9Sbfgt0qf+7ea0iTgOgL7jSeN5lZ4HwLAm w61XIdWy1D4cQpJUz/IcuqQmpMLyZbEbBkCUYlrJ3fXQSP/qnvNK/TSLJEA0W5/T bHgCCjNKEyRTtjfXdNB4/WJtSjVd+I5r7DXRJtb6h1XWLyOc8Xy6CSRdArX1A7i1 Xq17+aPsCcVpLGlqsXcvV2/ekbPCJMUehNrRq3+ji6RjqXfpQ8FpbSK6DTuxKqBk OmFYX010ibyoTpIcujvVddDrYeDFX8kWAFGpluIOwHT73qUk18vQt+izyU6GqS19 CkfT9nU74SQR2ugFshmZ+9u4hMPyfDXgGHwnU6eP6neSDp6eyEGw+MvHOdLxvhIi eAP5t3scMvFlyWA2MNopvn9wWx+HO7W/2HRuzrg1gIA0Nu/u2IRVYc+LnQWMlP4f 8Js1mBCDo3mBmkBpPUn665gOcADuIGzUPl6P9VSu6QyZYUxCoEvFb2xDSRBN2bWU zWCaIh/3739ZYXRuOtWMrSpgpwz/YMTehnfKddbjrs4myfc+uxlnNLGYmbwm6xJB twu5aCbkOlPwmTmTSTHziQm1l6AYGtxwV8hCTu2dUBhoOtF6ow6vFZ8HDX2P3WyO 1m3DhTsGSnBTaHnqG/cT =c7KM -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20151111' into staging Hopefully last big batch of s390x patches, including: - bugfixes for LE host and for pci translation - MAINTAINERS update - hugetlbfs enablement (kernel patches pending) - boot from El Torito iso images on virtio-blk (boot from scsi pending) - cleanup in the ipl device code There's also a helper function for resetting busless devices in the qdev core in there. # gpg: Signature made Wed 11 Nov 2015 17:49:58 GMT using RSA key ID C6F02FAF # gpg: Good signature from "Cornelia Huck <huckc@linux.vnet.ibm.com>" # gpg: aka "Cornelia Huck <cornelia.huck@de.ibm.com>" * remotes/cohuck/tags/s390x-20151111: s390: deprecate the non-ccw machine in 2.5 s390x/ipl: switch error reporting to error_setg s390x/ipl: clean up qom definitions and turn into TYPE_DEVICE qdev: provide qdev_reset_all_fn() pc-bios/s390-ccw: rebuild image pc-bios/s390-ccw: El Torito 16-bit boot image size field workaround pc-bios/s390-ccw: El Torito s390x boot entry check pc-bios/s390-ccw: ISO-9660 El Torito boot implementation pc-bios/s390-ccw: Always adjust virtio sector count s390x/kvm: don't enable CMMA when hugetlbfs will be used s390x: switch to memory_region_allocate_system_memory MAINTAINERS: update virtio-ccw/s390 git tree MAINTAINERS: update s390 file patterns s390x/pci : fix up s390 pci iommu translation function s390x/css: sense data endianness Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
31e49ac192
20
MAINTAINERS
20
MAINTAINERS
@ -237,9 +237,14 @@ M: Cornelia Huck <cornelia.huck@de.ibm.com>
|
||||
M: Alexander Graf <agraf@suse.de>
|
||||
S: Maintained
|
||||
F: target-s390x/kvm.c
|
||||
F: target-s390x/ioinst.[ch]
|
||||
F: target-s390x/machine.c
|
||||
F: hw/intc/s390_flic.c
|
||||
F: hw/intc/s390_flic_kvm.c
|
||||
F: include/hw/s390x/s390_flic.h
|
||||
F: gdb-xml/s390*.xml
|
||||
T: git git://github.com/cohuck/qemu.git s390-next
|
||||
T: git git://github.com/borntraeger/qemu.git s390-next
|
||||
|
||||
X86
|
||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||
@ -637,15 +642,13 @@ M: Christian Borntraeger <borntraeger@de.ibm.com>
|
||||
M: Alexander Graf <agraf@suse.de>
|
||||
S: Supported
|
||||
F: hw/char/sclp*.[hc]
|
||||
F: hw/s390x/s390-virtio-ccw.c
|
||||
F: hw/s390x/css.[hc]
|
||||
F: hw/s390x/sclp*.[hc]
|
||||
F: hw/s390x/ipl*.[hc]
|
||||
F: hw/s390x/*pci*.[hc]
|
||||
F: hw/s390x/s390-skeys*.c
|
||||
F: hw/s390x/
|
||||
X: hw/s390x/s390-virtio-bus.[ch]
|
||||
F: include/hw/s390x/
|
||||
F: pc-bios/s390-ccw/
|
||||
T: git git://github.com/cohuck/qemu virtio-ccw-upstr
|
||||
F: hw/watchdog/wdt_diag288.c
|
||||
T: git git://github.com/cohuck/qemu.git s390-next
|
||||
T: git git://github.com/borntraeger/qemu.git s390-next
|
||||
|
||||
UniCore32 Machines
|
||||
-------------
|
||||
@ -872,7 +875,8 @@ M: Cornelia Huck <cornelia.huck@de.ibm.com>
|
||||
M: Christian Borntraeger <borntraeger@de.ibm.com>
|
||||
S: Supported
|
||||
F: hw/s390x/virtio-ccw.[hc]
|
||||
T: git git://github.com/cohuck/qemu virtio-ccw-upstr
|
||||
T: git git://github.com/cohuck/qemu.git s390-next
|
||||
T: git git://github.com/borntraeger/qemu.git s390-next
|
||||
|
||||
virtio-input
|
||||
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||
|
@ -325,6 +325,11 @@ void qdev_reset_all(DeviceState *dev)
|
||||
qdev_walk_children(dev, NULL, NULL, qdev_reset_one, qbus_reset_one, NULL);
|
||||
}
|
||||
|
||||
void qdev_reset_all_fn(void *opaque)
|
||||
{
|
||||
qdev_reset_all(DEVICE(opaque));
|
||||
}
|
||||
|
||||
void qbus_reset_all(BusState *bus)
|
||||
{
|
||||
qbus_walk_children(bus, NULL, NULL, qdev_reset_one, qbus_reset_one, NULL);
|
||||
|
@ -892,8 +892,14 @@ int css_do_tsch_get_irb(SubchDev *sch, IRB *target_irb, int *irb_len)
|
||||
/* If a unit check is pending, copy sense data. */
|
||||
if ((s->dstat & SCSW_DSTAT_UNIT_CHECK) &&
|
||||
(p->chars & PMCW_CHARS_MASK_CSENSE)) {
|
||||
int i;
|
||||
|
||||
irb.scsw.flags |= SCSW_FLAGS_MASK_ESWF | SCSW_FLAGS_MASK_ECTL;
|
||||
/* Attention: sense_data is already BE! */
|
||||
memcpy(irb.ecw, sch->sense_data, sizeof(sch->sense_data));
|
||||
for (i = 0; i < ARRAY_SIZE(irb.ecw); i++) {
|
||||
irb.ecw[i] = be32_to_cpu(irb.ecw[i]);
|
||||
}
|
||||
irb.esw[1] = 0x01000000 | (sizeof(sch->sense_data) << 8);
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include "cpu.h"
|
||||
#include "elf.h"
|
||||
#include "hw/loader.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/s390x/virtio-ccw.h"
|
||||
#include "hw/s390x/css.h"
|
||||
#include "ipl.h"
|
||||
@ -29,44 +28,6 @@
|
||||
#define ZIPL_IMAGE_START 0x009000UL
|
||||
#define IPL_PSW_MASK (PSW_MASK_32 | PSW_MASK_64)
|
||||
|
||||
#define TYPE_S390_IPL "s390-ipl"
|
||||
#define S390_IPL(obj) \
|
||||
OBJECT_CHECK(S390IPLState, (obj), TYPE_S390_IPL)
|
||||
#if 0
|
||||
#define S390_IPL_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(S390IPLState, (klass), TYPE_S390_IPL)
|
||||
#define S390_IPL_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(S390IPLState, (obj), TYPE_S390_IPL)
|
||||
#endif
|
||||
|
||||
typedef struct S390IPLClass {
|
||||
/*< private >*/
|
||||
SysBusDeviceClass parent_class;
|
||||
/*< public >*/
|
||||
|
||||
void (*parent_reset) (SysBusDevice *dev);
|
||||
} S390IPLClass;
|
||||
|
||||
typedef struct S390IPLState {
|
||||
/*< private >*/
|
||||
SysBusDevice parent_obj;
|
||||
uint64_t start_addr;
|
||||
uint64_t bios_start_addr;
|
||||
bool enforce_bios;
|
||||
IplParameterBlock iplb;
|
||||
bool iplb_valid;
|
||||
bool reipl_requested;
|
||||
|
||||
/*< public >*/
|
||||
char *kernel;
|
||||
char *initrd;
|
||||
char *cmdline;
|
||||
char *firmware;
|
||||
uint8_t cssid;
|
||||
uint8_t ssid;
|
||||
uint16_t devno;
|
||||
} S390IPLState;
|
||||
|
||||
static const VMStateDescription vmstate_iplb = {
|
||||
.name = "ipl/iplb",
|
||||
.version_id = 0,
|
||||
@ -110,11 +71,12 @@ static uint64_t bios_translate_addr(void *opaque, uint64_t srcaddr)
|
||||
return srcaddr + dstaddr;
|
||||
}
|
||||
|
||||
static int s390_ipl_init(SysBusDevice *dev)
|
||||
static void s390_ipl_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
S390IPLState *ipl = S390_IPL(dev);
|
||||
uint64_t pentry = KERN_IMAGE_START;
|
||||
int kernel_size;
|
||||
Error *l_err = NULL;
|
||||
|
||||
int bios_size;
|
||||
char *bios_filename;
|
||||
@ -132,7 +94,8 @@ static int s390_ipl_init(SysBusDevice *dev)
|
||||
|
||||
bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
|
||||
if (bios_filename == NULL) {
|
||||
hw_error("could not find stage1 bootloader\n");
|
||||
error_setg(&l_err, "could not find stage1 bootloader\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
bios_size = load_elf(bios_filename, bios_translate_addr, &fwbase,
|
||||
@ -150,7 +113,8 @@ static int s390_ipl_init(SysBusDevice *dev)
|
||||
g_free(bios_filename);
|
||||
|
||||
if (bios_size == -1) {
|
||||
hw_error("could not load bootloader '%s'\n", bios_name);
|
||||
error_setg(&l_err, "could not load bootloader '%s'\n", bios_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* default boot target is the bios */
|
||||
@ -164,8 +128,8 @@ static int s390_ipl_init(SysBusDevice *dev)
|
||||
kernel_size = load_image_targphys(ipl->kernel, 0, ram_size);
|
||||
}
|
||||
if (kernel_size < 0) {
|
||||
fprintf(stderr, "could not load kernel '%s'\n", ipl->kernel);
|
||||
return -1;
|
||||
error_setg(&l_err, "could not load kernel '%s'\n", ipl->kernel);
|
||||
goto error;
|
||||
}
|
||||
/*
|
||||
* Is it a Linux kernel (starting at 0x10000)? If yes, we fill in the
|
||||
@ -192,9 +156,8 @@ static int s390_ipl_init(SysBusDevice *dev)
|
||||
initrd_size = load_image_targphys(ipl->initrd, initrd_offset,
|
||||
ram_size - initrd_offset);
|
||||
if (initrd_size == -1) {
|
||||
fprintf(stderr, "qemu: could not load initrd '%s'\n",
|
||||
ipl->initrd);
|
||||
exit(1);
|
||||
error_setg(&l_err, "could not load initrd '%s'\n", ipl->initrd);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -205,7 +168,9 @@ static int s390_ipl_init(SysBusDevice *dev)
|
||||
stq_p(rom_ptr(INITRD_PARM_SIZE), initrd_size);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
qemu_register_reset(qdev_reset_all_fn, dev);
|
||||
error:
|
||||
error_propagate(errp, l_err);
|
||||
}
|
||||
|
||||
static Property s390_ipl_properties[] = {
|
||||
@ -308,9 +273,8 @@ static void s390_ipl_reset(DeviceState *dev)
|
||||
static void s390_ipl_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = s390_ipl_init;
|
||||
dc->realize = s390_ipl_realize;
|
||||
dc->props = s390_ipl_properties;
|
||||
dc->reset = s390_ipl_reset;
|
||||
dc->vmsd = &vmstate_ipl;
|
||||
@ -319,8 +283,8 @@ static void s390_ipl_class_init(ObjectClass *klass, void *data)
|
||||
|
||||
static const TypeInfo s390_ipl_info = {
|
||||
.class_init = s390_ipl_class_init,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.name = "s390-ipl",
|
||||
.parent = TYPE_DEVICE,
|
||||
.name = TYPE_S390_IPL,
|
||||
.instance_size = sizeof(S390IPLState),
|
||||
};
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#ifndef HW_S390_IPL_H
|
||||
#define HW_S390_IPL_H
|
||||
|
||||
#include "hw/qdev.h"
|
||||
#include "cpu.h"
|
||||
|
||||
typedef struct IplParameterBlock {
|
||||
@ -25,4 +26,28 @@ void s390_ipl_prepare_cpu(S390CPU *cpu);
|
||||
IplParameterBlock *s390_ipl_get_iplb(void);
|
||||
void s390_reipl_request(void);
|
||||
|
||||
#define TYPE_S390_IPL "s390-ipl"
|
||||
#define S390_IPL(obj) OBJECT_CHECK(S390IPLState, (obj), TYPE_S390_IPL)
|
||||
|
||||
struct S390IPLState {
|
||||
/*< private >*/
|
||||
DeviceState parent_obj;
|
||||
uint64_t start_addr;
|
||||
uint64_t bios_start_addr;
|
||||
bool enforce_bios;
|
||||
IplParameterBlock iplb;
|
||||
bool iplb_valid;
|
||||
bool reipl_requested;
|
||||
|
||||
/*< public >*/
|
||||
char *kernel;
|
||||
char *initrd;
|
||||
char *cmdline;
|
||||
char *firmware;
|
||||
uint8_t cssid;
|
||||
uint8_t ssid;
|
||||
uint16_t devno;
|
||||
};
|
||||
typedef struct S390IPLState S390IPLState;
|
||||
|
||||
#endif
|
||||
|
@ -309,8 +309,7 @@ static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *iommu, hwaddr addr,
|
||||
uint64_t pte;
|
||||
uint32_t flags;
|
||||
S390PCIBusDevice *pbdev = container_of(iommu, S390PCIBusDevice, mr);
|
||||
S390pciState *s = S390_PCI_HOST_BRIDGE(pci_device_root_bus(pbdev->pdev)
|
||||
->qbus.parent);
|
||||
S390pciState *s;
|
||||
IOMMUTLBEntry ret = {
|
||||
.target_as = &address_space_memory,
|
||||
.iova = 0,
|
||||
@ -319,8 +318,13 @@ static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *iommu, hwaddr addr,
|
||||
.perm = IOMMU_NONE,
|
||||
};
|
||||
|
||||
if (!pbdev->configured || !pbdev->pdev) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
DPRINTF("iommu trans addr 0x%" PRIx64 "\n", addr);
|
||||
|
||||
s = S390_PCI_HOST_BRIDGE(pci_device_root_bus(pbdev->pdev)->qbus.parent);
|
||||
/* s390 does not have an APIC mapped to main storage so we use
|
||||
* a separate AddressSpace only for msix notifications
|
||||
*/
|
||||
|
@ -104,8 +104,7 @@ void s390_memory_init(ram_addr_t mem_size)
|
||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||
|
||||
/* allocate RAM for core */
|
||||
memory_region_init_ram(ram, NULL, "s390.ram", mem_size, &error_fatal);
|
||||
vmstate_register_ram_global(ram);
|
||||
memory_region_allocate_system_memory(ram, NULL, "s390.ram", mem_size);
|
||||
memory_region_add_subregion(sysmem, 0, ram);
|
||||
|
||||
/* Initialize storage key device */
|
||||
|
@ -31,7 +31,6 @@
|
||||
#include "hw/boards.h"
|
||||
#include "hw/loader.h"
|
||||
#include "hw/virtio/virtio.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "exec/address-spaces.h"
|
||||
|
||||
@ -151,9 +150,9 @@ void s390_init_ipl_dev(const char *kernel_filename,
|
||||
const char *firmware,
|
||||
bool enforce_bios)
|
||||
{
|
||||
DeviceState *dev;
|
||||
Object *new = object_new(TYPE_S390_IPL);
|
||||
DeviceState *dev = DEVICE(new);
|
||||
|
||||
dev = qdev_create(NULL, "s390-ipl");
|
||||
if (kernel_filename) {
|
||||
qdev_prop_set_string(dev, "kernel", kernel_filename);
|
||||
}
|
||||
@ -163,8 +162,9 @@ 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);
|
||||
object_property_add_child(qdev_get_machine(), "s390-ipl",
|
||||
OBJECT(dev), NULL);
|
||||
object_property_add_child(qdev_get_machine(), TYPE_S390_IPL,
|
||||
new, NULL);
|
||||
object_unref(new);
|
||||
qdev_init_nofail(dev);
|
||||
}
|
||||
|
||||
@ -268,6 +268,10 @@ static void s390_init(MachineState *machine)
|
||||
hwaddr virtio_region_len;
|
||||
hwaddr virtio_region_start;
|
||||
|
||||
error_printf("WARNING\n"
|
||||
"The s390-virtio machine (non-ccw) is deprecated.\n"
|
||||
"It will be removed in 2.6. Please use s390-ccw-virtio\n");
|
||||
|
||||
if (machine->ram_slots) {
|
||||
error_report("Memory hotplug not supported by the selected machine.");
|
||||
exit(EXIT_FAILURE);
|
||||
@ -334,7 +338,7 @@ static void s390_machine_class_init(ObjectClass *oc, void *data)
|
||||
NMIClass *nc = NMI_CLASS(oc);
|
||||
|
||||
mc->alias = "s390";
|
||||
mc->desc = "VirtIO based S390 machine";
|
||||
mc->desc = "VirtIO based S390 machine (deprecated)";
|
||||
mc->init = s390_init;
|
||||
mc->reset = s390_machine_reset;
|
||||
mc->block_default_type = IF_VIRTIO;
|
||||
|
@ -337,6 +337,7 @@ int qdev_walk_children(DeviceState *dev,
|
||||
void *opaque);
|
||||
|
||||
void qdev_reset_all(DeviceState *dev);
|
||||
void qdev_reset_all_fn(void *opaque);
|
||||
|
||||
/**
|
||||
* @qbus_reset_all:
|
||||
|
Binary file not shown.
@ -444,6 +444,206 @@ static void ipl_scsi(void)
|
||||
zipl_run(prog_table_entry); /* no return */
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* IPL El Torito ISO9660 image or DVD
|
||||
*/
|
||||
|
||||
static bool is_iso_bc_entry_compatible(IsoBcSection *s)
|
||||
{
|
||||
uint8_t *magic_sec = (uint8_t *)(sec + ISO_SECTOR_SIZE);
|
||||
|
||||
if (s->unused || !s->sector_count) {
|
||||
return false;
|
||||
}
|
||||
read_iso_sector(bswap32(s->load_rba), magic_sec,
|
||||
"Failed to read image sector 0");
|
||||
|
||||
/* Checking bytes 8 - 32 for S390 Linux magic */
|
||||
return !_memcmp(magic_sec + 8, linux_s390_magic, 24);
|
||||
}
|
||||
|
||||
/* Location of the current sector of the directory */
|
||||
static uint32_t sec_loc[ISO9660_MAX_DIR_DEPTH];
|
||||
/* Offset in the current sector of the directory */
|
||||
static uint32_t sec_offset[ISO9660_MAX_DIR_DEPTH];
|
||||
/* Remained directory space in bytes */
|
||||
static uint32_t dir_rem[ISO9660_MAX_DIR_DEPTH];
|
||||
|
||||
static inline uint32_t iso_get_file_size(uint32_t load_rba)
|
||||
{
|
||||
IsoVolDesc *vd = (IsoVolDesc *)sec;
|
||||
IsoDirHdr *cur_record = &vd->vd.primary.rootdir;
|
||||
uint8_t *temp = sec + ISO_SECTOR_SIZE;
|
||||
int level = 0;
|
||||
|
||||
read_iso_sector(ISO_PRIMARY_VD_SECTOR, sec,
|
||||
"Failed to read ISO primary descriptor");
|
||||
sec_loc[0] = iso_733_to_u32(cur_record->ext_loc);
|
||||
dir_rem[0] = 0;
|
||||
sec_offset[0] = 0;
|
||||
|
||||
while (level >= 0) {
|
||||
IPL_assert(sec_offset[level] <= ISO_SECTOR_SIZE,
|
||||
"Directory tree structure violation");
|
||||
|
||||
cur_record = (IsoDirHdr *)(temp + sec_offset[level]);
|
||||
|
||||
if (sec_offset[level] == 0) {
|
||||
read_iso_sector(sec_loc[level], temp,
|
||||
"Failed to read ISO directory");
|
||||
if (dir_rem[level] == 0) {
|
||||
/* Skip self and parent records */
|
||||
dir_rem[level] = iso_733_to_u32(cur_record->data_len) -
|
||||
cur_record->dr_len;
|
||||
sec_offset[level] += cur_record->dr_len;
|
||||
|
||||
cur_record = (IsoDirHdr *)(temp + sec_offset[level]);
|
||||
dir_rem[level] -= cur_record->dr_len;
|
||||
sec_offset[level] += cur_record->dr_len;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cur_record->dr_len || sec_offset[level] == ISO_SECTOR_SIZE) {
|
||||
/* Zero-padding and/or the end of current sector */
|
||||
dir_rem[level] -= ISO_SECTOR_SIZE - sec_offset[level];
|
||||
sec_offset[level] = 0;
|
||||
sec_loc[level]++;
|
||||
} else {
|
||||
/* The directory record is valid */
|
||||
if (load_rba == iso_733_to_u32(cur_record->ext_loc)) {
|
||||
return iso_733_to_u32(cur_record->data_len);
|
||||
}
|
||||
|
||||
dir_rem[level] -= cur_record->dr_len;
|
||||
sec_offset[level] += cur_record->dr_len;
|
||||
|
||||
if (cur_record->file_flags & 0x2) {
|
||||
/* Subdirectory */
|
||||
if (level == ISO9660_MAX_DIR_DEPTH - 1) {
|
||||
sclp_print("ISO-9660 directory depth limit exceeded\n");
|
||||
} else {
|
||||
level++;
|
||||
sec_loc[level] = iso_733_to_u32(cur_record->ext_loc);
|
||||
sec_offset[level] = 0;
|
||||
dir_rem[level] = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dir_rem[level] == 0) {
|
||||
/* Nothing remaining */
|
||||
level--;
|
||||
read_iso_sector(sec_loc[level], temp,
|
||||
"Failed to read ISO directory");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void load_iso_bc_entry(IsoBcSection *load)
|
||||
{
|
||||
IsoBcSection s = *load;
|
||||
/*
|
||||
* According to spec, extent for each file
|
||||
* is padded and ISO_SECTOR_SIZE bytes aligned
|
||||
*/
|
||||
uint32_t blks_to_load = bswap16(s.sector_count) >> ET_SECTOR_SHIFT;
|
||||
uint32_t real_size = iso_get_file_size(bswap32(s.load_rba));
|
||||
|
||||
if (real_size) {
|
||||
/* Round up blocks to load */
|
||||
blks_to_load = (real_size + ISO_SECTOR_SIZE - 1) / ISO_SECTOR_SIZE;
|
||||
sclp_print("ISO boot image size verified\n");
|
||||
} else {
|
||||
sclp_print("ISO boot image size could not be verified\n");
|
||||
}
|
||||
|
||||
read_iso_boot_image(bswap32(s.load_rba),
|
||||
(void *)((uint64_t)bswap16(s.load_segment)),
|
||||
blks_to_load);
|
||||
|
||||
/* Trying to get PSW at zero address */
|
||||
if (*((uint64_t *)0) & IPL_PSW_MASK) {
|
||||
jump_to_IPL_code((*((uint64_t *)0)) & 0x7fffffff);
|
||||
}
|
||||
|
||||
/* Try default linux start address */
|
||||
jump_to_IPL_code(KERN_IMAGE_START);
|
||||
}
|
||||
|
||||
static uint32_t find_iso_bc(void)
|
||||
{
|
||||
IsoVolDesc *vd = (IsoVolDesc *)sec;
|
||||
uint32_t block_num = ISO_PRIMARY_VD_SECTOR;
|
||||
|
||||
if (virtio_read_many(block_num++, sec, 1)) {
|
||||
/* If primary vd cannot be read, there is no boot catalog */
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (is_iso_vd_valid(vd) && vd->type != VOL_DESC_TERMINATOR) {
|
||||
if (vd->type == VOL_DESC_TYPE_BOOT) {
|
||||
IsoVdElTorito *et = &vd->vd.boot;
|
||||
|
||||
if (!_memcmp(&et->el_torito[0], el_torito_magic, 32)) {
|
||||
return bswap32(et->bc_offset);
|
||||
}
|
||||
}
|
||||
read_iso_sector(block_num++, sec,
|
||||
"Failed to read ISO volume descriptor");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static IsoBcSection *find_iso_bc_entry(void)
|
||||
{
|
||||
IsoBcEntry *e = (IsoBcEntry *)sec;
|
||||
uint32_t offset = find_iso_bc();
|
||||
int i;
|
||||
|
||||
if (!offset) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
read_iso_sector(offset, sec, "Failed to read El Torito boot catalog");
|
||||
|
||||
if (!is_iso_bc_valid(e)) {
|
||||
/* The validation entry is mandatory */
|
||||
virtio_panic("No valid boot catalog found!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Each entry has 32 bytes size, so one sector cannot contain > 64 entries.
|
||||
* We consider only boot catalogs with no more than 64 entries.
|
||||
*/
|
||||
for (i = 1; i < ISO_BC_ENTRY_PER_SECTOR; i++) {
|
||||
if (e[i].id == ISO_BC_BOOTABLE_SECTION) {
|
||||
if (is_iso_bc_entry_compatible(&e[i].body.sect)) {
|
||||
return &e[i].body.sect;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtio_panic("No suitable boot entry found on ISO-9660 media!\n");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ipl_iso_el_torito(void)
|
||||
{
|
||||
IsoBcSection *s = find_iso_bc_entry();
|
||||
|
||||
if (s) {
|
||||
load_iso_bc_entry(s);
|
||||
/* no return */
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* IPL starts here
|
||||
*/
|
||||
@ -463,6 +663,12 @@ void zipl_load(void)
|
||||
ipl_scsi(); /* no return */
|
||||
}
|
||||
|
||||
/* Check if we can boot as ISO media */
|
||||
if (virtio_guessed_disk_nature()) {
|
||||
virtio_assume_iso9660();
|
||||
}
|
||||
ipl_iso_el_torito();
|
||||
|
||||
/* We have failed to follow the SCSI scheme, so */
|
||||
if (virtio_guessed_disk_nature()) {
|
||||
sclp_print("Using guessed DASD geometry.\n");
|
||||
|
@ -341,4 +341,210 @@ static inline bool magic_match(const void *data, const void *magic)
|
||||
return *((uint32_t *)data) == *((uint32_t *)magic);
|
||||
}
|
||||
|
||||
static inline int _memcmp(const void *s1, const void *s2, size_t n)
|
||||
{
|
||||
int i;
|
||||
const uint8_t *p1 = s1, *p2 = s2;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
if (p1[i] != p2[i]) {
|
||||
return p1[i] > p2[i] ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* from include/qemu/bswap.h */
|
||||
|
||||
/* El Torito is always little-endian */
|
||||
static inline uint16_t bswap16(uint16_t x)
|
||||
{
|
||||
return ((x & 0x00ff) << 8) | ((x & 0xff00) >> 8);
|
||||
}
|
||||
|
||||
static inline uint32_t bswap32(uint32_t x)
|
||||
{
|
||||
return ((x & 0x000000ffU) << 24) | ((x & 0x0000ff00U) << 8) |
|
||||
((x & 0x00ff0000U) >> 8) | ((x & 0xff000000U) >> 24);
|
||||
}
|
||||
|
||||
static inline uint64_t bswap64(uint64_t x)
|
||||
{
|
||||
return ((x & 0x00000000000000ffULL) << 56) |
|
||||
((x & 0x000000000000ff00ULL) << 40) |
|
||||
((x & 0x0000000000ff0000ULL) << 24) |
|
||||
((x & 0x00000000ff000000ULL) << 8) |
|
||||
((x & 0x000000ff00000000ULL) >> 8) |
|
||||
((x & 0x0000ff0000000000ULL) >> 24) |
|
||||
((x & 0x00ff000000000000ULL) >> 40) |
|
||||
((x & 0xff00000000000000ULL) >> 56);
|
||||
}
|
||||
|
||||
static inline uint32_t iso_733_to_u32(uint64_t x)
|
||||
{
|
||||
return (uint32_t)x;
|
||||
}
|
||||
|
||||
#define ISO_SECTOR_SIZE 2048
|
||||
/* El Torito specifies boot image size in 512 byte blocks */
|
||||
#define ET_SECTOR_SHIFT 2
|
||||
#define KERN_IMAGE_START 0x010000UL
|
||||
#define PSW_MASK_64 0x0000000100000000ULL
|
||||
#define PSW_MASK_32 0x0000000080000000ULL
|
||||
#define IPL_PSW_MASK (PSW_MASK_32 | PSW_MASK_64)
|
||||
|
||||
#define ISO_PRIMARY_VD_SECTOR 16
|
||||
|
||||
static inline void read_iso_sector(uint32_t block_offset, void *buf,
|
||||
const char *errmsg)
|
||||
{
|
||||
IPL_assert(virtio_read_many(block_offset, buf, 1) == 0, errmsg);
|
||||
}
|
||||
|
||||
static inline void read_iso_boot_image(uint32_t block_offset, void *load_addr,
|
||||
uint32_t blks_to_load)
|
||||
{
|
||||
IPL_assert(virtio_read_many(block_offset, load_addr, blks_to_load) == 0,
|
||||
"Failed to read boot image!");
|
||||
}
|
||||
|
||||
const uint8_t el_torito_magic[] = "EL TORITO SPECIFICATION"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
|
||||
|
||||
#define ISO9660_MAX_DIR_DEPTH 8
|
||||
|
||||
typedef struct IsoDirHdr {
|
||||
uint8_t dr_len;
|
||||
uint8_t ear_len;
|
||||
uint64_t ext_loc;
|
||||
uint64_t data_len;
|
||||
uint8_t recording_datetime[7];
|
||||
uint8_t file_flags;
|
||||
uint8_t file_unit_size;
|
||||
uint8_t gap_size;
|
||||
uint32_t vol_seqnum;
|
||||
uint8_t fileid_len;
|
||||
} __attribute__((packed)) IsoDirHdr;
|
||||
|
||||
typedef struct IsoVdElTorito {
|
||||
uint8_t el_torito[32]; /* must contain el_torito_magic value */
|
||||
uint8_t unused0[32];
|
||||
uint32_t bc_offset;
|
||||
uint8_t unused1[1974];
|
||||
} __attribute__((packed)) IsoVdElTorito;
|
||||
|
||||
typedef struct IsoVdPrimary {
|
||||
uint8_t unused1;
|
||||
uint8_t sys_id[32];
|
||||
uint8_t vol_id[32];
|
||||
uint8_t unused2[8];
|
||||
uint64_t vol_space_size;
|
||||
uint8_t unused3[32];
|
||||
uint32_t vol_set_size;
|
||||
uint32_t vol_seqnum;
|
||||
uint32_t log_block_size;
|
||||
uint64_t path_table_size;
|
||||
uint32_t l_path_table;
|
||||
uint32_t opt_l_path_table;
|
||||
uint32_t m_path_table;
|
||||
uint32_t opt_m_path_table;
|
||||
IsoDirHdr rootdir;
|
||||
uint8_t root_null;
|
||||
uint8_t reserved2[1858];
|
||||
} __attribute__((packed)) IsoVdPrimary;
|
||||
|
||||
typedef struct IsoVolDesc {
|
||||
uint8_t type;
|
||||
uint8_t ident[5];
|
||||
uint8_t version;
|
||||
union {
|
||||
IsoVdElTorito boot;
|
||||
IsoVdPrimary primary;
|
||||
} vd;
|
||||
} __attribute__((packed)) IsoVolDesc;
|
||||
|
||||
const uint8_t vol_desc_magic[] = "CD001";
|
||||
#define VOL_DESC_TYPE_BOOT 0
|
||||
#define VOL_DESC_TYPE_PRIMARY 1
|
||||
#define VOL_DESC_TYPE_SUPPLEMENT 2
|
||||
#define VOL_DESC_TYPE_PARTITION 3
|
||||
#define VOL_DESC_TERMINATOR 255
|
||||
|
||||
static inline bool is_iso_vd_valid(IsoVolDesc *vd)
|
||||
{
|
||||
return !_memcmp(&vd->ident[0], vol_desc_magic, 5) &&
|
||||
vd->version == 0x1 &&
|
||||
vd->type <= VOL_DESC_TYPE_PARTITION;
|
||||
}
|
||||
|
||||
typedef struct IsoBcValid {
|
||||
uint8_t platform_id;
|
||||
uint16_t reserved;
|
||||
uint8_t id[24];
|
||||
uint16_t checksum;
|
||||
uint8_t key[2];
|
||||
} __attribute__((packed)) IsoBcValid;
|
||||
|
||||
typedef struct IsoBcSection {
|
||||
uint8_t boot_type;
|
||||
uint16_t load_segment;
|
||||
uint8_t sys_type;
|
||||
uint8_t unused;
|
||||
uint16_t sector_count;
|
||||
uint32_t load_rba;
|
||||
uint8_t selection[20];
|
||||
} __attribute__((packed)) IsoBcSection;
|
||||
|
||||
typedef struct IsoBcHdr {
|
||||
uint8_t platform_id;
|
||||
uint16_t sect_num;
|
||||
uint8_t id[28];
|
||||
} __attribute__((packed)) IsoBcHdr;
|
||||
|
||||
/*
|
||||
* Match two CCWs located after PSW and eight filler bytes.
|
||||
* From libmagic and arch/s390/kernel/head.S.
|
||||
*/
|
||||
const uint8_t linux_s390_magic[] = "\x02\x00\x00\x18\x60\x00\x00\x50\x02\x00"
|
||||
"\x00\x68\x60\x00\x00\x50\x40\x40\x40\x40"
|
||||
"\x40\x40\x40\x40";
|
||||
|
||||
typedef struct IsoBcEntry {
|
||||
uint8_t id;
|
||||
union {
|
||||
IsoBcValid valid; /* id == 0x01 */
|
||||
IsoBcSection sect; /* id == 0x88 || id == 0x0 */
|
||||
IsoBcHdr hdr; /* id == 0x90 || id == 0x91 */
|
||||
} body;
|
||||
} __attribute__((packed)) IsoBcEntry;
|
||||
|
||||
#define ISO_BC_ENTRY_PER_SECTOR (ISO_SECTOR_SIZE / sizeof(IsoBcEntry))
|
||||
#define ISO_BC_HDR_VALIDATION 0x01
|
||||
#define ISO_BC_BOOTABLE_SECTION 0x88
|
||||
#define ISO_BC_MAGIC_55 0x55
|
||||
#define ISO_BC_MAGIC_AA 0xaa
|
||||
#define ISO_BC_PLATFORM_X86 0x0
|
||||
#define ISO_BC_PLATFORM_PPC 0x1
|
||||
#define ISO_BC_PLATFORM_MAC 0x2
|
||||
|
||||
static inline bool is_iso_bc_valid(IsoBcEntry *e)
|
||||
{
|
||||
IsoBcValid *v = &e->body.valid;
|
||||
|
||||
if (e->id != ISO_BC_HDR_VALIDATION) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (v->platform_id != ISO_BC_PLATFORM_X86 &&
|
||||
v->platform_id != ISO_BC_PLATFORM_PPC &&
|
||||
v->platform_id != ISO_BC_PLATFORM_MAC) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return v->key[0] == ISO_BC_MAGIC_55 &&
|
||||
v->key[1] == ISO_BC_MAGIC_AA &&
|
||||
v->reserved == 0x0;
|
||||
}
|
||||
|
||||
#endif /* _PC_BIOS_S390_CCW_BOOTMAP_H */
|
||||
|
@ -278,6 +278,13 @@ void virtio_assume_scsi(void)
|
||||
blk_cfg.physical_block_exp = 0;
|
||||
}
|
||||
|
||||
void virtio_assume_iso9660(void)
|
||||
{
|
||||
guessed_disk_nature = true;
|
||||
blk_cfg.blk_size = 2048;
|
||||
blk_cfg.physical_block_exp = 0;
|
||||
}
|
||||
|
||||
void virtio_assume_eckd(void)
|
||||
{
|
||||
guessed_disk_nature = true;
|
||||
|
@ -187,6 +187,7 @@ typedef struct VirtioBlkConfig {
|
||||
bool virtio_guessed_disk_nature(void);
|
||||
void virtio_assume_scsi(void);
|
||||
void virtio_assume_eckd(void);
|
||||
void virtio_assume_iso9660(void);
|
||||
|
||||
extern bool virtio_disk_is_scsi(void);
|
||||
extern bool virtio_disk_is_eckd(void);
|
||||
@ -199,14 +200,9 @@ extern int virtio_read_many(ulong sector, void *load_addr, int sec_num);
|
||||
|
||||
#define VIRTIO_SECTOR_SIZE 512
|
||||
|
||||
static inline ulong virtio_eckd_sector_adjust(ulong sector)
|
||||
{
|
||||
return sector * (virtio_get_block_size() / VIRTIO_SECTOR_SIZE);
|
||||
}
|
||||
|
||||
static inline ulong virtio_sector_adjust(ulong sector)
|
||||
{
|
||||
return virtio_disk_is_eckd() ? virtio_eckd_sector_adjust(sector) : sector;
|
||||
return sector * (virtio_get_block_size() / VIRTIO_SECTOR_SIZE);
|
||||
}
|
||||
|
||||
#endif /* VIRTIO_H */
|
||||
|
@ -258,7 +258,9 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
|
||||
cap_mem_op = kvm_check_extension(s, KVM_CAP_S390_MEM_OP);
|
||||
cap_s390_irq = kvm_check_extension(s, KVM_CAP_S390_INJECT_IRQ);
|
||||
|
||||
kvm_s390_enable_cmma(s);
|
||||
if (!mem_path) {
|
||||
kvm_s390_enable_cmma(s);
|
||||
}
|
||||
|
||||
if (!kvm_check_extension(s, KVM_CAP_S390_GMAP)
|
||||
|| !kvm_check_extension(s, KVM_CAP_S390_COW)) {
|
||||
|
Loading…
Reference in New Issue
Block a user