linux/arch/s390/kvm/intercept.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * in-kernel handling for sie intercepts
   4 *
   5 * Copyright IBM Corp. 2008, 2014
   6 *
   7 *    Author(s): Carsten Otte <cotte@de.ibm.com>
   8 *               Christian Borntraeger <borntraeger@de.ibm.com>
   9 */
  10
  11#include <linux/kvm_host.h>
  12#include <linux/errno.h>
  13#include <linux/pagemap.h>
  14
  15#include <asm/kvm_host.h>
  16#include <asm/asm-offsets.h>
  17#include <asm/irq.h>
  18#include <asm/sysinfo.h>
  19
  20#include "kvm-s390.h"
  21#include "gaccess.h"
  22#include "trace.h"
  23#include "trace-s390.h"
  24
  25u8 kvm_s390_get_ilen(struct kvm_vcpu *vcpu)
  26{
  27        struct kvm_s390_sie_block *sie_block = vcpu->arch.sie_block;
  28        u8 ilen = 0;
  29
  30        switch (vcpu->arch.sie_block->icptcode) {
  31        case ICPT_INST:
  32        case ICPT_INSTPROGI:
  33        case ICPT_OPEREXC:
  34        case ICPT_PARTEXEC:
  35        case ICPT_IOINST:
  36                /* instruction only stored for these icptcodes */
  37                ilen = insn_length(vcpu->arch.sie_block->ipa >> 8);
  38                /* Use the length of the EXECUTE instruction if necessary */
  39                if (sie_block->icptstatus & 1) {
  40                        ilen = (sie_block->icptstatus >> 4) & 0x6;
  41                        if (!ilen)
  42                                ilen = 4;
  43                }
  44                break;
  45        case ICPT_PROGI:
  46                /* bit 1+2 of pgmilc are the ilc, so we directly get ilen */
  47                ilen = vcpu->arch.sie_block->pgmilc & 0x6;
  48                break;
  49        }
  50        return ilen;
  51}
  52
  53static int handle_stop(struct kvm_vcpu *vcpu)
  54{
  55        struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
  56        int rc = 0;
  57        uint8_t flags, stop_pending;
  58
  59        vcpu->stat.exit_stop_request++;
  60
  61        /* delay the stop if any non-stop irq is pending */
  62        if (kvm_s390_vcpu_has_irq(vcpu, 1))
  63                return 0;
  64
  65        /* avoid races with the injection/SIGP STOP code */
  66        spin_lock(&li->lock);
  67        flags = li->irq.stop.flags;
  68        stop_pending = kvm_s390_is_stop_irq_pending(vcpu);
  69        spin_unlock(&li->lock);
  70
  71        trace_kvm_s390_stop_request(stop_pending, flags);
  72        if (!stop_pending)
  73                return 0;
  74
  75        if (flags & KVM_S390_STOP_FLAG_STORE_STATUS) {
  76                rc = kvm_s390_vcpu_store_status(vcpu,
  77                                                KVM_S390_STORE_STATUS_NOADDR);
  78                if (rc)
  79                        return rc;
  80        }
  81
  82        if (!kvm_s390_user_cpu_state_ctrl(vcpu->kvm))
  83                kvm_s390_vcpu_stop(vcpu);
  84        return -EOPNOTSUPP;
  85}
  86
  87static int handle_validity(struct kvm_vcpu *vcpu)
  88{
  89        int viwhy = vcpu->arch.sie_block->ipb >> 16;
  90
  91        vcpu->stat.exit_validity++;
  92        trace_kvm_s390_intercept_validity(vcpu, viwhy);
  93        KVM_EVENT(3, "validity intercept 0x%x for pid %u (kvm 0x%pK)", viwhy,
  94                  current->pid, vcpu->kvm);
  95
  96        /* do not warn on invalid runtime instrumentation mode */
  97        WARN_ONCE(viwhy != 0x44, "kvm: unhandled validity intercept 0x%x\n",
  98                  viwhy);
  99        return -EINVAL;
 100}
 101
 102static int handle_instruction(struct kvm_vcpu *vcpu)
 103{
 104        vcpu->stat.exit_instruction++;
 105        trace_kvm_s390_intercept_instruction(vcpu,
 106                                             vcpu->arch.sie_block->ipa,
 107                                             vcpu->arch.sie_block->ipb);
 108
 109        switch (vcpu->arch.sie_block->ipa >> 8) {
 110        case 0x01:
 111                return kvm_s390_handle_01(vcpu);
 112        case 0x82:
 113                return kvm_s390_handle_lpsw(vcpu);
 114        case 0x83:
 115                return kvm_s390_handle_diag(vcpu);
 116        case 0xaa:
 117                return kvm_s390_handle_aa(vcpu);
 118        case 0xae:
 119                return kvm_s390_handle_sigp(vcpu);
 120        case 0xb2:
 121                return kvm_s390_handle_b2(vcpu);
 122        case 0xb6:
 123                return kvm_s390_handle_stctl(vcpu);
 124        case 0xb7:
 125                return kvm_s390_handle_lctl(vcpu);
 126        case 0xb9:
 127                return kvm_s390_handle_b9(vcpu);
 128        case 0xe3:
 129                return kvm_s390_handle_e3(vcpu);
 130        case 0xe5:
 131                return kvm_s390_handle_e5(vcpu);
 132        case 0xeb:
 133                return kvm_s390_handle_eb(vcpu);
 134        default:
 135                return -EOPNOTSUPP;
 136        }
 137}
 138
 139static int inject_prog_on_prog_intercept(struct kvm_vcpu *vcpu)
 140{
 141        struct kvm_s390_pgm_info pgm_info = {
 142                .code = vcpu->arch.sie_block->iprcc,
 143                /* the PSW has already been rewound */
 144                .flags = KVM_S390_PGM_FLAGS_NO_REWIND,
 145        };
 146
 147        switch (vcpu->arch.sie_block->iprcc & ~PGM_PER) {
 148        case PGM_AFX_TRANSLATION:
 149        case PGM_ASX_TRANSLATION:
 150        case PGM_EX_TRANSLATION:
 151        case PGM_LFX_TRANSLATION:
 152        case PGM_LSTE_SEQUENCE:
 153        case PGM_LSX_TRANSLATION:
 154        case PGM_LX_TRANSLATION:
 155        case PGM_PRIMARY_AUTHORITY:
 156        case PGM_SECONDARY_AUTHORITY:
 157        case PGM_SPACE_SWITCH:
 158                pgm_info.trans_exc_code = vcpu->arch.sie_block->tecmc;
 159                break;
 160        case PGM_ALEN_TRANSLATION:
 161        case PGM_ALE_SEQUENCE:
 162        case PGM_ASTE_INSTANCE:
 163        case PGM_ASTE_SEQUENCE:
 164        case PGM_ASTE_VALIDITY:
 165        case PGM_EXTENDED_AUTHORITY:
 166                pgm_info.exc_access_id = vcpu->arch.sie_block->eai;
 167                break;
 168        case PGM_ASCE_TYPE:
 169        case PGM_PAGE_TRANSLATION:
 170        case PGM_REGION_FIRST_TRANS:
 171        case PGM_REGION_SECOND_TRANS:
 172        case PGM_REGION_THIRD_TRANS:
 173        case PGM_SEGMENT_TRANSLATION:
 174                pgm_info.trans_exc_code = vcpu->arch.sie_block->tecmc;
 175                pgm_info.exc_access_id  = vcpu->arch.sie_block->eai;
 176                pgm_info.op_access_id  = vcpu->arch.sie_block->oai;
 177                break;
 178        case PGM_MONITOR:
 179                pgm_info.mon_class_nr = vcpu->arch.sie_block->mcn;
 180                pgm_info.mon_code = vcpu->arch.sie_block->tecmc;
 181                break;
 182        case PGM_VECTOR_PROCESSING:
 183        case PGM_DATA:
 184                pgm_info.data_exc_code = vcpu->arch.sie_block->dxc;
 185                break;
 186        case PGM_PROTECTION:
 187                pgm_info.trans_exc_code = vcpu->arch.sie_block->tecmc;
 188                pgm_info.exc_access_id  = vcpu->arch.sie_block->eai;
 189                break;
 190        default:
 191                break;
 192        }
 193
 194        if (vcpu->arch.sie_block->iprcc & PGM_PER) {
 195                pgm_info.per_code = vcpu->arch.sie_block->perc;
 196                pgm_info.per_atmid = vcpu->arch.sie_block->peratmid;
 197                pgm_info.per_address = vcpu->arch.sie_block->peraddr;
 198                pgm_info.per_access_id = vcpu->arch.sie_block->peraid;
 199        }
 200        return kvm_s390_inject_prog_irq(vcpu, &pgm_info);
 201}
 202
 203/*
 204 * restore ITDB to program-interruption TDB in guest lowcore
 205 * and set TX abort indication if required
 206*/
 207static int handle_itdb(struct kvm_vcpu *vcpu)
 208{
 209        struct kvm_s390_itdb *itdb;
 210        int rc;
 211
 212        if (!IS_TE_ENABLED(vcpu) || !IS_ITDB_VALID(vcpu))
 213                return 0;
 214        if (current->thread.per_flags & PER_FLAG_NO_TE)
 215                return 0;
 216        itdb = (struct kvm_s390_itdb *)vcpu->arch.sie_block->itdba;
 217        rc = write_guest_lc(vcpu, __LC_PGM_TDB, itdb, sizeof(*itdb));
 218        if (rc)
 219                return rc;
 220        memset(itdb, 0, sizeof(*itdb));
 221
 222        return 0;
 223}
 224
 225#define per_event(vcpu) (vcpu->arch.sie_block->iprcc & PGM_PER)
 226
 227static int handle_prog(struct kvm_vcpu *vcpu)
 228{
 229        psw_t psw;
 230        int rc;
 231
 232        vcpu->stat.exit_program_interruption++;
 233
 234        if (guestdbg_enabled(vcpu) && per_event(vcpu)) {
 235                rc = kvm_s390_handle_per_event(vcpu);
 236                if (rc)
 237                        return rc;
 238                /* the interrupt might have been filtered out completely */
 239                if (vcpu->arch.sie_block->iprcc == 0)
 240                        return 0;
 241        }
 242
 243        trace_kvm_s390_intercept_prog(vcpu, vcpu->arch.sie_block->iprcc);
 244        if (vcpu->arch.sie_block->iprcc == PGM_SPECIFICATION) {
 245                rc = read_guest_lc(vcpu, __LC_PGM_NEW_PSW, &psw, sizeof(psw_t));
 246                if (rc)
 247                        return rc;
 248                /* Avoid endless loops of specification exceptions */
 249                if (!is_valid_psw(&psw))
 250                        return -EOPNOTSUPP;
 251        }
 252        rc = handle_itdb(vcpu);
 253        if (rc)
 254                return rc;
 255
 256        return inject_prog_on_prog_intercept(vcpu);
 257}
 258
 259/**
 260 * handle_external_interrupt - used for external interruption interceptions
 261 *
 262 * This interception only occurs if the CPUSTAT_EXT_INT bit was set, or if
 263 * the new PSW does not have external interrupts disabled. In the first case,
 264 * we've got to deliver the interrupt manually, and in the second case, we
 265 * drop to userspace to handle the situation there.
 266 */
 267static int handle_external_interrupt(struct kvm_vcpu *vcpu)
 268{
 269        u16 eic = vcpu->arch.sie_block->eic;
 270        struct kvm_s390_irq irq;
 271        psw_t newpsw;
 272        int rc;
 273
 274        vcpu->stat.exit_external_interrupt++;
 275
 276        rc = read_guest_lc(vcpu, __LC_EXT_NEW_PSW, &newpsw, sizeof(psw_t));
 277        if (rc)
 278                return rc;
 279        /* We can not handle clock comparator or timer interrupt with bad PSW */
 280        if ((eic == EXT_IRQ_CLK_COMP || eic == EXT_IRQ_CPU_TIMER) &&
 281            (newpsw.mask & PSW_MASK_EXT))
 282                return -EOPNOTSUPP;
 283
 284        switch (eic) {
 285        case EXT_IRQ_CLK_COMP:
 286                irq.type = KVM_S390_INT_CLOCK_COMP;
 287                break;
 288        case EXT_IRQ_CPU_TIMER:
 289                irq.type = KVM_S390_INT_CPU_TIMER;
 290                break;
 291        case EXT_IRQ_EXTERNAL_CALL:
 292                irq.type = KVM_S390_INT_EXTERNAL_CALL;
 293                irq.u.extcall.code = vcpu->arch.sie_block->extcpuaddr;
 294                rc = kvm_s390_inject_vcpu(vcpu, &irq);
 295                /* ignore if another external call is already pending */
 296                if (rc == -EBUSY)
 297                        return 0;
 298                return rc;
 299        default:
 300                return -EOPNOTSUPP;
 301        }
 302
 303        return kvm_s390_inject_vcpu(vcpu, &irq);
 304}
 305
 306/**
 307 * Handle MOVE PAGE partial execution interception.
 308 *
 309 * This interception can only happen for guests with DAT disabled and
 310 * addresses that are currently not mapped in the host. Thus we try to
 311 * set up the mappings for the corresponding user pages here (or throw
 312 * addressing exceptions in case of illegal guest addresses).
 313 */
 314static int handle_mvpg_pei(struct kvm_vcpu *vcpu)
 315{
 316        unsigned long srcaddr, dstaddr;
 317        int reg1, reg2, rc;
 318
 319        kvm_s390_get_regs_rre(vcpu, &reg1, &reg2);
 320
 321        /* Make sure that the source is paged-in */
 322        rc = guest_translate_address(vcpu, vcpu->run->s.regs.gprs[reg2],
 323                                     reg2, &srcaddr, GACC_FETCH);
 324        if (rc)
 325                return kvm_s390_inject_prog_cond(vcpu, rc);
 326        rc = kvm_arch_fault_in_page(vcpu, srcaddr, 0);
 327        if (rc != 0)
 328                return rc;
 329
 330        /* Make sure that the destination is paged-in */
 331        rc = guest_translate_address(vcpu, vcpu->run->s.regs.gprs[reg1],
 332                                     reg1, &dstaddr, GACC_STORE);
 333        if (rc)
 334                return kvm_s390_inject_prog_cond(vcpu, rc);
 335        rc = kvm_arch_fault_in_page(vcpu, dstaddr, 1);
 336        if (rc != 0)
 337                return rc;
 338
 339        kvm_s390_retry_instr(vcpu);
 340
 341        return 0;
 342}
 343
 344static int handle_partial_execution(struct kvm_vcpu *vcpu)
 345{
 346        vcpu->stat.exit_pei++;
 347
 348        if (vcpu->arch.sie_block->ipa == 0xb254)        /* MVPG */
 349                return handle_mvpg_pei(vcpu);
 350        if (vcpu->arch.sie_block->ipa >> 8 == 0xae)     /* SIGP */
 351                return kvm_s390_handle_sigp_pei(vcpu);
 352
 353        return -EOPNOTSUPP;
 354}
 355
 356/*
 357 * Handle the sthyi instruction that provides the guest with system
 358 * information, like current CPU resources available at each level of
 359 * the machine.
 360 */
 361int handle_sthyi(struct kvm_vcpu *vcpu)
 362{
 363        int reg1, reg2, r = 0;
 364        u64 code, addr, cc = 0, rc = 0;
 365        struct sthyi_sctns *sctns = NULL;
 366
 367        if (!test_kvm_facility(vcpu->kvm, 74))
 368                return kvm_s390_inject_program_int(vcpu, PGM_OPERATION);
 369
 370        kvm_s390_get_regs_rre(vcpu, &reg1, &reg2);
 371        code = vcpu->run->s.regs.gprs[reg1];
 372        addr = vcpu->run->s.regs.gprs[reg2];
 373
 374        vcpu->stat.instruction_sthyi++;
 375        VCPU_EVENT(vcpu, 3, "STHYI: fc: %llu addr: 0x%016llx", code, addr);
 376        trace_kvm_s390_handle_sthyi(vcpu, code, addr);
 377
 378        if (reg1 == reg2 || reg1 & 1 || reg2 & 1)
 379                return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
 380
 381        if (code & 0xffff) {
 382                cc = 3;
 383                rc = 4;
 384                goto out;
 385        }
 386
 387        if (addr & ~PAGE_MASK)
 388                return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
 389
 390        sctns = (void *)get_zeroed_page(GFP_KERNEL);
 391        if (!sctns)
 392                return -ENOMEM;
 393
 394        cc = sthyi_fill(sctns, &rc);
 395
 396out:
 397        if (!cc) {
 398                r = write_guest(vcpu, addr, reg2, sctns, PAGE_SIZE);
 399                if (r) {
 400                        free_page((unsigned long)sctns);
 401                        return kvm_s390_inject_prog_cond(vcpu, r);
 402                }
 403        }
 404
 405        free_page((unsigned long)sctns);
 406        vcpu->run->s.regs.gprs[reg2 + 1] = rc;
 407        kvm_s390_set_psw_cc(vcpu, cc);
 408        return r;
 409}
 410
 411static int handle_operexc(struct kvm_vcpu *vcpu)
 412{
 413        psw_t oldpsw, newpsw;
 414        int rc;
 415
 416        vcpu->stat.exit_operation_exception++;
 417        trace_kvm_s390_handle_operexc(vcpu, vcpu->arch.sie_block->ipa,
 418                                      vcpu->arch.sie_block->ipb);
 419
 420        if (vcpu->arch.sie_block->ipa == 0xb256)
 421                return handle_sthyi(vcpu);
 422
 423        if (vcpu->arch.sie_block->ipa == 0 && vcpu->kvm->arch.user_instr0)
 424                return -EOPNOTSUPP;
 425        rc = read_guest_lc(vcpu, __LC_PGM_NEW_PSW, &newpsw, sizeof(psw_t));
 426        if (rc)
 427                return rc;
 428        /*
 429         * Avoid endless loops of operation exceptions, if the pgm new
 430         * PSW will cause a new operation exception.
 431         * The heuristic checks if the pgm new psw is within 6 bytes before
 432         * the faulting psw address (with same DAT, AS settings) and the
 433         * new psw is not a wait psw and the fault was not triggered by
 434         * problem state.
 435         */
 436        oldpsw = vcpu->arch.sie_block->gpsw;
 437        if (oldpsw.addr - newpsw.addr <= 6 &&
 438            !(newpsw.mask & PSW_MASK_WAIT) &&
 439            !(oldpsw.mask & PSW_MASK_PSTATE) &&
 440            (newpsw.mask & PSW_MASK_ASC) == (oldpsw.mask & PSW_MASK_ASC) &&
 441            (newpsw.mask & PSW_MASK_DAT) == (oldpsw.mask & PSW_MASK_DAT))
 442                return -EOPNOTSUPP;
 443
 444        return kvm_s390_inject_program_int(vcpu, PGM_OPERATION);
 445}
 446
 447int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu)
 448{
 449        int rc, per_rc = 0;
 450
 451        if (kvm_is_ucontrol(vcpu->kvm))
 452                return -EOPNOTSUPP;
 453
 454        switch (vcpu->arch.sie_block->icptcode) {
 455        case ICPT_EXTREQ:
 456                vcpu->stat.exit_external_request++;
 457                return 0;
 458        case ICPT_IOREQ:
 459                vcpu->stat.exit_io_request++;
 460                return 0;
 461        case ICPT_INST:
 462                rc = handle_instruction(vcpu);
 463                break;
 464        case ICPT_PROGI:
 465                return handle_prog(vcpu);
 466        case ICPT_EXTINT:
 467                return handle_external_interrupt(vcpu);
 468        case ICPT_WAIT:
 469                return kvm_s390_handle_wait(vcpu);
 470        case ICPT_VALIDITY:
 471                return handle_validity(vcpu);
 472        case ICPT_STOP:
 473                return handle_stop(vcpu);
 474        case ICPT_OPEREXC:
 475                rc = handle_operexc(vcpu);
 476                break;
 477        case ICPT_PARTEXEC:
 478                rc = handle_partial_execution(vcpu);
 479                break;
 480        case ICPT_KSS:
 481                rc = kvm_s390_skey_check_enable(vcpu);
 482                break;
 483        default:
 484                return -EOPNOTSUPP;
 485        }
 486
 487        /* process PER, also if the instrution is processed in user space */
 488        if (vcpu->arch.sie_block->icptstatus & 0x02 &&
 489            (!rc || rc == -EOPNOTSUPP))
 490                per_rc = kvm_s390_handle_per_ifetch_icpt(vcpu);
 491        return per_rc ? per_rc : rc;
 492}
 493