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

cpu-timers.c (8165B)


      1/*
      2 * QEMU System Emulator
      3 *
      4 * Copyright (c) 2003-2008 Fabrice Bellard
      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 "qemu-common.h"
     27#include "qemu/cutils.h"
     28#include "migration/vmstate.h"
     29#include "qapi/error.h"
     30#include "qemu/error-report.h"
     31#include "exec/exec-all.h"
     32#include "sysemu/cpus.h"
     33#include "qemu/main-loop.h"
     34#include "qemu/option.h"
     35#include "qemu/seqlock.h"
     36#include "sysemu/replay.h"
     37#include "sysemu/runstate.h"
     38#include "hw/core/cpu.h"
     39#include "sysemu/cpu-timers.h"
     40#include "sysemu/cpu-throttle.h"
     41#include "timers-state.h"
     42
     43/* clock and ticks */
     44
     45static int64_t cpu_get_ticks_locked(void)
     46{
     47    int64_t ticks = timers_state.cpu_ticks_offset;
     48    if (timers_state.cpu_ticks_enabled) {
     49        ticks += cpu_get_host_ticks();
     50    }
     51
     52    if (timers_state.cpu_ticks_prev > ticks) {
     53        /* Non increasing ticks may happen if the host uses software suspend. */
     54        timers_state.cpu_ticks_offset += timers_state.cpu_ticks_prev - ticks;
     55        ticks = timers_state.cpu_ticks_prev;
     56    }
     57
     58    timers_state.cpu_ticks_prev = ticks;
     59    return ticks;
     60}
     61
     62/*
     63 * return the time elapsed in VM between vm_start and vm_stop.
     64 * cpu_get_ticks() uses units of the host CPU cycle counter.
     65 */
     66int64_t cpu_get_ticks(void)
     67{
     68    int64_t ticks;
     69
     70    qemu_spin_lock(&timers_state.vm_clock_lock);
     71    ticks = cpu_get_ticks_locked();
     72    qemu_spin_unlock(&timers_state.vm_clock_lock);
     73    return ticks;
     74}
     75
     76int64_t cpu_get_clock_locked(void)
     77{
     78    int64_t time;
     79
     80    time = timers_state.cpu_clock_offset;
     81    if (timers_state.cpu_ticks_enabled) {
     82        time += get_clock();
     83    }
     84
     85    return time;
     86}
     87
     88/*
     89 * Return the monotonic time elapsed in VM, i.e.,
     90 * the time between vm_start and vm_stop
     91 */
     92int64_t cpu_get_clock(void)
     93{
     94    int64_t ti;
     95    unsigned start;
     96
     97    do {
     98        start = seqlock_read_begin(&timers_state.vm_clock_seqlock);
     99        ti = cpu_get_clock_locked();
    100    } while (seqlock_read_retry(&timers_state.vm_clock_seqlock, start));
    101
    102    return ti;
    103}
    104
    105/*
    106 * enable cpu_get_ticks()
    107 * Caller must hold BQL which serves as mutex for vm_clock_seqlock.
    108 */
    109void cpu_enable_ticks(void)
    110{
    111    seqlock_write_lock(&timers_state.vm_clock_seqlock,
    112                       &timers_state.vm_clock_lock);
    113    if (!timers_state.cpu_ticks_enabled) {
    114        timers_state.cpu_ticks_offset -= cpu_get_host_ticks();
    115        timers_state.cpu_clock_offset -= get_clock();
    116        timers_state.cpu_ticks_enabled = 1;
    117    }
    118    seqlock_write_unlock(&timers_state.vm_clock_seqlock,
    119                       &timers_state.vm_clock_lock);
    120}
    121
    122/*
    123 * disable cpu_get_ticks() : the clock is stopped. You must not call
    124 * cpu_get_ticks() after that.
    125 * Caller must hold BQL which serves as mutex for vm_clock_seqlock.
    126 */
    127void cpu_disable_ticks(void)
    128{
    129    seqlock_write_lock(&timers_state.vm_clock_seqlock,
    130                       &timers_state.vm_clock_lock);
    131    if (timers_state.cpu_ticks_enabled) {
    132        timers_state.cpu_ticks_offset += cpu_get_host_ticks();
    133        timers_state.cpu_clock_offset = cpu_get_clock_locked();
    134        timers_state.cpu_ticks_enabled = 0;
    135    }
    136    seqlock_write_unlock(&timers_state.vm_clock_seqlock,
    137                         &timers_state.vm_clock_lock);
    138}
    139
    140static bool icount_state_needed(void *opaque)
    141{
    142    return icount_enabled();
    143}
    144
    145static bool warp_timer_state_needed(void *opaque)
    146{
    147    TimersState *s = opaque;
    148    return s->icount_warp_timer != NULL;
    149}
    150
    151static bool adjust_timers_state_needed(void *opaque)
    152{
    153    TimersState *s = opaque;
    154    return s->icount_rt_timer != NULL;
    155}
    156
    157static bool icount_shift_state_needed(void *opaque)
    158{
    159    return icount_enabled() == 2;
    160}
    161
    162/*
    163 * Subsection for warp timer migration is optional, because may not be created
    164 */
    165static const VMStateDescription icount_vmstate_warp_timer = {
    166    .name = "timer/icount/warp_timer",
    167    .version_id = 1,
    168    .minimum_version_id = 1,
    169    .needed = warp_timer_state_needed,
    170    .fields = (VMStateField[]) {
    171        VMSTATE_INT64(vm_clock_warp_start, TimersState),
    172        VMSTATE_TIMER_PTR(icount_warp_timer, TimersState),
    173        VMSTATE_END_OF_LIST()
    174    }
    175};
    176
    177static const VMStateDescription icount_vmstate_adjust_timers = {
    178    .name = "timer/icount/timers",
    179    .version_id = 1,
    180    .minimum_version_id = 1,
    181    .needed = adjust_timers_state_needed,
    182    .fields = (VMStateField[]) {
    183        VMSTATE_TIMER_PTR(icount_rt_timer, TimersState),
    184        VMSTATE_TIMER_PTR(icount_vm_timer, TimersState),
    185        VMSTATE_END_OF_LIST()
    186    }
    187};
    188
    189static const VMStateDescription icount_vmstate_shift = {
    190    .name = "timer/icount/shift",
    191    .version_id = 2,
    192    .minimum_version_id = 2,
    193    .needed = icount_shift_state_needed,
    194    .fields = (VMStateField[]) {
    195        VMSTATE_INT16(icount_time_shift, TimersState),
    196        VMSTATE_INT64(last_delta, TimersState),
    197        VMSTATE_END_OF_LIST()
    198    }
    199};
    200
    201/*
    202 * This is a subsection for icount migration.
    203 */
    204static const VMStateDescription icount_vmstate_timers = {
    205    .name = "timer/icount",
    206    .version_id = 1,
    207    .minimum_version_id = 1,
    208    .needed = icount_state_needed,
    209    .fields = (VMStateField[]) {
    210        VMSTATE_INT64(qemu_icount_bias, TimersState),
    211        VMSTATE_INT64(qemu_icount, TimersState),
    212        VMSTATE_END_OF_LIST()
    213    },
    214    .subsections = (const VMStateDescription * []) {
    215        &icount_vmstate_warp_timer,
    216        &icount_vmstate_adjust_timers,
    217        &icount_vmstate_shift,
    218        NULL
    219    }
    220};
    221
    222static const VMStateDescription vmstate_timers = {
    223    .name = "timer",
    224    .version_id = 2,
    225    .minimum_version_id = 1,
    226    .fields = (VMStateField[]) {
    227        VMSTATE_INT64(cpu_ticks_offset, TimersState),
    228        VMSTATE_UNUSED(8),
    229        VMSTATE_INT64_V(cpu_clock_offset, TimersState, 2),
    230        VMSTATE_END_OF_LIST()
    231    },
    232    .subsections = (const VMStateDescription * []) {
    233        &icount_vmstate_timers,
    234        NULL
    235    }
    236};
    237
    238static void do_nothing(CPUState *cpu, run_on_cpu_data unused)
    239{
    240}
    241
    242void qemu_timer_notify_cb(void *opaque, QEMUClockType type)
    243{
    244    if (!icount_enabled() || type != QEMU_CLOCK_VIRTUAL) {
    245        qemu_notify_event();
    246        return;
    247    }
    248
    249    if (qemu_in_vcpu_thread()) {
    250        /*
    251         * A CPU is currently running; kick it back out to the
    252         * tcg_cpu_exec() loop so it will recalculate its
    253         * icount deadline immediately.
    254         */
    255        qemu_cpu_kick(current_cpu);
    256    } else if (first_cpu) {
    257        /*
    258         * qemu_cpu_kick is not enough to kick a halted CPU out of
    259         * qemu_tcg_wait_io_event.  async_run_on_cpu, instead,
    260         * causes cpu_thread_is_idle to return false.  This way,
    261         * handle_icount_deadline can run.
    262         * If we have no CPUs at all for some reason, we don't
    263         * need to do anything.
    264         */
    265        async_run_on_cpu(first_cpu, do_nothing, RUN_ON_CPU_NULL);
    266    }
    267}
    268
    269TimersState timers_state;
    270
    271/* initialize timers state and the cpu throttle for convenience */
    272void cpu_timers_init(void)
    273{
    274    seqlock_init(&timers_state.vm_clock_seqlock);
    275    qemu_spin_init(&timers_state.vm_clock_lock);
    276    vmstate_register(NULL, 0, &vmstate_timers, &timers_state);
    277
    278    cpu_throttle_init();
    279}