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