qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

riscv_aclint.c (19651B)


      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 
     37 typedef struct riscv_aclint_mtimer_callback {
     38     RISCVAclintMTimerState *s;
     39     int num;
     40 } riscv_aclint_mtimer_callback;
     41 
     42 static 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 
     48 static 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  */
     58 static 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  */
    116 static 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 */
    124 static 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 */
    166 static 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 
    250 static 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 
    264 static 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 
    279 static 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 
    303 static 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 
    319 static 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 
    331 static 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 
    341 static 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  */
    351 DeviceState *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 */
    403 static 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 */
    426 static 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 
    454 static 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 
    464 static 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 
    471 static 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 
    494 static 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 
    513 static 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 
    522 static 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  */
    532 DeviceState *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 
    559 static 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 
    565 type_init(riscv_aclint_register_types)