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