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

pmu.c (25406B)


      1/*
      2 * QEMU PowerMac PMU device support
      3 *
      4 * Copyright (c) 2016 Benjamin Herrenschmidt, IBM Corp.
      5 * Copyright (c) 2018 Mark Cave-Ayland
      6 *
      7 * Based on the CUDA device by:
      8 *
      9 * Copyright (c) 2004-2007 Fabrice Bellard
     10 * Copyright (c) 2007 Jocelyn Mayer
     11 *
     12 * Permission is hereby granted, free of charge, to any person obtaining a copy
     13 * of this software and associated documentation files (the "Software"), to deal
     14 * in the Software without restriction, including without limitation the rights
     15 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     16 * copies of the Software, and to permit persons to whom the Software is
     17 * furnished to do so, subject to the following conditions:
     18 *
     19 * The above copyright notice and this permission notice shall be included in
     20 * all copies or substantial portions of the Software.
     21 *
     22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     25 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     27 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     28 * THE SOFTWARE.
     29 */
     30
     31#include "qemu/osdep.h"
     32#include "qemu-common.h"
     33#include "hw/ppc/mac.h"
     34#include "hw/qdev-properties.h"
     35#include "migration/vmstate.h"
     36#include "hw/input/adb.h"
     37#include "hw/irq.h"
     38#include "hw/misc/mos6522.h"
     39#include "hw/misc/macio/gpio.h"
     40#include "hw/misc/macio/pmu.h"
     41#include "qapi/error.h"
     42#include "qemu/timer.h"
     43#include "sysemu/runstate.h"
     44#include "qapi/error.h"
     45#include "qemu/cutils.h"
     46#include "qemu/log.h"
     47#include "qemu/module.h"
     48#include "trace.h"
     49
     50
     51/* Bits in B data register: all active low */
     52#define TACK    0x08    /* Transfer request (input) */
     53#define TREQ    0x10    /* Transfer acknowledge (output) */
     54
     55/* PMU returns time_t's offset from Jan 1, 1904, not 1970 */
     56#define RTC_OFFSET                      2082844800
     57
     58#define VIA_TIMER_FREQ (4700000 / 6)
     59
     60static void via_update_irq(PMUState *s)
     61{
     62    MOS6522PMUState *mps = MOS6522_PMU(&s->mos6522_pmu);
     63    MOS6522State *ms = MOS6522(mps);
     64
     65    bool new_state = !!(ms->ifr & ms->ier & (SR_INT | T1_INT | T2_INT));
     66
     67    if (new_state != s->via_irq_state) {
     68        s->via_irq_state = new_state;
     69        qemu_set_irq(s->via_irq, new_state);
     70    }
     71}
     72
     73static void via_set_sr_int(void *opaque)
     74{
     75    PMUState *s = opaque;
     76    MOS6522PMUState *mps = MOS6522_PMU(&s->mos6522_pmu);
     77    MOS6522State *ms = MOS6522(mps);
     78    MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(ms);
     79
     80    mdc->set_sr_int(ms);
     81}
     82
     83static void pmu_update_extirq(PMUState *s)
     84{
     85    if ((s->intbits & s->intmask) != 0) {
     86        macio_set_gpio(s->gpio, 1, false);
     87    } else {
     88        macio_set_gpio(s->gpio, 1, true);
     89    }
     90}
     91
     92static void pmu_adb_poll(void *opaque)
     93{
     94    PMUState *s = opaque;
     95    ADBBusState *adb_bus = &s->adb_bus;
     96    int olen;
     97
     98    if (!(s->intbits & PMU_INT_ADB)) {
     99        olen = adb_poll(adb_bus, s->adb_reply, adb_bus->autopoll_mask);
    100        trace_pmu_adb_poll(olen);
    101
    102        if (olen > 0) {
    103            s->adb_reply_size = olen;
    104            s->intbits |= PMU_INT_ADB | PMU_INT_ADB_AUTO;
    105            pmu_update_extirq(s);
    106        }
    107    }
    108}
    109
    110static void pmu_one_sec_timer(void *opaque)
    111{
    112    PMUState *s = opaque;
    113
    114    trace_pmu_one_sec_timer();
    115
    116    s->intbits |= PMU_INT_TICK;
    117    pmu_update_extirq(s);
    118    s->one_sec_target += 1000;
    119
    120    timer_mod(s->one_sec_timer, s->one_sec_target);
    121}
    122
    123static void pmu_cmd_int_ack(PMUState *s,
    124                            const uint8_t *in_data, uint8_t in_len,
    125                            uint8_t *out_data, uint8_t *out_len)
    126{
    127    if (in_len != 0) {
    128        qemu_log_mask(LOG_GUEST_ERROR,
    129                      "PMU: INT_ACK command, invalid len: %d want: 0\n",
    130                      in_len);
    131        return;
    132    }
    133
    134    /* Make appropriate reply packet */
    135    if (s->intbits & PMU_INT_ADB) {
    136        if (!s->adb_reply_size) {
    137            qemu_log_mask(LOG_GUEST_ERROR,
    138                          "Odd, PMU_INT_ADB set with no reply in buffer\n");
    139        }
    140
    141        memcpy(out_data + 1, s->adb_reply, s->adb_reply_size);
    142        out_data[0] = s->intbits & (PMU_INT_ADB | PMU_INT_ADB_AUTO);
    143        *out_len = s->adb_reply_size + 1;
    144        s->intbits &= ~(PMU_INT_ADB | PMU_INT_ADB_AUTO);
    145        s->adb_reply_size = 0;
    146    } else {
    147        out_data[0] = s->intbits;
    148        s->intbits = 0;
    149        *out_len = 1;
    150    }
    151
    152    pmu_update_extirq(s);
    153}
    154
    155static void pmu_cmd_set_int_mask(PMUState *s,
    156                                 const uint8_t *in_data, uint8_t in_len,
    157                                 uint8_t *out_data, uint8_t *out_len)
    158{
    159    if (in_len != 1) {
    160        qemu_log_mask(LOG_GUEST_ERROR,
    161                      "PMU: SET_INT_MASK command, invalid len: %d want: 1\n",
    162                      in_len);
    163        return;
    164    }
    165
    166    trace_pmu_cmd_set_int_mask(s->intmask);
    167    s->intmask = in_data[0];
    168
    169    pmu_update_extirq(s);
    170}
    171
    172static void pmu_cmd_set_adb_autopoll(PMUState *s, uint16_t mask)
    173{
    174    ADBBusState *adb_bus = &s->adb_bus;
    175
    176    trace_pmu_cmd_set_adb_autopoll(mask);
    177
    178    if (mask) {
    179        adb_set_autopoll_mask(adb_bus, mask);
    180        adb_set_autopoll_enabled(adb_bus, true);
    181    } else {
    182        adb_set_autopoll_enabled(adb_bus, false);
    183    }
    184}
    185
    186static void pmu_cmd_adb(PMUState *s,
    187                        const uint8_t *in_data, uint8_t in_len,
    188                        uint8_t *out_data, uint8_t *out_len)
    189{
    190    int len, adblen;
    191    uint8_t adb_cmd[255];
    192
    193    if (in_len < 2) {
    194        qemu_log_mask(LOG_GUEST_ERROR,
    195                      "PMU: ADB PACKET, invalid len: %d want at least 2\n",
    196                      in_len);
    197        return;
    198    }
    199
    200    *out_len = 0;
    201
    202    if (!s->has_adb) {
    203        trace_pmu_cmd_adb_nobus();
    204        return;
    205    }
    206
    207    /* Set autopoll is a special form of the command */
    208    if (in_data[0] == 0 && in_data[1] == 0x86) {
    209        uint16_t mask = in_data[2];
    210        mask = (mask << 8) | in_data[3];
    211        if (in_len != 4) {
    212            qemu_log_mask(LOG_GUEST_ERROR,
    213                          "PMU: ADB Autopoll requires 4 bytes, got %d\n",
    214                          in_len);
    215            return;
    216        }
    217
    218        pmu_cmd_set_adb_autopoll(s, mask);
    219        return;
    220    }
    221
    222    trace_pmu_cmd_adb_request(in_len, in_data[0], in_data[1], in_data[2],
    223                              in_data[3], in_data[4]);
    224
    225    *out_len = 0;
    226
    227    /* Check ADB len */
    228    adblen = in_data[2];
    229    if (adblen > (in_len - 3)) {
    230        qemu_log_mask(LOG_GUEST_ERROR,
    231                      "PMU: ADB len is %d > %d (in_len -3)...erroring\n",
    232                      adblen, in_len - 3);
    233        len = -1;
    234    } else if (adblen > 252) {
    235        qemu_log_mask(LOG_GUEST_ERROR, "PMU: ADB command too big!\n");
    236        len = -1;
    237    } else {
    238        /* Format command */
    239        adb_cmd[0] = in_data[0];
    240        memcpy(&adb_cmd[1], &in_data[3], in_len - 3);
    241        len = adb_request(&s->adb_bus, s->adb_reply + 2, adb_cmd, in_len - 2);
    242
    243        trace_pmu_cmd_adb_reply(len);
    244    }
    245
    246    if (len > 0) {
    247        /* XXX Check this */
    248        s->adb_reply_size = len + 2;
    249        s->adb_reply[0] = 0x01;
    250        s->adb_reply[1] = len;
    251    } else {
    252        /* XXX Check this */
    253        s->adb_reply_size = 1;
    254        s->adb_reply[0] = 0x00;
    255    }
    256
    257    s->intbits |= PMU_INT_ADB;
    258    pmu_update_extirq(s);
    259}
    260
    261static void pmu_cmd_adb_poll_off(PMUState *s,
    262                                 const uint8_t *in_data, uint8_t in_len,
    263                                 uint8_t *out_data, uint8_t *out_len)
    264{
    265    ADBBusState *adb_bus = &s->adb_bus;
    266
    267    if (in_len != 0) {
    268        qemu_log_mask(LOG_GUEST_ERROR,
    269                      "PMU: ADB POLL OFF command, invalid len: %d want: 0\n",
    270                      in_len);
    271        return;
    272    }
    273
    274    if (s->has_adb) {
    275        adb_set_autopoll_enabled(adb_bus, false);
    276    }
    277}
    278
    279static void pmu_cmd_shutdown(PMUState *s,
    280                             const uint8_t *in_data, uint8_t in_len,
    281                             uint8_t *out_data, uint8_t *out_len)
    282{
    283    if (in_len != 4) {
    284        qemu_log_mask(LOG_GUEST_ERROR,
    285                      "PMU: SHUTDOWN command, invalid len: %d want: 4\n",
    286                      in_len);
    287        return;
    288    }
    289
    290    *out_len = 1;
    291    out_data[0] = 0;
    292
    293    if (in_data[0] != 'M' || in_data[1] != 'A' || in_data[2] != 'T' ||
    294        in_data[3] != 'T') {
    295
    296        qemu_log_mask(LOG_GUEST_ERROR,
    297                      "PMU: SHUTDOWN command, Bad MATT signature\n");
    298        return;
    299    }
    300
    301    qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
    302}
    303
    304static void pmu_cmd_reset(PMUState *s,
    305                          const uint8_t *in_data, uint8_t in_len,
    306                          uint8_t *out_data, uint8_t *out_len)
    307{
    308    if (in_len != 0) {
    309        qemu_log_mask(LOG_GUEST_ERROR,
    310                      "PMU: RESET command, invalid len: %d want: 0\n",
    311                      in_len);
    312        return;
    313    }
    314
    315    qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
    316}
    317
    318static void pmu_cmd_get_rtc(PMUState *s,
    319                            const uint8_t *in_data, uint8_t in_len,
    320                            uint8_t *out_data, uint8_t *out_len)
    321{
    322    uint32_t ti;
    323
    324    if (in_len != 0) {
    325        qemu_log_mask(LOG_GUEST_ERROR,
    326                      "PMU: GET_RTC command, invalid len: %d want: 0\n",
    327                      in_len);
    328        return;
    329    }
    330
    331    ti = s->tick_offset + (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)
    332                           / NANOSECONDS_PER_SECOND);
    333    out_data[0] = ti >> 24;
    334    out_data[1] = ti >> 16;
    335    out_data[2] = ti >> 8;
    336    out_data[3] = ti;
    337    *out_len = 4;
    338}
    339
    340static void pmu_cmd_set_rtc(PMUState *s,
    341                            const uint8_t *in_data, uint8_t in_len,
    342                            uint8_t *out_data, uint8_t *out_len)
    343{
    344    uint32_t ti;
    345
    346    if (in_len != 4) {
    347        qemu_log_mask(LOG_GUEST_ERROR,
    348                      "PMU: SET_RTC command, invalid len: %d want: 4\n",
    349                      in_len);
    350        return;
    351    }
    352
    353    ti = (((uint32_t)in_data[0]) << 24) + (((uint32_t)in_data[1]) << 16)
    354         + (((uint32_t)in_data[2]) << 8) + in_data[3];
    355
    356    s->tick_offset = ti - (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)
    357                           / NANOSECONDS_PER_SECOND);
    358}
    359
    360static void pmu_cmd_system_ready(PMUState *s,
    361                                 const uint8_t *in_data, uint8_t in_len,
    362                                 uint8_t *out_data, uint8_t *out_len)
    363{
    364    /* Do nothing */
    365}
    366
    367static void pmu_cmd_get_version(PMUState *s,
    368                                const uint8_t *in_data, uint8_t in_len,
    369                                uint8_t *out_data, uint8_t *out_len)
    370{
    371    *out_len = 1;
    372    *out_data = 1; /* ??? Check what Apple does */
    373}
    374
    375static void pmu_cmd_power_events(PMUState *s,
    376                                 const uint8_t *in_data, uint8_t in_len,
    377                                 uint8_t *out_data, uint8_t *out_len)
    378{
    379    if (in_len < 1) {
    380        qemu_log_mask(LOG_GUEST_ERROR,
    381                      "PMU: POWER EVENTS command, invalid len %d, want at least 1\n",
    382                      in_len);
    383        return;
    384    }
    385
    386    switch (in_data[0]) {
    387    /* Dummies for now */
    388    case PMU_PWR_GET_POWERUP_EVENTS:
    389        *out_len = 2;
    390        out_data[0] = 0;
    391        out_data[1] = 0;
    392        break;
    393    case PMU_PWR_SET_POWERUP_EVENTS:
    394    case PMU_PWR_CLR_POWERUP_EVENTS:
    395        break;
    396    case PMU_PWR_GET_WAKEUP_EVENTS:
    397        *out_len = 2;
    398        out_data[0] = 0;
    399        out_data[1] = 0;
    400        break;
    401    case PMU_PWR_SET_WAKEUP_EVENTS:
    402    case PMU_PWR_CLR_WAKEUP_EVENTS:
    403        break;
    404    default:
    405        qemu_log_mask(LOG_GUEST_ERROR,
    406                      "PMU: POWER EVENTS unknown subcommand 0x%02x\n",
    407                      in_data[0]);
    408    }
    409}
    410
    411static void pmu_cmd_get_cover(PMUState *s,
    412                              const uint8_t *in_data, uint8_t in_len,
    413                              uint8_t *out_data, uint8_t *out_len)
    414{
    415    /* Not 100% sure here, will have to check what a real Mac
    416     * returns other than byte 0 bit 0 is LID closed on laptops
    417     */
    418    *out_len = 1;
    419    *out_data = 0x00;
    420}
    421
    422static void pmu_cmd_download_status(PMUState *s,
    423                                    const uint8_t *in_data, uint8_t in_len,
    424                                    uint8_t *out_data, uint8_t *out_len)
    425{
    426    /* This has to do with PMU firmware updates as far as I can tell.
    427     *
    428     * We return 0x62 which is what OpenPMU expects
    429     */
    430    *out_len = 1;
    431    *out_data = 0x62;
    432}
    433
    434static void pmu_cmd_read_pmu_ram(PMUState *s,
    435                                 const uint8_t *in_data, uint8_t in_len,
    436                                 uint8_t *out_data, uint8_t *out_len)
    437{
    438    if (in_len < 3) {
    439        qemu_log_mask(LOG_GUEST_ERROR,
    440                      "PMU: READ_PMU_RAM command, invalid len %d, expected 3\n",
    441                      in_len);
    442        return;
    443    }
    444
    445    qemu_log_mask(LOG_GUEST_ERROR,
    446                  "PMU: Unsupported READ_PMU_RAM, args: %02x %02x %02x\n",
    447                  in_data[0], in_data[1], in_data[2]);
    448
    449    *out_len = 0;
    450}
    451
    452/* description of commands */
    453typedef struct PMUCmdHandler {
    454    uint8_t command;
    455    const char *name;
    456    void (*handler)(PMUState *s,
    457                    const uint8_t *in_args, uint8_t in_len,
    458                    uint8_t *out_args, uint8_t *out_len);
    459} PMUCmdHandler;
    460
    461static const PMUCmdHandler PMUCmdHandlers[] = {
    462    { PMU_INT_ACK, "INT ACK", pmu_cmd_int_ack },
    463    { PMU_SET_INTR_MASK, "SET INT MASK", pmu_cmd_set_int_mask },
    464    { PMU_ADB_CMD, "ADB COMMAND", pmu_cmd_adb },
    465    { PMU_ADB_POLL_OFF, "ADB POLL OFF", pmu_cmd_adb_poll_off },
    466    { PMU_RESET, "REBOOT", pmu_cmd_reset },
    467    { PMU_SHUTDOWN, "SHUTDOWN", pmu_cmd_shutdown },
    468    { PMU_READ_RTC, "GET RTC", pmu_cmd_get_rtc },
    469    { PMU_SET_RTC, "SET RTC", pmu_cmd_set_rtc },
    470    { PMU_SYSTEM_READY, "SYSTEM READY", pmu_cmd_system_ready },
    471    { PMU_GET_VERSION, "GET VERSION", pmu_cmd_get_version },
    472    { PMU_POWER_EVENTS, "POWER EVENTS", pmu_cmd_power_events },
    473    { PMU_GET_COVER, "GET_COVER", pmu_cmd_get_cover },
    474    { PMU_DOWNLOAD_STATUS, "DOWNLOAD STATUS", pmu_cmd_download_status },
    475    { PMU_READ_PMU_RAM, "READ PMGR RAM", pmu_cmd_read_pmu_ram },
    476};
    477
    478static void pmu_dispatch_cmd(PMUState *s)
    479{
    480    unsigned int i;
    481
    482    /* No response by default */
    483    s->cmd_rsp_sz = 0;
    484
    485    for (i = 0; i < ARRAY_SIZE(PMUCmdHandlers); i++) {
    486        const PMUCmdHandler *desc = &PMUCmdHandlers[i];
    487
    488        if (desc->command != s->cmd) {
    489            continue;
    490        }
    491
    492        trace_pmu_dispatch_cmd(desc->name);
    493        desc->handler(s, s->cmd_buf, s->cmd_buf_pos,
    494                      s->cmd_rsp, &s->cmd_rsp_sz);
    495
    496        if (s->rsplen != -1 && s->rsplen != s->cmd_rsp_sz) {
    497            trace_pmu_debug_protocol_string("QEMU internal cmd resp mismatch!");
    498        } else {
    499            trace_pmu_debug_protocol_resp_size(s->cmd_rsp_sz);
    500        }
    501
    502        return;
    503    }
    504
    505    trace_pmu_dispatch_unknown_cmd(s->cmd);
    506
    507    /* Manufacture fake response with 0's */
    508    if (s->rsplen == -1) {
    509        s->cmd_rsp_sz = 0;
    510    } else {
    511        s->cmd_rsp_sz = s->rsplen;
    512        memset(s->cmd_rsp, 0, s->rsplen);
    513    }
    514}
    515
    516static void pmu_update(PMUState *s)
    517{
    518    MOS6522PMUState *mps = &s->mos6522_pmu;
    519    MOS6522State *ms = MOS6522(mps);
    520    ADBBusState *adb_bus = &s->adb_bus;
    521
    522    /* Only react to changes in reg B */
    523    if (ms->b == s->last_b) {
    524        return;
    525    }
    526    s->last_b = ms->b;
    527
    528    /* Check the TREQ / TACK state */
    529    switch (ms->b & (TREQ | TACK)) {
    530    case TREQ:
    531        /* This is an ack release, handle it and bail out */
    532        ms->b |= TACK;
    533        s->last_b = ms->b;
    534
    535        trace_pmu_debug_protocol_string("handshake: TREQ high, setting TACK");
    536        return;
    537    case TACK:
    538        /* This is a valid request, handle below */
    539        break;
    540    case TREQ | TACK:
    541        /* This is an idle state */
    542        return;
    543    default:
    544        /* Invalid state, log and ignore */
    545        trace_pmu_debug_protocol_error(ms->b);
    546        return;
    547    }
    548
    549    /* If we wanted to handle commands asynchronously, this is where
    550     * we would delay the clearing of TACK until we are ready to send
    551     * the response
    552     */
    553
    554    /* We have a request, handshake TACK so we don't stay in
    555     * an invalid state. If we were concurrent with the OS we
    556     * should only do this after we grabbed the SR but that isn't
    557     * a problem here.
    558     */
    559
    560    trace_pmu_debug_protocol_clear_treq(s->cmd_state);
    561
    562    ms->b &= ~TACK;
    563    s->last_b = ms->b;
    564
    565    /* Act according to state */
    566    switch (s->cmd_state) {
    567    case pmu_state_idle:
    568        if (!(ms->acr & SR_OUT)) {
    569            trace_pmu_debug_protocol_string("protocol error! "
    570                                            "state idle, ACR reading");
    571            break;
    572        }
    573
    574        s->cmd = ms->sr;
    575        via_set_sr_int(s);
    576        s->cmdlen = pmu_data_len[s->cmd][0];
    577        s->rsplen = pmu_data_len[s->cmd][1];
    578        s->cmd_buf_pos = 0;
    579        s->cmd_rsp_pos = 0;
    580        s->cmd_state = pmu_state_cmd;
    581
    582        adb_autopoll_block(adb_bus);
    583        trace_pmu_debug_protocol_cmd(s->cmd, s->cmdlen, s->rsplen);
    584        break;
    585
    586    case pmu_state_cmd:
    587        if (!(ms->acr & SR_OUT)) {
    588            trace_pmu_debug_protocol_string("protocol error! "
    589                                            "state cmd, ACR reading");
    590            break;
    591        }
    592
    593        if (s->cmdlen == -1) {
    594            trace_pmu_debug_protocol_cmdlen(ms->sr);
    595
    596            s->cmdlen = ms->sr;
    597            if (s->cmdlen > sizeof(s->cmd_buf)) {
    598                trace_pmu_debug_protocol_cmd_toobig(s->cmdlen);
    599            }
    600        } else if (s->cmd_buf_pos < sizeof(s->cmd_buf)) {
    601            s->cmd_buf[s->cmd_buf_pos++] = ms->sr;
    602        }
    603
    604        via_set_sr_int(s);
    605        break;
    606
    607    case pmu_state_rsp:
    608        if (ms->acr & SR_OUT) {
    609            trace_pmu_debug_protocol_string("protocol error! "
    610                                            "state resp, ACR writing");
    611            break;
    612        }
    613
    614        if (s->rsplen == -1) {
    615            trace_pmu_debug_protocol_cmd_send_resp_size(s->cmd_rsp_sz);
    616
    617            ms->sr = s->cmd_rsp_sz;
    618            s->rsplen = s->cmd_rsp_sz;
    619        } else if (s->cmd_rsp_pos < s->cmd_rsp_sz) {
    620            trace_pmu_debug_protocol_cmd_send_resp(s->cmd_rsp_pos, s->rsplen);
    621
    622            ms->sr = s->cmd_rsp[s->cmd_rsp_pos++];
    623        }
    624
    625        via_set_sr_int(s);
    626        break;
    627    }
    628
    629    /* Check for state completion */
    630    if (s->cmd_state == pmu_state_cmd && s->cmdlen == s->cmd_buf_pos) {
    631        trace_pmu_debug_protocol_string("Command reception complete, "
    632                                        "dispatching...");
    633
    634        pmu_dispatch_cmd(s);
    635        s->cmd_state = pmu_state_rsp;
    636    }
    637
    638    if (s->cmd_state == pmu_state_rsp && s->rsplen == s->cmd_rsp_pos) {
    639        trace_pmu_debug_protocol_cmd_resp_complete(ms->ier);
    640
    641        adb_autopoll_unblock(adb_bus);
    642        s->cmd_state = pmu_state_idle;
    643    }
    644}
    645
    646static uint64_t mos6522_pmu_read(void *opaque, hwaddr addr, unsigned size)
    647{
    648    PMUState *s = opaque;
    649    MOS6522PMUState *mps = &s->mos6522_pmu;
    650    MOS6522State *ms = MOS6522(mps);
    651
    652    addr = (addr >> 9) & 0xf;
    653    return mos6522_read(ms, addr, size);
    654}
    655
    656static void mos6522_pmu_write(void *opaque, hwaddr addr, uint64_t val,
    657                              unsigned size)
    658{
    659    PMUState *s = opaque;
    660    MOS6522PMUState *mps = &s->mos6522_pmu;
    661    MOS6522State *ms = MOS6522(mps);
    662
    663    addr = (addr >> 9) & 0xf;
    664    mos6522_write(ms, addr, val, size);
    665}
    666
    667static const MemoryRegionOps mos6522_pmu_ops = {
    668    .read = mos6522_pmu_read,
    669    .write = mos6522_pmu_write,
    670    .endianness = DEVICE_BIG_ENDIAN,
    671    .impl = {
    672        .min_access_size = 1,
    673        .max_access_size = 1,
    674    },
    675};
    676
    677static bool pmu_adb_state_needed(void *opaque)
    678{
    679    PMUState *s = opaque;
    680
    681    return s->has_adb;
    682}
    683
    684static const VMStateDescription vmstate_pmu_adb = {
    685    .name = "pmu/adb",
    686    .version_id = 1,
    687    .minimum_version_id = 1,
    688    .needed = pmu_adb_state_needed,
    689    .fields = (VMStateField[]) {
    690        VMSTATE_UINT8(adb_reply_size, PMUState),
    691        VMSTATE_BUFFER(adb_reply, PMUState),
    692        VMSTATE_END_OF_LIST()
    693    }
    694};
    695
    696static const VMStateDescription vmstate_pmu = {
    697    .name = "pmu",
    698    .version_id = 1,
    699    .minimum_version_id = 1,
    700    .fields = (VMStateField[]) {
    701        VMSTATE_STRUCT(mos6522_pmu.parent_obj, PMUState, 0, vmstate_mos6522,
    702                       MOS6522State),
    703        VMSTATE_UINT8(last_b, PMUState),
    704        VMSTATE_UINT8(cmd, PMUState),
    705        VMSTATE_UINT32(cmdlen, PMUState),
    706        VMSTATE_UINT32(rsplen, PMUState),
    707        VMSTATE_UINT8(cmd_buf_pos, PMUState),
    708        VMSTATE_BUFFER(cmd_buf, PMUState),
    709        VMSTATE_UINT8(cmd_rsp_pos, PMUState),
    710        VMSTATE_UINT8(cmd_rsp_sz, PMUState),
    711        VMSTATE_BUFFER(cmd_rsp, PMUState),
    712        VMSTATE_UINT8(intbits, PMUState),
    713        VMSTATE_UINT8(intmask, PMUState),
    714        VMSTATE_UINT32(tick_offset, PMUState),
    715        VMSTATE_TIMER_PTR(one_sec_timer, PMUState),
    716        VMSTATE_INT64(one_sec_target, PMUState),
    717        VMSTATE_END_OF_LIST()
    718    },
    719    .subsections = (const VMStateDescription * []) {
    720        &vmstate_pmu_adb,
    721    }
    722};
    723
    724static void pmu_reset(DeviceState *dev)
    725{
    726    PMUState *s = VIA_PMU(dev);
    727
    728    /* OpenBIOS needs to do this? MacOS 9 needs it */
    729    s->intmask = PMU_INT_ADB | PMU_INT_TICK;
    730    s->intbits = 0;
    731
    732    s->cmd_state = pmu_state_idle;
    733}
    734
    735static void pmu_realize(DeviceState *dev, Error **errp)
    736{
    737    PMUState *s = VIA_PMU(dev);
    738    SysBusDevice *sbd;
    739    ADBBusState *adb_bus = &s->adb_bus;
    740    struct tm tm;
    741
    742    if (!sysbus_realize(SYS_BUS_DEVICE(&s->mos6522_pmu), errp)) {
    743        return;
    744    }
    745
    746    /* Pass IRQ from 6522 */
    747    sbd = SYS_BUS_DEVICE(s);
    748    sysbus_pass_irq(sbd, SYS_BUS_DEVICE(&s->mos6522_pmu));
    749
    750    qemu_get_timedate(&tm, 0);
    751    s->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET;
    752    s->one_sec_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, pmu_one_sec_timer, s);
    753    s->one_sec_target = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000;
    754    timer_mod(s->one_sec_timer, s->one_sec_target);
    755
    756    if (s->has_adb) {
    757        qbus_init(&s->adb_bus, sizeof(s->adb_bus), TYPE_ADB_BUS,
    758                  dev, "adb.0");
    759        adb_register_autopoll_callback(adb_bus, pmu_adb_poll, s);
    760    }
    761}
    762
    763static void pmu_init(Object *obj)
    764{
    765    SysBusDevice *d = SYS_BUS_DEVICE(obj);
    766    PMUState *s = VIA_PMU(obj);
    767
    768    object_property_add_link(obj, "gpio", TYPE_MACIO_GPIO,
    769                             (Object **) &s->gpio,
    770                             qdev_prop_allow_set_link_before_realize,
    771                             0);
    772
    773    object_initialize_child(obj, "mos6522-pmu", &s->mos6522_pmu,
    774                            TYPE_MOS6522_PMU);
    775
    776    memory_region_init_io(&s->mem, obj, &mos6522_pmu_ops, s, "via-pmu",
    777                          0x2000);
    778    sysbus_init_mmio(d, &s->mem);
    779}
    780
    781static Property pmu_properties[] = {
    782    DEFINE_PROP_BOOL("has-adb", PMUState, has_adb, true),
    783    DEFINE_PROP_END_OF_LIST()
    784};
    785
    786static void pmu_class_init(ObjectClass *oc, void *data)
    787{
    788    DeviceClass *dc = DEVICE_CLASS(oc);
    789
    790    dc->realize = pmu_realize;
    791    dc->reset = pmu_reset;
    792    dc->vmsd = &vmstate_pmu;
    793    device_class_set_props(dc, pmu_properties);
    794    set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
    795}
    796
    797static const TypeInfo pmu_type_info = {
    798    .name = TYPE_VIA_PMU,
    799    .parent = TYPE_SYS_BUS_DEVICE,
    800    .instance_size = sizeof(PMUState),
    801    .instance_init = pmu_init,
    802    .class_init = pmu_class_init,
    803};
    804
    805static void mos6522_pmu_portB_write(MOS6522State *s)
    806{
    807    MOS6522PMUState *mps = container_of(s, MOS6522PMUState, parent_obj);
    808    PMUState *ps = container_of(mps, PMUState, mos6522_pmu);
    809
    810    if ((s->pcr & 0xe0) == 0x20 || (s->pcr & 0xe0) == 0x60) {
    811        s->ifr &= ~CB2_INT;
    812    }
    813    s->ifr &= ~CB1_INT;
    814
    815    via_update_irq(ps);
    816    pmu_update(ps);
    817}
    818
    819static void mos6522_pmu_portA_write(MOS6522State *s)
    820{
    821    MOS6522PMUState *mps = container_of(s, MOS6522PMUState, parent_obj);
    822    PMUState *ps = container_of(mps, PMUState, mos6522_pmu);
    823
    824    if ((s->pcr & 0x0e) == 0x02 || (s->pcr & 0x0e) == 0x06) {
    825        s->ifr &= ~CA2_INT;
    826    }
    827    s->ifr &= ~CA1_INT;
    828
    829    via_update_irq(ps);
    830}
    831
    832static void mos6522_pmu_reset(DeviceState *dev)
    833{
    834    MOS6522State *ms = MOS6522(dev);
    835    MOS6522PMUState *mps = container_of(ms, MOS6522PMUState, parent_obj);
    836    PMUState *s = container_of(mps, PMUState, mos6522_pmu);
    837    MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(ms);
    838
    839    mdc->parent_reset(dev);
    840
    841    ms->timers[0].frequency = VIA_TIMER_FREQ;
    842    ms->timers[1].frequency = (SCALE_US * 6000) / 4700;
    843
    844    s->last_b = ms->b = TACK | TREQ;
    845}
    846
    847static void mos6522_pmu_class_init(ObjectClass *oc, void *data)
    848{
    849    DeviceClass *dc = DEVICE_CLASS(oc);
    850    MOS6522DeviceClass *mdc = MOS6522_CLASS(oc);
    851
    852    dc->reset = mos6522_pmu_reset;
    853    mdc->portB_write = mos6522_pmu_portB_write;
    854    mdc->portA_write = mos6522_pmu_portA_write;
    855}
    856
    857static const TypeInfo mos6522_pmu_type_info = {
    858    .name = TYPE_MOS6522_PMU,
    859    .parent = TYPE_MOS6522,
    860    .instance_size = sizeof(MOS6522PMUState),
    861    .class_init = mos6522_pmu_class_init,
    862};
    863
    864static void pmu_register_types(void)
    865{
    866    type_register_static(&pmu_type_info);
    867    type_register_static(&mos6522_pmu_type_info);
    868}
    869
    870type_init(pmu_register_types)