target-arm queue:
* enable 32-bit EL3 (TrustZone) for vexpress and virt boards * add fw_cfg device to virt board for UEFI firmware config * support passing commandline kernel/initrd to firmware -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCAAGBQJUmXMpAAoJEDwlJe0UNgzeIlIP/24UPoFsA/8rZV9JI41FDGJT ZH9SU6mjMhCIYZScbIwr2lfggRMOIzxFe3ohz4pTklXdwwz87Rg8Nfxecg+te/1i sqCmhAhsEcZr+Snirn/HmsqPE1dOGoNcCUP4Pb0XByBo3KQ1Gdqj9dUsV2S4CO0M ZkxjFaNJrqhyh5PJxoWYqO8aed38v2S+sNA5brCtWsrePo71e89M6qd3JyhKpNWC II33HWCS1leBmNc//bWP3DiIiZ1FIwyWgiEhscLD67LhtaQX1Am/x6RAsWzH4T8k rH4qZtIIYJi7up1qPCQqUA0TS3TvZuvvY46suAihxgaiLe1p/0KGEvwYmyyg35Pl yxdVny21gJi0s/HXVgBGTndjzCBVMfvDoN8BYGRZvuBia1a6QNdRybpiqq/X/8J2 fPXPgJNuDMzERSrnVHYPqriQpAyNw25gRJqDbo/3xoNS60Yzd4q06yhKxRg8ng3A jNrU0O+RVr4IslBXACFPS638WU1n+r6wfN4J/BJvdVugWrIxQ6mSp6ZKdr8dEOMM 6+R8bVHvCsMdaPB8Hfc94NyagrPM5+JItujfIvE+zRzjdB831IYHVoDOx4MsO+tD 8A7856tM4/l7LGVbx4ecmLxYyeQyPtEheLkcsaRLJ7FFbt31tnVSCDFcrpzw8TdX eRmZTKIFuN1NiaLZ7dev =MhXg -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20141223' into staging target-arm queue: * enable 32-bit EL3 (TrustZone) for vexpress and virt boards * add fw_cfg device to virt board for UEFI firmware config * support passing commandline kernel/initrd to firmware # gpg: Signature made Tue 23 Dec 2014 13:50:33 GMT using RSA key ID 14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" * remotes/pmaydell/tags/pull-target-arm-20141223: (31 commits) hw/arm/virt: enable passing of EFI-stubbed kernel to guest UEFI firmware hw/arm: pass pristine kernel image to guest firmware over fw_cfg hw/loader: split out load_image_gzipped_buffer() arm: add fw_cfg to "virt" board fw_cfg_mem: expose the "data_width" property with fw_cfg_init_mem_wide() fw_cfg_mem: introduce the "data_width" property exec: allows 8-byte accesses in subpage_ops fw_cfg_mem: flip ctl_mem_ops and data_mem_ops to DEVICE_BIG_ENDIAN fw_cfg_mem: max access size and region size are the same for data register fw_cfg: move boards to fw_cfg_init_io() / fw_cfg_init_mem() fw_cfg: hard separation between the MMIO and I/O port mappings target-arm: add cpu feature EL3 to CPUs with Security Extensions target-arm: Disable EL3 on unsupported machines target-arm: Breakout integratorcp and versatilepb cpu init target-arm: Set CPU has_el3 prop during virt init target-arm: Enable CPU has_el3 prop during VE init target-arm: Add arm_boot_info secure_boot control target-arm: Add ARMCPU secure property target-arm: Add feature unset function target-arm: Add virt machine secure property ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
ab0302ee76
@ -191,9 +191,9 @@ static void glue (audio_pcm_hw_gc_, TYPE) (HW **hwp)
|
||||
audio_detach_capture (hw);
|
||||
#endif
|
||||
QLIST_REMOVE (hw, entries);
|
||||
glue (hw->pcm_ops->fini_, TYPE) (hw);
|
||||
glue (s->nb_hw_voices_, TYPE) += 1;
|
||||
glue (audio_pcm_hw_free_resources_ ,TYPE) (hw);
|
||||
glue (hw->pcm_ops->fini_, TYPE) (hw);
|
||||
g_free (hw);
|
||||
*hwp = NULL;
|
||||
}
|
||||
|
13
exec.c
13
exec.c
@ -1768,7 +1768,7 @@ static uint64_t subpage_read(void *opaque, hwaddr addr,
|
||||
unsigned len)
|
||||
{
|
||||
subpage_t *subpage = opaque;
|
||||
uint8_t buf[4];
|
||||
uint8_t buf[8];
|
||||
|
||||
#if defined(DEBUG_SUBPAGE)
|
||||
printf("%s: subpage %p len %u addr " TARGET_FMT_plx "\n", __func__,
|
||||
@ -1782,6 +1782,8 @@ static uint64_t subpage_read(void *opaque, hwaddr addr,
|
||||
return lduw_p(buf);
|
||||
case 4:
|
||||
return ldl_p(buf);
|
||||
case 8:
|
||||
return ldq_p(buf);
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
@ -1791,7 +1793,7 @@ static void subpage_write(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned len)
|
||||
{
|
||||
subpage_t *subpage = opaque;
|
||||
uint8_t buf[4];
|
||||
uint8_t buf[8];
|
||||
|
||||
#if defined(DEBUG_SUBPAGE)
|
||||
printf("%s: subpage %p len %u addr " TARGET_FMT_plx
|
||||
@ -1808,6 +1810,9 @@ static void subpage_write(void *opaque, hwaddr addr,
|
||||
case 4:
|
||||
stl_p(buf, value);
|
||||
break;
|
||||
case 8:
|
||||
stq_p(buf, value);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
@ -1830,6 +1835,10 @@ static bool subpage_accepts(void *opaque, hwaddr addr,
|
||||
static const MemoryRegionOps subpage_ops = {
|
||||
.read = subpage_read,
|
||||
.write = subpage_write,
|
||||
.impl.min_access_size = 1,
|
||||
.impl.max_access_size = 8,
|
||||
.valid.min_access_size = 1,
|
||||
.valid.max_access_size = 8,
|
||||
.valid.accepts = subpage_accepts,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
@ -457,6 +457,16 @@ static void do_cpu_reset(void *opaque)
|
||||
env->thumb = info->entry & 1;
|
||||
}
|
||||
} else {
|
||||
/* If we are booting Linux then we need to check whether we are
|
||||
* booting into secure or non-secure state and adjust the state
|
||||
* accordingly. Out of reset, ARM is defined to be in secure state
|
||||
* (SCR.NS = 0), we change that here if non-secure boot has been
|
||||
* requested.
|
||||
*/
|
||||
if (arm_feature(env, ARM_FEATURE_EL3) && !info->secure_boot) {
|
||||
env->cp15.scr_el3 |= SCR_NS;
|
||||
}
|
||||
|
||||
if (CPU(cpu) == first_cpu) {
|
||||
if (env->aarch64) {
|
||||
env->pc = info->loader_start;
|
||||
@ -478,6 +488,55 @@ static void do_cpu_reset(void *opaque)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* load_image_to_fw_cfg() - Load an image file into an fw_cfg entry identified
|
||||
* by key.
|
||||
* @fw_cfg: The firmware config instance to store the data in.
|
||||
* @size_key: The firmware config key to store the size of the loaded
|
||||
* data under, with fw_cfg_add_i32().
|
||||
* @data_key: The firmware config key to store the loaded data under,
|
||||
* with fw_cfg_add_bytes().
|
||||
* @image_name: The name of the image file to load. If it is NULL, the
|
||||
* function returns without doing anything.
|
||||
* @try_decompress: Whether the image should be decompressed (gunzipped) before
|
||||
* adding it to fw_cfg. If decompression fails, the image is
|
||||
* loaded as-is.
|
||||
*
|
||||
* In case of failure, the function prints an error message to stderr and the
|
||||
* process exits with status 1.
|
||||
*/
|
||||
static void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key,
|
||||
uint16_t data_key, const char *image_name,
|
||||
bool try_decompress)
|
||||
{
|
||||
size_t size = -1;
|
||||
uint8_t *data;
|
||||
|
||||
if (image_name == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (try_decompress) {
|
||||
size = load_image_gzipped_buffer(image_name,
|
||||
LOAD_IMAGE_MAX_GUNZIP_BYTES, &data);
|
||||
}
|
||||
|
||||
if (size == (size_t)-1) {
|
||||
gchar *contents;
|
||||
gsize length;
|
||||
|
||||
if (!g_file_get_contents(image_name, &contents, &length, NULL)) {
|
||||
fprintf(stderr, "failed to load \"%s\"\n", image_name);
|
||||
exit(1);
|
||||
}
|
||||
size = length;
|
||||
data = (uint8_t *)contents;
|
||||
}
|
||||
|
||||
fw_cfg_add_i32(fw_cfg, size_key, size);
|
||||
fw_cfg_add_bytes(fw_cfg, data_key, data, size);
|
||||
}
|
||||
|
||||
void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
||||
{
|
||||
CPUState *cs;
|
||||
@ -500,19 +559,48 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
||||
}
|
||||
|
||||
/* Load the kernel. */
|
||||
if (!info->kernel_filename) {
|
||||
if (!info->kernel_filename || info->firmware_loaded) {
|
||||
|
||||
if (have_dtb(info)) {
|
||||
/* If we have a device tree blob, but no kernel to supply it to,
|
||||
* copy it to the base of RAM for a bootloader to pick up.
|
||||
/* If we have a device tree blob, but no kernel to supply it to (or
|
||||
* the kernel is supposed to be loaded by the bootloader), copy the
|
||||
* DTB to the base of RAM for the bootloader to pick up.
|
||||
*/
|
||||
if (load_dtb(info->loader_start, info, 0) < 0) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* If no kernel specified, do nothing; we will start from address 0
|
||||
* (typically a boot ROM image) in the same way as hardware.
|
||||
if (info->kernel_filename) {
|
||||
FWCfgState *fw_cfg;
|
||||
bool try_decompressing_kernel;
|
||||
|
||||
fw_cfg = fw_cfg_find();
|
||||
try_decompressing_kernel = arm_feature(&cpu->env,
|
||||
ARM_FEATURE_AARCH64);
|
||||
|
||||
/* Expose the kernel, the command line, and the initrd in fw_cfg.
|
||||
* We don't process them here at all, it's all left to the
|
||||
* firmware.
|
||||
*/
|
||||
load_image_to_fw_cfg(fw_cfg,
|
||||
FW_CFG_KERNEL_SIZE, FW_CFG_KERNEL_DATA,
|
||||
info->kernel_filename,
|
||||
try_decompressing_kernel);
|
||||
load_image_to_fw_cfg(fw_cfg,
|
||||
FW_CFG_INITRD_SIZE, FW_CFG_INITRD_DATA,
|
||||
info->initrd_filename, false);
|
||||
|
||||
if (info->kernel_cmdline) {
|
||||
fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
|
||||
strlen(info->kernel_cmdline) + 1);
|
||||
fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA,
|
||||
info->kernel_cmdline);
|
||||
}
|
||||
}
|
||||
|
||||
/* We will start from address 0 (typically a boot ROM image) in the
|
||||
* same way as hardware.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
@ -152,6 +152,17 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
|
||||
Object *cpuobj = object_new(object_class_get_name(cpu_oc));
|
||||
Error *err = NULL;
|
||||
|
||||
/* By default A9 CPUs have EL3 enabled. This board does not currently
|
||||
* support EL3 so the CPU EL3 property is disabled before realization.
|
||||
*/
|
||||
if (object_property_find(cpuobj, "has_el3", NULL)) {
|
||||
object_property_set_bool(cpuobj, false, "has_el3", &err);
|
||||
if (err) {
|
||||
error_report("%s", error_get_pretty(err));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
s->cpu[n] = ARM_CPU(cpuobj);
|
||||
object_property_set_int(cpuobj, EXYNOS4210_SMP_PRIVATE_BASE_ADDR,
|
||||
"reset-cbar", &error_abort);
|
||||
|
@ -241,6 +241,18 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
|
||||
cpuobj = object_new(object_class_get_name(oc));
|
||||
cpu = ARM_CPU(cpuobj);
|
||||
|
||||
/* By default A9 and A15 CPUs have EL3 enabled. This board does not
|
||||
* currently support EL3 so the CPU EL3 property is disabled before
|
||||
* realization.
|
||||
*/
|
||||
if (object_property_find(cpuobj, "has_el3", NULL)) {
|
||||
object_property_set_bool(cpuobj, false, "has_el3", &err);
|
||||
if (err) {
|
||||
error_report("%s", error_get_pretty(err));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (object_property_find(cpuobj, "reset-cbar", NULL)) {
|
||||
object_property_set_int(cpuobj, MPCORE_PERIPHBASE,
|
||||
"reset-cbar", &error_abort);
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "net/net.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
#define TYPE_INTEGRATOR_CM "integrator_core"
|
||||
#define INTEGRATOR_CM(obj) \
|
||||
@ -469,6 +470,8 @@ static void integratorcp_init(MachineState *machine)
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
ObjectClass *cpu_oc;
|
||||
Object *cpuobj;
|
||||
ARMCPU *cpu;
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||
@ -476,16 +479,40 @@ static void integratorcp_init(MachineState *machine)
|
||||
qemu_irq pic[32];
|
||||
DeviceState *dev;
|
||||
int i;
|
||||
Error *err = NULL;
|
||||
|
||||
if (!cpu_model) {
|
||||
cpu_model = "arm926";
|
||||
}
|
||||
cpu = cpu_arm_init(cpu_model);
|
||||
if (!cpu) {
|
||||
|
||||
cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
|
||||
if (!cpu_oc) {
|
||||
fprintf(stderr, "Unable to find CPU definition\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cpuobj = object_new(object_class_get_name(cpu_oc));
|
||||
|
||||
/* By default ARM1176 CPUs have EL3 enabled. This board does not
|
||||
* currently support EL3 so the CPU EL3 property is disabled before
|
||||
* realization.
|
||||
*/
|
||||
if (object_property_find(cpuobj, "has_el3", NULL)) {
|
||||
object_property_set_bool(cpuobj, false, "has_el3", &err);
|
||||
if (err) {
|
||||
error_report("%s", error_get_pretty(err));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
object_property_set_bool(cpuobj, true, "realized", &err);
|
||||
if (err) {
|
||||
error_report("%s", error_get_pretty(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cpu = ARM_CPU(cpuobj);
|
||||
|
||||
memory_region_init_ram(ram, NULL, "integrator.ram", ram_size, &error_abort);
|
||||
vmstate_register_ram_global(ram);
|
||||
/* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash. */
|
||||
|
@ -101,6 +101,18 @@ static void realview_init(MachineState *machine,
|
||||
Object *cpuobj = object_new(object_class_get_name(cpu_oc));
|
||||
Error *err = NULL;
|
||||
|
||||
/* By default A9,A15 and ARM1176 CPUs have EL3 enabled. This board
|
||||
* does not currently support EL3 so the CPU EL3 property is disabled
|
||||
* before realization.
|
||||
*/
|
||||
if (object_property_find(cpuobj, "has_el3", NULL)) {
|
||||
object_property_set_bool(cpuobj, false, "has_el3", &err);
|
||||
if (err) {
|
||||
error_report("%s", error_get_pretty(err));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_pb && is_mpcore) {
|
||||
object_property_set_int(cpuobj, periphbase, "reset-cbar", &err);
|
||||
if (err) {
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/block/flash.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
#define VERSATILE_FLASH_ADDR 0x34000000
|
||||
#define VERSATILE_FLASH_SIZE (64 * 1024 * 1024)
|
||||
@ -175,6 +176,8 @@ static struct arm_boot_info versatile_binfo;
|
||||
|
||||
static void versatile_init(MachineState *machine, int board_id)
|
||||
{
|
||||
ObjectClass *cpu_oc;
|
||||
Object *cpuobj;
|
||||
ARMCPU *cpu;
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||
@ -189,15 +192,40 @@ static void versatile_init(MachineState *machine, int board_id)
|
||||
int n;
|
||||
int done_smc = 0;
|
||||
DriveInfo *dinfo;
|
||||
Error *err = NULL;
|
||||
|
||||
if (!machine->cpu_model) {
|
||||
machine->cpu_model = "arm926";
|
||||
}
|
||||
cpu = cpu_arm_init(machine->cpu_model);
|
||||
if (!cpu) {
|
||||
|
||||
cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, machine->cpu_model);
|
||||
if (!cpu_oc) {
|
||||
fprintf(stderr, "Unable to find CPU definition\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cpuobj = object_new(object_class_get_name(cpu_oc));
|
||||
|
||||
/* By default ARM1176 CPUs have EL3 enabled. This board does not
|
||||
* currently support EL3 so the CPU EL3 property is disabled before
|
||||
* realization.
|
||||
*/
|
||||
if (object_property_find(cpuobj, "has_el3", NULL)) {
|
||||
object_property_set_bool(cpuobj, false, "has_el3", &err);
|
||||
if (err) {
|
||||
error_report("%s", error_get_pretty(err));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
object_property_set_bool(cpuobj, true, "realized", &err);
|
||||
if (err) {
|
||||
error_report("%s", error_get_pretty(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cpu = ARM_CPU(cpuobj);
|
||||
|
||||
memory_region_init_ram(ram, NULL, "versatile.ram", machine->ram_size,
|
||||
&error_abort);
|
||||
vmstate_register_ram_global(ram);
|
||||
|
@ -157,7 +157,27 @@ static hwaddr motherboard_aseries_map[] = {
|
||||
|
||||
typedef struct VEDBoardInfo VEDBoardInfo;
|
||||
|
||||
typedef void DBoardInitFn(const VEDBoardInfo *daughterboard,
|
||||
typedef struct {
|
||||
MachineClass parent;
|
||||
VEDBoardInfo *daughterboard;
|
||||
} VexpressMachineClass;
|
||||
|
||||
typedef struct {
|
||||
MachineState parent;
|
||||
bool secure;
|
||||
} VexpressMachineState;
|
||||
|
||||
#define TYPE_VEXPRESS_MACHINE "vexpress"
|
||||
#define TYPE_VEXPRESS_A9_MACHINE "vexpress-a9"
|
||||
#define TYPE_VEXPRESS_A15_MACHINE "vexpress-a15"
|
||||
#define VEXPRESS_MACHINE(obj) \
|
||||
OBJECT_CHECK(VexpressMachineState, (obj), TYPE_VEXPRESS_MACHINE)
|
||||
#define VEXPRESS_MACHINE_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(VexpressMachineClass, obj, TYPE_VEXPRESS_MACHINE)
|
||||
#define VEXPRESS_MACHINE_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(VexpressMachineClass, klass, TYPE_VEXPRESS_MACHINE)
|
||||
|
||||
typedef void DBoardInitFn(const VexpressMachineState *machine,
|
||||
ram_addr_t ram_size,
|
||||
const char *cpu_model,
|
||||
qemu_irq *pic);
|
||||
@ -176,7 +196,7 @@ struct VEDBoardInfo {
|
||||
};
|
||||
|
||||
static void init_cpus(const char *cpu_model, const char *privdev,
|
||||
hwaddr periphbase, qemu_irq *pic)
|
||||
hwaddr periphbase, qemu_irq *pic, bool secure)
|
||||
{
|
||||
ObjectClass *cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
|
||||
DeviceState *dev;
|
||||
@ -193,6 +213,10 @@ static void init_cpus(const char *cpu_model, const char *privdev,
|
||||
Object *cpuobj = object_new(object_class_get_name(cpu_oc));
|
||||
Error *err = NULL;
|
||||
|
||||
if (!secure) {
|
||||
object_property_set_bool(cpuobj, false, "has_el3", NULL);
|
||||
}
|
||||
|
||||
if (object_property_find(cpuobj, "reset-cbar", NULL)) {
|
||||
object_property_set_int(cpuobj, periphbase,
|
||||
"reset-cbar", &error_abort);
|
||||
@ -232,7 +256,7 @@ static void init_cpus(const char *cpu_model, const char *privdev,
|
||||
}
|
||||
}
|
||||
|
||||
static void a9_daughterboard_init(const VEDBoardInfo *daughterboard,
|
||||
static void a9_daughterboard_init(const VexpressMachineState *vms,
|
||||
ram_addr_t ram_size,
|
||||
const char *cpu_model,
|
||||
qemu_irq *pic)
|
||||
@ -268,7 +292,7 @@ static void a9_daughterboard_init(const VEDBoardInfo *daughterboard,
|
||||
memory_region_add_subregion(sysmem, 0x60000000, ram);
|
||||
|
||||
/* 0x1e000000 A9MPCore (SCU) private memory region */
|
||||
init_cpus(cpu_model, "a9mpcore_priv", 0x1e000000, pic);
|
||||
init_cpus(cpu_model, "a9mpcore_priv", 0x1e000000, pic, vms->secure);
|
||||
|
||||
/* Daughterboard peripherals : 0x10020000 .. 0x20000000 */
|
||||
|
||||
@ -322,7 +346,7 @@ static VEDBoardInfo a9_daughterboard = {
|
||||
.init = a9_daughterboard_init,
|
||||
};
|
||||
|
||||
static void a15_daughterboard_init(const VEDBoardInfo *daughterboard,
|
||||
static void a15_daughterboard_init(const VexpressMachineState *vms,
|
||||
ram_addr_t ram_size,
|
||||
const char *cpu_model,
|
||||
qemu_irq *pic)
|
||||
@ -354,7 +378,7 @@ static void a15_daughterboard_init(const VEDBoardInfo *daughterboard,
|
||||
memory_region_add_subregion(sysmem, 0x80000000, ram);
|
||||
|
||||
/* 0x2c000000 A15MPCore private memory region (GIC) */
|
||||
init_cpus(cpu_model, "a15mpcore_priv", 0x2c000000, pic);
|
||||
init_cpus(cpu_model, "a15mpcore_priv", 0x2c000000, pic, vms->secure);
|
||||
|
||||
/* A15 daughterboard peripherals: */
|
||||
|
||||
@ -513,9 +537,11 @@ static pflash_t *ve_pflash_cfi01_register(hwaddr base, const char *name,
|
||||
return OBJECT_CHECK(pflash_t, (dev), "cfi.pflash01");
|
||||
}
|
||||
|
||||
static void vexpress_common_init(VEDBoardInfo *daughterboard,
|
||||
MachineState *machine)
|
||||
static void vexpress_common_init(MachineState *machine)
|
||||
{
|
||||
VexpressMachineState *vms = VEXPRESS_MACHINE(machine);
|
||||
VexpressMachineClass *vmc = VEXPRESS_MACHINE_GET_CLASS(machine);
|
||||
VEDBoardInfo *daughterboard = vmc->daughterboard;;
|
||||
DeviceState *dev, *sysctl, *pl041;
|
||||
qemu_irq pic[64];
|
||||
uint32_t sys_id;
|
||||
@ -530,8 +556,7 @@ static void vexpress_common_init(VEDBoardInfo *daughterboard,
|
||||
const hwaddr *map = daughterboard->motherboard_map;
|
||||
int i;
|
||||
|
||||
daughterboard->init(daughterboard, machine->ram_size, machine->cpu_model,
|
||||
pic);
|
||||
daughterboard->init(vms, machine->ram_size, machine->cpu_model, pic);
|
||||
|
||||
/*
|
||||
* If a bios file was provided, attempt to map it into memory
|
||||
@ -678,39 +703,99 @@ static void vexpress_common_init(VEDBoardInfo *daughterboard,
|
||||
daughterboard->bootinfo.smp_bootreg_addr = map[VE_SYSREGS] + 0x30;
|
||||
daughterboard->bootinfo.gic_cpu_if_addr = daughterboard->gic_cpu_if_addr;
|
||||
daughterboard->bootinfo.modify_dtb = vexpress_modify_dtb;
|
||||
/* Indicate that when booting Linux we should be in secure state */
|
||||
daughterboard->bootinfo.secure_boot = true;
|
||||
arm_load_kernel(ARM_CPU(first_cpu), &daughterboard->bootinfo);
|
||||
}
|
||||
|
||||
static void vexpress_a9_init(MachineState *machine)
|
||||
static bool vexpress_get_secure(Object *obj, Error **errp)
|
||||
{
|
||||
vexpress_common_init(&a9_daughterboard, machine);
|
||||
VexpressMachineState *vms = VEXPRESS_MACHINE(obj);
|
||||
|
||||
return vms->secure;
|
||||
}
|
||||
|
||||
static void vexpress_a15_init(MachineState *machine)
|
||||
static void vexpress_set_secure(Object *obj, bool value, Error **errp)
|
||||
{
|
||||
vexpress_common_init(&a15_daughterboard, machine);
|
||||
VexpressMachineState *vms = VEXPRESS_MACHINE(obj);
|
||||
|
||||
vms->secure = value;
|
||||
}
|
||||
|
||||
static QEMUMachine vexpress_a9_machine = {
|
||||
.name = "vexpress-a9",
|
||||
.desc = "ARM Versatile Express for Cortex-A9",
|
||||
.init = vexpress_a9_init,
|
||||
.block_default_type = IF_SCSI,
|
||||
.max_cpus = 4,
|
||||
static void vexpress_instance_init(Object *obj)
|
||||
{
|
||||
VexpressMachineState *vms = VEXPRESS_MACHINE(obj);
|
||||
|
||||
/* EL3 is enabled by default on vexpress */
|
||||
vms->secure = true;
|
||||
object_property_add_bool(obj, "secure", vexpress_get_secure,
|
||||
vexpress_set_secure, NULL);
|
||||
object_property_set_description(obj, "secure",
|
||||
"Set on/off to enable/disable the ARM "
|
||||
"Security Extensions (TrustZone)",
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void vexpress_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->name = TYPE_VEXPRESS_MACHINE;
|
||||
mc->desc = "ARM Versatile Express";
|
||||
mc->init = vexpress_common_init;
|
||||
mc->block_default_type = IF_SCSI;
|
||||
mc->max_cpus = 4;
|
||||
}
|
||||
|
||||
static void vexpress_a9_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
VexpressMachineClass *vmc = VEXPRESS_MACHINE_CLASS(oc);
|
||||
|
||||
mc->name = TYPE_VEXPRESS_A9_MACHINE;
|
||||
mc->desc = "ARM Versatile Express for Cortex-A9";
|
||||
|
||||
vmc->daughterboard = &a9_daughterboard;;
|
||||
}
|
||||
|
||||
static void vexpress_a15_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
VexpressMachineClass *vmc = VEXPRESS_MACHINE_CLASS(oc);
|
||||
|
||||
mc->name = TYPE_VEXPRESS_A15_MACHINE;
|
||||
mc->desc = "ARM Versatile Express for Cortex-A15";
|
||||
|
||||
vmc->daughterboard = &a15_daughterboard;
|
||||
}
|
||||
|
||||
static const TypeInfo vexpress_info = {
|
||||
.name = TYPE_VEXPRESS_MACHINE,
|
||||
.parent = TYPE_MACHINE,
|
||||
.abstract = true,
|
||||
.instance_size = sizeof(VexpressMachineState),
|
||||
.instance_init = vexpress_instance_init,
|
||||
.class_size = sizeof(VexpressMachineClass),
|
||||
.class_init = vexpress_class_init,
|
||||
};
|
||||
|
||||
static QEMUMachine vexpress_a15_machine = {
|
||||
.name = "vexpress-a15",
|
||||
.desc = "ARM Versatile Express for Cortex-A15",
|
||||
.init = vexpress_a15_init,
|
||||
.block_default_type = IF_SCSI,
|
||||
.max_cpus = 4,
|
||||
static const TypeInfo vexpress_a9_info = {
|
||||
.name = TYPE_VEXPRESS_A9_MACHINE,
|
||||
.parent = TYPE_VEXPRESS_MACHINE,
|
||||
.class_init = vexpress_a9_class_init,
|
||||
};
|
||||
|
||||
static const TypeInfo vexpress_a15_info = {
|
||||
.name = TYPE_VEXPRESS_A15_MACHINE,
|
||||
.parent = TYPE_VEXPRESS_MACHINE,
|
||||
.class_init = vexpress_a15_class_init,
|
||||
};
|
||||
|
||||
static void vexpress_machine_init(void)
|
||||
{
|
||||
qemu_register_machine(&vexpress_a9_machine);
|
||||
qemu_register_machine(&vexpress_a15_machine);
|
||||
type_register_static(&vexpress_info);
|
||||
type_register_static(&vexpress_a9_info);
|
||||
type_register_static(&vexpress_a15_info);
|
||||
}
|
||||
|
||||
machine_init(vexpress_machine_init);
|
||||
|
@ -68,6 +68,7 @@ enum {
|
||||
VIRT_UART,
|
||||
VIRT_MMIO,
|
||||
VIRT_RTC,
|
||||
VIRT_FW_CFG,
|
||||
};
|
||||
|
||||
typedef struct MemMapEntry {
|
||||
@ -86,6 +87,24 @@ typedef struct VirtBoardInfo {
|
||||
uint32_t clock_phandle;
|
||||
} VirtBoardInfo;
|
||||
|
||||
typedef struct {
|
||||
MachineClass parent;
|
||||
VirtBoardInfo *daughterboard;
|
||||
} VirtMachineClass;
|
||||
|
||||
typedef struct {
|
||||
MachineState parent;
|
||||
bool secure;
|
||||
} VirtMachineState;
|
||||
|
||||
#define TYPE_VIRT_MACHINE "virt"
|
||||
#define VIRT_MACHINE(obj) \
|
||||
OBJECT_CHECK(VirtMachineState, (obj), TYPE_VIRT_MACHINE)
|
||||
#define VIRT_MACHINE_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(VirtMachineClass, obj, TYPE_VIRT_MACHINE)
|
||||
#define VIRT_MACHINE_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(VirtMachineClass, klass, TYPE_VIRT_MACHINE)
|
||||
|
||||
/* Addresses and sizes of our components.
|
||||
* 0..128MB is space for a flash device so we can run bootrom code such as UEFI.
|
||||
* 128MB..256MB is used for miscellaneous device I/O.
|
||||
@ -107,6 +126,7 @@ static const MemMapEntry a15memmap[] = {
|
||||
[VIRT_GIC_CPU] = { 0x08010000, 0x00010000 },
|
||||
[VIRT_UART] = { 0x09000000, 0x00001000 },
|
||||
[VIRT_RTC] = { 0x09010000, 0x00001000 },
|
||||
[VIRT_FW_CFG] = { 0x09020000, 0x0000000a },
|
||||
[VIRT_MMIO] = { 0x0a000000, 0x00000200 },
|
||||
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
|
||||
/* 0x10000000 .. 0x40000000 reserved for PCI */
|
||||
@ -519,6 +539,23 @@ static void create_flash(const VirtBoardInfo *vbi)
|
||||
g_free(nodename);
|
||||
}
|
||||
|
||||
static void create_fw_cfg(const VirtBoardInfo *vbi)
|
||||
{
|
||||
hwaddr base = vbi->memmap[VIRT_FW_CFG].base;
|
||||
hwaddr size = vbi->memmap[VIRT_FW_CFG].size;
|
||||
char *nodename;
|
||||
|
||||
fw_cfg_init_mem_wide(base + 8, base, 8);
|
||||
|
||||
nodename = g_strdup_printf("/fw-cfg@%" PRIx64, base);
|
||||
qemu_fdt_add_subnode(vbi->fdt, nodename);
|
||||
qemu_fdt_setprop_string(vbi->fdt, nodename,
|
||||
"compatible", "qemu,fw-cfg-mmio");
|
||||
qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
|
||||
2, base, 2, size);
|
||||
g_free(nodename);
|
||||
}
|
||||
|
||||
static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
|
||||
{
|
||||
const VirtBoardInfo *board = (const VirtBoardInfo *)binfo;
|
||||
@ -529,6 +566,7 @@ static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
|
||||
|
||||
static void machvirt_init(MachineState *machine)
|
||||
{
|
||||
VirtMachineState *vms = VIRT_MACHINE(machine);
|
||||
qemu_irq pic[NUM_IRQS];
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
int n;
|
||||
@ -566,6 +604,10 @@ static void machvirt_init(MachineState *machine)
|
||||
}
|
||||
cpuobj = object_new(object_class_get_name(oc));
|
||||
|
||||
if (!vms->secure) {
|
||||
object_property_set_bool(cpuobj, false, "has_el3", NULL);
|
||||
}
|
||||
|
||||
object_property_set_int(cpuobj, QEMU_PSCI_CONDUIT_HVC, "psci-conduit",
|
||||
NULL);
|
||||
|
||||
@ -604,6 +646,8 @@ static void machvirt_init(MachineState *machine)
|
||||
*/
|
||||
create_virtio_devices(vbi, pic);
|
||||
|
||||
create_fw_cfg(vbi);
|
||||
|
||||
vbi->bootinfo.ram_size = machine->ram_size;
|
||||
vbi->bootinfo.kernel_filename = machine->kernel_filename;
|
||||
vbi->bootinfo.kernel_cmdline = machine->kernel_cmdline;
|
||||
@ -612,19 +656,60 @@ static void machvirt_init(MachineState *machine)
|
||||
vbi->bootinfo.board_id = -1;
|
||||
vbi->bootinfo.loader_start = vbi->memmap[VIRT_MEM].base;
|
||||
vbi->bootinfo.get_dtb = machvirt_dtb;
|
||||
vbi->bootinfo.firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0);
|
||||
arm_load_kernel(ARM_CPU(first_cpu), &vbi->bootinfo);
|
||||
}
|
||||
|
||||
static QEMUMachine machvirt_a15_machine = {
|
||||
.name = "virt",
|
||||
.desc = "ARM Virtual Machine",
|
||||
.init = machvirt_init,
|
||||
.max_cpus = 8,
|
||||
static bool virt_get_secure(Object *obj, Error **errp)
|
||||
{
|
||||
VirtMachineState *vms = VIRT_MACHINE(obj);
|
||||
|
||||
return vms->secure;
|
||||
}
|
||||
|
||||
static void virt_set_secure(Object *obj, bool value, Error **errp)
|
||||
{
|
||||
VirtMachineState *vms = VIRT_MACHINE(obj);
|
||||
|
||||
vms->secure = value;
|
||||
}
|
||||
|
||||
static void virt_instance_init(Object *obj)
|
||||
{
|
||||
VirtMachineState *vms = VIRT_MACHINE(obj);
|
||||
|
||||
/* EL3 is enabled by default on virt */
|
||||
vms->secure = true;
|
||||
object_property_add_bool(obj, "secure", virt_get_secure,
|
||||
virt_set_secure, NULL);
|
||||
object_property_set_description(obj, "secure",
|
||||
"Set on/off to enable/disable the ARM "
|
||||
"Security Extensions (TrustZone)",
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void virt_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->name = TYPE_VIRT_MACHINE;
|
||||
mc->desc = "ARM Virtual Machine",
|
||||
mc->init = machvirt_init;
|
||||
mc->max_cpus = 8;
|
||||
}
|
||||
|
||||
static const TypeInfo machvirt_info = {
|
||||
.name = TYPE_VIRT_MACHINE,
|
||||
.parent = TYPE_MACHINE,
|
||||
.instance_size = sizeof(VirtMachineState),
|
||||
.instance_init = virt_instance_init,
|
||||
.class_size = sizeof(VirtMachineClass),
|
||||
.class_init = virt_class_init,
|
||||
};
|
||||
|
||||
static void machvirt_machine_init(void)
|
||||
{
|
||||
qemu_register_machine(&machvirt_a15_machine);
|
||||
type_register_static(&machvirt_info);
|
||||
}
|
||||
|
||||
machine_init(machvirt_machine_init);
|
||||
|
@ -126,6 +126,18 @@ static void zynq_init(MachineState *machine)
|
||||
|
||||
cpu = ARM_CPU(object_new(object_class_get_name(cpu_oc)));
|
||||
|
||||
/* By default A9 CPUs have EL3 enabled. This board does not
|
||||
* currently support EL3 so the CPU EL3 property is disabled before
|
||||
* realization.
|
||||
*/
|
||||
if (object_property_find(OBJECT(cpu), "has_el3", NULL)) {
|
||||
object_property_set_bool(OBJECT(cpu), false, "has_el3", &err);
|
||||
if (err) {
|
||||
error_report("%s", error_get_pretty(err));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
object_property_set_int(OBJECT(cpu), ZYNQ_BOARD_MIDR, "midr", &err);
|
||||
if (err) {
|
||||
error_report("%s", error_get_pretty(err));
|
||||
|
@ -614,14 +614,9 @@ int load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz)
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
/* This simply prevents g_malloc in the function below from allocating
|
||||
* a huge amount of memory, by placing a limit on the maximum
|
||||
* uncompressed image size that load_image_gzipped will read.
|
||||
*/
|
||||
#define LOAD_IMAGE_MAX_GUNZIP_BYTES (256 << 20)
|
||||
|
||||
/* Load a gzip-compressed kernel. */
|
||||
int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz)
|
||||
/* Load a gzip-compressed kernel to a dynamically allocated buffer. */
|
||||
int load_image_gzipped_buffer(const char *filename, uint64_t max_sz,
|
||||
uint8_t **buffer)
|
||||
{
|
||||
uint8_t *compressed_data = NULL;
|
||||
uint8_t *data = NULL;
|
||||
@ -653,8 +648,11 @@ int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz)
|
||||
goto out;
|
||||
}
|
||||
|
||||
rom_add_blob_fixed(filename, data, bytes, addr);
|
||||
/* trim to actual size and return to caller */
|
||||
*buffer = g_realloc(data, bytes);
|
||||
ret = bytes;
|
||||
/* ownership has been transferred to caller */
|
||||
data = NULL;
|
||||
|
||||
out:
|
||||
g_free(compressed_data);
|
||||
@ -662,6 +660,20 @@ int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Load a gzip-compressed kernel. */
|
||||
int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz)
|
||||
{
|
||||
int bytes;
|
||||
uint8_t *data;
|
||||
|
||||
bytes = load_image_gzipped_buffer(filename, max_sz, &data);
|
||||
if (bytes != -1) {
|
||||
rom_add_blob_fixed(filename, data, bytes, addr);
|
||||
g_free(data);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/*
|
||||
* Functions for reboot-persistent memory regions.
|
||||
* - used for vga bios and option roms.
|
||||
|
@ -291,48 +291,93 @@ static void machine_initfn(Object *obj)
|
||||
|
||||
object_property_add_str(obj, "accel",
|
||||
machine_get_accel, machine_set_accel, NULL);
|
||||
object_property_set_description(obj, "accel",
|
||||
"Accelerator list",
|
||||
NULL);
|
||||
object_property_add_bool(obj, "kernel-irqchip",
|
||||
machine_get_kernel_irqchip,
|
||||
machine_set_kernel_irqchip,
|
||||
NULL);
|
||||
object_property_set_description(obj, "kernel-irqchip",
|
||||
"Use KVM in-kernel irqchip",
|
||||
NULL);
|
||||
object_property_add(obj, "kvm-shadow-mem", "int",
|
||||
machine_get_kvm_shadow_mem,
|
||||
machine_set_kvm_shadow_mem,
|
||||
NULL, NULL, NULL);
|
||||
object_property_set_description(obj, "kvm-shadow-mem",
|
||||
"KVM shadow MMU size",
|
||||
NULL);
|
||||
object_property_add_str(obj, "kernel",
|
||||
machine_get_kernel, machine_set_kernel, NULL);
|
||||
object_property_set_description(obj, "kernel",
|
||||
"Linux kernel image file",
|
||||
NULL);
|
||||
object_property_add_str(obj, "initrd",
|
||||
machine_get_initrd, machine_set_initrd, NULL);
|
||||
object_property_set_description(obj, "initrd",
|
||||
"Linux initial ramdisk file",
|
||||
NULL);
|
||||
object_property_add_str(obj, "append",
|
||||
machine_get_append, machine_set_append, NULL);
|
||||
object_property_set_description(obj, "append",
|
||||
"Linux kernel command line",
|
||||
NULL);
|
||||
object_property_add_str(obj, "dtb",
|
||||
machine_get_dtb, machine_set_dtb, NULL);
|
||||
object_property_set_description(obj, "dtb",
|
||||
"Linux kernel device tree file",
|
||||
NULL);
|
||||
object_property_add_str(obj, "dumpdtb",
|
||||
machine_get_dumpdtb, machine_set_dumpdtb, NULL);
|
||||
object_property_set_description(obj, "dumpdtb",
|
||||
"Dump current dtb to a file and quit",
|
||||
NULL);
|
||||
object_property_add(obj, "phandle-start", "int",
|
||||
machine_get_phandle_start,
|
||||
machine_set_phandle_start,
|
||||
NULL, NULL, NULL);
|
||||
object_property_set_description(obj, "phandle-start",
|
||||
"The first phandle ID we may generate dynamically",
|
||||
NULL);
|
||||
object_property_add_str(obj, "dt-compatible",
|
||||
machine_get_dt_compatible,
|
||||
machine_set_dt_compatible,
|
||||
NULL);
|
||||
object_property_set_description(obj, "dt-compatible",
|
||||
"Overrides the \"compatible\" property of the dt root node",
|
||||
NULL);
|
||||
object_property_add_bool(obj, "dump-guest-core",
|
||||
machine_get_dump_guest_core,
|
||||
machine_set_dump_guest_core,
|
||||
NULL);
|
||||
object_property_set_description(obj, "dump-guest-core",
|
||||
"Include guest memory in a core dump",
|
||||
NULL);
|
||||
object_property_add_bool(obj, "mem-merge",
|
||||
machine_get_mem_merge,
|
||||
machine_set_mem_merge, NULL);
|
||||
object_property_set_description(obj, "mem-merge",
|
||||
"Enable/disable memory merge support",
|
||||
NULL);
|
||||
object_property_add_bool(obj, "usb",
|
||||
machine_get_usb,
|
||||
machine_set_usb, NULL);
|
||||
object_property_set_description(obj, "usb",
|
||||
"Set on/off to enable/disable usb",
|
||||
NULL);
|
||||
object_property_add_str(obj, "firmware",
|
||||
machine_get_firmware,
|
||||
machine_set_firmware, NULL);
|
||||
object_property_set_description(obj, "firmware",
|
||||
"Firmware image",
|
||||
NULL);
|
||||
object_property_add_bool(obj, "iommu",
|
||||
machine_get_iommu,
|
||||
machine_set_iommu, NULL);
|
||||
object_property_set_description(obj, "iommu",
|
||||
"Set on/off to enable/disable Intel IOMMU (VT-d)",
|
||||
NULL);
|
||||
|
||||
/* Register notifier when init is done for sysbus sanity checks */
|
||||
ms->sysbus_notifier.notify = machine_init_notify;
|
||||
|
11
hw/i386/pc.c
11
hw/i386/pc.c
@ -649,7 +649,7 @@ static FWCfgState *bochs_bios_init(void)
|
||||
int i, j;
|
||||
unsigned int apic_id_limit = pc_apic_id_limit(max_cpus);
|
||||
|
||||
fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0);
|
||||
fw_cfg = fw_cfg_init_io(BIOS_CFG_IOPORT);
|
||||
/* FW_CFG_MAX_CPUS is a bit confusing/problematic on x86:
|
||||
*
|
||||
* SeaBIOS needs FW_CFG_MAX_CPUS for CPU hotplug, but the CPU hotplug
|
||||
@ -1170,7 +1170,7 @@ FWCfgState *xen_load_linux(const char *kernel_filename,
|
||||
|
||||
assert(kernel_filename != NULL);
|
||||
|
||||
fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0);
|
||||
fw_cfg = fw_cfg_init_io(BIOS_CFG_IOPORT);
|
||||
rom_set_fw(fw_cfg);
|
||||
|
||||
load_linux(fw_cfg, kernel_filename, initrd_filename,
|
||||
@ -1805,17 +1805,24 @@ static void pc_machine_initfn(Object *obj)
|
||||
object_property_add(obj, PC_MACHINE_MEMHP_REGION_SIZE, "int",
|
||||
pc_machine_get_hotplug_memory_region_size,
|
||||
NULL, NULL, NULL, NULL);
|
||||
|
||||
pcms->max_ram_below_4g = 1ULL << 32; /* 4G */
|
||||
object_property_add(obj, PC_MACHINE_MAX_RAM_BELOW_4G, "size",
|
||||
pc_machine_get_max_ram_below_4g,
|
||||
pc_machine_set_max_ram_below_4g,
|
||||
NULL, NULL, NULL);
|
||||
object_property_set_description(obj, PC_MACHINE_MAX_RAM_BELOW_4G,
|
||||
"Maximum ram below the 4G boundary (32bit boundary)",
|
||||
NULL);
|
||||
|
||||
pcms->vmport = ON_OFF_AUTO_AUTO;
|
||||
object_property_add(obj, PC_MACHINE_VMPORT, "OnOffAuto",
|
||||
pc_machine_get_vmport,
|
||||
pc_machine_set_vmport,
|
||||
NULL, NULL, NULL);
|
||||
object_property_set_description(obj, PC_MACHINE_VMPORT,
|
||||
"Enable vmport (pc & q35)",
|
||||
NULL);
|
||||
|
||||
pcms->enforce_aligned_dimm = true;
|
||||
object_property_add_bool(obj, PC_MACHINE_ENFORCE_ALIGNED_DIMM,
|
||||
|
@ -31,11 +31,16 @@
|
||||
#include "qemu/config-file.h"
|
||||
|
||||
#define FW_CFG_SIZE 2
|
||||
#define FW_CFG_DATA_SIZE 1
|
||||
#define TYPE_FW_CFG "fw_cfg"
|
||||
#define FW_CFG_NAME "fw_cfg"
|
||||
#define FW_CFG_PATH "/machine/" FW_CFG_NAME
|
||||
#define FW_CFG(obj) OBJECT_CHECK(FWCfgState, (obj), TYPE_FW_CFG)
|
||||
|
||||
#define TYPE_FW_CFG "fw_cfg"
|
||||
#define TYPE_FW_CFG_IO "fw_cfg_io"
|
||||
#define TYPE_FW_CFG_MEM "fw_cfg_mem"
|
||||
|
||||
#define FW_CFG(obj) OBJECT_CHECK(FWCfgState, (obj), TYPE_FW_CFG)
|
||||
#define FW_CFG_IO(obj) OBJECT_CHECK(FWCfgIoState, (obj), TYPE_FW_CFG_IO)
|
||||
#define FW_CFG_MEM(obj) OBJECT_CHECK(FWCfgMemState, (obj), TYPE_FW_CFG_MEM)
|
||||
|
||||
typedef struct FWCfgEntry {
|
||||
uint32_t len;
|
||||
@ -50,8 +55,6 @@ struct FWCfgState {
|
||||
SysBusDevice parent_obj;
|
||||
/*< public >*/
|
||||
|
||||
MemoryRegion ctl_iomem, data_iomem, comb_iomem;
|
||||
uint32_t ctl_iobase, data_iobase;
|
||||
FWCfgEntry entries[2][FW_CFG_MAX_ENTRY];
|
||||
FWCfgFiles *files;
|
||||
uint16_t cur_entry;
|
||||
@ -59,6 +62,25 @@ struct FWCfgState {
|
||||
Notifier machine_ready;
|
||||
};
|
||||
|
||||
struct FWCfgIoState {
|
||||
/*< private >*/
|
||||
FWCfgState parent_obj;
|
||||
/*< public >*/
|
||||
|
||||
MemoryRegion comb_iomem;
|
||||
uint32_t iobase;
|
||||
};
|
||||
|
||||
struct FWCfgMemState {
|
||||
/*< private >*/
|
||||
FWCfgState parent_obj;
|
||||
/*< public >*/
|
||||
|
||||
MemoryRegion ctl_iomem, data_iomem;
|
||||
uint32_t data_width;
|
||||
MemoryRegionOps wide_data_ops;
|
||||
};
|
||||
|
||||
#define JPG_FILE 0
|
||||
#define BMP_FILE 1
|
||||
|
||||
@ -264,13 +286,58 @@ static uint8_t fw_cfg_read(FWCfgState *s)
|
||||
static uint64_t fw_cfg_data_mem_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
return fw_cfg_read(opaque);
|
||||
FWCfgState *s = opaque;
|
||||
uint8_t buf[8];
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < size; ++i) {
|
||||
buf[i] = fw_cfg_read(s);
|
||||
}
|
||||
switch (size) {
|
||||
case 1:
|
||||
return buf[0];
|
||||
case 2:
|
||||
return lduw_he_p(buf);
|
||||
case 4:
|
||||
return (uint32_t)ldl_he_p(buf);
|
||||
case 8:
|
||||
return ldq_he_p(buf);
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
static void fw_cfg_data_mem_write(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
fw_cfg_write(opaque, (uint8_t)value);
|
||||
FWCfgState *s = opaque;
|
||||
uint8_t buf[8];
|
||||
unsigned i;
|
||||
|
||||
switch (size) {
|
||||
case 1:
|
||||
buf[0] = value;
|
||||
break;
|
||||
case 2:
|
||||
stw_he_p(buf, value);
|
||||
break;
|
||||
case 4:
|
||||
stl_he_p(buf, value);
|
||||
break;
|
||||
case 8:
|
||||
stq_he_p(buf, value);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
for (i = 0; i < size; ++i) {
|
||||
fw_cfg_write(s, buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static bool fw_cfg_data_mem_valid(void *opaque, hwaddr addr,
|
||||
unsigned size, bool is_write)
|
||||
{
|
||||
return addr == 0;
|
||||
}
|
||||
|
||||
static void fw_cfg_ctl_mem_write(void *opaque, hwaddr addr,
|
||||
@ -312,17 +379,18 @@ static bool fw_cfg_comb_valid(void *opaque, hwaddr addr,
|
||||
|
||||
static const MemoryRegionOps fw_cfg_ctl_mem_ops = {
|
||||
.write = fw_cfg_ctl_mem_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.endianness = DEVICE_BIG_ENDIAN,
|
||||
.valid.accepts = fw_cfg_ctl_mem_valid,
|
||||
};
|
||||
|
||||
static const MemoryRegionOps fw_cfg_data_mem_ops = {
|
||||
.read = fw_cfg_data_mem_read,
|
||||
.write = fw_cfg_data_mem_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.endianness = DEVICE_BIG_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 1,
|
||||
.accepts = fw_cfg_data_mem_valid,
|
||||
},
|
||||
};
|
||||
|
||||
@ -560,19 +628,11 @@ static void fw_cfg_machine_ready(struct Notifier *n, void *data)
|
||||
qemu_register_reset(fw_cfg_machine_reset, s);
|
||||
}
|
||||
|
||||
FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
|
||||
hwaddr ctl_addr, hwaddr data_addr)
|
||||
|
||||
|
||||
static void fw_cfg_init1(DeviceState *dev)
|
||||
{
|
||||
DeviceState *dev;
|
||||
SysBusDevice *d;
|
||||
FWCfgState *s;
|
||||
|
||||
dev = qdev_create(NULL, TYPE_FW_CFG);
|
||||
qdev_prop_set_uint32(dev, "ctl_iobase", ctl_port);
|
||||
qdev_prop_set_uint32(dev, "data_iobase", data_port);
|
||||
d = SYS_BUS_DEVICE(dev);
|
||||
|
||||
s = FW_CFG(dev);
|
||||
FWCfgState *s = FW_CFG(dev);
|
||||
|
||||
assert(!object_resolve_path(FW_CFG_PATH, NULL));
|
||||
|
||||
@ -580,12 +640,6 @@ FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
|
||||
|
||||
qdev_init_nofail(dev);
|
||||
|
||||
if (ctl_addr) {
|
||||
sysbus_mmio_map(d, 0, ctl_addr);
|
||||
}
|
||||
if (data_addr) {
|
||||
sysbus_mmio_map(d, 1, data_addr);
|
||||
}
|
||||
fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (char *)"QEMU", 4);
|
||||
fw_cfg_add_bytes(s, FW_CFG_UUID, qemu_uuid, 16);
|
||||
fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC, (uint16_t)(display_type == DT_NOGRAPHIC));
|
||||
@ -596,48 +650,43 @@ FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
|
||||
|
||||
s->machine_ready.notify = fw_cfg_machine_ready;
|
||||
qemu_add_machine_init_done_notifier(&s->machine_ready);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static void fw_cfg_initfn(Object *obj)
|
||||
FWCfgState *fw_cfg_init_io(uint32_t iobase)
|
||||
{
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
FWCfgState *s = FW_CFG(obj);
|
||||
DeviceState *dev;
|
||||
|
||||
memory_region_init_io(&s->ctl_iomem, OBJECT(s), &fw_cfg_ctl_mem_ops, s,
|
||||
"fwcfg.ctl", FW_CFG_SIZE);
|
||||
sysbus_init_mmio(sbd, &s->ctl_iomem);
|
||||
memory_region_init_io(&s->data_iomem, OBJECT(s), &fw_cfg_data_mem_ops, s,
|
||||
"fwcfg.data", FW_CFG_DATA_SIZE);
|
||||
sysbus_init_mmio(sbd, &s->data_iomem);
|
||||
/* In case ctl and data overlap: */
|
||||
memory_region_init_io(&s->comb_iomem, OBJECT(s), &fw_cfg_comb_mem_ops, s,
|
||||
"fwcfg", FW_CFG_SIZE);
|
||||
dev = qdev_create(NULL, TYPE_FW_CFG_IO);
|
||||
qdev_prop_set_uint32(dev, "iobase", iobase);
|
||||
fw_cfg_init1(dev);
|
||||
|
||||
return FW_CFG(dev);
|
||||
}
|
||||
|
||||
static void fw_cfg_realize(DeviceState *dev, Error **errp)
|
||||
FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr, hwaddr data_addr,
|
||||
uint32_t data_width)
|
||||
{
|
||||
FWCfgState *s = FW_CFG(dev);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
DeviceState *dev;
|
||||
SysBusDevice *sbd;
|
||||
|
||||
if (s->ctl_iobase + 1 == s->data_iobase) {
|
||||
sysbus_add_io(sbd, s->ctl_iobase, &s->comb_iomem);
|
||||
} else {
|
||||
if (s->ctl_iobase) {
|
||||
sysbus_add_io(sbd, s->ctl_iobase, &s->ctl_iomem);
|
||||
}
|
||||
if (s->data_iobase) {
|
||||
sysbus_add_io(sbd, s->data_iobase, &s->data_iomem);
|
||||
}
|
||||
}
|
||||
dev = qdev_create(NULL, TYPE_FW_CFG_MEM);
|
||||
qdev_prop_set_uint32(dev, "data_width", data_width);
|
||||
|
||||
fw_cfg_init1(dev);
|
||||
|
||||
sbd = SYS_BUS_DEVICE(dev);
|
||||
sysbus_mmio_map(sbd, 0, ctl_addr);
|
||||
sysbus_mmio_map(sbd, 1, data_addr);
|
||||
|
||||
return FW_CFG(dev);
|
||||
}
|
||||
|
||||
FWCfgState *fw_cfg_init_mem(hwaddr ctl_addr, hwaddr data_addr)
|
||||
{
|
||||
return fw_cfg_init_mem_wide(ctl_addr, data_addr,
|
||||
fw_cfg_data_mem_ops.valid.max_access_size);
|
||||
}
|
||||
|
||||
static Property fw_cfg_properties[] = {
|
||||
DEFINE_PROP_UINT32("ctl_iobase", FWCfgState, ctl_iobase, -1),
|
||||
DEFINE_PROP_UINT32("data_iobase", FWCfgState, data_iobase, -1),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
FWCfgState *fw_cfg_find(void)
|
||||
{
|
||||
@ -648,23 +697,102 @@ static void fw_cfg_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = fw_cfg_realize;
|
||||
dc->reset = fw_cfg_reset;
|
||||
dc->vmsd = &vmstate_fw_cfg;
|
||||
dc->props = fw_cfg_properties;
|
||||
}
|
||||
|
||||
static const TypeInfo fw_cfg_info = {
|
||||
.name = TYPE_FW_CFG,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(FWCfgState),
|
||||
.instance_init = fw_cfg_initfn,
|
||||
.class_init = fw_cfg_class_init,
|
||||
};
|
||||
|
||||
|
||||
static Property fw_cfg_io_properties[] = {
|
||||
DEFINE_PROP_UINT32("iobase", FWCfgIoState, iobase, -1),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void fw_cfg_io_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
FWCfgIoState *s = FW_CFG_IO(dev);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
|
||||
memory_region_init_io(&s->comb_iomem, OBJECT(s), &fw_cfg_comb_mem_ops,
|
||||
FW_CFG(s), "fwcfg", FW_CFG_SIZE);
|
||||
sysbus_add_io(sbd, s->iobase, &s->comb_iomem);
|
||||
}
|
||||
|
||||
static void fw_cfg_io_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = fw_cfg_io_realize;
|
||||
dc->props = fw_cfg_io_properties;
|
||||
}
|
||||
|
||||
static const TypeInfo fw_cfg_io_info = {
|
||||
.name = TYPE_FW_CFG_IO,
|
||||
.parent = TYPE_FW_CFG,
|
||||
.instance_size = sizeof(FWCfgIoState),
|
||||
.class_init = fw_cfg_io_class_init,
|
||||
};
|
||||
|
||||
|
||||
static Property fw_cfg_mem_properties[] = {
|
||||
DEFINE_PROP_UINT32("data_width", FWCfgMemState, data_width, -1),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void fw_cfg_mem_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
FWCfgMemState *s = FW_CFG_MEM(dev);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
const MemoryRegionOps *data_ops = &fw_cfg_data_mem_ops;
|
||||
|
||||
memory_region_init_io(&s->ctl_iomem, OBJECT(s), &fw_cfg_ctl_mem_ops,
|
||||
FW_CFG(s), "fwcfg.ctl", FW_CFG_SIZE);
|
||||
sysbus_init_mmio(sbd, &s->ctl_iomem);
|
||||
|
||||
if (s->data_width > data_ops->valid.max_access_size) {
|
||||
/* memberwise copy because the "old_mmio" member is const */
|
||||
s->wide_data_ops.read = data_ops->read;
|
||||
s->wide_data_ops.write = data_ops->write;
|
||||
s->wide_data_ops.endianness = data_ops->endianness;
|
||||
s->wide_data_ops.valid = data_ops->valid;
|
||||
s->wide_data_ops.impl = data_ops->impl;
|
||||
|
||||
s->wide_data_ops.valid.max_access_size = s->data_width;
|
||||
s->wide_data_ops.impl.max_access_size = s->data_width;
|
||||
data_ops = &s->wide_data_ops;
|
||||
}
|
||||
memory_region_init_io(&s->data_iomem, OBJECT(s), data_ops, FW_CFG(s),
|
||||
"fwcfg.data", data_ops->valid.max_access_size);
|
||||
sysbus_init_mmio(sbd, &s->data_iomem);
|
||||
}
|
||||
|
||||
static void fw_cfg_mem_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = fw_cfg_mem_realize;
|
||||
dc->props = fw_cfg_mem_properties;
|
||||
}
|
||||
|
||||
static const TypeInfo fw_cfg_mem_info = {
|
||||
.name = TYPE_FW_CFG_MEM,
|
||||
.parent = TYPE_FW_CFG,
|
||||
.instance_size = sizeof(FWCfgMemState),
|
||||
.class_init = fw_cfg_mem_class_init,
|
||||
};
|
||||
|
||||
|
||||
static void fw_cfg_register_types(void)
|
||||
{
|
||||
type_register_static(&fw_cfg_info);
|
||||
type_register_static(&fw_cfg_io_info);
|
||||
type_register_static(&fw_cfg_mem_info);
|
||||
}
|
||||
|
||||
type_init(fw_cfg_register_types)
|
||||
|
@ -454,7 +454,7 @@ static void ppc_core99_init(MachineState *machine)
|
||||
pmac_format_nvram_partition(nvr, 0x2000);
|
||||
/* No PCI init: the BIOS will do it */
|
||||
|
||||
fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2);
|
||||
fw_cfg = fw_cfg_init_mem(CFG_ADDR, CFG_ADDR + 2);
|
||||
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
|
||||
fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
|
||||
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
|
||||
|
@ -313,7 +313,7 @@ static void ppc_heathrow_init(MachineState *machine)
|
||||
|
||||
/* No PCI init: the BIOS will do it */
|
||||
|
||||
fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2);
|
||||
fw_cfg = fw_cfg_init_mem(CFG_ADDR, CFG_ADDR + 2);
|
||||
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
|
||||
fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
|
||||
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
|
||||
|
@ -1655,6 +1655,9 @@ static void spapr_machine_initfn(Object *obj)
|
||||
{
|
||||
object_property_add_str(obj, "kvm-type",
|
||||
spapr_get_kvm_type, spapr_set_kvm_type, NULL);
|
||||
object_property_set_description(obj, "kvm-type",
|
||||
"Specifies the KVM virtualization mode (HV, PR)",
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void ppc_cpu_do_nmi_on_cpu(void *arg)
|
||||
|
@ -1084,7 +1084,7 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef,
|
||||
ecc_init(hwdef->ecc_base, slavio_irq[28],
|
||||
hwdef->ecc_version);
|
||||
|
||||
fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2);
|
||||
fw_cfg = fw_cfg_init_mem(CFG_ADDR, CFG_ADDR + 2);
|
||||
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
|
||||
fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
|
||||
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
|
||||
|
@ -892,7 +892,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
|
||||
graphic_width, graphic_height, graphic_depth,
|
||||
(uint8_t *)&nd_table[0].macaddr);
|
||||
|
||||
fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0);
|
||||
fw_cfg = fw_cfg_init_io(BIOS_CFG_IOPORT);
|
||||
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
|
||||
fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
|
||||
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
|
||||
|
@ -37,6 +37,10 @@ struct arm_boot_info {
|
||||
hwaddr gic_cpu_if_addr;
|
||||
int nb_cpus;
|
||||
int board_id;
|
||||
/* ARM machines that support the ARM Security Extensions use this field to
|
||||
* control whether Linux is booted as secure(true) or non-secure(false).
|
||||
*/
|
||||
bool secure_boot;
|
||||
int (*atag_board)(const struct arm_boot_info *info, void *p);
|
||||
/* multicore boards that use the default secondary core boot functions
|
||||
* can ignore these two function calls. If the default functions won't
|
||||
@ -66,6 +70,11 @@ struct arm_boot_info {
|
||||
hwaddr initrd_start;
|
||||
hwaddr initrd_size;
|
||||
hwaddr entry;
|
||||
|
||||
/* Boot firmware has been loaded, typically at address 0, with -bios or
|
||||
* -pflash. It also implies that fw_cfg_find() will succeed.
|
||||
*/
|
||||
bool firmware_loaded;
|
||||
};
|
||||
void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info);
|
||||
|
||||
|
@ -16,6 +16,15 @@ int load_image(const char *filename, uint8_t *addr); /* deprecated */
|
||||
ssize_t load_image_size(const char *filename, void *addr, size_t size);
|
||||
int load_image_targphys(const char *filename, hwaddr,
|
||||
uint64_t max_sz);
|
||||
|
||||
/* This is the limit on the maximum uncompressed image size that
|
||||
* load_image_gzipped_buffer() and load_image_gzipped() will read. It prevents
|
||||
* g_malloc() in those functions from allocating a huge amount of memory.
|
||||
*/
|
||||
#define LOAD_IMAGE_MAX_GUNZIP_BYTES (256 << 20)
|
||||
|
||||
int load_image_gzipped_buffer(const char *filename, uint64_t max_sz,
|
||||
uint8_t **buffer);
|
||||
int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz);
|
||||
|
||||
#define ELF_LOAD_FAILED -1
|
||||
|
@ -78,8 +78,10 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
|
||||
void *data, size_t len);
|
||||
void *fw_cfg_modify_file(FWCfgState *s, const char *filename, void *data,
|
||||
size_t len);
|
||||
FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
|
||||
hwaddr crl_addr, hwaddr data_addr);
|
||||
FWCfgState *fw_cfg_init_io(uint32_t iobase);
|
||||
FWCfgState *fw_cfg_init_mem(hwaddr ctl_addr, hwaddr data_addr);
|
||||
FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr, hwaddr data_addr,
|
||||
uint32_t data_width);
|
||||
|
||||
FWCfgState *fw_cfg_find(void);
|
||||
|
||||
|
@ -22,6 +22,8 @@ typedef struct DisplayState DisplayState;
|
||||
typedef struct DisplaySurface DisplaySurface;
|
||||
typedef struct DriveInfo DriveInfo;
|
||||
typedef struct EventNotifier EventNotifier;
|
||||
typedef struct FWCfgIoState FWCfgIoState;
|
||||
typedef struct FWCfgMemState FWCfgMemState;
|
||||
typedef struct FWCfgState FWCfgState;
|
||||
typedef struct HCIInfo HCIInfo;
|
||||
typedef struct I2CBus I2CBus;
|
||||
|
@ -100,6 +100,8 @@ typedef struct ARMCPU {
|
||||
bool start_powered_off;
|
||||
/* CPU currently in PSCI powered-off state */
|
||||
bool powered_off;
|
||||
/* CPU has security extension */
|
||||
bool has_el3;
|
||||
|
||||
/* PSCI conduit used to invoke PSCI methods
|
||||
* 0 - disabled, 1 - smc, 2 - hvc
|
||||
|
@ -327,6 +327,11 @@ static inline void set_feature(CPUARMState *env, int feature)
|
||||
env->features |= 1ULL << feature;
|
||||
}
|
||||
|
||||
static inline void unset_feature(CPUARMState *env, int feature)
|
||||
{
|
||||
env->features &= ~(1ULL << feature);
|
||||
}
|
||||
|
||||
static void arm_cpu_initfn(Object *obj)
|
||||
{
|
||||
CPUState *cs = CPU(obj);
|
||||
@ -383,6 +388,9 @@ static Property arm_cpu_reset_hivecs_property =
|
||||
static Property arm_cpu_rvbar_property =
|
||||
DEFINE_PROP_UINT64("rvbar", ARMCPU, rvbar, 0);
|
||||
|
||||
static Property arm_cpu_has_el3_property =
|
||||
DEFINE_PROP_BOOL("has_el3", ARMCPU, has_el3, true);
|
||||
|
||||
static void arm_cpu_post_init(Object *obj)
|
||||
{
|
||||
ARMCPU *cpu = ARM_CPU(obj);
|
||||
@ -402,6 +410,14 @@ static void arm_cpu_post_init(Object *obj)
|
||||
qdev_property_add_static(DEVICE(obj), &arm_cpu_rvbar_property,
|
||||
&error_abort);
|
||||
}
|
||||
|
||||
if (arm_feature(&cpu->env, ARM_FEATURE_EL3)) {
|
||||
/* Add the has_el3 state CPU property only if EL3 is allowed. This will
|
||||
* prevent "has_el3" from existing on CPUs which cannot support EL3.
|
||||
*/
|
||||
qdev_property_add_static(DEVICE(obj), &arm_cpu_has_el3_property,
|
||||
&error_abort);
|
||||
}
|
||||
}
|
||||
|
||||
static void arm_cpu_finalizefn(Object *obj)
|
||||
@ -471,6 +487,18 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
|
||||
cpu->reset_sctlr |= (1 << 13);
|
||||
}
|
||||
|
||||
if (!cpu->has_el3) {
|
||||
/* If the has_el3 CPU property is disabled then we need to disable the
|
||||
* feature.
|
||||
*/
|
||||
unset_feature(env, ARM_FEATURE_EL3);
|
||||
|
||||
/* Disable the security extension feature bits in the processor feature
|
||||
* register as well. This is id_pfr1[7:4].
|
||||
*/
|
||||
cpu->id_pfr1 &= ~0xf0;
|
||||
}
|
||||
|
||||
register_cp_regs_for_features(cpu);
|
||||
arm_cpu_register_gdb_regs_for_features(cpu);
|
||||
|
||||
@ -640,6 +668,7 @@ static void arm1176_initfn(Object *obj)
|
||||
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
|
||||
set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG);
|
||||
set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS);
|
||||
set_feature(&cpu->env, ARM_FEATURE_EL3);
|
||||
cpu->midr = 0x410fb767;
|
||||
cpu->reset_fpsid = 0x410120b5;
|
||||
cpu->mvfr0 = 0x11111111;
|
||||
@ -728,6 +757,7 @@ static void cortex_a8_initfn(Object *obj)
|
||||
set_feature(&cpu->env, ARM_FEATURE_NEON);
|
||||
set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
|
||||
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
|
||||
set_feature(&cpu->env, ARM_FEATURE_EL3);
|
||||
cpu->midr = 0x410fc080;
|
||||
cpu->reset_fpsid = 0x410330c0;
|
||||
cpu->mvfr0 = 0x11110222;
|
||||
@ -795,6 +825,7 @@ static void cortex_a9_initfn(Object *obj)
|
||||
set_feature(&cpu->env, ARM_FEATURE_VFP_FP16);
|
||||
set_feature(&cpu->env, ARM_FEATURE_NEON);
|
||||
set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
|
||||
set_feature(&cpu->env, ARM_FEATURE_EL3);
|
||||
/* Note that A9 supports the MP extensions even for
|
||||
* A9UP and single-core A9MP (which are both different
|
||||
* and valid configurations; we don't model A9UP).
|
||||
@ -862,6 +893,7 @@ static void cortex_a15_initfn(Object *obj)
|
||||
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
|
||||
set_feature(&cpu->env, ARM_FEATURE_CBAR_RO);
|
||||
set_feature(&cpu->env, ARM_FEATURE_LPAE);
|
||||
set_feature(&cpu->env, ARM_FEATURE_EL3);
|
||||
cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A15;
|
||||
cpu->midr = 0x412fc0f1;
|
||||
cpu->reset_fpsid = 0x410430f0;
|
||||
|
@ -2413,7 +2413,30 @@ static const ARMCPRegInfo v8_el2_cp_reginfo[] = {
|
||||
REGINFO_SENTINEL
|
||||
};
|
||||
|
||||
static const ARMCPRegInfo v8_el3_cp_reginfo[] = {
|
||||
static const ARMCPRegInfo el3_cp_reginfo[] = {
|
||||
{ .name = "SCR_EL3", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 6, .crn = 1, .crm = 1, .opc2 = 0,
|
||||
.access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.scr_el3),
|
||||
.resetvalue = 0, .writefn = scr_write },
|
||||
{ .name = "SCR", .type = ARM_CP_NO_MIGRATE,
|
||||
.cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 0,
|
||||
.access = PL3_RW, .fieldoffset = offsetoflow32(CPUARMState, cp15.scr_el3),
|
||||
.resetfn = arm_cp_reset_ignore, .writefn = scr_write },
|
||||
{ .name = "SDER32_EL3", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 6, .crn = 1, .crm = 1, .opc2 = 1,
|
||||
.access = PL3_RW, .resetvalue = 0,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.sder) },
|
||||
{ .name = "SDER",
|
||||
.cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 1,
|
||||
.access = PL3_RW, .resetvalue = 0,
|
||||
.fieldoffset = offsetoflow32(CPUARMState, cp15.sder) },
|
||||
/* TODO: Implement NSACR trapping of secure EL1 accesses to EL3 */
|
||||
{ .name = "NSACR", .cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 2,
|
||||
.access = PL3_W | PL1_R, .resetvalue = 0,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.nsacr) },
|
||||
{ .name = "MVBAR", .cp = 15, .opc1 = 0, .crn = 12, .crm = 0, .opc2 = 1,
|
||||
.access = PL3_RW, .writefn = vbar_write, .resetvalue = 0,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.mvbar) },
|
||||
{ .name = "SCTLR_EL3", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 6, .crn = 1, .crm = 0, .opc2 = 0,
|
||||
.access = PL3_RW, .raw_writefn = raw_write, .writefn = sctlr_write,
|
||||
@ -2451,33 +2474,6 @@ static const ARMCPRegInfo v8_el3_cp_reginfo[] = {
|
||||
REGINFO_SENTINEL
|
||||
};
|
||||
|
||||
static const ARMCPRegInfo el3_cp_reginfo[] = {
|
||||
{ .name = "SCR_EL3", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 6, .crn = 1, .crm = 1, .opc2 = 0,
|
||||
.access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.scr_el3),
|
||||
.resetvalue = 0, .writefn = scr_write },
|
||||
{ .name = "SCR", .type = ARM_CP_NO_MIGRATE,
|
||||
.cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 0,
|
||||
.access = PL3_RW, .fieldoffset = offsetoflow32(CPUARMState, cp15.scr_el3),
|
||||
.resetfn = arm_cp_reset_ignore, .writefn = scr_write },
|
||||
{ .name = "SDER32_EL3", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 6, .crn = 1, .crm = 1, .opc2 = 1,
|
||||
.access = PL3_RW, .resetvalue = 0,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.sder) },
|
||||
{ .name = "SDER",
|
||||
.cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 1,
|
||||
.access = PL3_RW, .resetvalue = 0,
|
||||
.fieldoffset = offsetoflow32(CPUARMState, cp15.sder) },
|
||||
/* TODO: Implement NSACR trapping of secure EL1 accesses to EL3 */
|
||||
{ .name = "NSACR", .cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 2,
|
||||
.access = PL3_W | PL1_R, .resetvalue = 0,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.nsacr) },
|
||||
{ .name = "MVBAR", .cp = 15, .opc1 = 0, .crn = 12, .crm = 0, .opc2 = 1,
|
||||
.access = PL3_RW, .writefn = vbar_write, .resetvalue = 0,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.mvbar) },
|
||||
REGINFO_SENTINEL
|
||||
};
|
||||
|
||||
static CPAccessResult ctr_el0_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
/* Only accessible in EL0 if SCTLR.UCT is set (and only in AArch64,
|
||||
@ -3077,9 +3073,6 @@ void register_cp_regs_for_features(ARMCPU *cpu)
|
||||
}
|
||||
}
|
||||
if (arm_feature(env, ARM_FEATURE_EL3)) {
|
||||
if (arm_feature(env, ARM_FEATURE_V8)) {
|
||||
define_arm_cp_regs(cpu, v8_el3_cp_reginfo);
|
||||
}
|
||||
define_arm_cp_regs(cpu, el3_cp_reginfo);
|
||||
}
|
||||
if (arm_feature(env, ARM_FEATURE_MPU)) {
|
||||
|
117
vl.c
117
vl.c
@ -308,84 +308,12 @@ static QemuOptsList qemu_machine_opts = {
|
||||
.merge_lists = true,
|
||||
.head = QTAILQ_HEAD_INITIALIZER(qemu_machine_opts.head),
|
||||
.desc = {
|
||||
{
|
||||
.name = "type",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "emulated machine"
|
||||
}, {
|
||||
.name = "accel",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "accelerator list",
|
||||
}, {
|
||||
.name = "kernel_irqchip",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "use KVM in-kernel irqchip",
|
||||
}, {
|
||||
.name = "kvm_shadow_mem",
|
||||
.type = QEMU_OPT_SIZE,
|
||||
.help = "KVM shadow MMU size",
|
||||
}, {
|
||||
.name = "kernel",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "Linux kernel image file",
|
||||
}, {
|
||||
.name = "initrd",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "Linux initial ramdisk file",
|
||||
}, {
|
||||
.name = "append",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "Linux kernel command line",
|
||||
}, {
|
||||
.name = "dtb",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "Linux kernel device tree file",
|
||||
}, {
|
||||
.name = "dumpdtb",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "Dump current dtb to a file and quit",
|
||||
}, {
|
||||
.name = "phandle_start",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.help = "The first phandle ID we may generate dynamically",
|
||||
}, {
|
||||
.name = "dt_compatible",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "Overrides the \"compatible\" property of the dt root node",
|
||||
}, {
|
||||
.name = "dump-guest-core",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "Include guest memory in a core dump",
|
||||
}, {
|
||||
.name = "mem-merge",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "enable/disable memory merge support",
|
||||
},{
|
||||
.name = "usb",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "Set on/off to enable/disable usb",
|
||||
},{
|
||||
.name = "firmware",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "firmware image",
|
||||
},{
|
||||
.name = "kvm-type",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "Specifies the KVM virtualization mode (HV, PR)",
|
||||
},{
|
||||
.name = PC_MACHINE_MAX_RAM_BELOW_4G,
|
||||
.type = QEMU_OPT_SIZE,
|
||||
.help = "maximum ram below the 4G boundary (32bit boundary)",
|
||||
}, {
|
||||
.name = PC_MACHINE_VMPORT,
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "Enable vmport (pc & q35)",
|
||||
},{
|
||||
.name = "iommu",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "Set on/off to enable/disable Intel IOMMU (VT-d)",
|
||||
},
|
||||
{ /* End of list */ }
|
||||
/*
|
||||
* no elements => accept any
|
||||
* sanity checking will happen later
|
||||
* when setting machine properties
|
||||
*/
|
||||
{ }
|
||||
},
|
||||
};
|
||||
|
||||
@ -1495,6 +1423,31 @@ MachineInfoList *qmp_query_machines(Error **errp)
|
||||
return mach_list;
|
||||
}
|
||||
|
||||
static int machine_help_func(QemuOpts *opts, MachineState *machine)
|
||||
{
|
||||
ObjectProperty *prop;
|
||||
|
||||
if (!qemu_opt_has_help_opt(opts)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
QTAILQ_FOREACH(prop, &OBJECT(machine)->properties, node) {
|
||||
if (!prop->set) {
|
||||
continue;
|
||||
}
|
||||
|
||||
error_printf("%s.%s=%s", MACHINE_GET_CLASS(machine)->name,
|
||||
prop->name, prop->type);
|
||||
if (prop->description) {
|
||||
error_printf(" (%s)\n", prop->description);
|
||||
} else {
|
||||
error_printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/***********************************************************/
|
||||
/* main execution loop */
|
||||
|
||||
@ -2607,7 +2560,6 @@ static int machine_set_property(const char *name, const char *value,
|
||||
void *opaque)
|
||||
{
|
||||
Object *obj = OBJECT(opaque);
|
||||
StringInputVisitor *siv;
|
||||
Error *local_err = NULL;
|
||||
char *c, *qom_name;
|
||||
|
||||
@ -2623,9 +2575,7 @@ static int machine_set_property(const char *name, const char *value,
|
||||
}
|
||||
}
|
||||
|
||||
siv = string_input_visitor_new(value);
|
||||
object_property_set(obj, string_input_get_visitor(siv), qom_name, &local_err);
|
||||
string_input_visitor_cleanup(siv);
|
||||
object_property_parse(obj, value, qom_name, &local_err);
|
||||
g_free(qom_name);
|
||||
|
||||
if (local_err) {
|
||||
@ -3833,6 +3783,9 @@ int main(int argc, char **argv, char **envp)
|
||||
|
||||
current_machine = MACHINE(object_new(object_class_get_name(
|
||||
OBJECT_CLASS(machine_class))));
|
||||
if (machine_help_func(qemu_get_machine_opts(), current_machine)) {
|
||||
exit(0);
|
||||
}
|
||||
object_property_add_child(object_get_root(), "machine",
|
||||
OBJECT(current_machine), &error_abort);
|
||||
cpu_exec_init_all();
|
||||
|
Loading…
Reference in New Issue
Block a user