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_typeinfo
是xlnx-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_cpus
和mc->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-virt
machine来说,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$