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

mips_gictimer.c (4463B)


      1/*
      2 * This file is subject to the terms and conditions of the GNU General Public
      3 * License.  See the file "COPYING" in the main directory of this archive
      4 * for more details.
      5 *
      6 * Copyright (C) 2016 Imagination Technologies
      7 */
      8
      9#include "qemu/osdep.h"
     10#include "qemu/timer.h"
     11#include "hw/timer/mips_gictimer.h"
     12
     13#define TIMER_PERIOD 10 /* 10 ns period for 100 Mhz frequency */
     14
     15uint32_t mips_gictimer_get_freq(MIPSGICTimerState *gic)
     16{
     17    return NANOSECONDS_PER_SECOND / TIMER_PERIOD;
     18}
     19
     20static void gic_vptimer_update(MIPSGICTimerState *gictimer,
     21                                   uint32_t vp_index, uint64_t now)
     22{
     23    uint64_t next;
     24    uint32_t wait;
     25
     26    wait = gictimer->vptimers[vp_index].comparelo - gictimer->sh_counterlo -
     27           (uint32_t)(now / TIMER_PERIOD);
     28    next = now + (uint64_t)wait * TIMER_PERIOD;
     29
     30    timer_mod(gictimer->vptimers[vp_index].qtimer, next);
     31}
     32
     33static void gic_vptimer_expire(MIPSGICTimerState *gictimer, uint32_t vp_index,
     34                               uint64_t now)
     35{
     36    if (gictimer->countstop) {
     37        /* timer stopped */
     38        return;
     39    }
     40    gictimer->cb(gictimer->opaque, vp_index);
     41    gic_vptimer_update(gictimer, vp_index, now);
     42}
     43
     44static void gic_vptimer_cb(void *opaque)
     45{
     46    MIPSGICTimerVPState *vptimer = opaque;
     47    MIPSGICTimerState *gictimer = vptimer->gictimer;
     48    gic_vptimer_expire(gictimer, vptimer->vp_index,
     49                       qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
     50}
     51
     52uint32_t mips_gictimer_get_sh_count(MIPSGICTimerState *gictimer)
     53{
     54    int i;
     55    if (gictimer->countstop) {
     56        return gictimer->sh_counterlo;
     57    } else {
     58        uint64_t now;
     59        now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
     60        for (i = 0; i < gictimer->num_vps; i++) {
     61            if (timer_pending(gictimer->vptimers[i].qtimer)
     62                && timer_expired(gictimer->vptimers[i].qtimer, now)) {
     63                /* The timer has already expired.  */
     64                gic_vptimer_expire(gictimer, i, now);
     65            }
     66        }
     67        return gictimer->sh_counterlo + (uint32_t)(now / TIMER_PERIOD);
     68    }
     69}
     70
     71void mips_gictimer_store_sh_count(MIPSGICTimerState *gictimer, uint64_t count)
     72{
     73    int i;
     74    uint64_t now;
     75
     76    if (gictimer->countstop || !gictimer->vptimers[0].qtimer) {
     77        gictimer->sh_counterlo = count;
     78    } else {
     79        /* Store new count register */
     80        now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
     81        gictimer->sh_counterlo = count - (uint32_t)(now / TIMER_PERIOD);
     82        /* Update timer timer */
     83        for (i = 0; i < gictimer->num_vps; i++) {
     84            gic_vptimer_update(gictimer, i, now);
     85        }
     86    }
     87}
     88
     89uint32_t mips_gictimer_get_vp_compare(MIPSGICTimerState *gictimer,
     90                                      uint32_t vp_index)
     91{
     92    return gictimer->vptimers[vp_index].comparelo;
     93}
     94
     95void mips_gictimer_store_vp_compare(MIPSGICTimerState *gictimer,
     96                                    uint32_t vp_index, uint64_t compare)
     97{
     98    gictimer->vptimers[vp_index].comparelo = (uint32_t) compare;
     99    gic_vptimer_update(gictimer, vp_index,
    100                       qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
    101}
    102
    103uint8_t mips_gictimer_get_countstop(MIPSGICTimerState *gictimer)
    104{
    105    return gictimer->countstop;
    106}
    107
    108void mips_gictimer_start_count(MIPSGICTimerState *gictimer)
    109{
    110    gictimer->countstop = 0;
    111    mips_gictimer_store_sh_count(gictimer, gictimer->sh_counterlo);
    112}
    113
    114void mips_gictimer_stop_count(MIPSGICTimerState *gictimer)
    115{
    116    int i;
    117
    118    gictimer->countstop = 1;
    119    /* Store the current value */
    120    gictimer->sh_counterlo +=
    121        (uint32_t)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / TIMER_PERIOD);
    122    for (i = 0; i < gictimer->num_vps; i++) {
    123        timer_del(gictimer->vptimers[i].qtimer);
    124    }
    125}
    126
    127MIPSGICTimerState *mips_gictimer_init(void *opaque, uint32_t nvps,
    128                                      MIPSGICTimerCB *cb)
    129{
    130    int i;
    131    MIPSGICTimerState *gictimer = g_new(MIPSGICTimerState, 1);
    132    gictimer->vptimers = g_new(MIPSGICTimerVPState, nvps);
    133    gictimer->countstop = 1;
    134    gictimer->num_vps = nvps;
    135    gictimer->opaque = opaque;
    136    gictimer->cb = cb;
    137    for (i = 0; i < nvps; i++) {
    138        gictimer->vptimers[i].gictimer = gictimer;
    139        gictimer->vptimers[i].vp_index = i;
    140        gictimer->vptimers[i].qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
    141                                            &gic_vptimer_cb,
    142                                            &gictimer->vptimers[i]);
    143    }
    144    return gictimer;
    145}