qemu

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

cpu-sysemu.c (8441B)


      1 /*
      2  * QEMU S/390 CPU - System Emulation-only code
      3  *
      4  * Copyright (c) 2009 Ulrich Hecht
      5  * Copyright (c) 2011 Alexander Graf
      6  * Copyright (c) 2012 SUSE LINUX Products GmbH
      7  * Copyright (c) 2012 IBM Corp.
      8  *
      9  * This program is free software; you can redistribute it and/or modify
     10  * it under the terms of the GNU General Public License as published by
     11  * the Free Software Foundation; either version 2 of the License, or
     12  * (at your option) any later version.
     13  *
     14  * This program is distributed in the hope that it will be useful,
     15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     17  * General Public License for more details.
     18  *
     19  * You should have received a copy of the GNU General Public License
     20  * along with this program; if not, see <http://www.gnu.org/licenses/>.
     21  */
     22 
     23 #include "qemu/osdep.h"
     24 #include "qapi/error.h"
     25 #include "cpu.h"
     26 #include "s390x-internal.h"
     27 #include "kvm/kvm_s390x.h"
     28 #include "sysemu/kvm.h"
     29 #include "sysemu/reset.h"
     30 #include "qemu/timer.h"
     31 #include "trace.h"
     32 #include "qapi/qapi-visit-run-state.h"
     33 #include "sysemu/hw_accel.h"
     34 
     35 #include "hw/s390x/pv.h"
     36 #include "hw/boards.h"
     37 #include "sysemu/sysemu.h"
     38 #include "sysemu/tcg.h"
     39 #include "hw/core/sysemu-cpu-ops.h"
     40 
     41 /* S390CPUClass::load_normal() */
     42 static void s390_cpu_load_normal(CPUState *s)
     43 {
     44     S390CPU *cpu = S390_CPU(s);
     45     uint64_t spsw;
     46 
     47     if (!s390_is_pv()) {
     48         spsw = ldq_phys(s->as, 0);
     49         cpu->env.psw.mask = spsw & PSW_MASK_SHORT_CTRL;
     50         /*
     51          * Invert short psw indication, so SIE will report a specification
     52          * exception if it was not set.
     53          */
     54         cpu->env.psw.mask ^= PSW_MASK_SHORTPSW;
     55         cpu->env.psw.addr = spsw & PSW_MASK_SHORT_ADDR;
     56     } else {
     57         /*
     58          * Firmware requires us to set the load state before we set
     59          * the cpu to operating on protected guests.
     60          */
     61         s390_cpu_set_state(S390_CPU_STATE_LOAD, cpu);
     62     }
     63     s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
     64 }
     65 
     66 void s390_cpu_machine_reset_cb(void *opaque)
     67 {
     68     S390CPU *cpu = opaque;
     69 
     70     run_on_cpu(CPU(cpu), s390_do_cpu_full_reset, RUN_ON_CPU_NULL);
     71 }
     72 
     73 static GuestPanicInformation *s390_cpu_get_crash_info(CPUState *cs)
     74 {
     75     GuestPanicInformation *panic_info;
     76     S390CPU *cpu = S390_CPU(cs);
     77 
     78     cpu_synchronize_state(cs);
     79     panic_info = g_new0(GuestPanicInformation, 1);
     80 
     81     panic_info->type = GUEST_PANIC_INFORMATION_TYPE_S390;
     82     panic_info->u.s390.core = cpu->env.core_id;
     83     panic_info->u.s390.psw_mask = cpu->env.psw.mask;
     84     panic_info->u.s390.psw_addr = cpu->env.psw.addr;
     85     panic_info->u.s390.reason = cpu->env.crash_reason;
     86 
     87     return panic_info;
     88 }
     89 
     90 static void s390_cpu_get_crash_info_qom(Object *obj, Visitor *v,
     91                                         const char *name, void *opaque,
     92                                         Error **errp)
     93 {
     94     CPUState *cs = CPU(obj);
     95     GuestPanicInformation *panic_info;
     96 
     97     if (!cs->crash_occurred) {
     98         error_setg(errp, "No crash occurred");
     99         return;
    100     }
    101 
    102     panic_info = s390_cpu_get_crash_info(cs);
    103 
    104     visit_type_GuestPanicInformation(v, "crash-information", &panic_info,
    105                                      errp);
    106     qapi_free_GuestPanicInformation(panic_info);
    107 }
    108 
    109 void s390_cpu_init_sysemu(Object *obj)
    110 {
    111     CPUState *cs = CPU(obj);
    112     S390CPU *cpu = S390_CPU(obj);
    113 
    114     cs->start_powered_off = true;
    115     object_property_add(obj, "crash-information", "GuestPanicInformation",
    116                         s390_cpu_get_crash_info_qom, NULL, NULL, NULL);
    117     cpu->env.tod_timer =
    118         timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_tod_timer, cpu);
    119     cpu->env.cpu_timer =
    120         timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_cpu_timer, cpu);
    121     s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu);
    122 }
    123 
    124 bool s390_cpu_realize_sysemu(DeviceState *dev, Error **errp)
    125 {
    126     S390CPU *cpu = S390_CPU(dev);
    127     MachineState *ms = MACHINE(qdev_get_machine());
    128     unsigned int max_cpus = ms->smp.max_cpus;
    129 
    130     if (cpu->env.core_id >= max_cpus) {
    131         error_setg(errp, "Unable to add CPU with core-id: %" PRIu32
    132                    ", maximum core-id: %d", cpu->env.core_id,
    133                    max_cpus - 1);
    134         return false;
    135     }
    136 
    137     if (cpu_exists(cpu->env.core_id)) {
    138         error_setg(errp, "Unable to add CPU with core-id: %" PRIu32
    139                    ", it already exists", cpu->env.core_id);
    140         return false;
    141     }
    142 
    143     /* sync cs->cpu_index and env->core_id. The latter is needed for TCG. */
    144     CPU(cpu)->cpu_index = cpu->env.core_id;
    145     return true;
    146 }
    147 
    148 void s390_cpu_finalize(Object *obj)
    149 {
    150     S390CPU *cpu = S390_CPU(obj);
    151 
    152     timer_free(cpu->env.tod_timer);
    153     timer_free(cpu->env.cpu_timer);
    154 
    155     qemu_unregister_reset(s390_cpu_machine_reset_cb, cpu);
    156     g_free(cpu->irqstate);
    157 }
    158 
    159 static const struct SysemuCPUOps s390_sysemu_ops = {
    160     .get_phys_page_debug = s390_cpu_get_phys_page_debug,
    161     .get_crash_info = s390_cpu_get_crash_info,
    162     .write_elf64_note = s390_cpu_write_elf64_note,
    163     .legacy_vmsd = &vmstate_s390_cpu,
    164 };
    165 
    166 void s390_cpu_class_init_sysemu(CPUClass *cc)
    167 {
    168     S390CPUClass *scc = S390_CPU_CLASS(cc);
    169 
    170     scc->load_normal = s390_cpu_load_normal;
    171     cc->sysemu_ops = &s390_sysemu_ops;
    172 }
    173 
    174 static bool disabled_wait(CPUState *cpu)
    175 {
    176     return cpu->halted && !(S390_CPU(cpu)->env.psw.mask &
    177                             (PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK));
    178 }
    179 
    180 static unsigned s390_count_running_cpus(void)
    181 {
    182     CPUState *cpu;
    183     int nr_running = 0;
    184 
    185     CPU_FOREACH(cpu) {
    186         uint8_t state = S390_CPU(cpu)->env.cpu_state;
    187         if (state == S390_CPU_STATE_OPERATING ||
    188             state == S390_CPU_STATE_LOAD) {
    189             if (!disabled_wait(cpu)) {
    190                 nr_running++;
    191             }
    192         }
    193     }
    194 
    195     return nr_running;
    196 }
    197 
    198 unsigned int s390_cpu_halt(S390CPU *cpu)
    199 {
    200     CPUState *cs = CPU(cpu);
    201     trace_cpu_halt(cs->cpu_index);
    202 
    203     if (!cs->halted) {
    204         cs->halted = 1;
    205         cs->exception_index = EXCP_HLT;
    206     }
    207 
    208     return s390_count_running_cpus();
    209 }
    210 
    211 void s390_cpu_unhalt(S390CPU *cpu)
    212 {
    213     CPUState *cs = CPU(cpu);
    214     trace_cpu_unhalt(cs->cpu_index);
    215 
    216     if (cs->halted) {
    217         cs->halted = 0;
    218         cs->exception_index = -1;
    219     }
    220 }
    221 
    222 unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu)
    223  {
    224     trace_cpu_set_state(CPU(cpu)->cpu_index, cpu_state);
    225 
    226     switch (cpu_state) {
    227     case S390_CPU_STATE_STOPPED:
    228     case S390_CPU_STATE_CHECK_STOP:
    229         /* halt the cpu for common infrastructure */
    230         s390_cpu_halt(cpu);
    231         break;
    232     case S390_CPU_STATE_OPERATING:
    233     case S390_CPU_STATE_LOAD:
    234         /*
    235          * Starting a CPU with a PSW WAIT bit set:
    236          * KVM: handles this internally and triggers another WAIT exit.
    237          * TCG: will actually try to continue to run. Don't unhalt, will
    238          *      be done when the CPU actually has work (an interrupt).
    239          */
    240         if (!tcg_enabled() || !(cpu->env.psw.mask & PSW_MASK_WAIT)) {
    241             s390_cpu_unhalt(cpu);
    242         }
    243         break;
    244     default:
    245         error_report("Requested CPU state is not a valid S390 CPU state: %u",
    246                      cpu_state);
    247         exit(1);
    248     }
    249     if (kvm_enabled() && cpu->env.cpu_state != cpu_state) {
    250         kvm_s390_set_cpu_state(cpu, cpu_state);
    251     }
    252     cpu->env.cpu_state = cpu_state;
    253 
    254     return s390_count_running_cpus();
    255 }
    256 
    257 int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit)
    258 {
    259     if (kvm_enabled()) {
    260         return kvm_s390_set_mem_limit(new_limit, hw_limit);
    261     }
    262     return 0;
    263 }
    264 
    265 void s390_set_max_pagesize(uint64_t pagesize, Error **errp)
    266 {
    267     if (kvm_enabled()) {
    268         kvm_s390_set_max_pagesize(pagesize, errp);
    269     }
    270 }
    271 
    272 void s390_cmma_reset(void)
    273 {
    274     if (kvm_enabled()) {
    275         kvm_s390_cmma_reset();
    276     }
    277 }
    278 
    279 int s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch_id,
    280                                 int vq, bool assign)
    281 {
    282     if (kvm_enabled()) {
    283         return kvm_s390_assign_subch_ioeventfd(notifier, sch_id, vq, assign);
    284     } else {
    285         return 0;
    286     }
    287 }
    288 
    289 void s390_crypto_reset(void)
    290 {
    291     if (kvm_enabled()) {
    292         kvm_s390_crypto_reset();
    293     }
    294 }
    295 
    296 void s390_enable_css_support(S390CPU *cpu)
    297 {
    298     if (kvm_enabled()) {
    299         kvm_s390_enable_css_support(cpu);
    300     }
    301 }
    302 
    303 void s390_do_cpu_set_diag318(CPUState *cs, run_on_cpu_data arg)
    304 {
    305     if (kvm_enabled()) {
    306         kvm_s390_set_diag318(cs, arg.host_ulong);
    307     }
    308 }