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

psci.c (6377B)


      1/*
      2 * Copyright (C) 2014 - Linaro
      3 * Author: Rob Herring <rob.herring@linaro.org>
      4 *
      5 *  This program is free software; you can redistribute it and/or modify
      6 *  it under the terms of the GNU General Public License as published by
      7 *  the Free Software Foundation; either version 2 of the License, or
      8 *  (at your option) any later version.
      9 *
     10 *  This program is distributed in the hope that it will be useful,
     11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 *  GNU General Public License for more details.
     14 *
     15 *  You should have received a copy of the GNU General Public License
     16 *  along with this program; if not, see <http://www.gnu.org/licenses/>.
     17 */
     18
     19#include "qemu/osdep.h"
     20#include "cpu.h"
     21#include "exec/helper-proto.h"
     22#include "kvm-consts.h"
     23#include "qemu/main-loop.h"
     24#include "sysemu/runstate.h"
     25#include "internals.h"
     26#include "arm-powerctl.h"
     27
     28bool arm_is_psci_call(ARMCPU *cpu, int excp_type)
     29{
     30    /*
     31     * Return true if the exception type matches the configured PSCI conduit.
     32     * This is called before the SMC/HVC instruction is executed, to decide
     33     * whether we should treat it as a PSCI call or with the architecturally
     34     * defined behaviour for an SMC or HVC (which might be UNDEF or trap
     35     * to EL2 or to EL3).
     36     */
     37
     38    switch (excp_type) {
     39    case EXCP_HVC:
     40        if (cpu->psci_conduit != QEMU_PSCI_CONDUIT_HVC) {
     41            return false;
     42        }
     43        break;
     44    case EXCP_SMC:
     45        if (cpu->psci_conduit != QEMU_PSCI_CONDUIT_SMC) {
     46            return false;
     47        }
     48        break;
     49    default:
     50        return false;
     51    }
     52
     53    return true;
     54}
     55
     56void arm_handle_psci_call(ARMCPU *cpu)
     57{
     58    /*
     59     * This function partially implements the logic for dispatching Power State
     60     * Coordination Interface (PSCI) calls (as described in ARM DEN 0022B.b),
     61     * to the extent required for bringing up and taking down secondary cores,
     62     * and for handling reset and poweroff requests.
     63     * Additional information about the calling convention used is available in
     64     * the document 'SMC Calling Convention' (ARM DEN 0028)
     65     */
     66    CPUARMState *env = &cpu->env;
     67    uint64_t param[4];
     68    uint64_t context_id, mpidr;
     69    target_ulong entry;
     70    int32_t ret = 0;
     71    int i;
     72
     73    for (i = 0; i < 4; i++) {
     74        /*
     75         * All PSCI functions take explicit 32-bit or native int sized
     76         * arguments so we can simply zero-extend all arguments regardless
     77         * of which exact function we are about to call.
     78         */
     79        param[i] = is_a64(env) ? env->xregs[i] : env->regs[i];
     80    }
     81
     82    if ((param[0] & QEMU_PSCI_0_2_64BIT) && !is_a64(env)) {
     83        ret = QEMU_PSCI_RET_INVALID_PARAMS;
     84        goto err;
     85    }
     86
     87    switch (param[0]) {
     88        CPUState *target_cpu_state;
     89        ARMCPU *target_cpu;
     90
     91    case QEMU_PSCI_0_2_FN_PSCI_VERSION:
     92        ret = QEMU_PSCI_0_2_RET_VERSION_0_2;
     93        break;
     94    case QEMU_PSCI_0_2_FN_MIGRATE_INFO_TYPE:
     95        ret = QEMU_PSCI_0_2_RET_TOS_MIGRATION_NOT_REQUIRED; /* No trusted OS */
     96        break;
     97    case QEMU_PSCI_0_2_FN_AFFINITY_INFO:
     98    case QEMU_PSCI_0_2_FN64_AFFINITY_INFO:
     99        mpidr = param[1];
    100
    101        switch (param[2]) {
    102        case 0:
    103            target_cpu_state = arm_get_cpu_by_id(mpidr);
    104            if (!target_cpu_state) {
    105                ret = QEMU_PSCI_RET_INVALID_PARAMS;
    106                break;
    107            }
    108            target_cpu = ARM_CPU(target_cpu_state);
    109
    110            g_assert(qemu_mutex_iothread_locked());
    111            ret = target_cpu->power_state;
    112            break;
    113        default:
    114            /* Everything above affinity level 0 is always on. */
    115            ret = 0;
    116        }
    117        break;
    118    case QEMU_PSCI_0_2_FN_SYSTEM_RESET:
    119        qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
    120        /* QEMU reset and shutdown are async requests, but PSCI
    121         * mandates that we never return from the reset/shutdown
    122         * call, so power the CPU off now so it doesn't execute
    123         * anything further.
    124         */
    125        goto cpu_off;
    126    case QEMU_PSCI_0_2_FN_SYSTEM_OFF:
    127        qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
    128        goto cpu_off;
    129    case QEMU_PSCI_0_1_FN_CPU_ON:
    130    case QEMU_PSCI_0_2_FN_CPU_ON:
    131    case QEMU_PSCI_0_2_FN64_CPU_ON:
    132    {
    133        /* The PSCI spec mandates that newly brought up CPUs start
    134         * in the highest exception level which exists and is enabled
    135         * on the calling CPU. Since the QEMU PSCI implementation is
    136         * acting as a "fake EL3" or "fake EL2" firmware, this for us
    137         * means that we want to start at the highest NS exception level
    138         * that we are providing to the guest.
    139         * The execution mode should be that which is currently in use
    140         * by the same exception level on the calling CPU.
    141         * The CPU should be started with the context_id value
    142         * in x0 (if AArch64) or r0 (if AArch32).
    143         */
    144        int target_el = arm_feature(env, ARM_FEATURE_EL2) ? 2 : 1;
    145        bool target_aarch64 = arm_el_is_aa64(env, target_el);
    146
    147        mpidr = param[1];
    148        entry = param[2];
    149        context_id = param[3];
    150        ret = arm_set_cpu_on(mpidr, entry, context_id,
    151                             target_el, target_aarch64);
    152        break;
    153    }
    154    case QEMU_PSCI_0_1_FN_CPU_OFF:
    155    case QEMU_PSCI_0_2_FN_CPU_OFF:
    156        goto cpu_off;
    157    case QEMU_PSCI_0_1_FN_CPU_SUSPEND:
    158    case QEMU_PSCI_0_2_FN_CPU_SUSPEND:
    159    case QEMU_PSCI_0_2_FN64_CPU_SUSPEND:
    160        /* Affinity levels are not supported in QEMU */
    161        if (param[1] & 0xfffe0000) {
    162            ret = QEMU_PSCI_RET_INVALID_PARAMS;
    163            break;
    164        }
    165        /* Powerdown is not supported, we always go into WFI */
    166        if (is_a64(env)) {
    167            env->xregs[0] = 0;
    168        } else {
    169            env->regs[0] = 0;
    170        }
    171        helper_wfi(env, 4);
    172        break;
    173    case QEMU_PSCI_0_1_FN_MIGRATE:
    174    case QEMU_PSCI_0_2_FN_MIGRATE:
    175    default:
    176        ret = QEMU_PSCI_RET_NOT_SUPPORTED;
    177        break;
    178    }
    179
    180err:
    181    if (is_a64(env)) {
    182        env->xregs[0] = ret;
    183    } else {
    184        env->regs[0] = ret;
    185    }
    186    return;
    187
    188cpu_off:
    189    ret = arm_set_cpu_off(cpu->mp_affinity);
    190    /* notreached */
    191    /* sanity check in case something failed */
    192    assert(ret == QEMU_ARM_POWERCTL_RET_SUCCESS);
    193}