Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20171006' int…
Browse files Browse the repository at this point in the history
…o staging

s390x changes:
- support for IDA (indirect addressing in ccws) via ccw data stream
- support for extended TOD-Clock (z14 feature)
- various fixes and improvements all over the place

# gpg: Signature made Fri 06 Oct 2017 10:52:22 BST
# gpg:                using RSA key 0xDECF6B93C6F02FAF
# gpg: Good signature from "Cornelia Huck <conny@cornelia-huck.de>"
# gpg:                 aka "Cornelia Huck <huckc@linux.vnet.ibm.com>"
# gpg:                 aka "Cornelia Huck <cornelia.huck@de.ibm.com>"
# gpg:                 aka "Cornelia Huck <cohuck@kernel.org>"
# gpg:                 aka "Cornelia Huck <cohuck@redhat.com>"
# Primary key fingerprint: C3D0 D66D C362 4FF6 A8C0  18CE DECF 6B93 C6F0 2FAF

* remotes/cohuck/tags/s390x-20171006: (33 commits)
  hw/s390x: Mark the "sclpquiesce" device with user_creatable = false
  s390x/tcg: initialize machine check queue
  s390x/sclp: mark sclp-cpu-hotplug as non-usercreatable
  s390x/sclp: Mark the sclp device with user_creatable = false
  s390/kvm: make TOD setting failures fatal for migration
  s390/kvm: Support for get/set of extended TOD-Clock for guest
  s390x/css: fix css migration compat handling
  s390x: sort some devices into categories
  s390x/tcg: make STFL store into the lowcore
  s390x: introduce and use S390_MAX_CPUS
  target/s390x: get rid of next_core_id
  s390x/cpumodel: fix max STFL(E) bit number
  s390x: raise CPU hotplug irq after really hotplugged
  MAINTAINERS: use KVM s390x maintainers for kvm-stubs.c and kvm_s390x.h
  s390x/3270: handle writes of arbitrary length
  s390x/3270: IDA support for 3270 via CcwDataStream
  Revert "s390x/ccw: create s390 phb conditionally"
  s390x/tcg: make idte/ipte use the new _real mmu
  s390x/tcg: make testblock use the new _real mmu
  s390x/tcg: make stora(g) use the new _real mmu
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
  • Loading branch information
pm215 committed Oct 6, 2017
2 parents d8f932c + b923ab3 commit a26a98d
Show file tree
Hide file tree
Showing 31 changed files with 730 additions and 295 deletions.
2 changes: 2 additions & 0 deletions MAINTAINERS
Expand Up @@ -299,6 +299,8 @@ M: Cornelia Huck <cohuck@redhat.com>
M: Alexander Graf <agraf@suse.de>
S: Maintained
F: target/s390x/kvm.c
F: target/s390x/kvm_s390x.h
F: target/s390x/kvm-stub.c
F: target/s390x/ioinst.[ch]
F: target/s390x/machine.c
F: hw/intc/s390_flic.c
Expand Down
46 changes: 28 additions & 18 deletions hw/char/terminal3270.c
Expand Up @@ -30,7 +30,6 @@ typedef struct Terminal3270 {
uint8_t inv[INPUT_BUFFER_SIZE];
uint8_t outv[OUTPUT_BUFFER_SIZE];
int in_len;
int out_len;
bool handshake_done;
guint timer_tag;
} Terminal3270;
Expand Down Expand Up @@ -145,7 +144,6 @@ static void chr_event(void *opaque, int event)

/* Ensure the initial status correct, always reset them. */
t->in_len = 0;
t->out_len = 0;
t->handshake_done = false;
if (t->timer_tag) {
g_source_remove(t->timer_tag);
Expand Down Expand Up @@ -182,14 +180,18 @@ static void terminal_init(EmulatedCcw3270Device *dev, Error **errp)
terminal_read, chr_event, NULL, t, NULL, true);
}

static int read_payload_3270(EmulatedCcw3270Device *dev, uint32_t cda,
uint16_t count)
static inline CcwDataStream *get_cds(Terminal3270 *t)
{
return &(CCW_DEVICE(&t->cdev)->sch->cds);
}

static int read_payload_3270(EmulatedCcw3270Device *dev)
{
Terminal3270 *t = TERMINAL_3270(dev);
int len;

len = MIN(count, t->in_len);
cpu_physical_memory_write(cda, t->inv, len);
len = MIN(ccw_dstream_avail(get_cds(t)), t->in_len);
ccw_dstream_write_buf(get_cds(t), t->inv, len);
t->in_len -= len;

return len;
Expand Down Expand Up @@ -222,13 +224,14 @@ static int insert_IAC_escape_char(uint8_t *outv, int out_len)
* Write 3270 outbound to socket.
* Return the count of 3270 data field if succeeded, zero if failed.
*/
static int write_payload_3270(EmulatedCcw3270Device *dev, uint8_t cmd,
uint32_t cda, uint16_t count)
static int write_payload_3270(EmulatedCcw3270Device *dev, uint8_t cmd)
{
Terminal3270 *t = TERMINAL_3270(dev);
int retval = 0;

assert(count <= (OUTPUT_BUFFER_SIZE - 3) / 2);
int count = ccw_dstream_avail(get_cds(t));
int bound = (OUTPUT_BUFFER_SIZE - 3) / 2;
int len = MIN(count, bound);
int out_len = 0;

if (!t->handshake_done) {
if (!(t->outv[0] == IAC && t->outv[1] != IAC)) {
Expand All @@ -243,16 +246,23 @@ static int write_payload_3270(EmulatedCcw3270Device *dev, uint8_t cmd,
/* We just say we consumed all data if there's no backend. */
return count;
}
t->outv[0] = cmd;
cpu_physical_memory_read(cda, &t->outv[1], count);
t->out_len = count + 1;

t->out_len = insert_IAC_escape_char(t->outv, t->out_len);
t->outv[t->out_len++] = IAC;
t->outv[t->out_len++] = IAC_EOR;
t->outv[out_len++] = cmd;
do {
ccw_dstream_read_buf(get_cds(t), &t->outv[out_len], len);
count = ccw_dstream_avail(get_cds(t));
out_len += len;

retval = qemu_chr_fe_write_all(&t->chr, t->outv, t->out_len);
return (retval <= 0) ? 0 : (retval - 3);
out_len = insert_IAC_escape_char(t->outv, out_len);
if (!count) {
t->outv[out_len++] = IAC;
t->outv[out_len++] = IAC_EOR;
}
retval = qemu_chr_fe_write_all(&t->chr, t->outv, out_len);
len = MIN(count, bound);
out_len = 0;
} while (len && retval >= 0);
return (retval <= 0) ? 0 : get_cds(t)->count;
}

static Property terminal_properties[] = {
Expand Down
5 changes: 3 additions & 2 deletions hw/s390x/3270-ccw.c
Expand Up @@ -28,7 +28,7 @@ static int handle_payload_3270_read(EmulatedCcw3270Device *dev, CCW1 *ccw)
return -EFAULT;
}

len = ck->read_payload_3270(dev, ccw->cda, ccw->count);
len = ck->read_payload_3270(dev);
ccw_dev->sch->curr_status.scsw.count = ccw->count - len;

return 0;
Expand All @@ -45,7 +45,7 @@ static int handle_payload_3270_write(EmulatedCcw3270Device *dev, CCW1 *ccw)
return -EFAULT;
}

len = ck->write_payload_3270(dev, ccw->cmd_code, ccw->cda, ccw->count);
len = ck->write_payload_3270(dev, ccw->cmd_code);

if (len <= 0) {
return -EIO;
Expand Down Expand Up @@ -160,6 +160,7 @@ static void emulated_ccw_3270_class_init(ObjectClass *klass, void *data)
dc->bus_type = TYPE_VIRTUAL_CSS_BUS;
dc->realize = emulated_ccw_3270_realize;
dc->hotpluggable = false;
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
}

static const TypeInfo emulated_ccw_3270_info = {
Expand Down
186 changes: 182 additions & 4 deletions hw/s390x/css.c
Expand Up @@ -787,6 +787,183 @@ static CCW1 copy_ccw_from_guest(hwaddr addr, bool fmt1)
}
return ret;
}
/**
* If out of bounds marks the stream broken. If broken returns -EINVAL,
* otherwise the requested length (may be zero)
*/
static inline int cds_check_len(CcwDataStream *cds, int len)
{
if (cds->at_byte + len > cds->count) {
cds->flags |= CDS_F_STREAM_BROKEN;
}
return cds->flags & CDS_F_STREAM_BROKEN ? -EINVAL : len;
}

static inline bool cds_ccw_addrs_ok(hwaddr addr, int len, bool ccw_fmt1)
{
return (addr + len) < (ccw_fmt1 ? (1UL << 31) : (1UL << 24));
}

static int ccw_dstream_rw_noflags(CcwDataStream *cds, void *buff, int len,
CcwDataStreamOp op)
{
int ret;

ret = cds_check_len(cds, len);
if (ret <= 0) {
return ret;
}
if (!cds_ccw_addrs_ok(cds->cda, len, cds->flags & CDS_F_FMT)) {
return -EINVAL; /* channel program check */
}
if (op == CDS_OP_A) {
goto incr;
}
ret = address_space_rw(&address_space_memory, cds->cda,
MEMTXATTRS_UNSPECIFIED, buff, len, op);
if (ret != MEMTX_OK) {
cds->flags |= CDS_F_STREAM_BROKEN;
return -EINVAL;
}
incr:
cds->at_byte += len;
cds->cda += len;
return 0;
}

/* returns values between 1 and bsz, where bsz is a power of 2 */
static inline uint16_t ida_continuous_left(hwaddr cda, uint64_t bsz)
{
return bsz - (cda & (bsz - 1));
}

static inline uint64_t ccw_ida_block_size(uint8_t flags)
{
if ((flags & CDS_F_C64) && !(flags & CDS_F_I2K)) {
return 1ULL << 12;
}
return 1ULL << 11;
}

static inline int ida_read_next_idaw(CcwDataStream *cds)
{
union {uint64_t fmt2; uint32_t fmt1; } idaw;
int ret;
hwaddr idaw_addr;
bool idaw_fmt2 = cds->flags & CDS_F_C64;
bool ccw_fmt1 = cds->flags & CDS_F_FMT;

if (idaw_fmt2) {
idaw_addr = cds->cda_orig + sizeof(idaw.fmt2) * cds->at_idaw;
if (idaw_addr & 0x07 || !cds_ccw_addrs_ok(idaw_addr, 0, ccw_fmt1)) {
return -EINVAL; /* channel program check */
}
ret = address_space_rw(&address_space_memory, idaw_addr,
MEMTXATTRS_UNSPECIFIED, (void *) &idaw.fmt2,
sizeof(idaw.fmt2), false);
cds->cda = be64_to_cpu(idaw.fmt2);
} else {
idaw_addr = cds->cda_orig + sizeof(idaw.fmt1) * cds->at_idaw;
if (idaw_addr & 0x03 || !cds_ccw_addrs_ok(idaw_addr, 0, ccw_fmt1)) {
return -EINVAL; /* channel program check */
}
ret = address_space_rw(&address_space_memory, idaw_addr,
MEMTXATTRS_UNSPECIFIED, (void *) &idaw.fmt1,
sizeof(idaw.fmt1), false);
cds->cda = be64_to_cpu(idaw.fmt1);
if (cds->cda & 0x80000000) {
return -EINVAL; /* channel program check */
}
}
++(cds->at_idaw);
if (ret != MEMTX_OK) {
/* assume inaccessible address */
return -EINVAL; /* channel program check */
}
return 0;
}

static int ccw_dstream_rw_ida(CcwDataStream *cds, void *buff, int len,
CcwDataStreamOp op)
{
uint64_t bsz = ccw_ida_block_size(cds->flags);
int ret = 0;
uint16_t cont_left, iter_len;

ret = cds_check_len(cds, len);
if (ret <= 0) {
return ret;
}
if (!cds->at_idaw) {
/* read first idaw */
ret = ida_read_next_idaw(cds);
if (ret) {
goto err;
}
cont_left = ida_continuous_left(cds->cda, bsz);
} else {
cont_left = ida_continuous_left(cds->cda, bsz);
if (cont_left == bsz) {
ret = ida_read_next_idaw(cds);
if (ret) {
goto err;
}
if (cds->cda & (bsz - 1)) {
ret = -EINVAL; /* channel program check */
goto err;
}
}
}
do {
iter_len = MIN(len, cont_left);
if (op != CDS_OP_A) {
ret = address_space_rw(&address_space_memory, cds->cda,
MEMTXATTRS_UNSPECIFIED, buff, iter_len, op);
if (ret != MEMTX_OK) {
/* assume inaccessible address */
ret = -EINVAL; /* channel program check */
goto err;
}
}
cds->at_byte += iter_len;
cds->cda += iter_len;
len -= iter_len;
if (!len) {
break;
}
ret = ida_read_next_idaw(cds);
if (ret) {
goto err;
}
cont_left = bsz;
} while (true);
return ret;
err:
cds->flags |= CDS_F_STREAM_BROKEN;
return ret;
}

void ccw_dstream_init(CcwDataStream *cds, CCW1 const *ccw, ORB const *orb)
{
/*
* We don't support MIDA (an optional facility) yet and we
* catch this earlier. Just for expressing the precondition.
*/
g_assert(!(orb->ctrl1 & ORB_CTRL1_MASK_MIDAW));
cds->flags = (orb->ctrl0 & ORB_CTRL0_MASK_I2K ? CDS_F_I2K : 0) |
(orb->ctrl0 & ORB_CTRL0_MASK_C64 ? CDS_F_C64 : 0) |
(orb->ctrl0 & ORB_CTRL0_MASK_FMT ? CDS_F_FMT : 0) |
(ccw->flags & CCW_FLAG_IDA ? CDS_F_IDA : 0);

cds->count = ccw->count;
cds->cda_orig = ccw->cda;
ccw_dstream_rewind(cds);
if (!(cds->flags & CDS_F_IDA)) {
cds->op_handler = ccw_dstream_rw_noflags;
} else {
cds->op_handler = ccw_dstream_rw_ida;
}
}

static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr,
bool suspend_allowed)
Expand Down Expand Up @@ -839,6 +1016,7 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr,
}

/* Look at the command. */
ccw_dstream_init(&sch->cds, &ccw, &(sch->orb));
switch (ccw.cmd_code) {
case CCW_CMD_NOOP:
/* Nothing to do. */
Expand All @@ -852,8 +1030,8 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr,
}
}
len = MIN(ccw.count, sizeof(sch->sense_data));
cpu_physical_memory_write(ccw.cda, sch->sense_data, len);
sch->curr_status.scsw.count = ccw.count - len;
ccw_dstream_write_buf(&sch->cds, sch->sense_data, len);
sch->curr_status.scsw.count = ccw_dstream_residual_count(&sch->cds);
memset(sch->sense_data, 0, sizeof(sch->sense_data));
ret = 0;
break;
Expand All @@ -879,8 +1057,8 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr,
} else {
sense_id.reserved = 0;
}
cpu_physical_memory_write(ccw.cda, &sense_id, len);
sch->curr_status.scsw.count = ccw.count - len;
ccw_dstream_write_buf(&sch->cds, &sense_id, len);
sch->curr_status.scsw.count = ccw_dstream_residual_count(&sch->cds);
ret = 0;
break;
}
Expand Down
1 change: 1 addition & 0 deletions hw/s390x/s390-pci-bus.c
Expand Up @@ -1032,6 +1032,7 @@ static void s390_pci_device_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);

dc->desc = "zpci device";
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
dc->reset = s390_pci_device_reset;
dc->bus_type = TYPE_S390_PCI_BUS;
dc->realize = s390_pci_device_realize;
Expand Down

0 comments on commit a26a98d

Please sign in to comment.