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

sparc64.c (8732B)


      1/*
      2 * QEMU Sun4u/Sun4v System Emulator common routines
      3 *
      4 * Copyright (c) 2005 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
     26#include "qemu/osdep.h"
     27#include "cpu.h"
     28#include "hw/boards.h"
     29#include "hw/sparc/sparc64.h"
     30#include "qemu/timer.h"
     31#include "sysemu/reset.h"
     32#include "trace.h"
     33
     34
     35#define TICK_MAX             0x7fffffffffffffffULL
     36
     37static void cpu_kick_irq(SPARCCPU *cpu)
     38{
     39    CPUState *cs = CPU(cpu);
     40    CPUSPARCState *env = &cpu->env;
     41
     42    cs->halted = 0;
     43    cpu_check_irqs(env);
     44    qemu_cpu_kick(cs);
     45}
     46
     47void sparc64_cpu_set_ivec_irq(void *opaque, int irq, int level)
     48{
     49    SPARCCPU *cpu = opaque;
     50    CPUSPARCState *env = &cpu->env;
     51    CPUState *cs;
     52
     53    if (level) {
     54        if (!(env->ivec_status & 0x20)) {
     55            trace_sparc64_cpu_ivec_raise_irq(irq);
     56            cs = CPU(cpu);
     57            cs->halted = 0;
     58            env->interrupt_index = TT_IVEC;
     59            env->ivec_status |= 0x20;
     60            env->ivec_data[0] = (0x1f << 6) | irq;
     61            env->ivec_data[1] = 0;
     62            env->ivec_data[2] = 0;
     63            cpu_interrupt(cs, CPU_INTERRUPT_HARD);
     64        }
     65    } else {
     66        if (env->ivec_status & 0x20) {
     67            trace_sparc64_cpu_ivec_lower_irq(irq);
     68            cs = CPU(cpu);
     69            env->ivec_status &= ~0x20;
     70            cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
     71        }
     72    }
     73}
     74
     75typedef struct ResetData {
     76    SPARCCPU *cpu;
     77    uint64_t prom_addr;
     78} ResetData;
     79
     80static CPUTimer *cpu_timer_create(const char *name, SPARCCPU *cpu,
     81                                  QEMUBHFunc *cb, uint32_t frequency,
     82                                  uint64_t disabled_mask, uint64_t npt_mask)
     83{
     84    CPUTimer *timer = g_malloc0(sizeof(CPUTimer));
     85
     86    timer->name = name;
     87    timer->frequency = frequency;
     88    timer->disabled_mask = disabled_mask;
     89    timer->npt_mask = npt_mask;
     90
     91    timer->disabled = 1;
     92    timer->npt = 1;
     93    timer->clock_offset = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
     94
     95    timer->qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cb, cpu);
     96
     97    return timer;
     98}
     99
    100static void cpu_timer_reset(CPUTimer *timer)
    101{
    102    timer->disabled = 1;
    103    timer->clock_offset = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
    104
    105    timer_del(timer->qtimer);
    106}
    107
    108static void main_cpu_reset(void *opaque)
    109{
    110    ResetData *s = (ResetData *)opaque;
    111    CPUSPARCState *env = &s->cpu->env;
    112    static unsigned int nr_resets;
    113
    114    cpu_reset(CPU(s->cpu));
    115
    116    cpu_timer_reset(env->tick);
    117    cpu_timer_reset(env->stick);
    118    cpu_timer_reset(env->hstick);
    119
    120    env->gregs[1] = 0; /* Memory start */
    121    env->gregs[2] = current_machine->ram_size; /* Memory size */
    122    env->gregs[3] = 0; /* Machine description XXX */
    123    if (nr_resets++ == 0) {
    124        /* Power on reset */
    125        env->pc = s->prom_addr + 0x20ULL;
    126    } else {
    127        env->pc = s->prom_addr + 0x40ULL;
    128    }
    129    env->npc = env->pc + 4;
    130}
    131
    132static void tick_irq(void *opaque)
    133{
    134    SPARCCPU *cpu = opaque;
    135    CPUSPARCState *env = &cpu->env;
    136
    137    CPUTimer *timer = env->tick;
    138
    139    if (timer->disabled) {
    140        trace_sparc64_cpu_tick_irq_disabled();
    141        return;
    142    } else {
    143        trace_sparc64_cpu_tick_irq_fire();
    144    }
    145
    146    env->softint |= SOFTINT_TIMER;
    147    cpu_kick_irq(cpu);
    148}
    149
    150static void stick_irq(void *opaque)
    151{
    152    SPARCCPU *cpu = opaque;
    153    CPUSPARCState *env = &cpu->env;
    154
    155    CPUTimer *timer = env->stick;
    156
    157    if (timer->disabled) {
    158        trace_sparc64_cpu_stick_irq_disabled();
    159        return;
    160    } else {
    161        trace_sparc64_cpu_stick_irq_fire();
    162    }
    163
    164    env->softint |= SOFTINT_STIMER;
    165    cpu_kick_irq(cpu);
    166}
    167
    168static void hstick_irq(void *opaque)
    169{
    170    SPARCCPU *cpu = opaque;
    171    CPUSPARCState *env = &cpu->env;
    172
    173    CPUTimer *timer = env->hstick;
    174
    175    if (timer->disabled) {
    176        trace_sparc64_cpu_hstick_irq_disabled();
    177        return;
    178    } else {
    179        trace_sparc64_cpu_hstick_irq_fire();
    180    }
    181
    182    env->softint |= SOFTINT_STIMER;
    183    cpu_kick_irq(cpu);
    184}
    185
    186static int64_t cpu_to_timer_ticks(int64_t cpu_ticks, uint32_t frequency)
    187{
    188    return muldiv64(cpu_ticks, NANOSECONDS_PER_SECOND, frequency);
    189}
    190
    191static uint64_t timer_to_cpu_ticks(int64_t timer_ticks, uint32_t frequency)
    192{
    193    return muldiv64(timer_ticks, frequency, NANOSECONDS_PER_SECOND);
    194}
    195
    196void cpu_tick_set_count(CPUTimer *timer, uint64_t count)
    197{
    198    uint64_t real_count = count & ~timer->npt_mask;
    199    uint64_t npt_bit = count & timer->npt_mask;
    200
    201    int64_t vm_clock_offset = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) -
    202                    cpu_to_timer_ticks(real_count, timer->frequency);
    203
    204    trace_sparc64_cpu_tick_set_count(timer->name, real_count,
    205                                     timer->npt ? "disabled" : "enabled",
    206                                     timer);
    207
    208    timer->npt = npt_bit ? 1 : 0;
    209    timer->clock_offset = vm_clock_offset;
    210}
    211
    212uint64_t cpu_tick_get_count(CPUTimer *timer)
    213{
    214    uint64_t real_count = timer_to_cpu_ticks(
    215                    qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - timer->clock_offset,
    216                    timer->frequency);
    217
    218    trace_sparc64_cpu_tick_get_count(timer->name, real_count,
    219                                     timer->npt ? "disabled" : "enabled",
    220                                     timer);
    221
    222    if (timer->npt) {
    223        real_count |= timer->npt_mask;
    224    }
    225
    226    return real_count;
    227}
    228
    229void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit)
    230{
    231    int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
    232
    233    uint64_t real_limit = limit & ~timer->disabled_mask;
    234    timer->disabled = (limit & timer->disabled_mask) ? 1 : 0;
    235
    236    int64_t expires = cpu_to_timer_ticks(real_limit, timer->frequency) +
    237                    timer->clock_offset;
    238
    239    if (expires < now) {
    240        expires = now + 1;
    241    }
    242
    243    trace_sparc64_cpu_tick_set_limit(timer->name, real_limit,
    244                                     timer->disabled ? "disabled" : "enabled",
    245                                     timer, limit,
    246                                     timer_to_cpu_ticks(
    247                                         now - timer->clock_offset,
    248                                         timer->frequency
    249                                     ),
    250                                     timer_to_cpu_ticks(
    251                                         expires - now, timer->frequency
    252                                     ));
    253
    254    if (!real_limit) {
    255        trace_sparc64_cpu_tick_set_limit_zero(timer->name);
    256        timer_del(timer->qtimer);
    257    } else if (timer->disabled) {
    258        timer_del(timer->qtimer);
    259    } else {
    260        timer_mod(timer->qtimer, expires);
    261    }
    262}
    263
    264SPARCCPU *sparc64_cpu_devinit(const char *cpu_type, uint64_t prom_addr)
    265{
    266    SPARCCPU *cpu;
    267    CPUSPARCState *env;
    268    ResetData *reset_info;
    269
    270    uint32_t   tick_frequency = 100 * 1000000;
    271    uint32_t  stick_frequency = 100 * 1000000;
    272    uint32_t hstick_frequency = 100 * 1000000;
    273
    274    cpu = SPARC_CPU(cpu_create(cpu_type));
    275    qdev_init_gpio_in_named(DEVICE(cpu), sparc64_cpu_set_ivec_irq,
    276                            "ivec-irq", IVEC_MAX);
    277    env = &cpu->env;
    278
    279    env->tick = cpu_timer_create("tick", cpu, tick_irq,
    280                                  tick_frequency, TICK_INT_DIS,
    281                                  TICK_NPT_MASK);
    282
    283    env->stick = cpu_timer_create("stick", cpu, stick_irq,
    284                                   stick_frequency, TICK_INT_DIS,
    285                                   TICK_NPT_MASK);
    286
    287    env->hstick = cpu_timer_create("hstick", cpu, hstick_irq,
    288                                    hstick_frequency, TICK_INT_DIS,
    289                                    TICK_NPT_MASK);
    290
    291    reset_info = g_malloc0(sizeof(ResetData));
    292    reset_info->cpu = cpu;
    293    reset_info->prom_addr = prom_addr;
    294    qemu_register_reset(main_cpu_reset, reset_info);
    295
    296    return cpu;
    297}