cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

diag.c (5534B)


      1/*
      2 * S390x DIAG instruction helper functions
      3 *
      4 * This program is free software; you can redistribute it and/or modify
      5 * it under the terms of the GNU General Public License as published by
      6 * the Free Software Foundation; either version 2 of the License, or
      7 * (at your option) any later version.
      8 *
      9 * This program is distributed in the hope that it will be useful,
     10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12 * GNU General Public License for more details.
     13 */
     14
     15#include "qemu/osdep.h"
     16#include "cpu.h"
     17#include "s390x-internal.h"
     18#include "hw/watchdog/wdt_diag288.h"
     19#include "sysemu/cpus.h"
     20#include "hw/s390x/ipl.h"
     21#include "hw/s390x/s390-virtio-ccw.h"
     22#include "hw/s390x/pv.h"
     23#include "sysemu/kvm.h"
     24#include "kvm/kvm_s390x.h"
     25
     26int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3)
     27{
     28    uint64_t func = env->regs[r1];
     29    uint64_t timeout = env->regs[r1 + 1];
     30    uint64_t action = env->regs[r3];
     31    Object *obj;
     32    DIAG288State *diag288;
     33    DIAG288Class *diag288_class;
     34
     35    if (r1 % 2 || action != 0) {
     36        return -1;
     37    }
     38
     39    /* Timeout must be more than 15 seconds except for timer deletion */
     40    if (func != WDT_DIAG288_CANCEL && timeout < 15) {
     41        return -1;
     42    }
     43
     44    obj = object_resolve_path_type("", TYPE_WDT_DIAG288, NULL);
     45    if (!obj) {
     46        return -1;
     47    }
     48
     49    diag288 = DIAG288(obj);
     50    diag288_class = DIAG288_GET_CLASS(diag288);
     51    return diag288_class->handle_timer(diag288, func, timeout);
     52}
     53
     54static int diag308_parm_check(CPUS390XState *env, uint64_t r1, uint64_t addr,
     55                              uintptr_t ra, bool write)
     56{
     57    /* Handled by the Ultravisor */
     58    if (s390_is_pv()) {
     59        return 0;
     60    }
     61    if ((r1 & 1) || (addr & ~TARGET_PAGE_MASK)) {
     62        s390_program_interrupt(env, PGM_SPECIFICATION, ra);
     63        return -1;
     64    }
     65    if (!address_space_access_valid(&address_space_memory, addr,
     66                                    sizeof(IplParameterBlock), write,
     67                                    MEMTXATTRS_UNSPECIFIED)) {
     68        s390_program_interrupt(env, PGM_ADDRESSING, ra);
     69        return -1;
     70    }
     71    return 0;
     72}
     73
     74void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
     75{
     76    bool valid;
     77    CPUState *cs = env_cpu(env);
     78    S390CPU *cpu = S390_CPU(cs);
     79    uint64_t addr =  env->regs[r1];
     80    uint64_t subcode = env->regs[r3];
     81    IplParameterBlock *iplb;
     82
     83    if (env->psw.mask & PSW_MASK_PSTATE) {
     84        s390_program_interrupt(env, PGM_PRIVILEGED, ra);
     85        return;
     86    }
     87
     88    if (subcode & ~0x0ffffULL) {
     89        s390_program_interrupt(env, PGM_SPECIFICATION, ra);
     90        return;
     91    }
     92
     93    if (subcode >= DIAG308_PV_SET && !s390_has_feat(S390_FEAT_UNPACK)) {
     94        s390_program_interrupt(env, PGM_SPECIFICATION, ra);
     95        return;
     96    }
     97
     98    switch (subcode) {
     99    case DIAG308_RESET_MOD_CLR:
    100        s390_ipl_reset_request(cs, S390_RESET_MODIFIED_CLEAR);
    101        break;
    102    case DIAG308_RESET_LOAD_NORM:
    103        s390_ipl_reset_request(cs, S390_RESET_LOAD_NORMAL);
    104        break;
    105    case DIAG308_LOAD_CLEAR:
    106        /* Well we still lack the clearing bit... */
    107        s390_ipl_reset_request(cs, S390_RESET_REIPL);
    108        break;
    109    case DIAG308_SET:
    110    case DIAG308_PV_SET:
    111        if (diag308_parm_check(env, r1, addr, ra, false)) {
    112            return;
    113        }
    114        iplb = g_new0(IplParameterBlock, 1);
    115        if (!s390_is_pv()) {
    116            cpu_physical_memory_read(addr, iplb, sizeof(iplb->len));
    117        } else {
    118            s390_cpu_pv_mem_read(cpu, 0, iplb, sizeof(iplb->len));
    119        }
    120
    121        if (!iplb_valid_len(iplb)) {
    122            env->regs[r1 + 1] = DIAG_308_RC_INVALID;
    123            goto out;
    124        }
    125
    126        if (!s390_is_pv()) {
    127            cpu_physical_memory_read(addr, iplb, be32_to_cpu(iplb->len));
    128        } else {
    129            s390_cpu_pv_mem_read(cpu, 0, iplb, be32_to_cpu(iplb->len));
    130        }
    131
    132        valid = subcode == DIAG308_PV_SET ? iplb_valid_pv(iplb) : iplb_valid(iplb);
    133        if (!valid) {
    134            env->regs[r1 + 1] = DIAG_308_RC_INVALID;
    135            goto out;
    136        }
    137
    138        s390_ipl_update_diag308(iplb);
    139        env->regs[r1 + 1] = DIAG_308_RC_OK;
    140out:
    141        g_free(iplb);
    142        return;
    143    case DIAG308_STORE:
    144    case DIAG308_PV_STORE:
    145        if (diag308_parm_check(env, r1, addr, ra, true)) {
    146            return;
    147        }
    148        if (subcode == DIAG308_PV_STORE) {
    149            iplb = s390_ipl_get_iplb_pv();
    150        } else {
    151            iplb = s390_ipl_get_iplb();
    152        }
    153        if (!iplb) {
    154            env->regs[r1 + 1] = DIAG_308_RC_NO_CONF;
    155            return;
    156        }
    157
    158        if (!s390_is_pv()) {
    159            cpu_physical_memory_write(addr, iplb, be32_to_cpu(iplb->len));
    160        } else {
    161            s390_cpu_pv_mem_write(cpu, 0, iplb, be32_to_cpu(iplb->len));
    162        }
    163        env->regs[r1 + 1] = DIAG_308_RC_OK;
    164        return;
    165    case DIAG308_PV_START:
    166        iplb = s390_ipl_get_iplb_pv();
    167        if (!iplb) {
    168            env->regs[r1 + 1] = DIAG_308_RC_NO_PV_CONF;
    169            return;
    170        }
    171
    172        if (kvm_enabled() && kvm_s390_get_hpage_1m()) {
    173            error_report("Protected VMs can currently not be backed with "
    174                         "huge pages");
    175            env->regs[r1 + 1] = DIAG_308_RC_INVAL_FOR_PV;
    176            return;
    177        }
    178
    179        s390_ipl_reset_request(cs, S390_RESET_PV);
    180        break;
    181    default:
    182        s390_program_interrupt(env, PGM_SPECIFICATION, ra);
    183        break;
    184    }
    185}