1 /*
2 * RISC-V ACLINT (Advanced Core Local Interruptor)
3 * URL: https://github.com/riscv/riscv-aclint
4 *
5 * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
6 * Copyright (c) 2017 SiFive, Inc.
7 * Copyright (c) 2021 Western Digital Corporation or its affiliates.
8 *
9 * This provides real-time clock, timer and interprocessor interrupts.
10 *
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms and conditions of the GNU General Public License,
13 * version 2 or later, as published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 * more details.
19 *
20 * You should have received a copy of the GNU General Public License along with
21 * this program. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "qemu/osdep.h"
25 #include "qapi/error.h"
26 #include "qemu/error-report.h"
27 #include "qemu/log.h"
28 #include "qemu/module.h"
29 #include "hw/sysbus.h"
30 #include "target/riscv/cpu.h"
31 #include "target/riscv/time_helper.h"
32 #include "hw/qdev-properties.h"
33 #include "hw/intc/riscv_aclint.h"
34 #include "qemu/timer.h"
35 #include "hw/irq.h"
36 #include "migration/vmstate.h"
37
38 typedef struct riscv_aclint_mtimer_callback {
39 RISCVAclintMTimerState *s;
40 int num;
41 } riscv_aclint_mtimer_callback;
42
cpu_riscv_read_rtc_raw(uint32_t timebase_freq)43 static uint64_t cpu_riscv_read_rtc_raw(uint32_t timebase_freq)
44 {
45 return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
46 timebase_freq, NANOSECONDS_PER_SECOND);
47 }
48
cpu_riscv_read_rtc(void * opaque)49 static uint64_t cpu_riscv_read_rtc(void *opaque)
50 {
51 RISCVAclintMTimerState *mtimer = opaque;
52 return cpu_riscv_read_rtc_raw(mtimer->timebase_freq) + mtimer->time_delta;
53 }
54
55 /*
56 * Called when timecmp is written to update the QEMU timer or immediately
57 * trigger timer interrupt if mtimecmp <= current timer value.
58 */
riscv_aclint_mtimer_write_timecmp(RISCVAclintMTimerState * mtimer,RISCVCPU * cpu,int hartid,uint64_t value)59 static void riscv_aclint_mtimer_write_timecmp(RISCVAclintMTimerState *mtimer,
60 RISCVCPU *cpu,
61 int hartid,
62 uint64_t value)
63 {
64 uint32_t timebase_freq = mtimer->timebase_freq;
65 uint64_t next;
66 uint64_t diff;
67
68 uint64_t rtc = cpu_riscv_read_rtc(mtimer);
69
70 /* Compute the relative hartid w.r.t the socket */
71 hartid = hartid - mtimer->hartid_base;
72
73 mtimer->timecmp[hartid] = value;
74 if (mtimer->timecmp[hartid] <= rtc) {
75 /*
76 * If we're setting an MTIMECMP value in the "past",
77 * immediately raise the timer interrupt
78 */
79 qemu_irq_raise(mtimer->timer_irqs[hartid]);
80 return;
81 }
82
83 /* otherwise, set up the future timer interrupt */
84 qemu_irq_lower(mtimer->timer_irqs[hartid]);
85 diff = mtimer->timecmp[hartid] - rtc;
86 /* back to ns (note args switched in muldiv64) */
87 uint64_t ns_diff = muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
88
89 /*
90 * check if ns_diff overflowed and check if the addition would potentially
91 * overflow
92 */
93 if ((NANOSECONDS_PER_SECOND > timebase_freq && ns_diff < diff) ||
94 ns_diff > INT64_MAX) {
95 next = INT64_MAX;
96 } else {
97 /*
98 * as it is very unlikely qemu_clock_get_ns will return a value
99 * greater than INT64_MAX, no additional check is needed for an
100 * unsigned integer overflow.
101 */
102 next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ns_diff;
103 /*
104 * if ns_diff is INT64_MAX next may still be outside the range
105 * of a signed integer.
106 */
107 next = MIN(next, INT64_MAX);
108 }
109
110 timer_mod(mtimer->timers[hartid], next);
111 }
112
113 /*
114 * Callback used when the timer set using timer_mod expires.
115 * Should raise the timer interrupt line
116 */
riscv_aclint_mtimer_cb(void * opaque)117 static void riscv_aclint_mtimer_cb(void *opaque)
118 {
119 riscv_aclint_mtimer_callback *state = opaque;
120
121 qemu_irq_raise(state->s->timer_irqs[state->num]);
122 }
123
124 /* CPU read MTIMER register */
riscv_aclint_mtimer_read(void * opaque,hwaddr addr,unsigned size)125 static uint64_t riscv_aclint_mtimer_read(void *opaque, hwaddr addr,
126 unsigned size)
127 {
128 RISCVAclintMTimerState *mtimer = opaque;
129
130 if (addr >= mtimer->timecmp_base &&
131 addr < (mtimer->timecmp_base + (mtimer->num_harts << 3))) {
132 size_t hartid = mtimer->hartid_base +
133 ((addr - mtimer->timecmp_base) >> 3);
134 CPUState *cpu = cpu_by_arch_id(hartid);
135 CPURISCVState *env = cpu ? cpu_env(cpu) : NULL;
136 if (!env) {
137 qemu_log_mask(LOG_GUEST_ERROR,
138 "aclint-mtimer: invalid hartid: %zu", hartid);
139 } else if ((addr & 0x7) == 0) {
140 /* timecmp_lo for RV32/RV64 or timecmp for RV64 */
141 uint64_t timecmp = mtimer->timecmp[hartid];
142 return (size == 4) ? (timecmp & 0xFFFFFFFF) : timecmp;
143 } else if ((addr & 0x7) == 4) {
144 /* timecmp_hi */
145 uint64_t timecmp = mtimer->timecmp[hartid];
146 return (timecmp >> 32) & 0xFFFFFFFF;
147 } else {
148 qemu_log_mask(LOG_UNIMP,
149 "aclint-mtimer: invalid read: %08x", (uint32_t)addr);
150 return 0;
151 }
152 } else if (addr == mtimer->time_base) {
153 /* time_lo for RV32/RV64 or timecmp for RV64 */
154 uint64_t rtc = cpu_riscv_read_rtc(mtimer);
155 return (size == 4) ? (rtc & 0xFFFFFFFF) : rtc;
156 } else if (addr == mtimer->time_base + 4) {
157 /* time_hi */
158 return (cpu_riscv_read_rtc(mtimer) >> 32) & 0xFFFFFFFF;
159 }
160
161 qemu_log_mask(LOG_UNIMP,
162 "aclint-mtimer: invalid read: %08x", (uint32_t)addr);
163 return 0;
164 }
165
166 /* CPU write MTIMER register */
riscv_aclint_mtimer_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)167 static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr,
168 uint64_t value, unsigned size)
169 {
170 RISCVAclintMTimerState *mtimer = opaque;
171 int i;
172
173 if (addr >= mtimer->timecmp_base &&
174 addr < (mtimer->timecmp_base + (mtimer->num_harts << 3))) {
175 size_t hartid = mtimer->hartid_base +
176 ((addr - mtimer->timecmp_base) >> 3);
177 CPUState *cpu = cpu_by_arch_id(hartid);
178 CPURISCVState *env = cpu ? cpu_env(cpu) : NULL;
179 if (!env) {
180 qemu_log_mask(LOG_GUEST_ERROR,
181 "aclint-mtimer: invalid hartid: %zu", hartid);
182 } else if ((addr & 0x7) == 0) {
183 if (size == 4) {
184 /* timecmp_lo for RV32/RV64 */
185 uint64_t timecmp_hi = mtimer->timecmp[hartid] >> 32;
186 riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu), hartid,
187 timecmp_hi << 32 | (value & 0xFFFFFFFF));
188 } else {
189 /* timecmp for RV64 */
190 riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu), hartid,
191 value);
192 }
193 } else if ((addr & 0x7) == 4) {
194 if (size == 4) {
195 /* timecmp_hi for RV32/RV64 */
196 uint64_t timecmp_lo = mtimer->timecmp[hartid];
197 riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu), hartid,
198 value << 32 | (timecmp_lo & 0xFFFFFFFF));
199 } else {
200 qemu_log_mask(LOG_GUEST_ERROR,
201 "aclint-mtimer: invalid timecmp_hi write: %08x",
202 (uint32_t)addr);
203 }
204 } else {
205 qemu_log_mask(LOG_UNIMP,
206 "aclint-mtimer: invalid timecmp write: %08x",
207 (uint32_t)addr);
208 }
209 return;
210 } else if (addr == mtimer->time_base || addr == mtimer->time_base + 4) {
211 uint64_t rtc_r = cpu_riscv_read_rtc_raw(mtimer->timebase_freq);
212 uint64_t rtc = cpu_riscv_read_rtc(mtimer);
213
214 if (addr == mtimer->time_base) {
215 if (size == 4) {
216 /* time_lo for RV32/RV64 */
217 mtimer->time_delta = ((rtc & ~0xFFFFFFFFULL) | value) - rtc_r;
218 } else {
219 /* time for RV64 */
220 mtimer->time_delta = value - rtc_r;
221 }
222 } else {
223 if (size == 4) {
224 /* time_hi for RV32/RV64 */
225 mtimer->time_delta = (value << 32 | (rtc & 0xFFFFFFFF)) - rtc_r;
226 } else {
227 qemu_log_mask(LOG_GUEST_ERROR,
228 "aclint-mtimer: invalid time_hi write: %08x",
229 (uint32_t)addr);
230 return;
231 }
232 }
233
234 /* Check if timer interrupt is triggered for each hart. */
235 for (i = 0; i < mtimer->num_harts; i++) {
236 CPUState *cpu = cpu_by_arch_id(mtimer->hartid_base + i);
237 CPURISCVState *env = cpu ? cpu_env(cpu) : NULL;
238 if (!env) {
239 continue;
240 }
241 riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu),
242 mtimer->hartid_base + i,
243 mtimer->timecmp[i]);
244 riscv_timer_write_timecmp(env, env->stimer, env->stimecmp, 0, MIP_STIP);
245 riscv_timer_write_timecmp(env, env->vstimer, env->vstimecmp,
246 env->htimedelta, MIP_VSTIP);
247
248 }
249 return;
250 }
251
252 qemu_log_mask(LOG_UNIMP,
253 "aclint-mtimer: invalid write: %08x", (uint32_t)addr);
254 }
255
256 static const MemoryRegionOps riscv_aclint_mtimer_ops = {
257 .read = riscv_aclint_mtimer_read,
258 .write = riscv_aclint_mtimer_write,
259 .endianness = DEVICE_LITTLE_ENDIAN,
260 .valid = {
261 .min_access_size = 4,
262 .max_access_size = 8
263 },
264 .impl = {
265 .min_access_size = 4,
266 .max_access_size = 8,
267 }
268 };
269
270 static const Property riscv_aclint_mtimer_properties[] = {
271 DEFINE_PROP_UINT32("hartid-base", RISCVAclintMTimerState,
272 hartid_base, 0),
273 DEFINE_PROP_UINT32("num-harts", RISCVAclintMTimerState, num_harts, 1),
274 DEFINE_PROP_UINT32("timecmp-base", RISCVAclintMTimerState,
275 timecmp_base, RISCV_ACLINT_DEFAULT_MTIMECMP),
276 DEFINE_PROP_UINT32("time-base", RISCVAclintMTimerState,
277 time_base, RISCV_ACLINT_DEFAULT_MTIME),
278 DEFINE_PROP_UINT32("aperture-size", RISCVAclintMTimerState,
279 aperture_size, RISCV_ACLINT_DEFAULT_MTIMER_SIZE),
280 DEFINE_PROP_UINT32("timebase-freq", RISCVAclintMTimerState,
281 timebase_freq, 0),
282 };
283
riscv_aclint_mtimer_realize(DeviceState * dev,Error ** errp)284 static void riscv_aclint_mtimer_realize(DeviceState *dev, Error **errp)
285 {
286 RISCVAclintMTimerState *s = RISCV_ACLINT_MTIMER(dev);
287 int i;
288
289 memory_region_init_io(&s->mmio, OBJECT(dev), &riscv_aclint_mtimer_ops,
290 s, TYPE_RISCV_ACLINT_MTIMER, s->aperture_size);
291 sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
292
293 s->timer_irqs = g_new(qemu_irq, s->num_harts);
294 qdev_init_gpio_out(dev, s->timer_irqs, s->num_harts);
295
296 s->timers = g_new0(QEMUTimer *, s->num_harts);
297 s->timecmp = g_new0(uint64_t, s->num_harts);
298 /* Claim timer interrupt bits */
299 for (i = 0; i < s->num_harts; i++) {
300 RISCVCPU *cpu = RISCV_CPU(cpu_by_arch_id(s->hartid_base + i));
301 if (riscv_cpu_claim_interrupts(cpu, MIP_MTIP) < 0) {
302 error_report("MTIP already claimed");
303 exit(1);
304 }
305 }
306 }
307
riscv_aclint_mtimer_reset_enter(Object * obj,ResetType type)308 static void riscv_aclint_mtimer_reset_enter(Object *obj, ResetType type)
309 {
310 /*
311 * According to RISC-V ACLINT spec:
312 * - On MTIMER device reset, the MTIME register is cleared to zero.
313 * - On MTIMER device reset, the MTIMECMP registers are in unknown state.
314 */
315 RISCVAclintMTimerState *mtimer = RISCV_ACLINT_MTIMER(obj);
316
317 /*
318 * Clear mtime register by writing to 0 it.
319 * Pending mtime interrupts will also be cleared at the same time.
320 */
321 riscv_aclint_mtimer_write(mtimer, mtimer->time_base, 0, 8);
322 }
323
324 static const VMStateDescription vmstate_riscv_mtimer = {
325 .name = "riscv_mtimer",
326 .version_id = 1,
327 .minimum_version_id = 1,
328 .fields = (const VMStateField[]) {
329 VMSTATE_VARRAY_UINT32(timecmp, RISCVAclintMTimerState,
330 num_harts, 0,
331 vmstate_info_uint64, uint64_t),
332 VMSTATE_END_OF_LIST()
333 }
334 };
335
riscv_aclint_mtimer_class_init(ObjectClass * klass,const void * data)336 static void riscv_aclint_mtimer_class_init(ObjectClass *klass, const void *data)
337 {
338 DeviceClass *dc = DEVICE_CLASS(klass);
339 dc->realize = riscv_aclint_mtimer_realize;
340 device_class_set_props(dc, riscv_aclint_mtimer_properties);
341 ResettableClass *rc = RESETTABLE_CLASS(klass);
342 rc->phases.enter = riscv_aclint_mtimer_reset_enter;
343 dc->vmsd = &vmstate_riscv_mtimer;
344 }
345
346 static const TypeInfo riscv_aclint_mtimer_info = {
347 .name = TYPE_RISCV_ACLINT_MTIMER,
348 .parent = TYPE_SYS_BUS_DEVICE,
349 .instance_size = sizeof(RISCVAclintMTimerState),
350 .class_init = riscv_aclint_mtimer_class_init,
351 };
352
353 /*
354 * Create ACLINT MTIMER device.
355 */
riscv_aclint_mtimer_create(hwaddr addr,hwaddr size,uint32_t hartid_base,uint32_t num_harts,uint32_t timecmp_base,uint32_t time_base,uint32_t timebase_freq,bool provide_rdtime)356 DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size,
357 uint32_t hartid_base, uint32_t num_harts,
358 uint32_t timecmp_base, uint32_t time_base, uint32_t timebase_freq,
359 bool provide_rdtime)
360 {
361 int i;
362 DeviceState *dev = qdev_new(TYPE_RISCV_ACLINT_MTIMER);
363 RISCVAclintMTimerState *s = RISCV_ACLINT_MTIMER(dev);
364
365 assert(num_harts <= RISCV_ACLINT_MAX_HARTS);
366 assert(!(addr & 0x7));
367 assert(!(timecmp_base & 0x7));
368 assert(!(time_base & 0x7));
369
370 qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
371 qdev_prop_set_uint32(dev, "num-harts", num_harts);
372 qdev_prop_set_uint32(dev, "timecmp-base", timecmp_base);
373 qdev_prop_set_uint32(dev, "time-base", time_base);
374 qdev_prop_set_uint32(dev, "aperture-size", size);
375 qdev_prop_set_uint32(dev, "timebase-freq", timebase_freq);
376 sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
377 sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
378
379 for (i = 0; i < num_harts; i++) {
380 CPUState *cpu = cpu_by_arch_id(hartid_base + i);
381 RISCVCPU *rvcpu = RISCV_CPU(cpu);
382 CPURISCVState *env = cpu ? cpu_env(cpu) : NULL;
383 riscv_aclint_mtimer_callback *cb =
384 g_new0(riscv_aclint_mtimer_callback, 1);
385
386 if (!env) {
387 g_free(cb);
388 continue;
389 }
390 if (provide_rdtime) {
391 riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, dev);
392 }
393
394 cb->s = s;
395 cb->num = i;
396 s->timers[i] = timer_new_ns(QEMU_CLOCK_VIRTUAL,
397 &riscv_aclint_mtimer_cb, cb);
398 s->timecmp[i] = 0;
399
400 qdev_connect_gpio_out(dev, i,
401 qdev_get_gpio_in(DEVICE(rvcpu), IRQ_M_TIMER));
402 }
403
404 return dev;
405 }
406
407 /* CPU read [M|S]SWI register */
riscv_aclint_swi_read(void * opaque,hwaddr addr,unsigned size)408 static uint64_t riscv_aclint_swi_read(void *opaque, hwaddr addr,
409 unsigned size)
410 {
411 RISCVAclintSwiState *swi = opaque;
412
413 if (addr < (swi->num_harts << 2)) {
414 size_t hartid = swi->hartid_base + (addr >> 2);
415 CPUState *cpu = cpu_by_arch_id(hartid);
416 CPURISCVState *env = cpu ? cpu_env(cpu) : NULL;
417 if (!env) {
418 qemu_log_mask(LOG_GUEST_ERROR,
419 "aclint-swi: invalid hartid: %zu", hartid);
420 } else if ((addr & 0x3) == 0) {
421 return (swi->sswi) ? 0 : ((env->mip & MIP_MSIP) > 0);
422 }
423 }
424
425 qemu_log_mask(LOG_UNIMP,
426 "aclint-swi: invalid read: %08x", (uint32_t)addr);
427 return 0;
428 }
429
430 /* CPU write [M|S]SWI register */
riscv_aclint_swi_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)431 static void riscv_aclint_swi_write(void *opaque, hwaddr addr, uint64_t value,
432 unsigned size)
433 {
434 RISCVAclintSwiState *swi = opaque;
435
436 if (addr < (swi->num_harts << 2)) {
437 size_t hartid = swi->hartid_base + (addr >> 2);
438 CPUState *cpu = cpu_by_arch_id(hartid);
439 CPURISCVState *env = cpu ? cpu_env(cpu) : NULL;
440 if (!env) {
441 qemu_log_mask(LOG_GUEST_ERROR,
442 "aclint-swi: invalid hartid: %zu", hartid);
443 } else if ((addr & 0x3) == 0) {
444 if (value & 0x1) {
445 qemu_irq_raise(swi->soft_irqs[hartid - swi->hartid_base]);
446 } else {
447 if (!swi->sswi) {
448 qemu_irq_lower(swi->soft_irqs[hartid - swi->hartid_base]);
449 }
450 }
451 return;
452 }
453 }
454
455 qemu_log_mask(LOG_UNIMP,
456 "aclint-swi: invalid write: %08x", (uint32_t)addr);
457 }
458
459 static const MemoryRegionOps riscv_aclint_swi_ops = {
460 .read = riscv_aclint_swi_read,
461 .write = riscv_aclint_swi_write,
462 .endianness = DEVICE_LITTLE_ENDIAN,
463 .valid = {
464 .min_access_size = 4,
465 .max_access_size = 4
466 }
467 };
468
469 static const Property riscv_aclint_swi_properties[] = {
470 DEFINE_PROP_UINT32("hartid-base", RISCVAclintSwiState, hartid_base, 0),
471 DEFINE_PROP_UINT32("num-harts", RISCVAclintSwiState, num_harts, 1),
472 DEFINE_PROP_UINT32("sswi", RISCVAclintSwiState, sswi, false),
473 };
474
riscv_aclint_swi_realize(DeviceState * dev,Error ** errp)475 static void riscv_aclint_swi_realize(DeviceState *dev, Error **errp)
476 {
477 RISCVAclintSwiState *swi = RISCV_ACLINT_SWI(dev);
478 int i;
479
480 memory_region_init_io(&swi->mmio, OBJECT(dev), &riscv_aclint_swi_ops, swi,
481 TYPE_RISCV_ACLINT_SWI, RISCV_ACLINT_SWI_SIZE);
482 sysbus_init_mmio(SYS_BUS_DEVICE(dev), &swi->mmio);
483
484 swi->soft_irqs = g_new(qemu_irq, swi->num_harts);
485 qdev_init_gpio_out(dev, swi->soft_irqs, swi->num_harts);
486
487 /* Claim software interrupt bits */
488 for (i = 0; i < swi->num_harts; i++) {
489 RISCVCPU *cpu = RISCV_CPU(qemu_get_cpu(swi->hartid_base + i));
490 /* We don't claim mip.SSIP because it is writable by software */
491 if (riscv_cpu_claim_interrupts(cpu, swi->sswi ? 0 : MIP_MSIP) < 0) {
492 error_report("MSIP already claimed");
493 exit(1);
494 }
495 }
496 }
497
riscv_aclint_swi_reset_enter(Object * obj,ResetType type)498 static void riscv_aclint_swi_reset_enter(Object *obj, ResetType type)
499 {
500 /*
501 * According to RISC-V ACLINT spec:
502 * - On MSWI device reset, each MSIP register is cleared to zero.
503 *
504 * p.s. SSWI device reset does nothing since SETSIP register always reads 0.
505 */
506 RISCVAclintSwiState *swi = RISCV_ACLINT_SWI(obj);
507 int i;
508
509 if (!swi->sswi) {
510 for (i = 0; i < swi->num_harts; i++) {
511 /* Clear MSIP registers by lowering software interrupts. */
512 qemu_irq_lower(swi->soft_irqs[i]);
513 }
514 }
515 }
516
riscv_aclint_swi_class_init(ObjectClass * klass,const void * data)517 static void riscv_aclint_swi_class_init(ObjectClass *klass, const void *data)
518 {
519 DeviceClass *dc = DEVICE_CLASS(klass);
520 dc->realize = riscv_aclint_swi_realize;
521 device_class_set_props(dc, riscv_aclint_swi_properties);
522 ResettableClass *rc = RESETTABLE_CLASS(klass);
523 rc->phases.enter = riscv_aclint_swi_reset_enter;
524 }
525
526 static const TypeInfo riscv_aclint_swi_info = {
527 .name = TYPE_RISCV_ACLINT_SWI,
528 .parent = TYPE_SYS_BUS_DEVICE,
529 .instance_size = sizeof(RISCVAclintSwiState),
530 .class_init = riscv_aclint_swi_class_init,
531 };
532
533 /*
534 * Create ACLINT [M|S]SWI device.
535 */
riscv_aclint_swi_create(hwaddr addr,uint32_t hartid_base,uint32_t num_harts,bool sswi)536 DeviceState *riscv_aclint_swi_create(hwaddr addr, uint32_t hartid_base,
537 uint32_t num_harts, bool sswi)
538 {
539 int i;
540 DeviceState *dev = qdev_new(TYPE_RISCV_ACLINT_SWI);
541
542 assert(num_harts <= RISCV_ACLINT_MAX_HARTS);
543 assert(!(addr & 0x3));
544
545 qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
546 qdev_prop_set_uint32(dev, "num-harts", num_harts);
547 qdev_prop_set_uint32(dev, "sswi", sswi ? true : false);
548 sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
549 sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
550
551 for (i = 0; i < num_harts; i++) {
552 CPUState *cpu = cpu_by_arch_id(hartid_base + i);
553 RISCVCPU *rvcpu = RISCV_CPU(cpu);
554
555 qdev_connect_gpio_out(dev, i,
556 qdev_get_gpio_in(DEVICE(rvcpu),
557 (sswi) ? IRQ_S_SOFT : IRQ_M_SOFT));
558 }
559
560 return dev;
561 }
562
riscv_aclint_register_types(void)563 static void riscv_aclint_register_types(void)
564 {
565 type_register_static(&riscv_aclint_mtimer_info);
566 type_register_static(&riscv_aclint_swi_info);
567 }
568
569 type_init(riscv_aclint_register_types)
570