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

ppc_booke.c (11899B)


      1/*
      2 * QEMU PowerPC Booke hardware System Emulator
      3 *
      4 * Copyright (c) 2011 AdaCore
      5 *
      6 * Permission is hereby granted, free of charge, to any person obtaining a copy
      7 * of this software and associated documentation files (the "Software"), to deal
      8 * in the Software without restriction, including without limitation the rights
      9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10 * copies of the Software, and to permit persons to whom the Software is
     11 * furnished to do so, subject to the following conditions:
     12 *
     13 * The above copyright notice and this permission notice shall be included in
     14 * all copies or substantial portions of the Software.
     15 *
     16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     22 * THE SOFTWARE.
     23 */
     24
     25#include "qemu/osdep.h"
     26#include "cpu.h"
     27#include "hw/ppc/ppc.h"
     28#include "qemu/timer.h"
     29#include "sysemu/reset.h"
     30#include "sysemu/runstate.h"
     31#include "hw/loader.h"
     32#include "kvm_ppc.h"
     33
     34
     35/* Timer Control Register */
     36
     37#define TCR_WP_SHIFT  30        /* Watchdog Timer Period */
     38#define TCR_WP_MASK   (0x3U << TCR_WP_SHIFT)
     39#define TCR_WRC_SHIFT 28        /* Watchdog Timer Reset Control */
     40#define TCR_WRC_MASK  (0x3U << TCR_WRC_SHIFT)
     41#define TCR_WIE       (1U << 27) /* Watchdog Timer Interrupt Enable */
     42#define TCR_DIE       (1U << 26) /* Decrementer Interrupt Enable */
     43#define TCR_FP_SHIFT  24        /* Fixed-Interval Timer Period */
     44#define TCR_FP_MASK   (0x3U << TCR_FP_SHIFT)
     45#define TCR_FIE       (1U << 23) /* Fixed-Interval Timer Interrupt Enable */
     46#define TCR_ARE       (1U << 22) /* Auto-Reload Enable */
     47
     48/* Timer Control Register (e500 specific fields) */
     49
     50#define TCR_E500_FPEXT_SHIFT 13 /* Fixed-Interval Timer Period Extension */
     51#define TCR_E500_FPEXT_MASK  (0xf << TCR_E500_FPEXT_SHIFT)
     52#define TCR_E500_WPEXT_SHIFT 17 /* Watchdog Timer Period Extension */
     53#define TCR_E500_WPEXT_MASK  (0xf << TCR_E500_WPEXT_SHIFT)
     54
     55/* Timer Status Register  */
     56
     57#define TSR_FIS       (1U << 26) /* Fixed-Interval Timer Interrupt Status */
     58#define TSR_DIS       (1U << 27) /* Decrementer Interrupt Status */
     59#define TSR_WRS_SHIFT 28        /* Watchdog Timer Reset Status */
     60#define TSR_WRS_MASK  (0x3U << TSR_WRS_SHIFT)
     61#define TSR_WIS       (1U << 30) /* Watchdog Timer Interrupt Status */
     62#define TSR_ENW       (1U << 31) /* Enable Next Watchdog Timer */
     63
     64typedef struct booke_timer_t booke_timer_t;
     65struct booke_timer_t {
     66
     67    uint64_t fit_next;
     68    QEMUTimer *fit_timer;
     69
     70    uint64_t wdt_next;
     71    QEMUTimer *wdt_timer;
     72
     73    uint32_t flags;
     74};
     75
     76static void booke_update_irq(PowerPCCPU *cpu)
     77{
     78    CPUPPCState *env = &cpu->env;
     79
     80    ppc_set_irq(cpu, PPC_INTERRUPT_DECR,
     81                (env->spr[SPR_BOOKE_TSR] & TSR_DIS
     82                 && env->spr[SPR_BOOKE_TCR] & TCR_DIE));
     83
     84    ppc_set_irq(cpu, PPC_INTERRUPT_WDT,
     85                (env->spr[SPR_BOOKE_TSR] & TSR_WIS
     86                 && env->spr[SPR_BOOKE_TCR] & TCR_WIE));
     87
     88    ppc_set_irq(cpu, PPC_INTERRUPT_FIT,
     89                (env->spr[SPR_BOOKE_TSR] & TSR_FIS
     90                 && env->spr[SPR_BOOKE_TCR] & TCR_FIE));
     91}
     92
     93/* Return the location of the bit of time base at which the FIT will raise an
     94   interrupt */
     95static uint8_t booke_get_fit_target(CPUPPCState *env, ppc_tb_t *tb_env)
     96{
     97    uint8_t fp = (env->spr[SPR_BOOKE_TCR] & TCR_FP_MASK) >> TCR_FP_SHIFT;
     98
     99    if (tb_env->flags & PPC_TIMER_E500) {
    100        /* e500 Fixed-interval timer period extension */
    101        uint32_t fpext = (env->spr[SPR_BOOKE_TCR] & TCR_E500_FPEXT_MASK)
    102            >> TCR_E500_FPEXT_SHIFT;
    103        fp = 63 - (fp | fpext << 2);
    104    } else {
    105        fp = env->fit_period[fp];
    106    }
    107
    108    return fp;
    109}
    110
    111/* Return the location of the bit of time base at which the WDT will raise an
    112   interrupt */
    113static uint8_t booke_get_wdt_target(CPUPPCState *env, ppc_tb_t *tb_env)
    114{
    115    uint8_t wp = (env->spr[SPR_BOOKE_TCR] & TCR_WP_MASK) >> TCR_WP_SHIFT;
    116
    117    if (tb_env->flags & PPC_TIMER_E500) {
    118        /* e500 Watchdog timer period extension */
    119        uint32_t wpext = (env->spr[SPR_BOOKE_TCR] & TCR_E500_WPEXT_MASK)
    120            >> TCR_E500_WPEXT_SHIFT;
    121        wp = 63 - (wp | wpext << 2);
    122    } else {
    123        wp = env->wdt_period[wp];
    124    }
    125
    126    return wp;
    127}
    128
    129static void booke_update_fixed_timer(CPUPPCState         *env,
    130                                     uint8_t           target_bit,
    131                                     uint64_t          *next,
    132                                     QEMUTimer         *timer,
    133                                     int               tsr_bit)
    134{
    135    ppc_tb_t *tb_env = env->tb_env;
    136    uint64_t delta_tick, ticks = 0;
    137    uint64_t tb;
    138    uint64_t period;
    139    uint64_t now;
    140
    141    if (!(env->spr[SPR_BOOKE_TSR] & tsr_bit)) {
    142        /*
    143         * Don't arm the timer again when the guest has the current
    144         * interrupt still pending. Wait for it to ack it.
    145         */
    146        return;
    147    }
    148
    149    now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
    150    tb  = cpu_ppc_get_tb(tb_env, now, tb_env->tb_offset);
    151    period = 1ULL << target_bit;
    152    delta_tick = period - (tb & (period - 1));
    153
    154    /* the timer triggers only when the selected bit toggles from 0 to 1 */
    155    if (tb & period) {
    156        ticks = period;
    157    }
    158
    159    if (ticks + delta_tick < ticks) {
    160        /* Overflow, so assume the biggest number we can express. */
    161        ticks = UINT64_MAX;
    162    } else {
    163        ticks += delta_tick;
    164    }
    165
    166    *next = now + muldiv64(ticks, NANOSECONDS_PER_SECOND, tb_env->tb_freq);
    167    if ((*next < now) || (*next > INT64_MAX)) {
    168        /* Overflow, so assume the biggest number the qemu timer supports. */
    169        *next = INT64_MAX;
    170    }
    171
    172    /* XXX: If expire time is now. We can't run the callback because we don't
    173     * have access to it. So we just set the timer one nanosecond later.
    174     */
    175
    176    if (*next == now) {
    177        (*next)++;
    178    } else {
    179        /*
    180         * There's no point to fake any granularity that's more fine grained
    181         * than milliseconds. Anything beyond that just overloads the system.
    182         */
    183        *next = MAX(*next, now + SCALE_MS);
    184    }
    185
    186    /* Fire the next timer */
    187    timer_mod(timer, *next);
    188}
    189
    190static void booke_decr_cb(void *opaque)
    191{
    192    PowerPCCPU *cpu = opaque;
    193    CPUPPCState *env = &cpu->env;
    194
    195    env->spr[SPR_BOOKE_TSR] |= TSR_DIS;
    196    booke_update_irq(cpu);
    197
    198    if (env->spr[SPR_BOOKE_TCR] & TCR_ARE) {
    199        /* Do not reload 0, it is already there. It would just trigger
    200         * the timer again and lead to infinite loop */
    201        if (env->spr[SPR_BOOKE_DECAR] != 0) {
    202            /* Auto Reload */
    203            cpu_ppc_store_decr(env, env->spr[SPR_BOOKE_DECAR]);
    204        }
    205    }
    206}
    207
    208static void booke_fit_cb(void *opaque)
    209{
    210    PowerPCCPU *cpu = opaque;
    211    CPUPPCState *env = &cpu->env;
    212    ppc_tb_t *tb_env;
    213    booke_timer_t *booke_timer;
    214
    215    tb_env = env->tb_env;
    216    booke_timer = tb_env->opaque;
    217    env->spr[SPR_BOOKE_TSR] |= TSR_FIS;
    218
    219    booke_update_irq(cpu);
    220
    221    booke_update_fixed_timer(env,
    222                             booke_get_fit_target(env, tb_env),
    223                             &booke_timer->fit_next,
    224                             booke_timer->fit_timer,
    225                             TSR_FIS);
    226}
    227
    228static void booke_wdt_cb(void *opaque)
    229{
    230    PowerPCCPU *cpu = opaque;
    231    CPUPPCState *env = &cpu->env;
    232    ppc_tb_t *tb_env;
    233    booke_timer_t *booke_timer;
    234
    235    tb_env = env->tb_env;
    236    booke_timer = tb_env->opaque;
    237
    238    /* TODO: There's lots of complicated stuff to do here */
    239
    240    booke_update_irq(cpu);
    241
    242    booke_update_fixed_timer(env,
    243                             booke_get_wdt_target(env, tb_env),
    244                             &booke_timer->wdt_next,
    245                             booke_timer->wdt_timer,
    246                             TSR_WIS);
    247}
    248
    249void store_booke_tsr(CPUPPCState *env, target_ulong val)
    250{
    251    PowerPCCPU *cpu = env_archcpu(env);
    252    ppc_tb_t *tb_env = env->tb_env;
    253    booke_timer_t *booke_timer = tb_env->opaque;
    254
    255    env->spr[SPR_BOOKE_TSR] &= ~val;
    256    kvmppc_clear_tsr_bits(cpu, val);
    257
    258    if (val & TSR_FIS) {
    259        booke_update_fixed_timer(env,
    260                                 booke_get_fit_target(env, tb_env),
    261                                 &booke_timer->fit_next,
    262                                 booke_timer->fit_timer,
    263                                 TSR_FIS);
    264    }
    265
    266    if (val & TSR_WIS) {
    267        booke_update_fixed_timer(env,
    268                                 booke_get_wdt_target(env, tb_env),
    269                                 &booke_timer->wdt_next,
    270                                 booke_timer->wdt_timer,
    271                                 TSR_WIS);
    272    }
    273
    274    booke_update_irq(cpu);
    275}
    276
    277void store_booke_tcr(CPUPPCState *env, target_ulong val)
    278{
    279    PowerPCCPU *cpu = env_archcpu(env);
    280    ppc_tb_t *tb_env = env->tb_env;
    281    booke_timer_t *booke_timer = tb_env->opaque;
    282
    283    env->spr[SPR_BOOKE_TCR] = val;
    284    kvmppc_set_tcr(cpu);
    285
    286    booke_update_irq(cpu);
    287
    288    booke_update_fixed_timer(env,
    289                             booke_get_fit_target(env, tb_env),
    290                             &booke_timer->fit_next,
    291                             booke_timer->fit_timer,
    292                             TSR_FIS);
    293
    294    booke_update_fixed_timer(env,
    295                             booke_get_wdt_target(env, tb_env),
    296                             &booke_timer->wdt_next,
    297                             booke_timer->wdt_timer,
    298                             TSR_WIS);
    299}
    300
    301static void ppc_booke_timer_reset_handle(void *opaque)
    302{
    303    PowerPCCPU *cpu = opaque;
    304    CPUPPCState *env = &cpu->env;
    305
    306    store_booke_tcr(env, 0);
    307    store_booke_tsr(env, -1);
    308}
    309
    310/*
    311 * This function will be called whenever the CPU state changes.
    312 * CPU states are defined "typedef enum RunState".
    313 * Regarding timer, When CPU state changes to running after debug halt
    314 * or similar cases which takes time then in between final watchdog
    315 * expiry happenes. This will cause exit to QEMU and configured watchdog
    316 * action will be taken. To avoid this we always clear the watchdog state when
    317 * state changes to running.
    318 */
    319static void cpu_state_change_handler(void *opaque, bool running, RunState state)
    320{
    321    PowerPCCPU *cpu = opaque;
    322    CPUPPCState *env = &cpu->env;
    323
    324    if (!running) {
    325        return;
    326    }
    327
    328    /*
    329     * Clear watchdog interrupt condition by clearing TSR.
    330     */
    331    store_booke_tsr(env, TSR_ENW | TSR_WIS | TSR_WRS_MASK);
    332}
    333
    334void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags)
    335{
    336    ppc_tb_t *tb_env;
    337    booke_timer_t *booke_timer;
    338    int ret = 0;
    339
    340    tb_env      = g_malloc0(sizeof(ppc_tb_t));
    341    booke_timer = g_malloc0(sizeof(booke_timer_t));
    342
    343    cpu->env.tb_env = tb_env;
    344    tb_env->flags = flags | PPC_TIMER_BOOKE | PPC_DECR_ZERO_TRIGGERED;
    345
    346    tb_env->tb_freq    = freq;
    347    tb_env->decr_freq  = freq;
    348    tb_env->opaque     = booke_timer;
    349    tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &booke_decr_cb, cpu);
    350
    351    booke_timer->fit_timer =
    352        timer_new_ns(QEMU_CLOCK_VIRTUAL, &booke_fit_cb, cpu);
    353    booke_timer->wdt_timer =
    354        timer_new_ns(QEMU_CLOCK_VIRTUAL, &booke_wdt_cb, cpu);
    355
    356    ret = kvmppc_booke_watchdog_enable(cpu);
    357
    358    if (ret) {
    359        /* TODO: Start the QEMU emulated watchdog if not running on KVM.
    360         * Also start the QEMU emulated watchdog if KVM does not support
    361         * emulated watchdog or somehow it is not enabled (supported but
    362         * not enabled is though some bug and requires debugging :)).
    363         */
    364    }
    365
    366    qemu_add_vm_change_state_handler(cpu_state_change_handler, cpu);
    367
    368    qemu_register_reset(ppc_booke_timer_reset_handle, cpu);
    369}