First batch of s390x patches for 2.7:

- The new machine for 2.7
 - Make use of the runtime instrumentation support introduced in
   the kernel
 - Enhance our ipl (boot) process: We can now start from devices
   in subchannel sets > 0 as well. As a bonus, the conversion to
   diag308 in the bios allows us to get rid of the gr7 hack.
 - Xiaoqiang Zhao's SCLP qomification patches
 - Several fixes in the s390x pci implementation
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJXOyw0AAoJEN7Pa5PG8C+v2fkQAI+woDEWJ9a1DtOw/sdIicX2
 wlXdzadtGM1/g0HWvmF1smMLCUcNtEA77+R5o0yE5cPnOBWI0WzuNPZmiMbkMROm
 gCC9OU9WOVDTPrrxfOGp4yhZkbZdz/K7TQUUB0bRRC+RTBJFNOqHSKrIDl+4AgkS
 v83hwYHcGEku53++BOrstlMcVY9gzGnL3E2KH6m1Rvhtac8bkjps5qzgmmQVCmL9
 EZCFZn0rH0LYq6Sdq3Fa6x89tdKsZ4ktnT76UJvJ4XGagHvOq9yojJixYQQnvfK4
 m5OlHadJdA/op4JxXxCM4TZbdxDQWo/r+pivULOmEA/cvwbQo+Ap1pDnp7BzByR+
 xjSzak7vSvfF+p8L7va/J9IZqSsMmTcrpBoRrhP6vGgDUZz53XzsZIOd/Q7haNFW
 5JeL3Qr7YqCi7//SQJAX0y1Q0JpyzZrZvwewAN1qyNeMSbW8lZOuj9Do2dHBvfkG
 l3C99V42idycu4DAVlmyULpirURg43XUjvztOjwEn9yXrnp3g+tThmwIdecDY4zQ
 IvTgIs5HEKFqy/HODZj7sCzY8YIJHhbGLmAzwqhtzemiH2ozsQFoN3tOITyMRL7F
 5T/l2C4COZJBevGtQyd/uAGrrVU/57Ro9Ly7qchHINpWYFbnE5YkKTA3IyUIWQdz
 9i36Szd8WGXgngh1z0Mz
 =bYQm
 -----END PGP SIGNATURE-----

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

First batch of s390x patches for 2.7:
- The new machine for 2.7
- Make use of the runtime instrumentation support introduced in
  the kernel
- Enhance our ipl (boot) process: We can now start from devices
  in subchannel sets > 0 as well. As a bonus, the conversion to
  diag308 in the bios allows us to get rid of the gr7 hack.
- Xiaoqiang Zhao's SCLP qomification patches
- Several fixes in the s390x pci implementation

# gpg: Signature made Tue 17 May 2016 15:35:32 BST using RSA key ID C6F02FAF
# gpg: Good signature from "Cornelia Huck <huckc@linux.vnet.ibm.com>"
# gpg:                 aka "Cornelia Huck <cornelia.huck@de.ibm.com>"

* remotes/cohuck/tags/s390x-20160517:
  s390x/pci: remove whitespace
  s390x/pci: add length checking for pci sclp handlers
  s390x/pci: enhance mpcifc_service_call
  s390x/pci: fix s390_pci_sclp_deconfigure
  s390x/pci: introduce S390PCIBusDevice.iommu_enabled
  s390x/pci: export pci_dereg_ioat and pci_dereg_irqs
  s390x/pci: separate s390_pcihost_iommu_configure function
  s390x/pci: separate s390_sclp_configure function
  s390x/pci: fix reg_irqs()
  hw/char: QOM'ify sclpconsole.c
  hw/char: QOM'ify sclpconsole-lm.c
  s390x/ipl: Remove redundant usage of gr7
  s390-ccw.img: rebuild image
  pc-bios/s390-ccw: Get device address via diag 308/6
  s390x/ipl: Add ssid field to IplParameterBlock
  s390x/ipl: Provide ipl parameter block
  s390x/ipl: Add type and length checks for IplParameterBlock values
  s390x/ipl: Extend the IplParameterBlock struct
  s390x: enable runtime instrumentation
  s390x: add compat machine for 2.7

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
master
Peter Maydell 2016-05-17 16:49:11 +01:00
commit a257c74149
22 changed files with 493 additions and 98 deletions

View File

@ -44,6 +44,10 @@ typedef struct SCLPConsoleLM {
uint8_t buf[SIZE_CONSOLE_BUFFER];
} SCLPConsoleLM;
#define TYPE_SCLPLM_CONSOLE "sclplmconsole"
#define SCLPLM_CONSOLE(obj) \
OBJECT_CHECK(SCLPConsoleLM, (obj), TYPE_SCLPLM_CONSOLE)
/*
* Character layer call-back functions
*
@ -116,7 +120,7 @@ static int get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size,
{
int len;
SCLPConsoleLM *cons = DO_UPCAST(SCLPConsoleLM, event, event);
SCLPConsoleLM *cons = SCLPLM_CONSOLE(event);
len = cons->length;
/* data need to fit into provided SCLP buffer */
@ -190,7 +194,7 @@ static int write_console_data(SCLPEvent *event, const uint8_t *buf, int len)
int ret = 0;
const uint8_t *buf_offset;
SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event);
SCLPConsoleLM *scon = SCLPLM_CONSOLE(event);
if (!scon->chr) {
/* If there's no backend, we can just say we consumed all data. */
@ -244,7 +248,7 @@ static int write_event_data(SCLPEvent *event, EventBufferHeader *ebh)
int errors = 0;
MDBO *mdbo;
SclpMsg *data = (SclpMsg *) ebh;
SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event);
SCLPConsoleLM *scon = SCLPLM_CONSOLE(event);
len = be16_to_cpu(data->mdb.header.length);
if (len < sizeof(data->mdb.header)) {
@ -313,7 +317,7 @@ static int console_init(SCLPEvent *event)
{
static bool console_available;
SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event);
SCLPConsoleLM *scon = SCLPLM_CONSOLE(event);
if (console_available) {
error_report("Multiple line-mode operator consoles are not supported");
@ -336,7 +340,7 @@ static int console_exit(SCLPEvent *event)
static void console_reset(DeviceState *dev)
{
SCLPEvent *event = SCLP_EVENT(dev);
SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event);
SCLPConsoleLM *scon = SCLPLM_CONSOLE(event);
event->event_pending = false;
scon->length = 0;

View File

@ -40,6 +40,10 @@ typedef struct SCLPConsole {
bool notify; /* qemu_notify_event() req'd if true */
} SCLPConsole;
#define TYPE_SCLP_CONSOLE "sclpconsole"
#define SCLP_CONSOLE(obj) \
OBJECT_CHECK(SCLPConsole, (obj), TYPE_SCLP_CONSOLE)
/* character layer call-back functions */
/* Return number of bytes that fit into iov buffer */
@ -95,7 +99,7 @@ static unsigned int receive_mask(void)
static void get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size,
int avail)
{
SCLPConsole *cons = DO_UPCAST(SCLPConsole, event, event);
SCLPConsole *cons = SCLP_CONSOLE(event);
/* first byte is hex 0 saying an ascii string follows */
*buf++ = '\0';
@ -157,7 +161,7 @@ static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
static ssize_t write_console_data(SCLPEvent *event, const uint8_t *buf,
size_t len)
{
SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
SCLPConsole *scon = SCLP_CONSOLE(event);
if (!scon->chr) {
/* If there's no backend, we can just say we consumed all data. */
@ -214,7 +218,7 @@ static int console_init(SCLPEvent *event)
{
static bool console_available;
SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
SCLPConsole *scon = SCLP_CONSOLE(event);
if (console_available) {
error_report("Multiple VT220 operator consoles are not supported");
@ -232,7 +236,7 @@ static int console_init(SCLPEvent *event)
static void console_reset(DeviceState *dev)
{
SCLPEvent *event = SCLP_EVENT(dev);
SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
SCLPConsole *scon = SCLP_CONSOLE(event);
event->event_pending = false;
scon->iov_sclp = 0;

View File

@ -30,6 +30,24 @@
#define ZIPL_IMAGE_START 0x009000UL
#define IPL_PSW_MASK (PSW_MASK_32 | PSW_MASK_64)
static bool iplb_extended_needed(void *opaque)
{
S390IPLState *ipl = S390_IPL(object_resolve_path(TYPE_S390_IPL, NULL));
return ipl->iplbext_migration;
}
static const VMStateDescription vmstate_iplb_extended = {
.name = "ipl/iplb_extended",
.version_id = 0,
.minimum_version_id = 0,
.needed = iplb_extended_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT8_ARRAY(reserved_ext, IplParameterBlock, 4096 - 200),
VMSTATE_END_OF_LIST()
}
};
static const VMStateDescription vmstate_iplb = {
.name = "ipl/iplb",
.version_id = 0,
@ -39,6 +57,10 @@ static const VMStateDescription vmstate_iplb = {
VMSTATE_UINT16(devno, IplParameterBlock),
VMSTATE_UINT8_ARRAY(reserved2, IplParameterBlock, 88),
VMSTATE_END_OF_LIST()
},
.subsections = (const VMStateDescription*[]) {
&vmstate_iplb_extended,
NULL
}
};
@ -181,46 +203,32 @@ static Property s390_ipl_properties[] = {
DEFINE_PROP_STRING("cmdline", S390IPLState, cmdline),
DEFINE_PROP_STRING("firmware", S390IPLState, firmware),
DEFINE_PROP_BOOL("enforce_bios", S390IPLState, enforce_bios, false),
DEFINE_PROP_BOOL("iplbext_migration", S390IPLState, iplbext_migration,
true),
DEFINE_PROP_END_OF_LIST(),
};
/*
* In addition to updating the iplstate, this function returns:
* - 0 if system was ipled with external kernel
* - -1 if no valid boot device was found
* - ccw id of the boot device otherwise
*/
static uint64_t s390_update_iplstate(S390IPLState *ipl)
static bool s390_gen_initial_iplb(S390IPLState *ipl)
{
DeviceState *dev_st;
if (ipl->iplb_valid) {
ipl->cssid = 0;
ipl->ssid = 0;
ipl->devno = ipl->iplb.devno;
goto out;
}
if (ipl->kernel) {
return 0;
}
dev_st = get_boot_device(0);
if (dev_st) {
VirtioCcwDevice *ccw_dev = (VirtioCcwDevice *) object_dynamic_cast(
OBJECT(qdev_get_parent_bus(dev_st)->parent),
TYPE_VIRTIO_CCW_DEVICE);
if (ccw_dev) {
ipl->cssid = ccw_dev->sch->cssid;
ipl->ssid = ccw_dev->sch->ssid;
ipl->devno = ccw_dev->sch->devno;
goto out;
ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_CCW_LEN);
ipl->iplb.blk0_len =
cpu_to_be32(S390_IPLB_MIN_CCW_LEN - S390_IPLB_HEADER_LEN);
ipl->iplb.pbt = S390_IPL_TYPE_CCW;
ipl->iplb.ccw.devno = cpu_to_be16(ccw_dev->sch->devno);
ipl->iplb.ccw.ssid = ccw_dev->sch->ssid & 3;
return true;
}
}
return -1;
out:
return (uint32_t) (ipl->cssid << 24 | ipl->ssid << 16 | ipl->devno);
return false;
}
void s390_ipl_update_diag308(IplParameterBlock *iplb)
@ -258,7 +266,9 @@ void s390_ipl_prepare_cpu(S390CPU *cpu)
if (!ipl->kernel || ipl->iplb_valid) {
cpu->env.psw.addr = ipl->bios_start_addr;
cpu->env.regs[7] = s390_update_iplstate(ipl);
if (!ipl->iplb_valid) {
ipl->iplb_valid = s390_gen_initial_iplb(ipl);
}
}
}
@ -268,6 +278,7 @@ static void s390_ipl_reset(DeviceState *dev)
if (!ipl->reipl_requested) {
ipl->iplb_valid = false;
memset(&ipl->iplb, 0, sizeof(IplParameterBlock));
}
ipl->reipl_requested = false;
}

View File

@ -15,11 +15,60 @@
#include "hw/qdev.h"
#include "cpu.h"
typedef struct IplParameterBlock {
uint8_t reserved1[110];
uint16_t devno;
uint8_t reserved2[88];
} IplParameterBlock;
struct IplBlockCcw {
uint8_t reserved0[85];
uint8_t ssid;
uint16_t devno;
uint8_t vm_flags;
uint8_t reserved3[3];
uint32_t vm_parm_len;
uint8_t nss_name[8];
uint8_t vm_parm[64];
uint8_t reserved4[8];
} QEMU_PACKED;
typedef struct IplBlockCcw IplBlockCcw;
struct IplBlockFcp {
uint8_t reserved1[305 - 1];
uint8_t opt;
uint8_t reserved2[3];
uint16_t reserved3;
uint16_t devno;
uint8_t reserved4[4];
uint64_t wwpn;
uint64_t lun;
uint32_t bootprog;
uint8_t reserved5[12];
uint64_t br_lba;
uint32_t scp_data_len;
uint8_t reserved6[260];
uint8_t scp_data[];
} QEMU_PACKED;
typedef struct IplBlockFcp IplBlockFcp;
union IplParameterBlock {
struct {
uint32_t len;
uint8_t reserved0[3];
uint8_t version;
uint32_t blk0_len;
uint8_t pbt;
uint8_t flags;
uint16_t reserved01;
uint8_t loadparm[8];
union {
IplBlockCcw ccw;
IplBlockFcp fcp;
};
} QEMU_PACKED;
struct {
uint8_t reserved1[110];
uint16_t devno;
uint8_t reserved2[88];
uint8_t reserved_ext[4096 - 200];
} QEMU_PACKED;
} QEMU_PACKED;
typedef union IplParameterBlock IplParameterBlock;
void s390_ipl_update_diag308(IplParameterBlock *iplb);
void s390_ipl_prepare_cpu(S390CPU *cpu);
@ -47,7 +96,32 @@ struct S390IPLState {
uint8_t cssid;
uint8_t ssid;
uint16_t devno;
bool iplbext_migration;
};
typedef struct S390IPLState S390IPLState;
#define S390_IPL_TYPE_FCP 0x00
#define S390_IPL_TYPE_CCW 0x02
#define S390_IPLB_HEADER_LEN 8
#define S390_IPLB_MIN_CCW_LEN 200
#define S390_IPLB_MIN_FCP_LEN 384
static inline bool iplb_valid_len(IplParameterBlock *iplb)
{
return be32_to_cpu(iplb->len) <= sizeof(IplParameterBlock);
}
static inline bool iplb_valid_ccw(IplParameterBlock *iplb)
{
return be32_to_cpu(iplb->len) >= S390_IPLB_MIN_CCW_LEN &&
iplb->pbt == S390_IPL_TYPE_CCW;
}
static inline bool iplb_valid_fcp(IplParameterBlock *iplb)
{
return be32_to_cpu(iplb->len) >= S390_IPLB_MIN_FCP_LEN &&
iplb->pbt == S390_IPL_TYPE_FCP;
}
#endif

View File

@ -15,6 +15,7 @@
#include "qemu-common.h"
#include "cpu.h"
#include "s390-pci-bus.h"
#include "s390-pci-inst.h"
#include <hw/pci/pci_bus.h>
#include <hw/pci/msi.h>
#include <qemu/error-report.h>
@ -106,25 +107,61 @@ S390PCIBusDevice *s390_pci_find_dev_by_fid(uint32_t fid)
return NULL;
}
void s390_pci_sclp_configure(int configure, SCCB *sccb)
void s390_pci_sclp_configure(SCCB *sccb)
{
PciCfgSccb *psccb = (PciCfgSccb *)sccb;
S390PCIBusDevice *pbdev = s390_pci_find_dev_by_fid(be32_to_cpu(psccb->aid));
uint16_t rc;
if (be16_to_cpu(sccb->h.length) < 16) {
rc = SCLP_RC_INSUFFICIENT_SCCB_LENGTH;
goto out;
}
if (pbdev) {
if ((configure == 1 && pbdev->configured == true) ||
(configure == 0 && pbdev->configured == false)) {
if (pbdev->configured) {
rc = SCLP_RC_NO_ACTION_REQUIRED;
} else {
pbdev->configured = !pbdev->configured;
pbdev->configured = true;
rc = SCLP_RC_NORMAL_COMPLETION;
}
} else {
DPRINTF("sclp config %d no dev found\n", configure);
DPRINTF("sclp config no dev found\n");
rc = SCLP_RC_ADAPTER_ID_NOT_RECOGNIZED;
}
out:
psccb->header.response_code = cpu_to_be16(rc);
}
void s390_pci_sclp_deconfigure(SCCB *sccb)
{
PciCfgSccb *psccb = (PciCfgSccb *)sccb;
S390PCIBusDevice *pbdev = s390_pci_find_dev_by_fid(be32_to_cpu(psccb->aid));
uint16_t rc;
if (be16_to_cpu(sccb->h.length) < 16) {
rc = SCLP_RC_INSUFFICIENT_SCCB_LENGTH;
goto out;
}
if (pbdev) {
if (!pbdev->configured) {
rc = SCLP_RC_NO_ACTION_REQUIRED;
} else {
if (pbdev->summary_ind) {
pci_dereg_irqs(pbdev);
}
if (pbdev->iommu_enabled) {
pci_dereg_ioat(pbdev);
}
pbdev->configured = false;
rc = SCLP_RC_NORMAL_COMPLETION;
}
} else {
DPRINTF("sclp deconfig no dev found\n");
rc = SCLP_RC_ADAPTER_ID_NOT_RECOGNIZED;
}
out:
psccb->header.response_code = cpu_to_be16(rc);
}
@ -320,7 +357,8 @@ static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *iommu, hwaddr addr,
.perm = IOMMU_NONE,
};
if (!pbdev->configured || !pbdev->pdev || !(pbdev->fh & FH_ENABLED)) {
if (!pbdev->configured || !pbdev->pdev ||
!(pbdev->fh & FH_ENABLED) || !pbdev->iommu_enabled) {
return ret;
}
@ -458,20 +496,21 @@ static const MemoryRegionOps s390_msi_ctrl_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
void s390_pcihost_iommu_configure(S390PCIBusDevice *pbdev, bool enable)
void s390_pci_iommu_enable(S390PCIBusDevice *pbdev)
{
pbdev->configured = false;
uint64_t size = pbdev->pal - pbdev->pba + 1;
if (enable) {
uint64_t size = pbdev->pal - pbdev->pba + 1;
memory_region_init_iommu(&pbdev->iommu_mr, OBJECT(&pbdev->mr),
&s390_iommu_ops, "iommu-s390", size);
memory_region_add_subregion(&pbdev->mr, pbdev->pba, &pbdev->iommu_mr);
} else {
memory_region_del_subregion(&pbdev->mr, &pbdev->iommu_mr);
}
memory_region_init_iommu(&pbdev->iommu_mr, OBJECT(&pbdev->mr),
&s390_iommu_ops, "iommu-s390", size);
memory_region_add_subregion(&pbdev->mr, pbdev->pba, &pbdev->iommu_mr);
pbdev->iommu_enabled = true;
}
pbdev->configured = true;
void s390_pci_iommu_disable(S390PCIBusDevice *pbdev)
{
memory_region_del_subregion(&pbdev->mr, &pbdev->iommu_mr);
object_unparent(OBJECT(&pbdev->iommu_mr));
pbdev->iommu_enabled = false;
}
static void s390_pcihost_init_as(S390pciState *s)

View File

@ -198,11 +198,11 @@ typedef struct ChscSeiNt2Res {
} QEMU_PACKED ChscSeiNt2Res;
typedef struct PciCfgSccb {
SCCBHeader header;
uint8_t atype;
uint8_t reserved1;
uint16_t reserved2;
uint32_t aid;
SCCBHeader header;
uint8_t atype;
uint8_t reserved1;
uint16_t reserved2;
uint32_t aid;
} QEMU_PACKED PciCfgSccb;
typedef struct S390MsixInfo {
@ -219,6 +219,7 @@ typedef struct S390PCIBusDevice {
bool configured;
bool error_state;
bool lgstg_blocked;
bool iommu_enabled;
uint32_t fh;
uint32_t fid;
uint64_t g_iota;
@ -247,8 +248,10 @@ typedef struct S390pciState {
int chsc_sei_nt2_get_event(void *res);
int chsc_sei_nt2_have_event(void);
void s390_pci_sclp_configure(int configure, SCCB *sccb);
void s390_pcihost_iommu_configure(S390PCIBusDevice *pbdev, bool enable);
void s390_pci_sclp_configure(SCCB *sccb);
void s390_pci_sclp_deconfigure(SCCB *sccb);
void s390_pci_iommu_enable(S390PCIBusDevice *pbdev);
void s390_pci_iommu_disable(S390PCIBusDevice *pbdev);
S390PCIBusDevice *s390_pci_find_dev_by_idx(uint32_t idx);
S390PCIBusDevice *s390_pci_find_dev_by_fh(uint32_t fh);
S390PCIBusDevice *s390_pci_find_dev_by_fid(uint32_t fid);

View File

@ -634,8 +634,15 @@ static int reg_irqs(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib)
len = BITS_TO_LONGS(FIB_DATA_NOI(ldl_p(&fib.data))) * sizeof(unsigned long);
pbdev->indicator = get_indicator(ldq_p(&fib.aibv), len);
map_indicator(&pbdev->routes.adapter, pbdev->summary_ind);
map_indicator(&pbdev->routes.adapter, pbdev->indicator);
ret = map_indicator(&pbdev->routes.adapter, pbdev->summary_ind);
if (ret) {
goto out;
}
ret = map_indicator(&pbdev->routes.adapter, pbdev->indicator);
if (ret) {
goto out;
}
pbdev->routes.adapter.summary_addr = ldq_p(&fib.aisb);
pbdev->routes.adapter.summary_offset = FIB_DATA_AISBO(ldl_p(&fib.data));
@ -647,9 +654,15 @@ static int reg_irqs(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib)
DPRINTF("reg_irqs adapter id %d\n", pbdev->routes.adapter.adapter_id);
return 0;
out:
release_indicator(&pbdev->routes.adapter, pbdev->summary_ind);
release_indicator(&pbdev->routes.adapter, pbdev->indicator);
pbdev->summary_ind = NULL;
pbdev->indicator = NULL;
return ret;
}
static int dereg_irqs(S390PCIBusDevice *pbdev)
int pci_dereg_irqs(S390PCIBusDevice *pbdev)
{
release_indicator(&pbdev->routes.adapter, pbdev->summary_ind);
release_indicator(&pbdev->routes.adapter, pbdev->indicator);
@ -692,24 +705,23 @@ static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib)
pbdev->pal = pal;
pbdev->g_iota = g_iota;
s390_pcihost_iommu_configure(pbdev, true);
s390_pci_iommu_enable(pbdev);
return 0;
}
static void dereg_ioat(S390PCIBusDevice *pbdev)
void pci_dereg_ioat(S390PCIBusDevice *pbdev)
{
s390_pci_iommu_disable(pbdev);
pbdev->pba = 0;
pbdev->pal = 0;
pbdev->g_iota = 0;
s390_pcihost_iommu_configure(pbdev, false);
}
int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
{
CPUS390XState *env = &cpu->env;
uint8_t oc;
uint8_t oc, dmaas;
uint32_t fh;
ZpciFib fib;
S390PCIBusDevice *pbdev;
@ -721,6 +733,7 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
}
oc = env->regs[r1] & 0xff;
dmaas = (env->regs[r1] >> 16) & 0xff;
fh = env->regs[r1] >> 32;
if (fiba & 0x7) {
@ -739,27 +752,65 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
return 0;
}
if (fib.fmt != 0) {
program_interrupt(env, PGM_OPERAND, 6);
return 0;
}
switch (oc) {
case ZPCI_MOD_FC_REG_INT:
if (reg_irqs(env, pbdev, fib)) {
if (pbdev->summary_ind) {
cc = ZPCI_PCI_LS_ERR;
s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
} else if (reg_irqs(env, pbdev, fib)) {
cc = ZPCI_PCI_LS_ERR;
s390_set_status_code(env, r1, ZPCI_MOD_ST_RES_NOT_AVAIL);
}
break;
case ZPCI_MOD_FC_DEREG_INT:
dereg_irqs(pbdev);
if (!pbdev->summary_ind) {
cc = ZPCI_PCI_LS_ERR;
s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
} else {
pci_dereg_irqs(pbdev);
}
break;
case ZPCI_MOD_FC_REG_IOAT:
if (reg_ioat(env, pbdev, fib)) {
if (dmaas != 0) {
cc = ZPCI_PCI_LS_ERR;
s390_set_status_code(env, r1, ZPCI_MOD_ST_DMAAS_INVAL);
} else if (pbdev->iommu_enabled) {
cc = ZPCI_PCI_LS_ERR;
s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
} else if (reg_ioat(env, pbdev, fib)) {
cc = ZPCI_PCI_LS_ERR;
s390_set_status_code(env, r1, ZPCI_MOD_ST_INSUF_RES);
}
break;
case ZPCI_MOD_FC_DEREG_IOAT:
dereg_ioat(pbdev);
if (dmaas != 0) {
cc = ZPCI_PCI_LS_ERR;
s390_set_status_code(env, r1, ZPCI_MOD_ST_DMAAS_INVAL);
} else if (!pbdev->iommu_enabled) {
cc = ZPCI_PCI_LS_ERR;
s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
} else {
pci_dereg_ioat(pbdev);
}
break;
case ZPCI_MOD_FC_REREG_IOAT:
dereg_ioat(pbdev);
if (reg_ioat(env, pbdev, fib)) {
if (dmaas != 0) {
cc = ZPCI_PCI_LS_ERR;
s390_set_status_code(env, r1, ZPCI_MOD_ST_DMAAS_INVAL);
} else if (!pbdev->iommu_enabled) {
cc = ZPCI_PCI_LS_ERR;
s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
} else {
pci_dereg_ioat(pbdev);
if (reg_ioat(env, pbdev, fib)) {
cc = ZPCI_PCI_LS_ERR;
s390_set_status_code(env, r1, ZPCI_MOD_ST_INSUF_RES);
}
}
break;
case ZPCI_MOD_FC_RESET_ERROR:

View File

@ -14,6 +14,7 @@
#ifndef HW_S390_PCI_INST_H
#define HW_S390_PCI_INST_H
#include "s390-pci-bus.h"
#include <sysemu/dma.h>
/* CLP common request & response block size */
@ -230,6 +231,14 @@ typedef struct ClpReqRspQueryPciGrp {
#define ZPCI_PCI_LS_BUSY 2
#define ZPCI_PCI_LS_INVAL_HANDLE 3
/* Modify PCI status codes */
#define ZPCI_MOD_ST_RES_NOT_AVAIL 4
#define ZPCI_MOD_ST_INSUF_RES 16
#define ZPCI_MOD_ST_SEQUENCE 24
#define ZPCI_MOD_ST_DMAAS_INVAL 28
#define ZPCI_MOD_ST_FRAME_INVAL 32
#define ZPCI_MOD_ST_ERROR_RECOVER 40
/* Modify PCI Function Controls */
#define ZPCI_MOD_FC_REG_INT 2
#define ZPCI_MOD_FC_DEREG_INT 3
@ -277,6 +286,8 @@ typedef struct ZpciFib {
uint32_t gd;
} QEMU_PACKED ZpciFib;
int pci_dereg_irqs(S390PCIBusDevice *pbdev);
void pci_dereg_ioat(S390PCIBusDevice *pbdev);
int clp_service_call(S390CPU *cpu, uint8_t r2);
int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2);
int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2);

View File

@ -25,6 +25,7 @@
#include "s390-pci-bus.h"
#include "hw/s390x/storage-keys.h"
#include "hw/compat.h"
#include "ipl.h"
#include "hw/s390x/s390-virtio-ccw.h"
static const char *const reset_dev_types[] = {
@ -190,7 +191,9 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data)
MachineClass *mc = MACHINE_CLASS(oc);
NMIClass *nc = NMI_CLASS(oc);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
s390mc->ri_allowed = true;
mc->init = ccw_init;
mc->reset = s390_machine_reset;
mc->hot_add_cpu = s390_hot_add_cpu;
@ -237,6 +240,20 @@ static inline void machine_set_dea_key_wrap(Object *obj, bool value,
ms->dea_key_wrap = value;
}
bool ri_allowed(void)
{
if (kvm_enabled()) {
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->ri_allowed;
}
}
return 0;
}
static inline void s390_machine_initfn(Object *obj)
{
object_property_add_bool(obj, "aes-key-wrap",
@ -262,6 +279,7 @@ static const TypeInfo ccw_machine_info = {
.abstract = true,
.instance_size = sizeof(S390CcwMachineState),
.instance_init = s390_machine_initfn,
.class_size = sizeof(S390CcwMachineClass),
.class_init = ccw_machine_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_NMI },
@ -299,7 +317,16 @@ static const TypeInfo ccw_machine_info = {
} \
type_init(ccw_machine_register_##suffix)
#define CCW_COMPAT_2_6 \
HW_COMPAT_2_6 \
{\
.driver = TYPE_S390_IPL,\
.property = "iplbext_migration",\
.value = "off",\
},
#define CCW_COMPAT_2_5 \
CCW_COMPAT_2_6 \
HW_COMPAT_2_5
#define CCW_COMPAT_2_4 \
@ -343,21 +370,38 @@ static const TypeInfo ccw_machine_info = {
.value = "0",\
},
static void ccw_machine_2_7_instance_options(MachineState *machine)
{
}
static void ccw_machine_2_7_class_options(MachineClass *mc)
{
}
DEFINE_CCW_MACHINE(2_7, "2.7", true);
static void ccw_machine_2_6_instance_options(MachineState *machine)
{
ccw_machine_2_7_instance_options(machine);
}
static void ccw_machine_2_6_class_options(MachineClass *mc)
{
S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
s390mc->ri_allowed = false;
ccw_machine_2_7_class_options(mc);
SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_6);
}
DEFINE_CCW_MACHINE(2_6, "2.6", true);
DEFINE_CCW_MACHINE(2_6, "2.6", false);
static void ccw_machine_2_5_instance_options(MachineState *machine)
{
ccw_machine_2_6_instance_options(machine);
}
static void ccw_machine_2_5_class_options(MachineClass *mc)
{
ccw_machine_2_6_class_options(mc);
SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_5);
}
DEFINE_CCW_MACHINE(2_5, "2.5", false);
@ -369,6 +413,7 @@ static void ccw_machine_2_4_instance_options(MachineState *machine)
static void ccw_machine_2_4_class_options(MachineClass *mc)
{
ccw_machine_2_5_class_options(mc);
SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_4);
}
DEFINE_CCW_MACHINE(2_4, "2.4", false);

View File

@ -357,10 +357,10 @@ static void sclp_execute(SCLPDevice *sclp, SCCB *sccb, uint32_t code)
sclp_c->unassign_storage(sclp, sccb);
break;
case SCLP_CMDW_CONFIGURE_PCI:
s390_pci_sclp_configure(1, sccb);
s390_pci_sclp_configure(sccb);
break;
case SCLP_CMDW_DECONFIGURE_PCI:
s390_pci_sclp_configure(0, sccb);
s390_pci_sclp_deconfigure(sccb);
break;
default:
efc->command_handler(ef, sccb, code);

View File

@ -1,6 +1,9 @@
#ifndef HW_COMPAT_H
#define HW_COMPAT_H
#define HW_COMPAT_2_6 \
/* empty */
#define HW_COMPAT_2_5 \
{\
.driver = "isa-fdc",\

View File

@ -35,6 +35,10 @@ typedef struct S390CcwMachineClass {
MachineClass parent_class;
/*< public >*/
bool ri_allowed;
} S390CcwMachineClass;
/* runtime-instrumentation allowed by the machine */
bool ri_allowed(void);
#endif

Binary file not shown.

79
pc-bios/s390-ccw/iplb.h Normal file
View File

@ -0,0 +1,79 @@
/*
* QEMU S390 IPL Block
*
* Copyright 2015 IBM Corp.
* Author(s): Alexander Yarygin <yarygin@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 IPLB_H
#define IPLB_H
struct IplBlockCcw {
uint8_t reserved0[85];
uint8_t ssid;
uint16_t devno;
uint8_t vm_flags;
uint8_t reserved3[3];
uint32_t vm_parm_len;
uint8_t nss_name[8];
uint8_t vm_parm[64];
uint8_t reserved4[8];
} __attribute__ ((packed));
typedef struct IplBlockCcw IplBlockCcw;
struct IplBlockFcp {
uint8_t reserved1[305 - 1];
uint8_t opt;
uint8_t reserved2[3];
uint16_t reserved3;
uint16_t devno;
uint8_t reserved4[4];
uint64_t wwpn;
uint64_t lun;
uint32_t bootprog;
uint8_t reserved5[12];
uint64_t br_lba;
uint32_t scp_data_len;
uint8_t reserved6[260];
uint8_t scp_data[];
} __attribute__ ((packed));
typedef struct IplBlockFcp IplBlockFcp;
struct IplParameterBlock {
uint32_t len;
uint8_t reserved0[3];
uint8_t version;
uint32_t blk0_len;
uint8_t pbt;
uint8_t flags;
uint16_t reserved01;
uint8_t loadparm[8];
union {
IplBlockCcw ccw;
IplBlockFcp fcp;
};
} __attribute__ ((packed));
typedef struct IplParameterBlock IplParameterBlock;
extern IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
#define S390_IPL_TYPE_FCP 0x00
#define S390_IPL_TYPE_CCW 0x02
static inline bool store_iplb(IplParameterBlock *iplb)
{
register unsigned long addr asm("0") = (unsigned long) iplb;
register unsigned long rc asm("1") = 0;
asm volatile ("diag %0,%2,0x308\n"
: "+d" (addr), "+d" (rc)
: "d" (6)
: "memory", "cc");
return rc == 0x01;
}
#endif /* IPLB_H */

View File

@ -12,8 +12,8 @@
#include "virtio.h"
char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
uint64_t boot_value;
static SubChannelId blk_schid = { .one = 1 };
IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
/*
* Priniciples of Operations (SA22-7832-09) chapter 17 requires that
@ -61,7 +61,7 @@ static bool find_dev(Schib *schib, int dev_no)
return false;
}
static void virtio_setup(uint64_t dev_info)
static void virtio_setup(void)
{
Schib schib;
int ssid;
@ -75,12 +75,18 @@ static void virtio_setup(uint64_t dev_info)
*/
enable_mss_facility();
if (dev_info != -1) {
dev_no = dev_info & 0xffff;
debug_print_int("device no. ", dev_no);
blk_schid.ssid = (dev_info >> 16) & 0x3;
debug_print_int("ssid ", blk_schid.ssid);
found = find_dev(&schib, dev_no);
if (store_iplb(&iplb)) {
switch (iplb.pbt) {
case S390_IPL_TYPE_CCW:
dev_no = iplb.ccw.devno;
debug_print_int("device no. ", dev_no);
blk_schid.ssid = iplb.ccw.ssid & 0x3;
debug_print_int("ssid ", blk_schid.ssid);
found = find_dev(&schib, dev_no);
break;
default:
panic("List-directed IPL not supported yet!\n");
}
} else {
for (ssid = 0; ssid < 0x3; ssid++) {
blk_schid.ssid = ssid;
@ -101,8 +107,7 @@ static void virtio_setup(uint64_t dev_info)
int main(void)
{
sclp_setup();
debug_print_int("boot reg[7] ", boot_value);
virtio_setup(boot_value);
virtio_setup();
zipl_load(); /* no return */

View File

@ -44,6 +44,7 @@ typedef unsigned long long __u64;
#endif
#include "cio.h"
#include "iplb.h"
typedef struct irb Irb;
typedef struct ccw1 Ccw1;
@ -61,7 +62,6 @@ void consume_sclp_int(void);
void panic(const char *string);
void write_subsystem_identification(void);
extern char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
extern uint64_t boot_value;
/* sclp-ascii.c */
void sclp_print(const char *string);

View File

@ -14,8 +14,6 @@
_start:
larl %r15, stack + 0x8000 /* Set up stack */
larl %r6, boot_value
stg %r7, 0(%r6) /* save the boot_value before any function calls */
j main /* And call C */
/*

View File

@ -135,6 +135,8 @@ typedef struct CPUS390XState {
uint64_t gbea;
uint64_t pp;
uint8_t riccb[64];
CPU_COMMON
/* reset does memset(0) up to here */
@ -1159,6 +1161,7 @@ void kvm_s390_reset_vcpu(S390CPU *cpu);
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);
int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu);
int kvm_s390_get_ri(void);
void kvm_s390_crypto_reset(void);
#else
static inline void kvm_s390_io_interrupt(uint16_t subchannel_id,
@ -1209,6 +1212,10 @@ static inline int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu)
{
return 0;
}
static inline int kvm_s390_get_ri(void)
{
return 0;
}
static inline void kvm_s390_crypto_reset(void)
{
}
@ -1272,11 +1279,22 @@ static inline bool vregs_needed(void *opaque)
}
return 0;
}
static inline bool riccb_needed(void *opaque)
{
if (kvm_enabled()) {
return kvm_s390_get_ri();
}
return 0;
}
#else
static inline bool vregs_needed(void *opaque)
{
return 0;
}
static inline bool riccb_needed(void *opaque)
{
return 0;
}
#endif
/* machine check interruption code */

View File

@ -509,6 +509,7 @@ static void ioinst_handle_chsc_scsc(ChscReq *req, ChscResp *res)
general_chars[0] = cpu_to_be32(0x03000000);
general_chars[1] = cpu_to_be32(0x00059000);
general_chars[3] = cpu_to_be32(0x00080000);
chsc_chars[0] = cpu_to_be32(0x40000000);
chsc_chars[3] = cpu_to_be32(0x00040000);

View File

@ -46,6 +46,7 @@
#include "hw/s390x/ipl.h"
#include "hw/s390x/ebcdic.h"
#include "exec/memattrs.h"
#include "hw/s390x/s390-virtio-ccw.h"
/* #define DEBUG_KVM */
@ -135,6 +136,7 @@ static int cap_sync_regs;
static int cap_async_pf;
static int cap_mem_op;
static int cap_s390_irq;
static int cap_ri;
static void *legacy_s390_alloc(size_t size, uint64_t *align);
@ -270,6 +272,11 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
kvm_vm_enable_cap(s, KVM_CAP_S390_USER_SIGP, 0);
kvm_vm_enable_cap(s, KVM_CAP_S390_VECTOR_REGISTERS, 0);
kvm_vm_enable_cap(s, KVM_CAP_S390_USER_STSI, 0);
if (ri_allowed()) {
if (kvm_vm_enable_cap(s, KVM_CAP_S390_RI, 0) == 0) {
cap_ri = 1;
}
}
return 0;
}
@ -386,6 +393,11 @@ int kvm_arch_put_registers(CPUState *cs, int level)
kvm_set_one_reg(cs, KVM_REG_S390_PP, &env->pp);
}
if (can_sync_regs(cs, KVM_SYNC_RICCB)) {
memcpy(cs->kvm_run->s.regs.riccb, env->riccb, 64);
cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_RICCB;
}
/* pfault parameters */
if (can_sync_regs(cs, KVM_SYNC_PFAULT)) {
cs->kvm_run->s.regs.pft = env->pfault_token;
@ -528,6 +540,10 @@ int kvm_arch_get_registers(CPUState *cs)
kvm_get_one_reg(cs, KVM_REG_S390_PP, &env->pp);
}
if (can_sync_regs(cs, KVM_SYNC_RICCB)) {
memcpy(env->riccb, cs->kvm_run->s.regs.riccb, 64);
}
/* pfault parameters */
if (can_sync_regs(cs, KVM_SYNC_PFAULT)) {
env->pfault_token = cs->kvm_run->s.regs.pft;
@ -2136,6 +2152,11 @@ int kvm_s390_get_memslot_count(KVMState *s)
return kvm_check_extension(s, KVM_CAP_NR_MEMSLOTS);
}
int kvm_s390_get_ri(void)
{
return cap_ri;
}
int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state)
{
struct kvm_mp_state mp_state = {};

View File

@ -135,6 +135,17 @@ static const VMStateDescription vmstate_vregs = {
}
};
const VMStateDescription vmstate_riccb = {
.name = "cpu/riccb",
.version_id = 1,
.minimum_version_id = 1,
.needed = riccb_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT8_ARRAY(env.riccb, S390CPU, 64),
VMSTATE_END_OF_LIST()
}
};
const VMStateDescription vmstate_s390_cpu = {
.name = "cpu",
.post_load = cpu_post_load,
@ -166,6 +177,7 @@ const VMStateDescription vmstate_s390_cpu = {
.subsections = (const VMStateDescription*[]) {
&vmstate_fpu,
&vmstate_vregs,
&vmstate_riccb,
NULL
},
};

View File

@ -232,10 +232,23 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3)
program_interrupt(env, PGM_ADDRESSING, ILEN_LATER_INC);
return;
}
iplb = g_malloc0(sizeof(struct IplParameterBlock));
cpu_physical_memory_read(addr, iplb, sizeof(struct IplParameterBlock));
iplb = g_malloc0(sizeof(IplParameterBlock));
cpu_physical_memory_read(addr, iplb, sizeof(iplb->len));
if (!iplb_valid_len(iplb)) {
env->regs[r1 + 1] = DIAG_308_RC_INVALID;
goto out;
}
cpu_physical_memory_read(addr, iplb, be32_to_cpu(iplb->len));
if (!iplb_valid_ccw(iplb) && !iplb_valid_fcp(iplb)) {
env->regs[r1 + 1] = DIAG_308_RC_INVALID;
goto out;
}
s390_ipl_update_diag308(iplb);
env->regs[r1 + 1] = DIAG_308_RC_OK;
out:
g_free(iplb);
return;
case 6:
@ -250,8 +263,7 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3)
}
iplb = s390_ipl_get_iplb();
if (iplb) {
cpu_physical_memory_write(addr, iplb,
sizeof(struct IplParameterBlock));
cpu_physical_memory_write(addr, iplb, be32_to_cpu(iplb->len));
env->regs[r1 + 1] = DIAG_308_RC_OK;
} else {
env->regs[r1 + 1] = DIAG_308_RC_NO_CONF;