qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

pnv_pnor.c (3655B)


      1 /*
      2  * QEMU PowerNV PNOR simple model
      3  *
      4  * Copyright (c) 2015-2019, IBM Corporation.
      5  *
      6  * This code is licensed under the GPL version 2 or later. See the
      7  * COPYING file in the top-level directory.
      8  */
      9 
     10 #include "qemu/osdep.h"
     11 #include "qapi/error.h"
     12 #include "qemu/error-report.h"
     13 #include "qemu/units.h"
     14 #include "sysemu/block-backend.h"
     15 #include "sysemu/blockdev.h"
     16 #include "hw/loader.h"
     17 #include "hw/ppc/pnv_pnor.h"
     18 #include "hw/qdev-properties.h"
     19 #include "hw/qdev-properties-system.h"
     20 
     21 static uint64_t pnv_pnor_read(void *opaque, hwaddr addr, unsigned size)
     22 {
     23     PnvPnor *s = PNV_PNOR(opaque);
     24     uint64_t ret = 0;
     25     int i;
     26 
     27     for (i = 0; i < size; i++) {
     28         ret |= (uint64_t) s->storage[addr + i] << (8 * (size - i - 1));
     29     }
     30 
     31     return ret;
     32 }
     33 
     34 static void pnv_pnor_update(PnvPnor *s, int offset, int size)
     35 {
     36     int offset_end;
     37     int ret;
     38 
     39     if (!s->blk || !blk_is_writable(s->blk)) {
     40         return;
     41     }
     42 
     43     offset_end = offset + size;
     44     offset = QEMU_ALIGN_DOWN(offset, BDRV_SECTOR_SIZE);
     45     offset_end = QEMU_ALIGN_UP(offset_end, BDRV_SECTOR_SIZE);
     46 
     47     ret = blk_pwrite(s->blk, offset, offset_end - offset, s->storage + offset,
     48                      0);
     49     if (ret < 0) {
     50         error_report("Could not update PNOR offset=0x%" PRIx32" : %s", offset,
     51                      strerror(-ret));
     52     }
     53 }
     54 
     55 static void pnv_pnor_write(void *opaque, hwaddr addr, uint64_t data,
     56                            unsigned size)
     57 {
     58     PnvPnor *s = PNV_PNOR(opaque);
     59     int i;
     60 
     61     for (i = 0; i < size; i++) {
     62         s->storage[addr + i] = (data >> (8 * (size - i - 1))) & 0xFF;
     63     }
     64     pnv_pnor_update(s, addr, size);
     65 }
     66 
     67 /*
     68  * TODO: Check endianness: skiboot is BIG, Aspeed AHB is LITTLE, flash
     69  * is BIG.
     70  */
     71 static const MemoryRegionOps pnv_pnor_ops = {
     72     .read = pnv_pnor_read,
     73     .write = pnv_pnor_write,
     74     .endianness = DEVICE_BIG_ENDIAN,
     75     .valid = {
     76         .min_access_size = 1,
     77         .max_access_size = 4,
     78     },
     79 };
     80 
     81 static void pnv_pnor_realize(DeviceState *dev, Error **errp)
     82 {
     83     PnvPnor *s = PNV_PNOR(dev);
     84     int ret;
     85 
     86     if (s->blk) {
     87         uint64_t perm = BLK_PERM_CONSISTENT_READ |
     88                         (blk_supports_write_perm(s->blk) ? BLK_PERM_WRITE : 0);
     89         ret = blk_set_perm(s->blk, perm, BLK_PERM_ALL, errp);
     90         if (ret < 0) {
     91             return;
     92         }
     93 
     94         s->size = blk_getlength(s->blk);
     95         if (s->size <= 0) {
     96             error_setg(errp, "failed to get flash size");
     97             return;
     98         }
     99 
    100         s->storage = blk_blockalign(s->blk, s->size);
    101 
    102         if (blk_pread(s->blk, 0, s->size, s->storage, 0) < 0) {
    103             error_setg(errp, "failed to read the initial flash content");
    104             return;
    105         }
    106     } else {
    107         s->storage = blk_blockalign(NULL, s->size);
    108         memset(s->storage, 0xFF, s->size);
    109     }
    110 
    111     memory_region_init_io(&s->mmio, OBJECT(s), &pnv_pnor_ops, s,
    112                           TYPE_PNV_PNOR, s->size);
    113 }
    114 
    115 static Property pnv_pnor_properties[] = {
    116     DEFINE_PROP_INT64("size", PnvPnor, size, 128 * MiB),
    117     DEFINE_PROP_DRIVE("drive", PnvPnor, blk),
    118     DEFINE_PROP_END_OF_LIST(),
    119 };
    120 
    121 static void pnv_pnor_class_init(ObjectClass *klass, void *data)
    122 {
    123     DeviceClass *dc = DEVICE_CLASS(klass);
    124 
    125     dc->realize = pnv_pnor_realize;
    126     device_class_set_props(dc, pnv_pnor_properties);
    127 }
    128 
    129 static const TypeInfo pnv_pnor_info = {
    130     .name          = TYPE_PNV_PNOR,
    131     .parent        = TYPE_SYS_BUS_DEVICE,
    132     .instance_size = sizeof(PnvPnor),
    133     .class_init    = pnv_pnor_class_init,
    134 };
    135 
    136 static void pnv_pnor_register_types(void)
    137 {
    138     type_register_static(&pnv_pnor_info);
    139 }
    140 
    141 type_init(pnv_pnor_register_types)