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#include "qemu/module.h"
  23
  24static inline void register_write_val(RegisterInfo *reg, uint64_t val)
  25{
  26    g_assert(reg->data);
  27
  28    switch (reg->data_size) {
  29    case 1:
  30        *(uint8_t *)reg->data = val;
  31        break;
  32    case 2:
  33        *(uint16_t *)reg->data = val;
  34        break;
  35    case 4:
  36        *(uint32_t *)reg->data = val;
  37        break;
  38    case 8:
  39        *(uint64_t *)reg->data = val;
  40        break;
  41    default:
  42        g_assert_not_reached();
  43    }
  44}
  45
  46static inline uint64_t register_read_val(RegisterInfo *reg)
  47{
  48    switch (reg->data_size) {
  49    case 1:
  50        return *(uint8_t *)reg->data;
  51    case 2:
  52        return *(uint16_t *)reg->data;
  53    case 4:
  54        return *(uint32_t *)reg->data;
  55    case 8:
  56        return *(uint64_t *)reg->data;
  57    default:
  58        g_assert_not_reached();
  59    }
  60    return 0; /* unreachable */
  61}
  62
  63static inline uint64_t register_enabled_mask(int data_size, unsigned size)
  64{
  65    if (data_size < size) {
  66        size = data_size;
  67    }
  68
  69    return MAKE_64BIT_MASK(0, size * 8);
  70}
  71
  72void register_write(RegisterInfo *reg, uint64_t val, uint64_t we,
  73                    const char *prefix, bool debug)
  74{
  75    uint64_t old_val, new_val, test, no_w_mask;
  76    const RegisterAccessInfo *ac;
  77
  78    assert(reg);
  79
  80    ac = reg->access;
  81
  82    if (!ac || !ac->name) {
  83        qemu_log_mask(LOG_GUEST_ERROR, "%s: write to undefined device state "
  84                      "(written value: %#" PRIx64 ")\n", prefix, val);
  85        return;
  86    }
  87
  88    old_val = reg->data ? register_read_val(reg) : ac->reset;
  89
  90    test = (old_val ^ val) & ac->rsvd;
  91    if (test) {
  92        qemu_log_mask(LOG_GUEST_ERROR, "%s: change of value in reserved bit"
  93                      "fields: %#" PRIx64 ")\n", prefix, test);
  94    }
  95
  96    test = val & ac->unimp;
  97    if (test) {
  98        qemu_log_mask(LOG_UNIMP,
  99                      "%s:%s writing %#" PRIx64 " to unimplemented bits:" \
 100                      " %#" PRIx64 "\n",
 101                      prefix, reg->access->name, val, ac->unimp);
 102    }
 103
 104    /* Create the no write mask based on the read only, write to clear and
 105     * reserved bit masks.
 106     */
 107    no_w_mask = ac->ro | ac->w1c | ac->rsvd | ~we;
 108    new_val = (val & ~no_w_mask) | (old_val & no_w_mask);
 109    new_val &= ~(val & ac->w1c);
 110
 111    if (ac->pre_write) {
 112        new_val = ac->pre_write(reg, new_val);
 113    }
 114
 115    if (debug) {
 116        qemu_log("%s:%s: write of value %#" PRIx64 "\n", prefix, ac->name,
 117                 new_val);
 118    }
 119
 120    register_write_val(reg, new_val);
 121
 122    if (ac->post_write) {
 123        ac->post_write(reg, new_val);
 124    }
 125}
 126
 127uint64_t register_read(RegisterInfo *reg, uint64_t re, const char* prefix,
 128                       bool debug)
 129{
 130    uint64_t ret;
 131    const RegisterAccessInfo *ac;
 132
 133    assert(reg);
 134
 135    ac = reg->access;
 136    if (!ac || !ac->name) {
 137        qemu_log_mask(LOG_GUEST_ERROR, "%s: read from undefined device state\n",
 138                      prefix);
 139        return 0;
 140    }
 141
 142    ret = reg->data ? register_read_val(reg) : ac->reset;
 143
 144    register_write_val(reg, ret & ~(ac->cor & re));
 145
 146    /* Mask based on the read enable size */
 147    ret &= re;
 148
 149    if (ac->post_read) {
 150        ret = ac->post_read(reg, ret);
 151    }
 152
 153    if (debug) {
 154        qemu_log("%s:%s: read of value %#" PRIx64 "\n", prefix,
 155                 ac->name, ret);
 156    }
 157
 158    return ret;
 159}
 160
 161void register_reset(RegisterInfo *reg)
 162{
 163    const RegisterAccessInfo *ac;
 164
 165    g_assert(reg);
 166
 167    if (!reg->data || !reg->access) {
 168        return;
 169    }
 170
 171    ac = reg->access;
 172
 173    register_write_val(reg, reg->access->reset);
 174
 175    if (ac->post_write) {
 176        ac->post_write(reg, reg->access->reset);
 177    }
 178}
 179
 180void register_init(RegisterInfo *reg)
 181{
 182    assert(reg);
 183
 184    if (!reg->data || !reg->access) {
 185        return;
 186    }
 187
 188    object_initialize((void *)reg, sizeof(*reg), TYPE_REGISTER);
 189}
 190
 191void register_write_memory(void *opaque, hwaddr addr,
 192                           uint64_t value, unsigned size)
 193{
 194    RegisterInfoArray *reg_array = opaque;
 195    RegisterInfo *reg = NULL;
 196    uint64_t we;
 197    int i;
 198
 199    for (i = 0; i < reg_array->num_elements; i++) {
 200        if (reg_array->r[i]->access->addr == addr) {
 201            reg = reg_array->r[i];
 202            break;
 203        }
 204    }
 205
 206    if (!reg) {
 207        qemu_log_mask(LOG_GUEST_ERROR, "%s: write to unimplemented register " \
 208                      "at address: %#" PRIx64 "\n", reg_array->prefix, addr);
 209        return;
 210    }
 211
 212    /* Generate appropriate write enable mask */
 213    we = register_enabled_mask(reg->data_size, size);
 214
 215    register_write(reg, value, we, reg_array->prefix,
 216                   reg_array->debug);
 217}
 218
 219uint64_t register_read_memory(void *opaque, hwaddr addr,
 220                              unsigned size)
 221{
 222    RegisterInfoArray *reg_array = opaque;
 223    RegisterInfo *reg = NULL;
 224    uint64_t read_val;
 225    uint64_t re;
 226    int i;
 227
 228    for (i = 0; i < reg_array->num_elements; i++) {
 229        if (reg_array->r[i]->access->addr == addr) {
 230            reg = reg_array->r[i];
 231            break;
 232        }
 233    }
 234
 235    if (!reg) {
 236        qemu_log_mask(LOG_GUEST_ERROR, "%s:  read to unimplemented register " \
 237                      "at address: %#" PRIx64 "\n", reg_array->prefix, addr);
 238        return 0;
 239    }
 240
 241    /* Generate appropriate read enable mask */
 242    re = register_enabled_mask(reg->data_size, size);
 243
 244    read_val = register_read(reg, re, reg_array->prefix,
 245                             reg_array->debug);
 246
 247    return extract64(read_val, 0, size * 8);
 248}
 249
 250RegisterInfoArray *register_init_block32(DeviceState *owner,
 251                                         const RegisterAccessInfo *rae,
 252                                         int num, RegisterInfo *ri,
 253                                         uint32_t *data,
 254                                         const MemoryRegionOps *ops,
 255                                         bool debug_enabled,
 256                                         uint64_t memory_size)
 257{
 258    const char *device_prefix = object_get_typename(OBJECT(owner));
 259    RegisterInfoArray *r_array = g_new0(RegisterInfoArray, 1);
 260    int i;
 261
 262    r_array->r = g_new0(RegisterInfo *, num);
 263    r_array->num_elements = num;
 264    r_array->debug = debug_enabled;
 265    r_array->prefix = device_prefix;
 266
 267    for (i = 0; i < num; i++) {
 268        int index = rae[i].addr / 4;
 269        RegisterInfo *r = &ri[index];
 270
 271        *r = (RegisterInfo) {
 272            .data = &data[index],
 273            .data_size = sizeof(uint32_t),
 274            .access = &rae[i],
 275            .opaque = owner,
 276        };
 277        register_init(r);
 278
 279        r_array->r[i] = r;
 280    }
 281
 282    memory_region_init_io(&r_array->mem, OBJECT(owner), ops, r_array,
 283                          device_prefix, memory_size);
 284
 285    return r_array;
 286}
 287
 288void register_finalize_block(RegisterInfoArray *r_array)
 289{
 290    object_unparent(OBJECT(&r_array->mem));
 291    g_free(r_array->r);
 292    g_free(r_array);
 293}
 294
 295static void register_class_init(ObjectClass *oc, void *data)
 296{
 297    DeviceClass *dc = DEVICE_CLASS(oc);
 298
 299    /* Reason: needs to be wired up to work */
 300    dc->user_creatable = false;
 301}
 302
 303static const TypeInfo register_info = {
 304    .name  = TYPE_REGISTER,
 305    .parent = TYPE_DEVICE,
 306    .class_init = register_class_init,
 307};
 308
 309static void register_register_types(void)
 310{
 311    type_register_static(&register_info);
 312}
 313
 314type_init(register_register_types)
 315