cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

xlnx-versal.c (18179B)


      1/*
      2 * Xilinx Versal SoC model.
      3 *
      4 * Copyright (c) 2018 Xilinx Inc.
      5 * Written by Edgar E. Iglesias
      6 *
      7 * This program is free software; you can redistribute it and/or modify
      8 * it under the terms of the GNU General Public License version 2 or
      9 * (at your option) any later version.
     10 */
     11
     12#include "qemu/osdep.h"
     13#include "qemu/units.h"
     14#include "qapi/error.h"
     15#include "qemu/module.h"
     16#include "hw/sysbus.h"
     17#include "net/net.h"
     18#include "sysemu/sysemu.h"
     19#include "sysemu/kvm.h"
     20#include "hw/arm/boot.h"
     21#include "kvm_arm.h"
     22#include "hw/misc/unimp.h"
     23#include "hw/arm/xlnx-versal.h"
     24
     25#define XLNX_VERSAL_ACPU_TYPE ARM_CPU_TYPE_NAME("cortex-a72")
     26#define GEM_REVISION        0x40070106
     27
     28static void versal_create_apu_cpus(Versal *s)
     29{
     30    int i;
     31
     32    for (i = 0; i < ARRAY_SIZE(s->fpd.apu.cpu); i++) {
     33        Object *obj;
     34
     35        object_initialize_child(OBJECT(s), "apu-cpu[*]", &s->fpd.apu.cpu[i],
     36                                XLNX_VERSAL_ACPU_TYPE);
     37        obj = OBJECT(&s->fpd.apu.cpu[i]);
     38        object_property_set_int(obj, "psci-conduit", s->cfg.psci_conduit,
     39                                &error_abort);
     40        if (i) {
     41            /* Secondary CPUs start in PSCI powered-down state */
     42            object_property_set_bool(obj, "start-powered-off", true,
     43                                     &error_abort);
     44        }
     45
     46        object_property_set_int(obj, "core-count", ARRAY_SIZE(s->fpd.apu.cpu),
     47                                &error_abort);
     48        object_property_set_link(obj, "memory", OBJECT(&s->fpd.apu.mr),
     49                                 &error_abort);
     50        qdev_realize(DEVICE(obj), NULL, &error_fatal);
     51    }
     52}
     53
     54static void versal_create_apu_gic(Versal *s, qemu_irq *pic)
     55{
     56    static const uint64_t addrs[] = {
     57        MM_GIC_APU_DIST_MAIN,
     58        MM_GIC_APU_REDIST_0
     59    };
     60    SysBusDevice *gicbusdev;
     61    DeviceState *gicdev;
     62    int nr_apu_cpus = ARRAY_SIZE(s->fpd.apu.cpu);
     63    int i;
     64
     65    object_initialize_child(OBJECT(s), "apu-gic", &s->fpd.apu.gic,
     66                            gicv3_class_name());
     67    gicbusdev = SYS_BUS_DEVICE(&s->fpd.apu.gic);
     68    gicdev = DEVICE(&s->fpd.apu.gic);
     69    qdev_prop_set_uint32(gicdev, "revision", 3);
     70    qdev_prop_set_uint32(gicdev, "num-cpu", nr_apu_cpus);
     71    qdev_prop_set_uint32(gicdev, "num-irq", XLNX_VERSAL_NR_IRQS + 32);
     72    qdev_prop_set_uint32(gicdev, "len-redist-region-count", 1);
     73    qdev_prop_set_uint32(gicdev, "redist-region-count[0]", nr_apu_cpus);
     74    qdev_prop_set_bit(gicdev, "has-security-extensions", true);
     75
     76    sysbus_realize(SYS_BUS_DEVICE(&s->fpd.apu.gic), &error_fatal);
     77
     78    for (i = 0; i < ARRAY_SIZE(addrs); i++) {
     79        MemoryRegion *mr;
     80
     81        mr = sysbus_mmio_get_region(gicbusdev, i);
     82        memory_region_add_subregion(&s->fpd.apu.mr, addrs[i], mr);
     83    }
     84
     85    for (i = 0; i < nr_apu_cpus; i++) {
     86        DeviceState *cpudev = DEVICE(&s->fpd.apu.cpu[i]);
     87        int ppibase = XLNX_VERSAL_NR_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS;
     88        qemu_irq maint_irq;
     89        int ti;
     90        /* Mapping from the output timer irq lines from the CPU to the
     91         * GIC PPI inputs.
     92         */
     93        const int timer_irq[] = {
     94            [GTIMER_PHYS] = VERSAL_TIMER_NS_EL1_IRQ,
     95            [GTIMER_VIRT] = VERSAL_TIMER_VIRT_IRQ,
     96            [GTIMER_HYP]  = VERSAL_TIMER_NS_EL2_IRQ,
     97            [GTIMER_SEC]  = VERSAL_TIMER_S_EL1_IRQ,
     98        };
     99
    100        for (ti = 0; ti < ARRAY_SIZE(timer_irq); ti++) {
    101            qdev_connect_gpio_out(cpudev, ti,
    102                                  qdev_get_gpio_in(gicdev,
    103                                                   ppibase + timer_irq[ti]));
    104        }
    105        maint_irq = qdev_get_gpio_in(gicdev,
    106                                        ppibase + VERSAL_GIC_MAINT_IRQ);
    107        qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt",
    108                                    0, maint_irq);
    109        sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
    110        sysbus_connect_irq(gicbusdev, i + nr_apu_cpus,
    111                           qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
    112        sysbus_connect_irq(gicbusdev, i + 2 * nr_apu_cpus,
    113                           qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
    114        sysbus_connect_irq(gicbusdev, i + 3 * nr_apu_cpus,
    115                           qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
    116    }
    117
    118    for (i = 0; i < XLNX_VERSAL_NR_IRQS; i++) {
    119        pic[i] = qdev_get_gpio_in(gicdev, i);
    120    }
    121}
    122
    123static void versal_create_uarts(Versal *s, qemu_irq *pic)
    124{
    125    int i;
    126
    127    for (i = 0; i < ARRAY_SIZE(s->lpd.iou.uart); i++) {
    128        static const int irqs[] = { VERSAL_UART0_IRQ_0, VERSAL_UART1_IRQ_0};
    129        static const uint64_t addrs[] = { MM_UART0, MM_UART1 };
    130        char *name = g_strdup_printf("uart%d", i);
    131        DeviceState *dev;
    132        MemoryRegion *mr;
    133
    134        object_initialize_child(OBJECT(s), name, &s->lpd.iou.uart[i],
    135                                TYPE_PL011);
    136        dev = DEVICE(&s->lpd.iou.uart[i]);
    137        qdev_prop_set_chr(dev, "chardev", serial_hd(i));
    138        sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
    139
    140        mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
    141        memory_region_add_subregion(&s->mr_ps, addrs[i], mr);
    142
    143        sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[irqs[i]]);
    144        g_free(name);
    145    }
    146}
    147
    148static void versal_create_usbs(Versal *s, qemu_irq *pic)
    149{
    150    DeviceState *dev;
    151    MemoryRegion *mr;
    152
    153    object_initialize_child(OBJECT(s), "usb2", &s->lpd.iou.usb,
    154                            TYPE_XILINX_VERSAL_USB2);
    155    dev = DEVICE(&s->lpd.iou.usb);
    156
    157    object_property_set_link(OBJECT(dev), "dma", OBJECT(&s->mr_ps),
    158                             &error_abort);
    159    qdev_prop_set_uint32(dev, "intrs", 1);
    160    qdev_prop_set_uint32(dev, "slots", 2);
    161
    162    sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
    163
    164    mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
    165    memory_region_add_subregion(&s->mr_ps, MM_USB_0, mr);
    166
    167    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[VERSAL_USB0_IRQ_0]);
    168
    169    mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
    170    memory_region_add_subregion(&s->mr_ps, MM_USB2_CTRL_REGS, mr);
    171}
    172
    173static void versal_create_gems(Versal *s, qemu_irq *pic)
    174{
    175    int i;
    176
    177    for (i = 0; i < ARRAY_SIZE(s->lpd.iou.gem); i++) {
    178        static const int irqs[] = { VERSAL_GEM0_IRQ_0, VERSAL_GEM1_IRQ_0};
    179        static const uint64_t addrs[] = { MM_GEM0, MM_GEM1 };
    180        char *name = g_strdup_printf("gem%d", i);
    181        NICInfo *nd = &nd_table[i];
    182        DeviceState *dev;
    183        MemoryRegion *mr;
    184
    185        object_initialize_child(OBJECT(s), name, &s->lpd.iou.gem[i],
    186                                TYPE_CADENCE_GEM);
    187        dev = DEVICE(&s->lpd.iou.gem[i]);
    188        /* FIXME use qdev NIC properties instead of nd_table[] */
    189        if (nd->used) {
    190            qemu_check_nic_model(nd, "cadence_gem");
    191            qdev_set_nic_properties(dev, nd);
    192        }
    193        object_property_set_int(OBJECT(dev), "phy-addr", 23, &error_abort);
    194        object_property_set_int(OBJECT(dev), "num-priority-queues", 2,
    195                                &error_abort);
    196        object_property_set_link(OBJECT(dev), "dma", OBJECT(&s->mr_ps),
    197                                 &error_abort);
    198        sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
    199
    200        mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
    201        memory_region_add_subregion(&s->mr_ps, addrs[i], mr);
    202
    203        sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[irqs[i]]);
    204        g_free(name);
    205    }
    206}
    207
    208static void versal_create_admas(Versal *s, qemu_irq *pic)
    209{
    210    int i;
    211
    212    for (i = 0; i < ARRAY_SIZE(s->lpd.iou.adma); i++) {
    213        char *name = g_strdup_printf("adma%d", i);
    214        DeviceState *dev;
    215        MemoryRegion *mr;
    216
    217        object_initialize_child(OBJECT(s), name, &s->lpd.iou.adma[i],
    218                                TYPE_XLNX_ZDMA);
    219        dev = DEVICE(&s->lpd.iou.adma[i]);
    220        object_property_set_int(OBJECT(dev), "bus-width", 128, &error_abort);
    221        object_property_set_link(OBJECT(dev), "dma",
    222                                 OBJECT(get_system_memory()), &error_fatal);
    223        sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
    224
    225        mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
    226        memory_region_add_subregion(&s->mr_ps,
    227                                    MM_ADMA_CH0 + i * MM_ADMA_CH0_SIZE, mr);
    228
    229        sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[VERSAL_ADMA_IRQ_0 + i]);
    230        g_free(name);
    231    }
    232}
    233
    234#define SDHCI_CAPABILITIES  0x280737ec6481 /* Same as on ZynqMP.  */
    235static void versal_create_sds(Versal *s, qemu_irq *pic)
    236{
    237    int i;
    238
    239    for (i = 0; i < ARRAY_SIZE(s->pmc.iou.sd); i++) {
    240        DeviceState *dev;
    241        MemoryRegion *mr;
    242
    243        object_initialize_child(OBJECT(s), "sd[*]", &s->pmc.iou.sd[i],
    244                                TYPE_SYSBUS_SDHCI);
    245        dev = DEVICE(&s->pmc.iou.sd[i]);
    246
    247        object_property_set_uint(OBJECT(dev), "sd-spec-version", 3,
    248                                 &error_fatal);
    249        object_property_set_uint(OBJECT(dev), "capareg", SDHCI_CAPABILITIES,
    250                                 &error_fatal);
    251        object_property_set_uint(OBJECT(dev), "uhs", UHS_I, &error_fatal);
    252        sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
    253
    254        mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
    255        memory_region_add_subregion(&s->mr_ps,
    256                                    MM_PMC_SD0 + i * MM_PMC_SD0_SIZE, mr);
    257
    258        sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
    259                           pic[VERSAL_SD0_IRQ_0 + i * 2]);
    260    }
    261}
    262
    263static void versal_create_rtc(Versal *s, qemu_irq *pic)
    264{
    265    SysBusDevice *sbd;
    266    MemoryRegion *mr;
    267
    268    object_initialize_child(OBJECT(s), "rtc", &s->pmc.rtc,
    269                            TYPE_XLNX_ZYNQMP_RTC);
    270    sbd = SYS_BUS_DEVICE(&s->pmc.rtc);
    271    sysbus_realize(SYS_BUS_DEVICE(sbd), &error_fatal);
    272
    273    mr = sysbus_mmio_get_region(sbd, 0);
    274    memory_region_add_subregion(&s->mr_ps, MM_PMC_RTC, mr);
    275
    276    /*
    277     * TODO: Connect the ALARM and SECONDS interrupts once our RTC model
    278     * supports them.
    279     */
    280    sysbus_connect_irq(sbd, 1, pic[VERSAL_RTC_APB_ERR_IRQ]);
    281}
    282
    283static void versal_create_xrams(Versal *s, qemu_irq *pic)
    284{
    285    int nr_xrams = ARRAY_SIZE(s->lpd.xram.ctrl);
    286    DeviceState *orgate;
    287    int i;
    288
    289    /* XRAM IRQs get ORed into a single line.  */
    290    object_initialize_child(OBJECT(s), "xram-irq-orgate",
    291                            &s->lpd.xram.irq_orgate, TYPE_OR_IRQ);
    292    orgate = DEVICE(&s->lpd.xram.irq_orgate);
    293    object_property_set_int(OBJECT(orgate),
    294                            "num-lines", nr_xrams, &error_fatal);
    295    qdev_realize(orgate, NULL, &error_fatal);
    296    qdev_connect_gpio_out(orgate, 0, pic[VERSAL_XRAM_IRQ_0]);
    297
    298    for (i = 0; i < ARRAY_SIZE(s->lpd.xram.ctrl); i++) {
    299        SysBusDevice *sbd;
    300        MemoryRegion *mr;
    301
    302        object_initialize_child(OBJECT(s), "xram[*]", &s->lpd.xram.ctrl[i],
    303                                TYPE_XLNX_XRAM_CTRL);
    304        sbd = SYS_BUS_DEVICE(&s->lpd.xram.ctrl[i]);
    305        sysbus_realize(sbd, &error_fatal);
    306
    307        mr = sysbus_mmio_get_region(sbd, 0);
    308        memory_region_add_subregion(&s->mr_ps,
    309                                    MM_XRAMC + i * MM_XRAMC_SIZE, mr);
    310        mr = sysbus_mmio_get_region(sbd, 1);
    311        memory_region_add_subregion(&s->mr_ps, MM_XRAM + i * MiB, mr);
    312
    313        sysbus_connect_irq(sbd, 0, qdev_get_gpio_in(orgate, i));
    314    }
    315}
    316
    317static void versal_create_bbram(Versal *s, qemu_irq *pic)
    318{
    319    SysBusDevice *sbd;
    320
    321    object_initialize_child_with_props(OBJECT(s), "bbram", &s->pmc.bbram,
    322                                       sizeof(s->pmc.bbram), TYPE_XLNX_BBRAM,
    323                                       &error_fatal,
    324                                       "crc-zpads", "0",
    325                                       NULL);
    326    sbd = SYS_BUS_DEVICE(&s->pmc.bbram);
    327
    328    sysbus_realize(sbd, &error_fatal);
    329    memory_region_add_subregion(&s->mr_ps, MM_PMC_BBRAM_CTRL,
    330                                sysbus_mmio_get_region(sbd, 0));
    331    sysbus_connect_irq(sbd, 0, pic[VERSAL_BBRAM_APB_IRQ_0]);
    332}
    333
    334static void versal_realize_efuse_part(Versal *s, Object *dev, hwaddr base)
    335{
    336    SysBusDevice *part = SYS_BUS_DEVICE(dev);
    337
    338    object_property_set_link(OBJECT(part), "efuse",
    339                             OBJECT(&s->pmc.efuse), &error_abort);
    340
    341    sysbus_realize(part, &error_abort);
    342    memory_region_add_subregion(&s->mr_ps, base,
    343                                sysbus_mmio_get_region(part, 0));
    344}
    345
    346static void versal_create_efuse(Versal *s, qemu_irq *pic)
    347{
    348    Object *bits = OBJECT(&s->pmc.efuse);
    349    Object *ctrl = OBJECT(&s->pmc.efuse_ctrl);
    350    Object *cache = OBJECT(&s->pmc.efuse_cache);
    351
    352    object_initialize_child(OBJECT(s), "efuse-ctrl", &s->pmc.efuse_ctrl,
    353                            TYPE_XLNX_VERSAL_EFUSE_CTRL);
    354
    355    object_initialize_child(OBJECT(s), "efuse-cache", &s->pmc.efuse_cache,
    356                            TYPE_XLNX_VERSAL_EFUSE_CACHE);
    357
    358    object_initialize_child_with_props(ctrl, "xlnx-efuse@0", bits,
    359                                       sizeof(s->pmc.efuse),
    360                                       TYPE_XLNX_EFUSE, &error_abort,
    361                                       "efuse-nr", "3",
    362                                       "efuse-size", "8192",
    363                                       NULL);
    364
    365    qdev_realize(DEVICE(bits), NULL, &error_abort);
    366    versal_realize_efuse_part(s, ctrl, MM_PMC_EFUSE_CTRL);
    367    versal_realize_efuse_part(s, cache, MM_PMC_EFUSE_CACHE);
    368
    369    sysbus_connect_irq(SYS_BUS_DEVICE(ctrl), 0, pic[VERSAL_EFUSE_IRQ]);
    370}
    371
    372/* This takes the board allocated linear DDR memory and creates aliases
    373 * for each split DDR range/aperture on the Versal address map.
    374 */
    375static void versal_map_ddr(Versal *s)
    376{
    377    uint64_t size = memory_region_size(s->cfg.mr_ddr);
    378    /* Describes the various split DDR access regions.  */
    379    static const struct {
    380        uint64_t base;
    381        uint64_t size;
    382    } addr_ranges[] = {
    383        { MM_TOP_DDR, MM_TOP_DDR_SIZE },
    384        { MM_TOP_DDR_2, MM_TOP_DDR_2_SIZE },
    385        { MM_TOP_DDR_3, MM_TOP_DDR_3_SIZE },
    386        { MM_TOP_DDR_4, MM_TOP_DDR_4_SIZE }
    387    };
    388    uint64_t offset = 0;
    389    int i;
    390
    391    assert(ARRAY_SIZE(addr_ranges) == ARRAY_SIZE(s->noc.mr_ddr_ranges));
    392    for (i = 0; i < ARRAY_SIZE(addr_ranges) && size; i++) {
    393        char *name;
    394        uint64_t mapsize;
    395
    396        mapsize = size < addr_ranges[i].size ? size : addr_ranges[i].size;
    397        name = g_strdup_printf("noc-ddr-range%d", i);
    398        /* Create the MR alias.  */
    399        memory_region_init_alias(&s->noc.mr_ddr_ranges[i], OBJECT(s),
    400                                 name, s->cfg.mr_ddr,
    401                                 offset, mapsize);
    402
    403        /* Map it onto the NoC MR.  */
    404        memory_region_add_subregion(&s->mr_ps, addr_ranges[i].base,
    405                                    &s->noc.mr_ddr_ranges[i]);
    406        offset += mapsize;
    407        size -= mapsize;
    408        g_free(name);
    409    }
    410}
    411
    412static void versal_unimp_area(Versal *s, const char *name,
    413                                MemoryRegion *mr,
    414                                hwaddr base, hwaddr size)
    415{
    416    DeviceState *dev = qdev_new(TYPE_UNIMPLEMENTED_DEVICE);
    417    MemoryRegion *mr_dev;
    418
    419    qdev_prop_set_string(dev, "name", name);
    420    qdev_prop_set_uint64(dev, "size", size);
    421    object_property_add_child(OBJECT(s), name, OBJECT(dev));
    422    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
    423
    424    mr_dev = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
    425    memory_region_add_subregion(mr, base, mr_dev);
    426}
    427
    428static void versal_unimp(Versal *s)
    429{
    430    versal_unimp_area(s, "psm", &s->mr_ps,
    431                        MM_PSM_START, MM_PSM_END - MM_PSM_START);
    432    versal_unimp_area(s, "crl", &s->mr_ps,
    433                        MM_CRL, MM_CRL_SIZE);
    434    versal_unimp_area(s, "crf", &s->mr_ps,
    435                        MM_FPD_CRF, MM_FPD_CRF_SIZE);
    436    versal_unimp_area(s, "apu", &s->mr_ps,
    437                        MM_FPD_FPD_APU, MM_FPD_FPD_APU_SIZE);
    438    versal_unimp_area(s, "crp", &s->mr_ps,
    439                        MM_PMC_CRP, MM_PMC_CRP_SIZE);
    440    versal_unimp_area(s, "iou-scntr", &s->mr_ps,
    441                        MM_IOU_SCNTR, MM_IOU_SCNTR_SIZE);
    442    versal_unimp_area(s, "iou-scntr-seucre", &s->mr_ps,
    443                        MM_IOU_SCNTRS, MM_IOU_SCNTRS_SIZE);
    444}
    445
    446static void versal_realize(DeviceState *dev, Error **errp)
    447{
    448    Versal *s = XLNX_VERSAL(dev);
    449    qemu_irq pic[XLNX_VERSAL_NR_IRQS];
    450
    451    versal_create_apu_cpus(s);
    452    versal_create_apu_gic(s, pic);
    453    versal_create_uarts(s, pic);
    454    versal_create_usbs(s, pic);
    455    versal_create_gems(s, pic);
    456    versal_create_admas(s, pic);
    457    versal_create_sds(s, pic);
    458    versal_create_rtc(s, pic);
    459    versal_create_xrams(s, pic);
    460    versal_create_bbram(s, pic);
    461    versal_create_efuse(s, pic);
    462    versal_map_ddr(s);
    463    versal_unimp(s);
    464
    465    /* Create the On Chip Memory (OCM).  */
    466    memory_region_init_ram(&s->lpd.mr_ocm, OBJECT(s), "ocm",
    467                           MM_OCM_SIZE, &error_fatal);
    468
    469    memory_region_add_subregion_overlap(&s->mr_ps, MM_OCM, &s->lpd.mr_ocm, 0);
    470    memory_region_add_subregion_overlap(&s->fpd.apu.mr, 0, &s->mr_ps, 0);
    471}
    472
    473static void versal_init(Object *obj)
    474{
    475    Versal *s = XLNX_VERSAL(obj);
    476
    477    memory_region_init(&s->fpd.apu.mr, obj, "mr-apu", UINT64_MAX);
    478    memory_region_init(&s->mr_ps, obj, "mr-ps-switch", UINT64_MAX);
    479}
    480
    481static Property versal_properties[] = {
    482    DEFINE_PROP_LINK("ddr", Versal, cfg.mr_ddr, TYPE_MEMORY_REGION,
    483                     MemoryRegion *),
    484    DEFINE_PROP_UINT32("psci-conduit", Versal, cfg.psci_conduit, 0),
    485    DEFINE_PROP_END_OF_LIST()
    486};
    487
    488static void versal_class_init(ObjectClass *klass, void *data)
    489{
    490    DeviceClass *dc = DEVICE_CLASS(klass);
    491
    492    dc->realize = versal_realize;
    493    device_class_set_props(dc, versal_properties);
    494    /* No VMSD since we haven't got any top-level SoC state to save.  */
    495}
    496
    497static const TypeInfo versal_info = {
    498    .name = TYPE_XLNX_VERSAL,
    499    .parent = TYPE_SYS_BUS_DEVICE,
    500    .instance_size = sizeof(Versal),
    501    .instance_init = versal_init,
    502    .class_init = versal_class_init,
    503};
    504
    505static void versal_register_types(void)
    506{
    507    type_register_static(&versal_info);
    508}
    509
    510type_init(versal_register_types);