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

mos6522.c (15696B)


      1/*
      2 * QEMU MOS6522 VIA emulation
      3 *
      4 * Copyright (c) 2004-2007 Fabrice Bellard
      5 * Copyright (c) 2007 Jocelyn Mayer
      6 * Copyright (c) 2018 Mark Cave-Ayland
      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 "hw/input/adb.h"
     29#include "hw/irq.h"
     30#include "hw/misc/mos6522.h"
     31#include "hw/qdev-properties.h"
     32#include "migration/vmstate.h"
     33#include "qemu/timer.h"
     34#include "qemu/cutils.h"
     35#include "qemu/log.h"
     36#include "qemu/module.h"
     37#include "trace.h"
     38
     39/* XXX: implement all timer modes */
     40
     41static void mos6522_timer1_update(MOS6522State *s, MOS6522Timer *ti,
     42                                  int64_t current_time);
     43static void mos6522_timer2_update(MOS6522State *s, MOS6522Timer *ti,
     44                                  int64_t current_time);
     45
     46static void mos6522_update_irq(MOS6522State *s)
     47{
     48    if (s->ifr & s->ier) {
     49        qemu_irq_raise(s->irq);
     50    } else {
     51        qemu_irq_lower(s->irq);
     52    }
     53}
     54
     55static uint64_t get_counter_value(MOS6522State *s, MOS6522Timer *ti)
     56{
     57    MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(s);
     58
     59    if (ti->index == 0) {
     60        return mdc->get_timer1_counter_value(s, ti);
     61    } else {
     62        return mdc->get_timer2_counter_value(s, ti);
     63    }
     64}
     65
     66static uint64_t get_load_time(MOS6522State *s, MOS6522Timer *ti)
     67{
     68    MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(s);
     69
     70    if (ti->index == 0) {
     71        return mdc->get_timer1_load_time(s, ti);
     72    } else {
     73        return mdc->get_timer2_load_time(s, ti);
     74    }
     75}
     76
     77static unsigned int get_counter(MOS6522State *s, MOS6522Timer *ti)
     78{
     79    int64_t d;
     80    unsigned int counter;
     81
     82    d = get_counter_value(s, ti);
     83
     84    if (ti->index == 0) {
     85        /* the timer goes down from latch to -1 (period of latch + 2) */
     86        if (d <= (ti->counter_value + 1)) {
     87            counter = (ti->counter_value - d) & 0xffff;
     88        } else {
     89            counter = (d - (ti->counter_value + 1)) % (ti->latch + 2);
     90            counter = (ti->latch - counter) & 0xffff;
     91        }
     92    } else {
     93        counter = (ti->counter_value - d) & 0xffff;
     94    }
     95    return counter;
     96}
     97
     98static void set_counter(MOS6522State *s, MOS6522Timer *ti, unsigned int val)
     99{
    100    trace_mos6522_set_counter(1 + ti->index, val);
    101    ti->load_time = get_load_time(s, ti);
    102    ti->counter_value = val;
    103    if (ti->index == 0) {
    104        mos6522_timer1_update(s, ti, ti->load_time);
    105    } else {
    106        mos6522_timer2_update(s, ti, ti->load_time);
    107    }
    108}
    109
    110static int64_t get_next_irq_time(MOS6522State *s, MOS6522Timer *ti,
    111                                 int64_t current_time)
    112{
    113    int64_t d, next_time;
    114    unsigned int counter;
    115
    116    if (ti->frequency == 0) {
    117        return INT64_MAX;
    118    }
    119
    120    /* current counter value */
    121    d = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - ti->load_time,
    122                 ti->frequency, NANOSECONDS_PER_SECOND);
    123
    124    /* the timer goes down from latch to -1 (period of latch + 2) */
    125    if (d <= (ti->counter_value + 1)) {
    126        counter = (ti->counter_value - d) & 0xffff;
    127    } else {
    128        counter = (d - (ti->counter_value + 1)) % (ti->latch + 2);
    129        counter = (ti->latch - counter) & 0xffff;
    130    }
    131
    132    /* Note: we consider the irq is raised on 0 */
    133    if (counter == 0xffff) {
    134        next_time = d + ti->latch + 1;
    135    } else if (counter == 0) {
    136        next_time = d + ti->latch + 2;
    137    } else {
    138        next_time = d + counter;
    139    }
    140    trace_mos6522_get_next_irq_time(ti->latch, d, next_time - d);
    141    next_time = muldiv64(next_time, NANOSECONDS_PER_SECOND, ti->frequency) +
    142                         ti->load_time;
    143
    144    if (next_time <= current_time) {
    145        next_time = current_time + 1;
    146    }
    147    return next_time;
    148}
    149
    150static void mos6522_timer1_update(MOS6522State *s, MOS6522Timer *ti,
    151                                 int64_t current_time)
    152{
    153    if (!ti->timer) {
    154        return;
    155    }
    156    ti->next_irq_time = get_next_irq_time(s, ti, current_time);
    157    if ((s->ier & T1_INT) == 0 || (s->acr & T1MODE) != T1MODE_CONT) {
    158        timer_del(ti->timer);
    159    } else {
    160        timer_mod(ti->timer, ti->next_irq_time);
    161    }
    162}
    163
    164static void mos6522_timer2_update(MOS6522State *s, MOS6522Timer *ti,
    165                                 int64_t current_time)
    166{
    167    if (!ti->timer) {
    168        return;
    169    }
    170    ti->next_irq_time = get_next_irq_time(s, ti, current_time);
    171    if ((s->ier & T2_INT) == 0) {
    172        timer_del(ti->timer);
    173    } else {
    174        timer_mod(ti->timer, ti->next_irq_time);
    175    }
    176}
    177
    178static void mos6522_timer1(void *opaque)
    179{
    180    MOS6522State *s = opaque;
    181    MOS6522Timer *ti = &s->timers[0];
    182
    183    mos6522_timer1_update(s, ti, ti->next_irq_time);
    184    s->ifr |= T1_INT;
    185    mos6522_update_irq(s);
    186}
    187
    188static void mos6522_timer2(void *opaque)
    189{
    190    MOS6522State *s = opaque;
    191    MOS6522Timer *ti = &s->timers[1];
    192
    193    mos6522_timer2_update(s, ti, ti->next_irq_time);
    194    s->ifr |= T2_INT;
    195    mos6522_update_irq(s);
    196}
    197
    198static void mos6522_set_sr_int(MOS6522State *s)
    199{
    200    trace_mos6522_set_sr_int();
    201    s->ifr |= SR_INT;
    202    mos6522_update_irq(s);
    203}
    204
    205static uint64_t mos6522_get_counter_value(MOS6522State *s, MOS6522Timer *ti)
    206{
    207    return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - ti->load_time,
    208                    ti->frequency, NANOSECONDS_PER_SECOND);
    209}
    210
    211static uint64_t mos6522_get_load_time(MOS6522State *s, MOS6522Timer *ti)
    212{
    213    uint64_t load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
    214
    215    return load_time;
    216}
    217
    218static void mos6522_portA_write(MOS6522State *s)
    219{
    220    qemu_log_mask(LOG_UNIMP, "portA_write unimplemented\n");
    221}
    222
    223static void mos6522_portB_write(MOS6522State *s)
    224{
    225    qemu_log_mask(LOG_UNIMP, "portB_write unimplemented\n");
    226}
    227
    228uint64_t mos6522_read(void *opaque, hwaddr addr, unsigned size)
    229{
    230    MOS6522State *s = opaque;
    231    uint32_t val;
    232    int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
    233
    234    if (now >= s->timers[0].next_irq_time) {
    235        mos6522_timer1_update(s, &s->timers[0], now);
    236        s->ifr |= T1_INT;
    237    }
    238    if (now >= s->timers[1].next_irq_time) {
    239        mos6522_timer2_update(s, &s->timers[1], now);
    240        s->ifr |= T2_INT;
    241    }
    242    switch (addr) {
    243    case VIA_REG_B:
    244        val = s->b;
    245        break;
    246    case VIA_REG_A:
    247       qemu_log_mask(LOG_UNIMP, "Read access to register A with handshake");
    248       /* fall through */
    249    case VIA_REG_ANH:
    250        val = s->a;
    251        break;
    252    case VIA_REG_DIRB:
    253        val = s->dirb;
    254        break;
    255    case VIA_REG_DIRA:
    256        val = s->dira;
    257        break;
    258    case VIA_REG_T1CL:
    259        val = get_counter(s, &s->timers[0]) & 0xff;
    260        s->ifr &= ~T1_INT;
    261        mos6522_update_irq(s);
    262        break;
    263    case VIA_REG_T1CH:
    264        val = get_counter(s, &s->timers[0]) >> 8;
    265        mos6522_update_irq(s);
    266        break;
    267    case VIA_REG_T1LL:
    268        val = s->timers[0].latch & 0xff;
    269        break;
    270    case VIA_REG_T1LH:
    271        /* XXX: check this */
    272        val = (s->timers[0].latch >> 8) & 0xff;
    273        break;
    274    case VIA_REG_T2CL:
    275        val = get_counter(s, &s->timers[1]) & 0xff;
    276        s->ifr &= ~T2_INT;
    277        mos6522_update_irq(s);
    278        break;
    279    case VIA_REG_T2CH:
    280        val = get_counter(s, &s->timers[1]) >> 8;
    281        break;
    282    case VIA_REG_SR:
    283        val = s->sr;
    284        s->ifr &= ~SR_INT;
    285        mos6522_update_irq(s);
    286        break;
    287    case VIA_REG_ACR:
    288        val = s->acr;
    289        break;
    290    case VIA_REG_PCR:
    291        val = s->pcr;
    292        break;
    293    case VIA_REG_IFR:
    294        val = s->ifr;
    295        if (s->ifr & s->ier) {
    296            val |= 0x80;
    297        }
    298        break;
    299    case VIA_REG_IER:
    300        val = s->ier | 0x80;
    301        break;
    302    default:
    303        g_assert_not_reached();
    304    }
    305
    306    if (addr != VIA_REG_IFR || val != 0) {
    307        trace_mos6522_read(addr, val);
    308    }
    309
    310    return val;
    311}
    312
    313void mos6522_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
    314{
    315    MOS6522State *s = opaque;
    316    MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(s);
    317
    318    trace_mos6522_write(addr, val);
    319
    320    switch (addr) {
    321    case VIA_REG_B:
    322        s->b = (s->b & ~s->dirb) | (val & s->dirb);
    323        mdc->portB_write(s);
    324        break;
    325    case VIA_REG_A:
    326       qemu_log_mask(LOG_UNIMP, "Write access to register A with handshake");
    327       /* fall through */
    328    case VIA_REG_ANH:
    329        s->a = (s->a & ~s->dira) | (val & s->dira);
    330        mdc->portA_write(s);
    331        break;
    332    case VIA_REG_DIRB:
    333        s->dirb = val;
    334        break;
    335    case VIA_REG_DIRA:
    336        s->dira = val;
    337        break;
    338    case VIA_REG_T1CL:
    339        s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
    340        mos6522_timer1_update(s, &s->timers[0],
    341                              qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
    342        break;
    343    case VIA_REG_T1CH:
    344        s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
    345        s->ifr &= ~T1_INT;
    346        set_counter(s, &s->timers[0], s->timers[0].latch);
    347        break;
    348    case VIA_REG_T1LL:
    349        s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
    350        mos6522_timer1_update(s, &s->timers[0],
    351                              qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
    352        break;
    353    case VIA_REG_T1LH:
    354        s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
    355        s->ifr &= ~T1_INT;
    356        mos6522_timer1_update(s, &s->timers[0],
    357                              qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
    358        break;
    359    case VIA_REG_T2CL:
    360        s->timers[1].latch = (s->timers[1].latch & 0xff00) | val;
    361        break;
    362    case VIA_REG_T2CH:
    363        /* To ensure T2 generates an interrupt on zero crossing with the
    364           common timer code, write the value directly from the latch to
    365           the counter */
    366        s->timers[1].latch = (s->timers[1].latch & 0xff) | (val << 8);
    367        s->ifr &= ~T2_INT;
    368        set_counter(s, &s->timers[1], s->timers[1].latch);
    369        break;
    370    case VIA_REG_SR:
    371        s->sr = val;
    372        break;
    373    case VIA_REG_ACR:
    374        s->acr = val;
    375        mos6522_timer1_update(s, &s->timers[0],
    376                              qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
    377        break;
    378    case VIA_REG_PCR:
    379        s->pcr = val;
    380        break;
    381    case VIA_REG_IFR:
    382        /* reset bits */
    383        s->ifr &= ~val;
    384        mos6522_update_irq(s);
    385        break;
    386    case VIA_REG_IER:
    387        if (val & IER_SET) {
    388            /* set bits */
    389            s->ier |= val & 0x7f;
    390        } else {
    391            /* reset bits */
    392            s->ier &= ~val;
    393        }
    394        mos6522_update_irq(s);
    395        /* if IER is modified starts needed timers */
    396        mos6522_timer1_update(s, &s->timers[0],
    397                              qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
    398        mos6522_timer2_update(s, &s->timers[1],
    399                              qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
    400        break;
    401    default:
    402        g_assert_not_reached();
    403    }
    404}
    405
    406static const MemoryRegionOps mos6522_ops = {
    407    .read = mos6522_read,
    408    .write = mos6522_write,
    409    .endianness = DEVICE_NATIVE_ENDIAN,
    410    .valid = {
    411        .min_access_size = 1,
    412        .max_access_size = 1,
    413    },
    414};
    415
    416static const VMStateDescription vmstate_mos6522_timer = {
    417    .name = "mos6522_timer",
    418    .version_id = 0,
    419    .minimum_version_id = 0,
    420    .fields = (VMStateField[]) {
    421        VMSTATE_UINT16(latch, MOS6522Timer),
    422        VMSTATE_UINT16(counter_value, MOS6522Timer),
    423        VMSTATE_INT64(load_time, MOS6522Timer),
    424        VMSTATE_INT64(next_irq_time, MOS6522Timer),
    425        VMSTATE_TIMER_PTR(timer, MOS6522Timer),
    426        VMSTATE_END_OF_LIST()
    427    }
    428};
    429
    430const VMStateDescription vmstate_mos6522 = {
    431    .name = "mos6522",
    432    .version_id = 0,
    433    .minimum_version_id = 0,
    434    .fields = (VMStateField[]) {
    435        VMSTATE_UINT8(a, MOS6522State),
    436        VMSTATE_UINT8(b, MOS6522State),
    437        VMSTATE_UINT8(dira, MOS6522State),
    438        VMSTATE_UINT8(dirb, MOS6522State),
    439        VMSTATE_UINT8(sr, MOS6522State),
    440        VMSTATE_UINT8(acr, MOS6522State),
    441        VMSTATE_UINT8(pcr, MOS6522State),
    442        VMSTATE_UINT8(ifr, MOS6522State),
    443        VMSTATE_UINT8(ier, MOS6522State),
    444        VMSTATE_STRUCT_ARRAY(timers, MOS6522State, 2, 0,
    445                             vmstate_mos6522_timer, MOS6522Timer),
    446        VMSTATE_END_OF_LIST()
    447    }
    448};
    449
    450static void mos6522_reset(DeviceState *dev)
    451{
    452    MOS6522State *s = MOS6522(dev);
    453
    454    s->b = 0;
    455    s->a = 0;
    456    s->dirb = 0xff;
    457    s->dira = 0;
    458    s->sr = 0;
    459    s->acr = 0;
    460    s->pcr = 0;
    461    s->ifr = 0;
    462    s->ier = 0;
    463    /* s->ier = T1_INT | SR_INT; */
    464
    465    s->timers[0].frequency = s->frequency;
    466    s->timers[0].latch = 0xffff;
    467    set_counter(s, &s->timers[0], 0xffff);
    468    timer_del(s->timers[0].timer);
    469
    470    s->timers[1].frequency = s->frequency;
    471    s->timers[1].latch = 0xffff;
    472    timer_del(s->timers[1].timer);
    473}
    474
    475static void mos6522_init(Object *obj)
    476{
    477    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    478    MOS6522State *s = MOS6522(obj);
    479    int i;
    480
    481    memory_region_init_io(&s->mem, obj, &mos6522_ops, s, "mos6522", 0x10);
    482    sysbus_init_mmio(sbd, &s->mem);
    483    sysbus_init_irq(sbd, &s->irq);
    484
    485    for (i = 0; i < ARRAY_SIZE(s->timers); i++) {
    486        s->timers[i].index = i;
    487    }
    488
    489    s->timers[0].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, mos6522_timer1, s);
    490    s->timers[1].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, mos6522_timer2, s);
    491}
    492
    493static void mos6522_finalize(Object *obj)
    494{
    495    MOS6522State *s = MOS6522(obj);
    496
    497    timer_free(s->timers[0].timer);
    498    timer_free(s->timers[1].timer);
    499}
    500
    501static Property mos6522_properties[] = {
    502    DEFINE_PROP_UINT64("frequency", MOS6522State, frequency, 0),
    503    DEFINE_PROP_END_OF_LIST()
    504};
    505
    506static void mos6522_class_init(ObjectClass *oc, void *data)
    507{
    508    DeviceClass *dc = DEVICE_CLASS(oc);
    509    MOS6522DeviceClass *mdc = MOS6522_CLASS(oc);
    510
    511    dc->reset = mos6522_reset;
    512    dc->vmsd = &vmstate_mos6522;
    513    device_class_set_props(dc, mos6522_properties);
    514    mdc->parent_reset = dc->reset;
    515    mdc->set_sr_int = mos6522_set_sr_int;
    516    mdc->portB_write = mos6522_portB_write;
    517    mdc->portA_write = mos6522_portA_write;
    518    mdc->update_irq = mos6522_update_irq;
    519    mdc->get_timer1_counter_value = mos6522_get_counter_value;
    520    mdc->get_timer2_counter_value = mos6522_get_counter_value;
    521    mdc->get_timer1_load_time = mos6522_get_load_time;
    522    mdc->get_timer2_load_time = mos6522_get_load_time;
    523}
    524
    525static const TypeInfo mos6522_type_info = {
    526    .name = TYPE_MOS6522,
    527    .parent = TYPE_SYS_BUS_DEVICE,
    528    .instance_size = sizeof(MOS6522State),
    529    .instance_init = mos6522_init,
    530    .instance_finalize = mos6522_finalize,
    531    .abstract = true,
    532    .class_size = sizeof(MOS6522DeviceClass),
    533    .class_init = mos6522_class_init,
    534};
    535
    536static void mos6522_register_types(void)
    537{
    538    type_register_static(&mos6522_type_info);
    539}
    540
    541type_init(mos6522_register_types)