Compare commits
133 Commits
pull-seabi
...
pull-input
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a5d4d7b580 | ||
|
|
006a5edebe | ||
|
|
6f2b9a5b24 | ||
|
|
0c8ff723bd | ||
|
|
2a8327e8a8 | ||
|
|
8c52f0cbba | ||
|
|
0a3346f5de | ||
|
|
cb4e0f9ddf | ||
|
|
ad7020a7e7 | ||
|
|
033af8e9aa | ||
|
|
a87310a62d | ||
|
|
6fad9e986b | ||
|
|
72e3875485 | ||
|
|
a88bbb006a | ||
|
|
a6c3ed2474 | ||
|
|
7144612370 | ||
|
|
be67e9ab97 | ||
|
|
f44c475cb6 | ||
|
|
4e5d45ae57 | ||
|
|
f27183abaa | ||
|
|
9aaaa18194 | ||
|
|
8bac22423e | ||
|
|
53432dc9ea | ||
|
|
d87636b18f | ||
|
|
daeba9699d | ||
|
|
0210afe669 | ||
|
|
a3590dacce | ||
|
|
a8e3fbedc8 | ||
|
|
2e4450ff43 | ||
|
|
a31bdae5a7 | ||
|
|
bc2256c4ae | ||
|
|
f08f9271bf | ||
|
|
b9174d4f25 | ||
|
|
b1028b4e86 | ||
|
|
799810fb28 | ||
|
|
a59d31a1eb | ||
|
|
cfe67cef48 | ||
|
|
b58850e79d | ||
|
|
6396a193d3 | ||
|
|
2e5577bc55 | ||
|
|
d6a6b13ea1 | ||
|
|
f6bda88ff8 | ||
|
|
6cb0b013a1 | ||
|
|
3281af8114 | ||
|
|
b061a82b8a | ||
|
|
decf4f807b | ||
|
|
ba890a9b25 | ||
|
|
ffdb1409a7 | ||
|
|
89e9429c3c | ||
|
|
e4a511f8cc | ||
|
|
965eb2fcdf | ||
|
|
ae46e23964 | ||
|
|
fb1a3a051d | ||
|
|
397c767b2d | ||
|
|
693a3e01af | ||
|
|
270746142c | ||
|
|
1e7398a140 | ||
|
|
74de5504fd | ||
|
|
5ba03e2dd7 | ||
|
|
1717388645 | ||
|
|
5be7d9f1b1 | ||
|
|
4ee9b43be9 | ||
|
|
8524f1c79e | ||
|
|
473a49460d | ||
|
|
ff5397bc72 | ||
|
|
53f77e4562 | ||
|
|
6bc5cf92c0 | ||
|
|
1590d266d9 | ||
|
|
8ffe756da0 | ||
|
|
e1d4210c3a | ||
|
|
c5ecd7e18f | ||
|
|
ae0a7a1090 | ||
|
|
4f35680023 | ||
|
|
f9a1427361 | ||
|
|
75276710ae | ||
|
|
00e4b285a3 | ||
|
|
4d076d67c2 | ||
|
|
e565d934d2 | ||
|
|
a136608727 | ||
|
|
8608d25251 | ||
|
|
54414047ec | ||
|
|
12c7079449 | ||
|
|
836c3b01d2 | ||
|
|
0311c5bde3 | ||
|
|
1b58f5a7f6 | ||
|
|
e207527751 | ||
|
|
a3122b681a | ||
|
|
c80cd6bb9c | ||
|
|
04b7a1523d | ||
|
|
41d283bdab | ||
|
|
332f64073b | ||
|
|
06b008d941 | ||
|
|
bea2f0982b | ||
|
|
28452758c4 | ||
|
|
ebe7d8b166 | ||
|
|
d4862a87e3 | ||
|
|
9dacf32d2c | ||
|
|
66ae13bb9e | ||
|
|
c69403fcd4 | ||
|
|
5e031072e7 | ||
|
|
67633bb4f7 | ||
|
|
f754c3c9cc | ||
|
|
1f68f1d36c | ||
|
|
3da0ab3529 | ||
|
|
83bb161299 | ||
|
|
2f54394997 | ||
|
|
311918b979 | ||
|
|
8d302e7675 | ||
|
|
f0e0d817c2 | ||
|
|
2c2275eb41 | ||
|
|
777c98c32c | ||
|
|
d453d10383 | ||
|
|
a8f931a931 | ||
|
|
fb01bf4c6b | ||
|
|
6da528d14d | ||
|
|
fc89efe693 | ||
|
|
d7ce6b7a0b | ||
|
|
2e83c49626 | ||
|
|
ad8a4570ad | ||
|
|
2ecacb0b4b | ||
|
|
8df7eef305 | ||
|
|
cbed0ba78f | ||
|
|
cc0d079d45 | ||
|
|
7107e5a756 | ||
|
|
06e3c077da | ||
|
|
a499973ff3 | ||
|
|
d49f4ab48e | ||
|
|
ae52e585bf | ||
|
|
a09f4a9d19 | ||
|
|
8c29f8d6b9 | ||
|
|
f8d30a4f96 | ||
|
|
bf6667d63e | ||
|
|
6a084ea39a |
11
MAINTAINERS
11
MAINTAINERS
@@ -702,6 +702,7 @@ virtio
|
||||
M: Michael S. Tsirkin <mst@redhat.com>
|
||||
S: Supported
|
||||
F: hw/*/virtio*
|
||||
F: net/vhost-user.c
|
||||
|
||||
virtio-9p
|
||||
M: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
|
||||
@@ -727,6 +728,12 @@ S: Supported
|
||||
F: hw/s390x/virtio-ccw.[hc]
|
||||
T: git git://github.com/cohuck/qemu virtio-ccw-upstr
|
||||
|
||||
virtio-input
|
||||
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||
S: Maintained
|
||||
F: hw/input/virtio-input*.c
|
||||
F: include/hw/virtio/virtio-input.h
|
||||
|
||||
virtio-serial
|
||||
M: Amit Shah <amit.shah@redhat.com>
|
||||
S: Supported
|
||||
@@ -952,7 +959,10 @@ M: Markus Armbruster <armbru@redhat.com>
|
||||
M: Michael Roth <mdroth@linux.vnet.ibm.com>
|
||||
S: Supported
|
||||
F: qapi/
|
||||
X: qapi/*.json
|
||||
F: tests/qapi-schema/
|
||||
F: scripts/qapi*
|
||||
F: docs/qapi*
|
||||
T: git git://repo.or.cz/qemu/armbru.git qapi-next
|
||||
|
||||
QAPI Schema
|
||||
@@ -960,6 +970,7 @@ M: Eric Blake <eblake@redhat.com>
|
||||
M: Markus Armbruster <armbru@redhat.com>
|
||||
S: Supported
|
||||
F: qapi-schema.json
|
||||
F: qapi/*.json
|
||||
T: git git://repo.or.cz/qemu/armbru.git qapi-next
|
||||
|
||||
QObject
|
||||
|
||||
24
Makefile
24
Makefile
@@ -74,7 +74,7 @@ Makefile: ;
|
||||
configure: ;
|
||||
|
||||
.PHONY: all clean cscope distclean dvi html info install install-doc \
|
||||
pdf recurse-all speed test dist
|
||||
pdf recurse-all speed test dist msi
|
||||
|
||||
$(call set-vpath, $(SRC_PATH))
|
||||
|
||||
@@ -287,10 +287,32 @@ $(qga-obj-y) qemu-ga.o: $(QGALIB_GEN)
|
||||
qemu-ga$(EXESUF): $(qga-obj-y) libqemuutil.a libqemustub.a
|
||||
$(call LINK, $^)
|
||||
|
||||
ifdef QEMU_GA_MSI_ENABLED
|
||||
QEMU_GA_MSI=qemu-ga-$(ARCH).msi
|
||||
|
||||
msi: ${QEMU_GA_MSI}
|
||||
|
||||
$(QEMU_GA_MSI): qemu-ga.exe
|
||||
|
||||
ifdef QEMU_GA_MSI_WITH_VSS
|
||||
$(QEMU_GA_MSI): qga/vss-win32/qga-vss.dll
|
||||
endif
|
||||
|
||||
$(QEMU_GA_MSI): config-host.mak
|
||||
|
||||
$(QEMU_GA_MSI): qga/installer/qemu-ga.wxs
|
||||
$(call quiet-command,QEMU_GA_VERSION="$(QEMU_GA_VERSION)" QEMU_GA_MANUFACTURER="$(QEMU_GA_MANUFACTURER)" QEMU_GA_DISTRO="$(QEMU_GA_DISTRO)" \
|
||||
wixl -o $@ $(QEMU_GA_MSI_ARCH) $(QEMU_GA_MSI_WITH_VSS) $(QEMU_GA_MSI_MINGW_DLL_PATH) $<, " WIXL $@")
|
||||
else
|
||||
msi:
|
||||
@echo MSI build not configured or dependency resolution failed (reconfigure with --enable-guest-agent-msi option)
|
||||
endif
|
||||
|
||||
clean:
|
||||
# avoid old build problems by removing potentially incorrect old files
|
||||
rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
|
||||
rm -f qemu-options.def
|
||||
rm -f *.msi
|
||||
find . \( -name '*.l[oa]' -o -name '*.so' -o -name '*.dll' -o -name '*.mo' -o -name '*.[oda]' \) -type f -exec rm {} +
|
||||
rm -f $(filter-out %.tlb,$(TOOLS)) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~
|
||||
rm -f fsdev/*.pod
|
||||
|
||||
@@ -113,24 +113,17 @@ host_memory_backend_set_host_nodes(Object *obj, Visitor *v, void *opaque,
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
host_memory_backend_get_policy(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
static int
|
||||
host_memory_backend_get_policy(Object *obj, Error **errp G_GNUC_UNUSED)
|
||||
{
|
||||
HostMemoryBackend *backend = MEMORY_BACKEND(obj);
|
||||
int policy = backend->policy;
|
||||
|
||||
visit_type_enum(v, &policy, HostMemPolicy_lookup, NULL, name, errp);
|
||||
return backend->policy;
|
||||
}
|
||||
|
||||
static void
|
||||
host_memory_backend_set_policy(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
host_memory_backend_set_policy(Object *obj, int policy, Error **errp)
|
||||
{
|
||||
HostMemoryBackend *backend = MEMORY_BACKEND(obj);
|
||||
int policy;
|
||||
|
||||
visit_type_enum(v, &policy, HostMemPolicy_lookup, NULL, name, errp);
|
||||
backend->policy = policy;
|
||||
|
||||
#ifndef CONFIG_NUMA
|
||||
@@ -252,9 +245,10 @@ static void host_memory_backend_init(Object *obj)
|
||||
object_property_add(obj, "host-nodes", "int",
|
||||
host_memory_backend_get_host_nodes,
|
||||
host_memory_backend_set_host_nodes, NULL, NULL, NULL);
|
||||
object_property_add(obj, "policy", "str",
|
||||
host_memory_backend_get_policy,
|
||||
host_memory_backend_set_policy, NULL, NULL, NULL);
|
||||
object_property_add_enum(obj, "policy", "HostMemPolicy",
|
||||
HostMemPolicy_lookup,
|
||||
host_memory_backend_get_policy,
|
||||
host_memory_backend_set_policy, NULL);
|
||||
}
|
||||
|
||||
MemoryRegion *
|
||||
|
||||
@@ -942,7 +942,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
|
||||
devopts = qemu_opts_create(qemu_find_opts("device"), NULL, 0,
|
||||
&error_abort);
|
||||
if (arch_type == QEMU_ARCH_S390X) {
|
||||
qemu_opt_set(devopts, "driver", "virtio-blk-s390", &error_abort);
|
||||
qemu_opt_set(devopts, "driver", "virtio-blk-ccw", &error_abort);
|
||||
} else {
|
||||
qemu_opt_set(devopts, "driver", "virtio-blk-pci", &error_abort);
|
||||
}
|
||||
|
||||
66
configure
vendored
66
configure
vendored
@@ -315,6 +315,7 @@ snappy=""
|
||||
bzip2=""
|
||||
guest_agent=""
|
||||
guest_agent_with_vss="no"
|
||||
guest_agent_msi=""
|
||||
vss_win32_sdk=""
|
||||
win_sdk="no"
|
||||
want_tools="yes"
|
||||
@@ -1078,6 +1079,10 @@ for opt do
|
||||
;;
|
||||
--disable-guest-agent) guest_agent="no"
|
||||
;;
|
||||
--enable-guest-agent-msi) guest_agent_msi="yes"
|
||||
;;
|
||||
--disable-guest-agent-msi) guest_agent_msi="no"
|
||||
;;
|
||||
--with-vss-sdk) vss_win32_sdk=""
|
||||
;;
|
||||
--with-vss-sdk=*) vss_win32_sdk="$optarg"
|
||||
@@ -1394,6 +1399,8 @@ Advanced options (experts only):
|
||||
reading bzip2-compressed dmg images)
|
||||
--disable-guest-agent disable building of the QEMU Guest Agent
|
||||
--enable-guest-agent enable building of the QEMU Guest Agent
|
||||
--enable-guest-agent-msi enable building guest agent Windows MSI installation package
|
||||
--disable-guest-agent-msi disable building guest agent Windows MSI installation
|
||||
--with-vss-sdk=SDK-path enable Windows VSS support in QEMU Guest Agent
|
||||
--with-win-sdk=SDK-path path to Windows Platform SDK (to build VSS .tlb)
|
||||
--disable-seccomp disable seccomp support
|
||||
@@ -3862,6 +3869,56 @@ if test "$mingw32" = "yes" -a "$guest_agent" != "no" -a "$guest_agent_with_vss"
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# Guest agent Window MSI package
|
||||
|
||||
if test "$guest_agent" != yes; then
|
||||
if test "$guest_agent_msi" = yes; then
|
||||
error_exit "MSI guest agent package requires guest agent enabled"
|
||||
fi
|
||||
guest_agent_msi=no
|
||||
elif test "$mingw32" != "yes"; then
|
||||
if test "$guest_agent_msi" = "yes"; then
|
||||
error_exit "MSI guest agent package is available only for MinGW Windows cross-compilation"
|
||||
fi
|
||||
guest_agent_msi=no
|
||||
elif ! has wixl; then
|
||||
if test "$guest_agent_msi" = "yes"; then
|
||||
error_exit "MSI guest agent package requires wixl tool installed ( usually from msitools package )"
|
||||
fi
|
||||
guest_agent_msi=no
|
||||
fi
|
||||
|
||||
if test "$guest_agent_msi" != "no"; then
|
||||
if test "$guest_agent_with_vss" = "yes"; then
|
||||
QEMU_GA_MSI_WITH_VSS="-D InstallVss"
|
||||
fi
|
||||
|
||||
if test "$QEMU_GA_MANUFACTURER" = ""; then
|
||||
QEMU_GA_MANUFACTURER=QEMU
|
||||
fi
|
||||
|
||||
if test "$QEMU_GA_DISTRO" = ""; then
|
||||
QEMU_GA_DISTRO=Linux
|
||||
fi
|
||||
|
||||
if test "$QEMU_GA_VERSION" = ""; then
|
||||
QEMU_GA_VERSION=`cat $source_path/VERSION`
|
||||
fi
|
||||
|
||||
QEMU_GA_MSI_MINGW_DLL_PATH="-D Mingw_dlls=`$pkg_config --variable=prefix glib-2.0`/bin"
|
||||
|
||||
case "$cpu" in
|
||||
x86_64)
|
||||
QEMU_GA_MSI_ARCH="-a x64 -D Arch=64"
|
||||
;;
|
||||
i386)
|
||||
QEMU_GA_MSI_ARCH="-D Arch=32"
|
||||
;;
|
||||
*)
|
||||
error_exit "CPU $cpu not supported for building installation package"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# check if we have fdatasync
|
||||
@@ -4558,6 +4615,15 @@ if test "$mingw32" = "yes" ; then
|
||||
echo "CONFIG_QGA_VSS=y" >> $config_host_mak
|
||||
echo "WIN_SDK=\"$win_sdk\"" >> $config_host_mak
|
||||
fi
|
||||
if test "$guest_agent_msi" != "no"; then
|
||||
echo "QEMU_GA_MSI_ENABLED=yes" >> $config_host_mak
|
||||
echo "QEMU_GA_MSI_MINGW_DLL_PATH=${QEMU_GA_MSI_MINGW_DLL_PATH}" >> $config_host_mak
|
||||
echo "QEMU_GA_MSI_WITH_VSS=${QEMU_GA_MSI_WITH_VSS}" >> $config_host_mak
|
||||
echo "QEMU_GA_MSI_ARCH=${QEMU_GA_MSI_ARCH}" >> $config_host_mak
|
||||
echo "QEMU_GA_MANUFACTURER=${QEMU_GA_MANUFACTURER}" >> $config_host_mak
|
||||
echo "QEMU_GA_DISTRO=${QEMU_GA_DISTRO}" >> $config_host_mak
|
||||
echo "QEMU_GA_VERSION=${QEMU_GA_VERSION}" >> $config_host_mak
|
||||
fi
|
||||
else
|
||||
echo "CONFIG_POSIX=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
@@ -680,8 +680,6 @@ Example:
|
||||
out:
|
||||
error_propagate(errp, err);
|
||||
}
|
||||
$ python scripts/qapi-commands.py --output-dir="qapi-generated" \
|
||||
--prefix="example-" example-schema.json
|
||||
$ cat qapi-generated/example-qapi-visit.h
|
||||
[Uninteresting stuff omitted...]
|
||||
|
||||
|
||||
8
exec.c
8
exec.c
@@ -341,6 +341,7 @@ address_space_translate_internal(AddressSpaceDispatch *d, hwaddr addr, hwaddr *x
|
||||
hwaddr *plen, bool resolve_subpage)
|
||||
{
|
||||
MemoryRegionSection *section;
|
||||
MemoryRegion *mr;
|
||||
Int128 diff;
|
||||
|
||||
section = address_space_lookup_region(d, addr, resolve_subpage);
|
||||
@@ -350,8 +351,11 @@ address_space_translate_internal(AddressSpaceDispatch *d, hwaddr addr, hwaddr *x
|
||||
/* Compute offset within MemoryRegion */
|
||||
*xlat = addr + section->offset_within_region;
|
||||
|
||||
diff = int128_sub(section->mr->size, int128_make64(addr));
|
||||
*plen = int128_get64(int128_min(diff, int128_make64(*plen)));
|
||||
mr = section->mr;
|
||||
if (memory_region_is_ram(mr)) {
|
||||
diff = int128_sub(section->size, int128_make64(addr));
|
||||
*plen = int128_get64(int128_min(diff, int128_make64(*plen)));
|
||||
}
|
||||
return section;
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ static struct option helper_opts[] = {
|
||||
{"socket", required_argument, NULL, 's'},
|
||||
{"uid", required_argument, NULL, 'u'},
|
||||
{"gid", required_argument, NULL, 'g'},
|
||||
{},
|
||||
};
|
||||
|
||||
static bool is_daemon;
|
||||
@@ -738,7 +739,12 @@ static int proxy_socket(const char *path, uid_t uid, gid_t gid)
|
||||
return -1;
|
||||
}
|
||||
|
||||
g_assert(strlen(path) < sizeof(proxy.sun_path));
|
||||
if (strlen(path) >= sizeof(proxy.sun_path)) {
|
||||
do_log(LOG_CRIT, "UNIX domain socket path exceeds %zu characters\n",
|
||||
sizeof(proxy.sun_path));
|
||||
return -1;
|
||||
}
|
||||
|
||||
sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (sock < 0) {
|
||||
do_perror("socket");
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "cpu.h"
|
||||
#include "qemu/sockets.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "exec/semihost.h"
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
#define GDB_ATTACHED "0"
|
||||
@@ -323,8 +324,6 @@ static GDBState *gdbserver_state;
|
||||
|
||||
bool gdb_has_xml;
|
||||
|
||||
int semihosting_target = SEMIHOSTING_TARGET_AUTO;
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
/* XXX: This is not thread safe. Do we care? */
|
||||
static int gdbserver_fd = -1;
|
||||
@@ -362,10 +361,11 @@ static enum {
|
||||
/* Decide if either remote gdb syscalls or native file IO should be used. */
|
||||
int use_gdb_syscalls(void)
|
||||
{
|
||||
if (semihosting_target == SEMIHOSTING_TARGET_NATIVE) {
|
||||
SemihostingTarget target = semihosting_get_target();
|
||||
if (target == SEMIHOSTING_TARGET_NATIVE) {
|
||||
/* -semihosting-config target=native */
|
||||
return false;
|
||||
} else if (semihosting_target == SEMIHOSTING_TARGET_GDB) {
|
||||
} else if (target == SEMIHOSTING_TARGET_GDB) {
|
||||
/* -semihosting-config target=gdb */
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,9 @@
|
||||
#include "sysemu/device_tree.h"
|
||||
#include "hw/platform-bus.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/vfio/vfio-platform.h"
|
||||
#include "hw/vfio/vfio-calxeda-xgmac.h"
|
||||
#include "hw/arm/fdt.h"
|
||||
|
||||
/*
|
||||
* internal struct that contains the information to create dynamic
|
||||
@@ -53,11 +56,81 @@ typedef struct NodeCreationPair {
|
||||
int (*add_fdt_node_fn)(SysBusDevice *sbdev, void *opaque);
|
||||
} NodeCreationPair;
|
||||
|
||||
/* Device Specific Code */
|
||||
|
||||
/**
|
||||
* add_calxeda_midway_xgmac_fdt_node
|
||||
*
|
||||
* Generates a simple node with following properties:
|
||||
* compatible string, regs, interrupts, dma-coherent
|
||||
*/
|
||||
static int add_calxeda_midway_xgmac_fdt_node(SysBusDevice *sbdev, void *opaque)
|
||||
{
|
||||
PlatformBusFDTData *data = opaque;
|
||||
PlatformBusDevice *pbus = data->pbus;
|
||||
void *fdt = data->fdt;
|
||||
const char *parent_node = data->pbus_node_name;
|
||||
int compat_str_len, i, ret = -1;
|
||||
char *nodename;
|
||||
uint32_t *irq_attr, *reg_attr;
|
||||
uint64_t mmio_base, irq_number;
|
||||
VFIOPlatformDevice *vdev = VFIO_PLATFORM_DEVICE(sbdev);
|
||||
VFIODevice *vbasedev = &vdev->vbasedev;
|
||||
|
||||
mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, 0);
|
||||
nodename = g_strdup_printf("%s/%s@%" PRIx64, parent_node,
|
||||
vbasedev->name, mmio_base);
|
||||
qemu_fdt_add_subnode(fdt, nodename);
|
||||
|
||||
compat_str_len = strlen(vdev->compat) + 1;
|
||||
qemu_fdt_setprop(fdt, nodename, "compatible",
|
||||
vdev->compat, compat_str_len);
|
||||
|
||||
qemu_fdt_setprop(fdt, nodename, "dma-coherent", "", 0);
|
||||
|
||||
reg_attr = g_new(uint32_t, vbasedev->num_regions * 2);
|
||||
for (i = 0; i < vbasedev->num_regions; i++) {
|
||||
mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, i);
|
||||
reg_attr[2 * i] = cpu_to_be32(mmio_base);
|
||||
reg_attr[2 * i + 1] = cpu_to_be32(
|
||||
memory_region_size(&vdev->regions[i]->mem));
|
||||
}
|
||||
ret = qemu_fdt_setprop(fdt, nodename, "reg", reg_attr,
|
||||
vbasedev->num_regions * 2 * sizeof(uint32_t));
|
||||
if (ret) {
|
||||
error_report("could not set reg property of node %s", nodename);
|
||||
goto fail_reg;
|
||||
}
|
||||
|
||||
irq_attr = g_new(uint32_t, vbasedev->num_irqs * 3);
|
||||
for (i = 0; i < vbasedev->num_irqs; i++) {
|
||||
irq_number = platform_bus_get_irqn(pbus, sbdev , i)
|
||||
+ data->irq_start;
|
||||
irq_attr[3 * i] = cpu_to_be32(GIC_FDT_IRQ_TYPE_SPI);
|
||||
irq_attr[3 * i + 1] = cpu_to_be32(irq_number);
|
||||
irq_attr[3 * i + 2] = cpu_to_be32(GIC_FDT_IRQ_FLAGS_LEVEL_HI);
|
||||
}
|
||||
ret = qemu_fdt_setprop(fdt, nodename, "interrupts",
|
||||
irq_attr, vbasedev->num_irqs * 3 * sizeof(uint32_t));
|
||||
if (ret) {
|
||||
error_report("could not set interrupts property of node %s",
|
||||
nodename);
|
||||
}
|
||||
g_free(irq_attr);
|
||||
fail_reg:
|
||||
g_free(reg_attr);
|
||||
g_free(nodename);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* list of supported dynamic sysbus devices */
|
||||
static const NodeCreationPair add_fdt_node_functions[] = {
|
||||
{TYPE_VFIO_CALXEDA_XGMAC, add_calxeda_midway_xgmac_fdt_node},
|
||||
{"", NULL}, /* last element */
|
||||
};
|
||||
|
||||
/* Generic Code */
|
||||
|
||||
/**
|
||||
* add_fdt_node - add the device tree node of a dynamic sysbus device
|
||||
*
|
||||
|
||||
@@ -47,21 +47,11 @@
|
||||
#include "hw/arm/virt-acpi-build.h"
|
||||
#include "hw/arm/sysbus-fdt.h"
|
||||
#include "hw/platform-bus.h"
|
||||
#include "hw/arm/fdt.h"
|
||||
|
||||
/* Number of external interrupt lines to configure the GIC with */
|
||||
#define NUM_IRQS 256
|
||||
|
||||
#define GIC_FDT_IRQ_TYPE_SPI 0
|
||||
#define GIC_FDT_IRQ_TYPE_PPI 1
|
||||
|
||||
#define GIC_FDT_IRQ_FLAGS_EDGE_LO_HI 1
|
||||
#define GIC_FDT_IRQ_FLAGS_EDGE_HI_LO 2
|
||||
#define GIC_FDT_IRQ_FLAGS_LEVEL_HI 4
|
||||
#define GIC_FDT_IRQ_FLAGS_LEVEL_LO 8
|
||||
|
||||
#define GIC_FDT_IRQ_PPI_CPU_START 8
|
||||
#define GIC_FDT_IRQ_PPI_CPU_WIDTH 8
|
||||
|
||||
#define PLATFORM_BUS_NUM_IRQS 64
|
||||
|
||||
static ARMPlatformBusSystemParams platform_bus_params;
|
||||
|
||||
@@ -65,7 +65,7 @@ static void xlnx_ep108_init(MachineState *machine)
|
||||
xlnx_ep108_binfo.kernel_cmdline = machine->kernel_cmdline;
|
||||
xlnx_ep108_binfo.initrd_filename = machine->initrd_filename;
|
||||
xlnx_ep108_binfo.loader_start = 0;
|
||||
arm_load_kernel(&s->soc.cpu[0], &xlnx_ep108_binfo);
|
||||
arm_load_kernel(s->soc.boot_cpu_ptr, &xlnx_ep108_binfo);
|
||||
}
|
||||
|
||||
static QEMUMachine xlnx_ep108_machine = {
|
||||
|
||||
@@ -64,10 +64,17 @@ static void xlnx_zynqmp_init(Object *obj)
|
||||
XlnxZynqMPState *s = XLNX_ZYNQMP(obj);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < XLNX_ZYNQMP_NUM_CPUS; i++) {
|
||||
object_initialize(&s->cpu[i], sizeof(s->cpu[i]),
|
||||
for (i = 0; i < XLNX_ZYNQMP_NUM_APU_CPUS; i++) {
|
||||
object_initialize(&s->apu_cpu[i], sizeof(s->apu_cpu[i]),
|
||||
"cortex-a53-" TYPE_ARM_CPU);
|
||||
object_property_add_child(obj, "cpu[*]", OBJECT(&s->cpu[i]),
|
||||
object_property_add_child(obj, "apu-cpu[*]", OBJECT(&s->apu_cpu[i]),
|
||||
&error_abort);
|
||||
}
|
||||
|
||||
for (i = 0; i < XLNX_ZYNQMP_NUM_RPU_CPUS; i++) {
|
||||
object_initialize(&s->rpu_cpu[i], sizeof(s->rpu_cpu[i]),
|
||||
"cortex-r5-" TYPE_ARM_CPU);
|
||||
object_property_add_child(obj, "rpu-cpu[*]", OBJECT(&s->rpu_cpu[i]),
|
||||
&error_abort);
|
||||
}
|
||||
|
||||
@@ -90,12 +97,13 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
|
||||
XlnxZynqMPState *s = XLNX_ZYNQMP(dev);
|
||||
MemoryRegion *system_memory = get_system_memory();
|
||||
uint8_t i;
|
||||
const char *boot_cpu = s->boot_cpu ? s->boot_cpu : "apu-cpu[0]";
|
||||
qemu_irq gic_spi[GIC_NUM_SPI_INTR];
|
||||
Error *err = NULL;
|
||||
|
||||
qdev_prop_set_uint32(DEVICE(&s->gic), "num-irq", GIC_NUM_SPI_INTR + 32);
|
||||
qdev_prop_set_uint32(DEVICE(&s->gic), "revision", 2);
|
||||
qdev_prop_set_uint32(DEVICE(&s->gic), "num-cpu", XLNX_ZYNQMP_NUM_CPUS);
|
||||
qdev_prop_set_uint32(DEVICE(&s->gic), "num-cpu", XLNX_ZYNQMP_NUM_APU_CPUS);
|
||||
object_property_set_bool(OBJECT(&s->gic), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate((errp), (err));
|
||||
@@ -121,38 +129,77 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < XLNX_ZYNQMP_NUM_CPUS; i++) {
|
||||
for (i = 0; i < XLNX_ZYNQMP_NUM_APU_CPUS; i++) {
|
||||
qemu_irq irq;
|
||||
char *name;
|
||||
|
||||
object_property_set_int(OBJECT(&s->cpu[i]), QEMU_PSCI_CONDUIT_SMC,
|
||||
object_property_set_int(OBJECT(&s->apu_cpu[i]), QEMU_PSCI_CONDUIT_SMC,
|
||||
"psci-conduit", &error_abort);
|
||||
if (i > 0) {
|
||||
|
||||
name = object_get_canonical_path_component(OBJECT(&s->apu_cpu[i]));
|
||||
if (strcmp(name, boot_cpu)) {
|
||||
/* Secondary CPUs start in PSCI powered-down state */
|
||||
object_property_set_bool(OBJECT(&s->cpu[i]), true,
|
||||
object_property_set_bool(OBJECT(&s->apu_cpu[i]), true,
|
||||
"start-powered-off", &error_abort);
|
||||
} else {
|
||||
s->boot_cpu_ptr = &s->apu_cpu[i];
|
||||
}
|
||||
|
||||
object_property_set_int(OBJECT(&s->cpu[i]), GIC_BASE_ADDR,
|
||||
object_property_set_int(OBJECT(&s->apu_cpu[i]), GIC_BASE_ADDR,
|
||||
"reset-cbar", &err);
|
||||
if (err) {
|
||||
error_propagate((errp), (err));
|
||||
return;
|
||||
}
|
||||
|
||||
object_property_set_bool(OBJECT(&s->cpu[i]), true, "realized", &err);
|
||||
object_property_set_bool(OBJECT(&s->apu_cpu[i]), true, "realized",
|
||||
&err);
|
||||
if (err) {
|
||||
error_propagate((errp), (err));
|
||||
return;
|
||||
}
|
||||
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), i,
|
||||
qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_IRQ));
|
||||
qdev_get_gpio_in(DEVICE(&s->apu_cpu[i]),
|
||||
ARM_CPU_IRQ));
|
||||
irq = qdev_get_gpio_in(DEVICE(&s->gic),
|
||||
arm_gic_ppi_index(i, ARM_PHYS_TIMER_PPI));
|
||||
qdev_connect_gpio_out(DEVICE(&s->cpu[i]), 0, irq);
|
||||
qdev_connect_gpio_out(DEVICE(&s->apu_cpu[i]), 0, irq);
|
||||
irq = qdev_get_gpio_in(DEVICE(&s->gic),
|
||||
arm_gic_ppi_index(i, ARM_VIRT_TIMER_PPI));
|
||||
qdev_connect_gpio_out(DEVICE(&s->cpu[i]), 1, irq);
|
||||
qdev_connect_gpio_out(DEVICE(&s->apu_cpu[i]), 1, irq);
|
||||
}
|
||||
|
||||
for (i = 0; i < XLNX_ZYNQMP_NUM_RPU_CPUS; i++) {
|
||||
char *name;
|
||||
|
||||
name = object_get_canonical_path_component(OBJECT(&s->rpu_cpu[i]));
|
||||
if (strcmp(name, boot_cpu)) {
|
||||
/* Secondary CPUs start in PSCI powered-down state */
|
||||
object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true,
|
||||
"start-powered-off", &error_abort);
|
||||
} else {
|
||||
s->boot_cpu_ptr = &s->rpu_cpu[i];
|
||||
}
|
||||
|
||||
object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, "reset-hivecs",
|
||||
&err);
|
||||
if (err != NULL) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, "realized",
|
||||
&err);
|
||||
if (err) {
|
||||
error_propagate((errp), (err));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!s->boot_cpu_ptr) {
|
||||
error_setg(errp, "ZynqMP Boot cpu %s not found\n", boot_cpu);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < GIC_NUM_SPI_INTR; i++) {
|
||||
@@ -188,10 +235,16 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
static Property xlnx_zynqmp_props[] = {
|
||||
DEFINE_PROP_STRING("boot-cpu", XlnxZynqMPState, boot_cpu),
|
||||
DEFINE_PROP_END_OF_LIST()
|
||||
};
|
||||
|
||||
static void xlnx_zynqmp_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
dc->props = xlnx_zynqmp_props;
|
||||
dc->realize = xlnx_zynqmp_realize;
|
||||
}
|
||||
|
||||
|
||||
@@ -126,9 +126,9 @@ void qbus_set_bus_hotplug_handler(BusState *bus, Error **errp)
|
||||
qbus_set_hotplug_handler_internal(bus, OBJECT(bus), errp);
|
||||
}
|
||||
|
||||
/* Create a new device. This only initializes the device state structure
|
||||
and allows properties to be set. qdev_init should be called to
|
||||
initialize the actual device emulation. */
|
||||
/* Create a new device. This only initializes the device state
|
||||
structure and allows properties to be set. The device still needs
|
||||
to be realized. See qdev-core.h. */
|
||||
DeviceState *qdev_create(BusState *bus, const char *name)
|
||||
{
|
||||
DeviceState *dev;
|
||||
@@ -168,27 +168,6 @@ DeviceState *qdev_try_create(BusState *bus, const char *type)
|
||||
return dev;
|
||||
}
|
||||
|
||||
/* Initialize a device. Device properties should be set before calling
|
||||
this function. IRQs and MMIO regions should be connected/mapped after
|
||||
calling this function.
|
||||
On failure, destroy the device and return negative value.
|
||||
Return 0 on success. */
|
||||
int qdev_init(DeviceState *dev)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
|
||||
assert(!dev->realized);
|
||||
|
||||
object_property_set_bool(OBJECT(dev), true, "realized", &local_err);
|
||||
if (local_err != NULL) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
object_unparent(OBJECT(dev));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static QTAILQ_HEAD(device_listeners, DeviceListener) device_listeners
|
||||
= QTAILQ_HEAD_INITIALIZER(device_listeners);
|
||||
|
||||
@@ -364,13 +343,19 @@ void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev,
|
||||
object_unparent(OBJECT(dev));
|
||||
}
|
||||
|
||||
/* Like qdev_init(), but terminate program via error_report() instead of
|
||||
returning an error value. This is okay during machine creation.
|
||||
Don't use for hotplug, because there callers need to recover from
|
||||
failure. Exception: if you know the device's init() callback can't
|
||||
fail, then qdev_init_nofail() can't fail either, and is therefore
|
||||
usable even then. But relying on the device implementation that
|
||||
way is somewhat unclean, and best avoided. */
|
||||
/*
|
||||
* Realize @dev.
|
||||
* Device properties should be set before calling this function. IRQs
|
||||
* and MMIO regions should be connected/mapped after calling this
|
||||
* function.
|
||||
* On failure, report an error with error_report() and terminate the
|
||||
* program. This is okay during machine creation. Don't use for
|
||||
* hotplug, because there callers need to recover from failure.
|
||||
* Exception: if you know the device's init() callback can't fail,
|
||||
* then qdev_init_nofail() can't fail either, and is therefore usable
|
||||
* even then. But relying on the device implementation that way is
|
||||
* somewhat unclean, and best avoided.
|
||||
*/
|
||||
void qdev_init_nofail(DeviceState *dev)
|
||||
{
|
||||
Error *err = NULL;
|
||||
@@ -563,6 +548,7 @@ void qdev_pass_gpios(DeviceState *dev, DeviceState *container,
|
||||
object_property_add_alias(OBJECT(container), propname,
|
||||
OBJECT(dev), propname,
|
||||
&error_abort);
|
||||
g_free(propname);
|
||||
}
|
||||
for (i = 0; i < ngl->num_out; i++) {
|
||||
const char *nm = ngl->name ? ngl->name : "unnamed-gpio-out";
|
||||
@@ -571,6 +557,7 @@ void qdev_pass_gpios(DeviceState *dev, DeviceState *container,
|
||||
object_property_add_alias(OBJECT(container), propname,
|
||||
OBJECT(dev), propname,
|
||||
&error_abort);
|
||||
g_free(propname);
|
||||
}
|
||||
QLIST_REMOVE(ngl, node);
|
||||
QLIST_INSERT_HEAD(&container->gpios, ngl, node);
|
||||
|
||||
@@ -281,19 +281,15 @@ static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent)
|
||||
static char *sysbus_get_fw_dev_path(DeviceState *dev)
|
||||
{
|
||||
SysBusDevice *s = SYS_BUS_DEVICE(dev);
|
||||
char path[40];
|
||||
int off;
|
||||
|
||||
off = snprintf(path, sizeof(path), "%s", qdev_fw_name(dev));
|
||||
|
||||
if (s->num_mmio) {
|
||||
snprintf(path + off, sizeof(path) - off, "@"TARGET_FMT_plx,
|
||||
s->mmio[0].addr);
|
||||
} else if (s->num_pio) {
|
||||
snprintf(path + off, sizeof(path) - off, "@i%04x", s->pio[0]);
|
||||
return g_strdup_printf("%s@" TARGET_FMT_plx, qdev_fw_name(dev),
|
||||
s->mmio[0].addr);
|
||||
}
|
||||
|
||||
return g_strdup(path);
|
||||
if (s->num_pio) {
|
||||
return g_strdup_printf("%s@i%04x", qdev_fw_name(dev), s->pio[0]);
|
||||
}
|
||||
return g_strdup(qdev_fw_name(dev));
|
||||
}
|
||||
|
||||
void sysbus_add_io(SysBusDevice *dev, hwaddr addr,
|
||||
|
||||
@@ -403,6 +403,7 @@ DEFINE_Q35_MACHINE(v2_4, "pc-q35-2.4", NULL,
|
||||
static void pc_q35_2_3_machine_options(MachineClass *m)
|
||||
{
|
||||
pc_q35_2_4_machine_options(m);
|
||||
m->no_floppy = 0;
|
||||
m->alias = NULL;
|
||||
SET_MACHINE_COMPAT(m, PC_COMPAT_2_3);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ common-obj-$(CONFIG_VMMOUSE) += vmmouse.o
|
||||
ifeq ($(CONFIG_LINUX),y)
|
||||
common-obj-$(CONFIG_VIRTIO) += virtio-input.o
|
||||
common-obj-$(CONFIG_VIRTIO) += virtio-input-hid.o
|
||||
common-obj-$(CONFIG_VIRTIO) += virtio-input-host.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_MILKYMIST) += milkymist-softusb.o
|
||||
|
||||
188
hw/input/virtio-input-host.c
Normal file
188
hw/input/virtio-input-host.c
Normal file
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
* (at your option) any later version. See the COPYING file in the
|
||||
* top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/sockets.h"
|
||||
|
||||
#include "hw/qdev.h"
|
||||
#include "hw/virtio/virtio.h"
|
||||
#include "hw/virtio/virtio-input.h"
|
||||
|
||||
#include "standard-headers/linux/input.h"
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
|
||||
static struct virtio_input_config virtio_input_host_config[] = {
|
||||
{ /* empty list */ },
|
||||
};
|
||||
|
||||
static void virtio_input_host_event(void *opaque)
|
||||
{
|
||||
VirtIOInputHost *vih = opaque;
|
||||
VirtIOInput *vinput = VIRTIO_INPUT(vih);
|
||||
struct virtio_input_event virtio;
|
||||
struct input_event evdev;
|
||||
int rc;
|
||||
|
||||
for (;;) {
|
||||
rc = read(vih->fd, &evdev, sizeof(evdev));
|
||||
if (rc != sizeof(evdev)) {
|
||||
break;
|
||||
}
|
||||
|
||||
virtio.type = cpu_to_le16(evdev.type);
|
||||
virtio.code = cpu_to_le16(evdev.code);
|
||||
virtio.value = cpu_to_le32(evdev.value);
|
||||
virtio_input_send(vinput, &virtio);
|
||||
}
|
||||
}
|
||||
|
||||
static void virtio_input_bits_config(VirtIOInputHost *vih,
|
||||
int type, int count)
|
||||
{
|
||||
virtio_input_config bits;
|
||||
int rc, i, size = 0;
|
||||
|
||||
memset(&bits, 0, sizeof(bits));
|
||||
rc = ioctl(vih->fd, EVIOCGBIT(type, count/8), bits.u.bitmap);
|
||||
if (rc < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < count/8; i++) {
|
||||
if (bits.u.bitmap[i]) {
|
||||
size = i+1;
|
||||
}
|
||||
}
|
||||
if (size == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
bits.select = VIRTIO_INPUT_CFG_EV_BITS;
|
||||
bits.subsel = type;
|
||||
bits.size = size;
|
||||
virtio_input_add_config(VIRTIO_INPUT(vih), &bits);
|
||||
}
|
||||
|
||||
static void virtio_input_host_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
VirtIOInputHost *vih = VIRTIO_INPUT_HOST(dev);
|
||||
VirtIOInput *vinput = VIRTIO_INPUT(dev);
|
||||
virtio_input_config id;
|
||||
struct input_id ids;
|
||||
int rc, ver;
|
||||
|
||||
if (!vih->evdev) {
|
||||
error_setg(errp, "evdev property is required");
|
||||
return;
|
||||
}
|
||||
|
||||
vih->fd = open(vih->evdev, O_RDWR);
|
||||
if (vih->fd < 0) {
|
||||
error_setg_file_open(errp, errno, vih->evdev);
|
||||
return;
|
||||
}
|
||||
qemu_set_nonblock(vih->fd);
|
||||
|
||||
rc = ioctl(vih->fd, EVIOCGVERSION, &ver);
|
||||
if (rc < 0) {
|
||||
error_setg(errp, "%s: is not an evdev device", vih->evdev);
|
||||
goto err_close;
|
||||
}
|
||||
|
||||
rc = ioctl(vih->fd, EVIOCGRAB, 1);
|
||||
if (rc < 0) {
|
||||
error_setg_errno(errp, errno, "%s: failed to get exclusive access",
|
||||
vih->evdev);
|
||||
goto err_close;
|
||||
}
|
||||
|
||||
memset(&id, 0, sizeof(id));
|
||||
ioctl(vih->fd, EVIOCGNAME(sizeof(id.u.string)-1), id.u.string);
|
||||
id.select = VIRTIO_INPUT_CFG_ID_NAME;
|
||||
id.size = strlen(id.u.string);
|
||||
virtio_input_add_config(vinput, &id);
|
||||
|
||||
if (ioctl(vih->fd, EVIOCGID, &ids) == 0) {
|
||||
memset(&id, 0, sizeof(id));
|
||||
id.select = VIRTIO_INPUT_CFG_ID_DEVIDS;
|
||||
id.size = sizeof(struct virtio_input_devids);
|
||||
id.u.ids.bustype = cpu_to_le16(ids.bustype);
|
||||
id.u.ids.vendor = cpu_to_le16(ids.vendor);
|
||||
id.u.ids.product = cpu_to_le16(ids.product);
|
||||
id.u.ids.version = cpu_to_le16(ids.version);
|
||||
virtio_input_add_config(vinput, &id);
|
||||
}
|
||||
|
||||
virtio_input_bits_config(vih, EV_KEY, KEY_CNT);
|
||||
virtio_input_bits_config(vih, EV_REL, REL_CNT);
|
||||
virtio_input_bits_config(vih, EV_ABS, ABS_CNT);
|
||||
virtio_input_bits_config(vih, EV_MSC, MSC_CNT);
|
||||
virtio_input_bits_config(vih, EV_SW, SW_CNT);
|
||||
|
||||
qemu_set_fd_handler(vih->fd, virtio_input_host_event, NULL, vih);
|
||||
return;
|
||||
|
||||
err_close:
|
||||
close(vih->fd);
|
||||
vih->fd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
static void virtio_input_host_unrealize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
VirtIOInputHost *vih = VIRTIO_INPUT_HOST(dev);
|
||||
|
||||
if (vih->fd > 0) {
|
||||
qemu_set_fd_handler(vih->fd, NULL, NULL, NULL);
|
||||
close(vih->fd);
|
||||
}
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_virtio_input_host = {
|
||||
.name = "virtio-input-host",
|
||||
.unmigratable = 1,
|
||||
};
|
||||
|
||||
static Property virtio_input_host_properties[] = {
|
||||
DEFINE_PROP_STRING("evdev", VirtIOInputHost, evdev),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void virtio_input_host_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
VirtIOInputClass *vic = VIRTIO_INPUT_CLASS(klass);
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->vmsd = &vmstate_virtio_input_host;
|
||||
dc->props = virtio_input_host_properties;
|
||||
vic->realize = virtio_input_host_realize;
|
||||
vic->unrealize = virtio_input_host_unrealize;
|
||||
}
|
||||
|
||||
static void virtio_input_host_init(Object *obj)
|
||||
{
|
||||
VirtIOInput *vinput = VIRTIO_INPUT(obj);
|
||||
|
||||
virtio_input_init_config(vinput, virtio_input_host_config);
|
||||
}
|
||||
|
||||
static const TypeInfo virtio_input_host_info = {
|
||||
.name = TYPE_VIRTIO_INPUT_HOST,
|
||||
.parent = TYPE_VIRTIO_INPUT,
|
||||
.instance_size = sizeof(VirtIOInputHost),
|
||||
.instance_init = virtio_input_host_init,
|
||||
.class_init = virtio_input_host_class_init,
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
|
||||
static void virtio_register_types(void)
|
||||
{
|
||||
type_register_static(&virtio_input_host_info);
|
||||
}
|
||||
|
||||
type_init(virtio_register_types)
|
||||
@@ -216,7 +216,7 @@ static void virtio_input_device_realize(DeviceState *dev, Error **errp)
|
||||
}
|
||||
|
||||
virtio_input_idstr_config(vinput, VIRTIO_INPUT_CFG_ID_SERIAL,
|
||||
vinput->input.serial);
|
||||
vinput->serial);
|
||||
|
||||
QTAILQ_FOREACH(cfg, &vinput->cfg_list, node) {
|
||||
if (vinput->cfg_size < cfg->config.size) {
|
||||
@@ -248,11 +248,17 @@ static void virtio_input_device_unrealize(DeviceState *dev, Error **errp)
|
||||
virtio_cleanup(vdev);
|
||||
}
|
||||
|
||||
static Property virtio_input_properties[] = {
|
||||
DEFINE_PROP_STRING("serial", VirtIOInput, serial),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void virtio_input_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
|
||||
|
||||
dc->props = virtio_input_properties;
|
||||
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
|
||||
vdc->realize = virtio_input_device_realize;
|
||||
vdc->unrealize = virtio_input_device_unrealize;
|
||||
|
||||
@@ -102,6 +102,20 @@ static void mcf_intc_write(void *opaque, hwaddr addr,
|
||||
case 0x0c:
|
||||
s->imr = (s->imr & 0xffffffff00000000ull) | (uint32_t)val;
|
||||
break;
|
||||
case 0x1c:
|
||||
if (val & 0x40) {
|
||||
s->imr = ~0ull;
|
||||
} else {
|
||||
s->imr |= (0x1ull << (val & 0x3f));
|
||||
}
|
||||
break;
|
||||
case 0x1d:
|
||||
if (val & 0x40) {
|
||||
s->imr = 0ull;
|
||||
} else {
|
||||
s->imr &= ~(0x1ull << (val & 0x3f));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
hw_error("mcf_intc_write: Bad write offset %d\n", offset);
|
||||
break;
|
||||
|
||||
@@ -64,20 +64,6 @@
|
||||
#define SPI_IRQ 4
|
||||
#define UART16550_IRQ 5
|
||||
|
||||
static void machine_cpu_reset(MicroBlazeCPU *cpu)
|
||||
{
|
||||
CPUMBState *env = &cpu->env;
|
||||
|
||||
env->pvr.regs[10] = 0x0e000000; /* virtex 6 */
|
||||
/* setup pvr to match kernel setting */
|
||||
env->pvr.regs[5] |= PVR5_DCACHE_WRITEBACK_MASK;
|
||||
env->pvr.regs[0] |= PVR0_USE_FPU_MASK | PVR0_ENDI;
|
||||
env->pvr.regs[0] = (env->pvr.regs[0] & ~PVR0_VERSION_MASK) | (0x14 << 8);
|
||||
env->pvr.regs[2] ^= PVR2_USE_FPU2_MASK;
|
||||
env->pvr.regs[4] = 0xc56b8000;
|
||||
env->pvr.regs[5] = 0xc56be000;
|
||||
}
|
||||
|
||||
static void
|
||||
petalogix_ml605_init(MachineState *machine)
|
||||
{
|
||||
@@ -95,6 +81,13 @@ petalogix_ml605_init(MachineState *machine)
|
||||
|
||||
/* init CPUs */
|
||||
cpu = MICROBLAZE_CPU(object_new(TYPE_MICROBLAZE_CPU));
|
||||
/* Use FPU but don't use floating point conversion and square
|
||||
* root instructions
|
||||
*/
|
||||
object_property_set_int(OBJECT(cpu), 1, "use-fpu", &error_abort);
|
||||
object_property_set_bool(OBJECT(cpu), true, "dcache-writeback",
|
||||
&error_abort);
|
||||
object_property_set_bool(OBJECT(cpu), true, "endianness", &error_abort);
|
||||
object_property_set_bool(OBJECT(cpu), true, "realized", &error_abort);
|
||||
|
||||
/* Attach emulated BRAM through the LMB. */
|
||||
@@ -201,10 +194,15 @@ petalogix_ml605_init(MachineState *machine)
|
||||
}
|
||||
}
|
||||
|
||||
/* setup PVR to match kernel settings */
|
||||
cpu->env.pvr.regs[4] = 0xc56b8000;
|
||||
cpu->env.pvr.regs[5] = 0xc56be000;
|
||||
cpu->env.pvr.regs[10] = 0x0e000000; /* virtex 6 */
|
||||
|
||||
microblaze_load_kernel(cpu, MEMORY_BASEADDR, ram_size,
|
||||
machine->initrd_filename,
|
||||
BINARY_DEVICE_TREE_FILE,
|
||||
machine_cpu_reset);
|
||||
NULL);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -51,18 +51,10 @@
|
||||
#define ETHLITE_IRQ 1
|
||||
#define UARTLITE_IRQ 3
|
||||
|
||||
static void machine_cpu_reset(MicroBlazeCPU *cpu)
|
||||
{
|
||||
CPUMBState *env = &cpu->env;
|
||||
|
||||
env->pvr.regs[10] = 0x0c000000; /* spartan 3a dsp family. */
|
||||
}
|
||||
|
||||
static void
|
||||
petalogix_s3adsp1800_init(MachineState *machine)
|
||||
{
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
DeviceState *dev;
|
||||
MicroBlazeCPU *cpu;
|
||||
DriveInfo *dinfo;
|
||||
@@ -73,11 +65,8 @@ petalogix_s3adsp1800_init(MachineState *machine)
|
||||
qemu_irq irq[32];
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
|
||||
/* init CPUs */
|
||||
if (cpu_model == NULL) {
|
||||
cpu_model = "microblaze";
|
||||
}
|
||||
cpu = cpu_mb_init(cpu_model);
|
||||
cpu = MICROBLAZE_CPU(object_new(TYPE_MICROBLAZE_CPU));
|
||||
object_property_set_bool(OBJECT(cpu), true, "realized", &error_abort);
|
||||
|
||||
/* Attach emulated BRAM through the LMB. */
|
||||
memory_region_init_ram(phys_lmb_bram, NULL,
|
||||
@@ -132,7 +121,7 @@ petalogix_s3adsp1800_init(MachineState *machine)
|
||||
microblaze_load_kernel(cpu, ddr_base, ram_size,
|
||||
machine->initrd_filename,
|
||||
BINARY_DEVICE_TREE_FILE,
|
||||
machine_cpu_reset);
|
||||
NULL);
|
||||
}
|
||||
|
||||
static QEMUMachine petalogix_s3adsp1800_machine = {
|
||||
|
||||
@@ -698,7 +698,6 @@ static void ivshmem_write_config(PCIDevice *pci_dev, uint32_t address,
|
||||
uint32_t val, int len)
|
||||
{
|
||||
pci_default_write_config(pci_dev, address, val, len);
|
||||
msix_write_config(pci_dev, address, val, len);
|
||||
}
|
||||
|
||||
static int pci_ivshmem_init(PCIDevice *dev)
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "standard-headers/linux/virtio_ring.h"
|
||||
#include "hw/virtio/vhost.h"
|
||||
#include "hw/virtio/virtio-bus.h"
|
||||
#include "hw/virtio/virtio-access.h"
|
||||
|
||||
struct vhost_net {
|
||||
struct vhost_dev dev;
|
||||
@@ -162,7 +163,7 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
|
||||
net->dev.vq_index = net->nc->queue_index;
|
||||
|
||||
r = vhost_dev_init(&net->dev, options->opaque,
|
||||
options->backend_type, options->force);
|
||||
options->backend_type);
|
||||
if (r < 0) {
|
||||
goto fail;
|
||||
}
|
||||
@@ -187,16 +188,32 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool vhost_net_query(VHostNetState *net, VirtIODevice *dev)
|
||||
{
|
||||
return vhost_dev_query(&net->dev, dev);
|
||||
}
|
||||
|
||||
static void vhost_net_set_vq_index(struct vhost_net *net, int vq_index)
|
||||
{
|
||||
net->dev.vq_index = vq_index;
|
||||
}
|
||||
|
||||
static int vhost_net_set_vnet_endian(VirtIODevice *dev, NetClientState *peer,
|
||||
bool set)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
if (virtio_has_feature(dev, VIRTIO_F_VERSION_1) ||
|
||||
(virtio_legacy_is_cross_endian(dev) && !virtio_is_big_endian(dev))) {
|
||||
r = qemu_set_vnet_le(peer, set);
|
||||
if (r) {
|
||||
error_report("backend does not support LE vnet headers");
|
||||
}
|
||||
} else if (virtio_legacy_is_cross_endian(dev)) {
|
||||
r = qemu_set_vnet_be(peer, set);
|
||||
if (r) {
|
||||
error_report("backend does not support BE vnet headers");
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int vhost_net_start_one(struct vhost_net *net,
|
||||
VirtIODevice *dev)
|
||||
{
|
||||
@@ -281,19 +298,6 @@ static void vhost_net_stop_one(struct vhost_net *net,
|
||||
vhost_dev_disable_notifiers(&net->dev, dev);
|
||||
}
|
||||
|
||||
static bool vhost_net_device_endian_ok(VirtIODevice *vdev)
|
||||
{
|
||||
#ifdef TARGET_IS_BIENDIAN
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
return virtio_is_big_endian(vdev);
|
||||
#else
|
||||
return !virtio_is_big_endian(vdev);
|
||||
#endif
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
|
||||
int total_queues)
|
||||
{
|
||||
@@ -302,15 +306,14 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
|
||||
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
|
||||
int r, e, i;
|
||||
|
||||
if (!vhost_net_device_endian_ok(dev)) {
|
||||
error_report("vhost-net does not support cross-endian");
|
||||
if (!k->set_guest_notifiers) {
|
||||
error_report("binding does not support guest notifiers");
|
||||
r = -ENOSYS;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!k->set_guest_notifiers) {
|
||||
error_report("binding does not support guest notifiers");
|
||||
r = -ENOSYS;
|
||||
r = vhost_net_set_vnet_endian(dev, ncs[0].peer, true);
|
||||
if (r < 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -321,7 +324,7 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
|
||||
r = k->set_guest_notifiers(qbus->parent, total_queues * 2, true);
|
||||
if (r < 0) {
|
||||
error_report("Error binding guest notifier: %d", -r);
|
||||
goto err;
|
||||
goto err_endian;
|
||||
}
|
||||
|
||||
for (i = 0; i < total_queues; i++) {
|
||||
@@ -343,6 +346,8 @@ err_start:
|
||||
fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", e);
|
||||
fflush(stderr);
|
||||
}
|
||||
err_endian:
|
||||
vhost_net_set_vnet_endian(dev, ncs[0].peer, false);
|
||||
err:
|
||||
return r;
|
||||
}
|
||||
@@ -365,6 +370,8 @@ void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs,
|
||||
fflush(stderr);
|
||||
}
|
||||
assert(r >= 0);
|
||||
|
||||
assert(vhost_net_set_vnet_endian(dev, ncs[0].peer, false) >= 0);
|
||||
}
|
||||
|
||||
void vhost_net_cleanup(struct vhost_net *net)
|
||||
@@ -412,11 +419,6 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool vhost_net_query(VHostNetState *net, VirtIODevice *dev)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int vhost_net_start(VirtIODevice *dev,
|
||||
NetClientState *ncs,
|
||||
int total_queues)
|
||||
|
||||
@@ -128,10 +128,6 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t status)
|
||||
if (!n->vhost_started) {
|
||||
int r, i;
|
||||
|
||||
if (!vhost_net_query(get_vhost_net(nc->peer), vdev)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Any packets outstanding? Purge them to avoid touching rings
|
||||
* when vhost is running.
|
||||
*/
|
||||
|
||||
@@ -2477,14 +2477,6 @@ static const VMStateDescription vmstate_vmxnet3 = {
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
vmxnet3_write_config(PCIDevice *pci_dev, uint32_t addr, uint32_t val, int len)
|
||||
{
|
||||
pci_default_write_config(pci_dev, addr, val, len);
|
||||
msix_write_config(pci_dev, addr, val, len);
|
||||
msi_write_config(pci_dev, addr, val, len);
|
||||
}
|
||||
|
||||
static Property vmxnet3_properties[] = {
|
||||
DEFINE_NIC_PROPERTIES(VMXNET3State, conf),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
@@ -2503,7 +2495,6 @@ static void vmxnet3_class_init(ObjectClass *class, void *data)
|
||||
c->class_id = PCI_CLASS_NETWORK_ETHERNET;
|
||||
c->subsystem_vendor_id = PCI_VENDOR_ID_VMWARE;
|
||||
c->subsystem_id = PCI_DEVICE_ID_VMWARE_VMXNET3;
|
||||
c->config_write = vmxnet3_write_config,
|
||||
dc->desc = "VMWare Paravirtualized Ethernet v3";
|
||||
dc->reset = vmxnet3_qdev_reset;
|
||||
dc->vmsd = &vmstate_vmxnet3;
|
||||
|
||||
@@ -216,6 +216,7 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data)
|
||||
mc->no_sdcard = 1;
|
||||
mc->use_sclp = 1;
|
||||
mc->max_cpus = 255;
|
||||
mc->is_default = 1;
|
||||
nc->nmi_monitor_handler = s390_nmi;
|
||||
}
|
||||
|
||||
|
||||
@@ -345,7 +345,6 @@ static void s390_machine_class_init(ObjectClass *oc, void *data)
|
||||
mc->no_floppy = 1;
|
||||
mc->no_cdrom = 1;
|
||||
mc->no_sdcard = 1;
|
||||
mc->is_default = 1;
|
||||
nc->nmi_monitor_handler = s390_nmi;
|
||||
}
|
||||
|
||||
|
||||
@@ -1401,6 +1401,10 @@ static void virtio_ccw_device_plugged(DeviceState *d, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!kvm_eventfds_enabled()) {
|
||||
dev->flags &= ~VIRTIO_CCW_FLAG_USE_IOEVENTFD;
|
||||
}
|
||||
|
||||
sch->id.cu_model = virtio_bus_get_vdev_id(&dev->bus);
|
||||
|
||||
css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid,
|
||||
|
||||
@@ -2407,13 +2407,6 @@ static void megasas_scsi_realize(PCIDevice *dev, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
megasas_write_config(PCIDevice *pci, uint32_t addr, uint32_t val, int len)
|
||||
{
|
||||
pci_default_write_config(pci, addr, val, len);
|
||||
msi_write_config(pci, addr, val, len);
|
||||
}
|
||||
|
||||
static Property megasas_properties_gen1[] = {
|
||||
DEFINE_PROP_UINT32("max_sge", MegasasState, fw_sge,
|
||||
MEGASAS_DEFAULT_SGE),
|
||||
@@ -2516,7 +2509,6 @@ static void megasas_class_init(ObjectClass *oc, void *data)
|
||||
dc->vmsd = info->vmsd;
|
||||
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
|
||||
dc->desc = info->desc;
|
||||
pc->config_write = megasas_write_config;
|
||||
}
|
||||
|
||||
static const TypeInfo megasas_info = {
|
||||
|
||||
@@ -246,7 +246,7 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp)
|
||||
s->dev.backend_features = 0;
|
||||
|
||||
ret = vhost_dev_init(&s->dev, (void *)(uintptr_t)vhostfd,
|
||||
VHOST_BACKEND_TYPE_KERNEL, true);
|
||||
VHOST_BACKEND_TYPE_KERNEL);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "vhost-scsi: vhost initialization failed: %s",
|
||||
strerror(-ret));
|
||||
|
||||
@@ -1174,13 +1174,6 @@ static const VMStateDescription vmstate_pvscsi = {
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
pvscsi_write_config(PCIDevice *pci, uint32_t addr, uint32_t val, int len)
|
||||
{
|
||||
pci_default_write_config(pci, addr, val, len);
|
||||
msi_write_config(pci, addr, val, len);
|
||||
}
|
||||
|
||||
static Property pvscsi_properties[] = {
|
||||
DEFINE_PROP_UINT8("use_msg", PVSCSIState, use_msg, 1),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
@@ -1202,7 +1195,6 @@ static void pvscsi_class_init(ObjectClass *klass, void *data)
|
||||
dc->vmsd = &vmstate_pvscsi;
|
||||
dc->props = pvscsi_properties;
|
||||
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
|
||||
k->config_write = pvscsi_write_config;
|
||||
hc->unplug = pvscsi_hot_unplug;
|
||||
hc->plug = pvscsi_hotplug;
|
||||
}
|
||||
|
||||
@@ -196,6 +196,12 @@ static uint64_t pit_ioport_read(void *opaque, hwaddr addr,
|
||||
PITChannelState *s;
|
||||
|
||||
addr &= 3;
|
||||
|
||||
if (addr == 3) {
|
||||
/* Mode/Command register is write only, read is ignored */
|
||||
return 0;
|
||||
}
|
||||
|
||||
s = &pit->channels[addr];
|
||||
if (s->status_latched) {
|
||||
s->status_latched = 0;
|
||||
|
||||
@@ -723,6 +723,12 @@ static int rtc_post_load(void *opaque, int version_id)
|
||||
check_update_timer(s);
|
||||
}
|
||||
|
||||
uint64_t now = qemu_clock_get_ns(rtc_clock);
|
||||
if (now < s->next_periodic_time ||
|
||||
now > (s->next_periodic_time + get_max_clock_jump())) {
|
||||
periodic_timer_update(s, qemu_clock_get_ns(rtc_clock));
|
||||
}
|
||||
|
||||
#ifdef TARGET_I386
|
||||
if (version_id >= 2) {
|
||||
if (s->lost_tick_policy == LOST_TICK_POLICY_SLEW) {
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
* Copyright Red Hat, Inc. 2012
|
||||
*/
|
||||
|
||||
#include <linux/vfio.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/vfio.h>
|
||||
|
||||
#include "hw/vfio/vfio-platform.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
@@ -17,9 +17,11 @@
|
||||
#include "hw/hw.h"
|
||||
#include "qemu/atomic.h"
|
||||
#include "qemu/range.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include <linux/vhost.h>
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/virtio/virtio-bus.h"
|
||||
#include "hw/virtio/virtio-access.h"
|
||||
#include "migration/migration.h"
|
||||
|
||||
static struct vhost_log *vhost_log;
|
||||
@@ -689,6 +691,27 @@ static void vhost_log_stop(MemoryListener *listener,
|
||||
/* FIXME: implement */
|
||||
}
|
||||
|
||||
static int vhost_virtqueue_set_vring_endian_legacy(struct vhost_dev *dev,
|
||||
bool is_big_endian,
|
||||
int vhost_vq_index)
|
||||
{
|
||||
struct vhost_vring_state s = {
|
||||
.index = vhost_vq_index,
|
||||
.num = is_big_endian
|
||||
};
|
||||
|
||||
if (!dev->vhost_ops->vhost_call(dev, VHOST_SET_VRING_ENDIAN, &s)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (errno == ENOTTY) {
|
||||
error_report("vhost does not support cross-endian");
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
static int vhost_virtqueue_start(struct vhost_dev *dev,
|
||||
struct VirtIODevice *vdev,
|
||||
struct vhost_virtqueue *vq,
|
||||
@@ -719,6 +742,16 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1) &&
|
||||
virtio_legacy_is_cross_endian(vdev)) {
|
||||
r = vhost_virtqueue_set_vring_endian_legacy(dev,
|
||||
virtio_is_big_endian(vdev),
|
||||
vhost_vq_index);
|
||||
if (r) {
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
|
||||
s = l = virtio_queue_get_desc_size(vdev, idx);
|
||||
a = virtio_queue_get_desc_addr(vdev, idx);
|
||||
vq->desc = cpu_physical_memory_map(a, &l, 0);
|
||||
@@ -789,8 +822,9 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev,
|
||||
struct vhost_virtqueue *vq,
|
||||
unsigned idx)
|
||||
{
|
||||
int vhost_vq_index = idx - dev->vq_index;
|
||||
struct vhost_vring_state state = {
|
||||
.index = idx - dev->vq_index
|
||||
.index = vhost_vq_index,
|
||||
};
|
||||
int r;
|
||||
assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs);
|
||||
@@ -801,6 +835,20 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev,
|
||||
}
|
||||
virtio_queue_set_last_avail_idx(vdev, idx, state.num);
|
||||
virtio_queue_invalidate_signalled_used(vdev, idx);
|
||||
|
||||
/* In the cross-endian case, we need to reset the vring endianness to
|
||||
* native as legacy devices expect so by default.
|
||||
*/
|
||||
if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1) &&
|
||||
virtio_legacy_is_cross_endian(vdev)) {
|
||||
r = vhost_virtqueue_set_vring_endian_legacy(dev,
|
||||
!virtio_is_big_endian(vdev),
|
||||
vhost_vq_index);
|
||||
if (r < 0) {
|
||||
error_report("failed to reset vring endianness");
|
||||
}
|
||||
}
|
||||
|
||||
assert (r >= 0);
|
||||
cpu_physical_memory_unmap(vq->ring, virtio_queue_get_ring_size(vdev, idx),
|
||||
0, virtio_queue_get_ring_size(vdev, idx));
|
||||
@@ -853,7 +901,7 @@ static void vhost_virtqueue_cleanup(struct vhost_virtqueue *vq)
|
||||
}
|
||||
|
||||
int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
|
||||
VhostBackendType backend_type, bool force)
|
||||
VhostBackendType backend_type)
|
||||
{
|
||||
uint64_t features;
|
||||
int i, r;
|
||||
@@ -916,7 +964,6 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
|
||||
hdev->started = false;
|
||||
hdev->memory_changed = false;
|
||||
memory_listener_register(&hdev->memory_listener, &address_space_memory);
|
||||
hdev->force = force;
|
||||
return 0;
|
||||
fail_vq:
|
||||
while (--i >= 0) {
|
||||
@@ -944,17 +991,6 @@ void vhost_dev_cleanup(struct vhost_dev *hdev)
|
||||
hdev->vhost_ops->vhost_backend_cleanup(hdev);
|
||||
}
|
||||
|
||||
bool vhost_dev_query(struct vhost_dev *hdev, VirtIODevice *vdev)
|
||||
{
|
||||
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
|
||||
VirtioBusState *vbus = VIRTIO_BUS(qbus);
|
||||
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
|
||||
|
||||
return !k->query_guest_notifiers ||
|
||||
k->query_guest_notifiers(qbus->parent) ||
|
||||
hdev->force;
|
||||
}
|
||||
|
||||
/* Stop processing guest IO notifications in qemu.
|
||||
* Start processing them in vhost in kernel.
|
||||
*/
|
||||
|
||||
@@ -1900,8 +1900,7 @@ static const TypeInfo virtio_rng_pci_info = {
|
||||
|
||||
/* virtio-input-pci */
|
||||
|
||||
static Property virtio_input_hid_pci_properties[] = {
|
||||
DEFINE_VIRTIO_INPUT_PROPERTIES(VirtIOInputPCI, vdev.input),
|
||||
static Property virtio_input_pci_properties[] = {
|
||||
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
@@ -1924,19 +1923,13 @@ static void virtio_input_pci_class_init(ObjectClass *klass, void *data)
|
||||
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
|
||||
PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
|
||||
|
||||
dc->props = virtio_input_pci_properties;
|
||||
k->realize = virtio_input_pci_realize;
|
||||
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
|
||||
|
||||
pcidev_k->class_id = PCI_CLASS_INPUT_OTHER;
|
||||
}
|
||||
|
||||
static void virtio_input_hid_pci_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->props = virtio_input_hid_pci_properties;
|
||||
}
|
||||
|
||||
static void virtio_input_hid_kbd_pci_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
|
||||
@@ -1955,22 +1948,33 @@ static void virtio_input_hid_mouse_pci_class_init(ObjectClass *klass,
|
||||
static void virtio_keyboard_initfn(Object *obj)
|
||||
{
|
||||
VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
|
||||
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_KEYBOARD);
|
||||
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
||||
|
||||
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||
TYPE_VIRTIO_KEYBOARD);
|
||||
}
|
||||
|
||||
static void virtio_mouse_initfn(Object *obj)
|
||||
{
|
||||
VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
|
||||
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_MOUSE);
|
||||
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
||||
|
||||
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||
TYPE_VIRTIO_MOUSE);
|
||||
}
|
||||
|
||||
static void virtio_tablet_initfn(Object *obj)
|
||||
{
|
||||
VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
|
||||
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_TABLET);
|
||||
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
||||
|
||||
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||
TYPE_VIRTIO_TABLET);
|
||||
}
|
||||
|
||||
static void virtio_host_initfn(Object *obj)
|
||||
{
|
||||
VirtIOInputHostPCI *dev = VIRTIO_INPUT_HOST_PCI(obj);
|
||||
|
||||
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||
TYPE_VIRTIO_INPUT_HOST);
|
||||
}
|
||||
|
||||
static const TypeInfo virtio_input_pci_info = {
|
||||
@@ -1985,7 +1989,6 @@ static const TypeInfo virtio_input_hid_pci_info = {
|
||||
.name = TYPE_VIRTIO_INPUT_HID_PCI,
|
||||
.parent = TYPE_VIRTIO_INPUT_PCI,
|
||||
.instance_size = sizeof(VirtIOInputHIDPCI),
|
||||
.class_init = virtio_input_hid_pci_class_init,
|
||||
.abstract = true,
|
||||
};
|
||||
|
||||
@@ -2012,6 +2015,13 @@ static const TypeInfo virtio_tablet_pci_info = {
|
||||
.instance_init = virtio_tablet_initfn,
|
||||
};
|
||||
|
||||
static const TypeInfo virtio_host_pci_info = {
|
||||
.name = TYPE_VIRTIO_INPUT_HOST_PCI,
|
||||
.parent = TYPE_VIRTIO_INPUT_PCI,
|
||||
.instance_size = sizeof(VirtIOInputHostPCI),
|
||||
.instance_init = virtio_host_initfn,
|
||||
};
|
||||
|
||||
/* virtio-pci-bus */
|
||||
|
||||
static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
|
||||
@@ -2058,6 +2068,7 @@ static void virtio_pci_register_types(void)
|
||||
type_register_static(&virtio_keyboard_pci_info);
|
||||
type_register_static(&virtio_mouse_pci_info);
|
||||
type_register_static(&virtio_tablet_pci_info);
|
||||
type_register_static(&virtio_host_pci_info);
|
||||
type_register_static(&virtio_pci_bus_info);
|
||||
type_register_static(&virtio_pci_info);
|
||||
#ifdef CONFIG_VIRTFS
|
||||
|
||||
@@ -43,6 +43,7 @@ typedef struct VHostSCSIPCI VHostSCSIPCI;
|
||||
typedef struct VirtIORngPCI VirtIORngPCI;
|
||||
typedef struct VirtIOInputPCI VirtIOInputPCI;
|
||||
typedef struct VirtIOInputHIDPCI VirtIOInputHIDPCI;
|
||||
typedef struct VirtIOInputHostPCI VirtIOInputHostPCI;
|
||||
typedef struct VirtIOGPUPCI VirtIOGPUPCI;
|
||||
|
||||
/* virtio-pci-bus */
|
||||
@@ -263,6 +264,15 @@ struct VirtIOInputHIDPCI {
|
||||
VirtIOInputHID vdev;
|
||||
};
|
||||
|
||||
#define TYPE_VIRTIO_INPUT_HOST_PCI "virtio-input-host-pci"
|
||||
#define VIRTIO_INPUT_HOST_PCI(obj) \
|
||||
OBJECT_CHECK(VirtIOInputHostPCI, (obj), TYPE_VIRTIO_INPUT_HOST_PCI)
|
||||
|
||||
struct VirtIOInputHostPCI {
|
||||
VirtIOPCIProxy parent_obj;
|
||||
VirtIOInputHost vdev;
|
||||
};
|
||||
|
||||
/*
|
||||
* virtio-gpu-pci: This extends VirtioPCIProxy.
|
||||
*/
|
||||
|
||||
@@ -399,6 +399,8 @@ uint64_t helper_ldq_cmmu(CPUArchState *env, target_ulong addr, int mmu_idx);
|
||||
#undef MEMSUFFIX
|
||||
#undef SOFTMMU_CODE_ACCESS
|
||||
|
||||
#endif /* defined(CONFIG_USER_ONLY) */
|
||||
|
||||
/**
|
||||
* tlb_vaddr_to_host:
|
||||
* @env: CPUArchState
|
||||
@@ -417,6 +419,9 @@ uint64_t helper_ldq_cmmu(CPUArchState *env, target_ulong addr, int mmu_idx);
|
||||
static inline void *tlb_vaddr_to_host(CPUArchState *env, target_ulong addr,
|
||||
int access_type, int mmu_idx)
|
||||
{
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
return g2h(vaddr);
|
||||
#else
|
||||
int index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
CPUTLBEntry *tlbentry = &env->tlb_table[mmu_idx][index];
|
||||
target_ulong tlb_addr;
|
||||
@@ -449,8 +454,7 @@ static inline void *tlb_vaddr_to_host(CPUArchState *env, target_ulong addr,
|
||||
|
||||
haddr = addr + env->tlb_table[mmu_idx][index].addend;
|
||||
return (void *)haddr;
|
||||
#endif /* defined(CONFIG_USER_ONLY) */
|
||||
}
|
||||
|
||||
#endif /* defined(CONFIG_USER_ONLY) */
|
||||
|
||||
#endif /* CPU_LDST_H */
|
||||
|
||||
@@ -95,10 +95,4 @@ extern bool gdb_has_xml;
|
||||
/* in gdbstub-xml.c, generated by scripts/feature_to_c.sh */
|
||||
extern const char *const xml_builtin[][2];
|
||||
|
||||
/* Command line option defining whether semihosting should go via gdb or not */
|
||||
extern int semihosting_target;
|
||||
#define SEMIHOSTING_TARGET_AUTO 0
|
||||
#define SEMIHOSTING_TARGET_NATIVE 1
|
||||
#define SEMIHOSTING_TARGET_GDB 2
|
||||
|
||||
#endif
|
||||
|
||||
62
include/exec/semihost.h
Normal file
62
include/exec/semihost.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Semihosting support
|
||||
*
|
||||
* Copyright (c) 2015 Imagination Technologies
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SEMIHOST_H
|
||||
#define SEMIHOST_H
|
||||
|
||||
typedef enum SemihostingTarget {
|
||||
SEMIHOSTING_TARGET_AUTO = 0,
|
||||
SEMIHOSTING_TARGET_NATIVE,
|
||||
SEMIHOSTING_TARGET_GDB
|
||||
} SemihostingTarget;
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
static inline bool semihosting_enabled(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline SemihostingTarget semihosting_get_target(void)
|
||||
{
|
||||
return SEMIHOSTING_TARGET_AUTO;
|
||||
}
|
||||
|
||||
static inline const char *semihosting_get_arg(int i)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int semihosting_get_argc(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline const char *semihosting_get_cmdline(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
bool semihosting_enabled(void);
|
||||
SemihostingTarget semihosting_get_target(void);
|
||||
const char *semihosting_get_arg(int i);
|
||||
int semihosting_get_argc(void);
|
||||
const char *semihosting_get_cmdline(void);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
34
include/hw/arm/fdt.h
Normal file
34
include/hw/arm/fdt.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2015 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/>.
|
||||
*
|
||||
* Define macros useful when building ARM device tree nodes
|
||||
*/
|
||||
|
||||
#ifndef QEMU_ARM_FDT_H
|
||||
#define QEMU_ARM_FDT_H
|
||||
|
||||
#define GIC_FDT_IRQ_TYPE_SPI 0
|
||||
#define GIC_FDT_IRQ_TYPE_PPI 1
|
||||
|
||||
#define GIC_FDT_IRQ_FLAGS_EDGE_LO_HI 1
|
||||
#define GIC_FDT_IRQ_FLAGS_EDGE_HI_LO 2
|
||||
#define GIC_FDT_IRQ_FLAGS_LEVEL_HI 4
|
||||
#define GIC_FDT_IRQ_FLAGS_LEVEL_LO 8
|
||||
|
||||
#define GIC_FDT_IRQ_PPI_CPU_START 8
|
||||
#define GIC_FDT_IRQ_PPI_CPU_WIDTH 8
|
||||
|
||||
#endif
|
||||
@@ -27,7 +27,8 @@
|
||||
#define XLNX_ZYNQMP(obj) OBJECT_CHECK(XlnxZynqMPState, (obj), \
|
||||
TYPE_XLNX_ZYNQMP)
|
||||
|
||||
#define XLNX_ZYNQMP_NUM_CPUS 4
|
||||
#define XLNX_ZYNQMP_NUM_APU_CPUS 4
|
||||
#define XLNX_ZYNQMP_NUM_RPU_CPUS 2
|
||||
#define XLNX_ZYNQMP_NUM_GEMS 4
|
||||
#define XLNX_ZYNQMP_NUM_UARTS 2
|
||||
|
||||
@@ -47,11 +48,15 @@ typedef struct XlnxZynqMPState {
|
||||
DeviceState parent_obj;
|
||||
|
||||
/*< public >*/
|
||||
ARMCPU cpu[XLNX_ZYNQMP_NUM_CPUS];
|
||||
ARMCPU apu_cpu[XLNX_ZYNQMP_NUM_APU_CPUS];
|
||||
ARMCPU rpu_cpu[XLNX_ZYNQMP_NUM_RPU_CPUS];
|
||||
GICState gic;
|
||||
MemoryRegion gic_mr[XLNX_ZYNQMP_GIC_REGIONS][XLNX_ZYNQMP_GIC_ALIASES];
|
||||
CadenceGEMState gem[XLNX_ZYNQMP_NUM_GEMS];
|
||||
CadenceUARTState uart[XLNX_ZYNQMP_NUM_UARTS];
|
||||
|
||||
char *boot_cpu;
|
||||
ARMCPU *boot_cpu_ptr;
|
||||
} XlnxZynqMPState;
|
||||
|
||||
#define XLNX_ZYNQMP_H
|
||||
|
||||
@@ -65,8 +65,8 @@ struct VMStateDescription;
|
||||
* Operations depending on @props static properties should go into @realize.
|
||||
* After successful realization, setting static properties will fail.
|
||||
*
|
||||
* As an interim step, the #DeviceState:realized property is set by deprecated
|
||||
* functions qdev_init() and qdev_init_nofail().
|
||||
* As an interim step, the #DeviceState:realized property can also be
|
||||
* set with qdev_init_nofail().
|
||||
* In the future, devices will propagate this state change to their children
|
||||
* and along busses they expose.
|
||||
* The point in time will be deferred to machine creation, so that values
|
||||
@@ -236,7 +236,7 @@ struct Property {
|
||||
struct PropertyInfo {
|
||||
const char *name;
|
||||
const char *description;
|
||||
const char **enum_table;
|
||||
const char * const *enum_table;
|
||||
int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len);
|
||||
ObjectPropertyAccessor *get;
|
||||
ObjectPropertyAccessor *set;
|
||||
@@ -262,7 +262,6 @@ typedef struct GlobalProperty {
|
||||
|
||||
DeviceState *qdev_create(BusState *bus, const char *name);
|
||||
DeviceState *qdev_try_create(BusState *bus, const char *name);
|
||||
int qdev_init(DeviceState *dev) QEMU_WARN_UNUSED_RESULT;
|
||||
void qdev_init_nofail(DeviceState *dev);
|
||||
void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
|
||||
int required_for_version);
|
||||
|
||||
@@ -51,7 +51,6 @@ struct vhost_dev {
|
||||
bool log_enabled;
|
||||
unsigned long long log_size;
|
||||
Error *migration_blocker;
|
||||
bool force;
|
||||
bool memory_changed;
|
||||
hwaddr mem_changed_start_addr;
|
||||
hwaddr mem_changed_end_addr;
|
||||
@@ -61,7 +60,7 @@ struct vhost_dev {
|
||||
};
|
||||
|
||||
int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
|
||||
VhostBackendType backend_type, bool force);
|
||||
VhostBackendType backend_type);
|
||||
void vhost_dev_cleanup(struct vhost_dev *hdev);
|
||||
bool vhost_dev_query(struct vhost_dev *hdev, VirtIODevice *vdev);
|
||||
int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev);
|
||||
|
||||
@@ -32,6 +32,19 @@ static inline bool virtio_access_is_big_endian(VirtIODevice *vdev)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool virtio_legacy_is_cross_endian(VirtIODevice *vdev)
|
||||
{
|
||||
#ifdef TARGET_IS_BIENDIAN
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
return !virtio_is_big_endian(vdev);
|
||||
#else
|
||||
return virtio_is_big_endian(vdev);
|
||||
#endif
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint16_t virtio_lduw_phys(VirtIODevice *vdev, hwaddr pa)
|
||||
{
|
||||
if (virtio_access_is_big_endian(vdev)) {
|
||||
|
||||
@@ -50,17 +50,17 @@ typedef struct virtio_input_event virtio_input_event;
|
||||
#define VIRTIO_INPUT_HID_GET_PARENT_CLASS(obj) \
|
||||
OBJECT_GET_PARENT_CLASS(obj, TYPE_VIRTIO_INPUT_HID)
|
||||
|
||||
#define DEFINE_VIRTIO_INPUT_PROPERTIES(_state, _field) \
|
||||
DEFINE_PROP_STRING("serial", _state, _field.serial)
|
||||
#define TYPE_VIRTIO_INPUT_HOST "virtio-input-host-device"
|
||||
#define VIRTIO_INPUT_HOST(obj) \
|
||||
OBJECT_CHECK(VirtIOInputHost, (obj), TYPE_VIRTIO_INPUT_HOST)
|
||||
#define VIRTIO_INPUT_HOST_GET_PARENT_CLASS(obj) \
|
||||
OBJECT_GET_PARENT_CLASS(obj, TYPE_VIRTIO_INPUT_HOST)
|
||||
|
||||
typedef struct VirtIOInput VirtIOInput;
|
||||
typedef struct VirtIOInputClass VirtIOInputClass;
|
||||
typedef struct VirtIOInputConfig VirtIOInputConfig;
|
||||
typedef struct VirtIOInputHID VirtIOInputHID;
|
||||
|
||||
struct virtio_input_conf {
|
||||
char *serial;
|
||||
};
|
||||
typedef struct VirtIOInputHost VirtIOInputHost;
|
||||
|
||||
struct VirtIOInputConfig {
|
||||
virtio_input_config config;
|
||||
@@ -74,7 +74,7 @@ struct VirtIOInput {
|
||||
uint32_t cfg_size;
|
||||
QTAILQ_HEAD(, VirtIOInputConfig) cfg_list;
|
||||
VirtQueue *evt, *sts;
|
||||
virtio_input_conf input;
|
||||
char *serial;
|
||||
|
||||
virtio_input_event *queue;
|
||||
uint32_t qindex, qsize;
|
||||
@@ -100,6 +100,12 @@ struct VirtIOInputHID {
|
||||
int ledstate;
|
||||
};
|
||||
|
||||
struct VirtIOInputHost {
|
||||
VirtIOInput parent_obj;
|
||||
char *evdev;
|
||||
int fd;
|
||||
};
|
||||
|
||||
void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event);
|
||||
void virtio_input_init_config(VirtIOInput *vinput,
|
||||
virtio_input_config *config);
|
||||
|
||||
@@ -55,6 +55,8 @@ typedef bool (HasVnetHdrLen)(NetClientState *, int);
|
||||
typedef void (UsingVnetHdr)(NetClientState *, bool);
|
||||
typedef void (SetOffload)(NetClientState *, int, int, int, int, int);
|
||||
typedef void (SetVnetHdrLen)(NetClientState *, int);
|
||||
typedef int (SetVnetLE)(NetClientState *, bool);
|
||||
typedef int (SetVnetBE)(NetClientState *, bool);
|
||||
|
||||
typedef struct NetClientInfo {
|
||||
NetClientOptionsKind type;
|
||||
@@ -73,6 +75,8 @@ typedef struct NetClientInfo {
|
||||
UsingVnetHdr *using_vnet_hdr;
|
||||
SetOffload *set_offload;
|
||||
SetVnetHdrLen *set_vnet_hdr_len;
|
||||
SetVnetLE *set_vnet_le;
|
||||
SetVnetBE *set_vnet_be;
|
||||
} NetClientInfo;
|
||||
|
||||
struct NetClientState {
|
||||
@@ -139,6 +143,8 @@ void qemu_using_vnet_hdr(NetClientState *nc, bool enable);
|
||||
void qemu_set_offload(NetClientState *nc, int csum, int tso4, int tso6,
|
||||
int ecn, int ufo);
|
||||
void qemu_set_vnet_hdr_len(NetClientState *nc, int len);
|
||||
int qemu_set_vnet_le(NetClientState *nc, bool is_le);
|
||||
int qemu_set_vnet_be(NetClientState *nc, bool is_be);
|
||||
void qemu_macaddr_default_if_unset(MACAddr *macaddr);
|
||||
int qemu_show_nic_models(const char *arg, const char *const *models);
|
||||
void qemu_check_nic_model(NICInfo *nd, const char *model);
|
||||
|
||||
@@ -11,12 +11,10 @@ typedef struct VhostNetOptions {
|
||||
VhostBackendType backend_type;
|
||||
NetClientState *net_backend;
|
||||
void *opaque;
|
||||
bool force;
|
||||
} VhostNetOptions;
|
||||
|
||||
struct vhost_net *vhost_net_init(VhostNetOptions *options);
|
||||
|
||||
bool vhost_net_query(VHostNetState *net, VirtIODevice *dev);
|
||||
int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, int total_queues);
|
||||
void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs, int total_queues);
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#ifndef QAPI_UTIL_H
|
||||
#define QAPI_UTIL_H
|
||||
|
||||
int qapi_enum_parse(const char *lookup[], const char *buf,
|
||||
int qapi_enum_parse(const char * const lookup[], const char *buf,
|
||||
int max, int def, Error **errp);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -30,7 +30,7 @@ struct Visitor
|
||||
GenericList *(*next_list)(Visitor *v, GenericList **list, Error **errp);
|
||||
void (*end_list)(Visitor *v, Error **errp);
|
||||
|
||||
void (*type_enum)(Visitor *v, int *obj, const char *strings[],
|
||||
void (*type_enum)(Visitor *v, int *obj, const char * const strings[],
|
||||
const char *kind, const char *name, Error **errp);
|
||||
void (*get_next_type)(Visitor *v, int *kind, const int *qobjects,
|
||||
const char *name, Error **errp);
|
||||
@@ -59,9 +59,9 @@ struct Visitor
|
||||
void (*end_union)(Visitor *v, bool data_present, Error **errp);
|
||||
};
|
||||
|
||||
void input_type_enum(Visitor *v, int *obj, const char *strings[],
|
||||
void input_type_enum(Visitor *v, int *obj, const char * const strings[],
|
||||
const char *kind, const char *name, Error **errp);
|
||||
void output_type_enum(Visitor *v, int *obj, const char *strings[],
|
||||
void output_type_enum(Visitor *v, int *obj, const char * const strings[],
|
||||
const char *kind, const char *name, Error **errp);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -43,7 +43,7 @@ void visit_optional(Visitor *v, bool *present, const char *name,
|
||||
Error **errp);
|
||||
void visit_get_next_type(Visitor *v, int *obj, const int *qtypes,
|
||||
const char *name, Error **errp);
|
||||
void visit_type_enum(Visitor *v, int *obj, const char *strings[],
|
||||
void visit_type_enum(Visitor *v, int *obj, const char * const strings[],
|
||||
const char *kind, const char *name, Error **errp);
|
||||
void visit_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp);
|
||||
void visit_type_uint8(Visitor *v, uint8_t *obj, const char *name, Error **errp);
|
||||
|
||||
@@ -24,6 +24,12 @@
|
||||
#define QEMU_WARN_UNUSED_RESULT
|
||||
#endif
|
||||
|
||||
#if QEMU_GNUC_PREREQ(4, 0)
|
||||
#define QEMU_SENTINEL __attribute__((sentinel))
|
||||
#else
|
||||
#define QEMU_SENTINEL
|
||||
#endif
|
||||
|
||||
#if QEMU_GNUC_PREREQ(4, 3)
|
||||
#define QEMU_ARTIFICIAL __attribute__((always_inline, artificial))
|
||||
#else
|
||||
|
||||
@@ -787,6 +787,15 @@ static inline int64_t get_ticks_per_sec(void)
|
||||
return 1000000000LL;
|
||||
}
|
||||
|
||||
static inline int64_t get_max_clock_jump(void)
|
||||
{
|
||||
/* This should be small enough to prevent excessive interrupts from being
|
||||
* generated by the RTC on clock jumps, but large enough to avoid frequent
|
||||
* unnecessary resets in idle VMs.
|
||||
*/
|
||||
return 60 * get_ticks_per_sec();
|
||||
}
|
||||
|
||||
/*
|
||||
* Low level clock functions
|
||||
*/
|
||||
|
||||
@@ -606,6 +606,134 @@ Object *object_new(const char *typename);
|
||||
*/
|
||||
Object *object_new_with_type(Type type);
|
||||
|
||||
/**
|
||||
* object_new_with_props:
|
||||
* @typename: The name of the type of the object to instantiate.
|
||||
* @parent: the parent object
|
||||
* @id: The unique ID of the object
|
||||
* @errp: pointer to error object
|
||||
* @...: list of property names and values
|
||||
*
|
||||
* This function will initialize a new object using heap allocated memory.
|
||||
* The returned object has a reference count of 1, and will be freed when
|
||||
* the last reference is dropped.
|
||||
*
|
||||
* The @id parameter will be used when registering the object as a
|
||||
* child of @parent in the composition tree.
|
||||
*
|
||||
* The variadic parameters are a list of pairs of (propname, propvalue)
|
||||
* strings. The propname of %NULL indicates the end of the property
|
||||
* list. If the object implements the user creatable interface, the
|
||||
* object will be marked complete once all the properties have been
|
||||
* processed.
|
||||
*
|
||||
* <example>
|
||||
* <title>Creating an object with properties</title>
|
||||
* <programlisting>
|
||||
* Error *err = NULL;
|
||||
* Object *obj;
|
||||
*
|
||||
* obj = object_new_with_props(TYPE_MEMORY_BACKEND_FILE,
|
||||
* object_get_objects_root(),
|
||||
* "hostmem0",
|
||||
* &err,
|
||||
* "share", "yes",
|
||||
* "mem-path", "/dev/shm/somefile",
|
||||
* "prealloc", "yes",
|
||||
* "size", "1048576",
|
||||
* NULL);
|
||||
*
|
||||
* if (!obj) {
|
||||
* g_printerr("Cannot create memory backend: %s\n",
|
||||
* error_get_pretty(err));
|
||||
* }
|
||||
* </programlisting>
|
||||
* </example>
|
||||
*
|
||||
* The returned object will have one stable reference maintained
|
||||
* for as long as it is present in the object hierarchy.
|
||||
*
|
||||
* Returns: The newly allocated, instantiated & initialized object.
|
||||
*/
|
||||
Object *object_new_with_props(const char *typename,
|
||||
Object *parent,
|
||||
const char *id,
|
||||
Error **errp,
|
||||
...) QEMU_SENTINEL;
|
||||
|
||||
/**
|
||||
* object_new_with_propv:
|
||||
* @typename: The name of the type of the object to instantiate.
|
||||
* @parent: the parent object
|
||||
* @id: The unique ID of the object
|
||||
* @errp: pointer to error object
|
||||
* @vargs: list of property names and values
|
||||
*
|
||||
* See object_new_with_props() for documentation.
|
||||
*/
|
||||
Object *object_new_with_propv(const char *typename,
|
||||
Object *parent,
|
||||
const char *id,
|
||||
Error **errp,
|
||||
va_list vargs);
|
||||
|
||||
/**
|
||||
* object_set_props:
|
||||
* @obj: the object instance to set properties on
|
||||
* @errp: pointer to error object
|
||||
* @...: list of property names and values
|
||||
*
|
||||
* This function will set a list of properties on an existing object
|
||||
* instance.
|
||||
*
|
||||
* The variadic parameters are a list of pairs of (propname, propvalue)
|
||||
* strings. The propname of %NULL indicates the end of the property
|
||||
* list.
|
||||
*
|
||||
* <example>
|
||||
* <title>Update an object's properties</title>
|
||||
* <programlisting>
|
||||
* Error *err = NULL;
|
||||
* Object *obj = ...get / create object...;
|
||||
*
|
||||
* obj = object_set_props(obj,
|
||||
* &err,
|
||||
* "share", "yes",
|
||||
* "mem-path", "/dev/shm/somefile",
|
||||
* "prealloc", "yes",
|
||||
* "size", "1048576",
|
||||
* NULL);
|
||||
*
|
||||
* if (!obj) {
|
||||
* g_printerr("Cannot set properties: %s\n",
|
||||
* error_get_pretty(err));
|
||||
* }
|
||||
* </programlisting>
|
||||
* </example>
|
||||
*
|
||||
* The returned object will have one stable reference maintained
|
||||
* for as long as it is present in the object hierarchy.
|
||||
*
|
||||
* Returns: -1 on error, 0 on success
|
||||
*/
|
||||
int object_set_props(Object *obj,
|
||||
Error **errp,
|
||||
...) QEMU_SENTINEL;
|
||||
|
||||
/**
|
||||
* object_set_propv:
|
||||
* @obj: the object instance to set properties on
|
||||
* @errp: pointer to error object
|
||||
* @vargs: list of property names and values
|
||||
*
|
||||
* See object_set_props() for documentation.
|
||||
*
|
||||
* Returns: -1 on error, 0 on success
|
||||
*/
|
||||
int object_set_propv(Object *obj,
|
||||
Error **errp,
|
||||
va_list vargs);
|
||||
|
||||
/**
|
||||
* object_initialize_with_type:
|
||||
* @data: A pointer to the memory to be used for the object.
|
||||
@@ -945,7 +1073,7 @@ int64_t object_property_get_int(Object *obj, const char *name,
|
||||
* object_property_get_enum:
|
||||
* @obj: the object
|
||||
* @name: the name of the property
|
||||
* @strings: strings corresponding to enums
|
||||
* @typename: the name of the enum data type
|
||||
* @errp: returns an error if this function fails
|
||||
*
|
||||
* Returns: the value of the property, converted to an integer, or
|
||||
@@ -953,7 +1081,7 @@ int64_t object_property_get_int(Object *obj, const char *name,
|
||||
* an enum).
|
||||
*/
|
||||
int object_property_get_enum(Object *obj, const char *name,
|
||||
const char *strings[], Error **errp);
|
||||
const char *typename, Error **errp);
|
||||
|
||||
/**
|
||||
* object_property_get_uint16List:
|
||||
@@ -1026,6 +1154,18 @@ const char *object_property_get_type(Object *obj, const char *name,
|
||||
*/
|
||||
Object *object_get_root(void);
|
||||
|
||||
|
||||
/**
|
||||
* object_get_objects_root:
|
||||
*
|
||||
* Get the container object that holds user created
|
||||
* object instances. This is the object at path
|
||||
* "/objects"
|
||||
*
|
||||
* Returns: the user object container
|
||||
*/
|
||||
Object *object_get_objects_root(void);
|
||||
|
||||
/**
|
||||
* object_get_canonical_path_component:
|
||||
*
|
||||
@@ -1203,6 +1343,25 @@ void object_property_add_bool(Object *obj, const char *name,
|
||||
void (*set)(Object *, bool, Error **),
|
||||
Error **errp);
|
||||
|
||||
/**
|
||||
* object_property_add_enum:
|
||||
* @obj: the object to add a property to
|
||||
* @name: the name of the property
|
||||
* @typename: the name of the enum data type
|
||||
* @get: the getter or %NULL if the property is write-only.
|
||||
* @set: the setter or %NULL if the property is read-only
|
||||
* @errp: if an error occurs, a pointer to an area to store the error
|
||||
*
|
||||
* Add an enum property using getters/setters. This function will add a
|
||||
* property of type '@typename'.
|
||||
*/
|
||||
void object_property_add_enum(Object *obj, const char *name,
|
||||
const char *typename,
|
||||
const char * const *strings,
|
||||
int (*get)(Object *, Error **),
|
||||
void (*set)(Object *, int, Error **),
|
||||
Error **errp);
|
||||
|
||||
/**
|
||||
* object_property_add_tm:
|
||||
* @obj: the object to add a property to
|
||||
|
||||
@@ -126,7 +126,6 @@ extern int cursor_hide;
|
||||
extern int graphic_rotate;
|
||||
extern int no_quit;
|
||||
extern int no_shutdown;
|
||||
extern int semihosting_enabled;
|
||||
extern int old_param;
|
||||
extern int boot_menu;
|
||||
extern bool boot_strict;
|
||||
|
||||
@@ -19,8 +19,6 @@
|
||||
#include "qmp-commands.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
#define IOTHREADS_PATH "/objects"
|
||||
|
||||
typedef ObjectClass IOThreadClass;
|
||||
|
||||
#define IOTHREAD_GET_CLASS(obj) \
|
||||
@@ -160,7 +158,7 @@ IOThreadInfoList *qmp_query_iothreads(Error **errp)
|
||||
{
|
||||
IOThreadInfoList *head = NULL;
|
||||
IOThreadInfoList **prev = &head;
|
||||
Object *container = container_get(object_get_root(), IOTHREADS_PATH);
|
||||
Object *container = object_get_objects_root();
|
||||
|
||||
object_child_foreach(container, query_one_iothread, &prev);
|
||||
return head;
|
||||
|
||||
@@ -103,6 +103,20 @@ struct vhost_memory {
|
||||
/* Get accessor: reads index, writes value in num */
|
||||
#define VHOST_GET_VRING_BASE _IOWR(VHOST_VIRTIO, 0x12, struct vhost_vring_state)
|
||||
|
||||
/* Set the vring byte order in num. Valid values are VHOST_VRING_LITTLE_ENDIAN
|
||||
* or VHOST_VRING_BIG_ENDIAN (other values return -EINVAL).
|
||||
* The byte order cannot be changed while the device is active: trying to do so
|
||||
* returns -EBUSY.
|
||||
* This is a legacy only API that is simply ignored when VIRTIO_F_VERSION_1 is
|
||||
* set.
|
||||
* Not all kernel configurations support this ioctl, but all configurations that
|
||||
* support SET also support GET.
|
||||
*/
|
||||
#define VHOST_VRING_LITTLE_ENDIAN 0
|
||||
#define VHOST_VRING_BIG_ENDIAN 1
|
||||
#define VHOST_SET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x13, struct vhost_vring_state)
|
||||
#define VHOST_GET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x14, struct vhost_vring_state)
|
||||
|
||||
/* The following ioctls use eventfd file descriptors to signal and poll
|
||||
* for events. */
|
||||
|
||||
|
||||
18
net/net.c
18
net/net.c
@@ -510,6 +510,24 @@ void qemu_set_vnet_hdr_len(NetClientState *nc, int len)
|
||||
nc->info->set_vnet_hdr_len(nc, len);
|
||||
}
|
||||
|
||||
int qemu_set_vnet_le(NetClientState *nc, bool is_le)
|
||||
{
|
||||
if (!nc || !nc->info->set_vnet_le) {
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
return nc->info->set_vnet_le(nc, is_le);
|
||||
}
|
||||
|
||||
int qemu_set_vnet_be(NetClientState *nc, bool is_be)
|
||||
{
|
||||
if (!nc || !nc->info->set_vnet_be) {
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
return nc->info->set_vnet_be(nc, is_be);
|
||||
}
|
||||
|
||||
int qemu_can_send_packet(NetClientState *sender)
|
||||
{
|
||||
int vm_running = runstate_is_running();
|
||||
|
||||
@@ -55,6 +55,16 @@ void tap_fd_set_vnet_hdr_len(int fd, int len)
|
||||
{
|
||||
}
|
||||
|
||||
int tap_fd_set_vnet_le(int fd, int is_le)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int tap_fd_set_vnet_be(int fd, int is_be)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
void tap_fd_set_offload(int fd, int csum, int tso4,
|
||||
int tso6, int ecn, int ufo)
|
||||
{
|
||||
|
||||
@@ -196,6 +196,16 @@ void tap_fd_set_vnet_hdr_len(int fd, int len)
|
||||
{
|
||||
}
|
||||
|
||||
int tap_fd_set_vnet_le(int fd, int is_le)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int tap_fd_set_vnet_be(int fd, int is_be)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
void tap_fd_set_offload(int fd, int csum, int tso4,
|
||||
int tso6, int ecn, int ufo)
|
||||
{
|
||||
|
||||
@@ -55,6 +55,16 @@ void tap_fd_set_vnet_hdr_len(int fd, int len)
|
||||
{
|
||||
}
|
||||
|
||||
int tap_fd_set_vnet_le(int fd, int is_le)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int tap_fd_set_vnet_be(int fd, int is_be)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
void tap_fd_set_offload(int fd, int csum, int tso4,
|
||||
int tso6, int ecn, int ufo)
|
||||
{
|
||||
|
||||
@@ -198,6 +198,40 @@ void tap_fd_set_vnet_hdr_len(int fd, int len)
|
||||
}
|
||||
}
|
||||
|
||||
int tap_fd_set_vnet_le(int fd, int is_le)
|
||||
{
|
||||
int arg = is_le ? 1 : 0;
|
||||
|
||||
if (!ioctl(fd, TUNSETVNETLE, &arg)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if our kernel supports TUNSETVNETLE */
|
||||
if (errno == EINVAL) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
error_report("TUNSETVNETLE ioctl() failed: %s.\n", strerror(errno));
|
||||
abort();
|
||||
}
|
||||
|
||||
int tap_fd_set_vnet_be(int fd, int is_be)
|
||||
{
|
||||
int arg = is_be ? 1 : 0;
|
||||
|
||||
if (!ioctl(fd, TUNSETVNETBE, &arg)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if our kernel supports TUNSETVNETBE */
|
||||
if (errno == EINVAL) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
error_report("TUNSETVNETBE ioctl() failed: %s.\n", strerror(errno));
|
||||
abort();
|
||||
}
|
||||
|
||||
void tap_fd_set_offload(int fd, int csum, int tso4,
|
||||
int tso6, int ecn, int ufo)
|
||||
{
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
#define TUNGETVNETHDRSZ _IOR('T', 215, int)
|
||||
#define TUNSETVNETHDRSZ _IOW('T', 216, int)
|
||||
#define TUNSETQUEUE _IOW('T', 217, int)
|
||||
#define TUNSETVNETLE _IOW('T', 220, int)
|
||||
#define TUNSETVNETBE _IOW('T', 222, int)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -223,6 +223,16 @@ void tap_fd_set_vnet_hdr_len(int fd, int len)
|
||||
{
|
||||
}
|
||||
|
||||
int tap_fd_set_vnet_le(int fd, int is_le)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int tap_fd_set_vnet_be(int fd, int is_be)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
void tap_fd_set_offload(int fd, int csum, int tso4,
|
||||
int tso6, int ecn, int ufo)
|
||||
{
|
||||
|
||||
@@ -688,6 +688,16 @@ void tap_fd_set_vnet_hdr_len(int fd, int len)
|
||||
{
|
||||
}
|
||||
|
||||
int tap_fd_set_vnet_le(int fd, int is_le)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int tap_fd_set_vnet_be(int fd, int is_be)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void tap_using_vnet_hdr(NetClientState *nc, bool using_vnet_hdr)
|
||||
{
|
||||
}
|
||||
|
||||
17
net/tap.c
17
net/tap.c
@@ -266,6 +266,20 @@ static void tap_using_vnet_hdr(NetClientState *nc, bool using_vnet_hdr)
|
||||
s->using_vnet_hdr = using_vnet_hdr;
|
||||
}
|
||||
|
||||
static int tap_set_vnet_le(NetClientState *nc, bool is_le)
|
||||
{
|
||||
TAPState *s = DO_UPCAST(TAPState, nc, nc);
|
||||
|
||||
return tap_fd_set_vnet_le(s->fd, is_le);
|
||||
}
|
||||
|
||||
static int tap_set_vnet_be(NetClientState *nc, bool is_be)
|
||||
{
|
||||
TAPState *s = DO_UPCAST(TAPState, nc, nc);
|
||||
|
||||
return tap_fd_set_vnet_be(s->fd, is_be);
|
||||
}
|
||||
|
||||
static void tap_set_offload(NetClientState *nc, int csum, int tso4,
|
||||
int tso6, int ecn, int ufo)
|
||||
{
|
||||
@@ -332,6 +346,8 @@ static NetClientInfo net_tap_info = {
|
||||
.using_vnet_hdr = tap_using_vnet_hdr,
|
||||
.set_offload = tap_set_offload,
|
||||
.set_vnet_hdr_len = tap_set_vnet_hdr_len,
|
||||
.set_vnet_le = tap_set_vnet_le,
|
||||
.set_vnet_be = tap_set_vnet_be,
|
||||
};
|
||||
|
||||
static TAPState *net_tap_fd_init(NetClientState *peer,
|
||||
@@ -646,7 +662,6 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
|
||||
|
||||
options.backend_type = VHOST_BACKEND_TYPE_KERNEL;
|
||||
options.net_backend = &s->nc;
|
||||
options.force = tap->has_vhostforce && tap->vhostforce;
|
||||
|
||||
if (tap->has_vhostfd || tap->has_vhostfds) {
|
||||
vhostfd = monitor_fd_param(cur_mon, vhostfdname, &err);
|
||||
|
||||
@@ -40,6 +40,8 @@ int tap_probe_vnet_hdr_len(int fd, int len);
|
||||
int tap_probe_has_ufo(int fd);
|
||||
void tap_fd_set_offload(int fd, int csum, int tso4, int tso6, int ecn, int ufo);
|
||||
void tap_fd_set_vnet_hdr_len(int fd, int len);
|
||||
int tap_fd_set_vnet_le(int fd, int vnet_is_le);
|
||||
int tap_fd_set_vnet_be(int fd, int vnet_is_be);
|
||||
int tap_fd_enable(int fd);
|
||||
int tap_fd_disable(int fd);
|
||||
int tap_fd_get_ifname(int fd, char *ifname);
|
||||
|
||||
@@ -50,7 +50,6 @@ static int vhost_user_start(VhostUserState *s)
|
||||
options.backend_type = VHOST_BACKEND_TYPE_USER;
|
||||
options.net_backend = &s->nc;
|
||||
options.opaque = s->chr;
|
||||
options.force = true;
|
||||
|
||||
s->vhost_net = vhost_net_init(&options);
|
||||
|
||||
|
||||
4
numa.c
4
numa.c
@@ -456,7 +456,7 @@ static int query_memdev(Object *obj, void *opaque)
|
||||
|
||||
m->value->policy = object_property_get_enum(obj,
|
||||
"policy",
|
||||
HostMemPolicy_lookup,
|
||||
"HostMemPolicy",
|
||||
&err);
|
||||
if (err) {
|
||||
goto error;
|
||||
@@ -485,7 +485,7 @@ MemdevList *qmp_query_memdev(Error **errp)
|
||||
Object *obj;
|
||||
MemdevList *list = NULL;
|
||||
|
||||
obj = object_resolve_path("/objects", NULL);
|
||||
obj = object_get_objects_root();
|
||||
if (obj == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -156,7 +156,8 @@ static void qapi_dealloc_type_size(Visitor *v, uint64_t *obj, const char *name,
|
||||
{
|
||||
}
|
||||
|
||||
static void qapi_dealloc_type_enum(Visitor *v, int *obj, const char *strings[],
|
||||
static void qapi_dealloc_type_enum(Visitor *v, int *obj,
|
||||
const char * const strings[],
|
||||
const char *kind, const char *name,
|
||||
Error **errp)
|
||||
{
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/util.h"
|
||||
|
||||
int qapi_enum_parse(const char *lookup[], const char *buf,
|
||||
int qapi_enum_parse(const char * const lookup[], const char *buf,
|
||||
int max, int def, Error **errp)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -89,7 +89,7 @@ void visit_get_next_type(Visitor *v, int *obj, const int *qtypes,
|
||||
}
|
||||
}
|
||||
|
||||
void visit_type_enum(Visitor *v, int *obj, const char *strings[],
|
||||
void visit_type_enum(Visitor *v, int *obj, const char * const strings[],
|
||||
const char *kind, const char *name, Error **errp)
|
||||
{
|
||||
v->type_enum(v, obj, strings, kind, name, errp);
|
||||
@@ -260,7 +260,7 @@ void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp)
|
||||
v->type_number(v, obj, name, errp);
|
||||
}
|
||||
|
||||
void output_type_enum(Visitor *v, int *obj, const char *strings[],
|
||||
void output_type_enum(Visitor *v, int *obj, const char * const strings[],
|
||||
const char *kind, const char *name,
|
||||
Error **errp)
|
||||
{
|
||||
@@ -279,7 +279,7 @@ void output_type_enum(Visitor *v, int *obj, const char *strings[],
|
||||
visit_type_str(v, &enum_str, name, errp);
|
||||
}
|
||||
|
||||
void input_type_enum(Visitor *v, int *obj, const char *strings[],
|
||||
void input_type_enum(Visitor *v, int *obj, const char * const strings[],
|
||||
const char *kind, const char *name,
|
||||
Error **errp)
|
||||
{
|
||||
|
||||
@@ -42,9 +42,9 @@ static const QDevAlias qdev_alias_table[] = {
|
||||
{ "virtio-serial-pci", "virtio-serial", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
|
||||
{ "virtio-balloon-pci", "virtio-balloon",
|
||||
QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
|
||||
{ "virtio-blk-s390", "virtio-blk", QEMU_ARCH_S390X },
|
||||
{ "virtio-net-s390", "virtio-net", QEMU_ARCH_S390X },
|
||||
{ "virtio-serial-s390", "virtio-serial", QEMU_ARCH_S390X },
|
||||
{ "virtio-blk-ccw", "virtio-blk", QEMU_ARCH_S390X },
|
||||
{ "virtio-net-ccw", "virtio-net", QEMU_ARCH_S390X },
|
||||
{ "virtio-serial-ccw", "virtio-serial", QEMU_ARCH_S390X },
|
||||
{ "lsi53c895a", "lsi" },
|
||||
{ "ich9-ahci", "ahci" },
|
||||
{ "kvm-pci-assign", "pci-assign" },
|
||||
|
||||
@@ -3351,14 +3351,25 @@ STEXI
|
||||
Enable semihosting mode (ARM, M68K, Xtensa only).
|
||||
ETEXI
|
||||
DEF("semihosting-config", HAS_ARG, QEMU_OPTION_semihosting_config,
|
||||
"-semihosting-config [enable=on|off,]target=native|gdb|auto semihosting configuration\n",
|
||||
"-semihosting-config [enable=on|off][,target=native|gdb|auto][,arg=str[,...]]\n" \
|
||||
" semihosting configuration\n",
|
||||
QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32)
|
||||
STEXI
|
||||
@item -semihosting-config [enable=on|off,]target=native|gdb|auto
|
||||
@item -semihosting-config [enable=on|off][,target=native|gdb|auto][,arg=str[,...]]
|
||||
@findex -semihosting-config
|
||||
Enable semihosting and define where the semihosting calls will be addressed,
|
||||
to QEMU (@code{native}) or to GDB (@code{gdb}). The default is @code{auto}, which means
|
||||
@code{gdb} during debug sessions and @code{native} otherwise (ARM, M68K, Xtensa only).
|
||||
Enable and configure semihosting (ARM, M68K, Xtensa only).
|
||||
@table @option
|
||||
@item target=@code{native|gdb|auto}
|
||||
Defines where the semihosting calls will be addressed, to QEMU (@code{native})
|
||||
or to GDB (@code{gdb}). The default is @code{auto}, which means @code{gdb}
|
||||
during debug sessions and @code{native} otherwise.
|
||||
@item arg=@var{str1},arg=@var{str2},...
|
||||
Allows the user to pass input arguments, and can be used multiple times to build
|
||||
up a list. The old-style @code{-kernel}/@code{-append} method of passing a
|
||||
command line is still supported for backward compatibility. If both the
|
||||
@code{--semihosting-config arg} and the @code{-kernel}/@code{-append} are
|
||||
specified, the former is passed to semihosting as it always takes precedence.
|
||||
@end table
|
||||
ETEXI
|
||||
DEF("old-param", 0, QEMU_OPTION_old_param,
|
||||
"-old-param old param mode\n", QEMU_ARCH_ARM)
|
||||
@@ -3476,22 +3487,6 @@ DEF("no-kvm-irqchip", 0, QEMU_OPTION_no_kvm_irqchip, "", QEMU_ARCH_I386)
|
||||
HXCOMM Deprecated (ignored)
|
||||
DEF("tdf", 0, QEMU_OPTION_tdf,"", QEMU_ARCH_ALL)
|
||||
|
||||
DEF("object", HAS_ARG, QEMU_OPTION_object,
|
||||
"-object TYPENAME[,PROP1=VALUE1,...]\n"
|
||||
" create an new object of type TYPENAME setting properties\n"
|
||||
" in the order they are specified. Note that the 'id'\n"
|
||||
" property must be set. These objects are placed in the\n"
|
||||
" '/objects' path.\n",
|
||||
QEMU_ARCH_ALL)
|
||||
STEXI
|
||||
@item -object @var{typename}[,@var{prop1}=@var{value1},...]
|
||||
@findex -object
|
||||
Create an new object of type @var{typename} setting properties
|
||||
in the order they are specified. Note that the 'id'
|
||||
property must be set. These objects are placed in the
|
||||
'/objects' path.
|
||||
ETEXI
|
||||
|
||||
DEF("msg", HAS_ARG, QEMU_OPTION_msg,
|
||||
"-msg timestamp[=on|off]\n"
|
||||
" change the format of messages\n"
|
||||
@@ -3517,6 +3512,60 @@ Dump json-encoded vmstate information for current machine type to file
|
||||
in @var{file}
|
||||
ETEXI
|
||||
|
||||
DEFHEADING(Generic object creation)
|
||||
|
||||
DEF("object", HAS_ARG, QEMU_OPTION_object,
|
||||
"-object TYPENAME[,PROP1=VALUE1,...]\n"
|
||||
" create a new object of type TYPENAME setting properties\n"
|
||||
" in the order they are specified. Note that the 'id'\n"
|
||||
" property must be set. These objects are placed in the\n"
|
||||
" '/objects' path.\n",
|
||||
QEMU_ARCH_ALL)
|
||||
STEXI
|
||||
@item -object @var{typename}[,@var{prop1}=@var{value1},...]
|
||||
@findex -object
|
||||
Create a new object of type @var{typename} setting properties
|
||||
in the order they are specified. Note that the 'id'
|
||||
property must be set. These objects are placed in the
|
||||
'/objects' path.
|
||||
|
||||
@table @option
|
||||
|
||||
@item -object memory-backend-file,id=@var{id},size=@var{size},mem-path=@var{dir},share=@var{on|off}
|
||||
|
||||
Creates a memory file backend object, which can be used to back
|
||||
the guest RAM with huge pages. The @option{id} parameter is a
|
||||
unique ID that will be used to reference this memory region
|
||||
when configuring the @option{-numa} argument. The @option{size}
|
||||
option provides the size of the memory region, and accepts
|
||||
common suffixes, eg @option{500M}. The @option{mem-path} provides
|
||||
the path to either a shared memory or huge page filesystem mount.
|
||||
The @option{share} boolean option determines whether the memory
|
||||
region is marked as private to QEMU, or shared. The latter allows
|
||||
a co-operating external process to access the QEMU memory region.
|
||||
|
||||
@item -object rng-random,id=@var{id},filename=@var{/dev/random}
|
||||
|
||||
Creates a random number generator backend which obtains entropy from
|
||||
a device on the host. The @option{id} parameter is a unique ID that
|
||||
will be used to reference this entropy backend from the @option{virtio-rng}
|
||||
device. The @option{filename} parameter specifies which file to obtain
|
||||
entropy from and if omitted defaults to @option{/dev/random}.
|
||||
|
||||
@item -object rng-egd,id=@var{id},chardev=@var{chardevid}
|
||||
|
||||
Creates a random number generator backend which obtains entropy from
|
||||
an external daemon running on the host. The @option{id} parameter is
|
||||
a unique ID that will be used to reference this entropy backend from
|
||||
the @option{virtio-rng} device. The @option{chardev} parameter is
|
||||
the unique ID of a character device backend that provides the connection
|
||||
to the RNG daemon.
|
||||
|
||||
@end table
|
||||
|
||||
ETEXI
|
||||
|
||||
|
||||
HXCOMM This is the last statement. Insert new options before this line!
|
||||
STEXI
|
||||
@end table
|
||||
|
||||
@@ -573,7 +573,7 @@ int64_t qemu_clock_get_ns(QEMUClockType type)
|
||||
now = get_clock_realtime();
|
||||
last = clock->last;
|
||||
clock->last = now;
|
||||
if (now < last) {
|
||||
if (now < last || now > (last + get_max_clock_jump())) {
|
||||
notifier_list_notify(&clock->reset_notifiers, &now);
|
||||
}
|
||||
return now;
|
||||
|
||||
@@ -306,7 +306,7 @@ static gboolean ga_channel_open(GAChannel *c, GAChannelMethod method,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL);
|
||||
if (c->handle == INVALID_HANDLE_VALUE) {
|
||||
g_critical("error opening path");
|
||||
g_critical("error opening path %s", newpath);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -721,6 +721,7 @@ GList *ga_command_blacklist_init(GList *blacklist)
|
||||
}
|
||||
|
||||
if (!vss_init(true)) {
|
||||
g_debug("vss_init failed, vss commands are going to be disabled");
|
||||
const char *list[] = {
|
||||
"guest-get-fsinfo", "guest-fsfreeze-status",
|
||||
"guest-fsfreeze-freeze", "guest-fsfreeze-thaw", NULL};
|
||||
|
||||
145
qga/installer/qemu-ga.wxs
Normal file
145
qga/installer/qemu-ga.wxs
Normal file
@@ -0,0 +1,145 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<?ifndef env.QEMU_GA_VERSION ?>
|
||||
<?error Environment variable QEMU_GA_VERSION undefined?>
|
||||
<?endif?>
|
||||
|
||||
<?ifndef env.QEMU_GA_DISTRO ?>
|
||||
<?error Environment variable QEMU_GA_DISTRO undefined?>
|
||||
<?endif?>
|
||||
|
||||
<?ifndef env.QEMU_GA_MANUFACTURER ?>
|
||||
<?error Environment variable QEMU_GA_MANUFACTURER undefined?>
|
||||
<?endif?>
|
||||
|
||||
<?ifndef var.Arch?>
|
||||
<?error Define Arch to 32 or 64?>
|
||||
<?endif?>
|
||||
|
||||
<?ifndef var.Mingw_bin?>
|
||||
<?if $(var.Arch) = "64"?>
|
||||
<?define Mingw_bin=/usr/x86_64-w64-mingw32/sys-root/mingw/bin ?>
|
||||
<?endif?>
|
||||
<?if $(var.Arch) = "32"?>
|
||||
<?define Mingw_bin=/usr/i686-w64-mingw32/sys-root/mingw/bin ?>
|
||||
<?endif?>
|
||||
<?endif?>
|
||||
|
||||
<?if $(var.Arch) = "64"?>
|
||||
<?define ArchLib=libgcc_s_seh-1.dll?>
|
||||
<?define GaProgramFilesFolder="ProgramFiles64Folder" ?>
|
||||
<?endif?>
|
||||
|
||||
<?if $(var.Arch) = "32"?>
|
||||
<?define ArchLib=libgcc_s_sjlj-1.dll?>
|
||||
<?define GaProgramFilesFolder="ProgramFilesFolder" ?>
|
||||
<?endif?>
|
||||
|
||||
<?ifndef var.ArchLib ?>
|
||||
<?error Unexpected Arch value $(var.Arch)?>
|
||||
<?endif?>
|
||||
|
||||
<Product
|
||||
Name="QEMU guest agent"
|
||||
Id="*"
|
||||
UpgradeCode="{EB6B8302-C06E-4bec-ADAC-932C68A3A98D}"
|
||||
Manufacturer="$(env.QEMU_GA_MANUFACTURER)"
|
||||
Version="$(env.QEMU_GA_VERSION)"
|
||||
Language="1033">
|
||||
<?if $(var.Arch) = 32 ?>
|
||||
<Condition Message="Error: 32-bit version of Qemu GA can not be installed on 64-bit Windows.">NOT VersionNT64</Condition>
|
||||
<?endif?>
|
||||
<Package
|
||||
Manufacturer="$(env.QEMU_GA_MANUFACTURER)"
|
||||
InstallerVersion="200"
|
||||
Languages="1033"
|
||||
Compressed="yes"
|
||||
InstallScope="perMachine"
|
||||
/>
|
||||
<Media Id="1" Cabinet="qemu_ga.$(env.QEMU_GA_VERSION).cab" EmbedCab="yes" />
|
||||
<Property Id="WHSLogo">1</Property>
|
||||
<Property Id="PREVIOUSVERSIONSINSTALLED" />
|
||||
<Upgrade Id="{EB6B8302-C06E-4bec-ADAC-932C68A3A98D}">
|
||||
<UpgradeVersion
|
||||
Minimum="1.0.0.0" Maximum="$(env.QEMU_GA_VERSION)"
|
||||
Property="PREVIOUSVERSIONSINSTALLED"
|
||||
IncludeMinimum="yes" IncludeMaximum="no" />
|
||||
</Upgrade>
|
||||
|
||||
<Directory Id="TARGETDIR" Name="SourceDir">
|
||||
<Directory Id="$(var.GaProgramFilesFolder)" Name="QEMU Guest Agent">
|
||||
<Directory Id="qemu_ga_directory" Name="Qemu-ga">
|
||||
<Component Id="qemu_ga" Guid="{908B7199-DE2A-4dc6-A8D0-27A5AE444FEA}">
|
||||
<File Id="qemu_ga.exe" Name="qemu-ga.exe" Source="../../qemu-ga.exe" KeyPath="yes" DiskId="1"/>
|
||||
<?ifdef var.InstallVss ?>
|
||||
<File Id="qga_vss.dll" Name="qga-vss.dll" Source="../vss-win32/qga-vss.dll" KeyPath="no" DiskId="1"/>
|
||||
<File Id="qga_vss.tlb" Name="qga-vss.tlb" Source="../vss-win32/qga-vss.tlb" KeyPath="no" DiskId="1"/>
|
||||
<?endif?>
|
||||
<File Id="iconv.dll" Name="iconv.dll" Source="$(var.Mingw_bin)/iconv.dll" KeyPath="no" DiskId="1"/>
|
||||
<File Id="libgcc_arch_lib" Name="$(var.ArchLib)" Source="$(var.Mingw_bin)/$(var.ArchLib)" KeyPath="no" DiskId="1"/>
|
||||
<File Id="libglib_2.0_0.dll" Name="libglib-2.0-0.dll" Source="$(var.Mingw_bin)/libglib-2.0-0.dll" KeyPath="no" DiskId="1"/>
|
||||
<File Id="libintl_8.dll" Name="libintl-8.dll" Source="$(var.Mingw_bin)/libintl-8.dll" KeyPath="no" DiskId="1"/>
|
||||
<File Id="libssp_0.dll" Name="libssp-0.dll" Source="$(var.Mingw_bin)/libssp-0.dll" KeyPath="no" DiskId="1"/>
|
||||
<File Id="libwinpthread_1.dll" Name="libwinpthread-1.dll" Source="$(var.Mingw_bin)/libwinpthread-1.dll" KeyPath="no" DiskId="1"/>
|
||||
<ServiceInstall
|
||||
Id="ServiceInstaller"
|
||||
Type="ownProcess"
|
||||
Vital="yes"
|
||||
Name="QEMU-GA"
|
||||
DisplayName="QEMU Guest Agent"
|
||||
Description="QEMU Guest Agent"
|
||||
Start="auto"
|
||||
Account="LocalSystem"
|
||||
ErrorControl="ignore"
|
||||
Interactive="no"
|
||||
Arguments="-d"
|
||||
>
|
||||
</ServiceInstall>
|
||||
<ServiceControl Id="StartService" Start="install" Stop="both" Remove="uninstall" Name="QEMU-GA" Wait="no" />
|
||||
</Component>
|
||||
|
||||
<Component Id="registry_entries" Guid="d075d109-51ca-11e3-9f8b-000c29858960">
|
||||
<RegistryKey Root="HKLM"
|
||||
Key="Software\$(env.QEMU_GA_MANUFACTURER)\$(env.QEMU_GA_DISTRO)\Tools\QemuGA">
|
||||
<RegistryValue Type="string" Name="ProductID" Value="fb0a0d66-c7fb-4e2e-a16b-c4a3bfe8d13b" />
|
||||
<RegistryValue Type="string" Name="Version" Value="$(env.QEMU_GA_VERSION)" />
|
||||
</RegistryKey>
|
||||
</Component>
|
||||
</Directory>
|
||||
</Directory>
|
||||
</Directory>
|
||||
|
||||
<Property Id="cmd" Value="cmd.exe"/>
|
||||
|
||||
<?ifdef var.InstallVss ?>
|
||||
<CustomAction Id="RegisterCom"
|
||||
ExeCommand='/c "[qemu_ga_directory]qemu-ga.exe" -s vss-install'
|
||||
Execute="deferred"
|
||||
Property="cmd"
|
||||
Impersonate="no"
|
||||
Return="check"
|
||||
>
|
||||
</CustomAction>
|
||||
<CustomAction Id="UnRegisterCom"
|
||||
ExeCommand='/c "[qemu_ga_directory]qemu-ga.exe" -s vss-uninstall'
|
||||
Execute="deferred"
|
||||
Property="cmd"
|
||||
Impersonate="no"
|
||||
Return="check"
|
||||
></CustomAction>
|
||||
<?endif?>
|
||||
|
||||
<Feature Id="QEMUFeature" Title="QEMU Guest Agent" Level="1">
|
||||
<ComponentRef Id="qemu_ga" />
|
||||
<ComponentRef Id="registry_entries" />
|
||||
</Feature>
|
||||
|
||||
<InstallExecuteSequence>
|
||||
<RemoveExistingProducts Before="InstallInitialize" />
|
||||
<?ifdef var.InstallVss ?>
|
||||
<Custom Action="RegisterCom" After="InstallServices">NOT Installed</Custom>
|
||||
<Custom Action="UnRegisterCom" After="StopServices">Installed</Custom>
|
||||
<?endif?>
|
||||
</InstallExecuteSequence>
|
||||
</Product>
|
||||
</Wix>
|
||||
10
qga/main.c
10
qga/main.c
@@ -211,7 +211,7 @@ static void usage(const char *cmd)
|
||||
" -V, --version print version information and exit\n"
|
||||
" -d, --daemonize become a daemon\n"
|
||||
#ifdef _WIN32
|
||||
" -s, --service service commands: install, uninstall\n"
|
||||
" -s, --service service commands: install, uninstall, vss-install, vss-uninstall\n"
|
||||
#endif
|
||||
" -b, --blacklist comma-separated list of RPCs to disable (no spaces, \"?\"\n"
|
||||
" to list available RPCs)\n"
|
||||
@@ -1036,6 +1036,14 @@ int main(int argc, char **argv)
|
||||
} else if (strcmp(service, "uninstall") == 0) {
|
||||
ga_uninstall_vss_provider();
|
||||
return ga_uninstall_service();
|
||||
} else if (strcmp(service, "vss-install") == 0) {
|
||||
if (ga_install_vss_provider()) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
} else if (strcmp(service, "vss-uninstall") == 0) {
|
||||
ga_uninstall_vss_provider();
|
||||
return EXIT_SUCCESS;
|
||||
} else {
|
||||
printf("Unknown service command.\n");
|
||||
return EXIT_FAILURE;
|
||||
|
||||
6
qmp.c
6
qmp.c
@@ -651,7 +651,7 @@ void object_add(const char *type, const char *id, const QDict *qdict,
|
||||
}
|
||||
}
|
||||
|
||||
object_property_add_child(container_get(object_get_root(), "/objects"),
|
||||
object_property_add_child(object_get_objects_root(),
|
||||
id, obj, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
@@ -659,7 +659,7 @@ void object_add(const char *type, const char *id, const QDict *qdict,
|
||||
|
||||
user_creatable_complete(obj, &local_err);
|
||||
if (local_err) {
|
||||
object_property_del(container_get(object_get_root(), "/objects"),
|
||||
object_property_del(object_get_objects_root(),
|
||||
id, &error_abort);
|
||||
goto out;
|
||||
}
|
||||
@@ -706,7 +706,7 @@ void qmp_object_del(const char *id, Error **errp)
|
||||
Object *container;
|
||||
Object *obj;
|
||||
|
||||
container = container_get(object_get_root(), "/objects");
|
||||
container = object_get_objects_root();
|
||||
obj = object_resolve_path_component(container, id);
|
||||
if (!obj) {
|
||||
error_setg(errp, "object id not found");
|
||||
|
||||
196
qom/object.c
196
qom/object.c
@@ -11,6 +11,7 @@
|
||||
*/
|
||||
|
||||
#include "qom/object.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qapi/visitor.h"
|
||||
#include "qapi-visit.h"
|
||||
@@ -439,6 +440,114 @@ Object *object_new(const char *typename)
|
||||
return object_new_with_type(ti);
|
||||
}
|
||||
|
||||
|
||||
Object *object_new_with_props(const char *typename,
|
||||
Object *parent,
|
||||
const char *id,
|
||||
Error **errp,
|
||||
...)
|
||||
{
|
||||
va_list vargs;
|
||||
Object *obj;
|
||||
|
||||
va_start(vargs, errp);
|
||||
obj = object_new_with_propv(typename, parent, id, errp, vargs);
|
||||
va_end(vargs);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
Object *object_new_with_propv(const char *typename,
|
||||
Object *parent,
|
||||
const char *id,
|
||||
Error **errp,
|
||||
va_list vargs)
|
||||
{
|
||||
Object *obj;
|
||||
ObjectClass *klass;
|
||||
Error *local_err = NULL;
|
||||
|
||||
klass = object_class_by_name(typename);
|
||||
if (!klass) {
|
||||
error_setg(errp, "invalid object type: %s", typename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (object_class_is_abstract(klass)) {
|
||||
error_setg(errp, "object type '%s' is abstract", typename);
|
||||
return NULL;
|
||||
}
|
||||
obj = object_new(typename);
|
||||
|
||||
if (object_set_propv(obj, &local_err, vargs) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
object_property_add_child(parent, id, obj, &local_err);
|
||||
if (local_err) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (object_dynamic_cast(obj, TYPE_USER_CREATABLE)) {
|
||||
user_creatable_complete(obj, &local_err);
|
||||
if (local_err) {
|
||||
object_unparent(obj);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
object_unref(OBJECT(obj));
|
||||
return obj;
|
||||
|
||||
error:
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
object_unref(obj);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int object_set_props(Object *obj,
|
||||
Error **errp,
|
||||
...)
|
||||
{
|
||||
va_list vargs;
|
||||
int ret;
|
||||
|
||||
va_start(vargs, errp);
|
||||
ret = object_set_propv(obj, errp, vargs);
|
||||
va_end(vargs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int object_set_propv(Object *obj,
|
||||
Error **errp,
|
||||
va_list vargs)
|
||||
{
|
||||
const char *propname;
|
||||
Error *local_err = NULL;
|
||||
|
||||
propname = va_arg(vargs, char *);
|
||||
while (propname != NULL) {
|
||||
const char *value = va_arg(vargs, char *);
|
||||
|
||||
g_assert(value != NULL);
|
||||
object_property_parse(obj, value, propname, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return -1;
|
||||
}
|
||||
propname = va_arg(vargs, char *);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Object *object_dynamic_cast(Object *obj, const char *typename)
|
||||
{
|
||||
if (obj && object_class_dynamic_cast(object_get_class(obj), typename)) {
|
||||
@@ -960,13 +1069,34 @@ int64_t object_property_get_int(Object *obj, const char *name,
|
||||
return retval;
|
||||
}
|
||||
|
||||
typedef struct EnumProperty {
|
||||
const char * const *strings;
|
||||
int (*get)(Object *, Error **);
|
||||
void (*set)(Object *, int, Error **);
|
||||
} EnumProperty;
|
||||
|
||||
int object_property_get_enum(Object *obj, const char *name,
|
||||
const char *strings[], Error **errp)
|
||||
const char *typename, Error **errp)
|
||||
{
|
||||
StringOutputVisitor *sov;
|
||||
StringInputVisitor *siv;
|
||||
char *str;
|
||||
int ret;
|
||||
ObjectProperty *prop = object_property_find(obj, name, errp);
|
||||
EnumProperty *enumprop;
|
||||
|
||||
if (prop == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!g_str_equal(prop->type, typename)) {
|
||||
error_setg(errp, "Property %s on %s is not '%s' enum type",
|
||||
name, object_class_get_name(
|
||||
object_get_class(obj)), typename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
enumprop = prop->opaque;
|
||||
|
||||
sov = string_output_visitor_new(false);
|
||||
object_property_get(obj, string_output_get_visitor(sov), name, errp);
|
||||
@@ -974,7 +1104,7 @@ int object_property_get_enum(Object *obj, const char *name,
|
||||
siv = string_input_visitor_new(str);
|
||||
string_output_visitor_cleanup(sov);
|
||||
visit_type_enum(string_input_get_visitor(siv),
|
||||
&ret, strings, NULL, name, errp);
|
||||
&ret, enumprop->strings, NULL, name, errp);
|
||||
|
||||
g_free(str);
|
||||
string_input_visitor_cleanup(siv);
|
||||
@@ -1054,6 +1184,11 @@ Object *object_get_root(void)
|
||||
return root;
|
||||
}
|
||||
|
||||
Object *object_get_objects_root(void)
|
||||
{
|
||||
return container_get(object_get_root(), "/objects");
|
||||
}
|
||||
|
||||
static void object_get_child_property(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
@@ -1559,6 +1694,58 @@ void object_property_add_bool(Object *obj, const char *name,
|
||||
}
|
||||
}
|
||||
|
||||
static void property_get_enum(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
EnumProperty *prop = opaque;
|
||||
int value;
|
||||
|
||||
value = prop->get(obj, errp);
|
||||
visit_type_enum(v, &value, prop->strings, NULL, name, errp);
|
||||
}
|
||||
|
||||
static void property_set_enum(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
EnumProperty *prop = opaque;
|
||||
int value;
|
||||
|
||||
visit_type_enum(v, &value, prop->strings, NULL, name, errp);
|
||||
prop->set(obj, value, errp);
|
||||
}
|
||||
|
||||
static void property_release_enum(Object *obj, const char *name,
|
||||
void *opaque)
|
||||
{
|
||||
EnumProperty *prop = opaque;
|
||||
g_free(prop);
|
||||
}
|
||||
|
||||
void object_property_add_enum(Object *obj, const char *name,
|
||||
const char *typename,
|
||||
const char * const *strings,
|
||||
int (*get)(Object *, Error **),
|
||||
void (*set)(Object *, int, Error **),
|
||||
Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
EnumProperty *prop = g_malloc(sizeof(*prop));
|
||||
|
||||
prop->strings = strings;
|
||||
prop->get = get;
|
||||
prop->set = set;
|
||||
|
||||
object_property_add(obj, name, typename,
|
||||
get ? property_get_enum : NULL,
|
||||
set ? property_set_enum : NULL,
|
||||
property_release_enum,
|
||||
prop, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
g_free(prop);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct TMProperty {
|
||||
void (*get)(Object *, struct tm *, Error **);
|
||||
} TMProperty;
|
||||
@@ -1705,7 +1892,7 @@ void object_property_add_uint64_ptr(Object *obj, const char *name,
|
||||
|
||||
typedef struct {
|
||||
Object *target_obj;
|
||||
const char *target_name;
|
||||
char *target_name;
|
||||
} AliasProperty;
|
||||
|
||||
static void property_get_alias(Object *obj, struct Visitor *v, void *opaque,
|
||||
@@ -1736,6 +1923,7 @@ static void property_release_alias(Object *obj, const char *name, void *opaque)
|
||||
{
|
||||
AliasProperty *prop = opaque;
|
||||
|
||||
g_free(prop->target_name);
|
||||
g_free(prop);
|
||||
}
|
||||
|
||||
@@ -1763,7 +1951,7 @@ void object_property_add_alias(Object *obj, const char *name,
|
||||
|
||||
prop = g_malloc(sizeof(*prop));
|
||||
prop->target_obj = target_obj;
|
||||
prop->target_name = target_name;
|
||||
prop->target_name = g_strdup(target_name);
|
||||
|
||||
op = object_property_add(obj, name, prop_type,
|
||||
property_get_alias,
|
||||
|
||||
Submodule roms/openbios updated: 5d3db90143...18f02b14de
@@ -12,9 +12,8 @@
|
||||
from ordereddict import OrderedDict
|
||||
from qapi import *
|
||||
|
||||
def generate_fwd_struct(name, members, builtin_type=False):
|
||||
if builtin_type:
|
||||
return mcgen('''
|
||||
def generate_fwd_builtin(name):
|
||||
return mcgen('''
|
||||
|
||||
typedef struct %(name)sList
|
||||
{
|
||||
@@ -25,9 +24,10 @@ typedef struct %(name)sList
|
||||
struct %(name)sList *next;
|
||||
} %(name)sList;
|
||||
''',
|
||||
type=c_type(name),
|
||||
name=name)
|
||||
type=c_type(name),
|
||||
name=name)
|
||||
|
||||
def generate_fwd_struct(name):
|
||||
return mcgen('''
|
||||
|
||||
typedef struct %(name)s %(name)s;
|
||||
@@ -43,7 +43,7 @@ typedef struct %(name)sList
|
||||
''',
|
||||
name=c_name(name))
|
||||
|
||||
def generate_fwd_enum_struct(name, members):
|
||||
def generate_fwd_enum_struct(name):
|
||||
return mcgen('''
|
||||
typedef struct %(name)sList
|
||||
{
|
||||
@@ -75,7 +75,6 @@ def generate_struct_fields(members):
|
||||
def generate_struct(expr):
|
||||
|
||||
structname = expr.get('struct', "")
|
||||
fieldname = expr.get('field', "")
|
||||
members = expr['data']
|
||||
base = expr.get('base')
|
||||
|
||||
@@ -98,18 +97,15 @@ struct %(name)s
|
||||
char qapi_dummy_field_for_empty_struct;
|
||||
''')
|
||||
|
||||
if len(fieldname):
|
||||
fieldname = " " + fieldname
|
||||
ret += mcgen('''
|
||||
}%(field)s;
|
||||
''',
|
||||
field=fieldname)
|
||||
};
|
||||
''')
|
||||
|
||||
return ret
|
||||
|
||||
def generate_enum_lookup(name, values):
|
||||
ret = mcgen('''
|
||||
const char *%(name)s_lookup[] = {
|
||||
const char * const %(name)s_lookup[] = {
|
||||
''',
|
||||
name=c_name(name))
|
||||
i = 0
|
||||
@@ -132,7 +128,7 @@ const char *%(name)s_lookup[] = {
|
||||
def generate_enum(name, values):
|
||||
name = c_name(name)
|
||||
lookup_decl = mcgen('''
|
||||
extern const char *%(name)s_lookup[];
|
||||
extern const char * const %(name)s_lookup[];
|
||||
''',
|
||||
name=name)
|
||||
|
||||
@@ -329,30 +325,29 @@ fdecl.write(mcgen('''
|
||||
'''))
|
||||
|
||||
exprs = parse_schema(input_file)
|
||||
exprs = filter(lambda expr: not expr.has_key('gen'), exprs)
|
||||
|
||||
fdecl.write(guardstart("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
|
||||
for typename in builtin_types.keys():
|
||||
fdecl.write(generate_fwd_struct(typename, None, builtin_type=True))
|
||||
fdecl.write(generate_fwd_builtin(typename))
|
||||
fdecl.write(guardend("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
|
||||
|
||||
for expr in exprs:
|
||||
ret = "\n"
|
||||
if expr.has_key('struct'):
|
||||
ret += generate_fwd_struct(expr['struct'], expr['data'])
|
||||
ret += generate_fwd_struct(expr['struct'])
|
||||
elif expr.has_key('enum'):
|
||||
ret += generate_enum(expr['enum'], expr['data']) + "\n"
|
||||
ret += generate_fwd_enum_struct(expr['enum'], expr['data'])
|
||||
ret += generate_fwd_enum_struct(expr['enum'])
|
||||
fdef.write(generate_enum_lookup(expr['enum'], expr['data']))
|
||||
elif expr.has_key('union'):
|
||||
ret += generate_fwd_struct(expr['union'], expr['data']) + "\n"
|
||||
ret += generate_fwd_struct(expr['union']) + "\n"
|
||||
enum_define = discriminator_find_enum_define(expr)
|
||||
if not enum_define:
|
||||
ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
|
||||
fdef.write(generate_enum_lookup('%sKind' % expr['union'],
|
||||
expr['data'].keys()))
|
||||
elif expr.has_key('alternate'):
|
||||
ret += generate_fwd_struct(expr['alternate'], expr['data']) + "\n"
|
||||
ret += generate_fwd_struct(expr['alternate']) + "\n"
|
||||
ret += generate_enum('%sKind' % expr['alternate'], expr['data'].keys())
|
||||
fdef.write(generate_enum_lookup('%sKind' % expr['alternate'],
|
||||
expr['data'].keys()))
|
||||
|
||||
348
scripts/qapi.py
348
scripts/qapi.py
@@ -65,6 +65,10 @@ union_types = []
|
||||
events = []
|
||||
all_names = {}
|
||||
|
||||
#
|
||||
# Parsing the schema into expressions
|
||||
#
|
||||
|
||||
def error_path(parent):
|
||||
res = ""
|
||||
while parent:
|
||||
@@ -75,7 +79,7 @@ def error_path(parent):
|
||||
|
||||
class QAPISchemaError(Exception):
|
||||
def __init__(self, schema, msg):
|
||||
self.input_file = schema.input_file
|
||||
self.fname = schema.fname
|
||||
self.msg = msg
|
||||
self.col = 1
|
||||
self.line = schema.line
|
||||
@@ -84,11 +88,11 @@ class QAPISchemaError(Exception):
|
||||
self.col = (self.col + 7) % 8 + 1
|
||||
else:
|
||||
self.col += 1
|
||||
self.info = schema.parent_info
|
||||
self.info = schema.incl_info
|
||||
|
||||
def __str__(self):
|
||||
return error_path(self.info) + \
|
||||
"%s:%d:%d: %s" % (self.input_file, self.line, self.col, self.msg)
|
||||
"%s:%d:%d: %s" % (self.fname, self.line, self.col, self.msg)
|
||||
|
||||
class QAPIExprError(Exception):
|
||||
def __init__(self, expr_info, msg):
|
||||
@@ -101,19 +105,12 @@ class QAPIExprError(Exception):
|
||||
|
||||
class QAPISchema:
|
||||
|
||||
def __init__(self, fp, input_relname=None, include_hist=[],
|
||||
previously_included=[], parent_info=None):
|
||||
""" include_hist is a stack used to detect inclusion cycles
|
||||
previously_included is a global state used to avoid multiple
|
||||
inclusions of the same file"""
|
||||
input_fname = os.path.abspath(fp.name)
|
||||
if input_relname is None:
|
||||
input_relname = fp.name
|
||||
self.input_dir = os.path.dirname(input_fname)
|
||||
self.input_file = input_relname
|
||||
self.include_hist = include_hist + [(input_relname, input_fname)]
|
||||
previously_included.append(input_fname)
|
||||
self.parent_info = parent_info
|
||||
def __init__(self, fp, previously_included = [], incl_info = None):
|
||||
abs_fname = os.path.abspath(fp.name)
|
||||
fname = fp.name
|
||||
self.fname = fname
|
||||
previously_included.append(abs_fname)
|
||||
self.incl_info = incl_info
|
||||
self.src = fp.read()
|
||||
if self.src == '' or self.src[-1] != '\n':
|
||||
self.src += '\n'
|
||||
@@ -124,7 +121,8 @@ class QAPISchema:
|
||||
self.accept()
|
||||
|
||||
while self.tok != None:
|
||||
expr_info = {'file': input_relname, 'line': self.line, 'parent': self.parent_info}
|
||||
expr_info = {'file': fname, 'line': self.line,
|
||||
'parent': self.incl_info}
|
||||
expr = self.get_expr(False)
|
||||
if isinstance(expr, dict) and "include" in expr:
|
||||
if len(expr) != 1:
|
||||
@@ -134,21 +132,25 @@ class QAPISchema:
|
||||
raise QAPIExprError(expr_info,
|
||||
'Expected a file name (string), got: %s'
|
||||
% include)
|
||||
include_path = os.path.join(self.input_dir, include)
|
||||
for elem in self.include_hist:
|
||||
if include_path == elem[1]:
|
||||
incl_abs_fname = os.path.join(os.path.dirname(abs_fname),
|
||||
include)
|
||||
# catch inclusion cycle
|
||||
inf = expr_info
|
||||
while inf:
|
||||
if incl_abs_fname == os.path.abspath(inf['file']):
|
||||
raise QAPIExprError(expr_info, "Inclusion loop for %s"
|
||||
% include)
|
||||
inf = inf['parent']
|
||||
# skip multiple include of the same file
|
||||
if include_path in previously_included:
|
||||
if incl_abs_fname in previously_included:
|
||||
continue
|
||||
try:
|
||||
fobj = open(include_path, 'r')
|
||||
fobj = open(incl_abs_fname, 'r')
|
||||
except IOError, e:
|
||||
raise QAPIExprError(expr_info,
|
||||
'%s: %s' % (e.strerror, include))
|
||||
exprs_include = QAPISchema(fobj, include, self.include_hist,
|
||||
previously_included, expr_info)
|
||||
exprs_include = QAPISchema(fobj, previously_included,
|
||||
expr_info)
|
||||
self.exprs.extend(exprs_include.exprs)
|
||||
else:
|
||||
expr_elem = {'expr': expr,
|
||||
@@ -219,20 +221,18 @@ class QAPISchema:
|
||||
return
|
||||
else:
|
||||
string += ch
|
||||
elif self.tok in "tfn":
|
||||
val = self.src[self.cursor - 1:]
|
||||
if val.startswith("true"):
|
||||
self.val = True
|
||||
self.cursor += 3
|
||||
return
|
||||
elif val.startswith("false"):
|
||||
self.val = False
|
||||
self.cursor += 4
|
||||
return
|
||||
elif val.startswith("null"):
|
||||
self.val = None
|
||||
self.cursor += 3
|
||||
return
|
||||
elif self.src.startswith("true", self.pos):
|
||||
self.val = True
|
||||
self.cursor += 3
|
||||
return
|
||||
elif self.src.startswith("false", self.pos):
|
||||
self.val = False
|
||||
self.cursor += 4
|
||||
return
|
||||
elif self.src.startswith("null", self.pos):
|
||||
self.val = None
|
||||
self.cursor += 3
|
||||
return
|
||||
elif self.tok == '\n':
|
||||
if self.cursor == len(self.src):
|
||||
self.tok = None
|
||||
@@ -300,6 +300,10 @@ class QAPISchema:
|
||||
raise QAPISchemaError(self, 'Expected "{", "[" or string')
|
||||
return expr
|
||||
|
||||
#
|
||||
# Semantic analysis of schema expressions
|
||||
#
|
||||
|
||||
def find_base_fields(base):
|
||||
base_struct_define = find_struct(base)
|
||||
if not base_struct_define:
|
||||
@@ -360,6 +364,60 @@ def check_name(expr_info, source, name, allow_optional = False,
|
||||
raise QAPIExprError(expr_info,
|
||||
"%s uses invalid name '%s'" % (source, name))
|
||||
|
||||
def add_name(name, info, meta, implicit = False):
|
||||
global all_names
|
||||
check_name(info, "'%s'" % meta, name)
|
||||
if name in all_names:
|
||||
raise QAPIExprError(info,
|
||||
"%s '%s' is already defined"
|
||||
% (all_names[name], name))
|
||||
if not implicit and name[-4:] == 'Kind':
|
||||
raise QAPIExprError(info,
|
||||
"%s '%s' should not end in 'Kind'"
|
||||
% (meta, name))
|
||||
all_names[name] = meta
|
||||
|
||||
def add_struct(definition, info):
|
||||
global struct_types
|
||||
name = definition['struct']
|
||||
add_name(name, info, 'struct')
|
||||
struct_types.append(definition)
|
||||
|
||||
def find_struct(name):
|
||||
global struct_types
|
||||
for struct in struct_types:
|
||||
if struct['struct'] == name:
|
||||
return struct
|
||||
return None
|
||||
|
||||
def add_union(definition, info):
|
||||
global union_types
|
||||
name = definition['union']
|
||||
add_name(name, info, 'union')
|
||||
union_types.append(definition)
|
||||
|
||||
def find_union(name):
|
||||
global union_types
|
||||
for union in union_types:
|
||||
if union['union'] == name:
|
||||
return union
|
||||
return None
|
||||
|
||||
def add_enum(name, info, enum_values = None, implicit = False):
|
||||
global enum_types
|
||||
add_name(name, info, 'enum', implicit)
|
||||
enum_types.append({"enum_name": name, "enum_values": enum_values})
|
||||
|
||||
def find_enum(name):
|
||||
global enum_types
|
||||
for enum in enum_types:
|
||||
if enum['enum_name'] == name:
|
||||
return enum
|
||||
return None
|
||||
|
||||
def is_enum(name):
|
||||
return find_enum(name) != None
|
||||
|
||||
def check_type(expr_info, source, value, allow_array = False,
|
||||
allow_dict = False, allow_optional = False,
|
||||
allow_star = False, allow_metas = []):
|
||||
@@ -522,7 +580,7 @@ def check_union(expr, expr_info):
|
||||
# Each value must name a known type; furthermore, in flat unions,
|
||||
# branches must be a struct with no overlapping member names
|
||||
check_type(expr_info, "Member '%s' of union '%s'" % (key, name),
|
||||
value, allow_array=True, allow_metas=allow_metas)
|
||||
value, allow_array=not base, allow_metas=allow_metas)
|
||||
if base:
|
||||
branch_struct = find_struct(value)
|
||||
assert branch_struct
|
||||
@@ -607,26 +665,6 @@ def check_struct(expr, expr_info):
|
||||
if expr.get('base'):
|
||||
check_member_clash(expr_info, expr['base'], expr['data'])
|
||||
|
||||
def check_exprs(schema):
|
||||
for expr_elem in schema.exprs:
|
||||
expr = expr_elem['expr']
|
||||
info = expr_elem['info']
|
||||
|
||||
if expr.has_key('enum'):
|
||||
check_enum(expr, info)
|
||||
elif expr.has_key('union'):
|
||||
check_union(expr, info)
|
||||
elif expr.has_key('alternate'):
|
||||
check_alternate(expr, info)
|
||||
elif expr.has_key('struct'):
|
||||
check_struct(expr, info)
|
||||
elif expr.has_key('command'):
|
||||
check_command(expr, info)
|
||||
elif expr.has_key('event'):
|
||||
check_event(expr, info)
|
||||
else:
|
||||
assert False, 'unexpected meta type'
|
||||
|
||||
def check_keys(expr_elem, meta, required, optional=[]):
|
||||
expr = expr_elem['expr']
|
||||
info = expr_elem['info']
|
||||
@@ -650,69 +688,83 @@ def check_keys(expr_elem, meta, required, optional=[]):
|
||||
"Key '%s' is missing from %s '%s'"
|
||||
% (key, meta, name))
|
||||
|
||||
|
||||
def parse_schema(input_file):
|
||||
def check_exprs(exprs):
|
||||
global all_names
|
||||
exprs = []
|
||||
|
||||
# First pass: read entire file into memory
|
||||
# Learn the types and check for valid expression keys
|
||||
for builtin in builtin_types.keys():
|
||||
all_names[builtin] = 'built-in'
|
||||
for expr_elem in exprs:
|
||||
expr = expr_elem['expr']
|
||||
info = expr_elem['info']
|
||||
if expr.has_key('enum'):
|
||||
check_keys(expr_elem, 'enum', ['data'])
|
||||
add_enum(expr['enum'], info, expr['data'])
|
||||
elif expr.has_key('union'):
|
||||
check_keys(expr_elem, 'union', ['data'],
|
||||
['base', 'discriminator'])
|
||||
add_union(expr, info)
|
||||
elif expr.has_key('alternate'):
|
||||
check_keys(expr_elem, 'alternate', ['data'])
|
||||
add_name(expr['alternate'], info, 'alternate')
|
||||
elif expr.has_key('struct'):
|
||||
check_keys(expr_elem, 'struct', ['data'], ['base'])
|
||||
add_struct(expr, info)
|
||||
elif expr.has_key('command'):
|
||||
check_keys(expr_elem, 'command', [],
|
||||
['data', 'returns', 'gen', 'success-response'])
|
||||
add_name(expr['command'], info, 'command')
|
||||
elif expr.has_key('event'):
|
||||
check_keys(expr_elem, 'event', [], ['data'])
|
||||
add_name(expr['event'], info, 'event')
|
||||
else:
|
||||
raise QAPIExprError(expr_elem['info'],
|
||||
"Expression is missing metatype")
|
||||
|
||||
# Try again for hidden UnionKind enum
|
||||
for expr_elem in exprs:
|
||||
expr = expr_elem['expr']
|
||||
if expr.has_key('union'):
|
||||
if not discriminator_find_enum_define(expr):
|
||||
add_enum('%sKind' % expr['union'], expr_elem['info'],
|
||||
implicit=True)
|
||||
elif expr.has_key('alternate'):
|
||||
add_enum('%sKind' % expr['alternate'], expr_elem['info'],
|
||||
implicit=True)
|
||||
|
||||
# Validate that exprs make sense
|
||||
for expr_elem in exprs:
|
||||
expr = expr_elem['expr']
|
||||
info = expr_elem['info']
|
||||
|
||||
if expr.has_key('enum'):
|
||||
check_enum(expr, info)
|
||||
elif expr.has_key('union'):
|
||||
check_union(expr, info)
|
||||
elif expr.has_key('alternate'):
|
||||
check_alternate(expr, info)
|
||||
elif expr.has_key('struct'):
|
||||
check_struct(expr, info)
|
||||
elif expr.has_key('command'):
|
||||
check_command(expr, info)
|
||||
elif expr.has_key('event'):
|
||||
check_event(expr, info)
|
||||
else:
|
||||
assert False, 'unexpected meta type'
|
||||
|
||||
return map(lambda expr_elem: expr_elem['expr'], exprs)
|
||||
|
||||
def parse_schema(fname):
|
||||
try:
|
||||
schema = QAPISchema(open(input_file, "r"))
|
||||
schema = QAPISchema(open(fname, "r"))
|
||||
return check_exprs(schema.exprs)
|
||||
except (QAPISchemaError, QAPIExprError), e:
|
||||
print >>sys.stderr, e
|
||||
exit(1)
|
||||
|
||||
try:
|
||||
# Next pass: learn the types and check for valid expression keys. At
|
||||
# this point, top-level 'include' has already been flattened.
|
||||
for builtin in builtin_types.keys():
|
||||
all_names[builtin] = 'built-in'
|
||||
for expr_elem in schema.exprs:
|
||||
expr = expr_elem['expr']
|
||||
info = expr_elem['info']
|
||||
if expr.has_key('enum'):
|
||||
check_keys(expr_elem, 'enum', ['data'])
|
||||
add_enum(expr['enum'], info, expr['data'])
|
||||
elif expr.has_key('union'):
|
||||
check_keys(expr_elem, 'union', ['data'],
|
||||
['base', 'discriminator'])
|
||||
add_union(expr, info)
|
||||
elif expr.has_key('alternate'):
|
||||
check_keys(expr_elem, 'alternate', ['data'])
|
||||
add_name(expr['alternate'], info, 'alternate')
|
||||
elif expr.has_key('struct'):
|
||||
check_keys(expr_elem, 'struct', ['data'], ['base'])
|
||||
add_struct(expr, info)
|
||||
elif expr.has_key('command'):
|
||||
check_keys(expr_elem, 'command', [],
|
||||
['data', 'returns', 'gen', 'success-response'])
|
||||
add_name(expr['command'], info, 'command')
|
||||
elif expr.has_key('event'):
|
||||
check_keys(expr_elem, 'event', [], ['data'])
|
||||
add_name(expr['event'], info, 'event')
|
||||
else:
|
||||
raise QAPIExprError(expr_elem['info'],
|
||||
"Expression is missing metatype")
|
||||
exprs.append(expr)
|
||||
|
||||
# Try again for hidden UnionKind enum
|
||||
for expr_elem in schema.exprs:
|
||||
expr = expr_elem['expr']
|
||||
if expr.has_key('union'):
|
||||
if not discriminator_find_enum_define(expr):
|
||||
add_enum('%sKind' % expr['union'], expr_elem['info'],
|
||||
implicit=True)
|
||||
elif expr.has_key('alternate'):
|
||||
add_enum('%sKind' % expr['alternate'], expr_elem['info'],
|
||||
implicit=True)
|
||||
|
||||
# Final pass - validate that exprs make sense
|
||||
check_exprs(schema)
|
||||
except QAPIExprError, e:
|
||||
print >>sys.stderr, e
|
||||
exit(1)
|
||||
|
||||
return exprs
|
||||
#
|
||||
# Code generation helpers
|
||||
#
|
||||
|
||||
def parse_args(typeinfo):
|
||||
if isinstance(typeinfo, str):
|
||||
@@ -831,60 +883,6 @@ def type_name(value):
|
||||
return value
|
||||
return c_name(value)
|
||||
|
||||
def add_name(name, info, meta, implicit = False):
|
||||
global all_names
|
||||
check_name(info, "'%s'" % meta, name)
|
||||
if name in all_names:
|
||||
raise QAPIExprError(info,
|
||||
"%s '%s' is already defined"
|
||||
% (all_names[name], name))
|
||||
if not implicit and name[-4:] == 'Kind':
|
||||
raise QAPIExprError(info,
|
||||
"%s '%s' should not end in 'Kind'"
|
||||
% (meta, name))
|
||||
all_names[name] = meta
|
||||
|
||||
def add_struct(definition, info):
|
||||
global struct_types
|
||||
name = definition['struct']
|
||||
add_name(name, info, 'struct')
|
||||
struct_types.append(definition)
|
||||
|
||||
def find_struct(name):
|
||||
global struct_types
|
||||
for struct in struct_types:
|
||||
if struct['struct'] == name:
|
||||
return struct
|
||||
return None
|
||||
|
||||
def add_union(definition, info):
|
||||
global union_types
|
||||
name = definition['union']
|
||||
add_name(name, info, 'union')
|
||||
union_types.append(definition)
|
||||
|
||||
def find_union(name):
|
||||
global union_types
|
||||
for union in union_types:
|
||||
if union['union'] == name:
|
||||
return union
|
||||
return None
|
||||
|
||||
def add_enum(name, info, enum_values = None, implicit = False):
|
||||
global enum_types
|
||||
add_name(name, info, 'enum', implicit)
|
||||
enum_types.append({"enum_name": name, "enum_values": enum_values})
|
||||
|
||||
def find_enum(name):
|
||||
global enum_types
|
||||
for enum in enum_types:
|
||||
if enum['enum_name'] == name:
|
||||
return enum
|
||||
return None
|
||||
|
||||
def is_enum(name):
|
||||
return find_enum(name) != None
|
||||
|
||||
eatspace = '\033EATSPACE.'
|
||||
pointer_suffix = ' *' + eatspace
|
||||
|
||||
@@ -981,6 +979,10 @@ def guardend(name):
|
||||
''',
|
||||
name=guardname(name))
|
||||
|
||||
#
|
||||
# Common command line parsing
|
||||
#
|
||||
|
||||
def parse_command_line(extra_options = "", extra_long_options = []):
|
||||
|
||||
try:
|
||||
@@ -1018,9 +1020,13 @@ def parse_command_line(extra_options = "", extra_long_options = []):
|
||||
if len(args) != 1:
|
||||
print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
|
||||
sys.exit(1)
|
||||
input_file = args[0]
|
||||
fname = args[0]
|
||||
|
||||
return (input_file, output_dir, do_c, do_h, prefix, extra_opts)
|
||||
return (fname, output_dir, do_c, do_h, prefix, extra_opts)
|
||||
|
||||
#
|
||||
# Generate output files with boilerplate
|
||||
#
|
||||
|
||||
def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
|
||||
c_comment, h_comment):
|
||||
|
||||
@@ -65,6 +65,11 @@ def list_node(path):
|
||||
print ''
|
||||
for item in items:
|
||||
if item['type'].startswith('child<'):
|
||||
list_node(path + '/' + item['name'])
|
||||
list_node((path if (path != '/') else '') + '/' + item['name'])
|
||||
|
||||
list_node('/machine')
|
||||
if len(args) == 0:
|
||||
path = '/'
|
||||
else:
|
||||
path = args[0]
|
||||
|
||||
list_node(path)
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <time.h>
|
||||
|
||||
#include "cpu.h"
|
||||
#include "exec/semihost.h"
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
#include "qemu.h"
|
||||
|
||||
@@ -440,10 +441,7 @@ uint32_t do_arm_semihosting(CPUARMState *env)
|
||||
input_size = arg1;
|
||||
/* Compute the size of the output string. */
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
output_size = strlen(ts->boot_info->kernel_filename)
|
||||
+ 1 /* Separating space. */
|
||||
+ strlen(ts->boot_info->kernel_cmdline)
|
||||
+ 1; /* Terminating null byte. */
|
||||
output_size = strlen(semihosting_get_cmdline()) + 1;
|
||||
#else
|
||||
unsigned int i;
|
||||
|
||||
@@ -474,9 +472,7 @@ uint32_t do_arm_semihosting(CPUARMState *env)
|
||||
|
||||
/* Copy the command-line arguments. */
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
pstrcpy(output_buffer, output_size, ts->boot_info->kernel_filename);
|
||||
pstrcat(output_buffer, output_size, " ");
|
||||
pstrcat(output_buffer, output_size, ts->boot_info->kernel_cmdline);
|
||||
pstrcpy(output_buffer, output_size, semihosting_get_cmdline());
|
||||
#else
|
||||
if (output_size == 1) {
|
||||
/* Empty command-line. */
|
||||
|
||||
@@ -105,6 +105,8 @@ typedef struct ARMCPU {
|
||||
|
||||
/* CPU has memory protection unit */
|
||||
bool has_mpu;
|
||||
/* PMSAv7 MPU number of supported regions */
|
||||
uint32_t pmsav7_dregion;
|
||||
|
||||
/* PSCI conduit used to invoke PSCI methods
|
||||
* 0 - disabled, 1 - smc, 2 - hvc
|
||||
|
||||
@@ -55,7 +55,7 @@ static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque)
|
||||
ARMCPRegInfo *ri = value;
|
||||
ARMCPU *cpu = opaque;
|
||||
|
||||
if (ri->type & ARM_CP_SPECIAL) {
|
||||
if (ri->type & (ARM_CP_SPECIAL | ARM_CP_ALIAS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -457,6 +457,9 @@ static Property arm_cpu_has_el3_property =
|
||||
static Property arm_cpu_has_mpu_property =
|
||||
DEFINE_PROP_BOOL("has-mpu", ARMCPU, has_mpu, true);
|
||||
|
||||
static Property arm_cpu_pmsav7_dregion_property =
|
||||
DEFINE_PROP_UINT32("pmsav7-dregion", ARMCPU, pmsav7_dregion, 16);
|
||||
|
||||
static void arm_cpu_post_init(Object *obj)
|
||||
{
|
||||
ARMCPU *cpu = ARM_CPU(obj);
|
||||
@@ -488,6 +491,11 @@ static void arm_cpu_post_init(Object *obj)
|
||||
if (arm_feature(&cpu->env, ARM_FEATURE_MPU)) {
|
||||
qdev_property_add_static(DEVICE(obj), &arm_cpu_has_mpu_property,
|
||||
&error_abort);
|
||||
if (arm_feature(&cpu->env, ARM_FEATURE_V7)) {
|
||||
qdev_property_add_static(DEVICE(obj),
|
||||
&arm_cpu_pmsav7_dregion_property,
|
||||
&error_abort);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -580,6 +588,22 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
|
||||
unset_feature(env, ARM_FEATURE_MPU);
|
||||
}
|
||||
|
||||
if (arm_feature(env, ARM_FEATURE_MPU) &&
|
||||
arm_feature(env, ARM_FEATURE_V7)) {
|
||||
uint32_t nr = cpu->pmsav7_dregion;
|
||||
|
||||
if (nr > 0xff) {
|
||||
error_setg(errp, "PMSAv7 MPU #regions invalid %" PRIu32 "\n", nr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nr) {
|
||||
env->pmsav7.drbar = g_new0(uint32_t, nr);
|
||||
env->pmsav7.drsr = g_new0(uint32_t, nr);
|
||||
env->pmsav7.dracr = g_new0(uint32_t, nr);
|
||||
}
|
||||
}
|
||||
|
||||
register_cp_regs_for_features(cpu);
|
||||
arm_cpu_register_gdb_regs_for_features(cpu);
|
||||
|
||||
@@ -812,6 +836,15 @@ static void cortex_m3_initfn(Object *obj)
|
||||
cpu->midr = 0x410fc231;
|
||||
}
|
||||
|
||||
static void cortex_m4_initfn(Object *obj)
|
||||
{
|
||||
ARMCPU *cpu = ARM_CPU(obj);
|
||||
|
||||
set_feature(&cpu->env, ARM_FEATURE_V7);
|
||||
set_feature(&cpu->env, ARM_FEATURE_M);
|
||||
set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP);
|
||||
cpu->midr = 0x410fc240; /* r0p0 */
|
||||
}
|
||||
static void arm_v7m_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
CPUClass *cc = CPU_CLASS(oc);
|
||||
@@ -823,6 +856,43 @@ static void arm_v7m_class_init(ObjectClass *oc, void *data)
|
||||
cc->cpu_exec_interrupt = arm_v7m_cpu_exec_interrupt;
|
||||
}
|
||||
|
||||
static const ARMCPRegInfo cortexr5_cp_reginfo[] = {
|
||||
/* Dummy the TCM region regs for the moment */
|
||||
{ .name = "ATCM", .cp = 15, .opc1 = 0, .crn = 9, .crm = 1, .opc2 = 0,
|
||||
.access = PL1_RW, .type = ARM_CP_CONST },
|
||||
{ .name = "BTCM", .cp = 15, .opc1 = 0, .crn = 9, .crm = 1, .opc2 = 1,
|
||||
.access = PL1_RW, .type = ARM_CP_CONST },
|
||||
REGINFO_SENTINEL
|
||||
};
|
||||
|
||||
static void cortex_r5_initfn(Object *obj)
|
||||
{
|
||||
ARMCPU *cpu = ARM_CPU(obj);
|
||||
|
||||
set_feature(&cpu->env, ARM_FEATURE_V7);
|
||||
set_feature(&cpu->env, ARM_FEATURE_THUMB_DIV);
|
||||
set_feature(&cpu->env, ARM_FEATURE_ARM_DIV);
|
||||
set_feature(&cpu->env, ARM_FEATURE_V7MP);
|
||||
set_feature(&cpu->env, ARM_FEATURE_MPU);
|
||||
cpu->midr = 0x411fc153; /* r1p3 */
|
||||
cpu->id_pfr0 = 0x0131;
|
||||
cpu->id_pfr1 = 0x001;
|
||||
cpu->id_dfr0 = 0x010400;
|
||||
cpu->id_afr0 = 0x0;
|
||||
cpu->id_mmfr0 = 0x0210030;
|
||||
cpu->id_mmfr1 = 0x00000000;
|
||||
cpu->id_mmfr2 = 0x01200000;
|
||||
cpu->id_mmfr3 = 0x0211;
|
||||
cpu->id_isar0 = 0x2101111;
|
||||
cpu->id_isar1 = 0x13112111;
|
||||
cpu->id_isar2 = 0x21232141;
|
||||
cpu->id_isar3 = 0x01112131;
|
||||
cpu->id_isar4 = 0x0010142;
|
||||
cpu->id_isar5 = 0x0;
|
||||
cpu->mp_is_up = true;
|
||||
define_arm_cp_regs(cpu, cortexr5_cp_reginfo);
|
||||
}
|
||||
|
||||
static const ARMCPRegInfo cortexa8_cp_reginfo[] = {
|
||||
{ .name = "L2LOCKDOWN", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 0,
|
||||
.access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
|
||||
@@ -1214,6 +1284,9 @@ static const ARMCPUInfo arm_cpus[] = {
|
||||
{ .name = "arm11mpcore", .initfn = arm11mpcore_initfn },
|
||||
{ .name = "cortex-m3", .initfn = cortex_m3_initfn,
|
||||
.class_init = arm_v7m_class_init },
|
||||
{ .name = "cortex-m4", .initfn = cortex_m4_initfn,
|
||||
.class_init = arm_v7m_class_init },
|
||||
{ .name = "cortex-r5", .initfn = cortex_r5_initfn },
|
||||
{ .name = "cortex-a8", .initfn = cortex_a8_initfn },
|
||||
{ .name = "cortex-a9", .initfn = cortex_a9_initfn },
|
||||
{ .name = "cortex-a15", .initfn = cortex_a15_initfn },
|
||||
|
||||
@@ -284,6 +284,9 @@ typedef struct CPUARMState {
|
||||
};
|
||||
uint64_t par_el[4];
|
||||
};
|
||||
|
||||
uint32_t c6_rgnr;
|
||||
|
||||
uint32_t c9_insn; /* Cache lockdown registers. */
|
||||
uint32_t c9_data;
|
||||
uint64_t c9_pmcr; /* performance monitor control register */
|
||||
@@ -482,6 +485,13 @@ typedef struct CPUARMState {
|
||||
/* Internal CPU feature flags. */
|
||||
uint64_t features;
|
||||
|
||||
/* PMSAv7 MPU */
|
||||
struct {
|
||||
uint32_t *drbar;
|
||||
uint32_t *drsr;
|
||||
uint32_t *dracr;
|
||||
} pmsav7;
|
||||
|
||||
void *nvic;
|
||||
const struct arm_boot_info *boot_info;
|
||||
} CPUARMState;
|
||||
@@ -550,6 +560,7 @@ void pmccntr_sync(CPUARMState *env);
|
||||
#define SCTLR_DT (1U << 16) /* up to ??, RAO in v6 and v7 */
|
||||
#define SCTLR_nTWI (1U << 16) /* v8 onward */
|
||||
#define SCTLR_HA (1U << 17)
|
||||
#define SCTLR_BR (1U << 17) /* PMSA only */
|
||||
#define SCTLR_IT (1U << 18) /* up to ??, RAO in v6 and v7 */
|
||||
#define SCTLR_nTWE (1U << 18) /* v8 onward */
|
||||
#define SCTLR_WXN (1U << 19)
|
||||
@@ -1116,8 +1127,8 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
|
||||
* old must have the OVERRIDE bit set.
|
||||
* ALIAS indicates that this register is an alias view of some underlying
|
||||
* state which is also visible via another register, and that the other
|
||||
* register is handling migration; registers marked ALIAS will not be migrated
|
||||
* but may have their state set by syncing of register state from KVM.
|
||||
* register is handling migration and reset; registers marked ALIAS will not be
|
||||
* migrated but may have their state set by syncing of register state from KVM.
|
||||
* NO_RAW indicates that this register has no underlying state and does not
|
||||
* support raw access for state saving/loading; it will not be used for either
|
||||
* migration or KVM state synchronization. (Typically this is for "registers"
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "arm_ldst.h"
|
||||
#include <zlib.h> /* For crc32 */
|
||||
#include "exec/semihost.h"
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
static inline bool get_phys_addr(CPUARMState *env, target_ulong address,
|
||||
@@ -984,7 +985,7 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
|
||||
{ .name = "PMINTENCLR", .cp = 15, .crn = 9, .crm = 14, .opc1 = 0, .opc2 = 2,
|
||||
.access = PL1_RW, .type = ARM_CP_ALIAS,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.c9_pminten),
|
||||
.resetvalue = 0, .writefn = pmintenclr_write, },
|
||||
.writefn = pmintenclr_write, },
|
||||
{ .name = "VBAR", .state = ARM_CP_STATE_BOTH,
|
||||
.opc0 = 3, .crn = 12, .crm = 0, .opc1 = 0, .opc2 = 0,
|
||||
.access = PL1_RW, .writefn = vbar_write,
|
||||
@@ -1323,7 +1324,6 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
|
||||
.type = ARM_CP_ALIAS,
|
||||
.access = PL1_RW | PL0_R, .accessfn = gt_cntfrq_access,
|
||||
.fieldoffset = offsetoflow32(CPUARMState, cp15.c14_cntfrq),
|
||||
.resetfn = arm_cp_reset_ignore,
|
||||
},
|
||||
{ .name = "CNTFRQ_EL0", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 0,
|
||||
@@ -1344,7 +1344,6 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
|
||||
.accessfn = gt_ptimer_access,
|
||||
.fieldoffset = offsetoflow32(CPUARMState,
|
||||
cp15.c14_timer[GTIMER_PHYS].ctl),
|
||||
.resetfn = arm_cp_reset_ignore,
|
||||
.writefn = gt_ctl_write, .raw_writefn = raw_write,
|
||||
},
|
||||
{ .name = "CNTP_CTL_EL0", .state = ARM_CP_STATE_AA64,
|
||||
@@ -1360,7 +1359,6 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
|
||||
.accessfn = gt_vtimer_access,
|
||||
.fieldoffset = offsetoflow32(CPUARMState,
|
||||
cp15.c14_timer[GTIMER_VIRT].ctl),
|
||||
.resetfn = arm_cp_reset_ignore,
|
||||
.writefn = gt_ctl_write, .raw_writefn = raw_write,
|
||||
},
|
||||
{ .name = "CNTV_CTL_EL0", .state = ARM_CP_STATE_AA64,
|
||||
@@ -1422,7 +1420,7 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
|
||||
.access = PL1_RW | PL0_R,
|
||||
.type = ARM_CP_64BIT | ARM_CP_IO | ARM_CP_ALIAS,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].cval),
|
||||
.accessfn = gt_ptimer_access, .resetfn = arm_cp_reset_ignore,
|
||||
.accessfn = gt_ptimer_access,
|
||||
.writefn = gt_cval_write, .raw_writefn = raw_write,
|
||||
},
|
||||
{ .name = "CNTP_CVAL_EL0", .state = ARM_CP_STATE_AA64,
|
||||
@@ -1437,7 +1435,7 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
|
||||
.access = PL1_RW | PL0_R,
|
||||
.type = ARM_CP_64BIT | ARM_CP_IO | ARM_CP_ALIAS,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].cval),
|
||||
.accessfn = gt_vtimer_access, .resetfn = arm_cp_reset_ignore,
|
||||
.accessfn = gt_vtimer_access,
|
||||
.writefn = gt_cval_write, .raw_writefn = raw_write,
|
||||
},
|
||||
{ .name = "CNTV_CVAL_EL0", .state = ARM_CP_STATE_AA64,
|
||||
@@ -1710,16 +1708,89 @@ static uint64_t pmsav5_insn_ap_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
return simple_mpu_ap_bits(env->cp15.pmsav5_insn_ap);
|
||||
}
|
||||
|
||||
static uint64_t pmsav7_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
uint32_t *u32p = *(uint32_t **)raw_ptr(env, ri);
|
||||
|
||||
if (!u32p) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32p += env->cp15.c6_rgnr;
|
||||
return *u32p;
|
||||
}
|
||||
|
||||
static void pmsav7_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
ARMCPU *cpu = arm_env_get_cpu(env);
|
||||
uint32_t *u32p = *(uint32_t **)raw_ptr(env, ri);
|
||||
|
||||
if (!u32p) {
|
||||
return;
|
||||
}
|
||||
|
||||
u32p += env->cp15.c6_rgnr;
|
||||
tlb_flush(CPU(cpu), 1); /* Mappings may have changed - purge! */
|
||||
*u32p = value;
|
||||
}
|
||||
|
||||
static void pmsav7_reset(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
ARMCPU *cpu = arm_env_get_cpu(env);
|
||||
uint32_t *u32p = *(uint32_t **)raw_ptr(env, ri);
|
||||
|
||||
if (!u32p) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset(u32p, 0, sizeof(*u32p) * cpu->pmsav7_dregion);
|
||||
}
|
||||
|
||||
static void pmsav7_rgnr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
ARMCPU *cpu = arm_env_get_cpu(env);
|
||||
uint32_t nrgs = cpu->pmsav7_dregion;
|
||||
|
||||
if (value >= nrgs) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"PMSAv7 RGNR write >= # supported regions, %" PRIu32
|
||||
" > %" PRIu32 "\n", (uint32_t)value, nrgs);
|
||||
return;
|
||||
}
|
||||
|
||||
raw_write(env, ri, value);
|
||||
}
|
||||
|
||||
static const ARMCPRegInfo pmsav7_cp_reginfo[] = {
|
||||
{ .name = "DRBAR", .cp = 15, .crn = 6, .opc1 = 0, .crm = 1, .opc2 = 0,
|
||||
.access = PL1_RW, .type = ARM_CP_NO_RAW,
|
||||
.fieldoffset = offsetof(CPUARMState, pmsav7.drbar),
|
||||
.readfn = pmsav7_read, .writefn = pmsav7_write, .resetfn = pmsav7_reset },
|
||||
{ .name = "DRSR", .cp = 15, .crn = 6, .opc1 = 0, .crm = 1, .opc2 = 2,
|
||||
.access = PL1_RW, .type = ARM_CP_NO_RAW,
|
||||
.fieldoffset = offsetof(CPUARMState, pmsav7.drsr),
|
||||
.readfn = pmsav7_read, .writefn = pmsav7_write, .resetfn = pmsav7_reset },
|
||||
{ .name = "DRACR", .cp = 15, .crn = 6, .opc1 = 0, .crm = 1, .opc2 = 4,
|
||||
.access = PL1_RW, .type = ARM_CP_NO_RAW,
|
||||
.fieldoffset = offsetof(CPUARMState, pmsav7.dracr),
|
||||
.readfn = pmsav7_read, .writefn = pmsav7_write, .resetfn = pmsav7_reset },
|
||||
{ .name = "RGNR", .cp = 15, .crn = 6, .opc1 = 0, .crm = 2, .opc2 = 0,
|
||||
.access = PL1_RW,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.c6_rgnr),
|
||||
.writefn = pmsav7_rgnr_write },
|
||||
REGINFO_SENTINEL
|
||||
};
|
||||
|
||||
static const ARMCPRegInfo pmsav5_cp_reginfo[] = {
|
||||
{ .name = "DATA_AP", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 0,
|
||||
.access = PL1_RW, .type = ARM_CP_ALIAS,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.pmsav5_data_ap),
|
||||
.resetvalue = 0,
|
||||
.readfn = pmsav5_data_ap_read, .writefn = pmsav5_data_ap_write, },
|
||||
{ .name = "INSN_AP", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 1,
|
||||
.access = PL1_RW, .type = ARM_CP_ALIAS,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.pmsav5_insn_ap),
|
||||
.resetvalue = 0,
|
||||
.readfn = pmsav5_insn_ap_read, .writefn = pmsav5_insn_ap_write, },
|
||||
{ .name = "DATA_EXT_AP", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 2,
|
||||
.access = PL1_RW,
|
||||
@@ -1851,8 +1922,7 @@ static const ARMCPRegInfo vmsa_pmsa_cp_reginfo[] = {
|
||||
{ .name = "DFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 0,
|
||||
.access = PL1_RW, .type = ARM_CP_ALIAS,
|
||||
.bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.dfsr_s),
|
||||
offsetoflow32(CPUARMState, cp15.dfsr_ns) },
|
||||
.resetfn = arm_cp_reset_ignore, },
|
||||
offsetoflow32(CPUARMState, cp15.dfsr_ns) }, },
|
||||
{ .name = "IFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 1,
|
||||
.access = PL1_RW, .resetvalue = 0,
|
||||
.bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.ifsr_s),
|
||||
@@ -1890,7 +1960,7 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = {
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.tcr_el[1]) },
|
||||
{ .name = "TTBCR", .cp = 15, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 2,
|
||||
.access = PL1_RW, .type = ARM_CP_ALIAS, .writefn = vmsa_ttbcr_write,
|
||||
.resetfn = arm_cp_reset_ignore, .raw_writefn = vmsa_ttbcr_raw_write,
|
||||
.raw_writefn = vmsa_ttbcr_raw_write,
|
||||
.bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.tcr_el[3]),
|
||||
offsetoflow32(CPUARMState, cp15.tcr_el[1])} },
|
||||
REGINFO_SENTINEL
|
||||
@@ -2109,12 +2179,12 @@ static const ARMCPRegInfo lpae_cp_reginfo[] = {
|
||||
.access = PL1_RW, .type = ARM_CP_64BIT | ARM_CP_ALIAS,
|
||||
.bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr0_s),
|
||||
offsetof(CPUARMState, cp15.ttbr0_ns) },
|
||||
.writefn = vmsa_ttbr_write, .resetfn = arm_cp_reset_ignore },
|
||||
.writefn = vmsa_ttbr_write, },
|
||||
{ .name = "TTBR1", .cp = 15, .crm = 2, .opc1 = 1,
|
||||
.access = PL1_RW, .type = ARM_CP_64BIT | ARM_CP_ALIAS,
|
||||
.bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr1_s),
|
||||
offsetof(CPUARMState, cp15.ttbr1_ns) },
|
||||
.writefn = vmsa_ttbr_write, .resetfn = arm_cp_reset_ignore },
|
||||
.writefn = vmsa_ttbr_write, },
|
||||
REGINFO_SENTINEL
|
||||
};
|
||||
|
||||
@@ -2641,7 +2711,6 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el[2]) },
|
||||
{ .name = "HTTBR", .cp = 15, .opc1 = 4, .crm = 2,
|
||||
.access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_ALIAS,
|
||||
.resetvalue = 0,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el[2]) },
|
||||
{ .name = "TLBI_ALLE2", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 0,
|
||||
@@ -2666,7 +2735,7 @@ static const ARMCPRegInfo el3_cp_reginfo[] = {
|
||||
{ .name = "SCR", .type = ARM_CP_ALIAS,
|
||||
.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 },
|
||||
.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,
|
||||
@@ -2761,8 +2830,7 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
|
||||
.cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 0,
|
||||
.type = ARM_CP_ALIAS,
|
||||
.access = PL1_R,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.mdscr_el1),
|
||||
.resetfn = arm_cp_reset_ignore },
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.mdscr_el1), },
|
||||
/* We define a dummy WI OSLAR_EL1, because Linux writes to it. */
|
||||
{ .name = "OSLAR_EL1", .state = ARM_CP_STATE_BOTH,
|
||||
.cp = 14, .opc0 = 2, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 4,
|
||||
@@ -3345,13 +3413,14 @@ void register_cp_regs_for_features(ARMCPU *cpu)
|
||||
define_one_arm_cp_reg(cpu, &rvbar);
|
||||
}
|
||||
if (arm_feature(env, ARM_FEATURE_MPU)) {
|
||||
/* These are the MPU registers prior to PMSAv6. Any new
|
||||
* PMSA core later than the ARM946 will require that we
|
||||
* implement the PMSAv6 or PMSAv7 registers, which are
|
||||
* completely different.
|
||||
*/
|
||||
assert(!arm_feature(env, ARM_FEATURE_V6));
|
||||
define_arm_cp_regs(cpu, pmsav5_cp_reginfo);
|
||||
if (arm_feature(env, ARM_FEATURE_V6)) {
|
||||
/* PMSAv6 not implemented */
|
||||
assert(arm_feature(env, ARM_FEATURE_V7));
|
||||
define_arm_cp_regs(cpu, vmsa_pmsa_cp_reginfo);
|
||||
define_arm_cp_regs(cpu, pmsav7_cp_reginfo);
|
||||
} else {
|
||||
define_arm_cp_regs(cpu, pmsav5_cp_reginfo);
|
||||
}
|
||||
} else {
|
||||
define_arm_cp_regs(cpu, vmsa_pmsa_cp_reginfo);
|
||||
define_arm_cp_regs(cpu, vmsa_cp_reginfo);
|
||||
@@ -3465,6 +3534,13 @@ void register_cp_regs_for_features(ARMCPU *cpu)
|
||||
.cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 3,
|
||||
.access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0,
|
||||
};
|
||||
/* MPUIR is specific to PMSA V6+ */
|
||||
ARMCPRegInfo id_mpuir_reginfo = {
|
||||
.name = "MPUIR",
|
||||
.cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 4,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = cpu->pmsav7_dregion << 8
|
||||
};
|
||||
ARMCPRegInfo crn0_wi_reginfo = {
|
||||
.name = "CRN0_WI", .cp = 15, .crn = 0, .crm = CP_ANY,
|
||||
.opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_W,
|
||||
@@ -3487,6 +3563,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
|
||||
r->access = PL1_RW;
|
||||
}
|
||||
id_tlbtr_reginfo.access = PL1_RW;
|
||||
id_tlbtr_reginfo.access = PL1_RW;
|
||||
}
|
||||
if (arm_feature(env, ARM_FEATURE_V8)) {
|
||||
define_arm_cp_regs(cpu, id_v8_midr_cp_reginfo);
|
||||
@@ -3496,6 +3573,8 @@ void register_cp_regs_for_features(ARMCPU *cpu)
|
||||
define_arm_cp_regs(cpu, id_cp_reginfo);
|
||||
if (!arm_feature(env, ARM_FEATURE_MPU)) {
|
||||
define_one_arm_cp_reg(cpu, &id_tlbtr_reginfo);
|
||||
} else if (arm_feature(env, ARM_FEATURE_V7)) {
|
||||
define_one_arm_cp_reg(cpu, &id_mpuir_reginfo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3721,14 +3800,12 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
|
||||
if ((r->state == ARM_CP_STATE_BOTH && ns) ||
|
||||
(arm_feature(&cpu->env, ARM_FEATURE_V8) && !ns)) {
|
||||
r2->type |= ARM_CP_ALIAS;
|
||||
r2->resetfn = arm_cp_reset_ignore;
|
||||
}
|
||||
} else if ((secstate != r->secure) && !ns) {
|
||||
/* The register is not banked so we only want to allow migration of
|
||||
* the non-secure instance.
|
||||
*/
|
||||
r2->type |= ARM_CP_ALIAS;
|
||||
r2->resetfn = arm_cp_reset_ignore;
|
||||
}
|
||||
|
||||
if (r->state == ARM_CP_STATE_BOTH) {
|
||||
@@ -4478,7 +4555,7 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
|
||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM);
|
||||
return;
|
||||
case EXCP_BKPT:
|
||||
if (semihosting_enabled) {
|
||||
if (semihosting_enabled()) {
|
||||
int nr;
|
||||
nr = arm_lduw_code(env, env->regs[15], env->bswap_code) & 0xff;
|
||||
if (nr == 0xab) {
|
||||
@@ -4790,7 +4867,7 @@ void arm_cpu_do_interrupt(CPUState *cs)
|
||||
offset = 4;
|
||||
break;
|
||||
case EXCP_SWI:
|
||||
if (semihosting_enabled) {
|
||||
if (semihosting_enabled()) {
|
||||
/* Check for semihosting interrupt. */
|
||||
if (env->thumb) {
|
||||
mask = arm_lduw_code(env, env->regs[15] - 2, env->bswap_code)
|
||||
@@ -4817,7 +4894,7 @@ void arm_cpu_do_interrupt(CPUState *cs)
|
||||
break;
|
||||
case EXCP_BKPT:
|
||||
/* See if this is a semihosting syscall. */
|
||||
if (env->thumb && semihosting_enabled) {
|
||||
if (env->thumb && semihosting_enabled()) {
|
||||
mask = arm_lduw_code(env, env->regs[15], env->bswap_code) & 0xff;
|
||||
if (mask == 0xab
|
||||
&& (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR) {
|
||||
@@ -5759,6 +5836,167 @@ do_fault:
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void get_phys_addr_pmsav7_default(CPUARMState *env,
|
||||
ARMMMUIdx mmu_idx,
|
||||
int32_t address, int *prot)
|
||||
{
|
||||
*prot = PAGE_READ | PAGE_WRITE;
|
||||
switch (address) {
|
||||
case 0xF0000000 ... 0xFFFFFFFF:
|
||||
if (regime_sctlr(env, mmu_idx) & SCTLR_V) { /* hivecs execing is ok */
|
||||
*prot |= PAGE_EXEC;
|
||||
}
|
||||
break;
|
||||
case 0x00000000 ... 0x7FFFFFFF:
|
||||
*prot |= PAGE_EXEC;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address,
|
||||
int access_type, ARMMMUIdx mmu_idx,
|
||||
hwaddr *phys_ptr, int *prot, uint32_t *fsr)
|
||||
{
|
||||
ARMCPU *cpu = arm_env_get_cpu(env);
|
||||
int n;
|
||||
bool is_user = regime_is_user(env, mmu_idx);
|
||||
|
||||
*phys_ptr = address;
|
||||
*prot = 0;
|
||||
|
||||
if (regime_translation_disabled(env, mmu_idx)) { /* MPU disabled */
|
||||
get_phys_addr_pmsav7_default(env, mmu_idx, address, prot);
|
||||
} else { /* MPU enabled */
|
||||
for (n = (int)cpu->pmsav7_dregion - 1; n >= 0; n--) {
|
||||
/* region search */
|
||||
uint32_t base = env->pmsav7.drbar[n];
|
||||
uint32_t rsize = extract32(env->pmsav7.drsr[n], 1, 5);
|
||||
uint32_t rmask;
|
||||
bool srdis = false;
|
||||
|
||||
if (!(env->pmsav7.drsr[n] & 0x1)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!rsize) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "DRSR.Rsize field can not be 0");
|
||||
continue;
|
||||
}
|
||||
rsize++;
|
||||
rmask = (1ull << rsize) - 1;
|
||||
|
||||
if (base & rmask) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "DRBAR %" PRIx32 " misaligned "
|
||||
"to DRSR region size, mask = %" PRIx32,
|
||||
base, rmask);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (address < base || address > base + rmask) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Region matched */
|
||||
|
||||
if (rsize >= 8) { /* no subregions for regions < 256 bytes */
|
||||
int i, snd;
|
||||
uint32_t srdis_mask;
|
||||
|
||||
rsize -= 3; /* sub region size (power of 2) */
|
||||
snd = ((address - base) >> rsize) & 0x7;
|
||||
srdis = extract32(env->pmsav7.drsr[n], snd + 8, 1);
|
||||
|
||||
srdis_mask = srdis ? 0x3 : 0x0;
|
||||
for (i = 2; i <= 8 && rsize < TARGET_PAGE_BITS; i *= 2) {
|
||||
/* This will check in groups of 2, 4 and then 8, whether
|
||||
* the subregion bits are consistent. rsize is incremented
|
||||
* back up to give the region size, considering consistent
|
||||
* adjacent subregions as one region. Stop testing if rsize
|
||||
* is already big enough for an entire QEMU page.
|
||||
*/
|
||||
int snd_rounded = snd & ~(i - 1);
|
||||
uint32_t srdis_multi = extract32(env->pmsav7.drsr[n],
|
||||
snd_rounded + 8, i);
|
||||
if (srdis_mask ^ srdis_multi) {
|
||||
break;
|
||||
}
|
||||
srdis_mask = (srdis_mask << i) | srdis_mask;
|
||||
rsize++;
|
||||
}
|
||||
}
|
||||
if (rsize < TARGET_PAGE_BITS) {
|
||||
qemu_log_mask(LOG_UNIMP, "No support for MPU (sub)region"
|
||||
"alignment of %" PRIu32 " bits. Minimum is %d\n",
|
||||
rsize, TARGET_PAGE_BITS);
|
||||
continue;
|
||||
}
|
||||
if (srdis) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (n == -1) { /* no hits */
|
||||
if (cpu->pmsav7_dregion &&
|
||||
(is_user || !(regime_sctlr(env, mmu_idx) & SCTLR_BR))) {
|
||||
/* background fault */
|
||||
*fsr = 0;
|
||||
return true;
|
||||
}
|
||||
get_phys_addr_pmsav7_default(env, mmu_idx, address, prot);
|
||||
} else { /* a MPU hit! */
|
||||
uint32_t ap = extract32(env->pmsav7.dracr[n], 8, 3);
|
||||
|
||||
if (is_user) { /* User mode AP bit decoding */
|
||||
switch (ap) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 5:
|
||||
break; /* no access */
|
||||
case 3:
|
||||
*prot |= PAGE_WRITE;
|
||||
/* fall through */
|
||||
case 2:
|
||||
case 6:
|
||||
*prot |= PAGE_READ | PAGE_EXEC;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"Bad value for AP bits in DRACR %"
|
||||
PRIx32 "\n", ap);
|
||||
}
|
||||
} else { /* Priv. mode AP bits decoding */
|
||||
switch (ap) {
|
||||
case 0:
|
||||
break; /* no access */
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
*prot |= PAGE_WRITE;
|
||||
/* fall through */
|
||||
case 5:
|
||||
case 6:
|
||||
*prot |= PAGE_READ | PAGE_EXEC;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"Bad value for AP bits in DRACR %"
|
||||
PRIx32 "\n", ap);
|
||||
}
|
||||
}
|
||||
|
||||
/* execute never */
|
||||
if (env->pmsav7.dracr[n] & (1 << 12)) {
|
||||
*prot &= ~PAGE_EXEC;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*fsr = 0x00d; /* Permission fault */
|
||||
return !(*prot & (1 << access_type));
|
||||
}
|
||||
|
||||
static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address,
|
||||
int access_type, ARMMMUIdx mmu_idx,
|
||||
hwaddr *phys_ptr, int *prot, uint32_t *fsr)
|
||||
@@ -5844,7 +6082,7 @@ static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address,
|
||||
* DFSR/IFSR fault register, with the following caveats:
|
||||
* * we honour the short vs long DFSR format differences.
|
||||
* * the WnR bit is never set (the caller must do this).
|
||||
* * for MPU based systems we don't bother to return a full FSR format
|
||||
* * for PSMAv5 based systems we don't bother to return a full FSR format
|
||||
* value.
|
||||
*
|
||||
* @env: CPUARMState
|
||||
@@ -5892,6 +6130,16 @@ static inline bool get_phys_addr(CPUARMState *env, target_ulong address,
|
||||
}
|
||||
}
|
||||
|
||||
/* pmsav7 has special handling for when MPU is disabled so call it before
|
||||
* the common MMU/MPU disabled check below.
|
||||
*/
|
||||
if (arm_feature(env, ARM_FEATURE_MPU) &&
|
||||
arm_feature(env, ARM_FEATURE_V7)) {
|
||||
*page_size = TARGET_PAGE_SIZE;
|
||||
return get_phys_addr_pmsav7(env, address, access_type, mmu_idx,
|
||||
phys_ptr, prot, fsr);
|
||||
}
|
||||
|
||||
if (regime_translation_disabled(env, mmu_idx)) {
|
||||
/* MMU/MPU disabled. */
|
||||
*phys_ptr = address;
|
||||
@@ -5901,6 +6149,7 @@ static inline bool get_phys_addr(CPUARMState *env, target_ulong address,
|
||||
}
|
||||
|
||||
if (arm_feature(env, ARM_FEATURE_MPU)) {
|
||||
/* Pre-v7 MPU */
|
||||
*page_size = TARGET_PAGE_SIZE;
|
||||
return get_phys_addr_pmsav5(env, address, access_type, mmu_idx,
|
||||
phys_ptr, prot, fsr);
|
||||
|
||||
@@ -125,6 +125,39 @@ static const VMStateDescription vmstate_thumb2ee = {
|
||||
}
|
||||
};
|
||||
|
||||
static bool pmsav7_needed(void *opaque)
|
||||
{
|
||||
ARMCPU *cpu = opaque;
|
||||
CPUARMState *env = &cpu->env;
|
||||
|
||||
return arm_feature(env, ARM_FEATURE_MPU) &&
|
||||
arm_feature(env, ARM_FEATURE_V7);
|
||||
}
|
||||
|
||||
static bool pmsav7_rgnr_vmstate_validate(void *opaque, int version_id)
|
||||
{
|
||||
ARMCPU *cpu = opaque;
|
||||
|
||||
return cpu->env.cp15.c6_rgnr < cpu->pmsav7_dregion;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_pmsav7 = {
|
||||
.name = "cpu/pmsav7",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.needed = pmsav7_needed,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_VARRAY_UINT32(env.pmsav7.drbar, ARMCPU, pmsav7_dregion, 0,
|
||||
vmstate_info_uint32, uint32_t),
|
||||
VMSTATE_VARRAY_UINT32(env.pmsav7.drsr, ARMCPU, pmsav7_dregion, 0,
|
||||
vmstate_info_uint32, uint32_t),
|
||||
VMSTATE_VARRAY_UINT32(env.pmsav7.dracr, ARMCPU, pmsav7_dregion, 0,
|
||||
vmstate_info_uint32, uint32_t),
|
||||
VMSTATE_VALIDATE("rgnr is valid", pmsav7_rgnr_vmstate_validate),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static int get_cpsr(QEMUFile *f, void *opaque, size_t size)
|
||||
{
|
||||
ARMCPU *cpu = opaque;
|
||||
@@ -291,6 +324,7 @@ const VMStateDescription vmstate_arm_cpu = {
|
||||
&vmstate_iwmmxt,
|
||||
&vmstate_m,
|
||||
&vmstate_thumb2ee,
|
||||
&vmstate_pmsav7,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "cpu.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "exec/semihost.h"
|
||||
|
||||
int lm32_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
|
||||
int mmu_idx)
|
||||
@@ -162,7 +163,7 @@ void lm32_cpu_do_interrupt(CPUState *cs)
|
||||
|
||||
switch (cs->exception_index) {
|
||||
case EXCP_SYSTEMCALL:
|
||||
if (unlikely(semihosting_enabled)) {
|
||||
if (unlikely(semihosting_enabled())) {
|
||||
/* do_semicall() returns true if call was handled. Otherwise
|
||||
* do the normal exception handling. */
|
||||
if (lm32_cpu_do_semihosting(cs)) {
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "cpu.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "exec/semihost.h"
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
|
||||
@@ -33,8 +34,6 @@ static inline void do_interrupt_m68k_hardirq(CPUM68KState *env)
|
||||
|
||||
#else
|
||||
|
||||
extern int semihosting_enabled;
|
||||
|
||||
/* Try to fill the TLB and return an exception if error. If retaddr is
|
||||
NULL, it means that the function was called in C code (i.e. not
|
||||
from generated code or from helper.c) */
|
||||
@@ -63,8 +62,8 @@ static void do_rte(CPUM68KState *env)
|
||||
env->pc = cpu_ldl_kernel(env, sp + 4);
|
||||
sp |= (fmt >> 28) & 3;
|
||||
env->sr = fmt & 0xffff;
|
||||
m68k_switch_sp(env);
|
||||
env->aregs[7] = sp + 8;
|
||||
m68k_switch_sp(env);
|
||||
}
|
||||
|
||||
static void do_interrupt_all(CPUM68KState *env, int is_hw)
|
||||
@@ -85,7 +84,7 @@ static void do_interrupt_all(CPUM68KState *env, int is_hw)
|
||||
do_rte(env);
|
||||
return;
|
||||
case EXCP_HALT_INSN:
|
||||
if (semihosting_enabled
|
||||
if (semihosting_enabled()
|
||||
&& (env->sr & SR_S) != 0
|
||||
&& (env->pc & 3) == 0
|
||||
&& cpu_lduw_code(env, env->pc - 4) == 0x4e71
|
||||
@@ -108,10 +107,7 @@ static void do_interrupt_all(CPUM68KState *env, int is_hw)
|
||||
|
||||
vector = cs->exception_index << 2;
|
||||
|
||||
sp = env->aregs[7];
|
||||
|
||||
fmt |= 0x40000000;
|
||||
fmt |= (sp & 3) << 28;
|
||||
fmt |= vector << 16;
|
||||
fmt |= env->sr;
|
||||
|
||||
@@ -121,6 +117,8 @@ static void do_interrupt_all(CPUM68KState *env, int is_hw)
|
||||
env->sr &= ~SR_M;
|
||||
}
|
||||
m68k_switch_sp(env);
|
||||
sp = env->aregs[7];
|
||||
fmt |= (sp & 3) << 28;
|
||||
|
||||
/* ??? This could cause MMU faults. */
|
||||
sp &= ~3;
|
||||
|
||||
@@ -1995,8 +1995,8 @@ DISAS_INSN(move_from_usp)
|
||||
gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
|
||||
return;
|
||||
}
|
||||
/* TODO: Implement USP. */
|
||||
gen_exception(s, s->pc - 2, EXCP_ILLEGAL);
|
||||
tcg_gen_ld_i32(AREG(insn, 0), cpu_env,
|
||||
offsetof(CPUM68KState, sp[M68K_USP]));
|
||||
}
|
||||
|
||||
DISAS_INSN(move_to_usp)
|
||||
@@ -2005,8 +2005,8 @@ DISAS_INSN(move_to_usp)
|
||||
gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
|
||||
return;
|
||||
}
|
||||
/* TODO: Implement USP. */
|
||||
gen_exception(s, s->pc - 2, EXCP_ILLEGAL);
|
||||
tcg_gen_st_i32(AREG(insn, 0), cpu_env,
|
||||
offsetof(CPUM68KState, sp[M68K_USP]));
|
||||
}
|
||||
|
||||
DISAS_INSN(halt)
|
||||
|
||||
@@ -56,9 +56,21 @@ typedef struct MicroBlazeCPUClass {
|
||||
typedef struct MicroBlazeCPU {
|
||||
/*< private >*/
|
||||
CPUState parent_obj;
|
||||
uint32_t base_vectors;
|
||||
|
||||
/*< public >*/
|
||||
|
||||
/* Microblaze Configuration Settings */
|
||||
struct {
|
||||
bool stackprot;
|
||||
uint32_t base_vectors;
|
||||
uint8_t use_fpu;
|
||||
bool use_mmu;
|
||||
bool dcache_writeback;
|
||||
bool endi;
|
||||
char *version;
|
||||
uint8_t pvr;
|
||||
} cfg;
|
||||
|
||||
CPUMBState env;
|
||||
} MicroBlazeCPU;
|
||||
|
||||
|
||||
@@ -26,6 +26,43 @@
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "migration/vmstate.h"
|
||||
|
||||
static const struct {
|
||||
const char *name;
|
||||
uint8_t version_id;
|
||||
} mb_cpu_lookup[] = {
|
||||
/* These key value are as per MBV field in PVR0 */
|
||||
{"5.00.a", 0x01},
|
||||
{"5.00.b", 0x02},
|
||||
{"5.00.c", 0x03},
|
||||
{"6.00.a", 0x04},
|
||||
{"6.00.b", 0x06},
|
||||
{"7.00.a", 0x05},
|
||||
{"7.00.b", 0x07},
|
||||
{"7.10.a", 0x08},
|
||||
{"7.10.b", 0x09},
|
||||
{"7.10.c", 0x0a},
|
||||
{"7.10.d", 0x0b},
|
||||
{"7.20.a", 0x0c},
|
||||
{"7.20.b", 0x0d},
|
||||
{"7.20.c", 0x0e},
|
||||
{"7.20.d", 0x0f},
|
||||
{"7.30.a", 0x10},
|
||||
{"7.30.b", 0x11},
|
||||
{"8.00.a", 0x12},
|
||||
{"8.00.b", 0x13},
|
||||
{"8.10.a", 0x14},
|
||||
{"8.20.a", 0x15},
|
||||
{"8.20.b", 0x16},
|
||||
{"8.30.a", 0x17},
|
||||
{"8.40.a", 0x18},
|
||||
{"8.40.b", 0x19},
|
||||
{"8.50.a", 0x1A},
|
||||
{"9.0", 0x1B},
|
||||
{"9.1", 0x1D},
|
||||
{"9.2", 0x1F},
|
||||
{"9.3", 0x20},
|
||||
{NULL, 0},
|
||||
};
|
||||
|
||||
static void mb_cpu_set_pc(CPUState *cs, vaddr value)
|
||||
{
|
||||
@@ -63,45 +100,16 @@ static void mb_cpu_reset(CPUState *s)
|
||||
|
||||
mcc->parent_reset(s);
|
||||
|
||||
memset(env, 0, sizeof(CPUMBState));
|
||||
memset(env, 0, offsetof(CPUMBState, pvr));
|
||||
env->res_addr = RES_ADDR_NONE;
|
||||
tlb_flush(s, 1);
|
||||
|
||||
/* Disable stack protector. */
|
||||
env->shr = ~0;
|
||||
|
||||
env->pvr.regs[0] = PVR0_PVR_FULL_MASK \
|
||||
| PVR0_USE_BARREL_MASK \
|
||||
| PVR0_USE_DIV_MASK \
|
||||
| PVR0_USE_HW_MUL_MASK \
|
||||
| PVR0_USE_EXC_MASK \
|
||||
| PVR0_USE_ICACHE_MASK \
|
||||
| PVR0_USE_DCACHE_MASK \
|
||||
| PVR0_USE_MMU \
|
||||
| (0xb << 8);
|
||||
env->pvr.regs[2] = PVR2_D_OPB_MASK \
|
||||
| PVR2_D_LMB_MASK \
|
||||
| PVR2_I_OPB_MASK \
|
||||
| PVR2_I_LMB_MASK \
|
||||
| PVR2_USE_MSR_INSTR \
|
||||
| PVR2_USE_PCMP_INSTR \
|
||||
| PVR2_USE_BARREL_MASK \
|
||||
| PVR2_USE_DIV_MASK \
|
||||
| PVR2_USE_HW_MUL_MASK \
|
||||
| PVR2_USE_MUL64_MASK \
|
||||
| PVR2_USE_FPU_MASK \
|
||||
| PVR2_USE_FPU2_MASK \
|
||||
| PVR2_FPU_EXC_MASK \
|
||||
| 0;
|
||||
env->pvr.regs[10] = 0x0c000000; /* Default to spartan 3a dsp family. */
|
||||
env->pvr.regs[11] = PVR11_USE_MMU | (16 << 17);
|
||||
|
||||
env->sregs[SR_PC] = cpu->base_vectors;
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
/* start in user mode with interrupts enabled. */
|
||||
env->sregs[SR_MSR] = MSR_EE | MSR_IE | MSR_VM | MSR_UM;
|
||||
env->pvr.regs[10] = 0x0c000000; /* Spartan 3a dsp. */
|
||||
#else
|
||||
env->sregs[SR_MSR] = 0;
|
||||
mmu_init(&env->mmu);
|
||||
@@ -115,10 +123,62 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp)
|
||||
{
|
||||
CPUState *cs = CPU(dev);
|
||||
MicroBlazeCPUClass *mcc = MICROBLAZE_CPU_GET_CLASS(dev);
|
||||
MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
|
||||
CPUMBState *env = &cpu->env;
|
||||
uint8_t version_code = 0;
|
||||
int i = 0;
|
||||
|
||||
cpu_reset(cs);
|
||||
qemu_init_vcpu(cs);
|
||||
|
||||
env->pvr.regs[0] = PVR0_USE_BARREL_MASK \
|
||||
| PVR0_USE_DIV_MASK \
|
||||
| PVR0_USE_HW_MUL_MASK \
|
||||
| PVR0_USE_EXC_MASK \
|
||||
| PVR0_USE_ICACHE_MASK \
|
||||
| PVR0_USE_DCACHE_MASK \
|
||||
| (0xb << 8);
|
||||
env->pvr.regs[2] = PVR2_D_OPB_MASK \
|
||||
| PVR2_D_LMB_MASK \
|
||||
| PVR2_I_OPB_MASK \
|
||||
| PVR2_I_LMB_MASK \
|
||||
| PVR2_USE_MSR_INSTR \
|
||||
| PVR2_USE_PCMP_INSTR \
|
||||
| PVR2_USE_BARREL_MASK \
|
||||
| PVR2_USE_DIV_MASK \
|
||||
| PVR2_USE_HW_MUL_MASK \
|
||||
| PVR2_USE_MUL64_MASK \
|
||||
| PVR2_FPU_EXC_MASK \
|
||||
| 0;
|
||||
|
||||
for (i = 0; mb_cpu_lookup[i].name && cpu->cfg.version; i++) {
|
||||
if (strcmp(mb_cpu_lookup[i].name, cpu->cfg.version) == 0) {
|
||||
version_code = mb_cpu_lookup[i].version_id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!version_code) {
|
||||
qemu_log("Invalid MicroBlaze version number: %s\n", cpu->cfg.version);
|
||||
}
|
||||
|
||||
env->pvr.regs[0] |= (cpu->cfg.stackprot ? PVR0_SPROT_MASK : 0) |
|
||||
(cpu->cfg.use_fpu ? PVR0_USE_FPU_MASK : 0) |
|
||||
(cpu->cfg.use_mmu ? PVR0_USE_MMU_MASK : 0) |
|
||||
(cpu->cfg.endi ? PVR0_ENDI_MASK : 0) |
|
||||
(version_code << 16) |
|
||||
(cpu->cfg.pvr == C_PVR_FULL ? PVR0_PVR_FULL_MASK : 0);
|
||||
|
||||
env->pvr.regs[2] |= (cpu->cfg.use_fpu ? PVR2_USE_FPU_MASK : 0) |
|
||||
(cpu->cfg.use_fpu > 1 ? PVR2_USE_FPU2_MASK : 0);
|
||||
|
||||
env->pvr.regs[5] |= cpu->cfg.dcache_writeback ?
|
||||
PVR5_DCACHE_WRITEBACK_MASK : 0;
|
||||
|
||||
env->pvr.regs[10] = 0x0c000000; /* Default to spartan 3a dsp family. */
|
||||
env->pvr.regs[11] = PVR11_USE_MMU | (16 << 17);
|
||||
|
||||
env->sregs[SR_PC] = cpu->cfg.base_vectors;
|
||||
|
||||
mcc->parent_realize(dev, errp);
|
||||
}
|
||||
|
||||
@@ -151,7 +211,20 @@ static const VMStateDescription vmstate_mb_cpu = {
|
||||
};
|
||||
|
||||
static Property mb_properties[] = {
|
||||
DEFINE_PROP_UINT32("xlnx.base-vectors", MicroBlazeCPU, base_vectors, 0),
|
||||
DEFINE_PROP_UINT32("base-vectors", MicroBlazeCPU, cfg.base_vectors, 0),
|
||||
DEFINE_PROP_BOOL("use-stack-protection", MicroBlazeCPU, cfg.stackprot,
|
||||
false),
|
||||
/* If use-fpu > 0 - FPU is enabled
|
||||
* If use-fpu = 2 - Floating point conversion and square root instructions
|
||||
* are enabled
|
||||
*/
|
||||
DEFINE_PROP_UINT8("use-fpu", MicroBlazeCPU, cfg.use_fpu, 2),
|
||||
DEFINE_PROP_BOOL("use-mmu", MicroBlazeCPU, cfg.use_mmu, true),
|
||||
DEFINE_PROP_BOOL("dcache-writeback", MicroBlazeCPU, cfg.dcache_writeback,
|
||||
false),
|
||||
DEFINE_PROP_BOOL("endianness", MicroBlazeCPU, cfg.endi, false),
|
||||
DEFINE_PROP_STRING("version", MicroBlazeCPU, cfg.version),
|
||||
DEFINE_PROP_UINT8("pvr", MicroBlazeCPU, cfg.pvr, C_PVR_FULL),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user