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

xlnx-zynqmp-rtc.c (8603B)


      1/*
      2 * QEMU model of the Xilinx ZynqMP Real Time Clock (RTC).
      3 *
      4 * Copyright (c) 2017 Xilinx Inc.
      5 *
      6 * Written-by: Alistair Francis <alistair.francis@xilinx.com>
      7 *
      8 * Permission is hereby granted, free of charge, to any person obtaining a copy
      9 * of this software and associated documentation files (the "Software"), to deal
     10 * in the Software without restriction, including without limitation the rights
     11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     12 * copies of the Software, and to permit persons to whom the Software is
     13 * furnished to do so, subject to the following conditions:
     14 *
     15 * The above copyright notice and this permission notice shall be included in
     16 * all copies or substantial portions of the Software.
     17 *
     18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     24 * THE SOFTWARE.
     25 */
     26
     27#include "qemu/osdep.h"
     28#include "qemu-common.h"
     29#include "hw/sysbus.h"
     30#include "hw/register.h"
     31#include "qemu/bitops.h"
     32#include "qemu/log.h"
     33#include "qemu/module.h"
     34#include "hw/irq.h"
     35#include "qemu/cutils.h"
     36#include "sysemu/sysemu.h"
     37#include "trace.h"
     38#include "hw/rtc/xlnx-zynqmp-rtc.h"
     39#include "migration/vmstate.h"
     40
     41#ifndef XLNX_ZYNQMP_RTC_ERR_DEBUG
     42#define XLNX_ZYNQMP_RTC_ERR_DEBUG 0
     43#endif
     44
     45static void rtc_int_update_irq(XlnxZynqMPRTC *s)
     46{
     47    bool pending = s->regs[R_RTC_INT_STATUS] & ~s->regs[R_RTC_INT_MASK];
     48    qemu_set_irq(s->irq_rtc_int, pending);
     49}
     50
     51static void addr_error_int_update_irq(XlnxZynqMPRTC *s)
     52{
     53    bool pending = s->regs[R_ADDR_ERROR] & ~s->regs[R_ADDR_ERROR_INT_MASK];
     54    qemu_set_irq(s->irq_addr_error_int, pending);
     55}
     56
     57static uint32_t rtc_get_count(XlnxZynqMPRTC *s)
     58{
     59    int64_t now = qemu_clock_get_ns(rtc_clock);
     60    return s->tick_offset + now / NANOSECONDS_PER_SECOND;
     61}
     62
     63static uint64_t current_time_postr(RegisterInfo *reg, uint64_t val64)
     64{
     65    XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
     66
     67    return rtc_get_count(s);
     68}
     69
     70static void rtc_int_status_postw(RegisterInfo *reg, uint64_t val64)
     71{
     72    XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
     73    rtc_int_update_irq(s);
     74}
     75
     76static uint64_t rtc_int_en_prew(RegisterInfo *reg, uint64_t val64)
     77{
     78    XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
     79
     80    s->regs[R_RTC_INT_MASK] &= (uint32_t) ~val64;
     81    rtc_int_update_irq(s);
     82    return 0;
     83}
     84
     85static uint64_t rtc_int_dis_prew(RegisterInfo *reg, uint64_t val64)
     86{
     87    XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
     88
     89    s->regs[R_RTC_INT_MASK] |= (uint32_t) val64;
     90    rtc_int_update_irq(s);
     91    return 0;
     92}
     93
     94static void addr_error_postw(RegisterInfo *reg, uint64_t val64)
     95{
     96    XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
     97    addr_error_int_update_irq(s);
     98}
     99
    100static uint64_t addr_error_int_en_prew(RegisterInfo *reg, uint64_t val64)
    101{
    102    XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
    103
    104    s->regs[R_ADDR_ERROR_INT_MASK] &= (uint32_t) ~val64;
    105    addr_error_int_update_irq(s);
    106    return 0;
    107}
    108
    109static uint64_t addr_error_int_dis_prew(RegisterInfo *reg, uint64_t val64)
    110{
    111    XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
    112
    113    s->regs[R_ADDR_ERROR_INT_MASK] |= (uint32_t) val64;
    114    addr_error_int_update_irq(s);
    115    return 0;
    116}
    117
    118static const RegisterAccessInfo rtc_regs_info[] = {
    119    {   .name = "SET_TIME_WRITE",  .addr = A_SET_TIME_WRITE,
    120        .unimp = MAKE_64BIT_MASK(0, 32),
    121    },{ .name = "SET_TIME_READ",  .addr = A_SET_TIME_READ,
    122        .ro = 0xffffffff,
    123        .post_read = current_time_postr,
    124    },{ .name = "CALIB_WRITE",  .addr = A_CALIB_WRITE,
    125        .unimp = MAKE_64BIT_MASK(0, 32),
    126    },{ .name = "CALIB_READ",  .addr = A_CALIB_READ,
    127        .ro = 0x1fffff,
    128    },{ .name = "CURRENT_TIME",  .addr = A_CURRENT_TIME,
    129        .ro = 0xffffffff,
    130        .post_read = current_time_postr,
    131    },{ .name = "CURRENT_TICK",  .addr = A_CURRENT_TICK,
    132        .ro = 0xffff,
    133    },{ .name = "ALARM",  .addr = A_ALARM,
    134    },{ .name = "RTC_INT_STATUS",  .addr = A_RTC_INT_STATUS,
    135        .w1c = 0x3,
    136        .post_write = rtc_int_status_postw,
    137    },{ .name = "RTC_INT_MASK",  .addr = A_RTC_INT_MASK,
    138        .reset = 0x3,
    139        .ro = 0x3,
    140    },{ .name = "RTC_INT_EN",  .addr = A_RTC_INT_EN,
    141        .pre_write = rtc_int_en_prew,
    142    },{ .name = "RTC_INT_DIS",  .addr = A_RTC_INT_DIS,
    143        .pre_write = rtc_int_dis_prew,
    144    },{ .name = "ADDR_ERROR",  .addr = A_ADDR_ERROR,
    145        .w1c = 0x1,
    146        .post_write = addr_error_postw,
    147    },{ .name = "ADDR_ERROR_INT_MASK",  .addr = A_ADDR_ERROR_INT_MASK,
    148        .reset = 0x1,
    149        .ro = 0x1,
    150    },{ .name = "ADDR_ERROR_INT_EN",  .addr = A_ADDR_ERROR_INT_EN,
    151        .pre_write = addr_error_int_en_prew,
    152    },{ .name = "ADDR_ERROR_INT_DIS",  .addr = A_ADDR_ERROR_INT_DIS,
    153        .pre_write = addr_error_int_dis_prew,
    154    },{ .name = "CONTROL",  .addr = A_CONTROL,
    155        .reset = 0x1000000,
    156        .rsvd = 0x70fffffe,
    157    },{ .name = "SAFETY_CHK",  .addr = A_SAFETY_CHK,
    158    }
    159};
    160
    161static void rtc_reset(DeviceState *dev)
    162{
    163    XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(dev);
    164    unsigned int i;
    165
    166    for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
    167        register_reset(&s->regs_info[i]);
    168    }
    169
    170    rtc_int_update_irq(s);
    171    addr_error_int_update_irq(s);
    172}
    173
    174static const MemoryRegionOps rtc_ops = {
    175    .read = register_read_memory,
    176    .write = register_write_memory,
    177    .endianness = DEVICE_LITTLE_ENDIAN,
    178    .valid = {
    179        .min_access_size = 4,
    180        .max_access_size = 4,
    181    },
    182};
    183
    184static void rtc_init(Object *obj)
    185{
    186    XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(obj);
    187    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    188    RegisterInfoArray *reg_array;
    189    struct tm current_tm;
    190
    191    memory_region_init(&s->iomem, obj, TYPE_XLNX_ZYNQMP_RTC,
    192                       XLNX_ZYNQMP_RTC_R_MAX * 4);
    193    reg_array =
    194        register_init_block32(DEVICE(obj), rtc_regs_info,
    195                              ARRAY_SIZE(rtc_regs_info),
    196                              s->regs_info, s->regs,
    197                              &rtc_ops,
    198                              XLNX_ZYNQMP_RTC_ERR_DEBUG,
    199                              XLNX_ZYNQMP_RTC_R_MAX * 4);
    200    memory_region_add_subregion(&s->iomem,
    201                                0x0,
    202                                &reg_array->mem);
    203    sysbus_init_mmio(sbd, &s->iomem);
    204    sysbus_init_irq(sbd, &s->irq_rtc_int);
    205    sysbus_init_irq(sbd, &s->irq_addr_error_int);
    206
    207    qemu_get_timedate(&current_tm, 0);
    208    s->tick_offset = mktimegm(&current_tm) -
    209        qemu_clock_get_ns(rtc_clock) / NANOSECONDS_PER_SECOND;
    210
    211    trace_xlnx_zynqmp_rtc_gettime(current_tm.tm_year, current_tm.tm_mon,
    212                                  current_tm.tm_mday, current_tm.tm_hour,
    213                                  current_tm.tm_min, current_tm.tm_sec);
    214}
    215
    216static int rtc_pre_save(void *opaque)
    217{
    218    XlnxZynqMPRTC *s = opaque;
    219    int64_t now = qemu_clock_get_ns(rtc_clock) / NANOSECONDS_PER_SECOND;
    220
    221    /* Add the time at migration */
    222    s->tick_offset = s->tick_offset + now;
    223
    224    return 0;
    225}
    226
    227static int rtc_post_load(void *opaque, int version_id)
    228{
    229    XlnxZynqMPRTC *s = opaque;
    230    int64_t now = qemu_clock_get_ns(rtc_clock) / NANOSECONDS_PER_SECOND;
    231
    232    /* Subtract the time after migration. This combined with the pre_save
    233     * action results in us having subtracted the time that the guest was
    234     * stopped to the offset.
    235     */
    236    s->tick_offset = s->tick_offset - now;
    237
    238    return 0;
    239}
    240
    241static const VMStateDescription vmstate_rtc = {
    242    .name = TYPE_XLNX_ZYNQMP_RTC,
    243    .version_id = 1,
    244    .minimum_version_id = 1,
    245    .pre_save = rtc_pre_save,
    246    .post_load = rtc_post_load,
    247    .fields = (VMStateField[]) {
    248        VMSTATE_UINT32_ARRAY(regs, XlnxZynqMPRTC, XLNX_ZYNQMP_RTC_R_MAX),
    249        VMSTATE_UINT32(tick_offset, XlnxZynqMPRTC),
    250        VMSTATE_END_OF_LIST(),
    251    }
    252};
    253
    254static void rtc_class_init(ObjectClass *klass, void *data)
    255{
    256    DeviceClass *dc = DEVICE_CLASS(klass);
    257
    258    dc->reset = rtc_reset;
    259    dc->vmsd = &vmstate_rtc;
    260}
    261
    262static const TypeInfo rtc_info = {
    263    .name          = TYPE_XLNX_ZYNQMP_RTC,
    264    .parent        = TYPE_SYS_BUS_DEVICE,
    265    .instance_size = sizeof(XlnxZynqMPRTC),
    266    .class_init    = rtc_class_init,
    267    .instance_init = rtc_init,
    268};
    269
    270static void rtc_register_types(void)
    271{
    272    type_register_static(&rtc_info);
    273}
    274
    275type_init(rtc_register_types)