s390x/kvm/migration/cpumodel: fixes, enhancements and cleanups

- add a network boot rom for s390 (Thomas Huth)
 - migration of storage attributes like the CMMA used/unused state
 - PCI related enhancements - full support for aen, ais and zpci
 - migration support for css with vmstates (Halil Pasic)
 - cpu model enhancements for cpu features
 - guarded storage support
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.14 (GNU/Linux)
 
 iQIcBAABAgAGBQJZaJ3gAAoJEBF7vIC1phx8VSAP/1zKh7ti4Y2dIVb94c1tvECE
 LRNdCdAPhEqL6zybty85aG04sjAmSu50NGfo5t8AGq1U9WBWrCy7/wWSFdK2GI63
 Umc1fR7aBF9FiFayKONhExaREh6gSWVHZF1RyaPIWnnjRIeX8nqgPEnpdZNiVVrG
 5cKHV2SUd5pMDJUiQdZGZgbgG1c+MWJx2BHoduM+K0UnmFjpyLCL4Rq58Q2Q87Nj
 /+yPSVApFFeMsDpem6DNttE6Msa+V+K+EmRhRKqZNOWrdRKH5vvj6Fl/LSxVtd9c
 CEG+aZGjFd693uP9ge0WmjeUJtVHIGt9xKdeU0d7FijZWehjsIqalLoqapzK8ddF
 h6HJuNsmk/SZF7O9JsbHT3Epyr+7Hk0dx78Ku1GNQuUxtFL93eyIJmRdgz7Zo3Lj
 ZTPJvCA13GjPWtgzG5dG3JH1hiAS+Yai18BgdzGbs+qfMCwPdbWkoqg7sARwAJNe
 50fo/ayJvcmHJnSNO6hErFoU38WctGgO8fWp+oVvD8Um1ny1aBFFuJgJIMf47nhu
 x1IdA6UGrNN0yNC4/UgyYBDV1hfvo/phMdoHqle9AcMmPYOD1DBr0genK/bYbICk
 Dio7og9nKgheLRBHz2u5TuYcCsfE/7rtwZX+iXMvoC7VE7Dqs+Q7Zjwwwtwj4x9F
 FwWuf/Bv1s6IkVLlP8Ow
 =2bOV
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/borntraeger/tags/s390x-20170714' into staging

s390x/kvm/migration/cpumodel: fixes, enhancements and cleanups

- add a network boot rom for s390 (Thomas Huth)
- migration of storage attributes like the CMMA used/unused state
- PCI related enhancements - full support for aen, ais and zpci
- migration support for css with vmstates (Halil Pasic)
- cpu model enhancements for cpu features
- guarded storage support

# gpg: Signature made Fri 14 Jul 2017 11:33:04 BST
# gpg:                using RSA key 0x117BBC80B5A61C7C
# gpg: Good signature from "Christian Borntraeger (IBM) <borntraeger@de.ibm.com>"
# Primary key fingerprint: F922 9381 A334 08F9 DBAB  FBCA 117B BC80 B5A6 1C7C

* remotes/borntraeger/tags/s390x-20170714: (40 commits)
  s390x/gdb: add gs registers
  s390x/arch_dump: also dump guarded storage control block
  s390x/kvm: enable guarded storage
  s390x/kvm: Enable KSS facility for nested virtualization
  s390x/cpumodel: add esop/esop2 to z12 model
  s390x/cpumodel: we are always in zarchitecture mode
  s390x/cpumodel: wire up new hardware features
  s390x/flic: migrate ais states
  s390x/cpumodel: add zpci, aen and ais facilities
  s390x: initialize cpu firstly
  pc-bios/s390: rebuild s390-ccw.img
  pc-bios/s390: add s390-netboot.img
  pc-bios/s390-ccw: Link libnet into the netboot image and do the TFTP load
  pc-bios/s390-ccw: Add virtio-net driver code
  pc-bios/s390-ccw: Add core files for the network bootloading program
  roms/SLOF: Update submodule to latest status
  pc-bios/s390-ccw: Add code for virtio feature negotiation
  pc-bios/s390-ccw: Remove unused structs from virtio.h
  pc-bios/s390-ccw: Move byteswap functions to a separate header
  pc-bios/s390-ccw: Add a write() function for stdio
  ...

Conflicts:
	target/s390x/kvm.c

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2017-07-14 14:19:35 +01:00
commit fbc8ea1ed0
61 changed files with 2833 additions and 510 deletions

View file

@ -553,7 +553,7 @@ efi-e1000e.rom efi-vmxnet3.rom \
qemu-icon.bmp qemu_logo_no_text.svg \ qemu-icon.bmp qemu_logo_no_text.svg \
bamboo.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \ bamboo.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \
multiboot.bin linuxboot.bin linuxboot_dma.bin kvmvapic.bin \ multiboot.bin linuxboot.bin linuxboot_dma.bin kvmvapic.bin \
s390-ccw.img \ s390-ccw.img s390-netboot.img \
spapr-rtas.bin slof.bin skiboot.lid \ spapr-rtas.bin slof.bin skiboot.lid \
palcode-clipper \ palcode-clipper \
u-boot.e500 \ u-boot.e500 \

2
configure vendored
View file

@ -6231,7 +6231,7 @@ case "$target_name" in
echo "TARGET_ABI32=y" >> $config_target_mak echo "TARGET_ABI32=y" >> $config_target_mak
;; ;;
s390x) s390x)
gdb_xml_files="s390x-core64.xml s390-acr.xml s390-fpr.xml s390-vx.xml s390-cr.xml s390-virt.xml" gdb_xml_files="s390x-core64.xml s390-acr.xml s390-fpr.xml s390-vx.xml s390-cr.xml s390-virt.xml s390-gs.xml"
;; ;;
tilegx) tilegx)
;; ;;

14
gdb-xml/s390-gs.xml Normal file
View file

@ -0,0 +1,14 @@
<?xml version="1.0"?>
<!-- Copyright 2017 IBM Corp.
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. -->
<!DOCTYPE feature SYSTEM "gdb-target.dtd">
<feature name="org.gnu.gdb.s390.gs">
<reg name="gs_reserved" bitsize="64" type="uint64" group="system"/>
<reg name="gsd" bitsize="64" type="uint64" group="system"/>
<reg name="gssm" bitsize="64" type="uint64" group="system"/>
<reg name="gsepla" bitsize="64" type="data_ptr" group="system"/>
</feature>

View file

@ -775,6 +775,22 @@ STEXI
@item info skeys @var{address} @item info skeys @var{address}
@findex skeys @findex skeys
Display the value of a storage key (s390 only) Display the value of a storage key (s390 only)
ETEXI
#if defined(TARGET_S390X)
{
.name = "cmma",
.args_type = "addr:l,count:l?",
.params = "address [count]",
.help = "Display the values of the CMMA storage attributes for a range of pages",
.cmd = hmp_info_cmma,
},
#endif
STEXI
@item info cmma @var{address}
@findex cmma
Display the values of the CMMA storage attributes for a range of pages (s390 only)
ETEXI ETEXI
{ {

View file

@ -1151,6 +1151,22 @@ STEXI
@item dump-skeys @var{filename} @item dump-skeys @var{filename}
@findex dump-skeys @findex dump-skeys
Save guest storage keys to a file. Save guest storage keys to a file.
ETEXI
#if defined(TARGET_S390X)
{
.name = "migration_mode",
.args_type = "mode:i",
.params = "mode",
.help = "Enables or disables migration mode\n",
.cmd = hmp_migrationmode,
},
#endif
STEXI
@item migration_mode @var{mode}
@findex migration_mode
Enables or disables migration mode.
ETEXI ETEXI
{ {

View file

@ -13,8 +13,11 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "hw/sysbus.h" #include "hw/sysbus.h"
#include "hw/s390x/ioinst.h"
#include "hw/s390x/s390_flic.h" #include "hw/s390x/s390_flic.h"
#include "hw/s390x/css.h"
#include "trace.h" #include "trace.h"
#include "cpu.h"
#include "hw/qdev.h" #include "hw/qdev.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "hw/s390x/s390-virtio-ccw.h" #include "hw/s390x/s390-virtio-ccw.h"
@ -48,7 +51,7 @@ void s390_flic_init(void)
static int qemu_s390_register_io_adapter(S390FLICState *fs, uint32_t id, static int qemu_s390_register_io_adapter(S390FLICState *fs, uint32_t id,
uint8_t isc, bool swap, uint8_t isc, bool swap,
bool is_maskable) bool is_maskable, uint8_t flags)
{ {
/* nothing to do */ /* nothing to do */
return 0; return 0;
@ -79,15 +82,91 @@ static int qemu_s390_clear_io_flic(S390FLICState *fs, uint16_t subchannel_id,
return -ENOSYS; return -ENOSYS;
} }
static int qemu_s390_modify_ais_mode(S390FLICState *fs, uint8_t isc,
uint16_t mode)
{
QEMUS390FLICState *flic = QEMU_S390_FLIC(fs);
switch (mode) {
case SIC_IRQ_MODE_ALL:
flic->simm &= ~AIS_MODE_MASK(isc);
flic->nimm &= ~AIS_MODE_MASK(isc);
break;
case SIC_IRQ_MODE_SINGLE:
flic->simm |= AIS_MODE_MASK(isc);
flic->nimm &= ~AIS_MODE_MASK(isc);
break;
default:
return -EINVAL;
}
return 0;
}
static int qemu_s390_inject_airq(S390FLICState *fs, uint8_t type,
uint8_t isc, uint8_t flags)
{
QEMUS390FLICState *flic = QEMU_S390_FLIC(fs);
bool flag = flags & S390_ADAPTER_SUPPRESSIBLE;
uint32_t io_int_word = (isc << 27) | IO_INT_WORD_AI;
if (flag && (flic->nimm & AIS_MODE_MASK(isc))) {
trace_qemu_s390_airq_suppressed(type, isc);
return 0;
}
s390_io_interrupt(0, 0, 0, io_int_word);
if (flag && (flic->simm & AIS_MODE_MASK(isc))) {
flic->nimm |= AIS_MODE_MASK(isc);
trace_qemu_s390_suppress_airq(isc, "Single-Interruption Mode",
"NO-Interruptions Mode");
}
return 0;
}
static void qemu_s390_flic_reset(DeviceState *dev)
{
QEMUS390FLICState *flic = QEMU_S390_FLIC(dev);
flic->simm = 0;
flic->nimm = 0;
}
bool ais_needed(void *opaque)
{
S390FLICState *s = opaque;
return s->ais_supported;
}
static const VMStateDescription qemu_s390_flic_vmstate = {
.name = "qemu-s390-flic",
.version_id = 1,
.minimum_version_id = 1,
.needed = ais_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT8(simm, QEMUS390FLICState),
VMSTATE_UINT8(nimm, QEMUS390FLICState),
VMSTATE_END_OF_LIST()
}
};
static void qemu_s390_flic_class_init(ObjectClass *oc, void *data) static void qemu_s390_flic_class_init(ObjectClass *oc, void *data)
{ {
DeviceClass *dc = DEVICE_CLASS(oc);
S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc); S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc);
dc->reset = qemu_s390_flic_reset;
dc->vmsd = &qemu_s390_flic_vmstate;
fsc->register_io_adapter = qemu_s390_register_io_adapter; fsc->register_io_adapter = qemu_s390_register_io_adapter;
fsc->io_adapter_map = qemu_s390_io_adapter_map; fsc->io_adapter_map = qemu_s390_io_adapter_map;
fsc->add_adapter_routes = qemu_s390_add_adapter_routes; fsc->add_adapter_routes = qemu_s390_add_adapter_routes;
fsc->release_adapter_routes = qemu_s390_release_adapter_routes; fsc->release_adapter_routes = qemu_s390_release_adapter_routes;
fsc->clear_io_irq = qemu_s390_clear_io_flic; fsc->clear_io_irq = qemu_s390_clear_io_flic;
fsc->modify_ais_mode = qemu_s390_modify_ais_mode;
fsc->inject_airq = qemu_s390_inject_airq;
} }
static Property s390_flic_common_properties[] = { static Property s390_flic_common_properties[] = {
@ -98,12 +177,16 @@ static Property s390_flic_common_properties[] = {
static void s390_flic_common_realize(DeviceState *dev, Error **errp) static void s390_flic_common_realize(DeviceState *dev, Error **errp)
{ {
uint32_t max_batch = S390_FLIC_COMMON(dev)->adapter_routes_max_batch; S390FLICState *fs = S390_FLIC_COMMON(dev);
uint32_t max_batch = fs->adapter_routes_max_batch;
if (max_batch > ADAPTER_ROUTES_MAX_GSI) { if (max_batch > ADAPTER_ROUTES_MAX_GSI) {
error_setg(errp, "flic property adapter_routes_max_batch too big" error_setg(errp, "flic property adapter_routes_max_batch too big"
" (%d > %d)", max_batch, ADAPTER_ROUTES_MAX_GSI); " (%d > %d)", max_batch, ADAPTER_ROUTES_MAX_GSI);
return;
} }
fs->ais_supported = s390_has_feat(S390_FEAT_ADAPTER_INT_SUPPRESSION);
} }
static void s390_flic_class_init(ObjectClass *oc, void *data) static void s390_flic_class_init(ObjectClass *oc, void *data)
@ -138,6 +221,22 @@ static void qemu_s390_flic_register_types(void)
type_init(qemu_s390_flic_register_types) type_init(qemu_s390_flic_register_types)
static bool adapter_info_so_needed(void *opaque)
{
return css_migration_enabled();
}
const VMStateDescription vmstate_adapter_info_so = {
.name = "s390_adapter_info/summary_offset",
.version_id = 1,
.minimum_version_id = 1,
.needed = adapter_info_so_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT32(summary_offset, AdapterInfo),
VMSTATE_END_OF_LIST()
}
};
const VMStateDescription vmstate_adapter_info = { const VMStateDescription vmstate_adapter_info = {
.name = "s390_adapter_info", .name = "s390_adapter_info",
.version_id = 1, .version_id = 1,
@ -151,6 +250,10 @@ const VMStateDescription vmstate_adapter_info = {
*/ */
VMSTATE_END_OF_LIST() VMSTATE_END_OF_LIST()
}, },
.subsections = (const VMStateDescription * []) {
&vmstate_adapter_info_so,
NULL
}
}; };
const VMStateDescription vmstate_adapter_routes = { const VMStateDescription vmstate_adapter_routes = {

View file

@ -20,6 +20,7 @@
#include "sysemu/kvm.h" #include "sysemu/kvm.h"
#include "hw/s390x/s390_flic.h" #include "hw/s390x/s390_flic.h"
#include "hw/s390x/adapter.h" #include "hw/s390x/adapter.h"
#include "hw/s390x/css.h"
#include "trace.h" #include "trace.h"
#define FLIC_SAVE_INITIAL_SIZE getpagesize() #define FLIC_SAVE_INITIAL_SIZE getpagesize()
@ -149,6 +150,43 @@ static int kvm_s390_clear_io_flic(S390FLICState *fs, uint16_t subchannel_id,
return rc ? -errno : 0; return rc ? -errno : 0;
} }
static int kvm_s390_modify_ais_mode(S390FLICState *fs, uint8_t isc,
uint16_t mode)
{
KVMS390FLICState *flic = KVM_S390_FLIC(fs);
struct kvm_s390_ais_req req = {
.isc = isc,
.mode = mode,
};
struct kvm_device_attr attr = {
.group = KVM_DEV_FLIC_AISM,
.addr = (uint64_t)&req,
};
if (!fs->ais_supported) {
return -ENOSYS;
}
return ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr) ? -errno : 0;
}
static int kvm_s390_inject_airq(S390FLICState *fs, uint8_t type,
uint8_t isc, uint8_t flags)
{
KVMS390FLICState *flic = KVM_S390_FLIC(fs);
uint32_t id = css_get_adapter_id(type, isc);
struct kvm_device_attr attr = {
.group = KVM_DEV_FLIC_AIRQ_INJECT,
.attr = id,
};
if (!fs->ais_supported) {
return -ENOSYS;
}
return ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr) ? -errno : 0;
}
/** /**
* __get_all_irqs - store all pending irqs in buffer * __get_all_irqs - store all pending irqs in buffer
* @flic: pointer to flic device state * @flic: pointer to flic device state
@ -186,13 +224,14 @@ static int __get_all_irqs(KVMS390FLICState *flic,
static int kvm_s390_register_io_adapter(S390FLICState *fs, uint32_t id, static int kvm_s390_register_io_adapter(S390FLICState *fs, uint32_t id,
uint8_t isc, bool swap, uint8_t isc, bool swap,
bool is_maskable) bool is_maskable, uint8_t flags)
{ {
struct kvm_s390_io_adapter adapter = { struct kvm_s390_io_adapter adapter = {
.id = id, .id = id,
.isc = isc, .isc = isc,
.maskable = is_maskable, .maskable = is_maskable,
.swap = swap, .swap = swap,
.flags = flags,
}; };
KVMS390FLICState *flic = KVM_S390_FLIC(fs); KVMS390FLICState *flic = KVM_S390_FLIC(fs);
int r; int r;
@ -374,7 +413,84 @@ out:
return r; return r;
} }
typedef struct KVMS390FLICStateMigTmp {
KVMS390FLICState *parent;
uint8_t simm;
uint8_t nimm;
} KVMS390FLICStateMigTmp;
static void kvm_flic_ais_pre_save(void *opaque)
{
KVMS390FLICStateMigTmp *tmp = opaque;
KVMS390FLICState *flic = tmp->parent;
struct kvm_s390_ais_all ais;
struct kvm_device_attr attr = {
.group = KVM_DEV_FLIC_AISM_ALL,
.addr = (uint64_t)&ais,
.attr = sizeof(ais),
};
if (ioctl(flic->fd, KVM_GET_DEVICE_ATTR, &attr)) {
error_report("Failed to retrieve kvm flic ais states");
return;
}
tmp->simm = ais.simm;
tmp->nimm = ais.nimm;
}
static int kvm_flic_ais_post_load(void *opaque, int version_id)
{
KVMS390FLICStateMigTmp *tmp = opaque;
KVMS390FLICState *flic = tmp->parent;
struct kvm_s390_ais_all ais = {
.simm = tmp->simm,
.nimm = tmp->nimm,
};
struct kvm_device_attr attr = {
.group = KVM_DEV_FLIC_AISM_ALL,
.addr = (uint64_t)&ais,
};
/* This can happen when the user mis-configures its guests in an
* incompatible fashion or without a CPU model. For example using
* qemu with -cpu host (which is not migration safe) and do a
* migration from a host that has AIS to a host that has no AIS.
* In that case the target system will reject the migration here.
*/
if (!ais_needed(flic)) {
return -ENOSYS;
}
return ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr) ? -errno : 0;
}
static const VMStateDescription kvm_s390_flic_ais_tmp = {
.name = "s390-flic-ais-tmp",
.pre_save = kvm_flic_ais_pre_save,
.post_load = kvm_flic_ais_post_load,
.fields = (VMStateField[]) {
VMSTATE_UINT8(simm, KVMS390FLICStateMigTmp),
VMSTATE_UINT8(nimm, KVMS390FLICStateMigTmp),
VMSTATE_END_OF_LIST()
}
};
static const VMStateDescription kvm_s390_flic_vmstate_ais = {
.name = "s390-flic/ais",
.version_id = 1,
.minimum_version_id = 1,
.needed = ais_needed,
.fields = (VMStateField[]) {
VMSTATE_WITH_TMP(KVMS390FLICState, KVMS390FLICStateMigTmp,
kvm_s390_flic_ais_tmp),
VMSTATE_END_OF_LIST()
}
};
static const VMStateDescription kvm_s390_flic_vmstate = { static const VMStateDescription kvm_s390_flic_vmstate = {
/* should have been like kvm-s390-flic,
* can't change without breaking compat */
.name = "s390-flic", .name = "s390-flic",
.version_id = FLIC_SAVEVM_VERSION, .version_id = FLIC_SAVEVM_VERSION,
.minimum_version_id = FLIC_SAVEVM_VERSION, .minimum_version_id = FLIC_SAVEVM_VERSION,
@ -389,6 +505,10 @@ static const VMStateDescription kvm_s390_flic_vmstate = {
.flags = VMS_SINGLE, .flags = VMS_SINGLE,
}, },
VMSTATE_END_OF_LIST() VMSTATE_END_OF_LIST()
},
.subsections = (const VMStateDescription * []) {
&kvm_s390_flic_vmstate_ais,
NULL
} }
}; };
@ -436,7 +556,6 @@ static void kvm_s390_flic_realize(DeviceState *dev, Error **errp)
test_attr.group = KVM_DEV_FLIC_CLEAR_IO_IRQ; test_attr.group = KVM_DEV_FLIC_CLEAR_IO_IRQ;
flic_state->clear_io_supported = !ioctl(flic_state->fd, flic_state->clear_io_supported = !ioctl(flic_state->fd,
KVM_HAS_DEVICE_ATTR, test_attr); KVM_HAS_DEVICE_ATTR, test_attr);
return; return;
fail: fail:
error_propagate(errp, errp_local); error_propagate(errp, errp_local);
@ -445,10 +564,12 @@ fail:
static void kvm_s390_flic_reset(DeviceState *dev) static void kvm_s390_flic_reset(DeviceState *dev)
{ {
KVMS390FLICState *flic = KVM_S390_FLIC(dev); KVMS390FLICState *flic = KVM_S390_FLIC(dev);
S390FLICState *fs = S390_FLIC_COMMON(dev);
struct kvm_device_attr attr = { struct kvm_device_attr attr = {
.group = KVM_DEV_FLIC_CLEAR_IRQS, .group = KVM_DEV_FLIC_CLEAR_IRQS,
}; };
int rc = 0; int rc = 0;
uint8_t isc;
if (flic->fd == -1) { if (flic->fd == -1) {
return; return;
@ -456,6 +577,16 @@ static void kvm_s390_flic_reset(DeviceState *dev)
flic_disable_wait_pfault(flic); flic_disable_wait_pfault(flic);
if (fs->ais_supported) {
for (isc = 0; isc <= MAX_ISC; isc++) {
rc = kvm_s390_modify_ais_mode(fs, isc, SIC_IRQ_MODE_ALL);
if (rc) {
error_report("Failed to reset ais mode for isc %d: %s",
isc, strerror(-rc));
}
}
}
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr); rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
if (rc) { if (rc) {
trace_flic_reset_failed(errno); trace_flic_reset_failed(errno);
@ -478,6 +609,8 @@ static void kvm_s390_flic_class_init(ObjectClass *oc, void *data)
fsc->add_adapter_routes = kvm_s390_add_adapter_routes; fsc->add_adapter_routes = kvm_s390_add_adapter_routes;
fsc->release_adapter_routes = kvm_s390_release_adapter_routes; fsc->release_adapter_routes = kvm_s390_release_adapter_routes;
fsc->clear_io_irq = kvm_s390_clear_io_flic; fsc->clear_io_irq = kvm_s390_clear_io_flic;
fsc->modify_ais_mode = kvm_s390_modify_ais_mode;
fsc->inject_airq = kvm_s390_inject_airq;
} }
static const TypeInfo kvm_s390_flic_info = { static const TypeInfo kvm_s390_flic_info = {

View file

@ -73,6 +73,10 @@ flic_create_device(int err) "flic: create device failed %d"
flic_no_device_api(int err) "flic: no Device Contral API support %d" flic_no_device_api(int err) "flic: no Device Contral API support %d"
flic_reset_failed(int err) "flic: reset failed %d" flic_reset_failed(int err) "flic: reset failed %d"
# hw/intc/s390_flic.c
qemu_s390_airq_suppressed(uint8_t type, uint8_t isc) "flic: adapter I/O interrupt suppressed (type %x isc %x)"
qemu_s390_suppress_airq(uint8_t isc, const char *from, const char *to) "flic: for isc %x, suppress airq by modifying ais mode from %s to %s"
# hw/intc/aspeed_vic.c # hw/intc/aspeed_vic.c
aspeed_vic_set_irq(int irq, int level) "Enabling IRQ %d: %d" aspeed_vic_set_irq(int irq, int level) "Enabling IRQ %d: %d"
aspeed_vic_update_fiq(int flags) "Raising FIQ: %d" aspeed_vic_update_fiq(int flags) "Raising FIQ: %d"

View file

@ -13,5 +13,7 @@ obj-y += css-bridge.o
obj-y += ccw-device.o obj-y += ccw-device.o
obj-y += s390-pci-bus.o s390-pci-inst.o obj-y += s390-pci-bus.o s390-pci-inst.o
obj-y += s390-skeys.o obj-y += s390-skeys.o
obj-y += s390-stattrib.o
obj-$(CONFIG_KVM) += s390-skeys-kvm.o obj-$(CONFIG_KVM) += s390-skeys-kvm.o
obj-$(CONFIG_KVM) += s390-stattrib-kvm.o
obj-y += s390-ccw.o obj-y += s390-ccw.o

View file

@ -110,7 +110,7 @@ VirtualCssBus *virtual_css_bus_init(void)
qbus_set_hotplug_handler(bus, dev, &error_abort); qbus_set_hotplug_handler(bus, dev, &error_abort);
css_register_io_adapters(CSS_IO_ADAPTER_VIRTIO, true, false, css_register_io_adapters(CSS_IO_ADAPTER_VIRTIO, true, false,
&error_abort); 0, &error_abort);
return cbus; return cbus;
} }

View file

@ -29,12 +29,45 @@ typedef struct CrwContainer {
QTAILQ_ENTRY(CrwContainer) sibling; QTAILQ_ENTRY(CrwContainer) sibling;
} CrwContainer; } CrwContainer;
static const VMStateDescription vmstate_crw = {
.name = "s390_crw",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT16(flags, CRW),
VMSTATE_UINT16(rsid, CRW),
VMSTATE_END_OF_LIST()
},
};
static const VMStateDescription vmstate_crw_container = {
.name = "s390_crw_container",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_STRUCT(crw, CrwContainer, 0, vmstate_crw, CRW),
VMSTATE_END_OF_LIST()
},
};
typedef struct ChpInfo { typedef struct ChpInfo {
uint8_t in_use; uint8_t in_use;
uint8_t type; uint8_t type;
uint8_t is_virtual; uint8_t is_virtual;
} ChpInfo; } ChpInfo;
static const VMStateDescription vmstate_chp_info = {
.name = "s390_chp_info",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT8(in_use, ChpInfo),
VMSTATE_UINT8(type, ChpInfo),
VMSTATE_UINT8(is_virtual, ChpInfo),
VMSTATE_END_OF_LIST()
}
};
typedef struct SubchSet { typedef struct SubchSet {
SubchDev *sch[MAX_SCHID + 1]; SubchDev *sch[MAX_SCHID + 1];
unsigned long schids_used[BITS_TO_LONGS(MAX_SCHID + 1)]; unsigned long schids_used[BITS_TO_LONGS(MAX_SCHID + 1)];
@ -132,6 +165,36 @@ static const VMStateDescription vmstate_sense_id = {
} }
}; };
static const VMStateDescription vmstate_orb = {
.name = "s390_orb",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32(intparm, ORB),
VMSTATE_UINT16(ctrl0, ORB),
VMSTATE_UINT8(lpm, ORB),
VMSTATE_UINT8(ctrl1, ORB),
VMSTATE_UINT32(cpa, ORB),
VMSTATE_END_OF_LIST()
}
};
static bool vmstate_schdev_orb_needed(void *opaque)
{
return css_migration_enabled();
}
static const VMStateDescription vmstate_schdev_orb = {
.name = "s390_subch_dev/orb",
.version_id = 1,
.minimum_version_id = 1,
.needed = vmstate_schdev_orb_needed,
.fields = (VMStateField[]) {
VMSTATE_STRUCT(orb, SubchDev, 1, vmstate_orb, ORB),
VMSTATE_END_OF_LIST()
}
};
static int subch_dev_post_load(void *opaque, int version_id); static int subch_dev_post_load(void *opaque, int version_id);
static void subch_dev_pre_save(void *opaque); static void subch_dev_pre_save(void *opaque);
@ -160,6 +223,10 @@ const VMStateDescription vmstate_subch_dev = {
VMSTATE_BOOL(ccw_fmt_1, SubchDev), VMSTATE_BOOL(ccw_fmt_1, SubchDev),
VMSTATE_UINT8(ccw_no_data_cnt, SubchDev), VMSTATE_UINT8(ccw_no_data_cnt, SubchDev),
VMSTATE_END_OF_LIST() VMSTATE_END_OF_LIST()
},
.subsections = (const VMStateDescription * []) {
&vmstate_schdev_orb,
NULL
} }
}; };
@ -221,10 +288,24 @@ typedef struct CssImage {
ChpInfo chpids[MAX_CHPID + 1]; ChpInfo chpids[MAX_CHPID + 1];
} CssImage; } CssImage;
static const VMStateDescription vmstate_css_img = {
.name = "s390_css_img",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
/* Subchannel sets have no relevant state. */
VMSTATE_STRUCT_ARRAY(chpids, CssImage, MAX_CHPID + 1, 0,
vmstate_chp_info, ChpInfo),
VMSTATE_END_OF_LIST()
}
};
typedef struct IoAdapter { typedef struct IoAdapter {
uint32_t id; uint32_t id;
uint8_t type; uint8_t type;
uint8_t isc; uint8_t isc;
uint8_t flags;
} IoAdapter; } IoAdapter;
typedef struct ChannelSubSys { typedef struct ChannelSubSys {
@ -238,10 +319,34 @@ typedef struct ChannelSubSys {
uint64_t chnmon_area; uint64_t chnmon_area;
CssImage *css[MAX_CSSID + 1]; CssImage *css[MAX_CSSID + 1];
uint8_t default_cssid; uint8_t default_cssid;
/* don't migrate, see css_register_io_adapters */
IoAdapter *io_adapters[CSS_IO_ADAPTER_TYPE_NUMS][MAX_ISC + 1]; IoAdapter *io_adapters[CSS_IO_ADAPTER_TYPE_NUMS][MAX_ISC + 1];
/* don't migrate, see get_indicator and IndAddrPtrTmp */
QTAILQ_HEAD(, IndAddr) indicator_addresses; QTAILQ_HEAD(, IndAddr) indicator_addresses;
} ChannelSubSys; } ChannelSubSys;
static const VMStateDescription vmstate_css = {
.name = "s390_css",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_QTAILQ_V(pending_crws, ChannelSubSys, 1, vmstate_crw_container,
CrwContainer, sibling),
VMSTATE_BOOL(sei_pending, ChannelSubSys),
VMSTATE_BOOL(do_crw_mchk, ChannelSubSys),
VMSTATE_BOOL(crws_lost, ChannelSubSys),
/* These were kind of migrated by virtio */
VMSTATE_UINT8(max_cssid, ChannelSubSys),
VMSTATE_UINT8(max_ssid, ChannelSubSys),
VMSTATE_BOOL(chnmon_active, ChannelSubSys),
VMSTATE_UINT64(chnmon_area, ChannelSubSys),
VMSTATE_ARRAY_OF_POINTER_TO_STRUCT(css, ChannelSubSys, MAX_CSSID + 1,
0, vmstate_css_img, CssImage),
VMSTATE_UINT8(default_cssid, ChannelSubSys),
VMSTATE_END_OF_LIST()
}
};
static ChannelSubSys channel_subsys = { static ChannelSubSys channel_subsys = {
.pending_crws = QTAILQ_HEAD_INITIALIZER(channel_subsys.pending_crws), .pending_crws = QTAILQ_HEAD_INITIALIZER(channel_subsys.pending_crws),
.do_crw_mchk = true, .do_crw_mchk = true,
@ -281,6 +386,10 @@ static int subch_dev_post_load(void *opaque, int version_id)
css_subch_assign(s->cssid, s->ssid, s->schid, s->devno, s); css_subch_assign(s->cssid, s->ssid, s->schid, s->devno, s);
} }
if (css_migration_enabled()) {
/* No compat voodoo to do ;) */
return 0;
}
/* /*
* Hack alert. If we don't migrate the channel subsystem status * Hack alert. If we don't migrate the channel subsystem status
* we still need to find out if the guest enabled mss/mcss-e. * we still need to find out if the guest enabled mss/mcss-e.
@ -299,6 +408,11 @@ static int subch_dev_post_load(void *opaque, int version_id)
return 0; return 0;
} }
void css_register_vmstate(void)
{
vmstate_register(NULL, 0, &vmstate_css, &channel_subsys);
}
IndAddr *get_indicator(hwaddr ind_addr, int len) IndAddr *get_indicator(hwaddr ind_addr, int len)
{ {
IndAddr *indicator; IndAddr *indicator;
@ -392,10 +506,12 @@ uint32_t css_get_adapter_id(CssIoAdapterType type, uint8_t isc)
* *
* @swap: an indication if byte swap is needed. * @swap: an indication if byte swap is needed.
* @maskable: an indication if the adapter is subject to the mask operation. * @maskable: an indication if the adapter is subject to the mask operation.
* @flags: further characteristics of the adapter.
* e.g. suppressible, an indication if the adapter is subject to AIS.
* @errp: location to store error information. * @errp: location to store error information.
*/ */
void css_register_io_adapters(CssIoAdapterType type, bool swap, bool maskable, void css_register_io_adapters(CssIoAdapterType type, bool swap, bool maskable,
Error **errp) uint8_t flags, Error **errp)
{ {
uint32_t id; uint32_t id;
int ret, isc; int ret, isc;
@ -413,12 +529,13 @@ void css_register_io_adapters(CssIoAdapterType type, bool swap, bool maskable,
for (isc = 0; isc <= MAX_ISC; isc++) { for (isc = 0; isc <= MAX_ISC; isc++) {
id = (type << 3) | isc; id = (type << 3) | isc;
ret = fsc->register_io_adapter(fs, id, isc, swap, maskable); ret = fsc->register_io_adapter(fs, id, isc, swap, maskable, flags);
if (ret == 0) { if (ret == 0) {
adapter = g_new0(IoAdapter, 1); adapter = g_new0(IoAdapter, 1);
adapter->id = id; adapter->id = id;
adapter->isc = isc; adapter->isc = isc;
adapter->type = type; adapter->type = type;
adapter->flags = flags;
channel_subsys.io_adapters[type][isc] = adapter; channel_subsys.io_adapters[type][isc] = adapter;
} else { } else {
error_setg_errno(errp, -ret, "Unexpected error %d when " error_setg_errno(errp, -ret, "Unexpected error %d when "
@ -517,12 +634,52 @@ void css_conditional_io_interrupt(SubchDev *sch)
} }
} }
void css_adapter_interrupt(uint8_t isc) int css_do_sic(CPUS390XState *env, uint8_t isc, uint16_t mode)
{ {
S390FLICState *fs = s390_get_flic();
S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
int r;
if (env->psw.mask & PSW_MASK_PSTATE) {
r = -PGM_PRIVILEGED;
goto out;
}
trace_css_do_sic(mode, isc);
switch (mode) {
case SIC_IRQ_MODE_ALL:
case SIC_IRQ_MODE_SINGLE:
break;
default:
r = -PGM_OPERAND;
goto out;
}
r = fsc->modify_ais_mode(fs, isc, mode) ? -PGM_OPERATION : 0;
out:
return r;
}
void css_adapter_interrupt(CssIoAdapterType type, uint8_t isc)
{
S390FLICState *fs = s390_get_flic();
S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
uint32_t io_int_word = (isc << 27) | IO_INT_WORD_AI; uint32_t io_int_word = (isc << 27) | IO_INT_WORD_AI;
IoAdapter *adapter = channel_subsys.io_adapters[type][isc];
if (!adapter) {
return;
}
trace_css_adapter_interrupt(isc); trace_css_adapter_interrupt(isc);
s390_io_interrupt(0, 0, 0, io_int_word); if (fs->ais_supported) {
if (fsc->inject_airq(fs, type, isc, adapter->flags)) {
error_report("Failed to inject airq with AIS supported");
exit(1);
}
} else {
s390_io_interrupt(0, 0, 0, io_int_word);
}
} }
static void sch_handle_clear_func(SubchDev *sch) static void sch_handle_clear_func(SubchDev *sch)
@ -752,7 +909,7 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr,
return ret; return ret;
} }
static void sch_handle_start_func_virtual(SubchDev *sch, ORB *orb) static void sch_handle_start_func_virtual(SubchDev *sch)
{ {
PMCW *p = &sch->curr_status.pmcw; PMCW *p = &sch->curr_status.pmcw;
@ -766,10 +923,10 @@ static void sch_handle_start_func_virtual(SubchDev *sch, ORB *orb)
if (!(s->ctrl & SCSW_ACTL_SUSP)) { if (!(s->ctrl & SCSW_ACTL_SUSP)) {
/* Start Function triggered via ssch, i.e. we have an ORB */ /* Start Function triggered via ssch, i.e. we have an ORB */
ORB *orb = &sch->orb;
s->cstat = 0; s->cstat = 0;
s->dstat = 0; s->dstat = 0;
/* Look at the orb and try to execute the channel program. */ /* Look at the orb and try to execute the channel program. */
assert(orb != NULL); /* resume does not pass an orb */
p->intparm = orb->intparm; p->intparm = orb->intparm;
if (!(orb->lpm & path)) { if (!(orb->lpm & path)) {
/* Generate a deferred cc 3 condition. */ /* Generate a deferred cc 3 condition. */
@ -783,8 +940,7 @@ static void sch_handle_start_func_virtual(SubchDev *sch, ORB *orb)
sch->ccw_no_data_cnt = 0; sch->ccw_no_data_cnt = 0;
suspend_allowed = !!(orb->ctrl0 & ORB_CTRL0_MASK_SPND); suspend_allowed = !!(orb->ctrl0 & ORB_CTRL0_MASK_SPND);
} else { } else {
/* Start Function resumed via rsch, i.e. we don't have an /* Start Function resumed via rsch */
* ORB */
s->ctrl &= ~(SCSW_ACTL_SUSP | SCSW_ACTL_RESUME_PEND); s->ctrl &= ~(SCSW_ACTL_SUSP | SCSW_ACTL_RESUME_PEND);
/* The channel program had been suspended before. */ /* The channel program had been suspended before. */
suspend_allowed = true; suspend_allowed = true;
@ -854,13 +1010,14 @@ static void sch_handle_start_func_virtual(SubchDev *sch, ORB *orb)
} }
static int sch_handle_start_func_passthrough(SubchDev *sch, ORB *orb) static int sch_handle_start_func_passthrough(SubchDev *sch)
{ {
PMCW *p = &sch->curr_status.pmcw; PMCW *p = &sch->curr_status.pmcw;
SCSW *s = &sch->curr_status.scsw; SCSW *s = &sch->curr_status.scsw;
int ret; int ret;
ORB *orb = &sch->orb;
if (!(s->ctrl & SCSW_ACTL_SUSP)) { if (!(s->ctrl & SCSW_ACTL_SUSP)) {
assert(orb != NULL); assert(orb != NULL);
p->intparm = orb->intparm; p->intparm = orb->intparm;
@ -905,7 +1062,7 @@ static int sch_handle_start_func_passthrough(SubchDev *sch, ORB *orb)
* read/writes) asynchronous later on if we start supporting more than * read/writes) asynchronous later on if we start supporting more than
* our current very simple devices. * our current very simple devices.
*/ */
int do_subchannel_work_virtual(SubchDev *sch, ORB *orb) int do_subchannel_work_virtual(SubchDev *sch)
{ {
SCSW *s = &sch->curr_status.scsw; SCSW *s = &sch->curr_status.scsw;
@ -916,7 +1073,7 @@ int do_subchannel_work_virtual(SubchDev *sch, ORB *orb)
sch_handle_halt_func(sch); sch_handle_halt_func(sch);
} else if (s->ctrl & SCSW_FCTL_START_FUNC) { } else if (s->ctrl & SCSW_FCTL_START_FUNC) {
/* Triggered by both ssch and rsch. */ /* Triggered by both ssch and rsch. */
sch_handle_start_func_virtual(sch, orb); sch_handle_start_func_virtual(sch);
} else { } else {
/* Cannot happen. */ /* Cannot happen. */
return 0; return 0;
@ -925,7 +1082,7 @@ int do_subchannel_work_virtual(SubchDev *sch, ORB *orb)
return 0; return 0;
} }
int do_subchannel_work_passthrough(SubchDev *sch, ORB *orb) int do_subchannel_work_passthrough(SubchDev *sch)
{ {
int ret; int ret;
SCSW *s = &sch->curr_status.scsw; SCSW *s = &sch->curr_status.scsw;
@ -939,7 +1096,7 @@ int do_subchannel_work_passthrough(SubchDev *sch, ORB *orb)
sch_handle_halt_func(sch); sch_handle_halt_func(sch);
ret = 0; ret = 0;
} else if (s->ctrl & SCSW_FCTL_START_FUNC) { } else if (s->ctrl & SCSW_FCTL_START_FUNC) {
ret = sch_handle_start_func_passthrough(sch, orb); ret = sch_handle_start_func_passthrough(sch);
} else { } else {
/* Cannot happen. */ /* Cannot happen. */
return -ENODEV; return -ENODEV;
@ -948,10 +1105,10 @@ int do_subchannel_work_passthrough(SubchDev *sch, ORB *orb)
return ret; return ret;
} }
static int do_subchannel_work(SubchDev *sch, ORB *orb) static int do_subchannel_work(SubchDev *sch)
{ {
if (sch->do_subchannel_work) { if (sch->do_subchannel_work) {
return sch->do_subchannel_work(sch, orb); return sch->do_subchannel_work(sch);
} else { } else {
return -EINVAL; return -EINVAL;
} }
@ -1158,7 +1315,7 @@ int css_do_csch(SubchDev *sch)
s->ctrl &= ~(SCSW_CTRL_MASK_FCTL | SCSW_CTRL_MASK_ACTL); s->ctrl &= ~(SCSW_CTRL_MASK_FCTL | SCSW_CTRL_MASK_ACTL);
s->ctrl |= SCSW_FCTL_CLEAR_FUNC | SCSW_ACTL_CLEAR_PEND; s->ctrl |= SCSW_FCTL_CLEAR_FUNC | SCSW_ACTL_CLEAR_PEND;
do_subchannel_work(sch, NULL); do_subchannel_work(sch);
ret = 0; ret = 0;
out: out:
@ -1199,7 +1356,7 @@ int css_do_hsch(SubchDev *sch)
} }
s->ctrl |= SCSW_ACTL_HALT_PEND; s->ctrl |= SCSW_ACTL_HALT_PEND;
do_subchannel_work(sch, NULL); do_subchannel_work(sch);
ret = 0; ret = 0;
out: out:
@ -1268,12 +1425,13 @@ int css_do_ssch(SubchDev *sch, ORB *orb)
if (channel_subsys.chnmon_active) { if (channel_subsys.chnmon_active) {
css_update_chnmon(sch); css_update_chnmon(sch);
} }
sch->orb = *orb;
sch->channel_prog = orb->cpa; sch->channel_prog = orb->cpa;
/* Trigger the start function. */ /* Trigger the start function. */
s->ctrl |= (SCSW_FCTL_START_FUNC | SCSW_ACTL_START_PEND); s->ctrl |= (SCSW_FCTL_START_FUNC | SCSW_ACTL_START_PEND);
s->flags &= ~SCSW_FLAGS_MASK_PNO; s->flags &= ~SCSW_FLAGS_MASK_PNO;
ret = do_subchannel_work(sch, orb); ret = do_subchannel_work(sch);
out: out:
return ret; return ret;
@ -1552,7 +1710,7 @@ int css_do_rsch(SubchDev *sch)
} }
s->ctrl |= SCSW_ACTL_RESUME_PEND; s->ctrl |= SCSW_ACTL_RESUME_PEND;
do_subchannel_work(sch, NULL); do_subchannel_work(sch);
ret = 0; ret = 0;
out: out:

View file

@ -500,7 +500,7 @@ static void s390_msi_ctrl_write(void *opaque, hwaddr addr, uint64_t data,
0x80 >> ((ind_bit + vec) % 8)); 0x80 >> ((ind_bit + vec) % 8));
if (!set_ind_atomic(pbdev->routes.adapter.summary_addr + sum_bit / 8, if (!set_ind_atomic(pbdev->routes.adapter.summary_addr + sum_bit / 8,
0x80 >> (sum_bit % 8))) { 0x80 >> (sum_bit % 8))) {
css_adapter_interrupt(pbdev->isc); css_adapter_interrupt(CSS_IO_ADAPTER_PCI, pbdev->isc);
} }
} }
@ -579,7 +579,8 @@ static int s390_pcihost_init(SysBusDevice *dev)
QTAILQ_INIT(&s->pending_sei); QTAILQ_INIT(&s->pending_sei);
QTAILQ_INIT(&s->zpci_devs); QTAILQ_INIT(&s->zpci_devs);
css_register_io_adapters(CSS_IO_ADAPTER_PCI, true, false, &error_abort); css_register_io_adapters(CSS_IO_ADAPTER_PCI, true, false,
S390_ADAPTER_SUPPRESSIBLE, &error_abort);
return 0; return 0;
} }

View file

@ -0,0 +1,190 @@
/*
* s390 storage attributes device -- KVM object
*
* Copyright 2016 IBM Corp.
* Author(s): Claudio Imbrenda <imbrenda@linux.vnet.ibm.com>
*
* 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 "qemu/osdep.h"
#include "hw/boards.h"
#include "migration/qemu-file.h"
#include "hw/s390x/storage-attributes.h"
#include "qemu/error-report.h"
#include "sysemu/kvm.h"
#include "exec/ram_addr.h"
#include "cpu.h"
Object *kvm_s390_stattrib_create(void)
{
if (kvm_enabled() &&
kvm_check_extension(kvm_state, KVM_CAP_S390_CMMA_MIGRATION)) {
return object_new(TYPE_KVM_S390_STATTRIB);
}
return NULL;
}
static void kvm_s390_stattrib_instance_init(Object *obj)
{
KVMS390StAttribState *sas = KVM_S390_STATTRIB(obj);
sas->still_dirty = 0;
}
static int kvm_s390_stattrib_read_helper(S390StAttribState *sa,
uint64_t *start_gfn,
uint32_t count,
uint8_t *values,
uint32_t flags)
{
KVMS390StAttribState *sas = KVM_S390_STATTRIB(sa);
int r;
struct kvm_s390_cmma_log clog = {
.values = (uint64_t)values,
.start_gfn = *start_gfn,
.count = count,
.flags = flags,
};
r = kvm_vm_ioctl(kvm_state, KVM_S390_GET_CMMA_BITS, &clog);
if (r < 0) {
error_report("KVM_S390_GET_CMMA_BITS failed: %s", strerror(-r));
return r;
}
*start_gfn = clog.start_gfn;
sas->still_dirty = clog.remaining;
return clog.count;
}
static int kvm_s390_stattrib_get_stattr(S390StAttribState *sa,
uint64_t *start_gfn,
uint32_t count,
uint8_t *values)
{
return kvm_s390_stattrib_read_helper(sa, start_gfn, count, values, 0);
}
static int kvm_s390_stattrib_peek_stattr(S390StAttribState *sa,
uint64_t start_gfn,
uint32_t count,
uint8_t *values)
{
return kvm_s390_stattrib_read_helper(sa, &start_gfn, count, values,
KVM_S390_CMMA_PEEK);
}
static int kvm_s390_stattrib_set_stattr(S390StAttribState *sa,
uint64_t start_gfn,
uint32_t count,
uint8_t *values)
{
KVMS390StAttribState *sas = KVM_S390_STATTRIB(sa);
MachineState *machine = MACHINE(qdev_get_machine());
unsigned long max = machine->maxram_size / TARGET_PAGE_SIZE;
if (start_gfn + count > max) {
error_report("Out of memory bounds when setting storage attributes");
return -1;
}
if (!sas->incoming_buffer) {
sas->incoming_buffer = g_malloc0(max);
}
memcpy(sas->incoming_buffer + start_gfn, values, count);
return 0;
}
static void kvm_s390_stattrib_synchronize(S390StAttribState *sa)
{
KVMS390StAttribState *sas = KVM_S390_STATTRIB(sa);
MachineState *machine = MACHINE(qdev_get_machine());
unsigned long max = machine->maxram_size / TARGET_PAGE_SIZE;
unsigned long cx, len = 1 << 19;
int r;
struct kvm_s390_cmma_log clog = {
.flags = 0,
.mask = ~0ULL,
};
if (sas->incoming_buffer) {
for (cx = 0; cx + len <= max; cx += len) {
clog.start_gfn = cx;
clog.count = len;
clog.values = (uint64_t)(sas->incoming_buffer + cx * len);
r = kvm_vm_ioctl(kvm_state, KVM_S390_SET_CMMA_BITS, &clog);
if (r) {
error_report("KVM_S390_SET_CMMA_BITS failed: %s", strerror(-r));
return;
}
}
if (cx < max) {
clog.start_gfn = cx;
clog.count = max - cx;
clog.values = (uint64_t)(sas->incoming_buffer + cx * len);
r = kvm_vm_ioctl(kvm_state, KVM_S390_SET_CMMA_BITS, &clog);
if (r) {
error_report("KVM_S390_SET_CMMA_BITS failed: %s", strerror(-r));
}
}
g_free(sas->incoming_buffer);
sas->incoming_buffer = NULL;
}
}
static int kvm_s390_stattrib_set_migrationmode(S390StAttribState *sa, bool val)
{
struct kvm_device_attr attr = {
.group = KVM_S390_VM_MIGRATION,
.attr = val,
.addr = 0,
};
return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
}
static long long kvm_s390_stattrib_get_dirtycount(S390StAttribState *sa)
{
KVMS390StAttribState *sas = KVM_S390_STATTRIB(sa);
uint8_t val[8];
kvm_s390_stattrib_peek_stattr(sa, 0, 1, val);
return sas->still_dirty;
}
static int kvm_s390_stattrib_get_active(S390StAttribState *sa)
{
return kvm_s390_cmma_active() && sa->migration_enabled;
}
static void kvm_s390_stattrib_class_init(ObjectClass *oc, void *data)
{
S390StAttribClass *sac = S390_STATTRIB_CLASS(oc);
sac->get_stattr = kvm_s390_stattrib_get_stattr;
sac->peek_stattr = kvm_s390_stattrib_peek_stattr;
sac->set_stattr = kvm_s390_stattrib_set_stattr;
sac->set_migrationmode = kvm_s390_stattrib_set_migrationmode;
sac->get_dirtycount = kvm_s390_stattrib_get_dirtycount;
sac->synchronize = kvm_s390_stattrib_synchronize;
sac->get_active = kvm_s390_stattrib_get_active;
}
static const TypeInfo kvm_s390_stattrib_info = {
.name = TYPE_KVM_S390_STATTRIB,
.parent = TYPE_S390_STATTRIB,
.instance_init = kvm_s390_stattrib_instance_init,
.instance_size = sizeof(KVMS390StAttribState),
.class_init = kvm_s390_stattrib_class_init,
.class_size = sizeof(S390StAttribClass),
};
static void kvm_s390_stattrib_register_types(void)
{
type_register_static(&kvm_s390_stattrib_info);
}
type_init(kvm_s390_stattrib_register_types)

404
hw/s390x/s390-stattrib.c Normal file
View file

@ -0,0 +1,404 @@
/*
* s390 storage attributes device
*
* Copyright 2016 IBM Corp.
* Author(s): Claudio Imbrenda <imbrenda@linux.vnet.ibm.com>
*
* 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 "qemu/osdep.h"
#include "hw/boards.h"
#include "qmp-commands.h"
#include "migration/qemu-file.h"
#include "migration/register.h"
#include "hw/s390x/storage-attributes.h"
#include "qemu/error-report.h"
#include "sysemu/kvm.h"
#include "exec/ram_addr.h"
#include "qapi/error.h"
#define CMMA_BLOCK_SIZE (1 << 10)
#define STATTR_FLAG_EOS 0x01ULL
#define STATTR_FLAG_MORE 0x02ULL
#define STATTR_FLAG_ERROR 0x04ULL
#define STATTR_FLAG_DONE 0x08ULL
static S390StAttribState *s390_get_stattrib_device(void)
{
S390StAttribState *sas;
sas = S390_STATTRIB(object_resolve_path_type("", TYPE_S390_STATTRIB, NULL));
assert(sas);
return sas;
}
void s390_stattrib_init(void)
{
Object *obj;
obj = kvm_s390_stattrib_create();
if (!obj) {
obj = object_new(TYPE_QEMU_S390_STATTRIB);
}
object_property_add_child(qdev_get_machine(), TYPE_S390_STATTRIB,
obj, NULL);
object_unref(obj);
qdev_init_nofail(DEVICE(obj));
}
/* Console commands: */
void hmp_migrationmode(Monitor *mon, const QDict *qdict)
{
S390StAttribState *sas = s390_get_stattrib_device();
S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
uint64_t what = qdict_get_int(qdict, "mode");
int r;
r = sac->set_migrationmode(sas, what);
if (r < 0) {
monitor_printf(mon, "Error: %s", strerror(-r));
}
}
void hmp_info_cmma(Monitor *mon, const QDict *qdict)
{
S390StAttribState *sas = s390_get_stattrib_device();
S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
uint64_t addr = qdict_get_int(qdict, "addr");
uint64_t buflen = qdict_get_try_int(qdict, "count", 8);
uint8_t *vals;
int cx, len;
vals = g_try_malloc(buflen);
if (!vals) {
monitor_printf(mon, "Error: %s\n", strerror(errno));
return;
}
len = sac->peek_stattr(sas, addr / TARGET_PAGE_SIZE, buflen, vals);
if (len < 0) {
monitor_printf(mon, "Error: %s", strerror(-len));
goto out;
}
monitor_printf(mon, " CMMA attributes, "
"pages %" PRIu64 "+%d (0x%" PRIx64 "):\n",
addr / TARGET_PAGE_SIZE, len, addr & ~TARGET_PAGE_MASK);
for (cx = 0; cx < len; cx++) {
if (cx % 8 == 7) {
monitor_printf(mon, "%02x\n", vals[cx]);
} else {
monitor_printf(mon, "%02x", vals[cx]);
}
}
monitor_printf(mon, "\n");
out:
g_free(vals);
}
/* Migration support: */
static int cmma_load(QEMUFile *f, void *opaque, int version_id)
{
S390StAttribState *sas = S390_STATTRIB(opaque);
S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
uint64_t count, cur_gfn;
int flags, ret = 0;
ram_addr_t addr;
uint8_t *buf;
while (!ret) {
addr = qemu_get_be64(f);
flags = addr & ~TARGET_PAGE_MASK;
addr &= TARGET_PAGE_MASK;
switch (flags) {
case STATTR_FLAG_MORE: {
cur_gfn = addr / TARGET_PAGE_SIZE;
count = qemu_get_be64(f);
buf = g_try_malloc(count);
if (!buf) {
error_report("cmma_load could not allocate memory");
ret = -ENOMEM;
break;
}
qemu_get_buffer(f, buf, count);
ret = sac->set_stattr(sas, cur_gfn, count, buf);
if (ret < 0) {
error_report("Error %d while setting storage attributes", ret);
}
g_free(buf);
break;
}
case STATTR_FLAG_ERROR: {
error_report("Storage attributes data is incomplete");
ret = -EINVAL;
break;
}
case STATTR_FLAG_DONE:
/* This is after the last pre-copied value has been sent, nothing
* more will be sent after this. Pre-copy has finished, and we
* are done flushing all the remaining values. Now the target
* system is about to take over. We synchronize the buffer to
* apply the actual correct values where needed.
*/
sac->synchronize(sas);
break;
case STATTR_FLAG_EOS:
/* Normal exit */
return 0;
default:
error_report("Unexpected storage attribute flag data: %#x", flags);
ret = -EINVAL;
}
}
return ret;
}
static int cmma_save_setup(QEMUFile *f, void *opaque)
{
S390StAttribState *sas = S390_STATTRIB(opaque);
S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
int res;
/*
* Signal that we want to start a migration, thus needing PGSTE dirty
* tracking.
*/
res = sac->set_migrationmode(sas, 1);
if (res) {
return res;
}
qemu_put_be64(f, STATTR_FLAG_EOS);
return 0;
}
static void cmma_save_pending(QEMUFile *f, void *opaque, uint64_t max_size,
uint64_t *non_postcopiable_pending,
uint64_t *postcopiable_pending)
{
S390StAttribState *sas = S390_STATTRIB(opaque);
S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
long long res = sac->get_dirtycount(sas);
if (res >= 0) {
*non_postcopiable_pending += res;
}
}
static int cmma_save(QEMUFile *f, void *opaque, int final)
{
S390StAttribState *sas = S390_STATTRIB(opaque);
S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
uint8_t *buf;
int r, cx, reallen = 0, ret = 0;
uint32_t buflen = 1 << 19; /* 512kB cover 2GB of guest memory */
uint64_t start_gfn = sas->migration_cur_gfn;
buf = g_try_malloc(buflen);
if (!buf) {
error_report("Could not allocate memory to save storage attributes");
return -ENOMEM;
}
while (final ? 1 : qemu_file_rate_limit(f) == 0) {
reallen = sac->get_stattr(sas, &start_gfn, buflen, buf);
if (reallen < 0) {
g_free(buf);
return reallen;
}
ret = 1;
if (!reallen) {
break;
}
qemu_put_be64(f, (start_gfn << TARGET_PAGE_BITS) | STATTR_FLAG_MORE);
qemu_put_be64(f, reallen);
for (cx = 0; cx < reallen; cx++) {
qemu_put_byte(f, buf[cx]);
}
if (!sac->get_dirtycount(sas)) {
break;
}
}
sas->migration_cur_gfn = start_gfn + reallen;
g_free(buf);
if (final) {
qemu_put_be64(f, STATTR_FLAG_DONE);
}
qemu_put_be64(f, STATTR_FLAG_EOS);
r = qemu_file_get_error(f);
if (r < 0) {
return r;
}
return ret;
}
static int cmma_save_iterate(QEMUFile *f, void *opaque)
{
return cmma_save(f, opaque, 0);
}
static int cmma_save_complete(QEMUFile *f, void *opaque)
{
return cmma_save(f, opaque, 1);
}
static void cmma_save_cleanup(void *opaque)
{
S390StAttribState *sas = S390_STATTRIB(opaque);
S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
sac->set_migrationmode(sas, 0);
}
static bool cmma_active(void *opaque)
{
S390StAttribState *sas = S390_STATTRIB(opaque);
S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
return sac->get_active(sas);
}
/* QEMU object: */
static void qemu_s390_stattrib_instance_init(Object *obj)
{
}
static int qemu_s390_peek_stattr_stub(S390StAttribState *sa, uint64_t start_gfn,
uint32_t count, uint8_t *values)
{
return 0;
}
static void qemu_s390_synchronize_stub(S390StAttribState *sa)
{
}
static int qemu_s390_get_stattr_stub(S390StAttribState *sa, uint64_t *start_gfn,
uint32_t count, uint8_t *values)
{
return 0;
}
static long long qemu_s390_get_dirtycount_stub(S390StAttribState *sa)
{
return 0;
}
static int qemu_s390_set_migrationmode_stub(S390StAttribState *sa, bool value)
{
return 0;
}
static int qemu_s390_get_active(S390StAttribState *sa)
{
return sa->migration_enabled;
}
static void qemu_s390_stattrib_class_init(ObjectClass *oc, void *data)
{
S390StAttribClass *sa_cl = S390_STATTRIB_CLASS(oc);
sa_cl->synchronize = qemu_s390_synchronize_stub;
sa_cl->get_stattr = qemu_s390_get_stattr_stub;
sa_cl->set_stattr = qemu_s390_peek_stattr_stub;
sa_cl->peek_stattr = qemu_s390_peek_stattr_stub;
sa_cl->set_migrationmode = qemu_s390_set_migrationmode_stub;
sa_cl->get_dirtycount = qemu_s390_get_dirtycount_stub;
sa_cl->get_active = qemu_s390_get_active;
}
static const TypeInfo qemu_s390_stattrib_info = {
.name = TYPE_QEMU_S390_STATTRIB,
.parent = TYPE_S390_STATTRIB,
.instance_init = qemu_s390_stattrib_instance_init,
.instance_size = sizeof(QEMUS390StAttribState),
.class_init = qemu_s390_stattrib_class_init,
.class_size = sizeof(S390StAttribClass),
};
/* Generic abstract object: */
static void s390_stattrib_realize(DeviceState *dev, Error **errp)
{
bool ambiguous = false;
object_resolve_path_type("", TYPE_S390_STATTRIB, &ambiguous);
if (ambiguous) {
error_setg(errp, "storage_attributes device already exists");
}
}
static void s390_stattrib_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->hotpluggable = false;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
dc->realize = s390_stattrib_realize;
}
static inline bool s390_stattrib_get_migration_enabled(Object *obj, Error **e)
{
S390StAttribState *s = S390_STATTRIB(obj);
return s->migration_enabled;
}
static inline void s390_stattrib_set_migration_enabled(Object *obj, bool value,
Error **errp)
{
S390StAttribState *s = S390_STATTRIB(obj);
s->migration_enabled = value;
}
static void s390_stattrib_instance_init(Object *obj)
{
S390StAttribState *sas = S390_STATTRIB(obj);
SaveVMHandlers *ops;
/* ops will always be freed by qemu when unregistering */
ops = g_new0(SaveVMHandlers, 1);
ops->save_setup = cmma_save_setup;
ops->save_live_iterate = cmma_save_iterate;
ops->save_live_complete_precopy = cmma_save_complete;
ops->save_live_pending = cmma_save_pending;
ops->save_cleanup = cmma_save_cleanup;
ops->load_state = cmma_load;
ops->is_active = cmma_active;
register_savevm_live(NULL, TYPE_S390_STATTRIB, 0, 0, ops, sas);
object_property_add_bool(obj, "migration-enabled",
s390_stattrib_get_migration_enabled,
s390_stattrib_set_migration_enabled, NULL);
object_property_set_bool(obj, true, "migration-enabled", NULL);
sas->migration_cur_gfn = 0;
}
static const TypeInfo s390_stattrib_info = {
.name = TYPE_S390_STATTRIB,
.parent = TYPE_DEVICE,
.instance_init = s390_stattrib_instance_init,
.instance_size = sizeof(S390StAttribState),
.class_init = s390_stattrib_class_init,
.class_size = sizeof(S390StAttribClass),
.abstract = true,
};
static void s390_stattrib_register_types(void)
{
type_register_static(&s390_stattrib_info);
type_register_static(&qemu_s390_stattrib_info);
}
type_init(s390_stattrib_register_types)

View file

@ -24,11 +24,13 @@
#include "qemu/config-file.h" #include "qemu/config-file.h"
#include "s390-pci-bus.h" #include "s390-pci-bus.h"
#include "hw/s390x/storage-keys.h" #include "hw/s390x/storage-keys.h"
#include "hw/s390x/storage-attributes.h"
#include "hw/compat.h" #include "hw/compat.h"
#include "ipl.h" #include "ipl.h"
#include "hw/s390x/s390-virtio-ccw.h" #include "hw/s390x/s390-virtio-ccw.h"
#include "hw/s390x/css-bridge.h" #include "hw/s390x/css-bridge.h"
#include "migration/register.h" #include "migration/register.h"
#include "cpu_models.h"
static const char *const reset_dev_types[] = { static const char *const reset_dev_types[] = {
TYPE_VIRTUAL_CSS_BRIDGE, TYPE_VIRTUAL_CSS_BRIDGE,
@ -103,6 +105,8 @@ void s390_memory_init(ram_addr_t mem_size)
/* Initialize storage key device */ /* Initialize storage key device */
s390_skeys_init(); s390_skeys_init();
/* Initialize storage attributes device */
s390_stattrib_init();
} }
static SaveVMHandlers savevm_gtod = { static SaveVMHandlers savevm_gtod = {
@ -119,6 +123,9 @@ static void ccw_init(MachineState *machine)
s390_sclp_init(); s390_sclp_init();
s390_memory_init(machine->ram_size); s390_memory_init(machine->ram_size);
/* init CPUs */
s390_init_cpus(machine);
s390_flic_init(); s390_flic_init();
/* get a BUS */ /* get a BUS */
@ -135,9 +142,6 @@ static void ccw_init(MachineState *machine)
/* register hypercalls */ /* register hypercalls */
virtio_ccw_register_hcalls(); virtio_ccw_register_hcalls();
/* init CPUs */
s390_init_cpus(machine);
if (kvm_enabled()) { if (kvm_enabled()) {
kvm_s390_enable_css_support(s390_cpu_addr2state(0)); kvm_s390_enable_css_support(s390_cpu_addr2state(0));
} }
@ -206,6 +210,8 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data)
s390mc->ri_allowed = true; s390mc->ri_allowed = true;
s390mc->cpu_model_allowed = true; s390mc->cpu_model_allowed = true;
s390mc->css_migration_enabled = true;
s390mc->gs_allowed = true;
mc->init = ccw_init; mc->init = ccw_init;
mc->reset = s390_machine_reset; mc->reset = s390_machine_reset;
mc->hot_add_cpu = s390_hot_add_cpu; mc->hot_add_cpu = s390_hot_add_cpu;
@ -252,7 +258,38 @@ static inline void machine_set_dea_key_wrap(Object *obj, bool value,
ms->dea_key_wrap = value; ms->dea_key_wrap = value;
} }
static S390CcwMachineClass *current_mc;
static S390CcwMachineClass *get_machine_class(void)
{
if (unlikely(!current_mc)) {
/*
* No s390 ccw machine was instantiated, we are likely to
* be called for the 'none' machine. The properties will
* have their after-initialization values.
*/
current_mc = S390_MACHINE_CLASS(
object_class_by_name(TYPE_S390_CCW_MACHINE));
}
return current_mc;
}
bool ri_allowed(void) bool ri_allowed(void)
{
if (!kvm_enabled()) {
return false;
}
/* for "none" machine this results in true */
return get_machine_class()->ri_allowed;
}
bool cpu_model_allowed(void)
{
/* for "none" machine this results in true */
return get_machine_class()->cpu_model_allowed;
}
bool gs_allowed(void)
{ {
if (kvm_enabled()) { if (kvm_enabled()) {
MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
@ -260,28 +297,12 @@ bool ri_allowed(void)
TYPE_S390_CCW_MACHINE)) { TYPE_S390_CCW_MACHINE)) {
S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc); S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
return s390mc->ri_allowed; return s390mc->gs_allowed;
} }
/* /* Make sure the "none" machine can have gs */
* Make sure the "none" machine can have ri, otherwise it won't * be
* unlocked in KVM and therefore the host CPU model might be wrong.
*/
return true; return true;
} }
return 0; return false;
}
bool cpu_model_allowed(void)
{
MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
if (object_class_dynamic_cast(OBJECT_CLASS(mc),
TYPE_S390_CCW_MACHINE)) {
S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
return s390mc->cpu_model_allowed;
}
/* allow CPU model qmp queries with the "none" machine */
return true;
} }
static char *machine_get_loadparm(Object *obj, Error **errp) static char *machine_get_loadparm(Object *obj, Error **errp)
@ -376,6 +397,11 @@ static const TypeInfo ccw_machine_info = {
}, },
}; };
bool css_migration_enabled(void)
{
return get_machine_class()->css_migration_enabled;
}
#define DEFINE_CCW_MACHINE(suffix, verstr, latest) \ #define DEFINE_CCW_MACHINE(suffix, verstr, latest) \
static void ccw_machine_##suffix##_class_init(ObjectClass *oc, \ static void ccw_machine_##suffix##_class_init(ObjectClass *oc, \
void *data) \ void *data) \
@ -391,6 +417,7 @@ static const TypeInfo ccw_machine_info = {
static void ccw_machine_##suffix##_instance_init(Object *obj) \ static void ccw_machine_##suffix##_instance_init(Object *obj) \
{ \ { \
MachineState *machine = MACHINE(obj); \ MachineState *machine = MACHINE(obj); \
current_mc = S390_MACHINE_CLASS(MACHINE_GET_CLASS(machine)); \
ccw_machine_##suffix##_instance_options(machine); \ ccw_machine_##suffix##_instance_options(machine); \
} \ } \
static const TypeInfo ccw_machine_##suffix##_info = { \ static const TypeInfo ccw_machine_##suffix##_info = { \
@ -406,7 +433,12 @@ static const TypeInfo ccw_machine_info = {
type_init(ccw_machine_register_##suffix) type_init(ccw_machine_register_##suffix)
#define CCW_COMPAT_2_9 \ #define CCW_COMPAT_2_9 \
HW_COMPAT_2_9 HW_COMPAT_2_9 \
{\
.driver = TYPE_S390_STATTRIB,\
.property = "migration-enabled",\
.value = "off",\
},
#define CCW_COMPAT_2_8 \ #define CCW_COMPAT_2_8 \
HW_COMPAT_2_8 \ HW_COMPAT_2_8 \
@ -476,6 +508,9 @@ static const TypeInfo ccw_machine_info = {
static void ccw_machine_2_10_instance_options(MachineState *machine) static void ccw_machine_2_10_instance_options(MachineState *machine)
{ {
if (css_migration_enabled()) {
css_register_vmstate();
}
} }
static void ccw_machine_2_10_class_options(MachineClass *mc) static void ccw_machine_2_10_class_options(MachineClass *mc)
@ -486,12 +521,21 @@ DEFINE_CCW_MACHINE(2_10, "2.10", true);
static void ccw_machine_2_9_instance_options(MachineState *machine) static void ccw_machine_2_9_instance_options(MachineState *machine)
{ {
ccw_machine_2_10_instance_options(machine); ccw_machine_2_10_instance_options(machine);
s390_cpudef_featoff_greater(12, 1, S390_FEAT_ESOP);
s390_cpudef_featoff_greater(12, 1, S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2);
s390_cpudef_featoff_greater(12, 1, S390_FEAT_ZPCI);
s390_cpudef_featoff_greater(12, 1, S390_FEAT_ADAPTER_INT_SUPPRESSION);
s390_cpudef_featoff_greater(12, 1, S390_FEAT_ADAPTER_EVENT_NOTIFICATION);
} }
static void ccw_machine_2_9_class_options(MachineClass *mc) static void ccw_machine_2_9_class_options(MachineClass *mc)
{ {
S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
s390mc->gs_allowed = false;
ccw_machine_2_10_class_options(mc); ccw_machine_2_10_class_options(mc);
SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_9); SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_9);
s390mc->css_migration_enabled = false;
} }
DEFINE_CCW_MACHINE(2_9, "2.9", false); DEFINE_CCW_MACHINE(2_9, "2.9", false);

View file

@ -8,6 +8,7 @@ css_new_image(uint8_t cssid, const char *default_cssid) "CSS: add css image %02x
css_assign_subch(const char *do_assign, uint8_t cssid, uint8_t ssid, uint16_t schid, uint16_t devno) "CSS: %s %x.%x.%04x (devno %04x)" css_assign_subch(const char *do_assign, uint8_t cssid, uint8_t ssid, uint16_t schid, uint16_t devno) "CSS: %s %x.%x.%04x (devno %04x)"
css_io_interrupt(int cssid, int ssid, int schid, uint32_t intparm, uint8_t isc, const char *conditional) "CSS: I/O interrupt on sch %x.%x.%04x (intparm %08x, isc %x) %s" css_io_interrupt(int cssid, int ssid, int schid, uint32_t intparm, uint8_t isc, const char *conditional) "CSS: I/O interrupt on sch %x.%x.%04x (intparm %08x, isc %x) %s"
css_adapter_interrupt(uint8_t isc) "CSS: adapter I/O interrupt (isc %x)" css_adapter_interrupt(uint8_t isc) "CSS: adapter I/O interrupt (isc %x)"
css_do_sic(uint16_t mode, uint8_t isc) "CSS: set interruption mode %x on isc %x"
# hw/s390x/virtio-ccw.c # hw/s390x/virtio-ccw.c
virtio_ccw_interpret_ccw(int cssid, int ssid, int schid, int cmd_code) "VIRTIO-CCW: %x.%x.%04x: interpret command %x" virtio_ccw_interpret_ccw(int cssid, int ssid, int schid, int cmd_code) "VIRTIO-CCW: %x.%x.%04x: interpret command %x"

View file

@ -1070,7 +1070,7 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
0x80 >> ((ind_bit + vector) % 8)); 0x80 >> ((ind_bit + vector) % 8));
if (!virtio_set_ind_atomic(sch, dev->summary_indicator->addr, if (!virtio_set_ind_atomic(sch, dev->summary_indicator->addr,
0x01)) { 0x01)) {
css_adapter_interrupt(dev->thinint_isc); css_adapter_interrupt(CSS_IO_ADAPTER_VIRTIO, dev->thinint_isc);
} }
} else { } else {
indicators = address_space_ldq(&address_space_memory, indicators = address_space_ldq(&address_space_memory,

View file

@ -1476,6 +1476,7 @@ typedef struct elf64_shdr {
#define NT_TASKSTRUCT 4 #define NT_TASKSTRUCT 4
#define NT_AUXV 6 #define NT_AUXV 6
#define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */ #define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */
#define NT_S390_GS_CB 0x30b /* s390 guarded storage registers */
#define NT_S390_VXRS_HIGH 0x30a /* s390 vector registers 16-31 */ #define NT_S390_VXRS_HIGH 0x30a /* s390 vector registers 16-31 */
#define NT_S390_VXRS_LOW 0x309 /* s390 vector registers 0-15 (lower half) */ #define NT_S390_VXRS_LOW 0x309 /* s390 vector registers 0-15 (lower half) */
#define NT_S390_PREFIX 0x305 /* s390 prefix register */ #define NT_S390_PREFIX 0x305 /* s390 prefix register */

View file

@ -12,6 +12,7 @@
#ifndef CSS_H #ifndef CSS_H
#define CSS_H #define CSS_H
#include "cpu.h"
#include "hw/s390x/adapter.h" #include "hw/s390x/adapter.h"
#include "hw/s390x/s390_flic.h" #include "hw/s390x/s390_flic.h"
#include "hw/s390x/ioinst.h" #include "hw/s390x/ioinst.h"
@ -89,10 +90,11 @@ struct SubchDev {
bool thinint_active; bool thinint_active;
uint8_t ccw_no_data_cnt; uint8_t ccw_no_data_cnt;
uint16_t migrated_schid; /* used for missmatch detection */ uint16_t migrated_schid; /* used for missmatch detection */
ORB orb;
/* transport-provided data: */ /* transport-provided data: */
int (*ccw_cb) (SubchDev *, CCW1); int (*ccw_cb) (SubchDev *, CCW1);
void (*disable_cb)(SubchDev *); void (*disable_cb)(SubchDev *);
int (*do_subchannel_work) (SubchDev *, ORB *); int (*do_subchannel_work) (SubchDev *);
SenseId id; SenseId id;
void *driver_data; void *driver_data;
}; };
@ -154,10 +156,9 @@ void css_generate_sch_crws(uint8_t cssid, uint8_t ssid, uint16_t schid,
void css_generate_chp_crws(uint8_t cssid, uint8_t chpid); void css_generate_chp_crws(uint8_t cssid, uint8_t chpid);
void css_generate_css_crws(uint8_t cssid); void css_generate_css_crws(uint8_t cssid);
void css_clear_sei_pending(void); void css_clear_sei_pending(void);
void css_adapter_interrupt(uint8_t isc);
int s390_ccw_cmd_request(ORB *orb, SCSW *scsw, void *data); int s390_ccw_cmd_request(ORB *orb, SCSW *scsw, void *data);
int do_subchannel_work_virtual(SubchDev *sub, ORB *orb); int do_subchannel_work_virtual(SubchDev *sub);
int do_subchannel_work_passthrough(SubchDev *sub, ORB *orb); int do_subchannel_work_passthrough(SubchDev *sub);
typedef enum { typedef enum {
CSS_IO_ADAPTER_VIRTIO = 0, CSS_IO_ADAPTER_VIRTIO = 0,
@ -165,9 +166,17 @@ typedef enum {
CSS_IO_ADAPTER_TYPE_NUMS, CSS_IO_ADAPTER_TYPE_NUMS,
} CssIoAdapterType; } CssIoAdapterType;
void css_adapter_interrupt(CssIoAdapterType type, uint8_t isc);
int css_do_sic(CPUS390XState *env, uint8_t isc, uint16_t mode);
uint32_t css_get_adapter_id(CssIoAdapterType type, uint8_t isc); uint32_t css_get_adapter_id(CssIoAdapterType type, uint8_t isc);
void css_register_io_adapters(CssIoAdapterType type, bool swap, bool maskable, void css_register_io_adapters(CssIoAdapterType type, bool swap, bool maskable,
Error **errp); uint8_t flags, Error **errp);
#ifndef CONFIG_KVM
#define S390_ADAPTER_SUPPRESSIBLE 0x01
#else
#define S390_ADAPTER_SUPPRESSIBLE KVM_S390_ADAPTER_SUPPRESSIBLE
#endif
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
SubchDev *css_find_subch(uint8_t m, uint8_t cssid, uint8_t ssid, SubchDev *css_find_subch(uint8_t m, uint8_t cssid, uint8_t ssid,
@ -225,4 +234,8 @@ extern const PropertyInfo css_devid_ro_propinfo;
*/ */
SubchDev *css_create_sch(CssDevId bus_id, bool is_virtual, bool squash_mcss, SubchDev *css_create_sch(CssDevId bus_id, bool is_virtual, bool squash_mcss,
Error **errp); Error **errp);
/** Turn on css migration */
void css_register_vmstate(void);
#endif #endif

View file

@ -39,11 +39,21 @@ typedef struct S390CcwMachineClass {
/*< public >*/ /*< public >*/
bool ri_allowed; bool ri_allowed;
bool cpu_model_allowed; bool cpu_model_allowed;
bool css_migration_enabled;
bool gs_allowed;
} S390CcwMachineClass; } S390CcwMachineClass;
/* runtime-instrumentation allowed by the machine */ /* runtime-instrumentation allowed by the machine */
bool ri_allowed(void); bool ri_allowed(void);
/* cpu model allowed by the machine */ /* cpu model allowed by the machine */
bool cpu_model_allowed(void); bool cpu_model_allowed(void);
/* guarded-storage allowed by the machine */
bool gs_allowed(void);
/**
* Returns true if (vmstate based) migration of the channel subsystem
* is enabled, false if it is disabled.
*/
bool css_migration_enabled(void);
#endif #endif

View file

@ -44,7 +44,7 @@ typedef struct S390FLICState {
SysBusDevice parent_obj; SysBusDevice parent_obj;
/* to limit AdapterRoutes.num_routes for compat */ /* to limit AdapterRoutes.num_routes for compat */
uint32_t adapter_routes_max_batch; uint32_t adapter_routes_max_batch;
bool ais_supported;
} S390FLICState; } S390FLICState;
#define S390_FLIC_COMMON_CLASS(klass) \ #define S390_FLIC_COMMON_CLASS(klass) \
@ -56,13 +56,16 @@ typedef struct S390FLICStateClass {
DeviceClass parent_class; DeviceClass parent_class;
int (*register_io_adapter)(S390FLICState *fs, uint32_t id, uint8_t isc, int (*register_io_adapter)(S390FLICState *fs, uint32_t id, uint8_t isc,
bool swap, bool maskable); bool swap, bool maskable, uint8_t flags);
int (*io_adapter_map)(S390FLICState *fs, uint32_t id, uint64_t map_addr, int (*io_adapter_map)(S390FLICState *fs, uint32_t id, uint64_t map_addr,
bool do_map); bool do_map);
int (*add_adapter_routes)(S390FLICState *fs, AdapterRoutes *routes); int (*add_adapter_routes)(S390FLICState *fs, AdapterRoutes *routes);
void (*release_adapter_routes)(S390FLICState *fs, AdapterRoutes *routes); void (*release_adapter_routes)(S390FLICState *fs, AdapterRoutes *routes);
int (*clear_io_irq)(S390FLICState *fs, uint16_t subchannel_id, int (*clear_io_irq)(S390FLICState *fs, uint16_t subchannel_id,
uint16_t subchannel_nr); uint16_t subchannel_nr);
int (*modify_ais_mode)(S390FLICState *fs, uint8_t isc, uint16_t mode);
int (*inject_airq)(S390FLICState *fs, uint8_t type, uint8_t isc,
uint8_t flags);
} S390FLICStateClass; } S390FLICStateClass;
#define TYPE_KVM_S390_FLIC "s390-flic-kvm" #define TYPE_KVM_S390_FLIC "s390-flic-kvm"
@ -73,13 +76,20 @@ typedef struct S390FLICStateClass {
#define QEMU_S390_FLIC(obj) \ #define QEMU_S390_FLIC(obj) \
OBJECT_CHECK(QEMUS390FLICState, (obj), TYPE_QEMU_S390_FLIC) OBJECT_CHECK(QEMUS390FLICState, (obj), TYPE_QEMU_S390_FLIC)
#define SIC_IRQ_MODE_ALL 0
#define SIC_IRQ_MODE_SINGLE 1
#define AIS_MODE_MASK(isc) (0x80 >> isc)
typedef struct QEMUS390FLICState { typedef struct QEMUS390FLICState {
S390FLICState parent_obj; S390FLICState parent_obj;
uint8_t simm;
uint8_t nimm;
} QEMUS390FLICState; } QEMUS390FLICState;
void s390_flic_init(void); void s390_flic_init(void);
S390FLICState *s390_get_flic(void); S390FLICState *s390_get_flic(void);
bool ais_needed(void *opaque);
#ifdef CONFIG_KVM #ifdef CONFIG_KVM
DeviceState *s390_flic_kvm_create(void); DeviceState *s390_flic_kvm_create(void);

View file

@ -123,8 +123,7 @@ typedef struct ReadInfo {
uint64_t facilities; /* 48-55 */ uint64_t facilities; /* 48-55 */
uint8_t _reserved0[76 - 56]; /* 56-75 */ uint8_t _reserved0[76 - 56]; /* 56-75 */
uint32_t ibc_val; uint32_t ibc_val;
uint8_t conf_char[96 - 80]; /* 80-95 */ uint8_t conf_char[99 - 80]; /* 80-98 */
uint8_t _reserved4[99 - 96]; /* 96-98 */
uint8_t mha_pow; uint8_t mha_pow;
uint32_t rnsize2; uint32_t rnsize2;
uint64_t rnmax2; uint64_t rnmax2;

View file

@ -0,0 +1,81 @@
/*
* s390 storage attributes device
*
* Copyright 2016 IBM Corp.
* Author(s): Claudio Imbrenda <imbrenda@linux.vnet.ibm.com>
*
* 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.
*/
#ifndef S390_STORAGE_ATTRIBUTES_H
#define S390_STORAGE_ATTRIBUTES_H
#include <hw/qdev.h>
#include "monitor/monitor.h"
#define TYPE_S390_STATTRIB "s390-storage_attributes"
#define TYPE_QEMU_S390_STATTRIB "s390-storage_attributes-qemu"
#define TYPE_KVM_S390_STATTRIB "s390-storage_attributes-kvm"
#define S390_STATTRIB(obj) \
OBJECT_CHECK(S390StAttribState, (obj), TYPE_S390_STATTRIB)
typedef struct S390StAttribState {
DeviceState parent_obj;
uint64_t migration_cur_gfn;
bool migration_enabled;
} S390StAttribState;
#define S390_STATTRIB_CLASS(klass) \
OBJECT_CLASS_CHECK(S390StAttribClass, (klass), TYPE_S390_STATTRIB)
#define S390_STATTRIB_GET_CLASS(obj) \
OBJECT_GET_CLASS(S390StAttribClass, (obj), TYPE_S390_STATTRIB)
typedef struct S390StAttribClass {
DeviceClass parent_class;
/* Return value: < 0 on error, or new count */
int (*get_stattr)(S390StAttribState *sa, uint64_t *start_gfn,
uint32_t count, uint8_t *values);
int (*peek_stattr)(S390StAttribState *sa, uint64_t start_gfn,
uint32_t count, uint8_t *values);
int (*set_stattr)(S390StAttribState *sa, uint64_t start_gfn,
uint32_t count, uint8_t *values);
void (*synchronize)(S390StAttribState *sa);
int (*set_migrationmode)(S390StAttribState *sa, bool value);
int (*get_active)(S390StAttribState *sa);
long long (*get_dirtycount)(S390StAttribState *sa);
} S390StAttribClass;
#define QEMU_S390_STATTRIB(obj) \
OBJECT_CHECK(QEMUS390StAttribState, (obj), TYPE_QEMU_S390_STATTRIB)
typedef struct QEMUS390StAttribState {
S390StAttribState parent_obj;
} QEMUS390StAttribState;
#define KVM_S390_STATTRIB(obj) \
OBJECT_CHECK(KVMS390StAttribState, (obj), TYPE_KVM_S390_STATTRIB)
typedef struct KVMS390StAttribState {
S390StAttribState parent_obj;
uint64_t still_dirty;
uint8_t *incoming_buffer;
} KVMS390StAttribState;
void s390_stattrib_init(void);
#ifdef CONFIG_KVM
Object *kvm_s390_stattrib_create(void);
#else
static inline Object *kvm_s390_stattrib_create(void)
{
return NULL;
}
#endif
void hmp_info_cmma(Monitor *mon, const QDict *qdict);
void hmp_migrationmode(Monitor *mon, const QDict *qdict);
#endif /* S390_STORAGE_ATTRIBUTES_H */

View file

@ -34,16 +34,10 @@
#define HV_X64_MSR_REFERENCE_TSC 0x40000021 #define HV_X64_MSR_REFERENCE_TSC 0x40000021
/* /*
* There is a single feature flag that signifies the presence of the MSR * There is a single feature flag that signifies if the partition has access
* that can be used to retrieve both the local APIC Timer frequency as * to MSRs with local APIC and TSC frequencies.
* well as the TSC frequency.
*/ */
#define HV_X64_ACCESS_FREQUENCY_MSRS (1 << 11)
/* Local APIC timer frequency MSR (HV_X64_MSR_APIC_FREQUENCY) is available */
#define HV_X64_MSR_APIC_FREQUENCY_AVAILABLE (1 << 11)
/* TSC frequency MSR (HV_X64_MSR_TSC_FREQUENCY) is available */
#define HV_X64_MSR_TSC_FREQUENCY_AVAILABLE (1 << 11)
/* /*
* Basic SynIC MSRs (HV_X64_MSR_SCONTROL through HV_X64_MSR_EOM * Basic SynIC MSRs (HV_X64_MSR_SCONTROL through HV_X64_MSR_EOM
@ -73,6 +67,9 @@
*/ */
#define HV_X64_MSR_STAT_PAGES_AVAILABLE (1 << 8) #define HV_X64_MSR_STAT_PAGES_AVAILABLE (1 << 8)
/* Frequency MSRs available */
#define HV_FEATURE_FREQUENCY_MSRS_AVAILABLE (1 << 8)
/* Crash MSR available */ /* Crash MSR available */
#define HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE (1 << 10) #define HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE (1 << 10)
@ -152,6 +149,12 @@
*/ */
#define HV_X64_DEPRECATING_AEOI_RECOMMENDED (1 << 9) #define HV_X64_DEPRECATING_AEOI_RECOMMENDED (1 << 9)
/*
* HV_VP_SET available
*/
#define HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED (1 << 11)
/* /*
* Crash notification flag. * Crash notification flag.
*/ */

View file

@ -600,6 +600,7 @@
#define KEY_APPSELECT 0x244 /* AL Select Task/Application */ #define KEY_APPSELECT 0x244 /* AL Select Task/Application */
#define KEY_SCREENSAVER 0x245 /* AL Screen Saver */ #define KEY_SCREENSAVER 0x245 /* AL Screen Saver */
#define KEY_VOICECOMMAND 0x246 /* Listening Voice Command */ #define KEY_VOICECOMMAND 0x246 /* Listening Voice Command */
#define KEY_ASSISTANT 0x247 /* AL Context-aware desktop assistant */
#define KEY_BRIGHTNESS_MIN 0x250 /* Set Brightness to Minimum */ #define KEY_BRIGHTNESS_MIN 0x250 /* Set Brightness to Minimum */
#define KEY_BRIGHTNESS_MAX 0x251 /* Set Brightness to Maximum */ #define KEY_BRIGHTNESS_MAX 0x251 /* Set Brightness to Maximum */

View file

@ -517,6 +517,7 @@
#define PCI_EXP_LNKCAP_SLS 0x0000000f /* Supported Link Speeds */ #define PCI_EXP_LNKCAP_SLS 0x0000000f /* Supported Link Speeds */
#define PCI_EXP_LNKCAP_SLS_2_5GB 0x00000001 /* LNKCAP2 SLS Vector bit 0 */ #define PCI_EXP_LNKCAP_SLS_2_5GB 0x00000001 /* LNKCAP2 SLS Vector bit 0 */
#define PCI_EXP_LNKCAP_SLS_5_0GB 0x00000002 /* LNKCAP2 SLS Vector bit 1 */ #define PCI_EXP_LNKCAP_SLS_5_0GB 0x00000002 /* LNKCAP2 SLS Vector bit 1 */
#define PCI_EXP_LNKCAP_SLS_8_0GB 0x00000003 /* LNKCAP2 SLS Vector bit 2 */
#define PCI_EXP_LNKCAP_MLW 0x000003f0 /* Maximum Link Width */ #define PCI_EXP_LNKCAP_MLW 0x000003f0 /* Maximum Link Width */
#define PCI_EXP_LNKCAP_ASPMS 0x00000c00 /* ASPM Support */ #define PCI_EXP_LNKCAP_ASPMS 0x00000c00 /* ASPM Support */
#define PCI_EXP_LNKCAP_L0SEL 0x00007000 /* L0s Exit Latency */ #define PCI_EXP_LNKCAP_L0SEL 0x00007000 /* L0s Exit Latency */

View file

@ -203,6 +203,14 @@ struct kvm_arch_memory_slot {
#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK 0x3ff #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK 0x3ff
#define VGIC_LEVEL_INFO_LINE_LEVEL 0 #define VGIC_LEVEL_INFO_LINE_LEVEL 0
/* Device Control API on vcpu fd */
#define KVM_ARM_VCPU_PMU_V3_CTRL 0
#define KVM_ARM_VCPU_PMU_V3_IRQ 0
#define KVM_ARM_VCPU_PMU_V3_INIT 1
#define KVM_ARM_VCPU_TIMER_CTRL 1
#define KVM_ARM_VCPU_TIMER_IRQ_VTIMER 0
#define KVM_ARM_VCPU_TIMER_IRQ_PTIMER 1
#define KVM_DEV_ARM_VGIC_CTRL_INIT 0 #define KVM_DEV_ARM_VGIC_CTRL_INIT 0
#define KVM_DEV_ARM_ITS_SAVE_TABLES 1 #define KVM_DEV_ARM_ITS_SAVE_TABLES 1
#define KVM_DEV_ARM_ITS_RESTORE_TABLES 2 #define KVM_DEV_ARM_ITS_RESTORE_TABLES 2

View file

@ -232,6 +232,9 @@ struct kvm_arch_memory_slot {
#define KVM_ARM_VCPU_PMU_V3_CTRL 0 #define KVM_ARM_VCPU_PMU_V3_CTRL 0
#define KVM_ARM_VCPU_PMU_V3_IRQ 0 #define KVM_ARM_VCPU_PMU_V3_IRQ 0
#define KVM_ARM_VCPU_PMU_V3_INIT 1 #define KVM_ARM_VCPU_PMU_V3_INIT 1
#define KVM_ARM_VCPU_TIMER_CTRL 1
#define KVM_ARM_VCPU_TIMER_IRQ_VTIMER 0
#define KVM_ARM_VCPU_TIMER_IRQ_PTIMER 1
/* KVM_IRQ_LINE irq field index values */ /* KVM_IRQ_LINE irq field index values */
#define KVM_ARM_IRQ_TYPE_SHIFT 24 #define KVM_ARM_IRQ_TYPE_SHIFT 24

View file

@ -60,6 +60,12 @@ struct kvm_regs {
#define KVM_SREGS_E_FSL_PIDn (1 << 0) /* PID1/PID2 */ #define KVM_SREGS_E_FSL_PIDn (1 << 0) /* PID1/PID2 */
/* flags for kvm_run.flags */
#define KVM_RUN_PPC_NMI_DISP_MASK (3 << 0)
#define KVM_RUN_PPC_NMI_DISP_FULLY_RECOV (1 << 0)
#define KVM_RUN_PPC_NMI_DISP_LIMITED_RECOV (2 << 0)
#define KVM_RUN_PPC_NMI_DISP_NOT_RECOV (3 << 0)
/* /*
* Feature bits indicate which sections of the sregs struct are valid, * Feature bits indicate which sections of the sregs struct are valid,
* both in KVM_GET_SREGS and KVM_SET_SREGS. On KVM_SET_SREGS, registers * both in KVM_GET_SREGS and KVM_SET_SREGS. On KVM_SET_SREGS, registers

View file

@ -28,6 +28,7 @@
#define KVM_DEV_FLIC_CLEAR_IO_IRQ 8 #define KVM_DEV_FLIC_CLEAR_IO_IRQ 8
#define KVM_DEV_FLIC_AISM 9 #define KVM_DEV_FLIC_AISM 9
#define KVM_DEV_FLIC_AIRQ_INJECT 10 #define KVM_DEV_FLIC_AIRQ_INJECT 10
#define KVM_DEV_FLIC_AISM_ALL 11
/* /*
* We can have up to 4*64k pending subchannels + 8 adapter interrupts, * We can have up to 4*64k pending subchannels + 8 adapter interrupts,
* as well as up to ASYNC_PF_PER_VCPU*KVM_MAX_VCPUS pfault done interrupts. * as well as up to ASYNC_PF_PER_VCPU*KVM_MAX_VCPUS pfault done interrupts.
@ -53,6 +54,11 @@ struct kvm_s390_ais_req {
__u16 mode; __u16 mode;
}; };
struct kvm_s390_ais_all {
__u8 simm;
__u8 nimm;
};
#define KVM_S390_IO_ADAPTER_MASK 1 #define KVM_S390_IO_ADAPTER_MASK 1
#define KVM_S390_IO_ADAPTER_MAP 2 #define KVM_S390_IO_ADAPTER_MAP 2
#define KVM_S390_IO_ADAPTER_UNMAP 3 #define KVM_S390_IO_ADAPTER_UNMAP 3
@ -70,6 +76,7 @@ struct kvm_s390_io_adapter_req {
#define KVM_S390_VM_TOD 1 #define KVM_S390_VM_TOD 1
#define KVM_S390_VM_CRYPTO 2 #define KVM_S390_VM_CRYPTO 2
#define KVM_S390_VM_CPU_MODEL 3 #define KVM_S390_VM_CPU_MODEL 3
#define KVM_S390_VM_MIGRATION 4
/* kvm attributes for mem_ctrl */ /* kvm attributes for mem_ctrl */
#define KVM_S390_VM_MEM_ENABLE_CMMA 0 #define KVM_S390_VM_MEM_ENABLE_CMMA 0
@ -151,6 +158,11 @@ struct kvm_s390_vm_cpu_subfunc {
#define KVM_S390_VM_CRYPTO_DISABLE_AES_KW 2 #define KVM_S390_VM_CRYPTO_DISABLE_AES_KW 2
#define KVM_S390_VM_CRYPTO_DISABLE_DEA_KW 3 #define KVM_S390_VM_CRYPTO_DISABLE_DEA_KW 3
/* kvm attributes for migration mode */
#define KVM_S390_VM_MIGRATION_STOP 0
#define KVM_S390_VM_MIGRATION_START 1
#define KVM_S390_VM_MIGRATION_STATUS 2
/* for KVM_GET_REGS and KVM_SET_REGS */ /* for KVM_GET_REGS and KVM_SET_REGS */
struct kvm_regs { struct kvm_regs {
/* general purpose regs for s390 */ /* general purpose regs for s390 */

View file

@ -155,6 +155,35 @@ struct kvm_s390_skeys {
__u32 reserved[9]; __u32 reserved[9];
}; };
#define KVM_S390_CMMA_PEEK (1 << 0)
/**
* kvm_s390_cmma_log - Used for CMMA migration.
*
* Used both for input and output.
*
* @start_gfn: Guest page number to start from.
* @count: Size of the result buffer.
* @flags: Control operation mode via KVM_S390_CMMA_* flags
* @remaining: Used with KVM_S390_GET_CMMA_BITS. Indicates how many dirty
* pages are still remaining.
* @mask: Used with KVM_S390_SET_CMMA_BITS. Bitmap of bits to actually set
* in the PGSTE.
* @values: Pointer to the values buffer.
*
* Used in KVM_S390_{G,S}ET_CMMA_BITS ioctls.
*/
struct kvm_s390_cmma_log {
__u64 start_gfn;
__u32 count;
__u32 flags;
union {
__u64 remaining;
__u64 mask;
};
__u64 values;
};
struct kvm_hyperv_exit { struct kvm_hyperv_exit {
#define KVM_EXIT_HYPERV_SYNIC 1 #define KVM_EXIT_HYPERV_SYNIC 1
#define KVM_EXIT_HYPERV_HCALL 2 #define KVM_EXIT_HYPERV_HCALL 2
@ -895,6 +924,9 @@ struct kvm_ppc_resize_hpt {
#define KVM_CAP_SPAPR_TCE_VFIO 142 #define KVM_CAP_SPAPR_TCE_VFIO 142
#define KVM_CAP_X86_GUEST_MWAIT 143 #define KVM_CAP_X86_GUEST_MWAIT 143
#define KVM_CAP_ARM_USER_IRQ 144 #define KVM_CAP_ARM_USER_IRQ 144
#define KVM_CAP_S390_CMMA_MIGRATION 145
#define KVM_CAP_PPC_FWNMI 146
#define KVM_CAP_PPC_SMT_POSSIBLE 147
#ifdef KVM_CAP_IRQ_ROUTING #ifdef KVM_CAP_IRQ_ROUTING
@ -1318,6 +1350,9 @@ struct kvm_s390_ucas_mapping {
#define KVM_S390_GET_IRQ_STATE _IOW(KVMIO, 0xb6, struct kvm_s390_irq_state) #define KVM_S390_GET_IRQ_STATE _IOW(KVMIO, 0xb6, struct kvm_s390_irq_state)
/* Available with KVM_CAP_X86_SMM */ /* Available with KVM_CAP_X86_SMM */
#define KVM_SMI _IO(KVMIO, 0xb7) #define KVM_SMI _IO(KVMIO, 0xb7)
/* Available with KVM_CAP_S390_CMMA_MIGRATION */
#define KVM_S390_GET_CMMA_BITS _IOW(KVMIO, 0xb8, struct kvm_s390_cmma_log)
#define KVM_S390_SET_CMMA_BITS _IOW(KVMIO, 0xb9, struct kvm_s390_cmma_log)
#define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0)
#define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1) #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1)

View file

@ -81,6 +81,7 @@
#if defined(TARGET_S390X) #if defined(TARGET_S390X)
#include "hw/s390x/storage-keys.h" #include "hw/s390x/storage-keys.h"
#include "hw/s390x/storage-attributes.h"
#endif #endif
/* /*

Binary file not shown.

View file

@ -9,14 +9,14 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw)
.PHONY : all clean build-all .PHONY : all clean build-all
OBJECTS = start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o OBJECTS = start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o virtio-blkdev.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 += $(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
build-all: s390-ccw.img build-all: s390-ccw.img s390-netboot.img
s390-ccw.elf: $(OBJECTS) s390-ccw.elf: $(OBJECTS)
$(call quiet-command,$(CC) $(LDFLAGS) -o $@ $(OBJECTS),"BUILD","$(TARGET_DIR)$@") $(call quiet-command,$(CC) $(LDFLAGS) -o $@ $(OBJECTS),"BUILD","$(TARGET_DIR)$@")
@ -28,5 +28,12 @@ s390-ccw.img: s390-ccw.elf
$(OBJECTS): Makefile $(OBJECTS): Makefile
ifneq ($(wildcard $(SRC_PATH)/roms/SLOF/lib/libnet),)
include $(SRC_PATH)/pc-bios/s390-ccw/netboot.mak
else
s390-netboot.img:
@echo "s390-netboot.img not built since roms/SLOF/ is not available."
endif
clean: clean:
rm -f *.o *.d *.img *.elf *~ $(RM) *.o *.d *.img *.elf *~ *.a

View file

@ -8,9 +8,11 @@
* directory. * directory.
*/ */
#include "libc.h"
#include "s390-ccw.h" #include "s390-ccw.h"
#include "bootmap.h" #include "bootmap.h"
#include "virtio.h" #include "virtio.h"
#include "bswap.h"
#ifdef DEBUG #ifdef DEBUG
/* #define DEBUG_FALLBACK */ /* #define DEBUG_FALLBACK */

View file

@ -324,32 +324,6 @@ static inline int _memcmp(const void *s1, const void *s2, size_t n)
return 0; return 0;
} }
/* from include/qemu/bswap.h */
/* El Torito is always little-endian */
static inline uint16_t bswap16(uint16_t x)
{
return ((x & 0x00ff) << 8) | ((x & 0xff00) >> 8);
}
static inline uint32_t bswap32(uint32_t x)
{
return ((x & 0x000000ffU) << 24) | ((x & 0x0000ff00U) << 8) |
((x & 0x00ff0000U) >> 8) | ((x & 0xff000000U) >> 24);
}
static inline uint64_t bswap64(uint64_t x)
{
return ((x & 0x00000000000000ffULL) << 56) |
((x & 0x000000000000ff00ULL) << 40) |
((x & 0x0000000000ff0000ULL) << 24) |
((x & 0x00000000ff000000ULL) << 8) |
((x & 0x000000ff00000000ULL) >> 8) |
((x & 0x0000ff0000000000ULL) >> 24) |
((x & 0x00ff000000000000ULL) >> 40) |
((x & 0xff00000000000000ULL) >> 56);
}
static inline uint32_t iso_733_to_u32(uint64_t x) static inline uint32_t iso_733_to_u32(uint64_t x)
{ {
return (uint32_t)x; return (uint32_t)x;

30
pc-bios/s390-ccw/bswap.h Normal file
View file

@ -0,0 +1,30 @@
/*
* Byte swap functions - taken from include/qemu/bswap.h
*
* 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.
*/
static inline uint16_t bswap16(uint16_t x)
{
return ((x & 0x00ff) << 8) | ((x & 0xff00) >> 8);
}
static inline uint32_t bswap32(uint32_t x)
{
return ((x & 0x000000ffU) << 24) | ((x & 0x0000ff00U) << 8) |
((x & 0x00ff0000U) >> 8) | ((x & 0xff000000U) >> 24);
}
static inline uint64_t bswap64(uint64_t x)
{
return ((x & 0x00000000000000ffULL) << 56) |
((x & 0x000000000000ff00ULL) << 40) |
((x & 0x0000000000ff0000ULL) << 24) |
((x & 0x00000000ff000000ULL) << 8) |
((x & 0x000000ff00000000ULL) >> 8) |
((x & 0x0000ff0000000000ULL) >> 24) |
((x & 0x00ff000000000000ULL) >> 40) |
((x & 0xff00000000000000ULL) >> 56);
}

45
pc-bios/s390-ccw/libc.h Normal file
View file

@ -0,0 +1,45 @@
/*
* libc-style definitions and functions
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef S390_CCW_LIBC_H
#define S390_CCW_LIBC_H
typedef long size_t;
typedef int bool;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
static inline void *memset(void *s, int c, size_t n)
{
int i;
unsigned char *p = s;
for (i = 0; i < n; i++) {
p[i] = c;
}
return s;
}
static inline void *memcpy(void *s1, const void *s2, size_t n)
{
uint8_t *dest = s1;
const uint8_t *src = s2;
int i;
for (i = 0; i < n; i++) {
dest[i] = src[i];
}
return s1;
}
#endif

View file

@ -8,6 +8,7 @@
* directory. * directory.
*/ */
#include "libc.h"
#include "s390-ccw.h" #include "s390-ccw.h"
#include "virtio.h" #include "virtio.h"
@ -16,17 +17,6 @@ static SubChannelId blk_schid = { .one = 1 };
IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE))); IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
static char loadparm[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; static char loadparm[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
const unsigned char ebc2asc[256] =
/* 0123456789abcdef0123456789abcdef */
"................................" /* 1F */
"................................" /* 3F */
" ...........<(+|&.........!$*);." /* 5F first.chr.here.is.real.space */
"-/.........,%_>?.........`:#@'=\""/* 7F */
".abcdefghi.......jklmnopqr......" /* 9F */
"..stuvwxyz......................" /* BF */
".ABCDEFGHI.......JKLMNOPQR......" /* DF */
"..STUVWXYZ......0123456789......";/* FF */
/* /*
* Priniciples of Operations (SA22-7832-09) chapter 17 requires that * Priniciples of Operations (SA22-7832-09) chapter 17 requires that
* a subsystem-identification is at 184-187 and bytes 188-191 are zero * a subsystem-identification is at 184-187 and bytes 188-191 are zero
@ -154,7 +144,7 @@ static void virtio_setup(void)
sclp_print("Network boot device detected\n"); sclp_print("Network boot device detected\n");
vdev->netboot_start_addr = iplb.ccw.netboot_start_addr; vdev->netboot_start_addr = iplb.ccw.netboot_start_addr;
} else { } else {
virtio_setup_device(blk_schid); virtio_blk_setup_device(blk_schid);
IPL_assert(virtio_ipl_disk_is_valid(), "No valid IPL device detected"); IPL_assert(virtio_ipl_disk_is_valid(), "No valid IPL device detected");
} }

View file

@ -0,0 +1,59 @@
SLOF_DIR := $(SRC_PATH)/roms/SLOF
NETOBJS := start.o sclp.o virtio.o virtio-net.o netmain.o libnet.a libc.a
LIBC_INC := -nostdinc -I$(SLOF_DIR)/lib/libc/include
LIBNET_INC := -I$(SLOF_DIR)/lib/libnet
NETLDFLAGS := $(LDFLAGS) -Ttext=0x7800000
$(NETOBJS): QEMU_CFLAGS += $(LIBC_INC) $(LIBNET_INC)
s390-netboot.elf: $(NETOBJS)
$(call quiet-command,$(CC) $(NETLDFLAGS) -o $@ $(NETOBJS),"BUILD","$(TARGET_DIR)$@")
s390-netboot.img: s390-netboot.elf
$(call quiet-command,$(STRIP) --strip-unneeded $< -o $@,"STRIP","$(TARGET_DIR)$@")
# libc files:
LIBC_CFLAGS := $(QEMU_CFLAGS) $(LIBC_INC) $(LIBNET_INC)
CTYPE_OBJS = isdigit.o isxdigit.o toupper.o
%.o : $(SLOF_DIR)/lib/libc/ctype/%.c
$(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 \
strstr.o memset.o memcpy.o memmove.o memcmp.o
%.o : $(SLOF_DIR)/lib/libc/string/%.c
$(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@")
STDLIB_OBJS = atoi.o atol.o strtoul.o strtol.o rand.o malloc.o free.o
%.o : $(SLOF_DIR)/lib/libc/stdlib/%.c
$(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@")
STDIO_OBJS = sprintf.o vfprintf.o vsnprintf.o vsprintf.o fprintf.o \
printf.o putc.o puts.o putchar.o stdchnls.o fileno.o
%.o : $(SLOF_DIR)/lib/libc/stdio/%.c
$(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@")
sbrk.o: $(SLOF_DIR)/slof/sbrk.c
$(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@")
LIBCOBJS := $(STRING_OBJS) $(CTYPE_OBJS) $(STDLIB_OBJS) $(STDIO_OBJS) sbrk.o
libc.a: $(LIBCOBJS)
$(call quiet-command,$(AR) -rc $@ $^,"AR","$(TARGET_DIR)$@")
# libnet files:
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
LIBNETCFLAGS := $(QEMU_CFLAGS) $(LIBC_INC) $(LIBNET_INC)
%.o : $(SLOF_DIR)/lib/libnet/%.c
$(call quiet-command,$(CC) $(LIBNETCFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@")
libnet.a: $(LIBNETOBJS)
$(call quiet-command,$(AR) -rc $@ $^,"AR","$(TARGET_DIR)$@")

361
pc-bios/s390-ccw/netmain.c Normal file
View file

@ -0,0 +1,361 @@
/*
* S390 virtio-ccw network boot loading program
*
* Copyright 2017 Thomas Huth, Red Hat Inc.
*
* Based on the S390 virtio-ccw loading program (main.c)
* Copyright (c) 2013 Alexander Graf <agraf@suse.de>
*
* And based on the network loading code from SLOF (netload.c)
* Copyright (c) 2004, 2008 IBM Corporation
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <tftp.h>
#include <ethernet.h>
#include <dhcp.h>
#include <dhcpv6.h>
#include <ipv4.h>
#include <ipv6.h>
#include <dns.h>
#include <time.h>
#include "s390-ccw.h"
#include "virtio.h"
#define DEFAULT_BOOT_RETRIES 10
#define DEFAULT_TFTP_RETRIES 20
extern char _start[];
char stack[PAGE_SIZE * 8] __attribute__((aligned(PAGE_SIZE)));
IplParameterBlock iplb __attribute__((aligned(PAGE_SIZE)));
static SubChannelId net_schid = { .one = 1 };
static int ip_version = 4;
static uint64_t dest_timer;
static uint64_t get_timer_ms(void)
{
uint64_t clk;
asm volatile(" stck %0 " : : "Q"(clk) : "memory");
/* Bit 51 is incremented each microsecond */
return (clk >> (63 - 51)) / 1000;
}
void set_timer(int val)
{
dest_timer = get_timer_ms() + val;
}
int get_timer(void)
{
return dest_timer - get_timer_ms();
}
int get_sec_ticks(void)
{
return 1000; /* number of ticks in 1 second */
}
/**
* Obtain IP and configuration info from DHCP server (either IPv4 or IPv6).
* @param fn_ip contains the following configuration information:
* client MAC, client IP, TFTP-server MAC, TFTP-server IP,
* boot file name
* @param retries Number of DHCP attempts
* @return 0 : IP and configuration info obtained;
* non-0 : error condition occurred.
*/
static int dhcp(struct filename_ip *fn_ip, int retries)
{
int i = retries + 1;
int rc = -1;
printf(" Requesting information via DHCP: ");
dhcpv4_generate_transaction_id();
dhcpv6_generate_transaction_id();
do {
printf("\b\b\b%03d", i - 1);
if (!--i) {
printf("\nGiving up after %d DHCP requests\n", retries);
return -1;
}
ip_version = 4;
rc = dhcpv4(NULL, fn_ip);
if (rc == -1) {
ip_version = 6;
set_ipv6_address(fn_ip->fd, 0);
rc = dhcpv6(NULL, fn_ip);
if (rc == 0) {
memcpy(&fn_ip->own_ip6, get_ipv6_address(), 16);
break;
}
}
if (rc != -1) { /* either success or non-dhcp failure */
break;
}
} while (1);
printf("\b\b\b\bdone\n");
return rc;
}
/**
* Seed the random number generator with our mac and current timestamp
*/
static void seed_rng(uint8_t mac[])
{
uint64_t seed;
asm volatile(" stck %0 " : : "Q"(seed) : "memory");
seed ^= (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5];
srand(seed);
}
static int tftp_load(filename_ip_t *fnip, void *buffer, int len,
unsigned int retries, int ip_vers)
{
tftp_err_t tftp_err;
int rc;
rc = tftp(fnip, buffer, len, retries, &tftp_err, 1, 1428, ip_vers);
if (rc > 0) {
printf(" TFTP: Received %s (%d KBytes)\n", fnip->filename,
rc / 1024);
} else if (rc == -1) {
puts("unknown TFTP error");
} else if (rc == -2) {
printf("TFTP buffer of %d bytes is too small for %s\n",
len, fnip->filename);
} 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;
}
static int net_load(char *buffer, int len)
{
filename_ip_t fn_ip;
uint8_t mac[6];
int rc;
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;
printf(" Using MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
set_mac_address(mac); /* init ethernet layer */
seed_rng(mac);
rc = dhcp(&fn_ip, DEFAULT_BOOT_RETRIES);
if (rc >= 0) {
if (ip_version == 4) {
set_ipv4_address(fn_ip.own_ip);
}
} else {
puts("Could not get IP address");
return -101;
}
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);
} else if (ip_version == 6) {
char ip6_str[40];
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);
return -102;
}
if (rc == -4 || rc == -3) {
puts("Can't obtain TFTP server IP address");
return -107;
}
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);
} 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);
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);
}
return rc;
}
void panic(const char *string)
{
sclp_print(string);
for (;;) {
disabled_wait();
}
}
static bool find_net_dev(Schib *schib, int dev_no)
{
int i, r;
for (i = 0; i < 0x10000; i++) {
net_schid.sch_no = i;
r = stsch_err(net_schid, schib);
if (r == 3 || r == -EIO) {
break;
}
if (!schib->pmcw.dnv) {
continue;
}
if (!virtio_is_supported(net_schid)) {
continue;
}
if (virtio_get_device_type() != VIRTIO_ID_NET) {
continue;
}
if (dev_no < 0 || schib->pmcw.dev == dev_no) {
return true;
}
}
return false;
}
static void virtio_setup(void)
{
Schib schib;
int ssid;
bool found = false;
uint16_t dev_no;
/*
* We unconditionally enable mss support. In every sane configuration,
* this will succeed; and even if it doesn't, stsch_err() can deal
* with the consequences.
*/
enable_mss_facility();
if (store_iplb(&iplb)) {
IPL_assert(iplb.pbt == S390_IPL_TYPE_CCW, "IPL_TYPE_CCW expected");
dev_no = iplb.ccw.devno;
debug_print_int("device no. ", dev_no);
net_schid.ssid = iplb.ccw.ssid & 0x3;
debug_print_int("ssid ", net_schid.ssid);
found = find_net_dev(&schib, dev_no);
} else {
for (ssid = 0; ssid < 0x3; ssid++) {
net_schid.ssid = ssid;
found = find_net_dev(&schib, -1);
if (found) {
break;
}
}
}
IPL_assert(found, "No virtio net device found");
}
void main(void)
{
int rc;
sclp_setup();
sclp_print("Network boot starting...\n");
virtio_setup();
rc = net_load(NULL, (long)_start);
if (rc > 0) {
sclp_print("Network loading done, starting kernel...\n");
asm volatile (" lpsw 0(%0) " : : "r"(0) : "memory");
}
panic("Failed to load OS from network\n");
}

View file

@ -18,12 +18,6 @@ typedef unsigned short u16;
typedef unsigned int u32; typedef unsigned int u32;
typedef unsigned long long u64; typedef unsigned long long u64;
typedef unsigned long ulong; typedef unsigned long ulong;
typedef long size_t;
typedef int bool;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
typedef unsigned char __u8; typedef unsigned char __u8;
typedef unsigned short __u16; typedef unsigned short __u16;
typedef unsigned int __u32; typedef unsigned int __u32;
@ -50,6 +44,8 @@ typedef unsigned long long __u64;
((b) == 0 ? (a) : (MIN(a, b)))) ((b) == 0 ? (a) : (MIN(a, b))))
#endif #endif
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#include "cio.h" #include "cio.h"
#include "iplb.h" #include "iplb.h"
@ -80,7 +76,7 @@ void sclp_get_loadparm_ascii(char *loadparm);
unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2, unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2,
ulong subchan_id, void *load_addr); ulong subchan_id, void *load_addr);
bool virtio_is_supported(SubChannelId schid); bool virtio_is_supported(SubChannelId schid);
void virtio_setup_device(SubChannelId schid); void virtio_blk_setup_device(SubChannelId schid);
int virtio_read(ulong sector, void *load_addr); int virtio_read(ulong sector, void *load_addr);
int enable_mss_facility(void); int enable_mss_facility(void);
ulong get_second(void); ulong get_second(void);
@ -88,18 +84,6 @@ ulong get_second(void);
/* bootmap.c */ /* bootmap.c */
void zipl_load(void); void zipl_load(void);
static inline void *memset(void *s, int c, size_t n)
{
int i;
unsigned char *p = s;
for (i = 0; i < n; i++) {
p[i] = c;
}
return s;
}
static inline void fill_hex(char *out, unsigned char val) static inline void fill_hex(char *out, unsigned char val)
{ {
const char hex[] = "0123456789abcdef"; const char hex[] = "0123456789abcdef";
@ -169,17 +153,6 @@ static inline void sleep(unsigned int seconds)
} }
} }
static inline void *memcpy(void *s1, const void *s2, size_t n)
{
uint8_t *p1 = s1;
const uint8_t *p2 = s2;
while (n--) {
p1[n] = p2[n];
}
return s1;
}
static inline void IPL_assert(bool term, const char *message) static inline void IPL_assert(bool term, const char *message)
{ {
if (!term) { if (!term) {

View file

@ -8,11 +8,25 @@
* directory. * directory.
*/ */
#include "libc.h"
#include "s390-ccw.h" #include "s390-ccw.h"
#include "sclp.h" #include "sclp.h"
long write(int fd, const void *str, size_t len);
static char _sccb[PAGE_SIZE] __attribute__((__aligned__(4096))); static char _sccb[PAGE_SIZE] __attribute__((__aligned__(4096)));
const unsigned char ebc2asc[256] =
/* 0123456789abcdef0123456789abcdef */
"................................" /* 1F */
"................................" /* 3F */
" ...........<(+|&.........!$*);." /* 5F first.chr.here.is.real.space */
"-/.........,%_>?.........`:#@'=\""/* 7F */
".abcdefghi.......jklmnopqr......" /* 9F */
"..stuvwxyz......................" /* BF */
".ABCDEFGHI.......JKLMNOPQR......" /* DF */
"..STUVWXYZ......0123456789......";/* FF */
/* Perform service call. Return 0 on success, non-zero otherwise. */ /* Perform service call. Return 0 on success, non-zero otherwise. */
static int sclp_service_call(unsigned int command, void *sccb) static int sclp_service_call(unsigned int command, void *sccb)
{ {
@ -59,26 +73,29 @@ static int _strlen(const char *str)
return i; return i;
} }
static void _memcpy(char *dest, const char *src, int len) long write(int fd, const void *str, size_t len)
{ {
int i;
for (i = 0; i < len; i++)
dest[i] = src[i];
}
void sclp_print(const char *str)
{
int len = _strlen(str);
WriteEventData *sccb = (void *)_sccb; WriteEventData *sccb = (void *)_sccb;
if (fd != 1 && fd != 2) {
return -EIO;
}
sccb->h.length = sizeof(WriteEventData) + len; sccb->h.length = sizeof(WriteEventData) + len;
sccb->h.function_code = SCLP_FC_NORMAL_WRITE; sccb->h.function_code = SCLP_FC_NORMAL_WRITE;
sccb->ebh.length = sizeof(EventBufferHeader) + len; sccb->ebh.length = sizeof(EventBufferHeader) + len;
sccb->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA; sccb->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA;
sccb->ebh.flags = 0; sccb->ebh.flags = 0;
_memcpy(sccb->data, str, len); memcpy(sccb->data, str, len);
sclp_service_call(SCLP_CMD_WRITE_EVENT_DATA, sccb); sclp_service_call(SCLP_CMD_WRITE_EVENT_DATA, sccb);
return len;
}
void sclp_print(const char *str)
{
write(1, str, _strlen(str));
} }
void sclp_get_loadparm_ascii(char *loadparm) void sclp_get_loadparm_ascii(char *loadparm)

View file

@ -0,0 +1,296 @@
/*
* Virtio driver bits
*
* Copyright (c) 2013 Alexander Graf <agraf@suse.de>
*
* 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"
#include "virtio.h"
#include "virtio-scsi.h"
static int virtio_blk_read_many(VDev *vdev, ulong sector, void *load_addr,
int sec_num)
{
VirtioBlkOuthdr out_hdr;
u8 status;
VRing *vr = &vdev->vrings[vdev->cmd_vr_idx];
/* Tell the host we want to read */
out_hdr.type = VIRTIO_BLK_T_IN;
out_hdr.ioprio = 99;
out_hdr.sector = virtio_sector_adjust(sector);
vring_send_buf(vr, &out_hdr, sizeof(out_hdr), VRING_DESC_F_NEXT);
/* This is where we want to receive data */
vring_send_buf(vr, load_addr, virtio_get_block_size() * sec_num,
VRING_DESC_F_WRITE | VRING_HIDDEN_IS_CHAIN |
VRING_DESC_F_NEXT);
/* status field */
vring_send_buf(vr, &status, sizeof(u8),
VRING_DESC_F_WRITE | VRING_HIDDEN_IS_CHAIN);
/* Now we can tell the host to read */
vring_wait_reply();
if (drain_irqs(vr->schid)) {
/* Well, whatever status is supposed to contain... */
status = 1;
}
return status;
}
int virtio_read_many(ulong sector, void *load_addr, int sec_num)
{
VDev *vdev = virtio_get_device();
switch (vdev->senseid.cu_model) {
case VIRTIO_ID_BLOCK:
return virtio_blk_read_many(vdev, sector, load_addr, sec_num);
case VIRTIO_ID_SCSI:
return virtio_scsi_read_many(vdev, sector, load_addr, sec_num);
}
panic("\n! No readable IPL device !\n");
return -1;
}
unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2,
ulong subchan_id, void *load_addr)
{
u8 status;
int sec = rec_list1;
int sec_num = ((rec_list2 >> 32) & 0xffff) + 1;
int sec_len = rec_list2 >> 48;
ulong addr = (ulong)load_addr;
if (sec_len != virtio_get_block_size()) {
return -1;
}
sclp_print(".");
status = virtio_read_many(sec, (void *)addr, sec_num);
if (status) {
panic("I/O Error");
}
addr += sec_num * virtio_get_block_size();
return addr;
}
int virtio_read(ulong sector, void *load_addr)
{
return virtio_read_many(sector, load_addr, 1);
}
/*
* Other supported value pairs, if any, would need to be added here.
* Note: head count is always 15.
*/
static inline u8 virtio_eckd_sectors_for_block_size(int size)
{
switch (size) {
case 512:
return 49;
case 1024:
return 33;
case 2048:
return 21;
case 4096:
return 12;
}
return 0;
}
VirtioGDN virtio_guessed_disk_nature(void)
{
return virtio_get_device()->guessed_disk_nature;
}
void virtio_assume_scsi(void)
{
VDev *vdev = virtio_get_device();
switch (vdev->senseid.cu_model) {
case VIRTIO_ID_BLOCK:
vdev->guessed_disk_nature = VIRTIO_GDN_SCSI;
vdev->config.blk.blk_size = VIRTIO_SCSI_BLOCK_SIZE;
vdev->config.blk.physical_block_exp = 0;
vdev->blk_factor = 1;
break;
case VIRTIO_ID_SCSI:
vdev->scsi_block_size = VIRTIO_SCSI_BLOCK_SIZE;
break;
}
}
void virtio_assume_iso9660(void)
{
VDev *vdev = virtio_get_device();
switch (vdev->senseid.cu_model) {
case VIRTIO_ID_BLOCK:
vdev->guessed_disk_nature = VIRTIO_GDN_SCSI;
vdev->config.blk.blk_size = VIRTIO_ISO_BLOCK_SIZE;
vdev->config.blk.physical_block_exp = 0;
vdev->blk_factor = VIRTIO_ISO_BLOCK_SIZE / VIRTIO_SECTOR_SIZE;
break;
case VIRTIO_ID_SCSI:
vdev->scsi_block_size = VIRTIO_ISO_BLOCK_SIZE;
break;
}
}
void virtio_assume_eckd(void)
{
VDev *vdev = virtio_get_device();
vdev->guessed_disk_nature = VIRTIO_GDN_DASD;
vdev->blk_factor = 1;
vdev->config.blk.physical_block_exp = 0;
switch (vdev->senseid.cu_model) {
case VIRTIO_ID_BLOCK:
vdev->config.blk.blk_size = 4096;
break;
case VIRTIO_ID_SCSI:
vdev->config.blk.blk_size = vdev->scsi_block_size;
break;
}
vdev->config.blk.geometry.heads = 15;
vdev->config.blk.geometry.sectors =
virtio_eckd_sectors_for_block_size(vdev->config.blk.blk_size);
}
bool virtio_disk_is_scsi(void)
{
VDev *vdev = virtio_get_device();
if (vdev->guessed_disk_nature == VIRTIO_GDN_SCSI) {
return true;
}
switch (vdev->senseid.cu_model) {
case VIRTIO_ID_BLOCK:
return (vdev->config.blk.geometry.heads == 255)
&& (vdev->config.blk.geometry.sectors == 63)
&& (virtio_get_block_size() == VIRTIO_SCSI_BLOCK_SIZE);
case VIRTIO_ID_SCSI:
return true;
}
return false;
}
bool virtio_disk_is_eckd(void)
{
VDev *vdev = virtio_get_device();
const int block_size = virtio_get_block_size();
if (vdev->guessed_disk_nature == VIRTIO_GDN_DASD) {
return true;
}
switch (vdev->senseid.cu_model) {
case VIRTIO_ID_BLOCK:
return (vdev->config.blk.geometry.heads == 15)
&& (vdev->config.blk.geometry.sectors ==
virtio_eckd_sectors_for_block_size(block_size));
case VIRTIO_ID_SCSI:
return false;
}
return false;
}
bool virtio_ipl_disk_is_valid(void)
{
return virtio_disk_is_scsi() || virtio_disk_is_eckd();
}
int virtio_get_block_size(void)
{
VDev *vdev = virtio_get_device();
switch (vdev->senseid.cu_model) {
case VIRTIO_ID_BLOCK:
return vdev->config.blk.blk_size << vdev->config.blk.physical_block_exp;
case VIRTIO_ID_SCSI:
return vdev->scsi_block_size;
}
return 0;
}
uint8_t virtio_get_heads(void)
{
VDev *vdev = virtio_get_device();
switch (vdev->senseid.cu_model) {
case VIRTIO_ID_BLOCK:
return vdev->config.blk.geometry.heads;
case VIRTIO_ID_SCSI:
return vdev->guessed_disk_nature == VIRTIO_GDN_DASD
? vdev->config.blk.geometry.heads : 255;
}
return 0;
}
uint8_t virtio_get_sectors(void)
{
VDev *vdev = virtio_get_device();
switch (vdev->senseid.cu_model) {
case VIRTIO_ID_BLOCK:
return vdev->config.blk.geometry.sectors;
case VIRTIO_ID_SCSI:
return vdev->guessed_disk_nature == VIRTIO_GDN_DASD
? vdev->config.blk.geometry.sectors : 63;
}
return 0;
}
uint64_t virtio_get_blocks(void)
{
VDev *vdev = virtio_get_device();
const uint64_t factor = virtio_get_block_size() / VIRTIO_SECTOR_SIZE;
switch (vdev->senseid.cu_model) {
case VIRTIO_ID_BLOCK:
return vdev->config.blk.capacity / factor;
case VIRTIO_ID_SCSI:
return vdev->scsi_last_block / factor;
}
return 0;
}
void virtio_blk_setup_device(SubChannelId schid)
{
VDev *vdev = virtio_get_device();
vdev->schid = schid;
virtio_setup_ccw(vdev);
switch (vdev->senseid.cu_model) {
case VIRTIO_ID_BLOCK:
sclp_print("Using virtio-blk.\n");
if (!virtio_ipl_disk_is_valid()) {
/* make sure all getters but blocksize return 0 for
* invalid IPL disk
*/
memset(&vdev->config.blk, 0, sizeof(vdev->config.blk));
virtio_assume_scsi();
}
break;
case VIRTIO_ID_SCSI:
IPL_assert(vdev->config.scsi.sense_size == VIRTIO_SCSI_SENSE_SIZE,
"Config: sense size mismatch");
IPL_assert(vdev->config.scsi.cdb_size == VIRTIO_SCSI_CDB_SIZE,
"Config: CDB size mismatch");
sclp_print("Using virtio-scsi.\n");
virtio_scsi_setup(vdev);
break;
default:
panic("\n! No IPL device available !\n");
}
}

View file

@ -0,0 +1,135 @@
/*
* Virtio-net driver for the s390-ccw firmware
*
* Copyright 2017 Thomas Huth, Red Hat Inc.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <ethernet.h>
#include "s390-ccw.h"
#include "virtio.h"
#ifndef DEBUG_VIRTIO_NET
#define DEBUG_VIRTIO_NET 0
#endif
#define VIRTIO_NET_F_MAC_BIT (1 << 5)
#define VQ_RX 0 /* Receive queue */
#define VQ_TX 1 /* Transmit queue */
struct VirtioNetHdr {
uint8_t flags;
uint8_t gso_type;
uint16_t hdr_len;
uint16_t gso_size;
uint16_t csum_start;
uint16_t csum_offset;
/*uint16_t num_buffers;*/ /* Only with VIRTIO_NET_F_MRG_RXBUF or VIRTIO1 */
};
typedef struct VirtioNetHdr VirtioNetHdr;
static uint16_t rx_last_idx; /* Last index in receive queue "used" ring */
int virtio_net_init(void *mac_addr)
{
VDev *vdev = virtio_get_device();
VRing *rxvq = &vdev->vrings[VQ_RX];
void *buf;
int i;
vdev->guest_features[0] = VIRTIO_NET_F_MAC_BIT;
virtio_setup_ccw(vdev);
IPL_assert(vdev->guest_features[0] & VIRTIO_NET_F_MAC_BIT,
"virtio-net device does not support the MAC address feature");
memcpy(mac_addr, vdev->config.net.mac, ETH_ALEN);
for (i = 0; i < 64; i++) {
buf = malloc(ETH_MTU_SIZE + sizeof(VirtioNetHdr));
IPL_assert(buf != NULL, "Can not allocate memory for receive buffers");
vring_send_buf(rxvq, buf, ETH_MTU_SIZE + sizeof(VirtioNetHdr),
VRING_DESC_F_WRITE);
}
vring_notify(rxvq);
return 0;
}
int send(int fd, const void *buf, int len, int flags)
{
VirtioNetHdr tx_hdr;
VDev *vdev = virtio_get_device();
VRing *txvq = &vdev->vrings[VQ_TX];
/* Set up header - we do not use anything special, so simply clear it */
memset(&tx_hdr, 0, sizeof(tx_hdr));
vring_send_buf(txvq, &tx_hdr, sizeof(tx_hdr), VRING_DESC_F_NEXT);
vring_send_buf(txvq, (void *)buf, len, VRING_HIDDEN_IS_CHAIN);
while (!vr_poll(txvq)) {
yield();
}
if (drain_irqs(txvq->schid)) {
puts("send: drain irqs failed");
return -1;
}
return len;
}
int recv(int fd, void *buf, int maxlen, int flags)
{
VDev *vdev = virtio_get_device();
VRing *rxvq = &vdev->vrings[VQ_RX];
int len, id;
uint8_t *pkt;
if (rx_last_idx == rxvq->used->idx) {
return 0;
}
len = rxvq->used->ring[rx_last_idx % rxvq->num].len - sizeof(VirtioNetHdr);
if (len > maxlen) {
puts("virtio-net: Receive buffer too small");
len = maxlen;
}
id = rxvq->used->ring[rx_last_idx % rxvq->num].id % rxvq->num;
pkt = (uint8_t *)(rxvq->desc[id].addr + sizeof(VirtioNetHdr));
#if DEBUG_VIRTIO_NET /* Dump packet */
int i;
printf("\nbuf %p: len=%i\n", (void *)rxvq->desc[id].addr, len);
for (i = 0; i < 64; i++) {
printf(" %02x", pkt[i]);
if ((i % 16) == 15) {
printf("\n");
}
}
printf("\n");
#endif
/* Copy data to destination buffer */
memcpy(buf, pkt, len);
/* Mark buffer as available to the host again */
rxvq->avail->ring[rxvq->avail->idx % rxvq->num] = id;
rxvq->avail->idx = rxvq->avail->idx + 1;
vring_notify(rxvq);
/* Move index to next entry */
rx_last_idx = rx_last_idx + 1;
return len;
}

View file

@ -9,6 +9,7 @@
* directory. * directory.
*/ */
#include "libc.h"
#include "s390-ccw.h" #include "s390-ccw.h"
#include "virtio.h" #include "virtio.h"
#include "scsi.h" #include "scsi.h"

View file

@ -8,9 +8,11 @@
* directory. * directory.
*/ */
#include "libc.h"
#include "s390-ccw.h" #include "s390-ccw.h"
#include "virtio.h" #include "virtio.h"
#include "virtio-scsi.h" #include "virtio-scsi.h"
#include "bswap.h"
#define VRING_WAIT_REPLY_TIMEOUT 3 #define VRING_WAIT_REPLY_TIMEOUT 3
@ -69,7 +71,7 @@ static long virtio_notify(SubChannelId schid, int vq_idx, long cookie)
* Virtio functions * * Virtio functions *
***********************************************/ ***********************************************/
static int drain_irqs(SubChannelId schid) int drain_irqs(SubChannelId schid)
{ {
Irb irb = {}; Irb irb = {};
int r = 0; int r = 0;
@ -148,13 +150,13 @@ static void vring_init(VRing *vr, VqInfo *info)
debug_print_addr("init vr", vr); debug_print_addr("init vr", vr);
} }
static bool vring_notify(VRing *vr) bool vring_notify(VRing *vr)
{ {
vr->cookie = virtio_notify(vr->schid, vr->id, vr->cookie); vr->cookie = virtio_notify(vr->schid, vr->id, vr->cookie);
return vr->cookie >= 0; return vr->cookie >= 0;
} }
static void vring_send_buf(VRing *vr, void *p, int len, int flags) void vring_send_buf(VRing *vr, void *p, int len, int flags)
{ {
/* For follow-up chains we need to keep the first entry point */ /* For follow-up chains we need to keep the first entry point */
if (!(flags & VRING_HIDDEN_IS_CHAIN)) { if (!(flags & VRING_HIDDEN_IS_CHAIN)) {
@ -187,7 +189,7 @@ ulong get_second(void)
return (get_clock() >> 12) / 1000000; return (get_clock() >> 12) / 1000000;
} }
static int vr_poll(VRing *vr) int vr_poll(VRing *vr)
{ {
if (vr->used->idx == vr->used_idx) { if (vr->used->idx == vr->used_idx) {
vring_notify(vr); vring_notify(vr);
@ -209,7 +211,7 @@ static int vr_poll(VRing *vr)
* *
* Returns 0 on success, 1 on timeout. * Returns 0 on success, 1 on timeout.
*/ */
static int vring_wait_reply(void) int vring_wait_reply(void)
{ {
ulong target_second = get_second() + vdev.wait_reply_timeout; ulong target_second = get_second() + vdev.wait_reply_timeout;
@ -246,245 +248,14 @@ int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd)
return 0; return 0;
} }
/*********************************************** void virtio_setup_ccw(VDev *vdev)
* Virtio block *
***********************************************/
static int virtio_blk_read_many(VDev *vdev,
ulong sector, void *load_addr, int sec_num)
{ {
VirtioBlkOuthdr out_hdr; int i, rc, cfg_size = 0;
u8 status;
VRing *vr = &vdev->vrings[vdev->cmd_vr_idx];
/* Tell the host we want to read */
out_hdr.type = VIRTIO_BLK_T_IN;
out_hdr.ioprio = 99;
out_hdr.sector = virtio_sector_adjust(sector);
vring_send_buf(vr, &out_hdr, sizeof(out_hdr), VRING_DESC_F_NEXT);
/* This is where we want to receive data */
vring_send_buf(vr, load_addr, virtio_get_block_size() * sec_num,
VRING_DESC_F_WRITE | VRING_HIDDEN_IS_CHAIN |
VRING_DESC_F_NEXT);
/* status field */
vring_send_buf(vr, &status, sizeof(u8),
VRING_DESC_F_WRITE | VRING_HIDDEN_IS_CHAIN);
/* Now we can tell the host to read */
vring_wait_reply();
if (drain_irqs(vr->schid)) {
/* Well, whatever status is supposed to contain... */
status = 1;
}
return status;
}
int virtio_read_many(ulong sector, void *load_addr, int sec_num)
{
switch (vdev.senseid.cu_model) {
case VIRTIO_ID_BLOCK:
return virtio_blk_read_many(&vdev, sector, load_addr, sec_num);
case VIRTIO_ID_SCSI:
return virtio_scsi_read_many(&vdev, sector, load_addr, sec_num);
}
panic("\n! No readable IPL device !\n");
return -1;
}
unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2,
ulong subchan_id, void *load_addr)
{
u8 status;
int sec = rec_list1;
int sec_num = ((rec_list2 >> 32) & 0xffff) + 1;
int sec_len = rec_list2 >> 48;
ulong addr = (ulong)load_addr;
if (sec_len != virtio_get_block_size()) {
return -1;
}
sclp_print(".");
status = virtio_read_many(sec, (void *)addr, sec_num);
if (status) {
panic("I/O Error");
}
addr += sec_num * virtio_get_block_size();
return addr;
}
int virtio_read(ulong sector, void *load_addr)
{
return virtio_read_many(sector, load_addr, 1);
}
/*
* Other supported value pairs, if any, would need to be added here.
* Note: head count is always 15.
*/
static inline u8 virtio_eckd_sectors_for_block_size(int size)
{
switch (size) {
case 512:
return 49;
case 1024:
return 33;
case 2048:
return 21;
case 4096:
return 12;
}
return 0;
}
VirtioGDN virtio_guessed_disk_nature(void)
{
return vdev.guessed_disk_nature;
}
void virtio_assume_scsi(void)
{
switch (vdev.senseid.cu_model) {
case VIRTIO_ID_BLOCK:
vdev.guessed_disk_nature = VIRTIO_GDN_SCSI;
vdev.config.blk.blk_size = VIRTIO_SCSI_BLOCK_SIZE;
vdev.config.blk.physical_block_exp = 0;
vdev.blk_factor = 1;
break;
case VIRTIO_ID_SCSI:
vdev.scsi_block_size = VIRTIO_SCSI_BLOCK_SIZE;
break;
}
}
void virtio_assume_iso9660(void)
{
switch (vdev.senseid.cu_model) {
case VIRTIO_ID_BLOCK:
vdev.guessed_disk_nature = VIRTIO_GDN_SCSI;
vdev.config.blk.blk_size = VIRTIO_ISO_BLOCK_SIZE;
vdev.config.blk.physical_block_exp = 0;
vdev.blk_factor = VIRTIO_ISO_BLOCK_SIZE / VIRTIO_SECTOR_SIZE;
break;
case VIRTIO_ID_SCSI:
vdev.scsi_block_size = VIRTIO_ISO_BLOCK_SIZE;
break;
}
}
void virtio_assume_eckd(void)
{
vdev.guessed_disk_nature = VIRTIO_GDN_DASD;
vdev.blk_factor = 1;
vdev.config.blk.physical_block_exp = 0;
switch (vdev.senseid.cu_model) {
case VIRTIO_ID_BLOCK:
vdev.config.blk.blk_size = 4096;
break;
case VIRTIO_ID_SCSI:
vdev.config.blk.blk_size = vdev.scsi_block_size;
break;
}
vdev.config.blk.geometry.heads = 15;
vdev.config.blk.geometry.sectors =
virtio_eckd_sectors_for_block_size(vdev.config.blk.blk_size);
}
bool virtio_disk_is_scsi(void)
{
if (vdev.guessed_disk_nature == VIRTIO_GDN_SCSI) {
return true;
}
switch (vdev.senseid.cu_model) {
case VIRTIO_ID_BLOCK:
return (vdev.config.blk.geometry.heads == 255)
&& (vdev.config.blk.geometry.sectors == 63)
&& (virtio_get_block_size() == VIRTIO_SCSI_BLOCK_SIZE);
case VIRTIO_ID_SCSI:
return true;
}
return false;
}
bool virtio_disk_is_eckd(void)
{
const int block_size = virtio_get_block_size();
if (vdev.guessed_disk_nature == VIRTIO_GDN_DASD) {
return true;
}
switch (vdev.senseid.cu_model) {
case VIRTIO_ID_BLOCK:
return (vdev.config.blk.geometry.heads == 15)
&& (vdev.config.blk.geometry.sectors ==
virtio_eckd_sectors_for_block_size(block_size));
case VIRTIO_ID_SCSI:
return false;
}
return false;
}
bool virtio_ipl_disk_is_valid(void)
{
return virtio_disk_is_scsi() || virtio_disk_is_eckd();
}
int virtio_get_block_size(void)
{
switch (vdev.senseid.cu_model) {
case VIRTIO_ID_BLOCK:
return vdev.config.blk.blk_size << vdev.config.blk.physical_block_exp;
case VIRTIO_ID_SCSI:
return vdev.scsi_block_size;
}
return 0;
}
uint8_t virtio_get_heads(void)
{
switch (vdev.senseid.cu_model) {
case VIRTIO_ID_BLOCK:
return vdev.config.blk.geometry.heads;
case VIRTIO_ID_SCSI:
return vdev.guessed_disk_nature == VIRTIO_GDN_DASD
? vdev.config.blk.geometry.heads : 255;
}
return 0;
}
uint8_t virtio_get_sectors(void)
{
switch (vdev.senseid.cu_model) {
case VIRTIO_ID_BLOCK:
return vdev.config.blk.geometry.sectors;
case VIRTIO_ID_SCSI:
return vdev.guessed_disk_nature == VIRTIO_GDN_DASD
? vdev.config.blk.geometry.sectors : 63;
}
return 0;
}
uint64_t virtio_get_blocks(void)
{
const uint64_t factor = virtio_get_block_size() / VIRTIO_SECTOR_SIZE;
switch (vdev.senseid.cu_model) {
case VIRTIO_ID_BLOCK:
return vdev.config.blk.capacity / factor;
case VIRTIO_ID_SCSI:
return vdev.scsi_last_block / factor;
}
return 0;
}
static void virtio_setup_ccw(VDev *vdev)
{
int i, cfg_size = 0;
unsigned char status = VIRTIO_CONFIG_S_DRIVER_OK; unsigned char status = VIRTIO_CONFIG_S_DRIVER_OK;
struct VirtioFeatureDesc {
uint32_t features;
uint8_t index;
} __attribute__((packed)) feats;
IPL_assert(virtio_is_supported(vdev->schid), "PE"); IPL_assert(virtio_is_supported(vdev->schid), "PE");
/* device ID has been established now */ /* device ID has been established now */
@ -495,6 +266,11 @@ static void virtio_setup_ccw(VDev *vdev)
run_ccw(vdev, CCW_CMD_VDEV_RESET, NULL, 0); run_ccw(vdev, CCW_CMD_VDEV_RESET, NULL, 0);
switch (vdev->senseid.cu_model) { switch (vdev->senseid.cu_model) {
case VIRTIO_ID_NET:
vdev->nr_vqs = 2;
vdev->cmd_vr_idx = 0;
cfg_size = sizeof(vdev->config.net);
break;
case VIRTIO_ID_BLOCK: case VIRTIO_ID_BLOCK:
vdev->nr_vqs = 1; vdev->nr_vqs = 1;
vdev->cmd_vr_idx = 0; vdev->cmd_vr_idx = 0;
@ -511,11 +287,17 @@ static void virtio_setup_ccw(VDev *vdev)
IPL_assert(run_ccw(vdev, CCW_CMD_READ_CONF, &vdev->config, cfg_size) == 0, IPL_assert(run_ccw(vdev, CCW_CMD_READ_CONF, &vdev->config, cfg_size) == 0,
"Could not get block device configuration"); "Could not get block device configuration");
/* /* Feature negotiation */
* Skipping CCW_CMD_READ_FEAT. We're not doing anything fancy, and for (i = 0; i < ARRAY_SIZE(vdev->guest_features); i++) {
* we'll just stop dead anyway if anything does not work like we feats.features = 0;
* expect it. feats.index = i;
*/ rc = run_ccw(vdev, CCW_CMD_READ_FEAT, &feats, sizeof(feats));
IPL_assert(rc == 0, "Could not get features bits");
vdev->guest_features[i] &= bswap32(feats.features);
feats.features = bswap32(vdev->guest_features[i]);
rc = run_ccw(vdev, CCW_CMD_WRITE_FEAT, &feats, sizeof(feats));
IPL_assert(rc == 0, "Could not set features bits");
}
for (i = 0; i < vdev->nr_vqs; i++) { for (i = 0; i < vdev->nr_vqs; i++) {
VqInfo info = { VqInfo info = {
@ -543,36 +325,6 @@ static void virtio_setup_ccw(VDev *vdev)
"Could not write status to host"); "Could not write status to host");
} }
void virtio_setup_device(SubChannelId schid)
{
vdev.schid = schid;
virtio_setup_ccw(&vdev);
switch (vdev.senseid.cu_model) {
case VIRTIO_ID_BLOCK:
sclp_print("Using virtio-blk.\n");
if (!virtio_ipl_disk_is_valid()) {
/* make sure all getters but blocksize return 0 for
* invalid IPL disk
*/
memset(&vdev.config.blk, 0, sizeof(vdev.config.blk));
virtio_assume_scsi();
}
break;
case VIRTIO_ID_SCSI:
IPL_assert(vdev.config.scsi.sense_size == VIRTIO_SCSI_SENSE_SIZE,
"Config: sense size mismatch");
IPL_assert(vdev.config.scsi.cdb_size == VIRTIO_SCSI_CDB_SIZE,
"Config: CDB size mismatch");
sclp_print("Using virtio-scsi.\n");
virtio_scsi_setup(&vdev);
break;
default:
panic("\n! No IPL device available !\n");
}
}
bool virtio_is_supported(SubChannelId schid) bool virtio_is_supported(SubChannelId schid)
{ {
vdev.schid = schid; vdev.schid = schid;

View file

@ -11,8 +11,6 @@
#ifndef VIRTIO_H #ifndef VIRTIO_H
#define VIRTIO_H #define VIRTIO_H
#include "s390-ccw.h"
/* Status byte for guest to report progress, and synchronize features. */ /* Status byte for guest to report progress, and synchronize features. */
/* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */ /* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */
#define VIRTIO_CONFIG_S_ACKNOWLEDGE 1 #define VIRTIO_CONFIG_S_ACKNOWLEDGE 1
@ -32,24 +30,6 @@ enum VirtioDevType {
}; };
typedef enum VirtioDevType VirtioDevType; typedef enum VirtioDevType VirtioDevType;
struct VirtioDevHeader {
VirtioDevType type:8;
uint8_t num_vq;
uint8_t feature_len;
uint8_t config_len;
uint8_t status;
uint8_t vqconfig[];
} __attribute__((packed));
typedef struct VirtioDevHeader VirtioDevHeader;
struct VirtioVqConfig {
uint64_t token;
uint64_t address;
uint16_t num;
uint8_t pad[6];
} __attribute__((packed));
typedef struct VirtioVqConfig VirtioVqConfig;
struct VqInfo { struct VqInfo {
uint64_t queue; uint64_t queue;
uint32_t align; uint32_t align;
@ -64,15 +44,6 @@ struct VqConfig {
} __attribute__((packed)); } __attribute__((packed));
typedef struct VqConfig VqConfig; typedef struct VqConfig VqConfig;
struct VirtioDev {
VirtioDevHeader *header;
VirtioVqConfig *vqconfig;
char *host_features;
char *guest_features;
char *config;
};
typedef struct VirtioDev VirtioDev;
#define VIRTIO_RING_SIZE (PAGE_SIZE * 8) #define VIRTIO_RING_SIZE (PAGE_SIZE * 8)
#define VIRTIO_MAX_VQS 3 #define VIRTIO_MAX_VQS 3
#define KVM_S390_VIRTIO_RING_ALIGN 4096 #define KVM_S390_VIRTIO_RING_ALIGN 4096
@ -254,6 +225,13 @@ struct ScsiDevice {
}; };
typedef struct ScsiDevice ScsiDevice; typedef struct ScsiDevice ScsiDevice;
struct VirtioNetConfig {
uint8_t mac[6];
/* uint16_t status; */ /* Only with VIRTIO_NET_F_STATUS */
/* uint16_t max_virtqueue_pairs; */ /* Only with VIRTIO_NET_F_MQ */
};
typedef struct VirtioNetConfig VirtioNetConfig;
struct VDev { struct VDev {
int nr_vqs; int nr_vqs;
VRing *vrings; VRing *vrings;
@ -266,6 +244,7 @@ struct VDev {
union { union {
VirtioBlkConfig blk; VirtioBlkConfig blk;
VirtioScsiConfig scsi; VirtioScsiConfig scsi;
VirtioNetConfig net;
} config; } config;
ScsiDevice *scsi_device; ScsiDevice *scsi_device;
bool is_cdrom; bool is_cdrom;
@ -278,6 +257,7 @@ struct VDev {
ScsiDevice selected_scsi_device; ScsiDevice selected_scsi_device;
uint64_t netboot_start_addr; uint64_t netboot_start_addr;
uint32_t max_transfer; uint32_t max_transfer;
uint32_t guest_features[2];
}; };
typedef struct VDev VDev; typedef struct VDev VDev;
@ -291,6 +271,14 @@ struct VirtioCmd {
}; };
typedef struct VirtioCmd VirtioCmd; typedef struct VirtioCmd VirtioCmd;
bool vring_notify(VRing *vr);
int drain_irqs(SubChannelId schid);
void vring_send_buf(VRing *vr, void *p, int len, int flags);
int vr_poll(VRing *vr);
int vring_wait_reply(void);
int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd); int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd);
void virtio_setup_ccw(VDev *vdev);
int virtio_net_init(void *mac_addr);
#endif /* VIRTIO_H */ #endif /* VIRTIO_H */

BIN
pc-bios/s390-netboot.img Executable file

Binary file not shown.

@ -1 +1 @@
Subproject commit 66d250ef0fd06bb88b7399b9563b5008201f2d63 Subproject commit 834113a1c67d6fb53dea153c3313d182238f2d36

View file

@ -57,6 +57,12 @@ struct S390xElfVregsHiStruct {
typedef struct S390xElfVregsHiStruct S390xElfVregsHi; typedef struct S390xElfVregsHiStruct S390xElfVregsHi;
struct S390xElfGSCBStruct {
uint64_t gsregs[4];
} QEMU_PACKED;
typedef struct S390xElfGSCBStruct S390xElfGSCB;
typedef struct noteStruct { typedef struct noteStruct {
Elf64_Nhdr hdr; Elf64_Nhdr hdr;
char name[8]; char name[8];
@ -65,6 +71,7 @@ typedef struct noteStruct {
S390xElfFpregset fpregset; S390xElfFpregset fpregset;
S390xElfVregsLo vregslo; S390xElfVregsLo vregslo;
S390xElfVregsHi vregshi; S390xElfVregsHi vregshi;
S390xElfGSCB gscb;
uint32_t prefix; uint32_t prefix;
uint64_t timer; uint64_t timer;
uint64_t todcmp; uint64_t todcmp;
@ -126,6 +133,16 @@ static void s390x_write_elf64_vregshi(Note *note, S390CPU *cpu, int id)
} }
} }
static void s390x_write_elf64_gscb(Note *note, S390CPU *cpu, int id)
{
int i;
note->hdr.n_type = cpu_to_be32(NT_S390_GS_CB);
for (i = 0; i < 4; i++) {
note->contents.gscb.gsregs[i] = cpu_to_be64(cpu->env.gscb[i]);
}
}
static void s390x_write_elf64_timer(Note *note, S390CPU *cpu, int id) static void s390x_write_elf64_timer(Note *note, S390CPU *cpu, int id)
{ {
note->hdr.n_type = cpu_to_be32(NT_S390_TIMER); note->hdr.n_type = cpu_to_be32(NT_S390_TIMER);
@ -181,6 +198,7 @@ static const NoteFuncDesc note_linux[] = {
{sizeof(((Note *)0)->contents.todpreg), s390x_write_elf64_todpreg}, {sizeof(((Note *)0)->contents.todpreg), s390x_write_elf64_todpreg},
{sizeof(((Note *)0)->contents.vregslo), s390x_write_elf64_vregslo}, {sizeof(((Note *)0)->contents.vregslo), s390x_write_elf64_vregslo},
{sizeof(((Note *)0)->contents.vregshi), s390x_write_elf64_vregshi}, {sizeof(((Note *)0)->contents.vregshi), s390x_write_elf64_vregshi},
{sizeof(((Note *)0)->contents.gscb), s390x_write_elf64_gscb},
{ 0, NULL} { 0, NULL}
}; };

View file

@ -89,6 +89,7 @@ typedef struct CPUS390XState {
CPU_DoubleU vregs[32][2]; /* vector registers */ CPU_DoubleU vregs[32][2]; /* vector registers */
uint32_t aregs[16]; /* access registers */ uint32_t aregs[16]; /* access registers */
uint8_t riccb[64]; /* runtime instrumentation control */ uint8_t riccb[64]; /* runtime instrumentation control */
uint64_t gscb[4]; /* guarded storage control */
/* Fields up to this point are not cleared by initial CPU reset */ /* Fields up to this point are not cleared by initial CPU reset */
struct {} start_initial_reset_fields; struct {} start_initial_reset_fields;
@ -1158,6 +1159,7 @@ int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch,
int vq, bool assign); int vq, bool assign);
int kvm_s390_cpu_restart(S390CPU *cpu); int kvm_s390_cpu_restart(S390CPU *cpu);
int kvm_s390_get_memslot_count(KVMState *s); int kvm_s390_get_memslot_count(KVMState *s);
int kvm_s390_cmma_active(void);
void kvm_s390_cmma_reset(void); void kvm_s390_cmma_reset(void);
int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state); int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state);
void kvm_s390_reset_vcpu(S390CPU *cpu); void kvm_s390_reset_vcpu(S390CPU *cpu);
@ -1165,6 +1167,7 @@ int kvm_s390_set_mem_limit(KVMState *s, uint64_t new_limit, uint64_t *hw_limit);
void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu); void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu);
int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu); int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu);
int kvm_s390_get_ri(void); int kvm_s390_get_ri(void);
int kvm_s390_get_gs(void);
void kvm_s390_crypto_reset(void); void kvm_s390_crypto_reset(void);
#else #else
static inline void kvm_s390_io_interrupt(uint16_t subchannel_id, static inline void kvm_s390_io_interrupt(uint16_t subchannel_id,
@ -1219,6 +1222,10 @@ static inline int kvm_s390_get_ri(void)
{ {
return 0; return 0;
} }
static inline int kvm_s390_get_gs(void)
{
return 0;
}
static inline void kvm_s390_crypto_reset(void) static inline void kvm_s390_crypto_reset(void)
{ {
} }
@ -1327,6 +1334,7 @@ static inline bool s390_get_squash_mcss(void)
#define MCIC_VB_CR 0x0000000400000000ULL #define MCIC_VB_CR 0x0000000400000000ULL
#define MCIC_VB_ST 0x0000000100000000ULL #define MCIC_VB_ST 0x0000000100000000ULL
#define MCIC_VB_AR 0x0000000040000000ULL #define MCIC_VB_AR 0x0000000040000000ULL
#define MCIC_VB_GS 0x0000000008000000ULL
#define MCIC_VB_PR 0x0000000000200000ULL #define MCIC_VB_PR 0x0000000000200000ULL
#define MCIC_VB_FC 0x0000000000100000ULL #define MCIC_VB_FC 0x0000000000100000ULL
#define MCIC_VB_CT 0x0000000000020000ULL #define MCIC_VB_CT 0x0000000000020000ULL

View file

@ -59,6 +59,7 @@ static const S390FeatDef s390_features[] = {
FEAT_INIT("exrl", S390_FEAT_TYPE_STFL, 35, "Execute-extensions facility"), FEAT_INIT("exrl", S390_FEAT_TYPE_STFL, 35, "Execute-extensions facility"),
FEAT_INIT("emon", S390_FEAT_TYPE_STFL, 36, "Enhanced-monitor facility"), FEAT_INIT("emon", S390_FEAT_TYPE_STFL, 36, "Enhanced-monitor facility"),
FEAT_INIT("fpe", S390_FEAT_TYPE_STFL, 37, "Floating-point extension facility"), FEAT_INIT("fpe", S390_FEAT_TYPE_STFL, 37, "Floating-point extension facility"),
FEAT_INIT("opc", S390_FEAT_TYPE_STFL, 38, "Order Preserving Compression facility"),
FEAT_INIT("sprogp", S390_FEAT_TYPE_STFL, 40, "Set-program-parameters facility"), FEAT_INIT("sprogp", S390_FEAT_TYPE_STFL, 40, "Set-program-parameters facility"),
FEAT_INIT("fpseh", S390_FEAT_TYPE_STFL, 41, "Floating-point-support-enhancement facilities"), FEAT_INIT("fpseh", S390_FEAT_TYPE_STFL, 41, "Floating-point-support-enhancement facilities"),
FEAT_INIT("dfp", S390_FEAT_TYPE_STFL, 42, "DFP (decimal-floating-point) facility"), FEAT_INIT("dfp", S390_FEAT_TYPE_STFL, 42, "DFP (decimal-floating-point) facility"),
@ -72,8 +73,15 @@ static const S390FeatDef s390_features[] = {
FEAT_INIT("ltlbc", S390_FEAT_TYPE_STFL, 51, "Local-TLB-clearing facility"), FEAT_INIT("ltlbc", S390_FEAT_TYPE_STFL, 51, "Local-TLB-clearing facility"),
FEAT_INIT("iacc2", S390_FEAT_TYPE_STFL, 52, "Interlocked-access facility 2"), FEAT_INIT("iacc2", S390_FEAT_TYPE_STFL, 52, "Interlocked-access facility 2"),
FEAT_INIT("stfle53", S390_FEAT_TYPE_STFL, 53, "Various facilities introduced with z13"), FEAT_INIT("stfle53", S390_FEAT_TYPE_STFL, 53, "Various facilities introduced with z13"),
FEAT_INIT("eec", S390_FEAT_TYPE_STFL, 54, "Entropy encoding compression facility"),
FEAT_INIT("msa5-base", S390_FEAT_TYPE_STFL, 57, "Message-security-assist-extension-5 facility (excluding subfunctions)"), FEAT_INIT("msa5-base", S390_FEAT_TYPE_STFL, 57, "Message-security-assist-extension-5 facility (excluding subfunctions)"),
FEAT_INIT("minste2", S390_FEAT_TYPE_STFL, 58, "Miscellaneous-instruction-extensions facility 2"),
FEAT_INIT("sema", S390_FEAT_TYPE_STFL, 59, "Semaphore-assist facility"),
FEAT_INIT("tsi", S390_FEAT_TYPE_STFL, 60, "Time-slice Instrumentation facility"),
FEAT_INIT("ri", S390_FEAT_TYPE_STFL, 64, "CPU runtime-instrumentation facility"), FEAT_INIT("ri", S390_FEAT_TYPE_STFL, 64, "CPU runtime-instrumentation facility"),
FEAT_INIT("zpci", S390_FEAT_TYPE_STFL, 69, "z/PCI facility"),
FEAT_INIT("aen", S390_FEAT_TYPE_STFL, 71, "General-purpose-adapter-event-notification facility"),
FEAT_INIT("ais", S390_FEAT_TYPE_STFL, 72, "General-purpose-adapter-interruption-suppression facility"),
FEAT_INIT("te", S390_FEAT_TYPE_STFL, 73, "Transactional-execution facility"), FEAT_INIT("te", S390_FEAT_TYPE_STFL, 73, "Transactional-execution facility"),
FEAT_INIT("sthyi", S390_FEAT_TYPE_STFL, 74, "Store-hypervisor-information facility"), FEAT_INIT("sthyi", S390_FEAT_TYPE_STFL, 74, "Store-hypervisor-information facility"),
FEAT_INIT("aefsi", S390_FEAT_TYPE_STFL, 75, "Access-exception-fetch/store-indication facility"), FEAT_INIT("aefsi", S390_FEAT_TYPE_STFL, 75, "Access-exception-fetch/store-indication facility"),
@ -82,10 +90,24 @@ static const S390FeatDef s390_features[] = {
FEAT_INIT("edat2", S390_FEAT_TYPE_STFL, 78, "Enhanced-DAT facility 2"), FEAT_INIT("edat2", S390_FEAT_TYPE_STFL, 78, "Enhanced-DAT facility 2"),
FEAT_INIT("dfppc", S390_FEAT_TYPE_STFL, 80, "Decimal-floating-point packed-conversion facility"), FEAT_INIT("dfppc", S390_FEAT_TYPE_STFL, 80, "Decimal-floating-point packed-conversion facility"),
FEAT_INIT("vx", S390_FEAT_TYPE_STFL, 129, "Vector facility"), FEAT_INIT("vx", S390_FEAT_TYPE_STFL, 129, "Vector facility"),
FEAT_INIT("iep", S390_FEAT_TYPE_STFL, 130, "Instruction-execution-protection facility"),
FEAT_INIT("sea_esop2", S390_FEAT_TYPE_STFL, 131, "Side-effect-access facility and Enhanced-suppression-on-protection facility 2"),
FEAT_INIT("gs", S390_FEAT_TYPE_STFL, 133, "Guarded-storage facility"),
FEAT_INIT("vxpd", S390_FEAT_TYPE_STFL, 134, "Vector packed decimal facility"),
FEAT_INIT("vxeh", S390_FEAT_TYPE_STFL, 135, "Vector enhancements facility"),
FEAT_INIT("mepoch", S390_FEAT_TYPE_STFL, 139, "Multiple-epoch facility"),
FEAT_INIT("tpei", S390_FEAT_TYPE_STFL, 144, "Test-pending-external-interruption facility"),
FEAT_INIT("irbm", S390_FEAT_TYPE_STFL, 145, "Insert-reference-bits-multiple facility"),
FEAT_INIT("msa8-base", S390_FEAT_TYPE_STFL, 146, "Message-security-assist-extension-8 facility (excluding subfunctions)"),
FEAT_INIT("cmmnt", S390_FEAT_TYPE_STFL, 147, "CMM: ESSA-enhancement (no translate) facility"),
/* SCLP SCCB Byte 80 - 98 (bit numbers relative to byte-80) */
FEAT_INIT("gsls", S390_FEAT_TYPE_SCLP_CONF_CHAR, 40, "SIE: Guest-storage-limit-suppression facility"), FEAT_INIT("gsls", S390_FEAT_TYPE_SCLP_CONF_CHAR, 40, "SIE: Guest-storage-limit-suppression facility"),
FEAT_INIT("esop", S390_FEAT_TYPE_SCLP_CONF_CHAR, 46, "Enhanced-suppression-on-protection facility"), FEAT_INIT("esop", S390_FEAT_TYPE_SCLP_CONF_CHAR, 46, "Enhanced-suppression-on-protection facility"),
FEAT_INIT("hpma2", S390_FEAT_TYPE_SCLP_CONF_CHAR, 90, "Host page management assist 2 Facility"), /* 91-2 */
FEAT_INIT("kss", S390_FEAT_TYPE_SCLP_CONF_CHAR, 151, "SIE: Keyless-subset facility"), /* 98-7 */
/* SCLP SCCB Byte 116 - 119 (bit numbers relative to byte-116) */
FEAT_INIT("64bscao", S390_FEAT_TYPE_SCLP_CONF_CHAR_EXT, 0, "SIE: 64-bit-SCAO facility"), FEAT_INIT("64bscao", S390_FEAT_TYPE_SCLP_CONF_CHAR_EXT, 0, "SIE: 64-bit-SCAO facility"),
FEAT_INIT("cmma", S390_FEAT_TYPE_SCLP_CONF_CHAR_EXT, 1, "SIE: Collaborative-memory-management assist"), FEAT_INIT("cmma", S390_FEAT_TYPE_SCLP_CONF_CHAR_EXT, 1, "SIE: Collaborative-memory-management assist"),
FEAT_INIT("pfmfi", S390_FEAT_TYPE_SCLP_CONF_CHAR_EXT, 9, "SIE: PFMF interpretation facility"), FEAT_INIT("pfmfi", S390_FEAT_TYPE_SCLP_CONF_CHAR_EXT, 9, "SIE: PFMF interpretation facility"),
@ -182,10 +204,23 @@ static const S390FeatDef s390_features[] = {
FEAT_INIT("kimd-sha-1", S390_FEAT_TYPE_KIMD, 1, "KIMD SHA-1"), FEAT_INIT("kimd-sha-1", S390_FEAT_TYPE_KIMD, 1, "KIMD SHA-1"),
FEAT_INIT("kimd-sha-256", S390_FEAT_TYPE_KIMD, 2, "KIMD SHA-256"), FEAT_INIT("kimd-sha-256", S390_FEAT_TYPE_KIMD, 2, "KIMD SHA-256"),
FEAT_INIT("kimd-sha-512", S390_FEAT_TYPE_KIMD, 3, "KIMD SHA-512"), FEAT_INIT("kimd-sha-512", S390_FEAT_TYPE_KIMD, 3, "KIMD SHA-512"),
FEAT_INIT("kimd-sha3-224", S390_FEAT_TYPE_KIMD, 32, "KIMD SHA3-224"),
FEAT_INIT("kimd-sha3-256", S390_FEAT_TYPE_KIMD, 33, "KIMD SHA3-256"),
FEAT_INIT("kimd-sha3-384", S390_FEAT_TYPE_KIMD, 34, "KIMD SHA3-384"),
FEAT_INIT("kimd-sha3-512", S390_FEAT_TYPE_KIMD, 35, "KIMD SHA3-512"),
FEAT_INIT("kimd-shake-128", S390_FEAT_TYPE_KIMD, 36, "KIMD SHAKE-128"),
FEAT_INIT("kimd-shake-256", S390_FEAT_TYPE_KIMD, 37, "KIMD SHAKE-256"),
FEAT_INIT("kimd-ghash", S390_FEAT_TYPE_KIMD, 65, "KIMD GHASH"), FEAT_INIT("kimd-ghash", S390_FEAT_TYPE_KIMD, 65, "KIMD GHASH"),
FEAT_INIT("klmd-sha-1", S390_FEAT_TYPE_KLMD, 1, "KLMD SHA-1"), FEAT_INIT("klmd-sha-1", S390_FEAT_TYPE_KLMD, 1, "KLMD SHA-1"),
FEAT_INIT("klmd-sha-256", S390_FEAT_TYPE_KLMD, 2, "KLMD SHA-256"), FEAT_INIT("klmd-sha-256", S390_FEAT_TYPE_KLMD, 2, "KLMD SHA-256"),
FEAT_INIT("klmd-sha-512", S390_FEAT_TYPE_KLMD, 3, "KLMD SHA-512"), FEAT_INIT("klmd-sha-512", S390_FEAT_TYPE_KLMD, 3, "KLMD SHA-512"),
FEAT_INIT("klmd-sha3-224", S390_FEAT_TYPE_KLMD, 32, "KLMD SHA3-224"),
FEAT_INIT("klmd-sha3-256", S390_FEAT_TYPE_KLMD, 33, "KLMD SHA3-256"),
FEAT_INIT("klmd-sha3-384", S390_FEAT_TYPE_KLMD, 34, "KLMD SHA3-384"),
FEAT_INIT("klmd-sha3-512", S390_FEAT_TYPE_KLMD, 35, "KLMD SHA3-512"),
FEAT_INIT("klmd-shake-128", S390_FEAT_TYPE_KLMD, 36, "KLMD SHAKE-128"),
FEAT_INIT("klmd-shake-256", S390_FEAT_TYPE_KLMD, 37, "KLMD SHAKE-256"),
FEAT_INIT("pckmo-edea", S390_FEAT_TYPE_PCKMO, 1, "PCKMO Encrypted-DEA-Key"), FEAT_INIT("pckmo-edea", S390_FEAT_TYPE_PCKMO, 1, "PCKMO Encrypted-DEA-Key"),
FEAT_INIT("pckmo-etdea-128", S390_FEAT_TYPE_PCKMO, 2, "PCKMO Encrypted-TDEA-128-Key"), FEAT_INIT("pckmo-etdea-128", S390_FEAT_TYPE_PCKMO, 2, "PCKMO Encrypted-TDEA-128-Key"),
@ -251,6 +286,15 @@ static const S390FeatDef s390_features[] = {
FEAT_INIT("pcc-xts-eaes-256", S390_FEAT_TYPE_PCC, 60, "PCC Compute-XTS-Parameter-Using-Encrypted-AES-256"), FEAT_INIT("pcc-xts-eaes-256", S390_FEAT_TYPE_PCC, 60, "PCC Compute-XTS-Parameter-Using-Encrypted-AES-256"),
FEAT_INIT("ppno-sha-512-drng", S390_FEAT_TYPE_PPNO, 3, "PPNO SHA-512-DRNG"), FEAT_INIT("ppno-sha-512-drng", S390_FEAT_TYPE_PPNO, 3, "PPNO SHA-512-DRNG"),
FEAT_INIT("prno-trng-qrtcr", S390_FEAT_TYPE_PPNO, 112, "PRNO TRNG-Query-Raw-to-Conditioned-Ratio"),
FEAT_INIT("prno-trng", S390_FEAT_TYPE_PPNO, 114, "PRNO TRNG"),
FEAT_INIT("kma-gcm-aes-128", S390_FEAT_TYPE_KMA, 18, "KMA GCM-AES-128"),
FEAT_INIT("kma-gcm-aes-192", S390_FEAT_TYPE_KMA, 19, "KMA GCM-AES-192"),
FEAT_INIT("kma-gcm-aes-256", S390_FEAT_TYPE_KMA, 20, "KMA GCM-AES-256"),
FEAT_INIT("kma-gcm-eaes-128", S390_FEAT_TYPE_KMA, 26, "KMA GCM-Encrypted-AES-128"),
FEAT_INIT("kma-gcm-eaes-192", S390_FEAT_TYPE_KMA, 27, "KMA GCM-Encrypted-AES-192"),
FEAT_INIT("kma-gcm-eaes-256", S390_FEAT_TYPE_KMA, 28, "KMA GCM-Encrypted-AES-256"),
}; };
const S390FeatDef *s390_feat_def(S390Feat feat) const S390FeatDef *s390_feat_def(S390Feat feat)
@ -293,8 +337,9 @@ void s390_fill_feat_block(const S390FeatBitmap features, S390FeatType type,
int bit_nr; int bit_nr;
if (type == S390_FEAT_TYPE_STFL && test_bit(S390_FEAT_ZARCH, features)) { if (type == S390_FEAT_TYPE_STFL && test_bit(S390_FEAT_ZARCH, features)) {
/* z/Architecture is always active if around */ /* Features that are always active */
data[0] |= 0x20; data[0] |= 0x20; /* z/Architecture */
data[17] |= 0x20; /* Configuration-z-architectural-mode */
} }
feat = find_first_bit(features, S390_FEAT_MAX); feat = find_first_bit(features, S390_FEAT_MAX);
@ -383,6 +428,9 @@ static S390FeatGroupDef s390_feature_groups[] = {
FEAT_GROUP_INIT("msa3", MSA_EXT_3, "Message-security-assist-extension 3 facility"), FEAT_GROUP_INIT("msa3", MSA_EXT_3, "Message-security-assist-extension 3 facility"),
FEAT_GROUP_INIT("msa4", MSA_EXT_4, "Message-security-assist-extension 4 facility"), FEAT_GROUP_INIT("msa4", MSA_EXT_4, "Message-security-assist-extension 4 facility"),
FEAT_GROUP_INIT("msa5", MSA_EXT_5, "Message-security-assist-extension 5 facility"), FEAT_GROUP_INIT("msa5", MSA_EXT_5, "Message-security-assist-extension 5 facility"),
FEAT_GROUP_INIT("msa6", MSA_EXT_6, "Message-security-assist-extension 6 facility"),
FEAT_GROUP_INIT("msa7", MSA_EXT_7, "Message-security-assist-extension 7 facility"),
FEAT_GROUP_INIT("msa8", MSA_EXT_8, "Message-security-assist-extension 8 facility"),
}; };
const S390FeatGroupDef *s390_feat_group_def(S390FeatGroup group) const S390FeatGroupDef *s390_feat_group_def(S390FeatGroup group)

View file

@ -37,6 +37,7 @@ typedef enum {
S390_FEAT_TYPE_KMO, S390_FEAT_TYPE_KMO,
S390_FEAT_TYPE_PCC, S390_FEAT_TYPE_PCC,
S390_FEAT_TYPE_PPNO, S390_FEAT_TYPE_PPNO,
S390_FEAT_TYPE_KMA,
} S390FeatType; } S390FeatType;
/* Definition of a CPU feature */ /* Definition of a CPU feature */
@ -74,6 +75,9 @@ typedef enum {
S390_FEAT_GROUP_MSA_EXT_3, S390_FEAT_GROUP_MSA_EXT_3,
S390_FEAT_GROUP_MSA_EXT_4, S390_FEAT_GROUP_MSA_EXT_4,
S390_FEAT_GROUP_MSA_EXT_5, S390_FEAT_GROUP_MSA_EXT_5,
S390_FEAT_GROUP_MSA_EXT_6,
S390_FEAT_GROUP_MSA_EXT_7,
S390_FEAT_GROUP_MSA_EXT_8,
S390_FEAT_GROUP_MAX, S390_FEAT_GROUP_MAX,
} S390FeatGroup; } S390FeatGroup;

View file

@ -15,6 +15,7 @@
#define TARGET_S390X_CPU_FEATURES_DEF_H #define TARGET_S390X_CPU_FEATURES_DEF_H
typedef enum { typedef enum {
/* Stfle */
S390_FEAT_ESAN3 = 0, S390_FEAT_ESAN3 = 0,
S390_FEAT_ZARCH, S390_FEAT_ZARCH,
S390_FEAT_DAT_ENH, S390_FEAT_DAT_ENH,
@ -49,6 +50,7 @@ typedef enum {
S390_FEAT_EXECUTE_EXT, S390_FEAT_EXECUTE_EXT,
S390_FEAT_ENHANCED_MONITOR, S390_FEAT_ENHANCED_MONITOR,
S390_FEAT_FLOATING_POINT_EXT, S390_FEAT_FLOATING_POINT_EXT,
S390_FEAT_ORDER_PRESERVING_COMPRESSION,
S390_FEAT_SET_PROGRAM_PARAMETERS, S390_FEAT_SET_PROGRAM_PARAMETERS,
S390_FEAT_FLOATING_POINT_SUPPPORT_ENH, S390_FEAT_FLOATING_POINT_SUPPPORT_ENH,
S390_FEAT_DFP, S390_FEAT_DFP,
@ -62,8 +64,15 @@ typedef enum {
S390_FEAT_LOCAL_TLB_CLEARING, S390_FEAT_LOCAL_TLB_CLEARING,
S390_FEAT_INTERLOCKED_ACCESS_2, S390_FEAT_INTERLOCKED_ACCESS_2,
S390_FEAT_STFLE_53, S390_FEAT_STFLE_53,
S390_FEAT_ENTROPY_ENC_COMP,
S390_FEAT_MSA_EXT_5, S390_FEAT_MSA_EXT_5,
S390_FEAT_MISC_INSTRUCTION_EXT,
S390_FEAT_SEMAPHORE_ASSIST,
S390_FEAT_TIME_SLICE_INSTRUMENTATION,
S390_FEAT_RUNTIME_INSTRUMENTATION, S390_FEAT_RUNTIME_INSTRUMENTATION,
S390_FEAT_ZPCI,
S390_FEAT_ADAPTER_EVENT_NOTIFICATION,
S390_FEAT_ADAPTER_INT_SUPPRESSION,
S390_FEAT_TRANSACTIONAL_EXE, S390_FEAT_TRANSACTIONAL_EXE,
S390_FEAT_STORE_HYPERVISOR_INFO, S390_FEAT_STORE_HYPERVISOR_INFO,
S390_FEAT_ACCESS_EXCEPTION_FS_INDICATION, S390_FEAT_ACCESS_EXCEPTION_FS_INDICATION,
@ -72,12 +81,30 @@ typedef enum {
S390_FEAT_EDAT_2, S390_FEAT_EDAT_2,
S390_FEAT_DFP_PACKED_CONVERSION, S390_FEAT_DFP_PACKED_CONVERSION,
S390_FEAT_VECTOR, S390_FEAT_VECTOR,
S390_FEAT_INSTRUCTION_EXEC_PROT,
S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2,
S390_FEAT_GUARDED_STORAGE,
S390_FEAT_VECTOR_PACKED_DECIMAL,
S390_FEAT_VECTOR_ENH,
S390_FEAT_MULTIPLE_EPOCH,
S390_FEAT_TEST_PENDING_EXT_INTERRUPTION,
S390_FEAT_INSERT_REFERENCE_BITS_MULT,
S390_FEAT_MSA_EXT_8,
S390_FEAT_CMM_NT,
/* Sclp Conf Char */
S390_FEAT_SIE_GSLS, S390_FEAT_SIE_GSLS,
S390_FEAT_ESOP, S390_FEAT_ESOP,
S390_FEAT_HPMA2,
S390_FEAT_SIE_KSS,
/* Sclp Conf Char Ext */
S390_FEAT_SIE_64BSCAO, S390_FEAT_SIE_64BSCAO,
S390_FEAT_SIE_CMMA, S390_FEAT_SIE_CMMA,
S390_FEAT_SIE_PFMFI, S390_FEAT_SIE_PFMFI,
S390_FEAT_SIE_IBS, S390_FEAT_SIE_IBS,
/* Sclp Cpu */
S390_FEAT_SIE_F2, S390_FEAT_SIE_F2,
S390_FEAT_SIE_SKEY, S390_FEAT_SIE_SKEY,
S390_FEAT_SIE_GPERE, S390_FEAT_SIE_GPERE,
@ -85,8 +112,12 @@ typedef enum {
S390_FEAT_SIE_SIGPIF, S390_FEAT_SIE_SIGPIF,
S390_FEAT_SIE_IB, S390_FEAT_SIE_IB,
S390_FEAT_SIE_CEI, S390_FEAT_SIE_CEI,
/* Misc */
S390_FEAT_DAT_ENH_2, S390_FEAT_DAT_ENH_2,
S390_FEAT_CMM, S390_FEAT_CMM,
/* PLO */
S390_FEAT_PLO_CL, S390_FEAT_PLO_CL,
S390_FEAT_PLO_CLG, S390_FEAT_PLO_CLG,
S390_FEAT_PLO_CLGR, S390_FEAT_PLO_CLGR,
@ -111,6 +142,8 @@ typedef enum {
S390_FEAT_PLO_CSTSTG, S390_FEAT_PLO_CSTSTG,
S390_FEAT_PLO_CSTSTGR, S390_FEAT_PLO_CSTSTGR,
S390_FEAT_PLO_CSTSTX, S390_FEAT_PLO_CSTSTX,
/* PTFF */
S390_FEAT_PTFF_QTO, S390_FEAT_PTFF_QTO,
S390_FEAT_PTFF_QSI, S390_FEAT_PTFF_QSI,
S390_FEAT_PTFF_QPT, S390_FEAT_PTFF_QPT,
@ -118,6 +151,8 @@ typedef enum {
S390_FEAT_PTFF_QTOU, S390_FEAT_PTFF_QTOU,
S390_FEAT_PTFF_STO, S390_FEAT_PTFF_STO,
S390_FEAT_PTFF_STOU, S390_FEAT_PTFF_STOU,
/* KMAC */
S390_FEAT_KMAC_DEA, S390_FEAT_KMAC_DEA,
S390_FEAT_KMAC_TDEA_128, S390_FEAT_KMAC_TDEA_128,
S390_FEAT_KMAC_TDEA_192, S390_FEAT_KMAC_TDEA_192,
@ -130,6 +165,8 @@ typedef enum {
S390_FEAT_KMAC_EAES_128, S390_FEAT_KMAC_EAES_128,
S390_FEAT_KMAC_EAES_192, S390_FEAT_KMAC_EAES_192,
S390_FEAT_KMAC_EAES_256, S390_FEAT_KMAC_EAES_256,
/* KMC */
S390_FEAT_KMC_DEA, S390_FEAT_KMC_DEA,
S390_FEAT_KMC_TDEA_128, S390_FEAT_KMC_TDEA_128,
S390_FEAT_KMC_TDEA_192, S390_FEAT_KMC_TDEA_192,
@ -143,6 +180,8 @@ typedef enum {
S390_FEAT_KMC_EAES_192, S390_FEAT_KMC_EAES_192,
S390_FEAT_KMC_EAES_256, S390_FEAT_KMC_EAES_256,
S390_FEAT_KMC_PRNG, S390_FEAT_KMC_PRNG,
/* KM */
S390_FEAT_KM_DEA, S390_FEAT_KM_DEA,
S390_FEAT_KM_TDEA_128, S390_FEAT_KM_TDEA_128,
S390_FEAT_KM_TDEA_192, S390_FEAT_KM_TDEA_192,
@ -159,19 +198,39 @@ typedef enum {
S390_FEAT_KM_XTS_AES_256, S390_FEAT_KM_XTS_AES_256,
S390_FEAT_KM_XTS_EAES_128, S390_FEAT_KM_XTS_EAES_128,
S390_FEAT_KM_XTS_EAES_256, S390_FEAT_KM_XTS_EAES_256,
/* KIMD */
S390_FEAT_KIMD_SHA_1, S390_FEAT_KIMD_SHA_1,
S390_FEAT_KIMD_SHA_256, S390_FEAT_KIMD_SHA_256,
S390_FEAT_KIMD_SHA_512, S390_FEAT_KIMD_SHA_512,
S390_FEAT_KIMD_SHA3_224,
S390_FEAT_KIMD_SHA3_256,
S390_FEAT_KIMD_SHA3_384,
S390_FEAT_KIMD_SHA3_512,
S390_FEAT_KIMD_SHAKE_128,
S390_FEAT_KIMD_SHAKE_256,
S390_FEAT_KIMD_GHASH, S390_FEAT_KIMD_GHASH,
/* KLMD */
S390_FEAT_KLMD_SHA_1, S390_FEAT_KLMD_SHA_1,
S390_FEAT_KLMD_SHA_256, S390_FEAT_KLMD_SHA_256,
S390_FEAT_KLMD_SHA_512, S390_FEAT_KLMD_SHA_512,
S390_FEAT_KLMD_SHA3_224,
S390_FEAT_KLMD_SHA3_256,
S390_FEAT_KLMD_SHA3_384,
S390_FEAT_KLMD_SHA3_512,
S390_FEAT_KLMD_SHAKE_128,
S390_FEAT_KLMD_SHAKE_256,
/* PCKMO */
S390_FEAT_PCKMO_EDEA, S390_FEAT_PCKMO_EDEA,
S390_FEAT_PCKMO_ETDEA_128, S390_FEAT_PCKMO_ETDEA_128,
S390_FEAT_PCKMO_ETDEA_256, S390_FEAT_PCKMO_ETDEA_256,
S390_FEAT_PCKMO_AES_128, S390_FEAT_PCKMO_AES_128,
S390_FEAT_PCKMO_AES_192, S390_FEAT_PCKMO_AES_192,
S390_FEAT_PCKMO_AES_256, S390_FEAT_PCKMO_AES_256,
/* KMCTR */
S390_FEAT_KMCTR_DEA, S390_FEAT_KMCTR_DEA,
S390_FEAT_KMCTR_TDEA_128, S390_FEAT_KMCTR_TDEA_128,
S390_FEAT_KMCTR_TDEA_192, S390_FEAT_KMCTR_TDEA_192,
@ -184,6 +243,8 @@ typedef enum {
S390_FEAT_KMCTR_EAES_128, S390_FEAT_KMCTR_EAES_128,
S390_FEAT_KMCTR_EAES_192, S390_FEAT_KMCTR_EAES_192,
S390_FEAT_KMCTR_EAES_256, S390_FEAT_KMCTR_EAES_256,
/* KMF */
S390_FEAT_KMF_DEA, S390_FEAT_KMF_DEA,
S390_FEAT_KMF_TDEA_128, S390_FEAT_KMF_TDEA_128,
S390_FEAT_KMF_TDEA_192, S390_FEAT_KMF_TDEA_192,
@ -196,6 +257,8 @@ typedef enum {
S390_FEAT_KMF_EAES_128, S390_FEAT_KMF_EAES_128,
S390_FEAT_KMF_EAES_192, S390_FEAT_KMF_EAES_192,
S390_FEAT_KMF_EAES_256, S390_FEAT_KMF_EAES_256,
/* KMO */
S390_FEAT_KMO_DEA, S390_FEAT_KMO_DEA,
S390_FEAT_KMO_TDEA_128, S390_FEAT_KMO_TDEA_128,
S390_FEAT_KMO_TDEA_192, S390_FEAT_KMO_TDEA_192,
@ -208,6 +271,8 @@ typedef enum {
S390_FEAT_KMO_EAES_128, S390_FEAT_KMO_EAES_128,
S390_FEAT_KMO_EAES_192, S390_FEAT_KMO_EAES_192,
S390_FEAT_KMO_EAES_256, S390_FEAT_KMO_EAES_256,
/* PCC */
S390_FEAT_PCC_CMAC_DEA, S390_FEAT_PCC_CMAC_DEA,
S390_FEAT_PCC_CMAC_TDEA_128, S390_FEAT_PCC_CMAC_TDEA_128,
S390_FEAT_PCC_CMAC_TDEA_192, S390_FEAT_PCC_CMAC_TDEA_192,
@ -224,7 +289,19 @@ typedef enum {
S390_FEAT_PCC_XTS_AES_256, S390_FEAT_PCC_XTS_AES_256,
S390_FEAT_PCC_XTS_EAES_128, S390_FEAT_PCC_XTS_EAES_128,
S390_FEAT_PCC_XTS_EAES_256, S390_FEAT_PCC_XTS_EAES_256,
/* PPNO/PRNO */
S390_FEAT_PPNO_SHA_512_DRNG, S390_FEAT_PPNO_SHA_512_DRNG,
S390_FEAT_PRNO_TRNG_QRTCR,
S390_FEAT_PRNO_TRNG,
/* KMA */
S390_FEAT_KMA_GCM_AES_128,
S390_FEAT_KMA_GCM_AES_192,
S390_FEAT_KMA_GCM_AES_256 ,
S390_FEAT_KMA_GCM_EAES_128,
S390_FEAT_KMA_GCM_EAES_192,
S390_FEAT_KMA_GCM_EAES_256,
S390_FEAT_MAX, S390_FEAT_MAX,
} S390Feat; } S390Feat;

View file

@ -77,6 +77,32 @@ static S390CPUDef s390_cpu_defs[] = {
CPUDEF_INIT(0x2965, 13, 2, 47, 0x08000000U, "z13s", "IBM z13s GA1"), CPUDEF_INIT(0x2965, 13, 2, 47, 0x08000000U, "z13s", "IBM z13s GA1"),
}; };
void s390_cpudef_featoff(uint8_t gen, uint8_t ec_ga, S390Feat feat)
{
const S390CPUDef *def;
def = s390_find_cpu_def(0, gen, ec_ga, NULL);
clear_bit(feat, (unsigned long *)&def->default_feat);
}
void s390_cpudef_featoff_greater(uint8_t gen, uint8_t ec_ga, S390Feat feat)
{
int i;
for (i = 0; i < ARRAY_SIZE(s390_cpu_defs); i++) {
const S390CPUDef *def = &s390_cpu_defs[i];
if (def->gen < gen) {
continue;
}
if (def->gen == gen && def->ec_ga < ec_ga) {
continue;
}
clear_bit(feat, (unsigned long *)&def->default_feat);
}
}
uint32_t s390_get_hmfai(void) uint32_t s390_get_hmfai(void)
{ {
static S390CPU *cpu; static S390CPU *cpu;
@ -671,6 +697,31 @@ static void check_consistency(const S390CPUModel *model)
{ S390_FEAT_SIE_CMMA, S390_FEAT_CMM }, { S390_FEAT_SIE_CMMA, S390_FEAT_CMM },
{ S390_FEAT_SIE_CMMA, S390_FEAT_SIE_GSLS }, { S390_FEAT_SIE_CMMA, S390_FEAT_SIE_GSLS },
{ S390_FEAT_SIE_PFMFI, S390_FEAT_EDAT }, { S390_FEAT_SIE_PFMFI, S390_FEAT_EDAT },
{ S390_FEAT_MSA_EXT_8, S390_FEAT_MSA_EXT_3 },
{ S390_FEAT_MULTIPLE_EPOCH, S390_FEAT_TOD_CLOCK_STEERING },
{ S390_FEAT_VECTOR_PACKED_DECIMAL, S390_FEAT_VECTOR },
{ S390_FEAT_VECTOR_ENH, S390_FEAT_VECTOR },
{ S390_FEAT_INSTRUCTION_EXEC_PROT, S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2 },
{ S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2, S390_FEAT_ESOP },
{ S390_FEAT_CMM_NT, S390_FEAT_CMM },
{ S390_FEAT_GUARDED_STORAGE, S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2 },
{ S390_FEAT_MULTIPLE_EPOCH, S390_FEAT_STORE_CLOCK_FAST },
{ S390_FEAT_MULTIPLE_EPOCH, S390_FEAT_TOD_CLOCK_STEERING },
{ S390_FEAT_SEMAPHORE_ASSIST, S390_FEAT_STFLE_49 },
{ S390_FEAT_KIMD_SHA3_224, S390_FEAT_MSA },
{ S390_FEAT_KIMD_SHA3_256, S390_FEAT_MSA },
{ S390_FEAT_KIMD_SHA3_384, S390_FEAT_MSA },
{ S390_FEAT_KIMD_SHA3_512, S390_FEAT_MSA },
{ S390_FEAT_KIMD_SHAKE_128, S390_FEAT_MSA },
{ S390_FEAT_KIMD_SHAKE_256, S390_FEAT_MSA },
{ S390_FEAT_KLMD_SHA3_224, S390_FEAT_MSA },
{ S390_FEAT_KLMD_SHA3_256, S390_FEAT_MSA },
{ S390_FEAT_KLMD_SHA3_384, S390_FEAT_MSA },
{ S390_FEAT_KLMD_SHA3_512, S390_FEAT_MSA },
{ S390_FEAT_KLMD_SHAKE_128, S390_FEAT_MSA },
{ S390_FEAT_KLMD_SHAKE_256, S390_FEAT_MSA },
{ S390_FEAT_PRNO_TRNG_QRTCR, S390_FEAT_MSA_EXT_5 },
{ S390_FEAT_PRNO_TRNG, S390_FEAT_MSA_EXT_5 },
}; };
int i; int i;

View file

@ -72,6 +72,8 @@ typedef struct S390CPUModel {
#define ibc_gen(x) (x == 0 ? 0 : ((x >> 4) + S390_GEN_Z10)) #define ibc_gen(x) (x == 0 ? 0 : ((x >> 4) + S390_GEN_Z10))
#define ibc_ec_ga(x) (x & 0xf) #define ibc_ec_ga(x) (x & 0xf)
void s390_cpudef_featoff(uint8_t gen, uint8_t ec_ga, S390Feat feat);
void s390_cpudef_featoff_greater(uint8_t gen, uint8_t ec_ga, S390Feat feat);
uint32_t s390_get_hmfai(void); uint32_t s390_get_hmfai(void);
uint8_t s390_get_mha_pow(void); uint8_t s390_get_mha_pow(void);
uint32_t s390_get_ibc_val(void); uint32_t s390_get_ibc_val(void);

View file

@ -286,6 +286,26 @@ static int cpu_write_virt_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
} }
#endif #endif
/* the values represent the positions in s390-gs.xml */
#define S390_GS_RESERVED_REGNUM 0
#define S390_GS_GSD_REGNUM 1
#define S390_GS_GSSM_REGNUM 2
#define S390_GS_GSEPLA_REGNUM 3
/* total number of registers in s390-gs.xml */
#define S390_NUM_GS_REGS 4
static int cpu_read_gs_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
{
return gdb_get_regl(mem_buf, env->gscb[n]);
}
static int cpu_write_gs_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
{
env->gscb[n] = ldtul_p(mem_buf);
cpu_synchronize_post_init(ENV_GET_CPU(env));
return 8;
}
void s390_cpu_gdb_init(CPUState *cs) void s390_cpu_gdb_init(CPUState *cs)
{ {
gdb_register_coprocessor(cs, cpu_read_ac_reg, gdb_register_coprocessor(cs, cpu_read_ac_reg,
@ -300,6 +320,10 @@ void s390_cpu_gdb_init(CPUState *cs)
cpu_write_vreg, cpu_write_vreg,
S390_NUM_VREGS, "s390-vx.xml", 0); S390_NUM_VREGS, "s390-vx.xml", 0);
gdb_register_coprocessor(cs, cpu_read_gs_reg,
cpu_write_gs_reg,
S390_NUM_GS_REGS, "s390-gs.xml", 0);
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
gdb_register_coprocessor(cs, cpu_read_c_reg, gdb_register_coprocessor(cs, cpu_read_c_reg,
cpu_write_c_reg, cpu_write_c_reg,

View file

@ -182,6 +182,33 @@
S390_FEAT_MSA_EXT_5, \ S390_FEAT_MSA_EXT_5, \
S390_FEAT_PPNO_SHA_512_DRNG S390_FEAT_PPNO_SHA_512_DRNG
#define S390_FEAT_GROUP_MSA_EXT_6 \
S390_FEAT_KIMD_SHA3_224, \
S390_FEAT_KIMD_SHA3_256, \
S390_FEAT_KIMD_SHA3_384, \
S390_FEAT_KIMD_SHA3_512, \
S390_FEAT_KIMD_SHAKE_128, \
S390_FEAT_KIMD_SHAKE_256, \
S390_FEAT_KLMD_SHA3_224, \
S390_FEAT_KLMD_SHA3_256, \
S390_FEAT_KLMD_SHA3_384, \
S390_FEAT_KLMD_SHA3_512, \
S390_FEAT_KLMD_SHAKE_128, \
S390_FEAT_KLMD_SHAKE_256
#define S390_FEAT_GROUP_MSA_EXT_7 \
S390_FEAT_PRNO_TRNG_QRTCR, \
S390_FEAT_PRNO_TRNG
#define S390_FEAT_GROUP_MSA_EXT_8 \
S390_FEAT_MSA_EXT_8, \
S390_FEAT_KMA_GCM_AES_128, \
S390_FEAT_KMA_GCM_AES_192, \
S390_FEAT_KMA_GCM_AES_256 , \
S390_FEAT_KMA_GCM_EAES_128, \
S390_FEAT_KMA_GCM_EAES_192, \
S390_FEAT_KMA_GCM_EAES_256
/* cpu feature groups */ /* cpu feature groups */
static uint16_t group_PLO[] = { static uint16_t group_PLO[] = {
S390_FEAT_GROUP_PLO, S390_FEAT_GROUP_PLO,
@ -210,15 +237,30 @@ static uint16_t group_MSA_EXT_4[] = {
static uint16_t group_MSA_EXT_5[] = { static uint16_t group_MSA_EXT_5[] = {
S390_FEAT_GROUP_MSA_EXT_5, S390_FEAT_GROUP_MSA_EXT_5,
}; };
static uint16_t group_MSA_EXT_6[] = {
S390_FEAT_GROUP_MSA_EXT_6,
};
static uint16_t group_MSA_EXT_7[] = {
S390_FEAT_GROUP_MSA_EXT_7,
};
static uint16_t group_MSA_EXT_8[] = {
S390_FEAT_GROUP_MSA_EXT_8,
};
/* base features in order of release */ /* Base features (in order of release)
* Only non-hypervisor managed features belong here.
* Base feature sets are static meaning they do not change in future QEMU
* releases.
*/
static uint16_t base_GEN7_GA1[] = { static uint16_t base_GEN7_GA1[] = {
S390_FEAT_GROUP_PLO, S390_FEAT_GROUP_PLO,
S390_FEAT_ESAN3, S390_FEAT_ESAN3,
S390_FEAT_ZARCH, S390_FEAT_ZARCH,
}; };
#define base_GEN7_GA2 EmptyFeat #define base_GEN7_GA2 EmptyFeat
#define base_GEN7_GA3 EmptyFeat #define base_GEN7_GA3 EmptyFeat
static uint16_t base_GEN8_GA1[] = { static uint16_t base_GEN8_GA1[] = {
S390_FEAT_DAT_ENH, S390_FEAT_DAT_ENH,
S390_FEAT_EXTENDED_TRANSLATION_2, S390_FEAT_EXTENDED_TRANSLATION_2,
@ -227,10 +269,12 @@ static uint16_t base_GEN8_GA1[] = {
S390_FEAT_LONG_DISPLACEMENT_FAST, S390_FEAT_LONG_DISPLACEMENT_FAST,
S390_FEAT_HFP_MADDSUB, S390_FEAT_HFP_MADDSUB,
}; };
#define base_GEN8_GA2 EmptyFeat #define base_GEN8_GA2 EmptyFeat
#define base_GEN8_GA3 EmptyFeat #define base_GEN8_GA3 EmptyFeat
#define base_GEN8_GA4 EmptyFeat #define base_GEN8_GA4 EmptyFeat
#define base_GEN8_GA5 EmptyFeat #define base_GEN8_GA5 EmptyFeat
static uint16_t base_GEN9_GA1[] = { static uint16_t base_GEN9_GA1[] = {
S390_FEAT_IDTE_SEGMENT, S390_FEAT_IDTE_SEGMENT,
S390_FEAT_ASN_LX_REUSE, S390_FEAT_ASN_LX_REUSE,
@ -245,8 +289,10 @@ static uint16_t base_GEN9_GA1[] = {
S390_FEAT_ETF3_ENH, S390_FEAT_ETF3_ENH,
S390_FEAT_DAT_ENH_2, S390_FEAT_DAT_ENH_2,
}; };
#define base_GEN9_GA2 EmptyFeat #define base_GEN9_GA2 EmptyFeat
#define base_GEN9_GA3 EmptyFeat #define base_GEN9_GA3 EmptyFeat
static uint16_t base_GEN10_GA1[] = { static uint16_t base_GEN10_GA1[] = {
S390_FEAT_CONDITIONAL_SSKE, S390_FEAT_CONDITIONAL_SSKE,
S390_FEAT_PARSING_ENH, S390_FEAT_PARSING_ENH,
@ -263,6 +309,7 @@ static uint16_t base_GEN10_GA1[] = {
}; };
#define base_GEN10_GA2 EmptyFeat #define base_GEN10_GA2 EmptyFeat
#define base_GEN10_GA3 EmptyFeat #define base_GEN10_GA3 EmptyFeat
static uint16_t base_GEN11_GA1[] = { static uint16_t base_GEN11_GA1[] = {
S390_FEAT_NONQ_KEY_SETTING, S390_FEAT_NONQ_KEY_SETTING,
S390_FEAT_ENHANCED_MONITOR, S390_FEAT_ENHANCED_MONITOR,
@ -272,21 +319,30 @@ static uint16_t base_GEN11_GA1[] = {
S390_FEAT_CMPSC_ENH, S390_FEAT_CMPSC_ENH,
S390_FEAT_INTERLOCKED_ACCESS_2, S390_FEAT_INTERLOCKED_ACCESS_2,
}; };
#define base_GEN11_GA2 EmptyFeat #define base_GEN11_GA2 EmptyFeat
static uint16_t base_GEN12_GA1[] = { static uint16_t base_GEN12_GA1[] = {
S390_FEAT_DFP_ZONED_CONVERSION, S390_FEAT_DFP_ZONED_CONVERSION,
S390_FEAT_STFLE_49, S390_FEAT_STFLE_49,
S390_FEAT_LOCAL_TLB_CLEARING, S390_FEAT_LOCAL_TLB_CLEARING,
}; };
#define base_GEN12_GA2 EmptyFeat #define base_GEN12_GA2 EmptyFeat
static uint16_t base_GEN13_GA1[] = { static uint16_t base_GEN13_GA1[] = {
S390_FEAT_STFLE_53, S390_FEAT_STFLE_53,
S390_FEAT_DFP_PACKED_CONVERSION, S390_FEAT_DFP_PACKED_CONVERSION,
S390_FEAT_GROUP_GEN13_PTFF, S390_FEAT_GROUP_GEN13_PTFF,
}; };
#define base_GEN13_GA2 EmptyFeat #define base_GEN13_GA2 EmptyFeat
/* full features differing to the base in order of release */ /* Full features (in order of release)
* Automatically includes corresponding base features.
* Full features are all features this hardware supports even if kvm/QEMU do not
* support these features yet.
*/
static uint16_t full_GEN7_GA1[] = { static uint16_t full_GEN7_GA1[] = {
S390_FEAT_SIE_F2, S390_FEAT_SIE_F2,
S390_FEAT_SIE_SKEY, S390_FEAT_SIE_SKEY,
@ -294,30 +350,38 @@ static uint16_t full_GEN7_GA1[] = {
S390_FEAT_SIE_IB, S390_FEAT_SIE_IB,
S390_FEAT_SIE_CEI, S390_FEAT_SIE_CEI,
}; };
static uint16_t full_GEN7_GA2[] = { static uint16_t full_GEN7_GA2[] = {
S390_FEAT_EXTENDED_TRANSLATION_2, S390_FEAT_EXTENDED_TRANSLATION_2,
}; };
static uint16_t full_GEN7_GA3[] = { static uint16_t full_GEN7_GA3[] = {
S390_FEAT_LONG_DISPLACEMENT, S390_FEAT_LONG_DISPLACEMENT,
S390_FEAT_SIE_SIIF, S390_FEAT_SIE_SIIF,
}; };
static uint16_t full_GEN8_GA1[] = { static uint16_t full_GEN8_GA1[] = {
S390_FEAT_SIE_GSLS, S390_FEAT_SIE_GSLS,
S390_FEAT_SIE_64BSCAO, S390_FEAT_SIE_64BSCAO,
}; };
#define full_GEN8_GA2 EmptyFeat #define full_GEN8_GA2 EmptyFeat
static uint16_t full_GEN8_GA3[] = { static uint16_t full_GEN8_GA3[] = {
S390_FEAT_ASN_LX_REUSE, S390_FEAT_ASN_LX_REUSE,
S390_FEAT_EXTENDED_TRANSLATION_3, S390_FEAT_EXTENDED_TRANSLATION_3,
}; };
#define full_GEN8_GA4 EmptyFeat #define full_GEN8_GA4 EmptyFeat
#define full_GEN8_GA5 EmptyFeat #define full_GEN8_GA5 EmptyFeat
static uint16_t full_GEN9_GA1[] = { static uint16_t full_GEN9_GA1[] = {
S390_FEAT_STORE_HYPERVISOR_INFO, S390_FEAT_STORE_HYPERVISOR_INFO,
S390_FEAT_GROUP_MSA_EXT_1, S390_FEAT_GROUP_MSA_EXT_1,
S390_FEAT_CMM, S390_FEAT_CMM,
S390_FEAT_SIE_CMMA, S390_FEAT_SIE_CMMA,
}; };
static uint16_t full_GEN9_GA2[] = { static uint16_t full_GEN9_GA2[] = {
S390_FEAT_MOVE_WITH_OPTIONAL_SPEC, S390_FEAT_MOVE_WITH_OPTIONAL_SPEC,
S390_FEAT_EXTRACT_CPU_TIME, S390_FEAT_EXTRACT_CPU_TIME,
@ -325,10 +389,12 @@ static uint16_t full_GEN9_GA2[] = {
S390_FEAT_FLOATING_POINT_SUPPPORT_ENH, S390_FEAT_FLOATING_POINT_SUPPPORT_ENH,
S390_FEAT_DFP, S390_FEAT_DFP,
}; };
static uint16_t full_GEN9_GA3[] = { static uint16_t full_GEN9_GA3[] = {
S390_FEAT_CONDITIONAL_SSKE, S390_FEAT_CONDITIONAL_SSKE,
S390_FEAT_PFPO, S390_FEAT_PFPO,
}; };
static uint16_t full_GEN10_GA1[] = { static uint16_t full_GEN10_GA1[] = {
S390_FEAT_EDAT, S390_FEAT_EDAT,
S390_FEAT_CONFIGURATION_TOPOLOGY, S390_FEAT_CONFIGURATION_TOPOLOGY,
@ -337,34 +403,50 @@ static uint16_t full_GEN10_GA1[] = {
S390_FEAT_SIE_PFMFI, S390_FEAT_SIE_PFMFI,
S390_FEAT_SIE_SIGPIF, S390_FEAT_SIE_SIGPIF,
}; };
static uint16_t full_GEN10_GA2[] = { static uint16_t full_GEN10_GA2[] = {
S390_FEAT_SET_PROGRAM_PARAMETERS, S390_FEAT_SET_PROGRAM_PARAMETERS,
S390_FEAT_SIE_IBS, S390_FEAT_SIE_IBS,
}; };
static uint16_t full_GEN10_GA3[] = { static uint16_t full_GEN10_GA3[] = {
S390_FEAT_GROUP_MSA_EXT_3, S390_FEAT_GROUP_MSA_EXT_3,
}; };
static uint16_t full_GEN11_GA1[] = { static uint16_t full_GEN11_GA1[] = {
S390_FEAT_IPTE_RANGE, S390_FEAT_IPTE_RANGE,
S390_FEAT_ACCESS_EXCEPTION_FS_INDICATION, S390_FEAT_ACCESS_EXCEPTION_FS_INDICATION,
S390_FEAT_GROUP_MSA_EXT_4, S390_FEAT_GROUP_MSA_EXT_4,
}; };
#define full_GEN11_GA2 EmptyFeat #define full_GEN11_GA2 EmptyFeat
static uint16_t full_GEN12_GA1[] = { static uint16_t full_GEN12_GA1[] = {
S390_FEAT_CONSTRAINT_TRANSACTIONAL_EXE, S390_FEAT_CONSTRAINT_TRANSACTIONAL_EXE,
S390_FEAT_TRANSACTIONAL_EXE, S390_FEAT_TRANSACTIONAL_EXE,
S390_FEAT_RUNTIME_INSTRUMENTATION, S390_FEAT_RUNTIME_INSTRUMENTATION,
S390_FEAT_ZPCI,
S390_FEAT_ADAPTER_EVENT_NOTIFICATION,
S390_FEAT_ADAPTER_INT_SUPPRESSION,
S390_FEAT_EDAT_2, S390_FEAT_EDAT_2,
S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2,
}; };
static uint16_t full_GEN12_GA2[] = { static uint16_t full_GEN12_GA2[] = {
S390_FEAT_GROUP_MSA_EXT_5, S390_FEAT_GROUP_MSA_EXT_5,
}; };
static uint16_t full_GEN13_GA1[] = { static uint16_t full_GEN13_GA1[] = {
S390_FEAT_VECTOR, S390_FEAT_VECTOR,
}; };
#define full_GEN13_GA2 EmptyFeat #define full_GEN13_GA2 EmptyFeat
/* default features differing to the base in order of release */ /* Default features (in order of release)
* Automatically includes corresponding base features.
* Default features are all features this version of QEMU supports for this
* hardware model. Default feature sets can grow with new QEMU releases.
*/
#define default_GEN7_GA1 EmptyFeat #define default_GEN7_GA1 EmptyFeat
#define default_GEN7_GA2 EmptyFeat #define default_GEN7_GA2 EmptyFeat
#define default_GEN7_GA3 EmptyFeat #define default_GEN7_GA3 EmptyFeat
@ -373,37 +455,51 @@ static uint16_t full_GEN13_GA1[] = {
#define default_GEN8_GA3 EmptyFeat #define default_GEN8_GA3 EmptyFeat
#define default_GEN8_GA4 EmptyFeat #define default_GEN8_GA4 EmptyFeat
#define default_GEN8_GA5 EmptyFeat #define default_GEN8_GA5 EmptyFeat
static uint16_t default_GEN9_GA1[] = { static uint16_t default_GEN9_GA1[] = {
S390_FEAT_STORE_HYPERVISOR_INFO, S390_FEAT_STORE_HYPERVISOR_INFO,
S390_FEAT_GROUP_MSA_EXT_1, S390_FEAT_GROUP_MSA_EXT_1,
S390_FEAT_CMM, S390_FEAT_CMM,
}; };
#define default_GEN9_GA2 EmptyFeat #define default_GEN9_GA2 EmptyFeat
#define default_GEN9_GA3 EmptyFeat #define default_GEN9_GA3 EmptyFeat
static uint16_t default_GEN10_GA1[] = { static uint16_t default_GEN10_GA1[] = {
S390_FEAT_EDAT, S390_FEAT_EDAT,
S390_FEAT_GROUP_MSA_EXT_2, S390_FEAT_GROUP_MSA_EXT_2,
}; };
#define default_GEN10_GA2 EmptyFeat #define default_GEN10_GA2 EmptyFeat
#define default_GEN10_GA3 EmptyFeat #define default_GEN10_GA3 EmptyFeat
static uint16_t default_GEN11_GA1[] = { static uint16_t default_GEN11_GA1[] = {
S390_FEAT_GROUP_MSA_EXT_3, S390_FEAT_GROUP_MSA_EXT_3,
S390_FEAT_IPTE_RANGE, S390_FEAT_IPTE_RANGE,
S390_FEAT_ACCESS_EXCEPTION_FS_INDICATION, S390_FEAT_ACCESS_EXCEPTION_FS_INDICATION,
S390_FEAT_GROUP_MSA_EXT_4, S390_FEAT_GROUP_MSA_EXT_4,
}; };
#define default_GEN11_GA2 EmptyFeat #define default_GEN11_GA2 EmptyFeat
static uint16_t default_GEN12_GA1[] = { static uint16_t default_GEN12_GA1[] = {
S390_FEAT_CONSTRAINT_TRANSACTIONAL_EXE, S390_FEAT_CONSTRAINT_TRANSACTIONAL_EXE,
S390_FEAT_TRANSACTIONAL_EXE, S390_FEAT_TRANSACTIONAL_EXE,
S390_FEAT_RUNTIME_INSTRUMENTATION, S390_FEAT_RUNTIME_INSTRUMENTATION,
S390_FEAT_ZPCI,
S390_FEAT_ADAPTER_EVENT_NOTIFICATION,
S390_FEAT_EDAT_2, S390_FEAT_EDAT_2,
S390_FEAT_ESOP,
S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2,
}; };
#define default_GEN12_GA2 EmptyFeat #define default_GEN12_GA2 EmptyFeat
static uint16_t default_GEN13_GA1[] = { static uint16_t default_GEN13_GA1[] = {
S390_FEAT_GROUP_MSA_EXT_5, S390_FEAT_GROUP_MSA_EXT_5,
S390_FEAT_VECTOR, S390_FEAT_VECTOR,
}; };
#define default_GEN13_GA2 EmptyFeat #define default_GEN13_GA2 EmptyFeat
/****** END FEATURE DEFS ******/ /****** END FEATURE DEFS ******/
@ -491,6 +587,9 @@ static FeatGroupDefSpec FeatGroupDef[] = {
FEAT_GROUP_INITIALIZER(MSA_EXT_3), FEAT_GROUP_INITIALIZER(MSA_EXT_3),
FEAT_GROUP_INITIALIZER(MSA_EXT_4), FEAT_GROUP_INITIALIZER(MSA_EXT_4),
FEAT_GROUP_INITIALIZER(MSA_EXT_5), FEAT_GROUP_INITIALIZER(MSA_EXT_5),
FEAT_GROUP_INITIALIZER(MSA_EXT_6),
FEAT_GROUP_INITIALIZER(MSA_EXT_7),
FEAT_GROUP_INITIALIZER(MSA_EXT_8),
}; };
static void set_bits(uint64_t list[], BitSpec bits) static void set_bits(uint64_t list[], BitSpec bits)

View file

@ -139,6 +139,9 @@ static int cap_async_pf;
static int cap_mem_op; static int cap_mem_op;
static int cap_s390_irq; static int cap_s390_irq;
static int cap_ri; static int cap_ri;
static int cap_gs;
static int active_cmma;
static void *legacy_s390_alloc(size_t size, uint64_t *align); static void *legacy_s390_alloc(size_t size, uint64_t *align);
@ -177,6 +180,11 @@ int kvm_s390_set_mem_limit(KVMState *s, uint64_t new_limit, uint64_t *hw_limit)
return kvm_vm_ioctl(s, KVM_SET_DEVICE_ATTR, &attr); return kvm_vm_ioctl(s, KVM_SET_DEVICE_ATTR, &attr);
} }
int kvm_s390_cmma_active(void)
{
return active_cmma;
}
static bool kvm_s390_cmma_available(void) static bool kvm_s390_cmma_available(void)
{ {
static bool initialized, value; static bool initialized, value;
@ -197,7 +205,7 @@ void kvm_s390_cmma_reset(void)
.attr = KVM_S390_VM_MEM_CLR_CMMA, .attr = KVM_S390_VM_MEM_CLR_CMMA,
}; };
if (mem_path || !kvm_s390_cmma_available()) { if (!kvm_s390_cmma_active()) {
return; return;
} }
@ -213,7 +221,13 @@ static void kvm_s390_enable_cmma(void)
.attr = KVM_S390_VM_MEM_ENABLE_CMMA, .attr = KVM_S390_VM_MEM_ENABLE_CMMA,
}; };
if (mem_path) {
error_report("Warning: CMM will not be enabled because it is not "
"compatible to hugetlbfs.");
return;
}
rc = kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr); rc = kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
active_cmma = !rc;
trace_kvm_enable_cmma(rc); trace_kvm_enable_cmma(rc);
} }
@ -288,6 +302,14 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
cap_ri = 1; cap_ri = 1;
} }
} }
if (gs_allowed()) {
if (kvm_vm_enable_cap(s, KVM_CAP_S390_GS, 0) == 0) {
cap_gs = 1;
}
}
/* Try to enable AIS facility */
kvm_vm_enable_cap(s, KVM_CAP_S390_AIS, 0);
qemu_mutex_init(&qemu_sigp_mutex); qemu_mutex_init(&qemu_sigp_mutex);
@ -456,6 +478,11 @@ int kvm_arch_put_registers(CPUState *cs, int level)
} }
} }
if (can_sync_regs(cs, KVM_SYNC_GSCB)) {
memcpy(cs->kvm_run->s.regs.gscb, env->gscb, 32);
cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_GSCB;
}
/* Finally the prefix */ /* Finally the prefix */
if (can_sync_regs(cs, KVM_SYNC_PREFIX)) { if (can_sync_regs(cs, KVM_SYNC_PREFIX)) {
cs->kvm_run->s.regs.prefix = env->psa; cs->kvm_run->s.regs.prefix = env->psa;
@ -562,6 +589,10 @@ int kvm_arch_get_registers(CPUState *cs)
memcpy(env->riccb, cs->kvm_run->s.regs.riccb, 64); memcpy(env->riccb, cs->kvm_run->s.regs.riccb, 64);
} }
if (can_sync_regs(cs, KVM_SYNC_GSCB)) {
memcpy(env->gscb, cs->kvm_run->s.regs.gscb, 32);
}
/* pfault parameters */ /* pfault parameters */
if (can_sync_regs(cs, KVM_SYNC_PFAULT)) { if (can_sync_regs(cs, KVM_SYNC_PFAULT)) {
env->pfault_token = cs->kvm_run->s.regs.pft; env->pfault_token = cs->kvm_run->s.regs.pft;
@ -1193,7 +1224,21 @@ static int kvm_stpcifc_service_call(S390CPU *cpu, struct kvm_run *run)
static int kvm_sic_service_call(S390CPU *cpu, struct kvm_run *run) static int kvm_sic_service_call(S390CPU *cpu, struct kvm_run *run)
{ {
/* NOOP */ CPUS390XState *env = &cpu->env;
uint8_t r1 = (run->s390_sieic.ipa & 0x00f0) >> 4;
uint8_t r3 = run->s390_sieic.ipa & 0x000f;
uint8_t isc;
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);
if (r) {
enter_pgmcheck(cpu, -r);
}
return 0; return 0;
} }
@ -1444,22 +1489,28 @@ static void sigp_stop(CPUState *cs, run_on_cpu_data arg)
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
} }
#define ADTL_SAVE_AREA_SIZE 1024 #define ADTL_GS_OFFSET 1024 /* offset of GS data in adtl save area */
static int kvm_s390_store_adtl_status(S390CPU *cpu, hwaddr addr) #define ADTL_GS_MIN_SIZE 2048 /* minimal size of adtl save area for GS */
static int do_store_adtl_status(S390CPU *cpu, hwaddr addr, hwaddr len)
{ {
hwaddr save = len;
void *mem; void *mem;
hwaddr len = ADTL_SAVE_AREA_SIZE;
mem = cpu_physical_memory_map(addr, &len, 1); mem = cpu_physical_memory_map(addr, &save, 1);
if (!mem) { if (!mem) {
return -EFAULT; return -EFAULT;
} }
if (len != ADTL_SAVE_AREA_SIZE) { if (save != len) {
cpu_physical_memory_unmap(mem, len, 1, 0); cpu_physical_memory_unmap(mem, len, 1, 0);
return -EFAULT; return -EFAULT;
} }
memcpy(mem, &cpu->env.vregs, 512); if (s390_has_feat(S390_FEAT_VECTOR)) {
memcpy(mem, &cpu->env.vregs, 512);
}
if (s390_has_feat(S390_FEAT_GUARDED_STORAGE) && len >= ADTL_GS_MIN_SIZE) {
memcpy(mem + ADTL_GS_OFFSET, &cpu->env.gscb, 32);
}
cpu_physical_memory_unmap(mem, len, 1, len); cpu_physical_memory_unmap(mem, len, 1, len);
@ -1555,12 +1606,17 @@ static void sigp_store_status_at_address(CPUState *cs, run_on_cpu_data arg)
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
} }
#define ADTL_SAVE_LC_MASK 0xfUL
static void sigp_store_adtl_status(CPUState *cs, run_on_cpu_data arg) static void sigp_store_adtl_status(CPUState *cs, run_on_cpu_data arg)
{ {
S390CPU *cpu = S390_CPU(cs); S390CPU *cpu = S390_CPU(cs);
SigpInfo *si = arg.host_ptr; SigpInfo *si = arg.host_ptr;
uint8_t lc = si->param & ADTL_SAVE_LC_MASK;
hwaddr addr = si->param & ~ADTL_SAVE_LC_MASK;
hwaddr len = 1UL << (lc ? lc : 10);
if (!s390_has_feat(S390_FEAT_VECTOR)) { if (!s390_has_feat(S390_FEAT_VECTOR) &&
!s390_has_feat(S390_FEAT_GUARDED_STORAGE)) {
set_sigp_status(si, SIGP_STAT_INVALID_ORDER); set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
return; return;
} }
@ -1571,15 +1627,32 @@ static void sigp_store_adtl_status(CPUState *cs, run_on_cpu_data arg)
return; return;
} }
/* parameter must be aligned to 1024-byte boundary */ /* address must be aligned to length */
if (si->param & 0x3ff) { if (addr & (len - 1)) {
set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
return;
}
/* no GS: only lc == 0 is valid */
if (!s390_has_feat(S390_FEAT_GUARDED_STORAGE) &&
lc != 0) {
set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
return;
}
/* GS: 0, 10, 11, 12 are valid */
if (s390_has_feat(S390_FEAT_GUARDED_STORAGE) &&
lc != 0 &&
lc != 10 &&
lc != 11 &&
lc != 12) {
set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER); set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
return; return;
} }
cpu_synchronize_state(cs); cpu_synchronize_state(cs);
if (kvm_s390_store_adtl_status(cpu, si->param)) { if (do_store_adtl_status(cpu, addr, len)) {
set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER); set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
return; return;
} }
@ -1727,41 +1800,25 @@ static int sigp_set_architecture(S390CPU *cpu, uint32_t param,
{ {
CPUState *cur_cs; CPUState *cur_cs;
S390CPU *cur_cpu; S390CPU *cur_cpu;
bool all_stopped = true;
/* due to the BQL, we are the only active cpu */
CPU_FOREACH(cur_cs) { CPU_FOREACH(cur_cs) {
cur_cpu = S390_CPU(cur_cs); cur_cpu = S390_CPU(cur_cs);
if (cur_cpu->env.sigp_order != 0) {
return SIGP_CC_BUSY; if (cur_cpu == cpu) {
continue;
} }
cpu_synchronize_state(cur_cs); if (s390_cpu_get_state(cur_cpu) != CPU_STATE_STOPPED) {
/* all but the current one have to be stopped */ all_stopped = false;
if (cur_cpu != cpu &&
s390_cpu_get_state(cur_cpu) != CPU_STATE_STOPPED) {
*status_reg &= 0xffffffff00000000ULL;
*status_reg |= SIGP_STAT_INCORRECT_STATE;
return SIGP_CC_STATUS_STORED;
} }
} }
switch (param & 0xff) { *status_reg &= 0xffffffff00000000ULL;
case SIGP_MODE_ESA_S390:
/* not supported */
return SIGP_CC_NOT_OPERATIONAL;
case SIGP_MODE_Z_ARCH_TRANS_ALL_PSW:
case SIGP_MODE_Z_ARCH_TRANS_CUR_PSW:
CPU_FOREACH(cur_cs) {
cur_cpu = S390_CPU(cur_cs);
cur_cpu->env.pfault_token = -1UL;
}
break;
default:
*status_reg &= 0xffffffff00000000ULL;
*status_reg |= SIGP_STAT_INVALID_PARAMETER;
return SIGP_CC_STATUS_STORED;
}
return SIGP_CC_ORDER_CODE_ACCEPTED; /* Reject set arch order, with czam we're always in z/Arch mode. */
*status_reg |= (all_stopped ? SIGP_STAT_INVALID_PARAMETER :
SIGP_STAT_INCORRECT_STATE);
return SIGP_CC_STATUS_STORED;
} }
static int handle_sigp(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) static int handle_sigp(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1)
@ -2174,6 +2231,9 @@ static uint64_t build_channel_report_mcic(void)
if (s390_has_feat(S390_FEAT_VECTOR)) { if (s390_has_feat(S390_FEAT_VECTOR)) {
mcic |= MCIC_VB_VR; mcic |= MCIC_VB_VR;
} }
if (s390_has_feat(S390_FEAT_GUARDED_STORAGE)) {
mcic |= MCIC_VB_GS;
}
return mcic; return mcic;
} }
@ -2239,6 +2299,11 @@ int kvm_s390_get_ri(void)
return cap_ri; return cap_ri;
} }
int kvm_s390_get_gs(void)
{
return cap_gs;
}
int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state) int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state)
{ {
struct kvm_mp_state mp_state = {}; struct kvm_mp_state mp_state = {};
@ -2417,6 +2482,9 @@ static int query_cpu_subfunc(S390FeatBitmap features)
if (test_bit(S390_FEAT_MSA_EXT_5, features)) { if (test_bit(S390_FEAT_MSA_EXT_5, features)) {
s390_add_from_feat_block(features, S390_FEAT_TYPE_PPNO, prop.ppno); s390_add_from_feat_block(features, S390_FEAT_TYPE_PPNO, prop.ppno);
} }
if (test_bit(S390_FEAT_MSA_EXT_8, features)) {
s390_add_from_feat_block(features, S390_FEAT_TYPE_KMA, prop.kma);
}
return 0; return 0;
} }
@ -2470,6 +2538,10 @@ static int configure_cpu_subfunc(const S390FeatBitmap features)
s390_fill_feat_block(features, S390_FEAT_TYPE_PPNO, prop.ppno); s390_fill_feat_block(features, S390_FEAT_TYPE_PPNO, prop.ppno);
prop.ppno[0] |= 0x80; /* query is always available */ prop.ppno[0] |= 0x80; /* query is always available */
} }
if (test_bit(S390_FEAT_MSA_EXT_8, features)) {
s390_fill_feat_block(features, S390_FEAT_TYPE_KMA, prop.kma);
prop.kma[0] |= 0x80; /* query is always available */
}
return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr); return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
} }
@ -2487,6 +2559,7 @@ static int kvm_to_feat[][2] = {
{ KVM_S390_VM_CPU_FEAT_CMMA, S390_FEAT_SIE_CMMA }, { KVM_S390_VM_CPU_FEAT_CMMA, S390_FEAT_SIE_CMMA },
{ KVM_S390_VM_CPU_FEAT_PFMFI, S390_FEAT_SIE_PFMFI}, { KVM_S390_VM_CPU_FEAT_PFMFI, S390_FEAT_SIE_PFMFI},
{ KVM_S390_VM_CPU_FEAT_SIGPIF, S390_FEAT_SIE_SIGPIF}, { KVM_S390_VM_CPU_FEAT_SIGPIF, S390_FEAT_SIE_SIGPIF},
{ KVM_S390_VM_CPU_FEAT_KSS, S390_FEAT_SIE_KSS},
}; };
static int query_cpu_feat(S390FeatBitmap features) static int query_cpu_feat(S390FeatBitmap features)
@ -2606,8 +2679,15 @@ void kvm_s390_get_host_cpu_model(S390CPUModel *model, Error **errp)
/* with cpu model support, CMM is only indicated if really available */ /* with cpu model support, CMM is only indicated if really available */
if (kvm_s390_cmma_available()) { if (kvm_s390_cmma_available()) {
set_bit(S390_FEAT_CMM, model->features); set_bit(S390_FEAT_CMM, model->features);
} else {
/* no cmm -> no cmm nt */
clear_bit(S390_FEAT_CMM_NT, model->features);
} }
/* set zpci and aen facilities */
set_bit(S390_FEAT_ZPCI, model->features);
set_bit(S390_FEAT_ADAPTER_EVENT_NOTIFICATION, model->features);
if (s390_known_cpu_type(cpu_type)) { if (s390_known_cpu_type(cpu_type)) {
/* we want the exact model, even if some features are missing */ /* we want the exact model, even if some features are missing */
model->def = s390_find_cpu_def(cpu_type, ibc_gen(unblocked_ibc), model->def = s390_find_cpu_def(cpu_type, ibc_gen(unblocked_ibc),
@ -2641,7 +2721,7 @@ void kvm_s390_apply_cpu_model(const S390CPUModel *model, Error **errp)
if (!model) { if (!model) {
/* compatibility handling if cpu models are disabled */ /* compatibility handling if cpu models are disabled */
if (kvm_s390_cmma_available() && !mem_path) { if (kvm_s390_cmma_available()) {
kvm_s390_enable_cmma(); kvm_s390_enable_cmma();
} }
return; return;
@ -2672,13 +2752,8 @@ void kvm_s390_apply_cpu_model(const S390CPUModel *model, Error **errp)
error_setg(errp, "KVM: Error configuring CPU subfunctions: %d", rc); error_setg(errp, "KVM: Error configuring CPU subfunctions: %d", rc);
return; return;
} }
/* enable CMM via CMMA - disable on hugetlbfs */ /* enable CMM via CMMA */
if (test_bit(S390_FEAT_CMM, model->features)) { if (test_bit(S390_FEAT_CMM, model->features)) {
if (mem_path) { kvm_s390_enable_cmma();
warn_report("CMM will not be enabled because it is not "
"compatible to hugetlbfs.");
} else {
kvm_s390_enable_cmma();
}
} }
} }

View file

@ -174,6 +174,22 @@ const VMStateDescription vmstate_exval = {
} }
}; };
static bool gscb_needed(void *opaque)
{
return kvm_s390_get_gs();
}
const VMStateDescription vmstate_gscb = {
.name = "cpu/gscb",
.version_id = 1,
.minimum_version_id = 1,
.needed = gscb_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT64_ARRAY(env.gscb, S390CPU, 4),
VMSTATE_END_OF_LIST()
}
};
const VMStateDescription vmstate_s390_cpu = { const VMStateDescription vmstate_s390_cpu = {
.name = "cpu", .name = "cpu",
.post_load = cpu_post_load, .post_load = cpu_post_load,
@ -207,6 +223,7 @@ const VMStateDescription vmstate_s390_cpu = {
&vmstate_vregs, &vmstate_vregs,
&vmstate_riccb, &vmstate_riccb,
&vmstate_exval, &vmstate_exval,
&vmstate_gscb,
NULL NULL
}, },
}; };