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

bcm2835_property.c (14563B)


      1/*
      2 * Raspberry Pi emulation (c) 2012 Gregory Estrade
      3 *
      4 * This work is licensed under the terms of the GNU GPL, version 2 or later.
      5 * See the COPYING file in the top-level directory.
      6 */
      7
      8#include "qemu/osdep.h"
      9#include "qapi/error.h"
     10#include "hw/misc/bcm2835_property.h"
     11#include "hw/qdev-properties.h"
     12#include "migration/vmstate.h"
     13#include "hw/irq.h"
     14#include "hw/misc/bcm2835_mbox_defs.h"
     15#include "sysemu/dma.h"
     16#include "qemu/log.h"
     17#include "qemu/module.h"
     18#include "trace.h"
     19
     20/* https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface */
     21
     22static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
     23{
     24    uint32_t tag;
     25    uint32_t bufsize;
     26    uint32_t tot_len;
     27    size_t resplen;
     28    uint32_t tmp;
     29    int n;
     30    uint32_t offset, length, color;
     31
     32    /*
     33     * Copy the current state of the framebuffer config; we will update
     34     * this copy as we process tags and then ask the framebuffer to use
     35     * it at the end.
     36     */
     37    BCM2835FBConfig fbconfig = s->fbdev->config;
     38    bool fbconfig_updated = false;
     39
     40    value &= ~0xf;
     41
     42    s->addr = value;
     43
     44    tot_len = ldl_le_phys(&s->dma_as, value);
     45
     46    /* @(addr + 4) : Buffer response code */
     47    value = s->addr + 8;
     48    while (value + 8 <= s->addr + tot_len) {
     49        tag = ldl_le_phys(&s->dma_as, value);
     50        bufsize = ldl_le_phys(&s->dma_as, value + 4);
     51        /* @(value + 8) : Request/response indicator */
     52        resplen = 0;
     53        switch (tag) {
     54        case 0x00000000: /* End tag */
     55            break;
     56        case 0x00000001: /* Get firmware revision */
     57            stl_le_phys(&s->dma_as, value + 12, 346337);
     58            resplen = 4;
     59            break;
     60        case 0x00010001: /* Get board model */
     61            qemu_log_mask(LOG_UNIMP,
     62                          "bcm2835_property: 0x%08x get board model NYI\n",
     63                          tag);
     64            resplen = 4;
     65            break;
     66        case 0x00010002: /* Get board revision */
     67            stl_le_phys(&s->dma_as, value + 12, s->board_rev);
     68            resplen = 4;
     69            break;
     70        case 0x00010003: /* Get board MAC address */
     71            resplen = sizeof(s->macaddr.a);
     72            dma_memory_write(&s->dma_as, value + 12, s->macaddr.a, resplen);
     73            break;
     74        case 0x00010004: /* Get board serial */
     75            qemu_log_mask(LOG_UNIMP,
     76                          "bcm2835_property: 0x%08x get board serial NYI\n",
     77                          tag);
     78            resplen = 8;
     79            break;
     80        case 0x00010005: /* Get ARM memory */
     81            /* base */
     82            stl_le_phys(&s->dma_as, value + 12, 0);
     83            /* size */
     84            stl_le_phys(&s->dma_as, value + 16, s->fbdev->vcram_base);
     85            resplen = 8;
     86            break;
     87        case 0x00010006: /* Get VC memory */
     88            /* base */
     89            stl_le_phys(&s->dma_as, value + 12, s->fbdev->vcram_base);
     90            /* size */
     91            stl_le_phys(&s->dma_as, value + 16, s->fbdev->vcram_size);
     92            resplen = 8;
     93            break;
     94        case 0x00028001: /* Set power state */
     95            /* Assume that whatever device they asked for exists,
     96             * and we'll just claim we set it to the desired state
     97             */
     98            tmp = ldl_le_phys(&s->dma_as, value + 16);
     99            stl_le_phys(&s->dma_as, value + 16, (tmp & 1));
    100            resplen = 8;
    101            break;
    102
    103        /* Clocks */
    104
    105        case 0x00030001: /* Get clock state */
    106            stl_le_phys(&s->dma_as, value + 16, 0x1);
    107            resplen = 8;
    108            break;
    109
    110        case 0x00038001: /* Set clock state */
    111            qemu_log_mask(LOG_UNIMP,
    112                          "bcm2835_property: 0x%08x set clock state NYI\n",
    113                          tag);
    114            resplen = 8;
    115            break;
    116
    117        case 0x00030002: /* Get clock rate */
    118        case 0x00030004: /* Get max clock rate */
    119        case 0x00030007: /* Get min clock rate */
    120            switch (ldl_le_phys(&s->dma_as, value + 12)) {
    121            case 1: /* EMMC */
    122                stl_le_phys(&s->dma_as, value + 16, 50000000);
    123                break;
    124            case 2: /* UART */
    125                stl_le_phys(&s->dma_as, value + 16, 3000000);
    126                break;
    127            default:
    128                stl_le_phys(&s->dma_as, value + 16, 700000000);
    129                break;
    130            }
    131            resplen = 8;
    132            break;
    133
    134        case 0x00038002: /* Set clock rate */
    135        case 0x00038004: /* Set max clock rate */
    136        case 0x00038007: /* Set min clock rate */
    137            qemu_log_mask(LOG_UNIMP,
    138                          "bcm2835_property: 0x%08x set clock rate NYI\n",
    139                          tag);
    140            resplen = 8;
    141            break;
    142
    143        /* Temperature */
    144
    145        case 0x00030006: /* Get temperature */
    146            stl_le_phys(&s->dma_as, value + 16, 25000);
    147            resplen = 8;
    148            break;
    149
    150        case 0x0003000A: /* Get max temperature */
    151            stl_le_phys(&s->dma_as, value + 16, 99000);
    152            resplen = 8;
    153            break;
    154
    155        /* Frame buffer */
    156
    157        case 0x00040001: /* Allocate buffer */
    158            stl_le_phys(&s->dma_as, value + 12, fbconfig.base);
    159            stl_le_phys(&s->dma_as, value + 16,
    160                        bcm2835_fb_get_size(&fbconfig));
    161            resplen = 8;
    162            break;
    163        case 0x00048001: /* Release buffer */
    164            resplen = 0;
    165            break;
    166        case 0x00040002: /* Blank screen */
    167            resplen = 4;
    168            break;
    169        case 0x00044003: /* Test physical display width/height */
    170        case 0x00044004: /* Test virtual display width/height */
    171            resplen = 8;
    172            break;
    173        case 0x00048003: /* Set physical display width/height */
    174            fbconfig.xres = ldl_le_phys(&s->dma_as, value + 12);
    175            fbconfig.yres = ldl_le_phys(&s->dma_as, value + 16);
    176            bcm2835_fb_validate_config(&fbconfig);
    177            fbconfig_updated = true;
    178            /* fall through */
    179        case 0x00040003: /* Get physical display width/height */
    180            stl_le_phys(&s->dma_as, value + 12, fbconfig.xres);
    181            stl_le_phys(&s->dma_as, value + 16, fbconfig.yres);
    182            resplen = 8;
    183            break;
    184        case 0x00048004: /* Set virtual display width/height */
    185            fbconfig.xres_virtual = ldl_le_phys(&s->dma_as, value + 12);
    186            fbconfig.yres_virtual = ldl_le_phys(&s->dma_as, value + 16);
    187            bcm2835_fb_validate_config(&fbconfig);
    188            fbconfig_updated = true;
    189            /* fall through */
    190        case 0x00040004: /* Get virtual display width/height */
    191            stl_le_phys(&s->dma_as, value + 12, fbconfig.xres_virtual);
    192            stl_le_phys(&s->dma_as, value + 16, fbconfig.yres_virtual);
    193            resplen = 8;
    194            break;
    195        case 0x00044005: /* Test depth */
    196            resplen = 4;
    197            break;
    198        case 0x00048005: /* Set depth */
    199            fbconfig.bpp = ldl_le_phys(&s->dma_as, value + 12);
    200            bcm2835_fb_validate_config(&fbconfig);
    201            fbconfig_updated = true;
    202            /* fall through */
    203        case 0x00040005: /* Get depth */
    204            stl_le_phys(&s->dma_as, value + 12, fbconfig.bpp);
    205            resplen = 4;
    206            break;
    207        case 0x00044006: /* Test pixel order */
    208            resplen = 4;
    209            break;
    210        case 0x00048006: /* Set pixel order */
    211            fbconfig.pixo = ldl_le_phys(&s->dma_as, value + 12);
    212            bcm2835_fb_validate_config(&fbconfig);
    213            fbconfig_updated = true;
    214            /* fall through */
    215        case 0x00040006: /* Get pixel order */
    216            stl_le_phys(&s->dma_as, value + 12, fbconfig.pixo);
    217            resplen = 4;
    218            break;
    219        case 0x00044007: /* Test pixel alpha */
    220            resplen = 4;
    221            break;
    222        case 0x00048007: /* Set alpha */
    223            fbconfig.alpha = ldl_le_phys(&s->dma_as, value + 12);
    224            bcm2835_fb_validate_config(&fbconfig);
    225            fbconfig_updated = true;
    226            /* fall through */
    227        case 0x00040007: /* Get alpha */
    228            stl_le_phys(&s->dma_as, value + 12, fbconfig.alpha);
    229            resplen = 4;
    230            break;
    231        case 0x00040008: /* Get pitch */
    232            stl_le_phys(&s->dma_as, value + 12,
    233                        bcm2835_fb_get_pitch(&fbconfig));
    234            resplen = 4;
    235            break;
    236        case 0x00044009: /* Test virtual offset */
    237            resplen = 8;
    238            break;
    239        case 0x00048009: /* Set virtual offset */
    240            fbconfig.xoffset = ldl_le_phys(&s->dma_as, value + 12);
    241            fbconfig.yoffset = ldl_le_phys(&s->dma_as, value + 16);
    242            bcm2835_fb_validate_config(&fbconfig);
    243            fbconfig_updated = true;
    244            /* fall through */
    245        case 0x00040009: /* Get virtual offset */
    246            stl_le_phys(&s->dma_as, value + 12, fbconfig.xoffset);
    247            stl_le_phys(&s->dma_as, value + 16, fbconfig.yoffset);
    248            resplen = 8;
    249            break;
    250        case 0x0004000a: /* Get/Test/Set overscan */
    251        case 0x0004400a:
    252        case 0x0004800a:
    253            stl_le_phys(&s->dma_as, value + 12, 0);
    254            stl_le_phys(&s->dma_as, value + 16, 0);
    255            stl_le_phys(&s->dma_as, value + 20, 0);
    256            stl_le_phys(&s->dma_as, value + 24, 0);
    257            resplen = 16;
    258            break;
    259        case 0x0004800b: /* Set palette */
    260            offset = ldl_le_phys(&s->dma_as, value + 12);
    261            length = ldl_le_phys(&s->dma_as, value + 16);
    262            n = 0;
    263            while (n < length - offset) {
    264                color = ldl_le_phys(&s->dma_as, value + 20 + (n << 2));
    265                stl_le_phys(&s->dma_as,
    266                            s->fbdev->vcram_base + ((offset + n) << 2), color);
    267                n++;
    268            }
    269            stl_le_phys(&s->dma_as, value + 12, 0);
    270            resplen = 4;
    271            break;
    272
    273        case 0x00060001: /* Get DMA channels */
    274            /* channels 2-5 */
    275            stl_le_phys(&s->dma_as, value + 12, 0x003C);
    276            resplen = 4;
    277            break;
    278
    279        case 0x00050001: /* Get command line */
    280            resplen = 0;
    281            break;
    282
    283        default:
    284            qemu_log_mask(LOG_UNIMP,
    285                          "bcm2835_property: unhandled tag 0x%08x\n", tag);
    286            break;
    287        }
    288
    289        trace_bcm2835_mbox_property(tag, bufsize, resplen);
    290        if (tag == 0) {
    291            break;
    292        }
    293
    294        stl_le_phys(&s->dma_as, value + 8, (1 << 31) | resplen);
    295        value += bufsize + 12;
    296    }
    297
    298    /* Reconfigure framebuffer if required */
    299    if (fbconfig_updated) {
    300        bcm2835_fb_reconfigure(s->fbdev, &fbconfig);
    301    }
    302
    303    /* Buffer response code */
    304    stl_le_phys(&s->dma_as, s->addr + 4, (1 << 31));
    305}
    306
    307static uint64_t bcm2835_property_read(void *opaque, hwaddr offset,
    308                                      unsigned size)
    309{
    310    BCM2835PropertyState *s = opaque;
    311    uint32_t res = 0;
    312
    313    switch (offset) {
    314    case MBOX_AS_DATA:
    315        res = MBOX_CHAN_PROPERTY | s->addr;
    316        s->pending = false;
    317        qemu_set_irq(s->mbox_irq, 0);
    318        break;
    319
    320    case MBOX_AS_PENDING:
    321        res = s->pending;
    322        break;
    323
    324    default:
    325        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
    326                      __func__, offset);
    327        return 0;
    328    }
    329
    330    return res;
    331}
    332
    333static void bcm2835_property_write(void *opaque, hwaddr offset,
    334                                   uint64_t value, unsigned size)
    335{
    336    BCM2835PropertyState *s = opaque;
    337
    338    switch (offset) {
    339    case MBOX_AS_DATA:
    340        /* bcm2835_mbox should check our pending status before pushing */
    341        assert(!s->pending);
    342        s->pending = true;
    343        bcm2835_property_mbox_push(s, value);
    344        qemu_set_irq(s->mbox_irq, 1);
    345        break;
    346
    347    default:
    348        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
    349                      __func__, offset);
    350        return;
    351    }
    352}
    353
    354static const MemoryRegionOps bcm2835_property_ops = {
    355    .read = bcm2835_property_read,
    356    .write = bcm2835_property_write,
    357    .endianness = DEVICE_NATIVE_ENDIAN,
    358    .valid.min_access_size = 4,
    359    .valid.max_access_size = 4,
    360};
    361
    362static const VMStateDescription vmstate_bcm2835_property = {
    363    .name = TYPE_BCM2835_PROPERTY,
    364    .version_id = 1,
    365    .minimum_version_id = 1,
    366    .fields      = (VMStateField[]) {
    367        VMSTATE_MACADDR(macaddr, BCM2835PropertyState),
    368        VMSTATE_UINT32(addr, BCM2835PropertyState),
    369        VMSTATE_BOOL(pending, BCM2835PropertyState),
    370        VMSTATE_END_OF_LIST()
    371    }
    372};
    373
    374static void bcm2835_property_init(Object *obj)
    375{
    376    BCM2835PropertyState *s = BCM2835_PROPERTY(obj);
    377
    378    memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_property_ops, s,
    379                          TYPE_BCM2835_PROPERTY, 0x10);
    380    sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
    381    sysbus_init_irq(SYS_BUS_DEVICE(s), &s->mbox_irq);
    382}
    383
    384static void bcm2835_property_reset(DeviceState *dev)
    385{
    386    BCM2835PropertyState *s = BCM2835_PROPERTY(dev);
    387
    388    s->pending = false;
    389}
    390
    391static void bcm2835_property_realize(DeviceState *dev, Error **errp)
    392{
    393    BCM2835PropertyState *s = BCM2835_PROPERTY(dev);
    394    Object *obj;
    395
    396    obj = object_property_get_link(OBJECT(dev), "fb", &error_abort);
    397    s->fbdev = BCM2835_FB(obj);
    398
    399    obj = object_property_get_link(OBJECT(dev), "dma-mr", &error_abort);
    400    s->dma_mr = MEMORY_REGION(obj);
    401    address_space_init(&s->dma_as, s->dma_mr, TYPE_BCM2835_PROPERTY "-memory");
    402
    403    /* TODO: connect to MAC address of USB NIC device, once we emulate it */
    404    qemu_macaddr_default_if_unset(&s->macaddr);
    405
    406    bcm2835_property_reset(dev);
    407}
    408
    409static Property bcm2835_property_props[] = {
    410    DEFINE_PROP_UINT32("board-rev", BCM2835PropertyState, board_rev, 0),
    411    DEFINE_PROP_END_OF_LIST()
    412};
    413
    414static void bcm2835_property_class_init(ObjectClass *klass, void *data)
    415{
    416    DeviceClass *dc = DEVICE_CLASS(klass);
    417
    418    device_class_set_props(dc, bcm2835_property_props);
    419    dc->realize = bcm2835_property_realize;
    420    dc->vmsd = &vmstate_bcm2835_property;
    421}
    422
    423static TypeInfo bcm2835_property_info = {
    424    .name          = TYPE_BCM2835_PROPERTY,
    425    .parent        = TYPE_SYS_BUS_DEVICE,
    426    .instance_size = sizeof(BCM2835PropertyState),
    427    .class_init    = bcm2835_property_class_init,
    428    .instance_init = bcm2835_property_init,
    429};
    430
    431static void bcm2835_property_register_types(void)
    432{
    433    type_register_static(&bcm2835_property_info);
    434}
    435
    436type_init(bcm2835_property_register_types)