qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

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 
     26 int 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 
     54 static 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 
     74 void 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;
    140 out:
    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 }