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

pm_smbus.c (14527B)


      1/*
      2 * PC SMBus implementation
      3 * splitted from acpi.c
      4 *
      5 * Copyright (c) 2006 Fabrice Bellard
      6 *
      7 * This library is free software; you can redistribute it and/or
      8 * modify it under the terms of the GNU Lesser General Public
      9 * License version 2.1 as published by the Free Software Foundation.
     10 *
     11 * This library is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14 * Lesser General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU Lesser General Public
     17 * License along with this library; if not, see
     18 * <http://www.gnu.org/licenses/>.
     19 */
     20
     21#include "qemu/osdep.h"
     22#include "hw/boards.h"
     23#include "hw/i2c/pm_smbus.h"
     24#include "hw/i2c/smbus_master.h"
     25#include "migration/vmstate.h"
     26
     27#define SMBHSTSTS       0x00
     28#define SMBHSTCNT       0x02
     29#define SMBHSTCMD       0x03
     30#define SMBHSTADD       0x04
     31#define SMBHSTDAT0      0x05
     32#define SMBHSTDAT1      0x06
     33#define SMBBLKDAT       0x07
     34#define SMBAUXCTL       0x0d
     35
     36#define STS_HOST_BUSY   (1 << 0)
     37#define STS_INTR        (1 << 1)
     38#define STS_DEV_ERR     (1 << 2)
     39#define STS_BUS_ERR     (1 << 3)
     40#define STS_FAILED      (1 << 4)
     41#define STS_SMBALERT    (1 << 5)
     42#define STS_INUSE_STS   (1 << 6)
     43#define STS_BYTE_DONE   (1 << 7)
     44/* Signs of successfully transaction end :
     45*  ByteDoneStatus = 1 (STS_BYTE_DONE) and INTR = 1 (STS_INTR )
     46*/
     47
     48#define CTL_INTREN      (1 << 0)
     49#define CTL_KILL        (1 << 1)
     50#define CTL_LAST_BYTE   (1 << 5)
     51#define CTL_START       (1 << 6)
     52#define CTL_PEC_EN      (1 << 7)
     53#define CTL_RETURN_MASK 0x1f
     54
     55#define PROT_QUICK          0
     56#define PROT_BYTE           1
     57#define PROT_BYTE_DATA      2
     58#define PROT_WORD_DATA      3
     59#define PROT_PROC_CALL      4
     60#define PROT_BLOCK_DATA     5
     61#define PROT_I2C_BLOCK_READ 6
     62
     63#define AUX_PEC       (1 << 0)
     64#define AUX_BLK       (1 << 1)
     65#define AUX_MASK      0x3
     66
     67/*#define DEBUG*/
     68
     69#ifdef DEBUG
     70# define SMBUS_DPRINTF(format, ...)     printf(format, ## __VA_ARGS__)
     71#else
     72# define SMBUS_DPRINTF(format, ...)     do { } while (0)
     73#endif
     74
     75
     76static void smb_transaction(PMSMBus *s)
     77{
     78    uint8_t prot = (s->smb_ctl >> 2) & 0x07;
     79    uint8_t read = s->smb_addr & 0x01;
     80    uint8_t cmd = s->smb_cmd;
     81    uint8_t addr = s->smb_addr >> 1;
     82    I2CBus *bus = s->smbus;
     83    int ret;
     84
     85    SMBUS_DPRINTF("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot);
     86    /* Transaction isn't exec if STS_DEV_ERR bit set */
     87    if ((s->smb_stat & STS_DEV_ERR) != 0)  {
     88        goto error;
     89    }
     90
     91    switch(prot) {
     92    case PROT_QUICK:
     93        ret = smbus_quick_command(bus, addr, read);
     94        goto done;
     95    case PROT_BYTE:
     96        if (read) {
     97            ret = smbus_receive_byte(bus, addr);
     98            goto data8;
     99        } else {
    100            ret = smbus_send_byte(bus, addr, cmd);
    101            goto done;
    102        }
    103    case PROT_BYTE_DATA:
    104        if (read) {
    105            ret = smbus_read_byte(bus, addr, cmd);
    106            goto data8;
    107        } else {
    108            ret = smbus_write_byte(bus, addr, cmd, s->smb_data0);
    109            goto done;
    110        }
    111        break;
    112    case PROT_WORD_DATA:
    113        if (read) {
    114            ret = smbus_read_word(bus, addr, cmd);
    115            goto data16;
    116        } else {
    117            ret = smbus_write_word(bus, addr, cmd,
    118                                   (s->smb_data1 << 8) | s->smb_data0);
    119            goto done;
    120        }
    121        break;
    122    case PROT_I2C_BLOCK_READ:
    123        /* According to the Linux i2c-i801 driver:
    124         *   NB: page 240 of ICH5 datasheet shows that the R/#W
    125         *   bit should be cleared here, even when reading.
    126         *   However if SPD Write Disable is set (Lynx Point and later),
    127         *   the read will fail if we don't set the R/#W bit.
    128         * So at least Linux may or may not set the read bit here.
    129         * So just ignore the read bit for this command.
    130         */
    131        if (i2c_start_send(bus, addr)) {
    132            goto error;
    133        }
    134        ret = i2c_send(bus, s->smb_data1);
    135        if (ret) {
    136            goto error;
    137        }
    138        if (i2c_start_recv(bus, addr)) {
    139            goto error;
    140        }
    141        s->in_i2c_block_read = true;
    142        s->smb_blkdata = i2c_recv(s->smbus);
    143        s->op_done = false;
    144        s->smb_stat |= STS_HOST_BUSY | STS_BYTE_DONE;
    145        goto out;
    146
    147    case PROT_BLOCK_DATA:
    148        if (read) {
    149            ret = smbus_read_block(bus, addr, cmd, s->smb_data,
    150                                   sizeof(s->smb_data), !s->i2c_enable,
    151                                   !s->i2c_enable);
    152            if (ret < 0) {
    153                goto error;
    154            }
    155            s->smb_index = 0;
    156            s->op_done = false;
    157            if (s->smb_auxctl & AUX_BLK) {
    158                s->smb_stat |= STS_INTR;
    159            } else {
    160                s->smb_blkdata = s->smb_data[0];
    161                s->smb_stat |= STS_HOST_BUSY | STS_BYTE_DONE;
    162            }
    163            s->smb_data0 = ret;
    164            goto out;
    165        } else {
    166            if (s->smb_auxctl & AUX_BLK) {
    167                if (s->smb_index != s->smb_data0) {
    168                    s->smb_index = 0;
    169                    goto error;
    170                }
    171                /* Data is already all written to the queue, just do
    172                   the operation. */
    173                s->smb_index = 0;
    174                ret = smbus_write_block(bus, addr, cmd, s->smb_data,
    175                                        s->smb_data0, !s->i2c_enable);
    176                if (ret < 0) {
    177                    goto error;
    178                }
    179                s->op_done = true;
    180                s->smb_stat |= STS_INTR;
    181                s->smb_stat &= ~STS_HOST_BUSY;
    182            } else {
    183                s->op_done = false;
    184                s->smb_stat |= STS_HOST_BUSY | STS_BYTE_DONE;
    185                s->smb_data[0] = s->smb_blkdata;
    186                s->smb_index = 0;
    187            }
    188            goto out;
    189        }
    190        break;
    191    default:
    192        goto error;
    193    }
    194    abort();
    195
    196data16:
    197    if (ret < 0) {
    198        goto error;
    199    }
    200    s->smb_data1 = ret >> 8;
    201data8:
    202    if (ret < 0) {
    203        goto error;
    204    }
    205    s->smb_data0 = ret;
    206done:
    207    if (ret < 0) {
    208        goto error;
    209    }
    210    s->smb_stat |= STS_INTR;
    211out:
    212    return;
    213
    214error:
    215    s->smb_stat |= STS_DEV_ERR;
    216    return;
    217}
    218
    219static void smb_transaction_start(PMSMBus *s)
    220{
    221    if (s->smb_ctl & CTL_INTREN) {
    222        smb_transaction(s);
    223        s->start_transaction_on_status_read = false;
    224    } else {
    225        /* Do not execute immediately the command; it will be
    226         * executed when guest will read SMB_STAT register.  This
    227         * is to work around a bug in AMIBIOS (that is working
    228         * around another bug in some specific hardware) where
    229         * it waits for STS_HOST_BUSY to be set before waiting
    230         * checking for status.  If STS_HOST_BUSY doesn't get
    231         * set, it gets stuck. */
    232        s->smb_stat |= STS_HOST_BUSY;
    233        s->start_transaction_on_status_read = true;
    234    }
    235}
    236
    237static bool
    238smb_irq_value(PMSMBus *s)
    239{
    240    return ((s->smb_stat & ~STS_HOST_BUSY) != 0) && (s->smb_ctl & CTL_INTREN);
    241}
    242
    243static bool
    244smb_byte_by_byte(PMSMBus *s)
    245{
    246    if (s->op_done) {
    247        return false;
    248    }
    249    if (s->in_i2c_block_read) {
    250        return true;
    251    }
    252    return !(s->smb_auxctl & AUX_BLK);
    253}
    254
    255static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val,
    256                              unsigned width)
    257{
    258    PMSMBus *s = opaque;
    259    uint8_t clear_byte_done;
    260
    261    SMBUS_DPRINTF("SMB writeb port=0x%04" HWADDR_PRIx
    262                  " val=0x%02" PRIx64 "\n", addr, val);
    263    switch(addr) {
    264    case SMBHSTSTS:
    265        clear_byte_done = s->smb_stat & val & STS_BYTE_DONE;
    266        s->smb_stat &= ~(val & ~STS_HOST_BUSY);
    267        if (clear_byte_done && smb_byte_by_byte(s)) {
    268            uint8_t read = s->smb_addr & 0x01;
    269
    270            if (s->in_i2c_block_read) {
    271                /* See comment below PROT_I2C_BLOCK_READ above. */
    272                read = 1;
    273            }
    274
    275            s->smb_index++;
    276            if (s->smb_index >= PM_SMBUS_MAX_MSG_SIZE) {
    277                s->smb_index = 0;
    278            }
    279            if (!read && s->smb_index == s->smb_data0) {
    280                uint8_t prot = (s->smb_ctl >> 2) & 0x07;
    281                uint8_t cmd = s->smb_cmd;
    282                uint8_t addr = s->smb_addr >> 1;
    283                int ret;
    284
    285                if (prot == PROT_I2C_BLOCK_READ) {
    286                    s->smb_stat |= STS_DEV_ERR;
    287                    goto out;
    288                }
    289
    290                ret = smbus_write_block(s->smbus, addr, cmd, s->smb_data,
    291                                        s->smb_data0, !s->i2c_enable);
    292                if (ret < 0) {
    293                    s->smb_stat |= STS_DEV_ERR;
    294                    goto out;
    295                }
    296                s->op_done = true;
    297                s->smb_stat |= STS_INTR;
    298                s->smb_stat &= ~STS_HOST_BUSY;
    299            } else if (!read) {
    300                s->smb_data[s->smb_index] = s->smb_blkdata;
    301                s->smb_stat |= STS_BYTE_DONE;
    302            } else if (s->smb_ctl & CTL_LAST_BYTE) {
    303                s->op_done = true;
    304                if (s->in_i2c_block_read) {
    305                    s->in_i2c_block_read = false;
    306                    s->smb_blkdata = i2c_recv(s->smbus);
    307                    i2c_nack(s->smbus);
    308                    i2c_end_transfer(s->smbus);
    309                } else {
    310                    s->smb_blkdata = s->smb_data[s->smb_index];
    311                }
    312                s->smb_index = 0;
    313                s->smb_stat |= STS_INTR;
    314                s->smb_stat &= ~STS_HOST_BUSY;
    315            } else {
    316                if (s->in_i2c_block_read) {
    317                    s->smb_blkdata = i2c_recv(s->smbus);
    318                } else {
    319                    s->smb_blkdata = s->smb_data[s->smb_index];
    320                }
    321                s->smb_stat |= STS_BYTE_DONE;
    322            }
    323        }
    324        break;
    325    case SMBHSTCNT:
    326        s->smb_ctl = val & ~CTL_START; /* CTL_START always reads 0 */
    327        if (val & CTL_START) {
    328            if (!s->op_done) {
    329                s->smb_index = 0;
    330                s->op_done = true;
    331                if (s->in_i2c_block_read) {
    332                    s->in_i2c_block_read = false;
    333                    i2c_end_transfer(s->smbus);
    334                }
    335            }
    336            smb_transaction_start(s);
    337        }
    338        if (s->smb_ctl & CTL_KILL) {
    339            s->op_done = true;
    340            s->smb_index = 0;
    341            s->smb_stat |= STS_FAILED;
    342            s->smb_stat &= ~STS_HOST_BUSY;
    343        }
    344        break;
    345    case SMBHSTCMD:
    346        s->smb_cmd = val;
    347        break;
    348    case SMBHSTADD:
    349        s->smb_addr = val;
    350        break;
    351    case SMBHSTDAT0:
    352        s->smb_data0 = val;
    353        break;
    354    case SMBHSTDAT1:
    355        s->smb_data1 = val;
    356        break;
    357    case SMBBLKDAT:
    358        if (s->smb_index >= PM_SMBUS_MAX_MSG_SIZE) {
    359            s->smb_index = 0;
    360        }
    361        if (s->smb_auxctl & AUX_BLK) {
    362            s->smb_data[s->smb_index++] = val;
    363        } else {
    364            s->smb_blkdata = val;
    365        }
    366        break;
    367    case SMBAUXCTL:
    368        s->smb_auxctl = val & AUX_MASK;
    369        break;
    370    default:
    371        break;
    372    }
    373
    374 out:
    375    if (s->set_irq) {
    376        s->set_irq(s, smb_irq_value(s));
    377    }
    378}
    379
    380static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width)
    381{
    382    PMSMBus *s = opaque;
    383    uint32_t val;
    384
    385    switch(addr) {
    386    case SMBHSTSTS:
    387        val = s->smb_stat;
    388        if (s->start_transaction_on_status_read) {
    389            /* execute command now */
    390            s->start_transaction_on_status_read = false;
    391            s->smb_stat &= ~STS_HOST_BUSY;
    392            smb_transaction(s);
    393        }
    394        break;
    395    case SMBHSTCNT:
    396        val = s->smb_ctl & CTL_RETURN_MASK;
    397        break;
    398    case SMBHSTCMD:
    399        val = s->smb_cmd;
    400        break;
    401    case SMBHSTADD:
    402        val = s->smb_addr;
    403        break;
    404    case SMBHSTDAT0:
    405        val = s->smb_data0;
    406        break;
    407    case SMBHSTDAT1:
    408        val = s->smb_data1;
    409        break;
    410    case SMBBLKDAT:
    411        if (s->smb_auxctl & AUX_BLK && !s->in_i2c_block_read) {
    412            if (s->smb_index >= PM_SMBUS_MAX_MSG_SIZE) {
    413                s->smb_index = 0;
    414            }
    415            val = s->smb_data[s->smb_index++];
    416            if (!s->op_done && s->smb_index == s->smb_data0) {
    417                s->op_done = true;
    418                s->smb_index = 0;
    419                s->smb_stat &= ~STS_HOST_BUSY;
    420            }
    421        } else {
    422            val = s->smb_blkdata;
    423        }
    424        break;
    425    case SMBAUXCTL:
    426        val = s->smb_auxctl;
    427        break;
    428    default:
    429        val = 0;
    430        break;
    431    }
    432    SMBUS_DPRINTF("SMB readb port=0x%04" HWADDR_PRIx " val=0x%02x\n",
    433                  addr, val);
    434
    435    if (s->set_irq) {
    436        s->set_irq(s, smb_irq_value(s));
    437    }
    438
    439    return val;
    440}
    441
    442static void pm_smbus_reset(PMSMBus *s)
    443{
    444    s->op_done = true;
    445    s->smb_index = 0;
    446    s->smb_stat = 0;
    447}
    448
    449static const MemoryRegionOps pm_smbus_ops = {
    450    .read = smb_ioport_readb,
    451    .write = smb_ioport_writeb,
    452    .valid.min_access_size = 1,
    453    .valid.max_access_size = 1,
    454    .endianness = DEVICE_LITTLE_ENDIAN,
    455};
    456
    457bool pm_smbus_vmstate_needed(void)
    458{
    459    MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
    460
    461    return !mc->smbus_no_migration_support;
    462}
    463
    464const VMStateDescription pmsmb_vmstate = {
    465    .name = "pmsmb",
    466    .version_id = 1,
    467    .minimum_version_id = 1,
    468    .fields = (VMStateField[]) {
    469        VMSTATE_UINT8(smb_stat, PMSMBus),
    470        VMSTATE_UINT8(smb_ctl, PMSMBus),
    471        VMSTATE_UINT8(smb_cmd, PMSMBus),
    472        VMSTATE_UINT8(smb_addr, PMSMBus),
    473        VMSTATE_UINT8(smb_data0, PMSMBus),
    474        VMSTATE_UINT8(smb_data1, PMSMBus),
    475        VMSTATE_UINT32(smb_index, PMSMBus),
    476        VMSTATE_UINT8_ARRAY(smb_data, PMSMBus, PM_SMBUS_MAX_MSG_SIZE),
    477        VMSTATE_UINT8(smb_auxctl, PMSMBus),
    478        VMSTATE_UINT8(smb_blkdata, PMSMBus),
    479        VMSTATE_BOOL(i2c_enable, PMSMBus),
    480        VMSTATE_BOOL(op_done, PMSMBus),
    481        VMSTATE_BOOL(in_i2c_block_read, PMSMBus),
    482        VMSTATE_BOOL(start_transaction_on_status_read, PMSMBus),
    483        VMSTATE_END_OF_LIST()
    484    }
    485};
    486
    487void pm_smbus_init(DeviceState *parent, PMSMBus *smb, bool force_aux_blk)
    488{
    489    smb->op_done = true;
    490    smb->reset = pm_smbus_reset;
    491    smb->smbus = i2c_init_bus(parent, "i2c");
    492    if (force_aux_blk) {
    493        smb->smb_auxctl |= AUX_BLK;
    494    }
    495    memory_region_init_io(&smb->io, OBJECT(parent), &pm_smbus_ops, smb,
    496                          "pm-smbus", 64);
    497}