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

mcf5206.c (16657B)


      1/*
      2 * Motorola ColdFire MCF5206 SoC embedded peripheral emulation.
      3 *
      4 * Copyright (c) 2007 CodeSourcery.
      5 *
      6 * This code is licensed under the GPL
      7 */
      8
      9#include "qemu/osdep.h"
     10#include "qemu/error-report.h"
     11#include "qemu/log.h"
     12#include "cpu.h"
     13#include "hw/boards.h"
     14#include "hw/irq.h"
     15#include "hw/m68k/mcf.h"
     16#include "qemu/timer.h"
     17#include "hw/ptimer.h"
     18#include "sysemu/sysemu.h"
     19#include "hw/sysbus.h"
     20
     21/* General purpose timer module.  */
     22typedef struct {
     23    uint16_t tmr;
     24    uint16_t trr;
     25    uint16_t tcr;
     26    uint16_t ter;
     27    ptimer_state *timer;
     28    qemu_irq irq;
     29    int irq_state;
     30} m5206_timer_state;
     31
     32#define TMR_RST 0x01
     33#define TMR_CLK 0x06
     34#define TMR_FRR 0x08
     35#define TMR_ORI 0x10
     36#define TMR_OM  0x20
     37#define TMR_CE  0xc0
     38
     39#define TER_CAP 0x01
     40#define TER_REF 0x02
     41
     42static void m5206_timer_update(m5206_timer_state *s)
     43{
     44    if ((s->tmr & TMR_ORI) != 0 && (s->ter & TER_REF))
     45        qemu_irq_raise(s->irq);
     46    else
     47        qemu_irq_lower(s->irq);
     48}
     49
     50static void m5206_timer_reset(m5206_timer_state *s)
     51{
     52    s->tmr = 0;
     53    s->trr = 0;
     54}
     55
     56static void m5206_timer_recalibrate(m5206_timer_state *s)
     57{
     58    int prescale;
     59    int mode;
     60
     61    ptimer_transaction_begin(s->timer);
     62    ptimer_stop(s->timer);
     63
     64    if ((s->tmr & TMR_RST) == 0) {
     65        goto exit;
     66    }
     67
     68    prescale = (s->tmr >> 8) + 1;
     69    mode = (s->tmr >> 1) & 3;
     70    if (mode == 2)
     71        prescale *= 16;
     72
     73    if (mode == 3 || mode == 0) {
     74        qemu_log_mask(LOG_UNIMP, "m5206_timer: mode %d not implemented\n",
     75                      mode);
     76        goto exit;
     77    }
     78    if ((s->tmr & TMR_FRR) == 0) {
     79        qemu_log_mask(LOG_UNIMP,
     80                      "m5206_timer: free running mode not implemented\n");
     81        goto exit;
     82    }
     83
     84    /* Assume 66MHz system clock.  */
     85    ptimer_set_freq(s->timer, 66000000 / prescale);
     86
     87    ptimer_set_limit(s->timer, s->trr, 0);
     88
     89    ptimer_run(s->timer, 0);
     90exit:
     91    ptimer_transaction_commit(s->timer);
     92}
     93
     94static void m5206_timer_trigger(void *opaque)
     95{
     96    m5206_timer_state *s = (m5206_timer_state *)opaque;
     97    s->ter |= TER_REF;
     98    m5206_timer_update(s);
     99}
    100
    101static uint32_t m5206_timer_read(m5206_timer_state *s, uint32_t addr)
    102{
    103    switch (addr) {
    104    case 0:
    105        return s->tmr;
    106    case 4:
    107        return s->trr;
    108    case 8:
    109        return s->tcr;
    110    case 0xc:
    111        return s->trr - ptimer_get_count(s->timer);
    112    case 0x11:
    113        return s->ter;
    114    default:
    115        return 0;
    116    }
    117}
    118
    119static void m5206_timer_write(m5206_timer_state *s, uint32_t addr, uint32_t val)
    120{
    121    switch (addr) {
    122    case 0:
    123        if ((s->tmr & TMR_RST) != 0 && (val & TMR_RST) == 0) {
    124            m5206_timer_reset(s);
    125        }
    126        s->tmr = val;
    127        m5206_timer_recalibrate(s);
    128        break;
    129    case 4:
    130        s->trr = val;
    131        m5206_timer_recalibrate(s);
    132        break;
    133    case 8:
    134        s->tcr = val;
    135        break;
    136    case 0xc:
    137        ptimer_transaction_begin(s->timer);
    138        ptimer_set_count(s->timer, val);
    139        ptimer_transaction_commit(s->timer);
    140        break;
    141    case 0x11:
    142        s->ter &= ~val;
    143        break;
    144    default:
    145        break;
    146    }
    147    m5206_timer_update(s);
    148}
    149
    150static m5206_timer_state *m5206_timer_init(qemu_irq irq)
    151{
    152    m5206_timer_state *s;
    153
    154    s = g_new0(m5206_timer_state, 1);
    155    s->timer = ptimer_init(m5206_timer_trigger, s, PTIMER_POLICY_DEFAULT);
    156    s->irq = irq;
    157    m5206_timer_reset(s);
    158    return s;
    159}
    160
    161/* System Integration Module.  */
    162
    163typedef struct {
    164    SysBusDevice parent_obj;
    165
    166    M68kCPU *cpu;
    167    MemoryRegion iomem;
    168    qemu_irq *pic;
    169    m5206_timer_state *timer[2];
    170    void *uart[2];
    171    uint8_t scr;
    172    uint8_t icr[14];
    173    uint16_t imr; /* 1 == interrupt is masked.  */
    174    uint16_t ipr;
    175    uint8_t rsr;
    176    uint8_t swivr;
    177    uint8_t par;
    178    /* Include the UART vector registers here.  */
    179    uint8_t uivr[2];
    180} m5206_mbar_state;
    181
    182#define MCF5206_MBAR(obj) OBJECT_CHECK(m5206_mbar_state, (obj), TYPE_MCF5206_MBAR)
    183
    184/* Interrupt controller.  */
    185
    186static int m5206_find_pending_irq(m5206_mbar_state *s)
    187{
    188    int level;
    189    int vector;
    190    uint16_t active;
    191    int i;
    192
    193    level = 0;
    194    vector = 0;
    195    active = s->ipr & ~s->imr;
    196    if (!active)
    197        return 0;
    198
    199    for (i = 1; i < 14; i++) {
    200        if (active & (1 << i)) {
    201            if ((s->icr[i] & 0x1f) > level) {
    202                level = s->icr[i] & 0x1f;
    203                vector = i;
    204            }
    205        }
    206    }
    207
    208    if (level < 4)
    209        vector = 0;
    210
    211    return vector;
    212}
    213
    214static void m5206_mbar_update(m5206_mbar_state *s)
    215{
    216    int irq;
    217    int vector;
    218    int level;
    219
    220    irq = m5206_find_pending_irq(s);
    221    if (irq) {
    222        int tmp;
    223        tmp = s->icr[irq];
    224        level = (tmp >> 2) & 7;
    225        if (tmp & 0x80) {
    226            /* Autovector.  */
    227            vector = 24 + level;
    228        } else {
    229            switch (irq) {
    230            case 8: /* SWT */
    231                vector = s->swivr;
    232                break;
    233            case 12: /* UART1 */
    234                vector = s->uivr[0];
    235                break;
    236            case 13: /* UART2 */
    237                vector = s->uivr[1];
    238                break;
    239            default:
    240                /* Unknown vector.  */
    241                qemu_log_mask(LOG_UNIMP, "%s: Unhandled vector for IRQ %d\n",
    242                              __func__, irq);
    243                vector = 0xf;
    244                break;
    245            }
    246        }
    247    } else {
    248        level = 0;
    249        vector = 0;
    250    }
    251    m68k_set_irq_level(s->cpu, level, vector);
    252}
    253
    254static void m5206_mbar_set_irq(void *opaque, int irq, int level)
    255{
    256    m5206_mbar_state *s = (m5206_mbar_state *)opaque;
    257    if (level) {
    258        s->ipr |= 1 << irq;
    259    } else {
    260        s->ipr &= ~(1 << irq);
    261    }
    262    m5206_mbar_update(s);
    263}
    264
    265/* System Integration Module.  */
    266
    267static void m5206_mbar_reset(DeviceState *dev)
    268{
    269    m5206_mbar_state *s = MCF5206_MBAR(dev);
    270
    271    s->scr = 0xc0;
    272    s->icr[1] = 0x04;
    273    s->icr[2] = 0x08;
    274    s->icr[3] = 0x0c;
    275    s->icr[4] = 0x10;
    276    s->icr[5] = 0x14;
    277    s->icr[6] = 0x18;
    278    s->icr[7] = 0x1c;
    279    s->icr[8] = 0x1c;
    280    s->icr[9] = 0x80;
    281    s->icr[10] = 0x80;
    282    s->icr[11] = 0x80;
    283    s->icr[12] = 0x00;
    284    s->icr[13] = 0x00;
    285    s->imr = 0x3ffe;
    286    s->rsr = 0x80;
    287    s->swivr = 0x0f;
    288    s->par = 0;
    289}
    290
    291static uint64_t m5206_mbar_read(m5206_mbar_state *s,
    292                                uint16_t offset, unsigned size)
    293{
    294    if (offset >= 0x100 && offset < 0x120) {
    295        return m5206_timer_read(s->timer[0], offset - 0x100);
    296    } else if (offset >= 0x120 && offset < 0x140) {
    297        return m5206_timer_read(s->timer[1], offset - 0x120);
    298    } else if (offset >= 0x140 && offset < 0x160) {
    299        return mcf_uart_read(s->uart[0], offset - 0x140, size);
    300    } else if (offset >= 0x180 && offset < 0x1a0) {
    301        return mcf_uart_read(s->uart[1], offset - 0x180, size);
    302    }
    303    switch (offset) {
    304    case 0x03: return s->scr;
    305    case 0x14 ... 0x20: return s->icr[offset - 0x13];
    306    case 0x36: return s->imr;
    307    case 0x3a: return s->ipr;
    308    case 0x40: return s->rsr;
    309    case 0x41: return 0;
    310    case 0x42: return s->swivr;
    311    case 0x50:
    312        /* DRAM mask register.  */
    313        /* FIXME: currently hardcoded to 128Mb.  */
    314        {
    315            uint32_t mask = ~0;
    316            while (mask > current_machine->ram_size) {
    317                mask >>= 1;
    318            }
    319            return mask & 0x0ffe0000;
    320        }
    321    case 0x5c: return 1; /* DRAM bank 1 empty.  */
    322    case 0xcb: return s->par;
    323    case 0x170: return s->uivr[0];
    324    case 0x1b0: return s->uivr[1];
    325    }
    326    qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad MBAR offset 0x%"PRIx16"\n",
    327                  __func__, offset);
    328    return 0;
    329}
    330
    331static void m5206_mbar_write(m5206_mbar_state *s, uint16_t offset,
    332                             uint64_t value, unsigned size)
    333{
    334    if (offset >= 0x100 && offset < 0x120) {
    335        m5206_timer_write(s->timer[0], offset - 0x100, value);
    336        return;
    337    } else if (offset >= 0x120 && offset < 0x140) {
    338        m5206_timer_write(s->timer[1], offset - 0x120, value);
    339        return;
    340    } else if (offset >= 0x140 && offset < 0x160) {
    341        mcf_uart_write(s->uart[0], offset - 0x140, value, size);
    342        return;
    343    } else if (offset >= 0x180 && offset < 0x1a0) {
    344        mcf_uart_write(s->uart[1], offset - 0x180, value, size);
    345        return;
    346    }
    347    switch (offset) {
    348    case 0x03:
    349        s->scr = value;
    350        break;
    351    case 0x14 ... 0x20:
    352        s->icr[offset - 0x13] = value;
    353        m5206_mbar_update(s);
    354        break;
    355    case 0x36:
    356        s->imr = value;
    357        m5206_mbar_update(s);
    358        break;
    359    case 0x40:
    360        s->rsr &= ~value;
    361        break;
    362    case 0x41:
    363        /* TODO: implement watchdog.  */
    364        break;
    365    case 0x42:
    366        s->swivr = value;
    367        break;
    368    case 0xcb:
    369        s->par = value;
    370        break;
    371    case 0x170:
    372        s->uivr[0] = value;
    373        break;
    374    case 0x178: case 0x17c: case 0x1c8: case 0x1bc:
    375        /* Not implemented: UART Output port bits.  */
    376        break;
    377    case 0x1b0:
    378        s->uivr[1] = value;
    379        break;
    380    default:
    381        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad MBAR offset 0x%"PRIx16"\n",
    382                      __func__, offset);
    383        break;
    384    }
    385}
    386
    387/* Internal peripherals use a variety of register widths.
    388   This lookup table allows a single routine to handle all of them.  */
    389static const uint8_t m5206_mbar_width[] =
    390{
    391  /* 000-040 */ 1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  2, 2, 2, 2,
    392  /* 040-080 */ 1, 2, 2, 2,  4, 1, 2, 4,  1, 2, 4, 2,  2, 4, 2, 2,
    393  /* 080-0c0 */ 4, 2, 2, 4,  2, 2, 4, 2,  2, 4, 2, 2,  4, 2, 2, 4,
    394  /* 0c0-100 */ 2, 2, 1, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,
    395  /* 100-140 */ 2, 2, 2, 2,  1, 0, 0, 0,  2, 2, 2, 2,  1, 0, 0, 0,
    396  /* 140-180 */ 1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
    397  /* 180-1c0 */ 1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
    398  /* 1c0-200 */ 1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
    399};
    400
    401static uint32_t m5206_mbar_readw(void *opaque, hwaddr offset);
    402static uint32_t m5206_mbar_readl(void *opaque, hwaddr offset);
    403
    404static uint32_t m5206_mbar_readb(void *opaque, hwaddr offset)
    405{
    406    m5206_mbar_state *s = (m5206_mbar_state *)opaque;
    407    offset &= 0x3ff;
    408    if (offset >= 0x200) {
    409        qemu_log_mask(LOG_GUEST_ERROR, "Bad MBAR read offset 0x%" HWADDR_PRIX,
    410                      offset);
    411        return 0;
    412    }
    413    if (m5206_mbar_width[offset >> 2] > 1) {
    414        uint16_t val;
    415        val = m5206_mbar_readw(opaque, offset & ~1);
    416        if ((offset & 1) == 0) {
    417            val >>= 8;
    418        }
    419        return val & 0xff;
    420    }
    421    return m5206_mbar_read(s, offset, 1);
    422}
    423
    424static uint32_t m5206_mbar_readw(void *opaque, hwaddr offset)
    425{
    426    m5206_mbar_state *s = (m5206_mbar_state *)opaque;
    427    int width;
    428    offset &= 0x3ff;
    429    if (offset >= 0x200) {
    430        qemu_log_mask(LOG_GUEST_ERROR, "Bad MBAR read offset 0x%" HWADDR_PRIX,
    431                      offset);
    432        return 0;
    433    }
    434    width = m5206_mbar_width[offset >> 2];
    435    if (width > 2) {
    436        uint32_t val;
    437        val = m5206_mbar_readl(opaque, offset & ~3);
    438        if ((offset & 3) == 0)
    439            val >>= 16;
    440        return val & 0xffff;
    441    } else if (width < 2) {
    442        uint16_t val;
    443        val = m5206_mbar_readb(opaque, offset) << 8;
    444        val |= m5206_mbar_readb(opaque, offset + 1);
    445        return val;
    446    }
    447    return m5206_mbar_read(s, offset, 2);
    448}
    449
    450static uint32_t m5206_mbar_readl(void *opaque, hwaddr offset)
    451{
    452    m5206_mbar_state *s = (m5206_mbar_state *)opaque;
    453    int width;
    454    offset &= 0x3ff;
    455    if (offset >= 0x200) {
    456        qemu_log_mask(LOG_GUEST_ERROR, "Bad MBAR read offset 0x%" HWADDR_PRIX,
    457                      offset);
    458        return 0;
    459    }
    460    width = m5206_mbar_width[offset >> 2];
    461    if (width < 4) {
    462        uint32_t val;
    463        val = m5206_mbar_readw(opaque, offset) << 16;
    464        val |= m5206_mbar_readw(opaque, offset + 2);
    465        return val;
    466    }
    467    return m5206_mbar_read(s, offset, 4);
    468}
    469
    470static void m5206_mbar_writew(void *opaque, hwaddr offset,
    471                              uint32_t value);
    472static void m5206_mbar_writel(void *opaque, hwaddr offset,
    473                              uint32_t value);
    474
    475static void m5206_mbar_writeb(void *opaque, hwaddr offset,
    476                              uint32_t value)
    477{
    478    m5206_mbar_state *s = (m5206_mbar_state *)opaque;
    479    int width;
    480    offset &= 0x3ff;
    481    if (offset >= 0x200) {
    482        qemu_log_mask(LOG_GUEST_ERROR, "Bad MBAR write offset 0x%" HWADDR_PRIX,
    483                      offset);
    484        return;
    485    }
    486    width = m5206_mbar_width[offset >> 2];
    487    if (width > 1) {
    488        uint32_t tmp;
    489        tmp = m5206_mbar_readw(opaque, offset & ~1);
    490        if (offset & 1) {
    491            tmp = (tmp & 0xff00) | value;
    492        } else {
    493            tmp = (tmp & 0x00ff) | (value << 8);
    494        }
    495        m5206_mbar_writew(opaque, offset & ~1, tmp);
    496        return;
    497    }
    498    m5206_mbar_write(s, offset, value, 1);
    499}
    500
    501static void m5206_mbar_writew(void *opaque, hwaddr offset,
    502                              uint32_t value)
    503{
    504    m5206_mbar_state *s = (m5206_mbar_state *)opaque;
    505    int width;
    506    offset &= 0x3ff;
    507    if (offset >= 0x200) {
    508        qemu_log_mask(LOG_GUEST_ERROR, "Bad MBAR write offset 0x%" HWADDR_PRIX,
    509                      offset);
    510        return;
    511    }
    512    width = m5206_mbar_width[offset >> 2];
    513    if (width > 2) {
    514        uint32_t tmp;
    515        tmp = m5206_mbar_readl(opaque, offset & ~3);
    516        if (offset & 3) {
    517            tmp = (tmp & 0xffff0000) | value;
    518        } else {
    519            tmp = (tmp & 0x0000ffff) | (value << 16);
    520        }
    521        m5206_mbar_writel(opaque, offset & ~3, tmp);
    522        return;
    523    } else if (width < 2) {
    524        m5206_mbar_writeb(opaque, offset, value >> 8);
    525        m5206_mbar_writeb(opaque, offset + 1, value & 0xff);
    526        return;
    527    }
    528    m5206_mbar_write(s, offset, value, 2);
    529}
    530
    531static void m5206_mbar_writel(void *opaque, hwaddr offset,
    532                              uint32_t value)
    533{
    534    m5206_mbar_state *s = (m5206_mbar_state *)opaque;
    535    int width;
    536    offset &= 0x3ff;
    537    if (offset >= 0x200) {
    538        qemu_log_mask(LOG_GUEST_ERROR, "Bad MBAR write offset 0x%" HWADDR_PRIX,
    539                      offset);
    540        return;
    541    }
    542    width = m5206_mbar_width[offset >> 2];
    543    if (width < 4) {
    544        m5206_mbar_writew(opaque, offset, value >> 16);
    545        m5206_mbar_writew(opaque, offset + 2, value & 0xffff);
    546        return;
    547    }
    548    m5206_mbar_write(s, offset, value, 4);
    549}
    550
    551static uint64_t m5206_mbar_readfn(void *opaque, hwaddr addr, unsigned size)
    552{
    553    switch (size) {
    554    case 1:
    555        return m5206_mbar_readb(opaque, addr);
    556    case 2:
    557        return m5206_mbar_readw(opaque, addr);
    558    case 4:
    559        return m5206_mbar_readl(opaque, addr);
    560    default:
    561        g_assert_not_reached();
    562    }
    563}
    564
    565static void m5206_mbar_writefn(void *opaque, hwaddr addr,
    566                               uint64_t value, unsigned size)
    567{
    568    switch (size) {
    569    case 1:
    570        m5206_mbar_writeb(opaque, addr, value);
    571        break;
    572    case 2:
    573        m5206_mbar_writew(opaque, addr, value);
    574        break;
    575    case 4:
    576        m5206_mbar_writel(opaque, addr, value);
    577        break;
    578    default:
    579        g_assert_not_reached();
    580    }
    581}
    582
    583static const MemoryRegionOps m5206_mbar_ops = {
    584    .read = m5206_mbar_readfn,
    585    .write = m5206_mbar_writefn,
    586    .valid.min_access_size = 1,
    587    .valid.max_access_size = 4,
    588    .endianness = DEVICE_NATIVE_ENDIAN,
    589};
    590
    591static void mcf5206_mbar_realize(DeviceState *dev, Error **errp)
    592{
    593    m5206_mbar_state *s = MCF5206_MBAR(dev);
    594
    595    memory_region_init_io(&s->iomem, NULL, &m5206_mbar_ops, s,
    596                          "mbar", 0x00001000);
    597    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
    598
    599    s->pic = qemu_allocate_irqs(m5206_mbar_set_irq, s, 14);
    600    s->timer[0] = m5206_timer_init(s->pic[9]);
    601    s->timer[1] = m5206_timer_init(s->pic[10]);
    602    s->uart[0] = mcf_uart_init(s->pic[12], serial_hd(0));
    603    s->uart[1] = mcf_uart_init(s->pic[13], serial_hd(1));
    604    s->cpu = M68K_CPU(qemu_get_cpu(0));
    605}
    606
    607static void mcf5206_mbar_class_init(ObjectClass *oc, void *data)
    608{
    609    DeviceClass *dc = DEVICE_CLASS(oc);
    610
    611    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
    612    dc->desc = "MCF5206 system integration module";
    613    dc->realize = mcf5206_mbar_realize;
    614    dc->reset = m5206_mbar_reset;
    615}
    616
    617static const TypeInfo mcf5206_mbar_info = {
    618    .name          = TYPE_MCF5206_MBAR,
    619    .parent        = TYPE_SYS_BUS_DEVICE,
    620    .instance_size = sizeof(m5206_mbar_state),
    621    .class_init    = mcf5206_mbar_class_init,
    622};
    623
    624static void mcf5206_mbar_register_types(void)
    625{
    626    type_register_static(&mcf5206_mbar_info);
    627}
    628
    629type_init(mcf5206_mbar_register_types)