mirror of https://github.com/xemu-project/xemu.git
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:
commit
46e04dacd3
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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.
|
@ -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:
|
||||
|
|
|
@ -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
50
vl.c
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue