mirror of
https://github.com/xemu-project/xemu.git
synced 2025-02-12 23:58:38 +00:00
* 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) -----BEGIN PGP SIGNATURE----- iQFIBAABCAAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAl90vFEUHHBib256aW5p QHJlZGhhdC5jb20ACgkQv/vSX3jHroOyZwf/e/tS0X4czuqTzlfU1X9hX4KbavFn zXs5gfhNlXak4Le6X4fFHGXLRdQi0QX2RaWN5mw4AiUDWyyyzyt8aUJKNPgJ6XYT UK2zWJ7NizUE8K7okEeW22IjaY9BgMqFiqroCmZPqM2Q+85TLa8cy2iAXbBU2bXI PKXPlE20EwsIdlVNJewUANfE7V05/x/XIePNsC7ERNV9Gwa4IGdABcCiNbjga5ES uGAopZeliOaPDLnBW/RH1O8v4oAhq9oVTDnKOedfnruHyT+BxZlOEcbWFQ5LJD6B Zz0khCFLtcBc+BywOFVOeboeNbLpR42SbhHogpQhf4/PBwHTmiTATTrv5g== =RafH -----END PGP SIGNATURE----- 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:
commit
37a712a0f9
18
MAINTAINERS
18
MAINTAINERS
@ -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
|
||||
|
4
Makefile
4
Makefile
@ -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 ''
|
||||
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
237
configure
vendored
237
configure
vendored
@ -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 \
|
||||
|
113
docs/can.txt
113
docs/can.txt
@ -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
|
||||
|
378
docs/devel/qom.rst
Normal file
378
docs/devel/qom.rst
Normal file
@ -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
|
@ -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)
|
||||
'''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
|
2
exec.c
2
exec.c
@ -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 = {
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -125,7 +125,7 @@ static void microvm_devices_init(MicrovmMachineState *mms)
|
||||
|
||||
ioapic_init_gsi(gsi_state, "machine");
|
||||
|
||||
kvmclock_create();
|
||||
kvmclock_create(true);
|
||||
|
||||
mms->virtio_irq_base = x86_machine_is_acpi_enabled(x86ms) ? 16 : 5;
|
||||
for (i = 0; i < VIRTIO_NUM_TRANSPORTS; i++) {
|
||||
|
@ -1657,6 +1657,7 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)
|
||||
pcmc->acpi_data_size = 0x20000 + 0x8000;
|
||||
pcmc->linuxboot_dma_enabled = true;
|
||||
pcmc->pvh_enabled = true;
|
||||
pcmc->kvmclock_create_always = true;
|
||||
assert(!mc->get_hotplug_handler);
|
||||
mc->get_hotplug_handler = pc_get_hotplug_handler;
|
||||
mc->hotplug_allowed = pc_hotplug_allowed;
|
||||
|
@ -46,7 +46,7 @@
|
||||
#include "hw/sysbus.h"
|
||||
#include "sysemu/arch_init.h"
|
||||
#include "hw/i2c/smbus_eeprom.h"
|
||||
#include "hw/xen/xen.h"
|
||||
#include "hw/xen/xen-x86.h"
|
||||
#include "exec/memory.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/acpi/acpi.h"
|
||||
@ -117,8 +117,8 @@ static void pc_init1(MachineState *machine,
|
||||
* so legacy non-PAE guests can get as much memory as possible in
|
||||
* the 32bit address space below 4G.
|
||||
*
|
||||
* - Note that Xen has its own ram setp code in xen_ram_init(),
|
||||
* called via xen_hvm_init().
|
||||
* - Note that Xen has its own ram setup code in xen_ram_init(),
|
||||
* called via xen_hvm_init_pc().
|
||||
*
|
||||
* Examples:
|
||||
* qemu -M pc-1.7 -m 4G (old default) -> 3584M low, 512M high
|
||||
@ -127,7 +127,7 @@ static void pc_init1(MachineState *machine,
|
||||
* qemu -M pc,max-ram-below-4g=4G -m 3968M -> 3968M low (=4G-128M)
|
||||
*/
|
||||
if (xen_enabled()) {
|
||||
xen_hvm_init(pcms, &ram_memory);
|
||||
xen_hvm_init_pc(pcms, &ram_memory);
|
||||
} else {
|
||||
if (!pcms->max_ram_below_4g) {
|
||||
pcms->max_ram_below_4g = 0xe0000000; /* default: 3.5G */
|
||||
@ -158,8 +158,8 @@ static void pc_init1(MachineState *machine,
|
||||
|
||||
x86_cpus_init(x86ms, pcmc->default_cpu_version);
|
||||
|
||||
if (kvm_enabled() && pcmc->kvmclock_enabled) {
|
||||
kvmclock_create();
|
||||
if (pcmc->kvmclock_enabled) {
|
||||
kvmclock_create(pcmc->kvmclock_create_always);
|
||||
}
|
||||
|
||||
if (pcmc->pci_enabled) {
|
||||
@ -440,11 +440,14 @@ DEFINE_I440FX_MACHINE(v5_2, "pc-i440fx-5.2", NULL,
|
||||
|
||||
static void pc_i440fx_5_1_machine_options(MachineClass *m)
|
||||
{
|
||||
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
|
||||
|
||||
pc_i440fx_5_2_machine_options(m);
|
||||
m->alias = NULL;
|
||||
m->is_default = false;
|
||||
compat_props_add(m->compat_props, hw_compat_5_1, hw_compat_5_1_len);
|
||||
compat_props_add(m->compat_props, pc_compat_5_1, pc_compat_5_1_len);
|
||||
pcmc->kvmclock_create_always = false;
|
||||
}
|
||||
|
||||
DEFINE_I440FX_MACHINE(v5_1, "pc-i440fx-5.1", NULL,
|
||||
@ -565,7 +568,6 @@ static void pc_i440fx_2_9_machine_options(MachineClass *m)
|
||||
pc_i440fx_2_10_machine_options(m);
|
||||
compat_props_add(m->compat_props, hw_compat_2_9, hw_compat_2_9_len);
|
||||
compat_props_add(m->compat_props, pc_compat_2_9, pc_compat_2_9_len);
|
||||
m->numa_auto_assign_ram = numa_legacy_auto_assign_ram;
|
||||
}
|
||||
|
||||
DEFINE_I440FX_MACHINE(v2_9, "pc-i440fx-2.9", NULL,
|
||||
|
@ -34,9 +34,7 @@
|
||||
#include "sysemu/arch_init.h"
|
||||
#include "hw/i2c/smbus_eeprom.h"
|
||||
#include "hw/rtc/mc146818rtc.h"
|
||||
#include "hw/xen/xen.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "sysemu/xen.h"
|
||||
#include "hw/kvm/clock.h"
|
||||
#include "hw/pci-host/q35.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
@ -179,13 +177,9 @@ static void pc_q35_init(MachineState *machine)
|
||||
x86ms->below_4g_mem_size = machine->ram_size;
|
||||
}
|
||||
|
||||
if (xen_enabled()) {
|
||||
xen_hvm_init(pcms, &ram_memory);
|
||||
}
|
||||
|
||||
x86_cpus_init(x86ms, pcmc->default_cpu_version);
|
||||
|
||||
kvmclock_create();
|
||||
kvmclock_create(pcmc->kvmclock_create_always);
|
||||
|
||||
/* pci enabled */
|
||||
if (pcmc->pci_enabled) {
|
||||
@ -208,10 +202,7 @@ static void pc_q35_init(MachineState *machine)
|
||||
}
|
||||
|
||||
/* allocate ram and load rom/bios */
|
||||
if (!xen_enabled()) {
|
||||
pc_memory_init(pcms, get_system_memory(),
|
||||
rom_memory, &ram_memory);
|
||||
}
|
||||
pc_memory_init(pcms, get_system_memory(), rom_memory, &ram_memory);
|
||||
|
||||
/* create pci host bus */
|
||||
q35_host = Q35_HOST_DEVICE(qdev_new(TYPE_Q35_HOST_DEVICE));
|
||||
@ -271,7 +262,7 @@ static void pc_q35_init(MachineState *machine)
|
||||
|
||||
assert(pcms->vmport != ON_OFF_AUTO__MAX);
|
||||
if (pcms->vmport == ON_OFF_AUTO_AUTO) {
|
||||
pcms->vmport = xen_enabled() ? ON_OFF_AUTO_OFF : ON_OFF_AUTO_ON;
|
||||
pcms->vmport = ON_OFF_AUTO_ON;
|
||||
}
|
||||
|
||||
/* init basic PC hardware */
|
||||
@ -366,10 +357,13 @@ DEFINE_Q35_MACHINE(v5_2, "pc-q35-5.2", NULL,
|
||||
|
||||
static void pc_q35_5_1_machine_options(MachineClass *m)
|
||||
{
|
||||
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
|
||||
|
||||
pc_q35_5_2_machine_options(m);
|
||||
m->alias = NULL;
|
||||
compat_props_add(m->compat_props, hw_compat_5_1, hw_compat_5_1_len);
|
||||
compat_props_add(m->compat_props, pc_compat_5_1, pc_compat_5_1_len);
|
||||
pcmc->kvmclock_create_always = false;
|
||||
}
|
||||
|
||||
DEFINE_Q35_MACHINE(v5_1, "pc-q35-5.1", NULL,
|
||||
@ -494,7 +488,6 @@ static void pc_q35_2_10_machine_options(MachineClass *m)
|
||||
pc_q35_2_11_machine_options(m);
|
||||
compat_props_add(m->compat_props, hw_compat_2_10, hw_compat_2_10_len);
|
||||
compat_props_add(m->compat_props, pc_compat_2_10, pc_compat_2_10_len);
|
||||
m->numa_auto_assign_ram = numa_legacy_auto_assign_ram;
|
||||
m->auto_enable_numa_with_memhp = false;
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "hw/xen/xen_common.h"
|
||||
#include "hw/xen/xen-legacy-backend.h"
|
||||
#include "hw/xen/xen-bus.h"
|
||||
#include "hw/xen/xen-x86.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qapi-commands-misc.h"
|
||||
#include "qemu/error-report.h"
|
||||
@ -1395,7 +1396,7 @@ static int xen_map_ioreq_server(XenIOState *state)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void xen_hvm_init(PCMachineState *pcms, MemoryRegion **ram_memory)
|
||||
void xen_hvm_init_pc(PCMachineState *pcms, MemoryRegion **ram_memory)
|
||||
{
|
||||
MachineState *ms = MACHINE(pcms);
|
||||
unsigned int max_cpus = ms->smp.max_cpus;
|
||||
|
@ -216,10 +216,11 @@ mips_mipssim_init(MachineState *machine)
|
||||
* MIPS CPU INT2, which is interrupt 4.
|
||||
*/
|
||||
if (serial_hd(0)) {
|
||||
DeviceState *dev = qdev_new(TYPE_SERIAL_IO);
|
||||
DeviceState *dev = qdev_new(TYPE_SERIAL_MM);
|
||||
|
||||
qdev_prop_set_chr(dev, "chardev", serial_hd(0));
|
||||
qdev_set_legacy_instance_id(dev, 0x3f8, 2);
|
||||
qdev_prop_set_uint8(dev, "regshift", 0);
|
||||
qdev_prop_set_uint8(dev, "endianness", DEVICE_LITTLE_ENDIAN);
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, env->irq[4]);
|
||||
sysbus_add_io(SYS_BUS_DEVICE(dev), 0x3f8,
|
||||
|
@ -132,14 +132,24 @@ config ROCKER
|
||||
config CAN_BUS
|
||||
bool
|
||||
|
||||
config CAN_PCI
|
||||
bool
|
||||
default y if PCI_DEVICES
|
||||
depends on PCI
|
||||
select CAN_BUS
|
||||
|
||||
config CAN_SJA1000
|
||||
bool
|
||||
default y if PCI_DEVICES
|
||||
depends on PCI
|
||||
select CAN_BUS
|
||||
|
||||
config CAN_PCI
|
||||
bool
|
||||
default y if PCI_DEVICES
|
||||
depends on PCI && CAN_SJA1000
|
||||
select CAN_BUS
|
||||
|
||||
config CAN_CTUCANFD
|
||||
bool
|
||||
default y if PCI_DEVICES
|
||||
select CAN_BUS
|
||||
|
||||
config CAN_CTUCANFD_PCI
|
||||
bool
|
||||
default y if PCI_DEVICES
|
||||
depends on PCI && CAN_CTUCANFD
|
||||
select CAN_BUS
|
||||
|
@ -268,6 +268,7 @@ static void buff2frame_pel(const uint8_t *buff, qemu_can_frame *frame)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
frame->flags = 0;
|
||||
frame->can_id = 0;
|
||||
if (buff[0] & 0x40) { /* RTR */
|
||||
frame->can_id = QEMU_CAN_RTR_FLAG;
|
||||
@ -303,6 +304,7 @@ static void buff2frame_bas(const uint8_t *buff, qemu_can_frame *frame)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
frame->flags = 0;
|
||||
frame->can_id = ((buff[0] << 3) & (0xff << 3)) + ((buff[1] >> 5) & 0x07);
|
||||
if (buff[1] & 0x10) { /* RTR */
|
||||
frame->can_id = QEMU_CAN_RTR_FLAG;
|
||||
@ -321,11 +323,16 @@ static void buff2frame_bas(const uint8_t *buff, qemu_can_frame *frame)
|
||||
static int frame2buff_pel(const qemu_can_frame *frame, uint8_t *buff)
|
||||
{
|
||||
int i;
|
||||
int dlen = frame->can_dlc;
|
||||
|
||||
if (frame->can_id & QEMU_CAN_ERR_FLAG) { /* error frame, NOT support now. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dlen > 8) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
buff[0] = 0x0f & frame->can_dlc; /* DLC */
|
||||
if (frame->can_id & QEMU_CAN_RTR_FLAG) { /* RTR */
|
||||
buff[0] |= (1 << 6);
|
||||
@ -336,18 +343,18 @@ static int frame2buff_pel(const qemu_can_frame *frame, uint8_t *buff)
|
||||
buff[2] = extract32(frame->can_id, 13, 8); /* ID.20~ID.13 */
|
||||
buff[3] = extract32(frame->can_id, 5, 8); /* ID.12~ID.05 */
|
||||
buff[4] = extract32(frame->can_id, 0, 5) << 3; /* ID.04~ID.00,xxx */
|
||||
for (i = 0; i < frame->can_dlc; i++) {
|
||||
for (i = 0; i < dlen; i++) {
|
||||
buff[5 + i] = frame->data[i];
|
||||
}
|
||||
return frame->can_dlc + 5;
|
||||
return dlen + 5;
|
||||
} else { /* SFF */
|
||||
buff[1] = extract32(frame->can_id, 3, 8); /* ID.10~ID.03 */
|
||||
buff[2] = extract32(frame->can_id, 0, 3) << 5; /* ID.02~ID.00,xxxxx */
|
||||
for (i = 0; i < frame->can_dlc; i++) {
|
||||
for (i = 0; i < dlen; i++) {
|
||||
buff[3 + i] = frame->data[i];
|
||||
}
|
||||
|
||||
return frame->can_dlc + 3;
|
||||
return dlen + 3;
|
||||
}
|
||||
|
||||
return -1;
|
||||
@ -356,6 +363,7 @@ static int frame2buff_pel(const qemu_can_frame *frame, uint8_t *buff)
|
||||
static int frame2buff_bas(const qemu_can_frame *frame, uint8_t *buff)
|
||||
{
|
||||
int i;
|
||||
int dlen = frame->can_dlc;
|
||||
|
||||
/*
|
||||
* EFF, no support for BasicMode
|
||||
@ -367,17 +375,21 @@ static int frame2buff_bas(const qemu_can_frame *frame, uint8_t *buff)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dlen > 8) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
buff[0] = extract32(frame->can_id, 3, 8); /* ID.10~ID.03 */
|
||||
buff[1] = extract32(frame->can_id, 0, 3) << 5; /* ID.02~ID.00,xxxxx */
|
||||
if (frame->can_id & QEMU_CAN_RTR_FLAG) { /* RTR */
|
||||
buff[1] |= (1 << 4);
|
||||
}
|
||||
buff[1] |= frame->can_dlc & 0x0f;
|
||||
for (i = 0; i < frame->can_dlc; i++) {
|
||||
for (i = 0; i < dlen; i++) {
|
||||
buff[2 + i] = frame->data[i];
|
||||
}
|
||||
|
||||
return frame->can_dlc + 2;
|
||||
return dlen + 2;
|
||||
}
|
||||
|
||||
static void can_sja_update_pel_irq(CanSJA1000State *s)
|
||||
@ -764,6 +776,13 @@ ssize_t can_sja_receive(CanBusClientState *client, const qemu_can_frame *frames,
|
||||
if (frames_cnt <= 0) {
|
||||
return 0;
|
||||
}
|
||||
if (frame->flags & QEMU_CAN_FRMF_TYPE_FD) {
|
||||
if (DEBUG_FILTER) {
|
||||
can_display_msg("[cansja]: ignor fd frame ", frame);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (DEBUG_FILTER) {
|
||||
can_display_msg("[cansja]: receive ", frame);
|
||||
}
|
||||
|
189
hw/net/can/ctu_can_fd_frame.h
Normal file
189
hw/net/can/ctu_can_fd_frame.h
Normal file
@ -0,0 +1,189 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*******************************************************************************
|
||||
*
|
||||
* CTU CAN FD IP Core
|
||||
*
|
||||
* Copyright (C) 2015-2018 Ondrej Ille <ondrej.ille@gmail.com> FEE CTU
|
||||
* Copyright (C) 2018-2020 Ondrej Ille <ondrej.ille@gmail.com> self-funded
|
||||
* Copyright (C) 2018-2019 Martin Jerabek <martin.jerabek01@gmail.com> FEE CTU
|
||||
* Copyright (C) 2018-2020 Pavel Pisa <pisa@cmp.felk.cvut.cz> FEE CTU/self-funded
|
||||
*
|
||||
* Project advisors:
|
||||
* Jiri Novak <jnovak@fel.cvut.cz>
|
||||
* Pavel Pisa <pisa@cmp.felk.cvut.cz>
|
||||
*
|
||||
* Department of Measurement (http://meas.fel.cvut.cz/)
|
||||
* Faculty of Electrical Engineering (http://www.fel.cvut.cz)
|
||||
* Czech Technical University (http://www.cvut.cz/)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
******************************************************************************/
|
||||
|
||||
/* This file is autogenerated, DO NOT EDIT! */
|
||||
|
||||
#ifndef __CTU_CAN_FD_CAN_FD_FRAME_FORMAT__
|
||||
#define __CTU_CAN_FD_CAN_FD_FRAME_FORMAT__
|
||||
|
||||
/* CAN_Frame_format memory map */
|
||||
enum ctu_can_fd_can_frame_format {
|
||||
CTU_CAN_FD_FRAME_FORM_W = 0x0,
|
||||
CTU_CAN_FD_IDENTIFIER_W = 0x4,
|
||||
CTU_CAN_FD_TIMESTAMP_L_W = 0x8,
|
||||
CTU_CAN_FD_TIMESTAMP_U_W = 0xc,
|
||||
CTU_CAN_FD_DATA_1_4_W = 0x10,
|
||||
CTU_CAN_FD_DATA_5_8_W = 0x14,
|
||||
CTU_CAN_FD_DATA_61_64_W = 0x4c,
|
||||
};
|
||||
|
||||
|
||||
/* Register descriptions: */
|
||||
union ctu_can_fd_frame_form_w {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_frame_form_w_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* FRAME_FORM_W */
|
||||
uint32_t dlc : 4;
|
||||
uint32_t reserved_4 : 1;
|
||||
uint32_t rtr : 1;
|
||||
uint32_t ide : 1;
|
||||
uint32_t fdf : 1;
|
||||
uint32_t reserved_8 : 1;
|
||||
uint32_t brs : 1;
|
||||
uint32_t esi_rsv : 1;
|
||||
uint32_t rwcnt : 5;
|
||||
uint32_t reserved_31_16 : 16;
|
||||
#else
|
||||
uint32_t reserved_31_16 : 16;
|
||||
uint32_t rwcnt : 5;
|
||||
uint32_t esi_rsv : 1;
|
||||
uint32_t brs : 1;
|
||||
uint32_t reserved_8 : 1;
|
||||
uint32_t fdf : 1;
|
||||
uint32_t ide : 1;
|
||||
uint32_t rtr : 1;
|
||||
uint32_t reserved_4 : 1;
|
||||
uint32_t dlc : 4;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
enum ctu_can_fd_frame_form_w_rtr {
|
||||
NO_RTR_FRAME = 0x0,
|
||||
RTR_FRAME = 0x1,
|
||||
};
|
||||
|
||||
enum ctu_can_fd_frame_form_w_ide {
|
||||
BASE = 0x0,
|
||||
EXTENDED = 0x1,
|
||||
};
|
||||
|
||||
enum ctu_can_fd_frame_form_w_fdf {
|
||||
NORMAL_CAN = 0x0,
|
||||
FD_CAN = 0x1,
|
||||
};
|
||||
|
||||
enum ctu_can_fd_frame_form_w_brs {
|
||||
BR_NO_SHIFT = 0x0,
|
||||
BR_SHIFT = 0x1,
|
||||
};
|
||||
|
||||
enum ctu_can_fd_frame_form_w_esi_rsv {
|
||||
ESI_ERR_ACTIVE = 0x0,
|
||||
ESI_ERR_PASIVE = 0x1,
|
||||
};
|
||||
|
||||
union ctu_can_fd_identifier_w {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_identifier_w_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* IDENTIFIER_W */
|
||||
uint32_t identifier_ext : 18;
|
||||
uint32_t identifier_base : 11;
|
||||
uint32_t reserved_31_29 : 3;
|
||||
#else
|
||||
uint32_t reserved_31_29 : 3;
|
||||
uint32_t identifier_base : 11;
|
||||
uint32_t identifier_ext : 18;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_timestamp_l_w {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_timestamp_l_w_s {
|
||||
/* TIMESTAMP_L_W */
|
||||
uint32_t time_stamp_31_0 : 32;
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_timestamp_u_w {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_timestamp_u_w_s {
|
||||
/* TIMESTAMP_U_W */
|
||||
uint32_t timestamp_l_w : 32;
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_data_1_4_w {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_data_1_4_w_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* DATA_1_4_W */
|
||||
uint32_t data_1 : 8;
|
||||
uint32_t data_2 : 8;
|
||||
uint32_t data_3 : 8;
|
||||
uint32_t data_4 : 8;
|
||||
#else
|
||||
uint32_t data_4 : 8;
|
||||
uint32_t data_3 : 8;
|
||||
uint32_t data_2 : 8;
|
||||
uint32_t data_1 : 8;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_data_5_8_w {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_data_5_8_w_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* DATA_5_8_W */
|
||||
uint32_t data_5 : 8;
|
||||
uint32_t data_6 : 8;
|
||||
uint32_t data_7 : 8;
|
||||
uint32_t data_8 : 8;
|
||||
#else
|
||||
uint32_t data_8 : 8;
|
||||
uint32_t data_7 : 8;
|
||||
uint32_t data_6 : 8;
|
||||
uint32_t data_5 : 8;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_data_61_64_w {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_data_61_64_w_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* DATA_61_64_W */
|
||||
uint32_t data_61 : 8;
|
||||
uint32_t data_62 : 8;
|
||||
uint32_t data_63 : 8;
|
||||
uint32_t data_64 : 8;
|
||||
#else
|
||||
uint32_t data_64 : 8;
|
||||
uint32_t data_63 : 8;
|
||||
uint32_t data_62 : 8;
|
||||
uint32_t data_61 : 8;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
#endif
|
971
hw/net/can/ctu_can_fd_regs.h
Normal file
971
hw/net/can/ctu_can_fd_regs.h
Normal file
@ -0,0 +1,971 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*******************************************************************************
|
||||
*
|
||||
* CTU CAN FD IP Core
|
||||
*
|
||||
* Copyright (C) 2015-2018 Ondrej Ille <ondrej.ille@gmail.com> FEE CTU
|
||||
* Copyright (C) 2018-2020 Ondrej Ille <ondrej.ille@gmail.com> self-funded
|
||||
* Copyright (C) 2018-2019 Martin Jerabek <martin.jerabek01@gmail.com> FEE CTU
|
||||
* Copyright (C) 2018-2020 Pavel Pisa <pisa@cmp.felk.cvut.cz> FEE CTU/self-funded
|
||||
*
|
||||
* Project advisors:
|
||||
* Jiri Novak <jnovak@fel.cvut.cz>
|
||||
* Pavel Pisa <pisa@cmp.felk.cvut.cz>
|
||||
*
|
||||
* Department of Measurement (http://meas.fel.cvut.cz/)
|
||||
* Faculty of Electrical Engineering (http://www.fel.cvut.cz)
|
||||
* Czech Technical University (http://www.cvut.cz/)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
******************************************************************************/
|
||||
|
||||
/* This file is autogenerated, DO NOT EDIT! */
|
||||
|
||||
#ifndef __CTU_CAN_FD_CAN_FD_REGISTER_MAP__
|
||||
#define __CTU_CAN_FD_CAN_FD_REGISTER_MAP__
|
||||
|
||||
/* CAN_Registers memory map */
|
||||
enum ctu_can_fd_can_registers {
|
||||
CTU_CAN_FD_DEVICE_ID = 0x0,
|
||||
CTU_CAN_FD_VERSION = 0x2,
|
||||
CTU_CAN_FD_MODE = 0x4,
|
||||
CTU_CAN_FD_SETTINGS = 0x6,
|
||||
CTU_CAN_FD_STATUS = 0x8,
|
||||
CTU_CAN_FD_COMMAND = 0xc,
|
||||
CTU_CAN_FD_INT_STAT = 0x10,
|
||||
CTU_CAN_FD_INT_ENA_SET = 0x14,
|
||||
CTU_CAN_FD_INT_ENA_CLR = 0x18,
|
||||
CTU_CAN_FD_INT_MASK_SET = 0x1c,
|
||||
CTU_CAN_FD_INT_MASK_CLR = 0x20,
|
||||
CTU_CAN_FD_BTR = 0x24,
|
||||
CTU_CAN_FD_BTR_FD = 0x28,
|
||||
CTU_CAN_FD_EWL = 0x2c,
|
||||
CTU_CAN_FD_ERP = 0x2d,
|
||||
CTU_CAN_FD_FAULT_STATE = 0x2e,
|
||||
CTU_CAN_FD_REC = 0x30,
|
||||
CTU_CAN_FD_TEC = 0x32,
|
||||
CTU_CAN_FD_ERR_NORM = 0x34,
|
||||
CTU_CAN_FD_ERR_FD = 0x36,
|
||||
CTU_CAN_FD_CTR_PRES = 0x38,
|
||||
CTU_CAN_FD_FILTER_A_MASK = 0x3c,
|
||||
CTU_CAN_FD_FILTER_A_VAL = 0x40,
|
||||
CTU_CAN_FD_FILTER_B_MASK = 0x44,
|
||||
CTU_CAN_FD_FILTER_B_VAL = 0x48,
|
||||
CTU_CAN_FD_FILTER_C_MASK = 0x4c,
|
||||
CTU_CAN_FD_FILTER_C_VAL = 0x50,
|
||||
CTU_CAN_FD_FILTER_RAN_LOW = 0x54,
|
||||
CTU_CAN_FD_FILTER_RAN_HIGH = 0x58,
|
||||
CTU_CAN_FD_FILTER_CONTROL = 0x5c,
|
||||
CTU_CAN_FD_FILTER_STATUS = 0x5e,
|
||||
CTU_CAN_FD_RX_MEM_INFO = 0x60,
|
||||
CTU_CAN_FD_RX_POINTERS = 0x64,
|
||||
CTU_CAN_FD_RX_STATUS = 0x68,
|
||||
CTU_CAN_FD_RX_SETTINGS = 0x6a,
|
||||
CTU_CAN_FD_RX_DATA = 0x6c,
|
||||
CTU_CAN_FD_TX_STATUS = 0x70,
|
||||
CTU_CAN_FD_TX_COMMAND = 0x74,
|
||||
CTU_CAN_FD_TX_PRIORITY = 0x78,
|
||||
CTU_CAN_FD_ERR_CAPT = 0x7c,
|
||||
CTU_CAN_FD_ALC = 0x7e,
|
||||
CTU_CAN_FD_TRV_DELAY = 0x80,
|
||||
CTU_CAN_FD_SSP_CFG = 0x82,
|
||||
CTU_CAN_FD_RX_FR_CTR = 0x84,
|
||||
CTU_CAN_FD_TX_FR_CTR = 0x88,
|
||||
CTU_CAN_FD_DEBUG_REGISTER = 0x8c,
|
||||
CTU_CAN_FD_YOLO_REG = 0x90,
|
||||
CTU_CAN_FD_TIMESTAMP_LOW = 0x94,
|
||||
CTU_CAN_FD_TIMESTAMP_HIGH = 0x98,
|
||||
CTU_CAN_FD_TXTB1_DATA_1 = 0x100,
|
||||
CTU_CAN_FD_TXTB1_DATA_2 = 0x104,
|
||||
CTU_CAN_FD_TXTB1_DATA_20 = 0x14c,
|
||||
CTU_CAN_FD_TXTB2_DATA_1 = 0x200,
|
||||
CTU_CAN_FD_TXTB2_DATA_2 = 0x204,
|
||||
CTU_CAN_FD_TXTB2_DATA_20 = 0x24c,
|
||||
CTU_CAN_FD_TXTB3_DATA_1 = 0x300,
|
||||
CTU_CAN_FD_TXTB3_DATA_2 = 0x304,
|
||||
CTU_CAN_FD_TXTB3_DATA_20 = 0x34c,
|
||||
CTU_CAN_FD_TXTB4_DATA_1 = 0x400,
|
||||
CTU_CAN_FD_TXTB4_DATA_2 = 0x404,
|
||||
CTU_CAN_FD_TXTB4_DATA_20 = 0x44c,
|
||||
};
|
||||
|
||||
|
||||
/* Register descriptions: */
|
||||
union ctu_can_fd_device_id_version {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_device_id_version_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* DEVICE_ID */
|
||||
uint32_t device_id : 16;
|
||||
/* VERSION */
|
||||
uint32_t ver_minor : 8;
|
||||
uint32_t ver_major : 8;
|
||||
#else
|
||||
uint32_t ver_major : 8;
|
||||
uint32_t ver_minor : 8;
|
||||
uint32_t device_id : 16;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
enum ctu_can_fd_device_id_device_id {
|
||||
CTU_CAN_FD_ID = 0xcafd,
|
||||
};
|
||||
|
||||
union ctu_can_fd_mode_settings {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_mode_settings_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* MODE */
|
||||
uint32_t rst : 1;
|
||||
uint32_t lom : 1;
|
||||
uint32_t stm : 1;
|
||||
uint32_t afm : 1;
|
||||
uint32_t fde : 1;
|
||||
uint32_t reserved_6_5 : 2;
|
||||
uint32_t acf : 1;
|
||||
uint32_t tstm : 1;
|
||||
uint32_t reserved_15_9 : 7;
|
||||
/* SETTINGS */
|
||||
uint32_t rtrle : 1;
|
||||
uint32_t rtrth : 4;
|
||||
uint32_t ilbp : 1;
|
||||
uint32_t ena : 1;
|
||||
uint32_t nisofd : 1;
|
||||
uint32_t pex : 1;
|
||||
uint32_t reserved_31_25 : 7;
|
||||
#else
|
||||
uint32_t reserved_31_25 : 7;
|
||||
uint32_t pex : 1;
|
||||
uint32_t nisofd : 1;
|
||||
uint32_t ena : 1;
|
||||
uint32_t ilbp : 1;
|
||||
uint32_t rtrth : 4;
|
||||
uint32_t rtrle : 1;
|
||||
uint32_t reserved_15_9 : 7;
|
||||
uint32_t tstm : 1;
|
||||
uint32_t acf : 1;
|
||||
uint32_t reserved_6_5 : 2;
|
||||
uint32_t fde : 1;
|
||||
uint32_t afm : 1;
|
||||
uint32_t stm : 1;
|
||||
uint32_t lom : 1;
|
||||
uint32_t rst : 1;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
enum ctu_can_fd_mode_lom {
|
||||
LOM_DISABLED = 0x0,
|
||||
LOM_ENABLED = 0x1,
|
||||
};
|
||||
|
||||
enum ctu_can_fd_mode_stm {
|
||||
STM_DISABLED = 0x0,
|
||||
STM_ENABLED = 0x1,
|
||||
};
|
||||
|
||||
enum ctu_can_fd_mode_afm {
|
||||
AFM_DISABLED = 0x0,
|
||||
AFM_ENABLED = 0x1,
|
||||
};
|
||||
|
||||
enum ctu_can_fd_mode_fde {
|
||||
FDE_DISABLE = 0x0,
|
||||
FDE_ENABLE = 0x1,
|
||||
};
|
||||
|
||||
enum ctu_can_fd_mode_acf {
|
||||
ACF_DISABLED = 0x0,
|
||||
ACF_ENABLED = 0x1,
|
||||
};
|
||||
|
||||
enum ctu_can_fd_settings_rtrle {
|
||||
RTRLE_DISABLED = 0x0,
|
||||
RTRLE_ENABLED = 0x1,
|
||||
};
|
||||
|
||||
enum ctu_can_fd_settings_ilbp {
|
||||
INT_LOOP_DISABLED = 0x0,
|
||||
INT_LOOP_ENABLED = 0x1,
|
||||
};
|
||||
|
||||
enum ctu_can_fd_settings_ena {
|
||||
CTU_CAN_DISABLED = 0x0,
|
||||
CTU_CAN_ENABLED = 0x1,
|
||||
};
|
||||
|
||||
enum ctu_can_fd_settings_nisofd {
|
||||
ISO_FD = 0x0,
|
||||
NON_ISO_FD = 0x1,
|
||||
};
|
||||
|
||||
enum ctu_can_fd_settings_pex {
|
||||
PROTOCOL_EXCEPTION_DISABLED = 0x0,
|
||||
PROTOCOL_EXCEPTION_ENABLED = 0x1,
|
||||
};
|
||||
|
||||
union ctu_can_fd_status {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_status_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* STATUS */
|
||||
uint32_t rxne : 1;
|
||||
uint32_t dor : 1;
|
||||
uint32_t txnf : 1;
|
||||
uint32_t eft : 1;
|
||||
uint32_t rxs : 1;
|
||||
uint32_t txs : 1;
|
||||
uint32_t ewl : 1;
|
||||
uint32_t idle : 1;
|
||||
uint32_t reserved_31_8 : 24;
|
||||
#else
|
||||
uint32_t reserved_31_8 : 24;
|
||||
uint32_t idle : 1;
|
||||
uint32_t ewl : 1;
|
||||
uint32_t txs : 1;
|
||||
uint32_t rxs : 1;
|
||||
uint32_t eft : 1;
|
||||
uint32_t txnf : 1;
|
||||
uint32_t dor : 1;
|
||||
uint32_t rxne : 1;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_command {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_command_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
uint32_t reserved_1_0 : 2;
|
||||
/* COMMAND */
|
||||
uint32_t rrb : 1;
|
||||
uint32_t cdo : 1;
|
||||
uint32_t ercrst : 1;
|
||||
uint32_t rxfcrst : 1;
|
||||
uint32_t txfcrst : 1;
|
||||
uint32_t reserved_31_7 : 25;
|
||||
#else
|
||||
uint32_t reserved_31_7 : 25;
|
||||
uint32_t txfcrst : 1;
|
||||
uint32_t rxfcrst : 1;
|
||||
uint32_t ercrst : 1;
|
||||
uint32_t cdo : 1;
|
||||
uint32_t rrb : 1;
|
||||
uint32_t reserved_1_0 : 2;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_int_stat {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_int_stat_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* INT_STAT */
|
||||
uint32_t rxi : 1;
|
||||
uint32_t txi : 1;
|
||||
uint32_t ewli : 1;
|
||||
uint32_t doi : 1;
|
||||
uint32_t fcsi : 1;
|
||||
uint32_t ali : 1;
|
||||
uint32_t bei : 1;
|
||||
uint32_t ofi : 1;
|
||||
uint32_t rxfi : 1;
|
||||
uint32_t bsi : 1;
|
||||
uint32_t rbnei : 1;
|
||||
uint32_t txbhci : 1;
|
||||
uint32_t reserved_31_12 : 20;
|
||||
#else
|
||||
uint32_t reserved_31_12 : 20;
|
||||
uint32_t txbhci : 1;
|
||||
uint32_t rbnei : 1;
|
||||
uint32_t bsi : 1;
|
||||
uint32_t rxfi : 1;
|
||||
uint32_t ofi : 1;
|
||||
uint32_t bei : 1;
|
||||
uint32_t ali : 1;
|
||||
uint32_t fcsi : 1;
|
||||
uint32_t doi : 1;
|
||||
uint32_t ewli : 1;
|
||||
uint32_t txi : 1;
|
||||
uint32_t rxi : 1;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_int_ena_set {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_int_ena_set_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* INT_ENA_SET */
|
||||
uint32_t int_ena_set : 12;
|
||||
uint32_t reserved_31_12 : 20;
|
||||
#else
|
||||
uint32_t reserved_31_12 : 20;
|
||||
uint32_t int_ena_set : 12;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_int_ena_clr {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_int_ena_clr_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* INT_ENA_CLR */
|
||||
uint32_t int_ena_clr : 12;
|
||||
uint32_t reserved_31_12 : 20;
|
||||
#else
|
||||
uint32_t reserved_31_12 : 20;
|
||||
uint32_t int_ena_clr : 12;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_int_mask_set {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_int_mask_set_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* INT_MASK_SET */
|
||||
uint32_t int_mask_set : 12;
|
||||
uint32_t reserved_31_12 : 20;
|
||||
#else
|
||||
uint32_t reserved_31_12 : 20;
|
||||
uint32_t int_mask_set : 12;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_int_mask_clr {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_int_mask_clr_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* INT_MASK_CLR */
|
||||
uint32_t int_mask_clr : 12;
|
||||
uint32_t reserved_31_12 : 20;
|
||||
#else
|
||||
uint32_t reserved_31_12 : 20;
|
||||
uint32_t int_mask_clr : 12;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_btr {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_btr_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* BTR */
|
||||
uint32_t prop : 7;
|
||||
uint32_t ph1 : 6;
|
||||
uint32_t ph2 : 6;
|
||||
uint32_t brp : 8;
|
||||
uint32_t sjw : 5;
|
||||
#else
|
||||
uint32_t sjw : 5;
|
||||
uint32_t brp : 8;
|
||||
uint32_t ph2 : 6;
|
||||
uint32_t ph1 : 6;
|
||||
uint32_t prop : 7;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_btr_fd {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_btr_fd_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* BTR_FD */
|
||||
uint32_t prop_fd : 6;
|
||||
uint32_t reserved_6 : 1;
|
||||
uint32_t ph1_fd : 5;
|
||||
uint32_t reserved_12 : 1;
|
||||
uint32_t ph2_fd : 5;
|
||||
uint32_t reserved_18 : 1;
|
||||
uint32_t brp_fd : 8;
|
||||
uint32_t sjw_fd : 5;
|
||||
#else
|
||||
uint32_t sjw_fd : 5;
|
||||
uint32_t brp_fd : 8;
|
||||
uint32_t reserved_18 : 1;
|
||||
uint32_t ph2_fd : 5;
|
||||
uint32_t reserved_12 : 1;
|
||||
uint32_t ph1_fd : 5;
|
||||
uint32_t reserved_6 : 1;
|
||||
uint32_t prop_fd : 6;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_ewl_erp_fault_state {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_ewl_erp_fault_state_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* EWL */
|
||||
uint32_t ew_limit : 8;
|
||||
/* ERP */
|
||||
uint32_t erp_limit : 8;
|
||||
/* FAULT_STATE */
|
||||
uint32_t era : 1;
|
||||
uint32_t erp : 1;
|
||||
uint32_t bof : 1;
|
||||
uint32_t reserved_31_19 : 13;
|
||||
#else
|
||||
uint32_t reserved_31_19 : 13;
|
||||
uint32_t bof : 1;
|
||||
uint32_t erp : 1;
|
||||
uint32_t era : 1;
|
||||
uint32_t erp_limit : 8;
|
||||
uint32_t ew_limit : 8;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_rec_tec {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_rec_tec_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* REC */
|
||||
uint32_t rec_val : 9;
|
||||
uint32_t reserved_15_9 : 7;
|
||||
/* TEC */
|
||||
uint32_t tec_val : 9;
|
||||
uint32_t reserved_31_25 : 7;
|
||||
#else
|
||||
uint32_t reserved_31_25 : 7;
|
||||
uint32_t tec_val : 9;
|
||||
uint32_t reserved_15_9 : 7;
|
||||
uint32_t rec_val : 9;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_err_norm_err_fd {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_err_norm_err_fd_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* ERR_NORM */
|
||||
uint32_t err_norm_val : 16;
|
||||
/* ERR_FD */
|
||||
uint32_t err_fd_val : 16;
|
||||
#else
|
||||
uint32_t err_fd_val : 16;
|
||||
uint32_t err_norm_val : 16;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_ctr_pres {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_ctr_pres_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* CTR_PRES */
|
||||
uint32_t ctpv : 9;
|
||||
uint32_t ptx : 1;
|
||||
uint32_t prx : 1;
|
||||
uint32_t enorm : 1;
|
||||
uint32_t efd : 1;
|
||||
uint32_t reserved_31_13 : 19;
|
||||
#else
|
||||
uint32_t reserved_31_13 : 19;
|
||||
uint32_t efd : 1;
|
||||
uint32_t enorm : 1;
|
||||
uint32_t prx : 1;
|
||||
uint32_t ptx : 1;
|
||||
uint32_t ctpv : 9;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_filter_a_mask {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_filter_a_mask_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* FILTER_A_MASK */
|
||||
uint32_t bit_mask_a_val : 29;
|
||||
uint32_t reserved_31_29 : 3;
|
||||
#else
|
||||
uint32_t reserved_31_29 : 3;
|
||||
uint32_t bit_mask_a_val : 29;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_filter_a_val {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_filter_a_val_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* FILTER_A_VAL */
|
||||
uint32_t bit_val_a_val : 29;
|
||||
uint32_t reserved_31_29 : 3;
|
||||
#else
|
||||
uint32_t reserved_31_29 : 3;
|
||||
uint32_t bit_val_a_val : 29;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_filter_b_mask {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_filter_b_mask_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* FILTER_B_MASK */
|
||||
uint32_t bit_mask_b_val : 29;
|
||||
uint32_t reserved_31_29 : 3;
|
||||
#else
|
||||
uint32_t reserved_31_29 : 3;
|
||||
uint32_t bit_mask_b_val : 29;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_filter_b_val {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_filter_b_val_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* FILTER_B_VAL */
|
||||
uint32_t bit_val_b_val : 29;
|
||||
uint32_t reserved_31_29 : 3;
|
||||
#else
|
||||
uint32_t reserved_31_29 : 3;
|
||||
uint32_t bit_val_b_val : 29;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_filter_c_mask {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_filter_c_mask_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* FILTER_C_MASK */
|
||||
uint32_t bit_mask_c_val : 29;
|
||||
uint32_t reserved_31_29 : 3;
|
||||
#else
|
||||
uint32_t reserved_31_29 : 3;
|
||||
uint32_t bit_mask_c_val : 29;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_filter_c_val {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_filter_c_val_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* FILTER_C_VAL */
|
||||
uint32_t bit_val_c_val : 29;
|
||||
uint32_t reserved_31_29 : 3;
|
||||
#else
|
||||
uint32_t reserved_31_29 : 3;
|
||||
uint32_t bit_val_c_val : 29;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_filter_ran_low {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_filter_ran_low_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* FILTER_RAN_LOW */
|
||||
uint32_t bit_ran_low_val : 29;
|
||||
uint32_t reserved_31_29 : 3;
|
||||
#else
|
||||
uint32_t reserved_31_29 : 3;
|
||||
uint32_t bit_ran_low_val : 29;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_filter_ran_high {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_filter_ran_high_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* FILTER_RAN_HIGH */
|
||||
uint32_t bit_ran_high_val : 29;
|
||||
uint32_t reserved_31_29 : 3;
|
||||
#else
|
||||
uint32_t reserved_31_29 : 3;
|
||||
uint32_t bit_ran_high_val : 29;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_filter_control_filter_status {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_filter_control_filter_status_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* FILTER_CONTROL */
|
||||
uint32_t fanb : 1;
|
||||
uint32_t fane : 1;
|
||||
uint32_t fafb : 1;
|
||||
uint32_t fafe : 1;
|
||||
uint32_t fbnb : 1;
|
||||
uint32_t fbne : 1;
|
||||
uint32_t fbfb : 1;
|
||||
uint32_t fbfe : 1;
|
||||
uint32_t fcnb : 1;
|
||||
uint32_t fcne : 1;
|
||||
uint32_t fcfb : 1;
|
||||
uint32_t fcfe : 1;
|
||||
uint32_t frnb : 1;
|
||||
uint32_t frne : 1;
|
||||
uint32_t frfb : 1;
|
||||
uint32_t frfe : 1;
|
||||
/* FILTER_STATUS */
|
||||
uint32_t sfa : 1;
|
||||
uint32_t sfb : 1;
|
||||
uint32_t sfc : 1;
|
||||
uint32_t sfr : 1;
|
||||
uint32_t reserved_31_20 : 12;
|
||||
#else
|
||||
uint32_t reserved_31_20 : 12;
|
||||
uint32_t sfr : 1;
|
||||
uint32_t sfc : 1;
|
||||
uint32_t sfb : 1;
|
||||
uint32_t sfa : 1;
|
||||
uint32_t frfe : 1;
|
||||
uint32_t frfb : 1;
|
||||
uint32_t frne : 1;
|
||||
uint32_t frnb : 1;
|
||||
uint32_t fcfe : 1;
|
||||
uint32_t fcfb : 1;
|
||||
uint32_t fcne : 1;
|
||||
uint32_t fcnb : 1;
|
||||
uint32_t fbfe : 1;
|
||||
uint32_t fbfb : 1;
|
||||
uint32_t fbne : 1;
|
||||
uint32_t fbnb : 1;
|
||||
uint32_t fafe : 1;
|
||||
uint32_t fafb : 1;
|
||||
uint32_t fane : 1;
|
||||
uint32_t fanb : 1;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_rx_mem_info {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_rx_mem_info_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* RX_MEM_INFO */
|
||||
uint32_t rx_buff_size : 13;
|
||||
uint32_t reserved_15_13 : 3;
|
||||
uint32_t rx_mem_free : 13;
|
||||
uint32_t reserved_31_29 : 3;
|
||||
#else
|
||||
uint32_t reserved_31_29 : 3;
|
||||
uint32_t rx_mem_free : 13;
|
||||
uint32_t reserved_15_13 : 3;
|
||||
uint32_t rx_buff_size : 13;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_rx_pointers {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_rx_pointers_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* RX_POINTERS */
|
||||
uint32_t rx_wpp : 12;
|
||||
uint32_t reserved_15_12 : 4;
|
||||
uint32_t rx_rpp : 12;
|
||||
uint32_t reserved_31_28 : 4;
|
||||
#else
|
||||
uint32_t reserved_31_28 : 4;
|
||||
uint32_t rx_rpp : 12;
|
||||
uint32_t reserved_15_12 : 4;
|
||||
uint32_t rx_wpp : 12;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_rx_status_rx_settings {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_rx_status_rx_settings_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* RX_STATUS */
|
||||
uint32_t rxe : 1;
|
||||
uint32_t rxf : 1;
|
||||
uint32_t reserved_3_2 : 2;
|
||||
uint32_t rxfrc : 11;
|
||||
uint32_t reserved_15 : 1;
|
||||
/* RX_SETTINGS */
|
||||
uint32_t rtsop : 1;
|
||||
uint32_t reserved_31_17 : 15;
|
||||
#else
|
||||
uint32_t reserved_31_17 : 15;
|
||||
uint32_t rtsop : 1;
|
||||
uint32_t reserved_15 : 1;
|
||||
uint32_t rxfrc : 11;
|
||||
uint32_t reserved_3_2 : 2;
|
||||
uint32_t rxf : 1;
|
||||
uint32_t rxe : 1;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
enum ctu_can_fd_rx_settings_rtsop {
|
||||
RTS_END = 0x0,
|
||||
RTS_BEG = 0x1,
|
||||
};
|
||||
|
||||
union ctu_can_fd_rx_data {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_rx_data_s {
|
||||
/* RX_DATA */
|
||||
uint32_t rx_data : 32;
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_tx_status {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_tx_status_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* TX_STATUS */
|
||||
uint32_t tx1s : 4;
|
||||
uint32_t tx2s : 4;
|
||||
uint32_t tx3s : 4;
|
||||
uint32_t tx4s : 4;
|
||||
uint32_t reserved_31_16 : 16;
|
||||
#else
|
||||
uint32_t reserved_31_16 : 16;
|
||||
uint32_t tx4s : 4;
|
||||
uint32_t tx3s : 4;
|
||||
uint32_t tx2s : 4;
|
||||
uint32_t tx1s : 4;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
enum ctu_can_fd_tx_status_tx1s {
|
||||
TXT_RDY = 0x1,
|
||||
TXT_TRAN = 0x2,
|
||||
TXT_ABTP = 0x3,
|
||||
TXT_TOK = 0x4,
|
||||
TXT_ERR = 0x6,
|
||||
TXT_ABT = 0x7,
|
||||
TXT_ETY = 0x8,
|
||||
};
|
||||
|
||||
union ctu_can_fd_tx_command {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_tx_command_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* TX_COMMAND */
|
||||
uint32_t txce : 1;
|
||||
uint32_t txcr : 1;
|
||||
uint32_t txca : 1;
|
||||
uint32_t reserved_7_3 : 5;
|
||||
uint32_t txb1 : 1;
|
||||
uint32_t txb2 : 1;
|
||||
uint32_t txb3 : 1;
|
||||
uint32_t txb4 : 1;
|
||||
uint32_t reserved_31_12 : 20;
|
||||
#else
|
||||
uint32_t reserved_31_12 : 20;
|
||||
uint32_t txb4 : 1;
|
||||
uint32_t txb3 : 1;
|
||||
uint32_t txb2 : 1;
|
||||
uint32_t txb1 : 1;
|
||||
uint32_t reserved_7_3 : 5;
|
||||
uint32_t txca : 1;
|
||||
uint32_t txcr : 1;
|
||||
uint32_t txce : 1;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_tx_priority {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_tx_priority_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* TX_PRIORITY */
|
||||
uint32_t txt1p : 3;
|
||||
uint32_t reserved_3 : 1;
|
||||
uint32_t txt2p : 3;
|
||||
uint32_t reserved_7 : 1;
|
||||
uint32_t txt3p : 3;
|
||||
uint32_t reserved_11 : 1;
|
||||
uint32_t txt4p : 3;
|
||||
uint32_t reserved_31_15 : 17;
|
||||
#else
|
||||
uint32_t reserved_31_15 : 17;
|
||||
uint32_t txt4p : 3;
|
||||
uint32_t reserved_11 : 1;
|
||||
uint32_t txt3p : 3;
|
||||
uint32_t reserved_7 : 1;
|
||||
uint32_t txt2p : 3;
|
||||
uint32_t reserved_3 : 1;
|
||||
uint32_t txt1p : 3;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_err_capt_alc {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_err_capt_alc_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* ERR_CAPT */
|
||||
uint32_t err_pos : 5;
|
||||
uint32_t err_type : 3;
|
||||
uint32_t reserved_15_8 : 8;
|
||||
/* ALC */
|
||||
uint32_t alc_bit : 5;
|
||||
uint32_t alc_id_field : 3;
|
||||
uint32_t reserved_31_24 : 8;
|
||||
#else
|
||||
uint32_t reserved_31_24 : 8;
|
||||
uint32_t alc_id_field : 3;
|
||||
uint32_t alc_bit : 5;
|
||||
uint32_t reserved_15_8 : 8;
|
||||
uint32_t err_type : 3;
|
||||
uint32_t err_pos : 5;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
enum ctu_can_fd_err_capt_err_pos {
|
||||
ERC_POS_SOF = 0x0,
|
||||
ERC_POS_ARB = 0x1,
|
||||
ERC_POS_CTRL = 0x2,
|
||||
ERC_POS_DATA = 0x3,
|
||||
ERC_POS_CRC = 0x4,
|
||||
ERC_POS_ACK = 0x5,
|
||||
ERC_POS_EOF = 0x6,
|
||||
ERC_POS_ERR = 0x7,
|
||||
ERC_POS_OVRL = 0x8,
|
||||
ERC_POS_OTHER = 0x1f,
|
||||
};
|
||||
|
||||
enum ctu_can_fd_err_capt_err_type {
|
||||
ERC_BIT_ERR = 0x0,
|
||||
ERC_CRC_ERR = 0x1,
|
||||
ERC_FRM_ERR = 0x2,
|
||||
ERC_ACK_ERR = 0x3,
|
||||
ERC_STUF_ERR = 0x4,
|
||||
};
|
||||
|
||||
enum ctu_can_fd_alc_alc_id_field {
|
||||
ALC_RSVD = 0x0,
|
||||
ALC_BASE_ID = 0x1,
|
||||
ALC_SRR_RTR = 0x2,
|
||||
ALC_IDE = 0x3,
|
||||
ALC_EXTENSION = 0x4,
|
||||
ALC_RTR = 0x5,
|
||||
};
|
||||
|
||||
union ctu_can_fd_trv_delay_ssp_cfg {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_trv_delay_ssp_cfg_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* TRV_DELAY */
|
||||
uint32_t trv_delay_value : 7;
|
||||
uint32_t reserved_15_7 : 9;
|
||||
/* SSP_CFG */
|
||||
uint32_t ssp_offset : 8;
|
||||
uint32_t ssp_src : 2;
|
||||
uint32_t reserved_31_26 : 6;
|
||||
#else
|
||||
uint32_t reserved_31_26 : 6;
|
||||
uint32_t ssp_src : 2;
|
||||
uint32_t ssp_offset : 8;
|
||||
uint32_t reserved_15_7 : 9;
|
||||
uint32_t trv_delay_value : 7;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
enum ctu_can_fd_ssp_cfg_ssp_src {
|
||||
SSP_SRC_MEAS_N_OFFSET = 0x0,
|
||||
SSP_SRC_NO_SSP = 0x1,
|
||||
SSP_SRC_OFFSET = 0x2,
|
||||
};
|
||||
|
||||
union ctu_can_fd_rx_fr_ctr {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_rx_fr_ctr_s {
|
||||
/* RX_FR_CTR */
|
||||
uint32_t rx_fr_ctr_val : 32;
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_tx_fr_ctr {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_tx_fr_ctr_s {
|
||||
/* TX_FR_CTR */
|
||||
uint32_t tx_fr_ctr_val : 32;
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_debug_register {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_debug_register_s {
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
/* DEBUG_REGISTER */
|
||||
uint32_t stuff_count : 3;
|
||||
uint32_t destuff_count : 3;
|
||||
uint32_t pc_arb : 1;
|
||||
uint32_t pc_con : 1;
|
||||
uint32_t pc_dat : 1;
|
||||
uint32_t pc_stc : 1;
|
||||
uint32_t pc_crc : 1;
|
||||
uint32_t pc_crcd : 1;
|
||||
uint32_t pc_ack : 1;
|
||||
uint32_t pc_ackd : 1;
|
||||
uint32_t pc_eof : 1;
|
||||
uint32_t pc_int : 1;
|
||||
uint32_t pc_susp : 1;
|
||||
uint32_t pc_ovr : 1;
|
||||
uint32_t pc_sof : 1;
|
||||
uint32_t reserved_31_19 : 13;
|
||||
#else
|
||||
uint32_t reserved_31_19 : 13;
|
||||
uint32_t pc_sof : 1;
|
||||
uint32_t pc_ovr : 1;
|
||||
uint32_t pc_susp : 1;
|
||||
uint32_t pc_int : 1;
|
||||
uint32_t pc_eof : 1;
|
||||
uint32_t pc_ackd : 1;
|
||||
uint32_t pc_ack : 1;
|
||||
uint32_t pc_crcd : 1;
|
||||
uint32_t pc_crc : 1;
|
||||
uint32_t pc_stc : 1;
|
||||
uint32_t pc_dat : 1;
|
||||
uint32_t pc_con : 1;
|
||||
uint32_t pc_arb : 1;
|
||||
uint32_t destuff_count : 3;
|
||||
uint32_t stuff_count : 3;
|
||||
#endif
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_yolo_reg {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_yolo_reg_s {
|
||||
/* YOLO_REG */
|
||||
uint32_t yolo_val : 32;
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_timestamp_low {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_timestamp_low_s {
|
||||
/* TIMESTAMP_LOW */
|
||||
uint32_t timestamp_low : 32;
|
||||
} s;
|
||||
};
|
||||
|
||||
union ctu_can_fd_timestamp_high {
|
||||
uint32_t u32;
|
||||
struct ctu_can_fd_timestamp_high_s {
|
||||
/* TIMESTAMP_HIGH */
|
||||
uint32_t timestamp_high : 32;
|
||||
} s;
|
||||
};
|
||||
|
||||
#endif
|
696
hw/net/can/ctucan_core.c
Normal file
696
hw/net/can/ctucan_core.c
Normal file
@ -0,0 +1,696 @@
|
||||
/*
|
||||
* CTU CAN FD PCI device emulation
|
||||
* http://canbus.pages.fel.cvut.cz/
|
||||
*
|
||||
* Copyright (c) 2019 Jan Charvat (jancharvat.charvat@gmail.com)
|
||||
*
|
||||
* Based on Kvaser PCI CAN device (SJA1000 based) emulation implemented by
|
||||
* Jin Yang and Pavel Pisa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "chardev/char.h"
|
||||
#include "hw/irq.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "net/can_emu.h"
|
||||
|
||||
#include "ctucan_core.h"
|
||||
|
||||
#ifndef DEBUG_CAN
|
||||
#define DEBUG_CAN 0
|
||||
#endif /*DEBUG_CAN*/
|
||||
|
||||
#define DPRINTF(fmt, ...) \
|
||||
do { \
|
||||
if (DEBUG_CAN) { \
|
||||
qemu_log("[ctucan]: " fmt , ## __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static void ctucan_buff2frame(const uint8_t *buff, qemu_can_frame *frame)
|
||||
{
|
||||
frame->can_id = 0;
|
||||
frame->can_dlc = 0;
|
||||
frame->flags = 0;
|
||||
|
||||
if (buff == NULL) {
|
||||
return;
|
||||
}
|
||||
{
|
||||
union ctu_can_fd_frame_form_w frame_form_w;
|
||||
union ctu_can_fd_identifier_w identifier_w;
|
||||
unsigned int ide;
|
||||
uint32_t w;
|
||||
|
||||
w = le32_to_cpu(*(uint32_t *)buff);
|
||||
frame_form_w = (union ctu_can_fd_frame_form_w)w;
|
||||
frame->can_dlc = can_dlc2len(frame_form_w.s.dlc);
|
||||
|
||||
w = le32_to_cpu(*(uint32_t *)(buff + 4));
|
||||
identifier_w = (union ctu_can_fd_identifier_w)w;
|
||||
|
||||
ide = frame_form_w.s.ide;
|
||||
if (ide) {
|
||||
frame->can_id = (identifier_w.s.identifier_base << 18) |
|
||||
identifier_w.s.identifier_ext;
|
||||
frame->can_id |= QEMU_CAN_EFF_FLAG;
|
||||
} else {
|
||||
frame->can_id = identifier_w.s.identifier_base;
|
||||
}
|
||||
|
||||
if (frame_form_w.s.esi_rsv) {
|
||||
frame->flags |= QEMU_CAN_FRMF_ESI;
|
||||
}
|
||||
|
||||
if (frame_form_w.s.rtr) {
|
||||
frame->can_id |= QEMU_CAN_RTR_FLAG;
|
||||
}
|
||||
|
||||
if (frame_form_w.s.fdf) { /*CAN FD*/
|
||||
frame->flags |= QEMU_CAN_FRMF_TYPE_FD;
|
||||
if (frame_form_w.s.brs) {
|
||||
frame->flags |= QEMU_CAN_FRMF_BRS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(frame->data, buff + 0x10, 0x40);
|
||||
}
|
||||
|
||||
|
||||
static int ctucan_frame2buff(const qemu_can_frame *frame, uint8_t *buff)
|
||||
{
|
||||
unsigned int bytes_cnt = -1;
|
||||
memset(buff, 0, CTUCAN_MSG_MAX_LEN * sizeof(*buff));
|
||||
|
||||
if (frame == NULL) {
|
||||
return bytes_cnt;
|
||||
}
|
||||
{
|
||||
union ctu_can_fd_frame_form_w frame_form_w;
|
||||
union ctu_can_fd_identifier_w identifier_w;
|
||||
|
||||
frame_form_w.u32 = 0;
|
||||
identifier_w.u32 = 0;
|
||||
|
||||
bytes_cnt = frame->can_dlc;
|
||||
bytes_cnt = (bytes_cnt + 3) & ~3;
|
||||
bytes_cnt += 16;
|
||||
frame_form_w.s.rwcnt = (bytes_cnt >> 2) - 1;
|
||||
|
||||
frame_form_w.s.dlc = can_len2dlc(frame->can_dlc);
|
||||
|
||||
if (frame->can_id & QEMU_CAN_EFF_FLAG) {
|
||||
frame_form_w.s.ide = 1;
|
||||
identifier_w.s.identifier_base =
|
||||
(frame->can_id & 0x1FFC0000) >> 18;
|
||||
identifier_w.s.identifier_ext = frame->can_id & 0x3FFFF;
|
||||
} else {
|
||||
identifier_w.s.identifier_base = frame->can_id & 0x7FF;
|
||||
}
|
||||
|
||||
if (frame->flags & QEMU_CAN_FRMF_ESI) {
|
||||
frame_form_w.s.esi_rsv = 1;
|
||||
}
|
||||
|
||||
if (frame->can_id & QEMU_CAN_RTR_FLAG) {
|
||||
frame_form_w.s.rtr = 1;
|
||||
}
|
||||
|
||||
if (frame->flags & QEMU_CAN_FRMF_TYPE_FD) { /*CAN FD*/
|
||||
frame_form_w.s.fdf = 1;
|
||||
if (frame->flags & QEMU_CAN_FRMF_BRS) {
|
||||
frame_form_w.s.brs = 1;
|
||||
}
|
||||
}
|
||||
*(uint32_t *)buff = cpu_to_le32(frame_form_w.u32);
|
||||
*(uint32_t *)(buff + 4) = cpu_to_le32(identifier_w.u32);
|
||||
}
|
||||
|
||||
memcpy(buff + 0x10, frame->data, 0x40);
|
||||
|
||||
return bytes_cnt;
|
||||
}
|
||||
|
||||
static void ctucan_update_irq(CtuCanCoreState *s)
|
||||
{
|
||||
union ctu_can_fd_int_stat int_rq;
|
||||
|
||||
int_rq.u32 = 0;
|
||||
|
||||
if (s->rx_status_rx_settings.s.rxfrc) {
|
||||
int_rq.s.rbnei = 1;
|
||||
}
|
||||
|
||||
int_rq.u32 &= ~s->int_mask.u32;
|
||||
s->int_stat.u32 |= int_rq.u32;
|
||||
if (s->int_stat.u32 & s->int_ena.u32) {
|
||||
qemu_irq_raise(s->irq);
|
||||
} else {
|
||||
qemu_irq_lower(s->irq);
|
||||
}
|
||||
}
|
||||
|
||||
static void ctucan_update_txnf(CtuCanCoreState *s)
|
||||
{
|
||||
int i;
|
||||
int txnf;
|
||||
unsigned int buff_st;
|
||||
|
||||
txnf = 0;
|
||||
|
||||
for (i = 0; i < CTUCAN_CORE_TXBUF_NUM; i++) {
|
||||
buff_st = (s->tx_status.u32 >> (i * 4)) & 0xf;
|
||||
if (buff_st == TXT_ETY) {
|
||||
txnf = 1;
|
||||
}
|
||||
}
|
||||
s->status.s.txnf = txnf;
|
||||
}
|
||||
|
||||
void ctucan_hardware_reset(CtuCanCoreState *s)
|
||||
{
|
||||
DPRINTF("Hardware reset in progress!!!\n");
|
||||
int i;
|
||||
unsigned int buff_st;
|
||||
uint32_t buff_st_mask;
|
||||
|
||||
s->tx_status.u32 = 0;
|
||||
for (i = 0; i < CTUCAN_CORE_TXBUF_NUM; i++) {
|
||||
buff_st_mask = 0xf << (i * 4);
|
||||
buff_st = TXT_ETY;
|
||||
s->tx_status.u32 = (s->tx_status.u32 & ~buff_st_mask) |
|
||||
(buff_st << (i * 4));
|
||||
}
|
||||
s->status.s.idle = 1;
|
||||
|
||||
ctucan_update_txnf(s);
|
||||
|
||||
s->rx_status_rx_settings.u32 = 0;
|
||||
s->rx_tail_pos = 0;
|
||||
s->rx_cnt = 0;
|
||||
s->rx_frame_rem = 0;
|
||||
|
||||
/* Flush RX buffer */
|
||||
s->rx_tail_pos = 0;
|
||||
s->rx_cnt = 0;
|
||||
s->rx_frame_rem = 0;
|
||||
|
||||
/* Set on progdokum reset value */
|
||||
s->mode_settings.u32 = 0;
|
||||
s->mode_settings.s.fde = 1;
|
||||
|
||||
s->int_stat.u32 = 0;
|
||||
s->int_ena.u32 = 0;
|
||||
s->int_mask.u32 = 0;
|
||||
|
||||
s->rx_status_rx_settings.u32 = 0;
|
||||
s->rx_status_rx_settings.s.rxe = 0;
|
||||
|
||||
s->rx_fr_ctr.u32 = 0;
|
||||
s->tx_fr_ctr.u32 = 0;
|
||||
|
||||
s->yolo_reg.s.yolo_val = 3735928559;
|
||||
|
||||
qemu_irq_lower(s->irq);
|
||||
}
|
||||
|
||||
static void ctucan_send_ready_buffers(CtuCanCoreState *s)
|
||||
{
|
||||
qemu_can_frame frame;
|
||||
uint8_t *pf;
|
||||
int buff2tx_idx;
|
||||
uint32_t tx_prio_max;
|
||||
unsigned int buff_st;
|
||||
uint32_t buff_st_mask;
|
||||
|
||||
if (!s->mode_settings.s.ena) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
union ctu_can_fd_int_stat int_stat;
|
||||
int i;
|
||||
buff2tx_idx = -1;
|
||||
tx_prio_max = 0;
|
||||
|
||||
for (i = 0; i < CTUCAN_CORE_TXBUF_NUM; i++) {
|
||||
uint32_t prio;
|
||||
|
||||
buff_st_mask = 0xf << (i * 4);
|
||||
buff_st = (s->tx_status.u32 >> (i * 4)) & 0xf;
|
||||
|
||||
if (buff_st != TXT_RDY) {
|
||||
continue;
|
||||
}
|
||||
prio = (s->tx_priority.u32 >> (i * 4)) & 0x7;
|
||||
if (tx_prio_max < prio) {
|
||||
tx_prio_max = prio;
|
||||
buff2tx_idx = i;
|
||||
}
|
||||
}
|
||||
if (buff2tx_idx == -1) {
|
||||
break;
|
||||
}
|
||||
buff_st_mask = 0xf << (buff2tx_idx * 4);
|
||||
buff_st = (s->tx_status.u32 >> (buff2tx_idx * 4)) & 0xf;
|
||||
int_stat.u32 = 0;
|
||||
buff_st = TXT_RDY;
|
||||
pf = s->tx_buffer[buff2tx_idx].data;
|
||||
ctucan_buff2frame(pf, &frame);
|
||||
s->status.s.idle = 0;
|
||||
s->status.s.txs = 1;
|
||||
can_bus_client_send(&s->bus_client, &frame, 1);
|
||||
s->status.s.idle = 1;
|
||||
s->status.s.txs = 0;
|
||||
s->tx_fr_ctr.s.tx_fr_ctr_val++;
|
||||
buff_st = TXT_TOK;
|
||||
int_stat.s.txi = 1;
|
||||
int_stat.s.txbhci = 1;
|
||||
s->int_stat.u32 |= int_stat.u32 & ~s->int_mask.u32;
|
||||
s->tx_status.u32 = (s->tx_status.u32 & ~buff_st_mask) |
|
||||
(buff_st << (buff2tx_idx * 4));
|
||||
} while (1);
|
||||
}
|
||||
|
||||
#define CTUCAN_CORE_TXBUFF_SPAN \
|
||||
(CTU_CAN_FD_TXTB2_DATA_1 - CTU_CAN_FD_TXTB1_DATA_1)
|
||||
|
||||
void ctucan_mem_write(CtuCanCoreState *s, hwaddr addr, uint64_t val,
|
||||
unsigned size)
|
||||
{
|
||||
int i;
|
||||
|
||||
DPRINTF("write 0x%02llx addr 0x%02x\n",
|
||||
(unsigned long long)val, (unsigned int)addr);
|
||||
|
||||
if (addr > CTUCAN_CORE_MEM_SIZE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (addr >= CTU_CAN_FD_TXTB1_DATA_1) {
|
||||
int buff_num;
|
||||
addr -= CTU_CAN_FD_TXTB1_DATA_1;
|
||||
buff_num = addr / CTUCAN_CORE_TXBUFF_SPAN;
|
||||
addr %= CTUCAN_CORE_TXBUFF_SPAN;
|
||||
if (buff_num < CTUCAN_CORE_TXBUF_NUM) {
|
||||
uint32_t *bufp = (uint32_t *)(s->tx_buffer[buff_num].data + addr);
|
||||
*bufp = cpu_to_le32(val);
|
||||
}
|
||||
} else {
|
||||
switch (addr & ~3) {
|
||||
case CTU_CAN_FD_MODE:
|
||||
s->mode_settings.u32 = (uint32_t)val;
|
||||
if (s->mode_settings.s.rst) {
|
||||
ctucan_hardware_reset(s);
|
||||
s->mode_settings.s.rst = 0;
|
||||
}
|
||||
break;
|
||||
case CTU_CAN_FD_COMMAND:
|
||||
{
|
||||
union ctu_can_fd_command command;
|
||||
command.u32 = (uint32_t)val;
|
||||
if (command.s.cdo) {
|
||||
s->status.s.dor = 0;
|
||||
}
|
||||
if (command.s.rrb) {
|
||||
s->rx_tail_pos = 0;
|
||||
s->rx_cnt = 0;
|
||||
s->rx_frame_rem = 0;
|
||||
s->rx_status_rx_settings.s.rxfrc = 0;
|
||||
}
|
||||
if (command.s.txfcrst) {
|
||||
s->tx_fr_ctr.s.tx_fr_ctr_val = 0;
|
||||
}
|
||||
if (command.s.rxfcrst) {
|
||||
s->rx_fr_ctr.s.rx_fr_ctr_val = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CTU_CAN_FD_INT_STAT:
|
||||
s->int_stat.u32 &= ~(uint32_t)val;
|
||||
break;
|
||||
case CTU_CAN_FD_INT_ENA_SET:
|
||||
s->int_ena.u32 |= (uint32_t)val;
|
||||
break;
|
||||
case CTU_CAN_FD_INT_ENA_CLR:
|
||||
s->int_ena.u32 &= ~(uint32_t)val;
|
||||
break;
|
||||
case CTU_CAN_FD_INT_MASK_SET:
|
||||
s->int_mask.u32 |= (uint32_t)val;
|
||||
break;
|
||||
case CTU_CAN_FD_INT_MASK_CLR:
|
||||
s->int_mask.u32 &= ~(uint32_t)val;
|
||||
break;
|
||||
case CTU_CAN_FD_TX_COMMAND:
|
||||
if (s->mode_settings.s.ena) {
|
||||
union ctu_can_fd_tx_command tx_command;
|
||||
union ctu_can_fd_tx_command mask;
|
||||
unsigned int buff_st;
|
||||
uint32_t buff_st_mask;
|
||||
|
||||
tx_command.u32 = (uint32_t)val;
|
||||
mask.u32 = 0;
|
||||
mask.s.txb1 = 1;
|
||||
|
||||
for (i = 0; i < CTUCAN_CORE_TXBUF_NUM; i++) {
|
||||
if (!(tx_command.u32 & (mask.u32 << i))) {
|
||||
continue;
|
||||
}
|
||||
buff_st_mask = 0xf << (i * 4);
|
||||
buff_st = (s->tx_status.u32 >> (i * 4)) & 0xf;
|
||||
if (tx_command.s.txca) {
|
||||
if (buff_st == TXT_RDY) {
|
||||
buff_st = TXT_ABT;
|
||||
}
|
||||
}
|
||||
if (tx_command.s.txcr) {
|
||||
if ((buff_st == TXT_TOK) || (buff_st == TXT_ERR) ||
|
||||
(buff_st == TXT_ABT) || (buff_st == TXT_ETY))
|
||||
buff_st = TXT_RDY;
|
||||
}
|
||||
if (tx_command.s.txce) {
|
||||
if ((buff_st == TXT_TOK) || (buff_st == TXT_ERR) ||
|
||||
(buff_st == TXT_ABT))
|
||||
buff_st = TXT_ETY;
|
||||
}
|
||||
s->tx_status.u32 = (s->tx_status.u32 & ~buff_st_mask) |
|
||||
(buff_st << (i * 4));
|
||||
}
|
||||
|
||||
ctucan_send_ready_buffers(s);
|
||||
ctucan_update_txnf(s);
|
||||
}
|
||||
break;
|
||||
case CTU_CAN_FD_TX_PRIORITY:
|
||||
s->tx_priority.u32 = (uint32_t)val;
|
||||
break;
|
||||
}
|
||||
|
||||
ctucan_update_irq(s);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t ctucan_mem_read(CtuCanCoreState *s, hwaddr addr, unsigned size)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
|
||||
DPRINTF("read addr 0x%02x ...\n", (unsigned int)addr);
|
||||
|
||||
if (addr > CTUCAN_CORE_MEM_SIZE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (addr & ~3) {
|
||||
case CTU_CAN_FD_DEVICE_ID:
|
||||
{
|
||||
union ctu_can_fd_device_id_version idver;
|
||||
idver.u32 = 0;
|
||||
idver.s.device_id = CTU_CAN_FD_ID;
|
||||
idver.s.ver_major = 2;
|
||||
idver.s.ver_minor = 2;
|
||||
val = idver.u32;
|
||||
}
|
||||
break;
|
||||
case CTU_CAN_FD_MODE:
|
||||
val = s->mode_settings.u32;
|
||||
break;
|
||||
case CTU_CAN_FD_STATUS:
|
||||
val = s->status.u32;
|
||||
break;
|
||||
case CTU_CAN_FD_INT_STAT:
|
||||
val = s->int_stat.u32;
|
||||
break;
|
||||
case CTU_CAN_FD_INT_ENA_SET:
|
||||
case CTU_CAN_FD_INT_ENA_CLR:
|
||||
val = s->int_ena.u32;
|
||||
break;
|
||||
case CTU_CAN_FD_INT_MASK_SET:
|
||||
case CTU_CAN_FD_INT_MASK_CLR:
|
||||
val = s->int_mask.u32;
|
||||
break;
|
||||
case CTU_CAN_FD_RX_MEM_INFO:
|
||||
s->rx_mem_info.u32 = 0;
|
||||
s->rx_mem_info.s.rx_buff_size = CTUCAN_RCV_BUF_LEN >> 2;
|
||||
s->rx_mem_info.s.rx_mem_free = (CTUCAN_RCV_BUF_LEN -
|
||||
s->rx_cnt) >> 2;
|
||||
val = s->rx_mem_info.u32;
|
||||
break;
|
||||
case CTU_CAN_FD_RX_POINTERS:
|
||||
{
|
||||
uint32_t rx_head_pos = s->rx_tail_pos + s->rx_cnt;
|
||||
rx_head_pos %= CTUCAN_RCV_BUF_LEN;
|
||||
s->rx_pointers.s.rx_wpp = rx_head_pos;
|
||||
s->rx_pointers.s.rx_rpp = s->rx_tail_pos;
|
||||
val = s->rx_pointers.u32;
|
||||
break;
|
||||
}
|
||||
case CTU_CAN_FD_RX_STATUS:
|
||||
case CTU_CAN_FD_RX_SETTINGS:
|
||||
if (!s->rx_status_rx_settings.s.rxfrc) {
|
||||
s->rx_status_rx_settings.s.rxe = 1;
|
||||
} else {
|
||||
s->rx_status_rx_settings.s.rxe = 0;
|
||||
}
|
||||
if (((s->rx_cnt + 3) & ~3) == CTUCAN_RCV_BUF_LEN) {
|
||||
s->rx_status_rx_settings.s.rxf = 1;
|
||||
} else {
|
||||
s->rx_status_rx_settings.s.rxf = 0;
|
||||
}
|
||||
val = s->rx_status_rx_settings.u32;
|
||||
break;
|
||||
case CTU_CAN_FD_RX_DATA:
|
||||
if (s->rx_cnt) {
|
||||
memcpy(&val, s->rx_buff + s->rx_tail_pos, 4);
|
||||
val = le32_to_cpu(val);
|
||||
if (!s->rx_frame_rem) {
|
||||
union ctu_can_fd_frame_form_w frame_form_w;
|
||||
frame_form_w.u32 = val;
|
||||
s->rx_frame_rem = frame_form_w.s.rwcnt * 4 + 4;
|
||||
}
|
||||
s->rx_cnt -= 4;
|
||||
s->rx_frame_rem -= 4;
|
||||
if (!s->rx_frame_rem) {
|
||||
s->rx_status_rx_settings.s.rxfrc--;
|
||||
if (!s->rx_status_rx_settings.s.rxfrc) {
|
||||
s->status.s.rxne = 0;
|
||||
s->status.s.idle = 1;
|
||||
s->status.s.rxs = 0;
|
||||
}
|
||||
}
|
||||
s->rx_tail_pos = (s->rx_tail_pos + 4) % CTUCAN_RCV_BUF_LEN;
|
||||
} else {
|
||||
val = 0;
|
||||
}
|
||||
break;
|
||||
case CTU_CAN_FD_TX_STATUS:
|
||||
val = s->tx_status.u32;
|
||||
break;
|
||||
case CTU_CAN_FD_TX_PRIORITY:
|
||||
val = s->tx_priority.u32;
|
||||
break;
|
||||
case CTU_CAN_FD_RX_FR_CTR:
|
||||
val = s->rx_fr_ctr.s.rx_fr_ctr_val;
|
||||
break;
|
||||
case CTU_CAN_FD_TX_FR_CTR:
|
||||
val = s->tx_fr_ctr.s.tx_fr_ctr_val;
|
||||
break;
|
||||
case CTU_CAN_FD_YOLO_REG:
|
||||
val = s->yolo_reg.s.yolo_val;
|
||||
break;
|
||||
}
|
||||
|
||||
val >>= ((addr & 3) << 3);
|
||||
if (size < 8) {
|
||||
val &= ((uint64_t)1 << (size << 3)) - 1;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
bool ctucan_can_receive(CanBusClientState *client)
|
||||
{
|
||||
CtuCanCoreState *s = container_of(client, CtuCanCoreState, bus_client);
|
||||
|
||||
if (!s->mode_settings.s.ena) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true; /* always return true, when operation mode */
|
||||
}
|
||||
|
||||
ssize_t ctucan_receive(CanBusClientState *client, const qemu_can_frame *frames,
|
||||
size_t frames_cnt)
|
||||
{
|
||||
CtuCanCoreState *s = container_of(client, CtuCanCoreState, bus_client);
|
||||
static uint8_t rcv[CTUCAN_MSG_MAX_LEN];
|
||||
int i;
|
||||
int ret = -1;
|
||||
const qemu_can_frame *frame = frames;
|
||||
union ctu_can_fd_int_stat int_stat;
|
||||
int_stat.u32 = 0;
|
||||
|
||||
if (frames_cnt <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = ctucan_frame2buff(frame, rcv);
|
||||
|
||||
if (s->rx_cnt + ret > CTUCAN_RCV_BUF_LEN) { /* Data overrun. */
|
||||
s->status.s.dor = 1;
|
||||
int_stat.s.doi = 1;
|
||||
s->int_stat.u32 |= int_stat.u32 & ~s->int_mask.u32;
|
||||
ctucan_update_irq(s);
|
||||
DPRINTF("Receive FIFO overrun\n");
|
||||
return ret;
|
||||
}
|
||||
s->status.s.idle = 0;
|
||||
s->status.s.rxs = 1;
|
||||
int_stat.s.rxi = 1;
|
||||
if (((s->rx_cnt + 3) & ~3) == CTUCAN_RCV_BUF_LEN) {
|
||||
int_stat.s.rxfi = 1;
|
||||
}
|
||||
s->int_stat.u32 |= int_stat.u32 & ~s->int_mask.u32;
|
||||
s->rx_fr_ctr.s.rx_fr_ctr_val++;
|
||||
s->rx_status_rx_settings.s.rxfrc++;
|
||||
for (i = 0; i < ret; i++) {
|
||||
s->rx_buff[(s->rx_tail_pos + s->rx_cnt) % CTUCAN_RCV_BUF_LEN] = rcv[i];
|
||||
s->rx_cnt++;
|
||||
}
|
||||
s->status.s.rxne = 1;
|
||||
|
||||
ctucan_update_irq(s);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static CanBusClientInfo ctucan_bus_client_info = {
|
||||
.can_receive = ctucan_can_receive,
|
||||
.receive = ctucan_receive,
|
||||
};
|
||||
|
||||
|
||||
int ctucan_connect_to_bus(CtuCanCoreState *s, CanBusState *bus)
|
||||
{
|
||||
s->bus_client.info = &ctucan_bus_client_info;
|
||||
|
||||
if (!bus) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (can_bus_insert_client(bus, &s->bus_client) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ctucan_disconnect(CtuCanCoreState *s)
|
||||
{
|
||||
can_bus_remove_client(&s->bus_client);
|
||||
}
|
||||
|
||||
int ctucan_init(CtuCanCoreState *s, qemu_irq irq)
|
||||
{
|
||||
s->irq = irq;
|
||||
|
||||
qemu_irq_lower(s->irq);
|
||||
|
||||
ctucan_hardware_reset(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const VMStateDescription vmstate_qemu_ctucan_tx_buffer = {
|
||||
.name = "qemu_ctucan_tx_buffer",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8_ARRAY(data, CtuCanCoreMsgBuffer, CTUCAN_CORE_MSG_MAX_LEN),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static int ctucan_post_load(void *opaque, int version_id)
|
||||
{
|
||||
CtuCanCoreState *s = opaque;
|
||||
ctucan_update_irq(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* VMState is needed for live migration of QEMU images */
|
||||
const VMStateDescription vmstate_ctucan = {
|
||||
.name = "ctucan",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.post_load = ctucan_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(mode_settings.u32, CtuCanCoreState),
|
||||
VMSTATE_UINT32(status.u32, CtuCanCoreState),
|
||||
VMSTATE_UINT32(int_stat.u32, CtuCanCoreState),
|
||||
VMSTATE_UINT32(int_ena.u32, CtuCanCoreState),
|
||||
VMSTATE_UINT32(int_mask.u32, CtuCanCoreState),
|
||||
VMSTATE_UINT32(brt.u32, CtuCanCoreState),
|
||||
VMSTATE_UINT32(brt_fd.u32, CtuCanCoreState),
|
||||
VMSTATE_UINT32(ewl_erp_fault_state.u32, CtuCanCoreState),
|
||||
VMSTATE_UINT32(rec_tec.u32, CtuCanCoreState),
|
||||
VMSTATE_UINT32(err_norm_err_fd.u32, CtuCanCoreState),
|
||||
VMSTATE_UINT32(ctr_pres.u32, CtuCanCoreState),
|
||||
VMSTATE_UINT32(filter_a_mask.u32, CtuCanCoreState),
|
||||
VMSTATE_UINT32(filter_a_val.u32, CtuCanCoreState),
|
||||
VMSTATE_UINT32(filter_b_mask.u32, CtuCanCoreState),
|
||||
VMSTATE_UINT32(filter_b_val.u32, CtuCanCoreState),
|
||||
VMSTATE_UINT32(filter_c_mask.u32, CtuCanCoreState),
|
||||
VMSTATE_UINT32(filter_c_val.u32, CtuCanCoreState),
|
||||
VMSTATE_UINT32(filter_ran_low.u32, CtuCanCoreState),
|
||||
VMSTATE_UINT32(filter_ran_high.u32, CtuCanCoreState),
|
||||
VMSTATE_UINT32(filter_control_filter_status.u32, CtuCanCoreState),
|
||||
VMSTATE_UINT32(rx_mem_info.u32, CtuCanCoreState),
|
||||
VMSTATE_UINT32(rx_pointers.u32, CtuCanCoreState),
|
||||
VMSTATE_UINT32(rx_status_rx_settings.u32, CtuCanCoreState),
|
||||
VMSTATE_UINT32(tx_status.u32, CtuCanCoreState),
|
||||
VMSTATE_UINT32(tx_priority.u32, CtuCanCoreState),
|
||||
VMSTATE_UINT32(err_capt_alc.u32, CtuCanCoreState),
|
||||
VMSTATE_UINT32(trv_delay_ssp_cfg.u32, CtuCanCoreState),
|
||||
VMSTATE_UINT32(rx_fr_ctr.u32, CtuCanCoreState),
|
||||
VMSTATE_UINT32(tx_fr_ctr.u32, CtuCanCoreState),
|
||||
VMSTATE_UINT32(debug_register.u32, CtuCanCoreState),
|
||||
VMSTATE_UINT32(yolo_reg.u32, CtuCanCoreState),
|
||||
VMSTATE_UINT32(timestamp_low.u32, CtuCanCoreState),
|
||||
VMSTATE_UINT32(timestamp_high.u32, CtuCanCoreState),
|
||||
|
||||
VMSTATE_STRUCT_ARRAY(tx_buffer, CtuCanCoreState,
|
||||
CTUCAN_CORE_TXBUF_NUM, 0, vmstate_qemu_ctucan_tx_buffer,
|
||||
CtuCanCoreMsgBuffer),
|
||||
|
||||
VMSTATE_BUFFER(rx_buff, CtuCanCoreState),
|
||||
VMSTATE_UINT32(rx_tail_pos, CtuCanCoreState),
|
||||
VMSTATE_UINT32(rx_cnt, CtuCanCoreState),
|
||||
VMSTATE_UINT32(rx_frame_rem, CtuCanCoreState),
|
||||
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
127
hw/net/can/ctucan_core.h
Normal file
127
hw/net/can/ctucan_core.h
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* CTU CAN FD device emulation
|
||||
* http://canbus.pages.fel.cvut.cz/
|
||||
*
|
||||
* Copyright (c) 2019 Jan Charvat (jancharvat.charvat@gmail.com)
|
||||
*
|
||||
* Based on Kvaser PCI CAN device (SJA1000 based) emulation implemented by
|
||||
* Jin Yang and Pavel Pisa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef HW_CAN_CTUCAN_CORE_H
|
||||
#define HW_CAN_CTUCAN_CORE_H
|
||||
|
||||
#include "exec/hwaddr.h"
|
||||
#include "net/can_emu.h"
|
||||
|
||||
|
||||
#ifndef __LITTLE_ENDIAN_BITFIELD
|
||||
#define __LITTLE_ENDIAN_BITFIELD 1
|
||||
#endif
|
||||
|
||||
#include "ctu_can_fd_frame.h"
|
||||
#include "ctu_can_fd_regs.h"
|
||||
|
||||
#define CTUCAN_CORE_MEM_SIZE 0x500
|
||||
|
||||
/* The max size for a message in FIFO */
|
||||
#define CTUCAN_MSG_MAX_LEN (CTU_CAN_FD_DATA_1_4_W + 64)
|
||||
/* The receive buffer size. */
|
||||
#define CTUCAN_RCV_BUF_LEN (1024 * 8)
|
||||
|
||||
|
||||
/* The max size for a message buffer */
|
||||
#define CTUCAN_CORE_MSG_MAX_LEN 0x50
|
||||
/* The receive buffer size. */
|
||||
#define CTUCAN_CORE_RCV_BUF_LEN 0x1000
|
||||
|
||||
#define CTUCAN_CORE_TXBUF_NUM 4
|
||||
|
||||
typedef struct CtuCanCoreMsgBuffer {
|
||||
uint8_t data[CTUCAN_CORE_MSG_MAX_LEN];
|
||||
} CtuCanCoreMsgBuffer;
|
||||
|
||||
typedef struct CtuCanCoreState {
|
||||
union ctu_can_fd_mode_settings mode_settings;
|
||||
union ctu_can_fd_status status;
|
||||
union ctu_can_fd_int_stat int_stat;
|
||||
union ctu_can_fd_int_ena_set int_ena;
|
||||
union ctu_can_fd_int_mask_set int_mask;
|
||||
union ctu_can_fd_btr brt;
|
||||
union ctu_can_fd_btr_fd brt_fd;
|
||||
union ctu_can_fd_ewl_erp_fault_state ewl_erp_fault_state;
|
||||
union ctu_can_fd_rec_tec rec_tec;
|
||||
union ctu_can_fd_err_norm_err_fd err_norm_err_fd;
|
||||
union ctu_can_fd_ctr_pres ctr_pres;
|
||||
union ctu_can_fd_filter_a_mask filter_a_mask;
|
||||
union ctu_can_fd_filter_a_val filter_a_val;
|
||||
union ctu_can_fd_filter_b_mask filter_b_mask;
|
||||
union ctu_can_fd_filter_b_val filter_b_val;
|
||||
union ctu_can_fd_filter_c_mask filter_c_mask;
|
||||
union ctu_can_fd_filter_c_val filter_c_val;
|
||||
union ctu_can_fd_filter_ran_low filter_ran_low;
|
||||
union ctu_can_fd_filter_ran_high filter_ran_high;
|
||||
union ctu_can_fd_filter_control_filter_status filter_control_filter_status;
|
||||
union ctu_can_fd_rx_mem_info rx_mem_info;
|
||||
union ctu_can_fd_rx_pointers rx_pointers;
|
||||
union ctu_can_fd_rx_status_rx_settings rx_status_rx_settings;
|
||||
union ctu_can_fd_tx_status tx_status;
|
||||
union ctu_can_fd_tx_priority tx_priority;
|
||||
union ctu_can_fd_err_capt_alc err_capt_alc;
|
||||
union ctu_can_fd_trv_delay_ssp_cfg trv_delay_ssp_cfg;
|
||||
union ctu_can_fd_rx_fr_ctr rx_fr_ctr;
|
||||
union ctu_can_fd_tx_fr_ctr tx_fr_ctr;
|
||||
union ctu_can_fd_debug_register debug_register;
|
||||
union ctu_can_fd_yolo_reg yolo_reg;
|
||||
union ctu_can_fd_timestamp_low timestamp_low;
|
||||
union ctu_can_fd_timestamp_high timestamp_high;
|
||||
|
||||
CtuCanCoreMsgBuffer tx_buffer[CTUCAN_CORE_TXBUF_NUM];
|
||||
|
||||
uint8_t rx_buff[CTUCAN_RCV_BUF_LEN]; /* 32~95 .. 64bytes Rx FIFO */
|
||||
uint32_t rx_tail_pos; /* Count by bytes. */
|
||||
uint32_t rx_cnt; /* Count by bytes. */
|
||||
uint32_t rx_frame_rem;
|
||||
|
||||
qemu_irq irq;
|
||||
CanBusClientState bus_client;
|
||||
} CtuCanCoreState;
|
||||
|
||||
void ctucan_hardware_reset(CtuCanCoreState *s);
|
||||
|
||||
void ctucan_mem_write(CtuCanCoreState *s, hwaddr addr, uint64_t val,
|
||||
unsigned size);
|
||||
|
||||
uint64_t ctucan_mem_read(CtuCanCoreState *s, hwaddr addr, unsigned size);
|
||||
|
||||
int ctucan_connect_to_bus(CtuCanCoreState *s, CanBusState *bus);
|
||||
|
||||
void ctucan_disconnect(CtuCanCoreState *s);
|
||||
|
||||
int ctucan_init(CtuCanCoreState *s, qemu_irq irq);
|
||||
|
||||
bool ctucan_can_receive(CanBusClientState *client);
|
||||
|
||||
ssize_t ctucan_receive(CanBusClientState *client,
|
||||
const qemu_can_frame *frames, size_t frames_cnt);
|
||||
|
||||
extern const VMStateDescription vmstate_ctucan;
|
||||
|
||||
#endif
|
281
hw/net/can/ctucan_pci.c
Normal file
281
hw/net/can/ctucan_pci.c
Normal file
@ -0,0 +1,281 @@
|
||||
/*
|
||||
* CTU CAN FD PCI device emulation
|
||||
* http://canbus.pages.fel.cvut.cz/
|
||||
*
|
||||
* Copyright (c) 2019 Jan Charvat (jancharvat.charvat@gmail.com)
|
||||
*
|
||||
* Based on Kvaser PCI CAN device (SJA1000 based) emulation implemented by
|
||||
* Jin Yang and Pavel Pisa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/event_notifier.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/thread.h"
|
||||
#include "qemu/sockets.h"
|
||||
#include "qapi/error.h"
|
||||
#include "chardev/char.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "net/can_emu.h"
|
||||
|
||||
#include "ctucan_core.h"
|
||||
|
||||
#define TYPE_CTUCAN_PCI_DEV "ctucan_pci"
|
||||
|
||||
typedef struct CtuCanPCIState CtuCanPCIState;
|
||||
DECLARE_INSTANCE_CHECKER(CtuCanPCIState, CTUCAN_PCI_DEV,
|
||||
TYPE_CTUCAN_PCI_DEV)
|
||||
|
||||
#define CTUCAN_PCI_CORE_COUNT 2
|
||||
#define CTUCAN_PCI_CORE_RANGE 0x10000
|
||||
|
||||
#define CTUCAN_PCI_BAR_COUNT 2
|
||||
|
||||
#define CTUCAN_PCI_BYTES_PER_CORE 0x4000
|
||||
|
||||
#ifndef PCI_VENDOR_ID_TEDIA
|
||||
#define PCI_VENDOR_ID_TEDIA 0x1760
|
||||
#endif
|
||||
|
||||
#define PCI_DEVICE_ID_TEDIA_CTUCAN_VER21 0xff00
|
||||
|
||||
#define CTUCAN_BAR0_RANGE 0x8000
|
||||
#define CTUCAN_BAR0_CTUCAN_ID 0x0000
|
||||
#define CTUCAN_BAR0_CRA_BASE 0x4000
|
||||
#define CYCLONE_IV_CRA_A2P_IE (0x0050)
|
||||
|
||||
#define CTUCAN_WITHOUT_CTUCAN_ID 0
|
||||
#define CTUCAN_WITH_CTUCAN_ID 1
|
||||
|
||||
struct CtuCanPCIState {
|
||||
/*< private >*/
|
||||
PCIDevice dev;
|
||||
/*< public >*/
|
||||
MemoryRegion ctucan_io[CTUCAN_PCI_BAR_COUNT];
|
||||
|
||||
CtuCanCoreState ctucan_state[CTUCAN_PCI_CORE_COUNT];
|
||||
qemu_irq irq;
|
||||
|
||||
char *model; /* The model that support, only SJA1000 now. */
|
||||
CanBusState *canbus[CTUCAN_PCI_CORE_COUNT];
|
||||
};
|
||||
|
||||
static void ctucan_pci_reset(DeviceState *dev)
|
||||
{
|
||||
CtuCanPCIState *d = CTUCAN_PCI_DEV(dev);
|
||||
int i;
|
||||
|
||||
for (i = 0 ; i < CTUCAN_PCI_CORE_COUNT; i++) {
|
||||
ctucan_hardware_reset(&d->ctucan_state[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t ctucan_pci_id_cra_io_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
if (addr >= 4) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t tmp = 0xC0000000 + CTUCAN_PCI_CORE_COUNT;
|
||||
tmp >>= ((addr & 3) << 3);
|
||||
if (size < 8) {
|
||||
tmp &= ((uint64_t)1 << (size << 3)) - 1;
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static void ctucan_pci_id_cra_io_write(void *opaque, hwaddr addr, uint64_t data,
|
||||
unsigned size)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static uint64_t ctucan_pci_cores_io_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
CtuCanPCIState *d = opaque;
|
||||
CtuCanCoreState *s;
|
||||
hwaddr core_num = addr / CTUCAN_PCI_BYTES_PER_CORE;
|
||||
|
||||
if (core_num >= CTUCAN_PCI_CORE_COUNT) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
s = &d->ctucan_state[core_num];
|
||||
|
||||
return ctucan_mem_read(s, addr % CTUCAN_PCI_BYTES_PER_CORE, size);
|
||||
}
|
||||
|
||||
static void ctucan_pci_cores_io_write(void *opaque, hwaddr addr, uint64_t data,
|
||||
unsigned size)
|
||||
{
|
||||
CtuCanPCIState *d = opaque;
|
||||
CtuCanCoreState *s;
|
||||
hwaddr core_num = addr / CTUCAN_PCI_BYTES_PER_CORE;
|
||||
|
||||
if (core_num >= CTUCAN_PCI_CORE_COUNT) {
|
||||
return;
|
||||
}
|
||||
|
||||
s = &d->ctucan_state[core_num];
|
||||
|
||||
return ctucan_mem_write(s, addr % CTUCAN_PCI_BYTES_PER_CORE, data, size);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps ctucan_pci_id_cra_io_ops = {
|
||||
.read = ctucan_pci_id_cra_io_read,
|
||||
.write = ctucan_pci_id_cra_io_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.impl.min_access_size = 1,
|
||||
.impl.max_access_size = 4,
|
||||
.valid.min_access_size = 1,
|
||||
.valid.max_access_size = 4,
|
||||
};
|
||||
|
||||
static const MemoryRegionOps ctucan_pci_cores_io_ops = {
|
||||
.read = ctucan_pci_cores_io_read,
|
||||
.write = ctucan_pci_cores_io_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.impl.min_access_size = 1,
|
||||
.impl.max_access_size = 4,
|
||||
.valid.min_access_size = 1,
|
||||
.valid.max_access_size = 4,
|
||||
};
|
||||
|
||||
static void ctucan_pci_realize(PCIDevice *pci_dev, Error **errp)
|
||||
{
|
||||
CtuCanPCIState *d = CTUCAN_PCI_DEV(pci_dev);
|
||||
uint8_t *pci_conf;
|
||||
int i;
|
||||
|
||||
pci_conf = pci_dev->config;
|
||||
pci_conf[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
|
||||
|
||||
d->irq = pci_allocate_irq(&d->dev);
|
||||
|
||||
for (i = 0 ; i < CTUCAN_PCI_CORE_COUNT; i++) {
|
||||
ctucan_init(&d->ctucan_state[i], d->irq);
|
||||
}
|
||||
|
||||
for (i = 0 ; i < CTUCAN_PCI_CORE_COUNT; i++) {
|
||||
if (ctucan_connect_to_bus(&d->ctucan_state[i], d->canbus[i]) < 0) {
|
||||
error_setg(errp, "ctucan_connect_to_bus failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
memory_region_init_io(&d->ctucan_io[0], OBJECT(d),
|
||||
&ctucan_pci_id_cra_io_ops, d,
|
||||
"ctucan_pci-core0", CTUCAN_BAR0_RANGE);
|
||||
memory_region_init_io(&d->ctucan_io[1], OBJECT(d),
|
||||
&ctucan_pci_cores_io_ops, d,
|
||||
"ctucan_pci-core1", CTUCAN_PCI_CORE_RANGE);
|
||||
|
||||
for (i = 0 ; i < CTUCAN_PCI_BAR_COUNT; i++) {
|
||||
pci_register_bar(&d->dev, i, PCI_BASE_ADDRESS_MEM_MASK & 0,
|
||||
&d->ctucan_io[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void ctucan_pci_exit(PCIDevice *pci_dev)
|
||||
{
|
||||
CtuCanPCIState *d = CTUCAN_PCI_DEV(pci_dev);
|
||||
int i;
|
||||
|
||||
for (i = 0 ; i < CTUCAN_PCI_CORE_COUNT; i++) {
|
||||
ctucan_disconnect(&d->ctucan_state[i]);
|
||||
}
|
||||
|
||||
qemu_free_irq(d->irq);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_ctucan_pci = {
|
||||
.name = "ctucan_pci",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_PCI_DEVICE(dev, CtuCanPCIState),
|
||||
VMSTATE_STRUCT(ctucan_state[0], CtuCanPCIState, 0, vmstate_ctucan,
|
||||
CtuCanCoreState),
|
||||
#if CTUCAN_PCI_CORE_COUNT >= 2
|
||||
VMSTATE_STRUCT(ctucan_state[1], CtuCanPCIState, 0, vmstate_ctucan,
|
||||
CtuCanCoreState),
|
||||
#endif
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void ctucan_pci_instance_init(Object *obj)
|
||||
{
|
||||
CtuCanPCIState *d = CTUCAN_PCI_DEV(obj);
|
||||
|
||||
object_property_add_link(obj, "canbus0", TYPE_CAN_BUS,
|
||||
(Object **)&d->canbus[0],
|
||||
qdev_prop_allow_set_link_before_realize, 0);
|
||||
#if CTUCAN_PCI_CORE_COUNT >= 2
|
||||
object_property_add_link(obj, "canbus1", TYPE_CAN_BUS,
|
||||
(Object **)&d->canbus[1],
|
||||
qdev_prop_allow_set_link_before_realize, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ctucan_pci_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
||||
|
||||
k->realize = ctucan_pci_realize;
|
||||
k->exit = ctucan_pci_exit;
|
||||
k->vendor_id = PCI_VENDOR_ID_TEDIA;
|
||||
k->device_id = PCI_DEVICE_ID_TEDIA_CTUCAN_VER21;
|
||||
k->revision = 0x00;
|
||||
k->class_id = 0x000c09;
|
||||
k->subsystem_vendor_id = PCI_VENDOR_ID_TEDIA;
|
||||
k->subsystem_id = PCI_DEVICE_ID_TEDIA_CTUCAN_VER21;
|
||||
dc->desc = "CTU CAN PCI";
|
||||
dc->vmsd = &vmstate_ctucan_pci;
|
||||
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
||||
dc->reset = ctucan_pci_reset;
|
||||
}
|
||||
|
||||
static const TypeInfo ctucan_pci_info = {
|
||||
.name = TYPE_CTUCAN_PCI_DEV,
|
||||
.parent = TYPE_PCI_DEVICE,
|
||||
.instance_size = sizeof(CtuCanPCIState),
|
||||
.class_init = ctucan_pci_class_init,
|
||||
.instance_init = ctucan_pci_instance_init,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
||||
static void ctucan_pci_register_types(void)
|
||||
{
|
||||
type_register_static(&ctucan_pci_info);
|
||||
}
|
||||
|
||||
type_init(ctucan_pci_register_types)
|
@ -2,3 +2,5 @@ softmmu_ss.add(when: 'CONFIG_CAN_SJA1000', if_true: files('can_sja1000.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_CAN_PCI', if_true: files('can_kvaser_pci.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_CAN_PCI', if_true: files('can_pcm3680_pci.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_CAN_PCI', if_true: files('can_mioe3680_pci.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_CAN_CTUCANFD', if_true: files('ctucan_core.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_CAN_CTUCANFD_PCI', if_true: files('ctucan_pci.c'))
|
||||
|
@ -4734,7 +4734,6 @@ static void spapr_machine_2_9_class_options(MachineClass *mc)
|
||||
spapr_machine_2_10_class_options(mc);
|
||||
compat_props_add(mc->compat_props, hw_compat_2_9, hw_compat_2_9_len);
|
||||
compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
|
||||
mc->numa_auto_assign_ram = numa_legacy_auto_assign_ram;
|
||||
smc->pre_2_10_has_unused_icps = true;
|
||||
smc->resize_hpt_default = SPAPR_RESIZE_HPT_DISABLED;
|
||||
}
|
||||
|
@ -277,10 +277,10 @@ static int megasas_map_sgl(MegasasState *s, MegasasCmd *cmd, union mfi_sgl *sgl)
|
||||
|
||||
cmd->flags = le16_to_cpu(cmd->frame->header.flags);
|
||||
iov_count = cmd->frame->header.sge_count;
|
||||
if (iov_count > MEGASAS_MAX_SGE) {
|
||||
if (!iov_count || iov_count > MEGASAS_MAX_SGE) {
|
||||
trace_megasas_iovec_sgl_overflow(cmd->index, iov_count,
|
||||
MEGASAS_MAX_SGE);
|
||||
return iov_count;
|
||||
return -1;
|
||||
}
|
||||
pci_dma_sglist_init(&cmd->qsg, PCI_DEVICE(s), iov_count);
|
||||
for (i = 0; i < iov_count; i++) {
|
||||
@ -310,7 +310,7 @@ static int megasas_map_sgl(MegasasState *s, MegasasCmd *cmd, union mfi_sgl *sgl)
|
||||
return 0;
|
||||
unmap:
|
||||
qemu_sglist_destroy(&cmd->qsg);
|
||||
return iov_count - i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -162,7 +162,8 @@ static void scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s)
|
||||
}
|
||||
}
|
||||
|
||||
if (s->type == TYPE_DISK && (r->req.cmd.buf[1] & 0x01)) {
|
||||
if ((s->type == TYPE_DISK || s->type == TYPE_ZBC) &&
|
||||
(r->req.cmd.buf[1] & 0x01)) {
|
||||
page = r->req.cmd.buf[2];
|
||||
if (page == 0xb0) {
|
||||
uint32_t max_transfer =
|
||||
@ -299,10 +300,11 @@ static void scsi_read_complete(void * opaque, int ret)
|
||||
}
|
||||
blk_set_guest_block_size(s->conf.blk, s->blocksize);
|
||||
|
||||
/* Patch MODE SENSE device specific parameters if the BDS is opened
|
||||
/*
|
||||
* Patch MODE SENSE device specific parameters if the BDS is opened
|
||||
* readonly.
|
||||
*/
|
||||
if ((s->type == TYPE_DISK || s->type == TYPE_TAPE) &&
|
||||
if ((s->type == TYPE_DISK || s->type == TYPE_TAPE || s->type == TYPE_ZBC) &&
|
||||
blk_is_read_only(s->conf.blk) &&
|
||||
(r->req.cmd.buf[0] == MODE_SENSE ||
|
||||
r->req.cmd.buf[0] == MODE_SENSE_10) &&
|
||||
@ -617,7 +619,7 @@ static void scsi_generic_read_device_identification(SCSIDevice *s)
|
||||
void scsi_generic_read_device_inquiry(SCSIDevice *s)
|
||||
{
|
||||
scsi_generic_read_device_identification(s);
|
||||
if (s->type == TYPE_DISK) {
|
||||
if (s->type == TYPE_DISK || s->type == TYPE_ZBC) {
|
||||
scsi_generic_set_vpd_bl_emulation(s);
|
||||
} else {
|
||||
s->needs_vpd_bl_emulation = false;
|
||||
|
@ -32,6 +32,8 @@ int vhost_scsi_common_start(VHostSCSICommon *vsc)
|
||||
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
|
||||
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
|
||||
|
||||
VirtIOSCSICommon *vs = (VirtIOSCSICommon *)vsc;
|
||||
|
||||
if (!k->set_guest_notifiers) {
|
||||
error_report("binding does not support guest notifiers");
|
||||
return -ENOSYS;
|
||||
@ -49,6 +51,23 @@ int vhost_scsi_common_start(VHostSCSICommon *vsc)
|
||||
}
|
||||
|
||||
vsc->dev.acked_features = vdev->guest_features;
|
||||
|
||||
assert(vsc->inflight == NULL);
|
||||
vsc->inflight = g_new0(struct vhost_inflight, 1);
|
||||
ret = vhost_dev_get_inflight(&vsc->dev,
|
||||
vs->conf.virtqueue_size,
|
||||
vsc->inflight);
|
||||
if (ret < 0) {
|
||||
error_report("Error get inflight: %d", -ret);
|
||||
goto err_guest_notifiers;
|
||||
}
|
||||
|
||||
ret = vhost_dev_set_inflight(&vsc->dev, vsc->inflight);
|
||||
if (ret < 0) {
|
||||
error_report("Error set inflight: %d", -ret);
|
||||
goto err_guest_notifiers;
|
||||
}
|
||||
|
||||
ret = vhost_dev_start(&vsc->dev, vdev);
|
||||
if (ret < 0) {
|
||||
error_report("Error start vhost dev");
|
||||
@ -66,6 +85,9 @@ int vhost_scsi_common_start(VHostSCSICommon *vsc)
|
||||
return ret;
|
||||
|
||||
err_guest_notifiers:
|
||||
g_free(vsc->inflight);
|
||||
vsc->inflight = NULL;
|
||||
|
||||
k->set_guest_notifiers(qbus->parent, vsc->dev.nvqs, false);
|
||||
err_host_notifiers:
|
||||
vhost_dev_disable_notifiers(&vsc->dev, vdev);
|
||||
@ -89,6 +111,11 @@ void vhost_scsi_common_stop(VHostSCSICommon *vsc)
|
||||
}
|
||||
assert(ret >= 0);
|
||||
|
||||
if (vsc->inflight) {
|
||||
vhost_dev_free_inflight(vsc->inflight);
|
||||
vsc->inflight = NULL;
|
||||
}
|
||||
|
||||
vhost_dev_disable_notifiers(&vsc->dev, vdev);
|
||||
}
|
||||
|
||||
|
@ -228,8 +228,11 @@ enum IOMMUMemoryRegionAttr {
|
||||
* attributes and the output TLB entry depends on the transaction
|
||||
* attributes, we represent this using IOMMU indexes. Each index
|
||||
* selects a particular translation table that the IOMMU has:
|
||||
*
|
||||
* @attrs_to_index returns the IOMMU index for a set of transaction attributes
|
||||
*
|
||||
* @translate takes an input address and an IOMMU index
|
||||
*
|
||||
* and the mapping returned can only depend on the input address and the
|
||||
* IOMMU index.
|
||||
*
|
||||
@ -238,10 +241,13 @@ enum IOMMUMemoryRegionAttr {
|
||||
* for secure transactions and one for non-secure transactions.
|
||||
*/
|
||||
struct IOMMUMemoryRegionClass {
|
||||
/* private */
|
||||
/* private: */
|
||||
MemoryRegionClass parent_class;
|
||||
|
||||
/*
|
||||
/* public: */
|
||||
/**
|
||||
* @translate:
|
||||
*
|
||||
* Return a TLB entry that contains a given address.
|
||||
*
|
||||
* The IOMMUAccessFlags indicated via @flag are optional and may
|
||||
@ -262,26 +268,38 @@ struct IOMMUMemoryRegionClass {
|
||||
* information when the IOMMU mapping changes.
|
||||
*
|
||||
* @iommu: the IOMMUMemoryRegion
|
||||
*
|
||||
* @hwaddr: address to be translated within the memory region
|
||||
* @flag: requested access permissions
|
||||
*
|
||||
* @flag: requested access permission
|
||||
*
|
||||
* @iommu_idx: IOMMU index for the translation
|
||||
*/
|
||||
IOMMUTLBEntry (*translate)(IOMMUMemoryRegion *iommu, hwaddr addr,
|
||||
IOMMUAccessFlags flag, int iommu_idx);
|
||||
/* Returns minimum supported page size in bytes.
|
||||
/**
|
||||
* @get_min_page_size:
|
||||
*
|
||||
* Returns minimum supported page size in bytes.
|
||||
*
|
||||
* If this method is not provided then the minimum is assumed to
|
||||
* be TARGET_PAGE_SIZE.
|
||||
*
|
||||
* @iommu: the IOMMUMemoryRegion
|
||||
*/
|
||||
uint64_t (*get_min_page_size)(IOMMUMemoryRegion *iommu);
|
||||
/* Called when IOMMU Notifier flag changes (ie when the set of
|
||||
/**
|
||||
* @notify_flag_changed:
|
||||
*
|
||||
* Called when IOMMU Notifier flag changes (ie when the set of
|
||||
* events which IOMMU users are requesting notification for changes).
|
||||
* Optional method -- need not be provided if the IOMMU does not
|
||||
* need to know exactly which events must be notified.
|
||||
*
|
||||
* @iommu: the IOMMUMemoryRegion
|
||||
*
|
||||
* @old_flags: events which previously needed to be notified
|
||||
*
|
||||
* @new_flags: events which now need to be notified
|
||||
*
|
||||
* Returns 0 on success, or a negative errno; in particular
|
||||
@ -293,7 +311,10 @@ struct IOMMUMemoryRegionClass {
|
||||
IOMMUNotifierFlag old_flags,
|
||||
IOMMUNotifierFlag new_flags,
|
||||
Error **errp);
|
||||
/* Called to handle memory_region_iommu_replay().
|
||||
/**
|
||||
* @replay:
|
||||
*
|
||||
* Called to handle memory_region_iommu_replay().
|
||||
*
|
||||
* The default implementation of memory_region_iommu_replay() is to
|
||||
* call the IOMMU translate method for every page in the address space
|
||||
@ -310,7 +331,10 @@ struct IOMMUMemoryRegionClass {
|
||||
*/
|
||||
void (*replay)(IOMMUMemoryRegion *iommu, IOMMUNotifier *notifier);
|
||||
|
||||
/* Get IOMMU misc attributes. This is an optional method that
|
||||
/**
|
||||
* @get_attr:
|
||||
*
|
||||
* Get IOMMU misc attributes. This is an optional method that
|
||||
* can be used to allow users of the IOMMU to get implementation-specific
|
||||
* information. The IOMMU implements this method to handle calls
|
||||
* by IOMMU users to memory_region_iommu_get_attr() by filling in
|
||||
@ -319,7 +343,9 @@ struct IOMMUMemoryRegionClass {
|
||||
* memory_region_iommu_get_attr() will always return -EINVAL.
|
||||
*
|
||||
* @iommu: the IOMMUMemoryRegion
|
||||
*
|
||||
* @attr: attribute being queried
|
||||
*
|
||||
* @data: memory to fill in with the attribute data
|
||||
*
|
||||
* Returns 0 on success, or a negative errno; in particular
|
||||
@ -328,7 +354,10 @@ struct IOMMUMemoryRegionClass {
|
||||
int (*get_attr)(IOMMUMemoryRegion *iommu, enum IOMMUMemoryRegionAttr attr,
|
||||
void *data);
|
||||
|
||||
/* Return the IOMMU index to use for a given set of transaction attributes.
|
||||
/**
|
||||
* @attrs_to_index:
|
||||
*
|
||||
* Return the IOMMU index to use for a given set of transaction attributes.
|
||||
*
|
||||
* Optional method: if an IOMMU only supports a single IOMMU index then
|
||||
* the default implementation of memory_region_iommu_attrs_to_index()
|
||||
@ -341,7 +370,10 @@ struct IOMMUMemoryRegionClass {
|
||||
*/
|
||||
int (*attrs_to_index)(IOMMUMemoryRegion *iommu, MemTxAttrs attrs);
|
||||
|
||||
/* Return the number of IOMMU indexes this IOMMU supports.
|
||||
/**
|
||||
* @num_indexes:
|
||||
*
|
||||
* Return the number of IOMMU indexes this IOMMU supports.
|
||||
*
|
||||
* Optional method: if this method is not provided, then
|
||||
* memory_region_iommu_num_indexes() will return 1, indicating that
|
||||
@ -372,7 +404,6 @@ struct MemoryRegion {
|
||||
bool nonvolatile;
|
||||
bool rom_device;
|
||||
bool flush_coalesced_mmio;
|
||||
bool global_locking;
|
||||
uint8_t dirty_log_mask;
|
||||
bool is_iommu;
|
||||
RAMBlock *ram_block;
|
||||
@ -1706,19 +1737,6 @@ void memory_region_set_flush_coalesced(MemoryRegion *mr);
|
||||
*/
|
||||
void memory_region_clear_flush_coalesced(MemoryRegion *mr);
|
||||
|
||||
/**
|
||||
* memory_region_clear_global_locking: Declares that access processing does
|
||||
* not depend on the QEMU global lock.
|
||||
*
|
||||
* By clearing this property, accesses to the memory region will be processed
|
||||
* outside of QEMU's global lock (unless the lock is held on when issuing the
|
||||
* access request). In this case, the device model implementing the access
|
||||
* handlers is responsible for synchronization of concurrency.
|
||||
*
|
||||
* @mr: the memory region to be updated.
|
||||
*/
|
||||
void memory_region_clear_global_locking(MemoryRegion *mr);
|
||||
|
||||
/**
|
||||
* memory_region_add_eventfd: Request an eventfd to be triggered when a word
|
||||
* is written to a location.
|
||||
|
@ -202,8 +202,6 @@ struct MachineClass {
|
||||
strList *allowed_dynamic_sysbus_devices;
|
||||
bool auto_enable_numa_with_memhp;
|
||||
bool auto_enable_numa_with_memdev;
|
||||
void (*numa_auto_assign_ram)(MachineClass *mc, NodeInfo *nodes,
|
||||
int nb_nodes, ram_addr_t size);
|
||||
bool ignore_boot_device_suffixes;
|
||||
bool smbus_no_migration_support;
|
||||
bool nvdimm_supported;
|
||||
|
@ -61,7 +61,7 @@ struct SerialState {
|
||||
uint32_t baudbase;
|
||||
uint32_t tsr_retry;
|
||||
guint watch_tag;
|
||||
uint32_t wakeup;
|
||||
bool wakeup;
|
||||
|
||||
/* Time when the last byte was successfully sent out of the tsr */
|
||||
uint64_t last_xmit_ts;
|
||||
@ -90,12 +90,6 @@ struct SerialMM {
|
||||
uint8_t endianness;
|
||||
};
|
||||
|
||||
struct SerialIO {
|
||||
SysBusDevice parent;
|
||||
|
||||
SerialState serial;
|
||||
};
|
||||
|
||||
extern const VMStateDescription vmstate_serial;
|
||||
extern const MemoryRegionOps serial_io_ops;
|
||||
|
||||
@ -107,9 +101,6 @@ OBJECT_DECLARE_SIMPLE_TYPE(SerialState, SERIAL)
|
||||
#define TYPE_SERIAL_MM "serial-mm"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(SerialMM, SERIAL_MM)
|
||||
|
||||
#define TYPE_SERIAL_IO "serial-io"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(SerialIO, SERIAL_IO)
|
||||
|
||||
SerialMM *serial_mm_init(MemoryRegion *address_space,
|
||||
hwaddr base, int regshift,
|
||||
qemu_irq irq, int baudbase,
|
||||
|
@ -20,7 +20,7 @@
|
||||
* @boot_cpus: number of present VCPUs
|
||||
* @smp_dies: number of dies per one package
|
||||
*/
|
||||
struct PCMachineState {
|
||||
typedef struct PCMachineState {
|
||||
/*< private >*/
|
||||
X86MachineState parent_obj;
|
||||
|
||||
@ -50,7 +50,7 @@ struct PCMachineState {
|
||||
|
||||
/* ACPI Memory hotplug IO base address */
|
||||
hwaddr memhp_io_base;
|
||||
};
|
||||
} PCMachineState;
|
||||
|
||||
#define PC_MACHINE_ACPI_DEVICE_PROP "acpi-device"
|
||||
#define PC_MACHINE_MAX_RAM_BELOW_4G "max-ram-below-4g"
|
||||
@ -118,6 +118,9 @@ struct PCMachineClass {
|
||||
|
||||
/* use PVH to load kernels that support this feature */
|
||||
bool pvh_enabled;
|
||||
|
||||
/* create kvmclock device even when KVM PV features are not exposed */
|
||||
bool kvmclock_create_always;
|
||||
};
|
||||
|
||||
#define TYPE_PC_MACHINE "generic-pc-machine"
|
||||
|
@ -15,11 +15,11 @@
|
||||
|
||||
#ifdef CONFIG_KVM
|
||||
|
||||
void kvmclock_create(void);
|
||||
void kvmclock_create(bool create_always);
|
||||
|
||||
#else /* CONFIG_KVM */
|
||||
|
||||
static inline void kvmclock_create(void)
|
||||
static inline void kvmclock_create(bool create_always)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,8 @@ struct VHostSCSICommon {
|
||||
int lun;
|
||||
uint64_t host_features;
|
||||
bool migratable;
|
||||
|
||||
struct vhost_inflight *inflight;
|
||||
};
|
||||
|
||||
int vhost_scsi_common_start(VHostSCSICommon *vsc);
|
||||
|
15
include/hw/xen/xen-x86.h
Normal file
15
include/hw/xen/xen-x86.h
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Xen X86-specific
|
||||
*
|
||||
* Copyright 2020 Red Hat, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
#ifndef QEMU_HW_XEN_X86_H
|
||||
#define QEMU_HW_XEN_X86_H
|
||||
|
||||
#include "hw/i386/pc.h"
|
||||
|
||||
void xen_hvm_init_pc(PCMachineState *pcms, MemoryRegion **ram_memory);
|
||||
|
||||
#endif /* QEMU_HW_XEN_X86_H */
|
@ -30,8 +30,6 @@ qemu_irq *xen_interrupt_controller_init(void);
|
||||
|
||||
void xenstore_store_pv_console_info(int i, struct Chardev *chr);
|
||||
|
||||
void xen_hvm_init(PCMachineState *pcms, MemoryRegion **ram_memory);
|
||||
|
||||
void xen_register_framebuffer(struct MemoryRegion *mr);
|
||||
|
||||
#endif /* QEMU_HW_XEN_H */
|
||||
|
@ -46,7 +46,8 @@ typedef uint32_t qemu_canid_t;
|
||||
typedef struct qemu_can_frame {
|
||||
qemu_canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */
|
||||
uint8_t can_dlc; /* data length code: 0 .. 8 */
|
||||
uint8_t data[8] QEMU_ALIGNED(8);
|
||||
uint8_t flags;
|
||||
uint8_t data[64] QEMU_ALIGNED(8);
|
||||
} qemu_can_frame;
|
||||
|
||||
/* Keep defines for QEMU separate from Linux ones for now */
|
||||
@ -58,6 +59,10 @@ typedef struct qemu_can_frame {
|
||||
#define QEMU_CAN_SFF_MASK 0x000007FFU /* standard frame format (SFF) */
|
||||
#define QEMU_CAN_EFF_MASK 0x1FFFFFFFU /* extended frame format (EFF) */
|
||||
|
||||
#define QEMU_CAN_FRMF_BRS 0x01 /* bit rate switch (2nd bitrate for data) */
|
||||
#define QEMU_CAN_FRMF_ESI 0x02 /* error state ind. of transmitting node */
|
||||
#define QEMU_CAN_FRMF_TYPE_FD 0x10 /* internal bit ind. of CAN FD frame */
|
||||
|
||||
/**
|
||||
* struct qemu_can_filter - CAN ID based filter in can_register().
|
||||
* @can_id: relevant bits of CAN ID which are not masked out.
|
||||
@ -97,6 +102,7 @@ struct CanBusClientState {
|
||||
char *model;
|
||||
char *name;
|
||||
void (*destructor)(CanBusClientState *);
|
||||
bool fd_mode;
|
||||
};
|
||||
|
||||
#define TYPE_CAN_BUS "can-bus"
|
||||
@ -116,4 +122,8 @@ int can_bus_client_set_filters(CanBusClientState *,
|
||||
const struct qemu_can_filter *filters,
|
||||
size_t filters_cnt);
|
||||
|
||||
uint8_t can_dlc2len(uint8_t can_dlc);
|
||||
|
||||
uint8_t can_len2dlc(uint8_t len);
|
||||
|
||||
#endif
|
||||
|
@ -209,8 +209,8 @@ void netdev_add(QemuOpts *opts, Error **errp);
|
||||
int net_hub_id_for_client(NetClientState *nc, int *id);
|
||||
NetClientState *net_hub_port_find(int hub_id);
|
||||
|
||||
#define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup"
|
||||
#define DEFAULT_NETWORK_DOWN_SCRIPT "/etc/qemu-ifdown"
|
||||
#define DEFAULT_NETWORK_SCRIPT CONFIG_SYSCONFDIR "/qemu-ifup"
|
||||
#define DEFAULT_NETWORK_DOWN_SCRIPT CONFIG_SYSCONFDIR "/qemu-ifdown"
|
||||
#define DEFAULT_BRIDGE_HELPER CONFIG_QEMU_HELPERDIR "/qemu-bridge-helper"
|
||||
#define DEFAULT_BRIDGE_INTERFACE "br0"
|
||||
|
||||
|
@ -131,7 +131,6 @@ char *qemu_find_file(int type, const char *name);
|
||||
|
||||
/* OS specific functions */
|
||||
void os_setup_early_signal_handling(void);
|
||||
char *os_find_datadir(void);
|
||||
int os_parse_cmd_args(int index, const char *optarg);
|
||||
|
||||
/*
|
||||
|
@ -184,4 +184,16 @@ int uleb128_decode_small(const uint8_t *in, uint32_t *n);
|
||||
*/
|
||||
int qemu_pstrcmp0(const char **str1, const char **str2);
|
||||
|
||||
|
||||
/**
|
||||
* get_relocated_path:
|
||||
* @dir: the directory (typically a `CONFIG_*DIR` variable) to be relocated.
|
||||
*
|
||||
* Returns a path for @dir that uses the directory of the running executable
|
||||
* as the prefix. For example, if `bindir` is `/usr/bin` and @dir is
|
||||
* `/usr/share/qemu`, the function will append `../share/qemu` to the
|
||||
* directory that contains the running executable and return the result.
|
||||
*/
|
||||
char *get_relocated_path(const char *dir);
|
||||
|
||||
#endif
|
||||
|
@ -597,12 +597,8 @@ char *qemu_get_local_state_pathname(const char *relative_pathname);
|
||||
* Try OS specific API first, if not working, parse from argv0. */
|
||||
void qemu_init_exec_dir(const char *argv0);
|
||||
|
||||
/* Get the saved exec dir.
|
||||
*
|
||||
* The caller is responsible for releasing the value returned with g_free()
|
||||
* after use.
|
||||
*/
|
||||
char *qemu_get_exec_dir(void);
|
||||
/* Get the saved exec dir. */
|
||||
const char *qemu_get_exec_dir(void);
|
||||
|
||||
/**
|
||||
* qemu_getauxval:
|
||||
|
@ -90,7 +90,6 @@ typedef struct PCIExpressDevice PCIExpressDevice;
|
||||
typedef struct PCIExpressHost PCIExpressHost;
|
||||
typedef struct PCIHostDeviceAddress PCIHostDeviceAddress;
|
||||
typedef struct PCIHostState PCIHostState;
|
||||
typedef struct PCMachineState PCMachineState;
|
||||
typedef struct PostcopyDiscardState PostcopyDiscardState;
|
||||
typedef struct Property Property;
|
||||
typedef struct PropertyInfo PropertyInfo;
|
||||
|
@ -28,399 +28,6 @@ typedef struct InterfaceInfo InterfaceInfo;
|
||||
|
||||
#define TYPE_OBJECT "object"
|
||||
|
||||
/**
|
||||
* SECTION:object.h
|
||||
* @title:Base Object Type System
|
||||
* @short_description: interfaces for creating new types and objects
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* <example>
|
||||
* <title>Creating a minimal type</title>
|
||||
* <programlisting>
|
||||
* #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)
|
||||
* </programlisting>
|
||||
* </example>
|
||||
*
|
||||
* 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()
|
||||
*
|
||||
* <example>
|
||||
* <programlisting>
|
||||
* 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)
|
||||
* </programlisting>
|
||||
* </example>
|
||||
*
|
||||
* 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:
|
||||
*
|
||||
* <example>
|
||||
* <title>Typecasting macros</title>
|
||||
* <programlisting>
|
||||
* #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)
|
||||
* </programlisting>
|
||||
* </example>
|
||||
*
|
||||
* # 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:
|
||||
*
|
||||
* <example>
|
||||
* <title>Overriding a virtual function</title>
|
||||
* <programlisting>
|
||||
* #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,
|
||||
* };
|
||||
* </programlisting>
|
||||
* </example>
|
||||
*
|
||||
* 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:
|
||||
*
|
||||
* <example>
|
||||
* <title>Defining an abstract class</title>
|
||||
* <programlisting>
|
||||
* #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);
|
||||
* }
|
||||
* </programlisting>
|
||||
* </example>
|
||||
*
|
||||
* # 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.
|
||||
*
|
||||
* <example>
|
||||
* <title>Overriding a virtual method</title>
|
||||
* <programlisting>
|
||||
* 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,
|
||||
* };
|
||||
* </programlisting>
|
||||
* </example>
|
||||
*
|
||||
* 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:
|
||||
*
|
||||
* <example>
|
||||
* <title>Declaring a simple type</title>
|
||||
* <programlisting>
|
||||
* OBJECT_DECLARE_SIMPLE_TYPE(MyDevice, my_device, MY_DEVICE, DEVICE)
|
||||
* </programlisting>
|
||||
* </example>
|
||||
*
|
||||
* This is equivalent to the following:
|
||||
*
|
||||
* <example>
|
||||
* <title>Expansion from declaring a simple type</title>
|
||||
* <programlisting>
|
||||
* 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;
|
||||
* };
|
||||
* </programlisting>
|
||||
* </example>
|
||||
*
|
||||
* 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:
|
||||
*
|
||||
* <example>
|
||||
* <title>Defining a simple type</title>
|
||||
* <programlisting>
|
||||
* OBJECT_DEFINE_TYPE(MyDevice, my_device, MY_DEVICE, DEVICE)
|
||||
* </programlisting>
|
||||
* </example>
|
||||
*
|
||||
* This is equivalent to the following:
|
||||
*
|
||||
* <example>
|
||||
* <title>Expansion from defining a simple type</title>
|
||||
* <programlisting>
|
||||
* 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);
|
||||
* </programlisting>
|
||||
* </example>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* <example>
|
||||
* <title>Defining a simple type implementing interfaces</title>
|
||||
* <programlisting>
|
||||
* OBJECT_DEFINE_TYPE_WITH_INTERFACES(MyDevice, my_device,
|
||||
* MY_DEVICE, DEVICE,
|
||||
* { TYPE_USER_CREATABLE }, { NULL })
|
||||
* </programlisting>
|
||||
* </example>
|
||||
*
|
||||
* If the type is not intended to be instantiated, then then
|
||||
* the OBJECT_DEFINE_ABSTRACT_TYPE() macro can be used instead:
|
||||
*
|
||||
* <example>
|
||||
* <title>Defining a simple type</title>
|
||||
* <programlisting>
|
||||
* OBJECT_DEFINE_ABSTRACT_TYPE(MyDevice, my_device, MY_DEVICE, DEVICE)
|
||||
* </programlisting>
|
||||
* </example>
|
||||
*/
|
||||
|
||||
|
||||
typedef struct ObjectProperty ObjectProperty;
|
||||
|
||||
/**
|
||||
@ -520,7 +127,7 @@ typedef void (ObjectFree)(void *obj);
|
||||
*/
|
||||
struct ObjectClass
|
||||
{
|
||||
/*< private >*/
|
||||
/* private: */
|
||||
Type type;
|
||||
GSList *interfaces;
|
||||
|
||||
@ -546,7 +153,7 @@ struct ObjectClass
|
||||
*/
|
||||
struct Object
|
||||
{
|
||||
/*< private >*/
|
||||
/* private: */
|
||||
ObjectClass *class;
|
||||
ObjectFree *free;
|
||||
GHashTable *properties;
|
||||
@ -908,7 +515,7 @@ struct InterfaceInfo {
|
||||
struct InterfaceClass
|
||||
{
|
||||
ObjectClass parent_class;
|
||||
/*< private >*/
|
||||
/* private: */
|
||||
ObjectClass *concrete_class;
|
||||
Type interface_type;
|
||||
};
|
||||
@ -980,27 +587,25 @@ Object *object_new(const char *typename);
|
||||
* 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;
|
||||
* .. code-block:: c
|
||||
* :caption: Creating an object with properties
|
||||
*
|
||||
* 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);
|
||||
* Error *err = NULL;
|
||||
* Object *obj;
|
||||
*
|
||||
* if (!obj) {
|
||||
* error_reportf_err(err, "Cannot create memory backend: ");
|
||||
* }
|
||||
* </programlisting>
|
||||
* </example>
|
||||
* 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) {
|
||||
* error_reportf_err(err, "Cannot create memory backend: ");
|
||||
* }
|
||||
*
|
||||
* The returned object will have one stable reference maintained
|
||||
* for as long as it is present in the object hierarchy.
|
||||
@ -1049,23 +654,21 @@ void object_apply_compat_props(Object *obj);
|
||||
* 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...;
|
||||
* .. code-block:: c
|
||||
* :caption: Update an object's properties
|
||||
*
|
||||
* if (!object_set_props(obj,
|
||||
* &err,
|
||||
* "share", "yes",
|
||||
* "mem-path", "/dev/shm/somefile",
|
||||
* "prealloc", "yes",
|
||||
* "size", "1048576",
|
||||
* NULL)) {
|
||||
* error_reportf_err(err, "Cannot set properties: ");
|
||||
* }
|
||||
* </programlisting>
|
||||
* </example>
|
||||
* Error *err = NULL;
|
||||
* Object *obj = ...get / create object...;
|
||||
*
|
||||
* if (!object_set_props(obj,
|
||||
* &err,
|
||||
* "share", "yes",
|
||||
* "mem-path", "/dev/shm/somefile",
|
||||
* "prealloc", "yes",
|
||||
* "size", "1048576",
|
||||
* NULL)) {
|
||||
* error_reportf_err(err, "Cannot set properties: ");
|
||||
* }
|
||||
*
|
||||
* The returned object will have one stable reference maintained
|
||||
* for as long as it is present in the object hierarchy.
|
||||
@ -1153,10 +756,11 @@ bool object_initialize_child_with_propsv(Object *parentobj,
|
||||
* object.
|
||||
* @type: The name of the type of the object to instantiate.
|
||||
*
|
||||
* This is like
|
||||
* object_initialize_child_with_props(parent, propname,
|
||||
* child, sizeof(*child), type,
|
||||
* &error_abort, NULL)
|
||||
* This is like::
|
||||
*
|
||||
* object_initialize_child_with_props(parent, propname,
|
||||
* child, sizeof(*child), type,
|
||||
* &error_abort, NULL)
|
||||
*/
|
||||
#define object_initialize_child(parent, propname, child, type) \
|
||||
object_initialize_child_internal((parent), (propname), \
|
||||
@ -1179,6 +783,11 @@ Object *object_dynamic_cast(Object *obj, const char *typename);
|
||||
|
||||
/**
|
||||
* object_dynamic_cast_assert:
|
||||
* @obj: The object to cast.
|
||||
* @typename: The @typename to cast to.
|
||||
* @file: Source code file where function was called
|
||||
* @line: Source code line where function was called
|
||||
* @func: Name of function where this function was called
|
||||
*
|
||||
* See object_dynamic_cast() for a description of the parameters of this
|
||||
* function. The only difference in behavior is that this function asserts
|
||||
@ -1255,6 +864,9 @@ type_init(do_qemu_init_ ## type_array)
|
||||
* object_class_dynamic_cast_assert:
|
||||
* @klass: The #ObjectClass to attempt to cast.
|
||||
* @typename: The QOM typename of the class to cast to.
|
||||
* @file: Source code file where function was called
|
||||
* @line: Source code line where function was called
|
||||
* @func: Name of function where this function was called
|
||||
*
|
||||
* See object_class_dynamic_cast() for a description of the parameters
|
||||
* of this function. The only difference in behavior is that this function
|
||||
@ -1406,6 +1018,23 @@ ObjectProperty *object_property_try_add(Object *obj, const char *name,
|
||||
* object_property_add:
|
||||
* Same as object_property_try_add() with @errp hardcoded to
|
||||
* &error_abort.
|
||||
*
|
||||
* @obj: the object to add a property to
|
||||
* @name: the name of the property. This can contain any character except for
|
||||
* a forward slash. In general, you should use hyphens '-' instead of
|
||||
* underscores '_' when naming properties.
|
||||
* @type: the type name of the property. This namespace is pretty loosely
|
||||
* defined. Sub namespaces are constructed by using a prefix and then
|
||||
* to angle brackets. For instance, the type 'virtio-net-pci' in the
|
||||
* 'link' namespace would be 'link<virtio-net-pci>'.
|
||||
* @get: The getter to be called to read a property. If this is NULL, then
|
||||
* the property cannot be read.
|
||||
* @set: the setter to be called to write a property. If this is NULL,
|
||||
* then the property cannot be written.
|
||||
* @release: called when the property is removed from the object. This is
|
||||
* meant to allow a property to free its opaque upon object
|
||||
* destruction. This may be NULL.
|
||||
* @opaque: an opaque pointer to pass to the callbacks for the property
|
||||
*/
|
||||
ObjectProperty *object_property_add(Object *obj, const char *name,
|
||||
const char *type,
|
||||
@ -1517,6 +1146,7 @@ typedef struct ObjectPropertyIterator {
|
||||
|
||||
/**
|
||||
* object_property_iter_init:
|
||||
* @iter: the iterator instance
|
||||
* @obj: the object
|
||||
*
|
||||
* Initializes an iterator for traversing all properties
|
||||
@ -1527,24 +1157,23 @@ typedef struct ObjectPropertyIterator {
|
||||
*
|
||||
* Typical usage pattern would be
|
||||
*
|
||||
* <example>
|
||||
* <title>Using object property iterators</title>
|
||||
* <programlisting>
|
||||
* ObjectProperty *prop;
|
||||
* ObjectPropertyIterator iter;
|
||||
* .. code-block:: c
|
||||
* :caption: Using object property iterators
|
||||
*
|
||||
* object_property_iter_init(&iter, obj);
|
||||
* while ((prop = object_property_iter_next(&iter))) {
|
||||
* ... do something with prop ...
|
||||
* }
|
||||
* </programlisting>
|
||||
* </example>
|
||||
* ObjectProperty *prop;
|
||||
* ObjectPropertyIterator iter;
|
||||
*
|
||||
* object_property_iter_init(&iter, obj);
|
||||
* while ((prop = object_property_iter_next(&iter))) {
|
||||
* ... do something with prop ...
|
||||
* }
|
||||
*/
|
||||
void object_property_iter_init(ObjectPropertyIterator *iter,
|
||||
Object *obj);
|
||||
|
||||
/**
|
||||
* object_class_property_iter_init:
|
||||
* @iter: the iterator instance
|
||||
* @klass: the class
|
||||
*
|
||||
* Initializes an iterator for traversing all properties
|
||||
@ -1592,6 +1221,7 @@ bool object_property_get(Object *obj, const char *name, Visitor *v,
|
||||
|
||||
/**
|
||||
* object_property_set_str:
|
||||
* @obj: the object
|
||||
* @name: the name of the property
|
||||
* @value: the value to be written to the property
|
||||
* @errp: returns an error if this function fails
|
||||
@ -1618,6 +1248,7 @@ char *object_property_get_str(Object *obj, const char *name,
|
||||
|
||||
/**
|
||||
* object_property_set_link:
|
||||
* @obj: the object
|
||||
* @name: the name of the property
|
||||
* @value: the value to be written to the property
|
||||
* @errp: returns an error if this function fails
|
||||
@ -1648,6 +1279,7 @@ Object *object_property_get_link(Object *obj, const char *name,
|
||||
|
||||
/**
|
||||
* object_property_set_bool:
|
||||
* @obj: the object
|
||||
* @name: the name of the property
|
||||
* @value: the value to be written to the property
|
||||
* @errp: returns an error if this function fails
|
||||
@ -1673,6 +1305,7 @@ bool object_property_get_bool(Object *obj, const char *name,
|
||||
|
||||
/**
|
||||
* object_property_set_int:
|
||||
* @obj: the object
|
||||
* @name: the name of the property
|
||||
* @value: the value to be written to the property
|
||||
* @errp: returns an error if this function fails
|
||||
@ -1698,6 +1331,7 @@ int64_t object_property_get_int(Object *obj, const char *name,
|
||||
|
||||
/**
|
||||
* object_property_set_uint:
|
||||
* @obj: the object
|
||||
* @name: the name of the property
|
||||
* @value: the value to be written to the property
|
||||
* @errp: returns an error if this function fails
|
||||
@ -1821,6 +1455,7 @@ Object *object_get_internal_root(void);
|
||||
|
||||
/**
|
||||
* object_get_canonical_path_component:
|
||||
* @obj: the object
|
||||
*
|
||||
* Returns: The final component in the object's canonical path. The canonical
|
||||
* path is the path within the composition tree starting from the root.
|
||||
@ -1830,6 +1465,7 @@ const char *object_get_canonical_path_component(const Object *obj);
|
||||
|
||||
/**
|
||||
* object_get_canonical_path:
|
||||
* @obj: the object
|
||||
*
|
||||
* Returns: The canonical path for a object, newly allocated. This is
|
||||
* the path within the composition tree starting from the root. Use
|
||||
@ -1919,6 +1555,10 @@ ObjectProperty *object_property_try_add_child(Object *obj, const char *name,
|
||||
|
||||
/**
|
||||
* object_property_add_child:
|
||||
* @obj: the object to add a property to
|
||||
* @name: the name of the property
|
||||
* @child: the child object
|
||||
*
|
||||
* Same as object_property_try_add_child() with @errp hardcoded to
|
||||
* &error_abort
|
||||
*/
|
||||
@ -1936,13 +1576,17 @@ typedef enum {
|
||||
|
||||
/**
|
||||
* object_property_allow_set_link:
|
||||
* @obj: the object to add a property to
|
||||
* @name: the name of the property
|
||||
* @child: the child object
|
||||
* @errp: pointer to error object
|
||||
*
|
||||
* The default implementation of the object_property_add_link() check()
|
||||
* callback function. It allows the link property to be set and never returns
|
||||
* an error.
|
||||
*/
|
||||
void object_property_allow_set_link(const Object *, const char *,
|
||||
Object *, Error **);
|
||||
void object_property_allow_set_link(const Object *obj, const char *name,
|
||||
Object *child, Error **errp);
|
||||
|
||||
/**
|
||||
* object_property_add_link:
|
||||
@ -2036,6 +1680,7 @@ ObjectProperty *object_class_property_add_bool(ObjectClass *klass,
|
||||
* @obj: the object to add a property to
|
||||
* @name: the name of the property
|
||||
* @typename: the name of the enum data type
|
||||
* @lookup: enum value namelookup table
|
||||
* @get: the getter or %NULL if the property is write-only.
|
||||
* @set: the setter or %NULL if the property is read-only
|
||||
*
|
||||
|
@ -218,6 +218,7 @@
|
||||
#define TYPE_ENCLOSURE 0x0d /* Enclosure Services Device */
|
||||
#define TYPE_RBC 0x0e /* Simplified Direct-Access Device */
|
||||
#define TYPE_OSD 0x11 /* Object-storage Device */
|
||||
#define TYPE_ZBC 0x14 /* Host-managed Zoned SCSI Device */
|
||||
#define TYPE_WLUN 0x1e /* Well known LUN */
|
||||
#define TYPE_NOT_PRESENT 0x1f
|
||||
#define TYPE_INACTIVE 0x20
|
||||
|
@ -106,10 +106,6 @@ void parse_numa_hmat_cache(MachineState *ms, NumaHmatCacheOptions *node,
|
||||
void numa_complete_configuration(MachineState *ms);
|
||||
void query_numa_node_mem(NumaNodeMem node_mem[], MachineState *ms);
|
||||
extern QemuOptsList qemu_numa_opts;
|
||||
void numa_legacy_auto_assign_ram(MachineClass *mc, NodeInfo *nodes,
|
||||
int nb_nodes, ram_addr_t size);
|
||||
void numa_default_auto_assign_ram(MachineClass *mc, NodeInfo *nodes,
|
||||
int nb_nodes, ram_addr_t size);
|
||||
void numa_cpu_pre_plug(const struct CPUArchId *slot, DeviceState *dev,
|
||||
Error **errp);
|
||||
bool numa_uses_legacy_mem(void);
|
||||
|
@ -14,7 +14,7 @@ extern const char *qemu_name;
|
||||
extern QemuUUID qemu_uuid;
|
||||
extern bool qemu_uuid_set;
|
||||
|
||||
void qemu_add_data_dir(const char *path);
|
||||
void qemu_add_data_dir(char *path);
|
||||
|
||||
void qemu_add_exit_notifier(Notifier *notify);
|
||||
void qemu_remove_exit_notifier(Notifier *notify);
|
||||
|
@ -8,6 +8,8 @@
|
||||
#ifndef SYSEMU_XEN_H
|
||||
#define SYSEMU_XEN_H
|
||||
|
||||
#include "exec/cpu-common.h"
|
||||
|
||||
#ifdef NEED_CPU_H
|
||||
# ifdef CONFIG_XEN
|
||||
# define CONFIG_XEN_IS_POSSIBLE
|
||||
|
202
meson.build
202
meson.build
@ -17,6 +17,11 @@ config_host = keyval.load(meson.current_build_dir() / 'config-host.mak')
|
||||
enable_modules = 'CONFIG_MODULES' in config_host
|
||||
enable_static = 'CONFIG_STATIC' in config_host
|
||||
build_docs = 'BUILD_DOCS' in config_host
|
||||
|
||||
if get_option('qemu_suffix').startswith('/')
|
||||
error('qemu_suffix cannot start with a /')
|
||||
endif
|
||||
|
||||
qemu_datadir = get_option('datadir') / get_option('qemu_suffix')
|
||||
qemu_docdir = get_option('docdir') / get_option('qemu_suffix')
|
||||
config_host_data = configuration_data()
|
||||
@ -49,6 +54,14 @@ configure_file(input: files('scripts/ninjatool.py'),
|
||||
# Compiler flags #
|
||||
##################
|
||||
|
||||
# Specify linker-script with add_project_link_arguments so that it is not placed
|
||||
# within a linker --start-group/--end-group pair
|
||||
if 'CONFIG_FUZZ' in config_host
|
||||
add_project_link_arguments(['-Wl,-T,',
|
||||
(meson.current_source_dir() / 'tests/qtest/fuzz/fork_fuzz.ld')],
|
||||
native: false, language: ['c', 'cpp', 'objc'])
|
||||
endif
|
||||
|
||||
add_project_arguments(config_host['QEMU_CFLAGS'].split(),
|
||||
native: false, language: ['c', 'objc'])
|
||||
add_project_arguments(config_host['QEMU_CXXFLAGS'].split(),
|
||||
@ -58,13 +71,6 @@ add_project_link_arguments(config_host['QEMU_LDFLAGS'].split(),
|
||||
add_project_arguments(config_host['QEMU_INCLUDES'].split(),
|
||||
language: ['c', 'cpp', 'objc'])
|
||||
|
||||
# Specify linker-script with add_project_link_arguments so that it is not placed
|
||||
# within a linker --start-group/--end-group pair
|
||||
if 'CONFIG_FUZZ' in config_host
|
||||
add_project_link_arguments(['-Wl,-T,',
|
||||
(meson.current_source_dir() / 'tests/qtest/fuzz/fork_fuzz.ld')],
|
||||
native: false, language: ['c', 'cpp', 'objc'])
|
||||
endif
|
||||
|
||||
link_language = meson.get_external_property('link_language', 'cpp')
|
||||
if link_language == 'cpp'
|
||||
@ -81,6 +87,14 @@ if 'SPARSE_CFLAGS' in config_host
|
||||
'compile_commands.json'])
|
||||
endif
|
||||
|
||||
###########################################
|
||||
# Target-specific checks and dependencies #
|
||||
###########################################
|
||||
|
||||
if targetos != 'linux' and get_option('mpath').enabled()
|
||||
error('Multipath is supported only on Linux')
|
||||
endif
|
||||
|
||||
m = cc.find_library('m', required: false)
|
||||
util = cc.find_library('util', required: false)
|
||||
winmm = []
|
||||
@ -88,7 +102,7 @@ socket = []
|
||||
version_res = []
|
||||
coref = []
|
||||
iokit = []
|
||||
cocoa = []
|
||||
cocoa = not_found
|
||||
hvf = []
|
||||
if targetos == 'windows'
|
||||
socket = cc.find_library('ws2_32')
|
||||
@ -101,7 +115,7 @@ if targetos == 'windows'
|
||||
elif targetos == 'darwin'
|
||||
coref = dependency('appleframeworks', modules: 'CoreFoundation')
|
||||
iokit = dependency('appleframeworks', modules: 'IOKit')
|
||||
cocoa = dependency('appleframeworks', modules: 'Cocoa')
|
||||
cocoa = dependency('appleframeworks', modules: 'Cocoa', required: get_option('cocoa'))
|
||||
hvf = dependency('appleframeworks', modules: 'Hypervisor')
|
||||
elif targetos == 'sunos'
|
||||
socket = [cc.find_library('socket'),
|
||||
@ -112,6 +126,15 @@ elif targetos == 'haiku'
|
||||
cc.find_library('network'),
|
||||
cc.find_library('bsd')]
|
||||
endif
|
||||
|
||||
if not cocoa.found() and get_option('cocoa').enabled()
|
||||
error('Cocoa not available on this platform')
|
||||
endif
|
||||
|
||||
################
|
||||
# Dependencies #
|
||||
################
|
||||
|
||||
# The path to glib.h is added to all compilation commands. This was
|
||||
# grandfathered in from the QEMU Makefiles.
|
||||
add_project_arguments(config_host['GLIB_CFLAGS'].split(),
|
||||
@ -218,10 +241,6 @@ if 'CONFIG_SPICE' in config_host
|
||||
link_args: config_host['SPICE_LIBS'].split())
|
||||
endif
|
||||
rt = cc.find_library('rt', required: false)
|
||||
libmpathpersist = not_found
|
||||
if config_host.has_key('CONFIG_MPATH')
|
||||
libmpathpersist = cc.find_library('mpathpersist')
|
||||
endif
|
||||
libdl = not_found
|
||||
if 'CONFIG_PLUGIN' in config_host
|
||||
libdl = cc.find_library('dl', required: true)
|
||||
@ -252,9 +271,76 @@ if 'CONFIG_CURL' in config_host
|
||||
link_args: config_host['CURL_LIBS'].split())
|
||||
endif
|
||||
libudev = not_found
|
||||
if 'CONFIG_LIBUDEV' in config_host
|
||||
libudev = declare_dependency(link_args: config_host['LIBUDEV_LIBS'].split())
|
||||
if targetos == 'linux' and (have_system or have_tools)
|
||||
libudev = dependency('libudev',
|
||||
required: get_option('mpath').enabled(),
|
||||
static: enable_static)
|
||||
endif
|
||||
|
||||
mpathpersist = not_found
|
||||
mpathpersist_new_api = false
|
||||
if targetos == 'linux' and have_tools and not get_option('mpath').disabled()
|
||||
mpath_test_source_new = '''
|
||||
#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;
|
||||
}'''
|
||||
mpath_test_source_old = '''
|
||||
#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;
|
||||
}'''
|
||||
mpathlibs = [libudev]
|
||||
if enable_static
|
||||
mpathlibs += cc.find_library('devmapper',
|
||||
required: get_option('mpath'),
|
||||
static: enable_static)
|
||||
endif
|
||||
mpathlibs += cc.find_library('multipath',
|
||||
required: get_option('mpath'),
|
||||
static: enable_static)
|
||||
mpathlibs += cc.find_library('mpathpersist',
|
||||
required: get_option('mpath'),
|
||||
static: enable_static)
|
||||
foreach lib: mpathlibs
|
||||
if not lib.found()
|
||||
mpathlibs = []
|
||||
break
|
||||
endif
|
||||
endforeach
|
||||
if mpathlibs.length() > 0
|
||||
if cc.links(mpath_test_source_new, dependencies: mpathlibs)
|
||||
mpathpersist = declare_dependency(dependencies: mpathlibs)
|
||||
mpathpersist_new_api = true
|
||||
elif cc.links(mpath_test_source_old, dependencies: mpathlibs)
|
||||
mpathpersist = declare_dependency(dependencies: mpathlibs)
|
||||
else
|
||||
if get_option('mpath').enabled()
|
||||
error('Cannot detect libmpathpersist API')
|
||||
else
|
||||
warning('Cannot detect libmpathpersist API, disabling')
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
brlapi = not_found
|
||||
if 'CONFIG_BRLAPI' in config_host
|
||||
brlapi = declare_dependency(link_args: config_host['BRLAPI_LIBS'].split())
|
||||
@ -433,8 +519,32 @@ keyutils = dependency('libkeyutils', required: false,
|
||||
|
||||
has_gettid = cc.has_function('gettid')
|
||||
|
||||
# Malloc tests
|
||||
|
||||
malloc = []
|
||||
if get_option('malloc') == 'system'
|
||||
has_malloc_trim = \
|
||||
not get_option('malloc_trim').disabled() and \
|
||||
cc.links('''#include <malloc.h>
|
||||
int main(void) { malloc_trim(0); return 0; }''')
|
||||
else
|
||||
has_malloc_trim = false
|
||||
malloc = cc.find_library(get_option('malloc'), required: true)
|
||||
endif
|
||||
if not has_malloc_trim and get_option('malloc_trim').enabled()
|
||||
if get_option('malloc') == 'system'
|
||||
error('malloc_trim not available on this platform.')
|
||||
else
|
||||
error('malloc_trim not available with non-libc memory allocator')
|
||||
endif
|
||||
endif
|
||||
|
||||
# Create config-host.h
|
||||
|
||||
config_host_data.set('CONFIG_COCOA', cocoa.found())
|
||||
config_host_data.set('CONFIG_LIBUDEV', libudev.found())
|
||||
config_host_data.set('CONFIG_MPATH', mpathpersist.found())
|
||||
config_host_data.set('CONFIG_MPATH_NEW_API', mpathpersist_new_api)
|
||||
config_host_data.set('CONFIG_SDL', sdl.found())
|
||||
config_host_data.set('CONFIG_SDL_IMAGE', sdl_image.found())
|
||||
config_host_data.set('CONFIG_VNC', vnc.found())
|
||||
@ -444,15 +554,16 @@ config_host_data.set('CONFIG_VNC_SASL', sasl.found())
|
||||
config_host_data.set('CONFIG_XKBCOMMON', xkbcommon.found())
|
||||
config_host_data.set('CONFIG_KEYUTILS', keyutils.found())
|
||||
config_host_data.set('CONFIG_GETTID', has_gettid)
|
||||
config_host_data.set('CONFIG_MALLOC_TRIM', has_malloc_trim)
|
||||
config_host_data.set('QEMU_VERSION', '"@0@"'.format(meson.project_version()))
|
||||
config_host_data.set('QEMU_VERSION_MAJOR', meson.project_version().split('.')[0])
|
||||
config_host_data.set('QEMU_VERSION_MINOR', meson.project_version().split('.')[1])
|
||||
config_host_data.set('QEMU_VERSION_MICRO', meson.project_version().split('.')[2])
|
||||
|
||||
arrays = ['CONFIG_AUDIO_DRIVERS', 'CONFIG_BDRV_RW_WHITELIST', 'CONFIG_BDRV_RO_WHITELIST']
|
||||
strings = ['HOST_DSOSUF', 'CONFIG_IASL', 'qemu_confdir', 'qemu_datadir',
|
||||
strings = ['HOST_DSOSUF', 'CONFIG_IASL', 'bindir', 'prefix', 'qemu_confdir', 'qemu_datadir',
|
||||
'qemu_moddir', 'qemu_localstatedir', 'qemu_helperdir', 'qemu_localedir',
|
||||
'qemu_icondir', 'qemu_desktopdir', 'qemu_firmwarepath']
|
||||
'qemu_icondir', 'qemu_desktopdir', 'qemu_firmwarepath', 'sysconfdir']
|
||||
foreach k, v: config_host
|
||||
if arrays.contains(k)
|
||||
if v != ''
|
||||
@ -473,6 +584,7 @@ endforeach
|
||||
genh += configure_file(output: 'config-host.h', configuration: config_host_data)
|
||||
|
||||
minikconf = find_program('scripts/minikconf.py')
|
||||
config_all = {}
|
||||
config_all_devices = {}
|
||||
config_all_disas = {}
|
||||
config_devices_mak_list = []
|
||||
@ -529,6 +641,14 @@ kconfig_external_symbols = [
|
||||
]
|
||||
ignored = ['TARGET_XML_FILES', 'TARGET_ABI_DIR', 'TARGET_DIRS']
|
||||
|
||||
accel_symbols = [
|
||||
'CONFIG_KVM',
|
||||
'CONFIG_HAX',
|
||||
'CONFIG_HVF',
|
||||
'CONFIG_TCG',
|
||||
'CONFIG_WHPX'
|
||||
]
|
||||
|
||||
foreach target : target_dirs
|
||||
config_target = keyval.load(meson.current_build_dir() / target / 'config-target.mak')
|
||||
|
||||
@ -557,6 +677,11 @@ foreach target : target_dirs
|
||||
config_target_data.set(k, v)
|
||||
endif
|
||||
endforeach
|
||||
foreach sym: accel_symbols
|
||||
if config_target.has_key(sym)
|
||||
config_all += { sym: 'y' }
|
||||
endif
|
||||
endforeach
|
||||
config_target_h += {target: configure_file(output: target + '-config-target.h',
|
||||
configuration: config_target_data)}
|
||||
|
||||
@ -601,7 +726,7 @@ endforeach
|
||||
# targets that are not built for this compilation. The CONFIG_ALL
|
||||
# pseudo symbol replaces it.
|
||||
|
||||
config_all = config_all_devices
|
||||
config_all += config_all_devices
|
||||
config_all += config_host
|
||||
config_all += config_all_disas
|
||||
config_all += {
|
||||
@ -827,7 +952,7 @@ util_ss.add_all(trace_ss)
|
||||
util_ss = util_ss.apply(config_all, strict: false)
|
||||
libqemuutil = static_library('qemuutil',
|
||||
sources: util_ss.sources() + stub_ss.sources() + genh,
|
||||
dependencies: [util_ss.dependencies(), m, glib, socket])
|
||||
dependencies: [util_ss.dependencies(), m, glib, socket, malloc])
|
||||
qemuutil = declare_dependency(link_with: libqemuutil,
|
||||
sources: genh + version_res)
|
||||
|
||||
@ -993,7 +1118,7 @@ common_all = static_library('common',
|
||||
|
||||
feature_to_c = find_program('scripts/feature_to_c.sh')
|
||||
|
||||
emulators = []
|
||||
emulators = {}
|
||||
foreach target : target_dirs
|
||||
config_target = config_target_mak[target]
|
||||
target_name = config_target['TARGET_NAME']
|
||||
@ -1112,7 +1237,8 @@ foreach target : target_dirs
|
||||
}]
|
||||
endif
|
||||
foreach exe: execs
|
||||
emulators += executable(exe['name'], exe['sources'],
|
||||
emulators += {exe['name']:
|
||||
executable(exe['name'], exe['sources'],
|
||||
install: true,
|
||||
c_args: c_args,
|
||||
dependencies: arch_deps + deps + exe['dependencies'],
|
||||
@ -1121,6 +1247,7 @@ foreach target : target_dirs
|
||||
link_depends: [block_syms, qemu_syms] + exe.get('link_depends', []),
|
||||
link_args: link_args,
|
||||
gui_app: exe['gui'])
|
||||
}
|
||||
|
||||
if 'CONFIG_TRACE_SYSTEMTAP' in config_host
|
||||
foreach stp: [
|
||||
@ -1166,7 +1293,6 @@ if xkbcommon.found()
|
||||
dependencies: [qemuutil, xkbcommon], install: have_tools)
|
||||
endif
|
||||
|
||||
qemu_block_tools = []
|
||||
if have_tools
|
||||
qemu_img = executable('qemu-img', [files('qemu-img.c'), hxdep],
|
||||
dependencies: [authz, block, crypto, io, qom, qemuutil], install: true)
|
||||
@ -1199,7 +1325,7 @@ if have_tools
|
||||
|
||||
executable('qemu-pr-helper', files('scsi/qemu-pr-helper.c', 'scsi/utils.c'),
|
||||
dependencies: [authz, crypto, io, qom, qemuutil,
|
||||
libcap_ng, libudev, libmpathpersist],
|
||||
libcap_ng, mpathpersist],
|
||||
install: true)
|
||||
endif
|
||||
|
||||
@ -1336,7 +1462,7 @@ summary_info += {'Audio drivers': config_host['CONFIG_AUDIO_DRIVERS']}
|
||||
summary_info += {'Block whitelist (rw)': config_host['CONFIG_BDRV_RW_WHITELIST']}
|
||||
summary_info += {'Block whitelist (ro)': config_host['CONFIG_BDRV_RO_WHITELIST']}
|
||||
summary_info += {'VirtFS support': config_host.has_key('CONFIG_VIRTFS')}
|
||||
summary_info += {'Multipath support': config_host.has_key('CONFIG_MPATH')}
|
||||
summary_info += {'Multipath support': mpathpersist.found()}
|
||||
summary_info += {'VNC support': vnc.found()}
|
||||
if vnc.found()
|
||||
summary_info += {'VNC SASL support': sasl.found()}
|
||||
@ -1356,17 +1482,16 @@ summary_info += {'Linux AIO support': config_host.has_key('CONFIG_LINUX_AIO')}
|
||||
summary_info += {'Linux io_uring support': config_host.has_key('CONFIG_LINUX_IO_URING')}
|
||||
summary_info += {'ATTR/XATTR support': config_host.has_key('CONFIG_ATTR')}
|
||||
summary_info += {'Install blobs': config_host.has_key('INSTALL_BLOBS')}
|
||||
# TODO: add back KVM/HAX/HVF/WHPX/TCG
|
||||
#summary_info += {'KVM support': have_kvm'}
|
||||
#summary_info += {'HAX support': have_hax'}
|
||||
#summary_info += {'HVF support': have_hvf'}
|
||||
#summary_info += {'WHPX support': have_whpx'}
|
||||
#summary_info += {'TCG support': have_tcg'}
|
||||
#if get_option('tcg')
|
||||
# summary_info += {'TCG debug enabled': config_host.has_key('CONFIG_DEBUG_TCG')}
|
||||
# summary_info += {'TCG interpreter': config_host.has_key('CONFIG_TCG_INTERPRETER')}
|
||||
#endif
|
||||
summary_info += {'malloc trim support': config_host.has_key('CONFIG_MALLOC_TRIM')}
|
||||
summary_info += {'KVM support': config_all.has_key('CONFIG_KVM')}
|
||||
summary_info += {'HAX support': config_all.has_key('CONFIG_HAX')}
|
||||
summary_info += {'HVF support': config_all.has_key('CONFIG_HVF')}
|
||||
summary_info += {'WHPX support': config_all.has_key('CONFIG_WHPX')}
|
||||
summary_info += {'TCG support': config_all.has_key('CONFIG_TCG')}
|
||||
if config_all.has_key('CONFIG_TCG')
|
||||
summary_info += {'TCG debug enabled': config_host.has_key('CONFIG_DEBUG_TCG')}
|
||||
summary_info += {'TCG interpreter': config_host.has_key('CONFIG_TCG_INTERPRETER')}
|
||||
endif
|
||||
summary_info += {'malloc trim support': has_malloc_trim}
|
||||
summary_info += {'RDMA support': config_host.has_key('CONFIG_RDMA')}
|
||||
summary_info += {'PVRDMA support': config_host.has_key('CONFIG_PVRDMA')}
|
||||
summary_info += {'fdt support': config_host.has_key('CONFIG_FDT')}
|
||||
@ -1407,7 +1532,7 @@ if targetos == 'windows'
|
||||
endif
|
||||
summary_info += {'QGA VSS support': config_host.has_key('CONFIG_QGA_VSS')}
|
||||
summary_info += {'QGA w32 disk info': config_host.has_key('CONFIG_QGA_NTDDSCSI')}
|
||||
summary_info += {'QGA MSI support': config_host.has_key('CONFIG_QGA_MSI_ENABLED')}
|
||||
summary_info += {'QGA MSI support': config_host.has_key('CONFIG_QGA_MSI')}
|
||||
endif
|
||||
summary_info += {'seccomp support': config_host.has_key('CONFIG_SECCOMP')}
|
||||
summary_info += {'coroutine backend': config_host['CONFIG_COROUTINE_BACKEND']}
|
||||
@ -1428,8 +1553,7 @@ summary_info += {'lzfse support': config_host.has_key('CONFIG_LZFSE')}
|
||||
summary_info += {'zstd support': config_host.has_key('CONFIG_ZSTD')}
|
||||
summary_info += {'NUMA host support': config_host.has_key('CONFIG_NUMA')}
|
||||
summary_info += {'libxml2': config_host.has_key('CONFIG_LIBXML2')}
|
||||
summary_info += {'tcmalloc support': config_host.has_key('CONFIG_TCMALLOC')}
|
||||
summary_info += {'jemalloc support': config_host.has_key('CONFIG_JEMALLOC')}
|
||||
summary_info += {'memory allocator': get_option('malloc')}
|
||||
summary_info += {'avx2 optimization': config_host.has_key('CONFIG_AVX2_OPT')}
|
||||
summary_info += {'avx512f optimization': config_host.has_key('CONFIG_AVX512F_OPT')}
|
||||
summary_info += {'replication support': config_host.has_key('CONFIG_REPLICATION')}
|
||||
@ -1445,7 +1569,7 @@ summary_info += {'sheepdog support': config_host.has_key('CONFIG_SHEEPDOG')}
|
||||
summary_info += {'capstone': config_host.has_key('CONFIG_CAPSTONE')}
|
||||
summary_info += {'libpmem support': config_host.has_key('CONFIG_LIBPMEM')}
|
||||
summary_info += {'libdaxctl support': config_host.has_key('CONFIG_LIBDAXCTL')}
|
||||
summary_info += {'libudev': config_host.has_key('CONFIG_LIBUDEV')}
|
||||
summary_info += {'libudev': libudev.found()}
|
||||
summary_info += {'default devices': config_host['CONFIG_MINIKCONF_MODE'] == '--defconfig'}
|
||||
summary_info += {'plugin support': config_host.has_key('CONFIG_PLUGIN')}
|
||||
summary_info += {'fuzzing support': config_host.has_key('CONFIG_FUZZ')}
|
||||
|
@ -6,6 +6,15 @@ option('docdir', type : 'string', value : 'doc',
|
||||
option('gettext', type : 'boolean', value : true,
|
||||
description: 'Localization of the GTK+ user interface')
|
||||
|
||||
option('malloc_trim', type : 'feature', value : 'auto',
|
||||
description: 'enable libc malloc_trim() for memory optimization')
|
||||
option('malloc', type : 'combo', choices : ['system', 'tcmalloc', 'jemalloc'],
|
||||
value: 'system', description: 'choose memory allocator to use')
|
||||
|
||||
option('cocoa', type : 'feature', value : 'auto',
|
||||
description: 'Cocoa user interface (macOS only)')
|
||||
option('mpath', type : 'feature', value : 'auto',
|
||||
description: 'Multipath persistent reservation passthrough')
|
||||
option('sdl', type : 'feature', value : 'auto',
|
||||
description: 'SDL user interface')
|
||||
option('sdl_image', type : 'feature', value : 'auto',
|
||||
|
@ -33,6 +33,42 @@
|
||||
#include "net/can_emu.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
|
||||
/* CAN DLC to real data length conversion helpers */
|
||||
|
||||
static const uint8_t dlc2len[] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
8, 12, 16, 20, 24, 32, 48, 64
|
||||
};
|
||||
|
||||
/* get data length from can_dlc with sanitized can_dlc */
|
||||
uint8_t can_dlc2len(uint8_t can_dlc)
|
||||
{
|
||||
return dlc2len[can_dlc & 0x0F];
|
||||
}
|
||||
|
||||
static const uint8_t len2dlc[] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, /* 0 - 8 */
|
||||
9, 9, 9, 9, /* 9 - 12 */
|
||||
10, 10, 10, 10, /* 13 - 16 */
|
||||
11, 11, 11, 11, /* 17 - 20 */
|
||||
12, 12, 12, 12, /* 21 - 24 */
|
||||
13, 13, 13, 13, 13, 13, 13, 13, /* 25 - 32 */
|
||||
14, 14, 14, 14, 14, 14, 14, 14, /* 33 - 40 */
|
||||
14, 14, 14, 14, 14, 14, 14, 14, /* 41 - 48 */
|
||||
15, 15, 15, 15, 15, 15, 15, 15, /* 49 - 56 */
|
||||
15, 15, 15, 15, 15, 15, 15, 15 /* 57 - 64 */
|
||||
};
|
||||
|
||||
/* map the sanitized data length to an appropriate data length code */
|
||||
uint8_t can_len2dlc(uint8_t len)
|
||||
{
|
||||
if (unlikely(len > 64)) {
|
||||
return 0xF;
|
||||
}
|
||||
|
||||
return len2dlc[len];
|
||||
}
|
||||
|
||||
struct CanBusState {
|
||||
Object object;
|
||||
|
||||
|
@ -103,6 +103,14 @@ static void can_host_socketcan_read(void *opaque)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ch->bus_client.fd_mode) {
|
||||
c->buf[0].flags = 0;
|
||||
} else {
|
||||
if (c->bufcnt > CAN_MTU) {
|
||||
c->buf[0].flags |= QEMU_CAN_FRMF_TYPE_FD;
|
||||
}
|
||||
}
|
||||
|
||||
can_bus_client_send(&ch->bus_client, c->buf, 1);
|
||||
|
||||
if (DEBUG_CAN) {
|
||||
@ -121,12 +129,21 @@ static ssize_t can_host_socketcan_receive(CanBusClientState *client,
|
||||
CanHostState *ch = container_of(client, CanHostState, bus_client);
|
||||
CanHostSocketCAN *c = CAN_HOST_SOCKETCAN(ch);
|
||||
|
||||
size_t len = sizeof(qemu_can_frame);
|
||||
size_t len;
|
||||
int res;
|
||||
|
||||
if (c->fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (frames->flags & QEMU_CAN_FRMF_TYPE_FD) {
|
||||
if (!ch->bus_client.fd_mode) {
|
||||
return 0;
|
||||
}
|
||||
len = CANFD_MTU;
|
||||
} else {
|
||||
len = CAN_MTU;
|
||||
|
||||
}
|
||||
|
||||
res = write(c->fd, frames, len);
|
||||
|
||||
@ -172,6 +189,8 @@ static void can_host_socketcan_connect(CanHostState *ch, Error **errp)
|
||||
{
|
||||
CanHostSocketCAN *c = CAN_HOST_SOCKETCAN(ch);
|
||||
int s; /* can raw socket */
|
||||
int mtu;
|
||||
int enable_canfd = 1;
|
||||
struct sockaddr_can addr;
|
||||
struct ifreq ifr;
|
||||
|
||||
@ -185,13 +204,34 @@ static void can_host_socketcan_connect(CanHostState *ch, Error **errp)
|
||||
addr.can_family = AF_CAN;
|
||||
memset(&ifr.ifr_name, 0, sizeof(ifr.ifr_name));
|
||||
strcpy(ifr.ifr_name, c->ifname);
|
||||
/* check if the frame fits into the CAN netdevice */
|
||||
if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
|
||||
error_setg_errno(errp, errno,
|
||||
"SocketCAN host interface %s not available", c->ifname);
|
||||
"SocketCAN host interface %s not available",
|
||||
c->ifname);
|
||||
goto fail;
|
||||
}
|
||||
addr.can_ifindex = ifr.ifr_ifindex;
|
||||
|
||||
if (ioctl(s, SIOCGIFMTU, &ifr) < 0) {
|
||||
error_setg_errno(errp, errno,
|
||||
"SocketCAN host interface %s SIOCGIFMTU failed",
|
||||
c->ifname);
|
||||
goto fail;
|
||||
}
|
||||
mtu = ifr.ifr_mtu;
|
||||
|
||||
if (mtu >= CANFD_MTU) {
|
||||
/* interface is ok - try to switch the socket into CAN FD mode */
|
||||
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES,
|
||||
&enable_canfd, sizeof(enable_canfd))) {
|
||||
warn_report("SocketCAN host interface %s enabling CAN FD failed",
|
||||
c->ifname);
|
||||
} else {
|
||||
c->parent.bus_client.fd_mode = true;
|
||||
}
|
||||
}
|
||||
|
||||
c->err_mask = 0xffffffff; /* Receive error frame. */
|
||||
setsockopt(s, SOL_CAN_RAW, CAN_RAW_ERR_FILTER,
|
||||
&c->err_mask, sizeof(c->err_mask));
|
||||
@ -232,7 +272,8 @@ static char *can_host_socketcan_get_if(Object *obj, Error **errp)
|
||||
return g_strdup(c->ifname);
|
||||
}
|
||||
|
||||
static void can_host_socketcan_set_if(Object *obj, const char *value, Error **errp)
|
||||
static void can_host_socketcan_set_if(Object *obj, const char *value,
|
||||
Error **errp)
|
||||
{
|
||||
CanHostSocketCAN *c = CAN_HOST_SOCKETCAN(obj);
|
||||
struct ifreq ifr;
|
||||
|
26
net/tap.c
26
net/tap.c
@ -478,6 +478,7 @@ static int net_bridge_run_helper(const char *helper, const char *bridge,
|
||||
Error **errp)
|
||||
{
|
||||
sigset_t oldmask, mask;
|
||||
g_autofree char *default_helper = NULL;
|
||||
int pid, status;
|
||||
char *args[5];
|
||||
char **parg;
|
||||
@ -487,6 +488,10 @@ static int net_bridge_run_helper(const char *helper, const char *bridge,
|
||||
sigaddset(&mask, SIGCHLD);
|
||||
sigprocmask(SIG_BLOCK, &mask, &oldmask);
|
||||
|
||||
if (!helper) {
|
||||
helper = default_helper = get_relocated_path(DEFAULT_BRIDGE_HELPER);
|
||||
}
|
||||
|
||||
if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) {
|
||||
error_setg_errno(errp, errno, "socketpair() failed");
|
||||
return -1;
|
||||
@ -588,8 +593,7 @@ int net_init_bridge(const Netdev *netdev, const char *name,
|
||||
|
||||
assert(netdev->type == NET_CLIENT_DRIVER_BRIDGE);
|
||||
bridge = &netdev->u.bridge;
|
||||
|
||||
helper = bridge->has_helper ? bridge->helper : DEFAULT_BRIDGE_HELPER;
|
||||
helper = bridge->has_helper ? bridge->helper : NULL;
|
||||
br = bridge->has_br ? bridge->br : DEFAULT_BRIDGE_INTERFACE;
|
||||
|
||||
fd = net_bridge_run_helper(helper, br, errp);
|
||||
@ -773,8 +777,8 @@ int net_init_tap(const Netdev *netdev, const char *name,
|
||||
const NetdevTapOptions *tap;
|
||||
int fd, vnet_hdr = 0, i = 0, queues;
|
||||
/* for the no-fd, no-helper case */
|
||||
const char *script = NULL; /* suppress wrong "uninit'd use" gcc warning */
|
||||
const char *downscript = NULL;
|
||||
const char *script;
|
||||
const char *downscript;
|
||||
Error *err = NULL;
|
||||
const char *vhostfdname;
|
||||
char ifname[128];
|
||||
@ -784,6 +788,8 @@ int net_init_tap(const Netdev *netdev, const char *name,
|
||||
tap = &netdev->u.tap;
|
||||
queues = tap->has_queues ? tap->queues : 1;
|
||||
vhostfdname = tap->has_vhostfd ? tap->vhostfd : NULL;
|
||||
script = tap->has_script ? tap->script : NULL;
|
||||
downscript = tap->has_downscript ? tap->downscript : NULL;
|
||||
|
||||
/* QEMU hubs do not support multiqueue tap, in this case peer is set.
|
||||
* For -netdev, peer is always NULL. */
|
||||
@ -934,13 +940,19 @@ free_fail:
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
g_autofree char *default_script = NULL;
|
||||
g_autofree char *default_downscript = NULL;
|
||||
if (tap->has_vhostfds) {
|
||||
error_setg(errp, "vhostfds= is invalid if fds= wasn't specified");
|
||||
return -1;
|
||||
}
|
||||
script = tap->has_script ? tap->script : DEFAULT_NETWORK_SCRIPT;
|
||||
downscript = tap->has_downscript ? tap->downscript :
|
||||
DEFAULT_NETWORK_DOWN_SCRIPT;
|
||||
|
||||
if (!script) {
|
||||
script = default_script = get_relocated_path(DEFAULT_NETWORK_SCRIPT);
|
||||
}
|
||||
if (!downscript) {
|
||||
downscript = default_downscript = get_relocated_path(DEFAULT_NETWORK_SCRIPT);
|
||||
}
|
||||
|
||||
if (tap->has_ifname) {
|
||||
pstrcpy(ifname, sizeof ifname, tap->ifname);
|
||||
|
24
os-posix.c
24
os-posix.c
@ -80,30 +80,6 @@ void os_setup_signal_handling(void)
|
||||
sigaction(SIGTERM, &act, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find a likely location for support files using the location of the binary.
|
||||
* When running from the build tree this will be "$bindir/pc-bios".
|
||||
* Otherwise, this is CONFIG_QEMU_DATADIR.
|
||||
*
|
||||
* The caller must use g_free() to free the returned data when it is
|
||||
* no longer required.
|
||||
*/
|
||||
char *os_find_datadir(void)
|
||||
{
|
||||
g_autofree char *exec_dir = NULL;
|
||||
g_autofree char *dir = NULL;
|
||||
|
||||
exec_dir = qemu_get_exec_dir();
|
||||
g_return_val_if_fail(exec_dir != NULL, NULL);
|
||||
|
||||
dir = g_build_filename(exec_dir, "pc-bios", NULL);
|
||||
if (g_file_test(dir, G_FILE_TEST_IS_DIR)) {
|
||||
return g_steal_pointer(&dir);
|
||||
}
|
||||
|
||||
return g_strdup(CONFIG_QEMU_DATADIR);
|
||||
}
|
||||
|
||||
void os_set_proc_name(const char *s)
|
||||
{
|
||||
#if defined(PR_SET_NAME)
|
||||
|
11
os-win32.c
11
os-win32.c
@ -57,17 +57,6 @@ void os_setup_early_signal_handling(void)
|
||||
atexit(os_undo_timer_resolution);
|
||||
}
|
||||
|
||||
/*
|
||||
* Look for support files in the same directory as the executable.
|
||||
*
|
||||
* The caller must use g_free() to free the returned data when it is
|
||||
* no longer required.
|
||||
*/
|
||||
char *os_find_datadir(void)
|
||||
{
|
||||
return qemu_get_exec_dir();
|
||||
}
|
||||
|
||||
void os_set_line_buffering(void)
|
||||
{
|
||||
setbuf(stdout, NULL);
|
||||
|
@ -47,6 +47,7 @@ foreach km, args: keymaps
|
||||
build_by_default: true,
|
||||
output: km,
|
||||
command: [native_qemu_keymap, '-f', '@OUTPUT@', args.split()],
|
||||
install: true,
|
||||
install_dir: qemu_datadir / 'keymaps')
|
||||
else
|
||||
# copy from source tree
|
||||
@ -55,6 +56,7 @@ foreach km, args: keymaps
|
||||
input: km,
|
||||
output: km,
|
||||
command: ['cp', '@INPUT@', '@OUTPUT@'],
|
||||
install: true,
|
||||
install_dir: qemu_datadir / 'keymaps')
|
||||
endif
|
||||
endforeach
|
||||
|
@ -40,6 +40,7 @@
|
||||
#endif
|
||||
|
||||
#include "qemu/queue.h"
|
||||
#include "qemu/cutils.h"
|
||||
|
||||
#include "net/tap-linux.h"
|
||||
|
||||
@ -245,6 +246,7 @@ int main(int argc, char **argv)
|
||||
ACLList acl_list;
|
||||
int access_allowed, access_denied;
|
||||
int ret = EXIT_SUCCESS;
|
||||
g_autofree char *acl_file = NULL;
|
||||
|
||||
#ifdef CONFIG_LIBCAP_NG
|
||||
/* if we're run from an suid binary, immediately drop privileges preserving
|
||||
@ -257,6 +259,8 @@ int main(int argc, char **argv)
|
||||
}
|
||||
#endif
|
||||
|
||||
qemu_init_exec_dir(argv[0]);
|
||||
|
||||
/* parse arguments */
|
||||
for (index = 1; index < argc; index++) {
|
||||
if (strcmp(argv[index], "--use-vnet") == 0) {
|
||||
@ -282,9 +286,10 @@ int main(int argc, char **argv)
|
||||
|
||||
/* parse default acl file */
|
||||
QSIMPLEQ_INIT(&acl_list);
|
||||
if (parse_acl_file(DEFAULT_ACL_FILE, &acl_list) == -1) {
|
||||
acl_file = get_relocated_path(DEFAULT_ACL_FILE);
|
||||
if (parse_acl_file(acl_file, &acl_list) == -1) {
|
||||
fprintf(stderr, "failed to parse default acl file `%s'\n",
|
||||
DEFAULT_ACL_FILE);
|
||||
acl_file);
|
||||
ret = EXIT_FAILURE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "qapi/error.h"
|
||||
#include "channel.h"
|
||||
#include "qemu/bswap.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qemu/help_option.h"
|
||||
#include "qemu/sockets.h"
|
||||
#include "qemu/systemd.h"
|
||||
@ -968,7 +969,7 @@ static void config_load(GAConfig *config)
|
||||
{
|
||||
GError *gerr = NULL;
|
||||
GKeyFile *keyfile;
|
||||
const char *conf = g_getenv("QGA_CONF") ?: QGA_CONF_DEFAULT;
|
||||
g_autofree char *conf = g_strdup(g_getenv("QGA_CONF")) ?: get_relocated_path(QGA_CONF_DEFAULT);
|
||||
|
||||
/* read system config */
|
||||
keyfile = g_key_file_new();
|
||||
@ -1027,7 +1028,7 @@ end:
|
||||
if (gerr &&
|
||||
!(gerr->domain == G_FILE_ERROR && gerr->code == G_FILE_ERROR_NOENT)) {
|
||||
g_critical("error loading configuration from path: %s, %s",
|
||||
QGA_CONF_DEFAULT, gerr->message);
|
||||
conf, gerr->message);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
g_clear_error(&gerr);
|
||||
@ -1141,7 +1142,7 @@ static void config_parse(GAConfig *config, int argc, char **argv)
|
||||
#ifdef CONFIG_FSFREEZE
|
||||
case 'F':
|
||||
g_free(config->fsfreeze_hook);
|
||||
config->fsfreeze_hook = g_strdup(optarg ?: QGA_FSFREEZE_HOOK_DEFAULT);
|
||||
config->fsfreeze_hook = optarg ? g_strdup(optarg) : get_relocated_path(QGA_FSFREEZE_HOOK_DEFAULT);
|
||||
break;
|
||||
#endif
|
||||
case 't':
|
||||
@ -1463,6 +1464,7 @@ int main(int argc, char **argv)
|
||||
|
||||
config->log_level = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL;
|
||||
|
||||
qemu_init_exec_dir(argv[0]);
|
||||
qga_qmp_init_marshal(&ga_commands);
|
||||
|
||||
init_dfl_pathnames();
|
||||
|
@ -69,6 +69,7 @@ if targetos == 'windows'
|
||||
output: 'qemu-ga-@0@.msi'.format(config_host['ARCH']),
|
||||
depends: deps,
|
||||
command: [
|
||||
find_program('env'),
|
||||
'QEMU_GA_VERSION=' + config_host['QEMU_GA_VERSION'],
|
||||
'QEMU_GA_MANUFACTURER=' + config_host['QEMU_GA_MANUFACTURER'],
|
||||
'QEMU_GA_DISTRO=' + config_host['QEMU_GA_DISTRO'],
|
||||
|
@ -2880,14 +2880,20 @@ sub process {
|
||||
$herecurr);
|
||||
}
|
||||
|
||||
# check for %L{u,d,i} in strings
|
||||
# format strings checks
|
||||
my $string;
|
||||
while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) {
|
||||
$string = substr($rawline, $-[1], $+[1] - $-[1]);
|
||||
$string =~ s/%%/__/g;
|
||||
# check for %L{u,d,i} in strings
|
||||
if ($string =~ /(?<!%)%L[udi]/) {
|
||||
ERROR("\%Ld/%Lu are not-standard C, use %lld/%llu\n" . $herecurr);
|
||||
last;
|
||||
}
|
||||
# check for %# or %0# in printf-style format strings
|
||||
if ($string =~ /(?<!%)%0?#/) {
|
||||
ERROR("Don't use '#' flag of printf format " .
|
||||
"('%#') in format strings, use '0x' " .
|
||||
"prefix instead\n" . $herecurr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3005,7 +3011,7 @@ sub process {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!$is_patch) {
|
||||
if (!$is_patch && $filename !~ /cover-letter\.patch$/) {
|
||||
ERROR("Does not appear to be a unified-diff format patch\n");
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
# Author: Paolo Bonzini <pbonzini@redhat.com>
|
||||
|
||||
from collections import defaultdict
|
||||
import itertools
|
||||
import json
|
||||
import os
|
||||
import shlex
|
||||
@ -36,7 +37,7 @@ SPEED = quick
|
||||
introspect = json.load(sys.stdin)
|
||||
i = 0
|
||||
|
||||
def process_tests(test, suites):
|
||||
def process_tests(test, targets, suites):
|
||||
global i
|
||||
env = ' '.join(('%s=%s' % (shlex.quote(k), shlex.quote(v))
|
||||
for k, v in test['env'].items()))
|
||||
@ -58,12 +59,19 @@ def process_tests(test, suites):
|
||||
i += 1
|
||||
if test['workdir'] is not None:
|
||||
print('.test.dir.%d := %s' % (i, shlex.quote(test['workdir'])))
|
||||
|
||||
if 'depends' in test:
|
||||
deps = (targets.get(x, []) for x in test['depends'])
|
||||
deps = itertools.chain.from_iterable(deps)
|
||||
else:
|
||||
deps = ['all']
|
||||
|
||||
print('.test.name.%d := %s' % (i, test['name']))
|
||||
print('.test.driver.%d := %s' % (i, driver))
|
||||
print('.test.env.%d := $(.test.env) %s' % (i, env))
|
||||
print('.test.cmd.%d := %s' % (i, cmd))
|
||||
print('.PHONY: run-test-%d' % (i,))
|
||||
print('run-test-%d: all' % (i,))
|
||||
print('run-test-%d: %s' % (i, ' '.join(deps)))
|
||||
print('\t@$(call .test.run,%d,$(.test.output-format))' % (i,))
|
||||
|
||||
test_suites = test['suite'] or ['default']
|
||||
@ -102,16 +110,19 @@ def emit_suite(name, suite, prefix):
|
||||
print('.tests += $(.test.$(SPEED).%s)' % (target, ))
|
||||
print('endif')
|
||||
|
||||
targets = {t['id']: [os.path.relpath(f) for f in t['filename']]
|
||||
for t in introspect['targets']}
|
||||
|
||||
testsuites = defaultdict(Suite)
|
||||
for test in introspect['tests']:
|
||||
process_tests(test, testsuites)
|
||||
process_tests(test, targets, testsuites)
|
||||
emit_prolog(testsuites, 'check')
|
||||
for name, suite in testsuites.items():
|
||||
emit_suite(name, suite, 'check')
|
||||
|
||||
benchsuites = defaultdict(Suite)
|
||||
for test in introspect['benchmarks']:
|
||||
process_tests(test, benchsuites)
|
||||
process_tests(test, targets, benchsuites)
|
||||
emit_prolog(benchsuites, 'bench')
|
||||
for name, suite in benchsuites.items():
|
||||
emit_suite(name, suite, 'bench')
|
||||
|
@ -908,6 +908,9 @@ class Ninja2Make(NinjaParserEventsWithVars):
|
||||
else:
|
||||
stamp = '%s@%s.stamp' % (rule, sha1_text(targets)[0:11])
|
||||
self.print('%s: %s; @:' % (targets, stamp))
|
||||
self.print('ifneq (%s, $(wildcard %s))' % (targets, targets))
|
||||
self.print('.PHONY: %s' % (stamp, ))
|
||||
self.print('endif')
|
||||
self.print('%s: %s | %s; ${ninja-command-restat}' % (stamp, inputs, orderonly))
|
||||
self.rule_targets[rule].append(stamp)
|
||||
self.stamp_targets[rule].append(stamp)
|
||||
|
@ -1221,7 +1221,6 @@ static void memory_region_initfn(Object *obj)
|
||||
mr->ops = &unassigned_mem_ops;
|
||||
mr->enabled = true;
|
||||
mr->romd_mode = true;
|
||||
mr->global_locking = true;
|
||||
mr->destructor = memory_region_destructor_none;
|
||||
QTAILQ_INIT(&mr->subregions);
|
||||
QTAILQ_INIT(&mr->coalesced);
|
||||
@ -2277,11 +2276,6 @@ void memory_region_clear_flush_coalesced(MemoryRegion *mr)
|
||||
}
|
||||
}
|
||||
|
||||
void memory_region_clear_global_locking(MemoryRegion *mr)
|
||||
{
|
||||
mr->global_locking = false;
|
||||
}
|
||||
|
||||
static bool userspace_eventfd_warning;
|
||||
|
||||
void memory_region_add_eventfd(MemoryRegion *mr,
|
||||
|
43
softmmu/vl.c
43
softmmu/vl.c
@ -2005,7 +2005,7 @@ char *qemu_find_file(int type, const char *name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void qemu_add_data_dir(const char *path)
|
||||
void qemu_add_data_dir(char *path)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -2017,10 +2017,11 @@ void qemu_add_data_dir(const char *path)
|
||||
}
|
||||
for (i = 0; i < data_dir_idx; i++) {
|
||||
if (strcmp(data_dir[i], path) == 0) {
|
||||
return; /* duplicate */
|
||||
g_free(path); /* duplicate */
|
||||
return;
|
||||
}
|
||||
}
|
||||
data_dir[data_dir_idx++] = g_strdup(path);
|
||||
data_dir[data_dir_idx++] = path;
|
||||
}
|
||||
|
||||
static inline bool nonempty_str(const char *str)
|
||||
@ -2675,8 +2676,9 @@ static int global_init_func(void *opaque, QemuOpts *opts, Error **errp)
|
||||
static int qemu_read_default_config_file(void)
|
||||
{
|
||||
int ret;
|
||||
g_autofree char *file = get_relocated_path(CONFIG_QEMU_CONFDIR "/qemu.conf");
|
||||
|
||||
ret = qemu_read_config_file(CONFIG_QEMU_CONFDIR "/qemu.conf");
|
||||
ret = qemu_read_config_file(file);
|
||||
if (ret < 0 && ret != -ENOENT) {
|
||||
return ret;
|
||||
}
|
||||
@ -2829,6 +2831,26 @@ static void create_default_memdev(MachineState *ms, const char *path)
|
||||
&error_fatal);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find a likely location for support files using the location of the binary.
|
||||
* When running from the build tree this will be "$bindir/pc-bios".
|
||||
* Otherwise, this is CONFIG_QEMU_DATADIR (possibly relocated).
|
||||
*
|
||||
* The caller must use g_free() to free the returned data when it is
|
||||
* no longer required.
|
||||
*/
|
||||
static char *find_datadir(void)
|
||||
{
|
||||
g_autofree char *dir = NULL;
|
||||
|
||||
dir = g_build_filename(qemu_get_exec_dir(), "pc-bios", NULL);
|
||||
if (g_file_test(dir, G_FILE_TEST_IS_DIR)) {
|
||||
return g_steal_pointer(&dir);
|
||||
}
|
||||
|
||||
return get_relocated_path(CONFIG_QEMU_DATADIR);
|
||||
}
|
||||
|
||||
void qemu_init(int argc, char **argv, char **envp)
|
||||
{
|
||||
int i;
|
||||
@ -2862,7 +2884,7 @@ void qemu_init(int argc, char **argv, char **envp)
|
||||
Error *main_loop_err = NULL;
|
||||
Error *err = NULL;
|
||||
bool list_data_dirs = false;
|
||||
char *dir, **dirs;
|
||||
char **dirs;
|
||||
const char *mem_path = NULL;
|
||||
bool have_custom_ram_size;
|
||||
BlockdevOptionsQueue bdo_queue = QSIMPLEQ_HEAD_INITIALIZER(bdo_queue);
|
||||
@ -3195,7 +3217,7 @@ void qemu_init(int argc, char **argv, char **envp)
|
||||
if (is_help_option(optarg)) {
|
||||
list_data_dirs = true;
|
||||
} else {
|
||||
qemu_add_data_dir(optarg);
|
||||
qemu_add_data_dir(g_strdup(optarg));
|
||||
}
|
||||
break;
|
||||
case QEMU_OPTION_bios:
|
||||
@ -3927,17 +3949,12 @@ void qemu_init(int argc, char **argv, char **envp)
|
||||
/* add configured firmware directories */
|
||||
dirs = g_strsplit(CONFIG_QEMU_FIRMWAREPATH, G_SEARCHPATH_SEPARATOR_S, 0);
|
||||
for (i = 0; dirs[i] != NULL; i++) {
|
||||
qemu_add_data_dir(dirs[i]);
|
||||
qemu_add_data_dir(get_relocated_path(dirs[i]));
|
||||
}
|
||||
g_strfreev(dirs);
|
||||
|
||||
/* try to find datadir relative to the executable path */
|
||||
dir = os_find_datadir();
|
||||
qemu_add_data_dir(dir);
|
||||
g_free(dir);
|
||||
|
||||
/* add the datadir specified when building */
|
||||
qemu_add_data_dir(CONFIG_QEMU_DATADIR);
|
||||
qemu_add_data_dir(find_datadir());
|
||||
|
||||
/* -L help lists the data directories and exits. */
|
||||
if (list_data_dirs) {
|
||||
|
@ -46,4 +46,5 @@ stub_ss.add(files('vm-stop.c'))
|
||||
stub_ss.add(files('win32-kbd-hook.c'))
|
||||
if have_system
|
||||
stub_ss.add(files('semihost.c'))
|
||||
stub_ss.add(files('xen-hw-stub.c'))
|
||||
endif
|
||||
|
50
stubs/xen-hw-stub.c
Normal file
50
stubs/xen-hw-stub.c
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Citrix Systems UK Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/xen/xen.h"
|
||||
#include "hw/xen/xen-x86.h"
|
||||
|
||||
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_pc(PCMachineState *pcms, MemoryRegion **ram_memory)
|
||||
{
|
||||
}
|
@ -799,7 +799,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
|
||||
"kvmclock", "kvm-nopiodelay", "kvm-mmu", "kvmclock",
|
||||
"kvm-asyncpf", "kvm-steal-time", "kvm-pv-eoi", "kvm-pv-unhalt",
|
||||
NULL, "kvm-pv-tlb-flush", NULL, "kvm-pv-ipi",
|
||||
"kvm-poll-control", "kvm-pv-sched-yield", NULL, NULL,
|
||||
"kvm-poll-control", "kvm-pv-sched-yield", "kvm-asyncpf-int", NULL,
|
||||
NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL,
|
||||
"kvmclock-stable-bit", NULL, NULL, NULL,
|
||||
@ -6267,6 +6267,8 @@ static void x86_cpu_enable_xsave_components(X86CPU *cpu)
|
||||
uint64_t mask;
|
||||
|
||||
if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) {
|
||||
env->features[FEAT_XSAVE_COMP_LO] = 0;
|
||||
env->features[FEAT_XSAVE_COMP_HI] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -6988,6 +6990,7 @@ static void x86_cpu_initfn(Object *obj)
|
||||
object_property_add_alias(obj, "kvm_nopiodelay", obj, "kvm-nopiodelay");
|
||||
object_property_add_alias(obj, "kvm_mmu", obj, "kvm-mmu");
|
||||
object_property_add_alias(obj, "kvm_asyncpf", obj, "kvm-asyncpf");
|
||||
object_property_add_alias(obj, "kvm_asyncpf_int", obj, "kvm-asyncpf-int");
|
||||
object_property_add_alias(obj, "kvm_steal_time", obj, "kvm-steal-time");
|
||||
object_property_add_alias(obj, "kvm_pv_eoi", obj, "kvm-pv-eoi");
|
||||
object_property_add_alias(obj, "kvm_pv_unhalt", obj, "kvm-pv-unhalt");
|
||||
|
@ -1492,6 +1492,7 @@ typedef struct CPUX86State {
|
||||
uint64_t wall_clock_msr;
|
||||
uint64_t steal_time_msr;
|
||||
uint64_t async_pf_en_msr;
|
||||
uint64_t async_pf_int_msr;
|
||||
uint64_t pv_eoi_en_msr;
|
||||
uint64_t poll_control_msr;
|
||||
|
||||
|
@ -143,6 +143,11 @@ bool kvm_has_adjust_clock_stable(void)
|
||||
return (ret == KVM_CLOCK_TSC_STABLE);
|
||||
}
|
||||
|
||||
bool kvm_has_adjust_clock(void)
|
||||
{
|
||||
return kvm_check_extension(kvm_state, KVM_CAP_ADJUST_CLOCK);
|
||||
}
|
||||
|
||||
bool kvm_has_exception_payload(void)
|
||||
{
|
||||
return has_exception_payload;
|
||||
@ -279,29 +284,6 @@ static struct kvm_cpuid2 *get_supported_cpuid(KVMState *s)
|
||||
return cpuid;
|
||||
}
|
||||
|
||||
static const struct kvm_para_features {
|
||||
int cap;
|
||||
int feature;
|
||||
} para_features[] = {
|
||||
{ KVM_CAP_CLOCKSOURCE, KVM_FEATURE_CLOCKSOURCE },
|
||||
{ KVM_CAP_NOP_IO_DELAY, KVM_FEATURE_NOP_IO_DELAY },
|
||||
{ KVM_CAP_PV_MMU, KVM_FEATURE_MMU_OP },
|
||||
{ KVM_CAP_ASYNC_PF, KVM_FEATURE_ASYNC_PF },
|
||||
};
|
||||
|
||||
static int get_para_features(KVMState *s)
|
||||
{
|
||||
int i, features = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(para_features); i++) {
|
||||
if (kvm_check_extension(s, para_features[i].cap)) {
|
||||
features |= (1 << para_features[i].feature);
|
||||
}
|
||||
}
|
||||
|
||||
return features;
|
||||
}
|
||||
|
||||
static bool host_tsx_broken(void)
|
||||
{
|
||||
int family, model, stepping;\
|
||||
@ -361,13 +343,11 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function,
|
||||
struct kvm_cpuid2 *cpuid;
|
||||
uint32_t ret = 0;
|
||||
uint32_t cpuid_1_edx;
|
||||
bool found = false;
|
||||
|
||||
cpuid = get_supported_cpuid(s);
|
||||
|
||||
struct kvm_cpuid_entry2 *entry = cpuid_find_entry(cpuid, function, index);
|
||||
if (entry) {
|
||||
found = true;
|
||||
ret = cpuid_entry_get_reg(entry, reg);
|
||||
}
|
||||
|
||||
@ -442,12 +422,6 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function,
|
||||
}
|
||||
} else if (function == KVM_CPUID_FEATURES && reg == R_EDX) {
|
||||
ret |= 1U << KVM_HINTS_REALTIME;
|
||||
found = 1;
|
||||
}
|
||||
|
||||
/* fallback for older kernels */
|
||||
if ((function == KVM_CPUID_FEATURES) && !found) {
|
||||
ret = get_para_features(s);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -2818,6 +2792,9 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
|
||||
kvm_msr_entry_add(cpu, MSR_IA32_TSC, env->tsc);
|
||||
kvm_msr_entry_add(cpu, MSR_KVM_SYSTEM_TIME, env->system_time_msr);
|
||||
kvm_msr_entry_add(cpu, MSR_KVM_WALL_CLOCK, env->wall_clock_msr);
|
||||
if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_ASYNC_PF_INT)) {
|
||||
kvm_msr_entry_add(cpu, MSR_KVM_ASYNC_PF_INT, env->async_pf_int_msr);
|
||||
}
|
||||
if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_ASYNC_PF)) {
|
||||
kvm_msr_entry_add(cpu, MSR_KVM_ASYNC_PF_EN, env->async_pf_en_msr);
|
||||
}
|
||||
@ -3203,6 +3180,9 @@ static int kvm_get_msrs(X86CPU *cpu)
|
||||
#endif
|
||||
kvm_msr_entry_add(cpu, MSR_KVM_SYSTEM_TIME, 0);
|
||||
kvm_msr_entry_add(cpu, MSR_KVM_WALL_CLOCK, 0);
|
||||
if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_ASYNC_PF_INT)) {
|
||||
kvm_msr_entry_add(cpu, MSR_KVM_ASYNC_PF_INT, 0);
|
||||
}
|
||||
if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_ASYNC_PF)) {
|
||||
kvm_msr_entry_add(cpu, MSR_KVM_ASYNC_PF_EN, 0);
|
||||
}
|
||||
@ -3446,6 +3426,9 @@ static int kvm_get_msrs(X86CPU *cpu)
|
||||
case MSR_KVM_ASYNC_PF_EN:
|
||||
env->async_pf_en_msr = msrs[i].data;
|
||||
break;
|
||||
case MSR_KVM_ASYNC_PF_INT:
|
||||
env->async_pf_int_msr = msrs[i].data;
|
||||
break;
|
||||
case MSR_KVM_PV_EOI_EN:
|
||||
env->pv_eoi_en_msr = msrs[i].data;
|
||||
break;
|
||||
|
@ -34,6 +34,7 @@
|
||||
|
||||
bool kvm_allows_irq0_override(void);
|
||||
bool kvm_has_smm(void);
|
||||
bool kvm_has_adjust_clock(void);
|
||||
bool kvm_has_adjust_clock_stable(void);
|
||||
bool kvm_has_exception_payload(void);
|
||||
void kvm_synchronize_all_tsc(void);
|
||||
|
@ -394,6 +394,13 @@ static bool async_pf_msr_needed(void *opaque)
|
||||
return cpu->env.async_pf_en_msr != 0;
|
||||
}
|
||||
|
||||
static bool async_pf_int_msr_needed(void *opaque)
|
||||
{
|
||||
X86CPU *cpu = opaque;
|
||||
|
||||
return cpu->env.async_pf_int_msr != 0;
|
||||
}
|
||||
|
||||
static bool pv_eoi_msr_needed(void *opaque)
|
||||
{
|
||||
X86CPU *cpu = opaque;
|
||||
@ -467,6 +474,17 @@ static const VMStateDescription vmstate_async_pf_msr = {
|
||||
}
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_async_pf_int_msr = {
|
||||
.name = "cpu/async_pf_int_msr",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.needed = async_pf_int_msr_needed,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT64(env.async_pf_int_msr, X86CPU),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_pv_eoi_msr = {
|
||||
.name = "cpu/async_pv_eoi_msr",
|
||||
.version_id = 1,
|
||||
@ -1438,6 +1456,7 @@ VMStateDescription vmstate_x86_cpu = {
|
||||
.subsections = (const VMStateDescription*[]) {
|
||||
&vmstate_exception_info,
|
||||
&vmstate_async_pf_msr,
|
||||
&vmstate_async_pf_int_msr,
|
||||
&vmstate_pv_eoi_msr,
|
||||
&vmstate_steal_time_msr,
|
||||
&vmstate_poll_control_msr,
|
||||
|
@ -975,6 +975,7 @@ void helper_syscall(CPUX86State *env, int next_eip_addend)
|
||||
CPUState *cs = env_cpu(env);
|
||||
|
||||
cs->exception_index = EXCP_SYSCALL;
|
||||
env->exception_is_int = 0;
|
||||
env->exception_next_eip = env->eip + next_eip_addend;
|
||||
cpu_loop_exit(cs);
|
||||
}
|
||||
|
@ -2,10 +2,11 @@
|
||||
#define WHP_DISPATCH_H
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <WinHvPlatform.h>
|
||||
#include <WinHvEmulation.h>
|
||||
|
||||
#define WHV_E_UNKNOWN_CAPABILITY 0x80370300L
|
||||
|
||||
#define LIST_WINHVPLATFORM_FUNCTIONS(X) \
|
||||
X(HRESULT, WHvGetCapability, (WHV_CAPABILITY_CODE CapabilityCode, VOID* CapabilityBuffer, UINT32 CapabilityBufferSizeInBytes, UINT32* WrittenSizeInBytes)) \
|
||||
X(HRESULT, WHvCreatePartition, (WHV_PARTITION_HANDLE* Partition)) \
|
||||
|
@ -27,6 +27,8 @@
|
||||
#include <WinHvPlatform.h>
|
||||
#include <WinHvEmulation.h>
|
||||
|
||||
#define HYPERV_APIC_BUS_FREQUENCY (200000000ULL)
|
||||
|
||||
struct whpx_state {
|
||||
uint64_t mem_quota;
|
||||
WHV_PARTITION_HANDLE partition;
|
||||
@ -1061,6 +1063,18 @@ static int whpx_vcpu_run(CPUState *cpu)
|
||||
cpu_x86_cpuid(env, cpuid_fn, 0, (UINT32 *)&rax, (UINT32 *)&rbx,
|
||||
(UINT32 *)&rcx, (UINT32 *)&rdx);
|
||||
switch (cpuid_fn) {
|
||||
case 0x40000000:
|
||||
/* Expose the vmware cpu frequency cpuid leaf */
|
||||
rax = 0x40000010;
|
||||
rbx = rcx = rdx = 0;
|
||||
break;
|
||||
|
||||
case 0x40000010:
|
||||
rax = env->tsc_khz;
|
||||
rbx = env->apic_bus_freq / 1000; /* Hz to KHz */
|
||||
rcx = rdx = 0;
|
||||
break;
|
||||
|
||||
case 0x80000001:
|
||||
/* Remove any support of OSVW */
|
||||
rcx &= ~CPUID_EXT3_OSVW;
|
||||
@ -1191,8 +1205,12 @@ int whpx_init_vcpu(CPUState *cpu)
|
||||
{
|
||||
HRESULT hr;
|
||||
struct whpx_state *whpx = &whpx_global;
|
||||
struct whpx_vcpu *vcpu;
|
||||
struct whpx_vcpu *vcpu = NULL;
|
||||
Error *local_error = NULL;
|
||||
struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr);
|
||||
X86CPU *x86_cpu = X86_CPU(cpu);
|
||||
UINT64 freq = 0;
|
||||
int ret;
|
||||
|
||||
/* Add migration blockers for all unsupported features of the
|
||||
* Windows Hypervisor Platform
|
||||
@ -1207,7 +1225,8 @@ int whpx_init_vcpu(CPUState *cpu)
|
||||
error_report_err(local_error);
|
||||
migrate_del_blocker(whpx_migration_blocker);
|
||||
error_free(whpx_migration_blocker);
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1215,7 +1234,8 @@ int whpx_init_vcpu(CPUState *cpu)
|
||||
|
||||
if (!vcpu) {
|
||||
error_report("WHPX: Failed to allocte VCPU context.");
|
||||
return -ENOMEM;
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
hr = whp_dispatch.WHvEmulatorCreateEmulator(
|
||||
@ -1224,8 +1244,8 @@ int whpx_init_vcpu(CPUState *cpu)
|
||||
if (FAILED(hr)) {
|
||||
error_report("WHPX: Failed to setup instruction completion support,"
|
||||
" hr=%08lx", hr);
|
||||
g_free(vcpu);
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
hr = whp_dispatch.WHvCreateVirtualProcessor(
|
||||
@ -1234,17 +1254,72 @@ int whpx_init_vcpu(CPUState *cpu)
|
||||
error_report("WHPX: Failed to create a virtual processor,"
|
||||
" hr=%08lx", hr);
|
||||
whp_dispatch.WHvEmulatorDestroyEmulator(vcpu->emulator);
|
||||
g_free(vcpu);
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* vcpu's TSC frequency is either specified by user, or use the value
|
||||
* provided by Hyper-V if the former is not present. In the latter case, we
|
||||
* query it from Hyper-V and record in env->tsc_khz, so that vcpu's TSC
|
||||
* frequency can be migrated later via this field.
|
||||
*/
|
||||
if (!env->tsc_khz) {
|
||||
hr = whp_dispatch.WHvGetCapability(
|
||||
WHvCapabilityCodeProcessorClockFrequency, &freq, sizeof(freq),
|
||||
NULL);
|
||||
if (hr != WHV_E_UNKNOWN_CAPABILITY) {
|
||||
if (FAILED(hr)) {
|
||||
printf("WHPX: Failed to query tsc frequency, hr=0x%08lx\n", hr);
|
||||
} else {
|
||||
env->tsc_khz = freq / 1000; /* Hz to KHz */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
env->apic_bus_freq = HYPERV_APIC_BUS_FREQUENCY;
|
||||
hr = whp_dispatch.WHvGetCapability(
|
||||
WHvCapabilityCodeInterruptClockFrequency, &freq, sizeof(freq), NULL);
|
||||
if (hr != WHV_E_UNKNOWN_CAPABILITY) {
|
||||
if (FAILED(hr)) {
|
||||
printf("WHPX: Failed to query apic bus frequency hr=0x%08lx\n", hr);
|
||||
} else {
|
||||
env->apic_bus_freq = freq;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the vmware cpuid frequency leaf option is set, and we have a valid
|
||||
* tsc value, trap the corresponding cpuid's.
|
||||
*/
|
||||
if (x86_cpu->vmware_cpuid_freq && env->tsc_khz) {
|
||||
UINT32 cpuidExitList[] = {1, 0x80000001, 0x40000000, 0x40000010};
|
||||
|
||||
hr = whp_dispatch.WHvSetPartitionProperty(
|
||||
whpx->partition,
|
||||
WHvPartitionPropertyCodeCpuidExitList,
|
||||
cpuidExitList,
|
||||
RTL_NUMBER_OF(cpuidExitList) * sizeof(UINT32));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
error_report("WHPX: Failed to set partition CpuidExitList hr=%08lx",
|
||||
hr);
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
vcpu->interruptable = true;
|
||||
|
||||
cpu->vcpu_dirty = true;
|
||||
cpu->hax_vcpu = (struct hax_vcpu_state *)vcpu;
|
||||
qemu_add_vm_change_state_handler(whpx_cpu_update_state, cpu->env_ptr);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
g_free(vcpu);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int whpx_vcpu_exec(CPUState *cpu)
|
||||
@ -1493,6 +1568,7 @@ static int whpx_accel_init(MachineState *ms)
|
||||
WHV_CAPABILITY whpx_cap;
|
||||
UINT32 whpx_cap_size;
|
||||
WHV_PARTITION_PROPERTY prop;
|
||||
UINT32 cpuidExitList[] = {1, 0x80000001};
|
||||
|
||||
whpx = &whpx_global;
|
||||
|
||||
@ -1551,7 +1627,6 @@ static int whpx_accel_init(MachineState *ms)
|
||||
goto error;
|
||||
}
|
||||
|
||||
UINT32 cpuidExitList[] = {1, 0x80000001};
|
||||
hr = whp_dispatch.WHvSetPartitionProperty(
|
||||
whpx->partition,
|
||||
WHvPartitionPropertyCodeCpuidExitList,
|
||||
@ -1579,14 +1654,13 @@ static int whpx_accel_init(MachineState *ms)
|
||||
printf("Windows Hypervisor Platform accelerator is operational\n");
|
||||
return 0;
|
||||
|
||||
error:
|
||||
error:
|
||||
|
||||
if (NULL != whpx->partition) {
|
||||
whp_dispatch.WHvDeletePartition(whpx->partition);
|
||||
whpx->partition = NULL;
|
||||
}
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -541,7 +541,6 @@ fpcflags += [
|
||||
fptest = executable(
|
||||
'fp-test',
|
||||
['fp-test.c', tfdir / 'slowfloat.c', '../../fpu/softfloat.c'],
|
||||
build_by_default: false,
|
||||
link_with: [libtestfloat, libsoftfloat],
|
||||
dependencies: [qemuutil],
|
||||
include_directories: [sfinc, include_directories(tfdir)],
|
||||
@ -628,7 +627,6 @@ test('fp-test:mulAdd', fptest,
|
||||
fpbench = executable(
|
||||
'fp-bench',
|
||||
['fp-bench.c', '../../fpu/softfloat.c'],
|
||||
build_by_default: false,
|
||||
link_with: [libtestfloat, libsoftfloat],
|
||||
dependencies: [qemuutil],
|
||||
include_directories: [sfinc, include_directories(tfdir)],
|
||||
|
@ -56,7 +56,7 @@ test_qapi_files = custom_target('Test QAPI files',
|
||||
# perhaps change qapi_gen to replace / with _, like Meson itself does?
|
||||
subdir('include')
|
||||
|
||||
libtestqapi = static_library('testqapi', sources: [test_qapi_files, test_qapi_outputs_extra])
|
||||
libtestqapi = static_library('testqapi', sources: [test_qapi_files, genh, test_qapi_outputs_extra])
|
||||
testqapi = declare_dependency(link_with: libtestqapi)
|
||||
|
||||
testblock = declare_dependency(dependencies: [block], sources: 'iothread.c')
|
||||
@ -232,7 +232,7 @@ foreach test_name, extra: tests
|
||||
src += test_ss.all_sources()
|
||||
deps += test_ss.all_dependencies()
|
||||
endif
|
||||
exe = executable(test_name, src, dependencies: deps)
|
||||
exe = executable(test_name, src, genh, dependencies: deps)
|
||||
|
||||
test(test_name, exe,
|
||||
depends: test_deps.get(test_name, []),
|
||||
@ -251,12 +251,11 @@ foreach bench_name, deps: benchs
|
||||
suite: ['speed'])
|
||||
endforeach
|
||||
|
||||
if have_tools and 'CONFIG_VHOST_USER' in config_host
|
||||
if have_tools and 'CONFIG_VHOST_USER' in config_host and 'CONFIG_LINUX' in config_host
|
||||
executable('vhost-user-bridge',
|
||||
sources: files('vhost-user-bridge.c'),
|
||||
link_with: [libvhost_user],
|
||||
dependencies: [qemuutil],
|
||||
build_by_default: false)
|
||||
dependencies: [qemuutil])
|
||||
endif
|
||||
|
||||
if have_system and 'CONFIG_POSIX' in config_host
|
||||
|
@ -1,6 +1,5 @@
|
||||
if 'CONFIG_LINUX' in config_host
|
||||
socket_scm_helper = executable('socket_scm_helper', 'socket_scm_helper.c',
|
||||
build_by_default: false)
|
||||
socket_scm_helper = executable('socket_scm_helper', 'socket_scm_helper.c')
|
||||
else
|
||||
socket_scm_helper = []
|
||||
endif
|
||||
|
@ -663,8 +663,7 @@ static void test_acpi_one(const char *params, test_data *data)
|
||||
data->uefi_fl1, data->uefi_fl2, data->cd, params ? params : "");
|
||||
|
||||
} else {
|
||||
/* Disable kernel irqchip to be able to override apic irq0. */
|
||||
args = g_strdup_printf("-machine %s,kernel-irqchip=off %s -accel tcg "
|
||||
args = g_strdup_printf("-machine %s %s -accel tcg "
|
||||
"-net none -display none %s "
|
||||
"-drive id=hd0,if=none,file=%s,format=raw "
|
||||
"-device %s,drive=hd0 ",
|
||||
|
@ -143,7 +143,8 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp)
|
||||
{
|
||||
|
||||
char *target_name;
|
||||
char *bindir, *datadir;
|
||||
const char *bindir;
|
||||
char *datadir;
|
||||
bool serialize = false;
|
||||
|
||||
/* Initialize qgraph and modules */
|
||||
@ -152,6 +153,7 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp)
|
||||
module_call_init(MODULE_INIT_QOM);
|
||||
module_call_init(MODULE_INIT_LIBQOS);
|
||||
|
||||
qemu_init_exec_dir(**argv);
|
||||
target_name = strstr(**argv, "-target-");
|
||||
if (target_name) { /* The binary name specifies the target */
|
||||
target_name += strlen("-target-");
|
||||
@ -164,13 +166,13 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp)
|
||||
* location of the executable. Using this we add exec_dir/pc-bios to
|
||||
* the datadirs.
|
||||
*/
|
||||
bindir = g_path_get_dirname(**argv);
|
||||
bindir = qemu_get_exec_dir();
|
||||
datadir = g_build_filename(bindir, "pc-bios", NULL);
|
||||
g_free(bindir);
|
||||
if (g_file_test(datadir, G_FILE_TEST_IS_DIR)) {
|
||||
qemu_add_data_dir(datadir);
|
||||
}
|
||||
g_free(datadir);
|
||||
} else {
|
||||
g_free(datadir);
|
||||
}
|
||||
} else if (*argc > 1) { /* The target is specified as an argument */
|
||||
target_name = (*argv)[1];
|
||||
if (!strstr(target_name, "--fuzz-target=")) {
|
||||
|
@ -228,10 +228,15 @@ foreach dir : target_dirs
|
||||
endif
|
||||
|
||||
target_base = dir.split('-')[0]
|
||||
qtest_emulator = emulators['qemu-system-' + target_base]
|
||||
qtests = get_variable('qtests_' + target_base, []) + qtests_generic
|
||||
|
||||
test_deps = []
|
||||
qtest_env = environment()
|
||||
qtest_env.set('QTEST_QEMU_IMG', './qemu-img')
|
||||
if have_tools
|
||||
qtest_env.set('QTEST_QEMU_IMG', './qemu-img')
|
||||
test_deps += [qemu_img]
|
||||
endif
|
||||
qtest_env.set('G_TEST_DBUS_DAEMON', meson.source_root() / 'tests/dbus-vmstate-daemon.sh')
|
||||
qtest_env.set('QTEST_QEMU_BINARY', './qemu-system-' + target_base)
|
||||
|
||||
@ -248,6 +253,7 @@ foreach dir : target_dirs
|
||||
# FIXME: missing dependency on the emulator binary and qemu-img
|
||||
test('qtest-@0@: @1@'.format(target_base, test),
|
||||
qtest_executables[test],
|
||||
depends: [test_deps, qtest_emulator],
|
||||
env: qtest_env,
|
||||
args: ['--tap', '-k'],
|
||||
protocol: 'tap',
|
||||
|
@ -11,9 +11,20 @@
|
||||
# The configure script fills in extra information about
|
||||
# useful docker images or alternative compiler flags.
|
||||
|
||||
# Usage: $(call quiet-command,command and args,"NAME","args to print")
|
||||
# This will run "command and args", and either:
|
||||
# if V=1 just print the whole command and args
|
||||
# otherwise print the 'quiet' output in the format " NAME args to print"
|
||||
# NAME should be a short name of the command, 7 letters or fewer.
|
||||
# If called with only a single argument, will print nothing in quiet mode.
|
||||
quiet-command-run = $(if $(V),,$(if $2,printf " %-7s %s\n" $2 $3 && ))$1
|
||||
quiet-@ = $(if $(V),,@)
|
||||
quiet-command = $(quiet-@)$(call quiet-command-run,$1,$2,$3)
|
||||
|
||||
CROSS_CC_GUEST:=
|
||||
DOCKER_IMAGE:=
|
||||
-include $(BUILD_DIR)/tests/tcg/config-$(TARGET).mak
|
||||
|
||||
-include tests/tcg/config-$(TARGET).mak
|
||||
|
||||
GUEST_BUILD=
|
||||
TCG_MAKE=../Makefile.target
|
||||
|
@ -193,11 +193,11 @@ for target in $target_list; do
|
||||
case $target in
|
||||
*-linux-user | *-bsd-user)
|
||||
echo "CONFIG_USER_ONLY=y" >> $config_target_mak
|
||||
echo "QEMU=\$(BUILD_DIR)/qemu-$arch" >> $config_target_mak
|
||||
echo "QEMU=$PWD/qemu-$arch" >> $config_target_mak
|
||||
;;
|
||||
*-softmmu)
|
||||
echo "CONFIG_SOFTMMU=y" >> $config_target_mak
|
||||
echo "QEMU=\$(BUILD_DIR)/qemu-system-$arch" >> $config_target_mak
|
||||
echo "QEMU=$PWD/qemu-system-$arch" >> $config_target_mak
|
||||
;;
|
||||
esac
|
||||
|
||||
|
@ -70,7 +70,6 @@ foreach d : [
|
||||
output: d[0],
|
||||
input: meson.source_root() / 'trace-events',
|
||||
command: [ tracetool, '--group=root', '--format=@0@'.format(d[1]), '@INPUT@' ],
|
||||
build_by_default: true, # to be removed when added to a target
|
||||
capture: true)
|
||||
specific_ss.add(gen)
|
||||
endforeach
|
||||
|
10
ui/gtk.c
10
ui/gtk.c
@ -51,6 +51,7 @@
|
||||
#include <math.h>
|
||||
|
||||
#include "trace.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "ui/input.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
@ -2202,6 +2203,7 @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *opts)
|
||||
GtkDisplayState *s = g_malloc0(sizeof(*s));
|
||||
GdkDisplay *window_display;
|
||||
GtkIconTheme *theme;
|
||||
char *dir;
|
||||
|
||||
if (!gtkinit) {
|
||||
fprintf(stderr, "gtk initialization failed\n");
|
||||
@ -2211,7 +2213,9 @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *opts)
|
||||
s->opts = opts;
|
||||
|
||||
theme = gtk_icon_theme_get_default();
|
||||
gtk_icon_theme_prepend_search_path(theme, CONFIG_QEMU_ICONDIR);
|
||||
dir = get_relocated_path(CONFIG_QEMU_ICONDIR);
|
||||
gtk_icon_theme_prepend_search_path(theme, dir);
|
||||
g_free(dir);
|
||||
g_set_prgname("qemu");
|
||||
|
||||
s->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
@ -2227,7 +2231,9 @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *opts)
|
||||
* sure that we don't accidentally break implicit assumptions. */
|
||||
setlocale(LC_MESSAGES, "");
|
||||
setlocale(LC_CTYPE, "C.UTF-8");
|
||||
bindtextdomain("qemu", CONFIG_QEMU_LOCALEDIR);
|
||||
dir = get_relocated_path(CONFIG_QEMU_LOCALEDIR);
|
||||
bindtextdomain("qemu", dir);
|
||||
g_free(dir);
|
||||
bind_textdomain_codeset("qemu", "UTF-8");
|
||||
textdomain("qemu");
|
||||
|
||||
|
@ -15,7 +15,7 @@ softmmu_ss.add(files(
|
||||
|
||||
softmmu_ss.add(when: 'CONFIG_LINUX', if_true: files('input-linux.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_SPICE', if_true: files('spice-core.c', 'spice-input.c', 'spice-display.c'))
|
||||
softmmu_ss.add(when: [cocoa, 'CONFIG_COCOA'], if_true: files('cocoa.m'))
|
||||
softmmu_ss.add(when: cocoa, if_true: files('cocoa.m'))
|
||||
|
||||
vnc_ss = ss.source_set()
|
||||
vnc_ss.add(files(
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "ui/console.h"
|
||||
#include "ui/input.h"
|
||||
#include "ui/sdl2.h"
|
||||
@ -795,6 +796,7 @@ static void sdl2_display_init(DisplayState *ds, DisplayOptions *o)
|
||||
int i;
|
||||
SDL_SysWMinfo info;
|
||||
SDL_Surface *icon = NULL;
|
||||
char *dir;
|
||||
|
||||
assert(o->type == DISPLAY_TYPE_SDL);
|
||||
|
||||
@ -868,15 +870,18 @@ static void sdl2_display_init(DisplayState *ds, DisplayOptions *o)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SDL_IMAGE
|
||||
icon = IMG_Load(CONFIG_QEMU_ICONDIR "/hicolor/128x128/apps/qemu.png");
|
||||
dir = get_relocated_path(CONFIG_QEMU_ICONDIR "/hicolor/128x128/apps/qemu.png");
|
||||
icon = IMG_Load(dir);
|
||||
#else
|
||||
/* Load a 32x32x4 image. White pixels are transparent. */
|
||||
icon = SDL_LoadBMP(CONFIG_QEMU_ICONDIR "/hicolor/32x32/apps/qemu.bmp");
|
||||
dir = get_relocated_path(CONFIG_QEMU_ICONDIR "/hicolor/32x32/apps/qemu.bmp");
|
||||
icon = SDL_LoadBMP(dir);
|
||||
if (icon) {
|
||||
uint32_t colorkey = SDL_MapRGB(icon->format, 255, 255, 255);
|
||||
SDL_SetColorKey(icon, SDL_TRUE, colorkey);
|
||||
}
|
||||
#endif
|
||||
g_free(dir);
|
||||
if (icon) {
|
||||
SDL_SetWindowIcon(sdl2_console[0].real_window, icon);
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ foreach e : shaders
|
||||
genh += custom_target(output,
|
||||
output: output,
|
||||
capture: true,
|
||||
build_by_default: true, # to be removed when added to a target
|
||||
input: files('@0@.@1@'.format(e[0], e[1])),
|
||||
command: [shaderinclude, '@INPUT0@'])
|
||||
endforeach
|
||||
|
@ -889,3 +889,64 @@ int qemu_pstrcmp0(const char **str1, const char **str2)
|
||||
{
|
||||
return g_strcmp0(*str1, *str2);
|
||||
}
|
||||
|
||||
static inline bool starts_with_prefix(const char *dir)
|
||||
{
|
||||
size_t prefix_len = strlen(CONFIG_PREFIX);
|
||||
return !memcmp(dir, CONFIG_PREFIX, prefix_len) &&
|
||||
(!dir[prefix_len] || G_IS_DIR_SEPARATOR(dir[prefix_len]));
|
||||
}
|
||||
|
||||
/* Return the next path component in dir, and store its length in *p_len. */
|
||||
static inline const char *next_component(const char *dir, int *p_len)
|
||||
{
|
||||
int len;
|
||||
while (*dir && G_IS_DIR_SEPARATOR(*dir)) {
|
||||
dir++;
|
||||
}
|
||||
len = 0;
|
||||
while (dir[len] && !G_IS_DIR_SEPARATOR(dir[len])) {
|
||||
len++;
|
||||
}
|
||||
*p_len = len;
|
||||
return dir;
|
||||
}
|
||||
|
||||
char *get_relocated_path(const char *dir)
|
||||
{
|
||||
size_t prefix_len = strlen(CONFIG_PREFIX);
|
||||
const char *bindir = CONFIG_BINDIR;
|
||||
const char *exec_dir = qemu_get_exec_dir();
|
||||
GString *result;
|
||||
int len_dir, len_bindir;
|
||||
|
||||
/* Fail if qemu_init_exec_dir was not called. */
|
||||
assert(exec_dir[0]);
|
||||
if (!starts_with_prefix(dir) || !starts_with_prefix(bindir)) {
|
||||
return strdup(dir);
|
||||
}
|
||||
|
||||
result = g_string_new(exec_dir);
|
||||
|
||||
/* Advance over common components. */
|
||||
len_dir = len_bindir = prefix_len;
|
||||
do {
|
||||
dir += len_dir;
|
||||
bindir += len_bindir;
|
||||
dir = next_component(dir, &len_dir);
|
||||
bindir = next_component(bindir, &len_bindir);
|
||||
} while (len_dir == len_bindir && !memcmp(dir, bindir, len_dir));
|
||||
|
||||
/* Ascend from bindir to the common prefix with dir. */
|
||||
while (len_bindir) {
|
||||
bindir += len_bindir;
|
||||
g_string_append(result, "/..");
|
||||
bindir = next_component(bindir, &len_bindir);
|
||||
}
|
||||
|
||||
if (*dir) {
|
||||
assert(G_IS_DIR_SEPARATOR(dir[-1]));
|
||||
g_string_append(result, dir - 1);
|
||||
}
|
||||
return result->str;
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
#endif
|
||||
#include "qemu/queue.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/cutils.h"
|
||||
#ifdef CONFIG_MODULE_UPGRADES
|
||||
#include "qemu-version.h"
|
||||
#endif
|
||||
@ -172,7 +173,6 @@ bool module_load_one(const char *prefix, const char *lib_name)
|
||||
|
||||
#ifdef CONFIG_MODULES
|
||||
char *fname = NULL;
|
||||
char *exec_dir;
|
||||
#ifdef CONFIG_MODULE_UPGRADES
|
||||
char *version_dir;
|
||||
#endif
|
||||
@ -199,13 +199,12 @@ bool module_load_one(const char *prefix, const char *lib_name)
|
||||
return true;
|
||||
}
|
||||
|
||||
exec_dir = qemu_get_exec_dir();
|
||||
search_dir = getenv("QEMU_MODULE_DIR");
|
||||
if (search_dir != NULL) {
|
||||
dirs[n_dirs++] = g_strdup_printf("%s", search_dir);
|
||||
}
|
||||
dirs[n_dirs++] = g_strdup_printf("%s", CONFIG_QEMU_MODDIR);
|
||||
dirs[n_dirs++] = g_strdup_printf("%s", exec_dir ? : "");
|
||||
dirs[n_dirs++] = get_relocated_path(CONFIG_QEMU_MODDIR);
|
||||
dirs[n_dirs++] = g_strdup(qemu_get_exec_dir());
|
||||
|
||||
#ifdef CONFIG_MODULE_UPGRADES
|
||||
version_dir = g_strcanon(g_strdup(QEMU_PKGVERSION),
|
||||
@ -216,9 +215,6 @@ bool module_load_one(const char *prefix, const char *lib_name)
|
||||
|
||||
assert(n_dirs <= ARRAY_SIZE(dirs));
|
||||
|
||||
g_free(exec_dir);
|
||||
exec_dir = NULL;
|
||||
|
||||
for (i = 0; i < n_dirs; i++) {
|
||||
fname = g_strdup_printf("%s/%s%s",
|
||||
dirs[i], module_name, CONFIG_HOST_DSOSUF);
|
||||
|
@ -339,8 +339,10 @@ int qemu_pipe(int pipefd[2])
|
||||
char *
|
||||
qemu_get_local_state_pathname(const char *relative_pathname)
|
||||
{
|
||||
return g_strdup_printf("%s/%s", CONFIG_QEMU_LOCALSTATEDIR,
|
||||
relative_pathname);
|
||||
g_autofree char *dir = g_strdup_printf("%s/%s",
|
||||
CONFIG_QEMU_LOCALSTATEDIR,
|
||||
relative_pathname);
|
||||
return get_relocated_path(dir);
|
||||
}
|
||||
|
||||
void qemu_set_tty_echo(int fd, bool echo)
|
||||
@ -358,15 +360,16 @@ void qemu_set_tty_echo(int fd, bool echo)
|
||||
tcsetattr(fd, TCSANOW, &tty);
|
||||
}
|
||||
|
||||
static char exec_dir[PATH_MAX];
|
||||
static const char *exec_dir;
|
||||
|
||||
void qemu_init_exec_dir(const char *argv0)
|
||||
{
|
||||
char *dir;
|
||||
char *p = NULL;
|
||||
char buf[PATH_MAX];
|
||||
|
||||
assert(!exec_dir[0]);
|
||||
if (exec_dir) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(__linux__)
|
||||
{
|
||||
@ -423,25 +426,19 @@ void qemu_init_exec_dir(const char *argv0)
|
||||
#endif
|
||||
/* If we don't have any way of figuring out the actual executable
|
||||
location then try argv[0]. */
|
||||
if (!p) {
|
||||
if (!argv0) {
|
||||
return;
|
||||
}
|
||||
if (!p && argv0) {
|
||||
p = realpath(argv0, buf);
|
||||
if (!p) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
dir = g_path_get_dirname(p);
|
||||
|
||||
pstrcpy(exec_dir, sizeof(exec_dir), dir);
|
||||
|
||||
g_free(dir);
|
||||
if (p) {
|
||||
exec_dir = g_path_get_dirname(p);
|
||||
} else {
|
||||
exec_dir = CONFIG_BINDIR;
|
||||
}
|
||||
}
|
||||
|
||||
char *qemu_get_exec_dir(void)
|
||||
const char *qemu_get_exec_dir(void)
|
||||
{
|
||||
return g_strdup(exec_dir);
|
||||
return exec_dir;
|
||||
}
|
||||
|
||||
static void sigbus_handler(int signal)
|
||||
|
@ -315,7 +315,7 @@ void qemu_set_tty_echo(int fd, bool echo)
|
||||
}
|
||||
}
|
||||
|
||||
static char exec_dir[PATH_MAX];
|
||||
static const char *exec_dir;
|
||||
|
||||
void qemu_init_exec_dir(const char *argv0)
|
||||
{
|
||||
@ -324,6 +324,10 @@ void qemu_init_exec_dir(const char *argv0)
|
||||
char buf[MAX_PATH];
|
||||
DWORD len;
|
||||
|
||||
if (exec_dir) {
|
||||
return;
|
||||
}
|
||||
|
||||
len = GetModuleFileName(NULL, buf, sizeof(buf) - 1);
|
||||
if (len == 0) {
|
||||
return;
|
||||
@ -336,13 +340,15 @@ void qemu_init_exec_dir(const char *argv0)
|
||||
}
|
||||
*p = 0;
|
||||
if (access(buf, R_OK) == 0) {
|
||||
pstrcpy(exec_dir, sizeof(exec_dir), buf);
|
||||
exec_dir = g_strdup(buf);
|
||||
} else {
|
||||
exec_dir = CONFIG_BINDIR;
|
||||
}
|
||||
}
|
||||
|
||||
char *qemu_get_exec_dir(void)
|
||||
const char *qemu_get_exec_dir(void)
|
||||
{
|
||||
return g_strdup(exec_dir);
|
||||
return exec_dir;
|
||||
}
|
||||
|
||||
#if !GLIB_CHECK_VERSION(2, 50, 0)
|
||||
|
Loading…
x
Reference in New Issue
Block a user