First s390x pull request for 2.13.

- new machine type
 - extend SCLP event masks
 - support configuration of consoles via -serial
 - firmware improvements: non-sequential entries in boot menu, support
   for indirect loading via .INS files in s390-netboot
 - bugfixes and cleanups
 -----BEGIN PGP SIGNATURE-----
 
 iQJGBAABCAAwFiEEw9DWbcNiT/aowBjO3s9rk8bwL68FAlrsCZ0SHGNvaHVja0By
 ZWRoYXQuY29tAAoJEN7Pa5PG8C+vrN8QAKP3poc2wm/+32vCUv+qUyHby6cm5bl+
 2PeHS/CLC1q/nIggb1l8z9I3BeVSgeWB3B5/dKHvuRM4sVGslg2t2ivSXXbU06Na
 4sv9NaPh1DV0YLuSIj7gIbk9BZdsuw5Ik2846KIFW4HjYmgWJZJc9WhC+ezBqMLI
 jbOUQiQk7JfhJ0julc5Z1BcZN50PxUquvN8BmmS+QHhbdcQ0xMjmlDpkhGNzk9Hg
 +Ui6Fu5HOnybGXE3u9V+xS1I9Gn0cG90lgGFkIRgGO6oqn0C0hmYfrcXc11xg9yH
 /hUx+lIg3k44T6e2nG6IxDyuAfugxJiKeD1PscAd8DzBceKHxpIVk37xoITlCO25
 iRAcvToruaxZf0RSprQsW3DCto5cEhdX5XLVs6J5I/jlBqNgllKkezS5mG2fpibe
 xH7MlRL00DqaNEqWCrQ2+64w5THIkkiukYQLv6eDdoaTP/6emJ6KeqGr7KDbijvx
 ViR8LQ2aaGR/sL90X/HDNvR3otnC3doAQTCjlxDlHkjE3hSL9Z6Nvq4KBztiP418
 leHoiscmzRLJzagAhOn+uZWjETnoBKv1OnEN1yLf80ADz/FaArvnb9zq5KR6Oh43
 30+5RKLFKaDx6fnXGB2eqIOgq/4x1wXcGwRCBpRfYDXc/pQjbnj7AsKQiSTdTOa3
 hfTCL7/LscMU
 =cYvD
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20180504' into staging

First s390x pull request for 2.13.
- new machine type
- extend SCLP event masks
- support configuration of consoles via -serial
- firmware improvements: non-sequential entries in boot menu, support
  for indirect loading via .INS files in s390-netboot
- bugfixes and cleanups

# gpg: Signature made Fri 04 May 2018 08:19:57 BST
# gpg:                using RSA key DECF6B93C6F02FAF
# gpg: Good signature from "Cornelia Huck <conny@cornelia-huck.de>"
# gpg:                 aka "Cornelia Huck <huckc@linux.vnet.ibm.com>"
# gpg:                 aka "Cornelia Huck <cornelia.huck@de.ibm.com>"
# gpg:                 aka "Cornelia Huck <cohuck@kernel.org>"
# gpg:                 aka "Cornelia Huck <cohuck@redhat.com>"
# Primary key fingerprint: C3D0 D66D C362 4FF6 A8C0  18CE DECF 6B93 C6F0 2FAF

* remotes/cohuck/tags/s390x-20180504:
  pc-bios/s390: Update firmware images
  s390-ccw: force diag 308 subcode to unsigned long
  pc-bios/s390-ccw/net: Add support for .INS config files
  pc-bios/s390-ccw/net: Use diag308 to reset machine before jumping to the OS
  pc-bios/s390-ccw/net: Split up net_load() into init, load and release parts
  pc-bios/s390-ccw: fix non-sequential boot entries (enum)
  pc-bios/s390-ccw: fix non-sequential boot entries (eckd)
  pc-bios/s390-ccw: fix loadparm initialization and int conversion
  pc-bios/s390-ccw: rename MAX_TABLE_ENTRIES to MAX_BOOT_ENTRIES
  pc-bios/s390-ccw: size_t should be unsigned
  hw/s390x: Allow to configure the consoles with the "-serial" parameter
  s390x/kvm: cleanup calls to cpu_synchronize_state()
  vfio-ccw: introduce vfio_ccw_get_device()
  s390x/sclp: extend SCLP event masks to 64 bits
  s390x: introduce 2.13 compat machine

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2018-05-04 11:53:58 +01:00
commit 46e04dacd3
24 changed files with 438 additions and 250 deletions

View File

@ -26,11 +26,23 @@ typedef struct SCLPEventsBus {
BusState qbus;
} SCLPEventsBus;
/* we need to save 32 bit chunks for compatibility */
#ifdef HOST_WORDS_BIGENDIAN
#define RECV_MASK_LOWER 1
#define RECV_MASK_UPPER 0
#else /* little endian host */
#define RECV_MASK_LOWER 0
#define RECV_MASK_UPPER 1
#endif
struct SCLPEventFacility {
SysBusDevice parent_obj;
SCLPEventsBus sbus;
/* guest's receive mask */
sccb_mask_t receive_mask;
union {
uint32_t receive_mask_pieces[2];
sccb_mask_t receive_mask;
};
/*
* when false, we keep the same broken, backwards compatible behaviour as
* before, allowing only masks of size exactly 4; when true, we implement
@ -262,7 +274,7 @@ static void read_event_data(SCLPEventFacility *ef, SCCB *sccb)
case SCLP_SELECTIVE_READ:
copy_mask((uint8_t *)&sclp_active_selection_mask, (uint8_t *)&red->mask,
sizeof(sclp_active_selection_mask), ef->mask_length);
sclp_active_selection_mask = be32_to_cpu(sclp_active_selection_mask);
sclp_active_selection_mask = be64_to_cpu(sclp_active_selection_mask);
if (!sclp_cp_receive_mask ||
(sclp_active_selection_mask & ~sclp_cp_receive_mask)) {
sccb->h.response_code =
@ -294,21 +306,22 @@ static void write_event_mask(SCLPEventFacility *ef, SCCB *sccb)
}
/*
* Note: We currently only support masks up to 4 byte length;
* the remainder is filled up with zeroes. Linux uses
* a 4 byte mask length.
* Note: We currently only support masks up to 8 byte length;
* the remainder is filled up with zeroes. Older Linux
* kernels use a 4 byte mask length, newer ones can use both
* 8 or 4 depending on what is available on the host.
*/
/* keep track of the guest's capability masks */
copy_mask((uint8_t *)&tmp_mask, WEM_CP_RECEIVE_MASK(we_mask, mask_length),
sizeof(tmp_mask), mask_length);
ef->receive_mask = be32_to_cpu(tmp_mask);
ef->receive_mask = be64_to_cpu(tmp_mask);
/* return the SCLP's capability masks to the guest */
tmp_mask = cpu_to_be32(get_host_receive_mask(ef));
tmp_mask = cpu_to_be64(get_host_receive_mask(ef));
copy_mask(WEM_RECEIVE_MASK(we_mask, mask_length), (uint8_t *)&tmp_mask,
mask_length, sizeof(tmp_mask));
tmp_mask = cpu_to_be32(get_host_send_mask(ef));
tmp_mask = cpu_to_be64(get_host_send_mask(ef));
copy_mask(WEM_SEND_MASK(we_mask, mask_length), (uint8_t *)&tmp_mask,
mask_length, sizeof(tmp_mask));
@ -369,6 +382,13 @@ static void command_handler(SCLPEventFacility *ef, SCCB *sccb, uint64_t code)
}
}
static bool vmstate_event_facility_mask64_needed(void *opaque)
{
SCLPEventFacility *ef = opaque;
return (ef->receive_mask & 0xFFFFFFFF) != 0;
}
static bool vmstate_event_facility_mask_length_needed(void *opaque)
{
SCLPEventFacility *ef = opaque;
@ -376,6 +396,17 @@ static bool vmstate_event_facility_mask_length_needed(void *opaque)
return ef->allow_all_mask_sizes;
}
static const VMStateDescription vmstate_event_facility_mask64 = {
.name = "vmstate-event-facility/mask64",
.version_id = 0,
.minimum_version_id = 0,
.needed = vmstate_event_facility_mask64_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT32(receive_mask_pieces[RECV_MASK_LOWER], SCLPEventFacility),
VMSTATE_END_OF_LIST()
}
};
static const VMStateDescription vmstate_event_facility_mask_length = {
.name = "vmstate-event-facility/mask_length",
.version_id = 0,
@ -392,10 +423,11 @@ static const VMStateDescription vmstate_event_facility = {
.version_id = 0,
.minimum_version_id = 0,
.fields = (VMStateField[]) {
VMSTATE_UINT32(receive_mask, SCLPEventFacility),
VMSTATE_UINT32(receive_mask_pieces[RECV_MASK_UPPER], SCLPEventFacility),
VMSTATE_END_OF_LIST()
},
.subsections = (const VMStateDescription * []) {
&vmstate_event_facility_mask64,
&vmstate_event_facility_mask_length,
NULL
}
@ -511,3 +543,17 @@ static void register_types(void)
}
type_init(register_types)
BusState *sclp_get_event_facility_bus(void)
{
Object *busobj;
SCLPEventsBus *sbus;
busobj = object_resolve_path_type("", TYPE_SCLP_EVENTS_BUS, NULL);
sbus = OBJECT_CHECK(SCLPEventsBus, busobj, TYPE_SCLP_EVENTS_BUS);
if (!sbus) {
return NULL;
}
return &sbus->qbus;
}

View File

@ -373,6 +373,10 @@ int s390_ipl_set_loadparm(uint8_t *loadparm)
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;
}

View File

@ -155,8 +155,6 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra)
S390pciState *s = s390_get_phb();
int i;
cpu_synchronize_state(CPU(cpu));
if (env->psw.mask & PSW_MASK_PSTATE) {
s390_program_interrupt(env, PGM_PRIVILEGED, 4, ra);
return 0;
@ -389,8 +387,6 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
uint32_t fh;
uint8_t pcias;
cpu_synchronize_state(CPU(cpu));
if (env->psw.mask & PSW_MASK_PSTATE) {
s390_program_interrupt(env, PGM_PRIVILEGED, 4, ra);
return 0;
@ -487,8 +483,6 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
uint32_t fh;
uint8_t pcias;
cpu_synchronize_state(CPU(cpu));
if (env->psw.mask & PSW_MASK_PSTATE) {
s390_program_interrupt(env, PGM_PRIVILEGED, 4, ra);
return 0;
@ -620,8 +614,6 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
S390IOTLBEntry entry;
hwaddr start, end;
cpu_synchronize_state(CPU(cpu));
if (env->psw.mask & PSW_MASK_PSTATE) {
s390_program_interrupt(env, PGM_PRIVILEGED, 4, ra);
return 0;

View File

@ -288,6 +288,15 @@ static void s390_create_virtio_net(BusState *bus, const char *name)
}
}
static void s390_create_sclpconsole(const char *type, Chardev *chardev)
{
DeviceState *dev;
dev = qdev_create(sclp_get_event_facility_bus(), type);
qdev_prop_set_chr(dev, "chardev", chardev);
qdev_init_nofail(dev);
}
static void ccw_init(MachineState *machine)
{
int ret;
@ -346,6 +355,14 @@ static void ccw_init(MachineState *machine)
/* Create VirtIO network adapters */
s390_create_virtio_net(BUS(css_bus), "virtio-net-ccw");
/* init consoles */
if (serial_hd(0)) {
s390_create_sclpconsole("sclpconsole", serial_hd(0));
}
if (serial_hd(1)) {
s390_create_sclpconsole("sclplmconsole", serial_hd(1));
}
/* Register savevm handler for guest TOD clock */
register_savevm_live(NULL, "todclock", 0, 1, &savevm_gtod, NULL);
}
@ -470,10 +487,8 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data)
mc->block_default_type = IF_VIRTIO;
mc->no_cdrom = 1;
mc->no_floppy = 1;
mc->no_serial = 1;
mc->no_parallel = 1;
mc->no_sdcard = 1;
mc->use_sclp = 1;
mc->max_cpus = S390_MAX_CPUS;
mc->has_hotpluggable_cpus = true;
mc->get_hotplug_handler = s390_get_hotplug_handler;
@ -671,6 +686,9 @@ bool css_migration_enabled(void)
} \
type_init(ccw_machine_register_##suffix)
#define CCW_COMPAT_2_12 \
HW_COMPAT_2_12
#define CCW_COMPAT_2_11 \
HW_COMPAT_2_11 \
{\
@ -756,14 +774,26 @@ bool css_migration_enabled(void)
.value = "0",\
},
static void ccw_machine_2_13_instance_options(MachineState *machine)
{
}
static void ccw_machine_2_13_class_options(MachineClass *mc)
{
}
DEFINE_CCW_MACHINE(2_13, "2.13", true);
static void ccw_machine_2_12_instance_options(MachineState *machine)
{
ccw_machine_2_13_instance_options(machine);
}
static void ccw_machine_2_12_class_options(MachineClass *mc)
{
ccw_machine_2_13_class_options(mc);
SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_12);
}
DEFINE_CCW_MACHINE(2_12, "2.12", true);
DEFINE_CCW_MACHINE(2_12, "2.12", false);
static void ccw_machine_2_11_instance_options(MachineState *machine)
{

View File

@ -292,12 +292,43 @@ static void vfio_ccw_put_region(VFIOCCWDevice *vcdev)
g_free(vcdev->io_region);
}
static void vfio_put_device(VFIOCCWDevice *vcdev)
static void vfio_ccw_put_device(VFIOCCWDevice *vcdev)
{
g_free(vcdev->vdev.name);
vfio_put_base_device(&vcdev->vdev);
}
static void vfio_ccw_get_device(VFIOGroup *group, VFIOCCWDevice *vcdev,
Error **errp)
{
char *name = g_strdup_printf("%x.%x.%04x", vcdev->cdev.hostid.cssid,
vcdev->cdev.hostid.ssid,
vcdev->cdev.hostid.devid);
VFIODevice *vbasedev;
QLIST_FOREACH(vbasedev, &group->device_list, next) {
if (strcmp(vbasedev->name, name) == 0) {
error_setg(errp, "vfio: subchannel %s has already been attached",
name);
goto out_err;
}
}
if (vfio_get_device(group, vcdev->cdev.mdevid, &vcdev->vdev, errp)) {
goto out_err;
}
vcdev->vdev.ops = &vfio_ccw_ops;
vcdev->vdev.type = VFIO_DEVICE_TYPE_CCW;
vcdev->vdev.name = name;
vcdev->vdev.dev = &vcdev->cdev.parent_obj.parent_obj;
return;
out_err:
g_free(name);
}
static VFIOGroup *vfio_ccw_get_group(S390CCWDevice *cdev, Error **errp)
{
char *tmp, group_path[PATH_MAX];
@ -327,7 +358,6 @@ static VFIOGroup *vfio_ccw_get_group(S390CCWDevice *cdev, Error **errp)
static void vfio_ccw_realize(DeviceState *dev, Error **errp)
{
VFIODevice *vbasedev;
VFIOGroup *group;
CcwDevice *ccw_dev = DO_UPCAST(CcwDevice, parent_obj, dev);
S390CCWDevice *cdev = DO_UPCAST(S390CCWDevice, parent_obj, ccw_dev);
@ -348,22 +378,8 @@ static void vfio_ccw_realize(DeviceState *dev, Error **errp)
goto out_group_err;
}
vcdev->vdev.ops = &vfio_ccw_ops;
vcdev->vdev.type = VFIO_DEVICE_TYPE_CCW;
vcdev->vdev.name = g_strdup_printf("%x.%x.%04x", cdev->hostid.cssid,
cdev->hostid.ssid, cdev->hostid.devid);
vcdev->vdev.dev = dev;
QLIST_FOREACH(vbasedev, &group->device_list, next) {
if (strcmp(vbasedev->name, vcdev->vdev.name) == 0) {
error_setg(&err, "vfio: subchannel %s has already been attached",
vcdev->vdev.name);
g_free(vcdev->vdev.name);
goto out_device_err;
}
}
if (vfio_get_device(group, cdev->mdevid, &vcdev->vdev, &err)) {
g_free(vcdev->vdev.name);
vfio_ccw_get_device(group, vcdev, &err);
if (err) {
goto out_device_err;
}
@ -382,7 +398,7 @@ static void vfio_ccw_realize(DeviceState *dev, Error **errp)
out_notifier_err:
vfio_ccw_put_region(vcdev);
out_region_err:
vfio_put_device(vcdev);
vfio_ccw_put_device(vcdev);
out_device_err:
vfio_put_group(group);
out_group_err:
@ -403,7 +419,7 @@ static void vfio_ccw_unrealize(DeviceState *dev, Error **errp)
vfio_ccw_unregister_io_notifier(vcdev);
vfio_ccw_put_region(vcdev);
vfio_put_device(vcdev);
vfio_ccw_put_device(vcdev);
vfio_put_group(group);
if (cdc->unrealize) {

View File

@ -180,7 +180,6 @@ struct MachineClass {
unsigned int no_serial:1,
no_parallel:1,
use_virtcon:1,
use_sclp:1,
no_floppy:1,
no_cdrom:1,
no_sdcard:1,

View File

@ -73,7 +73,7 @@ typedef struct WriteEventMask {
#define WEM_RECEIVE_MASK(wem, mask_len) ((wem)->masks + 2 * (mask_len))
#define WEM_SEND_MASK(wem, mask_len) ((wem)->masks + 3 * (mask_len))
typedef uint32_t sccb_mask_t;
typedef uint64_t sccb_mask_t;
typedef struct EventBufferHeader {
uint16_t length;
@ -210,4 +210,6 @@ typedef struct SCLPEventFacilityClass {
bool (*event_pending)(SCLPEventFacility *ef);
} SCLPEventFacilityClass;
BusState *sclp_get_event_facility_bus(void);
#endif

Binary file not shown.

View File

@ -9,7 +9,9 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw)
.PHONY : all clean build-all
OBJECTS = start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o virtio-blkdev.o libc.o menu.o
OBJECTS = start.o main.o bootmap.o jump2ipl.o sclp.o menu.o \
virtio.o virtio-scsi.o virtio-blkdev.o libc.o
QEMU_CFLAGS := $(filter -W%, $(QEMU_CFLAGS))
QEMU_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -msoft-float
QEMU_CFLAGS += -march=z900 -fPIE -fno-strict-aliasing

View File

@ -29,14 +29,6 @@
/* Scratch space */
static uint8_t sec[MAX_SECTOR_SIZE*4] __attribute__((__aligned__(PAGE_SIZE)));
typedef struct ResetInfo {
uint32_t ipl_mask;
uint32_t ipl_addr;
uint32_t ipl_continue;
} ResetInfo;
static ResetInfo save;
const uint8_t el_torito_magic[] = "EL TORITO SPECIFICATION"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
@ -57,53 +49,6 @@ static inline bool is_iso_vd_valid(IsoVolDesc *vd)
vd->type <= VOL_DESC_TYPE_PARTITION;
}
static void jump_to_IPL_2(void)
{
ResetInfo *current = 0;
void (*ipl)(void) = (void *) (uint64_t) current->ipl_continue;
*current = save;
ipl(); /* should not return */
}
static void jump_to_IPL_code(uint64_t address)
{
/* store the subsystem information _after_ the bootmap was loaded */
write_subsystem_identification();
/* prevent unknown IPL types in the guest */
if (iplb.pbt == S390_IPL_TYPE_QEMU_SCSI) {
iplb.pbt = S390_IPL_TYPE_CCW;
set_iplb(&iplb);
}
/*
* The IPL PSW is at address 0. We also must not overwrite the
* content of non-BIOS memory after we loaded the guest, so we
* save the original content and restore it in jump_to_IPL_2.
*/
ResetInfo *current = 0;
save = *current;
current->ipl_addr = (uint32_t) (uint64_t) &jump_to_IPL_2;
current->ipl_continue = address & 0x7fffffff;
debug_print_int("set IPL addr to", current->ipl_continue);
/* Ensure the guest output starts fresh */
sclp_print("\n");
/*
* HACK ALERT.
* We use the load normal reset to keep r15 unchanged. jump_to_IPL_2
* can then use r15 as its stack pointer.
*/
asm volatile("lghi 1,1\n\t"
"diag 1,1,0x308\n\t"
: : : "1", "memory");
panic("\n! IPL returns !\n");
}
/***********************************************************************
* IPL an ECKD DASD (CDL or LDL/CMS format)
*/
@ -297,7 +242,7 @@ static void run_eckd_boot_script(block_number_t bmt_block_nr,
}
debug_print_int("loadparm", loadparm);
IPL_assert(loadparm <= MAX_TABLE_ENTRIES, "loadparm value greater than"
IPL_assert(loadparm < MAX_BOOT_ENTRIES, "loadparm value greater than"
" maximum number of boot entries allowed");
memset(sec, FREE_SPACE_FILLER, sizeof(sec));
@ -565,6 +510,8 @@ static void ipl_scsi(void)
int program_table_entries = 0;
BootMapTable *prog_table = (void *)sec;
unsigned int loadparm = get_loadparm_index();
bool valid_entries[MAX_BOOT_ENTRIES] = {false};
size_t i;
/* Grab the MBR */
memset(sec, FREE_SPACE_FILLER, sizeof(sec));
@ -585,22 +532,22 @@ static void ipl_scsi(void)
read_block(mbr->pt.blockno, sec, "Error reading Program Table");
IPL_assert(magic_match(sec, ZIPL_MAGIC), "No zIPL magic in PT");
while (program_table_entries <= MAX_TABLE_ENTRIES) {
if (!prog_table->entry[program_table_entries].scsi.blockno) {
break;
for (i = 0; i < MAX_BOOT_ENTRIES; i++) {
if (prog_table->entry[i].scsi.blockno) {
valid_entries[i] = true;
program_table_entries++;
}
program_table_entries++;
}
debug_print_int("program table entries", program_table_entries);
IPL_assert(program_table_entries != 0, "Empty Program Table");
if (menu_is_enabled_enum()) {
loadparm = menu_get_enum_boot_index(program_table_entries);
loadparm = menu_get_enum_boot_index(valid_entries);
}
debug_print_int("loadparm", loadparm);
IPL_assert(loadparm <= MAX_TABLE_ENTRIES, "loadparm value greater than"
IPL_assert(loadparm < MAX_BOOT_ENTRIES, "loadparm value greater than"
" maximum number of boot entries allowed");
zipl_run(&prog_table->entry[loadparm].scsi); /* no return */
@ -727,13 +674,7 @@ static void load_iso_bc_entry(IsoBcSection *load)
(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);
jump_to_low_kernel();
}
static uint32_t find_iso_bc(void)

View File

@ -57,8 +57,6 @@ typedef union BootMapPointer {
ExtEckdBlockPtr xeckd;
} __attribute__ ((packed)) BootMapPointer;
#define MAX_TABLE_ENTRIES 30
/* aka Program Table */
typedef struct BootMapTable {
uint8_t magic[4];
@ -355,10 +353,6 @@ static inline uint32_t iso_733_to_u32(uint64_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

View File

@ -101,10 +101,11 @@ static inline bool manage_iplb(IplParameterBlock *iplb, bool store)
{
register unsigned long addr asm("0") = (unsigned long) iplb;
register unsigned long rc asm("1") = 0;
unsigned long subcode = store ? 6 : 5;
asm volatile ("diag %0,%2,0x308\n"
: "+d" (addr), "+d" (rc)
: "d" (store ? 6 : 5)
: "d" (subcode)
: "memory", "cc");
return rc == 0x01;
}

View File

@ -0,0 +1,91 @@
/*
* QEMU s390-ccw firmware - jump to IPL code
*
* This work is licensed under the terms of the GNU GPL, version 2 or (at
* your option) any later version. See the COPYING file in the top-level
* directory.
*/
#include "libc.h"
#include "s390-ccw.h"
#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)
typedef struct ResetInfo {
uint32_t ipl_mask;
uint32_t ipl_addr;
uint32_t ipl_continue;
} ResetInfo;
static ResetInfo save;
static void jump_to_IPL_2(void)
{
ResetInfo *current = 0;
void (*ipl)(void) = (void *) (uint64_t) current->ipl_continue;
*current = save;
ipl(); /* should not return */
}
void jump_to_IPL_code(uint64_t address)
{
/* store the subsystem information _after_ the bootmap was loaded */
write_subsystem_identification();
/* prevent unknown IPL types in the guest */
if (iplb.pbt == S390_IPL_TYPE_QEMU_SCSI) {
iplb.pbt = S390_IPL_TYPE_CCW;
set_iplb(&iplb);
}
/*
* The IPL PSW is at address 0. We also must not overwrite the
* content of non-BIOS memory after we loaded the guest, so we
* save the original content and restore it in jump_to_IPL_2.
*/
ResetInfo *current = 0;
save = *current;
current->ipl_addr = (uint32_t) (uint64_t) &jump_to_IPL_2;
current->ipl_continue = address & 0x7fffffff;
debug_print_int("set IPL addr to", current->ipl_continue);
/* Ensure the guest output starts fresh */
sclp_print("\n");
/*
* HACK ALERT.
* We use the load normal reset to keep r15 unchanged. jump_to_IPL_2
* can then use r15 as its stack pointer.
*/
asm volatile("lghi 1,1\n\t"
"diag 1,1,0x308\n\t"
: : : "1", "memory");
panic("\n! IPL returns !\n");
}
void jump_to_low_kernel(void)
{
/*
* If it looks like a Linux binary, i.e. there is the "S390EP" magic from
* arch/s390/kernel/head.S here, then let's jump to the well-known Linux
* kernel start address (when jumping to the PSW-at-zero address instead,
* the kernel startup code fails when we booted from a network device).
*/
if (!memcmp((char *)0x10008, "S390EP", 6)) {
jump_to_IPL_code(KERN_IMAGE_START);
}
/* Trying to get PSW at zero address */
if (*((uint64_t *)0) & IPL_PSW_MASK) {
jump_to_IPL_code((*((uint64_t *)0)) & 0x7fffffff);
}
/* No other option left, so use the Linux kernel start address */
jump_to_IPL_code(KERN_IMAGE_START);
}

View File

@ -63,7 +63,7 @@ uint64_t atoui(const char *str)
*/
char *uitoa(uint64_t num, char *str, size_t len)
{
size_t num_idx = 1; /* account for NUL */
long num_idx = 1; /* account for NUL */
uint64_t tmp = num;
IPL_assert(str != NULL, "uitoa: no space allocated to store string");

View File

@ -12,7 +12,7 @@
#ifndef S390_CCW_LIBC_H
#define S390_CCW_LIBC_H
typedef long size_t;
typedef unsigned long size_t;
typedef int bool;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;

View File

@ -15,11 +15,11 @@
char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
static SubChannelId blk_schid = { .one = 1 };
IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
static char loadparm[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
static char loadparm_str[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
QemuIplParameters qipl;
#define LOADPARM_PROMPT "PROMPT "
#define LOADPARM_EMPTY "........"
#define LOADPARM_EMPTY " "
#define BOOT_MENU_FLAG_MASK (QIPL_FLAG_BM_OPTS_CMD | QIPL_FLAG_BM_OPTS_ZIPL)
/*
@ -45,7 +45,7 @@ void panic(const char *string)
unsigned int get_loadparm_index(void)
{
return atoui(loadparm);
return atoui(loadparm_str);
}
static bool find_dev(Schib *schib, int dev_no)
@ -80,13 +80,13 @@ static bool find_dev(Schib *schib, int dev_no)
static void menu_setup(void)
{
if (memcmp(loadparm, LOADPARM_PROMPT, 8) == 0) {
if (memcmp(loadparm_str, LOADPARM_PROMPT, 8) == 0) {
menu_set_parms(QIPL_FLAG_BM_OPTS_CMD, 0);
return;
}
/* If loadparm was set to any other value, then do not enable menu */
if (memcmp(loadparm, LOADPARM_EMPTY, 8) != 0) {
if (memcmp(loadparm_str, LOADPARM_EMPTY, 8) != 0) {
return;
}
@ -116,8 +116,8 @@ static void virtio_setup(void)
*/
enable_mss_facility();
sclp_get_loadparm_ascii(loadparm);
memcpy(ldp + 10, loadparm, 8);
sclp_get_loadparm_ascii(loadparm_str);
memcpy(ldp + 10, loadparm_str, 8);
sclp_print(ldp);
memcpy(&qipl, early_qipl, sizeof(QemuIplParameters));

View File

@ -158,7 +158,7 @@ static void boot_menu_prompt(bool retry)
}
}
static int get_boot_index(int entries)
static int get_boot_index(bool *valid_entries)
{
int boot_index;
bool retry = false;
@ -168,7 +168,8 @@ static int get_boot_index(int entries)
boot_menu_prompt(retry);
boot_index = get_index();
retry = true;
} while (boot_index < 0 || boot_index >= entries);
} while (boot_index < 0 || boot_index >= MAX_BOOT_ENTRIES ||
!valid_entries[boot_index]);
sclp_print("\nBooting entry #");
sclp_print(uitoa(boot_index, tmp, sizeof(tmp)));
@ -176,7 +177,8 @@ static int get_boot_index(int entries)
return boot_index;
}
static void zipl_println(const char *data, size_t len)
/* Returns the entry number that was printed */
static int zipl_print_entry(const char *data, size_t len)
{
char buf[len + 2];
@ -185,12 +187,15 @@ static void zipl_println(const char *data, size_t len)
buf[len + 1] = '\0';
sclp_print(buf);
return buf[0] == ' ' ? atoui(buf + 1) : atoui(buf);
}
int menu_get_zipl_boot_index(const char *menu_data)
{
size_t len;
int entries;
int entry;
bool valid_entries[MAX_BOOT_ENTRIES] = {false};
uint16_t zipl_flag = *(uint16_t *)(menu_data - ZIPL_FLAG_OFFSET);
uint16_t zipl_timeout = *(uint16_t *)(menu_data - ZIPL_TIMEOUT_OFFSET);
@ -202,34 +207,51 @@ int menu_get_zipl_boot_index(const char *menu_data)
timeout = zipl_timeout * 1000;
}
/* Print and count all menu items, including the banner */
for (entries = 0; *menu_data; entries++) {
/* Print banner */
sclp_print("s390-ccw zIPL Boot Menu\n\n");
menu_data += strlen(menu_data) + 1;
/* Print entries */
while (*menu_data) {
len = strlen(menu_data);
zipl_println(menu_data, len);
entry = zipl_print_entry(menu_data, len);
menu_data += len + 1;
if (entries < 2) {
valid_entries[entry] = true;
if (entry == 0) {
sclp_print("\n");
}
}
sclp_print("\n");
return get_boot_index(entries - 1); /* subtract 1 to exclude banner */
return get_boot_index(valid_entries);
}
int menu_get_enum_boot_index(int entries)
int menu_get_enum_boot_index(bool *valid_entries)
{
char tmp[4];
char tmp[3];
int i;
sclp_print("s390x Enumerated Boot Menu.\n\n");
sclp_print("s390-ccw Enumerated Boot Menu.\n\n");
sclp_print(uitoa(entries, tmp, sizeof(tmp)));
sclp_print(" entries detected. Select from boot index 0 to ");
sclp_print(uitoa(entries - 1, tmp, sizeof(tmp)));
sclp_print(".\n\n");
for (i = 0; i < MAX_BOOT_ENTRIES; i++) {
if (valid_entries[i]) {
if (i < 10) {
sclp_print(" ");
}
sclp_print("[");
sclp_print(uitoa(i, tmp, sizeof(tmp)));
sclp_print("]");
if (i == 0) {
sclp_print(" default\n");
}
sclp_print("\n");
}
}
return get_boot_index(entries);
sclp_print("\n");
return get_boot_index(valid_entries);
}
void menu_set_parms(uint8_t boot_menu_flag, uint32_t boot_menu_timeout)

View File

@ -1,7 +1,8 @@
SLOF_DIR := $(SRC_PATH)/roms/SLOF
NETOBJS := start.o sclp.o virtio.o virtio-net.o netmain.o libnet.a libc.a
NETOBJS := start.o sclp.o virtio.o virtio-net.o jump2ipl.o netmain.o \
libnet.a libc.a
LIBC_INC := -nostdinc -I$(SLOF_DIR)/lib/libc/include
LIBNET_INC := -I$(SLOF_DIR)/lib/libnet

View File

@ -39,8 +39,12 @@
extern char _start[];
#define KERNEL_ADDR ((void *)0L)
#define KERNEL_MAX_SIZE ((long)_start)
char stack[PAGE_SIZE * 8] __attribute__((aligned(PAGE_SIZE)));
IplParameterBlock iplb __attribute__((aligned(PAGE_SIZE)));
static char cfgbuf[2048];
static SubChannelId net_schid = { .one = 1 };
static int ip_version = 4;
@ -128,17 +132,23 @@ static void seed_rng(uint8_t mac[])
srand(seed);
}
static int tftp_load(filename_ip_t *fnip, void *buffer, int len,
unsigned int retries, int ip_vers)
static int tftp_load(filename_ip_t *fnip, void *buffer, int len)
{
tftp_err_t tftp_err;
int rc;
rc = tftp(fnip, buffer, len, retries, &tftp_err, 1, 1428, ip_vers);
rc = tftp(fnip, buffer, len, DEFAULT_TFTP_RETRIES, &tftp_err, 1, 1428,
ip_version);
if (rc > 0) {
printf(" TFTP: Received %s (%d KBytes)\n", fnip->filename,
rc / 1024);
if (rc < 0) {
/* Make sure that error messages are put into a new line */
printf("\n ");
}
if (rc > 1024) {
printf(" TFTP: Received %s (%d KBytes)\n", fnip->filename, rc / 1024);
} else if (rc > 0) {
printf(" TFTP: Received %s (%d Bytes)\n", fnip->filename, rc);
} else if (rc == -1) {
puts("unknown TFTP error");
} else if (rc == -2) {
@ -199,20 +209,19 @@ static int tftp_load(filename_ip_t *fnip, void *buffer, int len,
return rc;
}
static int net_load(char *buffer, int len)
static int net_init(filename_ip_t *fn_ip)
{
filename_ip_t fn_ip;
uint8_t mac[6];
int rc;
memset(&fn_ip, 0, sizeof(filename_ip_t));
memset(fn_ip, 0, sizeof(filename_ip_t));
rc = virtio_net_init(mac);
if (rc < 0) {
puts("Could not initialize network device");
return -101;
}
fn_ip.fd = rc;
fn_ip->fd = rc;
printf(" Using MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
@ -220,10 +229,10 @@ static int net_load(char *buffer, int len)
set_mac_address(mac); /* init ethernet layer */
seed_rng(mac);
rc = dhcp(&fn_ip, DEFAULT_BOOT_RETRIES);
rc = dhcp(fn_ip, DEFAULT_BOOT_RETRIES);
if (rc >= 0) {
if (ip_version == 4) {
set_ipv4_address(fn_ip.own_ip);
set_ipv4_address(fn_ip->own_ip);
}
} else {
puts("Could not get IP address");
@ -232,18 +241,18 @@ static int net_load(char *buffer, int len)
if (ip_version == 4) {
printf(" Using IPv4 address: %d.%d.%d.%d\n",
(fn_ip.own_ip >> 24) & 0xFF, (fn_ip.own_ip >> 16) & 0xFF,
(fn_ip.own_ip >> 8) & 0xFF, fn_ip.own_ip & 0xFF);
(fn_ip->own_ip >> 24) & 0xFF, (fn_ip->own_ip >> 16) & 0xFF,
(fn_ip->own_ip >> 8) & 0xFF, fn_ip->own_ip & 0xFF);
} else if (ip_version == 6) {
char ip6_str[40];
ipv6_to_str(fn_ip.own_ip6.addr, ip6_str);
ipv6_to_str(fn_ip->own_ip6.addr, ip6_str);
printf(" Using IPv6 address: %s\n", ip6_str);
}
if (rc == -2) {
printf("ARP request to TFTP server (%d.%d.%d.%d) failed\n",
(fn_ip.server_ip >> 24) & 0xFF, (fn_ip.server_ip >> 16) & 0xFF,
(fn_ip.server_ip >> 8) & 0xFF, fn_ip.server_ip & 0xFF);
(fn_ip->server_ip >> 24) & 0xFF, (fn_ip->server_ip >> 16) & 0xFF,
(fn_ip->server_ip >> 8) & 0xFF, fn_ip->server_ip & 0xFF);
return -102;
}
if (rc == -4 || rc == -3) {
@ -251,28 +260,108 @@ static int net_load(char *buffer, int len)
return -107;
}
printf(" Using TFTP server: ");
if (ip_version == 4) {
printf(" Requesting file \"%s\" via TFTP from %d.%d.%d.%d\n",
fn_ip.filename,
(fn_ip.server_ip >> 24) & 0xFF, (fn_ip.server_ip >> 16) & 0xFF,
(fn_ip.server_ip >> 8) & 0xFF, fn_ip.server_ip & 0xFF);
printf("%d.%d.%d.%d\n",
(fn_ip->server_ip >> 24) & 0xFF, (fn_ip->server_ip >> 16) & 0xFF,
(fn_ip->server_ip >> 8) & 0xFF, fn_ip->server_ip & 0xFF);
} else if (ip_version == 6) {
char ip6_str[40];
printf(" Requesting file \"%s\" via TFTP from ", fn_ip.filename);
ipv6_to_str(fn_ip.server_ip6.addr, ip6_str);
ipv6_to_str(fn_ip->server_ip6.addr, ip6_str);
printf("%s\n", ip6_str);
}
/* Do the TFTP load and print error message if necessary */
rc = tftp_load(&fn_ip, buffer, len, DEFAULT_TFTP_RETRIES, ip_version);
if (ip_version == 4) {
dhcp_send_release(fn_ip.fd);
if (strlen((char *)fn_ip->filename) > 0) {
printf(" Bootfile name: '%s'\n", fn_ip->filename);
}
return rc;
}
static void net_release(filename_ip_t *fn_ip)
{
if (ip_version == 4) {
dhcp_send_release(fn_ip->fd);
}
}
/**
* Load via information from a .INS file (which can be found on CD-ROMs
* for example)
*/
static int handle_ins_cfg(filename_ip_t *fn_ip, char *cfg, int cfgsize)
{
char *ptr;
int rc = -1, llen;
void *destaddr;
char *insbuf = cfg;
ptr = strchr(insbuf, '\n');
if (!ptr) {
puts("Does not seem to be a valid .INS file");
return -1;
}
*ptr = 0;
printf("\nParsing .INS file:\n %s\n", &insbuf[2]);
insbuf = ptr + 1;
while (*insbuf && insbuf < cfg + cfgsize) {
ptr = strchr(insbuf, '\n');
if (ptr) {
*ptr = 0;
}
llen = strlen(insbuf);
if (!llen) {
insbuf = ptr + 1;
continue;
}
ptr = strchr(insbuf, ' ');
if (!ptr) {
puts("Missing space separator in .INS file");
return -1;
}
*ptr = 0;
strncpy((char *)fn_ip->filename, insbuf, sizeof(fn_ip->filename));
destaddr = (char *)atol(ptr + 1);
rc = tftp_load(fn_ip, destaddr, (long)_start - (long)destaddr);
if (rc <= 0) {
break;
}
insbuf += llen + 1;
}
return rc;
}
static int net_try_direct_tftp_load(filename_ip_t *fn_ip)
{
int rc;
void *loadaddr = (void *)0x2000; /* Load right after the low-core */
rc = tftp_load(fn_ip, loadaddr, KERNEL_MAX_SIZE - (long)loadaddr);
if (rc < 0) {
return rc;
} else if (rc < 8) {
printf("'%s' is too small (%i bytes only).\n", fn_ip->filename, rc);
return -1;
}
/* Check whether it is a configuration file instead of a kernel */
if (rc < sizeof(cfgbuf) - 1) {
memcpy(cfgbuf, loadaddr, rc);
cfgbuf[rc] = 0; /* Make sure that it is NUL-terminated */
if (!strncmp("* ", cfgbuf, 2)) {
return handle_ins_cfg(fn_ip, cfgbuf, rc);
}
}
/* Move kernel to right location */
memmove(KERNEL_ADDR, loadaddr, rc);
return rc;
}
void panic(const char *string)
{
sclp_print(string);
@ -281,6 +370,15 @@ void panic(const char *string)
}
}
void write_subsystem_identification(void)
{
SubChannelId *schid = (SubChannelId *) 184;
uint32_t *zeroes = (uint32_t *) 188;
*schid = net_schid;
*zeroes = 0;
}
static bool find_net_dev(Schib *schib, int dev_no)
{
int i, r;
@ -344,17 +442,29 @@ static void virtio_setup(void)
void main(void)
{
int rc;
filename_ip_t fn_ip;
int rc, fnlen;
sclp_setup();
sclp_print("Network boot starting...\n");
virtio_setup();
rc = net_load(NULL, (long)_start);
rc = net_init(&fn_ip);
if (rc) {
panic("Network initialization failed. Halting.\n");
}
fnlen = strlen((char *)fn_ip.filename);
if (fnlen > 0 && fn_ip.filename[fnlen - 1] != '/') {
rc = net_try_direct_tftp_load(&fn_ip);
}
net_release(&fn_ip);
if (rc > 0) {
sclp_print("Network loading done, starting kernel...\n");
asm volatile (" lpsw 0(%0) " : : "r"(0) : "memory");
jump_to_low_kernel();
}
panic("Failed to load OS from network\n");

View File

@ -87,13 +87,19 @@ ulong get_second(void);
/* bootmap.c */
void zipl_load(void);
/* jump2ipl.c */
void jump_to_IPL_code(uint64_t address);
void jump_to_low_kernel(void);
/* menu.c */
void menu_set_parms(uint8_t boot_menu_flag, uint32_t boot_menu_timeout);
int menu_get_zipl_boot_index(const char *menu_data);
bool menu_is_enabled_zipl(void);
int menu_get_enum_boot_index(int entries);
int menu_get_enum_boot_index(bool *valid_entries);
bool menu_is_enabled_enum(void);
#define MAX_BOOT_ENTRIES 31
static inline void fill_hex(char *out, unsigned char val)
{
const char hex[] = "0123456789abcdef";

Binary file not shown.

View File

@ -1081,7 +1081,6 @@ static int kvm_sclp_service_call(S390CPU *cpu, struct kvm_run *run,
uint32_t code;
int r = 0;
cpu_synchronize_state(CPU(cpu));
sccb = env->regs[ipbh0 & 0xf];
code = env->regs[(ipbh0 & 0xf0) >> 4];
@ -1101,8 +1100,6 @@ static int handle_b2(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1)
int rc = 0;
uint16_t ipbh0 = (run->s390_sieic.ipb & 0xffff0000) >> 16;
cpu_synchronize_state(CPU(cpu));
switch (ipa1) {
case PRIV_B2_XSCH:
ioinst_handle_xsch(cpu, env->regs[1], RA_IGNORED);
@ -1248,7 +1245,6 @@ static int kvm_stpcifc_service_call(S390CPU *cpu, struct kvm_run *run)
uint8_t ar;
if (s390_has_feat(S390_FEAT_ZPCI)) {
cpu_synchronize_state(CPU(cpu));
fiba = get_base_disp_rxy(cpu, run, &ar);
return stpcifc_service_call(cpu, r1, fiba, ar, RA_IGNORED);
@ -1266,7 +1262,6 @@ static int kvm_sic_service_call(S390CPU *cpu, struct kvm_run *run)
uint16_t mode;
int r;
cpu_synchronize_state(CPU(cpu));
mode = env->regs[r1] & 0xffff;
isc = (env->regs[r3] >> 27) & 0x7;
r = css_do_sic(env, isc, mode);
@ -1297,7 +1292,6 @@ static int kvm_pcistb_service_call(S390CPU *cpu, struct kvm_run *run)
uint8_t ar;
if (s390_has_feat(S390_FEAT_ZPCI)) {
cpu_synchronize_state(CPU(cpu));
gaddr = get_base_disp_rsy(cpu, run, &ar);
return pcistb_service_call(cpu, r1, r3, gaddr, ar, RA_IGNORED);
@ -1313,7 +1307,6 @@ static int kvm_mpcifc_service_call(S390CPU *cpu, struct kvm_run *run)
uint8_t ar;
if (s390_has_feat(S390_FEAT_ZPCI)) {
cpu_synchronize_state(CPU(cpu));
fiba = get_base_disp_rxy(cpu, run, &ar);
return mpcifc_service_call(cpu, r1, fiba, ar, RA_IGNORED);
@ -1401,7 +1394,6 @@ static int handle_hypercall(S390CPU *cpu, struct kvm_run *run)
CPUS390XState *env = &cpu->env;
int ret;
cpu_synchronize_state(CPU(cpu));
ret = s390_virtio_hypercall(env);
if (ret == -EINVAL) {
kvm_s390_program_interrupt(cpu, PGM_SPECIFICATION);
@ -1416,7 +1408,6 @@ static void kvm_handle_diag_288(S390CPU *cpu, struct kvm_run *run)
uint64_t r1, r3;
int rc;
cpu_synchronize_state(CPU(cpu));
r1 = (run->s390_sieic.ipa & 0x00f0) >> 4;
r3 = run->s390_sieic.ipa & 0x000f;
rc = handle_diag_288(&cpu->env, r1, r3);
@ -1429,7 +1420,6 @@ static void kvm_handle_diag_308(S390CPU *cpu, struct kvm_run *run)
{
uint64_t r1, r3;
cpu_synchronize_state(CPU(cpu));
r1 = (run->s390_sieic.ipa & 0x00f0) >> 4;
r3 = run->s390_sieic.ipa & 0x000f;
handle_diag_308(&cpu->env, r1, r3, RA_IGNORED);
@ -1440,8 +1430,6 @@ static int handle_sw_breakpoint(S390CPU *cpu, struct kvm_run *run)
CPUS390XState *env = &cpu->env;
unsigned long pc;
cpu_synchronize_state(CPU(cpu));
pc = env->psw.addr - sw_bp_ilen;
if (kvm_find_sw_breakpoint(CPU(cpu), pc)) {
env->psw.addr = pc;
@ -1493,8 +1481,6 @@ static int kvm_s390_handle_sigp(S390CPU *cpu, uint8_t ipa1, uint32_t ipb)
int ret;
uint8_t order;
cpu_synchronize_state(CPU(cpu));
/* get order code */
order = decode_basedisp_rs(env, ipb, NULL) & SIGP_ORDER_MASK;
@ -1556,7 +1542,6 @@ static int handle_oper_loop(S390CPU *cpu, struct kvm_run *run)
CPUState *cs = CPU(cpu);
PSW oldpsw, newpsw;
cpu_synchronize_state(cs);
newpsw.mask = ldq_phys(cs->as, cpu->env.psa +
offsetof(LowCore, program_new_psw));
newpsw.addr = ldq_phys(cs->as, cpu->env.psa +
@ -1609,7 +1594,6 @@ static int handle_intercept(S390CPU *cpu)
break;
case ICPT_WAITPSW:
/* disabled wait, since enabled wait is handled in kernel */
cpu_synchronize_state(cs);
s390_handle_wait(cpu);
r = EXCP_HALTED;
break;
@ -1651,8 +1635,6 @@ static int handle_tsch(S390CPU *cpu)
struct kvm_run *run = cs->kvm_run;
int ret;
cpu_synchronize_state(cs);
ret = ioinst_handle_tsch(cpu, cpu->env.regs[1], run->s390_tsch.ipb,
RA_IGNORED);
if (ret < 0) {
@ -1778,7 +1760,7 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
qemu_mutex_lock_iothread();
cpu_synchronize_state(cs);
kvm_cpu_synchronize_state(cs);
switch (run->exit_reason) {
case KVM_EXIT_S390_SIEIC:

View File

@ -96,8 +96,7 @@ static testdef_t tests[] = {
{ "sparc", "SS-4", "", "MB86904" },
{ "sparc", "SS-600MP", "", "TMS390Z55" },
{ "sparc64", "sun4u", "", "UltraSPARC" },
{ "s390x", "s390-ccw-virtio",
"-nodefaults -device sclpconsole,chardev=serial0", "virtio device" },
{ "s390x", "s390-ccw-virtio", "", "virtio device" },
{ "m68k", "mcf5208evb", "", "TT", sizeof(kernel_mcf5208), kernel_mcf5208 },
{ "microblaze", "petalogix-s3adsp1800", "", "TT",
sizeof(kernel_pls3adsp1800), kernel_pls3adsp1800 },

50
vl.c
View File

@ -133,7 +133,6 @@ int main(int argc, char **argv)
#include "sysemu/iothread.h"
#define MAX_VIRTIO_CONSOLES 1
#define MAX_SCLP_CONSOLES 1
static const char *data_dir[16];
static int data_dir_idx;
@ -158,7 +157,6 @@ static int num_serial_hds = 0;
static Chardev **serial_hds = NULL;
Chardev *parallel_hds[MAX_PARALLEL_PORTS];
Chardev *virtcon_hds[MAX_VIRTIO_CONSOLES];
Chardev *sclp_hds[MAX_SCLP_CONSOLES];
int win2k_install_hack = 0;
int singlestep = 0;
int smp_cpus;
@ -210,7 +208,6 @@ static int has_defaults = 1;
static int default_serial = 1;
static int default_parallel = 1;
static int default_virtcon = 1;
static int default_sclp = 1;
static int default_monitor = 1;
static int default_floppy = 1;
static int default_cdrom = 1;
@ -2588,39 +2585,6 @@ static int virtcon_parse(const char *devname)
return 0;
}
static int sclp_parse(const char *devname)
{
QemuOptsList *device = qemu_find_opts("device");
static int index = 0;
char label[32];
QemuOpts *dev_opts;
if (strcmp(devname, "none") == 0) {
return 0;
}
if (index == MAX_SCLP_CONSOLES) {
error_report("too many sclp consoles");
exit(1);
}
assert(arch_type == QEMU_ARCH_S390X);
dev_opts = qemu_opts_create(device, NULL, 0, NULL);
qemu_opt_set(dev_opts, "driver", "sclpconsole", &error_abort);
snprintf(label, sizeof(label), "sclpcon%d", index);
sclp_hds[index] = qemu_chr_new(label, devname);
if (!sclp_hds[index]) {
error_report("could not connect sclp console"
" to character backend '%s'", devname);
return -1;
}
qemu_opt_set(dev_opts, "chardev", label, &error_abort);
index++;
return 0;
}
static int debugcon_parse(const char *devname)
{
QemuOpts *opts;
@ -4254,9 +4218,6 @@ int main(int argc, char **argv, char **envp)
if (!has_defaults || !machine_class->use_virtcon) {
default_virtcon = 0;
}
if (!has_defaults || !machine_class->use_sclp) {
default_sclp = 0;
}
if (!has_defaults || machine_class->no_floppy) {
default_floppy = 0;
}
@ -4303,16 +4264,11 @@ int main(int argc, char **argv, char **envp)
add_device_config(DEV_SERIAL, "mon:stdio");
} else if (default_virtcon && default_monitor) {
add_device_config(DEV_VIRTCON, "mon:stdio");
} else if (default_sclp && default_monitor) {
add_device_config(DEV_SCLP, "mon:stdio");
} else {
if (default_serial)
add_device_config(DEV_SERIAL, "stdio");
if (default_virtcon)
add_device_config(DEV_VIRTCON, "stdio");
if (default_sclp) {
add_device_config(DEV_SCLP, "stdio");
}
if (default_monitor)
monitor_parse("stdio", "readline", false);
}
@ -4325,9 +4281,6 @@ int main(int argc, char **argv, char **envp)
monitor_parse("vc:80Cx24C", "readline", false);
if (default_virtcon)
add_device_config(DEV_VIRTCON, "vc:80Cx24C");
if (default_sclp) {
add_device_config(DEV_SCLP, "vc:80Cx24C");
}
}
#if defined(CONFIG_VNC)
@ -4577,9 +4530,6 @@ int main(int argc, char **argv, char **envp)
exit(1);
if (foreach_device_config(DEV_VIRTCON, virtcon_parse) < 0)
exit(1);
if (foreach_device_config(DEV_SCLP, sclp_parse) < 0) {
exit(1);
}
if (foreach_device_config(DEV_DEBUGCON, debugcon_parse) < 0)
exit(1);