Cornelia Huck | db1c8f5 | 2013-01-24 02:28:03 +0000 | [diff] [blame] | 1 | /* |
| 2 | * I/O instructions for S/390 |
| 3 | * |
Thomas Huth | 14b4e13 | 2015-02-12 18:09:33 +0100 | [diff] [blame] | 4 | * Copyright 2012, 2015 IBM Corp. |
Cornelia Huck | db1c8f5 | 2013-01-24 02:28:03 +0000 | [diff] [blame] | 5 | * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> |
| 6 | * |
| 7 | * This work is licensed under the terms of the GNU GPL, version 2 or (at |
| 8 | * your option) any later version. See the COPYING file in the top-level |
| 9 | * directory. |
| 10 | */ |
| 11 | |
Peter Maydell | 9615495 | 2016-01-26 18:17:00 +0000 | [diff] [blame] | 12 | #include "qemu/osdep.h" |
Cornelia Huck | db1c8f5 | 2013-01-24 02:28:03 +0000 | [diff] [blame] | 13 | |
| 14 | #include "cpu.h" |
Paolo Bonzini | bd3f16a | 2015-12-04 12:06:26 +0100 | [diff] [blame] | 15 | #include "hw/s390x/ioinst.h" |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 16 | #include "trace.h" |
Frank Blaschka | 8cba80c | 2015-01-09 09:04:38 +0100 | [diff] [blame] | 17 | #include "hw/s390x/s390-pci-bus.h" |
Cornelia Huck | db1c8f5 | 2013-01-24 02:28:03 +0000 | [diff] [blame] | 18 | |
| 19 | int ioinst_disassemble_sch_ident(uint32_t value, int *m, int *cssid, int *ssid, |
| 20 | int *schid) |
| 21 | { |
| 22 | if (!IOINST_SCHID_ONE(value)) { |
| 23 | return -EINVAL; |
| 24 | } |
| 25 | if (!IOINST_SCHID_M(value)) { |
| 26 | if (IOINST_SCHID_CSSID(value)) { |
| 27 | return -EINVAL; |
| 28 | } |
| 29 | *cssid = 0; |
| 30 | *m = 0; |
| 31 | } else { |
| 32 | *cssid = IOINST_SCHID_CSSID(value); |
| 33 | *m = 1; |
| 34 | } |
| 35 | *ssid = IOINST_SCHID_SSID(value); |
| 36 | *schid = IOINST_SCHID_NR(value); |
| 37 | return 0; |
| 38 | } |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 39 | |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 40 | void ioinst_handle_xsch(S390CPU *cpu, uint64_t reg1) |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 41 | { |
| 42 | int cssid, ssid, schid, m; |
| 43 | SubchDev *sch; |
| 44 | int ret = -ENODEV; |
| 45 | int cc; |
| 46 | |
| 47 | if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 48 | program_interrupt(&cpu->env, PGM_OPERAND, 2); |
| 49 | return; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 50 | } |
| 51 | trace_ioinst_sch_id("xsch", cssid, ssid, schid); |
| 52 | sch = css_find_subch(m, cssid, ssid, schid); |
| 53 | if (sch && css_subch_visible(sch)) { |
| 54 | ret = css_do_xsch(sch); |
| 55 | } |
| 56 | switch (ret) { |
| 57 | case -ENODEV: |
| 58 | cc = 3; |
| 59 | break; |
| 60 | case -EBUSY: |
| 61 | cc = 2; |
| 62 | break; |
| 63 | case 0: |
| 64 | cc = 0; |
| 65 | break; |
| 66 | default: |
| 67 | cc = 1; |
| 68 | break; |
| 69 | } |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 70 | setcc(cpu, cc); |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 71 | } |
| 72 | |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 73 | void ioinst_handle_csch(S390CPU *cpu, uint64_t reg1) |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 74 | { |
| 75 | int cssid, ssid, schid, m; |
| 76 | SubchDev *sch; |
| 77 | int ret = -ENODEV; |
| 78 | int cc; |
| 79 | |
| 80 | if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 81 | program_interrupt(&cpu->env, PGM_OPERAND, 2); |
| 82 | return; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 83 | } |
| 84 | trace_ioinst_sch_id("csch", cssid, ssid, schid); |
| 85 | sch = css_find_subch(m, cssid, ssid, schid); |
| 86 | if (sch && css_subch_visible(sch)) { |
| 87 | ret = css_do_csch(sch); |
| 88 | } |
| 89 | if (ret == -ENODEV) { |
| 90 | cc = 3; |
| 91 | } else { |
| 92 | cc = 0; |
| 93 | } |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 94 | setcc(cpu, cc); |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 95 | } |
| 96 | |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 97 | void ioinst_handle_hsch(S390CPU *cpu, uint64_t reg1) |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 98 | { |
| 99 | int cssid, ssid, schid, m; |
| 100 | SubchDev *sch; |
| 101 | int ret = -ENODEV; |
| 102 | int cc; |
| 103 | |
| 104 | if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 105 | program_interrupt(&cpu->env, PGM_OPERAND, 2); |
| 106 | return; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 107 | } |
| 108 | trace_ioinst_sch_id("hsch", cssid, ssid, schid); |
| 109 | sch = css_find_subch(m, cssid, ssid, schid); |
| 110 | if (sch && css_subch_visible(sch)) { |
| 111 | ret = css_do_hsch(sch); |
| 112 | } |
| 113 | switch (ret) { |
| 114 | case -ENODEV: |
| 115 | cc = 3; |
| 116 | break; |
| 117 | case -EBUSY: |
| 118 | cc = 2; |
| 119 | break; |
| 120 | case 0: |
| 121 | cc = 0; |
| 122 | break; |
| 123 | default: |
| 124 | cc = 1; |
| 125 | break; |
| 126 | } |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 127 | setcc(cpu, cc); |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 128 | } |
| 129 | |
| 130 | static int ioinst_schib_valid(SCHIB *schib) |
| 131 | { |
Alexander Graf | d49f4ab | 2015-06-15 17:57:01 +0200 | [diff] [blame] | 132 | if ((be16_to_cpu(schib->pmcw.flags) & PMCW_FLAGS_MASK_INVALID) || |
| 133 | (be32_to_cpu(schib->pmcw.chars) & PMCW_CHARS_MASK_INVALID)) { |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 134 | return 0; |
| 135 | } |
| 136 | /* Disallow extended measurements for now. */ |
Alexander Graf | d49f4ab | 2015-06-15 17:57:01 +0200 | [diff] [blame] | 137 | if (be32_to_cpu(schib->pmcw.chars) & PMCW_CHARS_MASK_XMWME) { |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 138 | return 0; |
| 139 | } |
| 140 | return 1; |
| 141 | } |
| 142 | |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 143 | void ioinst_handle_msch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 144 | { |
| 145 | int cssid, ssid, schid, m; |
| 146 | SubchDev *sch; |
Thomas Huth | 14b4e13 | 2015-02-12 18:09:33 +0100 | [diff] [blame] | 147 | SCHIB schib; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 148 | uint64_t addr; |
| 149 | int ret = -ENODEV; |
| 150 | int cc; |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 151 | CPUS390XState *env = &cpu->env; |
Alexander Yarygin | 6cb1e49 | 2015-03-05 12:36:48 +0300 | [diff] [blame] | 152 | uint8_t ar; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 153 | |
Alexander Yarygin | 6cb1e49 | 2015-03-05 12:36:48 +0300 | [diff] [blame] | 154 | addr = decode_basedisp_s(env, ipb, &ar); |
Thomas Huth | 61bf0dc | 2013-06-21 10:13:42 +0200 | [diff] [blame] | 155 | if (addr & 3) { |
| 156 | program_interrupt(env, PGM_SPECIFICATION, 2); |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 157 | return; |
Thomas Huth | 61bf0dc | 2013-06-21 10:13:42 +0200 | [diff] [blame] | 158 | } |
Alexander Yarygin | 6cb1e49 | 2015-03-05 12:36:48 +0300 | [diff] [blame] | 159 | if (s390_cpu_virt_mem_read(cpu, addr, ar, &schib, sizeof(schib))) { |
Thomas Huth | 14b4e13 | 2015-02-12 18:09:33 +0100 | [diff] [blame] | 160 | return; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 161 | } |
Thomas Huth | 71ed827 | 2013-06-25 14:59:12 +0200 | [diff] [blame] | 162 | if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid) || |
Thomas Huth | 14b4e13 | 2015-02-12 18:09:33 +0100 | [diff] [blame] | 163 | !ioinst_schib_valid(&schib)) { |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 164 | program_interrupt(env, PGM_OPERAND, 2); |
Thomas Huth | 14b4e13 | 2015-02-12 18:09:33 +0100 | [diff] [blame] | 165 | return; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 166 | } |
Thomas Huth | 71ed827 | 2013-06-25 14:59:12 +0200 | [diff] [blame] | 167 | trace_ioinst_sch_id("msch", cssid, ssid, schid); |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 168 | sch = css_find_subch(m, cssid, ssid, schid); |
| 169 | if (sch && css_subch_visible(sch)) { |
Thomas Huth | 14b4e13 | 2015-02-12 18:09:33 +0100 | [diff] [blame] | 170 | ret = css_do_msch(sch, &schib); |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 171 | } |
| 172 | switch (ret) { |
| 173 | case -ENODEV: |
| 174 | cc = 3; |
| 175 | break; |
| 176 | case -EBUSY: |
| 177 | cc = 2; |
| 178 | break; |
| 179 | case 0: |
| 180 | cc = 0; |
| 181 | break; |
| 182 | default: |
| 183 | cc = 1; |
| 184 | break; |
| 185 | } |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 186 | setcc(cpu, cc); |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 187 | } |
| 188 | |
| 189 | static void copy_orb_from_guest(ORB *dest, const ORB *src) |
| 190 | { |
| 191 | dest->intparm = be32_to_cpu(src->intparm); |
| 192 | dest->ctrl0 = be16_to_cpu(src->ctrl0); |
| 193 | dest->lpm = src->lpm; |
| 194 | dest->ctrl1 = src->ctrl1; |
| 195 | dest->cpa = be32_to_cpu(src->cpa); |
| 196 | } |
| 197 | |
| 198 | static int ioinst_orb_valid(ORB *orb) |
| 199 | { |
| 200 | if ((orb->ctrl0 & ORB_CTRL0_MASK_INVALID) || |
| 201 | (orb->ctrl1 & ORB_CTRL1_MASK_INVALID)) { |
| 202 | return 0; |
| 203 | } |
Cornelia Huck | 4e19b57 | 2017-05-24 14:06:12 +0200 | [diff] [blame] | 204 | /* We don't support MIDA. */ |
| 205 | if (orb->ctrl1 & ORB_CTRL1_MASK_MIDAW) { |
| 206 | return 0; |
| 207 | } |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 208 | if ((orb->cpa & HIGH_ORDER_BIT) != 0) { |
| 209 | return 0; |
| 210 | } |
| 211 | return 1; |
| 212 | } |
| 213 | |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 214 | void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 215 | { |
| 216 | int cssid, ssid, schid, m; |
| 217 | SubchDev *sch; |
Thomas Huth | 234d9b1 | 2015-02-12 18:09:34 +0100 | [diff] [blame] | 218 | ORB orig_orb, orb; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 219 | uint64_t addr; |
| 220 | int ret = -ENODEV; |
| 221 | int cc; |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 222 | CPUS390XState *env = &cpu->env; |
Alexander Yarygin | 6cb1e49 | 2015-03-05 12:36:48 +0300 | [diff] [blame] | 223 | uint8_t ar; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 224 | |
Alexander Yarygin | 6cb1e49 | 2015-03-05 12:36:48 +0300 | [diff] [blame] | 225 | addr = decode_basedisp_s(env, ipb, &ar); |
Thomas Huth | 61bf0dc | 2013-06-21 10:13:42 +0200 | [diff] [blame] | 226 | if (addr & 3) { |
| 227 | program_interrupt(env, PGM_SPECIFICATION, 2); |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 228 | return; |
Thomas Huth | 61bf0dc | 2013-06-21 10:13:42 +0200 | [diff] [blame] | 229 | } |
Alexander Yarygin | 6cb1e49 | 2015-03-05 12:36:48 +0300 | [diff] [blame] | 230 | if (s390_cpu_virt_mem_read(cpu, addr, ar, &orig_orb, sizeof(orb))) { |
Thomas Huth | 234d9b1 | 2015-02-12 18:09:34 +0100 | [diff] [blame] | 231 | return; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 232 | } |
Thomas Huth | 234d9b1 | 2015-02-12 18:09:34 +0100 | [diff] [blame] | 233 | copy_orb_from_guest(&orb, &orig_orb); |
Thomas Huth | 71ed827 | 2013-06-25 14:59:12 +0200 | [diff] [blame] | 234 | if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid) || |
| 235 | !ioinst_orb_valid(&orb)) { |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 236 | program_interrupt(env, PGM_OPERAND, 2); |
Thomas Huth | 234d9b1 | 2015-02-12 18:09:34 +0100 | [diff] [blame] | 237 | return; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 238 | } |
Thomas Huth | 71ed827 | 2013-06-25 14:59:12 +0200 | [diff] [blame] | 239 | trace_ioinst_sch_id("ssch", cssid, ssid, schid); |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 240 | sch = css_find_subch(m, cssid, ssid, schid); |
| 241 | if (sch && css_subch_visible(sch)) { |
| 242 | ret = css_do_ssch(sch, &orb); |
| 243 | } |
| 244 | switch (ret) { |
| 245 | case -ENODEV: |
| 246 | cc = 3; |
| 247 | break; |
| 248 | case -EBUSY: |
| 249 | cc = 2; |
| 250 | break; |
Xiao Feng Ren | bab482d | 2017-05-17 02:48:11 +0200 | [diff] [blame] | 251 | case -EFAULT: |
| 252 | /* |
| 253 | * TODO: |
| 254 | * I'm wondering whether there is something better |
| 255 | * to do for us here (like setting some device or |
| 256 | * subchannel status). |
| 257 | */ |
| 258 | program_interrupt(env, PGM_ADDRESSING, 4); |
| 259 | return; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 260 | case 0: |
| 261 | cc = 0; |
| 262 | break; |
| 263 | default: |
| 264 | cc = 1; |
| 265 | break; |
| 266 | } |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 267 | setcc(cpu, cc); |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 268 | } |
| 269 | |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 270 | void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb) |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 271 | { |
Thomas Huth | 7f74f0a | 2015-02-12 18:09:38 +0100 | [diff] [blame] | 272 | CRW crw; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 273 | uint64_t addr; |
| 274 | int cc; |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 275 | CPUS390XState *env = &cpu->env; |
Alexander Yarygin | 6cb1e49 | 2015-03-05 12:36:48 +0300 | [diff] [blame] | 276 | uint8_t ar; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 277 | |
Alexander Yarygin | 6cb1e49 | 2015-03-05 12:36:48 +0300 | [diff] [blame] | 278 | addr = decode_basedisp_s(env, ipb, &ar); |
Thomas Huth | 61bf0dc | 2013-06-21 10:13:42 +0200 | [diff] [blame] | 279 | if (addr & 3) { |
| 280 | program_interrupt(env, PGM_SPECIFICATION, 2); |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 281 | return; |
Thomas Huth | 61bf0dc | 2013-06-21 10:13:42 +0200 | [diff] [blame] | 282 | } |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 283 | |
Thomas Huth | 7f74f0a | 2015-02-12 18:09:38 +0100 | [diff] [blame] | 284 | cc = css_do_stcrw(&crw); |
| 285 | /* 0 - crw stored, 1 - zeroes stored */ |
| 286 | |
Alexander Yarygin | 6cb1e49 | 2015-03-05 12:36:48 +0300 | [diff] [blame] | 287 | if (s390_cpu_virt_mem_write(cpu, addr, ar, &crw, sizeof(crw)) == 0) { |
Thomas Huth | 7f74f0a | 2015-02-12 18:09:38 +0100 | [diff] [blame] | 288 | setcc(cpu, cc); |
| 289 | } else if (cc == 0) { |
| 290 | /* Write failed: requeue CRW since STCRW is a suppressing instruction */ |
| 291 | css_undo_stcrw(&crw); |
| 292 | } |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 293 | } |
| 294 | |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 295 | void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 296 | { |
| 297 | int cssid, ssid, schid, m; |
| 298 | SubchDev *sch; |
| 299 | uint64_t addr; |
| 300 | int cc; |
Thomas Huth | 57b22fc | 2015-02-12 18:09:35 +0100 | [diff] [blame] | 301 | SCHIB schib; |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 302 | CPUS390XState *env = &cpu->env; |
Alexander Yarygin | 6cb1e49 | 2015-03-05 12:36:48 +0300 | [diff] [blame] | 303 | uint8_t ar; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 304 | |
Alexander Yarygin | 6cb1e49 | 2015-03-05 12:36:48 +0300 | [diff] [blame] | 305 | addr = decode_basedisp_s(env, ipb, &ar); |
Thomas Huth | 61bf0dc | 2013-06-21 10:13:42 +0200 | [diff] [blame] | 306 | if (addr & 3) { |
| 307 | program_interrupt(env, PGM_SPECIFICATION, 2); |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 308 | return; |
Thomas Huth | 61bf0dc | 2013-06-21 10:13:42 +0200 | [diff] [blame] | 309 | } |
Thomas Huth | 71ed827 | 2013-06-25 14:59:12 +0200 | [diff] [blame] | 310 | |
| 311 | if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { |
Thomas Huth | 57b22fc | 2015-02-12 18:09:35 +0100 | [diff] [blame] | 312 | /* |
| 313 | * As operand exceptions have a lower priority than access exceptions, |
| 314 | * we check whether the memory area is writeable (injecting the |
| 315 | * access execption if it is not) first. |
| 316 | */ |
Alexander Yarygin | 6cb1e49 | 2015-03-05 12:36:48 +0300 | [diff] [blame] | 317 | if (!s390_cpu_virt_mem_check_write(cpu, addr, ar, sizeof(schib))) { |
Thomas Huth | 57b22fc | 2015-02-12 18:09:35 +0100 | [diff] [blame] | 318 | program_interrupt(env, PGM_OPERAND, 2); |
| 319 | } |
| 320 | return; |
Thomas Huth | 71ed827 | 2013-06-25 14:59:12 +0200 | [diff] [blame] | 321 | } |
| 322 | trace_ioinst_sch_id("stsch", cssid, ssid, schid); |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 323 | sch = css_find_subch(m, cssid, ssid, schid); |
| 324 | if (sch) { |
| 325 | if (css_subch_visible(sch)) { |
Thomas Huth | 57b22fc | 2015-02-12 18:09:35 +0100 | [diff] [blame] | 326 | css_do_stsch(sch, &schib); |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 327 | cc = 0; |
| 328 | } else { |
| 329 | /* Indicate no more subchannels in this css/ss */ |
| 330 | cc = 3; |
| 331 | } |
| 332 | } else { |
Christian Borntraeger | 38dd7cc | 2013-02-22 09:01:32 +0000 | [diff] [blame] | 333 | if (css_schid_final(m, cssid, ssid, schid)) { |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 334 | cc = 3; /* No more subchannels in this css/ss */ |
| 335 | } else { |
| 336 | /* Store an empty schib. */ |
Thomas Huth | 57b22fc | 2015-02-12 18:09:35 +0100 | [diff] [blame] | 337 | memset(&schib, 0, sizeof(schib)); |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 338 | cc = 0; |
| 339 | } |
| 340 | } |
Thomas Huth | 57b22fc | 2015-02-12 18:09:35 +0100 | [diff] [blame] | 341 | if (cc != 3) { |
Alexander Yarygin | 6cb1e49 | 2015-03-05 12:36:48 +0300 | [diff] [blame] | 342 | if (s390_cpu_virt_mem_write(cpu, addr, ar, &schib, |
| 343 | sizeof(schib)) != 0) { |
Thomas Huth | 57b22fc | 2015-02-12 18:09:35 +0100 | [diff] [blame] | 344 | return; |
| 345 | } |
| 346 | } else { |
| 347 | /* Access exceptions have a higher priority than cc3 */ |
Alexander Yarygin | 6cb1e49 | 2015-03-05 12:36:48 +0300 | [diff] [blame] | 348 | if (s390_cpu_virt_mem_check_write(cpu, addr, ar, sizeof(schib)) != 0) { |
Thomas Huth | 57b22fc | 2015-02-12 18:09:35 +0100 | [diff] [blame] | 349 | return; |
| 350 | } |
| 351 | } |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 352 | setcc(cpu, cc); |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 353 | } |
| 354 | |
Thomas Huth | 653b080 | 2015-02-12 18:09:36 +0100 | [diff] [blame] | 355 | int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 356 | { |
Thomas Huth | 653b080 | 2015-02-12 18:09:36 +0100 | [diff] [blame] | 357 | CPUS390XState *env = &cpu->env; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 358 | int cssid, ssid, schid, m; |
| 359 | SubchDev *sch; |
Thomas Huth | b7b6348 | 2015-02-12 18:09:37 +0100 | [diff] [blame] | 360 | IRB irb; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 361 | uint64_t addr; |
Thomas Huth | b7b6348 | 2015-02-12 18:09:37 +0100 | [diff] [blame] | 362 | int cc, irb_len; |
Alexander Yarygin | 6cb1e49 | 2015-03-05 12:36:48 +0300 | [diff] [blame] | 363 | uint8_t ar; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 364 | |
| 365 | if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { |
| 366 | program_interrupt(env, PGM_OPERAND, 2); |
| 367 | return -EIO; |
| 368 | } |
| 369 | trace_ioinst_sch_id("tsch", cssid, ssid, schid); |
Alexander Yarygin | 6cb1e49 | 2015-03-05 12:36:48 +0300 | [diff] [blame] | 370 | addr = decode_basedisp_s(env, ipb, &ar); |
Thomas Huth | 61bf0dc | 2013-06-21 10:13:42 +0200 | [diff] [blame] | 371 | if (addr & 3) { |
| 372 | program_interrupt(env, PGM_SPECIFICATION, 2); |
| 373 | return -EIO; |
| 374 | } |
Thomas Huth | b7b6348 | 2015-02-12 18:09:37 +0100 | [diff] [blame] | 375 | |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 376 | sch = css_find_subch(m, cssid, ssid, schid); |
| 377 | if (sch && css_subch_visible(sch)) { |
Thomas Huth | b7b6348 | 2015-02-12 18:09:37 +0100 | [diff] [blame] | 378 | cc = css_do_tsch_get_irb(sch, &irb, &irb_len); |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 379 | } else { |
| 380 | cc = 3; |
| 381 | } |
Thomas Huth | b7b6348 | 2015-02-12 18:09:37 +0100 | [diff] [blame] | 382 | /* 0 - status pending, 1 - not status pending, 3 - not operational */ |
| 383 | if (cc != 3) { |
Alexander Yarygin | 6cb1e49 | 2015-03-05 12:36:48 +0300 | [diff] [blame] | 384 | if (s390_cpu_virt_mem_write(cpu, addr, ar, &irb, irb_len) != 0) { |
Thomas Huth | b7b6348 | 2015-02-12 18:09:37 +0100 | [diff] [blame] | 385 | return -EFAULT; |
| 386 | } |
| 387 | css_do_tsch_update_subch(sch); |
| 388 | } else { |
| 389 | irb_len = sizeof(irb) - sizeof(irb.emw); |
| 390 | /* Access exceptions have a higher priority than cc3 */ |
Alexander Yarygin | 6cb1e49 | 2015-03-05 12:36:48 +0300 | [diff] [blame] | 391 | if (s390_cpu_virt_mem_check_write(cpu, addr, ar, irb_len) != 0) { |
Thomas Huth | b7b6348 | 2015-02-12 18:09:37 +0100 | [diff] [blame] | 392 | return -EFAULT; |
| 393 | } |
| 394 | } |
| 395 | |
Thomas Huth | 653b080 | 2015-02-12 18:09:36 +0100 | [diff] [blame] | 396 | setcc(cpu, cc); |
Thomas Huth | b7b6348 | 2015-02-12 18:09:37 +0100 | [diff] [blame] | 397 | return 0; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 398 | } |
| 399 | |
| 400 | typedef struct ChscReq { |
| 401 | uint16_t len; |
| 402 | uint16_t command; |
| 403 | uint32_t param0; |
| 404 | uint32_t param1; |
| 405 | uint32_t param2; |
| 406 | } QEMU_PACKED ChscReq; |
| 407 | |
| 408 | typedef struct ChscResp { |
| 409 | uint16_t len; |
| 410 | uint16_t code; |
| 411 | uint32_t param; |
| 412 | char data[0]; |
| 413 | } QEMU_PACKED ChscResp; |
| 414 | |
| 415 | #define CHSC_MIN_RESP_LEN 0x0008 |
| 416 | |
| 417 | #define CHSC_SCPD 0x0002 |
| 418 | #define CHSC_SCSC 0x0010 |
| 419 | #define CHSC_SDA 0x0031 |
Frank Blaschka | 8cba80c | 2015-01-09 09:04:38 +0100 | [diff] [blame] | 420 | #define CHSC_SEI 0x000e |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 421 | |
| 422 | #define CHSC_SCPD_0_M 0x20000000 |
| 423 | #define CHSC_SCPD_0_C 0x10000000 |
| 424 | #define CHSC_SCPD_0_FMT 0x0f000000 |
| 425 | #define CHSC_SCPD_0_CSSID 0x00ff0000 |
| 426 | #define CHSC_SCPD_0_RFMT 0x00000f00 |
| 427 | #define CHSC_SCPD_0_RES 0xc000f000 |
| 428 | #define CHSC_SCPD_1_RES 0xffffff00 |
| 429 | #define CHSC_SCPD_01_CHPID 0x000000ff |
| 430 | static void ioinst_handle_chsc_scpd(ChscReq *req, ChscResp *res) |
| 431 | { |
| 432 | uint16_t len = be16_to_cpu(req->len); |
| 433 | uint32_t param0 = be32_to_cpu(req->param0); |
| 434 | uint32_t param1 = be32_to_cpu(req->param1); |
| 435 | uint16_t resp_code; |
| 436 | int rfmt; |
| 437 | uint16_t cssid; |
| 438 | uint8_t f_chpid, l_chpid; |
| 439 | int desc_size; |
| 440 | int m; |
| 441 | |
| 442 | rfmt = (param0 & CHSC_SCPD_0_RFMT) >> 8; |
| 443 | if ((rfmt == 0) || (rfmt == 1)) { |
| 444 | rfmt = !!(param0 & CHSC_SCPD_0_C); |
| 445 | } |
| 446 | if ((len != 0x0010) || (param0 & CHSC_SCPD_0_RES) || |
| 447 | (param1 & CHSC_SCPD_1_RES) || req->param2) { |
| 448 | resp_code = 0x0003; |
| 449 | goto out_err; |
| 450 | } |
| 451 | if (param0 & CHSC_SCPD_0_FMT) { |
| 452 | resp_code = 0x0007; |
| 453 | goto out_err; |
| 454 | } |
| 455 | cssid = (param0 & CHSC_SCPD_0_CSSID) >> 16; |
| 456 | m = param0 & CHSC_SCPD_0_M; |
| 457 | if (cssid != 0) { |
| 458 | if (!m || !css_present(cssid)) { |
| 459 | resp_code = 0x0008; |
| 460 | goto out_err; |
| 461 | } |
| 462 | } |
| 463 | f_chpid = param0 & CHSC_SCPD_01_CHPID; |
| 464 | l_chpid = param1 & CHSC_SCPD_01_CHPID; |
| 465 | if (l_chpid < f_chpid) { |
| 466 | resp_code = 0x0003; |
| 467 | goto out_err; |
| 468 | } |
| 469 | /* css_collect_chp_desc() is endian-aware */ |
| 470 | desc_size = css_collect_chp_desc(m, cssid, f_chpid, l_chpid, rfmt, |
| 471 | &res->data); |
| 472 | res->code = cpu_to_be16(0x0001); |
| 473 | res->len = cpu_to_be16(8 + desc_size); |
| 474 | res->param = cpu_to_be32(rfmt); |
| 475 | return; |
| 476 | |
| 477 | out_err: |
| 478 | res->code = cpu_to_be16(resp_code); |
| 479 | res->len = cpu_to_be16(CHSC_MIN_RESP_LEN); |
| 480 | res->param = cpu_to_be32(rfmt); |
| 481 | } |
| 482 | |
| 483 | #define CHSC_SCSC_0_M 0x20000000 |
| 484 | #define CHSC_SCSC_0_FMT 0x000f0000 |
| 485 | #define CHSC_SCSC_0_CSSID 0x0000ff00 |
| 486 | #define CHSC_SCSC_0_RES 0xdff000ff |
| 487 | static void ioinst_handle_chsc_scsc(ChscReq *req, ChscResp *res) |
| 488 | { |
| 489 | uint16_t len = be16_to_cpu(req->len); |
| 490 | uint32_t param0 = be32_to_cpu(req->param0); |
| 491 | uint8_t cssid; |
| 492 | uint16_t resp_code; |
| 493 | uint32_t general_chars[510]; |
| 494 | uint32_t chsc_chars[508]; |
| 495 | |
| 496 | if (len != 0x0010) { |
| 497 | resp_code = 0x0003; |
| 498 | goto out_err; |
| 499 | } |
| 500 | |
| 501 | if (param0 & CHSC_SCSC_0_FMT) { |
| 502 | resp_code = 0x0007; |
| 503 | goto out_err; |
| 504 | } |
| 505 | cssid = (param0 & CHSC_SCSC_0_CSSID) >> 8; |
| 506 | if (cssid != 0) { |
| 507 | if (!(param0 & CHSC_SCSC_0_M) || !css_present(cssid)) { |
| 508 | resp_code = 0x0008; |
| 509 | goto out_err; |
| 510 | } |
| 511 | } |
| 512 | if ((param0 & CHSC_SCSC_0_RES) || req->param1 || req->param2) { |
| 513 | resp_code = 0x0003; |
| 514 | goto out_err; |
| 515 | } |
| 516 | res->code = cpu_to_be16(0x0001); |
| 517 | res->len = cpu_to_be16(4080); |
| 518 | res->param = 0; |
| 519 | |
| 520 | memset(general_chars, 0, sizeof(general_chars)); |
| 521 | memset(chsc_chars, 0, sizeof(chsc_chars)); |
| 522 | |
| 523 | general_chars[0] = cpu_to_be32(0x03000000); |
Cornelia Huck | 5759db1 | 2016-07-13 17:43:18 +0200 | [diff] [blame] | 524 | general_chars[1] = cpu_to_be32(0x00079000); |
Alexander Yarygin | 3041e3b | 2015-10-01 20:21:33 +0300 | [diff] [blame] | 525 | general_chars[3] = cpu_to_be32(0x00080000); |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 526 | |
| 527 | chsc_chars[0] = cpu_to_be32(0x40000000); |
| 528 | chsc_chars[3] = cpu_to_be32(0x00040000); |
| 529 | |
| 530 | memcpy(res->data, general_chars, sizeof(general_chars)); |
| 531 | memcpy(res->data + sizeof(general_chars), chsc_chars, sizeof(chsc_chars)); |
| 532 | return; |
| 533 | |
| 534 | out_err: |
| 535 | res->code = cpu_to_be16(resp_code); |
| 536 | res->len = cpu_to_be16(CHSC_MIN_RESP_LEN); |
| 537 | res->param = 0; |
| 538 | } |
| 539 | |
| 540 | #define CHSC_SDA_0_FMT 0x0f000000 |
| 541 | #define CHSC_SDA_0_OC 0x0000ffff |
| 542 | #define CHSC_SDA_0_RES 0xf0ff0000 |
| 543 | #define CHSC_SDA_OC_MCSSE 0x0 |
| 544 | #define CHSC_SDA_OC_MSS 0x2 |
| 545 | static void ioinst_handle_chsc_sda(ChscReq *req, ChscResp *res) |
| 546 | { |
| 547 | uint16_t resp_code = 0x0001; |
| 548 | uint16_t len = be16_to_cpu(req->len); |
| 549 | uint32_t param0 = be32_to_cpu(req->param0); |
| 550 | uint16_t oc; |
| 551 | int ret; |
| 552 | |
| 553 | if ((len != 0x0400) || (param0 & CHSC_SDA_0_RES)) { |
| 554 | resp_code = 0x0003; |
| 555 | goto out; |
| 556 | } |
| 557 | |
| 558 | if (param0 & CHSC_SDA_0_FMT) { |
| 559 | resp_code = 0x0007; |
| 560 | goto out; |
| 561 | } |
| 562 | |
| 563 | oc = param0 & CHSC_SDA_0_OC; |
| 564 | switch (oc) { |
| 565 | case CHSC_SDA_OC_MCSSE: |
| 566 | ret = css_enable_mcsse(); |
| 567 | if (ret == -EINVAL) { |
| 568 | resp_code = 0x0101; |
| 569 | goto out; |
| 570 | } |
| 571 | break; |
| 572 | case CHSC_SDA_OC_MSS: |
| 573 | ret = css_enable_mss(); |
| 574 | if (ret == -EINVAL) { |
| 575 | resp_code = 0x0101; |
| 576 | goto out; |
| 577 | } |
| 578 | break; |
| 579 | default: |
| 580 | resp_code = 0x0003; |
| 581 | goto out; |
| 582 | } |
| 583 | |
| 584 | out: |
| 585 | res->code = cpu_to_be16(resp_code); |
| 586 | res->len = cpu_to_be16(CHSC_MIN_RESP_LEN); |
| 587 | res->param = 0; |
| 588 | } |
| 589 | |
Frank Blaschka | 8cba80c | 2015-01-09 09:04:38 +0100 | [diff] [blame] | 590 | static int chsc_sei_nt0_get_event(void *res) |
| 591 | { |
| 592 | /* no events yet */ |
| 593 | return 1; |
| 594 | } |
| 595 | |
| 596 | static int chsc_sei_nt0_have_event(void) |
| 597 | { |
| 598 | /* no events yet */ |
| 599 | return 0; |
| 600 | } |
| 601 | |
| 602 | #define CHSC_SEI_NT0 (1ULL << 63) |
| 603 | #define CHSC_SEI_NT2 (1ULL << 61) |
| 604 | static void ioinst_handle_chsc_sei(ChscReq *req, ChscResp *res) |
| 605 | { |
| 606 | uint64_t selection_mask = ldq_p(&req->param1); |
| 607 | uint8_t *res_flags = (uint8_t *)res->data; |
| 608 | int have_event = 0; |
| 609 | int have_more = 0; |
| 610 | |
| 611 | /* regarding architecture nt0 can not be masked */ |
| 612 | have_event = !chsc_sei_nt0_get_event(res); |
| 613 | have_more = chsc_sei_nt0_have_event(); |
| 614 | |
| 615 | if (selection_mask & CHSC_SEI_NT2) { |
| 616 | if (!have_event) { |
| 617 | have_event = !chsc_sei_nt2_get_event(res); |
| 618 | } |
| 619 | |
| 620 | if (!have_more) { |
| 621 | have_more = chsc_sei_nt2_have_event(); |
| 622 | } |
| 623 | } |
| 624 | |
| 625 | if (have_event) { |
| 626 | res->code = cpu_to_be16(0x0001); |
| 627 | if (have_more) { |
| 628 | (*res_flags) |= 0x80; |
| 629 | } else { |
| 630 | (*res_flags) &= ~0x80; |
Song Shan Gong | c81b4f8 | 2016-01-19 02:55:00 +0100 | [diff] [blame] | 631 | css_clear_sei_pending(); |
Frank Blaschka | 8cba80c | 2015-01-09 09:04:38 +0100 | [diff] [blame] | 632 | } |
| 633 | } else { |
Pierre Morel | f70202b | 2016-01-14 13:29:53 +0100 | [diff] [blame] | 634 | res->code = cpu_to_be16(0x0005); |
| 635 | res->len = cpu_to_be16(CHSC_MIN_RESP_LEN); |
Frank Blaschka | 8cba80c | 2015-01-09 09:04:38 +0100 | [diff] [blame] | 636 | } |
| 637 | } |
| 638 | |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 639 | static void ioinst_handle_chsc_unimplemented(ChscResp *res) |
| 640 | { |
| 641 | res->len = cpu_to_be16(CHSC_MIN_RESP_LEN); |
| 642 | res->code = cpu_to_be16(0x0004); |
| 643 | res->param = 0; |
| 644 | } |
| 645 | |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 646 | void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb) |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 647 | { |
| 648 | ChscReq *req; |
| 649 | ChscResp *res; |
| 650 | uint64_t addr; |
| 651 | int reg; |
| 652 | uint16_t len; |
| 653 | uint16_t command; |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 654 | CPUS390XState *env = &cpu->env; |
Thomas Huth | 166f1bb | 2015-02-12 18:09:39 +0100 | [diff] [blame] | 655 | uint8_t buf[TARGET_PAGE_SIZE]; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 656 | |
| 657 | trace_ioinst("chsc"); |
| 658 | reg = (ipb >> 20) & 0x00f; |
| 659 | addr = env->regs[reg]; |
| 660 | /* Page boundary? */ |
| 661 | if (addr & 0xfff) { |
| 662 | program_interrupt(env, PGM_SPECIFICATION, 2); |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 663 | return; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 664 | } |
Thomas Huth | 166f1bb | 2015-02-12 18:09:39 +0100 | [diff] [blame] | 665 | /* |
| 666 | * Reading sizeof(ChscReq) bytes is currently enough for all of our |
| 667 | * present CHSC sub-handlers ... if we ever need more, we should take |
| 668 | * care of req->len here first. |
| 669 | */ |
Alexander Yarygin | 6cb1e49 | 2015-03-05 12:36:48 +0300 | [diff] [blame] | 670 | if (s390_cpu_virt_mem_read(cpu, addr, reg, buf, sizeof(ChscReq))) { |
Thomas Huth | 166f1bb | 2015-02-12 18:09:39 +0100 | [diff] [blame] | 671 | return; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 672 | } |
Thomas Huth | 166f1bb | 2015-02-12 18:09:39 +0100 | [diff] [blame] | 673 | req = (ChscReq *)buf; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 674 | len = be16_to_cpu(req->len); |
| 675 | /* Length field valid? */ |
| 676 | if ((len < 16) || (len > 4088) || (len & 7)) { |
| 677 | program_interrupt(env, PGM_OPERAND, 2); |
Thomas Huth | 166f1bb | 2015-02-12 18:09:39 +0100 | [diff] [blame] | 678 | return; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 679 | } |
| 680 | memset((char *)req + len, 0, TARGET_PAGE_SIZE - len); |
| 681 | res = (void *)((char *)req + len); |
| 682 | command = be16_to_cpu(req->command); |
| 683 | trace_ioinst_chsc_cmd(command, len); |
| 684 | switch (command) { |
| 685 | case CHSC_SCSC: |
| 686 | ioinst_handle_chsc_scsc(req, res); |
| 687 | break; |
| 688 | case CHSC_SCPD: |
| 689 | ioinst_handle_chsc_scpd(req, res); |
| 690 | break; |
| 691 | case CHSC_SDA: |
| 692 | ioinst_handle_chsc_sda(req, res); |
| 693 | break; |
Frank Blaschka | 8cba80c | 2015-01-09 09:04:38 +0100 | [diff] [blame] | 694 | case CHSC_SEI: |
| 695 | ioinst_handle_chsc_sei(req, res); |
| 696 | break; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 697 | default: |
| 698 | ioinst_handle_chsc_unimplemented(res); |
| 699 | break; |
| 700 | } |
| 701 | |
Alexander Yarygin | 6cb1e49 | 2015-03-05 12:36:48 +0300 | [diff] [blame] | 702 | if (!s390_cpu_virt_mem_write(cpu, addr + len, reg, res, |
| 703 | be16_to_cpu(res->len))) { |
Thomas Huth | 166f1bb | 2015-02-12 18:09:39 +0100 | [diff] [blame] | 704 | setcc(cpu, 0); /* Command execution complete */ |
| 705 | } |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 706 | } |
| 707 | |
Thomas Huth | 7781a49 | 2015-02-12 18:09:40 +0100 | [diff] [blame] | 708 | int ioinst_handle_tpi(S390CPU *cpu, uint32_t ipb) |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 709 | { |
Thomas Huth | 7781a49 | 2015-02-12 18:09:40 +0100 | [diff] [blame] | 710 | CPUS390XState *env = &cpu->env; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 711 | uint64_t addr; |
| 712 | int lowcore; |
Thomas Huth | 7781a49 | 2015-02-12 18:09:40 +0100 | [diff] [blame] | 713 | IOIntCode int_code; |
| 714 | hwaddr len; |
Cornelia Huck | 50c8d9b | 2013-01-27 23:59:26 +0000 | [diff] [blame] | 715 | int ret; |
Alexander Yarygin | 6cb1e49 | 2015-03-05 12:36:48 +0300 | [diff] [blame] | 716 | uint8_t ar; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 717 | |
| 718 | trace_ioinst("tpi"); |
Alexander Yarygin | 6cb1e49 | 2015-03-05 12:36:48 +0300 | [diff] [blame] | 719 | addr = decode_basedisp_s(env, ipb, &ar); |
Thomas Huth | 61bf0dc | 2013-06-21 10:13:42 +0200 | [diff] [blame] | 720 | if (addr & 3) { |
| 721 | program_interrupt(env, PGM_SPECIFICATION, 2); |
| 722 | return -EIO; |
| 723 | } |
| 724 | |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 725 | lowcore = addr ? 0 : 1; |
Cornelia Huck | 50c8d9b | 2013-01-27 23:59:26 +0000 | [diff] [blame] | 726 | len = lowcore ? 8 /* two words */ : 12 /* three words */; |
Thomas Huth | 7781a49 | 2015-02-12 18:09:40 +0100 | [diff] [blame] | 727 | ret = css_do_tpi(&int_code, lowcore); |
| 728 | if (ret == 1) { |
Alexander Yarygin | 6cb1e49 | 2015-03-05 12:36:48 +0300 | [diff] [blame] | 729 | s390_cpu_virt_mem_write(cpu, lowcore ? 184 : addr, ar, &int_code, len); |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 730 | } |
Cornelia Huck | 50c8d9b | 2013-01-27 23:59:26 +0000 | [diff] [blame] | 731 | return ret; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 732 | } |
| 733 | |
| 734 | #define SCHM_REG1_RES(_reg) (_reg & 0x000000000ffffffc) |
| 735 | #define SCHM_REG1_MBK(_reg) ((_reg & 0x00000000f0000000) >> 28) |
| 736 | #define SCHM_REG1_UPD(_reg) ((_reg & 0x0000000000000002) >> 1) |
| 737 | #define SCHM_REG1_DCT(_reg) (_reg & 0x0000000000000001) |
| 738 | |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 739 | void ioinst_handle_schm(S390CPU *cpu, uint64_t reg1, uint64_t reg2, |
| 740 | uint32_t ipb) |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 741 | { |
| 742 | uint8_t mbk; |
| 743 | int update; |
| 744 | int dct; |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 745 | CPUS390XState *env = &cpu->env; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 746 | |
| 747 | trace_ioinst("schm"); |
| 748 | |
| 749 | if (SCHM_REG1_RES(reg1)) { |
| 750 | program_interrupt(env, PGM_OPERAND, 2); |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 751 | return; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 752 | } |
| 753 | |
| 754 | mbk = SCHM_REG1_MBK(reg1); |
| 755 | update = SCHM_REG1_UPD(reg1); |
| 756 | dct = SCHM_REG1_DCT(reg1); |
| 757 | |
Thomas Huth | 7ae5a7c | 2013-06-21 15:57:31 +0200 | [diff] [blame] | 758 | if (update && (reg2 & 0x000000000000001f)) { |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 759 | program_interrupt(env, PGM_OPERAND, 2); |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 760 | return; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 761 | } |
| 762 | |
| 763 | css_do_schm(mbk, update, dct, update ? reg2 : 0); |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 764 | } |
| 765 | |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 766 | void ioinst_handle_rsch(S390CPU *cpu, uint64_t reg1) |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 767 | { |
| 768 | int cssid, ssid, schid, m; |
| 769 | SubchDev *sch; |
| 770 | int ret = -ENODEV; |
| 771 | int cc; |
| 772 | |
| 773 | if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 774 | program_interrupt(&cpu->env, PGM_OPERAND, 2); |
| 775 | return; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 776 | } |
| 777 | trace_ioinst_sch_id("rsch", cssid, ssid, schid); |
| 778 | sch = css_find_subch(m, cssid, ssid, schid); |
| 779 | if (sch && css_subch_visible(sch)) { |
| 780 | ret = css_do_rsch(sch); |
| 781 | } |
| 782 | switch (ret) { |
| 783 | case -ENODEV: |
| 784 | cc = 3; |
| 785 | break; |
| 786 | case -EINVAL: |
| 787 | cc = 2; |
| 788 | break; |
| 789 | case 0: |
| 790 | cc = 0; |
| 791 | break; |
| 792 | default: |
| 793 | cc = 1; |
| 794 | break; |
| 795 | } |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 796 | setcc(cpu, cc); |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 797 | } |
| 798 | |
| 799 | #define RCHP_REG1_RES(_reg) (_reg & 0x00000000ff00ff00) |
| 800 | #define RCHP_REG1_CSSID(_reg) ((_reg & 0x0000000000ff0000) >> 16) |
| 801 | #define RCHP_REG1_CHPID(_reg) (_reg & 0x00000000000000ff) |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 802 | void ioinst_handle_rchp(S390CPU *cpu, uint64_t reg1) |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 803 | { |
| 804 | int cc; |
| 805 | uint8_t cssid; |
| 806 | uint8_t chpid; |
| 807 | int ret; |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 808 | CPUS390XState *env = &cpu->env; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 809 | |
| 810 | if (RCHP_REG1_RES(reg1)) { |
| 811 | program_interrupt(env, PGM_OPERAND, 2); |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 812 | return; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 813 | } |
| 814 | |
| 815 | cssid = RCHP_REG1_CSSID(reg1); |
| 816 | chpid = RCHP_REG1_CHPID(reg1); |
| 817 | |
| 818 | trace_ioinst_chp_id("rchp", cssid, chpid); |
| 819 | |
| 820 | ret = css_do_rchp(cssid, chpid); |
| 821 | |
| 822 | switch (ret) { |
| 823 | case -ENODEV: |
| 824 | cc = 3; |
| 825 | break; |
| 826 | case -EBUSY: |
| 827 | cc = 2; |
| 828 | break; |
| 829 | case 0: |
| 830 | cc = 0; |
| 831 | break; |
| 832 | default: |
| 833 | /* Invalid channel subsystem. */ |
| 834 | program_interrupt(env, PGM_OPERAND, 2); |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 835 | return; |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 836 | } |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 837 | setcc(cpu, cc); |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 838 | } |
| 839 | |
| 840 | #define SAL_REG1_INVALID(_reg) (_reg & 0x0000000080000000) |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 841 | void ioinst_handle_sal(S390CPU *cpu, uint64_t reg1) |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 842 | { |
| 843 | /* We do not provide address limit checking, so let's suppress it. */ |
| 844 | if (SAL_REG1_INVALID(reg1) || reg1 & 0x000000000000ffff) { |
Thomas Huth | 5d9bf1c | 2013-07-01 15:44:18 +0200 | [diff] [blame] | 845 | program_interrupt(&cpu->env, PGM_OPERAND, 2); |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 846 | } |
Cornelia Huck | 7b18aad | 2013-01-24 02:28:05 +0000 | [diff] [blame] | 847 | } |