mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2024-10-21 10:28:20 +02:00
87db6e033b
Currently CPUClass->parse_features() is used to parse -cpu features string and set properties on created CPU instances. But considering that features specified by -cpu apply to every created CPU instance, it doesn't make sense to parse the same features string for every CPU created. It also makes every target that cares about parsing features string explicitly call CPUClass->parse_features() parser, which gets in a way if we consider using generic device_add for CPU hotplug as device_add has not a clue about CPU specific hooks. Turns out we can use global properties mechanism to set properties on every created CPU instance for a given type. That way it's possible to convert CPU features into a set of global properties for CPU type specified by -cpu cpu_model and common Device.device_post_init() will apply them to CPU of given type automatically regardless whether it's manually created CPU or CPU created with help of device_add. Backports commits 62a48a2a5798425997152dea3fc48708f9116c04 and f313369fdb78f849ecbbd8e5d88f01ddf38786c8 from qemu
164 lines
5.0 KiB
C
164 lines
5.0 KiB
C
/*
|
|
* ARM mach-virt emulation
|
|
*
|
|
* Copyright (c) 2013 Linaro Limited
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms and conditions of the GNU General Public License,
|
|
* version 2 or later, as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with
|
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Emulate a virtual board which works by passing Linux all the information
|
|
* it needs about what devices are present via the device tree.
|
|
* There are some restrictions about what we can do here:
|
|
* + we can only present devices whose Linux drivers will work based
|
|
* purely on the device tree with no platform data at all
|
|
* + we want to present a very stripped-down minimalist platform,
|
|
* both because this reduces the security attack surface from the guest
|
|
* and also because it reduces our exposure to being broken when
|
|
* the kernel updates its device tree bindings and requires further
|
|
* information in a device binding that we aren't providing.
|
|
* This is essentially the same approach kvmtool uses.
|
|
*/
|
|
|
|
/* Unicorn Emulator Engine */
|
|
/* By Nguyen Anh Quynh, 2015 */
|
|
|
|
#include "qemu/osdep.h"
|
|
#include "qapi/error.h"
|
|
#include "qemu-common.h"
|
|
#include "cpu.h"
|
|
#include "hw/arm/arm.h"
|
|
#include "hw/boards.h"
|
|
#include "exec/address-spaces.h"
|
|
|
|
// Unicorn: Daughterboard member removed, as it's not necessary
|
|
// for Unicorn's purposes.
|
|
typedef struct {
|
|
MachineClass parent;
|
|
} VirtMachineClass;
|
|
|
|
typedef struct {
|
|
MachineState parent;
|
|
bool secure;
|
|
} VirtMachineState;
|
|
|
|
#define TYPE_VIRT_MACHINE MACHINE_TYPE_NAME("virt")
|
|
#define VIRT_MACHINE(uc, obj) \
|
|
OBJECT_CHECK((uc), VirtMachineState, (obj), TYPE_VIRT_MACHINE)
|
|
#define VIRT_MACHINE_GET_CLASS(uc, obj) \
|
|
OBJECT_GET_CLASS(uc, VirtMachineClass, obj, TYPE_VIRT_MACHINE)
|
|
#define VIRT_MACHINE_CLASS(uc, klass) \
|
|
OBJECT_CLASS_CHECK(uc, VirtMachineClass, klass, TYPE_VIRT_MACHINE)
|
|
|
|
static int machvirt_init(struct uc_struct *uc, MachineState *machine)
|
|
{
|
|
const char *cpu_model = machine->cpu_model;
|
|
char **cpustr;
|
|
int n;
|
|
|
|
if (!cpu_model) {
|
|
// Unicorn: "max" used instead to allow use of ARMv8.1+ instructions.
|
|
//cpu_model = "cortex-a57"; // ARM64
|
|
cpu_model = "max";
|
|
}
|
|
|
|
/* Separate the actual CPU model name from any appended features */
|
|
cpustr = g_strsplit(cpu_model, ",", 2);
|
|
|
|
for (n = 0; n < smp_cpus; n++) {
|
|
ObjectClass *oc = cpu_class_by_name(uc, TYPE_ARM_CPU, cpustr[0]);
|
|
char *cpuopts = g_strdup(cpustr[1]);
|
|
CPUClass *cc = CPU_CLASS(uc, oc);
|
|
Object *cpuobj;
|
|
Error *err = NULL;
|
|
const char *typename = object_class_get_name(oc);
|
|
|
|
if (!oc) {
|
|
fprintf(stderr, "Unable to find CPU definition\n");
|
|
return -1;
|
|
}
|
|
|
|
/* convert -smp CPU options specified by the user into global props */
|
|
cc->parse_features(uc, typename, cpuopts, &err);
|
|
cpuobj = object_new(uc, typename);
|
|
uc->cpu = CPU(cpuobj);
|
|
object_property_set_bool(uc, cpuobj, true, "realized", NULL);
|
|
|
|
g_free(cpuopts);
|
|
}
|
|
g_strfreev(cpustr);
|
|
return 0;
|
|
}
|
|
|
|
static QEMU_UNUSED_FUNC bool virt_get_secure(struct uc_struct *uc, Object *obj, Error **errp)
|
|
{
|
|
VirtMachineState *vms = VIRT_MACHINE(uc, obj);
|
|
|
|
return vms->secure;
|
|
}
|
|
|
|
static QEMU_UNUSED_FUNC int virt_set_secure(struct uc_struct *uc, Object *obj, bool value, Error **errp)
|
|
{
|
|
VirtMachineState *vms = VIRT_MACHINE(uc, obj);
|
|
|
|
vms->secure = value;
|
|
return 0;
|
|
}
|
|
|
|
static void virt_instance_init(struct uc_struct *uc, Object *obj, void *opaque)
|
|
{
|
|
VirtMachineState *vms = VIRT_MACHINE(uc, obj);
|
|
|
|
/* EL3 is enabled by default on virt */
|
|
vms->secure = true;
|
|
|
|
/* Unicorn: should be uncommented, but causes linkage errors :/
|
|
object_property_add_bool(uc, obj, "secure", virt_get_secure,
|
|
virt_set_secure, NULL);
|
|
object_property_set_description(uc, obj, "secure",
|
|
"Set on/off to enable/disable the ARM "
|
|
"Security Extensions (TrustZone)",
|
|
NULL);
|
|
*/
|
|
}
|
|
|
|
static void virt_class_init(struct uc_struct *uc, ObjectClass *oc, void *data)
|
|
{
|
|
MachineClass *mc = MACHINE_CLASS(uc, oc);
|
|
|
|
mc->init = machvirt_init;
|
|
mc->max_cpus = 8;
|
|
mc->is_default = 1;
|
|
mc->arch = UC_ARCH_ARM64;
|
|
}
|
|
|
|
static const TypeInfo machvirt_info = {
|
|
TYPE_VIRT_MACHINE,
|
|
TYPE_MACHINE,
|
|
|
|
sizeof(VirtMachineClass),
|
|
sizeof(VirtMachineState),
|
|
NULL,
|
|
|
|
virt_instance_init,
|
|
NULL,
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
virt_class_init,
|
|
};
|
|
|
|
void machvirt_machine_init(struct uc_struct *uc)
|
|
{
|
|
type_register_static(uc, &machvirt_info);
|
|
}
|