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

imx_epit.c (10326B)


      1/*
      2 * IMX EPIT Timer
      3 *
      4 * Copyright (c) 2008 OK Labs
      5 * Copyright (c) 2011 NICTA Pty Ltd
      6 * Originally written by Hans Jiang
      7 * Updated by Peter Chubb
      8 * Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
      9 *
     10 * This code is licensed under GPL version 2 or later.  See
     11 * the COPYING file in the top-level directory.
     12 *
     13 */
     14
     15#include "qemu/osdep.h"
     16#include "hw/timer/imx_epit.h"
     17#include "migration/vmstate.h"
     18#include "hw/irq.h"
     19#include "hw/misc/imx_ccm.h"
     20#include "qemu/module.h"
     21#include "qemu/log.h"
     22
     23#ifndef DEBUG_IMX_EPIT
     24#define DEBUG_IMX_EPIT 0
     25#endif
     26
     27#define DPRINTF(fmt, args...) \
     28    do { \
     29        if (DEBUG_IMX_EPIT) { \
     30            fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_EPIT, \
     31                                             __func__, ##args); \
     32        } \
     33    } while (0)
     34
     35static const char *imx_epit_reg_name(uint32_t reg)
     36{
     37    switch (reg) {
     38    case 0:
     39        return "CR";
     40    case 1:
     41        return "SR";
     42    case 2:
     43        return "LR";
     44    case 3:
     45        return "CMP";
     46    case 4:
     47        return "CNT";
     48    default:
     49        return "[?]";
     50    }
     51}
     52
     53/*
     54 * Exact clock frequencies vary from board to board.
     55 * These are typical.
     56 */
     57static const IMXClk imx_epit_clocks[] =  {
     58    CLK_NONE,      /* 00 disabled */
     59    CLK_IPG,       /* 01 ipg_clk, ~532MHz */
     60    CLK_IPG_HIGH,  /* 10 ipg_clk_highfreq */
     61    CLK_32k,       /* 11 ipg_clk_32k -- ~32kHz */
     62};
     63
     64/*
     65 * Update interrupt status
     66 */
     67static void imx_epit_update_int(IMXEPITState *s)
     68{
     69    if (s->sr && (s->cr & CR_OCIEN) && (s->cr & CR_EN)) {
     70        qemu_irq_raise(s->irq);
     71    } else {
     72        qemu_irq_lower(s->irq);
     73    }
     74}
     75
     76/*
     77 * Must be called from within a ptimer_transaction_begin/commit block
     78 * for both s->timer_cmp and s->timer_reload.
     79 */
     80static void imx_epit_set_freq(IMXEPITState *s)
     81{
     82    uint32_t clksrc;
     83    uint32_t prescaler;
     84
     85    clksrc = extract32(s->cr, CR_CLKSRC_SHIFT, 2);
     86    prescaler = 1 + extract32(s->cr, CR_PRESCALE_SHIFT, 12);
     87
     88    s->freq = imx_ccm_get_clock_frequency(s->ccm,
     89                                imx_epit_clocks[clksrc]) / prescaler;
     90
     91    DPRINTF("Setting ptimer frequency to %u\n", s->freq);
     92
     93    if (s->freq) {
     94        ptimer_set_freq(s->timer_reload, s->freq);
     95        ptimer_set_freq(s->timer_cmp, s->freq);
     96    }
     97}
     98
     99static void imx_epit_reset(DeviceState *dev)
    100{
    101    IMXEPITState *s = IMX_EPIT(dev);
    102
    103    /*
    104     * Soft reset doesn't touch some bits; hard reset clears them
    105     */
    106    s->cr &= (CR_EN|CR_ENMOD|CR_STOPEN|CR_DOZEN|CR_WAITEN|CR_DBGEN);
    107    s->sr = 0;
    108    s->lr = EPIT_TIMER_MAX;
    109    s->cmp = 0;
    110    s->cnt = 0;
    111    ptimer_transaction_begin(s->timer_cmp);
    112    ptimer_transaction_begin(s->timer_reload);
    113    /* stop both timers */
    114    ptimer_stop(s->timer_cmp);
    115    ptimer_stop(s->timer_reload);
    116    /* compute new frequency */
    117    imx_epit_set_freq(s);
    118    /* init both timers to EPIT_TIMER_MAX */
    119    ptimer_set_limit(s->timer_cmp, EPIT_TIMER_MAX, 1);
    120    ptimer_set_limit(s->timer_reload, EPIT_TIMER_MAX, 1);
    121    if (s->freq && (s->cr & CR_EN)) {
    122        /* if the timer is still enabled, restart it */
    123        ptimer_run(s->timer_reload, 0);
    124    }
    125    ptimer_transaction_commit(s->timer_cmp);
    126    ptimer_transaction_commit(s->timer_reload);
    127}
    128
    129static uint32_t imx_epit_update_count(IMXEPITState *s)
    130{
    131    s->cnt = ptimer_get_count(s->timer_reload);
    132
    133    return s->cnt;
    134}
    135
    136static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size)
    137{
    138    IMXEPITState *s = IMX_EPIT(opaque);
    139    uint32_t reg_value = 0;
    140
    141    switch (offset >> 2) {
    142    case 0: /* Control Register */
    143        reg_value = s->cr;
    144        break;
    145
    146    case 1: /* Status Register */
    147        reg_value = s->sr;
    148        break;
    149
    150    case 2: /* LR - ticks*/
    151        reg_value = s->lr;
    152        break;
    153
    154    case 3: /* CMP */
    155        reg_value = s->cmp;
    156        break;
    157
    158    case 4: /* CNT */
    159        imx_epit_update_count(s);
    160        reg_value = s->cnt;
    161        break;
    162
    163    default:
    164        qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
    165                      HWADDR_PRIx "\n", TYPE_IMX_EPIT, __func__, offset);
    166        break;
    167    }
    168
    169    DPRINTF("(%s) = 0x%08x\n", imx_epit_reg_name(offset >> 2), reg_value);
    170
    171    return reg_value;
    172}
    173
    174/* Must be called from ptimer_transaction_begin/commit block for s->timer_cmp */
    175static void imx_epit_reload_compare_timer(IMXEPITState *s)
    176{
    177    if ((s->cr & (CR_EN | CR_OCIEN)) == (CR_EN | CR_OCIEN))  {
    178        /* if the compare feature is on and timers are running */
    179        uint32_t tmp = imx_epit_update_count(s);
    180        uint64_t next;
    181        if (tmp > s->cmp) {
    182            /* It'll fire in this round of the timer */
    183            next = tmp - s->cmp;
    184        } else { /* catch it next time around */
    185            next = tmp - s->cmp + ((s->cr & CR_RLD) ? EPIT_TIMER_MAX : s->lr);
    186        }
    187        ptimer_set_count(s->timer_cmp, next);
    188    }
    189}
    190
    191static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value,
    192                           unsigned size)
    193{
    194    IMXEPITState *s = IMX_EPIT(opaque);
    195    uint64_t oldcr;
    196
    197    DPRINTF("(%s, value = 0x%08x)\n", imx_epit_reg_name(offset >> 2),
    198            (uint32_t)value);
    199
    200    switch (offset >> 2) {
    201    case 0: /* CR */
    202
    203        oldcr = s->cr;
    204        s->cr = value & 0x03ffffff;
    205        if (s->cr & CR_SWR) {
    206            /* handle the reset */
    207            imx_epit_reset(DEVICE(s));
    208            /*
    209             * TODO: could we 'break' here? following operations appear
    210             * to duplicate the work imx_epit_reset() already did.
    211             */
    212        }
    213
    214        ptimer_transaction_begin(s->timer_cmp);
    215        ptimer_transaction_begin(s->timer_reload);
    216
    217        if (!(s->cr & CR_SWR)) {
    218            imx_epit_set_freq(s);
    219        }
    220
    221        if (s->freq && (s->cr & CR_EN) && !(oldcr & CR_EN)) {
    222            if (s->cr & CR_ENMOD) {
    223                if (s->cr & CR_RLD) {
    224                    ptimer_set_limit(s->timer_reload, s->lr, 1);
    225                    ptimer_set_limit(s->timer_cmp, s->lr, 1);
    226                } else {
    227                    ptimer_set_limit(s->timer_reload, EPIT_TIMER_MAX, 1);
    228                    ptimer_set_limit(s->timer_cmp, EPIT_TIMER_MAX, 1);
    229                }
    230            }
    231
    232            imx_epit_reload_compare_timer(s);
    233            ptimer_run(s->timer_reload, 0);
    234            if (s->cr & CR_OCIEN) {
    235                ptimer_run(s->timer_cmp, 0);
    236            } else {
    237                ptimer_stop(s->timer_cmp);
    238            }
    239        } else if (!(s->cr & CR_EN)) {
    240            /* stop both timers */
    241            ptimer_stop(s->timer_reload);
    242            ptimer_stop(s->timer_cmp);
    243        } else  if (s->cr & CR_OCIEN) {
    244            if (!(oldcr & CR_OCIEN)) {
    245                imx_epit_reload_compare_timer(s);
    246                ptimer_run(s->timer_cmp, 0);
    247            }
    248        } else {
    249            ptimer_stop(s->timer_cmp);
    250        }
    251
    252        ptimer_transaction_commit(s->timer_cmp);
    253        ptimer_transaction_commit(s->timer_reload);
    254        break;
    255
    256    case 1: /* SR - ACK*/
    257        /* writing 1 to OCIF clear the OCIF bit */
    258        if (value & 0x01) {
    259            s->sr = 0;
    260            imx_epit_update_int(s);
    261        }
    262        break;
    263
    264    case 2: /* LR - set ticks */
    265        s->lr = value;
    266
    267        ptimer_transaction_begin(s->timer_cmp);
    268        ptimer_transaction_begin(s->timer_reload);
    269        if (s->cr & CR_RLD) {
    270            /* Also set the limit if the LRD bit is set */
    271            /* If IOVW bit is set then set the timer value */
    272            ptimer_set_limit(s->timer_reload, s->lr, s->cr & CR_IOVW);
    273            ptimer_set_limit(s->timer_cmp, s->lr, 0);
    274        } else if (s->cr & CR_IOVW) {
    275            /* If IOVW bit is set then set the timer value */
    276            ptimer_set_count(s->timer_reload, s->lr);
    277        }
    278
    279        imx_epit_reload_compare_timer(s);
    280        ptimer_transaction_commit(s->timer_cmp);
    281        ptimer_transaction_commit(s->timer_reload);
    282        break;
    283
    284    case 3: /* CMP */
    285        s->cmp = value;
    286
    287        ptimer_transaction_begin(s->timer_cmp);
    288        imx_epit_reload_compare_timer(s);
    289        ptimer_transaction_commit(s->timer_cmp);
    290
    291        break;
    292
    293    default:
    294        qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
    295                      HWADDR_PRIx "\n", TYPE_IMX_EPIT, __func__, offset);
    296
    297        break;
    298    }
    299}
    300static void imx_epit_cmp(void *opaque)
    301{
    302    IMXEPITState *s = IMX_EPIT(opaque);
    303
    304    DPRINTF("sr was %d\n", s->sr);
    305
    306    s->sr = 1;
    307    imx_epit_update_int(s);
    308}
    309
    310static void imx_epit_reload(void *opaque)
    311{
    312    /* No action required on rollover of timer_reload */
    313}
    314
    315static const MemoryRegionOps imx_epit_ops = {
    316    .read = imx_epit_read,
    317    .write = imx_epit_write,
    318    .endianness = DEVICE_NATIVE_ENDIAN,
    319};
    320
    321static const VMStateDescription vmstate_imx_timer_epit = {
    322    .name = TYPE_IMX_EPIT,
    323    .version_id = 2,
    324    .minimum_version_id = 2,
    325    .fields = (VMStateField[]) {
    326        VMSTATE_UINT32(cr, IMXEPITState),
    327        VMSTATE_UINT32(sr, IMXEPITState),
    328        VMSTATE_UINT32(lr, IMXEPITState),
    329        VMSTATE_UINT32(cmp, IMXEPITState),
    330        VMSTATE_UINT32(cnt, IMXEPITState),
    331        VMSTATE_UINT32(freq, IMXEPITState),
    332        VMSTATE_PTIMER(timer_reload, IMXEPITState),
    333        VMSTATE_PTIMER(timer_cmp, IMXEPITState),
    334        VMSTATE_END_OF_LIST()
    335    }
    336};
    337
    338static void imx_epit_realize(DeviceState *dev, Error **errp)
    339{
    340    IMXEPITState *s = IMX_EPIT(dev);
    341    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
    342
    343    DPRINTF("\n");
    344
    345    sysbus_init_irq(sbd, &s->irq);
    346    memory_region_init_io(&s->iomem, OBJECT(s), &imx_epit_ops, s, TYPE_IMX_EPIT,
    347                          0x00001000);
    348    sysbus_init_mmio(sbd, &s->iomem);
    349
    350    s->timer_reload = ptimer_init(imx_epit_reload, s, PTIMER_POLICY_DEFAULT);
    351
    352    s->timer_cmp = ptimer_init(imx_epit_cmp, s, PTIMER_POLICY_DEFAULT);
    353}
    354
    355static void imx_epit_class_init(ObjectClass *klass, void *data)
    356{
    357    DeviceClass *dc  = DEVICE_CLASS(klass);
    358
    359    dc->realize = imx_epit_realize;
    360    dc->reset = imx_epit_reset;
    361    dc->vmsd = &vmstate_imx_timer_epit;
    362    dc->desc = "i.MX periodic timer";
    363}
    364
    365static const TypeInfo imx_epit_info = {
    366    .name = TYPE_IMX_EPIT,
    367    .parent = TYPE_SYS_BUS_DEVICE,
    368    .instance_size = sizeof(IMXEPITState),
    369    .class_init = imx_epit_class_init,
    370};
    371
    372static void imx_epit_register_types(void)
    373{
    374    type_register_static(&imx_epit_info);
    375}
    376
    377type_init(imx_epit_register_types)