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

char-parallel.c (8958B)


      1/*
      2 * QEMU System Emulator
      3 *
      4 * Copyright (c) 2003-2008 Fabrice Bellard
      5 *
      6 * Permission is hereby granted, free of charge, to any person obtaining a copy
      7 * of this software and associated documentation files (the "Software"), to deal
      8 * in the Software without restriction, including without limitation the rights
      9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10 * copies of the Software, and to permit persons to whom the Software is
     11 * furnished to do so, subject to the following conditions:
     12 *
     13 * The above copyright notice and this permission notice shall be included in
     14 * all copies or substantial portions of the Software.
     15 *
     16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     22 * THE SOFTWARE.
     23 */
     24
     25#include "qemu/osdep.h"
     26#include "chardev/char.h"
     27#include "qapi/error.h"
     28#include "qemu/module.h"
     29#include "qemu/option.h"
     30#include <sys/ioctl.h>
     31
     32#ifdef CONFIG_BSD
     33#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
     34#include <dev/ppbus/ppi.h>
     35#include <dev/ppbus/ppbconf.h>
     36#elif defined(__DragonFly__)
     37#include <dev/misc/ppi/ppi.h>
     38#include <bus/ppbus/ppbconf.h>
     39#endif
     40#else
     41#ifdef __linux__
     42#include <linux/ppdev.h>
     43#include <linux/parport.h>
     44#endif
     45#endif
     46
     47#include "chardev/char-fd.h"
     48#include "chardev/char-parallel.h"
     49
     50#if defined(__linux__)
     51
     52typedef struct {
     53    Chardev parent;
     54    int fd;
     55    int mode;
     56} ParallelChardev;
     57
     58#define PARALLEL_CHARDEV(obj) \
     59    OBJECT_CHECK(ParallelChardev, (obj), TYPE_CHARDEV_PARALLEL)
     60
     61static int pp_hw_mode(ParallelChardev *s, uint16_t mode)
     62{
     63    if (s->mode != mode) {
     64        int m = mode;
     65        if (ioctl(s->fd, PPSETMODE, &m) < 0) {
     66            return 0;
     67        }
     68        s->mode = mode;
     69    }
     70    return 1;
     71}
     72
     73static int pp_ioctl(Chardev *chr, int cmd, void *arg)
     74{
     75    ParallelChardev *drv = PARALLEL_CHARDEV(chr);
     76    int fd = drv->fd;
     77    uint8_t b;
     78
     79    switch (cmd) {
     80    case CHR_IOCTL_PP_READ_DATA:
     81        if (ioctl(fd, PPRDATA, &b) < 0) {
     82            return -ENOTSUP;
     83        }
     84        *(uint8_t *)arg = b;
     85        break;
     86    case CHR_IOCTL_PP_WRITE_DATA:
     87        b = *(uint8_t *)arg;
     88        if (ioctl(fd, PPWDATA, &b) < 0) {
     89            return -ENOTSUP;
     90        }
     91        break;
     92    case CHR_IOCTL_PP_READ_CONTROL:
     93        if (ioctl(fd, PPRCONTROL, &b) < 0) {
     94            return -ENOTSUP;
     95        }
     96        /* Linux gives only the lowest bits, and no way to know data
     97           direction! For better compatibility set the fixed upper
     98           bits. */
     99        *(uint8_t *)arg = b | 0xc0;
    100        break;
    101    case CHR_IOCTL_PP_WRITE_CONTROL:
    102        b = *(uint8_t *)arg;
    103        if (ioctl(fd, PPWCONTROL, &b) < 0) {
    104            return -ENOTSUP;
    105        }
    106        break;
    107    case CHR_IOCTL_PP_READ_STATUS:
    108        if (ioctl(fd, PPRSTATUS, &b) < 0) {
    109            return -ENOTSUP;
    110        }
    111        *(uint8_t *)arg = b;
    112        break;
    113    case CHR_IOCTL_PP_DATA_DIR:
    114        if (ioctl(fd, PPDATADIR, (int *)arg) < 0) {
    115            return -ENOTSUP;
    116        }
    117        break;
    118    case CHR_IOCTL_PP_EPP_READ_ADDR:
    119        if (pp_hw_mode(drv, IEEE1284_MODE_EPP | IEEE1284_ADDR)) {
    120            struct ParallelIOArg *parg = arg;
    121            int n = read(fd, parg->buffer, parg->count);
    122            if (n != parg->count) {
    123                return -EIO;
    124            }
    125        }
    126        break;
    127    case CHR_IOCTL_PP_EPP_READ:
    128        if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) {
    129            struct ParallelIOArg *parg = arg;
    130            int n = read(fd, parg->buffer, parg->count);
    131            if (n != parg->count) {
    132                return -EIO;
    133            }
    134        }
    135        break;
    136    case CHR_IOCTL_PP_EPP_WRITE_ADDR:
    137        if (pp_hw_mode(drv, IEEE1284_MODE_EPP | IEEE1284_ADDR)) {
    138            struct ParallelIOArg *parg = arg;
    139            int n = write(fd, parg->buffer, parg->count);
    140            if (n != parg->count) {
    141                return -EIO;
    142            }
    143        }
    144        break;
    145    case CHR_IOCTL_PP_EPP_WRITE:
    146        if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) {
    147            struct ParallelIOArg *parg = arg;
    148            int n = write(fd, parg->buffer, parg->count);
    149            if (n != parg->count) {
    150                return -EIO;
    151            }
    152        }
    153        break;
    154    default:
    155        return -ENOTSUP;
    156    }
    157    return 0;
    158}
    159
    160static void qemu_chr_open_pp_fd(Chardev *chr,
    161                                int fd,
    162                                bool *be_opened,
    163                                Error **errp)
    164{
    165    ParallelChardev *drv = PARALLEL_CHARDEV(chr);
    166
    167    if (ioctl(fd, PPCLAIM) < 0) {
    168        error_setg_errno(errp, errno, "not a parallel port");
    169        close(fd);
    170        return;
    171    }
    172
    173    drv->fd = fd;
    174    drv->mode = IEEE1284_MODE_COMPAT;
    175}
    176#endif /* __linux__ */
    177
    178#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
    179
    180typedef struct {
    181    Chardev parent;
    182    int fd;
    183} ParallelChardev;
    184
    185#define PARALLEL_CHARDEV(obj)                                   \
    186    OBJECT_CHECK(ParallelChardev, (obj), TYPE_CHARDEV_PARALLEL)
    187
    188static int pp_ioctl(Chardev *chr, int cmd, void *arg)
    189{
    190    ParallelChardev *drv = PARALLEL_CHARDEV(chr);
    191    uint8_t b;
    192
    193    switch (cmd) {
    194    case CHR_IOCTL_PP_READ_DATA:
    195        if (ioctl(drv->fd, PPIGDATA, &b) < 0) {
    196            return -ENOTSUP;
    197        }
    198        *(uint8_t *)arg = b;
    199        break;
    200    case CHR_IOCTL_PP_WRITE_DATA:
    201        b = *(uint8_t *)arg;
    202        if (ioctl(drv->fd, PPISDATA, &b) < 0) {
    203            return -ENOTSUP;
    204        }
    205        break;
    206    case CHR_IOCTL_PP_READ_CONTROL:
    207        if (ioctl(drv->fd, PPIGCTRL, &b) < 0) {
    208            return -ENOTSUP;
    209        }
    210        *(uint8_t *)arg = b;
    211        break;
    212    case CHR_IOCTL_PP_WRITE_CONTROL:
    213        b = *(uint8_t *)arg;
    214        if (ioctl(drv->fd, PPISCTRL, &b) < 0) {
    215            return -ENOTSUP;
    216        }
    217        break;
    218    case CHR_IOCTL_PP_READ_STATUS:
    219        if (ioctl(drv->fd, PPIGSTATUS, &b) < 0) {
    220            return -ENOTSUP;
    221        }
    222        *(uint8_t *)arg = b;
    223        break;
    224    default:
    225        return -ENOTSUP;
    226    }
    227    return 0;
    228}
    229
    230static void qemu_chr_open_pp_fd(Chardev *chr,
    231                                int fd,
    232                                bool *be_opened,
    233                                Error **errp)
    234{
    235    ParallelChardev *drv = PARALLEL_CHARDEV(chr);
    236    drv->fd = fd;
    237    *be_opened = false;
    238}
    239#endif
    240
    241#ifdef HAVE_CHARDEV_PARPORT
    242static void qmp_chardev_open_parallel(Chardev *chr,
    243                                      ChardevBackend *backend,
    244                                      bool *be_opened,
    245                                      Error **errp)
    246{
    247    ChardevHostdev *parallel = backend->u.parallel.data;
    248    int fd;
    249
    250    fd = qmp_chardev_open_file_source(parallel->device, O_RDWR, errp);
    251    if (fd < 0) {
    252        return;
    253    }
    254    qemu_chr_open_pp_fd(chr, fd, be_opened, errp);
    255}
    256
    257static void qemu_chr_parse_parallel(QemuOpts *opts, ChardevBackend *backend,
    258                                    Error **errp)
    259{
    260    const char *device = qemu_opt_get(opts, "path");
    261    ChardevHostdev *parallel;
    262
    263    if (device == NULL) {
    264        error_setg(errp, "chardev: parallel: no device path given");
    265        return;
    266    }
    267    backend->type = CHARDEV_BACKEND_KIND_PARALLEL;
    268    parallel = backend->u.parallel.data = g_new0(ChardevHostdev, 1);
    269    qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(parallel));
    270    parallel->device = g_strdup(device);
    271}
    272
    273static void char_parallel_class_init(ObjectClass *oc, void *data)
    274{
    275    ChardevClass *cc = CHARDEV_CLASS(oc);
    276
    277    cc->parse = qemu_chr_parse_parallel;
    278    cc->open = qmp_chardev_open_parallel;
    279#if defined(__linux__)
    280    cc->chr_ioctl = pp_ioctl;
    281#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
    282    defined(__DragonFly__)
    283    cc->chr_ioctl = pp_ioctl;
    284#endif
    285}
    286
    287static void char_parallel_finalize(Object *obj)
    288{
    289#if defined(__linux__)
    290    Chardev *chr = CHARDEV(obj);
    291    ParallelChardev *drv = PARALLEL_CHARDEV(chr);
    292    int fd = drv->fd;
    293
    294    pp_hw_mode(drv, IEEE1284_MODE_COMPAT);
    295    ioctl(fd, PPRELEASE);
    296    close(fd);
    297    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
    298#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
    299    defined(__DragonFly__)
    300    /* FIXME: close fd? */
    301#endif
    302}
    303
    304static const TypeInfo char_parallel_type_info = {
    305    .name = TYPE_CHARDEV_PARALLEL,
    306    .parent = TYPE_CHARDEV,
    307    .instance_size = sizeof(ParallelChardev),
    308    .instance_finalize = char_parallel_finalize,
    309    .class_init = char_parallel_class_init,
    310};
    311
    312static void register_types(void)
    313{
    314    type_register_static(&char_parallel_type_info);
    315}
    316
    317type_init(register_types);
    318
    319#endif