xref: /qemu/hw/core/register.c (revision 85aad98a)
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 
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 void 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 
117 uint64_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 
151 void 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 
162 void 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 
173 void 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 
205 uint64_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 
232 RegisterInfoArray *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 
270 void 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 
277 static const TypeInfo register_info = {
278     .name  = TYPE_REGISTER,
279     .parent = TYPE_DEVICE,
280 };
281 
282 static void register_register_types(void)
283 {
284     type_register_static(&register_info);
285 }
286 
287 type_init(register_register_types)
288