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

fw_cfg.c (4139B)


      1/*
      2 * libqos fw_cfg support
      3 *
      4 * Copyright IBM, Corp. 2012-2013
      5 * Copyright (C) 2013 Red Hat Inc.
      6 *
      7 * Authors:
      8 *  Anthony Liguori   <aliguori@us.ibm.com>
      9 *  Markus Armbruster <armbru@redhat.com>
     10 *
     11 * This work is licensed under the terms of the GNU GPL, version 2 or later.
     12 * See the COPYING file in the top-level directory.
     13 */
     14
     15#include "qemu/osdep.h"
     16#include "fw_cfg.h"
     17#include "libqtest.h"
     18#include "qemu/bswap.h"
     19#include "hw/nvram/fw_cfg.h"
     20
     21void qfw_cfg_select(QFWCFG *fw_cfg, uint16_t key)
     22{
     23    fw_cfg->select(fw_cfg, key);
     24}
     25
     26void qfw_cfg_read_data(QFWCFG *fw_cfg, void *data, size_t len)
     27{
     28    fw_cfg->read(fw_cfg, data, len);
     29}
     30
     31void qfw_cfg_get(QFWCFG *fw_cfg, uint16_t key, void *data, size_t len)
     32{
     33    qfw_cfg_select(fw_cfg, key);
     34    qfw_cfg_read_data(fw_cfg, data, len);
     35}
     36
     37uint16_t qfw_cfg_get_u16(QFWCFG *fw_cfg, uint16_t key)
     38{
     39    uint16_t value;
     40    qfw_cfg_get(fw_cfg, key, &value, sizeof(value));
     41    return le16_to_cpu(value);
     42}
     43
     44uint32_t qfw_cfg_get_u32(QFWCFG *fw_cfg, uint16_t key)
     45{
     46    uint32_t value;
     47    qfw_cfg_get(fw_cfg, key, &value, sizeof(value));
     48    return le32_to_cpu(value);
     49}
     50
     51uint64_t qfw_cfg_get_u64(QFWCFG *fw_cfg, uint16_t key)
     52{
     53    uint64_t value;
     54    qfw_cfg_get(fw_cfg, key, &value, sizeof(value));
     55    return le64_to_cpu(value);
     56}
     57
     58static void mm_fw_cfg_select(QFWCFG *fw_cfg, uint16_t key)
     59{
     60    qtest_writew(fw_cfg->qts, fw_cfg->base, key);
     61}
     62
     63/*
     64 * The caller need check the return value. When the return value is
     65 * nonzero, it means that some bytes have been transferred.
     66 *
     67 * If the fw_cfg file in question is smaller than the allocated & passed-in
     68 * buffer, then the buffer has been populated only in part.
     69 *
     70 * If the fw_cfg file in question is larger than the passed-in
     71 * buffer, then the return value explains how much room would have been
     72 * necessary in total. And, while the caller's buffer has been fully
     73 * populated, it has received only a starting slice of the fw_cfg file.
     74 */
     75size_t qfw_cfg_get_file(QFWCFG *fw_cfg, const char *filename,
     76                      void *data, size_t buflen)
     77{
     78    uint32_t count;
     79    uint32_t i;
     80    unsigned char *filesbuf = NULL;
     81    size_t dsize;
     82    FWCfgFile *pdir_entry;
     83    size_t filesize = 0;
     84
     85    qfw_cfg_get(fw_cfg, FW_CFG_FILE_DIR, &count, sizeof(count));
     86    count = be32_to_cpu(count);
     87    dsize = sizeof(uint32_t) + count * sizeof(struct fw_cfg_file);
     88    filesbuf = g_malloc(dsize);
     89    qfw_cfg_get(fw_cfg, FW_CFG_FILE_DIR, filesbuf, dsize);
     90    pdir_entry = (FWCfgFile *)(filesbuf + sizeof(uint32_t));
     91    for (i = 0; i < count; ++i, ++pdir_entry) {
     92        if (!strcmp(pdir_entry->name, filename)) {
     93            uint32_t len = be32_to_cpu(pdir_entry->size);
     94            uint16_t sel = be16_to_cpu(pdir_entry->select);
     95            filesize = len;
     96            if (len > buflen) {
     97                len = buflen;
     98            }
     99            qfw_cfg_get(fw_cfg, sel, data, len);
    100            break;
    101        }
    102    }
    103    g_free(filesbuf);
    104    return filesize;
    105}
    106
    107static void mm_fw_cfg_read(QFWCFG *fw_cfg, void *data, size_t len)
    108{
    109    uint8_t *ptr = data;
    110    int i;
    111
    112    for (i = 0; i < len; i++) {
    113        ptr[i] = qtest_readb(fw_cfg->qts, fw_cfg->base + 2);
    114    }
    115}
    116
    117QFWCFG *mm_fw_cfg_init(QTestState *qts, uint64_t base)
    118{
    119    QFWCFG *fw_cfg = g_malloc0(sizeof(*fw_cfg));
    120
    121    fw_cfg->base = base;
    122    fw_cfg->qts = qts;
    123    fw_cfg->select = mm_fw_cfg_select;
    124    fw_cfg->read = mm_fw_cfg_read;
    125
    126    return fw_cfg;
    127}
    128
    129void mm_fw_cfg_uninit(QFWCFG *fw_cfg)
    130{
    131    g_free(fw_cfg);
    132}
    133
    134static void io_fw_cfg_select(QFWCFG *fw_cfg, uint16_t key)
    135{
    136    qtest_outw(fw_cfg->qts, fw_cfg->base, key);
    137}
    138
    139static void io_fw_cfg_read(QFWCFG *fw_cfg, void *data, size_t len)
    140{
    141    uint8_t *ptr = data;
    142    int i;
    143
    144    for (i = 0; i < len; i++) {
    145        ptr[i] = qtest_inb(fw_cfg->qts, fw_cfg->base + 1);
    146    }
    147}
    148
    149QFWCFG *io_fw_cfg_init(QTestState *qts, uint16_t base)
    150{
    151    QFWCFG *fw_cfg = g_malloc0(sizeof(*fw_cfg));
    152
    153    fw_cfg->base = base;
    154    fw_cfg->qts = qts;
    155    fw_cfg->select = io_fw_cfg_select;
    156    fw_cfg->read = io_fw_cfg_read;
    157
    158    return fw_cfg;
    159}
    160
    161void io_fw_cfg_uninit(QFWCFG *fw_cfg)
    162{
    163    g_free(fw_cfg);
    164}