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

omap_gptimer.c (13801B)


      1/*
      2 * TI OMAP2 general purpose timers emulation.
      3 *
      4 * Copyright (C) 2007-2008 Nokia Corporation
      5 * Written by Andrzej Zaborowski <andrew@openedhand.com>
      6 *
      7 * This program is free software; you can redistribute it and/or
      8 * modify it under the terms of the GNU General Public License as
      9 * published by the Free Software Foundation; either version 2 or
     10 * (at your option) any later version of the License.
     11 *
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16 *
     17 * You should have received a copy of the GNU General Public License along
     18 * with this program; if not, see <http://www.gnu.org/licenses/>.
     19 */
     20
     21#include "qemu/osdep.h"
     22#include "hw/irq.h"
     23#include "qemu/timer.h"
     24#include "hw/arm/omap.h"
     25
     26/* GP timers */
     27struct omap_gp_timer_s {
     28    MemoryRegion iomem;
     29    qemu_irq irq;
     30    qemu_irq wkup;
     31    qemu_irq in;
     32    qemu_irq out;
     33    omap_clk clk;
     34    QEMUTimer *timer;
     35    QEMUTimer *match;
     36    struct omap_target_agent_s *ta;
     37
     38    int in_val;
     39    int out_val;
     40    int64_t time;
     41    int64_t rate;
     42    int64_t ticks_per_sec;
     43
     44    int16_t config;
     45    int status;
     46    int it_ena;
     47    int wu_ena;
     48    int enable;
     49    int inout;
     50    int capt2;
     51    int pt;
     52    enum {
     53        gpt_trigger_none, gpt_trigger_overflow, gpt_trigger_both
     54    } trigger;
     55    enum {
     56        gpt_capture_none, gpt_capture_rising,
     57        gpt_capture_falling, gpt_capture_both
     58    } capture;
     59    int scpwm;
     60    int ce;
     61    int pre;
     62    int ptv;
     63    int ar;
     64    int st;
     65    int posted;
     66    uint32_t val;
     67    uint32_t load_val;
     68    uint32_t capture_val[2];
     69    uint32_t match_val;
     70    int capt_num;
     71
     72    uint16_t writeh;	/* LSB */
     73    uint16_t readh;	/* MSB */
     74};
     75
     76#define GPT_TCAR_IT	(1 << 2)
     77#define GPT_OVF_IT	(1 << 1)
     78#define GPT_MAT_IT	(1 << 0)
     79
     80static inline void omap_gp_timer_intr(struct omap_gp_timer_s *timer, int it)
     81{
     82    if (timer->it_ena & it) {
     83        if (!timer->status)
     84            qemu_irq_raise(timer->irq);
     85
     86        timer->status |= it;
     87        /* Or are the status bits set even when masked?
     88         * i.e. is masking applied before or after the status register?  */
     89    }
     90
     91    if (timer->wu_ena & it)
     92        qemu_irq_pulse(timer->wkup);
     93}
     94
     95static inline void omap_gp_timer_out(struct omap_gp_timer_s *timer, int level)
     96{
     97    if (!timer->inout && timer->out_val != level) {
     98        timer->out_val = level;
     99        qemu_set_irq(timer->out, level);
    100    }
    101}
    102
    103static inline uint32_t omap_gp_timer_read(struct omap_gp_timer_s *timer)
    104{
    105    uint64_t distance;
    106
    107    if (timer->st && timer->rate) {
    108        distance = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - timer->time;
    109        distance = muldiv64(distance, timer->rate, timer->ticks_per_sec);
    110
    111        if (distance >= 0xffffffff - timer->val)
    112            return 0xffffffff;
    113        else
    114            return timer->val + distance;
    115    } else
    116        return timer->val;
    117}
    118
    119static inline void omap_gp_timer_sync(struct omap_gp_timer_s *timer)
    120{
    121    if (timer->st) {
    122        timer->val = omap_gp_timer_read(timer);
    123        timer->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
    124    }
    125}
    126
    127static inline void omap_gp_timer_update(struct omap_gp_timer_s *timer)
    128{
    129    int64_t expires, matches;
    130
    131    if (timer->st && timer->rate) {
    132        expires = muldiv64(0x100000000ll - timer->val,
    133                        timer->ticks_per_sec, timer->rate);
    134        timer_mod(timer->timer, timer->time + expires);
    135
    136        if (timer->ce && timer->match_val >= timer->val) {
    137            matches = muldiv64(timer->ticks_per_sec,
    138                               timer->match_val - timer->val, timer->rate);
    139            timer_mod(timer->match, timer->time + matches);
    140        } else
    141            timer_del(timer->match);
    142    } else {
    143        timer_del(timer->timer);
    144        timer_del(timer->match);
    145        omap_gp_timer_out(timer, timer->scpwm);
    146    }
    147}
    148
    149static inline void omap_gp_timer_trigger(struct omap_gp_timer_s *timer)
    150{
    151    if (timer->pt)
    152        /* TODO in overflow-and-match mode if the first event to
    153         * occur is the match, don't toggle.  */
    154        omap_gp_timer_out(timer, !timer->out_val);
    155    else
    156        /* TODO inverted pulse on timer->out_val == 1?  */
    157        qemu_irq_pulse(timer->out);
    158}
    159
    160static void omap_gp_timer_tick(void *opaque)
    161{
    162    struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
    163
    164    if (!timer->ar) {
    165        timer->st = 0;
    166        timer->val = 0;
    167    } else {
    168        timer->val = timer->load_val;
    169        timer->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
    170    }
    171
    172    if (timer->trigger == gpt_trigger_overflow ||
    173                    timer->trigger == gpt_trigger_both)
    174        omap_gp_timer_trigger(timer);
    175
    176    omap_gp_timer_intr(timer, GPT_OVF_IT);
    177    omap_gp_timer_update(timer);
    178}
    179
    180static void omap_gp_timer_match(void *opaque)
    181{
    182    struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
    183
    184    if (timer->trigger == gpt_trigger_both)
    185        omap_gp_timer_trigger(timer);
    186
    187    omap_gp_timer_intr(timer, GPT_MAT_IT);
    188}
    189
    190static void omap_gp_timer_input(void *opaque, int line, int on)
    191{
    192    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
    193    int trigger;
    194
    195    switch (s->capture) {
    196    default:
    197    case gpt_capture_none:
    198        trigger = 0;
    199        break;
    200    case gpt_capture_rising:
    201        trigger = !s->in_val && on;
    202        break;
    203    case gpt_capture_falling:
    204        trigger = s->in_val && !on;
    205        break;
    206    case gpt_capture_both:
    207        trigger = (s->in_val == !on);
    208        break;
    209    }
    210    s->in_val = on;
    211
    212    if (s->inout && trigger && s->capt_num < 2) {
    213        s->capture_val[s->capt_num] = omap_gp_timer_read(s);
    214
    215        if (s->capt2 == s->capt_num ++)
    216            omap_gp_timer_intr(s, GPT_TCAR_IT);
    217    }
    218}
    219
    220static void omap_gp_timer_clk_update(void *opaque, int line, int on)
    221{
    222    struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
    223
    224    omap_gp_timer_sync(timer);
    225    timer->rate = on ? omap_clk_getrate(timer->clk) : 0;
    226    omap_gp_timer_update(timer);
    227}
    228
    229static void omap_gp_timer_clk_setup(struct omap_gp_timer_s *timer)
    230{
    231    omap_clk_adduser(timer->clk,
    232                     qemu_allocate_irq(omap_gp_timer_clk_update, timer, 0));
    233    timer->rate = omap_clk_getrate(timer->clk);
    234}
    235
    236void omap_gp_timer_reset(struct omap_gp_timer_s *s)
    237{
    238    s->config = 0x000;
    239    s->status = 0;
    240    s->it_ena = 0;
    241    s->wu_ena = 0;
    242    s->inout = 0;
    243    s->capt2 = 0;
    244    s->capt_num = 0;
    245    s->pt = 0;
    246    s->trigger = gpt_trigger_none;
    247    s->capture = gpt_capture_none;
    248    s->scpwm = 0;
    249    s->ce = 0;
    250    s->pre = 0;
    251    s->ptv = 0;
    252    s->ar = 0;
    253    s->st = 0;
    254    s->posted = 1;
    255    s->val = 0x00000000;
    256    s->load_val = 0x00000000;
    257    s->capture_val[0] = 0x00000000;
    258    s->capture_val[1] = 0x00000000;
    259    s->match_val = 0x00000000;
    260    omap_gp_timer_update(s);
    261}
    262
    263static uint32_t omap_gp_timer_readw(void *opaque, hwaddr addr)
    264{
    265    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
    266
    267    switch (addr) {
    268    case 0x00:	/* TIDR */
    269        return 0x21;
    270
    271    case 0x10:	/* TIOCP_CFG */
    272        return s->config;
    273
    274    case 0x14:	/* TISTAT */
    275        /* ??? When's this bit reset? */
    276        return 1;						/* RESETDONE */
    277
    278    case 0x18:	/* TISR */
    279        return s->status;
    280
    281    case 0x1c:	/* TIER */
    282        return s->it_ena;
    283
    284    case 0x20:	/* TWER */
    285        return s->wu_ena;
    286
    287    case 0x24:	/* TCLR */
    288        return (s->inout << 14) |
    289                (s->capt2 << 13) |
    290                (s->pt << 12) |
    291                (s->trigger << 10) |
    292                (s->capture << 8) |
    293                (s->scpwm << 7) |
    294                (s->ce << 6) |
    295                (s->pre << 5) |
    296                (s->ptv << 2) |
    297                (s->ar << 1) |
    298                (s->st << 0);
    299
    300    case 0x28:	/* TCRR */
    301        return omap_gp_timer_read(s);
    302
    303    case 0x2c:	/* TLDR */
    304        return s->load_val;
    305
    306    case 0x30:	/* TTGR */
    307        return 0xffffffff;
    308
    309    case 0x34:	/* TWPS */
    310        return 0x00000000;	/* No posted writes pending.  */
    311
    312    case 0x38:	/* TMAR */
    313        return s->match_val;
    314
    315    case 0x3c:	/* TCAR1 */
    316        return s->capture_val[0];
    317
    318    case 0x40:	/* TSICR */
    319        return s->posted << 2;
    320
    321    case 0x44:	/* TCAR2 */
    322        return s->capture_val[1];
    323    }
    324
    325    OMAP_BAD_REG(addr);
    326    return 0;
    327}
    328
    329static uint32_t omap_gp_timer_readh(void *opaque, hwaddr addr)
    330{
    331    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
    332    uint32_t ret;
    333
    334    if (addr & 2)
    335        return s->readh;
    336    else {
    337        ret = omap_gp_timer_readw(opaque, addr);
    338        s->readh = ret >> 16;
    339        return ret & 0xffff;
    340    }
    341}
    342
    343static void omap_gp_timer_write(void *opaque, hwaddr addr,
    344                uint32_t value)
    345{
    346    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
    347
    348    switch (addr) {
    349    case 0x00:	/* TIDR */
    350    case 0x14:	/* TISTAT */
    351    case 0x34:	/* TWPS */
    352    case 0x3c:	/* TCAR1 */
    353    case 0x44:	/* TCAR2 */
    354        OMAP_RO_REG(addr);
    355        break;
    356
    357    case 0x10:	/* TIOCP_CFG */
    358        s->config = value & 0x33d;
    359        if (((value >> 3) & 3) == 3)				/* IDLEMODE */
    360            fprintf(stderr, "%s: illegal IDLEMODE value in TIOCP_CFG\n",
    361                            __func__);
    362        if (value & 2)						/* SOFTRESET */
    363            omap_gp_timer_reset(s);
    364        break;
    365
    366    case 0x18:	/* TISR */
    367        if (value & GPT_TCAR_IT)
    368            s->capt_num = 0;
    369        if (s->status && !(s->status &= ~value))
    370            qemu_irq_lower(s->irq);
    371        break;
    372
    373    case 0x1c:	/* TIER */
    374        s->it_ena = value & 7;
    375        break;
    376
    377    case 0x20:	/* TWER */
    378        s->wu_ena = value & 7;
    379        break;
    380
    381    case 0x24:	/* TCLR */
    382        omap_gp_timer_sync(s);
    383        s->inout = (value >> 14) & 1;
    384        s->capt2 = (value >> 13) & 1;
    385        s->pt = (value >> 12) & 1;
    386        s->trigger = (value >> 10) & 3;
    387        if (s->capture == gpt_capture_none &&
    388                        ((value >> 8) & 3) != gpt_capture_none)
    389            s->capt_num = 0;
    390        s->capture = (value >> 8) & 3;
    391        s->scpwm = (value >> 7) & 1;
    392        s->ce = (value >> 6) & 1;
    393        s->pre = (value >> 5) & 1;
    394        s->ptv = (value >> 2) & 7;
    395        s->ar = (value >> 1) & 1;
    396        s->st = (value >> 0) & 1;
    397        if (s->inout && s->trigger != gpt_trigger_none)
    398            fprintf(stderr, "%s: GP timer pin must be an output "
    399                            "for this trigger mode\n", __func__);
    400        if (!s->inout && s->capture != gpt_capture_none)
    401            fprintf(stderr, "%s: GP timer pin must be an input "
    402                            "for this capture mode\n", __func__);
    403        if (s->trigger == gpt_trigger_none)
    404            omap_gp_timer_out(s, s->scpwm);
    405        /* TODO: make sure this doesn't overflow 32-bits */
    406        s->ticks_per_sec = NANOSECONDS_PER_SECOND << (s->pre ? s->ptv + 1 : 0);
    407        omap_gp_timer_update(s);
    408        break;
    409
    410    case 0x28:	/* TCRR */
    411        s->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
    412        s->val = value;
    413        omap_gp_timer_update(s);
    414        break;
    415
    416    case 0x2c:	/* TLDR */
    417        s->load_val = value;
    418        break;
    419
    420    case 0x30:	/* TTGR */
    421        s->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
    422        s->val = s->load_val;
    423        omap_gp_timer_update(s);
    424        break;
    425
    426    case 0x38:	/* TMAR */
    427        omap_gp_timer_sync(s);
    428        s->match_val = value;
    429        omap_gp_timer_update(s);
    430        break;
    431
    432    case 0x40:	/* TSICR */
    433        s->posted = (value >> 2) & 1;
    434        if (value & 2)	/* How much exactly are we supposed to reset? */
    435            omap_gp_timer_reset(s);
    436        break;
    437
    438    default:
    439        OMAP_BAD_REG(addr);
    440    }
    441}
    442
    443static void omap_gp_timer_writeh(void *opaque, hwaddr addr,
    444                uint32_t value)
    445{
    446    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
    447
    448    if (addr & 2)
    449        omap_gp_timer_write(opaque, addr, (value << 16) | s->writeh);
    450    else
    451        s->writeh = (uint16_t) value;
    452}
    453
    454static uint64_t omap_gp_timer_readfn(void *opaque, hwaddr addr,
    455                                     unsigned size)
    456{
    457    switch (size) {
    458    case 1:
    459        return omap_badwidth_read32(opaque, addr);
    460    case 2:
    461        return omap_gp_timer_readh(opaque, addr);
    462    case 4:
    463        return omap_gp_timer_readw(opaque, addr);
    464    default:
    465        g_assert_not_reached();
    466    }
    467}
    468
    469static void omap_gp_timer_writefn(void *opaque, hwaddr addr,
    470                                  uint64_t value, unsigned size)
    471{
    472    switch (size) {
    473    case 1:
    474        omap_badwidth_write32(opaque, addr, value);
    475        break;
    476    case 2:
    477        omap_gp_timer_writeh(opaque, addr, value);
    478        break;
    479    case 4:
    480        omap_gp_timer_write(opaque, addr, value);
    481        break;
    482    default:
    483        g_assert_not_reached();
    484    }
    485}
    486
    487static const MemoryRegionOps omap_gp_timer_ops = {
    488    .read = omap_gp_timer_readfn,
    489    .write = omap_gp_timer_writefn,
    490    .valid.min_access_size = 1,
    491    .valid.max_access_size = 4,
    492    .endianness = DEVICE_NATIVE_ENDIAN,
    493};
    494
    495struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta,
    496                qemu_irq irq, omap_clk fclk, omap_clk iclk)
    497{
    498    struct omap_gp_timer_s *s = g_new0(struct omap_gp_timer_s, 1);
    499
    500    s->ta = ta;
    501    s->irq = irq;
    502    s->clk = fclk;
    503    s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_gp_timer_tick, s);
    504    s->match = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_gp_timer_match, s);
    505    s->in = qemu_allocate_irq(omap_gp_timer_input, s, 0);
    506    omap_gp_timer_reset(s);
    507    omap_gp_timer_clk_setup(s);
    508
    509    memory_region_init_io(&s->iomem, NULL, &omap_gp_timer_ops, s, "omap.gptimer",
    510                          omap_l4_region_size(ta, 0));
    511    omap_l4_attach(ta, 0, &s->iomem);
    512
    513    return s;
    514}