Merge remote-tracking branch 'upstream/master' into main

This commit is contained in:
Andrea Fioraldi 2022-06-16 10:56:25 +02:00
commit ac7bfe4325
201 changed files with 4167 additions and 1285 deletions

View File

@ -13,7 +13,7 @@
#############################################################
# Cirrus jobs can't run unless the creds / target repo are set
- if: '$QEMU_JOB_CIRRUS && ($CIRRUS_GITHUB_REPO == "" || $CIRRUS_API_TOKEN == "")'
- if: '$QEMU_JOB_CIRRUS && ($CIRRUS_GITHUB_REPO == null || $CIRRUS_API_TOKEN == null)'
when: never
# Publishing jobs should only run on the default branch in upstream

View File

@ -168,6 +168,7 @@ build-system-centos:
IMAGE: centos8
CONFIGURE_ARGS: --disable-nettle --enable-gcrypt --enable-fdt=system
--enable-modules --enable-trace-backends=dtrace --enable-docs
--enable-vfio-user-server
TARGETS: ppc64-softmmu or1k-softmmu s390x-softmmu
x86_64-softmmu rx-softmmu sh4-softmmu nios2-softmmu
MAKE_CHECK_ARGS: check-build
@ -357,16 +358,15 @@ build-cfi-aarch64:
--enable-safe-stack --enable-slirp=git
TARGETS: aarch64-softmmu
MAKE_CHECK_ARGS: check-build
timeout: 70m
artifacts:
expire_in: 2 days
paths:
- build
variables:
# FIXME: This job is often failing, likely due to out-of-memory problems in
# the constrained containers of the shared runners. Thus this is marked as
# skipped until the situation has been solved.
QEMU_JOB_SKIPPED: 1
timeout: 90m
artifacts:
expire_in: 2 days
paths:
- build
check-cfi-aarch64:
extends: .native_test_job_template
@ -398,16 +398,15 @@ build-cfi-ppc64-s390x:
--enable-safe-stack --enable-slirp=git
TARGETS: ppc64-softmmu s390x-softmmu
MAKE_CHECK_ARGS: check-build
timeout: 70m
artifacts:
expire_in: 2 days
paths:
- build
variables:
# FIXME: This job is often failing, likely due to out-of-memory problems in
# the constrained containers of the shared runners. Thus this is marked as
# skipped until the situation has been solved.
QEMU_JOB_SKIPPED: 1
timeout: 80m
artifacts:
expire_in: 2 days
paths:
- build
check-cfi-ppc64-s390x:
extends: .native_test_job_template

View File

@ -19,5 +19,5 @@ ubuntu-20.04-aarch32-all:
- mkdir build
- cd build
- ../configure --cross-prefix=arm-linux-gnueabihf-
- make --output-sync -j`nproc`
- make --output-sync -j`nproc` check V=1
- make --output-sync -j`nproc --ignore=40`
- make --output-sync -j`nproc --ignore=40` check V=1

View File

@ -17,9 +17,9 @@ ubuntu-20.04-aarch64-all-linux-static:
- mkdir build
- cd build
- ../configure --enable-debug --static --disable-system --disable-glusterfs --disable-libssh
- make --output-sync -j`nproc`
- make --output-sync -j`nproc` check V=1
- make --output-sync -j`nproc` check-tcg V=1
- make --output-sync -j`nproc --ignore=40`
- make --output-sync -j`nproc --ignore=40` check V=1
- make --output-sync -j`nproc --ignore=40` check-tcg V=1
ubuntu-20.04-aarch64-all:
needs: []
@ -38,8 +38,8 @@ ubuntu-20.04-aarch64-all:
- mkdir build
- cd build
- ../configure --disable-libssh
- make --output-sync -j`nproc`
- make --output-sync -j`nproc` check V=1
- make --output-sync -j`nproc --ignore=40`
- make --output-sync -j`nproc --ignore=40` check V=1
ubuntu-20.04-aarch64-alldbg:
needs: []
@ -55,8 +55,8 @@ ubuntu-20.04-aarch64-alldbg:
- cd build
- ../configure --enable-debug --disable-libssh
- make clean
- make --output-sync -j`nproc`
- make --output-sync -j`nproc` check V=1
- make --output-sync -j`nproc --ignore=40`
- make --output-sync -j`nproc --ignore=40` check V=1
ubuntu-20.04-aarch64-clang:
needs: []
@ -75,8 +75,8 @@ ubuntu-20.04-aarch64-clang:
- mkdir build
- cd build
- ../configure --disable-libssh --cc=clang-10 --cxx=clang++-10 --enable-sanitizers
- make --output-sync -j`nproc`
- make --output-sync -j`nproc` check V=1
- make --output-sync -j`nproc --ignore=40`
- make --output-sync -j`nproc --ignore=40` check V=1
ubuntu-20.04-aarch64-tci:
needs: []
@ -95,7 +95,7 @@ ubuntu-20.04-aarch64-tci:
- mkdir build
- cd build
- ../configure --disable-libssh --enable-tcg-interpreter
- make --output-sync -j`nproc`
- make --output-sync -j`nproc --ignore=40`
ubuntu-20.04-aarch64-notcg:
needs: []
@ -114,5 +114,5 @@ ubuntu-20.04-aarch64-notcg:
- mkdir build
- cd build
- ../configure --disable-libssh --disable-tcg
- make --output-sync -j`nproc`
- make --output-sync -j`nproc` check V=1
- make --output-sync -j`nproc --ignore=40`
- make --output-sync -j`nproc --ignore=40` check V=1

3
.gitmodules vendored
View File

@ -64,3 +64,6 @@
[submodule "tests/lcitool/libvirt-ci"]
path = tests/lcitool/libvirt-ci
url = https://gitlab.com/libvirt/libvirt-ci.git
[submodule "subprojects/libvfio-user"]
path = subprojects/libvfio-user
url = https://gitlab.com/qemu-project/libvfio-user.git

View File

@ -42,3 +42,7 @@ config MULTIPROCESS_ALLOWED
config FUZZ
bool
select SPARSE_MEM
config VFIO_USER_SERVER_ALLOWED
bool
imply VFIO_USER_SERVER

View File

@ -246,7 +246,8 @@ F: docs/system/cpu-models-mips.rst.inc
F: tests/tcg/mips/
MIPS TCG CPUs (nanoMIPS ISA)
S: Orphan
M: Stefan Pejic <stefan.pejic@syrmia.com>
S: Maintained
F: disas/nanomips.*
F: target/mips/tcg/*nanomips*
@ -2426,6 +2427,14 @@ F: hw/intc/s390_flic*.c
F: include/hw/s390x/s390_flic.h
L: qemu-s390x@nongnu.org
CanoKey
M: Hongren (Zenithal) Zheng <i@zenithal.me>
S: Maintained
R: Canokeys.org <contact@canokeys.org>
F: hw/usb/canokey.c
F: hw/usb/canokey.h
F: docs/system/devices/canokey.rst
Subsystems
----------
Overall Audio backends
@ -2537,7 +2546,7 @@ F: scsi/*
Block Jobs
M: John Snow <jsnow@redhat.com>
M: Vladimir Sementsov-Ogievskiy <v.sementsov-og@mail.ru>
M: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
L: qemu-block@nongnu.org
S: Supported
F: blockjob.c
@ -2562,7 +2571,7 @@ F: block/aio_task.c
F: util/qemu-co-shared-resource.c
F: include/qemu/co-shared-resource.h
T: git https://gitlab.com/jsnow/qemu.git jobs
T: git https://src.openvz.org/scm/~vsementsov/qemu.git jobs
T: git https://gitlab.com/vsementsov/qemu.git block
Block QAPI, monitor, command line
M: Markus Armbruster <armbru@redhat.com>
@ -2583,7 +2592,7 @@ F: include/hw/cxl/
Dirty Bitmaps
M: Eric Blake <eblake@redhat.com>
M: Vladimir Sementsov-Ogievskiy <v.sementsov-og@mail.ru>
M: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
R: John Snow <jsnow@redhat.com>
L: qemu-block@nongnu.org
S: Supported
@ -2597,6 +2606,7 @@ F: util/hbitmap.c
F: tests/unit/test-hbitmap.c
F: docs/interop/bitmaps.rst
T: git https://repo.or.cz/qemu/ericb.git bitmaps
T: git https://gitlab.com/vsementsov/qemu.git block
Character device backends
M: Marc-André Lureau <marcandre.lureau@redhat.com>
@ -2807,16 +2817,17 @@ F: scripts/*.py
F: tests/*.py
Benchmark util
M: Vladimir Sementsov-Ogievskiy <v.sementsov-og@mail.ru>
M: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
S: Maintained
F: scripts/simplebench/
T: git https://src.openvz.org/scm/~vsementsov/qemu.git simplebench
T: git https://gitlab.com/vsementsov/qemu.git simplebench
Transactions helper
M: Vladimir Sementsov-Ogievskiy <v.sementsov-og@mail.ru>
M: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
S: Maintained
F: include/qemu/transactions.h
F: util/transactions.c
T: git https://gitlab.com/vsementsov/qemu.git block
QAPI
M: Markus Armbruster <armbru@redhat.com>
@ -3393,7 +3404,7 @@ F: block/iscsi-opts.c
Network Block Device (NBD)
M: Eric Blake <eblake@redhat.com>
M: Vladimir Sementsov-Ogievskiy <v.sementsov-og@mail.ru>
M: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
L: qemu-block@nongnu.org
S: Maintained
F: block/nbd*
@ -3405,7 +3416,7 @@ F: docs/interop/nbd.txt
F: docs/tools/qemu-nbd.rst
F: tests/qemu-iotests/tests/*nbd*
T: git https://repo.or.cz/qemu/ericb.git nbd
T: git https://src.openvz.org/scm/~vsementsov/qemu.git nbd
T: git https://gitlab.com/vsementsov/qemu.git block
NFS
M: Peter Lieven <pl@kamp.de>
@ -3490,13 +3501,13 @@ F: block/dmg.c
parallels
M: Stefan Hajnoczi <stefanha@redhat.com>
M: Denis V. Lunev <den@openvz.org>
M: Vladimir Sementsov-Ogievskiy <v.sementsov-og@mail.ru>
M: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
L: qemu-block@nongnu.org
S: Supported
F: block/parallels.c
F: block/parallels-ext.c
F: docs/interop/parallels.txt
T: git https://src.openvz.org/scm/~vsementsov/qemu.git parallels
T: git https://gitlab.com/vsementsov/qemu.git block
qed
M: Stefan Hajnoczi <stefanha@redhat.com>
@ -3631,6 +3642,11 @@ F: hw/remote/proxy-memory-listener.c
F: include/hw/remote/proxy-memory-listener.h
F: hw/remote/iohub.c
F: include/hw/remote/iohub.h
F: subprojects/libvfio-user
F: hw/remote/vfio-user-obj.c
F: include/hw/remote/vfio-user-obj.h
F: hw/remote/iommu.c
F: include/hw/remote/iommu.h
EBPF:
M: Jason Wang <jasowang@redhat.com>

View File

@ -1088,7 +1088,7 @@ void tcg_exec_unrealizefn(CPUState *cpu)
#ifndef CONFIG_USER_ONLY
void dump_drift_info(GString *buf)
static void dump_drift_info(GString *buf)
{
if (!icount_enabled()) {
return;
@ -1131,7 +1131,7 @@ HumanReadableText *qmp_x_query_opcount(Error **errp)
return NULL;
}
dump_opcount_info(buf);
tcg_dump_op_count(buf);
return human_readable_text_from_str(buf);
}

View File

@ -2931,11 +2931,6 @@ void dump_exec_info(GString *buf)
tcg_dump_info(buf);
}
void dump_opcount_info(GString *buf)
{
tcg_dump_op_count(buf);
}
#else /* CONFIG_USER_ONLY */
void cpu_interrupt(CPUState *cpu, int mask)

View File

@ -18,6 +18,7 @@
#include "qapi/error.h"
#include "trace.h"
/* io_uring ring size */
#define MAX_ENTRIES 128
@ -434,8 +435,17 @@ LuringState *luring_init(Error **errp)
}
ioq_init(&s->io_q);
return s;
#ifdef CONFIG_LIBURING_REGISTER_RING_FD
if (io_uring_register_ring_fd(&s->ring) < 0) {
/*
* Only warn about this error: we will fallback to the non-optimized
* io_uring operations.
*/
warn_report("failed to register linux io_uring ring file descriptor");
}
#endif
return s;
}
void luring_cleanup(LuringState *s)

View File

@ -363,8 +363,16 @@ void laio_io_unplug(BlockDriverState *bs, LinuxAioState *s,
uint64_t dev_max_batch)
{
assert(s->io_q.plugged);
s->io_q.plugged--;
/*
* Why max batch checking is performed here:
* Another BDS may have queued requests with a higher dev_max_batch and
* therefore in_queue could now exceed our dev_max_batch. Re-check the max
* batch so we can honor our device's dev_max_batch.
*/
if (s->io_q.in_queue >= laio_max_batch(s, dev_max_batch) ||
(--s->io_q.plugged == 0 &&
(!s->io_q.plugged &&
!s->io_q.blocked && !QSIMPLEQ_EMPTY(&s->io_q.pending))) {
ioq_submit(s);
}

View File

@ -27,4 +27,167 @@ extern struct iovec *lock_iovec(int type, abi_ulong target_addr, int count,
extern void unlock_iovec(struct iovec *vec, abi_ulong target_addr, int count,
int copy);
ssize_t safe_read(int fd, void *buf, size_t nbytes);
ssize_t safe_pread(int fd, void *buf, size_t nbytes, off_t offset);
ssize_t safe_readv(int fd, const struct iovec *iov, int iovcnt);
ssize_t safe_preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset);
ssize_t safe_write(int fd, void *buf, size_t nbytes);
ssize_t safe_pwrite(int fd, void *buf, size_t nbytes, off_t offset);
ssize_t safe_writev(int fd, const struct iovec *iov, int iovcnt);
ssize_t safe_pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset);
/* read(2) */
static abi_long do_bsd_read(abi_long arg1, abi_long arg2, abi_long arg3)
{
abi_long ret;
void *p;
p = lock_user(VERIFY_WRITE, arg2, arg3, 0);
if (p == NULL) {
return -TARGET_EFAULT;
}
ret = get_errno(safe_read(arg1, p, arg3));
unlock_user(p, arg2, ret);
return ret;
}
/* pread(2) */
static abi_long do_bsd_pread(void *cpu_env, abi_long arg1,
abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
{
abi_long ret;
void *p;
p = lock_user(VERIFY_WRITE, arg2, arg3, 0);
if (p == NULL) {
return -TARGET_EFAULT;
}
if (regpairs_aligned(cpu_env) != 0) {
arg4 = arg5;
arg5 = arg6;
}
ret = get_errno(safe_pread(arg1, p, arg3, target_arg64(arg4, arg5)));
unlock_user(p, arg2, ret);
return ret;
}
/* readv(2) */
static abi_long do_bsd_readv(abi_long arg1, abi_long arg2, abi_long arg3)
{
abi_long ret;
struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
if (vec != NULL) {
ret = get_errno(safe_readv(arg1, vec, arg3));
unlock_iovec(vec, arg2, arg3, 1);
} else {
ret = -host_to_target_errno(errno);
}
return ret;
}
/* preadv(2) */
static abi_long do_bsd_preadv(void *cpu_env, abi_long arg1,
abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
{
abi_long ret;
struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 1);
if (vec != NULL) {
if (regpairs_aligned(cpu_env) != 0) {
arg4 = arg5;
arg5 = arg6;
}
ret = get_errno(safe_preadv(arg1, vec, arg3, target_arg64(arg4, arg5)));
unlock_iovec(vec, arg2, arg3, 0);
} else {
ret = -host_to_target_errno(errno);
}
return ret;
}
/* write(2) */
static abi_long do_bsd_write(abi_long arg1, abi_long arg2, abi_long arg3)
{
abi_long nbytes, ret;
void *p;
/* nbytes < 0 implies that it was larger than SIZE_MAX. */
nbytes = arg3;
if (nbytes < 0) {
return -TARGET_EINVAL;
}
p = lock_user(VERIFY_READ, arg2, nbytes, 1);
if (p == NULL) {
return -TARGET_EFAULT;
}
ret = get_errno(safe_write(arg1, p, arg3));
unlock_user(p, arg2, 0);
return ret;
}
/* pwrite(2) */
static abi_long do_bsd_pwrite(void *cpu_env, abi_long arg1,
abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
{
abi_long ret;
void *p;
p = lock_user(VERIFY_READ, arg2, arg3, 1);
if (p == NULL) {
return -TARGET_EFAULT;
}
if (regpairs_aligned(cpu_env) != 0) {
arg4 = arg5;
arg5 = arg6;
}
ret = get_errno(safe_pwrite(arg1, p, arg3, target_arg64(arg4, arg5)));
unlock_user(p, arg2, 0);
return ret;
}
/* writev(2) */
static abi_long do_bsd_writev(abi_long arg1, abi_long arg2, abi_long arg3)
{
abi_long ret;
struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
if (vec != NULL) {
ret = get_errno(safe_writev(arg1, vec, arg3));
unlock_iovec(vec, arg2, arg3, 0);
} else {
ret = -host_to_target_errno(errno);
}
return ret;
}
/* pwritev(2) */
static abi_long do_bsd_pwritev(void *cpu_env, abi_long arg1,
abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
{
abi_long ret;
struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
if (vec != NULL) {
if (regpairs_aligned(cpu_env) != 0) {
arg4 = arg5;
arg5 = arg6;
}
ret = get_errno(safe_pwritev(arg1, vec, arg3, target_arg64(arg4, arg5)));
unlock_iovec(vec, arg2, arg3, 0);
} else {
ret = -host_to_target_errno(errno);
}
return ret;
}
#endif /* BSD_FILE_H */

42
bsd-user/bsd-proc.h Normal file
View File

@ -0,0 +1,42 @@
/*
* process related system call shims and definitions
*
* Copyright (c) 2013-2014 Stacey D. Son
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef BSD_PROC_H_
#define BSD_PROC_H_
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
/* exit(2) */
static inline abi_long do_bsd_exit(void *cpu_env, abi_long arg1)
{
#ifdef TARGET_GPROF
_mcleanup();
#endif
gdb_exit(arg1);
qemu_plugin_user_exit();
_exit(arg1);
return 0;
}
#endif /* !BSD_PROC_H_ */

View File

@ -41,6 +41,22 @@
#include "user/syscall-trace.h"
#include "bsd-file.h"
#include "bsd-proc.h"
/* I/O */
safe_syscall3(ssize_t, read, int, fd, void *, buf, size_t, nbytes);
safe_syscall4(ssize_t, pread, int, fd, void *, buf, size_t, nbytes, off_t,
offset);
safe_syscall3(ssize_t, readv, int, fd, const struct iovec *, iov, int, iovcnt);
safe_syscall4(ssize_t, preadv, int, fd, const struct iovec *, iov, int, iovcnt,
off_t, offset);
safe_syscall3(ssize_t, write, int, fd, void *, buf, size_t, nbytes);
safe_syscall4(ssize_t, pwrite, int, fd, void *, buf, size_t, nbytes, off_t,
offset);
safe_syscall3(ssize_t, writev, int, fd, const struct iovec *, iov, int, iovcnt);
safe_syscall4(ssize_t, pwritev, int, fd, const struct iovec *, iov, int, iovcnt,
off_t, offset);
void target_set_brk(abi_ulong new_brk)
{
@ -74,16 +90,209 @@ bool is_error(abi_long ret)
}
/*
* do_syscall() should always have a single exit point at the end so that
* actions, such as logging of syscall results, can be performed. All errnos
* that do_syscall() returns must be -TARGET_<errcode>.
* Unlocks a iovec. Unlike unlock_iovec, it assumes the tvec array itself is
* already locked from target_addr. It will be unlocked as well as all the iovec
* elements.
*/
static void helper_unlock_iovec(struct target_iovec *target_vec,
abi_ulong target_addr, struct iovec *vec,
int count, int copy)
{
for (int i = 0; i < count; i++) {
abi_ulong base = tswapal(target_vec[i].iov_base);
if (vec[i].iov_base) {
unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
}
}
unlock_user(target_vec, target_addr, 0);
}
struct iovec *lock_iovec(int type, abi_ulong target_addr,
int count, int copy)
{
struct target_iovec *target_vec;
struct iovec *vec;
abi_ulong total_len, max_len;
int i;
int err = 0;
if (count == 0) {
errno = 0;
return NULL;
}
if (count < 0 || count > IOV_MAX) {
errno = EINVAL;
return NULL;
}
vec = g_try_new0(struct iovec, count);
if (vec == NULL) {
errno = ENOMEM;
return NULL;
}
target_vec = lock_user(VERIFY_READ, target_addr,
count * sizeof(struct target_iovec), 1);
if (target_vec == NULL) {
err = EFAULT;
goto fail2;
}
max_len = 0x7fffffff & MIN(TARGET_PAGE_MASK, PAGE_MASK);
total_len = 0;
for (i = 0; i < count; i++) {
abi_ulong base = tswapal(target_vec[i].iov_base);
abi_long len = tswapal(target_vec[i].iov_len);
if (len < 0) {
err = EINVAL;
goto fail;
} else if (len == 0) {
/* Zero length pointer is ignored. */
vec[i].iov_base = 0;
} else {
vec[i].iov_base = lock_user(type, base, len, copy);
/*
* If the first buffer pointer is bad, this is a fault. But
* subsequent bad buffers will result in a partial write; this is
* realized by filling the vector with null pointers and zero
* lengths.
*/
if (!vec[i].iov_base) {
if (i == 0) {
err = EFAULT;
goto fail;
} else {
/*
* Fail all the subsequent addresses, they are already
* zero'd.
*/
goto out;
}
}
if (len > max_len - total_len) {
len = max_len - total_len;
}
}
vec[i].iov_len = len;
total_len += len;
}
out:
unlock_user(target_vec, target_addr, 0);
return vec;
fail:
helper_unlock_iovec(target_vec, target_addr, vec, i, copy);
fail2:
g_free(vec);
errno = err;
return NULL;
}
void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
int count, int copy)
{
struct target_iovec *target_vec;
target_vec = lock_user(VERIFY_READ, target_addr,
count * sizeof(struct target_iovec), 1);
if (target_vec) {
helper_unlock_iovec(target_vec, target_addr, vec, count, copy);
}
g_free(vec);
}
/*
* All errnos that freebsd_syscall() returns must be -TARGET_<errcode>.
*/
static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1,
abi_long arg2, abi_long arg3, abi_long arg4,
abi_long arg5, abi_long arg6, abi_long arg7,
abi_long arg8)
{
abi_long ret;
switch (num) {
/*
* process system calls
*/
case TARGET_FREEBSD_NR_exit: /* exit(2) */
ret = do_bsd_exit(cpu_env, arg1);
break;
/*
* File system calls.
*/
case TARGET_FREEBSD_NR_read: /* read(2) */
ret = do_bsd_read(arg1, arg2, arg3);
break;
case TARGET_FREEBSD_NR_pread: /* pread(2) */
ret = do_bsd_pread(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
break;
case TARGET_FREEBSD_NR_readv: /* readv(2) */
ret = do_bsd_readv(arg1, arg2, arg3);
break;
case TARGET_FREEBSD_NR_preadv: /* preadv(2) */
ret = do_bsd_preadv(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
case TARGET_FREEBSD_NR_write: /* write(2) */
ret = do_bsd_write(arg1, arg2, arg3);
break;
case TARGET_FREEBSD_NR_pwrite: /* pwrite(2) */
ret = do_bsd_pwrite(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
break;
case TARGET_FREEBSD_NR_writev: /* writev(2) */
ret = do_bsd_writev(arg1, arg2, arg3);
break;
case TARGET_FREEBSD_NR_pwritev: /* pwritev(2) */
ret = do_bsd_pwritev(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
break;
default:
qemu_log_mask(LOG_UNIMP, "Unsupported syscall: %d\n", num);
ret = -TARGET_ENOSYS;
break;
}
return ret;
}
/*
* do_freebsd_syscall() should always have a single exit point at the end so
* that actions, such as logging of syscall results, can be performed. This
* as a wrapper around freebsd_syscall() so that actually happens. Since
* that is a singleton, modern compilers will inline it anyway...
*/
abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
abi_long arg2, abi_long arg3, abi_long arg4,
abi_long arg5, abi_long arg6, abi_long arg7,
abi_long arg8)
{
return 0;
CPUState *cpu = env_cpu(cpu_env);
int ret;
trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
if (do_strace) {
print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
}
ret = freebsd_syscall(cpu_env, num, arg1, arg2, arg3, arg4, arg5, arg6,
arg7, arg8);
if (do_strace) {
print_freebsd_syscall_ret(num, ret);
}
trace_guest_user_syscall_ret(cpu, num, ret);
return ret;
}
void syscall_init(void)

22
configure vendored
View File

@ -315,6 +315,7 @@ meson_args=""
ninja=""
bindir="bin"
skip_meson=no
vfio_user_server="disabled"
# The following Meson options are handled manually (still they
# are included in the automatically generated help message)
@ -911,6 +912,10 @@ for opt do
;;
--disable-blobs) meson_option_parse --disable-install-blobs ""
;;
--enable-vfio-user-server) vfio_user_server="enabled"
;;
--disable-vfio-user-server) vfio_user_server="disabled"
;;
--enable-tcmalloc) meson_option_parse --enable-malloc=tcmalloc tcmalloc
;;
--enable-jemalloc) meson_option_parse --enable-malloc=jemalloc jemalloc
@ -2041,7 +2046,6 @@ probe_target_compiler() {
container_cross_prefix=x86_64-linux-gnu-
;;
xtensa*)
# FIXME: xtensa-linux-user?
container_hosts=x86_64
container_image=debian-xtensa-cross
@ -2150,6 +2154,17 @@ write_container_target_makefile() {
##########################################
# check for vfio_user_server
case "$vfio_user_server" in
enabled )
if test "$git_submodules_action" != "ignore"; then
git_submodules="${git_submodules} subprojects/libvfio-user"
fi
;;
esac
##########################################
# End of CC checks
# After here, no more $cc or $ld runs
@ -2505,6 +2520,10 @@ for target in $target_list; do
echo "# Automatically generated by configure - do not modify" > $config_target_mak
echo "TARGET_NAME=$arch" >> $config_target_mak
case $target in
xtensa*-linux-user)
# the toolchain is not complete with headers, only build softmmu tests
continue
;;
*-softmmu)
test -f $source_path/tests/tcg/$arch/Makefile.softmmu-target || continue
qemu="qemu-system-$arch"
@ -2693,6 +2712,7 @@ if test "$skip_meson" = no; then
test "$slirp" != auto && meson_option_add "-Dslirp=$slirp"
test "$smbd" != '' && meson_option_add "-Dsmbd=$smbd"
test "$tcg" != enabled && meson_option_add "-Dtcg=$tcg"
test "$vfio_user_server" != auto && meson_option_add "-Dvfio_user_server=$vfio_user_server"
run_meson() {
NINJA=$ninja $meson setup --prefix "$prefix" "$@" $cross_arg "$PWD" "$source_path"
}

View File

@ -213,17 +213,6 @@ MIPS ``Trap-and-Emul`` KVM support (since 6.0)
The MIPS ``Trap-and-Emul`` KVM host and guest support has been removed
from Linux upstream kernel, declare it deprecated.
System emulator CPUS
--------------------
MIPS ``I7200`` CPU Model (since 5.2)
''''''''''''''''''''''''''''''''''''
The ``I7200`` guest CPU relies on the nanoMIPS ISA, which is deprecated
(the ISA has never been upstreamed to a compiler toolchain). Therefore
this CPU is also deprecated.
QEMU API (QAPI) events
----------------------
@ -337,16 +326,6 @@ The above, converted to the current supported format::
json:{"file.driver":"rbd", "file.pool":"rbd", "file.image":"name"}
linux-user mode CPUs
--------------------
MIPS ``I7200`` CPU (since 5.2)
''''''''''''''''''''''''''''''
The ``I7200`` guest CPU relies on the nanoMIPS ISA, which is deprecated
(the ISA has never been upstreamed to a compiler toolchain). Therefore
this CPU is also deprecated.
Backwards compatibility
-----------------------
@ -376,15 +355,6 @@ versions, aliases will point to newer CPU model versions
depending on the machine type, so management software must
resolve CPU model aliases before starting a virtual machine.
Guest Emulator ISAs
-------------------
nanoMIPS ISA
''''''''''''
The ``nanoMIPS`` ISA has never been upstreamed to any compiler toolchain.
As it is hard to generate binaries for it, declare it deprecated.
Tools
-----

View File

@ -18,9 +18,9 @@ one-shot fix, the bare minimum we ask is that:
<http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/SubmittingPatches?id=f6f94e2ab1b33f0082ac22d71f66385a60d8157f#n297>`__
policy.) ``git commit -s`` or ``git format-patch -s`` will add one.
- All contributions to QEMU must be **sent as patches** to the
qemu-devel `mailing list <MailingLists>`__. Patch contributions
should not be posted on the bug tracker, posted on forums, or
externally hosted and linked to. (We have other mailing lists too,
qemu-devel `mailing list <https://wiki.qemu.org/Contribute/MailingLists>`__.
Patch contributions should not be posted on the bug tracker, posted on
forums, or externally hosted and linked to. (We have other mailing lists too,
but all patches must go to qemu-devel, possibly with a Cc: to another
list.) ``git send-email`` (`step-by-step setup
guide <https://git-send-email.io/>`__ and `hints and

View File

@ -92,3 +92,4 @@ Emulated Devices
devices/vhost-user.rst
devices/virtio-pmem.rst
devices/vhost-user-rng.rst
devices/canokey.rst

View File

@ -0,0 +1,168 @@
.. _canokey:
CanoKey QEMU
------------
CanoKey [1]_ is an open-source secure key with supports of
* U2F / FIDO2 with Ed25519 and HMAC-secret
* OpenPGP Card V3.4 with RSA4096, Ed25519 and more [2]_
* PIV (NIST SP 800-73-4)
* HOTP / TOTP
* NDEF
All these platform-independent features are in canokey-core [3]_.
For different platforms, CanoKey has different implementations,
including both hardware implementions and virtual cards:
* CanoKey STM32 [4]_
* CanoKey Pigeon [5]_
* (virt-card) CanoKey USB/IP
* (virt-card) CanoKey FunctionFS
In QEMU, yet another CanoKey virt-card is implemented.
CanoKey QEMU exposes itself as a USB device to the guest OS.
With the same software configuration as a hardware key,
the guest OS can use all the functionalities of a secure key as if
there was actually an hardware key plugged in.
CanoKey QEMU provides much convenience for debuging:
* libcanokey-qemu supports debuging output thus developers can
inspect what happens inside a secure key
* CanoKey QEMU supports trace event thus event
* QEMU USB stack supports pcap thus USB packet between the guest
and key can be captured and analysed
Then for developers:
* For developers on software with secure key support (e.g. FIDO2, OpenPGP),
they can see what happens inside the secure key
* For secure key developers, USB packets between guest OS and CanoKey
can be easily captured and analysed
Also since this is a virtual card, it can be easily used in CI for testing
on code coping with secure key.
Building
========
libcanokey-qemu is required to use CanoKey QEMU.
.. code-block:: shell
git clone https://github.com/canokeys/canokey-qemu
mkdir canokey-qemu/build
pushd canokey-qemu/build
If you want to install libcanokey-qemu in a different place,
add ``-DCMAKE_INSTALL_PREFIX=/path/to/your/place`` to cmake below.
.. code-block:: shell
cmake ..
make
make install # may need sudo
popd
Then configuring and building:
.. code-block:: shell
# depending on your env, lib/pkgconfig can be lib64/pkgconfig
export PKG_CONFIG_PATH=/path/to/your/place/lib/pkgconfig:$PKG_CONFIG_PATH
./configure --enable-canokey && make
Using CanoKey QEMU
==================
CanoKey QEMU stores all its data on a file of the host specified by the argument
when invoking qemu.
.. parsed-literal::
|qemu_system| -usb -device canokey,file=$HOME/.canokey-file
Note: you should keep this file carefully as it may contain your private key!
The first time when the file is used, it is created and initialized by CanoKey,
afterwards CanoKey QEMU would just read this file.
After the guest OS boots, you can check that there is a USB device.
For example, If the guest OS is an Linux machine. You may invoke lsusb
and find CanoKey QEMU there:
.. code-block:: shell
$ lsusb
Bus 001 Device 002: ID 20a0:42d4 Clay Logic CanoKey QEMU
You may setup the key as guided in [6]_. The console for the key is at [7]_.
Debuging
========
CanoKey QEMU consists of two parts, ``libcanokey-qemu.so`` and ``canokey.c``,
the latter of which resides in QEMU. The former provides core functionality
of a secure key while the latter provides platform-dependent functions:
USB packet handling.
If you want to trace what happens inside the secure key, when compiling
libcanokey-qemu, you should add ``-DQEMU_DEBUG_OUTPUT=ON`` in cmake command
line:
.. code-block:: shell
cmake .. -DQEMU_DEBUG_OUTPUT=ON
If you want to trace events happened in canokey.c, use
.. parsed-literal::
|qemu_system| --trace "canokey_*" \\
-usb -device canokey,file=$HOME/.canokey-file
If you want to capture USB packets between the guest and the host, you can:
.. parsed-literal::
|qemu_system| -usb -device canokey,file=$HOME/.canokey-file,pcap=key.pcap
Limitations
===========
Currently libcanokey-qemu.so has dozens of global variables as it was originally
designed for embedded systems. Thus one qemu instance can not have
multiple CanoKey QEMU running, namely you can not
.. parsed-literal::
|qemu_system| -usb -device canokey,file=$HOME/.canokey-file \\
-device canokey,file=$HOME/.canokey-file2
Also, there is no lock on canokey-file, thus two CanoKey QEMU instance
can not read one canokey-file at the same time.
Another limitation is that this device is not compatible with ``qemu-xhci``,
in that this device would hang when there are FIDO2 packets (traffic on
interrupt endpoints). If you do not use FIDO2 then it works as intended,
but for full functionality you should use old uhci/ehci bus and attach canokey
to it, for example
.. parsed-literal::
|qemu_system| -device piix3-usb-uhci,id=uhci -device canokey,bus=uhci.0
References
==========
.. [1] `<https://canokeys.org>`_
.. [2] `<https://docs.canokeys.org/userguide/openpgp/#supported-algorithm>`_
.. [3] `<https://github.com/canokeys/canokey-core>`_
.. [4] `<https://github.com/canokeys/canokey-stm32>`_
.. [5] `<https://github.com/canokeys/canokey-pigeon>`_
.. [6] `<https://docs.canokeys.org/>`_
.. [7] `<https://console.canokeys.org/>`_

View File

@ -251,7 +251,7 @@ A very simple setup with just one directly attached CXL Type 3 device::
-device pxb-cxl,bus_nr=12,bus=pcie.0,id=cxl.1 \
-device cxl-rp,port=0,bus=cxl.1,id=root_port13,chassis=0,slot=2 \
-device cxl-type3,bus=root_port13,memdev=cxl-mem1,lsa=cxl-lsa1,id=cxl-pmem0 \
-cxl-fixed-memory-window targets.0=cxl.1,size=4G
-M cxl-fmw.0.targets.0=cxl.1,cxl-fmw.0.size=4G
A setup suitable for 4 way interleave. Only one fixed window provided, to enable 2 way
interleave across 2 CXL host bridges. Each host bridge has 2 CXL Root Ports, with
@ -277,7 +277,7 @@ the CXL Type3 device directly attached (no switches).::
-device cxl-type3,bus=root_port15,memdev=cxl-mem3,lsa=cxl-lsa3,id=cxl-pmem2 \
-device cxl-rp,port=1,bus=cxl.2,id=root_port16,chassis=0,slot=6 \
-device cxl-type3,bus=root_port16,memdev=cxl-mem4,lsa=cxl-lsa4,id=cxl-pmem3 \
-cxl-fixed-memory-window targets.0=cxl.1,targets.1=cxl.2,size=4G,interleave-granularity=8k
-M cxl-fmw.0.targets.0=cxl.1,cxl-fmw.0.targets.1=cxl.2,cxl-fmw.0.size=4G,cxl-fmw.0.interleave-granularity=8k
Kernel Configuration Options
----------------------------

View File

@ -199,6 +199,10 @@ option or the ``device_add`` monitor command. Available devices are:
``u2f-{emulated,passthru}``
Universal Second Factor device
``canokey``
An Open-source Secure Key implementing FIDO2, OpenPGP, PIV and more.
For more information, see :ref:`canokey`.
Physical port addressing
^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -443,6 +443,15 @@ static int get_char(void)
}
#endif
/*
* Return true if there is a GDB currently connected to the stub
* and attached to a CPU
*/
static bool gdb_attached(void)
{
return gdbserver_state.init && gdbserver_state.c_cpu;
}
static enum {
GDB_SYS_UNKNOWN,
GDB_SYS_ENABLED,
@ -464,8 +473,7 @@ int use_gdb_syscalls(void)
/* -semihosting-config target=auto */
/* On the first call check if gdb is connected and remember. */
if (gdb_syscall_mode == GDB_SYS_UNKNOWN) {
gdb_syscall_mode = gdbserver_state.init ?
GDB_SYS_ENABLED : GDB_SYS_DISABLED;
gdb_syscall_mode = gdb_attached() ? GDB_SYS_ENABLED : GDB_SYS_DISABLED;
}
return gdb_syscall_mode == GDB_SYS_ENABLED;
}
@ -2950,7 +2958,7 @@ void gdb_do_syscallv(gdb_syscall_complete_cb cb, const char *fmt, va_list va)
target_ulong addr;
uint64_t i64;
if (!gdbserver_state.init) {
if (!gdb_attached()) {
return;
}

View File

@ -1,5 +1,6 @@
#include "qemu/osdep.h"
#include "hw/acpi/acpi_dev_interface.h"
#include "hw/acpi/acpi_aml_interface.h"
#include "qemu/module.h"
void acpi_send_event(DeviceState *dev, AcpiEventStatusBits event)
@ -18,8 +19,15 @@ static void register_types(void)
.parent = TYPE_INTERFACE,
.class_size = sizeof(AcpiDeviceIfClass),
};
static const TypeInfo acpi_dev_aml_if_info = {
.name = TYPE_ACPI_DEV_AML_IF,
.parent = TYPE_INTERFACE,
.class_size = sizeof(AcpiDevAmlIfClass),
};
type_register_static(&acpi_dev_if_info);
type_register_static(&acpi_dev_aml_if_info);
}
type_init(register_types)

View File

@ -65,9 +65,8 @@ static void cedt_build_chbs(GArray *table_data, PXBDev *cxl)
* Interleave ways encoding in CXL 2.0 ECN: 3, 6, 12 and 16-way memory
* interleaving.
*/
static void cedt_build_cfmws(GArray *table_data, MachineState *ms)
static void cedt_build_cfmws(GArray *table_data, CXLState *cxls)
{
CXLState *cxls = ms->cxl_devices_state;
GList *it;
for (it = cxls->fixed_windows; it; it = it->next) {
@ -129,9 +128,9 @@ static int cxl_foreach_pxb_hb(Object *obj, void *opaque)
return 0;
}
void cxl_build_cedt(MachineState *ms, GArray *table_offsets, GArray *table_data,
void cxl_build_cedt(GArray *table_offsets, GArray *table_data,
BIOSLinker *linker, const char *oem_id,
const char *oem_table_id)
const char *oem_table_id, CXLState *cxl_state)
{
Aml *cedt;
AcpiTable table = { .sig = "CEDT", .rev = 1, .oem_id = oem_id,
@ -144,7 +143,7 @@ void cxl_build_cedt(MachineState *ms, GArray *table_offsets, GArray *table_data,
/* reserve space for CEDT header */
object_child_foreach_recursive(object_get_root(), cxl_foreach_pxb_hb, cedt);
cedt_build_cfmws(cedt->buf, ms);
cedt_build_cfmws(cedt->buf, cxl_state);
/* copy AML table into ACPI tables blob and patch header there */
g_array_append_vals(table_data, cedt->buf->data, cedt->buf->len);

View File

@ -10,6 +10,6 @@
#include "qemu/osdep.h"
#include "hw/acpi/ipmi.h"
void build_acpi_ipmi_devices(Aml *table, BusState *bus, const char *resource)
void build_ipmi_dev_aml(AcpiDevAmlIf *adev, Aml *scope)
{
}

View File

@ -13,7 +13,7 @@
#include "hw/acpi/acpi.h"
#include "hw/acpi/ipmi.h"
static Aml *aml_ipmi_crs(IPMIFwInfo *info, const char *resource)
static Aml *aml_ipmi_crs(IPMIFwInfo *info)
{
Aml *crs = aml_resource_template();
@ -49,7 +49,7 @@ static Aml *aml_ipmi_crs(IPMIFwInfo *info, const char *resource)
break;
case IPMI_MEMSPACE_SMBUS:
aml_append(crs, aml_i2c_serial_bus_device(info->base_address,
resource));
"^"));
break;
default:
abort();
@ -62,46 +62,27 @@ static Aml *aml_ipmi_crs(IPMIFwInfo *info, const char *resource)
return crs;
}
static Aml *aml_ipmi_device(IPMIFwInfo *info, const char *resource)
void build_ipmi_dev_aml(AcpiDevAmlIf *adev, Aml *scope)
{
Aml *dev;
uint16_t version = ((info->ipmi_spec_major_revision << 8)
| (info->ipmi_spec_minor_revision << 4));
IPMIFwInfo info = {};
IPMIInterface *ii = IPMI_INTERFACE(adev);
IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
uint16_t version;
assert(info->ipmi_spec_minor_revision <= 15);
iic->get_fwinfo(ii, &info);
assert(info.ipmi_spec_minor_revision <= 15);
version = ((info.ipmi_spec_major_revision << 8)
| (info.ipmi_spec_minor_revision << 4));
dev = aml_device("MI%d", info->uuid);
dev = aml_device("MI%d", info.uuid);
aml_append(dev, aml_name_decl("_HID", aml_eisaid("IPI0001")));
aml_append(dev, aml_name_decl("_STR", aml_string("ipmi_%s",
info->interface_name)));
aml_append(dev, aml_name_decl("_UID", aml_int(info->uuid)));
aml_append(dev, aml_name_decl("_CRS", aml_ipmi_crs(info, resource)));
aml_append(dev, aml_name_decl("_IFT", aml_int(info->interface_type)));
info.interface_name)));
aml_append(dev, aml_name_decl("_UID", aml_int(info.uuid)));
aml_append(dev, aml_name_decl("_CRS", aml_ipmi_crs(&info)));
aml_append(dev, aml_name_decl("_IFT", aml_int(info.interface_type)));
aml_append(dev, aml_name_decl("_SRV", aml_int(version)));
return dev;
}
void build_acpi_ipmi_devices(Aml *scope, BusState *bus, const char *resource)
{
BusChild *kid;
QTAILQ_FOREACH(kid, &bus->children, sibling) {
IPMIInterface *ii;
IPMIInterfaceClass *iic;
IPMIFwInfo info;
Object *obj = object_dynamic_cast(OBJECT(kid->child),
TYPE_IPMI_INTERFACE);
if (!obj) {
continue;
}
ii = IPMI_INTERFACE(obj);
iic = IPMI_INTERFACE_GET_CLASS(obj);
memset(&info, 0, sizeof(info));
iic->get_fwinfo(ii, &info);
aml_append(scope, aml_ipmi_device(&info, resource));
}
aml_append(scope, dev);
}

View File

@ -29,7 +29,7 @@ acpi_ss.add(when: 'CONFIG_PC', if_false: files('acpi-x86-stub.c'))
if have_tpm
acpi_ss.add(files('tpm.c'))
endif
softmmu_ss.add(when: 'CONFIG_ACPI', if_false: files('acpi-stub.c', 'aml-build-stub.c', 'ghes-stub.c'))
softmmu_ss.add(when: 'CONFIG_ACPI', if_false: files('acpi-stub.c', 'aml-build-stub.c', 'ghes-stub.c', 'acpi_interface.c'))
softmmu_ss.add_all(when: 'CONFIG_ACPI', if_true: acpi_ss)
softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('acpi-stub.c', 'aml-build-stub.c',
'acpi-x86-stub.c', 'ipmi-stub.c', 'ghes-stub.c',

View File

@ -28,6 +28,8 @@
#include "hw/pci/pci.h"
#include "hw/qdev-properties.h"
#include "hw/acpi/acpi.h"
#include "hw/acpi/pcihp.h"
#include "hw/acpi/piix4.h"
#include "sysemu/runstate.h"
#include "sysemu/sysemu.h"
#include "sysemu/xen.h"
@ -56,47 +58,6 @@ struct pci_status {
uint32_t down;
};
struct PIIX4PMState {
/*< private >*/
PCIDevice parent_obj;
/*< public >*/
MemoryRegion io;
uint32_t io_base;
MemoryRegion io_gpe;
ACPIREGS ar;
APMState apm;
PMSMBus smb;
uint32_t smb_io_base;
qemu_irq irq;
qemu_irq smi_irq;
int smm_enabled;
bool smm_compat;
Notifier machine_ready;
Notifier powerdown_notifier;
AcpiPciHpState acpi_pci_hotplug;
bool use_acpi_hotplug_bridge;
bool use_acpi_root_pci_hotplug;
bool not_migrate_acpi_index;
uint8_t disable_s3;
uint8_t disable_s4;
uint8_t s4_val;
bool cpu_hotplug_legacy;
AcpiCpuHotplug gpe_cpu;
CPUHotplugState cpuhp_state;
MemHotplugState acpi_memory_hotplug;
};
OBJECT_DECLARE_SIMPLE_TYPE(PIIX4PMState, PIIX4_PM)
static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
PCIBus *bus, PIIX4PMState *s);
@ -525,6 +486,10 @@ static void piix4_pm_realize(PCIDevice *dev, Error **errp)
s->machine_ready.notify = piix4_pm_machine_ready;
qemu_add_machine_init_done_notifier(&s->machine_ready);
if (xen_enabled()) {
s->use_acpi_hotplug_bridge = false;
}
piix4_acpi_system_hot_add_init(pci_address_space_io(dev),
pci_get_bus(dev), s);
qbus_set_hotplug_handler(BUS(pci_get_bus(dev)), OBJECT(s));
@ -532,32 +497,12 @@ static void piix4_pm_realize(PCIDevice *dev, Error **errp)
piix4_pm_add_properties(s);
}
I2CBus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
qemu_irq sci_irq, qemu_irq smi_irq,
int smm_enabled, DeviceState **piix4_pm)
static void piix4_pm_init(Object *obj)
{
PCIDevice *pci_dev;
DeviceState *dev;
PIIX4PMState *s;
PIIX4PMState *s = PIIX4_PM(obj);
pci_dev = pci_new(devfn, TYPE_PIIX4_PM);
dev = DEVICE(pci_dev);
qdev_prop_set_uint32(dev, "smb_io_base", smb_io_base);
if (piix4_pm) {
*piix4_pm = dev;
}
s = PIIX4_PM(dev);
s->irq = sci_irq;
s->smi_irq = smi_irq;
s->smm_enabled = smm_enabled;
if (xen_enabled()) {
s->use_acpi_hotplug_bridge = false;
}
pci_realize_and_unref(pci_dev, bus, &error_fatal);
return s->smb.smbus;
qdev_init_gpio_out(DEVICE(obj), &s->irq, 1);
qdev_init_gpio_out_named(DEVICE(obj), &s->smi_irq, "smi-irq", 1);
}
static uint64_t gpe_readb(void *opaque, hwaddr addr, unsigned width)
@ -663,6 +608,7 @@ static Property piix4_pm_properties[] = {
DEFINE_PROP_BOOL("memory-hotplug-support", PIIX4PMState,
acpi_memory_hotplug.is_enabled, true),
DEFINE_PROP_BOOL("smm-compat", PIIX4PMState, smm_compat, false),
DEFINE_PROP_BOOL("smm-enabled", PIIX4PMState, smm_enabled, false),
DEFINE_PROP_BOOL("x-not-migrate-acpi-index", PIIX4PMState,
not_migrate_acpi_index, false),
DEFINE_PROP_END_OF_LIST(),
@ -703,6 +649,7 @@ static void piix4_pm_class_init(ObjectClass *klass, void *data)
static const TypeInfo piix4_pm_info = {
.name = TYPE_PIIX4_PM,
.parent = TYPE_PCI_DEVICE,
.instance_init = piix4_pm_init,
.instance_size = sizeof(PIIX4PMState),
.class_init = piix4_pm_class_init,
.interfaces = (InterfaceInfo[]) {

View File

@ -10,17 +10,40 @@
#include "hw/pci/pci.h"
#include "hw/pci/pci_host.h"
struct viot_pci_ranges {
GArray *blob;
size_t count;
uint16_t output_node;
struct viot_pci_host_range {
int min_bus;
int max_bus;
};
/* Build PCI range for a given PCI host bridge */
static int build_pci_range_node(Object *obj, void *opaque)
static void build_pci_host_range(GArray *table_data, int min_bus, int max_bus,
uint16_t output_node)
{
struct viot_pci_ranges *pci_ranges = opaque;
GArray *blob = pci_ranges->blob;
/* Type */
build_append_int_noprefix(table_data, 1 /* PCI range */, 1);
/* Reserved */
build_append_int_noprefix(table_data, 0, 1);
/* Length */
build_append_int_noprefix(table_data, 24, 2);
/* Endpoint start */
build_append_int_noprefix(table_data, PCI_BUILD_BDF(min_bus, 0), 4);
/* PCI Segment start */
build_append_int_noprefix(table_data, 0, 2);
/* PCI Segment end */
build_append_int_noprefix(table_data, 0, 2);
/* PCI BDF start */
build_append_int_noprefix(table_data, PCI_BUILD_BDF(min_bus, 0), 2);
/* PCI BDF end */
build_append_int_noprefix(table_data, PCI_BUILD_BDF(max_bus, 0xff), 2);
/* Output node */
build_append_int_noprefix(table_data, output_node, 2);
/* Reserved */
build_append_int_noprefix(table_data, 0, 6);
}
/* Build PCI range for a given PCI host bridge */
static int enumerate_pci_host_bridges(Object *obj, void *opaque)
{
GArray *pci_host_ranges = opaque;
if (object_dynamic_cast(obj, TYPE_PCI_HOST_BRIDGE)) {
PCIBus *bus = PCI_HOST_BRIDGE(obj)->bus;
@ -30,34 +53,31 @@ static int build_pci_range_node(Object *obj, void *opaque)
pci_bus_range(bus, &min_bus, &max_bus);
/* Type */
build_append_int_noprefix(blob, 1 /* PCI range */, 1);
/* Reserved */
build_append_int_noprefix(blob, 0, 1);
/* Length */
build_append_int_noprefix(blob, 24, 2);
/* Endpoint start */
build_append_int_noprefix(blob, PCI_BUILD_BDF(min_bus, 0), 4);
/* PCI Segment start */
build_append_int_noprefix(blob, 0, 2);
/* PCI Segment end */
build_append_int_noprefix(blob, 0, 2);
/* PCI BDF start */
build_append_int_noprefix(blob, PCI_BUILD_BDF(min_bus, 0), 2);
/* PCI BDF end */
build_append_int_noprefix(blob, PCI_BUILD_BDF(max_bus, 0xff), 2);
/* Output node */
build_append_int_noprefix(blob, pci_ranges->output_node, 2);
/* Reserved */
build_append_int_noprefix(blob, 0, 6);
pci_ranges->count++;
const struct viot_pci_host_range pci_host_range = {
.min_bus = min_bus,
.max_bus = max_bus,
};
g_array_append_val(pci_host_ranges, pci_host_range);
}
}
return 0;
}
static gint pci_host_range_compare(gconstpointer a, gconstpointer b)
{
struct viot_pci_host_range *range_a = (struct viot_pci_host_range *)a;
struct viot_pci_host_range *range_b = (struct viot_pci_host_range *)b;
if (range_a->min_bus < range_b->min_bus) {
return -1;
} else if (range_a->min_bus > range_b->min_bus) {
return 1;
} else {
return 0;
}
}
/*
* Generate a VIOT table with one PCI-based virtio-iommu that manages PCI
* endpoints.
@ -72,19 +92,22 @@ void build_viot(MachineState *ms, GArray *table_data, BIOSLinker *linker,
int viommu_off = 48;
AcpiTable table = { .sig = "VIOT", .rev = 0,
.oem_id = oem_id, .oem_table_id = oem_table_id };
struct viot_pci_ranges pci_ranges = {
.output_node = viommu_off,
.blob = g_array_new(false, true /* clear */, 1),
};
GArray *pci_host_ranges = g_array_new(false, true,
sizeof(struct viot_pci_host_range));
struct viot_pci_host_range *pci_host_range;
int i;
/* Build the list of PCI ranges that this viommu manages */
object_child_foreach_recursive(OBJECT(ms), build_pci_range_node,
&pci_ranges);
object_child_foreach_recursive(OBJECT(ms), enumerate_pci_host_bridges,
pci_host_ranges);
/* Sort the pci host ranges by min_bus */
g_array_sort(pci_host_ranges, pci_host_range_compare);
/* ACPI table header */
acpi_table_begin(&table, table_data);
/* Node count */
build_append_int_noprefix(table_data, pci_ranges.count + 1, 2);
build_append_int_noprefix(table_data, pci_host_ranges->len + 1, 2);
/* Node offset */
build_append_int_noprefix(table_data, viommu_off, 2);
/* Reserved */
@ -105,9 +128,15 @@ void build_viot(MachineState *ms, GArray *table_data, BIOSLinker *linker,
build_append_int_noprefix(table_data, 0, 8);
/* PCI ranges found above */
g_array_append_vals(table_data, pci_ranges.blob->data,
pci_ranges.blob->len);
g_array_free(pci_ranges.blob, true);
for (i = 0; i < pci_host_ranges->len; i++) {
pci_host_range = &g_array_index(pci_host_ranges,
struct viot_pci_host_range, i);
build_pci_host_range(table_data, pci_host_range->min_bus,
pci_host_range->max_bus, viommu_off);
}
g_array_free(pci_host_ranges, true);
acpi_table_end(linker, &table);
}

View File

@ -84,7 +84,7 @@ struct CSState {
int transferred;
int aci_counter;
SWVoiceOut *voice;
int16_t *tab;
const int16_t *tab;
};
#define MODE2 (1 << 6)
@ -142,13 +142,13 @@ enum {
Capture_Lower_Base_Count
};
static int freqs[2][8] = {
static const int freqs[2][8] = {
{ 8000, 16000, 27420, 32000, -1, -1, 48000, 9000 },
{ 5510, 11025, 18900, 22050, 37800, 44100, 33075, 6620 }
};
/* Tables courtesy http://hazelware.luggle.com/tutorials/mulawcompression.html */
static int16_t MuLawDecompressTable[256] =
static const int16_t MuLawDecompressTable[256] =
{
-32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
-23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
@ -184,7 +184,7 @@ static int16_t MuLawDecompressTable[256] =
56, 48, 40, 32, 24, 16, 8, 0
};
static int16_t ALawDecompressTable[256] =
static const int16_t ALawDecompressTable[256] =
{
-5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
-7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,

View File

@ -32,7 +32,7 @@
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "qemu/timer.h"
#include "hw/acpi/aml-build.h"
#include "hw/acpi/acpi_aml_interface.h"
#include "hw/irq.h"
#include "hw/isa/isa.h"
#include "hw/qdev-properties.h"
@ -214,9 +214,9 @@ int cmos_get_fd_drive_type(FloppyDriveType fd0)
return val;
}
static void fdc_isa_build_aml(ISADevice *isadev, Aml *scope)
static void build_fdc_aml(AcpiDevAmlIf *adev, Aml *scope)
{
FDCtrlISABus *isa = ISA_FDC(isadev);
FDCtrlISABus *isa = ISA_FDC(adev);
Aml *dev;
Aml *crs;
int i;
@ -241,7 +241,7 @@ static void fdc_isa_build_aml(ISADevice *isadev, Aml *scope)
aml_append(dev, aml_name_decl("_CRS", crs));
for (i = 0; i < MIN(MAX_FD, ACPI_FDE_MAX_FD); i++) {
FloppyDriveType type = isa_fdc_get_drive_type(isadev, i);
FloppyDriveType type = isa_fdc_get_drive_type(ISA_DEVICE(adev), i);
if (type < FLOPPY_DRIVE_TYPE_NONE) {
fde_buf[i] = cpu_to_le32(1); /* drive present */
@ -283,14 +283,14 @@ static Property isa_fdc_properties[] = {
static void isabus_fdc_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ISADeviceClass *isa = ISA_DEVICE_CLASS(klass);
AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
dc->desc = "virtual floppy controller";
dc->realize = isabus_fdc_realize;
dc->fw_name = "fdc";
dc->reset = fdctrl_external_reset_isa;
dc->vmsd = &vmstate_isa_fdc;
isa->build_aml = fdc_isa_build_aml;
adevc->build_dev_aml = build_fdc_aml;
device_class_set_props(dc, isa_fdc_properties);
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
}
@ -313,6 +313,10 @@ static const TypeInfo isa_fdc_info = {
.instance_size = sizeof(FDCtrlISABus),
.class_init = isabus_fdc_class_init,
.instance_init = isabus_fdc_instance_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_ACPI_DEV_AML_IF },
{ },
},
};
static void isa_fdc_register_types(void)

View File

@ -94,18 +94,14 @@ static void fdctrl_handle_tc(void *opaque, int irq, int level)
trace_fdctrl_tc_pulse(level);
}
void fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
hwaddr mmio_base, DriveInfo **fds)
void fdctrl_init_sysbus(qemu_irq irq, hwaddr mmio_base, DriveInfo **fds)
{
FDCtrl *fdctrl;
DeviceState *dev;
SysBusDevice *sbd;
FDCtrlSysBus *sys;
dev = qdev_new("sysbus-fdc");
sys = SYSBUS_FDC(dev);
fdctrl = &sys->state;
fdctrl->dma_chann = dma_chann; /* FIXME */
sbd = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(sbd, &error_fatal);
sysbus_connect_irq(sbd, 0, irq);
@ -138,6 +134,16 @@ static void sysbus_fdc_common_instance_init(Object *obj)
FDCtrlSysBus *sys = SYSBUS_FDC(obj);
FDCtrl *fdctrl = &sys->state;
/*
* DMA is not currently supported for sysbus floppy controllers.
* If we wanted to add support then probably the best approach is
* to have a QOM link property 'dma-controller' which the board
* code can set to an instance of IsaDmaClass, and an integer
* property 'dma-channel', so that we can set fdctrl->dma and
* fdctrl->dma_chann accordingly.
*/
fdctrl->dma_chann = -1;
qdev_set_legacy_instance_id(dev, 0 /* io */, 2); /* FIXME */
memory_region_init_io(&fdctrl->iomem, obj,

View File

@ -337,6 +337,7 @@ static int vhost_user_blk_connect(DeviceState *dev, Error **errp)
vhost_dev_set_config_notifier(&s->dev, &blk_ops);
s->vhost_user.supports_config = true;
ret = vhost_dev_init(&s->dev, &s->vhost_user, VHOST_BACKEND_TYPE_USER, 0,
errp);
if (ret < 0) {

View File

@ -28,7 +28,7 @@
#include "qemu/module.h"
#include "chardev/char-parallel.h"
#include "chardev/char-fe.h"
#include "hw/acpi/aml-build.h"
#include "hw/acpi/acpi_aml_interface.h"
#include "hw/irq.h"
#include "hw/isa/isa.h"
#include "hw/qdev-properties.h"
@ -570,9 +570,9 @@ static void parallel_isa_realizefn(DeviceState *dev, Error **errp)
s, "parallel");
}
static void parallel_isa_build_aml(ISADevice *isadev, Aml *scope)
static void parallel_isa_build_aml(AcpiDevAmlIf *adev, Aml *scope)
{
ISAParallelState *isa = ISA_PARALLEL(isadev);
ISAParallelState *isa = ISA_PARALLEL(adev);
Aml *dev;
Aml *crs;
@ -645,11 +645,11 @@ static Property parallel_isa_properties[] = {
static void parallel_isa_class_initfn(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ISADeviceClass *isa = ISA_DEVICE_CLASS(klass);
AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
dc->realize = parallel_isa_realizefn;
dc->vmsd = &vmstate_parallel_isa;
isa->build_aml = parallel_isa_build_aml;
adevc->build_dev_aml = parallel_isa_build_aml;
device_class_set_props(dc, parallel_isa_properties);
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
}
@ -659,6 +659,10 @@ static const TypeInfo parallel_isa_info = {
.parent = TYPE_ISA_DEVICE,
.instance_size = sizeof(ISAParallelState),
.class_init = parallel_isa_class_initfn,
.interfaces = (InterfaceInfo[]) {
{ TYPE_ACPI_DEV_AML_IF },
{ },
},
};
static void parallel_register_types(void)

View File

@ -27,7 +27,7 @@
#include "qapi/error.h"
#include "qemu/module.h"
#include "sysemu/sysemu.h"
#include "hw/acpi/aml-build.h"
#include "hw/acpi/acpi_aml_interface.h"
#include "hw/char/serial.h"
#include "hw/isa/isa.h"
#include "hw/qdev-properties.h"
@ -83,9 +83,9 @@ static void serial_isa_realizefn(DeviceState *dev, Error **errp)
isa_register_ioport(isadev, &s->io, isa->iobase);
}
static void serial_isa_build_aml(ISADevice *isadev, Aml *scope)
static void serial_isa_build_aml(AcpiDevAmlIf *adev, Aml *scope)
{
ISASerialState *isa = ISA_SERIAL(isadev);
ISASerialState *isa = ISA_SERIAL(adev);
Aml *dev;
Aml *crs;
@ -122,11 +122,11 @@ static Property serial_isa_properties[] = {
static void serial_isa_class_initfn(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ISADeviceClass *isa = ISA_DEVICE_CLASS(klass);
AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
dc->realize = serial_isa_realizefn;
dc->vmsd = &vmstate_isa_serial;
isa->build_aml = serial_isa_build_aml;
adevc->build_dev_aml = serial_isa_build_aml;
device_class_set_props(dc, serial_isa_properties);
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
}
@ -146,6 +146,10 @@ static const TypeInfo serial_isa_info = {
.instance_size = sizeof(ISASerialState),
.instance_init = serial_isa_initfn,
.class_init = serial_isa_class_initfn,
.interfaces = (InterfaceInfo[]) {
{ TYPE_ACPI_DEV_AML_IF },
{ },
},
};
static void serial_register_types(void)

View File

@ -33,7 +33,6 @@
#include "sysemu/qtest.h"
#include "hw/pci/pci.h"
#include "hw/mem/nvdimm.h"
#include "hw/cxl/cxl.h"
#include "migration/global_state.h"
#include "migration/vmstate.h"
#include "exec/confidential-guest-support.h"
@ -629,20 +628,6 @@ static void machine_set_nvdimm_persistence(Object *obj, const char *value,
nvdimms_state->persistence_string = g_strdup(value);
}
static bool machine_get_cxl(Object *obj, Error **errp)
{
MachineState *ms = MACHINE(obj);
return ms->cxl_devices_state->is_enabled;
}
static void machine_set_cxl(Object *obj, bool value, Error **errp)
{
MachineState *ms = MACHINE(obj);
ms->cxl_devices_state->is_enabled = value;
}
void machine_class_allow_dynamic_sysbus_dev(MachineClass *mc, const char *type)
{
QAPI_LIST_PREPEND(mc->allowed_dynamic_sysbus_devices, g_strdup(type));
@ -929,8 +914,6 @@ static void machine_class_init(ObjectClass *oc, void *data)
mc->default_ram_size = 128 * MiB;
mc->rom_file_has_mr = true;
/* Few machines support CXL, so default to off */
mc->cxl_supported = false;
/* numa node memory size aligned on 8MB by default.
* On Linux, each node's border has to be 8MB aligned
*/
@ -1091,16 +1074,6 @@ static void machine_initfn(Object *obj)
"Valid values are cpu, mem-ctrl");
}
if (mc->cxl_supported) {
Object *obj = OBJECT(ms);
ms->cxl_devices_state = g_new0(CXLState, 1);
object_property_add_bool(obj, "cxl", machine_get_cxl, machine_set_cxl);
object_property_set_description(obj, "cxl",
"Set on/off to enable/disable "
"CXL instantiation");
}
if (mc->cpu_index_to_instance_props && mc->get_default_cpu_node_id) {
ms->numa_state = g_new0(NumaState, 1);
object_property_add_bool(obj, "hmat",
@ -1138,7 +1111,6 @@ static void machine_finalize(Object *obj)
g_free(ms->device_memory);
g_free(ms->nvdimms_state);
g_free(ms->numa_state);
g_free(ms->cxl_devices_state);
}
bool machine_usb(MachineState *machine)

View File

@ -468,6 +468,28 @@ char *qdev_get_dev_path(DeviceState *dev)
return NULL;
}
void qdev_add_unplug_blocker(DeviceState *dev, Error *reason)
{
dev->unplug_blockers = g_slist_prepend(dev->unplug_blockers, reason);
}
void qdev_del_unplug_blocker(DeviceState *dev, Error *reason)
{
dev->unplug_blockers = g_slist_remove(dev->unplug_blockers, reason);
}
bool qdev_unplug_blocked(DeviceState *dev, Error **errp)
{
ERRP_GUARD();
if (dev->unplug_blockers) {
error_propagate(errp, error_copy(dev->unplug_blockers->data));
return true;
}
return false;
}
static bool device_get_realized(Object *obj, Error **errp)
{
DeviceState *dev = DEVICE(obj);
@ -704,6 +726,8 @@ static void device_finalize(Object *obj)
DeviceState *dev = DEVICE(obj);
g_assert(!dev->unplug_blockers);
QLIST_FOREACH_SAFE(ngl, &dev->gpios, node, next) {
QLIST_REMOVE(ngl, node);
qemu_free_irqs(ngl->in, ngl->num_in);

View File

@ -154,7 +154,8 @@ static void ras_init_common(uint32_t *reg_state, uint32_t *write_msk)
reg_state[R_CXL_RAS_ERR_CAP_CTRL] = 0x00;
}
static void hdm_init_common(uint32_t *reg_state, uint32_t *write_msk)
static void hdm_init_common(uint32_t *reg_state, uint32_t *write_msk,
enum reg_type type)
{
int decoder_count = 1;
int i;
@ -174,6 +175,14 @@ static void hdm_init_common(uint32_t *reg_state, uint32_t *write_msk)
write_msk[R_CXL_HDM_DECODER0_SIZE_LO + i * 0x20] = 0xf0000000;
write_msk[R_CXL_HDM_DECODER0_SIZE_HI + i * 0x20] = 0xffffffff;
write_msk[R_CXL_HDM_DECODER0_CTRL + i * 0x20] = 0x13ff;
if (type == CXL2_DEVICE ||
type == CXL2_TYPE3_DEVICE ||
type == CXL2_LOGICAL_DEVICE) {
write_msk[R_CXL_HDM_DECODER0_TARGET_LIST_LO + i * 0x20] = 0xf0000000;
} else {
write_msk[R_CXL_HDM_DECODER0_TARGET_LIST_LO + i * 0x20] = 0xffffffff;
}
write_msk[R_CXL_HDM_DECODER0_TARGET_LIST_HI + i * 0x20] = 0xffffffff;
}
}
@ -239,7 +248,7 @@ void cxl_component_register_init_common(uint32_t *reg_state, uint32_t *write_msk
}
init_cap_reg(HDM, 5, 1);
hdm_init_common(reg_state, write_msk);
hdm_init_common(reg_state, write_msk, type);
if (caps < 5) {
return;

View File

@ -6,11 +6,10 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "hw/cxl/cxl.h"
#include "hw/cxl/cxl_host.h"
void cxl_fixed_memory_window_config(MachineState *ms,
CXLFixedMemoryWindowOptions *object,
Error **errp) {};
void cxl_fixed_memory_window_link_targets(Error **errp) {};
void cxl_fmws_link_targets(CXLState *stat, Error **errp) {};
void cxl_machine_init(Object *obj, CXLState *state) {};
void cxl_hook_up_pxb_registers(PCIBus *bus, CXLState *state, Error **errp) {};
const MemoryRegionOps cfmws_ops;

View File

@ -15,14 +15,16 @@
#include "qapi/qapi-visit-machine.h"
#include "hw/cxl/cxl.h"
#include "hw/cxl/cxl_host.h"
#include "hw/pci/pci_bus.h"
#include "hw/pci/pci_bridge.h"
#include "hw/pci/pci_host.h"
#include "hw/pci/pcie_port.h"
#include "hw/pci-bridge/pci_expander_bridge.h"
void cxl_fixed_memory_window_config(MachineState *ms,
CXLFixedMemoryWindowOptions *object,
Error **errp)
static void cxl_fixed_memory_window_config(CXLState *cxl_state,
CXLFixedMemoryWindowOptions *object,
Error **errp)
{
CXLFixedWindow *fw = g_malloc0(sizeof(*fw));
strList *target;
@ -62,20 +64,17 @@ void cxl_fixed_memory_window_config(MachineState *ms,
fw->enc_int_gran = 0;
}
ms->cxl_devices_state->fixed_windows =
g_list_append(ms->cxl_devices_state->fixed_windows, fw);
cxl_state->fixed_windows = g_list_append(cxl_state->fixed_windows, fw);
return;
}
void cxl_fixed_memory_window_link_targets(Error **errp)
void cxl_fmws_link_targets(CXLState *cxl_state, Error **errp)
{
MachineState *ms = MACHINE(qdev_get_machine());
if (ms->cxl_devices_state && ms->cxl_devices_state->fixed_windows) {
if (cxl_state && cxl_state->fixed_windows) {
GList *it;
for (it = ms->cxl_devices_state->fixed_windows; it; it = it->next) {
for (it = cxl_state->fixed_windows; it; it = it->next) {
CXLFixedWindow *fw = it->data;
int i;
@ -220,3 +219,84 @@ const MemoryRegionOps cfmws_ops = {
.unaligned = true,
},
};
static void machine_get_cxl(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
CXLState *cxl_state = opaque;
bool value = cxl_state->is_enabled;
visit_type_bool(v, name, &value, errp);
}
static void machine_set_cxl(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
CXLState *cxl_state = opaque;
bool value;
if (!visit_type_bool(v, name, &value, errp)) {
return;
}
cxl_state->is_enabled = value;
}
static void machine_get_cfmw(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
CXLFixedMemoryWindowOptionsList **list = opaque;
visit_type_CXLFixedMemoryWindowOptionsList(v, name, list, errp);
}
static void machine_set_cfmw(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
CXLState *state = opaque;
CXLFixedMemoryWindowOptionsList *cfmw_list = NULL;
CXLFixedMemoryWindowOptionsList *it;
visit_type_CXLFixedMemoryWindowOptionsList(v, name, &cfmw_list, errp);
if (!cfmw_list) {
return;
}
for (it = cfmw_list; it; it = it->next) {
cxl_fixed_memory_window_config(state, it->value, errp);
}
state->cfmw_list = cfmw_list;
}
void cxl_machine_init(Object *obj, CXLState *state)
{
object_property_add(obj, "cxl", "bool", machine_get_cxl,
machine_set_cxl, NULL, state);
object_property_set_description(obj, "cxl",
"Set on/off to enable/disable "
"CXL instantiation");
object_property_add(obj, "cxl-fmw", "CXLFixedMemoryWindow",
machine_get_cfmw, machine_set_cfmw,
NULL, state);
object_property_set_description(obj, "cxl-fmw",
"CXL Fixed Memory Windows (array)");
}
void cxl_hook_up_pxb_registers(PCIBus *bus, CXLState *state, Error **errp)
{
/* Walk the pci busses looking for pxb busses to hook up */
if (bus) {
QLIST_FOREACH(bus, &bus->child, sibling) {
if (!pci_bus_is_root(bus)) {
continue;
}
if (pci_bus_is_cxl(bus)) {
if (!state->is_enabled) {
error_setg(errp, "CXL host bridges present, but cxl=off");
return;
}
pxb_cxl_hook_up_registers(state, bus, errp);
}
}
}
}

View File

@ -69,16 +69,17 @@ static void virtio_gpu_notify_event(VirtIOGPUBase *g, uint32_t event_type)
virtio_notify_config(&g->parent_obj);
}
static int virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info)
static void virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info)
{
VirtIOGPUBase *g = opaque;
if (idx >= g->conf.max_outputs) {
return -1;
return;
}
g->req_state[idx].x = info->xoff;
g->req_state[idx].y = info->yoff;
g->req_state[idx].refresh_rate = info->refresh_rate;
g->req_state[idx].width = info->width;
g->req_state[idx].height = info->height;
g->req_state[idx].width_mm = info->width_mm;
@ -92,7 +93,7 @@ static int virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info)
/* send event to guest */
virtio_gpu_notify_event(g, VIRTIO_GPU_EVENT_DISPLAY);
return 0;
return;
}
static void

View File

@ -217,6 +217,7 @@ virtio_gpu_generate_edid(VirtIOGPU *g, int scanout,
.height_mm = b->req_state[scanout].height_mm,
.prefx = b->req_state[scanout].width,
.prefy = b->req_state[scanout].height,
.refresh_rate = b->req_state[scanout].refresh_rate,
};
edid->size = cpu_to_le32(sizeof(edid->edid));
@ -514,6 +515,9 @@ static void virtio_gpu_resource_flush(VirtIOGPU *g,
for (i = 0; i < g->parent_obj.conf.max_outputs; i++) {
scanout = &g->parent_obj.scanout[i];
if (scanout->resource_id == res->resource_id &&
rf.r.x >= scanout->x && rf.r.y >= scanout->y &&
rf.r.x + rf.r.width <= scanout->x + scanout->width &&
rf.r.y + rf.r.height <= scanout->y + scanout->height &&
console_has_gl(scanout->con)) {
dpy_gl_update(scanout->con, 0, 0, scanout->width,
scanout->height);

View File

@ -47,15 +47,14 @@ static void virtio_vga_base_text_update(void *opaque, console_ch_t *chardata)
}
}
static int virtio_vga_base_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info)
static void virtio_vga_base_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info)
{
VirtIOVGABase *vvga = opaque;
VirtIOGPUBase *g = vvga->vgpu;
if (g->hw_ops->ui_info) {
return g->hw_ops->ui_info(g, idx, info);
g->hw_ops->ui_info(g, idx, info);
}
return -1;
}
static void virtio_vga_base_gl_block(void *opaque, bool block)

View File

@ -777,16 +777,24 @@ static void xenfb_update(void *opaque)
xenfb->up_fullscreen = 0;
}
static void xenfb_update_interval(void *opaque, uint64_t interval)
static void xenfb_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info)
{
struct XenFB *xenfb = opaque;
uint32_t refresh_rate;
if (xenfb->feature_update) {
#ifdef XENFB_TYPE_REFRESH_PERIOD
if (xenfb_queue_full(xenfb)) {
return;
}
xenfb_send_refresh_period(xenfb, interval);
refresh_rate = info->refresh_rate;
if (!refresh_rate) {
refresh_rate = 75;
}
/* T = 1 / f = 1 [s*Hz] / f = 1000*1000 [ms*mHz] / f */
xenfb_send_refresh_period(xenfb, 1000 * 1000 / refresh_rate);
#endif
}
}
@ -983,5 +991,5 @@ struct XenDevOps xen_framebuffer_ops = {
static const GraphicHwOps xenfb_ops = {
.invalidate = xenfb_invalidate,
.gfx_update = xenfb_update,
.update_interval = xenfb_update_interval,
.ui_info = xenfb_ui_info,
};

View File

@ -29,6 +29,7 @@
#include "hw/i386/ich9.h"
#include "qom/object.h"
#include "hw/acpi/acpi_aml_interface.h"
OBJECT_DECLARE_SIMPLE_TYPE(ICH9SMBState, ICH9_SMB_DEVICE)
@ -94,10 +95,22 @@ static void ich9_smbus_realize(PCIDevice *d, Error **errp)
&s->smb.io);
}
static void build_ich9_smb_aml(AcpiDevAmlIf *adev, Aml *scope)
{
BusChild *kid;
ICH9SMBState *s = ICH9_SMB_DEVICE(adev);
BusState *bus = BUS(s->smb.smbus);
QTAILQ_FOREACH(kid, &bus->children, sibling) {
call_dev_aml_func(DEVICE(kid->child), scope);
}
}
static void ich9_smb_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
k->vendor_id = PCI_VENDOR_ID_INTEL;
k->device_id = PCI_DEVICE_ID_INTEL_ICH9_6;
@ -112,6 +125,7 @@ static void ich9_smb_class_init(ObjectClass *klass, void *data)
* pc_q35_init()
*/
dc->user_creatable = false;
adevc->build_dev_aml = build_ich9_smb_aml;
}
static void ich9_smb_set_irq(PMSMBus *pmsmb, bool enabled)
@ -143,6 +157,7 @@ static const TypeInfo ich9_smb_info = {
.class_init = ich9_smb_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ TYPE_ACPI_DEV_AML_IF },
{ },
},
};

View File

@ -31,21 +31,20 @@
#include "hw/cxl/cxl.h"
#include "hw/core/cpu.h"
#include "target/i386/cpu.h"
#include "hw/misc/pvpanic.h"
#include "hw/timer/hpet.h"
#include "hw/acpi/acpi-defs.h"
#include "hw/acpi/acpi.h"
#include "hw/acpi/cpu.h"
#include "hw/nvram/fw_cfg.h"
#include "hw/acpi/bios-linker-loader.h"
#include "hw/isa/isa.h"
#include "hw/acpi/acpi_aml_interface.h"
#include "hw/input/i8042.h"
#include "hw/block/fdc.h"
#include "hw/acpi/memory_hotplug.h"
#include "sysemu/tpm.h"
#include "hw/acpi/tpm.h"
#include "hw/acpi/vmgenid.h"
#include "hw/acpi/erst.h"
#include "hw/acpi/piix4.h"
#include "sysemu/tpm_backend.h"
#include "hw/rtc/mc146818rtc_regs.h"
#include "migration/vmstate.h"
@ -74,7 +73,6 @@
#include "hw/i386/intel_iommu.h"
#include "hw/virtio/virtio-iommu.h"
#include "hw/acpi/ipmi.h"
#include "hw/acpi/hmat.h"
#include "hw/acpi/viot.h"
#include "hw/acpi/cxl.h"
@ -121,8 +119,6 @@ typedef struct AcpiMiscInfo {
#endif
const unsigned char *dsdt_code;
unsigned dsdt_size;
uint16_t pvpanic_port;
uint16_t applesmc_io_base;
} AcpiMiscInfo;
typedef struct AcpiBuildPciBusHotplugState {
@ -307,8 +303,6 @@ static void acpi_get_misc_info(AcpiMiscInfo *info)
#ifdef CONFIG_TPM
info->tpm_version = tpm_get_version(tpm_find());
#endif
info->pvpanic_port = pvpanic_port();
info->applesmc_io_base = applesmc_port();
}
/*
@ -865,21 +859,6 @@ static Aml *build_vmbus_device_aml(VMBusBridge *vmbus_bridge)
return dev;
}
static void build_isa_devices_aml(Aml *table)
{
bool ambiguous;
Object *obj = object_resolve_path_type("", TYPE_ISA_BUS, &ambiguous);
Aml *scope;
assert(obj && !ambiguous);
scope = aml_scope("_SB.PCI0.ISA");
build_acpi_ipmi_devices(scope, BUS(obj), "\\_SB.PCI0.ISA");
isa_build_aml(ISA_BUS(obj), scope);
aml_append(table, scope);
}
static void build_dbg_aml(Aml *table)
{
Aml *field;
@ -1265,15 +1244,22 @@ static void build_q35_isa_bridge(Aml *table)
{
Aml *dev;
Aml *scope;
Object *obj;
bool ambiguous;
/*
* temporarily fish out isa bridge, build_q35_isa_bridge() will be dropped
* once PCI is converted to AcpiDevAmlIf and would be ble to generate
* AML for bridge itself
*/
obj = object_resolve_path_type("", TYPE_ICH9_LPC_DEVICE, &ambiguous);
assert(obj && !ambiguous);
scope = aml_scope("_SB.PCI0");
dev = aml_device("ISA");
aml_append(dev, aml_name_decl("_ADR", aml_int(0x001F0000)));
/* ICH9 PCI to ISA irq remapping */
aml_append(dev, aml_operation_region("PIRQ", AML_PCI_CONFIG,
aml_int(0x60), 0x0C));
call_dev_aml_func(DEVICE(obj), dev);
aml_append(scope, dev);
aml_append(table, scope);
}
@ -1282,15 +1268,22 @@ static void build_piix4_isa_bridge(Aml *table)
{
Aml *dev;
Aml *scope;
Object *obj;
bool ambiguous;
/*
* temporarily fish out isa bridge, build_piix4_isa_bridge() will be dropped
* once PCI is converted to AcpiDevAmlIf and would be ble to generate
* AML for bridge itself
*/
obj = object_resolve_path_type("", TYPE_PIIX3_PCI_DEVICE, &ambiguous);
assert(obj && !ambiguous);
scope = aml_scope("_SB.PCI0");
dev = aml_device("ISA");
aml_append(dev, aml_name_decl("_ADR", aml_int(0x00010000)));
/* PIIX PCI to ISA irq remapping */
aml_append(dev, aml_operation_region("P40C", AML_PCI_CONFIG,
aml_int(0x60), 0x04));
call_dev_aml_func(DEVICE(obj), dev);
aml_append(scope, dev);
aml_append(table, scope);
}
@ -1401,13 +1394,21 @@ static Aml *build_q35_osc_method(bool enable_native_pcie_hotplug)
return method;
}
static void build_smb0(Aml *table, I2CBus *smbus, int devnr, int func)
static void build_smb0(Aml *table, int devnr, int func)
{
Aml *scope = aml_scope("_SB.PCI0");
Aml *dev = aml_device("SMB0");
bool ambiguous;
Object *obj;
/*
* temporarily fish out device hosting SMBUS, build_smb0 will be gone once
* PCI enumeration will be switched to call_dev_aml_func()
*/
obj = object_resolve_path_type("", TYPE_ICH9_SMB_DEVICE, &ambiguous);
assert(obj && !ambiguous);
aml_append(dev, aml_name_decl("_ADR", aml_int(devnr << 16 | func)));
build_acpi_ipmi_devices(dev, BUS(smbus), "\\_SB.PCI0.SMB0");
call_dev_aml_func(DEVICE(obj), dev);
aml_append(scope, dev);
aml_append(table, scope);
}
@ -1470,7 +1471,6 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
build_hpet_aml(dsdt);
}
build_piix4_isa_bridge(dsdt);
build_isa_devices_aml(dsdt);
if (pm->pcihp_bridge_en || pm->pcihp_root_en) {
build_x86_acpi_pci_hotplug(dsdt, pm->pcihp_io_base);
}
@ -1519,13 +1519,12 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
build_hpet_aml(dsdt);
}
build_q35_isa_bridge(dsdt);
build_isa_devices_aml(dsdt);
if (pm->pcihp_bridge_en) {
build_x86_acpi_pci_hotplug(dsdt, pm->pcihp_io_base);
}
build_q35_pci0_int(dsdt);
if (pcms->smbus && !pcmc->do_not_add_smb_acpi) {
build_smb0(dsdt, pcms->smbus, ICH9_SMB_DEV, ICH9_SMB_FUNC);
if (pcms->smbus) {
build_smb0(dsdt, ICH9_SMB_DEV, ICH9_SMB_FUNC);
}
}
@ -1633,7 +1632,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
/* Handle the ranges for the PXB expanders */
if (pci_bus_is_cxl(bus)) {
MemoryRegion *mr = &machine->cxl_devices_state->host_mr;
MemoryRegion *mr = &pcms->cxl_devices_state.host_mr;
uint64_t base = mr->addr;
cxl_present = true;
@ -1796,110 +1795,15 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
aml_append(dsdt, scope);
}
if (misc->applesmc_io_base) {
scope = aml_scope("\\_SB.PCI0.ISA");
dev = aml_device("SMC");
aml_append(dev, aml_name_decl("_HID", aml_eisaid("APP0001")));
/* device present, functioning, decoding, not shown in UI */
aml_append(dev, aml_name_decl("_STA", aml_int(0xB)));
crs = aml_resource_template();
aml_append(crs,
aml_io(AML_DECODE16, misc->applesmc_io_base, misc->applesmc_io_base,
0x01, APPLESMC_MAX_DATA_LENGTH)
);
aml_append(crs, aml_irq_no_flags(6));
aml_append(dev, aml_name_decl("_CRS", crs));
aml_append(scope, dev);
aml_append(dsdt, scope);
}
if (misc->pvpanic_port) {
scope = aml_scope("\\_SB.PCI0.ISA");
dev = aml_device("PEVT");
aml_append(dev, aml_name_decl("_HID", aml_string("QEMU0001")));
crs = aml_resource_template();
aml_append(crs,
aml_io(AML_DECODE16, misc->pvpanic_port, misc->pvpanic_port, 1, 1)
);
aml_append(dev, aml_name_decl("_CRS", crs));
aml_append(dev, aml_operation_region("PEOR", AML_SYSTEM_IO,
aml_int(misc->pvpanic_port), 1));
field = aml_field("PEOR", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE);
aml_append(field, aml_named_field("PEPT", 8));
aml_append(dev, field);
/* device present, functioning, decoding, shown in UI */
aml_append(dev, aml_name_decl("_STA", aml_int(0xF)));
method = aml_method("RDPT", 0, AML_NOTSERIALIZED);
aml_append(method, aml_store(aml_name("PEPT"), aml_local(0)));
aml_append(method, aml_return(aml_local(0)));
aml_append(dev, method);
method = aml_method("WRPT", 1, AML_NOTSERIALIZED);
aml_append(method, aml_store(aml_arg(0), aml_name("PEPT")));
aml_append(dev, method);
aml_append(scope, dev);
aml_append(dsdt, scope);
}
sb_scope = aml_scope("\\_SB");
{
Object *pci_host;
PCIBus *bus = NULL;
pci_host = acpi_get_i386_pci_host();
Object *pci_host = acpi_get_i386_pci_host();
if (pci_host) {
bus = PCI_HOST_BRIDGE(pci_host)->bus;
}
if (bus) {
PCIBus *bus = PCI_HOST_BRIDGE(pci_host)->bus;
Aml *scope = aml_scope("PCI0");
/* Scan all PCI buses. Generate tables to support hotplug. */
build_append_pci_bus_devices(scope, bus, pm->pcihp_bridge_en);
#ifdef CONFIG_TPM
if (TPM_IS_TIS_ISA(tpm)) {
if (misc->tpm_version == TPM_VERSION_2_0) {
dev = aml_device("TPM");
aml_append(dev, aml_name_decl("_HID",
aml_string("MSFT0101")));
aml_append(dev,
aml_name_decl("_STR",
aml_string("TPM 2.0 Device")));
} else {
dev = aml_device("ISA.TPM");
aml_append(dev, aml_name_decl("_HID",
aml_eisaid("PNP0C31")));
}
aml_append(dev, aml_name_decl("_UID", aml_int(1)));
aml_append(dev, aml_name_decl("_STA", aml_int(0xF)));
crs = aml_resource_template();
aml_append(crs, aml_memory32_fixed(TPM_TIS_ADDR_BASE,
TPM_TIS_ADDR_SIZE, AML_READ_WRITE));
/*
FIXME: TPM_TIS_IRQ=5 conflicts with PNP0C0F irqs,
Rewrite to take IRQ from TPM device model and
fix default IRQ value there to use some unused IRQ
*/
/* aml_append(crs, aml_irq_no_flags(TPM_TIS_IRQ)); */
aml_append(dev, aml_name_decl("_CRS", crs));
tpm_build_ppi_acpi(tpm, dev);
aml_append(scope, dev);
}
#endif
aml_append(sb_scope, scope);
}
}
@ -2711,9 +2615,9 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
machine->nvdimms_state, machine->ram_slots,
x86ms->oem_id, x86ms->oem_table_id);
}
if (machine->cxl_devices_state->is_enabled) {
cxl_build_cedt(machine, table_offsets, tables_blob, tables->linker,
x86ms->oem_id, x86ms->oem_table_id);
if (pcms->cxl_devices_state.is_enabled) {
cxl_build_cedt(table_offsets, tables_blob, tables->linker,
x86ms->oem_id, x86ms->oem_table_id, &pcms->cxl_devices_state);
}
acpi_add_table(table_offsets, tables_blob);

View File

@ -32,6 +32,7 @@
*/
#include "qemu/osdep.h"
#include "qemu/cutils.h"
#include "qapi/error.h"
#include "sysemu/device_tree.h"
#include "hw/char/serial.h"
#include "hw/i386/fw_cfg.h"
@ -187,8 +188,8 @@ static void dt_add_ioapic(MicrovmMachineState *mms, SysBusDevice *dev)
static void dt_add_isa_serial(MicrovmMachineState *mms, ISADevice *dev)
{
const char compat[] = "ns16550";
uint32_t irq = object_property_get_int(OBJECT(dev), "irq", NULL);
hwaddr base = object_property_get_int(OBJECT(dev), "iobase", NULL);
uint32_t irq = object_property_get_int(OBJECT(dev), "irq", &error_fatal);
hwaddr base = object_property_get_int(OBJECT(dev), "iobase", &error_fatal);
hwaddr size = 8;
char *nodename;
@ -208,8 +209,8 @@ static void dt_add_isa_serial(MicrovmMachineState *mms, ISADevice *dev)
static void dt_add_isa_rtc(MicrovmMachineState *mms, ISADevice *dev)
{
const char compat[] = "motorola,mc146818";
uint32_t irq = RTC_ISA_IRQ;
hwaddr base = RTC_ISA_BASE;
uint32_t irq = object_property_get_uint(OBJECT(dev), "irq", &error_fatal);
hwaddr base = object_property_get_uint(OBJECT(dev), "iobase", &error_fatal);
hwaddr size = 8;
char *nodename;

View File

@ -37,6 +37,7 @@
#include "hw/ide.h"
#include "hw/pci/pci.h"
#include "hw/pci/pci_bus.h"
#include "hw/pci-bridge/pci_expander_bridge.h"
#include "hw/nvram/fw_cfg.h"
#include "hw/timer/hpet.h"
#include "hw/firmware/smbios.h"
@ -76,6 +77,7 @@
#include "hw/mem/pc-dimm.h"
#include "hw/mem/nvdimm.h"
#include "hw/cxl/cxl.h"
#include "hw/cxl/cxl_host.h"
#include "qapi/error.h"
#include "qapi/qapi-visit-common.h"
#include "qapi/qapi-visit-machine.h"
@ -96,6 +98,15 @@
#include "trace.h"
#include CONFIG_DEVICES
/*
* Helper for setting model-id for CPU models that changed model-id
* depending on QEMU versions up to QEMU 2.4.
*/
#define PC_CPU_MODEL_IDS(v) \
{ "qemu32-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, },\
{ "qemu64-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, },\
{ "athlon-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, },
GlobalProperty pc_compat_7_0[] = {};
const size_t pc_compat_7_0_len = G_N_ELEMENTS(pc_compat_7_0);
@ -561,7 +572,7 @@ static const char * const fdc_container_path[] = {
* Locate the FDC at IO address 0x3f0, in order to configure the CMOS registers
* and ACPI objects.
*/
ISADevice *pc_find_fdc0(void)
static ISADevice *pc_find_fdc0(void)
{
int i;
Object *container;
@ -705,7 +716,7 @@ static const int ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360,
0x280, 0x380 };
static const int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };
void pc_init_ne2k_isa(ISABus *bus, NICInfo *nd)
static void pc_init_ne2k_isa(ISABus *bus, NICInfo *nd)
{
static int nb_ne2k = 0;
@ -732,6 +743,13 @@ void pc_machine_done(Notifier *notifier, void *data)
PCMachineState, machine_done);
X86MachineState *x86ms = X86_MACHINE(pcms);
cxl_hook_up_pxb_registers(pcms->bus, &pcms->cxl_devices_state,
&error_fatal);
if (pcms->cxl_devices_state.is_enabled) {
cxl_fmws_link_targets(&pcms->cxl_devices_state, &error_fatal);
}
/* set the number of CPUs */
x86_rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus);
@ -899,8 +917,8 @@ void pc_memory_init(PCMachineState *pcms,
&machine->device_memory->mr);
}
if (machine->cxl_devices_state->is_enabled) {
MemoryRegion *mr = &machine->cxl_devices_state->host_mr;
if (pcms->cxl_devices_state.is_enabled) {
MemoryRegion *mr = &pcms->cxl_devices_state.host_mr;
hwaddr cxl_size = MiB;
if (pcmc->has_reserved_memory && machine->device_memory->base) {
@ -918,12 +936,12 @@ void pc_memory_init(PCMachineState *pcms,
memory_region_init(mr, OBJECT(machine), "cxl_host_reg", cxl_size);
memory_region_add_subregion(system_memory, cxl_base, mr);
cxl_resv_end = cxl_base + cxl_size;
if (machine->cxl_devices_state->fixed_windows) {
if (pcms->cxl_devices_state.fixed_windows) {
hwaddr cxl_fmw_base;
GList *it;
cxl_fmw_base = ROUND_UP(cxl_base + cxl_size, 256 * MiB);
for (it = machine->cxl_devices_state->fixed_windows; it; it = it->next) {
for (it = pcms->cxl_devices_state.fixed_windows; it; it = it->next) {
CXLFixedWindow *fw = it->data;
fw->base = cxl_fmw_base;
@ -965,7 +983,7 @@ void pc_memory_init(PCMachineState *pcms,
res_mem_end += memory_region_size(&machine->device_memory->mr);
}
if (machine->cxl_devices_state->is_enabled) {
if (pcms->cxl_devices_state.is_enabled) {
res_mem_end = cxl_resv_end;
}
*val = cpu_to_le64(ROUND_UP(res_mem_end, 1 * GiB));
@ -1001,12 +1019,12 @@ uint64_t pc_pci_hole64_start(void)
X86MachineState *x86ms = X86_MACHINE(pcms);
uint64_t hole64_start = 0;
if (ms->cxl_devices_state->host_mr.addr) {
hole64_start = ms->cxl_devices_state->host_mr.addr +
memory_region_size(&ms->cxl_devices_state->host_mr);
if (ms->cxl_devices_state->fixed_windows) {
if (pcms->cxl_devices_state.host_mr.addr) {
hole64_start = pcms->cxl_devices_state.host_mr.addr +
memory_region_size(&pcms->cxl_devices_state.host_mr);
if (pcms->cxl_devices_state.fixed_windows) {
GList *it;
for (it = ms->cxl_devices_state->fixed_windows; it; it = it->next) {
for (it = pcms->cxl_devices_state.fixed_windows; it; it = it->next) {
CXLFixedWindow *fw = it->data;
hole64_start = fw->mr.addr + memory_region_size(&fw->mr);
}
@ -1088,7 +1106,7 @@ static void pc_superio_init(ISABus *isa_bus, bool create_fdctrl,
return;
}
i8042 = isa_create_simple(isa_bus, "i8042");
i8042 = isa_create_simple(isa_bus, TYPE_I8042);
if (!no_vmport) {
isa_create_simple(isa_bus, TYPE_VMPORT);
vmmouse = isa_try_new("vmmouse");
@ -1096,7 +1114,7 @@ static void pc_superio_init(ISABus *isa_bus, bool create_fdctrl,
vmmouse = NULL;
}
if (vmmouse) {
object_property_set_link(OBJECT(vmmouse), "i8042", OBJECT(i8042),
object_property_set_link(OBJECT(vmmouse), TYPE_I8042, OBJECT(i8042),
&error_abort);
isa_realize_and_unref(vmmouse, isa_bus, &error_fatal);
}
@ -1706,6 +1724,7 @@ static void pc_machine_initfn(Object *obj)
pcms->pcspk = isa_new(TYPE_PC_SPEAKER);
object_property_add_alias(OBJECT(pcms), "pcspk-audiodev",
OBJECT(pcms->pcspk), "audiodev");
cxl_machine_init(obj, &pcms->cxl_devices_state);
}
static void pc_machine_reset(MachineState *machine)
@ -1794,7 +1813,6 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)
mc->default_cpu_type = TARGET_DEFAULT_CPU_TYPE;
mc->nvdimm_supported = true;
mc->smp_props.dies_supported = true;
mc->cxl_supported = true;
mc->default_ram_id = "pc.ram";
object_class_property_add(oc, PC_MACHINE_MAX_RAM_BELOW_4G, "size",

View File

@ -47,6 +47,7 @@
#include "hw/xen/xen-x86.h"
#include "exec/memory.h"
#include "hw/acpi/acpi.h"
#include "hw/acpi/piix4.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "sysemu/xen.h"
@ -196,6 +197,9 @@ static void pc_init1(MachineState *machine,
if (pcmc->pci_enabled) {
PIIX3State *piix3;
PCIDevice *pci_dev;
const char *type = xen_enabled() ? TYPE_PIIX3_XEN_DEVICE
: TYPE_PIIX3_DEVICE;
pci_bus = i440fx_init(host_type,
pci_type,
@ -206,9 +210,11 @@ static void pc_init1(MachineState *machine,
pci_memory, ram_memory);
pcms->bus = pci_bus;
piix3 = piix3_create(pci_bus, &isa_bus);
pci_dev = pci_create_simple_multifunction(pci_bus, -1, true, type);
piix3 = PIIX3_PCI_DEVICE(pci_dev);
piix3->pic = x86ms->gsi;
piix3_devfn = piix3->dev.devfn;
isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(piix3), "isa.0"));
} else {
pci_bus = NULL;
i440fx_state = NULL;
@ -280,14 +286,19 @@ static void pc_init1(MachineState *machine,
}
if (pcmc->pci_enabled && x86_machine_is_acpi_enabled(X86_MACHINE(pcms))) {
DeviceState *piix4_pm;
PCIDevice *piix4_pm;
smi_irq = qemu_allocate_irq(pc_acpi_smi_interrupt, first_cpu, 0);
piix4_pm = pci_new(piix3_devfn + 3, TYPE_PIIX4_PM);
qdev_prop_set_uint32(DEVICE(piix4_pm), "smb_io_base", 0xb100);
qdev_prop_set_bit(DEVICE(piix4_pm), "smm-enabled",
x86_machine_is_smm_enabled(x86ms));
pci_realize_and_unref(piix4_pm, pci_bus, &error_fatal);
qdev_connect_gpio_out(DEVICE(piix4_pm), 0, x86ms->gsi[9]);
qdev_connect_gpio_out_named(DEVICE(piix4_pm), "smi-irq", 0, smi_irq);
pcms->smbus = I2C_BUS(qdev_get_child_bus(DEVICE(piix4_pm), "i2c"));
/* TODO: Populate SPD eeprom data. */
pcms->smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
x86ms->gsi[9], smi_irq,
x86_machine_is_smm_enabled(x86ms),
&piix4_pm);
smbus_eeprom_init(pcms->smbus, 8, NULL, 0);
object_property_add_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP,
@ -563,7 +574,6 @@ static void pc_i440fx_3_1_machine_options(MachineClass *m)
pc_i440fx_4_0_machine_options(m);
m->is_default = false;
pcmc->do_not_add_smb_acpi = true;
m->smbus_no_migration_support = true;
m->alias = NULL;
pcmc->pvh_enabled = false;

View File

@ -514,7 +514,6 @@ static void pc_q35_3_1_machine_options(MachineClass *m)
pc_q35_4_0_machine_options(m);
m->default_kernel_irqchip_split = false;
pcmc->do_not_add_smb_acpi = true;
m->smbus_no_migration_support = true;
m->alias = NULL;
pcmc->pvh_enabled = false;

View File

@ -29,7 +29,7 @@
#include "qapi/error.h"
#include "hw/isa/isa.h"
#include "migration/vmstate.h"
#include "hw/acpi/aml-build.h"
#include "hw/acpi/acpi_aml_interface.h"
#include "hw/input/ps2.h"
#include "hw/irq.h"
#include "hw/input/i8042.h"
@ -767,9 +767,9 @@ static void i8042_realizefn(DeviceState *dev, Error **errp)
qemu_register_reset(kbd_reset, s);
}
static void i8042_build_aml(ISADevice *isadev, Aml *scope)
static void i8042_build_aml(AcpiDevAmlIf *adev, Aml *scope)
{
ISAKBDState *isa_s = I8042(isadev);
ISAKBDState *isa_s = I8042(adev);
Aml *kbd;
Aml *mou;
Aml *crs;
@ -807,12 +807,12 @@ static Property i8042_properties[] = {
static void i8042_class_initfn(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ISADeviceClass *isa = ISA_DEVICE_CLASS(klass);
AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
device_class_set_props(dc, i8042_properties);
dc->realize = i8042_realizefn;
dc->vmsd = &vmstate_kbd_isa;
isa->build_aml = i8042_build_aml;
adevc->build_dev_aml = i8042_build_aml;
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
}
@ -822,6 +822,10 @@ static const TypeInfo i8042_info = {
.instance_size = sizeof(ISAKBDState),
.instance_init = i8042_initfn,
.class_init = i8042_class_initfn,
.interfaces = (InterfaceInfo[]) {
{ TYPE_ACPI_DEV_AML_IF },
{ },
},
};
static void i8042_register_types(void)

View File

@ -31,6 +31,7 @@
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
#include "qom/object.h"
#include "hw/acpi/ipmi.h"
#define TYPE_ISA_IPMI_BT "isa-ipmi-bt"
OBJECT_DECLARE_SIMPLE_TYPE(ISAIPMIBTDevice, ISA_IPMI_BT)
@ -144,6 +145,7 @@ static void isa_ipmi_bt_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
IPMIInterfaceClass *iic = IPMI_INTERFACE_CLASS(oc);
AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(oc);
dc->realize = isa_ipmi_bt_realize;
device_class_set_props(dc, ipmi_isa_properties);
@ -151,6 +153,7 @@ static void isa_ipmi_bt_class_init(ObjectClass *oc, void *data)
iic->get_backend_data = isa_ipmi_bt_get_backend_data;
ipmi_bt_class_init(iic);
iic->get_fwinfo = isa_ipmi_bt_get_fwinfo;
adevc->build_dev_aml = build_ipmi_dev_aml;
}
static const TypeInfo isa_ipmi_bt_info = {
@ -161,6 +164,7 @@ static const TypeInfo isa_ipmi_bt_info = {
.class_init = isa_ipmi_bt_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_IPMI_INTERFACE },
{ TYPE_ACPI_DEV_AML_IF },
{ }
}
};

View File

@ -31,6 +31,7 @@
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
#include "qom/object.h"
#include "hw/acpi/ipmi.h"
#define TYPE_ISA_IPMI_KCS "isa-ipmi-kcs"
OBJECT_DECLARE_SIMPLE_TYPE(ISAIPMIKCSDevice, ISA_IPMI_KCS)
@ -151,6 +152,7 @@ static void isa_ipmi_kcs_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
IPMIInterfaceClass *iic = IPMI_INTERFACE_CLASS(oc);
AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(oc);
dc->realize = ipmi_isa_realize;
device_class_set_props(dc, ipmi_isa_properties);
@ -158,6 +160,7 @@ static void isa_ipmi_kcs_class_init(ObjectClass *oc, void *data)
iic->get_backend_data = isa_ipmi_kcs_get_backend_data;
ipmi_kcs_class_init(iic);
iic->get_fwinfo = isa_ipmi_kcs_get_fwinfo;
adevc->build_dev_aml = build_ipmi_dev_aml;
}
static const TypeInfo isa_ipmi_kcs_info = {
@ -168,6 +171,7 @@ static const TypeInfo isa_ipmi_kcs_info = {
.class_init = isa_ipmi_kcs_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_IPMI_INTERFACE },
{ TYPE_ACPI_DEV_AML_IF },
{ }
}
};

View File

@ -28,6 +28,7 @@
#include "qemu/error-report.h"
#include "hw/ipmi/ipmi.h"
#include "qom/object.h"
#include "hw/acpi/ipmi.h"
#define TYPE_SMBUS_IPMI "smbus-ipmi"
OBJECT_DECLARE_SIMPLE_TYPE(SMBusIPMIDevice, SMBUS_IPMI)
@ -353,6 +354,7 @@ static void smbus_ipmi_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
IPMIInterfaceClass *iic = IPMI_INTERFACE_CLASS(oc);
SMBusDeviceClass *sc = SMBUS_DEVICE_CLASS(oc);
AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(oc);
sc->receive_byte = ipmi_receive_byte;
sc->write_data = ipmi_write_data;
@ -363,6 +365,7 @@ static void smbus_ipmi_class_init(ObjectClass *oc, void *data)
iic->handle_if_event = smbus_ipmi_handle_event;
iic->set_irq_enable = smbus_ipmi_set_irq_enable;
iic->get_fwinfo = smbus_ipmi_get_fwinfo;
adevc->build_dev_aml = build_ipmi_dev_aml;
}
static const TypeInfo smbus_ipmi_info = {
@ -373,6 +376,7 @@ static const TypeInfo smbus_ipmi_info = {
.class_init = smbus_ipmi_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_IPMI_INTERFACE },
{ TYPE_ACPI_DEV_AML_IF },
{ }
}
};

View File

@ -24,6 +24,7 @@
#include "hw/sysbus.h"
#include "sysemu/sysemu.h"
#include "hw/isa/isa.h"
#include "hw/acpi/acpi_aml_interface.h"
static ISABus *isabus;
@ -190,15 +191,9 @@ ISADevice *isa_vga_init(ISABus *bus)
void isa_build_aml(ISABus *bus, Aml *scope)
{
BusChild *kid;
ISADevice *dev;
ISADeviceClass *dc;
QTAILQ_FOREACH(kid, &bus->parent_obj.children, sibling) {
dev = ISA_DEVICE(kid->child);
dc = ISA_DEVICE_GET_CLASS(dev);
if (dc->build_aml) {
dc->build_aml(dev, scope);
}
call_dev_aml_func(DEVICE(kid->child), scope);
}
}

View File

@ -50,6 +50,7 @@
#include "hw/core/cpu.h"
#include "hw/nvram/fw_cfg.h"
#include "qemu/cutils.h"
#include "hw/acpi/acpi_aml_interface.h"
/*****************************************************************************/
/* ICH9 LPC PCI to ISA bridge */
@ -803,12 +804,28 @@ static void ich9_send_gpe(AcpiDeviceIf *adev, AcpiEventStatusBits ev)
acpi_send_gpe_event(&s->pm.acpi_regs, s->pm.irq, ev);
}
static void build_ich9_isa_aml(AcpiDevAmlIf *adev, Aml *scope)
{
BusChild *kid;
ICH9LPCState *s = ICH9_LPC_DEVICE(adev);
BusState *bus = BUS(s->isa_bus);
/* ICH9 PCI to ISA irq remapping */
aml_append(scope, aml_operation_region("PIRQ", AML_PCI_CONFIG,
aml_int(0x60), 0x0C));
QTAILQ_FOREACH(kid, &bus->children, sibling) {
call_dev_aml_func(DEVICE(kid->child), scope);
}
}
static void ich9_lpc_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_CLASS(klass);
AcpiDevAmlIfClass *amldevc = ACPI_DEV_AML_IF_CLASS(klass);
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
dc->reset = ich9_lpc_reset;
@ -833,6 +850,7 @@ static void ich9_lpc_class_init(ObjectClass *klass, void *data)
adevc->ospm_status = ich9_pm_ospm_status;
adevc->send_event = ich9_send_gpe;
adevc->madt_cpu = pc_madt_cpu_entry;
amldevc->build_dev_aml = build_ich9_isa_aml;
}
static const TypeInfo ich9_lpc_info = {
@ -845,6 +863,7 @@ static const TypeInfo ich9_lpc_info = {
{ TYPE_HOTPLUG_HANDLER },
{ TYPE_ACPI_DEVICE_IF },
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ TYPE_ACPI_DEV_AML_IF },
{ }
}
};

View File

@ -24,6 +24,7 @@
#include "qemu/osdep.h"
#include "qemu/range.h"
#include "qapi/error.h"
#include "hw/southbridge/piix.h"
#include "hw/irq.h"
#include "hw/isa/isa.h"
@ -32,12 +33,10 @@
#include "sysemu/reset.h"
#include "sysemu/runstate.h"
#include "migration/vmstate.h"
#include "hw/acpi/acpi_aml_interface.h"
#define XEN_PIIX_NUM_PIRQS 128ULL
#define TYPE_PIIX3_DEVICE "PIIX3"
#define TYPE_PIIX3_XEN_DEVICE "PIIX3-xen"
static void piix3_set_irq_pic(PIIX3State *piix3, int pic_irq)
{
qemu_set_irq(piix3->pic[pic_irq],
@ -81,6 +80,17 @@ static void piix3_set_irq(void *opaque, int pirq, int level)
piix3_set_irq_level(piix3, pirq, level);
}
/*
* Return the global irq number corresponding to a given device irq
* pin. We could also use the bus number to have a more precise mapping.
*/
static int pci_slot_get_pirq(PCIDevice *pci_dev, int pci_intx)
{
int slot_addend;
slot_addend = PCI_SLOT(pci_dev->devfn) - 1;
return (pci_intx + slot_addend) & 3;
}
static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pin)
{
PIIX3State *piix3 = opaque;
@ -269,7 +279,7 @@ static const MemoryRegionOps rcr_ops = {
.endianness = DEVICE_LITTLE_ENDIAN
};
static void piix3_realize(PCIDevice *dev, Error **errp)
static void pci_piix3_realize(PCIDevice *dev, Error **errp)
{
PIIX3State *d = PIIX3_PCI_DEVICE(dev);
@ -286,15 +296,28 @@ static void piix3_realize(PCIDevice *dev, Error **errp)
qemu_register_reset(piix3_reset, d);
}
static void build_pci_isa_aml(AcpiDevAmlIf *adev, Aml *scope)
{
BusChild *kid;
BusState *bus = qdev_get_child_bus(DEVICE(adev), "isa.0");
/* PIIX PCI to ISA irq remapping */
aml_append(scope, aml_operation_region("P40C", AML_PCI_CONFIG,
aml_int(0x60), 0x04));
QTAILQ_FOREACH(kid, &bus->children, sibling) {
call_dev_aml_func(DEVICE(kid->child), scope);
}
}
static void pci_piix3_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
dc->desc = "ISA bridge";
dc->vmsd = &vmstate_piix3;
dc->hotpluggable = false;
k->realize = piix3_realize;
k->vendor_id = PCI_VENDOR_ID_INTEL;
/* 82371SB PIIX3 PCI-to-ISA bridge (Step A1) */
k->device_id = PCI_DEVICE_ID_INTEL_82371SB_0;
@ -304,6 +327,7 @@ static void pci_piix3_class_init(ObjectClass *klass, void *data)
* pc_piix.c's pc_init1()
*/
dc->user_creatable = false;
adevc->build_dev_aml = build_pci_isa_aml;
}
static const TypeInfo piix3_pci_type_info = {
@ -314,15 +338,33 @@ static const TypeInfo piix3_pci_type_info = {
.class_init = pci_piix3_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ TYPE_ACPI_DEV_AML_IF },
{ },
},
};
static void piix3_realize(PCIDevice *dev, Error **errp)
{
ERRP_GUARD();
PIIX3State *piix3 = PIIX3_PCI_DEVICE(dev);
PCIBus *pci_bus = pci_get_bus(dev);
pci_piix3_realize(dev, errp);
if (*errp) {
return;
}
pci_bus_irqs(pci_bus, piix3_set_irq, pci_slot_get_pirq,
piix3, PIIX_NUM_PIRQS);
pci_bus_set_route_irq_fn(pci_bus, piix3_route_intx_pin_to_irq);
};
static void piix3_class_init(ObjectClass *klass, void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->config_write = piix3_write_config;
k->realize = piix3_realize;
}
static const TypeInfo piix3_info = {
@ -331,11 +373,33 @@ static const TypeInfo piix3_info = {
.class_init = piix3_class_init,
};
static void piix3_xen_realize(PCIDevice *dev, Error **errp)
{
ERRP_GUARD();
PIIX3State *piix3 = PIIX3_PCI_DEVICE(dev);
PCIBus *pci_bus = pci_get_bus(dev);
pci_piix3_realize(dev, errp);
if (*errp) {
return;
}
/*
* Xen supports additional interrupt routes from the PCI devices to
* the IOAPIC: the four pins of each PCI device on the bus are also
* connected to the IOAPIC directly.
* These additional routes can be discovered through ACPI.
*/
pci_bus_irqs(pci_bus, xen_piix3_set_irq, xen_pci_slot_get_pirq,
piix3, XEN_PIIX_NUM_PIRQS);
};
static void piix3_xen_class_init(ObjectClass *klass, void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->config_write = piix3_write_config_xen;
k->realize = piix3_xen_realize;
};
static const TypeInfo piix3_xen_info = {
@ -352,44 +416,3 @@ static void piix3_register_types(void)
}
type_init(piix3_register_types)
/*
* Return the global irq number corresponding to a given device irq
* pin. We could also use the bus number to have a more precise mapping.
*/
static int pci_slot_get_pirq(PCIDevice *pci_dev, int pci_intx)
{
int slot_addend;
slot_addend = PCI_SLOT(pci_dev->devfn) - 1;
return (pci_intx + slot_addend) & 3;
}
PIIX3State *piix3_create(PCIBus *pci_bus, ISABus **isa_bus)
{
PIIX3State *piix3;
PCIDevice *pci_dev;
/*
* Xen supports additional interrupt routes from the PCI devices to
* the IOAPIC: the four pins of each PCI device on the bus are also
* connected to the IOAPIC directly.
* These additional routes can be discovered through ACPI.
*/
if (xen_enabled()) {
pci_dev = pci_create_simple_multifunction(pci_bus, -1, true,
TYPE_PIIX3_XEN_DEVICE);
piix3 = PIIX3_PCI_DEVICE(pci_dev);
pci_bus_irqs(pci_bus, xen_piix3_set_irq, xen_pci_slot_get_pirq,
piix3, XEN_PIIX_NUM_PIRQS);
} else {
pci_dev = pci_create_simple_multifunction(pci_bus, -1, true,
TYPE_PIIX3_DEVICE);
piix3 = PIIX3_PCI_DEVICE(pci_dev);
pci_bus_irqs(pci_bus, piix3_set_irq, pci_slot_get_pirq,
piix3, PIIX_NUM_PIRQS);
pci_bus_set_route_irq_fn(pci_bus, piix3_route_intx_pin_to_irq);
}
*isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(piix3), "isa.0"));
return piix3;
}

View File

@ -34,6 +34,8 @@
#include "hw/timer/i8254.h"
#include "hw/rtc/mc146818rtc.h"
#include "hw/ide/pci.h"
#include "hw/acpi/piix4.h"
#include "hw/usb/hcd-uhci.h"
#include "migration/vmstate.h"
#include "sysemu/reset.h"
#include "sysemu/runstate.h"
@ -45,6 +47,9 @@ struct PIIX4State {
qemu_irq *isa;
RTCState rtc;
PCIIDEState ide;
UHCIState uhci;
PIIX4PMState pm;
/* Reset Control Register */
MemoryRegion rcr_mem;
uint8_t rcr;
@ -73,6 +78,31 @@ static void piix4_set_irq(void *opaque, int irq_num, int level)
}
}
static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
{
int slot;
slot = PCI_SLOT(pci_dev->devfn);
switch (slot) {
/* PIIX4 USB */
case 10:
return 3;
/* AMD 79C973 Ethernet */
case 11:
return 1;
/* Crystal 4281 Sound */
case 12:
return 2;
/* PCI slot 1 to 4 */
case 18 ... 21:
return ((slot - 18) + irq_num) & 0x03;
/* Unknown device, don't do any translation */
default:
return irq_num;
}
}
static void piix4_isa_reset(DeviceState *dev)
{
PIIX4State *d = PIIX4_PCI_DEVICE(dev);
@ -179,6 +209,7 @@ static const MemoryRegionOps piix4_rcr_ops = {
static void piix4_realize(PCIDevice *dev, Error **errp)
{
PIIX4State *s = PIIX4_PCI_DEVICE(dev);
PCIBus *pci_bus = pci_get_bus(dev);
ISABus *isa_bus;
qemu_irq *i8259_out_irq;
@ -217,13 +248,41 @@ static void piix4_realize(PCIDevice *dev, Error **errp)
return;
}
s->rtc.irq = isa_get_irq(ISA_DEVICE(&s->rtc), s->rtc.isairq);
/* IDE */
qdev_prop_set_int32(DEVICE(&s->ide), "addr", dev->devfn + 1);
if (!qdev_realize(DEVICE(&s->ide), BUS(pci_bus), errp)) {
return;
}
pci_ide_create_devs(PCI_DEVICE(&s->ide));
/* USB */
qdev_prop_set_int32(DEVICE(&s->uhci), "addr", dev->devfn + 2);
if (!qdev_realize(DEVICE(&s->uhci), BUS(pci_bus), errp)) {
return;
}
/* ACPI controller */
qdev_prop_set_int32(DEVICE(&s->pm), "addr", dev->devfn + 3);
if (!qdev_realize(DEVICE(&s->pm), BUS(pci_bus), errp)) {
return;
}
qdev_connect_gpio_out(DEVICE(&s->pm), 0, s->isa[9]);
pci_bus_irqs(pci_bus, piix4_set_irq, pci_slot_get_pirq, s, PIIX_NUM_PIRQS);
}
static void piix4_init(Object *obj)
{
PIIX4State *s = PIIX4_PCI_DEVICE(obj);
object_initialize(&s->rtc, sizeof(s->rtc), TYPE_MC146818_RTC);
object_initialize_child(obj, "rtc", &s->rtc, TYPE_MC146818_RTC);
object_initialize_child(obj, "ide", &s->ide, "piix4-ide");
object_initialize_child(obj, "uhci", &s->uhci, "piix4-usb-uhci");
object_initialize_child(obj, "pm", &s->pm, TYPE_PIIX4_PM);
qdev_prop_set_uint32(DEVICE(&s->pm), "smb_io_base", 0x1100);
qdev_prop_set_bit(DEVICE(&s->pm), "smm-enabled", 0);
}
static void piix4_class_init(ObjectClass *klass, void *data)
@ -264,58 +323,3 @@ static void piix4_register_types(void)
}
type_init(piix4_register_types)
static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
{
int slot;
slot = PCI_SLOT(pci_dev->devfn);
switch (slot) {
/* PIIX4 USB */
case 10:
return 3;
/* AMD 79C973 Ethernet */
case 11:
return 1;
/* Crystal 4281 Sound */
case 12:
return 2;
/* PCI slot 1 to 4 */
case 18 ... 21:
return ((slot - 18) + irq_num) & 0x03;
/* Unknown device, don't do any translation */
default:
return irq_num;
}
}
DeviceState *piix4_create(PCIBus *pci_bus, ISABus **isa_bus, I2CBus **smbus)
{
PIIX4State *s;
PCIDevice *pci;
DeviceState *dev;
int devfn = PCI_DEVFN(10, 0);
pci = pci_create_simple_multifunction(pci_bus, devfn, true,
TYPE_PIIX4_PCI_DEVICE);
dev = DEVICE(pci);
s = PIIX4_PCI_DEVICE(pci);
if (isa_bus) {
*isa_bus = ISA_BUS(qdev_get_child_bus(dev, "isa.0"));
}
pci = pci_create_simple(pci_bus, devfn + 1, "piix4-ide");
pci_ide_create_devs(pci);
pci_create_simple(pci_bus, devfn + 2, "piix4-usb-uhci");
if (smbus) {
*smbus = piix4_pm_init(pci_bus, devfn + 3, 0x1100,
qdev_get_gpio_in_named(dev, "isa", 9),
NULL, 0, NULL);
}
pci_bus_irqs(pci_bus, piix4_set_irq, pci_slot_get_pirq, s, PIIX_NUM_PIRQS);
return dev;
}

View File

@ -787,7 +787,8 @@ static void boston_mach_init(MachineState *machine)
if (kernel_size > 0) {
int dt_size;
g_autofree const void *dtb_file_data, *dtb_load_data;
g_autofree const void *dtb_file_data = NULL;
g_autofree const void *dtb_load_data = NULL;
hwaddr dtb_paddr = QEMU_ALIGN_UP(kernel_high, 64 * KiB);
hwaddr dtb_vaddr = cpu_mips_phys_to_kseg0(NULL, dtb_paddr);

View File

@ -353,7 +353,7 @@ static void mips_jazz_init(MachineState *machine,
fds[n] = drive_get(IF_FLOPPY, 0, n);
}
/* FIXME: we should enable DMA with a custom IsaDma device */
fdctrl_init_sysbus(qdev_get_gpio_in(rc4030, 1), -1, 0x80003000, fds);
fdctrl_init_sysbus(qdev_get_gpio_in(rc4030, 1), 0x80003000, fds);
/* Real time clock */
mc146818_rtc_init(isa_bus, 1980, NULL);

View File

@ -1237,7 +1237,9 @@ void mips_malta_init(MachineState *machine)
int fl_idx = 0;
int be;
MaltaState *s;
PCIDevice *piix4;
DeviceState *dev;
DeviceState *pm_dev;
s = MIPS_MALTA(qdev_new(TYPE_MIPS_MALTA));
sysbus_realize_and_unref(SYS_BUS_DEVICE(s), &error_fatal);
@ -1399,7 +1401,12 @@ void mips_malta_init(MachineState *machine)
empty_slot_init("GT64120", 0, 0x20000000);
/* Southbridge */
dev = piix4_create(pci_bus, &isa_bus, &smbus);
piix4 = pci_create_simple_multifunction(pci_bus, PCI_DEVFN(10, 0), true,
TYPE_PIIX4_PCI_DEVICE);
dev = DEVICE(piix4);
isa_bus = ISA_BUS(qdev_get_child_bus(dev, "isa.0"));
pm_dev = DEVICE(object_resolve_path_component(OBJECT(dev), "pm"));
smbus = I2C_BUS(qdev_get_child_bus(pm_dev, "i2c"));
/* Interrupt controller */
qdev_connect_gpio_out_named(dev, "intr", 0, i8259_irq);

View File

@ -37,10 +37,14 @@
#include "qemu/module.h"
#include "qemu/timer.h"
#include "qom/object.h"
#include "hw/acpi/acpi_aml_interface.h"
/* #define DEBUG_SMC */
#define APPLESMC_DEFAULT_IOBASE 0x300
#define TYPE_APPLE_SMC "isa-applesmc"
#define APPLESMC_MAX_DATA_LENGTH 32
#define APPLESMC_PROP_IO_BASE "iobase"
enum {
APPLESMC_DATA_PORT = 0x00,
@ -347,14 +351,35 @@ static Property applesmc_isa_properties[] = {
DEFINE_PROP_END_OF_LIST(),
};
static void build_applesmc_aml(AcpiDevAmlIf *adev, Aml *scope)
{
Aml *crs;
AppleSMCState *s = APPLE_SMC(adev);
uint32_t iobase = s->iobase;
Aml *dev = aml_device("SMC");
aml_append(dev, aml_name_decl("_HID", aml_eisaid("APP0001")));
/* device present, functioning, decoding, not shown in UI */
aml_append(dev, aml_name_decl("_STA", aml_int(0xB)));
crs = aml_resource_template();
aml_append(crs,
aml_io(AML_DECODE16, iobase, iobase, 0x01, APPLESMC_MAX_DATA_LENGTH)
);
aml_append(crs, aml_irq_no_flags(6));
aml_append(dev, aml_name_decl("_CRS", crs));
aml_append(scope, dev);
}
static void qdev_applesmc_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
dc->realize = applesmc_isa_realize;
dc->reset = qdev_applesmc_isa_reset;
device_class_set_props(dc, applesmc_isa_properties);
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
adevc->build_dev_aml = build_applesmc_aml;
}
static const TypeInfo applesmc_isa_info = {
@ -362,6 +387,10 @@ static const TypeInfo applesmc_isa_info = {
.parent = TYPE_ISA_DEVICE,
.instance_size = sizeof(AppleSMCState),
.class_init = qdev_applesmc_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_ACPI_DEV_AML_IF },
{ },
},
};
static void applesmc_register_types(void)

View File

@ -22,6 +22,7 @@
#include "qom/object.h"
#include "hw/isa/isa.h"
#include "standard-headers/linux/pvpanic.h"
#include "hw/acpi/acpi_aml_interface.h"
OBJECT_DECLARE_SIMPLE_TYPE(PVPanicISAState, PVPANIC_ISA_DEVICE)
@ -63,6 +64,41 @@ static void pvpanic_isa_realizefn(DeviceState *dev, Error **errp)
isa_register_ioport(d, &ps->mr, s->ioport);
}
static void build_pvpanic_isa_aml(AcpiDevAmlIf *adev, Aml *scope)
{
Aml *crs, *field, *method;
PVPanicISAState *s = PVPANIC_ISA_DEVICE(adev);
Aml *dev = aml_device("PEVT");
aml_append(dev, aml_name_decl("_HID", aml_string("QEMU0001")));
crs = aml_resource_template();
aml_append(crs,
aml_io(AML_DECODE16, s->ioport, s->ioport, 1, 1)
);
aml_append(dev, aml_name_decl("_CRS", crs));
aml_append(dev, aml_operation_region("PEOR", AML_SYSTEM_IO,
aml_int(s->ioport), 1));
field = aml_field("PEOR", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE);
aml_append(field, aml_named_field("PEPT", 8));
aml_append(dev, field);
/* device present, functioning, decoding, shown in UI */
aml_append(dev, aml_name_decl("_STA", aml_int(0xF)));
method = aml_method("RDPT", 0, AML_NOTSERIALIZED);
aml_append(method, aml_store(aml_name("PEPT"), aml_local(0)));
aml_append(method, aml_return(aml_local(0)));
aml_append(dev, method);
method = aml_method("WRPT", 1, AML_NOTSERIALIZED);
aml_append(method, aml_store(aml_arg(0), aml_name("PEPT")));
aml_append(dev, method);
aml_append(scope, dev);
}
static Property pvpanic_isa_properties[] = {
DEFINE_PROP_UINT16(PVPANIC_IOPORT_PROP, PVPanicISAState, ioport, 0x505),
DEFINE_PROP_UINT8("events", PVPanicISAState, pvpanic.events,
@ -73,10 +109,12 @@ static Property pvpanic_isa_properties[] = {
static void pvpanic_isa_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
dc->realize = pvpanic_isa_realizefn;
device_class_set_props(dc, pvpanic_isa_properties);
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
adevc->build_dev_aml = build_pvpanic_isa_aml;
}
static const TypeInfo pvpanic_isa_info = {
@ -85,6 +123,10 @@ static const TypeInfo pvpanic_isa_info = {
.instance_size = sizeof(PVPanicISAState),
.instance_init = pvpanic_isa_initfn,
.class_init = pvpanic_isa_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_ACPI_DEV_AML_IF },
{ },
},
};
static void pvpanic_register_types(void)

View File

@ -443,26 +443,3 @@ static void etsec_register_types(void)
}
type_init(etsec_register_types)
DeviceState *etsec_create(hwaddr base,
MemoryRegion * mr,
NICInfo * nd,
qemu_irq tx_irq,
qemu_irq rx_irq,
qemu_irq err_irq)
{
DeviceState *dev;
dev = qdev_new("eTSEC");
qdev_set_nic_properties(dev, nd);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, tx_irq);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, rx_irq);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, err_irq);
memory_region_add_subregion(mr, base,
SYS_BUS_DEVICE(dev)->mmio[0].memory);
return dev;
}

View File

@ -155,13 +155,6 @@ OBJECT_DECLARE_SIMPLE_TYPE(eTSEC, ETSEC_COMMON)
#define eTSEC_TRANSMIT 1
#define eTSEC_RECEIVE 2
DeviceState *etsec_create(hwaddr base,
MemoryRegion *mr,
NICInfo *nd,
qemu_irq tx_irq,
qemu_irq rx_irq,
qemu_irq err_irq);
void etsec_update_irq(eTSEC *etsec);
void etsec_walk_tx_ring(eTSEC *etsec, int ring_nbr);

View File

@ -3,7 +3,8 @@ pci_ss.add(files('pci_bridge_dev.c'))
pci_ss.add(when: 'CONFIG_I82801B11', if_true: files('i82801b11.c'))
pci_ss.add(when: 'CONFIG_IOH3420', if_true: files('ioh3420.c'))
pci_ss.add(when: 'CONFIG_PCIE_PORT', if_true: files('pcie_root_port.c', 'gen_pcie_root_port.c', 'pcie_pci_bridge.c'))
pci_ss.add(when: 'CONFIG_PXB', if_true: files('pci_expander_bridge.c'))
pci_ss.add(when: 'CONFIG_PXB', if_true: files('pci_expander_bridge.c'),
if_false: files('pci_expander_bridge_stubs.c'))
pci_ss.add(when: 'CONFIG_XIO3130', if_true: files('xio3130_upstream.c', 'xio3130_downstream.c'))
pci_ss.add(when: 'CONFIG_CXL', if_true: files('cxl_root_port.c'))
@ -13,3 +14,5 @@ pci_ss.add(when: 'CONFIG_DEC_PCI', if_true: files('dec.c'))
pci_ss.add(when: 'CONFIG_SIMBA', if_true: files('simba.c'))
softmmu_ss.add_all(when: 'CONFIG_PCI', if_true: pci_ss)
softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('pci_expander_bridge_stubs.c'))

View File

@ -17,6 +17,7 @@
#include "hw/pci/pci_host.h"
#include "hw/qdev-properties.h"
#include "hw/pci/pci_bridge.h"
#include "hw/pci-bridge/pci_expander_bridge.h"
#include "hw/cxl/cxl.h"
#include "qemu/range.h"
#include "qemu/error-report.h"
@ -186,25 +187,38 @@ static const TypeInfo pxb_host_info = {
static void pxb_cxl_realize(DeviceState *dev, Error **errp)
{
MachineState *ms = MACHINE(qdev_get_machine());
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
CXLHost *cxl = PXB_CXL_HOST(dev);
CXLComponentState *cxl_cstate = &cxl->cxl_cstate;
struct MemoryRegion *mr = &cxl_cstate->crb.component_registers;
hwaddr offset;
cxl_component_register_block_init(OBJECT(dev), cxl_cstate,
TYPE_PXB_CXL_HOST);
sysbus_init_mmio(sbd, mr);
}
offset = memory_region_size(mr) * ms->cxl_devices_state->next_mr_idx;
if (offset > memory_region_size(&ms->cxl_devices_state->host_mr)) {
/*
* Host bridge realization has no means of knowning state associated
* with a particular machine. As such, it is nececssary to delay
* final setup of the host bridge register space until later in the
* machine bring up.
*/
void pxb_cxl_hook_up_registers(CXLState *cxl_state, PCIBus *bus, Error **errp)
{
PXBDev *pxb = PXB_CXL_DEV(pci_bridge_get_device(bus));
CXLHost *cxl = pxb->cxl.cxl_host_bridge;
CXLComponentState *cxl_cstate = &cxl->cxl_cstate;
struct MemoryRegion *mr = &cxl_cstate->crb.component_registers;
hwaddr offset;
offset = memory_region_size(mr) * cxl_state->next_mr_idx;
if (offset > memory_region_size(&cxl_state->host_mr)) {
error_setg(errp, "Insufficient space for pxb cxl host register space");
return;
}
memory_region_add_subregion(&ms->cxl_devices_state->host_mr, offset, mr);
ms->cxl_devices_state->next_mr_idx++;
memory_region_add_subregion(&cxl_state->host_mr, offset, mr);
cxl_state->next_mr_idx++;
}
static void pxb_cxl_host_class_init(ObjectClass *class, void *data)
@ -461,17 +475,11 @@ static const TypeInfo pxb_pcie_dev_info = {
static void pxb_cxl_dev_realize(PCIDevice *dev, Error **errp)
{
MachineState *ms = MACHINE(qdev_get_machine());
/* A CXL PXB's parent bus is still PCIe */
if (!pci_bus_is_express(pci_get_bus(dev))) {
error_setg(errp, "pxb-cxl devices cannot reside on a PCI bus");
return;
}
if (!ms->cxl_devices_state->is_enabled) {
error_setg(errp, "Machine does not have cxl=on");
return;
}
pxb_dev_realize_common(dev, CXL, errp);
pxb_dev_reset(DEVICE(dev));

View File

@ -0,0 +1,14 @@
/*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Stubs for calls made from machines to handle the case where CONFIG_PXB
* is not enabled.
*/
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "hw/pci/pci.h"
#include "hw/pci/pci_bus.h"
#include "hw/pci-bridge/pci_expander_bridge.h"
#include "hw/cxl/cxl.h"
void pxb_cxl_hook_up_registers(CXLState *state, PCIBus *bus, Error **errp) {};

View File

@ -134,7 +134,7 @@ void msi_set_message(PCIDevice *dev, MSIMessage msg)
pci_set_word(dev->config + msi_data_off(dev, msi64bit), msg.data);
}
MSIMessage msi_get_message(PCIDevice *dev, unsigned int vector)
static MSIMessage msi_prepare_message(PCIDevice *dev, unsigned int vector)
{
uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
bool msi64bit = flags & PCI_MSI_FLAGS_64BIT;
@ -159,6 +159,11 @@ MSIMessage msi_get_message(PCIDevice *dev, unsigned int vector)
return msg;
}
MSIMessage msi_get_message(PCIDevice *dev, unsigned int vector)
{
return dev->msi_prepare_message(dev, vector);
}
bool msi_enabled(const PCIDevice *dev)
{
return msi_present(dev) &&
@ -241,6 +246,8 @@ int msi_init(struct PCIDevice *dev, uint8_t offset,
0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors));
}
dev->msi_prepare_message = msi_prepare_message;
return 0;
}
@ -256,6 +263,7 @@ void msi_uninit(struct PCIDevice *dev)
cap_size = msi_cap_sizeof(flags);
pci_del_capability(dev, PCI_CAP_ID_MSI, cap_size);
dev->cap_present &= ~QEMU_PCI_CAP_MSI;
dev->msi_prepare_message = NULL;
MSI_DEV_PRINTF(dev, "uninit\n");
}
@ -307,6 +315,39 @@ bool msi_is_masked(const PCIDevice *dev, unsigned int vector)
return mask & (1U << vector);
}
void msi_set_mask(PCIDevice *dev, int vector, bool mask, Error **errp)
{
ERRP_GUARD();
uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
bool msi64bit = flags & PCI_MSI_FLAGS_64BIT;
uint32_t irq_state, vector_mask, pending;
if (vector > PCI_MSI_VECTORS_MAX) {
error_setg(errp, "msi: vector %d not allocated. max vector is %d",
vector, PCI_MSI_VECTORS_MAX);
return;
}
vector_mask = (1U << vector);
irq_state = pci_get_long(dev->config + msi_mask_off(dev, msi64bit));
if (mask) {
irq_state |= vector_mask;
} else {
irq_state &= ~vector_mask;
}
pci_set_long(dev->config + msi_mask_off(dev, msi64bit), irq_state);
pending = pci_get_long(dev->config + msi_pending_off(dev, msi64bit));
if (!mask && (pending & vector_mask)) {
pending &= ~vector_mask;
pci_set_long(dev->config + msi_pending_off(dev, msi64bit), pending);
msi_notify(dev, vector);
}
}
void msi_notify(PCIDevice *dev, unsigned int vector)
{
uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
@ -334,11 +375,7 @@ void msi_notify(PCIDevice *dev, unsigned int vector)
void msi_send_message(PCIDevice *dev, MSIMessage msg)
{
MemTxAttrs attrs = {};
attrs.requester_id = pci_requester_id(dev);
address_space_stl_le(&dev->bus_master_as, msg.address, msg.data,
attrs, NULL);
dev->msi_trigger(dev, msg);
}
/* Normally called by pci_default_write_config(). */

View File

@ -31,7 +31,7 @@
#define MSIX_ENABLE_MASK (PCI_MSIX_FLAGS_ENABLE >> 8)
#define MSIX_MASKALL_MASK (PCI_MSIX_FLAGS_MASKALL >> 8)
MSIMessage msix_get_message(PCIDevice *dev, unsigned vector)
static MSIMessage msix_prepare_message(PCIDevice *dev, unsigned vector)
{
uint8_t *table_entry = dev->msix_table + vector * PCI_MSIX_ENTRY_SIZE;
MSIMessage msg;
@ -41,6 +41,11 @@ MSIMessage msix_get_message(PCIDevice *dev, unsigned vector)
return msg;
}
MSIMessage msix_get_message(PCIDevice *dev, unsigned vector)
{
return dev->msix_prepare_message(dev, vector);
}
/*
* Special API for POWER to configure the vectors through
* a side channel. Should never be used by devices.
@ -131,6 +136,31 @@ static void msix_handle_mask_update(PCIDevice *dev, int vector, bool was_masked)
}
}
void msix_set_mask(PCIDevice *dev, int vector, bool mask, Error **errp)
{
ERRP_GUARD();
unsigned offset;
bool was_masked;
if (vector > dev->msix_entries_nr) {
error_setg(errp, "msix: vector %d not allocated. max vector is %d",
vector, dev->msix_entries_nr);
return;
}
offset = vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL;
was_masked = msix_is_masked(dev, vector);
if (mask) {
dev->msix_table[offset] |= PCI_MSIX_ENTRY_CTRL_MASKBIT;
} else {
dev->msix_table[offset] &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT;
}
msix_handle_mask_update(dev, vector, was_masked);
}
static bool msix_masked(PCIDevice *dev)
{
return dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & MSIX_MASKALL_MASK;
@ -344,6 +374,8 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries,
"msix-pba", pba_size);
memory_region_add_subregion(pba_bar, pba_offset, &dev->msix_pba_mmio);
dev->msix_prepare_message = msix_prepare_message;
return 0;
}
@ -429,6 +461,7 @@ void msix_uninit(PCIDevice *dev, MemoryRegion *table_bar, MemoryRegion *pba_bar)
g_free(dev->msix_entry_used);
dev->msix_entry_used = NULL;
dev->cap_present &= ~QEMU_PCI_CAP_MSIX;
dev->msix_prepare_message = NULL;
}
void msix_uninit_exclusive_bar(PCIDevice *dev)

View File

@ -317,6 +317,15 @@ void pci_device_deassert_intx(PCIDevice *dev)
}
}
static void pci_msi_trigger(PCIDevice *dev, MSIMessage msg)
{
MemTxAttrs attrs = {};
attrs.requester_id = pci_requester_id(dev);
address_space_stl_le(&dev->bus_master_as, msg.address, msg.data,
attrs, NULL);
}
static void pci_reset_regions(PCIDevice *dev)
{
int r;
@ -1212,6 +1221,8 @@ static void pci_qdev_unrealize(DeviceState *dev)
pci_device_deassert_intx(pci_dev);
do_pci_unregister_device(pci_dev);
pci_dev->msi_trigger = NULL;
}
void pci_register_bar(PCIDevice *pci_dev, int region_num,
@ -2251,6 +2262,8 @@ static void pci_qdev_realize(DeviceState *qdev, Error **errp)
}
pci_set_power(pci_dev, true);
pci_dev->msi_trigger = pci_msi_trigger;
}
PCIDevice *pci_new_multifunction(int devfn, bool multifunction,
@ -2640,15 +2653,15 @@ static char *pci_dev_fw_name(DeviceState *dev, char *buf, int len)
static char *pcibus_get_fw_dev_path(DeviceState *dev)
{
PCIDevice *d = (PCIDevice *)dev;
char path[50], name[33];
int off;
char name[33];
int has_func = !!PCI_FUNC(d->devfn);
off = snprintf(path, sizeof(path), "%s@%x",
pci_dev_fw_name(dev, name, sizeof name),
PCI_SLOT(d->devfn));
if (PCI_FUNC(d->devfn))
snprintf(path + off, sizeof(path) + off, ",%x", PCI_FUNC(d->devfn));
return g_strdup(path);
return g_strdup_printf("%s@%x%s%.*x",
pci_dev_fw_name(dev, name, sizeof(name)),
PCI_SLOT(d->devfn),
has_func ? "," : "",
has_func,
PCI_FUNC(d->devfn));
}
static char *pcibus_get_dev_path(DeviceState *dev)

View File

@ -2,3 +2,7 @@ config MULTIPROCESS
bool
depends on PCI && PCI_EXPRESS && KVM
select REMOTE_PCIHOST
config VFIO_USER_SERVER
bool
depends on MULTIPROCESS

131
hw/remote/iommu.c Normal file
View File

@ -0,0 +1,131 @@
/**
* IOMMU for remote device
*
* Copyright © 2022 Oracle and/or its affiliates.
*
* 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/remote/iommu.h"
#include "hw/pci/pci_bus.h"
#include "hw/pci/pci.h"
#include "exec/memory.h"
#include "exec/address-spaces.h"
#include "trace.h"
/**
* IOMMU for TYPE_REMOTE_MACHINE - manages DMA address space isolation
* for remote machine. It is used by TYPE_VFIO_USER_SERVER.
*
* - Each TYPE_VFIO_USER_SERVER instance handles one PCIDevice on a PCIBus.
* There is one RemoteIommu per PCIBus, so the RemoteIommu tracks multiple
* PCIDevices by maintaining a ->elem_by_devfn mapping.
*
* - memory_region_init_iommu() is not used because vfio-user MemoryRegions
* will be added to the elem->mr container instead. This is more natural
* than implementing the IOMMUMemoryRegionClass APIs since vfio-user
* provides something that is close to a full-fledged MemoryRegion and
* not like an IOMMU mapping.
*
* - When a device is hot unplugged, the elem->mr reference is dropped so
* all vfio-user MemoryRegions associated with this vfio-user server are
* destroyed.
*/
static AddressSpace *remote_iommu_find_add_as(PCIBus *pci_bus,
void *opaque, int devfn)
{
RemoteIommu *iommu = opaque;
RemoteIommuElem *elem = NULL;
qemu_mutex_lock(&iommu->lock);
elem = g_hash_table_lookup(iommu->elem_by_devfn, INT2VOIDP(devfn));
if (!elem) {
elem = g_malloc0(sizeof(RemoteIommuElem));
g_hash_table_insert(iommu->elem_by_devfn, INT2VOIDP(devfn), elem);
}
if (!elem->mr) {
elem->mr = MEMORY_REGION(object_new(TYPE_MEMORY_REGION));
memory_region_set_size(elem->mr, UINT64_MAX);
address_space_init(&elem->as, elem->mr, NULL);
}
qemu_mutex_unlock(&iommu->lock);
return &elem->as;
}
void remote_iommu_unplug_dev(PCIDevice *pci_dev)
{
AddressSpace *as = pci_device_iommu_address_space(pci_dev);
RemoteIommuElem *elem = NULL;
if (as == &address_space_memory) {
return;
}
elem = container_of(as, RemoteIommuElem, as);
address_space_destroy(&elem->as);
object_unref(elem->mr);
elem->mr = NULL;
}
static void remote_iommu_init(Object *obj)
{
RemoteIommu *iommu = REMOTE_IOMMU(obj);
iommu->elem_by_devfn = g_hash_table_new_full(NULL, NULL, NULL, g_free);
qemu_mutex_init(&iommu->lock);
}
static void remote_iommu_finalize(Object *obj)
{
RemoteIommu *iommu = REMOTE_IOMMU(obj);
qemu_mutex_destroy(&iommu->lock);
g_hash_table_destroy(iommu->elem_by_devfn);
iommu->elem_by_devfn = NULL;
}
void remote_iommu_setup(PCIBus *pci_bus)
{
RemoteIommu *iommu = NULL;
g_assert(pci_bus);
iommu = REMOTE_IOMMU(object_new(TYPE_REMOTE_IOMMU));
pci_setup_iommu(pci_bus, remote_iommu_find_add_as, iommu);
object_property_add_child(OBJECT(pci_bus), "remote-iommu", OBJECT(iommu));
object_unref(OBJECT(iommu));
}
static const TypeInfo remote_iommu_info = {
.name = TYPE_REMOTE_IOMMU,
.parent = TYPE_OBJECT,
.instance_size = sizeof(RemoteIommu),
.instance_init = remote_iommu_init,
.instance_finalize = remote_iommu_finalize,
};
static void remote_iommu_register_types(void)
{
type_register_static(&remote_iommu_info);
}
type_init(remote_iommu_register_types)

View File

@ -20,6 +20,11 @@
#include "qapi/error.h"
#include "hw/pci/pci_host.h"
#include "hw/remote/iohub.h"
#include "hw/remote/iommu.h"
#include "hw/qdev-core.h"
#include "hw/remote/iommu.h"
#include "hw/remote/vfio-user-obj.h"
#include "hw/pci/msi.h"
static void remote_machine_init(MachineState *machine)
{
@ -49,25 +54,102 @@ static void remote_machine_init(MachineState *machine)
pci_host = PCI_HOST_BRIDGE(rem_host);
remote_iohub_init(&s->iohub);
if (s->vfio_user) {
remote_iommu_setup(pci_host->bus);
pci_bus_irqs(pci_host->bus, remote_iohub_set_irq, remote_iohub_map_irq,
&s->iohub, REMOTE_IOHUB_NB_PIRQS);
msi_nonbroken = true;
vfu_object_set_bus_irq(pci_host->bus);
} else {
remote_iohub_init(&s->iohub);
pci_bus_irqs(pci_host->bus, remote_iohub_set_irq, remote_iohub_map_irq,
&s->iohub, REMOTE_IOHUB_NB_PIRQS);
}
qbus_set_hotplug_handler(BUS(pci_host->bus), OBJECT(s));
}
static bool remote_machine_get_vfio_user(Object *obj, Error **errp)
{
RemoteMachineState *s = REMOTE_MACHINE(obj);
return s->vfio_user;
}
static void remote_machine_set_vfio_user(Object *obj, bool value, Error **errp)
{
RemoteMachineState *s = REMOTE_MACHINE(obj);
if (phase_check(PHASE_MACHINE_CREATED)) {
error_setg(errp, "Error enabling vfio-user - machine already created");
return;
}
s->vfio_user = value;
}
static bool remote_machine_get_auto_shutdown(Object *obj, Error **errp)
{
RemoteMachineState *s = REMOTE_MACHINE(obj);
return s->auto_shutdown;
}
static void remote_machine_set_auto_shutdown(Object *obj, bool value,
Error **errp)
{
RemoteMachineState *s = REMOTE_MACHINE(obj);
s->auto_shutdown = value;
}
static void remote_machine_instance_init(Object *obj)
{
RemoteMachineState *s = REMOTE_MACHINE(obj);
s->auto_shutdown = true;
}
static void remote_machine_dev_unplug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
qdev_unrealize(dev);
if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
remote_iommu_unplug_dev(PCI_DEVICE(dev));
}
}
static void remote_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
mc->init = remote_machine_init;
mc->desc = "Experimental remote machine";
hc->unplug = remote_machine_dev_unplug_cb;
object_class_property_add_bool(oc, "vfio-user",
remote_machine_get_vfio_user,
remote_machine_set_vfio_user);
object_class_property_add_bool(oc, "auto-shutdown",
remote_machine_get_auto_shutdown,
remote_machine_set_auto_shutdown);
}
static const TypeInfo remote_machine = {
.name = TYPE_REMOTE_MACHINE,
.parent = TYPE_MACHINE,
.instance_size = sizeof(RemoteMachineState),
.instance_init = remote_machine_instance_init,
.class_init = remote_machine_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
}
};
static void remote_machine_register_types(void)

View File

@ -6,6 +6,10 @@ remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('message.c'))
remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('remote-obj.c'))
remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('proxy.c'))
remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('iohub.c'))
remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('iommu.c'))
remote_ss.add(when: 'CONFIG_VFIO_USER_SERVER', if_true: files('vfio-user-obj.c'))
remote_ss.add(when: 'CONFIG_VFIO_USER_SERVER', if_true: libvfio_user_dep)
specific_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('memory.c'))
specific_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('proxy-memory-listener.c'))

View File

@ -2,3 +2,14 @@
mpqemu_send_io_error(int cmd, int size, int nfds) "send command %d size %d, %d file descriptors to remote process"
mpqemu_recv_io_error(int cmd, int size, int nfds) "failed to receive %d size %d, %d file descriptors to remote process"
# vfio-user-obj.c
vfu_prop(const char *prop, const char *val) "vfu: setting %s as %s"
vfu_cfg_read(uint32_t offset, uint32_t val) "vfu: cfg: 0x%u -> 0x%x"
vfu_cfg_write(uint32_t offset, uint32_t val) "vfu: cfg: 0x%u <- 0x%x"
vfu_dma_register(uint64_t gpa, size_t len) "vfu: registering GPA 0x%"PRIx64", %zu bytes"
vfu_dma_unregister(uint64_t gpa) "vfu: unregistering GPA 0x%"PRIx64""
vfu_bar_register(int i, uint64_t addr, uint64_t size) "vfu: BAR %d: addr 0x%"PRIx64" size 0x%"PRIx64""
vfu_bar_rw_enter(const char *op, uint64_t addr) "vfu: %s request for BAR address 0x%"PRIx64""
vfu_bar_rw_exit(const char *op, uint64_t addr) "vfu: Finished %s of BAR address 0x%"PRIx64""
vfu_interrupt(int pirq) "vfu: sending interrupt to device - PIRQ %d"

958
hw/remote/vfio-user-obj.c Normal file
View File

@ -0,0 +1,958 @@
/**
* QEMU vfio-user-server server object
*
* Copyright © 2022 Oracle and/or its affiliates.
*
* This work is licensed under the terms of the GNU GPL-v2, version 2 or later.
*
* See the COPYING file in the top-level directory.
*
*/
/**
* Usage: add options:
* -machine x-remote,vfio-user=on,auto-shutdown=on
* -device <PCI-device>,id=<pci-dev-id>
* -object x-vfio-user-server,id=<id>,type=unix,path=<socket-path>,
* device=<pci-dev-id>
*
* Note that x-vfio-user-server object must be used with x-remote machine only.
* This server could only support PCI devices for now.
*
* type - SocketAddress type - presently "unix" alone is supported. Required
* option
*
* path - named unix socket, it will be created by the server. It is
* a required option
*
* device - id of a device on the server, a required option. PCI devices
* alone are supported presently.
*
* notes - x-vfio-user-server could block IO and monitor during the
* initialization phase.
*/
#include "qemu/osdep.h"
#include "qom/object.h"
#include "qom/object_interfaces.h"
#include "qemu/error-report.h"
#include "trace.h"
#include "sysemu/runstate.h"
#include "hw/boards.h"
#include "hw/remote/machine.h"
#include "qapi/error.h"
#include "qapi/qapi-visit-sockets.h"
#include "qapi/qapi-events-misc.h"
#include "qemu/notify.h"
#include "qemu/thread.h"
#include "qemu/main-loop.h"
#include "sysemu/sysemu.h"
#include "libvfio-user.h"
#include "hw/qdev-core.h"
#include "hw/pci/pci.h"
#include "qemu/timer.h"
#include "exec/memory.h"
#include "hw/pci/msi.h"
#include "hw/pci/msix.h"
#include "hw/remote/vfio-user-obj.h"
#define TYPE_VFU_OBJECT "x-vfio-user-server"
OBJECT_DECLARE_TYPE(VfuObject, VfuObjectClass, VFU_OBJECT)
/**
* VFU_OBJECT_ERROR - reports an error message. If auto_shutdown
* is set, it aborts the machine on error. Otherwise, it logs an
* error message without aborting.
*/
#define VFU_OBJECT_ERROR(o, fmt, ...) \
{ \
if (vfu_object_auto_shutdown()) { \
error_setg(&error_abort, (fmt), ## __VA_ARGS__); \
} else { \
error_report((fmt), ## __VA_ARGS__); \
} \
} \
struct VfuObjectClass {
ObjectClass parent_class;
unsigned int nr_devs;
};
struct VfuObject {
/* private */
Object parent;
SocketAddress *socket;
char *device;
Error *err;
Notifier machine_done;
vfu_ctx_t *vfu_ctx;
PCIDevice *pci_dev;
Error *unplug_blocker;
int vfu_poll_fd;
MSITriggerFunc *default_msi_trigger;
MSIPrepareMessageFunc *default_msi_prepare_message;
MSIxPrepareMessageFunc *default_msix_prepare_message;
};
static void vfu_object_init_ctx(VfuObject *o, Error **errp);
static bool vfu_object_auto_shutdown(void)
{
bool auto_shutdown = true;
Error *local_err = NULL;
if (!current_machine) {
return auto_shutdown;
}
auto_shutdown = object_property_get_bool(OBJECT(current_machine),
"auto-shutdown",
&local_err);
/*
* local_err would be set if no such property exists - safe to ignore.
* Unlikely scenario as auto-shutdown is always defined for
* TYPE_REMOTE_MACHINE, and TYPE_VFU_OBJECT only works with
* TYPE_REMOTE_MACHINE
*/
if (local_err) {
auto_shutdown = true;
error_free(local_err);
}
return auto_shutdown;
}
static void vfu_object_set_socket(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
VfuObject *o = VFU_OBJECT(obj);
if (o->vfu_ctx) {
error_setg(errp, "vfu: Unable to set socket property - server busy");
return;
}
qapi_free_SocketAddress(o->socket);
o->socket = NULL;
visit_type_SocketAddress(v, name, &o->socket, errp);
if (o->socket->type != SOCKET_ADDRESS_TYPE_UNIX) {
error_setg(errp, "vfu: Unsupported socket type - %s",
SocketAddressType_str(o->socket->type));
qapi_free_SocketAddress(o->socket);
o->socket = NULL;
return;
}
trace_vfu_prop("socket", o->socket->u.q_unix.path);
vfu_object_init_ctx(o, errp);
}
static void vfu_object_set_device(Object *obj, const char *str, Error **errp)
{
VfuObject *o = VFU_OBJECT(obj);
if (o->vfu_ctx) {
error_setg(errp, "vfu: Unable to set device property - server busy");
return;
}
g_free(o->device);
o->device = g_strdup(str);
trace_vfu_prop("device", str);
vfu_object_init_ctx(o, errp);
}
static void vfu_object_ctx_run(void *opaque)
{
VfuObject *o = opaque;
const char *vfu_id;
char *vfu_path, *pci_dev_path;
int ret = -1;
while (ret != 0) {
ret = vfu_run_ctx(o->vfu_ctx);
if (ret < 0) {
if (errno == EINTR) {
continue;
} else if (errno == ENOTCONN) {
vfu_id = object_get_canonical_path_component(OBJECT(o));
vfu_path = object_get_canonical_path(OBJECT(o));
g_assert(o->pci_dev);
pci_dev_path = object_get_canonical_path(OBJECT(o->pci_dev));
/* o->device is a required property and is non-NULL here */
g_assert(o->device);
qapi_event_send_vfu_client_hangup(vfu_id, vfu_path,
o->device, pci_dev_path);
qemu_set_fd_handler(o->vfu_poll_fd, NULL, NULL, NULL);
o->vfu_poll_fd = -1;
object_unparent(OBJECT(o));
g_free(vfu_path);
g_free(pci_dev_path);
break;
} else {
VFU_OBJECT_ERROR(o, "vfu: Failed to run device %s - %s",
o->device, strerror(errno));
break;
}
}
}
}
static void vfu_object_attach_ctx(void *opaque)
{
VfuObject *o = opaque;
GPollFD pfds[1];
int ret;
qemu_set_fd_handler(o->vfu_poll_fd, NULL, NULL, NULL);
pfds[0].fd = o->vfu_poll_fd;
pfds[0].events = G_IO_IN | G_IO_HUP | G_IO_ERR;
retry_attach:
ret = vfu_attach_ctx(o->vfu_ctx);
if (ret < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
/**
* vfu_object_attach_ctx can block QEMU's main loop
* during attach - the monitor and other IO
* could be unresponsive during this time.
*/
(void)qemu_poll_ns(pfds, 1, 500 * (int64_t)SCALE_MS);
goto retry_attach;
} else if (ret < 0) {
VFU_OBJECT_ERROR(o, "vfu: Failed to attach device %s to context - %s",
o->device, strerror(errno));
return;
}
o->vfu_poll_fd = vfu_get_poll_fd(o->vfu_ctx);
if (o->vfu_poll_fd < 0) {
VFU_OBJECT_ERROR(o, "vfu: Failed to get poll fd %s", o->device);
return;
}
qemu_set_fd_handler(o->vfu_poll_fd, vfu_object_ctx_run, NULL, o);
}
static ssize_t vfu_object_cfg_access(vfu_ctx_t *vfu_ctx, char * const buf,
size_t count, loff_t offset,
const bool is_write)
{
VfuObject *o = vfu_get_private(vfu_ctx);
uint32_t pci_access_width = sizeof(uint32_t);
size_t bytes = count;
uint32_t val = 0;
char *ptr = buf;
int len;
/*
* Writes to the BAR registers would trigger an update to the
* global Memory and IO AddressSpaces. But the remote device
* never uses the global AddressSpaces, therefore overlapping
* memory regions are not a problem
*/
while (bytes > 0) {
len = (bytes > pci_access_width) ? pci_access_width : bytes;
if (is_write) {
memcpy(&val, ptr, len);
pci_host_config_write_common(o->pci_dev, offset,
pci_config_size(o->pci_dev),
val, len);
trace_vfu_cfg_write(offset, val);
} else {
val = pci_host_config_read_common(o->pci_dev, offset,
pci_config_size(o->pci_dev), len);
memcpy(ptr, &val, len);
trace_vfu_cfg_read(offset, val);
}
offset += len;
ptr += len;
bytes -= len;
}
return count;
}
static void dma_register(vfu_ctx_t *vfu_ctx, vfu_dma_info_t *info)
{
VfuObject *o = vfu_get_private(vfu_ctx);
AddressSpace *dma_as = NULL;
MemoryRegion *subregion = NULL;
g_autofree char *name = NULL;
struct iovec *iov = &info->iova;
if (!info->vaddr) {
return;
}
name = g_strdup_printf("mem-%s-%"PRIx64"", o->device,
(uint64_t)info->vaddr);
subregion = g_new0(MemoryRegion, 1);
memory_region_init_ram_ptr(subregion, NULL, name,
iov->iov_len, info->vaddr);
dma_as = pci_device_iommu_address_space(o->pci_dev);
memory_region_add_subregion(dma_as->root, (hwaddr)iov->iov_base, subregion);
trace_vfu_dma_register((uint64_t)iov->iov_base, iov->iov_len);
}
static void dma_unregister(vfu_ctx_t *vfu_ctx, vfu_dma_info_t *info)
{
VfuObject *o = vfu_get_private(vfu_ctx);
AddressSpace *dma_as = NULL;
MemoryRegion *mr = NULL;
ram_addr_t offset;
mr = memory_region_from_host(info->vaddr, &offset);
if (!mr) {
return;
}
dma_as = pci_device_iommu_address_space(o->pci_dev);
memory_region_del_subregion(dma_as->root, mr);
object_unparent((OBJECT(mr)));
trace_vfu_dma_unregister((uint64_t)info->iova.iov_base);
}
static int vfu_object_mr_rw(MemoryRegion *mr, uint8_t *buf, hwaddr offset,
hwaddr size, const bool is_write)
{
uint8_t *ptr = buf;
bool release_lock = false;
uint8_t *ram_ptr = NULL;
MemTxResult result;
int access_size;
uint64_t val;
if (memory_access_is_direct(mr, is_write)) {
/**
* Some devices expose a PCI expansion ROM, which could be buffer
* based as compared to other regions which are primarily based on
* MemoryRegionOps. memory_region_find() would already check
* for buffer overflow, we don't need to repeat it here.
*/
ram_ptr = memory_region_get_ram_ptr(mr);
if (is_write) {
memcpy((ram_ptr + offset), buf, size);
} else {
memcpy(buf, (ram_ptr + offset), size);
}
return 0;
}
while (size) {
/**
* The read/write logic used below is similar to the ones in
* flatview_read/write_continue()
*/
release_lock = prepare_mmio_access(mr);
access_size = memory_access_size(mr, size, offset);
if (is_write) {
val = ldn_he_p(ptr, access_size);
result = memory_region_dispatch_write(mr, offset, val,
size_memop(access_size),
MEMTXATTRS_UNSPECIFIED);
} else {
result = memory_region_dispatch_read(mr, offset, &val,
size_memop(access_size),
MEMTXATTRS_UNSPECIFIED);
stn_he_p(ptr, access_size, val);
}
if (release_lock) {
qemu_mutex_unlock_iothread();
release_lock = false;
}
if (result != MEMTX_OK) {
return -1;
}
size -= access_size;
ptr += access_size;
offset += access_size;
}
return 0;
}
static size_t vfu_object_bar_rw(PCIDevice *pci_dev, int pci_bar,
hwaddr bar_offset, char * const buf,
hwaddr len, const bool is_write)
{
MemoryRegionSection section = { 0 };
uint8_t *ptr = (uint8_t *)buf;
MemoryRegion *section_mr = NULL;
uint64_t section_size;
hwaddr section_offset;
hwaddr size = 0;
while (len) {
section = memory_region_find(pci_dev->io_regions[pci_bar].memory,
bar_offset, len);
if (!section.mr) {
warn_report("vfu: invalid address 0x%"PRIx64"", bar_offset);
return size;
}
section_mr = section.mr;
section_offset = section.offset_within_region;
section_size = int128_get64(section.size);
if (is_write && section_mr->readonly) {
warn_report("vfu: attempting to write to readonly region in "
"bar %d - [0x%"PRIx64" - 0x%"PRIx64"]",
pci_bar, bar_offset,
(bar_offset + section_size));
memory_region_unref(section_mr);
return size;
}
if (vfu_object_mr_rw(section_mr, ptr, section_offset,
section_size, is_write)) {
warn_report("vfu: failed to %s "
"[0x%"PRIx64" - 0x%"PRIx64"] in bar %d",
is_write ? "write to" : "read from", bar_offset,
(bar_offset + section_size), pci_bar);
memory_region_unref(section_mr);
return size;
}
size += section_size;
bar_offset += section_size;
ptr += section_size;
len -= section_size;
memory_region_unref(section_mr);
}
return size;
}
/**
* VFU_OBJECT_BAR_HANDLER - macro for defining handlers for PCI BARs.
*
* To create handler for BAR number 2, VFU_OBJECT_BAR_HANDLER(2) would
* define vfu_object_bar2_handler
*/
#define VFU_OBJECT_BAR_HANDLER(BAR_NO) \
static ssize_t vfu_object_bar##BAR_NO##_handler(vfu_ctx_t *vfu_ctx, \
char * const buf, size_t count, \
loff_t offset, const bool is_write) \
{ \
VfuObject *o = vfu_get_private(vfu_ctx); \
PCIDevice *pci_dev = o->pci_dev; \
\
return vfu_object_bar_rw(pci_dev, BAR_NO, offset, \
buf, count, is_write); \
} \
VFU_OBJECT_BAR_HANDLER(0)
VFU_OBJECT_BAR_HANDLER(1)
VFU_OBJECT_BAR_HANDLER(2)
VFU_OBJECT_BAR_HANDLER(3)
VFU_OBJECT_BAR_HANDLER(4)
VFU_OBJECT_BAR_HANDLER(5)
VFU_OBJECT_BAR_HANDLER(6)
static vfu_region_access_cb_t *vfu_object_bar_handlers[PCI_NUM_REGIONS] = {
&vfu_object_bar0_handler,
&vfu_object_bar1_handler,
&vfu_object_bar2_handler,
&vfu_object_bar3_handler,
&vfu_object_bar4_handler,
&vfu_object_bar5_handler,
&vfu_object_bar6_handler,
};
/**
* vfu_object_register_bars - Identify active BAR regions of pdev and setup
* callbacks to handle read/write accesses
*/
static void vfu_object_register_bars(vfu_ctx_t *vfu_ctx, PCIDevice *pdev)
{
int flags = VFU_REGION_FLAG_RW;
int i;
for (i = 0; i < PCI_NUM_REGIONS; i++) {
if (!pdev->io_regions[i].size) {
continue;
}
if ((i == VFU_PCI_DEV_ROM_REGION_IDX) ||
pdev->io_regions[i].memory->readonly) {
flags &= ~VFU_REGION_FLAG_WRITE;
}
vfu_setup_region(vfu_ctx, VFU_PCI_DEV_BAR0_REGION_IDX + i,
(size_t)pdev->io_regions[i].size,
vfu_object_bar_handlers[i],
flags, NULL, 0, -1, 0);
trace_vfu_bar_register(i, pdev->io_regions[i].addr,
pdev->io_regions[i].size);
}
}
static int vfu_object_map_irq(PCIDevice *pci_dev, int intx)
{
int pci_bdf = PCI_BUILD_BDF(pci_bus_num(pci_get_bus(pci_dev)),
pci_dev->devfn);
return pci_bdf;
}
static void vfu_object_set_irq(void *opaque, int pirq, int level)
{
PCIBus *pci_bus = opaque;
PCIDevice *pci_dev = NULL;
vfu_ctx_t *vfu_ctx = NULL;
int pci_bus_num, devfn;
if (level) {
pci_bus_num = PCI_BUS_NUM(pirq);
devfn = PCI_BDF_TO_DEVFN(pirq);
/*
* pci_find_device() performs at O(1) if the device is attached
* to the root PCI bus. Whereas, if the device is attached to a
* secondary PCI bus (such as when a root port is involved),
* finding the parent PCI bus could take O(n)
*/
pci_dev = pci_find_device(pci_bus, pci_bus_num, devfn);
vfu_ctx = pci_dev->irq_opaque;
g_assert(vfu_ctx);
vfu_irq_trigger(vfu_ctx, 0);
}
}
static MSIMessage vfu_object_msi_prepare_msg(PCIDevice *pci_dev,
unsigned int vector)
{
MSIMessage msg;
msg.address = 0;
msg.data = vector;
return msg;
}
static void vfu_object_msi_trigger(PCIDevice *pci_dev, MSIMessage msg)
{
vfu_ctx_t *vfu_ctx = pci_dev->irq_opaque;
vfu_irq_trigger(vfu_ctx, msg.data);
}
static void vfu_object_setup_msi_cbs(VfuObject *o)
{
o->default_msi_trigger = o->pci_dev->msi_trigger;
o->default_msi_prepare_message = o->pci_dev->msi_prepare_message;
o->default_msix_prepare_message = o->pci_dev->msix_prepare_message;
o->pci_dev->msi_trigger = vfu_object_msi_trigger;
o->pci_dev->msi_prepare_message = vfu_object_msi_prepare_msg;
o->pci_dev->msix_prepare_message = vfu_object_msi_prepare_msg;
}
static void vfu_object_restore_msi_cbs(VfuObject *o)
{
o->pci_dev->msi_trigger = o->default_msi_trigger;
o->pci_dev->msi_prepare_message = o->default_msi_prepare_message;
o->pci_dev->msix_prepare_message = o->default_msix_prepare_message;
}
static void vfu_msix_irq_state(vfu_ctx_t *vfu_ctx, uint32_t start,
uint32_t count, bool mask)
{
VfuObject *o = vfu_get_private(vfu_ctx);
Error *err = NULL;
uint32_t vector;
for (vector = start; vector < count; vector++) {
msix_set_mask(o->pci_dev, vector, mask, &err);
if (err) {
VFU_OBJECT_ERROR(o, "vfu: %s: %s", o->device,
error_get_pretty(err));
error_free(err);
err = NULL;
}
}
}
static void vfu_msi_irq_state(vfu_ctx_t *vfu_ctx, uint32_t start,
uint32_t count, bool mask)
{
VfuObject *o = vfu_get_private(vfu_ctx);
Error *err = NULL;
uint32_t vector;
for (vector = start; vector < count; vector++) {
msi_set_mask(o->pci_dev, vector, mask, &err);
if (err) {
VFU_OBJECT_ERROR(o, "vfu: %s: %s", o->device,
error_get_pretty(err));
error_free(err);
err = NULL;
}
}
}
static int vfu_object_setup_irqs(VfuObject *o, PCIDevice *pci_dev)
{
vfu_ctx_t *vfu_ctx = o->vfu_ctx;
int ret;
ret = vfu_setup_device_nr_irqs(vfu_ctx, VFU_DEV_INTX_IRQ, 1);
if (ret < 0) {
return ret;
}
if (msix_nr_vectors_allocated(pci_dev)) {
ret = vfu_setup_device_nr_irqs(vfu_ctx, VFU_DEV_MSIX_IRQ,
msix_nr_vectors_allocated(pci_dev));
vfu_setup_irq_state_callback(vfu_ctx, VFU_DEV_MSIX_IRQ,
&vfu_msix_irq_state);
} else if (msi_nr_vectors_allocated(pci_dev)) {
ret = vfu_setup_device_nr_irqs(vfu_ctx, VFU_DEV_MSI_IRQ,
msi_nr_vectors_allocated(pci_dev));
vfu_setup_irq_state_callback(vfu_ctx, VFU_DEV_MSI_IRQ,
&vfu_msi_irq_state);
}
if (ret < 0) {
return ret;
}
vfu_object_setup_msi_cbs(o);
pci_dev->irq_opaque = vfu_ctx;
return 0;
}
void vfu_object_set_bus_irq(PCIBus *pci_bus)
{
int bus_num = pci_bus_num(pci_bus);
int max_bdf = PCI_BUILD_BDF(bus_num, PCI_DEVFN_MAX - 1);
pci_bus_irqs(pci_bus, vfu_object_set_irq, vfu_object_map_irq, pci_bus,
max_bdf);
}
static int vfu_object_device_reset(vfu_ctx_t *vfu_ctx, vfu_reset_type_t type)
{
VfuObject *o = vfu_get_private(vfu_ctx);
/* vfu_object_ctx_run() handles lost connection */
if (type == VFU_RESET_LOST_CONN) {
return 0;
}
qdev_reset_all(DEVICE(o->pci_dev));
return 0;
}
/*
* TYPE_VFU_OBJECT depends on the availability of the 'socket' and 'device'
* properties. It also depends on devices instantiated in QEMU. These
* dependencies are not available during the instance_init phase of this
* object's life-cycle. As such, the server is initialized after the
* machine is setup. machine_init_done_notifier notifies TYPE_VFU_OBJECT
* when the machine is setup, and the dependencies are available.
*/
static void vfu_object_machine_done(Notifier *notifier, void *data)
{
VfuObject *o = container_of(notifier, VfuObject, machine_done);
Error *err = NULL;
vfu_object_init_ctx(o, &err);
if (err) {
error_propagate(&error_abort, err);
}
}
/**
* vfu_object_init_ctx: Create and initialize libvfio-user context. Add
* an unplug blocker for the associated PCI device. Setup a FD handler
* to process incoming messages in the context's socket.
*
* The socket and device properties are mandatory, and this function
* will not create the context without them - the setters for these
* properties should call this function when the property is set. The
* machine should also be ready when this function is invoked - it is
* because QEMU objects are initialized before devices, and the
* associated PCI device wouldn't be available at the object
* initialization time. Until these conditions are satisfied, this
* function would return early without performing any task.
*/
static void vfu_object_init_ctx(VfuObject *o, Error **errp)
{
ERRP_GUARD();
DeviceState *dev = NULL;
vfu_pci_type_t pci_type = VFU_PCI_TYPE_CONVENTIONAL;
int ret;
if (o->vfu_ctx || !o->socket || !o->device ||
!phase_check(PHASE_MACHINE_READY)) {
return;
}
if (o->err) {
error_propagate(errp, o->err);
o->err = NULL;
return;
}
o->vfu_ctx = vfu_create_ctx(VFU_TRANS_SOCK, o->socket->u.q_unix.path,
LIBVFIO_USER_FLAG_ATTACH_NB,
o, VFU_DEV_TYPE_PCI);
if (o->vfu_ctx == NULL) {
error_setg(errp, "vfu: Failed to create context - %s", strerror(errno));
return;
}
dev = qdev_find_recursive(sysbus_get_default(), o->device);
if (dev == NULL) {
error_setg(errp, "vfu: Device %s not found", o->device);
goto fail;
}
if (!object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
error_setg(errp, "vfu: %s not a PCI device", o->device);
goto fail;
}
o->pci_dev = PCI_DEVICE(dev);
object_ref(OBJECT(o->pci_dev));
if (pci_is_express(o->pci_dev)) {
pci_type = VFU_PCI_TYPE_EXPRESS;
}
ret = vfu_pci_init(o->vfu_ctx, pci_type, PCI_HEADER_TYPE_NORMAL, 0);
if (ret < 0) {
error_setg(errp,
"vfu: Failed to attach PCI device %s to context - %s",
o->device, strerror(errno));
goto fail;
}
error_setg(&o->unplug_blocker,
"vfu: %s for %s must be deleted before unplugging",
TYPE_VFU_OBJECT, o->device);
qdev_add_unplug_blocker(DEVICE(o->pci_dev), o->unplug_blocker);
ret = vfu_setup_region(o->vfu_ctx, VFU_PCI_DEV_CFG_REGION_IDX,
pci_config_size(o->pci_dev), &vfu_object_cfg_access,
VFU_REGION_FLAG_RW | VFU_REGION_FLAG_ALWAYS_CB,
NULL, 0, -1, 0);
if (ret < 0) {
error_setg(errp,
"vfu: Failed to setup config space handlers for %s- %s",
o->device, strerror(errno));
goto fail;
}
ret = vfu_setup_device_dma(o->vfu_ctx, &dma_register, &dma_unregister);
if (ret < 0) {
error_setg(errp, "vfu: Failed to setup DMA handlers for %s",
o->device);
goto fail;
}
vfu_object_register_bars(o->vfu_ctx, o->pci_dev);
ret = vfu_object_setup_irqs(o, o->pci_dev);
if (ret < 0) {
error_setg(errp, "vfu: Failed to setup interrupts for %s",
o->device);
goto fail;
}
ret = vfu_setup_device_reset_cb(o->vfu_ctx, &vfu_object_device_reset);
if (ret < 0) {
error_setg(errp, "vfu: Failed to setup reset callback");
goto fail;
}
ret = vfu_realize_ctx(o->vfu_ctx);
if (ret < 0) {
error_setg(errp, "vfu: Failed to realize device %s- %s",
o->device, strerror(errno));
goto fail;
}
o->vfu_poll_fd = vfu_get_poll_fd(o->vfu_ctx);
if (o->vfu_poll_fd < 0) {
error_setg(errp, "vfu: Failed to get poll fd %s", o->device);
goto fail;
}
qemu_set_fd_handler(o->vfu_poll_fd, vfu_object_attach_ctx, NULL, o);
return;
fail:
vfu_destroy_ctx(o->vfu_ctx);
if (o->unplug_blocker && o->pci_dev) {
qdev_del_unplug_blocker(DEVICE(o->pci_dev), o->unplug_blocker);
error_free(o->unplug_blocker);
o->unplug_blocker = NULL;
}
if (o->pci_dev) {
vfu_object_restore_msi_cbs(o);
o->pci_dev->irq_opaque = NULL;
object_unref(OBJECT(o->pci_dev));
o->pci_dev = NULL;
}
o->vfu_ctx = NULL;
}
static void vfu_object_init(Object *obj)
{
VfuObjectClass *k = VFU_OBJECT_GET_CLASS(obj);
VfuObject *o = VFU_OBJECT(obj);
k->nr_devs++;
if (!object_dynamic_cast(OBJECT(current_machine), TYPE_REMOTE_MACHINE)) {
error_setg(&o->err, "vfu: %s only compatible with %s machine",
TYPE_VFU_OBJECT, TYPE_REMOTE_MACHINE);
return;
}
if (!phase_check(PHASE_MACHINE_READY)) {
o->machine_done.notify = vfu_object_machine_done;
qemu_add_machine_init_done_notifier(&o->machine_done);
}
o->vfu_poll_fd = -1;
}
static void vfu_object_finalize(Object *obj)
{
VfuObjectClass *k = VFU_OBJECT_GET_CLASS(obj);
VfuObject *o = VFU_OBJECT(obj);
k->nr_devs--;
qapi_free_SocketAddress(o->socket);
o->socket = NULL;
if (o->vfu_poll_fd != -1) {
qemu_set_fd_handler(o->vfu_poll_fd, NULL, NULL, NULL);
o->vfu_poll_fd = -1;
}
if (o->vfu_ctx) {
vfu_destroy_ctx(o->vfu_ctx);
o->vfu_ctx = NULL;
}
g_free(o->device);
o->device = NULL;
if (o->unplug_blocker && o->pci_dev) {
qdev_del_unplug_blocker(DEVICE(o->pci_dev), o->unplug_blocker);
error_free(o->unplug_blocker);
o->unplug_blocker = NULL;
}
if (o->pci_dev) {
vfu_object_restore_msi_cbs(o);
o->pci_dev->irq_opaque = NULL;
object_unref(OBJECT(o->pci_dev));
o->pci_dev = NULL;
}
if (!k->nr_devs && vfu_object_auto_shutdown()) {
qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
}
if (o->machine_done.notify) {
qemu_remove_machine_init_done_notifier(&o->machine_done);
o->machine_done.notify = NULL;
}
}
static void vfu_object_class_init(ObjectClass *klass, void *data)
{
VfuObjectClass *k = VFU_OBJECT_CLASS(klass);
k->nr_devs = 0;
object_class_property_add(klass, "socket", "SocketAddress", NULL,
vfu_object_set_socket, NULL, NULL);
object_class_property_set_description(klass, "socket",
"SocketAddress "
"(ex: type=unix,path=/tmp/sock). "
"Only UNIX is presently supported");
object_class_property_add_str(klass, "device", NULL,
vfu_object_set_device);
object_class_property_set_description(klass, "device",
"device ID - only PCI devices "
"are presently supported");
}
static const TypeInfo vfu_object_info = {
.name = TYPE_VFU_OBJECT,
.parent = TYPE_OBJECT,
.instance_size = sizeof(VfuObject),
.instance_init = vfu_object_init,
.instance_finalize = vfu_object_finalize,
.class_size = sizeof(VfuObjectClass),
.class_init = vfu_object_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_USER_CREATABLE },
{ }
}
};
static void vfu_register_types(void)
{
type_register_static(&vfu_object_info);
}
type_init(vfu_register_types);

View File

@ -26,7 +26,7 @@
#include "qemu/cutils.h"
#include "qemu/module.h"
#include "qemu/bcd.h"
#include "hw/acpi/aml-build.h"
#include "hw/acpi/acpi_aml_interface.h"
#include "hw/irq.h"
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"
@ -74,6 +74,8 @@
#define RTC_CLOCK_RATE 32768
#define UIP_HOLD_LENGTH (8 * NANOSECONDS_PER_SECOND / 32768)
#define RTC_ISA_BASE 0x70
static void rtc_set_time(RTCState *s);
static void rtc_update_time(RTCState *s);
static void rtc_set_cmos(RTCState *s, const struct tm *tm);
@ -941,7 +943,7 @@ static void rtc_realizefn(DeviceState *dev, Error **errp)
qemu_register_suspend_notifier(&s->suspend_notifier);
memory_region_init_io(&s->io, OBJECT(s), &cmos_ops, s, "rtc", 2);
isa_register_ioport(isadev, &s->io, RTC_ISA_BASE);
isa_register_ioport(isadev, &s->io, s->io_base);
/* register rtc 0x70 port for coalesced_pio */
memory_region_set_flush_coalesced(&s->io);
@ -950,7 +952,7 @@ static void rtc_realizefn(DeviceState *dev, Error **errp)
memory_region_add_subregion(&s->io, 0, &s->coalesced_io);
memory_region_add_coalescing(&s->coalesced_io, 0, 1);
qdev_set_legacy_instance_id(dev, RTC_ISA_BASE, 3);
qdev_set_legacy_instance_id(dev, s->io_base, 3);
object_property_add_tm(OBJECT(s), "date", rtc_get_date);
@ -983,6 +985,7 @@ ISADevice *mc146818_rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq)
static Property mc146818rtc_properties[] = {
DEFINE_PROP_INT32("base_year", RTCState, base_year, 1980),
DEFINE_PROP_UINT16("iobase", RTCState, io_base, RTC_ISA_BASE),
DEFINE_PROP_UINT8("irq", RTCState, isairq, RTC_ISA_IRQ),
DEFINE_PROP_LOSTTICKPOLICY("lost_tick_policy", RTCState,
lost_tick_policy, LOST_TICK_POLICY_DISCARD),
@ -1017,9 +1020,9 @@ static void rtc_reset_hold(Object *obj)
qemu_irq_lower(s->irq);
}
static void rtc_build_aml(ISADevice *isadev, Aml *scope)
static void rtc_build_aml(AcpiDevAmlIf *adev, Aml *scope)
{
RTCState *s = MC146818_RTC(isadev);
RTCState *s = MC146818_RTC(adev);
Aml *dev;
Aml *crs;
@ -1028,7 +1031,7 @@ static void rtc_build_aml(ISADevice *isadev, Aml *scope)
* does, even though qemu only responds to the first two ports.
*/
crs = aml_resource_template();
aml_append(crs, aml_io(AML_DECODE16, RTC_ISA_BASE, RTC_ISA_BASE,
aml_append(crs, aml_io(AML_DECODE16, s->io_base, s->io_base,
0x01, 0x08));
aml_append(crs, aml_irq_no_flags(s->isairq));
@ -1043,13 +1046,13 @@ static void rtc_class_initfn(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
ISADeviceClass *isa = ISA_DEVICE_CLASS(klass);
AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
dc->realize = rtc_realizefn;
dc->vmsd = &vmstate_rtc;
rc->phases.enter = rtc_reset_enter;
rc->phases.hold = rtc_reset_hold;
isa->build_aml = rtc_build_aml;
adevc->build_dev_aml = rtc_build_aml;
device_class_set_props(dc, mc146818rtc_properties);
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
}
@ -1059,6 +1062,10 @@ static const TypeInfo mc146818rtc_info = {
.parent = TYPE_ISA_DEVICE,
.instance_size = sizeof(RTCState),
.class_init = rtc_class_initfn,
.interfaces = (InterfaceInfo[]) {
{ TYPE_ACPI_DEV_AML_IF },
{ },
},
};
static void mc146818rtc_register_types(void)

View File

@ -121,7 +121,6 @@ static void vhost_user_scsi_realize(DeviceState *dev, Error **errp)
vsc->dev.backend_features = 0;
vqs = vsc->dev.vqs;
s->vhost_user.supports_config = true;
ret = vhost_dev_init(&vsc->dev, &s->vhost_user,
VHOST_BACKEND_TYPE_USER, 0, errp);
if (ret < 0) {

View File

@ -334,7 +334,7 @@ static void ebus_realize(PCIDevice *pci_dev, Error **errp)
parallel_hds_isa_init(s->isa_bus, MAX_PARALLEL_PORTS);
/* Keyboard */
isa_create_simple(s->isa_bus, "i8042");
isa_create_simple(s->isa_bus, TYPE_I8042);
/* Floppy */
for (i = 0; i < MAX_FD; i++) {

View File

@ -30,6 +30,7 @@
#include "tpm_prop.h"
#include "tpm_tis.h"
#include "qom/object.h"
#include "hw/acpi/acpi_aml_interface.h"
struct TPMStateISA {
/*< private >*/
@ -138,10 +139,39 @@ static void tpm_tis_isa_realizefn(DeviceState *dev, Error **errp)
}
}
static void build_tpm_tis_isa_aml(AcpiDevAmlIf *adev, Aml *scope)
{
Aml *dev, *crs;
TPMStateISA *isadev = TPM_TIS_ISA(adev);
TPMIf *ti = TPM_IF(isadev);
dev = aml_device("TPM");
if (tpm_tis_isa_get_tpm_version(ti) == TPM_VERSION_2_0) {
aml_append(dev, aml_name_decl("_HID", aml_string("MSFT0101")));
aml_append(dev, aml_name_decl("_STR", aml_string("TPM 2.0 Device")));
} else {
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C31")));
}
aml_append(dev, aml_name_decl("_UID", aml_int(1)));
aml_append(dev, aml_name_decl("_STA", aml_int(0xF)));
crs = aml_resource_template();
aml_append(crs, aml_memory32_fixed(TPM_TIS_ADDR_BASE, TPM_TIS_ADDR_SIZE,
AML_READ_WRITE));
/*
* FIXME: TPM_TIS_IRQ=5 conflicts with PNP0C0F irqs,
* fix default TPM_TIS_IRQ value there to use some unused IRQ
*/
/* aml_append(crs, aml_irq_no_flags(isadev->state.irq_num)); */
aml_append(dev, aml_name_decl("_CRS", crs));
tpm_build_ppi_acpi(ti, dev);
aml_append(scope, dev);
}
static void tpm_tis_isa_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
TPMIfClass *tc = TPM_IF_CLASS(klass);
AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
device_class_set_props(dc, tpm_tis_isa_properties);
dc->vmsd = &vmstate_tpm_tis_isa;
@ -151,6 +181,7 @@ static void tpm_tis_isa_class_init(ObjectClass *klass, void *data)
tc->request_completed = tpm_tis_isa_request_completed;
tc->get_version = tpm_tis_isa_get_tpm_version;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
adevc->build_dev_aml = build_tpm_tis_isa_aml;
}
static const TypeInfo tpm_tis_isa_info = {
@ -161,6 +192,7 @@ static const TypeInfo tpm_tis_isa_info = {
.class_init = tpm_tis_isa_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_TPM_IF },
{ TYPE_ACPI_DEV_AML_IF },
{ }
}
};

View File

@ -119,6 +119,11 @@ config USB_U2F
default y
depends on USB
config USB_CANOKEY
bool
default y
depends on USB
config IMX_USBPHY
bool
default y

313
hw/usb/canokey.c Normal file
View File

@ -0,0 +1,313 @@
/*
* CanoKey QEMU device implementation.
*
* Copyright (c) 2021-2022 Canokeys.org <contact@canokeys.org>
* Written by Hongren (Zenithal) Zheng <i@zenithal.me>
*
* This code is licensed under the Apache-2.0.
*/
#include "qemu/osdep.h"
#include <canokey-qemu.h>
#include "qemu/module.h"
#include "qapi/error.h"
#include "hw/usb.h"
#include "hw/qdev-properties.h"
#include "trace.h"
#include "desc.h"
#include "canokey.h"
#define CANOKEY_EP_IN(ep) ((ep) & 0x7F)
#define CANOKEY_VENDOR_NUM 0x20a0
#define CANOKEY_PRODUCT_NUM 0x42d2
/*
* placeholder, canokey-qemu implements its own usb desc
* Namely we do not use usb_desc_handle_contorl
*/
enum {
STR_MANUFACTURER = 1,
STR_PRODUCT,
STR_SERIALNUMBER
};
static const USBDescStrings desc_strings = {
[STR_MANUFACTURER] = "canokeys.org",
[STR_PRODUCT] = "CanoKey QEMU",
[STR_SERIALNUMBER] = "0"
};
static const USBDescDevice desc_device_canokey = {
.bcdUSB = 0x0,
.bMaxPacketSize0 = 16,
.bNumConfigurations = 0,
.confs = NULL,
};
static const USBDesc desc_canokey = {
.id = {
.idVendor = CANOKEY_VENDOR_NUM,
.idProduct = CANOKEY_PRODUCT_NUM,
.bcdDevice = 0x0100,
.iManufacturer = STR_MANUFACTURER,
.iProduct = STR_PRODUCT,
.iSerialNumber = STR_SERIALNUMBER,
},
.full = &desc_device_canokey,
.high = &desc_device_canokey,
.str = desc_strings,
};
/*
* libcanokey-qemu.so side functions
* All functions are called from canokey_emu_device_loop
*/
int canokey_emu_stall_ep(void *base, uint8_t ep)
{
trace_canokey_emu_stall_ep(ep);
CanoKeyState *key = base;
uint8_t ep_in = CANOKEY_EP_IN(ep); /* INTR IN has ep 129 */
key->ep_in_size[ep_in] = 0;
key->ep_in_state[ep_in] = CANOKEY_EP_IN_STALL;
return 0;
}
int canokey_emu_set_address(void *base, uint8_t addr)
{
trace_canokey_emu_set_address(addr);
CanoKeyState *key = base;
key->dev.addr = addr;
return 0;
}
int canokey_emu_prepare_receive(
void *base, uint8_t ep, uint8_t *pbuf, uint16_t size)
{
trace_canokey_emu_prepare_receive(ep, size);
CanoKeyState *key = base;
key->ep_out[ep] = pbuf;
key->ep_out_size[ep] = size;
return 0;
}
int canokey_emu_transmit(
void *base, uint8_t ep, const uint8_t *pbuf, uint16_t size)
{
trace_canokey_emu_transmit(ep, size);
CanoKeyState *key = base;
uint8_t ep_in = CANOKEY_EP_IN(ep); /* INTR IN has ep 129 */
memcpy(key->ep_in[ep_in] + key->ep_in_size[ep_in],
pbuf, size);
key->ep_in_size[ep_in] += size;
key->ep_in_state[ep_in] = CANOKEY_EP_IN_READY;
/*
* ready for more data in device loop
*
* Note: this is a quirk for CanoKey CTAPHID
* because it calls multiple emu_transmit in one device_loop
* but w/o data_in it would stuck in device_loop
* This has no side effect for CCID as it is strictly
* OUT then IN transfer
* However it has side effect for Control transfer
*/
if (ep_in != 0) {
canokey_emu_data_in(ep_in);
}
return 0;
}
uint32_t canokey_emu_get_rx_data_size(void *base, uint8_t ep)
{
CanoKeyState *key = base;
return key->ep_out_size[ep];
}
/*
* QEMU side functions
*/
static void canokey_handle_reset(USBDevice *dev)
{
trace_canokey_handle_reset();
CanoKeyState *key = CANOKEY(dev);
for (int i = 0; i != CANOKEY_EP_NUM; ++i) {
key->ep_in_state[i] = CANOKEY_EP_IN_WAIT;
key->ep_in_pos[i] = 0;
key->ep_in_size[i] = 0;
}
canokey_emu_reset();
}
static void canokey_handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data)
{
trace_canokey_handle_control_setup(request, value, index, length);
CanoKeyState *key = CANOKEY(dev);
canokey_emu_setup(request, value, index, length);
uint32_t dir_in = request & DeviceRequest;
if (!dir_in) {
/* OUT */
trace_canokey_handle_control_out();
if (key->ep_out[0] != NULL) {
memcpy(key->ep_out[0], data, length);
}
canokey_emu_data_out(p->ep->nr, data);
}
canokey_emu_device_loop();
/* IN */
switch (key->ep_in_state[0]) {
case CANOKEY_EP_IN_WAIT:
p->status = USB_RET_NAK;
break;
case CANOKEY_EP_IN_STALL:
p->status = USB_RET_STALL;
break;
case CANOKEY_EP_IN_READY:
memcpy(data, key->ep_in[0], key->ep_in_size[0]);
p->actual_length = key->ep_in_size[0];
trace_canokey_handle_control_in(p->actual_length);
/* reset state */
key->ep_in_state[0] = CANOKEY_EP_IN_WAIT;
key->ep_in_size[0] = 0;
key->ep_in_pos[0] = 0;
break;
}
}
static void canokey_handle_data(USBDevice *dev, USBPacket *p)
{
CanoKeyState *key = CANOKEY(dev);
uint8_t ep_in = CANOKEY_EP_IN(p->ep->nr);
uint8_t ep_out = p->ep->nr;
uint32_t in_len;
uint32_t out_pos;
uint32_t out_len;
switch (p->pid) {
case USB_TOKEN_OUT:
trace_canokey_handle_data_out(ep_out, p->iov.size);
usb_packet_copy(p, key->ep_out_buffer[ep_out], p->iov.size);
out_pos = 0;
while (out_pos != p->iov.size) {
/*
* key->ep_out[ep_out] set by prepare_receive
* to be a buffer inside libcanokey-qemu.so
* key->ep_out_size[ep_out] set by prepare_receive
* to be the buffer length
*/
out_len = MIN(p->iov.size - out_pos, key->ep_out_size[ep_out]);
memcpy(key->ep_out[ep_out],
key->ep_out_buffer[ep_out] + out_pos, out_len);
out_pos += out_len;
/* update ep_out_size to actual len */
key->ep_out_size[ep_out] = out_len;
canokey_emu_data_out(ep_out, NULL);
}
break;
case USB_TOKEN_IN:
if (key->ep_in_pos[ep_in] == 0) { /* first time IN */
canokey_emu_data_in(ep_in);
canokey_emu_device_loop(); /* may call transmit multiple times */
}
switch (key->ep_in_state[ep_in]) {
case CANOKEY_EP_IN_WAIT:
/* NAK for early INTR IN */
p->status = USB_RET_NAK;
break;
case CANOKEY_EP_IN_STALL:
p->status = USB_RET_STALL;
break;
case CANOKEY_EP_IN_READY:
/* submit part of ep_in buffer to USBPacket */
in_len = MIN(key->ep_in_size[ep_in] - key->ep_in_pos[ep_in],
p->iov.size);
usb_packet_copy(p,
key->ep_in[ep_in] + key->ep_in_pos[ep_in], in_len);
key->ep_in_pos[ep_in] += in_len;
/* reset state if all data submitted */
if (key->ep_in_pos[ep_in] == key->ep_in_size[ep_in]) {
key->ep_in_state[ep_in] = CANOKEY_EP_IN_WAIT;
key->ep_in_size[ep_in] = 0;
key->ep_in_pos[ep_in] = 0;
}
trace_canokey_handle_data_in(ep_in, in_len);
break;
}
break;
default:
p->status = USB_RET_STALL;
break;
}
}
static void canokey_realize(USBDevice *base, Error **errp)
{
trace_canokey_realize();
CanoKeyState *key = CANOKEY(base);
if (key->file == NULL) {
error_setg(errp, "You must provide file=/path/to/canokey-file");
return;
}
usb_desc_init(base);
for (int i = 0; i != CANOKEY_EP_NUM; ++i) {
key->ep_in_state[i] = CANOKEY_EP_IN_WAIT;
key->ep_in_size[i] = 0;
key->ep_in_pos[i] = 0;
}
if (canokey_emu_init(key, key->file)) {
error_setg(errp, "canokey can not create or read %s", key->file);
return;
}
}
static void canokey_unrealize(USBDevice *base)
{
trace_canokey_unrealize();
}
static Property canokey_properties[] = {
DEFINE_PROP_STRING("file", CanoKeyState, file),
DEFINE_PROP_END_OF_LIST(),
};
static void canokey_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
uc->product_desc = "CanoKey QEMU";
uc->usb_desc = &desc_canokey;
uc->handle_reset = canokey_handle_reset;
uc->handle_control = canokey_handle_control;
uc->handle_data = canokey_handle_data;
uc->handle_attach = usb_desc_attach;
uc->realize = canokey_realize;
uc->unrealize = canokey_unrealize;
dc->desc = "CanoKey QEMU";
device_class_set_props(dc, canokey_properties);
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
}
static const TypeInfo canokey_info = {
.name = TYPE_CANOKEY,
.parent = TYPE_USB_DEVICE,
.instance_size = sizeof(CanoKeyState),
.class_init = canokey_class_init
};
static void canokey_register_types(void)
{
type_register_static(&canokey_info);
}
type_init(canokey_register_types)

69
hw/usb/canokey.h Normal file
View File

@ -0,0 +1,69 @@
/*
* CanoKey QEMU device header.
*
* Copyright (c) 2021-2022 Canokeys.org <contact@canokeys.org>
* Written by Hongren (Zenithal) Zheng <i@zenithal.me>
*
* This code is licensed under the Apache-2.0.
*/
#ifndef CANOKEY_H
#define CANOKEY_H
#include "hw/qdev-core.h"
#define TYPE_CANOKEY "canokey"
#define CANOKEY(obj) \
OBJECT_CHECK(CanoKeyState, (obj), TYPE_CANOKEY)
/*
* State of Canokey (i.e. hw/canokey.c)
*/
/* CTRL INTR BULK */
#define CANOKEY_EP_NUM 3
/* BULK/INTR IN can be up to 1352 bytes, e.g. get key info */
#define CANOKEY_EP_IN_BUFFER_SIZE 2048
/* BULK OUT can be up to 270 bytes, e.g. PIV import cert */
#define CANOKEY_EP_OUT_BUFFER_SIZE 512
typedef enum {
CANOKEY_EP_IN_WAIT,
CANOKEY_EP_IN_READY,
CANOKEY_EP_IN_STALL
} CanoKeyEPState;
typedef struct CanoKeyState {
USBDevice dev;
/* IN packets from canokey device loop */
uint8_t ep_in[CANOKEY_EP_NUM][CANOKEY_EP_IN_BUFFER_SIZE];
/*
* See canokey_emu_transmit
*
* For large INTR IN, receive multiple data from canokey device loop
* in this case ep_in_size would increase with every call
*/
uint32_t ep_in_size[CANOKEY_EP_NUM];
/*
* Used in canokey_handle_data
* for IN larger than p->iov.size, we would do multiple handle_data()
*
* The difference between ep_in_pos and ep_in_size:
* We first increase ep_in_size to fill ep_in buffer in device_loop,
* then use ep_in_pos to submit data from ep_in buffer in handle_data
*/
uint32_t ep_in_pos[CANOKEY_EP_NUM];
CanoKeyEPState ep_in_state[CANOKEY_EP_NUM];
/* OUT pointer to canokey recv buffer */
uint8_t *ep_out[CANOKEY_EP_NUM];
uint32_t ep_out_size[CANOKEY_EP_NUM];
/* For large BULK OUT, multiple write to ep_out is needed */
uint8_t ep_out_buffer[CANOKEY_EP_NUM][CANOKEY_EP_OUT_BUFFER_SIZE];
/* Properties */
char *file; /* canokey-file */
} CanoKeyState;
#endif /* CANOKEY_H */

View File

@ -2011,7 +2011,10 @@ static int ehci_state_writeback(EHCIQueue *q)
ehci_trace_qtd(q, NLPTR_GET(p->qtdaddr), (EHCIqtd *) &q->qh.next_qtd);
qtd = (uint32_t *) &q->qh.next_qtd;
addr = NLPTR_GET(p->qtdaddr);
put_dwords(q->ehci, addr + 2 * sizeof(uint32_t), qtd + 2, 2);
/* First write back the offset */
put_dwords(q->ehci, addr + 3 * sizeof(uint32_t), qtd + 3, 1);
/* Then write back the token, clearing the 'active' bit */
put_dwords(q->ehci, addr + 2 * sizeof(uint32_t), qtd + 2, 1);
ehci_free_packet(p);
/*

View File

@ -63,6 +63,11 @@ if u2f.found()
softmmu_ss.add(when: 'CONFIG_USB_U2F', if_true: [u2f, files('u2f-emulated.c')])
endif
# CanoKey
if canokey.found()
softmmu_ss.add(when: 'CONFIG_USB_CANOKEY', if_true: [canokey, files('canokey.c')])
endif
# usb redirect
if usbredir.found()
usbredir_ss = ss.source_set()

View File

@ -1280,7 +1280,8 @@ static void usbredir_create_parser(USBRedirDevice *dev)
}
#endif
if (runstate_check(RUN_STATE_INMIGRATE)) {
if (runstate_check(RUN_STATE_INMIGRATE) ||
runstate_check(RUN_STATE_PRELAUNCH)) {
flags |= usbredirparser_fl_no_hello;
}
usbredirparser_init(dev->parser, VERSION, caps, USB_REDIR_CAPS_SIZE,

View File

@ -345,3 +345,19 @@ usb_serial_set_baud(int bus, int addr, int baud) "dev %d:%u baud rate %d"
usb_serial_set_data(int bus, int addr, int parity, int data, int stop) "dev %d:%u parity %c, data bits %d, stop bits %d"
usb_serial_set_flow_control(int bus, int addr, int index) "dev %d:%u flow control %d"
usb_serial_set_xonxoff(int bus, int addr, uint8_t xon, uint8_t xoff) "dev %d:%u xon 0x%x xoff 0x%x"
# canokey.c
canokey_emu_stall_ep(uint8_t ep) "ep %d"
canokey_emu_set_address(uint8_t addr) "addr %d"
canokey_emu_prepare_receive(uint8_t ep, uint16_t size) "ep %d size %d"
canokey_emu_transmit(uint8_t ep, uint16_t size) "ep %d size %d"
canokey_thread_start(void)
canokey_thread_stop(void)
canokey_handle_reset(void)
canokey_handle_control_setup(int request, int value, int index, int length) "request 0x%04X value 0x%04X index 0x%04X length 0x%04X"
canokey_handle_control_out(void)
canokey_handle_control_in(int actual_len) "len %d"
canokey_handle_data_out(uint8_t ep_out, uint32_t out_len) "ep %d len %d"
canokey_handle_data_in(uint8_t ep_in, uint32_t in_len) "ep %d len %d"
canokey_realize(void)
canokey_unrealize(void)

View File

@ -106,14 +106,14 @@ err:
return;
}
static int vfio_display_edid_ui_info(void *opaque, uint32_t idx,
QemuUIInfo *info)
static void vfio_display_edid_ui_info(void *opaque, uint32_t idx,
QemuUIInfo *info)
{
VFIOPCIDevice *vdev = opaque;
VFIODisplay *dpy = vdev->dpy;
if (!dpy->edid_regs) {
return 0;
return;
}
if (info->width && info->height) {
@ -121,8 +121,6 @@ static int vfio_display_edid_ui_info(void *opaque, uint32_t idx,
} else {
vfio_display_edid_update(vdev, false, 0, 0);
}
return 0;
}
static void vfio_display_edid_init(VFIOPCIDevice *vdev)

View File

@ -2031,18 +2031,16 @@ static int vhost_user_backend_init(struct vhost_dev *dev, void *opaque,
if (supports_f_config) {
if (!virtio_has_feature(protocol_features,
VHOST_USER_PROTOCOL_F_CONFIG)) {
error_setg(errp, "vhost-user device %s expecting "
error_setg(errp, "vhost-user device expecting "
"VHOST_USER_PROTOCOL_F_CONFIG but the vhost-user backend does "
"not support it.", dev->vdev->name);
"not support it.");
return -EPROTO;
}
} else {
if (virtio_has_feature(protocol_features,
VHOST_USER_PROTOCOL_F_CONFIG)) {
warn_reportf_err(*errp, "vhost-user backend supports "
"VHOST_USER_PROTOCOL_F_CONFIG for "
"device %s but QEMU does not.",
dev->vdev->name);
"VHOST_USER_PROTOCOL_F_CONFIG but QEMU does not.");
protocol_features &= ~(1ULL << VHOST_USER_PROTOCOL_F_CONFIG);
}
}

View File

@ -419,11 +419,8 @@ static inline bool tlb_hit(target_ulong tlb_addr, target_ulong addr)
}
#ifdef CONFIG_TCG
/* accel/tcg/cpu-exec.c */
void dump_drift_info(GString *buf);
/* accel/tcg/translate-all.c */
void dump_exec_info(GString *buf);
void dump_opcount_info(GString *buf);
#endif /* CONFIG_TCG */
#endif /* !CONFIG_USER_ONLY */

View File

@ -2810,6 +2810,9 @@ MemTxResult address_space_write_cached_slow(MemoryRegionCache *cache,
hwaddr addr, const void *buf,
hwaddr len);
int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr);
bool prepare_mmio_access(MemoryRegion *mr);
static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write)
{
if (is_write) {

View File

@ -0,0 +1,40 @@
#ifndef ACPI_AML_INTERFACE_H
#define ACPI_AML_INTERFACE_H
#include "qom/object.h"
#include "hw/acpi/aml-build.h"
#define TYPE_ACPI_DEV_AML_IF "acpi-dev-aml-interface"
typedef struct AcpiDevAmlIfClass AcpiDevAmlIfClass;
DECLARE_CLASS_CHECKERS(AcpiDevAmlIfClass, ACPI_DEV_AML_IF, TYPE_ACPI_DEV_AML_IF)
#define ACPI_DEV_AML_IF(obj) \
INTERFACE_CHECK(AcpiDevAmlIf, (obj), TYPE_ACPI_DEV_AML_IF)
typedef struct AcpiDevAmlIf AcpiDevAmlIf;
typedef void (*dev_aml_fn)(AcpiDevAmlIf *adev, Aml *scope);
/**
* AcpiDevAmlIfClass:
*
* build_dev_aml: adds device specific AML blob to provided scope
*
* Interface is designed for providing generic callback that builds device
* specific AML blob.
*/
struct AcpiDevAmlIfClass {
/* <private> */
InterfaceClass parent_class;
/* <public> */
dev_aml_fn build_dev_aml;
};
static inline void call_dev_aml_func(DeviceState *dev, Aml *scope)
{
if (object_dynamic_cast(OBJECT(dev), TYPE_ACPI_DEV_AML_IF)) {
AcpiDevAmlIfClass *klass = ACPI_DEV_AML_IF_GET_CLASS(dev);
klass->build_dev_aml(ACPI_DEV_AML_IF(dev), scope);
}
}
#endif

View File

@ -19,10 +19,11 @@
#define HW_ACPI_CXL_H
#include "hw/acpi/bios-linker-loader.h"
#include "hw/cxl/cxl.h"
void cxl_build_cedt(MachineState *ms, GArray *table_offsets, GArray *table_data,
void cxl_build_cedt(GArray *table_offsets, GArray *table_data,
BIOSLinker *linker, const char *oem_id,
const char *oem_table_id);
const char *oem_table_id, CXLState *cxl_state);
void build_cxl_osc_method(Aml *dev);
#endif

View File

@ -9,13 +9,8 @@
#ifndef HW_ACPI_IPMI_H
#define HW_ACPI_IPMI_H
#include "hw/acpi/aml-build.h"
#include "hw/acpi/acpi_aml_interface.h"
/*
* Add ACPI IPMI entries for all registered IPMI devices whose parent
* bus matches the given bus. The resource is the ACPI resource that
* contains the IPMI device, this is required for the I2C CRS.
*/
void build_acpi_ipmi_devices(Aml *table, BusState *bus, const char *resource);
void build_ipmi_dev_aml(AcpiDevAmlIf *adev, Aml *scope);
#endif /* HW_ACPI_IPMI_H */

75
include/hw/acpi/piix4.h Normal file
View File

@ -0,0 +1,75 @@
/*
* ACPI implementation
*
* Copyright (c) 2006 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>
*
* Contributions after 2012-01-13 are licensed under the terms of the
* GNU GPL, version 2 or (at your option) any later version.
*/
#ifndef HW_ACPI_PIIX4_H
#define HW_ACPI_PIIX4_H
#include "hw/pci/pci.h"
#include "hw/acpi/acpi.h"
#include "hw/acpi/cpu_hotplug.h"
#include "hw/acpi/memory_hotplug.h"
#include "hw/acpi/pcihp.h"
#include "hw/i2c/pm_smbus.h"
#include "hw/isa/apm.h"
#define TYPE_PIIX4_PM "PIIX4_PM"
OBJECT_DECLARE_SIMPLE_TYPE(PIIX4PMState, PIIX4_PM)
struct PIIX4PMState {
/*< private >*/
PCIDevice parent_obj;
/*< public >*/
MemoryRegion io;
uint32_t io_base;
MemoryRegion io_gpe;
ACPIREGS ar;
APMState apm;
PMSMBus smb;
uint32_t smb_io_base;
qemu_irq irq;
qemu_irq smi_irq;
bool smm_enabled;
bool smm_compat;
Notifier machine_ready;
Notifier powerdown_notifier;
AcpiPciHpState acpi_pci_hotplug;
bool use_acpi_hotplug_bridge;
bool use_acpi_root_pci_hotplug;
bool not_migrate_acpi_index;
uint8_t disable_s3;
uint8_t disable_s4;
uint8_t s4_val;
bool cpu_hotplug_legacy;
AcpiCpuHotplug gpe_cpu;
CPUHotplugState cpuhp_state;
MemHotplugState acpi_memory_hotplug;
};
#endif

View File

@ -10,8 +10,7 @@
#define TYPE_ISA_FDC "isa-fdc"
void isa_fdc_init_drives(ISADevice *fdc, DriveInfo **fds);
void fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
hwaddr mmio_base, DriveInfo **fds);
void fdctrl_init_sysbus(qemu_irq irq, hwaddr mmio_base, DriveInfo **fds);
void sun4m_fdctrl_init(qemu_irq irq, hwaddr io_base,
DriveInfo **fds, qemu_irq *fdc_tc);

View File

@ -269,7 +269,6 @@ struct MachineClass {
bool ignore_boot_device_suffixes;
bool smbus_no_migration_support;
bool nvdimm_supported;
bool cxl_supported;
bool numa_mem_supported;
bool auto_enable_numa;
SMPCompatProps smp_props;
@ -360,8 +359,8 @@ struct MachineState {
CPUArchIdList *possible_cpus;
CpuTopology smp;
struct NVDIMMState *nvdimms_state;
struct CXLState *cxl_devices_state;
struct NumaState *numa_state;
CXLFixedMemoryWindowOptionsList *cfmws_list;
};
#define DEFINE_MACHINE(namestr, machine_initfn) \

View File

@ -12,6 +12,7 @@
#include "qapi/qapi-types-machine.h"
#include "qapi/qapi-visit-machine.h"
#include "hw/pci/pci_bridge.h"
#include "hw/pci/pci_host.h"
#include "cxl_pci.h"
@ -40,6 +41,7 @@ typedef struct CXLState {
MemoryRegion host_mr;
unsigned int next_mr_idx;
GList *fixed_windows;
CXLFixedMemoryWindowOptionsList *cfmw_list;
} CXLState;
struct CXLHost {
@ -51,11 +53,4 @@ struct CXLHost {
#define TYPE_PXB_CXL_HOST "pxb-cxl-host"
OBJECT_DECLARE_SIMPLE_TYPE(CXLHost, PXB_CXL_HOST)
void cxl_fixed_memory_window_config(MachineState *ms,
CXLFixedMemoryWindowOptions *object,
Error **errp);
void cxl_fixed_memory_window_link_targets(Error **errp);
extern const MemoryRegionOps cfmws_ops;
#endif

23
include/hw/cxl/cxl_host.h Normal file
View File

@ -0,0 +1,23 @@
/*
* QEMU CXL Host Setup
*
* Copyright (c) 2022 Huawei
*
* This work is licensed under the terms of the GNU GPL, version 2. See the
* COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include "hw/cxl/cxl.h"
#include "hw/boards.h"
#ifndef CXL_HOST_H
#define CXL_HOST_H
void cxl_machine_init(Object *obj, CXLState *state);
void cxl_fmws_link_targets(CXLState *stat, Error **errp);
void cxl_hook_up_pxb_registers(PCIBus *bus, CXLState *state, Error **errp);
extern const MemoryRegionOps cfmws_ops;
#endif

Some files were not shown because too many files have changed in this diff Show More