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 "hw/qdev.h"
  21#include "qemu/log.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: %#" 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: %#" PRIx64 ")\n", prefix, test);
  93    }
  94
  95    test = val & ac->unimp;
  96    if (test) {
  97        qemu_log_mask(LOG_UNIMP,
  98                      "%s:%s writing %#" PRIx64 " to unimplemented bits:" \
  99                      " %#" PRIx64 "",
 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 %#" 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 %#" 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_init(RegisterInfo *reg)
 180{
 181    assert(reg);
 182
 183    if (!reg->data || !reg->access) {
 184        return;
 185    }
 186
 187    object_initialize((void *)reg, sizeof(*reg), TYPE_REGISTER);
 188}
 189
 190void register_write_memory(void *opaque, hwaddr addr,
 191                           uint64_t value, unsigned size)
 192{
 193    RegisterInfoArray *reg_array = opaque;
 194    RegisterInfo *reg = NULL;
 195    uint64_t we;
 196    int i;
 197
 198    for (i = 0; i < reg_array->num_elements; i++) {
 199        if (reg_array->r[i]->access->addr == addr) {
 200            reg = reg_array->r[i];
 201            break;
 202        }
 203    }
 204
 205    if (!reg) {
 206        qemu_log_mask(LOG_GUEST_ERROR, "%s: write to unimplemented register " \
 207                      "at address: %#" PRIx64 "\n", reg_array->prefix, addr);
 208        return;
 209    }
 210
 211    /* Generate appropriate write enable mask */
 212    we = register_enabled_mask(reg->data_size, size);
 213
 214    register_write(reg, value, we, reg_array->prefix,
 215                   reg_array->debug);
 216}
 217
 218uint64_t register_read_memory(void *opaque, hwaddr addr,
 219                              unsigned size)
 220{
 221    RegisterInfoArray *reg_array = opaque;
 222    RegisterInfo *reg = NULL;
 223    uint64_t read_val;
 224    uint64_t re;
 225    int i;
 226
 227    for (i = 0; i < reg_array->num_elements; i++) {
 228        if (reg_array->r[i]->access->addr == addr) {
 229            reg = reg_array->r[i];
 230            break;
 231        }
 232    }
 233
 234    if (!reg) {
 235        qemu_log_mask(LOG_GUEST_ERROR, "%s:  read to unimplemented register " \
 236                      "at address: %#" PRIx64 "\n", reg_array->prefix, addr);
 237        return 0;
 238    }
 239
 240    /* Generate appropriate read enable mask */
 241    re = register_enabled_mask(reg->data_size, size);
 242
 243    read_val = register_read(reg, re, reg_array->prefix,
 244                             reg_array->debug);
 245
 246    return extract64(read_val, 0, size * 8);
 247}
 248
 249RegisterInfoArray *register_init_block32(DeviceState *owner,
 250                                         const RegisterAccessInfo *rae,
 251                                         int num, RegisterInfo *ri,
 252                                         uint32_t *data,
 253                                         const MemoryRegionOps *ops,
 254                                         bool debug_enabled,
 255                                         uint64_t memory_size)
 256{
 257    const char *device_prefix = object_get_typename(OBJECT(owner));
 258    RegisterInfoArray *r_array = g_new0(RegisterInfoArray, 1);
 259    int i;
 260
 261    r_array->r = g_new0(RegisterInfo *, num);
 262    r_array->num_elements = num;
 263    r_array->debug = debug_enabled;
 264    r_array->prefix = device_prefix;
 265
 266    for (i = 0; i < num; i++) {
 267        int index = rae[i].addr / 4;
 268        RegisterInfo *r = &ri[index];
 269
 270        *r = (RegisterInfo) {
 271            .data = &data[index],
 272            .data_size = sizeof(uint32_t),
 273            .access = &rae[i],
 274            .opaque = owner,
 275        };
 276        register_init(r);
 277
 278        r_array->r[i] = r;
 279    }
 280
 281    memory_region_init_io(&r_array->mem, OBJECT(owner), ops, r_array,
 282                          device_prefix, memory_size);
 283
 284    return r_array;
 285}
 286
 287void register_finalize_block(RegisterInfoArray *r_array)
 288{
 289    object_unparent(OBJECT(&r_array->mem));
 290    g_free(r_array->r);
 291    g_free(r_array);
 292}
 293
 294static void register_class_init(ObjectClass *oc, void *data)
 295{
 296    DeviceClass *dc = DEVICE_CLASS(oc);
 297
 298    /* Reason: needs to be wired up to work */
 299    dc->user_creatable = false;
 300}
 301
 302static const TypeInfo register_info = {
 303    .name  = TYPE_REGISTER,
 304    .parent = TYPE_DEVICE,
 305    .class_init = register_class_init,
 306};
 307
 308static void register_register_types(void)
 309{
 310    type_register_static(&register_info);
 311}
 312
 313type_init(register_register_types)
 314