mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-11 03:24:58 -06:00
- cleanup in virtio-ccw
- accommodate guests using vfio-ccw without specifying unlimited prefetch, but actually working fine - add cpu model for the z14 Model ZR1 - add support for pxelinux.cfg-style network booting to the s390x firmware -----BEGIN PGP SIGNATURE----- iQJGBAABCAAwFiEEw9DWbcNiT/aowBjO3s9rk8bwL68FAlsozdISHGNvaHVja0By ZWRoYXQuY29tAAoJEN7Pa5PG8C+vafQQAIUl+TPrwXQQCp9xBy+CpMAAQtPp0PI2 DGisaVohLQARfNorqDXqPWMy9ulbYQ1bXcdpbhVwzIHlBZopMAvC+QTRwqs4EIFw 0vjvm5ttC2b3zt+7BAom2xWqaxmSen02O0Qj2l5HpFBVp+5afT74geiWhmmirWbw x/JEEnlOcP2dHAvujfbv9Slst1B/OQ4xz7gf5IOlfX2MCsDcIyvqrw6a2D5G4PlX DHPZ7PzA6edoG+qP1DvH6Myi19zs3edAKJp5sdCK92FgJBxW6nI1+ThoN3ApbuDm U7HYeLzrQ/dXWiHMwA+2QP5Iqe/VfKCvqVcm9+m458dQLiN8ZiyGmUbbZtL0L0X8 KQB70mSQjawWRVLr1vsvZNAnCeqjT2hZz37EAwA3gGOeIfFjxFLNtBu4WKgt4soG 7Uq99irLBkfJKY56gQUc0LYOKhTMlDk3Z3xzv2Y2q29T+Cp0927ruHQdRFo3xQAu kBc1pIjt2Rfuh2EJkyoprMuM/e5E8OZZv1uLbqUOYKxIHCHp05wqNEva5WOhS5Ah 05Un03Vw/CVWnXuNSYR+eKrMydIZALA+GTpQYZuiAo8+dT9R3dmTHjQRqOdck3lB BU1MzU3kfflmmToi4Pto1PtNPeAaCWMcFNLOgky3L+Wfx2p4WQxYZP2g42be0K4U m4G6RXHStHCy =hMax -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20180619' into staging - cleanup in virtio-ccw - accommodate guests using vfio-ccw without specifying unlimited prefetch, but actually working fine - add cpu model for the z14 Model ZR1 - add support for pxelinux.cfg-style network booting to the s390x firmware # gpg: Signature made Tue 19 Jun 2018 10:33:06 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-20180619: pc-bios/s390-ccw: Update the s390-netboot.img binary pc-bios/s390-ccw: Optimize the s390-netboot.img for size pc-bios/s390-ccw/net: Try to load pxelinux.cfg file accoring to the UUID pc-bios/s390-ccw/net: Add support for pxelinux-style config files pc-bios/s390-ccw/net: Update code for the latest changes in SLOF roms: Update SLOF submodule to current status pc-bios/s390-ccw: define loadparm length s390x/cpumodels: add z14 Model ZR1 s390x/ipl: Try to detect Linux vs non Linux for initial IPL PSW vfio-ccw: remove orb.c64 (64 bit data addresses) check vfio-ccw: add force unlimited prefetch property virtio-ccw: clean up notify Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
46012db666
14 changed files with 241 additions and 105 deletions
|
@ -1199,18 +1199,6 @@ static IOInstEnding sch_handle_start_func_passthrough(SubchDev *sch)
|
||||||
assert(orb != NULL);
|
assert(orb != NULL);
|
||||||
p->intparm = orb->intparm;
|
p->intparm = orb->intparm;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Only support prefetch enable mode.
|
|
||||||
* Only support 64bit addressing idal.
|
|
||||||
*/
|
|
||||||
if (!(orb->ctrl0 & ORB_CTRL0_MASK_PFCH) ||
|
|
||||||
!(orb->ctrl0 & ORB_CTRL0_MASK_C64)) {
|
|
||||||
warn_report("vfio-ccw requires PFCH and C64 flags set");
|
|
||||||
sch_gen_unit_exception(sch);
|
|
||||||
css_inject_io_interrupt(sch);
|
|
||||||
return IOINST_CC_EXPECTED;
|
|
||||||
}
|
|
||||||
return s390_ccw_cmd_request(sch);
|
return s390_ccw_cmd_request(sch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
|
|
||||||
#define KERN_IMAGE_START 0x010000UL
|
#define KERN_IMAGE_START 0x010000UL
|
||||||
|
#define LINUX_MAGIC_ADDR 0x010008UL
|
||||||
#define KERN_PARM_AREA 0x010480UL
|
#define KERN_PARM_AREA 0x010480UL
|
||||||
#define INITRD_START 0x800000UL
|
#define INITRD_START 0x800000UL
|
||||||
#define INITRD_PARM_START 0x010408UL
|
#define INITRD_PARM_START 0x010408UL
|
||||||
|
@ -105,7 +106,9 @@ static uint64_t bios_translate_addr(void *opaque, uint64_t srcaddr)
|
||||||
static void s390_ipl_realize(DeviceState *dev, Error **errp)
|
static void s390_ipl_realize(DeviceState *dev, Error **errp)
|
||||||
{
|
{
|
||||||
S390IPLState *ipl = S390_IPL(dev);
|
S390IPLState *ipl = S390_IPL(dev);
|
||||||
uint64_t pentry = KERN_IMAGE_START;
|
uint32_t *ipl_psw;
|
||||||
|
uint64_t pentry;
|
||||||
|
char *magic;
|
||||||
int kernel_size;
|
int kernel_size;
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
|
@ -157,11 +160,25 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
|
||||||
NULL, 1, EM_S390, 0, 0);
|
NULL, 1, EM_S390, 0, 0);
|
||||||
if (kernel_size < 0) {
|
if (kernel_size < 0) {
|
||||||
kernel_size = load_image_targphys(ipl->kernel, 0, ram_size);
|
kernel_size = load_image_targphys(ipl->kernel, 0, ram_size);
|
||||||
}
|
|
||||||
if (kernel_size < 0) {
|
if (kernel_size < 0) {
|
||||||
error_setg(&err, "could not load kernel '%s'", ipl->kernel);
|
error_setg(&err, "could not load kernel '%s'", ipl->kernel);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
/* if this is Linux use KERN_IMAGE_START */
|
||||||
|
magic = rom_ptr(LINUX_MAGIC_ADDR);
|
||||||
|
if (magic && !memcmp(magic, "S390EP", 6)) {
|
||||||
|
pentry = KERN_IMAGE_START;
|
||||||
|
} else {
|
||||||
|
/* if not Linux load the address of the (short) IPL PSW */
|
||||||
|
ipl_psw = rom_ptr(4);
|
||||||
|
if (ipl_psw) {
|
||||||
|
pentry = be32_to_cpu(*ipl_psw) & 0x7fffffffUL;
|
||||||
|
} else {
|
||||||
|
error_setg(&err, "Could not get IPL PSW");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Is it a Linux kernel (starting at 0x10000)? If yes, we fill in the
|
* Is it a Linux kernel (starting at 0x10000)? If yes, we fill in the
|
||||||
* kernel parameters here as well. Note: For old kernels (up to 3.2)
|
* kernel parameters here as well. Note: For old kernels (up to 3.2)
|
||||||
|
|
|
@ -1001,10 +1001,15 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
|
||||||
SubchDev *sch = ccw_dev->sch;
|
SubchDev *sch = ccw_dev->sch;
|
||||||
uint64_t indicators;
|
uint64_t indicators;
|
||||||
|
|
||||||
/* queue indicators + secondary indicators */
|
if (vector == VIRTIO_NO_VECTOR) {
|
||||||
if (vector >= VIRTIO_QUEUE_MAX + 64) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* vector < VIRTIO_QUEUE_MAX: notification for a virtqueue
|
||||||
|
* vector == VIRTIO_QUEUE_MAX: configuration change notification
|
||||||
|
* bits beyond that are unused and should never be notified for
|
||||||
|
*/
|
||||||
|
assert(vector <= VIRTIO_QUEUE_MAX);
|
||||||
|
|
||||||
if (vector < VIRTIO_QUEUE_MAX) {
|
if (vector < VIRTIO_QUEUE_MAX) {
|
||||||
if (!dev->indicators) {
|
if (!dev->indicators) {
|
||||||
|
@ -1027,6 +1032,7 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
|
||||||
css_adapter_interrupt(CSS_IO_ADAPTER_VIRTIO, dev->thinint_isc);
|
css_adapter_interrupt(CSS_IO_ADAPTER_VIRTIO, dev->thinint_isc);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
assert(vector < NR_CLASSIC_INDICATOR_BITS);
|
||||||
indicators = address_space_ldq(&address_space_memory,
|
indicators = address_space_ldq(&address_space_memory,
|
||||||
dev->indicators->addr,
|
dev->indicators->addr,
|
||||||
MEMTXATTRS_UNSPECIFIED,
|
MEMTXATTRS_UNSPECIFIED,
|
||||||
|
@ -1040,12 +1046,11 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
|
||||||
if (!dev->indicators2) {
|
if (!dev->indicators2) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
vector = 0;
|
|
||||||
indicators = address_space_ldq(&address_space_memory,
|
indicators = address_space_ldq(&address_space_memory,
|
||||||
dev->indicators2->addr,
|
dev->indicators2->addr,
|
||||||
MEMTXATTRS_UNSPECIFIED,
|
MEMTXATTRS_UNSPECIFIED,
|
||||||
NULL);
|
NULL);
|
||||||
indicators |= 1ULL << vector;
|
indicators |= 1ULL;
|
||||||
address_space_stq(&address_space_memory, dev->indicators2->addr,
|
address_space_stq(&address_space_memory, dev->indicators2->addr,
|
||||||
indicators, MEMTXATTRS_UNSPECIFIED, NULL);
|
indicators, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||||
css_conditional_io_interrupt(sch);
|
css_conditional_io_interrupt(sch);
|
||||||
|
|
|
@ -33,8 +33,30 @@ typedef struct VFIOCCWDevice {
|
||||||
uint64_t io_region_offset;
|
uint64_t io_region_offset;
|
||||||
struct ccw_io_region *io_region;
|
struct ccw_io_region *io_region;
|
||||||
EventNotifier io_notifier;
|
EventNotifier io_notifier;
|
||||||
|
bool force_orb_pfch;
|
||||||
|
bool warned_orb_pfch;
|
||||||
} VFIOCCWDevice;
|
} VFIOCCWDevice;
|
||||||
|
|
||||||
|
static inline void warn_once(bool *warned, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
if (!warned || *warned) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*warned = true;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
warn_vreport(fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void warn_once_pfch(VFIOCCWDevice *vcdev, SubchDev *sch,
|
||||||
|
const char *msg)
|
||||||
|
{
|
||||||
|
warn_once(&vcdev->warned_orb_pfch, "vfio-ccw (devno %x.%x.%04x): %s",
|
||||||
|
sch->cssid, sch->ssid, sch->devno, msg);
|
||||||
|
}
|
||||||
|
|
||||||
static void vfio_ccw_compute_needs_reset(VFIODevice *vdev)
|
static void vfio_ccw_compute_needs_reset(VFIODevice *vdev)
|
||||||
{
|
{
|
||||||
vdev->needs_reset = false;
|
vdev->needs_reset = false;
|
||||||
|
@ -55,6 +77,18 @@ static IOInstEnding vfio_ccw_handle_request(SubchDev *sch)
|
||||||
struct ccw_io_region *region = vcdev->io_region;
|
struct ccw_io_region *region = vcdev->io_region;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (!(sch->orb.ctrl0 & ORB_CTRL0_MASK_PFCH)) {
|
||||||
|
if (!(vcdev->force_orb_pfch)) {
|
||||||
|
warn_once_pfch(vcdev, sch, "requires PFCH flag set");
|
||||||
|
sch_gen_unit_exception(sch);
|
||||||
|
css_inject_io_interrupt(sch);
|
||||||
|
return IOINST_CC_EXPECTED;
|
||||||
|
} else {
|
||||||
|
sch->orb.ctrl0 |= ORB_CTRL0_MASK_PFCH;
|
||||||
|
warn_once_pfch(vcdev, sch, "PFCH flag forced");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QEMU_BUILD_BUG_ON(sizeof(region->orb_area) != sizeof(ORB));
|
QEMU_BUILD_BUG_ON(sizeof(region->orb_area) != sizeof(ORB));
|
||||||
QEMU_BUILD_BUG_ON(sizeof(region->scsw_area) != sizeof(SCSW));
|
QEMU_BUILD_BUG_ON(sizeof(region->scsw_area) != sizeof(SCSW));
|
||||||
QEMU_BUILD_BUG_ON(sizeof(region->irb_area) != sizeof(IRB));
|
QEMU_BUILD_BUG_ON(sizeof(region->irb_area) != sizeof(IRB));
|
||||||
|
@ -430,6 +464,7 @@ static void vfio_ccw_unrealize(DeviceState *dev, Error **errp)
|
||||||
|
|
||||||
static Property vfio_ccw_properties[] = {
|
static Property vfio_ccw_properties[] = {
|
||||||
DEFINE_PROP_STRING("sysfsdev", VFIOCCWDevice, vdev.sysfsdev),
|
DEFINE_PROP_STRING("sysfsdev", VFIOCCWDevice, vdev.sysfsdev),
|
||||||
|
DEFINE_PROP_BOOL("force-orb-pfch", VFIOCCWDevice, force_orb_pfch, false),
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ OBJECTS = start.o main.o bootmap.o jump2ipl.o sclp.o menu.o \
|
||||||
QEMU_CFLAGS := $(filter -W%, $(QEMU_CFLAGS))
|
QEMU_CFLAGS := $(filter -W%, $(QEMU_CFLAGS))
|
||||||
QEMU_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -msoft-float
|
QEMU_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -msoft-float
|
||||||
QEMU_CFLAGS += -march=z900 -fPIE -fno-strict-aliasing
|
QEMU_CFLAGS += -march=z900 -fPIE -fno-strict-aliasing
|
||||||
|
QEMU_CFLAGS += -fno-asynchronous-unwind-tables
|
||||||
QEMU_CFLAGS += $(call cc-option, $(QEMU_CFLAGS), -fno-stack-protector)
|
QEMU_CFLAGS += $(call cc-option, $(QEMU_CFLAGS), -fno-stack-protector)
|
||||||
LDFLAGS += -Wl,-pie -nostdlib
|
LDFLAGS += -Wl,-pie -nostdlib
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
#ifndef IPLB_H
|
#ifndef IPLB_H
|
||||||
#define IPLB_H
|
#define IPLB_H
|
||||||
|
|
||||||
|
#define LOADPARM_LEN 8
|
||||||
|
|
||||||
struct IplBlockCcw {
|
struct IplBlockCcw {
|
||||||
uint8_t reserved0[85];
|
uint8_t reserved0[85];
|
||||||
uint8_t ssid;
|
uint8_t ssid;
|
||||||
|
@ -61,7 +63,7 @@ struct IplParameterBlock {
|
||||||
uint8_t pbt;
|
uint8_t pbt;
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
uint16_t reserved01;
|
uint16_t reserved01;
|
||||||
uint8_t loadparm[8];
|
uint8_t loadparm[LOADPARM_LEN];
|
||||||
union {
|
union {
|
||||||
IplBlockCcw ccw;
|
IplBlockCcw ccw;
|
||||||
IplBlockFcp fcp;
|
IplBlockFcp fcp;
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
|
char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
|
||||||
static SubChannelId blk_schid = { .one = 1 };
|
static SubChannelId blk_schid = { .one = 1 };
|
||||||
IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
|
IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
|
||||||
static char loadparm_str[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
static char loadparm_str[LOADPARM_LEN + 1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||||
QemuIplParameters qipl;
|
QemuIplParameters qipl;
|
||||||
|
|
||||||
#define LOADPARM_PROMPT "PROMPT "
|
#define LOADPARM_PROMPT "PROMPT "
|
||||||
|
@ -80,13 +80,13 @@ static bool find_dev(Schib *schib, int dev_no)
|
||||||
|
|
||||||
static void menu_setup(void)
|
static void menu_setup(void)
|
||||||
{
|
{
|
||||||
if (memcmp(loadparm_str, LOADPARM_PROMPT, 8) == 0) {
|
if (memcmp(loadparm_str, LOADPARM_PROMPT, LOADPARM_LEN) == 0) {
|
||||||
menu_set_parms(QIPL_FLAG_BM_OPTS_CMD, 0);
|
menu_set_parms(QIPL_FLAG_BM_OPTS_CMD, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If loadparm was set to any other value, then do not enable menu */
|
/* If loadparm was set to any other value, then do not enable menu */
|
||||||
if (memcmp(loadparm_str, LOADPARM_EMPTY, 8) != 0) {
|
if (memcmp(loadparm_str, LOADPARM_EMPTY, LOADPARM_LEN) != 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ static void virtio_setup(void)
|
||||||
enable_mss_facility();
|
enable_mss_facility();
|
||||||
|
|
||||||
sclp_get_loadparm_ascii(loadparm_str);
|
sclp_get_loadparm_ascii(loadparm_str);
|
||||||
memcpy(ldp + 10, loadparm_str, 8);
|
memcpy(ldp + 10, loadparm_str, LOADPARM_LEN);
|
||||||
sclp_print(ldp);
|
sclp_print(ldp);
|
||||||
|
|
||||||
memcpy(&qipl, early_qipl, sizeof(QemuIplParameters));
|
memcpy(&qipl, early_qipl, sizeof(QemuIplParameters));
|
||||||
|
|
|
@ -19,14 +19,15 @@ s390-netboot.img: s390-netboot.elf
|
||||||
|
|
||||||
# libc files:
|
# libc files:
|
||||||
|
|
||||||
LIBC_CFLAGS := $(QEMU_CFLAGS) $(LIBC_INC) $(LIBNET_INC)
|
LIBC_CFLAGS := $(QEMU_CFLAGS) $(CFLAGS) $(LIBC_INC) $(LIBNET_INC)
|
||||||
|
|
||||||
CTYPE_OBJS = isdigit.o isxdigit.o toupper.o
|
CTYPE_OBJS = isdigit.o isxdigit.o toupper.o
|
||||||
%.o : $(SLOF_DIR)/lib/libc/ctype/%.c
|
%.o : $(SLOF_DIR)/lib/libc/ctype/%.c
|
||||||
$(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@")
|
$(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@")
|
||||||
|
|
||||||
STRING_OBJS = strcat.o strchr.o strcmp.o strcpy.o strlen.o strncmp.o strncpy.o \
|
STRING_OBJS = strcat.o strchr.o strrchr.o strcpy.o strlen.o strncpy.o \
|
||||||
strstr.o memset.o memcpy.o memmove.o memcmp.o
|
strcmp.o strncmp.o strcasecmp.o strncasecmp.o strstr.o \
|
||||||
|
memset.o memcpy.o memmove.o memcmp.o
|
||||||
%.o : $(SLOF_DIR)/lib/libc/string/%.c
|
%.o : $(SLOF_DIR)/lib/libc/string/%.c
|
||||||
$(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@")
|
$(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@")
|
||||||
|
|
||||||
|
@ -34,7 +35,7 @@ STDLIB_OBJS = atoi.o atol.o strtoul.o strtol.o rand.o malloc.o free.o
|
||||||
%.o : $(SLOF_DIR)/lib/libc/stdlib/%.c
|
%.o : $(SLOF_DIR)/lib/libc/stdlib/%.c
|
||||||
$(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@")
|
$(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@")
|
||||||
|
|
||||||
STDIO_OBJS = sprintf.o vfprintf.o vsnprintf.o vsprintf.o fprintf.o \
|
STDIO_OBJS = sprintf.o snprintf.o vfprintf.o vsnprintf.o vsprintf.o fprintf.o \
|
||||||
printf.o putc.o puts.o putchar.o stdchnls.o fileno.o
|
printf.o putc.o puts.o putchar.o stdchnls.o fileno.o
|
||||||
%.o : $(SLOF_DIR)/lib/libc/stdio/%.c
|
%.o : $(SLOF_DIR)/lib/libc/stdio/%.c
|
||||||
$(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@")
|
$(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@")
|
||||||
|
@ -50,8 +51,8 @@ libc.a: $(LIBCOBJS)
|
||||||
# libnet files:
|
# libnet files:
|
||||||
|
|
||||||
LIBNETOBJS := args.o dhcp.o dns.o icmpv6.o ipv6.o tcp.o udp.o bootp.o \
|
LIBNETOBJS := args.o dhcp.o dns.o icmpv6.o ipv6.o tcp.o udp.o bootp.o \
|
||||||
dhcpv6.o ethernet.o ipv4.o ndp.o tftp.o
|
dhcpv6.o ethernet.o ipv4.o ndp.o tftp.o pxelinux.o
|
||||||
LIBNETCFLAGS := $(QEMU_CFLAGS) -DDHCPARCH=0x1F $(LIBC_INC) $(LIBNET_INC)
|
LIBNETCFLAGS := $(QEMU_CFLAGS) $(CFLAGS) -DDHCPARCH=0x1F $(LIBC_INC) $(LIBNET_INC)
|
||||||
|
|
||||||
%.o : $(SLOF_DIR)/lib/libnet/%.c
|
%.o : $(SLOF_DIR)/lib/libnet/%.c
|
||||||
$(call quiet-command,$(CC) $(LIBNETCFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@")
|
$(call quiet-command,$(CC) $(LIBNETCFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@")
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include <ipv6.h>
|
#include <ipv6.h>
|
||||||
#include <dns.h>
|
#include <dns.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <pxelinux.h>
|
||||||
|
|
||||||
#include "s390-ccw.h"
|
#include "s390-ccw.h"
|
||||||
#include "virtio.h"
|
#include "virtio.h"
|
||||||
|
@ -41,13 +42,17 @@ extern char _start[];
|
||||||
|
|
||||||
#define KERNEL_ADDR ((void *)0L)
|
#define KERNEL_ADDR ((void *)0L)
|
||||||
#define KERNEL_MAX_SIZE ((long)_start)
|
#define KERNEL_MAX_SIZE ((long)_start)
|
||||||
|
#define ARCH_COMMAND_LINE_SIZE 896 /* Taken from Linux kernel */
|
||||||
|
|
||||||
|
/* STSI 3.2.2 offset of first vmdb + offset of uuid inside vmdb */
|
||||||
|
#define STSI322_VMDB_UUID_OFFSET ((8 + 12) * 4)
|
||||||
|
|
||||||
char stack[PAGE_SIZE * 8] __attribute__((aligned(PAGE_SIZE)));
|
char stack[PAGE_SIZE * 8] __attribute__((aligned(PAGE_SIZE)));
|
||||||
IplParameterBlock iplb __attribute__((aligned(PAGE_SIZE)));
|
IplParameterBlock iplb __attribute__((aligned(PAGE_SIZE)));
|
||||||
static char cfgbuf[2048];
|
static char cfgbuf[2048];
|
||||||
|
|
||||||
static SubChannelId net_schid = { .one = 1 };
|
static SubChannelId net_schid = { .one = 1 };
|
||||||
static int ip_version = 4;
|
static uint8_t mac[6];
|
||||||
static uint64_t dest_timer;
|
static uint64_t dest_timer;
|
||||||
|
|
||||||
static uint64_t get_timer_ms(void)
|
static uint64_t get_timer_ms(void)
|
||||||
|
@ -100,10 +105,10 @@ static int dhcp(struct filename_ip *fn_ip, int retries)
|
||||||
printf("\nGiving up after %d DHCP requests\n", retries);
|
printf("\nGiving up after %d DHCP requests\n", retries);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
ip_version = 4;
|
fn_ip->ip_version = 4;
|
||||||
rc = dhcpv4(NULL, fn_ip);
|
rc = dhcpv4(NULL, fn_ip);
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
ip_version = 6;
|
fn_ip->ip_version = 6;
|
||||||
set_ipv6_address(fn_ip->fd, 0);
|
set_ipv6_address(fn_ip->fd, 0);
|
||||||
rc = dhcpv6(NULL, fn_ip);
|
rc = dhcpv6(NULL, fn_ip);
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
|
@ -137,8 +142,7 @@ static int tftp_load(filename_ip_t *fnip, void *buffer, int len)
|
||||||
tftp_err_t tftp_err;
|
tftp_err_t tftp_err;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = tftp(fnip, buffer, len, DEFAULT_TFTP_RETRIES, &tftp_err, 1, 1428,
|
rc = tftp(fnip, buffer, len, DEFAULT_TFTP_RETRIES, &tftp_err);
|
||||||
ip_version);
|
|
||||||
|
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
/* Make sure that error messages are put into a new line */
|
/* Make sure that error messages are put into a new line */
|
||||||
|
@ -149,61 +153,11 @@ static int tftp_load(filename_ip_t *fnip, void *buffer, int len)
|
||||||
printf(" TFTP: Received %s (%d KBytes)\n", fnip->filename, rc / 1024);
|
printf(" TFTP: Received %s (%d KBytes)\n", fnip->filename, rc / 1024);
|
||||||
} else if (rc > 0) {
|
} else if (rc > 0) {
|
||||||
printf(" TFTP: Received %s (%d Bytes)\n", fnip->filename, rc);
|
printf(" TFTP: Received %s (%d Bytes)\n", fnip->filename, rc);
|
||||||
} else if (rc == -1) {
|
} else {
|
||||||
puts("unknown TFTP error");
|
const char *errstr = NULL;
|
||||||
} else if (rc == -2) {
|
int ecode;
|
||||||
printf("TFTP buffer of %d bytes is too small for %s\n",
|
tftp_get_error_info(fnip, &tftp_err, rc, &errstr, &ecode);
|
||||||
len, fnip->filename);
|
printf("TFTP error: %s\n", errstr ? errstr : "unknown error");
|
||||||
} else if (rc == -3) {
|
|
||||||
printf("file not found: %s\n", fnip->filename);
|
|
||||||
} else if (rc == -4) {
|
|
||||||
puts("TFTP access violation");
|
|
||||||
} else if (rc == -5) {
|
|
||||||
puts("illegal TFTP operation");
|
|
||||||
} else if (rc == -6) {
|
|
||||||
puts("unknown TFTP transfer ID");
|
|
||||||
} else if (rc == -7) {
|
|
||||||
puts("no such TFTP user");
|
|
||||||
} else if (rc == -8) {
|
|
||||||
puts("TFTP blocksize negotiation failed");
|
|
||||||
} else if (rc == -9) {
|
|
||||||
puts("file exceeds maximum TFTP transfer size");
|
|
||||||
} else if (rc <= -10 && rc >= -15) {
|
|
||||||
const char *icmp_err_str;
|
|
||||||
switch (rc) {
|
|
||||||
case -ICMP_NET_UNREACHABLE - 10:
|
|
||||||
icmp_err_str = "net unreachable";
|
|
||||||
break;
|
|
||||||
case -ICMP_HOST_UNREACHABLE - 10:
|
|
||||||
icmp_err_str = "host unreachable";
|
|
||||||
break;
|
|
||||||
case -ICMP_PROTOCOL_UNREACHABLE - 10:
|
|
||||||
icmp_err_str = "protocol unreachable";
|
|
||||||
break;
|
|
||||||
case -ICMP_PORT_UNREACHABLE - 10:
|
|
||||||
icmp_err_str = "port unreachable";
|
|
||||||
break;
|
|
||||||
case -ICMP_FRAGMENTATION_NEEDED - 10:
|
|
||||||
icmp_err_str = "fragmentation needed and DF set";
|
|
||||||
break;
|
|
||||||
case -ICMP_SOURCE_ROUTE_FAILED - 10:
|
|
||||||
icmp_err_str = "source route failed";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
icmp_err_str = " UNKNOWN";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
printf("ICMP ERROR \"%s\"\n", icmp_err_str);
|
|
||||||
} else if (rc == -40) {
|
|
||||||
printf("TFTP error occurred after %d bad packets received",
|
|
||||||
tftp_err.bad_tftp_packets);
|
|
||||||
} else if (rc == -41) {
|
|
||||||
printf("TFTP error occurred after missing %d responses",
|
|
||||||
tftp_err.no_packets);
|
|
||||||
} else if (rc == -42) {
|
|
||||||
printf("TFTP error missing block %d, expected block was %d",
|
|
||||||
tftp_err.blocks_missed,
|
|
||||||
tftp_err.blocks_received);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -211,7 +165,6 @@ static int tftp_load(filename_ip_t *fnip, void *buffer, int len)
|
||||||
|
|
||||||
static int net_init(filename_ip_t *fn_ip)
|
static int net_init(filename_ip_t *fn_ip)
|
||||||
{
|
{
|
||||||
uint8_t mac[6];
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
memset(fn_ip, 0, sizeof(filename_ip_t));
|
memset(fn_ip, 0, sizeof(filename_ip_t));
|
||||||
|
@ -231,7 +184,7 @@ static int net_init(filename_ip_t *fn_ip)
|
||||||
|
|
||||||
rc = dhcp(fn_ip, DEFAULT_BOOT_RETRIES);
|
rc = dhcp(fn_ip, DEFAULT_BOOT_RETRIES);
|
||||||
if (rc >= 0) {
|
if (rc >= 0) {
|
||||||
if (ip_version == 4) {
|
if (fn_ip->ip_version == 4) {
|
||||||
set_ipv4_address(fn_ip->own_ip);
|
set_ipv4_address(fn_ip->own_ip);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -239,11 +192,11 @@ static int net_init(filename_ip_t *fn_ip)
|
||||||
return -101;
|
return -101;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ip_version == 4) {
|
if (fn_ip->ip_version == 4) {
|
||||||
printf(" Using IPv4 address: %d.%d.%d.%d\n",
|
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 >> 24) & 0xFF, (fn_ip->own_ip >> 16) & 0xFF,
|
||||||
(fn_ip->own_ip >> 8) & 0xFF, fn_ip->own_ip & 0xFF);
|
(fn_ip->own_ip >> 8) & 0xFF, fn_ip->own_ip & 0xFF);
|
||||||
} else if (ip_version == 6) {
|
} else if (fn_ip->ip_version == 6) {
|
||||||
char ip6_str[40];
|
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);
|
printf(" Using IPv6 address: %s\n", ip6_str);
|
||||||
|
@ -261,17 +214,17 @@ static int net_init(filename_ip_t *fn_ip)
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(" Using TFTP server: ");
|
printf(" Using TFTP server: ");
|
||||||
if (ip_version == 4) {
|
if (fn_ip->ip_version == 4) {
|
||||||
printf("%d.%d.%d.%d\n",
|
printf("%d.%d.%d.%d\n",
|
||||||
(fn_ip->server_ip >> 24) & 0xFF, (fn_ip->server_ip >> 16) & 0xFF,
|
(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 >> 8) & 0xFF, fn_ip->server_ip & 0xFF);
|
||||||
} else if (ip_version == 6) {
|
} else if (fn_ip->ip_version == 6) {
|
||||||
char ip6_str[40];
|
char ip6_str[40];
|
||||||
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);
|
printf("%s\n", ip6_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen((char *)fn_ip->filename) > 0) {
|
if (strlen(fn_ip->filename) > 0) {
|
||||||
printf(" Bootfile name: '%s'\n", fn_ip->filename);
|
printf(" Bootfile name: '%s'\n", fn_ip->filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,11 +233,122 @@ static int net_init(filename_ip_t *fn_ip)
|
||||||
|
|
||||||
static void net_release(filename_ip_t *fn_ip)
|
static void net_release(filename_ip_t *fn_ip)
|
||||||
{
|
{
|
||||||
if (ip_version == 4) {
|
if (fn_ip->ip_version == 4) {
|
||||||
dhcp_send_release(fn_ip->fd);
|
dhcp_send_release(fn_ip->fd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the Universally Unique Identifier of the VM.
|
||||||
|
* @return UUID string, or NULL in case of errors
|
||||||
|
*/
|
||||||
|
static const char *get_uuid(void)
|
||||||
|
{
|
||||||
|
register int r0 asm("0");
|
||||||
|
register int r1 asm("1");
|
||||||
|
uint8_t *mem, *buf, uuid[16];
|
||||||
|
int i, cc, chk = 0;
|
||||||
|
static char uuid_str[37];
|
||||||
|
|
||||||
|
mem = malloc(2 * PAGE_SIZE);
|
||||||
|
if (!mem) {
|
||||||
|
puts("Out of memory ... can not get UUID.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
buf = (uint8_t *)(((uint64_t)mem + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1));
|
||||||
|
memset(buf, 0, PAGE_SIZE);
|
||||||
|
|
||||||
|
/* Get SYSIB 3.2.2 */
|
||||||
|
r0 = (3 << 28) | 2;
|
||||||
|
r1 = 2;
|
||||||
|
asm volatile(" stsi 0(%[addr])\n"
|
||||||
|
" ipm %[cc]\n"
|
||||||
|
" srl %[cc],28\n"
|
||||||
|
: [cc] "=d" (cc)
|
||||||
|
: "d" (r0), "d" (r1), [addr] "a" (buf)
|
||||||
|
: "cc", "memory");
|
||||||
|
if (cc) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
uuid[i] = buf[STSI322_VMDB_UUID_OFFSET + i];
|
||||||
|
chk |= uuid[i];
|
||||||
|
}
|
||||||
|
free(mem);
|
||||||
|
if (!chk) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf(uuid_str, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-"
|
||||||
|
"%02x%02x%02x%02x%02x%02x", uuid[0], uuid[1], uuid[2], uuid[3],
|
||||||
|
uuid[4], uuid[5], uuid[6], uuid[7], uuid[8], uuid[9], uuid[10],
|
||||||
|
uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
|
||||||
|
|
||||||
|
return uuid_str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a kernel with initrd (i.e. with the information that we've got from
|
||||||
|
* a pxelinux.cfg config file)
|
||||||
|
*/
|
||||||
|
static int load_kernel_with_initrd(filename_ip_t *fn_ip,
|
||||||
|
struct pl_cfg_entry *entry)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
printf("Loading pxelinux.cfg entry '%s'\n", entry->label);
|
||||||
|
|
||||||
|
if (!entry->kernel) {
|
||||||
|
printf("Kernel entry is missing!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(fn_ip->filename, entry->kernel, sizeof(fn_ip->filename));
|
||||||
|
rc = tftp_load(fn_ip, KERNEL_ADDR, KERNEL_MAX_SIZE);
|
||||||
|
if (rc < 0) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry->initrd) {
|
||||||
|
uint64_t iaddr = (rc + 0xfff) & ~0xfffUL;
|
||||||
|
|
||||||
|
strncpy(fn_ip->filename, entry->initrd, sizeof(fn_ip->filename));
|
||||||
|
rc = tftp_load(fn_ip, (void *)iaddr, KERNEL_MAX_SIZE - iaddr);
|
||||||
|
if (rc < 0) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
/* Patch location and size: */
|
||||||
|
*(uint64_t *)0x10408 = iaddr;
|
||||||
|
*(uint64_t *)0x10410 = rc;
|
||||||
|
rc += iaddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry->append) {
|
||||||
|
strncpy((char *)0x10480, entry->append, ARCH_COMMAND_LINE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAX_PXELINUX_ENTRIES 16
|
||||||
|
|
||||||
|
static int net_try_pxelinux_cfg(filename_ip_t *fn_ip)
|
||||||
|
{
|
||||||
|
struct pl_cfg_entry entries[MAX_PXELINUX_ENTRIES];
|
||||||
|
int num_ent, def_ent = 0;
|
||||||
|
|
||||||
|
num_ent = pxelinux_load_parse_cfg(fn_ip, mac, get_uuid(),
|
||||||
|
DEFAULT_TFTP_RETRIES,
|
||||||
|
cfgbuf, sizeof(cfgbuf),
|
||||||
|
entries, MAX_PXELINUX_ENTRIES, &def_ent);
|
||||||
|
if (num_ent > 0) {
|
||||||
|
return load_kernel_with_initrd(fn_ip, &entries[def_ent]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load via information from a .INS file (which can be found on CD-ROMs
|
* Load via information from a .INS file (which can be found on CD-ROMs
|
||||||
* for example)
|
* for example)
|
||||||
|
@ -322,7 +386,7 @@ static int handle_ins_cfg(filename_ip_t *fn_ip, char *cfg, int cfgsize)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
*ptr = 0;
|
*ptr = 0;
|
||||||
strncpy((char *)fn_ip->filename, insbuf, sizeof(fn_ip->filename));
|
strncpy(fn_ip->filename, insbuf, sizeof(fn_ip->filename));
|
||||||
destaddr = (char *)atol(ptr + 1);
|
destaddr = (char *)atol(ptr + 1);
|
||||||
rc = tftp_load(fn_ip, destaddr, (long)_start - (long)destaddr);
|
rc = tftp_load(fn_ip, destaddr, (long)_start - (long)destaddr);
|
||||||
if (rc <= 0) {
|
if (rc <= 0) {
|
||||||
|
@ -354,6 +418,25 @@ static int net_try_direct_tftp_load(filename_ip_t *fn_ip)
|
||||||
if (!strncmp("* ", cfgbuf, 2)) {
|
if (!strncmp("* ", cfgbuf, 2)) {
|
||||||
return handle_ins_cfg(fn_ip, cfgbuf, rc);
|
return handle_ins_cfg(fn_ip, cfgbuf, rc);
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* pxelinux.cfg support via bootfile name is just here for developers'
|
||||||
|
* convenience (it eases testing with the built-in DHCP server of QEMU
|
||||||
|
* that does not support RFC 5071). The official way to configure a
|
||||||
|
* pxelinux.cfg file name is to use DHCP options 209 and 210 instead.
|
||||||
|
* So only use the pxelinux.cfg parser here for files that start with
|
||||||
|
* a magic comment string.
|
||||||
|
*/
|
||||||
|
if (!strncasecmp("# pxelinux", cfgbuf, 10)) {
|
||||||
|
struct pl_cfg_entry entries[MAX_PXELINUX_ENTRIES];
|
||||||
|
int num_ent, def_ent = 0;
|
||||||
|
|
||||||
|
num_ent = pxelinux_parse_cfg(cfgbuf, sizeof(cfgbuf), entries,
|
||||||
|
MAX_PXELINUX_ENTRIES, &def_ent);
|
||||||
|
if (num_ent <= 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return load_kernel_with_initrd(fn_ip, &entries[def_ent]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Move kernel to right location */
|
/* Move kernel to right location */
|
||||||
|
@ -455,10 +538,13 @@ void main(void)
|
||||||
panic("Network initialization failed. Halting.\n");
|
panic("Network initialization failed. Halting.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
fnlen = strlen((char *)fn_ip.filename);
|
fnlen = strlen(fn_ip.filename);
|
||||||
if (fnlen > 0 && fn_ip.filename[fnlen - 1] != '/') {
|
if (fnlen > 0 && fn_ip.filename[fnlen - 1] != '/') {
|
||||||
rc = net_try_direct_tftp_load(&fn_ip);
|
rc = net_try_direct_tftp_load(&fn_ip);
|
||||||
}
|
}
|
||||||
|
if (rc <= 0) {
|
||||||
|
rc = net_try_pxelinux_cfg(&fn_ip);
|
||||||
|
}
|
||||||
|
|
||||||
net_release(&fn_ip);
|
net_release(&fn_ip);
|
||||||
|
|
||||||
|
|
|
@ -114,7 +114,7 @@ void sclp_get_loadparm_ascii(char *loadparm)
|
||||||
memset((char *)_sccb, 0, sizeof(ReadInfo));
|
memset((char *)_sccb, 0, sizeof(ReadInfo));
|
||||||
sccb->h.length = sizeof(ReadInfo);
|
sccb->h.length = sizeof(ReadInfo);
|
||||||
if (!sclp_service_call(SCLP_CMDW_READ_SCP_INFO, sccb)) {
|
if (!sclp_service_call(SCLP_CMDW_READ_SCP_INFO, sccb)) {
|
||||||
ebcdic_to_ascii((char *) sccb->loadparm, loadparm, 8);
|
ebcdic_to_ascii((char *) sccb->loadparm, loadparm, LOADPARM_LEN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ typedef struct ReadInfo {
|
||||||
uint16_t rnmax;
|
uint16_t rnmax;
|
||||||
uint8_t rnsize;
|
uint8_t rnsize;
|
||||||
uint8_t reserved[13];
|
uint8_t reserved[13];
|
||||||
uint8_t loadparm[8];
|
uint8_t loadparm[LOADPARM_LEN];
|
||||||
} __attribute__((packed)) ReadInfo;
|
} __attribute__((packed)) ReadInfo;
|
||||||
|
|
||||||
typedef struct SCCB {
|
typedef struct SCCB {
|
||||||
|
|
Binary file not shown.
|
@ -1 +1 @@
|
||||||
Subproject commit fa981320a1e0968d6fc1b8de319723ff8212b337
|
Subproject commit 2317427ce76006723f7ae103a6998ab41dd79c68
|
|
@ -79,6 +79,7 @@ static S390CPUDef s390_cpu_defs[] = {
|
||||||
CPUDEF_INIT(0x2964, 13, 2, 47, 0x08000000U, "z13.2", "IBM z13 GA2"),
|
CPUDEF_INIT(0x2964, 13, 2, 47, 0x08000000U, "z13.2", "IBM z13 GA2"),
|
||||||
CPUDEF_INIT(0x2965, 13, 2, 47, 0x08000000U, "z13s", "IBM z13s GA1"),
|
CPUDEF_INIT(0x2965, 13, 2, 47, 0x08000000U, "z13s", "IBM z13s GA1"),
|
||||||
CPUDEF_INIT(0x3906, 14, 1, 47, 0x08000000U, "z14", "IBM z14 GA1"),
|
CPUDEF_INIT(0x3906, 14, 1, 47, 0x08000000U, "z14", "IBM z14 GA1"),
|
||||||
|
CPUDEF_INIT(0x3907, 14, 1, 47, 0x08000000U, "z14ZR1", "IBM z14 Model ZR1 GA1"),
|
||||||
};
|
};
|
||||||
|
|
||||||
#define QEMU_MAX_CPU_TYPE 0x2827
|
#define QEMU_MAX_CPU_TYPE 0x2827
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue