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

ctucan_core.c (20599B)


      1/*
      2 * CTU CAN FD PCI device emulation
      3 * http://canbus.pages.fel.cvut.cz/
      4 *
      5 * Copyright (c) 2019 Jan Charvat (jancharvat.charvat@gmail.com)
      6 *
      7 * Based on Kvaser PCI CAN device (SJA1000 based) emulation implemented by
      8 * Jin Yang and Pavel Pisa
      9 *
     10 * Permission is hereby granted, free of charge, to any person obtaining a copy
     11 * of this software and associated documentation files (the "Software"), to deal
     12 * in the Software without restriction, including without limitation the rights
     13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     14 * copies of the Software, and to permit persons to whom the Software is
     15 * furnished to do so, subject to the following conditions:
     16 *
     17 * The above copyright notice and this permission notice shall be included in
     18 * all copies or substantial portions of the Software.
     19 *
     20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     26 * THE SOFTWARE.
     27 */
     28
     29#include "qemu/osdep.h"
     30#include "qemu/log.h"
     31#include "chardev/char.h"
     32#include "hw/irq.h"
     33#include "migration/vmstate.h"
     34#include "net/can_emu.h"
     35
     36#include "ctucan_core.h"
     37
     38#ifndef DEBUG_CAN
     39#define DEBUG_CAN 0
     40#endif /*DEBUG_CAN*/
     41
     42#define DPRINTF(fmt, ...) \
     43    do { \
     44        if (DEBUG_CAN) { \
     45            qemu_log("[ctucan]: " fmt , ## __VA_ARGS__); \
     46        } \
     47    } while (0)
     48
     49static void ctucan_buff2frame(const uint8_t *buff, qemu_can_frame *frame)
     50{
     51    frame->can_id = 0;
     52    frame->can_dlc = 0;
     53    frame->flags = 0;
     54
     55    if (buff == NULL) {
     56        return;
     57    }
     58    {
     59        union ctu_can_fd_frame_form_w frame_form_w;
     60        union ctu_can_fd_identifier_w identifier_w;
     61        unsigned int ide;
     62        uint32_t w;
     63
     64        w = le32_to_cpu(*(uint32_t *)buff);
     65        frame_form_w = (union ctu_can_fd_frame_form_w)w;
     66        frame->can_dlc = can_dlc2len(frame_form_w.s.dlc);
     67
     68        w = le32_to_cpu(*(uint32_t *)(buff + 4));
     69        identifier_w = (union ctu_can_fd_identifier_w)w;
     70
     71        ide = frame_form_w.s.ide;
     72        if (ide) {
     73            frame->can_id = (identifier_w.s.identifier_base << 18) |
     74                            identifier_w.s.identifier_ext;
     75            frame->can_id |= QEMU_CAN_EFF_FLAG;
     76        } else {
     77            frame->can_id = identifier_w.s.identifier_base;
     78        }
     79
     80        if (frame_form_w.s.esi_rsv) {
     81            frame->flags |= QEMU_CAN_FRMF_ESI;
     82        }
     83
     84        if (frame_form_w.s.rtr) {
     85            frame->can_id |= QEMU_CAN_RTR_FLAG;
     86        }
     87
     88        if (frame_form_w.s.fdf) {   /*CAN FD*/
     89            frame->flags |= QEMU_CAN_FRMF_TYPE_FD;
     90            if (frame_form_w.s.brs) {
     91                frame->flags |= QEMU_CAN_FRMF_BRS;
     92            }
     93        }
     94    }
     95
     96    memcpy(frame->data, buff + 0x10, 0x40);
     97}
     98
     99
    100static int ctucan_frame2buff(const qemu_can_frame *frame, uint8_t *buff)
    101{
    102    unsigned int bytes_cnt = -1;
    103    memset(buff, 0, CTUCAN_MSG_MAX_LEN * sizeof(*buff));
    104
    105    if (frame == NULL) {
    106        return bytes_cnt;
    107    }
    108    {
    109        union ctu_can_fd_frame_form_w frame_form_w;
    110        union ctu_can_fd_identifier_w identifier_w;
    111
    112        frame_form_w.u32 = 0;
    113        identifier_w.u32 = 0;
    114
    115        bytes_cnt = frame->can_dlc;
    116        bytes_cnt = (bytes_cnt + 3) & ~3;
    117        bytes_cnt += 16;
    118        frame_form_w.s.rwcnt = (bytes_cnt >> 2) - 1;
    119
    120        frame_form_w.s.dlc = can_len2dlc(frame->can_dlc);
    121
    122        if (frame->can_id & QEMU_CAN_EFF_FLAG) {
    123            frame_form_w.s.ide = 1;
    124            identifier_w.s.identifier_base =
    125                                    (frame->can_id & 0x1FFC0000) >> 18;
    126            identifier_w.s.identifier_ext = frame->can_id & 0x3FFFF;
    127        } else {
    128            identifier_w.s.identifier_base = frame->can_id & 0x7FF;
    129        }
    130
    131        if (frame->flags & QEMU_CAN_FRMF_ESI) {
    132            frame_form_w.s.esi_rsv = 1;
    133        }
    134
    135        if (frame->can_id & QEMU_CAN_RTR_FLAG) {
    136            frame_form_w.s.rtr = 1;
    137        }
    138
    139        if (frame->flags & QEMU_CAN_FRMF_TYPE_FD) {  /*CAN FD*/
    140           frame_form_w.s.fdf = 1;
    141            if (frame->flags & QEMU_CAN_FRMF_BRS) {
    142                frame_form_w.s.brs = 1;
    143            }
    144        }
    145        *(uint32_t *)buff = cpu_to_le32(frame_form_w.u32);
    146        *(uint32_t *)(buff + 4) = cpu_to_le32(identifier_w.u32);
    147    }
    148
    149    memcpy(buff + 0x10, frame->data, 0x40);
    150
    151    return bytes_cnt;
    152}
    153
    154static void ctucan_update_irq(CtuCanCoreState *s)
    155{
    156    union ctu_can_fd_int_stat int_rq;
    157
    158    int_rq.u32 = 0;
    159
    160    if (s->rx_status_rx_settings.s.rxfrc) {
    161        int_rq.s.rbnei = 1;
    162    }
    163
    164    int_rq.u32 &= ~s->int_mask.u32;
    165    s->int_stat.u32 |= int_rq.u32;
    166    if (s->int_stat.u32 & s->int_ena.u32) {
    167        qemu_irq_raise(s->irq);
    168    } else {
    169        qemu_irq_lower(s->irq);
    170    }
    171}
    172
    173static void ctucan_update_txnf(CtuCanCoreState *s)
    174{
    175    int i;
    176    int txnf;
    177    unsigned int buff_st;
    178
    179    txnf = 0;
    180
    181    for (i = 0; i < CTUCAN_CORE_TXBUF_NUM; i++) {
    182        buff_st = (s->tx_status.u32 >> (i * 4)) & 0xf;
    183        if (buff_st == TXT_ETY) {
    184            txnf = 1;
    185        }
    186    }
    187    s->status.s.txnf = txnf;
    188}
    189
    190void ctucan_hardware_reset(CtuCanCoreState *s)
    191{
    192    DPRINTF("Hardware reset in progress!!!\n");
    193    int i;
    194    unsigned int buff_st;
    195    uint32_t buff_st_mask;
    196
    197    s->tx_status.u32 = 0;
    198    for (i = 0; i < CTUCAN_CORE_TXBUF_NUM; i++) {
    199        buff_st_mask = 0xf << (i * 4);
    200        buff_st = TXT_ETY;
    201        s->tx_status.u32 = (s->tx_status.u32 & ~buff_st_mask) |
    202            (buff_st << (i * 4));
    203    }
    204    s->status.s.idle = 1;
    205
    206    ctucan_update_txnf(s);
    207
    208    s->rx_status_rx_settings.u32 = 0;
    209    s->rx_tail_pos = 0;
    210    s->rx_cnt = 0;
    211    s->rx_frame_rem = 0;
    212
    213    /* Flush RX buffer */
    214    s->rx_tail_pos = 0;
    215    s->rx_cnt = 0;
    216    s->rx_frame_rem = 0;
    217
    218    /* Set on progdokum reset value */
    219    s->mode_settings.u32 = 0;
    220    s->mode_settings.s.fde = 1;
    221
    222    s->int_stat.u32 = 0;
    223    s->int_ena.u32 = 0;
    224    s->int_mask.u32 = 0;
    225
    226    s->rx_status_rx_settings.u32 = 0;
    227    s->rx_status_rx_settings.s.rxe = 0;
    228
    229    s->rx_fr_ctr.u32 = 0;
    230    s->tx_fr_ctr.u32 = 0;
    231
    232    s->yolo_reg.s.yolo_val = 3735928559;
    233
    234    qemu_irq_lower(s->irq);
    235}
    236
    237static void ctucan_send_ready_buffers(CtuCanCoreState *s)
    238{
    239    qemu_can_frame frame;
    240    uint8_t *pf;
    241    int buff2tx_idx;
    242    uint32_t tx_prio_max;
    243
    244    if (!s->mode_settings.s.ena) {
    245        return;
    246    }
    247
    248    do {
    249        union ctu_can_fd_int_stat int_stat;
    250        int i;
    251        buff2tx_idx = -1;
    252        tx_prio_max = 0;
    253
    254        for (i = 0; i < CTUCAN_CORE_TXBUF_NUM; i++) {
    255            uint32_t prio;
    256
    257            if (extract32(s->tx_status.u32, i * 4, 4) != TXT_RDY) {
    258                continue;
    259            }
    260            prio = (s->tx_priority.u32 >> (i * 4)) & 0x7;
    261            if (tx_prio_max < prio) {
    262                tx_prio_max = prio;
    263                buff2tx_idx = i;
    264            }
    265        }
    266        if (buff2tx_idx == -1) {
    267            break;
    268        }
    269        int_stat.u32 = 0;
    270        pf = s->tx_buffer[buff2tx_idx].data;
    271        ctucan_buff2frame(pf, &frame);
    272        s->status.s.idle = 0;
    273        s->status.s.txs = 1;
    274        can_bus_client_send(&s->bus_client, &frame, 1);
    275        s->status.s.idle = 1;
    276        s->status.s.txs = 0;
    277        s->tx_fr_ctr.s.tx_fr_ctr_val++;
    278        int_stat.s.txi = 1;
    279        int_stat.s.txbhci = 1;
    280        s->int_stat.u32 |= int_stat.u32 & ~s->int_mask.u32;
    281        s->tx_status.u32 = deposit32(s->tx_status.u32,
    282                                     buff2tx_idx * 4, 4, TXT_TOK);
    283    } while (1);
    284}
    285
    286#define CTUCAN_CORE_TXBUFF_SPAN \
    287            (CTU_CAN_FD_TXTB2_DATA_1 - CTU_CAN_FD_TXTB1_DATA_1)
    288
    289void ctucan_mem_write(CtuCanCoreState *s, hwaddr addr, uint64_t val,
    290                       unsigned size)
    291{
    292    int              i;
    293
    294    DPRINTF("write 0x%02llx addr 0x%02x\n",
    295            (unsigned long long)val, (unsigned int)addr);
    296
    297    if (addr >= CTUCAN_CORE_MEM_SIZE) {
    298        return;
    299    }
    300
    301    if (addr >= CTU_CAN_FD_TXTB1_DATA_1) {
    302        int buff_num;
    303        addr -= CTU_CAN_FD_TXTB1_DATA_1;
    304        buff_num = addr / CTUCAN_CORE_TXBUFF_SPAN;
    305        addr %= CTUCAN_CORE_TXBUFF_SPAN;
    306        if ((buff_num < CTUCAN_CORE_TXBUF_NUM) &&
    307            ((addr + size) <= sizeof(s->tx_buffer[buff_num].data))) {
    308            stn_le_p(s->tx_buffer[buff_num].data + addr, size, val);
    309        }
    310    } else {
    311        switch (addr & ~3) {
    312        case CTU_CAN_FD_MODE:
    313            s->mode_settings.u32 = (uint32_t)val;
    314            if (s->mode_settings.s.rst) {
    315                ctucan_hardware_reset(s);
    316                s->mode_settings.s.rst = 0;
    317            }
    318            break;
    319        case CTU_CAN_FD_COMMAND:
    320        {
    321            union ctu_can_fd_command command;
    322            command.u32 = (uint32_t)val;
    323            if (command.s.cdo) {
    324                s->status.s.dor = 0;
    325            }
    326            if (command.s.rrb) {
    327                s->rx_tail_pos = 0;
    328                s->rx_cnt = 0;
    329                s->rx_frame_rem = 0;
    330                s->rx_status_rx_settings.s.rxfrc = 0;
    331            }
    332            if (command.s.txfcrst) {
    333                s->tx_fr_ctr.s.tx_fr_ctr_val = 0;
    334            }
    335            if (command.s.rxfcrst) {
    336                s->rx_fr_ctr.s.rx_fr_ctr_val = 0;
    337            }
    338            break;
    339        }
    340        case CTU_CAN_FD_INT_STAT:
    341            s->int_stat.u32 &= ~(uint32_t)val;
    342            break;
    343        case CTU_CAN_FD_INT_ENA_SET:
    344            s->int_ena.u32 |= (uint32_t)val;
    345            break;
    346        case CTU_CAN_FD_INT_ENA_CLR:
    347            s->int_ena.u32 &= ~(uint32_t)val;
    348            break;
    349        case CTU_CAN_FD_INT_MASK_SET:
    350            s->int_mask.u32 |= (uint32_t)val;
    351            break;
    352        case CTU_CAN_FD_INT_MASK_CLR:
    353            s->int_mask.u32 &= ~(uint32_t)val;
    354            break;
    355        case CTU_CAN_FD_TX_COMMAND:
    356            if (s->mode_settings.s.ena) {
    357                union ctu_can_fd_tx_command tx_command;
    358                union ctu_can_fd_tx_command mask;
    359                unsigned int buff_st;
    360                uint32_t buff_st_mask;
    361
    362                tx_command.u32 = (uint32_t)val;
    363                mask.u32 = 0;
    364                mask.s.txb1 = 1;
    365
    366                for (i = 0; i < CTUCAN_CORE_TXBUF_NUM; i++) {
    367                    if (!(tx_command.u32 & (mask.u32 << i))) {
    368                        continue;
    369                    }
    370                    buff_st_mask = 0xf << (i * 4);
    371                    buff_st = (s->tx_status.u32 >> (i * 4)) & 0xf;
    372                    if (tx_command.s.txca) {
    373                        if (buff_st == TXT_RDY) {
    374                            buff_st = TXT_ABT;
    375                        }
    376                    }
    377                    if (tx_command.s.txcr) {
    378                        if ((buff_st == TXT_TOK) || (buff_st == TXT_ERR) ||
    379                            (buff_st == TXT_ABT) || (buff_st == TXT_ETY))
    380                            buff_st = TXT_RDY;
    381                    }
    382                    if (tx_command.s.txce) {
    383                        if ((buff_st == TXT_TOK) || (buff_st == TXT_ERR) ||
    384                            (buff_st == TXT_ABT))
    385                            buff_st = TXT_ETY;
    386                    }
    387                    s->tx_status.u32 = (s->tx_status.u32 & ~buff_st_mask) |
    388                                        (buff_st << (i * 4));
    389                }
    390
    391                ctucan_send_ready_buffers(s);
    392                ctucan_update_txnf(s);
    393            }
    394            break;
    395        case CTU_CAN_FD_TX_PRIORITY:
    396            s->tx_priority.u32 = (uint32_t)val;
    397            break;
    398        }
    399
    400        ctucan_update_irq(s);
    401    }
    402
    403    return;
    404}
    405
    406uint64_t ctucan_mem_read(CtuCanCoreState *s, hwaddr addr, unsigned size)
    407{
    408    uint32_t val = 0;
    409
    410    DPRINTF("read addr 0x%02x ...\n", (unsigned int)addr);
    411
    412    if (addr > CTUCAN_CORE_MEM_SIZE) {
    413        return 0;
    414    }
    415
    416    switch (addr & ~3) {
    417    case CTU_CAN_FD_DEVICE_ID:
    418        {
    419            union ctu_can_fd_device_id_version idver;
    420            idver.u32 = 0;
    421            idver.s.device_id = CTU_CAN_FD_ID;
    422            idver.s.ver_major = 2;
    423            idver.s.ver_minor = 2;
    424            val = idver.u32;
    425        }
    426        break;
    427    case CTU_CAN_FD_MODE:
    428        val = s->mode_settings.u32;
    429        break;
    430    case CTU_CAN_FD_STATUS:
    431        val = s->status.u32;
    432        break;
    433    case CTU_CAN_FD_INT_STAT:
    434        val = s->int_stat.u32;
    435        break;
    436    case CTU_CAN_FD_INT_ENA_SET:
    437    case CTU_CAN_FD_INT_ENA_CLR:
    438        val = s->int_ena.u32;
    439        break;
    440    case CTU_CAN_FD_INT_MASK_SET:
    441    case CTU_CAN_FD_INT_MASK_CLR:
    442        val = s->int_mask.u32;
    443        break;
    444    case CTU_CAN_FD_RX_MEM_INFO:
    445        s->rx_mem_info.u32 = 0;
    446        s->rx_mem_info.s.rx_buff_size = CTUCAN_RCV_BUF_LEN >> 2;
    447        s->rx_mem_info.s.rx_mem_free = (CTUCAN_RCV_BUF_LEN -
    448                                        s->rx_cnt) >> 2;
    449        val = s->rx_mem_info.u32;
    450        break;
    451    case CTU_CAN_FD_RX_POINTERS:
    452    {
    453        uint32_t rx_head_pos = s->rx_tail_pos + s->rx_cnt;
    454        rx_head_pos %= CTUCAN_RCV_BUF_LEN;
    455        s->rx_pointers.s.rx_wpp = rx_head_pos;
    456        s->rx_pointers.s.rx_rpp = s->rx_tail_pos;
    457        val = s->rx_pointers.u32;
    458        break;
    459    }
    460    case CTU_CAN_FD_RX_STATUS:
    461    case CTU_CAN_FD_RX_SETTINGS:
    462        if (!s->rx_status_rx_settings.s.rxfrc) {
    463            s->rx_status_rx_settings.s.rxe = 1;
    464        } else {
    465            s->rx_status_rx_settings.s.rxe = 0;
    466        }
    467        if (((s->rx_cnt + 3) & ~3) == CTUCAN_RCV_BUF_LEN) {
    468            s->rx_status_rx_settings.s.rxf = 1;
    469        } else {
    470            s->rx_status_rx_settings.s.rxf = 0;
    471        }
    472        val = s->rx_status_rx_settings.u32;
    473        break;
    474    case CTU_CAN_FD_RX_DATA:
    475        if (s->rx_cnt) {
    476            memcpy(&val, s->rx_buff + s->rx_tail_pos, 4);
    477            val = le32_to_cpu(val);
    478            if (!s->rx_frame_rem) {
    479                union ctu_can_fd_frame_form_w frame_form_w;
    480                frame_form_w.u32 = val;
    481                s->rx_frame_rem = frame_form_w.s.rwcnt * 4 + 4;
    482            }
    483            s->rx_cnt -= 4;
    484            s->rx_frame_rem -= 4;
    485            if (!s->rx_frame_rem) {
    486                s->rx_status_rx_settings.s.rxfrc--;
    487                if (!s->rx_status_rx_settings.s.rxfrc) {
    488                    s->status.s.rxne = 0;
    489                    s->status.s.idle = 1;
    490                    s->status.s.rxs = 0;
    491                }
    492            }
    493            s->rx_tail_pos = (s->rx_tail_pos + 4) % CTUCAN_RCV_BUF_LEN;
    494        } else {
    495            val = 0;
    496        }
    497        break;
    498    case CTU_CAN_FD_TX_STATUS:
    499        val = s->tx_status.u32;
    500        break;
    501    case CTU_CAN_FD_TX_PRIORITY:
    502        val = s->tx_priority.u32;
    503        break;
    504    case CTU_CAN_FD_RX_FR_CTR:
    505        val = s->rx_fr_ctr.s.rx_fr_ctr_val;
    506        break;
    507    case CTU_CAN_FD_TX_FR_CTR:
    508        val = s->tx_fr_ctr.s.tx_fr_ctr_val;
    509        break;
    510    case CTU_CAN_FD_YOLO_REG:
    511        val = s->yolo_reg.s.yolo_val;
    512        break;
    513    }
    514
    515    val >>= ((addr & 3) << 3);
    516    if (size < 8) {
    517        val &= ((uint64_t)1 << (size << 3)) - 1;
    518    }
    519
    520    return val;
    521}
    522
    523bool ctucan_can_receive(CanBusClientState *client)
    524{
    525    CtuCanCoreState *s = container_of(client, CtuCanCoreState, bus_client);
    526
    527    if (!s->mode_settings.s.ena) {
    528        return false;
    529    }
    530
    531    return true; /* always return true, when operation mode */
    532}
    533
    534ssize_t ctucan_receive(CanBusClientState *client, const qemu_can_frame *frames,
    535                        size_t frames_cnt)
    536{
    537    CtuCanCoreState *s = container_of(client, CtuCanCoreState, bus_client);
    538    static uint8_t rcv[CTUCAN_MSG_MAX_LEN];
    539    int i;
    540    int ret = -1;
    541    const qemu_can_frame *frame = frames;
    542    union ctu_can_fd_int_stat int_stat;
    543    int_stat.u32 = 0;
    544
    545    if (frames_cnt <= 0) {
    546        return 0;
    547    }
    548
    549    ret = ctucan_frame2buff(frame, rcv);
    550
    551    if (s->rx_cnt + ret > CTUCAN_RCV_BUF_LEN) { /* Data overrun. */
    552        s->status.s.dor = 1;
    553        int_stat.s.doi = 1;
    554        s->int_stat.u32 |= int_stat.u32 & ~s->int_mask.u32;
    555        ctucan_update_irq(s);
    556        DPRINTF("Receive FIFO overrun\n");
    557        return ret;
    558    }
    559    s->status.s.idle = 0;
    560    s->status.s.rxs = 1;
    561    int_stat.s.rxi = 1;
    562    if (((s->rx_cnt + 3) & ~3) == CTUCAN_RCV_BUF_LEN) {
    563        int_stat.s.rxfi = 1;
    564    }
    565    s->int_stat.u32 |= int_stat.u32 & ~s->int_mask.u32;
    566    s->rx_fr_ctr.s.rx_fr_ctr_val++;
    567    s->rx_status_rx_settings.s.rxfrc++;
    568    for (i = 0; i < ret; i++) {
    569        s->rx_buff[(s->rx_tail_pos + s->rx_cnt) % CTUCAN_RCV_BUF_LEN] = rcv[i];
    570        s->rx_cnt++;
    571    }
    572    s->status.s.rxne = 1;
    573
    574    ctucan_update_irq(s);
    575
    576    return 1;
    577}
    578
    579static CanBusClientInfo ctucan_bus_client_info = {
    580    .can_receive = ctucan_can_receive,
    581    .receive = ctucan_receive,
    582};
    583
    584
    585int ctucan_connect_to_bus(CtuCanCoreState *s, CanBusState *bus)
    586{
    587    s->bus_client.info = &ctucan_bus_client_info;
    588
    589    if (!bus) {
    590        return -EINVAL;
    591    }
    592
    593    if (can_bus_insert_client(bus, &s->bus_client) < 0) {
    594        return -1;
    595    }
    596
    597    return 0;
    598}
    599
    600void ctucan_disconnect(CtuCanCoreState *s)
    601{
    602    can_bus_remove_client(&s->bus_client);
    603}
    604
    605int ctucan_init(CtuCanCoreState *s, qemu_irq irq)
    606{
    607    s->irq = irq;
    608
    609    qemu_irq_lower(s->irq);
    610
    611    ctucan_hardware_reset(s);
    612
    613    return 0;
    614}
    615
    616const VMStateDescription vmstate_qemu_ctucan_tx_buffer = {
    617    .name = "qemu_ctucan_tx_buffer",
    618    .version_id = 1,
    619    .minimum_version_id = 1,
    620    .minimum_version_id_old = 1,
    621    .fields = (VMStateField[]) {
    622        VMSTATE_UINT8_ARRAY(data, CtuCanCoreMsgBuffer, CTUCAN_CORE_MSG_MAX_LEN),
    623        VMSTATE_END_OF_LIST()
    624    }
    625};
    626
    627static int ctucan_post_load(void *opaque, int version_id)
    628{
    629    CtuCanCoreState *s = opaque;
    630    ctucan_update_irq(s);
    631    return 0;
    632}
    633
    634/* VMState is needed for live migration of QEMU images */
    635const VMStateDescription vmstate_ctucan = {
    636    .name = "ctucan",
    637    .version_id = 1,
    638    .minimum_version_id = 1,
    639    .minimum_version_id_old = 1,
    640    .post_load = ctucan_post_load,
    641    .fields = (VMStateField[]) {
    642        VMSTATE_UINT32(mode_settings.u32, CtuCanCoreState),
    643        VMSTATE_UINT32(status.u32, CtuCanCoreState),
    644        VMSTATE_UINT32(int_stat.u32, CtuCanCoreState),
    645        VMSTATE_UINT32(int_ena.u32, CtuCanCoreState),
    646        VMSTATE_UINT32(int_mask.u32, CtuCanCoreState),
    647        VMSTATE_UINT32(brt.u32, CtuCanCoreState),
    648        VMSTATE_UINT32(brt_fd.u32, CtuCanCoreState),
    649        VMSTATE_UINT32(ewl_erp_fault_state.u32, CtuCanCoreState),
    650        VMSTATE_UINT32(rec_tec.u32, CtuCanCoreState),
    651        VMSTATE_UINT32(err_norm_err_fd.u32, CtuCanCoreState),
    652        VMSTATE_UINT32(ctr_pres.u32, CtuCanCoreState),
    653        VMSTATE_UINT32(filter_a_mask.u32, CtuCanCoreState),
    654        VMSTATE_UINT32(filter_a_val.u32, CtuCanCoreState),
    655        VMSTATE_UINT32(filter_b_mask.u32, CtuCanCoreState),
    656        VMSTATE_UINT32(filter_b_val.u32, CtuCanCoreState),
    657        VMSTATE_UINT32(filter_c_mask.u32, CtuCanCoreState),
    658        VMSTATE_UINT32(filter_c_val.u32, CtuCanCoreState),
    659        VMSTATE_UINT32(filter_ran_low.u32, CtuCanCoreState),
    660        VMSTATE_UINT32(filter_ran_high.u32, CtuCanCoreState),
    661        VMSTATE_UINT32(filter_control_filter_status.u32, CtuCanCoreState),
    662        VMSTATE_UINT32(rx_mem_info.u32, CtuCanCoreState),
    663        VMSTATE_UINT32(rx_pointers.u32, CtuCanCoreState),
    664        VMSTATE_UINT32(rx_status_rx_settings.u32, CtuCanCoreState),
    665        VMSTATE_UINT32(tx_status.u32, CtuCanCoreState),
    666        VMSTATE_UINT32(tx_priority.u32, CtuCanCoreState),
    667        VMSTATE_UINT32(err_capt_alc.u32, CtuCanCoreState),
    668        VMSTATE_UINT32(trv_delay_ssp_cfg.u32, CtuCanCoreState),
    669        VMSTATE_UINT32(rx_fr_ctr.u32, CtuCanCoreState),
    670        VMSTATE_UINT32(tx_fr_ctr.u32, CtuCanCoreState),
    671        VMSTATE_UINT32(debug_register.u32, CtuCanCoreState),
    672        VMSTATE_UINT32(yolo_reg.u32, CtuCanCoreState),
    673        VMSTATE_UINT32(timestamp_low.u32, CtuCanCoreState),
    674        VMSTATE_UINT32(timestamp_high.u32, CtuCanCoreState),
    675
    676        VMSTATE_STRUCT_ARRAY(tx_buffer, CtuCanCoreState,
    677                CTUCAN_CORE_TXBUF_NUM, 0, vmstate_qemu_ctucan_tx_buffer,
    678                CtuCanCoreMsgBuffer),
    679
    680        VMSTATE_BUFFER(rx_buff, CtuCanCoreState),
    681        VMSTATE_UINT32(rx_tail_pos, CtuCanCoreState),
    682        VMSTATE_UINT32(rx_cnt, CtuCanCoreState),
    683        VMSTATE_UINT32(rx_frame_rem, CtuCanCoreState),
    684
    685        VMSTATE_END_OF_LIST()
    686    }
    687};