qemu学习之添加一个新machine

本文以xilinx的qemu为例去介绍,首先通过介绍xlnx-versal-virt machine的添加流程去了解添加一个新的machine需要注意和关注的地方。然后再通过完全从头开始添加一个machine的方式去处理,然后编译看一下实验效果。

xilinx qemu源码的链接:https://github.com/Xilinx/qemu

1 xlnx-versal-virt machine所在的代码

完成的添加xlnx-versal-virt machine的代码如下所示:
https://github.com/Xilinx/qemu/blob/master/hw/arm/xlnx-versal-virt.c

1.1 声明一个新的machine

1.1.1 xlnx-versal-virt machine声明

  • xlnx-versal-virt即为新声明的machine名称
#define TYPE_XLNX_VERSAL_VIRT_MACHINE MACHINE_TYPE_NAME("xlnx-versal-virt")
  • versal_virt_machine_init_typeinfoxlnx-versal-virt machine所需要关注的属性以及machine初始化相关的配置。
  • versal_virt_machine_init_register_types是machine的注册函数,通过type_init函数以模块注册到系统中,type_init宏的定义如下所示
    #define type_init(function) module_init(function, MODULE_INIT_QOM)
static const TypeInfo versal_virt_machine_init_typeinfo = {
    .name       = TYPE_XLNX_VERSAL_VIRT_MACHINE,
    .parent     = TYPE_MACHINE,
    .class_init = versal_virt_machine_class_init,
    .instance_init = versal_virt_machine_instance_init,
    .instance_size = sizeof(VersalVirt),
};

static void versal_virt_machine_init_register_types(void)
{
    type_register_static(&versal_virt_machine_init_typeinfo);
}

type_init(versal_virt_machine_init_register_types)

1.1.2 struct TypeInfo 结构体的声明

通过struct TypeInfo我们描述了一个新的单板所具有的一些基本的属性和初始化所需要的的接口。

/**
 * struct TypeInfo:
 * @name: The name of the type.
 * @parent: The name of the parent type.
 * @instance_size: The size of the object (derivative of #Object).  If
 *   @instance_size is 0, then the size of the object will be the size of the
 *   parent object.
 * @instance_align: The required alignment of the object.  If @instance_align
 *   is 0, then normal malloc alignment is sufficient; if non-zero, then we
 *   must use qemu_memalign for allocation.
 * @instance_init: This function is called to initialize an object.  The parent
 *   class will have already been initialized so the type is only responsible
 *   for initializing its own members.
 * @instance_post_init: This function is called to finish initialization of
 *   an object, after all @instance_init functions were called.
 * @instance_finalize: This function is called during object destruction.  This
 *   is called before the parent @instance_finalize function has been called.
 *   An object should only free the members that are unique to its type in this
 *   function.
 * @abstract: If this field is true, then the class is considered abstract and
 *   cannot be directly instantiated.
 * @class_size: The size of the class object (derivative of #ObjectClass)
 *   for this object.  If @class_size is 0, then the size of the class will be
 *   assumed to be the size of the parent class.  This allows a type to avoid
 *   implementing an explicit class type if they are not adding additional
 *   virtual functions.
 * @class_init: This function is called after all parent class initialization
 *   has occurred to allow a class to set its default virtual method pointers.
 *   This is also the function to use to override virtual methods from a parent
 *   class.
 * @class_base_init: This function is called for all base classes after all
 *   parent class initialization has occurred, but before the class itself
 *   is initialized.  This is the function to use to undo the effects of
 *   memcpy from the parent class to the descendants.
 * @class_data: Data to pass to the @class_init,
 *   @class_base_init. This can be useful when building dynamic
 *   classes.
 * @interfaces: The list of interfaces associated with this type.  This
 *   should point to a static array that's terminated with a zero filled
 *   element.
 */
struct TypeInfo
{
    const char *name;
    const char *parent;

    size_t instance_size;
    size_t instance_align;
    void (*instance_init)(Object *obj);
    void (*instance_post_init)(Object *obj);
    void (*instance_finalize)(Object *obj);

    bool abstract;
    size_t class_size;

    void (*class_init)(ObjectClass *klass, void *data);
    void (*class_base_init)(ObjectClass *klass, void *data);
    void *class_data;

    InterfaceInfo *interfaces;
};

1.1.3 versal_virt_machine_init_typeinfo

xlnx-versal-virt所声明的属性中添加了下面的配置信息。

  • TYPE_XLNX_VERSAL_VIRT_MACHINE表示是当前machine的名字
  • TYPE_MACHINE表示的是machine的公共属性
  • versal_virt_machine_class_init是当前machine初始化的接口
  • versal_virt_machine_instance_init是当前machine实例初始化的接口
static const TypeInfo versal_virt_machine_init_typeinfo = {
    .name       = TYPE_XLNX_VERSAL_VIRT_MACHINE,
    .parent     = TYPE_MACHINE,
    .class_init = versal_virt_machine_class_init,
    .instance_init = versal_virt_machine_instance_init,
    .instance_size = sizeof(VersalVirt),
};

1.2 versal_virt_machine_class_init

1.2.1 versal_virt_machine_class_init

  • XLNX_VERSAL_NR_ACPUS表示当前machine所支持的CPU的数量,在设备启动的过程中需要通过-cpu去指定
  • mc->min_cpusmc->max_cpus表示的是当前的machine支持的cpu的上限和下限,在qemu启动过程-cpu CPU_NR只要是在这个范围内都可以被接受。
  • mc->default_cpus表示如果在qemu启动时不通过-cpu 去指定CPU数量时,默认的CPU数量是多少
  • versal_virt_init是当前machine初始化的接口
  • mc->desc是对当前machine的描述,在执行sudo qemu-system-aarch64 -M help命令时,所支持machine后面所对应点描述信息。
sudo qemu-system-aarch64 -M help
...
xlnx-versal-virt     Xilinx Versal Virtual development board
...
static void versal_virt_machine_class_init(ObjectClass *oc, void *data)
{
    MachineClass *mc = MACHINE_CLASS(oc);

    mc->desc = "Xilinx Versal Virtual development board";
    mc->init = versal_virt_init;
    mc->min_cpus = XLNX_VERSAL_NR_ACPUS;
    mc->max_cpus = XLNX_VERSAL_NR_ACPUS;
    mc->default_cpus = XLNX_VERSAL_NR_ACPUS;
    mc->no_cdrom = true;
    mc->default_ram_id = "ddr";
}

1.2.2 struct MachineClass

struct MachineClass结构体描述了当前machine的一些更具体的属性信息。

/**
 * MachineClass:
 * @deprecation_reason: If set, the machine is marked as deprecated. The
 *    string should provide some clear information about what to use instead.
 * @max_cpus: maximum number of CPUs supported. Default: 1
 * @min_cpus: minimum number of CPUs supported. Default: 1
 * @default_cpus: number of CPUs instantiated if none are specified. Default: 1
 * @is_default:
 *    If true QEMU will use this machine by default if no '-M' option is given.
 * @get_hotplug_handler: this function is called during bus-less
 *    device hotplug. If defined it returns pointer to an instance
 *    of HotplugHandler object, which handles hotplug operation
 *    for a given @dev. It may return NULL if @dev doesn't require
 *    any actions to be performed by hotplug handler.
 * @cpu_index_to_instance_props:
 *    used to provide @cpu_index to socket/core/thread number mapping, allowing
 *    legacy code to perform maping from cpu_index to topology properties
 *    Returns: tuple of socket/core/thread ids given cpu_index belongs to.
 *    used to provide @cpu_index to socket number mapping, allowing
 *    a machine to group CPU threads belonging to the same socket/package
 *    Returns: socket number given cpu_index belongs to.
 * @hw_version:
 *    Value of QEMU_VERSION when the machine was added to QEMU.
 *    Set only by old machines because they need to keep
 *    compatibility on code that exposed QEMU_VERSION to guests in
 *    the past (and now use qemu_hw_version()).
 * @possible_cpu_arch_ids:
 *    Returns an array of @CPUArchId architecture-dependent CPU IDs
 *    which includes CPU IDs for present and possible to hotplug CPUs.
 *    Caller is responsible for freeing returned list.
 * @get_default_cpu_node_id:
 *    returns default board specific node_id value for CPU slot specified by
 *    index @idx in @ms->possible_cpus[]
 * @has_hotpluggable_cpus:
 *    If true, board supports CPUs creation with -device/device_add.
 * @default_cpu_type:
 *    specifies default CPU_TYPE, which will be used for parsing target
 *    specific features and for creating CPUs if CPU name wasn't provided
 *    explicitly at CLI
 * @minimum_page_bits:
 *    If non-zero, the board promises never to create a CPU with a page size
 *    smaller than this, so QEMU can use a more efficient larger page
 *    size than the target architecture's minimum. (Attempting to create
 *    such a CPU will fail.) Note that changing this is a migration
 *    compatibility break for the machine.
 * @ignore_memory_transaction_failures:
 *    If this is flag is true then the CPU will ignore memory transaction
 *    failures which should cause the CPU to take an exception due to an
 *    access to an unassigned physical address; the transaction will instead
 *    return zero (for a read) or be ignored (for a write). This should be
 *    set only by legacy board models which rely on the old RAZ/WI behaviour
 *    for handling devices that QEMU does not yet model. New board models
 *    should instead use "unimplemented-device" for all memory ranges where
 *    the guest will attempt to probe for a device that QEMU doesn't
 *    implement and a stub device is required.
 * @kvm_type:
 *    Return the type of KVM corresponding to the kvm-type string option or
 *    computed based on other criteria such as the host kernel capabilities.
 *    kvm-type may be NULL if it is not needed.
 * @numa_mem_supported:
 *    true if '--numa node.mem' option is supported and false otherwise
 * @smp_parse:
 *    The function pointer to hook different machine specific functions for
 *    parsing "smp-opts" from QemuOpts to MachineState::CpuTopology and more
 *    machine specific topology fields, such as smp_dies for PCMachine.
 * @hotplug_allowed:
 *    If the hook is provided, then it'll be called for each device
 *    hotplug to check whether the device hotplug is allowed.  Return
 *    true to grant allowance or false to reject the hotplug.  When
 *    false is returned, an error must be set to show the reason of
 *    the rejection.  If the hook is not provided, all hotplug will be
 *    allowed.
 * @default_ram_id:
 *    Specifies inital RAM MemoryRegion name to be used for default backend
 *    creation if user explicitly hasn't specified backend with "memory-backend"
 *    property.
 *    It also will be used as a way to optin into "-m" option support.
 *    If it's not set by board, '-m' will be ignored and generic code will
 *    not create default RAM MemoryRegion.
 * @fixup_ram_size:
 *    Amends user provided ram size (with -m option) using machine
 *    specific algorithm. To be used by old machine types for compat
 *    purposes only.
 *    Applies only to default memory backend, i.e., explicit memory backend
 *    wasn't used.
 */
struct MachineClass {
    /*< private >*/
    ObjectClass parent_class;
    /*< public >*/

    const char *family; /* NULL iff @name identifies a standalone machtype */
    char *name;
    const char *alias;
    const char *desc;
    const char *deprecation_reason;

    void (*init)(MachineState *state);
    void (*reset)(MachineState *state);
    void (*wakeup)(MachineState *state);
    int (*kvm_type)(MachineState *machine, const char *arg);
    void (*smp_parse)(MachineState *ms, SMPConfiguration *config, Error **errp);

    BlockInterfaceType block_default_type;
    int units_per_default_bus;
    int max_cpus;
    int min_cpus;
    int default_cpus;
    unsigned int no_serial:1,
        no_parallel:1,
        no_floppy:1,
        no_cdrom:1,
        no_sdcard:1,
        pci_allow_0_address:1,
        legacy_fw_cfg_order:1;
    bool is_default;
    const char *default_machine_opts;
    const char *default_boot_order;
    const char *default_display;
    GPtrArray *compat_props;
    const char *hw_version;
    ram_addr_t default_ram_size;
    const char *default_cpu_type;
    bool default_kernel_irqchip_split;
    bool option_rom_has_mr;
    bool rom_file_has_mr;
    int minimum_page_bits;
    bool has_hotpluggable_cpus;
    bool ignore_memory_transaction_failures;
    int numa_mem_align_shift;
    const char **valid_cpu_types;
    strList *allowed_dynamic_sysbus_devices;
    bool auto_enable_numa_with_memhp;
    bool auto_enable_numa_with_memdev;
    bool ignore_boot_device_suffixes;
    bool smbus_no_migration_support;
    bool nvdimm_supported;
    bool numa_mem_supported;
    bool auto_enable_numa;
    const char *default_ram_id;

    HotplugHandler *(*get_hotplug_handler)(MachineState *machine,
                                           DeviceState *dev);
    bool (*hotplug_allowed)(MachineState *state, DeviceState *dev,
                            Error **errp);
    CpuInstanceProperties (*cpu_index_to_instance_props)(MachineState *machine,
                                                         unsigned cpu_index);
    const CPUArchIdList *(*possible_cpu_arch_ids)(MachineState *machine);
    int64_t (*get_default_cpu_node_id)(const MachineState *ms, int idx);
    ram_addr_t (*fixup_ram_size)(ram_addr_t size);
};

1.3 versal_virt_init

1.3.1 versal_virt_init

对于xlnx-versal-virtmachine来说,versal_virt_init函数接口的处理主要是去解析设备所对应的设备树文件去获取对应的machine的device属性和配置。

static void versal_virt_init(MachineState *machine)
{
    VersalVirt *s = XLNX_VERSAL_VIRT_MACHINE(machine);
    int psci_conduit = QEMU_PSCI_CONDUIT_DISABLED;
    int i;

    /*
     * If the user provides an Operating System to be loaded, we expect them
     * to use the -kernel command line option.
     *
     * Users can load firmware or boot-loaders with the -device loader options.
     *
     * When loading an OS, we generate a dtb and let arm_load_kernel() select
     * where it gets loaded. This dtb will be passed to the kernel in x0.
     *
     * If there's no -kernel option, we generate a DTB and place it at 0x1000
     * for the bootloaders or firmware to pick up.
     *
     * If users want to provide their own DTB, they can use the -dtb option.
     * These dtb's will have their memory nodes modified to match QEMU's
     * selected ram_size option before they get passed to the kernel or fw.
     *
     * When loading an OS, we turn on QEMU's PSCI implementation with SMC
     * as the PSCI conduit. When there's no -kernel, we assume the user
     * provides EL3 firmware to handle PSCI.
     */
    if (machine->kernel_filename) {
        psci_conduit = QEMU_PSCI_CONDUIT_SMC;
    }

    object_initialize_child(OBJECT(machine), "xlnx-versal", &s->soc,
                            TYPE_XLNX_VERSAL);
    object_property_set_link(OBJECT(&s->soc), "ddr", OBJECT(machine->ram),
                             &error_abort);
    object_property_set_int(OBJECT(&s->soc), "psci-conduit", psci_conduit,
                            &error_abort);
    sysbus_realize(SYS_BUS_DEVICE(&s->soc), &error_fatal);

    fdt_create(s);
    create_virtio_regions(s);
    fdt_add_gem_nodes(s);
    fdt_add_uart_nodes(s);
    fdt_add_gic_nodes(s);
    fdt_add_timer_nodes(s);
    fdt_add_zdma_nodes(s);
    fdt_add_usb_xhci_nodes(s);
    fdt_add_sd_nodes(s);
    fdt_add_rtc_node(s);
    fdt_add_cpu_nodes(s, psci_conduit);
    fdt_add_clk_node(s, "/clk125", 125000000, s->phandle.clk_125Mhz);
    fdt_add_clk_node(s, "/clk25", 25000000, s->phandle.clk_25Mhz);

    /* Make the APU cpu address space visible to virtio and other
     * modules unaware of muliple address-spaces.  */
    memory_region_add_subregion_overlap(get_system_memory(),
                                        0, &s->soc.fpd.apu.mr, 0);

    /* Plugin SD cards.  */
    for (i = 0; i < ARRAY_SIZE(s->soc.pmc.iou.sd); i++) {
        sd_plugin_card(&s->soc.pmc.iou.sd[i], drive_get_next(IF_SD));
    }

    s->binfo.ram_size = machine->ram_size;
    s->binfo.loader_start = 0x0;
    s->binfo.get_dtb = versal_virt_get_dtb;
    s->binfo.modify_dtb = versal_virt_modify_dtb;
    if (machine->kernel_filename) {
        arm_load_kernel(&s->soc.fpd.apu.cpu[0], machine, &s->binfo);
    } else {
        AddressSpace *as = arm_boot_address_space(&s->soc.fpd.apu.cpu[0],
                                                  &s->binfo);
        /* Some boot-loaders (e.g u-boot) don't like blobs at address 0 (NULL).
         * Offset things by 4K.  */
        s->binfo.loader_start = 0x1000;
        s->binfo.dtb_limit = 0x1000000;
        if (arm_load_dtb(s->binfo.loader_start,
                         &s->binfo, s->binfo.dtb_limit, as, machine) < 0) {
            exit(EXIT_FAILURE);
        }
    }
}

1.3.2 XLNX_VERSAL_VIRT_MACHINE

XLNX_VERSAL_VIRT_MACHINE的定义是在hw/arm/xlnx-versal-virt.c文件中;通过OBJECT_DECLARE_SIMPLE_TYPE声明了XLNX_VERSAL_VIRT_MACHINE一个内联函数,其实现如下所示:

OBJECT_DECLARE_SIMPLE_TYPE(VersalVirt, XLNX_VERSAL_VIRT_MACHINE)

OBJECT_DECLARE_SIMPLE_TYPE的定义代码路径为:include/qom/object.h

 164 /**
 165  * DECLARE_INSTANCE_CHECKER:
 166  * @InstanceType: instance struct name
 167  * @OBJ_NAME: the object name in uppercase with underscore separators
 168  * @TYPENAME: type name
 169  *
 170  * Direct usage of this macro should be avoided, and the complete
 171  * OBJECT_DECLARE_TYPE macro is recommended instead.
 172  *
 173  * This macro will provide the instance type cast functions for a
 174  * QOM type.
 175  */
 176 #define DECLARE_INSTANCE_CHECKER(InstanceType, OBJ_NAME, TYPENAME) \
 177     static inline G_GNUC_UNUSED InstanceType * \
 178     OBJ_NAME(const void *obj) \
 179     { return OBJECT_CHECK(InstanceType, obj, TYPENAME); }

 243 /**
 244  * OBJECT_DECLARE_SIMPLE_TYPE:
 245  * @InstanceType: instance struct name
 246  * @MODULE_OBJ_NAME: the object name in uppercase with underscore separators
 247  *
 248  * This does the same as OBJECT_DECLARE_TYPE(), but with no class struct
 249  * declared.
 250  *
 251  * This macro should be used unless the class struct needs to have
 252  * virtual methods declared.
 253  */
 254 #define OBJECT_DECLARE_SIMPLE_TYPE(InstanceType, MODULE_OBJ_NAME) \
 255     typedef struct InstanceType InstanceType; \
 256     \
 257     G_DEFINE_AUTOPTR_CLEANUP_FUNC(InstanceType, object_unref) \
 258     \
 259     DECLARE_INSTANCE_CHECKER(InstanceType, MODULE_OBJ_NAME, TYPE_##MODULE_OBJ_NAME)

TYPE_##MODULE_OBJ_NAME所对应的是TYPE_XLNX_VERSAL_VIRT_MACHINE,在其中的##是一个连接符,用于讲TYPE_MODULE_OBJ_NAME组成一个符号。

1.3.3 fdt_create

versal_virt_init函数中的众多调用接口中以fdt_create为例来做简单介绍:

  • qemu_fdt_alloc_phandle用于依次去获取对应的device的配置信息,其起始地址为machine->phandle_start
  • qemu_fdt_setprop_cell用于解析对应的device node的属性信息
  • qemu_fdt_setprop_string用于解析设备树的信息,作为对当前machine的描述
static void fdt_create(VersalVirt *s)
{
    MachineClass *mc = MACHINE_GET_CLASS(s);
    int i;

    s->fdt = create_device_tree(&s->fdt_size);
    if (!s->fdt) {
        error_report("create_device_tree() failed");
        exit(1);
    }

    /* Allocate all phandles.  */
    s->phandle.gic = qemu_fdt_alloc_phandle(s->fdt);
    for (i = 0; i < ARRAY_SIZE(s->phandle.ethernet_phy); i++) {
        s->phandle.ethernet_phy[i] = qemu_fdt_alloc_phandle(s->fdt);
    }
    s->phandle.clk_25Mhz = qemu_fdt_alloc_phandle(s->fdt);
    s->phandle.clk_125Mhz = qemu_fdt_alloc_phandle(s->fdt);

    s->phandle.usb = qemu_fdt_alloc_phandle(s->fdt);
    s->phandle.dwc = qemu_fdt_alloc_phandle(s->fdt);
    /* Create /chosen node for load_dtb.  */
    qemu_fdt_add_subnode(s->fdt, "/chosen");

    /* Header */
    qemu_fdt_setprop_cell(s->fdt, "/", "interrupt-parent", s->phandle.gic);
    qemu_fdt_setprop_cell(s->fdt, "/", "#size-cells", 0x2);
    qemu_fdt_setprop_cell(s->fdt, "/", "#address-cells", 0x2);
    qemu_fdt_setprop_string(s->fdt, "/", "model", mc->desc);
    qemu_fdt_setprop_string(s->fdt, "/", "compatible", "xlnx-versal-virt");
}

2 xilinx qemu编译安装

2.1 添加xlnx-versal-virt.c的编译

代码路径:hw/arm/meson.build

arm_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal.c', 'xlnx-versal-virt.c'))

添加CONFIG_XLNX_VERSAL的配置宏。

2.2 添加配置开关XLNX_VERSAL和XLNX_VERSAL_ARM

代码路径:hw/arm/Kconfig

config XLNX_VERSAL
    bool
    select PL011
    select CADENCE
    select VIRTIO_MMIO
    select UNIMP
    select XLNX_ZDMA
    select XLNX_ZYNQMP
    select OR_IRQ

config XLNX_VERSAL_ARM
    bool
    select ARM_GIC
    select USB_DWC3
    select USB_XHCI_SYSBUS

2.3 编译和安装

cd qemu
mkdir build && cd build
../configure                (在该处会检查依赖软件)
make -j8                    (在该处编译的时间比较长)
sudo make install

安装完成之后通过sudo qemu-system-aarch64 --version查看qemu的版本是否正确

3 依据xlnx-versal-virt添加jimmy-virt测试machine

3.1 添加hw/arm/jimmy-virt.c

添加hw/arm/jimmy-virt.c时,直接借助xlnx-versal-virt的一些配置去处理,这样比较简单。现在只保留一个xlnx-versal-virt的简单框架,将xlnx-versal-virt的配置信息修改为jimmy-virt,然后添加jimmy-virt.c到编译中。

/*
 * Xilinx Versal Virtual board.
 *
 * Copyright (c) 2018 Xilinx Inc.
 * Written by Edgar E. Iglesias
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 or
 * (at your option) any later version.
 */

#include "qemu/osdep.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "sysemu/device_tree.h"
#include "hw/boards.h"
#include "hw/sysbus.h"
#include "hw/arm/sysbus-fdt.h"
#include "hw/arm/fdt.h"
#include "cpu.h"
#include "hw/qdev-properties.h"
#include "hw/arm/xlnx-versal.h"
#include "qom/object.h"

#define TYPE_JIMMY_VIRT_MACHINE MACHINE_TYPE_NAME("jimmy-virt")
OBJECT_DECLARE_SIMPLE_TYPE(JimmyVersalVirt, JIMMY_VIRT_MACHINE)

#define JIMMY_NR_ACPUS   8
#define JIMMY_NR_UARTS   2
#define JIMMY_NR_GEMS    2
#define JIMMY_NR_ADMAS   8
#define JIMMY_NR_SDS     2
#define JIMMY_NR_XRAM    4
#define JIMMY_NR_IRQS    192

struct JimmyVersalVirt {
    MachineState parent_obj;

    Versal soc;

    void *fdt;
    int fdt_size;
    struct {
        uint32_t gic;
        uint32_t ethernet_phy[2];
        uint32_t clk_125Mhz;
        uint32_t clk_25Mhz;
        uint32_t usb;
        uint32_t dwc;
    } phandle;
    struct arm_boot_info binfo;

    struct {
        bool secure;
    } cfg;
};

static void jimmy_virt_init(MachineState *machine)
{
}

static void jimmy_machine_instance_init(Object *obj)
{
}

static void jimmy_machine_class_init(ObjectClass *oc, void *data)
{
    MachineClass *mc = MACHINE_CLASS(oc);

    mc->desc = "Jimmy Versal Virtual development board";
    mc->init = jimmy_virt_init;
    mc->min_cpus = JIMMY_NR_ACPUS;
    mc->max_cpus = JIMMY_NR_ACPUS;
    mc->default_cpus = JIMMY_NR_ACPUS;
    mc->no_cdrom = true;
    mc->default_ram_id = "ddr";
}

static const TypeInfo jimmy_machine_init_typeinfo = {
    .name       = TYPE_JIMMY_VIRT_MACHINE,
    .parent     = TYPE_MACHINE,
    .class_init = jimmy_machine_class_init,
    .instance_init = jimmy_machine_instance_init,
    .instance_size = sizeof(JimmyVersalVirt),
};

static void jimmy_machine_init_register_types(void)
{
    type_register_static(&jimmy_machine_init_typeinfo);
}

type_init(jimmy_machine_init_register_types)

3.2 添加jimmy-virt.c的编译

代码路径:hw/arm/meson.build

arm_ss.add(when: 'CONFIG_JIMMY_VERSAL', if_true: files('jimmy-virt.c'))

3.3 添加CONFIG_JIMMY_VERSAL和CONFIG_JIMMY_VERSAL_ARM

代码路径:hw/arm/Kconfig

rlk@rlk:qemu-xilinx$ git diff hw/arm/Kconfig
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 4644930efb..e93cea5d86 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -375,6 +375,22 @@ config XLNX_ZYNQMP_ARM
     select USB_XHCI_SYSBUS
     select XLNX_ZDMA

+config JIMMY_VERSAL
+    bool
+    select PL011
+    select CADENCE
+    select VIRTIO_MMIO
+    select UNIMP
+    select XLNX_ZDMA
+    select XLNX_ZYNQMP
+    select OR_IRQ
+
+config JIMMY_VERSAL_ARM
+    bool
+    select ARM_GIC
+    select USB_DWC3
+    select USB_XHCI_SYSBUS
+
 config XLNX_VERSAL
     bool
     select PL011
rlk@rlk:qemu-xilinx$

3.3 编译和安装

cd qemu
mkdir build && cd build
../configure                (在该处会检查依赖软件)
make -j8                    (在该处编译的时间比较长)
sudo make install

3.4 查看新添加的测试machine是否成功

3.4.1 sudo qemu-system-aarch64 -M help | grep jimmy

当执行sudo qemu-system-aarch64 -M help | grep jimmy可以看到新添加的测试machine已经被添加到qemu中。

rlk@rlk:build$ sudo qemu-system-aarch64 -M help | grep jimmy
jimmy-virt           Jimmy Versal Virtual development board
rlk@rlk:build$

3.4.2 sudo qemu-system-aarch64 -M help

rlk@rlk:build$ sudo qemu-system-aarch64 -M help
Supported machines are:
akita                Sharp SL-C1000 (Akita) PDA (PXA270)
arm-generic-fdt-7series ARM device tree driven machine model for the Zynq-7000
arm-generic-fdt      ARM device tree driven machine model
arm-generic-fdt-plnx Deprecated ARM device tree driven machine for the Zynq-7000
ast2500-evb          Aspeed AST2500 EVB (ARM1176)
ast2600-evb          Aspeed AST2600 EVB (Cortex-A7)
borzoi               Sharp SL-C3100 (Borzoi) PDA (PXA270)
canon-a1100          Canon PowerShot A1100 IS (ARM946)
cheetah              Palm Tungsten|E aka. Cheetah PDA (OMAP310)
collie               Sharp SL-5500 (Collie) PDA (SA-1110)
connex               Gumstix Connex (PXA255)
cubieboard           cubietech cubieboard (Cortex-A8)
emcraft-sf2          SmartFusion2 SOM kit from Emcraft (M2S010)
g220a-bmc            Bytedance G220A BMC (ARM1176)
highbank             Calxeda Highbank (ECX-1000)
imx25-pdk            ARM i.MX25 PDK board (ARM926)
integratorcp         ARM Integrator/CP (ARM926EJ-S)
jimmy-virt           Jimmy Versal Virtual development board
kzm                  ARM KZM Emulation Baseboard (ARM1136)
lm3s6965evb          Stellaris LM3S6965EVB (Cortex-M3)
lm3s811evb           Stellaris LM3S811EVB (Cortex-M3)
mainstone            Mainstone II (PXA27x)
mcimx6ul-evk         Freescale i.MX6UL Evaluation Kit (Cortex-A7)
mcimx7d-sabre        Freescale i.MX7 DUAL SABRE (Cortex-A7)
microbit             BBC micro:bit (Cortex-M0)
midway               Calxeda Midway (ECX-2000)
mps2-an385           ARM MPS2 with AN385 FPGA image for Cortex-M3
mps2-an386           ARM MPS2 with AN386 FPGA image for Cortex-M4
mps2-an500           ARM MPS2 with AN500 FPGA image for Cortex-M7
mps2-an505           ARM MPS2 with AN505 FPGA image for Cortex-M33
mps2-an511           ARM MPS2 with AN511 DesignStart FPGA image for Cortex-M3
mps2-an521           ARM MPS2 with AN521 FPGA image for dual Cortex-M33
mps3-an524           ARM MPS3 with AN524 FPGA image for dual Cortex-M33
mps3-an547           ARM MPS3 with AN547 FPGA image for Cortex-M55
musca-a              ARM Musca-A board (dual Cortex-M33)
musca-b1             ARM Musca-B1 board (dual Cortex-M33)
musicpal             Marvell 88w8618 / MusicPal (ARM926EJ-S)
n800                 Nokia N800 tablet aka. RX-34 (OMAP2420)
n810                 Nokia N810 tablet aka. RX-44 (OMAP2420)
netduino2            Netduino 2 Machine (Cortex-M3)
netduinoplus2        Netduino Plus 2 Machine (Cortex-M4)
none                 empty machine
npcm750-evb          Nuvoton NPCM750 Evaluation Board (Cortex-A9)
nuri                 Samsung NURI board (Exynos4210)
orangepi-pc          Orange Pi PC (Cortex-A7)
palmetto-bmc         OpenPOWER Palmetto BMC (ARM926EJ-S)
quanta-gbs-bmc       Quanta GBS (Cortex-A9)
quanta-gsj           Quanta GSJ (Cortex-A9)
quanta-q71l-bmc      Quanta-Q71l BMC (ARM926EJ-S)
rainier-bmc          IBM Rainier BMC (Cortex-A7)
raspi0               Raspberry Pi Zero (revision 1.2)
raspi1ap             Raspberry Pi A+ (revision 1.1)
raspi2               Raspberry Pi 2B (revision 1.1) (alias of raspi2b)
raspi2b              Raspberry Pi 2B (revision 1.1)
raspi3ap             Raspberry Pi 3A+ (revision 1.0)
raspi3               Raspberry Pi 3B (revision 1.2) (alias of raspi3b)
raspi3b              Raspberry Pi 3B (revision 1.2)
realview-eb          ARM RealView Emulation Baseboard (ARM926EJ-S)
realview-eb-mpcore   ARM RealView Emulation Baseboard (ARM11MPCore)
realview-pb-a8       ARM RealView Platform Baseboard for Cortex-A8
realview-pbx-a9      ARM RealView Platform Baseboard Explore for Cortex-A9
romulus-bmc          OpenPOWER Romulus BMC (ARM1176)
sabrelite            Freescale i.MX6 Quad SABRE Lite Board (Cortex-A9)
sbsa-ref             QEMU 'SBSA Reference' ARM Virtual Machine
smdkc210             Samsung SMDKC210 board (Exynos4210)
sonorapass-bmc       OCP SonoraPass BMC (ARM1176)
spitz                Sharp SL-C3000 (Spitz) PDA (PXA270)
stm32vldiscovery     ST STM32VLDISCOVERY (Cortex-M3)
supermicrox11-bmc    Supermicro X11 BMC (ARM926EJ-S)
swift-bmc            OpenPOWER Swift BMC (ARM1176) (deprecated)
sx1                  Siemens SX1 (OMAP310) V2
sx1-v1               Siemens SX1 (OMAP310) V1
tacoma-bmc           OpenPOWER Tacoma BMC (Cortex-A7)
terrier              Sharp SL-C3200 (Terrier) PDA (PXA270)
tosa                 Sharp SL-6000 (Tosa) PDA (PXA255)
verdex               Gumstix Verdex (PXA270)
versatileab          ARM Versatile/AB (ARM926EJ-S)
versatilepb          ARM Versatile/PB (ARM926EJ-S)
vexpress-a15         ARM Versatile Express for Cortex-A15
vexpress-a9          ARM Versatile Express for Cortex-A9
virt-2.10            QEMU 2.10 ARM Virtual Machine
virt-2.11            QEMU 2.11 ARM Virtual Machine
virt-2.12            QEMU 2.12 ARM Virtual Machine
virt-2.6             QEMU 2.6 ARM Virtual Machine
virt-2.7             QEMU 2.7 ARM Virtual Machine
virt-2.8             QEMU 2.8 ARM Virtual Machine
virt-2.9             QEMU 2.9 ARM Virtual Machine
virt-3.0             QEMU 3.0 ARM Virtual Machine
virt-3.1             QEMU 3.1 ARM Virtual Machine
virt-4.0             QEMU 4.0 ARM Virtual Machine
virt-4.1             QEMU 4.1 ARM Virtual Machine
virt-4.2             QEMU 4.2 ARM Virtual Machine
virt-5.0             QEMU 5.0 ARM Virtual Machine
virt-5.1             QEMU 5.1 ARM Virtual Machine
virt-5.2             QEMU 5.2 ARM Virtual Machine
virt-6.0             QEMU 6.0 ARM Virtual Machine
virt                 QEMU 6.1 ARM Virtual Machine (alias of virt-6.1)
virt-6.1             QEMU 6.1 ARM Virtual Machine
witherspoon-bmc      OpenPOWER Witherspoon BMC (ARM1176)
xilinx-zynq-a9       Xilinx Zynq Platform Baseboard for Cortex-A9
xlnx-versal-virt     Xilinx Versal Virtual development board
xlnx-zcu102          Xilinx ZynqMP ZCU102 board with 4xA53s and 2xR5Fs based on the value of smp
z2                   Zipit Z2 (PXA27x)
rlk@rlk:build$ sudo qemu-system-aarch64 -M help | grep jimmy
jimmy-virt           Jimmy Versal Virtual development board
rlk@rlk:build$
  • 7
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值