mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/bonzini-gitlab/tags/for-upstream' into staging
* SCSI fix (Dmitry, Li Feng, Li Qiang) * memory API fixes (Eduardo) * removal of deprecated '-numa node', 'cpu-add', '-smp' (Igor) * ACPI fix for VMBus (Jon) * relocatable install (myself) * always remove docker containers (myself) * serial cleanups (Philippe) * vmware cpuid leaf for tsc and apic frequency (Sunil) * KVM_FEATURE_ASYNC_PF_INT support (Vitaly) * i386 XSAVE bugfix (Xiaoyao) * QOM developer documentation in docs/devel (Eduardo) * new checkpatch tests (Dov) * x86_64 syscall fix (Douglas) * interrupt-based APF fix (Vitaly) * always create kvmclock (Vitaly) * fix bios-tables-test (Eduardo) * KVM PV features cleanup (myself) * CAN FD (Pavel) meson: * fixes (Marc-André, Max, Stefan, Alexander, myself) * moved libmpathpersist, cocoa, malloc tests (myself) * support for 0.56 introspected test dependencies (myself) # gpg: Signature made Wed 30 Sep 2020 18:11:45 BST # gpg: using RSA key F13338574B662389866C7682BFFBD25F78C7AE83 # gpg: issuer "pbonzini@redhat.com" # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [full] # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" [full] # Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4 E2F7 7E15 100C CD36 69B1 # Subkey fingerprint: F133 3857 4B66 2389 866C 7682 BFFB D25F 78C7 AE83 * remotes/bonzini-gitlab/tags/for-upstream: (86 commits) hw/net/can: Correct Kconfig dependencies hw/net/can: Documentation for CTU CAN FD IP open hardware core emulation. hw/net/can: CTU CAN FD IP open hardware core emulation. hw/net/can/ctucafd: Add CTU CAN FD core register definitions. net/can: Add can_dlc2len and can_len2dlc for CAN FD. hw/net/can: sja1000 ignore CAN FD frames net/can: Initial host SocketCan support for CAN FD. target/i386: kvm: do not use kvm_check_extension to find paravirtual capabilities bios-tables-test: Remove kernel-irqchip=off option target/i386: always create kvmclock device target/i386: Fix VM migration when interrupt based APF is enabled helper_syscall x86_64: clear exception_is_int checkpatch: Detect '%#' or '%0#' in printf-style format strings typedefs: Restrict PCMachineState to 'hw/i386/pc.h' hw/xen: Split x86-specific declaration from generic hardware ones stubs: Split accelerator / hardware related stubs sysemu/xen: Add missing 'exec/cpu-common.h' header for ram_addr_t type hw/i386/xen: Rename X86/PC specific function as xen_hvm_init_pc() docs: Move object.h overview doc comment to qom.rst docs: Create docs/devel/qom.rst ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
+18
@@ -480,6 +480,7 @@ F: include/hw/block/dataplane/xen*
|
||||
F: include/hw/xen/
|
||||
F: include/sysemu/xen.h
|
||||
F: include/sysemu/xen-mapcache.h
|
||||
F: stubs/xen-hw-stub.c
|
||||
|
||||
Guest CPU Cores (HAXM)
|
||||
---------------------
|
||||
@@ -2090,6 +2091,15 @@ F: hw/rx/
|
||||
F: include/hw/intc/rx_icu.h
|
||||
F: include/hw/rx/
|
||||
|
||||
CAN bus subsystem and hardware
|
||||
M: Pavel Pisa <pisa@cmp.felk.cvut.cz>
|
||||
M: Vikram Garhwal <fnu.vikram@xilinx.com>
|
||||
S: Maintained
|
||||
W: https://canbus.pages.fel.cvut.cz/
|
||||
F: net/can/*
|
||||
F: hw/net/can/*
|
||||
F: include/net/can_*.h
|
||||
|
||||
Subsystems
|
||||
----------
|
||||
Audio
|
||||
@@ -2313,6 +2323,14 @@ F: softmmu/cpus.c
|
||||
F: softmmu/cpu-throttle.c
|
||||
F: qapi/run-state.json
|
||||
|
||||
Read, Copy, Update (RCU)
|
||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||
S: Maintained
|
||||
F: include/qemu/rcu*.h
|
||||
F: tests/rcutorture.c
|
||||
F: tests/test-rcu-*.c
|
||||
F: util/rcu.c
|
||||
|
||||
Human Monitor (HMP)
|
||||
M: Dr. David Alan Gilbert <dgilbert@redhat.com>
|
||||
S: Maintained
|
||||
|
||||
@@ -78,7 +78,7 @@ ${ninja-targets-c_COMPILER} ${ninja-targets-cpp_COMPILER}: .var.command += -MP
|
||||
# reread (and MESON won't be empty anymore).
|
||||
ifneq ($(MESON),)
|
||||
Makefile.mtest: build.ninja scripts/mtest2make.py
|
||||
$(MESON) introspect --tests --benchmarks | $(PYTHON) scripts/mtest2make.py > $@
|
||||
$(MESON) introspect --targets --tests --benchmarks | $(PYTHON) scripts/mtest2make.py > $@
|
||||
-include Makefile.mtest
|
||||
endif
|
||||
|
||||
@@ -285,7 +285,7 @@ endif
|
||||
ifdef CONFIG_WIN32
|
||||
@echo 'Windows targets:'
|
||||
$(call print-help,installer,Build NSIS-based installer for QEMU)
|
||||
ifdef QEMU_GA_MSI_ENABLED
|
||||
ifdef CONFIG_QGA_MSI
|
||||
$(call print-help,msi,Build MSI-based installer for qemu-ga)
|
||||
endif
|
||||
@echo ''
|
||||
|
||||
+1
-40
@@ -6,50 +6,11 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/xen/xen.h"
|
||||
#include "sysemu/xen.h"
|
||||
#include "qapi/qapi-commands-misc.h"
|
||||
|
||||
bool xen_allowed;
|
||||
|
||||
void xenstore_store_pv_console_info(int i, Chardev *chr)
|
||||
{
|
||||
}
|
||||
|
||||
int xen_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
void xen_piix3_set_irq(void *opaque, int irq_num, int level)
|
||||
{
|
||||
}
|
||||
|
||||
void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len)
|
||||
{
|
||||
}
|
||||
|
||||
void xen_hvm_inject_msi(uint64_t addr, uint32_t data)
|
||||
{
|
||||
}
|
||||
|
||||
int xen_is_pirq_msi(uint32_t msi_data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
qemu_irq *xen_interrupt_controller_init(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void xen_register_framebuffer(MemoryRegion *mr)
|
||||
{
|
||||
}
|
||||
|
||||
void xen_hvm_init(PCMachineState *pcms, MemoryRegion **ram_memory)
|
||||
{
|
||||
}
|
||||
|
||||
void qmp_xen_set_global_dirty_log(bool enable, Error **errp)
|
||||
{
|
||||
}
|
||||
|
||||
+2
-2
@@ -1053,7 +1053,7 @@ static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
|
||||
cpu_io_recompile(cpu, retaddr);
|
||||
}
|
||||
|
||||
if (mr->global_locking && !qemu_mutex_iothread_locked()) {
|
||||
if (!qemu_mutex_iothread_locked()) {
|
||||
qemu_mutex_lock_iothread();
|
||||
locked = true;
|
||||
}
|
||||
@@ -1114,7 +1114,7 @@ static void io_writex(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
|
||||
*/
|
||||
save_iotlb_data(cpu, iotlbentry->addr, section, mr_offset);
|
||||
|
||||
if (mr->global_locking && !qemu_mutex_iothread_locked()) {
|
||||
if (!qemu_mutex_iothread_locked()) {
|
||||
qemu_mutex_lock_iothread();
|
||||
locked = true;
|
||||
}
|
||||
|
||||
@@ -138,7 +138,20 @@ static int qemu_chr_write_buffer(Chardev *s,
|
||||
}
|
||||
}
|
||||
if (*offset > 0) {
|
||||
/*
|
||||
* If some data was written by backend, we should
|
||||
* only log what was actually written. This method
|
||||
* may be invoked again to write the remaining
|
||||
* method, thus we'll log the remainder at that time.
|
||||
*/
|
||||
qemu_chr_write_log(s, buf, *offset);
|
||||
} else if (res < 0) {
|
||||
/*
|
||||
* If a fatal error was reported by the backend,
|
||||
* assume this method won't be invoked again with
|
||||
* this buffer, so log it all right away.
|
||||
*/
|
||||
qemu_chr_write_log(s, buf, len);
|
||||
}
|
||||
qemu_mutex_unlock(&s->chr_write_lock);
|
||||
|
||||
|
||||
@@ -403,7 +403,7 @@ netmap="no"
|
||||
sdl="auto"
|
||||
sdl_image="auto"
|
||||
virtfs=""
|
||||
mpath=""
|
||||
mpath="auto"
|
||||
vnc="enabled"
|
||||
sparse="no"
|
||||
vde=""
|
||||
@@ -457,7 +457,7 @@ bsd="no"
|
||||
linux="no"
|
||||
solaris="no"
|
||||
profiler="no"
|
||||
cocoa="no"
|
||||
cocoa="auto"
|
||||
softmmu="yes"
|
||||
linux_user="no"
|
||||
bsd_user="no"
|
||||
@@ -549,7 +549,7 @@ skip_meson=no
|
||||
gettext=""
|
||||
|
||||
bogus_os="no"
|
||||
malloc_trim=""
|
||||
malloc_trim="auto"
|
||||
|
||||
# parse CC options first
|
||||
for opt do
|
||||
@@ -870,12 +870,12 @@ Darwin)
|
||||
bsd="yes"
|
||||
darwin="yes"
|
||||
hax="yes"
|
||||
hvf="yes"
|
||||
hvf=""
|
||||
if [ "$cpu" = "x86_64" ] ; then
|
||||
QEMU_CFLAGS="-arch x86_64 $QEMU_CFLAGS"
|
||||
QEMU_LDFLAGS="-arch x86_64 $QEMU_LDFLAGS"
|
||||
fi
|
||||
cocoa="yes"
|
||||
cocoa="enabled"
|
||||
audio_drv_list="coreaudio try-sdl"
|
||||
audio_possible_drivers="coreaudio sdl"
|
||||
QEMU_LDFLAGS="-framework CoreFoundation -framework IOKit $QEMU_LDFLAGS"
|
||||
@@ -908,7 +908,6 @@ Linux)
|
||||
linux_user="yes"
|
||||
kvm="yes"
|
||||
QEMU_INCLUDES="-isystem ${source_path}/linux-headers -Ilinux-headers $QEMU_INCLUDES"
|
||||
libudev="yes"
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -970,7 +969,7 @@ if test "$mingw32" = "yes" ; then
|
||||
# MinGW needs -mthreads for TLS and macro _MT.
|
||||
CFLAGS="-mthreads $CFLAGS"
|
||||
write_c_skeleton;
|
||||
prefix="c:/Program Files/QEMU"
|
||||
prefix="/qemu"
|
||||
qemu_suffix=""
|
||||
libs_qga="-lws2_32 -lwinmm -lpowrprof -lwtsapi32 -lwininet -liphlpapi -lnetapi32 $libs_qga"
|
||||
fi
|
||||
@@ -1117,9 +1116,9 @@ for opt do
|
||||
;;
|
||||
--enable-virtfs) virtfs="yes"
|
||||
;;
|
||||
--disable-mpath) mpath="no"
|
||||
--disable-mpath) mpath="disabled"
|
||||
;;
|
||||
--enable-mpath) mpath="yes"
|
||||
--enable-mpath) mpath="enabled"
|
||||
;;
|
||||
--disable-vnc) vnc="disabled"
|
||||
;;
|
||||
@@ -1229,9 +1228,9 @@ for opt do
|
||||
;;
|
||||
--enable-tcg) tcg="yes"
|
||||
;;
|
||||
--disable-malloc-trim) malloc_trim="no"
|
||||
--disable-malloc-trim) malloc_trim="disabled"
|
||||
;;
|
||||
--enable-malloc-trim) malloc_trim="yes"
|
||||
--enable-malloc-trim) malloc_trim="enabled"
|
||||
;;
|
||||
--disable-spice) spice="no"
|
||||
;;
|
||||
@@ -1247,10 +1246,10 @@ for opt do
|
||||
;;
|
||||
--enable-profiler) profiler="yes"
|
||||
;;
|
||||
--disable-cocoa) cocoa="no"
|
||||
--disable-cocoa) cocoa="disabled"
|
||||
;;
|
||||
--enable-cocoa)
|
||||
cocoa="yes" ;
|
||||
cocoa="enabled" ;
|
||||
audio_drv_list="coreaudio $(echo $audio_drv_list | sed s,coreaudio,,g)"
|
||||
;;
|
||||
--disable-system) softmmu="no"
|
||||
@@ -2016,7 +2015,7 @@ case "$meson" in
|
||||
fi
|
||||
meson="$python ${source_path}/meson/meson.py"
|
||||
;;
|
||||
*) meson=$(command -v meson) ;;
|
||||
*) meson=$(command -v "$meson") ;;
|
||||
esac
|
||||
|
||||
# Probe for ninja (used for compdb)
|
||||
@@ -2392,8 +2391,8 @@ fi
|
||||
# cocoa implies not SDL or GTK
|
||||
# (the cocoa UI code currently assumes it is always the active UI
|
||||
# and doesn't interact well with other UI frontend code)
|
||||
if test "$cocoa" = "yes"; then
|
||||
if test "$sdl" = "yes"; then
|
||||
if test "$cocoa" = "enabled"; then
|
||||
if test "$sdl" = "enabled"; then
|
||||
error_exit "Cocoa and SDL UIs cannot both be enabled at once"
|
||||
fi
|
||||
if test "$gtk" = "yes"; then
|
||||
@@ -2986,7 +2985,10 @@ fi
|
||||
|
||||
##########################################
|
||||
# Windows Hypervisor Platform accelerator (WHPX) check
|
||||
if test "$whpx" != "no" ; then
|
||||
if test "$whpx" = "yes" && test "$ARCH" != "x86_64"; then
|
||||
error_exit "WHPX requires 64-bit host"
|
||||
fi
|
||||
if test "$whpx" != "no" && test "$ARCH" = "x86_64"; then
|
||||
if check_include "WinHvPlatform.h" && check_include "WinHvEmulation.h"; then
|
||||
whpx="yes"
|
||||
else
|
||||
@@ -3850,57 +3852,6 @@ if test "$modules" = yes; then
|
||||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# libmpathpersist probe
|
||||
|
||||
if test "$mpath" != "no" ; then
|
||||
# probe for the new API
|
||||
cat > $TMPC <<EOF
|
||||
#include <libudev.h>
|
||||
#include <mpath_persist.h>
|
||||
unsigned mpath_mx_alloc_len = 1024;
|
||||
int logsink;
|
||||
static struct config *multipath_conf;
|
||||
extern struct udev *udev;
|
||||
extern struct config *get_multipath_config(void);
|
||||
extern void put_multipath_config(struct config *conf);
|
||||
struct udev *udev;
|
||||
struct config *get_multipath_config(void) { return multipath_conf; }
|
||||
void put_multipath_config(struct config *conf) { }
|
||||
|
||||
int main(void) {
|
||||
udev = udev_new();
|
||||
multipath_conf = mpath_lib_init();
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if compile_prog "" "-ludev -lmultipath -lmpathpersist" ; then
|
||||
mpathpersist=yes
|
||||
mpathpersist_new_api=yes
|
||||
else
|
||||
# probe for the old API
|
||||
cat > $TMPC <<EOF
|
||||
#include <libudev.h>
|
||||
#include <mpath_persist.h>
|
||||
unsigned mpath_mx_alloc_len = 1024;
|
||||
int logsink;
|
||||
int main(void) {
|
||||
struct udev *udev = udev_new();
|
||||
mpath_lib_init(udev);
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if compile_prog "" "-ludev -lmultipath -lmpathpersist" ; then
|
||||
mpathpersist=yes
|
||||
mpathpersist_new_api=no
|
||||
else
|
||||
mpathpersist=no
|
||||
fi
|
||||
fi
|
||||
else
|
||||
mpathpersist=no
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# pthread probe
|
||||
PTHREADLIBS_LIST="-pthread -lpthread -lpthreadGC2"
|
||||
@@ -4433,77 +4384,14 @@ EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
malloc=system
|
||||
if test "$tcmalloc" = "yes" && test "$jemalloc" = "yes" ; then
|
||||
echo "ERROR: tcmalloc && jemalloc can't be used at the same time"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Even if malloc_trim() is available, these non-libc memory allocators
|
||||
# do not support it.
|
||||
if test "$tcmalloc" = "yes" || test "$jemalloc" = "yes" ; then
|
||||
if test "$malloc_trim" = "yes" ; then
|
||||
echo "Disabling malloc_trim with non-libc memory allocator"
|
||||
fi
|
||||
malloc_trim="no"
|
||||
fi
|
||||
|
||||
#######################################
|
||||
# malloc_trim
|
||||
|
||||
if test "$malloc_trim" != "no" ; then
|
||||
cat > $TMPC << EOF
|
||||
#include <malloc.h>
|
||||
int main(void) { malloc_trim(0); return 0; }
|
||||
EOF
|
||||
if compile_prog "" "" ; then
|
||||
malloc_trim="yes"
|
||||
else
|
||||
malloc_trim="no"
|
||||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# tcmalloc probe
|
||||
|
||||
if test "$tcmalloc" = "yes" ; then
|
||||
cat > $TMPC << EOF
|
||||
#include <stdlib.h>
|
||||
int main(void) {
|
||||
void *tmp = malloc(1);
|
||||
if (tmp != NULL) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
EOF
|
||||
|
||||
if compile_prog "" "-ltcmalloc" ; then
|
||||
LIBS="-ltcmalloc $LIBS"
|
||||
else
|
||||
feature_not_found "tcmalloc" "install gperftools devel"
|
||||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# jemalloc probe
|
||||
|
||||
if test "$jemalloc" = "yes" ; then
|
||||
cat > $TMPC << EOF
|
||||
#include <stdlib.h>
|
||||
int main(void) {
|
||||
void *tmp = malloc(1);
|
||||
if (tmp != NULL) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
EOF
|
||||
|
||||
if compile_prog "" "-ljemalloc" ; then
|
||||
LIBS="-ljemalloc $LIBS"
|
||||
else
|
||||
feature_not_found "jemalloc" "install jemalloc devel"
|
||||
fi
|
||||
elif test "$tcmalloc" = "yes" ; then
|
||||
malloc=tcmalloc
|
||||
elif test "$jemalloc" = "yes" ; then
|
||||
malloc=jemalloc
|
||||
fi
|
||||
|
||||
##########################################
|
||||
@@ -5935,16 +5823,18 @@ fi
|
||||
|
||||
#################################################
|
||||
# Check to see if we have the Hypervisor framework
|
||||
if [ "$darwin" = "yes" ] ; then
|
||||
if [ "$hvf" != "no" ] ; then
|
||||
cat > $TMPC << EOF
|
||||
#include <Hypervisor/hv.h>
|
||||
int main() { return 0;}
|
||||
EOF
|
||||
if ! compile_object ""; then
|
||||
if test "$hvf" = "yes"; then
|
||||
error_exit "Hypervisor.framework not available"
|
||||
fi
|
||||
hvf='no'
|
||||
else
|
||||
hvf='yes'
|
||||
QEMU_LDFLAGS="-framework Hypervisor $QEMU_LDFLAGS"
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -6284,15 +6174,6 @@ if test "$libnfs" != "no" ; then
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# Do we have libudev
|
||||
if test "$libudev" != "no" ; then
|
||||
if $pkg_config libudev && test "$static" != "yes"; then
|
||||
libudev="yes"
|
||||
libudev_libs=$($pkg_config --libs libudev)
|
||||
else
|
||||
libudev="no"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Exclude --warn-common with TSan to suppress warnings from the TSan libraries.
|
||||
if test "$solaris" = "no" && test "$tsan" = "no"; then
|
||||
@@ -6344,23 +6225,11 @@ if test "$softmmu" = yes ; then
|
||||
fi
|
||||
virtfs=no
|
||||
fi
|
||||
if test "$mpath" != no && test "$mpathpersist" = yes ; then
|
||||
mpath=yes
|
||||
else
|
||||
if test "$mpath" = yes; then
|
||||
error_exit "Multipath requires libmpathpersist devel"
|
||||
fi
|
||||
mpath=no
|
||||
fi
|
||||
else
|
||||
if test "$virtfs" = yes; then
|
||||
error_exit "VirtFS is supported only on Linux"
|
||||
fi
|
||||
virtfs=no
|
||||
if test "$mpath" = yes; then
|
||||
error_exit "Multipath is supported only on Linux"
|
||||
fi
|
||||
mpath=no
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -6567,7 +6436,7 @@ if test "$mingw32" = "yes" ; then
|
||||
echo "CONFIG_QGA_NTDDSCSI=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$guest_agent_msi" = "yes"; then
|
||||
echo "QEMU_GA_MSI_ENABLED=yes" >> $config_host_mak
|
||||
echo "CONFIG_QGA_MSI=y" >> $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
|
||||
@@ -6683,9 +6552,6 @@ if test "$have_x11" = "yes" && test "$need_x11" = "yes"; then
|
||||
echo "X11_CFLAGS=$x11_cflags" >> $config_host_mak
|
||||
echo "X11_LIBS=$x11_libs" >> $config_host_mak
|
||||
fi
|
||||
if test "$cocoa" = "yes" ; then
|
||||
echo "CONFIG_COCOA=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$iconv" = "yes" ; then
|
||||
echo "CONFIG_ICONV=y" >> $config_host_mak
|
||||
echo "ICONV_CFLAGS=$iconv_cflags" >> $config_host_mak
|
||||
@@ -6901,12 +6767,6 @@ fi
|
||||
if test "$virtfs" = "yes" ; then
|
||||
echo "CONFIG_VIRTFS=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$mpath" = "yes" ; then
|
||||
echo "CONFIG_MPATH=y" >> $config_host_mak
|
||||
if test "$mpathpersist_new_api" = "yes"; then
|
||||
echo "CONFIG_MPATH_NEW_API=y" >> $config_host_mak
|
||||
fi
|
||||
fi
|
||||
if test "$vhost_scsi" = "yes" ; then
|
||||
echo "CONFIG_VHOST_SCSI=y" >> $config_host_mak
|
||||
fi
|
||||
@@ -7021,10 +6881,6 @@ if test "$gbm" = "yes" ; then
|
||||
fi
|
||||
|
||||
|
||||
if test "$malloc_trim" = "yes" ; then
|
||||
echo "CONFIG_MALLOC_TRIM=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$avx2_opt" = "yes" ; then
|
||||
echo "CONFIG_AVX2_OPT=y" >> $config_host_mak
|
||||
fi
|
||||
@@ -7453,10 +7309,6 @@ if test "$gcov" = "yes" ; then
|
||||
echo "CONFIG_GCOV=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$libudev" != "no"; then
|
||||
echo "CONFIG_LIBUDEV=y" >> $config_host_mak
|
||||
echo "LIBUDEV_LIBS=$libudev_libs" >> $config_host_mak
|
||||
fi
|
||||
if test "$fuzzing" != "no"; then
|
||||
echo "CONFIG_FUZZ=y" >> $config_host_mak
|
||||
fi
|
||||
@@ -7943,17 +7795,9 @@ echo "strip = $(meson_quote $strip)" >> $cross
|
||||
echo "windres = $(meson_quote $windres)" >> $cross
|
||||
if test -n "$cross_prefix"; then
|
||||
cross_arg="--cross-file config-meson.cross"
|
||||
# Hack: Meson expects an absolute path for the *build* machine
|
||||
# for the prefix, so add a slash in front of a Windows path that
|
||||
# includes a drive letter.
|
||||
#
|
||||
# See https://github.com/mesonbuild/meson/issues/7577.
|
||||
echo "[host_machine]" >> $cross
|
||||
if test "$mingw32" = "yes" ; then
|
||||
echo "system = 'windows'" >> $cross
|
||||
case $prefix in
|
||||
?:*) pre_prefix=/ ;;
|
||||
esac
|
||||
fi
|
||||
if test "$linux" = "yes" ; then
|
||||
echo "system = 'linux'" >> $cross
|
||||
@@ -7982,16 +7826,16 @@ mv $cross config-meson.cross
|
||||
|
||||
rm -rf meson-private meson-info meson-logs
|
||||
NINJA=${ninja:-$PWD/ninjatool} $meson setup \
|
||||
--prefix "${pre_prefix}$prefix" \
|
||||
--libdir "${pre_prefix}$libdir" \
|
||||
--libexecdir "${pre_prefix}$libexecdir" \
|
||||
--bindir "${pre_prefix}$bindir" \
|
||||
--includedir "${pre_prefix}$includedir" \
|
||||
--datadir "${pre_prefix}$datadir" \
|
||||
--mandir "${pre_prefix}$mandir" \
|
||||
--sysconfdir "${pre_prefix}$sysconfdir" \
|
||||
--localstatedir "${pre_prefix}$local_statedir" \
|
||||
-Ddocdir="${pre_prefix}$docdir" \
|
||||
--prefix "$prefix" \
|
||||
--libdir "$libdir" \
|
||||
--libexecdir "$libexecdir" \
|
||||
--bindir "$bindir" \
|
||||
--includedir "$includedir" \
|
||||
--datadir "$datadir" \
|
||||
--mandir "$mandir" \
|
||||
--sysconfdir "$sysconfdir" \
|
||||
--localstatedir "$local_statedir" \
|
||||
-Ddocdir="$docdir" \
|
||||
-Dqemu_suffix="$qemu_suffix" \
|
||||
-Doptimization=$(if test "$debug" = yes; then echo 0; else echo 2; fi) \
|
||||
-Ddebug=$(if test "$debug_info" = yes; then echo true; else echo false; fi) \
|
||||
@@ -7999,7 +7843,8 @@ NINJA=${ninja:-$PWD/ninjatool} $meson setup \
|
||||
-Dstrip=$(if test "$strip_opt" = yes; then echo true; else echo false; fi) \
|
||||
-Db_pie=$(if test "$pie" = yes; then echo true; else echo false; fi) \
|
||||
-Db_coverage=$(if test "$gcov" = yes; then echo true; else echo false; fi) \
|
||||
-Dsdl=$sdl -Dsdl_image=$sdl_image \
|
||||
-Dmalloc=$malloc -Dmalloc_trim=$malloc_trim \
|
||||
-Dcocoa=$cocoa -Dmpath=$mpath -Dsdl=$sdl -Dsdl_image=$sdl_image \
|
||||
-Dvnc=$vnc -Dvnc_sasl=$vnc_sasl -Dvnc_jpeg=$vnc_jpeg -Dvnc_png=$vnc_png \
|
||||
-Dgettext=$gettext -Dxkbcommon=$xkbcommon -Du2f=$u2f\
|
||||
$cross_arg \
|
||||
|
||||
+102
-11
@@ -8,13 +8,22 @@ can be connected to host system CAN API (at this time only Linux
|
||||
SocketCAN is supported).
|
||||
|
||||
The concept of busses is generic and different CAN controllers
|
||||
can be implemented for it but at this time only SJA1000 chip
|
||||
controller is implemented.
|
||||
can be implemented.
|
||||
|
||||
The initial submission implemented SJA1000 controller which
|
||||
is common and well supported by by drivers for the most operating
|
||||
systems.
|
||||
|
||||
The PCI addon card hardware has been selected as the first CAN
|
||||
interface to implement because such device can be easily connected
|
||||
to systems with different CPU architectures (x86, PowerPC, Arm, etc.).
|
||||
|
||||
In 2020, CTU CAN FD controller model has been added as part
|
||||
of the bachelor theses of Jan Charvat. This controller is complete
|
||||
open-source/design/hardware solution. The core designer
|
||||
of the project is Ondrej Ille, the financial support has been
|
||||
provided by CTU, and more companies including Volkswagen subsidiaries.
|
||||
|
||||
The project has been initially started in frame of RTEMS GSoC 2013
|
||||
slot by Jin Yang under our mentoring The initial idea was to provide generic
|
||||
CAN subsystem for RTEMS. But lack of common environment for code and RTEMS
|
||||
@@ -22,8 +31,8 @@ testing lead to goal change to provide environment which provides complete
|
||||
emulated environment for testing and RTEMS GSoC slot has been donated
|
||||
to work on CAN hardware emulation on QEMU.
|
||||
|
||||
Examples how to use CAN emulation
|
||||
=================================
|
||||
Examples how to use CAN emulation for SJA1000 based borads
|
||||
==========================================================
|
||||
|
||||
When QEMU with CAN PCI support is compiled then one of the next
|
||||
CAN boards can be selected
|
||||
@@ -90,18 +99,100 @@ traffic with "candump" command which is included in "can-utils".
|
||||
|
||||
candump can0
|
||||
|
||||
CTU CAN FD support examples
|
||||
===========================
|
||||
|
||||
This open-source core provides CAN FD support. CAN FD drames are
|
||||
delivered even to the host systems when SocketCAN interface is found
|
||||
CAN FD capable.
|
||||
|
||||
The PCIe borad emulation is provided for now (the device identifier is
|
||||
ctucan_pci). The defauld build defines two CTU CAN FD cores
|
||||
on the board.
|
||||
|
||||
Example how to connect the canbus0-bus (virtual wire) to the host
|
||||
Linux system (SocketCAN used) and to both CTU CAN FD cores emulated
|
||||
on the corresponding PCI card expects that host system CAN bus
|
||||
is setup according to the previous SJA1000 section.
|
||||
|
||||
qemu-system-x86_64 -enable-kvm -kernel /boot/vmlinuz-4.19.52+ \
|
||||
-initrd ramdisk.cpio \
|
||||
-virtfs local,path=shareddir,security_model=none,mount_tag=shareddir \
|
||||
-vga cirrus \
|
||||
-append "console=ttyS0" \
|
||||
-object can-bus,id=canbus0-bus \
|
||||
-object can-host-socketcan,if=can0,canbus=canbus0-bus,id=canbus0-socketcan \
|
||||
-device ctucan_pci,canbus0=canbus0-bus,canbus1=canbus0-bus \
|
||||
-nographic
|
||||
|
||||
Setup of CTU CAN FD controller in a guest Linux system
|
||||
|
||||
insmod ctucanfd.ko || modprobe ctucanfd
|
||||
insmod ctucanfd_pci.ko || modprobe ctucanfd_pci
|
||||
|
||||
for ifc in /sys/class/net/can* ; do
|
||||
if [ -e $ifc/device/vendor ] ; then
|
||||
if ! grep -q 0x1760 $ifc/device/vendor ; then
|
||||
continue;
|
||||
fi
|
||||
else
|
||||
continue;
|
||||
fi
|
||||
if [ -e $ifc/device/device ] ; then
|
||||
if ! grep -q 0xff00 $ifc/device/device ; then
|
||||
continue;
|
||||
fi
|
||||
else
|
||||
continue;
|
||||
fi
|
||||
ifc=$(basename $ifc)
|
||||
/bin/ip link set $ifc type can bitrate 1000000 dbitrate 10000000 fd on
|
||||
/bin/ip link set $ifc up
|
||||
done
|
||||
|
||||
The test can run for example
|
||||
|
||||
candump can1
|
||||
|
||||
in the guest system and next commands in the host system for basic CAN
|
||||
|
||||
cangen can0
|
||||
|
||||
for CAN FD without bitrate switch
|
||||
|
||||
cangen can0 -f
|
||||
|
||||
and with bitrate switch
|
||||
|
||||
cangen can0 -b
|
||||
|
||||
The test can be run viceversa, generate messages in the guest system and capture them
|
||||
in the host one and much more combinations.
|
||||
|
||||
Links to other resources
|
||||
========================
|
||||
|
||||
(1) Repository with development branch can-pci at Czech Technical University
|
||||
https://gitlab.fel.cvut.cz/canbus/qemu-canbus
|
||||
(2) GitHub repository with can-pci and our other changes included
|
||||
(1) CAN related projects at Czech Technical University, Faculty of Electrical Engineering
|
||||
http://canbus.pages.fel.cvut.cz/
|
||||
(2) Repository with development can-pci branch at Czech Technical University
|
||||
https://gitlab.fel.cvut.cz/canbus/qemu-canbus
|
||||
(3) RTEMS page describing project
|
||||
https://devel.rtems.org/wiki/Developer/Simulators/QEMU/CANEmulation
|
||||
(4) RTLWS 2015 article about the project and its use with CANopen emulation
|
||||
http://rtime.felk.cvut.cz/publications/public/rtlws2015-qemu-can.pdf
|
||||
Slides
|
||||
http://rtime.felk.cvut.cz/publications/public/rtlws2015-qemu-can-slides.pdf
|
||||
(5) Linux SocketCAN utilities
|
||||
http://cmp.felk.cvut.cz/~pisa/can/doc/rtlws-17-pisa-qemu-can.pdf
|
||||
(5) GNU/Linux, CAN and CANopen in Real-time Control Applications
|
||||
Slides from LinuxDays 2017 (include updated RTLWS 2015 content)
|
||||
https://www.linuxdays.cz/2017/video/Pavel_Pisa-CAN_canopen.pdf
|
||||
(6) Linux SocketCAN utilities
|
||||
https://github.com/linux-can/can-utils/
|
||||
(7) CTU CAN FD project including core VHDL design, Linux driver,
|
||||
test utilities etc.
|
||||
https://gitlab.fel.cvut.cz/canbus/ctucanfd_ip_core
|
||||
(8) CTU CAN FD Core Datasheet Documentation
|
||||
http://canbus.pages.fel.cvut.cz/ctucanfd_ip_core/Progdokum.pdf
|
||||
(9) CTU CAN FD Core System Architecture Documentation
|
||||
http://canbus.pages.fel.cvut.cz/ctucanfd_ip_core/ctu_can_fd_architecture.pdf
|
||||
(10) CTU CAN FD Driver Documentation
|
||||
http://canbus.pages.fel.cvut.cz/ctucanfd_ip_core/driver_doc/ctucanfd-driver.html
|
||||
(11) Integration with PCIe interfacing for Intel/Altera Cyclone IV based board
|
||||
https://gitlab.fel.cvut.cz/canbus/pcie-ctu_can_fd
|
||||
|
||||
@@ -193,6 +193,11 @@ compilation as possible. The Meson "sourceset" functionality is used
|
||||
to list the files and their dependency on various configuration
|
||||
symbols.
|
||||
|
||||
All executables are built by default, except for some `contrib/`
|
||||
binaries that are known to fail to build on some platforms (for example
|
||||
32-bit or big-endian platforms). Tests are also built by default,
|
||||
though that might change in the future.
|
||||
|
||||
Various subsystems that are common to both tools and emulators have
|
||||
their own sourceset, for example `block_ss` for the block device subsystem,
|
||||
`chardev_ss` for the character device subsystem, etc. These sourcesets
|
||||
|
||||
@@ -31,3 +31,4 @@ Contents:
|
||||
reset
|
||||
s390-dasd-ipl
|
||||
clocks
|
||||
qom
|
||||
|
||||
@@ -0,0 +1,378 @@
|
||||
===========================
|
||||
The QEMU Object Model (QOM)
|
||||
===========================
|
||||
|
||||
.. highlight:: c
|
||||
|
||||
The QEMU Object Model provides a framework for registering user creatable
|
||||
types and instantiating objects from those types. QOM provides the following
|
||||
features:
|
||||
|
||||
- System for dynamically registering types
|
||||
- Support for single-inheritance of types
|
||||
- Multiple inheritance of stateless interfaces
|
||||
|
||||
.. code-block:: c
|
||||
:caption: Creating a minimal type
|
||||
|
||||
#include "qdev.h"
|
||||
|
||||
#define TYPE_MY_DEVICE "my-device"
|
||||
|
||||
// No new virtual functions: we can reuse the typedef for the
|
||||
// superclass.
|
||||
typedef DeviceClass MyDeviceClass;
|
||||
typedef struct MyDevice
|
||||
{
|
||||
DeviceState parent;
|
||||
|
||||
int reg0, reg1, reg2;
|
||||
} MyDevice;
|
||||
|
||||
static const TypeInfo my_device_info = {
|
||||
.name = TYPE_MY_DEVICE,
|
||||
.parent = TYPE_DEVICE,
|
||||
.instance_size = sizeof(MyDevice),
|
||||
};
|
||||
|
||||
static void my_device_register_types(void)
|
||||
{
|
||||
type_register_static(&my_device_info);
|
||||
}
|
||||
|
||||
type_init(my_device_register_types)
|
||||
|
||||
In the above example, we create a simple type that is described by #TypeInfo.
|
||||
#TypeInfo describes information about the type including what it inherits
|
||||
from, the instance and class size, and constructor/destructor hooks.
|
||||
|
||||
Alternatively several static types could be registered using helper macro
|
||||
DEFINE_TYPES()
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static const TypeInfo device_types_info[] = {
|
||||
{
|
||||
.name = TYPE_MY_DEVICE_A,
|
||||
.parent = TYPE_DEVICE,
|
||||
.instance_size = sizeof(MyDeviceA),
|
||||
},
|
||||
{
|
||||
.name = TYPE_MY_DEVICE_B,
|
||||
.parent = TYPE_DEVICE,
|
||||
.instance_size = sizeof(MyDeviceB),
|
||||
},
|
||||
};
|
||||
|
||||
DEFINE_TYPES(device_types_info)
|
||||
|
||||
Every type has an #ObjectClass associated with it. #ObjectClass derivatives
|
||||
are instantiated dynamically but there is only ever one instance for any
|
||||
given type. The #ObjectClass typically holds a table of function pointers
|
||||
for the virtual methods implemented by this type.
|
||||
|
||||
Using object_new(), a new #Object derivative will be instantiated. You can
|
||||
cast an #Object to a subclass (or base-class) type using
|
||||
object_dynamic_cast(). You typically want to define macro wrappers around
|
||||
OBJECT_CHECK() and OBJECT_CLASS_CHECK() to make it easier to convert to a
|
||||
specific type:
|
||||
|
||||
.. code-block:: c
|
||||
:caption: Typecasting macros
|
||||
|
||||
#define MY_DEVICE_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(MyDeviceClass, obj, TYPE_MY_DEVICE)
|
||||
#define MY_DEVICE_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(MyDeviceClass, klass, TYPE_MY_DEVICE)
|
||||
#define MY_DEVICE(obj) \
|
||||
OBJECT_CHECK(MyDevice, obj, TYPE_MY_DEVICE)
|
||||
|
||||
Class Initialization
|
||||
====================
|
||||
|
||||
Before an object is initialized, the class for the object must be
|
||||
initialized. There is only one class object for all instance objects
|
||||
that is created lazily.
|
||||
|
||||
Classes are initialized by first initializing any parent classes (if
|
||||
necessary). After the parent class object has initialized, it will be
|
||||
copied into the current class object and any additional storage in the
|
||||
class object is zero filled.
|
||||
|
||||
The effect of this is that classes automatically inherit any virtual
|
||||
function pointers that the parent class has already initialized. All
|
||||
other fields will be zero filled.
|
||||
|
||||
Once all of the parent classes have been initialized, #TypeInfo::class_init
|
||||
is called to let the class being instantiated provide default initialize for
|
||||
its virtual functions. Here is how the above example might be modified
|
||||
to introduce an overridden virtual function:
|
||||
|
||||
.. code-block:: c
|
||||
:caption: Overriding a virtual function
|
||||
|
||||
#include "qdev.h"
|
||||
|
||||
void my_device_class_init(ObjectClass *klass, void *class_data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
dc->reset = my_device_reset;
|
||||
}
|
||||
|
||||
static const TypeInfo my_device_info = {
|
||||
.name = TYPE_MY_DEVICE,
|
||||
.parent = TYPE_DEVICE,
|
||||
.instance_size = sizeof(MyDevice),
|
||||
.class_init = my_device_class_init,
|
||||
};
|
||||
|
||||
Introducing new virtual methods requires a class to define its own
|
||||
struct and to add a .class_size member to the #TypeInfo. Each method
|
||||
will also have a wrapper function to call it easily:
|
||||
|
||||
.. code-block:: c
|
||||
:caption: Defining an abstract class
|
||||
|
||||
#include "qdev.h"
|
||||
|
||||
typedef struct MyDeviceClass
|
||||
{
|
||||
DeviceClass parent;
|
||||
|
||||
void (*frobnicate) (MyDevice *obj);
|
||||
} MyDeviceClass;
|
||||
|
||||
static const TypeInfo my_device_info = {
|
||||
.name = TYPE_MY_DEVICE,
|
||||
.parent = TYPE_DEVICE,
|
||||
.instance_size = sizeof(MyDevice),
|
||||
.abstract = true, // or set a default in my_device_class_init
|
||||
.class_size = sizeof(MyDeviceClass),
|
||||
};
|
||||
|
||||
void my_device_frobnicate(MyDevice *obj)
|
||||
{
|
||||
MyDeviceClass *klass = MY_DEVICE_GET_CLASS(obj);
|
||||
|
||||
klass->frobnicate(obj);
|
||||
}
|
||||
|
||||
Interfaces
|
||||
==========
|
||||
|
||||
Interfaces allow a limited form of multiple inheritance. Instances are
|
||||
similar to normal types except for the fact that are only defined by
|
||||
their classes and never carry any state. As a consequence, a pointer to
|
||||
an interface instance should always be of incomplete type in order to be
|
||||
sure it cannot be dereferenced. That is, you should define the
|
||||
'typedef struct SomethingIf SomethingIf' so that you can pass around
|
||||
``SomethingIf *si`` arguments, but not define a ``struct SomethingIf { ... }``.
|
||||
The only things you can validly do with a ``SomethingIf *`` are to pass it as
|
||||
an argument to a method on its corresponding SomethingIfClass, or to
|
||||
dynamically cast it to an object that implements the interface.
|
||||
|
||||
Methods
|
||||
=======
|
||||
|
||||
A <emphasis>method</emphasis> is a function within the namespace scope of
|
||||
a class. It usually operates on the object instance by passing it as a
|
||||
strongly-typed first argument.
|
||||
If it does not operate on an object instance, it is dubbed
|
||||
<emphasis>class method</emphasis>.
|
||||
|
||||
Methods cannot be overloaded. That is, the #ObjectClass and method name
|
||||
uniquely identity the function to be called; the signature does not vary
|
||||
except for trailing varargs.
|
||||
|
||||
Methods are always <emphasis>virtual</emphasis>. Overriding a method in
|
||||
#TypeInfo.class_init of a subclass leads to any user of the class obtained
|
||||
via OBJECT_GET_CLASS() accessing the overridden function.
|
||||
The original function is not automatically invoked. It is the responsibility
|
||||
of the overriding class to determine whether and when to invoke the method
|
||||
being overridden.
|
||||
|
||||
To invoke the method being overridden, the preferred solution is to store
|
||||
the original value in the overriding class before overriding the method.
|
||||
This corresponds to ``{super,base}.method(...)`` in Java and C#
|
||||
respectively; this frees the overriding class from hardcoding its parent
|
||||
class, which someone might choose to change at some point.
|
||||
|
||||
.. code-block:: c
|
||||
:caption: Overriding a virtual method
|
||||
|
||||
typedef struct MyState MyState;
|
||||
|
||||
typedef void (*MyDoSomething)(MyState *obj);
|
||||
|
||||
typedef struct MyClass {
|
||||
ObjectClass parent_class;
|
||||
|
||||
MyDoSomething do_something;
|
||||
} MyClass;
|
||||
|
||||
static void my_do_something(MyState *obj)
|
||||
{
|
||||
// do something
|
||||
}
|
||||
|
||||
static void my_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MyClass *mc = MY_CLASS(oc);
|
||||
|
||||
mc->do_something = my_do_something;
|
||||
}
|
||||
|
||||
static const TypeInfo my_type_info = {
|
||||
.name = TYPE_MY,
|
||||
.parent = TYPE_OBJECT,
|
||||
.instance_size = sizeof(MyState),
|
||||
.class_size = sizeof(MyClass),
|
||||
.class_init = my_class_init,
|
||||
};
|
||||
|
||||
typedef struct DerivedClass {
|
||||
MyClass parent_class;
|
||||
|
||||
MyDoSomething parent_do_something;
|
||||
} DerivedClass;
|
||||
|
||||
static void derived_do_something(MyState *obj)
|
||||
{
|
||||
DerivedClass *dc = DERIVED_GET_CLASS(obj);
|
||||
|
||||
// do something here
|
||||
dc->parent_do_something(obj);
|
||||
// do something else here
|
||||
}
|
||||
|
||||
static void derived_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MyClass *mc = MY_CLASS(oc);
|
||||
DerivedClass *dc = DERIVED_CLASS(oc);
|
||||
|
||||
dc->parent_do_something = mc->do_something;
|
||||
mc->do_something = derived_do_something;
|
||||
}
|
||||
|
||||
static const TypeInfo derived_type_info = {
|
||||
.name = TYPE_DERIVED,
|
||||
.parent = TYPE_MY,
|
||||
.class_size = sizeof(DerivedClass),
|
||||
.class_init = derived_class_init,
|
||||
};
|
||||
|
||||
Alternatively, object_class_by_name() can be used to obtain the class and
|
||||
its non-overridden methods for a specific type. This would correspond to
|
||||
``MyClass::method(...)`` in C++.
|
||||
|
||||
The first example of such a QOM method was #CPUClass.reset,
|
||||
another example is #DeviceClass.realize.
|
||||
|
||||
Standard type declaration and definition macros
|
||||
===============================================
|
||||
|
||||
A lot of the code outlined above follows a standard pattern and naming
|
||||
convention. To reduce the amount of boilerplate code that needs to be
|
||||
written for a new type there are two sets of macros to generate the
|
||||
common parts in a standard format.
|
||||
|
||||
A type is declared using the OBJECT_DECLARE macro family. In types
|
||||
which do not require any virtual functions in the class, the
|
||||
OBJECT_DECLARE_SIMPLE_TYPE macro is suitable, and is commonly placed
|
||||
in the header file:
|
||||
|
||||
.. code-block:: c
|
||||
:caption: Declaring a simple type
|
||||
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(MyDevice, my_device, MY_DEVICE, DEVICE)
|
||||
|
||||
This is equivalent to the following:
|
||||
|
||||
.. code-block:: c
|
||||
:caption: Expansion from declaring a simple type
|
||||
|
||||
typedef struct MyDevice MyDevice;
|
||||
typedef struct MyDeviceClass MyDeviceClass;
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(MyDeviceClass, object_unref)
|
||||
|
||||
#define MY_DEVICE_GET_CLASS(void *obj) \
|
||||
OBJECT_GET_CLASS(MyDeviceClass, obj, TYPE_MY_DEVICE)
|
||||
#define MY_DEVICE_CLASS(void *klass) \
|
||||
OBJECT_CLASS_CHECK(MyDeviceClass, klass, TYPE_MY_DEVICE)
|
||||
#define MY_DEVICE(void *obj)
|
||||
OBJECT_CHECK(MyDevice, obj, TYPE_MY_DEVICE)
|
||||
|
||||
struct MyDeviceClass {
|
||||
DeviceClass parent_class;
|
||||
};
|
||||
|
||||
The 'struct MyDevice' needs to be declared separately.
|
||||
If the type requires virtual functions to be declared in the class
|
||||
struct, then the alternative OBJECT_DECLARE_TYPE() macro can be
|
||||
used. This does the same as OBJECT_DECLARE_SIMPLE_TYPE(), but without
|
||||
the 'struct MyDeviceClass' definition.
|
||||
|
||||
To implement the type, the OBJECT_DEFINE macro family is available.
|
||||
In the simple case the OBJECT_DEFINE_TYPE macro is suitable:
|
||||
|
||||
.. code-block:: c
|
||||
:caption: Defining a simple type
|
||||
|
||||
OBJECT_DEFINE_TYPE(MyDevice, my_device, MY_DEVICE, DEVICE)
|
||||
|
||||
This is equivalent to the following:
|
||||
|
||||
.. code-block:: c
|
||||
:caption: Expansion from defining a simple type
|
||||
|
||||
static void my_device_finalize(Object *obj);
|
||||
static void my_device_class_init(ObjectClass *oc, void *data);
|
||||
static void my_device_init(Object *obj);
|
||||
|
||||
static const TypeInfo my_device_info = {
|
||||
.parent = TYPE_DEVICE,
|
||||
.name = TYPE_MY_DEVICE,
|
||||
.instance_size = sizeof(MyDevice),
|
||||
.instance_init = my_device_init,
|
||||
.instance_finalize = my_device_finalize,
|
||||
.class_size = sizeof(MyDeviceClass),
|
||||
.class_init = my_device_class_init,
|
||||
};
|
||||
|
||||
static void
|
||||
my_device_register_types(void)
|
||||
{
|
||||
type_register_static(&my_device_info);
|
||||
}
|
||||
type_init(my_device_register_types);
|
||||
|
||||
This is sufficient to get the type registered with the type
|
||||
system, and the three standard methods now need to be implemented
|
||||
along with any other logic required for the type.
|
||||
|
||||
If the type needs to implement one or more interfaces, then the
|
||||
OBJECT_DEFINE_TYPE_WITH_INTERFACES() macro can be used instead.
|
||||
This accepts an array of interface type names.
|
||||
|
||||
.. code-block:: c
|
||||
:caption: Defining a simple type implementing interfaces
|
||||
|
||||
OBJECT_DEFINE_TYPE_WITH_INTERFACES(MyDevice, my_device,
|
||||
MY_DEVICE, DEVICE,
|
||||
{ TYPE_USER_CREATABLE }, { NULL })
|
||||
|
||||
If the type is not intended to be instantiated, then then
|
||||
the OBJECT_DEFINE_ABSTRACT_TYPE() macro can be used instead:
|
||||
|
||||
.. code-block:: c
|
||||
:caption: Defining a simple abstract type
|
||||
|
||||
OBJECT_DEFINE_ABSTRACT_TYPE(MyDevice, my_device, MY_DEVICE, DEVICE)
|
||||
|
||||
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. kernel-doc:: include/qom/object.h
|
||||
+37
-20
@@ -92,26 +92,6 @@ error in the future.
|
||||
The ``-realtime mlock=on|off`` argument has been replaced by the
|
||||
``-overcommit mem-lock=on|off`` argument.
|
||||
|
||||
``-numa`` node (without memory specified) (since 4.1)
|
||||
'''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
Splitting RAM by default between NUMA nodes has the same issues as ``mem``
|
||||
parameter described above with the difference that the role of the user plays
|
||||
QEMU using implicit generic or board specific splitting rule.
|
||||
Use ``memdev`` with *memory-backend-ram* backend or ``mem`` (if
|
||||
it's supported by used machine type) to define mapping explicitly instead.
|
||||
|
||||
``-mem-path`` fallback to RAM (since 4.1)
|
||||
'''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
Currently if guest RAM allocation from file pointed by ``mem-path``
|
||||
fails, QEMU falls back to allocating from RAM, which might result
|
||||
in unpredictable behavior since the backing file specified by the user
|
||||
is ignored. In the future, users will be responsible for making sure
|
||||
the backing storage specified with ``-mem-path`` can actually provide
|
||||
the guest RAM configured with ``-m`` and QEMU will fail to start up if
|
||||
RAM allocation is unsuccessful.
|
||||
|
||||
RISC-V ``-bios`` (since 5.1)
|
||||
''''''''''''''''''''''''''''
|
||||
|
||||
@@ -612,6 +592,33 @@ error when ``-u`` is not used.
|
||||
Command line options
|
||||
--------------------
|
||||
|
||||
``-smp`` (invalid topologies) (removed 5.2)
|
||||
'''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
CPU topology properties should describe whole machine topology including
|
||||
possible CPUs.
|
||||
|
||||
However, historically it was possible to start QEMU with an incorrect topology
|
||||
where *n* <= *sockets* * *cores* * *threads* < *maxcpus*,
|
||||
which could lead to an incorrect topology enumeration by the guest.
|
||||
Support for invalid topologies is removed, the user must ensure
|
||||
topologies described with -smp include all possible cpus, i.e.
|
||||
*sockets* * *cores* * *threads* = *maxcpus*.
|
||||
|
||||
``-numa`` node (without memory specified) (removed 5.2)
|
||||
'''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
Splitting RAM by default between NUMA nodes had the same issues as ``mem``
|
||||
parameter with the difference that the role of the user plays QEMU using
|
||||
implicit generic or board specific splitting rule.
|
||||
Use ``memdev`` with *memory-backend-ram* backend or ``mem`` (if
|
||||
it's supported by used machine type) to define mapping explictly instead.
|
||||
Users of existing VMs, wishing to preserve the same RAM distribution, should
|
||||
configure it explicitly using ``-numa node,memdev`` options. Current RAM
|
||||
distribution can be retrieved using HMP command ``info numa`` and if separate
|
||||
memory devices (pc|nv-dimm) are present use ``info memory-device`` and subtract
|
||||
device memory from output of ``info numa``.
|
||||
|
||||
``-numa node,mem=``\ *size* (removed in 5.1)
|
||||
''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
@@ -629,6 +636,16 @@ New machine versions (since 5.1) will not accept the option but it will still
|
||||
work with old machine types. User can check the QAPI schema to see if the legacy
|
||||
option is supported by looking at MachineInfo::numa-mem-supported property.
|
||||
|
||||
``-mem-path`` fallback to RAM (removed in 5.0)
|
||||
''''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
If guest RAM allocation from file pointed by ``mem-path`` failed,
|
||||
QEMU was falling back to allocating from RAM, which might have resulted
|
||||
in unpredictable behavior since the backing file specified by the user
|
||||
as ignored. Currently, users are responsible for making sure the backing storage
|
||||
specified with ``-mem-path`` can actually provide the guest RAM configured with
|
||||
``-m`` and QEMU fails to start up if RAM allocation is unsuccessful.
|
||||
|
||||
``-smp`` (invalid topologies) (removed 5.2)
|
||||
'''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
|
||||
@@ -3137,7 +3137,7 @@ static bool prepare_mmio_access(MemoryRegion *mr)
|
||||
bool unlocked = !qemu_mutex_iothread_locked();
|
||||
bool release_lock = false;
|
||||
|
||||
if (unlocked && mr->global_locking) {
|
||||
if (unlocked) {
|
||||
qemu_mutex_lock_iothread();
|
||||
unlocked = false;
|
||||
release_lock = true;
|
||||
|
||||
@@ -116,8 +116,6 @@ static Property serial_isa_properties[] = {
|
||||
DEFINE_PROP_UINT32("index", ISASerialState, index, -1),
|
||||
DEFINE_PROP_UINT32("iobase", ISASerialState, iobase, -1),
|
||||
DEFINE_PROP_UINT32("irq", ISASerialState, isairq, -1),
|
||||
DEFINE_PROP_CHR("chardev", ISASerialState, state.chr),
|
||||
DEFINE_PROP_UINT32("wakeup", ISASerialState, state.wakeup, 0),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
@@ -138,6 +136,8 @@ static void serial_isa_initfn(Object *o)
|
||||
ISASerialState *self = ISA_SERIAL(o);
|
||||
|
||||
object_initialize_child(o, "serial", &self->state, TYPE_SERIAL);
|
||||
|
||||
qdev_alias_all_properties(DEVICE(&self->state), o);
|
||||
}
|
||||
|
||||
static const TypeInfo serial_isa_info = {
|
||||
|
||||
@@ -82,7 +82,6 @@ static const VMStateDescription vmstate_pci_serial = {
|
||||
};
|
||||
|
||||
static Property serial_pci_properties[] = {
|
||||
DEFINE_PROP_CHR("chardev", PCISerialState, state.chr),
|
||||
DEFINE_PROP_UINT8("prog_if", PCISerialState, prog_if, 0x02),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
@@ -107,6 +106,8 @@ static void serial_pci_init(Object *o)
|
||||
PCISerialState *ps = PCI_SERIAL(o);
|
||||
|
||||
object_initialize_child(o, "serial", &ps->state, TYPE_SERIAL);
|
||||
|
||||
qdev_alias_all_properties(DEVICE(&ps->state), o);
|
||||
}
|
||||
|
||||
static const TypeInfo serial_pci_info = {
|
||||
|
||||
+6
-59
@@ -36,8 +36,6 @@
|
||||
#include "trace.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
|
||||
//#define DEBUG_SERIAL
|
||||
|
||||
#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
|
||||
|
||||
#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */
|
||||
@@ -102,14 +100,6 @@
|
||||
|
||||
#define MAX_XMIT_RETRY 4
|
||||
|
||||
#ifdef DEBUG_SERIAL
|
||||
#define DPRINTF(fmt, ...) \
|
||||
do { fprintf(stderr, "serial: " fmt , ## __VA_ARGS__); } while (0)
|
||||
#else
|
||||
#define DPRINTF(fmt, ...) \
|
||||
do {} while (0)
|
||||
#endif
|
||||
|
||||
static void serial_receive1(void *opaque, const uint8_t *buf, int size);
|
||||
static void serial_xmit(SerialState *s);
|
||||
|
||||
@@ -187,9 +177,7 @@ static void serial_update_parameters(SerialState *s)
|
||||
ssp.stop_bits = stop_bits;
|
||||
s->char_transmit_time = (NANOSECONDS_PER_SECOND / speed) * frame_size;
|
||||
qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
|
||||
|
||||
DPRINTF("speed=%.2f parity=%c data=%d stop=%d\n",
|
||||
speed, parity, data_bits, stop_bits);
|
||||
trace_serial_update_parameters(speed, parity, data_bits, stop_bits);
|
||||
}
|
||||
|
||||
static void serial_update_msl(SerialState *s)
|
||||
@@ -344,8 +332,8 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
{
|
||||
SerialState *s = opaque;
|
||||
|
||||
addr &= 7;
|
||||
trace_serial_ioport_write(addr, val);
|
||||
assert(size == 1 && addr < 8);
|
||||
trace_serial_write(addr, val);
|
||||
switch(addr) {
|
||||
default:
|
||||
case 0:
|
||||
@@ -485,7 +473,7 @@ static uint64_t serial_ioport_read(void *opaque, hwaddr addr, unsigned size)
|
||||
SerialState *s = opaque;
|
||||
uint32_t ret;
|
||||
|
||||
addr &= 7;
|
||||
assert(size == 1 && addr < 8);
|
||||
switch(addr) {
|
||||
default:
|
||||
case 0:
|
||||
@@ -562,7 +550,7 @@ static uint64_t serial_ioport_read(void *opaque, hwaddr addr, unsigned size)
|
||||
ret = s->scr;
|
||||
break;
|
||||
}
|
||||
trace_serial_ioport_read(addr, ret);
|
||||
trace_serial_read(addr, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -638,7 +626,6 @@ static void serial_receive1(void *opaque, const uint8_t *buf, int size)
|
||||
static void serial_event(void *opaque, QEMUChrEvent event)
|
||||
{
|
||||
SerialState *s = opaque;
|
||||
DPRINTF("event %x\n", event);
|
||||
if (event == CHR_EVENT_BREAK)
|
||||
serial_receive_break(s);
|
||||
}
|
||||
@@ -985,49 +972,10 @@ const MemoryRegionOps serial_io_ops = {
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static void serial_io_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
SerialIO *sio = SERIAL_IO(dev);
|
||||
SerialState *s = &sio->serial;
|
||||
|
||||
if (!qdev_realize(DEVICE(s), NULL, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
memory_region_init_io(&s->io, OBJECT(dev), &serial_io_ops, s, "serial", 8);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(sio), &s->io);
|
||||
sysbus_init_irq(SYS_BUS_DEVICE(sio), &s->irq);
|
||||
}
|
||||
|
||||
static void serial_io_class_init(ObjectClass *klass, void* data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = serial_io_realize;
|
||||
/* No dc->vmsd: class has no migratable state */
|
||||
}
|
||||
|
||||
static void serial_io_instance_init(Object *o)
|
||||
{
|
||||
SerialIO *sio = SERIAL_IO(o);
|
||||
|
||||
object_initialize_child(o, "serial", &sio->serial, TYPE_SERIAL);
|
||||
|
||||
qdev_alias_all_properties(DEVICE(&sio->serial), o);
|
||||
}
|
||||
|
||||
|
||||
static const TypeInfo serial_io_info = {
|
||||
.name = TYPE_SERIAL_IO,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(SerialIO),
|
||||
.instance_init = serial_io_instance_init,
|
||||
.class_init = serial_io_class_init,
|
||||
};
|
||||
|
||||
static Property serial_properties[] = {
|
||||
DEFINE_PROP_CHR("chardev", SerialState, chr),
|
||||
DEFINE_PROP_UINT32("baudbase", SerialState, baudbase, 115200),
|
||||
DEFINE_PROP_BOOL("wakeup", SerialState, wakeup, false),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
@@ -1178,7 +1126,6 @@ static const TypeInfo serial_mm_info = {
|
||||
static void serial_register_types(void)
|
||||
{
|
||||
type_register_static(&serial_info);
|
||||
type_register_static(&serial_io_info);
|
||||
type_register_static(&serial_mm_info);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,8 +5,9 @@ parallel_ioport_read(const char *desc, uint16_t addr, uint8_t value) "read [%s]
|
||||
parallel_ioport_write(const char *desc, uint16_t addr, uint8_t value) "write [%s] addr 0x%02x val 0x%02x"
|
||||
|
||||
# serial.c
|
||||
serial_ioport_read(uint16_t addr, uint8_t value) "read addr 0x%02x val 0x%02x"
|
||||
serial_ioport_write(uint16_t addr, uint8_t value) "write addr 0x%02x val 0x%02x"
|
||||
serial_read(uint16_t addr, uint8_t value) "read addr 0x%02x val 0x%02x"
|
||||
serial_write(uint16_t addr, uint8_t value) "write addr 0x%02x val 0x%02x"
|
||||
serial_update_parameters(uint64_t baudrate, char parity, int data_bits, int stop_bits) "baudrate=%"PRIu64" parity='%c' data=%d stop=%d"
|
||||
|
||||
# virtio-serial-bus.c
|
||||
virtio_serial_send_control_event(unsigned int port, uint16_t event, uint16_t value) "port %u, event %u, value %u"
|
||||
|
||||
@@ -790,7 +790,6 @@ static void machine_class_init(ObjectClass *oc, void *data)
|
||||
* On Linux, each node's border has to be 8MB aligned
|
||||
*/
|
||||
mc->numa_mem_align_shift = 23;
|
||||
mc->numa_auto_assign_ram = numa_default_auto_assign_ram;
|
||||
|
||||
object_class_property_add_str(oc, "kernel",
|
||||
machine_get_kernel, machine_set_kernel);
|
||||
|
||||
@@ -611,42 +611,6 @@ static void complete_init_numa_distance(MachineState *ms)
|
||||
}
|
||||
}
|
||||
|
||||
void numa_legacy_auto_assign_ram(MachineClass *mc, NodeInfo *nodes,
|
||||
int nb_nodes, ram_addr_t size)
|
||||
{
|
||||
int i;
|
||||
uint64_t usedmem = 0;
|
||||
|
||||
/* Align each node according to the alignment
|
||||
* requirements of the machine class
|
||||
*/
|
||||
|
||||
for (i = 0; i < nb_nodes - 1; i++) {
|
||||
nodes[i].node_mem = (size / nb_nodes) &
|
||||
~((1 << mc->numa_mem_align_shift) - 1);
|
||||
usedmem += nodes[i].node_mem;
|
||||
}
|
||||
nodes[i].node_mem = size - usedmem;
|
||||
}
|
||||
|
||||
void numa_default_auto_assign_ram(MachineClass *mc, NodeInfo *nodes,
|
||||
int nb_nodes, ram_addr_t size)
|
||||
{
|
||||
int i;
|
||||
uint64_t usedmem = 0, node_mem;
|
||||
uint64_t granularity = size / nb_nodes;
|
||||
uint64_t propagate = 0;
|
||||
|
||||
for (i = 0; i < nb_nodes - 1; i++) {
|
||||
node_mem = (granularity + propagate) &
|
||||
~((1 << mc->numa_mem_align_shift) - 1);
|
||||
propagate = granularity + propagate - node_mem;
|
||||
nodes[i].node_mem = node_mem;
|
||||
usedmem += node_mem;
|
||||
}
|
||||
nodes[i].node_mem = size - usedmem;
|
||||
}
|
||||
|
||||
static void numa_init_memdev_container(MachineState *ms, MemoryRegion *ram)
|
||||
{
|
||||
int i;
|
||||
@@ -713,29 +677,6 @@ void numa_complete_configuration(MachineState *ms)
|
||||
if (ms->numa_state->num_nodes > 0) {
|
||||
uint64_t numa_total;
|
||||
|
||||
if (ms->numa_state->num_nodes > MAX_NODES) {
|
||||
ms->numa_state->num_nodes = MAX_NODES;
|
||||
}
|
||||
|
||||
/* If no memory size is given for any node, assume the default case
|
||||
* and distribute the available memory equally across all nodes
|
||||
*/
|
||||
for (i = 0; i < ms->numa_state->num_nodes; i++) {
|
||||
if (numa_info[i].node_mem != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == ms->numa_state->num_nodes) {
|
||||
assert(mc->numa_auto_assign_ram);
|
||||
mc->numa_auto_assign_ram(mc, numa_info,
|
||||
ms->numa_state->num_nodes, ram_size);
|
||||
if (!qtest_enabled()) {
|
||||
warn_report("Default splitting of RAM between nodes is deprecated,"
|
||||
" Use '-numa node,memdev' to explictly define RAM"
|
||||
" allocation per node");
|
||||
}
|
||||
}
|
||||
|
||||
numa_total = 0;
|
||||
for (i = 0; i < ms->numa_state->num_nodes; i++) {
|
||||
numa_total += numa_info[i].node_mem;
|
||||
|
||||
@@ -990,7 +990,6 @@ static Aml *build_vmbus_device_aml(VMBusBridge *vmbus_bridge)
|
||||
|
||||
static void build_isa_devices_aml(Aml *table)
|
||||
{
|
||||
VMBusBridge *vmbus_bridge = vmbus_bridge_find();
|
||||
bool ambiguous;
|
||||
Object *obj = object_resolve_path_type("", TYPE_ISA_BUS, &ambiguous);
|
||||
Aml *scope;
|
||||
@@ -1001,10 +1000,6 @@ static void build_isa_devices_aml(Aml *table)
|
||||
build_acpi_ipmi_devices(scope, BUS(obj), "\\_SB.PCI0.ISA");
|
||||
isa_build_aml(ISA_BUS(obj), scope);
|
||||
|
||||
if (vmbus_bridge) {
|
||||
aml_append(scope, build_vmbus_device_aml(vmbus_bridge));
|
||||
}
|
||||
|
||||
aml_append(table, scope);
|
||||
}
|
||||
|
||||
@@ -1500,6 +1495,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
||||
PCIBus *bus = NULL;
|
||||
TPMIf *tpm = tpm_find();
|
||||
int i;
|
||||
VMBusBridge *vmbus_bridge = vmbus_bridge_find();
|
||||
|
||||
dsdt = init_aml_allocator();
|
||||
|
||||
@@ -1569,6 +1565,12 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
||||
}
|
||||
}
|
||||
|
||||
if (vmbus_bridge) {
|
||||
sb_scope = aml_scope("_SB");
|
||||
aml_append(sb_scope, build_vmbus_device_aml(vmbus_bridge));
|
||||
aml_append(dsdt, sb_scope);
|
||||
}
|
||||
|
||||
if (pcmc->legacy_cpu_hotplug) {
|
||||
build_legacy_cpu_hotplug_aml(dsdt, machine, pm->cpu_hp_io_base);
|
||||
} else {
|
||||
|
||||
+5
-2
@@ -329,11 +329,14 @@ static const TypeInfo kvmclock_info = {
|
||||
};
|
||||
|
||||
/* Note: Must be called after VCPU initialization. */
|
||||
void kvmclock_create(void)
|
||||
void kvmclock_create(bool create_always)
|
||||
{
|
||||
X86CPU *cpu = X86_CPU(first_cpu);
|
||||
|
||||
if (kvm_enabled() &&
|
||||
if (!kvm_enabled() || !kvm_has_adjust_clock())
|
||||
return;
|
||||
|
||||
if (create_always ||
|
||||
cpu->env.features[FEAT_KVM] & ((1ULL << KVM_FEATURE_CLOCKSOURCE) |
|
||||
(1ULL << KVM_FEATURE_CLOCKSOURCE2))) {
|
||||
sysbus_create_simple(TYPE_KVM_CLOCK, -1, NULL);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user