| 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/core/register.h" |
| 20 | #include "qemu/log.h" |
| 21 | #include "qemu/module.h" |
| 22 | |
| 23 | static 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 | |
| 45 | static 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 | |
| 62 | static 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 | |
| 71 | void 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 | |
| 126 | uint64_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 | |
| 160 | void 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 | |
| 179 | void 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 | |
| 207 | uint64_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 | |
| 238 | static 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 | Object *obj; |
| 249 | RegisterInfoArray *r_array; |
| 250 | int data_size = data_size_bits >> 3; |
| 251 | int i; |
| 252 | |
| 253 | obj = object_new(TYPE_REGISTER_ARRAY); |
| 254 | object_property_add_child(OBJECT(owner), "reg-array[*]", obj); |
| 255 | object_unref(obj); |
| 256 | |
| 257 | r_array = REGISTER_ARRAY(obj); |
| 258 | r_array->r = g_new0(RegisterInfo *, num); |
| 259 | r_array->num_elements = num; |
| 260 | r_array->debug = debug_enabled; |
| 261 | r_array->prefix = device_prefix; |
| 262 | |
| 263 | for (i = 0; i < num; i++) { |
| 264 | int index = rae[i].addr / data_size; |
| 265 | RegisterInfo *r = &ri[index]; |
| 266 | |
| 267 | /* Set the properties of the register */ |
| 268 | r->data = data + data_size * index; |
| 269 | r->data_size = data_size; |
| 270 | r->access = &rae[i]; |
| 271 | r->opaque = owner; |
| 272 | |
| 273 | r_array->r[i] = r; |
| 274 | } |
| 275 | |
| 276 | memory_region_init_io(&r_array->mem, OBJECT(r_array), ops, r_array, |
| 277 | device_prefix, memory_size); |
| 278 | |
| 279 | return r_array; |
| 280 | } |
| 281 | |
| 282 | RegisterInfoArray *register_init_block8(DeviceState *owner, |
| 283 | const RegisterAccessInfo *rae, |
| 284 | int num, RegisterInfo *ri, |
| 285 | uint8_t *data, |
| 286 | const MemoryRegionOps *ops, |
| 287 | bool debug_enabled, |
| 288 | uint64_t memory_size) |
| 289 | { |
| 290 | return register_init_block(owner, rae, num, ri, (void *) |
| 291 | data, ops, debug_enabled, memory_size, 8); |
| 292 | } |
| 293 | |
| 294 | RegisterInfoArray *register_init_block32(DeviceState *owner, |
| 295 | const RegisterAccessInfo *rae, |
| 296 | int num, RegisterInfo *ri, |
| 297 | uint32_t *data, |
| 298 | const MemoryRegionOps *ops, |
| 299 | bool debug_enabled, |
| 300 | uint64_t memory_size) |
| 301 | { |
| 302 | return register_init_block(owner, rae, num, ri, (void *) |
| 303 | data, ops, debug_enabled, memory_size, 32); |
| 304 | } |
| 305 | |
| 306 | RegisterInfoArray *register_init_block64(DeviceState *owner, |
| 307 | const RegisterAccessInfo *rae, |
| 308 | int num, RegisterInfo *ri, |
| 309 | uint64_t *data, |
| 310 | const MemoryRegionOps *ops, |
| 311 | bool debug_enabled, |
| 312 | uint64_t memory_size) |
| 313 | { |
| 314 | return register_init_block(owner, rae, num, ri, (void *) |
| 315 | data, ops, debug_enabled, memory_size, 64); |
| 316 | } |
| 317 | |
| 318 | static void register_array_finalize(Object *obj) |
| 319 | { |
| 320 | RegisterInfoArray *r_array = REGISTER_ARRAY(obj); |
| 321 | |
| 322 | g_free(r_array->r); |
| 323 | } |
| 324 | |
| 325 | DeviceState *register_array_get_owner(const RegisterInfoArray *reg_array) |
| 326 | { |
| 327 | return DEVICE(OBJECT(reg_array)->parent); |
| 328 | } |
| 329 | |
| 330 | static const TypeInfo register_array_info = { |
| 331 | .name = TYPE_REGISTER_ARRAY, |
| 332 | .parent = TYPE_OBJECT, |
| 333 | .instance_size = sizeof(RegisterInfoArray), |
| 334 | .instance_finalize = register_array_finalize, |
| 335 | }; |
| 336 | |
| 337 | static void register_register_types(void) |
| 338 | { |
| 339 | type_register_static(®ister_array_info); |
| 340 | } |
| 341 | |
| 342 | type_init(register_register_types) |