From: Eric Farman <[email protected]>
The logic in css_interpret_ccw() correctly returns -EINVAL if a
Transfer-In-Channel (TIC) CCW is command chained to another TIC CCW.
The same routine also correctly returns -EINVAL if 256 CCWs do not
perform a data transfer as part of the I/O operation [0].
What is missing, however, is a combination of these two, where a loop
can be generated that will continue processing CCWs but without
providing an opportunity to catch a breath. Fix this by capping
the number of TIC CCWs in a channel program at the same limit as
the CCWs without data transfer.
[0] See "Invalid Sequence" in z/Architecture Principles of Operation
(SA22-7832-14), p16-27
Cc: [email protected]
Signed-off-by: Eric Farman <[email protected]>
Acked-by: Christian Borntraeger <[email protected]>
Reviewed-by: Farhan Ali <[email protected]>
Signed-off-by: Christian Borntraeger <[email protected]>
Message-ID: <[email protected]>
Signed-off-by: Cornelia Huck <[email protected]>
(cherry picked from commit 33bece0fa121c0a85df4f0372145ca74b967e78e)
Signed-off-by: Michael Tokarev <[email protected]>
diff --git a/hw/s390x/css.c b/hw/s390x/css.c
index 38d2d90028c..991fc126089 100644
--- a/hw/s390x/css.c
+++ b/hw/s390x/css.c
@@ -1104,6 +1104,12 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr
ccw_addr,
ret = -EINVAL;
break;
}
+ /* Limit the number of TICs in a given channel program */
+ if (sch->ccw_tic_cnt == 255) {
+ ret = -EINVAL;
+ break;
+ }
+ sch->ccw_tic_cnt++;
sch->channel_prog = ccw.cda;
ret = -EAGAIN;
break;
@@ -1155,6 +1161,7 @@ static void sch_handle_start_func_virtual(SubchDev *sch)
sch->ccw_fmt_1 = !!(orb->ctrl0 & ORB_CTRL0_MASK_FMT);
schib->scsw.flags |= (sch->ccw_fmt_1) ? SCSW_FLAGS_MASK_FMT : 0;
sch->ccw_no_data_cnt = 0;
+ sch->ccw_tic_cnt = 0;
suspend_allowed = !!(orb->ctrl0 & ORB_CTRL0_MASK_SPND);
} else {
/* Start Function resumed via rsch */
diff --git a/include/hw/s390x/css.h b/include/hw/s390x/css.h
index cd97e2b7075..9ee66ca39ac 100644
--- a/include/hw/s390x/css.h
+++ b/include/hw/s390x/css.h
@@ -132,6 +132,7 @@ struct SubchDev {
bool ccw_fmt_1;
bool thinint_active;
uint8_t ccw_no_data_cnt;
+ uint8_t ccw_tic_cnt;
uint16_t migrated_schid; /* used for mismatch detection */
CcwDataStream cds;
/* transport-provided data: */
--
2.47.3