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