qemu/hw/core/register.c
<<
>>
Prefs
   1/*
   2 * Register Definition API
   3 *
   4 * Copyright (c) 2016 Xilinx Inc.
   5 * Copyright (c) 2013 Peter Crosthwaite <peter.crosthwaite@xilinx.com>
   6 *
   7 * This program is free software; you can redistribute it and/or modify it
   8 * under the terms of the GNU General Public License as published by the
   9 * Free Software Foundation; either version 2 of the License, or
  10 * (at your option) any later version.
  11 *
  12 * This program is distributed in the hope that it will be useful, but WITHOUT
  13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  15 * for more details.
  16 */
  17
  18#include "qemu/osdep.h"
  19#include "hw/register.h"
  20#include "qemu/log.h"
  21#include "qemu/module.h"
  22
  23static inline void register_write_val(RegisterInfo *reg, uint64_t val)
  24{
  25    g_assert(reg->data);
  26
  27    switch (reg->data_size) {
  28    case 1:
  29        *(uint8_t *)reg->data = val;
  30        break;
  31    case 2:
  32        *(uint16_t *)reg->data = val;
  33        break;
  34    case 4:
  35        *(uint32_t *)reg->data = val;
  36        break;
  37    case 8:
  38        *(uint64_t *)reg->data = val;
  39        break;
  40    default:
  41        g_assert_not_reached();
  42    }
  43}
  44
  45static inline uint64_t register_read_val(RegisterInfo *reg)
  46{
  47    switch (reg->data_size) {
  48    case 1:
  49        return *(uint8_t *)reg->data;
  50    case 2:
  51        return *(uint16_t *)reg->data;
  52    case 4:
  53        return *(uint32_t *)reg->data;
  54    case 8:
  55        return *(uint64_t *)reg->data;
  56    default:
  57        g_assert_not_reached();
  58    }
  59    return 0; /* unreachable */
  60}
  61
  62static inline uint64_t register_enabled_mask(int data_size, unsigned size)
  63{
  64    if (data_size < size) {
  65        size = data_size;
  66    }
  67
  68    return MAKE_64BIT_MASK(0, size * 8);
  69}
  70
  71void register_write(RegisterInfo *reg, uint64_t val, uint64_t we,
  72                    const char *prefix, bool debug)
  73{
  74    uint64_t old_val, new_val, test, no_w_mask;
  75    const RegisterAccessInfo *ac;
  76
  77    assert(reg);
  78
  79    ac = reg->access;
  80
  81    if (!ac || !ac->name) {
  82        qemu_log_mask(LOG_GUEST_ERROR, "%s: write to undefined device state "
  83                      "(written value: 0x%" PRIx64 ")\n", prefix, val);
  84        return;
  85    }
  86
  87    old_val = reg->data ? register_read_val(reg) : ac->reset;
  88
  89    test = (old_val ^ val) & ac->rsvd;
  90    if (test) {
  91        qemu_log_mask(LOG_GUEST_ERROR, "%s: change of value in reserved bit"
  92                      "fields: 0x%" PRIx64 ")\n", prefix, test);
  93    }
  94
  95    test = val & ac->unimp;
  96    if (test) {
  97        qemu_log_mask(LOG_UNIMP,
  98                      "%s:%s writing 0x%" PRIx64 " to unimplemented bits:" \
  99                      " 0x%" PRIx64 "\n",
 100                      prefix, reg->access->name, val, ac->unimp);
 101    }
 102
 103    /* Create the no write mask based on the read only, write to clear and
 104     * reserved bit masks.
 105     */
 106    no_w_mask = ac->ro | ac->w1c | ac->rsvd | ~we;
 107    new_val = (val & ~no_w_mask) | (old_val & no_w_mask);
 108    new_val &= ~(val & ac->w1c);
 109
 110    if (ac->pre_write) {
 111        new_val = ac->pre_write(reg, new_val);
 112    }
 113
 114    if (debug) {
 115        qemu_log("%s:%s: write of value 0x%" PRIx64 "\n", prefix, ac->name,
 116                 new_val);
 117    }
 118
 119    register_write_val(reg, new_val);
 120
 121    if (ac->post_write) {
 122        ac->post_write(reg, new_val);
 123    }
 124}
 125
 126uint64_t register_read(RegisterInfo *reg, uint64_t re, const char* prefix,
 127                       bool debug)
 128{
 129    uint64_t ret;
 130    const RegisterAccessInfo *ac;
 131
 132    assert(reg);
 133
 134    ac = reg->access;
 135    if (!ac || !ac->name) {
 136        qemu_log_mask(LOG_GUEST_ERROR, "%s: read from undefined device state\n",
 137                      prefix);
 138        return 0;
 139    }
 140
 141    ret = reg->data ? register_read_val(reg) : ac->reset;
 142
 143    register_write_val(reg, ret & ~(ac->cor & re));
 144
 145    /* Mask based on the read enable size */
 146    ret &= re;
 147
 148    if (ac->post_read) {
 149        ret = ac->post_read(reg, ret);
 150    }
 151
 152    if (debug) {
 153        qemu_log("%s:%s: read of value 0x%" PRIx64 "\n", prefix,
 154                 ac->name, ret);
 155    }
 156
 157    return ret;
 158}
 159
 160void register_reset(RegisterInfo *reg)
 161{
 162    const RegisterAccessInfo *ac;
 163
 164    g_assert(reg);
 165
 166    if (!reg->data || !reg->access) {
 167        return;
 168    }
 169
 170    ac = reg->access;
 171
 172    register_write_val(reg, reg->access->reset);
 173
 174    if (ac->post_write) {
 175        ac->post_write(reg, reg->access->reset);
 176    }
 177}
 178
 179void register_write_memory(void *opaque, hwaddr addr,
 180                           uint64_t value, unsigned size)
 181{
 182    RegisterInfoArray *reg_array = opaque;
 183    RegisterInfo *reg = NULL;
 184    uint64_t we;
 185    int i;
 186
 187    for (i = 0; i < reg_array->num_elements; i++) {
 188        if (reg_array->r[i]->access->addr == addr) {
 189            reg = reg_array->r[i];
 190            break;
 191        }
 192    }
 193
 194    if (!reg) {
 195        qemu_log_mask(LOG_GUEST_ERROR, "%s: write to unimplemented register " \
 196                      "at address: 0x%" PRIx64 "\n", reg_array->prefix, addr);
 197        return;
 198    }
 199
 200    /* Generate appropriate write enable mask */
 201    we = register_enabled_mask(reg->data_size, size);
 202
 203    register_write(reg, value, we, reg_array->prefix,
 204                   reg_array->debug);
 205}
 206
 207uint64_t register_read_memory(void *opaque, hwaddr addr,
 208                              unsigned size)
 209{
 210    RegisterInfoArray *reg_array = opaque;
 211    RegisterInfo *reg = NULL;
 212    uint64_t read_val;
 213    uint64_t re;
 214    int i;
 215
 216    for (i = 0; i < reg_array->num_elements; i++) {
 217        if (reg_array->r[i]->access->addr == addr) {
 218            reg = reg_array->r[i];
 219            break;
 220        }
 221    }
 222
 223    if (!reg) {
 224        qemu_log_mask(LOG_GUEST_ERROR, "%s:  read to unimplemented register " \
 225                      "at address: 0x%" PRIx64 "\n", reg_array->prefix, addr);
 226        return 0;
 227    }
 228
 229    /* Generate appropriate read enable mask */
 230    re = register_enabled_mask(reg->data_size, size);
 231
 232    read_val = register_read(reg, re, reg_array->prefix,
 233                             reg_array->debug);
 234
 235    return extract64(read_val, 0, size * 8);
 236}
 237
 238static RegisterInfoArray *register_init_block(DeviceState *owner,
 239                                              const RegisterAccessInfo *rae,
 240                                              int num, RegisterInfo *ri,
 241                                              void *data,
 242                                              const MemoryRegionOps *ops,
 243                                              bool debug_enabled,
 244                                              uint64_t memory_size,
 245                                              size_t data_size_bits)
 246{
 247    const char *device_prefix = object_get_typename(OBJECT(owner));
 248    RegisterInfoArray *r_array = g_new0(RegisterInfoArray, 1);
 249    int data_size = data_size_bits >> 3;
 250    int i;
 251
 252    r_array->r = g_new0(RegisterInfo *, num);
 253    r_array->num_elements = num;
 254    r_array->debug = debug_enabled;
 255    r_array->prefix = device_prefix;
 256
 257    for (i = 0; i < num; i++) {
 258        int index = rae[i].addr / data_size;
 259        RegisterInfo *r = &ri[index];
 260
 261        /* Init the register, this will zero it. */
 262        object_initialize((void *)r, sizeof(*r), TYPE_REGISTER);
 263
 264        /* Set the properties of the register */
 265        r->data = data + data_size * index;
 266        r->data_size = data_size;
 267        r->access = &rae[i];
 268        r->opaque = owner;
 269
 270        r_array->r[i] = r;
 271    }
 272
 273    memory_region_init_io(&r_array->mem, OBJECT(owner), ops, r_array,
 274                          device_prefix, memory_size);
 275
 276    return r_array;
 277}
 278
 279RegisterInfoArray *register_init_block8(DeviceState *owner,
 280                                        const RegisterAccessInfo *rae,
 281                                        int num, RegisterInfo *ri,
 282                                        uint8_t *data,
 283                                        const MemoryRegionOps *ops,
 284                                        bool debug_enabled,
 285                                        uint64_t memory_size)
 286{
 287    return register_init_block(owner, rae, num, ri, (void *)
 288                               data, ops, debug_enabled, memory_size, 8);
 289}
 290
 291RegisterInfoArray *register_init_block32(DeviceState *owner,
 292                                         const RegisterAccessInfo *rae,
 293                                         int num, RegisterInfo *ri,
 294                                         uint32_t *data,
 295                                         const MemoryRegionOps *ops,
 296                                         bool debug_enabled,
 297                                         uint64_t memory_size)
 298{
 299    return register_init_block(owner, rae, num, ri, (void *)
 300                               data, ops, debug_enabled, memory_size, 32);
 301}
 302
 303RegisterInfoArray *register_init_block64(DeviceState *owner,
 304                                         const RegisterAccessInfo *rae,
 305                                         int num, RegisterInfo *ri,
 306                                         uint64_t *data,
 307                                         const MemoryRegionOps *ops,
 308                                         bool debug_enabled,
 309                                         uint64_t memory_size)
 310{
 311    return register_init_block(owner, rae, num, ri, (void *)
 312                               data, ops, debug_enabled, memory_size, 64);
 313}
 314
 315void register_finalize_block(RegisterInfoArray *r_array)
 316{
 317    object_unparent(OBJECT(&r_array->mem));
 318    g_free(r_array->r);
 319    g_free(r_array);
 320}
 321
 322static void register_class_init(ObjectClass *oc, void *data)
 323{
 324    DeviceClass *dc = DEVICE_CLASS(oc);
 325
 326    /* Reason: needs to be wired up to work */
 327    dc->user_creatable = false;
 328}
 329
 330static const TypeInfo register_info = {
 331    .name  = TYPE_REGISTER,
 332    .parent = TYPE_DEVICE,
 333    .class_init = register_class_init,
 334    .instance_size = sizeof(RegisterInfo),
 335};
 336
 337static void register_register_types(void)
 338{
 339    type_register_static(&register_info);
 340}
 341
 342type_init(register_register_types)
 343