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

next-kbd.c (7891B)


      1/*
      2 * QEMU NeXT Keyboard/Mouse emulation
      3 *
      4 * Copyright (c) 2011 Bryce Lanham
      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/*
     26 * This is admittedly hackish, but works well enough for basic input. Mouse
     27 * support will be added once we can boot something that needs the mouse.
     28 */
     29
     30#include "qemu/osdep.h"
     31#include "qemu/log.h"
     32#include "hw/sysbus.h"
     33#include "hw/m68k/next-cube.h"
     34#include "ui/console.h"
     35#include "migration/vmstate.h"
     36#include "qom/object.h"
     37
     38OBJECT_DECLARE_SIMPLE_TYPE(NextKBDState, NEXTKBD)
     39
     40/* following defintions from next68k netbsd */
     41#define CSR_INT 0x00800000
     42#define CSR_DATA 0x00400000
     43
     44#define KD_KEYMASK    0x007f
     45#define KD_DIRECTION  0x0080 /* pressed or released */
     46#define KD_CNTL       0x0100
     47#define KD_LSHIFT     0x0200
     48#define KD_RSHIFT     0x0400
     49#define KD_LCOMM      0x0800
     50#define KD_RCOMM      0x1000
     51#define KD_LALT       0x2000
     52#define KD_RALT       0x4000
     53#define KD_VALID      0x8000 /* only set for scancode keys ? */
     54#define KD_MODS       0x4f00
     55
     56#define KBD_QUEUE_SIZE 256
     57
     58typedef struct {
     59    uint8_t data[KBD_QUEUE_SIZE];
     60    int rptr, wptr, count;
     61} KBDQueue;
     62
     63
     64struct NextKBDState {
     65    SysBusDevice sbd;
     66    MemoryRegion mr;
     67    KBDQueue queue;
     68    uint16_t shift;
     69};
     70
     71static void queue_code(void *opaque, int code);
     72
     73/* lots of magic numbers here */
     74static uint32_t kbd_read_byte(void *opaque, hwaddr addr)
     75{
     76    switch (addr & 0x3) {
     77    case 0x0:   /* 0xe000 */
     78        return 0x80 | 0x20;
     79
     80    case 0x1:   /* 0xe001 */
     81        return 0x80 | 0x40 | 0x20 | 0x10;
     82
     83    case 0x2:   /* 0xe002 */
     84        /* returning 0x40 caused mach to hang */
     85        return 0x10 | 0x2 | 0x1;
     86
     87    default:
     88        qemu_log_mask(LOG_UNIMP, "NeXT kbd read byte %"HWADDR_PRIx"\n", addr);
     89    }
     90
     91    return 0;
     92}
     93
     94static uint32_t kbd_read_word(void *opaque, hwaddr addr)
     95{
     96    qemu_log_mask(LOG_UNIMP, "NeXT kbd read word %"HWADDR_PRIx"\n", addr);
     97    return 0;
     98}
     99
    100/* even more magic numbers */
    101static uint32_t kbd_read_long(void *opaque, hwaddr addr)
    102{
    103    int key = 0;
    104    NextKBDState *s = NEXTKBD(opaque);
    105    KBDQueue *q = &s->queue;
    106
    107    switch (addr & 0xf) {
    108    case 0x0:   /* 0xe000 */
    109        return 0xA0F09300;
    110
    111    case 0x8:   /* 0xe008 */
    112        /* get keycode from buffer */
    113        if (q->count > 0) {
    114            key = q->data[q->rptr];
    115            if (++q->rptr == KBD_QUEUE_SIZE) {
    116                q->rptr = 0;
    117            }
    118
    119            q->count--;
    120
    121            if (s->shift) {
    122                key |= s->shift;
    123            }
    124
    125            if (key & 0x80) {
    126                return 0;
    127            } else {
    128                return 0x10000000 | KD_VALID | key;
    129            }
    130        } else {
    131            return 0;
    132        }
    133
    134    default:
    135        qemu_log_mask(LOG_UNIMP, "NeXT kbd read long %"HWADDR_PRIx"\n", addr);
    136        return 0;
    137    }
    138}
    139
    140static uint64_t kbd_readfn(void *opaque, hwaddr addr, unsigned size)
    141{
    142    switch (size) {
    143    case 1:
    144        return kbd_read_byte(opaque, addr);
    145    case 2:
    146        return kbd_read_word(opaque, addr);
    147    case 4:
    148        return kbd_read_long(opaque, addr);
    149    default:
    150        g_assert_not_reached();
    151    }
    152}
    153
    154static void kbd_writefn(void *opaque, hwaddr addr, uint64_t value,
    155                        unsigned size)
    156{
    157    qemu_log_mask(LOG_UNIMP, "NeXT kbd write: size=%u addr=0x%"HWADDR_PRIx
    158                  "val=0x%"PRIx64"\n", size, addr, value);
    159}
    160
    161static const MemoryRegionOps kbd_ops = {
    162    .read = kbd_readfn,
    163    .write = kbd_writefn,
    164    .valid.min_access_size = 1,
    165    .valid.max_access_size = 4,
    166    .endianness = DEVICE_NATIVE_ENDIAN,
    167};
    168
    169static void nextkbd_event(void *opaque, int ch)
    170{
    171    /*
    172     * Will want to set vars for caps/num lock
    173     * if (ch & 0x80) -> key release
    174     * there's also e0 escaped scancodes that might need to be handled
    175     */
    176    queue_code(opaque, ch);
    177}
    178
    179static const unsigned char next_keycodes[128] = {
    180    0x00, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x50, 0x4F,
    181    0x4E, 0x1E, 0x1F, 0x20, 0x1D, 0x1C, 0x1B, 0x00,
    182    0x42, 0x43, 0x44, 0x45, 0x48, 0x47, 0x46, 0x06,
    183    0x07, 0x08, 0x00, 0x00, 0x2A, 0x00, 0x39, 0x3A,
    184    0x3B, 0x3C, 0x3D, 0x40, 0x3F, 0x3E, 0x2D, 0x2C,
    185    0x2B, 0x26, 0x00, 0x00, 0x31, 0x32, 0x33, 0x34,
    186    0x35, 0x37, 0x36, 0x2e, 0x2f, 0x30, 0x00, 0x00,
    187    0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    188    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    189    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    190    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    191    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
    192};
    193
    194static void queue_code(void *opaque, int code)
    195{
    196    NextKBDState *s = NEXTKBD(opaque);
    197    KBDQueue *q = &s->queue;
    198    int key = code & KD_KEYMASK;
    199    int release = code & 0x80;
    200    static int ext;
    201
    202    if (code == 0xE0) {
    203        ext = 1;
    204    }
    205
    206    if (code == 0x2A || code == 0x1D || code == 0x36) {
    207        if (code == 0x2A) {
    208            s->shift = KD_LSHIFT;
    209        } else if (code == 0x36) {
    210            s->shift = KD_RSHIFT;
    211            ext = 0;
    212        } else if (code == 0x1D && !ext) {
    213            s->shift = KD_LCOMM;
    214        } else if (code == 0x1D && ext) {
    215            ext = 0;
    216            s->shift = KD_RCOMM;
    217        }
    218        return;
    219    } else if (code == (0x2A | 0x80) || code == (0x1D | 0x80) ||
    220               code == (0x36 | 0x80)) {
    221        s->shift = 0;
    222        return;
    223    }
    224
    225    if (q->count >= KBD_QUEUE_SIZE) {
    226        return;
    227    }
    228
    229    q->data[q->wptr] = next_keycodes[key] | release;
    230
    231    if (++q->wptr == KBD_QUEUE_SIZE) {
    232        q->wptr = 0;
    233    }
    234
    235    q->count++;
    236
    237    /*
    238     * might need to actually trigger the NeXT irq, but as the keyboard works
    239     * at the moment, I'll worry about it later
    240     */
    241    /* s->update_irq(s->update_arg, 1); */
    242}
    243
    244static void nextkbd_reset(DeviceState *dev)
    245{
    246    NextKBDState *nks = NEXTKBD(dev);
    247
    248    memset(&nks->queue, 0, sizeof(KBDQueue));
    249    nks->shift = 0;
    250}
    251
    252static void nextkbd_realize(DeviceState *dev, Error **errp)
    253{
    254    NextKBDState *s = NEXTKBD(dev);
    255
    256    memory_region_init_io(&s->mr, OBJECT(dev), &kbd_ops, s, "next.kbd", 0x1000);
    257    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mr);
    258
    259    qemu_add_kbd_event_handler(nextkbd_event, s);
    260}
    261
    262static const VMStateDescription nextkbd_vmstate = {
    263    .name = TYPE_NEXTKBD,
    264    .unmigratable = 1,    /* TODO: Implement this when m68k CPU is migratable */
    265};
    266
    267static void nextkbd_class_init(ObjectClass *oc, void *data)
    268{
    269    DeviceClass *dc = DEVICE_CLASS(oc);
    270
    271    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
    272    dc->vmsd = &nextkbd_vmstate;
    273    dc->realize = nextkbd_realize;
    274    dc->reset = nextkbd_reset;
    275}
    276
    277static const TypeInfo nextkbd_info = {
    278    .name          = TYPE_NEXTKBD,
    279    .parent        = TYPE_SYS_BUS_DEVICE,
    280    .instance_size = sizeof(NextKBDState),
    281    .class_init    = nextkbd_class_init,
    282};
    283
    284static void nextkbd_register_types(void)
    285{
    286    type_register_static(&nextkbd_info);
    287}
    288
    289type_init(nextkbd_register_types)